From eca1e8c4580c94c6e9f33b0f9617a9ad5c992b5d Mon Sep 17 00:00:00 2001 From: James Russell Date: Fri, 3 Apr 2026 00:22:39 -0500 Subject: [PATCH] Initial commit --- Bin/x86-64/libZNet.a | Bin 0 -> 232656 bytes Bin/x86-64/libZUtil.a | Bin 0 -> 1113018 bytes Bin/x86-64/libsst-net.a | Bin 0 -> 18912 bytes BuildConfig/Darwin-Libs.rules | 22 + BuildConfig/DetectCompiler.rules | 48 + BuildConfig/DetectLibs.rules | 36 + BuildConfig/DetectPlatform.rules | 84 + BuildConfig/DetectWinSys.rules | 44 + BuildConfig/GCC-Flags.rules | 20 + BuildConfig/Makefile.Android.arm | 30 + BuildConfig/Makefile.Darwin.x86 | 30 + BuildConfig/Makefile.Darwin.x86-64 | 30 + BuildConfig/Makefile.Linux.arm | 30 + BuildConfig/Makefile.Linux.ia64 | 32 + BuildConfig/Makefile.Linux.mips | 30 + BuildConfig/Makefile.Linux.mips64 | 30 + BuildConfig/Makefile.Linux.ppc | 33 + BuildConfig/Makefile.Linux.sparc | 33 + BuildConfig/Makefile.Linux.sparc64 | 33 + BuildConfig/Makefile.Linux.x86 | 30 + BuildConfig/Makefile.Linux.x86-64 | 30 + BuildConfig/Makefile.Solaris.sparc | 56 + BuildConfig/Makefile.Solaris.sparc64 | 56 + BuildConfig/Makefile.Solaris.x86 | 52 + BuildConfig/Makefile.Windows.x86 | 28 + BuildConfig/POSIX-Libs.rules | 22 + BuildConfig/RaspPi-Flags.rules | 19 + BuildConfig/Solaris-Libs.rules | 26 + BuildConfig/SunPro-Flags.rules | 30 + Include/ZBuild.hpp | 137 + Include/ZNet/ZNet.hpp | 29 + Include/ZNet/ZNetBandwidthMeter.hpp | 57 + Include/ZNet/ZNetClient.hpp | 98 + Include/ZNet/ZNetConsts.hpp | 44 + Include/ZNet/ZNetEvent.hpp | 45 + Include/ZNet/ZNetHost.hpp | 184 + Include/ZNet/ZNetPacket.hpp | 46 + Include/ZNet/ZNetPacketChannel.hpp | 165 + Include/ZNet/ZNetPeer.hpp | 143 + Include/ZNet/ZNetServer.hpp | 240 + Include/ZNet/ZNetUtil.hpp | 49 + Include/ZRenderer/ZDataBuffer.hpp | 288 ++ Include/ZRenderer/ZDataBufferBase.hpp | 130 + Include/ZRenderer/ZDimensionTexture.hpp | 91 + Include/ZRenderer/ZDimensionTextureBase.hpp | 110 + Include/ZRenderer/ZDrawParams.hpp | 62 + .../ZRenderer/ZFrameBufferRenderTarget.hpp | 138 + .../ZFrameBufferRenderTargetBase.hpp | 150 + Include/ZRenderer/ZIndexParams.hpp | 163 + Include/ZRenderer/ZOpenGLDataBuffer.hpp | 98 + Include/ZRenderer/ZOpenGLDimensionTexture.hpp | 262 ++ .../ZOpenGLFrameBufferRenderTarget.hpp | 53 + Include/ZRenderer/ZOpenGLRenderBuffer.hpp | 84 + Include/ZRenderer/ZOpenGLRenderer.hpp | 197 + Include/ZRenderer/ZOpenGLSampler.hpp | 162 + Include/ZRenderer/ZOpenGLShader.hpp | 66 + Include/ZRenderer/ZOpenGLShaderProgram.hpp | 69 + .../ZRenderer/ZOpenGLTextureRenderTarget.h | 92 + Include/ZRenderer/ZOpenGLVertexParams.hpp | 46 + .../ZRenderer/ZOpenGLWindowRenderTarget.hpp | 60 + Include/ZRenderer/ZRenderBuffer.hpp | 71 + Include/ZRenderer/ZRenderTarget.hpp | 114 + Include/ZRenderer/ZRenderer.hpp | 559 +++ Include/ZRenderer/ZRendererBase.hpp | 259 ++ Include/ZRenderer/ZRendererBuild.hpp | 49 + Include/ZRenderer/ZRendererResource.hpp | 153 + Include/ZRenderer/ZSampler.hpp | 192 + Include/ZRenderer/ZSamplerBase.hpp | 98 + Include/ZRenderer/ZShader.hpp | 122 + Include/ZRenderer/ZShaderBase.hpp | 74 + Include/ZRenderer/ZShaderParams.hpp | 147 + Include/ZRenderer/ZShaderProgram.hpp | 315 ++ Include/ZRenderer/ZShaderProgramBase.hpp | 85 + Include/ZRenderer/ZTexture.hpp | 162 + Include/ZRenderer/ZVertexParams.hpp | 106 + Include/ZRenderer/ZWindowRenderTarget.hpp | 106 + Include/ZRenderer/ZWindowRenderTargetBase.hpp | 88 + Include/ZRendererUtil/ZFontRenderer.hpp | 164 + Include/ZRendererUtil/ZFontRendererBase.hpp | 67 + Include/ZRendererUtil/ZOutlineEvaluator.hpp | 126 + Include/ZRendererUtil/ZParticleEffect.h | 140 + Include/ZRendererUtil/ZParticleEmitter.h | 200 + .../ZRendererUtil/ZParticleRenderStrategy.h | 80 + .../ZRendererUtil/ZParticleSpawnStrategy.h | 61 + .../ZRendererUtil/ZParticleStorageAllocator.h | 82 + .../ZRendererUtil/ZParticleUpdateStrategy.h | 60 + Include/ZRendererUtil/ZPerspectiveCamera.hpp | 145 + Include/ZRendererUtil/ZSolidFontFace.hpp | 84 + Include/ZRendererUtil/ZSolidFontRenderer.hpp | 101 + .../ZStandardParticleRenderStrategy.h | 105 + .../ZStandardParticleSpawnStrategy.h | 218 + .../ZStandardParticleStorageAllocator.h | 167 + .../ZStandardParticleUpdateStrategy.h | 97 + Include/ZRendererUtil/ZStaticMesh.hpp | 134 + Include/ZRendererUtil/ZStaticMeshLoader.hpp | 27 + Include/ZRendererUtil/ZTessellator.hpp | 100 + Include/ZRendererUtil/ZTessellatorBase.hpp | 64 + Include/ZRendererUtil/ZTransformHierarchy.hpp | 37 + Include/ZRendererUtil/ZTriTessellator.hpp | 55 + Include/ZSimulation/ZEntity.hpp | 379 ++ Include/ZSimulation/ZMessageStream.hpp | 153 + Include/ZSimulation/ZNetworkEvent.hpp | 165 + Include/ZSimulation/ZNetworkRequest.hpp | 82 + Include/ZSimulation/ZNetworkService.hpp | 181 + Include/ZSimulation/ZNetworkUpdateStream.hpp | 114 + Include/ZSimulation/ZPropertyBuffer.cpp | 454 ++ Include/ZSimulation/ZPropertyBuffer.hpp | 134 + Include/ZSimulation/ZPropertyBufferUpdate.hpp | 62 + .../ZPropertyBufferUpdateQueue.hpp | 33 + Include/ZSimulation/ZRemotePeer.hpp | 74 + Include/ZSimulation/ZSimulation.hpp | 327 ++ Include/ZSimulation/ZSimulationDefs.hpp | 299 ++ Include/ZSimulation/ZStringBuffer.hpp | 72 + Include/ZUtil/ZAlloc.hpp | 161 + Include/ZUtil/ZAllocWindow.hpp | 205 + Include/ZUtil/ZAssert.hpp | 53 + Include/ZUtil/ZBinaryBufferReader.hpp | 87 + Include/ZUtil/ZBinaryBufferWriter.hpp | 78 + Include/ZUtil/ZBinaryFileReader.hpp | 72 + Include/ZUtil/ZBinaryFileWriter.hpp | 68 + Include/ZUtil/ZBinaryReader.hpp | 749 ++++ Include/ZUtil/ZBinaryWriter.hpp | 279 ++ Include/ZUtil/ZBitmap.hpp | 253 ++ Include/ZUtil/ZConcurrency.hpp | 137 + Include/ZUtil/ZEvent.hpp | 86 + Include/ZUtil/ZIniReader.hpp | 184 + Include/ZUtil/ZIniWriter.hpp | 69 + Include/ZUtil/ZJSONReader.hpp | 69 + Include/ZUtil/ZJSONWriter.hpp | 64 + Include/ZUtil/ZKVTree.hpp | 821 ++++ Include/ZUtil/ZLog.hpp | 269 ++ Include/ZUtil/ZMutex.hpp | 91 + Include/ZUtil/ZName.hpp | 172 + Include/ZUtil/ZNoise.hpp | 79 + Include/ZUtil/ZNoiseMap.hpp | 185 + Include/ZUtil/ZRandomGenerator.hpp | 245 ++ Include/ZUtil/ZReadWriteLock.hpp | 84 + Include/ZUtil/ZReferenceBuffer.hpp | 399 ++ Include/ZUtil/ZReferenceCounter.hpp | 243 + Include/ZUtil/ZRegistry.hpp | 145 + Include/ZUtil/ZSemaphore.hpp | 89 + Include/ZUtil/ZSimplexNoise.hpp | 41 + Include/ZUtil/ZSimplexNoiseMap.hpp | 261 ++ Include/ZUtil/ZSlabAllocator.hpp | 237 + Include/ZUtil/ZSmartPointer.hpp | 944 ++++ Include/ZUtil/ZTaskStream.hpp | 404 ++ Include/ZUtil/ZThread.hpp | 368 ++ Include/ZUtil/ZUtil.hpp | 49 + Include/ZUtil/ZUtilBuild.hpp | 121 + Include/ZUtil/ZWeakPointer.hpp | 1024 +++++ Include/ZUtil/ZXMLReader.hpp | 160 + Include/ZUtil/ZXMLWriter.hpp | 110 + Lib/Include/AL/al.h | 718 +++ Lib/Include/AL/alc.h | 280 ++ Lib/Include/AL/alext.h | 296 ++ Lib/Include/AL/efx-creative.h | 3 + Lib/Include/AL/efx-presets.h | 402 ++ Lib/Include/AL/efx.h | 758 ++++ Lib/Include/Box2D/Box2D.h | 68 + .../Box2D/Collision/Shapes/b2ChainShape.h | 102 + .../Box2D/Collision/Shapes/b2CircleShape.h | 91 + .../Box2D/Collision/Shapes/b2EdgeShape.h | 74 + .../Box2D/Collision/Shapes/b2PolygonShape.h | 101 + Lib/Include/Box2D/Collision/Shapes/b2Shape.h | 101 + Lib/Include/Box2D/Collision/b2BroadPhase.h | 257 ++ Lib/Include/Box2D/Collision/b2Collision.h | 277 ++ Lib/Include/Box2D/Collision/b2Distance.h | 141 + Lib/Include/Box2D/Collision/b2DynamicTree.h | 289 ++ Lib/Include/Box2D/Collision/b2TimeOfImpact.h | 58 + Lib/Include/Box2D/Common/b2BlockAllocator.h | 62 + Lib/Include/Box2D/Common/b2Draw.h | 86 + Lib/Include/Box2D/Common/b2GrowableStack.h | 85 + Lib/Include/Box2D/Common/b2Math.h | 722 +++ Lib/Include/Box2D/Common/b2Settings.h | 161 + Lib/Include/Box2D/Common/b2StackAllocator.h | 60 + Lib/Include/Box2D/Common/b2Timer.h | 50 + .../Contacts/b2ChainAndCircleContact.h | 39 + .../Contacts/b2ChainAndPolygonContact.h | 39 + .../Box2D/Dynamics/Contacts/b2CircleContact.h | 39 + .../Box2D/Dynamics/Contacts/b2Contact.h | 349 ++ .../Box2D/Dynamics/Contacts/b2ContactSolver.h | 95 + .../Contacts/b2EdgeAndCircleContact.h | 39 + .../Contacts/b2EdgeAndPolygonContact.h | 39 + .../Contacts/b2PolygonAndCircleContact.h | 38 + .../Dynamics/Contacts/b2PolygonContact.h | 39 + .../Box2D/Dynamics/Joints/b2DistanceJoint.h | 169 + .../Box2D/Dynamics/Joints/b2FrictionJoint.h | 119 + .../Box2D/Dynamics/Joints/b2GearJoint.h | 125 + Lib/Include/Box2D/Dynamics/Joints/b2Joint.h | 226 + .../Box2D/Dynamics/Joints/b2MotorJoint.h | 133 + .../Box2D/Dynamics/Joints/b2MouseJoint.h | 129 + .../Box2D/Dynamics/Joints/b2PrismaticJoint.h | 196 + .../Box2D/Dynamics/Joints/b2PulleyJoint.h | 152 + .../Box2D/Dynamics/Joints/b2RevoluteJoint.h | 204 + .../Box2D/Dynamics/Joints/b2RopeJoint.h | 114 + .../Box2D/Dynamics/Joints/b2WeldJoint.h | 126 + .../Box2D/Dynamics/Joints/b2WheelJoint.h | 211 + Lib/Include/Box2D/Dynamics/b2Body.h | 859 ++++ Lib/Include/Box2D/Dynamics/b2ContactManager.h | 52 + Lib/Include/Box2D/Dynamics/b2Fixture.h | 345 ++ Lib/Include/Box2D/Dynamics/b2Island.h | 93 + Lib/Include/Box2D/Dynamics/b2TimeStep.h | 70 + Lib/Include/Box2D/Dynamics/b2World.h | 354 ++ Lib/Include/Box2D/Dynamics/b2WorldCallbacks.h | 155 + Lib/Include/Box2D/Rope/b2Rope.h | 115 + Lib/Include/CML/cml.h | 75 + Lib/Include/CML/constants.h | 89 + Lib/Include/CML/core/cml_assert.h | 97 + Lib/Include/CML/core/cml_meta.h | 24 + Lib/Include/CML/core/common.h | 87 + Lib/Include/CML/core/dynamic_1D.h | 202 + Lib/Include/CML/core/dynamic_2D.h | 248 ++ Lib/Include/CML/core/external_1D.h | 226 + Lib/Include/CML/core/external_2D.h | 315 ++ Lib/Include/CML/core/fixed_1D.h | 135 + Lib/Include/CML/core/fixed_2D.h | 205 + Lib/Include/CML/core/fwd.h | 63 + Lib/Include/CML/core/meta/common.h | 118 + Lib/Include/CML/core/meta/if.h | 42 + Lib/Include/CML/core/meta/switch.h | 116 + Lib/Include/CML/defaults.h | 89 + Lib/Include/CML/dynamic.h | 35 + Lib/Include/CML/et/array_promotions.h | 288 ++ Lib/Include/CML/et/scalar_ops.h | 138 + Lib/Include/CML/et/scalar_promotions.h | 151 + Lib/Include/CML/et/size_checking.h | 431 ++ Lib/Include/CML/et/tags.h | 55 + Lib/Include/CML/et/traits.h | 143 + Lib/Include/CML/external.h | 41 + Lib/Include/CML/fixed.h | 42 + Lib/Include/CML/mathlib/checking.h | 382 ++ Lib/Include/CML/mathlib/coord_conversion.h | 162 + Lib/Include/CML/mathlib/epsilon.h | 44 + Lib/Include/CML/mathlib/frustum.h | 258 ++ Lib/Include/CML/mathlib/helper.h | 158 + Lib/Include/CML/mathlib/interpolation.h | 1129 +++++ Lib/Include/CML/mathlib/mathlib.h | 33 + Lib/Include/CML/mathlib/matrix_basis.h | 364 ++ Lib/Include/CML/mathlib/matrix_concat.h | 62 + Lib/Include/CML/mathlib/matrix_misc.h | 135 + Lib/Include/CML/mathlib/matrix_ortho.h | 60 + Lib/Include/CML/mathlib/matrix_projection.h | 348 ++ Lib/Include/CML/mathlib/matrix_rotation.h | 980 +++++ Lib/Include/CML/mathlib/matrix_transform.h | 984 +++++ Lib/Include/CML/mathlib/matrix_translation.h | 177 + Lib/Include/CML/mathlib/misc.h | 210 + Lib/Include/CML/mathlib/picking.h | 195 + Lib/Include/CML/mathlib/projection.h | 142 + Lib/Include/CML/mathlib/quaternion_basis.h | 89 + Lib/Include/CML/mathlib/quaternion_rotation.h | 635 +++ Lib/Include/CML/mathlib/typedef.h | 134 + Lib/Include/CML/mathlib/vector_angle.h | 69 + Lib/Include/CML/mathlib/vector_misc.h | 304 ++ Lib/Include/CML/mathlib/vector_ortho.h | 338 ++ Lib/Include/CML/mathlib/vector_transform.h | 176 + Lib/Include/CML/matrix.h | 63 + Lib/Include/CML/matrix/class_ops.h | 341 ++ Lib/Include/CML/matrix/determinant.h | 192 + Lib/Include/CML/matrix/dynamic.h | 320 ++ Lib/Include/CML/matrix/external.h | 543 +++ Lib/Include/CML/matrix/fixed.h | 284 ++ Lib/Include/CML/matrix/inverse.h | 444 ++ Lib/Include/CML/matrix/lu.h | 176 + Lib/Include/CML/matrix/matop_macros.h | 236 + Lib/Include/CML/matrix/matrix_comparison.h | 245 ++ Lib/Include/CML/matrix/matrix_expr.h | 483 ++ Lib/Include/CML/matrix/matrix_functions.h | 43 + Lib/Include/CML/matrix/matrix_mul.h | 205 + Lib/Include/CML/matrix/matrix_ops.h | 50 + Lib/Include/CML/matrix/matrix_print.h | 59 + Lib/Include/CML/matrix/matrix_promotions.h | 187 + Lib/Include/CML/matrix/matrix_rowcol.h | 273 ++ Lib/Include/CML/matrix/matrix_traits.h | 49 + Lib/Include/CML/matrix/matrix_transpose.h | 305 ++ Lib/Include/CML/matrix/matrix_unroller.h | 293 ++ Lib/Include/CML/matvec/matvec_mul.h | 285 ++ Lib/Include/CML/matvec/matvec_promotions.h | 92 + Lib/Include/CML/quaternion.h | 67 + Lib/Include/CML/quaternion/conjugate.h | 197 + Lib/Include/CML/quaternion/inverse.h | 268 ++ Lib/Include/CML/quaternion/quaternion.h | 526 +++ .../CML/quaternion/quaternion_comparison.h | 216 + Lib/Include/CML/quaternion/quaternion_dot.h | 73 + Lib/Include/CML/quaternion/quaternion_expr.h | 614 +++ .../CML/quaternion/quaternion_functions.h | 172 + Lib/Include/CML/quaternion/quaternion_mul.h | 140 + Lib/Include/CML/quaternion/quaternion_ops.h | 51 + Lib/Include/CML/quaternion/quaternion_print.h | 90 + .../CML/quaternion/quaternion_promotions.h | 140 + .../CML/quaternion/quaternion_traits.h | 45 + Lib/Include/CML/quaternion/quatop_macros.h | 232 + Lib/Include/CML/util.h | 368 ++ Lib/Include/CML/vector.h | 62 + Lib/Include/CML/vector/class_ops.h | 238 + Lib/Include/CML/vector/dynamic.h | 190 + Lib/Include/CML/vector/external.h | 343 ++ Lib/Include/CML/vector/fixed.h | 196 + Lib/Include/CML/vector/vecop_macros.h | 248 ++ Lib/Include/CML/vector/vector_comparison.h | 236 + Lib/Include/CML/vector/vector_expr.h | 458 ++ Lib/Include/CML/vector/vector_functions.h | 73 + Lib/Include/CML/vector/vector_ops.h | 51 + Lib/Include/CML/vector/vector_print.h | 47 + Lib/Include/CML/vector/vector_products.h | 361 ++ Lib/Include/CML/vector/vector_promotions.h | 77 + Lib/Include/CML/vector/vector_traits.h | 47 + Lib/Include/CML/vector/vector_unroller.h | 259 ++ Lib/Include/FMOD/fmod.h | 2428 ++++++++++ Lib/Include/FMOD/fmod.hpp | 603 +++ Lib/Include/FMOD/fmod_codec.h | 159 + Lib/Include/FMOD/fmod_dsp.h | 759 ++++ Lib/Include/FMOD/fmod_errors.h | 125 + Lib/Include/FMOD/fmod_memoryinfo.h | 201 + Lib/Include/FMOD/fmod_output.h | 93 + Lib/Include/FreeImage.h | 1090 +++++ Lib/Include/Recast.h | 1141 +++++ Lib/Include/RecastAlloc.h | 136 + Lib/Include/RecastAssert.h | 33 + Lib/Include/ZSTL/ZArray.hpp | 1768 ++++++++ Lib/Include/ZSTL/ZArrayAlgo.hpp | 2842 ++++++++++++ Lib/Include/ZSTL/ZBasicString.hpp | 855 ++++ Lib/Include/ZSTL/ZBasicStringAlgo.hpp | 2439 ++++++++++ Lib/Include/ZSTL/ZHashMap.hpp | 1230 ++++++ Lib/Include/ZSTL/ZList.hpp | 1554 +++++++ Lib/Include/ZSTL/ZListAlgo.hpp | 802 ++++ Lib/Include/ZSTL/ZPair.hpp | 206 + Lib/Include/ZSTL/ZRingBuffer.hpp | 1378 ++++++ Lib/Include/ZSTL/ZSTL.hpp | 55 + Lib/Include/ZSTL/ZSTLCommon.hpp | 383 ++ Lib/Include/ZSTL/ZSTLInvalidPos.hpp | 66 + Lib/Include/ZSTL/ZString.hpp | 35 + Lib/Include/assimp/Compiler/poppack1.h | 22 + Lib/Include/assimp/Compiler/pushpack1.h | 41 + Lib/Include/assimp/DefaultLogger.hpp | 190 + Lib/Include/assimp/Exporter.hpp | 304 ++ Lib/Include/assimp/IOStream.hpp | 135 + Lib/Include/assimp/IOSystem.hpp | 222 + Lib/Include/assimp/Importer.hpp | 642 +++ Lib/Include/assimp/LogStream.hpp | 93 + Lib/Include/assimp/Logger.hpp | 262 ++ Lib/Include/assimp/NullLogger.hpp | 95 + Lib/Include/assimp/ProgressHandler.hpp | 93 + Lib/Include/assimp/ai_assert.h | 14 + Lib/Include/assimp/anim.h | 484 ++ Lib/Include/assimp/camera.h | 223 + Lib/Include/assimp/cexport.h | 242 + Lib/Include/assimp/cfileio.h | 135 + Lib/Include/assimp/cimport.h | 493 +++ Lib/Include/assimp/color4.h | 103 + Lib/Include/assimp/color4.inl | 165 + Lib/Include/assimp/config.h | 738 ++++ Lib/Include/assimp/defs.h | 259 ++ Lib/Include/assimp/importerdesc.h | 136 + Lib/Include/assimp/light.h | 233 + Lib/Include/assimp/material.h | 1491 +++++++ Lib/Include/assimp/material.inl | 276 ++ Lib/Include/assimp/matrix3x3.h | 183 + Lib/Include/assimp/matrix3x3.inl | 316 ++ Lib/Include/assimp/matrix4x4.h | 238 + Lib/Include/assimp/matrix4x4.inl | 485 ++ Lib/Include/assimp/mesh.h | 734 +++ Lib/Include/assimp/postprocess.h | 631 +++ Lib/Include/assimp/quaternion.h | 124 + Lib/Include/assimp/quaternion.inl | 274 ++ Lib/Include/assimp/scene.h | 378 ++ Lib/Include/assimp/texture.h | 197 + Lib/Include/assimp/types.h | 499 +++ Lib/Include/assimp/vector2.h | 107 + Lib/Include/assimp/vector2.inl | 214 + Lib/Include/assimp/vector3.h | 143 + Lib/Include/assimp/vector3.inl | 212 + Lib/Include/assimp/version.h | 104 + Lib/Include/enet/callbacks.h | 27 + Lib/Include/enet/enet.h | 587 +++ Lib/Include/enet/list.h | 43 + Lib/Include/enet/protocol.h | 199 + Lib/Include/enet/time.h | 18 + Lib/Include/enet/types.h | 13 + Lib/Include/enet/unix.h | 47 + Lib/Include/enet/utility.h | 12 + Lib/Include/enet/win32.h | 60 + Lib/Include/freetype/config/ftconfig.h | 528 +++ Lib/Include/freetype/config/ftheader.h | 780 ++++ Lib/Include/freetype/config/ftmodule.h | 32 + Lib/Include/freetype/config/ftoption.h | 733 +++ Lib/Include/freetype/config/ftstdlib.h | 173 + Lib/Include/freetype/freetype.h | 3919 +++++++++++++++++ Lib/Include/freetype/ftadvanc.h | 179 + Lib/Include/freetype/ftbbox.h | 94 + Lib/Include/freetype/ftbdf.h | 209 + Lib/Include/freetype/ftbitmap.h | 227 + Lib/Include/freetype/ftcache.h | 1140 +++++ Lib/Include/freetype/ftchapters.h | 103 + Lib/Include/freetype/ftcid.h | 166 + Lib/Include/freetype/fterrdef.h | 244 + Lib/Include/freetype/fterrors.h | 206 + Lib/Include/freetype/ftgasp.h | 120 + Lib/Include/freetype/ftglyph.h | 613 +++ Lib/Include/freetype/ftgxval.h | 358 ++ Lib/Include/freetype/ftgzip.h | 102 + Lib/Include/freetype/ftimage.h | 1313 ++++++ Lib/Include/freetype/ftincrem.h | 353 ++ Lib/Include/freetype/ftlcdfil.h | 213 + Lib/Include/freetype/ftlist.h | 277 ++ Lib/Include/freetype/ftlzw.h | 99 + Lib/Include/freetype/ftmac.h | 274 ++ Lib/Include/freetype/ftmm.h | 378 ++ Lib/Include/freetype/ftmodapi.h | 483 ++ Lib/Include/freetype/ftmoderr.h | 155 + Lib/Include/freetype/ftotval.h | 203 + Lib/Include/freetype/ftoutln.h | 537 +++ Lib/Include/freetype/ftpfr.h | 172 + Lib/Include/freetype/ftrender.h | 230 + Lib/Include/freetype/ftsizes.h | 159 + Lib/Include/freetype/ftsnames.h | 200 + Lib/Include/freetype/ftstroke.h | 716 +++ Lib/Include/freetype/ftsynth.h | 80 + Lib/Include/freetype/ftsystem.h | 347 ++ Lib/Include/freetype/fttrigon.h | 350 ++ Lib/Include/freetype/fttypes.h | 588 +++ Lib/Include/freetype/ftwinfnt.h | 274 ++ Lib/Include/freetype/ftxf86.h | 83 + Lib/Include/freetype/internal/autohint.h | 231 + Lib/Include/freetype/internal/ftcalc.h | 179 + Lib/Include/freetype/internal/ftdebug.h | 250 ++ Lib/Include/freetype/internal/ftdriver.h | 422 ++ Lib/Include/freetype/internal/ftgloadr.h | 168 + Lib/Include/freetype/internal/ftmemory.h | 380 ++ Lib/Include/freetype/internal/ftobjs.h | 1428 ++++++ Lib/Include/freetype/internal/ftpic.h | 67 + Lib/Include/freetype/internal/ftrfork.h | 196 + Lib/Include/freetype/internal/ftserv.h | 620 +++ Lib/Include/freetype/internal/ftstream.h | 539 +++ Lib/Include/freetype/internal/fttrace.h | 139 + Lib/Include/freetype/internal/ftvalid.h | 150 + Lib/Include/freetype/internal/internal.h | 51 + Lib/Include/freetype/internal/pcftypes.h | 56 + Lib/Include/freetype/internal/psaux.h | 873 ++++ Lib/Include/freetype/internal/pshints.h | 712 +++ .../freetype/internal/services/svbdf.h | 77 + .../freetype/internal/services/svcid.h | 83 + .../freetype/internal/services/svgldict.h | 82 + .../freetype/internal/services/svgxval.h | 72 + .../freetype/internal/services/svkern.h | 51 + Lib/Include/freetype/internal/services/svmm.h | 104 + .../freetype/internal/services/svotval.h | 55 + .../freetype/internal/services/svpfr.h | 66 + .../freetype/internal/services/svpostnm.h | 79 + .../freetype/internal/services/svpscmap.h | 164 + .../freetype/internal/services/svpsinfo.h | 92 + .../freetype/internal/services/svsfnt.h | 102 + .../freetype/internal/services/svttcmap.h | 106 + .../freetype/internal/services/svtteng.h | 53 + .../freetype/internal/services/svttglyf.h | 67 + .../freetype/internal/services/svwinfnt.h | 50 + .../freetype/internal/services/svxf86nm.h | 55 + Lib/Include/freetype/internal/sfnt.h | 897 ++++ Lib/Include/freetype/internal/t1types.h | 270 ++ Lib/Include/freetype/internal/tttypes.h | 1543 +++++++ Lib/Include/freetype/t1tables.h | 504 +++ Lib/Include/freetype/ttnameid.h | 1247 ++++++ Lib/Include/freetype/tttables.h | 759 ++++ Lib/Include/freetype/tttags.h | 107 + Lib/Include/freetype/ttunpat.h | 59 + Lib/Include/ft2build.h | 39 + Lib/Include/jansson.h | 273 ++ Lib/Include/jansson_config.h | 39 + Lib/Include/lua.h | 439 ++ Lib/Include/lua.hpp | 8 + Lib/Include/luaconf.h | 547 +++ Lib/Include/lualib.h | 55 + Lib/Include/physfs.h | 2395 ++++++++++ Lib/Include/pstdbool.h | 60 + Lib/Include/rapidxml/rapidxml.hpp | 2774 ++++++++++++ Lib/Include/rapidxml/rapidxml_iterators.hpp | 174 + Lib/Include/rapidxml/rapidxml_print.hpp | 421 ++ Lib/Include/rapidxml/rapidxml_utils.hpp | 122 + Lib/Include/zconf.h | 507 +++ Lib/Include/zlib.h | 1744 ++++++++ Makefile | 206 + README.md | 79 + ZNet/Makefile | 34 + ZNet/ZNet.vcxproj | 200 + ZNet/ZNet.vcxproj.filters | 78 + ZNet/ZNetBandwidthMeter.cpp | 86 + ZNet/ZNetClient.cpp | 268 ++ ZNet/ZNetHost.cpp | 145 + ZNet/ZNetPacketChannel.cpp | 506 +++ ZNet/ZNetPeer.cpp | 156 + ZNet/ZNetPrivate.cpp | 174 + ZNet/ZNetPrivate.hpp | 243 + ZNet/ZNetServer.cpp | 403 ++ ZNet/obj/x86-64/release/ZNetBandwidthMeter.o | Bin 0 -> 1944 bytes ZNet/obj/x86-64/release/ZNetClient.o | Bin 0 -> 31968 bytes ZNet/obj/x86-64/release/ZNetHost.o | Bin 0 -> 17032 bytes ZNet/obj/x86-64/release/ZNetPacketChannel.o | Bin 0 -> 74416 bytes ZNet/obj/x86-64/release/ZNetPeer.o | Bin 0 -> 41312 bytes ZNet/obj/x86-64/release/ZNetPrivate.o | Bin 0 -> 6216 bytes ZNet/obj/x86-64/release/ZNetServer.o | Bin 0 -> 37768 bytes .../FileSystemTestDir/ZFileSystemTest-001.txt | 1 + .../FileSystemTestDir/ZFileSystemTest-002 | 4 + .../FileSystemTestDir/ZFileSystemTest-7z.zep | Bin 0 -> 127 bytes .../FileSystemTestDir/ZFileSystemTest-ZIP.zep | Bin 0 -> 282 bytes ZTestSuite/FileSystemTestDir/test1.xml | 40 + .../FileSystemTestDir/testAttributes.xml | 18 + .../FileSystemTestDir/writedir/FileWriteTest | 1 + .../writedir/ZRegistryTestWrite.ini | 4 + ZTestSuite/Makefile | 112 + ZTestSuite/Test-SST_Atomic.cpp | 430 ++ ZTestSuite/Test-SST_Endian.cpp | 219 + ZTestSuite/Test-SST_FileSys.cpp | 274 ++ ZTestSuite/Test-SST_Geo.cpp | 344 ++ ZTestSuite/Test-SST_Mat22d.cpp | 679 +++ ZTestSuite/Test-SST_Mat22f.cpp | 679 +++ ZTestSuite/Test-SST_Mat22i.cpp | 490 +++ ZTestSuite/Test-SST_Mat22u.cpp | 439 ++ ZTestSuite/Test-SST_Mat33d.cpp | 1002 +++++ ZTestSuite/Test-SST_Mat33f.cpp | 1002 +++++ ZTestSuite/Test-SST_Mat33i.cpp | 719 +++ ZTestSuite/Test-SST_Mat33u.cpp | 643 +++ ZTestSuite/Test-SST_Mat44d.cpp | 1435 ++++++ ZTestSuite/Test-SST_Mat44f.cpp | 1435 ++++++ ZTestSuite/Test-SST_Mat44i.cpp | 1026 +++++ ZTestSuite/Test-SST_Mat44u.cpp | 915 ++++ ZTestSuite/Test-SST_Math.cpp | 571 +++ ZTestSuite/Test-SST_SafeArithmetic.cpp | 387 ++ ZTestSuite/Test-SST_Transform.cpp | 615 +++ ZTestSuite/Test-SST_Vec2d.cpp | 749 ++++ ZTestSuite/Test-SST_Vec2f.cpp | 749 ++++ ZTestSuite/Test-SST_Vec2i.cpp | 451 ++ ZTestSuite/Test-SST_Vec2u.cpp | 318 ++ ZTestSuite/Test-SST_Vec3d.cpp | 888 ++++ ZTestSuite/Test-SST_Vec3f.cpp | 888 ++++ ZTestSuite/Test-SST_Vec3i.cpp | 502 +++ ZTestSuite/Test-SST_Vec3u.cpp | 354 ++ ZTestSuite/Test-SST_Vec4d.cpp | 859 ++++ ZTestSuite/Test-SST_Vec4f.cpp | 859 ++++ ZTestSuite/Test-SST_Vec4i.cpp | 553 +++ ZTestSuite/Test-SST_Vec4u.cpp | 390 ++ ZTestSuite/Test-ZAlloc.cpp | 100 + ZTestSuite/Test-ZAllocWindow.cpp | 120 + ZTestSuite/Test-ZArray.cpp | 548 +++ ZTestSuite/Test-ZArrayAlgo.cpp | 3163 +++++++++++++ ZTestSuite/Test-ZAssert.cpp | 60 + ZTestSuite/Test-ZBasicString.cpp | 660 +++ ZTestSuite/Test-ZBasicStringAlgo.cpp | 1903 ++++++++ ZTestSuite/Test-ZBinaryDataWriter.cpp | 244 + ZTestSuite/Test-ZConcurrency.cpp | 241 + ZTestSuite/Test-ZHashMap.cpp | 388 ++ ZTestSuite/Test-ZIniReader.cpp | 183 + ZTestSuite/Test-ZIniWriter.cpp | 104 + ZTestSuite/Test-ZJSONReader.cpp | 25 + ZTestSuite/Test-ZJSONWriter.cpp | 25 + ZTestSuite/Test-ZKVTree.cpp | 402 ++ ZTestSuite/Test-ZList.cpp | 416 ++ ZTestSuite/Test-ZListAlgo.cpp | 1143 +++++ ZTestSuite/Test-ZName.cpp | 96 + ZTestSuite/Test-ZRandomGenerator.cpp | 371 ++ ZTestSuite/Test-ZReferenceCounter.cpp | 106 + ZTestSuite/Test-ZRegistry.cpp | 89 + ZTestSuite/Test-ZRingBuffer.cpp | 1307 ++++++ ZTestSuite/Test-ZSimplexNoise.cpp | 124 + ZTestSuite/Test-ZSlabAllocator.cpp | 125 + ZTestSuite/Test-ZSmartPointer.cpp | 490 +++ ZTestSuite/Test-ZTaskStream.cpp | 207 + ZTestSuite/Test-ZWeakPointer.cpp | 383 ++ ZTestSuite/Test-ZXMLReader.cpp | 142 + ZTestSuite/Test-ZXMLWriter.cpp | 73 + ZTestSuite/ZTestSuite.vcxproj | 300 ++ ZTestSuite/ZTestSuite.vcxproj.filters | 278 ++ ZTestSuite/ZTestSuiteMain.cpp | 320 ++ ZTestSuite/ZUnitTest.cpp | 57 + ZTestSuite/ZUnitTest.hpp | 76 + .../obj/x86-64/release/Test-SST_Atomic.o | Bin 0 -> 14432 bytes .../obj/x86-64/release/Test-SST_Endian.o | Bin 0 -> 5512 bytes .../obj/x86-64/release/Test-SST_FileSys.o | Bin 0 -> 7168 bytes .../x86-64/release/Test-SST_SafeArithmetic.o | Bin 0 -> 17184 bytes ZTestSuite/obj/x86-64/release/Test-ZAlloc.o | Bin 0 -> 7840 bytes .../obj/x86-64/release/Test-ZAllocWindow.o | Bin 0 -> 9904 bytes ZTestSuite/obj/x86-64/release/Test-ZArray.o | Bin 0 -> 114736 bytes .../obj/x86-64/release/Test-ZArrayAlgo.o | Bin 0 -> 394272 bytes ZTestSuite/obj/x86-64/release/Test-ZAssert.o | Bin 0 -> 3304 bytes .../obj/x86-64/release/Test-ZBasicString.o | Bin 0 -> 133416 bytes .../x86-64/release/Test-ZBasicStringAlgo.o | Bin 0 -> 385352 bytes .../obj/x86-64/release/Test-ZConcurrency.o | Bin 0 -> 11352 bytes ZTestSuite/obj/x86-64/release/Test-ZHashMap.o | Bin 0 -> 170808 bytes .../obj/x86-64/release/Test-ZIniReader.o | Bin 0 -> 98160 bytes .../obj/x86-64/release/Test-ZIniWriter.o | Bin 0 -> 31840 bytes .../obj/x86-64/release/Test-ZJSONReader.o | Bin 0 -> 2944 bytes .../obj/x86-64/release/Test-ZJSONWriter.o | Bin 0 -> 2944 bytes ZTestSuite/obj/x86-64/release/Test-ZKVTree.o | Bin 0 -> 130736 bytes ZTestSuite/obj/x86-64/release/Test-ZList.o | Bin 0 -> 88224 bytes .../obj/x86-64/release/Test-ZListAlgo.o | Bin 0 -> 120792 bytes ZTestSuite/sst_fs/file1.txt | 1 + ZTestSuite/sst_fs/file2.txt | 0 ZTestSuite/test1.xml | 40 + ZTestSuite/testAttributes.xml | 18 + ZUtil/Makefile | 54 + ZUtil/ZAlloc.cpp | 288 ++ ZUtil/ZAllocWindow.cpp | 230 + ZUtil/ZBinaryBufferReader.cpp | 148 + ZUtil/ZBinaryBufferWriter.cpp | 148 + ZUtil/ZBinaryFileReader.cpp | 155 + ZUtil/ZBinaryFileWriter.cpp | 160 + ZUtil/ZConcurrency.cpp | 50 + ZUtil/ZEvent.cpp | 34 + ZUtil/ZIniReader.cpp | 256 ++ ZUtil/ZIniWriter.cpp | 68 + ZUtil/ZJSONReader.cpp | 81 + ZUtil/ZJSONWriter.cpp | 19 + ZUtil/ZKVTree.cpp | 547 +++ ZUtil/ZLog.cpp | 306 ++ ZUtil/ZMutex.cpp | 42 + ZUtil/ZName.cpp | 207 + ZUtil/ZRandomGenerator.cpp | 213 + ZUtil/ZReadWriteLock.cpp | 33 + ZUtil/ZRegistry.cpp | 104 + ZUtil/ZSemaphore.cpp | 35 + ZUtil/ZSimplexNoise.cpp | 38 + ZUtil/ZSimplexNoiseMap.cpp | 218 + ZUtil/ZTaskStream.cpp | 360 ++ ZUtil/ZThread.cpp | 322 ++ ZUtil/ZUtil.vcxproj | 252 ++ ZUtil/ZUtil.vcxproj.filters | 278 ++ ZUtil/ZXMLReader.cpp | 109 + ZUtil/ZXMLWriter.cpp | 96 + ZUtil/obj/x86-64/release/ZAlloc.o | Bin 0 -> 5120 bytes ZUtil/obj/x86-64/release/ZAllocWindow.o | Bin 0 -> 3888 bytes .../obj/x86-64/release/ZBinaryBufferReader.o | Bin 0 -> 8496 bytes .../obj/x86-64/release/ZBinaryBufferWriter.o | Bin 0 -> 7696 bytes ZUtil/obj/x86-64/release/ZBinaryFileReader.o | Bin 0 -> 9440 bytes ZUtil/obj/x86-64/release/ZBinaryFileWriter.o | Bin 0 -> 9048 bytes ZUtil/obj/x86-64/release/ZConcurrency.o | Bin 0 -> 3856 bytes ZUtil/obj/x86-64/release/ZEvent.o | Bin 0 -> 2976 bytes ZUtil/obj/x86-64/release/ZIniReader.o | Bin 0 -> 157144 bytes ZUtil/obj/x86-64/release/ZIniWriter.o | Bin 0 -> 43288 bytes ZUtil/obj/x86-64/release/ZJSONReader.o | Bin 0 -> 54320 bytes ZUtil/obj/x86-64/release/ZJSONWriter.o | Bin 0 -> 25848 bytes ZUtil/obj/x86-64/release/ZKVTree.o | Bin 0 -> 128768 bytes ZUtil/obj/x86-64/release/ZLog.o | Bin 0 -> 98768 bytes ZUtil/obj/x86-64/release/ZMutex.o | Bin 0 -> 3008 bytes ZUtil/obj/x86-64/release/ZName.o | Bin 0 -> 21592 bytes ZUtil/obj/x86-64/release/ZRandomGenerator.o | Bin 0 -> 9016 bytes ZUtil/obj/x86-64/release/ZReadWriteLock.o | Bin 0 -> 3224 bytes ZUtil/obj/x86-64/release/ZRegistry.o | Bin 0 -> 41336 bytes ZUtil/obj/x86-64/release/ZSemaphore.o | Bin 0 -> 2936 bytes ZUtil/obj/x86-64/release/ZSimplexNoise.o | Bin 0 -> 9192 bytes ZUtil/obj/x86-64/release/ZSimplexNoiseMap.o | Bin 0 -> 36208 bytes ZUtil/obj/x86-64/release/ZTaskStream.o | Bin 0 -> 86960 bytes ZUtil/obj/x86-64/release/ZThread.o | Bin 0 -> 83912 bytes ZUtil/obj/x86-64/release/ZXMLReader.o | Bin 0 -> 102776 bytes ZUtil/obj/x86-64/release/ZXMLWriter.o | Bin 0 -> 39904 bytes libsst-atomic/Makefile | 48 + libsst-atomic/SST_Atomic_arm.asm | 233 + libsst-atomic/SST_Atomic_ia64.asm | 265 ++ libsst-atomic/SST_Atomic_mips.asm | 219 + libsst-atomic/SST_Atomic_mips64.asm | 277 ++ libsst-atomic/SST_Atomic_ppc.asm | 201 + libsst-atomic/SST_Atomic_sparc.asm | 214 + libsst-atomic/SST_Atomic_sparc64.asm | 254 ++ libsst-atomic/SST_Atomic_x86-64-win64.asm | 237 + libsst-atomic/SST_Atomic_x86-64.asm | 285 ++ libsst-atomic/SST_Atomic_x86.asm | 271 ++ libsst-atomic/libsst-atomic.vcxproj | 151 + libsst-atomic/libsst-atomic.vcxproj.filters | 26 + .../obj/x86-64/release/SST_Atomic_x86-64.o | Bin 0 -> 2864 bytes libsst-concurrency/Makefile | 42 + libsst-concurrency/SST_Event_POSIX.c | 138 + libsst-concurrency/SST_Event_Solaris.c | 125 + libsst-concurrency/SST_Event_Win32.c | 74 + libsst-concurrency/SST_Mutex_POSIX.c | 70 + libsst-concurrency/SST_Mutex_Solaris.c | 68 + libsst-concurrency/SST_Mutex_Win32.c | 77 + libsst-concurrency/SST_Once.c | 89 + libsst-concurrency/SST_ReadWriteLock.c | 162 + libsst-concurrency/SST_Semaphore_MacOSX.c | 164 + libsst-concurrency/SST_Semaphore_POSIX.c | 126 + libsst-concurrency/SST_Semaphore_Solaris.c | 127 + libsst-concurrency/SST_Semaphore_Win32.c | 66 + libsst-concurrency/SST_TLS_POSIX.c | 70 + libsst-concurrency/SST_TLS_Solaris.c | 66 + libsst-concurrency/SST_TLS_Win32.c | 59 + libsst-concurrency/SST_ThreadBarrier.c | 150 + libsst-concurrency/SST_Thread_POSIX.c | 158 + libsst-concurrency/SST_Thread_Solaris.c | 127 + libsst-concurrency/SST_Thread_Win32.c | 166 + libsst-concurrency/libsst-concurrency.vcxproj | 183 + .../libsst-concurrency.vcxproj.filters | 71 + .../obj/x86-64/release/SST_Event_POSIX.o | Bin 0 -> 3520 bytes .../obj/x86-64/release/SST_Mutex_POSIX.o | Bin 0 -> 2424 bytes .../obj/x86-64/release/SST_Once.o | Bin 0 -> 1928 bytes .../obj/x86-64/release/SST_ReadWriteLock.o | Bin 0 -> 2936 bytes .../obj/x86-64/release/SST_Semaphore_POSIX.o | Bin 0 -> 2992 bytes .../obj/x86-64/release/SST_TLS_POSIX.o | Bin 0 -> 2264 bytes .../obj/x86-64/release/SST_ThreadBarrier.o | Bin 0 -> 3000 bytes .../obj/x86-64/release/SST_Thread_POSIX.o | Bin 0 -> 3320 bytes libsst-concurrency/sources-POSIX.mk | 30 + libsst-concurrency/sources-Solaris.mk | 23 + libsst-concurrency/sources-Win32.mk | 23 + libsst-concurrency/sources-common.mk | 21 + libsst-concurrency/timespecadd.h | 45 + libsst-crypto/Makefile | 39 + libsst-crypto/SST_Hash.c | 181 + libsst-crypto/libsst-crypto.vcxproj | 173 + libsst-crypto/libsst-crypto.vcxproj.filters | 26 + libsst-crypto/obj/x86-64/release/SST_Hash.o | Bin 0 -> 3472 bytes libsst-glapi/GLAPIPrivate.h | 59 + libsst-glapi/Makefile | 53 + libsst-glapi/SST_GLAPIContext.c | 228 + libsst-glapi/SST_GLAPIResolve_MacOSX.c | 65 + libsst-glapi/SST_GLAPIResolve_POSIX.c | 77 + libsst-glapi/SST_GLAPIResolve_Win32.c | 83 + libsst-glapi/SST_GLAPIStruct.c | 335 ++ libsst-glapi/gl33.txt | 388 ++ libsst-glapi/libsst-glapi.vcxproj | 180 + libsst-glapi/libsst-glapi.vcxproj.filters | 53 + libsst-glapi/libsst-glapi.vcxproj.user | 4 + .../obj/x86-64/release/SST_GLAPIContext.o | Bin 0 -> 4152 bytes .../x86-64/release/SST_GLAPIResolve_POSIX.o | Bin 0 -> 2328 bytes .../obj/x86-64/release/SST_GLAPIStruct.o | Bin 0 -> 33032 bytes libsst-glapi/parsegl.c | 356 ++ libsst-glapi/sources-MacOSX.mk | 18 + libsst-glapi/sources-POSIX.mk | 19 + libsst-glapi/sources-Win32.mk | 18 + libsst-math/Makefile | 370 ++ libsst-math/MatrixNxN.py | 1702 +++++++ libsst-math/SST_Geo.c | 411 ++ libsst-math/SST_Mat22d.c | 396 ++ libsst-math/SST_Mat22d_benchmark.c | 408 ++ libsst-math/SST_Mat22f.c | 396 ++ libsst-math/SST_Mat22f_benchmark.c | 408 ++ libsst-math/SST_Mat22i.c | 202 + libsst-math/SST_Mat22i_benchmark.c | 349 ++ libsst-math/SST_Mat22u.c | 185 + libsst-math/SST_Mat22u_benchmark.c | 345 ++ libsst-math/SST_Mat33d.c | 647 +++ libsst-math/SST_Mat33d_benchmark.c | 601 +++ libsst-math/SST_Mat33f.c | 647 +++ libsst-math/SST_Mat33f_benchmark.c | 601 +++ libsst-math/SST_Mat33i.c | 273 ++ libsst-math/SST_Mat33i_benchmark.c | 498 +++ libsst-math/SST_Mat33u.c | 256 ++ libsst-math/SST_Mat33u_benchmark.c | 494 +++ libsst-math/SST_Mat44d.c | 946 ++++ libsst-math/SST_Mat44d_benchmark.c | 856 ++++ libsst-math/SST_Mat44f.c | 946 ++++ libsst-math/SST_Mat44f_benchmark.c | 856 ++++ libsst-math/SST_Mat44i.c | 377 ++ libsst-math/SST_Mat44i_benchmark.c | 693 +++ libsst-math/SST_Mat44u.c | 354 ++ libsst-math/SST_Mat44u_benchmark.c | 689 +++ libsst-math/SST_Transform.c | 544 +++ libsst-math/SST_Vec2d.c | 467 ++ libsst-math/SST_Vec2f.c | 467 ++ libsst-math/SST_Vec2i.c | 322 ++ libsst-math/SST_Vec2u.c | 268 ++ libsst-math/SST_Vec3d.c | 553 +++ libsst-math/SST_Vec3f.c | 553 +++ libsst-math/SST_Vec3i.c | 373 ++ libsst-math/SST_Vec3u.c | 319 ++ libsst-math/SST_Vec4d.c | 458 ++ libsst-math/SST_Vec4f.c | 458 ++ libsst-math/SST_Vec4i.c | 391 ++ libsst-math/SST_Vec4u.c | 337 ++ libsst-math/SST_VectorN.c | 452 ++ libsst-math/VectorN.py | 1589 +++++++ libsst-math/dump_MatNN_headers.sh | 216 + libsst-math/dump_VecN_headers.sh | 197 + libsst-math/libsst-math.vcxproj | 224 + libsst-math/libsst-math.vcxproj.filters | 122 + libsst-math/obj/x86-64/release/SST_Geo.o | Bin 0 -> 12104 bytes libsst-math/obj/x86-64/release/SST_Mat22d.o | Bin 0 -> 9960 bytes libsst-math/obj/x86-64/release/SST_Mat22f.o | Bin 0 -> 9936 bytes libsst-math/obj/x86-64/release/SST_Mat22i.o | Bin 0 -> 5056 bytes libsst-math/obj/x86-64/release/SST_Mat22u.o | Bin 0 -> 4536 bytes libsst-math/obj/x86-64/release/SST_Mat33d.o | Bin 0 -> 18072 bytes libsst-math/obj/x86-64/release/SST_Mat33f.o | Bin 0 -> 17488 bytes libsst-math/obj/x86-64/release/SST_Mat33i.o | Bin 0 -> 7600 bytes libsst-math/obj/x86-64/release/SST_Mat33u.o | Bin 0 -> 6616 bytes libsst-math/obj/x86-64/release/SST_Mat44d.o | Bin 0 -> 31176 bytes libsst-math/obj/x86-64/release/SST_Mat44f.o | Bin 0 -> 28496 bytes libsst-math/obj/x86-64/release/SST_Mat44i.o | Bin 0 -> 11880 bytes libsst-math/obj/x86-64/release/SST_Mat44u.o | Bin 0 -> 9888 bytes .../obj/x86-64/release/SST_Transform.o | Bin 0 -> 16144 bytes libsst-math/obj/x86-64/release/SST_Vec2d.o | Bin 0 -> 11432 bytes libsst-math/obj/x86-64/release/SST_Vec2f.o | Bin 0 -> 11344 bytes libsst-math/obj/x86-64/release/SST_Vec2i.o | Bin 0 -> 6720 bytes libsst-math/obj/x86-64/release/SST_Vec2u.o | Bin 0 -> 5744 bytes libsst-math/obj/x86-64/release/SST_Vec3d.o | Bin 0 -> 13656 bytes libsst-math/obj/x86-64/release/SST_Vec3f.o | Bin 0 -> 13520 bytes libsst-math/obj/x86-64/release/SST_Vec3i.o | Bin 0 -> 7192 bytes libsst-math/obj/x86-64/release/SST_Vec3u.o | Bin 0 -> 6232 bytes libsst-math/obj/x86-64/release/SST_Vec4d.o | Bin 0 -> 10576 bytes libsst-math/obj/x86-64/release/SST_Vec4f.o | Bin 0 -> 10512 bytes libsst-math/obj/x86-64/release/SST_Vec4i.o | Bin 0 -> 7672 bytes libsst-math/obj/x86-64/release/SST_Vec4u.o | Bin 0 -> 6712 bytes libsst-math/obj/x86-64/release/SST_VectorN.o | Bin 0 -> 15304 bytes libsst-math/test.c | 41 + libsst-net/Makefile | 47 + libsst-net/POSIXPrivate.h | 44 + libsst-net/PlatformPrivate.h | 98 + libsst-net/SST_NetAddress.c | 292 ++ libsst-net/SST_NetInit_Generic.c | 29 + libsst-net/SST_NetInit_Win32.c | 36 + libsst-net/SST_NetResult_POSIX.c | 64 + libsst-net/SST_NetResult_Win32.c | 67 + libsst-net/SST_NetSocket.c | 309 ++ libsst-net/SST_Sockets_Win32.c | 772 ++++ libsst-net/Win32Private.h | 40 + libsst-net/libsst-net.vcxproj | 163 + libsst-net/libsst-net.vcxproj.filters | 63 + .../obj/x86-64/release/SST_NetAddress.o | Bin 0 -> 4544 bytes .../obj/x86-64/release/SST_NetInit_Generic.o | Bin 0 -> 1360 bytes .../obj/x86-64/release/SST_NetResult_POSIX.o | Bin 0 -> 5472 bytes libsst-net/obj/x86-64/release/SST_NetSocket.o | Bin 0 -> 6544 bytes libsst-net/sources-POSIX.mk | 19 + libsst-os/Makefile | 44 + libsst-os/POSIXPrivate.h | 57 + libsst-os/SST_Alloc.c | 118 + libsst-os/SST_Assert.c | 44 + libsst-os/SST_Assert_Generic.c | 74 + libsst-os/SST_Assert_Win32.c | 157 + libsst-os/SST_CPUCache_arm.asm | 41 + libsst-os/SST_CPUCache_ia64.asm | 38 + libsst-os/SST_CPUCache_mips.asm | 46 + libsst-os/SST_CPUCache_ppc.asm | 41 + libsst-os/SST_CPUCache_sparc.asm | 50 + libsst-os/SST_CPUCache_sparc64.asm | 49 + libsst-os/SST_CPUCache_x86-64-win64.asm | 76 + libsst-os/SST_CPUCache_x86-64.asm | 78 + libsst-os/SST_CPUCache_x86.asm | 77 + libsst-os/SST_CPU_POSIX.c | 94 + libsst-os/SST_CPU_Win32.c | 354 ++ libsst-os/SST_DynLib_POSIX.c | 77 + libsst-os/SST_DynLib_Win32.c | 66 + libsst-os/SST_Endian.c | 70 + libsst-os/SST_FileSys_POSIX.c | 191 + libsst-os/SST_FileSys_Win32.c | 164 + libsst-os/SST_File_POSIX.c | 350 ++ libsst-os/SST_File_Win32.c | 370 ++ libsst-os/SST_Mmap_POSIX.c | 170 + libsst-os/SST_Mmap_Win32.c | 188 + libsst-os/SST_OSInit.c | 33 + libsst-os/SST_SafeArithmetic.c | 407 ++ libsst-os/SST_SysMem_POSIX.c | 147 + libsst-os/SST_SysMem_Win32.c | 155 + libsst-os/SST_Time_MacOSX.c | 60 + libsst-os/SST_Time_POSIX.c | 85 + libsst-os/SST_Time_Win32.c | 80 + libsst-os/SST_User_POSIX.c | 152 + libsst-os/SST_User_Win32.c | 197 + libsst-os/Win32Private.h | 168 + libsst-os/libsst-os.vcxproj | 200 + libsst-os/libsst-os.vcxproj.filters | 115 + libsst-os/obj/x86-64/release/SST_Alloc.o | Bin 0 -> 3072 bytes libsst-os/obj/x86-64/release/SST_Assert.o | Bin 0 -> 1824 bytes .../obj/x86-64/release/SST_Assert_Generic.o | Bin 0 -> 2600 bytes .../obj/x86-64/release/SST_CPUCache_x86-64.o | Bin 0 -> 800 bytes libsst-os/obj/x86-64/release/SST_CPU_POSIX.o | Bin 0 -> 2648 bytes .../obj/x86-64/release/SST_DynLib_POSIX.o | Bin 0 -> 3144 bytes libsst-os/obj/x86-64/release/SST_Endian.o | Bin 0 -> 2360 bytes .../obj/x86-64/release/SST_FileSys_POSIX.o | Bin 0 -> 4336 bytes libsst-os/obj/x86-64/release/SST_File_POSIX.o | Bin 0 -> 6720 bytes libsst-os/obj/x86-64/release/SST_Mmap_POSIX.o | Bin 0 -> 5336 bytes libsst-os/obj/x86-64/release/SST_OSInit.o | Bin 0 -> 1736 bytes .../obj/x86-64/release/SST_SafeArithmetic.o | Bin 0 -> 5456 bytes .../obj/x86-64/release/SST_SysMem_POSIX.o | Bin 0 -> 3888 bytes libsst-os/obj/x86-64/release/SST_Time_POSIX.o | Bin 0 -> 2816 bytes libsst-os/obj/x86-64/release/SST_User_POSIX.o | Bin 0 -> 3232 bytes libsst-os/sources-POSIX.mk | 38 + libsst-os/sources-Solaris.mk | 18 + libsst-os/sources-Win32.mk | 28 + libsst-random/Makefile | 44 + libsst-random/RandomFuncTbl.h | 87 + libsst-random/SST_CMWC.c | 121 + libsst-random/SST_Mersenne.c | 143 + libsst-random/SST_PRNG.c | 157 + libsst-random/SST_SimplexNoise.c | 590 +++ libsst-random/SST_SmallPRNG.c | 100 + libsst-random/libsst-random.vcproj | 331 ++ libsst-random/libsst-random.vcxproj | 196 + libsst-random/libsst-random.vcxproj.filters | 44 + libsst-random/obj/x86-64/release/SST_CMWC.o | Bin 0 -> 3120 bytes .../obj/x86-64/release/SST_Mersenne.o | Bin 0 -> 3368 bytes libsst-random/obj/x86-64/release/SST_PRNG.o | Bin 0 -> 3680 bytes .../obj/x86-64/release/SST_SimplexNoise.o | Bin 0 -> 18056 bytes .../obj/x86-64/release/SST_SmallPRNG.o | Bin 0 -> 2992 bytes libsst-wm/API.c | 282 ++ libsst-wm/APIPrivate.h | 104 + libsst-wm/EventQueue.h | 147 + libsst-wm/MacOSX/MacOSXPrivate.h | 32 + libsst-wm/MacOSX/SST_WMEnum_MacOSX.m | 145 + libsst-wm/Makefile | 53 + libsst-wm/RaspPi/RaspPiPrivate.h | 80 + libsst-wm/RaspPi/SST_WMDialogBox_RaspPi.c | 49 + libsst-wm/RaspPi/SST_WMEnum_RaspPi.c | 144 + libsst-wm/RaspPi/SST_WMEvent_RaspPi.c | 60 + libsst-wm/RaspPi/SST_WMRender_RaspPi.c | 113 + libsst-wm/RaspPi/SST_WMVideoMode_RaspPi.c | 56 + libsst-wm/RaspPi/SST_WMWindow_RaspPi.c | 390 ++ libsst-wm/Win32/SST_WMDialogBox_Win32.c | 319 ++ libsst-wm/Win32/SST_WMEnum_Win32.c | 268 ++ libsst-wm/Win32/SST_WMEvent_Win32.c | 90 + libsst-wm/Win32/SST_WMNonPortable_Win32.c | 26 + libsst-wm/Win32/SST_WMOpenGL_Win32.c | 848 ++++ libsst-wm/Win32/SST_WMRender_Win32.c | 97 + libsst-wm/Win32/SST_WMVideoMode_Win32.c | 72 + libsst-wm/Win32/SST_WMWindow_Win32.c | 667 +++ libsst-wm/Win32/Win32Driver.c | 62 + libsst-wm/Win32/Win32Private.c | 1351 ++++++ libsst-wm/Win32/Win32Private.h | 267 ++ libsst-wm/Xlib/GLXPrivate.c | 374 ++ libsst-wm/Xlib/GLXPrivate.h | 95 + libsst-wm/Xlib/SST_WMDialogBox_Xlib.c | 49 + libsst-wm/Xlib/SST_WMEnum_Xlib.c | 166 + libsst-wm/Xlib/SST_WMEvent_Xlib.c | 482 ++ libsst-wm/Xlib/SST_WMNonPortable_Xlib.c | 38 + libsst-wm/Xlib/SST_WMOpenGL_Xlib.c | 315 ++ libsst-wm/Xlib/SST_WMRender_Xlib.c | 75 + libsst-wm/Xlib/SST_WMVideoMode_Xlib.c | 86 + libsst-wm/Xlib/SST_WMWindow_Xlib.c | 537 +++ libsst-wm/Xlib/XI2Private.c | 83 + libsst-wm/Xlib/XI2Private.h | 60 + libsst-wm/Xlib/XlibDriver.c | 76 + libsst-wm/Xlib/XlibPrivate.c | 91 + libsst-wm/Xlib/XlibPrivate.h | 186 + libsst-wm/Xlib/sources.mk | 32 + libsst-wm/libsst-wm.vcxproj | 208 + libsst-wm/libsst-wm.vcxproj.filters | 92 + libsst-wm/obj/x86-64/release/API.o | Bin 0 -> 8816 bytes .../obj/x86-64/release/Xlib/GLXPrivate.o | Bin 0 -> 8224 bytes .../release/Xlib/SST_WMDialogBox_Xlib.o | Bin 0 -> 1288 bytes .../obj/x86-64/release/Xlib/SST_WMEnum_Xlib.o | Bin 0 -> 3448 bytes .../x86-64/release/Xlib/SST_WMEvent_Xlib.o | Bin 0 -> 8528 bytes .../release/Xlib/SST_WMNonPortable_Xlib.o | Bin 0 -> 1416 bytes .../x86-64/release/Xlib/SST_WMOpenGL_Xlib.o | Bin 0 -> 3056 bytes .../x86-64/release/Xlib/SST_WMRender_Xlib.o | Bin 0 -> 1944 bytes .../release/Xlib/SST_WMVideoMode_Xlib.o | Bin 0 -> 2056 bytes .../x86-64/release/Xlib/SST_WMWindow_Xlib.o | Bin 0 -> 10304 bytes .../obj/x86-64/release/Xlib/XI2Private.o | Bin 0 -> 2920 bytes .../obj/x86-64/release/Xlib/XlibDriver.o | Bin 0 -> 2696 bytes .../obj/x86-64/release/Xlib/XlibPrivate.o | Bin 0 -> 5032 bytes libsst-wm/sources-MacOSX.mk | 26 + libsst-wm/sources-RaspPi.mk | 24 + libsst-wm/sources-Win32.mk | 26 + 945 files changed, 218160 insertions(+) create mode 100644 Bin/x86-64/libZNet.a create mode 100644 Bin/x86-64/libZUtil.a create mode 100644 Bin/x86-64/libsst-net.a create mode 100644 BuildConfig/Darwin-Libs.rules create mode 100644 BuildConfig/DetectCompiler.rules create mode 100644 BuildConfig/DetectLibs.rules create mode 100644 BuildConfig/DetectPlatform.rules create mode 100644 BuildConfig/DetectWinSys.rules create mode 100644 BuildConfig/GCC-Flags.rules create mode 100644 BuildConfig/Makefile.Android.arm create mode 100644 BuildConfig/Makefile.Darwin.x86 create mode 100644 BuildConfig/Makefile.Darwin.x86-64 create mode 100644 BuildConfig/Makefile.Linux.arm create mode 100644 BuildConfig/Makefile.Linux.ia64 create mode 100644 BuildConfig/Makefile.Linux.mips create mode 100644 BuildConfig/Makefile.Linux.mips64 create mode 100644 BuildConfig/Makefile.Linux.ppc create mode 100644 BuildConfig/Makefile.Linux.sparc create mode 100644 BuildConfig/Makefile.Linux.sparc64 create mode 100644 BuildConfig/Makefile.Linux.x86 create mode 100644 BuildConfig/Makefile.Linux.x86-64 create mode 100644 BuildConfig/Makefile.Solaris.sparc create mode 100644 BuildConfig/Makefile.Solaris.sparc64 create mode 100644 BuildConfig/Makefile.Solaris.x86 create mode 100644 BuildConfig/Makefile.Windows.x86 create mode 100644 BuildConfig/POSIX-Libs.rules create mode 100644 BuildConfig/RaspPi-Flags.rules create mode 100644 BuildConfig/Solaris-Libs.rules create mode 100644 BuildConfig/SunPro-Flags.rules create mode 100644 Include/ZBuild.hpp create mode 100644 Include/ZNet/ZNet.hpp create mode 100644 Include/ZNet/ZNetBandwidthMeter.hpp create mode 100644 Include/ZNet/ZNetClient.hpp create mode 100644 Include/ZNet/ZNetConsts.hpp create mode 100644 Include/ZNet/ZNetEvent.hpp create mode 100644 Include/ZNet/ZNetHost.hpp create mode 100644 Include/ZNet/ZNetPacket.hpp create mode 100644 Include/ZNet/ZNetPacketChannel.hpp create mode 100644 Include/ZNet/ZNetPeer.hpp create mode 100644 Include/ZNet/ZNetServer.hpp create mode 100644 Include/ZNet/ZNetUtil.hpp create mode 100644 Include/ZRenderer/ZDataBuffer.hpp create mode 100644 Include/ZRenderer/ZDataBufferBase.hpp create mode 100644 Include/ZRenderer/ZDimensionTexture.hpp create mode 100644 Include/ZRenderer/ZDimensionTextureBase.hpp create mode 100644 Include/ZRenderer/ZDrawParams.hpp create mode 100644 Include/ZRenderer/ZFrameBufferRenderTarget.hpp create mode 100644 Include/ZRenderer/ZFrameBufferRenderTargetBase.hpp create mode 100644 Include/ZRenderer/ZIndexParams.hpp create mode 100644 Include/ZRenderer/ZOpenGLDataBuffer.hpp create mode 100644 Include/ZRenderer/ZOpenGLDimensionTexture.hpp create mode 100644 Include/ZRenderer/ZOpenGLFrameBufferRenderTarget.hpp create mode 100644 Include/ZRenderer/ZOpenGLRenderBuffer.hpp create mode 100644 Include/ZRenderer/ZOpenGLRenderer.hpp create mode 100644 Include/ZRenderer/ZOpenGLSampler.hpp create mode 100644 Include/ZRenderer/ZOpenGLShader.hpp create mode 100644 Include/ZRenderer/ZOpenGLShaderProgram.hpp create mode 100644 Include/ZRenderer/ZOpenGLTextureRenderTarget.h create mode 100644 Include/ZRenderer/ZOpenGLVertexParams.hpp create mode 100644 Include/ZRenderer/ZOpenGLWindowRenderTarget.hpp create mode 100644 Include/ZRenderer/ZRenderBuffer.hpp create mode 100644 Include/ZRenderer/ZRenderTarget.hpp create mode 100644 Include/ZRenderer/ZRenderer.hpp create mode 100644 Include/ZRenderer/ZRendererBase.hpp create mode 100644 Include/ZRenderer/ZRendererBuild.hpp create mode 100644 Include/ZRenderer/ZRendererResource.hpp create mode 100644 Include/ZRenderer/ZSampler.hpp create mode 100644 Include/ZRenderer/ZSamplerBase.hpp create mode 100644 Include/ZRenderer/ZShader.hpp create mode 100644 Include/ZRenderer/ZShaderBase.hpp create mode 100644 Include/ZRenderer/ZShaderParams.hpp create mode 100644 Include/ZRenderer/ZShaderProgram.hpp create mode 100644 Include/ZRenderer/ZShaderProgramBase.hpp create mode 100644 Include/ZRenderer/ZTexture.hpp create mode 100644 Include/ZRenderer/ZVertexParams.hpp create mode 100644 Include/ZRenderer/ZWindowRenderTarget.hpp create mode 100644 Include/ZRenderer/ZWindowRenderTargetBase.hpp create mode 100644 Include/ZRendererUtil/ZFontRenderer.hpp create mode 100644 Include/ZRendererUtil/ZFontRendererBase.hpp create mode 100644 Include/ZRendererUtil/ZOutlineEvaluator.hpp create mode 100644 Include/ZRendererUtil/ZParticleEffect.h create mode 100644 Include/ZRendererUtil/ZParticleEmitter.h create mode 100644 Include/ZRendererUtil/ZParticleRenderStrategy.h create mode 100644 Include/ZRendererUtil/ZParticleSpawnStrategy.h create mode 100644 Include/ZRendererUtil/ZParticleStorageAllocator.h create mode 100644 Include/ZRendererUtil/ZParticleUpdateStrategy.h create mode 100644 Include/ZRendererUtil/ZPerspectiveCamera.hpp create mode 100644 Include/ZRendererUtil/ZSolidFontFace.hpp create mode 100644 Include/ZRendererUtil/ZSolidFontRenderer.hpp create mode 100644 Include/ZRendererUtil/ZStandardParticleRenderStrategy.h create mode 100644 Include/ZRendererUtil/ZStandardParticleSpawnStrategy.h create mode 100644 Include/ZRendererUtil/ZStandardParticleStorageAllocator.h create mode 100644 Include/ZRendererUtil/ZStandardParticleUpdateStrategy.h create mode 100644 Include/ZRendererUtil/ZStaticMesh.hpp create mode 100644 Include/ZRendererUtil/ZStaticMeshLoader.hpp create mode 100644 Include/ZRendererUtil/ZTessellator.hpp create mode 100644 Include/ZRendererUtil/ZTessellatorBase.hpp create mode 100644 Include/ZRendererUtil/ZTransformHierarchy.hpp create mode 100644 Include/ZRendererUtil/ZTriTessellator.hpp create mode 100644 Include/ZSimulation/ZEntity.hpp create mode 100644 Include/ZSimulation/ZMessageStream.hpp create mode 100644 Include/ZSimulation/ZNetworkEvent.hpp create mode 100644 Include/ZSimulation/ZNetworkRequest.hpp create mode 100644 Include/ZSimulation/ZNetworkService.hpp create mode 100644 Include/ZSimulation/ZNetworkUpdateStream.hpp create mode 100644 Include/ZSimulation/ZPropertyBuffer.cpp create mode 100644 Include/ZSimulation/ZPropertyBuffer.hpp create mode 100644 Include/ZSimulation/ZPropertyBufferUpdate.hpp create mode 100644 Include/ZSimulation/ZPropertyBufferUpdateQueue.hpp create mode 100644 Include/ZSimulation/ZRemotePeer.hpp create mode 100644 Include/ZSimulation/ZSimulation.hpp create mode 100644 Include/ZSimulation/ZSimulationDefs.hpp create mode 100644 Include/ZSimulation/ZStringBuffer.hpp create mode 100644 Include/ZUtil/ZAlloc.hpp create mode 100644 Include/ZUtil/ZAllocWindow.hpp create mode 100644 Include/ZUtil/ZAssert.hpp create mode 100644 Include/ZUtil/ZBinaryBufferReader.hpp create mode 100644 Include/ZUtil/ZBinaryBufferWriter.hpp create mode 100644 Include/ZUtil/ZBinaryFileReader.hpp create mode 100644 Include/ZUtil/ZBinaryFileWriter.hpp create mode 100644 Include/ZUtil/ZBinaryReader.hpp create mode 100644 Include/ZUtil/ZBinaryWriter.hpp create mode 100644 Include/ZUtil/ZBitmap.hpp create mode 100644 Include/ZUtil/ZConcurrency.hpp create mode 100644 Include/ZUtil/ZEvent.hpp create mode 100644 Include/ZUtil/ZIniReader.hpp create mode 100644 Include/ZUtil/ZIniWriter.hpp create mode 100644 Include/ZUtil/ZJSONReader.hpp create mode 100644 Include/ZUtil/ZJSONWriter.hpp create mode 100644 Include/ZUtil/ZKVTree.hpp create mode 100644 Include/ZUtil/ZLog.hpp create mode 100644 Include/ZUtil/ZMutex.hpp create mode 100644 Include/ZUtil/ZName.hpp create mode 100644 Include/ZUtil/ZNoise.hpp create mode 100644 Include/ZUtil/ZNoiseMap.hpp create mode 100644 Include/ZUtil/ZRandomGenerator.hpp create mode 100644 Include/ZUtil/ZReadWriteLock.hpp create mode 100644 Include/ZUtil/ZReferenceBuffer.hpp create mode 100644 Include/ZUtil/ZReferenceCounter.hpp create mode 100644 Include/ZUtil/ZRegistry.hpp create mode 100644 Include/ZUtil/ZSemaphore.hpp create mode 100644 Include/ZUtil/ZSimplexNoise.hpp create mode 100644 Include/ZUtil/ZSimplexNoiseMap.hpp create mode 100644 Include/ZUtil/ZSlabAllocator.hpp create mode 100644 Include/ZUtil/ZSmartPointer.hpp create mode 100644 Include/ZUtil/ZTaskStream.hpp create mode 100644 Include/ZUtil/ZThread.hpp create mode 100644 Include/ZUtil/ZUtil.hpp create mode 100644 Include/ZUtil/ZUtilBuild.hpp create mode 100644 Include/ZUtil/ZWeakPointer.hpp create mode 100644 Include/ZUtil/ZXMLReader.hpp create mode 100644 Include/ZUtil/ZXMLWriter.hpp create mode 100644 Lib/Include/AL/al.h create mode 100644 Lib/Include/AL/alc.h create mode 100644 Lib/Include/AL/alext.h create mode 100644 Lib/Include/AL/efx-creative.h create mode 100644 Lib/Include/AL/efx-presets.h create mode 100644 Lib/Include/AL/efx.h create mode 100644 Lib/Include/Box2D/Box2D.h create mode 100644 Lib/Include/Box2D/Collision/Shapes/b2ChainShape.h create mode 100644 Lib/Include/Box2D/Collision/Shapes/b2CircleShape.h create mode 100644 Lib/Include/Box2D/Collision/Shapes/b2EdgeShape.h create mode 100644 Lib/Include/Box2D/Collision/Shapes/b2PolygonShape.h create mode 100644 Lib/Include/Box2D/Collision/Shapes/b2Shape.h create mode 100644 Lib/Include/Box2D/Collision/b2BroadPhase.h create mode 100644 Lib/Include/Box2D/Collision/b2Collision.h create mode 100644 Lib/Include/Box2D/Collision/b2Distance.h create mode 100644 Lib/Include/Box2D/Collision/b2DynamicTree.h create mode 100644 Lib/Include/Box2D/Collision/b2TimeOfImpact.h create mode 100644 Lib/Include/Box2D/Common/b2BlockAllocator.h create mode 100644 Lib/Include/Box2D/Common/b2Draw.h create mode 100644 Lib/Include/Box2D/Common/b2GrowableStack.h create mode 100644 Lib/Include/Box2D/Common/b2Math.h create mode 100644 Lib/Include/Box2D/Common/b2Settings.h create mode 100644 Lib/Include/Box2D/Common/b2StackAllocator.h create mode 100644 Lib/Include/Box2D/Common/b2Timer.h create mode 100644 Lib/Include/Box2D/Dynamics/Contacts/b2ChainAndCircleContact.h create mode 100644 Lib/Include/Box2D/Dynamics/Contacts/b2ChainAndPolygonContact.h create mode 100644 Lib/Include/Box2D/Dynamics/Contacts/b2CircleContact.h create mode 100644 Lib/Include/Box2D/Dynamics/Contacts/b2Contact.h create mode 100644 Lib/Include/Box2D/Dynamics/Contacts/b2ContactSolver.h create mode 100644 Lib/Include/Box2D/Dynamics/Contacts/b2EdgeAndCircleContact.h create mode 100644 Lib/Include/Box2D/Dynamics/Contacts/b2EdgeAndPolygonContact.h create mode 100644 Lib/Include/Box2D/Dynamics/Contacts/b2PolygonAndCircleContact.h create mode 100644 Lib/Include/Box2D/Dynamics/Contacts/b2PolygonContact.h create mode 100644 Lib/Include/Box2D/Dynamics/Joints/b2DistanceJoint.h create mode 100644 Lib/Include/Box2D/Dynamics/Joints/b2FrictionJoint.h create mode 100644 Lib/Include/Box2D/Dynamics/Joints/b2GearJoint.h create mode 100644 Lib/Include/Box2D/Dynamics/Joints/b2Joint.h create mode 100644 Lib/Include/Box2D/Dynamics/Joints/b2MotorJoint.h create mode 100644 Lib/Include/Box2D/Dynamics/Joints/b2MouseJoint.h create mode 100644 Lib/Include/Box2D/Dynamics/Joints/b2PrismaticJoint.h create mode 100644 Lib/Include/Box2D/Dynamics/Joints/b2PulleyJoint.h create mode 100644 Lib/Include/Box2D/Dynamics/Joints/b2RevoluteJoint.h create mode 100644 Lib/Include/Box2D/Dynamics/Joints/b2RopeJoint.h create mode 100644 Lib/Include/Box2D/Dynamics/Joints/b2WeldJoint.h create mode 100644 Lib/Include/Box2D/Dynamics/Joints/b2WheelJoint.h create mode 100644 Lib/Include/Box2D/Dynamics/b2Body.h create mode 100644 Lib/Include/Box2D/Dynamics/b2ContactManager.h create mode 100644 Lib/Include/Box2D/Dynamics/b2Fixture.h create mode 100644 Lib/Include/Box2D/Dynamics/b2Island.h create mode 100644 Lib/Include/Box2D/Dynamics/b2TimeStep.h create mode 100644 Lib/Include/Box2D/Dynamics/b2World.h create mode 100644 Lib/Include/Box2D/Dynamics/b2WorldCallbacks.h create mode 100644 Lib/Include/Box2D/Rope/b2Rope.h create mode 100644 Lib/Include/CML/cml.h create mode 100644 Lib/Include/CML/constants.h create mode 100644 Lib/Include/CML/core/cml_assert.h create mode 100644 Lib/Include/CML/core/cml_meta.h create mode 100644 Lib/Include/CML/core/common.h create mode 100644 Lib/Include/CML/core/dynamic_1D.h create mode 100644 Lib/Include/CML/core/dynamic_2D.h create mode 100644 Lib/Include/CML/core/external_1D.h create mode 100644 Lib/Include/CML/core/external_2D.h create mode 100644 Lib/Include/CML/core/fixed_1D.h create mode 100644 Lib/Include/CML/core/fixed_2D.h create mode 100644 Lib/Include/CML/core/fwd.h create mode 100644 Lib/Include/CML/core/meta/common.h create mode 100644 Lib/Include/CML/core/meta/if.h create mode 100644 Lib/Include/CML/core/meta/switch.h create mode 100644 Lib/Include/CML/defaults.h create mode 100644 Lib/Include/CML/dynamic.h create mode 100644 Lib/Include/CML/et/array_promotions.h create mode 100644 Lib/Include/CML/et/scalar_ops.h create mode 100644 Lib/Include/CML/et/scalar_promotions.h create mode 100644 Lib/Include/CML/et/size_checking.h create mode 100644 Lib/Include/CML/et/tags.h create mode 100644 Lib/Include/CML/et/traits.h create mode 100644 Lib/Include/CML/external.h create mode 100644 Lib/Include/CML/fixed.h create mode 100644 Lib/Include/CML/mathlib/checking.h create mode 100644 Lib/Include/CML/mathlib/coord_conversion.h create mode 100644 Lib/Include/CML/mathlib/epsilon.h create mode 100644 Lib/Include/CML/mathlib/frustum.h create mode 100644 Lib/Include/CML/mathlib/helper.h create mode 100644 Lib/Include/CML/mathlib/interpolation.h create mode 100644 Lib/Include/CML/mathlib/mathlib.h create mode 100644 Lib/Include/CML/mathlib/matrix_basis.h create mode 100644 Lib/Include/CML/mathlib/matrix_concat.h create mode 100644 Lib/Include/CML/mathlib/matrix_misc.h create mode 100644 Lib/Include/CML/mathlib/matrix_ortho.h create mode 100644 Lib/Include/CML/mathlib/matrix_projection.h create mode 100644 Lib/Include/CML/mathlib/matrix_rotation.h create mode 100644 Lib/Include/CML/mathlib/matrix_transform.h create mode 100644 Lib/Include/CML/mathlib/matrix_translation.h create mode 100644 Lib/Include/CML/mathlib/misc.h create mode 100644 Lib/Include/CML/mathlib/picking.h create mode 100644 Lib/Include/CML/mathlib/projection.h create mode 100644 Lib/Include/CML/mathlib/quaternion_basis.h create mode 100644 Lib/Include/CML/mathlib/quaternion_rotation.h create mode 100644 Lib/Include/CML/mathlib/typedef.h create mode 100644 Lib/Include/CML/mathlib/vector_angle.h create mode 100644 Lib/Include/CML/mathlib/vector_misc.h create mode 100644 Lib/Include/CML/mathlib/vector_ortho.h create mode 100644 Lib/Include/CML/mathlib/vector_transform.h create mode 100644 Lib/Include/CML/matrix.h create mode 100644 Lib/Include/CML/matrix/class_ops.h create mode 100644 Lib/Include/CML/matrix/determinant.h create mode 100644 Lib/Include/CML/matrix/dynamic.h create mode 100644 Lib/Include/CML/matrix/external.h create mode 100644 Lib/Include/CML/matrix/fixed.h create mode 100644 Lib/Include/CML/matrix/inverse.h create mode 100644 Lib/Include/CML/matrix/lu.h create mode 100644 Lib/Include/CML/matrix/matop_macros.h create mode 100644 Lib/Include/CML/matrix/matrix_comparison.h create mode 100644 Lib/Include/CML/matrix/matrix_expr.h create mode 100644 Lib/Include/CML/matrix/matrix_functions.h create mode 100644 Lib/Include/CML/matrix/matrix_mul.h create mode 100644 Lib/Include/CML/matrix/matrix_ops.h create mode 100644 Lib/Include/CML/matrix/matrix_print.h create mode 100644 Lib/Include/CML/matrix/matrix_promotions.h create mode 100644 Lib/Include/CML/matrix/matrix_rowcol.h create mode 100644 Lib/Include/CML/matrix/matrix_traits.h create mode 100644 Lib/Include/CML/matrix/matrix_transpose.h create mode 100644 Lib/Include/CML/matrix/matrix_unroller.h create mode 100644 Lib/Include/CML/matvec/matvec_mul.h create mode 100644 Lib/Include/CML/matvec/matvec_promotions.h create mode 100644 Lib/Include/CML/quaternion.h create mode 100644 Lib/Include/CML/quaternion/conjugate.h create mode 100644 Lib/Include/CML/quaternion/inverse.h create mode 100644 Lib/Include/CML/quaternion/quaternion.h create mode 100644 Lib/Include/CML/quaternion/quaternion_comparison.h create mode 100644 Lib/Include/CML/quaternion/quaternion_dot.h create mode 100644 Lib/Include/CML/quaternion/quaternion_expr.h create mode 100644 Lib/Include/CML/quaternion/quaternion_functions.h create mode 100644 Lib/Include/CML/quaternion/quaternion_mul.h create mode 100644 Lib/Include/CML/quaternion/quaternion_ops.h create mode 100644 Lib/Include/CML/quaternion/quaternion_print.h create mode 100644 Lib/Include/CML/quaternion/quaternion_promotions.h create mode 100644 Lib/Include/CML/quaternion/quaternion_traits.h create mode 100644 Lib/Include/CML/quaternion/quatop_macros.h create mode 100644 Lib/Include/CML/util.h create mode 100644 Lib/Include/CML/vector.h create mode 100644 Lib/Include/CML/vector/class_ops.h create mode 100644 Lib/Include/CML/vector/dynamic.h create mode 100644 Lib/Include/CML/vector/external.h create mode 100644 Lib/Include/CML/vector/fixed.h create mode 100644 Lib/Include/CML/vector/vecop_macros.h create mode 100644 Lib/Include/CML/vector/vector_comparison.h create mode 100644 Lib/Include/CML/vector/vector_expr.h create mode 100644 Lib/Include/CML/vector/vector_functions.h create mode 100644 Lib/Include/CML/vector/vector_ops.h create mode 100644 Lib/Include/CML/vector/vector_print.h create mode 100644 Lib/Include/CML/vector/vector_products.h create mode 100644 Lib/Include/CML/vector/vector_promotions.h create mode 100644 Lib/Include/CML/vector/vector_traits.h create mode 100644 Lib/Include/CML/vector/vector_unroller.h create mode 100644 Lib/Include/FMOD/fmod.h create mode 100644 Lib/Include/FMOD/fmod.hpp create mode 100644 Lib/Include/FMOD/fmod_codec.h create mode 100644 Lib/Include/FMOD/fmod_dsp.h create mode 100644 Lib/Include/FMOD/fmod_errors.h create mode 100644 Lib/Include/FMOD/fmod_memoryinfo.h create mode 100644 Lib/Include/FMOD/fmod_output.h create mode 100644 Lib/Include/FreeImage.h create mode 100644 Lib/Include/Recast.h create mode 100644 Lib/Include/RecastAlloc.h create mode 100644 Lib/Include/RecastAssert.h create mode 100644 Lib/Include/ZSTL/ZArray.hpp create mode 100644 Lib/Include/ZSTL/ZArrayAlgo.hpp create mode 100644 Lib/Include/ZSTL/ZBasicString.hpp create mode 100644 Lib/Include/ZSTL/ZBasicStringAlgo.hpp create mode 100644 Lib/Include/ZSTL/ZHashMap.hpp create mode 100644 Lib/Include/ZSTL/ZList.hpp create mode 100644 Lib/Include/ZSTL/ZListAlgo.hpp create mode 100644 Lib/Include/ZSTL/ZPair.hpp create mode 100644 Lib/Include/ZSTL/ZRingBuffer.hpp create mode 100644 Lib/Include/ZSTL/ZSTL.hpp create mode 100644 Lib/Include/ZSTL/ZSTLCommon.hpp create mode 100644 Lib/Include/ZSTL/ZSTLInvalidPos.hpp create mode 100644 Lib/Include/ZSTL/ZString.hpp create mode 100644 Lib/Include/assimp/Compiler/poppack1.h create mode 100644 Lib/Include/assimp/Compiler/pushpack1.h create mode 100644 Lib/Include/assimp/DefaultLogger.hpp create mode 100644 Lib/Include/assimp/Exporter.hpp create mode 100644 Lib/Include/assimp/IOStream.hpp create mode 100644 Lib/Include/assimp/IOSystem.hpp create mode 100644 Lib/Include/assimp/Importer.hpp create mode 100644 Lib/Include/assimp/LogStream.hpp create mode 100644 Lib/Include/assimp/Logger.hpp create mode 100644 Lib/Include/assimp/NullLogger.hpp create mode 100644 Lib/Include/assimp/ProgressHandler.hpp create mode 100644 Lib/Include/assimp/ai_assert.h create mode 100644 Lib/Include/assimp/anim.h create mode 100644 Lib/Include/assimp/camera.h create mode 100644 Lib/Include/assimp/cexport.h create mode 100644 Lib/Include/assimp/cfileio.h create mode 100644 Lib/Include/assimp/cimport.h create mode 100644 Lib/Include/assimp/color4.h create mode 100644 Lib/Include/assimp/color4.inl create mode 100644 Lib/Include/assimp/config.h create mode 100644 Lib/Include/assimp/defs.h create mode 100644 Lib/Include/assimp/importerdesc.h create mode 100644 Lib/Include/assimp/light.h create mode 100644 Lib/Include/assimp/material.h create mode 100644 Lib/Include/assimp/material.inl create mode 100644 Lib/Include/assimp/matrix3x3.h create mode 100644 Lib/Include/assimp/matrix3x3.inl create mode 100644 Lib/Include/assimp/matrix4x4.h create mode 100644 Lib/Include/assimp/matrix4x4.inl create mode 100644 Lib/Include/assimp/mesh.h create mode 100644 Lib/Include/assimp/postprocess.h create mode 100644 Lib/Include/assimp/quaternion.h create mode 100644 Lib/Include/assimp/quaternion.inl create mode 100644 Lib/Include/assimp/scene.h create mode 100644 Lib/Include/assimp/texture.h create mode 100644 Lib/Include/assimp/types.h create mode 100644 Lib/Include/assimp/vector2.h create mode 100644 Lib/Include/assimp/vector2.inl create mode 100644 Lib/Include/assimp/vector3.h create mode 100644 Lib/Include/assimp/vector3.inl create mode 100644 Lib/Include/assimp/version.h create mode 100644 Lib/Include/enet/callbacks.h create mode 100644 Lib/Include/enet/enet.h create mode 100644 Lib/Include/enet/list.h create mode 100644 Lib/Include/enet/protocol.h create mode 100644 Lib/Include/enet/time.h create mode 100644 Lib/Include/enet/types.h create mode 100644 Lib/Include/enet/unix.h create mode 100644 Lib/Include/enet/utility.h create mode 100644 Lib/Include/enet/win32.h create mode 100644 Lib/Include/freetype/config/ftconfig.h create mode 100644 Lib/Include/freetype/config/ftheader.h create mode 100644 Lib/Include/freetype/config/ftmodule.h create mode 100644 Lib/Include/freetype/config/ftoption.h create mode 100644 Lib/Include/freetype/config/ftstdlib.h create mode 100644 Lib/Include/freetype/freetype.h create mode 100644 Lib/Include/freetype/ftadvanc.h create mode 100644 Lib/Include/freetype/ftbbox.h create mode 100644 Lib/Include/freetype/ftbdf.h create mode 100644 Lib/Include/freetype/ftbitmap.h create mode 100644 Lib/Include/freetype/ftcache.h create mode 100644 Lib/Include/freetype/ftchapters.h create mode 100644 Lib/Include/freetype/ftcid.h create mode 100644 Lib/Include/freetype/fterrdef.h create mode 100644 Lib/Include/freetype/fterrors.h create mode 100644 Lib/Include/freetype/ftgasp.h create mode 100644 Lib/Include/freetype/ftglyph.h create mode 100644 Lib/Include/freetype/ftgxval.h create mode 100644 Lib/Include/freetype/ftgzip.h create mode 100644 Lib/Include/freetype/ftimage.h create mode 100644 Lib/Include/freetype/ftincrem.h create mode 100644 Lib/Include/freetype/ftlcdfil.h create mode 100644 Lib/Include/freetype/ftlist.h create mode 100644 Lib/Include/freetype/ftlzw.h create mode 100644 Lib/Include/freetype/ftmac.h create mode 100644 Lib/Include/freetype/ftmm.h create mode 100644 Lib/Include/freetype/ftmodapi.h create mode 100644 Lib/Include/freetype/ftmoderr.h create mode 100644 Lib/Include/freetype/ftotval.h create mode 100644 Lib/Include/freetype/ftoutln.h create mode 100644 Lib/Include/freetype/ftpfr.h create mode 100644 Lib/Include/freetype/ftrender.h create mode 100644 Lib/Include/freetype/ftsizes.h create mode 100644 Lib/Include/freetype/ftsnames.h create mode 100644 Lib/Include/freetype/ftstroke.h create mode 100644 Lib/Include/freetype/ftsynth.h create mode 100644 Lib/Include/freetype/ftsystem.h create mode 100644 Lib/Include/freetype/fttrigon.h create mode 100644 Lib/Include/freetype/fttypes.h create mode 100644 Lib/Include/freetype/ftwinfnt.h create mode 100644 Lib/Include/freetype/ftxf86.h create mode 100644 Lib/Include/freetype/internal/autohint.h create mode 100644 Lib/Include/freetype/internal/ftcalc.h create mode 100644 Lib/Include/freetype/internal/ftdebug.h create mode 100644 Lib/Include/freetype/internal/ftdriver.h create mode 100644 Lib/Include/freetype/internal/ftgloadr.h create mode 100644 Lib/Include/freetype/internal/ftmemory.h create mode 100644 Lib/Include/freetype/internal/ftobjs.h create mode 100644 Lib/Include/freetype/internal/ftpic.h create mode 100644 Lib/Include/freetype/internal/ftrfork.h create mode 100644 Lib/Include/freetype/internal/ftserv.h create mode 100644 Lib/Include/freetype/internal/ftstream.h create mode 100644 Lib/Include/freetype/internal/fttrace.h create mode 100644 Lib/Include/freetype/internal/ftvalid.h create mode 100644 Lib/Include/freetype/internal/internal.h create mode 100644 Lib/Include/freetype/internal/pcftypes.h create mode 100644 Lib/Include/freetype/internal/psaux.h create mode 100644 Lib/Include/freetype/internal/pshints.h create mode 100644 Lib/Include/freetype/internal/services/svbdf.h create mode 100644 Lib/Include/freetype/internal/services/svcid.h create mode 100644 Lib/Include/freetype/internal/services/svgldict.h create mode 100644 Lib/Include/freetype/internal/services/svgxval.h create mode 100644 Lib/Include/freetype/internal/services/svkern.h create mode 100644 Lib/Include/freetype/internal/services/svmm.h create mode 100644 Lib/Include/freetype/internal/services/svotval.h create mode 100644 Lib/Include/freetype/internal/services/svpfr.h create mode 100644 Lib/Include/freetype/internal/services/svpostnm.h create mode 100644 Lib/Include/freetype/internal/services/svpscmap.h create mode 100644 Lib/Include/freetype/internal/services/svpsinfo.h create mode 100644 Lib/Include/freetype/internal/services/svsfnt.h create mode 100644 Lib/Include/freetype/internal/services/svttcmap.h create mode 100644 Lib/Include/freetype/internal/services/svtteng.h create mode 100644 Lib/Include/freetype/internal/services/svttglyf.h create mode 100644 Lib/Include/freetype/internal/services/svwinfnt.h create mode 100644 Lib/Include/freetype/internal/services/svxf86nm.h create mode 100644 Lib/Include/freetype/internal/sfnt.h create mode 100644 Lib/Include/freetype/internal/t1types.h create mode 100644 Lib/Include/freetype/internal/tttypes.h create mode 100644 Lib/Include/freetype/t1tables.h create mode 100644 Lib/Include/freetype/ttnameid.h create mode 100644 Lib/Include/freetype/tttables.h create mode 100644 Lib/Include/freetype/tttags.h create mode 100644 Lib/Include/freetype/ttunpat.h create mode 100644 Lib/Include/ft2build.h create mode 100644 Lib/Include/jansson.h create mode 100644 Lib/Include/jansson_config.h create mode 100644 Lib/Include/lua.h create mode 100644 Lib/Include/lua.hpp create mode 100644 Lib/Include/luaconf.h create mode 100644 Lib/Include/lualib.h create mode 100644 Lib/Include/physfs.h create mode 100644 Lib/Include/pstdbool.h create mode 100644 Lib/Include/rapidxml/rapidxml.hpp create mode 100644 Lib/Include/rapidxml/rapidxml_iterators.hpp create mode 100644 Lib/Include/rapidxml/rapidxml_print.hpp create mode 100644 Lib/Include/rapidxml/rapidxml_utils.hpp create mode 100644 Lib/Include/zconf.h create mode 100644 Lib/Include/zlib.h create mode 100644 Makefile create mode 100644 README.md create mode 100644 ZNet/Makefile create mode 100644 ZNet/ZNet.vcxproj create mode 100644 ZNet/ZNet.vcxproj.filters create mode 100644 ZNet/ZNetBandwidthMeter.cpp create mode 100644 ZNet/ZNetClient.cpp create mode 100644 ZNet/ZNetHost.cpp create mode 100644 ZNet/ZNetPacketChannel.cpp create mode 100644 ZNet/ZNetPeer.cpp create mode 100644 ZNet/ZNetPrivate.cpp create mode 100644 ZNet/ZNetPrivate.hpp create mode 100644 ZNet/ZNetServer.cpp create mode 100644 ZNet/obj/x86-64/release/ZNetBandwidthMeter.o create mode 100644 ZNet/obj/x86-64/release/ZNetClient.o create mode 100644 ZNet/obj/x86-64/release/ZNetHost.o create mode 100644 ZNet/obj/x86-64/release/ZNetPacketChannel.o create mode 100644 ZNet/obj/x86-64/release/ZNetPeer.o create mode 100644 ZNet/obj/x86-64/release/ZNetPrivate.o create mode 100644 ZNet/obj/x86-64/release/ZNetServer.o create mode 100644 ZTestSuite/FileSystemTestDir/ZFileSystemTest-001.txt create mode 100644 ZTestSuite/FileSystemTestDir/ZFileSystemTest-002 create mode 100644 ZTestSuite/FileSystemTestDir/ZFileSystemTest-7z.zep create mode 100644 ZTestSuite/FileSystemTestDir/ZFileSystemTest-ZIP.zep create mode 100644 ZTestSuite/FileSystemTestDir/test1.xml create mode 100644 ZTestSuite/FileSystemTestDir/testAttributes.xml create mode 100644 ZTestSuite/FileSystemTestDir/writedir/FileWriteTest create mode 100644 ZTestSuite/FileSystemTestDir/writedir/ZRegistryTestWrite.ini create mode 100644 ZTestSuite/Makefile create mode 100644 ZTestSuite/Test-SST_Atomic.cpp create mode 100644 ZTestSuite/Test-SST_Endian.cpp create mode 100644 ZTestSuite/Test-SST_FileSys.cpp create mode 100644 ZTestSuite/Test-SST_Geo.cpp create mode 100644 ZTestSuite/Test-SST_Mat22d.cpp create mode 100644 ZTestSuite/Test-SST_Mat22f.cpp create mode 100644 ZTestSuite/Test-SST_Mat22i.cpp create mode 100644 ZTestSuite/Test-SST_Mat22u.cpp create mode 100644 ZTestSuite/Test-SST_Mat33d.cpp create mode 100644 ZTestSuite/Test-SST_Mat33f.cpp create mode 100644 ZTestSuite/Test-SST_Mat33i.cpp create mode 100644 ZTestSuite/Test-SST_Mat33u.cpp create mode 100644 ZTestSuite/Test-SST_Mat44d.cpp create mode 100644 ZTestSuite/Test-SST_Mat44f.cpp create mode 100644 ZTestSuite/Test-SST_Mat44i.cpp create mode 100644 ZTestSuite/Test-SST_Mat44u.cpp create mode 100644 ZTestSuite/Test-SST_Math.cpp create mode 100644 ZTestSuite/Test-SST_SafeArithmetic.cpp create mode 100644 ZTestSuite/Test-SST_Transform.cpp create mode 100644 ZTestSuite/Test-SST_Vec2d.cpp create mode 100644 ZTestSuite/Test-SST_Vec2f.cpp create mode 100644 ZTestSuite/Test-SST_Vec2i.cpp create mode 100644 ZTestSuite/Test-SST_Vec2u.cpp create mode 100644 ZTestSuite/Test-SST_Vec3d.cpp create mode 100644 ZTestSuite/Test-SST_Vec3f.cpp create mode 100644 ZTestSuite/Test-SST_Vec3i.cpp create mode 100644 ZTestSuite/Test-SST_Vec3u.cpp create mode 100644 ZTestSuite/Test-SST_Vec4d.cpp create mode 100644 ZTestSuite/Test-SST_Vec4f.cpp create mode 100644 ZTestSuite/Test-SST_Vec4i.cpp create mode 100644 ZTestSuite/Test-SST_Vec4u.cpp create mode 100644 ZTestSuite/Test-ZAlloc.cpp create mode 100644 ZTestSuite/Test-ZAllocWindow.cpp create mode 100644 ZTestSuite/Test-ZArray.cpp create mode 100644 ZTestSuite/Test-ZArrayAlgo.cpp create mode 100644 ZTestSuite/Test-ZAssert.cpp create mode 100644 ZTestSuite/Test-ZBasicString.cpp create mode 100644 ZTestSuite/Test-ZBasicStringAlgo.cpp create mode 100644 ZTestSuite/Test-ZBinaryDataWriter.cpp create mode 100644 ZTestSuite/Test-ZConcurrency.cpp create mode 100644 ZTestSuite/Test-ZHashMap.cpp create mode 100644 ZTestSuite/Test-ZIniReader.cpp create mode 100644 ZTestSuite/Test-ZIniWriter.cpp create mode 100644 ZTestSuite/Test-ZJSONReader.cpp create mode 100644 ZTestSuite/Test-ZJSONWriter.cpp create mode 100644 ZTestSuite/Test-ZKVTree.cpp create mode 100644 ZTestSuite/Test-ZList.cpp create mode 100644 ZTestSuite/Test-ZListAlgo.cpp create mode 100644 ZTestSuite/Test-ZName.cpp create mode 100644 ZTestSuite/Test-ZRandomGenerator.cpp create mode 100644 ZTestSuite/Test-ZReferenceCounter.cpp create mode 100644 ZTestSuite/Test-ZRegistry.cpp create mode 100644 ZTestSuite/Test-ZRingBuffer.cpp create mode 100644 ZTestSuite/Test-ZSimplexNoise.cpp create mode 100644 ZTestSuite/Test-ZSlabAllocator.cpp create mode 100644 ZTestSuite/Test-ZSmartPointer.cpp create mode 100644 ZTestSuite/Test-ZTaskStream.cpp create mode 100644 ZTestSuite/Test-ZWeakPointer.cpp create mode 100644 ZTestSuite/Test-ZXMLReader.cpp create mode 100644 ZTestSuite/Test-ZXMLWriter.cpp create mode 100644 ZTestSuite/ZTestSuite.vcxproj create mode 100644 ZTestSuite/ZTestSuite.vcxproj.filters create mode 100644 ZTestSuite/ZTestSuiteMain.cpp create mode 100644 ZTestSuite/ZUnitTest.cpp create mode 100644 ZTestSuite/ZUnitTest.hpp create mode 100644 ZTestSuite/obj/x86-64/release/Test-SST_Atomic.o create mode 100644 ZTestSuite/obj/x86-64/release/Test-SST_Endian.o create mode 100644 ZTestSuite/obj/x86-64/release/Test-SST_FileSys.o create mode 100644 ZTestSuite/obj/x86-64/release/Test-SST_SafeArithmetic.o create mode 100644 ZTestSuite/obj/x86-64/release/Test-ZAlloc.o create mode 100644 ZTestSuite/obj/x86-64/release/Test-ZAllocWindow.o create mode 100644 ZTestSuite/obj/x86-64/release/Test-ZArray.o create mode 100644 ZTestSuite/obj/x86-64/release/Test-ZArrayAlgo.o create mode 100644 ZTestSuite/obj/x86-64/release/Test-ZAssert.o create mode 100644 ZTestSuite/obj/x86-64/release/Test-ZBasicString.o create mode 100644 ZTestSuite/obj/x86-64/release/Test-ZBasicStringAlgo.o create mode 100644 ZTestSuite/obj/x86-64/release/Test-ZConcurrency.o create mode 100644 ZTestSuite/obj/x86-64/release/Test-ZHashMap.o create mode 100644 ZTestSuite/obj/x86-64/release/Test-ZIniReader.o create mode 100644 ZTestSuite/obj/x86-64/release/Test-ZIniWriter.o create mode 100644 ZTestSuite/obj/x86-64/release/Test-ZJSONReader.o create mode 100644 ZTestSuite/obj/x86-64/release/Test-ZJSONWriter.o create mode 100644 ZTestSuite/obj/x86-64/release/Test-ZKVTree.o create mode 100644 ZTestSuite/obj/x86-64/release/Test-ZList.o create mode 100644 ZTestSuite/obj/x86-64/release/Test-ZListAlgo.o create mode 100644 ZTestSuite/sst_fs/file1.txt create mode 100644 ZTestSuite/sst_fs/file2.txt create mode 100644 ZTestSuite/test1.xml create mode 100644 ZTestSuite/testAttributes.xml create mode 100644 ZUtil/Makefile create mode 100644 ZUtil/ZAlloc.cpp create mode 100644 ZUtil/ZAllocWindow.cpp create mode 100644 ZUtil/ZBinaryBufferReader.cpp create mode 100644 ZUtil/ZBinaryBufferWriter.cpp create mode 100644 ZUtil/ZBinaryFileReader.cpp create mode 100644 ZUtil/ZBinaryFileWriter.cpp create mode 100644 ZUtil/ZConcurrency.cpp create mode 100644 ZUtil/ZEvent.cpp create mode 100644 ZUtil/ZIniReader.cpp create mode 100644 ZUtil/ZIniWriter.cpp create mode 100644 ZUtil/ZJSONReader.cpp create mode 100644 ZUtil/ZJSONWriter.cpp create mode 100644 ZUtil/ZKVTree.cpp create mode 100644 ZUtil/ZLog.cpp create mode 100644 ZUtil/ZMutex.cpp create mode 100644 ZUtil/ZName.cpp create mode 100644 ZUtil/ZRandomGenerator.cpp create mode 100644 ZUtil/ZReadWriteLock.cpp create mode 100644 ZUtil/ZRegistry.cpp create mode 100644 ZUtil/ZSemaphore.cpp create mode 100644 ZUtil/ZSimplexNoise.cpp create mode 100644 ZUtil/ZSimplexNoiseMap.cpp create mode 100644 ZUtil/ZTaskStream.cpp create mode 100644 ZUtil/ZThread.cpp create mode 100644 ZUtil/ZUtil.vcxproj create mode 100644 ZUtil/ZUtil.vcxproj.filters create mode 100644 ZUtil/ZXMLReader.cpp create mode 100644 ZUtil/ZXMLWriter.cpp create mode 100644 ZUtil/obj/x86-64/release/ZAlloc.o create mode 100644 ZUtil/obj/x86-64/release/ZAllocWindow.o create mode 100644 ZUtil/obj/x86-64/release/ZBinaryBufferReader.o create mode 100644 ZUtil/obj/x86-64/release/ZBinaryBufferWriter.o create mode 100644 ZUtil/obj/x86-64/release/ZBinaryFileReader.o create mode 100644 ZUtil/obj/x86-64/release/ZBinaryFileWriter.o create mode 100644 ZUtil/obj/x86-64/release/ZConcurrency.o create mode 100644 ZUtil/obj/x86-64/release/ZEvent.o create mode 100644 ZUtil/obj/x86-64/release/ZIniReader.o create mode 100644 ZUtil/obj/x86-64/release/ZIniWriter.o create mode 100644 ZUtil/obj/x86-64/release/ZJSONReader.o create mode 100644 ZUtil/obj/x86-64/release/ZJSONWriter.o create mode 100644 ZUtil/obj/x86-64/release/ZKVTree.o create mode 100644 ZUtil/obj/x86-64/release/ZLog.o create mode 100644 ZUtil/obj/x86-64/release/ZMutex.o create mode 100644 ZUtil/obj/x86-64/release/ZName.o create mode 100644 ZUtil/obj/x86-64/release/ZRandomGenerator.o create mode 100644 ZUtil/obj/x86-64/release/ZReadWriteLock.o create mode 100644 ZUtil/obj/x86-64/release/ZRegistry.o create mode 100644 ZUtil/obj/x86-64/release/ZSemaphore.o create mode 100644 ZUtil/obj/x86-64/release/ZSimplexNoise.o create mode 100644 ZUtil/obj/x86-64/release/ZSimplexNoiseMap.o create mode 100644 ZUtil/obj/x86-64/release/ZTaskStream.o create mode 100644 ZUtil/obj/x86-64/release/ZThread.o create mode 100644 ZUtil/obj/x86-64/release/ZXMLReader.o create mode 100644 ZUtil/obj/x86-64/release/ZXMLWriter.o create mode 100644 libsst-atomic/Makefile create mode 100644 libsst-atomic/SST_Atomic_arm.asm create mode 100644 libsst-atomic/SST_Atomic_ia64.asm create mode 100644 libsst-atomic/SST_Atomic_mips.asm create mode 100644 libsst-atomic/SST_Atomic_mips64.asm create mode 100644 libsst-atomic/SST_Atomic_ppc.asm create mode 100644 libsst-atomic/SST_Atomic_sparc.asm create mode 100644 libsst-atomic/SST_Atomic_sparc64.asm create mode 100644 libsst-atomic/SST_Atomic_x86-64-win64.asm create mode 100644 libsst-atomic/SST_Atomic_x86-64.asm create mode 100644 libsst-atomic/SST_Atomic_x86.asm create mode 100644 libsst-atomic/libsst-atomic.vcxproj create mode 100644 libsst-atomic/libsst-atomic.vcxproj.filters create mode 100644 libsst-atomic/obj/x86-64/release/SST_Atomic_x86-64.o create mode 100644 libsst-concurrency/Makefile create mode 100644 libsst-concurrency/SST_Event_POSIX.c create mode 100644 libsst-concurrency/SST_Event_Solaris.c create mode 100644 libsst-concurrency/SST_Event_Win32.c create mode 100644 libsst-concurrency/SST_Mutex_POSIX.c create mode 100644 libsst-concurrency/SST_Mutex_Solaris.c create mode 100644 libsst-concurrency/SST_Mutex_Win32.c create mode 100644 libsst-concurrency/SST_Once.c create mode 100644 libsst-concurrency/SST_ReadWriteLock.c create mode 100644 libsst-concurrency/SST_Semaphore_MacOSX.c create mode 100644 libsst-concurrency/SST_Semaphore_POSIX.c create mode 100644 libsst-concurrency/SST_Semaphore_Solaris.c create mode 100644 libsst-concurrency/SST_Semaphore_Win32.c create mode 100644 libsst-concurrency/SST_TLS_POSIX.c create mode 100644 libsst-concurrency/SST_TLS_Solaris.c create mode 100644 libsst-concurrency/SST_TLS_Win32.c create mode 100644 libsst-concurrency/SST_ThreadBarrier.c create mode 100644 libsst-concurrency/SST_Thread_POSIX.c create mode 100644 libsst-concurrency/SST_Thread_Solaris.c create mode 100644 libsst-concurrency/SST_Thread_Win32.c create mode 100644 libsst-concurrency/libsst-concurrency.vcxproj create mode 100644 libsst-concurrency/libsst-concurrency.vcxproj.filters create mode 100644 libsst-concurrency/obj/x86-64/release/SST_Event_POSIX.o create mode 100644 libsst-concurrency/obj/x86-64/release/SST_Mutex_POSIX.o create mode 100644 libsst-concurrency/obj/x86-64/release/SST_Once.o create mode 100644 libsst-concurrency/obj/x86-64/release/SST_ReadWriteLock.o create mode 100644 libsst-concurrency/obj/x86-64/release/SST_Semaphore_POSIX.o create mode 100644 libsst-concurrency/obj/x86-64/release/SST_TLS_POSIX.o create mode 100644 libsst-concurrency/obj/x86-64/release/SST_ThreadBarrier.o create mode 100644 libsst-concurrency/obj/x86-64/release/SST_Thread_POSIX.o create mode 100644 libsst-concurrency/sources-POSIX.mk create mode 100644 libsst-concurrency/sources-Solaris.mk create mode 100644 libsst-concurrency/sources-Win32.mk create mode 100644 libsst-concurrency/sources-common.mk create mode 100644 libsst-concurrency/timespecadd.h create mode 100644 libsst-crypto/Makefile create mode 100644 libsst-crypto/SST_Hash.c create mode 100644 libsst-crypto/libsst-crypto.vcxproj create mode 100644 libsst-crypto/libsst-crypto.vcxproj.filters create mode 100644 libsst-crypto/obj/x86-64/release/SST_Hash.o create mode 100644 libsst-glapi/GLAPIPrivate.h create mode 100644 libsst-glapi/Makefile create mode 100644 libsst-glapi/SST_GLAPIContext.c create mode 100644 libsst-glapi/SST_GLAPIResolve_MacOSX.c create mode 100644 libsst-glapi/SST_GLAPIResolve_POSIX.c create mode 100644 libsst-glapi/SST_GLAPIResolve_Win32.c create mode 100644 libsst-glapi/SST_GLAPIStruct.c create mode 100644 libsst-glapi/gl33.txt create mode 100644 libsst-glapi/libsst-glapi.vcxproj create mode 100644 libsst-glapi/libsst-glapi.vcxproj.filters create mode 100644 libsst-glapi/libsst-glapi.vcxproj.user create mode 100644 libsst-glapi/obj/x86-64/release/SST_GLAPIContext.o create mode 100644 libsst-glapi/obj/x86-64/release/SST_GLAPIResolve_POSIX.o create mode 100644 libsst-glapi/obj/x86-64/release/SST_GLAPIStruct.o create mode 100644 libsst-glapi/parsegl.c create mode 100644 libsst-glapi/sources-MacOSX.mk create mode 100644 libsst-glapi/sources-POSIX.mk create mode 100644 libsst-glapi/sources-Win32.mk create mode 100644 libsst-math/Makefile create mode 100644 libsst-math/MatrixNxN.py create mode 100644 libsst-math/SST_Geo.c create mode 100644 libsst-math/SST_Mat22d.c create mode 100644 libsst-math/SST_Mat22d_benchmark.c create mode 100644 libsst-math/SST_Mat22f.c create mode 100644 libsst-math/SST_Mat22f_benchmark.c create mode 100644 libsst-math/SST_Mat22i.c create mode 100644 libsst-math/SST_Mat22i_benchmark.c create mode 100644 libsst-math/SST_Mat22u.c create mode 100644 libsst-math/SST_Mat22u_benchmark.c create mode 100644 libsst-math/SST_Mat33d.c create mode 100644 libsst-math/SST_Mat33d_benchmark.c create mode 100644 libsst-math/SST_Mat33f.c create mode 100644 libsst-math/SST_Mat33f_benchmark.c create mode 100644 libsst-math/SST_Mat33i.c create mode 100644 libsst-math/SST_Mat33i_benchmark.c create mode 100644 libsst-math/SST_Mat33u.c create mode 100644 libsst-math/SST_Mat33u_benchmark.c create mode 100644 libsst-math/SST_Mat44d.c create mode 100644 libsst-math/SST_Mat44d_benchmark.c create mode 100644 libsst-math/SST_Mat44f.c create mode 100644 libsst-math/SST_Mat44f_benchmark.c create mode 100644 libsst-math/SST_Mat44i.c create mode 100644 libsst-math/SST_Mat44i_benchmark.c create mode 100644 libsst-math/SST_Mat44u.c create mode 100644 libsst-math/SST_Mat44u_benchmark.c create mode 100644 libsst-math/SST_Transform.c create mode 100644 libsst-math/SST_Vec2d.c create mode 100644 libsst-math/SST_Vec2f.c create mode 100644 libsst-math/SST_Vec2i.c create mode 100644 libsst-math/SST_Vec2u.c create mode 100644 libsst-math/SST_Vec3d.c create mode 100644 libsst-math/SST_Vec3f.c create mode 100644 libsst-math/SST_Vec3i.c create mode 100644 libsst-math/SST_Vec3u.c create mode 100644 libsst-math/SST_Vec4d.c create mode 100644 libsst-math/SST_Vec4f.c create mode 100644 libsst-math/SST_Vec4i.c create mode 100644 libsst-math/SST_Vec4u.c create mode 100644 libsst-math/SST_VectorN.c create mode 100644 libsst-math/VectorN.py create mode 100644 libsst-math/dump_MatNN_headers.sh create mode 100644 libsst-math/dump_VecN_headers.sh create mode 100644 libsst-math/libsst-math.vcxproj create mode 100644 libsst-math/libsst-math.vcxproj.filters create mode 100644 libsst-math/obj/x86-64/release/SST_Geo.o create mode 100644 libsst-math/obj/x86-64/release/SST_Mat22d.o create mode 100644 libsst-math/obj/x86-64/release/SST_Mat22f.o create mode 100644 libsst-math/obj/x86-64/release/SST_Mat22i.o create mode 100644 libsst-math/obj/x86-64/release/SST_Mat22u.o create mode 100644 libsst-math/obj/x86-64/release/SST_Mat33d.o create mode 100644 libsst-math/obj/x86-64/release/SST_Mat33f.o create mode 100644 libsst-math/obj/x86-64/release/SST_Mat33i.o create mode 100644 libsst-math/obj/x86-64/release/SST_Mat33u.o create mode 100644 libsst-math/obj/x86-64/release/SST_Mat44d.o create mode 100644 libsst-math/obj/x86-64/release/SST_Mat44f.o create mode 100644 libsst-math/obj/x86-64/release/SST_Mat44i.o create mode 100644 libsst-math/obj/x86-64/release/SST_Mat44u.o create mode 100644 libsst-math/obj/x86-64/release/SST_Transform.o create mode 100644 libsst-math/obj/x86-64/release/SST_Vec2d.o create mode 100644 libsst-math/obj/x86-64/release/SST_Vec2f.o create mode 100644 libsst-math/obj/x86-64/release/SST_Vec2i.o create mode 100644 libsst-math/obj/x86-64/release/SST_Vec2u.o create mode 100644 libsst-math/obj/x86-64/release/SST_Vec3d.o create mode 100644 libsst-math/obj/x86-64/release/SST_Vec3f.o create mode 100644 libsst-math/obj/x86-64/release/SST_Vec3i.o create mode 100644 libsst-math/obj/x86-64/release/SST_Vec3u.o create mode 100644 libsst-math/obj/x86-64/release/SST_Vec4d.o create mode 100644 libsst-math/obj/x86-64/release/SST_Vec4f.o create mode 100644 libsst-math/obj/x86-64/release/SST_Vec4i.o create mode 100644 libsst-math/obj/x86-64/release/SST_Vec4u.o create mode 100644 libsst-math/obj/x86-64/release/SST_VectorN.o create mode 100644 libsst-math/test.c create mode 100644 libsst-net/Makefile create mode 100644 libsst-net/POSIXPrivate.h create mode 100644 libsst-net/PlatformPrivate.h create mode 100644 libsst-net/SST_NetAddress.c create mode 100644 libsst-net/SST_NetInit_Generic.c create mode 100644 libsst-net/SST_NetInit_Win32.c create mode 100644 libsst-net/SST_NetResult_POSIX.c create mode 100644 libsst-net/SST_NetResult_Win32.c create mode 100644 libsst-net/SST_NetSocket.c create mode 100644 libsst-net/SST_Sockets_Win32.c create mode 100644 libsst-net/Win32Private.h create mode 100644 libsst-net/libsst-net.vcxproj create mode 100644 libsst-net/libsst-net.vcxproj.filters create mode 100644 libsst-net/obj/x86-64/release/SST_NetAddress.o create mode 100644 libsst-net/obj/x86-64/release/SST_NetInit_Generic.o create mode 100644 libsst-net/obj/x86-64/release/SST_NetResult_POSIX.o create mode 100644 libsst-net/obj/x86-64/release/SST_NetSocket.o create mode 100644 libsst-net/sources-POSIX.mk create mode 100644 libsst-os/Makefile create mode 100644 libsst-os/POSIXPrivate.h create mode 100644 libsst-os/SST_Alloc.c create mode 100644 libsst-os/SST_Assert.c create mode 100644 libsst-os/SST_Assert_Generic.c create mode 100644 libsst-os/SST_Assert_Win32.c create mode 100644 libsst-os/SST_CPUCache_arm.asm create mode 100644 libsst-os/SST_CPUCache_ia64.asm create mode 100644 libsst-os/SST_CPUCache_mips.asm create mode 100644 libsst-os/SST_CPUCache_ppc.asm create mode 100644 libsst-os/SST_CPUCache_sparc.asm create mode 100644 libsst-os/SST_CPUCache_sparc64.asm create mode 100644 libsst-os/SST_CPUCache_x86-64-win64.asm create mode 100644 libsst-os/SST_CPUCache_x86-64.asm create mode 100644 libsst-os/SST_CPUCache_x86.asm create mode 100644 libsst-os/SST_CPU_POSIX.c create mode 100644 libsst-os/SST_CPU_Win32.c create mode 100644 libsst-os/SST_DynLib_POSIX.c create mode 100644 libsst-os/SST_DynLib_Win32.c create mode 100644 libsst-os/SST_Endian.c create mode 100644 libsst-os/SST_FileSys_POSIX.c create mode 100644 libsst-os/SST_FileSys_Win32.c create mode 100644 libsst-os/SST_File_POSIX.c create mode 100644 libsst-os/SST_File_Win32.c create mode 100644 libsst-os/SST_Mmap_POSIX.c create mode 100644 libsst-os/SST_Mmap_Win32.c create mode 100644 libsst-os/SST_OSInit.c create mode 100644 libsst-os/SST_SafeArithmetic.c create mode 100644 libsst-os/SST_SysMem_POSIX.c create mode 100644 libsst-os/SST_SysMem_Win32.c create mode 100644 libsst-os/SST_Time_MacOSX.c create mode 100644 libsst-os/SST_Time_POSIX.c create mode 100644 libsst-os/SST_Time_Win32.c create mode 100644 libsst-os/SST_User_POSIX.c create mode 100644 libsst-os/SST_User_Win32.c create mode 100644 libsst-os/Win32Private.h create mode 100644 libsst-os/libsst-os.vcxproj create mode 100644 libsst-os/libsst-os.vcxproj.filters create mode 100644 libsst-os/obj/x86-64/release/SST_Alloc.o create mode 100644 libsst-os/obj/x86-64/release/SST_Assert.o create mode 100644 libsst-os/obj/x86-64/release/SST_Assert_Generic.o create mode 100644 libsst-os/obj/x86-64/release/SST_CPUCache_x86-64.o create mode 100644 libsst-os/obj/x86-64/release/SST_CPU_POSIX.o create mode 100644 libsst-os/obj/x86-64/release/SST_DynLib_POSIX.o create mode 100644 libsst-os/obj/x86-64/release/SST_Endian.o create mode 100644 libsst-os/obj/x86-64/release/SST_FileSys_POSIX.o create mode 100644 libsst-os/obj/x86-64/release/SST_File_POSIX.o create mode 100644 libsst-os/obj/x86-64/release/SST_Mmap_POSIX.o create mode 100644 libsst-os/obj/x86-64/release/SST_OSInit.o create mode 100644 libsst-os/obj/x86-64/release/SST_SafeArithmetic.o create mode 100644 libsst-os/obj/x86-64/release/SST_SysMem_POSIX.o create mode 100644 libsst-os/obj/x86-64/release/SST_Time_POSIX.o create mode 100644 libsst-os/obj/x86-64/release/SST_User_POSIX.o create mode 100644 libsst-os/sources-POSIX.mk create mode 100644 libsst-os/sources-Solaris.mk create mode 100644 libsst-os/sources-Win32.mk create mode 100644 libsst-random/Makefile create mode 100644 libsst-random/RandomFuncTbl.h create mode 100644 libsst-random/SST_CMWC.c create mode 100644 libsst-random/SST_Mersenne.c create mode 100644 libsst-random/SST_PRNG.c create mode 100644 libsst-random/SST_SimplexNoise.c create mode 100644 libsst-random/SST_SmallPRNG.c create mode 100644 libsst-random/libsst-random.vcproj create mode 100644 libsst-random/libsst-random.vcxproj create mode 100644 libsst-random/libsst-random.vcxproj.filters create mode 100644 libsst-random/obj/x86-64/release/SST_CMWC.o create mode 100644 libsst-random/obj/x86-64/release/SST_Mersenne.o create mode 100644 libsst-random/obj/x86-64/release/SST_PRNG.o create mode 100644 libsst-random/obj/x86-64/release/SST_SimplexNoise.o create mode 100644 libsst-random/obj/x86-64/release/SST_SmallPRNG.o create mode 100644 libsst-wm/API.c create mode 100644 libsst-wm/APIPrivate.h create mode 100644 libsst-wm/EventQueue.h create mode 100644 libsst-wm/MacOSX/MacOSXPrivate.h create mode 100644 libsst-wm/MacOSX/SST_WMEnum_MacOSX.m create mode 100644 libsst-wm/Makefile create mode 100644 libsst-wm/RaspPi/RaspPiPrivate.h create mode 100644 libsst-wm/RaspPi/SST_WMDialogBox_RaspPi.c create mode 100644 libsst-wm/RaspPi/SST_WMEnum_RaspPi.c create mode 100644 libsst-wm/RaspPi/SST_WMEvent_RaspPi.c create mode 100644 libsst-wm/RaspPi/SST_WMRender_RaspPi.c create mode 100644 libsst-wm/RaspPi/SST_WMVideoMode_RaspPi.c create mode 100644 libsst-wm/RaspPi/SST_WMWindow_RaspPi.c create mode 100644 libsst-wm/Win32/SST_WMDialogBox_Win32.c create mode 100644 libsst-wm/Win32/SST_WMEnum_Win32.c create mode 100644 libsst-wm/Win32/SST_WMEvent_Win32.c create mode 100644 libsst-wm/Win32/SST_WMNonPortable_Win32.c create mode 100644 libsst-wm/Win32/SST_WMOpenGL_Win32.c create mode 100644 libsst-wm/Win32/SST_WMRender_Win32.c create mode 100644 libsst-wm/Win32/SST_WMVideoMode_Win32.c create mode 100644 libsst-wm/Win32/SST_WMWindow_Win32.c create mode 100644 libsst-wm/Win32/Win32Driver.c create mode 100644 libsst-wm/Win32/Win32Private.c create mode 100644 libsst-wm/Win32/Win32Private.h create mode 100644 libsst-wm/Xlib/GLXPrivate.c create mode 100644 libsst-wm/Xlib/GLXPrivate.h create mode 100644 libsst-wm/Xlib/SST_WMDialogBox_Xlib.c create mode 100644 libsst-wm/Xlib/SST_WMEnum_Xlib.c create mode 100644 libsst-wm/Xlib/SST_WMEvent_Xlib.c create mode 100644 libsst-wm/Xlib/SST_WMNonPortable_Xlib.c create mode 100644 libsst-wm/Xlib/SST_WMOpenGL_Xlib.c create mode 100644 libsst-wm/Xlib/SST_WMRender_Xlib.c create mode 100644 libsst-wm/Xlib/SST_WMVideoMode_Xlib.c create mode 100644 libsst-wm/Xlib/SST_WMWindow_Xlib.c create mode 100644 libsst-wm/Xlib/XI2Private.c create mode 100644 libsst-wm/Xlib/XI2Private.h create mode 100644 libsst-wm/Xlib/XlibDriver.c create mode 100644 libsst-wm/Xlib/XlibPrivate.c create mode 100644 libsst-wm/Xlib/XlibPrivate.h create mode 100644 libsst-wm/Xlib/sources.mk create mode 100644 libsst-wm/libsst-wm.vcxproj create mode 100644 libsst-wm/libsst-wm.vcxproj.filters create mode 100644 libsst-wm/obj/x86-64/release/API.o create mode 100644 libsst-wm/obj/x86-64/release/Xlib/GLXPrivate.o create mode 100644 libsst-wm/obj/x86-64/release/Xlib/SST_WMDialogBox_Xlib.o create mode 100644 libsst-wm/obj/x86-64/release/Xlib/SST_WMEnum_Xlib.o create mode 100644 libsst-wm/obj/x86-64/release/Xlib/SST_WMEvent_Xlib.o create mode 100644 libsst-wm/obj/x86-64/release/Xlib/SST_WMNonPortable_Xlib.o create mode 100644 libsst-wm/obj/x86-64/release/Xlib/SST_WMOpenGL_Xlib.o create mode 100644 libsst-wm/obj/x86-64/release/Xlib/SST_WMRender_Xlib.o create mode 100644 libsst-wm/obj/x86-64/release/Xlib/SST_WMVideoMode_Xlib.o create mode 100644 libsst-wm/obj/x86-64/release/Xlib/SST_WMWindow_Xlib.o create mode 100644 libsst-wm/obj/x86-64/release/Xlib/XI2Private.o create mode 100644 libsst-wm/obj/x86-64/release/Xlib/XlibDriver.o create mode 100644 libsst-wm/obj/x86-64/release/Xlib/XlibPrivate.o create mode 100644 libsst-wm/sources-MacOSX.mk create mode 100644 libsst-wm/sources-RaspPi.mk create mode 100644 libsst-wm/sources-Win32.mk diff --git a/Bin/x86-64/libZNet.a b/Bin/x86-64/libZNet.a new file mode 100644 index 0000000000000000000000000000000000000000..956b3ec5c664a076549e162697f8a55a24c7315a GIT binary patch literal 232656 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 literal 0 HcmV?d00001 diff --git a/Bin/x86-64/libZUtil.a b/Bin/x86-64/libZUtil.a new file mode 100644 index 0000000000000000000000000000000000000000..ec78daad549d05e858e5cd0737f62a9644b5418d GIT binary patch literal 1113018 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 Rh!uEZV`7cluM$W#HyZrEH2 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
    Q@tg$RV>=+i*%6=Gnx0Z|4gL16{wFfcHH_W6Li z4Y2rz$t6G)PJjx4$`+6i2!n(`c@IQ`x(?`J4-)?XRS3He1tbQ-=zaz9v3V7AFAPY1 z1XL1K#(>HusIl;Uw4m++Hv2uGg&Q|iKgcW)2H6LqVK^!%H9fPqq^MFaUmw(0f%ITN zEZCj`hzP7tV`6A*4B1FPe4nNQw1FFHAtam~7$z|Eg5wfYPJ`S8+HV4)LEC3QG-w+K zhz6C{AR2UzB8UdHc|kO2Edq!J?QH?k&d_uK+Uo)0L)Nk|Fo4Qw5Fd0d9*72=g#n^L zYYjj&Xif)2gT_EXG-!H`oBI)f2JgU(6>(V%lGKs2b_1=0CXeW0@nKzz`d10WhSw-2I0d-y>#XfHm9 z2JNW_(XcTIP!NOopmrsQhV8G0jX8i;U4!;%fY$LMRs=&==z~{gHy_}D^#F;ujTzOf z&Qj27Tlk7|uz9`ULBhBWNA_4v)^#4JjVo zEUKUzcsx2?Ul<n4a5wHmI)wlrg#`boLZs?@hR96hyoA9 zDr(430Ax8lH0&DRfbIzN=-ev-_SseeFg2Cq|Ns9O{%-|Iq6Gn13=#^h3Lw4RV7(|| z0aXJEj#dMZ8ie;fdZ&U#dLfz-5}3pcqB0>2G`kigu6Ay&B-4 z-wM$@6%-PfF$|G}1#hbbNJ}?3Zcu}u^Dt;x9RtW@1`o@_{8JCK94O%et?6cXsmBPq z&bbw29cp4}-U~91fxqPwcq7DA5YM9<;-KEv0FYgs7op(^bwW4T7?0ip4p_K$_kvvR z(K{8Q9;yyC>^xwmL1iI6fQ77wHP~PLQx3EoC{6P~lk5ab9s@_ao<}#tk-b}?F%AhI zG)F?TAO#4r1spF~K>I9SGfwb;dIlD8u;7?_z@s}BlpJIr$wB3{EF_vye25v%puk7k z6VX}wr?d1&bL}6-QuW5#AOHU|FqFz690d+na3mtcpksIYKx+4c>VX&Q|Ns9FyD=TK zqv7}gP>Ba!n;#9T#u)T7@^e%5vl4Sti}lO%i?WLg5|dN)A){sbKAB1So_WbRr75ZU zpj(vmqmV8 z3=Hv^c`2zC3N{MyN%^IDDTzgukkA1uv{LXdEm6o%Qvk~qD zX;EHkih^ILj}Ij5;f8_&zSs~PXoe6A(4rd>a&DPL#U=h}L`5S*u@TrjBWjr!U!0ng zrUwoi(5Z!>zijlbxxS-V4fiy%ubX?1jK33=!Ar=m6a2yh$;qO0R&A1 zu;A8&`hk{70-P>j1d97GawII|k#AxV|jOOjZa{gGNETQ(|&9 zM$(5S9AqDm?qc+;2M%Ib_+l;LLA5k2h>;XP5;w$6pnQ)JiL6DctawH&wWz(L5s!0^Bs)XxO%0-b=|&VtUVvVsOsk;UOVMM3kn zA3&3!mWTMK9DwYbgw3RSfK`P;_M;=ZP|Y70F?YOnUg&Ur1DP@n{eavx?RNdazb*7l z#{`fQCY(HsGKUP-0ByHo$YHnLquccZ|2D8`Al-0t|Nm#?0Ufig!m7;xIyMi)mtbXJ z&}TJc@MdLTfbg{$R9G2c@_af93=DC;Cm9*;F+x#%mcF4uM3#@z?wYG4~7&7mwx_i15ag1;sE_ zCH4?>{Q&QvKn|EdiyfFOOgCcO12mq}T>F5bM98Dt^#M#B=){EAtdO2DXg@b1VSq*q z;HtoOy+E}KF*MV87*#Q7KEh zehte0@y0ix&ZI}@UJr1$5ZwR5=&nL~^{~z!yjKtF9Co)tG$SOyqYCKVDwMuBv7IlF z>!P7K6%-RFCjfYK`X0b=ENCPM=I3MJGZ4CcLE}az;8D@-dcwon^+1U*SQeUC__r~% z94KK2uZn)n3bGc&7eD6u92D|5JbFW)qedQl&ph^#A*90>u#60W&H{iYaM0ltFFZhL z3$%Z~)As_{Ro1Q-O8F5z$d{ABU3o+VgBO}W4kbYzkLh#;l}_+v07{!4-C!eMpep+T zDmTE#ib(DRm6^MmSQr@4x~-^5^0-I0?+=e|aPbEkKLjUAJmnW=nds3O`T|r&!4A|w zauLiNP+z#)^#@wHiX18hnG z%(wda`0_AVWC^#rLAQ!Rd#p5xL?oja9wrA%}$dW3L&Wj$MpTG$ip3j?) zNI=JJKqh099N>Hg59kYUZQy{u;Q>z_2RyW0Pk{3q=scAP&_KT70T1LGI0^>vaVpT_ z1+3rq1Vjja;thlgEv>*OYk-O>Pzi>tkClp0PJ;8_<%yd0@RKJ4Vr=ju=xe! zYeA3Z+!u_mcOXhvw9>}|k^!K#4*EGJ(1P4B^YKhAk2e=KDg|1 z{o&CKOHw~Px*NbHlI5YII&h%@<+mQF;07N*YA4JRbsNP&to zHXu=8?fRiu7+Tx?K+WH<$^#q>V9!7@Fw`DUSrg&WS$o2xv-E&RXXp-(PTvhaovtf< zI(-*-bh{q#uy);1!sXHJy28WSbpcAYk_QjzgGw8Sk>KD07YQd&vlXb3fN0P_vegc7 zPDRu+9-XeB^ME#>6l}gLFjav{QiLjqVGA&of$HuH9@efm%AhfIkr`W);em&>>kF8Y zOIVd4ECUzp2#<6g_vkKt;n58`n+tR{k?RG|&X1m*CpUhSk3>LAb$I;_ ziUdfW^=Lg%3U!?}D>m2t@Bo*bpsWUtzvdT=9*h^@r5{qx^aZt~et`1{QrN?K1#r7T zX&sb&OWDC~#@C7-jkO;@>vhUN&C3tqk^vS2ufZqT!Ab^5osUStAX7@@!AaEG^+Smm zBvAS$E({+YVr!S~Iy1~QRbp<$)&G4{xoq&?a zVj+oa2h31NBHI9&_(aq@ovxrnhEN4b7og;`11UV9iEII?VKY3sT^FFL0wpqpDu`hq zm!c`dNMsFIQxHlb1D)Cn4ri1S_<{%Ma4<-IyHT77Y3aCvYG6?7|3$F}#KTA#&Gi7d z=8%9m9$Df9Sc1XgFnBVn1XS`JcrD@4?0SOn^*WDc*8_~Nry^P2d?W+bXYqiZ3kPc8 zgT@5zfU6;BVzqXC0Lv)OY?!GP)YmL^fM|fV`d)Z|+mk4*d6Wj@3y5@71P!kRax;FV0w(md=OpmoHcbKgN2qy~Nm4$KVDc|uMQb3kf9@*s7f^!4wNjRYG5jxX4`NZ|W6Ve&}`dDyu~;PtF9`3i_U$Q>o1 zNnr*C22i}AxC0bUmk{b;dzsdv``@FPnP~w+9c+)|Wps5Q^G-t4f&2yATM5257UnLd zgJ1<9c@=QfGcbVm$HK!p6f6z)w+mDrbe20@J_8}20+k0JKMphB6CvLMmB(fN5~w_A zJto|I$njcW`;S27!RPYB%x8jRB#`@I_g{naD@?u|VLuBvup#$#!_7y^$0|^HT;bya zmB;1&6sSBl_k-4K!tTQctz(1R4~iqmky;EOH7lTI@PX0@%nz>3%*-r^^a=cNZ8KK<6aD<)Ll>$?HJnv87*-ybn|!S9zHOmA?hb=P*Ao zU4`4<1CCP!{ygN<#Cm_XQ1++Gx6c>&jo7-r;|5Od0hVEfi5%#tviM5XMz+^ zpg7Qh%4ea+K>{KU0-$QZYq{ZmKL%4AQR35Z;5-wkZklz56#})@5 zH(r3suRwR>JcJuz_kx4ZQHQyaITEY@6ptd%_0gbpoNzZFou_94mB$v2ps2-$LC(Rw zw@4qG76xVp&KotkA|7S!J2e}WV0+dG?k<5pQ zgXEauH!p*D2+Yg?S{aMr!&uA=pp~*P9)f0O0Ii%w@L?=w2GB}c7!N@+Gk{AjgaDMq z%m9udC=Wp~!*>=S#6T=&25_nZF;Orxc!v~<5SYWv09vsNW}*3#moR&2@YZ*usryV8xw{Gc8D10 z9zO^R6waU(<1ikAW@Z4bAV=_FEM^AKigFkaK{GReR+uCBAXY8Z-UZNjf$e1i$uTn^ z#}Y_{fdO=PHppKM(6+-gh%iGKGw5s)eTEfK|H4Y5HmLYBs5rQefa+mpXos>;DQ1Q) zQ~@ZDnV}oXLQu=WZ9TM&6ATOt2f*S`Pa%{uK-zZDKt>XWoZkc6v4M~PjW{!accvl4 zK&&jV|G_N}5EqUYfW<*OK;S}P2IMYmaElkrhY_I3cxVd?CIqHIlk*G=pxtC(E}Ve0 znP59w;KB@Zz~Kw3tr21{7BfR9jEO>%a*iiRBQ^H+Ld?O87l=4!yg2oMVuGc#b@eGAIh;Fd9}VsN<%+I5H_ z%)rb5I>`*1IBe7cRgM|baz_;en~#~UK#G_dz#|hNCJJVT?_fd^W?*JOzI`4c#|-Hi zA_Sl;W(M%c1C)oLn8B@a1Rus?W&oYE1mhuSW(IJN8zBH?F*ATpz=Cp+C}wbv2}uCT zWM)9#Sq>EhhYxhIDMAR$VrGC|_yXo32xbOQZymvhv6vZDVN4X7nE}+QL=ggWm>Iw$ z1zvzbv&_XP`q31;|dd0;M_U}gaKGT?j|gBg6<3yg=LnHj)6c!U6y z#moS`coWJ8QP)`+7?hCO+pv`V4J;07#eq~o`_!QEM>ddpOmWa%K1xXKXIP5#1gl51 zpJ6eS4i-nWpJ5@@3KmDSpTT2d3=9k>!QzN^EV$pqz`*byERLz(nH}U#M0*>Sf}_FW zpq*?Gf5Bp|7c7pcekoWSRx2_vfXCPv7#I%X5T6P@#}?5K0*!%zY`V+NfVDLFghQN* z1G{=D9O6be#2q<6=PYBo2Xvl~5Q9E=j1J^J(3l>G&ck6&Bh(z2e_-n8K*eEq3d7{r z;V@?(4)qtH;^1`*3=9mQF+q@f1Ua#XgE7U{2nJHJRd+il%O$5 zkUQnLu)EV0hj<1TD19ROU!buAm)Sa4g~Q*W0@fO9#}o1-v=v6#kfJ{fOcSl zR537s#u7oSJg_*TzXlpR1c|TX#_rB{VD*T89C(b3fq}t=2V_2?zXl$YVqjn>0gGei zqh(-mM865v(s~9KNA$B`IZcQcWIkrT_5h0``hBpPyB;i#=zqc7xgIQz8J>@MvHSNG zSUsXY2p)3;olnFEau1>(2lKBNSRB!hgVhApU~$lnR#50d$5t5_7*_LPw|6sGJ)++S z3lUL%kiD4k6$%zd^asJ?h71f06Tsq#{vgbq2f*Tp{x8g(U%}#t{xz(IFcHA+PA377 zdl3Cf@K_@Q1H(kHIHLau>lfSrizE7vu<}_@5M&N$2QDOhVD(D`SRBz$1dk;$Ffc3y zi(|&iMX)%c{|Fvi1dWFafy_tr6JhDi9xM(ET?Y8bOEy>>(SL-EKrIG~W2URiU~xph z66RkyVUWFuekFLUk%56B9W0LMSAxeF85kJOg2gf8kwXMz4x(QP9&cn|VDJZvBl?f9 z7C<9d9MOM-l?bcA;)wnuEc|bP#S#5S@OUBv1A~Pq$X-N05j=*-z`)Qfiak9{z#+Z_ zhxlq7;)g-vnB6{x3m|bw5K{R=W#D^Gw>OanfH4GocY zow(vPj~L@DV7r)H@%kSluni4Cp$*;GgD1d)jpA{Hd2Viycd&81Cn#+2dIJ{9@GT#n z_`=5ov{s)DCw%=Yj&_fJV*~(HpXKG%rxS4fc+3`M4~;;rmg|r z$)vf>+0+vhm99bF!SSG?C>MMhJ3N~4_{!PTm1woF5FparAaAJOiBpf{gX9oU!UqL` zH@F}-G>L~6*g0(3SaJrR?TybM7$Ly{MU%^*4Ajl!ONpkYb8F|f-k&|QN|92`E-jEJts8RP@7 zTzq;(MSMYOQE`4=VoqjBWqg?dC~2UdW9AHvVOadZ_~_~&jtR{x&&*2!6`ZBHsUYJJ z_QNzHiGbn}W-drEj16%lID;dp2Du!j0;C!t1wM%msThQ~1-YQa6ft!zN-PE?GUDR_ zWGTA0v79s)ALR#6&nBRnn55JSvIMT(*flQ&l7CF&fC8n9FIvcT40C<8eSrUY`!2WqnqU&(3+E60%> zA5dCClH-F-!HEmKwTZ`CGoRGF^pXrnWEhg&MNup~RLvCtrZhjfK#=%U)s9gu#PKNay&_WU12Zi;9KnWU69=Cz6 z&PLd>DRDuKq!X#(MvPt)r^MuJ;zQjcptLvxtR)E2KqeuvqW5?i;^PyGi&KkA;B^dg z9}ZEP;OW1Ci%6I^A)U7%Z*cb<9QM%RgLqJR0Xk!Vn2s4Dy@HzaAY%|Bcw!IJb5VXU z^8$ogvF=~;<9f%Jr@(WgIdzcuP z85+2x!j1uQ4M--si-lYi!-F1HJ`o%Ah%^IBMTX|kScH^Y#2N(mDaahKA81i#!A3kF zV>qCQgxiZZonS3@U^*xm=ONYw=0T8SfFS7=W-(@xMoXo*6=F*?$fXi$^?;{jg4GYO zaD)_2uyBTtEP*^qr6DBn;Hr6Eeo01AemO&YR9+%zV6MaxDiRO6NHHZb0NjKQF0shW zFOE-2EKW7?%*!l+^ta+uiu2<$67y1Wz?CDqB1o$yKDi<>KCvXVA`?7l4;z064I%e4 zFfhQ*W`@n!gTz4_S773>6`dgQiAd@lp`*+o@kvPHun~HYII{V$Jsu$OsYvRP&zwd! zA9NlF$O@2pWb^le1fgeCgVey>3A-N^q#oHE*t`h3_){cvkj;nPdk0bvT5}0A-vT;c z2@(hGyMT%NBZ<#N@>dd)cngwv0g^aqwgF}i=w4lrlR)OrLsCB-N&S2z@x@5u$mYQI zI)KbU7C(=q9@)QFkizCZVt4TkAVT% z9A2n6=v-sa>Mdw+F^EFNLFRzw?qTK_BZ(us(+No&v?>jzJ`hP9IUK5y#F5?Ek0g$4 z&SE5SWOLRbi6h7RW+ZXsc>jwez6>cm1;Fe3AS(hv;Q;bCD8412;voKVB=rhVaag#4 z)Pk@oR2-xpGz$j{2VW#{E$90#qEN9(gS+?EXTKII=mnkkrGYqvwgV;(+9LvTFUb6L zNcO^3n1aMX_nE-d!|osfiEl(wk6b_EGJi9Yde}-UkU3kB#N9xSftI(ReW);dVKez4 z_1lotry!|EPPed`e2{w3y$vvPKqo1Hw1C7xTeD%}Q$T`Hdy&M*>oh9G(|JilOEsr(4*HFpzrW@)Nc$3M39XiU;OS*h&hJIC6RbwJ|_epo`A} z31YDql-EE~Aoa-k1$H+8NE|udVJl)l;=7T;AGXo~Bo5kt3UeoHr8Y<$)K-CsPX}2F zbq{j5f#L!r1yYY3ZihjFQ1!^+2D(cJBn48B?0(n^O;A1smCqnGAPid<2vUz+{=n7+ zg2a*I7q(IfBo5j|4s$U}yei39o=)Mqa>OpY<6Gtw8 zK>KQ8;>h6!$_p@Y(A`QfcY;pWfr%r#2U#4pG8E(+&cvU^}FfI#Yz?S-vm0f{4*1IX??jTCOk;cx~?9JVqVWDasVK~9Ir;>h847RemY zoguJrL-ubLND!JYko|?64w3x@YD0pwfZT%|KCtu#5=V}AP+5dcJt*(P#F5p*_DqA! z!4+=jk^BXVM|i#f849}B5=w*2!Ie*u-H#k@$nHVTr^xD&!v|SCdOn5icS6snpt1(! zL|C}N+z-1;2Uk8t4mafR0UgE;G7n}Bhz-KXcLyPd11!D4)k6z8O^_xAM7vZ2+CYb` z)P||gfQrL*MuNf_xjccb$ODOkjJAPpu|V#(B8xAD+6z*D0ZaUX#6fi*ET6(wXu{kB z+ph(SN0>Ow{je30F!2RY_eUbxi|l^b`Zkcgmyq0pT(2R!6Sh(kq#ilHz}hn~d!g3B z*KLE;BgYGDy)sA~IbXxpgM!47>jl{UG>|y5dRRIHi6g6r?YjesBdcEzbr?t-Sv@FB zKvE!aWc8r4KVag>>R*BckaCj z>S5-Kp^3xHmqruM02#=@z<_)|G_v_RQ1u{X$n~H#4)J&-anPD(m^)!RPGIhY?Z<=F zk1%mq`h=CwFmYJ_9JW&#(I$Dr9S3v;_#mMy_DDGhHgzaDknSUM0 z97@tHayf~dZjsALhn zdb)*`+vw?*1KQ6gHr>L^M^Cpf^U>370MvY3={5i<9U|8YnK;B}K*d4n1XK=#!UTlp zLd8MhhFmV8r(4)K0xW&P%z>q6^z<_W>VDXM6_EL$ID(}^*a~!zIC47;)aC@a3nY%* zK7rjA4-!XKAByCD8f1_* z5U{)4K<0ojM3jNS6G=VtZbDdn4pIxkuzCn|=O;)n$gd#vAPnMz&guctAhjS2Yv;{G zGanYd;FE8m?gy!d?W;M6rXE(m!uGR()PgXK{}N3-=q@>sJ2*g!kj#heR}qAY!`u(s z4{ZPy2T`y+03dS$Kmt&6katfOAc-UIo}7Rr4r|+k%$W%lhuI4ny99~D%5{)5Z0-Og zeh?%8jYm)z!^%74aaZKsmM_uN!^%NeIRui1?Rf*4uK~?}AaPiq0wnH%Bo5oN0TRzZ z5{K478;+sg-1pMfL}>mz`~JCMX-btp)D4U#x)?gk`&0ZAOTcLgN=0ZANIHiEWV)K@x|R`5^HUByq&9N(P20NaC2VvMb0v2fEu=1buJ4;JaD@yc0>lX2> z3)X{OYzk8hTWtnkh6rAcr3aISFJgqtBQFWYqYS<5&^7O% zWv0Zh*-2u+ZydyzC{Dv_BWRJWUV3tJd}>8zU938oZ<|IX4$Q zIlxvH;8}#=3R@|O>NXNm62`J7L>5DHCLT}0S1F=7gD4+>)=s&Wp?RJdov2IIP^~6L zKX?@s>DnMU2Uf5VA4phMo04uhj+}>Bjf5wbkk??6ZZl#zCaPXqtX4woHzOlipyXWW zVo6jd6BSypb(5%Ck(UY~@;km93R({hOO223JY0$F@U@_3?AkP*TOuDxv0#QDp?j|#TncU@Iaw( z@gZuEP-h(?nwc1t9qKwc++he?CWlr|f_Et(vN=ZO2Q!e8C5EV8ASR_Ctu{o}408@< z8bL{1DD6PpdN5N2szw@abVbjW)Y;q$H5IgfH6DBkC4*jaelF;GN(Q~W{E}2XcfU~G z;*!MVY^ciAjQF&o#N1Q{z4W5|Qs_;qpxzDncpeV}1M)Zr%p}O&?C@g|89-x5pm9HF z_ZBv-!hlP^2h4@2(#ZNjbBr*3FdCPB*m@3R{h;+QFnur@ zmwwoI9!GR2GpO(`ayG3Fnur@mws5}BI^gOU4iL?(YW+iV6h*x#sa1f zM&r^Cx=R3L1hW00c^;TP7>!FmY#j`;eo&f#>4VX@^n=#MqT3HTJqD%^M&r^Cn?FUi z-;0Fw2OFP7)(={D2eTJO!FmXbu(K|DgE`m_8VdOFwAM z9lCzdIw6=o7>!FmY`h)W{h+aLm_8VdOF#J55C+up6Le}3OdpKKr5`p9j%+_@JrhhH zjK-xOHV=iY-;ad!51Us&)(=`A0<#xJ#1P+ zU^FiMuyypv_Jig%VftV+F8#21B4qub^;s}|FdCPB4=nBnt>c2}gVDJ3!{#lK?FY^C z!SumsT>3%h^`fUg(7Yc^AB@JOKLLyTLGy_)eJ~oAe%QPjvim{nx?uWXG%o$H{R_zY zLF>O@`d~CJ{S{c;4_fyH(+8t*>2JWIAGE#-rVmEr(hs_p6+QexWjahBjK-xOHjjwx zf6zJ~m_8VdOFwKL8(BYSy$(ztjK-xOwhjncKWH5XOdpKKr5|>F6|#QNdJLF87!8`s z0tGd6+5!}0V7vh&$iTqx8#*5Y7KF|}!q^}hGzSMV3)Wr-iGi>{D2QZWsDK&_YJY=H zSA@9-w*DG4cLlNvI_(D01UeTEIxhkjfHFX8p-eCZnwtWdiAz7adUQT$?g=Eu2AY%s zn+PG+K(oY9; zK`ktufYJ|Wz77=EAah{i-*ALq8PtB{xjc|Qbo)O-+a&1ecL5grLGyp;_Pc`5eP>`m z5C08N`$72wWG@V(+YhSeu=#%n7W-|G+H)}fgUWeq;eQ5dKl0op$PMWBCo?jD`_kzC zzktPl&{}?U|93(Ck8UnIbddt6%>c3&hCyzHu|f1gsDAYDI|0>?JU0(gk8Tg>ZXj&o z_X3OiL381g3qVNOh0_k#T>|U z$k^6-T(h_*slR9*g@y?gETQPfXA;u{cm*p{h6_s|0|)3a6oNNs1aZa`+KnJj3vJ^Xh-?MGSbhNb;eghT%^sD47>m&<}Z{w%P#AGB5+ z-TiBE*#7`(Kd5~L3O5)=k3Z1=>-wfJthgQQNtH2oD|8H>U_krps)P8%8!~G{fiG_iI0h*1$;RiZ3 z9Nqoe9N6Qp3u-^K8vu4Yh(LFLEe`#2p!$*bd}GsJ!GS&gHJ}@pk=vi3Q_Rube-(%Q zWza>uF#m(>24QsfgYHAXR{j(~?ME*EKzkz5?dRjf9)8!L_7f_9`vPr_lp2z0SCq4fI#hkh-ne%N{KAh&}sdiX!a;eOcFY{>OD z=oEN#_uFt`5C0md{jhW4L3V>MdiiV4g+2TXK!qIx1H%uf22lP7oi>kd|5_aOKZABW zVe`NsyFnP;|0{6VuK_CT(DEs`(+_B@ z2;F`gZtUTo1hpU3X9n2|!|3*#b7K$x1yK8u;~zACk8Xbf4*Qot?I%=zX5+B`0@QwF z|AWp6LAQS;4*MTM?T3w{!u$_SPB1RR5*+rwfZ8tr4KPsp1I_=V+b_a{J^Z_%n+ag| z4Ztjf8VBPt@bh2~{~w^r4z2$Q+WU=ee-;k|__igDSz zC@2^xAOM67A;R20QRrIK*TGX#oo~1_tQdmaU;Xf*2Sp1Q?}x*f~J+Z=fa=2!kvK_5I;@GcyH)FNg-o!TR^$b{gz%XQaE#p~H}n zo9$roabWG>Tlrx7{=xlBm^{*5>!7pGK=y;jfnoAUcie;K;{uhg_sW#$A&@a z2lw63AX!XZ)VP}xw11D0ft3MTw1E8&vx%7jt)PQSFf)KM43vXJF~bTrBr(ujgAh^< z2FDrbjvfZ=cjbWk10Xjc83AU3)^1@l2NV||ahSQ_IA>sB0Ilo6CJvhK2Z=+Q(vUR3 zz`y`HuL_&JKN&!GiZL>P><2jnoF+hSXM~7@&g}t-gVO>71A{svc7K89gh2Mf_H={O z21p|!)98UREcluo1B9TniEAd#3r9c~slfB6vyp2iLvV0NyfY&E#yc0KCYGea)qv&w zgX4or^GY&vQysxa`hr%4gU_}^w${)!6I~3vTOuBOdkfq^$T^d!VkQCk#U-v~V7rjr z0uqL6L^m9w34E-)A(A^x!V@#GnFSKYZ5Bw@6;j#4swz-@2ud5UJ=~yl2?~DDo>x`| z26+01&3VDZL25u4G*1GeVdAi~0$RU^EDjn^2JvAu$X-x&4YL=vh7lwVs^?+ipmls8 zedyw+K!VUQW>A?3Q~wo*IB4!3Bn2`Dgh6Z&hWQI52EwrX0_#hI#6TF9FOb~{5{IRK z*cwET7zo4CKWt11BnHB;bWZx7Mc8&kB9|S5JVyl#3O7(G3tgH3HxU+YNJSV}4&+BL z14@8~MzD=J1V9aht(^m%LeVQU`H z{RPtxI!6=PK3MvPiGeC^kekrk>}NoN3=9l}+U%gc@ld5OBf&Hyx`V)?kp2;r38p}2 z$AR>tD~Ij1hpoK?D@K|#hw(vU8rb3wG?oZb1Di7h#UCi{Ko}$ri$73aMvps?`~_$g z3LSa{34t-ltzZU}0P)e?4w8cHsfYC$L1hW33_`abSDPKS_d5n;0mwioM&mL>1!v|K z&!YK_0;tCVR{fb@(DwtR!{ERHR@@!>gz5nZm?@YL3)u* zyv45pG4u(@&?gAjfuaG_73-}1(^>kXx%LlZsd{7WkN^J}7)s?p=czD&;{Y5f;NBKO z4BFw^2U5Eq6s<4T|Ns9#_AmoV{|>AZ?9WaCaPO`4KnV|o4~fE)hf&lcOChu2{s;FO zkxfNbMFkr=Ykwe{J|Xt-|No2}s;uS=KA<)TG;0oe%Fr04w7_t$SroVwL5P#t4+OP$ zK!)J!1A^8M!ux<(kUkcujDYn4LG>zJ9;pup>jQ$@fv`SW8A3m?eLzt81UEkjp&#Pz z03UGgl^t9&FvI$=ptC$c7^DW&4g=LYa5G$+nVI|$=CFWLKd4^;QVeq^QeRUADi1zi z116t|(C-43$K}rys62R12Bx3M8EgP399y9B;H8^z`2e{55~w_A9T?mXm0)RbUlMjE zIjB5`%R{t-e1sK)jKtj+2GxF;+L#$YH6u204id%80IErm1fWc222jlkT^sAp-*gXlz6YDLsSBRt5$J(0VsTr1S$WD;O9U?t{ibP>lfd zo-u&#M@Hlem^q+6s}fSafQ2lmj8j6&7vQprfq?;ZuACxLdWPAn&j>Ofk&j^N-N53A z)C4m>7A%g)M=(|n4sp=@un+^HoB@^5Adgk!7~27jOQQFOK37i1XF4}4@3p*y)L zy>b|>DF?fE7}|n^-C&ER3MLFyhV0CJ}p zx-F3Vqe8;a#K9wns4Y;KfoLjSpaw(jLGv8+9vv*VrGf@ggA(&n@^fM1r$~KchIov- zP|>V~7#!t?CTv!eTAZ4i0v)7JjIS(~8? zPK`#cY4~&+;nr#Fnub@aF>b9UAg%bUH38`j@k9$GhWMxuPiTBG#DniIDkv>VjW5eA zDk)6_U2Yl@=4WUClBq~c$}BT9GKh~a&WumaNh~goFR3g@jnB+W%LiSY8WN1fY*fvL z=JD8d!d(#MhkmmXBzDQUehJ>f0~HydIuSOO3v01~Y6Q?Y9;|GF)n6d>p!4lu>Oo^= zpn?S?4pIXX2d(9XiG$9)gNcLcGnlwJ1LEE%*nV)3IiR*0O#Ne!V(6GNsE&Y%BcC@6 zT7v--Z-kcjAag)d#4z!tP;rpIzBKAx5C01cJ?92J)qVkOg*gs2@(gXfr-Ov6p%Qw zdSvsF;}Kasa(uzYMA6MbwimS4oshk-mK?gjU}J=!V1kchBemH;;vn-uVFtpm`WGY) zYfFH{VeSWsBcGcH@;gW#Bo5k#1!99RYz!DA4%#0D5(8nF8jv`we-09dxeX)^>mz`~ zk=>8H<_Ot6u)F|LkL(^~ab))(izB-SSsd9t$l@S7Kp5ms(7qj5`ayOl=sXdS8W4ub zgVZCtA0!9DAaT&V5=~xn zt$@Tp7}kCSsRxa3gTz1>d9DY!cMaMz43Y<#fxMOxc0K{f91sSn0b%6xs$qEqBo5n; z4^j)luy!wOpE^hkgkkRU00jUvUxUP9?O4!$H;{QCF%X8eS7G~oL1G{bYnQ^-Z-K-> z7}h^Mfo47|oXMZVLOBcwTB(5BM|xOgK4)VTSQ!AaA2uHeGMA8kSh;|#A5?$A^ucIc z_M@LG1hOAgzrysvXk7YXYfq5v2bEzkeJ~oAepvekSwE;8hUtURxb(xy7i9gQ@*1WO zM&r^Cn;S>g4=TT5`d~Duyap99&?#Y1)PON;Zt)gK5-b8CKxGqz1tDQ^3JM#D2!zxC zO`L(wb%*K)g+HilhPek;uY=kiASK|@XoyxYnT2ixH!wK;Z`(y#o0a zq!|`|pnQhSe$akXkUCKKf@l~<2|Dy8WPgD6rXo2x<|itq!vrL_>u^ zOfUwWCy&kl9MGXOSeqNK3E?+YA%XyN|>YCo(U4zmxPABn^L;KLG-`c*LfF#BQr5FG9|03~*`^bZ>Sgz1O5 zKNpAnu=`nI>S6Yw^V=A)uj_~1!2?~GEEDlUROneg5{jhuv zb0_S+SXh4;CJu@#5F19%hUy22A>&YxqmTulY?wYMmjQHs4M+?v`WYgi`eFBWz|_Os z596=K5q}j>|HJwrApe8k1|AWeOXi|e238rEDvSIg&fCZst1&j@%vAG>2ZUJpj za6qSkK=m}JEJn8<)EC5NzXP;W_5@85WFN?U7}hs5g09ntto(tj2tsB8cOFE8<|#llXfHdgjtA}W1&M)<3<1%g^#ULov|k!T zgN{-F(V+dyAR5$$2GO8(ULYE@)f7a7wrqm7oq^b(?LQzI)LsVBpm|Ub4O*!RqCxl2 zfoRYIdk_t(uR(MkG%bMEMuYgE_A;z30NVct5-WwO0p0Zn;)C|pfoM?M7(|2ixq;{^ zs5;QTGY}uN&H+S&_JM(D(0&jQ4cZq4qCxwUKs0Ed5Qqlt*8$O>yRSerX#Wa`2CWYS z(V#soAR1KHgJ{rw>>wI+k12?TwIM+Fz=QapyHPqtYMCO3DcbxD5$v}5wfF+MRfHEWlh}|7v z0Hz#F_}3rmbbSF@A2!1Sye@}<;efn{<%M!KkAn}GUbA}~KLFZ{0bZK~Th;{GMsmWV zGe84m3fQ971EpNx)j=;oH@QR1>lFco7}!FP8Wb~*yMj+p0qO5{P_TBr!{6u2$iR@s z|Ni7Bel6cSAc@cX0uBH>H*7KR!bWHmQHi?u!+cLfi`fK2IjFtB!g zz~2YD@ji|J{ejQ?TCNYE5+I{K^J|^>%pZ3UyzUGlZo_1onnsmBwzA4_=w4a5wukYB2)UK+xH3MM~~!_9tR&Xc`%;%%rC(4nLh&LWTs}< zCyXzn{{R2q?D~N5B{!IHhwWU}x!*&QMU0z32ud7}qDAu0O!51iKwHz|MYvC+UIHJ2*{W;O_%1+yf;KP?`oi4zkq^xWK&dQ+EiC}pRoRzyB zEYM8>r;jK68W%qEM~1>U;4Je6lz*OpvJBYm=vfA|5)+a!d_Q!D{$RY=9eRfmYrgr= z?fZlAT(|EX+?nSN<4b37p1HyJ^2;! z3P46dYK$G=bOcJsJHU>HvTVRP?nbxk4U%)*4rna`u^ds0gflTP9Crn+#sMYx9pLj+S#xC0|Uf%D28P+|k+Ik*~>{Pf~8zhLfz3;_v(%Mef)!}2Pq z3;{`?y9=B>@9=Bf_{<*}3*&$@E;z5=f!1~4HP&}P85bN#=ouGOg@EI^+xJCx=m${7 z1?S!?Xt@`nru0R(?*~xs1!v(axU=vT#+N$aEPR3StAZuh@HN7TsmDrr6iX842qB!;DA5W39jYgIUAbiA@K@|ABZy7J1EsEXsJ3pgl-^( z5Uz|bK*crY(AFo$T5xa+Z?La0hwe@Qw`RdD8cJ8j<6dzOHXf-(2j)XdP%4B~XDz6m z^#feS#X{HdBZRj4F!dh#b5~;(AX7{AHfbJIb>>MV%UHU z2Zfo<1kes1P_J?nkA}c#2n^;BFtk9~%JU;>&_$LVBD^~NNsH^Q&p4Bb80oni^u zd*+)68YIP{1h%9EE;Wqzrh(_fVSBca_Qt`^Cjre7!1rV!?TrHuX)rJ_fX*g{%QHa^ zPyx;BfyPNd;fG5M972A{|4EQOMVYjKX_gSWOCMU23VE;qqarz%R!30`E z0N3vY)($q`1}cxse=!8)YoPMD%!jQarti!R32CO?jaz5hk*Pas5~zFWk78*1_lOP z;b%iYK8ApN4OAXi_|JjL;|kwBPlR2D+IUm%I%D`4|H7HBfn6 z;R`zd7+?C{LqI?1{9}Cj|3LM7gYp3^{WH5UfpP$-e2{_8$AZ@v!{m!WvJ8;?50wY4 z5rgLsCP%OWkp38`{BacX55di^fy(1De-2b0G|z}IKN)WR9;iHM-xOS)S&bQ_0A&9i zs5~z7|3KwIb9iw5OcOxb!Tyth&O?LNYr*A__5|BN<-ybDu<)U1PcZt*Cs6Exc65Sv zDL~lBBr^lpWynHcHZucgh8fI6A($CJv(6|&U=A|_XcijGL?M_NKr_=QLSPOv12{*5 z*~kPl18DXdSp>pnhSb0i4wMuF&))Gk|8^K`d0v%mA8+ zM->C{n87#dfLN%QnE^Cgk17V@F*AT>??Eh7%*+6q%|{gj@t9#3bAUKVn3(}I+m9pw zWim5>X8)laB#M~E_O0Lo;BpV$l)fKtp1pw$9U4id%809rkOBmiYHGk{hTKsiVh zGwfhpBry<^nE|xo0K`JY%naa?0acIzlwUwA5-@}rm>EDT6tIbdRxDr>2d!YhCJtKB zfK42t0b_AgH}yo69=uLz$Ok_Re?<$w8{dTIB3-c zHgV7@3~b_{RTjTGfF~9JI;ct41BL`M185ZphA;y& z187wUHgV7@5p3e1RU_EML90lxiGx;^U=s(eGQlPeT6Ka=9JC4rn>e^e!;oNR0IgEN z5N2Rz0IgcVCJtJ~f+`N$@5IDl&7cihn9aZdFR4K}1tgvc6$jUeP_4`iv!N_hiWz#6 z0jek{|ISAjf~rKW4IoNDv((tmLIBN(flPv^LXeR2+@K9VgfIi-Tr=cdLl8+Gu$9QZ zfrvx)_COC(h6uq)W`?=V%L9t`CS*v?`BsbXdT?Vbg(P%$$D=wuyKF%XZL0knb^#6rc)44{>* zsA3=cK0Lo&9??8YGKq+Ph(9RVo2Z>^4K;Hd`kYHv2 z?bb%{VJv0_(5`G44?#0yoQ?>QV`f0!Z3__tk<1LBUEClRDrRN?_t;Pc!R?h4@i@*VNdup)g6L1d%qaznBl=U|F$e|* z2GBWEN=W@FSdR|0<{Mk71llW(P5m*j`H21(%>27xaYX+M=AQRpe<9jAus!kraHt2J z!>EMRUxS&i!~{B%2GP%g_0T|LeToc-_7%+hU>xdm!QzO18O;24usEV$1|C~wU|?7W z7Dx2UVB*)n;)s43cq|6ACx#j1PDH;9Rzhil#S#57n0O#q9MLa>m9Vv7anOosNV`d?(Du{L_%)g+sQiK?+8GJxv8Vn5ZlzIh+IiNimN=W@XSUB*ofZUJh-@$4!ORzYi ze+Tn#23Q=ldK=r+Z~)ykri9eLgNX;Tg4~Jd z-+{;K7#J9uz~YGh9ZY;9SRB#6gN5f=R#3h}wC7>r`HU5G_K!8gBvy#OU^$$;bf;Pei{7 z7M@ZZknoHHZIVDrpEevIcVe0o0TxH}H(}vf0v1Q~H(~x=2o^{5H(}uex~oWu0ny)t ziT?+yNAx#g;(DAQ_aOS4F!5NhIHJD^3!fgaIHJD^6WSJ+;r{ECJz#-ns1&QAlX!!#kdu3o? zSP2zB1r-O6xiT;?oWWtvE0}s{zJuiuer|~QM$oZQ@YpH?1A`Ga_V5XWs-Ff;Z?K+c zIX5VMBKpy=@Sgw{NA#Cr;-I@~6rm^Hf#L=xeh91{(f@^s-^AgbH(>QJS0LQ{8!V3K z=fdKSod=-?WG@UG@POQp==178;tkr;6&N-=xd8GwVA7N1e zj{lnXK3!8TH=zKo0?agnV*-KgNO=jiY?)R9GnO`slC`UF9Nrl46!JWBu#k~ zY0AU#DTl`rlG|}clc6Q1@<>Rbg}KVe$OW77DAJUN<5F(y0zPpEd@K$|q(D!M*>TnMEZ6Fh0g1W%eVAtlY2kd|h!E615;uq(%z zX0R*AnPx!BNk}u;mE%k^*p=fmovmi z!?8#}93G6#;ZbN#!Fl>As$YT; zexc%FsIZw1P*>{`(wU^7^EyFYERZp)hgVZDYYXg!vvcDc7i6i@q4LW5DG6z{)7&?9d5(nLV2Xp^+BynVS zg6^~j1vyAPvcF(!(LmzJ>aRh^LD2nm4=N5)kL)iac97|i8EIs9hT#xD1MSFz%(;gY zkIm5W6p%QwdqCq$AR9pLfd&bP%isqRfX3r{By)nH;vfn##|>7_5CIZkU;xkDBAWvm zrvj+}Nq+<}pg0L605$&;lKIdhSHR|gMn7QVDzKR{ko!TSH?Vkt&76Y7CnK4IoR5&z zBbyI8w*h88vU*USf|(CHdk17bvN_21f<{+h>XFSsR*!5iXw(H}FERcCt#%;Ae9(Ok zF!Mp@4S|9jVbrXa;Vps{3_dyvCtC6c|c8BCD9 zpw$jA^IcLy-p>p73 zW}xa9Ld8H7EFFT>F9HcbF>KxjB)%9b2BIKmA3@GwJP8tjV%WSZNImRsNRSk4W)LI} zI;RdK2Ewovk|1&LwtSEv(jD|5@g-0(5Ct3028k~P2|zJy1_UI&3@QeqU^5XQ@v|TS zD2AP>2@*dC6$4SQvob;A=RpEc3@VF2OprKuvpdu}IOseo5EJBnYQ-=3em0PyptDAyG{}6|xq~1f< z66E-WonH--L5|<`AOR>wj$hE7#!zASj5El;)QVrw`Is>Ck@N2+m>>fK{2pYGy_=E5 zk>hs@k~nhwUPKZ{j$csy2$Mq2zp#4?)0f{FdsYhPb+<+twTY~^nzW_-b)@KBXA3zd^tz`g-Bab7YtZD{11nPd! znbRP(Agq8S4r{}J#2t{tL3a#*#6UO!NgQ*8IZ=EkXJP;Ac@1$5=gxRk~rv$V~`jKCm@L%3&ODVTnT9EVe7dX(8OWuB^RKHpMtvY0Gc>#J=X&?ao9RR254aiatjE< z)^jPKiNp5&!0wX=sRdzJc}vC}GpRX=dL^k9C3^8ue$X*`@N6~YY87-D&_V=M8MHYa zEPByZV48uLD!`&0NfM$nKP9mw5qfV7%zcoUs^$eMths$=I}DS)Bq}m_V{7 z&{Q+Ynm`lIBx?dqI}^}^ee#)PO`s`gk~M)QqDj^SnvN!v0-!5kh)_l#q2OA(g2&aM zg%{XYJ&~-5KtjQ86M=++T@!(X0@6fsLcy+yKtjQ;i9kZZu8Ek00$uh(D4{@?s^E!0 zTnkq4YazWv0WHzMOkD&L3U*Bd5(;)r1QH5J6Uhk$yCwn&1-m8!2?e_*L_$Ga3m1mD zdcnj6+6cg_%9tosM%YwgtYyWt579Wml!LaWFeI=qEkVAqjwrukF$U~caPtUqTOLNG z3044V@gaf?i!tE9z-J6t0lG2RLJP?dY|>~(padpDD~d3h7DN~$)FZ?|iU;(*KR0gT z?)n4G<$-qVLAz(L?j!>){jeQ^u)Cr_`u(BzDuMbnFmrI}hm9{I>j#ZR!}P&uT>4W$ zmM}0dAnOP19)#(G(YW-(#yMeQIUx6g#@%81U^FiMu<=l2{U9@7`d~CJ{jl*QWc{Fd zQc$cbGmHjY~i14n0s3Kz2W9 zo*$+UM&r^C8-GXE4_XfZ(+8t*>4)6`ja>eLcCEwo!Dw9iL3i+>yC1ZE2c{23CeHUAGF>FrVmEr(qDo_Kd4NE>4VX@^ux|x zMfN{v-49G3jK-xObj|~M_=DC5!SumsT>5*kxF58R2&NB4ED7yKWH5#OdpKKr5|>7 zF0%hY>pWrlU^FiMN3hrrTK@{u2cvQ6KZ8X-Xl@Xu4@TqCe+7$v(EKt?AB@JOA9gk{ zvj0Kr%wYOpG%o#5u-Ffpmxk$s(YW-#!J;3u4hp6ZM&r`|1&e;rd^SuUjK-z^4;KBP zd3cyU7>!Fm3uw{TPm&5eIXk7Y5u;>TPpTqRQXk7Ybu;>S^ zqk!py(YW-hV9^hnkB8}l(V#g~P*6jsoj^q<80$dw*C9`iL+6jd3ZMjNt`}q$Y`z{U z%pl+dWkKgdLG3TlSv#=w44Z2P&5?rahbn_=VqjPWt9aoe5C%vsgasi%bDAJCap^}_ zkIo0p5rV|f@A`(>k3822vJo0AASM`t<~FhVAG+`xHYW=5Kj@SqkXu0-Vg3j8sj=CA z3+jJR_<+>IFuMJq^MA0}?|{XA(AsZw`#~qEV6&eAy1*M0XE3`#G`jtulU}gdUjVfq zwoVGFkM@;~To7p!5mT3!>5OftAVV<%b8<{jl{upzs5YX`#Dc6na-P zy8Ud>#XE$;57bY?7Je(B_9KTMX#5S`ep4Lw>p<;CUdw~c|4BIXI}oXV0uKElQ2oej zkFeQ)2#5YOsD6|+I9SSm(79&V;=hGR{jyAuy$9&=w+N~qR!)N44#Mc^Cj^K7T~Pg? zJO|PT!|3|`nHa!hsp#qN1~mSW(;w&*GW7Vb#$i7bbdeaL^jC(%eha9>k<%Y&Ocve# zxj5|CfZ7kGVBTjy_x}YP`YoUu38f!aX6*6jMWlW!9QtFR`k@p~_vho#p99qhrEuzB zfjMWp^(9Qsc{^+S^(PWvlZu;-r) zs7B=c13E1ZJ^e1hVZQ)$F(sk=GarZjC!qEt=O0j81>JtoIegg4FEgn9&|tvn|DQPA z?*`RRDF5iOVvqj_BK0TZ(4R%5{uwy**Fg0X@;~U@Ky2aH1JzF`|1hy(_x}*8}7*Y2XqP{y8Z8Q*dGA3pHTWyV#gl;2~hn|3TOC*hHm!zXhrh zO5xOh5QqM0P>oOur~Yp^^sj(wB$R)&Ik1P{0V4G$;Lv}ANc~fB=>I^Z{_{}%OlS=g z4(Q@|(3m4U@Q}uHU}C2@u;-r+X!?b%hX?f^K&Nq{r{AwQ?B777{U31Hp8-8!0@;4h z>8j}VOLIcv58eL}(2fHk|BG>A_rC|Iv&6u_fNVeLv|M!i9dX#t0Nrdr$bK6f_G^GT zOAHJQ8$gu<0|Nsn{6VJ^quZZ~!~PXS+Mj^K{u`jh4rum+PG3g1zY&N10nkkq&}0Nl zZt(d;m_Q8<`#V639T*rGVDtDO|AWRV(Cwdv!~Pji`_c11Oh3&2sW|MH08Q32FfhQ} z53(P0+9ymu%v{ji2Kg8kw6HtvXdte5@?1%C1;BbEe7Wae3 zieUO-<}z_%&p!{K_CqO{br|l~z@h&KR3pqDm;o^RVSHsS?D=m67Wad06@lr8nF~5E z1Y7tEKsWC|odL5B!~OX<+^+%E53>hm0L*?EKMRNZKVWe`===wmewev^IP7Vvk#^p z#(#=Ke+5)OA@@JP;ruf!Pmp|4$tDcR=ljsfW22oiD@Sz`24NehezfKX!v&~*&^h5CbubKbKa6jV!~Ywg{x5*;_W}7Ibj}M*Kg|E2W)gbX zgUnWl1d$93zGw*$-Tfdwy4yiIHJ}4`C!qcStz84vMd&6VX95XuTka2AymUqCw}7gJ@8j5k!O9ZXg=eh62%`whV{{wJAU}sBQ<*pgI;r zgHEOf(Y;XnKxIFO51NAp(V(-HKs2aK0@0wegg`Xt>>v;g$}1px4pcvA?i|Dit;++^ zp!5WyL2C*@G-z!gh+Ym=51N+%@j+)%fN0R#IS>t6!v>;3YtcY7XiXT12CeM^(V#V2 zAR4q*07Qe%Fagn^wNoG(w1x>pgVqv(XwaG-5Di*e1ELQ@?FXHe0^)<_CqOi4?F)zo ztw90NptT?%8nmVZM1$5=fN0R!4ImnHrWS|>o!teZL1%S==$laUL1&49_@H%eAR2Tw z7l^(Ol?Tn0gZQxd4bXZv5Fa#$3Zg-Kw?Q;$P8>vo=B7b3Xx$o!2F;a%XxRJ)=u9mT zAG9tFM1OW)|r9iK}j4$b3?^>p)@~~ z2F+7|;{K5lG{3Ocy#-| zNbxY{0Y_qq(Q9pw&chzyfPpykH8Vs25v`p!U?B#H=H?>-(T*{(he4?$*rV|cC`Wp9 z?)CWp|G!7)RtGRO)#CsE{}^edHQ@jM|0s#Wqq`NXuXid)3MF#DieWZ`N(}~>;!Xh= zixnjfpk`qvL74LHsSwvq2mnVS#OiLaTRl1_L?8qq$p=(tz_hZ06A(0|zs>`P5sC{v z5WxhJM0N|z6Of>V$sju&MFwgKvVq;Mpg4nMyb@MOG&CLo1$;Ct9-7}scy!jjfCiN7 z3lC5zxxVl~akxh}NCcEcVQzwmAiD)D0(AqZ&}L{oP!fhL_}T;PL3ER#egFw08;1~v znu+YM<|7i(v4u0N0*2WOuIr#HB&&e9KHm1rrz^#?4kce{Q7 zXR7Ov&;pr?sTQ16V75&-32_OiyaR_NvZul9<^vpPsn_)dC_}?cfGUze<13)>SwSoM z_krdLk%f;nfF@u;W$24z4HLoH78F;_2T%;#2bO>a3UcgoYQ~iBLY=bx=OsVNgEYO<+FMIfFAaFw!g3 zwcxbdI{_SNSW+sos^$Z5|H4uzIG=QuewcvBI|`u8@6lQMz@yvs0X%#=T|xQj1)L8` zQgB-zAm@+cuAl}ADE)o#uy*}X?BvlM3d&&*kjv!GL*NjH#v!8C1R0CuOpj*Q4~(z3 zfYm~Mg6?vU&d?Vy*MsVi2xd?%zxTwS|NlF;9{Gcs^=pNO#ToeCC#1ptx+R4F8cUeAJ=1dRdoAZtCqKlMP%0sfXcP_@_F8UV7VcPb=U zkxZQmk!XbkKavDQ2f}oS0*LJ%-3|hv#u~&1(6OPAAku~ecxUSmQ26#j4Moyp4VK}b z1Zw2*dK_=P@#p`4P&NEo(F2QWZLn&OPOvg`1)#(Vk?3?1@aUZic3*ERB%#3l@$v~M z;lO1JK%s!#L_~EW*i1-N!cFi%2!cynghV%kNAFZj6ColHPrpq4_y7N~)~g_I9&5b@ zqG0jX8=&CP+qwbGL68*a0g;@5CfPd`EP|n{Xx+$@O29^DKcovjQY1G>RfH@I!y z{DZMX*#jct(cJ)U?6w{#<%Bqq@ijZdk&GU_tqZ_W*b8zXq|woN4wk@QhW`KmpMM+J zTi}*3e+#Jl<^c-z8i{~>7`UT7d?|DsrrZb-?Z4K5BmI$Jp)K@Osj-Nu1% zb4Tm-KmY$X>;;hwC33LzfKowa1m;y+a$D;t8bD+L&{>?Z6RIsOb7(<$){4Jm!|4VQbf_f6DrBE=aeF809 zpeDSwhln9(186Ske2R^8m4t-05NMx&d5n^0$DtXJSZqx?b?;cD(>r z)(jd<0JqKdS1`e=ufra#w?TDWC`jQBaO2=UB&0fTfCBV}N2luvu({yU$MpnQ3A}xM z0?B1?HaM4*@OgBDR6_#v^?i?K*9(j<^FSR%Y@V17D*O|{79smj8#L133Tof%@IV%C ze!=Jg^4xJ(&~f*mfW6^i?fRft-lH4l6GV~RoO^-MquKQa;zA_cqHHO=ytt< z;^fYQ9-TKJh35B<9-S9DUEg%OzVVph(H(ljqxp~mO29IBbT@#zrp-q*puIglZX!wBqAa9|?Dpt|>g)b0m$YF@1W|Nnn1XwVN7dN{Ct zMt*LpepX^`YO#KKeo=ODL1J>MeokgmadC;hXI^qnX-cYoRA@Ovm4aVsPL2XpiGoXNQEFOh5$N8q6h#LAq^#8B5(PzDh4}cq(j4fu zpYg@1Ica*1MMa5~!I@R53U&$x3TkQ!N>N}TD+TAoyuADpg@XJ7g|wplT!loCN`>;w zk_?5se1+7U)ZEm(l43>padBww34%F5AvwPkH^4 zmYA87nxasWuTW5wUyxdqQweizD#YK43K}SmhJ*v$P*5O{<8H^C^n94xi%SxVN)&8t z6;kt3P#l?_Z)N3JPyiCvg~duDgb$7lkc5o_SUV^-Aijr3HrS}pJkW6tnTa`>RjDZo zkT6s5ECF3em|vt&TAZ2!(g_MZ1_sZ(l++3Z8wGHp&{oihPt8m5EDlS|$xKnOS1?qt zQZPUcM1(OJiNy-(`FW`d1&PHaU|-~?K|>D|J`i)Y72-4Vl0n`Cn~z9vM4JDS+jQ6%vz^Q;Q*qG(I`8ATc?!q*B4oRslWnBisQ` z_(iG3sYPX}3UF;Xsl~+#B^il%5Kk$9VjmG~kicVLU??t0EXhn(K*6e^ zf|CP0rK1@ER%oZAU}#X9V`r`4;s(-zT-dmz!gH++M6tC(5J(X`dpkpNH{1rqrOxmW zL1mQXXQto^9V;uix$cRXd8sKHSiD7JSB7Zeb{(i}0F_|6b{d)r$@zK3C77X3W9KnI z!Ves+pkxI~BhbK4)c_^Q_!8tWOU_6v!k!X9GCB%|Mi$_xhv-zWRmjQDOIIk(E6z*@ z70{V^CFl_fP2Wh)h!28f6>wq>!A!PbAvGOvhKVoHQAo|SjSV~1sqf`oGCs5f5&b!b&n_q;#NQStGn0yHf2dEBYpIKQs zfvU=4=Zw_kY-k~Y@FXN8kZKR)3IJZ}(=toIoDQau(ig0SViN+Y2tkf_E-flb%`4G> z6d@QcM@nqy#TM9X5P{cxztoBnXaM0T;Grqi8d{o>5;Gv%85k&!A0%JWAWKodd`HgV z)OPR#XYhO*bVLJkM-Zs*cN}t5G;D06v-Zb?*u&s80H97Dc+R2Q^#{rn6to+MBL5%M zuZMOiPh#rtc3?U9LcZldsV>M)kLCj`psry9(%`|5ZU+|C|NsBjL&pb8SSGxF0ksJ} zy9Cn2uphJt3DOks+J)4I@K2D+5C#RB5Us>rEbp0M?^C49VvhH}WtXWnw+c&2WXu zXCn{87G~Cm+zf}A?|>xsu^NBnX86szf@vcU!*&kVxjYQFIgC4b7-n#S*y}jgf>gcY z0vXlK4Kj5NH!B0fM;?g#1vE_<7^X0?_A)bUXZ*+r4jVp8Rt5&wq}_}R7ofi6jAqSa zXoqrmOj&&xTv-_yQXxig#+dyNf0s;=h6HIKBtB}4EMwE0BHQvqdOF3Y78_5*6sTPv9ba(OAj#%E#-xR z2C-fsjXSp-D3yd58Ub2n0v~DeusmGKz5_Ho@|qPq72k58gbk$dwI_&#IT&@y4>Csw zp8ZD{1R81vtqA}xV?mt{gd}%x4nfYxpa}wS2ISv%z;S0TBLjmY*a_e}rw~Ir(2Nd_ zfo=w9sG|C}x%L4=i4ck-djl9>v+e?U4B`*O039eCVP?V{jYIY@L@#7i(WCPq#D-ho z!L##_QUS#@RP~HEj)5lTK!E}=;k6WKTpC3OeBldnnSdoVfqf5kH7sR8Msh(*8eV|h z30fY{;MsY^qxtv$5+R??=U@kVHXo7jXnxK3`UR-i5daS;f@1;^f*=RA9w<=)8RF49 z12jtuW?CLD;qz#IEdeXPUcUqx0a{K0$`z>k;aLN;S^++r3^wL?18CtH=xh!s7c?{s zs&&EK?g=1SFcUGc0O3LdO%4`lNYfKYBkjN}T#&ITEZ2&0(O$M4&SD1I$g} z=~|E|xF|%9HmsiP4oL6-jhJ^EK;j(LgCH@O>(O1&?E%$^W&$+Sx?O+3bb?x95VwO; z2Pgx4@aT5n@UT3@KlK27rU_IV{Q!;lcZR+JISHj91`_b-273vjx3_@Nqucj`M`s}i znC>?8=&t?Y(RtCM^ANb`fjAw-&!E;FIP0S%S5WBv0K4bl17;7#3ouv1{0qu8Pz{jU zjzDZ9avjJ=;KC8MT%e^5w9yDu;(^u=Kn?A5{nPFGhkyHl)&r#h;L-p|62fQj=nj1W zo}2(JqlC;zb-Vsa+rhxldZ1JqqR2r2s)`d_LqJr4rI4~0wB_)c5#~xz+<<)84bE7Q z$N*(f_;e3)+W@p67Bt5OQS8xrpi~l4UAi$bFhE+Ypzwu-{{;_l8F0Y^s=hbiKX{6+ za{?$6gPGkBX6FSD#si>rDxfIn6#-2x-asnIAWFe5^ym!$$zJg2?m!sAfK@m}f&<}@GR#Fa@wF^*`A7f|1;j z@)NvA1!-Y}%QVn>FmOQkdT@ZVX*Z}GKjzU1X~@BJqq`28JwV>-1~+6pEDsgcfenK4 zTMtxlr}4i(@Y#c3>%ePCkmE1DYJR}z!FdQKeCRWO#DUNJQ3pQpM;u7w2OXrqz);No z$%9|#z-zfr`~u*eE1&pd4uXX|z*QUr14Dy{;RR@RLvB?-Y==}AQ1|tEf%4=Jk4{LQ zM9a;f7CrJ>RqVAUXl3hQiVIL77y(aw)c}Cx(6TDR5 zhKDw2MZYVknn5g`0J+8Wg$E<3tF!~T96jy|T2l>LLvX^w+Vw?o2E@Hk$AP*S;3Wko zKw42_Q3e#lNH!b&s8yEixgO^2GoiW z056ka-wEpby=Dd1jvkCBK-m@=ub}f<(W*+ExgYH451_~ZmjDg|9+rn->7yUhDKK*o z^-}^`{RFEQAgw--dm}(jtA_a0A;M#TixY|fMW|OLH}TUeSBz?Vc@n5IO#NiR$^n#f1nlAU|A1q*AK zmHTw3Uhn{mGB5AZ^fK1uc7oG)Ym~P2k+?3tF}Q16)TV)gV~YBPeH-vV(*0wH2rV!&Rma z&L?2q3=9wWJuEMjvw;E=dqBPhg~ks^yg|nc5hX3i^b&b+YOr?wP$CAhfC03O3e>WJ z#5lNN3M*Gp%V|*i$J+Hp5wujyV#Zdmen9VwfkObJE`X&%SgC-K=AdqeL?5{O1?hHl zgDZ;{NZ|-A6kdRPE}&8fxkO+*fp8DVH%R7z`oMS$0~JU=JPtm>*1rV%iG)}M`L3G* zlv_(dCF76R+2D{bRRu={GzEd#NUeWZzt0*h(G9B8N_fC*WDVd<4yiPu8qk%%(*mR= z4stsv9l%nVqDN!x2hfcmWx}9@hLS5`i3xjp0GUEcYC_l#8U^Tf#hoMIWfQo^1I^JM z&2QipLg$4J*E`^>4DF{{yFP%`vd(On=@OLHOC2B@5F=CIUJpuA0wpwf6uj_&j6{NZ zTrdAJFfj0MbG_3H-a0A@F$&VYw|0HN-wfKT3lU_1BuI=Ab(pNR>yJ_q2nRG?4|dK= z&=zP9#DQBT>xVK=Z~>25HvRDER!}e*sPMpqNGsCqfj!LXBY61vVLE5Y!d$5)+<2 zkm@c_?nab!q?T3KQkFvkXwfdgWMu^jRqzNbq!0oP;3N7I=xNFUbkrroOVA}Khy(?i zi+JJD?GOR7lD`?WLmgr)F{z0Uq7;;x0wP}5p{66SFFuqRLDYaswGWU|4b;>4;L*zi z+RYB?Ui<(xdcjRL$Yv?%oD#@ic#;Z88suLrwFkB^1!riG9|;C4EVqJMK@hitdi@yb z6(zTV)Pi&CHLST6Bn`5gzj-UD%>s%Tkbgm`7;kPBgxC)XU+|F0>nhYBhI#5k8K^*i z0cuHr(jTZV2M)Op9*igWw=r}uK?3#^#5k}~__HC{!60WsGXOXnf;>olY-oryzmIIZ zyR);Ef<|akXs^3c4p7gh6UR=d&|7@(HvtIrFkb^RR=a&OvfEAV~%W2JrD9FnKqG zd<;|`m;M^4JoqkcnEoh)e$crSASK{q%wY0Nu3!Zq`$6YGfaJmFgTv%qo0$uF*f~J* zpt2q$55D6WNj?KA4>~6SB#+DeGN7I&9{+*#GFAonfJ2TQe1ZuxEc`(Cbb~NRjU4oR zU3eI}_b@lJFbgs9uycUaK#xgd=wO7LV*^*`(ag+T%?S1{NL>lYFa`z&_#HGzeq!1V zR>lDGH|*XA@VSdHHHip$*u4nJAoF1IOmScZAbVipW{d6~*JfsBV}yG^=SYBz0G$&7 zI=>q3Zjd@=h&qsaQkX!h7#Ko96x_Z5uzetT*uB=^a~fgtUSMgkf0jV?gEk7m?O<90 zRshm}1S$_c=Lx3Y4=l|9@(=7DkyhwAlW;RY;akB5RtPeO2ONbA4B%sHVCF=ErNQpd zfy#rAvw_J6BIJFb^5A2uVDe19U0uQp#6Wpv3e+6%#sio+uFcF$ zX<(zkZrK4<13Kdc?jNQ$umX@@Zb0QhYr*02v0!Pi{vS|z(A^1e`7ngM1UNz&7^INn zEEFMc0hI@*U6>o0+`$S!eu#j|gU*71n-B8CT(A3=22VSw9%+(jn?V@lye{4_6)qorw!_F0MSY z1F9cfh{N1c0x=)tjs;-L85lrk`hb}*HK4HTg{T9$g8_Q!h84&%n3__AJnU|IRb=@D zggoqyde9kC@Obt?$iwcc$E6>3XFaxb1acqj?s{zg1j)nhu*W42yUQLFCUEz~BiskO z(;i$`!Tiq@4psm%A9lAr_zWV-72JFrkP;+pV2OOYEoq>S?eB>z19!Svz z)~^AT2Q_sN?ra8I0CJ}XR6YshU6_6*NPz>A&w$E<+YB)Ia3;#0$5pm-fDR$UQ`c)i<-uz?VD4vvG=@O_^MK0ZYD;85eY>^}jO$7TNus600NL1iQdXdMp&14AUJ%>(lvs2=wR)k=^uQU|IA zS6=oZAfE%32OodBB0kzyP{W2QHrjmIkL$9jH9GV+glD7_0!~J|Cz&t~knp%7ZDGex&wt z4_JbM0b3k_%wGeQ$5s}AxXNlC=zTxf@(`%})Pc%_c5TDM$FrBY zhoza7X(>1u7(i($1gfqMxhw$HJJ9+G$Q28iic_v5$1f+ilR34>H zuYkA#B!7c|{12!+uJS|zJadbu{R5T9m6ju*@}T>M;9*sVa9;&f9;g4I@}Ow}xPGQ? zumK?d!S2QZ-KPYXuK`Pg)9MYVeq7=611gWpehKKI^SIKQ1ysHjxx8R*02dY@_eDVE zTTtS!9_&Dnd<9emT6#M<)_TPZY$Dzna!sUNJrI;BqPz4wu_jfZQ ziG$n$QUp40j}gfnm^es|nE`ZiC5VNJnHfMQS)z)8c+3o-lPy6kRLsl(I_VNs48&t* z0G)gZVxeMY22kr5RSd*qW&oXx31XpQW(LqnnW$nQ9y0^zLR62;5_I>{4BfPsMl)F%hU;{s^=9<;0trh=IPbmAwBhoG4mK*xC@_%IeT1L#Ch z7!N@+Gk{JAMet!PW(II?62^to%nYCtMB!XGgP8$zq9~jTXD~B>P8fxA;S6R5Q11!O zg)^8LKqrvGxo`$Exc36*!WqmApc6{rTsVW70d!(1oC{|#Gr&fY;6h*qGXrQiAIwA{ zm>EDPoT3PUIn3Y_KwGFRGXv;k zRwxIFVrBrh0FXo=OlAhq$*mAJjO+xT4VuBg08P)xDUz81G=2_KiJ+Moz!R$o0Vs=^ z0Xn-1<-;gu2G~d-OawwRLl#a#I7lQj1L(w9BmpRsnE`ZyER=&pF*9HuF2M=DvnqoD z*1tne@yrb1v3evEAWUWk&{0MZHZsY~0A4zTECgmVGk{L21vBBqQmDNLp#2%-5`>un zbfPU>DV)K~06O6o&V@6W89*oA!nt6^U#R(@I}JbrpfhPfGzc>@fKJ8*u~0EH1L&k& zR51{bnE{l#KrB?u%m6w`7gcO8_ztTK1_fvv6?9J^Oa(Io=)_$Z4?=T-?>x$2Xn?9m zu34EGKqvD;)FG4140n*Za5ggo=;U5F7tUa20G;Fu=fWAx44{*J;ao5y5b7S-cnIj8 z8n6TdsD1&R01V?HXl8~d2o4g9nE`Y{Fp>b2$;|K^%0i`>89*lpql$re%nZn}2NHo` zW`;Kq1{%rC06K9PO%UvU(AE)b;-C|Wv5A9DD8?oZI zD36%|bkZ@DgG4bifJQ-(1fWc22GB{!P!19WPI5?m7?YU+bW$>mhoG4mU?biLF%XNH z0d$fwh=q!o89*m1ql$re%nYEDmO(63%*+5fc^OsA7JN5W1_SKU573MlOa(IoXyhHn zL(t3&{K(BbxCAo;=!|1H7tHt!GauR?ngSMu5X=mqlb#`L7#Rq@Ybk?a0aQJ54adv? zIuRPC5<(w_s)vo!O@j!7NoEGn$gcE@lR49N{B}LtGw1yc#^7h9S%_4J-~F=!e<|qBerX zp@|$M0L9$kavWNSLB&8+Dp(x67ZJpTB6{hIv6Yt?j6F#U<_skSG#O?F zXlEHioF7dD!ez#|VFf0RnQlQc%#cxM5EBJ6Ghn7$kOF4d#ZVv)5@v?<){#UYOlAh~ zj2(o7L^3mAre}~eGXrLNhKOUPXNWj>#0VGt7qGec%SP{cqSX2^^kh>3!k89<{JC_-QkGlM3WMkkmVw9tjXd}apl=oXlb zOfWNGmNOuEW(Lf11|qHpqA)Ns1NzO}5GBkE=r_s0#K9xW5DpT_3>oo75`i$88H^ze zG?JMCdNB%yICz!{O%zm~fNq$_5N2QokBVRux4;wxmv7)%HVipt2Jq}57IE;(3@qZ{ zSs*OpxXN=_t&XaNnE`a0J*pUp#|)Xp1u;=DGXr?E6h#cgVPHd!UT&r=+lVN56 z&r+a?g5oh6LkuLq%mAKk1~E}EGXwTxbeI|9P}IRV%nb1`CJN2W0G@$D5d(3U84^Jh z24-de&)Q-U2aQIe3ODdDFeo978-wP1Kq_YA5Z?wCM~o-KS|k^7h`#}gBgUCw=8Nz$ zU~N?>^Mc%i7=MP#-(97XCe;u^TFy71S2AhKz-v-a| zF)%P#^I`Xw6CcQ5h;eUNxW$0Q5#!!4@f3E@+&y9x1hnQ16fadc%#P~d{rS%^y zju;h#m9SBQ*xjFrL%d255}vSd1g*^jh38yBkb4m0@URi3i#W{T5(245jL(DDC^0ZF z*a$H&C?fTLVKuIw5O#Nh`mvb3K?a6Gu=$8_d)Ns3dmQF43u8B52#2_mF!pe8g^DkO zc99N(0*8TtAxaqJU&MR?Ea%+7q5dsYJOer*1D=m%U|?Vpf!Nyz6^E5X`63|m5%Uf( z^*=MrQ-Ic0fy{Z0!<_$6 zd-I@OB+!~aka{&SkomA!Vqk!^s1n4myC+`^yZc+9;s((5Kd_OYnK;DPLB;K$T~3(4 zq{SiTPl1X)e4y@cb0TxHh2f=!tnoEKv<8LSq5T`3{)J}(o&Ma9?qsR zAonBYn_&5?3WxfsIK;Q%5Wfm_&lG6*!%D6nIMnmXVt1#uEXbXh^;auc9J5}y4;Dwv zmx0&YF)%Q=$$`v4%$LDNz8-?b5%XoRk>xshkb1Mri@`?X>=Z!i5%Xf; z^>Yji49gX;`|AK$J!bv#1&8|IVD*T3G+0YcT@hq2V!jMk|3-tw5%XoR`0W9UBj&|m z>Fo$u9K72Ml#C(kff*PWz9?dM{~xe=#5@|TePW{oat~r&57qSKVHE$LKMkb1c|e$Zo`S_O>$PM}kok!DLGZdj1_lNmEs!{39uQVe_JG9^^MEk%6JT-7 z@>xwAWDa6}5Z03n28$!+`(Qoc7O*&C-VnS-kb!|=Cs-UY-v`Tg0y-e`VXZR;2Jo6c z1_p+FusCAA4>lq*M+bX)UIkWgRt_d5G;-0VxUB<=BjyKTJ>F^9#9JI3$T&@_zV_@wH6r|!0YoE7#Jp)fz%`B4Pog-+Z-g0m^XyEzX&Xj zm>&eM!((7zI13g>%maeg-!U*SNLYaSJBWEb*a*9p1$KW0gViJE`=HGrhEyEti*Sf{ zfyA*)?@R}YL!uUiT#rMX0le)FddYNhK>#``Qzt z!pHgha->h59*%c>4Rr$AfJ& zw1AvljeJLfC+V&*B;X1|Q;0S2gSb6|P2+uX4GmmfT}?o@F1QAnK~#Vwg3aSy@wu7m zfn;b34?xIO2zbK`=2H3wlLa*FQeAWLgbmDX0nlUzIYAps@EgK{pEz?34It42I_2FA zazP3i$;62CWMT$&XRt-Qt7{oNm4w8H7{t2nkhZx4Y=Hd$%Z$lG^2VlpX zd!mMrtDzD2z;@`F=dMY3!kD00mSCem$D0!sSIL;slkAggXk_8)>PlSfc*CNdzDd&1 z5b3CU{NWETXOOP1AR_@$znsa%8`H3GMNKT2@f8fuPLzfT@iw8Cn}+eh#__Ir{ev|Y z@FhPqJCcJz`3!f6nHa{$LyokM2i1SzJCG7fGV}A|6Z2ByQ&Njdib|8ge1ptPhIn@$ zeO7mQEK{c(RIYtHNZ0cHuL&^mvMfGX|ZYkAGhP&A) z$|^&Q&8)|1k_6QgT*GklG51}QdSY8 z78YiN+9aSn9&8w&3-KbBLeL0jA?R#~Q_2OmE*IRo42?l8skw;-8Tm!2CgF*hC9YXu3o(Sjo-&K_EiFl{Fn3HYEX^!R zh4^QH+M_0*YYrhUfH^BDH77N(80suo-XuNjC~0?^L$4o%IE-|=3B_AtFruWQzUi?Z@Qo_~eZ2c+f?m;FO1a=#jILE39&Y45>g0N21$6 z&W5md6D-p?8@U=1tsU$hqE$l!FC+}5Hx4obnm)1RIcG!HOo$Tj-DPy{C1G8bGryvg0iRN{chV!+50UIYOn$z{Nh; zS5Aq^*`OlD6x{eRL@xIO@{3DQ0t1o8xHIZGr#W3#Nt)jR9VHtFM8$*R9Eb9~_MtwBE-gs~rMF^OO$N?Skj5mq z)o5rG<(!|FTnf5iGP%;iJ+&kxGda5$n$@V^nKJ~HXOPYu4H`1$(5v8~&PNFjEE7H` z(Mo(l0gDpSOI1^+)bz|ei0eq#ZS0zt0?|uw;5#oB6wXHAdV`?i6lklQP%pTk0FsJO zlA<9v%_J6QBbUJ7qy^6~#D^?WzX8P(OOM2y61SqnT$oEyV>TeMv^W(aodk+gXbEl# z8sdi5lB9<=xcG$Cz=q(EgtfB_4TC|~)Y56TGPnX$P)`m+ z8pXSYCf=DjIiP$CF$`P+fI6?3J!81BCczjT)+j&H3v)t!99RQ``X<9`QK}a@hQ{zo zMIS`72|5rO59+Fd?(n8_^By{&56>jQrtzTJR#5VVPYyu)s{`jcSgt{G91TkC)Iv~U zMY~D?+$u~hf@Du@nwy(nmI?|0;;l0@0nhz<=9Q$T7m?&ac*~vWc!C#Q&@u%& z$eCY6gE9p=odfOXVRoWOPv3+(!B87vJs-OHk^Z3yi+NZ!pnh0l#uw6*6*Nu<#&)Fj z4WNt$&!F@T1N^y`zHWh~zk!JlLj%OLhHF5uX*{HdX9-z66A$XSgBquxN`(fc48C*< zZMndL1==|%%EX3gQc=T0#AWg6`0MX?lKGdLv4m`YrA&acQ#$qiKNj4gmY1RKON#K$Ls8~U*MG9y!z)xzNMXur~&oXoUJDy%0i3qVgm;H8+5 z1(=|4fq4jD`yZC!iBXHIu*GLS{^Av%PV@p5pIX!+G#Ry~g!OR1H6=b%(32Q=jU6Z; z4b7pIE~Mu}tU>TF1+Ucu8w71T$AdaH#2N!n@^JScL|{1z(cyqEOG6$?gIbGFg`RRC z2^mjH2YCVCA`DkZCjl*qU^L@k+! z3^;6>&^!%oIlxl~eSM9-+!mDH2PXVc2Pg){4X~jL&{A4sXzAey9swGd#yUJvKwImO zA`;DIsA&u{;Ud;nqZgIXIul|lf%W~MK`nU00~R~PTaA{xs6JSn7!0k*K09LvZ zEazYfQL`wdW`g+{UtNUeOK1U(XgJ~1iyk?!dLu6pb7fshB4kAze8?GEc7ZD=`W7Hi zXTw4VmQcYHI@oI9LE$=3DF;g?h+2I>oQ9soK~95<5ud-XmE%}b2k}Ot$1J4jo(qXt z*tR$1ghxc`h9whl;szTP;)ycgzz`o566R-U5FejhQIVLGS!QTt5FcNh8K0b!SX>-m zQdy81pP84I4_bl{5{#kM6E?913dZ0Pi_HAu_@u<*R1?t59b|D#d`fYCd`4nkN)C8v z8eI`&Ffl&4A~8O(B()+Fa%&vyggnqzNYJj+KcK6f|NsB*2;Kb%66a)OV1S9kZWsWG zgLb3B#H*0hgLap~#Cwp$d63Lmfg}#vbqZ5|3rU<0Nj+>oJjh9OAJ3wCMKE!=WC0Ydz>(8_-=1NbWp`q#oH{ zA8?2>f-HoZgRGthNgT8*7ZyH(NaDgs_J%>lK_`cTPA!F6#}Ee<2T`I(>dQd_PLlPH9Qr`^~2bmAr^$R<@Xcbf(L`fp4huz@^5(n-2g_$n`JzoeU4m!0LCa!@b zj%=?nk~nfWcq55}?sbHjlZqq`IyDw1UWp_QIu#fu-hw2KZ2k-+apZ8`0u@IOhqF*| zkiQg>!r?xWII=rGB8elr^DmM(vO9%XAQ=W^J~NW}nn>cv<~tyXBbyI8*BoRL$Q)$z zW02G%hXd?RKahGQBzrrM)FZoR4U#x=d2$R%TouWj8%W~F`T7--I4JMK;)@-WxS{D5 zIlajsi6f^s9VBrLBztXei2ERkYa*#nMiSRT67NJ3*G3Ybg(R+nB)$bn966nwL=x9U zQhyIgTn|Ycbj~*{9+Aa4pyx+{;tM%FNFs?Nrw0`zapZXSLJ~)Ie+-g1vioz8#F5=! zgCvgZ&K?}%bCAT5-M<1!9NGPcki?PQa~(+>**$NN#F5>@2t5}I6mH1kVo2i1?ome) zM|O`9k~ngBh9QX~=ZgX)apZhagCvfeFM5!~k@LkKByr^W`V5jdvc1oc#7&XX73BPK z&>8Fu3}#5;%FuJYK;eVzPGcl-WcRosi6gszDv~&IyJZQIIC8zP8He~WByme5cS6oh zhq&JgNn8_p)HcZd$l}3B;>h8XjUWo>WP44K#F5)eu)F?1?m-TpOdRT`;}GA0L;OCH zICA*>MH070iZ9sReIWPPAc-qN5845VgUt{gK2~ki_GV#F4|N4@uk} zN&RXhaR(&vBS_+oNaEL##GR1DO`u1$gWT_oBp!t%jvVieNaD!xJ_|`4Iowtvi6e*G zJ|uDEaJ!BqjvQ{Fb6a8c3v#&qMpBO)Zi3LG=0W~K7S})$M^0BoNaD!(YYLJ$a(S{7 zN!$b}+|DA2BbWd0aESBsfqVriACTQ?i$gpRhj=Ou@k$)xy*R`dB8elre=830lStyo z?!SU0j$H5DL=s1C$AZp(1%(7CzFd*Q(+hg8AV}N;Njx1%9J!q{14$gY{9J(~j%@yM z9OCz&;^5){)_GxIV0Zx)2e}7ymlZ6(GebKdAaT%b9x!n=Bymt55GHPfB<_XeFFPc0 zZzS)aWPdq9#X;(qA(`V26$hzbj+734ki?PA2}BZKfuueRDh@J# zC6f8D8z(^GpwrG^=@VHTblMqA9CnTvNImGZGnhCuTQh*%i8$4a0e;g3NIi0Xf!)9W z5(k~i1~UhCE+j}CbSfK69Cj`nNF2F;2fJYgBp!t1FJy7h*#KVxpVJD`8#F5K&j$9AIPLc+RBbze=oZ2DvLO7E7 zu=8F);SB1E!R~Q{-CO|^hc-tUVE%=P!_GT|-TVL(hutRzyJ-RBo(Lp+k;5ShNgP>y zG?F-Sc*Y=!!_GGZnIDTJ4m(*KBn~>$4HjRp6U{;5@kr`n=bVDX6OhDV_e+7qk<~9o z3QuJ7VfS5u)F&dD13Ot0Bn}#*gSiKGG9^eHxg0}IZ^-5#ha0jvu=6WH<{dqf966ke zkkliWOUU62J7*JQK5{tcAcX^R_#o$NWd9MKaacJFJ1-a}4$E)I;arDgFYKgVkiE$Lsl7<)tsY7JIV5r9aszhKEyx_?^!5=+ zJ#u{q^A|`x=#puee_=P1z}yeJZxwcP2uvL2U)Xv2F!38u`(Wh~OdRAUkQD6343NFZ z^$zT229P*tjt1r)*m=Gn@kXR@KrUyRki?PG53)GyoOF;mEjZMJ=3-#>BB!@D9O~O~ zh=cBUfSCik`3ht&=nh+$I4nKD!UuN$E6l$zaRq4G4t7%wOdM1fg2EFPUm)|5(-m_2 ztqaMW$n6tQyTS$9Uxl563^E5<9Co5SNW2@#9N5XhAaUgJA7uabAgM?9FYMk~TKKmY z$zJ603c0+6xd-I_J|y+9`wT$h$m)^He`NKrbPJCc=y)0I1aX-74QM>}fg+880o;BD zg|h_6A_l~{;UF$@JkE!z2Zl;aUEB@oUXVC) z{37RziAd%ki%&ulhqXgN<{+2zu=YPJd|>zW!s=zXIMf}m8`WUq2_OR*7~nUafw;)w z2D_mMrXFTKEd9g9q2|NxZ-9v}02#=@0KYLF#6>nA-951TgF*MhgTfPL4lMt|&Z&oq z{{R`tzyQBV48%n?A9nseNF0<-VEGieos29FyKw@fehO0f!|o*liBClmN6x3yki=p6 z0_INGJ;b!gr_+(_h23-qa_0;raoEjcAaUgK9J!pIiKHG@FM!;S+&_iYQy_C@A*qL* z+z%2*ZlA;IJCHbXJqt@GAo1Bq<{-D*=OBs0+9BxfL2kz)y9ah7AG-Ol`~@-x6z{Nm zj$!Q|m^duG!P=FCSj z2RVEeAc-Tl&yoAl$nk|Nj@(W|Zm%NeN91@%uJ?%vXJmISL~hNJ+RQL< zpV zA9*|nIs9Qa=7GWixt|ETaRnrf+z&-w|AVX^G{y@HXXJh;disIgV@-?ngWSGFPCv-) zXV9Do%$>;UL1SMqapdwA*4_tImy19IND%|#%zcm$Xq^UB7(N~d5?2NhPzhK+5hR4T z<$wWxQ!7XuwiXMd1y(PB#1Xe2fMg&TB)*st;SOYXE&)kGl)>-(0|_k!5m0d$1rh?q zG3b6YkQmIJATgMkAaPj#4kQk3>VbseHzk6^L1_*w$iTqR0A+y0p;L2U5!g*oAaQ6` z0gEHY7qn>(7JmRHA>)LwF<7t=$l_`Ou+#umotX0mJ~gksYcR#E11K zKAxIpi9(Ggk2B=*iwIB?;?+vz| z4W=GeFT&c(AhjS2yVvapnmMq0-C*r#kXjIi-P5KB;y~NmAopj29LK=G-~bf|Q6LPv z|I8D_K~fL9(Ix{b4x&I9cK=xihyx9O5EFL)*$NN`NgQ_n*$Fgp*nMU%(8OW)nSF$c z!@>uaJ_Mlk2}l}*VfT9(pozoo@d`i_huz~Rkk_Yy?1kNb zwg=4|*u7kLki>;S20-y2Bym_910*E_o#X(S4I7gLiQ6EFi-8277Rx)mfI3l)c{2aUOd#A~49AoZ}a3nV@VNgS3JLE?Lm z#9?=jfyD11iNpE`An~VAahScJwgpI>1!-Lqtd0hWBd_m*jeU69nn=6XQlDM;e5 zx)LPbf+P;>8-m1_Ac@1;7$ET@NaCplhHg6Rqaah|Dq}~Nd z9M<*#iG%J<1<|1JhmARa_$^54VRacu99ABH)Wg~UAn_we>S1kTkoZ}sI4t}@W2_+Y zH&AhqIk3J1NSp^+X@SIHZD5eN4w5*mjS3R?K@x|xkwD@(NaCfa!V!|sR$iSvLW3R(`p#y~*g21w$tzBx!d z07)Fy=LLxuAc@27qy&jiKoUp3ZF>WfIIPbOQhxzS9QpR_4@ly$v3iht0cc|d6#mG! zXB!}i!^R{*>I0C(VPj|@@d6}qsx`u{~(FO=0-u{GSJ2!$o;7x0VuXX5{J#Hfuv%P#M40nP+Wr~4jYpPNzFkL zhqZ}7;(L(95w~qKFx){BhmE0u)c-*ehmDbf#ATq3RFL}-w`wym*dU4LffPb9=ss!? z6QmwC#scEkAgPDl0SpqKgCq`{(*}v}K@x}TSOJMLFx){BN8EbN!0-o29AvjVbo~UZ zeFPE%VOYO_L9e(nw7(k!x8EAuLHZ=+GI(sLhCr8pwl|!=|x)B(W7Dx|VLg@{1AOWOEMJ+MuW;vD&HZW-#ODGJC zLk3NVpqz?p8jqH^VSz*Z-e5c-OuQk3CUn5Z>7ZrV!GB*PS|kooT?Rf?8{RaaL0OJ; zI5=t)!97fTii0>7wRoiZQ54Qb&~tH7olANqgC9FisX@>a$dO`+z+oTobI4I`CUklj z_@r@EEd-A!1D|4!rib*P!r!7IK7pW=lZNQ!Bs~ z*r;~GvLwDUKCo1y#Aw6P41gy(eAXc!f=#+(5ywrT>Lto**f~*XT8ZytAWqeWry$}r zV>z7<)giD@Cq1E1QeYsTt_1fLJUHp=mO&assOL(7&$~m7IYX?6V$wJ4(9ivW+;9Ln zC>YhXuyjU3{R*vVK&R|srV--JAv%6ZFcS6TX3(*GsJEP9Z)@ zuo*+B4GJ2)ft*u^W<4Q|7)Rfds2}C5U3l7twXhJaIO4qz&4}cr}N=+A2d0_5(?x9HzY?w#~Bgl=@DTVJZ*zbLrd8RNmwp|)*ksqp0JY| zU9tE4Ff~xW4uy=kq9hvBkp*agARJ9AHxO)Az~YSh4!{g(L=O__G)%OVhY>QU#TDrx zi%maTs9;v;@bpFBV8J-55jAiICawr}hv*wd*gIH;XeZy&*-h97L~_weEp$hsCQU5) z1%9Chw19;tOK4S$ZUHQT5N|N_-4o#=<1OPw97cGZU=|EqIsgT7#dZ4p>QIF_Fmqt7M z7rJT)q!I0GUx>!cyv&mL#G<0aN(Q~;{M_8syb=bzy!?_>J$JuQ-QtqO(6fdRCh9$h4>a0g?5C&L4p3gVDJ3 z!`A2_>j&-6hv|dSxb(v!7+F8)JOh|M7>!GR1(xsw?bCtjgVDJ3gW?)w1hW00{X8&z zFdCPB*m()a`kNRS;OT~t{s|z<85m&O^T6q^nFRf?^LUW$2kpCt*$bm_xgWN#2U$Pp z{5+UG7>!Fm?3`<4{hj#|$0MiGfap`}7#r>dj zD`EOzG%o!gu;}k1!T+GMxIjiAyC1Yi8fGty#$`Wj?=7-^&{;SzeJ~oAe$XClbo)W) z#KQE!Xk7Y1d$rN^gU*wM>4VX@^n=bAN7oP9YYWo{qjBkn?Yl$vKj>UIm_8VdOF!tW zXmtB~Nr*oK=>9ll`$6Z4!t907xa_yUq91hbC`=!W#-$&m7Tx`z^GRX)U^FiMptB#* z^@GkUh3SLQxbz2LaX;uBRG2;(jY~i1Od53iLFWv@^ucIc`eFMhk;5N!9wba3jK-xu z1B?4X``=;uU^FiMpgqUv?gyQV2h#_map?!0^@Oe;bbcO8AB@JOzX6N;L3@f}`d~CJ z{jhzd$l(V%uL`CQM&r^CI@<)@{h)IKVESM*F8!dhC(!kS&TN6{gVDJ3gU&WU*WXV< z{)L_8i0psR9zU49FdCQruzj}3`a$RK!SumsT>5uli9gW!dN6%38khb9SoDL=;e+Xe z(YW-Vz@i^?rU6VJjK-z^0v7$CJS!hX>OKqjBjMz@i^?ZXQe@jK-xOwvQay|Df~rVESM*F8vBv><9Hp zVESM*F8vx<^n=b#g6V_Nxbz!f(GS`y3eyLpap||fq91e)A50&N#-$&&uO2!4KxdD@ z^ucIc`aQ7N4?3q0rVmEr(jS0DKj>T&m_8VdOMe6w{h)I*VESM*F8#1`sgV5-I!6Ph z4@TqC4?AZ7SwHA}4wya|jZ1$47WaeBwS(z{(YW+iV9^gc{|=@PM&r`ofJHy(oIIF5 z7>!Fm>^ucz|AX2DFnur@m;MP@><68@2h#_map|9dML+2LJeWQhjY~i5+%RPKgU-)^ z>4VX@^ux}LK-LdBM-QeCM&r`I0gL-V=i$Nh!Dw9icVN*EI^PMV4@TqCe*lYq&^dH4 zeJ~oAe%SdK$o>bl>0tU`G%o!Yu-FeelLV#@M&r_d1B-spd3G>;FdCQs2Uzrj&SQh= zgVDJ3!_EOg_CM&{HkdvbjZ6OrEcS!WcZ2DJ(YW-(&ZR@PA9PL|OdpKKrJn(Mt_QMy zP@5X24@TqC&w)ih=zKSrJ{XNlKkQr-WcxwqvBC7gXk7Xwu-Fee4-KXdM&r`2fJHy( z+%%Xz7>!Fm>^?GN_k+$+gXx3Oxb(x$e?is{>XX3q!Dw9iEwH#BbPgI!AB@JOA9l_h zvi+bj6_`F4jZ41=7W+ZxO~LfRXk7YX=iDIM4>|`5rVmDg&PV|@wV}s?fVym8909ez z2)Yj(EC@Zv0mcT=ptE2=X2Iq=Kw=>LViSmDVAuhj90ARLfcEvn+ygs{26Xlb$bP7G z5KRmW45yF}y@87|z=qY}BA~NMKxU%rKLgbdl7lNo>VLw-KxdAC?1vT?FkyxVQ2hbW zef=;APc?YoYgvH-x21uNs`@aTiKk}J9AQREuzYd4}JFwUf zIzIv3e$e^5*!({SYCrPXBG~MIh{OI1SnLO#*^F*KC|t1F{|stB^4Txg><67Yi#7j1 z?T5_+g6sjE`+#mgXq*k3{Yub7h>*|D!Dc_`4g+lV8yp3xW?+Dw)dR90bml6${p%R9 z$A1XaenRONbYCYn_a_jk{}a@H^mLUC)ema(L3{!sL3Tk{5R!!nyZe7Y4{Jg`6AGjQ z-JVPw`lUbx8v_FasC)$JgJE?2DNK+#J@ovS01bawJ_Ch+CDM2TO#B=U`^}*CBcJUB zas#^kCvn(cfyI7MS%Dt^(ahMxF92#k@>xCD>{t!szyI!D0UisQs{c9FYB>`D1kZf8ek`1A0gq)ERIW zpxgf$hy5>(L$n~rKWP3G-G0!yaiBbnUjIyh+K+se7RW?&`wdvJhra}L0v49fK>i2K zpQ78pi4}YNpM%*Js0SKOgikxXB<-BVly=wb-!x-veqt za{2?!f1=yJ1Bd;Kp!S36EF|k;!=iAZ%{c5ofW>~${2#jgj_la|F9JRE4q6Pr?L+s! z4Lf%KTbzVwL5_dW`~|xGS8>>H1+^df3^0(1==NX0VSfPBe&qBIx+4SKekl&@{+|G~ zAJjet*$czy_KR|0_kRNx`$1_5-TrtS_Md{5?03`_rMDkt{v zkAT{boc?BFssH77hrKe=xl!U@Vkh^{$Ei0 z3AG>2;IO{~YCm%Oc^;PV1KnE+N)zbyha0G4$-uxsDF2vpWB30BsQt+C2U-(_?*C?P z?D5w?r2Ta`?0)%z~O#|(;(HT z{SVL`Ea>3}I>!)O{8>Q{D@8u@6J#Q~{n|X(E{O2{jha( zAoqjTB%-IE%{c7OfF7PpsQ)R!kKO%UQ2l7bcNp!j799HLK=p&x{2}`nJ^bqVvHO3+ z8Hg^}I!=)PL3aqC`~L?H`&FP7FY+0oAQRE;|BS=_h_fKosO85tEa^vI0DJhgLG4FA zqZec%y8T)L*!|yu#eUG5Qgr{P;jsS@)P6$cM6C9R8p+!RYZHg~NU;sQrY-&z9oQ?*`QmD?dSQ2VwN|yFd_o`jvpXAG!T~ z7)$sW2w@MuWl;MGx&H(X{hOfr35{PK7Q*iS2~hVVhd*dY13moXg|WN;3Do|#pg=>y z=;0S7jNSefQ2Sxw4=VpaU0QVec}1|>e+lYwn0}ZO(Cz0C!EQgtd58|=_yaWw(d`ex zVZRad;uu2lw*rTLJE(rBHz1C|(*IeE!~G3V_anz2C`+Te|2Gc%3!wH#f*OZ#+aY0% z#AWz~!~Pji`(f*7LGcF?LbrdtD8x+k{=+HgA@qd$Ppd?+$KMO+0)AxwgYM!*x8F(( zyZs-CwBJ+=yZsCx%NP*%S%dt48B6|e#9_Y}wBe0>_Btrs(bI1Y4*Mmr*nbs^{X22k zp9ZxbcAq22ZV*Pde+v%#4WRae%50E6kpHh^vHvFy`yWB=hxI=}W`Hod{aBbTCGDf3G<9^b>FitegSne~|k@ zW6|jD|Bl0c9_R&v&|(;37?$!wUjn=TZK3*M``BOxpcMxUS`ygZKLhH1rX7gRs;T@Ii)Ko9?8INa|5bw9Kj4BkKY9Ee(3!v^tPQS0PxPLhg`%gga2hHz;!VQMe!*3A| z`#YfaBj^7&SnSu9#vXn((1Eu)n8i>U-F`J`?Eb$1wI4bD-eIwS8xH$_LG6bQLqctb z+&c#6FfcG|#9==J^a5Js@CWTlL(jjiGT8mE1|7Httq(!A58eL`GT8ku0kt35|Dd~X z(d}==VSfYEenRtS4LI!gfZC7j|1Vg={|pZM_YrCTaUAw1K<$T>zo7c(8y5SMWU+_; zAE^C=`oFQV*u(z-)P7|DgZ31nhyMp0_A5abju6WKuW{Ia1B?B?u=u}L4!i$tp!O4L zzg5U#_x}eh_JhXK(EYC@kKO(rsQt)y5`ppodis}@$8J9dsIiDv|NO(^|7INaUx39*4!~Q=|`(f)3Kz;{dbpM~kVZQ~`e&q5OwErF5elrCe;SU}7 zLcT)^oBf6g*u%d8YCm%M1KK~2ZhsaI`_Dn`Csh8V;;?@M)PCgr2f8;C-TuWm?B{`6 zOep^6;jsS%7W+YadeQB_jl+HmsQrZ6Ke~$8v?m)q{)=$fzXEDMXwNF#axC`e z;;=sfYCm%SRR~M?-N0f0ALzmr(4Iwn_Fu+fzXCMjAlom3#eO{%Ncc0MCCmiqC3Vnd zDBKCK@Pi3xs$dWQ2T=QA2&>Alg4O(jjqCsn(Ks0FW5r_t@ z0RqvWwKyPpHq?D{q4azxy%0(-hSH$53n2BNH3T3UG?x#eL38RL8Z@^JqCxB7K{RNt z7(|1%QGjSrKO97Fg_;MN%LMU3bBZ8(CsZ6X#|Pqr=Gs6sXwC~ngUVqLeGsY+G?xS7 zgO<61XwY&?5Dl860MVei0uT+F#s$%!=?oAJ8V>}~py4SH4Ql3tXi#+xqCv$jh`t52 z=QfnS3#CD0Xdrpe`7j{*5mX#BHU#3s*7JkTe*y79V-_G9G02c3Nd;)9YRhz6ZS1)@P`N`YulVg%8kHZq82hOR3Io!JE9 zgW8TD8q|gZ(VS3uP@4$E2c3-sqCsaIfoM=&528V54uNQ4sCrQ-Ee@q6p){y$1*rq= z2LRD>P;pS11LA|$;eu#Is5q!R0P#U*;(%y%Mh1pZkItvT9?fqgJUVM%cyyLN03`+n zk8al&9-RVUsyBecqucd?N9Qq*&g-Bc2Fo660If`dGC>I!%=BOd&E0!+9*3**ULM07^oj+zz(!cmpWKz_`a6K!17bJCo^uFNV22Rs02l!h-v%a9Pj{re*B1~8*9Q%?M;J=j!KvppD>QChKY)!x z_t6cH-U$MX3=AH<=*8s?R3Gtgb3M}hfwAR4i7d!l`~HI>3hF1203tkHf24RAL;O(! zu^sB?V2{Q(pw#Bkx!2?Hmc(2*Tj z%MWaBf-CGsB&}Ysf1s%guOo;yo`0Kz zK+Ay=FPLf2q}kgV0FIh#aA)*R1&e^g7fBSV4pQ&Eoc9lu@gUxYn^b^qQY%CRswWFc z4@yl2jTKO16y`bR8$dn!c0i^HRPDm<*fIUTCTLBON+K#8yiOpk*A z+=I|afT!dM9-VN1zKn)g1U3`qF;GfF%DoU@qh<|oXhHlr0aPF%(zNMoJy0zL3ulNL zNbQ28$pca4LULf^5m4HXj)mlZMEj-N^#!(uNh~Ngzwqchwjb1}fEdx)3~8!NhE^^w zP}?rxP>1Jx@X1adh}s^xPJ>toszH9B8qso~#0*mML2QC}ju;VG*$b^Tp@sbfNJ|4& zmqJ7t&_wySftyRvkb$Y?-v(|up^0`kfcy?I6%>XVutF5QG(jpm!NnqK?1D;ANF(tE zQd+@O_*x1S)yQTcq7_`8cKg0a@i68Am)g+M&ZGH=2DF8R9OkIi`~+y3h^hiP&|40a z2w?_1l0IFQyRK2nG$N&Ef45f02 zWCd>hf%;Dj2r+1E?gOda4{CS6SpWb3|5#9O3X~kNWBrW$+*JLn#N5x?BasN zb=9LD5zrK0dEB2YL}bUi*DAlMrqQ4)M{C^2sbN z0b8vYU!0ngrstYlP*SO(si3B&pahn*Qt-=HNGrP5E7Bj>rCl(|oXO>hd*x4#T;t=fHU{DBvV-d`?Qh-KBQEG8& zQCX@2Tw6|Raj`;4Mq(bs>tJ6(oCpnJ2vwG!nW7K{Hp?bNN5Rp~$_g5wsT!bwi7(Mq zhz18!h=Q#`azP;Yg&;dCD|qm^CuZiQrf49$1v=^#lv-GtT3lkS;Nk{y z7P3h$sn7_@FS0>ZZD*|z1X2w*A9^bz+&^$eoCrMh@F-Km=%f*8cIr}VSGc~ha--mjt%)h=LS$sK&?9BfitcVs|hC$gU3o?Eo#sJ zO6vjssRv@w#6g4N44{FOAIBZQ6GxzS=Wz${ln`259a$-8KL~PLege!~q|vi|pvEJt zVG3;sS1+a&@B9T1%paP+W{d-2He01uvv0pNXNGwS$S_AS3HX zMuy9bthX2$b}+FrF#P||sHDI;gOS0Abv+}43+pjPhA`Hgn zAo^}F=YibP&48Yhz_AqyiZSFUB2N{_2B>X_J|?`3L6-sdQbAb=xr6=#Jh=J7qdW8g zYKnOQ8iYmfP~)}*Yj~l%0AnN{ZXWgBhBur+=?*+zfgBW|kLy0G+j%=I~_ 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 literal 0 HcmV?d00001 diff --git a/Bin/x86-64/libsst-net.a b/Bin/x86-64/libsst-net.a new file mode 100644 index 0000000000000000000000000000000000000000..40feb71d9ad0c5975005da7f5254bf87af4c2bdf GIT binary patch literal 18912 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 VkQg@m3!w1_+6xYL5R^a +# Created: 3/19/2012 +# +# Purpose: +# +# Defines common libraries required for linking on POSIX platforms +# +# License: +# +# This program is free software. It comes without any warranty, to +# the extent permitted by applicable law. You can redistribute it +# and/or modify it under the terms of the Do What The Fuck You Want +# To Public License, Version 2, as published by Sam Hocevar. See +# http://sam.zoy.org/wtfpl/COPYING for more details. + +# Base libraries (console) +export ZENGINE_BASE_LIBS = -lpthread -lm + +# GUI libraries (X Windows) +export ZENGINE_GUI_LIBS = -lGL -lX11 + diff --git a/BuildConfig/DetectCompiler.rules b/BuildConfig/DetectCompiler.rules new file mode 100644 index 0000000..832b7e1 --- /dev/null +++ b/BuildConfig/DetectCompiler.rules @@ -0,0 +1,48 @@ +# BuildConfig/DetectCompiler.rules +# Author: Patrick Baggett +# Created: 4/3/2012 +# +# Purpose: +# +# Check for common compilers and sets flags for them +# +# License: +# +# This program is free software. It comes without any warranty, to +# the extent permitted by applicable law. You can redistribute it +# and/or modify it under the terms of the Do What The Fuck You Want +# To Public License, Version 2, as published by Sam Hocevar. See +# http://sam.zoy.org/wtfpl/COPYING for more details. + +# ================= +# Detect "gcc" +# ================= +CC := $(shell which $(CC)) + +#Check if $CC filename has "gcc" in it, but don't be fooled if path has "gcc" +ifeq ($(findstring gcc,$(notdir $(realpath $(CC)))),gcc) + IS_GCC := 1 +else + IS_GCC := 0 +endif + +# ================= +# Detect "icc" +# ================= +#Check if $CC filename has "icc" in it, but don't be fooled if path has "icc" +ifeq ($(findstring icc,$(notdir $(realpath $(CC)))),icc) + IS_ICC := 1 +else + IS_ICC := 0 +endif + +# ================= +# Detect plain "cc" +# ================= +#Check if $CC filename /is/ "cc", but don't be fooled if path has "cc" +ifeq ($(notdir $(realpath $(CC))),cc) + IS_CC := 1 +else + IS_CC := 0 +endif + diff --git a/BuildConfig/DetectLibs.rules b/BuildConfig/DetectLibs.rules new file mode 100644 index 0000000..610aec6 --- /dev/null +++ b/BuildConfig/DetectLibs.rules @@ -0,0 +1,36 @@ +# BuildConfig/DetectLibs.rules +# Author: Patrick Baggett +# Created: 4/24/2014 +# +# Purpose: +# +# Detects presence of libraries +# +# License: +# +# This program is free software. It comes without any warranty, to +# the extent permitted by applicable law. You can redistribute it +# and/or modify it under the terms of the Do What The Fuck You Want +# To Public License, Version 2, as published by Sam Hocevar. See +# http://sam.zoy.org/wtfpl/COPYING for more details. + +# There is no reason for us to do this here - the reason being is that automatic detection with no alternative is simply a waste of time. +# It's better to have individual makefiles that you include for system stacks. Compiler detection and bifurcation is really solid - the auto +# detection is best left to full fledged build tools - since that's literally what auto-tools does. +# +# Use this file as as temp file +TEMPFILE := $(shell mktemp 2>/dev/null || mktemp -t 'mytmpdir') + +#Detect a library, called as: $(call detectLib,file.h,HAVE_FILE_H) +detectLib = $(shell echo "\#include $(1)" > $(TEMPFILE); $(CC) -E $(TEMPFILE) >/dev/null 2>&1; if [ $$? -eq 0 ]; then echo "-D$(2)"; else echo ""; fi) + +DETECTED_LIBS := +DETECTED_LIBS += $(call detectLib,,HAVE_XLIB) +DETECTED_LIBS += $(call detectLib,,HAVE_XINPUT2) +DETECTED_LIBS += $(call detectLib,,HAVE_WAYLAND) +DETECTED_LIBS += $(call detectLib,,HAVE_EGL) + +FORCE_REMOVE := $(shell rm $(TEMPFILE)) + +OS_CXXFLAGS += $(DETECTED_LIBS) +OS_CFLAGS += $(DETECTED_LIBS) diff --git a/BuildConfig/DetectPlatform.rules b/BuildConfig/DetectPlatform.rules new file mode 100644 index 0000000..8db6204 --- /dev/null +++ b/BuildConfig/DetectPlatform.rules @@ -0,0 +1,84 @@ +# BuildConfig/DetectPlatform.rules +# Author: Patrick Baggett +# Created: 11/15/2011 +# +# Purpose: +# +# OS/architecture detection rules. Requires GNU Make +# +# License: +# +# This program is free software. It comes without any warranty, to +# the extent permitted by applicable law. You can redistribute it +# and/or modify it under the terms of the Do What The Fuck You Want +# To Public License, Version 2, as published by Sam Hocevar. See +# http://sam.zoy.org/wtfpl/COPYING for more details. + +# Allow user overrides of $OS and $ARCH + +#============================== +# Detect operating system +#============================== +ifeq ($(OS),) + OS := $(shell uname) + ifeq ($(OS),SunOS) + OS := Solaris + endif + ifeq ($(findstring Windows,$(OS)),Windows) # *Windows* -> Windows + OS := Windows + endif + + ifeq ($(findstring MINGW,$(OS)),MINGW) # *MINGW* -> Windows + OS := Windows + endif +endif + +# Detect when the Win32 environment variable "Windows_NT" is set and normalize it +ifeq ($(OS),Windows_NT) + OS := Windows +endif + +#============================== +# Detect processor arch +# ============================= +ifeq ($(ARCH),) + ifeq ($(OS),Solaris) #Solaris likes "-p" instead of "-m" + ARCH := $(shell uname -p) + else + ARCH := $(shell uname -m) + endif + + #Replace "i86" with "x86", where can be [x, digit] + ARCH := $(shell echo $(ARCH) | sed s/i[x0-9]86/x86/) + + #Replace "powerpc" with "ppc" + ARCH := $(shell echo $(ARCH) | sed s/powerpc/ppc/) + + ifeq ($(ARCH),sparc64) #Linux on UltraSPARC gives sparc64 when running 64-bit kernel + ARCH := sparc + endif + + ifeq ($(ARCH),mips64) #Linux/mips64 kernel, but probably don't want 64-bit app + ARCH := mips + endif + + ifeq ($(ARCH),amd64) # "amd64" -> "x86-64" + ARCH := x86-64 + endif + + ifeq ($(ARCH),x86_64) # "x86_64" -> "x86-64" + ARCH := x86-64 + endif + + ifeq ($(ARCH),armv6l) # "armv6l" -> "arm" + ARCH := arm + SUBARCH := armv6 + endif + + ifeq ($(ARCH),armv7l) # "armv7l" -> "arm + ARCH := arm + SUBARCH := armv7 + endif + +endif + diff --git a/BuildConfig/DetectWinSys.rules b/BuildConfig/DetectWinSys.rules new file mode 100644 index 0000000..c2286a8 --- /dev/null +++ b/BuildConfig/DetectWinSys.rules @@ -0,0 +1,44 @@ +# BuildConfig/DetectWinSys.rules +# Author: Patrick Baggett +# Created: 1/18/2013 +# +# Purpose: +# +# Windowing system detection +# +# License: +# +# This program is free software. It comes without any warranty, to +# the extent permitted by applicable law. You can redistribute it +# and/or modify it under the terms of the Do What The Fuck You Want +# To Public License, Version 2, as published by Sam Hocevar. See +# http://sam.zoy.org/wtfpl/COPYING for more details. + +# This detects a default windowing system (WINSYS) based upon OS. The +# user may override it by setting $WINSYS ahead of time, in which case +# these rules act as a no-op + +ifeq ($(WINSYS),) + + #Windows uses...Win32 APIs + ifeq ($(OS),Windows) + WINSYS := Win32 + endif + + #MacOS X uses...MacOS X APIs + ifeq ($(OS),Darwin) + WINSYS := MacOSX + endif + + #Android uses...Android APIs + ifeq ($(OS),Android) + WINSYS := Android + endif + + #No specific rules, so default to Xlib + ifeq ($(WINSYS),) + WINSYS := Xlib + endif + +endif + diff --git a/BuildConfig/GCC-Flags.rules b/BuildConfig/GCC-Flags.rules new file mode 100644 index 0000000..39ca651 --- /dev/null +++ b/BuildConfig/GCC-Flags.rules @@ -0,0 +1,20 @@ +# BuildConfig/GCC-Flags.rules +# Author: Patrick Baggett +# Created: 1/11/2012 +# +# Purpose: +# +# Common flags for GNU "gcc" to reduce redundancy +# +# License: +# +# This program is free software. It comes without any warranty, to +# the extent permitted by applicable law. You can redistribute it +# and/or modify it under the terms of the Do What The Fuck You Want +# To Public License, Version 2, as published by Sam Hocevar. See +# http://sam.zoy.org/wtfpl/COPYING for more details. + +GCC_COMMON := -fstrict-aliasing -Wall -Wextra + +OS_CFLAGS += $(GCC_COMMON) +OS_CXXFLAGS += $(GCC_COMMON) diff --git a/BuildConfig/Makefile.Android.arm b/BuildConfig/Makefile.Android.arm new file mode 100644 index 0000000..4f214f1 --- /dev/null +++ b/BuildConfig/Makefile.Android.arm @@ -0,0 +1,30 @@ +# BuildConfig/Makefile.Android.arm +# Author: Patrick Baggett +# Created: 1/16/2013 +# +# Purpose: +# +# Makefile for Android running on 32-bit ARMv6+ architecture processors +# +# License: +# +# This program is free software. It comes without any warranty, to +# the extent permitted by applicable law. You can redistribute it +# and/or modify it under the terms of the Do What The Fuck You Want +# To Public License, Version 2, as published by Sam Hocevar. See +# http://sam.zoy.org/wtfpl/COPYING for more details. + +# All C/C++ compiler flags required by this OS platform +# TODO: anything required here? +OS_CXXFLAGS := -D_UNIX=1 +OS_CFLAGS := -D_UNIX=1 + +include BuildConfig/GCC-Flags.rules +include BuildConfig/POSIX-Libs.rules + +ASM ?= as +RANLIB ?= ranlib +SUBSYSTEM := POSIX + +# All flags/libraries the linker will need +OS_LDFLAGS := diff --git a/BuildConfig/Makefile.Darwin.x86 b/BuildConfig/Makefile.Darwin.x86 new file mode 100644 index 0000000..be72acf --- /dev/null +++ b/BuildConfig/Makefile.Darwin.x86 @@ -0,0 +1,30 @@ +# BuildConfig/Makefile.Darwin.x86 +# Author: Patrick Baggett +# Created: 12/28/2011 +# +# Purpose: +# +# Makefile for Mac OS running on 32-bit x86 architecture processors +# +# License: +# +# This program is free software. It comes without any warranty, to +# the extent permitted by applicable law. You can redistribute it +# and/or modify it under the terms of the Do What The Fuck You Want +# To Public License, Version 2, as published by Sam Hocevar. See +# http://sam.zoy.org/wtfpl/COPYING for more details. + +# All C/C++ compiler flags required by this OS platform +# NOTE: This pretty much assumes GCC +OS_CXXFLAGS := -m32 -D_UNIX=1 -I/usr/local/include +OS_CFLAGS := -m32 -D_UNIX=1 -I/usr/local/include + +include BuildConfig/GCC-Flags.rules +include BuildConfig/Darwin-Libs.rules + +ASM := yasm -f macho32 -m x86 +RANLIB := ranlib +SUBSYSTEM := POSIX + +# All flags/libraries the linker will need +OS_LDFLAGS := -m32 -L/usr/local/lib -Wl,-rpath,/usr/local/lib diff --git a/BuildConfig/Makefile.Darwin.x86-64 b/BuildConfig/Makefile.Darwin.x86-64 new file mode 100644 index 0000000..2b8ff0c --- /dev/null +++ b/BuildConfig/Makefile.Darwin.x86-64 @@ -0,0 +1,30 @@ +# BuildConfig/Makefile.Darwin.x86-64 +# Author: Patrick Baggett +# Created: 11/15/2012 +# +# Purpose: +# +# Makefile for Mac OS running on 64-bit x86 architecture processors +# +# License: +# +# This program is free software. It comes without any warranty, to +# the extent permitted by applicable law. You can redistribute it +# and/or modify it under the terms of the Do What The Fuck You Want +# To Public License, Version 2, as published by Sam Hocevar. See +# http://sam.zoy.org/wtfpl/COPYING for more details. + +# All C/C++ compiler flags required by this OS platform +# NOTE: This pretty much assumes GCC +OS_CXXFLAGS := -m64 -D_UNIX=1 -I/usr/local/include +OS_CFLAGS := -m64 -D_UNIX=1 -I/usr/local/include + +include BuildConfig/GCC-Flags.rules +include BuildConfig/Darwin-Libs.rules + +ASM := yasm -f macho64 -m amd64 +RANLIB := ranlib +SUBSYSTEM := POSIX + +# All flags/libraries the linker will need +OS_LDFLAGS := -m64 -L/usr/local/lib -Wl,-rpath,/usr/local/lib diff --git a/BuildConfig/Makefile.Linux.arm b/BuildConfig/Makefile.Linux.arm new file mode 100644 index 0000000..8970aeb --- /dev/null +++ b/BuildConfig/Makefile.Linux.arm @@ -0,0 +1,30 @@ +# BuildConfig/Makefile.Linux.arm +# Author: Patrick Baggett +# Created: 6/21/2012 +# +# Purpose: +# +# Makefile for Linux running on 32-bit ARMv6+ architecture processors +# +# License: +# +# This program is free software. It comes without any warranty, to +# the extent permitted by applicable law. You can redistribute it +# and/or modify it under the terms of the Do What The Fuck You Want +# To Public License, Version 2, as published by Sam Hocevar. See +# http://sam.zoy.org/wtfpl/COPYING for more details. + +# All C/C++ compiler flags required by this OS platform +# NOTE: This pretty much assumes GCC on Linux +OS_CXXFLAGS := -D_UNIX=1 -I/usr/local/include +OS_CFLAGS := -D_UNIX=1 -I/usr/local/include + +include BuildConfig/GCC-Flags.rules +include BuildConfig/POSIX-Libs.rules + +ASM ?= as +RANLIB ?= ranlib +SUBSYSTEM := POSIX + +# All flags/libraries the linker will need +OS_LDFLAGS := -L/usr/local/lib -Wl,-rpath,/usr/local/lib diff --git a/BuildConfig/Makefile.Linux.ia64 b/BuildConfig/Makefile.Linux.ia64 new file mode 100644 index 0000000..5a0daa7 --- /dev/null +++ b/BuildConfig/Makefile.Linux.ia64 @@ -0,0 +1,32 @@ +# BuildConfig/Makefile.Linux.ia64 +# Author: Patrick Baggett +# Created: 4/16/20112 +# +# Purpose: +# +# Makefile for Linux running on Itanium architecture processors +# +# License: +# +# This program is free software. It comes without any warranty, to +# the extent permitted by applicable law. You can redistribute it +# and/or modify it under the terms of the Do What The Fuck You Want +# To Public License, Version 2, as published by Sam Hocevar. See +# http://sam.zoy.org/wtfpl/COPYING for more details. + +# All C/C++ compiler flags required by this OS platform +# NOTE: This pretty much assumes GCC on Linux +OS_CXXFLAGS := -D_UNIX=1 -I/usr/local/include +OS_CFLAGS := -D_UNIX=1 -I/usr/local/include + +include BuildConfig/GCC-Flags.rules +include BuildConfig/POSIX-Libs.rules + +ASM := as -mtune=itanium2 +RANLIB := ranlib +SUBSYSTEM := POSIX + +# All flags/libraries the linker will need +OS_LDFLAGS := -L/usr/local/lib -Wl,-rpath,/usr/local/lib + + diff --git a/BuildConfig/Makefile.Linux.mips b/BuildConfig/Makefile.Linux.mips new file mode 100644 index 0000000..0e30186 --- /dev/null +++ b/BuildConfig/Makefile.Linux.mips @@ -0,0 +1,30 @@ +# BuildConfig/Makefile.Linux.mips +# Author: Patrick Baggett +# Created: 6/28/2013 +# +# Purpose: +# +# Makefile for Linux running on 32-bit MIPS architecture processors +# +# License: +# +# This program is free software. It comes without any warranty, to +# the extent permitted by applicable law. You can redistribute it +# and/or modify it under the terms of the Do What The Fuck You Want +# To Public License, Version 2, as published by Sam Hocevar. See +# http://sam.zoy.org/wtfpl/COPYING for more details. + +# All C/C++ compiler flags required by this OS platform +# NOTE: This pretty much assumes GCC on Linux +OS_CXXFLAGS := -D_UNIX=1 -I/usr/local/include +OS_CFLAGS := -D_UNIX=1 -I/usr/local/include + +include BuildConfig/GCC-Flags.rules +include BuildConfig/POSIX-Libs.rules + +ASM ?= as -mips32 +RANLIB ?= ranlib +SUBSYSTEM := POSIX + +# All flags/libraries the linker will need +OS_LDFLAGS := -L/usr/local/lib -Wl,-rpath,/usr/local/lib diff --git a/BuildConfig/Makefile.Linux.mips64 b/BuildConfig/Makefile.Linux.mips64 new file mode 100644 index 0000000..7d2fa3a --- /dev/null +++ b/BuildConfig/Makefile.Linux.mips64 @@ -0,0 +1,30 @@ +# BuildConfig/Makefile.Linux.mips +# Author: Patrick Baggett +# Created: 6/28/2013 +# +# Purpose: +# +# Makefile for Linux running on 64-bit MIPS architecture processors +# +# License: +# +# This program is free software. It comes without any warranty, to +# the extent permitted by applicable law. You can redistribute it +# and/or modify it under the terms of the Do What The Fuck You Want +# To Public License, Version 2, as published by Sam Hocevar. See +# http://sam.zoy.org/wtfpl/COPYING for more details. + +# All C/C++ compiler flags required by this OS platform +# NOTE: This pretty much assumes GCC on Linux +OS_CXXFLAGS := -mabi=64 -D_UNIX=1 -I/usr/local/include +OS_CFLAGS := -mabi=64 -D_UNIX=1 -I/usr/local/include + +include BuildConfig/GCC-Flags.rules +include BuildConfig/POSIX-Libs.rules + +ASM ?= as -mips64 -mabi=64 +RANLIB ?= ranlib +SUBSYSTEM := POSIX + +# All flags/libraries the linker will need +OS_LDFLAGS := -mabi=64 -L/usr/local/lib -Wl,-rpath,/usr/local/lib diff --git a/BuildConfig/Makefile.Linux.ppc b/BuildConfig/Makefile.Linux.ppc new file mode 100644 index 0000000..f755ffe --- /dev/null +++ b/BuildConfig/Makefile.Linux.ppc @@ -0,0 +1,33 @@ +# BuildConfig/Makefile.Linux.ppc +# Author: Patrick Baggett +# Created: 7/20/2012 +# +# Purpose: +# +# Makefile for Linux running on Power Arch. processors, 32-bit binary +# +# License: +# +# This program is free software. It comes without any warranty, to +# the extent permitted by applicable law. You can redistribute it +# and/or modify it under the terms of the Do What The Fuck You Want +# To Public License, Version 2, as published by Sam Hocevar. See +# http://sam.zoy.org/wtfpl/COPYING for more details. + +# All C++ compiler flags required by this OS platform +OS_CXXFLAGS := -m32 -D_UNIX=1 -I/usr/local/include +OS_CFLAGS := -m32 -D_UNIX=1 -I/usr/local/include + +# Assume GCC here +include BuildConfig/GCC-Flags.rules + +# Linux uses POSIX-like libraries +include BuildConfig/POSIX-Libs.rules + +ASM := as -mregnames +RANLIB := ranlib +SUBSYSTEM := POSIX + +# Flags for linker: 32-bit binary, and use "/usr/local/lib" in the path +OS_LDFLAGS := -m32 -L/usr/local/lib -Wl,-rpath,/usr/local/lib + diff --git a/BuildConfig/Makefile.Linux.sparc b/BuildConfig/Makefile.Linux.sparc new file mode 100644 index 0000000..ebde65e --- /dev/null +++ b/BuildConfig/Makefile.Linux.sparc @@ -0,0 +1,33 @@ +# BuildConfig/Makefile.Linux.sparc +# Author: Patrick Baggett +# Created: 11/15/2011 +# +# Purpose: +# +# Makefile for Linux running on SPARCv9 processors, 32-bit binary +# +# License: +# +# This program is free software. It comes without any warranty, to +# the extent permitted by applicable law. You can redistribute it +# and/or modify it under the terms of the Do What The Fuck You Want +# To Public License, Version 2, as published by Sam Hocevar. See +# http://sam.zoy.org/wtfpl/COPYING for more details. + +# All C++ compiler flags required by this OS platform +OS_CXXFLAGS := -m32 -D_UNIX=1 -I/usr/local/include +OS_CFLAGS := -m32 -D_UNIX=1 -I/usr/local/include + +# Assume GCC here +include BuildConfig/GCC-Flags.rules + +# Linux uses POSIX-like libraries +include BuildConfig/POSIX-Libs.rules + +ASM := as -xarch=v8plusa +RANLIB := ranlib +SUBSYSTEM := POSIX + +# Flags for linker: 32-bit binary, and use "/usr/local/lib" in the path +OS_LDFLAGS := -m32 -L/usr/local/lib -Wl,-rpath,/usr/local/lib + diff --git a/BuildConfig/Makefile.Linux.sparc64 b/BuildConfig/Makefile.Linux.sparc64 new file mode 100644 index 0000000..c49c33d --- /dev/null +++ b/BuildConfig/Makefile.Linux.sparc64 @@ -0,0 +1,33 @@ +# BuildConfig/Makefile.Linux.sparc64 +# Author: Patrick Baggett +# Created: 7/9/2012 +# +# Purpose: +# +# Makefile for Linux running on SPARCv9 processors, 64-bit binary +# +# License: +# +# This program is free software. It comes without any warranty, to +# the extent permitted by applicable law. You can redistribute it +# and/or modify it under the terms of the Do What The Fuck You Want +# To Public License, Version 2, as published by Sam Hocevar. See +# http://sam.zoy.org/wtfpl/COPYING for more details. + +# All C++ compiler flags required by this OS platform +OS_CXXFLAGS := -m64 -D_UNIX=1 -I/usr/local/include +OS_CFLAGS := -m64 -D_UNIX=1 -I/usr/local/include + +# Assume GCC here +include BuildConfig/GCC-Flags.rules + +# Linux uses POSIX-like libraries +include BuildConfig/POSIX-Libs.rules + +ASM := as -xarch=v9a +RANLIB := ranlib +SUBSYSTEM := POSIX + +# Flags for linker: 64-bit binary, and use "/usr/local/lib64" in the path +OS_LDFLAGS := -m64 -L/usr/local/lib64 -Wl,-rpath,/usr/local/lib64 + diff --git a/BuildConfig/Makefile.Linux.x86 b/BuildConfig/Makefile.Linux.x86 new file mode 100644 index 0000000..a17940e --- /dev/null +++ b/BuildConfig/Makefile.Linux.x86 @@ -0,0 +1,30 @@ +# BuildConfig/Makefile.Linux.x86 +# Author: Patrick Baggett +# Created: 12/28/2011 +# +# Purpose: +# +# Makefile for Linux running on 32-bit x86 architecture processors +# +# License: +# +# This program is free software. It comes without any warranty, to +# the extent permitted by applicable law. You can redistribute it +# and/or modify it under the terms of the Do What The Fuck You Want +# To Public License, Version 2, as published by Sam Hocevar. See +# http://sam.zoy.org/wtfpl/COPYING for more details. + +# All C/C++ compiler flags required by this OS platform +# NOTE: This pretty much assumes GCC on Linux +OS_CXXFLAGS := -m32 -D_UNIX=1 -I/usr/local/include +OS_CFLAGS := -m32 -D_UNIX=1 -I/usr/local/include + +include BuildConfig/GCC-Flags.rules +include BuildConfig/POSIX-Libs.rules + +ASM := yasm -f elf32 -m x86 +RANLIB := ranlib +SUBSYSTEM := POSIX + +# All flags/libraries the linker will need +OS_LDFLAGS := -m32 -L/usr/local/lib -Wl,-rpath,/usr/local/lib diff --git a/BuildConfig/Makefile.Linux.x86-64 b/BuildConfig/Makefile.Linux.x86-64 new file mode 100644 index 0000000..a925637 --- /dev/null +++ b/BuildConfig/Makefile.Linux.x86-64 @@ -0,0 +1,30 @@ +# BuildConfig/Makefile.Linux.x86-64 +# Author: Patrick Baggett +# Created: 7/25/2011 +# +# Purpose: +# +# Makefile for Linux running on 64-bit x86 architecture processors +# +# License: +# +# This program is free software. It comes without any warranty, to +# the extent permitted by applicable law. You can redistribute it +# and/or modify it under the terms of the Do What The Fuck You Want +# To Public License, Version 2, as published by Sam Hocevar. See +# http://sam.zoy.org/wtfpl/COPYING for more details. + +# All C/C++ compiler flags required by this OS platform +OS_CXXFLAGS := -m64 -D_UNIX=1 -I/usr/local/include +OS_CFLAGS := -m64 -D_UNIX=1 -I/usr/local/include + +include BuildConfig/GCC-Flags.rules +include BuildConfig/POSIX-Libs.rules + +ASM := yasm -f elf64 -m amd64 +RANLIB := ranlib +SUBSYSTEM := POSIX + +CWD = $(shell pwd) +# All flags/libraries the linker will need +OS_LDFLAGS := -m64 -L/usr/local/lib64 -Wl,-rpath,/usr/local/lib64 diff --git a/BuildConfig/Makefile.Solaris.sparc b/BuildConfig/Makefile.Solaris.sparc new file mode 100644 index 0000000..a75bb01 --- /dev/null +++ b/BuildConfig/Makefile.Solaris.sparc @@ -0,0 +1,56 @@ +# BuildConfig/Makefile.Solaris.sparc +# Author: Patrick Baggett +# Created: 12/15/2011 +# +# Purpose: +# +# Makefile for Solaris 10 running on SPARCv9 processors, 32-bit binary +# +# License: +# +# This program is free software. It comes without any warranty, to +# the extent permitted by applicable law. You can redistribute it +# and/or modify it under the terms of the Do What The Fuck You Want +# To Public License, Version 2, as published by Sam Hocevar. See +# http://sam.zoy.org/wtfpl/COPYING for more details. + +# All C++ compiler flags required by this OS platform +OS_CXXFLAGS := -D_POSIX_PTHREAD_SEMANTICS -m32 -D_UNIX=1 -I/usr/local/include +OS_CFLAGS := -D_POSIX_PTHREAD_SEMANTICS -m32 -D_UNIX=1 -I/usr/local/include + +# All flags/libraries the linker will need +OS_LDFLAGS := -m32 -L/usr/local/lib -Wl,-R,/usr/local/lib + +ASM := /usr/ccs/bin/as -xarch=v8plusa +RANLIB := /usr/ccs/bin/ranlib +AR := /usr/ccs/bin/ar +SUBSYSTEM := Solaris + +#Default $CC to Sun "cc" +ifeq ($(origin CC),default) + CC := cc +endif + +#Default $CXX to Sun "CC" +ifeq ($(origin CXX),default) + CXX := CC +endif + +include BuildConfig/DetectCompiler.rules +include BuildConfig/Solaris-Libs.rules + +ifeq ($(IS_GCC),1) + CXX := g++ #Use matching GNU g++ + include BuildConfig/GCC-Flags.rules + + #These are gcc + sparc specific + OS_CFLAGS += -mcpu=ultrasparc -mvis -threads + OS_CXXFLAGS += -mcpu=ultrasparc -mvis -threads +else ifeq ($(IS_CC),1) + CXX := CC #Use matching Sun C++ + include BuildConfig/SunPro-Flags.rules + + #These are SunPro + sparc specific + OS_CFLAGS += -xvis=yes -xarch=sparcvis + OS_CXXFLAGS += -xvis=yes -xarch=sparcvis +endif diff --git a/BuildConfig/Makefile.Solaris.sparc64 b/BuildConfig/Makefile.Solaris.sparc64 new file mode 100644 index 0000000..309fd42 --- /dev/null +++ b/BuildConfig/Makefile.Solaris.sparc64 @@ -0,0 +1,56 @@ +# BuildConfig/Makefile.Solaris.sparc64 +# Author: Patrick Baggett +# Created: 4/3/2012 +# +# Purpose: +# +# Makefile for Solaris 10 running on SPARCv9 processors, 64-bit binary +# +# License: +# +# This program is free software. It comes without any warranty, to +# the extent permitted by applicable law. You can redistribute it +# and/or modify it under the terms of the Do What The Fuck You Want +# To Public License, Version 2, as published by Sam Hocevar. See +# http://sam.zoy.org/wtfpl/COPYING for more details. + +# All C++ compiler flags required by this OS platform +OS_CXXFLAGS := -D_POSIX_PTHREAD_SEMANTICS -m64 -D_UNIX=1 -I/usr/local/include +OS_CFLAGS := -D_POSIX_PTHREAD_SEMANTICS -m64 -D_UNIX=1 -I/usr/local/include + +# All flags/libraries the linker will need +OS_LDFLAGS := -m64 -L/usr/local/lib/sparcv9 -Wl,-R,/usr/local/lib/sparcv9 + +ASM := /usr/ccs/bin/as -xarch=v9a +RANLIB := /usr/ccs/bin/ranlib +AR := /usr/ccs/bin/ar +SUBSYSTEM := Solaris + +#Default $CC to Sun "cc" +ifeq ($(origin CC),default) + CC := cc +endif + +#Default $CXX to Sun "CC" +ifeq ($(origin CXX),default) + CXX := CC +endif + +include BuildConfig/DetectCompiler.rules +include BuildConfig/Solaris-Libs.rules + +ifeq ($(IS_GCC),1) + CXX := g++ #Use matching GNU g++ + include BuildConfig/GCC-Flags.rules + + #These are gcc + sparc specific + OS_CFLAGS += -mcpu=ultrasparc -mvis -threads + OS_CXXFLAGS += -mcpu=ultrasparc -mvis -threads +else ifeq ($(IS_CC),1) + CXX := CC #Use matching Sun C++ + include BuildConfig/SunPro-Flags.rules + + #These are SunPro + sparc64 specific + OS_CFLAGS += -xvis=yes -xarch=sparcvis + OS_CXXFLAGS += -xvis=yes -xarch=sparcvis +endif diff --git a/BuildConfig/Makefile.Solaris.x86 b/BuildConfig/Makefile.Solaris.x86 new file mode 100644 index 0000000..add8e69 --- /dev/null +++ b/BuildConfig/Makefile.Solaris.x86 @@ -0,0 +1,52 @@ +# BuildConfig/Makefile.Solaris.x86 +# Author: Patrick Baggett +# Created: 12/15/2011 +# +# Purpose: +# +# Makefile for Solaris 10 running on x86 processors, 32-bit binary +# +# License: +# +# This program is free software. It comes without any warranty, to +# the extent permitted by applicable law. You can redistribute it +# and/or modify it under the terms of the Do What The Fuck You Want +# To Public License, Version 2, as published by Sam Hocevar. See +# http://sam.zoy.org/wtfpl/COPYING for more details. + +# All C++ compiler flags required by this OS platform +OS_CXXFLAGS := -D_POSIX_PTHREAD_SEMANTICS=1 -m32 -D_UNIX=1 -I/usr/local/include +OS_CFLAGS := -D_POSIX_PTHREAD_SEMANTICS=1 -m32 -D_UNIX=1 -I/usr/local/include + +# All flags/libraries the linker will need +OS_LDFLAGS := -m32 -L/usr/local/lib -Wl,-R,/usr/local/lib + +ASM := yasm -f elf32 +RANLIB := /usr/ccs/bin/ranlib +AR := /usr/ccs/bin/ar +SUBSYSTEM := Solaris + +#Default $CC to Sun "cc" +ifeq ($(origin CC),default) + CC := cc +endif + +#Default $CXX to Sun "CC" +ifeq ($(origin CXX),default) + CXX := CC +endif + +include BuildConfig/DetectCompiler.rules +include BuildConfig/Solaris-Libs.rules + +ifeq ($(IS_GCC),1) + CXX := g++ #Use matching GNU g++ + include BuildConfig/GCC-Flags.rules + + #These are gcc + Solaris specific + OS_CFLAGS += -threads + OS_CXXFLAGS += -threads +else ifeq ($(IS_CC),1) + CXX := CC #Use matching Sun C++ + include BuildConfig/SunPro-Flags.rules +endif diff --git a/BuildConfig/Makefile.Windows.x86 b/BuildConfig/Makefile.Windows.x86 new file mode 100644 index 0000000..2b45b1b --- /dev/null +++ b/BuildConfig/Makefile.Windows.x86 @@ -0,0 +1,28 @@ +# BuildConfig/Makefile.Windows.x86 +# Author: Patrick Baggett +# Created: 11/09/2012 +# +# Purpose: +# +# Makefile for Windows running on 32-bit x86 architecture processors +# +# License: +# +# This program is free software. It comes without any warranty, to +# the extent permitted by applicable law. You can redistribute it +# and/or modify it under the terms of the Do What The Fuck You Want +# To Public License, Version 2, as published by Sam Hocevar. See +# http://sam.zoy.org/wtfpl/COPYING for more details. + +# All C/C++ compiler flags required by this OS platform +OS_CXXFLAGS := -m32 -D_WINDOWS=1 +OS_CFLAGS := -m32 -D_WINDOWS=1 + +include BuildConfig/GCC-Flags.rules + +ASM := yasm -f win32 -m x86 +RANLIB := ranlib +SUBSYSTEM := Win32 + +# All flags/libraries the linker will need +OS_LDFLAGS := -m32 -L/usr/local/lib -Wl,-rpath,/usr/local/lib diff --git a/BuildConfig/POSIX-Libs.rules b/BuildConfig/POSIX-Libs.rules new file mode 100644 index 0000000..d256be3 --- /dev/null +++ b/BuildConfig/POSIX-Libs.rules @@ -0,0 +1,22 @@ +# BuildConfig/POSIX-Libs.rules +# Author: Patrick Baggett +# Created: 3/19/2012 +# +# Purpose: +# +# Defines common libraries required for linking on POSIX platforms +# +# License: +# +# This program is free software. It comes without any warranty, to +# the extent permitted by applicable law. You can redistribute it +# and/or modify it under the terms of the Do What The Fuck You Want +# To Public License, Version 2, as published by Sam Hocevar. See +# http://sam.zoy.org/wtfpl/COPYING for more details. + +# Base libraries (console) +export ZENGINE_BASE_LIBS = -lrt -ldl -lpthread -lm + +# GUI libraries (X Windows) +export ZENGINE_GUI_LIBS = -lGL -lX11 + diff --git a/BuildConfig/RaspPi-Flags.rules b/BuildConfig/RaspPi-Flags.rules new file mode 100644 index 0000000..d49080a --- /dev/null +++ b/BuildConfig/RaspPi-Flags.rules @@ -0,0 +1,19 @@ +# BuildConfig/RaspPi-Flags.rules +# Author: Patrick Baggett +# Created: 1/4/2013 +# +# Purpose: +# +# Special flags for the Raspberry Pi running on Linux +# +# License: +# +# This program is free software. It comes without any warranty, to +# the extent permitted by applicable law. You can redistribute it +# and/or modify it under the terms of the Do What The Fuck You Want +# To Public License, Version 2, as published by Sam Hocevar. See +# http://sam.zoy.org/wtfpl/COPYING for more details. + +OS_CFLAGS += -I/opt/vc/include -I/opt/vc/include/interface/vcos/pthreads +OS_LDFLAGS += -L/opt/vc/lib -lbcm_host + diff --git a/BuildConfig/Solaris-Libs.rules b/BuildConfig/Solaris-Libs.rules new file mode 100644 index 0000000..624467a --- /dev/null +++ b/BuildConfig/Solaris-Libs.rules @@ -0,0 +1,26 @@ +# BuildConfig/Solaris-Libs.rules +# Author: Patrick Baggett +# Created: 4/11/2012 +# +# Purpose: +# +# Defines common libraries required for linking on Solaris 10 and later +# +# License: +# +# This program is free software. It comes without any warranty, to +# the extent permitted by applicable law. You can redistribute it +# and/or modify it under the terms of the Do What The Fuck You Want +# To Public License, Version 2, as published by Sam Hocevar. See +# http://sam.zoy.org/wtfpl/COPYING for more details. + +# The major difference between this file and POSIX-Libs.rules is that Solaris +# uses native threads, so linking to libpthread.so just bloats the binary. Also, +# Solaris native threads are in libc.so, so no other library is needed. + +# Base libraries (console) +export ZENGINE_BASE_LIBS = -lrt -lm + +# GUI libraries (X Windows) +export ZENGINE_GUI_LIBS = -lGL -lX11 + diff --git a/BuildConfig/SunPro-Flags.rules b/BuildConfig/SunPro-Flags.rules new file mode 100644 index 0000000..ca3c070 --- /dev/null +++ b/BuildConfig/SunPro-Flags.rules @@ -0,0 +1,30 @@ +# BuildConfig/SunPro-Flags.rules +# Author: Patrick Baggett +# Created: 4/1/2012 +# +# Purpose: +# +# Common flags for Sun "cc" to reduce redundancy +# +# License: +# +# This program is free software. It comes without any warranty, to +# the extent permitted by applicable law. You can redistribute it +# and/or modify it under the terms of the Do What The Fuck You Want +# To Public License, Version 2, as published by Sam Hocevar. See +# http://sam.zoy.org/wtfpl/COPYING for more details. + +SUNPRO_COMMON := -mt -features=extensions + +ifeq ($(findstring sparc,$(ARCH)),sparc) + ISSPARC := 1 +endif + +ifeq ($(ISSPARC),1) + SUNPRO_COMMON += -xmemalign=8s +endif + +OS_CFLAGS += $(SUNPRO_COMMON) -xalias_level=std +OS_CXXFLAGS += $(SUNPRO_COMMON) -xalias_level=simple +OS_LDFLAGS += $(SUNPRO_COMMON) + diff --git a/Include/ZBuild.hpp b/Include/ZBuild.hpp new file mode 100644 index 0000000..aa0c8a2 --- /dev/null +++ b/Include/ZBuild.hpp @@ -0,0 +1,137 @@ +/* + ZBuild.hpp + Author: James Russell + + Purpose: This is the build file that is used to set overall build configuration + when building ZEngine projects. This needs to be on the build path for + all ZEngine projects. + + Changelog + 2011/12/11 - creation (jcrussell) +*/ + +#pragma once + +#ifndef _ZBUILD_HPP +#define _ZBUILD_HPP + +//Current version of ZEngine (overall, not individual lib versions) +#define ZENGINE_CURRENT_VERSION "0.6.0" + +//These should be modified for the game in question +#ifndef COMPANY_NAME +#define COMPANY_NAME "762Studios" +#endif + +#ifndef GAME_NAME +#define GAME_NAME "762Game" +#endif + +/* +The following flags can be enabled / disabled based off of compile type. Usually enabled as a 1 or 0, but +some will have additional options. + +--- ZRendererUtil --- +#define ZASSERT_RENDERERUTIL - Enables run-time asserts for renderer util project debugging + +--- ZRenderer --- +#define ZASSERT_RENDERER - Enables run-time asserts for renderer project debugging + +#define ZGL_CHECKGL - Enables the CHECKGL function call to check graphics library state after library calls + +--- ZUtil --- +#define ZALLOC_CHECK_ALLOC - Indicates that ZAlloc should record allocations +#define ZALLOC_EXTRA_SPAMMY - Indicates that ZAlloc should log all allocations + +#define ZASSERT_DISABLE - Disables run-time asserts for debugging purposes +#define ZASSERT_UTIL_ENABLE - Enables run-time asserts for util project debugging + +#define ZLOG_LEVEL - Defined as one of ZLOG_LEVEL_NONE, ZLOG_LEVEL_ERROR, ZLOG_LEVEL_WARNING, ZLOG_LEVEL_DETAILED, or ZLOG_LEVEL_EVERYTHING + +#define ZSTL_CHECK_INTEGRITY - Causes ZSTL containers to check integrity after function calls (uses ZASSERT) +#define ZSTL_CHECK_NAME - Causes ZName to ensure no hash collision has occurred +#define ZSTL_DISABLE_RUNTIME_CHECKS - Causes ZSTL containers to no longer do runtime bounds and error checking (ballsy) +*/ + +//Engine Debug version engine flags +#ifdef _DEBUGENG + + #define ZALLOC_CHECK_ALLOC 1 + #define ZALLOC_EXTRA_SPAMMY 0 + + #define ZASSERT_ENABLE 1 + #define ZASSERT_UTIL_ENABLE 1 + #define ZASSERT_RENDERER_ENABLE 1 + + #define ZRENDERER_CHECKGL 1 + + #define ZLOG_LEVEL ZLOG_LEVEL_SPAM + + #define ZSTL_CHECK_INTEGRITY 1 + #define ZSTL_CHECK_NAME 1 + #define ZSTL_DISABLE_RUNTIME_CHECKS 0 + +#endif //_DEBUGENG + +//Debug version engine flags +#ifdef _DEBUG + + #define ZALLOC_CHECK_ALLOC 1 + #define ZALLOC_EXTRA_SPAMMY 0 + + #define ZASSERT_ENABLE 1 + #define ZASSERT_UTIL_ENABLE 1 + #define ZASSERT_RENDERER_ENABLE 0 + + #define ZLOG_LEVEL ZLOG_LEVEL_INFO + + #define ZRENDERER_CHECKGL 1 + + #define ZSTL_CHECK_INTEGRITY 1 + #define ZSTL_CHECK_NAME 1 + #define ZSTL_DISABLE_RUNTIME_CHECKS 0 + +#endif //_DEBUG + +//Dev version engine flags +#ifdef _DEV + + #define ZALLOC_CHECK_ALLOC 0 + #define ZALLOC_EXTRA_SPAMMY 0 + + #define ZASSERT_ENABLE 1 + #define ZASSERT_UTIL_ENABLE 0 + #define ZASSERT_RENDERER_ENABLE 0 + + #define ZRENDERER_CHECKGL 0 + + #define ZLOG_LEVEL ZLOG_LEVEL_WARNING + + #define ZSTL_CHECK_INTEGRITY 0 + #define ZSTL_CHECK_NAME 0 + #define ZSTL_DISABLE_RUNTIME_CHECKS 0 + +#endif //_DEV + +//Release version engine flags +#ifdef _RELEASE + + #define ZALLOC_CHECK_ALLOC 0 + #define ZALLOC_EXTRA_SPAMMY 0 + + #define ZASSERT_ENABLE 0 + #define ZASSERT_UTIL_ENABLE 0 + #define ZASSERT_RENDERER_ENABLE 0 + + #define ZRENDERER_CHECKGL 0 + + #define ZLOG_LEVEL ZLOG_LEVEL_WARNING + + #define ZSTL_CHECK_INTEGRITY 0 + #define ZSTL_CHECK_NAME 0 + #define ZSTL_DISABLE_RUNTIME_CHECKS 1 + +#endif //_RELEASE + +#endif + diff --git a/Include/ZNet/ZNet.hpp b/Include/ZNet/ZNet.hpp new file mode 100644 index 0000000..73a4a8e --- /dev/null +++ b/Include/ZNet/ZNet.hpp @@ -0,0 +1,29 @@ +/* + ZNet.hpp + Author: Patrick Baggett + Created: 6/4/2013 + + Purpose: + + ZNet main include + + License: + + Copyright 2013, 762 Studios +*/ + +#pragma once + +#ifndef _ZNET_HPP +#define _ZNET_HPP + + +#include +#include +#include +#include +#include +#include + +#endif + diff --git a/Include/ZNet/ZNetBandwidthMeter.hpp b/Include/ZNet/ZNetBandwidthMeter.hpp new file mode 100644 index 0000000..f5638c2 --- /dev/null +++ b/Include/ZNet/ZNetBandwidthMeter.hpp @@ -0,0 +1,57 @@ +/* + ZNetBandwidthMeter.hpp + Author: Patrick Baggett + Created: 7/10/2013 + + Purpose: + + ** NOT PART OF PUBLIC SDK ** + This class is not part of the public SDK; its fields and methods are not present + in the documentation and cannot be guaranteed in future revisions. + ** NOT PART OF PUBLIC SDK ** + + Bandwidth metering using a simple token bucket algorithm. A single value is + metered, so a incoming / outgoing each need an instance. + + License: + + Copyright 2013, 762 Studios +*/ + +#pragma once + +#ifndef _ZNETBANDWIDTHMETER_HPP +#define _ZNETBANDWIDTHMETER_HPP + + +#include + +class ZNetBandwidthMeter +{ + public: + /* Sets the new bandwidth limit */ + void SetLimit(uint32_t newLimit); + + /* Resets the meter for reuse. Takes the current time */ + void Reset(uint64_t newStartTime); + + /* Try to allocate a given number of bytes */ + bool TryAllocate(uint32_t bytes); + + /* Update the token bucket */ + void Update(uint64_t newTime); + + /* Get the bandwidth limit */ + uint32_t GetLimit() const { return limit; } + + /* Get the available instantaneous bandwidth */ + uint32_t GetAvailable() const { return tokens; } + + private: //Should be POD basically + uint64_t lastTime; //The last time this was updated + uint32_t limit; //The bandwidth limit, in bytes per second + uint32_t tokens; //The available bandwidth within this 1 second timeframe +}; + +#endif + diff --git a/Include/ZNet/ZNetClient.hpp b/Include/ZNet/ZNetClient.hpp new file mode 100644 index 0000000..8d83744 --- /dev/null +++ b/Include/ZNet/ZNetClient.hpp @@ -0,0 +1,98 @@ +/* + ZNetClient.hpp + Author: Patrick Baggett + Created: 7/11/2013 + + Purpose: + + ZNetClient -- extends ZNetHost to provide a client + + License: + + Copyright 2013, 762 Studios +*/ + +#pragma once + +#ifndef _ZNETCLIENT_HPP +#define _ZNETCLIENT_HPP + +#include +#include + +class ZNetClient : public ZNetHost +{ + public: + ZNetClient(); + ~ZNetClient(); + + /* + ZNetClient::Update() + + Implements ZNetHost::Update(). + + This should be called to read incoming network data and send outgoing traffic. Events + are only generated by calling Update(). + + @return (int) - Less than 0: error. 0: OK + */ + int Update(); + + /* + ZNetClient::Connect() + + Initiates a connection to the given host. This method is asynchronous, so an event is + generated. However, if this returns false, then no events will be generated because + an error has occurred locally. + */ + bool Connect(SST_Socket socket, SST_NetAddress* addr, uint32_t nrChannels, uint32_t userData); + + /* + ZNetClient::SendPacket() + + Sends a packet to the server via a certain channel. Use ZNetPacket::Release() + when the packet is no longer needed. + + @param packet - The packet to broadcast + @param channelId - The channel ID + */ + void SendPacket(ZNetPacket* packet, uint32_t channelId); + + + /* + ZNetClient::Disconnect() + + Begins a graceful disconnect. Update() should be called until an event of type DISCONNECT occurs, + or a timeout happens. If a timeout is reached, Reset() should be used. + + */ + void Disconnect(); + + /* + ZNetClient::Reset() + + Disconnects from the server, but does not inform him/her that the disconnect has occurred. + This should only be used when a graceful disconnect does not work or when aborting + the client. No local event is generated, so any cleanup must be done immediately. + */ + void Reset(); + + /* + ZNetClient::GetServer() + + Gets the ZNetPeer object that represents the server. If the client is + not connected, then this returns NULL. + */ + ZNetPeer* GetServer() const; + + bool IsConnected() const { return connectedFlag; } + + private: + ZNetPeer server; + bool connectedFlag; + + /* Handle a raw packet sent by the server */ + void HandlePacket(const uint8_t* data, uint32_t dataSize); +}; + +#endif \ No newline at end of file diff --git a/Include/ZNet/ZNetConsts.hpp b/Include/ZNet/ZNetConsts.hpp new file mode 100644 index 0000000..218ed9a --- /dev/null +++ b/Include/ZNet/ZNetConsts.hpp @@ -0,0 +1,44 @@ +/* + ZNetConsts.hpp + Author: Patrick Baggett + Created: 6/5/2013 + + Purpose: + + ZNet symbolic constants + + License: + + Copyright 2013, 762 Studios +*/ + +#pragma once + +#ifndef _ZNETCONSTS_HPP +#define _ZNETCONSTS_HPP + +#define ZNET_MTU_IPV4SAFE 512 //Like ZNET_MTU_IPV4, but with slightly less space, allowing for 64 bytes of IP overhead via optional sections +#define ZNET_MTU_IPV4 548 //Minimum maximum reassembly buffer size of 576 minus 28 bytes of overhead for UDPv4 +#define ZNET_MTU_ETHERNET 1500 +#define ZNET_MTU_IPV6 1280 +#define ZNET_MTU_IPV6SAFE 1232 //IPv6 required 1280 minus 48 for UDPv6+IPv6 header + +#define ZNET_MAX_SERVER_SOCKETS 4 //Maximum number of sockets a server may listen on + +//Flags for ZNetPacket::Initialize() +#define ZNET_TRANSIENT 0x00000000u //< Default value. The packet is unreliable, but transient, so the newest copy is presented and older version discarded. +#define ZNET_RELIABLE 0x00000001u //< This packet will be reliable. + + + +//Peer state +enum ZNetConnectionState +{ + STATE_UNCONNECTED, //No connection(s) established + STATE_HANDSHAKE, //Machine has attempted connection, awaiting handshake + STATE_CONNECTED, //Machine is connected actively to a remote machine + STATE_SERVING //Clients connected, actively serving them +}; + +#endif + diff --git a/Include/ZNet/ZNetEvent.hpp b/Include/ZNet/ZNetEvent.hpp new file mode 100644 index 0000000..a708c3c --- /dev/null +++ b/Include/ZNet/ZNetEvent.hpp @@ -0,0 +1,45 @@ +/* + ZNetEvent.hpp + Author: Patrick Baggett + Created: 6/5/2013 + + Purpose: + + ZNet event structure + + License: + + Copyright 2013, 762 Studios +*/ + +#pragma once + +#ifndef _ZNETEVENT_HPP +#define _ZNETEVENT_HPP + +class ZNetPeer; +struct ZNetPacket; + +enum ZNetEventType +{ + ZNETEVENT_NONE, //No event + ZNETEVENT_CONNECT, //A new incoming connection was made + ZNETEVENT_DISCONNECT, //A graceful disconnection occurred + ZNETEVENT_TIMEOUT, //A timeout occurred + ZNETEVENT_DATA //Data was received +}; + +//Event when connected +struct ZNetEvent +{ + ZNetPeer* remote; //The remote host + ZNetPacket* packet; //The packet data + uint32_t userdata; //The user data (if applicable) + ZNetEventType type; //The type +}; + + + +#endif + + diff --git a/Include/ZNet/ZNetHost.hpp b/Include/ZNet/ZNetHost.hpp new file mode 100644 index 0000000..ce3c47d --- /dev/null +++ b/Include/ZNet/ZNetHost.hpp @@ -0,0 +1,184 @@ +/* + ZNetHost.hpp + Author: Patrick Baggett + Created: 7/10/2013 + + Purpose: + + ZNet base class for shared client/server data + + License: + + Copyright 2013, 762 Studios +*/ + +#pragma once + +#ifndef _ZNETHOST_HPP +#define _ZNETHOST_HPP + +#include +#include +#include + +struct ZNetPacket; + +class ZNetHost +{ + public: + ZNetHost(); + virtual ~ZNetHost() { } + + /* + ZNetHost::Update() + + Fetches and sends data as necessary to perform the given role. See the + documentation for the specific class. Generally, you need to call this + each frame. + + @return (int) - Less than 0: error. 0: OK + */ + virtual int Update() = 0; + + /* + ZNetHost::CreatePacket() + + Creates a packet and copies the given initialization data (if any). + + @param initData - Data to copy to the new packet, or NULL for uninitialized packet. + @param dataSize - The size of the packet's payload + @param flags - The flags. No flags defined, so must be 0 + */ + ZNetPacket* CreatePacket(const void* initData, uint32_t dataSize, uint32_t flags); + + /* + ZNetHost::HasEvent() + + Returns true if there are queued events. The next call to GetNextEvent() + is guaranteed to succeed. + + @return (bool) - True if at least one event is pending + */ + bool HasEvent() { return events.Size() > 0; } + + /* + ZNetHost::GetNextEvent() + + Attempt to fetch the next event form the queue and returns + whether one was fetched or not. + + @param eventReturn - Pointer to ZNetEvent structure to receive event data + @return (bool) - True if an event was returned, false if none was available (and eventReturn is not modified) + */ + bool GetNextEvent(ZNetEvent* eventReturn); + + //====================================================================== + // TRIVIAL GETTER / SETTER + //====================================================================== + + /* + ZNetHost::SetIncomingBandwidth() + + Sets the desired incoming bandwidth cap. + + Note that this is a request made of the remote host; malicious hosts can still + attempt DoS attacks by sending far above this limit. + + @param bwIn - The target incoming bandwidth, measured in bytes per second. + */ + void SetIncomingBandwidth(uint32_t bwIn) { inBW.SetLimit(bwIn); } + + /* + ZNetHost::SetOutgoingBandwidth() + + Sets the desired outgoing bandwidth cap. + + @param bwOut - The target outgoing bandwidth, measured in bytes per second. + */ + void SetOutgoingBandwidth(uint32_t bwOut) { outBW.SetLimit(bwOut); } + + /* + ZNetHost::SetDropChance() + + ** DEBUG ONLY ** + + Sets the chance that a packet will be intentionally dropped. This is used to + simulate high packet loss networks; it should not be used in production. As + such, the percent chance defaults to 0. Values over 100 are treated as 100%. + + @param _dropChance - The percent chance to drop. The value should be 0-99. + */ + void SetDropChance(uint32_t _dropChance) { dropChance = _dropChance; } + + /* + ZNetHost::SetMTU() + + Sets the MTU used by ZNet. ZNet will not send raw packets larger than this; + they will be fragmented into multiple calls into libsst-net. This typically less + the MTU on the adapter, since the "path MTU" is minimum of all nodes between the + two endpoints. The minimum MTU is clamped to 256 bytes. + */ + void SetMTU(uint32_t _mtu) { mtu = _mtu; if(mtu<256) mtu = 256; } + + /* + ZNetHost::GetIncomingBandwidth() + + Gets the incoming bandwidth, in bytes per second. + + @return (uint32_t) - The incoming bandwidth + */ + uint32_t GetIncomingBandwidth() const { return inBW.GetLimit(); } + + /* + ZNetHost::GetOutgoingBandwidth() + + Gets the outgoing bandwidth, in bytes per second. + + @return (uint32_t) - The outgoing bandwidth + */ + uint32_t GetOutgoingBandwidth() const { return outBW.GetLimit(); } + + /* + ZNetHost::GetDropChance() + + ** DEBUG ONLY ** + + Gets the chance to drop intentionally drop a packet. This should + be zero unless testing network code. + + @return (uint32_t) - The chance to drop a packet. + */ + uint32_t GetDropChance() const { return dropChance; } + + /* + ZNetHost::GetMTU() + + Gets the ZNet maximum transmission unit. + */ + uint32_t GetMTU() const { return mtu; } + + + protected: //These are used by ZNetServer/ZNetClient + + void Reset(uint64_t time); + + void AddEvent(const ZNetEvent* newEvent) { events.PushBack(*newEvent); } + + //Send all channel data to peer + bool SendToPeer(ZNetPeer* peer); + + void TrySendPing(bool isReply, uint32_t givenToken, ZNetPeer* peer); + void TrySendConnResp(uint32_t flags, uint32_t code); + + ZNetBandwidthMeter inBW; + ZNetBandwidthMeter outBW; + + private: + ZList events; + uint32_t mtu; //< Maximum (wire) size packet + uint32_t dropChance; //< Chance to drop a packet + +}; + +#endif + diff --git a/Include/ZNet/ZNetPacket.hpp b/Include/ZNet/ZNetPacket.hpp new file mode 100644 index 0000000..d691183 --- /dev/null +++ b/Include/ZNet/ZNetPacket.hpp @@ -0,0 +1,46 @@ +/* + ZNetPacket.hpp + Author: Patrick Baggett + Created: 6/4/2013 + + Purpose: + + ZNet packet class, represents a packet + + License: + + Copyright 2013, 762 Studios +*/ + +#pragma once + +#ifndef _ZNETPACKET_HPP +#define _ZNETPACKET_HPP + +#include + +/* + ZNetPacket defines a logical packet that is to be sent or has been received. The data is appended + at the end of the structure, so getting the address requires pointer manipulation. It does + not represent the wire format of what is sent, since packets may be merged. +*/ + +struct ZNetPacket +{ + uint32_t dataSize; //< Size of the packet (logically) + uint32_t flags; //< The flags. ZNET_TRANSIENT, ZNET_RELIABLE, etc. + int32_t refCount; //< Reference count + + uint8_t* GetData() { return (uint8_t*) ((uintptr_t)this + sizeof(ZNetPacket)); } + void AddReference() { refCount++; } + void ReleaseReference() + { + refCount--; + if(refCount == 0) + free(this); + } +}; + +#endif + + diff --git a/Include/ZNet/ZNetPacketChannel.hpp b/Include/ZNet/ZNetPacketChannel.hpp new file mode 100644 index 0000000..ec375a3 --- /dev/null +++ b/Include/ZNet/ZNetPacketChannel.hpp @@ -0,0 +1,165 @@ +/* + ZNetPacketChannel.hpp + Author: Patrick Baggett + Created: 6/14/2013 + + Purpose: + + ** NOT PART OF PUBLIC SDK ** + This class is not part of the public SDK; its fields and methods are not present + in the documentation and cannot be guaranteed in future revisions. + ** NOT PART OF PUBLIC SDK ** + + Queue of incoming and outgoing packets. + + License: + + Copyright 2013, 762 Studios +*/ + +#pragma once + +#ifndef _ZNETPACKETCHANNEL_HPP +#define _ZNETPACKETCHANNEL_HPP + +#include +#include + +struct ZNetPacket; +class ZNetHost; + +namespace ZNetPrivate { struct ZNetMessageContainer; } //urgh + +class ZNetPacketChannel +{ + public: + struct ZNetQueuedPacket + { + uint64_t timeSent; //< Time this packet was sent (or 0 for never) + ZNetPacket* packet; //< Logical packet data (payload) + uint32_t subsequence; //< For data packets, this is the number of bytes successfully acked on the remote end + uint32_t command; //< Logical packet command such as ZNETCMD_CONNECT, ZNETCMD_DATA, ... + uint16_t sequence; //< Logical packet sequence + }; + + ZNetPacketChannel() : + packetCount(0), overflowLimit(1024), localAck(0), remoteAck(0), nextSequenceNumber(1), critical(false) + { + + } + + void SetOverflowThreshold(uint32_t _overflowLimit) { overflowLimit = _overflowLimit; } + + + /* + ZNetPacketChannel::QueueForSending() + + Attempts to queue a new packet to the channel. If the overflow limit is reached, + this returns false and the client should be disconnected. + */ + bool QueueForSending(ZNetPacket* packet, uint32_t command); + + bool QueueForReceiving(); + + + /* + ZNetPacketChannel::SetChannelId() + + Sets the channel's ID value for use in outgoing packets. + */ + void SetChannelId(uint32_t chId) { channelId = chId; } + + /* + ZNetPacketChannel::FillBuffer() + + Fills a buffer with as many packets as the buffer can hold. If all packets + have been added, this returns true. If there was not enough space to hold + all of the packets, this returns false and the index to resume at is provided. + + @param buffer - Input buffer pointer + @param bufferSize - The size of the buffer pointed to by buffer[] + @param packetStartIndex - The starting index. Should start at 0, and use the value returned in restartIndexReturn to resume + @param restartIndexReturn - The index to resume packet storage. + @param bytesWritten - The number of bytes written + */ + bool FillBuffer(uint8_t* buffer, uint32_t bufferSize, uint32_t packetStartIndex, uint32_t* restartIndexReturn, uint32_t* bytesWritten); + + /* + ZNetPacketChannel::Deinitialize() + */ + void Deinitialize(); + + + /* + ZNetPacketChannel::UpdateRemoteAck() + + Updates the remote ack counter and dequeues packets as necessary. + + @param newHighest - The new highest sequence number + @param pingAdjust - Set to the current ping value, this value is adjusted by the RTT on a per-packet basis + */ + void UpdateRemoteAck(uint16_t newHighest, int32_t* pingAdjust); + + /* + ZNetPacketChannel::UpdateLocalAck() + + Updates the local sequence counter for this time period. + */ + void UpdateLocalAck(uint16_t seq); + + /* + ZNetPacketChannel::QueueLocally() + + Queue a received packet for local consumption. Since packets have an ordering and they may be received out of + order (e.g. send 1, 2, 3 may be processed as 2, 1, 3), this allows ZNet to reorder them and generate the + appropriate sequence of events. + */ + bool QueueLocally(const ZNetPacketChannel::ZNetQueuedPacket* container); + + /* + ZNetPacketChannel::QueueData() + + Queue a received data packet. This has one of three effects: + 1) Full data packet received (e.g. short packet), so it just acts like QueueLocally() + 2) Fragmented data packet, did not exist before now -- creates a reassembly buffer. + 3) Fragmented data packet, did exist -- adds to reassembly and check if reassembly is complete. If it is, QueueLocally(). + */ + bool QueueData(ZNetPrivate::ZNetMessageContainer* data); + + void ProcessLocalAcks(); + + void SetHost(ZNetHost* _host) { host = _host; } + + ZNetHost* GetHost() const { return host; } + + uint16_t GetLocalAck() { return localAck; } + + //Return the highest sequence number for this channel. This is one less than the "next", intuitively. + uint16_t GetHighestSent() { return nextSequenceNumber == 0 ? UINT16_MAX : nextSequenceNumber; } + private: + + struct ZNetDataReassemblyPacket + { + ZNetPacket* packet; //< Logical packet data (not yet fully assembled) + uint32_t subsequence; //< Highest contiguous amount of data received + uint16_t sequence; //< The sequence number of this packet + }; + + ZList packets; //List of packets we've sent (or will send) but have not yet been acknowledged + ZList reassembly; + ZList assembled; + ZList sequencesFound; //The sequence numbers found this time around (sorted) + ZNetHost* host; //Owner (used for memory allocations) + uint32_t packetCount; //ZList::Size() is O(n), keep track manually + uint32_t overflowLimit; //When this many outgoing packets are unacknowledged, + uint32_t channelId; //This channel's ID value for outgoing packets + uint16_t localAck; //Local acknowledge counter (i.e. highest number of incoming packets we've confirmed) + uint16_t remoteAck; //Remote acknowledge counter (i.e. highest number the remote host has told us it has confirmed) + uint16_t nextSequenceNumber; //Next outgoing sequence number + + bool critical; //Is the remote host in a critical state? + +}; + +#endif + diff --git a/Include/ZNet/ZNetPeer.hpp b/Include/ZNet/ZNetPeer.hpp new file mode 100644 index 0000000..fed2a7d --- /dev/null +++ b/Include/ZNet/ZNetPeer.hpp @@ -0,0 +1,143 @@ +/* + ZNetPeer.hpp + Author: Patrick Baggett + Created: 6/5/2013 + + Purpose: + + ZNet peer class, representing a remote host + + License: + + Copyright 2013, 762 Studios +*/ + +#pragma once + +#ifndef _ZNETPEER_HPP +#define _ZNETPEER_HPP + +#include +#include +#include + +class ZNetPeer; +class ZNetServer; + +class ZNetPeer +{ + public: + ZNetPeer(); + ~ZNetPeer() { Deinitialize(); } + + /* + ZNetPeer::SetUserData() + + Sets the user data for this peer. This value is not + modified or inspected by ZNet. It defaults to NULL. + + @param ud - The user data + */ + void SetUserData(void* ud) { userdata = ud; } + + /* + ZNetPeer:GetUserData() + + Gets the user data for this peer. + + @return (void*) - The user data + */ + void* GetUserData() { return userdata; } + + /* + ZNetPeer::GetNetAddress() + + Gets the network address that this remote host uses. + + @return (const SST_NetAddress*) - The remote host's network address + */ + const SST_NetAddress* GetNetAddress() const { return &addr; } + + + /* + ZNetPeer::GetState() + + Gets the remote host's state. TODO: Is this necessary for public API? + + @return (ZNetConnectionState) - The connection state + */ + ZNetConnectionState GetState() const { return state; } + + /* + ZNetPeer::GetSocket() + + Gets the socket that was is used to send/receive from the remote host. + */ + SST_Socket GetSocket() const { return socketCopy; } + + /* + ZNetPeer::GetPing() + + Gets the approximate ping. Note that the ping value is only updated + when a packet is received, so during a disconnect event, this would not + be accurate. Use GetLastReceived() to find the time since the last packet. + + @return (int32_t) - The last known ping value. If < 0, then the ping is unknown. + */ + int32_t GetPing() { return ping; } + + /* + Gets the timestamp at which the last valid packet was received. Applications + can use this as a sort of "health" meter for the link and decide how to change + things such as client predictions during times of high latency. A value of 0 + indicates that no valid packet has yet been received. To compare timestamps, + use SST_OS_GetMilliTime(). Note that only *valid* packets are considered; so + hosts sending incompatible data are not considered. + + @return (uint64_t) - The timestamp of the last valid packet. + */ + uint64_t GetLastReceived() { return lastValidIncoming; } + + private: + + /* Initialize the peer */ + bool Initialize(ZNetHost* _host, const SST_NetAddress* newAddr, SST_Socket s, uint32_t nrChannels); + + void Deinitialize(); + + void SetState(ZNetConnectionState s) { state = s; } + void SetLastReceived(uint64_t ts) { lastValidIncoming = ts; } + void SetPing(int32_t _ping) { ping = _ping; } + + + uint32_t GetNumberChannels() const { return nrChannels; } + + ZNetPacketChannel* GetPacketChannel(uint32_t chId); + + + //Process all received packets' sequence number to come up with a + //new sequence number to tell the remote server that we've received. + void ProcessLocalAcks(); + + void SendAcksForAllChannels(); + + friend class ZNetHost; + friend class ZNetClient; + friend class ZNetServer; + + SST_NetAddress addr; //Remote address + uint64_t lastValidIncoming; //Last time a valid packet was received + uint64_t lastOutgoingAck; //Last time an outgoing ACK was sent, or 0 for never. + SST_Socket socketCopy; //Copy of the socket that was used connect to this peer + ZNetPacketChannel* channels; //The packet channels + void* userdata; //User data + uint32_t nrChannels; //Size of channels[] array + int32_t ping; //Estimated ping + ZNetConnectionState state; //Connection state + + +}; + +#endif + + diff --git a/Include/ZNet/ZNetServer.hpp b/Include/ZNet/ZNetServer.hpp new file mode 100644 index 0000000..d8cad25 --- /dev/null +++ b/Include/ZNet/ZNetServer.hpp @@ -0,0 +1,240 @@ +/* + ZNetServer.hpp + Author: Patrick Baggett + Created: 7/10/2013 + + Purpose: + + ZNetServer -- extends ZNetHost to provide a server + + License: + + Copyright 2013, 762 Studios +*/ + +#pragma once + +#ifndef _ZNETSERVER_HPP +#define _ZNETSERVER_HPP + +#include +#include +#include +#include + +typedef uint32_t (*ZNetConnectCallback)(const SST_NetAddress* addr, uint32_t userdata, void* callbackParam); + + +class ZNetServer : public ZNetHost +{ + public: + + ZNetServer(); + ~ZNetServer(); + + /* + ZNetServer::Initialize() + + Initializes the ZNetServer instance. + + */ + bool Initialize(uint32_t peerCount, uint32_t channelCount); + + /* + ZNetServer::AddSocket() + + Adds a socket for ZNet to listen on. ZNet may listen on multiple + sockets, but once a socket is added, it cannot be removed. This + limit may be lifted. Only up to ZNET_MAX_SERVER_SOCKETS can be + added. + + @param s - The socket to listen on. + @return (bool) - True if successful, false otherwise + */ + bool AddSocket(SST_Socket s); + + /* + ZNetServer::Update() + + Checks sockets and packet queues for incoming/outgoing traffic. Use GetEvent() to + fetch events generated. + + @return (int) - Less than 0: error. 0: OK + */ + int Update(); + + /* + ZNetServer::SendPacket() + + Sends a packet to a peer via a certain channel. Use ZNetPacket::Release() + when the packet is no longer needed. + + @param packet - The packet to broadcast + @param peer - The remote host to send to + @param channelId - The channel ID + */ + void SendPacket(ZNetPacket* packet, ZNetPeer* peer, uint8_t channelId); + + /* + ZNetServer::BroadcastPacket() + + Sends a packet to all peers via a certain channel. Use ZNetPacket::Release() + when the packet is no longer needed. + + @param packet - The packet to broadcast + @param channelId - The channel ID + */ + void BroadcastPacket(ZNetPacket* packet, uint8_t channelId); + + /* + ZNetServer::DisconnectPeer() + + Gracefully disconnects a peer. The peer is sent a message letting him/her + that he/she has been disconnected and awaiting confirmation. The reason code + parameter is sent to the peer. + + @param peer - The peer to signal a disconnect to + @param reasonCode - The application-specific reason code. This is not interpreted by ZNet in any way. + */ + void DisconnectPeer(ZNetPeer* peer, uint32_t reasonCode); + + /* + ZNetServer::ResetPeer() + + Disconnects the peer, but does not inform him/her that the disconnect has occurred. + This should only be used when a graceful disconnect does not work or when aborting + the server. No local event is generated, so any cleanup of the peer must be done + immediately. + + @param packet - The packet to broadcast + @param channelId - The channel ID + */ + void ResetPeer(ZNetPeer* peer); + + /* + ZNetServer::NextPeer() + + Gets the next peer in list of peers. The ordering is completely arbitrary and should not be + relied on, thus you should only pass NULL or the return value from an earlier NextPeer() call. + + This can be used to iterate through the list of peers: + + ZNetPeer* p = Server->NextPeer(NULL); + while(p) + { + DoSomethingWithPeer(p); + p = Server->NextPeer(p); + } + + @param thisPeer - The peer to get the next of, or NULL to start. + @return (ZNetPeer*) - The next peer, or NULL if reached the end. + */ + ZNetPeer* NextPeer(ZNetPeer* thisPeer); + + //====================================================================== + // TRIVIAL GETTER / SETTER + //====================================================================== + + /* + ZNetServer::SetListenFlag() + + Sets the listen flag. When true, the server reports incoming connections + for normal processing. When false, the server does not report incoming connections + and automatically rejects them. + + @param _listenFlag - The new value for the listen flag + */ + void SetListenFlag(bool _listenFlag) { listenFlag = _listenFlag; } + + /* + ZNetServer::SetConnectCallback() + + Sets the connection callback. When non-NULL, the server calls this function when + a connection attempt is made. Returning 0 indicates the client should be accepted, + while any other value indicates that the client should be rejected. If no function + is present, the server automatically accepts the client. This should be used to + implement ban lists. + + @param fn - The new callback function, or NULL to disable it + */ + void SetConnectCallback(ZNetConnectCallback fn) { connectCallback = fn; } + + /* + ZNetServer::SetCallbackParam() + + Sets the parameter that is passed to the callback. It defaults to NULL. + + @param param - The callback parameter + */ + void SetCallbackParam(void* param) { callbackParam = param; } + + /* + ZNetServer::GetListenFlag() + + Gets the listen flag. See ZNetServer::SetListenFlag() for a description of the + listen flag. + + @return (bool) - The value of the listen flag + */ + bool GetListenFlag() const { return listenFlag; } + + /* + ZNetServer::GetMaximumClientCount() + + Gets the maximum number of clients that may be simultaneously connected. + + @return (uint32_t) - The maximum number of clients + */ + uint32_t GetMaximumClientCount() const { return maxClients; } + + /* + ZNetServer::GetClientCount() + + Gets the number of clients who are currently connected. + + @return (uint32_t) - The number of clients who are connected. + */ + uint32_t GetClientCount() const { return clientCount; } + + /* + ZNetServer::GetConnectCallback() + + Gets the currently installed callback function, or NULL if none is + present. + + @return (ZNetConnectCallback) - The connect callback + */ + ZNetConnectCallback GetConnectCallback() { return connectCallback; } + + /* + ZNetServer::GetCallbackParam() + + Gets the parameter that is passed to the callback function. This + defaults to NULL. + + @return (void*) - The callback parameter + */ + void* GetCallbackParam() { return callbackParam; } + private: + ZNetPeer* peers; //< The number of peers + SST_Socket sockets[ZNET_MAX_SERVER_SOCKETS]; //< The sockets that ZNet can listen on + ZNetConnectCallback connectCallback; + void* callbackParam; + uint32_t channelCount; //< The number of channels + uint32_t maxClients; //< The maximum number of clients + uint32_t clientCount; //< The current number of clients + bool listenFlag; //< The listen flag + + + + void HandlePacket(SST_Socket s, const SST_NetAddress* addr, const uint8_t* data, uint32_t length); + + void TrySendConnResp(SST_Socket s, const SST_NetAddress* addr, uint32_t reasonCode, uint32_t flags); + + ZNetPeer* PeerForAddress(const SST_NetAddress* addr) const; + + ZNetPeer* FindEmptyPeerSlot(); +}; + +#endif + diff --git a/Include/ZNet/ZNetUtil.hpp b/Include/ZNet/ZNetUtil.hpp new file mode 100644 index 0000000..a56700b --- /dev/null +++ b/Include/ZNet/ZNetUtil.hpp @@ -0,0 +1,49 @@ +/* + ZNetUtil.hpp + Author: Patrick Baggett + Created: 6/5/2013 + + Purpose: + + ZNet utility functions + + License: + + Copyright 2013, 762 Studios +*/ + +#pragma once + +#ifndef _ZNETUTIL_HPP +#define _ZNETUTIL_HPP + +#include +#include +#include + +namespace ZNetUtil +{ + /* + ZNetUtil::ReaderForPacket + + Constructs a ZBinaryBufferReader for the given packet to read it. + + @param packet - The packet to read + @return (ZBinaryBufferReader) - The reader class + */ + inline ZBinaryBufferReader ReaderForPacket(ZNetPacket* packet) { return ZBinaryBufferReader(packet->data, packet->dataSize, ZNET_BYTEORDER); } + + /* + ZNetUtil::WriterForPacket + + Constructs a ZBinaryBufferWriter for the given packet to read it. + + @param packet - The packet to read + @return (ZBinaryBufferWriter) - The writer class + */ + inline ZBinaryBufferWriter WriterForPacket(ZNetPacket* packet) { return ZBinaryBufferWriter(packet->data, packet->dataSize, ZNET_BYTEORDER); } +} + +#endif + + diff --git a/Include/ZRenderer/ZDataBuffer.hpp b/Include/ZRenderer/ZDataBuffer.hpp new file mode 100644 index 0000000..1aabc57 --- /dev/null +++ b/Include/ZRenderer/ZDataBuffer.hpp @@ -0,0 +1,288 @@ +/* + ZDataBuffer.hpp + Author: James Russell + Created: 3/20/2011 + + Purpose: + + Interface for graphics device buffered memory, used for uniform buffers, vertex buffers, and + index buffers. + + Note that ZDataBuffer is a ZRendererResource, and should be used as such. + + License: + + TODO +*/ + +#pragma once + +#ifndef _ZDATABUFFER_HPP +#define _ZDATABUFFER_HPP + +#include + +#include + +//Forward Declarations +class ZDataBuffer; + +//The type of data buffer +enum ZDataBufferType +{ + ZDBT_VERTEX, //Contains Vertex Data + ZDBT_INDEX, //Contains Index Data + ZDBT_UNIFORM, //Contains Uniform (Constant) Data + ZDBT_SIZE +}; + +//The usage type of the data buffer +enum ZDataBufferUsage +{ + ZDBU_STATIC, //Static Buffer (never or rarely updated) + ZDBU_DYNAMIC, //Dynamic Buffer (updated frequently) + ZDBU_STREAMING, //Streaming Buffer (updated every frame) + ZDBU_SIZE +}; + +//The data type in a stream +enum ZDataBufferStreamType +{ + ZDBST_FLOAT32, //32-bit floating point + ZDBST_FLOAT64, //64-bit floating point + ZDBST_INT8, //8-bit integer, signed + ZDBST_INT16, //16-bit integer, signed + ZDBST_INT32, //32-bit integer, signed + ZDBST_UINT8, //8-bit integer, unsigned + ZDBST_UINT16, //16-bit integer, unsigned + ZDBST_UINT32, //32-bit integer, unsigned + ZDBST_SIZE +}; + +//The data type in a block +enum ZDataBufferBlockType +{ + ZDBBT_UNIFORM, //Uniform Data + ZDBBT_INDEX8, //8-bit index data + ZDBBT_INDEX16, //16-bit index data + ZDBBT_INDEX32, //32-bit index data + ZDBBT_SIZE +}; + +//Struct for stream definitions +struct ZDataBufferStream +{ + ZDataBuffer* Buffer; //Parent buffer that contains this stream + size_t ElementSize; //Size of an element in terms of data type (e.g., 2 for vec2, 3 for vec3, etc.) + size_t Offset; //Offset (in bytes) that this stream starts from beginning of data buffer + size_t Stride; //Distance (in bytes) between elements of this stream + ZDataBufferStreamType Type; //Type of data in each element of this stream (this gives us size of each unit of data) + bool Normalize; //true: fixed point value converted to [0,1] or [-1,1] range; false: typecasted. +}; + +//Struct for block definitions +struct ZDataBufferBlock +{ + ZDataBufferBlockType Type; //Type of data contained by this block + + size_t Offset; //Offset (in bytes) into the buffer where this block begins + size_t Size; //Size (in bytes) of the block + + ZDataBuffer* Buffer; //Parent buffer that contains this block data +}; + +//Wrapper class for data buffers +class ZDataBuffer : public ZRendererResource +{ +private: + DISABLE_COPY_AND_ASSIGN(ZDataBuffer); + +public: + //Default Constructor + ZDataBuffer() : ZRendererResource() { } + + //Virtual Destructor + virtual ~ZDataBuffer() { } + + /* + virtual public ZDataBuffer::DefineBlock + + Defines a block of data present in the buffer. Examples of blocks include + index blocks and uniform buffer storage blocks. + + @param _type - the type of block (index or uniform) + @param _size - the size of the block (in bytes) + @return (const ZDataBufferBlock*) - the data buffer block created + @context (all) + */ + virtual const ZDataBufferBlock* DefineBlock(ZDataBufferBlockType _type, + size_t _size + ) = 0; + /* + virtual public ZDataBuffer::DefineStream + + Defines a stream that is present in this buffer. Examples of streams include + the position stream (vertex coordinates), the color stream, the normal stream, + and uv coordinate streams. Other streams can be defined so as to be usable by + shader programs. + + @param _type - The type of stream. + @param _elemCount - The number of elements in the stream, e.g., 3D position has an element + count of 3, 2D position has an element count of 2, etc... + @param _offset - The offset into the buffer (in bytes) where this stream begins + @param _stride - The stride between beginnings of consecutive elements (in bytes), or 0 for packed elements + @param _normalize - If true, fixed point data should be normalized (i.e. changed to [0,1] or [-1,1] if unsigned/signed), otherwise + it is converted similar to a C typecast, i.e. 'float value = (float)fixedValue' + @return (const ZDataBufferStream*) - the data buffer stream created + @context (all) + */ + virtual const ZDataBufferStream* DefineStream(ZDataBufferStreamType _type, + size_t _elemCount, + size_t _offset, + size_t _stride, + bool _normalize + ) = 0; + + /* + virtual public ZDataBuffer::Fill + + Fills the buffer with data, as specified. This is equivalent to calling + 'MapBuffer', filling the buffer, and calling 'UnmapBuffer'. + + @param _data - the data to fill the buffer with + @param _offset - offset into the buffer to start copying to + @param _byteCount - number of bytes to copy from _data + @return (bool) - true if this update was successful, false if the buffer is 'locked' or 'contended' + @context (all) + */ + virtual bool Fill(const void* _data, + size_t _offset, + size_t _byteCount + ) = 0; + + /* + virtual public ZDataBuffer::GetBlock + + Gets the pointer to a block previously defined using DefineBlock(). + + @param index - The block's index. The first block created with DefineBlock() is 0, the second is 1, and so on. + @return ( const ZDataBufferBlock*) - block definition + @context (all) + */ + virtual const ZDataBufferBlock* GetBlock(size_t index) = 0; + + /* + virtual public ZDataBuffer::GetStream + + Gets the pointer to a stream previously defined using DefineStream(). + + @param index - The stream's index. The first stream created with DefineStream() is 0, the second is 1, and so on. + @return (const ZDataBufferStream*) - stream definition + @context (all) + */ + virtual const ZDataBufferStream* GetStream(size_t index) = 0; + + /* + virtual public ZDataBuffer::GetBlockCount + + Gets the number of blocks that have been defined so far. + + @return (size_t) - The number of blocks defined with DefineBlock() + @context (all) + */ + virtual size_t GetBlockCount() const = 0; + + /* + virtual public ZDataBuffer::GetStreamCount + + Gets the number of streams that have been defined so far. + + @return (size_t) - The number of blocks defined with DefineStream() + @context (all) + */ + virtual size_t GetStreamCount() const = 0; + + + /* + virtual public ZDataBuffer::GetSize + + Gets the size of this data buffer. + + @return (size_t) - the size (in bytes) of this buffer + @context (all) + */ + virtual size_t GetSize() = 0; + + /* + virtual public ZDataBuffer::GetType + + Gets the type of this data buffer. + + @return (ZDataBufferType) - the buffer type + @context (all) + */ + virtual ZDataBufferType GetType() = 0; + + /* + virtual public ZDataBuffer::GetUsage + + Gets the usage of this data buffer. + + @return (ZDataBufferUsage) - the usage type + @context (all) + */ + virtual ZDataBufferUsage GetUsage() = 0; + + /* + virtual public ZDataBuffer::Map + + Maps the data buffer into user memory and marks this resource as locked until 'UnmapBuffer' is called. + + If the discard parameter is set to true, this tells the implementation that the data + that is currently present in the buffer is not required, and this may result in a faster + return, especially in the case of static usage buffers. If the current data is needed + (discard is false), static usage buffers must wait for the render thread to get the data + from the graphics memory. Dynamic and streaming usage buffers typically suffer no + performance penalty regardless of the value of the discard parameter, though this may + vary based on implementation. + + @param _discard - hint to the implementation that the data in the buffer can be discarded + @return (void*) - pointer to the buffer in mapped memory, NULL if this buffer is 'locked' or 'contended' + @context (all) + */ + virtual void* Map(bool _discard = false) = 0; + + /* + virtual public ZDataBuffer::UndefBlocks + + Undefines all currently set blocks. This will invalidate existing block + definition structures returned from DefineBlock. + + @return (void) + @context (all) + */ + virtual void UndefBlocks() = 0; + + /* + virtual public ZDataBuffer::UndefStreams + + Undefines all currently set streams. This will invalidate existing stream + definition structures returned from DefineStream. + + @return (void) + @context (all) + */ + virtual void UndefStreams() = 0; + + /* + virtual public ZDataBuffer::Unmap + + Unmaps a previously mapped data buffer and unlocks the data buffer. + + @return (void) + @context (all) + */ + virtual void Unmap() = 0; +}; + +#endif \ No newline at end of file diff --git a/Include/ZRenderer/ZDataBufferBase.hpp b/Include/ZRenderer/ZDataBufferBase.hpp new file mode 100644 index 0000000..6ace39e --- /dev/null +++ b/Include/ZRenderer/ZDataBufferBase.hpp @@ -0,0 +1,130 @@ +/* + ZDataBufferBase.hpp + Author: James Russell + Created: 3/20/2011 + + Purpose: + + The ZDataBufferBase class is meant to be used by implementations that are + required to handle threading and concurrency problems that are not solved by + the graphics library. + + License: + + TODO +*/ + +#pragma once + +#ifndef _ZDATABUFFERBASE_HPP +#define _ZDATABUFFERBASE_HPP + +#include + +/* +Base class implementation for the Data Buffer. +*/ +class ZDataBufferBase : public ZDataBuffer +{ +protected: + //Default Constructor + ZDataBufferBase(ZDataBufferType _type, ZDataBufferUsage _usage, size_t _size); + + //Type of the Data Buffer + ZDataBufferType Type; + + //Usage setting for the Data Buffer + ZDataBufferUsage Usage; + + //Size (in bytes) of the Data Buffer + size_t Size; + + //Array of DataBufferBlocks held by this DataBuffer + ZArray Blocks; + + //Array of DataBufferStreams held by this DataBuffer + ZArray Streams; + + //Backing buffer, used to double-buffer the graphics device buffer + void* MemBuffer; + + //Flag indicating this buffer was mapped or filled + bool bIsDirty; + + //Gets the buffer data from graphics memory + virtual void GetDeviceData(void* _buffer) = 0; + + //Gets the next block offset we should use from the subclass + virtual size_t GetNextBlockOffset(size_t _size) = 0; + + //Resets the block offset to zero + virtual void ResetBlockOffset() = 0; + +public: + //Destructor + virtual ~ZDataBufferBase(); + + /* + public ZDataBufferBase::GetMemBufferResetDirty + + Gets the backing memory buffer for this device. This will return + NULL if the buffer has not been modified since the last call to + this function, and in the case it has been modified, a call to this + resets the 'dirty' flag for the buffer. + + @return (void*) - the backing memory buffer, NULL if not modified + @context (renderer) + */ + void* GetMemBufferResetDirty(); + + //Subclass Implementation + virtual const ZDataBufferBlock* DefineBlock(ZDataBufferBlockType _type, + size_t _size + ); + + //Subclass Implementation + virtual const ZDataBufferStream* DefineStream(ZDataBufferStreamType _type, + size_t _elemCount, + size_t _offset, + size_t _stride, + bool _normalize + ); + //Subclass Implementation + virtual bool Fill(const void* _data, size_t _offset, size_t _byteCount); + + //Subclass Implementation + virtual const ZDataBufferBlock* GetBlock(size_t index) { return Blocks[index]; } + + //Subclass Implementation + virtual const ZDataBufferStream* GetStream(size_t index) { return Streams[index]; } + + //Subclass Implementation + virtual size_t GetBlockCount() const { return Blocks.Size(); } + + //Subclass Implementation + virtual size_t GetStreamCount() const { return Streams.Size(); } + + //Subclass Implementation + virtual size_t GetSize(); + + //Subclass Implementation + virtual ZDataBufferType GetType(); + + //Subclass Implementation + virtual ZDataBufferUsage GetUsage(); + + //Subclass Implementation + virtual void* Map( bool _discard = false ); + + //Subclass Implementation + virtual void UndefBlocks(); + + //Subclass Implementation + virtual void UndefStreams(); + + //Subclass Implementation + virtual void Unmap(); + +}; + +#endif \ No newline at end of file diff --git a/Include/ZRenderer/ZDimensionTexture.hpp b/Include/ZRenderer/ZDimensionTexture.hpp new file mode 100644 index 0000000..f5cf2d2 --- /dev/null +++ b/Include/ZRenderer/ZDimensionTexture.hpp @@ -0,0 +1,91 @@ +/* + ZDimensionTexture.hpp + Author: James Russell + Created: 7/1/2012 + + Purpose: + + 'Dimension' (1D, 2D, 3D) Texture Interface. + + License: + + TODO + +*/ + +#pragma once + +#ifndef _ZDIMENSIONTEXTURE_HPP +#define _ZDIMENSIONTEXTURE_HPP + +#include + +#include + +//Two dimensional texture interface class +class ZDimensionTexture : public ZTexture +{ +public: + //Virtual Destructor + virtual ~ZDimensionTexture() { } + + /* + virtual public ZDimensionTexture::Fill + + Fills this texture with the data given in the bitmap data structure. + + @param _data - the bitmap data + @return (bool) - true if able to fill the texture, false if unable (contested or locked) + @context (all) + */ + virtual bool Fill(const void* _data) = 0; + + /* + virtual public ZDimensionTexture::GetBitmap + + Function to get the image metadata for a texture as a ZBitmap. Does not get the + bitmap data field in the ZBitmap instance, which is set to NULL. + + @return (const ZBitmapFormat) - bitmap format + @context (all) + */ + virtual const ZBitmapFormat GetBitmapFormat() = 0; + + /* + virtual public ZDimensionTexture::Map + + Maps this texture into memory and locks this texture until 'UnmapTexture' is called. + + The bitmap parameter is a description of how the data is laid out in memory. + + If the discard parameter is set to true, this tells the implementation that the data + that is currently present in the texture is not required, and this may result in a faster + return. + + @param _discard - hint to the implementation that the data in the texture can be discarded + @return (void*) - pointer to the mapped buffer + @context (all) + */ + virtual void* Map( bool _discard) = 0; + + /* + virtual public ZDimensionTexture::Unmap + + Unmaps a previously mapped texture and unlocks the texture. + + @return (void) + @context (all) + */ + virtual void Unmap() = 0; + + //Not Implemented + virtual ZTextureType GetType() = 0; + + //Not Implemented + virtual ZTextureUsage GetUsage() = 0; + + //Not Implemented + virtual bool IsMipmapped() = 0; +}; + +#endif diff --git a/Include/ZRenderer/ZDimensionTextureBase.hpp b/Include/ZRenderer/ZDimensionTextureBase.hpp new file mode 100644 index 0000000..9f4d7f7 --- /dev/null +++ b/Include/ZRenderer/ZDimensionTextureBase.hpp @@ -0,0 +1,110 @@ +/* + ZDimensionTextureBase.hpp + Author: James Russell + Created: 7/1/2012 + + Purpose: + + Base implementation of a dimension (1D, 2D, 3D) texture. + + License: + + TODO + +*/ + +#pragma once + +#ifndef _ZDIMENSIONTEXTUREBASE_HPP +#define _ZDIMENSIONTEXTUREBASE_HPP + +#include + +class ZDimensionTextureBase : public ZDimensionTexture +{ +protected: + //Type of texture + ZTextureType Type; + + //Format of texture + ZTextureFormat Format; + + //Usage type of texture + ZTextureUsage Usage; + + //Bitmap format (including memory buffer, if needed) + ZBitmap Bitmap; + + //Flag indicating this is a mipmapped texture + bool bIsMipmapped; + + //Flag indicating the texture data has been modified + bool bIsDirty; + + //Gets the texture data from graphics memory + virtual void GetDeviceData(void* _buffer) = 0; + + /* + Parameterized Constructor. + + @param _type - the texture type + @param _format - the texture internal storage format + @param _usage - the texture usage hint + @param _bitmap - the bitmap for this texture (or side of texture, in case of cube map) + @param _generateMipmaps - flag indicating we should generate mipmaps for this texture + */ + ZDimensionTextureBase(ZTextureType _type, ZTextureFormat _format, ZTextureUsage _usage, const ZBitmap& _bitmap, bool _generateMipmaps); + +public: + //Virtual Destructor + virtual ~ZDimensionTextureBase(); + + /* + public ZDimensionTextureBase::GetBitmapResetDirty + + Gets the bitmap data for this dimension texture. This will return + NULL if the texture has not been modified since the last call to + this function, and in the case it has been modified, a call to this + resets the 'dirty' flag for the render target. + + @return (ZBitmap*) - bitmap data, NULL if not dirty + @context (all) + */ + ZBitmap* GetBitmapResetDirty(); + + uint32_t GetWidth() { return Bitmap.GetWidth(); } + uint32_t GetHeight() { return Bitmap.GetHeight(); } + uint32_t GetDepth() { return Bitmap.GetDepth(); } + + /*****************************/ + /* ZDimensionTexture Methods */ + /*****************************/ + + //Subclass Implementation + virtual bool Fill(const void* _data); + + //Subclass Implementation + virtual const ZBitmapFormat GetBitmapFormat(); + + //Subclass Implementation + virtual void* Map(bool _discard); + + //Subclass Implementation + virtual void Unmap(); + + /********************/ + /* ZTexture Methods */ + /********************/ + + //Subclass Implementation + virtual ZTextureType GetType(); + + //Subclass Implementation + virtual ZTextureUsage GetUsage(); + + //Subclass Implementation + virtual bool IsMipmapped(); +}; + +#endif + diff --git a/Include/ZRenderer/ZDrawParams.hpp b/Include/ZRenderer/ZDrawParams.hpp new file mode 100644 index 0000000..a8058be --- /dev/null +++ b/Include/ZRenderer/ZDrawParams.hpp @@ -0,0 +1,62 @@ +/* + ZDrawParams.hpp + Author: James Russell + Created: 7/17/2012 + + Purpose: + + TODO + + License: + + TODO + +*/ + + +#pragma once + +#ifndef _ZDRAWPARAMS_HPP +#define _ZDRAWPARAMS_HPP + +#include + +//Draw Parameters Types +enum ZDrawParamsType +{ + ZDPT_SHADER, //Shader Parameter Binding Structure + ZDPT_VERTEX, //Vertex Parameter Binding Structure + ZDPT_INDEX, //Index Parameter Binding Structure + ZDPT_SIZE +}; + +class ZDrawParams +{ +public: + //Virtual Destructor + virtual ~ZDrawParams() { } + + /* + virtual public ZDrawParams::MarkResourcesContended + + Marks all resources bound in this draw parameters structure to be + contended by the renderer. + + @return (void) + @context (renderer) + */ + virtual void MarkResourcesContended() = 0; + + /* + virtual public ZDrawParams::ReleaseResourceContention + + Releases resource contention from the renderer. + + @return (void) + @context (renderer) + */ + virtual void ReleaseResourceContention() = 0; +}; + +#endif + diff --git a/Include/ZRenderer/ZFrameBufferRenderTarget.hpp b/Include/ZRenderer/ZFrameBufferRenderTarget.hpp new file mode 100644 index 0000000..dc9cce6 --- /dev/null +++ b/Include/ZRenderer/ZFrameBufferRenderTarget.hpp @@ -0,0 +1,138 @@ +/* + ZFramebufferRenderTarget.h + Author: James Russell + + Purpose: Interface which defines a FrameBuffer, which is a render target that contains + a set of Textures or RenderBuffers which can be used for off-screen rendering. + + Changelog + 2011/04/03 - creation (jcrussell) +*/ + +#pragma once + +#ifndef _ZFRAMEBUFFERRENDERTARGET_HPP +#define _ZFRAMEBUFFERRENDERTARGET_HPP + +#include + +#include +#include +#include + +//The maximum number of color buffers supported on a single frame buffer render target +#ifndef ZFBRT_MAX_COLOR_BUFFERS +#define ZFBRT_MAX_COLOR_BUFFERS (16) +#endif + +//Frame Buffer Render Target, used for off-screen rendering +class ZFramebufferRenderTarget : public ZRenderTarget +{ +public: + /* + public ZFramebufferRenderTarget::AttachColorBuffer + + Attach a texture to this frame buffer render target as a color buffer. All textures + set as color buffers must be of the same dimension, and their dimensions must match + that of GetWidth() and GetHeight(). + + @param _buffer - the texture to bind to this render target + @param _index - the index to bind this color buffer to + @return (bool) - true if able to attach buffer, false if resource contended + @context (all) + */ + virtual bool AttachColorTexture(ZPtr _texture, size_t _index) = 0; + + /* + virtual public ZFramebufferRenderTarget::AttachDepthTexture + + Attaches a texture to this frame buffer render target as a depth buffer. The texture + set as the depth buffer must be of the same dimension as the color buffers, and it's + dimension must match that of GetWidth() and GetHeight(). + + A frame buffer render target cannot have a texture attached as a depth buffer as well + as a render buffer attached for the same purpose. + + @param _texture - the texture to bind + @return (bool) - true if able to attach, false otherwise + @context (all) + */ + virtual bool AttachDepthTexture(ZPtr _texture) = 0; + + /* + virtual public ZFramebufferRenderTarget::AttachRenderBuffer + + Attaches a render buffer to this frame buffer render target. The type of attachment + is determined by render buffer type. + + A render buffer cannot be attached if another buffer is already attached that would + perform it's function, i.e., it is not possible to attach a depth buffer when a + depth texture is in place, and it is not possible to attach a stencil buffer + when a depth buffer is acting as depth and stencil buffer. + + @param _buffer - the render buffer to attach + @return (bool) - true if able to attach buffer, false if resource contended + @context (all) + */ + virtual bool AttachRenderBuffer(ZPtr _buffer) = 0; + + /* + virtual public ZFramebufferRenderTarget::IsComplete + + Checks to see if this FrameBuffer is in a 'complete' status and can be used. A + 'complete' frame buffer requires at least one color buffer (bound at index 0) and + one depth buffer, and the buffers should be bound by the graphics library to the + frame buffer object. + + @return (bool) - true if complete, false otherwise + @context (all) + */ + virtual bool IsComplete() = 0; + + /* + virtual public ZFramebufferRenderTarget::RemoveColorBuffers + + Removes the current set of color buffers attached to this frame buffer render target. + + @return (bool) - true if able to remove buffers, false if resource contended + @context (all) + */ + virtual bool RemoveColorBuffers() = 0; + + /* + virtual public ZFramebufferRenderTarget::RemoveDepthBuffer + + Removes the current set depth buffers attached to this frame buffer render target. + + @return (bool) - true if able to remove buffer, false if resource contended + @context (all) + */ + virtual bool RemoveDepthBuffer() = 0; + + /* + virtual public ZFramebufferRenderTarget::RemoveStencilBuffer + + Removes the current set stencil buffer attached to this frame buffer render target. + + @return (bool) - true if able to remove buffer, false if resource contended + @context (all) + */ + virtual bool RemoveStencilBuffer() = 0; + + //Not Implemented + virtual const ZRenderTargetClearFlags& GetClearFlags() = 0; + + //Not Implemented + virtual size_t GetHeight() = 0; + + //Not Implemented + virtual ZRenderTargetType GetType() = 0; + + //Not Implemented + virtual size_t GetWidth() = 0; + + //Not Implemented + virtual bool SetClearFlags(const ZRenderTargetClearFlags& _flags) = 0; +}; + +#endif \ No newline at end of file diff --git a/Include/ZRenderer/ZFrameBufferRenderTargetBase.hpp b/Include/ZRenderer/ZFrameBufferRenderTargetBase.hpp new file mode 100644 index 0000000..6ee98ba --- /dev/null +++ b/Include/ZRenderer/ZFrameBufferRenderTargetBase.hpp @@ -0,0 +1,150 @@ +/* + ZFramebufferRenderTargetBase.hpp + Author: James Russell + Created: 08/07/2011 + + Purpose: + + Base class implementation of the ZFramebufferRenderTarget interface. + + License: + + TODO +*/ + +#pragma once + +#ifndef _ZFRAMEBUFFERRENDERTARGETBASE_HPP +#define _ZFRAMEBUFFERRENDERTARGETBASE_HPP + +#include +#include +#include + +//Buffer Data Struct, used to indicate buffer state +struct ZFramebufferRenderTargetBufferState +{ + //Our set of attached Color Buffers + ZPtr ColorBuffers[ZFBRT_MAX_COLOR_BUFFERS]; + + //Our attached depth texture + ZPtr DepthTexture; + + //Our attached depth buffer + ZPtr DepthBuffer; + + //Our attached stencil buffer + ZPtr StencilBuffer; + + //Indicates we are in a usable state + bool bIsComplete; + + ZFramebufferRenderTargetBufferState() + : bIsComplete(false) { } +}; + +//Base class implementation of a frame buffer render target +class ZFramebufferRenderTargetBase : public ZFramebufferRenderTarget +{ +private: + DISABLE_COPY_AND_ASSIGN(ZFramebufferRenderTargetBase); + +protected: + //The 'clear' flags + ZRenderTargetClearFlags Flags; + + //Width of the FBRT + size_t Width; + + //Height of the FBRT + size_t Height; + + //Flag indicating state has changed + bool bIsDirty; + + //Buffer State for this frame buffer render target + ZFramebufferRenderTargetBufferState BufferState; + + /* + Constructor. + + @param _width - the width (in pixels / texels) of the FBRT + @param _height - the height (in pixels / texels) of the FBRT + */ + ZFramebufferRenderTargetBase(size_t _width, size_t _height); + +public: + //Virtual Destructor + virtual ~ZFramebufferRenderTargetBase() { } + + /* + public ZFramebufferRenderTargetBase::GetBufferState + + Gets the buffer state for this frame buffer render target. + + @return (ZFramebufferRenderTargetBufferState*) - the buffer state + @context (all) + */ + ZFramebufferRenderTargetBufferState* GetBufferState(); + + /* + public ZFramebufferRenderTargetBase::GetBufferStateResetDirty + + Gets the backing buffer state for this render target. This will return + NULL if the buffer state has not been modified since the last call to + this function, and in the case it has been modified, a call to this + resets the 'dirty' flag for the render target. + + @return (ZFramebufferRenderTargetBufferState*) - buffer state, NULL if not modified + @context (all) + */ + ZFramebufferRenderTargetBufferState* GetBufferStateResetDirty(); + + /*************************/ + /* ZRenderTarget Methods */ + /*************************/ + + //Subclass Implementation + virtual const ZRenderTargetClearFlags& GetClearFlags(); + + //Subclass Implementation + virtual size_t GetHeight(); + + //Subclass Implementation + virtual ZRenderTargetType GetType(); + + //Subclass Implementation + virtual size_t GetWidth(); + + //Subclass Implementation + virtual bool SetClearFlags(const ZRenderTargetClearFlags& _flags); + + /************************************/ + /* ZFramebufferRenderTarget Methods */ + /************************************/ + + //Subclass Implementation + virtual bool AttachColorTexture(ZPtr _texture, size_t _index); + + //Subclass Implementation + virtual bool AttachDepthTexture(ZPtr _texture); + + //Subclass Implementation + virtual bool AttachRenderBuffer(ZPtr _buffer); + + //Subclass Implementation + virtual bool IsComplete(); + + //Subclass Implementation + virtual bool RemoveColorBuffers(); + + //Subclass Implementation + virtual bool RemoveDepthBuffer(); + + //Subclass Implementation + virtual bool RemoveStencilBuffer(); + +}; + +#endif + diff --git a/Include/ZRenderer/ZIndexParams.hpp b/Include/ZRenderer/ZIndexParams.hpp new file mode 100644 index 0000000..6c11fe4 --- /dev/null +++ b/Include/ZRenderer/ZIndexParams.hpp @@ -0,0 +1,163 @@ +/* + ZIndexParams.hpp + Author: James Russell + Created: 7/1/2012 + + Purpose: + + TODO + + License: + + TODO + +*/ + +#pragma once + +#ifndef _ZINDEXPARAMS_HPP +#define _ZINDEXPARAMS_HPP + +#include + +#include + +#include + +#include + +typedef enum ZIndexPrimitiveType { + ZIPT_TRIANGLES, //Unrelated triangles, n/3 primitives are drawn + ZIPT_TRISTRIP, //Triangle Strip, n-2 primitives are drawn + ZIPT_LINES, //Unrelated lines, n/2 primitives are drawn + ZIPT_LINESTRIP, //Line Strip, n-1 primitives are drawn + ZIPT_POINTS, //Point list, n primitives are drawn +} ZIndexPrimitiveType; + +class ZIndexParams : public ZDrawParams +{ +private: + //This is the bound index buffer and block + ZPtr IndexBuffer; + ZPair Binding; + + ZIndexPrimitiveType primType; + size_t nrPrims; + size_t offset; + +public: + /* + Default Constructor. + */ + ZIndexParams(); + + /* + public ZIndexParams::ClearBlock + + Clears the current block definition and index buffer. + + @return (void) + @context (all) + */ + void ClearIndexBlock(); + + /* + public ZIndexParams::SetBlock + + Sets the index buffer and index block that will be being used. + + @param _indexBuffer - data buffer containing index data + @param _block - the index block + @return (void) + @context (all) + */ + void SetIndexBlock(ZPtr _indexBuffer, const ZDataBufferBlock* _block); + + /* + public ZIndexParams::SetPrimitiveDrawCount + + Sets the number of primitives that will be drawn. This is not the number + of indices used in total. For example, 300 indices with triangles will draw + 100 triangles, so the primitive draw count should be 100. + + The special value of '0' is interpreted as "draw as many as possible". + + @param count - The number of primitives + @return (void) + @context (all) + */ + void SetPrimitiveDrawCount(size_t _count) { nrPrims = _count; } + + /* + public ZIndexParams::GetPrimitiveDrawCount + + Gets the number of primitives that will be drawn. + + @return (size_t) - The number of primitives + @context (all) + */ + size_t GetPrimitiveDrawCount() const { return nrPrims; } + + /* + public ZIndexParams::SetDrawOffset + + Sets starting point for drawing, measured in whole indices (not bytes). For example, + if you had a stream that contained { 1, 3, 5, 7 } and you wanted to draw + starting at '3', then you would use an offset of 1 -- regardless of the + type of index (8, 16, 32-bit). + + @param _offset - The offset measured in whole indices + @return (void) + @context (all) + */ + void SetDrawOffset(size_t _offset) { offset = _offset; } + + /* + public ZIndexParams::GetDrawOffset + + Gets starting point for drawing, measured in whole indices (not bytes) + + @return (size_t) - The offset + @context (all) + */ + + size_t GetDrawOffset() const { return offset; } + + /* + public ZIndexParams::SetPrimitiveType + + Sets primitive type to draw. + + @param _type - The primitive type + @return (void) + @context (all) + */ + + void SetPrimitiveType(ZIndexPrimitiveType _type) { primType = _type; } + + /* + public ZIndexParams::GetPrimitiveType + + Gets the type of primitive being rendered + + @return (ZIndexPrimitiveType) - The primitive type + @context (all) + */ + ZIndexPrimitiveType GetPrimitiveType() { return primType; } + + /* + The following methods are used by the renderer to get the values needed when + binding shader parameter values to pass to the shader program, to mark + all bound resources as contended, and release contention. + */ + const ZPair* GetIndexBlock(); + ZDataBuffer* GetIndexBuffer(); + + //Subclass Override + virtual void MarkResourcesContended(); + + //Subclass Override + virtual void ReleaseResourceContention(); +}; + +#endif diff --git a/Include/ZRenderer/ZOpenGLDataBuffer.hpp b/Include/ZRenderer/ZOpenGLDataBuffer.hpp new file mode 100644 index 0000000..f7337d3 --- /dev/null +++ b/Include/ZRenderer/ZOpenGLDataBuffer.hpp @@ -0,0 +1,98 @@ +/* + ZOpenGLDataBuffer.hpp + Author: James Russell + Created: 3/20/2011 + + Purpose: + + OpenGL implementation of the ZDataBuffer interfaces. + + License: + + TODO +*/ + +#pragma once + +#ifndef _ZOPENGLDATABUFFER_HPP +#define _ZOPENGLDATABUFFER_HPP + +#include + +#include + +//Forward Declarations +class ZOpenGLRenderer; + +/* +OpenGL Data Buffer. +*/ +class ZOpenGLDataBuffer : public ZDataBufferBase +{ +protected: + //Renderer associated with this buffer + ZOpenGLRenderer *Renderer; + + //The current offset to use + size_t NextOffset; + + //Offset Alignment Requirement + static int OffsetAlignment; + + //Gets the buffer data from the graphics device as part of a thread request + static void GetDeviceData_( ZThread *_renderThread, void *_dataBuffer ); + + //Subclass Override + virtual void GetDeviceData(void* _buffer); + + //Subclass Override + virtual size_t GetNextBlockOffset(size_t _size); + + //Subclass Override + virtual void ResetBlockOffset(); + +public: + //OpenGL Handle to the Buffer + GLuint GLHandle; + + //Gets a GLenum based off of type + GLenum GetGLType() + { + switch (Type) + { + case ZDBT_UNIFORM: return GL_UNIFORM_BUFFER; + case ZDBT_VERTEX: return GL_ARRAY_BUFFER; + case ZDBT_INDEX: return GL_ELEMENT_ARRAY_BUFFER; + default: return GL_INVALID_ENUM; + } + } + + //Gets a GLenum based off of usage + GLenum GetGLUsage() + { + switch(Usage) + { + case ZDBU_STATIC: return GL_STATIC_DRAW; + case ZDBU_DYNAMIC: return GL_DYNAMIC_DRAW; + case ZDBU_STREAMING: return GL_STREAM_DRAW; + default: return GL_INVALID_ENUM; + } + } + + /* + Constructor. + + @param _renderer - the current renderer + @param _type - the type of buffer this is + @param _usage - the usage type of this buffer + @param _size - the size (in bytes) of the data buffer + */ + ZOpenGLDataBuffer(ZOpenGLRenderer *_renderer, ZDataBufferType _type, ZDataBufferUsage _usage, size_t _size); + + /* + Destructor. + */ + virtual ~ZOpenGLDataBuffer(); +}; + +#endif diff --git a/Include/ZRenderer/ZOpenGLDimensionTexture.hpp b/Include/ZRenderer/ZOpenGLDimensionTexture.hpp new file mode 100644 index 0000000..2e6a415 --- /dev/null +++ b/Include/ZRenderer/ZOpenGLDimensionTexture.hpp @@ -0,0 +1,262 @@ +/* + ZOpenGLDimensionTexture.hpp + Author: James Russell + Created: 7/1/2012 + + Purpose: + + OpenGL implementation of a 'dimensional' (1D, 2D, 3D) texture. + + License: + + TODO + +*/ + +#pragma once + +#ifndef _ZOPENGLDIMENSIONTEXTURE_HPP +#define _ZOPENGLDIMENSIONTEXTURE_HPP + +#include + +#include + +//Forward Declarations +class ZOpenGLRenderer; + +//OpenGL implementation of the two dimensional texture interface +class ZOpenGLDimensionTexture : public ZDimensionTextureBase +{ +private: + DISABLE_COPY_AND_ASSIGN(ZOpenGLDimensionTexture); + +protected: + //Gets the texture data from the graphics device as part of a thread request + static void GetDeviceData_( ZThread *_renderThread, void *_dataBuffer ); + + //Subclass Implementation + virtual void GetDeviceData(void* _buffer); + +public: + //Renderer associated with this texture + ZOpenGLRenderer *Renderer; + + //The OpenGL handle to the loaded texture + GLuint GLHandle; + + //Gets the OpenGL 'target' parameter for this texture type + GLenum GetGLTarget() + { + switch(Type) + { + case ZTT_TEXTURE1D: return GL_TEXTURE_1D; + case ZTT_TEXTURE2D: return GL_TEXTURE_2D; + case ZTT_TEXTURE3D: return GL_TEXTURE_3D; + case ZTT_TEXTURE_CUBE: /* Invalid Here */ + default: return GL_INVALID_ENUM; + } + } + + //Gets the OpenGL 'internalFormat' parameter for this texture format (used for glTexImage*D) + GLenum GetGLInternalFormat() + { + switch (Format) + { + case ZTF_R8: return GL_R8; + case ZTF_R8_SNORM: return GL_R8_SNORM; + case ZTF_R8I: return GL_R8I; + case ZTF_R8UI: return GL_R8UI; + case ZTF_R16: return GL_R16; + case ZTF_R16_SNORM: return GL_R16_SNORM; + case ZTF_R16I: return GL_R16I; + case ZTF_R16UI: return GL_R16UI; + case ZTF_R16F: return GL_R16F; + case ZTF_R32I: return GL_R32I; + case ZTF_R32UI: return GL_R32UI; + case ZTF_R32F: return GL_R32F; + + case ZTF_RG8: return GL_RG8; + case ZTF_RG8_SNORM: return GL_RG8_SNORM; + case ZTF_RG8I: return GL_RG8I; + case ZTF_RG8UI: return GL_RG8UI; + case ZTF_RG16: return GL_RG16; + case ZTF_RG16_SNORM: return GL_RG16_SNORM; + case ZTF_RG16I: return GL_RG16I; + case ZTF_RG16UI: return GL_RG16UI; + case ZTF_RG16F: return GL_RG16F; + case ZTF_RG32I: return GL_RG32I; + case ZTF_RG32UI: return GL_RG32UI; + case ZTF_RG32F: return GL_RG32F; + + case ZTF_RGB8: return GL_RGB8; + case ZTF_RGB8_SNORM: return GL_RGB8_SNORM; + case ZTF_RGB8I: return GL_RGB8I; + case ZTF_RGB8UI: return GL_RGB8UI; + case ZTF_RGB16: return GL_RGB16; + case ZTF_RGB16_SNORM: return GL_RGB16_SNORM; + case ZTF_RGB16I: return GL_RGB16I; + case ZTF_RGB16UI: return GL_RGB16UI; + case ZTF_RGB16F: return GL_RGB16F; + case ZTF_RGB32I: return GL_RGB32I; + case ZTF_RGB32UI: return GL_RGB32UI; + case ZTF_RGB32F: return GL_RGB32F; + + case ZTF_RGBA8: return GL_RGBA8; + case ZTF_RGBA8_SNORM: return GL_RGBA8_SNORM; + case ZTF_RGBA8I: return GL_RGBA8I; + case ZTF_RGBA8UI: return GL_RGBA8UI; + case ZTF_RGBA16: return GL_RGBA16; + case ZTF_RGBA16_SNORM: return GL_RGBA16_SNORM; + case ZTF_RGBA16I: return GL_RGBA16I; + case ZTF_RGBA16UI: return GL_RGBA16UI; + case ZTF_RGBA16F: return GL_RGBA16F; + case ZTF_RGBA32I: return GL_RGBA32I; + case ZTF_RGBA32UI: return GL_RGBA32UI; + case ZTF_RGBA32F: return GL_RGBA32F; + + case ZTF_DEPTH16: return GL_DEPTH_COMPONENT16; + case ZTF_DEPTH24: return GL_DEPTH_COMPONENT24; + case ZTF_DEPTH32: return GL_DEPTH_COMPONENT32; + case ZTF_DEPTH24_STENCIL8: return GL_DEPTH24_STENCIL8; + + default: return GL_INVALID_ENUM; + } + } + + //Gets the OpenGL 'format' parameter for this texture's bitmap format (used for glTexImage*D) + GLenum GetGLFormat() + { + switch (Bitmap.GetFormat()) + { + case ZBF_R8: + case ZBF_R8I: + case ZBF_R16: + case ZBF_R16I: + case ZBF_R32: + case ZBF_R32I: + case ZBF_R32F: return GL_RED; + + case ZBF_RG8: + case ZBF_RG8I: + case ZBF_RG16: + case ZBF_RG16I: + case ZBF_RG32: + case ZBF_RG32I: + case ZBF_RG32F: return GL_RG; + + case ZBF_RGB8: + case ZBF_RGB8I: + case ZBF_RGB16: + case ZBF_RGB16I: + case ZBF_RGB32: + case ZBF_RGB32I: + case ZBF_RGB32F: return GL_RGB; + + case ZBF_RGBA8: + case ZBF_RGBA8I: + case ZBF_RGBA16: + case ZBF_RGBA16I: + case ZBF_RGBA32: + case ZBF_RGBA32I: + case ZBF_RGBA32F: return GL_RGBA; + + case ZBF_BGR8: + case ZBF_BGR8I: + case ZBF_BGR16: + case ZBF_BGR16I: + case ZBF_BGR32: + case ZBF_BGR32I: + case ZBF_BGR32F: return GL_BGR; + + case ZBF_BGRA8: + case ZBF_BGRA8I: + case ZBF_BGRA16: + case ZBF_BGRA16I: + case ZBF_BGRA32: + case ZBF_BGRA32I: + case ZBF_BGRA32F: return GL_BGRA; + + case ZBF_DEPTH32: return GL_DEPTH_COMPONENT; + + default: return GL_INVALID_ENUM; + } + } + + //Gets the OpenGL 'type' parameter for this texture's bitmap format (used for glTexImage*D calls) + GLenum GetGLType() + { + switch (Bitmap.GetFormat()) + { + case ZBF_R8: + case ZBF_RG8: + case ZBF_RGB8: + case ZBF_RGBA8: + case ZBF_BGR8: + case ZBF_BGRA8: return GL_UNSIGNED_BYTE; + + case ZBF_R8I: + case ZBF_RG8I: + case ZBF_RGB8I: + case ZBF_RGBA8I: + case ZBF_BGR8I: + case ZBF_BGRA8I: return GL_BYTE; + + case ZBF_R16: + case ZBF_RG16: + case ZBF_RGB16: + case ZBF_RGBA16: + case ZBF_BGR16: + case ZBF_BGRA16: return GL_UNSIGNED_SHORT; + + case ZBF_R16I: + case ZBF_RG16I: + case ZBF_RGB16I: + case ZBF_RGBA16I: + case ZBF_BGR16I: + case ZBF_BGRA16I: return GL_SHORT; + + case ZBF_R32: + case ZBF_RG32: + case ZBF_RGB32: + case ZBF_RGBA32: + case ZBF_BGR32: + case ZBF_BGRA32: return GL_UNSIGNED_INT; + + case ZBF_R32I: + case ZBF_RG32I: + case ZBF_RGB32I: + case ZBF_RGBA32I: + case ZBF_BGR32I: + case ZBF_BGRA32I: return GL_INT; + + case ZBF_R32F: + case ZBF_RG32F: + case ZBF_RGB32F: + case ZBF_RGBA32F: + case ZBF_BGR32F: + case ZBF_BGRA32F: return GL_FLOAT; + + case ZBF_DEPTH32: return GL_UNSIGNED_INT; + + default: return GL_INVALID_ENUM; + } + } + + /* + Constructor. + + @param _renderer - the current renderer instance + @param _type - the type of texture + @param _format - the format of the texture + @param _usage - the usage type of texture + @param _bitmap - the bitmap for this texture (or side, in case of cube map) + @param _generateMipmaps - flag indicating we should generate mipmaps + */ + ZOpenGLDimensionTexture(ZOpenGLRenderer* _renderer, ZTextureType _type, ZTextureFormat _format, ZTextureUsage _usage, const ZBitmap& _bitmap, bool _generateMipmaps); + + //Virtual destructor + virtual ~ZOpenGLDimensionTexture(); +}; + +#endif diff --git a/Include/ZRenderer/ZOpenGLFrameBufferRenderTarget.hpp b/Include/ZRenderer/ZOpenGLFrameBufferRenderTarget.hpp new file mode 100644 index 0000000..4c5e310 --- /dev/null +++ b/Include/ZRenderer/ZOpenGLFrameBufferRenderTarget.hpp @@ -0,0 +1,53 @@ +/* + ZOpenGLFrameBufferRenderTarget.hpp + Author: James Russell + Created: 07/24/2011 + + Purpose: + + OpenGL implementation of the ZFramebufferRenderTargetBase class. + + License: + + TODO +*/ + +#pragma once + +#ifndef _ZOPENGLFRAMEBUFFERRENDERTARGET_HPP +#define _ZOPENGLFRAMEBUFFERRENDERTARGET_HPP + +//Forward Declarations +class ZOpenGLRenderer; + +#include + +#include + +class ZOpenGLFramebufferRenderTarget : public ZFramebufferRenderTargetBase +{ +protected: + //Renderer Instance + ZOpenGLRenderer* Renderer; + +public: + //The OpenGL handle to the FBO + GLuint GLHandle; + + /* + Constructor. + + @param _renderer - the current renderer + @param _width - the width this frame buffer render target be be + @param _height - the height this frame buffer render target will be + */ + ZOpenGLFramebufferRenderTarget(ZOpenGLRenderer *_renderer, size_t _width, size_t _height); + + /* + Destructor. + */ + ~ZOpenGLFramebufferRenderTarget(); +}; + +#endif + diff --git a/Include/ZRenderer/ZOpenGLRenderBuffer.hpp b/Include/ZRenderer/ZOpenGLRenderBuffer.hpp new file mode 100644 index 0000000..3f943c3 --- /dev/null +++ b/Include/ZRenderer/ZOpenGLRenderBuffer.hpp @@ -0,0 +1,84 @@ +/* + ZOpenGLRenderBuffer.hpp + Author: Chris Ertel , + James Russell + + Purpose: + + Implementation of the render buffer interface for OpenGL renderers. + + License: + + TODO +*/ + +#pragma once + +#ifndef _ZOPENGLRENDERBUFFER_HPP +#define _ZOPENGLRENDERBUFFER_HPP + +//Forward Declaration +class ZOpenGLRenderer; + +#include + +#include + +class ZOpenGLRenderBuffer : public ZRenderBuffer +{ +protected: + //Renderer Instance + ZOpenGLRenderer* Renderer; + + //The type of render buffer + ZRenderBufferType Type; + + //Width of the render buffer + size_t Width; + + //Height of the render buffer + size_t Height; + + +public: + //Gets the GL storage type + inline GLenum GetGLType() + { + switch(Type) + { + case ZRBT_DEPTH16: return GL_DEPTH_COMPONENT16; + case ZRBT_DEPTH24: return GL_DEPTH_COMPONENT24; + case ZRBT_DEPTH32: return GL_DEPTH_COMPONENT32; + case ZRBT_STENCIL8: return GL_STENCIL_INDEX8; + case ZRBT_DEPTH24_STENCIL8: return GL_DEPTH24_STENCIL8; + default: return GL_INVALID_ENUM; + } + } + + //The OpenGL handle to the render buffer + GLuint GLHandle; + + /* + Constructor. + + @param _renderer - the current renderer instance + @param _type - the type of render buffer this will be + @param _width - with of the render buffer + @param _height - height of the render buffer + */ + ZOpenGLRenderBuffer( ZOpenGLRenderer *_renderer, ZRenderBufferType _type, size_t _width, size_t _height); + + //Destructor + virtual ~ZOpenGLRenderBuffer(); + + //Subclass Implementation + virtual size_t GetHeight(); + + //Subclass Implementation + virtual ZRenderBufferType GetType(); + + //Subclass Implementation + virtual size_t GetWidth(); +}; + +#endif \ No newline at end of file diff --git a/Include/ZRenderer/ZOpenGLRenderer.hpp b/Include/ZRenderer/ZOpenGLRenderer.hpp new file mode 100644 index 0000000..f48f22d --- /dev/null +++ b/Include/ZRenderer/ZOpenGLRenderer.hpp @@ -0,0 +1,197 @@ +/* + ZOpenGLRenderer.hpp + Author: James Russell + Created: 3/27/2011 + + Purpose: + + OpenGL implementation of the Renderer. Currently requires OpenGL 3.3. + + License: + + TODO +*/ + +#pragma once + +#ifndef _ZOPENGLRENDERER_HPP +#define _ZOPENGLRENDERER_HPP + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//CHECKGL function, which checks for OpenGL Error conditions and asserts when they are found +void CheckGL(); + +//CHECKGL macro for debug mode +#if ZRENDERER_CHECKGL + #define CHECKGL() (CheckGL()) +#else + #define CHECKGL() +#endif + +//Enumeration for various OpenGL resource types +enum ZOpenGLResourceType +{ + ZOGLRT_BUFFER, //OpenGL Buffer Object + ZOGLRT_SHADER, //OpenGL Shader Object + ZOGLRT_SHADER_PROGRAM, //OpenGL Shader Program Object + ZOGLRT_TEXTURE, //OpenGL Texture Object + ZOGLRT_SAMPLER, //OpenGL Sampler Object + ZOGLRT_FRAME_BUFFER, //OpenGL Frame Buffer Object + ZOGLRT_RENDER_BUFFER, //OpenGL Render Buffer Object + ZOGLRT_VERTEX_ARRAY, //OpenGL Vertex Array Object + ZOGLRT_SIZE +}; + +/* +OpenGL Renderer implementation class. +*/ +class ZOpenGLRenderer : public ZRendererBase +{ +private: + DISABLE_COPY_AND_ASSIGN(ZOpenGLRenderer); + + //Resource Generation Thread Request + class ResourceGenerationThreadRequest : public ZThreadRequest + { + public: + //Default Constructor + ResourceGenerationThreadRequest() : ZThreadRequest(true) { } + + //Concurrency control lock for resource generation and cleanup + ZMutex ResourceMutex; + + //Indicator that we have a pending resource request + bool bPendingResourceRequest; + + //Resource Generation Requests + ZArray< ZPtr > DataBufferGenerateRequests; + ZArray< ZPtr > ShaderGenerateRequests; + ZArray< ZPtr > ShaderProgramGenerateRequests; + ZArray< ZPtr > DimensionTextureGenerateRequests; + ZArray > SamplerGenerateRequests; + ZArray< ZPtr > FrameBufferGenerateRequests; + ZArray< ZPtr > RenderBufferGenerateRequests; + ZArray< ZPtr > VertexParamsGenerateRequests; + + //Resource Delete Requests + ZArray< ZPair > ResourceDeleteRequests; + + //Subclass Implementation + virtual void Execute( ZThread *_threadObj ); + }; + +protected: + //The initialization window + SST_Window InitializationWindow; + + //The OpenGL Context for this renderer + SST_OpenGLContext GLContext; + + //Indicates we own the GLContext + bool bOwnsContext; + + //The Current Render State + ZRenderState *CurrentRenderState; + + //Resource Request Object + ZPtr ResourceThreadRequest; + + //Subclass Override + virtual bool init(); + + //Subclass Override + virtual void initThread(); + + //Subclass Override + virtual void shutdown(); + + //Subclass Override + virtual void shutdownThread(); + + //Subclass Override + virtual void Draw(ZArray >& _renderList, + ZRenderTarget* _renderTarget); + +public: + /* + Constructor. + + Initializes this renderer with the given OpenGL context. + + The provided window handle is only used for binding to a window so that OpenGL values can be obtained. In order + to render to the provided window, a ZWindowRenderTarget will need to be created using that window handle after + the renderer has finished initializing. + + @param _glContext - the OpenGL context to initialize this renderer with + @param _window - window to initialize this renderer with + @param _ownContext - indicates whether this renderer 'owns' the context and should clean up when destructed + */ + ZOpenGLRenderer(SST_OpenGLContext _glContext, SST_Window _window, bool _ownContext); + + /* + Destructor. + */ + ~ZOpenGLRenderer(); + + /* + public ZOpenGLRenderer::DeleteResource + + This will ask the renderer thread to clean up a previously generated OpenGL resource. + + @param _type - the type of resource + @param _handle - the handle to the resource + @return (void) + @context (all) + */ + void DeleteResource(ZOpenGLResourceType _type, GLuint _handle); + + ////////////////////////// + /* Logistics Operations */ + ////////////////////////// + + //Subclass Override + virtual ZPtr CreateDataBuffer(ZDataBufferType _type, + ZDataBufferUsage _usage, + size_t _size); + + //Subclass Override + virtual ZPtr CreateDrawParams(ZDrawParamsType _type); + + //Subclass Override + virtual ZPtr CreateFrameBufferRenderTarget(size_t _width, size_t _height); + + //Subclass Override + virtual ZPtr CreateRenderBuffer(ZRenderBufferType _type, size_t _width, size_t _height); + + //Subclass Override + virtual ZPtr CreateSampler(); + + //Subclass Override + virtual ZPtr CreateShader(ZShaderType _type); + + //Subclass Override + virtual ZPtr CreateShaderProgram(); + + //Subclass Override + virtual ZPtr CreateTexture(ZTextureType _type, ZTextureFormat _format, ZTextureUsage _usage, const ZBitmap& _bitmap, bool _generateMipmaps); + + //Subclass Override + virtual ZPtr CreateWindowRenderTarget(SST_Window _window, + size_t _screenIndex); +}; + +#endif diff --git a/Include/ZRenderer/ZOpenGLSampler.hpp b/Include/ZRenderer/ZOpenGLSampler.hpp new file mode 100644 index 0000000..3c569c9 --- /dev/null +++ b/Include/ZRenderer/ZOpenGLSampler.hpp @@ -0,0 +1,162 @@ +/* + ZOpenGLSampler.hpp + Author: James Russell , + Chris Ertel + Created: 7/1/2012 + + Purpose: + + OpenGL implementation of the ZSampler interface class. + + License: + + TODO + +*/ + +#pragma once + +#ifndef _ZOPENGLSAMPLER_HPP +#define _ZOPENGLSAMPLER_HPP + +#include + +#include + +#include + +//Forward Declarations +class ZOpenGLRenderer; + +struct ZOpenGLSamplerState +{ + GLenum SWrapMode; //Wrapping mode for S + GLenum TWrapMode; //Wrapping mode for T (unused for 1D) + GLenum RWrapMode; //Wrapping mode for R (unused for 1D, 2D) + + GLenum MinFilter; //Minification Filter (including mip filter) + GLenum MagFilter; //Magnification Filter + + float MaxAnisotropy; //Maximum Anisotropy (< 2.0 has no effect) + float MinLOD; //Minimum LOD + float MaxLOD; //Maximum LOD + float LODBias; //LOD Bias + + float BorderColor[4]; //RGBA Border Color + + GLenum CompareMode; //Sampler Comparison Mode + GLenum CompareFunc; //Sampler Comparison Function +}; + +//OpenGL implementation of the ZSampler interface class +class ZOpenGLSampler : public ZSamplerBase +{ +private: + DISABLE_COPY_AND_ASSIGN(ZOpenGLSampler); + +protected: + //The current renderer + ZOpenGLRenderer* Renderer; + + //Sampler State + ZOpenGLSamplerState OpenGLSamplerState; + +public: + //OpenGL Handle for the Sampler object + GLuint GLHandle; + + //Gets the OpenGL Sampler State + const ZOpenGLSamplerState& GetGLSamplerState() + { + switch (State.SWrapMode) + { + case ZSWM_CLAMP_EDGE: OpenGLSamplerState.SWrapMode = GL_CLAMP_TO_EDGE; break; + case ZSWM_CLAMP_BORDER: OpenGLSamplerState.SWrapMode = GL_CLAMP_TO_BORDER; break; + case ZSWM_MIRROR_REPEAT: OpenGLSamplerState.SWrapMode = GL_MIRRORED_REPEAT; break; + case ZSWM_REPEAT: OpenGLSamplerState.SWrapMode = GL_REPEAT; break; + default: OpenGLSamplerState.SWrapMode = GL_INVALID_ENUM; break; + } + + switch (State.TWrapMode) + { + case ZSWM_CLAMP_EDGE: OpenGLSamplerState.TWrapMode = GL_CLAMP_TO_EDGE; break; + case ZSWM_CLAMP_BORDER: OpenGLSamplerState.TWrapMode = GL_CLAMP_TO_BORDER; break; + case ZSWM_MIRROR_REPEAT: OpenGLSamplerState.TWrapMode = GL_MIRRORED_REPEAT; break; + case ZSWM_REPEAT: OpenGLSamplerState.TWrapMode = GL_REPEAT; break; + default: OpenGLSamplerState.TWrapMode = GL_INVALID_ENUM; break; + } + + switch (State.RWrapMode) + { + case ZSWM_CLAMP_EDGE: OpenGLSamplerState.RWrapMode = GL_CLAMP_TO_EDGE; break; + case ZSWM_CLAMP_BORDER: OpenGLSamplerState.RWrapMode = GL_CLAMP_TO_BORDER; break; + case ZSWM_MIRROR_REPEAT: OpenGLSamplerState.RWrapMode = GL_MIRRORED_REPEAT; break; + case ZSWM_REPEAT: OpenGLSamplerState.RWrapMode = GL_REPEAT; break; + default: OpenGLSamplerState.RWrapMode = GL_INVALID_ENUM; break; + } + + switch(State.MagFilter) + { + case ZSMAGF_NEAREST: OpenGLSamplerState.MagFilter = GL_NEAREST; break; + case ZSMAGF_LINEAR: OpenGLSamplerState.MagFilter = GL_LINEAR; break; + default: OpenGLSamplerState.MagFilter = GL_INVALID_ENUM; break; + } + + switch(State.MinFilter) + { + case ZSMINF_NEAREST: OpenGLSamplerState.MinFilter = GL_NEAREST; break; + case ZSMINF_NEAREST_MIP_NEAREST: OpenGLSamplerState.MinFilter = GL_NEAREST_MIPMAP_NEAREST; break; + case ZSMINF_NEAREST_MIP_LINEAR: OpenGLSamplerState.MinFilter = GL_NEAREST_MIPMAP_LINEAR; break; + case ZSMINF_LINEAR: OpenGLSamplerState.MinFilter = GL_LINEAR; break; + case ZSMINF_LINEAR_MIP_NEAREST: OpenGLSamplerState.MinFilter = GL_LINEAR_MIPMAP_NEAREST; break; + case ZSMINF_LINEAR_MIP_LINEAR: OpenGLSamplerState.MinFilter = GL_LINEAR_MIPMAP_LINEAR; break; + default: OpenGLSamplerState.MinFilter = GL_INVALID_ENUM; break; + } + + OpenGLSamplerState.MaxAnisotropy = State.MaxAnisotropy; + OpenGLSamplerState.MinLOD = State.MinLOD; + OpenGLSamplerState.MaxLOD = State.MaxLOD; + OpenGLSamplerState.LODBias = State.LODBias; + + OpenGLSamplerState.BorderColor[0] = State.BorderColor[0]; + OpenGLSamplerState.BorderColor[1] = State.BorderColor[1]; + OpenGLSamplerState.BorderColor[2] = State.BorderColor[2]; + OpenGLSamplerState.BorderColor[3] = State.BorderColor[3]; + + switch(State.CompareMode) + { + case ZSCM_NONE: OpenGLSamplerState.CompareMode = GL_NONE; break; + case ZSCM_COMPARE_REF_TO_TEXTURE: OpenGLSamplerState.CompareMode = GL_COMPARE_REF_TO_TEXTURE; break; + default: OpenGLSamplerState.CompareMode = GL_INVALID_ENUM; break; + } + + switch(State.CompareFunc) + { + case ZSCF_NEVER: OpenGLSamplerState.CompareFunc = GL_NEVER; break; + case ZSCF_ALWAYS: OpenGLSamplerState.CompareFunc = GL_ALWAYS; break; + case ZSCF_EQUAL: OpenGLSamplerState.CompareFunc = GL_EQUAL; break; + case ZSCF_NOT_EQUAL: OpenGLSamplerState.CompareFunc = GL_NOTEQUAL; break; + case ZSCF_LESS: OpenGLSamplerState.CompareFunc = GL_LESS; break; + case ZSCF_LESS_EQUAL: OpenGLSamplerState.CompareFunc = GL_LEQUAL; break; + case ZSCF_GREATER: OpenGLSamplerState.CompareFunc = GL_GREATER; break; + case ZSCF_GREATER_EQUAL: OpenGLSamplerState.CompareFunc = GL_GEQUAL; break; + default: OpenGLSamplerState.CompareFunc = GL_INVALID_ENUM; break; + } + + return OpenGLSamplerState; + } + + /* + Default Constructor. + */ + ZOpenGLSampler(ZOpenGLRenderer* _renderer); + + /* + Destructor. + */ + ~ZOpenGLSampler(); +}; + + +#endif + diff --git a/Include/ZRenderer/ZOpenGLShader.hpp b/Include/ZRenderer/ZOpenGLShader.hpp new file mode 100644 index 0000000..26f9b07 --- /dev/null +++ b/Include/ZRenderer/ZOpenGLShader.hpp @@ -0,0 +1,66 @@ +/* + ZOpenGLShader.hpp + Author: Chris Ertel , + James Russell + Created: 04/20/2011 + + Purpose: + + OpenGL implementation of the shader interface. + + License: + + TODO +*/ + +#pragma once + +#ifndef _ZOPENGLSHADER_HPP +#define _ZOPENGLSHADER_HPP + +#include + +#include + +#include + +//Forward Declarations +class ZOpenGLRenderer; + +/* +OpenGL Shader Implementation. +*/ +class ZOpenGLShader : public ZShaderBase +{ +private: + DISABLE_COPY_AND_ASSIGN(ZOpenGLShader); + +protected: + //The renderer that created us + ZOpenGLRenderer* Renderer; + + //Method used to compile the shader + static void Compile_(ZThread* _thread, void* _shader); + +public: + //OpenGL Shader Handle + GLuint GLHandle; + + /* + Constructor. + + @param _renderer - the current renderer instance + @param _type - the type of shader + */ + ZOpenGLShader(ZOpenGLRenderer* _renderer, ZShaderType _type); + + /* + Destructor. + */ + virtual ~ZOpenGLShader(); + + //Subclass Override + virtual bool Compile(); +}; + +#endif diff --git a/Include/ZRenderer/ZOpenGLShaderProgram.hpp b/Include/ZRenderer/ZOpenGLShaderProgram.hpp new file mode 100644 index 0000000..4cd6592 --- /dev/null +++ b/Include/ZRenderer/ZOpenGLShaderProgram.hpp @@ -0,0 +1,69 @@ +/* + ZOpenGLShaderProgram.h + Author: Chris Ertel , + James Russell + Created: 04/03/2011 + + Purpose: + + TODO + + License: + + TODO +*/ + +#pragma once + +#ifndef _ZOPENGLSHADERPROGRAM_HPP +#define _ZOPENGLSHADERPROGRAM_HPP + +#include +#include + +#include + +//Forward Declarations +class ZOpenGLRenderer; + +//Struct we use to track opengl handles for uniform blocks and block members +struct ZOpenGLUniformBlockData +{ + GLuint BlockIndex; //OpenGL Index for UniformBlocks[i] + ZArray MemberIndices; //OpenGL Index for UniformBlocks[i].Members[i] +}; + +//OpenGL Implementation of ZShaderProgram +class ZOpenGLShaderProgram : public ZShaderProgramBase +{ +protected: + //Parent renderer + ZOpenGLRenderer* Renderer; + + //Static method used to link a shader program + static void Link_(ZThread* _thread, void* _shaderProgram); + +public: + //Handle to the program in OpenGL + GLuint GLHandle; + + //Our set of uniform indices, sampler indices, and stream indices + ZArray OpenGLUniformBlockData; + ZArray OpenGLSamplerData; + ZArray OpenGLStreamData; + + /* + Constructor. + + @param _renderer - the current renderer + */ + ZOpenGLShaderProgram(ZOpenGLRenderer* _renderer); + + //Virtual destructor + virtual ~ZOpenGLShaderProgram(); + + //Subclass Implementation + virtual bool Link(); +}; + +#endif \ No newline at end of file diff --git a/Include/ZRenderer/ZOpenGLTextureRenderTarget.h b/Include/ZRenderer/ZOpenGLTextureRenderTarget.h new file mode 100644 index 0000000..d1cd27c --- /dev/null +++ b/Include/ZRenderer/ZOpenGLTextureRenderTarget.h @@ -0,0 +1,92 @@ +/* + ZOpenGLTextureRenderTarget.h + Author: Chris Ertel (cre1) + + Purpose: TODO + + Changelog + 2011/05/22 - creation (cre1) +*/ + +#pragma once + +#ifndef _ZOPENGLTEXTURERENDERTARGET_H +#define _ZOPENGLTEXTURERENDERTARGET_H + +#include +#include +#include + +class ZOpenGLTexture; +class ZOpenGLTextureRenderTarget; + +class ZOpenGLTextureRenderTargetLoadRequest : public ZThreadRequest +{ +private: + ZOpenGLTextureRenderTarget *Target; + +public: + ZOpenGLTextureRenderTargetLoadRequest(ZOpenGLTextureRenderTarget *_target); + + void Execute(ZThread *_renderer); +}; + +class ZOpenGLTextureRenderTarget : public ZTextureRenderTarget +{ +friend class ZOpenGLTextureRenderTargetLoadRequest; +protected: + //The OpenGL Texture +// ZOpenGLTexture Tex; + + //The glhandle to the FrameBuffer + GLuint FrameBufferHandle; + + //The glhandle to the RenderBuffer + GLuint RenderBufferHandle; + float ClearColor[4]; + + int Width; + int Height; + int BPP; + +public: + //Default Constructor + ZOpenGLTextureRenderTarget(ZOpenGLRenderer *_renderer, int _width, int _height, int _bpp, int _rgbaSize, float *_clearColor = NULL); + + //Subclass Implementation + bool Activate(); + + //Subclass Implementation + void Deactivate(); + + void SetClearColor(float r, float g, float b, float a); + + void SetClearColor(float* _in); + + //Subclass Implementation (Currently Non-Functional) + void SetDimensions(int _width, int _height) + { + URFP(_width); + URFP(_height); + } + + //Subclass Implementation (Currently Non-Functional) + void SetBitsPerPixel(int _bbp) + { + URFP(_bbp); + } + + //Subclass Implementation (Currently Non-Functional) + void SetRGBASize(int _rgbaSize) + { + URFP(_rgbaSize); + } + + //Gets the render target as a texture + ZTexture* GetTexture(); + + //Gets the texture as a render target + ZRenderTarget* GetRenderTarget(); +}; + +#endif diff --git a/Include/ZRenderer/ZOpenGLVertexParams.hpp b/Include/ZRenderer/ZOpenGLVertexParams.hpp new file mode 100644 index 0000000..e58319b --- /dev/null +++ b/Include/ZRenderer/ZOpenGLVertexParams.hpp @@ -0,0 +1,46 @@ +/* + ZOpenGLVertexParams.hpp + Author: Patrick Baggett + Created: 12/13/2012 + + Purpose: + + OpenGL specific version of ZVertexParams that implements VAOs. + + License: + + TODO + +*/ + +#pragma once + +#ifndef _ZOPENGLVERTEXPARAMS_HPP +#define _ZOPENGLVERTEXPARAMS_HPP + +#include +#include +#include + + +class ZOpenGLRenderer; + +class ZOpenGLVertexParams : public ZVertexParams +{ + public: + ZOpenGLVertexParams(ZOpenGLRenderer* renderer) : + Renderer(renderer), vaoHandle(0), arrayBufferBound(0), elementBufferBound(0) + { + } + + ~ZOpenGLVertexParams(); + + void UpdateDirty(ZOpenGLShaderProgram* prgm); + + ZOpenGLRenderer* Renderer; + GLuint vaoHandle; //Vertex Array Object (VAO) handle + GLuint arrayBufferBound; //VBO (GL_ARRAY_BUFFER) that was bound + GLuint elementBufferBound; //VBO (GL_ELEMENT_BUFFER) that was bound +}; + +#endif \ No newline at end of file diff --git a/Include/ZRenderer/ZOpenGLWindowRenderTarget.hpp b/Include/ZRenderer/ZOpenGLWindowRenderTarget.hpp new file mode 100644 index 0000000..84280d0 --- /dev/null +++ b/Include/ZRenderer/ZOpenGLWindowRenderTarget.hpp @@ -0,0 +1,60 @@ +/* + ZOpenGLWindowRenderTarget.hpp + Author: James Russell + Created: 04/01/2011 + + Purpose: + + Initializes and manages an OpenGL window. + + License: + + TODO +*/ + +#pragma once + +#ifndef _ZOPENGLWINDOWRENDERTARGET_HPP +#define _ZOPENGLWINDOWRENDERTARGET_HPP + +#include + +//Forward Declarations +class ZOpenGLRenderer; + +/* +Screen Render Target for the OpenGL library. +*/ +class ZOpenGLWindowRenderTarget : public ZWindowRenderTargetBase +{ +private: + DISABLE_COPY_AND_ASSIGN(ZOpenGLWindowRenderTarget); + +protected: + //Renderer Instance + ZOpenGLRenderer *Renderer; + +public: + //OpenGL Context + SST_OpenGLContext GLContext; + + /* + Parameterized Constructor. + + @param _renderer - the renderer instance + @param _glContext - the OpenGL context to bind to this window + @param _window - the window instance (created with libsst-wm) + @param _screen - the screen index chosen + */ + ZOpenGLWindowRenderTarget(ZOpenGLRenderer* _renderer, SST_OpenGLContext _glContext, SST_Window _window, size_t _screenIndex); + + /* + Destructor. + */ + ~ZOpenGLWindowRenderTarget(); + + //Subclass Override + virtual bool SwapBuffers(); +}; + +#endif diff --git a/Include/ZRenderer/ZRenderBuffer.hpp b/Include/ZRenderer/ZRenderBuffer.hpp new file mode 100644 index 0000000..3b35062 --- /dev/null +++ b/Include/ZRenderer/ZRenderBuffer.hpp @@ -0,0 +1,71 @@ +/* + ZRenderBuffer.hpp + Author: James Russell + Created: 04/03/2011 + + Purpose: + + Buffer that can be used for depth and stencil buffers in frame buffer render targets + for off-screen rendering. + + License: + + TODO +*/ + +#pragma once + +#ifndef _ZRENDERBUFFER_HPP +#define _ZRENDERBUFFER_HPP + +#include + +//Enumeration of render buffer type +enum ZRenderBufferType +{ + ZRBT_DEPTH16, //16-bit Depth Storage + ZRBT_DEPTH24, //24-bit Depth Storage + ZRBT_DEPTH32, //32-bit Depth Storage + ZRBT_STENCIL8, //8-bit Stencil Storage + ZRBT_DEPTH24_STENCIL8, //24-bit Depth and 8-bit Stencil + ZRBT_SIZE +}; + +class ZRenderBuffer +{ +public: + //Virtual Destructor + virtual ~ZRenderBuffer() { } + + /* + public ZRenderBuffer::GetHeight + + Gets the height value for the render buffer (in pixels). + + @return (size_t) - height value + @context (all) + */ + virtual size_t GetHeight() = 0; + + /* + virtual public ZRenderBuffer::GetType + + Gets the type of render buffer this is set up to be (depth or stencil). + + @return (ZRenderBufferType) - the type of render buffer + @context (all) + */ + virtual ZRenderBufferType GetType() = 0; + + /* + public ZRenderBuffer::GetWidth + + Gets the width value for the render buffer (in pixels). + + @return (size_t) - width value + @context (all) + */ + virtual size_t GetWidth() = 0; +}; + +#endif \ No newline at end of file diff --git a/Include/ZRenderer/ZRenderTarget.hpp b/Include/ZRenderer/ZRenderTarget.hpp new file mode 100644 index 0000000..d8310e3 --- /dev/null +++ b/Include/ZRenderer/ZRenderTarget.hpp @@ -0,0 +1,114 @@ +/* + ZRenderTarget.hpp + Author: James Russell + Created: 03/20/2011 + + Purpose: + + Defines an interface for a rendering surface. + + License: + + TODO +*/ + +#pragma once + +#ifndef _ZRENDERTARGET_HPP +#define _ZRENDERTARGET_HPP + +#include +#include + +//Enumeration of possible render target types +enum ZRenderTargetType +{ + ZRTT_WINDOW, //Used for window render targets + ZRTT_FRAMEBUFFER, //Used for frame buffer render targets + ZRTT_SIZE +}; + +//Used to flag which buffers should be cleared, and to what value +struct ZRenderTargetClearFlags +{ + bool AutoClear; //Indicates that the renderer should 'clear' the toggled buffers before rendering to this target + + bool ClearColorBuffer; //Indicates we should clear the color buffer + bool ClearDepthBuffer; //Indicates we should clear the depth buffer + bool ClearStencilBuffer; //Indicates we should clear the stencil buffer + + float ClearColor[4]; //RGBA clear color to use + + //Default Constructor + ZRenderTargetClearFlags() + : AutoClear(true), ClearColorBuffer(true), ClearDepthBuffer(true), ClearStencilBuffer(false) + { + ClearColor[0] = 0.0f; + ClearColor[1] = 0.0f; + ClearColor[2] = 0.0f; + ClearColor[3] = 1.0f; + } +}; + +/* +RenderTarget Interface. +*/ +class ZRenderTarget : public ZRendererResource +{ +public: + //Virtual Destructor + virtual ~ZRenderTarget() { } + + /* + public ZRenderTarget::GetClearFlags + + Gets the current set of clear flags for this render target. + + @return (const ZRenderTargetClearFlags&) - clearing flags for this render target + @context (all) + */ + virtual const ZRenderTargetClearFlags& GetClearFlags() = 0; + + /* + public ZRenderTarget::GetHeight + + Gets the height value for the render target (in pixels). + + @return (size_t) + @context (all) + */ + virtual size_t GetHeight() = 0; + + /* + public ZRenderTarget::GetType + + Gets the type of render target. + + @return (ZRenderTargetType) - the type of render target + @context (all) + */ + virtual ZRenderTargetType GetType() = 0; + + /* + public ZRenderTarget::GetWidth + + Gets the width value for the render target (in pixels). + + @return (size_t) + @context (all) + */ + virtual size_t GetWidth() = 0; + + /* + public ZRenderTarget::SetClearFlags + + Sets the clear flags for this render target. + + @param _flags - flags structure which has our clear settings + @return (bool) - true if able to set flags, false if resource contended + @context (all) + */ + virtual bool SetClearFlags(const ZRenderTargetClearFlags& _flags) = 0; +}; + +#endif diff --git a/Include/ZRenderer/ZRenderer.hpp b/Include/ZRenderer/ZRenderer.hpp new file mode 100644 index 0000000..4095648 --- /dev/null +++ b/Include/ZRenderer/ZRenderer.hpp @@ -0,0 +1,559 @@ +/* + ZRenderer.hpp + Authors: Patrick Baggett , + Chris Ertel , + James Russell + Created: 3/20/2011 + + Purpose: + + Defines an interface for rendering to screen in graphics-library agnostic fashion. + + License: + + TODO +*/ + +#pragma once + +#ifndef _ZRENDERER_HPP +#define _ZRENDERER_HPP + +#include + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//Forward Declarations +class ZRenderer; + +//Typedef for a frame context (opaque handle) +typedef void* ZFrameContext; + +//Rendering phases the ZRenderer can exist in +enum ZRenderPhase +{ + ZRP_UNINITIALIZED, //Renderer has yet to be initialized + ZRP_IDLE, //Renderer is idle (no frame contexts currently created) + ZRP_FRAME_ACCEPTING, //Renderer is accepting SubmitDrawData calls (frame contexts have been created) + ZRP_FRAME_RENDERING, //Renderer is rendering Geometry (a frame context is rendering) + ZRP_SIZE +}; + +//Render State Structure, used to set up a render state for SubmitDrawData calls +struct ZRenderState +{ +public: + //The default constructor for render state initializes to a sane configuration + ZRenderState() + : EnableStencilTest(false), + EnableBlend(true), + SourceBlendFunc(SBFV_SRC_ALPHA), + DestBlendFunc(DBFV_ONE_MINUS_SRC_ALPHA), + blendR(0), blendG(0), blendB(0), blendA(0), + EnableCullTest(false), + EnableDepthTest(true), + DepthFunc(DFV_LESS_THAN), + EnableDepthWrite(true) { } + + ///////////////////////////////// + /* Draw Sort Relevant Settings */ + ///////////////////////////////// + + // BLENDING + uint32_t EnableBlend:1; //Enables Blending + uint32_t SourceBlendFunc:4; //Specifies Source Blending Function + uint32_t DestBlendFunc:3; //Specifies Destination Blending Function + + enum SourceBlendFuncValue //Values for the Source Blend Function + { + SBFV_ZERO, + SBFV_ONE, + SBFV_SRC_COLOR, + SBFV_ONE_MINUS_SRC_COLOR, + SBFV_DST_COLOR, + SBFV_ONE_MINUS_DST_COLOR, + SBFV_SRC_ALPHA, + SBFV_ONE_MINUS_SRC_ALPHA, + SBFV_DST_ALPHA, + SBFV_ONE_MINUS_DST_ALPHA, + SBFV_CONSTANT_COLOR, + SBFV_ONE_MINUS_CONSTANT_COLOR, + SBFV_CONSTANT_ALPHA, + SBFV_ONE_MINUS_CONSTANT_ALPHA, + SBFV_SRC_ALPHA_SATURATE, + SBFV_SIZE + }; + + enum DestBlendFuncValue //Values for the Destination Blend Function + { + DBFV_ZERO, + DBFV_ONE, + DBFV_SRC_COLOR, + DBFV_ONE_MINUS_SRC_COLOR, + DBFV_DST_COLOR, + DBFV_ONE_MINUS_DST_COLOR, + DBFV_SRC_ALPHA, + DBFV_ONE_MINUS_SRC_ALPHA, + DBFV_DST_ALPHA, + DBFV_ONE_MINUS_DST_ALPHA, + DBFV_CONSTANT_COLOR, + DBFV_ONE_MINUS_CONSTANT_COLOR, + DBFV_CONSTANT_ALPHA, + DBFV_ONE_MINUS_CONSTANT_ALPHA, + DBFV_SIZE + }; + + float blendR; //Red value used when blending needs a constant color + float blendG; //Green value used when blending needs a constant color + float blendB; //Blue value used when blending needs a constant color + float blendA; //Alpha value used when blending needs a constant color + + // DEPTH + uint32_t EnableDepthTest:1; //Bit Enables Depth Testing + uint32_t EnableDepthWrite:1; //Sets Depth Buffer to Read Only (Depth Values are not written) + uint32_t DepthFunc:3; //Specifies Depth Function + + enum DepthFuncValue //Values for the Depth Function + { + DFV_NEVER, + DFV_LESS_THAN, + DFV_EQUAL, + DFV_LESS_THAN_EQUAL, + DFV_GREATER_THAN, + DFV_NOT_EQUAL, + DFV_GREATER_THAN_EQUAL, + DFV_ALWAYS, + DFV_SIZE + }; + + // CULLING + uint32_t EnableCullTest:1; //Enable or disable face culling. + uint32_t CullMode:2; //Sets up front/back/both culling + + enum CullModeValue + { + CMV_FRONT, + CMV_BACK, + CMV_FRONT_AND_BACK, + CMV_SIZE + }; + + uint32_t CullWinding:1; //Sets winding for culling + + enum CullWindingValue + { + CWV_CW, + CWV_CCW, + CWV_SIZE + }; + + // STENCIL + uint32_t EnableStencilTest:1; //Bit Enables Stencil Testing + uint32_t StencilTestFuncFront:4; //Specifies the stencil comparisons + uint32_t StencilTestMaskFront:8; //Mask for front facing stencil post-op + uint32_t StencilTestReferenceFront:8; //Reference value for front facing stencil post-op + uint32_t StencilTestFuncBack:4; //Specifies the stencil comparisons + uint32_t StencilTestMaskBack:8; //Mask for back facing stencil post-op + uint32_t StencilTestReferenceBack:8; //Reference value for back facing stencil post-op + + enum StencilComparisonsValue //Values for the stencil comparisons + { + SCV_NEVER, + SCV_ALWAYS, + SCV_LESS, + SCV_LEQUAL, + SCV_EQUAL, + SCV_GEQUAL, + SCV_GREATER, + SCV_NOTEQUAL, + SCV_SIZE + }; + + uint32_t StencilOpStencilFailFront:3; //Specifies the stencil operation when stencil test fails for front-facing polys + uint32_t StencilOpStencilPassDepthFailFront:3; //Specifies the stencil operation when stencil test succeeds and depth test fails fails for front-facing polys + uint32_t StencilOpStencilPassDepthPassFront:3; //Specifies the stencil operation when stencil and depth tests pass fails for front-facing polys + uint32_t StencilOpStencilFailBack:3; //Specifies the stencil operation when stencil test fails for back-facing polys + uint32_t StencilOpStencilPassDepthFailBack:3; //Specifies the stencil operation when stencil test succeeds and depth test fails for back-facing polys + uint32_t StencilOpStencilPassDepthPassBack:3; //Specifies the stencil operation when stencil and depth tests pass for back-facing polys + + enum StencilOperationValue //Values for the stencil operations + { + SOV_KEEP, + SOV_ZERO, + SOV_REPLACE, + SOV_INCR, + SOV_INCR_WRAP, + SOV_DECR, + SOV_DECR_WRAP, + SOV_INVERT, + SOV_SIZE + }; +}; + +class ZRenderer : public ZThread +{ +protected: + //Default Constructor + ZRenderer() : ZThread("ZRenderer Thread") { } + +public: + //Virtual Destructor + virtual ~ZRenderer() { } + + ////////////////////////// + /* Lifecycle Operations */ + ////////////////////////// + + /* + virtual public ZRenderer::Init + + Initializes the Renderer for use as a long running subsystem. After this call, the + render thread will be running. + + @return (bool) + @context (all) + */ + virtual bool Init() = 0; + + /* + virtual public ZRenderer::Shutdown + + Shuts down the system and stops the render thread. + + @return (void) + @context (all) + */ + virtual void Shutdown() = 0; + + /////////////////////////// + /* Renderer Data Getters */ + /////////////////////////// + + /* + virtual public ZRenderer::GetCapabilities + + Returns a map describing the capabilities and configuration of this renderer. All + renderer implementations must map the following keys: + + gl { directx, opengl } + gl.version { 9.0c, 10.0, 10.1, 11.0, 11.1, 2.1, 3.1, 3.2, 3.3 ... } + : version number should always have major.minor format and should be the highest version required + gl.shaderlang { hlsl_40, hlsl_30, hlsl, glsl_14, glsl_13, glsl_12, glsl_11, glsl, ... } + : shading languages accepted should be listed in a comma separated list in order of preference + + data_buffer.block_alignment { integer } + : alignment requirement for buffer blocks + + frame_buffer_render_target.max_color_attachments { integer } + : maximum number of color buffer attachments + + Other keys may be supported depending upon the implementation. + + @return (const ZHashMap&) - map of capabilities + @context (all) + */ + virtual const ZHashMap& GetCapabilities() = 0; + + /* + virtual public ZRenderer::GetRenderPhase + + Gets the current rendering phase. + + @return (ZRenderPhase) - current rendering phase + @context (all) + */ + virtual ZRenderPhase GetRenderPhase() = 0; + + ////////////////////////// + /* Logistics Operations */ + ////////////////////////// + + /* + virtual public ZRenderer::CreateDataBuffer + + Creates a data buffer which contains data stored in graphics memory. The data + buffer is created but not initialized with values (use FillBuffer or MapBuffer). + + Keep in mind when allocating a buffer that defines block data that determining the + required size to fit all blocks includes taking into account alignment requirements. + The alignment requirement for block data for this renderer can be determined through + the capabilities map with key 'buffer.block_alignment'. + + @param _type - the type of buffer to allocate + @param _usage - the usage pattern the buffer will follow + @param _size - the size (in bytes) to allocate + @return (ZDataBuffer) - new data buffer object, NULL if not successful + @context (all) + */ + virtual ZPtr CreateDataBuffer(ZDataBufferType _type, + ZDataBufferUsage _usage, + size_t _size + ) = 0; + + /* + virtual public ZRenderer::CreateDrawParams + + Creates a draw parameters binding class, which is provided to the draw calls and + is used to bind data to shader variables. + + @param _type - the type of draw parameters binding + @return (ZPtr) - new draw parameters object, NULL if not successful + @context (all) + */ + virtual ZPtr CreateDrawParams(ZDrawParamsType _type) = 0; + + /* + virtual public ZRenderer::CreateFrameBufferRenderTarget + + Function to create a framebuffer-backed render target. + + @param _width - number of pixels wide to make the frame buffer + @param _height - number of pixels tall to make the frame buffer + @return (ZPtr) - new frame buffer render target, NULL if not successful + @context (all) + */ + virtual ZPtr CreateFrameBufferRenderTarget(size_t _width, size_t _height) = 0; + + /* + virtual public ZRenderer::CreateRenderBuffer + + Function to create a render buffer for use in a frame buffer render target. + + @param _type - the type of render buffer this will be + @param _width - number of pixels wide to make the render buffer + @param _height - number of pixels tall to make the render buffer + @return (ZPtr) - new render buffer, NULL if not successful + @context (all) + */ + virtual ZPtr CreateRenderBuffer(ZRenderBufferType _type, size_t _width, size_t _height) = 0; + + /* + virtual public ZRenderer::CreateSampler + + Creates a sampler object to use as a view onto a texture. + + @return (ZPtr) - new sampler object, NULL if unsuccessful + @context (all) + */ + virtual ZPtr CreateSampler() = 0; + + /* + virtual public ZRenderer::CreateShader + + Function to create a shader object for the renderer. + + @param _type - type of shader to create: + ZST_SOFT : Soft shaders + ZST_VERTEX : Vertex shaders + ZST_HULL : Hull shaders + ZST_DOMAIN : Domain shaders + ZST_GEOMETRY: Geometry shaders + ZST_FRAGMENT: Fragment (pixel) shaders + + @return (ZPtr) - the created shader, NULL if not successful + @context (all) + */ + virtual ZPtr CreateShader(ZShaderType _type) = 0; + + /* + virtual public ZRenderer::CreateShaderProgram + + Function to create a shader program. + + @return (ZPtr) - new shader program, NULL if not successful + @context (all) + */ + virtual ZPtr CreateShaderProgram() = 0; + + /* + virtual public ZRenderer::CreateTexture + + Creates a texture object. + + In the case of cube map textures, the bitmap format describes a single 'side' + of the cube map texture. + + If the bitmap provided has NULL for data, then the texture storage is initialized + but no data is copied. + + @param _type - the type of texture + @param _format - the texture internal storage format + @param _usage - the usage type of the texture + @param _bitmap - bitmap structure containing image format and size, as well as data (can be NULL) + @param _generateMipmaps - indicating whether or not we should generate mipmaps + @return (ZPtr) - new texture object, NULL if not successful + @context (all) + */ + virtual ZPtr CreateTexture(ZTextureType _type, + ZTextureFormat _format, + ZTextureUsage _usage, + const ZBitmap& _bitmap, + bool _generateMipmaps) = 0; + + /* + virtual public ZRenderer::CreateWindowRenderTarget + + Creates a window render target. + + @param _window - the window handle (created using libsst-wm) + @param _screenIndex - the screen index bound to the window + @return (ZPtr) - new window render target, NULL if not successful + @context (all) + */ + virtual ZPtr CreateWindowRenderTarget(SST_Window _window, + size_t _screenIndex + ) = 0; + + //////////////////////// + /* Frame Data Getters */ + //////////////////////// + + /* + virtual public ZRenderer::GetFrameRenderTarget + + Gets the render target set for the given frame context. + + @param _frameContext - frame context + @return (ZRenderTarget*) - the render target for the given context + @context (all) + */ + virtual ZRenderTarget* GetFrameRenderTarget(ZFrameContext _frameContext) = 0; + + ////////////////////////// + /* Rendering Operations */ + ////////////////////////// + + /* + The renderer can maintain a few different states, each of which is described by an enumeration. The various + rendering operations affect this state, and thread synchronization calls such as WaitFrameStart and WaitFrameEnd + will wait until events are triggered after state changes, as follows. + + BeginFrame() + | SubmitDrawData() + | | RenderFrame() + | +-------+-------+ | + | | | | | + ---------------+---+-------+-------+---+-----------------------+--------------- + ===============|///////////////////////|///////////////////////|=============== + ZRP_IDLE ... =|/ ZRP_FRAME_ACCEPTING /|/ ZRP_FRAME_RENDERING /|= ZRP_IDLE ... + ===============|///////////////////////|///////////////////////|=============== + | | + +-> WaitFrameStart() +-> WaitFrameEnd() + ^ | + | Frame to Render? | + +<----------------------+ + + Because of the multi threaded nature of ZRenderer, multiple threads can call SubmitDrawData to populate + the render lists full of buffered data to draw. A single call should be placed to BeginFrame for each + frame context that is desired, and a single call to RenderFrame should occur for each frame context that has + been created. + + It is guaranteed that order will be maintained between calls to RenderFrame, meaning if RenderFrame is called + for frame context 0, and then afterwards RenderFrame is called for frame context 1, frame context 0 is guaranteed + to render in its entirety before frame context 0 is rendered. + */ + + /* + virtual public ZRenderer::BeginFrame + + Tells the renderer that threads will begin providing draw data for a frame of rendering. The value returned + is later used as a frame context for render calls. + + BeginFrame can be called multiple times, each time returning a new frame context that can be provided + for draw calls. + + BeginFrame should be called once for as many frame contexts there will be before beginning render calls + for any of them. Calling BeginFrame after other frames have begun rendering results in undefined + behavior. Frame contexts should never be re-used across multiple render cycles - always ask for a new one. + + @param _canvas - the canvas to render to + @return (ZFrameContext) - the frame context that has been created + @context (all) + */ + virtual ZFrameContext BeginFrame(ZPtr _canvas) = 0; + + /* + virtual public ZRenderer::EndFrame + + TODO + + @param _frameContext - the frame context we are done submitting draw data to + @return (void) + @context (all) + */ + virtual void EndFrame(ZFrameContext _frameContext) = 0; + + /* + virtual public ZRenderer::SubmitDrawData + + Draws geometry defined in a DataBuffer (Queues them up for rendering). + + @param _frameContext - the frame context to provide data for + @param _shaderProgram - the shader program to draw with + @param _shaderParams - the shader parameters binding + @param _vertexParams - the vertex parameters binding + @param _indexParams - the index parameters binding + @param _renderState - the render state to render the geometry with + @param _drawGroup - the draw group to render this call with; objects with lower draw group + are rendered before objects with higher draw group + @return (void) + @context (all) + */ + virtual void SubmitDrawData(ZFrameContext _frameContext, + ZPtr _shaderProgram, + ZPtr _shaderParams, + ZPtr _vertexParams, + ZPtr _indexParams, + const ZRenderState& _renderState, + int _drawGroup = 0 + ) = 0; + + /* + virtual public ZRenderer::RenderFrame + + Renders the frame context. + + @param _frameContext - the frame context to render + @return (void) + @context (all) + */ + virtual void RenderFrame(ZFrameContext _frameContext) = 0; + + /* + virtual public ZRenderer::WaitFrameStart + + Calling thread waits until RenderFrame is called for the given frame context. + + @param _frameContext - the frame context to wait for + @return (void) + @context (all) + */ + virtual void WaitFrameStart(ZFrameContext _frameContext) = 0; + + /* + virtual public ZRenderer::WaitFrameEnd + + Calling thread waits until after the render thread has finished rendering a frame. + + @param _frameContext - the frame context to wait for + @return (void) + @context (all) + */ + virtual void WaitFrameEnd(ZFrameContext _frameContext) = 0; +}; + +#endif diff --git a/Include/ZRenderer/ZRendererBase.hpp b/Include/ZRenderer/ZRendererBase.hpp new file mode 100644 index 0000000..9234b19 --- /dev/null +++ b/Include/ZRenderer/ZRendererBase.hpp @@ -0,0 +1,259 @@ +/* + ZRendererBase.hpp + Author: James Russell + Created: 3/23/2011 + + Purpose: + + Base implementation of the ZRenderer class, which handles many of the details that + are common to multi threaded renderers. + + License: + + TODO +*/ + +#pragma once + +#ifndef _ZRENDERERBASE_HPP +#define _ZRENDERERBASE_HPP + +#include +#include + +//Forward Declarations +struct ZFrameData; + +//Maximum number of concurrent frame contexts +#ifndef ZRB_MAX_FRAME_CONTEXT_COUNT +#define ZRB_MAX_FRAME_CONTEXT_COUNT (4) +#endif + +//Default slab allocation of Draw Objects, will auto correct at runtime if exceeded +#ifndef ZRB_DEFAULT_DRAWDATA_COUNT +#define ZRB_DEFAULT_DRAWDATA_COUNT (128) +#endif + +//Default buffer size for a draw list +#ifndef ZRB_DEFAULT_DRAWDATA_BUFFER_SIZE +#define ZRB_DEFAULT_DRAWDATA_BUFFER_SIZE (128) +#endif + +/* +Used to contain only the minimum data necessary to draw geometry +and hold no ownership (in smart pointer terms) over the parameters. +*/ +struct ZDrawData +{ + ZShaderProgram* ShaderProgram; //The shader program we will be drawing with + ZShaderParams* ShaderParams; //The shader parameters we will be using + ZVertexParams* VertexParams; //The vertex parameters we will be using + ZIndexParams* IndexParams; //The index parameters we will be using + ZRenderState RenderState; //The renderer state we will be using + int DrawGroup; //The draw group for drawing data + + ZFrameData* Parent; //The parent ZFrameData struct that holds ownership + + //Default Constructor + ZDrawData() + : ShaderProgram(NULL), + ShaderParams(NULL), VertexParams(NULL), IndexParams(NULL), + RenderState(), DrawGroup(-1), + Parent(NULL) + { } +}; + +/* +Used to contain references to the data necessary to draw geometry per frame. Holds +strong references long enough to ensure parameters do not get deleted. +*/ +struct ZFrameData +{ + ZArray< ZPtr > ShaderPrograms; //The shader programs we will be using + ZArray< ZPtr > ShaderParams; //The shader parameters we will be using + ZArray< ZPtr > VertexParams; //The vertex parameters we will be using + ZArray< ZPtr > IndexParams; //The index parameters we will be using + + ZPtr RenderTarget; //The render target for this frame + + ZArray > DrawData; //Our set of draw data + + //Concurrency Control Variables + ZMutex FrameLock; + ZEvent FrameEndSignal; + ZEvent FrameStartSignal; +}; + +/* +ZRendererBase class, which can be extended by GL-specific renderers. +*/ +class ZRendererBase : public ZRenderer +{ +private: + //The renderer lock + ZMutex RendererLock; + + //Current Render Phase + volatile ZRenderPhase Phase; + + //Slab allocator for ZFrameData + ZSlabAllocator DrawDataAllocator; + + //Slab allocator for ZFrameData + ZSlabAllocator FrameDataAllocator; + + //The frame data available queue (available for use) + ZRingBuffer > FrameAvailableQueue; + + //The frame data render queue (pending renders) + ZRingBuffer > FrameRenderQueue; + + //The frame data we are rendering + ZFrameData* CurrentFrame; + +protected: + //Capabilities mapping + ZHashMap Capabilities; + + //Protected Constructor + ZRendererBase(); + + /* + virtual protected ZRendererBase::init + + This will be called by ZRendererBase::Init and should handle subclass + initialization. + + @return (bool) - true if successful, false otherwise + */ + virtual bool init() = 0; + + /* + virtual protected ZRendererBase::shutdown + + This will be called by ZRendererBase::Shutdown and should handle subclass + shutdown. + + @return (void) + */ + virtual void shutdown() = 0; + + /* + virtual protected ZRendererBase::Draw + + Method which should, given a list of render data, draw it to the provided render target. + + @param _renderList - the sorted list of draw data objects to draw + @param _renderTarget - the render target to draw to + @return (void) + */ + virtual void Draw(ZArray >& _renderList, + ZRenderTarget* _renderTarget) = 0; + + +public: + /* + Destructor. + */ + virtual ~ZRendererBase(); + + ////////////////////////// + /* Lifecycle Operations */ + ////////////////////////// + + //Subclass Implementation + virtual bool Init(); + + //Subclass Implementation + virtual void Shutdown(); + + /////////////////////////// + /* Renderer Data Getters */ + /////////////////////////// + + //Subclass Override + virtual const ZHashMap& GetCapabilities(); + + //Subclass Override + virtual ZRenderPhase GetRenderPhase(); + + ////////////////////////// + /* Logistics Operations */ + ////////////////////////// + + //Subclass Implementation + virtual ZPtr CreateDrawParams(ZDrawParamsType _type); + + //Not Implemented + virtual ZPtr CreateDataBuffer(ZDataBufferType _type, + ZDataBufferUsage _usage, + size_t _size + ) = 0; + + //Not Implemented + virtual ZPtr CreateFrameBufferRenderTarget(size_t _width, size_t _height) = 0; + + //Not Implemented + virtual ZPtr CreateRenderBuffer(ZRenderBufferType _type, size_t _width, size_t _height) = 0; + + //Not Implemented + virtual ZPtr CreateSampler() = 0; + + //Not Implemented + virtual ZPtr CreateShader(ZShaderType _type) = 0; + + //Not Implemented + virtual ZPtr CreateShaderProgram() = 0; + + //Not Implemented + virtual ZPtr CreateTexture(ZTextureType _type, ZTextureFormat _format, ZTextureUsage _usage, const ZBitmap& _bitmap, bool _generateMipmaps) = 0; + + //Not Implemented + virtual ZPtr CreateWindowRenderTarget(SST_Window _window, size_t _screenIndex) = 0; + + //////////////////////// + /* Frame Data Getters */ + //////////////////////// + + //Subclass Implementation + virtual ZRenderTarget* GetFrameRenderTarget(ZFrameContext _frameContext); + + ////////////////////////// + /* Rendering Operations */ + ////////////////////////// + + //Subclass Implementation + virtual ZFrameContext BeginFrame(ZPtr _canvas); + + virtual void EndFrame(ZFrameContext _frameContext); + + //Subclass Implementation + virtual void SubmitDrawData(ZFrameContext _frameContext, + ZPtr _shaderProgram, + ZPtr _shaderParams, + ZPtr _vertexParams, + ZPtr _indexParams, + const ZRenderState& _renderState, + int _drawGroup = 0 + ); + + //Subclass Implementation + virtual void RenderFrame(ZFrameContext _frameContext); + + //Subclass Implementation + virtual void WaitFrameStart(ZFrameContext _frameContext); + + //Subclass Implementation + virtual void WaitFrameEnd(ZFrameContext _frameContext); + + //Implementation of the render thread + virtual ZThreadReturn run(uint64_t _dt); +}; + +#endif diff --git a/Include/ZRenderer/ZRendererBuild.hpp b/Include/ZRenderer/ZRendererBuild.hpp new file mode 100644 index 0000000..d0596a8 --- /dev/null +++ b/Include/ZRenderer/ZRendererBuild.hpp @@ -0,0 +1,49 @@ +/* + ZRendererBuild.hpp + Author: James Russell + Created: 5/21/2012 + + Purpose: + + Used to generate definitions for the preprocessor using only compiler-set variables + and include headers necessary to ensure previous project build files are included + in the correct order. + + License: + + TODO +*/ + +#pragma once + +#ifndef _ZRENDERERBUILD_HPP +#define _ZRENDERERBUILD_HPP + +#include "ZBuild.hpp" + +#include + +//Version number constants for ZRenderer +#define ZRENDERER_VERSION_MAJOR 0x01 +#define ZRENDERER_VERSION_MINOR 0x00 +#define ZRENDERER_VERSION_PATCH 0x0000 +#define ZRENDERER_VERSION (ZRENDERER_VERSION_MAJOR << 24) | (ZRENDERER_VERSION_MINOR << 16) | (ZRENDERER_VERSION_PATCH) + +#define ZRENDERER_VERSION_STRING "1.0.0" + +#if ZASSERT_RENDERER_ENABLE + +//ZASSERT_RENDERER macro, which will trigger a breakpoint if the condition is not met +//ZASSERT_RENDERER is meant to be used within the ZRenderer project for internal assertion debugging +//ZASSERT should be used when the error condition can be caused by user actions +#define ZASSERT_RENDERER(_condition, _message) SST_OS_DebugAssert(_condition, _message) + +#else + +//ZASSERT_RENDERER is disabled +#define ZASSERT_RENDERER(_condition, _message) ((void)sizeof(_condition), sizeof(_message)) + +#endif //ZASSERT_RENDERER_ENABLE + +#endif + diff --git a/Include/ZRenderer/ZRendererResource.hpp b/Include/ZRenderer/ZRendererResource.hpp new file mode 100644 index 0000000..cd37cd8 --- /dev/null +++ b/Include/ZRenderer/ZRendererResource.hpp @@ -0,0 +1,153 @@ +/* + ZRendererResource.hpp + Author: James Russell + Created: 7/8/2012 + + Purpose: + + A renderer resource is anything that is created by the renderer and is used as part of + the rendering process. Generally, renderer resources are objects that act as an interface + to graphics device state, such as buffers, textures, etc. + + It should be noted that resources are not safe to be used across multiple threads, even though + the renderer is multi thread capable. A resource should only be used within the context of a + single thread, and draw calls using that resource should also remain within the same thread + (this is done to avoid costly concurrent operations). + + Different resources are free to be used across different threads. + + Usage: + + A renderer resource can be 'available', 'locked', or 'contended'. When a resource is available, + all calls to methods that modify the underlying data (or make the underlying data available for + modification) succeed and this will be indicated by the return value. If the resource is locked + or contended, the return value of the method will indicate failure to modify the resource. + + If a resource is 'locked', then the resource is currently in the midst of modification. This + means that some modification methods will be unavailable. As an example, 'MapBuffer' cannot + be called while the buffer is already mapped, and 'FillBuffer' will fail if a buffer has + been mapped. A locked resource can be unlocked and returned to 'available' state before + rendering. + + If a resource is contended, this means that the renderer is relying on the data that is currently + present in graphics memory, as a draw call has been placed using the data at the time of contention. + This means that any calls that would allow the user to modify the underlying data will fail. A + contended buffer becomes available when the renderer has finished reading the data needed from + the resource, which will occur at frame end. + + Note that this means that the following set of actions (using an example of ZDataBuffer): + + buffer = dataBuffer->MapBuffer(true); + ... //Update Buffer + dataBuffer->UnmapBuffer(); + + renderer->SubmitDrawData(...); //Draw using this buffer + + buffer = dataBuffer->MapBuffer(true); + ... //Update Buffer + dataBuffer->UnmapBuffer(); + + renderer->SubmitDrawData(...); //Draw using the updated buffer + + renderer->RenderFrame(...); //Render this frame + + Will not work. The second call to 'MapBuffer' will fail because the buffer became contended + as soon as the buffer was used as an argument to 'SubmitDrawData'. The renderer's 'WaitFameEnd' + method will enable you to wait until the resource is no longer contended. + + License: + + TODO + +*/ + +#pragma once + +#ifndef _ZRENDERERRESOURCE_HPP +#define _ZRENDERERRESOURCE_HPP + +#include + +class ZRendererResource +{ +private: + DISABLE_COPY_AND_ASSIGN(ZRendererResource); + +protected: + //Counter of 'owners' claiming contention + int ContentionCount; + + //Flag indicating that this resource has been 'locked' + bool bIsLocked; + +public: + //Default Constructor + ZRendererResource(); + + //Virtual Destructor + virtual ~ZRendererResource() { } + + /* + public ZRendererResource::Available + + Returns whether or not this resource is currently available (able to be modified). + If a resource is locked or contended, then it is not available for modification. + + @return (bool) - true if available, false otherwise + @context (all) + */ + bool IsAvailable(); + + /* + public ZRendererResource::Lock + + Locks this resource, making it unavailable for modification. + + @return (void) + @context (all) + */ + void Lock(); + + /* + public ZRendererResource::MarkContended + + Marks this resource as contended. Resources should, from this point out, + understand that modification of the underlying resource should not happen + until after the frame is drawn that would release this resource from + contention. From this point out, the caller 'owns' the resource. + + Resources can be marked as contended by multiple sources, and the resource + will not be available until all owners who have marked contended have + released their claim. + + Generally, this should only be called by the renderer. + + @return (void) + @context (renderer) + */ + void MarkContended(); + + /* + public ZRendererResource::ReleaseContended + + Removes a previous claim of contention. If all previous owners have + released their contention, then the resource is available. + + @return (void) + @context (all) + */ + void ReleaseContention(); + + /* + public ZRendererResource::Unlock + + Unlocks a resource, making it available for modification. + + @return (void) + @context (all) + */ + void Unlock(); +}; + +#endif + diff --git a/Include/ZRenderer/ZSampler.hpp b/Include/ZRenderer/ZSampler.hpp new file mode 100644 index 0000000..1e77312 --- /dev/null +++ b/Include/ZRenderer/ZSampler.hpp @@ -0,0 +1,192 @@ +/* + ZSampler.hpp + Author: James Russell + Created: 7/1/2012 + + Purpose: + + Samplers act as a view onto a texture object, encapsulating all the filtering, mipmapping, + and addressing settings for shaders to access a texture. + + TODO - A writeup here on the various settings and how they interact, or at least a link to + some place that does + + License: + + TODO + +*/ + +#pragma once + +#ifndef _ZSAMPLER_HPP +#define _ZSAMPLER_HPP + +#include +#include + +//This should be ~log2 of ZT_MAX_TEXTURE_DIMENSION +#ifndef ZS_DEFAULT_MAX_LOD +#define ZS_DEFAULT_MAX_LOD (13.0f) +#endif + +//Enumeration of sampler wrapping modes +enum ZSamplerWrapMode +{ + ZSWM_CLAMP_EDGE, //Sampling beyond the edge results in the last pixel value + ZSWM_CLAMP_BORDER, //Sampling beyond the edge results in the specified border value + ZSWM_MIRROR_REPEAT, //Sampling beyond the edge wraps back in on itself + ZSWM_REPEAT, //Sampling beyond the edge wraps around to the other side + ZSWM_SIZE +}; + +//Enumeration of magnification sampler filtering modes +enum ZSamplerMagFilter +{ + ZSMAGF_NEAREST, //Nearest mode filter + ZSMAGF_LINEAR, //Linear mode filter + ZSMAGF_SIZE +}; + +//Enumeration of minification sampler filtering modes +enum ZSamplerMinFilter +{ + ZSMINF_NEAREST, //Nearest-neighbor pixel, no mip levels + ZSMINF_NEAREST_MIP_NEAREST, //Nearest-neighbor sampling on nearest mip level + ZSMINF_NEAREST_MIP_LINEAR, //Nearest-neighbor sampling on lerped mip level + ZSMINF_LINEAR, //Linear interpolation, no mip levels + ZSMINF_LINEAR_MIP_NEAREST, //Lerped sampling on nearest mip level + ZSMINF_LINEAR_MIP_LINEAR, //Lerped sampling on lerped mip level + ZSMINF_SIZE +}; + +//Enumeration of sampler comparison modes +enum ZSamplerCompareMode +{ + ZSCM_COMPARE_REF_TO_TEXTURE, //Compares reference to texture + ZSCM_NONE, //No comparison + ZSCM_SIZE +}; + +//Enumeration of sampler comparison functions +enum ZSamplerCompareFunc +{ + ZSCF_LESS_EQUAL, //Less than or equal + ZSCF_GREATER_EQUAL, //Greater than or equal + ZSCF_LESS, //Less than + ZSCF_GREATER, //Greater than + ZSCF_EQUAL, //Equal + ZSCF_NOT_EQUAL, //Not Equal + ZSCF_ALWAYS, //Always + ZSCF_NEVER, //Never + ZSCF_SIZE +}; + +//Struct that encapsulates the sampler state +struct ZSamplerState +{ + ZSamplerWrapMode SWrapMode; //Wrapping mode for S + ZSamplerWrapMode TWrapMode; //Wrapping mode for T (unused for 1D) + ZSamplerWrapMode RWrapMode; //Wrapping mode for R (unused for 1D, 2D) + + ZSamplerMinFilter MinFilter; //Minification Filter + ZSamplerMagFilter MagFilter; //Magnification Filter + + float MaxAnisotropy; //Maximum Anisotropy (< 2.0 has no effect) + float MinLOD; //Minimum LOD + float MaxLOD; //Maximum LOD + float LODBias; //LOD Bias + + float BorderColor[4]; //RGBA Border Color + + ZSamplerCompareMode CompareMode; //Sampler Comparison Mode + ZSamplerCompareFunc CompareFunc; //Sampler Comparison Function + + //Default Configuration + ZSamplerState() + : SWrapMode(ZSWM_REPEAT), TWrapMode(ZSWM_REPEAT), RWrapMode(ZSWM_REPEAT), + MinFilter(ZSMINF_LINEAR), MagFilter(ZSMAGF_LINEAR), + MaxAnisotropy(1.0), MinLOD(0), MaxLOD(ZS_DEFAULT_MAX_LOD), LODBias(0), + CompareMode(ZSCM_NONE), CompareFunc(ZSCF_ALWAYS) + { } +}; + +/* +Sampler interface class. +*/ +class ZSampler : public ZRendererResource +{ +public: + //Virtual Destructor + virtual ~ZSampler() { } + + /* + ZSampler::Get* + + The following methods are getters for the various ZSampler settings + that can be set on a given sampler. For a greater explanation of each + setting and what it does, see above. + */ + + //Getters for the S, T, and R Wrap Mode set on this sampler + virtual ZSamplerWrapMode GetSWrapMode() = 0; + virtual ZSamplerWrapMode GetTWrapMode() = 0; + virtual ZSamplerWrapMode GetRWrapMode() = 0; + + //Getters for the minification filter and magnification filter + virtual ZSamplerMagFilter GetMagFilter() = 0; + virtual ZSamplerMinFilter GetMinFilter() = 0; + + //Getters for the maximum anisotropy, minimum LOD, maximum LOD, and LOD bias + virtual float GetMaxAnisotropy() = 0; + virtual float GetMinLOD() = 0; + virtual float GetMaxLOD() = 0; + virtual float GetLODBias() = 0; + + //Getter for the border color setting (four-element array, RGBA) + virtual const float* GetBorderColor() = 0; + + //Getter for the comparison mode and comparison function + virtual ZSamplerCompareMode GetCompareMode() = 0; + virtual ZSamplerCompareFunc GetCompareFunc() = 0; + + //Getter for the entire sampler state + virtual const ZSamplerState& GetSamplerState() = 0; + + /* + ZSampler::Set* + + The following methods are setters for the various ZSampler settings than + can be set on a given sampler. For a greater explanation of each setting and what it + does, see above. + + If any of the setters returns false, it is because the resource is contended. + */ + + //Setters for the S, T, and R wrapping modes + virtual bool SetSWrapMode(ZSamplerWrapMode _mode) = 0; + virtual bool SetTWrapMode(ZSamplerWrapMode _mode) = 0; + virtual bool SetRWrapMode(ZSamplerWrapMode _mode) = 0; + + //Setters for the minification and magnification filter + virtual bool SetMagFilter(ZSamplerMagFilter _filter) = 0; + virtual bool SetMinFilter(ZSamplerMinFilter _filter) = 0; + + //Setters for maximum anisotropy, minimum LOD, maximum LOD, and LOD bias + virtual bool SetMaxAnisotropy(float _max) = 0; + virtual bool SetMinLOD(float _min) = 0; + virtual bool SetMaxLOD(float _max) = 0; + virtual bool SetLODBias(float _bias) = 0; + + //Setter for border color + virtual bool SetBorderColor(float _r, float _g, float _b, float _a) = 0; + + //Setter for comparison mode and comparison function + virtual bool SetCompareMode(ZSamplerCompareMode _mode) = 0; + virtual bool SetCompareFunc(ZSamplerCompareFunc _func) = 0; + + //Setter for entire sampler state + virtual bool SetSamplerState(const ZSamplerState& _state) = 0; +}; + +#endif diff --git a/Include/ZRenderer/ZSamplerBase.hpp b/Include/ZRenderer/ZSamplerBase.hpp new file mode 100644 index 0000000..721666d --- /dev/null +++ b/Include/ZRenderer/ZSamplerBase.hpp @@ -0,0 +1,98 @@ +/* + ZSamplerBase.hpp + Author: James Russell + Created: 7/1/2012 + + Purpose: + + TODO + + License: + + TODO + +*/ + +#pragma once + +#ifndef _ZSAMPLERBASE_HPP +#define _ZSAMPLERBASE_HPP + +#include + +//Base implementation of ZSampler Interface +class ZSamplerBase : public ZSampler +{ +private: + DISABLE_COPY_AND_ASSIGN(ZSamplerBase); + +protected: + //Current sampler state + ZSamplerState State; + + //Flag indicating values have changed + bool bIsDirty; + + //Default Constructor, which initializes with some sane default settings + ZSamplerBase(); + +public: + //Virtual Destructor + virtual ~ZSamplerBase() { } + + /* + public ZSamplerBase::GetSamplerStateResetDirty + + Gets the sampler state for this device. This will return + NULL if the sampler has not been modified since the last call to + this function, and in the case it has been modified, a call to this + resets the 'dirty' flag for the buffer. + + @return (ZSamplerState*) + @context (all) + */ + ZSamplerState* GetSamplerStateResetDirty(); + + //Subclass Getter Implementations + virtual ZSamplerWrapMode GetSWrapMode(); + virtual ZSamplerWrapMode GetTWrapMode(); + virtual ZSamplerWrapMode GetRWrapMode(); + + virtual ZSamplerMinFilter GetMinFilter(); + virtual ZSamplerMagFilter GetMagFilter(); + + virtual float GetMaxAnisotropy(); + virtual float GetMinLOD(); + virtual float GetMaxLOD(); + virtual float GetLODBias(); + + virtual const float* GetBorderColor(); + + virtual ZSamplerCompareMode GetCompareMode(); + virtual ZSamplerCompareFunc GetCompareFunc(); + + virtual const ZSamplerState& GetSamplerState(); + + //Subclass Setter Implementations + virtual bool SetSWrapMode( ZSamplerWrapMode _mode ); + virtual bool SetTWrapMode( ZSamplerWrapMode _mode ); + virtual bool SetRWrapMode( ZSamplerWrapMode _mode ); + + virtual bool SetMinFilter( ZSamplerMinFilter _filter ); + virtual bool SetMagFilter( ZSamplerMagFilter _filter ); + + virtual bool SetMaxAnisotropy( float _max ); + virtual bool SetMinLOD( float _min ); + virtual bool SetMaxLOD( float _max ); + virtual bool SetLODBias( float _bias ); + + virtual bool SetBorderColor( float _r, float _g, float _b, float _a ); + + virtual bool SetCompareMode(ZSamplerCompareMode _mode); + virtual bool SetCompareFunc(ZSamplerCompareFunc _func); + + virtual bool SetSamplerState(const ZSamplerState& _state); +}; + +#endif + diff --git a/Include/ZRenderer/ZShader.hpp b/Include/ZRenderer/ZShader.hpp new file mode 100644 index 0000000..80cf4d5 --- /dev/null +++ b/Include/ZRenderer/ZShader.hpp @@ -0,0 +1,122 @@ +/* + ZShader.hpp + Author: Chris Ertel , + James Russell + Created: 4/20/2011 + + Purpose: + + TODO + + License: + + TODO +*/ + +#pragma once + +#ifndef _ZSHADER_HPP +#define _ZSHADER_HPP + +#include +#include + +#include + +//Shader Type +enum ZShaderType +{ + ZST_SOFT, //Software Shader (unsupported) + ZST_VERTEX, //Vertex Shader + ZST_FRAGMENT, //Fragment/Pixel Shader + ZST_GEOMETRY, //Geometry Shader (unsupported) + ZST_HULL, //Hull Shader (unsupported) + ZST_DOMAIN, //Domain Shader (unsupported) + ZST_SIZE +}; + +//For you non OpenGL types +#define ZST_PIXEL (ZST_FRAGMENT) + +class ZShader : public ZRendererResource +{ +public: + /* + virtual public ZShader::ClearLog + + Function to clear the log of a shader. + + @return (void) + @context (all) + */ + virtual void ClearCompileLog() = 0; + + /* + virtual public ZShdaer::Compile + + Function to compile a shader. + + @return (bool) - true if successfully compiled, false otherwise. + @context (all) + */ + virtual bool Compile() = 0; + + /* + virtual public ZShdaer::IsUsable + + Function to compile a shader. + + @return (bool) - true if successfully compiled, false otherwise. + @context (all) + */ + virtual bool IsUsable() = 0; + + /* + virtual public ZShader::GetLog + + Function to get the log of a shader. + + @return (ZString) - the log of the shader. + @context (all) + */ + virtual const ZString& GetCompileLog() = 0; + + /* + virtual public ZShader::GetSource + + Function to get the source of a shader. + + @return (ZString) - the source of the shader. + @context (all) + */ + virtual const ZString& GetSource() = 0; + + /* + virtual public ZShader::GetType + + Function to get the type of a shader. + + ZST_SOFT : Soft shaders + ZST_VERTEX : Vertex shaders + ZST_HULL : Hull shaders + ZST_DOMAIN : Domain shaders + ZST_GEOMETRY: Geometry shaders + ZST_FRAGMENT: Fragment (pixel) shaders + + @return (ZShaderType) - type of shader. + @context (all) + */ + virtual ZShaderType GetType() = 0; + + /* + virtual public ZShader::SetSource + + Function to set the source of a shader. + + @param _source - shader source, as a string + @return (void) + @context (all) + */ + virtual void SetSource(const ZString& _source) = 0; +}; +#endif \ No newline at end of file diff --git a/Include/ZRenderer/ZShaderBase.hpp b/Include/ZRenderer/ZShaderBase.hpp new file mode 100644 index 0000000..38b2f14 --- /dev/null +++ b/Include/ZRenderer/ZShaderBase.hpp @@ -0,0 +1,74 @@ +/* + ZShaderBase.hpp + Author: Chris Ertel , + James Russell + Created: 4/20/2011 + + Purpose: + + Base implementation of the ZShader interface. + + License: + + TODO +*/ + +#pragma once + +#ifndef _ZSHADERBASE_HPP +#define _ZSHADERBASE_HPP + +#include + +/* +Shader base class implementation. +*/ +class ZShaderBase : public ZShader +{ +protected: + //The type of shader + ZShaderType Type; + + //The shader source + ZString Source; + + //The shader compilation log + ZString Log; + + //Boolean set to true indicates this is a usable shader + bool bIsUsable; + +public: + /* + Constructor. + + @param _type - the type of shader this is + */ + ZShaderBase(ZShaderType _type); + + //Virtual Destructor + virtual ~ZShaderBase(); + + //Subclass Implementation + virtual void ClearCompileLog(); + + //Subclass Implementation + virtual const ZString& GetCompileLog(); + + //Subclass Implementation + virtual const ZString& GetSource(); + + //Subclass Implementation + virtual ZShaderType GetType(); + + //Subclass Implementation + virtual bool IsUsable(); + + //Subclass Implementation + virtual void SetSource( const ZString& _source ); + + //Not Implemented + virtual bool Compile() = 0; +}; + +#endif diff --git a/Include/ZRenderer/ZShaderParams.hpp b/Include/ZRenderer/ZShaderParams.hpp new file mode 100644 index 0000000..3f62976 --- /dev/null +++ b/Include/ZRenderer/ZShaderParams.hpp @@ -0,0 +1,147 @@ +/* + ZShaderParams.hpp + Author: James Russell + Created: 7/1/2012 + + Purpose: + + Shader parameters class, to which uniform buffers and samplers are bound + and passed to draw calls. The attached buffers and samplers will be used + to provide data to the shader. + + License: + + TODO + +*/ + +#pragma once + +#ifndef _ZSHADERPARAMS_HPP +#define _ZSHADERPARAMS_HPP + +#include + +#include + +#include + +#include +#include +#include + +#ifndef ZSP_MAX_UNIFORM_BLOCKS +#define ZSP_MAX_UNIFORM_BLOCKS (128) +#endif + +#ifndef ZSP_MAX_SAMPLERS +#define ZSP_MAX_SAMPLERS (32) +#endif + +//Shader Parameters Structure, used to hold shader parameters +class ZShaderParams : public ZDrawParams +{ +private: + DISABLE_COPY_AND_ASSIGN(ZShaderParams); + +protected: + //A uniform block binding + struct UniformBlockBinding + { + ZName Name; //Name of the uniform block binding + ZPtr Buffer; //Parent buffer + + ZPair Binding; //Pair Binding + }; + + //A sampler binding + struct SamplerBinding + { + ZName Name; //Name of the sampler binding + ZPtr Sampler; //Sampler + ZPtr Texture; //Texture + + ZPair Binding; //Pair binding + }; + + //These are the buffer bindings and samplers that are provided to the shader program + UniformBlockBinding UniformBlockBindings[ZSP_MAX_UNIFORM_BLOCKS]; + SamplerBinding SamplerBindings[ZSP_MAX_SAMPLERS]; + + //Our current uniform block count and sampler count + size_t UniformBlockBindingCount; + size_t SamplerBindingCount; + + +public: + + /* + Default Constructor. + */ + ZShaderParams(); + + virtual ~ZShaderParams() { } + + /* + public ZShaderParams::ClearUniformBufferBlocks + + Clears the current set of uniform buffer blocks. + + @return (void) + @context (all) + */ + void ClearUniformBufferBlocks(); + + /* + public ZShaderParams::ClearSamplers + + Clears the current set of sampler bindings. + + @return (void) + @context (all) + */ + void ClearSamplers(); + + /* + public ZShaderParams::SetUniformBufferBlock + + Sets the value of a uniform buffer block for a shader. Set to NULL using overload + to remove binding. + + @param _name - the name of the uniform block in the shader + @param _buffer - the buffer containing the values + @param _block - the block definition for the buffer block + @return (void) + @context (all) + */ + void SetUniformBufferBlock(const ZName& _name, ZPtr _buffer, const ZDataBufferBlock* _block); + + /* + public ZShaderParams::SetSampler + + Sets the value of a sampler for a shader. + + @param _name - the name of the sampler in the shader + @param _sampler - the sampler object to use + @param _texture - the texture the sampler object is a view onto + @return (void) + @context (all) + */ + void SetSampler(const ZName& _name, ZPtr _sampler, ZPtr _texture); + + /* + The following methods are used by the renderer to get the values needed when + binding shader parameter values to pass to the shader program, to mark + all bound resources as contended, and release contention. + */ + const ZPair* GetUniformBlockByName(const ZName& _name); + const ZPair* GetSamplerByName(const ZName& _name); + + //Subclass Override + virtual void MarkResourcesContended(); + + //Subclass Override + virtual void ReleaseResourceContention(); +}; + +#endif diff --git a/Include/ZRenderer/ZShaderProgram.hpp b/Include/ZRenderer/ZShaderProgram.hpp new file mode 100644 index 0000000..4aa3729 --- /dev/null +++ b/Include/ZRenderer/ZShaderProgram.hpp @@ -0,0 +1,315 @@ +/* + ZShaderProgram.hpp + Author: Chris Ertel , + James Russell + Created: 04/03/2011 + + Purpose: + + TODO + + License: + + TODO +*/ + +#pragma once + +#ifndef _ZSHADERPROGRAM_HPP +#define _ZSHADERPROGRAM_HPP + +#include +#include +#include +#include + +#include + +#include + +//Enumeration for shader stream attribute types +enum ZShaderStreamAttributeType +{ + // VECTOR TYPE + ZSSAT_VECTOR_MIN, + + // Single-precision float + ZSSAT_FLOAT, + ZSSAT_FLOAT_VEC2, + ZSSAT_FLOAT_VEC3, + ZSSAT_FLOAT_VEC4, + + ZSSAT_VECTOR_MAX, + + // MATRIX TYPE + ZSSAT_MATRIX_MIN, + + // Single-precision float matrix + ZSSAT_MAT_22, + ZSSAT_MAT_23, + ZSSAT_MAT_24, + ZSSAT_MAT_32, + ZSSAT_MAT_33, + ZSSAT_MAT_34, + ZSSAT_MAT_42, + ZSSAT_MAT_43, + ZSSAT_MAT_44, + + ZSSAT_MATRIX_MAX, + + ZSSAT_SIZE, + ZSSAT_UNKNOWN +}; + +//Enumeration for types of shader uniform block member types +enum ZShaderUniformBlockMemberType +{ + //VECTOR TYPE + ZSUBMT_VECTOR_MIN, + + //Signed integer + ZSUBMT_INT, + ZSUBMT_INT_VEC2, + ZSUBMT_INT_VEC3, + ZSUBMT_INT_VEC4, + + //Unsigned integer + ZSUBMT_UINT, + ZSUBMT_UINT_VEC2, + ZSUBMT_UINT_VEC3, + ZSUBMT_UINT_VEC4, + + //Single-precision float + ZSUBMT_FLOAT, + ZSUBMT_FLOAT_VEC2, + ZSUBMT_FLOAT_VEC3, + ZSUBMT_FLOAT_VEC4, + + //Half-precision float + ZSUBMT_HALF, + ZSUBMT_HALF_VEC2, + ZSUBMT_HALF_VEC3, + ZSUBMT_HALF_VEC4, + + //Boolean + ZSUBMT_BOOL, + ZSUBMT_BOOL_VEC2, + ZSUBMT_BOOL_VEC3, + ZSUBMT_BOOL_VEC4, + + ZSUBMT_VECTOR_MAX, + + //MATRIX + ZSUBMT_MATRIX_MIN, + + //Single-precision float matrix + ZSUBMT_MAT_22, + ZSUBMT_MAT_23, + ZSUBMT_MAT_24, + ZSUBMT_MAT_32, + ZSUBMT_MAT_33, + ZSUBMT_MAT_34, + ZSUBMT_MAT_42, + ZSUBMT_MAT_43, + ZSUBMT_MAT_44, + + ZSUBMT_MATRIX_MAX, + + ZSUBMT_SIZE +}; + +//Enumeration of sampler types +enum ZShaderSamplerType +{ + ZSST_SAMPLER_1D, //1D texture map + ZSST_SAMPLER_2D, //2D texture map + ZSST_SAMPLER_3D, //3D texture map + ZSST_SAMPLER_CUBE, //Cubic texture map (unsupported) + ZSST_SAMPLER_1D_SHADOW, //1D shadow map (unsupported) + ZSST_SAMPLER_2D_SHADOW, //2D shadow map (unsupported) + ZSST_SIZE +}; + +//Struct defining a shader stream attribute +struct ZShaderStreamAttribute +{ + ZName Name; //The name of the attribute + size_t Size; //The size of the attribute in terms of elements (arrays have Size > 1) + size_t Index; //Index of this attribute in the attributes array + + ZShaderStreamAttributeType Type; //The type of the attribute +}; + +//Struct defining a uniform block member +struct ZShaderUniformBlockMember +{ + ZName Name; //Name of the member + size_t Offset; //Offset (within the block) to the member + size_t Size; //Size of the member in terms of elements (arrays have Size > 1) + size_t Index; //Index of this member in the member array + + size_t ArrayStride; //Stride between elements in an array (0 if not array) + + size_t MatrixStride; //Stride between columns (or rows) of a matrix type (0 if not matrix type) + enum { ROW_MAJOR, COLUMN_MAJOR } MatrixOrder; //Order of a matrix type (row or column) + + ZShaderUniformBlockMemberType Type; //Type of the member +}; + +//Struct defining a uniform block layout +struct ZShaderUniformBlock +{ + ZName Name; //Name of the block + size_t Size; //Size of the block (in bytes) + size_t Index; //Index of this block in the blocks array + + ZArray Members; //Members contained in the block + + /* + public ZShaderUniformBlock::GetMemberByName + + This lookup method is used to get a pointer to a member by name, or NULL if not found. + Bear in mind that the name is qualified by the block name. + + @param _name - the qualified name of the parameter + @return (const ZShaderUniformBlockMember*) - pointer to member if found, NULL if not found + */ + inline const ZShaderUniformBlockMember* GetMemberByName(const ZName& _name) const + { + for (size_t i = 0; i < Members.Size(); i++) { + if (Members.Data()[i].Name == _name) { + return &Members.Data()[i]; + } + } + + return NULL; + } +}; + +//Struct defining a shader sampler +struct ZShaderSampler +{ + ZName Name; //Name of the sampler + size_t Index; //Index of this sampler in the samplers array + + ZShaderSamplerType Type; //Type of the sampler +}; + +/* +Interface for a shader program. +*/ +class ZShaderProgram : public ZRendererResource +{ +public: + //Virtual Destructor + virtual ~ZShaderProgram() { } + + /* + virtual public ZShaderProgram::AttachShader + + Function to attach a shader. This will compile the shader. + + @param _shader - The shader to attach to this shader program. + @return (bool) - true if able to compile and attach the shader + @context (all) + */ + virtual bool AttachShader(ZPtr _shader) = 0; + + /* + virtual public ZShaderProgram::ClearLog + + Function to clear the log of a shader program. + + @return (void) + @context (all) + */ + virtual void ClearLog() = 0; + + /* + virtual public ZShaderProgram::DetachShaders + + Function to get the remove all attached shaders. + + @return (void) + @context (all) + */ + virtual void DetachShaders() = 0; + + /* + virtual public ZShaderProgram::GetLinkLog + + Function to get the link log of a shader program. + + @return (ZString) The log of the shader. + @context (all) + */ + virtual const ZString& GetLinkLog() = 0; + + /* + virtual public ZShaderProgram::GetShaders + + Function to get the an array of the currently attached shaders. + + @return (ZArray< ZPtr >) + @context (all) + */ + virtual const ZArray< ZPtr >& GetShaders() = 0; + + /* + virtual public ZShaderProgram::GetStreamAttributes + + Function to get the stream shader attributes declarations for a linked shader program. + + This returns an empty array until after linking. + + @return (const ZArray&) List of shader attributes. + @context (all) + */ + virtual const ZArray& GetStreamDeclarations() = 0; + + /* + virtual public ZShaderProgram::GetUniformBlockDeclarations + + Function to get the shader uniform block declarations for a linked shader program. + + This returns an empty array until after linking. + + @return (const ZArray&) + @context (all) + */ + virtual const ZArray& GetUniformBlockDeclarations() = 0; + + /* + virtual public ZShaderProgram::GetShaderSamplerDeclarations + + Function to get teh shader sampler declarations for a linked shader program. + + This returns an empty array until after linking. + + @return (const ZArray&) + @context (all) + */ + virtual const ZArray& GetShaderSamplerDeclarations() = 0; + + /* + virtual public ZShaderProgram::Link + + Function to link the attached shaders into a usable shader program object. + + @return (bool) True if successfully linked, false otherwise. + @context (all) + */ + virtual bool Link() = 0; + + /* + virtual public ZShaderProgram::IsUsable + + Function to see if shader program is usable. + + @return (bool) True if shader program is usable, false otherwise. + @context (all) + */ + virtual bool IsUsable() = 0; +}; + +#endif diff --git a/Include/ZRenderer/ZShaderProgramBase.hpp b/Include/ZRenderer/ZShaderProgramBase.hpp new file mode 100644 index 0000000..0aa35d0 --- /dev/null +++ b/Include/ZRenderer/ZShaderProgramBase.hpp @@ -0,0 +1,85 @@ +/* + ZShaderProgramBase.hpp + Author: Chris Ertel , + James Russell + Created: 04/03/2011 + + Purpose: + + ZShaderProgramBase handles the simple logistics for shader programs (e.g., log access, check usability). It + is intended to be extended by subclasses to handle implementation-specific issues. + + License: + + TODO + +*/ + +#pragma once + +#ifndef _ZSHADERPROGRAMBASE_HPP +#define _ZSHADERPROGRAMBASE_HPP + +#include + +#include + +class ZShaderProgramBase : public ZShaderProgram +{ +protected: + //Default Constructor + ZShaderProgramBase(); + + //Our attached shaders (currently only support vertex and fragment) + ZPtr VertexShader; + ZPtr FragmentShader; + + ZArray< ZPtr > Shaders; + + //Our cached set of uniform blocks, samplers, and vertex streams + ZArray UniformBlocks; + ZArray Samplers; + ZArray Streams; + + //Link log for shader program + ZString Log; + + //Flag for shader in usable state + bool bIsUsable; + +public: + //Virtual destructor + virtual ~ZShaderProgramBase(); + + //Subclass Implementation + virtual bool AttachShader(ZPtr _shader); + + //Subclass Implementation + virtual void ClearLog(); + + //Subclass Implementation + virtual void DetachShaders(); + + //Subclass Implementation + virtual const ZString& GetLinkLog(); + + //Subclass Implementation + virtual const ZArray& GetStreamDeclarations(); + + //Subclass Implementation + virtual const ZArray& GetUniformBlockDeclarations(); + + //Subclass Implementation + virtual const ZArray& GetShaderSamplerDeclarations(); + + //Subclass Implementation + virtual const ZArray< ZPtr >& GetShaders(); + + //Subclass Implementation + virtual bool IsUsable(); + + //Not Implemented + virtual bool Link() = 0; +}; + +#endif diff --git a/Include/ZRenderer/ZTexture.hpp b/Include/ZRenderer/ZTexture.hpp new file mode 100644 index 0000000..365c471 --- /dev/null +++ b/Include/ZRenderer/ZTexture.hpp @@ -0,0 +1,162 @@ +/* + ZTexture.hpp + Author: James Russell + Created: 04/06/2011 + + Purpose: + + Texture interface for the ZEngine. Texture instances are loaded and created by the + renderer, which acts as a factory for the correct type of texture. + + License: + + TODO +*/ + +#pragma once + +#ifndef _ZTEXTURE_HPP +#define _ZTEXTURE_HPP + +#include +#include + +#include +#include + +//Our maximum size for a texture +#ifndef ZT_MAX_TEXTURE_DIMENSION +#define ZT_MAX_TEXTURE_DIMENSION (8096) +#endif + +/* +Enumeration of texture types. Not all are currently supported. +*/ +enum ZTextureType +{ + ZTT_TEXTURE1D, //1D texture map + ZTT_TEXTURE2D, //2D texture map + ZTT_TEXTURE3D, //3D texture map (unsupported) + ZTT_TEXTURE_CUBE, //Cubic texture map (unsupported) + ZTT_SIZE +}; + +/* +Enumeration of internal storage format for texture types. +*/ +enum ZTextureFormat +{ + ZTF_R8, //8-bit Unsigned Red (Normalized) + ZTF_R8_SNORM, //8-bit Signed Red (Normalized) + ZTF_R8I, //8-bit Signed Red + ZTF_R8UI, //8-bit Unsigned Red + ZTF_R16, //16-bit Unsigned Red (Normalized) + ZTF_R16_SNORM, //16-bit Signed Red (Normalized) + ZTF_R16I, //16-bit Signed Red + ZTF_R16UI, //16-bit Unsigned Red + ZTF_R16F, //16-bit Floating Point Red + ZTF_R32I, //32-bit Signed Red + ZTF_R32UI, //32-bit Unsigned Red + ZTF_R32F, //32-bit Floating Point Red + + ZTF_RG8, //8-bit Unsigned Red, Green (Normalized) + ZTF_RG8_SNORM, //8-bit Signed Red, Green (Normalized) + ZTF_RG8I, //8-bit Signed Red, Green + ZTF_RG8UI, //8-bit Unsigned Red, Green + ZTF_RG16, //16-bit Unsigned Red, Green (Normalized) + ZTF_RG16_SNORM, //16-bit Signed Red, Green (Normalized) + ZTF_RG16I, //16-bit Signed Red, Green + ZTF_RG16UI, //16-bit Unsigned Red, Green + ZTF_RG16F, //16-bit Floating Point Red, Green + ZTF_RG32, //32-bit Unsigned Red, Green (Normalized) + ZTF_RG32_SNORM, //32-bit Signed Red, Green (Normalized) + ZTF_RG32I, //32-bit Signed Red, Green + ZTF_RG32UI, //32-bit Unsigned Red, Green + ZTF_RG32F, //32-bit Floating Point Red, Green + + ZTF_RGB8, //8-bit Unsigned Red, Green, Blue (Normalized) + ZTF_RGB8_SNORM, //8-bit Signed Red, Green, Blue (Normalized) + ZTF_RGB8I, //8-bit Signed Red, Green, Blue + ZTF_RGB8UI, //8-bit Unsigned Red, Green, Blue + ZTF_RGB16, //16-bit Unsigned Red, Green, Blue (Normalized) + ZTF_RGB16_SNORM, //16-bit Signed Red, Green, Blue (Normalized) + ZTF_RGB16I, //16-bit Signed Red, Green, Blue + ZTF_RGB16UI, //16-bit Unsigned Red, Green, Blue + ZTF_RGB16F, //16-bit Floating Point Red, Green, Blue + ZTF_RGB32, //32-bit Unsigned Red, Green, Blue (Normalized) + ZTF_RGB32_SNORM, //32-bit Signed Red, Green, Blue (Normalized) + ZTF_RGB32I, //32-bit Signed Red, Green, Blue + ZTF_RGB32UI, //32-bit Unsigned Red, Green, Blue + ZTF_RGB32F, //32-bit Floating Point Red, Green, Blue + + ZTF_RGBA8, //8-bit Unsigned Red, Green, Blue, Alpha (Normalized) + ZTF_RGBA8_SNORM, //8-bit Signed Red, Green, Blue, Alpha (Normalized) + ZTF_RGBA8I, //8-bit Signed Red, Green, Blue, Alpha + ZTF_RGBA8UI, //8-bit Unsigned Red, Green, Blue, Alpha + ZTF_RGBA16, //16-bit Unsigned Red, Green, Blue, Alpha (Normalized) + ZTF_RGBA16_SNORM, //16-bit Signed Red, Green, Blue, Alpha (Normalized) + ZTF_RGBA16I, //16-bit Signed Red, Green, Blue, Alpha + ZTF_RGBA16UI, //16-bit Unsigned Red, Green, Blue, Alpha + ZTF_RGBA16F, //16-bit Floating Point Red, Green, Blue, Alpha + ZTF_RGBA32, //32-bit Unsigned Red, Green, Blue, Alpha (Normalized) + ZTF_RGBA32_SNORM, //32-bit Signed Red, Green, Blue, Alpha (Normalized) + ZTF_RGBA32I, //32-bit Signed Red, Green, Blue, Alpha + ZTF_RGBA32UI, //32-bit Unsigned Red, Green, Blue, Alpha + ZTF_RGBA32F, //32-bit Floating Point Red, Green, Blue, Alpha + + ZTF_DEPTH16, //16-bit Depth Texture + ZTF_DEPTH24, //24-bit Depth Texture + ZTF_DEPTH32, //32-bit Depth Texture + ZTF_DEPTH24_STENCIL8, //32-bit Depth, 8-bit Stencil + + ZTF_SIZE +}; + +/* +Enumeration of texture usage types. +*/ +enum ZTextureUsage +{ + ZTU_STATIC, //Static Texture (never or rarely updated) + ZTU_DYNAMIC, //Dynamic Texture (updated frequently) + ZTU_STREAMING, //Streaming Texture (updated every frame) + ZTU_SIZE +}; + +class ZTexture : public ZRendererResource +{ +public: + //Virtual Destructor + virtual ~ZTexture() { } + + /* + virtual public ZTexture::GetType + + Gets the type of this texture. + + @return (ZTextureType) - the type of texture + */ + virtual ZTextureType GetType() = 0; + + /* + virtual public ZTexture::GetUsage + + Gets the usage type of this texture. + + @return (ZTextureUsage) + @context (all) + */ + virtual ZTextureUsage GetUsage() = 0; + + /* + public ZTexture::IsMipmapped + + Tells you whether or not this texture has been mipmapped. + + @return (bool) - true if mipmapped, false otherwise + @context (all) + */ + virtual bool IsMipmapped() = 0; +}; + +#endif diff --git a/Include/ZRenderer/ZVertexParams.hpp b/Include/ZRenderer/ZVertexParams.hpp new file mode 100644 index 0000000..722ca55 --- /dev/null +++ b/Include/ZRenderer/ZVertexParams.hpp @@ -0,0 +1,106 @@ +/* + ZVertexParams.hpp + Author: James Russell + Created: 7/1/2012 + + Purpose: + + TODO + + License: + + TODO + +*/ + +#pragma once + +#ifndef _ZVERTEXPARAMS_HPP +#define _ZVERTEXPARAMS_HPP + +#include + +#include + +#include + +#include + +#ifndef ZVP_MAX_STREAMS +#define ZVP_MAX_STREAMS (128) +#endif + +class ZVertexParams : public ZDrawParams +{ +private: + //A binding for a vertex stream + struct VertexStreamBinding + { + ZName Name; //Name of the stream attribute + ZPair Binding; //Pair Binding + }; + + //This is the bound vertex buffer and streams + ZPtr VertexBuffer; + VertexStreamBinding VertexStreams[ZVP_MAX_STREAMS]; + + //Our current set number of streams + size_t CurrentStreamCount; + +protected: + //Does this vertex parameter object need to be updated before rendered with? + bool Dirty; + +public: + /* + Default Constructor. + */ + ZVertexParams(); + + /* + public ZVertexParams::ClearStreams + + Clears the list of currently set streams. + + @return (void) + @context (all) + */ + void ClearVertexStreams(); + + /* + public ZVertexParams::SetStream + + Sets a vertex buffer stream. The vertex buffer provided to each call + of 'SetVertexStream' must be the same. + + @param _name - the name of the stream binding + @param _vertexBuffer - the vertex buffer to bind streams from + @param _stream - the stream definition + @return (void) + @context (all) + */ + void SetVertexStream(const ZName& _name, ZPtr _vertexBuffer, const ZDataBufferStream* _stream); + + /* + The following methods are used by the renderer to get the values needed when + binding shader parameter values to pass to the shader program, to mark + all bound resources as contended, and release contention. + */ + const ZPair* GetStreamByName(const ZName& _name); + + + ZDataBuffer* GetVertexBuffer(); + + bool IsDirty() const { return Dirty; } + + size_t GetStreamCount() const { return CurrentStreamCount; } + + //Subclass Override + virtual void MarkResourcesContended(); + + //Subclass Override + virtual void ReleaseResourceContention(); + +}; + +#endif diff --git a/Include/ZRenderer/ZWindowRenderTarget.hpp b/Include/ZRenderer/ZWindowRenderTarget.hpp new file mode 100644 index 0000000..45a51e1 --- /dev/null +++ b/Include/ZRenderer/ZWindowRenderTarget.hpp @@ -0,0 +1,106 @@ +/* + ZWindowRenderTarget.hpp + Author: James Russell + Created: 04/01/2011 + + Purpose: + + Interface class for a window render target. This interface requires that windows + be created and manipulated using libsst-wm. + + License: + + TODO +*/ + +#pragma once + +#ifndef _ZWINDOWRENDERTARGET_HPP +#define _ZWINDOWRENDERTARGET_HPP + +#include + +#include + +#include + +#include + +class ZWindowRenderTarget : public ZRenderTarget +{ +public: + //Virtual destructor + virtual ~ZWindowRenderTarget() { } + + /* + virtual public ZWindowRenderTarget::GetAutoSwapBuffers + + Gets the flag indicating whether or not this target will auto-swap buffers by the + renderer when used as a render target. + + @return (bool) + @context (all) + */ + virtual bool GetAutoSwapBuffers() = 0; + + /* + virtual public ZWindowRenderTarget::GetScreenIndex + + Gets the screen index held by this window render target. Used to interface with libsst-wm + functionality. + + @return (size_t) - the screen index + @context (all) + */ + virtual size_t GetScreenIndex() = 0; + + /* + virtual public ZWindowRenderTarget::GetWindowHandle + + Gets the window handle held by this window render target. Used to interface with + libsst-wm functionality. + + @return (SST_Window) - the window handle + */ + virtual SST_Window GetWindowHandle() = 0; + + /* + virtual public ZWindowRenderTarget::SetAutoSwapBuffers + + Indicates that the renderer should automatically swap buffers after a render is + complete with this render target. + + @param _value - true if we can, false if not + @return (bool) - true if able to set flag, false if resource contended + @context (all) + */ + virtual bool SetAutoSwapBuffers(bool _value) = 0; + + /* + virtual public ZWindowRenderTarget::SwapBuffers + + Swaps the buffers on the screen, bringing the back buffer to the front buffer. This should be called + every frame, and signals the end of the frame. This is only safe to call from within the render thread. + + @return (bool) - true if able to swapbuffers, false if resource contended + @context (renderer) + */ + virtual bool SwapBuffers() = 0; + + //Not Implemented + virtual const ZRenderTargetClearFlags& GetClearFlags() = 0; + + //Not Implemented + virtual size_t GetHeight() = 0; + + //Not Implemented + virtual ZRenderTargetType GetType() = 0; + + //Not Implemented + virtual size_t GetWidth() = 0; + + //Not Implemented + virtual bool SetClearFlags(const ZRenderTargetClearFlags& _flags) = 0; +}; + +#endif \ No newline at end of file diff --git a/Include/ZRenderer/ZWindowRenderTargetBase.hpp b/Include/ZRenderer/ZWindowRenderTargetBase.hpp new file mode 100644 index 0000000..ae77f61 --- /dev/null +++ b/Include/ZRenderer/ZWindowRenderTargetBase.hpp @@ -0,0 +1,88 @@ +/* + ZWindowRenderTargetBase.hpp + Author: James Russell + Created: 04/03/2011 + + Purpose: + + Base class for a window render target. + + License: + + TODO +*/ + +#pragma once + +#ifndef _ZWINDOWRENDERTARGETBASE_HPP +#define _ZWINDOWRENDERTARGETBASE_HPP + +#include + +class ZWindowRenderTargetBase : public ZWindowRenderTarget +{ +protected: + //The Window Handle + SST_Window WindowHandle; + + //The Screen Index + size_t ScreenIndex; + + //Our current clear flags + ZRenderTargetClearFlags ClearFlags; + + //Whether or not we should auto-swap buffers + bool bAutoSwapBuffers; + + /* + Parameterized Constructor. + + @param _window - the libsst-wm window handle to this render target + @param _screenIndex - the libsst-wm index of this screen + */ + ZWindowRenderTargetBase(SST_Window _window, size_t _screenIndex); + +public: + //Virtual Destructor + virtual ~ZWindowRenderTargetBase() { } + + /*************************/ + /* ZRenderTarget Methods */ + /*************************/ + + //Subclass Implementation + virtual const ZRenderTargetClearFlags& GetClearFlags(); + + //Subclass Implementation + virtual size_t GetHeight(); + + //Subclass Implementation + virtual ZRenderTargetType GetType(); + + //Subclass Implementation + virtual size_t GetWidth(); + + //Subclass Implementation + virtual bool SetClearFlags(const ZRenderTargetClearFlags& _flags); + + /***********************************/ + /* ZWindowRenderTargetBase Methods */ + /***********************************/ + + //Subclass Implementation + virtual bool GetAutoSwapBuffers(); + + //Subclass Implementation + virtual size_t GetScreenIndex(); + + //Subclass Implementation + virtual SST_Window GetWindowHandle(); + + //Subclass Implementation + virtual bool SetAutoSwapBuffers(bool _value); + + //Not Implemented + virtual bool SwapBuffers() = 0; +}; + +#endif \ No newline at end of file diff --git a/Include/ZRendererUtil/ZFontRenderer.hpp b/Include/ZRendererUtil/ZFontRenderer.hpp new file mode 100644 index 0000000..b00b6cc --- /dev/null +++ b/Include/ZRendererUtil/ZFontRenderer.hpp @@ -0,0 +1,164 @@ +/* + ZFontRenderer.h + Author: Patrick Baggett + + Purpose: TODO + + Changelog + 2011/09/18 - creation (ptbaggett) +*/ + +#pragma once + +#ifndef _ZFONTRENDERER_HPP +#define _ZFONTRENDERER_HPP + +#include + +#include + +//Font Face +typedef void* ZFontFace; + +//ZFontBounds struct, used as such +// top --- right +// | | +// left --- bottom +struct ZFontBounds +{ + //ZFontBounds of a rectangle (lower-left orientation) + int left, bottom, right, top; +}; + +class ZFontRenderer +{ +protected: + //Protected Constructor + ZFontRenderer() { } + +public: + //Virtual Destructor + virtual ~ZFontRenderer() { } + + /* + virtual public ZFontRenderer::createFontFace + + Creates a font face from a memory image of a font file. + + @param _pixelSize - The pixel size of a character. To use point size (ala MS Word), use (point size / 72.0) * DPI. + @param _fontData - The font file's data + @param _dataSize - The size in bytes of the file data. + @return (ZFontFace) + @context (all) + */ + virtual ZFontFace CreateFontFace(int _pixelSize, const void* _fontData, unsigned int _dataSize) = 0; + + /* + virtual public ZFontRenderer::deleteFontFace + + Deletes a font face. If this face is the currently active face, then the active face is set to NULL. + + @param face - The font face to delete. + @return (void) + @context (all) + */ + virtual void DeleteFontFace(ZFontFace face) = 0; + + /* + virtual public ZFontRenderer::beginText + + Sets up render state to begin drawing text. The only legal functions to call between beginText(), + and endText() are renderText(), computeBounds(), and setColor(). + + @param _ctx - The ZFrameContext for this frame + @param _xform - The transformation + @return (void) + @context (all) + */ + virtual void BeginText(ZFrameContext _ctx, const SST_Mat44f& _xform) = 0; + + /* + virtual public ZFontRenderer::endText + + Restores render state when done drawing text, flushes any buffered text. + + @return (void) + @context (all) + */ + virtual void EndText() = 0; + + /* + virtual public ZFontRenderer::renderText + + Renders text at the given XY location + + @param x - The left edge of the text + @param y - The bottom edge of the text + @param text - Some letters render below this line (e.g. the letter g's "tail"). + @return (void) + @context (all) + */ + virtual void RenderText(int x, int y, const char* text) = 0; + + /* + virtual public ZFontRenderer::computeBounds + + Computes the bounding box for text, as if it was placed at the origin. + + @param text - The text to compute a bounding box for. + @param bounds - Pointer to where the computed boundaries are stored. + @return (void) + @context (all) + */ + virtual void ComputeBounds(const char* text, ZFontBounds* bounds) = 0; + + /* + virtual public ZFontRenderer::setColor + + Sets the color of the text. Requires that there is a current font face, set with setFontFace(). + + @param r - The red component in the range of [0,1] + @param g - The green component in the range of [0,1] + @param b - The blue component in the range of [0,1] + @param a - The alpha (transparency) component in the range of [0,1] + @return (void) + @context (all) + */ + virtual void SetColor(float r, float g, float b, float a) = 0; + + /* + virtual public ZFontRenderer::setColor + + Sets a color with a packed 32-bit integer, converting to 4x32-bit floats first. Due to + endian-ness differences, don't typecast an char[4] to int* and then dereference it! + + @param rgba - The RGBA color stored as (hex) 0xRRGGBBAA + @return (void) + @context (all) + */ + virtual void SetColor(unsigned int rgba) = 0; + + /* + public ZFontRenderer::setFontFace + + Sets the current font face. + + @param face - The face to make current + @return (void) + @context (all) + */ + virtual void SetFontFace(ZFontFace face) = 0; + + /* + public ZFontRenderer::getFontFace + + Gets the current font face. + + @return (ZFontFace) - Handle to the current font face. It is not reference counted. + @context (all) + */ + virtual ZFontFace GetFontFace() = 0; + +}; + +#endif diff --git a/Include/ZRendererUtil/ZFontRendererBase.hpp b/Include/ZRendererUtil/ZFontRendererBase.hpp new file mode 100644 index 0000000..2b961e9 --- /dev/null +++ b/Include/ZRendererUtil/ZFontRendererBase.hpp @@ -0,0 +1,67 @@ +/* + ZFontRendererBase.h + Author: James Russell + + Purpose: TODO + + Changelog + 2011/09/18 - creation (jcrussell) +*/ + +#pragma once + +#ifndef _ZFONTRENDERERBASE_HPP +#define _ZFONTRENDERERBASE_HPP + +#include + +class ZFontRendererBase : public ZFontRenderer +{ +protected: + //Our current font face + ZFontFace currentFace; + +public: + /* + Default Constructor. + */ + ZFontRendererBase(); + + /* + Destructor. + */ + virtual ~ZFontRendererBase(); + + //Subclass Implementation + virtual ZFontFace GetFontFace(); + + //Subclass Implementation + virtual void SetColor(unsigned int rgba); + + //Subclass Implementation + virtual void SetFontFace(ZFontFace face); + + //Not Implemented + virtual ZFontFace CreateFontFace( int PixelSize, const void* fontData, unsigned int dataSize ) = 0; + + //Not Implemented + virtual void DeleteFontFace( ZFontFace face ) = 0; + + //Not Implemented + virtual void BeginText( ZFrameContext _ctx, const SST_Mat44f& _xform ) = 0; + + //Not Implemented + virtual void EndText() = 0; + + //Not Implemented + virtual void RenderText( int x, int y, const char* text ) = 0; + + //Not Implemented + virtual void ComputeBounds( const char* text, ZFontBounds* bounds ) = 0; + + //Not Implemented + virtual void SetColor( float r, float g, float b, float a ) = 0; +}; + +#endif + diff --git a/Include/ZRendererUtil/ZOutlineEvaluator.hpp b/Include/ZRendererUtil/ZOutlineEvaluator.hpp new file mode 100644 index 0000000..398a035 --- /dev/null +++ b/Include/ZRendererUtil/ZOutlineEvaluator.hpp @@ -0,0 +1,126 @@ +/* + ZOutlineEvaluator.h + Author: Patrick Baggett + + Purpose: TODO + + Changelog + 2011/09/18 - creation (ptbaggett) +*/ + +#pragma once + +#ifndef _ZOUTLINEEVALUATOR_H +#define _ZOUTLINEEVALUATOR_H + +#include +#include + +#include +#include +#include FT_FREETYPE_H + +class ZOutlineEvaluator +{ +private: + FT_Outline* outline; + int detail; + int curContour; + int* bounds; + std::vector pts; + + //Process a curve + int processCurve(int contour, int curveStart); + + //Evaluate a line segment + void evalLinear(FT_Vector* p0, FT_Vector* p1); + + //Evaluate a quadric path (called conic) + void evalQuadratic(FT_Vector* p0, FT_Vector* p1, FT_Vector* p2); + + //Evaluate a cubic path + void evalCubic(FT_Vector* p0, FT_Vector* p1, FT_Vector* p2, FT_Vector* p3); + + //Adds a point + void addPoint(const FT_Vector* pt); + +public: + /* + Constructor. + + @param _outline - + @param _detail - + */ + ZOutlineEvaluator(FT_Outline* _outline, int _detail); + + /* + Destructor. + */ + ~ZOutlineEvaluator(); + + /* + public ZOutlineEvaluator::evaluate + + TODO + + @return (void) + @context (all) + */ + void evaluate(); + + /* + public ZOutlineEvaluator::getContourCount + + TODO + + @return (int) + @context (all) + */ + int getContourCount() const; + + /* + public ZOutlineEvaluator::getContourStart + + TODO + + @param contour - + @return (int) + @context (all) + */ + int getContourStart(int contour) const; + + /* + public ZOutlineEvaluator::getContourEnd + + TODO + + @param contour - + @return (int) + @context (all) + */ + int getContourEnd(int contour) const; + + /* + public ZOutlineEvaluator::getPoint + + TODO + + @param pt - + @return (const SST_Vec2f*) + @context (all) + */ + const SST_Vec2f* getPoint(int pt) const; + + /* + public ZOutlineEvaluator::printContourPoints + + TODO + + @param contour - + @return (void) + @context (all) + */ + void printContourPoints(int contour); +}; + +#endif diff --git a/Include/ZRendererUtil/ZParticleEffect.h b/Include/ZRendererUtil/ZParticleEffect.h new file mode 100644 index 0000000..feee271 --- /dev/null +++ b/Include/ZRendererUtil/ZParticleEffect.h @@ -0,0 +1,140 @@ +/* + ZParticleEffect.h + Author: James Russell + + Purpose: A particle effect class which maintains a set of particle emitters. + + Changelog + 2011/08/28 - creation (jcrussell) +*/ + +#pragma once + +#ifndef _ZPARTICLEEFFECT_H +#define _ZPARTICLEEFFECT_H + +#include +#include + +class ZParticleEffect +{ +private: + //The name of this particle effect + ZString Name; + + //Boolean indicating this particle effect has completed + bool bIsFinished; + + //The emitters attached to this particle effect + ZArray< ZSmartPointer > Emitters; + +public: + /* + Default Constructor. + */ + ZParticleEffect(); + + /* + Parameterized Constructor. + + @param _name - the name of this particle effect + */ + ZParticleEffect(const ZString& _name); + + /* + Destructor. + */ + ~ZParticleEffect(); + + /* + public ZParticleEffect::AddEmitter + + Adds an emitter to this particle effect. The emitter will be updated and rendered when the + effect is. + + @param _emitter - the emitter to add + @return (void) + @context (all) + */ + void AddEmitter(ZPtr _emitter); + + /* + public ZParticleEffect::GetName + + Gets the name of this particle effect. + + @return (ZString) - the name of this effect + @context (all) + */ + ZString GetName(); + + /* + public ZParticleEffect::IsFinished + + Returns true if this particle effect is finished. + + @return (bool) - true if completed, false otherwise + @context (all) + */ + bool IsFinished(); + + /* + public ZParticleEffect::RemoveEmitter + + Removes an emitter from this particle effect. + + @param _emitter - the particle effect + @return (bool) - true if the emitter was contained, false otherwise + @context (all) + */ + bool RemoveEmitter(ZPtr _emitter); + + /* + public ZParticleEffect::Render + + Renders this particle effect using the provided renderer. + + @param _renderer - the renderer to use + @param _frameContext - the frame context to render with + @param _drawGroup - the draw group to render in + @return (void) + @context (all) + */ + void Render(ZRenderer* _renderer, ZFrameContext _frameContext, int _drawGroup = 0); + + /* + public ZParticleEffect::SetFinished + + Sets completion status of this effect to the provided value. + + @param _status - completion status (true if finished, false otherwise) + @return (void) + @context (all) + */ + void SetFinished(bool _status); + + /* + public ZParticleEffect::SetName + + Sets the name of this particle effect. + + @param _name - the name of this particle effect + @return (void) + @context (all) + */ + void SetName(const ZString& _name); + + /* + public ZParticleEffect::Update + + Updates this particle effect with the provided delta time since last call to update. + + @param _dt - the time (in milliseconds) since the last call to Update + @return (void) + @context (all) + */ + void Update(size_t _dt); +}; + +#endif + \ No newline at end of file diff --git a/Include/ZRendererUtil/ZParticleEmitter.h b/Include/ZRendererUtil/ZParticleEmitter.h new file mode 100644 index 0000000..cc1e595 --- /dev/null +++ b/Include/ZRendererUtil/ZParticleEmitter.h @@ -0,0 +1,200 @@ +/* + ZParticleEmitter.h + Author: James Russell + + Purpose: Particle emitter class, which maintains a set of strategies used to store, create, update, and render + particles. + + Changelog + 2011/08/28 - creation (jcrussell) +*/ + +#pragma once + +#ifndef _ZPARTICLEEMITTER_H +#define _ZPARTICLEEMITTER_H + +#include +#include +#include +#include +#include + +//Forward Declaration +class ZParticleEffect; + +class ZParticleEmitter +{ +protected: + //Number of particles at a time this emitter supports + size_t MaxParticles; + + //Boolean indicating this emitter is complete (no longer emits particles) + bool bIsFinished; + + //The transform for the particle emitter + ZMatrix44f Transform; + + //Particle Generator + ZPtr StorageAllocator; + + //Particle Spawn Strategy + ZPtr SpawnStrategy; + + //Particle Update Strategy + ZPtr UpdateStrategy; + + //Particle Render Strategy + ZPtr RenderStrategy; + +public: + /* + Default Constructor. + */ + ZParticleEmitter(); + + /* + Destructor. + */ + ~ZParticleEmitter(); + + /* + public ZParticleEmitter::GetMaxParticles + + Returns the current amount of max particles this particle emitter supports. + + @return (size_t) + @context (all) + */ + size_t GetMaxParticles(); + + /* + public ZParticleEmitter::GetTransform + + Gets the local transform for this particle emitter. + + @return (ZMatrix44f) - local transform for this emitter + @context (all) + */ + ZMatrix44f GetTransform(); + + /* + public ZParticleEmitter::IsFinished + + Returns true if this particle emitter will no longer emit particles. + + @return (bool) - true if finished, false otherwise + @context (all) + */ + bool IsFinished(); + + /* + public ZParticleEmitter::Render + + Renders the contained particles using the provided render strategy. + + @param _particleEffect - the parent particle effect + @param _renderer - the renderer to use + @param _context - frame context to render with + @param _drawGroup - the draw group to render with + @return (void) + @context (all) + */ + void Render(ZParticleEffect* _particleEffect, ZRenderer* _renderer, ZFrameContext _context, int _drawGroup); + + /* + public ZParticleEmitter::SetMaxParticles + + Sets the maximum number of particles this emitter supports. + + @param _maxParticles - the maximum particle count + @return (void) + @context (all) + */ + void SetMaxParticles(size_t _maxParticles); + + /* + public ZParticleEmitter::SetFinished + + Sets completion status of this emitter to the provided value. + + @param _status - completion status (true if finished, false otherwise) + @return (void) + @context (all) + */ + void SetFinished(bool _status); + + /* + public ZParticleEmitter::SetParticleStorageAllocator + + Sets the particle storage allocator for this particle emitter. This will call + ZParticleStorageAllocator::AllocateParticleStorage. + + @param _allocator - the allocator to use + @param _maxParticles - the number of particles to allocate storage for + @return (ZPtr) - the storage allocator that was previously attached + @context (all) + */ + ZPtr SetParticleStorageAllocator(ZPtr _allocator, size_t _maxParticles); + + /* + public ZParticleEmitter::SetParticleSpawnStrategy + + Sets the particle span strategy for this particle emitter. + + @param _spawnStrategy - the spawn strategy to use + @return (ZPtr) - the spawn strategy that was previously attached + @context (all) + */ + ZPtr SetParticleSpawnStrategy(ZPtr _spawnStrategy); + + /* + public ZParticleEmitter::SetParticleUpdateStrategy + + Sets the particle update strategy for this particle emitter. + + @param _updateStrategy - the particle update strategy to use + @return (ZPtr) - the update strategy that was previously attached + @context (all) + */ + ZPtr SetParticleUpdateStrategy(ZPtr _updateStrategy); + + /* + public ZParticleEmitter::SetParticleRenderStrategy + + Sets the render strategy for this particle emitter. This will call AllocateBuffers on the render strategy. + + @param _renderStrategy - the render strategy to use + @param _renderer - the renderer to allocate buffers from + @return (ZPtr) - the render strategy that was previously attached + @context (all) + */ + ZPtr SetParticleRenderStrategy(ZPtr _renderStrategy, ZRenderer *_renderer); + + /* + public ZParticleEmitter::SetTransform + + Sets the transform for this particle emitter. + + @param _transform - the transform to use + @return (void) + @context (all) + */ + void SetTransform(ZMatrix44f _transform); + + /* + public ZParticleEmitter::Update + + Runs through the various installed strategies, which can will both create new particles (as dictated by strategy) + and update existing ones. + + @param _particleEffect - the parent particle effect + @param _dt - the time (in milliseconds) since last update + @return (void) + @context (all) + */ + void Update(ZParticleEffect* _particleEffect, size_t _dt); +}; + +#endif + diff --git a/Include/ZRendererUtil/ZParticleRenderStrategy.h b/Include/ZRendererUtil/ZParticleRenderStrategy.h new file mode 100644 index 0000000..f38c596 --- /dev/null +++ b/Include/ZRendererUtil/ZParticleRenderStrategy.h @@ -0,0 +1,80 @@ +/* + ZParticleRenderStrategy.h + Author: James Russell + + Purpose: TODO + + Changelog + 2011/08/28 - creation (jcrussell) +*/ + +#pragma once + +#ifndef _ZPARTICLERENDERSTRATEGY_H +#define _ZPARTICLERENDERSTRATEGY_H + +#include +#include +#include + +//Forward Declarations +class ZParticleEffect; +class ZParticleEmitter; +class ZParticleStorageAllocator; + +class ZParticleRenderStrategy +{ +public: + //Virtual Destructor + ~ZParticleRenderStrategy() { } + + /* + public ZParticleRenderStrategy::AllocateBuffers + + Called when the particle render strategy needs to allocate buffers from the renderer + for particle data. + + @param _maxParticles - the number of particles to allocate buffer space for + @param _renderer - the renderer to allocate buffers from + @return (void) + @context (all) + */ + virtual void AllocateBuffers(size_t _maxParticles, ZRenderer *_renderer) = 0; + + /* + virtual public ZParticleRenderStrategy::CheckParticleFormat + + Checks to see if this render strategy can render the provided particle format. + + @param _format - string description of the particle format + @return (bool) - true if this render strategy can handle it, false otherwise + @context (all) + */ + virtual bool CheckParticleFormat(const ZString& _format) = 0; + + /* + virtual public ZParticleUpdateStrategy::RenderParticles + + Renders the particle data present in particle storage. + + @param _particleEffect - the emitter's parent particle effect + @param _particleEmitter - the parent emitter + @param _storageAllocator - the particle data storage + @param _renderer - the renderer to render to + @param _frameContext - the frame context to render with + @return (void) + @context (all) + */ + virtual void RenderParticles(ZParticleEffect* _particleEffect, + ZParticleEmitter* _particleEmitter, + ZParticleStorageAllocator* _storageAllocator, + ZRenderer* _renderer, + ZFrameContext _frameContext, + const ZMatrix44f& _transform, + int _drawGroup + ) = 0; + +}; + +#endif + diff --git a/Include/ZRendererUtil/ZParticleSpawnStrategy.h b/Include/ZRendererUtil/ZParticleSpawnStrategy.h new file mode 100644 index 0000000..39ce470 --- /dev/null +++ b/Include/ZRendererUtil/ZParticleSpawnStrategy.h @@ -0,0 +1,61 @@ +/* + ZParticleSpawnStrategy.h + Author: James Russell + + Purpose: TODO + + Changelog + 2011/08/28 - creation (jcrussell) +*/ + +#pragma once + +#ifndef _ZPARTICLESPAWNSTRATEGY_H +#define _ZPARTICLESPAWNSTRATEGY_H + +#include + +//Forward Declarations +class ZParticleEffect; +class ZParticleEmitter; +class ZParticleStorageAllocator; + +class ZParticleSpawnStrategy +{ +public: + //Virtual Destructor + ~ZParticleSpawnStrategy() { } + + /* + virtual public ZParticleSpawnStrategy::CheckParticleFormat + + Checks to see if this spawn strategy can spawn the provided particle format. + + @param _format - string description of the particle format + @return (bool) - true if this spawn strategy can handle it, false otherwise + @context (all) + */ + virtual bool CheckParticleFormat(const ZString& _format) = 0; + + /* + virtual public ZParticleSpawnStrategy::UpdateSpawn + + An update call to the spawn strategy that determines if more particles should be created. If so, the new particle data + can be placed directly into particle storage. + + @param _particleEffect - the emitter's parent particle effect + @param _particleEmitter - the parent emitter + @param _storageAllocator - particle storage used by this particle effect + @param _dt - the time (in milliseconds) since last update + @return (void) + @context (all) + */ + virtual void UpdateSpawn(ZParticleEffect* _particleEffect, + ZParticleEmitter* _particleEmitter, + ZParticleStorageAllocator* _storageAllocator, + size_t _dt + ) = 0; +}; + +#endif + diff --git a/Include/ZRendererUtil/ZParticleStorageAllocator.h b/Include/ZRendererUtil/ZParticleStorageAllocator.h new file mode 100644 index 0000000..19aaacb --- /dev/null +++ b/Include/ZRendererUtil/ZParticleStorageAllocator.h @@ -0,0 +1,82 @@ +/* + ZParticleGenerator.h + Author: James Russell + + Purpose: The particle generator is responsible for generating / allocating the particle data + and storing it for the duration the particle emitter is alive. + + Also responsible for cleanup. + + Changelog + 2011/08/28 - creation (jcrussell) +*/ + +#pragma once + +#ifndef _ZPARTICLESTORAGEALLOCATOR_H +#define _ZPARTICLESTORAGEALLOCATOR_H + +#include + +//Forward Declaration +class ZParticleEffect; +class ZParticleEmitter; + +class ZParticleStorageAllocator +{ +public: + //Virtual Destructor + virtual ~ZParticleStorageAllocator() { } + + /* + virtual public ZParticleGenerator::AllocateParticleStorage + + Allocates particle storage for this particle emitter. + + @param _emitter - the emitter we are creating storage for + @param _maxParticles - the number of particles we allocate storage for + @return (void) + @context (all) + */ + virtual void AllocateParticleStorage(ZParticleEmitter* _emitter, size_t _maxParticles) = 0; + + /* + virtual public ZParticleGenerator::DeallocateParticleStorage + + Deallocates storage previously allocated with AllocateParticleStorage. + + @return (void) + @context (all) + */ + virtual void DeallocateParticleStorage() = 0; + + /* + virtual public ZParticleStorageAllocator::GetParticleFormat + + Returns a string 'type' indicating the type of particle storage used by this allocator. Checked + against the other strategies to ensure compatibility. + + @return (ZString) + @context (all) + */ + virtual ZString GetParticleFormat() = 0; + + /* + virtual public ZParticleStorageAllocator::Update + + Updates the storage allocator, indicating another frame has passed. + + @param _effect - the particle effect + @param _emitter - the particle emitter + @param _dt - amount of time passed (in ms) + @return (void) + @context (all) + */ + virtual void Update(ZParticleEffect *_effect, + ZParticleEmitter *_emitter, + size_t _dt + ) = 0; +}; + +#endif + \ No newline at end of file diff --git a/Include/ZRendererUtil/ZParticleUpdateStrategy.h b/Include/ZRendererUtil/ZParticleUpdateStrategy.h new file mode 100644 index 0000000..9e5860c --- /dev/null +++ b/Include/ZRendererUtil/ZParticleUpdateStrategy.h @@ -0,0 +1,60 @@ +/* + ZParticleUpdateStrategy.h + Author: James Russell + + Purpose: TODO + + Changelog + 2011/08/28 - creation (jcrussell) +*/ + +#pragma once + +#ifndef _ZPARTICLEUPDATESTRATEGY_H +#define _ZPARTICLEUPDATESTRATEGY_H + +#include + +//Forward Declarations +class ZParticleEffect; +class ZParticleEmitter; +class ZParticleStorageAllocator; + +class ZParticleUpdateStrategy +{ +public: + //Virtual Destructor + ~ZParticleUpdateStrategy() { } + + /* + virtual public ZParticleUpdateStrategy::CheckParticleFormat + + Checks to see if this update strategy can update the provided particle format. + + @param _format - string description of the particle format + @return (bool) - true if this udpate strategy can handle it, false otherwise + @context (all) + */ + virtual bool CheckParticleFormat(const ZString& _format) = 0; + + /* + virtual public ZParticleUpdateStrategy::UpdateParticles + + Updates the particle data present in particle storage. + + @param _particleEffect - the emitter's parent particle effect + @param _particleEmitter - the parent emitter + @param _storageAllocator - the particle data storage + @param _dt - the time (in millisecond) since last update + @return (void) + @context (all) + */ + virtual void UpdateParticles(ZParticleEffect* _particleEffect, + ZParticleEmitter* _particleEmitter, + ZParticleStorageAllocator* _storageAllocator, + size_t _dt + ) = 0; +}; + +#endif + \ No newline at end of file diff --git a/Include/ZRendererUtil/ZPerspectiveCamera.hpp b/Include/ZRendererUtil/ZPerspectiveCamera.hpp new file mode 100644 index 0000000..7c6492b --- /dev/null +++ b/Include/ZRendererUtil/ZPerspectiveCamera.hpp @@ -0,0 +1,145 @@ +#include + +//Perspective Camera Class, Used to compute camera transforms +class ZPerspectiveCamera +{ +protected: + bool transformDirty; //Dirty flag for computing camera transform + + SST_Mat44f CameraTransform; + + SST_Vec3f EyePoint; + SST_Vec3f ForwardVec; + SST_Vec3f UpVec; + SST_Vec3f RightVec; + + float NearClip; + float FarClip; + float XFov; + float AspectRatio; + + void ComputeCameraTransform() + { + SST_Mat44f perspectiveMatrix; + SST_Mat44f viewMatrix; + SST_Vec3f target = {ForwardVec.x + EyePoint.x, + ForwardVec.y + EyePoint.y, + ForwardVec.z + EyePoint.z}; + + SST_Math_Mat44fCreatePerspective(&perspectiveMatrix, this->XFov, this->AspectRatio, this->NearClip, this->FarClip); + SST_Math_Mat44fCreateLookAt(&viewMatrix, &this->EyePoint, &target, &this->UpVec); + SST_Math_Mat44fMultiplyMatrix(&perspectiveMatrix, &viewMatrix, &this->CameraTransform); + + this->transformDirty = false; + } + + //Flags the transform as 'dirty' + void FlagTransforms() + { + this->transformDirty = true; + } + +public: + ZPerspectiveCamera() + { + SST_Vec3f eye = { 0, 0, 0 }; + SST_Vec3f forward = { 0, 1, 0 }; + SST_Vec3f up = { 0, 0, 1 }; + SST_Vec3f right = { 1, 0, 1 }; + + SetEyePoint(&eye); + SetForwardVec(&forward); + SetUpVec(&up); + SetRightVec(&right); + + NearClip = 1.0f; + FarClip = 10000.0f; + XFov = 90.0f; + AspectRatio = 1.0f; + + this->transformDirty = true; + } + + //Getters for camera data + const SST_Vec3f* GetEyePoint() { return &EyePoint; } + const SST_Vec3f* GetForwardVec() { return &ForwardVec; } + const SST_Vec3f* GetUpVec() { return &UpVec; } + const SST_Vec3f* GetRightVec() { return &RightVec; } + float GetNearClip() { return NearClip; } + float GetFarClip() { return FarClip; } + float GetXFov() { return XFov; } + float GetAspectRatio() { return AspectRatio; } + + //Setters for camera data. Will flag the transform as 'dirty' + void SetEyePoint(const SST_Vec3f* _eye) { EyePoint = *_eye; FlagTransforms(); } + void SetForwardVec(const SST_Vec3f* _forward) { ForwardVec = *_forward; FlagTransforms(); } + void SetUpVec(const SST_Vec3f* _up) { UpVec = *_up; FlagTransforms(); } + void SetRightVec(const SST_Vec3f* _right) { RightVec = *_right; FlagTransforms(); } + + void SetNearClip(float _nearClip) { NearClip = _nearClip; FlagTransforms(); } + void SetFarClip(float _farClip) { FarClip = _farClip; FlagTransforms(); } + void SetXFov(float _xFov) { XFov = _xFov; FlagTransforms(); } + void SetAspectRatio(float _ratio) { AspectRatio = _ratio; FlagTransforms(); } + + //Movement methods, which move the camera in the direction if it's basis vectors by a factor + void MoveForward(float t) + { + SST_Vec3f tmp; + + SST_Math_Vec3fScale(&ForwardVec, t, &tmp); + SST_Math_Vec3fAddLocal(&EyePoint, &tmp); + + FlagTransforms(); + } + + void MoveUp(float t) + { + SST_Vec3f tmp; + + SST_Math_Vec3fScale(&UpVec, t, &tmp); + SST_Math_Vec3fAddLocal(&EyePoint, &tmp); + + FlagTransforms(); + } + + void MoveRight(float t) + { + SST_Vec3f tmp; + + SST_Math_Vec3fScale(&RightVec, t, &tmp); + SST_Math_Vec3fAddLocal(&EyePoint, &tmp); + FlagTransforms(); + } + + //Rotation Methods, which rotate the camera about it's basis vectors + void RotateUp(float t) + { + SST_Math_Vec3fRotateAboutLocal(&this->ForwardVec, &this->RightVec, t); + SST_Math_Vec3fRotateAboutLocal(&this->UpVec, &this->RightVec, t); + FlagTransforms(); + } + + void RotateRight(float t) + { + SST_Math_Vec3fRotateAboutLocal(&this->ForwardVec, &this->UpVec, t); + SST_Math_Vec3fRotateAboutLocal(&this->RightVec, &this->UpVec, t); + FlagTransforms(); + } + + void RotateClockwise(float t) + { + SST_Math_Vec3fRotateAboutLocal(&this->UpVec, &this->ForwardVec, t); + SST_Math_Vec3fRotateAboutLocal(&this->RightVec, &this->ForwardVec, t); + FlagTransforms(); + } + + //Camera transform getters, which will trigger a recompute of the transform matrix if need be + const SST_Mat44f* GetCameraTransform() + { + if (this->transformDirty) + { + this->ComputeCameraTransform(); + } + return &this->CameraTransform; + } +}; \ No newline at end of file diff --git a/Include/ZRendererUtil/ZSolidFontFace.hpp b/Include/ZRendererUtil/ZSolidFontFace.hpp new file mode 100644 index 0000000..9405832 --- /dev/null +++ b/Include/ZRendererUtil/ZSolidFontFace.hpp @@ -0,0 +1,84 @@ +/* + ZSolidFontFace.hpp + Author: Patrick Baggett + + Purpose: TODO + + Changelog + 2011/09/18 - creation (ptbaggett) +*/ + +#pragma once + +#ifndef _ZSOLIDFONTFACE_HPP +#define _ZSOLIDFONTFACE_HPP + +#include + +#include //Need ZFontBounds structure + +//#include +#include +#include FT_FREETYPE_H +#include FT_GLYPH_H + +//Needed for friend class definition +class ZSolidFontRenderer; + +// Structure representing glyph information for use in solid font rendering +struct ZSolidGlyphInfo +{ + FT_UInt glyphId; // Glyph ID, as read from the font + ZArray verts; // Vertex data, every 3 vertices makes a triangle + int advancex; // Amount along X axis to advance pen by, in pixels + int advancey; // Amount along Y axis to advance pen by, in pixels + ZFontBounds bbox; // Bounding box of this glyph, in pixels +}; + +//Class representing a font face created by a SolidFontRenderer +class ZSolidFontFace +{ +friend class ZSolidFontRenderer; +private: + FT_Face face; + char* fontData; + int hasKerning; + + ZHashMap glyphCache; + +public: + + /* + Default Constructor. + */ + ZSolidFontFace(); + + /* + Destructor. + */ + ~ZSolidFontFace(); + + /* + public ZSolidFontFace::cacheGlyph + + Caches a glyph, given a UTF-32 character code. The glyph must not already be loaded. + + @param charCode - The UTF-32 character code for this glyph + @return (const ZSolidGlyphInfo&) - Reference to the glyph information. + @context (all) + */ + const ZSolidGlyphInfo& CacheGlyph(unsigned int charCode); + + /* + public ZSolidFontFace::getGlyph + + Gets a glyph from the cache, or loads it if necessary. + + @param charCode - + @return (const ZSolidGlyphInfo*) + @context (all) + */ + const ZSolidGlyphInfo* GetGlyph(unsigned int charCode); +}; + +#endif diff --git a/Include/ZRendererUtil/ZSolidFontRenderer.hpp b/Include/ZRendererUtil/ZSolidFontRenderer.hpp new file mode 100644 index 0000000..7a1e199 --- /dev/null +++ b/Include/ZRendererUtil/ZSolidFontRenderer.hpp @@ -0,0 +1,101 @@ +/* + ZSolidFontRenderer.hpp + Author: Patrick Baggett + + Purpose: TODO + + Changelog + 2011/09/18 - creation (ptbaggett) +*/ + +#pragma once + +#ifndef _ZSOLIDFONTRENDERER_H +#define _ZSOLIDFONTRENDERER_H + +#include + +#include +#include +#include +#include + +#include +#include FT_FREETYPE_H + +#define TRICACHE_SIZE (8*1024) //Cache up to 8K polygons before drawing + +class ZSolidFontRenderer : public ZFontRendererBase +{ +protected: + ZRenderer* renderer; + ZPtr tricache; + + const ZDataBufferStream* posstream; + const ZDataBufferStream* colorstream; + const ZDataBufferBlock* matrixBlock; + const ZDataBufferBlock* indexBlock; + + ZPtr shaderprogram; + ZPtr shaderparams; + ZPtr indexparams; + ZPtr vertexparams; + + ZPtr uniforms; + ZPtr indexes; + + ZFrameContext ctx; + SST_Mat44f xform; + + //Internal used struct for vertex / color pairing + struct SolidVertex + { + float x, y; + float rgba[4]; + }; + + SolidVertex* vtx_dma; + FT_Library library; + float color[4]; + size_t nrTrisWritten; + bool inRendering; + + void flushTriCache(); + +public: + + /* + Constructor. + + @param _renderer - the current renderer instance. + */ + ZSolidFontRenderer(ZRenderer* _renderer); + + /* + Destructor. + */ + virtual ~ZSolidFontRenderer(); + + //Subclass Implementation + virtual ZFontFace CreateFontFace(int pixelSize, const void* fontData, unsigned int dataSize); + + //Subclass Implementation + virtual void DeleteFontFace(ZFontFace face); + + //Subclass Implementation + virtual void BeginText(ZFrameContext _ctx, const SST_Mat44f& _xform); + + //Subclass Implementation + virtual void EndText(); + + //Subclass Implementation + virtual void RenderText(int x, int y, const char* text); + + //Subclass Implementation + virtual void ComputeBounds(const char* text, ZFontBounds* bounds); + + //Subclass Implementation + virtual void SetColor(float r, float g, float b, float a); +}; + +#endif \ No newline at end of file diff --git a/Include/ZRendererUtil/ZStandardParticleRenderStrategy.h b/Include/ZRendererUtil/ZStandardParticleRenderStrategy.h new file mode 100644 index 0000000..266d98b --- /dev/null +++ b/Include/ZRendererUtil/ZStandardParticleRenderStrategy.h @@ -0,0 +1,105 @@ +/* + ZStandardParticleRenderStrategy.h + Author: James Russell + + Purpose: TODO + + Changelog + 2011/09/11 - creation (jcrussell) +*/ + +#pragma once + +#ifndef _ZSTANDARDPARTICLERENDERSTRATEGY_H +#define _ZSTANDARDPARTICLERENDERSTRATEGY_H + +#include +#include + +class ZStandardParticleRenderStrategy : public ZParticleRenderStrategy +{ +protected: + //Vertex buffer + ZPtr VertexBuffer; + + //Index buffer + ZPtr IndexBuffer; + + //Material we use + ZPtr ParticleMaterial; + + //Texture we'll be using + ZPtr ParticleTexture; + + //Our render state + ZRenderState RenderState; + + //Our UV coordinates (per vertex) + float UVs[8]; + +public: + /* + Constructor. + + @param _maxParticles - maximum number of particles we will use + @param _renderer - the renderer instance + */ + ZStandardParticleRenderStrategy(); + + /* + Destructor. + */ + ~ZStandardParticleRenderStrategy(); + + /* + public ZStandardParticleRenderStrategy::SetParticleTexture + + TODO + + @param _texture - + @return (void) + @context (all) + */ + void SetParticleTexture(ZPtr _texture); + + /* + public ZStandardParticleRenderStrategy::SetParticleTextureUVs + + TODO + + @param _uvs - uv coordinate array (size 8) + @return (void) + @context (all) + */ + void SetParticleTextureUVs(float *_uvs); + + /* + public ZStandardParticleRenderStrategy::SetRenderState + + TODO + + @param _state - + @return (void) + @context (all) + */ + void SetRenderState(ZRenderState _state); + + //Subclass Override + void AllocateBuffers(size_t _maxParticles, ZRenderer *_renderer); + + //Subclass Override + virtual bool CheckParticleFormat( const ZString& _format ); + + //Subclass Override + virtual void RenderParticles(ZParticleEffect* _particleEffect, + ZParticleEmitter* _particleEmitter, + ZParticleStorageAllocator* _storageAllocator, + ZRenderer* _renderer, + ZFrameContext _frameContext, + const ZMatrix44f& _transform, + int _drawGroup ); + +}; + +#endif + diff --git a/Include/ZRendererUtil/ZStandardParticleSpawnStrategy.h b/Include/ZRendererUtil/ZStandardParticleSpawnStrategy.h new file mode 100644 index 0000000..88390b9 --- /dev/null +++ b/Include/ZRendererUtil/ZStandardParticleSpawnStrategy.h @@ -0,0 +1,218 @@ +/* + ZStandardParticleSpawnStrategy.h + Author: James Russell + + Purpose: TODO + + Changelog + 2011/09/11 - creation (jcrussell) +*/ + +#pragma once + +#ifndef _ZSTANDARDPARTICLESPAWNSTRATEGY_H +#define _ZSTANDARDPARTICLESPAWNSTRATEGY_H + +#define ZSP_DEFAULT_SPAWN_MASS (1) + +#define ZSP_DEFAULT_SPAWN_ENERGY (1000) + +#define ZSP_DEFAULT_SPAWN_VELOCITY_X (0.0f) +#define ZSP_DEFAULT_SPAWN_VELOCITY_Y (0.0f) +#define ZSP_DEFAULT_SPAWN_VELOCITY_Z (0.0f) + +#define ZSP_DEFAULT_SPAWN_FACING_X (0.0f) +#define ZSP_DEFAULT_SPAWN_FACING_Y (0.0f) +#define ZSP_DEFAULT_SPAWN_FACING_Z (1.0f) + +#define ZSP_DEFAULT_SPAWN_SCALE_X (1.0f) +#define ZSP_DEFAULT_SPAWN_SCALE_Y (1.0f) + +#define ZSP_DEFAULT_SPAWN_COLOR_R (1.0f) +#define ZSP_DEFAULT_SPAWN_COLOR_G (1.0f) +#define ZSP_DEFAULT_SPAWN_COLOR_B (1.0f) +#define ZSP_DEFAULT_SPAWN_COLOR_A (1.0f) + +#define ZSP_DEFAULT_TEXTURE_U (0.0f) +#define ZSP_DEFAULT_TEXTURE_V (0.0f) +#define ZSP_DEFAULT_TEXTURE_OFFSET (1.0f) + +#define ZSP_DEFAULT_SPAWN_INTERVAL (100) +#define ZSP_DEFAULT_SPAWN_ANGLE (0.0f) +#define ZSP_DEFAULT_SPAWN_COUNT_MIN (0) +#define ZSP_DEFAULT_SPAWN_COUNT_MAX (1) + +#include +#include + +class ZStandardParticleSpawnStrategy : public ZParticleSpawnStrategy +{ +private: + //The time until our next spawn + int NextSpawn; + + //Our current spawn group + size_t CurrentSpawnGroup; + +protected: + //Template for the particle we will be spawning with + ZStandardParticle TemplateParticle; + + //The span between particle spawns + size_t SpawnInterval; + + //The half-angle we deviate within when spawning a particle [0.0 - pi] + float SpawnAngle; + + //The particle count spawn range (lower, upper) + ZPair SpawnCountRange; + +public: + /* + Default Constructor. + */ + ZStandardParticleSpawnStrategy(); + + /* + Destructor. + */ + virtual ~ZStandardParticleSpawnStrategy(); + + //Subclass Override + virtual bool CheckParticleFormat( const ZString& _format ); + + //Subclass Override + virtual void UpdateSpawn(ZParticleEffect* _particleEffect, + ZParticleEmitter* _particleEmitter, + ZParticleStorageAllocator* _storageAllocator, + size_t _dt ); + + /* + public ZStandardParticleSpawnStrategy::GetSpawnAngle + + TODO + + @return (float) + @context (all) + */ + float GetSpawnAngle(); + + /* + public ZStandardParticleSpawnStrategy::GetSpawnColor + + TODO + + @return (const ZVector4f&) + @context (all) + */ + const ZVector4f& GetSpawnColor(); + + /* + public ZStandardParticleSpawnStrategy::GetSpawnEnergy + + TODO + + @return (size_t) + @context (all) + */ + size_t GetSpawnEnergy(); + + /* + public ZStandardParticleSpawnStrategy::GetSpawnInterval + + TODO + + @return (size_t) + @context (all) + */ + size_t GetSpawnInterval(); + + /* + public ZStandardParticleSpawnStrategy::GetSpawnScale + + TODO + + @return (const ZVector2f&) + @context (all) + */ + const ZVector2f& GetSpawnScale(); + + /* + public ZStandardParticleSpawnStrategy::GetSpawnVelocity + + TODO + + @return (const ZVector3f&) + @context (all) + */ + const ZVector3f& GetSpawnVelocity(); + + /* + public ZStandardParticleSpawnStrategy::SetSpawnAngle + + TODO + + @param _angle - + @return (void) + @context (all) + */ + void SetSpawnAngle(float _angle); + + /* + public ZStandardParticleSpawnStrategy::SetSpawnColor + + TODO + + @param _color - + @return (void) + @context (all) + */ + void SetSpawnColor(const ZVector4f& _color); + + /* + public ZStandardParticleSpawnStrategy::SetSpawnEnergy + + TODO + + @param _energy - + @return (void) + @context (all) + */ + void SetSpawnEnergy(size_t _energy); + + /* + public ZStandardParticleSpawnStrategy::SetSpawnInterval + + TODO + + @param _interval - + @return (void) + @context (all) + */ + void SetSpawnInterval(size_t _interval); + + /* + public ZStandardParticleSpawnStrategy::SetSpawnScale + + TODO + + @param _scale - + @return (void) + @context (all) + */ + void SetSpawnScale(const ZVector2f& _scale); + + /* + public ZStandardParticleSpawnStrategy::SetDirection + + TODO + + @param _direction - + @return (void) + @context (all) + */ + void SetSpawnVelocity(const ZVector3f& _velocity); +}; + +#endif + diff --git a/Include/ZRendererUtil/ZStandardParticleStorageAllocator.h b/Include/ZRendererUtil/ZStandardParticleStorageAllocator.h new file mode 100644 index 0000000..8d29d05 --- /dev/null +++ b/Include/ZRendererUtil/ZStandardParticleStorageAllocator.h @@ -0,0 +1,167 @@ +/* + ZStandardParticleStorageAllocator.h + Author: James Russell + + Purpose: Standard particle type allocator. Stores particle data as an array of structs containing particle data. + + Changelog + 2011/09/11 - creation (jcrussell) +*/ + +#pragma once + +#ifndef _ZSTANDARDPARTICLESTORAGEALLOCATOR_H +#define _ZSTANDARDPARTICLESTORAGEALLOCATOR_H + +#include + +//Struct containing our per-particle data +struct ZStandardParticle +{ + //Particle mass (sign indicates charge) + int Mass; + + //Particle Energy (when zero or less, dead) + int Energy; + + //Particle Position (offset from emitter transform) + ZVector3f Position; + + //Particle Facing (only matters if not billboarding) + ZVector3f Facing; + + //Particle Velocity + ZVector3f Velocity; + + //Particle Scaling + ZVector2f Scale; + + //Particle Color (per vertex, includes alpha) + // 3 --- 2 + // | | + // 0 --- 1 + ZVector4f Color[4]; + + //Texture data (U, V, texture width and height) + ZVector3f TextureData; + + //Particle Id + size_t Id; + + //Default Constructor + ZStandardParticle() + : Mass(1), Energy(0), + Position(0, 0, 0), Facing(0, 0, 0), + Velocity(0, 0, 0), Scale(0, 0), + TextureData(0, 0, 0), Id(0) + { + for (int i = 0; i < 4; ++i) + { + Color[i].Data[0] = 0; + Color[i].Data[1] = 0; + Color[i].Data[2] = 0; + Color[i].Data[3] = 0; + } + } +}; + +class ZStandardParticleStorageAllocator : public ZParticleStorageAllocator +{ +protected: + //The next inactive particle + int NextInactive; + + //The current particle group + size_t CurrentGroup; + + //The current particle within the current group + size_t CurrentParticle; + + //Array containing particle storage + ZArray ParticleData; + + //Array containing indices for particles that have been activated (must be cleared manually) + ZArray NewParticles; + +public: + /* + Constructor. + */ + ZStandardParticleStorageAllocator(); + + /* + Destructor. + */ + virtual ~ZStandardParticleStorageAllocator(); + + /* + public ZStandardParticleStorageAllocator::ActivateParticle + + Activates a particle contained in storage and returns the index of the activated particle. This + sets the particle id. + + @param _group - the group number this particle is being activated with + @return (int) - index to the activated particle + @context (all) + */ + int ActivateParticle(size_t _group); + + /* + public ZStandardParticleStorageAllocator::DeactivateParticle + + Deactivates a particle given the index to the particle in storage. + + @param _index - index to the particle in storage + @return (void) + @context (all) + */ + void DeactivateParticle(size_t _index); + + /* + public ZStandardParticleStorageAllocator::GetActiveParticleCount + + Gets the number of currently active particles. So long as only the methods + ActivateParticle and DeactivateParticle have been used, they are guaranteed + to be sequential in the ParticleData array and starting at index 0. + + @return (int) - number of active particles + @context (all) + */ + int GetActiveParticleCount(); + + /* + public ZStandardParticleStorageAllocator::GetParticleData + + Gets a reference to the array containing particle data. + + @return (ZArray&) - the particle data array + @context (all) + */ + ZArray& GetParticleData(); + + /* + public ZStandardParticleStorageAllocator::GetNewParticles + + Gets an array containing indices that correspond to newly activated particles. Should be + cleared by the spawn strategy when updated. + + @return (ZArray&) - list of indices to particles that have been activated + @context (all) + */ + ZArray& GetNewParticles(); + + //Subclass Override + virtual void AllocateParticleStorage( ZParticleEmitter* _emitter, size_t _maxParticles ); + + //Subclass Override + virtual void DeallocateParticleStorage(); + + //Subclass Override + virtual ZString GetParticleFormat(); + + //Subclass Override + virtual void Update(ZParticleEffect *_effect, ZParticleEmitter *_emitter, size_t _dt); +}; + +#endif + diff --git a/Include/ZRendererUtil/ZStandardParticleUpdateStrategy.h b/Include/ZRendererUtil/ZStandardParticleUpdateStrategy.h new file mode 100644 index 0000000..9333ff1 --- /dev/null +++ b/Include/ZRendererUtil/ZStandardParticleUpdateStrategy.h @@ -0,0 +1,97 @@ +/* + ZStandardParticleUpdateStrategy.h + Author: James Russell + + Purpose: TODO + + Changelog + 2011/09/11 - creation (jcrussell) +*/ + +#pragma once + +#ifndef _ZSTANDARDPARTICLEUPDATESTRATEGY_H +#define _ZSTANDARDPARTICLEUPDATESTRATEGY_H + +#include + +#define ZSP_DEFAULT_ENERGY_BLEED (1) +#define ZSP_DEFAULT_ACCELERATION_X (0.0f) +#define ZSP_DEFAULT_ACCELERATION_Y (0.0f) +#define ZSP_DEFAULT_ACCELERATION_Z (0.5f) + +class ZStandardParticleUpdateStrategy : public ZParticleUpdateStrategy +{ +protected: + //Acceleration Vector + ZVector3f ParticleAcceleration; + + //Energy drop per ms + size_t EnergyBleed; + +public: + /* + Default Constructor. + */ + ZStandardParticleUpdateStrategy(); + + /* + Destructor. + */ + ~ZStandardParticleUpdateStrategy(); + + /* + public ZStandardParticleUpdateStrategy::GetEnergyBleed + + TODO + + @return (const size_t) + @context (all) + */ + const size_t GetEnergyBleed(); + + /* + public ZStandardParticleUpdateStrategy::GetParticleAcceleration + + TODO + + @return (const ZVector3f) + @context (all) + */ + const ZVector3f GetParticleAcceleration(); + + /* + public ZStandardParticleUpdateStrategy::SetEnergyBleed + + TODO + + @param _bleedRate - + @return (void) + @context (all) + */ + void SetEnergyBleed(size_t _bleedRate); + + /* + public ZStandardParticleUpdateStrategy::SetParticleAcceleration + + TODO + + @param _accel - + @return (void) + @context (all) + */ + void SetParticleAcceleration(const ZVector3f& _accel); + + //Subclass Implementation + virtual bool CheckParticleFormat( const ZString& _format ); + + //Subclass Implementation + virtual void UpdateParticles(ZParticleEffect* _particleEffect, + ZParticleEmitter* _particleEmitter, + ZParticleStorageAllocator* _storageAllocator, + size_t _dt ); + +}; + +#endif + diff --git a/Include/ZRendererUtil/ZStaticMesh.hpp b/Include/ZRendererUtil/ZStaticMesh.hpp new file mode 100644 index 0000000..05ee480 --- /dev/null +++ b/Include/ZRendererUtil/ZStaticMesh.hpp @@ -0,0 +1,134 @@ +/* + ZStaticMesh.h + Author: Chris Ertel + + Purpose: Classes for holding static mesh data. + + Changelog + 2011/09/18 - creation (crertel) +*/ + +#pragma once + +#ifndef _ZSTATICMESH_H +#define _ZSTATICMESH_H + +#include +#include +#include + +typedef uint32_t ZSMFaceIndex; + +typedef enum ZSMChannelType +{ + ZSMCT_UNKNOWN = 0, + + ZSMCT_BOOL = 0x11, + ZSMCT_BOOL_VEC2 = 0x12, + ZSMCT_BOOL_VEC3 = 0x13, + ZSMCT_BOOL_VEC4 = 0x14, + + ZSMCT_INT = 0x21, + ZSMCT_INT_VEC2 = 0x22, + ZSMCT_INT_VEC3 = 0x23, + ZSMCT_INT_VEC4 = 0x24, + + ZSMCT_UINT = 0x31, + ZSMCT_UINT_VEC2 = 0x32, + ZSMCT_UINT_VEC3 = 0x33, + ZSMCT_UINT_VEC4 = 0x34, + + ZSMCT_FLOAT = 0x41, + ZSMCT_FLOAT_VEC2 = 0x42, + ZSMCT_FLOAT_VEC3 = 0x43, + ZSMCT_FLOAT_VEC4 = 0x44 +}; + +class ZSMChannelDefinition +{ +protected: + ZString Name; + ZSMChannelType Datatype; + uint32_t StartOffset; + uint32_t Stride; + +public: + ZSMChannelDefinition( ZString _name, ZSMChannelType _datatype, uint32_t _offset, uint32_t _stride) + : Name(_name), Datatype(_datatype), StartOffset(_offset), Stride(_stride) + { + } +}; + +class ZStaticMeshMaterial +{ +protected: + ZString Name; + ZArray< ZSMFaceIndex > FaceIndices; + ZArray< ZPtr > ChannelDefinitions; + +public: + ZStaticMeshMaterial(ZString _name, ZArray< ZSMFaceIndex> _faceIndices, ZArray< ZPtr > _channelDefinitions) + : Name(_name), FaceIndices(_faceIndices), ChannelDefinitions(_channelDefinitions) + { + } + + /* + public ZStaticMeshMaterial::GetName + + Function to get the name of the material. + + @return (ZString) - Name of the material. + */ + inline ZString GetName() { return this->Name; } + + /* + public ZStaticMeshMaterial::GetFaceIndices + + Function to get the face indices for a material. + + @return (ZArray) - Array of the face indices. + */ + inline ZArray GetFaceIndices() { return this->FaceIndices; } + + /* + public ZStaticMeshMaterial::GetChannelDefinitions + + Function to get the vertex channel definiitions for this material. + + @return (ZArray) - Array of vertex channel definitions. + */ + inline ZArray< ZPtr > GetChannelDefinitions() { return this->ChannelDefinitions; } +}; + +class ZStaticMesh +{ +protected: + ZArray< ZPtr > MaterialGroups; + ZPtr< ZArray< char > > VertexData; + +public: + ZStaticMesh(ZArray< ZPtr > _groups, ZPtr< ZArray< char > > _vertexData) + : MaterialGroups(_groups), VertexData(_vertexData) + { + } + + /* + public ZStaticMesh::GetMaterialGroups + + Function to get the material groups. + + @return (ZArray) - Material groups that make up the mesh. + */ + inline ZArray< ZPtr > GetMaterialGroups() { return this->MaterialGroups; } + + /* + public ZStaticMesh::GetVertexData + + Function to get the vertex data. + + @return (ZPtr< ZArray< char > >) - Vertex data for the mesh. + */ + inline ZPtr< ZArray< char > > GetVertexData() { return this->VertexData; } +}; + +#endif \ No newline at end of file diff --git a/Include/ZRendererUtil/ZStaticMeshLoader.hpp b/Include/ZRendererUtil/ZStaticMeshLoader.hpp new file mode 100644 index 0000000..bb0eef4 --- /dev/null +++ b/Include/ZRendererUtil/ZStaticMeshLoader.hpp @@ -0,0 +1,27 @@ +/* + ZStaticMeshLoader.h + Author: Chris Ertel + + Purpose: File for loading ZStaticMeshes + + Changelog + 2013/02/24 - Removed dependency on renderer. + 2011/09/25 - creation (crertel) +*/ + +#pragma once + +#ifndef _ZSTATICMESHLOADER_H +#define _ZSTATICMESHLOADER_H + +#include +#define ZSM_CURRENT_VERSION (4) + +class ZStaticMesh; +class ZStaticMeshLoader +{ +public: + static ZPtr loadFromMemory(const void* _memory, size_t _sizeInMemory); +}; + +#endif \ No newline at end of file diff --git a/Include/ZRendererUtil/ZTessellator.hpp b/Include/ZRendererUtil/ZTessellator.hpp new file mode 100644 index 0000000..1c06da8 --- /dev/null +++ b/Include/ZRendererUtil/ZTessellator.hpp @@ -0,0 +1,100 @@ +/* + ZTessellator.h + Author: Patrick Baggett + + Purpose: Header for tessellator interface. (currently requires GLU) + + Changelog + 2011/09/18 - creation (ptbaggett) +*/ + +#pragma once + +#ifndef _ZTESSELLATOR_HPP +#define _ZTESSELLATOR_HPP + +#include + +//Types of tessellations we can handle +enum ZTesselatorPolyType +{ + ZTPT_POLY_TRIANGLES, + ZTPT_POLY_TRIFAN, + ZTPT_POLY_TRISTRIP +}; + +class ZTessellator +{ +protected: + //Protected Constructor + ZTessellator() { } + +public: + //Virtual Destructor + virtual ~ZTessellator() { } + + /* + virtual public ZTessellator::BeginPoly + + TODO + + @param type - + @return (void) + @context (all) + */ + virtual void BeginPoly(ZTesselatorPolyType type) = 0; + + /* + virtual public ZTessellator::BeginTessellate + + TODO + + @return (void) + @context (all) + */ + virtual void BeginTessellate() = 0; + + /* + virtual public ZTessellator::EndPoly + + TODO + + @return (void) + @context (all) + */ + virtual void EndPoly() = 0; + + /* + virtual public ZTessellator::EndTessellate + + TODO + + @return (void) + @context (all) + */ + virtual void EndTessellate() = 0; + + /* + virtual public ZTessellator::Tessellate + + TODO + + @return (void) + @context (all) + */ + virtual void Tesselate() = 0; + + /* + virtual public ZTessellator::Vertex + + TODO + + @param p - + @return (void) + @context (all) + */ + virtual void Vertex(SST_Vec2f* p) = 0; +}; + +#endif + diff --git a/Include/ZRendererUtil/ZTessellatorBase.hpp b/Include/ZRendererUtil/ZTessellatorBase.hpp new file mode 100644 index 0000000..ded5309 --- /dev/null +++ b/Include/ZRendererUtil/ZTessellatorBase.hpp @@ -0,0 +1,64 @@ +/* + ZTessellatorBase.h + Author: James Russell + + Purpose: TODO + + Changelog + 2011/09/18 - creation (jcrussell) +*/ + +#pragma once + +#ifndef _ZTESSELLATORBASE_HPP +#define _ZTESSELLATORBASE_HPP + +#include + +//#if WINDOWS +#include +//#endif + +#include //TODO: remove dependency on GLU for tessellation + +class ZTessellatorBase : public ZTessellator +{ +protected: + //Outline Evaluator to use + ZOutlineEvaluator* Evaluator; + + //Tessellator (TODO: remove dependency on GLU) + GLUtesselator *Tessellator; + +public: + /* + Default Constructor. + */ + ZTessellatorBase(ZOutlineEvaluator* _eval); + + /* + Destructor. + */ + virtual ~ZTessellatorBase(); + + //Subclass Implementation + virtual void Tesselate(); + + //Not Implemented + virtual void BeginTessellate() = 0; + + //Not Implemented + virtual void EndTessellate() = 0; + + //Not Implemented + virtual void BeginPoly( ZTesselatorPolyType type ) = 0; + + //Not Implemented + virtual void EndPoly() = 0; + + //Not Implemented + virtual void Vertex( SST_Vec2f* p ) = 0; +}; + +#endif + \ No newline at end of file diff --git a/Include/ZRendererUtil/ZTransformHierarchy.hpp b/Include/ZRendererUtil/ZTransformHierarchy.hpp new file mode 100644 index 0000000..73bb6c3 --- /dev/null +++ b/Include/ZRendererUtil/ZTransformHierarchy.hpp @@ -0,0 +1,37 @@ +/* + ZTransformHierarchy.h + Author: Chris Ertel + + Purpose: Helper classes to setup a simple transform hierarchy. + + Changelog + 2011/09/20 - creation (crertel) +*/ + +#pragma once + +#ifndef _ZTRANSFORMHIERARCHY_H +#define _ZTRANSFORMHIERARCHY_H + +#include +#include +#include + +class ZTransformHierarchy +{ +protected: + ZMatrix44f Transform; + ZString Name; + + ZArray Children; + +public: + ZTransformHierarchy(); + ~ZTransformHierarchy(); + + + void Render(ZPtr _renderer, ZFrameContext _context, int _drawgroup, ZMatrix44f _transform, ZRenderState _renderState); +}; + + +#endif \ No newline at end of file diff --git a/Include/ZRendererUtil/ZTriTessellator.hpp b/Include/ZRendererUtil/ZTriTessellator.hpp new file mode 100644 index 0000000..c356529 --- /dev/null +++ b/Include/ZRendererUtil/ZTriTessellator.hpp @@ -0,0 +1,55 @@ +/* + ZTriTessellator.h + Author: Patrick Baggett + Chris Ertel + + Purpose: Implementation of tessellator interface that tessellates into lists of triangles (unindexed) + + Changelog + 2011/09/18 - creation (ptbaggett) + 2012/08/05 - Updated to use new SST functions. +*/ + +#pragma once + +#ifndef _ZTRITESSELLATOR_HPP +#define _ZTRITESSELLATOR_HPP + +#include + +#include + +class ZTriTessellator : public ZTessellatorBase +{ +protected: + //Our set of vertices + ZArray& Vertices; + + //Temporary use array + ZArray Temp; + + //Tessellation poly type + ZTesselatorPolyType PolyType; + +public: + //Dumps a list of vertices into 'verts' when complete + ZTriTessellator(ZOutlineEvaluator* _eval, ZArray& _verts); + + //Subclass Implementation + virtual void BeginTessellate(); + + //Subclass Implementation + virtual void EndTessellate(); + + //Subclass Implementation + virtual void BeginPoly(ZTesselatorPolyType _type); + + //Subclass Implementation + virtual void EndPoly(); + + //Subclass Implementation + virtual void Vertex(SST_Vec2f* _p); +}; + +#endif + diff --git a/Include/ZSimulation/ZEntity.hpp b/Include/ZSimulation/ZEntity.hpp new file mode 100644 index 0000000..cb90f6c --- /dev/null +++ b/Include/ZSimulation/ZEntity.hpp @@ -0,0 +1,379 @@ +/* + ZEntity.hpp + Author: James Russell + Created: 2/5/2013 + + Purpose: + + Entity class for the ZSimulation framework. + + All objects affecting the simulation will exist as an entity. Entities can either + be created with state or without state. Entities with and without state can + be messaged by other entities within the simulation. Entities with state + have their state function called once per tick, and this state function + can modify the entity state, making the entity an autonomous state machine. + + // ENTITY MESSAGING // + + Entities are created in order to be processed in a threaded fashion. When + entities have their current state function called, they should be expected to be + able to process this in a thread-safe manner, able to call their own non-const methods + but only able to affect other entities via messaging. + + After the state functions are called, remaining messages are delivered to the entity + 'mailbox'. Any action that could mutate an entity that is not done from within the + call to the state function must be handled via a message. + + These delivered messages are then processed in a multi threaded manner, but each entity + has it's messages processed serially, meaning that modifications can take place as per + normal. + + Entity messages are processed by deferring to the handler installed for a particular + message type on an entity. If no message handler is installed for that message type + on an entity, the message handler installed for that type on the simulation message + stream will be called. If no message handler is installed there, the message is + dropped. + + // ENTITY PROPERTIES // + + Entities hold their state via allocation into the simulation 'property buffer', which + allows for contiguous space allocation for properties to be stored. The property + buffer is a raw memory allocator and does not care what the underlying data actually + is. + + Entity properties can be allocated as 'local' or 'synchronized'. Data stored locally + is not updated to other simulation instances. Data stored in a 'synchronized' state is + mirrored to other simulation instances. + + License: + + Copyright 2013, 762 Studios +*/ + +#pragma once + +#ifndef ZENTITY_HPP +#define ZENTITY_HPP + +#include +#include + +#include "ZSimulationDefs.hpp" +#include "ZPropertyBuffer.hpp" +#include "ZStringBuffer.hpp" + +// forward decl +class ZSimulation; +struct ZMessage; + +/* +Entity class. +*/ +class ZEntity +{ +public: + /* + This is the entity state typedef, which corresponds to 'AI State'. The current think state + is called once per simulation tick. + + @param entity - the entity who is thinking + @param sim - the running simulation + @param dt - the time (expressed in seconds) since last call of this function + */ + typedef void (*StateFunc)(ZEntity& entity, const ZSimulation& sim, double dt); + + /* + This is the entity message handler typedef, which corresponds to 'Behavior'. If there is no message + handler installed for a given message type, the default handler installed in the message queue + is used. + + @param entity - the entity receiving the message + @param sim - the running simulation + @param sender - the sending entity + @param payload - the payload of the message + */ + typedef void (*MessageFunc)(ZEntity& entity, const ZSimulation& sim, eID sender, void* payload); + + /* + This is the entity initialization function typedef, which can be passed to the simulation to initialize + the entity upon creation. + + @param entity - the entity to initialize + @param sim - the running simulation + */ + typedef void (*InitFunc)(ZEntity& entity, const ZSimulation& sim); + + /* + Entity property class. An ease of access class for reading and writing + property data. + + This class does not handle type coercion on read. Types will change when + values are set. + */ + struct Property { + + // we'll be using this a lot + typedef ZStringBuffer::StringKey StringKey; + + enum { + BOOL, // boolean type + INT, // integer type + FLOAT, // floating point type + DOUBLE, // double precision floating point type + STRING, // string type (stored in string buffer or dynamic, limited size) + VECTOR, // vector type (4 floating point values) + MATRIX, // matrix type (16 floating point values) + + NONE // untyped data + + } Type; // the type of property + + ZString LocalString; // local storage for strings + uint8_t Local[64]; // local storage for simple types + void* Data; // data for more complex types + size_t Size; // size of data (in bytes) + + // default constructor, which initializes an empty string + Property(); + + // generic and array constructor, which takes data and size + Property(void* data, size_t size); + + // value constructors + Property(const Property& other); + Property(const bool val); + Property(const int val); + Property(const float val); + Property(const double val); + Property(const char* val); // checks to see if this string has a string key, if not makes a dynamic string + Property(const StringKey val); // quicker method of directly creating a static string type + Property(const SST_Vec4f& val); + Property(const SST_Vec3f& val); // convenience for SST_Vec4f(x, y, z, 0.0) + Property(const SST_Vec2f& val); // convenience for SST_Vec4f(x, y, 0.0, 0.0) + Property(const SST_Mat44f& val); + + // assignment operators + Property& operator = (const Property& other); + Property& operator = (const bool& val); + Property& operator = (const int& val); + Property& operator = (const float& val); + Property& operator = (const double& al); + Property& operator = (const char* val); + Property& operator = (const StringKey val); // quicker method of using a static string type + Property& operator = (const SST_Vec4f& val); + Property& operator = (const SST_Vec3f& val); // convenience for SST_Vec4f(x, y, z, 0.0) + Property& operator = (const SST_Vec2f& val); // convenience for SST_Vec4f(x, y, 0.0, 0.0) + Property& operator = (const SST_Mat44f& val); + + // cast operators + operator bool () const; + operator int () const; + operator float () const; + operator double () const; + operator char* () const; + operator bool* () const; + operator int* () const; + operator float* () const; + operator double* () const; + operator SST_Vec4f () const; + operator SST_Vec3f () const; // gets [x, y, z] only + operator SST_Vec2f () const; // gets [x, y] only + operator SST_Mat44f () const; + }; + + // c'tor + ZEntity(eID entityId, ZSimulation& sim); + + // parameterized c'tor (creates an actor) + ZEntity(eID entityId, ZSimulation& sim, StateFunc startState); + + // d'tor + ~ZEntity(); + + ////////////////////////////////////////////////////////////////////////// + // Member Data Getter Functions + + eID GetId() const; + ZRandomGenerator& GetPRNG(); + + ////////////////////////////////////////////////////////////////////////// + // Property Manipulation Functions + + /* + Property access functions. Used to create, remove, read, and write properties + and their values. + + The 'HasProperty' function will return true if the named property exists on + this entity. + + The 'CreateSyncProperty' functions is used to declare a synchronized property + on this entity. Synchronized properties are automatically mirrored across + the network system whenever a change is made. If the 'owner' boolean is + set to true, modifications to the entity on this simulation are synchronized + to other simulations. If the owner boolean is set to false, modifications + are not synchronized, and the property will be updated periodically from + other simulations. Only one simulation should be the owner of an entity, + or they will update over each other. + + The 'GetProperty' function will fill out a Property instance that references + the read value of the named property. If the named property does not exist + on this entity, the function will return false. + + The 'SetProperty' function will set the write value of the property to be + the value provided. If the named property does not exist, it will be created + as a non-synchronized property. Note that the read value is not updated until + the next simulation tick. + + The 'EraseProperty' function will queue the property for removal at the end + of this tick, which allows 'get' operations to function as normal until the + next tick. + + The template 'Get' function is a shortcut to directly get the value of + a specific property. Note that if the property does not exist, this will + return a default constructed property value. + */ + + bool HasProperty(const ZName& name) const; + void CreateSyncProperty(const ZName& name, const Property& prop, bool owner); + bool GetProperty(const ZName& name, Property& val) const; + void SetProperty(const ZName& name, const Property& val); + void EraseProperty(const ZName& name); + + template + T Get(const ZName& name) const + { Property prop; GetProperty(name, prop); return (T)prop; } + + template + void Set(const ZName& name, const T val) + { Property prop(val); SetProperty(name, prop); } + + /*************************************************************************/ + + /* State Management Functions */ + + /* + State functions. Used to get information about the current state and + manipulate the state stack, as well as call the current state function. + + Push and Pop operate as you would expect for a state stack. The maximum + number of states is defined by ZENT_STACK_SIZE. + + SetState sets the current state to the given state, replacing it. + + ResetState clears the state stack and sets the current state to be the + provided one. + */ + + StateFunc GetCurrentState() const; + double GetTimeInCurrentState() const; + void PushState(StateFunc state); + void PopState(); + void SetState(StateFunc state); + void ResetState(StateFunc state); + + /* + State property stack manipulation functions. Used to read and write information + to the state property stack, which can be used to pass transient information from + one state function to another. + */ + + size_t GetStatePropertyCount() const; + Property PopStateProperty(); + void PushStateProperty(const Property& prop); + void ClearStatePropertyStack(); + + /*************************************************************************/ + + /* Messaging Management Functions */ + + /* + Messages, once posted to the message queue, can be 'delivered' to entities for + sorting purposes to be later processed in a convenient fashion. + + When processing delivered messages, order of delivery is maintained. Any + messages that do not have a corresponding handler type installed will be + handled by the handler installed in the message stream. If no corresponding + handler is installed there, the message is dropped, and the simulation is + notified. + */ + + void DeliverMessage(ZMessage* msg); + void ProcessMessages(); + void PushMessageHandler(mID type, MessageFunc handler); + void PopMessageHandler(mID type); + void ClearMessageHandlers(); + +protected: + /* + Typedef for the property map used by ZEntity. It has a bucket size of 32, local + storage for the buckets of 32, 10 local nodes for each hash-chain, 10 local storage + for each property array, and will not resize based on load factor. Uses a 64-bit + hash value. + */ + typedef ZHashMap, 0> PropMap; + + /* + Stack used to indicate which properties have been modified since last swap of properties. + */ + typedef ZArray> PropModifiedStack; + + /* + Stack used to indicate which properties have been deleted since last swap of properties. + */ + typedef ZArray PropDeletedStack; + + /* + Stack used for state properties, which can be used to send data from one state to another. + */ + typedef ZArray StatePropStack; + + /* + Buffer used as an entity mailbox - targeted messages are delivered here. + */ + typedef ZRingBuffer Mailbox; + + /* + Typedef for the handler map used by ZEntity, which maps message type to a + stack of handlers. Only keeps two local nodes in the allocator, and will not + resize based on load factor. + */ + typedef ZHashMap, int64_t, ZHasher, 0, + ZListPooledAllocator, int64_t>, 2 >> HandlerMap; + + /* Member Data */ + ZSimulation& Sim; // the simulation running this thing + const eID Id; // the id of the entity + ZRandomGenerator PRNG; // entity PRNG, kept so there are no thread conflicts with PRNG access + + /* Property Management */ + PropMap PropertyMap; // entity properties map + PropModifiedStack PropertyModifiedStack; // properties that need to be mirrored into the read properties map + PropDeletedStack PropertyDeletedStack; // properties have been deleted + + /* State Management */ + int StateIndex; // index to our current state (-1 indicates no state) + StateFunc StateStack[ZSIM_ENT_STATE_STACK_SIZE]; // stack of states (StateStack[StateIndex] is our current) + StatePropStack StatePropertyStack; // stack of properties so that states can pass data to each other + double StateTime; // amount of time we have spent in our current state + + /* Message Management */ + Mailbox MessageMailbox; // entity 'Mailbox', which is where messages get delivered to + HandlerMap MessageHandlers; // entity handlers, used to process received messages + +private: + friend class ZSimulation; + friend class ActorTickTask; + DISABLE_COPY_AND_ASSIGN(ZEntity); + + // allocates a new property + // TODO + + // called by the simulation to tick the current state + void StateTick(double dt); + + // called by the simulation to dealloc properties + void HandlePropertyDelete(); +}; + +#endif + diff --git a/Include/ZSimulation/ZMessageStream.hpp b/Include/ZSimulation/ZMessageStream.hpp new file mode 100644 index 0000000..c3aeea4 --- /dev/null +++ b/Include/ZSimulation/ZMessageStream.hpp @@ -0,0 +1,153 @@ +/* + ZMessageStream.hpp + Author: James Russell + Created: 2/4/2013 + + Purpose: + + Messaging stream class, which acts as an event loop for the entire simulation. Processes both + untargeted (or 'simulation' targeted) messages and messages that are intended for a specific entity. + Handles organization and sorting so that the messages can be processed in a thread safe fashion at + a later time. + + License: + + Copyright 2013, 762 Studios + +*/ + +#pragma once + +#ifndef _ZMESSAGESTREAM_HPP +#define _ZMESSAGESTREAM_HPP + +#include +#include + +#include "ZSimulationDefs.hpp" + +//Forward Declarations +class ZSimulation; + +/* +Message structure. Messages are in the form of a POD struct of a set size +payload. Message layout definitions (see ZSimulationDefs.hpp for examples) +can be used to interpret the data. +*/ +struct ZMessage { + mID Type; // type of the message + eID Sender; // the entity who sent the message (ZSIM_EID_SYSTEM means system or simulation) + eID Target; // the target of the message (ZSIM_EID_SYSTEM calls the default handler) + + char Payload[ZSIM_MESSAGE_SIZE]; // the message payload, which can be interpreted via layout definitions +}; + +/* +Message handler function profile. +*/ +typedef void (*ZMessageHandler)(eID _sender, eID _target, void* _payload, ZSimulation& _sim); + +/* +Message streaming class, used to send messages from one entity to another or to the simulation. +*/ +class ZMessageStream +{ +public: + // c'tor + ZMessageStream(); + + // d'tor + ~ZMessageStream(); + + // message 'Send' method, which will copy data from a struct into the message (MT must be a POD type) + template + void Send(mID _type, eID _sender, eID _target, MT _payload) + { + ZMessage* msg; + + #if SST_COMPILER == SST_COMPILER_MSVC + #pragma warning(push) + #pragma warning(disable:4127) + #endif + + ZASSERT(sizeof(MT) <= ZSIM_MESSAGE_SIZE, "Message sent with payload too large!"); + + #if SST_COMPILER == SST_COMPILER_MSVC + #pragma warning(pop) + #endif + + // Synchronized Section + { + ZLock lock(AllocatorMutex); + + msg = MessageAllocator.Allocate(); + } + + ZASSERT(msg != NULL, "Unable to allocate message!"); + + msg->Type = _type; + msg->Sender = _sender; + msg->Target = _target; + + MemCopy(uint8_t, msg->Payload, &_payload, sizeof(MT)); + + // Synchronized Section + { + ZLock lock(BufferMutex); + + MessageBuffers[CurrentBufferIndex].PushBack(msg); + } + } + + /* + Pumps the message queue, processing the messages that have been sent since last time this method was + called. Returns true if additional messages were generated during the processing of the current set + of messages. + + Messages that are targeted at a specific entity will be delivered to that entity. If that entity cannot + be found, the message is dropped. Messages that target the reserved eID of '0' will be handled by the + message stream handlers. + + Only one thread should ever be calling this method. Multiple threads calling this method will result + in that thread waiting until the previous has finished. + + Returns true if messages are still available for processing, false if the current queue is empty. + */ + bool ProcessMessages(ZSimulation& _sim); + + /* + External message handlers. Used to return an entity targeted message or process a targeted + message that had no installed handler. + */ + void HandleMessage(ZMessage* _msg, ZSimulation& _sim); + void ReturnMessage(ZMessage* _msg); + + /* + Push and Pop Methods for Handlers. + */ + void PushHandler(mID _type, ZMessageHandler _handler); + ZMessageHandler PopHandler(mID _type); + +protected: + + ZMutex AllocatorMutex; // lock for allocators + ZMutex BufferMutex; // lock for buffers + ZMutex HandlerMutex; // lock for handlers + ZMutex ProcessingMutex; // lock for processing + + int CurrentBufferIndex; // index to our current message buffer + + ZRingBuffer MessageBuffers[2]; // the current set of messages (one receives messages while the other is processed) + ZHashMap> MessageHandlers; // set of handler functions + + ZSlabAllocator MessageAllocator; // slab allocator for messages + + +private: + DISABLE_COPY_AND_ASSIGN(ZMessageStream); +}; + +#endif + diff --git a/Include/ZSimulation/ZNetworkEvent.hpp b/Include/ZSimulation/ZNetworkEvent.hpp new file mode 100644 index 0000000..38e9371 --- /dev/null +++ b/Include/ZSimulation/ZNetworkEvent.hpp @@ -0,0 +1,165 @@ +/* + ZNetworkEvent.hpp + Author: James Russell + Created: 9/13/2015 + + Purpose: + + Network Event abstract class. Intended to be subclassed into various subclasses that will be + serialized / deserialized and processed on both client and server. + + Note that events that originate on the server will generally not have their HandleServer method + called, as the server already processed the occurrence that originated the event. Events + that originate on the client will generally be pushed to the server, have HandleServer + called on them, which will generally also cause an event to be pushed to each client, who + will then have HandleClient called when the event gets deserialized. + + From the above usage pattern, we can see that clients generally push events to the server but + do not process the local occurrence (the HandleClient) until after the server has confirmed + the event happens by pushing the event back to all clients, the original sender included. + + This usage pattern is not required for client authoritative events, which are processed locally + and then handed to the server to notify other attached clients. + + License: + + TODO + +*/ + +#pragma once + +#ifndef _ZNETWORKEVENT_HPP +#define _ZNETWORKEVENT_HPP + +#include "ZSimulationDefs.hpp" + +// forward decl +class ZSimulation; + +/* +ZNetworkEvent class. +*/ +class ZNetworkEvent { +DISABLE_COPY_AND_ASSIGN(ZNetworkEvent); +public: + + nID Type; // the type of event this is + cID NetTarget; // the connection this is targeting + cID NetIgnore; // if NetTarget is set to all, this target will be ignored + bool InQueue; // flag set during a handle method to indicate this has been queued up for sending + + // handler for events on client side + virtual void HandleClient(ZSimulation& server_sim) = 0; + + // handler for events on server side + virtual void HandleServer(ZSimulation& client_sim) = 0; + + // called by the network system to deserialize this event from binary form (after header is read) + virtual bool Deserialize(ZBinaryBufferReader& reader) = 0; + + // called by the network system to serialize this event into binary form + virtual void Serialize(ZBinaryBufferWriter& writer) = 0; + + // called to get the serialized size of this event (including uint8_t message type flag) + virtual size_t GetSerializedSize() = 0; + + // called by subclass to serialize the header (Type, PlayerSource, and PlayerTarget) + void SerializeHeader(ZBinaryBufferWriter& writer) { + writer.WriteU32(Type); + } + + // called by subclass to get serialized header size + size_t GetHeaderSize() { + return sizeof(nID); + } + +protected: + // c'tor + ZNetworkEvent(nID type) : Type(type) { } +}; + +/* +Network Event base implementation, which attempts to automatically handle serialization and +deserialization via template POD structs. + +Note the template on the game event (DS), which indicates a POD struct. This is the data +that is serialized and sent as part of the event. Wrap the struct definition in pragma +pack statements to ensure correct behavior across systems and reduce bandwidth. +*/ +template +class ZNetworkEventBase : public ZNetworkEvent +{ +DISABLE_COPY_AND_ASSIGN(ZNetworkEventBase); +public: + // the data struct for this event + DS EventData; + + // called by the network system to deserialize this event from binary form (after header is read) + virtual bool Deserialize(ZBinaryBufferReader& reader) { + if (reader.CanRead(sizeof(DS))) { + reader.ReadU8Array((uint8_t*)&EventData, sizeof(DS)); + return true; + } else return false; + } + + // called by the network system to serialize this event into binary form + virtual void Serialize(ZBinaryBufferWriter& writer) { + SerializeHeader(writer); + writer.WriteU8Array((uint8_t*)&EventData, sizeof(DS)); + } + + // called to get the serialized size of this event + virtual size_t GetSerializedSize() { + return GetHeaderSize() + sizeof(DS); + } + +protected: + // c'tor + ZNetworkEventBase(nID type) : ZNetworkEvent(type) { } +}; + +#pragma pack (push, 1) + +/* +Data struct used for message events, which will simply create the +given message on the other side and pass it to the simulation. +*/ +template +struct ZMessageEventData { + mID Type; + eID Sender; + eID Target; + M MessageData; + + cID Connection; +}; + +#pragma pack (pop) + +/* +Message network event. This is used to duplicate a message on other +connected simulations. The template parameter type is the message +data definition struct. Be sure to use pragma pack to reduce network +overhead. +*/ +template +class ZMessageEvent : public ZNetworkEventBase> { +public: + // c'tor + ZMessageEvent(mID msg_type) : ZNetworkEventBase(0) { } + ZMessageEvent(mID msg_type, eID sender, eID target, MT payload, cID connection) + : ZNetworkEventBase(0), EventData({msg_type, sender, target, connection, payload}) { } + + // subclass implementations + virtual void HandleClient(ZSimulation& server_sim) { + server_sim.SendLocalMessage(Data.Type, Data.Sender, Data.Target, Data.MessageData); + } + + virtual void HandleServer(ZSimulation& client_sim) { + client_sim.SendLocalMessage(Data.Type, Data.Sender, Data.Target, Data.MessageData); + } +}; + + +#endif \ No newline at end of file diff --git a/Include/ZSimulation/ZNetworkRequest.hpp b/Include/ZSimulation/ZNetworkRequest.hpp new file mode 100644 index 0000000..4e81e3d --- /dev/null +++ b/Include/ZSimulation/ZNetworkRequest.hpp @@ -0,0 +1,82 @@ +/* + NetworkRequest.hpp + Author: Patrick Baggett , James Russell + Created: 12/03/2013 + + Purpose: + + Cancel-able network thread request, similar to ZThreadRequest, but + with more cancellation points. + + Used to communicate between any other thread and the NetworkService + thread. The "payload" field contains the message's data, and the event + is used to cancel and signal when the request has been handled. For some + requests, no response is required; these are called "responseless" and + have no SST_Event object associated. Obviously, they cannot be waited on + nor canceled -- they are simply "fire and forget". + + License: + + Copyright 2013, 762 Studios. + +*/ + +#ifndef __ZNETWORKREQUEST_HPP +#define __ZNETWORKREQUEST_HPP + +#include + +class ZNetworkRequest +{ +public: + // result enumeration + enum RequestResult { + RESULT_CANCELED, // nope + RESULT_FINISHED, // yep + RESULT_INPROGRESS // go away + }; + + // type enumeration + enum RequestType { + REQUEST_CONNECT, // connect to another simulation + REQUEST_DISCONNECT, // disconnect from a server + REQUEST_RESET, // immediately disconnect (no notice) + REQUEST_STOP_NETWORK, // stop the network thread + }; + + // public member variables + uint8_t Payload[64]; // generic data payload, used to input data and read results back + RequestType Type; // request type + RequestResult Result; // in progress, success, or failure + + // c'tor + ZNetworkRequest(RequestType type, bool needEvent = true) + : Type(type), Result(RESULT_INPROGRESS) { + FinishedEvent = needEvent ? SST_Concurrency_CreateEvent() : NULL; + SST_Atomic_StoreRelease(&Canceled, 0); + } + + // d'tor + ~ZNetworkRequest() { + if (FinishedEvent) { + SST_Concurrency_DestroyEvent(FinishedEvent); + } + } + + // getters + bool IsResponseless() { return (FinishedEvent == NULL); } + bool WaitFinished() { return (SST_Concurrency_WaitEvent(FinishedEvent, SST_WAIT_INFINITE) != 0); } + bool CheckFinished() { return (SST_Concurrency_WaitEvent(FinishedEvent, 0) != 0); } + void Cancel() { Canceled = 1; } + bool IsCancelPending() { return (Canceled != 0); } + + // used to signal the request should be finished or canceled + void MarkFinished() { Result = RESULT_FINISHED; SST_Concurrency_SignalEvent(FinishedEvent); } + void MarkCanceled() { Result = RESULT_CANCELED; SST_Concurrency_SignalEvent(FinishedEvent); } + +private: + SST_Event FinishedEvent; // when signaled, the request has been completed + volatile int Canceled; // when non-zero, the network thread will not attempt to process it +}; + +#endif diff --git a/Include/ZSimulation/ZNetworkService.hpp b/Include/ZSimulation/ZNetworkService.hpp new file mode 100644 index 0000000..4744c27 --- /dev/null +++ b/Include/ZSimulation/ZNetworkService.hpp @@ -0,0 +1,181 @@ +/* + ZNetworkService.hpp + Author: Patrick Baggett , James Russell + Created: 12/03/2013 + + Purpose: + + Network functionality for ZSimulation. Operates a thread that handles sending and + receiving of network data. Can be initialized as a server instance of a client + instance, with the real difference being that client instances connect to a single + server and servers listen for connections from multiple clients and other server + instances. + + License: + + Copyright 2013, 762 Studios. + + */ + +#pragma once + +#ifndef __ZNETWORKSERVICE_HPP +#define __ZNETWORKSERVICE_HPP + +#include +#include + +#include "ZRemotePeer.hpp" +#include "ZNetworkRequest.hpp" +#include "ZNetworkUpdateStream.hpp" + +// forward decl +class ZSimulation; + +// class decl +class ZNetworkService +{ +public: + // c'tor + ZNetworkService(ZSimulation& sim); + + /* + Initializes the network system as client or server. The name is for display + purposes for both client and server. + + If initialized as a server, the maximum number of simultaneous connections must + be specified. + */ + bool InitAsClient(const char* name); + bool InitAsServer(uint32_t maxConnections, uint16_t listenPort, const char* name); + + /* + As a client, initializes a connection to the provided remote host. As a server, + links to another server instance to share workload. Delete this when done. + */ + ZNetworkRequest* InitiateConnection(const char* remoteHost, uint16_t port); + + /* + As a client, disconnects from the server (cID for server is always zero). As + a server, disconnects the given connection. This is a soft disconnect that + notifies the other side and waits for a response. Delete this when done. + */ + ZNetworkRequest* Disconnect(cID id); + + /* + Generates the disconnection event immediately, but gives no notice to the other + side. Delete this when done. + */ + ZNetworkRequest* ResetConnection(cID id); + + /* + Given a connection id, gets the associated remote peer object. + */ + ZRemotePeer* GetPeer(cID id); + + /* + Given the network name, gets the associated id. Returns cID(-1) if not connected + to this simulation instance. + */ + cID GetId(const char* netname); + + /* + Gets a list of node and host pairings on the network. If the pairing exists in both + directions, then the connection is between two servers. + */ + void GetTopography(ZArray>& mappings); + + // thread control methods + void SignalAndWaitShutdown(); + void ThreadMain(); + +private: + + // spawns the network thread + void SpawnThread(); + + // main thread = these four functions, in a loop + void PollNetEvents(); + void ProcessRequests(); + void PushBufferUpdates(uint64_t dt); + void PushNetworkEvents(uint64_t dt); + + // handlers for requests (return value indicates 'done') + bool HandleRequest(ZNetworkRequest* req); + + bool HandleConnectRequest(ZNetworkRequest* req); + bool HandleDisconnectRequest(ZNetworkRequest* req); + bool HandleResetRequest(ZNetworkRequest* req); + bool HandleStopNetworkRequest(ZNetworkRequest* req); + + // handlers for ENet Events + void HandleEvent(ENetEvent* ev); + + // server side + void ServerHandleConnectEvent(ENetEvent* ev); // initial connection event from ENet + void ServerHandleDisconnectEvent(ENetEvent* ev); // disconnect event from ENet + void ServerHandleReceiveEvent(ENetEvent* ev); // data received (any channel) + + void ServerReceiveJoinMessage(ZRemotePeer* client, const void* data, uint32_t len); // process client (or server) join message + + void ServerReceiveSystemChannel(ZRemotePeer* client, const void* data, uint32_t len); // data received + void ServerReceiveUpdateChannel(ZRemotePeer* client, const void* data, uint32_t len); // data received on update channel + void ServerReceiveEventChannel(ZRemotePeer* client, const void* data, uint32_t len); // data received on event channel + + // client side + void ClientHandleConnectEvent(ENetEvent* ev); // initial connect event from ENet + void ClientHandleDisconnectEvent(ENetEvent* ev); // disconnect event from ENet + void ClientHandleReceiveEvent(ENetEvent* ev); // data received (any channel) + + void ClientRecieveJoinResponse(const void* data, uint32_t len); // process server response from join message + + void ClientReceiveSystemChannel(const void* data, uint32_t len); // data received on system channel + void ClientReceiveUpdateChannel(const void* data, uint32_t len); // data received from server on update channel + void ClientReceiveEventChannel(const void* data, uint32_t len); // data received from server on event channel + + // adds and removes a network node mapping + void AddNode(const ZString& node, const ZString& host); + void RemoveNode(const ZString& node); + + enum Netstate { + UNINITIALIZED, // not yet initialized as client or server + DISCONNECTED, // initialized as client and disconnected + LISTEN, // initialized as server and listening for connections + CONNECTING, // initiating low-level connection + JOINING, // connected, but not yet ready to play + CONNECTED // connected and ready to SIMULATE + }; + + ZSimulation& Sim; // simulation reference + ZString Name; // network name + + Netstate State; // state of this service + SST_Thread Thread; // thread running this service + + bool bIsServer; // true if initialized as server + bool bIsConnected; // true if connected + volatile int iShouldShutdown; // shutdown flag + + ENetHost* Host; // enet host service (server and client) + ENetPeer* RemoteServer; // as a client, this is the server (otherwise NULL) + uint32_t NrConnectionsMax; // max number of connections + ZRemotePeer* Connections; // all connections (as client, only a single remote peer, the server) + + ZMutex NodesMutex; // mutex for locking access to nodes listing + ZArray> Nodes; // node name and host name pairing for all simulations on the network + + void* PacketBuffer; // packet data buffer, used as local copy + size_t PacketBufferSize; // size of the buffer + + ZMutex QueueMutex; // mutex for locking access to request queue + ZArray SharedRequestQueue; // network request queue + ZNetworkRequest* CurrentRequest; // network request currently being processed + uint32_t WaitTime; // value used to modify polling frequency + + ZArray PendingRequests; // queue used to process a single tick worth of requests + + NetworkUpdateQueue DelayedUpdates; // updates that are being delayed for artificial lag simulation + NetworkEventQueue DelayedEvents; // events that are being delayed for artificial lag simulation +}; + +#endif \ No newline at end of file diff --git a/Include/ZSimulation/ZNetworkUpdateStream.hpp b/Include/ZSimulation/ZNetworkUpdateStream.hpp new file mode 100644 index 0000000..9ae182e --- /dev/null +++ b/Include/ZSimulation/ZNetworkUpdateStream.hpp @@ -0,0 +1,114 @@ +/* + ZNetworkUpdateStream.hpp + Author: James Russell + Created: 9/13/2015 + + Purpose: + + Exists for the express purpose of holding onto network events and property updates + that the simulation wants to send out, and providing them to the network system when + the network system requires them. + + In addition, holds onto network events and updates received until the simulation asks + for them. + + License: + + TODO + +*/ + +#pragma once + +#ifndef _ZNETWORKUPDATESTREAM_HPP +#define _ZNETWORKUPDATESTREAM_HPP + +#include +#include + +#include "ZNetworkEvent.hpp" +#include "ZPropertyBufferUpdate.hpp" + +// forward decl +class ZSimulation; + +// typedefs +typedef ZArray> NetworkEventQueue; +typedef ZArray> NetworkUpdateQueue; + +// class decl +class ZNetworkUpdateStream { +public: + + // event constructor and destructor function + typedef ZNetworkEvent* (*EventConstructor)(); + typedef void (*EventDestructor)(ZNetworkEvent*); + + // c'tor + ZNetworkUpdateStream(); + + // d'tor + ~ZNetworkUpdateStream(); + + /* + Maps an event type to an event constructor and destructor. Events will not be properly recreated + unless the type is mapped to a constructor function. + */ + void MapEventAlloc(nID type, EventConstructor ctor, EventDestructor dtor); + + /* + Allocator for events and updates. The version without id will be called by the network + system - the deserialize method will fill out the id. + */ + ZNetworkEvent* AllocEvent(nID type); + ZPropertyBufferUpdate* AllocUpdate(eID id); + ZPropertyBufferUpdate* AllocUpdate(); + + /* + Deallocation for events and updates. + */ + void DeallocEvent(ZNetworkEvent* e); + void DeallocUpdate(ZPropertyBufferUpdate* u); + + /* + Enqueues an event or update to sync across the network. + */ + void EnqueueOutgoingEvent(ZNetworkEvent* e); + void EnqueueOutgoingUpdate(ZPropertyBufferUpdate* u); + void EnqueueOutgoingUpdates(NetworkUpdateQueue& q); + + /* + Enqueues an event or update to be processed here. + */ + void EnqueueIncomingEvent(ZNetworkEvent* e); + void EnqueueIncomingEvents(NetworkEventQueue& q); + void EnqueueIncomingUpdate(ZPropertyBufferUpdate* u); + void EnqueueIncomingUpdates(NetworkUpdateQueue& q); + + /* + Read outgoing events or updates to sync across the network. + */ + void ReadOutgoingEvents(NetworkEventQueue& out); + void ReadOutgoingUpdates(NetworkUpdateQueue& out); + + /* + Processes events or updates that have been enqueued. + */ + void ProcessIncomingEvents(ZSimulation& sim); + void ProcessIncomingUpdates(ZSimulation& sim); + +private: + DISABLE_COPY_AND_ASSIGN(ZNetworkUpdateStream); + + ZMutex EventMutex[2]; // mutex for event queues (incoming / outgoing) + ZMutex UpdateMutex[2]; // mutex for update queues (incoming / outgoing) + + NetworkEventQueue Events[2]; // buffered events (incoming / outgoing) + NetworkUpdateQueue Updates[2]; // buffered updates (incoming / outgoing) + + ZHashMap> Constructors; // ctor and dtor for network events +}; + + +#endif \ No newline at end of file diff --git a/Include/ZSimulation/ZPropertyBuffer.cpp b/Include/ZSimulation/ZPropertyBuffer.cpp new file mode 100644 index 0000000..6061e98 --- /dev/null +++ b/Include/ZSimulation/ZPropertyBuffer.cpp @@ -0,0 +1,454 @@ +#include +#include + +#include + +#define BUFFER_SYNC 0 +#define BUFFER_LOCAL 1 +#define BUFFER_WRITE 0 +#define BUFFER_READ 1 + +#define MIN_ALLOC 4 + +struct PropertyPage { + eID Id; // id of the entity that these properties are allocated for + void* Data[2]; // the data for this page (read and write) + size_t Size; // amount of data on this page + size_t Offset; // the current offset on this page + PropertyPage* Next; // the next page, or NULL + + ZArray> Avail; // available data slots on this page + ZArray> Updates; // properties that have been updated since last update + + // c'tor + PropertyPage(size_t alloc_size) : Next(NULL) { + Data[0] = SST_OS_AllocPages(alloc_size*2); // allocate 2x to account for read and write + Data[1] = (char*)Data[0] + alloc_size; // split in half, with first half being write and second for read + Size = alloc_size; + Offset = 0; + } + + // d'tor + ~PropertyPage() { + delete Next; + if (Size > 0) { + SST_OS_FreePages(Data[0], Size*2); + } + } +}; + +/*************************************************************************/ + +// Key is currently a 64 bit integer, which is partitioned as follows +// +// [ SYNC MOE (2) | OFFSET (14) | SUB PAGE (16) | PAGE (32) ] + +static ZPropertyBuffer::PropertyKey GenerateKey(ZPropertyBuffer::SyncMode mode, uint32_t page, uint16_t sub_page, uint16_t offset) { + + uint64_t key; + + key = mode; + key = key << 14; + key = key + offset; + key = key << 16; + key = key + sub_page; + key = key << 32; + key = key + page; + + // dumb assert + static_assert(sizeof(eID) == 4, "Cannot generate property key with sizeof(eID) not 32 bits, update property buffer"); + + return key; +} + +static void ParseKey(ZPropertyBuffer::PropertyKey key, ZPropertyBuffer::SyncMode* mode, uint32_t* page, uint16_t* sub_page, uint16_t* offset) { + *page = (uint32_t)(key & 0xFFFFFFFF); + *sub_page = (uint16_t)((key >> 32) & 0xFFFF); + *offset = (uint16_t)((key >> 48) & 0x3FFF); + *mode = (ZPropertyBuffer::SyncMode)((key >> 62) & 0xFFFF); +} + +void* ZPropertyBuffer::GetData( PropertyKey key, int rw, PropertyPage** page_out /*= NULL*/, SyncMode* mode_out /*= NULL*/ ) +{ + SyncMode mode; + uint32_t page_idx; + uint16_t sub_page_idx, offset; + + ParseKey(key, &mode, &page_idx, &sub_page_idx, &offset); // parse data key + + ZArray& pages = mode != SYNC_NONE ? Pages[BUFFER_SYNC] : + Pages[BUFFER_LOCAL]; // determine if we are using sync or local data + + if (pages.Size() >= page_idx) { // determine if we have this many pages + PropertyPage* page = pages[page_idx]; + + for (size_t i = 0; i < sub_page_idx; i++) { // see of we can find the sub page + page = page->Next; + if (page == NULL) { // check for bad sub page index + return NULL; + } + } + + if (offset % MIN_ALLOC == 0 && offset <= page->Size - MIN_ALLOC) { // see if our offset is valid + if (page_out != NULL) *page_out = page; // get pointer to page + if (mode_out != NULL) *mode_out = mode; // get sync value + return (char*)page->Data[rw] + offset; // get read / write pointer + } else return NULL; + } else return NULL; +} + +/*************************************************************************/ + +ZPropertyBuffer::Property ZPropertyBuffer::AllocData( PropertyPage* page, eID id, uint32_t page_idx, size_t size, SyncMode mode) +{ + Property prop; + + ZArray& pages = mode ? Pages[BUFFER_SYNC] : Pages[BUFFER_LOCAL]; // determine if we are using sync or local data + + size_t alloc_size = size > MIN_ALLOC ? (size + MIN_ALLOC - 1) & ~(MIN_ALLOC - 1) // ensure we allocate at least MIN_ALLOC, and align to MIN_ALLOC + : size; + + uint16_t sub_page_idx; + + for (sub_page_idx = 0; page != NULL; sub_page_idx++) { // loop pages seeing if we can drop the data in here + if (page->Offset + size <= page->Size) { // see if we have room + uint16_t offset = (uint16_t)page->Offset; // we do, so get current offset + page->Offset = page->Offset + alloc_size; // increment stored offset by alloc size, not property size + prop.Key = GenerateKey(mode, page_idx, sub_page_idx, offset); // key for this value + prop.Write = (char*)page->Data[BUFFER_WRITE] + offset; // write pointer for this value + prop.Read = (char*)page->Data[BUFFER_READ] + offset; // read pointer for this value + prop.Size = size; // size of this value + return prop; + } else { + for (size_t i = 0; i < page->Avail.Size(); i++) { // for each available slot from previous deallocs + if (page->Avail[i].Second >= size) { // see if we have room + uint16_t offset = (uint16_t)page->Avail[i].First; // we do, so store the offset + page->Avail.Erase(i); // no longer available + prop.Key = GenerateKey(mode, page_idx, sub_page_idx, offset); // key for this value + prop.Write = (char*)page->Data[BUFFER_WRITE] + offset; // write pointer for this value + prop.Read = (char*)page->Data[BUFFER_READ] + offset; // read pointer for this value + prop.Size = size; // size of this value + return prop; + } + } + + if (page->Next != NULL) { + page = page->Next; // NEXT + } else { + sub_page_idx++; // sub page index will be next index + break; + } + } + } + + // found nothing, time to allocate new + + if (Pages[BUFFER_LOCAL].Size() <= page_idx) { // push NULL entry for local buffer if not present at page_idx + Pages[BUFFER_LOCAL].PushBack(NULL); + } + + if (Pages[BUFFER_SYNC].Size() <= page_idx) { // push NULL entry for sync buffer if not present at page_idx + Pages[BUFFER_SYNC].PushBack(NULL); + } + + const uint32_t page_size = SST_OS_GetPageSize(); // system page size + const uint32_t min_buffer_alloc = page_size / 2; // minimum amount we will allocate + + uint32_t page_alloc_size = min_buffer_alloc; // starting page alloc + + if (size > page_alloc_size) { + page_alloc_size = + ((size+min_buffer_alloc-1) & ~(min_buffer_alloc-1)); // round up to nearest multiple of min_buffer_alloc + } + + PropertyPage* npage = new PropertyPage(page_alloc_size); // new page + npage->Id = id; // set id for page + npage->Offset = alloc_size; // allocate enough space for the first property + + if (page != NULL) { // link page into page list + page->Next = npage; + } else { // allocating new pages + pages[page_idx] = npage; + } + + prop.Key = GenerateKey(mode, page_idx, sub_page_idx, 0); // generate a key for the correct page with sub-page and offset 0 + prop.Write = (char*)npage->Data[BUFFER_WRITE]; // set the write pointer + prop.Read = (char*)npage->Data[BUFFER_READ]; // set the read pointer + prop.Size = size; // set the size of the data + return prop; +} + +/*************************************************************************/ + +ZPropertyBuffer::ZPropertyBuffer() +{ + +} + +/*************************************************************************/ + +ZPropertyBuffer::~ZPropertyBuffer() +{ + for (size_t i = 0; i < Pages[BUFFER_LOCAL].Size(); i++) { + delete Pages[BUFFER_LOCAL][i]; + } + + for (size_t i = 0; i < Pages[BUFFER_SYNC].Size(); i++) { + delete Pages[BUFFER_SYNC][i]; + } +} + +/*************************************************************************/ + +ZPropertyBuffer::Property ZPropertyBuffer::AllocProperty(eID id, size_t size, SyncMode mode) +{ + // sanity check - synchronized properties should be less than ZSIM_BUFFER_SYNC_MAX + ZASSERT_RUNTIME(!mode || size < ZSIM_SYNCBUFFER_MAX, "Synchronized property allocation too large!"); + + auto itr = IdPageMap.Find(id); + + ZArray& pages = mode != SYNC_NONE ? Pages[BUFFER_SYNC] : + Pages[BUFFER_LOCAL]; + + if (itr != IdPageMap.End()) { + uint32_t page_idx = itr.GetValue(); + PropertyPage* page = pages[page_idx]; + + return AllocData(page, id, page_idx, size, mode); + } + + if (Avail.Size() > 0) { + size_t page_idx = Avail.PopBack(); + IdPageMap.Put(id, page_idx); + return AllocData(NULL, id, page_idx, size, mode); + } else { + IdPageMap.Put(id, pages.Size()); + return AllocData(NULL, id, pages.Size(), size, mode); + } +} + +/*************************************************************************/ + +void ZPropertyBuffer::DeallocEntity( eID id ) +{ + auto itr = IdPageMap.Find(id); + + if (itr != IdPageMap.End()) { + uint32_t page_idx = itr.GetValue(); + + delete Pages[BUFFER_LOCAL][page_idx]; + delete Pages[BUFFER_SYNC][page_idx]; + + Pages[BUFFER_LOCAL][page_idx] = NULL; + Pages[BUFFER_SYNC][page_idx] = NULL; + + Avail.PushBack(page_idx); + + IdPageMap.Erase(id); + } +} + +/*************************************************************************/ + +void ZPropertyBuffer::DeallocProperty( PropertyKey key, size_t size ) +{ + SyncMode mode; + uint32_t page_idx; + uint16_t sub_page_idx, offset; + + ParseKey(key, &mode, &page_idx, &sub_page_idx, &offset); + + ZArray& pages = mode != SYNC_NONE ? Pages[BUFFER_SYNC] : + Pages[BUFFER_LOCAL]; + + PropertyPage* page = pages[page_idx]; + + for (size_t i = 0; i < sub_page_idx; i++) { + page = page->Next; + } + + page->Avail.PushBack(ZPair(offset, size)); +} + +/*************************************************************************/ + +void ZPropertyBuffer::FlagModified( PropertyKey key, size_t size ) +{ + PropertyPage* page; + SyncMode mode; + + void* data = GetData(key, BUFFER_WRITE, &page, &mode); + + ZASSERT(data != NULL && page != NULL, "Attempt to flag modified on invalid property key"); + + page->Updates.PushBack(ZPair(key, size)); +} + +/*************************************************************************/ + +void ZPropertyBuffer::UpdateModified(bool sync, ZNetworkUpdateStream& stream) +{ + // wherever we have an update, copy the write buffer + for (size_t b = 0; b < 2; b++) { + for (size_t i = 0; i < Pages[b].Size(); i++) { + PropertyPage* page = Pages[b][i]; + ZPropertyBufferUpdate* buffer_update = NULL; + + // synchronized buffers require a property buffer update call + if (sync && b == BUFFER_SYNC && page != NULL && page->Updates.Size() > 0) { + buffer_update = stream.AllocUpdate(page->Id); + } + + // for all pages and sub-pages + while (page != NULL) { + for (size_t j = 0; page != NULL && j < page->Updates.Size(); j++) { + PropertyKey key = page->Updates[j].First; + size_t size = page->Updates[j].Second; + + SyncMode mode; + uint32_t page_idx; + uint16_t sub_page_idx, offset; + + ParseKey(key, &mode, &page_idx, &sub_page_idx, &offset); + + void* data = (char*)page->Data[BUFFER_WRITE] + offset; + MemCopyChar((char*)page->Data[BUFFER_READ] + offset, data, size); + + // if needed, make it happen + if (buffer_update != NULL && mode == SYNC_SEND) { + ZPropertyBufferUpdate::Update update; + + update.SubPage = sub_page_idx; + update.Offset = offset; + update.Size = size; + update.Data = (char*)page->Data[BUFFER_READ] + offset; + + buffer_update->Updates.PushBack(update); + } + } + + page->Updates.Clear(); + page = page->Next; + } + + // push the entity update + if (buffer_update != NULL) { + stream.EnqueueOutgoingUpdate(buffer_update); + } + } + } +} + +/*************************************************************************/ + +void ZPropertyBuffer::UpdateModified( eID id, bool sync, ZNetworkUpdateStream& stream ) +{ + auto itr = IdPageMap.Find(id); + + if (itr != IdPageMap.End()) { + uint32_t page_idx = itr.GetValue(); + + // wherever we have an update, copy the write buffer + for (size_t b = BUFFER_LOCAL; b != BUFFER_SYNC; b = BUFFER_SYNC) { + PropertyPage* page = Pages[b][page_idx]; + ZPropertyBufferUpdate* buffer_update = NULL; + + // synchronized buffers require a property buffer update call + if (sync && b == BUFFER_SYNC && page != NULL) { + buffer_update = stream.AllocUpdate(id); + } + + // for all pages and sub-pages + while (page != NULL) { + for (size_t j = 0; page != NULL && j < page->Updates.Size(); j++) { + PropertyKey key = page->Updates[j].First; + size_t size = page->Updates[j].Second; + + SyncMode mode; + uint32_t page_idx; + uint16_t sub_page_idx, offset; + + ParseKey(key, &mode, &page_idx, &sub_page_idx, &offset); + + void* data = (char*)page->Data[BUFFER_WRITE] + offset; + MemCopyChar((char*)page->Data[BUFFER_READ] + offset, data, size); + + if (buffer_update != NULL && mode == SYNC_SEND) { + ZPropertyBufferUpdate::Update update; + + update.SubPage = sub_page_idx; + update.Offset = offset; + update.Size = size; + update.Data = (char*)page->Data[BUFFER_READ] + offset; + + buffer_update->Updates.PushBack(update); + } + } + + page->Updates.Clear(); + page = page->Next; + } + + // push the entity update + if (buffer_update != NULL) { + stream.EnqueueOutgoingUpdate(buffer_update); + } + } + } else { + SystemLogError("Unable to update entity property buffer - invalid id"); + } +} + +/*************************************************************************/ + +static void* GetSyncData(PropertyPage* page, uint16_t offset) +{ + if (offset % MIN_ALLOC == 0 && offset <= page->Size - MIN_ALLOC) { // see if our offset is valid + return (char*)page->Data[BUFFER_READ] + offset; // return read + } else return NULL; +} + +void ZPropertyBuffer::ApplyBufferUpdates( const ZArray& updates ) +{ + for (size_t i = 0; i < updates.Size(); i++) { + ZPropertyBufferUpdate& buffer_update = *updates[i]; + eID id = buffer_update.Id; + + ZArray& pages = Pages[BUFFER_SYNC]; // always sync data + + auto itr = IdPageMap.Find(id); // find page mapped for id + + if (itr != IdPageMap.End()) { // make sure we have a valid one + uint32_t page_idx = itr.GetValue(); + PropertyPage* base_page = pages[page_idx]; + + for (size_t j = 0; j < buffer_update.Updates.Size(); j++) { + ZPropertyBufferUpdate::Update& update = buffer_update.Updates[j]; + + uint16_t sub_page_idx = update.SubPage; + uint16_t offset = update.Offset; + size_t size = update.Size; + + PropertyPage* sub_page = base_page; + + for (uint16_t k = 0; k < sub_page_idx; k++) { + if (sub_page->Next != NULL) { + sub_page = sub_page->Next; + } + } + + if (sub_page != NULL) { + void* rd_ptr = GetSyncData(sub_page, offset); + + if (rd_ptr != NULL) { + MemCopyChar(rd_ptr, update.Data, size); + } else { + SystemLogError("Recieved invalid buffer update offset"); + } + } else { + SystemLogError("Recieved invalid buffer update sub page"); + } + } + } + } +} diff --git a/Include/ZSimulation/ZPropertyBuffer.hpp b/Include/ZSimulation/ZPropertyBuffer.hpp new file mode 100644 index 0000000..3b7d7f4 --- /dev/null +++ b/Include/ZSimulation/ZPropertyBuffer.hpp @@ -0,0 +1,134 @@ +/* + ZPropertyBuffer.hpp + Author: author_name + Created: 8/30/2015 + + Purpose: + + The property buffer system is an allocator which holds entity property data in + contiguous blocks of memory that can then be synchronized across the network when + properties change, though properties can be kept in non-synchronized buffers for + local use. + + The buffer keeps both a read and write copy of the properties which can be updated + on call. + + This allocator does not lock, so any locking that would be required must be handled + by the caller. + + In order to have proper synchronization, each entity that has properties allocated + should have it's synchronized variables created in the same order on all machines. + This will ensure that the data layouts are identical and proper synchronization can + occur. + + License: + + TODO + +*/ + +#pragma once + +#ifndef _ZPROPERTYBUFFER_HPP +#define _ZPROPERTYBUFFER_HPP + +#include "ZSimulationDefs.hpp" +#include "ZPropertyBufferUpdate.hpp" + +// forward decl +struct PropertyPage; +class ZNetworkUpdateStream; + +// class decl +class ZPropertyBuffer +{ +public: + // key used to look up allocated data in the property buffer + typedef uint64_t PropertyKey; + + // used to flag synchronization type (none, send, or receive) + enum SyncMode { + SYNC_NONE = 0, + SYNC_SEND = 1, + SYNC_RECV = 2, + + SYNC_ENUM_SIZE + }; + + // data struct for property data + struct Property { + void* Read; // pointer to the read property + void* Write; // pointer to the write property + size_t Size; // size of the property + PropertyKey Key; // the property key + }; + + // c'tor + ZPropertyBuffer(); + + // d'tor + ~ZPropertyBuffer(); + + /* + Allocates a chunk of memory in the property buffer given the entity id, the entity size, + and whether or not the property should be synchronized. The read buffer for the property + is returned. + + Allocations from these methods return static sized properties - they will not ever be able + to increase in size - alloc a new property and remove the old one in order to increase + size. The size limit on a synchronized property is 1024 bytes. + + In order to have proper synchronization, each entity that has properties allocated + should have its synchronized variables created in the same order on all machines. + This will ensure that the data layouts are identical and proper synchronization can + occur. + */ + Property AllocProperty(eID id, size_t size, SyncMode mode = SYNC_NONE ); + + /* + Deallocation methods, which deallocate previously allocated property data. The version + which takes an entity id deallocates all data associated with that entity id. The + version which takes a property key merely deallocates that particular property. + + Deallocating individual properties is not terribly fast, so avoid it where possible. + */ + void DeallocEntity(eID id); + void DeallocProperty(PropertyKey key, size_t size); + + /* + Flags a previously allocated property as modified. The size (in bytes) of the property + is required. + */ + void FlagModified(PropertyKey key, size_t size); + + /* + Updates the read properties from the write properties where modifications have happened. + + The version which takes an entity id will update a single entities properties. + + If told to synchronize, the buffer will queue up the network updates needed to sync + the buffer state. + */ + void UpdateModified(bool sync, ZNetworkUpdateStream& stream); + void UpdateModified(eID id, bool sync, ZNetworkUpdateStream& stream); + + /* + Applies buffer updates that have been read from the network. These are applied directly + to the read value of the property. + */ + void ApplyBufferUpdates(const ZArray& updates); + +private: + /* synchronized and non-synchronized data storage */ + ZArray Pages[2]; // the individual buffer pages (synchronized and local) + ZHashMap IdPageMap; // maps the entity id to its page number + ZArray Avail; // available indices from dealloc'd entities + + // given the property key will get the data, page, and synchronization flag + void* GetData(PropertyKey key, int rw, PropertyPage** page_out = NULL, SyncMode* mode_out = NULL); + + // will alloc data for the property (searches page, otherwise makes new pages) + Property AllocData(PropertyPage* page, eID id, uint32_t page_idx, size_t size, SyncMode mode); +}; + +#endif \ No newline at end of file diff --git a/Include/ZSimulation/ZPropertyBufferUpdate.hpp b/Include/ZSimulation/ZPropertyBufferUpdate.hpp new file mode 100644 index 0000000..392a509 --- /dev/null +++ b/Include/ZSimulation/ZPropertyBufferUpdate.hpp @@ -0,0 +1,62 @@ +/* + ZBufferUpdate.hpp + Author: James Russell + Created: 9/13/2015 + + Purpose: + + Buffer updates are created by the property buffer when synchronization + happens. They are then passed along to the network service to be serialized + and sent across the wire. + + License: + + TODO + +*/ + +#pragma once + +#ifndef _ZPROPERTYBUFFERUPDATE_HPP +#define _ZPROPERTYBUFFERUPDATE_HPP + +#include + +#include "ZSimulationDefs.hpp" + +class ZPropertyBufferUpdate { +public: + // update marker for a single bit of data in the buffer + struct Update { + uint16_t SubPage; // sub property page + uint16_t Offset; // offset into buffer (NOT into Data) + size_t Size; // size of the data + void* Data; // pointer to the data + + uint8_t Local[ZSIM_SYNCBUFFER_MAX]; // local storage for Data (if copy is required) + }; + + eID Id; // entity we are updating in this packet + ZArray Updates; // the updates in the data array + int Delay; // simulated lag + + // c'tor + ZPropertyBufferUpdate(); + + // parameterized c'tor + ZPropertyBufferUpdate(eID id); + + // d'tor + ~ZPropertyBufferUpdate(); + + // called by the network system to serialize this update into binary form + void Serialize(ZBinaryBufferWriter& writer); + + // called by the network system to deserialize this update from binary form + bool Deserialize(ZBinaryBufferReader& reader); + + // called to get the serialized size of this update + size_t GetSerializedSize(); +}; + +#endif \ No newline at end of file diff --git a/Include/ZSimulation/ZPropertyBufferUpdateQueue.hpp b/Include/ZSimulation/ZPropertyBufferUpdateQueue.hpp new file mode 100644 index 0000000..63c5ad9 --- /dev/null +++ b/Include/ZSimulation/ZPropertyBufferUpdateQueue.hpp @@ -0,0 +1,33 @@ +/* + ZPropertyBufferUpdateQueue.hpp + Author: James Russell + Created: 9/17/2015 + + Purpose: + + License: + + Copyright 2015, 762 Studios. + +*/ + +#pragma once + +#ifndef _ZPROPERTYBUFFERUPDATEQUEUE_HPP +#define _ZPROPERTYBUFFERUPDATEQUEUE_HPP + +#include "ZPropertyBufferUpdate.hpp" + +class ZPropertyBufferUpdateQueue { +public: + // c'tor + ZPropertyBufferUpdateQueue(); + + // d'tor + ~ZPropertyBufferUpdateQueue(); + +private: + +}; + +#endif \ No newline at end of file diff --git a/Include/ZSimulation/ZRemotePeer.hpp b/Include/ZSimulation/ZRemotePeer.hpp new file mode 100644 index 0000000..2a0fdd7 --- /dev/null +++ b/Include/ZSimulation/ZRemotePeer.hpp @@ -0,0 +1,74 @@ +/* + RemoteClient.hpp + Author: Patrick Baggett , James Russell + Created: 12/2/2013 + + Purpose: + + Network peer as seen by a running simulation. May refer to either a + client or another server instance. + + License: + + Copyright 2013, 762 Studios. + +*/ + +#ifndef __ZREMOTEPEER_HPP +#define __ZREMOTEPEER_HPP + +#include + +class ZRemotePeer +{ +public: + // the client state + enum PeerState { + AVAILABLE, + JOINING, + CONNECTED, + CONNECTED_LOCAL, + DISCONNECTED + }; + + // c'tor + ZRemotePeer() : bIsClient(true), + State(AVAILABLE), + Peer(NULL) { } + + // getters + cID GetId() const { return Id; } + PeerState GetState() const { return State; } + bool IsClient() const { return bIsClient; } + const char* GetName() const { return Name; } + const char* GetHost() const { return Host; } + ENetPeer* GetPeer() { return Peer; } + + // setters + void SetId(cID id) { Id = id; } + void SetState(PeerState cs) { State = cs; } + void SetClient(bool isClient) { bIsClient = isClient; } + void SetName(const char* name) { strcpy(Name, name); } + void SetHostIP(const char* host) { strcpy(Host, host); } + void SetPeer(ENetPeer* newPeer) { Peer = newPeer; } + + // resets this peer object (must be called to reuse object and connection id) + void Reset() { + SetPeer(NULL); + SetState(AVAILABLE); + SetName(""); + SetHostIP(""); + SetClient(true); + } + +private: + cID Id; // id of this connection assigned by network service + ENetPeer* Peer; // peer object + PeerState State; // overall state + bool bIsClient; // true if this connects to a client + + char Host[ZSIM_NETWORK_MAX_HOST_LENGTH]; // host name in readable format + char Name[ZSIM_NETWORK_MAX_NAME_LENGTH]; // network 'name' (unique among network peers) +}; + +#endif \ No newline at end of file diff --git a/Include/ZSimulation/ZSimulation.hpp b/Include/ZSimulation/ZSimulation.hpp new file mode 100644 index 0000000..1d5b7c8 --- /dev/null +++ b/Include/ZSimulation/ZSimulation.hpp @@ -0,0 +1,327 @@ +/* + ZSimulation.hpp + Author: James Russell + Created: 2/4/2013 + + Purpose: + + Simulation base class for the ZSimulation project. Simulation is intended to be a server + that handles the simulation of a large number of interacting entities. Entities will + interact with each other via a messaging queue which will have handlers defined per + message type. + + Per this simulation, Actors are simply Entities with a 'think' function defined. + + The nominal difference between server and client instances is that client instances + can only ever connect to a single server instance, whereas server instances listen + for client connections and can connect to other server instances to share the + workload. + + License: + + Copyright 2013, 762 Studios +*/ + +#pragma once + +#ifndef ZSIMULATION_HPP +#define ZSIMULATION_HPP + +#include + +#include +#include + +#include + +#include "ZSimulationDefs.hpp" +#include "ZMessageStream.hpp" +#include "ZEntity.hpp" +#include "ZPropertyBuffer.hpp" +#include "ZNetworkService.hpp" + +/* +Simulation class, which handles the following sphere of responsibilities: + + * Fixed Timestep and Entity Update + * Entity Message Passing + * Entity Lifetime and Memory Management + * Entity Property Allocation + * Entity Property Network Synchronization + * Entity Type Declaration + * Entity State Declaration +*/ +class ZSimulation : public ZThread +{ +public: + // c'tor + ZSimulation(); + + // d'tor + virtual ~ZSimulation(); + + // initialization methods + bool InitAsServer(bool start = true); + bool InitAsClient(bool start = true); + + // shutdown method (this will deallocate entities) + void Shutdown(); + + // getters + uint32_t GetCurrentEntityCount() const { return CurrentEntityCount; } + const ZEntity* GetEntity(eID entityId) const { return Entities[entityId]; } + ZEntity* GetEntity(eID entityId) { return Entities[entityId]; } + ZArray& GetBaseEntities() { return BaseEntities; } + ZArray& GetActorEntities() { return ActorEntities; } + uint64_t GetCurrentFrame() const { return CurrentFrame; } + double GetCurrentFrameStartTime() const { return CurrentFrameStartTime; } + int16_t GetSimulationHz() const { return SimulationHz; } + double GetSimulationTimestep() const { return 1.0 / (double)SimulationHz; } + size_t GetSimulationThreadCount() const { return ThreadCount; } + ZPropertyBuffer& GetPropertyBuffer() { return PropertyBuffer; } + ZRandomGenerator& GetPRNG() { return PRNG; } + uint16_t GetListenPort() { return ListenPort; } + uint8_t GetSyncRate() { return SyncRate; } + ZNetworkService& GetNetworkService() { return NetworkService; } + ZNetworkUpdateStream& GetNetworkUpdateStream() { return NetworkUpdateStream; } + uint8_t GetNetworkSendRate() { return NetSendRate; } + ZString& GetNetworkName() { return NetName; } + bool IsServer() { return bIsServer; } + + // function getters (can return NULL) + ZEntity::InitFunc GetEntityInitFunc(const ZName& type); + ZEntity::InitFunc GetEntityInitFunc(ZHashValue type); + ZEntity::StateFunc GetEntityStateFunc(const ZName& name); + ZEntity::StateFunc GetEntityStateFunc(ZHashValue name); + + // setters + void SetHz(int16_t simHz) { SimulationHz = simHz; } + void SetThreadCount(int16_t threadCount) { ThreadCount = threadCount; } + void SetListenPort(uint16_t port) { ListenPort = port; } + void SetSyncRate(uint8_t rate) { SyncRate = rate; } + void SetNetworkName(const ZString& name) { NetName = name; } + + /* + Connection method. Connects to another simulation instance. Returns the network request + object which can be used to check status of the connection attempt. Delete the request + when done. + */ + ZNetworkRequest* Connect(const char* remoteHost); + + /* + Declares an entity and initialization function. All entity initialization functions + must be declared in order to ensure proper allocation of properties on all simulations, + client and server. + + It is recommended that all mapping be done during simulation initialization - no locking + or concurrent access mechanisms are used when looking up mapped data. + + The initialization function can be NULL, which will create an empty entity. + + Ensure when declaring entity types that the name provided has its string representation. + + @assert - on name collision (name hash resolves to same or entry already exists) + */ + void DeclareEntityType(const ZName& type, ZEntity::InitFunc init); + + /* + Declares an entity state function. Entity states are looked up by name to ensure recognition + on all simulations, client and server. + + It is recommended that all state mapping be done during simulation initialization - no locking + or concurrent access mechanisms are used when looking up mapped data. + + State functions cannot be NULL. + + @assert - on name collision (name hash resolves to same or entry already exists) + */ + void DeclareEntityState(const ZName& name, ZEntity::StateFunc state); + + /* + Given the name, gives a string name for an entity type or state. These exist because names + can be constructed without a string representation (such as when used for network communication). + */ + ZString LookupEntityTypeName(const ZName& type); + ZString LookupEntityStateName(const ZName& name); + + /* + Spawn methods which add an entity to the simulation, returning the eID (0 if failure). + + Variant which takes an eID request that an entity with a specific eID be added (returns + false if unable to create). + + @assert - if the entity type is undefined + */ + eID SpawnEntity(const ZName& type); + bool SpawnEntity(const ZName& type, eID id); + + /* + Kill method, which removes entities from the simulation. This call cleans up the entity and any + memory it has allocated. + */ + void KillEntity(eID id); + + /* + Sends a message through the simulation message queue, which will copy data from + a struct into the message for you (MT must be a POD type). Local messages are not + reflected across the network. + */ + template void SendLocalMessage(mID type, MT payload) const + { const_cast(this)->MessageQueue.Send(type, ZSIM_EID_SYSTEM, ZSIM_EID_SYSTEM, payload); } + + template void SendLocalMessage(mID type, eID sender, eID target, MT payload) const + { const_cast(this)->MessageQueue.Send(type, sender, target, payload); } + + /* + Sends a message across the network, which will be processed by the message queue of + another connected simulation. MT must be POD type and in order to ensure proper + processing it should not contain pointers as these will be invalid on the other side. + */ + template void SendNetworkMessage(mID type, MT payload, cID connection) const + { const_cast(this)->NetworkUpdateStream.EnqueueOutgoingEvent(new (std::nothrow) ZMessageEvent(type, ZSIM_EID_SYSTEM, ZSIM_EID_SYSTEM, payload, connection)); } + + template void SendNetworkMessage(mID type, eID sender, eID target, MT payload, cID connection) const + { const_cast(this)->NetworkUpdateStream.EnqueueOutgoingEvent(new (std::nothrow) ZMessageEvent(type, sender, target, payload, connection)); } + + /* + Pushes a task onto the task stream. This task will be executed by the simulation after + simulation tasks have completed. + */ + void PushTask(ZPtr task); + void PushTasks(ZArray>& tasks); + + /* + Pushes a future onto the task stream, which can be used to evaluate task progress. + */ + template void PushFuture(ZPtr> future) { + TaskStream.PushFuture(future); + } + + /* + Pushes or Pops a message handler onto the simulation. These message handlers are used for + messages that are directed at the simulation or for messages that do not have a valid + target entity. + */ + void PopHandler(mID type); + void PushHandler(mID type, ZMessageHandler handler); + + /* + These methods notify the simulation that a targeted message was handled correctly or was + unhandled. The simulation will return these messages to the message pool. These functions + are primarily used by entities as they handle their own message queues. + */ + void HandledMessage(ZMessage* msg) const; + void UnhandledMessage(ZMessage* msg) const; + + /* + This method notifies the simulation that an entity has had one or more of it's properties + deleted. It's not terribly efficient to delete entity properties - use sparingly. + */ + void PropertyDeleted(eID id); + +protected: + int16_t SimulationHz; // current simulation Hz (tick rate per second) + size_t ThreadCount; // number of concurrent simulation threads + + double CurrentTime; // current tick count (most recent) + double TotalTime; // total number of ticks that have been processed + double Accumulator; // tick accumulator, used to help fix the timestep + double LastSync; // the time we last did a network sync + + uint64_t CurrentFrame; // number of simulation frames that have passed + double CurrentFrameStartTime; // time at the start of the current frame + + uint32_t CurrentEntityCount; // number of entities we have spawned + size_t CurrentEntityIndex; // next entity we will hand out for simulation entities + ZEntity* Entities[ZSIM_EID_MAX + 1]; // array mapping of entity id -> entity + + ZArray BaseEntities; // base entities that have been created (no think state) + ZArray ActorEntities; // actor entities that have been created (has a think state) + + ZMessageStream MessageQueue; // message queue for the simulation + ZTaskStream TaskStream; // task stream for the simulation, which concurrently processes actors + ZRandomGenerator PRNG; // PRNG for the simulation + + ZNetworkService NetworkService; // network service for this simulation + ZNetworkUpdateStream NetworkUpdateStream; // the network update stream that processes sync and events + bool bIsServer; // set by which init method we call + uint16_t ListenPort; // listen port for this simulation server (0 = don't listen) + uint8_t SyncRate; // the number of times per second we should send network updates + uint8_t NetSendRate; // the rate at which the buffers are synchronized (updates per second) + ZString NetName; // the name of this server / client on the network + + ZPropertyBuffer PropertyBuffer; // allocator and sync manager for entity properties + ZArray PropertyDeletedStack; // list of entities that have had a property deleted + ZMutex PropertyDeletedLock; // lock for manipulating PropertyDeletedStack + + ZHashMap EntityTypeMap; // map of entity name to initialization functions + ZHashMap EntityStateMap; // map of entity name to initialization functions + + // function to get the next entity id available + eID GetNextEntityId() + { + size_t startIndex = CurrentEntityIndex; + + ZEntity* ent = Entities[CurrentEntityIndex]; + + while (ent != NULL) + { + CurrentEntityIndex++; + + if (CurrentEntityIndex > ZSIM_EID_MAX) + CurrentEntityIndex = 0; + + ZASSERT_RUNTIME(CurrentEntityIndex != startIndex, "No available entity Id's! Also, wow, that's a lot of entities."); + + ent = Entities[CurrentEntityIndex]; + } + + return (eID)CurrentEntityIndex; + } + + // Entity allocation methods (override in subclass to use specialized memory management) + virtual ZEntity* AllocEntity(eID entityId); + virtual ZEntity* AllocEntity(eID entityId, ZEntity::StateFunc startState); + virtual void DeallocEntity(ZEntity* entity); + + // Thread initialization method and shutdown method (be sure to call ZSimulation::initThread and ZSimulation::shutdownThread if subclassed) + virtual void initThread(); + virtual void shutdownThread(); + + // Overridden 'Run' Method + virtual ZThreadReturn run(uint64_t dt); + + // Exposed Init and Shutdown methods for subclass simulations to implement + virtual bool SubInitServer() { return true; } + virtual bool SubInitClient() { return true; } + virtual void SubShutdown() { } + + // Exposed 'Simulation Tick' method for subclass simulations to implement + virtual void Tick(double dt) { URFP(dt); } + + // Some private static functions for handling the base message types + static void HandleNetworkSystemShutdown(eID sender, eID target, void* payload, ZSimulation& sim); // + static void HandleConnectionEstablished(eID sender, eID target, void* payload, ZSimulation& sim); // + static void HandleConnectionFailed(eID sender, eID target, void* payload, ZSimulation& sim); // + static void HandleConnectionLost(eID sender, eID target, void* payload, ZSimulation& sim); // + static void HandleServerNodeGained(eID sender, eID target, void* payload, ZSimulation& sim); // + static void HandleServerNodeLost(eID sender, eID target, void* payload, ZSimulation& sim); // + + static void HandleSpawnEntity(eID sender, eID target, void* payload, ZSimulation& sim); // spawns an entity of a specific type + static void HandleGainState(eID sender, eID target, void* payload, ZSimulation& sim); // transitions entity to 'actor' status + static void HandleLoseState(eID sender, eID target, void* payload, ZSimulation& sim); // transitions from 'actor' to 'base entity' status + static void HandleKill(eID sender, eID target, void* payload, ZSimulation& sim); // removes an entity from the simulation + + static void HandleShutdownSimulation(eID sender, eID target, void* payload, ZSimulation& sim); // handles a shutdown message (shuts down this simulation) + + static void HandleSetInt(eID sender, eID target, void* payload, ZSimulation& sim); // sets the integer value of a property + static void HandleSetDbl(eID sender, eID target, void* payload, ZSimulation& sim); // sets the real number value of a property + static void HandleSetVec(eID sender, eID target, void* payload, ZSimulation& sim); // sets the vector value of a property + static void HandleSetMat(eID sender, eID target, void* payload, ZSimulation& sim); // sets the matrix value of a property + static void HandleSetStr(eID sender, eID target, void* payload, ZSimulation& sim); // sets the string value of a property + +private: + DISABLE_COPY_AND_ASSIGN(ZSimulation); +}; + +#endif diff --git a/Include/ZSimulation/ZSimulationDefs.hpp b/Include/ZSimulation/ZSimulationDefs.hpp new file mode 100644 index 0000000..2791544 --- /dev/null +++ b/Include/ZSimulation/ZSimulationDefs.hpp @@ -0,0 +1,299 @@ +/* + ZFrameworkDefs.hpp + Author: James Russell + Created: 2/5/2013 + + Purpose: + + This is our definitions and typedefs file for the ZFramework project. + + License: + + Copyright 2013, 762 Studios +*/ + +#pragma once + +#ifndef _ZSIMULATIONDEFS_HPP +#define _ZSIMULATIONDEFS_HPP + +#include "pstdint.h" + +#include // For SST_Vec*, SST_Mat* +#include // For SST_NetResult + +#include // For Build Definitions + +////////////////////////////////////////////////////////////////////////// +// Defines + +#ifndef ZSIM_ENT_STATE_STACK_SIZE +#define ZSIM_ENT_STATE_STACK_SIZE (16) // size of the entity state stack (maximum number of pushed states) +#endif + +#define ZSIM_DEFAULT_HZ (10) // Simulation default Hz +#define ZSIM_EID_MAX UINT16_MAX // Maximum eID that will ever be returned by the simulation +#define ZSIM_EID_SYSTEM (0) // eID that signifies target is 'system' or the running simulation +#define ZSIM_MSG_USER_BASE (128) // This is the base required Id for user messages (anything lower is reserved) + +#define ZSIM_SYNCBUFFER_MAX (1024) // Maximum size of a buffer-synchronized property +#define ZSIM_STRINGBUFFER_DEFAULT (65535) // Default size of the string buffer + +#define ZSIM_NETWORK_MAX_PEER_ID (32) // Maximum length of a peer id string +#define ZSIM_NETWORK_SLOT_LOCAL (0) // Array position for a local client +#define ZSIM_NETWORK_MAX_PACKETSIZE (1400) // Maximum network packet data size (coincidentally, size of the local buffer used to read packets) +#define ZSIM_NETWORK_REPLY_TIMEOUT (50) // Timeout on waiting for a reply from a connection +#define ZSIM_NETWORK_LISTEN_PORT (0x762C) // Listen port for the simulation (port 30252) +#define ZSIM_NETWORK_PROTOCOL_VERSION 0x1000000 // Protocol version +#define ZSIM_NETWORK_BYTEORDER SST_BIG_ENDIAN // Net system byteorder +#define ZSIM_NETWORK_DISCONNECT_TIME (1000) // Amount of time (in ms) we will send disconnection notices before giving up +#define ZSIM_NETWORK_MAX_CONNECTIONS (64) // Default number of maximum connections +#define ZSIM_NETWORK_MAX_CHANNELS (3) // Maximum number of network channels +#define ZSIM_NETWORK_CH_SYSTEM (0) // System Net Channel +#define ZSIM_NETWORK_CH_UPDATE (1) // Update Stream Net Channel +#define ZSIM_NETWORK_CH_EVENT (2) // Game Event Net Channel +#define ZSIM_NETWORK_SEND_RATE (10) // Number of buffer updates per second +#define ZSIM_NETWORK_MAX_NAME_LENGTH (128) // Maximum id length for a connection (steam max name length is 32, FYI) +#define ZSIM_NETWORK_MAX_HOST_LENGTH (1024) // Maximum length for readable host name +#define ZSIM_NETWORK_TARGET_ALL (UINT16_MAX) // Indicates the network event should target all connected + +#ifndef ZSIM_MESSAGE_SIZE +#define ZSIM_MESSAGE_SIZE (1024) // The payload size (in bytes) for a message, which can be interpreted via a layout definition +#endif + +#ifndef ZSIM_MESSAGE_ALLOC +#define ZSIM_MESSAGE_ALLOC (65535) //The number of messages the message stream holds locally +#endif + +////////////////////////////////////////////////////////////////////////// +// Typedefs + +// Equivalent to typedef T D;, but makes it a strong type +// ARE YOU NOT ENTERTAINED?!?! +#define strong_typedef(T, D) \ +struct D { \ + T t; \ + explicit D(const T _t) : t(_t) {} \ + D() {}; \ + D(const D& _t) : t(_t) {} \ + D& operator = (const D& other) { t = other.t; return *this; } \ + D& operator = (const T& other) { t = other; return *this; } \ + operator const T& () const { return t; } \ + operator T& () { return t; } \ + bool operator == (const D& other) { return t == other.t; } \ + bool operator < (const D& other) { return t < other.t; } \ + T value() { return t; } \ +} + +typedef uint32_t eID; // entity identifier +typedef uint16_t cID; // connection identifier +typedef uint32_t nID; // net event type identifier (0 reserved by simulation) +typedef uint32_t mID; // message type identifier (0 - 127 are reserved by the simulation) + +////////////////////////////////////////////////////////////////////////// +// Enumerations + +// base simulation message types +enum ZMessageType { + ZSIM_MSG_NETWORK_SHUTDOWN = 1, // network system has shutdown + + ZSIM_MSG_CONNECTION_ESTABLISHED, // connection attempt successful + ZSIM_MSG_CONNECTION_FAILED, // connection attempt failed + ZSIM_MSG_CONNECTION_LOST, // connection lost + + ZSIM_MSG_NODE_JOINED, // server node has joined the network + ZSIM_MSG_NODE_LOST, // server node has left the network + + ZSIM_MSG_ENT_SPAWN, // spawns an entity + ZSIM_MSG_ENT_GAIN_STATE, // entity has gained state (becomes Actor) + ZSIM_MSG_ENT_LOSE_STATE, // actor has lost state (becomes Entity) + ZSIM_MSG_ENT_KILL, // kills an entity + + ZSIM_MSG_SET_INT_PROPERTY, // sets an integer entity property + ZSIM_MSG_SET_REAL_PROPERTY, // sets a real number entity property + ZSIM_MSG_SET_STRING_PROPERTY, // sets a string entity property + ZSIM_MSG_SET_VEC_PROPERTY, // sets a vector entity property + ZSIM_MSG_SET_MAT_PROPERTY, // sets a matrix entity property + + ZSIM_MSG_SHUTDOWN_SIMULATION = ZSIM_MSG_USER_BASE - 1, // stops the running simulation and cleans up (can restart) +}; + +////////////////////////////////////////////////////////////////////////// +// Message Layouts + +#pragma pack (push, 1) // tightly compact data in message structs + +#if SST_COMPILER == SST_COMPILER_MSVC +#pragma warning(push) +#pragma warning(disable:4201) // Disables the warning about nameless structs +#pragma warning(disable:4100) // Disables the warning about unreferenced formal parameters +#endif + +/* Networking Messages */ + +/* +Sent to the simulation when the network system thread fails to initialize. +*/ +struct ZMessage_NetworkSystemShutdown { + int Reason; // 0 - stop network request, 1 - failed to poll for net events +}; + +/* +Sent to the simulation when a connection has been established. Contains information +about the connection and a connection identifier. +*/ +struct ZMessage_ConnectionEstablished { + cID ConnectionId; // id that has been assigned to this connection + int ConnectionType; // 0 - client, 1 - server, 2 - unknown + char NetworkName[ZSIM_NETWORK_MAX_NAME_LENGTH+1]; // network name given by the other simulation +}; + +/* +Sent to the simulation when a connection attempt has failed. Contains information +about the connection attempt. +*/ +struct ZMessage_ConnectionFailed { + int Reason; // 0 - unable to resolve host, 1 - no slots available, 2 - malformed response + char RemoteHost[ZSIM_NETWORK_MAX_HOST_LENGTH+1]; // remote host address that connection failed +}; + +/* +Sent to the simulation when a connection has been lost due to error. Contains information +about the error and a connection identifier. Any handler for this message should call +'Reset' on the remote peer object - otherwise the connection id remains unused. +*/ +struct ZMessage_ConnectionLost { + int Reason; // 0 - terminated here, 1 - terminated other side, 2 - connection unresponsive, 3 - malformed data + cID ConnectionId; // connection id for connection that was lost +}; + +/* +Sent to the simulation when another simulation instance is connected to the network. +Contains the name of the node and the name of its host node. +*/ +struct ZMessage_NodeGained { + char NodeName[ZSIM_NETWORK_MAX_NAME_LENGTH+1]; // network node name of the other simulation + char HostName[ZSIM_NETWORK_MAX_NAME_LENGTH+1]; // network node name of the host the simulation is connected to +}; + +/* +Sent to the simulation when a simulation node connection is lost. Contains the name +as well as a reason flag. +*/ +struct ZMessage_NodeLost { + int Reason; // 1 - connection terminated, 2 - connection unresponsive + char NodeName[ZSIM_NETWORK_MAX_NAME_LENGTH+1]; // network node name of the lost node +}; + +/* Simulation Messages */ + +/* +Spawns an entity into the simulation. +*/ +struct ZMessage_SpawnEntity { + eID RequestedId; // id being requested for the entity + ZHashValue Type; // the entity type (name hash) + ZHashValue State; // the state to spawn with (zero for no state) +}; + +/* +Notifies the simulation that an entity has gained state, turning a base entity into an +actor entity that will have state ticked. The sender must be a valid entity that has +gained an initial state. This is not needed if the entity is created with state. + +Message source is used to find the entity. +*/ +struct ZMessage_EntityGainState { +}; + +/* +Notifies the simulation that an actor entity has lost all state and become a base entity. +Base entities do not have their state ticked by the simulation (as they have none). + +Message source is used to find the entity. +*/ +struct ZMessage_EntityLoseState { +}; + +/* +Kills off an entity from the simulation. + +Message target is used to find the entity. +*/ +struct ZMessage_KillEntity { +}; + +/* +Simulation Stop message layout. This will take a shutdown message and shut down the +simulation. +*/ +struct ZMessage_ShutdownSimulation { + char ShutdownMessage[ZSIM_MESSAGE_SIZE]; // the shutdown message +}; + +/* Property Set Messages */ + +/* +All property set messages behave in a similar fashion to cope with the threaded processing +of values. + +Provided the original value of the property, this will set it if that value remains the same at +the time this message is processed. If the value has changed from the original value, this will +call the provided callback function to recompute the value. If the provided callback function is +NULL, set messages will simply apply the value regardless of original value. + +The function pointer always has the following signature: + + T callback_function(const T& new_value); + +Where T is the property type. Note that the behavior of set messages make them unsuitable +as network messages - rely on synchronized properties instead. +*/ + +/* +Templated set message. Contains the new value, the original value, and the name hash which +is used to look up the property. When this message is processed it will set the property +value regardless of the current read or write value. + +If you wish to have the message take the current value into account, use a lambda message. +*/ +template +struct ZMessage_Set { + uint64_t NameHash; + T Value; +}; + +typedef ZMessage_Set ZMessage_SetBool; +typedef ZMessage_Set ZMessage_SetInt; +typedef ZMessage_Set ZMessage_SetFloat; +typedef ZMessage_Set ZMessage_SetDouble; +typedef ZMessage_Set ZMessage_SetVector; +typedef ZMessage_Set ZMessage_SetMatrix; +typedef ZMessage_Set ZMessage_SetString; + +/* +Specialized set string message that holds the string in the message (up to ZSIM_MESSAGE_SIZE). +Useful when a pointer would leave scope befor the message can be processed. +*/ +struct ZMessage_SetStringCopy { + uint64_t NameHash; + char Value[ZSIM_MESSAGE_SIZE-sizeof(uint64_t)]; +}; + +/* +Templated lambda message. Simply carries a pointer to a lambda function which is run +on the property when this message is processed. +*/ +template +struct ZMessage_Lambda { + uint64_t NameHash; + T (*LambdaFnc)(const T&); +}; + +#if SST_COMPILER == SST_COMPILER_MSVC +#pragma warning(pop) +#endif + +#pragma pack (pop) + +#endif diff --git a/Include/ZSimulation/ZStringBuffer.hpp b/Include/ZSimulation/ZStringBuffer.hpp new file mode 100644 index 0000000..cca1aed --- /dev/null +++ b/Include/ZSimulation/ZStringBuffer.hpp @@ -0,0 +1,72 @@ +/* + ZStringBuffer.hpp + Author: James Russell + Created: 10/19/2016 + + Purpose: + + The string buffer is a specialized lookup table for strings, designed to hold + static strings for entity properties. In doing so, properties need merely keep + a reference key for a static string that is shared between entities and different + simulations, reducing memory usage and network traffic. + + Dynamic strings are stored within the property buffer and are limited in size. + + It is recommended that all static strings be declared during the simulation + initialization step, as no concurrency mechanisms are in place when looking up + strings from string keys. As such, there is no way of removing a string once + added. + + This class is implemented as a singleton. + + License: + + Copyright 2016, 762 Studios. + +*/ + +#pragma once + +#ifndef _ZSTRINGBUFFER_HPP +#define _ZSTRINGBUFFER_HPP + +#include "ZSimulationDefs.hpp" + +class ZStringBuffer +{ +public: + // typedef used to look up a static string + typedef uint32_t StringKey; + + // singleton instance getter + static ZStringBuffer* Instance() + { if (_Instance == NULL) _Instance = new ZStringBuffer(); return _Instance; } + + // adds a string to the buffer + StringKey AddString(const char* str); + + // given a string, finds the key (returns StringKey(-1) if not found) + StringKey GetKey(const char* str); + + // given a key, finds the string (returns NULL if not found) + const char* GetString(StringKey key); + +private: + static ZStringBuffer* _Instance; // singleton instance + + char* Buffer; // the buffer all strings will be stored in + size_t BufferSize; // current size of the buffer + size_t BufferOffset; // current offset into the buffer + + ZArray Offsets; // string key as index into this array, which provides offset into buffer + + ZHashMap> Lookup; // fast lookup for strings (narrows the search) + + // c'tor + ZStringBuffer(); + + // d'tor + ~ZStringBuffer(); +}; + +#endif \ No newline at end of file diff --git a/Include/ZUtil/ZAlloc.hpp b/Include/ZUtil/ZAlloc.hpp new file mode 100644 index 0000000..c0f7f26 --- /dev/null +++ b/Include/ZUtil/ZAlloc.hpp @@ -0,0 +1,161 @@ +/* + ZAlloc.hpp (created 9/12/10) + Author : James Russell + + Purpose : + + Memory allocation library and memory allocation tracker for ZEngine. If ZALLOC_EXTRA_SPAMMY is defined, + then allocations will log a message to stderr when allocation occurs indicating how much. + + License: + + TODO + +*/ + +#pragma once + +#ifndef _ZALLOC_H +#define _ZALLOC_H + +#include + +#include + +//The compiler really should be smart enough to include size_t in the global +//namespace by default. But, on some Linux configurations, it will drop +//it in std. Explicitly including this doesn't hurt anything. +#include + +#if ZALLOC_CHECK_ALLOC + +//Memory Checkpoint Struct +struct ZMemState +{ + int Checkpoint; //Checkpoint Number +}; + +//Allocation Info Struct +struct ZAllocInfo +{ + static int CurrentAllocCount; //Current number of unfreed allocations + static int CurrentCheckpoint; //Static current checkpoint tracker + + ZAllocInfo* Next; //Next Info Node + uintptr_t Address; //Address assigned + size_t Size; //Size of the allocation + int Line; //Line Number + int Checkpoint; //Checkpoint Integer + char File[128]; //File String +}; + +//Adds a tracking node for an allocation +extern void ZAllocAddTrack(uintptr_t _address, size_t _size, const char *_file, int _line, int _checkpoint); + +//Removes a tracking node for an allocation +extern void ZAllocRemoveTrack(uintptr_t _address); + +//Dumps unfreed memory string containing a list of memory leaks +extern void ZAllocDumpUnfreed(ZMemState *_state); + +//Debug Placement Operator New +extern void* operator new(size_t _size, const char *_file, int _line, int _checkpoint) throw(); +extern void* operator new[](size_t _size, const char *_file, int _line, int _checkpoint) throw(); + +//Debug Placement Delete +extern void operator delete(void *_ptr, const char* _file, int _line, int _checkpoint); +extern void operator delete[](void *_ptr, const char* _file, int _line, int _checkpoint); + +//Our arguments to znew +#define ZNEW_ARGS (__FILE__, __LINE__, ZAllocInfo::CurrentCheckpoint) + +//Macros for declaring a memory 'checkpoint' and +//dumping memory leaks to stderr +#define ZALLOC_MEM_CHECKPOINT(stateP) stateP->Checkpoint = AtomicAddReturn((volatile int*)&ZAllocInfo::CurrentCheckpoint, 1) +#define ZALLOC_MEM_DUMP_LEAKS(stateP) ZAllocDumpUnfreed(stateP) + +#else //!ZALLOC_CHECK_ALLOC + +#define ZNEW_ARGS (std::nothrow) + +#define ZALLOC_MEM_CHECKPOINT(stateP) +#define ZALLOC_MEM_DUMP_LEAKS(stateP) + +#endif //ZALLOC_CHECK_ALLOC + +/* Some definitions we need for znew_static */ + +//This is used to indicate a static allocation (basically a type flag) +struct znew_static_t { }; + +//Our actual static allocation overrides +extern void* operator new(size_t _size, znew_static_t _staticAlloc); +extern void* operator new[](size_t _size, znew_static_t _staticAlloc); + +/* Some Memory Management Macros */ + +//znew loves you! +#define znew new ZNEW_ARGS //Allocate with params +#define znew_notrack new (std::nothrow) //Allocate without tracking +#define znew_static new (znew_static_t()) //Allocate, but register for delete onexit +#define zdelete delete //Delete + +#define zalloc(_type, _size) ZAlloc::Alloc<_type>(_size) //Allocates an array (block of memory) using the ZAlloc allocation library +#define zfree(_data) ZAlloc::Free(_data) //Frees an array (block of memory) using the ZAlloc allocation library + +#define MemCopy(_type, _dest, _src, _count) memcpy(_dest, _src, _count * sizeof(_type)) +#define MemCopyFloat(_dest, _src, _count) memcpy(_dest, _src, _count * sizeof(float)) +#define MemCopyInt(_dest, _src, _count) memcpy(_dest, _src, _count * sizeof(int)) +#define MemCopyChar(_dest, _src, _count) memcpy(_dest, _src, _count * sizeof(char)) + +#define MemMove(_type, _dest, _src, _count) memmove(_dest, _src, _count * sizeof(_type)) +#define MemMoveFloat(_dest, _src, _count) memmove(_dest, _src, _count * sizeof(float)) +#define MemMoveInt(_dest, _src, _count) memmove(_dest, _src, _count * sizeof(int)) +#define MemMoveChar(_dest, _src, _count) memmove(_dest, _src, _count * sizeof(char)) + +#define MemSet(_type, _dest, _val, _count) memset(_dest, _val, _count * sizeof(_type)) +#define MemSetFloat(_dest, _val, _count) memset(_dest, _val, _count * sizeof(float)) +#define MemSetInt(_dest, _val, _count) memset(_dest, _val, _count * sizeof(int)) +#define MemSetChar(_dest, _val, _count) memset(_dest, _val, _count * sizeof(char)) + +class ZAlloc +{ +public: + /* + static public Alloc + Allocation function. Gives back an allocated array of at least _size in length. + + @param _size - the size of the block of type T + + @return (T*) - an array of T of at least _size in length + */ + template + static T* Alloc(size_t _size); + + /* + public static Free + + Free function. + + @param _data - an array allocated through the use of Alloc + + @return (void) + */ + template + static void Free(T *_data); +}; + +template +T* ZAlloc::Alloc(size_t _size) +{ + return new (std::nothrow) T[_size]; +} + +template +void ZAlloc::Free(T *_data) +{ + delete [] _data; +} + +#endif + diff --git a/Include/ZUtil/ZAllocWindow.hpp b/Include/ZUtil/ZAllocWindow.hpp new file mode 100644 index 0000000..8e720a2 --- /dev/null +++ b/Include/ZUtil/ZAllocWindow.hpp @@ -0,0 +1,205 @@ +/* + ZAllocWindow.hpp + Author: James Russell + Created: 3/7/2013 + + Purpose: + + Buffer used to maintain a sliding window of allocations in a buffer. Primary + use case is sliding packet windows, but could also be used for other forms + of data. + + Able to allocate raw memory blocks or perform in-place construction using + default constructors. Destructor calls can be omitted or performed. + + License: + + TODO + +*/ + +#pragma once + +#ifndef _ZALLOCWINDOW_HPP +#define _ZALLOCWINDOW_HPP + +#include // for placement new + +#include + +/* +Allocation window class. Operating on a contiguous array of backing memory, +this will allocate chunks of that memory, increasing the window until the +entire block would be used. + +When deallocations are performed, no memory is actually freed from the buffer +unless the earliest allocation is deallocated, which will shrink the window. + +As an example, consider the following: + + buffer.Allocate(A); + buffer.Allocate(B); + buffer.Allocate(C); + buffer.Allocate(D); + +A large enough buffer would return four pointers and would have the following +layout (a = allocated flag, d = deallocated flag, f = free memory): + + +-----------------------------------+ + | a | A | a | B | a | C | a | D | f | + +-----------------------------------+ + ^ ^ + buffer begin buffer end + + buffer.Deallocate(B); + + +-----------------------------------+ + | a | A | d | B | a | C | a | D | f | + +-----------------------------------+ + ^ ^ + buffer begin buffer end + + buffer.Deallocate(A); + + +-----------------------------------+ + | f | f | f | f | a | C | a | D | f | + +-----------------------------------+ + ^ ^ + buffer begin buffer end + +Notice that when B was deallocated, no space was actually made available +in the buffer until A was deallocated. If a further attempt had been made +to allocate data, it would have returned NULL, indicating that the allocation +window was full. The only way to free data at that point would have been to +deallocate the earliest allocation (A, in this case). + +The allocation window will automatically handle wrapping around when the end +of the buffer is reached. +*/ +class ZAllocWindow +{ +public: + // c'tor + ZAllocWindow(); + + // parameterized c'tor + ZAllocWindow(size_t _buffersize); + + // d'tor + ~ZAllocWindow(); + + /* + void* ZAllocWindow::Allocate + + Allocates a contiguous block of memory from the buffer. If this + would wrap around such that the previously allocated data (that has + not been deallocated) would be overwritten, then it returns NULL. + + An additional 8 bytes are used per allocation from the buffer for + allocation metadata. + + This will always return a word aligned pointer. + + The template version will default construct an object of type T. + + @param _size - number of bytes to allocate + @return (void*) - the allocated block of memory (NULL if not possible) + */ + void* Allocate(size_t _size); + template T* Allocate() + { T* obj = (T*)Allocate(sizeof(T)); return (obj != NULL ? new (obj) T() : NULL); } + + /* + void ZAllocWindow::Deallocate + + Deallocates a previously allocated block of memory from the binary buffer. Since + allocation is done in a sliding window, this only moves frees up memory if this + is the oldest currently allocated block of data. Any other data that is deallocated + will be marked as freed to be made available when the oldest allocated block is freed. + + The template version will call the destructor for the object. + + @param _data - the data to be deallocated + @param _obj - the object to deallocate (destructor is called) + @return (void) + */ + void Deallocate(void* _data); + template void Deallocate(T* _obj) + { _obj->~T(); Deallocate((void*)_obj); } + + /* + size_t ZAllocWindow::GetAllocCount + + Gets the current number of allocations out on this allocation window. + + @return (size_t) - the number of allocations + */ + size_t GetAllocCount() const + { return NumAllocs; } + + /* + void ZAllocWindow::Reset + + Completely resets the allocation window, completely invalidating all + existing allocations. + + @return (void) + */ + void Reset(); + + /* + bool ZAllocWindow::Resize + + Attempts to resize the buffer. This will fail if data is currently allocated in + the buffer. + + The template version will set the buffer to enough room for N objects of type T. + + @param _newsize - the new desired size of the buffer + @param _count - the number of objects of type T to resize the buffer for + @return (bool) - true if able to resize, false otherwise + */ + bool Resize(size_t _newsize); + template bool Resize(size_t _count) + { return Resize((sizeof(T) + 8) * _count); } + + /* + void ZAllocWindow::SetBuffer + + Sets the backing buffer for this binary buffer. This will fail if data is currently + allocated in the buffer. If NULL, will release ownership of any previous set buffer + and allocate a new one equal to the current size. + + Does not assume ownership of the buffer - will not delete it upon destruction of this + buffer. + + @param _buffer - the buffer to use as backing + @param _buffersize - the size of the buffer being set + @return (bool) - true if able to use, false otherwise + */ + bool SetBuffer(void* _buffer, size_t _buffersize); + + /* + size_t ZAllocWindow::Size + + Returns the current size of the buffer. + + @return (size_t) - size (in bytes) of the buffer + */ + size_t Size() const + { return BufferSize; } + +private: + DISABLE_COPY_AND_ASSIGN(ZAllocWindow); + + void* Buffer; // The allocated buffer + void* Begin; // The (moving) front pointer of the buffer + void* End; // The (moving) back pointer of the buffer + + size_t BufferSize; // The current allocated size of the buffer + bool bOwnsBuffer; // Flag indicating we own the buffer (and should free when done) + size_t NumAllocs; // The number of allocations we've done +}; + +#endif + \ No newline at end of file diff --git a/Include/ZUtil/ZAssert.hpp b/Include/ZUtil/ZAssert.hpp new file mode 100644 index 0000000..c8bf075 --- /dev/null +++ b/Include/ZUtil/ZAssert.hpp @@ -0,0 +1,53 @@ +/* + ZAssert.hpp + Author : Chris Ertel + + Purpose : Asserts for debugging and error checking purposes. + + Changelog + 8/16/2010 - creation (crertel) + 12/4/2011 - Updated to use libsst-os asserts (jcrussell) +*/ + +#pragma once + +#ifndef _ZASSERT_H +#define _ZASSERT_H + +#include + +/*****************/ +/* Assert Macros */ +/*****************/ + +//ZASSERT_RUNTIME macro, which will raise an error with debug output if the condition is not true after logging the message +#define ZASSERT_RUNTIME(_condition, _message) SST_OS_RuntimeAssert(_condition, _message) + +//ZASSERT_RUNTIME_FAIL macro, which will raise an error with debug output +#define ZASSERT_RUNTIME_FAIL(_message) SST_OS_RuntimeError(_message) + +#if ZASSERT_ENABLE + + //ZASSERT macro, which will trigger a breakpoint if the condition is not met + #define ZASSERT(_condition, _message) SST_OS_DebugAssert(_condition, _message) + + //ZASSERT_FAIL macro, which triggers a breakpoint + #define ZASSERT_FAIL(_message) SST_OS_DebugError(_message) + +#else /* ZASSERT is disabled */ + #define ZASSERT(_condition, _message) + #define ZASSERT_FAIL(_message) +#endif //ZASSERT_ENABLE + +#if ZASSERT_UTIL_ENABLE + + //ZASSERT_UTIL macro, which will trigger a breakpoint if the condition is not met + //ZASSERT_UTIL is meant to be used within the ZUtil project for internal assertion debugging + //ZASSERT should be used when the error condition can be caused by user actions + #define ZASSERT_UTIL(_condition, _message) SST_OS_DebugAssert(_condition, _message) + +#else /* ZASSERT_UTIL is disabled */ + #define ZASSERT_UTIL(_condition, _message) ((void)0) +#endif //ZASSERT_UTIL_ENABLE + +#endif diff --git a/Include/ZUtil/ZBinaryBufferReader.hpp b/Include/ZUtil/ZBinaryBufferReader.hpp new file mode 100644 index 0000000..05ac37e --- /dev/null +++ b/Include/ZUtil/ZBinaryBufferReader.hpp @@ -0,0 +1,87 @@ +/* + ZBinaryBufferReader.hpp + Author: Chris Ertel , Patrick Baggett + Created: 3/6/2013 + + Purpose: + + Reads a binary stream from memory. + + License: + + TODO + +*/ + +#pragma once + +#ifndef _ZBINARYBUFFERREADER_HPP +#define _ZBINARYBUFFERREADER_HPP + +#include +#include + +#include + +class ZBinaryBufferReader : public ZBinaryReader +{ + private: + const char* Data; + size_t Size; + size_t Offset; + + //This is typed to char* so pointer arithmetic can occur + const char* GetPosition() const { return &Data[Offset]; } + public: + ZBinaryBufferReader(const void* _data, size_t _size, SST_ByteOrder bo) + : ZBinaryReader(bo), Data( (const char*) _data), Size(_size), Offset(0) + { + + } + + //Subclass implementation + uint8_t ReadU8(); + + //Subclass implementation + uint16_t ReadU16(); + + //Subclass implementation + uint32_t ReadU32(); + + //Subclass implementation + uint64_t ReadU64(); + + //Subclass implementation + void ReadU8Array(uint8_t* ptr, size_t count); + + //Subclass implementation + void ReadU16Array(uint16_t* ptr, size_t count); + + //Subclass implementation + void ReadU32Array(uint32_t* ptr, size_t count); + + //Subclass implementation + void ReadU64Array(uint64_t* ptr, size_t count); + + //Subclass implementation + size_t GetLength() const { return Size; } + + //Subclass implementation + size_t GetOffset() const { return Offset; } + + //Subclass implementation + void SeekTo(size_t offset) { Offset = offset; } + + //New to ZBinaryBufferReader. Returns the current address that would be read by the next ReadXxx() call. + //Since 'const void*' is the constructor type, this returns 'const void*' as well. See [private] GetPosition(). + const void* GetBufferReadAddress() const { return (const void*)GetPosition(); } + + //New to ZBinaryBufferReader. Returns the original buffer address + const void* GetBufferBaseAddress() const { return (const void*)Data; } + + //New to ZBinaryBufferReader. Reads a pointer + void* ReadPointer(); +}; + +#endif + diff --git a/Include/ZUtil/ZBinaryBufferWriter.hpp b/Include/ZUtil/ZBinaryBufferWriter.hpp new file mode 100644 index 0000000..1a7ce22 --- /dev/null +++ b/Include/ZUtil/ZBinaryBufferWriter.hpp @@ -0,0 +1,78 @@ +/* + ZBinaryBufferWriter.hpp + Author: Patrick Baggett + Created: 6/05/2013 + + Purpose: + + Writes a binary stream to memory + + License: + + TODO + +*/ + +#pragma once + +#ifndef _ZBINARYBUFFERWRITER_HPP +#define _ZBINARYBUFFERWRITER_HPP + +#include + +class ZBinaryBufferWriter : public ZBinaryWriter +{ + public: + ZBinaryBufferWriter(void* data, size_t _size, SST_ByteOrder bo) : + ZBinaryWriter(bo), Data((uint8_t*)data), Size(_size), Offset(0) + { + + } + + //Subclass implementation + void WriteU8(uint8_t v); + + //Subclass implementation + void WriteU16(uint16_t v); + + //Subclass implementation + void WriteU32(uint32_t v); + + //Subclass implementation + void WriteU64(uint64_t v); + + //Subclass implementation + void WriteU8Array(const uint8_t* v, size_t count); + + //Subclass implementation + void WriteU16Array(const uint16_t* v, size_t count); + + //Subclass implementation + void WriteU32Array(const uint32_t* v, size_t count); + + //Subclass implementation + void WriteU64Array(const uint64_t* v, size_t count); + + //Subclass implementation + size_t GetOffset() const { return Offset; } + + //Subclass implementation + void SeekTo(size_t offset) { Offset = offset; } + + //Specific to ZBinaryBufferWriter, returns next write address + const void* GetBufferWriteAddress() const { return &Data[Offset]; } + + //Specific to ZBinaryBufferWriter, returns base address + void* GetBufferBaseAddress() const { return Data; } + + //Specific to ZBinaryBufferWriter, writes a pointer + void WritePointer(void* pointer); + + private: + uint8_t* Data; + size_t Size; //TODO: no safe ops ? + size_t Offset; +}; + +#endif + diff --git a/Include/ZUtil/ZBinaryFileReader.hpp b/Include/ZUtil/ZBinaryFileReader.hpp new file mode 100644 index 0000000..3a6ffb0 --- /dev/null +++ b/Include/ZUtil/ZBinaryFileReader.hpp @@ -0,0 +1,72 @@ +/* + ZBinaryFileReader.hpp + Author: Patrick Baggett + Created: 3/6/2013 + + Purpose: + + Reads a binary stream from a SST_File handle. NOTE: On 32-bit platforms, only files up to 4GB are supported. + + License: + + TODO + +*/ + +#pragma once + +#ifndef _ZBINARYFILEREADER_HPP +#define _ZBINARYFILEREADER_HPP + +#include +#include + +class ZBinaryFileReader : public ZBinaryReader +{ + private: + SST_File fp; + size_t Size; + size_t Offset; + + public: + ZBinaryFileReader(SST_File handle, SST_ByteOrder bo); + + //Subclass implementation + uint8_t ReadU8(); + + //Subclass implementation + uint16_t ReadU16(); + + //Subclass implementation + uint32_t ReadU32(); + + //Subclass implementation + uint64_t ReadU64(); + + //Subclass implementation + void ReadU8Array(uint8_t* ptr, size_t count); + + //Subclass implementation + void ReadU16Array(uint16_t* ptr, size_t count); + + //Subclass implementation + void ReadU32Array(uint32_t* ptr, size_t count); + + //Subclass implementation + void ReadU64Array(uint64_t* ptr, size_t count); + + //Subclass implementation + size_t GetLength() const { return Size; } + + //Subclass implementation + size_t GetOffset() const { return Offset; } + + //Subclass implementation + void SeekTo(size_t offset); + + //Unique to ZBinaryFileReader + SST_File GetFileHandle() { return fp; } +}; + +#endif + diff --git a/Include/ZUtil/ZBinaryFileWriter.hpp b/Include/ZUtil/ZBinaryFileWriter.hpp new file mode 100644 index 0000000..8bc0cbd --- /dev/null +++ b/Include/ZUtil/ZBinaryFileWriter.hpp @@ -0,0 +1,68 @@ +/* + ZBinaryFileWriter.hpp + Author: Chris Ertel , Patrick Baggett + Created: 3/11/2013 + + Purpose: + + Writes a binary stream from a SST_File handle. NOTE: On 32-bit platforms, only files up to 4GB are supported. + + License: + + TODO + +*/ + +#pragma once + +#ifndef _ZBINARYFILEWRITER_HPP +#define _ZBINARYFILEWRITER_HPP + +#include +#include + +class ZBinaryFileWriter : public ZBinaryWriter +{ + public: + ZBinaryFileWriter(SST_File handle, SST_ByteOrder bo); + + //Subclass implementation + void WriteU8(uint8_t v); + + //Subclass implementation + void WriteU16(uint16_t v); + + //Subclass implementation + void WriteU32(uint32_t v); + + //Subclass implementation + void WriteU64(uint64_t v); + + //Subclass implementation + void WriteU8Array(const uint8_t* v, size_t count); + + //Subclass implementation + void WriteU16Array(const uint16_t* v, size_t count); + + //Subclass implementation + void WriteU32Array(const uint32_t* v, size_t count); + + //Subclass implementation + void WriteU64Array(const uint64_t* v, size_t count); + + //Subclass implementation + size_t GetOffset() const { return Offset; } + + //Subclass implementation + void SeekTo(size_t offset); + + //Unique to ZBinaryFileWriter + SST_File GetFileHandle() { return fp; } + + private: + SST_File fp; + size_t Offset; +}; + +#endif + diff --git a/Include/ZUtil/ZBinaryReader.hpp b/Include/ZUtil/ZBinaryReader.hpp new file mode 100644 index 0000000..6187bb4 --- /dev/null +++ b/Include/ZUtil/ZBinaryReader.hpp @@ -0,0 +1,749 @@ +/* + ZBinaryReader.hpp + Author: Patrick Baggett +#include + +class ZBinaryReader +{ + public: + ZBinaryReader(SST_ByteOrder streamOrder) : + streamByteOrder(streamOrder) + { + + } + + //SINGLE ELEMENT READ + /* + virtual public ZBinaryReader::ReadU8 + + Reads a single unsigned 8-bit value from the stream. + No validation is performed. + + @return (uint8_t) - value read from the stream + */ + virtual uint8_t ReadU8() = 0; + + /* + virtual public ZBinaryReader::ReadU16 + + Reads a single unsigned 16-bit value from the stream. + No validation is performed. + + @return (uint16_t) - value read from the stream + */ + virtual uint16_t ReadU16() = 0; + + /* + virtual public ZBinaryReader::ReadU32 + + Reads a single unsigned 32-bit value from the stream. + No validation is performed. + + @return (uint32_t) - value read from the stream + */ + virtual uint32_t ReadU32() = 0; + + /* + virtual public ZBinaryReader::ReadU64 + + Reads a single unsigned 64-bit value from the stream. + No validation is performed. + + @return (uint64_t) - value read from the stream + */ + virtual uint64_t ReadU64() = 0; + + /* + public ZBinaryReader::ReadF32 + + Reads a single 32-bit floating point value from the stream. + No validation is performed. + + @return (float) - value read from the stream + */ + float ReadF32() { return cast_i2f(ReadU32()); } + + /* + public ZBinaryReader::ReadF64 + + Reads a single 64-bit floating point value from the stream. + No validation is performed. + + @return (double) - value read from the stream + */ + double ReadF64() { return cast_i2d(ReadU64()); } + + + //===================================================================== + //ARRAY READ + //===================================================================== + + /* + virtual public ZBinaryReader::ReadU8Array + + Reads an array of 8-bit unsigned values from the stream. + No validation is performed. + + @param ptr - The base of the array + @param count - Number of elements to read + @return (void) + */ + virtual void ReadU8Array(uint8_t* ptr, size_t count) = 0; + + /* + virtual public ZBinaryReader::ReadU16Array + + Reads an array of 16-bit unsigned values from the stream. + No validation is performed. + + @param ptr - The base of the array + @param count - Number of elements to read + @return (void) + */ + virtual void ReadU16Array(uint16_t* ptr, size_t count) = 0; + + /* + virtual public ZBinaryReader::ReadU32Array + + Reads an array of 32-bit unsigned values from the stream. + No validation is performed. + + @param ptr - The base of the array + @param count - Number of elements to read + @return (void) + */ + virtual void ReadU32Array(uint32_t* ptr, size_t count) = 0; + + /* + virtual public ZBinaryReader::ReadU64Array + + Reads an array of 64-bit unsigned values from the stream. + No validation is performed. + + @param ptr - The base of the array + @param count - Number of elements to read + @return (void) + */ + virtual void ReadU64Array(uint64_t* ptr, size_t count) = 0; + + /* + public ZBinaryReader::ReadF32Array + + Reads an array of 32-bit floating point values from the stream. + No validation is performed. + + @param ptr - The base of the array + @param count - Number of elements to read + @return (void) + */ + void ReadF32Array(float* ptr, size_t count) { ReadU32Array((uint32_t*)ptr, count); } + + /* + public ZBinaryReader::ReadF64Array + + Reads an array of 64-bit floating point values from the stream. + No validation is performed. + + @param ptr - The base of the array + @param count - Number of elements to read + @return (void) + */ + void ReadF64Array(double* ptr, size_t count) { ReadU64Array((uint64_t*)ptr, count); } + + //===================================================================== + //STREAM SEEKING / POSITIONING + //===================================================================== + + /* + virtual public ZBinaryReader::GetLength + + Gets the total length of the stream in bytes. + + @return (size_t) - The total length of the stream + */ + virtual size_t GetLength() const = 0; + + /* + virtual public ZBinaryReader::GetOffset + + Gets the current (zero-based) offset into the stream from which the next read will + be performed. + + @return (size_t) - The offset. + */ + virtual size_t GetOffset() const = 0; + + /* + public ZBinaryReader::SeekForward + + Advances the offset into the stream by the given number of bytes. + No validation is performed. + + @param amount - The amount of seek forward by. + @return (void) + */ + void SeekForward(size_t amount) { SeekTo(GetOffset() + amount); } + + /* + public ZBinaryReader::SeekBackward + + Rewinds the offset into the stream by the given number of bytes. + No validation is performed. + + @param amount - The amount of seek backward by. + @return (void) + */ + void SeekBackward(size_t amount) { SeekTo(GetOffset() - amount); } + + /* + virtual public ZBinaryReader::SeekTo + + Directly sets the offset into the stream from which reads will occur. + No validation is performed. + + @param offset - The new offset + @return (void) + */ + virtual void SeekTo(size_t offset) = 0; + + /* + public ZBinaryReader::Rewind + + Sets the offset to the start of the stream + + @param offset - The new offset + @return (void) + */ + void Rewind() { SeekTo(0); } + + /* + public ZBinaryReader::CanRead + + Checks if the given number of bytes can be read + + @param bytes - The number of bytes that wish to be read + @return (void) + */ + bool CanRead(size_t bytes) const { return (GetLength() - GetOffset() >= bytes); } + + //===================================================================== + //SAFE SEEK FUNCTIONS + //===================================================================== + /* + public ZBinaryReader::SafeSeekForward + + Attempts to advance the offset into the stream by the given number of bytes. If + this would produce an out-of-bounds result, then false is returned and the offset + is not adjusted, otherwise, the offset is adjusted and true is returned. + + @param amount - The amount to seek forward by + @return (bool) - True if the seek operation succeeded, false if the value was invalid + */ + bool SafeSeekForward(size_t amount) + { + bool ok = (GetLength() - GetOffset() > amount); //i.e. length > offset + amount + if(ok) + SeekTo(GetOffset() + amount); + return ok; + } + + /* + public ZBinaryReader::SafeSeekBackward + + Attempts to rewind the offset into the stream by the given number of bytes. If + this would produce an out-of-bounds result, then false is returned and the offset + is not adjusted, otherwise, the offset is adjusted and true is returned. + + @param amount - The amount to seek backward by + @return (bool) - True if the seek operation succeeded, false if the value was invalid + */ + bool SafeSeekBackward(size_t amount) + { + bool ok = (GetOffset() >= amount); //i.e. offset - amount >= 0 + if(ok) + SeekTo(GetOffset() - amount); + return ok; + } + + /* + public ZBinaryReader::SafeSeekTo + + Attempts to set the offset into the stream directly. If the new offset is + out-of-bounds, then false is returned and the offset is not adjusted, + otherwise, the offset is adjusted and true is returned. + + @return (bool) - True if the seek operation succeeded, false if the value was invalid + */ + bool SafeSeekTo(size_t offset) + { + bool ok = (offset < GetLength()); + if(ok) SeekTo(offset); + return ok; + } + + //===================================================================== + //SAFE READ FUNCTIONS + //===================================================================== + /* + public ZBinaryReader::SafeReadU8 + + Attempt to reads a single unsigned 8-bit value from the stream. If this would + result in reading out of bounds, false is returned and *ptr is unmodified, otherwise + the value is read and stored at *ptr and true is returned. + No validation is performed. + + @param ptr - The address to store the read value at + @return (bool) - If the value was successfully read + */ + bool SafeReadU8(uint8_t* ptr) + { + bool ok = CanRead(sizeof(uint8_t)); + if(ok) *ptr = ReadU8(); + return ok; + } + + /* + public ZBinaryReader::SafeReadU16 + + Attempt to reads a single unsigned 16-bit value from the stream. If this would + result in reading out of bounds, false is returned and *ptr is unmodified, otherwise + the value is read and stored at *ptr and true is returned. + No validation is performed. + + @param ptr - The address to store the read value at + @return (bool) - If the value was successfully read + */ + bool SafeReadU16(uint16_t* ptr) + { + bool ok = CanRead(sizeof(uint16_t)); + if(ok) *ptr = ReadU16(); + return ok; + } + + /* + public ZBinaryReader::SafeReadU32 + + Attempt to reads a single unsigned 32-bit value from the stream. If this would + result in reading out of bounds, false is returned and *ptr is unmodified, otherwise + the value is read and stored at *ptr and true is returned. + No validation is performed. + + @param ptr - The address to store the read value at + @return (bool) - If the value was successfully read + */ + bool SafeReadU32(uint32_t* ptr) + { + bool ok = CanRead(sizeof(uint32_t)); + if(ok) *ptr = ReadU32(); + return ok; + } + + /* + public ZBinaryReader::SafeReadU64 + + Attempt to reads a single unsigned 64-bit value from the stream. If this would + result in reading out of bounds, false is returned and *ptr is unmodified, otherwise + the value is read and stored at *ptr and true is returned. + No validation is performed. + + @param ptr - The address to store the read value at + @return (bool) - If the value was successfully read + */ + bool SafeReadU64(uint64_t* ptr) + { + bool ok = CanRead(sizeof(uint64_t)); + if(ok) *ptr = ReadU64(); + return ok; + } + + /* + public ZBinaryReader::SafeReadF32 + + Attempt to reads a single 32-bit floating point value from the stream. If this would + result in reading out of bounds, false is returned and *ptr is unmodified, otherwise + the value is read and stored at *ptr and true is returned. + No validation is performed. + + @param ptr - The address to store the read value at + @return (bool) - If the value was successfully read + */ + bool SafeReadF32(float* ptr) + { + bool ok = CanRead(sizeof(float)); + if(ok) *ptr = ReadF32(); + return ok; + } + + /* + public ZBinaryReader::SafeReadF64 + + Attempt to reads a single 64-bit floating point value from the stream. If this would + result in reading out of bounds, false is returned and *ptr is unmodified, otherwise + the value is read and stored at *ptr and true is returned. + No validation is performed. + + @param ptr - The address to store the read value at + @return (bool) - If the value was successfully read + */ + bool SafeReadF64(double* ptr) + { + bool ok = CanRead(sizeof(double)); + if(ok) *ptr = ReadF64(); + return ok; + } + + /* + public ZBinaryReader::SafeReadU8Array + + Attempt to reads an array of unsigned 8-bit values from the stream. If this would + result in reading out of bounds, false is returned and *ptr is unmodified, otherwise + the values are read and stored at *ptr and true is returned. + No validation is performed. + + @param ptr - The address to store the values + @param count - The number of values to read + @return (bool) - If the array was successfully read + */ + bool SafeReadU8Array(uint8_t* ptr, size_t count) + { + bool ok = CanRead(count); + if(ok) ReadU8Array(ptr, count); + return ok; + } + + /* + public ZBinaryReader::SafeReadU16Array + + Attempt to reads an array of unsigned 16-bit values from the stream. If this would + result in reading out of bounds, false is returned and *ptr is unmodified, otherwise + the values are read and stored at *ptr and true is returned. + No validation is performed. + + @param ptr - The address to store the values + @param count - The number of values to read + @return (bool) - If the array was successfully read + */ + bool SafeReadU16Array(uint16_t* ptr, size_t count) + { + bool ok = (SIZE_MAX / count > sizeof(uint16_t)); //i.e. SIZE_MAX > count * size + ok = ok && CanRead(count * sizeof(uint16_t)); + if(ok) ReadU16Array(ptr, count); + return ok; + } + + /* + public ZBinaryReader::SafeReadU32Array + + Attempt to reads an array of unsigned 32-bit values from the stream. If this would + result in reading out of bounds, false is returned and *ptr is unmodified, otherwise + the values are read and stored at *ptr and true is returned. + No validation is performed. + + @param ptr - The address to store the values + @param count - The number of values to read + @return (bool) - If the array was successfully read + */ + bool SafeReadU32Array(uint32_t* ptr, size_t count) + { + bool ok = (SIZE_MAX / count > sizeof(uint32_t)); //i.e. SIZE_MAX > count * size + ok = ok && CanRead(count * sizeof(uint32_t)); + if(ok) ReadU32Array(ptr, count); + return ok; + } + + /* + public ZBinaryReader::SafeReadU64Array + + Attempt to reads an array of unsigned 64-bit values from the stream. If this would + result in reading out of bounds, false is returned and *ptr is unmodified, otherwise + the values are read and stored at *ptr and true is returned. + No validation is performed. + + @param ptr - The address to store the values + @param count - The number of values to read + @return (bool) - If the array was successfully read + */ + bool SafeReadU64Array(uint64_t* ptr, size_t count) + { + bool ok = (SIZE_MAX / count > sizeof(uint64_t)); //i.e. SIZE_MAX > count * size + ok = ok && CanRead(count * sizeof(uint64_t)); + if(ok) ReadU64Array(ptr, count); + return ok; + } + + /* + public ZBinaryReader::SafeReadF32Array + + Attempt to reads an array of 32-bit floating point values from the stream. If this would + result in reading out of bounds, false is returned and *ptr is unmodified, otherwise + the values are read and stored at *ptr and true is returned. + No validation is performed. + + @param ptr - The address to store the values + @param count - The number of values to read + @return (bool) - If the array was successfully read + */ + bool SafeReadF32Array(float* ptr, size_t count) { return SafeReadU32Array((uint32_t*)ptr, count); } + + /* + public ZBinaryReader::SafeReadF64Array + + Attempt to reads an array of 64-bit floating point values from the stream. If this would + result in reading out of bounds, false is returned and *ptr is unmodified, otherwise + the values are read and stored at *ptr and true is returned. + No validation is performed. + + @param ptr - The address to store the values + @param count - The number of values to read + @return (bool) - If the array was successfully read + */ + bool SafeReadF64Array(double* ptr, size_t count) { return SafeReadU64Array((uint64_t*)ptr, count); } + + //===================================================================== + //TYPED ALIASES + //===================================================================== + /* + public ZBinaryReader::ReadI8 + + Reads a single signed 8-bit value from the stream. + No validation is performed. + + @return (int8_t) - value read from the stream + */ + int8_t ReadI8() { return (int8_t)ReadU8(); } + + /* + public ZBinaryReader::ReadI16 + + Reads a single signed 16-bit value from the stream. + No validation is performed. + + @return (int16_t) - value read from the stream + */ + int16_t ReadI16() { return (int16_t)ReadU16(); } + + /* + public ZBinaryReader::ReadI32 + + Reads a single signed 32-bit value from the stream. + No validation is performed. + + @return (int32_t) - value read from the stream + */ + int32_t ReadI32() { return (int32_t)ReadU32(); } + + /* + public ZBinaryReader::ReadI64 + + Reads a single signed 64-bit value from the stream. + No validation is performed. + + @return (int64_t) - value read from the stream + */ + int64_t ReadI64() { return (int64_t)ReadU64(); } + + /* + public ZBinaryReader::ReadI8Array + + Reads an array of 8-bit signed values from the stream. + No validation is performed. + + @param ptr - The base of the array + @param count - Number of elements to read + @return (void) + */ + void ReadI8Array(int8_t* ptr, size_t count) { return ReadU8Array((uint8_t*)ptr, count); } + + /* + public ZBinaryReader::ReadI16Array + + Reads an array of 16-bit signed values from the stream. + No validation is performed. + + @param ptr - The base of the array + @param count - Number of elements to read + @return (void) + */ + void ReadI16Array(int16_t* ptr, size_t count) { return ReadU16Array((uint16_t*)ptr, count); } + + /* + public ZBinaryReader::ReadI32Array + + Reads an array of 32-bit signed values from the stream. + No validation is performed. + + @param ptr - The base of the array + @param count - Number of elements to read + @return (void) + */ + void ReadI32Array(int32_t* ptr, size_t count) { return ReadU32Array((uint32_t*)ptr, count); } + + /* + public ZBinaryReader::ReadI64Array + + Reads an array of 64-bit signed values from the stream. + No validation is performed. + + @param ptr - The base of the array + @param count - Number of elements to read + @return (void) + */ + void ReadI64Array(int64_t* ptr, size_t count) { return ReadU64Array((uint64_t*)ptr, count); } + + /* + public ZBinaryReader::SafeReadI8 + + Attempt to reads a single signed 8-bit value from the stream. If this would + result in reading out of bounds, false is returned and *ptr is unmodified, otherwise + the value is read and stored at *ptr and true is returned. + No validation is performed. + + @param ptr - The address to store the read value at + @return (bool) - If the value was successfully read + */ + bool SafeReadI8(int8_t* ptr) { return SafeReadU8((uint8_t*)ptr); } + + /* + public ZBinaryReader::SafeReadI16 + + Attempt to reads a single signed 16-bit value from the stream. If this would + result in reading out of bounds, false is returned and *ptr is unmodified, otherwise + the value is read and stored at *ptr and true is returned. + No validation is performed. + + @param ptr - The address to store the read value at + @return (bool) - If the value was successfully read + */ + bool SafeReadI16(int16_t* ptr) { return SafeReadU16((uint16_t*)ptr); } + + /* + public ZBinaryReader::SafeReadI32 + + Attempt to reads a single signed 32-bit value from the stream. If this would + result in reading out of bounds, false is returned and *ptr is unmodified, otherwise + the value is read and stored at *ptr and true is returned. + No validation is performed. + + @param ptr - The address to store the read value at + @return (bool) - If the value was successfully read + */ + bool SafeReadI32(int32_t* ptr) { return SafeReadU32((uint32_t*)ptr); } + + /* + public ZBinaryReader::SafeReadI64 + + Attempt to reads a single signed 64-bit value from the stream. If this would + result in reading out of bounds, false is returned and *ptr is unmodified, otherwise + the value is read and stored at *ptr and true is returned. + No validation is performed. + + @param ptr - The address to store the read value at + @return (bool) - If the value was successfully read + */ + bool SafeReadI64(int64_t* ptr) { return SafeReadU64((uint64_t*)ptr); } + + /* + public ZBinaryReader::SafeReadI8Array + + Attempt to reads an array of signed 8-bit values from the stream. If this would + result in reading out of bounds, false is returned and *ptr is unmodified, otherwise + the values are read and stored at *ptr and true is returned. + No validation is performed. + + @param ptr - The address to store the values + @param count - The number of values to read + @return (bool) - If the array was successfully read + */ + bool SafeReadI8Array(int8_t* ptr, size_t count) { return SafeReadU8Array((uint8_t*)ptr, count); } + + /* + public ZBinaryReader::SafeReadI16Array + + Attempt to reads an array of signed 16-bit values from the stream. If this would + result in reading out of bounds, false is returned and *ptr is unmodified, otherwise + the values are read and stored at *ptr and true is returned. + No validation is performed. + + @param ptr - The address to store the values + @param count - The number of values to read + @return (bool) - If the array was successfully read + */ + bool SafeReadI16Array(int16_t* ptr, size_t count) { return SafeReadU16Array((uint16_t*)ptr, count); } + + /* + public ZBinaryReader::SafeReadI32Array + + Attempt to reads an array of signed 32-bit values from the stream. If this would + result in reading out of bounds, false is returned and *ptr is unmodified, otherwise + the values are read and stored at *ptr and true is returned. + No validation is performed. + + @param ptr - The address to store the values + @param count - The number of values to read + @return (bool) - If the array was successfully read + */ + bool SafeReadI32Array(int32_t* ptr, size_t count) { return SafeReadU32Array((uint32_t*)ptr, count); } + + /* + public ZBinaryReader::SafeReadI64Array + + Attempt to reads an array of signed 64-bit values from the stream. If this would + result in reading out of bounds, false is returned and *ptr is unmodified, otherwise + the values are read and stored at *ptr and true is returned. + No validation is performed. + + @param ptr - The address to store the values + @param count - The number of values to read + @return (bool) - If the array was successfully read + */ + bool SafeReadI64Array(int64_t* ptr, size_t count) { return SafeReadU64Array((uint64_t*)ptr, count); } + + + //===================================================================== + //GETTERS / SETTERS + //===================================================================== + /* + public ZBinaryReader::GetStreamByteOrder + + Gets the byte order in which the stream (source data) is read as. + + @return (SST_ByteOrder) - The byte order + */ + SST_ByteOrder GetStreamByteOrder() const { return streamByteOrder; } + + /* + public ZBinaryReader::SetStreamByteOrder + + Sets the byte order in which the stream (source data) is read as. + + @param newOrder - The new byte order + @return (void) + */ + void SetStreamByteOrder(SST_ByteOrder newOrder) { streamByteOrder = newOrder; } + + private: + SST_ByteOrder streamByteOrder; //The current byte order the stream is being read in. + +}; + +#endif + diff --git a/Include/ZUtil/ZBinaryWriter.hpp b/Include/ZUtil/ZBinaryWriter.hpp new file mode 100644 index 0000000..dd7f29e --- /dev/null +++ b/Include/ZUtil/ZBinaryWriter.hpp @@ -0,0 +1,279 @@ +/* + ZBinaryWriter.hpp + Author: Patrick Baggett + Created: 3/11/2013 + + Purpose: + + Binary stream writer interface + + License: + + TODO + +*/ + +#pragma once + +#ifndef _ZBINARYWRITER_HPP +#define _ZBINARYWRITER_HPP + +#include +#include + +class ZBinaryWriter +{ + + public: + ZBinaryWriter(SST_ByteOrder streamOrder) : + streamByteOrder(streamOrder) + { + } + + //===================================================================== + //SINGLE ELEMENT WRITE + //===================================================================== + virtual void WriteU8(uint8_t v) = 0; + virtual void WriteU16(uint16_t v) = 0; + virtual void WriteU32(uint32_t v) = 0; + virtual void WriteU64(uint64_t v) = 0; + void WriteF32(float v) { WriteU32(cast_f2i(v)); } + void WriteF64(double v) { WriteU64(cast_d2i(v)); } + + //===================================================================== + //ARRAY WRITE + //===================================================================== + /* + virtual public ZBinaryWriter::WriteU8Array + + Writes an array of 8-bit unsigned values to the stream. + + @param v - The base of the array + @param count - Number of elements to write + @return (void) + */ + virtual void WriteU8Array(const uint8_t* v, size_t count) = 0; + + /* + virtual public ZBinaryWriter::WriteU16Array + + Writes an array of 16-bit unsigned values to the stream. + + @param v - The base of the array + @param count - Number of elements to write + @return (void) + */ + virtual void WriteU16Array(const uint16_t* v, size_t count) = 0; + + /* + virtual public ZBinaryWriter::WriteU32Array + + Writes an array of 32-bit unsigned values to the stream. + + @param v - The base of the array + @param count - Number of elements to write + @return (void) + */ + virtual void WriteU32Array(const uint32_t* v, size_t count) = 0; + + /* + virtual public ZBinaryWriter::WriteU64Array + + Writes an array of 64-bit unsigned values to the stream. + + @param v - The base of the array + @param count - Number of elements to write + @return (void) + */ + virtual void WriteU64Array(const uint64_t* v, size_t count) = 0; + + /* + public ZBinaryWriter::WriteF32Array + + Writes an array of 32-bit floating point values to the stream. + + @param v - The base of the array + @param count - Number of elements to write + @return (void) + */ + void WriteF32Array(const float* v, size_t count) { WriteU32Array((uint32_t*)v, count); } + + /* + public ZBinaryWriter::WriteF64Array + + Writes an array of 64-bit floating point values to the stream. + + @param v - The base of the array + @param count - Number of elements to write + @return (void) + */ + void WriteF64Array(const double* v, size_t count) { WriteU64Array((uint64_t*)v, count); } + + //===================================================================== + //STREAM SEEKING / POSITIONING + //===================================================================== + /* + virtual public ZBinaryReader::GetOffset + + Gets the current (zero-based) offset into the stream from which the next read will + be performed. + + @return (size_t) - The offset. + */ + virtual size_t GetOffset() const = 0; + + /* + public ZBinaryReader::SeekForward + + Advances the offset into the stream by the given number of bytes. + No validation is performed. + + @param amount - The amount of seek forward by. + @return (void) + */ + void SeekForward(size_t amount) { SeekTo(GetOffset() + amount); } + + /* + public ZBinaryReader::SeekBackward + + Rewinds the offset into the stream by the given number of bytes. + No validation is performed. + + @param amount - The amount of seek backward by. + @return (void) + */ + void SeekBackward(size_t amount) { SeekTo(GetOffset() - amount); } + + /* + virtual public ZBinaryReader::SeekTo + + Directly sets the offset into the stream from which reads will occur. + No validation is performed. + + @param offset - The new offset + @return (void) + */ + virtual void SeekTo(size_t offset) = 0; + + /* + public ZBinaryReader::Rewind + + Sets the offset to the start of the stream + + @param offset - The new offset + @return (void) + */ + void Rewind() { SeekTo(0); } + + //===================================================================== + //TYPED ALIASES + //===================================================================== + /* + public ZBinaryWriter::WriteI8 + + Writes a single signed 8-bit value to the stream. + + @param v - value read to write to the stream + */ + void WriteI8(int8_t v) { return WriteU8((uint8_t)v); } + + /* + public ZBinaryWriter::WriteI16 + + Writes a single signed 16-bit value to the stream. + + @param v - value read to write to the stream + */ + void WriteI16(int16_t v) { return WriteU16((uint16_t)v); } + + /* + public ZBinaryWriter::WriteI32 + + Writes a single signed 32-bit value to the stream. + + @param v - value read to write to the stream + */ + void WriteI32(int32_t v) { return WriteU32((uint32_t)v); } + + /* + public ZBinaryWriter::WriteI64 + + Writes a single signed 64-bit value to the stream. + + @param v - value read to write to the stream + */ + void WriteI64(int64_t v) { return WriteU64((uint64_t)v); } + + /* + public ZBinaryWriter::WriteI8Array + + Writes an array of 8-bit signed values to the stream. + + @param v - The base of the array + @param count - Number of elements to write + @return (void) + */ + void WriteI8Array(const int8_t* v, size_t count) { return WriteU8Array((const uint8_t*)v, count); } + + /* + public ZBinaryWriter::WriteI16Array + + Writes an array of 16-bit signed values to the stream. + + @param v - The base of the array + @param count - Number of elements to write + @return (void) + */ + void WriteI16Array(const int16_t* v, size_t count) { return WriteU16Array((const uint16_t*)v, count); } + + /* + public ZBinaryWriter::WriteI32Array + + Writes an array of 32-bit signed values to the stream. + + @param v - The base of the array + @param count - Number of elements to write + @return (void) + */ + void WriteI32Array(const int32_t* v, size_t count) { return WriteU32Array((const uint32_t*)v, count); } + + /* + public ZBinaryWriter::WriteI64Array + + Writes an array of 64-bit signed values to the stream. + + @param v - The base of the array + @param count - Number of elements to write + @return (void) + */ + void WriteI64Array(const int64_t* v, size_t count) { return WriteU64Array((const uint64_t*)v, count); } + + //===================================================================== + //GETTERS / SETTERS + //===================================================================== + /* + public ZBinaryReader::GetStreamByteOrder + + Gets the byte order in which the stream (source data) is read as. + + @return (SST_ByteOrder) - The byte order + */ + SST_ByteOrder GetStreamByteOrder() const { return streamByteOrder; } + + /* + public ZBinaryReader::SetStreamByteOrder + + Sets the byte order in which the stream (source data) is read as. + + @param newOrder - The new byte order + @return (void) + */ + void SetStreamByteOrder(SST_ByteOrder newOrder) { streamByteOrder = newOrder; } + + private: + SST_ByteOrder streamByteOrder; //The current byte order the stream is being read in. + +}; + +#endif + diff --git a/Include/ZUtil/ZBitmap.hpp b/Include/ZUtil/ZBitmap.hpp new file mode 100644 index 0000000..1dc2947 --- /dev/null +++ b/Include/ZUtil/ZBitmap.hpp @@ -0,0 +1,253 @@ +/* + ZBitmap.hpp + Author: Chris Ertel , + James Russell + Created: 12/09/2010 + + Purpose: + + Bitmap metadata class. This is designed as a metadata package for the data, and + does not assume ownership of the data. By passing around a ZBitmap instead of a raw + pointer to byte data we always have metadata about the byte data on hand. + + License: + + TODO +*/ + +#pragma once + +#ifndef _ZBITMAP_H +#define _ZBITMAP_H + +#include + +//This is the format of the bitmap, which describes color layout and bits per channel +enum ZBitmapFormat +{ + ZBF_UNKNOWN, //Unknown Format (usually uninitialized) + + ZBF_R8, //8-bit Red Channel + ZBF_R8I, //8-bit Signed Red Channel + ZBF_R16, //16-bit Red Channel + ZBF_R16I, //16-bit Signed Red Channel + ZBF_R32, //32-bit Red Channel + ZBF_R32I, //32-bit Signed Red Channel + ZBF_R32F, //32-bit Floating Point Red Channel + + ZBF_RG8, //8-bit Red, Green Channel + ZBF_RG8I, //8-bit Signed Red, Green Channel + ZBF_RG16, //16-bit Red, Green Channel + ZBF_RG16I, //16-bit Signed Red, Green Channel + ZBF_RG32, //32-bit Red, Green Channel + ZBF_RG32I, //32-bit Signed Red, Green Channel + ZBF_RG32F, //32-bit Floating Point Red, Green Channel + + ZBF_RGB8, //8-bit Red, Green, Blue Channel + ZBF_RGB8I, //8-bit Signed Red, Green, Blue Channel + ZBF_RGB16, //16-bit Red, Green, Blue Channel + ZBF_RGB16I, //16-bit Signed Red, Green, Blue Channel + ZBF_RGB32, //32-bit Red, Green, Blue Channel + ZBF_RGB32I, //32-bit Signed Red, Green, Blue Channel + ZBF_RGB32F, //32-bit Floating Point Red, Green, Blue Channel + + ZBF_RGBA8, //8-bit Red, Green, Blue, Alpha Channel + ZBF_RGBA8I, //8-bit Signed Red, Green, Blue, Alpha Channel + ZBF_RGBA16, //16-bit Red, Green, Blue, Alpha Channel + ZBF_RGBA16I, //16-bit Signed Red, Green, Blue, Alpha Channel + ZBF_RGBA32, //32-bit Red, Green, Blue, Alpha Channel + ZBF_RGBA32I, //32-bit Signed Red, Green, Blue, Alpha Channel + ZBF_RGBA32F, //32-bit Floating Point Red, Green, Blue, Alpha Channel + + ZBF_BGR8, //8-bit Blue, Green, Red Channel + ZBF_BGR8I, //8-bit Signed Blue, Green, Red Channel + ZBF_BGR16, //16-bit Blue, Green, Red Channel + ZBF_BGR16I, //16-bit Signed Blue, Green, Red Channel + ZBF_BGR32, //32-bit Blue, Green, Red Channel + ZBF_BGR32I, //32-bit Signed Blue, Green, Red Channel + ZBF_BGR32F, //32-bit Floating Point Blue, Green, Red Channel + + ZBF_BGRA8, //8-bit Blue, Green, Red, Alpha Channel + ZBF_BGRA8I, //8-bit Signed Blue, Green, Red, Alpha Channel + ZBF_BGRA16, //16-bit Blue, Green, Red, Alpha Channel + ZBF_BGRA16I, //16-bit Signed Blue, Green, Red, Alpha Channel + ZBF_BGRA32, //32-bit Blue, Green, Red, Alpha Channel + ZBF_BGRA32I, //32-bit Signed Blue, Green, Red, Alpha Channel + ZBF_BGRA32F, //32-bit Floating Point Blue, Green, Red, Alpha Channel + + ZBF_DEPTH32, //32-bit Unsigned Depth + + ZBCM_SIZE +}; + +/* +Bitmap data class. +*/ +class ZBitmap +{ +protected: + ZBitmapFormat Format; //Format of the bitmap + uint32_t Width; //Width of the bitmap + uint32_t Height; //Height of the bitmap + uint32_t Depth; //Depth of the bitmap + void* Data; //Pointer to the bitmap data (can be NULL) + +public: + + /* + Default Constructor + */ + ZBitmap() + : Format(ZBF_UNKNOWN), + Width(1), + Height(1), + Depth(1), + Data(NULL) + { } + + /* + Constructor. + + @param _format - the bitmap format + @param _width - the width (pixels) + @param _height - the height (pixels) + */ + ZBitmap(ZBitmapFormat _format, uint32_t _width, uint32_t _height) + : Format(_format), + Width(_width), + Height(_height), + Depth(1), + Data(NULL) + { } + + /* + Constructor. + + @param _format - the bitmap format + @param _width - the width (pixels) + @param _height - the height (pixels) + @param _depth - the depth (pixels) + */ + ZBitmap(ZBitmapFormat _format, uint32_t _width, uint32_t _height, uint32_t _depth) + : Format(_format), + Width(_width), + Height(_height), + Depth(_depth), + Data(NULL) + { } + + /* + Constructor. + + @param _format - the bitmap format + @param _width - the width (pixels) + @param _height - the height (pixels) + @param _depth - the depth (pixels) + @param _data - the bitmap data + */ + ZBitmap(ZBitmapFormat _format, uint32_t _width, uint32_t _height, uint32_t _depth, void* _data) + : Format(_format), + Width(_width), + Height(_height), + Depth(_depth), + Data(_data) + { } + + //Determines (based off Format) the Bits Per Pixel of this bitmap + size_t GetBPP() const + { + switch(Format) + { + case ZBF_R8: return 8; + case ZBF_R8I: return 8; + case ZBF_R16: return 16; + case ZBF_R16I: return 16; + case ZBF_R32: return 32; + case ZBF_R32I: return 32; + case ZBF_R32F: return 32; + + case ZBF_RG8: return 16; + case ZBF_RG8I: return 16; + case ZBF_RG16: return 32; + case ZBF_RG16I: return 32; + case ZBF_RG32: return 64; + case ZBF_RG32I: return 64; + case ZBF_RG32F: return 64; + + case ZBF_RGB8: return 24; + case ZBF_RGB8I: return 24; + case ZBF_RGB16: return 48; + case ZBF_RGB16I: return 48; + case ZBF_RGB32: return 96; + case ZBF_RGB32I: return 96; + case ZBF_RGB32F: return 96; + + case ZBF_RGBA8: return 32; + case ZBF_RGBA8I: return 32; + case ZBF_RGBA16: return 64; + case ZBF_RGBA16I: return 64; + case ZBF_RGBA32: return 128; + case ZBF_RGBA32I: return 128; + case ZBF_RGBA32F: return 128; + + case ZBF_BGR8: return 24; + case ZBF_BGR8I: return 24; + case ZBF_BGR16: return 48; + case ZBF_BGR16I: return 48; + case ZBF_BGR32: return 96; + case ZBF_BGR32I: return 96; + case ZBF_BGR32F: return 96; + + case ZBF_BGRA8: return 32; + case ZBF_BGRA8I: return 32; + case ZBF_BGRA16: return 64; + case ZBF_BGRA16I: return 64; + case ZBF_BGRA32: return 128; + case ZBF_BGRA32I: return 128; + case ZBF_BGRA32F: return 128; + + default: return 0; + } + } + + //Determines (based off of Width, Height, and Depth) the dimension of this bitmap (1, 2, or 3, 0 if inconsistent values) + size_t GetDimension() const + { + if (Width > 1 && Height > 1 && Depth > 1) + return 3; + else if (Width > 1 && Height > 1 && Depth <= 1) + return 2; + else if (Width > 1 && Height <= 1 && Depth <= 1) + return 1; + + return 0; + } + + //Computes and returns the size of the bitmap (in bytes) + size_t GetSize() const + { + return (Width * Depth * Height * GetBPP()) / 8; + } + + //Getter and Settter for 'Format' + inline ZBitmapFormat GetFormat() const { return this->Format; } + inline void SetFormat(ZBitmapFormat _format) { this->Format = _format; } + + //Getter and Setter for 'Width', in pixels + inline uint32_t GetWidth() const { return this->Width; } + inline void SetWidth(uint32_t _width) { this->Width = _width; } + + //Getter and Setter for 'Height', in pixels + inline uint32_t GetHeight() const { return this->Height; } + inline void SetHeight(uint32_t _height) { this->Height = _height; } + + //Getter and Setter for 'Depth', in pixels + inline uint32_t GetDepth() const { return this->Depth; } + inline void SetDepth(uint32_t _depth) { this->Depth = _depth; } + + //Getter and Setter for 'Data' + inline void* GetData() const { return this->Data; } + inline void SetData(void* _data) { this->Data = _data; } +}; + +#endif diff --git a/Include/ZUtil/ZConcurrency.hpp b/Include/ZUtil/ZConcurrency.hpp new file mode 100644 index 0000000..c2f993d --- /dev/null +++ b/Include/ZUtil/ZConcurrency.hpp @@ -0,0 +1,137 @@ +/* + ZConcurrency.hpp + Author : James Russell, Patrick Baggett + + Purpose : Provides a number of primitives for building concurrent programs. Each supported + platform has a separate implementation. + + Changelog + 1/24/11 - Creation (jcrussell) + 3/17/11 - Major change to support events, mutexes, thread local storage, and semaphores. (ptbaggett) +*/ + +#pragma once + +#ifndef _ZCONCURRENCY_HPP +#define _ZCONCURRENCY_HPP + +#include +#include +#include +#include +#include + +//Used to indicate an indefinite wait +#define ZWAIT_INFINITE (~((uint32_t)0)) + +//Typedef for a thread handle +typedef void* ZThreadHandle; + +/* +ZEngine thread data, used as a context for threads. The fields here should not be accessed directly. +*/ +struct ZThreadContext +{ + //The handle to this thread + ZThreadHandle Thread; + + //The id given to this thread. Unique, but may be reused after thread is destroyed + uint32_t ThreadId; + + //The return status this thread exited with (invalid unless Thread == NULL) + int ThreadExitStatus; + + //Default Constructor + ZThreadContext() { Invalidate(); } + + //Returns if it's valid + bool IsValid() const { return Thread != NULL; } + + //Marks a thread context as invalid + void Invalidate() { Thread = NULL; ThreadId = 0; ThreadExitStatus = 0; } +}; + +/* +Namespace used for static access to low-level thread functionality. +*/ +namespace ZConcurrency +{ + /* + ZThreadContext CreateThread() + + Creates a thread instance that will begin running the provided function. + The thread context should be cleaned up with DestroyThread() after the + thread exits (use WaitThread() to ensure it is exited). + + @param _func - function that the thread will execute. Should be of return type + int and take a void* as an argument. + @param _arg - the argument that is passed to the function. + + @return (ZThreadContext) - thread context, used as a handle to the thread + */ + ZThreadContext CreateThread(int(*_func)(void*), void *_arg); + + /* + void DestroyThread() + + Frees memory associated with a thread context. This should only be called + after the thread is known to be dead (e.g. using WaitThread()). As implied + by the last comment, this does not kill the OS thread if it was already + running. + + @param _context - Thread context to be cleaned up + @return (void) + */ + void DestroyThread(ZThreadContext& _context); + + /* + void SleepThread() + + Causes the calling thread to sleep for a minimum of the specified time (in ms). + + @param _ms - the specified time to sleep (in ms) + @return (void) + */ + void SleepThread(uint32_t _ms); + + /* + int GetThreadId() + + Gets the thread ID of the calling thread. + + @return (uint32_t) - int that is the thread id of the calling thread + */ + uint32_t GetThreadId(); + + /* + unsigned int GetTicks() + + Gets the tick count since the last call to GetTicks. + + @return (uint64_t) - the count (in ms) since program start. + */ + uint64_t GetTicks(); + + /* + int WaitThread() + + Waits for a thread to terminate. This is the only way to ensure thread resources are + returned. The termination code from the thread is stored in the thread context. + + @param _context - the handle returned from CreateThread (the termination code is stored here) + @return (bool) - true if the thread terminated, false otherwise + */ + bool WaitThread(ZThreadContext& _context); + + /* + void YieldThread() + + Causes the calling thread to yield execution to another thread. + + @return (void) + */ + void YieldThread(); +} + +#endif + diff --git a/Include/ZUtil/ZEvent.hpp b/Include/ZUtil/ZEvent.hpp new file mode 100644 index 0000000..8ae3cab --- /dev/null +++ b/Include/ZUtil/ZEvent.hpp @@ -0,0 +1,86 @@ +/* + ZEvent.hpp + Author: James Russell + + Purpose: RAII wrapper for SST_Event from libsst-concurrency. + + Changelog + 2011/11/27 - creation (jcrussell) +*/ + +#pragma once + +#ifndef _ZEVENT_H +#define _ZEVENT_H + +#include +#include + +/* +Event class. Used to manage allocation and deallocation of events. +Cannot be copied or assigned, which prevents it from being used in stl-like containers. +*/ +class ZEvent +{ +private: + DISABLE_COPY_AND_ASSIGN(ZEvent); + + //libsst Event + SST_Event Event; + +public: + /* + Constructor. Creates an event from libsst-concurrency. + */ + ZEvent(); + + /* + Destructor. Frees our event from libsst-concurrency. + */ + ~ZEvent(); + + /* + public ZSignal::Notify + + Signals event, waking up all waiting threads. Until this event is reset, waiting threads will return. + + @return (void) + @context (all) + */ + void Notify(); + + /* + public ZSignal::Reset + + Signals reset, which causes threads that call Wait to block until signaled. + + @return (void) + @context (all) + */ + void Reset(); + + /* + public ZSignal::Wait + + Waits on a signal. Blocks until Signal is called. + + @return (bool) - true if the event was signaled, false if returned before a signal (such as event not reset) + @context (all) + */ + bool Wait(); + + /* + public ZSignal::Wait + + Waits on a signal for an amount of time. + + @param _ms - the amount of time (in ms) to wait. + @return (bool) - true if the event was signaled, false if returned before a signal (event not reset our out of time). + @context (all) + */ + bool Wait(uint32_t _ms); +}; + + +#endif + diff --git a/Include/ZUtil/ZIniReader.hpp b/Include/ZUtil/ZIniReader.hpp new file mode 100644 index 0000000..3eab0b4 --- /dev/null +++ b/Include/ZUtil/ZIniReader.hpp @@ -0,0 +1,184 @@ +/* + ZIniReader.hpp + Author: James Russell + Created: 4/27/2012 + + Purpose: + + Parses INI file format in memory. + + (File Begin) + + # This is a commented line + ; This is too + + [SectionA] + Key1=Value1 + Key2 =Value2 + Key3= Value3 + Key4 = Value4 + + [SectionB] + Key1 = Value1 + + ... + + (File End) + + Comments must be on their own line. Sections must be unique to a file. Keys can be repeated, + but the final value seen is the value recorded. + + ZIniReader class does no I/O - it merely parses in-memory representations. + + The data structures it provides a read-only, but you can get a mutable copy of its data as + a ZRegistry object. The data above would be loaded into a registry with the following layout: + + Root + | + +-> SectionA + | | + | +-> Key1 (Value1) + | +-> Key2 (Value2) + | +-> Key3 (Value3) + | +-> Key4 (Value4) + | + +-> SectionB + | + +-> Key1 (Value1) + + License: + + TODO +*/ + +#ifndef _ZINIREADER_HPP +#define _ZINIREADER_HPP + +#include + +/* +IniReader class. +*/ +class ZIniReader +{ +public: + /* + Default constructor. + */ + ZIniReader() + : ErrorMessage() { } + + /* + Destructor. + */ + ~ZIniReader() + { ClearData(); } + + /* + public ZIniReader::Read + + Reads an INI file stored as a ZString. + + @param _iniData - string holding the data of an ini file, which will be parsed + @return (bool) - True if successful, false if failure. Use GetErrorString() to get the message + */ + bool Read(const ZString& _iniData) + { return Read(_iniData.Data(), _iniData.Length()); } + + /* + public ZIniReader::Read + + Reads an INI file stored as memory block + + @param data - Pointer to INI data + @param length - Length of INI data + @return (bool) - true if successful, false if failure (use GetErrorString() to get the message) + */ + bool Read(const char* data, size_t length); + + /* + public ZIniReader::GetErrorString + + Gets the error message generated while loading the data if loading failed. If loading + the data was successful, this returns an empty string. + + @return (const ZString&) - error message string + */ + const ZString& GetErrorString() + { return ErrorMessage; } + + /* + public ZIniReader::GetSection + + Looks up a section by name and returns a pointer to the ZHashMap object. If the + section does not exist, NULL is returned. The hashmap contains a list of key-value pairs + found for that section + + @param sectionName - The name of the section + @return (const ZHashMap*) - The section, or NULL if it does not exist + */ + const ZHashMap* GetSection(const ZString& sectionName); + + /* + public ZIniReader::GetSection + + Looks up a section by ordinal and returns a pointer to the ZHashMap object. Sections + are given in order of appearance in the file. The hashmap contains a list of key-value pairs + found for that section. + + @param index - The index of the section, between 0 and GetSectionCount() - 1 + @return (const ZHashMap*) - The section + */ + const ZHashMap* GetSection(size_t index) + { return Sections[index]; } + + /* + public ZIniReader::GetSectionCount + + Gets the number of sections parsed. If Read() returned true, this will be at least one. + @return (size_t) - The number of sections parsed. + */ + size_t GetSectionCount() + { return Sections.Size(); } + + /* + public ZIniReader::GetSectionName + + Gets the name for a section by ordinal. Sections names are given in order of appearance + in the file. + + @param index - The index of the section, between 0 and GetSectionCount()-1 + @return (const ZString&) - The section name + */ + const ZString& GetSectionName(size_t index) + { return SectionNames[index]; } + + /* + public ZIniReader::GetKVTree + + Populates a ZKVTree using the read values. If loading the data has failed, + no data is entered. + + To get values in the kv-tree, use the path string 'Section.Key'. + + @param _kvtree - the kv-tree to contain the parsed ini values + @return (void) + */ + void GetKVTree(ZKVTree& _kvtree); + +private: + DISABLE_COPY_AND_ASSIGN(ZIniReader); + + ZString ErrorMessage; // Error Message (if an error has happened) + + ZHashMap*> StringSectionMap; // String -> Hashmap table + ZArray*> Sections; // Linear order in which sections were found + ZArray SectionNames; // Name of sections parsed + + void SetError(const char* message, uint32_t line); // Sets the error message + void ClearData(); // Clears previously read section data + +}; + +#endif + diff --git a/Include/ZUtil/ZIniWriter.hpp b/Include/ZUtil/ZIniWriter.hpp new file mode 100644 index 0000000..6d1aec6 --- /dev/null +++ b/Include/ZUtil/ZIniWriter.hpp @@ -0,0 +1,69 @@ +/* + ZIniWriter.hpp + Author: James Russell + Created: 5/6/2012 + + Purpose: + + The 'inverse' of ZIniReader, this will take a kvtree of values (like the one given by + ZIniReader) and write to an output string in the .ini format specified in ZIniReader.hpp. + + License: + + TODO + +*/ + +#pragma once + +#ifndef _ZINIWRITER_HPP +#define _ZINIWRITER_HPP + +#include +#include + +/* +IniWriter class. +*/ +class ZIniWriter +{ +public: + /* + Default Constructor. + */ + ZIniWriter() { } + + /* + Destructor. + */ + ~ZIniWriter() { } + + /* + public ZIniWriter::GetErrorString + + Gets the error message generated while writing the data if writing failed. If writing + the data was successful, this returns an empty string. + + @return (const ZString&) + */ + const ZString& GetErrorString(); + + /* + public ZIniWriter::Write + + Writes the data from the provided kvtree into the provided output string in the 'ini' format. + + @param _input - the tree to read values from + @param _output - the string to write the data into (the data is appended) + @return (bool) - true if successful, false otherwise + */ + bool Write(const ZKVTree& _input, ZString& _output); + +private: + DISABLE_COPY_AND_ASSIGN(ZIniWriter); + + //Error message (if an error has happened) + ZString ErrorMessage; +}; + +#endif diff --git a/Include/ZUtil/ZJSONReader.hpp b/Include/ZUtil/ZJSONReader.hpp new file mode 100644 index 0000000..ccc612f --- /dev/null +++ b/Include/ZUtil/ZJSONReader.hpp @@ -0,0 +1,69 @@ +/* + ZJSONReader.hpp + Author: Chris Ertel + Created: 3/26/2013 + + Purpose: + + JSON reading support, to convert JSON strings into ZKVTrees. + + License: + + TODO + +*/ +#pragma once +#ifndef _ZJSONREADER_H +#define _ZJSONREADER_H + +#include +#include + +/* +ZJSONReader class, which converts JSON data into a ZKVTree that can be used to access / iterate +the data. +*/ +class ZJSONReader +{ +private: + DISABLE_COPY_AND_ASSIGN(ZJSONReader); + + //Error Message (if an error has happened) + ZString ErrorMessage; + const ZString JSONData; + + //Registry of data + ZPtr Registry; + +public: + /* + Parameterized Constructor. + + @param _jsonData - string containing JSON data to parse + */ + ZJSONReader(const ZString& _jsonData); + + /* + public ZJSONReader::GetErrorString + + Gets the error message generated while loading the data if loading failed. If loading + the data was successful, this returns an empty string. + + @return (const ZString&) - error message string + */ + const ZString& GetErrorString(); + + /* + public ZJSONReader::GetKVTree + + Gets the registry that was constructed from the parsed JSON data. If the loading failed, + the pointer returned is NULL. + + TODO - describe the format + + @return (ZPtr) - registry containing the parsed JSON data + */ + ZPtr GetKVTree(); +}; + +#endif \ No newline at end of file diff --git a/Include/ZUtil/ZJSONWriter.hpp b/Include/ZUtil/ZJSONWriter.hpp new file mode 100644 index 0000000..5375bf2 --- /dev/null +++ b/Include/ZUtil/ZJSONWriter.hpp @@ -0,0 +1,64 @@ +/* + ZJSONWriter.hpp + Author: Chris Ertel + Created: 3/26/2013 + + Purpose: + + JSON writing support, to convert ZKVTrees into JSON strings. + + License: + + TODO + +*/ +#pragma once +#ifndef _ZJSONWRITER_H +#define _ZJSONWRITER_H + +#include +#include + +class ZJSONWriter +{ +private: + DISABLE_COPY_AND_ASSIGN(ZJSONWriter); + + //Error message (if an error has happened) + ZString ErrorMessage; + + //The registry we will be getting values from + ZPtr Registry; + + const ZString NoError; + +public: + /* + Parameterized Constructor. + + @param _registry - the registry to generate XML data from + */ + ZJSONWriter(ZPtr _registry); + + /* + public ZJSONWriter::GetErrorString + + Gets the error message generated while writing the data if writing failed. If writing + the data was successful, this returns an empty string. + + @return (const ZString&) - a string describing an error that occurred + */ + const ZString& GetErrorString(); + + /* + public ZJSONWriter::Write + + Writes the data from the registry into the provided output string in XML format. + + @param _output - the string to write the data into (the data is appended) + @return (bool) - true if successful, false otherwise + */ + bool Write(ZString& _output); +}; + +#endif \ No newline at end of file diff --git a/Include/ZUtil/ZKVTree.hpp b/Include/ZUtil/ZKVTree.hpp new file mode 100644 index 0000000..5c6a800 --- /dev/null +++ b/Include/ZUtil/ZKVTree.hpp @@ -0,0 +1,821 @@ + /* + ZKVTree.hpp + Author: James Russell + Created: 3/22/2012 + + Purpose: + + ZKVTree defines a KV-Tree that uses strings as both keys and values. The model + supported is hierarchical with no nesting limit, and individual nodes can be addressed + directly or the tree can be iterated. This makes ZKVTree's typical use case as an + in memory representation of hierarchical text formats such as XML and JSON, and can + be used for simpler formats such as INI. When the layout and keys are known + (such as with most INI files), lookup via path string is the easiest route. When the layout + is not known (such as with an XML file with variable numbers of children and attributes), + then iteration is the preferred method of getting access to the data. + + Multiple nodes of the same name existing at the same level in the tree is supported. + When a path is given that does not contain the number, then it is assumed to be + referencing the first sibling node at that location (index 0). + + Unnamed tree nodes are supported, with the key used to access those being omitted from the + path string but the subscript being required. + + If the tree has the following layout, with the values at each node contained + in parenthesis: + + Root + | + +-> A (0) + | | + | +-> B (8) + | | | + | | +-> c (16) + | | +-> c (32) + | | +-> (100) + | | +-> (200) + | | + | +-> B (8) + | | | + | | +-> c (64) + | | +-> d (128) + | | +-> (10) + | | +-> (20) + | | + | +-> b (5) + | +-> b (10) + | +-> c (15) + | +-> d (20) + | + +-> B (8) + | | + | +-> c (50) + | +-> d (100) + | + +-> a (1) + +-> a (2) + +-> a (3) + +-> b (4) + + Then valid path strings include (but are not limited to): + + A.B - would get the value of node 'B[0]' (8) with parent node 'A[0]' + A.B.c - would get the value of node 'c[0]' (16) with parent node 'A[0].B[0]' + A.B.c[1] - would get the value of node 'c[1]' (32) with parent node 'A[0].B[0]' + A.B[1].c - would get the value of node 'c[0]' (64) with parent node 'A[0].B[1]' + A.B[1].c[1] - would get the value of node 'c[1]' (128) with parent node 'A[0].B[1]' + A.b[1] - would get the value of node 'b[1]' (10) with parent node 'A[0]' + B.c - would get the value of node 'c[0]' (50) with parent node 'B[0]' + a - would get the value of node 'a[0]' (1) with root parent node '' + a[2] - would get the value of node 'a[2]' (3) with root parent node '' + + If this KVTree were to be iterated using ZKVTree::Iterator::Next(), a depth first + traversal of the structure would take place, giving us the following order: + + A + A.B[0] + A.B[0].c[0] + A.B[0].c[1] + A.B[0].[0] + A.B[0].[1] + A.B[1].c + A.B[1].d + A.B[1].[0] + A.B[1].[1] + A.b[0] + A.b[1] + A.c + A.d + B + B.c + B.d + a[0] + a[1] + a[2] + + A special syntax for accessing unnamed children is supported, which enables nested array behavior + for values: + + A.B[0][0] - would get the value of (unnamed) node '[0]' (100) with parent node 'A.B[0]' + A.B[1][0] - would get the value of (unnamed) node '[0]' (10) with parent node 'A.B[0]' + A.B[1][1] - would get the value of (unnamed) node '[1]' (20) with parent node 'A.B[1]' + + Note that these are syntactic sugar for: + + A.B[0].[0] (could also be expressed as A.B[0]. or A.B. due to the implicit [0]) + A.B[1].[0] (could also be expressed as A.B[1]. due to the implicit [0]) + A.B[1].[1] + + License: + + TODO +*/ + +#ifndef _ZREGISTRY_H +#define _ZREGISTRY_H + +#include + +#include +#include +#include + +#include +#include + +#include + +//Valid path separator for ZKVTree +#ifndef ZKVTREE_PATH_SEPARATOR +#define ZKVTREE_PATH_SEPARATOR '.' +#endif + +//Default number of nodes preallocated +#ifndef ZKVTREE_NODE_COUNT +#define ZKVTREE_NODE_COUNT (128) +#endif + +//Invalid characters for a path ([] valid on subscript only) +#define ZKVTREE_INVALID_PATH_CHARS "%[]" + +/* +ZKVTree class. +*/ +class ZKVTree +{ +public: + //KVTree node structure + struct Node + { + ZString Name; //Name of the node + ZString Value; //Value held by this node + Node* ParentNode; //Pointer to our parent node + size_t Index; //Index of this node in the parent's children array + ZArray< Node* > Children; //Children of this node + + //Determines if this is the root node + bool IsRootNode() const { + if (ParentNode == NULL) { + return true; + } else return false; + } + + //Finds the node with the given name in the child array + Node* GetChildByName(const ZString& _name, size_t _start, size_t _end, size_t _subscript) const { + for (size_t i = 0; i < Children.Size(); i++) { + Node* child = Children.Data()[i]; + if (child->Name.Length() == (_end - _start)) { + if (ZStringAlgo::Equal(child->Name, 0, child->Name.Length(), _name, _start, _end)) { + if (_subscript-- == 0) { + return child; + } + } + } + } + return NULL; + } + + //Finds the number of children with the given name + size_t GetChildCountByName(const ZString& _name, size_t _start, size_t _end) const { + size_t num = 0; + for (size_t i = 0; i < Children.Size(); i++) { + Node* child = Children.Data()[i]; + if (child->Name.Length() == (_end - _start)) { + if (ZStringAlgo::Equal(child->Name, 0, child->Name.Length(), _name, _start, _end)) { + num++; + } + } + } + return num; + } + + //Finds the index of the last occurrence of a node with the given name + size_t GetLastIndexByName(const ZString& _name, size_t _start, size_t _end) const { + size_t idx = 0; + for (size_t i = 0; i < Children.Size(); i++) { + Node* child = Children.Data()[i]; + if (child->Name.Length() == (_end - _start)) { + if (ZStringAlgo::Equal(child->Name, 0, child->Name.Length(), _name, _start, _end)) { + idx = i; + } + } + } + return idx; + } + + //Gets the path to this node + void GetPath(ZString& _out, Node* _end = NULL) const { + if (this != _end && ParentNode != NULL) { + ParentNode->GetPath(_out, _end); + } else return; + + if (!_out.Empty()) { + _out.PushBack(ZKVTREE_PATH_SEPARATOR); + } + + if (!IsRootNode()) { + size_t siblings = ParentNode->GetChildCountByName(Name, 0, Name.Length()); + size_t last_idx = ParentNode->GetLastIndexByName(Name, 0, Name.Length()); + + _out += Name; + + if (ParentNode != _end) { + ZString subscript; + ZStringAlgo::BuildPrintf(subscript, "[%i]", siblings - (1 + last_idx - Index)); + + _out += subscript; + } + } + } + + // gets the simple path to this node (avoids [0] subscript) + void GetSimplePath(ZString& _out, Node* _end = NULL) const { + if (this != _end && ParentNode != NULL) { + ParentNode->GetSimplePath(_out, _end); + } else return; + + if (!_out.Empty()) { + _out.PushBack(ZKVTREE_PATH_SEPARATOR); + } + + if (!IsRootNode()) { + size_t siblings = ParentNode->GetChildCountByName(Name, 0, Name.Length()); + size_t last_idx = ParentNode->GetLastIndexByName(Name, 0, Name.Length()); + + _out += Name; + + if (ParentNode != _end && siblings - (1 + last_idx - Index) != 0) { + ZString subscript; + ZStringAlgo::BuildPrintf(subscript, "[%i]", siblings - (1 + last_idx - Index)); + + _out += subscript; + } + } + } + }; + + /* + KVTree iterator, used to directly iterate the nodes in the KVTree. + */ + class Iterator + { + friend class ZKVTree; + public: + /* + Parameterized Constructor. + + @param _node - the node to start the iterator at + @param _tree - the KVTree we are iterating (reference needed for locking / unlocking) + */ + Iterator(Node* _node, ZKVTree* _tree) + : CurrentNode(_node), KVTree(_tree) { } + + /* + Copy Constructor. + + @param _other - the other iterator + */ + Iterator(const Iterator& _other) + :CurrentNode(_other.CurrentNode), KVTree(_other.KVTree) { } + + /* + Destructor. Releases the lock (when 'Lock' is destructed). + */ + ~Iterator() { } + + /* + Gets the path to the current iterator location. + + @return (ZString) - path to this node + */ + ZString GetPath() const + { ZString path; CurrentNode->GetPath(path); return path; } + + /* + Gets the path to the current iterator from an end node. If the end node + is not on the parent path, functionally equivalent to GetPath. + + @param _end - node we should get path from + @return (ZString) - path to this node from provided node + */ + ZString GetPath(Iterator end) const + { ZString path; CurrentNode->GetPath(path, end.CurrentNode); return path; } + + /* + As GetPath, but avoids the [0] subscript. + + @return (ZString) - path to this node + */ + ZString GetSimplePath() const + { ZString path; CurrentNode->GetSimplePath(path); return path; } + + /* + As GetPath, but avoids the [0] subscript. + + @param _end - node we should get path from + @return (ZString) - path to this node from provided node + */ + ZString GetSimplePath(Iterator end) const + { ZString path; CurrentNode->GetSimplePath(path, end.CurrentNode); return path; } + + /* + Gets a reference to the name of the current node. + + @return (const ZString&) - reference to the name of the current node + */ + const ZString& GetName() const + { ZASSERT(!CurrentNode->IsRootNode(), "Cannot get name on root node!"); return CurrentNode->Name; } + + /* + Gets a reference to the value of the current node. + + @return (ZString&) - reference to the value of the current node + */ + const ZString& GetValue() const + { ZASSERT(!CurrentNode->IsRootNode(), "Cannot get value on root node!"); return CurrentNode->Value; } + + /* + Gets the index of the current node (sibling index). + + @return (size_t) - the index of the current node. + */ + size_t GetIndex() const + { return CurrentNode->Index; } + + /* + Gets the number of children contained by this node. + */ + size_t GetChildCount() const + { return CurrentNode->Children.Size(); } + + /* + Gets the number of children of this node with the given name. + */ + size_t GetChildCountByName(const ZString& _name) const + { return CurrentNode->GetChildCountByName(_name, 0, _name.Length()); } + + /* + Gets the index of the nth child of the given name (ZSTL::InvalidPos if not found). + */ + size_t GetChildIndexByName(const ZString& _name, size_t _n = 0) const + { + Node* childNode = CurrentNode->GetChildByName(_name, 0, _name.Length(), _n); + + return (childNode == NULL ? ZSTL::InvalidPos : childNode->Index); + } + + /* + Gets the number of siblings to the current node, including the current node. + */ + size_t GetSiblingCount() const + { + if (CurrentNode->ParentNode == NULL) + return 0; + + return CurrentNode->ParentNode->Children.Size(); + } + + /* + Gets the number of siblings to the current node with the given name (can + include this node if name is equivalent). + */ + size_t GetSiblingCountByName(const ZString& _name) const + { + if (CurrentNode->ParentNode == NULL) + return 0; + + return CurrentNode->ParentNode->GetChildCountByName(_name, 0, _name.Length()); + } + + /* + Gets the index of the nth sibling of the given name (ZSTL::InvalidPos if not found, can + be the node this iterator points to). + */ + size_t GetSiblingIndexByName(const ZString& _name, size_t _n = 0) const + { + if (CurrentNode->ParentNode == NULL) + return ZSTL::InvalidPos; + + Node* siblingNode = CurrentNode->ParentNode->GetChildByName(_name, 0, _name.Length(), _n); + + return (siblingNode == NULL ? ZSTL::InvalidPos : siblingNode->Index); + } + + //Checks to see if this is an end node + bool CheckEnd() + { return CurrentNode->IsRootNode(); } + + //Checks to see if we can move to the parent node + bool CheckParent() + { return CurrentNode->ParentNode != NULL; } + + //Checks to see if we can move to the child node + bool CheckChild(size_t _index = 0) + { return _index < CurrentNode->Children.Size(); } + + //Checks to see if we can move to the sibling node + bool CheckSibling(size_t _index = 0) + { return CurrentNode->ParentNode != NULL && _index < CurrentNode->ParentNode->Children.Size() - 1; } + + //Checks to see if we can move to the next sibling node + bool CheckNextSibling() + { return CurrentNode->ParentNode != NULL && CurrentNode->Index < CurrentNode->ParentNode->Children.Size() - 1; } + + //Checks to see if we can move to the previous sibling node + bool CheckPrevSibling() + { return CurrentNode->Index > 0; } + + /* + Sets the value of the current node. + + @param (ZString&) - value to set this node to + */ + void SetValue(const ZString& _value) + { CurrentNode->Value = _value; } + + /* + public ZKVTree::Iterator::Next + + This operation attempts to move this iterator to the first child of this node. If this + is an invalid move, then it attempts to iterate to the next sibling. If this is invalid, + it will attempt to iterate to the next sibling of the parent, and will continue to + attempt this until it has either reached the end or it can do so. + + This basically means using nothing but 'Next' from beginning to end will result in + a depth-first traversal of the KVTree. + + @return (Iterator&) - this iterator + */ + Iterator& Next() + { + if (CheckChild()) + Child(); + else if (CheckNextSibling()) + NextSibling(); + else { + while (CurrentNode->ParentNode != NULL) { + if (CheckParent()) { + Parent(); + if (CheckNextSibling()) { + NextSibling(); + break; + } + } + } + } + + return *this; + } + + /* + public ZKVTree::Iterator::Parent + + This operation attempts to move the iterator to the parent node of this node. + + @return (Iterator&) - this iterator + */ + Iterator& Parent() + { + if (CheckParent()) { + CurrentNode = CurrentNode->ParentNode; + } else *this = KVTree->End(); + + return *this; + } + + /* + public ZKVTree::Iterator::Child + + This operation moves the iterator to child node at the given index. + + @param _index - the child number to move to + @return (Iterator&) - this iterator + */ + Iterator& Child(size_t _index = 0) + { + if (CheckChild(_index)) { + CurrentNode = CurrentNode->Children[_index]; + } else *this = KVTree->End(); + + return *this; + } + + /* + public ZKVTree::Iterator::Sibling + + This operation moves the iterator to the sibling node at the given index. + + @param _index - the sibling index + @return (Iterator&) - this iterator + */ + Iterator& Sibling(size_t _index = 0) + { + ZASSERT(CheckSibling(_index), "ZKVTree::Iterator unable to move to sibling node!"); + + if (CheckSibling(_index)) { + CurrentNode = CurrentNode->ParentNode->Children[_index]; + } else *this = KVTree->End(); + + return *this; + } + + /* + public ZKVTree::Iterator::PrevSibling + + This operation moves the iterator to the previous sibling node of this node. + + @return (Iterator&) - this iterator + */ + Iterator& PrevSibling() + { + if (CheckPrevSibling()) { + CurrentNode = CurrentNode->ParentNode->Children[CurrentNode->Index - 1]; + } else *this = KVTree->End(); + + return *this; + } + + /* + public ZKVTree::Iterator::NextSibling + + This operation moves the iterator to the next sibling node of this node. + + @return (Iterator&) - this iterator + */ + Iterator& NextSibling() + { + if (CheckNextSibling()) { + CurrentNode = CurrentNode->ParentNode->Children[CurrentNode->Index + 1]; + } else *this = KVTree->End(); + + return *this; + } + + /* + public ZKVTree::Iterator::ParentItr + + This operation returns an iterator to the parent node. + + @return (ZKVTree::Iterator) - iterator to the parent node + */ + Iterator ParentItr() const + { + ZASSERT(CurrentNode->ParentNode != NULL, "Unable to get KVTree parent!"); + + return Iterator(CurrentNode->ParentNode, KVTree); + } + + /* + public ZKVTree::Iterator::ChildItr + + This operation returns an iterator to the first child node of this iterator, + or the end iterator if no child is found. + + @param _index - the child node index to get an iterator to + @return (Iterator) - iterator to the child node + */ + Iterator ChildItr() const + { + return ChildItr(0); + } + + /* + public ZKVTree::Iterator::ChildItr + + This operation returns an iterator to the child node at the given index. + + @param _index - the child node index to get an iterator to + @return (Iterator) - iterator to the child node + */ + Iterator ChildItr(size_t _index) const + { + if (_index == ZSTL::InvalidPos || _index >= CurrentNode->Children.Size()) { + return KVTree->End(); + } else return Iterator(CurrentNode->Children.Data()[_index], KVTree); + } + + /* + public ZKVTree::Iterator::ChildItr + + This returns an iterator to the nth child of the given name. + + @param _name - the name of the child to get an iterator to + @param _n - the occurrence of the child to get (0 = first occurrence) + @return (Iterator) - iterator to the child node + */ + Iterator ChildItr(const ZString& name, size_t _n = 0) const + { + return ChildItr(GetChildIndexByName(name, _n)); + } + + /* + public ZKVTree::Iterator::GetSibling + + This operation returns an iterator to the sibling node at the given index. + + @param _index - the child node index to get an iterator to + @return (Iterator) - iterator to the child node + */ + Iterator SiblingItr(size_t _index) const + { + if (_index == ZSTL::InvalidPos || _index >= CurrentNode->ParentNode->Children.Size()) { + return KVTree->End(); + } else return Iterator(CurrentNode->ParentNode->Children.Data()[_index], KVTree); + } + + /* + public ZKVTree::Iterator::GetSibling + + This operation returns an iterator to the nth sibling of the given name. + + @param _name - the name of the sibling to get an iterator to + @param _n - the occurrence of the sibling to get (0 = first occurrence) + @return (Iterator) - iterator to the sibling node + */ + Iterator SiblingItr(const ZString& name, size_t _n = 0) const + { + return SiblingItr(GetSiblingIndexByName(name, _n)); + } + + //Operator Overloads + Iterator& operator ++ () { return Next(); } + Iterator operator ++ (int) { Iterator itr = *this; Next(); return itr; } + + Iterator& operator = (const Iterator& _other) { CurrentNode = _other.CurrentNode; KVTree = _other.KVTree; return *this; } + + bool operator == (const Iterator& _other) const { return CurrentNode == _other.CurrentNode; } + bool operator != (const Iterator& _other) const { return !(*this == _other); } + + private: + Node* CurrentNode; //Our current KVTree node + ZKVTree* KVTree; //The KVTree we are iterating + }; + + /* + Constructor. + */ + ZKVTree(); + + /* + Copy Constructor. + */ + ZKVTree(const ZKVTree& _other); + + /* + Destructor. + */ + ~ZKVTree(); + + /* + = operator. Performs a copy of node names and data. + + @param _other - the KVTree to copy from + */ + ZKVTree& operator = (const ZKVTree& _other); + + /* + public ZKVTree::Add + + Adds a node to the tree under the given parent node. The version that takes no parent path + will add the child under the root node. The iterator returned is used to directly address the + node. + + The two parameter version of this function adds children to the root node. + + @param _parent - the path to the parent node + @param _itr - iterator to the parent node + @param _name - the name of the child node + @param _value - the value of the child node + @return (Iterator) - iterator to the created node + */ + Iterator Add(const ZString& _name, const ZString& _value); + Iterator Add(const ZString& _parent, const ZString& _name, const ZString& _value); + Iterator Add(const Iterator& _itr, const ZString& _name, const ZString& _value); + + /* + public ZKVTree::Begin + + Gets a ZKVTree::Iterator to the first child of the root node of this KVTree. If there + are no children, returns ZKVTree::End(). + + @return (ZKVTree::Iterator) - iterator to the beginning of the KVTree (first child node) + */ + Iterator Begin() const; + + /* + public ZKVTree::Clear + + Clears the KVTree of all values. + + @return (void) + */ + void Clear(); + + /* + public ZKVTree::End + + Gets a ZKVTree::Iterator to the end of the KVTree. + + @return (ZKVTree::Iterator) - iterator to the end of the KVTree + */ + const Iterator End() const; + + /* + public ZKVTree::Erase + + Erases the node at the given position and all children. + + @param _path - the path to the node + @param _itr - iterator to the node (invalidated by this call) + @return (void) + */ + void Erase(const ZString& _path); + void Erase(const Iterator& _itr); + + /* + public ZKVTree::Find + + Gets a ZKVTree::Iterator to the given element if found. Returns an iterator + equivalent to ZKVTree::End() if not found. + + @param _path - path to the node to get an iterator to + @param _itr - parent iterator to search from (path will be searched from this node as root) + @return (ZKVTree::Iterator) - iterator to value if found, End() otherwise + */ + Iterator Find(const ZString& _path) const; + Iterator Find(const Iterator& _itr, const ZString& _path) const; + + /* + public ZKVTree::Get + + Gets a value from the KVTree that held by the node at the provided path. + + @param _path - the path to the node to get the value from (if no subscript, [0] is assumed) + @return (const ZString&) - reference to the value held by the node at the provided path + @assert - if no value exists at the provided path + */ + const ZString& Get(const ZString& _path) const; + const ZString& Get(const Iterator& _itr, const ZString& _path); + + /* + public ZKVTree::Merge + + Merges this KVTree with another, bringing in the values defined in the other + KVTree. + + @param _other - the KVTree to merge values from + @param _overwrite - if true, values will be overwritten when a conflict occurs + @return (void) + */ + void Merge(const ZKVTree& _other, bool _overwrite); + + /* + public ZKVTree::Put + + Puts a node with the given value into the KVTree at the provided path. Will overwrite + any existing value at that location. + + If the path string has a child node that does not exist, it will be created so long as the + subscript is for the next child node, i.e., if A.B.c[1] is passed in, it will be created so + long as A.B.c[0] exists. + + The iterator version overwrites the data at that location if the iterator was created by this + tree, and will attempt to create it as above if not from this tree. + + @param _path - the path to the KVTree value (if no index, [0] is assumed) + @param _itr - iterator to the node to assign the value to (will overwrite) + @param _value - the value to assign to the node + @return (Iterator) - iterator to the created value + */ + Iterator Put(const ZString& _key, const ZString& _value); + Iterator Put(const Iterator& _itr, const ZString& _value); + + /* + public ZKVTree::IsValidKeyName + + Checks that a key name is able to be put into the KVTree. + + This basically ensures that a key will be valid for use in pathing. + A valid key name doesn't contain whitespace, square brackets, or periods. + + @param _name - the name being considered for validity. + @return (bool) - true if the keyname would be valid in a path, false otherwise + */ + bool IsValidKeyName( const ZString& _key ) const; + +protected: + ZSlabAllocator NodeAllocator; + + Node RootNode; // The root node of the KVTree (also acts as the end node) + + //Gets a node from the KVTree given a path (NULL if not found) + Node* GetFromPath(const ZString& _path) const; + + //Creates all the nodes needed along a path to be able to get and set the value, returning the node + Node* CreatePath(const ZString& _path); + + //Helper function used to check in all nodes + void NodeCheckIn(Node* _node); +}; + +#endif diff --git a/Include/ZUtil/ZLog.hpp b/Include/ZUtil/ZLog.hpp new file mode 100644 index 0000000..a13a0bb --- /dev/null +++ b/Include/ZUtil/ZLog.hpp @@ -0,0 +1,269 @@ +/* + ZLog.hpp + Author: James Russell + + Purpose: + + Logging utility. The logging class cannot be instantiated, but instead is utilized through + static public method calls. The logging system must be initialized before use and can be + shutdown at any time. Any logging calls placed after the system has been shutdown amount + to a no-op. + + The logging system is thread-safe. + + License: + + TODO +*/ + + +#ifndef _ZLOG_HPP +#define _ZLOG_HPP + +#include +#include + +#include +#include + +#include +#include + +//Typedef to define a log file handle +typedef size_t ZLogFile; + +//Logging type enumeration used to specify which level of log is being performed +enum ZLogType +{ + LOG_ERROR, //Used when an error condition has occurred + LOG_WARNING, //Used when a recoverable error condition has occurred + LOG_INFO, //Used when significant events have occurred + LOG_SPAM, //Used for insignificant events and process flow notification + LOG_SIZE +}; + +//Overall Logging Levels +#define ZLOG_LEVEL_NONE 0 +#define ZLOG_LEVEL_ERROR 1 +#define ZLOG_LEVEL_WARNING 2 +#define ZLOG_LEVEL_INFO 3 +#define ZLOG_LEVEL_SPAM 4 + +//If the log level is not defined by the user, then ensure all logging is handled +#ifndef ZLOG_LEVEL +#define ZLOG_LEVEL ZLOG_LEVEL_SPAM +#endif + +//Define used to enumerate the default log file +#define ZLOGFILE_DEFAULT 0 + +#if defined(_MSC_VER) || defined(__GNUC__) || defined(__SUNPRO_CC) //C99 style variadic macros + +#define SystemLogError(...) ZLog::Printf(LOG_ERROR, ZLOGFILE_DEFAULT, 0, 0, __FUNCTION__, __VA_ARGS__) +#define SystemLogWarning(...) ZLog::Printf(LOG_WARNING, ZLOGFILE_DEFAULT, 0, 0, __FUNCTION__, __VA_ARGS__) +#define SystemLogInfo(...) ZLog::Printf(LOG_INFO, ZLOGFILE_DEFAULT, 0, 0, __FUNCTION__, __VA_ARGS__) +#define SystemLogSpam(...) ZLog::Printf(LOG_SPAM, ZLOGFILE_DEFAULT, 0, 0, __FUNCTION__, __VA_ARGS__) + +#if ZLOG_LEVEL < ZLOG_LEVEL_SPAM +#undef SystemLogSpam +#define SystemLogSpam(...) +#endif +#if ZLOG_LEVEL < ZLOG_LEVEL_INFO +#undef SystemLogInfo +#define SystemLogInfo(...) +#endif +#if ZLOG_LEVEL < ZLOG_LEVEL_WARNING +#undef SystemLogWarning +#define SystemLogWarning(...) +#endif +#if ZLOG_LEVEL < ZLOG_LEVEL_ERROR +#undef SystemLogError +#define SystemLogError(...) +#endif +#if (ZLOG_LEVEL < ZLOG_LEVEL_NONE) || (ZLOG_LEVEL > ZLOG_LEVEL_SPAM) +#error ZLOG_LEVEL Set to Invalid Value! +#endif + +#else //Not C99-style variadic macro + +#error Define variadic macro flavor for your compiler in ZLog.hpp + +#endif + +/* +Logging delegate. Called when a log entry has been made. +*/ +class ZLogDelegate +{ +public: + virtual ~ZLogDelegate() { } + /* + virtual public ZLogDelegate::Execute + + Delegate execute method. This is called whenever a logging entry has been made. + + @param _type - the type of logging entry + @param _file - the log file written to + @param _logEntry - the logging entry made + @return (void) + */ + virtual void Execute(ZLogType _type, ZLogFile _file, const ZString& _logEntry) = 0; +}; + +/* +ZEngine logging class. +*/ +class ZLog +{ +private: + //Mutex for logging system + static ZMutex LogLock; + + //Boolean indicating the logging system is activated + static bool bIsInitialized; + + //Array of logging output streams (second pair parameter indicates active / suspended) + static ZArray< ZPair > LogFiles; + + //Array of logging delegates + static ZArray< ZPtr > Delegates; + + //Root path for logging + static ZString LogFileRoot; + + //Maintained Tick Count + static uint64_t *UserTick; + + //Maintained Update Frame Count + static uint64_t *UserUpdate; + + //Tick Estimate when NULL is passed in as Tick + static uint64_t TickEstimate; + + //Update Frame estimate when NULL is passed in as Update tick + static uint64_t UpdateFrameEstimate; + + //Private Constructor + ZLog() { } + + //Private Copy Constructor + ZLog(const ZLog& _other) { URFP(_other); } + + //Private Destructor + ~ZLog() { } + +public: + + ///////////////////////////////// + /* Initialization and Shutdown */ + ///////////////////////////////// + + /* + static public ZFileSystem::Init + + Initialization method for ZLog. Until this is called, all logging calls return immediately. + + @param _logFileRoot - the directory to place log files in + @param _defaultLogFile - log file name for the 'default' log file (NULL log file) + @param _ticks - pointer to a value that will be updated with tick count (NULL to use parameter value only) + @param _update - pointer to a value that will be updated with update frame count (NULL to use parameter value only) + @return (void) + */ + static void Init(const ZString& _logFileRoot, const ZString& _defaultLogFile, uint64_t* _ticks = NULL, uint64_t* _update = NULL); + + /* + static public ZFileSystem::Shutdown + + Shutdown method for ZLog. Closes out the opened log files and flushes the output buffers. After + this is called, all logging operations return immediately. + + @return (void) + */ + static void Shutdown(); + + /////////////////////////////// + /* Logging System Operations */ + /////////////////////////////// + + /* + static public ZFileSystem::AddLoggingDelegate + + Adds a logging delegate to the system which is called whenever logging takes + place. + + @param _delegate - the logging delegate to call when logging takes place + @return (void) + */ + static void AddLoggingDelegate(ZPtr _delegate); + + /* + static public ZFileSystem::CreateLogFile + + Creates a log file for use in the system. + + @param _fileName - the name to use for the log file + @return (ZLOG_FILE) - the created log file (will be NULL if could not create) + */ + static ZLogFile CreateLogFile(const ZString& _fileName); + + /* + public static ZLog::Resume + + Resumes logging operations on a given log file. + + @param _logFile - the file to suspend logging operations on + @return (void) + */ + static void Resume(ZLogFile _logFile); + + /* + public static ZLog::SuspendLogging + + Suspends logging operations on a given log file. + + @param _logFile - the file to suspend logging operations on + @return (void) + */ + static void Suspend(ZLogFile _logFile); + + ///////////////////// + /* Logging Methods */ + ///////////////////// + + /* + static public ZFileSystem::Printf + + Varardic logging function, which writes the given string out to the log file. This version takes varargs in the + same way as printf. This logging function has a limit on the length of the output string of 4096 characters - excess + characters will be truncated. + + @param _type - the logging type + @param _file - the file to write to (if ZLOG_DEFAULT, uses the default file) + @param _ticks - the tick count at which the log file is written + @param _updateFrame - the update 'frame' during which the log is written + @param _str - the string to write to the log file + @param ... - the variable arguments to provide to format _str + @param args - parsed va_list + @return (void) + */ + static void Printf(ZLogType _type, ZLogFile _file, uint64_t _ticks, uint32_t _updateFrame, const char *_function, const char *_str, ...); + + /* + static public ZFileSystem::WriteLine + + Writes a string out to the given log file. + + @param _type - the logging type + @param _file - the file to write to (if ZLOG_DEFAULT, uses the default file) + @param _ticks - the tick count at which the log file is written + @param _updateFrame - the update 'frame' during which the log is written + @param _renderFrame - the render 'frame' during which the log is written + @param _str - the string to write to the log file + @return (void) + */ + static void WriteLine(ZLogType _type, ZLogFile _file, uint64_t _ticks, uint32_t _updateFrame, const char* _str); +}; + +#endif + + diff --git a/Include/ZUtil/ZMutex.hpp b/Include/ZUtil/ZMutex.hpp new file mode 100644 index 0000000..c1b3c61 --- /dev/null +++ b/Include/ZUtil/ZMutex.hpp @@ -0,0 +1,91 @@ +/* + ZMutex.hpp + Author: James Russell + + Purpose: RAII Wrapper for libsst-concurrency SST_Mutex objects. + + Changelog + 2011/11/27 - creation (jcrussell) +*/ + +#pragma once + +#ifndef _ZMUTEX_H +#define _ZMUTEX_H + +#include + +#include + +/* +ZMutex class. Used to allocate and deallocate a mutex within the scope of a class. +Cannot be copied or assigned, which prevents it from being used in stl-like containers. +*/ +class ZMutex +{ +private: + DISABLE_COPY_AND_ASSIGN(ZMutex); + + //libsst Mutex + SST_Mutex Mutex; + +public: + /* + Constructor. Creates a mutex from libsst-concurrency. + */ + ZMutex(); + + /* + Destructor. Frees our mutex from libsst-concurrency. + */ + ~ZMutex(); + + /* + public ZLock::Acquire + + Acquires this lock, which locks the contained mutex. + + @return (void) + @context (all) + */ + void Acquire(); + + /* + public ZLock::Release + + Releases this lock, which unlocks the contained mutex. + + @return (void) + @context (all) + */ + void Release(); +}; + +/* +Scoped lock. Acquires the provided lock so long as it remains in scope. Releases the lock when +it goes out of scope. +*/ +class ZLock +{ +private: + DISABLE_COPY_AND_ASSIGN(ZLock); + + //The Mutex + ZMutex& Mutex; + +public: + /* + Constructor. Acquires the mutex during construction. + + @param _mutex - the mutex we are to acquire + */ + ZLock(ZMutex& _lock); + + /* + Destructor. Releases the mutex when the object is destructed (goes out of scope). + */ + ~ZLock(); +}; + +#endif + diff --git a/Include/ZUtil/ZName.hpp b/Include/ZUtil/ZName.hpp new file mode 100644 index 0000000..0984aaf --- /dev/null +++ b/Include/ZUtil/ZName.hpp @@ -0,0 +1,172 @@ +/* + ZName.hpp + Author: James Russell + Created: 4/6/2011 + + Purpose: + + 'Name' implementation, which is a bit like a ZBasicString but remains constant after + construction. This allows for fast comparison and copy. + + In addition this allows the name to be compared to a hash of the name and determine equality. + + License: + + TODO + +*/ + +#ifndef _ZNAME_H +#define _ZNAME_H + +#include + +#include + +//This is the maximum allowed length of a name +#ifndef ZNAME_MAX_LENGTH +#define ZNAME_MAX_LENGTH (128) +#endif + +/* +ZName Implementation. +*/ +class ZName +{ +private: + //The string + char String[ZNAME_MAX_LENGTH + 1]; + + //Length of the string + size_t Length; + + //Hash of the string + uint64_t Hash; + +public: + /* + Constructor. + */ + ZName(); + + /* + Parameterized constructor. + + @param _string - the string name (null terminated) + */ + ZName(const char *_string); + + /* + Parameterized constructor. + + @param _string - the string name + */ + explicit ZName(const ZString& _string); + + /* + Parameterized constructor that takes the pre-computed hash value + for the name. When a ZName is constructed in this fashion, the + ToString() function will return ''. + + @param _hash - the precomputed hash value for this string + */ + ZName(uint64_t _hash); + + /* + Copy Constructor. + + @param _other - the other name + */ + ZName(const ZName& _other); + + /* + Destructor. + */ + ~ZName(); + + /* + = operator overload, that assigns this name to be another. + + @param _other - the name to assign this to + @return - this name + */ + ZName& operator = (const ZName& _other); + + /* + = operator overload, that assigns this name to be a string. + + @param _string - the string to create this name from + @return - this name + */ + ZName& operator = (const ZString& _string); + + /* + = operator overload, that assigns this name to be equal to a C-style string. + + @param _string - the string to create this name from + @return - this name + */ + ZName& operator = (const char* _string); + + /* + == operator. Because names are constant, this is a fast comparison. + + @param _other - the name to compare this to + @return - true if equal, false otherwise + */ + bool operator == (const ZName& _other) const; + + /* + == operator for comparison with strings. Less fast. + + @param _other - the string to compare this to + @return - true if equal, false otherwise + */ + bool operator == (const ZString& _other) const; + + /* + == operator. Compares a name against hash value only. + + @param hash - the hash value to compare + @return - true if equivalent hashes, false otherwise + */ + bool operator == (const ZHashValue hash) const; + + /* + != operator. Because names are constant, this is a fast comparison. + + @param _other - the name to compare this to + @return (bool) - true if not equal, false otherwise + */ + bool operator != (const ZName& _other) const; + + /* + Hash code override. Returns the (pre-computed) hash code. + + @return - hash code for this name + */ + operator ZHashValue () const; + + /* + Returns this name as a string. + + @return (ZString) - this name as a ZString + */ + operator ZString () const; + + /* + Gets this name as a string. + + @return (ZString) - this name as a ZString + */ + ZString ToString() const; + + /* + Returns the string data for this name. + + @return (char*) - string data + */ + const char* Data() const; +}; + +#endif diff --git a/Include/ZUtil/ZNoise.hpp b/Include/ZUtil/ZNoise.hpp new file mode 100644 index 0000000..b52d6bb --- /dev/null +++ b/Include/ZUtil/ZNoise.hpp @@ -0,0 +1,79 @@ +/* + ZNoise.hpp + Author : Chris Ertel + + Purpose : Interface class to call noise generation functions. + + Changelog + 2/13/11 - Creation (crertel) +*/ + +#ifndef _ZNOISE_H +#define _ZNOISE_H + +#include + +class ZNoise +{ +public: + virtual ~ZNoise() {} + + /* + virtual public ZNoise::reseed + + Function to set seed for the noise generator. + + @param _seed - int to seed the noise with. + @return (void) + */ + virtual void reseed (const int _seed) = 0; + + /* + virtual public ZNoise::noise1 + + Function for getting 1D noise. + + @param _x - float x coord + @return (float) - value of noise at x + */ + virtual float noise1(const float _x) = 0; + + /* + virtual public ZNoise::noise2 + + Function for getting 2D noise. + + @param _x - float x coord + @param _y - float y coord + @return (float) - value of noise at (x,y) + */ + virtual float noise2(const float _x, const float _y) = 0; + + /* + virtual public ZNoise::noise3 + + Function for getting 3D noise. + + @param _x - float x coord + @param _y - float y coord + @param _z - float z coord + @return (float) - value of noise at (x,y,z) + */ + virtual float noise3(const float _x, const float _y, const float _z) = 0; + + /* + virtual public ZNoise::noise4 + + Function for getting 4D noise. + + @param _x - float x coord + @param _y - float y coord + @param _z - float z coord + @param _w - float w coord + @return (float) - value of noise at (x,y,z,w) + */ + virtual float noise4(const float _x, const float _y, const float _z, const float _w) = 0; +}; + +#endif + diff --git a/Include/ZUtil/ZNoiseMap.hpp b/Include/ZUtil/ZNoiseMap.hpp new file mode 100644 index 0000000..36394e9 --- /dev/null +++ b/Include/ZUtil/ZNoiseMap.hpp @@ -0,0 +1,185 @@ +/* + ZNoiseMap.hpp + Author : Chris Ertel + + Purpose : Interface to create a map for noise values. + + Changelog + 2/13/11 - Creation (crertel) + 2/20/11 - Changed interface to be useful. (crertel) +*/ + +#ifndef _ZNOISEMAP_H +#define _ZNOISEMAP_H + +#include + +class ZNoiseMap +{ +public: + virtual ~ZNoiseMap() {} + + /* + virtual public ZNoiseMap::GetDimensionality + + Gets dimension of noise map (1,2,etc.). + + @return (int) - dimension of noise map + */ + virtual int GetDimensionality() = 0; + + /* + virtual public ZNoiseMap::GetLacunarity + + Get lacunarity (scaling of successive frequencies in noise series). + + @return (float) - lacunarity of noise map + */ + virtual float GetLacunarity() = 0; // scaling of successive frequencies in noise octaves + + /* + virtual public ZNoiseMap::GetPersistence + + Get persistence (scaling of successive amplitudes in noise series). + + @return (float) + */ + virtual float GetPersistence() = 0; // scaling of successive amplitudes in noise octaves + + + /* + virtual public ZNoiseMap::GetNumberOfOctaves + + Get number of octaves in noise series. + + @return (int) - number of terms in noise series. + */ + virtual int GetNumberOfOctaves() = 0; + + /* + virtual public ZNoiseMap::GetNumberSamplesInX + + Get number of samples in X dimensions of noise map. + + @return (int) - number of samples in X. + */ + virtual int GetNumberSamplesInX() = 0; + + /* + virtual public ZNoiseMap::GetNumberSamplesInY + + Get number of samples in Y dimensions of noise map. + + @return (int) - number of samples in Y. + */ + virtual int GetNumberSamplesInY() = 0; + + /* + virtual public ZNoiseMap::GetNumberSamplesInZ + + Get number of samples in Z dimensions of noise map. + + @return (int) - number of samples in Z. + */ + virtual int GetNumberSamplesInZ() = 0; + + /* + virtual public ZNoiseMap::GetNumberSamplesInW + + Get number of samples in Z dimensions of noise map. + + @return (int) - number of samples in W. + */ + virtual int GetNumberSamplesInW() = 0; + + /* + virtual public ZNoiseMap::SetLacunarity + + Sets the lacunarity (scaling of successive frequencies in noise series). + + @param _lac - lacunarity to use. + @return (void) + */ + virtual void SetLacunarity(float _lac) = 0; // scaling of successive frequencies in noise octaves + + /* + virtual public ZNoiseMap::SetPersistence + + Sets the persistence (scaling of successive amplitudes in noise series). + + @param _per - persistence to set noise map to. + @return (void) + */ + virtual void SetPersistence(float _per) = 0; // scaling of successive amplitudes in noise octaves + + /* + virtual public ZNoiseMap::SetNumberOfOctaves + + Set number of octave in noise series. + + @param _numOctaves - number of octaves to use. + @return (void) + */ + virtual void SetNumberOfOctaves(int _numOctaves ) = 0; + + /* + virtual public ZNoiseMap::SetNumberSamplesInX + + Sets number of samples in X direction. + + @param _numSamples - number of samples in X direction. + @return (void) + */ + virtual void SetNumberSamplesInX(int _numSamples) = 0; + + /* + virtual public ZNoiseMap::SetNumberSamplesInY + + Sets number of samples in Y direction. + + @param _numSamples - number of samples in Y direction. + @return (void) + */ + virtual void SetNumberSamplesInY(int _numSamples) = 0; + + /* + virtual public ZNoiseMap::SetNumberSamplesInZ + + Sets number of samples in Z direction. + + @param _numSamples - number of samples in Z direction. + @return (void) + */ + virtual void SetNumberSamplesInZ(int _numSamples) = 0; + + /* + virtual public ZNoiseMap::SetNumberSamplesInW + + Sets number of samples in W direction. + + @param _numSamples - number of samples in W direction. + @return (void) + */ + virtual void SetNumberSamplesInW(int _numSamples) = 0; + + /* + virtual public ZNoiseMap::Generate + + Generates noise map values. + + @return (bool) - True if successful, false otherwise. + */ + virtual bool Generate(int _seed) = 0; + + /* + virtual public ZNoiseMap::Cleanup + + Cleans up resources for noise map. + + @return (void) + */ + virtual void Cleanup() = 0; +}; + +#endif + diff --git a/Include/ZUtil/ZRandomGenerator.hpp b/Include/ZUtil/ZRandomGenerator.hpp new file mode 100644 index 0000000..bf3efcc --- /dev/null +++ b/Include/ZUtil/ZRandomGenerator.hpp @@ -0,0 +1,245 @@ +/* + ZRandomGeneratorBase.hpp + Author: James Russell + + Purpose: + + This is an RAII wrapper class for the libsst-random pseudo-random number generators that + also introduces some extra functionality. + + License: + + TODO +*/ + +#pragma once + +#ifndef _ZRANDOMGENERATOR_H +#define _ZRANDOMGENERATOR_H + +#include + +#include + +class ZRandomGenerator +{ +private: + DISABLE_COPY_AND_ASSIGN(ZRandomGenerator); + +protected: + //Our random generator type + const SST_PRNG_TYPE Type; + + //Random Seed + uint32_t Seed; + + //Random Sequence + uint64_t Sequence; + + //Our SST RNG Instance + SST_PRNG RNG; + +public: + /* + Default Constructor. + + This constructor will create a random generator that uses type SST_PRNG_SMALLPRNG, + that is seeded with the current time, and starts at sequence 0. + */ + ZRandomGenerator(); + + /* + Parameterized Constructor. + + @param _type - the type of random number generator to create + @param _seed - the seed to create the generator with + @param _sequence - the sequence number to start at + */ + ZRandomGenerator(SST_PRNG_TYPE _type, uint32_t _seed, uint64_t _sequence = 0); + + /* + Destructor. + */ + ~ZRandomGenerator(); + + /* + public ZRandomGenerator::GetFloat + + Gets next float from random generator in the range [0, 1). + + @return (float) - next float from the PRNG + */ + float GetFloat(); + + /* + public ZRandomGenerator::GetFloatArray + + Gets an array of floats from the random generator in the range [0, 1). + + @param _array - array to store floats into + @param _count - number of elements in array + @return (void) + */ + void GetFloatArray(float *_array, size_t _count); + + /* + public ZRandomGenerator::GetFloatInRange + + Gets a float in the range [_min, _max) + + @param _min - inclusive lower bound of range. + @param _max - exclusive upper bound of range. + @return (float) - next float in range. + */ + float GetFloatInRange(float _min, float _max); + + /* + public ZRandomGenerator::GetFloatArrayInRange + + Gets an array of floats in range [_min, _max). + + @param _array - array to store floats into + @param _count - number of elements in array + @param _min - inclusive lower bound of range + @param _max - exclusive upper bound of range + @return (void) + */ + void GetFloatArrayInRange(float *_array, size_t _count, float _min, float _max); + + /* + public ZRandomGeneratorGenerator::GetInt + + Gets an int in the range [STDINT_MIN, STDINT_MAX). + + @return (int) - next int from generator + */ + int GetInt(); + + /* + public ZRandomGenerator::GetIntArray + + Gets an array of ints in the range [STDINT_MIN, STDINT_MAX). + + @param _array - array to store ints into + @param _count - number of elements in + @return (void) + */ + void GetIntArray(int *_array, size_t _count); + + /* + public ZRandomGenerator::GetIntInRange + + Gets an int in the range [_min, _max). + + @param _min - inclusive lower bound of range + @param _max - exclusive upper bound of range + @return (int) - next int from range + */ + int GetIntInRange(int _min, int _max); + + /* + public ZRandomGenerator::GetIntArrayInRange + + Gets an array of ints in the range [_min, _max). + + @param _array - array to store floats into + @param _count - number of elements in array + @param _min - inclusive lower bound of range + @param _max - exclusive upper bound of range + @return (void) + */ + void GetIntArrayInRange( int *_array, size_t _count, int _min, int _max); + + /* + public ZRandomGenerator::GetGaussianFloat + + Gets a gaussian-distributed float in the range [_min, _max). This is expected to generate + two random numbers to get the gaussian distributed number, which will increase sequence by two. + + @param _min - inclusive lower bound of range + @param _max - exclusive upper bound of range + @return (float) - floating point number in range + */ + float GetGaussianFloat(float _min, float _max); + + /* + public ZRandomGenerator::GetGaussianFloatArray + + Gets an array of guassian-distributed floats in the range [_min, _max). This is expected to generate + two random numbers to get the gaussian distributed number, which will increase sequence by two. + + @param _array - array to store floats into + @param _count - number of elements in array + @param _min - inclusive lower bound of range + @param _max - exclusive upper bound of range + @return (void) + */ + void GetGaussianFloatArray(float *_array, size_t _count, float _min, float _max); + + /* + public ZRandomGenerator::GetGaussianInt + + Gets a gaussian-distributed int in the range [_min, _max). This is expected to generate + two random numbers to get the gaussian distributed number, which will increase sequence by two. + + @param _min - inclusive lower bound of range + @param _max - exclusive upper bound of range + @return (int) + */ + int GetGaussianInt(int _min, int _max); + + /* + public ZRandomGenerator::GetGaussianIntArray + + Gets an array of gaussian-distributed int in the range [_min, _max). This is expected to generate + two random numbers to get the gaussian distributed number, which will increase sequence by two. + + @param _array - array to store ints into + @param _count - number of elements in array + @param _min - inclusive lower bound of range + @param _max - exclusive upper bound of range + @return (void) + */ + void GetGaussianIntArray(int *_array, size_t _count, int _min, int _max); + + /* + public ZRandomGenerator::GetSeed + + Gets the seed of this random generator. + + @return (uint32_t) - PRNG seed + */ + uint32_t GetSeed(); + + /* + public ZRandomGenerator::GetSequence + + Gets the sequence of this random number generator, which is the number of random + numbers that have currently been generated. + + @return (uint64_t) - sequence of this random generator + */ + uint64_t GetSequence(); + + /* + public ZRandomGenerator::SetSequence + + Sets the sequence (amount of numbers generated) for this PRNG. + + @param _seq - sequence to set this generator to. + @return (void) + */ + void SetSequence(uint64_t _seq); + + /* + public ZRandomGenerator::SetSeed + + Sets the seed on this PRNG. + + @param _seed - 32 bit unsigned integer seed to use + @return (void) + */ + void SetSeed(uint32_t _seed); +}; + +#endif diff --git a/Include/ZUtil/ZReadWriteLock.hpp b/Include/ZUtil/ZReadWriteLock.hpp new file mode 100644 index 0000000..c74b585 --- /dev/null +++ b/Include/ZUtil/ZReadWriteLock.hpp @@ -0,0 +1,84 @@ +/* + ZReadWriteLock.hpp + Author: James Russell + Created: 5/17/2012 + + Purpose: + + RAII wrapper for SST_ReadWriteLock from libsst-concurrency. + + License: + + TODO + +*/ + +#pragma once + +#ifndef _ZREADWRITELOCK_HPP +#define _ZREADWRITELOCK_HPP + +#include + +#include + +class ZReadWriteLock +{ +private: + DISABLE_COPY_AND_ASSIGN(ZReadWriteLock); + + //The SST_ReadWriteLock + SST_ReadWriteLock Lock; + +public: + /* + Default Constructor. + */ + ZReadWriteLock(); + + /* + Destructor. + */ + ~ZReadWriteLock(); + + /* + public LockForReading + + Locks this read write lock for reading. Blocks until the lock is obtained. + + @param ticks - the maximum amount of time to block + @return (bool) - true if the lock was obtained, false otherwise + */ + bool LockForReading(uint32_t ticks) const; + + /* + public LockForWriting + + Locks this read write lock for writing. Blocks until the lock is obtained. + + @param ticks - the maximum amount of time to block + @return (bool) - true if the lock was obtained, false otherwise + */ + bool LockForWriting(uint32_t ticks); + + /* + public EndReading + + Signals that a read operation has completed. + + @return (void) + */ + void EndReading() const; + + /* + public EndWriting + + Signals that a write operation has completed. + + @return (void) + */ + void EndWriting(); +}; + +#endif + diff --git a/Include/ZUtil/ZReferenceBuffer.hpp b/Include/ZUtil/ZReferenceBuffer.hpp new file mode 100644 index 0000000..b720f92 --- /dev/null +++ b/Include/ZUtil/ZReferenceBuffer.hpp @@ -0,0 +1,399 @@ +/* + ZReferenceBuffer.hpp + Author: James Russell + + Purpose : Acts as a means of storing arbitrary types of values in an array which gives back index-based references to + pointers of those types of values. Handles, internally, the Buffer overflowing and looping back around + the end of the storage array. + + Changelog : + 2/11/10 - Creation (jcr2) + 2/13/10 - Should be working as advertised (jcr) + 3/04/10 - NOW working as advertised (jcr) + +*/ + +#ifndef _ZREFERENCEBUFFER_H +#define _ZREFERENCEBUFFER_H + +#include +#include +#include +#include + +#define ZRB_DEFAULT_BUFFER_SIZE (10) +#define ZRB_INVALID_HANDLE (-1) + +typedef int ZReferenceBufferHandle; + +template +class ZReferenceBuffer +{ +protected: + //The Current Index Value (next value to be assigned) + int CurrentIndex; + + //The Current Size of the Buffer (Storage Capacity) + int BufferSize; + + //The Current Number of Items contained in the Buffer + int ItemCount; + + //Indicator array used to indicate which indices of the Buffer are valid + ZArray Indicator; + + //Buffer of T* Values + ZArray Buffer; + + //Checks if a given reference is valid + inline bool IsValid(int index); + + //Checks if a given reference is invalid + inline bool IsInvalid(int index); + + //Sets the Indicator of an index to valid + inline void SetValid(int index); + + //Sets the Indicator of an index to invalid + inline void SetInvalid(int index); + +public: + + /* + Default constructor. + */ + ZReferenceBuffer(); + + /* + Constructor. + + @param _size - The starting size of the reference buffer. + */ + ZReferenceBuffer(int _size); + + /* + Constructor. + + @param _allocator - the allocator to use for allocations / deallocations in the reference buffer + */ + ZReferenceBuffer(ZArrayAllocator *_allocator); + + /* + Constructor. + + @param _size - The starting size of the reference buffer. + @param _allocator - the allocator to use for allocations / deallocations in the reference buffer + */ + ZReferenceBuffer( int _size, ZArrayAllocator *_allocator); + + /* + Destructor. + */ + ~ZReferenceBuffer(); + + /* + public ZReferenceBuffer::AddItem + + Adds the item to the reference Buffer, returning a handle. Resizes the Buffer automatically to + increase the size of the buffer if full. + + @param _item - the item to add to the buffer + + @return (ZReferenceBufferHandle) - a ZReferenceBufferHandle which can be used to reference item, Will never return NULL. + */ + ZReferenceBufferHandle AddItem(T _item); + + /* + public ZReferenceBuffer::GetItem + + Gets an item in the Buffer given a reference handle. + + @param _ref - the reference handle to the item you wish to get + + @return (T&) - the item the handle refers to + */ + T& GetItem(ZReferenceBufferHandle _ref); + + /* + public ZReferenceBuffer::SetItem + + Attempts to set the reference to map to the provided item. Used for updating references. + + @param _ref - a valid reference handle to update. If NULL, will set the null handle, allowing a NULL reference to be valid. + @param _item - the item to update the reference to + + @return (T) - the overwritten value that ref pointed to + */ + T SetItem(ZReferenceBufferHandle _ref, T _item); + + /* + public ZReferenceBuffer::RemoveItem + + Removes an item from the Buffer given a reference handle and invalidates the handle (until reassigned). + + @param _ref - the reference handle to the item you wish to remove + + @return (T) - the item removed + */ + T RemoveItem(ZReferenceBufferHandle _ref); + + /* + public ZReferenceBuffer::Remove + + Removes all occurrences of an item from the Buffer given a pointer to the item. + + @param _item - the item you wish to remove + + @return (void) + */ + void Remove(T _item); + + /* + public ZReferenceBuffer::Size + + Gets the current size of the buffer. + + @return (int) - the size (capacity) of the buffer + */ + int Size(); + + /* + public ZReferenceBuffer::Count + + Returns the number of elements currently stored in the Buffer + + @return (int) - the count (number of items) in the buffer + */ + int Count(); + + /* + public ZReferenceBuffer::Items + + Returns a ZList containing the elements of the reference Buffer. + + @return (ZList) - a list containing all the values currently in the buffer + */ + ZList Items(); + + /* + inline public ZReferenceBuffer::IsFull + + Returns true if the Buffer is full, false otherwise. + + @return (bool) - boolean indicating the buffer is full + */ + inline bool IsFull(); + + /* + public ZReferenceBuffer::Resize + + Resizes the Buffer to store _newSize number of elements. Already existing references remain valid. Returns true + on success, false otherwise. Newsize must be greater than the current size of the reference Buffer. + + @param _newSize - the ZNew capacity of the buffer + + @return (bool) - boolean indicating success or failure + */ + bool Resize( int _newSize); +}; + +template +ZReferenceBuffer::ZReferenceBuffer( int _size, ZArrayAllocator* _allocator) +: CurrentIndex(1), BufferSize(_size+1), ItemCount(0), Allocator(_allocator) +{ + this->Buffer.Resize(BufferSize); + this->Indicator.Resize(this->BufferSize, false); +} + +template +ZReferenceBuffer::ZReferenceBuffer( int _size) +: CurrentIndex(1), BufferSize(_size+1), ItemCount(0) +{ + this->Buffer.Resize(BufferSize); + this->Indicator.Resize(this->BufferSize, false); +} + +template +ZReferenceBuffer::ZReferenceBuffer(ZArrayAllocator* _allocator) +: CurrentIndex(1), BufferSize(ZRB_DEFAULT_BUFFER_SIZE+1), ItemCount(0), Allocator(_allocator) +{ + this->Buffer.Resize(BufferSize); + this->Indicator.Resize(this->BufferSize, false); +} + +template +ZReferenceBuffer::ZReferenceBuffer() +: CurrentIndex(1), BufferSize(ZRB_DEFAULT_BUFFER_SIZE+1), ItemCount(0) +{ + this->Buffer.Resize(BufferSize); + this->Indicator.Resize(this->BufferSize, false); +} + +template +ZReferenceBuffer::~ZReferenceBuffer() +{ +} + +template +bool ZReferenceBuffer::IsValid(int _index) +{ + if (_index >= 0) + return this->Indicator[_index] != 0; + + return false; +} + +template +bool ZReferenceBuffer::IsInvalid(int _index) +{ + return !IsValid(_index); +} + +template +void ZReferenceBuffer::SetValid( int _index) +{ + this->Indicator[_index] = 1; +} + +template +void ZReferenceBuffer::SetInvalid( int _index) +{ + this->Indicator[_index] = 0; +} + +template +ZReferenceBufferHandle ZReferenceBuffer::AddItem(T _item) +{ + int startIndex; + int ref; + + //CurrentIndex should only be zero if Buffer is full + if (this->CurrentIndex == 0) + return this->CurrentIndex; + + ref = startIndex = this->CurrentIndex; + + while (this->IsValid(this->CurrentIndex)) + { + this->CurrentIndex++; + ref = this->CurrentIndex; + + if (this->CurrentIndex == startIndex) + this->Resize(this->BufferSize * 2); + + if (this->CurrentIndex >= this->BufferSize) + ref = this->CurrentIndex = 1; + } + + if (ref != -1) + { + this->Buffer[ref] = _item; + this->SetValid(ref); + + this->ItemCount++; + } + + return ref; +} + +template +T& ZReferenceBuffer::GetItem(ZReferenceBufferHandle _ref) +{ + ZASSERT(this->IsValid(_ref), "ERROR: ZReferenceBuffer::GetItemRef passed invalid reference!"); + + return this->Buffer[_ref]; +} + +template +T ZReferenceBuffer::RemoveItem(ZReferenceBufferHandle _ref) +{ + T item; + + ZASSERT( this->IsValid(_ref) , "ERROR: ZReferenceBuffer::RemoveItem passed invalid reference!" ); + + this->ItemCount--; + this->SetInvalid(_ref); + item = this->Buffer[_ref]; + + return item; +} + +template +void ZReferenceBuffer::Remove(T _item) +{ + for ( int i = 0; i < this->BufferSize; i++) + if (this->Buffer[i] == _item) + this->RemoveItem(i); +} + +template +T ZReferenceBuffer::SetItem(int _ref, T _item) +{ + T ret; + + ret = this->Buffer[_ref]; + this->Buffer[_ref] = _item; + + this->SetValid(_ref); + + this->ItemCount++; + + return ret; +} + +template + int ZReferenceBuffer::Size() +{ + return this->BufferSize; +} + +template + int ZReferenceBuffer::Count() +{ + return this->ItemCount; +} + +template +bool ZReferenceBuffer::IsFull() +{ + return (!this->CurrentIndex); +} + +template +bool ZReferenceBuffer::Resize( int _newSize) +{ + if (_newSize < this->BufferSize) + return false; + + this->BufferSize = _newSize + 1; + + ZArray newBuffer; + newBuffer.Resize(this->BufferSize); + + for ( int i = 0; i < this->BufferSize; i++) + newBuffer[i] = this->Buffer[i]; + + this->Indicator.Resize(this->BufferSize, false); + + this->Buffer = newBuffer; + + return true; +} + +template +ZList ZReferenceBuffer::Items() +{ + int i; + ZList items; + + for (i = 1; i < this->BufferSize; i++) + { + if (this->IsValid(i)) + items.PushBack(this->Buffer[i]); + } + + return items; +} + +#endif + diff --git a/Include/ZUtil/ZReferenceCounter.hpp b/Include/ZUtil/ZReferenceCounter.hpp new file mode 100644 index 0000000..721b7a7 --- /dev/null +++ b/Include/ZUtil/ZReferenceCounter.hpp @@ -0,0 +1,243 @@ +/* + ZReferenceCounter.hpp + Author: James Russell + Created: 3/22/2012 + + Purpose: + + Defines a structure that is usually allocated on the heap and will maintain a strong + reference count, a weak reference count, and an integer flag used to signal state. This + reference counter is designed to be thread safe by using atomic operations. + + License: + + TODO + +*/ + +#pragma once + +#ifndef _ZREFERENCECOUNTER_HPP +#define _ZREFERENCECOUNTER_HPP + +#include + +#include +#include +#include + +//The leading (negative) bit is used to indicate deallocation on the State int +#define ZREFCOUNTER_DEALLOC_BIT (0x80000000) + +/* + ZReferenceCounter::CombinedCount is a 32-bit integer value containing + 2x16-bit integer values -- the strong and weak reference counts. They + are stored as 0xWWWWSSSS, i.e. upper 16 bits are the weak reference + count, and the lower 16 bits are the strong reference count. + + Do realize that this limits us to 65565 strong and 65565 weak references + without error conditions. We find this to be an acceptable limit. +*/ + +//These define how much to shift by to affect the strong/weak counters +#define ZREFCOUNTER_STRONG_SHIFT (0) +#define ZREFCOUNTER_WEAK_SHIFT (16) + +//These masks are what we will use to mask the upper half (weak) and lower half (strong) parts +//of the integer reference count +#define ZREFCOUNTER_STRONG_MASK (0xFFFF << ZREFCOUNTER_STRONG_SHIFT) +#define ZREFCOUNTER_WEAK_MASK (0xFFFF << ZREFCOUNTER_WEAK_SHIFT) + +//These values are used to add a single weak reference or a single strong reference to the +//reference count +#define ZREFCOUNTER_STRONG_REF (1 << ZREFCOUNTER_STRONG_SHIFT) +#define ZREFCOUNTER_WEAK_REF (1 << ZREFCOUNTER_WEAK_SHIFT) + +//These macros extract the strong/weak reference counts respectively from the combined counts +#define ZREFCOUNTER_EXTRACT_STRONG_REF(x) (((x) >> ZREFCOUNTER_STRONG_SHIFT) & 0xFFFF) +#define ZREFCOUNTER_EXTRACT_WEAK_REF(x) (((x) >> ZREFCOUNTER_WEAK_SHIFT) & 0xFFFF) + +/* +Reference counting struct. Keeps a reference count to an +object (both strong and weak), and a state signaling integer. +*/ +struct ZReferenceCounter +{ + /* + Integer we use for keeping track of strong and weak references within the + space of a single native integer. The upper half is used to determine + weak count. The lower half is used to determine strong count. This allows + us to use atomic operations on both the strong reference count and weak + reference count on architectures that do not have a DoubleCAS operation. + + Must be unsigned so >> doesn't do arthimetic shift. + */ + volatile uint32_t CombinedCount; + + /* + Flag used for signaling object usage state + + > 0 - in use (number of users) + 0 - not in use + < 0 - ready for deallocation (discounting deallocation bit gives number of users) + */ + volatile int State; + + /* + Default constructor. + */ + ZReferenceCounter() + : CombinedCount(0), State(0) { } + + /* + Destructor. + */ + ~ZReferenceCounter() + { } + + /* + Using atomic operations, will increment the strong reference count. + */ + inline void GainStrongRef() + { + SST_Atomic_Add((volatile int*)&CombinedCount, ZREFCOUNTER_STRONG_REF); + } + + /* + Using atomic operations, will increment the weak reference count. + */ + inline void GainWeakRef() + { + SST_Atomic_Add((volatile int*)&CombinedCount, ZREFCOUNTER_WEAK_REF); + } + + /* + Gets the current strong reference count. + */ + inline uint32_t GetStrongRefCount() + { + return ZREFCOUNTER_EXTRACT_STRONG_REF(CombinedCount); + } + + /* + Gets the current weak reference count. + */ + inline uint32_t GetWeakRefCount() + { + return ZREFCOUNTER_EXTRACT_WEAK_REF(CombinedCount); + } + + /* + Using atomic operations, will decrement the strong reference count and + return the number of remaining references, both strong and weak, as part + of the same value. + + To get the strong reference count, use ZREFCOUNTER_EXTRACT_STRONG_REF() on the return value. + + To get the weak reference count, use ZREFCOUNTER_EXTRACT_WEAK_REF() on the return value. + */ + inline uint32_t LoseStrongRef() + { + return SST_Atomic_AddReturn((volatile int*)&CombinedCount, -ZREFCOUNTER_STRONG_REF); + } + + /* + Using atomic operations, will decrement the weak reference count and + return the number of remaining references, both strong and weak, as part + of the same value. + + To get the strong reference count, use ZREFCOUNTER_EXTRACT_STRONG_REF() on the return value. + + To get the weak reference count, use ZREFCOUNTER_EXTRACT_WEAK_REF() on the return value. + */ + inline uint32_t LoseWeakRef() + { + return SST_Atomic_AddReturn((volatile int*)&CombinedCount, -ZREFCOUNTER_WEAK_REF); + } + + /* + Using atomic operations, will set the state flag as 'deallocated' as soon as possible, + which will ensure anyone using 'SignalInUse' will get a 'false' return value. + */ + inline void SignalDeallocateObject() + { + //Check deallocated + if (State & ZREFCOUNTER_DEALLOC_BIT) + return; + + //Set high bit + SST_Atomic_Or(&State, ZREFCOUNTER_DEALLOC_BIT); + + //Wait logic + while ((State & ~ZREFCOUNTER_DEALLOC_BIT) != 0) + continue; + + //State is guaranteed here to be == ZREFCOUNTER_DEALLOC_BIT + } + + /* + Using atomic operations, will set the state flag as 'in use'. If unable to set + state flag as 'in use' because the object is deallocated, will return false. + + This is important to weak reference holders to signal to strong reference holders that + the object should not be deallocated until the object is no longer in use. + */ + inline bool SignalInUse() + { + //Check deallocated + if (State & ZREFCOUNTER_DEALLOC_BIT) + return false; + + int val = SST_Atomic_IncReturn(&State); + + if (val & ZREFCOUNTER_DEALLOC_BIT) + { + SST_Atomic_Dec(&State); //Atomic decrement to ensure we don't starve the waiting deallocation thread + return false; + } + else + return true; + } + + /* + Using atomic operations, will set the state flag as 'no longer in use'. + */ + inline void SignalUnused() + { + SST_Atomic_Dec(&State); + } +}; + +/* +Allocator class for ZReferenceCounter. Responsible for heap allocation and deletion of +ZReferenceCounter instances. +*/ +class ZReferenceCounterAllocator +{ +public: + /* + public ZSmartPointerAllocator::AllocateCounter + + Allocation method that allocates a reference counter for use by the smart pointer. + + @return (ZSmartPointerRefCounter*) + */ + ZReferenceCounter* AllocateCounter() + { + return znew ZReferenceCounter(); + } + + /* + public ZSmartPointerAllocator::DeallocateCounter + + Deallocates a reference counter that was provided by AllocateCounter. + + @param _counter - the counter to deallocate + */ + void DeallocateCounter(ZReferenceCounter* _counter) + { + zdelete _counter; + } +}; + +#endif diff --git a/Include/ZUtil/ZRegistry.hpp b/Include/ZUtil/ZRegistry.hpp new file mode 100644 index 0000000..6407061 --- /dev/null +++ b/Include/ZUtil/ZRegistry.hpp @@ -0,0 +1,145 @@ +/* + ZRegistry.hpp + Author: James Russell + Created: 2/18/2013 + + Purpose: + + ZRegistry defines a use case for ZKVTree as a concurrent data store. A ZRegistry + maps keys to values using path strings, just as ZKVTree does, but the path string + must be unique as subscripts are not supported and siblings with the same name + are not supported. + + ZRegistry is thread-safe on all operations. + + ZRegistry (currently) supports only string value types, but the return value struct + from 'Get' can be converted to integer and double types with the Convert() function. + + License: + + TODO + +*/ + +#pragma once + +#ifndef _ZREGISTRY_HPP +#define _ZREGISTRY_HPP + +#include +#include + +class ZRegistry +{ +public: + /* + Default Constructor. + */ + ZRegistry(); + + /* + Constructs this registry from a KVTree. + */ + ZRegistry(const ZKVTree& _tree); + + /* + Destructor. + */ + ~ZRegistry(); + + /* + ZRegistry value type, which will evaluate to true if the value was found + and false otherwise. + */ + class Value + { + friend class ZRegistry; + public: + /* + Operator overload used to get the value. + */ + operator ZString () const + { return Val; } + + /* + Function used to verify validity of the returned value. + */ + bool Valid() const + { return bValid; } + + /* + Function used to get the string value. + */ + const ZString& GetString() const + { return Val; } + + int GetInt() const + { return ZStringAlgo::NumericInt(Val); } + + double GetDouble() const + { return ZStringAlgo::NumericDouble(Val); } + + private: + /* + Constructor, which initializes the reference and the flag indicating + whether or not this is a valid value. + */ + Value(const ZString& _val, bool _valid) + : Val(_val), bValid(_valid) { } + + ZString Val; //Value copy (cannot maintain reference into data structure) + bool bValid; //Validity flag + }; + + /* + public ZRegistry::operator [] + + [] operator overload, equivalent to Get(_key). + + @param _key - the key to look up + @return (const ZString&) - the value looked up + */ + const Value operator [] (const ZString& _key) const + { return Get(_key); } + + /* + public ZRegistry::Erase + + Erases a key/value pair (and all child key/value pairs) from the registry. + + @param _key - the key to erase + @return (void) + */ + void Erase(const ZString& _key); + + /* + public ZRegistry::Get + + Returns the value instance bound to the given key. + + @param _key - the key to evaluate + @return (Value) - value instance for this key + */ + const Value Get(const ZString& _key) const; + + /* + public ZRegistry::Put + + Places a key / value pair into the registry. Will create any necessary nodes + to place the key and value pair. + + @param _key - the key to map + @param _value - the value to map to the key + @return (bool) - true if able to map the key/value, false otherwise + */ + bool Put(const ZString& _key, const ZString& _value); + +private: + DISABLE_COPY_AND_ASSIGN(ZRegistry); + + ZReadWriteLock Lock; //The concurrency read write lock + ZKVTree Tree; //The tree we store out data in +}; + +#endif + diff --git a/Include/ZUtil/ZSemaphore.hpp b/Include/ZUtil/ZSemaphore.hpp new file mode 100644 index 0000000..cd801b3 --- /dev/null +++ b/Include/ZUtil/ZSemaphore.hpp @@ -0,0 +1,89 @@ +/* + ZSema.hpp + Author: James Russell + + Purpose: RAII wrapper for libsst-concurrency SST_Semaphore. + + Changelog + 2011/11/27 - creation (jcrussell) +*/ + +#pragma once + +#ifndef _ZSEMAPHORE_H +#define _ZSEMAPHORE_H + +#include + +#include + +/* +ZSemaphore class. Used to allocate and deallocate a semaphore within the scope of a class. +Cannot be copied or assigned, which prevents it from being used in stl-like containers. +*/ +class ZSemaphore +{ +private: + DISABLE_COPY_AND_ASSIGN(ZSemaphore); + + //libsst Semaphore + SST_Semaphore Semaphore; + +public: + /* + Constructor. + + @param _initialCount - initial count of the semaphore + */ + ZSemaphore(int _initialCount); + + /* + Destructor. + */ + ~ZSemaphore(); + + /* + public ZSema::Post + + TODO + + @return (void) + @context (all) + */ + void Post(); + + /* + public ZSema::Post + + TODO + + @param _count - + @return (void) + @context (all) + */ + void Post(uint32_t _count); + + /* + public ZSema::Wait + + TODO + + @return (bool) + @context (all) + */ + bool Wait(); + + /* + public ZSema::Wait + + TODO + + @param _ms - + @return (bool) + @context (all) + */ + bool Wait(uint32_t _ms); +}; + +#endif + diff --git a/Include/ZUtil/ZSimplexNoise.hpp b/Include/ZUtil/ZSimplexNoise.hpp new file mode 100644 index 0000000..aec2db2 --- /dev/null +++ b/Include/ZUtil/ZSimplexNoise.hpp @@ -0,0 +1,41 @@ +/* + ZSimplexNoise.hpp + Author : Chris Ertel + + Purpose : Math namespace for the ZEngine which will contain functions for mathematical operations on primitives + and arrays of primitives. + + Changelog + 2/13/11 - Creation (crertel) +*/ + +#pragma once + +#ifndef _ZSIMPLEXNOISE_H +#define _ZSIMPLEXNOISE_H + +#include +#include + +class ZSimplexNoise : public ZNoise +{ +protected: + SST_SimplexNoise simplexGenerator; + +public: + ZSimplexNoise(); + virtual ~ZSimplexNoise() {} + + //Subclass implementation + void reseed(const int _seed); + //Subclass implementation + float noise1(const float _x); + //Subclass implementation + float noise2(const float _x, const float _y); + //Subclass implementation + float noise3(const float _x, const float _y, const float _z); + //Subclass implementation + float noise4(const float _x, const float _y, const float _z, const float _w); +}; + +#endif diff --git a/Include/ZUtil/ZSimplexNoiseMap.hpp b/Include/ZUtil/ZSimplexNoiseMap.hpp new file mode 100644 index 0000000..747afd5 --- /dev/null +++ b/Include/ZUtil/ZSimplexNoiseMap.hpp @@ -0,0 +1,261 @@ +/* + ZSimplexNoiseMap.hpp + Author : Chris Ertel + + Purpose : Interface to create a map for simplex noise values. + + Changelog + 2/20/11 - Creation (crertel) +*/ + +#pragma once + +#ifndef _ZSIMPLEXNOISEMAP_H +#define _ZSIMPLEXNOISEMAP_H + +#include +#include +#include + +class ZSimplexNoiseMap : public ZNoiseMap +{ +protected: + ZSimplexNoise noiseGen; + float lacunarity; + float persistence; + int numberofoctaves; + float* values; + +public: + + ZSimplexNoiseMap() + : lacunarity(.5), persistence(.5), numberofoctaves(8), values(NULL) + { + } + + virtual ~ZSimplexNoiseMap() + { + } + + virtual int GetDimensionality() = 0; + + //Subclass implementation + float GetLacunarity() { return this->lacunarity; } + + //Subclass implementation + float GetPersistence() { return this->persistence; } + + //Subclass implementation + int GetNumberOfOctaves() { return this->numberofoctaves; } + + //Not implemented + virtual int GetNumberSamplesInX() = 0; + //Not implemented + virtual int GetNumberSamplesInY() = 0; + //Not implemented + virtual int GetNumberSamplesInZ() = 0; + //Not implemented + virtual int GetNumberSamplesInW() = 0; + + /* + public ZSimplexNoiseMap::GetSamples + + Function to get array of values for noise map. + + @return (float*) - array of values + */ + float* GetSamples() { return this->values; } + + //Subclass implementation + void SetLacunarity(float _lac) { this->lacunarity = _lac; } // scaling of successive frequencies in noise octaves + //Subclass implementation + void SetPersistence(float _per) { this->persistence = _per; } // scaling of successive amplitudes in noise octaves + //Subclass implementation + void SetNumberOfOctaves(int _numOctaves ) { this->numberofoctaves = _numOctaves; } + + //Not implemented + virtual void SetNumberSamplesInX(int _numSamples) = 0; + //Not implemented + virtual void SetNumberSamplesInY(int _numSamples) = 0; + //Not implemented + virtual void SetNumberSamplesInZ(int _numSamples) = 0; + //Not implemented + virtual void SetNumberSamplesInW(int _numSamples) = 0; + + //Not implemented + virtual bool Generate(int _seed) = 0; + //Not implemented + virtual void Cleanup() = 0; +}; + +class ZSimplexNoiseMap2D : public ZSimplexNoiseMap +{ +protected: + int numberSamplesInX; + int numberSamplesInY; + +public: + ZSimplexNoiseMap2D() + : ZSimplexNoiseMap(), numberSamplesInX(0), numberSamplesInY(0) + { + } + + ~ZSimplexNoiseMap2D() + { + this->Cleanup(); + } + + //Subclass implementation + int GetDimensionality() { return 2; } + //Subclass implementation + int GetNumberSamplesInX() { return this->numberSamplesInX; } + //Subclass implementation + int GetNumberSamplesInY() { return this->numberSamplesInY; } + //Subclass implementation + int GetNumberSamplesInZ() { return 0; } + //Subclass implementation + int GetNumberSamplesInW() { return 0; } + + //Subclass implementation + void SetNumberSamplesInX(int _numSamples) { this->numberSamplesInX = _numSamples; } + //Subclass implementation + void SetNumberSamplesInY(int _numSamples) { this->numberSamplesInY = _numSamples; } + //Subclass implementation + void SetNumberSamplesInZ(int _numSamples) { URFP ( _numSamples) ; } + //Subclass implementation + void SetNumberSamplesInW(int _numSamples) { URFP ( _numSamples) ; } + + /* + public ZSimplexNoiseMap2D::getValue + + Gets value at a particular point on the noise map. + + @param _x - x-coordinate to sample + @param _y - y-coordinate to sample + @return (double) - value at point (x,y) + */ + float getValue(int _x, int _y); + + //Subclass implementation + bool Generate(int _seed = 0); + //Subclass implementation + void Cleanup(); +}; + +class ZSimplexNoiseMap3D : public ZSimplexNoiseMap +{ +protected: + int numberSamplesInX; + int numberSamplesInY; + int numberSamplesInZ; + +public: + ZSimplexNoiseMap3D() + : ZSimplexNoiseMap(), numberSamplesInX(0), numberSamplesInY(0), numberSamplesInZ(0) + { + } + + ~ZSimplexNoiseMap3D() + { + this->Cleanup(); + } + + //Subclass implementation + int GetDimensionality() { return 3; } + //Subclass implementation + int GetNumberSamplesInX() { return this->numberSamplesInX; } + //Subclass implementation + int GetNumberSamplesInY() { return this->numberSamplesInY; } + //Subclass implementation + int GetNumberSamplesInZ() { return this->numberSamplesInZ; } + //Subclass implementation + int GetNumberSamplesInW() { return 0; } + + //Subclass implementation + void SetNumberSamplesInX(int _numSamples) { this->numberSamplesInX = _numSamples; } + //Subclass implementation + void SetNumberSamplesInY(int _numSamples) { this->numberSamplesInY = _numSamples; } + //Subclass implementation + void SetNumberSamplesInZ(int _numSamples) { this->numberSamplesInZ = _numSamples; } + //Subclass implementation + void SetNumberSamplesInW(int _numSamples) { URFP ( _numSamples) ; } + + /* + public ZSimplexNoiseMap3D::getValue + + Gets value at a particular point on the noise map. + + @param _x - x-coordinate to sample + @param _y - y-coordinate to sample + @param _z - z-coordinate to sample + @return (float) - value at point in noise map. + */ + float getValue(int _x, int _y, int _z); + + //Subclass implementation + bool Generate(int _seed = 0); + //Subclass implementation + void Cleanup(); +}; + +class ZSimplexNoiseMap4D : public ZSimplexNoiseMap +{ +protected: + int numberSamplesInX; + int numberSamplesInY; + int numberSamplesInZ; + int numberSamplesInW; + +public: + ZSimplexNoiseMap4D() + : ZSimplexNoiseMap(), numberSamplesInX(0), numberSamplesInY(0), numberSamplesInZ(0), + numberSamplesInW(0) + { + } + + ~ZSimplexNoiseMap4D() + { + this->Cleanup(); + } + + //Subclass implementation + int GetDimensionality() { return 4; } + //Subclass implementation + int GetNumberSamplesInX() { return this->numberSamplesInX; } + //Subclass implementation + int GetNumberSamplesInY() { return this->numberSamplesInY; } + //Subclass implementation + int GetNumberSamplesInZ() { return this->numberSamplesInZ; } + //Subclass implementation + int GetNumberSamplesInW() { return this->numberSamplesInW; } + + //Subclass implementation + void SetNumberSamplesInX(int _numSamples) { this->numberSamplesInX = _numSamples; } + //Subclass implementation + void SetNumberSamplesInY(int _numSamples) { this->numberSamplesInY = _numSamples; } + //Subclass implementation + void SetNumberSamplesInZ(int _numSamples) { this->numberSamplesInZ = _numSamples; } + //Subclass implementation + void SetNumberSamplesInW(int _numSamples) { this->numberSamplesInW = _numSamples; } + + /* + public ZSimplexNoiseMap4D::getValue + + Gets value at a particular point on the noise map. + + @param _x - x-coordinate to sample + @param _y - y-coordinate to sample + @param _z - z-coordinate to sample + @param _w - w-coordinate to sample + @return (float) - value at point in noise map. + */ + float getValue(int _x, int _y, int _z, int _w); + + //Subclass implementation + bool Generate(int _seed = 0); + //Subclass implementation + void Cleanup(); +}; + +#endif + diff --git a/Include/ZUtil/ZSlabAllocator.hpp b/Include/ZUtil/ZSlabAllocator.hpp new file mode 100644 index 0000000..f9eb7f3 --- /dev/null +++ b/Include/ZUtil/ZSlabAllocator.hpp @@ -0,0 +1,237 @@ +/* + ZSlabAllocator.hpp + Author: James Russell + Created: 9/12/2011 + + Purpose: + + Used to pre-allocate a large pool of objects whose size is fixed. These objects can + then be allocated and deallocated as needed, which will return a pointer to an already + allocated member. + + Will correctly handle allocation of more objects than is allocated at compile time, but + performance will be impacted as another slab of equivalent size to the original is + allocated. + + This is not a multithreaded access allocator. The user of this is required to provide + their own thread safety mechanisms. + + License: + + TODO +*/ + +#pragma once + +#ifndef _ZSLABALLOCATOR_H +#define _ZSLABALLOCATOR_H + +#include +#include +#include +#include + +/* +Slab Allocator, which holds a contiguous array of objects and leases them out for use. + +The template parameter T is the type of object to hold. + +The template parameter N is the size of the slab (how many objects to allocate statically). +*/ +template +class ZSlabAllocator +{ +private: + DISABLE_COPY_AND_ASSIGN(ZSlabAllocator); + +protected: + + /* + Allocated slab of objects, that links to the next + slab of objects. + */ + class Slab + { + private: + T Pool[N]; //The object pool + T* Handles[N]; //Handles to objects in the object pool + size_t HandleIndex; //Handle index to the next available handle + Slab* NextPool; //Next pool + + public: + Slab() : + HandleIndex(0), NextPool(NULL) + { + //Populate our handles pool + for (size_t i = 0; i < N; i++) + Handles[i] = &(Pool[i]); + } + + //Used to verify that a handle belongs to the pool of objects + bool IsPoolMember(T* _handle) + { + uintptr_t handle = (uintptr_t) _handle; + uintptr_t poolLower = (uintptr_t) &Pool[0]; + uintptr_t poolUpper = (uintptr_t) &Pool[N - 1]; + + if ((handle >= poolLower) && (handle <= poolUpper)) //Checks to see if handle is within the range of the pool + if (((handle - poolLower) % sizeof(T)) == 0) //Checks to see if handle is aligned on an object in the pool + return true; + + return false; + } + + T* Allocate() + { + T* object = NULL; + + if (HandleIndex < N) + { + //Grab an object from the object pool + object = Handles[HandleIndex++]; + } + return object; + } + + void Deallocate(T* object) + { + Handles[--HandleIndex] = object; + } + + Slab* GetNextPool() { return NextPool; } + void SetNextPool(Slab* p) { NextPool = p; } + + }; + + //ZSlabAllocator members + Slab FirstPool; + size_t NrAllocated; + size_t NrSlabs; + +public: + /* + Default Constructor. + */ + ZSlabAllocator() : + NrAllocated(0), NrSlabs(1) + { + } + + /* + Destructor. + */ + ~ZSlabAllocator() + { + Slab* slab = FirstPool.GetNextPool(); + + while(slab) + { + Slab* next = slab->GetNextPool(); + + zdelete slab; + slab = next; + } + } + + /* + public ZSlabAllocator::Allocate + + Gets a valid object of type T and returns a pointer. + + @return (T*) - a valid object pointer of type T + */ + T* Allocate() + { + T* object = NULL; + + Slab* slab = &FirstPool; //Begin with first pool + + while(object == NULL) + { + //Any objects left in this pool? + object = slab->Allocate(); + if(object == NULL) + { + //Doh, try next pool + Slab* next = slab->GetNextPool(); + + //Unless there is no next pool... + if(next == NULL) + { + //Try to allocate another one + Slab* newPool = znew Slab; + if(newPool == NULL) + return NULL; //Doh, out of memory. :( + else + NrSlabs++; + + //Save this pool + slab->SetNextPool(newPool); + next = newPool; + } + + //Try next pool + slab = next; + } + else + NrAllocated++; + } + + return object; + } + + /* + public ZSlabAllocator::Capacity + + Gets the size of the object pool. Returns the total capacity of the pool. + + @return (size_t) - the capacity of the object pool + */ + size_t Capacity() const + { + return NrSlabs * N; + } + + /* + public ZSlabAllocator::Count + + Gets the number of objects contained by the object pool. + + @return (size_t) - the number of objects contained by this pool + */ + size_t Available() const + { + return NrSlabs * N - NrAllocated; + } + + size_t Allocated() const + { + return NrAllocated; + } + + /* + public ZSlabAllocator::Deallocate + + Allocates an object from the slab. + + @param _object - a valid object pointer of type T gained through 'Allocate' + @return (void) + */ + void Deallocate(T *_object) + { + for(Slab* slab = &FirstPool; slab != NULL; slab = slab->GetNextPool()) + { + if(slab->IsPoolMember(_object)) + { + NrAllocated--; + slab->Deallocate(_object); + return; + } + } + + ZASSERT_RUNTIME_FAIL("ZSlabAllocator: Object deallocated that was not allocated here!"); + } + +}; + +#endif diff --git a/Include/ZUtil/ZSmartPointer.hpp b/Include/ZUtil/ZSmartPointer.hpp new file mode 100644 index 0000000..5849238 --- /dev/null +++ b/Include/ZUtil/ZSmartPointer.hpp @@ -0,0 +1,944 @@ +/* + ZSmartPointer.hpp + Author: James Russell + Created: 08/12/2011 + + Purpose: + + Smart pointer implementation for the ZEngine. Frees up the programmer from having to + worry too hard about the minutiae of memory management for allocated objects. Not to + use on arrays; use ZArray for dynamic array management. + + Uses atomic operations to enable the smart pointer to work across threads. + + Don't pass these things around by pointer or reference unless you really know what you + are doing. You won't like the results. + + License: + + TODO + +*/ + +#pragma once + +#ifndef _ZSMARTPOINTER_H +#define _ZSMARTPOINTER_H + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +//Shorthand used for ZSmartPointer +#define ZPtr ZSmartPointer + +/* +Default deallocator functor for ZSmartPointer, which is responsible for deallocating +the managed object. This default version uses 'zdelete'. + +The template parameter T is the type of object pointed to by the smart pointer. + +The unary functor takes a single argument of type T*, which is the object to be deallocated. +*/ +template +struct ZSmartPointerDeallocator { + void operator () (T* _object) { + zdelete _object; + } +}; + +/* +NULL deallocator functor for ZSmartPointer, which doesn't actually deallocate anything. + +The template parameter T is the type of object pointed to by the smart pointer. + +The unary functor takes a single argument of type T*, which is destroyed. +*/ +template +struct ZSmartPointerNullDeallocator { + void operator() (T* _object) { + URFP(_object); + } +}; + +/* +Smart pointer class, used to share a references to an allocated object. This smart pointer +uses atomic operations to ensure that the reference count is maintained properly even when +the object is shared among threads. + +The template parameter T is the type of the object pointed to. + +The template parameter DF is the type of object deallocator functor to use. + +The template parameter R is the type of reference counter allocator to use. +*/ +template , typename R = ZReferenceCounterAllocator > +class ZSmartPointer +{ +protected: + //The pointed to object + T* Object; + + //Object Deallocator + DF ObjDeallocator; + + //Reference Counter Allocator + R RefAllocator; + + //Reference Counter for the pointer (also contains the pointer) + ZReferenceCounter* Ref; + + //Checks to see if we need a reference counter, allocates if so, and increments the strong + //reference count + inline void ReferenceGained() + { + if (Object == NULL) + return; + + if (Ref == NULL) + { + Ref = RefAllocator.AllocateCounter(); + + ZASSERT_RUNTIME(Ref != NULL, "ZSmartPointer: Reference counter allocator returned NULL!"); + } + + Ref->GainStrongRef(); + } + + //Checks to see if we can delete the reference and lowers the count + inline void ReferenceLost() + { + if (Ref == NULL) + { + ZASSERT_UTIL(Object == NULL, "ZSmartPointer: Reference lost with no reference counter, but object is still present!"); + return; + } + + ZASSERT_UTIL(Ref->GetStrongRefCount() > 0 && Object != NULL, "ZSmartPointer: Reference lost but object is already deallocated!"); + + uint32_t combinedCount = Ref->LoseStrongRef(); //Decrement our strong count and get the combined count + + //Check if we lost the last strong ref + if ((combinedCount & ZREFCOUNTER_STRONG_MASK) == 0) //Note we don't use the EXTRACT_STRONG_REF() since 0 bitshifted is still 0 + { + Ref->SignalDeallocateObject(); //Signal object deallocation + + ObjDeallocator(Object); //Deallocate the object + + //Check if we lost the last weak reference + if ((combinedCount & ZREFCOUNTER_WEAK_MASK) == 0) //Note we don't use the EXTRACT_WEAK_REF() since 0 bitshifted is still 0 + { + RefAllocator.DeallocateCounter(Ref); //Deallocate the counter + } + } + + //We lost our reference, so we don't need these + Object = NULL; + Ref = NULL; + } + +public: + /* + Default constructor. Sets the reference to NULL and does not allocate a reference + counter. + */ + ZSmartPointer() + : Object(NULL), Ref(NULL) + { } + + /* + Constructor. Explicit to ensure we don't accidentally take ownership of + a pointer. Allocates a reference counter from the reference counter allocator. + + @param _ptr - pointer to be managed + */ + explicit ZSmartPointer(T* _ptr) + : Object(_ptr), Ref(NULL) + { + ReferenceGained(); + } + + /* + Copy constructor. + + @param _other - the other smart pointer + */ + ZSmartPointer(const ZSmartPointer& _other) + : Object(_other.Pointer()), Ref(_other.Counter()) + { + ZASSERT_UTIL(!(Object != NULL && Ref == NULL), "ZSmartPointer: Copy constructor called from smart pointer with invalid reference counter!"); + + ReferenceGained(); + } + + /* + Conversion constructor. Used to auto up-cast derived classes or other + classes that can be converted. + + @param D - the typename of the derived class + @param EF - the deallocator functor type of the other class + @param S - the reference counter allocator type of the other class + @param _other - the other smart pointer + */ + template + ZSmartPointer(const ZSmartPointer& _other) + : Object(static_cast(_other.Pointer())), Ref(_other.Counter()) + { + ZASSERT_UTIL(!(Object != NULL && Ref == NULL), "ZSmartPointer: Copy constructor called from smart pointer with invalid reference counter!"); + + ReferenceGained(); + } + + /* + Destructor. Causes a strong reference to be lost. + */ + ~ZSmartPointer() + { + ReferenceLost(); + } + + /* + = operator overload. Sets this smart pointer to be the owner of the provided pointer, + which may require allocation of a reference counter. + + @param _ptr - the pointer to the object to own + @return (ZSmartPointer&) - this smart pointer + */ + ZSmartPointer& operator = (T* _ptr) + { + if (Object == _ptr) + return *this; + + if (_ptr == NULL) + { + ReferenceLost(); //Ditch our reference + + Object = NULL; //Nullify our object pointer + Ref = NULL; //Nullify our counter + } + else + { + if (Object != NULL) + ReferenceLost(); //Lose our reference to the valid object + + Object = _ptr; //Own it + Ref = NULL; //Make sure Ref is set to NULL + + ReferenceGained(); //Create a new reference counter + + } + + return *this; + } + + /* + = operator overload. Sets this smart pointer to provide a strong reference to the same object + managed by the other smart pointer. + + @param _other - the other smart pointer + @return (ZSmartPointer&) - this smart pointer + */ + ZSmartPointer& operator = (const ZSmartPointer& _other) + { + if (*this == _other || Ref == _other.Counter()) + return *this; + + ReferenceLost(); //Lose a reference to our current object + + Object = _other.Pointer(); //Own the new one + Ref = _other.Counter(); //Get our new reference counter + + ReferenceGained(); //Increment the reference + + + return *this; + } + + /* + = operator overload. Used to assign to derived classes and classes that can + be converted to T. + + @param D - the type held by the other smart pointer + @param EF - the deallocator type of the other smart pointer + @param S - the reference counter allocator type of the other smart pointer + @param _other - the other smart pointer + @return (ZSmartPointer&) - this smart pointer + */ + template + ZSmartPointer& operator = (const ZSmartPointer& _other) + { + T* testCast = static_cast(_other.Pointer()); ((void)testCast); //This will fail to compile if T* cannot static cast to D* + + return *this = static_cast< ZSmartPointer >(_other); + } + + /* + == operator overload. Checks to see if this smart pointer owns the provided raw pointer. + + @param _ptr - the pointer to check + @return (bool) - true if the pointer is managed by this smart pointer, false otherwise + */ + bool operator == (const T* _ptr) const + { + return Object == _ptr; + } + + /* + == operator overload. Checks to see if these pointers reference the same object. + + @param _other - the other smart pointer + @return (bool) - true if equal, false otherwise + */ + bool operator == (const ZSmartPointer& _other) const + { + return Object == _other.Object; + } + + /* + == operator overload. Used to compare with smart pointers referencing derived + classes or a class that can be converted to T. + + @param _other - the other smart pointer + @return (bool) - true if equal, false otherwise + */ + template + bool operator == (const ZSmartPointer& _other) const + { + return Object == static_cast( _other.Pointer()); + } + + /* + != operator overload. Checks to see if this smart pointer does not + own the provided raw pointer. + + @param _ptr - the pointer to check + @return (bool) - true if this smart pointer does not reference the provided, false otherwise + */ + bool operator != (const T* _ptr) const + { + return !(*this == _ptr); + } + + /* + != operator overload. Checks to see if the smart pointers reference different objects. + + @param _other - the other smart pointer + @return (bool) - true if this smart pointer and the other do not reference the same object, false otherwise + */ + bool operator != (const ZSmartPointer& _other) const + { + return !(*this == _other); + } + + /* + != operator overload. Checks to see if these pointers reference different objects. Used + to compare with derived classes. + + @param D - the type contained by the other smart pointer + @param EF - the allocator used by the other smart pointer + @param S - the reference counter allocator type used by the other smart pointer + @param _other - the other smart pointer + @return (bool) - true if this smart pointer and the other do not reference the same object, false otherwise + */ + template + bool operator != (const ZSmartPointer& _other) const + { + return !(*this == _other); + } + + /* + -> operator overload. Allows this to be accessed as a T* would be. + + @return (T*) - raw pointer to the object + @assert - if the pointer is NULL + */ + T* operator -> () const + { + ZASSERT_RUNTIME(Object != NULL, "ZSmartPointer: Null Pointer Dereferenced!"); + + return Object; + } + + /* + '*' operator overload. Allows this to be dereferenced as a T* would be. + + @return (T&) - reference to the object + @assert - if the object is NULL + */ + T& operator * () const + { + ZASSERT_RUNTIME(Object != NULL, "ZSmartPointer: Null Pointer Dereferenced!"); + + return *Object; + } + + /* + public ZSmartPointer::CounterAllocator + + Gets the reference counter allocator for this smart pointer. + + @return (R&) - the reference counter allocator + */ + R& CounterAllocator() const + { + return RefAllocator; + } + + /* + public ZSmartPointer::Cast + + Used to cast this smart pointer into another type. This will construct an + additional smart pointer that also references the object. The owned + object must be convertible to type C* via static_cast. + + @param C - the type contained by the other type + @return (ZSmartPointer) - this smart pointer as another type + */ + template + ZSmartPointer Cast() + { + return static_cast< ZSmartPointer >(*this); + } + + /* + public ZSmartPointer::Counter + + Gets the ZRefrenceCounter instance used by this smart pointer. + + @return (ZReferenceCounter*)- ZRefCounter instance + */ + ZReferenceCounter* Counter() const + { + return Ref; + } + + /* + public ZSmartPointer::Deallocator + + Gets the object deallocator for this smart pointer. + + @return (DF&) - reference to the object deallocator + */ + DF& Deallocator() const + { + return ObjDeallocator; + } + + /* + public ZSmartPointer::Detach + + Detaches the pointer from memory management by the smart pointer. Should only be + called if there is a single strong reference to the object, otherwise it will return + NULL. Weak references will be nullified as if the object has been deallocated. + + @return (T*) - raw pointer detached from this smart pointer, or NULL if more + than one reference and unable to detach + */ + T* Detach() + { + if (Object == NULL || Ref == NULL || Ref->GetStrongRefCount() != 1) + return NULL; + else + { + uint32_t combinedCount = Ref->LoseStrongRef(); //Notify everyone we are losing this strong reference + + Ref->SignalDeallocateObject(); //Signal that we are deallocating the object + + if ((combinedCount & ZREFCOUNTER_WEAK_MASK) == 0) + RefAllocator.DeallocateCounter(Ref); //Deallocate our reference counter + + T* ptr; + + ptr = Object; //Detach the pointer + + Object = NULL; //Nullify our object reference + Ref = NULL; //Nullify our reference counter + + return ptr; + } + } + + /* + public ZSmartPointer::Pointer + + Gets the smart pointer as a raw pointer. Buyer beware. + + @return (T*) - raw pointer that this smart pointer manages + */ + T* Pointer() const + { + return Object; + } +}; + +//////////////////////////////////////// +/* ZArray Containment Specializations */ +//////////////////////////////////////// + +//Helper function used to nullify references in a range +template +void ZSmartPointerArrayNullify(ZSmartPointer* _array, size_t _start, size_t _end) +{ + for (size_t i = _start; i < _end; i++) + _array[i] = NULL; +} + +//Specialization for ZArray_ClearImpl containing ZSmartPointer +template +struct ZArray_ClearImpl< ZSmartPointer, A> { + + inline static void Call(ZArray, A>& _self) + { + //Nullify references + ZSmartPointerArrayNullify(_self.Array, 0, _self.ArraySize); + + //Reset size and check integrity + _self.ArraySize = 0; + _self.CheckIntegrity(); + } + + inline static void Call(ZArray, A>& _self, size_t _newCapacity) + { + //Nullify references + ZSmartPointerArrayNullify(_self.Array, 0, _self.ArraySize); + + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(_newCapacity > 0, "ZArray: Cannot set capacity to zero!"); + #endif + + //Reallocate if needed, drop our size to zero, and check integrity + if (_newCapacity > _self.ArrayCapacity) + { + _self.Deallocate(_self.Array, _self.ArrayCapacity); + _self.ArrayCapacity = _newCapacity; + _self.Allocate(_self.ArrayCapacity); + } + + _self.ArraySize = 0; + _self.CheckIntegrity(); + } + +}; + +//Specialization for ZArray_EraseImpl containing ZSmartPointer +template +struct ZArray_EraseImpl< ZSmartPointer, A> { + + inline static ZSmartPointer Call(ZArray, A>& _self, size_t _index) + { + size_t index = _self.BoundsCheck(_index, _self.ArraySize); + + //Grab the currently held element, shift the array down, reduce size, and check integrity + ZSmartPointer element = _self.Array[index]; + + for (size_t i = index; i + 1 < _self.ArraySize; i++) + _self.Array[i] = _self.Array[i + 1]; + + _self.ArraySize--; + _self.CheckIntegrity(); + + //Nullify reference + ZSmartPointerArrayNullify(_self.Array, _self.ArraySize, _self.ArraySize + 1); + + return element; + } + + inline static void Call(ZArray, A>& _self, const size_t _start, const size_t _end) + { + size_t start = _self.BoundsCheck(_start, _self.ArraySize); + size_t end = _self.BoundsCheck(_end, _self.ArraySize + 1); + + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(start <= end, "ZArray: cannot erase with start < end!"); + #endif + + //Copy the elements down, compute new size, and check integrity + for (size_t idx = start; idx + (end - start) < _self.ArraySize; idx++) + _self.Array[idx] = _self.Array[idx + (end - start)]; + + _self.ArraySize = _self.ArraySize - (end - start); + _self.CheckIntegrity(); + + //Nullify references (where we moved from) + ZSmartPointerArrayNullify(_self.Array, _self.ArraySize, _self.ArraySize + (end - start)); + } +}; + +//Specialization for ZArray_PopBackImpl containing ZSmartPointer +template +struct ZArray_PopBackImpl< ZSmartPointer, A> { + + inline static ZSmartPointer Call(ZArray, A>& _self) + { + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(_self.ArraySize > 0, "ZArray: Cannot pop from array with no elements!"); + #endif + + ZSmartPointer ptr = _self.Array[--(_self.ArraySize)]; + + //Nullify reference + ZSmartPointerArrayNullify(_self.Array, _self.ArraySize, _self.ArraySize + 1); + + //Grab the last element in the array and decrease our array size + return ptr; + } + +}; + +//Specialization for ZArray_PopFrontImpl containing ZSmartPointer +template +struct ZArray_PopFrontImpl< ZSmartPointer, A> { + + inline static ZSmartPointer Call(ZArray, A>& _self) + { + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(_self.ArraySize > 0, "ZArray: Cannot pop from array with no elements!"); + #endif + + //This will nullify the reference + return _self.Erase(0); + } + +}; + +//Specialization for ZArray_ResizeImpl containing ZSmartPointer +template +struct ZArray_ResizeImpl< ZSmartPointer, A> { + + inline static void Call(ZArray, A>& _self, const size_t _size) + { + //Nullify references if needed + if (_size < _self.ArraySize) + ZSmartPointerArrayNullify(_self.Array, _size, _self.ArraySize); + + //Check to see if we need more space, change our size, and check integrity + if (_size > _self.ArrayCapacity) + _self.Reserve(_size); + + _self.ArraySize = _size; + _self.CheckIntegrity(); + } + + inline static void Call(ZArray, A>& _self, const size_t _size, const ZSmartPointer& _value) + { + //Nullify references if needed + if (_size < _self.ArraySize) + ZSmartPointerArrayNullify(_self.Array, _size, _self.ArraySize); + + //See if we need more space, copy in the new value, change our size, and check integrity + if (_size > _self.ArrayCapacity) + _self.Reserve(_size); + + for (size_t i = _self.ArraySize; i < _size; i++) + _self.Array[i] = _value; + + _self.ArraySize = _size; + _self.CheckIntegrity(); + } + +}; + +/////////////////////////////////////// +/* ZList Containment Specializations */ +/////////////////////////////////////// + +//Specialization for ZList_ClearImpl containing ZSmartPointer +template +struct ZList_ClearImpl < ZSmartPointer, A> { + + inline static void Call(ZList, A>& _self, ZListIterator< ZSmartPointer >& _itr) { + + ZListNode >* next; + ZListNode >* current = _itr.GetNode(); + + _self.CheckIntegrity(); + + //Early out + if (_self.Empty()) + return; + + //If we are the starting node, be sure to reset the EmptyNode.Next pointer + if (current == _self.EmptyNode.Next) + _self.EmptyNode.Next = &_self.EmptyNode; + + //This is always true + _self.EmptyNode.Previous = current->Previous; + current->Previous->Next = &_self.EmptyNode; + + //Iterate and deallocate the nodes + while (current != &_self.EmptyNode) + { + next = current->Next; + current->Element = NULL; //This is the specialization + _self.DeallocateNode(current); + current = next; + } + + //Set the node on the iterator equal to the end node + _itr.SetNode(&_self.EmptyNode); + + _self.CheckIntegrity(); + } + +}; + +//Specialization for ZList_EraseImpl containing ZSmartPointer +template +struct ZList_EraseImpl < ZSmartPointer, A> { + + inline static ZSmartPointer Call(ZList, A>& _self, ZListIterator< ZSmartPointer >& _itr) + { + ZSmartPointer elem; + ZListNode< ZSmartPointer > *node = _itr.GetNode(); + + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(node != NULL, "ZList: Iterator is invalid!"); + ZSTL_ASSERT(node != &_self.EmptyNode, "ZList: Cannot erase end node!"); + #endif + + //Increment the iterator to the next list node to keep the iterator valid + ++_itr; + + //Rearrange the pointers + node->Previous->Next = node->Next; + node->Next->Previous = node->Previous; + + elem = node->Element; + node->Element = NULL; //This is the specialization + + _self.DeallocateNode(node); + + _self.CheckIntegrity(); + + return elem; + } + + inline static void Call(ZList, A>& _self, ZListIterator< ZSmartPointer >& _start, const ZListIterator< ZSmartPointer >& _end) + { + + ZListNode< ZSmartPointer > *nodeStart = _start.GetNode(); + ZListNode< ZSmartPointer > *nodeEnd = _end.GetNode(); + + ZListNode< ZSmartPointer > *curNode; + ZListNode< ZSmartPointer > *prevNode; + + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(nodeStart != NULL && nodeEnd != NULL, "ZList: Cannot erase with invalid iterator!"); + ZSTL_ASSERT(nodeStart != &_self.EmptyNode, "ZList: Cannot erase end node!"); + #endif + + //Rearrange the pointers + nodeStart->Previous->Next = nodeEnd; + nodeEnd->Previous = nodeStart->Previous; + + //Erase each element between from and to + curNode = nodeStart; + prevNode = NULL; + + while (curNode != nodeEnd) + { + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(curNode != &_self.EmptyNode, "ZList: Cannot erase end node!"); + #endif + + prevNode = curNode; + curNode = curNode->Next; + + prevNode->Element = NULL; //This is the specialization + _self.DeallocateNode(prevNode); + } + + _start = _end; + } + +}; + +//Specialization for ZList_PopBackImpl containing ZSmartPointer +template +struct ZList_PopBackImpl < ZSmartPointer, A> { + inline static ZSmartPointer Call(ZList, A>& _self) { + + ZSmartPointer elem; + ZListNode< ZSmartPointer > *node; + + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(!_self.Empty(), "ZList: Cannot pop from back of empty list!"); + #endif + + //Grab the element at the back of the list + node = _self.EmptyNode.Previous; + + //Remove the node from the list + node->Previous->Next = &_self.EmptyNode; + _self.EmptyNode.Previous = node->Previous; + + //Get the element value and lose our reference + elem = node->Element; + node->Element = NULL; + + //Deallocate and then return + _self.DeallocateNode(node); + + _self.CheckIntegrity(); + + return elem; + } +}; + +//Specialization for ZList_PopFrontImpl containing ZSmartPointer +template +struct ZList_PopFrontImpl < ZSmartPointer, A> { + inline static ZSmartPointer Call(ZList, A>& _self) { + + ZSmartPointer elem; + ZListNode< ZSmartPointer > *node; + + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(!_self.Empty(), "ZList: Cannot pop from front of empty list!"); + #endif + + //Grab the element at the front of the list + node = _self.EmptyNode.Next; + + //Remove the node from the list + node->Next->Previous = node->Previous; + node->Previous->Next = node->Next; + + //Get the element value and lose our reference + elem = node->Element; + node->Element = NULL; + + //Deallocate and then return + _self.DeallocateNode(node); + + _self.CheckIntegrity(); + + return elem; + } +}; + +///////////////////////////////////////////// +/* ZRingBuffer Containment Specializations */ +///////////////////////////////////////////// + +//Specialization for ZRingBuffer_ClearImpl containing ZSmartPointer +template +struct ZRingBuffer_ClearImpl < ZSmartPointer, P, A> { + inline static void Call( ZRingBuffer< ZSmartPointer, P, A>& _self ) + { + // set to null to remove references + for (size_t i = 0; i < _self.BufferSize; i++) + _self.At(i) = ZSmartPointer(NULL); + + _self.BufferSize = 0; + _self.FrontIndex = 0; + _self.BackIndex = 0; + } + inline static void Call( ZRingBuffer< ZSmartPointer, P, A>& _self, size_t _newCapacity ) + { + // set to null to remove references + for (size_t i = 0; i < _self.BufferSize; i++) + _self.At(i) = ZSmartPointer(NULL); + + _self.Buffer.Resize(_newCapacity); + + _self.BufferSize = 0; + _self.FrontIndex = 0; + _self.BackIndex = 0; + } +}; + +//Specialization for ZRingBuffer_EraseImpl containing ZSmartPointer +template +struct ZRingBuffer_EraseImpl < ZSmartPointer, P, A> { + inline static T Call( ZRingBuffer< ZSmartPointer, P, A>& _self, size_t _index) + { + //We are going to do this in a very naive fashion, as this container is not intended for these + //kinds of operations anyhow. Anyone who wishes to optimize this at a later date is welcome. + + _self.AlignBuffer(); + + _self.BufferSize--; + _self.BackIndex--; + + // set to null to remove references + ZSmartPointer ret = _self.Buffer.At(_index); + _self.Buffer.At(_index) = ZSmartPointer(NULL); + return ret; + + } + inline static void Call( ZRingBuffer< ZSmartPointer, P, A>& _self, size_t _i, size_t _j ) + { + //We are going to do this in a very naive fashion, as this container is not intended for these + //kinds of operations anyhow. Anyone who wishes to optimize this at a later date is welcome. + + size_t count; + + _self.AlignBuffer(); + + count = (size_t)(_j - _i); + + _self.BufferSize = _self.BufferSize - count; + _self.BackIndex = _self.BackIndex - count; + + // set to null to remove references + for( size_t i = _i; i < _j; i++) + _self.Buffer.At(i) = ZSmartPointer(NULL); + + _self.Buffer.Erase(_i, _j); + } +}; + +//Specialization for ZRingBuffer_PopBackImpl containing ZSmartPointer +template +struct ZRingBuffer_PopBackImpl < ZSmartPointer, P, A> { + inline static T Call( ZRingBuffer< ZSmartPointer, P, A>& _self ) + { + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT( _self.BufferSize > 0, "ZRingBuffer::PopBack() caused underflow!"); + #endif + + size_t index = _self.BackIndex; + + _self.DecrementBack(); + + _self.CheckIntegrity(); + + // set to NULL to fix ref count issues + ZSmartPointer< T, DF, R > ret = _self.Buffer.At(index); + _self.Buffer.At(index) = ZSmartPointer< T, DF, R>(NULL); + return ret; + } +}; + +//Specialization for ZRingBuffer_PopFrontImpl containing ZSmartPointer +template +struct ZRingBuffer_PopFrontImpl < ZSmartPointer, P, A> { + inline static T Call( ZRingBuffer< ZSmartPointer, P, A>& _self ) + { + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT( _self.BufferSize > 0, "ZRingBuffer::PopFront() caused underflow!"); + #endif + + size_t index = _self.FrontIndex; + + _self.IncrementFront(); + + _self.CheckIntegrity(); + + // set to NULL to fix ref count issues + ZSmartPointer< T, DF, R > ret = _self.Buffer.At(index); + _self.Buffer.At(index) = ZSmartPointer< T, DF, R>(NULL); + return ret; + } +}; + +#endif diff --git a/Include/ZUtil/ZTaskStream.hpp b/Include/ZUtil/ZTaskStream.hpp new file mode 100644 index 0000000..f96909e --- /dev/null +++ b/Include/ZUtil/ZTaskStream.hpp @@ -0,0 +1,404 @@ +/* + ZTaskStream.hpp + Author: James Russell + + Purpose: Manages the execution of 'Tasks' by a number of threads determined at runtime. Attempts to parallelize + execution as well as possible with the provided information. + + Changelog + 2011/04/10 - creation (jcrussell) +*/ + +#ifndef _ZTASKSTREAM_H +#define _ZTASKSTREAM_H + +#include +#include //size_t + +//Forward Declarations +class ZTaskStream; + +typedef size_t ZTaskPriority; //Task Priority +typedef size_t ZTaskThreadId; //Task Thread Id + +//Definition for immediate task execution priority +#define ZTASK_PRIORITY_IMMEDIATE (0) + +//Default allocator buffer size for the task thread +#define ZTT_DEFAULT_BUFFER_SIZE 256 + +//Default allocator buffer size for the task stream +#define ZTS_DEFAULT_BUFFER_SIZE 1024 + +/* +ZTask execute return values. +*/ +enum ZTaskReturnStatus +{ + ZTRS_SUCCESS, // Task has succeeded + ZTRS_FAILURE, // Task has failed + + ZTRS_ENUM_SIZE +}; + +/* +ZTask thread Status enumeration. +*/ +enum ZTaskThreadStatus +{ + ZTTS_UNINITIALIZED, // Task thread is uninitialized + ZTTS_WAITING, // Task thread is awaiting tasks + ZTTS_EXECUTING, // Task thread is executing tasks + + ZTTS_ENUM_SIZE +}; + +/* +Tasks are the basic unit of execution for a ZTaskStream. They are added to the ZTaskStream and +assigned to a thread for execution. They are then executed as TaskThreads +become available. +*/ +class ZTask +{ +friend class ZTaskThread; +friend class ZTaskStream; +public: + ZTaskStream* TaskStream; // The task stream that is executing this task + ZTaskPriority Priority; // Priority, assigned at construction, decreased each time it is delayed to zero, which is immediate priority + bool bCancelTask; // Cancel Boolean, if set to true, will prevent the task from being executed + + /* + Parameterized c'tor (with default arguments). + + @param _priority - The amount of time (in ms) the task can be delayed is priority. This means the closer to zero + the priority is set, the faster it will be executed. + */ + ZTask(ZTaskPriority _priority = ZTASK_PRIORITY_IMMEDIATE) + : TaskStream(NULL), Priority(_priority), bCancelTask(false), Func(NULL), TaskArgument(NULL) { } + + /* + Parameterized c'tor. + + @param _func - function to execute + @param _taskArg - argument to the task + @param _priority - The amount of time (in ms) the task can be delayed is priority. This means the closer to zero + the priority is set, the faster it will be executed. + */ + ZTask(ZTaskReturnStatus (*_func)(ZTaskStream*, ZTask*, void*), void *_taskArg, ZTaskPriority _priority = ZTASK_PRIORITY_IMMEDIATE) + : TaskStream(NULL), Priority(_priority), bCancelTask(false), Func(_func),TaskArgument(_taskArg) { } + + /* + Destructor. + */ + virtual ~ZTask() { } + + /* + virtual public ZTask::Execute + + Execute method. Defined by the task implementation. + + @param _arg - argument to the task (NULL by default) + @return (ZTaskReturnStatus) - task return value + */ + virtual ZTaskReturnStatus Execute(void *_arg) + { URFP(_arg); if (Func != NULL) return Func(TaskStream, this, TaskArgument); else return ZTRS_FAILURE; } + + /* + virtual public ZTask::OnTaskFailed + + Handler function for task failure. No-op by default. + + @return (void) + */ + virtual void OnTaskFailed(void *_taskArgument) + { URFP(_taskArgument); } + +protected: + ZTaskReturnStatus (*Func)(ZTaskStream*, ZTask*, void*); // function for the ZTask to execute if not implemented as a subtask + void* TaskArgument; // Argument passed to this task +}; + +/* +Future. Used to asynchronously execute a function that will return a value when completed. +*/ +template +class ZFuture +{ +friend class ZTaskStream; +protected: + // Future Task + class ZFutureTask : public ZTask + { + public: + R (*Func)(A); // The Function + A Arg; // The argument + R Ret; // The return value + bool Completed; // Completed flag + ZEvent CompletedEvent; // Completed Event + + // c'tor + ZFutureTask(R (*_func)(A), A _arg) + : ZTask(), Func(_func), Arg(_arg), Ret(), Completed(false), CompletedEvent() { } + + // d'tor + ~ZFutureTask() { } + + // subclass override + virtual ZTaskReturnStatus Execute(void *_arg) + { + URFP(_arg); + + CompletedEvent.Reset(); + Ret = Func(Arg); + Completed = true; + CompletedEvent.Notify(); + + return ZTRS_SUCCESS; + } + }; + + ZPtr FutureTask; // The function execute task + +public: + /* + Parameterized c'tor. + + @param _func - the function to execute, must return a value of type R + @param _arg - argument to the function + */ + ZFuture(R (_func)(A), A _arg) : FutureTask(znew ZFutureTask(_func, _arg)) { } + + /* + public ZFuture::IsComplete + + Returns whether or not the future has completed. + + @return (bool) - true if the task has completed + */ + bool IsComplete() { return FutureTask->Completed; } + + /* + public ZFuture::GetValue + + Gets the return value from the future. + + @return (R) - return from the task + */ + R GetValue() { if (!FutureTask->Completed) FutureTask->CompletedEvent.Wait(); return FutureTask->Ret; } + + /* + public ZFuture::GetValueRef + + Gets the return value from the future as a reference. + + @return (R&) - reference to return from the task + */ + R& GetValueRef() { if (!FutureTask->Completed) FutureTask->CompletedEvent.Wait(); return FutureTask->Ret; } +}; + +/* +Threads which execute tasks in the ZTaskStream. The number of operating Task Threads is +assigned at construction of a ZTaskStream and can be changed. +*/ +class ZTaskThread : public ZThread +{ +friend class ZTaskStream; +public: + /* + Parameterized c'tor. + + @param _stream - the stream giving us tasks + @param _id - the id of this task + */ + ZTaskThread(ZTaskStream *_stream, ZTaskThreadId _id); + + // d'tor + virtual ~ZTaskThread(); + + /* + public ZTaskThread::PushTask() + + Adds a task to the task thread. + + @param _task - the task to add to this task thread (argument already set) + @return (void) + */ + void PushTask(ZPtr _task); + +protected: + // Subclass implementation of thread run, which executes tasks + ZThreadReturn run(uint64_t _dt); + +private: + ZMutex TaskLock; // Concurrency lock + ZSemaphore TaskSema; // Event that is set when new tasks are available + ZTaskStream* Stream; // The task stream providing us with tasks + ZTaskThreadId Id; // Task thread ID, used to identify this task thread + ZTaskThreadStatus ThrStatus; // Status of this task thread + + ZTaskPriority CurrentTaskPriority; //The priority of the currently executing task + ZArray< ZPtr > Tasks; //Set of tasks to execute +}; + +/* +The task stream. Assigns tasks to task threads that execute when desired. Can also +handle 'background' tasks. +*/ +class ZTaskStream +{ +public: + /* + Default c'tor. + + Creates a single task thread. The amount of task threads running concurrently can be changed + using SetTaskThreadCount. + */ + ZTaskStream(); + + // d'tor + ~ZTaskStream(); + + /* + public ZTaskStream::ExecuteTasks + + Begins execution on the currently loaded set of tasks and any further tasks generated + during the execution of those tasks. Returns after all tasks that will be executed this + frame are done executing. + + Tasks that were not completed have had their priority values reduced, meaning that if + they are again added to the ZTaskStream for execution repeatedly until executed, they + are guaranteed to eventually execute within their priority time frame. + + @param _frameTime - (given in ms) is the desired amount of time that execution of all tasks + should take; if any time is remaining after execution of ALL priority zero + tasks, a number of extra priority > 0 tasks are executed as can be fit into + the extra time. Because of this definition, frameTime is an estimate and + not a guarantee - execution of priority 0 tasks can take more than frameTime. + @return (void) + */ + void ExecuteTasks(int _frameTime); + + /* + public ZTaskStream::GetTaskThreadCount + + Gets the current number of worker threads. + + @return (size_t) - number of task stream worker threads + */ + size_t GetTaskThreadCount(); + + /* + public ZTaskStream::HaltFrame + + Notifies the ZTaskStream to stop assigning tasks tasks and return from the ExecuteTasks + call that started the process. This does not stop the execution of tasks that have already + been assigned. + + @return (void) + */ + void HaltFrame(); + + /* + public ZTaskStream::Pause + + Notifies the ZTaskStream to pause task execution for all tasks. + + @param _pause - true to pause the stream, false to unpause + @return (void) + */ + void PauseFrame(bool _pause); + + /* + public ZTaskStream::PushFuture + + Adds a ZFuture to the task stream, which will execute the future at the soonest available + opportunity. + + The ZSmartPointer version will hold a reference to the future until after execution. If + the raw pointer version is used, the user is required to keep the pointer valid until after + execution. + + @param _future - the future to execute + @return (void) + */ + template + void PushFuture(ZPtr< ZFuture > _future) { + TaskThreads[AssignTask(_future->FutureTask.Pointer())]->PushTask(_future->FutureTask); + } + + template + void PushFuture(ZFuture* _future) { + // TODO + } + + /* + public ZTaskStream::PushTask + + Adds a task to the task list. The task is added to the task queue in the currently executing + frame phase, or if a phase is not yet executing, it will be added to the next frame phase to + execute. + + The ZSmartPointer version will hold a reference to the task until after execution. If the + raw pointer version is used, the user is required to keep the pointer valid until after + execution. + + @param _task - the task to add + @return (void) - the id of the task + */ + void PushTask(ZPtr _task); + void PushTask(ZTask* _task); + + /* + public ZTaskStream::PushTasks + + Adds a list of tasks. Identical to PushTask() but with less locking overhead. The list of + tasks is not emptied (i.e _tasks.Clear() is not called). + + The ZSmartPointer version will hold a reference to the tasks until after execution. If the + raw pointer version is used, the user is required to keep the pointer valid until after + execution. + + @param _tasks - the tasks to add + @param _count - the number of tasks + @return (void) + */ + void PushTasks(ZArray< ZPtr >& _tasks); + void PushTasks(ZTask* _tasks, size_t _count); + + /* + public ZTaskStream::SetTaskThreadCount + + Sets the number of task threads that will be running. Should be greater than zero, or the + call has no effect. + + @param _count - the number of task threads to run simultaneously + + @return (void) + */ + void SetTaskThreadCount(size_t _count); + +protected: + ZMutex TaskStreamLock; // Lock for controlling access to the ZTaskStream objects + ZSemaphore TaskStreamSema; // Semaphore for signaling events + ZEvent FrameCompletedEvent; // Event for notifying the execute caller thread that a frame is completed + ZEvent PausedEvent; // Event for pausing the Task Stream + ZArray TaskThreads; // Task threads that run the set of tasks + ZArray< ZPtr > Tasks; // The task list + + // Pause flag, which indicates that task execution should be paused + // This is only used for debugging purposes, 'PausedEvent' has the same state + // wrapped into an OS object. + bool bPaused; + + //Halt flag, which indicates that task execution should halt + bool bShouldHalt; + + //Assigns a task to one of the task threads + ZTaskThreadId AssignTask( ZTask *_task); + + //Kills a given task thread + void KillTaskThread(size_t _idx); + +}; + +#endif diff --git a/Include/ZUtil/ZThread.hpp b/Include/ZUtil/ZThread.hpp new file mode 100644 index 0000000..e9a8a3b --- /dev/null +++ b/Include/ZUtil/ZThread.hpp @@ -0,0 +1,368 @@ +/* + ZThread.hpp + Author : James Russell + Created: 07/04/09 + + Purpose : + + Wrapper class to allow easy thread creation. By making a class that is + a subclass of ZThread and defining the run() method, a thread 'object' can + be created that allows for greater consistency and when dealing with thread + resources. + + License: + + TODO +*/ + +#ifndef _ZTHREAD_H +#define _ZTHREAD_H + +#include +#include + +#include +#include + +class ZThread; +typedef void (*ZThreadCallbackFunc)(ZThread* executor, void* arg); + +/* +Macro that creates an anonymous request object for marshalling code into a thread request. + +Example: + +TODO + +@param zthread - the zthread object that should execute the request +@param argument - the void* argument to pass in (accessible as Arg) +@param wait - a boolean indicating if we should wait or not +@param code - the actual code that should be executed as part of the request (wrap in parenthesis) +*/ +#define ZTHREAD_EXECUTE(zthread, argument, wait, code) \ + { \ + class Z##__FUNCTION__##__LINE__##ThreadRequest : public ZThreadRequest \ + { \ + protected: \ + void *Arg; \ + public: \ + Z##__FUNCTION__##__LINE__##ThreadRequest() : ZThreadRequest(), Arg(argument) { } \ + \ + virtual void Execute(ZThread *_threadObj) \ + { \ + code \ + } \ + }; \ + \ + zthread->AddThreadRequest(ZPtr(znew Z##__FUNCTION__##__LINE__##ThreadRequest), wait); \ + } + +//Forward declaration of ZThread +class ZThread; + +//Possible return values from ZThread run +typedef enum ZThreadReturn +{ + ZTR_TERMINATE, //Indicates the thread should terminate after returning from run + ZTR_LOOP, //Indicates the thread should loop after returning from run + ZTR_PAUSE, //Indicates the thread should pause after returning from run + ZTR_SIZE +} ZThreadReturn; + +/* +A ZThread 'Request' object. Used for thread marshaling. +*/ +class ZThreadRequest +{ +friend class ZThread; +private: + //Completion Event + ZEvent CompletedEvent; + + //Indicates this 'ThreadRequest' should persist until removed + bool Persist; + + //Indicates to the ZThread that this request should stop running immediately + //This value is checked before execution + bool Stop; + +public: + /* + Default Constructor. + + @param _persist - boolean indicating this thread request should execute continuously until + the ZThread object is deleted + */ + ZThreadRequest(bool _persist = false) + : CompletedEvent(), Persist(_persist), Stop(false) { } + + /* + Destructor. + + Destroys the concurrency event. + */ + virtual ~ZThreadRequest() { } + + /* + virtual public ZThreadRequest::Execute + + Virtual method, which defines the thread request to be executed. The function will be executed + from within the ZThread object's thread context. If this method is not overridden and Func is not + NULL, Func is called with the provided argument. + + @param _threadObj - the ZThread object executing this request + + @return (void) + */ + virtual void Execute(ZThread *_threadObj) = 0; + + /* + public ZThreadRequest::StopExecution + + Stops execution of the thread request, provided it has not executed yet. + + @return (void) + */ + void StopExecution() { this->Stop = true; } + + /* + public ZThreadRequest::Wait + + Blocks until after the thread request has been executed. + + @return (void) + */ + void Wait() { CompletedEvent.Wait(); } +}; + +/* +ZThread object class. Should be subclassed to make a threadable 'object'. +*/ +class ZThread +{ +private: + DISABLE_COPY_AND_ASSIGN(ZThread); + +public: + /* + Default Constructor. + + @param _threadName - the name of this thread + */ + ZThread(ZString _threadName = ""); + + /* + Destructor for the ZThread Object. When the ZThread object is deleted, the destructor will wait on + the thread to terminate and return resources to the system. + */ + virtual ~ZThread(); + + /* + public ZThread::AddThreadRequest() + + Adds a callback that will be executed when the thread loops. + + @param _request - the thread request to add to the thread's context + + @return (void) + */ + void AddThreadRequest(ZPtr _request, bool _wait = false); + + /* + public ZThread::AddCallbackRequest() + + Adds a callback to be executed by the thread. It can be executed synchronously or asynchronously. + + @param function - The function to execute + @param arg - The argument + @param async - If true, this returns immediately, otherwise it waits for the function to execute. + + @return (void) + */ + void AddCallbackRequest(ZThreadCallbackFunc function, void* arg, bool async); + + /* + public ZThread::GetThreadID + + Gets the thread ID of the thread object. + + @return (uint32_t) - int that is the thread id of the thread object + */ + uint32_t GetThreadId(); + + /* + public ZThread::GetThreadName + + Gets the thread name of the ZThread object. The name of a thread is either a + string value of the thread id or a name that was set by the ZThread object. + + @return (ZString) - string representing the 'name' of this thread + */ + ZString GetThreadName(); + + /* + public ZThread::PauseThread + + Tells the user thread to pause. + + @return (void) + */ + void PauseThread(); + + /* + public ZThread::RestartThread + + Restarts a paused thread. + + @return (void) + */ + void RestartThread(); + + /* + public ZThread::ThreadRunning + + Indicates if a ZThread object is executing it's run method or is paused. + + @return (bool) - boolean indicating thread is running or is paused + */ + bool ThreadRunning(); + + /* + public ZThread::ThreadInitialized + + Returns true if the ZThread object has called it's initThread() method and returned. + + @return (bool) - boolean indicating the thread is initialized + */ + bool ThreadInitialized(); + + /* + public ZThread::ShutdownThread + + Tells the user thread to shutdown. Blocks until it happens. + + @return (void) + */ + void ShutdownThread(); + + /* + public ZThread::StartThread + + When StartThread is called on a class that extends ZThread, a thread will be created + that will call the run() function implemented by the subclass. + + @return (bool) - boolean indicating the thread has started successfully + */ + bool StartThread(); + + /* + public ZThread::WaitInitialized + + Caller waits until the ZThread has initialized. + + @return (void) + @context (all) + */ + void WaitInitialized(); + + /* + public ZThread::WaitShutdown + + Caller waits until the ZThread has shutdown. + + @return (void) + @context (all) + */ + void WaitShutdown(); + +protected: + //Thread 'name' of this thread + ZString ThreadName; + + //Boolean field which, when set to true, indicates the thread should terminate. + bool bShouldShutdown; + + //Boolean field which, when set to true, indicates the thread should pause. + bool bShouldPause; + + /* + This is a wrapper around the user run() method, which calls that method in a loop, executing + thread requests and setting the condition variables appropriately. + */ + void Run(); + + /* + Executes the thread requests that may be pending at the time it is called by the subclass. + */ + void ExecuteThreadRequests(); + + /* + Initialization method which is called when the thread starts. Does not have to be overridden, but any + thread specific initialization that must be done in the thread context of the ZThread object needs + to be defined here. + */ + virtual void initThread() { } + + /* + Shutdown method which is called when the thread terminates. Does not have to be overridden, but any + thread specific shutdown requirements that must be done in the thread context of the ZThread object + needs to be defined here. + */ + virtual void shutdownThread() { } + + /* + This method must be implemented by the ZThread subclass. This is the 'main' function of execution for + the newly created thread. + + @param _dt - the time (in ms) since last time run was called + @return - a ZTHREAD_RETURN value indicating whether the thread should run once (ZTR_TERMINATE), + loop (ZTR_RETURN), or pause (ZTR_PAUSE). + */ + virtual ZThreadReturn run(uint64_t _dt) = 0; + + bool IsCallerTheThread(); +private: + struct ZThreadCallbackRequest { + ZThreadCallbackFunc callback; + void* arg; + SST_Event doneEvent; + }; + + + + //Thread context of this thread + ZThreadContext ThreadContext; + + //The mutex for use by this thread object for handling thread marshaling. + ZMutex ThreadLock; + + //The event signaled when the thread has finished initializing + ZEvent InitEvent; + + //Previous tick count for this thread object + uint64_t PreviousTickCount; + + //Current tick count for this thread object + uint64_t CurrentTickCount; + + //Boolean field which, when set to true, indicates the thread is initialized and running. + bool bIsRunning; + + //Boolean field which, when set to true, indicates the thread has called and returned from initThread() + bool bIsInitialized; + + //List of callbacks that will occur when the ZThread object runs. + ZList< ZPtr > ZTRCallbacks; // ZTR callbacks + ZList< ZThreadCallbackRequest > Callbacks; // Simple (non-object) callbacks + + /* + Proxy method called by StartThread() which will call initThread and Run on the ZThread Object. + + @param _runnable - a pointer to the ZThread object to run + @return - integer condition (not used) + */ + static int InitThread(void *_runnable); +}; + +#endif + diff --git a/Include/ZUtil/ZUtil.hpp b/Include/ZUtil/ZUtil.hpp new file mode 100644 index 0000000..5a76e28 --- /dev/null +++ b/Include/ZUtil/ZUtil.hpp @@ -0,0 +1,49 @@ +/* + ZUtil.hpp + Author: James Russell + Created: 12/26/2011 + + Purpose: + + Header for the ZUtil project that includes all other ZUtil headers + in the proper order. + + License: + + TODO +*/ + +#pragma once + +#ifndef _ZUTIL_HPP +#define _ZUTIL_HPP + +/* ZUtil Project Build File */ +#include + +/* External Includes */ +#include + +/* Standard Util Includes */ +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include +#include +#include + +#include +#include + +#include + +#endif + diff --git a/Include/ZUtil/ZUtilBuild.hpp b/Include/ZUtil/ZUtilBuild.hpp new file mode 100644 index 0000000..81139f5 --- /dev/null +++ b/Include/ZUtil/ZUtilBuild.hpp @@ -0,0 +1,121 @@ +/* + ZUtilBuild.hpp + Author: James Russell + Created: 11/7/2010 + + Purpose: + + Used to generate definitions for the preprocessor using only compiler-set + preprocessor variables, mostly to force a semblance of cross-system compatibility. + + License: + + TODO + +*/ + +#pragma once + +#ifndef _ZUTILBUILD_HPP +#define _ZUTILBUILD_HPP + +//This gives us our standard int types +#include + +#include "ZBuild.hpp" + +//Version number constants for ZUtil +#define ZUTIL_VERSION_MAJOR 0x01 +#define ZUTIL_VERSION_MINOR 0x00 +#define ZUTIL_VERSION_PATCH 0x0000 +#define ZUTIL_VERSION (ZUTIL_VERSION_MAJOR << 24) | (ZUTIL_VERSION_MINOR << 16) | (ZUTIL_VERSION_PATCH) + +#define ZUTIL_VERSION_STRING "1.0.0" + +//Make sure we get proper C-style TRUE, FALSE, and NULL +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +#ifndef NULL +#define NULL 0 +#endif + +//Get our numeric limits +#include +#undef min +#undef max +#define STDINT_MAX std::numeric_limits::max() +#define STDINT_MIN std::numeric_limits::min() +#define STDFLT_MAX std::numeric_limits::max() +#define STDFLT_MIN std::numeric_limits::min() +#define STDDBL_MAX std::numeric_limits::max() +#define STDDBL_MIN std::numeric_limits::min() + +//Used to get rid of the (/W4 or -Wall) warning 'Unreferenced Formal Parameter' +#if !defined(URFP) + #define URFP(x) ((void)x) +#endif + +//Use this to disable copy construction and assignment on a class +#define DISABLE_COPY_AND_ASSIGN(ClassName) \ + ClassName(const ClassName&); \ + void operator = (const ClassName&) + +//Directory separators and line terminators for the various platforms +#define DIRECTORY_SEPARATOR_WIN32 "\\" +#define LINE_TERMINATOR_WIN32 "\r\n" + +#define DIRECTORY_SEPARATOR_UNIX "/" +#define LINE_TERMINATOR_UNIX "\n" + +#define DIRECTORY_SEPARATOR_OSX ":" +#define LINE_TERMINATOR_OSX "\n" + +//Windows specialized defines +#ifdef _WIN32 +#define WINDOWS 1 +#define UNIX 0 +#define OSX 0 + +#define DIRECTORY_SEPARATOR DIRECTORY_SEPARATOR_WIN32 +#define LINE_TERMINATOR LINE_TERMINATOR_WIN32 + +#define _SCL_SECURE_NO_WARNINGS + +#endif + +//UNIX specialized defines +#ifdef _UNIX +#define WINDOWS 0 +#define UNIX 1 +#define OSX 0 + +#define DIRECTORY_SEPARATOR DIRECTORY_SEPARATOR_UNIX +#define LINE_TERMINATOR LINE_TERMINATOR_UNIX + +//Macros to get around gcc's lack of *_s and _* functions and vc9's insistence on using them +#define _stricmp(a, b) strcasecmp(a, b) +#define sprintf_s(a, b, c, d...) snprintf(a, b, c, ## d) +#define vsnprintf_s(a, b, c, d, e...) vsnprintf(a, b, d, ## e) +#endif + +//Mac specialized defines +#ifdef _MACOS +#define WINDOWS 0 +#define UNIX 0 +#define OSX 1 + +#define DIRECTORY_SEPARATOR DIRECTORY_SEPARATOR_OSX +#define LINE_TERMINATOR LINE_TERMINATOR_OSX + +#define _stricmp(a, b) strcasecmp(a, b) +#define sprintf_s(a, b, c, d...) snprintf(a, b, c, ## d) +#define vsnprintf_s(a, b, c, d, e...) vsnprintf(a, b, d, ## e) +#endif + +#endif //_ZUTILBUILD_HPP diff --git a/Include/ZUtil/ZWeakPointer.hpp b/Include/ZUtil/ZWeakPointer.hpp new file mode 100644 index 0000000..f6f1608 --- /dev/null +++ b/Include/ZUtil/ZWeakPointer.hpp @@ -0,0 +1,1024 @@ +/* + ZWeakPointer.hpp + Author: James Russell + Created: 08/12/2011 + + Purpose: + + TODO + + Don't pass these things around by pointer or reference unless you really know what you + are doing. You won't like the results. + + License: + + TODO +*/ + +#pragma once + +#ifndef _ZWEAKPOINTER_H +#define _ZWEAKPOINTER_H + +#include + +/* +DeallocLock macro, used to lock a weak pointer when in use to prevent +deallocation. Using this ensures that the ZReferenceCounter functions +SignalInUse / SignalUnused are respected. + + Usage: + ZWeakPointer ptr; + + DeallocLock(ptr) { + ... code to execute using ptr ... + } +*/ +#define DeallocLock(weakPointer) if (ZWeakPointerDeallocLock dealloc_lock##__LINE__ = weakPointer()) + +/* +Struct used to ensure (via RAII and scoped construction and destruction) that while weak pointers +are in use, the object will not be deallocated by the owning smart pointer. +*/ +struct ZWeakPointerDeallocLock { + + //Indicates whether or not we successfully obtained the lock on our reference counter + bool bLockObtained; + + //The reference counter we attempt to lock + ZReferenceCounter* Ref; + + /* + Default constructor. Calls the SignalInUse function on _counter and stores the + result of the call. + + @param _counter - the reference counter struct to signal + */ + ZWeakPointerDeallocLock(ZReferenceCounter* _counter) + : bLockObtained(_counter != NULL && _counter->SignalInUse()), Ref(_counter) + { } + + /* + Destructor. If the lock was successfully obtained, will signal the object no longer + in use. + */ + ~ZWeakPointerDeallocLock() + { + if (bLockObtained && Ref != NULL) + Ref->SignalUnused(); + } + + /* + operator bool override. Returns whether or not the lock was successful. + + @return (bool) - true if the lock succeeded, false otherwise + */ + operator bool () + { + return bLockObtained; + } +}; + +/* +Weak pointer class, used to maintain a weak reference to an object that has a reference +whose lifetime is maintained by instances of ZSmartPointer. + +@param T - the type of object referenced by the weak pointer + +@param R - the reference counter allocator type to use +*/ +template +class ZWeakPointer +{ +private: + //Managed Pointer + T* Object; + + //Reference Counter Allocator, used to deallocate the ref counter + R RefAllocator; + + //Reference Counter for the pointer + ZReferenceCounter* Ref; + + //Checks to see if the object has lost all strong references and is deleted + inline void CheckReferences() + { + if (Ref != NULL && Ref->GetStrongRefCount() == 0) + { + //There is an edge case here wherein the strong count is zero, the deallocation flag + //on the reference counter has been set, but the object is in use (by us) + if (Ref->State != ZREFCOUNTER_DEALLOC_BIT) + return; + + ReferenceLost(); + + Object = NULL; + Ref = NULL; + } + } + + //Checks to see if the counter is NULL because the pointer is NULL and increments the count + inline void ReferenceGained() + { + if (Ref != NULL) + Ref->GainWeakRef(); + } + + //Checks to see if we can delete the reference and lowers the count + inline void ReferenceLost() + { + //This can be NULL in the case of a default constructed (NULL) pointer + if (Ref == NULL) + return; + + ZASSERT_UTIL(Ref->GetWeakRefCount() > 0 && Object != NULL, "ZSmartPointer: Reference lost but object is already deleted!"); + + uint32_t combinedCount = Ref->LoseWeakRef(); + + if(combinedCount == 0) //If we by losing the weak reference we've reached zero on both weak/strong, deallocate the counter + { + //Deallocate the counter + RefAllocator.DeallocateCounter(Ref); + } + + //We lost our reference, so we don't need these + Object = NULL; + Ref = NULL; + } + +public: + /* + Default constructor. Sets the reference to NULL. + */ + ZWeakPointer() + : Object(NULL), Ref(NULL) + { } + + /* + Copy constructor. + + @param _other - the other weak pointer + */ + ZWeakPointer(const ZWeakPointer& _other) + : Object(_other.Pointer()), Ref(_other.Counter()) + { + ZASSERT_UTIL(!(Object != NULL && Ref == NULL), "ZWeakPointer: Copy constructor called from weak pointer with invalid reference counter!"); + + ReferenceGained(); + } + + /* + Conversion constructor. Used to auto up-cast derived classes, or a + class/object convertible to T. + + @param D - the type contained by the other weak pointer + @param S - the reference counter allocator type used by the other weak pointer + @param _other - the other weak pointer + */ + template + ZWeakPointer(const ZWeakPointer& _other) + : Object(static_cast(_other.Pointer())), Ref(_other.Counter()) + { + ZASSERT_UTIL(!(Object != NULL && Ref == NULL), "ZWeakPointer: Copy constructor called from weak pointer with invalid reference counter!"); + + ReferenceGained(); + } + + /* + Constructor. Takes a ZSmartPointer instance to create a weak pointer. + + @param DF - the deallocation functor type used by the smart pointer + @param _host - the host smart pointer used to initialize this weak pointer + */ + template + ZWeakPointer(const ZSmartPointer& _host) + : Object(_host.Pointer()), Ref(_host.Counter()) + { + ZASSERT_UTIL(!(Object != NULL && Ref == NULL), "ZWeakPointer: Copy constructor called from smart pointer with invalid reference counter!"); + + ReferenceGained(); + } + + /* + Conversion constructor. Used to construct from a ZSmartPointer of a derived class, + or a class/object convertible to T. + + @param D - the type contained by the other weak pointer + @param DF - the deallocation functor type used by the smart pointer + @param S - the reference counter allocator type used by the other weak pointer + @param _host - the host smart pointer used to initialize this weak pointer + */ + template + ZWeakPointer(const ZSmartPointer& _host) + : Object(static_cast(_host.Pointer())), Ref(_host.Counter()) + { + ZASSERT_UTIL(!(Object != NULL && Ref == NULL), "ZWeakPointer: Copy constructor called from smart pointer with invalid reference counter!"); + + ReferenceGained(); + } + + /* + Destructor. Causes a weak reference to be lost. + */ + ~ZWeakPointer() + { + ReferenceLost(); + } + + /* + = operator overload. This version is used only to assign to NULL and nullify + the reference. + + @param _null - the NULL value + @return (ZWeakPointer&) - this weak pointer + @assert - if _null is not the value NULL + */ + ZWeakPointer& operator = (int _null) + { + ZASSERT_RUNTIME(_null == 0, "ZWeakPointer: Assignment operator to int can only be used to assign to NULL!"); + + ReferenceLost(); //Lose a weak reference + Object = NULL; //Nullify our object pointer + Ref = NULL; //Nullify our reference counter + + return *this; + } + + /* + = operator overload. Constructs this weak pointer from another weak pointer, + incrementing the weak reference count on the object. + + @param _other - the other weak pointer + @return (ZWeakPointer&)- this weak pointer + */ + ZWeakPointer& operator = (const ZWeakPointer& _other) + { + if (*this == _other || Ref == _other.Counter()) + return *this; + + ReferenceLost(); //Lose a reference to our current object + Ref = _other.Counter(); //Get our new reference counter + ReferenceGained(); //Increment the reference + + Object = _other.Pointer(); //Reference It + + return *this; + } + + /* + = operator overload. Used to assign to derived classes or classes that + can be converted. + + @param D - the type contained by the other weak pointer + @param S - the reference counter allocator type used by the other weak pointer + @param _other - the other smart pointer + @return (ZWeakPointer&) - this weak pointer + */ + template + ZWeakPointer& operator = (const ZWeakPointer& _other) + { + T* testCast = static_cast(_other.Pointer()); ((void)testCast); //This will fail to compile if T* cannot static cast to D* + + return *this = static_cast< ZWeakPointer >(_other); + } + + /* + = operator overload. Used to set the weak pointer from a host smart pointer. + + @param DF - the deallocation functor type used by the smart pointer + @param _host - the host smart pointer used to initialize this weak pointer + @return (ZWeakPointer&) - this weak pointer + */ + template + ZWeakPointer& operator = (const ZSmartPointer& _host) + { + if (*this == _host || Ref == _host.Counter()) + return *this; + + ReferenceLost(); //Lose a reference to our current object + + Object = _host.Pointer(); //Reference It + Ref = _host.Counter(); //Get our new reference counter + + ReferenceGained(); //Increment the reference + + + return *this; + } + + /* + = operator overload. Used to set the weak pointer from a host smart pointer of + a derived type or a type that can be converted. + + @param D - the type contained by the other weak pointer + @param DF - the deallocation functor type used by the smart pointer + @param S - the reference counter allocator type used by the other weak pointer + @param _host - the host smart pointer used to initialize this weak pointer + @return (ZWeakPointer&) - this weak pointer + */ + template + ZWeakPointer& operator = (const ZSmartPointer& _host) + { + T* testCast = static_cast(_host.Pointer()); ((void)testCast); //This will fail to compile if T* cannot static cast to D* + + return *this = static_cast< ZSmartPointer >(_host); + } + + /* + == operator overload. Checks to see if this weak pointer references the provided + raw pointer. + + @param _ptr - the pointer to check + @return (bool) - true if the pointer is referenced by the weak pointer, false otherwise + */ + bool operator == (const T* _ptr) + { + CheckReferences(); + + return Object == _ptr; + } + + /* + == operator overload. Checks to see if these pointers reference the same object. + + @param _other - the other weak pointer + @return (bool) - true if they reference the same object, false otherwise + */ + bool operator == (const ZWeakPointer& _other) + { + CheckReferences(); + + return Object == _other.Pointer(); + } + + /* + == operator overload. Used to compare with weak pointers containing objects of a + derived type or a type that can be converted to T. + + @param D - the type contained by the other weak pointer + @param S - the reference counter allocator type used by the other weak pointer + @param _other - the other smart pointer + @return (bool) - true if equal, false otherwise + */ + template + bool operator == (const ZWeakPointer& _other) + { + CheckReferences(); + + return Object == static_cast(_other.Pointer()); + } + + /* + == operator overload. Used to determine if this weak pointer and a smart pointer + reference the same object. + + @param DF - the deallocator functor used by the smart pointer + @param _other - the other smart pointer + @return (bool) - true if they reference the same object, false otherwise. + */ + template + bool operator == (const ZSmartPointer& _other) + { + CheckReferences(); + + return Object == _other.Pointer(); + } + + /* + == operator overload. Used to compare to determine if this weak pointer and a smart + pointer with different template types reference the same object. + + @param D - the type contained by the smart pointer + @param DF - the deallocator functor used by the smart pointer + @param S - the reference counter allocator type used by the other smart pointer + @param _other - the other smart pointer + @return -this weak pointer + */ + template + bool operator == (const ZSmartPointer& _other) + { + return Object == static_cast(_other.Pointer()); + } + + /* + != operator overload. Checks to see if this weak pointer does not + reference the provided raw pointer. + + @param _ptr - the pointer to check + @return (bool) - false if equal, true otherwise + */ + bool operator != (const T* _ptr) + { + return !(*this == _ptr); + } + + /* + != operator overload. Checks to see if these pointers reference different + objects. + + @param _other - the other smart pointer + @return (bool) - false if equal, true otherwise + */ + bool operator != (const ZWeakPointer& _other) + { + return !(*this == _other); + } + + /* + != operator overload. Checks to see if these pointers reference different + objects. + + @param D - the type contained by the other weak pointer + @param S - the reference counter allocator type for the other weak pointeR + @param _other - the other smart pointer + @return (bool) - false if equal, true otherwise + */ + template + bool operator != (const ZWeakPointer& _other) + { + return !(*this == _other); + } + + /* + != operator overload. Used to determine if this weak pointer and the given smart + pointer reference the same object. + + @param DF - the deallocator functor type for the smart pointer + @param _other - the other smart pointer + @return (bool) - false if equal, true otherwise + */ + template + bool operator != (const ZSmartPointer& _other) + { + return !(*this == _other); + } + + /* + != operator overload. Used to determine if this weak pointer and the given smart + pointer with different template arguments reference the same object. + + @param D - the type referenced by the other smart pointer + @param DF - the deallocator functor type for the smart pointer + @param S - the reference counter deallocator type for the smart pointer + @param _other - the other smart pointer + @return (bool) - false if equal, true otherwise + */ + template + bool operator != (const ZSmartPointer& _other) + { + return !(*this == _other); + } + + /* + -> operator overload. Allows this to be dereferenced as a T* would be. ZWeakPointer instances + should only be accessed (via -> and *) from within the scope of a DeallocLock macro. + + @return - the managed pointer + @assert - if the pointer is NULL + */ + T* operator -> () + { + CheckReferences(); + + ZASSERT_RUNTIME(Object != NULL, "ZSmartPointer: Null Pointer Dereferenced!"); + + return Object; + } + + /* + '*' operator overload. Allows this to be dereferenced as a T* would be. ZWeakPointer instances + should only be accessed (via -> and *) from within the scope of a DeallocLock macro. + + @return - reference to the managed object + @assert - if the object is NULL + */ + T& operator * () + { + CheckReferences(); + + ZASSERT_RUNTIME(Object != NULL, "ZSmartPointer: Null Pointer Dereferenced!"); + + return *Object; + } + + /* + Operator override which enables use of the DeallocLock macro. ZWeakPointer instances + should only be accessed (via -> and *) from within the scope of a DeallocLock macro. + + @return (ZWeakPointerDeallocLock) - dealloc lock + */ + ZWeakPointerDeallocLock operator () () + { + CheckReferences(); + + return ZWeakPointerDeallocLock(Ref); + } + + /* + public ZWeakPointer::Cast + + Used to cast this weak pointer into another type. This will construct an + additional weak pointer that also references the object. The referenced + object must be convertible to type C* via static_cast. + + + @param C - the type we should cast this weak pointer to + @return (ZWeakPointer) - the casted weak pointer + */ + template + ZWeakPointer Cast() + { + CheckReferences(); + + return static_cast< ZWeakPointer >(*this); + } + + /* + public ZWeakPointer::Counter + + Gets the reference counter used by this weak pointer. + + @return (ZSmartPointerRefCounter*) - reference counter instance + */ + ZReferenceCounter* Counter() const + { + return Ref; + } + + /* + public ZWeakPointer::Pointer + + Gets the weak pointer as a raw pointer. Buyer beware. + + @return (T*) - raw pointer that this smart pointer manages + */ + T* Pointer() const + { + return Object; + } +}; + +//////////////////////////////////////// +/* ZArray Containment Specializations */ +//////////////////////////////////////// + +//Helper function used to nullify references in a range +template +void ZWeakPointerArrayNullify(ZWeakPointer* _array, size_t _start, size_t _end) +{ + for (size_t i = _start; i < _end; i++) + _array[i] = NULL; +} + +//Specialization for ZArray_ClearImpl containing ZWeakPointer +template +struct ZArray_ClearImpl< ZWeakPointer, A> { + + inline static void Call(ZArray, A>& _self) + { + //Nullify references + ZWeakPointerArrayNullify(_self.Array, 0, _self.ArraySize); + + //Reset size and check integrity + _self.ArraySize = 0; + _self.CheckIntegrity(); + } + + inline static void Call(ZArray, A>& _self, size_t _newCapacity) + { + //Nullify references + ZWeakPointerArrayNullify(_self.Array, 0, _self.ArraySize); + + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(_newCapacity > 0, "ZArray: Cannot set capacity to zero!"); + #endif + + //Reallocate if needed, drop our size to zero, and check integrity + if (_newCapacity > _self.ArrayCapacity) + { + _self.Deallocate(_self.Array, _self.ArrayCapacity); + _self.ArrayCapacity = _newCapacity; + _self.Allocate(_self.ArrayCapacity); + } + + _self.ArraySize = 0; + _self.CheckIntegrity(); + } + +}; + +//Specialization for ZArray_EraseImpl containing ZWeakPointer +template +struct ZArray_EraseImpl< ZWeakPointer, A> { + + inline static ZWeakPointer Call(ZArray, A>& _self, size_t _index) + { + size_t index = _self.BoundsCheck(_index, _self.ArraySize); + + //Grab the currently held element, shift the array down, reduce size, and check integrity + ZWeakPointer element = _self.Array[index]; + + for (size_t i = index; i + 1 < _self.ArraySize; i++) + _self.Array[i] = _self.Array[i + 1]; + + _self.ArraySize--; + _self.CheckIntegrity(); + + //Nullify reference + ZWeakPointerArrayNullify(_self.Array, _self.ArraySize, _self.ArraySize + 1); + + return element; + } + + inline static void Call(ZArray, A>& _self, const size_t _start, const size_t _end) + { + size_t start = _self.BoundsCheck(_start, _self.ArraySize); + size_t end = _self.BoundsCheck(_end, _self.ArraySize + 1); + + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(start <= end, "ZArray: cannot erase with start < end!"); + #endif + + //Copy the elements down, compute new size, and check integrity + for (size_t idx = start; idx + (end - start) < _self.ArraySize; idx++) + _self.Array[idx] = _self.Array[idx + (end - start)]; + + _self.ArraySize = _self.ArraySize - (end - start); + _self.CheckIntegrity(); + + //Nullify references (where we moved from) + ZWeakPointerArrayNullify(_self.Array, _self.ArraySize, _self.ArraySize + (end - start)); + } +}; + +//Specialization for ZArray_PopBackImpl containing ZWeakPointer +template +struct ZArray_PopBackImpl< ZWeakPointer, A> { + + inline static ZWeakPointer Call(ZArray, A>& _self) + { + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(_self.ArraySize > 0, "ZArray: Cannot pop from array with no elements!"); + #endif + + ZWeakPointer ptr = _self.Array[--(_self.ArraySize)]; + + //Nullify reference + ZWeakPointerArrayNullify(_self.Array, _self.ArraySize, _self.ArraySize + 1); + + //Grab the last element in the array and decrease our array size + return ptr; + } + +}; + +//Specialization for ZArray_PopFrontImpl containing ZWeakPointer +template +struct ZArray_PopFrontImpl< ZWeakPointer, A> { + + inline static ZWeakPointer Call(ZArray, A>& _self) + { + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(_self.ArraySize > 0, "ZArray: Cannot pop from array with no elements!"); + #endif + + //This will nullify the reference + return _self.Erase(0); + } + +}; + +//Specialization for ZArray_ResizeImpl containing ZWeakPointer +template +struct ZArray_ResizeImpl< ZWeakPointer, A> { + + inline static void Call(ZArray, A>& _self, const size_t _size) + { + //Nullify references if needed + if (_size < _self.ArraySize) + ZWeakPointerArrayNullify(_self.Array, _size, _self.ArraySize); + + //Check to see if we need more space, change our size, and check integrity + if (_size > _self.ArrayCapacity) + _self.Reserve(_size); + + _self.ArraySize = _size; + _self.CheckIntegrity(); + } + + inline static void Call(ZArray, A>& _self, const size_t _size, const ZWeakPointer& _value) + { + //Nullify references if needed + if (_size < _self.ArraySize) + ZWeakPointerArrayNullify(_self.Array, _size, _self.ArraySize); + + //See if we need more space, copy in the new value, change our size, and check integrity + if (_size > _self.ArrayCapacity) + _self.Reserve(_size); + + for (size_t i = _self.ArraySize; i < _size; i++) + _self.Array[i] = _value; + + _self.ArraySize = _size; + _self.CheckIntegrity(); + } + +}; + +/////////////////////////////////////// +/* ZList Containment Specializations */ +/////////////////////////////////////// + +//Specialization for ZList_ClearImpl containing ZWeakPointer +template +struct ZList_ClearImpl < ZWeakPointer, A> { + + inline static void Call(ZList, A>& _self, ZListIterator< ZWeakPointer >& _itr) { + + ZListNode >* next; + ZListNode >* current = _itr.GetNode(); + + _self.CheckIntegrity(); + + //Early out + if (_self.Empty()) + return; + + //If we are the starting node, be sure to reset the EmptyNode.Next pointer + if (current == _self.EmptyNode.Next) + _self.EmptyNode.Next = &_self.EmptyNode; + + //This is always true + _self.EmptyNode.Previous = current->Previous; + current->Previous->Next = &_self.EmptyNode; + + //Iterate and deallocate the nodes + while (current != &_self.EmptyNode) + { + next = current->Next; + current->Element = NULL; //This is the specialization + _self.DeallocateNode(current); + current = next; + } + + //Set the node on the iterator equal to the end node + _itr.SetNode(&_self.EmptyNode); + + _self.CheckIntegrity(); + } + +}; + +//Specialization for ZList_EraseImpl containing ZWeakPointer +template +struct ZList_EraseImpl < ZWeakPointer, A> { + + inline static ZWeakPointer Call(ZList, A>& _self, ZListIterator< ZWeakPointer >& _itr) + { + ZWeakPointer elem; + ZListNode< ZWeakPointer > *node = _itr.GetNode(); + + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(node != NULL, "ZList: Iterator is invalid!"); + ZSTL_ASSERT(node != &_self.EmptyNode, "ZList: Cannot erase end node!"); + #endif + + //Increment the iterator to the next list node to keep the iterator valid + ++_itr; + + //Rearrange the pointers + node->Previous->Next = node->Next; + node->Next->Previous = node->Previous; + + elem = node->Element; + node->Element = NULL; //This is the specialization + + _self.DeallocateNode(node); + + _self.CheckIntegrity(); + + return elem; + } + + inline static void Call(ZList, A>& _self, ZListIterator< ZWeakPointer >& _start, const ZListIterator< ZWeakPointer >& _end) + { + + ZListNode< ZWeakPointer > *nodeStart = _start.GetNode(); + ZListNode< ZWeakPointer > *nodeEnd = _end.GetNode(); + + ZListNode< ZWeakPointer > *curNode; + ZListNode< ZWeakPointer > *prevNode; + + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(nodeStart != NULL && nodeEnd != NULL, "ZList: Cannot erase with invalid iterator!"); + ZSTL_ASSERT(nodeStart != &_self.EmptyNode, "ZList: Cannot erase end node!"); + #endif + + //Rearrange the pointers + nodeStart->Previous->Next = nodeEnd; + nodeEnd->Previous = nodeStart->Previous; + + //Erase each element between from and to + curNode = nodeStart; + prevNode = NULL; + + while (curNode != nodeEnd) + { + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(curNode != &_self.EmptyNode, "ZList: Cannot erase end node!"); + #endif + + prevNode = curNode; + curNode = curNode->Next; + + prevNode->Element = NULL; //This is the specialization + _self.DeallocateNode(prevNode); + } + + _start = _end; + } + +}; + +//Specialization for ZList_PopBackImpl containing ZWeakPointer +template +struct ZList_PopBackImpl < ZWeakPointer, A> { + inline static ZWeakPointer Call(ZList, A>& _self) { + + ZWeakPointer elem; + ZListNode< ZWeakPointer > *node; + + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(!_self.Empty(), "ZList: Cannot pop from back of empty list!"); + #endif + + //Grab the element at the back of the list + node = _self.EmptyNode.Previous; + + //Remove the node from the list + node->Previous->Next = &_self.EmptyNode; + _self.EmptyNode.Previous = node->Previous; + + //Get the element value and lose our reference + elem = node->Element; + node->Element = NULL; + + //Deallocate and then return + _self.DeallocateNode(node); + + _self.CheckIntegrity(); + + return elem; + } +}; + +//Specialization for ZList_PopFrontImpl containing ZWeakPointer +template +struct ZList_PopFrontImpl < ZWeakPointer, A> { + inline static ZWeakPointer Call(ZList, A>& _self) { + + ZWeakPointer elem; + ZListNode< ZWeakPointer > *node; + + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(!_self.Empty(), "ZList: Cannot pop from front of empty list!"); + #endif + + //Grab the element at the front of the list + node = _self.EmptyNode.Next; + + //Remove the node from the list + node->Next->Previous = node->Previous; + node->Previous->Next = node->Next; + + //Get the element value and lose our reference + elem = node->Element; + node->Element = NULL; + + //Deallocate and then return + _self.DeallocateNode(node); + + _self.CheckIntegrity(); + + return elem; + } +}; + +///////////////////////////////////////////// +/* ZRingBuffer Containment Specializations */ +///////////////////////////////////////////// + +//Specialization for ZRingBuffer_ClearImpl containing ZWeakPointer +template +struct ZRingBuffer_ClearImpl < ZWeakPointer, P, A> { + inline static void Call( ZRingBuffer< ZWeakPointer, P, A>& _self ) + { + // set to null to remove references + for (size_t i = 0; i < _self.BufferSize; i++) + _self.At(i) = ZWeakPointer(NULL); + + _self.BufferSize = 0; + _self.FrontIndex = 0; + _self.BackIndex = 0; + } + inline static void Call( ZRingBuffer< ZWeakPointer, P, A>& _self, size_t _newCapacity ) + { + // set to null to remove references + for (size_t i = 0; i < _self.BufferSize; i++) + _self.At(i) = ZWeakPointer(NULL); + + _self.Buffer.Resize(_newCapacity); + + _self.BufferSize = 0; + _self.FrontIndex = 0; + _self.BackIndex = 0; + } +}; + +//Specialization for ZRingBuffer_EraseImpl containing ZWeakPointer +template +struct ZRingBuffer_EraseImpl < ZWeakPointer, P, A> { + inline static T Call( ZRingBuffer< ZWeakPointer, P, A>& _self, size_t _index) + { + //We are going to do this in a very naive fashion, as this container is not intended for these + //kinds of operations anyhow. Anyone who wishes to optimize this at a later date is welcome. + + _self.AlignBuffer(); + + _self.BufferSize--; + _self.BackIndex--; + + // set to null to remove references + ZWeakPointer ret = _self.Buffer.At(_index); + _self.Buffer.At(_index) = ZWeakPointer(NULL); + return ret; + + } + inline static void Call( ZRingBuffer< ZWeakPointer, P, A>& _self, size_t _i, size_t _j ) + { + //We are going to do this in a very naive fashion, as this container is not intended for these + //kinds of operations anyhow. Anyone who wishes to optimize this at a later date is welcome. + + size_t count; + + _self.AlignBuffer(); + + count = (size_t)(_j - _i); + + _self.BufferSize = _self.BufferSize - count; + _self.BackIndex = _self.BackIndex - count; + + // set to null to remove references + for( size_t i = _i; i < _j; i++) + _self.Buffer.At(i) = ZWeakPointer(NULL); + + _self.Buffer.Erase(_i, _j); + } +}; + +//Specialization for ZRingBuffer_PopBackImpl containing ZWeakPointer +template +struct ZRingBuffer_PopBackImpl < ZWeakPointer, P, A> { + inline static T Call( ZRingBuffer< ZWeakPointer, P, A>& _self ) + { + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT( _self.BufferSize > 0, "ZRingBuffer::PopBack() caused underflow!"); + #endif + + size_t index = _self.BackIndex; + + _self.DecrementBack(); + + _self.CheckIntegrity(); + + // set to NULL to fix ref count issues + ZWeakPointer ret = _self.Buffer.At(index); + _self.Buffer.At(index) = ZWeakPointer(NULL); + return ret; + } +}; + +//Specialization for ZRingBuffer_PopFrontImpl containing ZWeakPointer +template +struct ZRingBuffer_PopFrontImpl < ZWeakPointer, P, A> { + inline static T Call( ZRingBuffer< ZWeakPointer, P, A>& _self ) + { + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT( _self.BufferSize > 0, "ZRingBuffer::PopFront() caused underflow!"); + #endif + + size_t index = _self.FrontIndex; + + _self.IncrementFront(); + + _self.CheckIntegrity(); + + // set to NULL to fix ref count issues + ZWeakPointer ret = _self.Buffer.At(index); + _self.Buffer.At(index) = ZWeakPointer(NULL); + return ret; + } +}; + + +#endif diff --git a/Include/ZUtil/ZXMLReader.hpp b/Include/ZUtil/ZXMLReader.hpp new file mode 100644 index 0000000..a87514e --- /dev/null +++ b/Include/ZUtil/ZXMLReader.hpp @@ -0,0 +1,160 @@ +/* + ZXMLReader.hpp + Author: James Russell + Created: 5/11/2012 + + Purpose: + + Reads in data from the given XML input and parses the data into a ZKVTree instance + that can be used for path-based lookup and iteration of values. For example, the following + XML data: + + + + + + This is a particle emitter node. + + + + Is given the following ZKVTree layout (node values in parenthesis): + + Root + | + +-> node (This is a particle emitter node.) + | | + | +-> type (emitter) + | | + | +-> position () + | | | + | | +-> x (100) + | | +-> y (100) + | | +-> z (1) + | | + | +-> facing () + | | | + | +-> x (0) + | +-> y (0) + | +-> z (1) + | + +-> node + | + +-> type (time) + +-> value (2200) + + Note that all XML elements will have the body assigned to the value of the node. Attributes + will have their attribute value assigned to the node value, but will never have child nodes. + + This does mean that an XML element with a body value but no attributes will be functionally + identical in the KVTree representation to an attribute of the parent element. For example, the + following two XML snippets will have an identical layout in the KVTree: + + + 1 + + + + + The parsed layout in ZKVTree form is as follows: + + Root + | + +-> node () + | + +-> type (emitter) + | + +-> flags (1) + + Note that the current implementation uses rapidxml, and will technically parse a superset of W3C + compliant XML as valid. In particular, closing tags are not checked for matching, meaning that + any closing tag will close any node. There are other non-W3C compliance issues with rapidxml + as well, although it will never refuse to parse valid XML. + + More information about rapidxml can be found here: http://rapidxml.sourceforge.net/manual.html + + License: + + TODO + +*/ + +#pragma once + +#ifndef _ZXMLREADER_HPP +#define _ZXMLREADER_HPP + +#include +#include + +/* +ZXMLReader class, which converts XML data into a ZKVtree that can be used to access / iterate +the data. +*/ +class ZXMLReader +{ +public: + /* + Default Constructor. + */ + ZXMLReader() + : ErrorMessage() { } + + /* + Destructor. + */ + ~ZXMLReader() + { Tree.Clear(); } + + + /* + public ZXMLReader::Read + + Reads in XML data stored as a ZString and parses it into an internal format. + + @param _xml - Pointer to XML data + @return (bool) - true if successful, false if failure (use GetErrorString() to get the message) + */ + bool Read(const ZString& _xml) + { return Read(_xml.Data(), _xml.Length()); } + + /* + public ZXMLReader::Read + + Reads in XML data stored as a memory block and parses it into an internal format. + + @param _data - Pointer to XML data + @param _length - Length of XML data + @return (bool) - true if successful, false if failure (use GetErrorString() to get the message) + */ + bool Read(const char* _data, size_t _length); + + /* + public ZXMLReader::GetErrorString + + Gets the error message generated while loading the data if loading failed. If loading + the data was successful, this returns an empty string. + + @return (const ZString&) - error message string + */ + const ZString& GetErrorString(); + + /* + public ZXMLReader::GetKVTree + + Gets the data from the parsed XML as a key-value tree. If the loading failed, + the tree is returned empty. + + + + @param _kvtree - the tree to fill with parsed xml data + */ + void GetKVTree(ZKVTree& _kvtree); + +private: + DISABLE_COPY_AND_ASSIGN(ZXMLReader); + + ZString ErrorMessage; // error message (if there has been an error) + ZKVTree Tree; // tree to store the xml in +}; + +#endif diff --git a/Include/ZUtil/ZXMLWriter.hpp b/Include/ZUtil/ZXMLWriter.hpp new file mode 100644 index 0000000..4fb556f --- /dev/null +++ b/Include/ZUtil/ZXMLWriter.hpp @@ -0,0 +1,110 @@ +/* + ZXMLWriter.hpp + Author: James Russell + Created: 5/13/2012 + + Purpose: + + Interprets a ZKVTree as XML, writing the node structure and values into XML elements. Acts as + an inverse of ZXMLReader (see header for details on format). + + Note that the same ambiguity is present for elements with no attributes and body data - they will + be written out as attributes. For example, consider the following ZKVTree structure: + + Root + | + +-> node (This is a particle emitter node.) + | | + | +-> type (emitter) + | | + | +-> position () + | | | + | | +-> x (100) + | | +-> y (100) + | | +-> z (1) + | | + | +-> facing () + | | | + | | +-> x (0) + | | +-> y (0) + | | +-> z (1) + | | + | +-> flags (1) + | + +-> node + | + +-> type (time) + +-> value (2200) + + The above will be written out as follows: + + + + + This is a particle emitter node. + + + + Notice that the ambiguous case described in ZXMLReader.hpp for an attribute of an XML + element and the body of an attribute-free element will always be written out as an + attribute. + + The body of 'node' is not ambiguous because the 'node' element has attributes and child + elements. + + License: + + TODO + +*/ + +#pragma once + +#ifndef _ZXMLWRITER_HPP +#define _ZXMLWRITER_HPP + +#include + +class ZXMLWriter +{ +private: + DISABLE_COPY_AND_ASSIGN(ZXMLWriter); + + //Error message (if an error has happened) + ZString ErrorMessage; + + // recursive functions for writing XML + bool writeAttributes(ZString& _output, const ZKVTree::Iterator& _itr); + bool writeElements(ZString& _output, bool _useNewlines, const ZKVTree::Iterator& _itr); + +public: + /* + Default Constructor. + */ + ZXMLWriter() { } + + /* + public ZXMLWriter::GetErrorString + + Gets the error message generated while writing the data if writing failed. If writing + the data was successful, this returns an empty string. + + @return (const ZString&) + */ + const ZString& GetErrorString(); + + /* + public ZXMLWriter::Write + + Writes the data from the registry into the provided output string in XML format. + + @param _input - the KVTree we wish to represent as XML + @param _output - the string to write the data into (the data is appended) + @param _useNewlines - indicates whether or not we should use newlines in the output + @return (bool) - true if successful, false otherwise + */ + bool Write(const ZKVTree& _input, ZString& _output, bool _useNewlines); +}; + +#endif + diff --git a/Lib/Include/AL/al.h b/Lib/Include/AL/al.h new file mode 100644 index 0000000..10aeae4 --- /dev/null +++ b/Lib/Include/AL/al.h @@ -0,0 +1,718 @@ +#ifndef AL_AL_H +#define AL_AL_H + +#if defined(__cplusplus) +extern "C" { +#endif + +#ifndef AL_API + #if defined(AL_LIBTYPE_STATIC) + #define AL_API + #elif defined(_WIN32) + #define AL_API __declspec(dllimport) + #else + #define AL_API extern + #endif +#endif + +#if defined(_WIN32) + #define AL_APIENTRY __cdecl +#else + #define AL_APIENTRY +#endif + +#if defined(TARGET_OS_MAC) && TARGET_OS_MAC + #pragma export on +#endif + +/* + * The OPENAL, ALAPI, ALAPIENTRY, AL_INVALID, AL_ILLEGAL_ENUM, and + * AL_ILLEGAL_COMMAND macros are deprecated, but are included for + * applications porting code from AL 1.0 + */ +#define OPENAL +#define ALAPI AL_API +#define ALAPIENTRY AL_APIENTRY +#define AL_INVALID (-1) +#define AL_ILLEGAL_ENUM AL_INVALID_ENUM +#define AL_ILLEGAL_COMMAND AL_INVALID_OPERATION + +#define AL_VERSION_1_0 +#define AL_VERSION_1_1 + + +/** 8-bit boolean */ +typedef char ALboolean; + +/** character */ +typedef char ALchar; + +/** signed 8-bit 2's complement integer */ +typedef signed char ALbyte; + +/** unsigned 8-bit integer */ +typedef unsigned char ALubyte; + +/** signed 16-bit 2's complement integer */ +typedef short ALshort; + +/** unsigned 16-bit integer */ +typedef unsigned short ALushort; + +/** signed 32-bit 2's complement integer */ +typedef int ALint; + +/** unsigned 32-bit integer */ +typedef unsigned int ALuint; + +/** non-negative 32-bit binary integer size */ +typedef int ALsizei; + +/** enumerated 32-bit value */ +typedef int ALenum; + +/** 32-bit IEEE754 floating-point */ +typedef float ALfloat; + +/** 64-bit IEEE754 floating-point */ +typedef double ALdouble; + +/** void type (for opaque pointers only) */ +typedef void ALvoid; + + +/* Enumerant values begin at column 50. No tabs. */ + +/* "no distance model" or "no buffer" */ +#define AL_NONE 0 + +/* Boolean False. */ +#define AL_FALSE 0 + +/** Boolean True. */ +#define AL_TRUE 1 + +/** Indicate Source has relative coordinates. */ +#define AL_SOURCE_RELATIVE 0x202 + + + +/** + * Directional source, inner cone angle, in degrees. + * Range: [0-360] + * Default: 360 + */ +#define AL_CONE_INNER_ANGLE 0x1001 + +/** + * Directional source, outer cone angle, in degrees. + * Range: [0-360] + * Default: 360 + */ +#define AL_CONE_OUTER_ANGLE 0x1002 + +/** + * Specify the pitch to be applied at source. + * Range: [0.5-2.0] + * Default: 1.0 + */ +#define AL_PITCH 0x1003 + +/** + * Specify the current location in three dimensional space. + * OpenAL, like OpenGL, uses a right handed coordinate system, + * where in a frontal default view X (thumb) points right, + * Y points up (index finger), and Z points towards the + * viewer/camera (middle finger). + * To switch from a left handed coordinate system, flip the + * sign on the Z coordinate. + * Listener position is always in the world coordinate system. + */ +#define AL_POSITION 0x1004 + +/** Specify the current direction. */ +#define AL_DIRECTION 0x1005 + +/** Specify the current velocity in three dimensional space. */ +#define AL_VELOCITY 0x1006 + +/** + * Indicate whether source is looping. + * Type: ALboolean? + * Range: [AL_TRUE, AL_FALSE] + * Default: FALSE. + */ +#define AL_LOOPING 0x1007 + +/** + * Indicate the buffer to provide sound samples. + * Type: ALuint. + * Range: any valid Buffer id. + */ +#define AL_BUFFER 0x1009 + +/** + * Indicate the gain (volume amplification) applied. + * Type: ALfloat. + * Range: ]0.0- ] + * A value of 1.0 means un-attenuated/unchanged. + * Each division by 2 equals an attenuation of -6dB. + * Each multiplicaton with 2 equals an amplification of +6dB. + * A value of 0.0 is meaningless with respect to a logarithmic + * scale; it is interpreted as zero volume - the channel + * is effectively disabled. + */ +#define AL_GAIN 0x100A + +/* + * Indicate minimum source attenuation + * Type: ALfloat + * Range: [0.0 - 1.0] + * + * Logarthmic + */ +#define AL_MIN_GAIN 0x100D + +/** + * Indicate maximum source attenuation + * Type: ALfloat + * Range: [0.0 - 1.0] + * + * Logarthmic + */ +#define AL_MAX_GAIN 0x100E + +/** + * Indicate listener orientation. + * + * at/up + */ +#define AL_ORIENTATION 0x100F + +/** + * Source state information. + */ +#define AL_SOURCE_STATE 0x1010 +#define AL_INITIAL 0x1011 +#define AL_PLAYING 0x1012 +#define AL_PAUSED 0x1013 +#define AL_STOPPED 0x1014 + +/** + * Buffer Queue params + */ +#define AL_BUFFERS_QUEUED 0x1015 +#define AL_BUFFERS_PROCESSED 0x1016 + +/** + * Source buffer position information + */ +#define AL_SEC_OFFSET 0x1024 +#define AL_SAMPLE_OFFSET 0x1025 +#define AL_BYTE_OFFSET 0x1026 + +/* + * Source type (Static, Streaming or undetermined) + * Source is Static if a Buffer has been attached using AL_BUFFER + * Source is Streaming if one or more Buffers have been attached using alSourceQueueBuffers + * Source is undetermined when it has the NULL buffer attached + */ +#define AL_SOURCE_TYPE 0x1027 +#define AL_STATIC 0x1028 +#define AL_STREAMING 0x1029 +#define AL_UNDETERMINED 0x1030 + +/** Sound samples: format specifier. */ +#define AL_FORMAT_MONO8 0x1100 +#define AL_FORMAT_MONO16 0x1101 +#define AL_FORMAT_STEREO8 0x1102 +#define AL_FORMAT_STEREO16 0x1103 + +/** + * source specific reference distance + * Type: ALfloat + * Range: 0.0 - +inf + * + * At 0.0, no distance attenuation occurs. Default is + * 1.0. + */ +#define AL_REFERENCE_DISTANCE 0x1020 + +/** + * source specific rolloff factor + * Type: ALfloat + * Range: 0.0 - +inf + * + */ +#define AL_ROLLOFF_FACTOR 0x1021 + +/** + * Directional source, outer cone gain. + * + * Default: 0.0 + * Range: [0.0 - 1.0] + * Logarithmic + */ +#define AL_CONE_OUTER_GAIN 0x1022 + +/** + * Indicate distance above which sources are not + * attenuated using the inverse clamped distance model. + * + * Default: +inf + * Type: ALfloat + * Range: 0.0 - +inf + */ +#define AL_MAX_DISTANCE 0x1023 + +/** + * Sound samples: frequency, in units of Hertz [Hz]. + * This is the number of samples per second. Half of the + * sample frequency marks the maximum significant + * frequency component. + */ +#define AL_FREQUENCY 0x2001 +#define AL_BITS 0x2002 +#define AL_CHANNELS 0x2003 +#define AL_SIZE 0x2004 + +/** + * Buffer state. + * + * Not supported for public use (yet). + */ +#define AL_UNUSED 0x2010 +#define AL_PENDING 0x2011 +#define AL_PROCESSED 0x2012 + + +/** Errors: No Error. */ +#define AL_NO_ERROR 0 + +/** + * Invalid Name paramater passed to AL call. + */ +#define AL_INVALID_NAME 0xA001 + +/** + * Invalid parameter passed to AL call. + */ +#define AL_INVALID_ENUM 0xA002 + +/** + * Invalid enum parameter value. + */ +#define AL_INVALID_VALUE 0xA003 + +/** + * Illegal call. + */ +#define AL_INVALID_OPERATION 0xA004 + + +/** + * No mojo. + */ +#define AL_OUT_OF_MEMORY 0xA005 + + +/** Context strings: Vendor Name. */ +#define AL_VENDOR 0xB001 +#define AL_VERSION 0xB002 +#define AL_RENDERER 0xB003 +#define AL_EXTENSIONS 0xB004 + +/** Global tweakage. */ + +/** + * Doppler scale. Default 1.0 + */ +#define AL_DOPPLER_FACTOR 0xC000 + +/** + * Tweaks speed of propagation. + */ +#define AL_DOPPLER_VELOCITY 0xC001 + +/** + * Speed of Sound in units per second + */ +#define AL_SPEED_OF_SOUND 0xC003 + +/** + * Distance models + * + * used in conjunction with DistanceModel + * + * implicit: NONE, which disances distance attenuation. + */ +#define AL_DISTANCE_MODEL 0xD000 +#define AL_INVERSE_DISTANCE 0xD001 +#define AL_INVERSE_DISTANCE_CLAMPED 0xD002 +#define AL_LINEAR_DISTANCE 0xD003 +#define AL_LINEAR_DISTANCE_CLAMPED 0xD004 +#define AL_EXPONENT_DISTANCE 0xD005 +#define AL_EXPONENT_DISTANCE_CLAMPED 0xD006 + +/* + * Renderer State management + */ +AL_API void AL_APIENTRY alEnable( ALenum capability ); + +AL_API void AL_APIENTRY alDisable( ALenum capability ); + +AL_API ALboolean AL_APIENTRY alIsEnabled( ALenum capability ); + + +/* + * State retrieval + */ +AL_API const ALchar* AL_APIENTRY alGetString( ALenum param ); + +AL_API void AL_APIENTRY alGetBooleanv( ALenum param, ALboolean* data ); + +AL_API void AL_APIENTRY alGetIntegerv( ALenum param, ALint* data ); + +AL_API void AL_APIENTRY alGetFloatv( ALenum param, ALfloat* data ); + +AL_API void AL_APIENTRY alGetDoublev( ALenum param, ALdouble* data ); + +AL_API ALboolean AL_APIENTRY alGetBoolean( ALenum param ); + +AL_API ALint AL_APIENTRY alGetInteger( ALenum param ); + +AL_API ALfloat AL_APIENTRY alGetFloat( ALenum param ); + +AL_API ALdouble AL_APIENTRY alGetDouble( ALenum param ); + + +/* + * Error support. + * Obtain the most recent error generated in the AL state machine. + */ +AL_API ALenum AL_APIENTRY alGetError( void ); + + +/* + * Extension support. + * Query for the presence of an extension, and obtain any appropriate + * function pointers and enum values. + */ +AL_API ALboolean AL_APIENTRY alIsExtensionPresent( const ALchar* extname ); + +AL_API void* AL_APIENTRY alGetProcAddress( const ALchar* fname ); + +AL_API ALenum AL_APIENTRY alGetEnumValue( const ALchar* ename ); + + +/* + * LISTENER + * Listener represents the location and orientation of the + * 'user' in 3D-space. + * + * Properties include: - + * + * Gain AL_GAIN ALfloat + * Position AL_POSITION ALfloat[3] + * Velocity AL_VELOCITY ALfloat[3] + * Orientation AL_ORIENTATION ALfloat[6] (Forward then Up vectors) +*/ + +/* + * Set Listener parameters + */ +AL_API void AL_APIENTRY alListenerf( ALenum param, ALfloat value ); + +AL_API void AL_APIENTRY alListener3f( ALenum param, ALfloat value1, ALfloat value2, ALfloat value3 ); + +AL_API void AL_APIENTRY alListenerfv( ALenum param, const ALfloat* values ); + +AL_API void AL_APIENTRY alListeneri( ALenum param, ALint value ); + +AL_API void AL_APIENTRY alListener3i( ALenum param, ALint value1, ALint value2, ALint value3 ); + +AL_API void AL_APIENTRY alListeneriv( ALenum param, const ALint* values ); + +/* + * Get Listener parameters + */ +AL_API void AL_APIENTRY alGetListenerf( ALenum param, ALfloat* value ); + +AL_API void AL_APIENTRY alGetListener3f( ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3 ); + +AL_API void AL_APIENTRY alGetListenerfv( ALenum param, ALfloat* values ); + +AL_API void AL_APIENTRY alGetListeneri( ALenum param, ALint* value ); + +AL_API void AL_APIENTRY alGetListener3i( ALenum param, ALint *value1, ALint *value2, ALint *value3 ); + +AL_API void AL_APIENTRY alGetListeneriv( ALenum param, ALint* values ); + + +/** + * SOURCE + * Sources represent individual sound objects in 3D-space. + * Sources take the PCM data provided in the specified Buffer, + * apply Source-specific modifications, and then + * submit them to be mixed according to spatial arrangement etc. + * + * Properties include: - + * + * Gain AL_GAIN ALfloat + * Min Gain AL_MIN_GAIN ALfloat + * Max Gain AL_MAX_GAIN ALfloat + * Position AL_POSITION ALfloat[3] + * Velocity AL_VELOCITY ALfloat[3] + * Direction AL_DIRECTION ALfloat[3] + * Head Relative Mode AL_SOURCE_RELATIVE ALint (AL_TRUE or AL_FALSE) + * Reference Distance AL_REFERENCE_DISTANCE ALfloat + * Max Distance AL_MAX_DISTANCE ALfloat + * RollOff Factor AL_ROLLOFF_FACTOR ALfloat + * Inner Angle AL_CONE_INNER_ANGLE ALint or ALfloat + * Outer Angle AL_CONE_OUTER_ANGLE ALint or ALfloat + * Cone Outer Gain AL_CONE_OUTER_GAIN ALint or ALfloat + * Pitch AL_PITCH ALfloat + * Looping AL_LOOPING ALint (AL_TRUE or AL_FALSE) + * MS Offset AL_MSEC_OFFSET ALint or ALfloat + * Byte Offset AL_BYTE_OFFSET ALint or ALfloat + * Sample Offset AL_SAMPLE_OFFSET ALint or ALfloat + * Attached Buffer AL_BUFFER ALint + * State (Query only) AL_SOURCE_STATE ALint + * Buffers Queued (Query only) AL_BUFFERS_QUEUED ALint + * Buffers Processed (Query only) AL_BUFFERS_PROCESSED ALint + */ + +/* Create Source objects */ +AL_API void AL_APIENTRY alGenSources( ALsizei n, ALuint* sources ); + +/* Delete Source objects */ +AL_API void AL_APIENTRY alDeleteSources( ALsizei n, const ALuint* sources ); + +/* Verify a handle is a valid Source */ +AL_API ALboolean AL_APIENTRY alIsSource( ALuint sid ); + +/* + * Set Source parameters + */ +AL_API void AL_APIENTRY alSourcef( ALuint sid, ALenum param, ALfloat value ); + +AL_API void AL_APIENTRY alSource3f( ALuint sid, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3 ); + +AL_API void AL_APIENTRY alSourcefv( ALuint sid, ALenum param, const ALfloat* values ); + +AL_API void AL_APIENTRY alSourcei( ALuint sid, ALenum param, ALint value ); + +AL_API void AL_APIENTRY alSource3i( ALuint sid, ALenum param, ALint value1, ALint value2, ALint value3 ); + +AL_API void AL_APIENTRY alSourceiv( ALuint sid, ALenum param, const ALint* values ); + +/* + * Get Source parameters + */ +AL_API void AL_APIENTRY alGetSourcef( ALuint sid, ALenum param, ALfloat* value ); + +AL_API void AL_APIENTRY alGetSource3f( ALuint sid, ALenum param, ALfloat* value1, ALfloat* value2, ALfloat* value3); + +AL_API void AL_APIENTRY alGetSourcefv( ALuint sid, ALenum param, ALfloat* values ); + +AL_API void AL_APIENTRY alGetSourcei( ALuint sid, ALenum param, ALint* value ); + +AL_API void AL_APIENTRY alGetSource3i( ALuint sid, ALenum param, ALint* value1, ALint* value2, ALint* value3); + +AL_API void AL_APIENTRY alGetSourceiv( ALuint sid, ALenum param, ALint* values ); + + +/* + * Source vector based playback calls + */ + +/* Play, replay, or resume (if paused) a list of Sources */ +AL_API void AL_APIENTRY alSourcePlayv( ALsizei ns, const ALuint *sids ); + +/* Stop a list of Sources */ +AL_API void AL_APIENTRY alSourceStopv( ALsizei ns, const ALuint *sids ); + +/* Rewind a list of Sources */ +AL_API void AL_APIENTRY alSourceRewindv( ALsizei ns, const ALuint *sids ); + +/* Pause a list of Sources */ +AL_API void AL_APIENTRY alSourcePausev( ALsizei ns, const ALuint *sids ); + +/* + * Source based playback calls + */ + +/* Play, replay, or resume a Source */ +AL_API void AL_APIENTRY alSourcePlay( ALuint sid ); + +/* Stop a Source */ +AL_API void AL_APIENTRY alSourceStop( ALuint sid ); + +/* Rewind a Source (set playback postiton to beginning) */ +AL_API void AL_APIENTRY alSourceRewind( ALuint sid ); + +/* Pause a Source */ +AL_API void AL_APIENTRY alSourcePause( ALuint sid ); + +/* + * Source Queuing + */ +AL_API void AL_APIENTRY alSourceQueueBuffers( ALuint sid, ALsizei numEntries, const ALuint *bids ); + +AL_API void AL_APIENTRY alSourceUnqueueBuffers( ALuint sid, ALsizei numEntries, ALuint *bids ); + + +/** + * BUFFER + * Buffer objects are storage space for sample data. + * Buffers are referred to by Sources. One Buffer can be used + * by multiple Sources. + * + * Properties include: - + * + * Frequency (Query only) AL_FREQUENCY ALint + * Size (Query only) AL_SIZE ALint + * Bits (Query only) AL_BITS ALint + * Channels (Query only) AL_CHANNELS ALint + */ + +/* Create Buffer objects */ +AL_API void AL_APIENTRY alGenBuffers( ALsizei n, ALuint* buffers ); + +/* Delete Buffer objects */ +AL_API void AL_APIENTRY alDeleteBuffers( ALsizei n, const ALuint* buffers ); + +/* Verify a handle is a valid Buffer */ +AL_API ALboolean AL_APIENTRY alIsBuffer( ALuint bid ); + +/* Specify the data to be copied into a buffer */ +AL_API void AL_APIENTRY alBufferData( ALuint bid, ALenum format, const ALvoid* data, ALsizei size, ALsizei freq ); + +/* + * Set Buffer parameters + */ +AL_API void AL_APIENTRY alBufferf( ALuint bid, ALenum param, ALfloat value ); + +AL_API void AL_APIENTRY alBuffer3f( ALuint bid, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3 ); + +AL_API void AL_APIENTRY alBufferfv( ALuint bid, ALenum param, const ALfloat* values ); + +AL_API void AL_APIENTRY alBufferi( ALuint bid, ALenum param, ALint value ); + +AL_API void AL_APIENTRY alBuffer3i( ALuint bid, ALenum param, ALint value1, ALint value2, ALint value3 ); + +AL_API void AL_APIENTRY alBufferiv( ALuint bid, ALenum param, const ALint* values ); + +/* + * Get Buffer parameters + */ +AL_API void AL_APIENTRY alGetBufferf( ALuint bid, ALenum param, ALfloat* value ); + +AL_API void AL_APIENTRY alGetBuffer3f( ALuint bid, ALenum param, ALfloat* value1, ALfloat* value2, ALfloat* value3); + +AL_API void AL_APIENTRY alGetBufferfv( ALuint bid, ALenum param, ALfloat* values ); + +AL_API void AL_APIENTRY alGetBufferi( ALuint bid, ALenum param, ALint* value ); + +AL_API void AL_APIENTRY alGetBuffer3i( ALuint bid, ALenum param, ALint* value1, ALint* value2, ALint* value3); + +AL_API void AL_APIENTRY alGetBufferiv( ALuint bid, ALenum param, ALint* values ); + + +/* + * Global Parameters + */ +AL_API void AL_APIENTRY alDopplerFactor( ALfloat value ); + +AL_API void AL_APIENTRY alDopplerVelocity( ALfloat value ); + +AL_API void AL_APIENTRY alSpeedOfSound( ALfloat value ); + +AL_API void AL_APIENTRY alDistanceModel( ALenum distanceModel ); + +/* + * Pointer-to-function types, useful for dynamically getting AL entry points. + */ +typedef void (AL_APIENTRY *LPALENABLE)( ALenum capability ); +typedef void (AL_APIENTRY *LPALDISABLE)( ALenum capability ); +typedef ALboolean (AL_APIENTRY *LPALISENABLED)( ALenum capability ); +typedef const ALchar* (AL_APIENTRY *LPALGETSTRING)( ALenum param ); +typedef void (AL_APIENTRY *LPALGETBOOLEANV)( ALenum param, ALboolean* data ); +typedef void (AL_APIENTRY *LPALGETINTEGERV)( ALenum param, ALint* data ); +typedef void (AL_APIENTRY *LPALGETFLOATV)( ALenum param, ALfloat* data ); +typedef void (AL_APIENTRY *LPALGETDOUBLEV)( ALenum param, ALdouble* data ); +typedef ALboolean (AL_APIENTRY *LPALGETBOOLEAN)( ALenum param ); +typedef ALint (AL_APIENTRY *LPALGETINTEGER)( ALenum param ); +typedef ALfloat (AL_APIENTRY *LPALGETFLOAT)( ALenum param ); +typedef ALdouble (AL_APIENTRY *LPALGETDOUBLE)( ALenum param ); +typedef ALenum (AL_APIENTRY *LPALGETERROR)( void ); +typedef ALboolean (AL_APIENTRY *LPALISEXTENSIONPRESENT)(const ALchar* extname ); +typedef void* (AL_APIENTRY *LPALGETPROCADDRESS)( const ALchar* fname ); +typedef ALenum (AL_APIENTRY *LPALGETENUMVALUE)( const ALchar* ename ); +typedef void (AL_APIENTRY *LPALLISTENERF)( ALenum param, ALfloat value ); +typedef void (AL_APIENTRY *LPALLISTENER3F)( ALenum param, ALfloat value1, ALfloat value2, ALfloat value3 ); +typedef void (AL_APIENTRY *LPALLISTENERFV)( ALenum param, const ALfloat* values ); +typedef void (AL_APIENTRY *LPALLISTENERI)( ALenum param, ALint value ); +typedef void (AL_APIENTRY *LPALLISTENER3I)( ALenum param, ALint value1, ALint value2, ALint value3 ); +typedef void (AL_APIENTRY *LPALLISTENERIV)( ALenum param, const ALint* values ); +typedef void (AL_APIENTRY *LPALGETLISTENERF)( ALenum param, ALfloat* value ); +typedef void (AL_APIENTRY *LPALGETLISTENER3F)( ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3 ); +typedef void (AL_APIENTRY *LPALGETLISTENERFV)( ALenum param, ALfloat* values ); +typedef void (AL_APIENTRY *LPALGETLISTENERI)( ALenum param, ALint* value ); +typedef void (AL_APIENTRY *LPALGETLISTENER3I)( ALenum param, ALint *value1, ALint *value2, ALint *value3 ); +typedef void (AL_APIENTRY *LPALGETLISTENERIV)( ALenum param, ALint* values ); +typedef void (AL_APIENTRY *LPALGENSOURCES)( ALsizei n, ALuint* sources ); +typedef void (AL_APIENTRY *LPALDELETESOURCES)( ALsizei n, const ALuint* sources ); +typedef ALboolean (AL_APIENTRY *LPALISSOURCE)( ALuint sid ); +typedef void (AL_APIENTRY *LPALSOURCEF)( ALuint sid, ALenum param, ALfloat value); +typedef void (AL_APIENTRY *LPALSOURCE3F)( ALuint sid, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3 ); +typedef void (AL_APIENTRY *LPALSOURCEFV)( ALuint sid, ALenum param, const ALfloat* values ); +typedef void (AL_APIENTRY *LPALSOURCEI)( ALuint sid, ALenum param, ALint value); +typedef void (AL_APIENTRY *LPALSOURCE3I)( ALuint sid, ALenum param, ALint value1, ALint value2, ALint value3 ); +typedef void (AL_APIENTRY *LPALSOURCEIV)( ALuint sid, ALenum param, const ALint* values ); +typedef void (AL_APIENTRY *LPALGETSOURCEF)( ALuint sid, ALenum param, ALfloat* value ); +typedef void (AL_APIENTRY *LPALGETSOURCE3F)( ALuint sid, ALenum param, ALfloat* value1, ALfloat* value2, ALfloat* value3); +typedef void (AL_APIENTRY *LPALGETSOURCEFV)( ALuint sid, ALenum param, ALfloat* values ); +typedef void (AL_APIENTRY *LPALGETSOURCEI)( ALuint sid, ALenum param, ALint* value ); +typedef void (AL_APIENTRY *LPALGETSOURCE3I)( ALuint sid, ALenum param, ALint* value1, ALint* value2, ALint* value3); +typedef void (AL_APIENTRY *LPALGETSOURCEIV)( ALuint sid, ALenum param, ALint* values ); +typedef void (AL_APIENTRY *LPALSOURCEPLAYV)( ALsizei ns, const ALuint *sids ); +typedef void (AL_APIENTRY *LPALSOURCESTOPV)( ALsizei ns, const ALuint *sids ); +typedef void (AL_APIENTRY *LPALSOURCEREWINDV)( ALsizei ns, const ALuint *sids ); +typedef void (AL_APIENTRY *LPALSOURCEPAUSEV)( ALsizei ns, const ALuint *sids ); +typedef void (AL_APIENTRY *LPALSOURCEPLAY)( ALuint sid ); +typedef void (AL_APIENTRY *LPALSOURCESTOP)( ALuint sid ); +typedef void (AL_APIENTRY *LPALSOURCEREWIND)( ALuint sid ); +typedef void (AL_APIENTRY *LPALSOURCEPAUSE)( ALuint sid ); +typedef void (AL_APIENTRY *LPALSOURCEQUEUEBUFFERS)(ALuint sid, ALsizei numEntries, const ALuint *bids ); +typedef void (AL_APIENTRY *LPALSOURCEUNQUEUEBUFFERS)(ALuint sid, ALsizei numEntries, ALuint *bids ); +typedef void (AL_APIENTRY *LPALGENBUFFERS)( ALsizei n, ALuint* buffers ); +typedef void (AL_APIENTRY *LPALDELETEBUFFERS)( ALsizei n, const ALuint* buffers ); +typedef ALboolean (AL_APIENTRY *LPALISBUFFER)( ALuint bid ); +typedef void (AL_APIENTRY *LPALBUFFERDATA)( ALuint bid, ALenum format, const ALvoid* data, ALsizei size, ALsizei freq ); +typedef void (AL_APIENTRY *LPALBUFFERF)( ALuint bid, ALenum param, ALfloat value); +typedef void (AL_APIENTRY *LPALBUFFER3F)( ALuint bid, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3 ); +typedef void (AL_APIENTRY *LPALBUFFERFV)( ALuint bid, ALenum param, const ALfloat* values ); +typedef void (AL_APIENTRY *LPALBUFFERI)( ALuint bid, ALenum param, ALint value); +typedef void (AL_APIENTRY *LPALBUFFER3I)( ALuint bid, ALenum param, ALint value1, ALint value2, ALint value3 ); +typedef void (AL_APIENTRY *LPALBUFFERIV)( ALuint bid, ALenum param, const ALint* values ); +typedef void (AL_APIENTRY *LPALGETBUFFERF)( ALuint bid, ALenum param, ALfloat* value ); +typedef void (AL_APIENTRY *LPALGETBUFFER3F)( ALuint bid, ALenum param, ALfloat* value1, ALfloat* value2, ALfloat* value3); +typedef void (AL_APIENTRY *LPALGETBUFFERFV)( ALuint bid, ALenum param, ALfloat* values ); +typedef void (AL_APIENTRY *LPALGETBUFFERI)( ALuint bid, ALenum param, ALint* value ); +typedef void (AL_APIENTRY *LPALGETBUFFER3I)( ALuint bid, ALenum param, ALint* value1, ALint* value2, ALint* value3); +typedef void (AL_APIENTRY *LPALGETBUFFERIV)( ALuint bid, ALenum param, ALint* values ); +typedef void (AL_APIENTRY *LPALDOPPLERFACTOR)( ALfloat value ); +typedef void (AL_APIENTRY *LPALDOPPLERVELOCITY)( ALfloat value ); +typedef void (AL_APIENTRY *LPALSPEEDOFSOUND)( ALfloat value ); +typedef void (AL_APIENTRY *LPALDISTANCEMODEL)( ALenum distanceModel ); + +#if defined(TARGET_OS_MAC) && TARGET_OS_MAC + #pragma export off +#endif + +#if defined(__cplusplus) +} /* extern "C" */ +#endif + +#endif /* AL_AL_H */ diff --git a/Lib/Include/AL/alc.h b/Lib/Include/AL/alc.h new file mode 100644 index 0000000..22639f8 --- /dev/null +++ b/Lib/Include/AL/alc.h @@ -0,0 +1,280 @@ +#ifndef AL_ALC_H +#define AL_ALC_H + +#if defined(__cplusplus) +extern "C" { +#endif + +#ifndef ALC_API + #if defined(AL_LIBTYPE_STATIC) + #define ALC_API + #elif defined(_WIN32) + #define ALC_API __declspec(dllimport) + #else + #define ALC_API extern + #endif +#endif + +#if defined(_WIN32) + #define ALC_APIENTRY __cdecl +#else + #define ALC_APIENTRY +#endif + +#if defined(TARGET_OS_MAC) && TARGET_OS_MAC + #pragma export on +#endif + +/* + * The ALCAPI, ALCAPIENTRY, and ALC_INVALID macros are deprecated, but are + * included for applications porting code from AL 1.0 + */ +#define ALCAPI ALC_API +#define ALCAPIENTRY ALC_APIENTRY +#define ALC_INVALID 0 + + +#define ALC_VERSION_0_1 1 + +typedef struct ALCdevice_struct ALCdevice; +typedef struct ALCcontext_struct ALCcontext; + + +/** 8-bit boolean */ +typedef char ALCboolean; + +/** character */ +typedef char ALCchar; + +/** signed 8-bit 2's complement integer */ +typedef signed char ALCbyte; + +/** unsigned 8-bit integer */ +typedef unsigned char ALCubyte; + +/** signed 16-bit 2's complement integer */ +typedef short ALCshort; + +/** unsigned 16-bit integer */ +typedef unsigned short ALCushort; + +/** signed 32-bit 2's complement integer */ +typedef int ALCint; + +/** unsigned 32-bit integer */ +typedef unsigned int ALCuint; + +/** non-negative 32-bit binary integer size */ +typedef int ALCsizei; + +/** enumerated 32-bit value */ +typedef int ALCenum; + +/** 32-bit IEEE754 floating-point */ +typedef float ALCfloat; + +/** 64-bit IEEE754 floating-point */ +typedef double ALCdouble; + +/** void type (for opaque pointers only) */ +typedef void ALCvoid; + + +/* Enumerant values begin at column 50. No tabs. */ + +/* Boolean False. */ +#define ALC_FALSE 0 + +/* Boolean True. */ +#define ALC_TRUE 1 + +/** + * followed by Hz + */ +#define ALC_FREQUENCY 0x1007 + +/** + * followed by Hz + */ +#define ALC_REFRESH 0x1008 + +/** + * followed by AL_TRUE, AL_FALSE + */ +#define ALC_SYNC 0x1009 + +/** + * followed by Num of requested Mono (3D) Sources + */ +#define ALC_MONO_SOURCES 0x1010 + +/** + * followed by Num of requested Stereo Sources + */ +#define ALC_STEREO_SOURCES 0x1011 + +/** + * errors + */ + +/** + * No error + */ +#define ALC_NO_ERROR 0 + +/** + * No device + */ +#define ALC_INVALID_DEVICE 0xA001 + +/** + * invalid context ID + */ +#define ALC_INVALID_CONTEXT 0xA002 + +/** + * bad enum + */ +#define ALC_INVALID_ENUM 0xA003 + +/** + * bad value + */ +#define ALC_INVALID_VALUE 0xA004 + +/** + * Out of memory. + */ +#define ALC_OUT_OF_MEMORY 0xA005 + + +/** + * The Specifier string for default device + */ +#define ALC_DEFAULT_DEVICE_SPECIFIER 0x1004 +#define ALC_DEVICE_SPECIFIER 0x1005 +#define ALC_EXTENSIONS 0x1006 + +#define ALC_MAJOR_VERSION 0x1000 +#define ALC_MINOR_VERSION 0x1001 + +#define ALC_ATTRIBUTES_SIZE 0x1002 +#define ALC_ALL_ATTRIBUTES 0x1003 + + +/** + * Capture extension + */ +#define ALC_EXT_CAPTURE 1 +#define ALC_CAPTURE_DEVICE_SPECIFIER 0x310 +#define ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER 0x311 +#define ALC_CAPTURE_SAMPLES 0x312 + + +/** + * ALC_ENUMERATE_ALL_EXT enums + */ +#define ALC_ENUMERATE_ALL_EXT 1 +#define ALC_DEFAULT_ALL_DEVICES_SPECIFIER 0x1012 +#define ALC_ALL_DEVICES_SPECIFIER 0x1013 + + +/* + * Context Management + */ +ALC_API ALCcontext * ALC_APIENTRY alcCreateContext( ALCdevice *device, const ALCint* attrlist ); + +ALC_API ALCboolean ALC_APIENTRY alcMakeContextCurrent( ALCcontext *context ); + +ALC_API void ALC_APIENTRY alcProcessContext( ALCcontext *context ); + +ALC_API void ALC_APIENTRY alcSuspendContext( ALCcontext *context ); + +ALC_API void ALC_APIENTRY alcDestroyContext( ALCcontext *context ); + +ALC_API ALCcontext * ALC_APIENTRY alcGetCurrentContext( void ); + +ALC_API ALCdevice* ALC_APIENTRY alcGetContextsDevice( ALCcontext *context ); + + +/* + * Device Management + */ +ALC_API ALCdevice * ALC_APIENTRY alcOpenDevice( const ALCchar *devicename ); + +ALC_API ALCboolean ALC_APIENTRY alcCloseDevice( ALCdevice *device ); + + +/* + * Error support. + * Obtain the most recent Context error + */ +ALC_API ALCenum ALC_APIENTRY alcGetError( ALCdevice *device ); + + +/* + * Extension support. + * Query for the presence of an extension, and obtain any appropriate + * function pointers and enum values. + */ +ALC_API ALCboolean ALC_APIENTRY alcIsExtensionPresent( ALCdevice *device, const ALCchar *extname ); + +ALC_API void * ALC_APIENTRY alcGetProcAddress( ALCdevice *device, const ALCchar *funcname ); + +ALC_API ALCenum ALC_APIENTRY alcGetEnumValue( ALCdevice *device, const ALCchar *enumname ); + + +/* + * Query functions + */ +ALC_API const ALCchar * ALC_APIENTRY alcGetString( ALCdevice *device, ALCenum param ); + +ALC_API void ALC_APIENTRY alcGetIntegerv( ALCdevice *device, ALCenum param, ALCsizei size, ALCint *data ); + + +/* + * Capture functions + */ +ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice( const ALCchar *devicename, ALCuint frequency, ALCenum format, ALCsizei buffersize ); + +ALC_API ALCboolean ALC_APIENTRY alcCaptureCloseDevice( ALCdevice *device ); + +ALC_API void ALC_APIENTRY alcCaptureStart( ALCdevice *device ); + +ALC_API void ALC_APIENTRY alcCaptureStop( ALCdevice *device ); + +ALC_API void ALC_APIENTRY alcCaptureSamples( ALCdevice *device, ALCvoid *buffer, ALCsizei samples ); + +/* + * Pointer-to-function types, useful for dynamically getting ALC entry points. + */ +typedef ALCcontext * (ALC_APIENTRY *LPALCCREATECONTEXT) (ALCdevice *device, const ALCint *attrlist); +typedef ALCboolean (ALC_APIENTRY *LPALCMAKECONTEXTCURRENT)( ALCcontext *context ); +typedef void (ALC_APIENTRY *LPALCPROCESSCONTEXT)( ALCcontext *context ); +typedef void (ALC_APIENTRY *LPALCSUSPENDCONTEXT)( ALCcontext *context ); +typedef void (ALC_APIENTRY *LPALCDESTROYCONTEXT)( ALCcontext *context ); +typedef ALCcontext * (ALC_APIENTRY *LPALCGETCURRENTCONTEXT)( void ); +typedef ALCdevice * (ALC_APIENTRY *LPALCGETCONTEXTSDEVICE)( ALCcontext *context ); +typedef ALCdevice * (ALC_APIENTRY *LPALCOPENDEVICE)( const ALCchar *devicename ); +typedef ALCboolean (ALC_APIENTRY *LPALCCLOSEDEVICE)( ALCdevice *device ); +typedef ALCenum (ALC_APIENTRY *LPALCGETERROR)( ALCdevice *device ); +typedef ALCboolean (ALC_APIENTRY *LPALCISEXTENSIONPRESENT)( ALCdevice *device, const ALCchar *extname ); +typedef void * (ALC_APIENTRY *LPALCGETPROCADDRESS)(ALCdevice *device, const ALCchar *funcname ); +typedef ALCenum (ALC_APIENTRY *LPALCGETENUMVALUE)(ALCdevice *device, const ALCchar *enumname ); +typedef const ALCchar* (ALC_APIENTRY *LPALCGETSTRING)( ALCdevice *device, ALCenum param ); +typedef void (ALC_APIENTRY *LPALCGETINTEGERV)( ALCdevice *device, ALCenum param, ALCsizei size, ALCint *dest ); +typedef ALCdevice * (ALC_APIENTRY *LPALCCAPTUREOPENDEVICE)( const ALCchar *devicename, ALCuint frequency, ALCenum format, ALCsizei buffersize ); +typedef ALCboolean (ALC_APIENTRY *LPALCCAPTURECLOSEDEVICE)( ALCdevice *device ); +typedef void (ALC_APIENTRY *LPALCCAPTURESTART)( ALCdevice *device ); +typedef void (ALC_APIENTRY *LPALCCAPTURESTOP)( ALCdevice *device ); +typedef void (ALC_APIENTRY *LPALCCAPTURESAMPLES)( ALCdevice *device, ALCvoid *buffer, ALCsizei samples ); + +#if defined(TARGET_OS_MAC) && TARGET_OS_MAC + #pragma export off +#endif + +#if defined(__cplusplus) +} +#endif + +#endif /* AL_ALC_H */ diff --git a/Lib/Include/AL/alext.h b/Lib/Include/AL/alext.h new file mode 100644 index 0000000..eef1ed8 --- /dev/null +++ b/Lib/Include/AL/alext.h @@ -0,0 +1,296 @@ +/** + * OpenAL cross platform audio library + * Copyright (C) 2008 by authors. + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#ifndef AL_ALEXT_H +#define AL_ALEXT_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef AL_LOKI_IMA_ADPCM_format +#define AL_LOKI_IMA_ADPCM_format 1 +#define AL_FORMAT_IMA_ADPCM_MONO16_EXT 0x10000 +#define AL_FORMAT_IMA_ADPCM_STEREO16_EXT 0x10001 +#endif + +#ifndef AL_LOKI_WAVE_format +#define AL_LOKI_WAVE_format 1 +#define AL_FORMAT_WAVE_EXT 0x10002 +#endif + +#ifndef AL_EXT_vorbis +#define AL_EXT_vorbis 1 +#define AL_FORMAT_VORBIS_EXT 0x10003 +#endif + +#ifndef AL_LOKI_quadriphonic +#define AL_LOKI_quadriphonic 1 +#define AL_FORMAT_QUAD8_LOKI 0x10004 +#define AL_FORMAT_QUAD16_LOKI 0x10005 +#endif + +#ifndef AL_EXT_float32 +#define AL_EXT_float32 1 +#define AL_FORMAT_MONO_FLOAT32 0x10010 +#define AL_FORMAT_STEREO_FLOAT32 0x10011 +#endif + +#ifndef AL_EXT_double +#define AL_EXT_double 1 +#define AL_FORMAT_MONO_DOUBLE_EXT 0x10012 +#define AL_FORMAT_STEREO_DOUBLE_EXT 0x10013 +#endif + +#ifndef AL_EXT_MULAW +#define AL_EXT_MULAW 1 +#define AL_FORMAT_MONO_MULAW_EXT 0x10014 +#define AL_FORMAT_STEREO_MULAW_EXT 0x10015 +#endif + +#ifndef AL_EXT_ALAW +#define AL_EXT_ALAW 1 +#define AL_FORMAT_MONO_ALAW_EXT 0x10016 +#define AL_FORMAT_STEREO_ALAW_EXT 0x10017 +#endif + +#ifndef ALC_LOKI_audio_channel +#define ALC_LOKI_audio_channel 1 +#define ALC_CHAN_MAIN_LOKI 0x500001 +#define ALC_CHAN_PCM_LOKI 0x500002 +#define ALC_CHAN_CD_LOKI 0x500003 +#endif + +#ifndef AL_EXT_MCFORMATS +#define AL_EXT_MCFORMATS 1 +#define AL_FORMAT_QUAD8 0x1204 +#define AL_FORMAT_QUAD16 0x1205 +#define AL_FORMAT_QUAD32 0x1206 +#define AL_FORMAT_REAR8 0x1207 +#define AL_FORMAT_REAR16 0x1208 +#define AL_FORMAT_REAR32 0x1209 +#define AL_FORMAT_51CHN8 0x120A +#define AL_FORMAT_51CHN16 0x120B +#define AL_FORMAT_51CHN32 0x120C +#define AL_FORMAT_61CHN8 0x120D +#define AL_FORMAT_61CHN16 0x120E +#define AL_FORMAT_61CHN32 0x120F +#define AL_FORMAT_71CHN8 0x1210 +#define AL_FORMAT_71CHN16 0x1211 +#define AL_FORMAT_71CHN32 0x1212 +#endif + +#ifndef AL_EXT_MULAW_MCFORMATS +#define AL_EXT_MULAW_MCFORMATS 1 +#define AL_FORMAT_MONO_MULAW 0x10014 +#define AL_FORMAT_STEREO_MULAW 0x10015 +#define AL_FORMAT_QUAD_MULAW 0x10021 +#define AL_FORMAT_REAR_MULAW 0x10022 +#define AL_FORMAT_51CHN_MULAW 0x10023 +#define AL_FORMAT_61CHN_MULAW 0x10024 +#define AL_FORMAT_71CHN_MULAW 0x10025 +#endif + +#ifndef AL_EXT_IMA4 +#define AL_EXT_IMA4 1 +#define AL_FORMAT_MONO_IMA4 0x1300 +#define AL_FORMAT_STEREO_IMA4 0x1301 +#endif + +#ifndef AL_EXT_STATIC_BUFFER +#define AL_EXT_STATIC_BUFFER 1 +typedef ALvoid (AL_APIENTRY*PFNALBUFFERDATASTATICPROC)(const ALint,ALenum,ALvoid*,ALsizei,ALsizei); +#ifdef AL_ALEXT_PROTOTYPES +AL_API ALvoid AL_APIENTRY alBufferDataStatic(const ALint buffer, ALenum format, ALvoid *data, ALsizei len, ALsizei freq); +#endif +#endif + +#ifndef ALC_EXT_EFX +#define ALC_EXT_EFX 1 +#include "efx.h" +#endif + +#ifndef ALC_EXT_disconnect +#define ALC_EXT_disconnect 1 +#define ALC_CONNECTED 0x313 +#endif + +#ifndef ALC_EXT_thread_local_context +#define ALC_EXT_thread_local_context 1 +typedef ALCboolean (ALC_APIENTRY*PFNALCSETTHREADCONTEXTPROC)(ALCcontext *context); +typedef ALCcontext* (ALC_APIENTRY*PFNALCGETTHREADCONTEXTPROC)(void); +#ifdef AL_ALEXT_PROTOTYPES +ALC_API ALCboolean ALC_APIENTRY alcSetThreadContext(ALCcontext *context); +ALC_API ALCcontext* ALC_APIENTRY alcGetThreadContext(void); +#endif +#endif + +#ifndef AL_EXT_source_distance_model +#define AL_EXT_source_distance_model 1 +#define AL_SOURCE_DISTANCE_MODEL 0x200 +#endif + +#ifndef AL_SOFT_buffer_sub_data +#define AL_SOFT_buffer_sub_data 1 +#define AL_BYTE_RW_OFFSETS_SOFT 0x1031 +#define AL_SAMPLE_RW_OFFSETS_SOFT 0x1032 +typedef ALvoid (AL_APIENTRY*PFNALBUFFERSUBDATASOFTPROC)(ALuint,ALenum,const ALvoid*,ALsizei,ALsizei); +#ifdef AL_ALEXT_PROTOTYPES +AL_API ALvoid AL_APIENTRY alBufferSubDataSOFT(ALuint buffer,ALenum format,const ALvoid *data,ALsizei offset,ALsizei length); +#endif +#endif + +#ifndef AL_SOFT_loop_points +#define AL_SOFT_loop_points 1 +#define AL_LOOP_POINTS_SOFT 0x2015 +#endif + +#ifndef AL_EXT_FOLDBACK +#define AL_EXT_FOLDBACK 1 +#define AL_EXT_FOLDBACK_NAME "AL_EXT_FOLDBACK" +#define AL_FOLDBACK_EVENT_BLOCK 0x4112 +#define AL_FOLDBACK_EVENT_START 0x4111 +#define AL_FOLDBACK_EVENT_STOP 0x4113 +#define AL_FOLDBACK_MODE_MONO 0x4101 +#define AL_FOLDBACK_MODE_STEREO 0x4102 +typedef void (AL_APIENTRY*LPALFOLDBACKCALLBACK)(ALenum,ALsizei); +typedef void (AL_APIENTRY*LPALREQUESTFOLDBACKSTART)(ALenum,ALsizei,ALsizei,ALfloat*,LPALFOLDBACKCALLBACK); +typedef void (AL_APIENTRY*LPALREQUESTFOLDBACKSTOP)(void); +#ifdef AL_ALEXT_PROTOTYPES +AL_API void AL_APIENTRY alRequestFoldbackStart(ALenum mode,ALsizei count,ALsizei length,ALfloat *mem,LPALFOLDBACKCALLBACK callback); +AL_API void AL_APIENTRY alRequestFoldbackStop(void); +#endif +#endif + +#ifndef ALC_EXT_DEDICATED +#define ALC_EXT_DEDICATED 1 +#define AL_DEDICATED_GAIN 0x0001 +#define AL_EFFECT_DEDICATED_DIALOGUE 0x9001 +#define AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT 0x9000 +#endif + +#ifndef AL_SOFT_buffer_samples +#define AL_SOFT_buffer_samples 1 +/* Channel configurations */ +#define AL_MONO_SOFT 0x1500 +#define AL_STEREO_SOFT 0x1501 +#define AL_REAR_SOFT 0x1502 +#define AL_QUAD_SOFT 0x1503 +#define AL_5POINT1_SOFT 0x1504 +#define AL_6POINT1_SOFT 0x1505 +#define AL_7POINT1_SOFT 0x1506 + +/* Sample types */ +#define AL_BYTE_SOFT 0x1400 +#define AL_UNSIGNED_BYTE_SOFT 0x1401 +#define AL_SHORT_SOFT 0x1402 +#define AL_UNSIGNED_SHORT_SOFT 0x1403 +#define AL_INT_SOFT 0x1404 +#define AL_UNSIGNED_INT_SOFT 0x1405 +#define AL_FLOAT_SOFT 0x1406 +#define AL_DOUBLE_SOFT 0x1407 +#define AL_BYTE3_SOFT 0x1408 +#define AL_UNSIGNED_BYTE3_SOFT 0x1409 + +/* Storage formats */ +#define AL_MONO8_SOFT 0x1100 +#define AL_MONO16_SOFT 0x1101 +#define AL_MONO32F_SOFT 0x10010 +#define AL_STEREO8_SOFT 0x1102 +#define AL_STEREO16_SOFT 0x1103 +#define AL_STEREO32F_SOFT 0x10011 +#define AL_QUAD8_SOFT 0x1204 +#define AL_QUAD16_SOFT 0x1205 +#define AL_QUAD32F_SOFT 0x1206 +#define AL_REAR8_SOFT 0x1207 +#define AL_REAR16_SOFT 0x1208 +#define AL_REAR32F_SOFT 0x1209 +#define AL_5POINT1_8_SOFT 0x120A +#define AL_5POINT1_16_SOFT 0x120B +#define AL_5POINT1_32F_SOFT 0x120C +#define AL_6POINT1_8_SOFT 0x120D +#define AL_6POINT1_16_SOFT 0x120E +#define AL_6POINT1_32F_SOFT 0x120F +#define AL_7POINT1_8_SOFT 0x1210 +#define AL_7POINT1_16_SOFT 0x1211 +#define AL_7POINT1_32F_SOFT 0x1212 + +/* Buffer attributes */ +#define AL_INTERNAL_FORMAT_SOFT 0x2008 +#define AL_BYTE_LENGTH_SOFT 0x2009 +#define AL_SAMPLE_LENGTH_SOFT 0x200A +#define AL_SEC_LENGTH_SOFT 0x200B + +typedef void (AL_APIENTRY*LPALBUFFERSAMPLESSOFT)(ALuint,ALuint,ALenum,ALsizei,ALenum,ALenum,const ALvoid*); +typedef void (AL_APIENTRY*LPALBUFFERSUBSAMPLESSOFT)(ALuint,ALsizei,ALsizei,ALenum,ALenum,const ALvoid*); +typedef void (AL_APIENTRY*LPALGETBUFFERSAMPLESSOFT)(ALuint,ALsizei,ALsizei,ALenum,ALenum,ALvoid*); +typedef ALboolean (AL_APIENTRY*LPALISBUFFERFORMATSUPPORTEDSOFT)(ALenum); +#ifdef AL_ALEXT_PROTOTYPES +AL_API void AL_APIENTRY alBufferSamplesSOFT(ALuint buffer, ALuint samplerate, ALenum internalformat, ALsizei samples, ALenum channels, ALenum type, const ALvoid *data); +AL_API void AL_APIENTRY alBufferSubSamplesSOFT(ALuint buffer, ALsizei offset, ALsizei samples, ALenum channels, ALenum type, const ALvoid *data); +AL_API void AL_APIENTRY alGetBufferSamplesSOFT(ALuint buffer, ALsizei offset, ALsizei samples, ALenum channels, ALenum type, ALvoid *data); +AL_API ALboolean AL_APIENTRY alIsBufferFormatSupportedSOFT(ALenum format); +#endif +#endif + +#ifndef AL_SOFT_direct_channels +#define AL_SOFT_direct_channels 1 +#define AL_DIRECT_CHANNELS_SOFT 0x1033 +#endif + +#ifndef ALC_SOFT_loopback +#define ALC_SOFT_loopback 1 +#define ALC_FORMAT_CHANNELS_SOFT 0x1990 +#define ALC_FORMAT_TYPE_SOFT 0x1991 + +/* Sample types */ +#define ALC_BYTE_SOFT 0x1400 +#define ALC_UNSIGNED_BYTE_SOFT 0x1401 +#define ALC_SHORT_SOFT 0x1402 +#define ALC_UNSIGNED_SHORT_SOFT 0x1403 +#define ALC_INT_SOFT 0x1404 +#define ALC_UNSIGNED_INT_SOFT 0x1405 +#define ALC_FLOAT_SOFT 0x1406 + +/* Channel configurations */ +#define ALC_MONO_SOFT 0x1500 +#define ALC_STEREO_SOFT 0x1501 +#define ALC_QUAD_SOFT 0x1503 +#define ALC_5POINT1_SOFT 0x1504 +#define ALC_6POINT1_SOFT 0x1505 +#define ALC_7POINT1_SOFT 0x1506 + +typedef ALCdevice* (ALC_APIENTRY*LPALCLOOPBACKOPENDEVICESOFT)(const ALCchar*); +typedef ALCboolean (ALC_APIENTRY*LPALCISRENDERFORMATSUPPORTEDSOFT)(ALCdevice*,ALCsizei,ALCenum,ALCenum); +typedef void (ALC_APIENTRY*LPALCRENDERSAMPLESSOFT)(ALCdevice*,ALCvoid*,ALCsizei); +#ifdef AL_ALEXT_PROTOTYPES +ALC_API ALCdevice* ALC_APIENTRY alcLoopbackOpenDeviceSOFT(const ALCchar *deviceName); +ALC_API ALCboolean ALC_APIENTRY alcIsRenderFormatSupportedSOFT(ALCdevice *device, ALCsizei freq, ALCenum channels, ALCenum type); +ALC_API void ALC_APIENTRY alcRenderSamplesSOFT(ALCdevice *device, ALCvoid *buffer, ALCsizei samples); +#endif +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Lib/Include/AL/efx-creative.h b/Lib/Include/AL/efx-creative.h new file mode 100644 index 0000000..0a04c98 --- /dev/null +++ b/Lib/Include/AL/efx-creative.h @@ -0,0 +1,3 @@ +/* The tokens that would be defined here are already defined in efx.h. This + * empty file is here to provide compatibility with Windows-based projects + * that would include it. */ diff --git a/Lib/Include/AL/efx-presets.h b/Lib/Include/AL/efx-presets.h new file mode 100644 index 0000000..86dcbda --- /dev/null +++ b/Lib/Include/AL/efx-presets.h @@ -0,0 +1,402 @@ +/* Reverb presets for EFX */ + +#ifndef EFX_PRESETS_H +#define EFX_PRESETS_H + +#ifndef EFXEAXREVERBPROPERTIES_DEFINED +#define EFXEAXREVERBPROPERTIES_DEFINED +typedef struct { + float flDensity; + float flDiffusion; + float flGain; + float flGainHF; + float flGainLF; + float flDecayTime; + float flDecayHFRatio; + float flDecayLFRatio; + float flReflectionsGain; + float flReflectionsDelay; + float flReflectionsPan[3]; + float flLateReverbGain; + float flLateReverbDelay; + float flLateReverbPan[3]; + float flEchoTime; + float flEchoDepth; + float flModulationTime; + float flModulationDepth; + float flAirAbsorptionGainHF; + float flHFReference; + float flLFReference; + float flRoomRolloffFactor; + int iDecayHFLimit; +} EFXEAXREVERBPROPERTIES, *LPEFXEAXREVERBPROPERTIES; +#endif + +/* Default Presets */ + +#define EFX_REVERB_PRESET_GENERIC \ + { 1.0000f, 1.0000f, 0.3162f, 0.8913f, 1.0000f, 1.4900f, 0.8300f, 1.0000f, 0.0500f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_PADDEDCELL \ + { 0.1715f, 1.0000f, 0.3162f, 0.0010f, 1.0000f, 0.1700f, 0.1000f, 1.0000f, 0.2500f, 0.0010f, { 0.0000f, 0.0000f, 0.0000f }, 1.2691f, 0.0020f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_ROOM \ + { 0.4287f, 1.0000f, 0.3162f, 0.5929f, 1.0000f, 0.4000f, 0.8300f, 1.0000f, 0.1503f, 0.0020f, { 0.0000f, 0.0000f, 0.0000f }, 1.0629f, 0.0030f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_BATHROOM \ + { 0.1715f, 1.0000f, 0.3162f, 0.2512f, 1.0000f, 1.4900f, 0.5400f, 1.0000f, 0.6531f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 3.2734f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_LIVINGROOM \ + { 0.9766f, 1.0000f, 0.3162f, 0.0010f, 1.0000f, 0.5000f, 0.1000f, 1.0000f, 0.2051f, 0.0030f, { 0.0000f, 0.0000f, 0.0000f }, 0.2805f, 0.0040f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_STONEROOM \ + { 1.0000f, 1.0000f, 0.3162f, 0.7079f, 1.0000f, 2.3100f, 0.6400f, 1.0000f, 0.4411f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 1.1003f, 0.0170f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_AUDITORIUM \ + { 1.0000f, 1.0000f, 0.3162f, 0.5781f, 1.0000f, 4.3200f, 0.5900f, 1.0000f, 0.4032f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 0.7170f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_CONCERTHALL \ + { 1.0000f, 1.0000f, 0.3162f, 0.5623f, 1.0000f, 3.9200f, 0.7000f, 1.0000f, 0.2427f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 0.9977f, 0.0290f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_CAVE \ + { 1.0000f, 1.0000f, 0.3162f, 1.0000f, 1.0000f, 2.9100f, 1.3000f, 1.0000f, 0.5000f, 0.0150f, { 0.0000f, 0.0000f, 0.0000f }, 0.7063f, 0.0220f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 } + +#define EFX_REVERB_PRESET_ARENA \ + { 1.0000f, 1.0000f, 0.3162f, 0.4477f, 1.0000f, 7.2400f, 0.3300f, 1.0000f, 0.2612f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 1.0186f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_HANGAR \ + { 1.0000f, 1.0000f, 0.3162f, 0.3162f, 1.0000f, 10.0500f, 0.2300f, 1.0000f, 0.5000f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 1.2560f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_CARPETEDHALLWAY \ + { 0.4287f, 1.0000f, 0.3162f, 0.0100f, 1.0000f, 0.3000f, 0.1000f, 1.0000f, 0.1215f, 0.0020f, { 0.0000f, 0.0000f, 0.0000f }, 0.1531f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_HALLWAY \ + { 0.3645f, 1.0000f, 0.3162f, 0.7079f, 1.0000f, 1.4900f, 0.5900f, 1.0000f, 0.2458f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 1.6615f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_STONECORRIDOR \ + { 1.0000f, 1.0000f, 0.3162f, 0.7612f, 1.0000f, 2.7000f, 0.7900f, 1.0000f, 0.2472f, 0.0130f, { 0.0000f, 0.0000f, 0.0000f }, 1.5758f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_ALLEY \ + { 1.0000f, 0.3000f, 0.3162f, 0.7328f, 1.0000f, 1.4900f, 0.8600f, 1.0000f, 0.2500f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 0.9954f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.1250f, 0.9500f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_FOREST \ + { 1.0000f, 0.3000f, 0.3162f, 0.0224f, 1.0000f, 1.4900f, 0.5400f, 1.0000f, 0.0525f, 0.1620f, { 0.0000f, 0.0000f, 0.0000f }, 0.7682f, 0.0880f, { 0.0000f, 0.0000f, 0.0000f }, 0.1250f, 1.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_CITY \ + { 1.0000f, 0.5000f, 0.3162f, 0.3981f, 1.0000f, 1.4900f, 0.6700f, 1.0000f, 0.0730f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 0.1427f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_MOUNTAINS \ + { 1.0000f, 0.2700f, 0.3162f, 0.0562f, 1.0000f, 1.4900f, 0.2100f, 1.0000f, 0.0407f, 0.3000f, { 0.0000f, 0.0000f, 0.0000f }, 0.1919f, 0.1000f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 1.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 } + +#define EFX_REVERB_PRESET_QUARRY \ + { 1.0000f, 1.0000f, 0.3162f, 0.3162f, 1.0000f, 1.4900f, 0.8300f, 1.0000f, 0.0000f, 0.0610f, { 0.0000f, 0.0000f, 0.0000f }, 1.7783f, 0.0250f, { 0.0000f, 0.0000f, 0.0000f }, 0.1250f, 0.7000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_PLAIN \ + { 1.0000f, 0.2100f, 0.3162f, 0.1000f, 1.0000f, 1.4900f, 0.5000f, 1.0000f, 0.0585f, 0.1790f, { 0.0000f, 0.0000f, 0.0000f }, 0.1089f, 0.1000f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 1.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_PARKINGLOT \ + { 1.0000f, 1.0000f, 0.3162f, 1.0000f, 1.0000f, 1.6500f, 1.5000f, 1.0000f, 0.2082f, 0.0080f, { 0.0000f, 0.0000f, 0.0000f }, 0.2652f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 } + +#define EFX_REVERB_PRESET_SEWERPIPE \ + { 0.3071f, 0.8000f, 0.3162f, 0.3162f, 1.0000f, 2.8100f, 0.1400f, 1.0000f, 1.6387f, 0.0140f, { 0.0000f, 0.0000f, 0.0000f }, 3.2471f, 0.0210f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_UNDERWATER \ + { 0.3645f, 1.0000f, 0.3162f, 0.0100f, 1.0000f, 1.4900f, 0.1000f, 1.0000f, 0.5963f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 7.0795f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 1.1800f, 0.3480f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_DRUGGED \ + { 0.4287f, 0.5000f, 0.3162f, 1.0000f, 1.0000f, 8.3900f, 1.3900f, 1.0000f, 0.8760f, 0.0020f, { 0.0000f, 0.0000f, 0.0000f }, 3.1081f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 1.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 } + +#define EFX_REVERB_PRESET_DIZZY \ + { 0.3645f, 0.6000f, 0.3162f, 0.6310f, 1.0000f, 17.2300f, 0.5600f, 1.0000f, 0.1392f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 0.4937f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 1.0000f, 0.8100f, 0.3100f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 } + +#define EFX_REVERB_PRESET_PSYCHOTIC \ + { 0.0625f, 0.5000f, 0.3162f, 0.8404f, 1.0000f, 7.5600f, 0.9100f, 1.0000f, 0.4864f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 2.4378f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 4.0000f, 1.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 } + +/* Castle Presets */ + +#define EFX_REVERB_PRESET_CASTLE_SMALLROOM \ + { 1.0000f, 0.8900f, 0.3162f, 0.3981f, 0.1000f, 1.2200f, 0.8300f, 0.3100f, 0.8913f, 0.0220f, { 0.0000f, 0.0000f, 0.0000f }, 1.9953f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.1380f, 0.0800f, 0.2500f, 0.0000f, 0.9943f, 5168.6001f, 139.5000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_CASTLE_SHORTPASSAGE \ + { 1.0000f, 0.8900f, 0.3162f, 0.3162f, 0.1000f, 2.3200f, 0.8300f, 0.3100f, 0.8913f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0230f, { 0.0000f, 0.0000f, 0.0000f }, 0.1380f, 0.0800f, 0.2500f, 0.0000f, 0.9943f, 5168.6001f, 139.5000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_CASTLE_MEDIUMROOM \ + { 1.0000f, 0.9300f, 0.3162f, 0.2818f, 0.1000f, 2.0400f, 0.8300f, 0.4600f, 0.6310f, 0.0220f, { 0.0000f, 0.0000f, 0.0000f }, 1.5849f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.1550f, 0.0300f, 0.2500f, 0.0000f, 0.9943f, 5168.6001f, 139.5000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_CASTLE_LARGEROOM \ + { 1.0000f, 0.8200f, 0.3162f, 0.2818f, 0.1259f, 2.5300f, 0.8300f, 0.5000f, 0.4467f, 0.0340f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0160f, { 0.0000f, 0.0000f, 0.0000f }, 0.1850f, 0.0700f, 0.2500f, 0.0000f, 0.9943f, 5168.6001f, 139.5000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_CASTLE_LONGPASSAGE \ + { 1.0000f, 0.8900f, 0.3162f, 0.3981f, 0.1000f, 3.4200f, 0.8300f, 0.3100f, 0.8913f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 1.4125f, 0.0230f, { 0.0000f, 0.0000f, 0.0000f }, 0.1380f, 0.0800f, 0.2500f, 0.0000f, 0.9943f, 5168.6001f, 139.5000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_CASTLE_HALL \ + { 1.0000f, 0.8100f, 0.3162f, 0.2818f, 0.1778f, 3.1400f, 0.7900f, 0.6200f, 0.1778f, 0.0560f, { 0.0000f, 0.0000f, 0.0000f }, 1.1220f, 0.0240f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5168.6001f, 139.5000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_CASTLE_CUPBOARD \ + { 1.0000f, 0.8900f, 0.3162f, 0.2818f, 0.1000f, 0.6700f, 0.8700f, 0.3100f, 1.4125f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 3.5481f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 0.1380f, 0.0800f, 0.2500f, 0.0000f, 0.9943f, 5168.6001f, 139.5000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_CASTLE_COURTYARD \ + { 1.0000f, 0.4200f, 0.3162f, 0.4467f, 0.1995f, 2.1300f, 0.6100f, 0.2300f, 0.2239f, 0.1600f, { 0.0000f, 0.0000f, 0.0000f }, 0.7079f, 0.0360f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.3700f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 } + +#define EFX_REVERB_PRESET_CASTLE_ALCOVE \ + { 1.0000f, 0.8900f, 0.3162f, 0.5012f, 0.1000f, 1.6400f, 0.8700f, 0.3100f, 1.0000f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 1.4125f, 0.0340f, { 0.0000f, 0.0000f, 0.0000f }, 0.1380f, 0.0800f, 0.2500f, 0.0000f, 0.9943f, 5168.6001f, 139.5000f, 0.0000f, 0x1 } + +/* Factory Presets */ + +#define EFX_REVERB_PRESET_FACTORY_SMALLROOM \ + { 0.3645f, 0.8200f, 0.3162f, 0.7943f, 0.5012f, 1.7200f, 0.6500f, 1.3100f, 0.7079f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 1.7783f, 0.0240f, { 0.0000f, 0.0000f, 0.0000f }, 0.1190f, 0.0700f, 0.2500f, 0.0000f, 0.9943f, 3762.6001f, 362.5000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_FACTORY_SHORTPASSAGE \ + { 0.3645f, 0.6400f, 0.2512f, 0.7943f, 0.5012f, 2.5300f, 0.6500f, 1.3100f, 1.0000f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0380f, { 0.0000f, 0.0000f, 0.0000f }, 0.1350f, 0.2300f, 0.2500f, 0.0000f, 0.9943f, 3762.6001f, 362.5000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_FACTORY_MEDIUMROOM \ + { 0.4287f, 0.8200f, 0.2512f, 0.7943f, 0.5012f, 2.7600f, 0.6500f, 1.3100f, 0.2818f, 0.0220f, { 0.0000f, 0.0000f, 0.0000f }, 1.4125f, 0.0230f, { 0.0000f, 0.0000f, 0.0000f }, 0.1740f, 0.0700f, 0.2500f, 0.0000f, 0.9943f, 3762.6001f, 362.5000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_FACTORY_LARGEROOM \ + { 0.4287f, 0.7500f, 0.2512f, 0.7079f, 0.6310f, 4.2400f, 0.5100f, 1.3100f, 0.1778f, 0.0390f, { 0.0000f, 0.0000f, 0.0000f }, 1.1220f, 0.0230f, { 0.0000f, 0.0000f, 0.0000f }, 0.2310f, 0.0700f, 0.2500f, 0.0000f, 0.9943f, 3762.6001f, 362.5000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_FACTORY_LONGPASSAGE \ + { 0.3645f, 0.6400f, 0.2512f, 0.7943f, 0.5012f, 4.0600f, 0.6500f, 1.3100f, 1.0000f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0370f, { 0.0000f, 0.0000f, 0.0000f }, 0.1350f, 0.2300f, 0.2500f, 0.0000f, 0.9943f, 3762.6001f, 362.5000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_FACTORY_HALL \ + { 0.4287f, 0.7500f, 0.3162f, 0.7079f, 0.6310f, 7.4300f, 0.5100f, 1.3100f, 0.0631f, 0.0730f, { 0.0000f, 0.0000f, 0.0000f }, 0.8913f, 0.0270f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0700f, 0.2500f, 0.0000f, 0.9943f, 3762.6001f, 362.5000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_FACTORY_CUPBOARD \ + { 0.3071f, 0.6300f, 0.2512f, 0.7943f, 0.5012f, 0.4900f, 0.6500f, 1.3100f, 1.2589f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 1.9953f, 0.0320f, { 0.0000f, 0.0000f, 0.0000f }, 0.1070f, 0.0700f, 0.2500f, 0.0000f, 0.9943f, 3762.6001f, 362.5000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_FACTORY_COURTYARD \ + { 0.3071f, 0.5700f, 0.3162f, 0.3162f, 0.6310f, 2.3200f, 0.2900f, 0.5600f, 0.2239f, 0.1400f, { 0.0000f, 0.0000f, 0.0000f }, 0.3981f, 0.0390f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.2900f, 0.2500f, 0.0000f, 0.9943f, 3762.6001f, 362.5000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_FACTORY_ALCOVE \ + { 0.3645f, 0.5900f, 0.2512f, 0.7943f, 0.5012f, 3.1400f, 0.6500f, 1.3100f, 1.4125f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 1.0000f, 0.0380f, { 0.0000f, 0.0000f, 0.0000f }, 0.1140f, 0.1000f, 0.2500f, 0.0000f, 0.9943f, 3762.6001f, 362.5000f, 0.0000f, 0x1 } + +/* Ice Palace Presets */ + +#define EFX_REVERB_PRESET_ICEPALACE_SMALLROOM \ + { 1.0000f, 0.8400f, 0.3162f, 0.5623f, 0.2818f, 1.5100f, 1.5300f, 0.2700f, 0.8913f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 1.4125f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.1640f, 0.1400f, 0.2500f, 0.0000f, 0.9943f, 12428.5000f, 99.6000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_ICEPALACE_SHORTPASSAGE \ + { 1.0000f, 0.7500f, 0.3162f, 0.5623f, 0.2818f, 1.7900f, 1.4600f, 0.2800f, 0.5012f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 1.1220f, 0.0190f, { 0.0000f, 0.0000f, 0.0000f }, 0.1770f, 0.0900f, 0.2500f, 0.0000f, 0.9943f, 12428.5000f, 99.6000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_ICEPALACE_MEDIUMROOM \ + { 1.0000f, 0.8700f, 0.3162f, 0.5623f, 0.4467f, 2.2200f, 1.5300f, 0.3200f, 0.3981f, 0.0390f, { 0.0000f, 0.0000f, 0.0000f }, 1.1220f, 0.0270f, { 0.0000f, 0.0000f, 0.0000f }, 0.1860f, 0.1200f, 0.2500f, 0.0000f, 0.9943f, 12428.5000f, 99.6000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_ICEPALACE_LARGEROOM \ + { 1.0000f, 0.8100f, 0.3162f, 0.5623f, 0.4467f, 3.1400f, 1.5300f, 0.3200f, 0.2512f, 0.0390f, { 0.0000f, 0.0000f, 0.0000f }, 1.0000f, 0.0270f, { 0.0000f, 0.0000f, 0.0000f }, 0.2140f, 0.1100f, 0.2500f, 0.0000f, 0.9943f, 12428.5000f, 99.6000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_ICEPALACE_LONGPASSAGE \ + { 1.0000f, 0.7700f, 0.3162f, 0.5623f, 0.3981f, 3.0100f, 1.4600f, 0.2800f, 0.7943f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0250f, { 0.0000f, 0.0000f, 0.0000f }, 0.1860f, 0.0400f, 0.2500f, 0.0000f, 0.9943f, 12428.5000f, 99.6000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_ICEPALACE_HALL \ + { 1.0000f, 0.7600f, 0.3162f, 0.4467f, 0.5623f, 5.4900f, 1.5300f, 0.3800f, 0.1122f, 0.0540f, { 0.0000f, 0.0000f, 0.0000f }, 0.6310f, 0.0520f, { 0.0000f, 0.0000f, 0.0000f }, 0.2260f, 0.1100f, 0.2500f, 0.0000f, 0.9943f, 12428.5000f, 99.6000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_ICEPALACE_CUPBOARD \ + { 1.0000f, 0.8300f, 0.3162f, 0.5012f, 0.2239f, 0.7600f, 1.5300f, 0.2600f, 1.1220f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 1.9953f, 0.0160f, { 0.0000f, 0.0000f, 0.0000f }, 0.1430f, 0.0800f, 0.2500f, 0.0000f, 0.9943f, 12428.5000f, 99.6000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_ICEPALACE_COURTYARD \ + { 1.0000f, 0.5900f, 0.3162f, 0.2818f, 0.3162f, 2.0400f, 1.2000f, 0.3800f, 0.3162f, 0.1730f, { 0.0000f, 0.0000f, 0.0000f }, 0.3162f, 0.0430f, { 0.0000f, 0.0000f, 0.0000f }, 0.2350f, 0.4800f, 0.2500f, 0.0000f, 0.9943f, 12428.5000f, 99.6000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_ICEPALACE_ALCOVE \ + { 1.0000f, 0.8400f, 0.3162f, 0.5623f, 0.2818f, 2.7600f, 1.4600f, 0.2800f, 1.1220f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 0.8913f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.1610f, 0.0900f, 0.2500f, 0.0000f, 0.9943f, 12428.5000f, 99.6000f, 0.0000f, 0x1 } + +/* Space Station Presets */ + +#define EFX_REVERB_PRESET_SPACESTATION_SMALLROOM \ + { 0.2109f, 0.7000f, 0.3162f, 0.7079f, 0.8913f, 1.7200f, 0.8200f, 0.5500f, 0.7943f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 1.4125f, 0.0130f, { 0.0000f, 0.0000f, 0.0000f }, 0.1880f, 0.2600f, 0.2500f, 0.0000f, 0.9943f, 3316.1001f, 458.2000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_SPACESTATION_SHORTPASSAGE \ + { 0.2109f, 0.8700f, 0.3162f, 0.6310f, 0.8913f, 3.5700f, 0.5000f, 0.5500f, 1.0000f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 1.1220f, 0.0160f, { 0.0000f, 0.0000f, 0.0000f }, 0.1720f, 0.2000f, 0.2500f, 0.0000f, 0.9943f, 3316.1001f, 458.2000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_SPACESTATION_MEDIUMROOM \ + { 0.2109f, 0.7500f, 0.3162f, 0.6310f, 0.8913f, 3.0100f, 0.5000f, 0.5500f, 0.3981f, 0.0340f, { 0.0000f, 0.0000f, 0.0000f }, 1.1220f, 0.0350f, { 0.0000f, 0.0000f, 0.0000f }, 0.2090f, 0.3100f, 0.2500f, 0.0000f, 0.9943f, 3316.1001f, 458.2000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_SPACESTATION_LARGEROOM \ + { 0.3645f, 0.8100f, 0.3162f, 0.6310f, 0.8913f, 3.8900f, 0.3800f, 0.6100f, 0.3162f, 0.0560f, { 0.0000f, 0.0000f, 0.0000f }, 0.8913f, 0.0350f, { 0.0000f, 0.0000f, 0.0000f }, 0.2330f, 0.2800f, 0.2500f, 0.0000f, 0.9943f, 3316.1001f, 458.2000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_SPACESTATION_LONGPASSAGE \ + { 0.4287f, 0.8200f, 0.3162f, 0.6310f, 0.8913f, 4.6200f, 0.6200f, 0.5500f, 1.0000f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0310f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.2300f, 0.2500f, 0.0000f, 0.9943f, 3316.1001f, 458.2000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_SPACESTATION_HALL \ + { 0.4287f, 0.8700f, 0.3162f, 0.6310f, 0.8913f, 7.1100f, 0.3800f, 0.6100f, 0.1778f, 0.1000f, { 0.0000f, 0.0000f, 0.0000f }, 0.6310f, 0.0470f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.2500f, 0.2500f, 0.0000f, 0.9943f, 3316.1001f, 458.2000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_SPACESTATION_CUPBOARD \ + { 0.1715f, 0.5600f, 0.3162f, 0.7079f, 0.8913f, 0.7900f, 0.8100f, 0.5500f, 1.4125f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 1.7783f, 0.0180f, { 0.0000f, 0.0000f, 0.0000f }, 0.1810f, 0.3100f, 0.2500f, 0.0000f, 0.9943f, 3316.1001f, 458.2000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_SPACESTATION_ALCOVE \ + { 0.2109f, 0.7800f, 0.3162f, 0.7079f, 0.8913f, 1.1600f, 0.8100f, 0.5500f, 1.4125f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 1.0000f, 0.0180f, { 0.0000f, 0.0000f, 0.0000f }, 0.1920f, 0.2100f, 0.2500f, 0.0000f, 0.9943f, 3316.1001f, 458.2000f, 0.0000f, 0x1 } + +/* Wooden Galleon Presets */ + +#define EFX_REVERB_PRESET_WOODEN_SMALLROOM \ + { 1.0000f, 1.0000f, 0.3162f, 0.1122f, 0.3162f, 0.7900f, 0.3200f, 0.8700f, 1.0000f, 0.0320f, { 0.0000f, 0.0000f, 0.0000f }, 0.8913f, 0.0290f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 4705.0000f, 99.6000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_WOODEN_SHORTPASSAGE \ + { 1.0000f, 1.0000f, 0.3162f, 0.1259f, 0.3162f, 1.7500f, 0.5000f, 0.8700f, 0.8913f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 0.6310f, 0.0240f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 4705.0000f, 99.6000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_WOODEN_MEDIUMROOM \ + { 1.0000f, 1.0000f, 0.3162f, 0.1000f, 0.2818f, 1.4700f, 0.4200f, 0.8200f, 0.8913f, 0.0490f, { 0.0000f, 0.0000f, 0.0000f }, 0.8913f, 0.0290f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 4705.0000f, 99.6000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_WOODEN_LARGEROOM \ + { 1.0000f, 1.0000f, 0.3162f, 0.0891f, 0.2818f, 2.6500f, 0.3300f, 0.8200f, 0.8913f, 0.0660f, { 0.0000f, 0.0000f, 0.0000f }, 0.7943f, 0.0490f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 4705.0000f, 99.6000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_WOODEN_LONGPASSAGE \ + { 1.0000f, 1.0000f, 0.3162f, 0.1000f, 0.3162f, 1.9900f, 0.4000f, 0.7900f, 1.0000f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 0.4467f, 0.0360f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 4705.0000f, 99.6000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_WOODEN_HALL \ + { 1.0000f, 1.0000f, 0.3162f, 0.0794f, 0.2818f, 3.4500f, 0.3000f, 0.8200f, 0.8913f, 0.0880f, { 0.0000f, 0.0000f, 0.0000f }, 0.7943f, 0.0630f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 4705.0000f, 99.6000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_WOODEN_CUPBOARD \ + { 1.0000f, 1.0000f, 0.3162f, 0.1413f, 0.3162f, 0.5600f, 0.4600f, 0.9100f, 1.1220f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 1.1220f, 0.0280f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 4705.0000f, 99.6000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_WOODEN_COURTYARD \ + { 1.0000f, 0.6500f, 0.3162f, 0.0794f, 0.3162f, 1.7900f, 0.3500f, 0.7900f, 0.5623f, 0.1230f, { 0.0000f, 0.0000f, 0.0000f }, 0.1000f, 0.0320f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 4705.0000f, 99.6000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_WOODEN_ALCOVE \ + { 1.0000f, 1.0000f, 0.3162f, 0.1259f, 0.3162f, 1.2200f, 0.6200f, 0.9100f, 1.1220f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 0.7079f, 0.0240f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 4705.0000f, 99.6000f, 0.0000f, 0x1 } + +/* Sports Presets */ + +#define EFX_REVERB_PRESET_SPORT_EMPTYSTADIUM \ + { 1.0000f, 1.0000f, 0.3162f, 0.4467f, 0.7943f, 6.2600f, 0.5100f, 1.1000f, 0.0631f, 0.1830f, { 0.0000f, 0.0000f, 0.0000f }, 0.3981f, 0.0380f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_SPORT_SQUASHCOURT \ + { 1.0000f, 0.7500f, 0.3162f, 0.3162f, 0.7943f, 2.2200f, 0.9100f, 1.1600f, 0.4467f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 0.7943f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.1260f, 0.1900f, 0.2500f, 0.0000f, 0.9943f, 7176.8999f, 211.2000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_SPORT_SMALLSWIMMINGPOOL \ + { 1.0000f, 0.7000f, 0.3162f, 0.7943f, 0.8913f, 2.7600f, 1.2500f, 1.1400f, 0.6310f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 0.7943f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.1790f, 0.1500f, 0.8950f, 0.1900f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 } + +#define EFX_REVERB_PRESET_SPORT_LARGESWIMMINGPOOL \ + { 1.0000f, 0.8200f, 0.3162f, 0.7943f, 1.0000f, 5.4900f, 1.3100f, 1.1400f, 0.4467f, 0.0390f, { 0.0000f, 0.0000f, 0.0000f }, 0.5012f, 0.0490f, { 0.0000f, 0.0000f, 0.0000f }, 0.2220f, 0.5500f, 1.1590f, 0.2100f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 } + +#define EFX_REVERB_PRESET_SPORT_GYMNASIUM \ + { 1.0000f, 0.8100f, 0.3162f, 0.4467f, 0.8913f, 3.1400f, 1.0600f, 1.3500f, 0.3981f, 0.0290f, { 0.0000f, 0.0000f, 0.0000f }, 0.5623f, 0.0450f, { 0.0000f, 0.0000f, 0.0000f }, 0.1460f, 0.1400f, 0.2500f, 0.0000f, 0.9943f, 7176.8999f, 211.2000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_SPORT_FULLSTADIUM \ + { 1.0000f, 1.0000f, 0.3162f, 0.0708f, 0.7943f, 5.2500f, 0.1700f, 0.8000f, 0.1000f, 0.1880f, { 0.0000f, 0.0000f, 0.0000f }, 0.2818f, 0.0380f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_SPORT_STADIUMTANNOY \ + { 1.0000f, 0.7800f, 0.3162f, 0.5623f, 0.5012f, 2.5300f, 0.8800f, 0.6800f, 0.2818f, 0.2300f, { 0.0000f, 0.0000f, 0.0000f }, 0.5012f, 0.0630f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.2000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +/* Prefab Presets */ + +#define EFX_REVERB_PRESET_PREFAB_WORKSHOP \ + { 0.4287f, 1.0000f, 0.3162f, 0.1413f, 0.3981f, 0.7600f, 1.0000f, 1.0000f, 1.0000f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 1.1220f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 } + +#define EFX_REVERB_PRESET_PREFAB_SCHOOLROOM \ + { 0.4022f, 0.6900f, 0.3162f, 0.6310f, 0.5012f, 0.9800f, 0.4500f, 0.1800f, 1.4125f, 0.0170f, { 0.0000f, 0.0000f, 0.0000f }, 1.4125f, 0.0150f, { 0.0000f, 0.0000f, 0.0000f }, 0.0950f, 0.1400f, 0.2500f, 0.0000f, 0.9943f, 7176.8999f, 211.2000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_PREFAB_PRACTISEROOM \ + { 0.4022f, 0.8700f, 0.3162f, 0.3981f, 0.5012f, 1.1200f, 0.5600f, 0.1800f, 1.2589f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 1.4125f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.0950f, 0.1400f, 0.2500f, 0.0000f, 0.9943f, 7176.8999f, 211.2000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_PREFAB_OUTHOUSE \ + { 1.0000f, 0.8200f, 0.3162f, 0.1122f, 0.1585f, 1.3800f, 0.3800f, 0.3500f, 0.8913f, 0.0240f, { 0.0000f, 0.0000f, -0.0000f }, 0.6310f, 0.0440f, { 0.0000f, 0.0000f, 0.0000f }, 0.1210f, 0.1700f, 0.2500f, 0.0000f, 0.9943f, 2854.3999f, 107.5000f, 0.0000f, 0x0 } + +#define EFX_REVERB_PRESET_PREFAB_CARAVAN \ + { 1.0000f, 1.0000f, 0.3162f, 0.0891f, 0.1259f, 0.4300f, 1.5000f, 1.0000f, 1.0000f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 1.9953f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 } + +/* Dome and Pipe Presets */ + +#define EFX_REVERB_PRESET_DOME_TOMB \ + { 1.0000f, 0.7900f, 0.3162f, 0.3548f, 0.2239f, 4.1800f, 0.2100f, 0.1000f, 0.3868f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 1.6788f, 0.0220f, { 0.0000f, 0.0000f, 0.0000f }, 0.1770f, 0.1900f, 0.2500f, 0.0000f, 0.9943f, 2854.3999f, 20.0000f, 0.0000f, 0x0 } + +#define EFX_REVERB_PRESET_PIPE_SMALL \ + { 1.0000f, 1.0000f, 0.3162f, 0.3548f, 0.2239f, 5.0400f, 0.1000f, 0.1000f, 0.5012f, 0.0320f, { 0.0000f, 0.0000f, 0.0000f }, 2.5119f, 0.0150f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 2854.3999f, 20.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_DOME_SAINTPAULS \ + { 1.0000f, 0.8700f, 0.3162f, 0.3548f, 0.2239f, 10.4800f, 0.1900f, 0.1000f, 0.1778f, 0.0900f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0420f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.1200f, 0.2500f, 0.0000f, 0.9943f, 2854.3999f, 20.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_PIPE_LONGTHIN \ + { 0.2560f, 0.9100f, 0.3162f, 0.4467f, 0.2818f, 9.2100f, 0.1800f, 0.1000f, 0.7079f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 0.7079f, 0.0220f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 2854.3999f, 20.0000f, 0.0000f, 0x0 } + +#define EFX_REVERB_PRESET_PIPE_LARGE \ + { 1.0000f, 1.0000f, 0.3162f, 0.3548f, 0.2239f, 8.4500f, 0.1000f, 0.1000f, 0.3981f, 0.0460f, { 0.0000f, 0.0000f, 0.0000f }, 1.5849f, 0.0320f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 2854.3999f, 20.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_PIPE_RESONANT \ + { 0.1373f, 0.9100f, 0.3162f, 0.4467f, 0.2818f, 6.8100f, 0.1800f, 0.1000f, 0.7079f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 1.0000f, 0.0220f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 2854.3999f, 20.0000f, 0.0000f, 0x0 } + +/* Outdoors Presets */ + +#define EFX_REVERB_PRESET_OUTDOORS_BACKYARD \ + { 1.0000f, 0.4500f, 0.3162f, 0.2512f, 0.5012f, 1.1200f, 0.3400f, 0.4600f, 0.4467f, 0.0690f, { 0.0000f, 0.0000f, -0.0000f }, 0.7079f, 0.0230f, { 0.0000f, 0.0000f, 0.0000f }, 0.2180f, 0.3400f, 0.2500f, 0.0000f, 0.9943f, 4399.1001f, 242.9000f, 0.0000f, 0x0 } + +#define EFX_REVERB_PRESET_OUTDOORS_ROLLINGPLAINS \ + { 1.0000f, 0.0000f, 0.3162f, 0.0112f, 0.6310f, 2.1300f, 0.2100f, 0.4600f, 0.1778f, 0.3000f, { 0.0000f, 0.0000f, -0.0000f }, 0.4467f, 0.0190f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 1.0000f, 0.2500f, 0.0000f, 0.9943f, 4399.1001f, 242.9000f, 0.0000f, 0x0 } + +#define EFX_REVERB_PRESET_OUTDOORS_DEEPCANYON \ + { 1.0000f, 0.7400f, 0.3162f, 0.1778f, 0.6310f, 3.8900f, 0.2100f, 0.4600f, 0.3162f, 0.2230f, { 0.0000f, 0.0000f, -0.0000f }, 0.3548f, 0.0190f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 1.0000f, 0.2500f, 0.0000f, 0.9943f, 4399.1001f, 242.9000f, 0.0000f, 0x0 } + +#define EFX_REVERB_PRESET_OUTDOORS_CREEK \ + { 1.0000f, 0.3500f, 0.3162f, 0.1778f, 0.5012f, 2.1300f, 0.2100f, 0.4600f, 0.3981f, 0.1150f, { 0.0000f, 0.0000f, -0.0000f }, 0.1995f, 0.0310f, { 0.0000f, 0.0000f, 0.0000f }, 0.2180f, 0.3400f, 0.2500f, 0.0000f, 0.9943f, 4399.1001f, 242.9000f, 0.0000f, 0x0 } + +#define EFX_REVERB_PRESET_OUTDOORS_VALLEY \ + { 1.0000f, 0.2800f, 0.3162f, 0.0282f, 0.1585f, 2.8800f, 0.2600f, 0.3500f, 0.1413f, 0.2630f, { 0.0000f, 0.0000f, -0.0000f }, 0.3981f, 0.1000f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.3400f, 0.2500f, 0.0000f, 0.9943f, 2854.3999f, 107.5000f, 0.0000f, 0x0 } + +/* Mood Presets */ + +#define EFX_REVERB_PRESET_MOOD_HEAVEN \ + { 1.0000f, 0.9400f, 0.3162f, 0.7943f, 0.4467f, 5.0400f, 1.1200f, 0.5600f, 0.2427f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0290f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0800f, 2.7420f, 0.0500f, 0.9977f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_MOOD_HELL \ + { 1.0000f, 0.5700f, 0.3162f, 0.3548f, 0.4467f, 3.5700f, 0.4900f, 2.0000f, 0.0000f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 1.4125f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.1100f, 0.0400f, 2.1090f, 0.5200f, 0.9943f, 5000.0000f, 139.5000f, 0.0000f, 0x0 } + +#define EFX_REVERB_PRESET_MOOD_MEMORY \ + { 1.0000f, 0.8500f, 0.3162f, 0.6310f, 0.3548f, 4.0600f, 0.8200f, 0.5600f, 0.0398f, 0.0000f, { 0.0000f, 0.0000f, 0.0000f }, 1.1220f, 0.0000f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.4740f, 0.4500f, 0.9886f, 5000.0000f, 250.0000f, 0.0000f, 0x0 } + +/* Driving Presets */ + +#define EFX_REVERB_PRESET_DRIVING_COMMENTATOR \ + { 1.0000f, 0.0000f, 3.1623f, 0.5623f, 0.5012f, 2.4200f, 0.8800f, 0.6800f, 0.1995f, 0.0930f, { 0.0000f, 0.0000f, 0.0000f }, 0.2512f, 0.0170f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 1.0000f, 0.2500f, 0.0000f, 0.9886f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_DRIVING_PITGARAGE \ + { 0.4287f, 0.5900f, 0.3162f, 0.7079f, 0.5623f, 1.7200f, 0.9300f, 0.8700f, 0.5623f, 0.0000f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0160f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.1100f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 } + +#define EFX_REVERB_PRESET_DRIVING_INCAR_RACER \ + { 0.0832f, 0.8000f, 0.3162f, 1.0000f, 0.7943f, 0.1700f, 2.0000f, 0.4100f, 1.7783f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 0.7079f, 0.0150f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 10268.2002f, 251.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_DRIVING_INCAR_SPORTS \ + { 0.0832f, 0.8000f, 0.3162f, 0.6310f, 1.0000f, 0.1700f, 0.7500f, 0.4100f, 1.0000f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 0.5623f, 0.0000f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 10268.2002f, 251.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_DRIVING_INCAR_LUXURY \ + { 0.2560f, 1.0000f, 0.3162f, 0.1000f, 0.5012f, 0.1300f, 0.4100f, 0.4600f, 0.7943f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 1.5849f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 10268.2002f, 251.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_DRIVING_FULLGRANDSTAND \ + { 1.0000f, 1.0000f, 0.3162f, 0.2818f, 0.6310f, 3.0100f, 1.3700f, 1.2800f, 0.3548f, 0.0900f, { 0.0000f, 0.0000f, 0.0000f }, 0.1778f, 0.0490f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 10420.2002f, 250.0000f, 0.0000f, 0x0 } + +#define EFX_REVERB_PRESET_DRIVING_EMPTYGRANDSTAND \ + { 1.0000f, 1.0000f, 0.3162f, 1.0000f, 0.7943f, 4.6200f, 1.7500f, 1.4000f, 0.2082f, 0.0900f, { 0.0000f, 0.0000f, 0.0000f }, 0.2512f, 0.0490f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 10420.2002f, 250.0000f, 0.0000f, 0x0 } + +#define EFX_REVERB_PRESET_DRIVING_TUNNEL \ + { 1.0000f, 0.8100f, 0.3162f, 0.3981f, 0.8913f, 3.4200f, 0.9400f, 1.3100f, 0.7079f, 0.0510f, { 0.0000f, 0.0000f, 0.0000f }, 0.7079f, 0.0470f, { 0.0000f, 0.0000f, 0.0000f }, 0.2140f, 0.0500f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 155.3000f, 0.0000f, 0x1 } + +/* City Presets */ + +#define EFX_REVERB_PRESET_CITY_STREETS \ + { 1.0000f, 0.7800f, 0.3162f, 0.7079f, 0.8913f, 1.7900f, 1.1200f, 0.9100f, 0.2818f, 0.0460f, { 0.0000f, 0.0000f, 0.0000f }, 0.1995f, 0.0280f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.2000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_CITY_SUBWAY \ + { 1.0000f, 0.7400f, 0.3162f, 0.7079f, 0.8913f, 3.0100f, 1.2300f, 0.9100f, 0.7079f, 0.0460f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0280f, { 0.0000f, 0.0000f, 0.0000f }, 0.1250f, 0.2100f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_CITY_MUSEUM \ + { 1.0000f, 0.8200f, 0.3162f, 0.1778f, 0.1778f, 3.2800f, 1.4000f, 0.5700f, 0.2512f, 0.0390f, { 0.0000f, 0.0000f, -0.0000f }, 0.8913f, 0.0340f, { 0.0000f, 0.0000f, 0.0000f }, 0.1300f, 0.1700f, 0.2500f, 0.0000f, 0.9943f, 2854.3999f, 107.5000f, 0.0000f, 0x0 } + +#define EFX_REVERB_PRESET_CITY_LIBRARY \ + { 1.0000f, 0.8200f, 0.3162f, 0.2818f, 0.0891f, 2.7600f, 0.8900f, 0.4100f, 0.3548f, 0.0290f, { 0.0000f, 0.0000f, -0.0000f }, 0.8913f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 0.1300f, 0.1700f, 0.2500f, 0.0000f, 0.9943f, 2854.3999f, 107.5000f, 0.0000f, 0x0 } + +#define EFX_REVERB_PRESET_CITY_UNDERPASS \ + { 1.0000f, 0.8200f, 0.3162f, 0.4467f, 0.8913f, 3.5700f, 1.1200f, 0.9100f, 0.3981f, 0.0590f, { 0.0000f, 0.0000f, 0.0000f }, 0.8913f, 0.0370f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.1400f, 0.2500f, 0.0000f, 0.9920f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_CITY_ABANDONED \ + { 1.0000f, 0.6900f, 0.3162f, 0.7943f, 0.8913f, 3.2800f, 1.1700f, 0.9100f, 0.4467f, 0.0440f, { 0.0000f, 0.0000f, 0.0000f }, 0.2818f, 0.0240f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.2000f, 0.2500f, 0.0000f, 0.9966f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +/* Misc. Presets */ + +#define EFX_REVERB_PRESET_DUSTYROOM \ + { 0.3645f, 0.5600f, 0.3162f, 0.7943f, 0.7079f, 1.7900f, 0.3800f, 0.2100f, 0.5012f, 0.0020f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0060f, { 0.0000f, 0.0000f, 0.0000f }, 0.2020f, 0.0500f, 0.2500f, 0.0000f, 0.9886f, 13046.0000f, 163.3000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_CHAPEL \ + { 1.0000f, 0.8400f, 0.3162f, 0.5623f, 1.0000f, 4.6200f, 0.6400f, 1.2300f, 0.4467f, 0.0320f, { 0.0000f, 0.0000f, 0.0000f }, 0.7943f, 0.0490f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.1100f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_SMALLWATERROOM \ + { 1.0000f, 0.7000f, 0.3162f, 0.4477f, 1.0000f, 1.5100f, 1.2500f, 1.1400f, 0.8913f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 1.4125f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.1790f, 0.1500f, 0.8950f, 0.1900f, 0.9920f, 5000.0000f, 250.0000f, 0.0000f, 0x0 } + +#endif /* EFX_PRESETS_H */ diff --git a/Lib/Include/AL/efx.h b/Lib/Include/AL/efx.h new file mode 100644 index 0000000..978f64a --- /dev/null +++ b/Lib/Include/AL/efx.h @@ -0,0 +1,758 @@ +#ifndef AL_EFX_H +#define AL_EFX_H + + +#ifdef __cplusplus +extern "C" { +#endif + +#define ALC_EXT_EFX_NAME "ALC_EXT_EFX" + +#define ALC_EFX_MAJOR_VERSION 0x20001 +#define ALC_EFX_MINOR_VERSION 0x20002 +#define ALC_MAX_AUXILIARY_SENDS 0x20003 + + +/* Listener properties. */ +#define AL_METERS_PER_UNIT 0x20004 + +/* Source properties. */ +#define AL_DIRECT_FILTER 0x20005 +#define AL_AUXILIARY_SEND_FILTER 0x20006 +#define AL_AIR_ABSORPTION_FACTOR 0x20007 +#define AL_ROOM_ROLLOFF_FACTOR 0x20008 +#define AL_CONE_OUTER_GAINHF 0x20009 +#define AL_DIRECT_FILTER_GAINHF_AUTO 0x2000A +#define AL_AUXILIARY_SEND_FILTER_GAIN_AUTO 0x2000B +#define AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO 0x2000C + + +/* Effect properties. */ + +/* Reverb effect parameters */ +#define AL_REVERB_DENSITY 0x0001 +#define AL_REVERB_DIFFUSION 0x0002 +#define AL_REVERB_GAIN 0x0003 +#define AL_REVERB_GAINHF 0x0004 +#define AL_REVERB_DECAY_TIME 0x0005 +#define AL_REVERB_DECAY_HFRATIO 0x0006 +#define AL_REVERB_REFLECTIONS_GAIN 0x0007 +#define AL_REVERB_REFLECTIONS_DELAY 0x0008 +#define AL_REVERB_LATE_REVERB_GAIN 0x0009 +#define AL_REVERB_LATE_REVERB_DELAY 0x000A +#define AL_REVERB_AIR_ABSORPTION_GAINHF 0x000B +#define AL_REVERB_ROOM_ROLLOFF_FACTOR 0x000C +#define AL_REVERB_DECAY_HFLIMIT 0x000D + +/* EAX Reverb effect parameters */ +#define AL_EAXREVERB_DENSITY 0x0001 +#define AL_EAXREVERB_DIFFUSION 0x0002 +#define AL_EAXREVERB_GAIN 0x0003 +#define AL_EAXREVERB_GAINHF 0x0004 +#define AL_EAXREVERB_GAINLF 0x0005 +#define AL_EAXREVERB_DECAY_TIME 0x0006 +#define AL_EAXREVERB_DECAY_HFRATIO 0x0007 +#define AL_EAXREVERB_DECAY_LFRATIO 0x0008 +#define AL_EAXREVERB_REFLECTIONS_GAIN 0x0009 +#define AL_EAXREVERB_REFLECTIONS_DELAY 0x000A +#define AL_EAXREVERB_REFLECTIONS_PAN 0x000B +#define AL_EAXREVERB_LATE_REVERB_GAIN 0x000C +#define AL_EAXREVERB_LATE_REVERB_DELAY 0x000D +#define AL_EAXREVERB_LATE_REVERB_PAN 0x000E +#define AL_EAXREVERB_ECHO_TIME 0x000F +#define AL_EAXREVERB_ECHO_DEPTH 0x0010 +#define AL_EAXREVERB_MODULATION_TIME 0x0011 +#define AL_EAXREVERB_MODULATION_DEPTH 0x0012 +#define AL_EAXREVERB_AIR_ABSORPTION_GAINHF 0x0013 +#define AL_EAXREVERB_HFREFERENCE 0x0014 +#define AL_EAXREVERB_LFREFERENCE 0x0015 +#define AL_EAXREVERB_ROOM_ROLLOFF_FACTOR 0x0016 +#define AL_EAXREVERB_DECAY_HFLIMIT 0x0017 + +/* Chorus effect parameters */ +#define AL_CHORUS_WAVEFORM 0x0001 +#define AL_CHORUS_PHASE 0x0002 +#define AL_CHORUS_RATE 0x0003 +#define AL_CHORUS_DEPTH 0x0004 +#define AL_CHORUS_FEEDBACK 0x0005 +#define AL_CHORUS_DELAY 0x0006 + +/* Distortion effect parameters */ +#define AL_DISTORTION_EDGE 0x0001 +#define AL_DISTORTION_GAIN 0x0002 +#define AL_DISTORTION_LOWPASS_CUTOFF 0x0003 +#define AL_DISTORTION_EQCENTER 0x0004 +#define AL_DISTORTION_EQBANDWIDTH 0x0005 + +/* Echo effect parameters */ +#define AL_ECHO_DELAY 0x0001 +#define AL_ECHO_LRDELAY 0x0002 +#define AL_ECHO_DAMPING 0x0003 +#define AL_ECHO_FEEDBACK 0x0004 +#define AL_ECHO_SPREAD 0x0005 + +/* Flanger effect parameters */ +#define AL_FLANGER_WAVEFORM 0x0001 +#define AL_FLANGER_PHASE 0x0002 +#define AL_FLANGER_RATE 0x0003 +#define AL_FLANGER_DEPTH 0x0004 +#define AL_FLANGER_FEEDBACK 0x0005 +#define AL_FLANGER_DELAY 0x0006 + +/* Frequency shifter effect parameters */ +#define AL_FREQUENCY_SHIFTER_FREQUENCY 0x0001 +#define AL_FREQUENCY_SHIFTER_LEFT_DIRECTION 0x0002 +#define AL_FREQUENCY_SHIFTER_RIGHT_DIRECTION 0x0003 + +/* Vocal morpher effect parameters */ +#define AL_VOCAL_MORPHER_PHONEMEA 0x0001 +#define AL_VOCAL_MORPHER_PHONEMEA_COARSE_TUNING 0x0002 +#define AL_VOCAL_MORPHER_PHONEMEB 0x0003 +#define AL_VOCAL_MORPHER_PHONEMEB_COARSE_TUNING 0x0004 +#define AL_VOCAL_MORPHER_WAVEFORM 0x0005 +#define AL_VOCAL_MORPHER_RATE 0x0006 + +/* Pitchshifter effect parameters */ +#define AL_PITCH_SHIFTER_COARSE_TUNE 0x0001 +#define AL_PITCH_SHIFTER_FINE_TUNE 0x0002 + +/* Ringmodulator effect parameters */ +#define AL_RING_MODULATOR_FREQUENCY 0x0001 +#define AL_RING_MODULATOR_HIGHPASS_CUTOFF 0x0002 +#define AL_RING_MODULATOR_WAVEFORM 0x0003 + +/* Autowah effect parameters */ +#define AL_AUTOWAH_ATTACK_TIME 0x0001 +#define AL_AUTOWAH_RELEASE_TIME 0x0002 +#define AL_AUTOWAH_RESONANCE 0x0003 +#define AL_AUTOWAH_PEAK_GAIN 0x0004 + +/* Compressor effect parameters */ +#define AL_COMPRESSOR_ONOFF 0x0001 + +/* Equalizer effect parameters */ +#define AL_EQUALIZER_LOW_GAIN 0x0001 +#define AL_EQUALIZER_LOW_CUTOFF 0x0002 +#define AL_EQUALIZER_MID1_GAIN 0x0003 +#define AL_EQUALIZER_MID1_CENTER 0x0004 +#define AL_EQUALIZER_MID1_WIDTH 0x0005 +#define AL_EQUALIZER_MID2_GAIN 0x0006 +#define AL_EQUALIZER_MID2_CENTER 0x0007 +#define AL_EQUALIZER_MID2_WIDTH 0x0008 +#define AL_EQUALIZER_HIGH_GAIN 0x0009 +#define AL_EQUALIZER_HIGH_CUTOFF 0x000A + +/* Effect type */ +#define AL_EFFECT_FIRST_PARAMETER 0x0000 +#define AL_EFFECT_LAST_PARAMETER 0x8000 +#define AL_EFFECT_TYPE 0x8001 + +/* Effect types, used with the AL_EFFECT_TYPE property */ +#define AL_EFFECT_NULL 0x0000 +#define AL_EFFECT_REVERB 0x0001 +#define AL_EFFECT_CHORUS 0x0002 +#define AL_EFFECT_DISTORTION 0x0003 +#define AL_EFFECT_ECHO 0x0004 +#define AL_EFFECT_FLANGER 0x0005 +#define AL_EFFECT_FREQUENCY_SHIFTER 0x0006 +#define AL_EFFECT_VOCAL_MORPHER 0x0007 +#define AL_EFFECT_PITCH_SHIFTER 0x0008 +#define AL_EFFECT_RING_MODULATOR 0x0009 +#define AL_EFFECT_AUTOWAH 0x000A +#define AL_EFFECT_COMPRESSOR 0x000B +#define AL_EFFECT_EQUALIZER 0x000C +#define AL_EFFECT_EAXREVERB 0x8000 + +/* Auxiliary Effect Slot properties. */ +#define AL_EFFECTSLOT_EFFECT 0x0001 +#define AL_EFFECTSLOT_GAIN 0x0002 +#define AL_EFFECTSLOT_AUXILIARY_SEND_AUTO 0x0003 + +/* NULL Auxiliary Slot ID to disable a source send. */ +#define AL_EFFECTSLOT_NULL 0x0000 + + +/* Filter properties. */ + +/* Lowpass filter parameters */ +#define AL_LOWPASS_GAIN 0x0001 +#define AL_LOWPASS_GAINHF 0x0002 + +/* Highpass filter parameters */ +#define AL_HIGHPASS_GAIN 0x0001 +#define AL_HIGHPASS_GAINLF 0x0002 + +/* Bandpass filter parameters */ +#define AL_BANDPASS_GAIN 0x0001 +#define AL_BANDPASS_GAINLF 0x0002 +#define AL_BANDPASS_GAINHF 0x0003 + +/* Filter type */ +#define AL_FILTER_FIRST_PARAMETER 0x0000 +#define AL_FILTER_LAST_PARAMETER 0x8000 +#define AL_FILTER_TYPE 0x8001 + +/* Filter types, used with the AL_FILTER_TYPE property */ +#define AL_FILTER_NULL 0x0000 +#define AL_FILTER_LOWPASS 0x0001 +#define AL_FILTER_HIGHPASS 0x0002 +#define AL_FILTER_BANDPASS 0x0003 + + +/* Effect object function types. */ +typedef void (AL_APIENTRY *LPALGENEFFECTS)(ALsizei, ALuint*); +typedef void (AL_APIENTRY *LPALDELETEEFFECTS)(ALsizei, const ALuint*); +typedef ALboolean (AL_APIENTRY *LPALISEFFECT)(ALuint); +typedef void (AL_APIENTRY *LPALEFFECTI)(ALuint, ALenum, ALint); +typedef void (AL_APIENTRY *LPALEFFECTIV)(ALuint, ALenum, const ALint*); +typedef void (AL_APIENTRY *LPALEFFECTF)(ALuint, ALenum, ALfloat); +typedef void (AL_APIENTRY *LPALEFFECTFV)(ALuint, ALenum, const ALfloat*); +typedef void (AL_APIENTRY *LPALGETEFFECTI)(ALuint, ALenum, ALint*); +typedef void (AL_APIENTRY *LPALGETEFFECTIV)(ALuint, ALenum, ALint*); +typedef void (AL_APIENTRY *LPALGETEFFECTF)(ALuint, ALenum, ALfloat*); +typedef void (AL_APIENTRY *LPALGETEFFECTFV)(ALuint, ALenum, ALfloat*); + +/* Filter object function types. */ +typedef void (AL_APIENTRY *LPALGENFILTERS)(ALsizei, ALuint*); +typedef void (AL_APIENTRY *LPALDELETEFILTERS)(ALsizei, const ALuint*); +typedef ALboolean (AL_APIENTRY *LPALISFILTER)(ALuint); +typedef void (AL_APIENTRY *LPALFILTERI)(ALuint, ALenum, ALint); +typedef void (AL_APIENTRY *LPALFILTERIV)(ALuint, ALenum, const ALint*); +typedef void (AL_APIENTRY *LPALFILTERF)(ALuint, ALenum, ALfloat); +typedef void (AL_APIENTRY *LPALFILTERFV)(ALuint, ALenum, const ALfloat*); +typedef void (AL_APIENTRY *LPALGETFILTERI)(ALuint, ALenum, ALint*); +typedef void (AL_APIENTRY *LPALGETFILTERIV)(ALuint, ALenum, ALint*); +typedef void (AL_APIENTRY *LPALGETFILTERF)(ALuint, ALenum, ALfloat*); +typedef void (AL_APIENTRY *LPALGETFILTERFV)(ALuint, ALenum, ALfloat*); + +/* Auxiliary Effect Slot object function types. */ +typedef void (AL_APIENTRY *LPALGENAUXILIARYEFFECTSLOTS)(ALsizei, ALuint*); +typedef void (AL_APIENTRY *LPALDELETEAUXILIARYEFFECTSLOTS)(ALsizei, const ALuint*); +typedef ALboolean (AL_APIENTRY *LPALISAUXILIARYEFFECTSLOT)(ALuint); +typedef void (AL_APIENTRY *LPALAUXILIARYEFFECTSLOTI)(ALuint, ALenum, ALint); +typedef void (AL_APIENTRY *LPALAUXILIARYEFFECTSLOTIV)(ALuint, ALenum, const ALint*); +typedef void (AL_APIENTRY *LPALAUXILIARYEFFECTSLOTF)(ALuint, ALenum, ALfloat); +typedef void (AL_APIENTRY *LPALAUXILIARYEFFECTSLOTFV)(ALuint, ALenum, const ALfloat*); +typedef void (AL_APIENTRY *LPALGETAUXILIARYEFFECTSLOTI)(ALuint, ALenum, ALint*); +typedef void (AL_APIENTRY *LPALGETAUXILIARYEFFECTSLOTIV)(ALuint, ALenum, ALint*); +typedef void (AL_APIENTRY *LPALGETAUXILIARYEFFECTSLOTF)(ALuint, ALenum, ALfloat*); +typedef void (AL_APIENTRY *LPALGETAUXILIARYEFFECTSLOTFV)(ALuint, ALenum, ALfloat*); + +#ifdef AL_ALEXT_PROTOTYPES +AL_API ALvoid AL_APIENTRY alGenEffects(ALsizei n, ALuint *effects); +AL_API ALvoid AL_APIENTRY alDeleteEffects(ALsizei n, const ALuint *effects); +AL_API ALboolean AL_APIENTRY alIsEffect(ALuint effect); +AL_API ALvoid AL_APIENTRY alEffecti(ALuint effect, ALenum param, ALint iValue); +AL_API ALvoid AL_APIENTRY alEffectiv(ALuint effect, ALenum param, const ALint *piValues); +AL_API ALvoid AL_APIENTRY alEffectf(ALuint effect, ALenum param, ALfloat flValue); +AL_API ALvoid AL_APIENTRY alEffectfv(ALuint effect, ALenum param, const ALfloat *pflValues); +AL_API ALvoid AL_APIENTRY alGetEffecti(ALuint effect, ALenum param, ALint *piValue); +AL_API ALvoid AL_APIENTRY alGetEffectiv(ALuint effect, ALenum param, ALint *piValues); +AL_API ALvoid AL_APIENTRY alGetEffectf(ALuint effect, ALenum param, ALfloat *pflValue); +AL_API ALvoid AL_APIENTRY alGetEffectfv(ALuint effect, ALenum param, ALfloat *pflValues); + +AL_API ALvoid AL_APIENTRY alGenFilters(ALsizei n, ALuint *filters); +AL_API ALvoid AL_APIENTRY alDeleteFilters(ALsizei n, const ALuint *filters); +AL_API ALboolean AL_APIENTRY alIsFilter(ALuint filter); +AL_API ALvoid AL_APIENTRY alFilteri(ALuint filter, ALenum param, ALint iValue); +AL_API ALvoid AL_APIENTRY alFilteriv(ALuint filter, ALenum param, const ALint *piValues); +AL_API ALvoid AL_APIENTRY alFilterf(ALuint filter, ALenum param, ALfloat flValue); +AL_API ALvoid AL_APIENTRY alFilterfv(ALuint filter, ALenum param, const ALfloat *pflValues); +AL_API ALvoid AL_APIENTRY alGetFilteri(ALuint filter, ALenum param, ALint *piValue); +AL_API ALvoid AL_APIENTRY alGetFilteriv(ALuint filter, ALenum param, ALint *piValues); +AL_API ALvoid AL_APIENTRY alGetFilterf(ALuint filter, ALenum param, ALfloat *pflValue); +AL_API ALvoid AL_APIENTRY alGetFilterfv(ALuint filter, ALenum param, ALfloat *pflValues); + +AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslots); +AL_API ALvoid AL_APIENTRY alDeleteAuxiliaryEffectSlots(ALsizei n, const ALuint *effectslots); +AL_API ALboolean AL_APIENTRY alIsAuxiliaryEffectSlot(ALuint effectslot); +AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint iValue); +AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, const ALint *piValues); +AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat flValue); +AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, const ALfloat *pflValues); +AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint *piValue); +AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, ALint *piValues); +AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat *pflValue); +AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, ALfloat *pflValues); +#endif + +/* Filter ranges and defaults. */ + +/* Lowpass filter */ +#define AL_LOWPASS_MIN_GAIN (0.0f) +#define AL_LOWPASS_MAX_GAIN (1.0f) +#define AL_LOWPASS_DEFAULT_GAIN (1.0f) + +#define AL_LOWPASS_MIN_GAINHF (0.0f) +#define AL_LOWPASS_MAX_GAINHF (1.0f) +#define AL_LOWPASS_DEFAULT_GAINHF (1.0f) + +/* Highpass filter */ +#define AL_HIGHPASS_MIN_GAIN (0.0f) +#define AL_HIGHPASS_MAX_GAIN (1.0f) +#define AL_HIGHPASS_DEFAULT_GAIN (1.0f) + +#define AL_HIGHPASS_MIN_GAINLF (0.0f) +#define AL_HIGHPASS_MAX_GAINLF (1.0f) +#define AL_HIGHPASS_DEFAULT_GAINLF (1.0f) + +/* Bandpass filter */ +#define AL_BANDPASS_MIN_GAIN (0.0f) +#define AL_BANDPASS_MAX_GAIN (1.0f) +#define AL_BANDPASS_DEFAULT_GAIN (1.0f) + +#define AL_BANDPASS_MIN_GAINHF (0.0f) +#define AL_BANDPASS_MAX_GAINHF (1.0f) +#define AL_BANDPASS_DEFAULT_GAINHF (1.0f) + +#define AL_BANDPASS_MIN_GAINLF (0.0f) +#define AL_BANDPASS_MAX_GAINLF (1.0f) +#define AL_BANDPASS_DEFAULT_GAINLF (1.0f) + + +/* Effect parameter ranges and defaults. */ + +/* Standard reverb effect */ +#define AL_REVERB_MIN_DENSITY (0.0f) +#define AL_REVERB_MAX_DENSITY (1.0f) +#define AL_REVERB_DEFAULT_DENSITY (1.0f) + +#define AL_REVERB_MIN_DIFFUSION (0.0f) +#define AL_REVERB_MAX_DIFFUSION (1.0f) +#define AL_REVERB_DEFAULT_DIFFUSION (1.0f) + +#define AL_REVERB_MIN_GAIN (0.0f) +#define AL_REVERB_MAX_GAIN (1.0f) +#define AL_REVERB_DEFAULT_GAIN (0.32f) + +#define AL_REVERB_MIN_GAINHF (0.0f) +#define AL_REVERB_MAX_GAINHF (1.0f) +#define AL_REVERB_DEFAULT_GAINHF (0.89f) + +#define AL_REVERB_MIN_DECAY_TIME (0.1f) +#define AL_REVERB_MAX_DECAY_TIME (20.0f) +#define AL_REVERB_DEFAULT_DECAY_TIME (1.49f) + +#define AL_REVERB_MIN_DECAY_HFRATIO (0.1f) +#define AL_REVERB_MAX_DECAY_HFRATIO (2.0f) +#define AL_REVERB_DEFAULT_DECAY_HFRATIO (0.83f) + +#define AL_REVERB_MIN_REFLECTIONS_GAIN (0.0f) +#define AL_REVERB_MAX_REFLECTIONS_GAIN (3.16f) +#define AL_REVERB_DEFAULT_REFLECTIONS_GAIN (0.05f) + +#define AL_REVERB_MIN_REFLECTIONS_DELAY (0.0f) +#define AL_REVERB_MAX_REFLECTIONS_DELAY (0.3f) +#define AL_REVERB_DEFAULT_REFLECTIONS_DELAY (0.007f) + +#define AL_REVERB_MIN_LATE_REVERB_GAIN (0.0f) +#define AL_REVERB_MAX_LATE_REVERB_GAIN (10.0f) +#define AL_REVERB_DEFAULT_LATE_REVERB_GAIN (1.26f) + +#define AL_REVERB_MIN_LATE_REVERB_DELAY (0.0f) +#define AL_REVERB_MAX_LATE_REVERB_DELAY (0.1f) +#define AL_REVERB_DEFAULT_LATE_REVERB_DELAY (0.011f) + +#define AL_REVERB_MIN_AIR_ABSORPTION_GAINHF (0.892f) +#define AL_REVERB_MAX_AIR_ABSORPTION_GAINHF (1.0f) +#define AL_REVERB_DEFAULT_AIR_ABSORPTION_GAINHF (0.994f) + +#define AL_REVERB_MIN_ROOM_ROLLOFF_FACTOR (0.0f) +#define AL_REVERB_MAX_ROOM_ROLLOFF_FACTOR (10.0f) +#define AL_REVERB_DEFAULT_ROOM_ROLLOFF_FACTOR (0.0f) + +#define AL_REVERB_MIN_DECAY_HFLIMIT AL_FALSE +#define AL_REVERB_MAX_DECAY_HFLIMIT AL_TRUE +#define AL_REVERB_DEFAULT_DECAY_HFLIMIT AL_TRUE + +/* EAX reverb effect */ +#define AL_EAXREVERB_MIN_DENSITY (0.0f) +#define AL_EAXREVERB_MAX_DENSITY (1.0f) +#define AL_EAXREVERB_DEFAULT_DENSITY (1.0f) + +#define AL_EAXREVERB_MIN_DIFFUSION (0.0f) +#define AL_EAXREVERB_MAX_DIFFUSION (1.0f) +#define AL_EAXREVERB_DEFAULT_DIFFUSION (1.0f) + +#define AL_EAXREVERB_MIN_GAIN (0.0f) +#define AL_EAXREVERB_MAX_GAIN (1.0f) +#define AL_EAXREVERB_DEFAULT_GAIN (0.32f) + +#define AL_EAXREVERB_MIN_GAINHF (0.0f) +#define AL_EAXREVERB_MAX_GAINHF (1.0f) +#define AL_EAXREVERB_DEFAULT_GAINHF (0.89f) + +#define AL_EAXREVERB_MIN_GAINLF (0.0f) +#define AL_EAXREVERB_MAX_GAINLF (1.0f) +#define AL_EAXREVERB_DEFAULT_GAINLF (1.0f) + +#define AL_EAXREVERB_MIN_DECAY_TIME (0.1f) +#define AL_EAXREVERB_MAX_DECAY_TIME (20.0f) +#define AL_EAXREVERB_DEFAULT_DECAY_TIME (1.49f) + +#define AL_EAXREVERB_MIN_DECAY_HFRATIO (0.1f) +#define AL_EAXREVERB_MAX_DECAY_HFRATIO (2.0f) +#define AL_EAXREVERB_DEFAULT_DECAY_HFRATIO (0.83f) + +#define AL_EAXREVERB_MIN_DECAY_LFRATIO (0.1f) +#define AL_EAXREVERB_MAX_DECAY_LFRATIO (2.0f) +#define AL_EAXREVERB_DEFAULT_DECAY_LFRATIO (1.0f) + +#define AL_EAXREVERB_MIN_REFLECTIONS_GAIN (0.0f) +#define AL_EAXREVERB_MAX_REFLECTIONS_GAIN (3.16f) +#define AL_EAXREVERB_DEFAULT_REFLECTIONS_GAIN (0.05f) + +#define AL_EAXREVERB_MIN_REFLECTIONS_DELAY (0.0f) +#define AL_EAXREVERB_MAX_REFLECTIONS_DELAY (0.3f) +#define AL_EAXREVERB_DEFAULT_REFLECTIONS_DELAY (0.007f) + +#define AL_EAXREVERB_DEFAULT_REFLECTIONS_PAN_XYZ (0.0f) + +#define AL_EAXREVERB_MIN_LATE_REVERB_GAIN (0.0f) +#define AL_EAXREVERB_MAX_LATE_REVERB_GAIN (10.0f) +#define AL_EAXREVERB_DEFAULT_LATE_REVERB_GAIN (1.26f) + +#define AL_EAXREVERB_MIN_LATE_REVERB_DELAY (0.0f) +#define AL_EAXREVERB_MAX_LATE_REVERB_DELAY (0.1f) +#define AL_EAXREVERB_DEFAULT_LATE_REVERB_DELAY (0.011f) + +#define AL_EAXREVERB_DEFAULT_LATE_REVERB_PAN_XYZ (0.0f) + +#define AL_EAXREVERB_MIN_ECHO_TIME (0.075f) +#define AL_EAXREVERB_MAX_ECHO_TIME (0.25f) +#define AL_EAXREVERB_DEFAULT_ECHO_TIME (0.25f) + +#define AL_EAXREVERB_MIN_ECHO_DEPTH (0.0f) +#define AL_EAXREVERB_MAX_ECHO_DEPTH (1.0f) +#define AL_EAXREVERB_DEFAULT_ECHO_DEPTH (0.0f) + +#define AL_EAXREVERB_MIN_MODULATION_TIME (0.04f) +#define AL_EAXREVERB_MAX_MODULATION_TIME (4.0f) +#define AL_EAXREVERB_DEFAULT_MODULATION_TIME (0.25f) + +#define AL_EAXREVERB_MIN_MODULATION_DEPTH (0.0f) +#define AL_EAXREVERB_MAX_MODULATION_DEPTH (1.0f) +#define AL_EAXREVERB_DEFAULT_MODULATION_DEPTH (0.0f) + +#define AL_EAXREVERB_MIN_AIR_ABSORPTION_GAINHF (0.892f) +#define AL_EAXREVERB_MAX_AIR_ABSORPTION_GAINHF (1.0f) +#define AL_EAXREVERB_DEFAULT_AIR_ABSORPTION_GAINHF (0.994f) + +#define AL_EAXREVERB_MIN_HFREFERENCE (1000.0f) +#define AL_EAXREVERB_MAX_HFREFERENCE (20000.0f) +#define AL_EAXREVERB_DEFAULT_HFREFERENCE (5000.0f) + +#define AL_EAXREVERB_MIN_LFREFERENCE (20.0f) +#define AL_EAXREVERB_MAX_LFREFERENCE (1000.0f) +#define AL_EAXREVERB_DEFAULT_LFREFERENCE (250.0f) + +#define AL_EAXREVERB_MIN_ROOM_ROLLOFF_FACTOR (0.0f) +#define AL_EAXREVERB_MAX_ROOM_ROLLOFF_FACTOR (10.0f) +#define AL_EAXREVERB_DEFAULT_ROOM_ROLLOFF_FACTOR (0.0f) + +#define AL_EAXREVERB_MIN_DECAY_HFLIMIT AL_FALSE +#define AL_EAXREVERB_MAX_DECAY_HFLIMIT AL_TRUE +#define AL_EAXREVERB_DEFAULT_DECAY_HFLIMIT AL_TRUE + +/* Chorus effect */ +#define AL_CHORUS_WAVEFORM_SINUSOID (0) +#define AL_CHORUS_WAVEFORM_TRIANGLE (1) + +#define AL_CHORUS_MIN_WAVEFORM (0) +#define AL_CHORUS_MAX_WAVEFORM (1) +#define AL_CHORUS_DEFAULT_WAVEFORM (1) + +#define AL_CHORUS_MIN_PHASE (-180) +#define AL_CHORUS_MAX_PHASE (180) +#define AL_CHORUS_DEFAULT_PHASE (90) + +#define AL_CHORUS_MIN_RATE (0.0f) +#define AL_CHORUS_MAX_RATE (10.0f) +#define AL_CHORUS_DEFAULT_RATE (1.1f) + +#define AL_CHORUS_MIN_DEPTH (0.0f) +#define AL_CHORUS_MAX_DEPTH (1.0f) +#define AL_CHORUS_DEFAULT_DEPTH (0.1f) + +#define AL_CHORUS_MIN_FEEDBACK (-1.0f) +#define AL_CHORUS_MAX_FEEDBACK (1.0f) +#define AL_CHORUS_DEFAULT_FEEDBACK (0.25f) + +#define AL_CHORUS_MIN_DELAY (0.0f) +#define AL_CHORUS_MAX_DELAY (0.016f) +#define AL_CHORUS_DEFAULT_DELAY (0.016f) + +/* Distortion effect */ +#define AL_DISTORTION_MIN_EDGE (0.0f) +#define AL_DISTORTION_MAX_EDGE (1.0f) +#define AL_DISTORTION_DEFAULT_EDGE (0.2f) + +#define AL_DISTORTION_MIN_GAIN (0.01f) +#define AL_DISTORTION_MAX_GAIN (1.0f) +#define AL_DISTORTION_DEFAULT_GAIN (0.05f) + +#define AL_DISTORTION_MIN_LOWPASS_CUTOFF (80.0f) +#define AL_DISTORTION_MAX_LOWPASS_CUTOFF (24000.0f) +#define AL_DISTORTION_DEFAULT_LOWPASS_CUTOFF (8000.0f) + +#define AL_DISTORTION_MIN_EQCENTER (80.0f) +#define AL_DISTORTION_MAX_EQCENTER (24000.0f) +#define AL_DISTORTION_DEFAULT_EQCENTER (3600.0f) + +#define AL_DISTORTION_MIN_EQBANDWIDTH (80.0f) +#define AL_DISTORTION_MAX_EQBANDWIDTH (24000.0f) +#define AL_DISTORTION_DEFAULT_EQBANDWIDTH (3600.0f) + +/* Echo effect */ +#define AL_ECHO_MIN_DELAY (0.0f) +#define AL_ECHO_MAX_DELAY (0.207f) +#define AL_ECHO_DEFAULT_DELAY (0.1f) + +#define AL_ECHO_MIN_LRDELAY (0.0f) +#define AL_ECHO_MAX_LRDELAY (0.404f) +#define AL_ECHO_DEFAULT_LRDELAY (0.1f) + +#define AL_ECHO_MIN_DAMPING (0.0f) +#define AL_ECHO_MAX_DAMPING (0.99f) +#define AL_ECHO_DEFAULT_DAMPING (0.5f) + +#define AL_ECHO_MIN_FEEDBACK (0.0f) +#define AL_ECHO_MAX_FEEDBACK (1.0f) +#define AL_ECHO_DEFAULT_FEEDBACK (0.5f) + +#define AL_ECHO_MIN_SPREAD (-1.0f) +#define AL_ECHO_MAX_SPREAD (1.0f) +#define AL_ECHO_DEFAULT_SPREAD (-1.0f) + +/* Flanger effect */ +#define AL_FLANGER_WAVEFORM_SINUSOID (0) +#define AL_FLANGER_WAVEFORM_TRIANGLE (1) + +#define AL_FLANGER_MIN_WAVEFORM (0) +#define AL_FLANGER_MAX_WAVEFORM (1) +#define AL_FLANGER_DEFAULT_WAVEFORM (1) + +#define AL_FLANGER_MIN_PHASE (-180) +#define AL_FLANGER_MAX_PHASE (180) +#define AL_FLANGER_DEFAULT_PHASE (0) + +#define AL_FLANGER_MIN_RATE (0.0f) +#define AL_FLANGER_MAX_RATE (10.0f) +#define AL_FLANGER_DEFAULT_RATE (0.27f) + +#define AL_FLANGER_MIN_DEPTH (0.0f) +#define AL_FLANGER_MAX_DEPTH (1.0f) +#define AL_FLANGER_DEFAULT_DEPTH (1.0f) + +#define AL_FLANGER_MIN_FEEDBACK (-1.0f) +#define AL_FLANGER_MAX_FEEDBACK (1.0f) +#define AL_FLANGER_DEFAULT_FEEDBACK (-0.5f) + +#define AL_FLANGER_MIN_DELAY (0.0f) +#define AL_FLANGER_MAX_DELAY (0.004f) +#define AL_FLANGER_DEFAULT_DELAY (0.002f) + +/* Frequency shifter effect */ +#define AL_FREQUENCY_SHIFTER_MIN_FREQUENCY (0.0f) +#define AL_FREQUENCY_SHIFTER_MAX_FREQUENCY (24000.0f) +#define AL_FREQUENCY_SHIFTER_DEFAULT_FREQUENCY (0.0f) + +#define AL_FREQUENCY_SHIFTER_MIN_LEFT_DIRECTION (0) +#define AL_FREQUENCY_SHIFTER_MAX_LEFT_DIRECTION (2) +#define AL_FREQUENCY_SHIFTER_DEFAULT_LEFT_DIRECTION (0) + +#define AL_FREQUENCY_SHIFTER_DIRECTION_DOWN (0) +#define AL_FREQUENCY_SHIFTER_DIRECTION_UP (1) +#define AL_FREQUENCY_SHIFTER_DIRECTION_OFF (2) + +#define AL_FREQUENCY_SHIFTER_MIN_RIGHT_DIRECTION (0) +#define AL_FREQUENCY_SHIFTER_MAX_RIGHT_DIRECTION (2) +#define AL_FREQUENCY_SHIFTER_DEFAULT_RIGHT_DIRECTION (0) + +/* Vocal morpher effect */ +#define AL_VOCAL_MORPHER_MIN_PHONEMEA (0) +#define AL_VOCAL_MORPHER_MAX_PHONEMEA (29) +#define AL_VOCAL_MORPHER_DEFAULT_PHONEMEA (0) + +#define AL_VOCAL_MORPHER_MIN_PHONEMEA_COARSE_TUNING (-24) +#define AL_VOCAL_MORPHER_MAX_PHONEMEA_COARSE_TUNING (24) +#define AL_VOCAL_MORPHER_DEFAULT_PHONEMEA_COARSE_TUNING (0) + +#define AL_VOCAL_MORPHER_MIN_PHONEMEB (0) +#define AL_VOCAL_MORPHER_MAX_PHONEMEB (29) +#define AL_VOCAL_MORPHER_DEFAULT_PHONEMEB (10) + +#define AL_VOCAL_MORPHER_MIN_PHONEMEB_COARSE_TUNING (-24) +#define AL_VOCAL_MORPHER_MAX_PHONEMEB_COARSE_TUNING (24) +#define AL_VOCAL_MORPHER_DEFAULT_PHONEMEB_COARSE_TUNING (0) + +#define AL_VOCAL_MORPHER_PHONEME_A (0) +#define AL_VOCAL_MORPHER_PHONEME_E (1) +#define AL_VOCAL_MORPHER_PHONEME_I (2) +#define AL_VOCAL_MORPHER_PHONEME_O (3) +#define AL_VOCAL_MORPHER_PHONEME_U (4) +#define AL_VOCAL_MORPHER_PHONEME_AA (5) +#define AL_VOCAL_MORPHER_PHONEME_AE (6) +#define AL_VOCAL_MORPHER_PHONEME_AH (7) +#define AL_VOCAL_MORPHER_PHONEME_AO (8) +#define AL_VOCAL_MORPHER_PHONEME_EH (9) +#define AL_VOCAL_MORPHER_PHONEME_ER (10) +#define AL_VOCAL_MORPHER_PHONEME_IH (11) +#define AL_VOCAL_MORPHER_PHONEME_IY (12) +#define AL_VOCAL_MORPHER_PHONEME_UH (13) +#define AL_VOCAL_MORPHER_PHONEME_UW (14) +#define AL_VOCAL_MORPHER_PHONEME_B (15) +#define AL_VOCAL_MORPHER_PHONEME_D (16) +#define AL_VOCAL_MORPHER_PHONEME_F (17) +#define AL_VOCAL_MORPHER_PHONEME_G (18) +#define AL_VOCAL_MORPHER_PHONEME_J (19) +#define AL_VOCAL_MORPHER_PHONEME_K (20) +#define AL_VOCAL_MORPHER_PHONEME_L (21) +#define AL_VOCAL_MORPHER_PHONEME_M (22) +#define AL_VOCAL_MORPHER_PHONEME_N (23) +#define AL_VOCAL_MORPHER_PHONEME_P (24) +#define AL_VOCAL_MORPHER_PHONEME_R (25) +#define AL_VOCAL_MORPHER_PHONEME_S (26) +#define AL_VOCAL_MORPHER_PHONEME_T (27) +#define AL_VOCAL_MORPHER_PHONEME_V (28) +#define AL_VOCAL_MORPHER_PHONEME_Z (29) + +#define AL_VOCAL_MORPHER_WAVEFORM_SINUSOID (0) +#define AL_VOCAL_MORPHER_WAVEFORM_TRIANGLE (1) +#define AL_VOCAL_MORPHER_WAVEFORM_SAWTOOTH (2) + +#define AL_VOCAL_MORPHER_MIN_WAVEFORM (0) +#define AL_VOCAL_MORPHER_MAX_WAVEFORM (2) +#define AL_VOCAL_MORPHER_DEFAULT_WAVEFORM (0) + +#define AL_VOCAL_MORPHER_MIN_RATE (0.0f) +#define AL_VOCAL_MORPHER_MAX_RATE (10.0f) +#define AL_VOCAL_MORPHER_DEFAULT_RATE (1.41f) + +/* Pitch shifter effect */ +#define AL_PITCH_SHIFTER_MIN_COARSE_TUNE (-12) +#define AL_PITCH_SHIFTER_MAX_COARSE_TUNE (12) +#define AL_PITCH_SHIFTER_DEFAULT_COARSE_TUNE (12) + +#define AL_PITCH_SHIFTER_MIN_FINE_TUNE (-50) +#define AL_PITCH_SHIFTER_MAX_FINE_TUNE (50) +#define AL_PITCH_SHIFTER_DEFAULT_FINE_TUNE (0) + +/* Ring modulator effect */ +#define AL_RING_MODULATOR_MIN_FREQUENCY (0.0f) +#define AL_RING_MODULATOR_MAX_FREQUENCY (8000.0f) +#define AL_RING_MODULATOR_DEFAULT_FREQUENCY (440.0f) + +#define AL_RING_MODULATOR_MIN_HIGHPASS_CUTOFF (0.0f) +#define AL_RING_MODULATOR_MAX_HIGHPASS_CUTOFF (24000.0f) +#define AL_RING_MODULATOR_DEFAULT_HIGHPASS_CUTOFF (800.0f) + +#define AL_RING_MODULATOR_SINUSOID (0) +#define AL_RING_MODULATOR_SAWTOOTH (1) +#define AL_RING_MODULATOR_SQUARE (2) + +#define AL_RING_MODULATOR_MIN_WAVEFORM (0) +#define AL_RING_MODULATOR_MAX_WAVEFORM (2) +#define AL_RING_MODULATOR_DEFAULT_WAVEFORM (0) + +/* Autowah effect */ +#define AL_AUTOWAH_MIN_ATTACK_TIME (0.0001f) +#define AL_AUTOWAH_MAX_ATTACK_TIME (1.0f) +#define AL_AUTOWAH_DEFAULT_ATTACK_TIME (0.06f) + +#define AL_AUTOWAH_MIN_RELEASE_TIME (0.0001f) +#define AL_AUTOWAH_MAX_RELEASE_TIME (1.0f) +#define AL_AUTOWAH_DEFAULT_RELEASE_TIME (0.06f) + +#define AL_AUTOWAH_MIN_RESONANCE (2.0f) +#define AL_AUTOWAH_MAX_RESONANCE (1000.0f) +#define AL_AUTOWAH_DEFAULT_RESONANCE (1000.0f) + +#define AL_AUTOWAH_MIN_PEAK_GAIN (0.00003f) +#define AL_AUTOWAH_MAX_PEAK_GAIN (31621.0f) +#define AL_AUTOWAH_DEFAULT_PEAK_GAIN (11.22f) + +/* Compressor effect */ +#define AL_COMPRESSOR_MIN_ONOFF (0) +#define AL_COMPRESSOR_MAX_ONOFF (1) +#define AL_COMPRESSOR_DEFAULT_ONOFF (1) + +/* Equalizer effect */ +#define AL_EQUALIZER_MIN_LOW_GAIN (0.126f) +#define AL_EQUALIZER_MAX_LOW_GAIN (7.943f) +#define AL_EQUALIZER_DEFAULT_LOW_GAIN (1.0f) + +#define AL_EQUALIZER_MIN_LOW_CUTOFF (50.0f) +#define AL_EQUALIZER_MAX_LOW_CUTOFF (800.0f) +#define AL_EQUALIZER_DEFAULT_LOW_CUTOFF (200.0f) + +#define AL_EQUALIZER_MIN_MID1_GAIN (0.126f) +#define AL_EQUALIZER_MAX_MID1_GAIN (7.943f) +#define AL_EQUALIZER_DEFAULT_MID1_GAIN (1.0f) + +#define AL_EQUALIZER_MIN_MID1_CENTER (200.0f) +#define AL_EQUALIZER_MAX_MID1_CENTER (3000.0f) +#define AL_EQUALIZER_DEFAULT_MID1_CENTER (500.0f) + +#define AL_EQUALIZER_MIN_MID1_WIDTH (0.01f) +#define AL_EQUALIZER_MAX_MID1_WIDTH (1.0f) +#define AL_EQUALIZER_DEFAULT_MID1_WIDTH (1.0f) + +#define AL_EQUALIZER_MIN_MID2_GAIN (0.126f) +#define AL_EQUALIZER_MAX_MID2_GAIN (7.943f) +#define AL_EQUALIZER_DEFAULT_MID2_GAIN (1.0f) + +#define AL_EQUALIZER_MIN_MID2_CENTER (1000.0f) +#define AL_EQUALIZER_MAX_MID2_CENTER (8000.0f) +#define AL_EQUALIZER_DEFAULT_MID2_CENTER (3000.0f) + +#define AL_EQUALIZER_MIN_MID2_WIDTH (0.01f) +#define AL_EQUALIZER_MAX_MID2_WIDTH (1.0f) +#define AL_EQUALIZER_DEFAULT_MID2_WIDTH (1.0f) + +#define AL_EQUALIZER_MIN_HIGH_GAIN (0.126f) +#define AL_EQUALIZER_MAX_HIGH_GAIN (7.943f) +#define AL_EQUALIZER_DEFAULT_HIGH_GAIN (1.0f) + +#define AL_EQUALIZER_MIN_HIGH_CUTOFF (4000.0f) +#define AL_EQUALIZER_MAX_HIGH_CUTOFF (16000.0f) +#define AL_EQUALIZER_DEFAULT_HIGH_CUTOFF (6000.0f) + + +/* Source parameter value ranges and defaults. */ +#define AL_MIN_AIR_ABSORPTION_FACTOR (0.0f) +#define AL_MAX_AIR_ABSORPTION_FACTOR (10.0f) +#define AL_DEFAULT_AIR_ABSORPTION_FACTOR (0.0f) + +#define AL_MIN_ROOM_ROLLOFF_FACTOR (0.0f) +#define AL_MAX_ROOM_ROLLOFF_FACTOR (10.0f) +#define AL_DEFAULT_ROOM_ROLLOFF_FACTOR (0.0f) + +#define AL_MIN_CONE_OUTER_GAINHF (0.0f) +#define AL_MAX_CONE_OUTER_GAINHF (1.0f) +#define AL_DEFAULT_CONE_OUTER_GAINHF (1.0f) + +#define AL_MIN_DIRECT_FILTER_GAINHF_AUTO AL_FALSE +#define AL_MAX_DIRECT_FILTER_GAINHF_AUTO AL_TRUE +#define AL_DEFAULT_DIRECT_FILTER_GAINHF_AUTO AL_TRUE + +#define AL_MIN_AUXILIARY_SEND_FILTER_GAIN_AUTO AL_FALSE +#define AL_MAX_AUXILIARY_SEND_FILTER_GAIN_AUTO AL_TRUE +#define AL_DEFAULT_AUXILIARY_SEND_FILTER_GAIN_AUTO AL_TRUE + +#define AL_MIN_AUXILIARY_SEND_FILTER_GAINHF_AUTO AL_FALSE +#define AL_MAX_AUXILIARY_SEND_FILTER_GAINHF_AUTO AL_TRUE +#define AL_DEFAULT_AUXILIARY_SEND_FILTER_GAINHF_AUTO AL_TRUE + + +/* Listener parameter value ranges and defaults. */ +#define AL_MIN_METERS_PER_UNIT FLT_MIN +#define AL_MAX_METERS_PER_UNIT FLT_MAX +#define AL_DEFAULT_METERS_PER_UNIT (1.0f) + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* AL_EFX_H */ diff --git a/Lib/Include/Box2D/Box2D.h b/Lib/Include/Box2D/Box2D.h new file mode 100644 index 0000000..1870461 --- /dev/null +++ b/Lib/Include/Box2D/Box2D.h @@ -0,0 +1,68 @@ +/* +* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org +* +* This software is provided 'as-is', without any express or implied +* warranty. In no event will the authors be held liable for any damages +* arising from the use of this software. +* Permission is granted to anyone to use this software for any purpose, +* including commercial applications, and to alter it and redistribute it +* freely, subject to the following restrictions: +* 1. The origin of this software must not be misrepresented; you must not +* claim that you wrote the original software. If you use this software +* in a product, an acknowledgment in the product documentation would be +* appreciated but is not required. +* 2. Altered source versions must be plainly marked as such, and must not be +* misrepresented as being the original software. +* 3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef BOX2D_H +#define BOX2D_H + +/** +\mainpage Box2D API Documentation + +\section intro_sec Getting Started + +For documentation please see http://box2d.org/documentation.html + +For discussion please visit http://box2d.org/forum +*/ + +// These include files constitute the main Box2D API + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#endif diff --git a/Lib/Include/Box2D/Collision/Shapes/b2ChainShape.h b/Lib/Include/Box2D/Collision/Shapes/b2ChainShape.h new file mode 100644 index 0000000..c66a329 --- /dev/null +++ b/Lib/Include/Box2D/Collision/Shapes/b2ChainShape.h @@ -0,0 +1,102 @@ +/* +* Copyright (c) 2006-2010 Erin Catto http://www.box2d.org +* +* This software is provided 'as-is', without any express or implied +* warranty. In no event will the authors be held liable for any damages +* arising from the use of this software. +* Permission is granted to anyone to use this software for any purpose, +* including commercial applications, and to alter it and redistribute it +* freely, subject to the following restrictions: +* 1. The origin of this software must not be misrepresented; you must not +* claim that you wrote the original software. If you use this software +* in a product, an acknowledgment in the product documentation would be +* appreciated but is not required. +* 2. Altered source versions must be plainly marked as such, and must not be +* misrepresented as being the original software. +* 3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef B2_CHAIN_SHAPE_H +#define B2_CHAIN_SHAPE_H + +#include + +class b2EdgeShape; + +/// A chain shape is a free form sequence of line segments. +/// The chain has two-sided collision, so you can use inside and outside collision. +/// Therefore, you may use any winding order. +/// Since there may be many vertices, they are allocated using b2Alloc. +/// Connectivity information is used to create smooth collisions. +/// WARNING: The chain will not collide properly if there are self-intersections. +class BOX2D_API b2ChainShape : public b2Shape +{ +public: + b2ChainShape(); + + /// The destructor frees the vertices using b2Free. + ~b2ChainShape(); + + /// Create a loop. This automatically adjusts connectivity. + /// @param vertices an array of vertices, these are copied + /// @param count the vertex count + void CreateLoop(const b2Vec2* vertices, int32 count); + + /// Create a chain with isolated end vertices. + /// @param vertices an array of vertices, these are copied + /// @param count the vertex count + void CreateChain(const b2Vec2* vertices, int32 count); + + /// Establish connectivity to a vertex that precedes the first vertex. + /// Don't call this for loops. + void SetPrevVertex(const b2Vec2& prevVertex); + + /// Establish connectivity to a vertex that follows the last vertex. + /// Don't call this for loops. + void SetNextVertex(const b2Vec2& nextVertex); + + /// Implement b2Shape. Vertices are cloned using b2Alloc. + b2Shape* Clone(b2BlockAllocator* allocator) const; + + /// @see b2Shape::GetChildCount + int32 GetChildCount() const; + + /// Get a child edge. + void GetChildEdge(b2EdgeShape* edge, int32 index) const; + + /// This always return false. + /// @see b2Shape::TestPoint + bool TestPoint(const b2Transform& transform, const b2Vec2& p) const; + + /// Implement b2Shape. + bool RayCast(b2RayCastOutput* output, const b2RayCastInput& input, + const b2Transform& transform, int32 childIndex) const; + + /// @see b2Shape::ComputeAABB + void ComputeAABB(b2AABB* aabb, const b2Transform& transform, int32 childIndex) const; + + /// Chains have zero mass. + /// @see b2Shape::ComputeMass + void ComputeMass(b2MassData* massData, float32 density) const; + + /// The vertices. Owned by this class. + b2Vec2* m_vertices; + + /// The vertex count. + int32 m_count; + + b2Vec2 m_prevVertex, m_nextVertex; + bool m_hasPrevVertex, m_hasNextVertex; +}; + +inline b2ChainShape::b2ChainShape() +{ + m_type = e_chain; + m_radius = b2_polygonRadius; + m_vertices = NULL; + m_count = 0; + m_hasPrevVertex = false; + m_hasNextVertex = false; +} + +#endif diff --git a/Lib/Include/Box2D/Collision/Shapes/b2CircleShape.h b/Lib/Include/Box2D/Collision/Shapes/b2CircleShape.h new file mode 100644 index 0000000..75933d1 --- /dev/null +++ b/Lib/Include/Box2D/Collision/Shapes/b2CircleShape.h @@ -0,0 +1,91 @@ +/* +* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org +* +* This software is provided 'as-is', without any express or implied +* warranty. In no event will the authors be held liable for any damages +* arising from the use of this software. +* Permission is granted to anyone to use this software for any purpose, +* including commercial applications, and to alter it and redistribute it +* freely, subject to the following restrictions: +* 1. The origin of this software must not be misrepresented; you must not +* claim that you wrote the original software. If you use this software +* in a product, an acknowledgment in the product documentation would be +* appreciated but is not required. +* 2. Altered source versions must be plainly marked as such, and must not be +* misrepresented as being the original software. +* 3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef B2_CIRCLE_SHAPE_H +#define B2_CIRCLE_SHAPE_H + +#include + +/// A circle shape. +class BOX2D_API b2CircleShape : public b2Shape +{ +public: + b2CircleShape(); + + /// Implement b2Shape. + b2Shape* Clone(b2BlockAllocator* allocator) const; + + /// @see b2Shape::GetChildCount + int32 GetChildCount() const; + + /// Implement b2Shape. + bool TestPoint(const b2Transform& transform, const b2Vec2& p) const; + + /// Implement b2Shape. + bool RayCast(b2RayCastOutput* output, const b2RayCastInput& input, + const b2Transform& transform, int32 childIndex) const; + + /// @see b2Shape::ComputeAABB + void ComputeAABB(b2AABB* aabb, const b2Transform& transform, int32 childIndex) const; + + /// @see b2Shape::ComputeMass + void ComputeMass(b2MassData* massData, float32 density) const; + + /// Get the supporting vertex index in the given direction. + int32 GetSupport(const b2Vec2& d) const; + + /// Get the supporting vertex in the given direction. + const b2Vec2& GetSupportVertex(const b2Vec2& d) const; + + /// Get the vertex count. + int32 GetVertexCount() const { return 1; } + + /// Get a vertex by index. Used by b2Distance. + const b2Vec2& GetVertex(int32 index) const; + + /// Position + b2Vec2 m_p; +}; + +inline b2CircleShape::b2CircleShape() +{ + m_type = e_circle; + m_radius = 0.0f; + m_p.SetZero(); +} + +inline int32 b2CircleShape::GetSupport(const b2Vec2 &d) const +{ + B2_NOT_USED(d); + return 0; +} + +inline const b2Vec2& b2CircleShape::GetSupportVertex(const b2Vec2 &d) const +{ + B2_NOT_USED(d); + return m_p; +} + +inline const b2Vec2& b2CircleShape::GetVertex(int32 index) const +{ + B2_NOT_USED(index); + b2Assert(index == 0); + return m_p; +} + +#endif diff --git a/Lib/Include/Box2D/Collision/Shapes/b2EdgeShape.h b/Lib/Include/Box2D/Collision/Shapes/b2EdgeShape.h new file mode 100644 index 0000000..f591d10 --- /dev/null +++ b/Lib/Include/Box2D/Collision/Shapes/b2EdgeShape.h @@ -0,0 +1,74 @@ +/* +* Copyright (c) 2006-2010 Erin Catto http://www.box2d.org +* +* This software is provided 'as-is', without any express or implied +* warranty. In no event will the authors be held liable for any damages +* arising from the use of this software. +* Permission is granted to anyone to use this software for any purpose, +* including commercial applications, and to alter it and redistribute it +* freely, subject to the following restrictions: +* 1. The origin of this software must not be misrepresented; you must not +* claim that you wrote the original software. If you use this software +* in a product, an acknowledgment in the product documentation would be +* appreciated but is not required. +* 2. Altered source versions must be plainly marked as such, and must not be +* misrepresented as being the original software. +* 3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef B2_EDGE_SHAPE_H +#define B2_EDGE_SHAPE_H + +#include + +/// A line segment (edge) shape. These can be connected in chains or loops +/// to other edge shapes. The connectivity information is used to ensure +/// correct contact normals. +class BOX2D_API b2EdgeShape : public b2Shape +{ +public: + b2EdgeShape(); + + /// Set this as an isolated edge. + void Set(const b2Vec2& v1, const b2Vec2& v2); + + /// Implement b2Shape. + b2Shape* Clone(b2BlockAllocator* allocator) const; + + /// @see b2Shape::GetChildCount + int32 GetChildCount() const; + + /// @see b2Shape::TestPoint + bool TestPoint(const b2Transform& transform, const b2Vec2& p) const; + + /// Implement b2Shape. + bool RayCast(b2RayCastOutput* output, const b2RayCastInput& input, + const b2Transform& transform, int32 childIndex) const; + + /// @see b2Shape::ComputeAABB + void ComputeAABB(b2AABB* aabb, const b2Transform& transform, int32 childIndex) const; + + /// @see b2Shape::ComputeMass + void ComputeMass(b2MassData* massData, float32 density) const; + + /// These are the edge vertices + b2Vec2 m_vertex1, m_vertex2; + + /// Optional adjacent vertices. These are used for smooth collision. + b2Vec2 m_vertex0, m_vertex3; + bool m_hasVertex0, m_hasVertex3; +}; + +inline b2EdgeShape::b2EdgeShape() +{ + m_type = e_edge; + m_radius = b2_polygonRadius; + m_vertex0.x = 0.0f; + m_vertex0.y = 0.0f; + m_vertex3.x = 0.0f; + m_vertex3.y = 0.0f; + m_hasVertex0 = false; + m_hasVertex3 = false; +} + +#endif diff --git a/Lib/Include/Box2D/Collision/Shapes/b2PolygonShape.h b/Lib/Include/Box2D/Collision/Shapes/b2PolygonShape.h new file mode 100644 index 0000000..53fc97d --- /dev/null +++ b/Lib/Include/Box2D/Collision/Shapes/b2PolygonShape.h @@ -0,0 +1,101 @@ +/* +* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org +* +* This software is provided 'as-is', without any express or implied +* warranty. In no event will the authors be held liable for any damages +* arising from the use of this software. +* Permission is granted to anyone to use this software for any purpose, +* including commercial applications, and to alter it and redistribute it +* freely, subject to the following restrictions: +* 1. The origin of this software must not be misrepresented; you must not +* claim that you wrote the original software. If you use this software +* in a product, an acknowledgment in the product documentation would be +* appreciated but is not required. +* 2. Altered source versions must be plainly marked as such, and must not be +* misrepresented as being the original software. +* 3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef B2_POLYGON_SHAPE_H +#define B2_POLYGON_SHAPE_H + +#include + +/// A convex polygon. It is assumed that the interior of the polygon is to +/// the left of each edge. +/// Polygons have a maximum number of vertices equal to b2_maxPolygonVertices. +/// In most cases you should not need many vertices for a convex polygon. +class BOX2D_API b2PolygonShape : public b2Shape +{ +public: + b2PolygonShape(); + + /// Implement b2Shape. + b2Shape* Clone(b2BlockAllocator* allocator) const; + + /// @see b2Shape::GetChildCount + int32 GetChildCount() const; + + /// Create a convex hull from the given array of local points. + /// The count must be in the range [3, b2_maxPolygonVertices]. + /// @warning the points may be re-ordered, even if they form a convex polygon + /// @warning collinear points are handled but not removed. Collinear points + /// may lead to poor stacking behavior. + void Set(const b2Vec2* points, int32 count); + + /// Build vertices to represent an axis-aligned box centered on the local origin. + /// @param hx the half-width. + /// @param hy the half-height. + void SetAsBox(float32 hx, float32 hy); + + /// Build vertices to represent an oriented box. + /// @param hx the half-width. + /// @param hy the half-height. + /// @param center the center of the box in local coordinates. + /// @param angle the rotation of the box in local coordinates. + void SetAsBox(float32 hx, float32 hy, const b2Vec2& center, float32 angle); + + /// @see b2Shape::TestPoint + bool TestPoint(const b2Transform& transform, const b2Vec2& p) const; + + /// Implement b2Shape. + bool RayCast(b2RayCastOutput* output, const b2RayCastInput& input, + const b2Transform& transform, int32 childIndex) const; + + /// @see b2Shape::ComputeAABB + void ComputeAABB(b2AABB* aabb, const b2Transform& transform, int32 childIndex) const; + + /// @see b2Shape::ComputeMass + void ComputeMass(b2MassData* massData, float32 density) const; + + /// Get the vertex count. + int32 GetVertexCount() const { return m_count; } + + /// Get a vertex by index. + const b2Vec2& GetVertex(int32 index) const; + + /// Validate convexity. This is a very time consuming operation. + /// @returns true if valid + bool Validate() const; + + b2Vec2 m_centroid; + b2Vec2 m_vertices[b2_maxPolygonVertices]; + b2Vec2 m_normals[b2_maxPolygonVertices]; + int32 m_count; +}; + +inline b2PolygonShape::b2PolygonShape() +{ + m_type = e_polygon; + m_radius = b2_polygonRadius; + m_count = 0; + m_centroid.SetZero(); +} + +inline const b2Vec2& b2PolygonShape::GetVertex(int32 index) const +{ + b2Assert(0 <= index && index < m_count); + return m_vertices[index]; +} + +#endif diff --git a/Lib/Include/Box2D/Collision/Shapes/b2Shape.h b/Lib/Include/Box2D/Collision/Shapes/b2Shape.h new file mode 100644 index 0000000..3914b6f --- /dev/null +++ b/Lib/Include/Box2D/Collision/Shapes/b2Shape.h @@ -0,0 +1,101 @@ +/* +* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org +* +* This software is provided 'as-is', without any express or implied +* warranty. In no event will the authors be held liable for any damages +* arising from the use of this software. +* Permission is granted to anyone to use this software for any purpose, +* including commercial applications, and to alter it and redistribute it +* freely, subject to the following restrictions: +* 1. The origin of this software must not be misrepresented; you must not +* claim that you wrote the original software. If you use this software +* in a product, an acknowledgment in the product documentation would be +* appreciated but is not required. +* 2. Altered source versions must be plainly marked as such, and must not be +* misrepresented as being the original software. +* 3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef B2_SHAPE_H +#define B2_SHAPE_H + +#include +#include +#include + +/// This holds the mass data computed for a shape. +struct b2MassData +{ + /// The mass of the shape, usually in kilograms. + float32 mass; + + /// The position of the shape's centroid relative to the shape's origin. + b2Vec2 center; + + /// The rotational inertia of the shape about the local origin. + float32 I; +}; + +/// A shape is used for collision detection. You can create a shape however you like. +/// Shapes used for simulation in b2World are created automatically when a b2Fixture +/// is created. Shapes may encapsulate a one or more child shapes. +class BOX2D_API b2Shape +{ +public: + + enum Type + { + e_circle = 0, + e_edge = 1, + e_polygon = 2, + e_chain = 3, + e_typeCount = 4 + }; + + virtual ~b2Shape() {} + + /// Clone the concrete shape using the provided allocator. + virtual b2Shape* Clone(b2BlockAllocator* allocator) const = 0; + + /// Get the type of this shape. You can use this to down cast to the concrete shape. + /// @return the shape type. + Type GetType() const; + + /// Get the number of child primitives. + virtual int32 GetChildCount() const = 0; + + /// Test a point for containment in this shape. This only works for convex shapes. + /// @param xf the shape world transform. + /// @param p a point in world coordinates. + virtual bool TestPoint(const b2Transform& xf, const b2Vec2& p) const = 0; + + /// Cast a ray against a child shape. + /// @param output the ray-cast results. + /// @param input the ray-cast input parameters. + /// @param transform the transform to be applied to the shape. + /// @param childIndex the child shape index + virtual bool RayCast(b2RayCastOutput* output, const b2RayCastInput& input, + const b2Transform& transform, int32 childIndex) const = 0; + + /// Given a transform, compute the associated axis aligned bounding box for a child shape. + /// @param aabb returns the axis aligned box. + /// @param xf the world transform of the shape. + /// @param childIndex the child shape + virtual void ComputeAABB(b2AABB* aabb, const b2Transform& xf, int32 childIndex) const = 0; + + /// Compute the mass properties of this shape using its dimensions and density. + /// The inertia tensor is computed about the local origin. + /// @param massData returns the mass data for this shape. + /// @param density the density in kilograms per meter squared. + virtual void ComputeMass(b2MassData* massData, float32 density) const = 0; + + Type m_type; + float32 m_radius; +}; + +inline b2Shape::Type b2Shape::GetType() const +{ + return m_type; +} + +#endif diff --git a/Lib/Include/Box2D/Collision/b2BroadPhase.h b/Lib/Include/Box2D/Collision/b2BroadPhase.h new file mode 100644 index 0000000..0fbef95 --- /dev/null +++ b/Lib/Include/Box2D/Collision/b2BroadPhase.h @@ -0,0 +1,257 @@ +/* +* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org +* +* This software is provided 'as-is', without any express or implied +* warranty. In no event will the authors be held liable for any damages +* arising from the use of this software. +* Permission is granted to anyone to use this software for any purpose, +* including commercial applications, and to alter it and redistribute it +* freely, subject to the following restrictions: +* 1. The origin of this software must not be misrepresented; you must not +* claim that you wrote the original software. If you use this software +* in a product, an acknowledgment in the product documentation would be +* appreciated but is not required. +* 2. Altered source versions must be plainly marked as such, and must not be +* misrepresented as being the original software. +* 3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef B2_BROAD_PHASE_H +#define B2_BROAD_PHASE_H + +#include +#include +#include +#include + +struct b2Pair +{ + int32 proxyIdA; + int32 proxyIdB; +}; + +/// The broad-phase is used for computing pairs and performing volume queries and ray casts. +/// This broad-phase does not persist pairs. Instead, this reports potentially new pairs. +/// It is up to the client to consume the new pairs and to track subsequent overlap. +class BOX2D_API b2BroadPhase +{ +public: + + enum + { + e_nullProxy = -1 + }; + + b2BroadPhase(); + ~b2BroadPhase(); + + /// Create a proxy with an initial AABB. Pairs are not reported until + /// UpdatePairs is called. + int32 CreateProxy(const b2AABB& aabb, void* userData); + + /// Destroy a proxy. It is up to the client to remove any pairs. + void DestroyProxy(int32 proxyId); + + /// Call MoveProxy as many times as you like, then when you are done + /// call UpdatePairs to finalized the proxy pairs (for your time step). + void MoveProxy(int32 proxyId, const b2AABB& aabb, const b2Vec2& displacement); + + /// Call to trigger a re-processing of it's pairs on the next call to UpdatePairs. + void TouchProxy(int32 proxyId); + + /// Get the fat AABB for a proxy. + const b2AABB& GetFatAABB(int32 proxyId) const; + + /// Get user data from a proxy. Returns NULL if the id is invalid. + void* GetUserData(int32 proxyId) const; + + /// Test overlap of fat AABBs. + bool TestOverlap(int32 proxyIdA, int32 proxyIdB) const; + + /// Get the number of proxies. + int32 GetProxyCount() const; + + /// Update the pairs. This results in pair callbacks. This can only add pairs. + template + void UpdatePairs(T* callback); + + /// Query an AABB for overlapping proxies. The callback class + /// is called for each proxy that overlaps the supplied AABB. + template + void Query(T* callback, const b2AABB& aabb) const; + + /// Ray-cast against the proxies in the tree. This relies on the callback + /// to perform a exact ray-cast in the case were the proxy contains a shape. + /// The callback also performs the any collision filtering. This has performance + /// roughly equal to k * log(n), where k is the number of collisions and n is the + /// number of proxies in the tree. + /// @param input the ray-cast input data. The ray extends from p1 to p1 + maxFraction * (p2 - p1). + /// @param callback a callback class that is called for each proxy that is hit by the ray. + template + void RayCast(T* callback, const b2RayCastInput& input) const; + + /// Get the height of the embedded tree. + int32 GetTreeHeight() const; + + /// Get the balance of the embedded tree. + int32 GetTreeBalance() const; + + /// Get the quality metric of the embedded tree. + float32 GetTreeQuality() const; + + /// Shift the world origin. Useful for large worlds. + /// The shift formula is: position -= newOrigin + /// @param newOrigin the new origin with respect to the old origin + void ShiftOrigin(const b2Vec2& newOrigin); + +private: + + friend class b2DynamicTree; + + void BufferMove(int32 proxyId); + void UnBufferMove(int32 proxyId); + + bool QueryCallback(int32 proxyId); + + b2DynamicTree m_tree; + + int32 m_proxyCount; + + int32* m_moveBuffer; + int32 m_moveCapacity; + int32 m_moveCount; + + b2Pair* m_pairBuffer; + int32 m_pairCapacity; + int32 m_pairCount; + + int32 m_queryProxyId; +}; + +/// This is used to sort pairs. +inline bool b2PairLessThan(const b2Pair& pair1, const b2Pair& pair2) +{ + if (pair1.proxyIdA < pair2.proxyIdA) + { + return true; + } + + if (pair1.proxyIdA == pair2.proxyIdA) + { + return pair1.proxyIdB < pair2.proxyIdB; + } + + return false; +} + +inline void* b2BroadPhase::GetUserData(int32 proxyId) const +{ + return m_tree.GetUserData(proxyId); +} + +inline bool b2BroadPhase::TestOverlap(int32 proxyIdA, int32 proxyIdB) const +{ + const b2AABB& aabbA = m_tree.GetFatAABB(proxyIdA); + const b2AABB& aabbB = m_tree.GetFatAABB(proxyIdB); + return b2TestOverlap(aabbA, aabbB); +} + +inline const b2AABB& b2BroadPhase::GetFatAABB(int32 proxyId) const +{ + return m_tree.GetFatAABB(proxyId); +} + +inline int32 b2BroadPhase::GetProxyCount() const +{ + return m_proxyCount; +} + +inline int32 b2BroadPhase::GetTreeHeight() const +{ + return m_tree.GetHeight(); +} + +inline int32 b2BroadPhase::GetTreeBalance() const +{ + return m_tree.GetMaxBalance(); +} + +inline float32 b2BroadPhase::GetTreeQuality() const +{ + return m_tree.GetAreaRatio(); +} + +template +void b2BroadPhase::UpdatePairs(T* callback) +{ + // Reset pair buffer + m_pairCount = 0; + + // Perform tree queries for all moving proxies. + for (int32 i = 0; i < m_moveCount; ++i) + { + m_queryProxyId = m_moveBuffer[i]; + if (m_queryProxyId == e_nullProxy) + { + continue; + } + + // We have to query the tree with the fat AABB so that + // we don't fail to create a pair that may touch later. + const b2AABB& fatAABB = m_tree.GetFatAABB(m_queryProxyId); + + // Query tree, create pairs and add them pair buffer. + m_tree.Query(this, fatAABB); + } + + // Reset move buffer + m_moveCount = 0; + + // Sort the pair buffer to expose duplicates. + std::sort(m_pairBuffer, m_pairBuffer + m_pairCount, b2PairLessThan); + + // Send the pairs back to the client. + int32 i = 0; + while (i < m_pairCount) + { + b2Pair* primaryPair = m_pairBuffer + i; + void* userDataA = m_tree.GetUserData(primaryPair->proxyIdA); + void* userDataB = m_tree.GetUserData(primaryPair->proxyIdB); + + callback->AddPair(userDataA, userDataB); + ++i; + + // Skip any duplicate pairs. + while (i < m_pairCount) + { + b2Pair* pair = m_pairBuffer + i; + if (pair->proxyIdA != primaryPair->proxyIdA || pair->proxyIdB != primaryPair->proxyIdB) + { + break; + } + ++i; + } + } + + // Try to keep the tree balanced. + //m_tree.Rebalance(4); +} + +template +inline void b2BroadPhase::Query(T* callback, const b2AABB& aabb) const +{ + m_tree.Query(callback, aabb); +} + +template +inline void b2BroadPhase::RayCast(T* callback, const b2RayCastInput& input) const +{ + m_tree.RayCast(callback, input); +} + +inline void b2BroadPhase::ShiftOrigin(const b2Vec2& newOrigin) +{ + m_tree.ShiftOrigin(newOrigin); +} + +#endif diff --git a/Lib/Include/Box2D/Collision/b2Collision.h b/Lib/Include/Box2D/Collision/b2Collision.h new file mode 100644 index 0000000..3166dca --- /dev/null +++ b/Lib/Include/Box2D/Collision/b2Collision.h @@ -0,0 +1,277 @@ +/* +* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org +* +* This software is provided 'as-is', without any express or implied +* warranty. In no event will the authors be held liable for any damages +* arising from the use of this software. +* Permission is granted to anyone to use this software for any purpose, +* including commercial applications, and to alter it and redistribute it +* freely, subject to the following restrictions: +* 1. The origin of this software must not be misrepresented; you must not +* claim that you wrote the original software. If you use this software +* in a product, an acknowledgment in the product documentation would be +* appreciated but is not required. +* 2. Altered source versions must be plainly marked as such, and must not be +* misrepresented as being the original software. +* 3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef B2_COLLISION_H +#define B2_COLLISION_H + +#include +#include + +/// @file +/// Structures and functions used for computing contact points, distance +/// queries, and TOI queries. + +class b2Shape; +class b2CircleShape; +class b2EdgeShape; +class b2PolygonShape; + +const uint8 b2_nullFeature = UCHAR_MAX; + +/// The features that intersect to form the contact point +/// This must be 4 bytes or less. +struct b2ContactFeature +{ + enum Type + { + e_vertex = 0, + e_face = 1 + }; + + uint8 indexA; ///< Feature index on shapeA + uint8 indexB; ///< Feature index on shapeB + uint8 typeA; ///< The feature type on shapeA + uint8 typeB; ///< The feature type on shapeB +}; + +/// Contact ids to facilitate warm starting. +union b2ContactID +{ + b2ContactFeature cf; + uint32 key; ///< Used to quickly compare contact ids. +}; + +/// A manifold point is a contact point belonging to a contact +/// manifold. It holds details related to the geometry and dynamics +/// of the contact points. +/// The local point usage depends on the manifold type: +/// -e_circles: the local center of circleB +/// -e_faceA: the local center of cirlceB or the clip point of polygonB +/// -e_faceB: the clip point of polygonA +/// This structure is stored across time steps, so we keep it small. +/// Note: the impulses are used for internal caching and may not +/// provide reliable contact forces, especially for high speed collisions. +struct b2ManifoldPoint +{ + b2Vec2 localPoint; ///< usage depends on manifold type + float32 normalImpulse; ///< the non-penetration impulse + float32 tangentImpulse; ///< the friction impulse + b2ContactID id; ///< uniquely identifies a contact point between two shapes +}; + +/// A manifold for two touching convex shapes. +/// Box2D supports multiple types of contact: +/// - clip point versus plane with radius +/// - point versus point with radius (circles) +/// The local point usage depends on the manifold type: +/// -e_circles: the local center of circleA +/// -e_faceA: the center of faceA +/// -e_faceB: the center of faceB +/// Similarly the local normal usage: +/// -e_circles: not used +/// -e_faceA: the normal on polygonA +/// -e_faceB: the normal on polygonB +/// We store contacts in this way so that position correction can +/// account for movement, which is critical for continuous physics. +/// All contact scenarios must be expressed in one of these types. +/// This structure is stored across time steps, so we keep it small. +struct b2Manifold +{ + enum Type + { + e_circles, + e_faceA, + e_faceB + }; + + b2ManifoldPoint points[b2_maxManifoldPoints]; ///< the points of contact + b2Vec2 localNormal; ///< not use for Type::e_points + b2Vec2 localPoint; ///< usage depends on manifold type + Type type; + int32 pointCount; ///< the number of manifold points +}; + +/// This is used to compute the current state of a contact manifold. +struct BOX2D_API b2WorldManifold +{ + /// Evaluate the manifold with supplied transforms. This assumes + /// modest motion from the original state. This does not change the + /// point count, impulses, etc. The radii must come from the shapes + /// that generated the manifold. + void Initialize(const b2Manifold* manifold, + const b2Transform& xfA, float32 radiusA, + const b2Transform& xfB, float32 radiusB); + + b2Vec2 normal; ///< world vector pointing from A to B + b2Vec2 points[b2_maxManifoldPoints]; ///< world contact point (point of intersection) + float32 separations[b2_maxManifoldPoints]; ///< a negative value indicates overlap, in meters +}; + +/// This is used for determining the state of contact points. +enum b2PointState +{ + b2_nullState, ///< point does not exist + b2_addState, ///< point was added in the update + b2_persistState, ///< point persisted across the update + b2_removeState ///< point was removed in the update +}; + +/// Compute the point states given two manifolds. The states pertain to the transition from manifold1 +/// to manifold2. So state1 is either persist or remove while state2 is either add or persist. +BOX2D_API void b2GetPointStates(b2PointState state1[b2_maxManifoldPoints], b2PointState state2[b2_maxManifoldPoints], + const b2Manifold* manifold1, const b2Manifold* manifold2); + +/// Used for computing contact manifolds. +struct b2ClipVertex +{ + b2Vec2 v; + b2ContactID id; +}; + +/// Ray-cast input data. The ray extends from p1 to p1 + maxFraction * (p2 - p1). +struct b2RayCastInput +{ + b2Vec2 p1, p2; + float32 maxFraction; +}; + +/// Ray-cast output data. The ray hits at p1 + fraction * (p2 - p1), where p1 and p2 +/// come from b2RayCastInput. +struct b2RayCastOutput +{ + b2Vec2 normal; + float32 fraction; +}; + +/// An axis aligned bounding box. +struct BOX2D_API b2AABB +{ + /// Verify that the bounds are sorted. + bool IsValid() const; + + /// Get the center of the AABB. + b2Vec2 GetCenter() const + { + return 0.5f * (lowerBound + upperBound); + } + + /// Get the extents of the AABB (half-widths). + b2Vec2 GetExtents() const + { + return 0.5f * (upperBound - lowerBound); + } + + /// Get the perimeter length + float32 GetPerimeter() const + { + float32 wx = upperBound.x - lowerBound.x; + float32 wy = upperBound.y - lowerBound.y; + return 2.0f * (wx + wy); + } + + /// Combine an AABB into this one. + void Combine(const b2AABB& aabb) + { + lowerBound = b2Min(lowerBound, aabb.lowerBound); + upperBound = b2Max(upperBound, aabb.upperBound); + } + + /// Combine two AABBs into this one. + void Combine(const b2AABB& aabb1, const b2AABB& aabb2) + { + lowerBound = b2Min(aabb1.lowerBound, aabb2.lowerBound); + upperBound = b2Max(aabb1.upperBound, aabb2.upperBound); + } + + /// Does this aabb contain the provided AABB. + bool Contains(const b2AABB& aabb) const + { + bool result = true; + result = result && lowerBound.x <= aabb.lowerBound.x; + result = result && lowerBound.y <= aabb.lowerBound.y; + result = result && aabb.upperBound.x <= upperBound.x; + result = result && aabb.upperBound.y <= upperBound.y; + return result; + } + + bool RayCast(b2RayCastOutput* output, const b2RayCastInput& input) const; + + b2Vec2 lowerBound; ///< the lower vertex + b2Vec2 upperBound; ///< the upper vertex +}; + +/// Compute the collision manifold between two circles. +BOX2D_API void b2CollideCircles(b2Manifold* manifold, + const b2CircleShape* circleA, const b2Transform& xfA, + const b2CircleShape* circleB, const b2Transform& xfB); + +/// Compute the collision manifold between a polygon and a circle. +BOX2D_API void b2CollidePolygonAndCircle(b2Manifold* manifold, + const b2PolygonShape* polygonA, const b2Transform& xfA, + const b2CircleShape* circleB, const b2Transform& xfB); + +/// Compute the collision manifold between two polygons. +BOX2D_API void b2CollidePolygons(b2Manifold* manifold, + const b2PolygonShape* polygonA, const b2Transform& xfA, + const b2PolygonShape* polygonB, const b2Transform& xfB); + +/// Compute the collision manifold between an edge and a circle. +BOX2D_API void b2CollideEdgeAndCircle(b2Manifold* manifold, + const b2EdgeShape* polygonA, const b2Transform& xfA, + const b2CircleShape* circleB, const b2Transform& xfB); + +/// Compute the collision manifold between an edge and a circle. +BOX2D_API void b2CollideEdgeAndPolygon(b2Manifold* manifold, + const b2EdgeShape* edgeA, const b2Transform& xfA, + const b2PolygonShape* circleB, const b2Transform& xfB); + +/// Clipping for contact manifolds. +BOX2D_API int32 b2ClipSegmentToLine(b2ClipVertex vOut[2], const b2ClipVertex vIn[2], + const b2Vec2& normal, float32 offset, int32 vertexIndexA); + +/// Determine if two generic shapes overlap. +BOX2D_API bool b2TestOverlap( const b2Shape* shapeA, int32 indexA, + const b2Shape* shapeB, int32 indexB, + const b2Transform& xfA, const b2Transform& xfB); + +// ---------------- Inline Functions ------------------------------------------ + +inline bool b2AABB::IsValid() const +{ + b2Vec2 d = upperBound - lowerBound; + bool valid = d.x >= 0.0f && d.y >= 0.0f; + valid = valid && lowerBound.IsValid() && upperBound.IsValid(); + return valid; +} + +inline bool b2TestOverlap(const b2AABB& a, const b2AABB& b) +{ + b2Vec2 d1, d2; + d1 = b.lowerBound - a.upperBound; + d2 = a.lowerBound - b.upperBound; + + if (d1.x > 0.0f || d1.y > 0.0f) + return false; + + if (d2.x > 0.0f || d2.y > 0.0f) + return false; + + return true; +} + +#endif diff --git a/Lib/Include/Box2D/Collision/b2Distance.h b/Lib/Include/Box2D/Collision/b2Distance.h new file mode 100644 index 0000000..05a1256 --- /dev/null +++ b/Lib/Include/Box2D/Collision/b2Distance.h @@ -0,0 +1,141 @@ + +/* +* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org +* +* This software is provided 'as-is', without any express or implied +* warranty. In no event will the authors be held liable for any damages +* arising from the use of this software. +* Permission is granted to anyone to use this software for any purpose, +* including commercial applications, and to alter it and redistribute it +* freely, subject to the following restrictions: +* 1. The origin of this software must not be misrepresented; you must not +* claim that you wrote the original software. If you use this software +* in a product, an acknowledgment in the product documentation would be +* appreciated but is not required. +* 2. Altered source versions must be plainly marked as such, and must not be +* misrepresented as being the original software. +* 3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef B2_DISTANCE_H +#define B2_DISTANCE_H + +#include + +class b2Shape; + +/// A distance proxy is used by the GJK algorithm. +/// It encapsulates any shape. +struct BOX2D_API b2DistanceProxy +{ + b2DistanceProxy() : m_vertices(NULL), m_count(0), m_radius(0.0f) {} + + /// Initialize the proxy using the given shape. The shape + /// must remain in scope while the proxy is in use. + void Set(const b2Shape* shape, int32 index); + + /// Get the supporting vertex index in the given direction. + int32 GetSupport(const b2Vec2& d) const; + + /// Get the supporting vertex in the given direction. + const b2Vec2& GetSupportVertex(const b2Vec2& d) const; + + /// Get the vertex count. + int32 GetVertexCount() const; + + /// Get a vertex by index. Used by b2Distance. + const b2Vec2& GetVertex(int32 index) const; + + b2Vec2 m_buffer[2]; + const b2Vec2* m_vertices; + int32 m_count; + float32 m_radius; +}; + +/// Used to warm start b2Distance. +/// Set count to zero on first call. +struct b2SimplexCache +{ + float32 metric; ///< length or area + uint16 count; + uint8 indexA[3]; ///< vertices on shape A + uint8 indexB[3]; ///< vertices on shape B +}; + +/// Input for b2Distance. +/// You have to option to use the shape radii +/// in the computation. Even +struct b2DistanceInput +{ + b2DistanceProxy proxyA; + b2DistanceProxy proxyB; + b2Transform transformA; + b2Transform transformB; + bool useRadii; +}; + +/// Output for b2Distance. +struct b2DistanceOutput +{ + b2Vec2 pointA; ///< closest point on shapeA + b2Vec2 pointB; ///< closest point on shapeB + float32 distance; + int32 iterations; ///< number of GJK iterations used +}; + +/// Compute the closest points between two shapes. Supports any combination of: +/// b2CircleShape, b2PolygonShape, b2EdgeShape. The simplex cache is input/output. +/// On the first call set b2SimplexCache.count to zero. +void b2Distance(b2DistanceOutput* output, + b2SimplexCache* cache, + const b2DistanceInput* input); + + +////////////////////////////////////////////////////////////////////////// + +inline int32 b2DistanceProxy::GetVertexCount() const +{ + return m_count; +} + +inline const b2Vec2& b2DistanceProxy::GetVertex(int32 index) const +{ + b2Assert(0 <= index && index < m_count); + return m_vertices[index]; +} + +inline int32 b2DistanceProxy::GetSupport(const b2Vec2& d) const +{ + int32 bestIndex = 0; + float32 bestValue = b2Dot(m_vertices[0], d); + for (int32 i = 1; i < m_count; ++i) + { + float32 value = b2Dot(m_vertices[i], d); + if (value > bestValue) + { + bestIndex = i; + bestValue = value; + } + } + + return bestIndex; +} + +inline const b2Vec2& b2DistanceProxy::GetSupportVertex(const b2Vec2& d) const +{ + int32 bestIndex = 0; + float32 bestValue = b2Dot(m_vertices[0], d); + for (int32 i = 1; i < m_count; ++i) + { + float32 value = b2Dot(m_vertices[i], d); + if (value > bestValue) + { + bestIndex = i; + bestValue = value; + } + } + + return m_vertices[bestIndex]; +} + +#endif diff --git a/Lib/Include/Box2D/Collision/b2DynamicTree.h b/Lib/Include/Box2D/Collision/b2DynamicTree.h new file mode 100644 index 0000000..f0bbef0 --- /dev/null +++ b/Lib/Include/Box2D/Collision/b2DynamicTree.h @@ -0,0 +1,289 @@ +/* +* Copyright (c) 2009 Erin Catto http://www.box2d.org +* +* This software is provided 'as-is', without any express or implied +* warranty. In no event will the authors be held liable for any damages +* arising from the use of this software. +* Permission is granted to anyone to use this software for any purpose, +* including commercial applications, and to alter it and redistribute it +* freely, subject to the following restrictions: +* 1. The origin of this software must not be misrepresented; you must not +* claim that you wrote the original software. If you use this software +* in a product, an acknowledgment in the product documentation would be +* appreciated but is not required. +* 2. Altered source versions must be plainly marked as such, and must not be +* misrepresented as being the original software. +* 3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef B2_DYNAMIC_TREE_H +#define B2_DYNAMIC_TREE_H + +#include +#include + +#define b2_nullNode (-1) + +/// A node in the dynamic tree. The client does not interact with this directly. +struct b2TreeNode +{ + bool IsLeaf() const + { + return child1 == b2_nullNode; + } + + /// Enlarged AABB + b2AABB aabb; + + void* userData; + + union + { + int32 parent; + int32 next; + }; + + int32 child1; + int32 child2; + + // leaf = 0, free node = -1 + int32 height; +}; + +/// A dynamic AABB tree broad-phase, inspired by Nathanael Presson's btDbvt. +/// A dynamic tree arranges data in a binary tree to accelerate +/// queries such as volume queries and ray casts. Leafs are proxies +/// with an AABB. In the tree we expand the proxy AABB by b2_fatAABBFactor +/// so that the proxy AABB is bigger than the client object. This allows the client +/// object to move by small amounts without triggering a tree update. +/// +/// Nodes are pooled and relocatable, so we use node indices rather than pointers. +class BOX2D_API b2DynamicTree +{ +public: + /// Constructing the tree initializes the node pool. + b2DynamicTree(); + + /// Destroy the tree, freeing the node pool. + ~b2DynamicTree(); + + /// Create a proxy. Provide a tight fitting AABB and a userData pointer. + int32 CreateProxy(const b2AABB& aabb, void* userData); + + /// Destroy a proxy. This asserts if the id is invalid. + void DestroyProxy(int32 proxyId); + + /// Move a proxy with a swepted AABB. If the proxy has moved outside of its fattened AABB, + /// then the proxy is removed from the tree and re-inserted. Otherwise + /// the function returns immediately. + /// @return true if the proxy was re-inserted. + bool MoveProxy(int32 proxyId, const b2AABB& aabb1, const b2Vec2& displacement); + + /// Get proxy user data. + /// @return the proxy user data or 0 if the id is invalid. + void* GetUserData(int32 proxyId) const; + + /// Get the fat AABB for a proxy. + const b2AABB& GetFatAABB(int32 proxyId) const; + + /// Query an AABB for overlapping proxies. The callback class + /// is called for each proxy that overlaps the supplied AABB. + template + void Query(T* callback, const b2AABB& aabb) const; + + /// Ray-cast against the proxies in the tree. This relies on the callback + /// to perform a exact ray-cast in the case were the proxy contains a shape. + /// The callback also performs the any collision filtering. This has performance + /// roughly equal to k * log(n), where k is the number of collisions and n is the + /// number of proxies in the tree. + /// @param input the ray-cast input data. The ray extends from p1 to p1 + maxFraction * (p2 - p1). + /// @param callback a callback class that is called for each proxy that is hit by the ray. + template + void RayCast(T* callback, const b2RayCastInput& input) const; + + /// Validate this tree. For testing. + void Validate() const; + + /// Compute the height of the binary tree in O(N) time. Should not be + /// called often. + int32 GetHeight() const; + + /// Get the maximum balance of an node in the tree. The balance is the difference + /// in height of the two children of a node. + int32 GetMaxBalance() const; + + /// Get the ratio of the sum of the node areas to the root area. + float32 GetAreaRatio() const; + + /// Build an optimal tree. Very expensive. For testing. + void RebuildBottomUp(); + + /// Shift the world origin. Useful for large worlds. + /// The shift formula is: position -= newOrigin + /// @param newOrigin the new origin with respect to the old origin + void ShiftOrigin(const b2Vec2& newOrigin); + +private: + + int32 AllocateNode(); + void FreeNode(int32 node); + + void InsertLeaf(int32 node); + void RemoveLeaf(int32 node); + + int32 Balance(int32 index); + + int32 ComputeHeight() const; + int32 ComputeHeight(int32 nodeId) const; + + void ValidateStructure(int32 index) const; + void ValidateMetrics(int32 index) const; + + + b2TreeNode* m_nodes; + int32 m_root; + int32 m_nodeCount; + int32 m_nodeCapacity; + + int32 m_freeList; + + /// This is used to incrementally traverse the tree for re-balancing. + uint32 m_path; + + int32 m_insertionCount; +}; + +inline void* b2DynamicTree::GetUserData(int32 proxyId) const +{ + b2Assert(0 <= proxyId && proxyId < m_nodeCapacity); + return m_nodes[proxyId].userData; +} + +inline const b2AABB& b2DynamicTree::GetFatAABB(int32 proxyId) const +{ + b2Assert(0 <= proxyId && proxyId < m_nodeCapacity); + return m_nodes[proxyId].aabb; +} + +template +inline void b2DynamicTree::Query(T* callback, const b2AABB& aabb) const +{ + b2GrowableStack stack; + stack.Push(m_root); + + while (stack.GetCount() > 0) + { + int32 nodeId = stack.Pop(); + if (nodeId == b2_nullNode) + { + continue; + } + + const b2TreeNode* node = m_nodes + nodeId; + + if (b2TestOverlap(node->aabb, aabb)) + { + if (node->IsLeaf()) + { + bool proceed = callback->QueryCallback(nodeId); + if (proceed == false) + { + return; + } + } + else + { + stack.Push(node->child1); + stack.Push(node->child2); + } + } + } +} + +template +inline void b2DynamicTree::RayCast(T* callback, const b2RayCastInput& input) const +{ + b2Vec2 p1 = input.p1; + b2Vec2 p2 = input.p2; + b2Vec2 r = p2 - p1; + b2Assert(r.LengthSquared() > 0.0f); + r.Normalize(); + + // v is perpendicular to the segment. + b2Vec2 v = b2Cross(1.0f, r); + b2Vec2 abs_v = b2Abs(v); + + // Separating axis for segment (Gino, p80). + // |dot(v, p1 - c)| > dot(|v|, h) + + float32 maxFraction = input.maxFraction; + + // Build a bounding box for the segment. + b2AABB segmentAABB; + { + b2Vec2 t = p1 + maxFraction * (p2 - p1); + segmentAABB.lowerBound = b2Min(p1, t); + segmentAABB.upperBound = b2Max(p1, t); + } + + b2GrowableStack stack; + stack.Push(m_root); + + while (stack.GetCount() > 0) + { + int32 nodeId = stack.Pop(); + if (nodeId == b2_nullNode) + { + continue; + } + + const b2TreeNode* node = m_nodes + nodeId; + + if (b2TestOverlap(node->aabb, segmentAABB) == false) + { + continue; + } + + // Separating axis for segment (Gino, p80). + // |dot(v, p1 - c)| > dot(|v|, h) + b2Vec2 c = node->aabb.GetCenter(); + b2Vec2 h = node->aabb.GetExtents(); + float32 separation = b2Abs(b2Dot(v, p1 - c)) - b2Dot(abs_v, h); + if (separation > 0.0f) + { + continue; + } + + if (node->IsLeaf()) + { + b2RayCastInput subInput; + subInput.p1 = input.p1; + subInput.p2 = input.p2; + subInput.maxFraction = maxFraction; + + float32 value = callback->RayCastCallback(subInput, nodeId); + + if (value == 0.0f) + { + // The client has terminated the ray cast. + return; + } + + if (value > 0.0f) + { + // Update segment bounding box. + maxFraction = value; + b2Vec2 t = p1 + maxFraction * (p2 - p1); + segmentAABB.lowerBound = b2Min(p1, t); + segmentAABB.upperBound = b2Max(p1, t); + } + } + else + { + stack.Push(node->child1); + stack.Push(node->child2); + } + } +} + +#endif diff --git a/Lib/Include/Box2D/Collision/b2TimeOfImpact.h b/Lib/Include/Box2D/Collision/b2TimeOfImpact.h new file mode 100644 index 0000000..b5c2c01 --- /dev/null +++ b/Lib/Include/Box2D/Collision/b2TimeOfImpact.h @@ -0,0 +1,58 @@ +/* +* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org +* +* This software is provided 'as-is', without any express or implied +* warranty. In no event will the authors be held liable for any damages +* arising from the use of this software. +* Permission is granted to anyone to use this software for any purpose, +* including commercial applications, and to alter it and redistribute it +* freely, subject to the following restrictions: +* 1. The origin of this software must not be misrepresented; you must not +* claim that you wrote the original software. If you use this software +* in a product, an acknowledgment in the product documentation would be +* appreciated but is not required. +* 2. Altered source versions must be plainly marked as such, and must not be +* misrepresented as being the original software. +* 3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef B2_TIME_OF_IMPACT_H +#define B2_TIME_OF_IMPACT_H + +#include +#include + +/// Input parameters for b2TimeOfImpact +struct b2TOIInput +{ + b2DistanceProxy proxyA; + b2DistanceProxy proxyB; + b2Sweep sweepA; + b2Sweep sweepB; + float32 tMax; // defines sweep interval [0, tMax] +}; + +// Output parameters for b2TimeOfImpact. +struct b2TOIOutput +{ + enum State + { + e_unknown, + e_failed, + e_overlapped, + e_touching, + e_separated + }; + + State state; + float32 t; +}; + +/// Compute the upper bound on time before two shapes penetrate. Time is represented as +/// a fraction between [0,tMax]. This uses a swept separating axis and may miss some intermediate, +/// non-tunneling collision. If you change the time interval, you should call this function +/// again. +/// Note: use b2Distance to compute the contact point and normal at the time of impact. +BOX2D_API void b2TimeOfImpact(b2TOIOutput* output, const b2TOIInput* input); + +#endif diff --git a/Lib/Include/Box2D/Common/b2BlockAllocator.h b/Lib/Include/Box2D/Common/b2BlockAllocator.h new file mode 100644 index 0000000..da52ade --- /dev/null +++ b/Lib/Include/Box2D/Common/b2BlockAllocator.h @@ -0,0 +1,62 @@ +/* +* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org +* +* This software is provided 'as-is', without any express or implied +* warranty. In no event will the authors be held liable for any damages +* arising from the use of this software. +* Permission is granted to anyone to use this software for any purpose, +* including commercial applications, and to alter it and redistribute it +* freely, subject to the following restrictions: +* 1. The origin of this software must not be misrepresented; you must not +* claim that you wrote the original software. If you use this software +* in a product, an acknowledgment in the product documentation would be +* appreciated but is not required. +* 2. Altered source versions must be plainly marked as such, and must not be +* misrepresented as being the original software. +* 3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef B2_BLOCK_ALLOCATOR_H +#define B2_BLOCK_ALLOCATOR_H + +#include + +const int32 b2_chunkSize = 16 * 1024; +const int32 b2_maxBlockSize = 640; +const int32 b2_blockSizes = 14; +const int32 b2_chunkArrayIncrement = 128; + +struct b2Block; +struct b2Chunk; + +/// This is a small object allocator used for allocating small +/// objects that persist for more than one time step. +/// See: http://www.codeproject.com/useritems/Small_Block_Allocator.asp +class BOX2D_API b2BlockAllocator +{ +public: + b2BlockAllocator(); + ~b2BlockAllocator(); + + /// Allocate memory. This will use b2Alloc if the size is larger than b2_maxBlockSize. + void* Allocate(int32 size); + + /// Free memory. This will use b2Free if the size is larger than b2_maxBlockSize. + void Free(void* p, int32 size); + + void Clear(); + +private: + + b2Chunk* m_chunks; + int32 m_chunkCount; + int32 m_chunkSpace; + + b2Block* m_freeLists[b2_blockSizes]; + + static int32 s_blockSizes[b2_blockSizes]; + static uint8 s_blockSizeLookup[b2_maxBlockSize + 1]; + static bool s_blockSizeLookupInitialized; +}; + +#endif diff --git a/Lib/Include/Box2D/Common/b2Draw.h b/Lib/Include/Box2D/Common/b2Draw.h new file mode 100644 index 0000000..a9724a1 --- /dev/null +++ b/Lib/Include/Box2D/Common/b2Draw.h @@ -0,0 +1,86 @@ +/* +* Copyright (c) 2011 Erin Catto http://box2d.org +* +* This software is provided 'as-is', without any express or implied +* warranty. In no event will the authors be held liable for any damages +* arising from the use of this software. +* Permission is granted to anyone to use this software for any purpose, +* including commercial applications, and to alter it and redistribute it +* freely, subject to the following restrictions: +* 1. The origin of this software must not be misrepresented; you must not +* claim that you wrote the original software. If you use this software +* in a product, an acknowledgment in the product documentation would be +* appreciated but is not required. +* 2. Altered source versions must be plainly marked as such, and must not be +* misrepresented as being the original software. +* 3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef B2_DRAW_H +#define B2_DRAW_H + +#include + +/// Color for debug drawing. Each value has the range [0,1]. +struct b2Color +{ + b2Color() {} + b2Color(float32 r, float32 g, float32 b) : r(r), g(g), b(b) {} + void Set(float32 ri, float32 gi, float32 bi) { r = ri; g = gi; b = bi; } + float32 r, g, b; +}; + +/// Implement and register this class with a b2World to provide debug drawing of physics +/// entities in your game. +class BOX2D_API b2Draw +{ +public: + b2Draw(); + + virtual ~b2Draw() {} + + enum + { + e_shapeBit = 0x0001, ///< draw shapes + e_jointBit = 0x0002, ///< draw joint connections + e_aabbBit = 0x0004, ///< draw axis aligned bounding boxes + e_pairBit = 0x0008, ///< draw broad-phase pairs + e_centerOfMassBit = 0x0010 ///< draw center of mass frame + }; + + /// Set the drawing flags. + void SetFlags(uint32 flags); + + /// Get the drawing flags. + uint32 GetFlags() const; + + /// Append flags to the current flags. + void AppendFlags(uint32 flags); + + /// Clear flags from the current flags. + void ClearFlags(uint32 flags); + + /// Draw a closed polygon provided in CCW order. + virtual void DrawPolygon(const b2Vec2* vertices, int32 vertexCount, const b2Color& color) = 0; + + /// Draw a solid closed polygon provided in CCW order. + virtual void DrawSolidPolygon(const b2Vec2* vertices, int32 vertexCount, const b2Color& color) = 0; + + /// Draw a circle. + virtual void DrawCircle(const b2Vec2& center, float32 radius, const b2Color& color) = 0; + + /// Draw a solid circle. + virtual void DrawSolidCircle(const b2Vec2& center, float32 radius, const b2Vec2& axis, const b2Color& color) = 0; + + /// Draw a line segment. + virtual void DrawSegment(const b2Vec2& p1, const b2Vec2& p2, const b2Color& color) = 0; + + /// Draw a transform. Choose your own length scale. + /// @param xf a transform. + virtual void DrawTransform(const b2Transform& xf) = 0; + +protected: + uint32 m_drawFlags; +}; + +#endif diff --git a/Lib/Include/Box2D/Common/b2GrowableStack.h b/Lib/Include/Box2D/Common/b2GrowableStack.h new file mode 100644 index 0000000..4094644 --- /dev/null +++ b/Lib/Include/Box2D/Common/b2GrowableStack.h @@ -0,0 +1,85 @@ +/* +* Copyright (c) 2010 Erin Catto http://www.box2d.org +* +* This software is provided 'as-is', without any express or implied +* warranty. In no event will the authors be held liable for any damages +* arising from the use of this software. +* Permission is granted to anyone to use this software for any purpose, +* including commercial applications, and to alter it and redistribute it +* freely, subject to the following restrictions: +* 1. The origin of this software must not be misrepresented; you must not +* claim that you wrote the original software. If you use this software +* in a product, an acknowledgment in the product documentation would be +* appreciated but is not required. +* 2. Altered source versions must be plainly marked as such, and must not be +* misrepresented as being the original software. +* 3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef B2_GROWABLE_STACK_H +#define B2_GROWABLE_STACK_H +#include +#include + +/// This is a growable LIFO stack with an initial capacity of N. +/// If the stack size exceeds the initial capacity, the heap is used +/// to increase the size of the stack. +template +class b2GrowableStack +{ +public: + b2GrowableStack() + { + m_stack = m_array; + m_count = 0; + m_capacity = N; + } + + ~b2GrowableStack() + { + if (m_stack != m_array) + { + b2Free(m_stack); + m_stack = NULL; + } + } + + void Push(const T& element) + { + if (m_count == m_capacity) + { + T* old = m_stack; + m_capacity *= 2; + m_stack = (T*)b2Alloc(m_capacity * sizeof(T)); + memcpy(m_stack, old, m_count * sizeof(T)); + if (old != m_array) + { + b2Free(old); + } + } + + m_stack[m_count] = element; + ++m_count; + } + + T Pop() + { + b2Assert(m_count > 0); + --m_count; + return m_stack[m_count]; + } + + int32 GetCount() + { + return m_count; + } + +private: + T* m_stack; + T m_array[N]; + int32 m_count; + int32 m_capacity; +}; + + +#endif diff --git a/Lib/Include/Box2D/Common/b2Math.h b/Lib/Include/Box2D/Common/b2Math.h new file mode 100644 index 0000000..9192817 --- /dev/null +++ b/Lib/Include/Box2D/Common/b2Math.h @@ -0,0 +1,722 @@ +/* +* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org +* +* This software is provided 'as-is', without any express or implied +* warranty. In no event will the authors be held liable for any damages +* arising from the use of this software. +* Permission is granted to anyone to use this software for any purpose, +* including commercial applications, and to alter it and redistribute it +* freely, subject to the following restrictions: +* 1. The origin of this software must not be misrepresented; you must not +* claim that you wrote the original software. If you use this software +* in a product, an acknowledgment in the product documentation would be +* appreciated but is not required. +* 2. Altered source versions must be plainly marked as such, and must not be +* misrepresented as being the original software. +* 3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef B2_MATH_H +#define B2_MATH_H + +#include +#include +#include //memcpy() + +/// This function is used to ensure that a floating point number is not a NaN or infinity. +inline bool b2IsValid(float32 x) +{ + int32 ix; + memcpy(&ix, &x, sizeof(int32)); + return (ix & 0x7f800000) != 0x7f800000; +} + +/// This is a approximate yet fast inverse square-root. +inline float32 b2InvSqrt(float32 x) +{ + union + { + float32 x; + int32 i; + } convert; + + convert.x = x; + float32 xhalf = 0.5f * x; + convert.i = 0x5f3759df - (convert.i >> 1); + x = convert.x; + x = x * (1.5f - xhalf * x * x); + return x; +} + +#define b2Sqrt(x) sqrtf(x) +#define b2Atan2(y, x) atan2f(y, x) + +/// A 2D column vector. +struct BOX2D_API b2Vec2 +{ + /// Default constructor does nothing (for performance). + b2Vec2() {} + + /// Construct using coordinates. + b2Vec2(float32 x, float32 y) : x(x), y(y) {} + + /// Set this vector to all zeros. + void SetZero() { x = 0.0f; y = 0.0f; } + + /// Set this vector to some specified coordinates. + void Set(float32 x_, float32 y_) { x = x_; y = y_; } + + /// Negate this vector. + b2Vec2 operator -() const { b2Vec2 v; v.Set(-x, -y); return v; } + + /// Read from and indexed element. + float32 operator () (int32 i) const + { + return (&x)[i]; + } + + /// Write to an indexed element. + float32& operator () (int32 i) + { + return (&x)[i]; + } + + /// Add a vector to this vector. + void operator += (const b2Vec2& v) + { + x += v.x; y += v.y; + } + + /// Subtract a vector from this vector. + void operator -= (const b2Vec2& v) + { + x -= v.x; y -= v.y; + } + + /// Multiply this vector by a scalar. + void operator *= (float32 a) + { + x *= a; y *= a; + } + + /// Get the length of this vector (the norm). + float32 Length() const + { + return b2Sqrt(x * x + y * y); + } + + /// Get the length squared. For performance, use this instead of + /// b2Vec2::Length (if possible). + float32 LengthSquared() const + { + return x * x + y * y; + } + + /// Convert this vector into a unit vector. Returns the length. + float32 Normalize() + { + float32 length = Length(); + if (length < b2_epsilon) + { + return 0.0f; + } + float32 invLength = 1.0f / length; + x *= invLength; + y *= invLength; + + return length; + } + + /// Does this vector contain finite coordinates? + bool IsValid() const + { + return b2IsValid(x) && b2IsValid(y); + } + + /// Get the skew vector such that dot(skew_vec, other) == cross(vec, other) + b2Vec2 Skew() const + { + return b2Vec2(-y, x); + } + + float32 x, y; +}; + +/// A 2D column vector with 3 elements. +struct BOX2D_API b2Vec3 +{ + /// Default constructor does nothing (for performance). + b2Vec3() {} + + /// Construct using coordinates. + b2Vec3(float32 x, float32 y, float32 z) : x(x), y(y), z(z) {} + + /// Set this vector to all zeros. + void SetZero() { x = 0.0f; y = 0.0f; z = 0.0f; } + + /// Set this vector to some specified coordinates. + void Set(float32 x_, float32 y_, float32 z_) { x = x_; y = y_; z = z_; } + + /// Negate this vector. + b2Vec3 operator -() const { b2Vec3 v; v.Set(-x, -y, -z); return v; } + + /// Add a vector to this vector. + void operator += (const b2Vec3& v) + { + x += v.x; y += v.y; z += v.z; + } + + /// Subtract a vector from this vector. + void operator -= (const b2Vec3& v) + { + x -= v.x; y -= v.y; z -= v.z; + } + + /// Multiply this vector by a scalar. + void operator *= (float32 s) + { + x *= s; y *= s; z *= s; + } + + float32 x, y, z; +}; + +/// A 2-by-2 matrix. Stored in column-major order. +struct BOX2D_API b2Mat22 +{ + /// The default constructor does nothing (for performance). + b2Mat22() {} + + /// Construct this matrix using columns. + b2Mat22(const b2Vec2& c1, const b2Vec2& c2) + { + ex = c1; + ey = c2; + } + + /// Construct this matrix using scalars. + b2Mat22(float32 a11, float32 a12, float32 a21, float32 a22) + { + ex.x = a11; ex.y = a21; + ey.x = a12; ey.y = a22; + } + + /// Initialize this matrix using columns. + void Set(const b2Vec2& c1, const b2Vec2& c2) + { + ex = c1; + ey = c2; + } + + /// Set this to the identity matrix. + void SetIdentity() + { + ex.x = 1.0f; ey.x = 0.0f; + ex.y = 0.0f; ey.y = 1.0f; + } + + /// Set this matrix to all zeros. + void SetZero() + { + ex.x = 0.0f; ey.x = 0.0f; + ex.y = 0.0f; ey.y = 0.0f; + } + + b2Mat22 GetInverse() const + { + float32 a = ex.x, b = ey.x, c = ex.y, d = ey.y; + b2Mat22 B; + float32 det = a * d - b * c; + if (det != 0.0f) + { + det = 1.0f / det; + } + B.ex.x = det * d; B.ey.x = -det * b; + B.ex.y = -det * c; B.ey.y = det * a; + return B; + } + + /// Solve A * x = b, where b is a column vector. This is more efficient + /// than computing the inverse in one-shot cases. + b2Vec2 Solve(const b2Vec2& b) const + { + float32 a11 = ex.x, a12 = ey.x, a21 = ex.y, a22 = ey.y; + float32 det = a11 * a22 - a12 * a21; + if (det != 0.0f) + { + det = 1.0f / det; + } + b2Vec2 x; + x.x = det * (a22 * b.x - a12 * b.y); + x.y = det * (a11 * b.y - a21 * b.x); + return x; + } + + b2Vec2 ex, ey; +}; + +/// A 3-by-3 matrix. Stored in column-major order. +struct BOX2D_API b2Mat33 +{ + /// The default constructor does nothing (for performance). + b2Mat33() {} + + /// Construct this matrix using columns. + b2Mat33(const b2Vec3& c1, const b2Vec3& c2, const b2Vec3& c3) + { + ex = c1; + ey = c2; + ez = c3; + } + + /// Set this matrix to all zeros. + void SetZero() + { + ex.SetZero(); + ey.SetZero(); + ez.SetZero(); + } + + /// Solve A * x = b, where b is a column vector. This is more efficient + /// than computing the inverse in one-shot cases. + b2Vec3 Solve33(const b2Vec3& b) const; + + /// Solve A * x = b, where b is a column vector. This is more efficient + /// than computing the inverse in one-shot cases. Solve only the upper + /// 2-by-2 matrix equation. + b2Vec2 Solve22(const b2Vec2& b) const; + + /// Get the inverse of this matrix as a 2-by-2. + /// Returns the zero matrix if singular. + void GetInverse22(b2Mat33* M) const; + + /// Get the symmetric inverse of this matrix as a 3-by-3. + /// Returns the zero matrix if singular. + void GetSymInverse33(b2Mat33* M) const; + + b2Vec3 ex, ey, ez; +}; + +/// Rotation +struct BOX2D_API b2Rot +{ + b2Rot() {} + + /// Initialize from an angle in radians + explicit b2Rot(float32 angle) + { + /// TODO_ERIN optimize + s = sinf(angle); + c = cosf(angle); + } + + /// Set using an angle in radians. + void Set(float32 angle) + { + /// TODO_ERIN optimize + s = sinf(angle); + c = cosf(angle); + } + + /// Set to the identity rotation + void SetIdentity() + { + s = 0.0f; + c = 1.0f; + } + + /// Get the angle in radians + float32 GetAngle() const + { + return b2Atan2(s, c); + } + + /// Get the x-axis + b2Vec2 GetXAxis() const + { + return b2Vec2(c, s); + } + + /// Get the u-axis + b2Vec2 GetYAxis() const + { + return b2Vec2(-s, c); + } + + /// Sine and cosine + float32 s, c; +}; + +/// A transform contains translation and rotation. It is used to represent +/// the position and orientation of rigid frames. +struct BOX2D_API b2Transform +{ + /// The default constructor does nothing. + b2Transform() {} + + /// Initialize using a position vector and a rotation. + b2Transform(const b2Vec2& position, const b2Rot& rotation) : p(position), q(rotation) {} + + /// Set this to the identity transform. + void SetIdentity() + { + p.SetZero(); + q.SetIdentity(); + } + + /// Set this based on the position and angle. + void Set(const b2Vec2& position, float32 angle) + { + p = position; + q.Set(angle); + } + + b2Vec2 p; + b2Rot q; +}; + +/// This describes the motion of a body/shape for TOI computation. +/// Shapes are defined with respect to the body origin, which may +/// no coincide with the center of mass. However, to support dynamics +/// we must interpolate the center of mass position. +struct BOX2D_API b2Sweep +{ + /// Get the interpolated transform at a specific time. + /// @param beta is a factor in [0,1], where 0 indicates alpha0. + void GetTransform(b2Transform* xfb, float32 beta) const; + + /// Advance the sweep forward, yielding a new initial state. + /// @param alpha the new initial time. + void Advance(float32 alpha); + + /// Normalize the angles. + void Normalize(); + + b2Vec2 localCenter; ///< local center of mass position + b2Vec2 c0, c; ///< center world positions + float32 a0, a; ///< world angles + + /// Fraction of the current time step in the range [0,1] + /// c0 and a0 are the positions at alpha0. + float32 alpha0; +}; + +/// Useful constant +BOX2D_API extern const b2Vec2 b2Vec2_zero; + +/// Perform the dot product on two vectors. +inline float32 b2Dot(const b2Vec2& a, const b2Vec2& b) +{ + return a.x * b.x + a.y * b.y; +} + +/// Perform the cross product on two vectors. In 2D this produces a scalar. +inline float32 b2Cross(const b2Vec2& a, const b2Vec2& b) +{ + return a.x * b.y - a.y * b.x; +} + +/// Perform the cross product on a vector and a scalar. In 2D this produces +/// a vector. +inline b2Vec2 b2Cross(const b2Vec2& a, float32 s) +{ + return b2Vec2(s * a.y, -s * a.x); +} + +/// Perform the cross product on a scalar and a vector. In 2D this produces +/// a vector. +inline b2Vec2 b2Cross(float32 s, const b2Vec2& a) +{ + return b2Vec2(-s * a.y, s * a.x); +} + +/// Multiply a matrix times a vector. If a rotation matrix is provided, +/// then this transforms the vector from one frame to another. +inline b2Vec2 b2Mul(const b2Mat22& A, const b2Vec2& v) +{ + return b2Vec2(A.ex.x * v.x + A.ey.x * v.y, A.ex.y * v.x + A.ey.y * v.y); +} + +/// Multiply a matrix transpose times a vector. If a rotation matrix is provided, +/// then this transforms the vector from one frame to another (inverse transform). +inline b2Vec2 b2MulT(const b2Mat22& A, const b2Vec2& v) +{ + return b2Vec2(b2Dot(v, A.ex), b2Dot(v, A.ey)); +} + +/// Add two vectors component-wise. +inline b2Vec2 operator + (const b2Vec2& a, const b2Vec2& b) +{ + return b2Vec2(a.x + b.x, a.y + b.y); +} + +/// Subtract two vectors component-wise. +inline b2Vec2 operator - (const b2Vec2& a, const b2Vec2& b) +{ + return b2Vec2(a.x - b.x, a.y - b.y); +} + +inline b2Vec2 operator * (float32 s, const b2Vec2& a) +{ + return b2Vec2(s * a.x, s * a.y); +} + +inline bool operator == (const b2Vec2& a, const b2Vec2& b) +{ + return a.x == b.x && a.y == b.y; +} + +inline float32 b2Distance(const b2Vec2& a, const b2Vec2& b) +{ + b2Vec2 c = a - b; + return c.Length(); +} + +inline float32 b2DistanceSquared(const b2Vec2& a, const b2Vec2& b) +{ + b2Vec2 c = a - b; + return b2Dot(c, c); +} + +inline b2Vec3 operator * (float32 s, const b2Vec3& a) +{ + return b2Vec3(s * a.x, s * a.y, s * a.z); +} + +/// Add two vectors component-wise. +inline b2Vec3 operator + (const b2Vec3& a, const b2Vec3& b) +{ + return b2Vec3(a.x + b.x, a.y + b.y, a.z + b.z); +} + +/// Subtract two vectors component-wise. +inline b2Vec3 operator - (const b2Vec3& a, const b2Vec3& b) +{ + return b2Vec3(a.x - b.x, a.y - b.y, a.z - b.z); +} + +/// Perform the dot product on two vectors. +inline float32 b2Dot(const b2Vec3& a, const b2Vec3& b) +{ + return a.x * b.x + a.y * b.y + a.z * b.z; +} + +/// Perform the cross product on two vectors. +inline b2Vec3 b2Cross(const b2Vec3& a, const b2Vec3& b) +{ + return b2Vec3(a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x); +} + +inline b2Mat22 operator + (const b2Mat22& A, const b2Mat22& B) +{ + return b2Mat22(A.ex + B.ex, A.ey + B.ey); +} + +// A * B +inline b2Mat22 b2Mul(const b2Mat22& A, const b2Mat22& B) +{ + return b2Mat22(b2Mul(A, B.ex), b2Mul(A, B.ey)); +} + +// A^T * B +inline b2Mat22 b2MulT(const b2Mat22& A, const b2Mat22& B) +{ + b2Vec2 c1(b2Dot(A.ex, B.ex), b2Dot(A.ey, B.ex)); + b2Vec2 c2(b2Dot(A.ex, B.ey), b2Dot(A.ey, B.ey)); + return b2Mat22(c1, c2); +} + +/// Multiply a matrix times a vector. +inline b2Vec3 b2Mul(const b2Mat33& A, const b2Vec3& v) +{ + return v.x * A.ex + v.y * A.ey + v.z * A.ez; +} + +/// Multiply a matrix times a vector. +inline b2Vec2 b2Mul22(const b2Mat33& A, const b2Vec2& v) +{ + return b2Vec2(A.ex.x * v.x + A.ey.x * v.y, A.ex.y * v.x + A.ey.y * v.y); +} + +/// Multiply two rotations: q * r +inline b2Rot b2Mul(const b2Rot& q, const b2Rot& r) +{ + // [qc -qs] * [rc -rs] = [qc*rc-qs*rs -qc*rs-qs*rc] + // [qs qc] [rs rc] [qs*rc+qc*rs -qs*rs+qc*rc] + // s = qs * rc + qc * rs + // c = qc * rc - qs * rs + b2Rot qr; + qr.s = q.s * r.c + q.c * r.s; + qr.c = q.c * r.c - q.s * r.s; + return qr; +} + +/// Transpose multiply two rotations: qT * r +inline b2Rot b2MulT(const b2Rot& q, const b2Rot& r) +{ + // [ qc qs] * [rc -rs] = [qc*rc+qs*rs -qc*rs+qs*rc] + // [-qs qc] [rs rc] [-qs*rc+qc*rs qs*rs+qc*rc] + // s = qc * rs - qs * rc + // c = qc * rc + qs * rs + b2Rot qr; + qr.s = q.c * r.s - q.s * r.c; + qr.c = q.c * r.c + q.s * r.s; + return qr; +} + +/// Rotate a vector +inline b2Vec2 b2Mul(const b2Rot& q, const b2Vec2& v) +{ + return b2Vec2(q.c * v.x - q.s * v.y, q.s * v.x + q.c * v.y); +} + +/// Inverse rotate a vector +inline b2Vec2 b2MulT(const b2Rot& q, const b2Vec2& v) +{ + return b2Vec2(q.c * v.x + q.s * v.y, -q.s * v.x + q.c * v.y); +} + +inline b2Vec2 b2Mul(const b2Transform& T, const b2Vec2& v) +{ + float32 x = (T.q.c * v.x - T.q.s * v.y) + T.p.x; + float32 y = (T.q.s * v.x + T.q.c * v.y) + T.p.y; + + return b2Vec2(x, y); +} + +inline b2Vec2 b2MulT(const b2Transform& T, const b2Vec2& v) +{ + float32 px = v.x - T.p.x; + float32 py = v.y - T.p.y; + float32 x = (T.q.c * px + T.q.s * py); + float32 y = (-T.q.s * px + T.q.c * py); + + return b2Vec2(x, y); +} + +// v2 = A.q.Rot(B.q.Rot(v1) + B.p) + A.p +// = (A.q * B.q).Rot(v1) + A.q.Rot(B.p) + A.p +inline b2Transform b2Mul(const b2Transform& A, const b2Transform& B) +{ + b2Transform C; + C.q = b2Mul(A.q, B.q); + C.p = b2Mul(A.q, B.p) + A.p; + return C; +} + +// v2 = A.q' * (B.q * v1 + B.p - A.p) +// = A.q' * B.q * v1 + A.q' * (B.p - A.p) +inline b2Transform b2MulT(const b2Transform& A, const b2Transform& B) +{ + b2Transform C; + C.q = b2MulT(A.q, B.q); + C.p = b2MulT(A.q, B.p - A.p); + return C; +} + +template +inline T b2Abs(T a) +{ + return a > T(0) ? a : -a; +} + +inline b2Vec2 b2Abs(const b2Vec2& a) +{ + return b2Vec2(b2Abs(a.x), b2Abs(a.y)); +} + +inline b2Mat22 b2Abs(const b2Mat22& A) +{ + return b2Mat22(b2Abs(A.ex), b2Abs(A.ey)); +} + +template +inline T b2Min(T a, T b) +{ + return a < b ? a : b; +} + +inline b2Vec2 b2Min(const b2Vec2& a, const b2Vec2& b) +{ + return b2Vec2(b2Min(a.x, b.x), b2Min(a.y, b.y)); +} + +template +inline T b2Max(T a, T b) +{ + return a > b ? a : b; +} + +inline b2Vec2 b2Max(const b2Vec2& a, const b2Vec2& b) +{ + return b2Vec2(b2Max(a.x, b.x), b2Max(a.y, b.y)); +} + +template +inline T b2Clamp(T a, T low, T high) +{ + return b2Max(low, b2Min(a, high)); +} + +inline b2Vec2 b2Clamp(const b2Vec2& a, const b2Vec2& low, const b2Vec2& high) +{ + return b2Max(low, b2Min(a, high)); +} + +template inline void b2Swap(T& a, T& b) +{ + T tmp = a; + a = b; + b = tmp; +} + +/// "Next Largest Power of 2 +/// Given a binary integer value x, the next largest power of 2 can be computed by a SWAR algorithm +/// that recursively "folds" the upper bits into the lower bits. This process yields a bit vector with +/// the same most significant 1 as x, but all 1's below it. Adding 1 to that value yields the next +/// largest power of 2. For a 32-bit value:" +inline uint32 b2NextPowerOfTwo(uint32 x) +{ + x |= (x >> 1); + x |= (x >> 2); + x |= (x >> 4); + x |= (x >> 8); + x |= (x >> 16); + return x + 1; +} + +inline bool b2IsPowerOfTwo(uint32 x) +{ + bool result = x > 0 && (x & (x - 1)) == 0; + return result; +} + +inline void b2Sweep::GetTransform(b2Transform* xf, float32 beta) const +{ + xf->p = (1.0f - beta) * c0 + beta * c; + float32 angle = (1.0f - beta) * a0 + beta * a; + xf->q.Set(angle); + + // Shift to origin + xf->p -= b2Mul(xf->q, localCenter); +} + +inline void b2Sweep::Advance(float32 alpha) +{ + b2Assert(alpha0 < 1.0f); + float32 beta = (alpha - alpha0) / (1.0f - alpha0); + c0 += beta * (c - c0); + a0 += beta * (a - a0); + alpha0 = alpha; +} + +/// Normalize an angle in radians to be between -pi and pi +inline void b2Sweep::Normalize() +{ + float32 twoPi = 2.0f * b2_pi; + float32 d = twoPi * floorf(a0 / twoPi); + a0 -= d; + a -= d; +} + +#endif diff --git a/Lib/Include/Box2D/Common/b2Settings.h b/Lib/Include/Box2D/Common/b2Settings.h new file mode 100644 index 0000000..149605f --- /dev/null +++ b/Lib/Include/Box2D/Common/b2Settings.h @@ -0,0 +1,161 @@ +/* +* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org +* +* This software is provided 'as-is', without any express or implied +* warranty. In no event will the authors be held liable for any damages +* arising from the use of this software. +* Permission is granted to anyone to use this software for any purpose, +* including commercial applications, and to alter it and redistribute it +* freely, subject to the following restrictions: +* 1. The origin of this software must not be misrepresented; you must not +* claim that you wrote the original software. If you use this software +* in a product, an acknowledgment in the product documentation would be +* appreciated but is not required. +* 2. Altered source versions must be plainly marked as such, and must not be +* misrepresented as being the original software. +* 3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef B2_SETTINGS_H +#define B2_SETTINGS_H + +#include +#include +#include + +#define B2_NOT_USED(x) ((void)(x)) +#define b2Assert(A) assert(A) + +typedef signed char int8; +typedef signed short int16; +typedef signed int int32; +typedef unsigned char uint8; +typedef unsigned short uint16; +typedef unsigned int uint32; +typedef float float32; +typedef double float64; + +#define b2_maxFloat FLT_MAX +#define b2_epsilon FLT_EPSILON +#define b2_pi 3.14159265359f + +/// @file +/// Global tuning constants based on meters-kilograms-seconds (MKS) units. +/// + +// Collision + +/// The maximum number of contact points between two convex shapes. Do +/// not change this value. +#define b2_maxManifoldPoints 2 + +/// The maximum number of vertices on a convex polygon. You cannot increase +/// this too much because b2BlockAllocator has a maximum object size. +#define b2_maxPolygonVertices 8 + +/// This is used to fatten AABBs in the dynamic tree. This allows proxies +/// to move by a small amount without triggering a tree adjustment. +/// This is in meters. +#define b2_aabbExtension 0.1f + +/// This is used to fatten AABBs in the dynamic tree. This is used to predict +/// the future position based on the current displacement. +/// This is a dimensionless multiplier. +#define b2_aabbMultiplier 2.0f + +/// A small length used as a collision and constraint tolerance. Usually it is +/// chosen to be numerically significant, but visually insignificant. +#define b2_linearSlop 0.005f + +/// A small angle used as a collision and constraint tolerance. Usually it is +/// chosen to be numerically significant, but visually insignificant. +#define b2_angularSlop (2.0f / 180.0f * b2_pi) + +/// The radius of the polygon/edge shape skin. This should not be modified. Making +/// this smaller means polygons will have an insufficient buffer for continuous collision. +/// Making it larger may create artifacts for vertex collision. +#define b2_polygonRadius (2.0f * b2_linearSlop) + +/// Maximum number of sub-steps per contact in continuous physics simulation. +#define b2_maxSubSteps 8 + + +// Dynamics + +/// Maximum number of contacts to be handled to solve a TOI impact. +#define b2_maxTOIContacts 32 + +/// A velocity threshold for elastic collisions. Any collision with a relative linear +/// velocity below this threshold will be treated as inelastic. +#define b2_velocityThreshold 1.0f + +/// The maximum linear position correction used when solving constraints. This helps to +/// prevent overshoot. +#define b2_maxLinearCorrection 0.2f + +/// The maximum angular position correction used when solving constraints. This helps to +/// prevent overshoot. +#define b2_maxAngularCorrection (8.0f / 180.0f * b2_pi) + +/// The maximum linear velocity of a body. This limit is very large and is used +/// to prevent numerical problems. You shouldn't need to adjust this. +#define b2_maxTranslation 2.0f +#define b2_maxTranslationSquared (b2_maxTranslation * b2_maxTranslation) + +/// The maximum angular velocity of a body. This limit is very large and is used +/// to prevent numerical problems. You shouldn't need to adjust this. +#define b2_maxRotation (0.5f * b2_pi) +#define b2_maxRotationSquared (b2_maxRotation * b2_maxRotation) + +/// This scale factor controls how fast overlap is resolved. Ideally this would be 1 so +/// that overlap is removed in one time step. However using values close to 1 often lead +/// to overshoot. +#define b2_baumgarte 0.2f +#define b2_toiBaugarte 0.75f + + +// Sleep + +/// The time that a body must be still before it will go to sleep. +#define b2_timeToSleep 0.5f + +/// A body cannot sleep if its linear velocity is above this tolerance. +#define b2_linearSleepTolerance 0.01f + +/// A body cannot sleep if its angular velocity is above this tolerance. +#define b2_angularSleepTolerance (2.0f / 180.0f * b2_pi) + +// Memory Allocation + +/// Implement this function to use your own memory allocator. +void* b2Alloc(int32 size); + +/// If you implement b2Alloc, you should also implement this function. +void b2Free(void* mem); + +/// Logging function. +void b2Log(const char* string, ...); + +/// Version numbering scheme. +/// See http://en.wikipedia.org/wiki/Software_versioning +struct b2Version +{ + int32 major; ///< significant changes + int32 minor; ///< incremental changes + int32 revision; ///< bug fixes +}; + +#ifdef _WIN32 +#ifdef BOX2D_BUILD_DLL +#define BOX2D_API __declspec(dllexport) +#else +#define BOX2D_API __declspec(dllimport) +#endif +#else +#define BOX2D_API /* Nothing */ +#endif + +/// Current version. +extern BOX2D_API b2Version b2_version; + +#endif diff --git a/Lib/Include/Box2D/Common/b2StackAllocator.h b/Lib/Include/Box2D/Common/b2StackAllocator.h new file mode 100644 index 0000000..0670963 --- /dev/null +++ b/Lib/Include/Box2D/Common/b2StackAllocator.h @@ -0,0 +1,60 @@ +/* +* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org +* +* This software is provided 'as-is', without any express or implied +* warranty. In no event will the authors be held liable for any damages +* arising from the use of this software. +* Permission is granted to anyone to use this software for any purpose, +* including commercial applications, and to alter it and redistribute it +* freely, subject to the following restrictions: +* 1. The origin of this software must not be misrepresented; you must not +* claim that you wrote the original software. If you use this software +* in a product, an acknowledgment in the product documentation would be +* appreciated but is not required. +* 2. Altered source versions must be plainly marked as such, and must not be +* misrepresented as being the original software. +* 3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef B2_STACK_ALLOCATOR_H +#define B2_STACK_ALLOCATOR_H + +#include + +const int32 b2_stackSize = 100 * 1024; // 100k +const int32 b2_maxStackEntries = 32; + +struct b2StackEntry +{ + char* data; + int32 size; + bool usedMalloc; +}; + +// This is a stack allocator used for fast per step allocations. +// You must nest allocate/free pairs. The code will assert +// if you try to interleave multiple allocate/free pairs. +class BOX2D_API b2StackAllocator +{ +public: + b2StackAllocator(); + ~b2StackAllocator(); + + void* Allocate(int32 size); + void Free(void* p); + + int32 GetMaxAllocation() const; + +private: + + char m_data[b2_stackSize]; + int32 m_index; + + int32 m_allocation; + int32 m_maxAllocation; + + b2StackEntry m_entries[b2_maxStackEntries]; + int32 m_entryCount; +}; + +#endif diff --git a/Lib/Include/Box2D/Common/b2Timer.h b/Lib/Include/Box2D/Common/b2Timer.h new file mode 100644 index 0000000..f1eac94 --- /dev/null +++ b/Lib/Include/Box2D/Common/b2Timer.h @@ -0,0 +1,50 @@ +/* +* Copyright (c) 2011 Erin Catto http://box2d.org +* +* This software is provided 'as-is', without any express or implied +* warranty. In no event will the authors be held liable for any damages +* arising from the use of this software. +* Permission is granted to anyone to use this software for any purpose, +* including commercial applications, and to alter it and redistribute it +* freely, subject to the following restrictions: +* 1. The origin of this software must not be misrepresented; you must not +* claim that you wrote the original software. If you use this software +* in a product, an acknowledgment in the product documentation would be +* appreciated but is not required. +* 2. Altered source versions must be plainly marked as such, and must not be +* misrepresented as being the original software. +* 3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef B2_TIMER_H +#define B2_TIMER_H + +#include + +/// Timer for profiling. This has platform specific code and may +/// not work on every platform. +class BOX2D_API b2Timer +{ +public: + + /// Constructor + b2Timer(); + + /// Reset the timer. + void Reset(); + + /// Get the time since construction or the last reset. + float32 GetMilliseconds() const; + +private: + +#if defined(_WIN32) + float64 m_start; + static float64 s_invFrequency; +#elif defined(__linux__) || defined (__APPLE__) + unsigned long m_start_sec; + unsigned long m_start_usec; +#endif +}; + +#endif diff --git a/Lib/Include/Box2D/Dynamics/Contacts/b2ChainAndCircleContact.h b/Lib/Include/Box2D/Dynamics/Contacts/b2ChainAndCircleContact.h new file mode 100644 index 0000000..714d3ca --- /dev/null +++ b/Lib/Include/Box2D/Dynamics/Contacts/b2ChainAndCircleContact.h @@ -0,0 +1,39 @@ +/* +* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org +* +* This software is provided 'as-is', without any express or implied +* warranty. In no event will the authors be held liable for any damages +* arising from the use of this software. +* Permission is granted to anyone to use this software for any purpose, +* including commercial applications, and to alter it and redistribute it +* freely, subject to the following restrictions: +* 1. The origin of this software must not be misrepresented; you must not +* claim that you wrote the original software. If you use this software +* in a product, an acknowledgment in the product documentation would be +* appreciated but is not required. +* 2. Altered source versions must be plainly marked as such, and must not be +* misrepresented as being the original software. +* 3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef B2_CHAIN_AND_CIRCLE_CONTACT_H +#define B2_CHAIN_AND_CIRCLE_CONTACT_H + +#include + +class b2BlockAllocator; + +class BOX2D_API b2ChainAndCircleContact : public b2Contact +{ +public: + static b2Contact* Create( b2Fixture* fixtureA, int32 indexA, + b2Fixture* fixtureB, int32 indexB, b2BlockAllocator* allocator); + static void Destroy(b2Contact* contact, b2BlockAllocator* allocator); + + b2ChainAndCircleContact(b2Fixture* fixtureA, int32 indexA, b2Fixture* fixtureB, int32 indexB); + ~b2ChainAndCircleContact() {} + + void Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB); +}; + +#endif diff --git a/Lib/Include/Box2D/Dynamics/Contacts/b2ChainAndPolygonContact.h b/Lib/Include/Box2D/Dynamics/Contacts/b2ChainAndPolygonContact.h new file mode 100644 index 0000000..e3accc7 --- /dev/null +++ b/Lib/Include/Box2D/Dynamics/Contacts/b2ChainAndPolygonContact.h @@ -0,0 +1,39 @@ +/* +* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org +* +* This software is provided 'as-is', without any express or implied +* warranty. In no event will the authors be held liable for any damages +* arising from the use of this software. +* Permission is granted to anyone to use this software for any purpose, +* including commercial applications, and to alter it and redistribute it +* freely, subject to the following restrictions: +* 1. The origin of this software must not be misrepresented; you must not +* claim that you wrote the original software. If you use this software +* in a product, an acknowledgment in the product documentation would be +* appreciated but is not required. +* 2. Altered source versions must be plainly marked as such, and must not be +* misrepresented as being the original software. +* 3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef B2_CHAIN_AND_POLYGON_CONTACT_H +#define B2_CHAIN_AND_POLYGON_CONTACT_H + +#include + +class b2BlockAllocator; + +class BOX2D_API b2ChainAndPolygonContact : public b2Contact +{ +public: + static b2Contact* Create( b2Fixture* fixtureA, int32 indexA, + b2Fixture* fixtureB, int32 indexB, b2BlockAllocator* allocator); + static void Destroy(b2Contact* contact, b2BlockAllocator* allocator); + + b2ChainAndPolygonContact(b2Fixture* fixtureA, int32 indexA, b2Fixture* fixtureB, int32 indexB); + ~b2ChainAndPolygonContact() {} + + void Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB); +}; + +#endif diff --git a/Lib/Include/Box2D/Dynamics/Contacts/b2CircleContact.h b/Lib/Include/Box2D/Dynamics/Contacts/b2CircleContact.h new file mode 100644 index 0000000..976c1be --- /dev/null +++ b/Lib/Include/Box2D/Dynamics/Contacts/b2CircleContact.h @@ -0,0 +1,39 @@ +/* +* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org +* +* This software is provided 'as-is', without any express or implied +* warranty. In no event will the authors be held liable for any damages +* arising from the use of this software. +* Permission is granted to anyone to use this software for any purpose, +* including commercial applications, and to alter it and redistribute it +* freely, subject to the following restrictions: +* 1. The origin of this software must not be misrepresented; you must not +* claim that you wrote the original software. If you use this software +* in a product, an acknowledgment in the product documentation would be +* appreciated but is not required. +* 2. Altered source versions must be plainly marked as such, and must not be +* misrepresented as being the original software. +* 3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef B2_CIRCLE_CONTACT_H +#define B2_CIRCLE_CONTACT_H + +#include + +class b2BlockAllocator; + +class BOX2D_API b2CircleContact : public b2Contact +{ +public: + static b2Contact* Create( b2Fixture* fixtureA, int32 indexA, + b2Fixture* fixtureB, int32 indexB, b2BlockAllocator* allocator); + static void Destroy(b2Contact* contact, b2BlockAllocator* allocator); + + b2CircleContact(b2Fixture* fixtureA, b2Fixture* fixtureB); + ~b2CircleContact() {} + + void Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB); +}; + +#endif diff --git a/Lib/Include/Box2D/Dynamics/Contacts/b2Contact.h b/Lib/Include/Box2D/Dynamics/Contacts/b2Contact.h new file mode 100644 index 0000000..47aaf0e --- /dev/null +++ b/Lib/Include/Box2D/Dynamics/Contacts/b2Contact.h @@ -0,0 +1,349 @@ +/* +* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org +* +* This software is provided 'as-is', without any express or implied +* warranty. In no event will the authors be held liable for any damages +* arising from the use of this software. +* Permission is granted to anyone to use this software for any purpose, +* including commercial applications, and to alter it and redistribute it +* freely, subject to the following restrictions: +* 1. The origin of this software must not be misrepresented; you must not +* claim that you wrote the original software. If you use this software +* in a product, an acknowledgment in the product documentation would be +* appreciated but is not required. +* 2. Altered source versions must be plainly marked as such, and must not be +* misrepresented as being the original software. +* 3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef B2_CONTACT_H +#define B2_CONTACT_H + +#include +#include +#include +#include + +class b2Body; +class b2Contact; +class b2Fixture; +class b2World; +class b2BlockAllocator; +class b2StackAllocator; +class b2ContactListener; + +/// Friction mixing law. The idea is to allow either fixture to drive the restitution to zero. +/// For example, anything slides on ice. +inline float32 b2MixFriction(float32 friction1, float32 friction2) +{ + return b2Sqrt(friction1 * friction2); +} + +/// Restitution mixing law. The idea is allow for anything to bounce off an inelastic surface. +/// For example, a superball bounces on anything. +inline float32 b2MixRestitution(float32 restitution1, float32 restitution2) +{ + return restitution1 > restitution2 ? restitution1 : restitution2; +} + +typedef b2Contact* b2ContactCreateFcn( b2Fixture* fixtureA, int32 indexA, + b2Fixture* fixtureB, int32 indexB, + b2BlockAllocator* allocator); +typedef void b2ContactDestroyFcn(b2Contact* contact, b2BlockAllocator* allocator); + +struct b2ContactRegister +{ + b2ContactCreateFcn* createFcn; + b2ContactDestroyFcn* destroyFcn; + bool primary; +}; + +/// A contact edge is used to connect bodies and contacts together +/// in a contact graph where each body is a node and each contact +/// is an edge. A contact edge belongs to a doubly linked list +/// maintained in each attached body. Each contact has two contact +/// nodes, one for each attached body. +struct b2ContactEdge +{ + b2Body* other; ///< provides quick access to the other body attached. + b2Contact* contact; ///< the contact + b2ContactEdge* prev; ///< the previous contact edge in the body's contact list + b2ContactEdge* next; ///< the next contact edge in the body's contact list +}; + +/// The class manages contact between two shapes. A contact exists for each overlapping +/// AABB in the broad-phase (except if filtered). Therefore a contact object may exist +/// that has no contact points. +class BOX2D_API b2Contact +{ +public: + + /// Get the contact manifold. Do not modify the manifold unless you understand the + /// internals of Box2D. + b2Manifold* GetManifold(); + const b2Manifold* GetManifold() const; + + /// Get the world manifold. + void GetWorldManifold(b2WorldManifold* worldManifold) const; + + /// Is this contact touching? + bool IsTouching() const; + + /// Enable/disable this contact. This can be used inside the pre-solve + /// contact listener. The contact is only disabled for the current + /// time step (or sub-step in continuous collisions). + void SetEnabled(bool flag); + + /// Has this contact been disabled? + bool IsEnabled() const; + + /// Get the next contact in the world's contact list. + b2Contact* GetNext(); + const b2Contact* GetNext() const; + + /// Get fixture A in this contact. + b2Fixture* GetFixtureA(); + const b2Fixture* GetFixtureA() const; + + /// Get the child primitive index for fixture A. + int32 GetChildIndexA() const; + + /// Get fixture B in this contact. + b2Fixture* GetFixtureB(); + const b2Fixture* GetFixtureB() const; + + /// Get the child primitive index for fixture B. + int32 GetChildIndexB() const; + + /// Override the default friction mixture. You can call this in b2ContactListener::PreSolve. + /// This value persists until set or reset. + void SetFriction(float32 friction); + + /// Get the friction. + float32 GetFriction() const; + + /// Reset the friction mixture to the default value. + void ResetFriction(); + + /// Override the default restitution mixture. You can call this in b2ContactListener::PreSolve. + /// The value persists until you set or reset. + void SetRestitution(float32 restitution); + + /// Get the restitution. + float32 GetRestitution() const; + + /// Reset the restitution to the default value. + void ResetRestitution(); + + /// Set the desired tangent speed for a conveyor belt behavior. In meters per second. + void SetTangentSpeed(float32 speed); + + /// Get the desired tangent speed. In meters per second. + float32 GetTangentSpeed() const; + + /// Evaluate this contact with your own manifold and transforms. + virtual void Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB) = 0; + +protected: + friend class b2ContactManager; + friend class b2World; + friend class b2ContactSolver; + friend class b2Body; + friend class b2Fixture; + + // Flags stored in m_flags + enum + { + // Used when crawling contact graph when forming islands. + e_islandFlag = 0x0001, + + // Set when the shapes are touching. + e_touchingFlag = 0x0002, + + // This contact can be disabled (by user) + e_enabledFlag = 0x0004, + + // This contact needs filtering because a fixture filter was changed. + e_filterFlag = 0x0008, + + // This bullet contact had a TOI event + e_bulletHitFlag = 0x0010, + + // This contact has a valid TOI in m_toi + e_toiFlag = 0x0020 + }; + + /// Flag this contact for filtering. Filtering will occur the next time step. + void FlagForFiltering(); + + static void AddType(b2ContactCreateFcn* createFcn, b2ContactDestroyFcn* destroyFcn, + b2Shape::Type typeA, b2Shape::Type typeB); + static void InitializeRegisters(); + static b2Contact* Create(b2Fixture* fixtureA, int32 indexA, b2Fixture* fixtureB, int32 indexB, b2BlockAllocator* allocator); + static void Destroy(b2Contact* contact, b2Shape::Type typeA, b2Shape::Type typeB, b2BlockAllocator* allocator); + static void Destroy(b2Contact* contact, b2BlockAllocator* allocator); + + b2Contact() : m_fixtureA(NULL), m_fixtureB(NULL) {} + b2Contact(b2Fixture* fixtureA, int32 indexA, b2Fixture* fixtureB, int32 indexB); + virtual ~b2Contact() {} + + void Update(b2ContactListener* listener); + + static b2ContactRegister s_registers[b2Shape::e_typeCount][b2Shape::e_typeCount]; + static bool s_initialized; + + uint32 m_flags; + + // World pool and list pointers. + b2Contact* m_prev; + b2Contact* m_next; + + // Nodes for connecting bodies. + b2ContactEdge m_nodeA; + b2ContactEdge m_nodeB; + + b2Fixture* m_fixtureA; + b2Fixture* m_fixtureB; + + int32 m_indexA; + int32 m_indexB; + + b2Manifold m_manifold; + + int32 m_toiCount; + float32 m_toi; + + float32 m_friction; + float32 m_restitution; + + float32 m_tangentSpeed; +}; + +inline b2Manifold* b2Contact::GetManifold() +{ + return &m_manifold; +} + +inline const b2Manifold* b2Contact::GetManifold() const +{ + return &m_manifold; +} + +inline void b2Contact::GetWorldManifold(b2WorldManifold* worldManifold) const +{ + const b2Body* bodyA = m_fixtureA->GetBody(); + const b2Body* bodyB = m_fixtureB->GetBody(); + const b2Shape* shapeA = m_fixtureA->GetShape(); + const b2Shape* shapeB = m_fixtureB->GetShape(); + + worldManifold->Initialize(&m_manifold, bodyA->GetTransform(), shapeA->m_radius, bodyB->GetTransform(), shapeB->m_radius); +} + +inline void b2Contact::SetEnabled(bool flag) +{ + if (flag) + { + m_flags |= e_enabledFlag; + } + else + { + m_flags &= ~e_enabledFlag; + } +} + +inline bool b2Contact::IsEnabled() const +{ + return (m_flags & e_enabledFlag) == e_enabledFlag; +} + +inline bool b2Contact::IsTouching() const +{ + return (m_flags & e_touchingFlag) == e_touchingFlag; +} + +inline b2Contact* b2Contact::GetNext() +{ + return m_next; +} + +inline const b2Contact* b2Contact::GetNext() const +{ + return m_next; +} + +inline b2Fixture* b2Contact::GetFixtureA() +{ + return m_fixtureA; +} + +inline const b2Fixture* b2Contact::GetFixtureA() const +{ + return m_fixtureA; +} + +inline b2Fixture* b2Contact::GetFixtureB() +{ + return m_fixtureB; +} + +inline int32 b2Contact::GetChildIndexA() const +{ + return m_indexA; +} + +inline const b2Fixture* b2Contact::GetFixtureB() const +{ + return m_fixtureB; +} + +inline int32 b2Contact::GetChildIndexB() const +{ + return m_indexB; +} + +inline void b2Contact::FlagForFiltering() +{ + m_flags |= e_filterFlag; +} + +inline void b2Contact::SetFriction(float32 friction) +{ + m_friction = friction; +} + +inline float32 b2Contact::GetFriction() const +{ + return m_friction; +} + +inline void b2Contact::ResetFriction() +{ + m_friction = b2MixFriction(m_fixtureA->m_friction, m_fixtureB->m_friction); +} + +inline void b2Contact::SetRestitution(float32 restitution) +{ + m_restitution = restitution; +} + +inline float32 b2Contact::GetRestitution() const +{ + return m_restitution; +} + +inline void b2Contact::ResetRestitution() +{ + m_restitution = b2MixRestitution(m_fixtureA->m_restitution, m_fixtureB->m_restitution); +} + +inline void b2Contact::SetTangentSpeed(float32 speed) +{ + m_tangentSpeed = speed; +} + +inline float32 b2Contact::GetTangentSpeed() const +{ + return m_tangentSpeed; +} + +#endif diff --git a/Lib/Include/Box2D/Dynamics/Contacts/b2ContactSolver.h b/Lib/Include/Box2D/Dynamics/Contacts/b2ContactSolver.h new file mode 100644 index 0000000..c61e460 --- /dev/null +++ b/Lib/Include/Box2D/Dynamics/Contacts/b2ContactSolver.h @@ -0,0 +1,95 @@ +/* +* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org +* +* This software is provided 'as-is', without any express or implied +* warranty. In no event will the authors be held liable for any damages +* arising from the use of this software. +* Permission is granted to anyone to use this software for any purpose, +* including commercial applications, and to alter it and redistribute it +* freely, subject to the following restrictions: +* 1. The origin of this software must not be misrepresented; you must not +* claim that you wrote the original software. If you use this software +* in a product, an acknowledgment in the product documentation would be +* appreciated but is not required. +* 2. Altered source versions must be plainly marked as such, and must not be +* misrepresented as being the original software. +* 3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef B2_CONTACT_SOLVER_H +#define B2_CONTACT_SOLVER_H + +#include +#include +#include + +class b2Contact; +class b2Body; +class b2StackAllocator; +struct b2ContactPositionConstraint; + +struct b2VelocityConstraintPoint +{ + b2Vec2 rA; + b2Vec2 rB; + float32 normalImpulse; + float32 tangentImpulse; + float32 normalMass; + float32 tangentMass; + float32 velocityBias; +}; + +struct b2ContactVelocityConstraint +{ + b2VelocityConstraintPoint points[b2_maxManifoldPoints]; + b2Vec2 normal; + b2Mat22 normalMass; + b2Mat22 K; + int32 indexA; + int32 indexB; + float32 invMassA, invMassB; + float32 invIA, invIB; + float32 friction; + float32 restitution; + float32 tangentSpeed; + int32 pointCount; + int32 contactIndex; +}; + +struct b2ContactSolverDef +{ + b2TimeStep step; + b2Contact** contacts; + int32 count; + b2Position* positions; + b2Velocity* velocities; + b2StackAllocator* allocator; +}; + +class BOX2D_API b2ContactSolver +{ +public: + b2ContactSolver(b2ContactSolverDef* def); + ~b2ContactSolver(); + + void InitializeVelocityConstraints(); + + void WarmStart(); + void SolveVelocityConstraints(); + void StoreImpulses(); + + bool SolvePositionConstraints(); + bool SolveTOIPositionConstraints(int32 toiIndexA, int32 toiIndexB); + + b2TimeStep m_step; + b2Position* m_positions; + b2Velocity* m_velocities; + b2StackAllocator* m_allocator; + b2ContactPositionConstraint* m_positionConstraints; + b2ContactVelocityConstraint* m_velocityConstraints; + b2Contact** m_contacts; + int m_count; +}; + +#endif + diff --git a/Lib/Include/Box2D/Dynamics/Contacts/b2EdgeAndCircleContact.h b/Lib/Include/Box2D/Dynamics/Contacts/b2EdgeAndCircleContact.h new file mode 100644 index 0000000..1068352 --- /dev/null +++ b/Lib/Include/Box2D/Dynamics/Contacts/b2EdgeAndCircleContact.h @@ -0,0 +1,39 @@ +/* +* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org +* +* This software is provided 'as-is', without any express or implied +* warranty. In no event will the authors be held liable for any damages +* arising from the use of this software. +* Permission is granted to anyone to use this software for any purpose, +* including commercial applications, and to alter it and redistribute it +* freely, subject to the following restrictions: +* 1. The origin of this software must not be misrepresented; you must not +* claim that you wrote the original software. If you use this software +* in a product, an acknowledgment in the product documentation would be +* appreciated but is not required. +* 2. Altered source versions must be plainly marked as such, and must not be +* misrepresented as being the original software. +* 3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef B2_EDGE_AND_CIRCLE_CONTACT_H +#define B2_EDGE_AND_CIRCLE_CONTACT_H + +#include + +class b2BlockAllocator; + +class BOX2D_API b2EdgeAndCircleContact : public b2Contact +{ +public: + static b2Contact* Create( b2Fixture* fixtureA, int32 indexA, + b2Fixture* fixtureB, int32 indexB, b2BlockAllocator* allocator); + static void Destroy(b2Contact* contact, b2BlockAllocator* allocator); + + b2EdgeAndCircleContact(b2Fixture* fixtureA, b2Fixture* fixtureB); + ~b2EdgeAndCircleContact() {} + + void Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB); +}; + +#endif diff --git a/Lib/Include/Box2D/Dynamics/Contacts/b2EdgeAndPolygonContact.h b/Lib/Include/Box2D/Dynamics/Contacts/b2EdgeAndPolygonContact.h new file mode 100644 index 0000000..ff328e4 --- /dev/null +++ b/Lib/Include/Box2D/Dynamics/Contacts/b2EdgeAndPolygonContact.h @@ -0,0 +1,39 @@ +/* +* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org +* +* This software is provided 'as-is', without any express or implied +* warranty. In no event will the authors be held liable for any damages +* arising from the use of this software. +* Permission is granted to anyone to use this software for any purpose, +* including commercial applications, and to alter it and redistribute it +* freely, subject to the following restrictions: +* 1. The origin of this software must not be misrepresented; you must not +* claim that you wrote the original software. If you use this software +* in a product, an acknowledgment in the product documentation would be +* appreciated but is not required. +* 2. Altered source versions must be plainly marked as such, and must not be +* misrepresented as being the original software. +* 3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef B2_EDGE_AND_POLYGON_CONTACT_H +#define B2_EDGE_AND_POLYGON_CONTACT_H + +#include + +class b2BlockAllocator; + +class BOX2D_API b2EdgeAndPolygonContact : public b2Contact +{ +public: + static b2Contact* Create( b2Fixture* fixtureA, int32 indexA, + b2Fixture* fixtureB, int32 indexB, b2BlockAllocator* allocator); + static void Destroy(b2Contact* contact, b2BlockAllocator* allocator); + + b2EdgeAndPolygonContact(b2Fixture* fixtureA, b2Fixture* fixtureB); + ~b2EdgeAndPolygonContact() {} + + void Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB); +}; + +#endif diff --git a/Lib/Include/Box2D/Dynamics/Contacts/b2PolygonAndCircleContact.h b/Lib/Include/Box2D/Dynamics/Contacts/b2PolygonAndCircleContact.h new file mode 100644 index 0000000..34a6766 --- /dev/null +++ b/Lib/Include/Box2D/Dynamics/Contacts/b2PolygonAndCircleContact.h @@ -0,0 +1,38 @@ +/* +* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org +* +* This software is provided 'as-is', without any express or implied +* warranty. In no event will the authors be held liable for any damages +* arising from the use of this software. +* Permission is granted to anyone to use this software for any purpose, +* including commercial applications, and to alter it and redistribute it +* freely, subject to the following restrictions: +* 1. The origin of this software must not be misrepresented; you must not +* claim that you wrote the original software. If you use this software +* in a product, an acknowledgment in the product documentation would be +* appreciated but is not required. +* 2. Altered source versions must be plainly marked as such, and must not be +* misrepresented as being the original software. +* 3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef B2_POLYGON_AND_CIRCLE_CONTACT_H +#define B2_POLYGON_AND_CIRCLE_CONTACT_H + +#include + +class b2BlockAllocator; + +class BOX2D_API b2PolygonAndCircleContact : public b2Contact +{ +public: + static b2Contact* Create(b2Fixture* fixtureA, int32 indexA, b2Fixture* fixtureB, int32 indexB, b2BlockAllocator* allocator); + static void Destroy(b2Contact* contact, b2BlockAllocator* allocator); + + b2PolygonAndCircleContact(b2Fixture* fixtureA, b2Fixture* fixtureB); + ~b2PolygonAndCircleContact() {} + + void Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB); +}; + +#endif diff --git a/Lib/Include/Box2D/Dynamics/Contacts/b2PolygonContact.h b/Lib/Include/Box2D/Dynamics/Contacts/b2PolygonContact.h new file mode 100644 index 0000000..c7775b0 --- /dev/null +++ b/Lib/Include/Box2D/Dynamics/Contacts/b2PolygonContact.h @@ -0,0 +1,39 @@ +/* +* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org +* +* This software is provided 'as-is', without any express or implied +* warranty. In no event will the authors be held liable for any damages +* arising from the use of this software. +* Permission is granted to anyone to use this software for any purpose, +* including commercial applications, and to alter it and redistribute it +* freely, subject to the following restrictions: +* 1. The origin of this software must not be misrepresented; you must not +* claim that you wrote the original software. If you use this software +* in a product, an acknowledgment in the product documentation would be +* appreciated but is not required. +* 2. Altered source versions must be plainly marked as such, and must not be +* misrepresented as being the original software. +* 3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef B2_POLYGON_CONTACT_H +#define B2_POLYGON_CONTACT_H + +#include + +class b2BlockAllocator; + +class BOX2D_API b2PolygonContact : public b2Contact +{ +public: + static b2Contact* Create( b2Fixture* fixtureA, int32 indexA, + b2Fixture* fixtureB, int32 indexB, b2BlockAllocator* allocator); + static void Destroy(b2Contact* contact, b2BlockAllocator* allocator); + + b2PolygonContact(b2Fixture* fixtureA, b2Fixture* fixtureB); + ~b2PolygonContact() {} + + void Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB); +}; + +#endif diff --git a/Lib/Include/Box2D/Dynamics/Joints/b2DistanceJoint.h b/Lib/Include/Box2D/Dynamics/Joints/b2DistanceJoint.h new file mode 100644 index 0000000..16871a7 --- /dev/null +++ b/Lib/Include/Box2D/Dynamics/Joints/b2DistanceJoint.h @@ -0,0 +1,169 @@ +/* +* Copyright (c) 2006-2007 Erin Catto http://www.box2d.org +* +* This software is provided 'as-is', without any express or implied +* warranty. In no event will the authors be held liable for any damages +* arising from the use of this software. +* Permission is granted to anyone to use this software for any purpose, +* including commercial applications, and to alter it and redistribute it +* freely, subject to the following restrictions: +* 1. The origin of this software must not be misrepresented; you must not +* claim that you wrote the original software. If you use this software +* in a product, an acknowledgment in the product documentation would be +* appreciated but is not required. +* 2. Altered source versions must be plainly marked as such, and must not be +* misrepresented as being the original software. +* 3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef B2_DISTANCE_JOINT_H +#define B2_DISTANCE_JOINT_H + +#include + +/// Distance joint definition. This requires defining an +/// anchor point on both bodies and the non-zero length of the +/// distance joint. The definition uses local anchor points +/// so that the initial configuration can violate the constraint +/// slightly. This helps when saving and loading a game. +/// @warning Do not use a zero or short length. +struct BOX2D_API b2DistanceJointDef : public b2JointDef +{ + b2DistanceJointDef() + { + type = e_distanceJoint; + localAnchorA.Set(0.0f, 0.0f); + localAnchorB.Set(0.0f, 0.0f); + length = 1.0f; + frequencyHz = 0.0f; + dampingRatio = 0.0f; + } + + /// Initialize the bodies, anchors, and length using the world + /// anchors. + void Initialize(b2Body* bodyA, b2Body* bodyB, + const b2Vec2& anchorA, const b2Vec2& anchorB); + + /// The local anchor point relative to bodyA's origin. + b2Vec2 localAnchorA; + + /// The local anchor point relative to bodyB's origin. + b2Vec2 localAnchorB; + + /// The natural length between the anchor points. + float32 length; + + /// The mass-spring-damper frequency in Hertz. A value of 0 + /// disables softness. + float32 frequencyHz; + + /// The damping ratio. 0 = no damping, 1 = critical damping. + float32 dampingRatio; +}; + +/// A distance joint constrains two points on two bodies +/// to remain at a fixed distance from each other. You can view +/// this as a massless, rigid rod. +class BOX2D_API b2DistanceJoint : public b2Joint +{ +public: + + b2Vec2 GetAnchorA() const; + b2Vec2 GetAnchorB() const; + + /// Get the reaction force given the inverse time step. + /// Unit is N. + b2Vec2 GetReactionForce(float32 inv_dt) const; + + /// Get the reaction torque given the inverse time step. + /// Unit is N*m. This is always zero for a distance joint. + float32 GetReactionTorque(float32 inv_dt) const; + + /// The local anchor point relative to bodyA's origin. + const b2Vec2& GetLocalAnchorA() const { return m_localAnchorA; } + + /// The local anchor point relative to bodyB's origin. + const b2Vec2& GetLocalAnchorB() const { return m_localAnchorB; } + + /// Set/get the natural length. + /// Manipulating the length can lead to non-physical behavior when the frequency is zero. + void SetLength(float32 length); + float32 GetLength() const; + + /// Set/get frequency in Hz. + void SetFrequency(float32 hz); + float32 GetFrequency() const; + + /// Set/get damping ratio. + void SetDampingRatio(float32 ratio); + float32 GetDampingRatio() const; + + /// Dump joint to dmLog + void Dump(); + +protected: + + friend class b2Joint; + b2DistanceJoint(const b2DistanceJointDef* data); + + void InitVelocityConstraints(const b2SolverData& data); + void SolveVelocityConstraints(const b2SolverData& data); + bool SolvePositionConstraints(const b2SolverData& data); + + float32 m_frequencyHz; + float32 m_dampingRatio; + float32 m_bias; + + // Solver shared + b2Vec2 m_localAnchorA; + b2Vec2 m_localAnchorB; + float32 m_gamma; + float32 m_impulse; + float32 m_length; + + // Solver temp + int32 m_indexA; + int32 m_indexB; + b2Vec2 m_u; + b2Vec2 m_rA; + b2Vec2 m_rB; + b2Vec2 m_localCenterA; + b2Vec2 m_localCenterB; + float32 m_invMassA; + float32 m_invMassB; + float32 m_invIA; + float32 m_invIB; + float32 m_mass; +}; + +inline void b2DistanceJoint::SetLength(float32 length) +{ + m_length = length; +} + +inline float32 b2DistanceJoint::GetLength() const +{ + return m_length; +} + +inline void b2DistanceJoint::SetFrequency(float32 hz) +{ + m_frequencyHz = hz; +} + +inline float32 b2DistanceJoint::GetFrequency() const +{ + return m_frequencyHz; +} + +inline void b2DistanceJoint::SetDampingRatio(float32 ratio) +{ + m_dampingRatio = ratio; +} + +inline float32 b2DistanceJoint::GetDampingRatio() const +{ + return m_dampingRatio; +} + +#endif diff --git a/Lib/Include/Box2D/Dynamics/Joints/b2FrictionJoint.h b/Lib/Include/Box2D/Dynamics/Joints/b2FrictionJoint.h new file mode 100644 index 0000000..3804e5b --- /dev/null +++ b/Lib/Include/Box2D/Dynamics/Joints/b2FrictionJoint.h @@ -0,0 +1,119 @@ +/* +* Copyright (c) 2006-2007 Erin Catto http://www.box2d.org +* +* This software is provided 'as-is', without any express or implied +* warranty. In no event will the authors be held liable for any damages +* arising from the use of this software. +* Permission is granted to anyone to use this software for any purpose, +* including commercial applications, and to alter it and redistribute it +* freely, subject to the following restrictions: +* 1. The origin of this software must not be misrepresented; you must not +* claim that you wrote the original software. If you use this software +* in a product, an acknowledgment in the product documentation would be +* appreciated but is not required. +* 2. Altered source versions must be plainly marked as such, and must not be +* misrepresented as being the original software. +* 3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef B2_FRICTION_JOINT_H +#define B2_FRICTION_JOINT_H + +#include + +/// Friction joint definition. +struct BOX2D_API b2FrictionJointDef : public b2JointDef +{ + b2FrictionJointDef() + { + type = e_frictionJoint; + localAnchorA.SetZero(); + localAnchorB.SetZero(); + maxForce = 0.0f; + maxTorque = 0.0f; + } + + /// Initialize the bodies, anchors, axis, and reference angle using the world + /// anchor and world axis. + void Initialize(b2Body* bodyA, b2Body* bodyB, const b2Vec2& anchor); + + /// The local anchor point relative to bodyA's origin. + b2Vec2 localAnchorA; + + /// The local anchor point relative to bodyB's origin. + b2Vec2 localAnchorB; + + /// The maximum friction force in N. + float32 maxForce; + + /// The maximum friction torque in N-m. + float32 maxTorque; +}; + +/// Friction joint. This is used for top-down friction. +/// It provides 2D translational friction and angular friction. +class BOX2D_API b2FrictionJoint : public b2Joint +{ +public: + b2Vec2 GetAnchorA() const; + b2Vec2 GetAnchorB() const; + + b2Vec2 GetReactionForce(float32 inv_dt) const; + float32 GetReactionTorque(float32 inv_dt) const; + + /// The local anchor point relative to bodyA's origin. + const b2Vec2& GetLocalAnchorA() const { return m_localAnchorA; } + + /// The local anchor point relative to bodyB's origin. + const b2Vec2& GetLocalAnchorB() const { return m_localAnchorB; } + + /// Set the maximum friction force in N. + void SetMaxForce(float32 force); + + /// Get the maximum friction force in N. + float32 GetMaxForce() const; + + /// Set the maximum friction torque in N*m. + void SetMaxTorque(float32 torque); + + /// Get the maximum friction torque in N*m. + float32 GetMaxTorque() const; + + /// Dump joint to dmLog + void Dump(); + +protected: + + friend class b2Joint; + + b2FrictionJoint(const b2FrictionJointDef* def); + + void InitVelocityConstraints(const b2SolverData& data); + void SolveVelocityConstraints(const b2SolverData& data); + bool SolvePositionConstraints(const b2SolverData& data); + + b2Vec2 m_localAnchorA; + b2Vec2 m_localAnchorB; + + // Solver shared + b2Vec2 m_linearImpulse; + float32 m_angularImpulse; + float32 m_maxForce; + float32 m_maxTorque; + + // Solver temp + int32 m_indexA; + int32 m_indexB; + b2Vec2 m_rA; + b2Vec2 m_rB; + b2Vec2 m_localCenterA; + b2Vec2 m_localCenterB; + float32 m_invMassA; + float32 m_invMassB; + float32 m_invIA; + float32 m_invIB; + b2Mat22 m_linearMass; + float32 m_angularMass; +}; + +#endif diff --git a/Lib/Include/Box2D/Dynamics/Joints/b2GearJoint.h b/Lib/Include/Box2D/Dynamics/Joints/b2GearJoint.h new file mode 100644 index 0000000..48f471d --- /dev/null +++ b/Lib/Include/Box2D/Dynamics/Joints/b2GearJoint.h @@ -0,0 +1,125 @@ +/* +* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org +* +* This software is provided 'as-is', without any express or implied +* warranty. In no event will the authors be held liable for any damages +* arising from the use of this software. +* Permission is granted to anyone to use this software for any purpose, +* including commercial applications, and to alter it and redistribute it +* freely, subject to the following restrictions: +* 1. The origin of this software must not be misrepresented; you must not +* claim that you wrote the original software. If you use this software +* in a product, an acknowledgment in the product documentation would be +* appreciated but is not required. +* 2. Altered source versions must be plainly marked as such, and must not be +* misrepresented as being the original software. +* 3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef B2_GEAR_JOINT_H +#define B2_GEAR_JOINT_H + +#include + +/// Gear joint definition. This definition requires two existing +/// revolute or prismatic joints (any combination will work). +struct BOX2D_API b2GearJointDef : public b2JointDef +{ + b2GearJointDef() + { + type = e_gearJoint; + joint1 = NULL; + joint2 = NULL; + ratio = 1.0f; + } + + /// The first revolute/prismatic joint attached to the gear joint. + b2Joint* joint1; + + /// The second revolute/prismatic joint attached to the gear joint. + b2Joint* joint2; + + /// The gear ratio. + /// @see b2GearJoint for explanation. + float32 ratio; +}; + +/// A gear joint is used to connect two joints together. Either joint +/// can be a revolute or prismatic joint. You specify a gear ratio +/// to bind the motions together: +/// coordinate1 + ratio * coordinate2 = constant +/// The ratio can be negative or positive. If one joint is a revolute joint +/// and the other joint is a prismatic joint, then the ratio will have units +/// of length or units of 1/length. +/// @warning You have to manually destroy the gear joint if joint1 or joint2 +/// is destroyed. +class BOX2D_API b2GearJoint : public b2Joint +{ +public: + b2Vec2 GetAnchorA() const; + b2Vec2 GetAnchorB() const; + + b2Vec2 GetReactionForce(float32 inv_dt) const; + float32 GetReactionTorque(float32 inv_dt) const; + + /// Get the first joint. + b2Joint* GetJoint1() { return m_joint1; } + + /// Get the second joint. + b2Joint* GetJoint2() { return m_joint2; } + + /// Set/Get the gear ratio. + void SetRatio(float32 ratio); + float32 GetRatio() const; + + /// Dump joint to dmLog + void Dump(); + +protected: + + friend class b2Joint; + b2GearJoint(const b2GearJointDef* data); + + void InitVelocityConstraints(const b2SolverData& data); + void SolveVelocityConstraints(const b2SolverData& data); + bool SolvePositionConstraints(const b2SolverData& data); + + b2Joint* m_joint1; + b2Joint* m_joint2; + + b2JointType m_typeA; + b2JointType m_typeB; + + // Body A is connected to body C + // Body B is connected to body D + b2Body* m_bodyC; + b2Body* m_bodyD; + + // Solver shared + b2Vec2 m_localAnchorA; + b2Vec2 m_localAnchorB; + b2Vec2 m_localAnchorC; + b2Vec2 m_localAnchorD; + + b2Vec2 m_localAxisC; + b2Vec2 m_localAxisD; + + float32 m_referenceAngleA; + float32 m_referenceAngleB; + + float32 m_constant; + float32 m_ratio; + + float32 m_impulse; + + // Solver temp + int32 m_indexA, m_indexB, m_indexC, m_indexD; + b2Vec2 m_lcA, m_lcB, m_lcC, m_lcD; + float32 m_mA, m_mB, m_mC, m_mD; + float32 m_iA, m_iB, m_iC, m_iD; + b2Vec2 m_JvAC, m_JvBD; + float32 m_JwA, m_JwB, m_JwC, m_JwD; + float32 m_mass; +}; + +#endif diff --git a/Lib/Include/Box2D/Dynamics/Joints/b2Joint.h b/Lib/Include/Box2D/Dynamics/Joints/b2Joint.h new file mode 100644 index 0000000..8040e48 --- /dev/null +++ b/Lib/Include/Box2D/Dynamics/Joints/b2Joint.h @@ -0,0 +1,226 @@ +/* +* Copyright (c) 2006-2007 Erin Catto http://www.box2d.org +* +* This software is provided 'as-is', without any express or implied +* warranty. In no event will the authors be held liable for any damages +* arising from the use of this software. +* Permission is granted to anyone to use this software for any purpose, +* including commercial applications, and to alter it and redistribute it +* freely, subject to the following restrictions: +* 1. The origin of this software must not be misrepresented; you must not +* claim that you wrote the original software. If you use this software +* in a product, an acknowledgment in the product documentation would be +* appreciated but is not required. +* 2. Altered source versions must be plainly marked as such, and must not be +* misrepresented as being the original software. +* 3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef B2_JOINT_H +#define B2_JOINT_H + +#include + +class b2Body; +class b2Joint; +struct b2SolverData; +class b2BlockAllocator; + +enum b2JointType +{ + e_unknownJoint, + e_revoluteJoint, + e_prismaticJoint, + e_distanceJoint, + e_pulleyJoint, + e_mouseJoint, + e_gearJoint, + e_wheelJoint, + e_weldJoint, + e_frictionJoint, + e_ropeJoint, + e_motorJoint +}; + +enum b2LimitState +{ + e_inactiveLimit, + e_atLowerLimit, + e_atUpperLimit, + e_equalLimits +}; + +struct b2Jacobian +{ + b2Vec2 linear; + float32 angularA; + float32 angularB; +}; + +/// A joint edge is used to connect bodies and joints together +/// in a joint graph where each body is a node and each joint +/// is an edge. A joint edge belongs to a doubly linked list +/// maintained in each attached body. Each joint has two joint +/// nodes, one for each attached body. +struct b2JointEdge +{ + b2Body* other; ///< provides quick access to the other body attached. + b2Joint* joint; ///< the joint + b2JointEdge* prev; ///< the previous joint edge in the body's joint list + b2JointEdge* next; ///< the next joint edge in the body's joint list +}; + +/// Joint definitions are used to construct joints. +struct BOX2D_API b2JointDef +{ + b2JointDef() + { + type = e_unknownJoint; + userData = NULL; + bodyA = NULL; + bodyB = NULL; + collideConnected = false; + } + + /// Use this to attach application specific data to your joints. + void* userData; + + /// The first attached body. + b2Body* bodyA; + + /// The second attached body. + b2Body* bodyB; + + /// The joint type is set automatically for concrete joint types. + b2JointType type; + + /// Set this flag to true if the attached bodies should collide. + bool collideConnected; +}; + +/// The base joint class. Joints are used to constraint two bodies together in +/// various fashions. Some joints also feature limits and motors. +class BOX2D_API b2Joint +{ +public: + + /// Get the type of the concrete joint. + b2JointType GetType() const; + + /// Get the first body attached to this joint. + b2Body* GetBodyA(); + + /// Get the second body attached to this joint. + b2Body* GetBodyB(); + + /// Get the anchor point on bodyA in world coordinates. + virtual b2Vec2 GetAnchorA() const = 0; + + /// Get the anchor point on bodyB in world coordinates. + virtual b2Vec2 GetAnchorB() const = 0; + + /// Get the reaction force on bodyB at the joint anchor in Newtons. + virtual b2Vec2 GetReactionForce(float32 inv_dt) const = 0; + + /// Get the reaction torque on bodyB in N*m. + virtual float32 GetReactionTorque(float32 inv_dt) const = 0; + + /// Get the next joint the world joint list. + b2Joint* GetNext(); + const b2Joint* GetNext() const; + + /// Get the user data pointer. + void* GetUserData() const; + + /// Set the user data pointer. + void SetUserData(void* data); + + /// Short-cut function to determine if either body is inactive. + bool IsActive() const; + + /// Get collide connected. + /// Note: modifying the collide connect flag won't work correctly because + /// the flag is only checked when fixture AABBs begin to overlap. + bool GetCollideConnected() const; + + /// Dump this joint to the log file. + virtual void Dump() { b2Log("// Dump is not supported for this joint type.\n"); } + + /// Shift the origin for any points stored in world coordinates. + virtual void ShiftOrigin(const b2Vec2& newOrigin) { B2_NOT_USED(newOrigin); } + +protected: + friend class b2World; + friend class b2Body; + friend class b2Island; + friend class b2GearJoint; + + static b2Joint* Create(const b2JointDef* def, b2BlockAllocator* allocator); + static void Destroy(b2Joint* joint, b2BlockAllocator* allocator); + + b2Joint(const b2JointDef* def); + virtual ~b2Joint() {} + + virtual void InitVelocityConstraints(const b2SolverData& data) = 0; + virtual void SolveVelocityConstraints(const b2SolverData& data) = 0; + + // This returns true if the position errors are within tolerance. + virtual bool SolvePositionConstraints(const b2SolverData& data) = 0; + + b2JointType m_type; + b2Joint* m_prev; + b2Joint* m_next; + b2JointEdge m_edgeA; + b2JointEdge m_edgeB; + b2Body* m_bodyA; + b2Body* m_bodyB; + + int32 m_index; + + bool m_islandFlag; + bool m_collideConnected; + + void* m_userData; +}; + +inline b2JointType b2Joint::GetType() const +{ + return m_type; +} + +inline b2Body* b2Joint::GetBodyA() +{ + return m_bodyA; +} + +inline b2Body* b2Joint::GetBodyB() +{ + return m_bodyB; +} + +inline b2Joint* b2Joint::GetNext() +{ + return m_next; +} + +inline const b2Joint* b2Joint::GetNext() const +{ + return m_next; +} + +inline void* b2Joint::GetUserData() const +{ + return m_userData; +} + +inline void b2Joint::SetUserData(void* data) +{ + m_userData = data; +} + +inline bool b2Joint::GetCollideConnected() const +{ + return m_collideConnected; +} + +#endif diff --git a/Lib/Include/Box2D/Dynamics/Joints/b2MotorJoint.h b/Lib/Include/Box2D/Dynamics/Joints/b2MotorJoint.h new file mode 100644 index 0000000..de60079 --- /dev/null +++ b/Lib/Include/Box2D/Dynamics/Joints/b2MotorJoint.h @@ -0,0 +1,133 @@ +/* +* Copyright (c) 2006-2012 Erin Catto http://www.box2d.org +* +* This software is provided 'as-is', without any express or implied +* warranty. In no event will the authors be held liable for any damages +* arising from the use of this software. +* Permission is granted to anyone to use this software for any purpose, +* including commercial applications, and to alter it and redistribute it +* freely, subject to the following restrictions: +* 1. The origin of this software must not be misrepresented; you must not +* claim that you wrote the original software. If you use this software +* in a product, an acknowledgment in the product documentation would be +* appreciated but is not required. +* 2. Altered source versions must be plainly marked as such, and must not be +* misrepresented as being the original software. +* 3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef B2_MOTOR_JOINT_H +#define B2_MOTOR_JOINT_H + +#include + +/// Motor joint definition. +struct BOX2D_API b2MotorJointDef : public b2JointDef +{ + b2MotorJointDef() + { + type = e_motorJoint; + linearOffset.SetZero(); + angularOffset = 0.0f; + maxForce = 1.0f; + maxTorque = 1.0f; + correctionFactor = 0.3f; + } + + /// Initialize the bodies and offsets using the current transforms. + void Initialize(b2Body* bodyA, b2Body* bodyB); + + /// Position of bodyB minus the position of bodyA, in bodyA's frame, in meters. + b2Vec2 linearOffset; + + /// The bodyB angle minus bodyA angle in radians. + float32 angularOffset; + + /// The maximum motor force in N. + float32 maxForce; + + /// The maximum motor torque in N-m. + float32 maxTorque; + + /// Position correction factor in the range [0,1]. + float32 correctionFactor; +}; + +/// A motor joint is used to control the relative motion +/// between two bodies. A typical usage is to control the movement +/// of a dynamic body with respect to the ground. +class BOX2D_API b2MotorJoint : public b2Joint +{ +public: + b2Vec2 GetAnchorA() const; + b2Vec2 GetAnchorB() const; + + b2Vec2 GetReactionForce(float32 inv_dt) const; + float32 GetReactionTorque(float32 inv_dt) const; + + /// Set/get the target linear offset, in frame A, in meters. + void SetLinearOffset(const b2Vec2& linearOffset); + const b2Vec2& GetLinearOffset() const; + + /// Set/get the target angular offset, in radians. + void SetAngularOffset(float32 angularOffset); + float32 GetAngularOffset() const; + + /// Set the maximum friction force in N. + void SetMaxForce(float32 force); + + /// Get the maximum friction force in N. + float32 GetMaxForce() const; + + /// Set the maximum friction torque in N*m. + void SetMaxTorque(float32 torque); + + /// Get the maximum friction torque in N*m. + float32 GetMaxTorque() const; + + /// Set the position correction factor in the range [0,1]. + void SetCorrectionFactor(float32 factor); + + /// Get the position correction factor in the range [0,1]. + float32 GetCorrectionFactor() const; + + /// Dump to b2Log + void Dump(); + +protected: + + friend class b2Joint; + + b2MotorJoint(const b2MotorJointDef* def); + + void InitVelocityConstraints(const b2SolverData& data); + void SolveVelocityConstraints(const b2SolverData& data); + bool SolvePositionConstraints(const b2SolverData& data); + + // Solver shared + b2Vec2 m_linearOffset; + float32 m_angularOffset; + b2Vec2 m_linearImpulse; + float32 m_angularImpulse; + float32 m_maxForce; + float32 m_maxTorque; + float32 m_correctionFactor; + + // Solver temp + int32 m_indexA; + int32 m_indexB; + b2Vec2 m_rA; + b2Vec2 m_rB; + b2Vec2 m_localCenterA; + b2Vec2 m_localCenterB; + b2Vec2 m_linearError; + float32 m_angularError; + float32 m_invMassA; + float32 m_invMassB; + float32 m_invIA; + float32 m_invIB; + b2Mat22 m_linearMass; + float32 m_angularMass; +}; + +#endif diff --git a/Lib/Include/Box2D/Dynamics/Joints/b2MouseJoint.h b/Lib/Include/Box2D/Dynamics/Joints/b2MouseJoint.h new file mode 100644 index 0000000..4bcb880 --- /dev/null +++ b/Lib/Include/Box2D/Dynamics/Joints/b2MouseJoint.h @@ -0,0 +1,129 @@ +/* +* Copyright (c) 2006-2007 Erin Catto http://www.box2d.org +* +* This software is provided 'as-is', without any express or implied +* warranty. In no event will the authors be held liable for any damages +* arising from the use of this software. +* Permission is granted to anyone to use this software for any purpose, +* including commercial applications, and to alter it and redistribute it +* freely, subject to the following restrictions: +* 1. The origin of this software must not be misrepresented; you must not +* claim that you wrote the original software. If you use this software +* in a product, an acknowledgment in the product documentation would be +* appreciated but is not required. +* 2. Altered source versions must be plainly marked as such, and must not be +* misrepresented as being the original software. +* 3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef B2_MOUSE_JOINT_H +#define B2_MOUSE_JOINT_H + +#include + +/// Mouse joint definition. This requires a world target point, +/// tuning parameters, and the time step. +struct BOX2D_API b2MouseJointDef : public b2JointDef +{ + b2MouseJointDef() + { + type = e_mouseJoint; + target.Set(0.0f, 0.0f); + maxForce = 0.0f; + frequencyHz = 5.0f; + dampingRatio = 0.7f; + } + + /// The initial world target point. This is assumed + /// to coincide with the body anchor initially. + b2Vec2 target; + + /// The maximum constraint force that can be exerted + /// to move the candidate body. Usually you will express + /// as some multiple of the weight (multiplier * mass * gravity). + float32 maxForce; + + /// The response speed. + float32 frequencyHz; + + /// The damping ratio. 0 = no damping, 1 = critical damping. + float32 dampingRatio; +}; + +/// A mouse joint is used to make a point on a body track a +/// specified world point. This a soft constraint with a maximum +/// force. This allows the constraint to stretch and without +/// applying huge forces. +/// NOTE: this joint is not documented in the manual because it was +/// developed to be used in the testbed. If you want to learn how to +/// use the mouse joint, look at the testbed. +class BOX2D_API b2MouseJoint : public b2Joint +{ +public: + + /// Implements b2Joint. + b2Vec2 GetAnchorA() const; + + /// Implements b2Joint. + b2Vec2 GetAnchorB() const; + + /// Implements b2Joint. + b2Vec2 GetReactionForce(float32 inv_dt) const; + + /// Implements b2Joint. + float32 GetReactionTorque(float32 inv_dt) const; + + /// Use this to update the target point. + void SetTarget(const b2Vec2& target); + const b2Vec2& GetTarget() const; + + /// Set/get the maximum force in Newtons. + void SetMaxForce(float32 force); + float32 GetMaxForce() const; + + /// Set/get the frequency in Hertz. + void SetFrequency(float32 hz); + float32 GetFrequency() const; + + /// Set/get the damping ratio (dimensionless). + void SetDampingRatio(float32 ratio); + float32 GetDampingRatio() const; + + /// The mouse joint does not support dumping. + void Dump() { b2Log("Mouse joint dumping is not supported.\n"); } + + /// Implement b2Joint::ShiftOrigin + void ShiftOrigin(const b2Vec2& newOrigin); + +protected: + friend class b2Joint; + + b2MouseJoint(const b2MouseJointDef* def); + + void InitVelocityConstraints(const b2SolverData& data); + void SolveVelocityConstraints(const b2SolverData& data); + bool SolvePositionConstraints(const b2SolverData& data); + + b2Vec2 m_localAnchorB; + b2Vec2 m_targetA; + float32 m_frequencyHz; + float32 m_dampingRatio; + float32 m_beta; + + // Solver shared + b2Vec2 m_impulse; + float32 m_maxForce; + float32 m_gamma; + + // Solver temp + int32 m_indexA; + int32 m_indexB; + b2Vec2 m_rB; + b2Vec2 m_localCenterB; + float32 m_invMassB; + float32 m_invIB; + b2Mat22 m_mass; + b2Vec2 m_C; +}; + +#endif diff --git a/Lib/Include/Box2D/Dynamics/Joints/b2PrismaticJoint.h b/Lib/Include/Box2D/Dynamics/Joints/b2PrismaticJoint.h new file mode 100644 index 0000000..bcdbd7b --- /dev/null +++ b/Lib/Include/Box2D/Dynamics/Joints/b2PrismaticJoint.h @@ -0,0 +1,196 @@ +/* +* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org +* +* This software is provided 'as-is', without any express or implied +* warranty. In no event will the authors be held liable for any damages +* arising from the use of this software. +* Permission is granted to anyone to use this software for any purpose, +* including commercial applications, and to alter it and redistribute it +* freely, subject to the following restrictions: +* 1. The origin of this software must not be misrepresented; you must not +* claim that you wrote the original software. If you use this software +* in a product, an acknowledgment in the product documentation would be +* appreciated but is not required. +* 2. Altered source versions must be plainly marked as such, and must not be +* misrepresented as being the original software. +* 3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef B2_PRISMATIC_JOINT_H +#define B2_PRISMATIC_JOINT_H + +#include + +/// Prismatic joint definition. This requires defining a line of +/// motion using an axis and an anchor point. The definition uses local +/// anchor points and a local axis so that the initial configuration +/// can violate the constraint slightly. The joint translation is zero +/// when the local anchor points coincide in world space. Using local +/// anchors and a local axis helps when saving and loading a game. +struct BOX2D_API b2PrismaticJointDef : public b2JointDef +{ + b2PrismaticJointDef() + { + type = e_prismaticJoint; + localAnchorA.SetZero(); + localAnchorB.SetZero(); + localAxisA.Set(1.0f, 0.0f); + referenceAngle = 0.0f; + enableLimit = false; + lowerTranslation = 0.0f; + upperTranslation = 0.0f; + enableMotor = false; + maxMotorForce = 0.0f; + motorSpeed = 0.0f; + } + + /// Initialize the bodies, anchors, axis, and reference angle using the world + /// anchor and unit world axis. + void Initialize(b2Body* bodyA, b2Body* bodyB, const b2Vec2& anchor, const b2Vec2& axis); + + /// The local anchor point relative to bodyA's origin. + b2Vec2 localAnchorA; + + /// The local anchor point relative to bodyB's origin. + b2Vec2 localAnchorB; + + /// The local translation unit axis in bodyA. + b2Vec2 localAxisA; + + /// The constrained angle between the bodies: bodyB_angle - bodyA_angle. + float32 referenceAngle; + + /// Enable/disable the joint limit. + bool enableLimit; + + /// The lower translation limit, usually in meters. + float32 lowerTranslation; + + /// The upper translation limit, usually in meters. + float32 upperTranslation; + + /// Enable/disable the joint motor. + bool enableMotor; + + /// The maximum motor torque, usually in N-m. + float32 maxMotorForce; + + /// The desired motor speed in radians per second. + float32 motorSpeed; +}; + +/// A prismatic joint. This joint provides one degree of freedom: translation +/// along an axis fixed in bodyA. Relative rotation is prevented. You can +/// use a joint limit to restrict the range of motion and a joint motor to +/// drive the motion or to model joint friction. +class BOX2D_API b2PrismaticJoint : public b2Joint +{ +public: + b2Vec2 GetAnchorA() const; + b2Vec2 GetAnchorB() const; + + b2Vec2 GetReactionForce(float32 inv_dt) const; + float32 GetReactionTorque(float32 inv_dt) const; + + /// The local anchor point relative to bodyA's origin. + const b2Vec2& GetLocalAnchorA() const { return m_localAnchorA; } + + /// The local anchor point relative to bodyB's origin. + const b2Vec2& GetLocalAnchorB() const { return m_localAnchorB; } + + /// The local joint axis relative to bodyA. + const b2Vec2& GetLocalAxisA() const { return m_localXAxisA; } + + /// Get the reference angle. + float32 GetReferenceAngle() const { return m_referenceAngle; } + + /// Get the current joint translation, usually in meters. + float32 GetJointTranslation() const; + + /// Get the current joint translation speed, usually in meters per second. + float32 GetJointSpeed() const; + + /// Is the joint limit enabled? + bool IsLimitEnabled() const; + + /// Enable/disable the joint limit. + void EnableLimit(bool flag); + + /// Get the lower joint limit, usually in meters. + float32 GetLowerLimit() const; + + /// Get the upper joint limit, usually in meters. + float32 GetUpperLimit() const; + + /// Set the joint limits, usually in meters. + void SetLimits(float32 lower, float32 upper); + + /// Is the joint motor enabled? + bool IsMotorEnabled() const; + + /// Enable/disable the joint motor. + void EnableMotor(bool flag); + + /// Set the motor speed, usually in meters per second. + void SetMotorSpeed(float32 speed); + + /// Get the motor speed, usually in meters per second. + float32 GetMotorSpeed() const; + + /// Set the maximum motor force, usually in N. + void SetMaxMotorForce(float32 force); + float32 GetMaxMotorForce() const { return m_maxMotorForce; } + + /// Get the current motor force given the inverse time step, usually in N. + float32 GetMotorForce(float32 inv_dt) const; + + /// Dump to b2Log + void Dump(); + +protected: + friend class b2Joint; + friend class b2GearJoint; + b2PrismaticJoint(const b2PrismaticJointDef* def); + + void InitVelocityConstraints(const b2SolverData& data); + void SolveVelocityConstraints(const b2SolverData& data); + bool SolvePositionConstraints(const b2SolverData& data); + + // Solver shared + b2Vec2 m_localAnchorA; + b2Vec2 m_localAnchorB; + b2Vec2 m_localXAxisA; + b2Vec2 m_localYAxisA; + float32 m_referenceAngle; + b2Vec3 m_impulse; + float32 m_motorImpulse; + float32 m_lowerTranslation; + float32 m_upperTranslation; + float32 m_maxMotorForce; + float32 m_motorSpeed; + bool m_enableLimit; + bool m_enableMotor; + b2LimitState m_limitState; + + // Solver temp + int32 m_indexA; + int32 m_indexB; + b2Vec2 m_localCenterA; + b2Vec2 m_localCenterB; + float32 m_invMassA; + float32 m_invMassB; + float32 m_invIA; + float32 m_invIB; + b2Vec2 m_axis, m_perp; + float32 m_s1, m_s2; + float32 m_a1, m_a2; + b2Mat33 m_K; + float32 m_motorMass; +}; + +inline float32 b2PrismaticJoint::GetMotorSpeed() const +{ + return m_motorSpeed; +} + +#endif diff --git a/Lib/Include/Box2D/Dynamics/Joints/b2PulleyJoint.h b/Lib/Include/Box2D/Dynamics/Joints/b2PulleyJoint.h new file mode 100644 index 0000000..e051a81 --- /dev/null +++ b/Lib/Include/Box2D/Dynamics/Joints/b2PulleyJoint.h @@ -0,0 +1,152 @@ +/* +* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org +* +* This software is provided 'as-is', without any express or implied +* warranty. In no event will the authors be held liable for any damages +* arising from the use of this software. +* Permission is granted to anyone to use this software for any purpose, +* including commercial applications, and to alter it and redistribute it +* freely, subject to the following restrictions: +* 1. The origin of this software must not be misrepresented; you must not +* claim that you wrote the original software. If you use this software +* in a product, an acknowledgment in the product documentation would be +* appreciated but is not required. +* 2. Altered source versions must be plainly marked as such, and must not be +* misrepresented as being the original software. +* 3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef B2_PULLEY_JOINT_H +#define B2_PULLEY_JOINT_H + +#include + +const float32 b2_minPulleyLength = 2.0f; + +/// Pulley joint definition. This requires two ground anchors, +/// two dynamic body anchor points, and a pulley ratio. +struct BOX2D_API b2PulleyJointDef : public b2JointDef +{ + b2PulleyJointDef() + { + type = e_pulleyJoint; + groundAnchorA.Set(-1.0f, 1.0f); + groundAnchorB.Set(1.0f, 1.0f); + localAnchorA.Set(-1.0f, 0.0f); + localAnchorB.Set(1.0f, 0.0f); + lengthA = 0.0f; + lengthB = 0.0f; + ratio = 1.0f; + collideConnected = true; + } + + /// Initialize the bodies, anchors, lengths, max lengths, and ratio using the world anchors. + void Initialize(b2Body* bodyA, b2Body* bodyB, + const b2Vec2& groundAnchorA, const b2Vec2& groundAnchorB, + const b2Vec2& anchorA, const b2Vec2& anchorB, + float32 ratio); + + /// The first ground anchor in world coordinates. This point never moves. + b2Vec2 groundAnchorA; + + /// The second ground anchor in world coordinates. This point never moves. + b2Vec2 groundAnchorB; + + /// The local anchor point relative to bodyA's origin. + b2Vec2 localAnchorA; + + /// The local anchor point relative to bodyB's origin. + b2Vec2 localAnchorB; + + /// The a reference length for the segment attached to bodyA. + float32 lengthA; + + /// The a reference length for the segment attached to bodyB. + float32 lengthB; + + /// The pulley ratio, used to simulate a block-and-tackle. + float32 ratio; +}; + +/// The pulley joint is connected to two bodies and two fixed ground points. +/// The pulley supports a ratio such that: +/// length1 + ratio * length2 <= constant +/// Yes, the force transmitted is scaled by the ratio. +/// Warning: the pulley joint can get a bit squirrelly by itself. They often +/// work better when combined with prismatic joints. You should also cover the +/// the anchor points with static shapes to prevent one side from going to +/// zero length. +class BOX2D_API b2PulleyJoint : public b2Joint +{ +public: + b2Vec2 GetAnchorA() const; + b2Vec2 GetAnchorB() const; + + b2Vec2 GetReactionForce(float32 inv_dt) const; + float32 GetReactionTorque(float32 inv_dt) const; + + /// Get the first ground anchor. + b2Vec2 GetGroundAnchorA() const; + + /// Get the second ground anchor. + b2Vec2 GetGroundAnchorB() const; + + /// Get the current length of the segment attached to bodyA. + float32 GetLengthA() const; + + /// Get the current length of the segment attached to bodyB. + float32 GetLengthB() const; + + /// Get the pulley ratio. + float32 GetRatio() const; + + /// Get the current length of the segment attached to bodyA. + float32 GetCurrentLengthA() const; + + /// Get the current length of the segment attached to bodyB. + float32 GetCurrentLengthB() const; + + /// Dump joint to dmLog + void Dump(); + + /// Implement b2Joint::ShiftOrigin + void ShiftOrigin(const b2Vec2& newOrigin); + +protected: + + friend class b2Joint; + b2PulleyJoint(const b2PulleyJointDef* data); + + void InitVelocityConstraints(const b2SolverData& data); + void SolveVelocityConstraints(const b2SolverData& data); + bool SolvePositionConstraints(const b2SolverData& data); + + b2Vec2 m_groundAnchorA; + b2Vec2 m_groundAnchorB; + float32 m_lengthA; + float32 m_lengthB; + + // Solver shared + b2Vec2 m_localAnchorA; + b2Vec2 m_localAnchorB; + float32 m_constant; + float32 m_ratio; + float32 m_impulse; + + // Solver temp + int32 m_indexA; + int32 m_indexB; + b2Vec2 m_uA; + b2Vec2 m_uB; + b2Vec2 m_rA; + b2Vec2 m_rB; + b2Vec2 m_localCenterA; + b2Vec2 m_localCenterB; + float32 m_invMassA; + float32 m_invMassB; + float32 m_invIA; + float32 m_invIB; + float32 m_mass; +}; + +#endif diff --git a/Lib/Include/Box2D/Dynamics/Joints/b2RevoluteJoint.h b/Lib/Include/Box2D/Dynamics/Joints/b2RevoluteJoint.h new file mode 100644 index 0000000..4427d72 --- /dev/null +++ b/Lib/Include/Box2D/Dynamics/Joints/b2RevoluteJoint.h @@ -0,0 +1,204 @@ +/* +* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org +* +* This software is provided 'as-is', without any express or implied +* warranty. In no event will the authors be held liable for any damages +* arising from the use of this software. +* Permission is granted to anyone to use this software for any purpose, +* including commercial applications, and to alter it and redistribute it +* freely, subject to the following restrictions: +* 1. The origin of this software must not be misrepresented; you must not +* claim that you wrote the original software. If you use this software +* in a product, an acknowledgment in the product documentation would be +* appreciated but is not required. +* 2. Altered source versions must be plainly marked as such, and must not be +* misrepresented as being the original software. +* 3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef B2_REVOLUTE_JOINT_H +#define B2_REVOLUTE_JOINT_H + +#include + +/// Revolute joint definition. This requires defining an +/// anchor point where the bodies are joined. The definition +/// uses local anchor points so that the initial configuration +/// can violate the constraint slightly. You also need to +/// specify the initial relative angle for joint limits. This +/// helps when saving and loading a game. +/// The local anchor points are measured from the body's origin +/// rather than the center of mass because: +/// 1. you might not know where the center of mass will be. +/// 2. if you add/remove shapes from a body and recompute the mass, +/// the joints will be broken. +struct BOX2D_API b2RevoluteJointDef : public b2JointDef +{ + b2RevoluteJointDef() + { + type = e_revoluteJoint; + localAnchorA.Set(0.0f, 0.0f); + localAnchorB.Set(0.0f, 0.0f); + referenceAngle = 0.0f; + lowerAngle = 0.0f; + upperAngle = 0.0f; + maxMotorTorque = 0.0f; + motorSpeed = 0.0f; + enableLimit = false; + enableMotor = false; + } + + /// Initialize the bodies, anchors, and reference angle using a world + /// anchor point. + void Initialize(b2Body* bodyA, b2Body* bodyB, const b2Vec2& anchor); + + /// The local anchor point relative to bodyA's origin. + b2Vec2 localAnchorA; + + /// The local anchor point relative to bodyB's origin. + b2Vec2 localAnchorB; + + /// The bodyB angle minus bodyA angle in the reference state (radians). + float32 referenceAngle; + + /// A flag to enable joint limits. + bool enableLimit; + + /// The lower angle for the joint limit (radians). + float32 lowerAngle; + + /// The upper angle for the joint limit (radians). + float32 upperAngle; + + /// A flag to enable the joint motor. + bool enableMotor; + + /// The desired motor speed. Usually in radians per second. + float32 motorSpeed; + + /// The maximum motor torque used to achieve the desired motor speed. + /// Usually in N-m. + float32 maxMotorTorque; +}; + +/// A revolute joint constrains two bodies to share a common point while they +/// are free to rotate about the point. The relative rotation about the shared +/// point is the joint angle. You can limit the relative rotation with +/// a joint limit that specifies a lower and upper angle. You can use a motor +/// to drive the relative rotation about the shared point. A maximum motor torque +/// is provided so that infinite forces are not generated. +class BOX2D_API b2RevoluteJoint : public b2Joint +{ +public: + b2Vec2 GetAnchorA() const; + b2Vec2 GetAnchorB() const; + + /// The local anchor point relative to bodyA's origin. + const b2Vec2& GetLocalAnchorA() const { return m_localAnchorA; } + + /// The local anchor point relative to bodyB's origin. + const b2Vec2& GetLocalAnchorB() const { return m_localAnchorB; } + + /// Get the reference angle. + float32 GetReferenceAngle() const { return m_referenceAngle; } + + /// Get the current joint angle in radians. + float32 GetJointAngle() const; + + /// Get the current joint angle speed in radians per second. + float32 GetJointSpeed() const; + + /// Is the joint limit enabled? + bool IsLimitEnabled() const; + + /// Enable/disable the joint limit. + void EnableLimit(bool flag); + + /// Get the lower joint limit in radians. + float32 GetLowerLimit() const; + + /// Get the upper joint limit in radians. + float32 GetUpperLimit() const; + + /// Set the joint limits in radians. + void SetLimits(float32 lower, float32 upper); + + /// Is the joint motor enabled? + bool IsMotorEnabled() const; + + /// Enable/disable the joint motor. + void EnableMotor(bool flag); + + /// Set the motor speed in radians per second. + void SetMotorSpeed(float32 speed); + + /// Get the motor speed in radians per second. + float32 GetMotorSpeed() const; + + /// Set the maximum motor torque, usually in N-m. + void SetMaxMotorTorque(float32 torque); + float32 GetMaxMotorTorque() const { return m_maxMotorTorque; } + + /// Get the reaction force given the inverse time step. + /// Unit is N. + b2Vec2 GetReactionForce(float32 inv_dt) const; + + /// Get the reaction torque due to the joint limit given the inverse time step. + /// Unit is N*m. + float32 GetReactionTorque(float32 inv_dt) const; + + /// Get the current motor torque given the inverse time step. + /// Unit is N*m. + float32 GetMotorTorque(float32 inv_dt) const; + + /// Dump to b2Log. + void Dump(); + +protected: + + friend class b2Joint; + friend class b2GearJoint; + + b2RevoluteJoint(const b2RevoluteJointDef* def); + + void InitVelocityConstraints(const b2SolverData& data); + void SolveVelocityConstraints(const b2SolverData& data); + bool SolvePositionConstraints(const b2SolverData& data); + + // Solver shared + b2Vec2 m_localAnchorA; + b2Vec2 m_localAnchorB; + b2Vec3 m_impulse; + float32 m_motorImpulse; + + bool m_enableMotor; + float32 m_maxMotorTorque; + float32 m_motorSpeed; + + bool m_enableLimit; + float32 m_referenceAngle; + float32 m_lowerAngle; + float32 m_upperAngle; + + // Solver temp + int32 m_indexA; + int32 m_indexB; + b2Vec2 m_rA; + b2Vec2 m_rB; + b2Vec2 m_localCenterA; + b2Vec2 m_localCenterB; + float32 m_invMassA; + float32 m_invMassB; + float32 m_invIA; + float32 m_invIB; + b2Mat33 m_mass; // effective mass for point-to-point constraint. + float32 m_motorMass; // effective mass for motor/limit angular constraint. + b2LimitState m_limitState; +}; + +inline float32 b2RevoluteJoint::GetMotorSpeed() const +{ + return m_motorSpeed; +} + +#endif diff --git a/Lib/Include/Box2D/Dynamics/Joints/b2RopeJoint.h b/Lib/Include/Box2D/Dynamics/Joints/b2RopeJoint.h new file mode 100644 index 0000000..34ea304 --- /dev/null +++ b/Lib/Include/Box2D/Dynamics/Joints/b2RopeJoint.h @@ -0,0 +1,114 @@ +/* +* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org +* +* This software is provided 'as-is', without any express or implied +* warranty. In no event will the authors be held liable for any damages +* arising from the use of this software. +* Permission is granted to anyone to use this software for any purpose, +* including commercial applications, and to alter it and redistribute it +* freely, subject to the following restrictions: +* 1. The origin of this software must not be misrepresented; you must not +* claim that you wrote the original software. If you use this software +* in a product, an acknowledgment in the product documentation would be +* appreciated but is not required. +* 2. Altered source versions must be plainly marked as such, and must not be +* misrepresented as being the original software. +* 3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef B2_ROPE_JOINT_H +#define B2_ROPE_JOINT_H + +#include + +/// Rope joint definition. This requires two body anchor points and +/// a maximum lengths. +/// Note: by default the connected objects will not collide. +/// see collideConnected in b2JointDef. +struct BOX2D_API b2RopeJointDef : public b2JointDef +{ + b2RopeJointDef() + { + type = e_ropeJoint; + localAnchorA.Set(-1.0f, 0.0f); + localAnchorB.Set(1.0f, 0.0f); + maxLength = 0.0f; + } + + /// The local anchor point relative to bodyA's origin. + b2Vec2 localAnchorA; + + /// The local anchor point relative to bodyB's origin. + b2Vec2 localAnchorB; + + /// The maximum length of the rope. + /// Warning: this must be larger than b2_linearSlop or + /// the joint will have no effect. + float32 maxLength; +}; + +/// A rope joint enforces a maximum distance between two points +/// on two bodies. It has no other effect. +/// Warning: if you attempt to change the maximum length during +/// the simulation you will get some non-physical behavior. +/// A model that would allow you to dynamically modify the length +/// would have some sponginess, so I chose not to implement it +/// that way. See b2DistanceJoint if you want to dynamically +/// control length. +class BOX2D_API b2RopeJoint : public b2Joint +{ +public: + b2Vec2 GetAnchorA() const; + b2Vec2 GetAnchorB() const; + + b2Vec2 GetReactionForce(float32 inv_dt) const; + float32 GetReactionTorque(float32 inv_dt) const; + + /// The local anchor point relative to bodyA's origin. + const b2Vec2& GetLocalAnchorA() const { return m_localAnchorA; } + + /// The local anchor point relative to bodyB's origin. + const b2Vec2& GetLocalAnchorB() const { return m_localAnchorB; } + + /// Set/Get the maximum length of the rope. + void SetMaxLength(float32 length) { m_maxLength = length; } + float32 GetMaxLength() const; + + b2LimitState GetLimitState() const; + + /// Dump joint to dmLog + void Dump(); + +protected: + + friend class b2Joint; + b2RopeJoint(const b2RopeJointDef* data); + + void InitVelocityConstraints(const b2SolverData& data); + void SolveVelocityConstraints(const b2SolverData& data); + bool SolvePositionConstraints(const b2SolverData& data); + + // Solver shared + b2Vec2 m_localAnchorA; + b2Vec2 m_localAnchorB; + float32 m_maxLength; + float32 m_length; + float32 m_impulse; + + // Solver temp + int32 m_indexA; + int32 m_indexB; + b2Vec2 m_u; + b2Vec2 m_rA; + b2Vec2 m_rB; + b2Vec2 m_localCenterA; + b2Vec2 m_localCenterB; + float32 m_invMassA; + float32 m_invMassB; + float32 m_invIA; + float32 m_invIB; + float32 m_mass; + b2LimitState m_state; +}; + +#endif diff --git a/Lib/Include/Box2D/Dynamics/Joints/b2WeldJoint.h b/Lib/Include/Box2D/Dynamics/Joints/b2WeldJoint.h new file mode 100644 index 0000000..2887a12 --- /dev/null +++ b/Lib/Include/Box2D/Dynamics/Joints/b2WeldJoint.h @@ -0,0 +1,126 @@ +/* +* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org +* +* This software is provided 'as-is', without any express or implied +* warranty. In no event will the authors be held liable for any damages +* arising from the use of this software. +* Permission is granted to anyone to use this software for any purpose, +* including commercial applications, and to alter it and redistribute it +* freely, subject to the following restrictions: +* 1. The origin of this software must not be misrepresented; you must not +* claim that you wrote the original software. If you use this software +* in a product, an acknowledgment in the product documentation would be +* appreciated but is not required. +* 2. Altered source versions must be plainly marked as such, and must not be +* misrepresented as being the original software. +* 3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef B2_WELD_JOINT_H +#define B2_WELD_JOINT_H + +#include + +/// Weld joint definition. You need to specify local anchor points +/// where they are attached and the relative body angle. The position +/// of the anchor points is important for computing the reaction torque. +struct BOX2D_API b2WeldJointDef : public b2JointDef +{ + b2WeldJointDef() + { + type = e_weldJoint; + localAnchorA.Set(0.0f, 0.0f); + localAnchorB.Set(0.0f, 0.0f); + referenceAngle = 0.0f; + frequencyHz = 0.0f; + dampingRatio = 0.0f; + } + + /// Initialize the bodies, anchors, and reference angle using a world + /// anchor point. + void Initialize(b2Body* bodyA, b2Body* bodyB, const b2Vec2& anchor); + + /// The local anchor point relative to bodyA's origin. + b2Vec2 localAnchorA; + + /// The local anchor point relative to bodyB's origin. + b2Vec2 localAnchorB; + + /// The bodyB angle minus bodyA angle in the reference state (radians). + float32 referenceAngle; + + /// The mass-spring-damper frequency in Hertz. Rotation only. + /// Disable softness with a value of 0. + float32 frequencyHz; + + /// The damping ratio. 0 = no damping, 1 = critical damping. + float32 dampingRatio; +}; + +/// A weld joint essentially glues two bodies together. A weld joint may +/// distort somewhat because the island constraint solver is approximate. +class BOX2D_API b2WeldJoint : public b2Joint +{ +public: + b2Vec2 GetAnchorA() const; + b2Vec2 GetAnchorB() const; + + b2Vec2 GetReactionForce(float32 inv_dt) const; + float32 GetReactionTorque(float32 inv_dt) const; + + /// The local anchor point relative to bodyA's origin. + const b2Vec2& GetLocalAnchorA() const { return m_localAnchorA; } + + /// The local anchor point relative to bodyB's origin. + const b2Vec2& GetLocalAnchorB() const { return m_localAnchorB; } + + /// Get the reference angle. + float32 GetReferenceAngle() const { return m_referenceAngle; } + + /// Set/get frequency in Hz. + void SetFrequency(float32 hz) { m_frequencyHz = hz; } + float32 GetFrequency() const { return m_frequencyHz; } + + /// Set/get damping ratio. + void SetDampingRatio(float32 ratio) { m_dampingRatio = ratio; } + float32 GetDampingRatio() const { return m_dampingRatio; } + + /// Dump to b2Log + void Dump(); + +protected: + + friend class b2Joint; + + b2WeldJoint(const b2WeldJointDef* def); + + void InitVelocityConstraints(const b2SolverData& data); + void SolveVelocityConstraints(const b2SolverData& data); + bool SolvePositionConstraints(const b2SolverData& data); + + float32 m_frequencyHz; + float32 m_dampingRatio; + float32 m_bias; + + // Solver shared + b2Vec2 m_localAnchorA; + b2Vec2 m_localAnchorB; + float32 m_referenceAngle; + float32 m_gamma; + b2Vec3 m_impulse; + + // Solver temp + int32 m_indexA; + int32 m_indexB; + b2Vec2 m_rA; + b2Vec2 m_rB; + b2Vec2 m_localCenterA; + b2Vec2 m_localCenterB; + float32 m_invMassA; + float32 m_invMassB; + float32 m_invIA; + float32 m_invIB; + b2Mat33 m_mass; +}; + +#endif diff --git a/Lib/Include/Box2D/Dynamics/Joints/b2WheelJoint.h b/Lib/Include/Box2D/Dynamics/Joints/b2WheelJoint.h new file mode 100644 index 0000000..d7ebe13 --- /dev/null +++ b/Lib/Include/Box2D/Dynamics/Joints/b2WheelJoint.h @@ -0,0 +1,211 @@ +/* +* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org +* +* This software is provided 'as-is', without any express or implied +* warranty. In no event will the authors be held liable for any damages +* arising from the use of this software. +* Permission is granted to anyone to use this software for any purpose, +* including commercial applications, and to alter it and redistribute it +* freely, subject to the following restrictions: +* 1. The origin of this software must not be misrepresented; you must not +* claim that you wrote the original software. If you use this software +* in a product, an acknowledgment in the product documentation would be +* appreciated but is not required. +* 2. Altered source versions must be plainly marked as such, and must not be +* misrepresented as being the original software. +* 3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef B2_WHEEL_JOINT_H +#define B2_WHEEL_JOINT_H + +#include + +/// Wheel joint definition. This requires defining a line of +/// motion using an axis and an anchor point. The definition uses local +/// anchor points and a local axis so that the initial configuration +/// can violate the constraint slightly. The joint translation is zero +/// when the local anchor points coincide in world space. Using local +/// anchors and a local axis helps when saving and loading a game. +struct BOX2D_API b2WheelJointDef : public b2JointDef +{ + b2WheelJointDef() + { + type = e_wheelJoint; + localAnchorA.SetZero(); + localAnchorB.SetZero(); + localAxisA.Set(1.0f, 0.0f); + enableMotor = false; + maxMotorTorque = 0.0f; + motorSpeed = 0.0f; + frequencyHz = 2.0f; + dampingRatio = 0.7f; + } + + /// Initialize the bodies, anchors, axis, and reference angle using the world + /// anchor and world axis. + void Initialize(b2Body* bodyA, b2Body* bodyB, const b2Vec2& anchor, const b2Vec2& axis); + + /// The local anchor point relative to bodyA's origin. + b2Vec2 localAnchorA; + + /// The local anchor point relative to bodyB's origin. + b2Vec2 localAnchorB; + + /// The local translation axis in bodyA. + b2Vec2 localAxisA; + + /// Enable/disable the joint motor. + bool enableMotor; + + /// The maximum motor torque, usually in N-m. + float32 maxMotorTorque; + + /// The desired motor speed in radians per second. + float32 motorSpeed; + + /// Suspension frequency, zero indicates no suspension + float32 frequencyHz; + + /// Suspension damping ratio, one indicates critical damping + float32 dampingRatio; +}; + +/// A wheel joint. This joint provides two degrees of freedom: translation +/// along an axis fixed in bodyA and rotation in the plane. You can use a +/// joint limit to restrict the range of motion and a joint motor to drive +/// the rotation or to model rotational friction. +/// This joint is designed for vehicle suspensions. +class BOX2D_API b2WheelJoint : public b2Joint +{ +public: + b2Vec2 GetAnchorA() const; + b2Vec2 GetAnchorB() const; + + b2Vec2 GetReactionForce(float32 inv_dt) const; + float32 GetReactionTorque(float32 inv_dt) const; + + /// The local anchor point relative to bodyA's origin. + const b2Vec2& GetLocalAnchorA() const { return m_localAnchorA; } + + /// The local anchor point relative to bodyB's origin. + const b2Vec2& GetLocalAnchorB() const { return m_localAnchorB; } + + /// The local joint axis relative to bodyA. + const b2Vec2& GetLocalAxisA() const { return m_localXAxisA; } + + /// Get the current joint translation, usually in meters. + float32 GetJointTranslation() const; + + /// Get the current joint translation speed, usually in meters per second. + float32 GetJointSpeed() const; + + /// Is the joint motor enabled? + bool IsMotorEnabled() const; + + /// Enable/disable the joint motor. + void EnableMotor(bool flag); + + /// Set the motor speed, usually in radians per second. + void SetMotorSpeed(float32 speed); + + /// Get the motor speed, usually in radians per second. + float32 GetMotorSpeed() const; + + /// Set/Get the maximum motor force, usually in N-m. + void SetMaxMotorTorque(float32 torque); + float32 GetMaxMotorTorque() const; + + /// Get the current motor torque given the inverse time step, usually in N-m. + float32 GetMotorTorque(float32 inv_dt) const; + + /// Set/Get the spring frequency in hertz. Setting the frequency to zero disables the spring. + void SetSpringFrequencyHz(float32 hz); + float32 GetSpringFrequencyHz() const; + + /// Set/Get the spring damping ratio + void SetSpringDampingRatio(float32 ratio); + float32 GetSpringDampingRatio() const; + + /// Dump to b2Log + void Dump(); + +protected: + + friend class b2Joint; + b2WheelJoint(const b2WheelJointDef* def); + + void InitVelocityConstraints(const b2SolverData& data); + void SolveVelocityConstraints(const b2SolverData& data); + bool SolvePositionConstraints(const b2SolverData& data); + + float32 m_frequencyHz; + float32 m_dampingRatio; + + // Solver shared + b2Vec2 m_localAnchorA; + b2Vec2 m_localAnchorB; + b2Vec2 m_localXAxisA; + b2Vec2 m_localYAxisA; + + float32 m_impulse; + float32 m_motorImpulse; + float32 m_springImpulse; + + float32 m_maxMotorTorque; + float32 m_motorSpeed; + bool m_enableMotor; + + // Solver temp + int32 m_indexA; + int32 m_indexB; + b2Vec2 m_localCenterA; + b2Vec2 m_localCenterB; + float32 m_invMassA; + float32 m_invMassB; + float32 m_invIA; + float32 m_invIB; + + b2Vec2 m_ax, m_ay; + float32 m_sAx, m_sBx; + float32 m_sAy, m_sBy; + + float32 m_mass; + float32 m_motorMass; + float32 m_springMass; + + float32 m_bias; + float32 m_gamma; +}; + +inline float32 b2WheelJoint::GetMotorSpeed() const +{ + return m_motorSpeed; +} + +inline float32 b2WheelJoint::GetMaxMotorTorque() const +{ + return m_maxMotorTorque; +} + +inline void b2WheelJoint::SetSpringFrequencyHz(float32 hz) +{ + m_frequencyHz = hz; +} + +inline float32 b2WheelJoint::GetSpringFrequencyHz() const +{ + return m_frequencyHz; +} + +inline void b2WheelJoint::SetSpringDampingRatio(float32 ratio) +{ + m_dampingRatio = ratio; +} + +inline float32 b2WheelJoint::GetSpringDampingRatio() const +{ + return m_dampingRatio; +} + +#endif diff --git a/Lib/Include/Box2D/Dynamics/b2Body.h b/Lib/Include/Box2D/Dynamics/b2Body.h new file mode 100644 index 0000000..27fe561 --- /dev/null +++ b/Lib/Include/Box2D/Dynamics/b2Body.h @@ -0,0 +1,859 @@ +/* +* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org +* +* This software is provided 'as-is', without any express or implied +* warranty. In no event will the authors be held liable for any damages +* arising from the use of this software. +* Permission is granted to anyone to use this software for any purpose, +* including commercial applications, and to alter it and redistribute it +* freely, subject to the following restrictions: +* 1. The origin of this software must not be misrepresented; you must not +* claim that you wrote the original software. If you use this software +* in a product, an acknowledgment in the product documentation would be +* appreciated but is not required. +* 2. Altered source versions must be plainly marked as such, and must not be +* misrepresented as being the original software. +* 3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef B2_BODY_H +#define B2_BODY_H + +#include +#include +#include + +class b2Fixture; +class b2Joint; +class b2Contact; +class b2Controller; +class b2World; +struct b2FixtureDef; +struct b2JointEdge; +struct b2ContactEdge; + +/// The body type. +/// static: zero mass, zero velocity, may be manually moved +/// kinematic: zero mass, non-zero velocity set by user, moved by solver +/// dynamic: positive mass, non-zero velocity determined by forces, moved by solver +enum b2BodyType +{ + b2_staticBody = 0, + b2_kinematicBody, + b2_dynamicBody + + // TODO_ERIN + //b2_bulletBody, +}; + +/// A body definition holds all the data needed to construct a rigid body. +/// You can safely re-use body definitions. Shapes are added to a body after construction. +struct b2BodyDef +{ + /// This constructor sets the body definition default values. + b2BodyDef() + { + userData = NULL; + position.Set(0.0f, 0.0f); + angle = 0.0f; + linearVelocity.Set(0.0f, 0.0f); + angularVelocity = 0.0f; + linearDamping = 0.0f; + angularDamping = 0.0f; + allowSleep = true; + awake = true; + fixedRotation = false; + bullet = false; + type = b2_staticBody; + active = true; + gravityScale = 1.0f; + } + /// Use this to store application specific body data. + void* userData; + + /// The body type: static, kinematic, or dynamic. + /// Note: if a dynamic body would have zero mass, the mass is set to one. + b2BodyType type; + + /// The world position of the body. Avoid creating bodies at the origin + /// since this can lead to many overlapping shapes. + b2Vec2 position; + + /// The world angle of the body in radians. + float32 angle; + + /// The linear velocity of the body's origin in world co-ordinates. + b2Vec2 linearVelocity; + + /// The angular velocity of the body. + float32 angularVelocity; + + /// Linear damping is use to reduce the linear velocity. The damping parameter + /// can be larger than 1.0f but the damping effect becomes sensitive to the + /// time step when the damping parameter is large. + float32 linearDamping; + + /// Angular damping is use to reduce the angular velocity. The damping parameter + /// can be larger than 1.0f but the damping effect becomes sensitive to the + /// time step when the damping parameter is large. + float32 angularDamping; + + /// Scale the gravity applied to this body. + float32 gravityScale; + + /// Set this flag to false if this body should never fall asleep. Note that + /// this increases CPU usage. + bool allowSleep; + + /// Is this body initially awake or sleeping? + bool awake; + + /// Should this body be prevented from rotating? Useful for characters. + bool fixedRotation; + + /// Is this a fast moving body that should be prevented from tunneling through + /// other moving bodies? Note that all bodies are prevented from tunneling through + /// kinematic and static bodies. This setting is only considered on dynamic bodies. + /// @warning You should use this flag sparingly since it increases processing time. + bool bullet; + + /// Does this body start out active? + bool active; +}; + +/// A rigid body. These are created via b2World::CreateBody. +class BOX2D_API b2Body +{ +public: + /// Creates a fixture and attach it to this body. Use this function if you need + /// to set some fixture parameters, like friction. Otherwise you can create the + /// fixture directly from a shape. + /// If the density is non-zero, this function automatically updates the mass of the body. + /// Contacts are not created until the next time step. + /// @param def the fixture definition. + /// @warning This function is locked during callbacks. + b2Fixture* CreateFixture(const b2FixtureDef* def); + + /// Creates a fixture from a shape and attach it to this body. + /// This is a convenience function. Use b2FixtureDef if you need to set parameters + /// like friction, restitution, user data, or filtering. + /// If the density is non-zero, this function automatically updates the mass of the body. + /// @param shape the shape to be cloned. + /// @param density the shape density (set to zero for static bodies). + /// @warning This function is locked during callbacks. + b2Fixture* CreateFixture(const b2Shape* shape, float32 density); + + /// Destroy a fixture. This removes the fixture from the broad-phase and + /// destroys all contacts associated with this fixture. This will + /// automatically adjust the mass of the body if the body is dynamic and the + /// fixture has positive density. + /// All fixtures attached to a body are implicitly destroyed when the body is destroyed. + /// @param fixture the fixture to be removed. + /// @warning This function is locked during callbacks. + void DestroyFixture(b2Fixture* fixture); + + /// Set the position of the body's origin and rotation. + /// Manipulating a body's transform may cause non-physical behavior. + /// Note: contacts are updated on the next call to b2World::Step. + /// @param position the world position of the body's local origin. + /// @param angle the world rotation in radians. + void SetTransform(const b2Vec2& position, float32 angle); + + /// Get the body transform for the body's origin. + /// @return the world transform of the body's origin. + const b2Transform& GetTransform() const; + + /// Get the world body origin position. + /// @return the world position of the body's origin. + const b2Vec2& GetPosition() const; + + /// Get the angle in radians. + /// @return the current world rotation angle in radians. + float32 GetAngle() const; + + /// Get the world position of the center of mass. + const b2Vec2& GetWorldCenter() const; + + /// Get the local position of the center of mass. + const b2Vec2& GetLocalCenter() const; + + /// Set the linear velocity of the center of mass. + /// @param v the new linear velocity of the center of mass. + void SetLinearVelocity(const b2Vec2& v); + + /// Get the linear velocity of the center of mass. + /// @return the linear velocity of the center of mass. + const b2Vec2& GetLinearVelocity() const; + + /// Set the angular velocity. + /// @param omega the new angular velocity in radians/second. + void SetAngularVelocity(float32 omega); + + /// Get the angular velocity. + /// @return the angular velocity in radians/second. + float32 GetAngularVelocity() const; + + /// Apply a force at a world point. If the force is not + /// applied at the center of mass, it will generate a torque and + /// affect the angular velocity. This wakes up the body. + /// @param force the world force vector, usually in Newtons (N). + /// @param point the world position of the point of application. + /// @param wake also wake up the body + void ApplyForce(const b2Vec2& force, const b2Vec2& point, bool wake); + + /// Apply a force to the center of mass. This wakes up the body. + /// @param force the world force vector, usually in Newtons (N). + /// @param wake also wake up the body + void ApplyForceToCenter(const b2Vec2& force, bool wake); + + /// Apply a torque. This affects the angular velocity + /// without affecting the linear velocity of the center of mass. + /// This wakes up the body. + /// @param torque about the z-axis (out of the screen), usually in N-m. + /// @param wake also wake up the body + void ApplyTorque(float32 torque, bool wake); + + /// Apply an impulse at a point. This immediately modifies the velocity. + /// It also modifies the angular velocity if the point of application + /// is not at the center of mass. This wakes up the body. + /// @param impulse the world impulse vector, usually in N-seconds or kg-m/s. + /// @param point the world position of the point of application. + /// @param wake also wake up the body + void ApplyLinearImpulse(const b2Vec2& impulse, const b2Vec2& point, bool wake); + + /// Apply an angular impulse. + /// @param impulse the angular impulse in units of kg*m*m/s + /// @param wake also wake up the body + void ApplyAngularImpulse(float32 impulse, bool wake); + + /// Get the total mass of the body. + /// @return the mass, usually in kilograms (kg). + float32 GetMass() const; + + /// Get the rotational inertia of the body about the local origin. + /// @return the rotational inertia, usually in kg-m^2. + float32 GetInertia() const; + + /// Get the mass data of the body. + /// @return a struct containing the mass, inertia and center of the body. + void GetMassData(b2MassData* data) const; + + /// Set the mass properties to override the mass properties of the fixtures. + /// Note that this changes the center of mass position. + /// Note that creating or destroying fixtures can also alter the mass. + /// This function has no effect if the body isn't dynamic. + /// @param massData the mass properties. + void SetMassData(const b2MassData* data); + + /// This resets the mass properties to the sum of the mass properties of the fixtures. + /// This normally does not need to be called unless you called SetMassData to override + /// the mass and you later want to reset the mass. + void ResetMassData(); + + /// Get the world coordinates of a point given the local coordinates. + /// @param localPoint a point on the body measured relative the the body's origin. + /// @return the same point expressed in world coordinates. + b2Vec2 GetWorldPoint(const b2Vec2& localPoint) const; + + /// Get the world coordinates of a vector given the local coordinates. + /// @param localVector a vector fixed in the body. + /// @return the same vector expressed in world coordinates. + b2Vec2 GetWorldVector(const b2Vec2& localVector) const; + + /// Gets a local point relative to the body's origin given a world point. + /// @param a point in world coordinates. + /// @return the corresponding local point relative to the body's origin. + b2Vec2 GetLocalPoint(const b2Vec2& worldPoint) const; + + /// Gets a local vector given a world vector. + /// @param a vector in world coordinates. + /// @return the corresponding local vector. + b2Vec2 GetLocalVector(const b2Vec2& worldVector) const; + + /// Get the world linear velocity of a world point attached to this body. + /// @param a point in world coordinates. + /// @return the world velocity of a point. + b2Vec2 GetLinearVelocityFromWorldPoint(const b2Vec2& worldPoint) const; + + /// Get the world velocity of a local point. + /// @param a point in local coordinates. + /// @return the world velocity of a point. + b2Vec2 GetLinearVelocityFromLocalPoint(const b2Vec2& localPoint) const; + + /// Get the linear damping of the body. + float32 GetLinearDamping() const; + + /// Set the linear damping of the body. + void SetLinearDamping(float32 linearDamping); + + /// Get the angular damping of the body. + float32 GetAngularDamping() const; + + /// Set the angular damping of the body. + void SetAngularDamping(float32 angularDamping); + + /// Get the gravity scale of the body. + float32 GetGravityScale() const; + + /// Set the gravity scale of the body. + void SetGravityScale(float32 scale); + + /// Set the type of this body. This may alter the mass and velocity. + void SetType(b2BodyType type); + + /// Get the type of this body. + b2BodyType GetType() const; + + /// Should this body be treated like a bullet for continuous collision detection? + void SetBullet(bool flag); + + /// Is this body treated like a bullet for continuous collision detection? + bool IsBullet() const; + + /// You can disable sleeping on this body. If you disable sleeping, the + /// body will be woken. + void SetSleepingAllowed(bool flag); + + /// Is this body allowed to sleep + bool IsSleepingAllowed() const; + + /// Set the sleep state of the body. A sleeping body has very + /// low CPU cost. + /// @param flag set to true to wake the body, false to put it to sleep. + void SetAwake(bool flag); + + /// Get the sleeping state of this body. + /// @return true if the body is awake. + bool IsAwake() const; + + /// Set the active state of the body. An inactive body is not + /// simulated and cannot be collided with or woken up. + /// If you pass a flag of true, all fixtures will be added to the + /// broad-phase. + /// If you pass a flag of false, all fixtures will be removed from + /// the broad-phase and all contacts will be destroyed. + /// Fixtures and joints are otherwise unaffected. You may continue + /// to create/destroy fixtures and joints on inactive bodies. + /// Fixtures on an inactive body are implicitly inactive and will + /// not participate in collisions, ray-casts, or queries. + /// Joints connected to an inactive body are implicitly inactive. + /// An inactive body is still owned by a b2World object and remains + /// in the body list. + void SetActive(bool flag); + + /// Get the active state of the body. + bool IsActive() const; + + /// Set this body to have fixed rotation. This causes the mass + /// to be reset. + void SetFixedRotation(bool flag); + + /// Does this body have fixed rotation? + bool IsFixedRotation() const; + + /// Get the list of all fixtures attached to this body. + b2Fixture* GetFixtureList(); + const b2Fixture* GetFixtureList() const; + + /// Get the list of all joints attached to this body. + b2JointEdge* GetJointList(); + const b2JointEdge* GetJointList() const; + + /// Get the list of all contacts attached to this body. + /// @warning this list changes during the time step and you may + /// miss some collisions if you don't use b2ContactListener. + b2ContactEdge* GetContactList(); + const b2ContactEdge* GetContactList() const; + + /// Get the next body in the world's body list. + b2Body* GetNext(); + const b2Body* GetNext() const; + + /// Get the user data pointer that was provided in the body definition. + void* GetUserData() const; + + /// Set the user data. Use this to store your application specific data. + void SetUserData(void* data); + + /// Get the parent world of this body. + b2World* GetWorld(); + const b2World* GetWorld() const; + + /// Dump this body to a log file + void Dump(); + +private: + + friend class b2World; + friend class b2Island; + friend class b2ContactManager; + friend class b2ContactSolver; + friend class b2Contact; + + friend class b2DistanceJoint; + friend class b2FrictionJoint; + friend class b2GearJoint; + friend class b2MotorJoint; + friend class b2MouseJoint; + friend class b2PrismaticJoint; + friend class b2PulleyJoint; + friend class b2RevoluteJoint; + friend class b2RopeJoint; + friend class b2WeldJoint; + friend class b2WheelJoint; + + // m_flags + enum + { + e_islandFlag = 0x0001, + e_awakeFlag = 0x0002, + e_autoSleepFlag = 0x0004, + e_bulletFlag = 0x0008, + e_fixedRotationFlag = 0x0010, + e_activeFlag = 0x0020, + e_toiFlag = 0x0040 + }; + + b2Body(const b2BodyDef* bd, b2World* world); + ~b2Body(); + + void SynchronizeFixtures(); + void SynchronizeTransform(); + + // This is used to prevent connected bodies from colliding. + // It may lie, depending on the collideConnected flag. + bool ShouldCollide(const b2Body* other) const; + + void Advance(float32 t); + + b2BodyType m_type; + + uint16 m_flags; + + int32 m_islandIndex; + + b2Transform m_xf; // the body origin transform + b2Sweep m_sweep; // the swept motion for CCD + + b2Vec2 m_linearVelocity; + float32 m_angularVelocity; + + b2Vec2 m_force; + float32 m_torque; + + b2World* m_world; + b2Body* m_prev; + b2Body* m_next; + + b2Fixture* m_fixtureList; + int32 m_fixtureCount; + + b2JointEdge* m_jointList; + b2ContactEdge* m_contactList; + + float32 m_mass, m_invMass; + + // Rotational inertia about the center of mass. + float32 m_I, m_invI; + + float32 m_linearDamping; + float32 m_angularDamping; + float32 m_gravityScale; + + float32 m_sleepTime; + + void* m_userData; +}; + +inline b2BodyType b2Body::GetType() const +{ + return m_type; +} + +inline const b2Transform& b2Body::GetTransform() const +{ + return m_xf; +} + +inline const b2Vec2& b2Body::GetPosition() const +{ + return m_xf.p; +} + +inline float32 b2Body::GetAngle() const +{ + return m_sweep.a; +} + +inline const b2Vec2& b2Body::GetWorldCenter() const +{ + return m_sweep.c; +} + +inline const b2Vec2& b2Body::GetLocalCenter() const +{ + return m_sweep.localCenter; +} + +inline void b2Body::SetLinearVelocity(const b2Vec2& v) +{ + if (m_type == b2_staticBody) + { + return; + } + + if (b2Dot(v,v) > 0.0f) + { + SetAwake(true); + } + + m_linearVelocity = v; +} + +inline const b2Vec2& b2Body::GetLinearVelocity() const +{ + return m_linearVelocity; +} + +inline void b2Body::SetAngularVelocity(float32 w) +{ + if (m_type == b2_staticBody) + { + return; + } + + if (w * w > 0.0f) + { + SetAwake(true); + } + + m_angularVelocity = w; +} + +inline float32 b2Body::GetAngularVelocity() const +{ + return m_angularVelocity; +} + +inline float32 b2Body::GetMass() const +{ + return m_mass; +} + +inline float32 b2Body::GetInertia() const +{ + return m_I + m_mass * b2Dot(m_sweep.localCenter, m_sweep.localCenter); +} + +inline void b2Body::GetMassData(b2MassData* data) const +{ + data->mass = m_mass; + data->I = m_I + m_mass * b2Dot(m_sweep.localCenter, m_sweep.localCenter); + data->center = m_sweep.localCenter; +} + +inline b2Vec2 b2Body::GetWorldPoint(const b2Vec2& localPoint) const +{ + return b2Mul(m_xf, localPoint); +} + +inline b2Vec2 b2Body::GetWorldVector(const b2Vec2& localVector) const +{ + return b2Mul(m_xf.q, localVector); +} + +inline b2Vec2 b2Body::GetLocalPoint(const b2Vec2& worldPoint) const +{ + return b2MulT(m_xf, worldPoint); +} + +inline b2Vec2 b2Body::GetLocalVector(const b2Vec2& worldVector) const +{ + return b2MulT(m_xf.q, worldVector); +} + +inline b2Vec2 b2Body::GetLinearVelocityFromWorldPoint(const b2Vec2& worldPoint) const +{ + return m_linearVelocity + b2Cross(m_angularVelocity, worldPoint - m_sweep.c); +} + +inline b2Vec2 b2Body::GetLinearVelocityFromLocalPoint(const b2Vec2& localPoint) const +{ + return GetLinearVelocityFromWorldPoint(GetWorldPoint(localPoint)); +} + +inline float32 b2Body::GetLinearDamping() const +{ + return m_linearDamping; +} + +inline void b2Body::SetLinearDamping(float32 linearDamping) +{ + m_linearDamping = linearDamping; +} + +inline float32 b2Body::GetAngularDamping() const +{ + return m_angularDamping; +} + +inline void b2Body::SetAngularDamping(float32 angularDamping) +{ + m_angularDamping = angularDamping; +} + +inline float32 b2Body::GetGravityScale() const +{ + return m_gravityScale; +} + +inline void b2Body::SetGravityScale(float32 scale) +{ + m_gravityScale = scale; +} + +inline void b2Body::SetBullet(bool flag) +{ + if (flag) + { + m_flags |= e_bulletFlag; + } + else + { + m_flags &= ~e_bulletFlag; + } +} + +inline bool b2Body::IsBullet() const +{ + return (m_flags & e_bulletFlag) == e_bulletFlag; +} + +inline void b2Body::SetAwake(bool flag) +{ + if (flag) + { + if ((m_flags & e_awakeFlag) == 0) + { + m_flags |= e_awakeFlag; + m_sleepTime = 0.0f; + } + } + else + { + m_flags &= ~e_awakeFlag; + m_sleepTime = 0.0f; + m_linearVelocity.SetZero(); + m_angularVelocity = 0.0f; + m_force.SetZero(); + m_torque = 0.0f; + } +} + +inline bool b2Body::IsAwake() const +{ + return (m_flags & e_awakeFlag) == e_awakeFlag; +} + +inline bool b2Body::IsActive() const +{ + return (m_flags & e_activeFlag) == e_activeFlag; +} + +inline bool b2Body::IsFixedRotation() const +{ + return (m_flags & e_fixedRotationFlag) == e_fixedRotationFlag; +} + +inline void b2Body::SetSleepingAllowed(bool flag) +{ + if (flag) + { + m_flags |= e_autoSleepFlag; + } + else + { + m_flags &= ~e_autoSleepFlag; + SetAwake(true); + } +} + +inline bool b2Body::IsSleepingAllowed() const +{ + return (m_flags & e_autoSleepFlag) == e_autoSleepFlag; +} + +inline b2Fixture* b2Body::GetFixtureList() +{ + return m_fixtureList; +} + +inline const b2Fixture* b2Body::GetFixtureList() const +{ + return m_fixtureList; +} + +inline b2JointEdge* b2Body::GetJointList() +{ + return m_jointList; +} + +inline const b2JointEdge* b2Body::GetJointList() const +{ + return m_jointList; +} + +inline b2ContactEdge* b2Body::GetContactList() +{ + return m_contactList; +} + +inline const b2ContactEdge* b2Body::GetContactList() const +{ + return m_contactList; +} + +inline b2Body* b2Body::GetNext() +{ + return m_next; +} + +inline const b2Body* b2Body::GetNext() const +{ + return m_next; +} + +inline void b2Body::SetUserData(void* data) +{ + m_userData = data; +} + +inline void* b2Body::GetUserData() const +{ + return m_userData; +} + +inline void b2Body::ApplyForce(const b2Vec2& force, const b2Vec2& point, bool wake) +{ + if (m_type != b2_dynamicBody) + { + return; + } + + if (wake && (m_flags & e_awakeFlag) == 0) + { + SetAwake(true); + } + + // Don't accumulate a force if the body is sleeping. + if (m_flags & e_awakeFlag) + { + m_force += force; + m_torque += b2Cross(point - m_sweep.c, force); + } +} + +inline void b2Body::ApplyForceToCenter(const b2Vec2& force, bool wake) +{ + if (m_type != b2_dynamicBody) + { + return; + } + + if (wake && (m_flags & e_awakeFlag) == 0) + { + SetAwake(true); + } + + // Don't accumulate a force if the body is sleeping + if (m_flags & e_awakeFlag) + { + m_force += force; + } +} + +inline void b2Body::ApplyTorque(float32 torque, bool wake) +{ + if (m_type != b2_dynamicBody) + { + return; + } + + if (wake && (m_flags & e_awakeFlag) == 0) + { + SetAwake(true); + } + + // Don't accumulate a force if the body is sleeping + if (m_flags & e_awakeFlag) + { + m_torque += torque; + } +} + +inline void b2Body::ApplyLinearImpulse(const b2Vec2& impulse, const b2Vec2& point, bool wake) +{ + if (m_type != b2_dynamicBody) + { + return; + } + + if (wake && (m_flags & e_awakeFlag) == 0) + { + SetAwake(true); + } + + // Don't accumulate velocity if the body is sleeping + if (m_flags & e_awakeFlag) + { + m_linearVelocity += m_invMass * impulse; + m_angularVelocity += m_invI * b2Cross(point - m_sweep.c, impulse); + } +} + +inline void b2Body::ApplyAngularImpulse(float32 impulse, bool wake) +{ + if (m_type != b2_dynamicBody) + { + return; + } + + if (wake && (m_flags & e_awakeFlag) == 0) + { + SetAwake(true); + } + + // Don't accumulate velocity if the body is sleeping + if (m_flags & e_awakeFlag) + { + m_angularVelocity += m_invI * impulse; + } +} + +inline void b2Body::SynchronizeTransform() +{ + m_xf.q.Set(m_sweep.a); + m_xf.p = m_sweep.c - b2Mul(m_xf.q, m_sweep.localCenter); +} + +inline void b2Body::Advance(float32 alpha) +{ + // Advance to the new safe time. This doesn't sync the broad-phase. + m_sweep.Advance(alpha); + m_sweep.c = m_sweep.c0; + m_sweep.a = m_sweep.a0; + m_xf.q.Set(m_sweep.a); + m_xf.p = m_sweep.c - b2Mul(m_xf.q, m_sweep.localCenter); +} + +inline b2World* b2Body::GetWorld() +{ + return m_world; +} + +inline const b2World* b2Body::GetWorld() const +{ + return m_world; +} + +#endif diff --git a/Lib/Include/Box2D/Dynamics/b2ContactManager.h b/Lib/Include/Box2D/Dynamics/b2ContactManager.h new file mode 100644 index 0000000..f4dd1e4 --- /dev/null +++ b/Lib/Include/Box2D/Dynamics/b2ContactManager.h @@ -0,0 +1,52 @@ +/* +* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org +* +* This software is provided 'as-is', without any express or implied +* warranty. In no event will the authors be held liable for any damages +* arising from the use of this software. +* Permission is granted to anyone to use this software for any purpose, +* including commercial applications, and to alter it and redistribute it +* freely, subject to the following restrictions: +* 1. The origin of this software must not be misrepresented; you must not +* claim that you wrote the original software. If you use this software +* in a product, an acknowledgment in the product documentation would be +* appreciated but is not required. +* 2. Altered source versions must be plainly marked as such, and must not be +* misrepresented as being the original software. +* 3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef B2_CONTACT_MANAGER_H +#define B2_CONTACT_MANAGER_H + +#include + +class b2Contact; +class b2ContactFilter; +class b2ContactListener; +class b2BlockAllocator; + +// Delegate of b2World. +class BOX2D_API b2ContactManager +{ +public: + b2ContactManager(); + + // Broad-phase callback. + void AddPair(void* proxyUserDataA, void* proxyUserDataB); + + void FindNewContacts(); + + void Destroy(b2Contact* c); + + void Collide(); + + b2BroadPhase m_broadPhase; + b2Contact* m_contactList; + int32 m_contactCount; + b2ContactFilter* m_contactFilter; + b2ContactListener* m_contactListener; + b2BlockAllocator* m_allocator; +}; + +#endif diff --git a/Lib/Include/Box2D/Dynamics/b2Fixture.h b/Lib/Include/Box2D/Dynamics/b2Fixture.h new file mode 100644 index 0000000..7afd7a2 --- /dev/null +++ b/Lib/Include/Box2D/Dynamics/b2Fixture.h @@ -0,0 +1,345 @@ +/* +* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org +* +* This software is provided 'as-is', without any express or implied +* warranty. In no event will the authors be held liable for any damages +* arising from the use of this software. +* Permission is granted to anyone to use this software for any purpose, +* including commercial applications, and to alter it and redistribute it +* freely, subject to the following restrictions: +* 1. The origin of this software must not be misrepresented; you must not +* claim that you wrote the original software. If you use this software +* in a product, an acknowledgment in the product documentation would be +* appreciated but is not required. +* 2. Altered source versions must be plainly marked as such, and must not be +* misrepresented as being the original software. +* 3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef B2_FIXTURE_H +#define B2_FIXTURE_H + +#include +#include +#include + +class b2BlockAllocator; +class b2Body; +class b2BroadPhase; +class b2Fixture; + +/// This holds contact filtering data. +struct BOX2D_API b2Filter +{ + b2Filter() + { + categoryBits = 0x0001; + maskBits = 0xFFFF; + groupIndex = 0; + } + + /// The collision category bits. Normally you would just set one bit. + uint16 categoryBits; + + /// The collision mask bits. This states the categories that this + /// shape would accept for collision. + uint16 maskBits; + + /// Collision groups allow a certain group of objects to never collide (negative) + /// or always collide (positive). Zero means no collision group. Non-zero group + /// filtering always wins against the mask bits. + int16 groupIndex; +}; + +/// A fixture definition is used to create a fixture. This class defines an +/// abstract fixture definition. You can reuse fixture definitions safely. +struct b2FixtureDef +{ + /// The constructor sets the default fixture definition values. + b2FixtureDef() + { + shape = NULL; + userData = NULL; + friction = 0.2f; + restitution = 0.0f; + density = 0.0f; + isSensor = false; + } + + /// The shape, this must be set. The shape will be cloned, so you + /// can create the shape on the stack. + const b2Shape* shape; + + /// Use this to store application specific fixture data. + void* userData; + + /// The friction coefficient, usually in the range [0,1]. + float32 friction; + + /// The restitution (elasticity) usually in the range [0,1]. + float32 restitution; + + /// The density, usually in kg/m^2. + float32 density; + + /// A sensor shape collects contact information but never generates a collision + /// response. + bool isSensor; + + /// Contact filtering data. + b2Filter filter; +}; + +/// This proxy is used internally to connect fixtures to the broad-phase. +struct b2FixtureProxy +{ + b2AABB aabb; + b2Fixture* fixture; + int32 childIndex; + int32 proxyId; +}; + +/// A fixture is used to attach a shape to a body for collision detection. A fixture +/// inherits its transform from its parent. Fixtures hold additional non-geometric data +/// such as friction, collision filters, etc. +/// Fixtures are created via b2Body::CreateFixture. +/// @warning you cannot reuse fixtures. +class BOX2D_API b2Fixture +{ +public: + /// Get the type of the child shape. You can use this to down cast to the concrete shape. + /// @return the shape type. + b2Shape::Type GetType() const; + + /// Get the child shape. You can modify the child shape, however you should not change the + /// number of vertices because this will crash some collision caching mechanisms. + /// Manipulating the shape may lead to non-physical behavior. + b2Shape* GetShape(); + const b2Shape* GetShape() const; + + /// Set if this fixture is a sensor. + void SetSensor(bool sensor); + + /// Is this fixture a sensor (non-solid)? + /// @return the true if the shape is a sensor. + bool IsSensor() const; + + /// Set the contact filtering data. This will not update contacts until the next time + /// step when either parent body is active and awake. + /// This automatically calls Refilter. + void SetFilterData(const b2Filter& filter); + + /// Get the contact filtering data. + const b2Filter& GetFilterData() const; + + /// Call this if you want to establish collision that was previously disabled by b2ContactFilter::ShouldCollide. + void Refilter(); + + /// Get the parent body of this fixture. This is NULL if the fixture is not attached. + /// @return the parent body. + b2Body* GetBody(); + const b2Body* GetBody() const; + + /// Get the next fixture in the parent body's fixture list. + /// @return the next shape. + b2Fixture* GetNext(); + const b2Fixture* GetNext() const; + + /// Get the user data that was assigned in the fixture definition. Use this to + /// store your application specific data. + void* GetUserData() const; + + /// Set the user data. Use this to store your application specific data. + void SetUserData(void* data); + + /// Test a point for containment in this fixture. + /// @param p a point in world coordinates. + bool TestPoint(const b2Vec2& p) const; + + /// Cast a ray against this shape. + /// @param output the ray-cast results. + /// @param input the ray-cast input parameters. + bool RayCast(b2RayCastOutput* output, const b2RayCastInput& input, int32 childIndex) const; + + /// Get the mass data for this fixture. The mass data is based on the density and + /// the shape. The rotational inertia is about the shape's origin. This operation + /// may be expensive. + void GetMassData(b2MassData* massData) const; + + /// Set the density of this fixture. This will _not_ automatically adjust the mass + /// of the body. You must call b2Body::ResetMassData to update the body's mass. + void SetDensity(float32 density); + + /// Get the density of this fixture. + float32 GetDensity() const; + + /// Get the coefficient of friction. + float32 GetFriction() const; + + /// Set the coefficient of friction. This will _not_ change the friction of + /// existing contacts. + void SetFriction(float32 friction); + + /// Get the coefficient of restitution. + float32 GetRestitution() const; + + /// Set the coefficient of restitution. This will _not_ change the restitution of + /// existing contacts. + void SetRestitution(float32 restitution); + + /// Get the fixture's AABB. This AABB may be enlarge and/or stale. + /// If you need a more accurate AABB, compute it using the shape and + /// the body transform. + const b2AABB& GetAABB(int32 childIndex) const; + + /// Dump this fixture to the log file. + void Dump(int32 bodyIndex); + +protected: + + friend class b2Body; + friend class b2World; + friend class b2Contact; + friend class b2ContactManager; + + b2Fixture(); + + // We need separation create/destroy functions from the constructor/destructor because + // the destructor cannot access the allocator (no destructor arguments allowed by C++). + void Create(b2BlockAllocator* allocator, b2Body* body, const b2FixtureDef* def); + void Destroy(b2BlockAllocator* allocator); + + // These support body activation/deactivation. + void CreateProxies(b2BroadPhase* broadPhase, const b2Transform& xf); + void DestroyProxies(b2BroadPhase* broadPhase); + + void Synchronize(b2BroadPhase* broadPhase, const b2Transform& xf1, const b2Transform& xf2); + + float32 m_density; + + b2Fixture* m_next; + b2Body* m_body; + + b2Shape* m_shape; + + float32 m_friction; + float32 m_restitution; + + b2FixtureProxy* m_proxies; + int32 m_proxyCount; + + b2Filter m_filter; + + bool m_isSensor; + + void* m_userData; +}; + +inline b2Shape::Type b2Fixture::GetType() const +{ + return m_shape->GetType(); +} + +inline b2Shape* b2Fixture::GetShape() +{ + return m_shape; +} + +inline const b2Shape* b2Fixture::GetShape() const +{ + return m_shape; +} + +inline bool b2Fixture::IsSensor() const +{ + return m_isSensor; +} + +inline const b2Filter& b2Fixture::GetFilterData() const +{ + return m_filter; +} + +inline void* b2Fixture::GetUserData() const +{ + return m_userData; +} + +inline void b2Fixture::SetUserData(void* data) +{ + m_userData = data; +} + +inline b2Body* b2Fixture::GetBody() +{ + return m_body; +} + +inline const b2Body* b2Fixture::GetBody() const +{ + return m_body; +} + +inline b2Fixture* b2Fixture::GetNext() +{ + return m_next; +} + +inline const b2Fixture* b2Fixture::GetNext() const +{ + return m_next; +} + +inline void b2Fixture::SetDensity(float32 density) +{ + b2Assert(b2IsValid(density) && density >= 0.0f); + m_density = density; +} + +inline float32 b2Fixture::GetDensity() const +{ + return m_density; +} + +inline float32 b2Fixture::GetFriction() const +{ + return m_friction; +} + +inline void b2Fixture::SetFriction(float32 friction) +{ + m_friction = friction; +} + +inline float32 b2Fixture::GetRestitution() const +{ + return m_restitution; +} + +inline void b2Fixture::SetRestitution(float32 restitution) +{ + m_restitution = restitution; +} + +inline bool b2Fixture::TestPoint(const b2Vec2& p) const +{ + return m_shape->TestPoint(m_body->GetTransform(), p); +} + +inline bool b2Fixture::RayCast(b2RayCastOutput* output, const b2RayCastInput& input, int32 childIndex) const +{ + return m_shape->RayCast(output, input, m_body->GetTransform(), childIndex); +} + +inline void b2Fixture::GetMassData(b2MassData* massData) const +{ + m_shape->ComputeMass(massData, m_density); +} + +inline const b2AABB& b2Fixture::GetAABB(int32 childIndex) const +{ + b2Assert(0 <= childIndex && childIndex < m_proxyCount); + return m_proxies[childIndex].aabb; +} + +#endif diff --git a/Lib/Include/Box2D/Dynamics/b2Island.h b/Lib/Include/Box2D/Dynamics/b2Island.h new file mode 100644 index 0000000..4a814c4 --- /dev/null +++ b/Lib/Include/Box2D/Dynamics/b2Island.h @@ -0,0 +1,93 @@ +/* +* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org +* +* This software is provided 'as-is', without any express or implied +* warranty. In no event will the authors be held liable for any damages +* arising from the use of this software. +* Permission is granted to anyone to use this software for any purpose, +* including commercial applications, and to alter it and redistribute it +* freely, subject to the following restrictions: +* 1. The origin of this software must not be misrepresented; you must not +* claim that you wrote the original software. If you use this software +* in a product, an acknowledgment in the product documentation would be +* appreciated but is not required. +* 2. Altered source versions must be plainly marked as such, and must not be +* misrepresented as being the original software. +* 3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef B2_ISLAND_H +#define B2_ISLAND_H + +#include +#include +#include + +class b2Contact; +class b2Joint; +class b2StackAllocator; +class b2ContactListener; +struct b2ContactVelocityConstraint; +struct b2Profile; + +/// This is an internal class. +class b2Island +{ +public: + b2Island(int32 bodyCapacity, int32 contactCapacity, int32 jointCapacity, + b2StackAllocator* allocator, b2ContactListener* listener); + ~b2Island(); + + void Clear() + { + m_bodyCount = 0; + m_contactCount = 0; + m_jointCount = 0; + } + + void Solve(b2Profile* profile, const b2TimeStep& step, const b2Vec2& gravity, bool allowSleep); + + void SolveTOI(const b2TimeStep& subStep, int32 toiIndexA, int32 toiIndexB); + + void Add(b2Body* body) + { + b2Assert(m_bodyCount < m_bodyCapacity); + body->m_islandIndex = m_bodyCount; + m_bodies[m_bodyCount] = body; + ++m_bodyCount; + } + + void Add(b2Contact* contact) + { + b2Assert(m_contactCount < m_contactCapacity); + m_contacts[m_contactCount++] = contact; + } + + void Add(b2Joint* joint) + { + b2Assert(m_jointCount < m_jointCapacity); + m_joints[m_jointCount++] = joint; + } + + void Report(const b2ContactVelocityConstraint* constraints); + + b2StackAllocator* m_allocator; + b2ContactListener* m_listener; + + b2Body** m_bodies; + b2Contact** m_contacts; + b2Joint** m_joints; + + b2Position* m_positions; + b2Velocity* m_velocities; + + int32 m_bodyCount; + int32 m_jointCount; + int32 m_contactCount; + + int32 m_bodyCapacity; + int32 m_contactCapacity; + int32 m_jointCapacity; +}; + +#endif diff --git a/Lib/Include/Box2D/Dynamics/b2TimeStep.h b/Lib/Include/Box2D/Dynamics/b2TimeStep.h new file mode 100644 index 0000000..a372762 --- /dev/null +++ b/Lib/Include/Box2D/Dynamics/b2TimeStep.h @@ -0,0 +1,70 @@ +/* +* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org +* +* This software is provided 'as-is', without any express or implied +* warranty. In no event will the authors be held liable for any damages +* arising from the use of this software. +* Permission is granted to anyone to use this software for any purpose, +* including commercial applications, and to alter it and redistribute it +* freely, subject to the following restrictions: +* 1. The origin of this software must not be misrepresented; you must not +* claim that you wrote the original software. If you use this software +* in a product, an acknowledgment in the product documentation would be +* appreciated but is not required. +* 2. Altered source versions must be plainly marked as such, and must not be +* misrepresented as being the original software. +* 3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef B2_TIME_STEP_H +#define B2_TIME_STEP_H + +#include + +/// Profiling data. Times are in milliseconds. +struct b2Profile +{ + float32 step; + float32 collide; + float32 solve; + float32 solveInit; + float32 solveVelocity; + float32 solvePosition; + float32 broadphase; + float32 solveTOI; +}; + +/// This is an internal structure. +struct b2TimeStep +{ + float32 dt; // time step + float32 inv_dt; // inverse time step (0 if dt == 0). + float32 dtRatio; // dt * inv_dt0 + int32 velocityIterations; + int32 positionIterations; + bool warmStarting; +}; + +/// This is an internal structure. +struct b2Position +{ + b2Vec2 c; + float32 a; +}; + +/// This is an internal structure. +struct b2Velocity +{ + b2Vec2 v; + float32 w; +}; + +/// Solver Data +struct b2SolverData +{ + b2TimeStep step; + b2Position* positions; + b2Velocity* velocities; +}; + +#endif diff --git a/Lib/Include/Box2D/Dynamics/b2World.h b/Lib/Include/Box2D/Dynamics/b2World.h new file mode 100644 index 0000000..9e15e72 --- /dev/null +++ b/Lib/Include/Box2D/Dynamics/b2World.h @@ -0,0 +1,354 @@ +/* +* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org +* +* This software is provided 'as-is', without any express or implied +* warranty. In no event will the authors be held liable for any damages +* arising from the use of this software. +* Permission is granted to anyone to use this software for any purpose, +* including commercial applications, and to alter it and redistribute it +* freely, subject to the following restrictions: +* 1. The origin of this software must not be misrepresented; you must not +* claim that you wrote the original software. If you use this software +* in a product, an acknowledgment in the product documentation would be +* appreciated but is not required. +* 2. Altered source versions must be plainly marked as such, and must not be +* misrepresented as being the original software. +* 3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef B2_WORLD_H +#define B2_WORLD_H + +#include +#include +#include +#include +#include +#include + +struct b2AABB; +struct b2BodyDef; +struct b2Color; +struct b2JointDef; +class b2Body; +class b2Draw; +class b2Fixture; +class b2Joint; + +/// The world class manages all physics entities, dynamic simulation, +/// and asynchronous queries. The world also contains efficient memory +/// management facilities. +class BOX2D_API b2World +{ +public: + /// Construct a world object. + /// @param gravity the world gravity vector. + b2World(const b2Vec2& gravity); + + /// Destruct the world. All physics entities are destroyed and all heap memory is released. + ~b2World(); + + /// Register a destruction listener. The listener is owned by you and must + /// remain in scope. + void SetDestructionListener(b2DestructionListener* listener); + + /// Register a contact filter to provide specific control over collision. + /// Otherwise the default filter is used (b2_defaultFilter). The listener is + /// owned by you and must remain in scope. + void SetContactFilter(b2ContactFilter* filter); + + /// Register a contact event listener. The listener is owned by you and must + /// remain in scope. + void SetContactListener(b2ContactListener* listener); + + /// Register a routine for debug drawing. The debug draw functions are called + /// inside with b2World::DrawDebugData method. The debug draw object is owned + /// by you and must remain in scope. + void SetDebugDraw(b2Draw* debugDraw); + + /// Create a rigid body given a definition. No reference to the definition + /// is retained. + /// @warning This function is locked during callbacks. + b2Body* CreateBody(const b2BodyDef* def); + + /// Destroy a rigid body given a definition. No reference to the definition + /// is retained. This function is locked during callbacks. + /// @warning This automatically deletes all associated shapes and joints. + /// @warning This function is locked during callbacks. + void DestroyBody(b2Body* body); + + /// Create a joint to constrain bodies together. No reference to the definition + /// is retained. This may cause the connected bodies to cease colliding. + /// @warning This function is locked during callbacks. + b2Joint* CreateJoint(const b2JointDef* def); + + /// Destroy a joint. This may cause the connected bodies to begin colliding. + /// @warning This function is locked during callbacks. + void DestroyJoint(b2Joint* joint); + + /// Take a time step. This performs collision detection, integration, + /// and constraint solution. + /// @param timeStep the amount of time to simulate, this should not vary. + /// @param velocityIterations for the velocity constraint solver. + /// @param positionIterations for the position constraint solver. + void Step( float32 timeStep, + int32 velocityIterations, + int32 positionIterations); + + /// Manually clear the force buffer on all bodies. By default, forces are cleared automatically + /// after each call to Step. The default behavior is modified by calling SetAutoClearForces. + /// The purpose of this function is to support sub-stepping. Sub-stepping is often used to maintain + /// a fixed sized time step under a variable frame-rate. + /// When you perform sub-stepping you will disable auto clearing of forces and instead call + /// ClearForces after all sub-steps are complete in one pass of your game loop. + /// @see SetAutoClearForces + void ClearForces(); + + /// Call this to draw shapes and other debug draw data. This is intentionally non-const. + void DrawDebugData(); + + /// Query the world for all fixtures that potentially overlap the + /// provided AABB. + /// @param callback a user implemented callback class. + /// @param aabb the query box. + void QueryAABB(b2QueryCallback* callback, const b2AABB& aabb) const; + + /// Ray-cast the world for all fixtures in the path of the ray. Your callback + /// controls whether you get the closest point, any point, or n-points. + /// The ray-cast ignores shapes that contain the starting point. + /// @param callback a user implemented callback class. + /// @param point1 the ray starting point + /// @param point2 the ray ending point + void RayCast(b2RayCastCallback* callback, const b2Vec2& point1, const b2Vec2& point2) const; + + /// Get the world body list. With the returned body, use b2Body::GetNext to get + /// the next body in the world list. A NULL body indicates the end of the list. + /// @return the head of the world body list. + b2Body* GetBodyList(); + const b2Body* GetBodyList() const; + + /// Get the world joint list. With the returned joint, use b2Joint::GetNext to get + /// the next joint in the world list. A NULL joint indicates the end of the list. + /// @return the head of the world joint list. + b2Joint* GetJointList(); + const b2Joint* GetJointList() const; + + /// Get the world contact list. With the returned contact, use b2Contact::GetNext to get + /// the next contact in the world list. A NULL contact indicates the end of the list. + /// @return the head of the world contact list. + /// @warning contacts are created and destroyed in the middle of a time step. + /// Use b2ContactListener to avoid missing contacts. + b2Contact* GetContactList(); + const b2Contact* GetContactList() const; + + /// Enable/disable sleep. + void SetAllowSleeping(bool flag); + bool GetAllowSleeping() const { return m_allowSleep; } + + /// Enable/disable warm starting. For testing. + void SetWarmStarting(bool flag) { m_warmStarting = flag; } + bool GetWarmStarting() const { return m_warmStarting; } + + /// Enable/disable continuous physics. For testing. + void SetContinuousPhysics(bool flag) { m_continuousPhysics = flag; } + bool GetContinuousPhysics() const { return m_continuousPhysics; } + + /// Enable/disable single stepped continuous physics. For testing. + void SetSubStepping(bool flag) { m_subStepping = flag; } + bool GetSubStepping() const { return m_subStepping; } + + /// Get the number of broad-phase proxies. + int32 GetProxyCount() const; + + /// Get the number of bodies. + int32 GetBodyCount() const; + + /// Get the number of joints. + int32 GetJointCount() const; + + /// Get the number of contacts (each may have 0 or more contact points). + int32 GetContactCount() const; + + /// Get the height of the dynamic tree. + int32 GetTreeHeight() const; + + /// Get the balance of the dynamic tree. + int32 GetTreeBalance() const; + + /// Get the quality metric of the dynamic tree. The smaller the better. + /// The minimum is 1. + float32 GetTreeQuality() const; + + /// Change the global gravity vector. + void SetGravity(const b2Vec2& gravity); + + /// Get the global gravity vector. + b2Vec2 GetGravity() const; + + /// Is the world locked (in the middle of a time step). + bool IsLocked() const; + + /// Set flag to control automatic clearing of forces after each time step. + void SetAutoClearForces(bool flag); + + /// Get the flag that controls automatic clearing of forces after each time step. + bool GetAutoClearForces() const; + + /// Shift the world origin. Useful for large worlds. + /// The body shift formula is: position -= newOrigin + /// @param newOrigin the new origin with respect to the old origin + void ShiftOrigin(const b2Vec2& newOrigin); + + /// Get the contact manager for testing. + const b2ContactManager& GetContactManager() const; + + /// Get the current profile. + const b2Profile& GetProfile() const; + + /// Dump the world into the log file. + /// @warning this should be called outside of a time step. + void Dump(); + +private: + + // m_flags + enum + { + e_newFixture = 0x0001, + e_locked = 0x0002, + e_clearForces = 0x0004 + }; + + friend class b2Body; + friend class b2Fixture; + friend class b2ContactManager; + friend class b2Controller; + + void Solve(const b2TimeStep& step); + void SolveTOI(const b2TimeStep& step); + + void DrawJoint(b2Joint* joint); + void DrawShape(b2Fixture* shape, const b2Transform& xf, const b2Color& color); + + b2BlockAllocator m_blockAllocator; + b2StackAllocator m_stackAllocator; + + int32 m_flags; + + b2ContactManager m_contactManager; + + b2Body* m_bodyList; + b2Joint* m_jointList; + + int32 m_bodyCount; + int32 m_jointCount; + + b2Vec2 m_gravity; + bool m_allowSleep; + + b2DestructionListener* m_destructionListener; + b2Draw* m_debugDraw; + + // This is used to compute the time step ratio to + // support a variable time step. + float32 m_inv_dt0; + + // These are for debugging the solver. + bool m_warmStarting; + bool m_continuousPhysics; + bool m_subStepping; + + bool m_stepComplete; + + b2Profile m_profile; +}; + +inline b2Body* b2World::GetBodyList() +{ + return m_bodyList; +} + +inline const b2Body* b2World::GetBodyList() const +{ + return m_bodyList; +} + +inline b2Joint* b2World::GetJointList() +{ + return m_jointList; +} + +inline const b2Joint* b2World::GetJointList() const +{ + return m_jointList; +} + +inline b2Contact* b2World::GetContactList() +{ + return m_contactManager.m_contactList; +} + +inline const b2Contact* b2World::GetContactList() const +{ + return m_contactManager.m_contactList; +} + +inline int32 b2World::GetBodyCount() const +{ + return m_bodyCount; +} + +inline int32 b2World::GetJointCount() const +{ + return m_jointCount; +} + +inline int32 b2World::GetContactCount() const +{ + return m_contactManager.m_contactCount; +} + +inline void b2World::SetGravity(const b2Vec2& gravity) +{ + m_gravity = gravity; +} + +inline b2Vec2 b2World::GetGravity() const +{ + return m_gravity; +} + +inline bool b2World::IsLocked() const +{ + return (m_flags & e_locked) == e_locked; +} + +inline void b2World::SetAutoClearForces(bool flag) +{ + if (flag) + { + m_flags |= e_clearForces; + } + else + { + m_flags &= ~e_clearForces; + } +} + +/// Get the flag that controls automatic clearing of forces after each time step. +inline bool b2World::GetAutoClearForces() const +{ + return (m_flags & e_clearForces) == e_clearForces; +} + +inline const b2ContactManager& b2World::GetContactManager() const +{ + return m_contactManager; +} + +inline const b2Profile& b2World::GetProfile() const +{ + return m_profile; +} + +#endif diff --git a/Lib/Include/Box2D/Dynamics/b2WorldCallbacks.h b/Lib/Include/Box2D/Dynamics/b2WorldCallbacks.h new file mode 100644 index 0000000..e307a9d --- /dev/null +++ b/Lib/Include/Box2D/Dynamics/b2WorldCallbacks.h @@ -0,0 +1,155 @@ +/* +* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org +* +* This software is provided 'as-is', without any express or implied +* warranty. In no event will the authors be held liable for any damages +* arising from the use of this software. +* Permission is granted to anyone to use this software for any purpose, +* including commercial applications, and to alter it and redistribute it +* freely, subject to the following restrictions: +* 1. The origin of this software must not be misrepresented; you must not +* claim that you wrote the original software. If you use this software +* in a product, an acknowledgment in the product documentation would be +* appreciated but is not required. +* 2. Altered source versions must be plainly marked as such, and must not be +* misrepresented as being the original software. +* 3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef B2_WORLD_CALLBACKS_H +#define B2_WORLD_CALLBACKS_H + +#include + +struct b2Vec2; +struct b2Transform; +class b2Fixture; +class b2Body; +class b2Joint; +class b2Contact; +struct b2ContactResult; +struct b2Manifold; + +/// Joints and fixtures are destroyed when their associated +/// body is destroyed. Implement this listener so that you +/// may nullify references to these joints and shapes. +class BOX2D_API b2DestructionListener +{ +public: + virtual ~b2DestructionListener() {} + + /// Called when any joint is about to be destroyed due + /// to the destruction of one of its attached bodies. + virtual void SayGoodbye(b2Joint* joint) = 0; + + /// Called when any fixture is about to be destroyed due + /// to the destruction of its parent body. + virtual void SayGoodbye(b2Fixture* fixture) = 0; +}; + +/// Implement this class to provide collision filtering. In other words, you can implement +/// this class if you want finer control over contact creation. +class BOX2D_API b2ContactFilter +{ +public: + virtual ~b2ContactFilter() {} + + /// Return true if contact calculations should be performed between these two shapes. + /// @warning for performance reasons this is only called when the AABBs begin to overlap. + virtual bool ShouldCollide(b2Fixture* fixtureA, b2Fixture* fixtureB); +}; + +/// Contact impulses for reporting. Impulses are used instead of forces because +/// sub-step forces may approach infinity for rigid body collisions. These +/// match up one-to-one with the contact points in b2Manifold. +struct b2ContactImpulse +{ + float32 normalImpulses[b2_maxManifoldPoints]; + float32 tangentImpulses[b2_maxManifoldPoints]; + int32 count; +}; + +/// Implement this class to get contact information. You can use these results for +/// things like sounds and game logic. You can also get contact results by +/// traversing the contact lists after the time step. However, you might miss +/// some contacts because continuous physics leads to sub-stepping. +/// Additionally you may receive multiple callbacks for the same contact in a +/// single time step. +/// You should strive to make your callbacks efficient because there may be +/// many callbacks per time step. +/// @warning You cannot create/destroy Box2D entities inside these callbacks. +class BOX2D_API b2ContactListener +{ +public: + virtual ~b2ContactListener() {} + + /// Called when two fixtures begin to touch. + virtual void BeginContact(b2Contact* contact) { B2_NOT_USED(contact); } + + /// Called when two fixtures cease to touch. + virtual void EndContact(b2Contact* contact) { B2_NOT_USED(contact); } + + /// This is called after a contact is updated. This allows you to inspect a + /// contact before it goes to the solver. If you are careful, you can modify the + /// contact manifold (e.g. disable contact). + /// A copy of the old manifold is provided so that you can detect changes. + /// Note: this is called only for awake bodies. + /// Note: this is called even when the number of contact points is zero. + /// Note: this is not called for sensors. + /// Note: if you set the number of contact points to zero, you will not + /// get an EndContact callback. However, you may get a BeginContact callback + /// the next step. + virtual void PreSolve(b2Contact* contact, const b2Manifold* oldManifold) + { + B2_NOT_USED(contact); + B2_NOT_USED(oldManifold); + } + + /// This lets you inspect a contact after the solver is finished. This is useful + /// for inspecting impulses. + /// Note: the contact manifold does not include time of impact impulses, which can be + /// arbitrarily large if the sub-step is small. Hence the impulse is provided explicitly + /// in a separate data structure. + /// Note: this is only called for contacts that are touching, solid, and awake. + virtual void PostSolve(b2Contact* contact, const b2ContactImpulse* impulse) + { + B2_NOT_USED(contact); + B2_NOT_USED(impulse); + } +}; + +/// Callback class for AABB queries. +/// See b2World::Query +class BOX2D_API b2QueryCallback +{ +public: + virtual ~b2QueryCallback() {} + + /// Called for each fixture found in the query AABB. + /// @return false to terminate the query. + virtual bool ReportFixture(b2Fixture* fixture) = 0; +}; + +/// Callback class for ray casts. +/// See b2World::RayCast +class BOX2D_API b2RayCastCallback +{ +public: + virtual ~b2RayCastCallback() {} + + /// Called for each fixture found in the query. You control how the ray cast + /// proceeds by returning a float: + /// return -1: ignore this fixture and continue + /// return 0: terminate the ray cast + /// return fraction: clip the ray to this point + /// return 1: don't clip the ray and continue + /// @param fixture the fixture hit by the ray + /// @param point the point of initial intersection + /// @param normal the normal vector at the point of intersection + /// @return -1 to filter, 0 to terminate, fraction to clip the ray for + /// closest hit, 1 to continue + virtual float32 ReportFixture( b2Fixture* fixture, const b2Vec2& point, + const b2Vec2& normal, float32 fraction) = 0; +}; + +#endif diff --git a/Lib/Include/Box2D/Rope/b2Rope.h b/Lib/Include/Box2D/Rope/b2Rope.h new file mode 100644 index 0000000..246cf92 --- /dev/null +++ b/Lib/Include/Box2D/Rope/b2Rope.h @@ -0,0 +1,115 @@ +/* +* Copyright (c) 2011 Erin Catto http://www.box2d.org +* +* This software is provided 'as-is', without any express or implied +* warranty. In no event will the authors be held liable for any damages +* arising from the use of this software. +* Permission is granted to anyone to use this software for any purpose, +* including commercial applications, and to alter it and redistribute it +* freely, subject to the following restrictions: +* 1. The origin of this software must not be misrepresented; you must not +* claim that you wrote the original software. If you use this software +* in a product, an acknowledgment in the product documentation would be +* appreciated but is not required. +* 2. Altered source versions must be plainly marked as such, and must not be +* misrepresented as being the original software. +* 3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef B2_ROPE_H +#define B2_ROPE_H + +#include + +class b2Draw; + +/// +struct b2RopeDef +{ + b2RopeDef() + { + vertices = NULL; + count = 0; + masses = NULL; + gravity.SetZero(); + damping = 0.1f; + k2 = 0.9f; + k3 = 0.1f; + } + + /// + b2Vec2* vertices; + + /// + int32 count; + + /// + float32* masses; + + /// + b2Vec2 gravity; + + /// + float32 damping; + + /// Stretching stiffness + float32 k2; + + /// Bending stiffness. Values above 0.5 can make the simulation blow up. + float32 k3; +}; + +/// +class b2Rope +{ +public: + b2Rope(); + ~b2Rope(); + + /// + void Initialize(const b2RopeDef* def); + + /// + void Step(float32 timeStep, int32 iterations); + + /// + int32 GetVertexCount() const + { + return m_count; + } + + /// + const b2Vec2* GetVertices() const + { + return m_ps; + } + + /// + void Draw(b2Draw* draw) const; + + /// + void SetAngle(float32 angle); + +private: + + void SolveC2(); + void SolveC3(); + + int32 m_count; + b2Vec2* m_ps; + b2Vec2* m_p0s; + b2Vec2* m_vs; + + float32* m_ims; + + float32* m_Ls; + float32* m_as; + + b2Vec2 m_gravity; + float32 m_damping; + + float32 m_k2; + float32 m_k3; +}; + +#endif diff --git a/Lib/Include/CML/cml.h b/Lib/Include/CML/cml.h new file mode 100644 index 0000000..d8ef6a9 --- /dev/null +++ b/Lib/Include/CML/cml.h @@ -0,0 +1,75 @@ +/* -*- C++ -*- ------------------------------------------------------------ + +Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/ + +The Configurable Math Library (CML) is distributed under the terms of the +Boost Software License, v1.0 (see cml/LICENSE for details). + + *-----------------------------------------------------------------------*/ +/** @file + * @brief Main CML header to include all CML functionality. + * + * @todo load vectors, matrices, and quaternions from a stream. + * + * @todo Move common vector and matrix class ops to a base class (requires + * SCOOP-like programming, see below). + * + * @todo Implement matrix<>::orthogonalize(). + * + * @todo Add is_square<>, is_rectangular<>, etc. to make it easier to + * detect specific matrix types. + * + * @todo Implement dedicated square matrix classes to get rid of duplicated + * code in the specialized matrix classes. + * + * @todo Implement automatic temporary generation, along with expression + * node return types for mat-vec and mat-mat operators. + * + * @todo switch to ssize_t instead of size_t to avoid having to explicitly + * deal with wrap-arounds to 2^32-1 when a size_t is subtracted from. + * + * @todo Finish tests for mat-vec multiply. + * + * @todo Differentiate between references used for function arguments, and + * those used for variable types. In particular, GCC 3.4 requires const T & + * function arguments to ensure complete unrolling/inlining of expressions. + * + * @todo Specialize matrix multiplication based upon the size type (fixed or + * dynamic). This makes a difference for at least GCC 3.4. + * + * @todo need a build system for the tests/ and examples/ directories. + * + * @todo clean up the testing infrastructure, and make it easier to add new + * tests + * + * @todo figure out if scalars should be passed by value or reference, or + * if it should be determined by traits + * + * @todo change use of typename and class to be like Alexandrescu book + * + * @todo figure out if it makes sense to unroll assignment if either the + * source expression or the target vector/matrix has a fixed size (right + * now, unrolling happens only if the target has a fixed size) + * + * @todo Allow addition of new types, a la glommable ETs (but simpler). + * Can use ideas from "SCOOP" method: Nicolas Burrus, Alexandre Duret-Lutz, + * Thierry G‰raud, David Lesage and Rapha‹l Poss. A Static C++ + * Object-Oriented Programming (SCOOP) Paradigm Mixing Benefits of + * Traditional OOP and Generic Programming. In the Proceedings of the + * Workshop on Multiple Paradigm with OO Languages (MPOOL'03) Anaheim, CA, + * USA Oct. 2003 + */ + +#ifndef cml_h +#define cml_h + +#include +#include +#include +#include +#include + +#endif + +// ------------------------------------------------------------------------- +// vim:ft=cpp diff --git a/Lib/Include/CML/constants.h b/Lib/Include/CML/constants.h new file mode 100644 index 0000000..d3392ef --- /dev/null +++ b/Lib/Include/CML/constants.h @@ -0,0 +1,89 @@ +/* -*- C++ -*- ------------------------------------------------------------ + +Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/ + +The Configurable Math Library (CML) is distributed under the terms of the +Boost Software License, v1.0 (see cml/LICENSE for details). + + *-----------------------------------------------------------------------*/ +/** @file + * @brief Useful constants. + */ + +#ifndef cml_constants_h +#define cml_constants_h + +#include + +#if !defined(M_PI) +#define M_PI 3.14159265358979323846264338327950288 +#endif + +#if !defined(M_SQRT2) +#define M_SQRT2 1.41421356237309504880168872420969808 +#endif + +#if !defined(M_E) +#define M_E 2.71828182845904523536028747135266250 +#endif + +namespace cml { + +#if 1 + +/** Templated constants struct. + * + * Either float or double can be used. + */ +template +struct constants { + static Float pi() { return Float(M_PI); } + static Float two_pi() { return Float(2.*M_PI); } + static Float inv_pi() { return Float(1./M_PI); } + static Float inv_two_pi() { return Float(1./(2.*M_PI)); } + static Float pi_over_2() { return Float(M_PI/2.); } + static Float pi_over_4() { return Float(M_PI/4.); } + static Float deg_per_rad() { return Float(180./M_PI); } + static Float rad_per_deg() { return Float(M_PI/180.); } + + static Float sqrt_2() { return Float(M_SQRT2); } + static Float sqrt_3() { return Float(1.732050807568877293527446341505); } + static Float sqrt_5() { return Float(2.236067977499789696409173668731); } + static Float sqrt_6() { return Float(2.449489742783178098197284074705); } + + static Float e() { return Float(M_E); } +}; + +#else + +/* XXX This version requires an explicit instantiation of *every* constant + * below, e.g.: + * + * template const F cml::constants::pi; + */ +/** Templated constants struct. + * + * Either float or double can be used. + */ +template +struct constants { + static const Float pi = M_PI; + static const Float two_pi = 2.*M_PI; + static const Float inv_pi = 1./M_PI; /* 1/pi */ + static const Float inv_two_pi = 1./(2.*M_PI); /* 1/(2*pi) */ + static const Float pi_over_2 = M_PI/2.; /* pi/2 */ + static const Float pi_over_4 = M_PI/4.; /* pi/4 */ + static const Float deg_per_rad = 180./M_PI; + static const Float rad_per_deg = M_PI/180.; + static const Float sqrt_2 = M_SQRT2; + static const Float sqrt_3 = 1.73205080756887729352744634150587237; + static const Float sqrt_5 = 2.23606797749978969640917366873127624; + static const Float sqrt_6 = 2.44948974278317809819728407470589139; + static const Float e = M_E; +}; + +#endif + +} // namespace cml + +#endif diff --git a/Lib/Include/CML/core/cml_assert.h b/Lib/Include/CML/core/cml_assert.h new file mode 100644 index 0000000..9b29c6d --- /dev/null +++ b/Lib/Include/CML/core/cml_assert.h @@ -0,0 +1,97 @@ +/* -*- C++ -*- ------------------------------------------------------------ + +Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/ + +The Configurable Math Library (CML) is distributed under the terms of the +Boost Software License, v1.0 (see cml/LICENSE for details). + + *-----------------------------------------------------------------------*/ +/** @file + * @brief + * + * Macros and template metaprogramming to implement compile- and run-time + * assertions. + */ + +#ifndef cml_assert_h +#define cml_assert_h + +#include + +namespace cml { + +/* Join preprocessor macros into a new preprocessor macro: */ +#define CML_JOIN(X,Y) CML_DO_JOIN(X,Y) +#define CML_DO_JOIN(X,Y) CML_DO_JOIN2(X,Y) +#define CML_DO_JOIN2(X,Y) X##Y + +/* Change a macro value into a string: */ +#define TO_STRING(X) TO_STRING2(X) +#define TO_STRING2(X) #X + +/** Default undefined compile-time assertion struct. */ +template struct STATIC_ASSERTION_FAILURE; + +/** Struct instantiated when a true assertion is made at compile-time. */ +template<> struct STATIC_ASSERTION_FAILURE { + typedef true_type result; + enum { value = true }; +}; + +/** Create a compile-time assertion. + * + * @note Compile-time assertions must be expressions that can be evaluated at + * comile time. This means that the expression must only rely on constants, + * enums, and/or template parameters, not variables having run-time storage + * requirements. + * + * @warning Enclose expressions that have commas with parens, otherwise the + * preprocessor will parse the commas as macro argument separators! + * + * @sa STATIC_ASSERTION_FAILURE + */ +#define CML_STATIC_REQUIRE(_E_) \ + typedef typename STATIC_ASSERTION_FAILURE<(_E_)>::result \ + CML_JOIN(__cml_assert_test_typedef_, __LINE__) + + +/** A more meaningful compile-time assertion struct. + * + * The parameter M is a struct type which has been declared but not + * defined; e.g. struct this_is_an_error. + * + * When used with CML_STATIC_REQUIRE_M(,M), the compiler errors will + * contain the struct name at the point of the error. + */ +template struct STATIC_ASSERTION_FAILURE_M { + typename M::bogus result; +}; + +/** Instantiated for true assertions. */ +template struct STATIC_ASSERTION_FAILURE_M { + typedef true_type result; + enum { value = true }; +}; + +/** Create a compile-time assertion with a message. + * + * @note Compile-time assertions must be expressions that can be evaluated at + * comile time. This means that the expression must only rely on constants, + * enums, and/or template parameters, not variables having run-time storage + * requirements. + * + * @warning Enclose expressions that have commas with parens, otherwise the + * preprocessor will parse the commas as macro argument separators! + * + * @sa STATIC_ASSERTION_FAILURE_M + */ +#define CML_STATIC_REQUIRE_M(_E_, _M_) \ + typedef typename STATIC_ASSERTION_FAILURE_M<(_E_),_M_> \ + ::result CML_JOIN(__bogus_assert_type_, __LINE__) + +} // namespace cml + +#endif + +// ------------------------------------------------------------------------- +// vim:ft=cpp diff --git a/Lib/Include/CML/core/cml_meta.h b/Lib/Include/CML/core/cml_meta.h new file mode 100644 index 0000000..679f761 --- /dev/null +++ b/Lib/Include/CML/core/cml_meta.h @@ -0,0 +1,24 @@ +/* -*- C++ -*- ------------------------------------------------------------ + +Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/ + +The Configurable Math Library (CML) is distributed under the terms of the +Boost Software License, v1.0 (see cml/LICENSE for details). + + *-----------------------------------------------------------------------*/ +/** @file + * @brief A few simple metaprogramming tools. + */ + +#ifndef cml_meta_h +#define cml_meta_h + +/* Include all of the template metaprogramming tools: */ +#include +#include +#include + +#endif + +// ------------------------------------------------------------------------- +// vim:ft=cpp diff --git a/Lib/Include/CML/core/common.h b/Lib/Include/CML/core/common.h new file mode 100644 index 0000000..01b3f7e --- /dev/null +++ b/Lib/Include/CML/core/common.h @@ -0,0 +1,87 @@ +/* -*- C++ -*- ------------------------------------------------------------ + +Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/ + +The Configurable Math Library (CML) is distributed under the terms of the +Boost Software License, v1.0 (see cml/LICENSE for details). + + *-----------------------------------------------------------------------*/ +/** @file + * @brief + */ + +#ifndef core_common_h +#define core_common_h + +// XXX This isn't really the right place for this. +#if defined(_MSC_VER) +#include +#ifndef _SSIZE_T_DEFINED +#ifdef _WIN64 +typedef __int64 ssize_t; +#else +typedef _W64 int ssize_t; +#endif +#define _SSIZE_T_DEFINED +#endif +#endif + +#include // for size_t +#include // for std::pair<> +#include + +namespace cml { + +/** 1D tag (to select array shape). */ +struct oned_tag {}; + +/** 2D tag (to select array shape). */ +struct twod_tag {}; + +/** Statically-allocated memory tag. */ +struct fixed_memory_tag {}; + +/** Dynamically-allocated memory tag. */ +struct dynamic_memory_tag {}; + +/** Externally-allocated memory tag. */ +struct external_memory_tag {}; + +/** Statically-sized tag. */ +struct fixed_size_tag {}; + +/** Runtime-sized tag. */ +struct dynamic_size_tag {}; + +/** Resizable tag. */ +struct resizable_tag {}; + +/** Not resizable tag. */ +struct not_resizable_tag {}; + +/** Unit-sized tag. */ +struct unit_size_tag {}; + +/** Row-major storage tag. */ +struct row_major {}; + +/** Col-major storage tag. */ +struct col_major {}; + +/** Row-vector matrix basis tag. */ +struct row_basis {}; + +/** Column-vector matrix basis tag. */ +struct col_basis {}; + +/* This is the pair returned from the matrix size() method, as well as from + * the matrix expression size checking code: + */ +typedef std::pair matrix_size; + +} // namespace cml + +#endif + +// ------------------------------------------------------------------------- +// vim:ft=cpp diff --git a/Lib/Include/CML/core/dynamic_1D.h b/Lib/Include/CML/core/dynamic_1D.h new file mode 100644 index 0000000..f69305d --- /dev/null +++ b/Lib/Include/CML/core/dynamic_1D.h @@ -0,0 +1,202 @@ +/* -*- C++ -*- ------------------------------------------------------------ + +Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/ + +The Configurable Math Library (CML) is distributed under the terms of the +Boost Software License, v1.0 (see cml/LICENSE for details). + + *-----------------------------------------------------------------------*/ +/** @file + * @brief + */ + +#ifndef dynamic_1D_h +#define dynamic_1D_h + +#include +#include +#include + +namespace cml { + +/** Dynamically-sized and allocated 1D array. + * + * @note The allocator should be an STL-compatible allocator. + * + * @internal The internal array type must have the proper copy + * semantics, otherwise copy construction will fail. + */ +template +class dynamic_1D +{ + public: + + /* Record the allocator type: */ + typedef typename Alloc::template rebind::other allocator_type; + + /* Record the generator: */ + typedef dynamic generator_type; + + /* Standard: */ + typedef typename allocator_type::value_type value_type; + typedef typename allocator_type::pointer pointer; + typedef typename allocator_type::reference reference; + typedef typename allocator_type::const_reference const_reference; + typedef typename allocator_type::const_pointer const_pointer; + + /* For matching by memory type: */ + typedef dynamic_memory_tag memory_tag; + + /* For matching by size type: */ + typedef dynamic_size_tag size_tag; + + /* For matching by resizability: */ + typedef resizable_tag resizing_tag; + + /* For matching by dimensions: */ + typedef oned_tag dimension_tag; + + + public: + + /** Dynamic arrays have no fixed size. */ + enum { array_size = -1 }; + + + public: + + /** Construct a dynamic array with no size. */ + dynamic_1D() : m_size(0), m_data(0), m_alloc() {} + + /** Construct a dynamic array given the size. */ + explicit dynamic_1D(size_t size) : m_size(0), m_data(0), m_alloc() { + this->resize(size); + } + + /** Copy construct a dynamic array. */ + dynamic_1D(const dynamic_1D& other) + : m_size(0), m_data(0), m_alloc() + { + this->copy(other); + } + + ~dynamic_1D() { + this->destroy(); + } + + + public: + + /** Return the number of elements in the array. */ + size_t size() const { return m_size; } + + /** Access to the data as a C array. + * + * @param i a size_t index into the array. + * @return a mutable reference to the array value at i. + * + * @note This function does not range-check the argument. + */ + reference operator[](size_t i) { return m_data[i]; } + + /** Const access to the data as a C array. + * + * @param i a size_t index into the array. + * @return a const reference to the array value at i. + * + * @note This function does not range-check the argument. + */ + const_reference operator[](size_t i) const { return m_data[i]; } + + /** Return access to the data as a raw pointer. */ + pointer data() { return &m_data[0]; } + + /** Return access to the data as a raw pointer. */ + const_pointer data() const { return &m_data[0]; } + + + public: + + /** Set the array size to the given value. The previous contents are + * destroyed before reallocating the array. If s == size(), + * nothing happens. + * + * @warning This is not guaranteed to preserve the original data. + */ + void resize(size_t s) { + + /* Nothing to do if the size isn't changing: */ + if(s == m_size) return; + + /* Destroy the current array contents: */ + this->destroy(); + + /* Set the new size if non-zero: */ + if(s > 0) { + value_type* data = m_alloc.allocate(s); + for(size_t i = 0; i < s; ++ i) + m_alloc.construct(&data[i], value_type()); + + /* Success, save s and data: */ + m_size = s; + m_data = data; + } + } + + /** Copy the source array. The previous contents are destroyed before + * reallocating the array. If other == *this, nothing happens. + */ + void copy(const dynamic_1D& other) { + + /* Nothing to do if it's the same array: */ + if(&other == this) return; + + /* Destroy the current array contents: */ + this->destroy(); + + /* Set the new size if non-zero: */ + size_t s = other.size(); + if(s > 0) { + value_type* data = m_alloc.allocate(s); + for(size_t i = 0; i < s; ++ i) + m_alloc.construct(&data[i], other[i]); + + /* Success, so save the new array and the size: */ + m_size = s; + m_data = data; + } + } + + + protected: + + /** Destroy the current contents of the array. */ + void destroy() { + if(m_data) { + for(size_t i = 0; i < m_size; ++ i) + m_alloc.destroy(&m_data[i]); + m_alloc.deallocate(m_data, m_size); + m_size = 0; + m_data = 0; + } + } + + + protected: + + /** Current array size (may be 0). */ + size_t m_size; + + /** Array data (may be NULL). */ + value_type* m_data; + + /** Allocator for the array. */ + allocator_type m_alloc; +}; + +} // namespace cml + +#endif + +// ------------------------------------------------------------------------- +// vim:ft=cpp diff --git a/Lib/Include/CML/core/dynamic_2D.h b/Lib/Include/CML/core/dynamic_2D.h new file mode 100644 index 0000000..374c539 --- /dev/null +++ b/Lib/Include/CML/core/dynamic_2D.h @@ -0,0 +1,248 @@ +/* -*- C++ -*- ------------------------------------------------------------ + +Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/ + +The Configurable Math Library (CML) is distributed under the terms of the +Boost Software License, v1.0 (see cml/LICENSE for details). + + *-----------------------------------------------------------------------*/ +/** @file + * @brief + */ + +#ifndef dynamic_2D_h +#define dynamic_2D_h + +#include +#include +#include +#include + +namespace cml { + +/** Dynamically-sized and allocated 2D array. + * + * @note The allocator should be an STL-compatible allocator. + * + * @internal The internal array type must have the proper copy + * semantics, otherwise copy construction will fail. + * + * @internal This class does not need a destructor. + */ +template +class dynamic_2D +{ + public: + + /* Record the allocator type: */ + typedef typename Alloc::template rebind::other allocator_type; + + /* Record the generator: */ + typedef dynamic generator_type; + + /* Standard: */ + typedef typename allocator_type::value_type value_type; + typedef typename allocator_type::pointer pointer; + typedef typename allocator_type::reference reference; + typedef typename allocator_type::const_reference const_reference; + typedef typename allocator_type::const_pointer const_pointer; + + /* For matching by memory layout: */ + typedef Layout layout; + + /* For matching by memory type: */ + typedef dynamic_memory_tag memory_tag; + + /* For matching by size type: */ + typedef dynamic_size_tag size_tag; + + /* For matching by resizability: */ + typedef resizable_tag resizing_tag; + + /* For matching by dimensions: */ + typedef twod_tag dimension_tag; + + /* To simplify the matrix transpose operator: */ + typedef dynamic_2D::type, + Layout,Alloc> transposed_type; + + /* To simplify the matrix row and column operators: */ + typedef dynamic_1D row_array_type; + typedef dynamic_1D col_array_type; + + + protected: + + /** Construct a dynamic array with no size. */ + dynamic_2D() : m_rows(0), m_cols(0), m_data(0), m_alloc() {} + + /** Construct a dynamic matrix given the dimensions. */ + explicit dynamic_2D(size_t rows, size_t cols) + : m_rows(0), m_cols(0), m_data(0), m_alloc() + { + this->resize(rows, cols); + } + + /** Copy construct a dynamic matrix. */ + dynamic_2D(const dynamic_2D& other) + : m_rows(0), m_cols(0), m_data(0), m_alloc() + { + this->copy(other); + } + + ~dynamic_2D() { + this->destroy(); + } + + + public: + + enum { array_rows = -1, array_cols = -1 }; + + + public: + + /** Return the number of rows in the array. */ + size_t rows() const { return m_rows; } + + /** Return the number of cols in the array. */ + size_t cols() const { return m_cols; } + + + public: + + /** Access the given element of the matrix. + * + * @param row row of element. + * @param col column of element. + * @returns mutable reference. + */ + reference operator()(size_t row, size_t col) { + return this->get_element(row, col, layout()); + } + + /** Access the given element of the matrix. + * + * @param row row of element. + * @param col column of element. + * @returns const reference. + */ + const_reference operator()(size_t row, size_t col) const { + return this->get_element(row, col, layout()); + } + + /** Return access to the data as a raw pointer. */ + pointer data() { return &m_data[0]; } + + /** Return access to the data as a raw pointer. */ + const_pointer data() const { return &m_data[0]; } + + + public: + + /** Set the array dimensions. The previous contents are destroyed + * before reallocating the array. If the number of rows and columns + * isn't changing, nothing happens. Also, if either rows or cols is 0, + * the array is cleared. + * + * @warning This is not guaranteed to preserve the original data. + */ + void resize(size_t rows, size_t cols) { + + /* Nothing to do if the size isn't changing: */ + if(rows == m_rows && cols == m_cols) return; + + /* Destroy the current array contents: */ + this->destroy(); + + /* Set the new size if non-zero: */ + if(rows*cols > 0) { + value_type* data = m_alloc.allocate(rows*cols); + for(size_t i = 0; i < rows*cols; ++ i) + m_alloc.construct(&data[i], value_type()); + + /* Success, so save the new array and the dimensions: */ + m_rows = rows; + m_cols = cols; + m_data = data; + } + } + + /** Copy the other array. The previous contents are destroyed before + * reallocating the array. If other == *this, nothing happens. Also, + * if either other.rows() or other.cols() is 0, the array is cleared. + */ + void copy(const dynamic_2D& other) { + + /* Nothing to do if it's the same array: */ + if(&other == this) return; + + /* Destroy the current array contents: */ + this->destroy(); + + /* Set the new size if non-zero: */ + size_t rows = other.rows(), cols = other.cols(); + if(rows*cols > 0) { + value_type* data = m_alloc.allocate(rows*cols); + for(size_t i = 0; i < rows*cols; ++ i) + m_alloc.construct(&data[i], other[i]); + + /* Success, so save the new array and the dimensions: */ + m_rows = rows; + m_cols = cols; + m_data = data; + } + } + + + protected: + + reference get_element(size_t row, size_t col, row_major) { + return m_data[row*m_cols + col]; + } + + const_reference get_element(size_t row, size_t col, row_major) const { + return m_data[row*m_cols + col]; + } + + reference get_element(size_t row, size_t col, col_major) { + return m_data[col*m_rows + row]; + } + + const_reference get_element(size_t row, size_t col, col_major) const { + return m_data[col*m_rows + row]; + } + + + protected: + + /** Destroy the current contents of the array. */ + void destroy() { + if(m_data) { + for(size_t i = 0; i < m_rows*m_cols; ++ i) + m_alloc.destroy(&m_data[i]); + m_alloc.deallocate(m_data, m_rows*m_cols); + m_rows = m_cols = 0; + m_data = 0; + } + } + + + protected: + + /** Current array dimensions (may be 0,0). */ + size_t m_rows, m_cols; + + /** Array data (may be NULL). */ + value_type* m_data; + + /** Allocator for the array. */ + allocator_type m_alloc; +}; + +} // namespace cml + +#endif + +// ------------------------------------------------------------------------- +// vim:ft=cpp diff --git a/Lib/Include/CML/core/external_1D.h b/Lib/Include/CML/core/external_1D.h new file mode 100644 index 0000000..8798805 --- /dev/null +++ b/Lib/Include/CML/core/external_1D.h @@ -0,0 +1,226 @@ +/* -*- C++ -*- ------------------------------------------------------------ + +Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/ + +The Configurable Math Library (CML) is distributed under the terms of the +Boost Software License, v1.0 (see cml/LICENSE for details). + + *-----------------------------------------------------------------------*/ +/** @file + * @brief + * + * Defines the fixed-size and runtime-sized external 1D arrays. + * + * @todo Need a better way to designate non-resizable, run-time sized + * arrays (e.g. by a resizeable tag). + */ + +#ifndef external_1D_h +#define external_1D_h + +#include +#include +#include +#include + +namespace cml { + +/** Fixed-size external 1D array. + * + * Both the memory and the size are fixed at compile time, and cannot be + * changed. + */ +template +class external_1D +{ + public: + + /* Require Size > 0: */ + CML_STATIC_REQUIRE(Size > 0); + + /* Record the generator: */ + typedef external generator_type; + + /* Standard: */ + typedef Element value_type; + typedef Element* pointer; + typedef Element& reference; + typedef const Element& const_reference; + typedef const Element* const_pointer; + + /* Array implementation: */ + typedef value_type array_impl[Size]; + + /* For matching by memory type: */ + typedef external_memory_tag memory_tag; + + /* For matching by size type: */ + typedef fixed_size_tag size_tag; + + /* For matching by resizability: */ + typedef not_resizable_tag resizing_tag; + + /* For matching by dimensions: */ + typedef oned_tag dimension_tag; + + + public: + + /** The length as an enumerated value. */ + enum { array_size = Size }; + + + public: + + external_1D(pointer const ptr) + : m_data(ptr) {} + + + public: + + /** Return the number of elements in the array. */ + size_t size() const { return size_t(array_size); } + + /** Access to the data as a C array. + * + * @param i a size_t index into the array. + * @return a mutable reference to the array value at i. + * + * @note This function does not range-check the argument. + */ + reference operator[](size_t i) { return m_data[i]; } + + /** Const access to the data as a C array. + * + * @param i a size_t index into the array. + * @return a const reference to the array value at i. + * + * @note This function does not range-check the argument. + */ + const_reference operator[](size_t i) const { return m_data[i]; } + + /** Return access to the data as a raw pointer. */ + pointer data() { return m_data; } + + /** Return access to the data as a raw pointer. */ + const_pointer data() const { return m_data; } + + + protected: + + pointer m_data; + + + private: + + /* Initialization without an argument isn't allowed: */ + external_1D(); + + + private: + + external_1D& operator=(const external_1D&); +}; + +/** Run-time sized external 1D array. + * + * Both the memory and the size are fixed at run-time, and cannot be + * changed. This is a specialization for the case that Rows and Cols are + * not specified (i.e. given as the default of -1,-1). + */ +template +class external_1D +{ + public: + + /* Record the generator. Note: this is *not* unique, as it is the same + * generator used by external_2D. However, external_2D is used only by + * matrix<> classes, so this is not a problem. + */ + typedef external<> generator_type; + + /* Standard: */ + typedef Element value_type; + typedef Element* pointer; + typedef Element& reference; + typedef const Element& const_reference; + typedef const Element* const_pointer; + + /* For matching by memory type: */ + typedef external_memory_tag memory_tag; + + /* For matching by size type: */ + typedef dynamic_size_tag size_tag; + + /* For matching by resizability: */ + typedef not_resizable_tag resizing_tag; + + /* For matching by dimensions: */ + typedef oned_tag dimension_tag; + + + public: + + /** The length as an enumerated value. */ + enum { array_size = -1 }; + + + public: + + external_1D(pointer const ptr, size_t size) + : m_data(ptr), m_size(size) {} + + + public: + + /** Return the number of elements in the array. */ + size_t size() const { return m_size; } + + /** Access to the data as a C array. + * + * @param i a size_t index into the array. + * @return a mutable reference to the array value at i. + * + * @note This function does not range-check the argument. + */ + reference operator[](size_t i) { return m_data[i]; } + + /** Const access to the data as a C array. + * + * @param i a size_t index into the array. + * @return a const reference to the array value at i. + * + * @note This function does not range-check the argument. + */ + const_reference operator[](size_t i) const { return m_data[i]; } + + /** Return access to the data as a raw pointer. */ + pointer data() { return m_data; } + + /** Return access to the data as a raw pointer. */ + const_pointer data() const { return m_data; } + + + protected: + + pointer m_data; + size_t m_size; + + + private: + + /* Initialization without an argument isn't allowed: */ + external_1D(); + + + private: + + external_1D& operator=(const external_1D&); +}; + +} // namespace cml + +#endif + +// ------------------------------------------------------------------------- +// vim:ft=cpp diff --git a/Lib/Include/CML/core/external_2D.h b/Lib/Include/CML/core/external_2D.h new file mode 100644 index 0000000..4fd9d2d --- /dev/null +++ b/Lib/Include/CML/core/external_2D.h @@ -0,0 +1,315 @@ +/* -*- C++ -*- ------------------------------------------------------------ + +Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/ + +The Configurable Math Library (CML) is distributed under the terms of the +Boost Software License, v1.0 (see cml/LICENSE for details). + + *-----------------------------------------------------------------------*/ +/** @file + * @brief + * + * Defines the fixed-size and runtime-sized external 2D arrays. + * + * @todo Would casting get better performance in the external_2D<> element + * access methods? + */ + +#ifndef external_2D_h +#define external_2D_h + +#include +#include +#include +#include +#include +#include + +namespace cml { + +/** Fixed-size external 2D array. + * + * Both the memory and the size are fixed at compile time, and cannot be + * changed. + */ +template +class external_2D +{ + public: + + /* Require Rows > 0, Cols > 0: */ + CML_STATIC_REQUIRE((Rows > 0) && (Cols > 0)); + + /* Record the generator: */ + typedef external generator_type; + + /* Standard: */ + typedef Element value_type; + typedef Element* pointer; + typedef Element& reference; + typedef const Element& const_reference; + typedef const Element* const_pointer; + + /* For matching by memory layout: */ + typedef Layout layout; + + /* For matching by memory type: */ + typedef external_memory_tag memory_tag; + + /* For matching by size type: */ + typedef fixed_size_tag size_tag; + + /* For matching by resizability: */ + typedef not_resizable_tag resizing_tag; + + /* For matching by dimensions: */ + typedef twod_tag dimension_tag; + + /* To simplify the matrix transpose operator: */ + typedef fixed_2D::type, + Cols,Rows,Layout> transposed_type; + /* Note: the transposed type must be fixed_2D, since an external array + * cannot be specified without a corresponding memory location. + */ + + /* To simplify the matrix row and column operators: */ + typedef fixed_1D row_array_type; + typedef fixed_1D col_array_type; + /* Note: the row types must be fixed_1D, since external arrays cannot be + * specified without a memory location. + */ + + + public: + + enum { array_rows = Rows, array_cols = Cols }; + + + public: + + /** Construct an external array from a pointer. */ + external_2D(value_type const ptr[Rows][Cols]) + : m_data(const_cast(&ptr[0][0])) {} + + /** Construct an external array from a pointer. */ + external_2D(value_type* const ptr) : m_data(ptr) {} + + + public: + + /** Return the number of rows in the array. */ + size_t rows() const { return size_t(array_rows); } + + /** Return the number of cols in the array. */ + size_t cols() const { return size_t(array_cols); } + + + public: + + /** Access element (row,col) of the matrix. + * + * @param row row of element. + * @param col column of element. + * @returns mutable reference. + * + * @note This function does not range-check the arguments. + */ + reference operator()(size_t row, size_t col) { + /* Dispatch to the right function based on layout: */ + return get_element(row,col,layout()); + } + + /** Const access element (row,col) of the matrix. + * + * @param row row of element. + * @param col column of element. + * @returns const reference. + * + * @note This function does not range-check the arguments. + */ + const_reference operator()(size_t row, size_t col) const { + /* Dispatch to the right function based on layout: */ + return get_element(row,col,layout()); + } + + /** Return access to the data as a raw pointer. */ + pointer data() { return m_data; } + + /** Return access to the data as a raw pointer. */ + const_pointer data() const { return m_data; } + + + protected: + + /* XXX May be able to cast to get better performance? */ + reference get_element(size_t row, size_t col, row_major) { + return m_data[row*Cols + col]; + } + + const_reference get_element(size_t row, size_t col, row_major) const { + return m_data[row*Cols + col]; + } + + reference get_element(size_t row, size_t col, col_major) { + return m_data[col*Rows + row]; + } + + const_reference get_element(size_t row, size_t col, col_major) const { + return m_data[col*Rows + row]; + } + + + protected: + + /* Declare the data array: */ + pointer m_data; + + + private: + + external_2D& operator=(const external_2D&); +}; + +/** Run-time sized external 2D array. + * + * Both the memory and the size are fixed at run-time, but cannot be changed. + * This is a specialization for the case that Rows and Cols are not specified + * (i.e. given as the default of -1,-1). + */ +template +class external_2D +{ + public: + + /* Record the generator. Note: this is *not* unique, as it is the same + * generator used by external_1D. However, external_1D is used only by + * vector<> classes, so this is not a problem. + */ + typedef external<> generator_type; + + /* Standard: */ + typedef Element value_type; + typedef Element* pointer; + typedef Element& reference; + typedef const Element& const_reference; + typedef const Element* const_pointer; + + /* For matching by memory layout: */ + typedef Layout layout; + + /* For matching by memory type: */ + typedef external_memory_tag memory_tag; + + /* For matching by size type: */ + typedef dynamic_size_tag size_tag; + + /* For matching by resizability: */ + typedef not_resizable_tag resizing_tag; + + /* For matching by dimensions: */ + typedef twod_tag dimension_tag; + + /* To simplify the matrix transpose operator: */ + typedef dynamic_2D::type, + Layout, CML_DEFAULT_ARRAY_ALLOC> transposed_type; + + /* To simplify the matrix row and column operators: */ + typedef dynamic_1D row_array_type; + typedef dynamic_1D col_array_type; + + + public: + + enum { array_rows = -1, array_cols = -1 }; + + + public: + + /** Construct an external array with no size. */ + external_2D(pointer const ptr, size_t rows, size_t cols) + : m_data(ptr), m_rows(rows), m_cols(cols) {} + + + public: + + /** Return the number of rows in the array. */ + size_t rows() const { return m_rows; } + + /** Return the number of cols in the array. */ + size_t cols() const { return m_cols; } + + + public: + + /** Access element (row,col) of the matrix. + * + * @param row row of element. + * @param col column of element. + * @returns mutable reference. + * + * @note This function does not range-check the arguments. + */ + reference operator()(size_t row, size_t col) { + /* Dispatch to the right function based on layout: */ + return get_element(row,col,layout()); + } + + /** Const access element (row,col) of the matrix. + * + * @param row row of element. + * @param col column of element. + * @returns const reference. + * + * @note This function does not range-check the arguments. + */ + const_reference operator()(size_t row, size_t col) const { + /* Dispatch to the right function based on layout: */ + return get_element(row,col,layout()); + } + + /** Return access to the data as a raw pointer. */ + pointer data() { return m_data; } + + /** Return access to the data as a raw pointer. */ + const_pointer data() const { return m_data; } + + + protected: + + /* XXX May be able to cast to get better performance? */ + reference get_element(size_t row, size_t col, row_major) { + return m_data[row*m_cols + col]; + } + + const_reference get_element(size_t row, size_t col, row_major) const { + return m_data[row*m_cols + col]; + } + + reference get_element(size_t row, size_t col, col_major) { + return m_data[col*m_rows + row]; + } + + const_reference get_element(size_t row, size_t col, col_major) const { + return m_data[col*m_rows + row]; + } + + + protected: + + /* Declare the data array: */ + value_type* m_data; + size_t m_rows; + size_t m_cols; + + + private: + + external_2D& operator=(const external_2D&); +}; + +} // namespace cml + +#endif + +// ------------------------------------------------------------------------- +// vim:ft=cpp diff --git a/Lib/Include/CML/core/fixed_1D.h b/Lib/Include/CML/core/fixed_1D.h new file mode 100644 index 0000000..69514c0 --- /dev/null +++ b/Lib/Include/CML/core/fixed_1D.h @@ -0,0 +1,135 @@ +/* -*- C++ -*- ------------------------------------------------------------ + +Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/ + +The Configurable Math Library (CML) is distributed under the terms of the +Boost Software License, v1.0 (see cml/LICENSE for details). + + *-----------------------------------------------------------------------*/ +/** @file + * @brief + */ + +#ifndef fixed_1D_h +#define fixed_1D_h + +#include +#include +#include +#include + +namespace cml { + +/** Statically-allocated array. + * + * @note This class is designed to have the same size as a C array with the + * same length. It's therefore possible (but not recommended!) to coerce + * a normal C array into a fixed_1D<> like this: + * + * typedef fixed_1D array; + * double c_array[10]; + * array& array_object = *((array*)&c_array); + * double e1 = array_object[1]; + * + * It's also possible to do this with a pointer to an array of values (e.g. a + * double*), whether or not it was actually declared as a fixed C array. This + * is HIGHLY DISCOURAGED, though. It's relatively straightforward to implement + * a separate class to take a C array (or pointer) and turn it into an array + * object. + * + * @sa cml::fixed + * + * @internal Do not add the empty constructor and destructor; at + * least one compiler (Intel C++ 9.0) fails to optimize them away, and they + * aren't needed anyway here. + */ +template +class fixed_1D +{ + public: + + /* Require Size > 0: */ + CML_STATIC_REQUIRE(Size > 0); + + /* Record the generator: */ + typedef fixed generator_type; + + /* Standard: */ + typedef Element value_type; + typedef Element* pointer; + typedef Element& reference; + typedef const Element& const_reference; + typedef const Element* const_pointer; + + /* Array implementation: */ + typedef value_type array_impl[Size]; + + /* For matching by memory type: */ + typedef fixed_memory_tag memory_tag; + + /* For matching by size type: */ + typedef fixed_size_tag size_tag; + + /* For matching by resizability: */ + typedef not_resizable_tag resizing_tag; + + /* For matching by dimensions: */ + typedef oned_tag dimension_tag; + + + public: + + /** The length as an enumerated value. */ + enum { array_size = Size }; + + + public: + + /** Return the number of elements in the array. */ + size_t size() const { return size_t(array_size); } + + /** Access to the data as a C array. + * + * @param i a size_t index into the array. + * @return a mutable reference to the array value at i. + * + * @note This function does not range-check the argument. + */ + reference operator[](size_t i) { return m_data[i]; } + + /** Const access to the data as a C array. + * + * @param i a size_t index into the array. + * @return a const reference to the array value at i. + * + * @note This function does not range-check the argument. + */ + const_reference operator[](size_t i) const { return m_data[i]; } + + /** Return access to the data as a raw pointer. */ + pointer data() { return &m_data[0]; } + + /** Return access to the data as a raw pointer. */ + const_pointer data() const { return &m_data[0]; } + + protected: + + fixed_1D() {} + + + protected: + + array_impl m_data; + + + private: + + fixed_1D& operator=(const fixed_1D&); +}; + +} // namespace cml + +#endif + +// ------------------------------------------------------------------------- +// vim:ft=cpp diff --git a/Lib/Include/CML/core/fixed_2D.h b/Lib/Include/CML/core/fixed_2D.h new file mode 100644 index 0000000..0f68890 --- /dev/null +++ b/Lib/Include/CML/core/fixed_2D.h @@ -0,0 +1,205 @@ +/* -*- C++ -*- ------------------------------------------------------------ + +Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/ + +The Configurable Math Library (CML) is distributed under the terms of the +Boost Software License, v1.0 (see cml/LICENSE for details). + + *-----------------------------------------------------------------------*/ +/** @file + * @brief + */ + +#ifndef fixed_2D_h +#define fixed_2D_h + +#include +#include + +/* This is used below to create a more meaningful compile-time error when + * an unknown layout argument is given: + */ +struct invalid_layout_type_error; + +/* This is used below to create a more meaningful compile-time error when + * a negative size is given. + */ +struct negative_array_size_error; + +namespace cml { + +/** The internal statically-allocated 2D-array implementation class. + * + * This uses an internal class to setup the data matrix with the proper + * layout. The alternative is to use a 1D array with size Rows*Cols and a + * multiplication to dereference an element, but it seems that compilers + * better optimize 2D array dereferences. This is different from + * dynamic_2D<>, which must use the 1D array method. + * + * @sa cml::fixed + * + * @note This class is designed to have the same size as a C array with the + * same dimensions. It's therefore possible (but not recommended!) to coerce + * a normal C array into a fixed_2D<> like this: + * + * typedef fixed_2D array; + * double c_array[10][10]; + * array& array_object = *((array*)&c_array); + * double e11 = array_object[1][1]; + * + * It's also possible to do this with a pointer to an array of values (e.g. a + * double*), whether or not it was actually declared as a fixed C array. This + * is HIGHLY DISCOURAGED, though, since it's relatively straightforward to + * implement a separate class to take a C array (or pointer) and turn it into + * an array object. + * + * @internal Do not add the empty constructor and destructor; at + * least one compiler (Intel C++ 9.0) fails to optimize them away, and they + * aren't needed anyway here. + */ +template +class fixed_2D +{ + public: + + /* Require Rows > 0, Cols > 0: */ + CML_STATIC_REQUIRE_M( + (Rows > 0) && (Cols > 0), + negative_array_size_error); + + /* Require Layout to be row_major or col_major: */ + CML_STATIC_REQUIRE_M( + (same_type::is_true + || same_type::is_true), + invalid_layout_type_error); + + + /* Record the generator: */ + typedef fixed generator_type; + + /* Standard: */ + typedef Element value_type; + typedef Element* pointer; + typedef Element& reference; + typedef const Element& const_reference; + typedef const Element* const_pointer; + + /* For matching by memory layout: */ + typedef Layout layout; + + /* For matching by memory type: */ + typedef fixed_memory_tag memory_tag; + + /* For matching by size type: */ + typedef fixed_size_tag size_tag; + + /* For matching by resizability: */ + typedef not_resizable_tag resizing_tag; + + /* For matching by dimensions: */ + typedef twod_tag dimension_tag; + + /* To simplify the matrix transpose operator: */ + typedef fixed_2D::type, + Cols,Rows,Layout> transposed_type; + + /* To simplify the matrix row and column operators: */ + typedef fixed_1D row_array_type; + typedef fixed_1D col_array_type; + + + public: + + enum { array_rows = Rows, array_cols = Cols }; + + + public: + + /** Return the number of rows in the array. */ + size_t rows() const { return size_t(array_rows); } + + /** Return the number of cols in the array. */ + size_t cols() const { return size_t(array_cols); } + + + public: + + /** Access element (row,col) of the matrix. + * + * @param row row of element. + * @param col column of element. + * @returns mutable reference. + * + * @note This function does not range-check the arguments. + */ + reference operator()(size_t row, size_t col) { + /* Dispatch to the right function based on layout: */ + return get_element(row,col,layout()); + } + + /** Const access element (row,col) of the matrix. + * + * @param row row of element. + * @param col column of element. + * @returns const reference. + * + * @note This function does not range-check the arguments. + */ + const_reference operator()(size_t row, size_t col) const { + /* Dispatch to the right function based on layout: */ + return get_element(row,col,layout()); + } + + /** Return access to the data as a raw pointer. */ + pointer data() { return &m_data[0][0]; } + + /** Return access to the data as a raw pointer. */ + const_pointer data() const { return &m_data[0][0]; } + + + public: + + fixed_2D() {} + + + protected: + + reference get_element(size_t row, size_t col, row_major) { + return m_data[row][col]; + } + + const_reference get_element(size_t row, size_t col, row_major) const { + return m_data[row][col]; + } + + reference get_element(size_t row, size_t col, col_major) { + return m_data[col][row]; + } + + const_reference get_element(size_t row, size_t col, col_major) const { + return m_data[col][row]; + } + + + protected: + + /* Typedef the possible layouts: */ + typedef Element row_major_array[Rows][Cols]; + typedef Element col_major_array[Cols][Rows]; + + /* Now, select the right layout for the current matrix: */ + typedef typename select_switch< + Layout, row_major, row_major_array, /* Case 1 */ + col_major, col_major_array /* Case 2 */ + >::result array_data; + + /* Declare the data array: */ + array_data m_data; +}; + +} // namespace cml + +#endif + +// ------------------------------------------------------------------------- +// vim:ft=cpp diff --git a/Lib/Include/CML/core/fwd.h b/Lib/Include/CML/core/fwd.h new file mode 100644 index 0000000..84fada0 --- /dev/null +++ b/Lib/Include/CML/core/fwd.h @@ -0,0 +1,63 @@ +/* -*- C++ -*- ------------------------------------------------------------ + +Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/ + +The Configurable Math Library (CML) is distributed under the terms of the +Boost Software License, v1.0 (see cml/LICENSE for details). + + *-----------------------------------------------------------------------*/ +/** @file + * @brief + * + * Forward declarations, useful to avoid including lots of headers. + * + * @sa cml/et/array_promotions.h + */ + +#ifndef core_fwd_h +#define core_fwd_h + +namespace cml { + +/* cml/core/fixed_1D.h */ +template class fixed_1D; + +/* cml/core/fixed_2D.h */ +template class fixed_2D; + +/* cml/core/dynamic_1D.h */ +template class dynamic_1D; + +/* cml/core/dynamic_2D.h */ +template class dynamic_2D; + +/* cml/core/external_1D.h */ +template class external_1D; + +/* cml/core/external_2D.h */ +template class external_2D; + +/* cml/fixed.h */ +template struct fixed; + +/* cml/dynamic.h */ +template struct dynamic; + +/* cml/external.h */ +template struct external; + +/* cml/vector.h */ +template class vector; + +/* cml/matrix.h */ +template class matrix; + +/* cml/quaternion.h */ +template class quaternion; + +} // namespace cml + +#endif + +// ------------------------------------------------------------------------- +// vim:ft=cpp diff --git a/Lib/Include/CML/core/meta/common.h b/Lib/Include/CML/core/meta/common.h new file mode 100644 index 0000000..08c129d --- /dev/null +++ b/Lib/Include/CML/core/meta/common.h @@ -0,0 +1,118 @@ +/* -*- C++ -*- ------------------------------------------------------------ + +Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/ + +The Configurable Math Library (CML) is distributed under the terms of the +Boost Software License, v1.0 (see cml/LICENSE for details). + + *-----------------------------------------------------------------------*/ +/** @file + * @brief + */ + +#ifndef core_meta_common_h +#define core_meta_common_h + +namespace cml { + +/** Type of a true statement. */ +struct true_type {}; + +/** Type of a false statement. */ +struct false_type {}; + +template struct is_true { + typedef false_type result; +}; + +template<> struct is_true { + typedef true_type result; +}; + +/** A "type pair". */ +template struct type_pair { + typedef T1 first; + typedef T2 second; +}; + +/** A "type quadruple". */ +template +struct type_quad { + typedef T1 first; + typedef T2 second; + typedef T3 third; + typedef T3 fourth; +}; + +/** Match any type (for use with same_type<> and select_switch<>). */ +struct any_type {}; + +/** Determine if two types are the same. + * + * Defaults to false. + */ +template struct same_type { + typedef false_type result; + enum { is_true = false, is_false = true }; +}; + +/** Match the same type for both of same_type's template arguments. */ +template struct same_type { + typedef true_type result; + enum { is_true = true, is_false = false }; +}; + +/** Match a type and any_type. */ +template struct same_type { + typedef true_type result; + enum { is_true = true, is_false = false }; +}; + +/** Match a type and any_type. */ +template struct same_type { + typedef true_type result; + enum { is_true = true, is_false = false }; +}; + +/** Disambiguate pair of any_type's. */ +template<> struct same_type { + typedef true_type result; + enum { is_true = true, is_false = false }; +}; + +/** Remove a reference qualifier from a type. */ +template struct remove_reference { + template struct helper { + typedef Q type; + }; + + template struct helper { + typedef Q type; + }; + + template struct helper { + typedef const Q type; + }; + + typedef typename helper::type type; +}; + +/** Remove a const qualifier from a type. */ +template struct remove_const { + template struct helper { + typedef Q type; + }; + + template struct helper { + typedef Q type; + }; + + typedef typename helper::type type; +}; + +} // namespace cml + +#endif + +// ------------------------------------------------------------------------- +// vim:ft=cpp diff --git a/Lib/Include/CML/core/meta/if.h b/Lib/Include/CML/core/meta/if.h new file mode 100644 index 0000000..1ea3235 --- /dev/null +++ b/Lib/Include/CML/core/meta/if.h @@ -0,0 +1,42 @@ +/* -*- C++ -*- ------------------------------------------------------------ + +Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/ + +The Configurable Math Library (CML) is distributed under the terms of the +Boost Software License, v1.0 (see cml/LICENSE for details). + + *-----------------------------------------------------------------------*/ +/** @file + * @brief + */ + +#ifndef meta_if_h +#define meta_if_h + +#include + +namespace cml { + +/** Select argument type based upon truth value. */ +template struct select_if; + +/** Result is TrueT if true. */ +template +struct select_if { + typedef TrueT result; + enum { is_true = true }; +}; + +/** Result is FalseT if false. */ +template +struct select_if { + typedef FalseT result; + enum { is_true = false }; +}; + +} // namespace cml + +#endif + +// ------------------------------------------------------------------------- +// vim:ft=cpp diff --git a/Lib/Include/CML/core/meta/switch.h b/Lib/Include/CML/core/meta/switch.h new file mode 100644 index 0000000..736e21a --- /dev/null +++ b/Lib/Include/CML/core/meta/switch.h @@ -0,0 +1,116 @@ +/* -*- C++ -*- ------------------------------------------------------------ + +Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/ + +The Configurable Math Library (CML) is distributed under the terms of the +Boost Software License, v1.0 (see cml/LICENSE for details). + + *-----------------------------------------------------------------------*/ +/** @file + * @brief + */ + +#ifndef meta_switch_h +#define meta_switch_h + +#include +#include + +namespace cml { + +struct NilCase {}; /* For terminating the case list. */ +struct Default {}; /* For indicating the default result. */ + +/* The working parts of the meta-switch go into namespace meta: */ +namespace meta { + +/* "Interior" case statements: */ +template +struct select_case +{ + template struct match { + typedef typename select_if< + same_type::is_true, + Result, + typename NextCase::template match::result + >::result result; + }; +}; + +/* Default case, returned when no match is found in a previous case: */ +template +struct select_case +{ + template struct match { + typedef Result result; + }; +}; + +/* The last case statement (if no match until now, the result is 'void'): */ +template +struct select_case +{ + template struct match { + typedef typename select_if< + same_type::is_true, + Result, + void + >::result result; + }; +}; + +} // namespace meta + +/** Return the matched type (like a switch/case statement). + * + * This is a convenience wrapper to avoid having to explicitly type out + * select_case for each case in the list of types to match against. + */ +template struct select_switch +{ + typedef typename + meta::select_case< T1,R1 + , meta::select_case< T2,R2 + , meta::select_case< T3,R3 + , meta::select_case< T4,R4 + , meta::select_case< T5,R5 + , meta::select_case< T6,R6 + , meta::select_case< T7,R7 + , meta::select_case< T8,R8 + , meta::select_case< T9,R9 + , meta::select_case< T10,R10 + , meta::select_case< T11,R11 + , meta::select_case< T12,R12 + , meta::select_case< T13,R13 + , meta::select_case< T14,R14 + , meta::select_case< T15,R15 + , meta::select_case< T16,R16 + , NilCase + > > > > > > /* 6 */ + > > > > > > > > > > /* 10 */ + ::template match::result result; +}; + +} // namespace cml + +#endif + +// ------------------------------------------------------------------------- +// vim:ft=cpp diff --git a/Lib/Include/CML/defaults.h b/Lib/Include/CML/defaults.h new file mode 100644 index 0000000..4b7c4cf --- /dev/null +++ b/Lib/Include/CML/defaults.h @@ -0,0 +1,89 @@ +/* -*- C++ -*- ------------------------------------------------------------ + +Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/ + +The Configurable Math Library (CML) is distributed under the terms of the +Boost Software License, v1.0 (see cml/LICENSE for details). + + *-----------------------------------------------------------------------*/ +/** @file + * @brief Default values for certain parameters. + */ + +#ifndef defaults_h +#define defaults_h + +#if defined(_MSC_VER) + +#if _MSC_VER >= 1400 + +/* Ignore "C4003: not enough actual parameters for macro": */ +#pragma warning (disable: 4003) + +/* This one is odd, but apparently harmless (but should be fixed!): + * "C4348: redefinition of default parameter" + */ +#pragma warning (disable: 4348) + +#endif + +#endif + +/* The default vector unroll limit: */ +#if !defined(CML_VECTOR_UNROLL_LIMIT) +#define CML_VECTOR_UNROLL_LIMIT 8 +#endif + +/* Don't unroll matrix operations by default: */ +#if !defined(CML_2D_UNROLLER) && !defined(CML_NO_2D_UNROLLER) +#define CML_NO_2D_UNROLLER +#endif + +/* The default vector dot() unroll limit: */ +#if !defined(CML_VECTOR_DOT_UNROLL_LIMIT) +#define CML_VECTOR_DOT_UNROLL_LIMIT CML_VECTOR_UNROLL_LIMIT +#endif + +/* The default array layout is the C/C++ row-major array layout: */ +#if !defined(CML_DEFAULT_ARRAY_LAYOUT) +#define CML_DEFAULT_ARRAY_LAYOUT cml::row_major +#endif + +/* The default basis orientation: */ +#if !defined(CML_DEFAULT_BASIS_ORIENTATION) +#define CML_DEFAULT_BASIS_ORIENTATION cml::col_basis +#endif + +/* Always use the default layout in promotions, by default: */ +#if !defined(CML_ALWAYS_PROMOTE_TO_DEFAULT_LAYOUT) +#define CML_ALWAYS_PROMOTE_TO_DEFAULT_LAYOUT +#endif + +/* The default memory allocator is std::allocator: */ +#if !defined(CML_DEFAULT_ARRAY_ALLOC) +#include // for std::allocator +#define CML_DEFAULT_ARRAY_ALLOC std::allocator +#endif + +/* By default, automatically resize dynamic vectors and matrices: */ +#if !defined(CML_AUTOMATIC_VECTOR_RESIZE_ON_ASSIGNMENT) +#define CML_AUTOMATIC_VECTOR_RESIZE_ON_ASSIGNMENT +#endif + +#if !defined(CML_AUTOMATIC_MATRIX_RESIZE_ON_ASSIGNMENT) +#define CML_AUTOMATIC_MATRIX_RESIZE_ON_ASSIGNMENT +#endif + +/* By default, check vector and matrix sizes: */ +#if !defined(CML_CHECK_VECTOR_EXPR_SIZES) +#define CML_CHECK_VECTOR_EXPR_SIZES +#endif + +#if !defined(CML_CHECK_MATRIX_EXPR_SIZES) +#define CML_CHECK_MATRIX_EXPR_SIZES +#endif + +#endif + +// ------------------------------------------------------------------------- +// vim:ft=cpp diff --git a/Lib/Include/CML/dynamic.h b/Lib/Include/CML/dynamic.h new file mode 100644 index 0000000..8c942b4 --- /dev/null +++ b/Lib/Include/CML/dynamic.h @@ -0,0 +1,35 @@ +/* -*- C++ -*- ------------------------------------------------------------ + +Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/ + +The Configurable Math Library (CML) is distributed under the terms of the +Boost Software License, v1.0 (see cml/LICENSE for details). + + *-----------------------------------------------------------------------*/ +/** @file + * @brief + */ + +#ifndef dynamic_h +#define dynamic_h + +#include + +namespace cml { + +/** This is a selector for dynamic 1D and 2D arrays. + * + * The dynamic<> struct has no implementation; it is used only to select a + * 1D or 2D array type as the base class of a vector or matrix. + * + * @sa fixed + * @sa external + */ +template struct dynamic; + +} // namespace cml + +#endif + +// ------------------------------------------------------------------------- +// vim:ft=cpp diff --git a/Lib/Include/CML/et/array_promotions.h b/Lib/Include/CML/et/array_promotions.h new file mode 100644 index 0000000..418211d --- /dev/null +++ b/Lib/Include/CML/et/array_promotions.h @@ -0,0 +1,288 @@ +/* -*- C++ -*- ------------------------------------------------------------ + +Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/ + +The Configurable Math Library (CML) is distributed under the terms of the +Boost Software License, v1.0 (see cml/LICENSE for details). + + *-----------------------------------------------------------------------*/ +/** @file + * @brief + * + * Defines promotions between array types. + * + * @todo Can/should an expression with a fixed-size argument promote to a + * fixed array instead of a dynamic array? + */ + +#ifndef array_promotions_h +#define array_promotions_h + +#include +#include + +namespace cml { +namespace et { + +#define VAL_MAX(_a_,_b_) ( ((_a_)>(_b_))?(_a_):(_b_) ) + +namespace detail { + +/* This is specialized for 1D and 2D promotions: */ +template struct promote; + +/* Promote 1D fixed-size arrays to a 1D fixed-size array: */ +template +struct promote +{ + typedef typename A1::value_type left_scalar; + typedef typename A2::value_type right_scalar; + + /* First, promote the scalar type: */ + typedef typename ScalarPromote< + left_scalar,right_scalar>::type promoted_scalar; + + /* Next, deduce the array size: */ + enum { Size = VAL_MAX((size_t)A1::array_size, (size_t)A2::array_size) }; + + /* Finally, generate the promoted array type: */ + typedef fixed_1D type; +}; + +/* Promote 1D dynamic arrays to a 1D dynamic array: */ +template +struct promote +{ + typedef typename A1::value_type left_scalar; + typedef typename A2::value_type right_scalar; + + /* First, promote the scalar type: */ + typedef typename ScalarPromote< + left_scalar,right_scalar>::type promoted_scalar; + + /* Next, rebind to get the proper allocator: */ + typedef typename CML_DEFAULT_ARRAY_ALLOC + ::rebind::other allocator; + + /* Finally, generate the promoted array type: */ + typedef dynamic_1D type; +}; + +/* Promote fixed 2D+1D array expressions to a fixed 1D array: */ +template +struct promote +{ + typedef typename A1::value_type left_scalar; + typedef typename A2::value_type right_scalar; + + /* First, promote the scalar type: */ + typedef typename ScalarPromote< + left_scalar,right_scalar>::type promoted_scalar; + + /* Next, deduce the array size: */ + enum { Size = (size_t)A1::array_rows }; + + /* Finally, generate the promoted array type: */ + typedef fixed_1D type; +}; + +/* Promote fixed 1D+2D array expressions to a fixed 1D array: */ +template +struct promote +{ + typedef typename A1::value_type left_scalar; + typedef typename A2::value_type right_scalar; + + /* First, promote the scalar type: */ + typedef typename ScalarPromote< + left_scalar,right_scalar>::type promoted_scalar; + + /* Next, deduce the array size: */ + enum { Size = (size_t)A2::array_cols }; + + /* Finally, generate the promoted array type: */ + typedef fixed_1D type; +}; + +/* Promote dynamic 2D+1D array expression to a 1D dynamic array: */ +template +struct promote +{ + typedef typename A1::value_type left_scalar; + typedef typename A2::value_type right_scalar; + + /* First, promote the scalar type: */ + typedef typename ScalarPromote< + left_scalar,right_scalar>::type promoted_scalar; + + /* Next, rebind to get the proper allocator: */ + typedef typename CML_DEFAULT_ARRAY_ALLOC + ::rebind::other allocator; + + /* Finally, generate the promoted array type: */ + typedef dynamic_1D type; +}; + +/* Promote dynamic 1D+2D array expression to a 1D dynamic array: */ +template +struct promote +{ + typedef typename A1::value_type left_scalar; + typedef typename A2::value_type right_scalar; + + /* First, promote the scalar type: */ + typedef typename ScalarPromote< + left_scalar,right_scalar>::type promoted_scalar; + + /* Next, rebind to get the proper allocator: */ + typedef typename CML_DEFAULT_ARRAY_ALLOC + ::rebind::other allocator; + + /* Finally, generate the promoted array type: */ + typedef dynamic_1D type; +}; + + +/* This is a helper to deduce the result of a promoted 2D array: */ +template struct deduce_layout { +#if defined(CML_ALWAYS_PROMOTE_TO_DEFAULT_LAYOUT) + typedef CML_DEFAULT_ARRAY_LAYOUT promoted_layout; +#else + typedef typename select_if< + same_type::is_true, LeftL, + CML_DEFAULT_ARRAY_LAYOUT>::result promoted_layout; +#endif +}; + +/* Promote 2D fixed-size arrays to a 2D fixed-size array. The resulting + * matrix has the same number of rows as A1, and the same number of + * columns as A2. + */ +template +struct promote +{ + typedef typename A1::value_type left_scalar; + typedef typename A2::value_type right_scalar; + + /* First, promote the scalar type: */ + typedef typename ScalarPromote< + left_scalar,right_scalar>::type promoted_scalar; + + /* Next, deduce the array size: */ + enum { + Rows = (size_t)A1::array_rows, + Cols = (size_t)A2::array_cols + }; + + /* Then deduce the array layout: */ + typedef typename A1::layout left_layout; + typedef typename A2::layout right_layout; + typedef typename deduce_layout + ::promoted_layout promoted_layout; + + /* Finally, generate the promoted array type: */ + typedef fixed_2D type; +}; + +/* Promote 2D dynamic arrays to a 2D dynamic array: */ +template +struct promote +{ + typedef typename A1::value_type left_scalar; + typedef typename A2::value_type right_scalar; + + /* First, promote the scalar type: */ + typedef typename ScalarPromote< + left_scalar,right_scalar>::type promoted_scalar; + + /* Next, rebind to get the proper allocator: */ + typedef typename CML_DEFAULT_ARRAY_ALLOC + ::rebind::other allocator; + + /* Then deduce the array layout: */ + typedef typename A1::layout left_layout; + typedef typename A2::layout right_layout; + typedef typename deduce_layout + ::promoted_layout promoted_layout; + + /* Finally, generate the promoted array type: */ + typedef dynamic_2D type; +}; + +} // namespace detail + +/** Class to promote array types. + * + * Both arguments must be array types. + * + * @sa fixed_1D + * @sa fixed_2D + * @sa dynamic_1D + * @sa dynamic_2D + */ +template +struct ArrayPromote +{ + /* Shorthand: */ + //typedef typename A1::value_type left_scalar; + //typedef typename A2::value_type right_scalar; + typedef typename A1::dimension_tag left_dtag; + typedef typename A2::dimension_tag right_dtag; + + /* Deduce the proper type based upon the characteristics of AT1 and + * AT2. This is the table of type conversions: + * + * AT1 AT2 Result + * memory size memory size memory size + * + * fixed fixed fixed fixed fixed fixed + * fixed fixed dynamic dynamic dynamic dynamic + * fixed fixed external fixed fixed fixed + * fixed fixed external dynamic dynamic dynamic + * + * dynamic dynamic fixed fixed dynamic dynamic + * dynamic dynamic dynamic dynamic dynamic dynamic + * dynamic dynamic external fixed dynamic dynamic + * dynamic dynamic external dynamic dynamic dynamic + * + * external fixed external fixed fixed fixed + * external fixed fixed fixed fixed fixed + * external fixed dynamic dynamic dynamic dynamic + * external fixed external dynamic dynamic dynamic + * + * external dynamic external fixed dynamic dynamic + * external dynamic fixed fixed dynamic dynamic + * external dynamic dynamic dynamic dynamic dynamic + * external dynamic external dynamic dynamic dynamic + * + * Note that if one argument is a dynamically-sized array, the result + * must be a dynamically allocated and sized array. Likewise, if both + * arguments have fixed size, the result can be a fixed-sized array. + */ + + /* Check if both arguments are fixed-size arrays. If so, the promoted + * array will be a fixed array, and if not, it will be a dynamic array: + */ + typedef typename select_if< + (same_type::is_true + && same_type::is_true), + fixed_size_tag, /* True */ + dynamic_size_tag /* False */ + >::result promoted_size_tag; + + /* Deduce the promoted type: */ + typedef typename detail::promote< + A1, A2, left_dtag, right_dtag, promoted_size_tag>::type type; +}; + +/* Cleanup internal macros: */ +#undef VAL_MAX + +} // namespace et +} // namespace cml + +#endif + +// ------------------------------------------------------------------------- +// vim:ft=cpp diff --git a/Lib/Include/CML/et/scalar_ops.h b/Lib/Include/CML/et/scalar_ops.h new file mode 100644 index 0000000..6bd236d --- /dev/null +++ b/Lib/Include/CML/et/scalar_ops.h @@ -0,0 +1,138 @@ +/* -*- C++ -*- ------------------------------------------------------------ + +Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/ + +The Configurable Math Library (CML) is distributed under the terms of the +Boost Software License, v1.0 (see cml/LICENSE for details). + + *-----------------------------------------------------------------------*/ +/** @file + * @brief + */ + +#ifndef ops_h +#define ops_h + +#include +#include + +/** Declare a unary scalar operator, like negation. */ +#define CML_UNARY_SCALAR_OP(_op_, _op_name_) \ +template struct _op_name_ { \ + typedef ExprTraits arg_traits; \ + typedef typename arg_traits::const_reference arg_reference; \ + typedef typename arg_traits::value_type value_type; \ + typedef scalar_result_tag result_tag; \ + value_type apply(arg_reference arg) const { return _op_ arg; } \ +}; + +/** Declare a binary scalar operator, like addition, s1+s2. */ +#define CML_BINARY_SCALAR_OP(_op_, _op_name_) \ +template struct _op_name_ { \ + typedef ExprTraits left_traits; \ + typedef ExprTraits right_traits; \ + typedef typename left_traits::const_reference left_reference; \ + typedef typename right_traits::const_reference right_reference; \ + typedef typename left_traits::value_type left_value; \ + typedef typename right_traits::value_type right_value; \ + typedef typename ScalarPromote::type value_type; \ + typedef scalar_result_tag result_tag; \ + value_type apply(left_reference left, right_reference right) const { \ + return left _op_ right; } \ +}; + +/** Declare an op-assignment operator. + * + * @note The ExprTraits for both argument types must be defined, LeftT must + * have an assignment operator, and ExprTraits::reference must specify + * a type that allows assignment. + */ +#define CML_BINARY_SCALAR_OP_ASSIGN(_op_, _op_name_) \ +template struct _op_name_ { \ + typedef ExprTraits left_traits; \ + typedef ExprTraits right_traits; \ + typedef typename left_traits::reference left_reference; \ + typedef typename right_traits::const_reference right_reference; \ + typedef typename left_traits::value_type left_value; \ + typedef typename right_traits::value_type right_value; \ + typedef typename ScalarPromote::type value_type; \ + typedef scalar_result_tag result_tag; \ + value_type apply(left_reference left, right_reference right) const { \ + return left _op_ (LeftT) right; } \ +}; + +/** Declare a binary boolean operator, like less-than, s1 < s2. + * + * The operator should return the appropriate truth value for the operator. + * + * @note Both scalar types must have operator<() defined. + */ +#define CML_BOOLEAN_SCALAR_OP(_op_, _op_name_) \ +template struct _op_name_ { \ + typedef ExprTraits left_traits; \ + typedef ExprTraits right_traits; \ + typedef typename left_traits::const_reference left_reference; \ + typedef typename right_traits::const_reference right_reference; \ + typedef scalar_result_tag result_tag; \ + bool apply(left_reference left, right_reference right) const { \ + return left _op_ right; } \ +}; + +namespace cml { +namespace et { + +/* Define the operators: */ + +/* Unary scalar ops: */ +CML_UNARY_SCALAR_OP(-, OpNeg) +CML_UNARY_SCALAR_OP(+, OpPos) + +/* Binary scalar ops: */ +CML_BINARY_SCALAR_OP(+, OpAdd) +CML_BINARY_SCALAR_OP(-, OpSub) +CML_BINARY_SCALAR_OP(*, OpMul) + +#if defined(CML_RECIPROCAL_OPTIMIZATION) +/* XXX Yikes... this should really be written out in full. *= 1./ is the + * "_op_" parameter to the macro (see above): + */ +CML_BINARY_SCALAR_OP(* value_type(1)/, OpDiv) +#else +CML_BINARY_SCALAR_OP(/, OpDiv) +#endif + +/* Binary scalar op-assigns: */ +CML_BINARY_SCALAR_OP_ASSIGN( =, OpAssign) +CML_BINARY_SCALAR_OP_ASSIGN(+=, OpAddAssign) +CML_BINARY_SCALAR_OP_ASSIGN(-=, OpSubAssign) +CML_BINARY_SCALAR_OP_ASSIGN(*=, OpMulAssign) + +#if defined(CML_RECIPROCAL_OPTIMIZATION) +/* XXX Yikes... this should really be written out in full. *= 1./ is the + * "_op_" parameter to the macro (see above): + */ +CML_BINARY_SCALAR_OP_ASSIGN(*= value_type(1)/, OpDivAssign) +#else +CML_BINARY_SCALAR_OP_ASSIGN(/=, OpDivAssign) +#endif + +/* Boolean operators for scalars: */ +CML_BOOLEAN_SCALAR_OP(==, OpEqual) +CML_BOOLEAN_SCALAR_OP(!=, OpNotEqual) +CML_BOOLEAN_SCALAR_OP( <, OpLess) +CML_BOOLEAN_SCALAR_OP( >, OpGreater) +CML_BOOLEAN_SCALAR_OP(<=, OpLessEqual) +CML_BOOLEAN_SCALAR_OP(>=, OpGreaterEqual) + +#undef CML_UNARY_SCALAR_OP +#undef CML_BINARY_SCALAR_OP +#undef CML_BINARY_SCALAR_OP_ASSIGN +#undef CML_BOOLEAN_SCALAR_OP + +} // namespace et +} // namespace cml + +#endif + +// ------------------------------------------------------------------------- +// vim:ft=cpp diff --git a/Lib/Include/CML/et/scalar_promotions.h b/Lib/Include/CML/et/scalar_promotions.h new file mode 100644 index 0000000..5c6a4a1 --- /dev/null +++ b/Lib/Include/CML/et/scalar_promotions.h @@ -0,0 +1,151 @@ +/* -*- C++ -*- ------------------------------------------------------------ + +Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/ + +The Configurable Math Library (CML) is distributed under the terms of the +Boost Software License, v1.0 (see cml/LICENSE for details). + + *-----------------------------------------------------------------------*/ +/** @file + * @brief + */ + +#ifndef scalar_promotions_h +#define scalar_promotions_h + +#include +#include + +namespace cml { +namespace et { + +/* The type promotion code below is a slightly modified version of: + * http://ubiety.uwaterloo.ca/~tveldhui/papers/techniques/techniques01.html + */ +namespace detail { + +template +struct precision_trait { + enum { precisionRank = 0, + knowPrecisionRank = 0 }; +}; + +#define DECLARE_PRECISION(T,rank) \ + template<> \ + struct precision_trait< T > { \ + enum { precisionRank = rank, \ + knowPrecisionRank = 1 }; \ + }; + +DECLARE_PRECISION(int,100) +DECLARE_PRECISION(unsigned int,200) +DECLARE_PRECISION(long,300) +DECLARE_PRECISION(unsigned long,400) + +DECLARE_PRECISION(long long,425) +DECLARE_PRECISION(unsigned long long,475) + +DECLARE_PRECISION(float,500) +DECLARE_PRECISION(double,600) +DECLARE_PRECISION(long double,700) +DECLARE_PRECISION(std::complex,800) +DECLARE_PRECISION(std::complex,900) +DECLARE_PRECISION(std::complex,1000) + +template +struct autopromote_trait { + typedef T T_numtype; +}; + +#define DECLARE_AUTOPROMOTE(T1,T2) \ + template<> \ + struct autopromote_trait { \ + typedef T2 T_numtype; \ + }; + +// These are the odd cases where small integer types +// are automatically promoted to int or unsigned int for +// arithmetic. +DECLARE_AUTOPROMOTE(bool, int) +DECLARE_AUTOPROMOTE(char, int) +DECLARE_AUTOPROMOTE(unsigned char, int) +DECLARE_AUTOPROMOTE(short int, int) +DECLARE_AUTOPROMOTE(short unsigned int, unsigned int) + +template +struct promote2 { + typedef T1 T_promote; +}; + +template +struct promote2 { + typedef T2 T_promote; +}; + +template +struct promote_trait { + + // Need to remove const-ness: + typedef typename cml::remove_const::type T1_non_const; + typedef typename cml::remove_const::type T2_non_const; + + // Handle promotion of small integers to int/unsigned int + typedef typename autopromote_trait::T_numtype T1; + typedef typename autopromote_trait::T_numtype T2; + + // True if T1 is higher ranked + enum { + T1IsBetter = + (int) precision_trait::precisionRank > + (int) precision_trait::precisionRank, + + // True if we know ranks for both T1 and T2 + knowBothRanks = + precision_trait::knowPrecisionRank + && precision_trait::knowPrecisionRank, + + // True if we know T1 but not T2 + knowT1butNotT2 = precision_trait::knowPrecisionRank + && !(precision_trait::knowPrecisionRank), + + // True if we know T2 but not T1 + knowT2butNotT1 = precision_trait::knowPrecisionRank + && !(precision_trait::knowPrecisionRank), + + // True if T1 is bigger than T2 + T1IsLarger = sizeof(T1) >= sizeof(T2), + + // We know T1 but not T2: true + // We know T2 but not T1: false + // Otherwise, if T1 is bigger than T2: true + defaultPromotion = knowT1butNotT2 ? false : + (knowT2butNotT1 ? true : T1IsLarger) + }; + + // If we have both ranks, then use them. + // If we have only one rank, then use the unknown type. + // If we have neither rank, then promote to the larger type. + + enum { + promoteToT1 = (knowBothRanks ? T1IsBetter : defaultPromotion) + ? 1 : 0 + }; + + typedef typename promote2::T_promote T_promote; +}; + +} // namespace detail + +/** Defers to detail::promote_trait<>. */ +template struct ScalarPromote +{ + typedef typename detail::promote_trait::T_promote type; +}; + +} // namespace et +} // namespace cml + +#endif + +// ------------------------------------------------------------------------- +// vim:ft=cpp diff --git a/Lib/Include/CML/et/size_checking.h b/Lib/Include/CML/et/size_checking.h new file mode 100644 index 0000000..b8ed560 --- /dev/null +++ b/Lib/Include/CML/et/size_checking.h @@ -0,0 +1,431 @@ +/* -*- C++ -*- ------------------------------------------------------------ + +Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/ + +The Configurable Math Library (CML) is distributed under the terms of the +Boost Software License, v1.0 (see cml/LICENSE for details). + + *-----------------------------------------------------------------------*/ +/** @file + * @brief + * + * Define matrix and vector linear expression size-checking classes. + */ + +#ifndef size_checking_h +#define size_checking_h + +#include +#include +#include +#include +#include + +#if defined(_MSC_VER) && _MSC_VER < 1400 +#pragma warning(push) +#pragma warning(disable:4348) +// XXX This is a terrible hack for VC7.1, and should really be fixed by +// separating out the "impl" templates from GetCheckedSize. +#endif + +/* This is used below to create a more meaningful compile-time error when + * fixed-size vector arguments don't match at compile time: + */ +struct incompatible_expression_size_error; + +/* This is used below to create a more meaningful compile-time error when a + * function is not provided with a square matrix or MatrixExpr argument: + */ +struct square_matrix_arg_expected_error; + +namespace cml { +namespace et { +namespace detail { + +} // namespace detail + +/* Forward declare for specialization below: */ +template + struct GetCheckedSize; + +/* Checking for fixed-size expression: */ +template +struct GetCheckedSize +{ + /* Record argument traits: */ + typedef ExprTraits left_traits; + typedef ExprTraits right_traits; + + /* Result types: */ + typedef typename left_traits::result_tag left_result; + typedef typename right_traits::result_tag right_result; + + + /* For specialization below: */ + template struct impl; + + /* Check for two matrices (linear operators only): */ + template struct impl { + typedef matrix_size size_type; + CML_STATIC_REQUIRE_M( + (size_t)LeftT::array_rows == (size_t)RightT::array_rows + && (size_t)LeftT::array_cols == (size_t)RightT::array_cols, + incompatible_expression_size_error); + + /* Record the array size as a constant: */ + enum { + array_rows = LeftT::array_rows, + array_cols = LeftT::array_cols + }; + + /* Return the matrix size: */ + size_type size() const { return size_type(array_rows,array_cols); } + }; + + /* Check for a matrix and a vector: */ + template struct impl { + typedef size_t size_type; + CML_STATIC_REQUIRE_M( + (size_t)LeftT::array_cols == (size_t)RightT::array_size, + incompatible_expression_size_error); + + /* Record the array size as a constant: */ + enum { array_size = LeftT::array_rows }; + + /* Return the vector size: */ + size_type size() const { return size_type(array_size); } + }; + + /* Check for a vector and a matrix: */ + template struct impl { + typedef size_t size_type; + CML_STATIC_REQUIRE_M( + (size_t)LeftT::array_size == (size_t)RightT::array_rows, + incompatible_expression_size_error); + + /* Record the array size as a constant: */ + enum { array_size = RightT::array_cols }; + + /* Return the vector size: */ + size_type size() const { return size_type(array_size); } + }; + + /* Check for a matrix and a scalar: */ + template struct impl { + typedef matrix_size size_type; + + /* Record the array size as a constant: */ + enum { + array_rows = LeftT::array_rows, + array_cols = LeftT::array_cols + }; + + /* Return the matrix size: */ + size_type size() const { return size_type(array_rows,array_cols); } + }; + + /* Check for a scalar and a matrix: */ + template struct impl { + typedef matrix_size size_type; + + /* Record the array size as a constant: */ + enum { + array_rows = RightT::array_rows, + array_cols = RightT::array_cols + }; + + /* Return the matrix size: */ + size_type size() const { return size_type(array_rows,array_cols); } + }; + + + /* Check for two vectors: */ + template struct impl { + typedef size_t size_type; + CML_STATIC_REQUIRE_M( + (size_t)LeftT::array_size == (size_t)RightT::array_size, + incompatible_expression_size_error); + + /* Record the array size as a constant: */ + enum { array_size = LeftT::array_size }; + + /* Return the vector size: */ + size_type size() const { return size_type(array_size); } + }; + + /* Check for a vector and a scalar: */ + template struct impl { + typedef size_t size_type; + + /* Record the array size as a constant: */ + enum { array_size = LeftT::array_size }; + + /* Return the vector size: */ + size_type size() const { return size_type(array_size); } + }; + + /* Check for a scalar and a vector: */ + template struct impl { + typedef size_t size_type; + + /* Record the array size as a constant: */ + enum { array_size = RightT::array_size }; + + /* Return the vector size: */ + size_type size() const { return size_type(array_size); } + }; + + + /* Check for two quaternions: */ + template + struct impl { + typedef size_t size_type; + + /* Record the quaternion size as a constant: */ + enum { array_size = 4 }; + + /* Return the quaternion size: */ + size_type size() const { return size_type(array_size); } + }; + + /* Check for a quaternion and a vector: */ + template struct impl { + typedef size_t size_type; + CML_STATIC_REQUIRE_M( + RightT::array_size == 4, + incompatible_expression_size_error); + + /* Record the quaternion size as a constant: */ + enum { array_size = 4 }; + + /* Return the quaternion size: */ + size_type size() const { return size_type(array_size); } + }; + + /* Check for a vector and a quaternion: */ + template struct impl { + typedef size_t size_type; + CML_STATIC_REQUIRE_M( + LeftT::array_size == 4, + incompatible_expression_size_error); + + /* Record the quaternion size as a constant: */ + enum { array_size = 4 }; + + /* Return the quaternion size: */ + size_type size() const { return size_type(array_size); } + }; + + /* Check for a quaternion and a scalar: */ + template struct impl { + typedef size_t size_type; + + /* Record the quaternion size as a constant: */ + enum { array_size = 4 }; + + /* Return the quaternion size: */ + size_type size() const { return size_type(array_size); } + }; + + /* Check for a scalar and a quaternion: */ + template struct impl { + typedef size_t size_type; + + /* Record the array size as a constant: */ + enum { array_size = 4 }; + + /* Return the quaternion size: */ + size_type size() const { return size_type(array_size); } + }; + + /* Record the type of the checker: */ + typedef impl check_type; + typedef typename check_type::size_type size_type; + + /* The implementation: */ + size_type operator()(const LeftT&, const RightT&) const { + return check_type().size(); + } +}; + +/* Checking for resizeable expression: */ +template +struct GetCheckedSize +{ + /* Type of the size checker (for calling equal_or_fail): */ + typedef GetCheckedSize self; + + /* Record argument traits: */ + typedef ExprTraits left_traits; + typedef ExprTraits right_traits; + + /* Result types: */ + typedef typename left_traits::result_tag left_result; + typedef typename right_traits::result_tag right_result; + + + /* For specialization below: */ + template struct impl; + + /* Return the size if the same, or fail if different: */ + template V equal_or_fail(V left, V right) const { + if(left != right) + throw std::invalid_argument( + "expressions have incompatible sizes."); + return left; + } + + /* Check for two matrices (linear operators only): */ + template struct impl { + typedef matrix_size size_type; + + /* Return the matrix size, or fail if incompatible: */ + size_type size(const LeftT& left, const RightT& right) const { +#if defined(CML_CHECK_MATRIX_EXPR_SIZES) + return self().equal_or_fail(left.size(), right.size()); +#else + return left.size(); +#endif + } + }; + + /* Check for a matrix and a vector: */ + template struct impl { + typedef size_t size_type; + + /* Return the vector size: */ +#if defined(CML_CHECK_MATVEC_EXPR_SIZES) + size_type size(const LeftT& left, const RightT& right) const +#else + size_type size(const LeftT& left, const RightT& /*right*/) const +#endif + { +#if defined(CML_CHECK_MATVEC_EXPR_SIZES) + self().equal_or_fail(left.cols(), right.size()); +#endif + return left.rows(); + } + }; + + /* Check for a vector and a matrix: */ + template struct impl { + typedef size_t size_type; + + /* Return the vector size: */ + size_type size(const LeftT& left, const RightT& right) const { +#if defined(CML_CHECK_MATVEC_EXPR_SIZES) + self().equal_or_fail(left.size(), right.rows()); +#endif + return right.cols(right); + } + }; + + /* Check for a matrix and a scalar: */ + template struct impl { + typedef matrix_size size_type; + + /* Return the matrix size: */ + size_type size(const LeftT& left, const RightT&) const { + return left.size(); + } + }; + + /* Check for a scalar and a matrix: */ + template struct impl { + typedef matrix_size size_type; + + /* Return the matrix size: */ + size_type size(const LeftT&, const RightT& right) const { + return right.size(); + } + }; + + /* Check for two vectors: */ + template struct impl { + typedef size_t size_type; + + /* Return the vector size: */ + size_type size(const LeftT& left, const RightT& right) const { +#if defined(CML_CHECK_VECTOR_EXPR_SIZES) + return self().equal_or_fail(left.size(), right.size()); +#else + return left.size(); +#endif + } + }; + + /* Check for a vector and a scalar: */ + template struct impl { + typedef size_t size_type; + + /* Return the vector size: */ + size_type size(const LeftT& left, const RightT&) const { + return left.size(); + } + }; + + /* Check for a scalar and a vector: */ + template struct impl { + typedef size_t size_type; + + /* Return the vector size: */ + size_type size(const LeftT&, const RightT& right) const { + return right.size(); + } + }; + + /* Record the type of the checker: */ + typedef impl check_type; + typedef typename check_type::size_type size_type; + + /* The implementation: */ + size_type operator()(const LeftT& left, const RightT& right) const { + return check_type().size(left,right); + } +}; + +/** Generator for GetCheckedSize. */ +template +inline typename et::GetCheckedSize::size_type +CheckedSize(const LeftT& left, const RightT& right, SizeTag) +{ + return et::GetCheckedSize()(left,right); +} + +/** Verify the sizes of the argument matrices for matrix multiplication. + * + * @returns a the size of the resulting matrix. + */ +template inline size_t +CheckedSquare(const MatT&, fixed_size_tag) +{ + CML_STATIC_REQUIRE_M( + ((size_t)MatT::array_rows == (size_t)MatT::array_cols), + square_matrix_arg_expected_error); + return (size_t)MatT::array_rows; +} + +/** Verify the sizes of the argument matrices for matrix multiplication. + * + * @returns the size of the resulting matrix. + */ +template inline size_t +CheckedSquare(const MatT& m, dynamic_size_tag) +{ + matrix_size N = m.size(); + et::GetCheckedSize() + .equal_or_fail(N.first, N.second); + return N.first; +} + +} // namespace et +} // namespace cml + +#if defined(_MSC_VER) && _MSC_VER < 1400 +#pragma warning(pop) +#endif + +#endif + +// ------------------------------------------------------------------------- +// vim:ft=cpp diff --git a/Lib/Include/CML/et/tags.h b/Lib/Include/CML/et/tags.h new file mode 100644 index 0000000..a940134 --- /dev/null +++ b/Lib/Include/CML/et/tags.h @@ -0,0 +1,55 @@ +/* -*- C++ -*- ------------------------------------------------------------ + +Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/ + +The Configurable Math Library (CML) is distributed under the terms of the +Boost Software License, v1.0 (see cml/LICENSE for details). + + *-----------------------------------------------------------------------*/ +/** @file + * @brief + */ + +#ifndef et_tags_h +#define et_tags_h + +namespace cml { +namespace et { + +/** Tag an expression as returning a scalar. */ +struct scalar_result_tag {}; + +/** Tag an expression as returning a vector. */ +struct vector_result_tag {}; + +/** Tag an expression as returning a matrix. */ +struct matrix_result_tag {}; + +/** Tag an expression as returning a quaternion. */ +struct quaternion_result_tag {}; + +/** Marker for unary expression ops. */ +struct unary_expression {}; + +/** Marker for biary expression ops. */ +struct binary_expression {}; + +/** Marker for expression tree operator nodes. */ +struct expr_node_tag {}; + +/** Marker for expression tree terminals (leaves). */ +struct expr_leaf_tag {}; + +/** Marker for assignable types. */ +struct assignable_tag {}; + +/** Marker for assignable types. */ +struct not_assignable_tag {}; + +} // namespace et +} // namespace cml + +#endif + +// ------------------------------------------------------------------------- +// vim:ft=cpp diff --git a/Lib/Include/CML/et/traits.h b/Lib/Include/CML/et/traits.h new file mode 100644 index 0000000..0e59e4b --- /dev/null +++ b/Lib/Include/CML/et/traits.h @@ -0,0 +1,143 @@ +/* -*- C++ -*- ------------------------------------------------------------ + +Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/ + +The Configurable Math Library (CML) is distributed under the terms of the +Boost Software License, v1.0 (see cml/LICENSE for details). + + *-----------------------------------------------------------------------*/ +/** @file + * @brief + */ + +#ifndef traits_h +#define traits_h + +#include + +/* XXX This is here temporarily, should be rolled into the traits classes + * once it's clear how to best specify scalar args + */ +//#define SCALAR_ARG_TYPE const ScalarT& +//#define ELEMENT_ARG_TYPE const Element& +#define SCALAR_ARG_TYPE ScalarT +#define ELEMENT_ARG_TYPE Element + +namespace cml { +namespace et { + +/** The expression traits class. + * + * The traits class is used to provide uniform access to expression + * objects, including scalars, when used in vector and matrix expressions. + * One especially useful property for scalars is that scalars are + * implicitly "promoted" to vectors or scalars as necessary via the + * ExprTraits's get() method. Without this functionality, a separate + * expression tree node would be needed to hold a scalar, which would + * adversely affect performance. + * + * @internal This is also currently used for determining traits of scalar + * types from the scalar operators (+,-,etc.). Really, a separate traits + * class should probably be used for this (e.g. ScalarTraits). + */ +template struct ExprTraits +#if defined(CML_NO_DEFAULT_EXPR_TRAITS) +/* For testing, don't default to scalar traits: */ +#else +{ + /* Standard: */ + typedef T expr_type; + typedef T value_type; + typedef T& reference; + typedef T const_reference; + typedef scalar_result_tag result_tag; + typedef fixed_memory_tag memory_tag; + typedef unit_size_tag size_tag; + typedef expr_type result_type; + typedef expr_leaf_tag node_tag; + + /** Vector-like access, just returns the value. */ + value_type get(const_reference v, size_t) const { return v; } + + /** Matrix-like access, just returns the value. */ + value_type get(const_reference v, size_t, size_t) const { return v; } + + /** Size is always 1. */ + size_t size(const_reference) const { return 1; } + + /** Size is always 1. */ + size_t rows(double) const { return 1; } + + /** Size is always 1. */ + size_t cols(double) const { return 1; } +} +#endif +; + +#if defined(CML_NO_DEFAULT_EXPR_TRAITS) +template<> struct ExprTraits +{ + /* Standard: */ + typedef double expr_type; + typedef double value_type; + typedef double& reference; + typedef double const_reference; + typedef scalar_result_tag result_tag; + typedef fixed_memory_tag memory_tag; + typedef unit_size_tag size_tag; + typedef double result_type; + typedef expr_leaf_tag node_tag; + + /** Vector-like access, just returns the value. */ + value_type get(double v, size_t) const { return v; } + + /** Matrix-like access, just returns the value. */ + value_type get(double v, size_t, size_t) const { return v; } + + /** Size is always 1. */ + size_t size(double) const { return 1; } + + /** Size is always 1. */ + size_t rows(double) const { return 1; } + + /** Size is always 1. */ + size_t cols(double) const { return 1; } +}; + +template<> struct ExprTraits +{ + /* Standard: */ + typedef float expr_type; + typedef float value_type; + typedef float& reference; + typedef float const_reference; + typedef scalar_result_tag result_tag; + typedef fixed_memory_tag memory_tag; + typedef unit_size_tag size_tag; + typedef float result_type; + typedef expr_leaf_tag node_tag; + + /** Vector-like access, just returns the value. */ + value_type get(float v, size_t) const { return v; } + + /** Matrix-like access, just returns the value. */ + value_type get(float v, size_t, size_t) const { return v; } + + /** Size is always 1. */ + size_t size(float) const { return 1; } + + /** Size is always 1. */ + size_t rows(float) const { return 1; } + + /** Size is always 1. */ + size_t cols(float) const { return 1; } +}; +#endif + +} // namespace et +} // namespace cml + +#endif + +// ------------------------------------------------------------------------- +// vim:ft=cpp diff --git a/Lib/Include/CML/external.h b/Lib/Include/CML/external.h new file mode 100644 index 0000000..cc052e7 --- /dev/null +++ b/Lib/Include/CML/external.h @@ -0,0 +1,41 @@ +/* -*- C++ -*- ------------------------------------------------------------ + +Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/ + +The Configurable Math Library (CML) is distributed under the terms of the +Boost Software License, v1.0 (see cml/LICENSE for details). + + *-----------------------------------------------------------------------*/ +/** @file + * @brief + */ + +#ifndef external_h +#define external_h + +namespace cml { + +/** This is a selector for external 1D and 2D arrays. + * + * The external<> struct is used only to select a 1D or 2D array as the + * base class of a vector or matrix. The rebind<> template is used by + * quaternion<> to select its vector length in a generic way. + * + * @sa fixed + * @sa dynamic + */ +template struct external { + + /** Rebind to a 1D type. + * + * This is used by quaternion<>. + */ + template struct rebind { typedef external other; }; +}; + +} // namespace cml + +#endif + +// ------------------------------------------------------------------------- +// vim:ft=cpp diff --git a/Lib/Include/CML/fixed.h b/Lib/Include/CML/fixed.h new file mode 100644 index 0000000..536eb3c --- /dev/null +++ b/Lib/Include/CML/fixed.h @@ -0,0 +1,42 @@ +/* -*- C++ -*- ------------------------------------------------------------ + +Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/ + +The Configurable Math Library (CML) is distributed under the terms of the +Boost Software License, v1.0 (see cml/LICENSE for details). + + *-----------------------------------------------------------------------*/ +/** @file + * @brief + */ + +#ifndef fixed_h +#define fixed_h + +namespace cml { + + +/** This is a selector for fixed 1D and 2D arrays. + * + * The fixed<> struct is used only to select a 1D or 2D array as the base + * class of a vector or matrix. The rebind<> template is used by + * quaternion<> to select its vector length in a generic way. + * + * @sa dynamic + * @sa external + */ +template struct fixed { + + /** Rebind to a 1D type. + * + * This is used by quaternion<>. + */ + template struct rebind { typedef fixed other; }; +}; + +} // namespace cml + +#endif + +// ------------------------------------------------------------------------- +// vim:ft=cpp diff --git a/Lib/Include/CML/mathlib/checking.h b/Lib/Include/CML/mathlib/checking.h new file mode 100644 index 0000000..36a7ced --- /dev/null +++ b/Lib/Include/CML/mathlib/checking.h @@ -0,0 +1,382 @@ +/* -*- C++ -*- ------------------------------------------------------------ + +Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/ + +The Configurable Math Library (CML) is distributed under the terms of the +Boost Software License, v1.0 (see cml/LICENSE for details). + + *-----------------------------------------------------------------------*/ +/** @file + * @brief + */ + +#ifndef checking_h +#define checking_h + +#include +#include +#include + +/* Run- and compile-time checking of argument types, values and sizes. */ + +struct function_expects_vector_arg_error; +struct function_expects_matrix_arg_error; +struct function_expects_quaternion_arg_error; + +struct function_expects_2D_vector_arg_error; +struct function_expects_3D_vector_arg_error; +struct function_expects_4D_vector_arg_error; +struct function_expects_2D_or_3D_vector_arg_error; +struct function_expects_2x2_matrix_arg_error; +struct function_expects_3x3_matrix_arg_error; +struct function_expects_4x4_matrix_arg_error; +struct function_expects_square_matrix_arg_error; + +struct matrix_arg_fails_minimum_size_requirement; + +namespace cml { +namespace detail { + +////////////////////////////////////////////////////////////////////////////// +// Vector argument checking +////////////////////////////////////////////////////////////////////////////// + +/** Compile-time check for a vector argument */ +template< class VecT > inline void +CheckVec(const VecT&) +{ + typedef et::ExprTraits vector_traits; + typedef typename vector_traits::result_tag result_type; + + CML_STATIC_REQUIRE_M( + (same_type::is_true), + function_expects_vector_arg_error); +} + +/** Compile-time check for a vector of size N */ +template< class VecT, size_t N, class ErrorT > inline void +CheckVecN(const VecT& v, fixed_size_tag) { + CheckVec(v); + + CML_STATIC_REQUIRE_M(((size_t)VecT::array_size == N), ErrorT); +} + +/** Run-time check for a vector of size N */ +template< class VecT, size_t N, class /*ErrorT*/ > inline void +CheckVecN(const VecT& v, dynamic_size_tag) { + CheckVec(v); + + et::GetCheckedSize() + .equal_or_fail(v.size(),size_t(N)); +} + +/** Check for a vector of size N */ +template< class VecT, size_t N, class ErrorT > inline void +CheckVecN(const VecT& v) { + typedef et::ExprTraits vector_traits; + typedef typename vector_traits::size_tag size_tag; + + detail::CheckVecN(v, size_tag()); +} + +/** Check for a vector of size 2 */ +template< class VecT > inline void +CheckVec2(const VecT& v) { + detail::CheckVecN(v); +} + +/** Check for a vector of size 3 */ +template< class VecT > inline void +CheckVec3(const VecT& v) { + detail::CheckVecN(v); +} + +/** Check for a vector of size 4 */ +template< class VecT > inline void +CheckVec4(const VecT& v) { + CheckVecN(v); +} + +/** Compile-time check for a vector of size 2 or 3 */ +template< class VecT > inline void +CheckVec2Or3(const VecT& v, fixed_size_tag) { + CheckVec(v); + + CML_STATIC_REQUIRE_M( + (VecT::array_size == 2 || VecT::array_size == 3), + function_expects_2D_or_3D_vector_arg_error); +} + +/** Run-time check for a vector of size 2 or 3 */ +template< class VecT > inline void +CheckVec2Or3(const VecT& v, dynamic_size_tag) { + CheckVec(v); + + if (v.size() != 2 && v.size() != 3) { + throw std::invalid_argument("2d or 3d vector arg expected"); + } +} + +/** Check for a vector of size 2 or 3 */ +template< class VecT > inline void +CheckVec2Or3(const VecT& v) { + typedef et::ExprTraits vector_traits; + typedef typename vector_traits::size_tag size_tag; + + detail::CheckVec2Or3(v, size_tag()); +} + +////////////////////////////////////////////////////////////////////////////// +// Matrix argument checking +////////////////////////////////////////////////////////////////////////////// + +/** Compile-time check for a matrix argument */ +template< class MatT > inline void +CheckMat(const MatT&) +{ + typedef et::ExprTraits matrix_traits; + typedef typename matrix_traits::result_tag result_type; + + CML_STATIC_REQUIRE_M( + (same_type::is_true), + function_expects_matrix_arg_error); +} + +/** Compile-time check for a matrix of size NxM */ +template< class MatT, size_t N, size_t M, class ErrorT > inline void +CheckMatNxM(const MatT& m, fixed_size_tag) { + CheckMat(m); + + CML_STATIC_REQUIRE_M( + (MatT::array_rows == N && MatT::array_cols == M), ErrorT); +} + +/** Run-time check for a matrix of size NxM */ +template< class MatT, size_t N, size_t M, class /*ErrorT*/ > inline void +CheckMatNxM(const MatT& m, dynamic_size_tag) { + CheckMat(m); + + et::GetCheckedSize() + .equal_or_fail(m.rows(),N); + et::GetCheckedSize() + .equal_or_fail(m.cols(),M); +} + +/** Check for a matrix of size NxM */ +template< class MatT, size_t N, size_t M, class ErrorT > inline void +CheckMatNxM(const MatT& m) { + typedef et::ExprTraits matrix_traits; + typedef typename matrix_traits::size_tag size_tag; + + CheckMatNxM(m, size_tag()); +} + +/** Check for a square matrix of size NxN */ +template< class MatT, size_t N, class ErrorT > inline void +CheckMatN(const MatT& m) { + CheckMatNxM(m); +} + +/** Check for a square matrix of size 2x2 */ +template< class MatT > inline void +CheckMat2x2(const MatT& m) { + CheckMatN(m); +} + +/** Check for a square matrix of size 3x3 */ +template< class MatT > inline void +CheckMat3x3(const MatT& m) { + CheckMatN(m); +} + +/** Check for a square matrix of size 4x4 */ +template< class MatT > inline void +CheckMat4x4(const MatT& m) { + CheckMatN(m); +} + +/** Compile-time check for a matrix with minimum dimensions NxM */ +template< class MatT, size_t N, size_t M, class ErrorT > inline void +CheckMatMinNxM(const MatT& m, fixed_size_tag) { + CheckMat(m); + + CML_STATIC_REQUIRE_M( + (MatT::array_rows >= N && MatT::array_cols >= M), ErrorT); +} + +/** Run-time check for a matrix with minimum dimensions NxM */ +template< class MatT, size_t N, size_t M, class /*ErrorT*/ > inline void +CheckMatMinNxM(const MatT& m, dynamic_size_tag) { + CheckMat(m); + + if (m.rows() < N || m.cols() < M) { + throw std::invalid_argument( + "matrix does not meet minimum size requirement"); + } +} + +/** Check for a matrix with minimum dimensions NxM */ +template< class MatT, size_t N, size_t M, class ErrorT > inline void +CheckMatMinNxM(const MatT& m) { + typedef et::ExprTraits matrix_traits; + typedef typename matrix_traits::size_tag size_tag; + + CheckMatMinNxM(m, size_tag()); +} + +/** Check for a matrix with minimum dimensions NxN */ +template< class MatT, size_t N, class ErrorT > inline void +CheckMatMinN(const MatT& m) { + CheckMatMinNxM(m); +} + +/** Check for a matrix with minimum dimensions 2x2 */ +template< class MatT > inline void +CheckMatMin2x2(const MatT& m) { + CheckMatMinN(m); +} + +/** Check for a matrix with minimum dimensions 3x3 */ +template< class MatT > inline void +CheckMatMin3x3(const MatT& m) { + CheckMatMinN(m); +} + +/** Check for a matrix with minimum dimensions 4x4 */ +template< class MatT > inline void +CheckMatMin4x4(const MatT& m) { + CheckMatMinN(m); +} + +/** Check for a matrix that can represent a 3D linear transform */ +template< class MatT > inline void +CheckMatLinear3D(const MatT& m) { + CheckMatMin3x3(m); +} + +/** Check for a matrix that can represent a 2D linear transform */ +template< class MatT > inline void +CheckMatLinear2D(const MatT& m) { + CheckMatMin2x2(m); +} + +/** Check for a matrix that can represent a 3D row-basis affine transform */ +template< class MatT > inline void +CheckMatAffine3D(const MatT& m, row_basis) { + CheckMatMinNxM(m); +} + +/** Check for a matrix that can represent a 3D col-basis affine transform */ +template< class MatT > inline void +CheckMatAffine3D(const MatT& m, col_basis) { + CheckMatMinNxM(m); +} + +/** Check for a matrix that can represent a 2D row-basis affine transform */ +template< class MatT > inline void +CheckMatAffine2D(const MatT& m, row_basis) { + CheckMatMinNxM(m); +} + +/** Check for a matrix that can represent a 2D col-basis affine transform */ +template< class MatT > inline void +CheckMatAffine2D(const MatT& m, col_basis) { + CheckMatMinNxM(m); +} + +/** Check for a matrix that can represent a 3D affine transform */ +template< class MatT > inline void +CheckMatAffine3D(const MatT& m) { + CheckMatAffine3D(m, typename MatT::basis_orient()); +} + +/** Check for a matrix that can represent a 2D affine transform */ +template< class MatT > inline void +CheckMatAffine2D(const MatT& m) { + CheckMatAffine2D(m, typename MatT::basis_orient()); +} + +/** Check for a matrix that can represent a 3D homogenous transform */ +template< class MatT > inline void +CheckMatHomogeneous3D(const MatT& m) { + CheckMatMin4x4(m); +} + +/** Compile-time check for a square matrix */ +template< class MatT, class ErrorT> inline void +CheckMatSquare(const MatT& m, fixed_size_tag) { + CheckMat(m); + + CML_STATIC_REQUIRE_M( + (MatT::array_rows == MatT::array_cols), ErrorT); +} + +/** Run-time check for a square matrix */ +template< class MatT, class /*ErrorT*/ > inline void +CheckMatSquare(const MatT& m, dynamic_size_tag) { + CheckMat(m); + + if (m.rows() != m.cols()) { + throw std::invalid_argument( + "function expects square matrix as argument"); + } +} + +/** Check for a square matrix */ +template< class MatT > inline void +CheckMatSquare(const MatT& m) { + typedef et::ExprTraits matrix_traits; + typedef typename matrix_traits::size_tag size_tag; + + detail::CheckMatSquare< + MatT,function_expects_square_matrix_arg_error>(m, size_tag()); +} + +////////////////////////////////////////////////////////////////////////////// +// Quaternion argument checking +////////////////////////////////////////////////////////////////////////////// + +/** Compile-time check for a quaternion argument*/ +template< class QuatT > inline void +CheckQuat(const QuatT& /*q*/) +{ + typedef et::ExprTraits quaternion_traits; + typedef typename quaternion_traits::result_tag result_type; + + CML_STATIC_REQUIRE_M( + (same_type::is_true), + function_expects_quaternion_arg_error); +} + +////////////////////////////////////////////////////////////////////////////// +// Index argument checking +////////////////////////////////////////////////////////////////////////////// + +/** Run-time check for a valid argument */ +inline void CheckValidArg(bool valid) +{ + if (!valid) { + throw std::invalid_argument("invalid function argument"); + } +} + +/** Check for a valid integer index with value < N */ +template < size_t N > +inline void CheckIndexN(size_t index) { + CheckValidArg(index < N); +} + +/** Check for a valid integer index with value < 2 */ +inline void CheckIndex2(size_t index) { + CheckIndexN<2>(index); +} + +/** Check for a valid integer index with value < 3 */ +inline void CheckIndex3(size_t index) { + CheckIndexN<3>(index); +} + +} // namespace detail +} // namespace cml + +#endif diff --git a/Lib/Include/CML/mathlib/coord_conversion.h b/Lib/Include/CML/mathlib/coord_conversion.h new file mode 100644 index 0000000..8d0b2fa --- /dev/null +++ b/Lib/Include/CML/mathlib/coord_conversion.h @@ -0,0 +1,162 @@ +/* -*- C++ -*- ------------------------------------------------------------ + +Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/ + +The Configurable Math Library (CML) is distributed under the terms of the +Boost Software License, v1.0 (see cml/LICENSE for details). + + *-----------------------------------------------------------------------*/ +/** @file + * @brief + */ + +#ifndef coord_conversion_h +#define coord_conversion_h + +#include +#include +#include + +/* Functions for converting between Cartesian, polar, cylindrical and + * spherical coordinates. + * + * The 3D conversion functions take an integer axis index argument. For + * cylindrical coordinates this determines the axis of the cylinder, and for + * spherical it determines which cardinal axis is normal to the azimuth plane. + * + * For spherical coordinates the option of whether to treat phi as latitude + * or colatitude is also available. The 'type' argument takes either of the + * enumerants cml::latitude and cml::colatitude to reflect this. + */ + +namespace cml { + +////////////////////////////////////////////////////////////////////////////// +// Conversion to Cartesian coordinates +////////////////////////////////////////////////////////////////////////////// + +/* Convert cylindrical coordinates to Cartesian coordinates in R3 */ +template < typename E, class A > void +cylindrical_to_cartesian( + E radius, E theta, E height, size_t axis, vector& v) +{ + typedef vector vector_type; + typedef typename vector_type::value_type value_type; + + /* Checking */ + detail::CheckVec3(v); + detail::CheckIndex3(axis); + + size_t i, j, k; + cyclic_permutation(axis, i, j, k); + + v[i] = height; + v[j] = std::cos(theta) * radius; + v[k] = std::sin(theta) * radius; +} + +/* Convert spherical coordinates to Cartesian coordinates in R3 */ +template < typename E, class A > void +spherical_to_cartesian(E radius, E theta, E phi, size_t axis, + SphericalType type, vector& v) +{ + typedef vector vector_type; + typedef typename vector_type::value_type value_type; + + /* Checking */ + detail::CheckVec3(v); + detail::CheckIndex3(axis); + + if (type == latitude) { + phi = constants::pi_over_2() - phi; + } + + value_type sin_phi = std::sin(phi); + value_type cos_phi = std::cos(phi); + value_type sin_phi_r = sin_phi * radius; + + size_t i, j, k; + cyclic_permutation(axis, i, j, k); + + v[i] = cos_phi * radius; + v[j] = sin_phi_r * std::cos(theta); + v[k] = sin_phi_r * std::sin(theta); +} + +/* Convert polar coordinates to Cartesian coordinates in R2 */ +template < typename E, class A > void +polar_to_cartesian(E radius, E theta, vector& v) +{ + /* Checking handled by set() */ + v.set(std::cos(theta) * radius, std::sin(theta) * radius); +} + +////////////////////////////////////////////////////////////////////////////// +// Conversion from Cartesian coordinates +////////////////////////////////////////////////////////////////////////////// + +/* Convert Cartesian coordinates to cylindrical coordinates in R3 */ +template < class VecT, typename Real > void +cartesian_to_cylindrical(const VecT& v, Real& radius, Real& theta, + Real& height, size_t axis, Real tolerance = epsilon::placeholder()) +{ + typedef Real value_type; + + /* Checking */ + detail::CheckVec3(v); + detail::CheckIndex3(axis); + + size_t i, j, k; + cyclic_permutation(axis, i, j, k); + + radius = length(v[j],v[k]); + theta = radius < tolerance ? value_type(0) : std::atan2(v[k],v[j]); + height = v[i]; +} + +/* Convert Cartesian coordinates to spherical coordinates in R3 */ +template < class VecT, typename Real > void +cartesian_to_spherical(const VecT& v, Real& radius, Real& theta, Real& phi, + size_t axis, SphericalType type, + Real tolerance = epsilon::placeholder()) +{ + typedef Real value_type; + + /* Checking */ + detail::CheckVec3(v); + detail::CheckIndex3(axis); + + size_t i, j, k; + cyclic_permutation(axis, i, j, k); + + value_type len = length(v[j],v[k]); + theta = len < tolerance ? value_type(0) : std::atan2(v[k],v[j]); + radius = length(v[i], len); + if (radius < tolerance) { + phi = value_type(0); + } else { + phi = std::atan2(len,v[i]); + //phi = type.convert(phi); + if (type == latitude) { + phi = constants::pi_over_2() - phi; + } + } +} + +/* Convert Cartesian coordinates to polar coordinates in R2 */ +template < class VecT, typename Real > void +cartesian_to_polar(const VecT& v, Real& radius, Real& theta, + Real tolerance = epsilon::placeholder()) +{ + typedef Real value_type; + + /* Checking */ + detail::CheckVec2(v); + + radius = v.length(); + theta = radius < tolerance ? value_type(0) : std::atan2(v[1],v[0]); +} + +} // namespace cml + +#endif diff --git a/Lib/Include/CML/mathlib/epsilon.h b/Lib/Include/CML/mathlib/epsilon.h new file mode 100644 index 0000000..14059fa --- /dev/null +++ b/Lib/Include/CML/mathlib/epsilon.h @@ -0,0 +1,44 @@ +/* -*- C++ -*- ------------------------------------------------------------ + +Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/ + +The Configurable Math Library (CML) is distributed under the terms of the +Boost Software License, v1.0 (see cml/LICENSE for details). + + *-----------------------------------------------------------------------*/ +/** @file + * @brief + */ + +#ifndef epsilon_h +#define epsilon_h + +namespace cml { + +/* @todo: epsilon and tolerance handling. + * + * @note This is a placeholder for a more sophisticated epsilon/tolerance + * system. + */ + +template < typename Real > +struct epsilon +{ + typedef Real value_type; + +private: + + /** For convenience */ + typedef value_type T; + +public: + + static T placeholder() { + /* Completely arbitrary placeholder value: */ + return T(0.0001); + } +}; + +} // namespace cml + +#endif diff --git a/Lib/Include/CML/mathlib/frustum.h b/Lib/Include/CML/mathlib/frustum.h new file mode 100644 index 0000000..43eb41f --- /dev/null +++ b/Lib/Include/CML/mathlib/frustum.h @@ -0,0 +1,258 @@ +/* -*- C++ -*- ------------------------------------------------------------ + +Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/ + +The Configurable Math Library (CML) is distributed under the terms of the +Boost Software License, v1.0 (see cml/LICENSE for details). + + *-----------------------------------------------------------------------*/ +/** @file + * @brief + */ + +#ifndef frustum_h +#define frustum_h + +#include +#include + +namespace cml { + +/* @todo: plane class, and perhaps named arguments instead of an array. */ + +/* Extract the planes of a frustum given a modelview matrix and a projection + * matrix with the given near z-clipping range. The planes are normalized by + * default, but this can be turned off with the 'normalize' argument. + * + * The planes are in ax+by+cz+d = 0 form, and are in the order: + * left + * right + * bottom + * top + * near + * far + */ + +template < class MatT, typename Real > void +extract_frustum_planes( + const MatT& modelview, + const MatT& projection, + Real planes[6][4], + ZClip z_clip, + bool normalize = true) +{ + extract_frustum_planes( + detail::matrix_concat_transforms_4x4(modelview,projection), + planes, + z_clip, + normalize + ); +} + +/* Extract the planes of a frustum from a single matrix assumed to contain any + * model and view transforms followed by a projection transform with the given + * near z-cliping range. The planes are normalized by default, but this can be + * turned off with the 'normalize' argument. + * + * The planes are in ax+by+cz+d = 0 form, and are in the order: + * left + * right + * bottom + * top + * near + * far + */ + +template < class MatT, typename Real > void +extract_frustum_planes( + const MatT& m, + Real planes[6][4], + ZClip z_clip, + bool normalize = true) +{ + detail::CheckMatHomogeneous3D(m); + + /* Left: [03+00, 13+10, 23+20, 33+30] */ + + planes[0][0] = m.basis_element(0,3) + m.basis_element(0,0); + planes[0][1] = m.basis_element(1,3) + m.basis_element(1,0); + planes[0][2] = m.basis_element(2,3) + m.basis_element(2,0); + planes[0][3] = m.basis_element(3,3) + m.basis_element(3,0); + + /* Right: [03-00, 13-10, 23-20, 33-30] */ + + planes[1][0] = m.basis_element(0,3) - m.basis_element(0,0); + planes[1][1] = m.basis_element(1,3) - m.basis_element(1,0); + planes[1][2] = m.basis_element(2,3) - m.basis_element(2,0); + planes[1][3] = m.basis_element(3,3) - m.basis_element(3,0); + + /* Bottom: [03+01, 13+11, 23+21, 33+31] */ + + planes[2][0] = m.basis_element(0,3) + m.basis_element(0,1); + planes[2][1] = m.basis_element(1,3) + m.basis_element(1,1); + planes[2][2] = m.basis_element(2,3) + m.basis_element(2,1); + planes[2][3] = m.basis_element(3,3) + m.basis_element(3,1); + + /* Top: [03-01, 13-11, 23-21, 33-31] */ + + planes[3][0] = m.basis_element(0,3) - m.basis_element(0,1); + planes[3][1] = m.basis_element(1,3) - m.basis_element(1,1); + planes[3][2] = m.basis_element(2,3) - m.basis_element(2,1); + planes[3][3] = m.basis_element(3,3) - m.basis_element(3,1); + + /* Far: [03-02, 13-12, 23-22, 33-32] */ + + planes[5][0] = m.basis_element(0,3) - m.basis_element(0,2); + planes[5][1] = m.basis_element(1,3) - m.basis_element(1,2); + planes[5][2] = m.basis_element(2,3) - m.basis_element(2,2); + planes[5][3] = m.basis_element(3,3) - m.basis_element(3,2); + + /* Near: [03+02, 13+12, 23+22, 33+32] : [02, 12, 22, 32] */ + extract_near_frustum_plane(m, planes[4], z_clip); + + /* @todo: This will be handled by the plane class */ + if (normalize) { + for (size_t i = 0; i < 6; ++i) { + Real invl = inv_sqrt(planes[i][0] * planes[i][0] + + planes[i][1] * planes[i][1] + + planes[i][2] * planes[i][2]); + + planes[i][0] *= invl; + planes[i][1] *= invl; + planes[i][2] *= invl; + planes[i][3] *= invl; + } + } +} + +/** Extract the near plane of a frustum given a concatenated modelview and + * projection matrix with the given near z-clipping range. The plane is + * not normalized. + * + * @note The plane is in ax+by+cz+d = 0 form. + * + * @warning The matrix is assumed to be a homogeneous transformation + * matrix. + */ +template < class MatT, class PlaneT > void +extract_near_frustum_plane( + const MatT& m, + PlaneT& plane, + ZClip z_clip + ) +{ + /* Near: [03+02, 13+12, 23+22, 33+32] : [02, 12, 22, 32] */ + if (z_clip == z_clip_neg_one) { + plane[0] = m.basis_element(0,3) + m.basis_element(0,2); + plane[1] = m.basis_element(1,3) + m.basis_element(1,2); + plane[2] = m.basis_element(2,3) + m.basis_element(2,2); + plane[3] = m.basis_element(3,3) + m.basis_element(3,2); + } else { // z_clip == z_clip_zero + plane[0] = m.basis_element(0,2); + plane[1] = m.basis_element(1,2); + plane[2] = m.basis_element(2,2); + plane[3] = m.basis_element(3,2); + } +} + +namespace detail { + +/* This is currently only in support of finding the corners of a frustum. + * The input planes are assumed to have a single unique intersection, so + * no tolerance is used. + */ + +template < typename Real > vector< Real, fixed<3> > +intersect_planes(Real p1[4], Real p2[4], Real p3[4]) +{ + typedef vector< Real, fixed<3> > vector_type; + typedef typename vector_type::value_type value_type; + + vector_type n1(p1[0],p1[1],p1[2]); + vector_type n2(p2[0],p2[1],p2[2]); + vector_type n3(p3[0],p3[1],p3[2]); + + value_type d1 = -p1[3]; + value_type d2 = -p2[3]; + value_type d3 = -p3[3]; + + vector_type numer = + d1*cross(n2,n3) + d2*cross(n3,n1) + d3*cross(n1,n2); + value_type denom = triple_product(n1,n2,n3); + return numer/denom; +} + +} // namespace detail + +/* Get the corners of a frustum defined by 6 planes. The planes are in + * ax+by+cz+d = 0 form, and are in the order: + * left + * right + * bottom + * top + * near + * far + * + * The corners are in CCW order starting in the lower-left, first at the near + * plane, then at the far plane. + */ + +template < typename Real, typename E, class A > void +get_frustum_corners(Real planes[6][4], vector corners[8]) +{ + // NOTE: Prefixed with 'PLANE_' due to symbol conflict with Windows + // macros PLANE_LEFT and PLANE_RIGHT. + enum { + PLANE_LEFT, + PLANE_RIGHT, + PLANE_BOTTOM, + PLANE_TOP, + PLANE_NEAR, + PLANE_FAR + }; + + corners[0] = detail::intersect_planes( + planes[PLANE_LEFT], + planes[PLANE_BOTTOM], + planes[PLANE_NEAR] + ); + corners[1] = detail::intersect_planes( + planes[PLANE_RIGHT], + planes[PLANE_BOTTOM], + planes[PLANE_NEAR] + ); + corners[2] = detail::intersect_planes( + planes[PLANE_RIGHT], + planes[PLANE_TOP], + planes[PLANE_NEAR] + ); + corners[3] = detail::intersect_planes( + planes[PLANE_LEFT], + planes[PLANE_TOP], + planes[PLANE_NEAR] + ); + corners[4] = detail::intersect_planes( + planes[PLANE_LEFT], + planes[PLANE_BOTTOM], + planes[PLANE_FAR] + ); + corners[5] = detail::intersect_planes( + planes[PLANE_RIGHT], + planes[PLANE_BOTTOM], + planes[PLANE_FAR] + ); + corners[6] = detail::intersect_planes( + planes[PLANE_RIGHT], + planes[PLANE_TOP], + planes[PLANE_FAR] + ); + corners[7] = detail::intersect_planes( + planes[PLANE_LEFT], + planes[PLANE_TOP], + planes[PLANE_FAR] + ); +} + +} // namespace cml + +#endif diff --git a/Lib/Include/CML/mathlib/helper.h b/Lib/Include/CML/mathlib/helper.h new file mode 100644 index 0000000..fde83f5 --- /dev/null +++ b/Lib/Include/CML/mathlib/helper.h @@ -0,0 +1,158 @@ +/* -*- C++ -*- ------------------------------------------------------------ + +Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/ + +The Configurable Math Library (CML) is distributed under the terms of the +Boost Software License, v1.0 (see cml/LICENSE for details). + + *-----------------------------------------------------------------------*/ +/** @file + * @brief + */ + +#ifndef helper_h +#define helper_h + +#include +#include + +namespace cml { + +/* Helper classes for axis order, coordinate system handedness, z-clipping + * range and spherical coordinate type. + */ + +////////////////////////////////////////////////////////////////////////////// +// Euler order +////////////////////////////////////////////////////////////////////////////// + +enum EulerOrder { + euler_order_xyz, // 0x00 [0000] + euler_order_xyx, // 0x01 [0001] + euler_order_xzy, // 0x02 [0010] + euler_order_xzx, // 0x03 [0011] + euler_order_yzx, // 0x04 [0100] + euler_order_yzy, // 0x05 [0101] + euler_order_yxz, // 0x06 [0110] + euler_order_yxy, // 0x07 [0111] + euler_order_zxy, // 0x08 [1000] + euler_order_zxz, // 0x09 [1001] + euler_order_zyx, // 0x0A [1010] + euler_order_zyz // 0x0B [1011] +}; + +namespace detail { + +inline void unpack_euler_order( + EulerOrder order, + size_t& i, + size_t& j, + size_t& k, + bool& odd, + bool& repeat) +{ + enum { REPEAT = 0x01, ODD = 0x02, AXIS = 0x0C }; + + repeat = order & REPEAT; + odd = ((order & ODD) == ODD); + size_t offset = size_t(odd); + i = (order & AXIS) % 3; + j = (i + 1 + offset) % 3; + k = (i + 2 - offset) % 3; +} + +} // namespace detail + +////////////////////////////////////////////////////////////////////////////// +// Axis order +////////////////////////////////////////////////////////////////////////////// + +enum AxisOrder { + axis_order_xyz = euler_order_xyz, // 0x00 [0000] + axis_order_xzy = euler_order_xzy, // 0x02 [0010] + axis_order_yzx = euler_order_yzx, // 0x04 [0100] + axis_order_yxz = euler_order_yxz, // 0x06 [0110] + axis_order_zxy = euler_order_zxy, // 0x08 [1000] + axis_order_zyx = euler_order_zyx // 0x0A [1010] +}; + +namespace detail { + +inline void unpack_axis_order( + AxisOrder order, + size_t& i, + size_t& j, + size_t& k, + bool& odd) +{ + enum { ODD = 0x02, AXIS = 0x0C }; + + odd = ((order & ODD) == ODD); + size_t offset = size_t(odd); + i = (order & AXIS) % 3; + j = (i + 1 + offset) % 3; + k = (i + 2 - offset) % 3; +} + +inline AxisOrder pack_axis_order(size_t i, bool odd) { + return AxisOrder((i << 2) | (size_t(odd) << 1)); +} + +inline AxisOrder swap_axis_order(AxisOrder order) +{ + size_t i, j, k; + bool odd; + unpack_axis_order(order, i, j, k, odd); + return pack_axis_order(j, !odd); +} + +} // namespace detail + +////////////////////////////////////////////////////////////////////////////// +// Axis order 2D +////////////////////////////////////////////////////////////////////////////// + +enum AxisOrder2D { + axis_order_xy = axis_order_xyz, // 0x00 [0000] + axis_order_yx = axis_order_yxz // 0x06 [0110] +}; + +namespace detail { + +inline void unpack_axis_order_2D( + AxisOrder2D order, + size_t& i, + size_t& j, + bool& odd) +{ + enum { ODD = 0x02, AXIS = 0x0C }; + + odd = ((order & ODD) == ODD); + size_t offset = size_t(odd); + i = (order & AXIS) % 3; + j = (i + 1 + offset) % 3; +} + +} // namespace detail + +////////////////////////////////////////////////////////////////////////////// +// Handedness +////////////////////////////////////////////////////////////////////////////// + +enum Handedness { left_handed, right_handed }; + +////////////////////////////////////////////////////////////////////////////// +// Z clip +////////////////////////////////////////////////////////////////////////////// + +enum ZClip { z_clip_neg_one, z_clip_zero }; + +////////////////////////////////////////////////////////////////////////////// +// Spherical coordinate type +////////////////////////////////////////////////////////////////////////////// + +enum SphericalType { latitude, colatitude }; + +} // namespace cml + +#endif diff --git a/Lib/Include/CML/mathlib/interpolation.h b/Lib/Include/CML/mathlib/interpolation.h new file mode 100644 index 0000000..4a9fd54 --- /dev/null +++ b/Lib/Include/CML/mathlib/interpolation.h @@ -0,0 +1,1129 @@ +/* -*- C++ -*- ------------------------------------------------------------ + +Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/ + +The Configurable Math Library (CML) is distributed under the terms of the +Boost Software License, v1.0 (see cml/LICENSE for details). + + *-----------------------------------------------------------------------*/ +/** @file + * @brief + */ + +#ifndef interpolation_h +#define interpolation_h + +#include + +/* Interpolation functions. + * + * @todo: This code works, but it needs a lot of cleanup. + */ + +namespace cml { + +struct function_expects_args_of_same_type_error; + +namespace detail { + +////////////////////////////////////////////////////////////////////////////// +// Helper struct to promote vectors, quaternions, and matrices +////////////////////////////////////////////////////////////////////////////// + +template< class T1, class T2, class ResultT > struct TypePromote; + +template< class T > +struct TypePromote< T,T,et::scalar_result_tag > { + typedef T temporary_type; +}; + +template< class T1, class T2 > +struct TypePromote< T1,T2,et::scalar_result_tag > { + typedef et::ExprTraits traits_1; + typedef et::ExprTraits traits_2; + typedef typename traits_1::result_tag result_type_1; + typedef typename traits_2::result_tag result_type_2; + + /* Check that results are of the same type */ + CML_STATIC_REQUIRE_M( + (same_type::is_true), + function_expects_args_of_same_type_error); + + typedef typename et::ScalarPromote::type temporary_type; +}; + +template< class T1, class T2 > +struct TypePromote< T1,T2,et::vector_result_tag > { + typedef et::ExprTraits traits_1; + typedef et::ExprTraits traits_2; + typedef typename traits_1::result_tag result_type_1; + typedef typename traits_2::result_tag result_type_2; + + /* Check that results are of the same type */ + CML_STATIC_REQUIRE_M( + (same_type::is_true), + function_expects_args_of_same_type_error); + + /* @todo: This should be VectorPromote<> for symmetry with the other + * type promotions. + */ + typedef typename CrossPromote::promoted_vector temporary_type; +}; + +template< class T1, class T2 > +struct TypePromote< T1,T2,et::matrix_result_tag > { + typedef et::ExprTraits traits_1; + typedef et::ExprTraits traits_2; + typedef typename traits_1::result_tag result_type_1; + typedef typename traits_2::result_tag result_type_2; + + /* Check that results are of the same type */ + CML_STATIC_REQUIRE_M( + (same_type::is_true), + function_expects_args_of_same_type_error); + + typedef typename et::MatrixPromote2::temporary_type temporary_type; +}; + +template< class T1, class T2 > +struct TypePromote< T1,T2,et::quaternion_result_tag > { + typedef et::ExprTraits traits_1; + typedef et::ExprTraits traits_2; + typedef typename traits_1::result_tag result_type_1; + typedef typename traits_2::result_tag result_type_2; + + /* Check that results are of the same type */ + CML_STATIC_REQUIRE_M( + (same_type::is_true), + function_expects_args_of_same_type_error); + + typedef typename et::QuaternionPromote2::temporary_type + temporary_type; +}; + +template< class T1, class T2, class T3, class ResultT > struct TypePromote3; + +template< class T1, class T2, class T3 > +struct TypePromote3< T1,T2,T3,et::matrix_result_tag > { + typedef et::ExprTraits traits_1; + typedef et::ExprTraits traits_2; + typedef et::ExprTraits traits_3; + typedef typename traits_1::result_tag result_type_1; + typedef typename traits_2::result_tag result_type_2; + typedef typename traits_3::result_tag result_type_3; + + /* Check that results are of the same type */ + CML_STATIC_REQUIRE_M( + (same_type::is_true), + function_expects_args_of_same_type_error); + CML_STATIC_REQUIRE_M( + (same_type::is_true), + function_expects_args_of_same_type_error); + + typedef typename et::MatrixPromote3::temporary_type + temporary_type; + typedef typename temporary_type::value_type value_type; +}; + +template< class T1, class T2, class T3 > +struct TypePromote3< T1,T2,T3,et::quaternion_result_tag > { + typedef et::ExprTraits traits_1; + typedef et::ExprTraits traits_2; + typedef et::ExprTraits traits_3; + typedef typename traits_1::result_tag result_type_1; + typedef typename traits_2::result_tag result_type_2; + typedef typename traits_3::result_tag result_type_3; + + /* Check that results are of the same type */ + CML_STATIC_REQUIRE_M( + (same_type::is_true), + function_expects_args_of_same_type_error); + CML_STATIC_REQUIRE_M( + (same_type::is_true), + function_expects_args_of_same_type_error); + + typedef typename et::QuaternionPromote3::temporary_type + temporary_type; + typedef typename temporary_type::value_type value_type; +}; + +template < + class T1, class T2, class T3, class T4, class ResultT +> struct TypePromote4; + +template< class T1, class T2, class T3, class T4 > +struct TypePromote4< T1,T2,T3,T4,et::matrix_result_tag > { + typedef et::ExprTraits traits_1; + typedef et::ExprTraits traits_2; + typedef et::ExprTraits traits_3; + typedef et::ExprTraits traits_4; + typedef typename traits_1::result_tag result_type_1; + typedef typename traits_2::result_tag result_type_2; + typedef typename traits_3::result_tag result_type_3; + typedef typename traits_4::result_tag result_type_4; + + /* Check that results are of the same type */ + CML_STATIC_REQUIRE_M( + (same_type::is_true), + function_expects_args_of_same_type_error); + CML_STATIC_REQUIRE_M( + (same_type::is_true), + function_expects_args_of_same_type_error); + CML_STATIC_REQUIRE_M( + (same_type::is_true), + function_expects_args_of_same_type_error); + + typedef typename et::MatrixPromote4::temporary_type + temporary_type; + typedef typename temporary_type::value_type value_type; +}; + +template< class T1, class T2, class T3, class T4 > +struct TypePromote4< T1,T2,T3,T4,et::quaternion_result_tag > { + typedef et::ExprTraits traits_1; + typedef et::ExprTraits traits_2; + typedef et::ExprTraits traits_3; + typedef et::ExprTraits traits_4; + typedef typename traits_1::result_tag result_type_1; + typedef typename traits_2::result_tag result_type_2; + typedef typename traits_3::result_tag result_type_3; + typedef typename traits_4::result_tag result_type_4; + + /* Check that results are of the same type */ + CML_STATIC_REQUIRE_M( + (same_type::is_true), + function_expects_args_of_same_type_error); + CML_STATIC_REQUIRE_M( + (same_type::is_true), + function_expects_args_of_same_type_error); + CML_STATIC_REQUIRE_M( + (same_type::is_true), + function_expects_args_of_same_type_error); + + typedef typename et::QuaternionPromote4::temporary_type + temporary_type; + typedef typename temporary_type::value_type value_type; +}; + +////////////////////////////////////////////////////////////////////////////// +// Helper functions to resize a vector, quaternion or matrix +////////////////////////////////////////////////////////////////////////////// + +// Should be able to catch all no-ops with a generic function template... + +template < class T1, class T2, class SizeTag > void +InterpResize(T1& t1, const T2& t2, SizeTag) {} + +// Catch vector and matrix resizes... + +template< typename E, class A, class VecT > void +InterpResize(vector& v, const VecT& target, dynamic_size_tag) { + v.resize(target.size()); +} + +template< typename E, class A, class B, class L, class MatT > void +InterpResize(matrix& m, const MatT& target, dynamic_size_tag) { + m.resize(target.rows(),target.cols()); +} + +////////////////////////////////////////////////////////////////////////////// +// Construction of 'intermediate' quaternions and matrices for use with squad +////////////////////////////////////////////////////////////////////////////// + +#if 0 +template < class QuatT_1, class QuatT_2 > +typename et::QuaternionPromote2::temporary_type +concatenate_quaternions( + const QuatT_1& q1, + const QuatT_2& q2, + positive_cross) +{ + return q2 * q1; +} + +template < class QuatT_1, class QuatT_2 > +typename et::QuaternionPromote2::temporary_type +concatenate_quaternions( + const QuatT_1& q1, + const QuatT_2& q2, + negative_cross) +{ + return q1 * q2; +} + +template< class T1, class T2, class T3, class SizeT > +typename detail::TypePromote3< + T1,T2,T3,typename et::ExprTraits::result_tag +>::temporary_type +squad_intermediate( + const T1& t1, + const T2& t2, + const T3& t3, + typename detail::TypePromote3< + T1, T2, T3, typename et::ExprTraits::result_tag + >::value_type tolerance, + et::quaternion_result_tag, + SizeT) +{ + typedef et::ExprTraits traits_1; + typedef typename traits_1::result_tag result_type_1; + + typedef typename detail::TypePromote3::temporary_type + temporary_type; + typedef typename temporary_type::value_type value_type; + typedef typename temporary_type::cross_type cross_type; + typedef et::ExprTraits result_traits; + typedef typename result_traits::size_tag size_tag; + + /** + * NOTE: It seems that the equation for computing an intermediate + * quaternion produces the same results regardless of whether 'standard' + * or 'reverse' multiplication order is used (I haven't proved this - + * I've just observed it). Still, just to be sure I've used a pair of + * helper functions to ensure that the quaternions are multiplied in the + * right order. + */ + + temporary_type result; + detail::InterpResize(result, t1, size_tag()); + + temporary_type t2_inverse = conjugate(t2); + temporary_type temp1 = concatenate_quaternions(t1, t2_inverse, cross_type()); + temporary_type temp2 = concatenate_quaternions(t3, t2_inverse, cross_type()); + result = concatenate_quaternions( + exp(-(log(temp1) + log(temp2)) * value_type(.25)), t2, cross_type()); + return result; +} + +/** + * NOTE: Construction of intermediate rotation matrices for use with squad + * is currently implemented in terms of quaternions. This is pretty + * inefficient (especially so in the 2-d case, which involves jumping through + * a lot of hoops to get to 3-d and back), and is inelegant as well. + * + * I imagine this could be streamlined to work directly with the matrices, but + * I'd need to dig a bit first (figure out the matrix equivalents of + * quaternion exp() and log(), figure out what shortcuts can be taken in + * 2-d, etc.), so for now it'll just have to remain as-is. + * + * In future versions of the CML, it might also be worth reconsidering + * whether it's wise to support slerp and squad for matrices. Although it + * can be done, it's not efficient, and may give the user a false sense of + * security with respect to the efficiency of the underlying operations. + */ + +template< class MatT_1, class MatT_2, class MatT_3, size_t N > +struct squad_intermediate_f; + +template< class MatT_1, class MatT_2, class MatT_3 > +struct squad_intermediate_f +{ + template< typename Real > + typename et::MatrixPromote3< MatT_1,MatT_2,MatT_3 >::temporary_type + operator()( + const MatT_1& m1, + const MatT_2& m2, + const MatT_3& m3, + Real tolerance) + { + typedef typename et::MatrixPromote3< + MatT_1,MatT_2,MatT_3 >::temporary_type temporary_type; + typedef typename temporary_type::value_type value_type; + typedef quaternion< value_type > quaternion_type; + + quaternion_type q1, q2, q3; + quaternion_rotation_matrix(q1, m1); + quaternion_rotation_matrix(q2, m2); + quaternion_rotation_matrix(q3, m3); + + quaternion_type q4 = squad_intermediate(q1, q2, q3, tolerance); + + temporary_type m; + et::detail::Resize(m,3,3); + + matrix_rotation_quaternion(m, q4); + + return m; + } +}; + +template< class MatT_1, class MatT_2, class MatT_3 > +struct squad_intermediate_f +{ + template< typename Real > + typename et::MatrixPromote3< MatT_1,MatT_2,MatT_3 >::temporary_type + operator()( + const MatT_1& m1, + const MatT_2& m2, + const MatT_3& m3, + Real tolerance) + { + typedef typename et::MatrixPromote3< + MatT_1,MatT_2,MatT_3 >::temporary_type temporary_type; + typedef typename temporary_type::value_type value_type; + typedef quaternion< value_type > quaternion_type; + typedef vector< value_type, fixed<3> > vector_type; + + value_type angle1 = matrix_to_rotation_2D(m1); + value_type angle2 = matrix_to_rotation_2D(m2); + value_type angle3 = matrix_to_rotation_2D(m3); + vector_type axis(value_type(0), value_type(0), value_type(1)); + + quaternion_type q1, q2, q3; + quaternion_rotation_axis_angle(q1, axis, angle1); + quaternion_rotation_axis_angle(q2, axis, angle2); + quaternion_rotation_axis_angle(q3, axis, angle3); + + quaternion_type q4 = squad_intermediate(q1, q2, q3, tolerance); + + value_type angle; + quaternion_to_axis_angle(q4, axis, angle); + + temporary_type m; + et::detail::Resize(m,2,2); + + matrix_rotation_2D(m, angle); + + return m; + } +}; + +template< class MatT_1, class MatT_2, class MatT_3, typename Real > +typename et::MatrixPromote3< MatT_1,MatT_2,MatT_3 >::temporary_type +squad_intermediate( + const MatT_1& m1, + const MatT_2& m2, + const MatT_3& m3, + Real tolerance, + et::matrix_result_tag, + fixed_size_tag) +{ + return squad_intermediate_f()( + m1,m2,m3,tolerance); +} + +template< class MatT_1, class MatT_2, class MatT_3, typename Real > +typename et::MatrixPromote3< MatT_1,MatT_2,MatT_3 >::temporary_type +squad_intermediate( + const MatT_1& m1, + const MatT_2& m2, + const MatT_3& m3, + Real tolerance, + et::matrix_result_tag, + dynamic_size_tag) +{ + typedef typename et::MatrixPromote3< + MatT_1,MatT_2,MatT_3 >::temporary_type temporary_type; + + temporary_type m; + et::detail::Resize(m,m1.rows(),m1.cols()); + + switch (m1.rows()) { + case 3: + m = squad_intermediate_f()(m1,m2,m3,tolerance); + break; + case 2: + m = squad_intermediate_f()(m1,m2,m3,tolerance); + break; + default: + throw std::invalid_argument( + "matrix squad_intermediate_f() expects sizes 3x3 or 2x2"); + break; + } + return m; +} +#endif + +////////////////////////////////////////////////////////////////////////////// +// Spherical linear interpolation of two vectors of any size +////////////////////////////////////////////////////////////////////////////// + +template< class VecT_1, class VecT_2, typename Real, class SizeT > +typename detail::TypePromote< + VecT_1,VecT_2,typename et::ExprTraits::result_tag +>::temporary_type +slerp( + const VecT_1& v1, + const VecT_2& v2, + Real t, + Real tolerance, + et::vector_result_tag, + SizeT) +{ + typedef et::ExprTraits type_traits; + typedef typename type_traits::result_tag result_type; + typedef typename + detail::TypePromote::temporary_type + temporary_type; + typedef typename temporary_type::value_type value_type; + typedef et::ExprTraits result_traits; + typedef typename result_traits::size_tag size_tag; + + temporary_type result; + detail::InterpResize(result, v1, size_tag()); + + value_type omega = acos_safe(dot(v1,v2)); + value_type s = std::sin(omega); + if (s < tolerance) { + result = nlerp(v1,v2,t); + } else { + result = (value_type(std::sin((value_type(1)-t)*omega))*v1 + + value_type(std::sin(t*omega))*v2) / s; + } + return result; +} + +////////////////////////////////////////////////////////////////////////////// +// Spherical linear interpolation of two quaternions +////////////////////////////////////////////////////////////////////////////// + +template< class QuatT_1, class QuatT_2, typename Real, class SizeT > +typename detail::TypePromote< + QuatT_1,QuatT_2,typename et::ExprTraits::result_tag +>::temporary_type +slerp( + const QuatT_1& q1, + const QuatT_2& q2, + Real t, + Real tolerance, + et::quaternion_result_tag, + SizeT) +{ + typedef et::ExprTraits type_traits; + typedef typename type_traits::result_tag result_type; + typedef typename + detail::TypePromote::temporary_type + temporary_type; + typedef typename temporary_type::value_type value_type; + + temporary_type q3 = q2; + value_type c = dot(q1,q3); + if (c < value_type(0)) { + // Turning this off temporarily to test squad... + q3 = -q3; + c = -c; + } + + value_type omega = acos_safe(c); + value_type s = std::sin(omega); + + return (s < tolerance) ? + normalize(lerp(q1,q3,t)) : + (value_type(std::sin((value_type(1) - t) * omega)) * q1+ + value_type(std::sin(t * omega)) * q3) / s; +} + +////////////////////////////////////////////////////////////////////////////// +// Helper struct for spherical linear interpolation of 3x3 and 2x2 matrices +////////////////////////////////////////////////////////////////////////////// + +template< class MatT_1, class MatT_2, size_t N > struct slerp_f; + +template< class MatT_1, class MatT_2 > struct slerp_f +{ + template< typename Real > + typename detail::TypePromote< + MatT_1,MatT_2,typename et::ExprTraits::result_tag + >::temporary_type + operator()( + const MatT_1& m1, + const MatT_2& m2, + Real t, + Real tolerance) + { + typedef typename detail::TypePromote< + MatT_1,MatT_2,typename et::ExprTraits::result_tag + >::temporary_type temporary_type; + + temporary_type m; + et::detail::Resize(m,3,3); + m = matrix_rotation_difference(m1,m2); + matrix_scale_rotation_angle(m,t,tolerance); + m = detail::matrix_concat_rotations(m1,m); + return m; + } +}; + +template< class MatT_1, class MatT_2 > struct slerp_f +{ + template< typename Real > + typename detail::TypePromote< + MatT_1,MatT_2,typename et::ExprTraits::result_tag + >::temporary_type + operator()( + const MatT_1& m1, + const MatT_2& m2, + Real t, + Real tolerance) + { + typedef typename detail::TypePromote< + MatT_1,MatT_2,typename et::ExprTraits::result_tag + >::temporary_type temporary_type; + + temporary_type m; + et::detail::Resize(m,2,2); + m = matrix_rotation_difference_2D(m1,m2); + matrix_scale_rotation_angle_2D(m,t,tolerance); + m = detail::matrix_concat_rotations_2D(m1,m); + return m; + } +}; + +////////////////////////////////////////////////////////////////////////////// +// Spherical linear interpolation of two matrices of size 3x3 or 2x2 +////////////////////////////////////////////////////////////////////////////// + +template< class MatT_1, class MatT_2, typename Real > +typename detail::TypePromote< + MatT_1,MatT_2,typename et::ExprTraits::result_tag +>::temporary_type +slerp( + const MatT_1& m1, + const MatT_2& m2, + Real t, + Real tolerance, + et::matrix_result_tag, + fixed_size_tag) +{ + return slerp_f()(m1,m2,t,tolerance); +} + +template< class MatT_1, class MatT_2, typename Real > +typename detail::TypePromote< + MatT_1,MatT_2,typename et::ExprTraits::result_tag +>::temporary_type +slerp( + const MatT_1& m1, + const MatT_2& m2, + Real t, + Real tolerance, + et::matrix_result_tag, + dynamic_size_tag) +{ + typedef typename detail::TypePromote< + MatT_1,MatT_2,typename et::ExprTraits::result_tag + >::temporary_type temporary_type; + + temporary_type m; + et::detail::Resize(m,m1.rows(),m1.cols()); + + switch (m1.rows()) { + case 3: + m = slerp_f()(m1,m2,t,tolerance); + break; + case 2: + m = slerp_f()(m1,m2,t,tolerance); + break; + default: + throw std::invalid_argument( + "matrix slerp() expects sizes 3x3 or 2x2"); + break; + } + return m; +} + +////////////////////////////////////////////////////////////////////////////// +// Normalized linear interpolation of two vectors of any size +////////////////////////////////////////////////////////////////////////////// + +template< class VecT_1, class VecT_2, typename Real, class SizeT > +typename detail::TypePromote< + VecT_1,VecT_2,typename et::ExprTraits::result_tag +>::temporary_type +nlerp( + const VecT_1& v1, + const VecT_2& v2, + Real t, + et::vector_result_tag, + SizeT) +{ + typedef et::ExprTraits type_traits; + typedef typename type_traits::result_tag result_type; + typedef typename + detail::TypePromote::temporary_type + temporary_type; + typedef typename temporary_type::value_type value_type; + typedef et::ExprTraits result_traits; + typedef typename result_traits::size_tag size_tag; + + temporary_type result; + detail::InterpResize(result, v1, size_tag()); + + result = (value_type(1)-t)*v1+t*v2; + result.normalize(); + return result; +} + +////////////////////////////////////////////////////////////////////////////// +// Normalized linear interpolation of two quaternions +////////////////////////////////////////////////////////////////////////////// + +template< class QuatT_1, class QuatT_2, typename Real, class SizeT > +typename detail::TypePromote< + QuatT_1,QuatT_2,typename et::ExprTraits::result_tag +>::temporary_type +nlerp( + const QuatT_1& q1, + const QuatT_2& q2, + Real t, + et::quaternion_result_tag, + SizeT) +{ + typedef et::ExprTraits type_traits; + typedef typename type_traits::result_tag result_type; + typedef typename + detail::TypePromote::temporary_type + temporary_type; + typedef typename temporary_type::value_type value_type; + + return normalize(lerp(q1, (dot(q1,q2) < value_type(0)) ? -q2 : q2, t)); +} + +////////////////////////////////////////////////////////////////////////////// +// Helper struct for normalized linear interpolation of 3x3 and 2x2 matrices +////////////////////////////////////////////////////////////////////////////// + +template< class MatT_1, class MatT_2, size_t N > struct nlerp_f; + +template< class MatT_1, class MatT_2 > struct nlerp_f +{ + template< typename Real > + typename detail::TypePromote< + MatT_1,MatT_2,typename et::ExprTraits::result_tag + >::temporary_type + operator()( + const MatT_1& m1, + const MatT_2& m2, + Real t) + { + typedef typename detail::TypePromote< + MatT_1,MatT_2,typename et::ExprTraits::result_tag + >::temporary_type temporary_type; + typedef typename temporary_type::value_type value_type; + + temporary_type m; + et::detail::Resize(m,3,3); + m = lerp(m1,m2,t); + matrix_orthogonalize_3x3(m); + return m; + } +}; + +template< class MatT_1, class MatT_2 > struct nlerp_f +{ + template< typename Real > + typename detail::TypePromote< + MatT_1,MatT_2,typename et::ExprTraits::result_tag + >::temporary_type + operator()( + const MatT_1& m1, + const MatT_2& m2, + Real t) + { + typedef typename detail::TypePromote< + MatT_1,MatT_2,typename et::ExprTraits::result_tag + >::temporary_type temporary_type; + typedef typename temporary_type::value_type value_type; + + temporary_type m; + et::detail::Resize(m,2,2); + m = lerp(m1,m2,t); + matrix_orthogonalize_2x2(m); + return m; + } +}; + +////////////////////////////////////////////////////////////////////////////// +// Normalized linear interpolation of two matrices of size 3x3 or 2x2 +////////////////////////////////////////////////////////////////////////////// + +template< class MatT_1, class MatT_2, typename Real > +typename detail::TypePromote< + MatT_1,MatT_2,typename et::ExprTraits::result_tag +>::temporary_type +nlerp( + const MatT_1& m1, + const MatT_2& m2, + Real t, + et::matrix_result_tag, + fixed_size_tag) +{ + return nlerp_f()(m1,m2,t); +} + +template< class MatT_1, class MatT_2, typename Real > +typename detail::TypePromote< + MatT_1,MatT_2,typename et::ExprTraits::result_tag +>::temporary_type +nlerp( + const MatT_1& m1, + const MatT_2& m2, + Real t, + et::matrix_result_tag, + dynamic_size_tag) +{ + typedef typename detail::TypePromote< + MatT_1,MatT_2,typename et::ExprTraits::result_tag + >::temporary_type temporary_type; + + temporary_type m; + et::detail::Resize(m,m1.rows(),m1.cols()); + + switch (m1.rows()) { + case 3: + m = nlerp_f()(m1,m2,t); + break; + case 2: + m = nlerp_f()(m1,m2,t); + break; + default: + throw std::invalid_argument( + "matrix nlerp() expects sizes 3x3 or 2x2"); + break; + } + return m; +} + +} // namespace detail + +////////////////////////////////////////////////////////////////////////////// +// Construction of 'intermediate' quaternions and matrices for use with squad +////////////////////////////////////////////////////////////////////////////// + +/** + * NOTE: Computation of intermediate rotation matrices for matrix 'squad' + * doesn't seem to be working correctly. I'm not sure what the problem is + * (it might have to do with q and -q representing the same rotation), but + * in any case, I don't have time to get it sorted at the moment. + * + * In the meantime, I've just hacked in static assertions that will + * restrict squad usage to quats. For anyone reading these comments, don't + * worry: the quaternion verison of squad works just fine. However, you'll + * just have to live without matrix squad for the time being (which is + * probably just as well, given that matrix interpolation isn't terribly + * efficient). + */ + +#if 0 +template< class T1, class T2, class T3 > +typename detail::TypePromote3< + T1,T2,T3,typename et::ExprTraits::result_tag +>::temporary_type +squad_intermediate( + const T1& t1, + const T2& t2, + const T3& t3, + typename detail::TypePromote3< + T1, T2, T3, typename et::ExprTraits::result_tag + >::value_type tolerance = + epsilon < + typename detail::TypePromote3< + T1, T2, T3, typename et::ExprTraits::result_tag + >::value_type + >::placeholder()) +{ + // HACK: See note above... + detail::CheckQuat(t1); + detail::CheckQuat(t2); + detail::CheckQuat(t3); + + typedef et::ExprTraits traits_1; + typedef typename traits_1::result_tag result_type_1; + + typedef typename detail::TypePromote3::temporary_type + temporary_type; + typedef et::ExprTraits result_traits; + typedef typename result_traits::size_tag size_tag; + + temporary_type result; + detail::InterpResize(result, t1, size_tag()); + + result = detail::squad_intermediate( + t1,t2,t3,tolerance,result_type_1(),size_tag()); + return result; +} + +////////////////////////////////////////////////////////////////////////////// +// Spherical quadrangle interpolation of two quaternions or matrices +////////////////////////////////////////////////////////////////////////////// + +/** + * NOTE: The squad() impelementation is unfinished. I'm leaving the code + * here (but preprocessor'ed out) for future reference. + * + * Currently, it seems that: + * + * 1. Computation of intermediate matrices is incorrect. + * 2. The interpolated orientation sometimes 'jumps' while between nodes. + * + * I've observed that removing the 'shortest path' negation from the slerp + * function eliminates the second problem. Also, in another implementation + * of squad that I've seen, q1 and q2 are interpolated over the shortest + * path, while the helper quaternions are not. I've never seen this + * mentioned as a requirement of squad, but maybe they know something I + * don't. + * + * For anyone who happens to read these comments, all of the other + * interpolation functions (lerp, nlerp, slerp, etc.) should work fine - + * it's just squad() that's on hold. + */ + +template< class T1, class T2, class T3, class T4, typename Real > +typename detail::TypePromote4< + T1,T2,T3,T4,typename et::ExprTraits::result_tag +>::temporary_type +squad( + const T1& t1, + const T2& t1_intermediate, + const T3& t2_intermediate, + const T4& t2, + Real t, + Real tolerance = epsilon::placeholder()) +{ + // HACK: See note above... + detail::CheckQuat(t1); + detail::CheckQuat(t1_intermediate); + detail::CheckQuat(t2_intermediate); + detail::CheckQuat(t2); + + typedef et::ExprTraits traits_1; + typedef typename traits_1::result_tag result_type_1; + + typedef typename detail::TypePromote4< + T1,T2,T3,T4,result_type_1>::temporary_type temporary_type; + typedef typename temporary_type::value_type value_type; + typedef et::ExprTraits result_traits; + typedef typename result_traits::size_tag size_tag; + + temporary_type result; + detail::InterpResize(result, t1, size_tag()); + + result = slerp( + slerp(t1, t2, t, tolerance), + slerp(t1_intermediate, t2_intermediate, t, tolerance), + value_type(2) * t * (value_type(1) - t), + tolerance + ); + + return result; +} +#endif + +////////////////////////////////////////////////////////////////////////////// +// Spherical linear interpolation of two vectors, quaternions or matrices +////////////////////////////////////////////////////////////////////////////// + +template< class T1, class T2, typename Real > +typename detail::TypePromote< + T1,T2,typename et::ExprTraits::result_tag +>::temporary_type +slerp( + const T1& t1, + const T2& t2, + Real t, + Real tolerance = epsilon::placeholder()) +{ + typedef et::ExprTraits traits_1; + typedef typename traits_1::result_tag result_type_1; + + typedef typename detail::TypePromote::temporary_type + temporary_type; + typedef et::ExprTraits result_traits; + typedef typename result_traits::size_tag size_tag; + + temporary_type result; + detail::InterpResize(result, t1, size_tag()); + + result = detail::slerp(t1,t2,t,tolerance,result_type_1(),size_tag()); + return result; +} + +////////////////////////////////////////////////////////////////////////////// +// Normalized linear interpolation of two vectors, quaternions or matrices +////////////////////////////////////////////////////////////////////////////// + +template< class T1, class T2, typename Real > +typename detail::TypePromote< + T1,T2,typename et::ExprTraits::result_tag +>::temporary_type +nlerp(const T1& t1, const T2& t2, Real t) +{ + typedef et::ExprTraits traits_1; + typedef typename traits_1::result_tag result_type_1; + + typedef typename detail::TypePromote::temporary_type + temporary_type; + typedef et::ExprTraits result_traits; + typedef typename result_traits::size_tag size_tag; + + temporary_type result; + detail::InterpResize(result, t1, size_tag()); + + result = detail::nlerp(t1,t2,t,result_type_1(),size_tag()); + return result; +} + +////////////////////////////////////////////////////////////////////////////// +// Linear interpolation of two values of any qualified type +////////////////////////////////////////////////////////////////////////////// + +/** Linear interpolation of 2 values. + * + * @note The data points are assumed to be sampled at u = 0 and u = 1, so + * for interpolation u must lie between 0 and 1. + */ +template< class T1, class T2, typename Scalar > +typename detail::TypePromote< + T1,T2,typename et::ExprTraits::result_tag +>::temporary_type +lerp(const T1& val0, const T2& val1, Scalar u) +{ + typedef + typename detail::TypePromote< + T1,T2,typename et::ExprTraits::result_tag + >::temporary_type temporary_type; + + typedef et::ExprTraits result_traits; + typedef typename result_traits::size_tag size_tag; + + temporary_type result; + detail::InterpResize(result, val1, size_tag()); + + result = (Scalar(1) - u) * val0 + u * val1; + return result; +} + +////////////////////////////////////////////////////////////////////////////// +// Bilinear interpolation of four values of any qualified type +////////////////////////////////////////////////////////////////////////////// + +template < class T1, class T2, class T3, class T4, typename Scalar > +typename detail::TypePromote< + typename detail::TypePromote< + T1,T2,typename et::ExprTraits::result_tag + >::temporary_type, + typename detail::TypePromote< + T3,T4,typename et::ExprTraits::result_tag + >::temporary_type, + typename et::ExprTraits::result_tag +>::temporary_type +bilerp(const T1& val00, const T2& val10, + const T3& val01, const T4& val11, + Scalar u, Scalar v) +{ + typedef + typename detail::TypePromote< + typename detail::TypePromote< + T1,T2,typename et::ExprTraits::result_tag + >::temporary_type, + typename detail::TypePromote< + T3,T4,typename et::ExprTraits::result_tag + >::temporary_type, + typename et::ExprTraits::result_tag + >::temporary_type temporary_type; + + typedef et::ExprTraits result_traits; + typedef typename result_traits::size_tag size_tag; + + temporary_type result; + detail::InterpResize(result, val00, size_tag()); + + Scalar uv = u * v; + result = ( + (Scalar(1.0) - u - v + uv) * val00 + + (u - uv) * val10 + + (v - uv) * val01 + + uv * val11 + ); + return result; +} + +////////////////////////////////////////////////////////////////////////////// +// Trilinear interpolation of eight values of any qualified type +////////////////////////////////////////////////////////////////////////////// + +/** Trilinear interpolation of 8 values. + * + * @note The data values are assumed to be sampled at the corners of a unit + * cube, so for interpolation, u, v, and w must lie between 0 and 1. + */ +template < class T1, class T2, class T3, class T4, + class T5, class T6, class T7, class T8, + typename Scalar > +typename detail::TypePromote< + typename detail::TypePromote< + typename detail::TypePromote< + T1,T2,typename et::ExprTraits::result_tag + >::temporary_type, + typename detail::TypePromote< + T3,T4,typename et::ExprTraits::result_tag + >::temporary_type, + typename et::ExprTraits::result_tag + >::temporary_type, + typename detail::TypePromote< + typename detail::TypePromote< + T5,T6,typename et::ExprTraits::result_tag + >::temporary_type, + typename detail::TypePromote< + T7,T8,typename et::ExprTraits::result_tag + >::temporary_type, + typename et::ExprTraits::result_tag + >::temporary_type, + typename et::ExprTraits::result_tag +>::temporary_type +trilerp(const T1& val000, const T2& val100, + const T3& val010, const T4& val110, + const T5& val001, const T6& val101, + const T7& val011, const T8& val111, + Scalar u, Scalar v, Scalar w) +{ + typedef + typename detail::TypePromote< + typename detail::TypePromote< + typename detail::TypePromote< + T1,T2,typename et::ExprTraits::result_tag + >::temporary_type, + typename detail::TypePromote< + T3,T4,typename et::ExprTraits::result_tag + >::temporary_type, + typename et::ExprTraits::result_tag + >::temporary_type, + typename detail::TypePromote< + typename detail::TypePromote< + T5,T6,typename et::ExprTraits::result_tag + >::temporary_type, + typename detail::TypePromote< + T7,T8,typename et::ExprTraits::result_tag + >::temporary_type, + typename et::ExprTraits::result_tag + >::temporary_type, + typename et::ExprTraits::result_tag + >::temporary_type temporary_type; + + typedef et::ExprTraits result_traits; + typedef typename result_traits::size_tag size_tag; + + temporary_type result; + detail::InterpResize(result, val000, size_tag()); + + Scalar uv = u * v; + Scalar vw = v * w; + Scalar wu = w * u; + Scalar uvw = uv * w; + + result = ( + (Scalar(1.0) - u - v - w + uv + vw + wu - uvw) * val000 + + (u - uv - wu + uvw) * val100 + + (v - uv - vw + uvw) * val010 + + (uv - uvw) * val110 + + (w - vw - wu + uvw) * val001 + + (wu - uvw) * val101 + + (vw - uvw) * val011 + + uvw * val111 + ); + return result; +} + +} // namespace cml + +#endif diff --git a/Lib/Include/CML/mathlib/mathlib.h b/Lib/Include/CML/mathlib/mathlib.h new file mode 100644 index 0000000..d15c5f2 --- /dev/null +++ b/Lib/Include/CML/mathlib/mathlib.h @@ -0,0 +1,33 @@ +/* -*- C++ -*- ------------------------------------------------------------ + +Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/ + +The Configurable Math Library (CML) is distributed under the terms of the +Boost Software License, v1.0 (see cml/LICENSE for details). + + *-----------------------------------------------------------------------*/ +/** @file + * @brief + */ + +#ifndef mathlib_h +#define mathlib_h + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#endif diff --git a/Lib/Include/CML/mathlib/matrix_basis.h b/Lib/Include/CML/mathlib/matrix_basis.h new file mode 100644 index 0000000..7732270 --- /dev/null +++ b/Lib/Include/CML/mathlib/matrix_basis.h @@ -0,0 +1,364 @@ +/* -*- C++ -*- ------------------------------------------------------------ + +Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/ + +The Configurable Math Library (CML) is distributed under the terms of the +Boost Software License, v1.0 (see cml/LICENSE for details). + + *-----------------------------------------------------------------------*/ +/** @file + * @brief + */ + +#ifndef matrix_basis_h +#define matrix_basis_h + +#include + +/* This file contains functions for setting and retrieving the basis vectors + * or transposed basis vectors of a matrix representing a 3D or 2D transform, + * either by index (0,1,2) or name (x,y,z). + * + * In addition to being a convenience for the user, the functions are also + * in support of other matrix functions which are best implemented in vector + * form (such as orthogonalization and construction of orthonormal bases). + * + * Note that matrix expression arguments are allowed to have dimensions larger + * than the minimum requirement. For example, matrix_get_basis_vector() can be + * called on any NxM matrix with N,M >= 3. + * + * As with other matrix functions, the following template argument notation is + * used for conciseness: + * + * E = vector or matrix element type + * A = vector or matrix array storage type + * B = matrix basis orientation type + * L = matrix layout type + */ + +namespace cml { + +////////////////////////////////////////////////////////////////////////////// +// Functions for setting the basis vectors of a 3D or 2D transform matrix +////////////////////////////////////////////////////////////////////////////// + +/** Set the i'th basis vector of a 3D transform */ +template < typename E, class A, class B, class L, class VecT > void +matrix_set_basis_vector(matrix& m, size_t i, const VecT& v) +{ + /* Checking */ + detail::CheckMatLinear3D(m); + detail::CheckVec3(v); + detail::CheckIndex3(i); + + m.set_basis_element(i,0,v[0]); + m.set_basis_element(i,1,v[1]); + m.set_basis_element(i,2,v[2]); +} + +/** Set the i'th transposed basis vector of a 3D transform */ +template < typename E, class A, class B, class L, class VecT > void +matrix_set_transposed_basis_vector(matrix& m,size_t i,const VecT& v) +{ + /* Checking */ + detail::CheckMatLinear3D(m); + detail::CheckVec3(v); + detail::CheckIndex3(i); + + m.set_basis_element(0,i,v[0]); + m.set_basis_element(1,i,v[1]); + m.set_basis_element(2,i,v[2]); +} + +/** Set the i'th basis vector of a 2D transform */ +template < typename E, class A, class B, class L, class VecT > void +matrix_set_basis_vector_2D(matrix& m, size_t i, const VecT& v) +{ + /* Checking */ + detail::CheckMatLinear2D(m); + detail::CheckVec2(v); + detail::CheckIndex2(i); + + m.set_basis_element(i,0,v[0]); + m.set_basis_element(i,1,v[1]); +} + +/** Set the i'th transposed basis vector of a 2D transform */ +template < typename E, class A, class B, class L, class VecT > void +matrix_set_transposed_basis_vector_2D( + matrix& m, size_t i, const VecT& v) +{ + /* Checking */ + detail::CheckMatLinear2D(m); + detail::CheckVec2(v); + detail::CheckIndex2(i); + + m.set_basis_element(0,i,v[0]); + m.set_basis_element(1,i,v[1]); +} + +/** Set the x basis vector of a 3D transform */ +template < typename E, class A, class B, class L, class VecT > void +matrix_set_x_basis_vector(matrix& m, const VecT& x) { + matrix_set_basis_vector(m,0,x); +} + +/** Set the y basis vector of a 3D transform */ +template < typename E, class A, class B, class L, class VecT > void +matrix_set_y_basis_vector(matrix& m, const VecT& y) { + matrix_set_basis_vector(m,1,y); +} + +/** Set the z basis vector of a 3D transform */ +template < typename E, class A, class B, class L, class VecT > void +matrix_set_z_basis_vector(matrix& m, const VecT& z) { + matrix_set_basis_vector(m,2,z); +} + +/** Set the transposed x basis vector of a 3D transform */ +template < typename E, class A, class B, class L, class VecT > void +matrix_set_transposed_x_basis_vector(matrix& m, const VecT& x) { + matrix_set_transposed_basis_vector(m,0,x); +} + +/** Set the transposed y basis vector of a 3D transform */ +template < typename E, class A, class B, class L, class VecT > void +matrix_set_transposed_y_basis_vector(matrix& m, const VecT& y) { + matrix_set_transposed_basis_vector(m,1,y); +} + +/** Set the transposed z basis vector of a 3D transform */ +template < typename E, class A, class B, class L, class VecT > void +matrix_set_transposed_z_basis_vector(matrix& m, const VecT& z) { + matrix_set_transposed_basis_vector(m,2,z); +} + +/** Set the x basis vector of a 2D transform */ +template < typename E, class A, class B, class L, class VecT > void +matrix_set_x_basis_vector_2D(matrix& m, const VecT& x) { + matrix_set_basis_vector_2D(m,0,x); +} + +/** Set the y basis vector of a 2D transform */ +template < typename E, class A, class B, class L, class VecT > void +matrix_set_y_basis_vector_2D(matrix& m, const VecT& y) { + matrix_set_basis_vector_2D(m,1,y); +} + +/** Set the transposed x basis vector of a 2D transform */ +template < typename E, class A, class B, class L, class VecT > void +matrix_set_transposed_x_basis_vector_2D(matrix& m,const VecT& x) { + matrix_set_transposed_basis_vector_2D(m,0,x); +} + +/** Set the transposed y basis vector of a 2D transform */ +template < typename E, class A, class B, class L, class VecT > void +matrix_set_transposed_y_basis_vector_2D(matrix& m,const VecT& y) { + matrix_set_transposed_basis_vector_2D(m,1,y); +} + +/** Set the basis vectors of a 3D transform */ +template < typename E, class A, class B, class L, + class VecT_1, class VecT_2, class VecT_3 > void +matrix_set_basis_vectors( + matrix& m, const VecT_1& x, const VecT_2& y, const VecT_3& z) +{ + matrix_set_x_basis_vector(m,x); + matrix_set_y_basis_vector(m,y); + matrix_set_z_basis_vector(m,z); +} + +/** Set the transposed basis vectors of a 3D transform */ +template < typename E, class A, class B, class L, + class VecT_1, class VecT_2, class VecT_3 > void +matrix_set_transposed_basis_vectors( + matrix& m, const VecT_1& x, const VecT_2& y, const VecT_3& z) +{ + matrix_set_transposed_x_basis_vector(m,x); + matrix_set_transposed_y_basis_vector(m,y); + matrix_set_transposed_z_basis_vector(m,z); +} + +/** Set the basis vectors of a 2D transform */ +template < typename E,class A,class B,class L,class VecT_1,class VecT_2 > void +matrix_set_basis_vectors_2D( + matrix& m, const VecT_1& x, const VecT_2& y) +{ + matrix_set_x_basis_vector_2D(m,x); + matrix_set_y_basis_vector_2D(m,y); +} + +/** Set the transposed basis vectors of a 2D transform */ +template < typename E,class A,class B,class L,class VecT_1,class VecT_2 > void +matrix_set_transposed_basis_vectors_2D( + matrix& m, const VecT_1& x, const VecT_2& y) +{ + matrix_set_transposed_x_basis_vector_2D(m,x); + matrix_set_transposed_y_basis_vector_2D(m,y); +} + +////////////////////////////////////////////////////////////////////////////// +// Functions for getting the basis vectors of a 3D or 2D transform matrix +////////////////////////////////////////////////////////////////////////////// + +#define TEMP_VEC3 vector< typename MatT::value_type, fixed<3> > +#define TEMP_VEC2 vector< typename MatT::value_type, fixed<2> > + +/** Get the i'th basis vector of a 3D transform */ +template < class MatT > TEMP_VEC3 +matrix_get_basis_vector(const MatT& m, size_t i) +{ + typedef TEMP_VEC3 vector_type; + + /* Checking */ + detail::CheckMatLinear3D(m); + detail::CheckIndex3(i); + + return vector_type( + m.basis_element(i,0), m.basis_element(i,1), m.basis_element(i,2)); +} + +/** Get the i'th transposed basis vector of a 3D transform */ +template < class MatT > TEMP_VEC3 +matrix_get_transposed_basis_vector(const MatT& m, size_t i) +{ + typedef typename MatT::value_type value_type; + typedef vector< value_type, fixed<3> > vector_type; + + /* Checking */ + detail::CheckMatLinear3D(m); + detail::CheckIndex3(i); + + return vector_type( + m.basis_element(0,i), m.basis_element(1,i), m.basis_element(2,i)); +} + +/** Get the i'th basis vector of a 2D transform */ +template < class MatT > TEMP_VEC2 +matrix_get_basis_vector_2D(const MatT& m, size_t i) +{ + typedef TEMP_VEC2 vector_type; + + /* Checking */ + detail::CheckMatLinear2D(m); + detail::CheckIndex2(i); + + return vector_type(m.basis_element(i,0), m.basis_element(i,1)); +} + +/** Get the i'th transposed basis vector of a 2D transform */ +template < class MatT > TEMP_VEC2 +matrix_get_transposed_basis_vector_2D(const MatT& m, size_t i) +{ + typedef TEMP_VEC2 vector_type; + + /* Checking */ + detail::CheckMatLinear2D(m); + detail::CheckIndex2(i); + + return vector_type(m.basis_element(0,i), m.basis_element(1,i)); +} + +/** Get the x basis vector of a 3D transform */ +template < class MatT > TEMP_VEC3 +matrix_get_x_basis_vector(const MatT& m) { + return matrix_get_basis_vector(m,0); +} + +/** Get the y basis vector of a 3D transform */ +template < class MatT > TEMP_VEC3 +matrix_get_y_basis_vector(const MatT& m) { + return matrix_get_basis_vector(m,1); +} + +/** Get the z basis vector of a 3D transform */ +template < class MatT > TEMP_VEC3 +matrix_get_z_basis_vector(const MatT& m) { + return matrix_get_basis_vector(m,2); +} + +/** Get the transposed x basis vector of a 3D transform */ +template < class MatT > TEMP_VEC3 +matrix_get_transposed_x_basis_vector(const MatT& m) { + return matrix_get_transposed_basis_vector(m,0); +} + +/** Get the transposed y basis vector of a 3D transform */ +template < class MatT > TEMP_VEC3 +matrix_get_transposed_y_basis_vector(const MatT& m) { + return matrix_get_transposed_basis_vector(m,1); +} + +/** Get the transposed z basis vector of a 3D transform */ +template < class MatT > TEMP_VEC3 +matrix_get_transposed_z_basis_vector(const MatT& m) { + return matrix_get_transposed_basis_vector(m,2); +} + +/** Get the x basis vector of a 2D transform */ +template < class MatT > TEMP_VEC2 +matrix_get_x_basis_vector_2D(const MatT& m) { + return matrix_get_basis_vector_2D(m,0); +} + +/** Get the y basis vector of a 2D transform */ +template < class MatT > TEMP_VEC2 +matrix_get_y_basis_vector_2D(const MatT& m) { + return matrix_get_basis_vector_2D(m,1); +} + +/** Get the transposed x basis vector of a 2D transform */ +template < class MatT > TEMP_VEC2 +matrix_get_transposed_x_basis_vector_2D(const MatT& m) { + return matrix_get_transposed_basis_vector_2D(m,0); +} + +/** Get the transposed y basis vector of a 2D transform */ +template < class MatT > TEMP_VEC2 +matrix_get_transposed_y_basis_vector_2D(const MatT& m) { + return matrix_get_transposed_basis_vector_2D(m,1); +} + +/** Get the basis vectors of a 3D transform */ +template < class MatT, class E, class A > void +matrix_get_basis_vectors( + const MatT& m, vector& x, vector& y, vector& z) +{ + x = matrix_get_x_basis_vector(m); + y = matrix_get_y_basis_vector(m); + z = matrix_get_z_basis_vector(m); +} + +/** Get the transposed basis vectors of a 3D transform */ +template < class MatT, typename E, class A > void +matrix_get_transposed_basis_vectors( + const MatT& m, vector& x, vector& y, vector& z) +{ + x = matrix_get_transposed_x_basis_vector(m); + y = matrix_get_transposed_y_basis_vector(m); + z = matrix_get_transposed_z_basis_vector(m); +} + +/** Get the basis vectors of a 2D transform */ +template < class MatT, typename E, class A > void +matrix_get_basis_vectors_2D(const MatT& m,vector& x,vector& y) +{ + x = matrix_get_x_basis_vector_2D(m); + y = matrix_get_y_basis_vector_2D(m); +} + +/** Get the transposed basis vectors of a 2D transform */ +template < class MatT, typename E, class A > void +matrix_get_transposed_basis_vectors_2D( + const MatT& m, vector& x, vector& y) +{ + x = matrix_get_transposed_x_basis_vector_2D(m); + y = matrix_get_transposed_y_basis_vector_2D(m); +} + +#undef TEMP_VEC3 +#undef TEMP_VEC2 + +} // namespace cml + +#endif diff --git a/Lib/Include/CML/mathlib/matrix_concat.h b/Lib/Include/CML/mathlib/matrix_concat.h new file mode 100644 index 0000000..8e789aa --- /dev/null +++ b/Lib/Include/CML/mathlib/matrix_concat.h @@ -0,0 +1,62 @@ +/* -*- C++ -*- ------------------------------------------------------------ + +Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/ + +The Configurable Math Library (CML) is distributed under the terms of the +Boost Software License, v1.0 (see cml/LICENSE for details). + + *-----------------------------------------------------------------------*/ +/** @file + * @brief + */ + +#ifndef matrix_concat_h +#define matrix_concat_h + +#include + +/* This will all most likely be abstracted away in a future version of the + * CML. For now, this file provides support for functions that need to + * concatenate transformation matrices in a basis-independent manner. + * + * @todo: The 2x2 and 3x3 versions of these functions are currently in + * matrix_rotation.h. They should be moved here. + */ + +namespace cml { +namespace detail { + +/** A fixed-size temporary 4x4 matrix */ +#define MAT_TEMP_4X4 matrix< \ + typename et::ScalarPromote< \ + typename MatT_1::value_type, \ + typename MatT_2::value_type \ + >::type, \ + fixed<4,4>, \ + typename MatT_1::basis_orient, \ + typename MatT_1::layout \ +> + +template < class MatT_1, class MatT_2 > MAT_TEMP_4X4 +matrix_concat_transforms_4x4(const MatT_1& m1, const MatT_2& m2, row_basis) { + return m1*m2; +} + +/** Concatenate two 3D col-basis rotation matrices in the order m1->m2 */ +template < class MatT_1, class MatT_2 > MAT_TEMP_4X4 +matrix_concat_transforms_4x4(const MatT_1& m1, const MatT_2& m2, col_basis) { + return m2*m1; +} + +/** Concatenate two 3D rotation matrices in the order m1->m2 */ +template < class MatT_1, class MatT_2 > MAT_TEMP_4X4 +matrix_concat_transforms_4x4(const MatT_1& m1, const MatT_2& m2) { + return matrix_concat_transforms_4x4(m1,m2,typename MatT_1::basis_orient()); +} + +#undef MAT_TEMP_4x4 + +} // namespace detail +} // namespace cml + +#endif diff --git a/Lib/Include/CML/mathlib/matrix_misc.h b/Lib/Include/CML/mathlib/matrix_misc.h new file mode 100644 index 0000000..c36a399 --- /dev/null +++ b/Lib/Include/CML/mathlib/matrix_misc.h @@ -0,0 +1,135 @@ +/* -*- C++ -*- ------------------------------------------------------------ + +Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/ + +The Configurable Math Library (CML) is distributed under the terms of the +Boost Software License, v1.0 (see cml/LICENSE for details). + + *-----------------------------------------------------------------------*/ +/** @file + * @brief + */ + +#ifndef matrix_misc_h +#define matrix_misc_h + +#include + +/* Miscellaneous matrix functions. */ + +namespace cml { + +/** Set a (possibly non-square) matrix to represent an identity transform */ +template < typename E, class A, class B, class L > void +identity_transform(matrix& m) +{ + typedef matrix matrix_type; + typedef typename matrix_type::value_type value_type; + + for (size_t i = 0; i < m.rows(); ++i) { + for (size_t j = 0; j < m.cols(); ++j) { + m(i,j) = value_type((i == j) ? 1 : 0); + } + } +} + +/** Trace of a square matrix */ +template < class MatT > typename MatT::value_type +trace(const MatT& m) +{ + typedef typename MatT::value_type value_type; + + /* Checking */ + detail::CheckMatSquare(m); + + value_type t = value_type(0); + for (size_t i = 0; i < m.rows(); ++i) { + t += m(i,i); + } + return t; +} + +/** Trace of the upper-left 3x3 part of a matrix */ +template < class MatT > typename MatT::value_type +trace_3x3(const MatT& m) +{ + /* Checking */ + detail::CheckMatMin3x3(m); + + return m(0,0) + m(1,1) + m(2,2); +} + +/** Trace of the upper-left 2x2 part of a matrix */ +template < class MatT > typename MatT::value_type +trace_2x2(const MatT& m) +{ + /* Checking */ + detail::CheckMatMin2x2(m); + + return m(0,0) + m(1,1); +} + +/** 3D skew-symmetric matrix */ +template < typename E, class A, class B, class L, class VecT > void +matrix_skew_symmetric(matrix& m, const VecT& v) +{ + /* Checking */ + detail::CheckMatMin3x3(m); + detail::CheckVec3(v); + + m.zero(); + + m.set_basis_element(1,2, v[0]); + m.set_basis_element(2,1,-v[0]); + m.set_basis_element(2,0, v[1]); + m.set_basis_element(0,2,-v[1]); + m.set_basis_element(0,1, v[2]); + m.set_basis_element(1,0,-v[2]); +} + +/** 2D skew-symmetric matrix */ +template < typename E, class A, class B, class L > void +matrix_skew_symmetric_2D(matrix& m, E s) +{ + /* Checking */ + detail::CheckMatMin2x2(m); + + m.zero(); + + m.set_basis_element(0,1, s); + m.set_basis_element(1,0,-s); +} + +/* @todo: Clean this up, and implement SRT as well */ + +/** Invert a matrix consisting of a 3D rotation and translation */ +template < typename E, class A, class B, class L > void +matrix_invert_RT_only(matrix& m) +{ + typedef vector< E, fixed<3> > vector_type; + + vector_type x, y, z; + matrix_get_basis_vectors(m,x,y,z); + matrix_set_transposed_basis_vectors(m,x,y,z); + + vector_type p = matrix_get_translation(m); + matrix_set_translation(m,-dot(p,x),-dot(p,y),-dot(p,z)); +} + +/** Invert a matrix consisting of a 2D rotation and ranslation */ +template < typename E, class A, class B, class L > void +matrix_invert_RT_only_2D(matrix& m) +{ + typedef vector< E, fixed<2> > vector_type; + + vector_type x, y; + matrix_get_basis_vectors_2D(m,x,y); + matrix_set_transposed_basis_vectors_2D(m,x,y); + + vector_type p = matrix_get_translation_2D(m); + matrix_set_translation_2D(m,-dot(p,x),-dot(p,y)); +} + +} // namespace cml + +#endif diff --git a/Lib/Include/CML/mathlib/matrix_ortho.h b/Lib/Include/CML/mathlib/matrix_ortho.h new file mode 100644 index 0000000..f0087f2 --- /dev/null +++ b/Lib/Include/CML/mathlib/matrix_ortho.h @@ -0,0 +1,60 @@ +/* -*- C++ -*- ------------------------------------------------------------ + +Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/ + +The Configurable Math Library (CML) is distributed under the terms of the +Boost Software License, v1.0 (see cml/LICENSE for details). + + *-----------------------------------------------------------------------*/ +/** @file + * @brief + */ + +#ifndef matrix_ortho_h +#define matrix_ortho_h + +#include + +/* Functions for orthogonalizing a matrix. + * + * matrix_orthogonalize_3x3() and _2x2() operate on the upper-left-hand part + * of any matrix of suitable size; this is to allow orthonormalization of the + * rotation part of an affine transform matrix. + * + * Note: These functions pass off to the orthonormalization functions in + * vector_ortho.h, so see that file for details on the optional parameters. + * + * @todo: General NxN matrix orthogonalization. + */ + +namespace cml { + +/** Orthogonalize the upper-left 3x3 portion of a matrix */ +template < typename E, class A, class B, class L > void +matrix_orthogonalize_3x3(matrix& m, size_t stable_axis = 2, + size_t num_iter = 0, E s = E(1)) +{ + typedef vector< E, fixed<3> > vector_type; + + vector_type x, y, z; + matrix_get_basis_vectors(m,x,y,z); + orthonormalize(x,y,z,stable_axis,num_iter,s); + matrix_set_basis_vectors(m,x,y,z); +} + +/** Orthogonalize the upper-left 2x2 portion of a matrix */ +template < typename E, class A, class B, class L > void +matrix_orthogonalize_2x2(matrix& m, size_t stable_axis = 0, + size_t num_iter = 0, E s = E(1)) +{ + typedef vector< E, fixed<2> > vector_type; + + vector_type x, y; + matrix_get_basis_vectors_2D(m,x,y); + orthonormalize(x,y,stable_axis,num_iter,s); + matrix_set_basis_vectors_2D(m,x,y); +} + +} // namespace cml + +#endif diff --git a/Lib/Include/CML/mathlib/matrix_projection.h b/Lib/Include/CML/mathlib/matrix_projection.h new file mode 100644 index 0000000..2b07727 --- /dev/null +++ b/Lib/Include/CML/mathlib/matrix_projection.h @@ -0,0 +1,348 @@ +/* -*- C++ -*- ------------------------------------------------------------ + +Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/ + +The Configurable Math Library (CML) is distributed under the terms of the +Boost Software License, v1.0 (see cml/LICENSE for details). + + *-----------------------------------------------------------------------*/ +/** @file + * @brief + */ + +#ifndef matrix_projection_h +#define matrix_projection_h + +#include +#include + +/* Functions for building matrix transforms other than rotations + * (matrix_rotation.h) and viewing projections (matrix_projection.h). + * + * @todo: Clean up comments and documentation throughout. + */ + +// NOTE: Changed 'near' and 'far' to 'n' and 'f' throughout to work around +// windows.h 'near' and 'far' macros. + +namespace cml { + +////////////////////////////////////////////////////////////////////////////// +// 3D perspective projection from frustum +////////////////////////////////////////////////////////////////////////////// + +/** Build a matrix representing a perspective projection, specified by frustum + * bounds in l,r,b,t,n,f form, and with the given handedness and z clipping + * range + */ +template < typename E, class A, class B, class L > void +matrix_perspective(matrix& m, E left, E right, E bottom, E top, + E n, E f, Handedness handedness, + ZClip z_clip) +{ + typedef matrix matrix_type; + typedef typename matrix_type::value_type value_type; + + /* Checking */ + detail::CheckMatHomogeneous3D(m); + + identity_transform(m); + + value_type inv_width = value_type(1) / (right - left); + value_type inv_height = value_type(1) / (top - bottom); + value_type inv_depth = value_type(1) / (f - n); + value_type near2 = value_type(2) * n; + value_type s = handedness == left_handed + ? value_type(1) : value_type(-1); + + if (z_clip == z_clip_neg_one) { + m.set_basis_element(2,2,s * (f + n) * inv_depth); + m.set_basis_element(3,2,value_type(-2) * f * n * inv_depth); + } else { // z_clip == z_clip_zero + m.set_basis_element(2,2,s * f * inv_depth); + m.set_basis_element(3,2,-s * n * m.basis_element(2,2)); + } + + m.set_basis_element(0,0,near2 * inv_width ); + m.set_basis_element(1,1,near2 * inv_height ); + m.set_basis_element(2,0,-s * (right + left) * inv_width ); + m.set_basis_element(2,1,-s * (top + bottom) * inv_height); + m.set_basis_element(2,3,s ); + m.set_basis_element(3,3,value_type(0) ); +} + +/** Build a matrix representing a perspective projection, specified by frustum + * bounds in w,h,n,f form, and with the given handedness and z clipping + * range + */ +template < typename E, class A, class B, class L > void +matrix_perspective(matrix& m, E width, E height, E n, E f, + Handedness handedness, ZClip z_clip) +{ + typedef matrix matrix_type; + typedef typename matrix_type::value_type value_type; + + value_type half_width = width * value_type(.5); + value_type half_height = height * value_type(.5); + matrix_perspective(m, -half_width, half_width, + -half_height, half_height, n, f, handedness, z_clip); +} + +/** Build a left-handedness frustum perspective matrix */ +template < typename E, class A, class B, class L > void +matrix_perspective_LH(matrix& m, E left, E right, E bottom, + E top, E n, E f, ZClip z_clip) +{ + matrix_perspective(m, left, right, bottom, top, n, f, + left_handed, z_clip); +} + +/** Build a right-handedness frustum perspective matrix */ +template < typename E, class A, class B, class L > void +matrix_perspective_RH(matrix& m, E left, E right, E bottom, + E top, E n, E f, ZClip z_clip) +{ + matrix_perspective(m, left, right, bottom, top, n, f, + right_handed, z_clip); +} + +/** Build a left-handedness frustum perspective matrix */ +template < typename E, class A, class B, class L > void +matrix_perspective_LH(matrix& m, E width, E height, E n, + E f, ZClip z_clip) +{ + matrix_perspective(m, width, height, n, f, left_handed, z_clip); +} + +/** Build a right-handedness frustum perspective matrix */ +template < typename E, class A, class B, class L > void +matrix_perspective_RH(matrix& m, E width, E height, E n, + E f, ZClip z_clip) +{ + matrix_perspective(m, width, height, n, f, right_handed, z_clip); +} + +////////////////////////////////////////////////////////////////////////////// +// 3D perspective projection from horizontal field of view +////////////////////////////////////////////////////////////////////////////// + +/** Build a perspective matrix */ +template < typename E, class A, class B, class L > void +matrix_perspective_xfov(matrix& m, E xfov, E aspect, E n, + E f, Handedness handedness, ZClip z_clip) +{ + typedef matrix matrix_type; + typedef typename matrix_type::value_type value_type; + + value_type width = value_type(2) * std::tan(xfov * value_type(.5)) * n; + matrix_perspective(m, width, width / aspect, n, f, + handedness, z_clip); +} + +/** Build a left-handedness perspective matrix */ +template < typename E, class A, class B, class L > void +matrix_perspective_xfov_LH(matrix& m, E xfov, E aspect, E n, + E f, ZClip z_clip) +{ + matrix_perspective_xfov(m,xfov,aspect,n,f,left_handed,z_clip); +} + +/** Build a right-handedness perspective matrix */ +template < typename E, class A, class B, class L > void +matrix_perspective_xfov_RH(matrix& m, E xfov, E aspect, E n, + E f, ZClip z_clip) +{ + matrix_perspective_xfov(m,xfov,aspect,n,f,right_handed,z_clip); +} + +////////////////////////////////////////////////////////////////////////////// +// 3D perspective projection from vertical field of view +////////////////////////////////////////////////////////////////////////////// + +/** Build a perspective matrix */ +template < typename E, class A, class B, class L > void +matrix_perspective_yfov(matrix& m, E yfov, E aspect, E n, + E f, Handedness handedness, ZClip z_clip) +{ + typedef matrix matrix_type; + typedef typename matrix_type::value_type value_type; + + value_type height = value_type(2) * std::tan(yfov * value_type(.5)) * n; + matrix_perspective(m, height * aspect, height, n, f, + handedness, z_clip); +} + +/** Build a left-handedness perspective matrix */ +template < typename E, class A, class B, class L > void +matrix_perspective_yfov_LH(matrix& m, E yfov, E aspect, E n, + E f, ZClip z_clip) +{ + matrix_perspective_yfov(m,yfov,aspect,n,f,left_handed,z_clip); +} + +/** Build a right-handedness perspective matrix */ +template < typename E, class A, class B, class L > void +matrix_perspective_yfov_RH(matrix& m, E yfov, E aspect, E n, + E f, ZClip z_clip) +{ + matrix_perspective_yfov(m,yfov,aspect,n,f,right_handed,z_clip); +} + +////////////////////////////////////////////////////////////////////////////// +// 3D orthographic projection from frustum +////////////////////////////////////////////////////////////////////////////// + +/** Build a matrix representing an orthographic projection, specified by + * frustum bounds in l,r,b,t,n,f form, and with the given handedness and z + * clipping range + */ + +template < typename E, class A, class B, class L > void +matrix_orthographic(matrix& m, E left, E right, E bottom, E top, + E n, E f, Handedness handedness, + ZClip z_clip) +{ + typedef matrix matrix_type; + typedef typename matrix_type::value_type value_type; + + /* Checking */ + detail::CheckMatHomogeneous3D(m); + + identity_transform(m); + + value_type inv_width = value_type(1) / (right - left); + value_type inv_height = value_type(1) / (top - bottom); + value_type inv_depth = value_type(1) / (f - n); + value_type s = handedness == left_handed + ? value_type(1) : value_type(-1); + + if (z_clip == z_clip_neg_one) { + m.set_basis_element(2,2,s * value_type(2) * inv_depth); + m.set_basis_element(3,2,-(f + n) * inv_depth); + } else { // z_clip.z_clip() == 0 + m.set_basis_element(2,2,s * inv_depth); + m.set_basis_element(3,2,-n * inv_depth); + } + + m.set_basis_element(0,0,value_type(2) * inv_width ); + m.set_basis_element(1,1,value_type(2) * inv_height ); + m.set_basis_element(3,0,-(right + left) * inv_width ); + m.set_basis_element(3,1,-(top + bottom) * inv_height); +} + +/** Build an orthographic projection matrix */ +template < typename E, class A, class B, class L > void +matrix_orthographic(matrix& m, E width, E height, E n, E f, + Handedness handedness, ZClip z_clip) +{ + typedef matrix matrix_type; + typedef typename matrix_type::value_type value_type; + + value_type half_width = width * value_type(.5); + value_type half_height = height * value_type(.5); + matrix_orthographic(m, -half_width, half_width, + -half_height, half_height, n, f, handedness, z_clip); +} + +/** Build a left-handedness orthographic projection matrix */ +template < typename E, class A, class B, class L > void +matrix_orthographic_LH(matrix& m, E left, E right, E bottom, + E top, E n, E f, ZClip z_clip) +{ + matrix_orthographic(m, left, right, bottom, top, n, f, + left_handed, z_clip); +} + +/** Build a right-handedness orthographic projection matrix */ +template < typename E, class A, class B, class L > void +matrix_orthographic_RH(matrix& m, E left, E right, E bottom, + E top, E n, E f, ZClip z_clip) +{ + matrix_orthographic(m, left, right, bottom, top, n, f, + right_handed, z_clip); +} + +/** Build a left-handedness orthographic projection matrix */ +template < typename E, class A, class B, class L > void +matrix_orthographic_LH(matrix& m, E width, E height, E n, + E f, ZClip z_clip) +{ + matrix_orthographic(m, width, height, n, f, left_handed, + z_clip); +} + +/** Build a right-handedness orthographic projection matrix */ +template < typename E, class A, class B, class L > void +matrix_orthographic_RH(matrix& m, E width, E height, E n, + E f, ZClip z_clip) +{ + matrix_orthographic(m, width, height, n, f, right_handed, + z_clip); +} + +////////////////////////////////////////////////////////////////////////////// +// 3D viewport +////////////////////////////////////////////////////////////////////////////// + +/* Build a viewport matrix + * + * Note: A viewport matrix is in a sense the opposite of an orthographics + * projection matrix, and can be build by constructing and inverting the + * latter. + * + * @todo: Need to look into D3D viewport conventions and see if this needs to + * be adapted accordingly. + */ + +template < typename E, class A, class B, class L > void +matrix_viewport(matrix& m, E left, E right, E bottom, + E top, ZClip z_clip, E n = E(0), E f = E(1)) +{ + matrix_orthographic_LH(m, left, right, bottom, top, n, f, z_clip); + /* @todo: invert(m), when available */ + m = inverse(m); +} + +////////////////////////////////////////////////////////////////////////////// +// 3D picking volume +////////////////////////////////////////////////////////////////////////////// + +/* Build a pick volume matrix + * + * When post-concatenated with a projection matrix, the pick matrix modifies + * the view volume to create a 'picking volume'. This volume corresponds to + * a screen rectangle centered at (pick_x, pick_y) and with dimensions + * pick_widthXpick_height. + * + * @todo: Representation of viewport between this function and + * matrix_viewport() is inconsistent (position and dimensions vs. bounds). + * Should this be addressed? + */ + +template < typename E, class A, class B, class L > void +matrix_pick( + matrix& m, E pick_x, E pick_y, E pick_width, E pick_height, + E viewport_x, E viewport_y, E viewport_width, E viewport_height) +{ + typedef matrix matrix_type; + typedef typename matrix_type::value_type value_type; + + /* Checking */ + detail::CheckMatHomogeneous3D(m); + + identity_transform(m); + + value_type inv_width = value_type(1) / pick_width; + value_type inv_height = value_type(1) / pick_height; + + m.set_basis_element(0,0,viewport_width*inv_width); + m.set_basis_element(1,1,viewport_height*inv_height); + m.set_basis_element(3,0, + (viewport_width+value_type(2)*(viewport_x-pick_x))*inv_width); + m.set_basis_element(3,1, + (viewport_height+value_type(2)*(viewport_y-pick_y))*inv_height); +} + +} // namespace cml + +#endif diff --git a/Lib/Include/CML/mathlib/matrix_rotation.h b/Lib/Include/CML/mathlib/matrix_rotation.h new file mode 100644 index 0000000..2a30f3a --- /dev/null +++ b/Lib/Include/CML/mathlib/matrix_rotation.h @@ -0,0 +1,980 @@ +/* -*- C++ -*- ------------------------------------------------------------ + +Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/ + +The Configurable Math Library (CML) is distributed under the terms of the +Boost Software License, v1.0 (see cml/LICENSE for details). + + *-----------------------------------------------------------------------*/ +/** @file + * @brief + */ + +#ifndef matrix_rotation_h +#define matrix_rotation_h + +#include +#include + +/* Functions related to matrix rotations in 3D and 2D. */ + +namespace cml { + +////////////////////////////////////////////////////////////////////////////// +// 3D rotation about world axes +////////////////////////////////////////////////////////////////////////////// + +/** Build a matrix representing a 3D rotation about the given world axis */ +template < typename E, class A, class B, class L > void +matrix_rotation_world_axis( matrix& m, size_t axis, E angle) +{ + typedef matrix matrix_type; + typedef typename matrix_type::value_type value_type; + + /* Checking */ + detail::CheckMatLinear3D(m); + detail::CheckIndex3(axis); + + size_t i, j, k; + cyclic_permutation(axis, i, j, k); + + value_type s = value_type(std::sin(angle)); + value_type c = value_type(std::cos(angle)); + + identity_transform(m); + + m.set_basis_element(j,j, c); + m.set_basis_element(j,k, s); + m.set_basis_element(k,j,-s); + m.set_basis_element(k,k, c); +} + +/** Build a matrix representing a 3D rotation about the world x axis */ +template < typename E, class A, class B, class L > void +matrix_rotation_world_x(matrix& m, E angle) { + matrix_rotation_world_axis(m,0,angle); +} + +/** Build a matrix representing a 3D rotation about the world y axis */ +template < typename E, class A, class B, class L > void +matrix_rotation_world_y(matrix& m, E angle) { + matrix_rotation_world_axis(m,1,angle); +} + +/** Build a matrix representing a 3D rotation about the world z axis */ +template < typename E, class A, class B, class L > void +matrix_rotation_world_z(matrix& m, E angle) { + matrix_rotation_world_axis(m,2,angle); +} + +////////////////////////////////////////////////////////////////////////////// +// 3D rotation from an axis-angle pair +////////////////////////////////////////////////////////////////////////////// + +/** Build a rotation matrix from an axis-angle pair */ +template < typename E, class A, class B, class L, class VecT > void +matrix_rotation_axis_angle(matrix& m, const VecT& axis, E angle) +{ + typedef matrix matrix_type; + typedef typename matrix_type::value_type value_type; + + /* Checking */ + detail::CheckMatLinear3D(m); + detail::CheckVec3(axis); + + identity_transform(m); + + value_type s = std::sin(angle); + value_type c = std::cos(angle); + value_type omc = value_type(1) - c; + + value_type xomc = axis[0] * omc; + value_type yomc = axis[1] * omc; + value_type zomc = axis[2] * omc; + + value_type xxomc = axis[0] * xomc; + value_type yyomc = axis[1] * yomc; + value_type zzomc = axis[2] * zomc; + value_type xyomc = axis[0] * yomc; + value_type yzomc = axis[1] * zomc; + value_type zxomc = axis[2] * xomc; + + value_type xs = axis[0] * s; + value_type ys = axis[1] * s; + value_type zs = axis[2] * s; + + m.set_basis_element(0,0, xxomc + c ); + m.set_basis_element(0,1, xyomc + zs); + m.set_basis_element(0,2, zxomc - ys); + m.set_basis_element(1,0, xyomc - zs); + m.set_basis_element(1,1, yyomc + c ); + m.set_basis_element(1,2, yzomc + xs); + m.set_basis_element(2,0, zxomc + ys); + m.set_basis_element(2,1, yzomc - xs); + m.set_basis_element(2,2, zzomc + c ); +} + +////////////////////////////////////////////////////////////////////////////// +// 3D rotation from a quaternion +////////////////////////////////////////////////////////////////////////////// + +/** Build a rotation matrix from a quaternion */ +template < typename E, class A, class B, class L, class QuatT > void +matrix_rotation_quaternion(matrix& m, const QuatT& q) +{ + typedef matrix matrix_type; + typedef QuatT quaternion_type; + typedef typename quaternion_type::order_type order_type; + typedef typename matrix_type::value_type value_type; + + enum { + W = order_type::W, + X = order_type::X, + Y = order_type::Y, + Z = order_type::Z + }; + + /* Checking */ + detail::CheckMatLinear3D(m); + detail::CheckQuat(q); + + identity_transform(m); + + value_type x2 = q[X] + q[X]; + value_type y2 = q[Y] + q[Y]; + value_type z2 = q[Z] + q[Z]; + + value_type xx2 = q[X] * x2; + value_type yy2 = q[Y] * y2; + value_type zz2 = q[Z] * z2; + value_type xy2 = q[X] * y2; + value_type yz2 = q[Y] * z2; + value_type zx2 = q[Z] * x2; + value_type xw2 = q[W] * x2; + value_type yw2 = q[W] * y2; + value_type zw2 = q[W] * z2; + + m.set_basis_element(0,0, value_type(1) - yy2 - zz2); + m.set_basis_element(0,1, xy2 + zw2); + m.set_basis_element(0,2, zx2 - yw2); + m.set_basis_element(1,0, xy2 - zw2); + m.set_basis_element(1,1, value_type(1) - zz2 - xx2); + m.set_basis_element(1,2, yz2 + xw2); + m.set_basis_element(2,0, zx2 + yw2); + m.set_basis_element(2,1, yz2 - xw2); + m.set_basis_element(2,2, value_type(1) - xx2 - yy2); +} + +////////////////////////////////////////////////////////////////////////////// +// 3D rotation from Euler angles +////////////////////////////////////////////////////////////////////////////// + +/** Build a rotation matrix from an Euler-angle triple + * + * The rotations are applied about the cardinal axes in the order specified by + * the 'order' argument, where 'order' is one of the following enumerants: + * + * euler_order_xyz + * euler_order_xzy + * euler_order_xyx + * euler_order_xzx + * euler_order_yzx + * euler_order_yxz + * euler_order_yzy + * euler_order_yxy + * euler_order_zxy + * euler_order_zyx + * euler_order_zxz + * euler_order_zyz + * + * e.g. euler_order_xyz means compute the column-basis rotation matrix + * equivalent to R_x * R_y * R_z, where R_i is the rotation matrix above + * axis i (the row-basis matrix would be R_z * R_y * R_x). + */ +template < typename E, class A, class B, class L > void +matrix_rotation_euler(matrix& m, E angle_0, E angle_1, E angle_2, + EulerOrder order) +{ + typedef matrix matrix_type; + typedef typename matrix_type::value_type value_type; + + /* Checking */ + detail::CheckMatLinear3D(m); + + identity_transform(m); + + size_t i, j, k; + bool odd, repeat; + detail::unpack_euler_order(order, i, j, k, odd, repeat); + + if (odd) { + angle_0 = -angle_0; + angle_1 = -angle_1; + angle_2 = -angle_2; + } + + value_type s0 = std::sin(angle_0); + value_type c0 = std::cos(angle_0); + value_type s1 = std::sin(angle_1); + value_type c1 = std::cos(angle_1); + value_type s2 = std::sin(angle_2); + value_type c2 = std::cos(angle_2); + + value_type s0s2 = s0 * s2; + value_type s0c2 = s0 * c2; + value_type c0s2 = c0 * s2; + value_type c0c2 = c0 * c2; + + if (repeat) { + m.set_basis_element(i,i, c1 ); + m.set_basis_element(i,j, s1 * s2 ); + m.set_basis_element(i,k,-s1 * c2 ); + m.set_basis_element(j,i, s0 * s1 ); + m.set_basis_element(j,j,-c1 * s0s2 + c0c2); + m.set_basis_element(j,k, c1 * s0c2 + c0s2); + m.set_basis_element(k,i, c0 * s1 ); + m.set_basis_element(k,j,-c1 * c0s2 - s0c2); + m.set_basis_element(k,k, c1 * c0c2 - s0s2); + } else { + m.set_basis_element(i,i, c1 * c2 ); + m.set_basis_element(i,j, c1 * s2 ); + m.set_basis_element(i,k,-s1 ); + m.set_basis_element(j,i, s1 * s0c2 - c0s2); + m.set_basis_element(j,j, s1 * s0s2 + c0c2); + m.set_basis_element(j,k, s0 * c1 ); + m.set_basis_element(k,i, s1 * c0c2 + s0s2); + m.set_basis_element(k,j, s1 * c0s2 - s0c2); + m.set_basis_element(k,k, c0 * c1 ); + } +} + +/** Build a matrix of derivatives of Euler angles about the specified axis. + * + * The rotation derivatives are applied about the cardinal axes in the + * order specified by the 'order' argument, where 'order' is one of the + * following enumerants: + * + * euler_order_xyz + * euler_order_xzy + * euler_order_yzx + * euler_order_yxz + * euler_order_zxy + * euler_order_zyx + * + * e.g. euler_order_xyz means compute the column-basis rotation matrix + * equivalent to R_x * R_y * R_z, where R_i is the rotation matrix above + * axis i (the row-basis matrix would be R_z * R_y * R_x). + * + * The derivative is taken with respect to the specified 'axis', which is + * the position of the axis in the triple; e.g. if order = euler_order_xyz, + * then axis = 0 would mean take the derivative with respect to x. Note + * that repeated axes are not currently supported. + */ +template < typename E, class A, class B, class L > void +matrix_rotation_euler_derivatives( + matrix& m, int axis, E angle_0, E angle_1, E angle_2, + EulerOrder order) +{ + typedef matrix matrix_type; + typedef typename matrix_type::value_type value_type; + + /* Checking */ + detail::CheckMatLinear3D(m); + + size_t i, j, k; + bool odd, repeat; + detail::unpack_euler_order(order, i, j, k, odd, repeat); + if(repeat) throw std::invalid_argument( + "matrix_rotation_euler_derivatives does not support repeated axes"); + + if (odd) { + angle_0 = -angle_0; + angle_1 = -angle_1; + angle_2 = -angle_2; + } + + value_type s0 = std::sin(angle_0); + value_type c0 = std::cos(angle_0); + value_type s1 = std::sin(angle_1); + value_type c1 = std::cos(angle_1); + value_type s2 = std::sin(angle_2); + value_type c2 = std::cos(angle_2); + + value_type s0s2 = s0 * s2; + value_type s0c2 = s0 * c2; + value_type c0s2 = c0 * s2; + value_type c0c2 = c0 * c2; + + if(axis == 0) { + m.set_basis_element(i,i, 0. ); + m.set_basis_element(i,j, 0. ); + m.set_basis_element(i,k, 0. ); + m.set_basis_element(j,i, s1 * c0*c2 + s0*s2); + m.set_basis_element(j,j, s1 * c0*s2 - s0*c2); + m.set_basis_element(j,k, c0 * c1 ); + m.set_basis_element(k,i,-s1 * s0*c2 + c0*s2); + m.set_basis_element(k,j,-s1 * s0*s2 - c0*c2); + m.set_basis_element(k,k,-s0 * c1 ); + } else if(axis == 1) { + m.set_basis_element(i,i,-s1 * c2 ); + m.set_basis_element(i,j,-s1 * s2 ); + m.set_basis_element(i,k,-c1 ); + m.set_basis_element(j,i, c1 * s0*c2 ); + m.set_basis_element(j,j, c1 * s0*s2 ); + m.set_basis_element(j,k,-s0 * s1 ); + m.set_basis_element(k,i, c1 * c0*c2 ); + m.set_basis_element(k,j, c1 * c0*s2 ); + m.set_basis_element(k,k,-c0 * s1 ); + } else if(axis == 2) { + m.set_basis_element(i,i,-c1 * s2 ); + m.set_basis_element(i,j, c1 * c2 ); + m.set_basis_element(i,k, 0. ); + m.set_basis_element(j,i,-s1 * s0*s2 - c0*c2); + m.set_basis_element(j,j, s1 * s0*c2 - c0*s2); + m.set_basis_element(j,k, 0. ); + m.set_basis_element(k,i,-s1 * c0*s2 + s0*c2); + m.set_basis_element(k,j, s1 * c0*c2 + s0*s2); + m.set_basis_element(k,k, 0. ); + } +} + +////////////////////////////////////////////////////////////////////////////// +// 3D rotation to align with a vector, multiple vectors, or the view plane +////////////////////////////////////////////////////////////////////////////// + +/** See vector_ortho.h for details */ +template < typename E,class A,class B,class L,class VecT_1,class VecT_2 > void +matrix_rotation_align( + matrix& m, + const VecT_1& align, + const VecT_2& reference, + bool normalize = true, + AxisOrder order = axis_order_zyx) +{ + typedef vector< E,fixed<3> > vector_type; + + identity_transform(m); + + vector_type x, y, z; + + orthonormal_basis(align, reference, x, y, z, normalize, order); + matrix_set_basis_vectors(m, x, y, z); +} + +/** See vector_ortho.h for details */ +template < typename E, class A, class B, class L, class VecT > void +matrix_rotation_align(matrix& m, const VecT& align, + bool normalize = true, AxisOrder order = axis_order_zyx) +{ + typedef vector< E,fixed<3> > vector_type; + + identity_transform(m); + + vector_type x, y, z; + + orthonormal_basis(align, x, y, z, normalize, order); + matrix_set_basis_vectors(m, x, y, z); +} + +/** See vector_ortho.h for details */ +template < typename E,class A,class B,class L,class VecT_1,class VecT_2 > void +matrix_rotation_align_axial(matrix& m, const VecT_1& align, + const VecT_2& axis, bool normalize = true, + AxisOrder order = axis_order_zyx) +{ + typedef vector< E,fixed<3> > vector_type; + + identity_transform(m); + + vector_type x, y, z; + + orthonormal_basis_axial(align, axis, x, y, z, normalize, order); + matrix_set_basis_vectors(m, x, y, z); +} + +/** See vector_ortho.h for details */ +template < typename E, class A, class B, class L, class MatT > void +matrix_rotation_align_viewplane( + matrix& m, + const MatT& view_matrix, + Handedness handedness, + AxisOrder order = axis_order_zyx) +{ + typedef vector< E, fixed<3> > vector_type; + + identity_transform(m); + + vector_type x, y, z; + + orthonormal_basis_viewplane(view_matrix, x, y, z, handedness, order); + matrix_set_basis_vectors(m, x, y, z); +} + +/** See vector_ortho.h for details */ +template < typename E, class A, class B, class L, class MatT > void +matrix_rotation_align_viewplane_LH( + matrix& m, + const MatT& view_matrix, + AxisOrder order = axis_order_zyx) +{ + matrix_rotation_align_viewplane( + m,view_matrix,left_handed,order); +} + +/** See vector_ortho.h for details */ +template < typename E, class A, class B, class L, class MatT > void +matrix_rotation_align_viewplane_RH( + matrix& m, + const MatT& view_matrix, + AxisOrder order = axis_order_zyx) +{ + matrix_rotation_align_viewplane( + m,view_matrix,right_handed,order); +} + +////////////////////////////////////////////////////////////////////////////// +// 3D rotation to aim at a target +////////////////////////////////////////////////////////////////////////////// + +/** See vector_ortho.h for details */ +template < typename E, class A, class B, class L, + class VecT_1, class VecT_2, class VecT_3 > void +matrix_rotation_aim_at( + matrix& m, + const VecT_1& pos, + const VecT_2& target, + const VecT_3& reference, + AxisOrder order = axis_order_zyx) +{ + matrix_rotation_align(m, target - pos, reference, true, order); +} + +/** See vector_ortho.h for details */ +template < typename E, class A, class B, class L, + class VecT_1, class VecT_2 > void +matrix_rotation_aim_at( + matrix& m, + const VecT_1& pos, + const VecT_2& target, + AxisOrder order = axis_order_zyx) +{ + matrix_rotation_align(m, target - pos, true, order); +} + +/** See vector_ortho.h for details */ +template < typename E, class A, class B, class L, + class VecT_1, class VecT_2, class VecT_3 > void +matrix_rotation_aim_at_axial( + matrix& m, + const VecT_1& pos, + const VecT_2& target, + const VecT_3& axis, + AxisOrder order = axis_order_zyx) +{ + matrix_rotation_align_axial(m, target - pos, axis, true, order); +} + +////////////////////////////////////////////////////////////////////////////// +// 2D rotation +////////////////////////////////////////////////////////////////////////////// + +/** Build a matrix representing a 2D rotation */ +template < typename E, class A, class B, class L > void +matrix_rotation_2D( matrix& m, E angle) +{ + typedef matrix matrix_type; + typedef typename matrix_type::value_type value_type; + + /* Checking */ + detail::CheckMatLinear2D(m); + + value_type s = value_type(std::sin(angle)); + value_type c = value_type(std::cos(angle)); + + identity_transform(m); + + m.set_basis_element(0,0, c); + m.set_basis_element(0,1, s); + m.set_basis_element(1,0,-s); + m.set_basis_element(1,1, c); +} + +////////////////////////////////////////////////////////////////////////////// +// 2D rotation to align with a vector +////////////////////////////////////////////////////////////////////////////// + +/** See vector_ortho.h for details */ +template < typename E, class A, class B, class L, class VecT > void +matrix_rotation_align_2D(matrix& m, const VecT& align, + bool normalize = true, AxisOrder2D order = axis_order_xy) +{ + typedef vector< E, fixed<2> > vector_type; + + identity_transform(m); + + vector_type x, y; + + orthonormal_basis_2D(align, x, y, normalize, order); + matrix_set_basis_vectors_2D(m, x, y); +} + +////////////////////////////////////////////////////////////////////////////// +// 3D relative rotation about world axes +////////////////////////////////////////////////////////////////////////////// + +/** Rotate a rotation matrix about the given world axis */ +template < typename E, class A, class B, class L > void +matrix_rotate_about_world_axis(matrix& m, size_t axis, E angle) +{ + typedef matrix matrix_type; + typedef typename matrix_type::value_type value_type; + + /* Checking */ + detail::CheckMatLinear3D(m); + detail::CheckIndex3(axis); + + size_t i, j, k; + cyclic_permutation(axis, i, j, k); + + value_type s = value_type(std::sin(angle)); + value_type c = value_type(std::cos(angle)); + + value_type ij = c * m.basis_element(i,j) - s * m.basis_element(i,k); + value_type jj = c * m.basis_element(j,j) - s * m.basis_element(j,k); + value_type kj = c * m.basis_element(k,j) - s * m.basis_element(k,k); + + m.set_basis_element(i,k, s*m.basis_element(i,j) + c*m.basis_element(i,k)); + m.set_basis_element(j,k, s*m.basis_element(j,j) + c*m.basis_element(j,k)); + m.set_basis_element(k,k, s*m.basis_element(k,j) + c*m.basis_element(k,k)); + + m.set_basis_element(i,j,ij); + m.set_basis_element(j,j,jj); + m.set_basis_element(k,j,kj); +} + +/** Rotate a rotation matrix about the world x axis */ +template < typename E, class A, class B, class L > void +matrix_rotate_about_world_x(matrix& m, E angle) { + matrix_rotate_about_world_axis(m,0,angle); +} + +/** Rotate a rotation matrix about the world y axis */ +template < typename E, class A, class B, class L > void +matrix_rotate_about_world_y(matrix& m, E angle) { + matrix_rotate_about_world_axis(m,1,angle); +} + +/** Rotate a rotation matrix about the world z axis */ +template < typename E, class A, class B, class L > void +matrix_rotate_about_world_z(matrix& m, E angle) { + matrix_rotate_about_world_axis(m,2,angle); +} + +////////////////////////////////////////////////////////////////////////////// +// 3D relative rotation about local axes +////////////////////////////////////////////////////////////////////////////// + +/** Rotate a rotation matrix about the given local axis */ +template < typename E, class A, class B, class L > void +matrix_rotate_about_local_axis(matrix& m, size_t axis, E angle) +{ + typedef matrix matrix_type; + typedef typename matrix_type::value_type value_type; + + /* Checking */ + detail::CheckMatLinear3D(m); + detail::CheckIndex3(axis); + + size_t i, j, k; + cyclic_permutation(axis, i, j, k); + + value_type s = value_type(std::sin(angle)); + value_type c = value_type(std::cos(angle)); + + value_type j0 = c * m.basis_element(j,0) + s * m.basis_element(k,0); + value_type j1 = c * m.basis_element(j,1) + s * m.basis_element(k,1); + value_type j2 = c * m.basis_element(j,2) + s * m.basis_element(k,2); + + m.set_basis_element(k,0, c*m.basis_element(k,0) - s*m.basis_element(j,0)); + m.set_basis_element(k,1, c*m.basis_element(k,1) - s*m.basis_element(j,1)); + m.set_basis_element(k,2, c*m.basis_element(k,2) - s*m.basis_element(j,2)); + + m.set_basis_element(j,0,j0); + m.set_basis_element(j,1,j1); + m.set_basis_element(j,2,j2); +} + +/** Rotate a rotation matrix about its local x axis */ +template < typename E, class A, class B, class L > void +matrix_rotate_about_local_x(matrix& m, E angle) { + matrix_rotate_about_local_axis(m,0,angle); +} + +/** Rotate a rotation matrix about its local y axis */ +template < typename E, class A, class B, class L > void +matrix_rotate_about_local_y(matrix& m, E angle) { + matrix_rotate_about_local_axis(m,1,angle); +} + +/** Rotate a rotation matrix about its local z axis */ +template < typename E, class A, class B, class L > void +matrix_rotate_about_local_z(matrix& m, E angle) { + matrix_rotate_about_local_axis(m,2,angle); +} + +////////////////////////////////////////////////////////////////////////////// +// 2D relative rotation +////////////////////////////////////////////////////////////////////////////// + +template < typename E, class A, class B, class L > void +matrix_rotate_2D(matrix& m, E angle) +{ + typedef matrix matrix_type; + typedef typename matrix_type::value_type value_type; + + /* Checking */ + detail::CheckMatLinear2D(m); + + value_type s = value_type(std::sin(angle)); + value_type c = value_type(std::cos(angle)); + + value_type m00 = c * m.basis_element(0,0) - s * m.basis_element(0,1); + value_type m10 = c * m.basis_element(1,0) - s * m.basis_element(1,1); + + m.set_basis_element(0,1, s*m.basis_element(0,0) + c*m.basis_element(0,1)); + m.set_basis_element(1,1, s*m.basis_element(1,0) + c*m.basis_element(1,1)); + + m.set_basis_element(0,0,m00); + m.set_basis_element(1,0,m10); +} + +////////////////////////////////////////////////////////////////////////////// +// Rotation from vector to vector +////////////////////////////////////////////////////////////////////////////// + +/** Build a rotation matrix to rotate from one vector to another + * + * Note: The quaternion algorithm is more stable than the matrix algorithm, so + * we simply pass off to the quaternion function here. + */ +template < class E,class A,class B,class L,class VecT_1,class VecT_2 > void +matrix_rotation_vec_to_vec( + matrix& m, + const VecT_1& v1, + const VecT_2& v2, + bool unit_length_vectors = false) +{ + typedef quaternion< E,fixed<>,vector_first,positive_cross > + quaternion_type; + + quaternion_type q; + quaternion_rotation_vec_to_vec(q,v1,v2,unit_length_vectors); + matrix_rotation_quaternion(m,q); +} + +////////////////////////////////////////////////////////////////////////////// +// Scale the angle of a rotation matrix +////////////////////////////////////////////////////////////////////////////// + +/** Scale the angle of a 3D rotation matrix */ +template < typename E, class A, class B, class L > void +matrix_scale_rotation_angle(matrix& m, E t, + E tolerance = epsilon::placeholder()) +{ + typedef vector< E,fixed<3> > vector_type; + typedef typename vector_type::value_type value_type; + + vector_type axis; + value_type angle; + matrix_to_axis_angle(m, axis, angle, tolerance); + matrix_rotation_axis_angle(m, axis, angle * t); +} + +/** Scale the angle of a 2D rotation matrix */ +template < typename E, class A, class B, class L > void +matrix_scale_rotation_angle_2D( + matrix& m, E t, E tolerance = epsilon::placeholder()) +{ + typedef vector< E,fixed<2> > vector_type; + typedef typename vector_type::value_type value_type; + + value_type angle = matrix_to_rotation_2D(m); + matrix_rotation_2D(m, angle * t); +} + +////////////////////////////////////////////////////////////////////////////// +// Support functions for uniform handling of row- and column-basis matrices +////////////////////////////////////////////////////////////////////////////// + +/* Note: The matrix rotation slerp, difference and concatenation functions do + * not use et::MatrixPromote::temporary_type as the return type, even + * though that is the return type of the underlying matrix multiplication. + * This is because the sizes of these matrices are known at compile time (3x3 + * and 2x2), and using fixed<> obviates the need for resizing of intermediate + * temporaries. + * + * Also, no size- or type-checking is done on the arguments to these + * functions, as any such errors will be caught by the matrix multiplication + * and assignment to the 3x3 temporary. + */ + +/** A fixed-size temporary 3x3 matrix */ +#define MAT_TEMP_3X3 matrix< \ + typename et::ScalarPromote< \ + typename MatT_1::value_type, \ + typename MatT_2::value_type \ + >::type, \ + fixed<3,3>, \ + typename MatT_1::basis_orient, \ + row_major \ +> + +/** A fixed-size temporary 2x2 matrix */ +#define MAT_TEMP_2X2 matrix< \ + typename et::ScalarPromote< \ + typename MatT_1::value_type, \ + typename MatT_2::value_type \ + >::type, \ + fixed<2,2>, \ + typename MatT_1::basis_orient, \ + row_major \ +> + +namespace detail { + +/** Concatenate two 3D row-basis rotation matrices in the order m1->m2 */ +template < class MatT_1, class MatT_2 > MAT_TEMP_3X3 +matrix_concat_rotations(const MatT_1& m1, const MatT_2& m2, row_basis) { + return m1*m2; +} + +/** Concatenate two 3D col-basis rotation matrices in the order m1->m2 */ +template < class MatT_1, class MatT_2 > MAT_TEMP_3X3 +matrix_concat_rotations(const MatT_1& m1, const MatT_2& m2, col_basis) { + return m2*m1; +} + +/** Concatenate two 3D rotation matrices in the order m1->m2 */ +template < class MatT_1, class MatT_2 > MAT_TEMP_3X3 +matrix_concat_rotations(const MatT_1& m1, const MatT_2& m2) { + return matrix_concat_rotations(m1,m2,typename MatT_1::basis_orient()); +} + +/** Concatenate two 2D row-basis rotation matrices in the order m1->m2 */ +template < class MatT_1, class MatT_2 > MAT_TEMP_2X2 +matrix_concat_rotations_2D(const MatT_1& m1, const MatT_2& m2, row_basis) { + return m1*m2; +} + +/** Concatenate two 2D col-basis rotation matrices in the order m1->m2 */ +template < class MatT_1, class MatT_2 > MAT_TEMP_2X2 +matrix_concat_rotations_2D(const MatT_1& m1, const MatT_2& m2, col_basis) { + return m2*m1; +} + +/** Concatenate two 2D rotation matrices in the order m1->m2 */ +template < class MatT_1, class MatT_2 > MAT_TEMP_2X2 +matrix_concat_rotations_2D(const MatT_1& m1, const MatT_2& m2) { + return matrix_concat_rotations_2D(m1,m2,typename MatT_1::basis_orient()); +} + +} // namespace detail + +////////////////////////////////////////////////////////////////////////////// +// Matrix rotation difference +////////////////////////////////////////////////////////////////////////////// + +/** Return the rotational 'difference' between two 3D rotation matrices */ +template < class MatT_1, class MatT_2 > MAT_TEMP_3X3 +matrix_rotation_difference(const MatT_1& m1, const MatT_2& m2) { + return detail::matrix_concat_rotations(transpose(m1),m2); +} + +/** Return the rotational 'difference' between two 2D rotation matrices */ +template < class MatT_1, class MatT_2 > MAT_TEMP_2X2 +matrix_rotation_difference_2D(const MatT_1& m1, const MatT_2& m2) { + return detail::matrix_concat_rotations_2D(transpose(m1),m2); +} + +////////////////////////////////////////////////////////////////////////////// +// Spherical linear interpolation of rotation matrices +////////////////////////////////////////////////////////////////////////////// + +/* @todo: It might be as fast or faster to simply convert the matrices to + * quaternions, interpolate, and convert back. + * + * @todo: The behavior of matrix slerp is currently a little different than + * for quaternions: in the matrix function, when the two matrices are close + * to identical the first is returned, while in the quaternion function the + * quaternions are nlerp()'d in this case. + * + * I still need to do the equivalent of nlerp() for matrices, in which case + * these functions could be revised to pass off to nlerp() when the matrices + * are nearly aligned. +*/ + +/** Spherical linear interpolation of two 3D rotation matrices */ +template < class MatT_1, class MatT_2, typename E > MAT_TEMP_3X3 +matrix_slerp(const MatT_1& m1, const MatT_2& m2, E t, + E tolerance = epsilon::placeholder()) +{ + typedef MAT_TEMP_3X3 temporary_type; + + temporary_type m = matrix_rotation_difference(m1,m2); + matrix_scale_rotation_angle(m,t,tolerance); + return detail::matrix_concat_rotations(m1,m); +} + +/** Spherical linear interpolation of two 2D rotation matrices */ +template < class MatT_1, class MatT_2, typename E > MAT_TEMP_2X2 +matrix_slerp_2D(const MatT_1& m1, const MatT_2& m2, E t, + E tolerance = epsilon::placeholder()) +{ + typedef MAT_TEMP_2X2 temporary_type; + + temporary_type m = matrix_rotation_difference_2D(m1,m2); + matrix_scale_rotation_angle_2D(m,t,tolerance); + return detail::matrix_concat_rotations_2D(m1,m); +} + +#undef MAT_TEMP_3X3 +#undef MAT_TEMP_2X2 + +////////////////////////////////////////////////////////////////////////////// +// Conversions +////////////////////////////////////////////////////////////////////////////// + +/** Convert a 3D rotation matrix to an axis-angle pair */ +template < class MatT, typename E, class A > void +matrix_to_axis_angle( + const MatT& m, + vector& axis, + E& angle, + E tolerance = epsilon::placeholder()) +{ + typedef MatT matrix_type; + typedef typename matrix_type::value_type value_type; + + /* Checking */ + detail::CheckMatLinear3D(m); + + axis.set( + m.basis_element(1,2) - m.basis_element(2,1), + m.basis_element(2,0) - m.basis_element(0,2), + m.basis_element(0,1) - m.basis_element(1,0) + ); + value_type l = length(axis); + value_type tmo = trace_3x3(m) - value_type(1); + + if (l > tolerance) { + axis /= l; + angle = std::atan2(l, tmo); // l=2sin(theta),tmo=2cos(theta) + } else if (tmo > value_type(0)) { + axis.zero(); + angle = value_type(0); + } else { + size_t largest_diagonal_element = + index_of_max( + m.basis_element(0,0), + m.basis_element(1,1), + m.basis_element(2,2) + ); + size_t i, j, k; + cyclic_permutation(largest_diagonal_element, i, j, k); + axis[i] = + std::sqrt( + m.basis_element(i,i) - + m.basis_element(j,j) - + m.basis_element(k,k) + + value_type(1) + ) * value_type(.5); + value_type s = value_type(.5) / axis[i]; + axis[j] = m.basis_element(i,j) * s; + axis[k] = m.basis_element(i,k) * s; + angle = constants::pi(); + } +} + +/** Convert a 3D rotation matrix to an Euler-angle triple */ +template < class MatT, typename Real > +void matrix_to_euler( + const MatT& m, + Real& angle_0, + Real& angle_1, + Real& angle_2, + EulerOrder order, + Real tolerance = epsilon::placeholder()) +{ + typedef MatT matrix_type; + typedef typename matrix_type::value_type value_type; + + /* Checking */ + detail::CheckMatLinear3D(m); + + size_t i, j, k; + bool odd, repeat; + detail::unpack_euler_order(order, i, j, k, odd, repeat); + + if (repeat) { + value_type s1 = length(m.basis_element(j,i),m.basis_element(k,i)); + value_type c1 = m.basis_element(i,i); + + angle_1 = std::atan2(s1, c1); + if (s1 > tolerance) { + angle_0 = std::atan2(m.basis_element(j,i),m.basis_element(k,i)); + angle_2 = std::atan2(m.basis_element(i,j),-m.basis_element(i,k)); + } else { + angle_0 = value_type(0); + angle_2 = sign(c1) * + std::atan2(-m.basis_element(k,j),m.basis_element(j,j)); + } + } else { + value_type s1 = -m.basis_element(i,k); + value_type c1 = length(m.basis_element(i,i),m.basis_element(i,j)); + + angle_1 = std::atan2(s1, c1); + if (c1 > tolerance) { + angle_0 = std::atan2(m.basis_element(j,k),m.basis_element(k,k)); + angle_2 = std::atan2(m.basis_element(i,j),m.basis_element(i,i)); + } else { + angle_0 = value_type(0); + angle_2 = -sign(s1) * + std::atan2(-m.basis_element(k,j),m.basis_element(j,j)); + } + } + + if (odd) { + angle_0 = -angle_0; + angle_1 = -angle_1; + angle_2 = -angle_2; + } +} + +/** Convenience function to return a 3D vector containing the Euler angles + * in the requested order. + */ +template < class MatT > vector< typename MatT::value_type, fixed<3> > +matrix_to_euler( + const MatT& m, + EulerOrder order, + const typename MatT::value_type& + tolerance = epsilon::placeholder()) +{ + typename MatT::value_type e0, e1, e2; + matrix_to_euler(m, e0, e1, e2, order, tolerance); + return vector< typename MatT::value_type, fixed<3> >(e0, e1, e2); +} + +/** Convert a 2D rotation matrix to a rotation angle */ +template < class MatT > typename MatT::value_type +matrix_to_rotation_2D(const MatT& m) +{ + /* Checking */ + detail::CheckMatLinear2D(m); + + return std::atan2(m.basis_element(0,1),m.basis_element(0,0)); +} + +} // namespace cml + +#endif diff --git a/Lib/Include/CML/mathlib/matrix_transform.h b/Lib/Include/CML/mathlib/matrix_transform.h new file mode 100644 index 0000000..bac6569 --- /dev/null +++ b/Lib/Include/CML/mathlib/matrix_transform.h @@ -0,0 +1,984 @@ +/* -*- C++ -*- ------------------------------------------------------------ + +Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/ + +The Configurable Math Library (CML) is distributed under the terms of the +Boost Software License, v1.0 (see cml/LICENSE for details). + + *-----------------------------------------------------------------------*/ +/** @file + * @brief + */ + +#ifndef matrix_transform_h +#define matrix_transform_h + +#include +#include +#include + +/* Functions for building matrix transforms other than rotations + * (matrix_rotation.h) and viewing projections (matrix_projection.h). + */ + +namespace cml { + +////////////////////////////////////////////////////////////////////////////// +// 3D translation +////////////////////////////////////////////////////////////////////////////// + +/** Build a matrix representing a 3D translation */ +template < typename E, class A, class B, class L > void +matrix_translation(matrix& m, E x, E y, E z) +{ + identity_transform(m); + matrix_set_translation(m,x,y,z); +} + +/** Build a matrix representing a 3D translation with z set to 0 */ +template < typename E, class A, class B, class L > void +matrix_translation(matrix& m, E x, E y) +{ + identity_transform(m); + matrix_set_translation(m,x,y); +} + +/** Build a matrix representing a 3D translation */ +template < typename E, class A, class B, class L, class VecT > void +matrix_translation(matrix& m, const VecT& translation) +{ + identity_transform(m); + matrix_set_translation(m,translation); +} + +////////////////////////////////////////////////////////////////////////////// +// 2D translation +////////////////////////////////////////////////////////////////////////////// + +/** Build a matrix representing a 2D translation */ +template < typename E, class A, class B, class L > void +matrix_translation_2D(matrix& m, E x, E y) +{ + identity_transform(m); + matrix_set_translation_2D(m,x,y); +} + +/** Build a matrix representing a 2D translation */ +template < typename E, class A, class B, class L, class VecT > void +matrix_translation_2D(matrix& m, const VecT& translation) +{ + identity_transform(m); + matrix_set_translation_2D(m, translation); +} + +////////////////////////////////////////////////////////////////////////////// +// 3D scale +////////////////////////////////////////////////////////////////////////////// + +/** Build a matrix representing a uniform 3D scale */ +template < typename E, class A, class B, class L > void +matrix_uniform_scale(matrix& m, E scale) { + matrix_scale(m,scale,scale,scale); +} + +/** Build a matrix representing a non-uniform 3D scale */ +template < typename E, class A, class B, class L > void +matrix_scale(matrix& m, E scale_x, E scale_y, E scale_z) +{ + /* Checking */ + detail::CheckMatLinear3D(m); + + identity_transform(m); + + m.set_basis_element(0,0,scale_x); + m.set_basis_element(1,1,scale_y); + m.set_basis_element(2,2,scale_z); +} + +/** Build a matrix representing a non-uniform 3D scale */ +template < typename E, class A, class B, class L, class VecT > void +matrix_scale(matrix& m, const VecT& scale) +{ + /* Checking */ + detail::CheckVec3(scale); + + matrix_scale(m, scale[0], scale[1], scale[2]); +} + +////////////////////////////////////////////////////////////////////////////// +// 2D scale +////////////////////////////////////////////////////////////////////////////// + +/** Build a matrix representing a uniform 2D scale */ +template < typename E, class A, class B, class L > void +matrix_uniform_scale_2D(matrix& m, E scale) { + matrix_scale_2D(m,scale,scale); +} + +/** Build a matrix representing a non-uniform 2D scale */ +template < typename E, class A, class B, class L > void +matrix_scale_2D(matrix& m, E scale_x, E scale_y) +{ + /* Checking */ + detail::CheckMatLinear2D(m); + + identity_transform(m); + + m.set_basis_element(0,0,scale_x); + m.set_basis_element(1,1,scale_y); +} + +/** Build a matrix representing a non-uniform 2D scale */ +template < typename E, class A, class B, class L, class VecT > void +matrix_scale_2D(matrix& m, const VecT& scale) +{ + /* Checking */ + detail::CheckVec2(scale); + + matrix_scale_2D(m, scale[0], scale[1]); +} + +////////////////////////////////////////////////////////////////////////////// +// 3D scale along axis +////////////////////////////////////////////////////////////////////////////// + +/** Build a matrix representing a 3D scale along an arbitrary axis */ +template < typename E, class A, class B, class L, class VecT > void +matrix_scale_along_axis(matrix&m, const VecT& axis, E scale) +{ + typedef matrix matrix_type; + typedef typename matrix_type::value_type value_type; + + /* Checking */ + detail::CheckVec3(axis); + + matrix,B,L> outer_p = outer(axis,axis)*(scale-value_type(1)); + outer_p(0,0) += value_type(1); + outer_p(1,1) += value_type(1); + outer_p(2,2) += value_type(1); + + matrix_linear_transform(m, outer_p); +} + +////////////////////////////////////////////////////////////////////////////// +// 2D scale along axis +////////////////////////////////////////////////////////////////////////////// + +/** Build a matrix representing a 2D scale along an arbitrary axis */ +template < typename E, class A, class B, class L, class VecT > +void matrix_scale_along_axis_2D(matrix& m, const VecT& axis, + E scale) +{ + typedef matrix matrix_type; + typedef typename matrix_type::value_type value_type; + + /* Checking */ + detail::CheckVec2(axis); + + matrix,B,L> outer_p = outer(axis,axis)*(scale-value_type(1)); + outer_p(0,0) += value_type(1); + outer_p(1,1) += value_type(1); + + matrix_linear_transform_2D(m, outer_p); +} + +////////////////////////////////////////////////////////////////////////////// +// 3D shear +////////////////////////////////////////////////////////////////////////////// + +/** Build a matrix representing a 3D shear along the specified world axis */ +template < typename E, class A, class B, class L > void +matrix_shear(matrix& m, size_t axis, E shear_s, E shear_t) +{ + /* Checking */ + detail::CheckMatLinear3D(m); + detail::CheckIndex3(axis); + + identity_transform(m); + + size_t i, j, k; + cyclic_permutation(axis, i, j, k); + + m.set_basis_element(i,j,shear_s); + m.set_basis_element(i,k,shear_t); +} + +/** Build a matrix representing a 3D shear along the world x axis */ +template < typename E, class A, class B, class L > void +matrix_shear_x(matrix& m, E shear_s, E shear_t) { + matrix_shear(m,0,shear_s,shear_t); +} + +/** Build a matrix representing a 3D shear along the world y axis */ +template < typename E, class A, class B, class L > void +matrix_shear_y(matrix& m, E shear_s, E shear_t) { + matrix_shear(m,1,shear_s,shear_t); +} + +/** Build a matrix representing a 3D shear along the world z axis */ +template < typename E, class A, class B, class L > void +matrix_shear_z(matrix& m, E shear_s, E shear_t) { + matrix_shear(m,2,shear_s,shear_t); +} + +////////////////////////////////////////////////////////////////////////////// +// 2D shear +////////////////////////////////////////////////////////////////////////////// + +/** Build a matrix representing a 2D shear along the specified world axis */ +template < typename E, class A, class B, class L > void +matrix_shear_2D(matrix& m, size_t axis, E shear) +{ + /* Checking */ + detail::CheckMatLinear2D(m); + detail::CheckIndex2(axis); + + identity_transform(m); + + size_t i, j; + cyclic_permutation(axis, i, j); + + m.set_basis_element(i,j,shear); +} + +/** Build a matrix representing a 2D shear along the world x axis */ +template < typename E, class A, class B, class L > void +matrix_shear_x_2D(matrix& m, E shear) { + matrix_shear_2D(m,0,shear); +} + +/** Build a matrix representing a 2D shear along the world y axis */ +template < typename E, class A, class B, class L > void +matrix_shear_y_2D(matrix& m, E shear) { + matrix_shear_2D(m,1,shear); +} + +////////////////////////////////////////////////////////////////////////////// +// 3D reflection +////////////////////////////////////////////////////////////////////////////// + +/** Build a matrix representing a 3D reflection along the given world axis */ +template < typename E, class A, class B, class L > void +matrix_reflect(matrix& m, size_t axis) +{ + typedef matrix matrix_type; + typedef typename matrix_type::value_type value_type; + + /* Checking */ + detail::CheckMatLinear3D(m); + detail::CheckIndex3(axis); + + identity_transform(m); + + m(axis,axis) = value_type(-1); +} + +/** Build a matrix representing a 3D reflection along the world x axis */ +template < typename E, class A, class B, class L > void +matrix_reflect_x(matrix& m) { + matrix_reflect(m,0); +} + +/** Build a matrix representing a 3D reflection along the world y axis */ +template < typename E, class A, class B, class L > void +matrix_reflect_y(matrix& m) { + matrix_reflect(m,1); +} + +/** Build a matrix representing a 3D reflection along the world z axis */ +template < typename E, class A, class B, class L > void +matrix_reflect_z(matrix& m) { + matrix_reflect(m,2); +} + +////////////////////////////////////////////////////////////////////////////// +// 2D reflection +////////////////////////////////////////////////////////////////////////////// + +/** Build a matrix representing a 2D reflection along the given world axis */ +template < typename E, class A, class B, class L > void +matrix_reflect_2D(matrix& m, size_t axis) +{ + typedef matrix matrix_type; + typedef typename matrix_type::value_type value_type; + + /* Checking */ + detail::CheckMatLinear2D(m); + detail::CheckIndex2(axis); + + identity_transform(m); + + m(axis,axis) = value_type(-1); +} + +/** Build a matrix representing a 2D reflection along the world x axis */ +template < typename E, class A, class B, class L > void +matrix_reflect_x_2D(matrix& m) { + matrix_reflect_2D(m,0); +} + +/** Build a matrix representing a 2D reflection along the world y axis */ +template < typename E, class A, class B, class L > void +matrix_reflect_y_2D(matrix& m) { + matrix_reflect_2D(m,1); +} + +////////////////////////////////////////////////////////////////////////////// +// 3D reflection about hyperplane +////////////////////////////////////////////////////////////////////////////// + +/** Build a matrix representing a 3D reflection about the given hyperplane */ +template < typename E, class A, class B, class L, class VecT > void +matrix_reflect_about_hplane(matrix& m, const VecT& normal) +{ + typedef matrix matrix_type; + typedef typename matrix_type::value_type value_type; + + matrix_scale_along_axis(m, normal, value_type(-1)); +} + +////////////////////////////////////////////////////////////////////////////// +// 2D reflection about hyperplane +////////////////////////////////////////////////////////////////////////////// + +/** Build a matrix representing a 2D reflection about the given hyperplane */ +template < typename E, class A, class B, class L, class VecT > void +matrix_reflect_about_hplane_2D(matrix&m, const VecT& normal) +{ + typedef matrix matrix_type; + typedef typename matrix_type::value_type value_type; + + matrix_scale_along_axis_2D(m, normal, value_type(-1)); +} + +////////////////////////////////////////////////////////////////////////////// +// 3D orthographic projection to cardinal hyperplane +////////////////////////////////////////////////////////////////////////////// + +/** Build a matrix representing an orthographic projection onto a plane */ +template < typename E, class A, class B, class L > void +matrix_ortho_project(matrix& m, size_t axis) +{ + typedef matrix matrix_type; + typedef typename matrix_type::value_type value_type; + + /* Checking */ + detail::CheckMatLinear3D(m); + detail::CheckIndex3(axis); + + identity_transform(m); + + m(axis,axis) = value_type(0); +} + +/** Build a matrix representing an orthographic projection onto the yz plane*/ +template < typename E, class A, class B, class L > void +matrix_ortho_project_yz(matrix& m) { + matrix_ortho_project(m,0); +} + +/** Build a matrix representing an orthographic projection onto the zx plane*/ +template < typename E, class A, class B, class L > void +matrix_ortho_project_zx(matrix& m) { + matrix_ortho_project(m,1); +} + +/** Build a matrix representing an orthographic projection onto the zy plane*/ +template < typename E, class A, class B, class L > void +matrix_ortho_project_xy(matrix& m) { + matrix_ortho_project(m,2); +} + +////////////////////////////////////////////////////////////////////////////// +// 2D orthographic projection to cardinal hyperplane +////////////////////////////////////////////////////////////////////////////// + +/** Build a matrix representing a 2D orthographic projection */ +template < typename E, class A, class B, class L > void +matrix_ortho_project_2D(matrix& m, size_t axis) +{ + typedef matrix matrix_type; + typedef typename matrix_type::value_type value_type; + + /* Checking */ + detail::CheckMatLinear2D(m); + detail::CheckIndex2(axis); + + identity_transform(m); + + m(axis,axis) = value_type(0); +} + +/** Build a matrix representing an orthographic projection onto the y axis */ +template < typename E, class A, class B, class L > void +matrix_ortho_project_y_2D(matrix& m) { + matrix_ortho_project_2D(m,0); +} + +/** Build a matrix representing an orthographic projection onto the x axis */ +template < typename E, class A, class B, class L > void +matrix_ortho_project_x_2D(matrix& m) { + matrix_ortho_project_2D(m,1); +} + +////////////////////////////////////////////////////////////////////////////// +// 3D orthographic projection to hyperplane +////////////////////////////////////////////////////////////////////////////// + +/** Build a matrix representing a 3D orthographic projection about the given + * hyperplane passing through the origin. + */ +template < typename E, class A, class B, class L, class VecT > void +matrix_ortho_project_to_hplane(matrix& m, const VecT& normal) +{ + typedef matrix matrix_type; + typedef typename matrix_type::value_type value_type; + + matrix_scale_along_axis(m, normal, value_type(0)); +} + +////////////////////////////////////////////////////////////////////////////// +// 2D orthographic projection to hyperplane +////////////////////////////////////////////////////////////////////////////// + +/** Build a matrix representing a 2D orthographic projection about the given + * hyperplane passing through the origin. + */ +template < typename E, class A, class B, class L, class VecT > void +matrix_ortho_project_to_hplane_2D(matrix& m, const VecT& normal) +{ + typedef matrix matrix_type; + typedef typename matrix_type::value_type value_type; + + matrix_scale_along_axis_2D(m, normal, value_type(0)); +} + +////////////////////////////////////////////////////////////////////////////// +// 3D 'aim at' +////////////////////////////////////////////////////////////////////////////// + +/** See vector_ortho.h for details */ +template < typename E, class A, class B, class L, + class VecT_1, class VecT_2, class VecT_3 > void +matrix_aim_at(matrix& m, const VecT_1& pos, const VecT_2& target, + const VecT_3& reference, + AxisOrder order = axis_order_zyx) +{ + matrix_rotation_aim_at(m, pos, target, reference, order); + matrix_set_translation(m, pos); +} + +/** See vector_ortho.h for details */ +template < typename E, class A, class B, class L, + class VecT_1, class VecT_2 > void +matrix_aim_at(matrix& m, const VecT_1& pos, const VecT_2& target, + AxisOrder order = axis_order_zyx) +{ + matrix_rotation_aim_at(m, pos, target, order); + matrix_set_translation(m, pos); +} + +/** See vector_ortho.h for details */ +template < typename E, class A, class B, class L, + class VecT_1, class VecT_2, class VecT_3 > void +matrix_aim_at_axial( + matrix& m, + const VecT_1& pos, + const VecT_2& target, + const VecT_3& axis, + AxisOrder order = axis_order_zyx) +{ + matrix_rotation_aim_at_axial(m, pos, target, axis, order); + matrix_set_translation(m, pos); +} + +/** See vector_ortho.h for details */ +template < typename E,class A,class B,class L,class VecT,class MatT > void +matrix_aim_at_viewplane( + matrix& m, + const VecT& pos, + const MatT& view_matrix, + Handedness handedness, + AxisOrder order = axis_order_zyx) +{ + matrix_rotation_align_viewplane(m, view_matrix, handedness, order); + matrix_set_translation(m, pos); +} + +////////////////////////////////////////////////////////////////////////////// +// 2D 'aim at' +////////////////////////////////////////////////////////////////////////////// + +/** See vector_ortho.h for details */ +template < typename E,class A,class B,class L,class VecT_1,class VecT_2 > void +matrix_aim_at_2D( + matrix& m, + const VecT_1& pos, + const VecT_2& target, + AxisOrder2D order = axis_order_xy) +{ + matrix_rotation_align_2D(m, target - pos, true, order); + matrix_set_translation_2D(m, pos); +} + +////////////////////////////////////////////////////////////////////////////// +// 3D 'look at' view matrix +////////////////////////////////////////////////////////////////////////////// + +/** Build a matrix representing a 'look at' view transform */ +template < typename E, class A, class B, class L, + class VecT_1, class VecT_2, class VecT_3 > void +matrix_look_at( + matrix& m, + const VecT_1& eye, + const VecT_2& target, + const VecT_3& up, + Handedness handedness) +{ + typedef matrix matrix_type; + typedef vector< E,fixed<3> > vector_type; + typedef typename matrix_type::value_type value_type; + + /* Checking */ + detail::CheckMatAffine3D(m); + + identity_transform(m); + + value_type s = handedness == left_handed ? + static_cast(1) : static_cast(-1); + vector_type z = s * normalize(target - eye); + vector_type x = unit_cross(up,z); + vector_type y = cross(z,x); + + matrix_set_transposed_basis_vectors(m,x,y,z); + matrix_set_translation(m,-dot(eye,x),-dot(eye,y),-dot(eye,z)); +} + +/** Build a matrix representing a left-handedness 'look at' view transform */ +template < typename E, class A, class B, class L, + class VecT_1, class VecT_2, class VecT_3 > void +matrix_look_at_LH(matrix& m, const VecT_1& eye, + const VecT_2& target, const VecT_3& up) +{ + matrix_look_at(m, eye, target, up, left_handed); +} + +/** Build a matrix representing a right-handedness 'look at' view transform */ +template < typename E, class A, class B, class L, + class VecT_1, class VecT_2, class VecT_3 > void +matrix_look_at_RH(matrix& m, const VecT_1& eye, + const VecT_2& target, const VecT_3& up) +{ + matrix_look_at(m, eye, target, up, right_handed); +} + +/** Build a matrix representing a 'look at' view transform */ +template < typename E, class A, class B, class L > void +matrix_look_at(matrix& m, E eye_x, E eye_y, E eye_z, E target_x, + E target_y, E target_z, E up_x, E up_y, E up_z, + Handedness handedness) +{ + typedef vector< E, fixed<3> > vector_type; + + matrix_look_at(m, + vector_type(eye_x,eye_y,eye_z), + vector_type(target_x,target_y,target_z), + vector_type(up_x,up_y,up_z), + handedness + ); +} + +/** Build a matrix representing a left-handed'look at' view transform */ +template < typename E, class A, class B, class L > void +matrix_look_at_LH(matrix& m, E eye_x, E eye_y, E eye_z, + E target_x, E target_y, E target_z, E up_x, E up_y, E up_z) +{ + matrix_look_at(m,eye_x,eye_y,eye_z,target_x,target_y,target_z,up_x,up_y, + up_z,left_handed); +} + +/** Build a matrix representing a right-handed'look at' view transform */ +template < typename E, class A, class B, class L > void +matrix_look_at_RH(matrix& m, E eye_x, E eye_y, E eye_z, + E target_x, E target_y, E target_z, E up_x, E up_y, E up_z) +{ + matrix_look_at(m,eye_x,eye_y,eye_z,target_x,target_y,target_z,up_x,up_y, + up_z,right_handed); +} + +////////////////////////////////////////////////////////////////////////////// +// 3D linear transform +////////////////////////////////////////////////////////////////////////////// + +/** Build a matrix from the 3x3 linear transform part of another matrix */ +template < typename E, class A, class B, class L, class MatT > void +matrix_linear_transform(matrix& m, const MatT& linear) +{ + /* Checking */ + detail::CheckMatLinear3D(m); + detail::CheckMatLinear3D(linear); + + identity_transform(m); + + for(size_t i = 0; i < 3; ++i) { + for(size_t j = 0; j < 3; ++j) { + m.set_basis_element(i,j,linear.basis_element(i,j)); + } + } +} + +////////////////////////////////////////////////////////////////////////////// +// 2D linear transform +////////////////////////////////////////////////////////////////////////////// + +/** Build a matrix from the 2x2 linear transform part of another matrix */ +template < typename E, class A, class B, class L, class MatT > void +matrix_linear_transform_2D(matrix& m, const MatT& linear) +{ + /* Checking */ + detail::CheckMatLinear2D(m); + detail::CheckMatLinear2D(linear); + + identity_transform(m); + + for(size_t i = 0; i < 2; ++i) { + for(size_t j = 0; j < 2; ++j) { + m.set_basis_element(i,j,linear.basis_element(i,j)); + } + } +} + +////////////////////////////////////////////////////////////////////////////// +// 3D affine transform +////////////////////////////////////////////////////////////////////////////// + +/** 3D affine transform from three basis vectors and a translation */ +template void +matrix_affine_transform(matrix& m, const VecT_1& x, const VecT_2& y, + const VecT_3& z, const VecT_4& translation) +{ + identity_transform(m); + matrix_set_basis_vectors(m,x,y,z); + matrix_set_translation(m,translation); +} + +/** 3D affine transform from a quaternion and a translation */ +template < + typename E, class A, class B, class L, + typename QE, class QA, class O, class C, class VecT > void +matrix_affine_transform( + matrix& m, const quaternion& q, + const VecT& translation) +{ + matrix_rotation_quaternion(m,q); + matrix_set_translation(m,translation); +} + +/** 3D affine transform from a quaternion expression and a translation */ +template < typename E,class A,class B,class L,class XprT,class VecT > void +matrix_affine_transform( + matrix& m, const et::QuaternionXpr& q, + const VecT& translation) +{ + matrix_rotation_quaternion(m,q); + matrix_set_translation(m,translation); +} + +/** 3D affine transform from an axis-angle pair and a translation */ +template < + typename E, class A, class B, class L, class VecT_1, class VecT_2 > void +matrix_affine_transform( + matrix& m,const VecT_1& axis,E angle,const VecT_2& translation) +{ + matrix_rotation_axis_angle(m,axis,angle); + matrix_set_translation(m,translation); +} + +/** 3D affine transform from an Euler-angle triple and a translation */ +template < typename E, class A, class B, class L, class VecT > void +matrix_affine_transform(matrix& m, E angle_0, E angle_1, + E angle_2, EulerOrder order, const VecT& translation) +{ + matrix_rotation_euler(m,angle_0,angle_1,angle_2,order); + matrix_set_translation(m,translation); +} + +/** 3D affine transform from a matrix and a translation */ +template < + typename E, class A, class B, class L, + typename ME, class MA, class MB, class ML, class VecT > void +matrix_affine_transform(matrix& m, + const matrix& linear, const VecT& translation) +{ + matrix_linear_transform(m,linear); + matrix_set_translation(m,translation); +} + +/** 3D affine transform from a matrix expression and a translation */ +template < typename E,class A,class B,class L,class XprT,class VecT > void +matrix_affine_transform( + matrix& m, const et::MatrixXpr& linear, + const VecT& translation) +{ + matrix_linear_transform(m,linear); + matrix_set_translation(m,translation); +} + +////////////////////////////////////////////////////////////////////////////// +// 2D affine transform +////////////////////////////////////////////////////////////////////////////// + +/** 2D affine transform from two basis vectors and a translation */ +template void +matrix_affine_transform_2D(matrix& m, const VecT_1& x, + const VecT_2& y, const VecT_3& translation) +{ + identity_transform(m); + matrix_set_basis_vectors_2D(m,x,y); + matrix_set_translation_2D(m,translation); +} + +/** 2D affine transform from a rotation angle and a translation */ +template +void matrix_affine_transform_2D(matrix& m, E angle, + const VecT& translation) +{ + matrix_rotation_2D(m,angle); + matrix_set_translation_2D(m,translation); +} + +/** 2D affine transform from a matrix and a translation */ +template < typename E,class A,class B,class L,class MatT,class VecT > void +matrix_affine_transform_2D( + matrix& m, const MatT& linear, const VecT& translation) +{ + matrix_linear_transform_2D(m, linear); + matrix_set_translation_2D(m,translation); +} + +////////////////////////////////////////////////////////////////////////////// +// 3D affine from 2D affine +////////////////////////////////////////////////////////////////////////////// + +/** Construct a 3D affine transform from a 2D affine transform */ +template < typename E, class A, class B, class L, class MatT > void +matrix_3D_affine_from_2D_affine(matrix& m, const MatT& affine_2D) +{ + typedef vector< E, fixed<2> > vector_type; + + vector_type x = matrix_get_x_basis_vector_2D(affine_2D); + vector_type y = matrix_get_y_basis_vector_2D(affine_2D); + vector_type p = matrix_get_translation_2D(affine_2D); + + identity_transform(m); + + matrix_set_basis_vectors_2D(m,x,y); + matrix_set_translation(m,p); +} + +////////////////////////////////////////////////////////////////////////////// +// 3D affine from 3D affine +////////////////////////////////////////////////////////////////////////////// + +/** Construct a 3D affine transform from another 3D affine transform */ +template < typename E, class A, class B, class L, class MatT > void +matrix_3D_affine_from_3D_affine(matrix& m, const MatT& affine_3D) +{ + typedef vector< E, fixed<3> > vector_type; + + vector_type x = matrix_get_x_basis_vector(affine_3D); + vector_type y = matrix_get_y_basis_vector(affine_3D); + vector_type z = matrix_get_z_basis_vector(affine_3D); + vector_type p = matrix_get_translation(affine_3D); + + identity_transform(m); + + matrix_set_basis_vectors(m,x,y,z); + matrix_set_translation(m,p); +} + +////////////////////////////////////////////////////////////////////////////// +// Matrix decomposition (scale->rotate->translate) +////////////////////////////////////////////////////////////////////////////// + +/* 3x3 matrix version */ +template < + class MatT, + typename Real, + typename ME, + class MA, + class B, + class L, + typename VE, + class VA +> +void matrix_decompose_SRT( + const MatT& m, + Real& scale_x, + Real& scale_y, + Real& scale_z, + matrix& rotation, + vector& translation) +{ + typedef MatT matrix_type; + typedef typename matrix_type::value_type value_type; + typedef vector > vector_type; + + /* Checking */ + detail::CheckMatAffine3D(m); + detail::CheckMatLinear3D(rotation); + + vector_type x, y, z; + matrix_get_basis_vectors(m, x, y, z); + + scale_x = x.length(); + scale_y = y.length(); + scale_z = z.length(); + + x /= scale_x; + y /= scale_y; + z /= scale_z; + + matrix_set_basis_vectors(rotation, x, y, z); + translation = matrix_get_translation(m); +} + +/* Quaternion version */ +template < + class MatT, + typename Real, + typename QE, + class QA, + class O, + class C, + typename VE, + class VA +> +void matrix_decompose_SRT( + const MatT& m, + Real& scale_x, + Real& scale_y, + Real& scale_z, + quaternion& rotation, + vector& translation) +{ + typedef MatT matrix_type; + typedef typename matrix_type::value_type value_type; + typedef matrix< value_type, fixed<3,3> > rotation_type; + + rotation_type rotation_matrix; + matrix_decompose_SRT( + m, scale_x, scale_y, scale_z, rotation_matrix, translation); + quaternion_rotation_matrix(rotation, rotation_matrix); +} + +/* Euler angle version */ +template < class MatT, typename Real, typename E, class A > +void matrix_decompose_SRT( + const MatT& m, + Real& scale_x, + Real& scale_y, + Real& scale_z, + Real& angle_0, + Real& angle_1, + Real& angle_2, + EulerOrder order, + vector& translation, + Real tolerance = epsilon::placeholder()) +{ + typedef MatT matrix_type; + typedef typename matrix_type::value_type value_type; + typedef matrix< value_type, fixed<3,3> > rotation_type; + + rotation_type rotation_matrix; + matrix_decompose_SRT( + m, scale_x, scale_y, scale_z, rotation_matrix, translation); + matrix_to_euler( + rotation_matrix, angle_0, angle_1, angle_2, order, tolerance); +} + +/* Axis-angle version */ +template < class MatT, typename Real, typename E, class A > +void matrix_decompose_SRT( + const MatT& m, + Real& scale_x, + Real& scale_y, + Real& scale_z, + vector& axis, + Real& angle, + vector& translation, + Real tolerance = epsilon::placeholder()) +{ + typedef MatT matrix_type; + typedef typename matrix_type::value_type value_type; + typedef matrix< value_type, fixed<3,3> > rotation_type; + + rotation_type rotation_matrix; + matrix_decompose_SRT( + m, scale_x, scale_y, scale_z, rotation_matrix, translation); + matrix_to_axis_angle(rotation_matrix, axis, angle, tolerance); +} + +/* 2x2 matrix version, 2-d */ +template < + class MatT, + typename Real, + typename ME, + class MA, + class B, + class L, + typename VE, + class VA +> +void matrix_decompose_SRT_2D( + const MatT& m, + Real& scale_x, + Real& scale_y, + matrix& rotation, + vector& translation) +{ + typedef MatT matrix_type; + typedef typename matrix_type::value_type value_type; + typedef vector > vector_type; + + /* Checking */ + detail::CheckMatAffine2D(m); + detail::CheckMatLinear2D(rotation); + + vector_type x, y; + matrix_get_basis_vectors_2D(m, x, y); + + scale_x = x.length(); + scale_y = y.length(); + + x /= scale_x; + y /= scale_y; + + matrix_set_basis_vectors_2D(rotation, x, y); + translation = matrix_get_translation_2D(m); +} + +/* Angle version, 2-d */ +template < class MatT, typename Real, typename E, class A > +void matrix_decompose_SRT_2D( + const MatT& m, + Real& scale_x, + Real& scale_y, + Real& angle, + vector& translation) +{ + typedef MatT matrix_type; + typedef typename matrix_type::value_type value_type; + typedef matrix< value_type, fixed<2,2> > rotation_type; + + rotation_type rotation_matrix; + matrix_decompose_SRT_2D( + m, scale_x, scale_y, rotation_matrix, translation); + angle = matrix_to_rotation_2D(rotation_matrix); +} + +} // namespace cml + +#endif diff --git a/Lib/Include/CML/mathlib/matrix_translation.h b/Lib/Include/CML/mathlib/matrix_translation.h new file mode 100644 index 0000000..664c577 --- /dev/null +++ b/Lib/Include/CML/mathlib/matrix_translation.h @@ -0,0 +1,177 @@ +/* -*- C++ -*- ------------------------------------------------------------ + +Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/ + +The Configurable Math Library (CML) is distributed under the terms of the +Boost Software License, v1.0 (see cml/LICENSE for details). + + *-----------------------------------------------------------------------*/ +/** @file + * @brief + */ + +#ifndef matrix_translation_h +#define matrix_translation_h + +#include + +/* Functions for getting and setting the translation of a 3D or 2D affine + * transform. + */ + +namespace cml { + +////////////////////////////////////////////////////////////////////////////// +// Functions for setting the translation of a 3D or 2D affine transform matrix +////////////////////////////////////////////////////////////////////////////// + +/** Set the translation of a 3D affine transform */ +template < typename E, class A, class B, class L > void +matrix_set_translation(matrix& m, E x, E y, E z) +{ + /* Checking */ + detail::CheckMatAffine3D(m); + + m.set_basis_element(3,0,x); + m.set_basis_element(3,1,y); + m.set_basis_element(3,2,z); +} + +/** Set the translation of a 3D affine transform with z set to 0 */ +template < typename E, class A, class B, class L > void +matrix_set_translation(matrix& m, E x, E y) +{ + typedef matrix matrix_type; + typedef typename matrix_type::value_type value_type; + + matrix_set_translation(m, x, y, value_type(0)); +} + +/** Set the translation of a 3D affine transform from a 3D or 2D vector */ +template < typename E, class A, class B, class L, class VecT > void +matrix_set_translation(matrix& m, const VecT& translation) +{ + /* Checking */ + detail::CheckVec2Or3(translation); + + if (translation.size() == 3) { + matrix_set_translation( + m,translation[0], translation[1], translation[2]); + } else { // translation.size() == 2 + matrix_set_translation(m, translation[0], translation[1]); + } +} + +/** Set the translation of a 2D affine transform */ +template < typename E, class A, class B, class L > void +matrix_set_translation_2D(matrix& m, E x, E y) +{ + /* Checking */ + detail::CheckMatAffine2D(m); + + m.set_basis_element(2,0,x); + m.set_basis_element(2,1,y); +} + +/** Set the translation of a 2D affine transform from a 2D vector */ +template < typename E, class A, class B, class L, class VecT > void +matrix_set_translation_2D(matrix& m, const VecT& translation) +{ + /* Checking */ + detail::CheckVec2(translation); + + matrix_set_translation_2D(m, translation[0], translation[1]); +} + +////////////////////////////////////////////////////////////////////////////// +// Functions for getting the translation of a 3D or 2D affine transform matrix +////////////////////////////////////////////////////////////////////////////// + +/** Get the translation of a 3D affine transform */ +template < class MatT > vector< typename MatT::value_type, fixed<3> > +matrix_get_translation(const MatT& m) +{ + typedef typename MatT::value_type value_type; + typedef vector< value_type, fixed<3> > vector_type; + + /* Checking */ + detail::CheckMatAffine3D(m); + + return vector_type( + m.basis_element(3,0), + m.basis_element(3,1), + m.basis_element(3,2) + ); +} + +/** Get the translation of a 3D affine transform */ +template < class MatT > void +matrix_get_translation( + const MatT& m, + typename MatT::value_type& t1, + typename MatT::value_type& t2, + typename MatT::value_type& t3 + ) +{ + typedef typename MatT::value_type value_type; + typedef vector< value_type, fixed<3> > vector_type; + + /* Checking */ + detail::CheckMatAffine3D(m); + + t1 = m.basis_element(3,0); + t2 = m.basis_element(3,1); + t3 = m.basis_element(3,2); +} + +/** Get the translation of a 2D affine transform */ +template < class MatT > vector< typename MatT::value_type, fixed<2> > +matrix_get_translation_2D(const MatT& m) +{ + typedef typename MatT::value_type value_type; + typedef vector< value_type, fixed<2> > vector_type; + + /* Checking */ + detail::CheckMatAffine2D(m); + + return vector_type(m.basis_element(2,0), m.basis_element(2,1)); +} + +/** Get the translation of a 2D affine transform */ +template < class MatT > void +matrix_get_translation_2D( + const MatT& m, + typename MatT::value_type& t1, + typename MatT::value_type& t2 + ) +{ + typedef typename MatT::value_type value_type; + typedef vector< value_type, fixed<2> > vector_type; + + /* Checking */ + detail::CheckMatAffine2D(m); + + t1 = m.basis_element(2,0); + t2 = m.basis_element(2,1); +} + +////////////////////////////////////////////////////////////////////////////// +// Function for getting the translation of a 3D view matrix +////////////////////////////////////////////////////////////////////////////// + +/** Get the translation of a 3D affine transform */ +template < class MatT > vector< typename MatT::value_type, fixed<3> > +matrix_get_view_translation(const MatT& m) +{ + typedef typename MatT::value_type value_type; + typedef vector< value_type, fixed<3> > vector_type; + + vector_type x, y, z; + matrix_get_basis_vectors(m,x,y,z); + vector_type p = matrix_get_translation(m); + return vector_type(-dot(p,x),-dot(p,y),-dot(p,z)); +} + +} // namespace cml + +#endif diff --git a/Lib/Include/CML/mathlib/misc.h b/Lib/Include/CML/mathlib/misc.h new file mode 100644 index 0000000..1017690 --- /dev/null +++ b/Lib/Include/CML/mathlib/misc.h @@ -0,0 +1,210 @@ +/* -*- C++ -*- ------------------------------------------------------------ + +Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/ + +The Configurable Math Library (CML) is distributed under the terms of the +Boost Software License, v1.0 (see cml/LICENSE for details). + + *-----------------------------------------------------------------------*/ +/** @file + * @brief + */ + +#ifndef misc_h +#define misc_h + +#include + +/* A few miscellaneous functions and helper classes. + * + * @note: This is somewhat ad-hoc and will probably all be replaced in a future + * version of the CML (I don't think I even bothered to document these functions + * on the website). + */ + +namespace cml { + +////////////////////////////////////////////////////////////////////////////// +// N-d functions +////////////////////////////////////////////////////////////////////////////// + +/** Return an N-d zero vector */ +template < size_t N > +vector< double, fixed > zero() +{ + typedef vector< double, fixed > vector_type; + + vector_type result; + result.zero(); + return result; +} + +/** Return an N-d cardinal axis by index */ +template < size_t N > +vector< double, fixed > axis(size_t i) +{ + /* Checking */ + detail::CheckValidArg(i < N); + + typedef vector< double, fixed > vector_type; + vector_type result; + result.cardinal(i); + return result; +} + +/** Return an NxM zero matrix */ +template < size_t N, size_t M > +matrix< double, fixed, row_basis, row_major > zero() +{ + typedef matrix< double, fixed, row_basis, row_major > matrix_type; + + matrix_type result; + result.zero(); + return result; +} + +/** Return an NxN identity matrix */ +template < size_t N > +matrix< double, fixed, row_basis, row_major > identity() +{ + typedef matrix< double, fixed, row_basis, row_major > matrix_type; + + matrix_type result; + result.identity(); + return result; +} + +/** Return an NxM identity transform */ +template < size_t N, size_t M > +matrix< double, fixed, row_basis, row_major > identity_transform() +{ + typedef matrix< double, fixed, row_basis, row_major > matrix_type; + + matrix_type result; + identity_transform(result); + return result; +} + +////////////////////////////////////////////////////////////////////////////// +// Zero vector +////////////////////////////////////////////////////////////////////////////// + +/** Return the 2D zero vector */ +inline vector< double, fixed<2> > zero_2D() { + return zero<2>(); +} + +/** Return the 3D zero vector */ +inline vector< double, fixed<3> > zero_3D() { + return zero<3>(); +} + +/** Return the 4D zero vector */ +inline vector< double, fixed<4> > zero_4D() { + return zero<4>(); +} + +////////////////////////////////////////////////////////////////////////////// +// Cardinal axis +////////////////////////////////////////////////////////////////////////////// + +/** Return a 2D cardinal axis by index */ +inline vector< double, fixed<2> > axis_2D(size_t i) { + return axis<2>(i); +} + +/** Return a 3D cardinal axis by index */ +inline vector< double, fixed<3> > axis_3D(size_t i) { + return axis<3>(i); +} + +/** Return a the 2D x cardinal axis */ +inline vector< double, fixed<2> > x_axis_2D() { + return axis_2D(0); +} + +/** Return a the 2D y cardinal axis */ +inline vector< double, fixed<2> > y_axis_2D() { + return axis_2D(1); +} + +/** Return a the 3D x cardinal axis */ +inline vector< double, fixed<3> > x_axis_3D() { + return axis_3D(0); +} + +/** Return a the 3D y cardinal axis */ +inline vector< double, fixed<3> > y_axis_3D() { + return axis_3D(1); +} + +/** Return a the 3D z cardinal axis */ +inline vector< double, fixed<3> > z_axis_3D() { + return axis_3D(2); +} + +////////////////////////////////////////////////////////////////////////////// +// Zero matrix +////////////////////////////////////////////////////////////////////////////// + +/** Return the 2x2 zero matrix */ +inline matrix< double, fixed<2,2>, row_basis, row_major > zero_2x2() { + return zero<2,2>(); +} + +/** Return the 3x3 zero matrix */ +inline matrix< double, fixed<3,3>, row_basis, row_major > zero_3x3() { + return zero<3,3>(); +} + +/** Return the 4x4 zero matrix */ +inline matrix< double, fixed<4,4>, row_basis, row_major > zero_4x4() { + return zero<4,4>(); +} + +////////////////////////////////////////////////////////////////////////////// +// Identity matrix +////////////////////////////////////////////////////////////////////////////// + +/** Return the 2x2 identity matrix */ +inline matrix< double, fixed<2,2>, row_basis, row_major > identity_2x2() { + return identity<2>(); +} + +/** Return the 3x3 identity matrix */ +inline matrix< double, fixed<3,3>, row_basis, row_major > identity_3x3() { + return identity<3>(); +} + +/** Return the 4x4 identity matrix */ +inline matrix< double, fixed<4,4>, row_basis, row_major > identity_4x4() { + return identity<4>(); +} + +////////////////////////////////////////////////////////////////////////////// +// Identity transform matrix +////////////////////////////////////////////////////////////////////////////// + +/** Return a 3x2 identity transform */ +inline matrix< double,fixed<3,2>,row_basis,row_major > identity_transform_3x2() { + return identity_transform<3,2>(); +} + +/** Return a 2x3 identity transform */ +inline matrix< double,fixed<2,3>,col_basis,col_major > identity_transform_2x3() { + return identity_transform<2,3>(); +} + +/** Return a 4x3 identity transform */ +inline matrix< double,fixed<4,3>,row_basis,row_major > identity_transform_4x3() { + return identity_transform<4,3>(); +} + +/** Return a 3x4 identity transform */ +inline matrix< double,fixed<3,4>,col_basis,col_major > identity_transform_3x4() { + return identity_transform<3,4>(); +} + +} // namespace cml + +#endif diff --git a/Lib/Include/CML/mathlib/picking.h b/Lib/Include/CML/mathlib/picking.h new file mode 100644 index 0000000..75d1697 --- /dev/null +++ b/Lib/Include/CML/mathlib/picking.h @@ -0,0 +1,195 @@ +/* -*- C++ -*- ------------------------------------------------------------ + +Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/ + +The Configurable Math Library (CML) is distributed under the terms of the +Boost Software License, v1.0 (see cml/LICENSE for details). + + *-----------------------------------------------------------------------*/ +/** @file + * @brief + */ + +#ifndef picking_h +#define picking_h + +#include + +/* Functions for picking with rays, volumes, and drag-enclosed volumes. */ + +namespace cml { + +/* Support function for extracting the near and far depth range values from + * a viewport matrix. + */ + +namespace detail { + +// NOTE: Changed 'near' and 'far' to 'n' and 'f' to work around windows.h +// 'near' and 'far' macros. + +template < class MatT, typename Real > void +depth_range_from_viewport_matrix(const MatT& viewport, Real& n, Real& f) +{ + detail::CheckMatHomogeneous3D(viewport); + + n = viewport.basis_element(3,2); + f = viewport.basis_element(2,2) + n; +} + +} // namespace detail + +/* Make a pick ray given screen coordinates and view, projection, and viewport + * matrices. The origin of the ray lies in the near plane of the frustum; the + * direction vector extends to the far plane if 'normalize' is false, and is + * made unit-length if 'normalize' is true (its default value). + * + * Note that the origin of the ray lies in the near plane rather than + * coinciding with the position of the virtual camera, as the latter gives + * incorrect results when the projection is orthographic. + * + * Note also that the screen y coordinate increases from bottom to top rather + * than top to bottom. If mouse coordinates are returned in window space where + * the y coordinate increases from top to bottom (as is often the case), the + * y value should be recomputed as 'y = - y' before being + * submitted to this function. + */ + +template < class MatT_1, class MatT_2, class MatT_3, typename E, class A > +void make_pick_ray( + E pick_x, + E pick_y, + const MatT_1& view, + const MatT_2& projection, + const MatT_3& viewport, + vector& origin, + vector& direction, + bool normalize = true) +{ + typedef vector vector_type; + typedef typename vector_type::value_type value_type; + + // NOTE: Changed 'near' and 'far' to 'n' and 'f' to work around + // windows.h 'near' and 'far' macros. + value_type n, f; + detail::depth_range_from_viewport_matrix(viewport, n, f); + + origin = + unproject_point( + view,projection,viewport,vector_type(pick_x,pick_y,n) + ); + direction = + unproject_point( + view,projection,viewport,vector_type(pick_x,pick_y,f) + ) - origin; + if (normalize) { + direction.normalize(); + } +} + +/* Make a pick volume given the screen coordinates of the center of the + * picking rect, the width and height of the picking rect, and view and + * projection matrices. + * + * The volume is loaded into the 'planes' array. The planes are of the form + * ax+by+cz+d = 0, and are in the order left, right, bottom, top, near, far. + * + * The z_clip argument should be either z_clip_neg_one or z_clip_zero, and + * should correspond to the near z-clipping range of the projection matrix + * argument. + * + * The 'normalize' argument indicates whether the output planes should be + * normalized; its default value is 'true'. + * + * Note that the screen y coordinate increases from bottom to top rather + * than top to bottom. If mouse coordinates are returned in window space where + * the y coordinate increases from top to bottom (as is often the case), the + * y value should be recomputed as 'y = - y' before being + * submitted to this function. + */ + +template < class MatT_1, class MatT_2, typename Real > +void make_pick_volume( + Real pick_x, + Real pick_y, + Real pick_width, + Real pick_height, + Real viewport_x, + Real viewport_y, + Real viewport_width, + Real viewport_height, + const MatT_1& view, + const MatT_2& projection, + Real planes[6][4], + ZClip z_clip, + bool normalize = true) +{ + // FIXME: Should be promoted type... + typedef matrix< + Real, fixed<4,4>, + typename MatT_1::basis_orient, typename MatT_1::layout > + matrix_type; + + matrix_type pick; + matrix_pick( + pick, pick_x, pick_y, pick_width, pick_height, + viewport_x, viewport_y, viewport_width, viewport_height + ); + cml::extract_frustum_planes( + view,detail::matrix_concat_transforms_4x4(projection,pick), + planes,z_clip,normalize); +} + +/* Make a pick volume given two opposite corners of a rectangle in screen + * space, and view and projection matrices. The corners of the screen rect + * need not be in any particular 'order' with regard to the values of the + * coordinates. + * + * The volume is loaded into the 'planes' array. The planes are of the form + * ax+by+cz+d = 0, and are in the order left, right, bottom, top, near, far. + * + * The z_clip argument should be either z_clip_neg_one or z_clip_zero, and + * should correspond to the near z-clipping range of the projection matrix + * argument. + * + * The 'normalize' argument indicates whether the output planes should be + * normalized; its default value is 'true'. + * + * Note that the screen y coordinate increases from bottom to top rather + * than top to bottom. If mouse coordinates are returned in window space where + * the y coordinate increases from top to bottom (as is often the case), the + * y value should be recomputed as 'y = - y' before being + * submitted to this function. + */ + +template < class MatT_1, class MatT_2, typename Real > +void make_pick_drag_volume( + Real pick_x1, + Real pick_y1, + Real pick_x2, + Real pick_y2, + Real viewport_x, + Real viewport_y, + Real viewport_width, + Real viewport_height, + const MatT_1& view, + const MatT_2& projection, + Real planes[6][4], + ZClip z_clip, + bool normalize = true) +{ + typedef Real value_type; + + make_pick_volume( + (pick_x1+pick_x2)*value_type(.5), + (pick_y1+pick_y2)*value_type(.5), + std::fabs(pick_x2-pick_x1), + std::fabs(pick_y2-pick_y1), + viewport_x, viewport_y, viewport_width, viewport_height, + view, projection, planes, z_clip, normalize + ); +} + +} // namespace cml + +#endif diff --git a/Lib/Include/CML/mathlib/projection.h b/Lib/Include/CML/mathlib/projection.h new file mode 100644 index 0000000..7996851 --- /dev/null +++ b/Lib/Include/CML/mathlib/projection.h @@ -0,0 +1,142 @@ +/* -*- C++ -*- ------------------------------------------------------------ + +Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/ + +The Configurable Math Library (CML) is distributed under the terms of the +Boost Software License, v1.0 (see cml/LICENSE for details). + + *-----------------------------------------------------------------------*/ +/** @file + * @brief + */ + +#ifndef projection_h +#define projection_h + +#include +#include + +/* Functions for projection and 'unprojection' of points in 3D. */ + +namespace cml { + +namespace detail { + +template < typename E > void +divide_by_w(vector< E,fixed<4> >& v) { + v *= E(1) / v[3]; +} + +} // namespace detail + +/* Project a point to screen space using the given model, view, projection, + * and viewport matrices. The z value of the returned point is a depth value + * in the range specified by the viewport matrix. + */ + +template +vector< typename VecT::value_type, fixed<3> > project_point( + const MatT_1& model, + const MatT_2& view, + const MatT_3& projection, + const MatT_4& viewport, + const VecT& p) +{ + return project_point( + detail::matrix_concat_transforms_4x4(model,view), + projection, + viewport, + p + ); +} + +/* Project a point to screen space using the given modelview, projection, and + * viewport matrices. The z value of the returned point is a depth value in + * the range specified by the viewport matrix. + */ + +template < class MatT_1, class MatT_2, class MatT_3, class VecT > +vector< typename VecT::value_type, fixed<3> > project_point( + const MatT_1& modelview, + const MatT_2& projection, + const MatT_3& viewport, + const VecT& p) +{ + typedef vector< typename VecT::value_type, fixed<3> > vector3_type; + typedef vector< typename VecT::value_type, fixed<4> > vector4_type; + typedef typename vector3_type::value_type value_type; + + detail::CheckVec3(p); + + vector4_type result = transform_vector_4D( + detail::matrix_concat_transforms_4x4( + modelview, + detail::matrix_concat_transforms_4x4( + projection, + viewport + ) + ), + vector4_type(p[0],p[1],p[2],value_type(1)) + ); + detail::divide_by_w(result); + return vector3_type(result[0],result[1],result[2]); +} + +/* 'Unproject' a point from screen space using the given model, view, + * projection, and viewport matrices. The z value of the input point is a + * depth value in the range specified by the viewport matrix. + */ + +template +vector< typename VecT::value_type, fixed<3> > unproject_point( + const MatT_1& model, + const MatT_2& view, + const MatT_3& projection, + const MatT_4& viewport, + const VecT& p) +{ + return unproject_point( + detail::matrix_concat_transforms_4x4(model,view), + projection, + viewport, + p + ); +} + +/* 'Unproject' a point from screen space using the given modelview, + * projection, and viewport matrices. The z value of the input point is a + * depth value in the range specified by the viewport matrix. + */ + +template < class MatT_1, class MatT_2, class MatT_3, class VecT > +vector< typename VecT::value_type, fixed<3> > unproject_point( + const MatT_1& modelview, + const MatT_2& projection, + const MatT_3& viewport, + const VecT& p) +{ + typedef vector< typename VecT::value_type, fixed<3> > vector3_type; + typedef vector< typename VecT::value_type, fixed<4> > vector4_type; + typedef typename vector3_type::value_type value_type; + + detail::CheckVec3(p); + + vector4_type result = transform_vector_4D( + inverse( + detail::matrix_concat_transforms_4x4( + modelview, + detail::matrix_concat_transforms_4x4( + projection, + viewport + ) + ) + ), + vector4_type(p[0],p[1],p[2],value_type(1)) + ); + detail::divide_by_w(result); + return vector3_type(result[0],result[1],result[2]); +} + +} // namespace cml + +#endif diff --git a/Lib/Include/CML/mathlib/quaternion_basis.h b/Lib/Include/CML/mathlib/quaternion_basis.h new file mode 100644 index 0000000..5c4633e --- /dev/null +++ b/Lib/Include/CML/mathlib/quaternion_basis.h @@ -0,0 +1,89 @@ +/* -*- C++ -*- ------------------------------------------------------------ + +Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/ + +The Configurable Math Library (CML) is distributed under the terms of the +Boost Software License, v1.0 (see cml/LICENSE for details). + + *-----------------------------------------------------------------------*/ +/** @file + * @brief + */ + +#ifndef quaternion_basis_h +#define quaternion_basis_h + +#include + +/* Functions for getting the basis vectors of a quaternion rotation. */ + +namespace cml { + +/** Get the i'th basis vector of a quaternion rotation */ +template < class QuatT > vector< typename QuatT::value_type, fixed<3> > +quaternion_get_basis_vector(const QuatT& q, size_t i) +{ + typedef QuatT quaternion_type; + typedef typename quaternion_type::value_type value_type; + typedef typename quaternion_type::order_type order_type; + typedef vector< value_type, fixed<3> > vector_type; + + /* Checking */ + detail::CheckQuat(q); + detail::CheckIndex3(i); + + size_t j, k; + cyclic_permutation(i, i, j, k); + + /* @todo: Clean this up. */ + const size_t W = order_type::W; + const size_t I = order_type::X + i; + const size_t J = order_type::X + j; + const size_t K = order_type::X + k; + + value_type j2 = q[J] + q[J]; + value_type k2 = q[K] + q[K]; + + /* @todo: use set_permuted() for the following when available. */ + + vector_type result; + result[i] = value_type(1) - q[J] * j2 - q[K] * k2; + result[j] = q[I] * j2 + q[W] * k2; + result[k] = q[I] * k2 - q[W] * j2; + return result; +} + +/** Get the x basis vector of a quaternion rotation */ +template < class QuatT > vector< typename QuatT::value_type, fixed<3> > +quaternion_get_x_basis_vector(const QuatT& q) { + return quaternion_get_basis_vector(q,0); +} + +/** Get the y basis vector of a quaternion rotation */ +template < class QuatT > vector< typename QuatT::value_type, fixed<3> > +quaternion_get_y_basis_vector(const QuatT& q) { + return quaternion_get_basis_vector(q,1); +} + +/** Get the z basis vector of a quaternion rotation */ +template < class QuatT > vector< typename QuatT::value_type, fixed<3> > +quaternion_get_z_basis_vector(const QuatT& q) { + return quaternion_get_basis_vector(q,2); +} + +/** Get the basis vectors of a quaternion rotation */ +template < class QuatT, typename E, class A > void +quaternion_get_basis_vectors( + const QuatT& q, + vector& x, + vector& y, + vector& z) +{ + x = quaternion_get_x_basis_vector(q); + y = quaternion_get_y_basis_vector(q); + z = quaternion_get_z_basis_vector(q); +} + +} // namespace cml + +#endif diff --git a/Lib/Include/CML/mathlib/quaternion_rotation.h b/Lib/Include/CML/mathlib/quaternion_rotation.h new file mode 100644 index 0000000..2e8c0e9 --- /dev/null +++ b/Lib/Include/CML/mathlib/quaternion_rotation.h @@ -0,0 +1,635 @@ +/* -*- C++ -*- ------------------------------------------------------------ + +Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/ + +The Configurable Math Library (CML) is distributed under the terms of the +Boost Software License, v1.0 (see cml/LICENSE for details). + + *-----------------------------------------------------------------------*/ +/** @file + * @brief + */ + +#ifndef quaternion_rotation_h +#define quaternion_rotation_h + +#include + +/* Functions related to quaternion rotations. + * + * Note: A number of these functions simply wrap calls to the corresponding + * matrix functions. Some of them (the 'aim-at' and 'align' functions in + * particular) might be considered a bit superfluous, since the resulting + * quaternion will most likely be converted to a matrix at some point anyway. + * However, they're included here for completeness, and for convenience in + * cases where a quaternion is being used as the primary rotation + * representation. +*/ + +namespace cml { + +////////////////////////////////////////////////////////////////////////////// +// Rotation about world axes +////////////////////////////////////////////////////////////////////////////// + +/** Build a quaternion representing a rotation about the given world axis */ +template < class E, class A, class O, class C > void +quaternion_rotation_world_axis(quaternion& q, size_t axis, E angle) +{ + typedef quaternion quaternion_type; + typedef typename quaternion_type::value_type value_type; + typedef typename quaternion_type::order_type order_type; + + /* Checking */ + detail::CheckIndex3(axis); + + q.identity(); + + const size_t W = order_type::W; + const size_t I = order_type::X + axis; + + angle *= value_type(.5); + q[I] = std::sin(angle); + q[W] = std::cos(angle); +} + +/** Build a quaternion representing a rotation about the world x axis */ +template < class E, class A, class O, class C > void +quaternion_rotation_world_x(quaternion& q, E angle) { + quaternion_rotation_world_axis(q,0,angle); +} + +/** Build a quaternion representing a rotation about the world y axis */ +template < class E, class A, class O, class C > void +quaternion_rotation_world_y(quaternion& q, E angle) { + quaternion_rotation_world_axis(q,1,angle); +} + +/** Build a quaternion representing a rotation about the world z axis */ +template < class E, class A, class O, class C > void +quaternion_rotation_world_z(quaternion& q, E angle) { + quaternion_rotation_world_axis(q,2,angle); +} + +////////////////////////////////////////////////////////////////////////////// +// Rotation from an axis-angle pair +////////////////////////////////////////////////////////////////////////////// + +/** Build a quaternion from an axis-angle pair */ +template < class E, class A, class O, class C, class VecT > void +quaternion_rotation_axis_angle( + quaternion& q, const VecT& axis, E angle) +{ + typedef quaternion quaternion_type; + typedef typename quaternion_type::value_type value_type; + typedef typename quaternion_type::order_type order_type; + + /* Checking */ + detail::CheckVec3(axis); + + enum { + W = order_type::W, + X = order_type::X, + Y = order_type::Y, + Z = order_type::Z + }; + + angle *= value_type(.5); + + /* @todo: If and when we have a set() function that takes a vector and a + * scalar, this can be written as: + * + * q.set(std::cos(angle), axis * std::sin(angle)); + * + * In which case the enum will also not be necessary. + */ + + q[W] = std::cos(angle); + value_type s = std::sin(angle); + q[X] = axis[0] * s; + q[Y] = axis[1] * s; + q[Z] = axis[2] * s; +} + +////////////////////////////////////////////////////////////////////////////// +// Rotation from a matrix +////////////////////////////////////////////////////////////////////////////// + +/** Build a quaternion from a rotation matrix */ +template < class E, class A, class O, class C, class MatT > void +quaternion_rotation_matrix(quaternion& q, const MatT& m) +{ + typedef quaternion quaternion_type; + typedef typename quaternion_type::value_type value_type; + typedef typename quaternion_type::order_type order_type; + + /* Checking */ + detail::CheckMatLinear3D(m); + + enum { + W = order_type::W, + X = order_type::X, + Y = order_type::Y, + Z = order_type::Z + }; + + value_type tr = trace_3x3(m); + if (tr >= value_type(0)) { + q[W] = std::sqrt(tr + value_type(1)) * value_type(.5); + value_type s = value_type(.25) / q[W]; + q[X] = (m.basis_element(1,2) - m.basis_element(2,1)) * s; + q[Y] = (m.basis_element(2,0) - m.basis_element(0,2)) * s; + q[Z] = (m.basis_element(0,1) - m.basis_element(1,0)) * s; + } else { + size_t largest_diagonal_element = + index_of_max( + m.basis_element(0,0), + m.basis_element(1,1), + m.basis_element(2,2) + ); + size_t i, j, k; + cyclic_permutation(largest_diagonal_element, i, j, k); + const size_t I = X + i; + const size_t J = X + j; + const size_t K = X + k; + q[I] = + std::sqrt( + m.basis_element(i,i) - + m.basis_element(j,j) - + m.basis_element(k,k) + + value_type(1) + ) * value_type(.5); + value_type s = value_type(.25) / q[I]; + q[J] = (m.basis_element(i,j) + m.basis_element(j,i)) * s; + q[K] = (m.basis_element(i,k) + m.basis_element(k,i)) * s; + q[W] = (m.basis_element(j,k) - m.basis_element(k,j)) * s; + } +} + +////////////////////////////////////////////////////////////////////////////// +// Rotation from Euler angles +////////////////////////////////////////////////////////////////////////////// + +/** Build a quaternion from an Euler-angle triple */ +template < class E, class A, class O, class C > void +quaternion_rotation_euler( + quaternion& q, E angle_0, E angle_1, E angle_2, + EulerOrder order) +{ + typedef quaternion quaternion_type; + typedef typename quaternion_type::value_type value_type; + typedef typename quaternion_type::order_type order_type; + + size_t i, j, k; + bool odd, repeat; + detail::unpack_euler_order(order, i, j, k, odd, repeat); + + const size_t W = order_type::W; + const size_t I = order_type::X + i; + const size_t J = order_type::X + j; + const size_t K = order_type::X + k; + + if (odd) { + angle_1 = -angle_1; + } + + angle_0 *= value_type(.5); + angle_1 *= value_type(.5); + angle_2 *= value_type(.5); + + value_type s0 = std::sin(angle_0); + value_type c0 = std::cos(angle_0); + value_type s1 = std::sin(angle_1); + value_type c1 = std::cos(angle_1); + value_type s2 = std::sin(angle_2); + value_type c2 = std::cos(angle_2); + + value_type s0s2 = s0 * s2; + value_type s0c2 = s0 * c2; + value_type c0s2 = c0 * s2; + value_type c0c2 = c0 * c2; + + if (repeat) { + q[I] = c1 * (c0s2 + s0c2); + q[J] = s1 * (c0c2 + s0s2); + q[K] = s1 * (c0s2 - s0c2); + q[W] = c1 * (c0c2 - s0s2); + } else { + q[I] = c1 * s0c2 - s1 * c0s2; + q[J] = c1 * s0s2 + s1 * c0c2; + q[K] = c1 * c0s2 - s1 * s0c2; + q[W] = c1 * c0c2 + s1 * s0s2; + } + if (odd) { + q[J] = -q[J]; + } +} + +////////////////////////////////////////////////////////////////////////////// +// Rotation to align with a vector, multiple vectors, or the view plane +////////////////////////////////////////////////////////////////////////////// + +/** See vector_ortho.h for details */ +template < typename E,class A,class O,class C,class VecT_1,class VecT_2 > void +quaternion_rotation_align( + quaternion& q, + const VecT_1& align, + const VecT_2& reference, + bool normalize = true, + AxisOrder order = axis_order_zyx) +{ + typedef matrix< E,fixed<3,3>,row_basis,row_major > matrix_type; + + matrix_type m; + matrix_rotation_align(m,align,reference,normalize,order); + quaternion_rotation_matrix(q,m); +} + +/** See vector_ortho.h for details */ +template < typename E, class A, class O, class C, class VecT > void +quaternion_rotation_align(quaternion& q, const VecT& align, + bool normalize = true, AxisOrder order = axis_order_zyx) +{ + typedef matrix< E,fixed<3,3>,row_basis,row_major > matrix_type; + + matrix_type m; + matrix_rotation_align(m,align,normalize,order); + quaternion_rotation_matrix(q,m); +} + +/** See vector_ortho.h for details */ +template < typename E,class A,class O,class C,class VecT_1,class VecT_2 > void +quaternion_rotation_align_axial(quaternion& q, const VecT_1& align, + const VecT_2& axis, bool normalize = true, + AxisOrder order = axis_order_zyx) +{ + typedef matrix< E,fixed<3,3>,row_basis,row_major > matrix_type; + + matrix_type m; + matrix_rotation_align_axial(m,align,axis,normalize,order); + quaternion_rotation_matrix(q,m); +} + +/** See vector_ortho.h for details */ +template < typename E, class A, class O, class C, class MatT > void +quaternion_rotation_align_viewplane( + quaternion& q, + const MatT& view_matrix, + Handedness handedness, + AxisOrder order = axis_order_zyx) +{ + typedef matrix< E,fixed<3,3>,row_basis,row_major > matrix_type; + + matrix_type m; + matrix_rotation_align_viewplane(m,view_matrix,handedness,order); + quaternion_rotation_matrix(q,m); +} + +/** See vector_ortho.h for details */ +template < typename E, class A, class O, class C, class MatT > void +quaternion_rotation_align_viewplane_LH( + quaternion& q, + const MatT& view_matrix, + AxisOrder order = axis_order_zyx) +{ + typedef matrix< E,fixed<3,3>,row_basis,row_major > matrix_type; + + matrix_type m; + matrix_rotation_align_viewplane_LH(m,view_matrix,order); + quaternion_rotation_matrix(q,m); +} + +/** See vector_ortho.h for details */ +template < typename E, class A, class O, class C, class MatT > void +quaternion_rotation_align_viewplane_RH( + quaternion& q, + const MatT& view_matrix, + AxisOrder order = axis_order_zyx) +{ + typedef matrix< E,fixed<3,3>,row_basis,row_major > matrix_type; + + matrix_type m; + matrix_rotation_align_viewplane_RH(m,view_matrix,order); + quaternion_rotation_matrix(q,m); +} + +////////////////////////////////////////////////////////////////////////////// +// Rotation to aim at a target +////////////////////////////////////////////////////////////////////////////// + +/** See vector_ortho.h for details */ +template < typename E, class A, class O, class C, + class VecT_1, class VecT_2, class VecT_3 > void +quaternion_rotation_aim_at( + quaternion& q, + const VecT_1& pos, + const VecT_2& target, + const VecT_3& reference, + AxisOrder order = axis_order_zyx) +{ + typedef matrix< E,fixed<3,3>,row_basis,row_major > matrix_type; + + matrix_type m; + matrix_rotation_aim_at(m,pos,target,reference,order); + quaternion_rotation_matrix(q,m); +} + +/** See vector_ortho.h for details */ +template < typename E, class A, class O, class C, + class VecT_1, class VecT_2 > void +quaternion_rotation_aim_at( + quaternion& q, + const VecT_1& pos, + const VecT_2& target, + AxisOrder order = axis_order_zyx) +{ + typedef matrix< E,fixed<3,3>,row_basis,row_major > matrix_type; + + matrix_type m; + matrix_rotation_aim_at(m,pos,target,order); + quaternion_rotation_matrix(q,m); +} + +/** See vector_ortho.h for details */ +template < typename E, class A, class O, class C, + class VecT_1, class VecT_2, class VecT_3 > void +quaternion_rotation_aim_at_axial( + quaternion& q, + const VecT_1& pos, + const VecT_2& target, + const VecT_3& axis, + AxisOrder order = axis_order_zyx) +{ + typedef matrix< E,fixed<3,3>,row_basis,row_major > matrix_type; + + matrix_type m; + matrix_rotation_aim_at_axial(m,pos,target,axis,order); + quaternion_rotation_matrix(q,m); +} + +////////////////////////////////////////////////////////////////////////////// +// Relative rotation about world axes +////////////////////////////////////////////////////////////////////////////// + +/* Rotate a quaternion about the given world axis */ +template < class E, class A, class O, class C > void +quaternion_rotate_about_world_axis(quaternion& q,size_t axis,E angle) +{ + typedef quaternion quaternion_type; + typedef typename quaternion_type::value_type value_type; + typedef typename quaternion_type::order_type order_type; + + /* Checking */ + detail::CheckIndex3(axis); + + size_t i, j, k; + cyclic_permutation(axis, i, j, k); + + const size_t W = order_type::W; + const size_t I = order_type::X + i; + const size_t J = order_type::X + j; + const size_t K = order_type::X + k; + + angle *= value_type(.5); + value_type s = value_type(std::sin(angle)); + value_type c = value_type(std::cos(angle)); + + quaternion_type result; + result[I] = c * q[I] + s * q[W]; + result[J] = c * q[J] - s * q[K]; + result[K] = c * q[K] + s * q[J]; + result[W] = c * q[W] - s * q[I]; + q = result; +} + +/* Rotate a quaternion about the world x axis */ +template < class E, class A, class O, class C > void +quaternion_rotate_about_world_x(quaternion& q, E angle) { + quaternion_rotate_about_world_axis(q,0,angle); +} + +/* Rotate a quaternion about the world y axis */ +template < class E, class A, class O, class C > void +quaternion_rotate_about_world_y(quaternion& q, E angle) { + quaternion_rotate_about_world_axis(q,1,angle); +} + +/* Rotate a quaternion about the world z axis */ +template < class E, class A, class O, class C > void +quaternion_rotate_about_world_z(quaternion& q, E angle) { + quaternion_rotate_about_world_axis(q,2,angle); +} + +////////////////////////////////////////////////////////////////////////////// +// Relative rotation about local axes +////////////////////////////////////////////////////////////////////////////// + +/* Rotate a quaternion about the given local axis */ +template < class E, class A, class O, class C > void +quaternion_rotate_about_local_axis(quaternion& q,size_t axis,E angle) +{ + typedef quaternion quaternion_type; + typedef typename quaternion_type::value_type value_type; + typedef typename quaternion_type::order_type order_type; + + /* Checking */ + detail::CheckIndex3(axis); + + size_t i, j, k; + cyclic_permutation(axis, i, j, k); + + const size_t W = order_type::W; + const size_t I = order_type::X + i; + const size_t J = order_type::X + j; + const size_t K = order_type::X + k; + + angle *= value_type(.5); + value_type s = value_type(std::sin(angle)); + value_type c = value_type(std::cos(angle)); + + quaternion_type result; + result[I] = c * q[I] + s * q[W]; + result[J] = c * q[J] + s * q[K]; + result[K] = c * q[K] - s * q[J]; + result[W] = c * q[W] - s * q[I]; + q = result; +} + +/* Rotate a quaternion about its local x axis */ +template < class E, class A, class O, class C > void +quaternion_rotate_about_local_x(quaternion& q, E angle) { + quaternion_rotate_about_local_axis(q,0,angle); +} + +/* Rotate a quaternion about its local y axis */ +template < class E, class A, class O, class C > void +quaternion_rotate_about_local_y(quaternion& q, E angle) { + quaternion_rotate_about_local_axis(q,1,angle); +} + +/* Rotate a quaternion about its local z axis */ +template < class E, class A, class O, class C > void +quaternion_rotate_about_local_z(quaternion& q, E angle) { + quaternion_rotate_about_local_axis(q,2,angle); +} + +////////////////////////////////////////////////////////////////////////////// +// Rotation from vector to vector +////////////////////////////////////////////////////////////////////////////// + +/* http://www.martinb.com/maths/algebra/vectors/angleBetween/index.htm. */ + +/** Build a quaternion to rotate from one vector to another */ +template < class E,class A,class O,class C,class VecT_1,class VecT_2 > void +quaternion_rotation_vec_to_vec( + quaternion& q, + const VecT_1& v1, + const VecT_2& v2, + bool unit_length_vectors = false) +{ + typedef quaternion quaternion_type; + typedef typename quaternion_type::value_type value_type; + typedef vector< value_type, fixed<3> > vector_type; + + /* Checking handled by cross() */ + + /* @todo: If at some point quaternion<> has a set() function that takes a + * vector and a scalar, this can then be written as: + * + * if (...) { + * q.set(value_type(1)+dot(v1,v2), cross(v1,v2)); + * } else { + * q.set(std::sqrt(...)+dot(v1,v2), cross(v1,v2)); + * } + */ + + vector_type c = cross(v1,v2); + if (unit_length_vectors) { + q = quaternion_type(value_type(1) + dot(v1,v2), c.data()); + } else { + q = quaternion_type( + std::sqrt(v1.length_squared() * v2.length_squared()) + dot(v1,v2), + c/*.data()*/ + ); + } + q.normalize(); +} + +////////////////////////////////////////////////////////////////////////////// +// Scale the angle of a rotation matrix +////////////////////////////////////////////////////////////////////////////// + +template < typename E, class A, class O, class C > void +quaternion_scale_angle(quaternion& q, E t, + E tolerance = epsilon::placeholder()) +{ + typedef vector< E,fixed<3> > vector_type; + typedef typename vector_type::value_type value_type; + + vector_type axis; + value_type angle; + quaternion_to_axis_angle(q, axis, angle, tolerance); + quaternion_rotation_axis_angle(q, axis, angle * t); +} + +////////////////////////////////////////////////////////////////////////////// +// Support functions for uniform handling of pos- and neg-cross quaternions +////////////////////////////////////////////////////////////////////////////// + +namespace detail { + +/** Concatenate two quaternions in the order q1->q2 */ +template < class QuatT_1, class QuatT_2 > +typename et::QuaternionPromote2::temporary_type +quaternion_rotation_difference( + const QuatT_1& q1, const QuatT_2& q2, positive_cross) +{ + return q2 * conjugate(q1); +} + +/** Concatenate two quaternions in the order q1->q2 */ +template < class QuatT_1, class QuatT_2 > +typename et::QuaternionPromote2::temporary_type +quaternion_rotation_difference( + const QuatT_1& q1, const QuatT_2& q2, negative_cross) +{ + return conjugate(q1) * q2; +} + +} // namespace detail + +////////////////////////////////////////////////////////////////////////////// +// Quaternions rotation difference +////////////////////////////////////////////////////////////////////////////// + +/** Return the rotational 'difference' between two quaternions */ +template < class QuatT_1, class QuatT_2 > +typename et::QuaternionPromote2::temporary_type +quaternion_rotation_difference(const QuatT_1& q1, const QuatT_2& q2) { + return detail::quaternion_rotation_difference( + q1, q2, typename QuatT_1::cross_type()); +} + +////////////////////////////////////////////////////////////////////////////// +// Conversions +////////////////////////////////////////////////////////////////////////////// + +/** Convert a quaternion to an axis-angle pair */ +template < class QuatT, typename E, class A > void +quaternion_to_axis_angle( + const QuatT& q, + vector& axis, + E& angle, + E tolerance = epsilon::placeholder()) +{ + typedef QuatT quaternion_type; + typedef typename quaternion_type::value_type value_type; + typedef typename quaternion_type::order_type order_type; + + /* Checking */ + detail::CheckQuat(q); + + axis = q.imaginary(); + value_type l = length(axis); + if (l > tolerance) { + axis /= l; + angle = value_type(2) * std::atan2(l,q.real()); + } else { + axis.zero(); + angle = value_type(0); + } +} + +/** Convert a quaternion to an Euler-angle triple + * + * Note: I've implemented direct quaternion-to-Euler conversion, but as far as + * I can tell it more or less reduces to converting the quaternion to a matrix + * as you go. The direct method is a little more efficient in that it doesn't + * require a temporary and only the necessary matrix elements need be + * computed. However, the implementation is complex and there's considerable + * opportunity for error, so from a development and debugging standpoint I + * think it's better to just perform the conversion via matrix_to_euler(), + * which is already known to be correct. +*/ + +template < class QuatT, typename Real > void +quaternion_to_euler( + const QuatT& q, + Real& angle_0, + Real& angle_1, + Real& angle_2, + EulerOrder order, + Real tolerance = epsilon::placeholder()) +{ + typedef QuatT quaternion_type; + typedef typename quaternion_type::value_type value_type; + typedef matrix< value_type,fixed<3,3>,row_basis,row_major > matrix_type; + + matrix_type m; + matrix_rotation_quaternion(m, q); + matrix_to_euler(m, angle_0, angle_1, angle_2, order, tolerance); +} + +} // namespace cml + +#endif diff --git a/Lib/Include/CML/mathlib/typedef.h b/Lib/Include/CML/mathlib/typedef.h new file mode 100644 index 0000000..902a331 --- /dev/null +++ b/Lib/Include/CML/mathlib/typedef.h @@ -0,0 +1,134 @@ +/* -*- C++ -*- ------------------------------------------------------------ + +Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/ + +The Configurable Math Library (CML) is distributed under the terms of the +Boost Software License, v1.0 (see cml/LICENSE for details). + + *-----------------------------------------------------------------------*/ +/** @file + * @brief + */ + +#ifndef typedef_h +#define typedef_h + +#include +#include +#include +#include +#include + +namespace cml { + +/* fixed-size vectors */ +typedef vector< int, fixed<2> > vector2i; +typedef vector< float, fixed<2> > vector2f; +typedef vector< double, fixed<2> > vector2d; + +typedef vector< int, fixed<3> > vector3i; +typedef vector< float, fixed<3> > vector3f; +typedef vector< double, fixed<3> > vector3d; + +typedef vector< int, fixed<4> > vector4i; +typedef vector< float, fixed<4> > vector4f; +typedef vector< double, fixed<4> > vector4d; + +/* fixed-size matrices */ + +typedef matrix< int, fixed<2,2> > matrix22i; +typedef matrix< float, fixed<2,2> > matrix22f; +typedef matrix< double, fixed<2,2> > matrix22d; + +typedef matrix< int, fixed<2,2>, row_basis, row_major > matrix22i_r; +typedef matrix< int, fixed<2,2>, col_basis, col_major > matrix22i_c; +typedef matrix< float, fixed<2,2>, row_basis, row_major > matrix22f_r; +typedef matrix< float, fixed<2,2>, col_basis, col_major > matrix22f_c; +typedef matrix< double, fixed<2,2>, row_basis, row_major > matrix22d_r; +typedef matrix< double, fixed<2,2>, col_basis, col_major > matrix22d_c; + + +typedef matrix< int, fixed<3,3> > matrix33i; +typedef matrix< float, fixed<3,3> > matrix33f; +typedef matrix< double, fixed<3,3> > matrix33d; + +typedef matrix< int, fixed<3,3>, row_basis, row_major > matrix33i_r; +typedef matrix< int, fixed<3,3>, col_basis, col_major > matrix33i_c; +typedef matrix< float, fixed<3,3>, row_basis, row_major > matrix33f_r; +typedef matrix< float, fixed<3,3>, col_basis, col_major > matrix33f_c; +typedef matrix< double, fixed<3,3>, row_basis, row_major > matrix33d_r; +typedef matrix< double, fixed<3,3>, col_basis, col_major > matrix33d_c; + + +typedef matrix< int, fixed<4,4> > matrix44i; +typedef matrix< float, fixed<4,4> > matrix44f; +typedef matrix< double, fixed<4,4> > matrix44d; + +typedef matrix< int, fixed<4,4>, row_basis, row_major > matrix44i_r; +typedef matrix< int, fixed<4,4>, col_basis, col_major > matrix44i_c; +typedef matrix< float, fixed<4,4>, row_basis, row_major > matrix44f_r; +typedef matrix< float, fixed<4,4>, col_basis, col_major > matrix44f_c; +typedef matrix< double, fixed<4,4>, row_basis, row_major > matrix44d_r; +typedef matrix< double, fixed<4,4>, col_basis, col_major > matrix44d_c; + + +typedef matrix< int, fixed<3,2>, row_basis, row_major > matrix32i_r; +typedef matrix< float, fixed<3,2>, row_basis, row_major > matrix32f_r; +typedef matrix< double, fixed<3,2>, row_basis, row_major > matrix32d_r; + +typedef matrix< int, fixed<2,3>, col_basis, col_major > matrix23i_c; +typedef matrix< float, fixed<2,3>, col_basis, col_major > matrix23f_c; +typedef matrix< double, fixed<2,3>, col_basis, col_major > matrix23d_c; + +typedef matrix< int, fixed<4,3>, row_basis, row_major > matrix43i_r; +typedef matrix< float, fixed<4,3>, row_basis, row_major > matrix43f_r; +typedef matrix< double, fixed<4,3>, row_basis, row_major > matrix43d_r; + +typedef matrix< int, fixed<3,4>, col_basis, col_major > matrix34i_c; +typedef matrix< float, fixed<3,4>, col_basis, col_major > matrix34f_c; +typedef matrix< double, fixed<3,4>, col_basis, col_major > matrix34d_c; + + +/* quaternions */ +typedef quaternion,vector_first,negative_cross> + quaternionf_n; +typedef quaternion,vector_first,positive_cross> + quaternionf_p; +typedef quaternion,vector_first,negative_cross> + quaterniond_n; +typedef quaternion,vector_first,positive_cross> + quaterniond_p; +typedef quaternion quaternionf; +typedef quaternion quaterniond; + + +/* dynamically resizable vectors */ +typedef vector< int, dynamic<> > vectori; +typedef vector< float, dynamic<> > vectorf; +typedef vector< double, dynamic<> > vectord; + + +/* dynamically resizable matrices */ +typedef matrix< int, dynamic<> > matrixi; +typedef matrix< float, dynamic<> > matrixf; +typedef matrix< double, dynamic<> > matrixd; + +typedef matrix< int, dynamic<>, row_basis, row_major > matrixi_r; +typedef matrix< int, dynamic<>, col_basis, col_major > matrixi_c; +typedef matrix< float, dynamic<>, row_basis, row_major > matrixf_r; +typedef matrix< float, dynamic<>, col_basis, col_major > matrixf_c; +typedef matrix< double, dynamic<>, row_basis, row_major > matrixd_r; +typedef matrix< double, dynamic<>, col_basis, col_major > matrixd_c; + + +/* constants */ +typedef constants constantsf; +typedef constants constantsd; + +/* epsilon/tolerance values (placeholder) */ +typedef epsilon epsilonf; +typedef epsilon epsilond; + +} // namespace cml + +#endif diff --git a/Lib/Include/CML/mathlib/vector_angle.h b/Lib/Include/CML/mathlib/vector_angle.h new file mode 100644 index 0000000..910817b --- /dev/null +++ b/Lib/Include/CML/mathlib/vector_angle.h @@ -0,0 +1,69 @@ +/* -*- C++ -*- ------------------------------------------------------------ + +Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/ + +The Configurable Math Library (CML) is distributed under the terms of the +Boost Software License, v1.0 (see cml/LICENSE for details). + + *-----------------------------------------------------------------------*/ +/** @file + * @brief + */ + +#ifndef vector_angle_h +#define vector_angle_h + +#include + +/* Functions for finding the signed and unsigned angles between vectors in + * 3D and 2D. + * + * Note that the input vectors for these functions are not required to be + * unit length. + * + * @todo: Clean up promotions, conversions, and return types. + */ + +namespace cml { + +/** Signed angle between two 3D vectors. */ +template< class VecT_1, class VecT_2, class VecT_3 > +typename detail::DotPromote< + typename detail::CrossPromote::promoted_vector, VecT_3 +>::promoted_scalar +signed_angle(const VecT_1& v1, const VecT_2& v2, const VecT_3& reference) +{ + typedef typename detail::CrossPromote::promoted_vector + vector_type; + typedef typename detail::DotPromote::promoted_scalar + value_type; + + vector_type c = cross(v1,v2); + value_type angle = std::atan2(double(length(c)),double(dot(v1,v2))); + return dot(c,reference) < value_type(0) ? -angle : angle; +} + +/** Unsigned angle between two 3D vectors. */ +template< class VecT_1, class VecT_2 > +typename detail::DotPromote< VecT_1, VecT_2 >::promoted_scalar +unsigned_angle(const VecT_1& v1, const VecT_2& v2) { + return std::atan2(double(length(cross(v1,v2))),double(dot(v1,v2))); +} + +/** Signed angle between two 2D vectors. */ +template< class VecT_1, class VecT_2 > +typename detail::DotPromote< VecT_1, VecT_2 >::promoted_scalar +signed_angle_2D(const VecT_1& v1, const VecT_2& v2) { + return std::atan2(double(perp_dot(v1,v2)),double(dot(v1,v2))); +} + +/** Unsigned angle between two 2D vectors. */ +template< class VecT_1, class VecT_2 > +typename detail::DotPromote< VecT_1, VecT_2 >::promoted_scalar +unsigned_angle_2D(const VecT_1& v1, const VecT_2& v2) { + return std::fabs(signed_angle_2D(v1,v2)); +} + +} // namespace cml + +#endif diff --git a/Lib/Include/CML/mathlib/vector_misc.h b/Lib/Include/CML/mathlib/vector_misc.h new file mode 100644 index 0000000..6553342 --- /dev/null +++ b/Lib/Include/CML/mathlib/vector_misc.h @@ -0,0 +1,304 @@ +/* -*- C++ -*- ------------------------------------------------------------ + +Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/ + +The Configurable Math Library (CML) is distributed under the terms of the +Boost Software License, v1.0 (see cml/LICENSE for details). + + *-----------------------------------------------------------------------*/ +/** @file + * @brief + */ + +#ifndef vector_misc_h +#define vector_misc_h + +#include + +/* Miscellaneous vector functions. */ + +namespace cml { + +/* Function to project a vector v onto a hyperplane specified by a unit-length + * normal n. + * + * @todo: Clean up promotion code. + */ + +template < class VecT_1, class VecT_2 > +typename detail::CrossPromote::promoted_vector +project_to_hplane(const VecT_1& v, const VecT_2& n) +{ + typedef typename detail::CrossPromote::promoted_vector + result_type; + + result_type result; + et::detail::Resize(result, v.size()); + + result = v - dot(v,n) * n; + return result; +} + +/* Return a vector perpendicular (CCW) to a 2D vector. */ +template < class VecT > vector< typename VecT::value_type, fixed<2> > +perp(const VecT& v) +{ + typedef vector< typename VecT::value_type, fixed<2> > temporary_type; + + /* Checking */ + detail::CheckVec2(v); + + return temporary_type(-v[1],v[0]); +} + +/* @todo: unit_cross() and cross_cardinal() should probably go in + * vector_products.h, but I'm trying to avoid modifying the existing codebase + * for now. + */ + +/** Return normalized cross product of two vectors */ +template< class LeftT, class RightT > +typename detail::CrossPromote::promoted_vector +unit_cross(const LeftT& left, const RightT& right) { + /* @todo: This will probably break with dynamic<> vectors */ + return normalize(cross(left,right)); +} + +/** Return the cross product of v and the i'th cardinal basis vector */ +template < class VecT > vector< typename VecT::value_type, fixed<3> > +cross_cardinal(const VecT& v, size_t i) +{ + typedef vector< typename VecT::value_type, fixed<3> > vector_type; + typedef typename vector_type::value_type value_type; + + /* Checking */ + detail::CheckVec3(v); + detail::CheckIndex3(i); + + size_t j, k; + cyclic_permutation(i, i, j, k); + vector_type result; + result[i] = value_type(0); + result[j] = v[k]; + result[k] = -v[j]; + return result; +} + +/** Return the cross product of the i'th cardinal basis vector and v */ +template < class VecT > vector< typename VecT::value_type, fixed<3> > +cross_cardinal(size_t i, const VecT& v) +{ + typedef vector< typename VecT::value_type, fixed<3> > vector_type; + typedef typename vector_type::value_type value_type; + + /* Checking */ + detail::CheckVec3(v); + detail::CheckIndex3(i); + + size_t j, k; + cyclic_permutation(i, i, j, k); + vector_type result; + result[i] = value_type(0); + result[j] = -v[k]; + result[k] = v[j]; + return result; +} + +/** Rotate a 3D vector v about a unit-length vector n. */ +template< class VecT_1, class VecT_2, typename Real > +vector< + typename et::ScalarPromote< + typename VecT_1::value_type, + typename VecT_2::value_type + >::type, + fixed<3> +> +rotate_vector(const VecT_1& v, const VecT_2& n, Real angle) +{ + typedef vector< + typename et::ScalarPromote< + typename VecT_1::value_type, + typename VecT_2::value_type + >::type, + fixed<3> + > result_type; + + /* Checking */ + detail::CheckVec3(v); + detail::CheckVec3(n); + + result_type parallel = dot(v,n)*n; + return ( + std::cos(angle)*(v-parallel) + std::sin(angle)*cross(n,v) + parallel + ); +} + +/** Rotate a 2D vector v about a unit-length vector n. */ +template< class VecT, typename Real > +vector< typename VecT::value_type, fixed<2> > +rotate_vector_2D(const VecT& v, Real angle) +{ + typedef vector< typename VecT::value_type, fixed<2> > result_type; + typedef typename result_type::value_type value_type; + + /* Checking */ + detail::CheckVec2(v); + + value_type s = std::sin(angle); + value_type c = std::cos(angle); + + return result_type(c * v[0] - s * v[1], s * v[0] + c * v[1]); +} + +/** Random unit 3D or 2D vector + * + * @todo: This is just placeholder code for what will be a more thorough + * 'random unit' implementation: + * + * - All dimensions will be handled uniformly if practical, perhaps through + * a normal distrubution PRNG. + * + * - Failing that (or perhaps even in this case), dimensions 2 and 3 will be + * dispatched to special-case code, most likely implementing the algorithms + * below. + * + * - Like the utility random functions, the option of using one's own PRGN + * will be made available. + * + * @todo: Once N-d random vectors are supported, add a 'random unit + * quaternion' function that wraps a call to random_unit() with a 4D vector as + * the argument. + */ +template < typename E, class A > void +random_unit(vector& v) +{ + typedef vector vector_type; + typedef typename vector_type::value_type value_type; + + switch (v.size()) { + case 3: + { + vector< E, fixed<3> > temp; + spherical_to_cartesian( + value_type(1), + value_type(random_unit() * constants::two_pi()), + acos_safe(random_real(value_type(-1),value_type(1))), + 2, + colatitude, + temp + ); + v[0] = temp[0]; + v[1] = temp[1]; + v[2] = temp[2]; + break; + } + case 2: + { + vector< E, fixed<2> > temp; + polar_to_cartesian( + value_type(1), + value_type(random_unit() * constants::two_pi()), + temp + ); + v[0] = temp[0]; + v[1] = temp[1]; + break; + } + default: + throw std::invalid_argument( + "random_unit() for N-d vectors not implemented yet"); + break; + } +} + +/* Random vector within a given angle of a unit-length axis, i.e. in a cone + * (3D) or wedge (2D). + * + * The same notes the appear above apply here too, more or less. One + * difference is that this is really only useful in 2D and 3D (presumably), so + * we'll probably just do a compile- or run-time dispatch as appropriate. + * + * Also, there may be a better algorithm for generating a random unit vector + * in a cone; need to look into that. + * + * All of this 'temp' stuff is because there's no compile-time dispatch for + * 3D and 2D vectors, but that'll be fixed soon. + */ + +template < typename E, class A, class VecT > void +random_unit(vector& v, const VecT& axis, E theta) +{ + typedef vector vector_type; + typedef typename vector_type::value_type value_type; + + switch (v.size()) { + case 3: + { + vector< E, fixed<3> > temp, n, temp_axis; + temp_axis[0] = axis[0]; + temp_axis[1] = axis[1]; + temp_axis[2] = axis[2]; + + /* @todo: Function for finding 'any perpendicular vector'? */ + n = axis_3D(cml::index_of_min_abs(axis[0],axis[1],axis[2])); + n = cross(n,temp_axis); + + /* Rotate v 'away from' the axis by a random angle in the range + * [-theta,theta] + */ + temp = rotate_vector(temp_axis,n,random_real(-theta,theta)); + + /* Rotate v about the axis by a random angle in the range [-pi,pi] + */ + temp = rotate_vector( + temp, + temp_axis, + random_real( + -constants::pi(), + constants::pi() + ) + ); + + v[0] = temp[0]; + v[1] = temp[1]; + v[2] = temp[2]; + break; + } + case 2: + { + vector< E, fixed<2> > temp, temp_axis; + temp_axis[0] = axis[0]; + temp_axis[1] = axis[1]; + temp = rotate_vector_2D(temp_axis, random_real(-theta,theta)); + v[0] = temp[0]; + v[1] = temp[1]; + break; + } + default: + throw std::invalid_argument( + "random_unit(v,axis,theta) only implemented for 2D and 3D"); + break; + } +} + +/* NEW: Manhattan distance */ + +template< class VecT_1, class VecT_2 > +typename detail::DotPromote< VecT_1, VecT_2 >::promoted_scalar +manhattan_distance(const VecT_1& v1, const VecT_2& v2) { + /* Check that a promotion exists */ + typedef typename et::VectorPromote< + VecT_1,VecT_2>::temporary_type promoted_vector; + + typedef typename detail::DotPromote< VecT_1, VecT_2 >::promoted_scalar scalar_type; + + scalar_type sum = scalar_type(0); + for (size_t i = 0; i < v1.size(); ++i) { + sum += std::fabs(v2[i]-v1[i]); + } + return sum; +} + +} // namespace cml + +#endif diff --git a/Lib/Include/CML/mathlib/vector_ortho.h b/Lib/Include/CML/mathlib/vector_ortho.h new file mode 100644 index 0000000..3983264 --- /dev/null +++ b/Lib/Include/CML/mathlib/vector_ortho.h @@ -0,0 +1,338 @@ +/* -*- C++ -*- ------------------------------------------------------------ + +Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/ + +The Configurable Math Library (CML) is distributed under the terms of the +Boost Software License, v1.0 (see cml/LICENSE for details). + + *-----------------------------------------------------------------------*/ +/** @file + * + * Functions for orthonormalizing a set of basis vectors in 3D or 2D, and for + * constructing an orthonormal basis given various input parameters. + */ + +#ifndef vector_ortho_h +#define vector_ortho_h + +#include +#include + +namespace cml { + +////////////////////////////////////////////////////////////////////////////// +// Orthonormalization in 3D and 2D +////////////////////////////////////////////////////////////////////////////// + + +/** Orthonormalize 3 basis vectors in R3. + * + * Called with the default values, this function performs a single Gram- + * Schmidt step to orthonormalize the input vectors. By default, the direction + * of the 3rd basis vector is unchanged by this operation, but the unaffected + * axis can be specified via the 'stable_axis' parameter. + * + * The arguments 'num_iter' and 's' can be specified to an iterative Gram- + * Schmidt step. 'num_iter' is the number of iterations applied, and 's' is + * the fraction applied towards orthonormality each step. + * + * In most cases, the default arguments can be ignored, leaving only the three + * input vectors. + */ +template < typename E, class A > void +orthonormalize(vector& v0, vector& v1, vector& v2, + size_t stable_axis = 2, size_t num_iter = 0, E s = E(1)) +{ + /* Checking */ + detail::CheckVec3(v0); + detail::CheckVec3(v1); + detail::CheckVec3(v2); + detail::CheckIndex3(stable_axis); + + typedef vector< E, fixed<3> > vector_type; + typedef typename vector_type::value_type value_type; + + /* Iterative Gram-Schmidt; this step is skipped by default. */ + + for (size_t i = 0; i < num_iter; ++i) { + value_type dot01 = dot(v0,v1); + value_type dot12 = dot(v1,v2); + value_type dot20 = dot(v2,v0); + value_type inv_dot00 = value_type(1) / dot(v0,v0); + value_type inv_dot11 = value_type(1) / dot(v1,v1); + value_type inv_dot22 = value_type(1) / dot(v2,v2); + + vector_type temp0 = v0 - s*dot01*inv_dot11*v1 - s*dot20*inv_dot22*v2; + vector_type temp1 = v1 - s*dot12*inv_dot22*v2 - s*dot01*inv_dot00*v0; + vector_type temp2 = v2 - s*dot20*inv_dot00*v0 - s*dot12*inv_dot11*v1; + + v0 = temp0; + v1 = temp1; + v2 = temp2; + } + + /* Final Gram-Schmidt step to ensure orthonormality. If no iterations + * have been requested (num_iter = 0), this is the only step. The step + * is performed such that the direction of the axis indexed by + * 'stable_axis' is unchanged. + */ + + size_t i, j, k; + cyclic_permutation(stable_axis, i, j, k); + vector_type v[] = { v0, v1, v2 }; + + v[i].normalize(); + v[j] = normalize(project_to_hplane(v[j],v[i])); + v[k] = normalize(project_to_hplane(project_to_hplane(v[k],v[i]),v[j])); + + v0 = v[0]; + v1 = v[1]; + v2 = v[2]; +} + +/** Orthonormalize 2 basis vectors in R2 */ +template < typename E, class A > void +orthonormalize(vector& v0, vector& v1, + size_t stable_axis = 0, size_t num_iter = 0, E s = E(1)) +{ + typedef vector< E, fixed<2> > vector_type; + typedef typename vector_type::value_type value_type; + + /* Checking */ + detail::CheckVec2(v0); + detail::CheckVec2(v1); + detail::CheckIndex2(stable_axis); + + /* Iterative Gram-Schmidt; this step is skipped by default. */ + + for (size_t i = 0; i < num_iter; ++i) { + value_type dot01 = dot(v0,v1); + + vector_type temp0 = v0 - (s * dot01 * v1) / dot(v1,v1); + vector_type temp1 = v1 - (s * dot01 * v0) / dot(v0,v0); + + v0 = temp0; + v1 = temp1; + } + + /* Final Gram-Schmidt step to ensure orthonormality. If no iterations + * have been requested (num_iter = 0), this is the only step. The step + * is performed such that the direction of the axis indexed by + * 'stable_axis' is unchanged. + */ + + size_t i, j; + cyclic_permutation(stable_axis, i, j); + vector_type v[] = { v0, v1 }; + + v[i].normalize(); + v[j] = normalize(project_to_hplane(v[j],v[i])); + + v0 = v[0]; + v1 = v[1]; +} + +////////////////////////////////////////////////////////////////////////////// +// Orthonormal basis construction in 3D and 2D +////////////////////////////////////////////////////////////////////////////// + +/** This version of orthonormal_basis() ultimately does the work for all + * orthonormal_basis_*() functions. Given input vectors 'align' and + * 'reference', and an order 'axis_order_\\\', it constructs an + * orthonormal basis such that the i'th basis vector is aligned with (parallel + * to and pointing in the same direction as) 'align', and the j'th basis + * vector is maximally aligned with 'reference'. The k'th basis vector is + * chosen such that the basis has a determinant of +1. + * + * @note The algorithm fails when 'align' is nearly parallel to + * 'reference'; this should be checked for and handled externally if it's a + * case that may occur. + * + * @internal This is an example of the 'non-const argument modification + * invalidates expression' gotcha. If x, y or z were to be assigned to before + * we were 'done' with align and reference, and if one of them were the same + * object as align or reference, then the algorithm could fail. As is the + * basis vectors are assigned at the end of the function from a temporary + * array, so all is well. + */ +template < class VecT_1, class VecT_2, typename E, class A > void +orthonormal_basis( + const VecT_1& align, + const VecT_2& reference, + vector& x, + vector& y, + vector& z, + bool normalize_align = true, + AxisOrder order = axis_order_zyx) +{ + typedef vector< E,fixed<3> > vector_type; + typedef typename vector_type::value_type value_type; + + /* Checking handled by cross() and assignment to fixed<3>. */ + + size_t i, j, k; + bool odd; + detail::unpack_axis_order(order, i, j, k, odd); + + vector_type axis[3]; + + axis[i] = normalize_align ? normalize(align) : align; + axis[k] = unit_cross(axis[i],reference); + axis[j] = cross(axis[k],axis[i]); + + if (odd) { + axis[k] = -axis[k]; + } + + x = axis[0]; + y = axis[1]; + z = axis[2]; +} + +/** This version of orthonormal_basis() constructs in arbitrary basis given a + * vector with which to align the i'th basis vector. To avoid the failure + * case, the reference vector is always chosen so as to not be parallel to + * 'align'. This means the algorithm will always generate a valid basis, which + * can be useful in some circumstances; however, it should be noted that the + * basis will likely 'pop' as the alignment vector changes, and so may not be + * suitable for billboarding or other similar applications. + */ +template < class VecT, typename E, class A > +void orthonormal_basis( + const VecT& align, + vector& x, + vector& y, + vector& z, + bool normalize_align = true, + AxisOrder order = axis_order_zyx) +{ + /* Checking (won't be necessary with index_of_min_abs() member function */ + detail::CheckVec3(align); + + /* @todo: vector member function index_of_min_abs() would clean this up */ + + orthonormal_basis( + align, + axis_3D(cml::index_of_min_abs(align[0],align[1],align[2])), + x, y, z, normalize_align, order + ); +} + +/** orthonormal_basis_axial() generates a basis in which the j'th basis vector + * is aligned with 'axis' and the i'th basis vector is maximally aligned (as + * 'aligned as possible') with 'align'. This can be used for e.g. axial + * billboarding for, say, trees or beam effects. + * + * Note that the implementation simply passes off to the 'reference' version + * of orthonormal_basis(), with the parameters adjusted so that the alignment + * is axial. + * + * @note With this algorithm the failure case is when 'align' and 'axis' + * are nearly parallel; if this is likely, it should be checked for and + * handled externally. + */ +template < class VecT_1, class VecT_2, typename E, class A > +void orthonormal_basis_axial( + const VecT_1& align, + const VecT_2& axis, + vector& x, + vector& y, + vector& z, + bool normalize_align = true, + AxisOrder order = axis_order_zyx) +{ + orthonormal_basis( + axis, + align, + x, + y, + z, + normalize_align, + detail::swap_axis_order(order)); +} + +/** orthonormal_basis_viewplane() builds a basis aligned with a viewplane, as + * extracted from the input view matrix. The function takes into account the + * handedness of the input view matrix and orients the basis accordingly. + * + * @note The generated basis will always be valid. + */ +template < class MatT, typename E, class A > +void orthonormal_basis_viewplane( + const MatT& view_matrix, + vector& x, + vector& y, + vector& z, + Handedness handedness, + AxisOrder order = axis_order_zyx) +{ + typedef MatT matrix_type; + typedef typename matrix_type::value_type value_type; + + orthonormal_basis( + -(handedness == left_handed ? value_type(1) : value_type(-1)) * + matrix_get_transposed_z_basis_vector(view_matrix), + matrix_get_transposed_y_basis_vector(view_matrix), + x, y, z, false, order + ); +} + +/** Build a viewplane-oriented basis from a left-handedness view matrix. */ +template < class MatT, typename E, class A > +void orthonormal_basis_viewplane_LH( + const MatT& view_matrix, + vector& x, + vector& y, + vector& z, + AxisOrder order = axis_order_zyx) +{ + orthonormal_basis_viewplane( + view_matrix,x,y,z,left_handed,order); +} + +/** Build a viewplane-oriented basis from a right-handedness view matrix. */ +template < class MatT, typename E, class A > +void orthonormal_basis_viewplane_RH( + const MatT& view_matrix, + vector& x, + vector& y, + vector& z, + AxisOrder order = axis_order_zyx) +{ + orthonormal_basis_viewplane( + view_matrix,x,y,z,right_handed,order); +} + +/** Build a 2D orthonormal basis. */ +template < class VecT, typename E, class A > +void orthonormal_basis_2D( + const VecT& align, + vector& x, + vector& y, + bool normalize_align = true, + AxisOrder2D order = axis_order_xy) +{ + typedef vector< E,fixed<2> > vector_type; + + /* Checking handled by perp() and assignment to fixed<2>. */ + + size_t i, j; + bool odd; + detail::unpack_axis_order_2D(order, i, j, odd); + + vector_type axis[2]; + + axis[i] = normalize_align ? normalize(align) : align; + axis[j] = perp(axis[i]); + + if (odd) { + axis[j] = -axis[j]; + } + + x = axis[0]; + y = axis[1]; +} + +} // namespace cml + +#endif diff --git a/Lib/Include/CML/mathlib/vector_transform.h b/Lib/Include/CML/mathlib/vector_transform.h new file mode 100644 index 0000000..7681ad6 --- /dev/null +++ b/Lib/Include/CML/mathlib/vector_transform.h @@ -0,0 +1,176 @@ +/* -*- C++ -*- ------------------------------------------------------------ + +Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/ + +The Configurable Math Library (CML) is distributed under the terms of the +Boost Software License, v1.0 (see cml/LICENSE for details). + + *-----------------------------------------------------------------------*/ +/** @file + * @brief + */ + +#ifndef vector_transform_h +#define vector_transform_h + +#include + +/* Functions for transforming a vector, representing a geometric point or + * or vector, by an affine transfom. + * + * Note: This functionality may be provisional, depending on what architecture + * we settle on for the higher-level math functions. If we do keep these + * functions, then this code may ending up being a placeholder for expression + * template code. + */ + +namespace cml { + +/** A fixed-size temporary 4D vector */ +#define TEMP_VEC4 vector< \ + typename et::ScalarPromote< \ + typename MatT::value_type, \ + typename VecT::value_type \ + >::type, \ + fixed<4> \ +> + +/** A fixed-size temporary 3D vector */ +#define TEMP_VEC3 vector< \ + typename et::ScalarPromote< \ + typename MatT::value_type, \ + typename VecT::value_type \ + >::type, \ + fixed<3> \ +> + +/** A fixed-size temporary 2D vector */ +#define TEMP_VEC2 vector< \ + typename et::ScalarPromote< \ + typename MatT::value_type, \ + typename VecT::value_type \ + >::type, \ + fixed<2> \ +> + +namespace detail { + +template < class MatT, class VecT > TEMP_VEC4 +transform_vector_4D(const MatT& m, const VecT& v, row_basis) { + return v*m; +} + +template < class MatT, class VecT > TEMP_VEC4 +transform_vector_4D(const MatT& m, const VecT& v, col_basis) { + return m*v; +} + +} // namespace detail + +/** Apply a 4x4 homogeneous transform matrix to a 4D vector */ +template < class MatT, class VecT > TEMP_VEC4 +transform_vector_4D(const MatT& m, const VecT& v) { + return detail::transform_vector_4D(m,v,typename MatT::basis_orient()); +} + +/** Apply a homogeneous (e.g. perspective) transform to a 3D point. */ +template < class MatT, class VecT > TEMP_VEC3 +transform_point_4D(const MatT& m, const VecT& v) +{ + typedef TEMP_VEC3 vector_type; + typedef typename TEMP_VEC3::coordinate_type coordinate_type; + + /* Checking */ + detail::CheckMatHomogeneous3D(m); + detail::CheckVec3(v); + + /* Compute the 4D point: */ + TEMP_VEC4 v4 = transform_vector_4D( + m, TEMP_VEC4(v[0], v[1], v[2], coordinate_type(1))); + + /* Return the projected point: */ + coordinate_type w = v4[3]; + return vector_type(v4[0]/w, v4[1]/w, v4[2]/w); +} + +/** Apply a 3D affine transform to a 3D point */ +template < class MatT, class VecT > TEMP_VEC3 +transform_point(const MatT& m, const VecT& v) +{ + typedef TEMP_VEC3 vector_type; + + /* Checking */ + detail::CheckMatAffine3D(m); + detail::CheckVec3(v); + + return vector_type( + m.basis_element(0,0)*v[0]+m.basis_element(1,0)*v[1]+ + m.basis_element(2,0)*v[2]+m.basis_element(3,0), + m.basis_element(0,1)*v[0]+m.basis_element(1,1)*v[1]+ + m.basis_element(2,1)*v[2]+m.basis_element(3,1), + m.basis_element(0,2)*v[0]+m.basis_element(1,2)*v[1]+ + m.basis_element(2,2)*v[2]+m.basis_element(3,2) + ); +} + +/** Apply a 3D affine transform to a 3D vector */ +template < class MatT, class VecT > TEMP_VEC3 +transform_vector(const MatT& m, const VecT& v) +{ + typedef TEMP_VEC3 vector_type; + + /* Checking */ + detail::CheckMatLinear3D(m); + detail::CheckVec3(v); + + return vector_type( + m.basis_element(0,0)*v[0]+m.basis_element(1,0)*v[1]+ + m.basis_element(2,0)*v[2], + m.basis_element(0,1)*v[0]+m.basis_element(1,1)*v[1]+ + m.basis_element(2,1)*v[2], + m.basis_element(0,2)*v[0]+m.basis_element(1,2)*v[1]+ + m.basis_element(2,2)*v[2] + ); +} + +/** Apply a 2D affine transform to a 2D point */ +template < class MatT, class VecT > TEMP_VEC2 +transform_point_2D(const MatT& m, const VecT& v) +{ + typedef TEMP_VEC2 vector_type; + + /* Checking */ + detail::CheckMatAffine2D(m); + detail::CheckVec2(v); + + return vector_type( + m.basis_element(0,0)*v[0]+m.basis_element(1,0)*v[1]+ + m.basis_element(2,0), + m.basis_element(0,1)*v[0]+m.basis_element(1,1)*v[1]+ + m.basis_element(2,1) + ); +} + +/** Apply a 2D affine transform to a 2D vector */ +template < class MatT, class VecT > TEMP_VEC2 +transform_vector_2D(const MatT& m, const VecT& v) +{ + typedef TEMP_VEC2 vector_type; + + /* Checking */ + detail::CheckMatLinear2D(m); + detail::CheckVec2(v); + + return vector_type( + m.basis_element(0,0)*v[0] + m.basis_element(1,0)*v[1], + m.basis_element(0,1)*v[0] + m.basis_element(1,1)*v[1] + ); +} + +#undef TEMP_VEC4 +#undef TEMP_VEC3 +#undef TEMP_VEC2 + +} // namespace cml + +#endif diff --git a/Lib/Include/CML/matrix.h b/Lib/Include/CML/matrix.h new file mode 100644 index 0000000..a96031f --- /dev/null +++ b/Lib/Include/CML/matrix.h @@ -0,0 +1,63 @@ +/* -*- C++ -*- ------------------------------------------------------------ + +Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/ + +The Configurable Math Library (CML) is distributed under the terms of the +Boost Software License, v1.0 (see cml/LICENSE for details). + + *-----------------------------------------------------------------------*/ +/** @file + * @brief + * + * The configurable matrix<> class. + */ + +#ifndef cml_matrix_h +#define cml_matrix_h + +#include + +namespace cml { + +/** A configurable matrix. + * + * This class encapsulates the notion of a matrix. The ArrayType template + * argument can be used to select the type of array to be used as internal + * storage for a 2D array of type Element. + * + * @internal Unlike the previous version, this uses specializations to better + * enable varied array and matrix types. For example, with the rebind method, + * it's difficult to support external<> matrix types that should not be + * assigned to. + * + * @internal All assignments to the matrix should go through UnrollAssignment, + * which ensures that the source expression and the destination matrix have + * the same size. This is particularly important for dynamically-sized + * matrices. + */ +template class matrix; + +} // namespace cml + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#endif + +// ------------------------------------------------------------------------- +// vim:ft=cpp diff --git a/Lib/Include/CML/matrix/class_ops.h b/Lib/Include/CML/matrix/class_ops.h new file mode 100644 index 0000000..d2a8dbd --- /dev/null +++ b/Lib/Include/CML/matrix/class_ops.h @@ -0,0 +1,341 @@ +/* -*- C++ -*- ------------------------------------------------------------ + +Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/ + +The Configurable Math Library (CML) is distributed under the terms of the +Boost Software License, v1.0 (see cml/LICENSE for details). + + *-----------------------------------------------------------------------*/ +/** @file + * @brief + * + * @note GCC4 requires a copy constructor to elide---it won't elide a + * compiler-generated copy constructor! + */ + +#ifndef matrix_class_ops_h +#define matrix_class_ops_h + +#if defined(_MSC_VER) && _MSC_VER < 1400 +#pragma warning(disable:4003) +// XXX Horrible hack to turn off warnings about "not enough actual params" +// for the macros below. +#endif + +/* This is to circumvent the problem of commas in a macro argument. It's + * used to instantiate CML_ACCUMULATED_MATRIX_MULT: + */ +#define TEMPLATED_MATRIX_MACRO matrix + +/* XXX HACK!!! This is a hack to resize in the assign() functions only when + * auto resizing is turned off. + */ +#if !defined(CML_MATRIX_RESIZE_ON_ASSIGNMENT) +#define _DO_MATRIX_SET_RESIZE(_R_,_C_) cml::et::detail::Resize(*this,_R_,_C_) +#else +#define _DO_MATRIX_SET_RESIZE(_R_,_C_) +#endif + +/** Set a matrix from 2x2 values. + * + * The layout assumed for the values is that of the matrix being assigned. + */ +#define CML_ASSIGN_MAT_22 \ +matrix_type& \ +set( \ + ELEMENT_ARG_TYPE e00, ELEMENT_ARG_TYPE e01, \ + ELEMENT_ARG_TYPE e10, ELEMENT_ARG_TYPE e11 \ + ) \ +{ \ + _DO_MATRIX_SET_RESIZE(2,2); \ + /* This is overkill, but simplifies size checking: */ \ + value_type v[2][2] = {{e00,e01},{e10,e11}}; \ + typedef et::OpAssign OpT; \ + typedef const value_type element; \ + cml::matrix, basis_orient, row_major> \ + src(&v[0][0]); \ + et::UnrollAssignment(*this,src); \ + return *this; \ +} + +/** Create a matrix from 3x3 values. + * + * The layout assumed for the values is that of the matrix being assigned. + */ +#define CML_ASSIGN_MAT_33 \ +matrix_type& \ +set( \ + ELEMENT_ARG_TYPE e00, ELEMENT_ARG_TYPE e01, ELEMENT_ARG_TYPE e02, \ + ELEMENT_ARG_TYPE e10, ELEMENT_ARG_TYPE e11, ELEMENT_ARG_TYPE e12, \ + ELEMENT_ARG_TYPE e20, ELEMENT_ARG_TYPE e21, ELEMENT_ARG_TYPE e22 \ + ) \ +{ \ + _DO_MATRIX_SET_RESIZE(3,3); \ + /* This is overkill, but simplifies size checking: */ \ + value_type v[3][3] = { \ + {e00,e01,e02}, \ + {e10,e11,e12}, \ + {e20,e21,e22} \ + }; \ + typedef et::OpAssign OpT; \ + typedef const value_type element; \ + cml::matrix, basis_orient, row_major> \ + src(&v[0][0]); \ + et::UnrollAssignment(*this,src); \ + return *this; \ +} + +/** Create a matrix from 4x4 values. + * + * The layout assumed for the values is that of the matrix being assigned. + */ +#define CML_ASSIGN_MAT_44 \ +matrix_type& \ +set( \ + ELEMENT_ARG_TYPE e00, ELEMENT_ARG_TYPE e01, \ + ELEMENT_ARG_TYPE e02, ELEMENT_ARG_TYPE e03, \ + ELEMENT_ARG_TYPE e10, ELEMENT_ARG_TYPE e11, \ + ELEMENT_ARG_TYPE e12, ELEMENT_ARG_TYPE e13, \ + ELEMENT_ARG_TYPE e20, ELEMENT_ARG_TYPE e21, \ + ELEMENT_ARG_TYPE e22, ELEMENT_ARG_TYPE e23, \ + ELEMENT_ARG_TYPE e30, ELEMENT_ARG_TYPE e31, \ + ELEMENT_ARG_TYPE e32, ELEMENT_ARG_TYPE e33 \ + ) \ +{ \ + _DO_MATRIX_SET_RESIZE(4,4); \ + /* This is overkill, but simplifies size checking: */ \ + value_type v[4][4] = { \ + {e00,e01,e02,e03}, \ + {e10,e11,e12,e13}, \ + {e20,e21,e22,e23}, \ + {e30,e31,e32,e33} \ + }; \ + typedef et::OpAssign OpT; \ + typedef const value_type element; \ + cml::matrix, basis_orient, row_major> \ + src(&v[0][0]); \ + et::UnrollAssignment(*this,src); \ + return *this; \ +} + +/** Create a matrix from 2x2 values. + * + * The layout assumed for the values is that of the matrix being assigned. + */ +#define CML_CONSTRUCT_MAT_22 \ +matrix( \ + ELEMENT_ARG_TYPE e00, ELEMENT_ARG_TYPE e01, \ + ELEMENT_ARG_TYPE e10, ELEMENT_ARG_TYPE e11 \ + ) \ +{ \ + set( \ + e00,e01, \ + e10,e11 \ + ); \ +} + +/** Create a matrix from 3x3 values. + * + * The layout assumed for the values is that of the matrix being assigned. + */ +#define CML_CONSTRUCT_MAT_33 \ +matrix( \ + ELEMENT_ARG_TYPE e00, ELEMENT_ARG_TYPE e01, ELEMENT_ARG_TYPE e02, \ + ELEMENT_ARG_TYPE e10, ELEMENT_ARG_TYPE e11, ELEMENT_ARG_TYPE e12, \ + ELEMENT_ARG_TYPE e20, ELEMENT_ARG_TYPE e21, ELEMENT_ARG_TYPE e22 \ + ) \ +{ \ + set( \ + e00,e01,e02, \ + e10,e11,e12, \ + e20,e21,e22 \ + ); \ +} + +/** Create a matrix from 4x4 values. + * + * The layout assumed for the values is that of the matrix being assigned. + */ +#define CML_CONSTRUCT_MAT_44 \ +matrix( \ + ELEMENT_ARG_TYPE e00, ELEMENT_ARG_TYPE e01, \ + ELEMENT_ARG_TYPE e02, ELEMENT_ARG_TYPE e03, \ + ELEMENT_ARG_TYPE e10, ELEMENT_ARG_TYPE e11, \ + ELEMENT_ARG_TYPE e12, ELEMENT_ARG_TYPE e13, \ + ELEMENT_ARG_TYPE e20, ELEMENT_ARG_TYPE e21, \ + ELEMENT_ARG_TYPE e22, ELEMENT_ARG_TYPE e23, \ + ELEMENT_ARG_TYPE e30, ELEMENT_ARG_TYPE e31, \ + ELEMENT_ARG_TYPE e32, ELEMENT_ARG_TYPE e33 \ + ) \ +{ \ + set( \ + e00,e01,e02,e03, \ + e10,e11,e12,e13, \ + e20,e21,e22,e23, \ + e30,e31,e32,e33 \ + ); \ +} + +/** Copy-construct a matrix from a fixed-size array of values. */ +#define CML_MAT_COPY_FROM_FIXED_ARRAY(_R_,_C_) \ +matrix(const value_type m[_R_][_C_]) { \ + typedef et::OpAssign OpT; \ + cml::matrix, \ + basis_orient, row_major> src(&m[0][0]); \ + et::UnrollAssignment(*this,src); \ +} + +/** Copy-construct a matrix from a runtime-sized array of values. */ +#define CML_MAT_COPY_FROM_ARRAY(_add_) \ +matrix(const value_type* const v, size_t R, size_t C) _add_ { \ + typedef et::OpAssign OpT; \ + cml::matrix, basis_orient, \ + row_major > src(const_cast(v),R,C); \ + et::UnrollAssignment(*this,src); \ +} + +/** Copy this matrix from another using the given elementwise op. + * + * @internal This is required for GCC4, since it won't elide the default + * copy constructor. + */ +#define CML_MAT_COPY_FROM_MATTYPE \ +matrix(const matrix_type& m) : array_type() { \ + typedef et::OpAssign OpT; \ + et::UnrollAssignment(*this,m); \ +} + +/** Copy this matrix from another using the given elementwise op. + * + * This allows copies from arbitrary matrix types. + */ +#define CML_MAT_COPY_FROM_MAT \ +template \ +matrix(const TEMPLATED_MATRIX_MACRO& m) { \ + typedef et::OpAssign OpT; \ + et::UnrollAssignment(*this,m); \ +} + +/** Declare a function to copy this matrix from a matrix expression. */ +#define CML_MAT_COPY_FROM_MATXPR \ +template \ +matrix(MATXPR_ARG_TYPE e) { \ + /* Verify that a promotion exists at compile time: */ \ + typedef typename et::MatrixPromote< \ + matrix_type, typename XprT::result_type>::type result_type; \ + typedef typename XprT::value_type src_value_type; \ + typedef et::OpAssign OpT; \ + et::UnrollAssignment(*this,e); \ +} + +#if defined(CML_USE_GENERATED_MATRIX_ASSIGN_OP) +#define CML_MAT_ASSIGN_FROM_MATTYPE +#else +/** Assign from the same matrix type. + * + * @param m the matrix to copy from. + * + * @note This is required for GCC4, otherwise it generates a slow + * assignment operator using memcpy. + * + * @note ICC9/Linux-x86 seems to prefer its own assignment operator (need + * to figure out why). + */ +#define CML_MAT_ASSIGN_FROM_MATTYPE \ +matrix_type& operator=(const matrix_type& m) { \ + typedef et::OpAssign OpT; \ + et::UnrollAssignment(*this,m); \ + return *this; \ +} +#endif + + +/** Assign this matrix from another using the given elementwise op. + * + * This allows assignment from arbitrary matrix types. + * + * @param _op_ the operator (e.g. +=) + * @param _op_name_ the op functor (e.g. et::OpAssign) + */ +#define CML_MAT_ASSIGN_FROM_MAT(_op_, _op_name_) \ +template matrix_type& \ +operator _op_ (const TEMPLATED_MATRIX_MACRO& m) { \ + typedef _op_name_ OpT; \ + et::UnrollAssignment(*this,m); \ + return *this; \ +} + +/** Declare a function to assign this matrix from a matrix expression. + * + * @param _op_ the operator (e.g. +=) + * @param _op_name_ the op functor (e.g. et::OpAssign) + */ +#define CML_MAT_ASSIGN_FROM_MATXPR(_op_, _op_name_) \ +template matrix_type& \ +operator _op_ (MATXPR_ARG_TYPE e) { \ + /* Verify that a promotion exists at compile time: */ \ + typedef typename et::MatrixPromote< \ + matrix_type, typename XprT::result_type>::type result_type; \ + typedef typename XprT::value_type src_value_type; \ + typedef _op_name_ OpT; \ + et::UnrollAssignment(*this,e); \ + return *this; \ +} + +/** Declare a function to assign this matrix from a scalar. + * + * @param _op_ the operator (e.g. +=) + * @param _op_name_ the op functor (e.g. et::OpAssign) + * + * @internal This shouldn't be used for ops, like +=, which aren't + * defined in vector algebra. + */ +#define CML_MAT_ASSIGN_FROM_SCALAR(_op_, _op_name_) \ +matrix_type& operator _op_ (ELEMENT_ARG_TYPE s) { \ + typedef _op_name_ OpT; \ + et::UnrollAssignment(*this,s); \ + return *this; \ +} + + +/** Accumulated matrix multiplication. + * + * @throws std::invalid_argument if the matrices are not square. + */ +#define CML_ACCUMULATED_MATRIX_MULT(_arg_type_) \ +matrix_type& operator*=(_arg_type_ m) { \ + typedef typename et::MatrixPromote< \ + matrix_type, _arg_type_>::type result_type; \ + cml::et::CheckedSquare(*this, typename result_type::size_tag()); \ + return (*this = (*this)*m); \ +} + + +/* These should only be used for testing: */ +#define CML_MATRIX_BRACE_OPERATORS \ +template struct row_ref { \ + typedef typename Matrix::reference reference; \ + reference operator[](size_t col) { return m(row,col); } \ + Matrix& m; \ + size_t row; \ +}; \ + \ +template struct const_row_ref { \ + typedef typename Matrix::const_reference const_reference; \ + const_reference operator[](size_t col) const { return m(row,col); } \ + const Matrix& m; \ + size_t row; \ +}; \ + \ +row_ref operator[](size_t row) { \ + row_ref ref = { *this, row }; return ref; \ +} \ + \ +const_row_ref operator[](size_t row) const { \ + const_row_ref ref = { *this, row }; return ref; \ +} + +#endif + +// ------------------------------------------------------------------------- +// vim:ft=cpp diff --git a/Lib/Include/CML/matrix/determinant.h b/Lib/Include/CML/matrix/determinant.h new file mode 100644 index 0000000..fa2cba3 --- /dev/null +++ b/Lib/Include/CML/matrix/determinant.h @@ -0,0 +1,192 @@ +/* -*- C++ -*- ------------------------------------------------------------ + +Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/ + +The Configurable Math Library (CML) is distributed under the terms of the +Boost Software License, v1.0 (see cml/LICENSE for details). + + *-----------------------------------------------------------------------*/ +/** @file + * @brief Compute the determinant of a square matrix using LU factorization. + * + * @todo This should be specialized on the matrix size for small matrices. + */ + +#ifndef determinant_h +#define determinant_h + +#include + +namespace cml { +namespace detail { + +/* Need to use a functional, since template functions cannot be + * specialized. N is used to differentiate dimension only, so this can be + * used for any matrix size type: + */ +template struct determinant_f; + +/* 2x2 determinant. Despite being marked for fixed_size matrices, this can + * be used for dynamic-sized ones also: + */ +template +struct determinant_f +{ + typename MatT::value_type operator()(const MatT& M) const + { + return M(0,0)*M(1,1) - M(1,0)*M(0,1); + } + +}; + +/* 3x3 determinant. Despite being marked for fixed_size matrices, this can + * be used for dynamic-sized ones also: + */ +template +struct determinant_f +{ + /* [00 01 02] + * M = [10 11 12] + * [20 21 22] + */ + typename MatT::value_type operator()(const MatT& M) const + { + return M(0,0)*(M(1,1)*M(2,2) - M(1,2)*M(2,1)) + + M(0,1)*(M(1,2)*M(2,0) - M(1,0)*M(2,2)) + + M(0,2)*(M(1,0)*M(2,1) - M(1,1)*M(2,0)); + } + +}; + +/* 4x4 determinant. Despite being marked for fixed_size matrices, this can + * be used for dynamic-sized ones also: + */ +template +struct determinant_f +{ + /* [00 01 02 03] + * M = [10 11 12 13] + * [20 21 22 23] + * [30 31 32 33] + * + * |11 12 13| |10 12 13| + * C00 = |21 22 23| C01 = |20 22 23| + * |31 32 33| |30 32 33| + * + * |10 11 13| |10 11 12| + * C02 = |20 21 23| C03 = |20 21 22| + * |30 31 33| |30 31 32| + * + * d00 = 11 * (22*33 - 23*32) d01 = 10 * (22*33 - 23*32) + * + 12 * (23*31 - 21*33) + 12 * (23*30 - 20*33) + * + 13 * (21*32 - 22*31) + 13 * (20*32 - 22*30) + * + * d02 = 10 * (21*33 - 23*31) d03 = 10 * (21*32 - 22*31) + * + 11 * (23*30 - 20*33) + 11 * (22*30 - 20*32) + * + 13 * (20*31 - 21*30) + 12 * (20*31 - 21*30) + */ + typename MatT::value_type operator()(const MatT& M) const + { + /* Shorthand. */ + typedef typename MatT::value_type value_type; + + /* Common cofactors: */ + value_type m_22_33_23_32 = M(2,2)*M(3,3) - M(2,3)*M(3,2); + value_type m_23_30_20_33 = M(2,3)*M(3,0) - M(2,0)*M(3,3); + value_type m_20_31_21_30 = M(2,0)*M(3,1) - M(2,1)*M(3,0); + value_type m_21_32_22_31 = M(2,1)*M(3,2) - M(2,2)*M(3,1); + value_type m_23_31_21_33 = M(2,3)*M(3,1) - M(2,1)*M(3,3); + value_type m_20_32_22_30 = M(2,0)*M(3,2) - M(2,2)*M(3,0); + + value_type d00 = M(0,0)*( + M(1,1) * m_22_33_23_32 + + M(1,2) * m_23_31_21_33 + + M(1,3) * m_21_32_22_31); + + value_type d01 = M(0,1)*( + M(1,0) * m_22_33_23_32 + + M(1,2) * m_23_30_20_33 + + M(1,3) * m_20_32_22_30); + + value_type d02 = M(0,2)*( + M(1,0) * - m_23_31_21_33 + + M(1,1) * m_23_30_20_33 + + M(1,3) * m_20_31_21_30); + + value_type d03 = M(0,3)*( + M(1,0) * m_21_32_22_31 + + M(1,1) * - m_20_32_22_30 + + M(1,2) * m_20_31_21_30); + + return d00 - d01 + d02 - d03; + } + +}; + +/* General NxN determinant by LU factorization: */ +template +struct determinant_f +{ + typename MatT::value_type operator()(const MatT& M) const + { + /* Compute the LU factorization: */ + typename MatT::temporary_type LU = lu(M); + + /* The product of the diagonal entries is the determinant: */ + typename MatT::value_type det = LU(0,0); + for(size_t i = 1; i < LU.rows(); ++ i) + det *= LU(i,i); + return det; + } + +}; + +/* Generator for the determinant functional for fixed-size matrices: */ +template typename MatT::value_type +determinant(const MatT& M, fixed_size_tag) +{ + /* Require a square matrix: */ + cml::et::CheckedSquare(M, fixed_size_tag()); + return determinant_f()(M); +} + +/* Generator for the determinant functional for dynamic-size matrices: */ +template typename MatT::value_type +determinant(const MatT& M, dynamic_size_tag) +{ + /* Require a square matrix: */ + cml::et::CheckedSquare(M, dynamic_size_tag()); + + /* Dispatch based upon the matrix dimension: */ + switch(M.rows()) { + case 2: return determinant_f()(M); + case 3: return determinant_f()(M); + case 4: return determinant_f()(M); + default: return determinant_f()(M); // > 4x4. + } +} + +} // namespace detail + +/** Determinant of a matrix. */ +template inline E +determinant(const matrix& M) +{ + typedef typename matrix::size_tag size_tag; + return detail::determinant(M,size_tag()); +} + +/** Determinant of a matrix expression. */ +template inline typename XprT::value_type +determinant(const et::MatrixXpr& e) +{ + typedef typename et::MatrixXpr::size_tag size_tag; + return detail::determinant(e,size_tag()); +} + +} // namespace cml + +#endif + +// ------------------------------------------------------------------------- +// vim:ft=cpp diff --git a/Lib/Include/CML/matrix/dynamic.h b/Lib/Include/CML/matrix/dynamic.h new file mode 100644 index 0000000..4092bfe --- /dev/null +++ b/Lib/Include/CML/matrix/dynamic.h @@ -0,0 +1,320 @@ +/* -*- C++ -*- ------------------------------------------------------------ + +Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/ + +The Configurable Math Library (CML) is distributed under the terms of the +Boost Software License, v1.0 (see cml/LICENSE for details). + + *-----------------------------------------------------------------------*/ +/** @file + * @brief + */ + +#ifndef dynamic_matrix_h +#define dynamic_matrix_h + +#include +#include +#include +#include + +namespace cml { + +/** Resizeable, dynamic-memory matrix. */ +template +class matrix,BasisOrient,Layout> +: public dynamic_2D +{ + public: + + /* Shorthand for the generator: */ + typedef dynamic generator_type; + + /* Shorthand for the array type: */ + typedef dynamic_2D array_type; + + /* Shorthand for the type of this matrix: */ + typedef matrix matrix_type; + + /* For integration into the expression template code: */ + typedef matrix_type expr_type; + + /* For integration into the expression template code: */ + typedef matrix_type temporary_type; + + /* Standard: */ + typedef typename array_type::value_type value_type; + typedef typename array_type::reference reference; + typedef typename array_type::const_reference const_reference; + + /* For integration into the expression templates code: */ + typedef matrix_type& expr_reference; + typedef const matrix_type& expr_const_reference; + + /* For matching by basis: */ + typedef BasisOrient basis_orient; + + /* For matching by memory layout: */ + typedef typename array_type::layout layout; + + /* For matching by storage type: */ + typedef typename array_type::memory_tag memory_tag; + + /* For matching by size type if necessary: */ + typedef typename array_type::size_tag size_tag; + + /* For matching by resizability: */ + typedef typename array_type::resizing_tag resizing_tag; + + /* For matching by result type: */ + typedef cml::et::matrix_result_tag result_tag; + + /* For matching by assignability: */ + typedef cml::et::assignable_tag assignable_tag; + + /* To simplify the matrix transpose operator: */ + typedef matrix< + Element, + typename array_type::transposed_type::generator_type, + BasisOrient, + Layout + > transposed_type; + + /* To simplify the matrix row and column operators: */ + typedef vector< + Element, + typename array_type::row_array_type::generator_type + > row_vector_type; + + typedef vector< + Element, + typename array_type::col_array_type::generator_type + > col_vector_type; + + + public: + + /** Set this matrix to zero. */ + matrix_type& zero() { + typedef cml::et::OpAssign OpT; + cml::et::UnrollAssignment(*this,Element(0)); + return *this; + } + + /** Set this matrix to the identity. + * + * This only makes sense for a square matrix, but no error will be + * signaled if the matrix is not square. + */ + matrix_type& identity() { + for(size_t i = 0; i < this->rows(); ++ i) { + for(size_t j = 0; j < this->cols(); ++ j) { + (*this)(i,j) = value_type((i == j)?1:0); + } + } + return *this; + } + + /** Set this matrix to its transpose. + * + * This only makes sense for a square matrix, but no error will be + * signaled if the matrix is not square. + */ + matrix_type& transpose() { + /* transpose() returns a temporary: */ + *this = cml::transpose(*this); + return *this; + } + + /** Set this matrix to its inverse. + * + * This only makes sense for a square matrix, but no error will be + * signaled if the matrix is not square. + */ + matrix_type& inverse() { + /* inverse() returns a temporary: */ + *this = cml::inverse(*this); + return *this; + } + + /* NOTE: minimize() and maximize() no longer supported (Jesse) */ + + #if 0 + /** Pairwise minimum of this matrix with another. */ + template + void minimize(const matrix& v) { + /* XXX This should probably use ScalarPromote: */ + for (size_t i = 0; i < this->rows(); ++i) { + for (size_t j = 0; j < this->cols(); ++j) { + (*this)(i,j) = std::min((*this)(i,j),v(i,j)); + } + } + } + + /** Pairwise maximum of this matrix with another. */ + template + void maximize(const matrix& v) { + /* XXX This should probably use ScalarPromote: */ + for (size_t i = 0; i < this->rows(); ++i) { + for (size_t j = 0; j < this->cols(); ++j) { + (*this)(i,j) = std::max((*this)(i,j),v(i,j)); + } + } + } + #endif + + /* Set each element to a random number in the range [min,max] */ + void random(ELEMENT_ARG_TYPE min, ELEMENT_ARG_TYPE max) { + for(size_t i = 0; i < this->rows(); ++i) { + for(size_t j = 0; j < this->cols(); ++j) { + (*this)(i,j) = cml::random_real(min,max); + } + } + } + + + public: + + /** Default constructor. */ + matrix() {} + + /** Constructor for dynamically-sized arrays. + * + * @param rows specify the number of rows. + * @param cols specify the number of cols. + */ + explicit matrix(size_t rows, size_t cols) + : array_type(rows,cols) {} + + + public: + + /** Return the matrix size as a pair. */ + matrix_size size() const { + return matrix_size(this->rows(),this->cols()); + } + + /** Return element j of basis vector i. */ + value_type basis_element(size_t i, size_t j) const { + return basis_element(i,j,basis_orient()); + } + + /** Set the given basis element. */ + void set_basis_element(size_t i, size_t j, ELEMENT_ARG_TYPE s) { + set_basis_element(i,j,s,basis_orient()); + } + + /** Set the matrix row from the given vector. */ + void set_row(size_t i, const row_vector_type& row) { + for(size_t j = 0; j < this->cols(); ++ j) (*this)(i,j) = row[j]; + } + + /** Set the matrix column from the given vector. */ + void set_col(size_t j, const col_vector_type& col) { + for(size_t i = 0; i < this->rows(); ++ i) (*this)(i,j) = col[i]; + } + + + public: + + /* Define common class operators: */ + + CML_CONSTRUCT_MAT_22 + CML_CONSTRUCT_MAT_33 + CML_CONSTRUCT_MAT_44 + + CML_MAT_COPY_FROM_ARRAY(: array_type()) + CML_MAT_COPY_FROM_MATTYPE + CML_MAT_COPY_FROM_MAT + CML_MAT_COPY_FROM_MATXPR + + CML_ASSIGN_MAT_22 + CML_ASSIGN_MAT_33 + CML_ASSIGN_MAT_44 + + CML_MAT_ASSIGN_FROM_MATTYPE + + CML_MAT_ASSIGN_FROM_MAT(=, et::OpAssign) + CML_MAT_ASSIGN_FROM_MAT(+=, et::OpAddAssign) + CML_MAT_ASSIGN_FROM_MAT(-=, et::OpSubAssign) + + CML_MAT_ASSIGN_FROM_MATXPR(=, et::OpAssign) + CML_MAT_ASSIGN_FROM_MATXPR(+=, et::OpAddAssign) + CML_MAT_ASSIGN_FROM_MATXPR(-=, et::OpSubAssign) + + CML_MAT_ASSIGN_FROM_SCALAR(*=, et::OpMulAssign) + CML_MAT_ASSIGN_FROM_SCALAR(/=, et::OpDivAssign) + + /** Accumulated matrix multiplication. + * + * This only makes sense for a square matrix, but no error will be + * signaled if the matrix is not square. + */ + matrix_type& operator*=(const matrix_type& m) { + /* Matrix multiplication returns a temporary: */ + *this = (*this)*m; + return *this; + } + + /** Accumulated matrix multiplication. + * + * This only makes sense for a square matrix, but no error will be + * signaled if the matrix is not square. + */ + template matrix_type& + operator*=(const matrix& m) { + /* Matrix multiplication returns a temporary: */ + *this = (*this)*m; + return *this; + } + + /** Accumulated matrix multiplication. + * + * This only makes sense for a square matrix, but no error will be + * signaled if the matrix is not square. + */ + template matrix_type& + operator*=(MATXPR_ARG_TYPE e) { + /* Verify that a promotion exists at compile time: */ + typedef typename et::MatrixPromote< + matrix_type, typename XprT::result_type>::type result_type; + /* Matrix multiplication returns a temporary: */ + *this = (*this)*e; + return *this; + } + + + protected: + + value_type basis_element(size_t i, size_t j, row_basis) const { + return (*this)(i,j); + } + + value_type basis_element(size_t i, size_t j, col_basis) const { + return (*this)(j,i); + } + + void set_basis_element(size_t i, size_t j, ELEMENT_ARG_TYPE s, row_basis) { + (*this)(i,j) = s; + } + + void set_basis_element(size_t i, size_t j, ELEMENT_ARG_TYPE s, col_basis) { + (*this)(j,i) = s; + } + + + public: + + /* Braces should only be used for testing: */ +#if defined(CML_ENABLE_MATRIX_BRACES) + CML_MATRIX_BRACE_OPERATORS +#endif +}; + +} // namespace cml + +#endif + +// ------------------------------------------------------------------------- +// vim:ft=cpp diff --git a/Lib/Include/CML/matrix/external.h b/Lib/Include/CML/matrix/external.h new file mode 100644 index 0000000..6bfb8c4 --- /dev/null +++ b/Lib/Include/CML/matrix/external.h @@ -0,0 +1,543 @@ +/* -*- C++ -*- ------------------------------------------------------------ + +Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/ + +The Configurable Math Library (CML) is distributed under the terms of the +Boost Software License, v1.0 (see cml/LICENSE for details). + + *-----------------------------------------------------------------------*/ +/** @file + * @brief + */ + +#ifndef external_matrix_h +#define external_matrix_h + +#include +#include +#include +#include +#include + +namespace cml { + +/** Fixed-size, external-memory matrix. */ +template +class matrix,BasisOrient,Layout> +: public external_2D +{ + public: + + /* Shorthand for the generator: */ + typedef external generator_type; + + /* Shorthand for the array type: */ + typedef external_2D array_type; + + /* Shorthand for the type of this matrix: */ + typedef matrix matrix_type; + + /* For integration into the expression template code: */ + typedef matrix_type expr_type; + + /* For integration into the expression template code: */ + typedef matrix,BasisOrient,Layout> temporary_type; + /* Note: this ensures that an external matrix is copied into the proper + * temporary; external<> temporaries are not allowed. + */ + + /* Standard: */ + typedef typename array_type::value_type value_type; + typedef typename array_type::reference reference; + typedef typename array_type::const_reference const_reference; + + typedef matrix_type& expr_reference; + typedef const matrix_type& expr_const_reference; + + /* For matching by basis: */ + typedef BasisOrient basis_orient; + + /* For matching by memory layout: */ + typedef typename array_type::layout layout; + + /* For matching by storage type if necessary: */ + typedef typename array_type::memory_tag memory_tag; + + /* For matching by size type if necessary: */ + typedef typename array_type::size_tag size_tag; + + /* For matching by resizability: */ + typedef typename array_type::resizing_tag resizing_tag; + + /* For matching by result-type: */ + typedef cml::et::matrix_result_tag result_tag; + + /* For matching by assignability: */ + typedef cml::et::assignable_tag assignable_tag; + + /* To simplify the matrix transpose operator: */ + typedef matrix< + typename cml::remove_const::type, + typename array_type::transposed_type::generator_type, + BasisOrient, + Layout + > transposed_type; + + /* To simplify the matrix row and column operators: */ + typedef vector< + Element, + typename array_type::row_array_type::generator_type + > row_vector_type; + + typedef vector< + Element, + typename array_type::col_array_type::generator_type + > col_vector_type; + + + public: + + /** Set this matrix to zero. */ + matrix_type& zero() { + typedef cml::et::OpAssign OpT; + cml::et::UnrollAssignment(*this,Element(0)); + return *this; + } + + /** Set this matrix to the identity. + * + * This only makes sense for a square matrix, but no error will be + * signaled if the matrix is not square. + */ + matrix_type& identity() { + for(size_t i = 0; i < this->rows(); ++ i) { + for(size_t j = 0; j < this->cols(); ++ j) { + (*this)(i,j) = value_type((i == j)?1:0); + } + } + return *this; + } + + /** Set this matrix to its transpose. + * + * This only makes sense for a square matrix, but no error will be + * signaled if the matrix is not square. + */ + matrix_type& transpose() { + /* transpose() returns a temporary: */ + *this = transpose(*this); + return *this; + } + + /** Set this matrix to its inverse. + * + * This only makes sense for a square matrix, but no error will be + * signaled if the matrix is not square. + */ + matrix_type& inverse() { + /* inverse() returns a temporary: */ + *this = cml::inverse(*this); + return *this; + } + + /* NOTE: minimize() and maximize() no longer supported (Jesse) */ + + #if 0 + /** Pairwise minimum of this matrix with another. */ + template + void minimize(const matrix& v) { + /* XXX This should probably use ScalarPromote: */ + for (size_t i = 0; i < this->rows(); ++i) { + for (size_t j = 0; j < this->cols(); ++j) { + (*this)(i,j) = std::min((*this)(i,j),v(i,j)); + } + } + } + + /** Pairwise maximum of this matrix with another. */ + template + void maximize(const matrix& v) { + /* XXX This should probably use ScalarPromote: */ + for (size_t i = 0; i < this->rows(); ++i) { + for (size_t j = 0; j < this->cols(); ++j) { + (*this)(i,j) = std::max((*this)(i,j),v(i,j)); + } + } + } + #endif + + /* Set each element to a random number in the range [min,max] */ + void random(ELEMENT_ARG_TYPE min, ELEMENT_ARG_TYPE max) { + for(size_t i = 0; i < this->rows(); ++i) { + for(size_t j = 0; j < this->cols(); ++j) { + (*this)(i,j) = random_real(min,max); + } + } + } + + + public: + + /** Constructor for fixed-size external matrices. + * + * The array must be given as a pointer to Element*, not a + * multi-dimensional array. The caller owns the pointer, and is + * responsible for doing any necessary memory management. + * + * @param ptr specify the external pointer. + * + * @throws same as the ArrayType constructor. + */ + explicit matrix(value_type ptr[Rows][Cols]) : array_type(ptr) {} + + /** Constructor for fixed-size external matrices. + * + * The array must be given as a pointer to Element*, not a + * multi-dimensional array. The caller owns the pointer, and is + * responsible for doing any necessary memory management. + * + * @param ptr specify the external pointer. + * + * @throws same as the ArrayType constructor. + */ + explicit matrix(value_type* ptr) : array_type(ptr) {} + + + public: + + /** Return the matrix size as a pair. */ + matrix_size size() const { + return matrix_size(this->rows(),this->cols()); + } + + /** Return element j of basis vector i. */ + value_type basis_element(size_t i, size_t j) const { + return basis_element(i,j,basis_orient()); + } + + /** Set the given basis element. */ + void set_basis_element(size_t i, size_t j, ELEMENT_ARG_TYPE s) { + set_basis_element(i,j,s,basis_orient()); + } + + /** Set the matrix row from the given vector. */ + void set_row(size_t i, const row_vector_type& row) { + for(size_t j = 0; j < this->cols(); ++ j) (*this)(i,j) = row[j]; + } + + /** Set the matrix column from the given vector. */ + void set_col(size_t j, const col_vector_type& col) { + for(size_t i = 0; i < this->rows(); ++ i) (*this)(i,j) = col[i]; + } + + + public: + + CML_ASSIGN_MAT_22 + CML_ASSIGN_MAT_33 + CML_ASSIGN_MAT_44 + + /* Define class operators for external matrices. Note: external matrices + * cannot be copy-constructed, but they can be assigned to: + */ + CML_MAT_ASSIGN_FROM_MATTYPE + + CML_MAT_ASSIGN_FROM_MAT(=, et::OpAssign) + CML_MAT_ASSIGN_FROM_MAT(+=, et::OpAddAssign) + CML_MAT_ASSIGN_FROM_MAT(-=, et::OpSubAssign) + + CML_MAT_ASSIGN_FROM_MATXPR(=, et::OpAssign) + CML_MAT_ASSIGN_FROM_MATXPR(+=, et::OpAddAssign) + CML_MAT_ASSIGN_FROM_MATXPR(-=, et::OpSubAssign) + + CML_MAT_ASSIGN_FROM_SCALAR(*=, et::OpMulAssign) + CML_MAT_ASSIGN_FROM_SCALAR(/=, et::OpDivAssign) + + CML_ACCUMULATED_MATRIX_MULT(const matrix_type&) + + template + CML_ACCUMULATED_MATRIX_MULT(const TEMPLATED_MATRIX_MACRO&) + + template + CML_ACCUMULATED_MATRIX_MULT(MATXPR_ARG_TYPE) + + + protected: + + value_type basis_element(size_t i, size_t j, row_basis) const { + return (*this)(i,j); + } + + value_type basis_element(size_t i, size_t j, col_basis) const { + return (*this)(j,i); + } + + void set_basis_element(size_t i, size_t j, ELEMENT_ARG_TYPE s, row_basis) { + (*this)(i,j) = s; + } + + void set_basis_element(size_t i, size_t j, ELEMENT_ARG_TYPE s, col_basis) { + (*this)(j,i) = s; + } + + + public: + + /* Braces should only be used for testing: */ +#if defined(CML_ENABLE_MATRIX_BRACES) + CML_MATRIX_BRACE_OPERATORS +#endif +}; + +/** Dynamic-size, external-memory matrix. */ +template +class matrix,BasisOrient,Layout> +: public external_2D +{ + public: + + /* Shorthand for the generator: */ + typedef external<> generator_type; + + /* Shorthand for the array type: */ + typedef external_2D array_type; + + /* Shorthand for the type of this matrix: */ + typedef matrix matrix_type; + + /* For integration into the expression template code: */ + typedef matrix_type expr_type; + + /* For integration into the expression template code: */ + typedef matrix,BasisOrient,Layout> temporary_type; + /* Note: this ensures that an external matrix is copied into the proper + * temporary; external<> temporaries are not allowed. + */ + + /* Standard: */ + typedef typename array_type::value_type value_type; + typedef typename array_type::reference reference; + typedef typename array_type::const_reference const_reference; + + typedef matrix_type& expr_reference; + typedef const matrix_type& expr_const_reference; + + /* For matching by basis: */ + typedef BasisOrient basis_orient; + + /* For matching by memory layout: */ + typedef typename array_type::layout layout; + + /* For matching by storage type if necessary: */ + typedef typename array_type::memory_tag memory_tag; + + /* For matching by size type if necessary: */ + typedef typename array_type::size_tag size_tag; + + /* For matching by resizability: */ + typedef typename array_type::resizing_tag resizing_tag; + + /* For matching by result-type: */ + typedef cml::et::matrix_result_tag result_tag; + + /* For matching by assignability: */ + typedef cml::et::assignable_tag assignable_tag; + + /* To simplify the matrix transpose operator: */ + typedef matrix< + Element, + typename array_type::transposed_type::generator_type, + BasisOrient, + Layout + > transposed_type; + + /* To simplify the matrix row and column operators: */ + typedef vector< + Element, + typename array_type::row_array_type::generator_type + > row_vector_type; + + typedef vector< + Element, + typename array_type::col_array_type::generator_type + > col_vector_type; + + + public: + + /** Set this matrix to zero. */ + matrix_type& zero() { + typedef cml::et::OpAssign OpT; + cml::et::UnrollAssignment(*this,Element(0)); + return *this; + } + + /** Set this matrix to the identity. + * + * This only makes sense for a square matrix, but no error will be + * signaled if the matrix is not square. + */ + matrix_type& identity() { + for(size_t i = 0; i < this->rows(); ++ i) { + for(size_t j = 0; j < this->cols(); ++ j) { + (*this)(i,j) = value_type((i == j)?1:0); + } + } + return *this; + } + + /** Set this matrix to its transpose. + * + * This only makes sense for a square matrix, but no error will be + * signaled if the matrix is not square. + */ + matrix_type& transpose() { + /* transpose() returns a temporary: */ + *this = cml::transpose(*this); + return *this; + } + + /** Set this matrix to its inverse. + * + * This only makes sense for a square matrix, but no error will be + * signaled if the matrix is not square. + */ + matrix_type& inverse() { + /* inverse() returns a temporary: */ + *this = inverse(*this); + return *this; + } + + /** Pairwise minimum of this matrix with another. */ + template + void minimize(const matrix& v) { + /* XXX This should probably use ScalarPromote: */ + for (size_t i = 0; i < this->rows(); ++i) { + for (size_t j = 0; j < this->cols(); ++j) { + (*this)[i] = std::min((*this)(i,j),v(i,j)); + } + } + } + + /** Pairwise maximum of this matrix with another. */ + template + void maximize(const matrix& v) { + /* XXX This should probably use ScalarPromote: */ + for (size_t i = 0; i < this->rows(); ++i) { + for (size_t j = 0; j < this->cols(); ++j) { + (*this)[i] = std::max((*this)(i,j),v(i,j)); + } + } + } + + /* Set each element to a random number in the range [min,max] */ + void random(ELEMENT_ARG_TYPE min, ELEMENT_ARG_TYPE max) { + for(size_t i = 0; i < this->rows(); ++i) { + for(size_t j = 0; j < this->cols(); ++j) { + (*this)(i,j) = cml::random_real(min,max); + } + } + } + + + public: + + /** Constructor for fixed-size external matrices. + * + * The array must be given as a pointer to Element*, not a + * multi-dimensional array. The caller owns the pointer, and is + * responsible for doing any necessary memory management. + * + * @param ptr specify the external pointer. + * @param rows the number of rows in the C array. + * @param cols the number of columns in the C array. + * + * @throws same as the ArrayType constructor. + */ + explicit matrix(value_type* const ptr, size_t rows, size_t cols) + : array_type(ptr,rows,cols) {} + + + public: + + /** Return the matrix size as a pair. */ + matrix_size size() const { + return matrix_size(this->rows(),this->cols()); + } + + /** Return element j of basis vector i. */ + value_type basis_element(size_t i, size_t j) const { + return basis_element(i,j,basis_orient()); + } + + /** Set the given basis element. */ + void set_basis_element(size_t i, size_t j, ELEMENT_ARG_TYPE s) { + set_basis_element(i,j,s,basis_orient()); + } + + + public: + + CML_ASSIGN_MAT_22 + CML_ASSIGN_MAT_33 + CML_ASSIGN_MAT_44 + + /* Define class operators for external matrices. Note: external matrices + * cannot be copy-constructed, but they can be assigned to: + */ + CML_MAT_ASSIGN_FROM_MATTYPE + + CML_MAT_ASSIGN_FROM_MAT(=, et::OpAssign) + CML_MAT_ASSIGN_FROM_MAT(+=, et::OpAddAssign) + CML_MAT_ASSIGN_FROM_MAT(-=, et::OpSubAssign) + + CML_MAT_ASSIGN_FROM_MATXPR(=, et::OpAssign) + CML_MAT_ASSIGN_FROM_MATXPR(+=, et::OpAddAssign) + CML_MAT_ASSIGN_FROM_MATXPR(-=, et::OpSubAssign) + + CML_MAT_ASSIGN_FROM_SCALAR(*=, et::OpMulAssign) + CML_MAT_ASSIGN_FROM_SCALAR(/=, et::OpDivAssign) + + CML_ACCUMULATED_MATRIX_MULT(const matrix_type&) + + template + CML_ACCUMULATED_MATRIX_MULT(const TEMPLATED_MATRIX_MACRO&) + + template + CML_ACCUMULATED_MATRIX_MULT(MATXPR_ARG_TYPE) + + + protected: + + value_type basis_element(size_t i, size_t j, row_basis) const { + return (*this)(i,j); + } + + value_type basis_element(size_t i, size_t j, col_basis) const { + return (*this)(j,i); + } + + void set_basis_element(size_t i, size_t j, ELEMENT_ARG_TYPE s, row_basis) { + (*this)(i,j) = s; + } + + void set_basis_element(size_t i, size_t j, ELEMENT_ARG_TYPE s, col_basis) { + (*this)(j,i) = s; + } + + + public: + + /* Braces should only be used for testing: */ +#if defined(CML_ENABLE_MATRIX_BRACES) + CML_MATRIX_BRACE_OPERATORS +#endif +}; + +} // namespace cml + +#endif + +// ------------------------------------------------------------------------- +// vim:ft=cpp diff --git a/Lib/Include/CML/matrix/fixed.h b/Lib/Include/CML/matrix/fixed.h new file mode 100644 index 0000000..1a64938 --- /dev/null +++ b/Lib/Include/CML/matrix/fixed.h @@ -0,0 +1,284 @@ +/* -*- C++ -*- ------------------------------------------------------------ + +Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/ + +The Configurable Math Library (CML) is distributed under the terms of the +Boost Software License, v1.0 (see cml/LICENSE for details). + + *-----------------------------------------------------------------------*/ +/** @file + * @brief + */ + +#ifndef fixed_matrix_h +#define fixed_matrix_h + +#include +#include +#include +#include + +namespace cml { + +/** Fixed-size, fixed-memory matrix. */ +template +class matrix,BasisOrient,Layout> +: public fixed_2D +{ + public: + + /* Shorthand for the generator: */ + typedef fixed generator_type; + + /* Shorthand for the array type: */ + typedef fixed_2D array_type; + + /* Shorthand for the type of this matrix: */ + typedef matrix matrix_type; + + /* For integration into the expression template code: */ + typedef matrix_type expr_type; + + /* For integration into the expression template code: */ + typedef matrix_type temporary_type; + + /* Standard: */ + typedef typename array_type::value_type value_type; + typedef typename array_type::reference reference; + typedef typename array_type::const_reference const_reference; + + typedef matrix_type& expr_reference; + typedef const matrix_type& expr_const_reference; + + /* For matching by basis: */ + typedef BasisOrient basis_orient; + + /* For matching by memory layout: */ + typedef typename array_type::layout layout; + + /* For matching by storage type if necessary: */ + typedef typename array_type::memory_tag memory_tag; + + /* For matching by size type if necessary: */ + typedef typename array_type::size_tag size_tag; + + /* For matching by result type: */ + typedef cml::et::matrix_result_tag result_tag; + + /* For matching by assignability: */ + typedef cml::et::assignable_tag assignable_tag; + + /* To simplify the matrix transpose operator: */ + typedef matrix< + typename cml::remove_const::type, + typename array_type::transposed_type::generator_type, + BasisOrient, Layout + > transposed_type; + + /* To simplify the matrix row and column operators: */ + typedef vector< + Element, + typename array_type::row_array_type::generator_type + > row_vector_type; + + typedef vector< + Element, + typename array_type::col_array_type::generator_type + > col_vector_type; + + + public: + + /** Set this matrix to zero. */ + matrix_type& zero() { + typedef cml::et::OpAssign OpT; + cml::et::UnrollAssignment(*this,Element(0)); + return *this; + } + + /** Set this matrix to the identity. + * + * This only makes sense for a square matrix, but no error will be + * signaled if the matrix is not square. + */ + matrix_type& identity() { + for(size_t i = 0; i < this->rows(); ++ i) { + for(size_t j = 0; j < this->cols(); ++ j) { + (*this)(i,j) = value_type((i == j)?1:0); + } + } + return *this; + } + + /** Set this matrix to its transpose. + * + * This only makes sense for a square matrix, but no error will be + * signaled if the matrix is not square. + */ + matrix_type& transpose() { + /* transpose() returns a temporary: */ + *this = cml::transpose(*this); + return *this; + } + + /** Set this matrix to its inverse. + * + * This only makes sense for a square matrix, but no error will be + * signaled if the matrix is not square. + */ + matrix_type& inverse() { + /* inverse() returns a temporary: */ + *this = cml::inverse(*this); + return *this; + } + + /* NOTE: minimize() and maximize() no longer supported (Jesse) */ + + #if 0 + /** Pairwise minimum of this matrix with another. */ + template + void minimize(const matrix& v) { + /* XXX This should probably use ScalarPromote: */ + for (size_t i = 0; i < this->rows(); ++i) { + for (size_t j = 0; j < this->cols(); ++j) { + (*this)(i,j) = std::min((*this)(i,j),v(i,j)); + } + } + } + + /** Pairwise maximum of this matrix with another. */ + template + void maximize(const matrix& v) { + /* XXX This should probably use ScalarPromote: */ + for (size_t i = 0; i < this->rows(); ++i) { + for (size_t j = 0; j < this->cols(); ++j) { + (*this)(i,j) = std::max((*this)(i,j),v(i,j)); + } + } + } + #endif + + /* Set each element to a random number in the range [min,max] */ + void random(ELEMENT_ARG_TYPE min, ELEMENT_ARG_TYPE max) { + for(size_t i = 0; i < this->rows(); ++i) { + for(size_t j = 0; j < this->cols(); ++j) { + (*this)(i,j) = cml::random_real(min,max); + } + } + } + + + public: + + /** Default constructor. + * + * @throws same as the ArrayType constructor. + * @sa cml::fixed + * @sa cml::dynamic + */ + matrix() {} + + + public: + + /** Return the matrix size as a pair. */ + matrix_size size() const { + return matrix_size(this->rows(),this->cols()); + } + + /** Return element j of basis vector i. */ + value_type basis_element(size_t i, size_t j) const { + return basis_element(i,j,basis_orient()); + } + + /** Set the given basis element. */ + void set_basis_element(size_t i, size_t j, ELEMENT_ARG_TYPE s) { + set_basis_element(i,j,s,basis_orient()); + } + + /** Set the matrix row from the given vector. */ + void set_row(size_t i, const row_vector_type& row) { + for(size_t j = 0; j < this->cols(); ++ j) (*this)(i,j) = row[j]; + } + + /** Set the matrix column from the given vector. */ + void set_col(size_t j, const col_vector_type& col) { + for(size_t i = 0; i < this->rows(); ++ i) (*this)(i,j) = col[i]; + } + + + public: + + /* Define common class operators: */ + + CML_CONSTRUCT_MAT_22 + CML_CONSTRUCT_MAT_33 + CML_CONSTRUCT_MAT_44 + + CML_MAT_COPY_FROM_FIXED_ARRAY( + array_type::array_rows, array_type::array_cols) + + CML_MAT_COPY_FROM_MATTYPE + CML_MAT_COPY_FROM_MAT + CML_MAT_COPY_FROM_MATXPR + + CML_ASSIGN_MAT_22 + CML_ASSIGN_MAT_33 + CML_ASSIGN_MAT_44 + + CML_MAT_ASSIGN_FROM_MATTYPE + + CML_MAT_ASSIGN_FROM_MAT(=, et::OpAssign) + CML_MAT_ASSIGN_FROM_MAT(+=, et::OpAddAssign) + CML_MAT_ASSIGN_FROM_MAT(-=, et::OpSubAssign) + + CML_MAT_ASSIGN_FROM_MATXPR(=, et::OpAssign) + CML_MAT_ASSIGN_FROM_MATXPR(+=, et::OpAddAssign) + CML_MAT_ASSIGN_FROM_MATXPR(-=, et::OpSubAssign) + + CML_MAT_ASSIGN_FROM_SCALAR(*=, et::OpMulAssign) + CML_MAT_ASSIGN_FROM_SCALAR(/=, et::OpDivAssign) + + CML_ACCUMULATED_MATRIX_MULT(const matrix_type&) + + template + CML_ACCUMULATED_MATRIX_MULT(const TEMPLATED_MATRIX_MACRO&) + + template + CML_ACCUMULATED_MATRIX_MULT(MATXPR_ARG_TYPE) + + + protected: + + value_type basis_element(size_t i, size_t j, row_basis) const { + return (*this)(i,j); + } + + value_type basis_element(size_t i, size_t j, col_basis) const { + return (*this)(j,i); + } + + void set_basis_element(size_t i, size_t j, ELEMENT_ARG_TYPE s, row_basis) { + (*this)(i,j) = s; + } + + void set_basis_element(size_t i, size_t j, ELEMENT_ARG_TYPE s, col_basis) { + (*this)(j,i) = s; + } + + + public: + + /* Braces should only be used for testing: */ +#if defined(CML_ENABLE_MATRIX_BRACES) + CML_MATRIX_BRACE_OPERATORS +#endif +}; + +} // namespace cml + +#endif + +// ------------------------------------------------------------------------- +// vim:ft=cpp diff --git a/Lib/Include/CML/matrix/inverse.h b/Lib/Include/CML/matrix/inverse.h new file mode 100644 index 0000000..359a42c --- /dev/null +++ b/Lib/Include/CML/matrix/inverse.h @@ -0,0 +1,444 @@ +/* -*- C++ -*- ------------------------------------------------------------ + +Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/ + +The Configurable Math Library (CML) is distributed under the terms of the +Boost Software License, v1.0 (see cml/LICENSE for details). + + *-----------------------------------------------------------------------*/ +/** @file + * @brief Compute the inverse of a matrix by LU factorization. + */ + +#ifndef matrix_inverse_h +#define matrix_inverse_h + +#include +#include + +namespace cml { +namespace detail { + +/* Need to use a functional, since template functions cannot be + * specialized. _tag is used to specialize based upon dimension: + */ +template struct inverse_f; + +/* @todo: Reciprocal optimization for division by determinant. + */ + +/* 2x2 inverse. Despite being marked for fixed_size matrices, this can + * be used for dynamic-sized ones also: + */ +template +struct inverse_f +{ + typename MatT::temporary_type operator()(const MatT& M) const + { + typedef typename MatT::temporary_type temporary_type; + typedef typename temporary_type::value_type value_type; + + /* Matrix containing the inverse: */ + temporary_type Z; + cml::et::detail::Resize(Z,2,2); + + /* Compute determinant and inverse: */ + value_type D = value_type(1) / (M(0,0)*M(1,1) - M(0,1)*M(1,0)); + Z(0,0) = M(1,1)*D; Z(0,1) = - M(0,1)*D; + Z(1,0) = - M(1,0)*D; Z(1,1) = M(0,0)*D; + + return Z; + } +}; + +/* 3x3 inverse. Despite being marked for fixed_size matrices, this can + * be used for dynamic-sized ones also: + */ +template +struct inverse_f +{ + /* [00 01 02] + * M = [10 11 12] + * [20 21 22] + */ + typename MatT::temporary_type operator()(const MatT& M) const + { + /* Shorthand. */ + typedef typename MatT::value_type value_type; + + /* Compute cofactors for each entry: */ + value_type m_00 = M(1,1)*M(2,2) - M(1,2)*M(2,1); + value_type m_01 = M(1,2)*M(2,0) - M(1,0)*M(2,2); + value_type m_02 = M(1,0)*M(2,1) - M(1,1)*M(2,0); + + value_type m_10 = M(0,2)*M(2,1) - M(0,1)*M(2,2); + value_type m_11 = M(0,0)*M(2,2) - M(0,2)*M(2,0); + value_type m_12 = M(0,1)*M(2,0) - M(0,0)*M(2,1); + + value_type m_20 = M(0,1)*M(1,2) - M(0,2)*M(1,1); + value_type m_21 = M(0,2)*M(1,0) - M(0,0)*M(1,2); + value_type m_22 = M(0,0)*M(1,1) - M(0,1)*M(1,0); + + /* Compute determinant from the minors: */ + value_type D = + value_type(1) / (M(0,0)*m_00 + M(0,1)*m_01 + M(0,2)*m_02); + + /* Matrix containing the inverse: */ + typename MatT::temporary_type Z; + cml::et::detail::Resize(Z,3,3); + + /* Assign the inverse as (1/D) * (cofactor matrix)^T: */ + Z(0,0) = m_00*D; Z(0,1) = m_10*D; Z(0,2) = m_20*D; + Z(1,0) = m_01*D; Z(1,1) = m_11*D; Z(1,2) = m_21*D; + Z(2,0) = m_02*D; Z(2,1) = m_12*D; Z(2,2) = m_22*D; + + return Z; + } +}; + +/* 4x4 inverse. Despite being marked for fixed_size matrices, this can + * be used for dynamic-sized ones also: + */ +template +struct inverse_f +{ + /* [00 01 02 03] + * M = [10 11 12 13] + * [20 21 22 23] + * [30 31 32 33] + * + * |11 12 13| |10 12 13| + * C00 = |21 22 23| C01 = |20 22 23| + * |31 32 33| |30 32 33| + * + * |10 11 13| |10 11 12| + * C02 = |20 21 23| C03 = |20 21 22| + * |30 31 33| |30 31 32| + */ + typename MatT::temporary_type operator()(const MatT& M) const + { + /* Shorthand. */ + typedef typename MatT::value_type value_type; + + /* Common cofactors, rows 0,1: */ + value_type m_22_33_23_32 = M(2,2)*M(3,3) - M(2,3)*M(3,2); + value_type m_23_30_20_33 = M(2,3)*M(3,0) - M(2,0)*M(3,3); + value_type m_20_31_21_30 = M(2,0)*M(3,1) - M(2,1)*M(3,0); + value_type m_21_32_22_31 = M(2,1)*M(3,2) - M(2,2)*M(3,1); + value_type m_23_31_21_33 = M(2,3)*M(3,1) - M(2,1)*M(3,3); + value_type m_20_32_22_30 = M(2,0)*M(3,2) - M(2,2)*M(3,0); + + /* Compute minors: */ + value_type d00 + = M(1,1)*m_22_33_23_32+M(1,2)*m_23_31_21_33+M(1,3)*m_21_32_22_31; + + value_type d01 + = M(1,0)*m_22_33_23_32+M(1,2)*m_23_30_20_33+M(1,3)*m_20_32_22_30; + + value_type d02 + = M(1,0)*-m_23_31_21_33+M(1,1)*m_23_30_20_33+M(1,3)*m_20_31_21_30; + + value_type d03 + = M(1,0)*m_21_32_22_31+M(1,1)*-m_20_32_22_30+M(1,2)*m_20_31_21_30; + + /* Compute minors: */ + value_type d10 + = M(0,1)*m_22_33_23_32+M(0,2)*m_23_31_21_33+M(0,3)*m_21_32_22_31; + + value_type d11 + = M(0,0)*m_22_33_23_32+M(0,2)*m_23_30_20_33+M(0,3)*m_20_32_22_30; + + value_type d12 + = M(0,0)*-m_23_31_21_33+M(0,1)*m_23_30_20_33+M(0,3)*m_20_31_21_30; + + value_type d13 + = M(0,0)*m_21_32_22_31+M(0,1)*-m_20_32_22_30+M(0,2)*m_20_31_21_30; + + /* Common cofactors, rows 2,3: */ + value_type m_02_13_03_12 = M(0,2)*M(1,3) - M(0,3)*M(1,2); + value_type m_03_10_00_13 = M(0,3)*M(1,0) - M(0,0)*M(1,3); + value_type m_00_11_01_10 = M(0,0)*M(1,1) - M(0,1)*M(1,0); + value_type m_01_12_02_11 = M(0,1)*M(1,2) - M(0,2)*M(1,1); + value_type m_03_11_01_13 = M(0,3)*M(1,1) - M(0,1)*M(1,3); + value_type m_00_12_02_10 = M(0,0)*M(1,2) - M(0,2)*M(1,0); + + /* Compute minors (uses row 3 as the multipliers instead of row 0, + * which uses the same signs as row 0): + */ + value_type d20 + = M(3,1)*m_02_13_03_12+M(3,2)*m_03_11_01_13+M(3,3)*m_01_12_02_11; + + value_type d21 + = M(3,0)*m_02_13_03_12+M(3,2)*m_03_10_00_13+M(3,3)*m_00_12_02_10; + + value_type d22 + = M(3,0)*-m_03_11_01_13+M(3,1)*m_03_10_00_13+M(3,3)*m_00_11_01_10; + + value_type d23 + = M(3,0)*m_01_12_02_11+M(3,1)*-m_00_12_02_10+M(3,2)*m_00_11_01_10; + + /* Compute minors: */ + value_type d30 + = M(2,1)*m_02_13_03_12+M(2,2)*m_03_11_01_13+M(2,3)*m_01_12_02_11; + + value_type d31 + = M(2,0)*m_02_13_03_12+M(2,2)*m_03_10_00_13+M(2,3)*m_00_12_02_10; + + value_type d32 + = M(2,0)*-m_03_11_01_13+M(2,1)*m_03_10_00_13+M(2,3)*m_00_11_01_10; + + value_type d33 + = M(2,0)*m_01_12_02_11+M(2,1)*-m_00_12_02_10+M(2,2)*m_00_11_01_10; + + /* Finally, compute determinant from the minors, and assign the + * inverse as (1/D) * (cofactor matrix)^T: + */ + typename MatT::temporary_type Z; + cml::et::detail::Resize(Z,4,4); + + value_type D = value_type(1) / + (M(0,0)*d00 - M(0,1)*d01 + M(0,2)*d02 - M(0,3)*d03); + Z(0,0) = +d00*D; Z(0,1) = -d10*D; Z(0,2) = +d20*D; Z(0,3) = -d30*D; + Z(1,0) = -d01*D; Z(1,1) = +d11*D; Z(1,2) = -d21*D; Z(1,3) = +d31*D; + Z(2,0) = +d02*D; Z(2,1) = -d12*D; Z(2,2) = +d22*D; Z(2,3) = -d32*D; + Z(3,0) = -d03*D; Z(3,1) = +d13*D; Z(3,2) = -d23*D; Z(3,3) = +d33*D; + + return Z; + } +}; + +/* If more extensive general linear algebra functionality is offered in + * future versions it may be useful to make the elementary row and column + * operations separate functions. For now they're simply performed in place, + * but the commented-out lines of code show where the calls to these functions + * should go if and when they become available. + */ + +/* @todo: In-place version, and address memory allocation for pivot vector. + */ + +/* General NxN inverse by Gauss-Jordan elimination with full pivoting: */ +template +struct inverse_f +{ + typename MatT::temporary_type operator()(const MatT& M) const + { + /* Shorthand. */ + typedef typename MatT::value_type value_type; + + /* Size of matrix */ + size_t N = M.rows(); + + /* Matrix containing the inverse: */ + typename MatT::temporary_type Z; + cml::et::detail::Resize(Z,N,N); + Z = M; + + /* For tracking pivots */ + std::vector row_index(N); + std::vector col_index(N); + std::vector pivoted(N,0); + + /* For each column */ + for (size_t i = 0; i < N; ++i) { + + /* Find the pivot */ + size_t row = 0, col = 0; + value_type max = value_type(0); + for (size_t j = 0; j < N; ++j) { + if (!pivoted[j]) { + for (size_t k = 0; k < N; ++k) { + if (!pivoted[k]) { + value_type mag = std::fabs(Z(j,k)); + if (mag > max) { + max = mag; + row = j; + col = k; + } + } + } + } + } + + /* TODO: Check max against epsilon here to catch singularity */ + + row_index[i] = row; + col_index[i] = col; + + /* Swap rows if necessary */ + if (row != col) { + /*Z.row_op_swap(row,col);*/ + for (size_t j = 0; j < Z.cols(); ++j) { + std::swap(Z(row,j),Z(col,j)); + } + } + + /* Process pivot row */ + pivoted[col] = true; + value_type pivot = Z(col,col); + Z(col,col) = value_type(1); + /*Z.row_op_mult(col,value_type(1)/pivot);*/ + value_type k = value_type(1)/pivot; + for (size_t j = 0; j < Z.cols(); ++j) { + Z(col,j) *= k; + } + + /* Process other rows */ + for (size_t j = 0; j < N; ++j) { + if (j != col) { + value_type mult = -Z(j,col); + Z(j,col) = value_type(0); + /*Z.row_op_add_mult(col,j,mult);*/ + for (size_t k = 0; k < Z.cols(); ++k) { + Z(j,k) += mult * Z(col,k); + } + } + } + } + + /* Swap columns if necessary */ + for (int i = N-1; i >= 0; --i) { + if (row_index[i] != col_index[i]) { + /*Z.col_op_swap(row_index[i],col_index[i]);*/ + for (size_t j = 0; j < Z.rows(); ++j) { + std::swap(Z(j,row_index[i]),Z(j,col_index[i])); + } + } + } + + /* Return result */ + return Z; + } +}; + +/* Inversion by LU factorization is turned off for now due to lack of + * pivoting in the implementation, but we may switch back to it at some future + * time. + */ + +#if 0 + +/* General NxN inverse by LU factorization: */ +template +struct inverse_f +{ + typename MatT::temporary_type operator()(const MatT& M) const + { + /* Shorthand. */ + typedef typename MatT::value_type value_type; + + /* Compute LU factorization: */ + size_t N = M.rows(); + typename MatT::temporary_type LU; + cml::et::detail::Resize(LU,N,N); + LU = lu(M); + + /* Matrix containing the inverse: */ + typename MatT::temporary_type Z; + cml::et::detail::Resize(Z,N,N); + + typename MatT::col_vector_type v, x; + cml::et::detail::Resize(v,N); + cml::et::detail::Resize(x,N); + for(size_t i = 0; i < N; ++i) + v[i] = value_type(0); + /* XXX Need a fill() function here. */ + + /* Use lu_solve to solve M*x = v for x, where v = [0 ... 1 ... 0]^T: */ + for(size_t i = 0; i < N; ++i) { + v[i] = 1.; + x = lu_solve(LU,v); + + /* x is column i of the inverse of LU: */ + for(size_t k = 0; k < N; ++ k) { + Z(k,i) = x[k]; + } + v[i] = 0.; + } + + return Z; + } + +}; + +#endif + +/* Note: force_NxN is for checking general NxN inversion against the special- + * case 2x2, 3x3 and 4x4 code. I'm leaving it in for now since we may need to + * test the NxN code further if the implementation changes. At some future + * time when the implementation is stable, everything related to force_NxN can + * be taken out. + */ + +/* Note: Commenting the force_NxN stuff out, but leaving the code here in + * case we need to do more testing in the future. + */ + +/* Generator for the inverse functional for fixed-size matrices: */ +template typename MatT::temporary_type +inverse(const MatT& M, fixed_size_tag/*, bool force_NxN*/) +{ + /* Require a square matrix: */ + cml::et::CheckedSquare(M, fixed_size_tag()); + + /* + if (force_NxN) { + return inverse_f()(M); + } else { + */ + return inverse_f()(M); + /* + } + */ +} + +/* Generator for the inverse functional for dynamic-size matrices: */ +template typename MatT::temporary_type +inverse(const MatT& M, dynamic_size_tag/*, bool force_NxN*/) +{ + /* Require a square matrix: */ + cml::et::CheckedSquare(M, dynamic_size_tag()); + + /* + if (force_NxN) { + return inverse_f()(M); + } else { + */ + /* Dispatch based upon the matrix dimension: */ + switch(M.rows()) { + case 2: return inverse_f()(M); // 2x2 + case 3: return inverse_f()(M); // 3x3 + case 4: return inverse_f()(M); // 4x4 + default: return inverse_f()(M); // > 4x4 (or 1x1) + } + /* + } + */ +} + +} // namespace detail + +/** Inverse of a matrix. */ +template inline +typename matrix::temporary_type +inverse(const matrix& M/*, bool force_NxN = false*/) +{ + typedef typename matrix::size_tag size_tag; + return detail::inverse(M,size_tag()/*,force_NxN*/); +} + +/** Inverse of a matrix expression. */ +template inline +typename et::MatrixXpr::temporary_type +inverse(const et::MatrixXpr& e/*, bool force_NxN = false*/) +{ + typedef typename et::MatrixXpr::size_tag size_tag; + return detail::inverse(e,size_tag()/*,force_NxN*/); +} + +} // namespace cml + +#endif + +// ------------------------------------------------------------------------- +// vim:ft=cpp diff --git a/Lib/Include/CML/matrix/lu.h b/Lib/Include/CML/matrix/lu.h new file mode 100644 index 0000000..06e2835 --- /dev/null +++ b/Lib/Include/CML/matrix/lu.h @@ -0,0 +1,176 @@ +/* -*- C++ -*- ------------------------------------------------------------ + +Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/ + +The Configurable Math Library (CML) is distributed under the terms of the +Boost Software License, v1.0 (see cml/LICENSE for details). + + *-----------------------------------------------------------------------*/ +/** @file + * @brief Implements LU decomposition for square matrix expressions. + * + * @todo The LU implementation does not check for a zero diagonal entry + * (implying that the input has no LU factorization). + * + * @todo Should also have a pivoting implementation. + * + * @todo need to throw a numeric error if the determinant of the matrix + * given to lu(), lu_solve(), or inverse() is 0. + * + * @internal The implementation is the same for fixed- and dynamic-size + * matrices. It can be sped up for small matrices later. + */ + +#ifndef lu_h +#define lu_h + +#include +#include +#include + +/* This is used below to create a more meaningful compile-time error when + * lu is not provided with a matrix or MatrixExpr argument: + */ +struct lu_expects_a_matrix_arg_error; + +/* This is used below to create a more meaningful compile-time error when + * lu_inplace is not provided with an assignable matrix argument: + */ +struct lu_inplace_expects_an_assignable_matrix_arg_error; + +namespace cml { +namespace detail { + +/* Compute the LU decomposition in-place: */ +template inline +void lu_inplace(MatT& A) +{ + /* Shorthand: */ + typedef et::ExprTraits arg_traits; + typedef typename arg_traits::result_tag arg_result; + typedef typename arg_traits::assignable_tag arg_assignment; + typedef typename arg_traits::size_tag size_tag; + typedef typename arg_traits::value_type value_type; + + /* lu_inplace() requires an assignable matrix expression: */ + CML_STATIC_REQUIRE_M( + (same_type::is_true + && same_type::is_true), + lu_inplace_expects_an_assignable_matrix_arg_error); + /* Note: parens are required here so that the preprocessor ignores the + * commas. + */ + + /* Verify that the matrix is square, and get the size: */ + ssize_t N = (ssize_t) cml::et::CheckedSquare(A, size_tag()); + + + for(ssize_t k = 0; k < N-1; ++k) { + /* XXX Should check if A(k,k) = 0! */ + for(ssize_t i = k+1; i < N; ++i) { + value_type n = (A(i,k) /= A(k,k)); + for(ssize_t j = k+1; j < N; ++ j) { + A(i,j) -= n*A(k,j); + } + } + } +} + +/* Compute the LU decomposition, and return a copy of the result: */ +template +inline typename MatT::temporary_type +lu_copy(const MatT& M) +{ + /* Shorthand: */ + typedef et::ExprTraits arg_traits; + typedef typename arg_traits::result_tag arg_result; + + /* lu_with_copy() requires a matrix expression: */ + CML_STATIC_REQUIRE_M( + (same_type::is_true), + lu_expects_a_matrix_arg_error); + /* Note: parens are required here so that the preprocessor ignores the + * commas. + */ + + /* Use the in-place LU function, and return the result: */ + typename MatT::temporary_type A; + cml::et::detail::Resize(A,M.rows(),M.cols()); + A = M; + lu_inplace(A); + return A; +} + +} // namespace detail + +/** LU factorization for a matrix. */ +template +inline typename matrix::temporary_type +lu(const matrix& m) +{ + return detail::lu_copy(m); +} + +/** LU factorization for a matrix expression. */ +template +inline typename et::MatrixXpr::temporary_type +lu(const et::MatrixXpr& e) +{ + return detail::lu_copy(e); +} + +/** Solve y = LUx for x. + * + * This solves Lb = y for b by forward substitution, then Ux = b for x by + * backward substitution. + */ +template inline +typename et::MatVecPromote::temporary_type +lu_solve(const MatT& LU, const VecT& b) +{ + /* Shorthand. */ + typedef et::ExprTraits lu_traits; + typedef typename et::MatVecPromote::temporary_type vector_type; + typedef typename vector_type::value_type value_type; + + /* Verify that the matrix is square, and get the size: */ + ssize_t N = (ssize_t) cml::et::CheckedSquare( + LU, typename lu_traits::size_tag()); + + /* Verify that the matrix and vector have compatible sizes: */ + et::CheckedSize(LU, b, typename vector_type::size_tag()); + + /* Solve Ly = b for y by forward substitution. The entries below the + * diagonal of LU correspond to L, understood to be below a diagonal of + * 1's: + */ + vector_type y; cml::et::detail::Resize(y,N); + for(ssize_t i = 0; i < N; ++i) { + y[i] = b[i]; + for(ssize_t j = 0; j < i; ++j) { + y[i] -= LU(i,j)*y[j]; + } + } + + /* Solve Ux = y for x by backward substitution. The entries at and above + * the diagonal of LU correspond to U: + */ + vector_type x; cml::et::detail::Resize(x,N); + for(ssize_t i = N-1; i >= 0; --i) { + x[i] = y[i]; + for(ssize_t j = i+1; j < N; ++j) { + x[i] -= LU(i,j)*x[j]; + } + x[i] /= LU(i,i); + } + + /* Return x: */ + return x; +} + +} // namespace cml + +#endif + +// ------------------------------------------------------------------------- +// vim:ft=cpp diff --git a/Lib/Include/CML/matrix/matop_macros.h b/Lib/Include/CML/matrix/matop_macros.h new file mode 100644 index 0000000..f13b678 --- /dev/null +++ b/Lib/Include/CML/matrix/matop_macros.h @@ -0,0 +1,236 @@ +/* -*- C++ -*- ------------------------------------------------------------ + +Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/ + +The Configurable Math Library (CML) is distributed under the terms of the +Boost Software License, v1.0 (see cml/LICENSE for details). + + *-----------------------------------------------------------------------*/ +/** @file + * @brief Defines the various combinations of matrix expressions. + * + * Create unary and binary operators with macros. The available combinations + * are: + * + * Unary expressions: + * + * op Matrix -> Matrix + * op MatXpr -> Matrix + * + * Binary expressions: + * + * Matrix op Matrix -> Matrix + * MatXpr op Matrix -> MatXpr + * Matrix op MatXpr -> MatXpr + * MatXpr op MatXpr -> MatXpr + * + * Matrix op Scalar -> Matrix + * Scalar op Matrix -> Matrix + * MatXpr op Scalar -> MatXpr + * Scalar op MatXpr -> MatXpr + * + * All of the generator functions compress the expression tree by hoisting + * subexpressions into the containing expression. This has the effect of + * forcing only the root node of the expression tree to be a MatrixXpr. + * Every other node is a Unary or BinaryMatrixOp. + */ +#ifndef matop_macros_h +#define matop_macros_h + +/** Declare a unary operator taking a matrix operand. */ +#define CML_MAT_UNIOP(_op_, _OpT_) \ +template \ +inline et::MatrixXpr< \ + et::UnaryMatrixOp< matrix, _OpT_ > \ +> \ + \ +_op_ (const matrix& arg) \ +{ \ + typedef et::UnaryMatrixOp< \ + matrix, _OpT_ \ + > ExprT; \ + return et::MatrixXpr(ExprT(arg)); \ +} + +/** Declare a unary operator taking a et::MatrixXpr operand. */ +#define CML_MATXPR_UNIOP(_op_, _OpT_) \ +template \ +inline et::MatrixXpr< \ + et::UnaryMatrixOp > \ +> \ + \ +_op_ (MATXPR_ARG_TYPE arg) \ +{ \ + typedef et::UnaryMatrixOp< \ + XprT, _OpT_ \ + > ExprT; \ + return et::MatrixXpr(ExprT(arg.expression())); \ +} + +/** Declare an operator taking two matrix operands. */ +#define CML_MAT_MAT_BINOP(_op_, _OpT_) \ +template \ +inline et::MatrixXpr< \ + et::BinaryMatrixOp< \ + matrix, matrix, _OpT_ > \ +> \ + \ +_op_ ( \ + const matrix& left, \ + const matrix& right) \ +{ \ + typedef et::BinaryMatrixOp< \ + matrix, matrix, _OpT_ \ + > ExprT; \ + return et::MatrixXpr(ExprT(left,right)); \ +} + +/** Declare an operator taking a matrix and a et::MatrixXpr. */ +#define CML_MAT_MATXPR_BINOP(_op_, _OpT_) \ +template \ +inline et::MatrixXpr< \ + et::BinaryMatrixOp< \ + matrix, XprT, _OpT_ \ + > \ +> \ + \ +_op_ ( \ + const matrix& left, \ + MATXPR_ARG_TYPE right) \ +{ \ + typedef et::BinaryMatrixOp< \ + matrix, XprT, \ + _OpT_ \ + > ExprT; \ + return et::MatrixXpr(ExprT(left,right.expression())); \ +} + +/** Declare an operator taking a et::MatrixXpr and a matrix. */ +#define CML_MATXPR_MAT_BINOP(_op_, _OpT_) \ +template \ +inline et::MatrixXpr< \ + et::BinaryMatrixOp< \ + XprT, matrix, _OpT_ \ + > \ +> \ + \ +_op_ ( \ + MATXPR_ARG_TYPE left, \ + const matrix& right) \ +{ \ + typedef et::BinaryMatrixOp< \ + XprT, matrix, \ + _OpT_ \ + > ExprT; \ + return et::MatrixXpr(ExprT(left.expression(),right)); \ +} + +/** Declare an operator taking two et::MatrixXpr operands. */ +#define CML_MATXPR_MATXPR_BINOP(_op_, _OpT_) \ +template \ +inline et::MatrixXpr< \ + et::BinaryMatrixOp< \ + XprT1, XprT2, \ + _OpT_ < \ + typename XprT1::value_type, \ + typename XprT2::value_type \ + > \ + > \ +> \ + \ +_op_ ( \ + MATXPR_ARG_TYPE_N(1) left, \ + MATXPR_ARG_TYPE_N(2) right) \ +{ \ + typedef et::BinaryMatrixOp< \ + XprT1, XprT2, \ + _OpT_ < \ + typename XprT1::value_type, \ + typename XprT2::value_type> \ + > ExprT; \ + return et::MatrixXpr( \ + ExprT(left.expression(),right.expression())); \ +} + + +/** Declare an operator taking a matrix and a scalar. */ +#define CML_MAT_SCALAR_BINOP(_op_, _OpT_) \ +template\ +inline et::MatrixXpr< \ + et::BinaryMatrixOp< \ + matrix, ScalarT, _OpT_ \ + > \ +> \ + \ +_op_ ( \ + const matrix& left, \ + SCALAR_ARG_TYPE right) \ +{ \ + typedef et::BinaryMatrixOp< \ + matrix, ScalarT, _OpT_ \ + > ExprT; \ + return et::MatrixXpr(ExprT(left,right)); \ +} + +/** Declare an operator taking a scalar and a matrix. */ +#define CML_SCALAR_MAT_BINOP(_op_, _OpT_) \ +template\ +inline et::MatrixXpr< \ + et::BinaryMatrixOp< \ + ScalarT, matrix, _OpT_ \ + > \ +> \ + \ +_op_ ( \ + SCALAR_ARG_TYPE left, \ + const matrix& right) \ +{ \ + typedef et::BinaryMatrixOp< \ + ScalarT, matrix, _OpT_ \ + > ExprT; \ + return et::MatrixXpr(ExprT(left,right)); \ +} + +/** Declare an operator taking a et::MatrixXpr and a scalar. */ +#define CML_MATXPR_SCALAR_BINOP(_op_, _OpT_) \ +template \ +inline et::MatrixXpr< \ + et::BinaryMatrixOp< \ + XprT, ScalarT, _OpT_ \ + > \ +> \ + \ +_op_ ( \ + MATXPR_ARG_TYPE left, \ + SCALAR_ARG_TYPE right) \ +{ \ + typedef et::BinaryMatrixOp< \ + XprT, ScalarT, _OpT_ \ + > ExprT; \ + return et::MatrixXpr(ExprT(left.expression(),right)); \ +} + +/** Declare an operator taking a scalar and a et::MatrixXpr. */ +#define CML_SCALAR_MATXPR_BINOP(_op_, _OpT_) \ +template \ +inline et::MatrixXpr< \ + et::BinaryMatrixOp< \ + ScalarT, XprT, _OpT_ \ + > \ +> \ + \ +_op_ ( \ + SCALAR_ARG_TYPE left, \ + MATXPR_ARG_TYPE right) \ +{ \ + typedef et::BinaryMatrixOp< \ + ScalarT, XprT, _OpT_ \ + > ExprT; \ + return et::MatrixXpr(ExprT(left,right.expression())); \ +} + +#endif + +// ------------------------------------------------------------------------- +// vim:ft=cpp diff --git a/Lib/Include/CML/matrix/matrix_comparison.h b/Lib/Include/CML/matrix/matrix_comparison.h new file mode 100644 index 0000000..f3def4f --- /dev/null +++ b/Lib/Include/CML/matrix/matrix_comparison.h @@ -0,0 +1,245 @@ +/* -*- C++ -*- ------------------------------------------------------------ + +Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/ + +The Configurable Math Library (CML) is distributed under the terms of the +Boost Software License, v1.0 (see cml/LICENSE for details). + + *-----------------------------------------------------------------------*/ +/** @file + * @brief + * + * @todo The matrix and matrix order operators could probably be combined + * into a single templated implementation, since the only thing that is + * different is the access method. + */ + +#ifndef matrix_comparison_h +#define matrix_comparison_h + +#include +#include +#include + +/* This is used below to create a more meaningful compile-time error when + * matrix_comparison is not provided with matrix or MatrixExpr arguments: + */ +struct matrix_comparison_expects_matrix_args_error; + +#define CML_MAT_MAT_ORDER(_order_, _op_, _OpT_) \ +template \ +inline bool \ +_op_ ( \ + const matrix& left, \ + const matrix& right) \ +{ \ + return detail::matrix_##_order_ (left, right, _OpT_ ()); \ +} + +#define CML_MAT_MATXPR_ORDER(_order_, _op_, _OpT_) \ +template \ +inline bool \ +_op_ ( \ + const matrix& left, \ + MATXPR_ARG_TYPE right) \ +{ \ + return detail::matrix_##_order_ (left, right, \ + _OpT_ ()); \ +} + +#define CML_MATXPR_MAT_ORDER(_order_, _op_, _OpT_) \ +template \ +inline bool \ +_op_ ( \ + MATXPR_ARG_TYPE left, \ + const matrix& right) \ +{ \ + return detail::matrix_##_order_ (left, right, \ + _OpT_ ()); \ +} + +#define CML_MATXPR_MATXPR_ORDER(_order_, _op_, _OpT_) \ +template \ +inline bool \ +_op_ ( \ + MATXPR_ARG_TYPE_N(1) left, \ + MATXPR_ARG_TYPE_N(2) right) \ +{ \ + return detail::matrix_##_order_ (left, right, \ + _OpT_ < \ + typename XprT1::value_type, \ + typename XprT2::value_type>()); \ +} + + +namespace cml { +namespace detail { + +/** Matrix strict weak ordering relationship. + * + * OpT must implement a strict weak order on the matrix element type. + * operator< and operator> on integer and floating-point types are + * examples. + */ +template +inline bool +matrix_weak_order(const LeftT& left, const RightT& right, OpT) +{ + /* Shorthand: */ + typedef et::ExprTraits left_traits; + typedef et::ExprTraits right_traits; + + /* matrix_comparison() requires matrix expressions: */ + CML_STATIC_REQUIRE_M( + (et::MatrixExpressions::is_true), + matrix_comparison_expects_matrix_args_error); + /* Note: parens are required here so that the preprocessor ignores the + * commas: + */ + + typedef typename et::MatrixPromote< + typename left_traits::result_type, + typename right_traits::result_type + >::type result_type; + typedef typename result_type::size_tag size_tag; + + /* Verify expression size: */ + matrix_size N = et::CheckedSize(left,right,size_tag()); + for(ssize_t i = 0; i < N.first; ++ i) { + for(ssize_t j = 0; j < N.second; ++ j) { + if(OpT().apply( + left_traits().get(left,i,j), + right_traits().get(right,i,j) + )) + { + /* If weak order (a < b) is satisfied, return true: */ + return true; + } else if(OpT().apply( + right_traits().get(right,i,j), + left_traits().get(left,i,j) + )) + { + /* If !(b < a), then return false: */ + return false; + } else { + + /* Have !(a < b) && !(b < a) <=> (a >= b && b >= a) + * <=> (a == b). so need to test next element: + */ + continue; + } + } + } + /* XXX Can this be unrolled in any reasonable way? */ + + /* If we get here, then left == right: */ + return false; +} + +/** Matrix total order relationship. + * + * OpT must implement a total order on the matrix element type. operator<= + * and operator>= on integer and floating-point types are examples. + */ +template +inline bool +matrix_total_order(const LeftT& left, const RightT& right, OpT) +{ + /* Shorthand: */ + typedef et::ExprTraits left_traits; + typedef et::ExprTraits right_traits; + + /* matrix_comparison() requires matrix expressions: */ + CML_STATIC_REQUIRE_M( + (et::MatrixExpressions::is_true), + matrix_comparison_expects_matrix_args_error); + /* Note: parens are required here so that the preprocessor ignores the + * commas: + */ + + typedef typename et::MatrixPromote< + typename left_traits::result_type, + typename right_traits::result_type + >::type result_type; + typedef typename result_type::size_tag size_tag; + + /* Verify expression size: */ + matrix_size N = et::CheckedSize(left,right,size_tag()); + for(size_t i = 0; i < N.first; ++ i) { + for(size_t j = 0; j < N.second; ++ j) { + + /* Test total order: */ + if(OpT().apply( + left_traits().get(left,i,j), + right_traits().get(right,i,j) + )) + { + /* Automatically true if weak order (a <= b) && !(b <= a) + * <=> (a <= b) && (b > a) <=> (a < b) is satisfied: + */ + if(!OpT().apply( + right_traits().get(right,i,j), + left_traits().get(left,i,j) + )) + return true; + + /* Otherwise, have equality (a <= b) && (b <= a), so + * continue to next element: + */ + else + continue; + + } else { + + /* Total order isn't satisfied (a > b), so return false: */ + return false; + } + } + } + /* XXX Can this be unrolled in any reasonable way? */ + + /* Total (==) or weak (<) order was satisfied, so return true: */ + return true; +} + +} + +/* XXX There is a better way to handle these with operator traits... */ + +CML_MAT_MAT_ORDER( total_order, operator==, et::OpEqual) +CML_MATXPR_MAT_ORDER( total_order, operator==, et::OpEqual) +CML_MAT_MATXPR_ORDER( total_order, operator==, et::OpEqual) +CML_MATXPR_MATXPR_ORDER( total_order, operator==, et::OpEqual) + +CML_MAT_MAT_ORDER( weak_order, operator!=, et::OpNotEqual) +CML_MATXPR_MAT_ORDER( weak_order, operator!=, et::OpNotEqual) +CML_MAT_MATXPR_ORDER( weak_order, operator!=, et::OpNotEqual) +CML_MATXPR_MATXPR_ORDER( weak_order, operator!=, et::OpNotEqual) + +CML_MAT_MAT_ORDER( weak_order, operator<, et::OpLess) +CML_MATXPR_MAT_ORDER( weak_order, operator<, et::OpLess) +CML_MAT_MATXPR_ORDER( weak_order, operator<, et::OpLess) +CML_MATXPR_MATXPR_ORDER( weak_order, operator<, et::OpLess) + +CML_MAT_MAT_ORDER( weak_order, operator>, et::OpGreater) +CML_MATXPR_MAT_ORDER( weak_order, operator>, et::OpGreater) +CML_MAT_MATXPR_ORDER( weak_order, operator>, et::OpGreater) +CML_MATXPR_MATXPR_ORDER( weak_order, operator>, et::OpGreater) + +CML_MAT_MAT_ORDER( total_order, operator<=, et::OpLessEqual) +CML_MATXPR_MAT_ORDER( total_order, operator<=, et::OpLessEqual) +CML_MAT_MATXPR_ORDER( total_order, operator<=, et::OpLessEqual) +CML_MATXPR_MATXPR_ORDER( total_order, operator<=, et::OpLessEqual) + +CML_MAT_MAT_ORDER( total_order, operator>=, et::OpGreaterEqual) +CML_MATXPR_MAT_ORDER( total_order, operator>=, et::OpGreaterEqual) +CML_MAT_MATXPR_ORDER( total_order, operator>=, et::OpGreaterEqual) +CML_MATXPR_MATXPR_ORDER( total_order, operator>=, et::OpGreaterEqual) + +} // namespace cml + +#endif + +// ------------------------------------------------------------------------- +// vim:ft=cpp diff --git a/Lib/Include/CML/matrix/matrix_expr.h b/Lib/Include/CML/matrix/matrix_expr.h new file mode 100644 index 0000000..00cb668 --- /dev/null +++ b/Lib/Include/CML/matrix/matrix_expr.h @@ -0,0 +1,483 @@ +/* -*- C++ -*- ------------------------------------------------------------ + +Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/ + +The Configurable Math Library (CML) is distributed under the terms of the +Boost Software License, v1.0 (see cml/LICENSE for details). + + *-----------------------------------------------------------------------*/ +/** @file + * @brief Matrix linear expression classes. + * + * @todo Dynamic resizing needs to be integrated more naturally into + * mul() and matrix transpose(): + */ + +#ifndef matrix_expr_h +#define matrix_expr_h + + +#include +#include +#include + +/* XXX Don't know which it should be just yet, since RVO seems to obviate the + * need for a reference type. However, copy by value copies the *entire + * expression tree rooted at the MatrixXpr<>, so this choice is bound to affect + * performance for some compiler or another: + */ +#define MATXPR_ARG_TYPE const et::MatrixXpr& +#define MATXPR_ARG_TYPE_N(_N_) const et::MatrixXpr& + +//#define MATXPR_ARG_TYPE const et::MatrixXpr +//#define MATXPR_ARG_TYPE_N(_N_) const et::MatrixXpr + +namespace cml { +namespace et { + +/** A placeholder for a matrix expression in the expression tree. */ +template +class MatrixXpr +{ + public: + + typedef MatrixXpr expr_type; + + /* Copy the expression by value into higher-up expressions: */ + typedef expr_type expr_const_reference; + + typedef typename ExprT::value_type value_type; + typedef matrix_result_tag result_tag; + typedef typename ExprT::size_tag size_tag; // Just inherit size type. + + /* Store the expression traits: */ + typedef ExprTraits expr_traits; + + /* Get the reference type: */ + typedef typename expr_traits::const_reference expr_reference; + + /* Get the result type: */ + typedef typename expr_traits::result_type result_type; + + /* Get the basis type: */ + typedef typename result_type::basis_orient basis_orient; + + /* Get the temporary type: */ + typedef typename result_type::temporary_type temporary_type; + + /* For matching by assignability: */ + typedef cml::et::not_assignable_tag assignable_tag; + + + public: + + /** Record result size as an enum (if applicable). */ + enum { array_rows = ExprT::array_rows, array_cols = ExprT::array_cols }; + + + public: + + /** Return the expression size as a pair. */ + matrix_size size() const { + return matrix_size(this->rows(),this->cols()); + } + + /** Return number of rows in the expression (same as subexpression). */ + size_t rows() const { + return expr_traits().rows(m_expr); + } + + /** Return number of columns in the expression (same as subexpression). */ + size_t cols() const { + return expr_traits().cols(m_expr); + } + + /** Return reference to contained expression. */ + expr_reference expression() const { return m_expr; } + + /** Compute value at index i,j of the result matrix. */ + value_type operator()(size_t i, size_t j) const { + return expr_traits().get(m_expr,i,j); + } + + /** Return element j of basis vector i. */ + value_type basis_element(size_t i, size_t j) const { + return basis_element(i,j,basis_orient()); + } + + + public: + + /** Construct from the subexpression to store. */ + explicit MatrixXpr(expr_reference expr) : m_expr(expr) {} + + /** Copy constructor. */ + MatrixXpr(const expr_type& e) : m_expr(e.m_expr) {} + + + protected: + + value_type basis_element(size_t i, size_t j, row_basis) const { + return (*this)(i,j); + } + + value_type basis_element(size_t i, size_t j, col_basis) const { + return (*this)(j,i); + } + + + protected: + + expr_reference m_expr; + + + private: + + /* Cannot be assigned to: */ + expr_type& operator=(const expr_type&); +}; + +/** Expression traits for MatrixXpr<>. */ +template +struct ExprTraits< MatrixXpr > +{ + typedef MatrixXpr expr_type; + typedef ExprT arg_type; + + typedef typename expr_type::value_type value_type; + typedef typename expr_type::expr_const_reference const_reference; + typedef typename expr_type::result_tag result_tag; + typedef typename expr_type::size_tag size_tag; + typedef typename expr_type::result_type result_type; + typedef typename expr_type::assignable_tag assignable_tag; + typedef expr_node_tag node_tag; + + value_type get(const expr_type& e, size_t i, size_t j) const { + return e(i,j); + } + + + matrix_size size(const expr_type& e) const { return e.size(); } + size_t rows(const expr_type& e) const { return e.rows(); } + size_t cols(const expr_type& e) const { return e.cols(); } +}; + + +/** A unary matrix expression operating on matrix elements as a list. + * + * The operator must take exactly one argument. + */ +template +class UnaryMatrixOp +{ + public: + + typedef UnaryMatrixOp expr_type; + + /* Record ary-ness of the expression: */ + typedef unary_expression expr_ary; + + /* Copy the expression by value into higher-up expressions: */ + typedef expr_type expr_const_reference; + + typedef typename OpT::value_type value_type; + typedef matrix_result_tag result_tag; + typedef typename ExprT::size_tag size_tag; + + /* Store the expression traits for the subexpression: */ + typedef ExprTraits expr_traits; + + /* Reference type for the subexpression: */ + typedef typename expr_traits::const_reference expr_reference; + + /* Get the result type: */ + typedef typename expr_traits::result_type result_type; + + /* Get the temporary type: */ + typedef typename result_type::temporary_type temporary_type; + + /* For matching by assignability: */ + typedef cml::et::not_assignable_tag assignable_tag; + + + public: + + /** Record result size as an enum (if applicable). */ + enum { array_rows = ExprT::array_rows, array_cols = ExprT::array_cols }; + + + public: + + /** Return the expression size as a pair. */ + matrix_size size() const { + return matrix_size(this->rows(),this->cols()); + } + + /** Return number of rows in the expression (same as argument). */ + size_t rows() const { + return expr_traits().rows(m_expr); + } + + /** Return number of columns in the expression (same as argument). */ + size_t cols() const { + return expr_traits().cols(m_expr); + } + + /** Compute value at index i,j of the result matrix. */ + value_type operator()(size_t i, size_t j) const { + + /* This uses the expression traits to figure out how to access the + * i,j'th element of the subexpression: + */ + return OpT().apply(expr_traits().get(m_expr,i,j)); + } + + + public: + + /** Construct from the subexpression. */ + explicit UnaryMatrixOp(expr_reference expr) : m_expr(expr) {} + + /** Copy constructor. */ + UnaryMatrixOp(const expr_type& e) : m_expr(e.m_expr) {} + + + protected: + + expr_reference m_expr; + + + private: + + /* Cannot be assigned to: */ + expr_type& operator=(const expr_type&); +}; + +/** Expression traits for UnaryMatrixOp<>. */ +template +struct ExprTraits< UnaryMatrixOp > +{ + typedef UnaryMatrixOp expr_type; + typedef ExprT arg_type; + + typedef typename expr_type::value_type value_type; + typedef typename expr_type::expr_const_reference const_reference; + typedef typename expr_type::result_tag result_tag; + typedef typename expr_type::size_tag size_tag; + typedef typename expr_type::result_type result_type; + typedef typename expr_type::assignable_tag assignable_tag; + typedef expr_node_tag node_tag; + + value_type get(const expr_type& e, size_t i, size_t j) const { + return e(i,j); + } + + matrix_size size(const expr_type& e) const { return e.size(); } + size_t rows(const expr_type& e) const { return e.rows(); } + size_t cols(const expr_type& e) const { return e.cols(); } +}; + + +/** A binary matrix expression. */ +template +class BinaryMatrixOp +{ + public: + + typedef BinaryMatrixOp expr_type; + + /* Copy the UnaryMatrixOp expression by value into parent + * expression tree nodes: + */ + typedef expr_type expr_const_reference; + + typedef typename OpT::value_type value_type; + typedef matrix_result_tag result_tag; + + /* For matching by assignability: */ + typedef cml::et::not_assignable_tag assignable_tag; + + /* Record the expression traits for the two subexpressions: */ + typedef ExprTraits left_traits; + typedef ExprTraits right_traits; + + /* Reference types for the two subexpressions: */ + typedef typename left_traits::const_reference left_reference; + typedef typename right_traits::const_reference right_reference; + + /* Figure out the expression's resulting (matrix) type: */ + typedef typename left_traits::result_type left_result; + typedef typename right_traits::result_type right_result; + typedef typename MatrixPromote::type result_type; + typedef typename result_type::size_tag size_tag; + + /* Get the temporary type: */ + typedef typename result_type::temporary_type temporary_type; + + /* Define a size checker: */ + typedef GetCheckedSize checked_size; + + + public: + + /** Record result size as an enum (if applicable). + * + * CheckExprSizes<> ensures that this works as expected. + */ + enum { + array_rows = result_type::array_rows, + array_cols = result_type::array_cols + }; + + + public: + + /** Return the expression size as a pair. */ + matrix_size size() const { + return CheckedSize(m_left,m_right,size_tag()); + } + + /** Return number of rows in the result. + * + * @note Because this calls size() internally, calling both rows() + * and cols() with CML_CHECK_MATRIX_EXPR_SIZES defined will cause the size + * checking code to be executed twice. + */ + size_t rows() const { +#if defined(CML_CHECK_MATRIX_EXPR_SIZES) + return this->size().first; +#else + return left_traits().rows(m_left); +#endif + } + + /** Return number of cols in the result. + * + * @note Because this calls size() internally, calling both rows() + * and cols() with CML_CHECK_MATRIX_EXPR_SIZES defined will cause the size + * checking code to be executed twice. + */ + size_t cols() const { +#if defined(CML_CHECK_MATRIX_EXPR_SIZES) + return this->size().second; +#else + return right_traits().cols(m_right); +#endif + } + + /** Compute value at index i,j of the result matrix. */ + value_type operator()(size_t i, size_t j) const { + + /* This uses the expression traits to figure out how to access the + * i'th index of the two subexpressions: + */ + return OpT().apply( + left_traits().get(m_left,i,j), + right_traits().get(m_right,i,j)); + } + + + public: + + /** Construct from the two subexpressions. + * + * @throws std::invalid_argument if the subexpression sizes don't + * match. + */ + explicit BinaryMatrixOp(left_reference left, right_reference right) + : m_left(left), m_right(right) {} + + /** Copy constructor. */ + BinaryMatrixOp(const expr_type& e) + : m_left(e.m_left), m_right(e.m_right) {} + + + protected: + + left_reference m_left; + right_reference m_right; + + + private: + + /* This ensures that a compile-time size check is executed: */ + typename checked_size::check_type _dummy; + + + private: + + /* Cannot be assigned to: */ + expr_type& operator=(const expr_type&); +}; + +/** Expression traits for BinaryMatrixOp<>. */ +template +struct ExprTraits< BinaryMatrixOp > +{ + typedef BinaryMatrixOp expr_type; + typedef LeftT left_type; + typedef RightT right_type; + + typedef typename expr_type::value_type value_type; + typedef typename expr_type::expr_const_reference const_reference; + typedef typename expr_type::result_tag result_tag; + typedef typename expr_type::size_tag size_tag; + typedef typename expr_type::result_type result_type; + typedef typename expr_type::assignable_tag assignable_tag; + typedef expr_node_tag node_tag; + + value_type get(const expr_type& e, size_t i, size_t j) const { + return e(i,j); + } + + matrix_size size(const expr_type& e) const { return e.size(); } + size_t rows(const expr_type& e) const { return e.rows(); } + size_t cols(const expr_type& e) const { return e.cols(); } +}; + +/* Helper struct to verify that both arguments are matrix expressions: */ +template +struct MatrixExpressions +{ + /* Require that both arguments are matrix expressions: */ + typedef typename LeftTraits::result_tag left_result; + typedef typename RightTraits::result_tag right_result; + enum { is_true = (same_type::is_true + && same_type::is_true) }; +}; + +namespace detail { + +/* XXX These are temporary helpers until dynamic resizing is integrated more + * naturally into mul() and matrix transpose(): + */ +template inline +void Resize(MatT&, size_t, size_t, fixed_size_tag, MT) {} + +template inline +void Resize(MatT& m, + size_t R, size_t C, dynamic_size_tag, dynamic_memory_tag) +{ + m.resize(R,C); +} + +template inline +void Resize(MatT& m, size_t R, size_t C) { + Resize(m, R, C, typename MatT::size_tag(), typename MatT::memory_tag()); +} + +template inline +void Resize(MatT& m, matrix_size N) { + Resize(m, N.first, N.second, + typename MatT::size_tag(), typename MatT::memory_tag()); +} + +} // namespace detail + +} // namespace et +} // namespace cml + +#endif + +// ------------------------------------------------------------------------- +// vim:ft=cpp diff --git a/Lib/Include/CML/matrix/matrix_functions.h b/Lib/Include/CML/matrix/matrix_functions.h new file mode 100644 index 0000000..cd2c92a --- /dev/null +++ b/Lib/Include/CML/matrix/matrix_functions.h @@ -0,0 +1,43 @@ +/* -*- C++ -*- ------------------------------------------------------------ + +Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/ + +The Configurable Math Library (CML) is distributed under the terms of the +Boost Software License, v1.0 (see cml/LICENSE for details). + + *-----------------------------------------------------------------------*/ +/** @file + * @brief + */ + +#ifndef matrix_functions_h +#define matrix_functions_h + +namespace cml { + +/** Set the given matrix to the identity matrix. + * + * This only makes sense for a square matrix, but no error will be + * signaled if the matrix is not square. + * + * @todo This should return a MatrixXpr to allow loop unrolling, as should + * the class method. + */ +template +inline matrix +identity(const matrix& m) +{ + typename matrix::temporary_type result; + + /* This is a no-op for fixed-size matrices: */ + cml::et::detail::Resize(result, m.size()); + result.identity(); + return result; +} + +} // namespace cml + +#endif + +// ------------------------------------------------------------------------- +// vim:ft=cpp diff --git a/Lib/Include/CML/matrix/matrix_mul.h b/Lib/Include/CML/matrix/matrix_mul.h new file mode 100644 index 0000000..6d2dc11 --- /dev/null +++ b/Lib/Include/CML/matrix/matrix_mul.h @@ -0,0 +1,205 @@ +/* -*- C++ -*- ------------------------------------------------------------ + +Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/ + +The Configurable Math Library (CML) is distributed under the terms of the +Boost Software License, v1.0 (see cml/LICENSE for details). + + *-----------------------------------------------------------------------*/ +/** @file + * @brief Multiply two matrices. + * + * @todo Does it make sense to put mat-mat multiplication as a node into the + * expression tree? + * + * @internal This does not need to return an expression type, since the + * temporary generation for the matrix result is handled automatically by the + * compiler. i.e. when used in an expression, the result is automatically + * included in the expression tree as a temporary by the compiler. + */ + +#ifndef matrix_mul_h +#define matrix_mul_h + +#include +#include + +/* This is used below to create a more meaningful compile-time error when + * mul is not provided with matrix or MatrixExpr arguments: + */ +struct mul_expects_matrix_args_error; + +/* This is used below to create a more meaningful compile-time error when + * fixed-size arguments to mul() have the wrong size: + */ +struct mul_expressions_have_wrong_size_error; + +namespace cml { +namespace detail { + +/** Verify the sizes of the argument matrices for matrix multiplication. + * + * @returns a matrix_size containing the size of the resulting matrix. + */ +template inline matrix_size +MatMulCheckedSize(const LeftT&, const RightT&, fixed_size_tag) +{ + CML_STATIC_REQUIRE_M( + ((size_t)LeftT::array_cols == (size_t)RightT::array_rows), + mul_expressions_have_wrong_size_error); + return matrix_size(LeftT::array_rows,RightT::array_cols); +} + +/** Verify the sizes of the argument matrices for matrix multiplication. + * + * @returns a matrix_size containing the size of the resulting matrix. + */ +template inline matrix_size +MatMulCheckedSize(const LeftT& left, const RightT& right, dynamic_size_tag) +{ + matrix_size left_N = left.size(), right_N = right.size(); + et::GetCheckedSize() + .equal_or_fail(left_N.second, right_N.first); /* cols,rows */ + return matrix_size(left_N.first, right_N.second); /* rows,cols */ +} + + +/** Matrix multiplication. + * + * Computes C = A x B (O(N^3), non-blocked algorithm). + */ +template +inline typename et::MatrixPromote< + typename et::ExprTraits::result_type, + typename et::ExprTraits::result_type +>::temporary_type +mul(const LeftT& left, const RightT& right) +{ + /* Shorthand: */ + typedef et::ExprTraits left_traits; + typedef et::ExprTraits right_traits; + typedef typename left_traits::result_type left_result; + typedef typename right_traits::result_type right_result; + + /* First, require matrix expressions: */ + CML_STATIC_REQUIRE_M( + (et::MatrixExpressions::is_true), + mul_expects_matrix_args_error); + /* Note: parens are required here so that the preprocessor ignores the + * commas. + */ + + /* Deduce size type to ensure that a run-time check is performed if + * necessary: + */ + typedef typename et::MatrixPromote< + typename left_traits::result_type, + typename right_traits::result_type + >::type result_type; + typedef typename result_type::size_tag size_tag; + + /* Require that left has the same number of columns as right has rows. + * This automatically checks fixed-size matrices at compile time, and + * throws at run-time if the sizes don't match: + */ + matrix_size N = detail::MatMulCheckedSize(left, right, size_tag()); + + /* Create an array with the right size (resize() is a no-op for + * fixed-size matrices): + */ + result_type C; + cml::et::detail::Resize(C, N); + + /* XXX Specialize this for fixed-size matrices: */ + typedef typename result_type::value_type value_type; + for(size_t i = 0; i < left.rows(); ++i) { /* rows */ + for(size_t j = 0; j < right.cols(); ++j) { /* cols */ + value_type sum(left(i,0)*right(0,j)); + for(size_t k = 1; k < right.rows(); ++k) { + sum += (left(i,k)*right(k,j)); + } + C(i,j) = sum; + } + } + + return C; +} + +} // namespace detail + + +/** operator*() for two matrices. */ +template +inline typename et::MatrixPromote< + matrix, matrix +>::temporary_type +operator*(const matrix& left, + const matrix& right) +{ + return detail::mul(left,right); +} + +/** operator*() for a matrix and a MatrixXpr. */ +template +inline typename et::MatrixPromote< + matrix, typename XprT::result_type +>::temporary_type +operator*(const matrix& left, + const et::MatrixXpr& right) +{ + /* Generate a temporary, and compute the right-hand expression: */ + typedef typename et::MatrixXpr::temporary_type expr_tmp; + expr_tmp tmp; + cml::et::detail::Resize(tmp,right.rows(),right.cols()); + tmp = right; + + return detail::mul(left,tmp); +} + +/** operator*() for a MatrixXpr and a matrix. */ +template +inline typename et::MatrixPromote< + typename XprT::result_type , matrix +>::temporary_type +operator*(const et::MatrixXpr& left, + const matrix& right) +{ + /* Generate a temporary, and compute the left-hand expression: */ + typedef typename et::MatrixXpr::temporary_type expr_tmp; + expr_tmp tmp; + cml::et::detail::Resize(tmp,left.rows(),left.cols()); + tmp = left; + + return detail::mul(tmp,right); +} + +/** operator*() for two MatrixXpr's. */ +template +inline typename et::MatrixPromote< + typename XprT1::result_type, typename XprT2::result_type +>::temporary_type +operator*(const et::MatrixXpr& left, + const et::MatrixXpr& right) +{ + /* Generate temporaries and compute expressions: */ + typedef typename et::MatrixXpr::temporary_type left_tmp; + left_tmp ltmp; + cml::et::detail::Resize(ltmp,left.rows(),left.cols()); + ltmp = left; + + typedef typename et::MatrixXpr::temporary_type right_tmp; + right_tmp rtmp; + cml::et::detail::Resize(rtmp,right.rows(),right.cols()); + rtmp = right; + + return detail::mul(ltmp,rtmp); +} + +} // namespace cml + +#endif + +// ------------------------------------------------------------------------- +// vim:ft=cpp diff --git a/Lib/Include/CML/matrix/matrix_ops.h b/Lib/Include/CML/matrix/matrix_ops.h new file mode 100644 index 0000000..8188f87 --- /dev/null +++ b/Lib/Include/CML/matrix/matrix_ops.h @@ -0,0 +1,50 @@ +/* -*- C++ -*- ------------------------------------------------------------ + +Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/ + +The Configurable Math Library (CML) is distributed under the terms of the +Boost Software License, v1.0 (see cml/LICENSE for details). + + *-----------------------------------------------------------------------*/ +/** @file + * @brief Defines matrix operators. + */ +#ifndef matrix_ops_h +#define matrix_ops_h + +#include +#include +#include + +namespace cml { + +CML_MAT_UNIOP( operator+, et::OpPos) +CML_MATXPR_UNIOP( operator+, et::OpPos) + +CML_MAT_UNIOP( operator-, et::OpNeg) +CML_MATXPR_UNIOP( operator-, et::OpNeg) + +CML_MAT_MAT_BINOP( operator+, et::OpAdd) +CML_MATXPR_MAT_BINOP( operator+, et::OpAdd) +CML_MAT_MATXPR_BINOP( operator+, et::OpAdd) +CML_MATXPR_MATXPR_BINOP( operator+, et::OpAdd) + +CML_MAT_MAT_BINOP( operator-, et::OpSub) +CML_MATXPR_MAT_BINOP( operator-, et::OpSub) +CML_MAT_MATXPR_BINOP( operator-, et::OpSub) +CML_MATXPR_MATXPR_BINOP( operator-, et::OpSub) + +CML_MAT_SCALAR_BINOP( operator*, et::OpMul) +CML_SCALAR_MAT_BINOP( operator*, et::OpMul) +CML_MATXPR_SCALAR_BINOP( operator*, et::OpMul) +CML_SCALAR_MATXPR_BINOP( operator*, et::OpMul) + +CML_MAT_SCALAR_BINOP( operator/, et::OpDiv) +CML_MATXPR_SCALAR_BINOP( operator/, et::OpDiv) + +} // namespace cml + +#endif + +// ------------------------------------------------------------------------- +// vim:ft=cpp diff --git a/Lib/Include/CML/matrix/matrix_print.h b/Lib/Include/CML/matrix/matrix_print.h new file mode 100644 index 0000000..0937afd --- /dev/null +++ b/Lib/Include/CML/matrix/matrix_print.h @@ -0,0 +1,59 @@ +/* -*- C++ -*- ------------------------------------------------------------ + +Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/ + +The Configurable Math Library (CML) is distributed under the terms of the +Boost Software License, v1.0 (see cml/LICENSE for details). + + *-----------------------------------------------------------------------*/ +/** @file + * @brief + */ + +#ifndef matrix_print_h +#define matrix_print_h + +#include + +namespace cml { + +/** Output a matrix to a std::ostream. */ +template inline std::ostream& +operator<<(std::ostream& os, const matrix& m) +{ + for(size_t i = 0; i < m.rows(); ++i) { + os << "["; + for(size_t j = 0; j < m.cols(); ++j) { + os << " " << m(i,j); + } + os << " ]"; + if (i != m.rows()-1) { + os << std::endl; + } + } + return os; +} + +/** Output a matrix expression to a std::ostream. */ +template< class XprT > inline std::ostream& +operator<<(std::ostream& os, const et::MatrixXpr& m) +{ + for(size_t i = 0; i < m.rows(); ++i) { + os << "["; + for(size_t j = 0; j < m.cols(); ++j) { + os << " " << m(i,j); + } + os << " ]"; + if (i != m.rows()-1) { + os << std::endl; + } + } + return os; +} + +} // namespace cml + +#endif + +// ------------------------------------------------------------------------- +// vim:ft=cpp diff --git a/Lib/Include/CML/matrix/matrix_promotions.h b/Lib/Include/CML/matrix/matrix_promotions.h new file mode 100644 index 0000000..8be57cb --- /dev/null +++ b/Lib/Include/CML/matrix/matrix_promotions.h @@ -0,0 +1,187 @@ +/* -*- C++ -*- ------------------------------------------------------------ + +Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/ + +The Configurable Math Library (CML) is distributed under the terms of the +Boost Software License, v1.0 (see cml/LICENSE for details). + + *-----------------------------------------------------------------------*/ +/** @file + * @brief + * + * Defines promotions for matrices used in matrix/matrix or matrix/scalar + * expressions. + * + * @sa UnaryMat4_TOp + * @sa BinaryMat4_TOp + */ + +#ifndef matrix_promotions_h +#define matrix_promotions_h + +#include +#include +#include +#include +#include + +/* This is used below to create a more meaningful compile-time error when + * either argument to OuterPromote has the wrong orientation. + */ +struct outer_promote_expects_properly_oriented_args_error; + +namespace cml { +namespace et { + +/** Promote two types to a matrixt type. */ +template struct MatrixPromote +{ + /* Default matrix type promotion template. */ + template struct MatrixPromoteHelper; + + /** Type promotion for two matrix types. + * + * @note This always uses the basis orientation of the left-hand matrix. + * @bug This always uses the basis orientation of the left-hand matrix, + * which is not always correct. + */ + template + struct MatrixPromoteHelper< + cml::matrix, cml::matrix + > + { + /* Promote the arrays: */ + typedef typename ArrayPromote< + typename cml::matrix::array_type, + typename cml::matrix::array_type + >::type promoted_array; + + /* The deduced matrix result type: */ + typedef cml::matrix< + typename promoted_array::value_type, + typename promoted_array::generator_type, + BO1, + typename promoted_array::layout + > type; + + /* The deduced temporary type: */ + typedef typename type::temporary_type temporary_type; + }; + + /** Type promotion for a matrix and a scalar. */ + template + struct MatrixPromoteHelper, S> + { + /* The deduced matrix result type (the array type is the same): */ + typedef cml::matrix::type, AT, BO, L> type; + + /* The deduced temporary type: */ + typedef typename type::temporary_type temporary_type; + }; + + /** Type promotion for a scalar and a matrix. */ + template + struct MatrixPromoteHelper > + { + /* The deduced matrix result type (the array type is the same): */ + typedef cml::matrix::type, AT, BO, L> type; + + /* The deduced temporary type: */ + typedef typename type::temporary_type temporary_type; + }; + + /** Type promotion for outer product. */ + template + struct MatrixPromoteHelper< cml::vector, cml::vector > + { + typedef cml::vector left_type; + typedef cml::vector right_type; + typedef CML_DEFAULT_BASIS_ORIENTATION basis_orient; + + /* Get matrix size: */ + enum { + array_rows = left_type::array_size, + array_cols = right_type::array_size + }; + + /* Deduce the corresponding matrix types for the vectors: */ + typedef CML_DEFAULT_ARRAY_LAYOUT layout; + typedef typename select_if< + array_rows == -1, dynamic<>, fixed + >::result left_storage; + typedef cml::matrix left_matrix; + + typedef typename select_if< + array_cols == -1, dynamic<>, fixed<1,array_cols> + >::result right_storage; + typedef cml::matrix right_matrix; + + /* Finally, promote the matrix types to get the result: */ + typedef typename et::MatrixPromote::type type; + typedef typename type::temporary_type temporary_type; + }; + + /** Remove const and & from the to-be-promoted types. */ + typedef typename remove_const< + typename remove_reference::type>::type LeftBaseT; + typedef typename remove_const< + typename remove_reference::type>::type RightBaseT; + + typedef typename MatrixPromoteHelper::type type; + typedef typename type::temporary_type temporary_type; +}; + +/** + * NOTE: MatrixPromote* are somewhat ad hoc, and were added to + * simplify the code for matrix slerp/squad/etc. + */ + +/** Type promotion for two matrix types. */ +template < class Mat1_T, class Mat2_T > +struct MatrixPromote2 +{ + typedef typename MatrixPromote< + typename Mat1_T::temporary_type, typename Mat2_T::temporary_type + >::temporary_type temporary_type; + typedef typename temporary_type::value_type value_type; +}; + +/** Type promotion for three matrix types. */ +template < class Mat1_T, class Mat2_T, class Mat3_T > +struct MatrixPromote3 +{ + typedef typename MatrixPromote< + typename Mat1_T::temporary_type, + typename MatrixPromote< + typename Mat2_T::temporary_type, + typename Mat3_T::temporary_type + >::temporary_type + >::temporary_type temporary_type; + typedef typename temporary_type::value_type value_type; +}; + +/** Type promotion for four matrix types. */ +template < class Mat1_T, class Mat2_T, class Mat3_T, class Mat4_T > +struct MatrixPromote4 +{ + typedef typename MatrixPromote< + typename Mat1_T::temporary_type, + typename MatrixPromote< + typename Mat2_T::temporary_type, + typename MatrixPromote< + typename Mat3_T::temporary_type, + typename Mat4_T::temporary_type + >::temporary_type + >::temporary_type + >::temporary_type temporary_type; + typedef typename temporary_type::value_type value_type; +}; + +} // namespace et +} // namespace cml + +#endif + +// ------------------------------------------------------------------------- +// vim:ft=cpp diff --git a/Lib/Include/CML/matrix/matrix_rowcol.h b/Lib/Include/CML/matrix/matrix_rowcol.h new file mode 100644 index 0000000..9c7b4eb --- /dev/null +++ b/Lib/Include/CML/matrix/matrix_rowcol.h @@ -0,0 +1,273 @@ +/* -*- C++ -*- ------------------------------------------------------------ + +Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/ + +The Configurable Math Library (CML) is distributed under the terms of the +Boost Software License, v1.0 (see cml/LICENSE for details). + + *-----------------------------------------------------------------------*/ +/** @file + * @brief Expressions to extract a row or column of a matrix. + */ + +#ifndef matrix_rowcol_h +#define matrix_rowcol_h + +#include +#include + +namespace cml { +namespace et { + +template +class MatrixRowOp +{ + public: + + typedef MatrixRowOp expr_type; + + /* Record ary-ness of the expression: */ + typedef unary_expression expr_ary; + + /* Copy the expression by value into higher-up expressions: */ + typedef expr_type expr_const_reference; + + typedef typename ExprT::value_type value_type; + typedef vector_result_tag result_tag; + typedef typename ExprT::size_tag size_tag; + + /* Store the expression traits: */ + typedef ExprTraits expr_traits; + + /* Get the reference type: */ + typedef typename expr_traits::const_reference expr_reference; + + /* Get the result vector type: */ + typedef typename expr_traits::result_type::row_vector_type result_type; + + /* Get the temporary type: */ + typedef typename result_type::temporary_type temporary_type; + + + public: + + /** Record result size as an enum. */ + enum { array_size = result_type::array_size }; + + + public: + + /** Return the expression size as a pair. */ + matrix_size size() const { + return expr_traits().rows(m_expr); + } + + /** Return the result as a normalized vector. */ + result_type normalize() const { + result_type v(VectorXpr(*this)); + return v.normalize(); + } + + /** Return reference to contained expression. */ + expr_reference expression() const { return m_expr; } + + /** Compute value at index i of the row vector. */ + value_type operator[](size_t i) const { + return expr_traits().get(m_expr,m_row,i); + } + + + public: + + /** Construct from the subexpression to store. */ + explicit MatrixRowOp(const ExprT& expr, size_t row) + : m_expr(expr), m_row(row) {} + + /** Copy constructor. */ + MatrixRowOp(const expr_type& e) + : m_expr(e.m_expr), m_row(e.m_row) {} + + + protected: + + expr_reference m_expr; + const size_t m_row; + + + private: + + /* Cannot be assigned to: */ + expr_type& operator=(const expr_type&); +}; + +/** Expression traits class for MatrixRowOp<>. */ +template +struct ExprTraits< MatrixRowOp > +{ + typedef MatrixRowOp expr_type; + typedef ExprT arg_type; + + typedef typename expr_type::value_type value_type; + typedef typename expr_type::expr_const_reference const_reference; + typedef typename expr_type::result_tag result_tag; + typedef typename expr_type::size_tag size_tag; + typedef typename expr_type::result_type result_type; + typedef expr_node_tag node_tag; + + value_type get(const expr_type& v, size_t i) const { return v[i]; } + size_t size(const expr_type& e) const { return e.size(); } +}; + +template +class MatrixColOp +{ + public: + + typedef MatrixColOp expr_type; + + /* Record ary-ness of the expression: */ + typedef unary_expression expr_ary; + + /* Copy the expression by value into higher-up expressions: */ + typedef expr_type expr_const_reference; + + typedef typename ExprT::value_type value_type; + typedef vector_result_tag result_tag; + typedef typename ExprT::size_tag size_tag; + + /* Store the expression traits: */ + typedef ExprTraits expr_traits; + + /* Get the reference type: */ + typedef typename expr_traits::const_reference expr_reference; + + /* Get the result vector type: */ + typedef typename expr_traits::result_type::col_vector_type result_type; + + /* Get the temporary type: */ + typedef typename result_type::temporary_type temporary_type; + + + public: + + /** Record result size as an enum. */ + enum { array_size = result_type::array_size }; + + + public: + + /** Return the expression size as a pair. */ + matrix_size size() const { + return expr_traits().cols(m_expr); + } + + /** Return reference to contained expression. */ + expr_reference expression() const { return m_expr; } + + /** Return the result as a normalized vector. */ + result_type normalize() const { + result_type v(VectorXpr(*this)); + return v.normalize(); + } + + /** Compute value at index i of the col vector. */ + value_type operator[](size_t i) const { + return expr_traits().get(m_expr,i,m_col); + } + + + public: + + /** Construct from the subexpression to store. */ + explicit MatrixColOp(const ExprT& expr, size_t col) + : m_expr(expr), m_col(col) {} + + /** Copy constructor. */ + MatrixColOp(const expr_type& e) + : m_expr(e.m_expr), m_col(e.m_col) {} + + + protected: + + expr_reference m_expr; + const size_t m_col; + + + private: + + /* Cannot be assigned to: */ + expr_type& operator=(const expr_type&); +}; + +/** Expression traits class for MatrixColOp<>. */ +template +struct ExprTraits< MatrixColOp > +{ + typedef MatrixColOp expr_type; + typedef ExprT arg_type; + + typedef typename expr_type::value_type value_type; + typedef typename expr_type::expr_const_reference const_reference; + typedef typename expr_type::result_tag result_tag; + typedef typename expr_type::size_tag size_tag; + typedef typename expr_type::result_type result_type; + typedef expr_node_tag node_tag; + + value_type get(const expr_type& v, size_t i) const { return v[i]; } + size_t size(const expr_type& e) const { return e.size(); } +}; + +} // namespace et + +/* Define the row and column operators in the cml namespace: */ + +/** Matrix row operator taking a matrix operand. */ +template +et::VectorXpr< et::MatrixRowOp< matrix > > +row(const matrix& expr, size_t i) +{ + typedef et::MatrixRowOp< matrix > ExprT; + return et::VectorXpr(ExprT(expr,i)); +} + +/** Matrix row operator taking an et::MatrixXpr operand. + * + * The parse tree is automatically compressed by hoisting the MatrixXpr's + * subexpression into the subexpression of the MatrixRowOp. + */ +template +et::VectorXpr< et::MatrixRowOp > +row(const et::MatrixXpr& expr, size_t i) +{ + typedef et::MatrixRowOp ExprT; + return et::MatrixXpr(ExprT(expr.expression(),i)); +} + +/** Matrix col operator taking a matrix operand. */ +template +et::VectorXpr< et::MatrixColOp< matrix > > +col(const matrix& expr, size_t i) +{ + typedef et::MatrixColOp< matrix > ExprT; + return et::VectorXpr(ExprT(expr,i)); +} + +/** Matrix col operator taking an et::MatrixXpr operand. + * + * The parse tree is automatically compressed by hoisting the MatrixXpr's + * subexpression into the subexpression of the MatrixColOp. + */ +template +et::VectorXpr< et::MatrixColOp > +col(const et::MatrixXpr& expr, size_t i) +{ + typedef et::MatrixColOp ExprT; + return et::VectorXpr(ExprT(expr.expression(),i)); +} + +} // namespace cml + +#endif + +// ------------------------------------------------------------------------- +// vim:ft=cpp diff --git a/Lib/Include/CML/matrix/matrix_traits.h b/Lib/Include/CML/matrix/matrix_traits.h new file mode 100644 index 0000000..7574ff6 --- /dev/null +++ b/Lib/Include/CML/matrix/matrix_traits.h @@ -0,0 +1,49 @@ +/* -*- C++ -*- ------------------------------------------------------------ + +Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/ + +The Configurable Math Library (CML) is distributed under the terms of the +Boost Software License, v1.0 (see cml/LICENSE for details). + + *-----------------------------------------------------------------------*/ +/** @file + * @brief + */ + +#ifndef matrix_traits_h +#define matrix_traits_h + +#include + +namespace cml { +namespace et { + +template +struct ExprTraits< cml::matrix > +{ + typedef typename cml::matrix expr_type; + typedef typename expr_type::value_type value_type; + typedef typename expr_type::expr_reference reference; + typedef typename expr_type::expr_const_reference const_reference; + typedef typename expr_type::result_tag result_tag; + typedef typename expr_type::size_tag size_tag; + typedef typename expr_type::assignable_tag assignable_tag; + typedef expr_type result_type; + typedef expr_leaf_tag node_tag; + + value_type get(const expr_type& m, size_t i, size_t j) const { + return m(i,j); + } + + matrix_size size(const expr_type& e) const { return e.size(); } + size_t rows(const expr_type& m) const { return m.rows(); } + size_t cols(const expr_type& m) const { return m.cols(); } +}; + +} // namespace et +} // namespace cml + +#endif + +// ------------------------------------------------------------------------- +// vim:ft=cpp diff --git a/Lib/Include/CML/matrix/matrix_transpose.h b/Lib/Include/CML/matrix/matrix_transpose.h new file mode 100644 index 0000000..3f54843 --- /dev/null +++ b/Lib/Include/CML/matrix/matrix_transpose.h @@ -0,0 +1,305 @@ +/* -*- C++ -*- ------------------------------------------------------------ + +Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/ + +The Configurable Math Library (CML) is distributed under the terms of the +Boost Software License, v1.0 (see cml/LICENSE for details). + + *-----------------------------------------------------------------------*/ +/** @file + * @brief + * + * @todo Currently, the transpose() and T() functions copy the transposed + * result into a temporary, and return it to avoid aliasing problems, e.g. + * C = transpose(C). By checking for C on the right-hand side, this can + * be avoided, but experimentation is needed to determine the impact on + * performance. Another option is to use a function to explicitly specify + * when a temporary is needed; e.g. C = transpose(temp(C)). + */ + +#ifndef matrix_transpose_h +#define matrix_transpose_h + +#include + +#define MATRIX_TRANSPOSE_RETURNS_TEMP + +namespace cml { +namespace et { + +/** "Transpose" the given matrix expression. + * + * This does nothing more than change the result type of the expression + * into one with the opposite orientation (i.e. row->col, col->row). + */ +template +class MatrixTransposeOp +{ + public: + + typedef MatrixTransposeOp expr_type; + + /* Record ary-ness of the expression: */ + typedef unary_expression expr_ary; + + /* Copy the expression by value into higher-up expressions: */ + typedef expr_type expr_const_reference; + + typedef typename ExprT::value_type value_type; + typedef matrix_result_tag result_tag; + typedef typename ExprT::size_tag size_tag; + + /* Store the expression traits: */ + typedef ExprTraits expr_traits; + + /* Get the reference type: */ + typedef typename expr_traits::const_reference expr_reference; + + /* Swap the orientation: */ + typedef typename expr_traits::result_type::transposed_type result_type; + + /* Get the temporary type: */ + typedef typename result_type::temporary_type temporary_type; + + /* For matching by assignability: */ + typedef cml::et::not_assignable_tag assignable_tag; + + + public: + + /** Record result size as an enum. */ + enum { + array_rows = result_type::array_rows, + array_cols = result_type::array_cols + }; + + + public: + + /** Return the expression size as a pair. */ + matrix_size size() const { + return matrix_size(this->rows(),this->cols()); + } + + /** Return result rows. + * + * The tranpose has the same number of rows as the original has + * columns. + */ + size_t rows() const { + return expr_traits().cols(m_expr); + } + + /** Return result cols. + * + * The tranpose has the same number of columns as the original has + * rows. + */ + size_t cols() const { + return expr_traits().rows(m_expr); + } + + /** Return reference to contained expression. */ + expr_reference expression() const { return m_expr; } + + /** Compute value at index i of the result matrix. + * + * Element (i,j) of the transpose is element (j,i) of the original + * expression. + */ + value_type operator()(size_t i, size_t j) const { + return expr_traits().get(m_expr,j,i); + } + + + public: + + /** Construct from the subexpression to store. */ + explicit MatrixTransposeOp(const ExprT& expr) : m_expr(expr) {} + + /** Copy constructor. */ + MatrixTransposeOp(const expr_type& e) : m_expr(e.m_expr) {} + + + protected: + + expr_reference m_expr; + + + private: + + /* Cannot be assigned to: */ + expr_type& operator=(const expr_type&); +}; + +/** Expression traits class for VectorTransposeOp<>. */ +template +struct ExprTraits< MatrixTransposeOp > +{ + typedef MatrixTransposeOp expr_type; + typedef typename expr_type::value_type value_type; + typedef typename expr_type::expr_const_reference const_reference; + typedef typename expr_type::result_tag result_tag; + typedef typename expr_type::size_tag size_tag; + typedef typename expr_type::result_type result_type; + typedef typename expr_type::assignable_tag assignable_tag; + typedef expr_node_tag node_tag; + + value_type get(const expr_type& m, size_t i, size_t j) const { + return m(i,j); + } + + matrix_size size(const expr_type& e) const { return e.size(); } + size_t rows(const expr_type& e) const { return e.rows(); } + size_t cols(const expr_type& e) const { return e.cols(); } +}; + +} // namespace et + + +/* Define the transpose operators in the cml namespace: */ +#if defined(MATRIX_TRANSPOSE_RETURNS_TEMP) + +/** Matrix transpose operator taking a matrix operand. */ +template +typename et::MatrixTransposeOp< + matrix +>::temporary_type +transpose(const matrix& expr) +{ + /* Record the matrix type: */ + typedef matrix matrix_type; + + /* Record the type of the transpose op: */ + typedef et::MatrixTransposeOp Op; + + /* Determine the returned matrix type: */ + typedef typename et::MatrixTransposeOp< + matrix_type + >::temporary_type tmp_type; + + /* The expression to use to assign the temporary: */ + typedef et::MatrixXpr ExprT; + + /* Create the temporary and return it: */ + tmp_type tmp; + cml::et::detail::Resize(tmp,expr.rows(),expr.cols()); + tmp = ExprT(Op(expr)); + return tmp; +} + +/** Matrix transpose operator taking an et::MatrixXpr operand. + * + * The parse tree is automatically compressed by hoisting the MatrixXpr's + * subexpression into the subexpression of the MatrixTransposeOp. + */ +template +typename et::MatrixTransposeOp< + XprT +>::temporary_type +transpose(MATXPR_ARG_TYPE expr) +{ + /* Record the type of the transpose op: */ + typedef et::MatrixTransposeOp Op; + + /* Determine the returned matrix type: */ + typedef typename et::MatrixTransposeOp::temporary_type tmp_type; + + /* The expression to use to assign the temporary: */ + typedef et::MatrixXpr ExprT; + + /* Create the temporary and return it: */ + tmp_type tmp; + cml::et::detail::Resize(tmp,expr.rows(),expr.cols()); + tmp = ExprT(Op(expr.expression())); + return tmp; +} + + +/* For notational convenience: */ + +/** Matrix transpose operator taking a matrix operand. */ +template +typename et::MatrixTransposeOp< + matrix +>::temporary_type +T(const matrix& expr) +{ + return transpose(expr); +} + +/** Matrix transpose operator taking an et::MatrixXpr operand. + * + * The parse tree is automatically compressed by hoisting the MatrixXpr's + * subexpression into the subexpression of the MatrixTransposeOp. + */ +template +typename et::MatrixTransposeOp< + XprT +>::temporary_type +T(MATXPR_ARG_TYPE expr) +{ + return transpose(expr); +} + +#else + +/* XXX For this to work correctly, matrix assignment and copy have to be + * changed to either use a temporary all the time, or to create a temporary + * when the same matrix appears on both sides of an assignment, and a + * temporary was not already created on the RHS by the ET code. + */ + +/** Matrix transpose operator taking a matrix operand. */ +template +et::MatrixXpr< et::MatrixTransposeOp< matrix > > +transpose(const matrix& expr) +{ + typedef et::MatrixTransposeOp< matrix > ExprT; + return et::MatrixXpr(ExprT(expr)); +} + +/** Matrix transpose operator taking an et::MatrixXpr operand. + * + * The parse tree is automatically compressed by hoisting the MatrixXpr's + * subexpression into the subexpression of the MatrixTransposeOp. + */ +template +et::MatrixXpr< et::MatrixTransposeOp > +transpose(MATXPR_ARG_TYPE expr) +{ + typedef et::MatrixTransposeOp ExprT; + return et::MatrixXpr(ExprT(expr.expression())); +} + + +/* For notational convenience: */ + +/** Matrix transpose operator taking a matrix operand. */ +template +et::MatrixXpr< et::MatrixTransposeOp< matrix > > +T(const matrix& expr) +{ + return transpose(expr); +} + +/** Matrix transpose operator taking an et::MatrixXpr operand. + * + * The parse tree is automatically compressed by hoisting the MatrixXpr's + * subexpression into the subexpression of the MatrixTransposeOp. + */ +template +et::MatrixXpr< et::MatrixTransposeOp > +T(MATXPR_ARG_TYPE expr) +{ + return transpose(expr); +} + +#endif + +} // namespace cml + +#endif + +// ------------------------------------------------------------------------- +// vim:ft=cpp diff --git a/Lib/Include/CML/matrix/matrix_unroller.h b/Lib/Include/CML/matrix/matrix_unroller.h new file mode 100644 index 0000000..ab85945 --- /dev/null +++ b/Lib/Include/CML/matrix/matrix_unroller.h @@ -0,0 +1,293 @@ +/* -*- C++ -*- ------------------------------------------------------------ + +Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/ + +The Configurable Math Library (CML) is distributed under the terms of the +Boost Software License, v1.0 (see cml/LICENSE for details). + + *-----------------------------------------------------------------------*/ +/** @file + * @brief + * + * @todo Need to implement unrolling for efficient col-major array access. + * + * @todo Does it make sense to unroll an assignment if either side of the + * assignment has a fixed size, or just when the target matrix is fixed + * size? + */ + +#ifndef matrix_unroller_h +#define matrix_unroller_h + +#include +#include +#include + +#if !defined(CML_2D_UNROLLER) && !defined(CML_NO_2D_UNROLLER) +#error "The matrix unroller has not been defined." +#endif + +#if defined(CML_2D_UNROLLER) && !defined(CML_MATRIX_UNROLL_LIMIT) +#error "CML_MATRIX_UNROLL_LIMIT is undefined." +#endif + +namespace cml { +namespace et { +namespace detail { + +/** Unroll a binary assignment operator on a fixed-size matrix. + * + * This uses a forward iteration to make better use of the cache. + * + * @sa cml::matrix + * @sa cml::et::OpAssign + * + * @bug Need to verify that OpT is actually an assignment operator. + * @bug The 2D unroller needs to be specified for efficient col-major + * access. + */ +template +class MatrixAssignmentUnroller +{ + protected: + + /* The matrix type being assigned to: */ + typedef cml::matrix matrix_type; + + /* Record traits for the arguments: */ + typedef ExprTraits dest_traits; + typedef ExprTraits src_traits; + +#if defined(CML_2D_UNROLLER) + + /* Forward declare: */ + template + struct Eval; + + /* XXX This needs to be specified for efficient col-major access also! */ + + /** Evaluate the binary operator at element R,C. */ + template + struct Eval { + void operator()(matrix_type& dest, const SrcT& src) const { + + /* Apply to current R,C: */ + OpT().apply(dest(R,C), src_traits().get(src,R,C)); + + /* Evaluate at R,C+1: */ + Eval()(dest,src); + } + }; + + /** Evaluate the binary operator at element R,LastCol. */ + template + struct Eval { + void operator()(matrix_type& dest, const SrcT& src) const { + + /* Apply to R,LastCol: */ + OpT().apply(dest(R,LastCol), src_traits().get(src,R,LastCol)); + + /* Evaluate at R+1,0; i.e. move to next row and start the + * col iteration from 0: + */ + Eval()(dest,src); + } + }; + + /** Evaluate the binary operator at element LastRow,C. */ + template + struct Eval { + void operator()(matrix_type& dest, const SrcT& src) const { + + /* Apply to LastRow,C: */ + OpT().apply(dest(LastRow,C), src_traits().get(src,LastRow,C)); + + /* Evaluate at LastRow,C+1: */ + Eval()(dest,src); + } + }; + + /** Evaluate the binary operator at element LastRow,LastCol. */ + template + struct Eval { + void operator()(matrix_type& dest, const SrcT& src) const { + + /* Apply to LastRow,LastCol: */ + OpT().apply( + dest(LastRow,LastCol), + src_traits().get(src,LastRow,LastCol)); + } + }; + + + /** Evaluate operators on large matrices using a loop. */ + template + struct Eval { + void operator()(matrix_type& dest, const SrcT& src) const { + for(size_t i = 0; i <= LastRow; ++i) { + for(size_t j = 0; j <= LastCol; ++j) { + OpT().apply(dest(i,j), src_traits().get(src,i,j)); + } + } + } + }; + +#endif // CML_2D_UNROLLER + +#if defined(CML_NO_2D_UNROLLER) + + /** Evaluate the binary operator using a loop. */ + template struct Eval { + void operator()(matrix_type& dest, const SrcT& src) const { + for(size_t i = 0; i <= LastRow; ++i) { + for(size_t j = 0; j <= LastCol; ++j) { + OpT().apply(dest(i,j), src_traits().get(src,i,j)); + } + } + } + }; + +#endif // CML_NO_2D_UNROLLER + + + public: + + /** Unroll assignment for a fixed-sized matrix. */ + void operator()( + cml::matrix& dest, const SrcT& src, cml::fixed_size_tag) + { + typedef cml::matrix matrix_type; + enum { + LastRow = matrix_type::array_rows-1, + LastCol = matrix_type::array_cols-1, + Max = (LastRow+1)*(LastCol+1) + }; + +#if defined(CML_2D_UNROLLER) + typedef typename MatrixAssignmentUnroller + ::template Eval<0, 0, LastRow, LastCol, + (Max <= CML_MATRIX_UNROLL_LIMIT)> Unroller; +#endif + +#if defined(CML_NO_2D_UNROLLER) + /* Use a loop: */ + typedef typename MatrixAssignmentUnroller + ::template Eval<0, 0, LastRow, LastCol> Unroller; +#endif + + /* Use a run-time check if src is a run-time sized expression: */ + typedef typename ExprTraits::size_tag src_size; + typedef typename select_if< + same_type::is_true, + dynamic_size_tag, fixed_size_tag>::result size_tag; + + /* Check the expression size (the returned size isn't needed): */ + CheckedSize(dest,src,size_tag()); + /* Note: for two fixed-size expressions, the if-statements and + * comparisons should be completely eliminated as dead code. If + * src is a dynamic-sized expression, the check will still happen. + */ + + Unroller()(dest,src); + } + + + private: + /* XXX Blah, a temp. hack to fix the auto-resizing stuff below. */ + matrix_size hack_actual_size( + matrix_type& dest, const SrcT& /*src*/, scalar_result_tag + ) + { + typedef ExprTraits dest_traits; + return dest_traits().size(dest); + } + + matrix_size hack_actual_size( + matrix_type& /*dest*/, const SrcT& src, matrix_result_tag + ) + { + typedef ExprTraits src_traits; + return src_traits().size(src); + } + + matrix_size CheckOrResize( + matrix_type& dest, const SrcT& src, cml::resizable_tag) + { +#if defined(CML_AUTOMATIC_MATRIX_RESIZE_ON_ASSIGNMENT) + /* Get the size of src. This also causes src to check its size: */ + matrix_size N = hack_actual_size( + dest, src, typename src_traits::result_tag()); + + /* Set the destination matrix's size: */ + dest.resize(N.first,N.second); +#else + matrix_size N = CheckedSize(dest,src,dynamic_size_tag()); +#endif + return N; + } + + matrix_size CheckOrResize( + matrix_type& dest, const SrcT& src, cml::not_resizable_tag) + { + return CheckedSize(dest,src,dynamic_size_tag()); + } + + + public: + + + /** Use a loop for dynamic-sized matrix assignment. + * + * @note The target matrix must already have the correct size. + * + * @todo This needs to be specialized for efficient row-major or col-major + * layout access. + */ + void operator()(matrix_type& dest, const SrcT& src, cml::dynamic_size_tag) + { + typedef ExprTraits src_traits; + matrix_size N = this->CheckOrResize( + dest,src,typename matrix_type::resizing_tag()); + for(size_t i = 0; i < N.first; ++i) { + for(size_t j = 0; j < N.second; ++j) { + OpT().apply(dest(i,j), src_traits().get(src,i,j)); + /* Note: we don't need get(), since dest is a matrix. */ + } + } + } +}; + +} + +/** This constructs an assignment unroller for fixed-size arrays. + * + * The operator must be an assignment op (otherwise, this doesn't make any + * sense). Also, automatic unrolling is only performed for fixed-size + * matrices; a loop is used for dynamic-sized matrices. + * + * @sa cml::matrix + * @sa cml::et::OpAssign + * + * @bug Need to verify that OpT is actually an assignment operator. + */ +template +inline void UnrollAssignment(cml::matrix& dest, const SrcT& src) +{ + /* Record the destination matrix type, and the expression traits: */ + typedef cml::matrix matrix_type; + + /* Record the type of the unroller: */ + typedef detail::MatrixAssignmentUnroller unroller; + + /* Finally, do the unroll call: */ + unroller()(dest, src, typename matrix_type::size_tag()); + /* XXX It may make sense to unroll if either side is a fixed size. */ +} + +} // namespace et +} // namespace cml + +#endif + +// ------------------------------------------------------------------------- +// vim:ft=cpp diff --git a/Lib/Include/CML/matvec/matvec_mul.h b/Lib/Include/CML/matvec/matvec_mul.h new file mode 100644 index 0000000..5f5ea92 --- /dev/null +++ b/Lib/Include/CML/matvec/matvec_mul.h @@ -0,0 +1,285 @@ +/* -*- C++ -*- ------------------------------------------------------------ + +Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/ + +The Configurable Math Library (CML) is distributed under the terms of the +Boost Software License, v1.0 (see cml/LICENSE for details). + + *-----------------------------------------------------------------------*/ +/** @file + * @brief Multiply a matrix and a vector. + * + * @todo Implement smarter temporary generation. + * + * @todo Does it make sense to put mat-vec multiplication as a node into the + * expression tree? + * + * @internal This does not need to return an expression type, since the + * temporary generation for the matrix result is handled automatically by the + * compiler. i.e. when used in an expression, the result is automatically + * included in the expression tree as a temporary by the compiler. + */ + +#ifndef matvec_mul_h +#define matvec_mul_h + +#include +#include +#include +#include + +/* This is used below to create a more meaningful compile-time error when + * mat-vec mul is not provided with the right arguments: + */ +struct mvmul_expects_one_matrix_and_one_vector_arg_error; +struct mvmul_expects_one_vector_and_one_matrix_arg_error; + +namespace cml { +namespace detail { + +/* For choosing the proper multiplication order: */ +typedef true_type mul_Ax; +typedef false_type mul_xA; + +/** Compute y = A*x. */ +template inline +typename et::MatVecPromote< + typename et::ExprTraits::result_type, + typename et::ExprTraits::result_type +>::temporary_type +mul(const LeftT& A, const RightT& x, mul_Ax) +{ + /* Shorthand: */ + typedef et::ExprTraits left_traits; + typedef et::ExprTraits right_traits; + typedef typename left_traits::result_tag left_result; + typedef typename right_traits::result_tag right_result; + + /* mul()[A*x] requires a matrix and a vector expression: */ + CML_STATIC_REQUIRE_M( + (same_type::is_true + && same_type::is_true), + mvmul_expects_one_matrix_and_one_vector_arg_error); + /* Note: parens are required here so that the preprocessor ignores the + * commas. + */ + + /* Get result type: */ + typedef typename et::MatVecPromote< + typename left_traits::result_type, + typename right_traits::result_type + >::temporary_type result_type; + + /* Record size type: */ + typedef typename result_type::size_tag size_tag; + + /* Check the size: */ + size_t N = et::CheckedSize(A, x, size_tag()); + + /* Initialize the new vector: */ + result_type y; cml::et::detail::Resize(y, N); + + /* Compute y = A*x: */ + typedef typename result_type::value_type sum_type; + for(size_t i = 0; i < N; ++i) { + /* XXX This should be unrolled. */ + sum_type sum(A(i,0)*x[0]); + for(size_t k = 1; k < x.size(); ++k) { + sum += (A(i,k)*x[k]); + } + y[i] = sum; + } + + return y; +} + +/** Compute y = x*A. */ +template inline +typename et::MatVecPromote< + typename et::ExprTraits::result_type, + typename et::ExprTraits::result_type +>::temporary_type +mul(const LeftT& x, const RightT& A, mul_xA) +{ + /* Shorthand: */ + typedef et::ExprTraits left_traits; + typedef et::ExprTraits right_traits; + typedef typename left_traits::result_tag left_result; + typedef typename right_traits::result_tag right_result; + + /* mul()[x*A] requires a vector and a matrix expression: */ + CML_STATIC_REQUIRE_M( + (same_type::is_true + && same_type::is_true), + mvmul_expects_one_vector_and_one_matrix_arg_error); + /* Note: parens are required here so that the preprocessor ignores the + * commas. + */ + + /* Get result type: */ + typedef typename et::MatVecPromote< + typename left_traits::result_type, + typename right_traits::result_type + >::temporary_type result_type; + + /* Record size type: */ + typedef typename result_type::size_tag size_tag; + + /* Check the size: */ + size_t N = et::CheckedSize(x, A, size_tag()); + + /* Initialize the new vector: */ + result_type y; cml::et::detail::Resize(y, N); + + /* Compute y = x*A: */ + typedef typename result_type::value_type sum_type; + for(size_t i = 0; i < N; ++i) { + /* XXX This should be unrolled. */ + sum_type sum(x[0]*A(0,i)); + for(size_t k = 1; k < x.size(); ++k) { + sum += (x[k]*A(k,i)); + } + y[i] = sum; + } + + return y; +} + +} // namespace detail + + +/** operator*() for a matrix and a vector. */ +template +inline typename et::MatVecPromote< + matrix, vector +>::temporary_type +operator*(const matrix& left, + const vector& right) +{ + return detail::mul(left,right,detail::mul_Ax()); +} + +/** operator*() for a matrix and a VectorXpr. */ +template +inline typename et::MatVecPromote< + matrix, typename XprT::result_type +>::temporary_type +operator*(const matrix& left, + const et::VectorXpr& right) +{ + /* Generate a temporary, and compute the right-hand expression: */ + typename et::VectorXpr::temporary_type right_tmp; + cml::et::detail::Resize(right_tmp,right.size()); + right_tmp = right; + + return detail::mul(left,right_tmp,detail::mul_Ax()); +} + +/** operator*() for a MatrixXpr and a vector. */ +template +inline typename et::MatVecPromote< + typename XprT::result_type, vector +>::temporary_type +operator*(const et::MatrixXpr& left, + const vector& right) +{ + /* Generate a temporary, and compute the left-hand expression: */ + typename et::MatrixXpr::temporary_type left_tmp; + cml::et::detail::Resize(left_tmp,left.rows(),left.cols()); + left_tmp = left; + + return detail::mul(left_tmp,right,detail::mul_Ax()); +} + +/** operator*() for a MatrixXpr and a VectorXpr. */ +template +inline typename et::MatVecPromote< + typename XprT1::result_type, typename XprT2::result_type +>::temporary_type +operator*(const et::MatrixXpr& left, + const et::VectorXpr& right) +{ + /* Generate a temporary, and compute the left-hand expression: */ + typename et::MatrixXpr::temporary_type left_tmp; + cml::et::detail::Resize(left_tmp,left.rows(),left.cols()); + left_tmp = left; + + /* Generate a temporary, and compute the right-hand expression: */ + typename et::VectorXpr::temporary_type right_tmp; + cml::et::detail::Resize(right_tmp,right.size()); + right_tmp = right; + + return detail::mul(left_tmp,right_tmp,detail::mul_Ax()); +} + +/** operator*() for a vector and a matrix. */ +template +inline typename et::MatVecPromote< + vector, matrix +>::temporary_type +operator*(const vector& left, + const matrix& right) +{ + return detail::mul(left,right,detail::mul_xA()); +} + +/** operator*() for a vector and a MatrixXpr. */ +template +inline typename et::MatVecPromote< + typename XprT::result_type, vector +>::temporary_type +operator*(const vector& left, + const et::MatrixXpr& right) +{ + /* Generate a temporary, and compute the right-hand expression: */ + typename et::MatrixXpr::temporary_type right_tmp; + cml::et::detail::Resize(right_tmp,right.rows(),right.cols()); + right_tmp = right; + + return detail::mul(left,right_tmp,detail::mul_xA()); +} + +/** operator*() for a VectorXpr and a matrix. */ +template +inline typename et::MatVecPromote< + typename XprT::result_type, matrix +>::temporary_type +operator*(const et::VectorXpr& left, + const matrix& right) +{ + /* Generate a temporary, and compute the left-hand expression: */ + typename et::VectorXpr::temporary_type left_tmp; + cml::et::detail::Resize(left_tmp,left.size()); + left_tmp = left; + + return detail::mul(left_tmp,right,detail::mul_xA()); +} + +/** operator*() for a VectorXpr and a MatrixXpr. */ +template +inline typename et::MatVecPromote< + typename XprT1::result_type, typename XprT2::result_type +>::temporary_type +operator*(const et::VectorXpr& left, + const et::MatrixXpr& right) +{ + /* Generate a temporary, and compute the left-hand expression: */ + typename et::VectorXpr::temporary_type left_tmp; + cml::et::detail::Resize(left_tmp,left.size()); + left_tmp = left; + + /* Generate a temporary, and compute the right-hand expression: */ + typename et::MatrixXpr::temporary_type right_tmp; + cml::et::detail::Resize(right_tmp,right.rows(),right.cols()); + right_tmp = right; + + return detail::mul(left_tmp,right_tmp,detail::mul_xA()); +} + +} // namespace cml + +#endif + +// ------------------------------------------------------------------------- +// vim:ft=cpp diff --git a/Lib/Include/CML/matvec/matvec_promotions.h b/Lib/Include/CML/matvec/matvec_promotions.h new file mode 100644 index 0000000..3b85d1f --- /dev/null +++ b/Lib/Include/CML/matvec/matvec_promotions.h @@ -0,0 +1,92 @@ +/* -*- C++ -*- ------------------------------------------------------------ + +Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/ + +The Configurable Math Library (CML) is distributed under the terms of the +Boost Software License, v1.0 (see cml/LICENSE for details). + + *-----------------------------------------------------------------------*/ +/** @file + * @brief + * + * Defines promotions for the vectors resulting from matrix/vector or + * vector/matrix ops. + * + * @sa matvec_ops::mvmul + */ + +#ifndef matvec_promotions_h +#define matvec_promotions_h + +#include +#include + +namespace cml { +namespace et { + +/* Default mat/vec type promotion template. */ +template struct MatVecPromote; + +/** Type promotion for a matrix and a vector. */ +template< + typename E1, class AT1, typename BO, typename L, + typename E2, class AT2> +struct MatVecPromote< cml::matrix, cml::vector > +{ + typedef cml::matrix matrix_type; + typedef cml::vector vector_type; + + /* Promote the arrays: */ + typedef typename ArrayPromote< + typename matrix_type::array_type, + typename vector_type::array_type + >::type promoted_array; + + /* The deduced vector result type: */ + typedef cml::vector< + typename promoted_array::value_type, + typename promoted_array::generator_type + > type; + + /* The deduced temporary type: */ + typedef typename type::temporary_type temporary_type; + /* Note: this is to avoid an "incomplete type" error from ICC9, which + * can't handle e.g. :::: when is a template type. + */ +}; + +/** Type promotion for a vector and a matrix. */ +template< + typename E1, class AT1, + typename E2, class AT2, typename BO, typename L> +struct MatVecPromote< cml::vector, cml::matrix > +{ + typedef cml::vector vector_type; + typedef cml::matrix matrix_type; + + /* Promote the arrays: */ + typedef typename ArrayPromote< + typename vector_type::array_type, + typename matrix_type::array_type + >::type promoted_array; + + /* The deduced vector result type: */ + typedef cml::vector< + typename promoted_array::value_type, + typename promoted_array::generator_type + > type; + + /* The deduced temporary type: */ + typedef typename type::temporary_type temporary_type; + /* Note: this is to avoid an "incomplete type" error from ICC9, which + * can't handle e.g. :::: when is a template type. + */ +}; + +} // namespace et +} // namespace cml + +#endif + +// ------------------------------------------------------------------------- +// vim:ft=cpp diff --git a/Lib/Include/CML/quaternion.h b/Lib/Include/CML/quaternion.h new file mode 100644 index 0000000..eee3da8 --- /dev/null +++ b/Lib/Include/CML/quaternion.h @@ -0,0 +1,67 @@ +/* -*- C++ -*- ------------------------------------------------------------ + +Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/ + +The Configurable Math Library (CML) is distributed under the terms of the +Boost Software License, v1.0 (see cml/LICENSE for details). + + *-----------------------------------------------------------------------*/ +/** @file + * @brief + */ + +#ifndef cml_quaternion_h +#define cml_quaternion_h + +#include + +namespace cml { + +// NOTE: 'scale' constant no longer used. + +/** Helper to specify v1^v2 multiplication order. */ +struct positive_cross { + /*enum { scale = 1 };*/ +}; + +/** Helper to specify v2^v1 multiplication order. */ +struct negative_cross { + /*enum { scale = -1 };*/ +}; + +/** Helper to specify scalar-first quaternion ordering. */ +struct scalar_first { + enum { W, X, Y, Z }; +}; + +/** Helper to specify vector-first quaternion ordering. */ +struct vector_first { + enum { X, Y, Z, W }; +}; + +/** A configurable quaternion. + * + * This class encapsulates the notion of a quaternion. The ArrayType + * template argument can be used to select the type of array to be used as + * internal storage for the quaternion's coefficients. + * + * @note Quaternions with two different orders cannot be used in the same + * expression. + */ +template, + class Order = scalar_first, class Cross = positive_cross> class quaternion; + +} // namespace cml + +#include +#include +#include +#include +#include +#include +#include +#include +#endif + +// ------------------------------------------------------------------------- +// vim:ft=cpp diff --git a/Lib/Include/CML/quaternion/conjugate.h b/Lib/Include/CML/quaternion/conjugate.h new file mode 100644 index 0000000..63bdcb0 --- /dev/null +++ b/Lib/Include/CML/quaternion/conjugate.h @@ -0,0 +1,197 @@ +/* -*- C++ -*- ------------------------------------------------------------ + +Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/ + +The Configurable Math Library (CML) is distributed under the terms of the +Boost Software License, v1.0 (see cml/LICENSE for details). + + *-----------------------------------------------------------------------*/ +/** @file + * @brief Defines an operator for quaternion conjugation. + */ + +#ifndef conjugate_h +#define conjugate_h + +#include + +namespace cml { +namespace et { + +/** An expression node for conjugating a quaternion. */ +template +class ConjugateOp +{ + public: + + typedef ConjugateOp expr_type; + + /* Record ary-ness of the expression: */ + typedef unary_expression expr_ary; + + /* Copy the expression by value into higher-up expressions: */ + typedef expr_type expr_const_reference; + + typedef typename ExprT::value_type value_type; + typedef quaternion_result_tag result_tag; + typedef typename ExprT::size_tag size_tag; + + /* Store the expression traits for the subexpression: */ + typedef ExprTraits expr_traits; + + /* Reference type for the subexpression: */ + typedef typename expr_traits::const_reference expr_reference; + + /* Get the result type (same as for subexpression): */ + typedef typename expr_traits::result_type result_type; + + /* For matching by assignability: */ + typedef cml::et::not_assignable_tag assignable_tag; + + /* Get the temporary type: */ + typedef typename result_type::temporary_type temporary_type; + + /* Get the vector type: */ + typedef typename result_type::vector_type vector_type; + + /* Get the imaginary part type: */ + typedef typename vector_type::subvector_type imaginary_type; + + /* Record the order type: */ + typedef typename result_type::order_type order_type; + + + public: + + /** Record result size as an enum. */ + enum { array_size = ExprT::array_size }; + + /** Localize the ordering as an enum. */ + enum { + W = order_type::W, + X = order_type::X, + Y = order_type::Y, + Z = order_type::Z + }; + + + public: + + /** Return the real part of the expression. */ + value_type real() const { + return m_expr.real(); + } + + /** Return the vector part of the expression. */ + imaginary_type imaginary() const { + return -m_expr.imaginary(); + } + + /** Return the Cayley norm of the expression. */ + value_type norm() const { + return length_squared(); + } + + /** Return square of the quaternion length. */ + value_type length_squared() const { + return dot( + QuaternionXpr(*this), + QuaternionXpr(*this)); + } + + /** Return the quaternion length. */ + value_type length() const { + return std::sqrt(length_squared()); + } + + /** Return the result as a normalized quaternion. */ + temporary_type normalize() const { + temporary_type q(QuaternionXpr(*this)); + return q.normalize(); + } + + /** Compute conjugated result at index i. + * + * The conjugate of quaternion s + v is s - v. + */ + value_type operator[](size_t i) const { + return (i == W) ? m_expr[W] : - m_expr[i] ; + } + + + public: + + /** Return size of this expression (same as argument's size). */ + size_t size() const { + return m_expr.size(); + } + + /** Return reference to contained expression. */ + expr_reference expression() const { return m_expr; } + + + public: + + /** Construct from the subexpression. */ + explicit ConjugateOp(expr_reference expr) : m_expr(expr) {} + + /** Copy constructor. */ + ConjugateOp(const expr_type& e) : m_expr(e.m_expr) {} + + + protected: + + expr_reference m_expr; + + + private: + + /* Cannot be assigned to: */ + expr_type& operator=(const expr_type&); +}; + +/** Expression traits class for ConjugateOp<>. */ +template +struct ExprTraits< ConjugateOp > +{ + typedef ConjugateOp expr_type; + typedef ExprT arg_type; + + typedef typename expr_type::value_type value_type; + typedef typename expr_type::expr_const_reference const_reference; + typedef typename expr_type::result_tag result_tag; + typedef typename expr_type::size_tag size_tag; + typedef typename expr_type::result_type result_type; + typedef typename expr_type::assignable_tag assignable_tag; + typedef expr_node_tag node_tag; + + value_type get(const expr_type& v, size_t i) const { return v[i]; } + size_t size(const expr_type& e) const { return e.size(); } +}; + +} // namespace et + +/** Conjugation of a quaternion. */ +template inline +et::QuaternionXpr< et::ConjugateOp< quaternion > > +conjugate(const quaternion& arg) +{ + typedef et::ConjugateOp< quaternion > ExprT; + return et::QuaternionXpr(ExprT(arg)); +} + +/** Conjugation of a QuaternionXpr. */ +template inline +et::QuaternionXpr< et::ConjugateOp > +conjugate(QUATXPR_ARG_TYPE arg) +{ + typedef et::ConjugateOp ExprT; + return et::QuaternionXpr(ExprT(arg.expression())); +} + +} // namespace cml + +#endif + +// ------------------------------------------------------------------------- +// vim:ft=cpp diff --git a/Lib/Include/CML/quaternion/inverse.h b/Lib/Include/CML/quaternion/inverse.h new file mode 100644 index 0000000..8387c90 --- /dev/null +++ b/Lib/Include/CML/quaternion/inverse.h @@ -0,0 +1,268 @@ +/* -*- C++ -*- ------------------------------------------------------------ + +Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/ + +The Configurable Math Library (CML) is distributed under the terms of the +Boost Software License, v1.0 (see cml/LICENSE for details). + + *-----------------------------------------------------------------------*/ +/** @file + * @brief Defines an operator for quaternion inverse. + */ + +#ifndef quaternion_inverse_h +#define quaternion_inverse_h + +#include +#include + +namespace cml { +namespace et { + +/** An expression node for inverting a quaternion. + * + * This internally creates a ConjugateOp node to process the conjugate + * of the given expression. The values produced by the ConjugateOp are then + * divided by the Cayley norm of the expression on the fly. + */ +template +class QuaternionInverseOp +{ + public: + + typedef QuaternionInverseOp expr_type; + + /* Record ary-ness of the expression: */ + typedef unary_expression expr_ary; + + /* Copy the expression by value into higher-up expressions: */ + typedef expr_type expr_const_reference; + + /* The subexpression is a ConjugateOp: */ + typedef et::ConjugateOp subexpression_type; + typedef ExprTraits expr_traits; + + /* Get traits for the ExprT: */ + typedef ExprTraits arg_traits; + typedef typename arg_traits::const_reference arg_reference; + + typedef typename subexpression_type::value_type value_type; + typedef quaternion_result_tag result_tag; + typedef typename subexpression_type::size_tag size_tag; + + /* Reference type for the subexpression: */ + typedef typename expr_traits::const_reference expr_reference; + + /* Get the result type (same as for subexpression): */ + typedef typename expr_traits::result_type result_type; + + /* For matching by assignability: */ + typedef cml::et::not_assignable_tag assignable_tag; + + /* Get the temporary type: */ + typedef typename result_type::temporary_type temporary_type; + + /* Get the vector type: */ + typedef typename result_type::vector_type vector_type; + + /* Get the imaginary part type: */ + typedef typename vector_type::subvector_type imaginary_type; + + /* Record the order type: */ + typedef typename result_type::order_type order_type; + + + public: + + /** Record result size as an enum. */ + enum { array_size = ExprT::array_size }; + + /** Localize the ordering as an enum. */ + enum { + W = order_type::W, + X = order_type::X, + Y = order_type::Y, + Z = order_type::Z + }; + + + public: + + /** Return the real part of the expression. */ + value_type real() const { + return m_expr.real()/m_norm; + } + + /** Return the vector part of the expression. + * + * @todo This could be returned as a VectorXpr also. + */ + imaginary_type imaginary() const { + return m_expr.imaginary()/m_norm; + } + + /** Return the Cayley norm of the expression. */ + value_type norm() const { + return length_squared(); + } + + /** Return square of the quaternion length. */ + value_type length_squared() const { + return dot( + QuaternionXpr(*this), + QuaternionXpr(*this)); + } + + /** Return the quaternion length. */ + value_type length() const { + return std::sqrt(length_squared()); + } + + /** Return the result as a normalized quaternion. */ + temporary_type normalize() const { + temporary_type q(QuaternionXpr(*this)); + return q.normalize(); + } + + /** Compute inverse result at index i. + * + * The inverse of a quaternion p is ~p/norm(p). + */ + value_type operator[](size_t i) const { + return m_expr[i]/m_norm; + } + + + public: + + /** Return size of this expression (same as argument's size). */ + size_t size() const { + return m_expr.size(); + } + + /** Return reference to contained expression. */ + expr_reference expression() const { return m_expr; } + + + public: + + /** Construct from an input expression. */ + explicit QuaternionInverseOp(arg_reference arg) + //: m_expr(arg), m_norm(cml::norm(arg)) {} + : m_expr(arg), m_norm(arg.norm()) {} + + /** Copy constructor. */ + QuaternionInverseOp(const expr_type& e) + : m_expr(e.m_expr), m_norm(e.m_norm) {} + + + protected: + + subexpression_type m_expr; + value_type m_norm; + + + private: + + /* Cannot be assigned to: */ + expr_type& operator=(const expr_type&); +}; + +/** Expression traits class for QuaternionInverseOp<>. */ +template +struct ExprTraits< QuaternionInverseOp > +{ + typedef QuaternionInverseOp expr_type; + typedef ExprT arg_type; + + typedef typename expr_type::value_type value_type; + typedef typename expr_type::expr_const_reference const_reference; + typedef typename expr_type::result_tag result_tag; + typedef typename expr_type::size_tag size_tag; + typedef typename expr_type::result_type result_type; + typedef typename expr_type::assignable_tag assignable_tag; + typedef expr_node_tag node_tag; + + value_type get(const expr_type& v, size_t i) const { return v[i]; } + size_t size(const expr_type& e) const { return e.size(); } +}; + +} // namespace et + +/** Inverse of a quaternion. */ +template inline +et::QuaternionXpr< et::QuaternionInverseOp< quaternion > > +inverse(const quaternion& arg) +{ + typedef et::QuaternionInverseOp< quaternion > ExprT; + return et::QuaternionXpr(ExprT(arg)); +} + +/** Inverse of a QuaternionXpr. */ +template inline +et::QuaternionXpr< et::QuaternionInverseOp > +inverse(QUATXPR_ARG_TYPE arg) +{ + typedef et::QuaternionInverseOp ExprT; + return et::QuaternionXpr(ExprT(arg.expression())); +} + +/* NOTE: Quaternion division no longer supported, but I'm leaving the + code here for reference (Jesse) */ + +#if 0 +/** Declare div taking two quaternion operands. */ +template +inline typename et::QuaternionPromote< + quaternion, quaternion +>::temporary_type +operator/( + const quaternion& left, + const quaternion& right) +{ + return left*inverse(right); +} + +/** Declare div taking a quaternion and a et::QuaternionXpr. */ +template +inline typename et::QuaternionPromote< + quaternion, typename XprT::result_type +>::temporary_type +operator/( + const quaternion& left, + QUATXPR_ARG_TYPE right) +{ + return left*inverse(right); +} + +/** Declare div taking an et::QuaternionXpr and a quaternion. */ +template +inline typename et::QuaternionPromote< + typename XprT::result_type, quaternion +>::temporary_type +operator/( + QUATXPR_ARG_TYPE left, + const quaternion& right) +{ + return left*inverse(right); +} + +/** Declare div taking two et::QuaternionXpr operands. */ +template +inline typename et::QuaternionPromote< + typename XprT1::result_type, typename XprT2::result_type +>::temporary_type +operator/( + QUATXPR_ARG_TYPE_N(1) left, + QUATXPR_ARG_TYPE_N(2) right) +{ + return left*inverse(right); +} +#endif + +} // namespace cml + +#endif + +// ------------------------------------------------------------------------- +// vim:ft=cpp diff --git a/Lib/Include/CML/quaternion/quaternion.h b/Lib/Include/CML/quaternion/quaternion.h new file mode 100644 index 0000000..6f320f3 --- /dev/null +++ b/Lib/Include/CML/quaternion/quaternion.h @@ -0,0 +1,526 @@ +/* -*- C++ -*- ------------------------------------------------------------ + +Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/ + +The Configurable Math Library (CML) is distributed under the terms of the +Boost Software License, v1.0 (see cml/LICENSE for details). + + *-----------------------------------------------------------------------*/ +/** @file + * @brief + * + * @todo Return a VectorXpr adaptor from the imaginary() method of + * quaternion and the expression node types. + * + * @todo swap multiplication order based upon template param + * + * @todo change element order based upon template param + */ + +#ifndef quaternion_h +#define quaternion_h + +#include +#include +#include +#include + +/* This is used below to create a more meaningful compile-time error when + * the quaternion class is not created with a fixed-size 4-vector: + */ +struct quaternion_requires_fixed_size_array_type_error; + +namespace cml { + +/** A configurable quaternion type. + * + * @note Quaternions with two different orders cannot be used in the same + * expression. + */ +template< + typename Element, + class ArrayType, + class Order, + class Cross +> +class quaternion +{ + /* The ArrayType must be fixed<> or external<>: */ + CML_STATIC_REQUIRE_M( + (same_type< ArrayType, fixed<> >::is_true + || same_type< ArrayType, external<> >::is_true), + quaternion_requires_fixed_size_array_type_error); + + public: + + /* Shorthand for the array type generator: */ + typedef ArrayType storage_type; + typedef typename ArrayType::template rebind<4>::other generator_type; + + /* Vector representing the quaternion. Use the rebinding template to + * set the vector size: + */ + typedef vector vector_type; + + /* Vector temporary type: */ + typedef typename vector_type::temporary_type vector_temporary; + + /* Quaternion order: */ + typedef Order order_type; + + /* Quaternion multiplication order: */ + typedef Cross cross_type; + + /* Scalar type representing the scalar part: */ + typedef typename vector_type::value_type value_type; + typedef typename vector_type::reference reference; + typedef typename vector_type::const_reference const_reference; + /* XXX Need to verify that this is a true scalar type. */ + + /* The quaternion type: */ + typedef quaternion + quaternion_type; + + /* For integration into the expression template code: */ + typedef quaternion_type expr_type; + + /* For integration into the expression template code: */ + typedef quaternion< + Element, typename vector_temporary::storage_type, + order_type, cross_type> temporary_type; + + /* For integration into the expression templates code: */ + typedef quaternion_type& expr_reference; + typedef const quaternion_type& expr_const_reference; + + /* For matching by storage type: */ + typedef typename vector_type::memory_tag memory_tag; + + /* For matching by size type: */ + typedef typename vector_type::size_tag size_tag; + + /* Get the imaginary part type: */ + typedef typename vector_temporary::subvector_type imaginary_type; + + /* For matching by result-type: */ + typedef cml::et::quaternion_result_tag result_tag; + + /* For matching by assignability: */ + typedef cml::et::assignable_tag assignable_tag; + + + public: + + /** Record result size as an enum. */ + enum { array_size = 4 }; + + /** Localize the ordering as an enum. */ + enum { + W = order_type::W, + X = order_type::X, + Y = order_type::Y, + Z = order_type::Z + }; + + + public: + + /** Return the scalar part. */ + value_type real() const { return m_q[W]; } + + /** Return the imaginary vector. */ + imaginary_type imaginary() const { + /* + imaginary_type v; + v[0] = m_q[X]; v[1] = m_q[Y]; v[2] = m_q[Z]; + return v; + */ + return imaginary_type(m_q[X], m_q[Y], m_q[Z]); + } + + /** Return the vector representing the quaternion. */ + const vector_type& as_vector() const { + return m_q; + } + + /** Return the Cayley norm of the quaternion. */ + value_type norm() const { + return length_squared(); + } + + /** Return square of the quaternion length. */ + value_type length_squared() const { + return cml::dot(*this,*this); + } + + /** Return the quaternion length. */ + value_type length() const { + return std::sqrt(length_squared()); + } + + /** Normalize this quaternion (divide by its length). + * + * @todo Make this return a QuaternionXpr. + */ + quaternion_type& normalize() { + return (*this /= length()); + } + + /** Set this quaternion to the conjugate. */ + quaternion_type& conjugate() { + return (*this) = cml::conjugate(*this); + } + + /** Set this quaternion to the inverse. */ + quaternion_type& inverse() { + return (*this) = cml::inverse(*this); + } + + /** Set this quaternion to the multiplicative identity. */ + quaternion_type& identity() { + m_q[W] = value_type(1); + m_q[X] = value_type(0); + m_q[Y] = value_type(0); + m_q[Z] = value_type(0); + return *this; + } + + /** Return the log of this quaternion. */ + temporary_type log( + value_type tolerance = epsilon::placeholder()) const + { + value_type a = acos_safe(real()); + value_type s = std::sin(a); + + if (s > tolerance) { + return temporary_type(value_type(0), imaginary() * (a / s)); + } else { + return temporary_type(value_type(0), imaginary()); + } + } + + /** + * Return the result of the exponential function as applied to + * this quaternion. + */ + temporary_type exp( + value_type tolerance = epsilon::placeholder()) const + { + imaginary_type v = imaginary(); + value_type a = cml::length(v); + + if (a > tolerance) { + return temporary_type(std::cos(a), v * (std::sin(a) / a)); + } else { + return temporary_type(std::cos(a), v); + } + } + + + /** Const access to the quaternion as a vector. */ + const_reference operator[](size_t i) const { return m_q[i]; } + + /** Mutable access to the quaternion as a vector. */ + reference operator[](size_t i) { return m_q[i]; } + + /** Fill quaternion with random elements. + * + * @warning This does not generate uniformly random rotations. + */ + void random(value_type min, value_type max) { + for (size_t i = 0; i < 4; ++i) { + m_q[i] = random_real(min,max); + } + } + + public: + + /** Default initializer. + * + * @note The default constructor cannot be used with an external<> + * array type. + */ + quaternion() {} + + /** Initializer for an external<> vector type. */ + quaternion(Element* const array) : m_q(array) {} + + /** Copy construct from the same type of quaternion. */ + quaternion(const quaternion_type& q) : m_q(q.m_q) {} + + /** Construct from a quaternion having a different array type. */ + template quaternion( + const quaternion& q) + : m_q(q.as_vector()) {} + + /** Copy construct from a QuaternionXpr. */ + template quaternion(QUATXPR_ARG_TYPE e) { + typedef typename XprT::order_type arg_order; + m_q[W] = e[arg_order::W]; + m_q[X] = e[arg_order::X]; + m_q[Y] = e[arg_order::Y]; + m_q[Z] = e[arg_order::Z]; + } + + + + /** Initialize from a 4-vector. + * + * If Order is scalar_first, then v[0] is the real part. Otherwise, + * v[3] is the real part. + */ + quaternion(const vector_type& v) : m_q(v) {} + + /** Initialize from an array of scalars. + * + * If Order is scalar_first, then v[0] is the real part. Otherwise, + * v[3] is the real part. + * + * @note The target vector must have CML_VEC_COPY_FROM_ARRAY + * implemented, so this cannot be used with external<> vectors. + */ + quaternion(const value_type v[4]) : m_q(v) {} + + /** Initialize from 4 scalars. + * + * If Order is scalar_first, then a is the real part, and (b,c,d) is + * the imaginary part. Otherwise, (a,b,c) is the imaginary part, and d + * is the real part. + */ + quaternion( + const value_type& a, const value_type& b, + const value_type& c, const value_type& d) + { + /* Call the overloaded assignment function: */ + assign(a, b, c, d, Order()); + } + + /** Initialize both the real and imaginary parts. + * + * The imaginary part is given by a 3-vector. Although the imaginary + * part is specified first, the proper coefficient order (vector or + * scalar first) is maintained. + */ + quaternion(const value_type& s, const imaginary_type& v) { + m_q[W] = s; m_q[X] = v[0]; m_q[Y] = v[1]; m_q[Z] = v[2]; + } + + /** Initialize both the real and imaginary parts. + * + * The imaginary part is given by a 3-vector. Although the imaginary + * part is specified second, the proper coefficient order (vector or + * scalar first) is maintained. + */ + quaternion(const imaginary_type& v, const value_type& s) { + m_q[W] = s; m_q[X] = v[0]; m_q[Y] = v[1]; m_q[Z] = v[2]; + } + + /** Initialize both the real and imaginary parts. + * + * The imaginary part is given by an array of scalars. Although the + * imaginary part is specified first, the proper coefficient order + * (vector or scalar first) is maintained. + */ + quaternion(const value_type v[3], const value_type& s) { + m_q[W] = s; m_q[X] = v[0]; m_q[Y] = v[1]; m_q[Z] = v[2]; + } + + /** Initialize both the real and imaginary parts. + * + * The imaginary part is given by an array of scalars. Although the + * imaginary part is specified second, the proper coefficient order + * (vector or scalar first) is maintained. + */ + quaternion(const value_type& s, const value_type v[3]) { + m_q[W] = s; m_q[X] = v[0]; m_q[Y] = v[1]; m_q[Z] = v[2]; + } + + + + /** Initialize from a VectorXpr. */ + template + quaternion(VECXPR_ARG_TYPE e) : m_q(e) {} + + /** Initialize both the real and imaginary parts. + * + * The imaginary part is initialized with a VectorXpr. + */ + template + quaternion(const value_type& s, VECXPR_ARG_TYPE e) { + m_q[W] = s; m_q[X] = e[0]; m_q[Y] = e[1]; m_q[Z] = e[2]; + } + + // @todo: Are we missing: + + // quaternion(VECXPR_ARG_TYPE e, const value_type& s) {} + + // Or is that covered elsewhere? + + /** In-place op from a quaternion. + * + * This assumes that _op_ is defined for both the quaternion's vector + * type and its scalar type. + */ +#define CML_QUAT_ASSIGN_FROM_QUAT(_op_) \ + template const quaternion_type& \ + operator _op_ (const quaternion& q) { \ + m_q[W] _op_ q[W]; \ + m_q[X] _op_ q[X]; \ + m_q[Y] _op_ q[Y]; \ + m_q[Z] _op_ q[Z]; \ + return *this; \ + } + + /** In-place op from a QuaternionXpr. + * + * This assumes that _op_ is defined for the quaternion's scalar type. + */ +#define CML_QUAT_ASSIGN_FROM_QUATXPR(_op_) \ + template quaternion_type& \ + operator _op_ (QUATXPR_ARG_TYPE e) { \ + typedef typename XprT::order_type arg_order; \ + m_q[W] _op_ e[arg_order::W]; \ + m_q[X] _op_ e[arg_order::X]; \ + m_q[Y] _op_ e[arg_order::Y]; \ + m_q[Z] _op_ e[arg_order::Z]; \ + return *this; \ + } + + /** In-place op from a scalar type. + * + * This assumes that _op_ is defined for the quaternion's scalar type. + */ +#define CML_QUAT_ASSIGN_FROM_SCALAR(_op_,_op_name_) \ + quaternion_type& operator _op_ (const value_type& s) { \ + typedef _op_name_ OpT; \ + OpT().apply(m_q[W],s); \ + OpT().apply(m_q[X],s); \ + OpT().apply(m_q[Y],s); \ + OpT().apply(m_q[Z],s); \ + return *this; \ + } + + CML_QUAT_ASSIGN_FROM_QUAT(=) + CML_QUAT_ASSIGN_FROM_QUAT(+=) + CML_QUAT_ASSIGN_FROM_QUAT(-=) + + CML_QUAT_ASSIGN_FROM_QUATXPR(=) + CML_QUAT_ASSIGN_FROM_QUATXPR(+=) + CML_QUAT_ASSIGN_FROM_QUATXPR(-=) + + CML_QUAT_ASSIGN_FROM_SCALAR(*=, cml::et::OpMulAssign) + CML_QUAT_ASSIGN_FROM_SCALAR(/=, cml::et::OpDivAssign) + +#undef CML_QUAT_ASSIGN_FROM_QUAT +#undef CML_QUAT_ASSIGN_FROM_QUATXPR +#undef CML_QUAT_ASSIGN_FROM_SCALAR + + /** Accumulated multiplication with a quaternion. + * + * Compute p = p * q for two quaternions p and q. + * + * @internal Using operator* here is okay, as long as cml/quaternion.h + * is included before using this method (the only supported case for + * end-user code). This is because modern compilers won't instantiate a + * method in a template class until it is used, and including the main + * header ensures all definitions are available before any possible use + * of this method. + */ + quaternion_type& operator*=(const quaternion_type& q) { + return (*this = *this * q); + } + + /** Accumulated multiplication with a quaternion expression. + * + * Compute p = p * e for a quaternion p and a quaternion expression e. + * + * @internal Using operator* here is okay, as long as cml/quaternion.h + * is included before using this method (the only supported case for + * end-user code). This is because modern compilers won't instantiate a + * method in a template class until it is used, and including the main + * header ensures all definitions are available before any possible use + * of this method. + */ + template quaternion_type& operator*=(QUATXPR_ARG_TYPE e) { + return (*this = *this * e); + } + + /** Return access to the data as a raw pointer. */ + typename vector_type::pointer data() { return m_q.data(); } + + /** Return access to the data as a const raw pointer. */ + const typename vector_type::pointer data() const { return m_q.data(); } + + + /* NOTE: Quaternion division no longer supported, but I'm leaving the + code here for reference (Jesse) */ + + #if 0 + /** Accumulated division with a quaternion. + * + * Compute p = p * inverse(q). + * + * @note Because quaternion multiplication is non-commutative, division + * is ambiguous. This method assumes a multiplication order consistent + * with the notational order; i.e. p = q / r means p = q*inverse(r). + * + * @internal Using operator* and cml::inverse here is okay, as long as + * cml/quaternion.h is included before using this method (the only + * supported case for end-user code). This is because modern compilers + * won't instantiate a method in a template class until it is used, and + * including the main header ensures all definitions are available + * before any possible use of this method. + */ + quaternion_type& operator/=(const quaternion_type& q) { + return (*this = *this * cml::inverse(q)); + } + + /** Accumulated division with a quaternion expression. + * + * Compute p = p * inverse(q). + * + * @note Because quaternion multiplication is non-commutative, division + * is ambiguous. This method assumes a multiplication order consistent + * with the notational order; i.e. p = q / r means p = q*inverse(r). + * + * @internal Using operator* and cml::inverse here is okay, as long as + * cml/quaternion.h is included before using this method (the only + * supported case for end-user code). This is because modern compilers + * won't instantiate a method in a template class until it is used, and + * including the main header ensures all definitions are available + * before any possible use of this method. + */ + template quaternion_type& operator/=(QUATXPR_ARG_TYPE e) { + return (*this = *this * cml::inverse(e)); + } + #endif + + + protected: + + /** Overloaded function to assign the quaternion from 4 scalars. */ + void assign(const value_type& a, const value_type& b, + const value_type& c, const value_type& d, scalar_first) + { + m_q[W] = a; m_q[X] = b; m_q[Y] = c; m_q[Z] = d; + } + + /** Overloaded function to assign the quaternion from 4 scalars. */ + void assign(const value_type& a, const value_type& b, + const value_type& c, const value_type& d, vector_first) + { + m_q[X] = a; m_q[Y] = b; m_q[Z] = c; m_q[W] = d; + } + + + protected: + + vector_type m_q; +}; + +} // namespace cml + +#endif + +// ------------------------------------------------------------------------- +// vim:ft=cpp diff --git a/Lib/Include/CML/quaternion/quaternion_comparison.h b/Lib/Include/CML/quaternion/quaternion_comparison.h new file mode 100644 index 0000000..c1e6d0c --- /dev/null +++ b/Lib/Include/CML/quaternion/quaternion_comparison.h @@ -0,0 +1,216 @@ +/* -*- C++ -*- ------------------------------------------------------------ + +Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/ + +The Configurable Math Library (CML) is distributed under the terms of the +Boost Software License, v1.0 (see cml/LICENSE for details). + + *-----------------------------------------------------------------------*/ +/** @file + * @brief + */ + +#ifndef quaternion_comparison_h +#define quaternion_comparison_h + +#include +#include + +/* This is used below to create a more meaningful compile-time error when + * quaternion_comparison is not provided with quaternion or QuaternionExpr arguments: + */ +struct quaternion_comparison_expects_quaternion_args_error; + +#define CML_QUAT_QUAT_ORDER(_order_, _op_, _OpT_) \ +template< \ + typename E1, class AT1, typename E2, class AT2, class O, class C > \ +inline bool \ +_op_ ( \ + const quaternion& left, \ + const quaternion& right) \ +{ \ + return detail::quaternion_##_order_ (left, right, _OpT_ ()); \ +} + +#define CML_QUAT_QUATXPR_ORDER(_order_, _op_, _OpT_) \ +template \ +inline bool \ +_op_ ( \ + const quaternion& left, \ + QUATXPR_ARG_TYPE right) \ +{ \ + return detail::quaternion_##_order_ (left, right, \ + _OpT_ ()); \ +} + +#define CML_QUATXPR_QUAT_ORDER(_order_, _op_, _OpT_) \ +template \ +inline bool \ +_op_ ( \ + QUATXPR_ARG_TYPE left, \ + const quaternion& right) \ +{ \ + return detail::quaternion_##_order_ (left, right, \ + _OpT_ ()); \ +} + +#define CML_QUATXPR_QUATXPR_ORDER(_order_, _op_, _OpT_) \ +template \ +inline bool \ +_op_ ( \ + QUATXPR_ARG_TYPE_N(1) left, \ + QUATXPR_ARG_TYPE_N(2) right) \ +{ \ + return detail::quaternion_##_order_ (left, right, \ + _OpT_ < \ + typename XprT1::value_type, \ + typename XprT2::value_type>()); \ +} + + +namespace cml { +namespace detail { + +/** Quaternion strict weak ordering relationship. + * + * OpT must implement a strict weak order on the quaternion element type. + * operator< and operator> on integer and floating-point types are + * examples. + */ +template +inline bool +quaternion_weak_order(const LeftT& left, const RightT& right, OpT) +{ + /* Shorthand: */ + typedef et::ExprTraits left_traits; + typedef et::ExprTraits right_traits; + + /* quaternion_comparison() requires quaternion expressions: */ + CML_STATIC_REQUIRE_M( + (et::QuaternionExpressions::is_true), + quaternion_comparison_expects_quaternion_args_error); + /* Note: parens are required here so that the preprocessor ignores the + * commas: + */ + + typedef typename et::QuaternionPromote< + typename left_traits::result_type, + typename right_traits::result_type + >::type result_type; + + for(ssize_t i = 0; i < result_type::array_size; ++ i) { + + if(OpT().apply( + left_traits().get(left,i), + right_traits().get(right,i) + )) + { + /* If weak order (a < b) is satisfied, return true: */ + return true; + } else if(OpT().apply( + right_traits().get(right,i), + left_traits().get(left,i) + )) + { + /* If !(b < a), then return false: */ + return false; + } else { + + /* Have !(a < b) && !(b < a) <=> (a >= b && b >= a) <=> (a == b). + * so need to test next element: + */ + continue; + } + } + /* XXX Can this be unrolled in any reasonable way? */ + + /* If we get here, then left == right: */ + return false; +} + +/** Quaternion total order relationship. + * + * OpT must implement a total order on the quaternion element type. operator<= + * and operator>= on integer and floating-point types are examples. + */ +template +inline bool +quaternion_total_order(const LeftT& left, const RightT& right, OpT) +{ + /* Shorthand: */ + typedef et::ExprTraits left_traits; + typedef et::ExprTraits right_traits; + + /* quaternion_comparison() requires quaternion expressions: */ + CML_STATIC_REQUIRE_M( + (et::QuaternionExpressions::is_true), + quaternion_comparison_expects_quaternion_args_error); + /* Note: parens are required here so that the preprocessor ignores the + * commas: + */ + + typedef typename et::QuaternionPromote< + typename left_traits::result_type, + typename right_traits::result_type + >::type result_type; + + for(ssize_t i = 0; i < result_type::array_size; ++ i) { + + /* Test total order: */ + if(OpT().apply( + left_traits().get(left,i), + right_traits().get(right,i) + )) + { + /* Automatically true if weak order (a <= b) && !(b <= a) <=> + * (a <= b) && (b > a) <=> (a < b) is satisfied: + */ + if(!OpT().apply( + right_traits().get(right,i), + left_traits().get(left,i) + )) + return true; + + /* Otherwise, have equality (a <= b) && (b <= a), so continue + * to next element: + */ + else + continue; + + } else { + + /* Total order isn't satisfied (a > b), so return false: */ + return false; + } + } + /* XXX Can this be unrolled in any reasonable way? */ + + /* Total (==) or weak (<) order was satisfied, so return true: */ + return true; +} + +} + +/* XXX There is a better way to handle these with operator traits... */ + +CML_QUAT_QUAT_ORDER( total_order, operator==, et::OpEqual) +CML_QUATXPR_QUAT_ORDER( total_order, operator==, et::OpEqual) +CML_QUAT_QUATXPR_ORDER( total_order, operator==, et::OpEqual) +CML_QUATXPR_QUATXPR_ORDER( total_order, operator==, et::OpEqual) + +CML_QUAT_QUAT_ORDER( weak_order, operator!=, et::OpNotEqual) +CML_QUATXPR_QUAT_ORDER( weak_order, operator!=, et::OpNotEqual) +CML_QUAT_QUATXPR_ORDER( weak_order, operator!=, et::OpNotEqual) +CML_QUATXPR_QUATXPR_ORDER( weak_order, operator!=, et::OpNotEqual) + +CML_QUAT_QUAT_ORDER( weak_order, operator<, et::OpLess) +CML_QUATXPR_QUAT_ORDER( weak_order, operator<, et::OpLess) +CML_QUAT_QUATXPR_ORDER( weak_order, operator<, et::OpLess) +CML_QUATXPR_QUATXPR_ORDER( weak_order, operator<, et::OpLess) + +} // namespace cml + +#endif + +// ------------------------------------------------------------------------- +// vim:ft=cpp diff --git a/Lib/Include/CML/quaternion/quaternion_dot.h b/Lib/Include/CML/quaternion/quaternion_dot.h new file mode 100644 index 0000000..72a53e2 --- /dev/null +++ b/Lib/Include/CML/quaternion/quaternion_dot.h @@ -0,0 +1,73 @@ +/* -*- C++ -*- ------------------------------------------------------------ + +Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/ + +The Configurable Math Library (CML) is distributed under the terms of the +Boost Software License, v1.0 (see cml/LICENSE for details). + + *-----------------------------------------------------------------------*/ +/** @file + * @brief + */ + +#ifndef quaternion_dot_h +#define quaternion_dot_h + +#include +#include + +namespace cml { +namespace detail { + +template inline +typename detail::DotPromote::promoted_scalar +quaternion_dot(const LeftT& p, const RightT& q) +{ + return p[0]*q[0] + p[1]*q[1] + p[2]*q[2] + p[3]*q[3]; +} + +} // namespace detail + +template +inline typename detail::DotPromote< + quaternion, quaternion +>::promoted_scalar +dot(const quaternion& p, + const quaternion& q) +{ + return detail::quaternion_dot(p,q); +} + +template +inline typename detail::DotPromote< + quaternion, et::QuaternionXpr +>::promoted_scalar +dot(const quaternion& p, QUATXPR_ARG_TYPE q) +{ + return detail::quaternion_dot(p,q); +} + +template +inline typename detail::DotPromote< + et::QuaternionXpr, quaternion +>::promoted_scalar +dot(QUATXPR_ARG_TYPE p, const quaternion& q) +{ + return detail::quaternion_dot(p,q); +} + +template inline +typename detail::DotPromote< + et::QuaternionXpr, et::QuaternionXpr +>::promoted_scalar +dot(QUATXPR_ARG_TYPE_N(1) p, QUATXPR_ARG_TYPE_N(2) q) +{ + return detail::quaternion_dot(p,q); +} + +} // namespace cml + +#endif + +// ------------------------------------------------------------------------- +// vim:ft=cpp diff --git a/Lib/Include/CML/quaternion/quaternion_expr.h b/Lib/Include/CML/quaternion/quaternion_expr.h new file mode 100644 index 0000000..dcec9fd --- /dev/null +++ b/Lib/Include/CML/quaternion/quaternion_expr.h @@ -0,0 +1,614 @@ +/* -*- C++ -*- ------------------------------------------------------------ + +Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/ + +The Configurable Math Library (CML) is distributed under the terms of the +Boost Software License, v1.0 (see cml/LICENSE for details). + + *-----------------------------------------------------------------------*/ +/** @file + * @brief + */ + +#ifndef quaternion_expr_h +#define quaternion_expr_h + +#include +#include +#include +#include +#include + +#define QUATXPR_ARG_TYPE const et::QuaternionXpr& +#define QUATXPR_ARG_TYPE_N(_N_) const et::QuaternionXpr& + +namespace cml { +namespace et { + +/** A placeholder for a quaternion expression in an expression tree. */ +template +class QuaternionXpr +{ + public: + + typedef QuaternionXpr expr_type; + + /* Record ary-ness of the expression: */ + typedef typename ExprT::expr_ary expr_ary; + + /* Copy the expression by value into higher-up expressions: */ + typedef expr_type expr_const_reference; + + typedef typename ExprT::value_type value_type; + typedef quaternion_result_tag result_tag; + typedef typename ExprT::size_tag size_tag; + + /* Store the expression traits: */ + typedef ExprTraits expr_traits; + + /* Get the reference type: */ + typedef typename expr_traits::const_reference expr_reference; + + /* Get the result type: */ + typedef typename expr_traits::result_type result_type; + + /* Get the vector type: */ + typedef typename result_type::vector_type vector_type; + + /* Get the imaginary part type: */ + typedef typename vector_type::subvector_type imaginary_type; + + /* For matching by assignability: */ + typedef cml::et::not_assignable_tag assignable_tag; + + /* Get the temporary type: */ + typedef typename result_type::temporary_type temporary_type; + + /* Record the order type: */ + typedef typename result_type::order_type order_type; + + /* Record the cross type: */ + typedef typename result_type::cross_type cross_type; + + + public: + + /** Record result size as an enum. */ + enum { array_size = ExprT::array_size }; + + + public: + + /** Return the real part of the expression. */ + value_type real() const { + return m_expr.real(); + } + + /** Return the vector part of the expression. */ + imaginary_type imaginary() const { + return m_expr.imaginary(); + } + + /** Return the Cayley norm of the expression. */ + value_type norm() const { + return m_expr.length_squared(); + } + + /** Return square of the quaternion length. */ + value_type length_squared() const { + return m_expr.length_squared(); + } + + /** Return the quaternion length. */ + value_type length() const { + return m_expr.length(); + } + + /** Return the result as a normalized quaternion. */ + temporary_type normalize() const { + return m_expr.normalize(); + } + + /** Return the log of the expression. */ + temporary_type log( + value_type tolerance = epsilon::placeholder()) const + { + return m_expr.log(tolerance); + } + + /** + * Return the result of the exponential function as applied to + * this expression. + */ + temporary_type exp( + value_type tolerance = epsilon::placeholder()) const + { + return m_expr.exp(tolerance); + } + + /** Compute value at index i of the result quaternion. */ + value_type operator[](size_t i) const { + return m_expr[i]; + } + + + public: + + /** Return size of this expression (same as subexpression's size). */ + size_t size() const { + return m_expr.size(); + } + + /** Return reference to contained expression. */ + expr_reference expression() const { return m_expr; } + + + public: + + /** Construct from the subexpression to store. */ + explicit QuaternionXpr(expr_reference expr) : m_expr(expr) {} + + /** Copy constructor. */ + QuaternionXpr(const expr_type& e) : m_expr(e.m_expr) {} + + + protected: + + expr_reference m_expr; + + + private: + + /* Cannot be assigned to: */ + expr_type& operator=(const expr_type&); +}; + +/** Expression traits class for QuaternionXpr<>. */ +template +struct ExprTraits< QuaternionXpr > +{ + typedef QuaternionXpr expr_type; + typedef ExprT arg_type; + typedef typename expr_type::value_type value_type; + typedef typename expr_type::expr_const_reference const_reference; + typedef typename expr_type::result_tag result_tag; + typedef typename expr_type::size_tag size_tag; + typedef typename expr_type::result_type result_type; + typedef typename expr_type::assignable_tag not_assignable_tag; + typedef expr_node_tag node_tag; + + value_type get(const expr_type& v, size_t i) const { return v[i]; } + size_t size(const expr_type& e) const { return e.size(); } +}; + + +/** A unary quaternion expression. + * + * The operator's operator() method must take exactly one argument. + */ +template +class UnaryQuaternionOp +{ + public: + + typedef UnaryQuaternionOp expr_type; + + /* Record ary-ness of the expression: */ + typedef unary_expression expr_ary; + + /* Copy the expression by value into higher-up expressions: */ + typedef expr_type expr_const_reference; + + typedef typename OpT::value_type value_type; + typedef quaternion_result_tag result_tag; + typedef typename ExprT::size_tag size_tag; + + /* Store the expression traits for the subexpression: */ + typedef ExprTraits expr_traits; + + /* Reference type for the subexpression: */ + typedef typename expr_traits::const_reference expr_reference; + + /* Get the result type (same as for subexpression): */ + typedef typename expr_traits::result_type result_type; + + /* For matching by assignability: */ + typedef cml::et::not_assignable_tag assignable_tag; + + /* Get the temporary type: */ + typedef typename result_type::temporary_type temporary_type; + + /* Get the vector type: */ + typedef typename result_type::vector_type vector_type; + + /* Get the imaginary part type: */ + typedef typename vector_type::subvector_type imaginary_type; + + /* Record the order type: */ + typedef typename result_type::order_type order_type; + + + public: + + /** Record result size as an enum. */ + enum { array_size = ExprT::array_size }; + + /** Localize the ordering as an enum. */ + enum { + W = order_type::W, + X = order_type::X, + Y = order_type::Y, + Z = order_type::Z + }; + + + public: + + /** Return the real part of the expression. */ + value_type real() const { + return (*this)[W]; + } + + /** Return the vector part of the expression. */ + imaginary_type imaginary() const { + imaginary_type v; + v[0] = (*this)[X]; v[1] = (*this)[Y]; v[2] = (*this)[Z]; + return v; + } + + /** Return the Cayley norm of the expression. */ + value_type norm() const { + return length_squared(); + } + + /** Return square of the quaternion length. */ + value_type length_squared() const { + return dot( + QuaternionXpr(*this), + QuaternionXpr(*this)); + } + + /** Return the quaternion length. */ + value_type length() const { + return std::sqrt(length_squared()); + } + + /** Return the result as a normalized quaternion. */ + temporary_type normalize() const { + temporary_type q(QuaternionXpr(*this)); + return q.normalize(); + } + + /** Return the log of this expression. */ + temporary_type log( + value_type tolerance = epsilon::placeholder()) const + { + value_type a = acos_safe(real()); + value_type s = std::sin(a); + + if (s > tolerance) { + return temporary_type(value_type(0), imaginary() * (a / s)); + } else { + return temporary_type(value_type(0), imaginary()); + } + } + + /** + * Return the result of the exponential function as applied to + * this expression. + */ + temporary_type exp( + value_type tolerance = epsilon::placeholder()) const + { + imaginary_type v = imaginary(); + value_type a = cml::length(v); + + if (a > tolerance) { + return temporary_type(std::cos(a), v * (std::sin(a) / a)); + } else { + return temporary_type(std::cos(a), v); + } + } + + /** Compute value at index i of the result quaternion. */ + value_type operator[](size_t i) const { + + /* This uses the expression traits to figure out how to access the + * i'th index of the subexpression: + */ + return OpT().apply(expr_traits().get(m_expr,i)); + } + + + public: + + /** Return size of this expression (same as argument's size). */ + size_t size() const { + return m_expr.size(); + } + + /** Return reference to contained expression. */ + expr_reference expression() const { return m_expr; } + + + public: + + /** Construct from the subexpression. */ + explicit UnaryQuaternionOp(expr_reference expr) : m_expr(expr) {} + + /** Copy constructor. */ + UnaryQuaternionOp(const expr_type& e) : m_expr(e.m_expr) {} + + + protected: + + expr_reference m_expr; + + + private: + + /* Cannot be assigned to: */ + expr_type& operator=(const expr_type&); +}; + +/** Expression traits class for UnaryQuaternionOp<>. */ +template +struct ExprTraits< UnaryQuaternionOp > +{ + typedef UnaryQuaternionOp expr_type; + typedef ExprT arg_type; + + typedef typename expr_type::value_type value_type; + typedef typename expr_type::expr_const_reference const_reference; + typedef typename expr_type::result_tag result_tag; + typedef typename expr_type::size_tag size_tag; + typedef typename expr_type::result_type result_type; + typedef typename expr_type::assignable_tag not_assignable_tag; + typedef expr_node_tag node_tag; + + value_type get(const expr_type& v, size_t i) const { return v[i]; } + size_t size(const expr_type& e) const { return e.size(); } +}; + + +/** A binary quaternion expression. + * + * The operator's operator() method must take exactly two arguments. + */ +template +class BinaryQuaternionOp +{ + public: + + typedef BinaryQuaternionOp expr_type; + + /* Record ary-ness of the expression: */ + typedef binary_expression expr_ary; + + /* Copy the expression by value into higher-up expressions: */ + typedef expr_type expr_const_reference; + + typedef typename OpT::value_type value_type; + typedef quaternion_result_tag result_tag; + + /* Store the expression traits types for the two subexpressions: */ + typedef ExprTraits left_traits; + typedef ExprTraits right_traits; + + /* Reference types for the two subexpressions: */ + typedef typename left_traits::const_reference left_reference; + typedef typename right_traits::const_reference right_reference; + + /* Figure out the expression's resulting (quaternion) type: */ + typedef typename left_traits::result_type left_result; + typedef typename right_traits::result_type right_result; + typedef typename QuaternionPromote::type + result_type; + typedef typename result_type::size_tag size_tag; + + /* For matching by assignability: */ + typedef cml::et::not_assignable_tag assignable_tag; + + /* Get the temporary type: */ + typedef typename result_type::temporary_type temporary_type; + + /* Get the vector type: */ + typedef typename result_type::vector_type vector_type; + + /* Get the imaginary part type: */ + typedef typename vector_type::subvector_type imaginary_type; + + /* Record the order type: */ + typedef typename result_type::order_type order_type; + + /* Define a size checker: */ + typedef GetCheckedSize checked_size; + + + public: + + /** Record result size as an enum. */ + enum { array_size = 4 }; + + /** Localize the ordering as an enum. */ + enum { + W = order_type::W, + X = order_type::X, + Y = order_type::Y, + Z = order_type::Z + }; + + + public: + + /** Return the real part of the expression. */ + value_type real() const { + return (*this)[W]; + } + + /** Return the vector part of the expression. */ + imaginary_type imaginary() const { + imaginary_type v; + v[0] = (*this)[X]; v[1] = (*this)[Y]; v[2] = (*this)[Z]; + return v; + } + + /** Return the Cayley norm of the expression. */ + value_type norm() const { + return length_squared(); + } + + /** Return square of the quaternion length. */ + value_type length_squared() const { + return dot( + QuaternionXpr(*this), + QuaternionXpr(*this)); + } + + /** Return the quaternion length. */ + value_type length() const { + return std::sqrt(length_squared()); + } + + /** Return the result as a normalized quaternion. */ + temporary_type normalize() const { + temporary_type q(QuaternionXpr(*this)); + return q.normalize(); + } + + /** Return the log of this expression. */ + temporary_type log( + value_type tolerance = epsilon::placeholder()) const + { + value_type a = acos_safe(real()); + value_type s = std::sin(a); + + if (s > tolerance) { + return temporary_type(value_type(0), imaginary() * (a / s)); + } else { + return temporary_type(value_type(0), imaginary()); + } + } + + /** + * Return the result of the exponential function as applied to + * this expression. + */ + temporary_type exp( + value_type tolerance = epsilon::placeholder()) const + { + imaginary_type v = imaginary(); + value_type a = cml::length(v); + + if (a > tolerance) { + return temporary_type(std::cos(a), v * (std::sin(a) / a)); + } else { + return temporary_type(std::cos(a), v); + } + } + + /** Compute value at index i of the result quaternion. */ + value_type operator[](size_t i) const { + + /* This uses the expression traits to figure out how to access the + * i'th index of the two subexpressions: + */ + return OpT().apply( + left_traits().get(m_left,i), + right_traits().get(m_right,i)); + } + + + public: + + /** Return the size of the quaternion result. + * + * @throws std::invalid_argument if the expressions do not have the same + * size. + */ + size_t size() const { + /* Note: This actually does a check only if + * CML_CHECK_VECTOR_EXPR_SIZES is set: + */ + CheckedSize(m_left,m_right,size_tag()); + + /* The size is always 4: */ + return 4; + } + + /** Return reference to left expression. */ + left_reference left_expression() const { return m_left; } + + /** Return reference to right expression. */ + right_reference right_expression() const { return m_right; } + + + public: + + /** Construct from the two subexpressions. */ + explicit BinaryQuaternionOp(left_reference left, right_reference right) + : m_left(left), m_right(right) {} + + /** Copy constructor. */ + BinaryQuaternionOp(const expr_type& e) + : m_left(e.m_left), m_right(e.m_right) {} + + + protected: + + left_reference m_left; + right_reference m_right; + + + private: + + /* This ensures that a compile-time size check is executed: */ + typename checked_size::check_type _dummy; + + + private: + + /* Cannot be assigned to: */ + expr_type& operator=(const expr_type&); +}; + +/** Expression traits class for BinaryQuaternionOp<>. */ +template +struct ExprTraits< BinaryQuaternionOp > +{ + typedef BinaryQuaternionOp expr_type; + typedef LeftT left_type; + typedef RightT right_type; + + typedef typename expr_type::value_type value_type; + typedef typename expr_type::expr_const_reference const_reference; + typedef typename expr_type::result_tag result_tag; + typedef typename expr_type::size_tag size_tag; + typedef typename expr_type::result_type result_type; + typedef typename expr_type::imaginary_type imaginary_type; + typedef typename expr_type::assignable_tag not_assignable_tag; + typedef expr_node_tag node_tag; + + value_type get(const expr_type& v, size_t i) const { return v[i]; } + size_t size(const expr_type& e) const { return e.size(); } +}; + + +/* Helper struct to verify that both arguments are quaternion expressions: */ +template +struct QuaternionExpressions +{ + /* Require that both arguments are quaternion expressions: */ + typedef typename LeftTraits::result_tag left_result; + typedef typename RightTraits::result_tag right_result; + enum { is_true = (same_type::is_true + && same_type::is_true) }; +}; + +} // namespace et +} // namespace cml + +#endif + +// ------------------------------------------------------------------------- +// vim:ft=cpp diff --git a/Lib/Include/CML/quaternion/quaternion_functions.h b/Lib/Include/CML/quaternion/quaternion_functions.h new file mode 100644 index 0000000..95abcb9 --- /dev/null +++ b/Lib/Include/CML/quaternion/quaternion_functions.h @@ -0,0 +1,172 @@ +/* -*- C++ -*- ------------------------------------------------------------ + +Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/ + +The Configurable Math Library (CML) is distributed under the terms of the +Boost Software License, v1.0 (see cml/LICENSE for details). + + *-----------------------------------------------------------------------*/ +/** @file + * @brief Functions on quaternions. + * + * @todo The functions that return quaternions and vectors should be changed + * to return quaternion expression nodes, as should the corresponding + * class methods. + */ + +#ifndef quaternion_functions_h +#define quaternion_functions_h + +#include // For CheckQuat() +#include +#include // For acos_safe() + +namespace cml { + +/** Returns the real part of the quaternion. */ +template +inline typename quaternion::value_type +real(const quaternion& q) +{ + return q.real(); +} + +/** Returns the real (scalar) part of the QuaternionXpr. */ +template +inline typename et::QuaternionXpr::value_type +real(const et::QuaternionXpr& e) +{ + return e.real(); +} + +/** Returns the imaginary (vector) part of the quaternion. */ +template +inline typename quaternion::imaginary_type +imaginary(const quaternion& q) +{ + return q.imaginary(); +} + +/** Returns the imaginary (vector) part of the QuaternionXpr. */ +template +//inline typename et::QuaternionXpr::temporary_type +inline typename et::QuaternionXpr::imaginary_type +imaginary(const et::QuaternionXpr& e) +{ + return e.imaginary(); +} + +/** Cayley norm of a quaternion. */ +template +inline typename quaternion::value_type +norm(const quaternion& arg) +{ + return arg.length_squared(); +} + +/** Cayley norm of a QuaternionXpr. */ +template +inline typename XprT::value_type +norm(QUATXPR_ARG_TYPE arg) +{ + return arg.length_squared(); +} + +/** Squared length of a quaternion. */ +template +inline typename quaternion::value_type +length_squared(const quaternion& arg) +{ + return arg.length_squared(); +} + +/** Squared length of a quaternion expr. */ +template +inline typename XprT::value_type +length_squared(QUATXPR_ARG_TYPE arg) +{ + return arg.length_squared(); +} + +/** Length of a quaternion. */ +template +inline typename quaternion::value_type +length(const quaternion& arg) +{ + return arg.length(); +} + +/** Length of a quaternion expr. */ +template +inline typename XprT::value_type +length(QUATXPR_ARG_TYPE arg) +{ + return arg.length(); +} + +/** Normalize a quaternion. + * + * The input quaternion is not changed. + */ +template +inline quaternion +normalize(const quaternion& arg) +{ + typename quaternion::temporary_type result(arg); + result.normalize(); + return result; +} + +/** Normalize a quaternion expr. */ +template +inline typename XprT::temporary_type +normalize(QUATXPR_ARG_TYPE arg) +{ + return arg.normalize(); +} + +/** Set a quaternion to the multiplicative identity. + * + * The input quaternion is not changed. + */ +template +inline quaternion +identity(const quaternion& arg) +{ + typename quaternion::temporary_type result(arg); + result.identity(); + return result; +} + +/** Log of a quaternion or quaternion expression. + */ +template < class QuatT > +typename QuatT::temporary_type log( + const QuatT& q, + typename QuatT::value_type tolerance = + epsilon::placeholder()) +{ + detail::CheckQuat(q); + + return q.log(); +} + +/** Exponential function of a quaternion or quaternion expression. + */ +template < class QuatT > +typename QuatT::temporary_type exp( + const QuatT& q, + typename QuatT::value_type tolerance = + epsilon::placeholder()) +{ + detail::CheckQuat(q); + + return q.exp(); +} + +} // namespace cml + +#endif + +// ------------------------------------------------------------------------- +// vim:ft=cpp diff --git a/Lib/Include/CML/quaternion/quaternion_mul.h b/Lib/Include/CML/quaternion/quaternion_mul.h new file mode 100644 index 0000000..bfb533b --- /dev/null +++ b/Lib/Include/CML/quaternion/quaternion_mul.h @@ -0,0 +1,140 @@ +/* -*- C++ -*- ------------------------------------------------------------ + +Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/ + +The Configurable Math Library (CML) is distributed under the terms of the +Boost Software License, v1.0 (see cml/LICENSE for details). + + *-----------------------------------------------------------------------*/ +/** @file + * @brief Multiplication of two quaternions, p*q. + * + * This uses the expression tree, since the result is closed-form and can be + * computed by index. + */ + +#ifndef quaternion_mul_h +#define quaternion_mul_h + +#include +#include + +namespace cml { +namespace detail { + +template < class CrossType, class Real > struct SumOp; + +template < class Real > struct SumOp< positive_cross, Real > { + Real operator()(Real a, Real b) const { + return a + b; + } +}; + +template < class Real > struct SumOp< negative_cross, Real > { + Real operator()(Real a, Real b) const { + return a - b; + } +}; + +template < class Quat1_T, class Quat2_T > +typename et::QuaternionPromote< + typename Quat1_T::temporary_type, typename Quat2_T::temporary_type +>::temporary_type +QuaternionMult(const Quat1_T& q1, const Quat2_T& q2) +{ + detail::CheckQuat(q1); + detail::CheckQuat(q2); + + typedef typename et::QuaternionPromote< + typename Quat1_T::temporary_type, typename Quat2_T::temporary_type + >::temporary_type temporary_type; + + typedef typename temporary_type::value_type value_type; + typedef typename temporary_type::order_type order_type; + typedef typename temporary_type::cross_type cross_type; + + typedef detail::SumOp sum_op; + + enum { + W = order_type::W, + X = order_type::X, + Y = order_type::Y, + Z = order_type::Z + }; + + temporary_type result; + + /* s1*s2-dot(v1,v2): */ + result[W] = + q1[W]*q2[W] - q1[X]*q2[X] - q1[Y]*q2[Y] - q1[Z]*q2[Z]; + + /* (s1*v2 + s2*v1 + v1^v2) i: */ + result[X] = + sum_op()(q1[W]*q2[X] + q2[W]*q1[X], q1[Y]*q2[Z] - q1[Z]*q2[Y]); + + /* (s1*v2 + s2*v1 + v1^v2) j: */ + result[Y] = + sum_op()(q1[W]*q2[Y] + q2[W]*q1[Y], q1[Z]*q2[X] - q1[X]*q2[Z]); + + /* (s1*v2 + s2*v1 + v1^v2) k: */ + result[Z] = + sum_op()(q1[W]*q2[Z] + q2[W]*q1[Z], q1[X]*q2[Y] - q1[Y]*q2[X]); + + return result; +} + +} // namespace detail + +/** Declare mul taking two quaternion operands. */ +template +inline typename et::QuaternionPromote< + typename quaternion::temporary_type, + typename quaternion::temporary_type +>::temporary_type operator*( + const quaternion& left, + const quaternion& right) +{ + return detail::QuaternionMult(left, right); +} + +/** Declare mul taking a quaternion and a et::QuaternionXpr. */ +template +inline typename et::QuaternionPromote< + typename quaternion::temporary_type, + typename XprT::temporary_type +>::temporary_type operator*( + const quaternion& left, + QUATXPR_ARG_TYPE right) +{ + return detail::QuaternionMult(left, right); +} + +/** Declare mul taking an et::QuaternionXpr and a quaternion. */ +template +inline typename et::QuaternionPromote< + typename XprT::temporary_type, + typename quaternion::temporary_type +>::temporary_type operator*( + QUATXPR_ARG_TYPE left, + const quaternion& right) +{ + return detail::QuaternionMult(left, right); +} + +/** Declare mul taking two et::QuaternionXpr operands. */ +template +inline typename et::QuaternionPromote< + typename XprT1::temporary_type, typename XprT2::temporary_type +>::temporary_type operator*( + QUATXPR_ARG_TYPE_N(1) left, + QUATXPR_ARG_TYPE_N(2) right) +{ + return detail::QuaternionMult(left, right); +} + +} // namespace cml + +#endif + +// ------------------------------------------------------------------------- +// vim:ft=cpp diff --git a/Lib/Include/CML/quaternion/quaternion_ops.h b/Lib/Include/CML/quaternion/quaternion_ops.h new file mode 100644 index 0000000..e973f9b --- /dev/null +++ b/Lib/Include/CML/quaternion/quaternion_ops.h @@ -0,0 +1,51 @@ +/* -*- C++ -*- ------------------------------------------------------------ + +Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/ + +The Configurable Math Library (CML) is distributed under the terms of the +Boost Software License, v1.0 (see cml/LICENSE for details). + + *-----------------------------------------------------------------------*/ +/** @file + * @brief Defines the linear quaternion ops. + */ + +#ifndef quaternion_ops_h +#define quaternion_ops_h + +#include +#include +#include + +namespace cml { + +CML_QUAT_UNIOP( operator+, et::OpPos) +CML_QUATXPR_UNIOP( operator+, et::OpPos) + +CML_QUAT_UNIOP( operator-, et::OpNeg) +CML_QUATXPR_UNIOP( operator-, et::OpNeg) + +CML_QUAT_QUAT_BINOP( operator+, et::OpAdd) +CML_QUATXPR_QUAT_BINOP( operator+, et::OpAdd) +CML_QUAT_QUATXPR_BINOP( operator+, et::OpAdd) +CML_QUATXPR_QUATXPR_BINOP( operator+, et::OpAdd) + +CML_QUAT_QUAT_BINOP( operator-, et::OpSub) +CML_QUATXPR_QUAT_BINOP( operator-, et::OpSub) +CML_QUAT_QUATXPR_BINOP( operator-, et::OpSub) +CML_QUATXPR_QUATXPR_BINOP( operator-, et::OpSub) + +CML_QUAT_SCALAR_BINOP( operator*, et::OpMul) +CML_SCALAR_QUAT_BINOP( operator*, et::OpMul) +CML_QUATXPR_SCALAR_BINOP( operator*, et::OpMul) +CML_SCALAR_QUATXPR_BINOP( operator*, et::OpMul) + +CML_QUAT_SCALAR_BINOP( operator/, et::OpDiv) +CML_QUATXPR_SCALAR_BINOP( operator/, et::OpDiv) + +} // namespace cml + +#endif + +// ------------------------------------------------------------------------- +// vim:ft=cpp diff --git a/Lib/Include/CML/quaternion/quaternion_print.h b/Lib/Include/CML/quaternion/quaternion_print.h new file mode 100644 index 0000000..483dfc4 --- /dev/null +++ b/Lib/Include/CML/quaternion/quaternion_print.h @@ -0,0 +1,90 @@ +/* -*- C++ -*- ------------------------------------------------------------ + +Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/ + +The Configurable Math Library (CML) is distributed under the terms of the +Boost Software License, v1.0 (see cml/LICENSE for details). + + *-----------------------------------------------------------------------*/ +/** @file + * @brief + */ + +#ifndef quaternion_print_h +#define quaternion_print_h + +#include + +namespace cml { + +/* NOTE: Made 'plain' quaternion output the default (Jesse) */ + +/* #if !defined(CML_PLAIN_QUATERNION_OUTPUT) */ +#if defined(CML_COMPLEX_QUATERNION_OUTPUT) + +template std::ostream& +operator<<(std::ostream& os, const cml::quaternion& q) +{ + os << ((q[0] < 0)?" - ":"") << std::fabs(q[0]); + os << ((q[1] < 0)?" - ":" + ") << std::fabs(q[1]) << "i"; + os << ((q[2] < 0)?" - ":" + ") << std::fabs(q[2]) << "j"; + os << ((q[3] < 0)?" - ":" + ") << std::fabs(q[3]) << "k"; + return os; +} + +template std::ostream& +operator<<(std::ostream& os, const cml::quaternion& q) +{ + os << ((q[0] < 0)?" - ":"") << std::fabs(q[0]) << "i"; + os << ((q[1] < 0)?" - ":" + ") << std::fabs(q[1]) << "j"; + os << ((q[2] < 0)?" - ":" + ") << std::fabs(q[2]) << "k"; + os << ((q[3] < 0)?" - ":" + ") << std::fabs(q[3]); + return os; +} + +#else + +/** Output a quaternion to a std::ostream. */ +template std::ostream& +operator<<(std::ostream& os, const cml::quaternion& q) +{ + typedef typename cml::quaternion::order_type order_type; + enum { + W = order_type::W, + X = order_type::X, + Y = order_type::Y, + Z = order_type::Z + }; + + os << "[ " + << " " << q[W] + << " " << q[X] + << " " << q[Y] + << " " << q[Z] + << " ]"; + + return os; +} + +#endif + +/** Output a quaternion expression to a std::ostream. */ +template< class XprT > inline std::ostream& +operator<<(std::ostream& os, const et::QuaternionXpr& q) +{ + typedef typename et::QuaternionXpr::result_type quaternion_type; + + os << quaternion_type(q); + /* XXX This temporary can be removed by templating the stream insertion + * operators above. + */ + + return os; +} + +} // namespace cml + +#endif + +// ------------------------------------------------------------------------- +// vim:ft=cpp diff --git a/Lib/Include/CML/quaternion/quaternion_promotions.h b/Lib/Include/CML/quaternion/quaternion_promotions.h new file mode 100644 index 0000000..049a1b3 --- /dev/null +++ b/Lib/Include/CML/quaternion/quaternion_promotions.h @@ -0,0 +1,140 @@ +/* -*- C++ -*- ------------------------------------------------------------ + +Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/ + +The Configurable Math Library (CML) is distributed under the terms of the +Boost Software License, v1.0 (see cml/LICENSE for details). + + *-----------------------------------------------------------------------*/ +/** @file + * @brief + */ + +#ifndef quaternion_promotions_h +#define quaternion_promotions_h + +#include +#include + +namespace cml { +namespace et { + +/* Default quaternion type promotion templates. */ +template struct QuaternionPromote; + +/** Type promotion for two quaternion types. */ +template +struct QuaternionPromote< + cml::quaternion, + cml::quaternion +> +{ + /* The deduced vector type: */ + typedef typename VectorPromote< + typename cml::quaternion::vector_type, + typename cml::quaternion::vector_type + >::type promoted_vector; + + /* The deduced element and storage types: */ + typedef typename promoted_vector::value_type value_type; + typedef typename promoted_vector::storage_type storage_type; + + /* The deduced quaternion result type: */ + typedef cml::quaternion type; + + /* The temporary type: */ + typedef typename type::temporary_type temporary_type; +}; + +/** + * NOTE: QuaternionPromote* are somewhat ad hoc, and were added to + * simplify the code for quaternion slerp/squad/etc. + */ + +/** Type promotion for two quaternion types. */ +template < class Quat1_T, class Quat2_T > +struct QuaternionPromote2 +{ + typedef typename QuaternionPromote< + typename Quat1_T::temporary_type, typename Quat2_T::temporary_type + >::temporary_type temporary_type; + typedef typename temporary_type::value_type value_type; +}; + +/** Type promotion for three quaternion types. */ +template < class Quat1_T, class Quat2_T, class Quat3_T > +struct QuaternionPromote3 +{ + typedef typename QuaternionPromote< + typename Quat1_T::temporary_type, + typename QuaternionPromote< + typename Quat2_T::temporary_type, typename Quat3_T::temporary_type + >::temporary_type + >::temporary_type temporary_type; + typedef typename temporary_type::value_type value_type; +}; + +/** Type promotion for four quaternion types. */ +template < class Quat1_T, class Quat2_T, class Quat3_T, class Quat4_T > +struct QuaternionPromote4 +{ + typedef typename QuaternionPromote< + typename Quat1_T::temporary_type, + typename QuaternionPromote< + typename Quat2_T::temporary_type, + typename QuaternionPromote< + typename Quat3_T::temporary_type, + typename Quat4_T::temporary_type + >::temporary_type + >::temporary_type + >::temporary_type temporary_type; + typedef typename temporary_type::value_type value_type; +}; + +/** Type promotion for a quaternion and a scalar. */ +template +struct QuaternionPromote, S> +{ + /* The deduced vector type: */ + typedef typename VectorPromote< + typename quaternion::vector_type, S + >::type promoted_vector; + + /* The deduced element and storage types: */ + typedef typename promoted_vector::value_type value_type; + typedef typename promoted_vector::storage_type storage_type; + + /* The deduced quaternion result type: */ + typedef cml::quaternion type; + + /* The temporary type: */ + typedef typename type::temporary_type temporary_type; +}; + +/** Type promotion for a scalar and a quaternion. */ +template +struct QuaternionPromote > +{ + /* The deduced vector type: */ + typedef typename VectorPromote< + S, typename quaternion::vector_type + >::type promoted_vector; + + /* The deduced element and storage types: */ + typedef typename promoted_vector::value_type value_type; + typedef typename promoted_vector::storage_type storage_type; + + /* The deduced quaternion result type: */ + typedef cml::quaternion type; + + /* The temporary type: */ + typedef typename type::temporary_type temporary_type; +}; + +} // namespace et +} // namespace cml + +#endif + +// ------------------------------------------------------------------------- +// vim:ft=cpp diff --git a/Lib/Include/CML/quaternion/quaternion_traits.h b/Lib/Include/CML/quaternion/quaternion_traits.h new file mode 100644 index 0000000..fbf23cf --- /dev/null +++ b/Lib/Include/CML/quaternion/quaternion_traits.h @@ -0,0 +1,45 @@ +/* -*- C++ -*- ------------------------------------------------------------ + +Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/ + +The Configurable Math Library (CML) is distributed under the terms of the +Boost Software License, v1.0 (see cml/LICENSE for details). + + *-----------------------------------------------------------------------*/ +/** @file + * @brief + */ + +#ifndef quaternion_traits_h +#define quaternion_traits_h + +#include + +namespace cml { +namespace et { + +/** Expression traits for a quaternion<> type. */ +template +struct ExprTraits< cml::quaternion > +{ + typedef typename cml::quaternion::expr_type expr_type; + typedef typename expr_type::value_type value_type; + typedef typename expr_type::expr_reference reference; + typedef typename expr_type::expr_const_reference const_reference; + typedef typename expr_type::result_tag result_tag; + typedef typename expr_type::size_tag size_tag; + typedef typename expr_type::assignable_tag assignable_tag; + typedef expr_type result_type; + typedef expr_leaf_tag node_tag; + + value_type get(const expr_type& v, size_t i) const { return v[i]; } + size_t size(const expr_type& v) const { return 4; } +}; + +} // namespace et +} // namespace cml + +#endif + +// ------------------------------------------------------------------------- +// vim:ft=cpp diff --git a/Lib/Include/CML/quaternion/quatop_macros.h b/Lib/Include/CML/quaternion/quatop_macros.h new file mode 100644 index 0000000..112e348 --- /dev/null +++ b/Lib/Include/CML/quaternion/quatop_macros.h @@ -0,0 +1,232 @@ +/* -*- C++ -*- ------------------------------------------------------------ + +Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/ + +The Configurable Math Library (CML) is distributed under the terms of the +Boost Software License, v1.0 (see cml/LICENSE for details). + + *-----------------------------------------------------------------------*/ +/** @file + * @brief + * + * Create unary and binary operators with macros. + * + * These macros work just like those in cml/quaternion/vecop_macros.h. + */ + +#ifndef quatop_macros_h +#define quatop_macros_h + +/** Declare a unary operator taking a quaternion operand. */ +#define CML_QUAT_UNIOP(_op_, _OpT_) \ +template \ +inline et::QuaternionXpr< \ + et::UnaryQuaternionOp< quaternion, _OpT_ > \ +> \ + \ +_op_ (const quaternion& arg) \ +{ \ + typedef et::UnaryQuaternionOp< \ + quaternion, _OpT_ \ + > ExprT; \ + return et::QuaternionXpr(ExprT(arg)); \ +} + + +/** Declare a unary operator taking a et::QuaternionXpr operand. */ +#define CML_QUATXPR_UNIOP(_op_, _OpT_) \ +template \ +inline et::QuaternionXpr< \ + et::UnaryQuaternionOp< XprT, _OpT_ > \ +> \ + \ +_op_ (QUATXPR_ARG_TYPE arg) \ +{ \ + typedef et::UnaryQuaternionOp< \ + XprT, _OpT_ \ + > ExprT; \ + return et::QuaternionXpr(ExprT(arg.expression())); \ +} + + + +/** Declare an operator taking two quaternion operands. */ +#define CML_QUAT_QUAT_BINOP(_op_, _OpT_) \ +template \ +inline et::QuaternionXpr< \ + et::BinaryQuaternionOp< \ + quaternion, quaternion, \ + _OpT_ \ + > \ +> \ + \ +_op_ ( \ + const quaternion& left, \ + const quaternion& right) \ +{ \ + typedef et::BinaryQuaternionOp< \ + quaternion, quaternion, \ + _OpT_ \ + > ExprT; \ + return et::QuaternionXpr(ExprT(left,right)); \ +} + + +/** Declare an operator taking a quaternion and a et::QuaternionXpr. */ +#define CML_QUAT_QUATXPR_BINOP(_op_, _OpT_) \ +template \ +inline et::QuaternionXpr< \ + et::BinaryQuaternionOp< \ + quaternion, XprT, \ + _OpT_ \ + > \ +> \ + \ +_op_ ( \ + const quaternion& left, \ + QUATXPR_ARG_TYPE right) \ +{ \ + typedef et::BinaryQuaternionOp< \ + quaternion, XprT, \ + _OpT_ \ + > ExprT; \ + return et::QuaternionXpr(ExprT(left,right.expression())); \ +} + + +/** Declare an operator taking an et::QuaternionXpr and a quaternion. */ +#define CML_QUATXPR_QUAT_BINOP(_op_, _OpT_) \ +template \ +inline et::QuaternionXpr< \ + et::BinaryQuaternionOp< \ + XprT, quaternion, \ + _OpT_ \ + > \ +> \ + \ +_op_ ( \ + QUATXPR_ARG_TYPE left, \ + const quaternion& right) \ +{ \ + typedef et::BinaryQuaternionOp< \ + XprT, quaternion, \ + _OpT_ \ + > ExprT; \ + return et::QuaternionXpr(ExprT(left.expression(),right)); \ +} + + +/** Declare an operator taking two et::QuaternionXpr operands. */ +#define CML_QUATXPR_QUATXPR_BINOP(_op_, _OpT_) \ +template \ +inline et::QuaternionXpr< \ + et::BinaryQuaternionOp< \ + XprT1, XprT2, \ + _OpT_ < \ + typename XprT1::value_type, \ + typename XprT2::value_type \ + > \ + > \ +> \ + \ +_op_ ( \ + QUATXPR_ARG_TYPE_N(1) left, \ + QUATXPR_ARG_TYPE_N(2) right) \ +{ \ + typedef et::BinaryQuaternionOp< \ + XprT1, XprT2, \ + _OpT_ < \ + typename XprT1::value_type, \ + typename XprT2::value_type> \ + > ExprT; \ + return et::QuaternionXpr( \ + ExprT(left.expression(),right.expression())); \ +} + + +/** Declare an operator taking a quaternion and a scalar. */ +#define CML_QUAT_SCALAR_BINOP(_op_, _OpT_) \ +template \ +inline et::QuaternionXpr< \ + et::BinaryQuaternionOp< \ + quaternion, ScalarT, \ + _OpT_ \ + > \ +> \ + \ +_op_ ( \ + const quaternion& left, \ + SCALAR_ARG_TYPE right) \ +{ \ + typedef et::BinaryQuaternionOp< \ + quaternion, ScalarT, _OpT_ \ + > ExprT; \ + return et::QuaternionXpr(ExprT(left,right)); \ +} + + +/** Declare an operator taking a scalar and a quaternion. */ +#define CML_SCALAR_QUAT_BINOP(_op_, _OpT_) \ +template \ +inline et::QuaternionXpr< \ + et::BinaryQuaternionOp< \ + ScalarT, quaternion, _OpT_ \ + > \ +> \ + \ +_op_ ( \ + SCALAR_ARG_TYPE left, \ + const quaternion& right) \ +{ \ + typedef et::BinaryQuaternionOp< \ + ScalarT, quaternion, _OpT_ \ + > ExprT; \ + return et::QuaternionXpr(ExprT(left,right)); \ +} + + +/** Declare an operator taking a et::QuaternionXpr and a scalar. */ +#define CML_QUATXPR_SCALAR_BINOP(_op_, _OpT_) \ +template \ +inline et::QuaternionXpr< \ + et::BinaryQuaternionOp< \ + XprT, ScalarT, _OpT_ \ + > \ +> \ + \ +_op_ ( \ + QUATXPR_ARG_TYPE left, \ + SCALAR_ARG_TYPE right) \ +{ \ + typedef et::BinaryQuaternionOp< \ + XprT, ScalarT, _OpT_ \ + > ExprT; \ + return et::QuaternionXpr(ExprT(left.expression(),right)); \ +} + + +/** Declare an operator taking a scalar and a et::QuaternionXpr. */ +#define CML_SCALAR_QUATXPR_BINOP(_op_, _OpT_) \ +template \ +inline et::QuaternionXpr< \ + et::BinaryQuaternionOp< \ + ScalarT, XprT, _OpT_ \ + > \ +> \ + \ +_op_ ( \ + SCALAR_ARG_TYPE left, \ + QUATXPR_ARG_TYPE right) \ +{ \ + typedef et::BinaryQuaternionOp< \ + ScalarT, XprT, \ + _OpT_ \ + > ExprT; \ + return et::QuaternionXpr(ExprT(left,right.expression())); \ +} + +#endif + +// ------------------------------------------------------------------------- +// vim:ft=cpp diff --git a/Lib/Include/CML/util.h b/Lib/Include/CML/util.h new file mode 100644 index 0000000..b55a0e5 --- /dev/null +++ b/Lib/Include/CML/util.h @@ -0,0 +1,368 @@ +/* -*- C++ -*- ------------------------------------------------------------ + +Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/ + +The Configurable Math Library (CML) is distributed under the terms of the +Boost Software License, v1.0 (see cml/LICENSE for details). + + *-----------------------------------------------------------------------*/ +/** @file + * @brief + */ + +#ifndef cml_util_h +#define cml_util_h + +#include // For std::min and std::max. +#include // For std::rand. +#include + +#if defined(_MSC_VER) +#pragma push_macro("min") +#pragma push_macro("max") +#undef min +#undef max +#endif + +namespace cml { + +/** Sign of input value as double. */ +template < typename T > +double sign(T value) { + return value < T(0) ? -1.0 : (value > T(0) ? 1.0 : 0.0); +} + +/** Clamp input value to the range [min, max]. */ +template < typename T > +T clamp(T value, T min, T max) { + return std::max(std::min(value, max), min); +} + +/** Test input value for inclusion in [min, max]. */ +template < typename T > +bool in_range(T value, T min, T max) { + return !(value < min) && !(value > max); +} + +/** Map input value from [min1, max1] to [min2, max2]. */ +template < typename T > +T map_range(T value, T min1, T max1, T min2, T max2) { + return min2 + ((value - min1) / (max1 - min1)) * (max2 - min2); +} + + +/** Wrap std::acos() and clamp argument to [-1, 1]. */ +template < typename T > +T acos_safe(T theta) { + return T(std::acos(clamp(theta, T(-1.0), T(1.0)))); +} + +/** Wrap std::asin() and clamp argument to [-1, 1]. */ +template < typename T > +T asin_safe(T theta) { + return T(std::asin(clamp(theta, T(-1.0), T(1.0)))); +} + +/** Wrap std::sqrt() and clamp argument to [0, inf). */ +template < typename T > +T sqrt_safe(T value) { + return T(std::sqrt(std::max(value, T(0.0)))); +} + + +/** Square a value. */ +template < typename T > +T sqr(T value) { + return value * value; +} + +/** Cube a value. */ +template < typename T > +T cub(T value) { + return value * value * value; +} + +/** Inverse square root. */ +template < typename T > +T inv_sqrt(T value) { + return T(1.0 / std::sqrt(value)); +} + + +/* The next few functions deal with indexing. next() and prev() are useful + * for operations involving the vertices of a polygon or other cyclic set, + * and cyclic_permutation() is used by various functions that deal with + * axes or basis vectors in a generic way. As these functions are only + * relevant for unsigned integer types, I've just used size_t, but there + * may be reasons I haven't thought of that they should be templated. + */ + +/** Return next, with cycling, in a series of N non-negative integers. */ +inline size_t next(size_t i, size_t N) { + return (i + 1) % N; +} + +/** Return previous, with cycling, in a series of N non-negative integers. */ +inline size_t prev(size_t i, size_t N) { + return i ? (i - 1) : (N - 1); +} + +/** Cyclic permutation of the set { 0, 1 }, starting with 'first'. */ +inline void cyclic_permutation(size_t first, size_t& i, size_t& j) { + i = first; + j = next(i, 2); +} + +/** Cyclic permutation of the set { 0, 1, 2 }, starting with 'first'. */ +inline void cyclic_permutation(size_t first, size_t& i, size_t& j, size_t& k) +{ + i = first; + j = next(i, 3); + k = next(j, 3); +} + +/** Cyclic permutation of the set { 0, 1, 2, 3 }, starting with 'first'. */ +inline void cyclic_permutation( + size_t first, size_t& i, size_t& j, size_t& k, size_t& l) +{ + i = first; + j = next(i, 4); + k = next(j, 4); + l = next(k, 4); +} + + +/** Convert radians to degrees. */ +template < typename T > +T deg(T theta) { + return theta * constants::deg_per_rad(); +} + +/** Convert degrees to radians. */ +template < typename T > +T rad(T theta) { + return theta * constants::rad_per_deg(); +} + +/* Note: Moving interpolation functions to interpolation.h */ + +#if 0 +/** Linear interpolation of 2 values. + * + * @note The data points are assumed to be sampled at u = 0 and u = 1, so + * for interpolation u must lie between 0 and 1. + */ +template +T lerp(const T& f0, const T& f1, Scalar u) { + return (Scalar(1.0) - u) * f0 + u * f1; +} +#endif + +#if 0 +/** Bilinear interpolation of 4 values. + * + * @note The data points are assumed to be sampled at the corners of a unit + * square, so for interpolation u and v must lie between 0 and 1, + */ +template +T bilerp(const T& f00, const T& f10, + const T& f01, const T& f11, + Scalar u, Scalar v) +{ + Scalar uv = u * v; + return ( + (Scalar(1.0) - u - v + uv) * f00 + + (u - uv) * f10 + + (v - uv) * f01 + + uv * f11 + ); +} +#endif + +#if 0 +/** Trilinear interpolation of 8 values. + * + * @note The data values are assumed to be sampled at the corners of a unit + * cube, so for interpolation, u, v, and w must lie between 0 and 1. + */ +template +T trilerp(const T& f000, const T& f100, + const T& f010, const T& f110, + const T& f001, const T& f101, + const T& f011, const T& f111, + Scalar u, Scalar v, Scalar w) +{ + Scalar uv = u * v; + Scalar vw = v * w; + Scalar wu = w * u; + Scalar uvw = uv * w; + + return ( + (Scalar(1.0) - u - v - w + uv + vw + wu - uvw) * f000 + + (u - uv - wu + uvw) * f100 + + (v - uv - vw + uvw) * f010 + + (uv - uvw) * f110 + + (w - vw - wu + uvw) * f001 + + (wu - uvw) * f101 + + (vw - uvw) * f011 + + uvw * f111 + ); +} +#endif + +/** Random binary (0,1) value. */ +inline size_t random_binary() { + return std::rand() % 2; +} + +/** Random polar (-1,1) value. */ +inline int random_polar() { + return random_binary() ? 1 : -1; +} + +/** Random real in [0,1]. */ +inline double random_unit() { + return double(std::rand()) / double(RAND_MAX); +} + +/* Random integer in the range [min, max] */ +inline long random_integer(long min, long max) { + return min + std::rand() % (max - min + 1); +} + +/* Random real number in the range [min, max] */ +template < typename T > +T random_real(T min, T max) { + return min + static_cast(random_unit()) * (max - min); +} + +/** Squared length in R2. */ +template < typename T > +T length_squared(T x, T y) { + return x * x + y * y; +} + +/** Squared length in R3. */ +template < typename T > +T length_squared(T x, T y, T z) { + return x * x + y * y + z * z; +} + +/** Length in R2. */ +template < typename T > +T length(T x, T y) { + return std::sqrt(length_squared(x,y)); +} + +/** Length in R3. */ +template < typename T > +T length(T x, T y, T z) { + return std::sqrt(length_squared(x,y,z)); +} + +/** Index of maximum of 2 values. */ +template < typename T > +size_t index_of_max(T a, T b) { + return a > b ? 0 : 1; +} + +/** Index of maximum of 2 values by magnitude. */ +template < typename T > +size_t index_of_max_abs(T a, T b) { + return index_of_max(std::fabs(a),std::fabs(b)); +} + +/** Index of minimum of 2 values. */ +template < typename T > +size_t index_of_min(T a, T b) { + return a < b ? 0 : 1; +} + +/** Index of minimum of 2 values by magnitude. */ +template < typename T > +size_t index_of_min_abs(T a, T b) { + return index_of_min(std::fabs(a),std::fabs(b)); +} + +/** Index of maximum of 3 values. */ +template < typename T > +size_t index_of_max(T a, T b, T c) { + return a > b ? (c > a ? 2 : 0) : (b > c ? 1 : 2); +} + +/** Index of maximum of 3 values by magnitude. */ +template < typename T > +size_t index_of_max_abs(T a, T b, T c) { + return index_of_max(std::fabs(a),std::fabs(b),std::fabs(c)); +} + +/** Index of minimum of 3 values. */ +template < typename T > +size_t index_of_min(T a, T b, T c) { + return a < b ? (c < a ? 2 : 0) : (b < c ? 1 : 2); +} + +/** Index of minimum of 3 values by magnitude. */ +template < typename T > +size_t index_of_min_abs(T a, T b, T c) { + return index_of_min(std::fabs(a),std::fabs(b),std::fabs(c)); +} + +/** Wrap input value to the range [min,max]. */ +template < typename T > +T wrap(T value, T min, T max) { + max -= min; + value = std::fmod(value - min, max); + if (value < T(0)) { + value += max; + } + return min + value; +} + +/** Convert horizontal field of view to vertical field of view. */ +template < typename T > +T xfov_to_yfov(T xfov, T aspect) { + return T(2.0 * std::atan(std::tan(xfov * T(.5)) / double(aspect))); +} + +/** Convert vertical field of view to horizontal field of view. */ +template < typename T > +T yfov_to_xfov(T yfov, T aspect) { + return T(2.0 * std::atan(std::tan(yfov * T(.5)) * double(aspect))); +} + +/** Convert horizontal zoom to vertical zoom. */ +template < typename T > +T xzoom_to_yzoom(T xzoom, T aspect) { + return xzoom * aspect; +} + +/** Convert vertical zoom to horizontal zoom. */ +template < typename T > +T yzoom_to_xzoom(T yzoom, T aspect) { + return yzoom / aspect; +} + +/** Convert zoom factor to field of view. */ +template < typename T > +T zoom_to_fov(T zoom) { + return T(2) * T(std::atan(T(1) / zoom)); +} + +/** Convert field of view to zoom factor. */ +template < typename T > +T fov_to_zoom(T fov) { + return T(1) / T(std::tan(fov * T(.5))); +} + +} // namespace cml + +#if defined(_MSC_VER) +#pragma pop_macro("min") +#pragma pop_macro("max") +#endif + +#endif + +// ------------------------------------------------------------------------- +// vim:ft=cpp diff --git a/Lib/Include/CML/vector.h b/Lib/Include/CML/vector.h new file mode 100644 index 0000000..58c3c91 --- /dev/null +++ b/Lib/Include/CML/vector.h @@ -0,0 +1,62 @@ +/* -*- C++ -*- ------------------------------------------------------------ + +Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/ + +The Configurable Math Library (CML) is distributed under the terms of the +Boost Software License, v1.0 (see cml/LICENSE for details). + + *-----------------------------------------------------------------------*/ +/** @file + * @brief + * + * The configurable vector<> class. + */ + +#ifndef cml_vector_h +#define cml_vector_h + +#include + +namespace cml { + +/** A configurable vector type. + * + * This class encapsulates the notion of a vector. The ArrayType template + * argument can be used to select the type of array to be used as internal + * storage for a list of type Element. The vector orientation determines + * how vectors are used arithmetically in expressions; i.e. a*b, when a is + * a row vector and b is a column vector, is the dot (inner) product, while + * a*b, when a is a column vector and b is a row vector, is the matrix + * (outer) product of a and b. + * + * @internal Unlike the previous version, this uses specializations to + * better enable varied array and vector types. For example, with the + * rebind method, it's difficult to support external<> vector types that + * should not be assigned to. + * + * @internal All assignments to the vector should go through UnrollAssignment, + * which ensures that the source expression and the destination vector have + * the same size. This is particularly important for dynamically-sized + * vectors. + */ +template class vector; + +} // namespace cml + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#endif + +// ------------------------------------------------------------------------- +// vim:ft=cpp diff --git a/Lib/Include/CML/vector/class_ops.h b/Lib/Include/CML/vector/class_ops.h new file mode 100644 index 0000000..0b7a361 --- /dev/null +++ b/Lib/Include/CML/vector/class_ops.h @@ -0,0 +1,238 @@ +/* -*- C++ -*- ------------------------------------------------------------ + +Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/ + +The Configurable Math Library (CML) is distributed under the terms of the +Boost Software License, v1.0 (see cml/LICENSE for details). + + *-----------------------------------------------------------------------*/ +/** @file + * @brief Vector class operators. + */ + +#ifndef vector_class_ops_h +#define vector_class_ops_h + +#if defined(_MSC_VER) && _MSC_VER < 1400 +#pragma warning(disable:4003) +// XXX Horrible hack to turn off warnings about "not enough actual params" +// for the macros below. +#endif + +/* XXX HACK!!! This is a hack to resize in the assign() functions only when + * auto resizing is turned off. + */ +#if !defined(CML_VECTOR_RESIZE_ON_ASSIGNMENT) +#define _DO_VECTOR_SET_RESIZE(_N_) cml::et::detail::Resize(*this,_N_) +#else +#define _DO_VECTOR_SET_RESIZE(_N_) +#endif + +/** Set a vector from 2 values. */ +#define CML_ASSIGN_VEC_2 \ +vector_type& \ +set(ELEMENT_ARG_TYPE e0, ELEMENT_ARG_TYPE e1) { \ + _DO_VECTOR_SET_RESIZE(2); \ + /* This is overkill, but simplifies size checking: */ \ + value_type v[] = {e0,e1}; \ + typedef et::OpAssign OpT; \ + cml::vector< const value_type, external<2> > src(v); \ + et::UnrollAssignment(*this,src); \ + return *this; \ +} + +/** Set a vector from 3 values. */ +#define CML_ASSIGN_VEC_3 \ +vector_type& \ +set( \ + ELEMENT_ARG_TYPE e0, \ + ELEMENT_ARG_TYPE e1, \ + ELEMENT_ARG_TYPE e2 \ + ) \ +{ \ + _DO_VECTOR_SET_RESIZE(3); \ + /* This is overkill, but simplifies size checking: */ \ + value_type v[] = {e0,e1,e2}; \ + typedef et::OpAssign OpT; \ + cml::vector< const value_type, external<3> > src(v); \ + et::UnrollAssignment(*this,src); \ + return *this; \ +} + +/** Create a vector from 4 values. */ +#define CML_ASSIGN_VEC_4 \ +vector_type& \ +set( \ + ELEMENT_ARG_TYPE e0, \ + ELEMENT_ARG_TYPE e1, \ + ELEMENT_ARG_TYPE e2, \ + ELEMENT_ARG_TYPE e3 \ + ) \ +{ \ + _DO_VECTOR_SET_RESIZE(4); \ + /* This is overkill, but simplifies size checking: */ \ + value_type v[] = {e0,e1,e2,e3}; \ + typedef et::OpAssign OpT; \ + cml::vector< const value_type, external<4> > src(v); \ + et::UnrollAssignment(*this,src); \ + return *this; \ +} + + +/** Create a vector from 2 values. */ +#define CML_CONSTRUCT_VEC_2(_add_) \ +vector(ELEMENT_ARG_TYPE e0, ELEMENT_ARG_TYPE e1) _add_ { \ + set(e0,e1); \ +} + +/** Create a vector from 3 values. */ +#define CML_CONSTRUCT_VEC_3(_add_) \ +vector( \ + ELEMENT_ARG_TYPE e0, \ + ELEMENT_ARG_TYPE e1, \ + ELEMENT_ARG_TYPE e2 \ + ) _add_ \ +{ \ + set(e0,e1,e2); \ +} + +/** Create a vector from 4 values. */ +#define CML_CONSTRUCT_VEC_4(_add_) \ +vector( \ + ELEMENT_ARG_TYPE e0, \ + ELEMENT_ARG_TYPE e1, \ + ELEMENT_ARG_TYPE e2, \ + ELEMENT_ARG_TYPE e3 \ + ) _add_ \ +{ \ + set(e0,e1,e2,e3); \ +} + +/** Create a (fixed-size) N vector from an N-1-vector and a scalar. */ +#define CML_CONSTRUCT_FROM_SUBVEC(_add_) \ +vector( \ + const subvector_type& s, \ + ELEMENT_ARG_TYPE e \ + ) _add_ \ +{ \ + _DO_VECTOR_SET_RESIZE(s.size()+1); \ + for(size_t i = 0; i < s.size(); ++ i) \ + (*this)[i] = s[i]; \ + (*this)[s.size()] = e; \ +} + +/** Copy-construct a vector from a fixed-size array of values. */ +#define CML_VEC_COPY_FROM_FIXED_ARRAY(_N_,_add_) \ +vector(const value_type v[_N_]) _add_ { \ + typedef et::OpAssign OpT; \ + cml::vector< const value_type, external<_N_> > src(v); \ + et::UnrollAssignment(*this,src); \ +} + +/** Copy-construct a vector from a runtime-sized array of values. */ +#define CML_VEC_COPY_FROM_ARRAY(_add_) \ +vector(const value_type* const v, size_t N) _add_ { \ + typedef et::OpAssign OpT; \ + cml::vector > src(v,N); \ + et::UnrollAssignment(*this,src); \ +} + +/** Copy-construct a vector. + * + * @internal This is required for GCC4, since it won't elide the default + * copy constructor. + */ +#define CML_VEC_COPY_FROM_VECTYPE(_add_) \ +vector(const vector_type& v) _add_ { \ + typedef et::OpAssign OpT; \ + et::UnrollAssignment(*this,v); \ +} + +/** Construct from an arbitrary vector. + * + * @param v the vector to copy from. + */ +#define CML_VEC_COPY_FROM_VEC \ +template \ +vector(const vector& m) { \ + typedef et::OpAssign OpT; \ + et::UnrollAssignment(*this,m); \ +} + +/** Construct from a vector expression. + * + * @param expr the expression to copy from. + */ +#define CML_VEC_COPY_FROM_VECXPR \ +template \ +vector(VECXPR_ARG_TYPE e) { \ + /* Verify that a promotion exists at compile time: */ \ + typedef typename et::VectorPromote< \ + vector_type, typename XprT::result_type>::type result_type; \ + typedef typename XprT::value_type src_value_type; \ + typedef et::OpAssign OpT; \ + et::UnrollAssignment(*this,e); \ +} + +/** Assign from the same vector type. + * + * @param v the vector to copy from. + */ +#define CML_VEC_ASSIGN_FROM_VECTYPE \ +vector_type& operator=(const vector_type& v) { \ + typedef et::OpAssign OpT; \ + et::UnrollAssignment(*this,v); \ + return *this; \ +} + +/** Assign this vector from another using the given elementwise op. + * + * This allows assignment from arbitrary vector types. + * + * @param _op_ the operator (e.g. +=) + * @param _op_name_ the op functor (e.g. et::OpAssign) + */ +#define CML_VEC_ASSIGN_FROM_VEC(_op_, _op_name_) \ +template vector_type& \ +operator _op_ (const cml::vector& m) { \ + typedef _op_name_ OpT; \ + cml::et::UnrollAssignment(*this,m); \ + return *this; \ +} + +/** Declare a function to assign this vector from a vector expression. + * + * @param _op_ the operator (e.g. +=) + * @param _op_name_ the op functor (e.g. et::OpAssign) + */ +#define CML_VEC_ASSIGN_FROM_VECXPR(_op_, _op_name_) \ +template vector_type& \ +operator _op_ (VECXPR_ARG_TYPE e) { \ + /* Verify that a promotion exists at compile time: */ \ + typedef typename et::VectorPromote< \ + vector_type, typename XprT::result_type>::type result_type; \ + typedef typename XprT::value_type src_value_type; \ + typedef _op_name_ OpT; \ + cml::et::UnrollAssignment(*this,e); \ + return *this; \ +} + +/** Declare a function to assign this vector from a scalar. + * + * @param _op_ the operator (e.g. *=) + * @param _op_name_ the op functor (e.g. et::OpAssign) + * + * @internal This shouldn't be used for ops, like +=, which aren't + * defined in vector algebra. + */ +#define CML_VEC_ASSIGN_FROM_SCALAR(_op_, _op_name_) \ +vector_type& operator _op_ (ELEMENT_ARG_TYPE s) { \ + typedef _op_name_ OpT; \ + cml::et::UnrollAssignment(*this,s); \ + return *this; \ +} + +#endif + +// ------------------------------------------------------------------------- +// vim:ft=cpp diff --git a/Lib/Include/CML/vector/dynamic.h b/Lib/Include/CML/vector/dynamic.h new file mode 100644 index 0000000..023a86c --- /dev/null +++ b/Lib/Include/CML/vector/dynamic.h @@ -0,0 +1,190 @@ +/* -*- C++ -*- ------------------------------------------------------------ + +Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/ + +The Configurable Math Library (CML) is distributed under the terms of the +Boost Software License, v1.0 (see cml/LICENSE for details). + + *-----------------------------------------------------------------------*/ +/** @file + * @brief Specialization for resizeable, dynamic-memory vector. + */ + +#ifndef dynamic_vector_h +#define dynamic_vector_h + +#include +#include +#include +#include + +namespace cml { + +/** Resizeable, dynamic-memory vector. */ +template +class vector< Element, dynamic > +: public dynamic_1D +{ + public: + + /* Shorthand for the generator: */ + typedef dynamic<> storage_type; + typedef dynamic generator_type; + + /* Shorthand for the array type: */ + typedef dynamic_1D array_type; + + /* Shorthand for the type of this vector: */ + typedef vector vector_type; + + /* The vector coordinate type: */ + typedef Element coordinate_type; + + /* For integration into the expression template code: */ + typedef vector_type expr_type; + + /* For integration into the expression template code: */ + typedef vector_type temporary_type; + + /* The type for a vector in one lower dimension: */ + typedef vector_type subvector_type; + + /* Standard: */ + typedef typename array_type::value_type value_type; + typedef typename array_type::reference reference; + typedef typename array_type::const_reference const_reference; + + /* For integration into the expression templates code: */ + typedef vector_type& expr_reference; + typedef const vector_type& expr_const_reference; + + /* For matching by storage type: */ + typedef typename array_type::memory_tag memory_tag; + + /* For matching by size type: */ + typedef typename array_type::size_tag size_tag; + + /* For matching by resizability: */ + typedef typename array_type::resizing_tag resizing_tag; + + /* For matching by result-type: */ + typedef cml::et::vector_result_tag result_tag; + + /* For matching by assignability: */ + typedef cml::et::assignable_tag assignable_tag; + + + public: + + /** Return square of the length. */ + value_type length_squared() const { + return cml::dot(*this,*this); + } + + /** Return the length. */ + value_type length() const { + return std::sqrt(length_squared()); + } + + /** Normalize the vector. */ + vector_type& normalize() { + return (*this /= length()); + } + + /** Set this vector to [0]. */ + vector_type& zero() { + typedef cml::et::OpAssign OpT; + cml::et::UnrollAssignment(*this,Element(0)); + return *this; + } + + /** Set this vector to a cardinal vector. */ + vector_type& cardinal(size_t i) { + zero(); + (*this)[i] = Element(1); + return *this; + } + + /** Pairwise minimum of this vector with another. */ + template + void minimize(const vector& v) { + /* XXX This should probably use ScalarPromote: */ + for (size_t i = 0; i < this->size(); ++i) { + (*this)[i] = std::min((*this)[i],v[i]); + } + } + + /** Pairwise maximum of this vector with another. */ + template + void maximize(const vector& v) { + /* XXX This should probably use ScalarPromote: */ + for (size_t i = 0; i < this->size(); ++i) { + (*this)[i] = std::max((*this)[i],v[i]); + } + } + + /** Fill vector with random elements. */ + void random(value_type min, value_type max) { + for (size_t i = 0; i < this->size(); ++i) { + (*this)[i] = cml::random_real(min,max); + } + } + + /** Return a subvector by removing element i. + * + * @internal This is horribly inefficient... + */ + subvector_type subvector(size_t i) const { + subvector_type s; s.resize(this->size()-1); + for(size_t m = 0, n = 0; m < this->size(); ++ m) + if(m != i) s[n++] = (*this)[m]; + return s; + }; + + + public: + + /** Default constructor. */ + vector() : array_type() {} + + /** Construct given array size. */ + vector(size_t N) : array_type(N) {} + + + public: + + /* Define common class operators: */ + + CML_CONSTRUCT_VEC_2(: array_type()) + CML_CONSTRUCT_VEC_3(: array_type()) + CML_CONSTRUCT_VEC_4(: array_type()) + + CML_VEC_COPY_FROM_ARRAY(: array_type()) + CML_VEC_COPY_FROM_VECTYPE(: array_type()) + CML_VEC_COPY_FROM_VEC + CML_VEC_COPY_FROM_VECXPR + + CML_ASSIGN_VEC_2 + CML_ASSIGN_VEC_3 + CML_ASSIGN_VEC_4 + + CML_VEC_ASSIGN_FROM_VECTYPE + + CML_VEC_ASSIGN_FROM_VEC(=, cml::et::OpAssign) + CML_VEC_ASSIGN_FROM_VEC(+=, cml::et::OpAddAssign) + CML_VEC_ASSIGN_FROM_VEC(-=, cml::et::OpSubAssign) + + CML_VEC_ASSIGN_FROM_VECXPR(=, cml::et::OpAssign) + CML_VEC_ASSIGN_FROM_VECXPR(+=, cml::et::OpAddAssign) + CML_VEC_ASSIGN_FROM_VECXPR(-=, cml::et::OpSubAssign) + + CML_VEC_ASSIGN_FROM_SCALAR(*=, cml::et::OpMulAssign) + CML_VEC_ASSIGN_FROM_SCALAR(/=, cml::et::OpDivAssign) +}; + +} // namespace cml + +#endif + +// ------------------------------------------------------------------------- +// vim:ft=cpp diff --git a/Lib/Include/CML/vector/external.h b/Lib/Include/CML/vector/external.h new file mode 100644 index 0000000..d0f7194 --- /dev/null +++ b/Lib/Include/CML/vector/external.h @@ -0,0 +1,343 @@ +/* -*- C++ -*- ------------------------------------------------------------ + +Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/ + +The Configurable Math Library (CML) is distributed under the terms of the +Boost Software License, v1.0 (see cml/LICENSE for details). + + *-----------------------------------------------------------------------*/ +/** @file + * @brief Specializations for external-memory vectors. + * + * @note Copy-constructing one external<> vector from another is not + * supported, since an external<> vector is essentially a wrapper for a + * pointer and has no allocated storage of its own. + */ + +#ifndef external_vector_h +#define external_vector_h + +#include +#include +#include +#include +#include + +namespace cml { + +/** Fixed-size, fixed-memory vector. */ +template +class vector< Element, external > +: public external_1D +{ + public: + + /* Shorthand for the generator: */ + typedef external<> storage_type; + typedef external generator_type; + + /* Shorthand for the array type: */ + typedef external_1D array_type; + + /* Shorthand for the type of this vector: */ + typedef vector vector_type; + + /* The vector coordinate type: */ + typedef Element coordinate_type; + + /* For integration into the expression template code: */ + typedef vector_type expr_type; + + /* For integration into the expression template code: */ + typedef vector::type, + fixed > temporary_type; + /* Note: this ensures that an external vector is copied into the proper + * temporary; external<> temporaries are not allowed. + */ + + /* The type for a vector in one lower dimension: */ + typedef typename temporary_type::subvector_type subvector_type; + + /* Standard: */ + typedef typename array_type::value_type value_type; + typedef typename array_type::reference reference; + typedef typename array_type::const_reference const_reference; + + /* For integration into the expression templates code: */ + typedef vector_type& expr_reference; + typedef const vector_type& expr_const_reference; + + /* For matching by storage type: */ + typedef typename array_type::memory_tag memory_tag; + + /* For matching by size type: */ + typedef typename array_type::size_tag size_tag; + + /* For matching by result-type: */ + typedef cml::et::vector_result_tag result_tag; + + /* For matching by assignability: */ + typedef cml::et::assignable_tag assignable_tag; + + + public: + + /** Static constant containing the vector's space dimension. */ + enum { dimension = Size }; + + + public: + + /** Return square of the length. */ + value_type length_squared() const { + return cml::dot(*this,*this); + } + + /** Return the length. */ + value_type length() const { + return std::sqrt(length_squared()); + } + + /** Normalize the vector. */ + vector_type& normalize() { + return (*this /= length()); + } + + /** Set this vector to [0]. */ + vector_type& zero() { + typedef cml::et::OpAssign OpT; + cml::et::UnrollAssignment(*this,Element(0)); + return *this; + } + + /** Set this vector to a cardinal vector. */ + vector_type& cardinal(size_t i) { + zero(); + (*this)[i] = Element(1); + return *this; + } + + /** Pairwise minimum of this vector with another. */ + template + void minimize(const vector& v) { + /* XXX This should probably use ScalarPromote: */ + for (size_t i = 0; i < this->size(); ++i) { + (*this)[i] = std::min((*this)[i],v[i]); + } + } + + /** Pairwise maximum of this vector with another. */ + template + void maximize(const vector& v) { + /* XXX This should probably use ScalarPromote: */ + for (size_t i = 0; i < this->size(); ++i) { + (*this)[i] = std::max((*this)[i],v[i]); + } + } + + /** Fill vector with random elements. */ + void random(value_type min, value_type max) { + for (size_t i = 0; i < this->size(); ++i) { + (*this)[i] = cml::random_real(min,max); + } + } + + /** Return a subvector by removing element i. + * + * @internal This is horribly inefficient... + */ + subvector_type subvector(size_t i) const { + subvector_type s; + for(size_t m = 0, n = 0; m < this->size(); ++ m) + if(m != i) s[n++] = (*this)[m]; + return s; + }; + + + public: + + /** Construct from an array of values. */ + vector(Element* const array) : array_type(array) {} + + + public: + + CML_ASSIGN_VEC_2 + CML_ASSIGN_VEC_3 + CML_ASSIGN_VEC_4 + + CML_VEC_ASSIGN_FROM_VECTYPE + + /* Only assignment operators can be used to copy from other types: */ + CML_VEC_ASSIGN_FROM_VEC(=, cml::et::OpAssign) + CML_VEC_ASSIGN_FROM_VEC(+=, cml::et::OpAddAssign) + CML_VEC_ASSIGN_FROM_VEC(-=, cml::et::OpSubAssign) + + CML_VEC_ASSIGN_FROM_VECXPR(=, cml::et::OpAssign) + CML_VEC_ASSIGN_FROM_VECXPR(+=, cml::et::OpAddAssign) + CML_VEC_ASSIGN_FROM_VECXPR(-=, cml::et::OpSubAssign) + + CML_VEC_ASSIGN_FROM_SCALAR(*=, cml::et::OpMulAssign) + CML_VEC_ASSIGN_FROM_SCALAR(/=, cml::et::OpDivAssign) +}; + +/** Run-time sized vector. */ +template +class vector< Element, external<> > +: public external_1D +{ + public: + + /* Shorthand for the generator: */ + typedef external<> storage_type; + typedef external<> generator_type; + + /* Shorthand for the array type: */ + typedef external_1D array_type; + + /* Shorthand for the type of this vector: */ + typedef vector vector_type; + + /* For integration into the expression template code: */ + typedef vector_type expr_type; + + /* For integration into the expression template code: */ + typedef vector::type, + dynamic<> > temporary_type; + /* Note: this ensures that an external vector is copied into the proper + * temporary; external<> temporaries are not allowed. + */ + + /* The type for a vector in one lower dimension: */ + typedef typename temporary_type::subvector_type subvector_type; + + /* Standard: */ + typedef typename array_type::value_type value_type; + typedef typename array_type::reference reference; + typedef typename array_type::const_reference const_reference; + + /* For integration into the expression templates code: */ + typedef vector_type& expr_reference; + typedef const vector_type& expr_const_reference; + + /* For matching by storage type: */ + typedef typename array_type::memory_tag memory_tag; + + /* For matching by size type: */ + typedef typename array_type::size_tag size_tag; + + /* For matching by resizability: */ + typedef typename array_type::resizing_tag resizing_tag; + + /* For matching by result-type: */ + typedef cml::et::vector_result_tag result_tag; + + /* For matching by assignability: */ + typedef cml::et::assignable_tag assignable_tag; + + + public: + + /** Return square of the length. */ + value_type length_squared() const { + return dot(*this,*this); + } + + /** Return the length. */ + value_type length() const { + return std::sqrt(length_squared()); + } + + /** Normalize the vector. */ + vector_type& normalize() { + return (*this /= length()); + } + + /** Set this vector to [0]. */ + vector_type& zero() { + typedef cml::et::OpAssign OpT; + cml::et::UnrollAssignment(*this,Element(0)); + return *this; + } + + /** Set this vector to a cardinal vector. */ + vector_type& cardinal(size_t i) { + zero(); + (*this)[i] = Element(1); + return *this; + } + + /** Pairwise minimum of this vector with another. */ + template + void minimize(const vector& v) { + /* XXX This should probably use ScalarPromote: */ + for (size_t i = 0; i < this->size(); ++i) { + (*this)[i] = std::min((*this)[i],v[i]); + } + } + + /** Pairwise maximum of this vector with another. */ + template + void maximize(const vector& v) { + /* XXX This should probably use ScalarPromote: */ + for (size_t i = 0; i < this->size(); ++i) { + (*this)[i] = std::max((*this)[i],v[i]); + } + } + + /** Fill vector with random elements. */ + void random(value_type min, value_type max) { + for (size_t i = 0; i < this->size(); ++i) { + (*this)[i] = random_real(min,max); + } + } + + /** Return a subvector by removing element i. + * + * @internal This is horribly inefficient... + */ + subvector_type subvector(size_t i) const { + subvector_type s; s.resize(this->size()-1); + for(size_t m = 0, n = 0; m < this->size(); ++ m) + if(m != i) s[n++] = (*this)[m]; + return s; + }; + + + public: + + /** Construct from an array of values and the size. */ + vector(Element* const array, size_t size) + : array_type(array, size) {} + + + public: + + /* Define class operators for external vectors. Note: external vectors + * cannot be copy-constructed, but they can be assigned to: + */ + CML_ASSIGN_VEC_2 + CML_ASSIGN_VEC_3 + CML_ASSIGN_VEC_4 + + CML_VEC_ASSIGN_FROM_VECTYPE + + /* Only assignment operators can be used to copy from other types: */ + CML_VEC_ASSIGN_FROM_VEC(=, cml::et::OpAssign) + CML_VEC_ASSIGN_FROM_VEC(+=, cml::et::OpAddAssign) + CML_VEC_ASSIGN_FROM_VEC(-=, cml::et::OpSubAssign) + + CML_VEC_ASSIGN_FROM_VECXPR(=, cml::et::OpAssign) + CML_VEC_ASSIGN_FROM_VECXPR(+=, cml::et::OpAddAssign) + CML_VEC_ASSIGN_FROM_VECXPR(-=, cml::et::OpSubAssign) + + CML_VEC_ASSIGN_FROM_SCALAR(*=, cml::et::OpMulAssign) + CML_VEC_ASSIGN_FROM_SCALAR(/=, cml::et::OpDivAssign) +}; + +} // namespace cml + +#endif + +// ------------------------------------------------------------------------- +// vim:ft=cpp diff --git a/Lib/Include/CML/vector/fixed.h b/Lib/Include/CML/vector/fixed.h new file mode 100644 index 0000000..20f49cc --- /dev/null +++ b/Lib/Include/CML/vector/fixed.h @@ -0,0 +1,196 @@ +/* -*- C++ -*- ------------------------------------------------------------ + +Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/ + +The Configurable Math Library (CML) is distributed under the terms of the +Boost Software License, v1.0 (see cml/LICENSE for details). + + *-----------------------------------------------------------------------*/ +/** @file + * @brief Specialization for fixed-size, fixed-memory vectors. + */ + +#ifndef fixed_vector_h +#define fixed_vector_h + +#include +#include +#include +#include +#include +#include + +namespace cml { + +/** Fixed-size, fixed-memory vector. */ +template +class vector< Element, fixed > +: public fixed_1D +{ + public: + + /* Shorthand for the generator: */ + typedef fixed<> storage_type; + typedef fixed generator_type; + + /* Shorthand for the array type: */ + typedef fixed_1D array_type; + + /* Shorthand for the type of this vector: */ + typedef vector vector_type; + + /* The vector coordinate type: */ + typedef Element coordinate_type; + + /* For integration into the expression template code: */ + typedef vector_type expr_type; + + /* For integration into the expression template code: */ + typedef vector_type temporary_type; + + /* The type for a vector in one lower dimension: */ + typedef vector< Element, fixed > subvector_type; + + /* The type for a vector in one higher dimension: */ + typedef vector< Element, fixed > supervector_type; + + /* Standard: */ + typedef typename array_type::value_type value_type; + typedef typename array_type::reference reference; + typedef typename array_type::const_reference const_reference; + + /* For integration into the expression templates code: */ + typedef vector_type& expr_reference; + typedef const vector_type& expr_const_reference; + + /* For matching by storage type: */ + typedef typename array_type::memory_tag memory_tag; + + /* For matching by size type: */ + typedef typename array_type::size_tag size_tag; + + /* For matching by result-type: */ + typedef cml::et::vector_result_tag result_tag; + + /* For matching by assignability: */ + typedef cml::et::assignable_tag assignable_tag; + + + public: + + /** Static constant containing the vector's space dimension. */ + enum { dimension = Size }; + + + public: + + /** Return square of the length. */ + value_type length_squared() const { + return cml::dot(*this,*this); + } + + /** Return the length. */ + value_type length() const { + return std::sqrt(length_squared()); + } + + /** Normalize the vector. */ + vector_type& normalize() { + return (*this /= length()); + } + + /** Set this vector to [0]. */ + vector_type& zero() { + typedef cml::et::OpAssign OpT; + cml::et::UnrollAssignment(*this,Element(0)); + return *this; + } + + /** Set this vector to a cardinal vector. */ + vector_type& cardinal(size_t i) { + zero(); + (*this)[i] = Element(1); + return *this; + } + + /** Pairwise minimum of this vector with another. */ + template + void minimize(const vector& v) { + /* XXX This should probably use ScalarPromote: */ + for (size_t i = 0; i < this->size(); ++i) { + (*this)[i] = std::min((*this)[i],v[i]); + } + } + + /** Pairwise maximum of this vector with another. */ + template + void maximize(const vector& v) { + /* XXX This should probably use ScalarPromote: */ + for (size_t i = 0; i < this->size(); ++i) { + (*this)[i] = std::max((*this)[i],v[i]); + } + } + + /** Fill vector with random elements. */ + void random(value_type min, value_type max) { + for (size_t i = 0; i < this->size(); ++i) { + (*this)[i] = cml::random_real(min,max); + } + } + + /** Return a subvector by removing element i. + * + * @internal This is horribly inefficient... + */ + subvector_type subvector(size_t i) const { + subvector_type s; + for(size_t m = 0, n = 0; m < this->size(); ++ m) + if(m != i) s[n++] = (*this)[m]; + return s; + }; + + + public: + + vector() : array_type() {} + + + public: + + /* Define common class operators: */ + + CML_CONSTRUCT_VEC_2(/**/) + CML_CONSTRUCT_VEC_3(/**/) + CML_CONSTRUCT_VEC_4(/**/) + + CML_CONSTRUCT_FROM_SUBVEC(/**/) + + CML_VEC_COPY_FROM_FIXED_ARRAY(array_type::array_size,/**/) + CML_VEC_COPY_FROM_VECTYPE(: array_type()) + CML_VEC_COPY_FROM_VEC + CML_VEC_COPY_FROM_VECXPR + + CML_ASSIGN_VEC_2 + CML_ASSIGN_VEC_3 + CML_ASSIGN_VEC_4 + + CML_VEC_ASSIGN_FROM_VECTYPE + + CML_VEC_ASSIGN_FROM_VEC(=, cml::et::OpAssign) + CML_VEC_ASSIGN_FROM_VEC(+=, cml::et::OpAddAssign) + CML_VEC_ASSIGN_FROM_VEC(-=, cml::et::OpSubAssign) + + CML_VEC_ASSIGN_FROM_VECXPR(=, cml::et::OpAssign) + CML_VEC_ASSIGN_FROM_VECXPR(+=, cml::et::OpAddAssign) + CML_VEC_ASSIGN_FROM_VECXPR(-=, cml::et::OpSubAssign) + + CML_VEC_ASSIGN_FROM_SCALAR(*=, cml::et::OpMulAssign) + CML_VEC_ASSIGN_FROM_SCALAR(/=, cml::et::OpDivAssign) +}; + +} // namespace cml + +#endif + +// ------------------------------------------------------------------------- +// vim:ft=cpp diff --git a/Lib/Include/CML/vector/vecop_macros.h b/Lib/Include/CML/vector/vecop_macros.h new file mode 100644 index 0000000..a82c29a --- /dev/null +++ b/Lib/Include/CML/vector/vecop_macros.h @@ -0,0 +1,248 @@ +/* -*- C++ -*- ------------------------------------------------------------ + +Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/ + +The Configurable Math Library (CML) is distributed under the terms of the +Boost Software License, v1.0 (see cml/LICENSE for details). + + *-----------------------------------------------------------------------*/ +/** @file + * @brief Defines the various combinations of vector expressions. + * + * Create unary and binary operators with macros. The available combinations + * are: + * + * Unary expressions: + * + * op Vector -> Vector + * op VecXpr -> VecXpr + * + * Binary expressions: + * + * Vector op Vector -> Vector + * VecXpr op Vector -> VecXpr + * Vector op VecXpr -> VecXpr + * VecXpr op VecXpr -> VecXpr + * + * Vector op Scalar -> Vector + * Scalar op Vector -> Vector + * VecXpr op Scalar -> VecXpr + * Scalar op VecXpr -> VecXpr + * + * All of the generator functions compress the expression tree by hoisting + * subexpressions into the containing expression. This has the effect of + * forcing only the root node of the expression tree to be a VectorXpr. + * Every other node is a Unary or BinaryVectorOp. + * + * @todo Should ScalarT in expressions be passed by reference or by value? + */ + +#ifndef vecop_macros_h +#define vecop_macros_h + +/** Declare a unary operator taking a vector operand. */ +#define CML_VEC_UNIOP(_op_, _OpT_) \ +template \ +inline et::VectorXpr< \ + et::UnaryVectorOp< vector, _OpT_ > \ +> \ + \ +_op_ (const vector& arg) \ +{ \ + typedef et::UnaryVectorOp< \ + vector, _OpT_ \ + > ExprT; \ + return et::VectorXpr(ExprT(arg)); \ +} + + +/** Declare a unary operator taking a et::VectorXpr operand. */ +#define CML_VECXPR_UNIOP(_op_, _OpT_) \ +template \ +inline et::VectorXpr< \ + et::UnaryVectorOp< XprT, _OpT_ > \ +> \ + \ +_op_ (VECXPR_ARG_TYPE arg) \ +{ \ + typedef et::UnaryVectorOp< \ + XprT, _OpT_ \ + > ExprT; \ + return et::VectorXpr(ExprT(arg.expression())); \ +} + + +/** Declare an operator taking two vector operands. */ +#define CML_VEC_VEC_BINOP(_op_, _OpT_) \ +template \ +inline et::VectorXpr< \ + et::BinaryVectorOp< \ + vector, vector, _OpT_ \ + > \ +> \ + \ +_op_ ( \ + const vector& left, \ + const vector& right) \ +{ \ + typedef et::BinaryVectorOp< \ + vector, vector, _OpT_ \ + > ExprT; \ + return et::VectorXpr(ExprT(left,right)); \ +} + + +/** Declare an operator taking a vector and a et::VectorXpr. */ +#define CML_VEC_VECXPR_BINOP(_op_, _OpT_) \ +template \ +inline et::VectorXpr< \ + et::BinaryVectorOp< \ + vector, XprT, _OpT_ \ + > \ +> \ + \ +_op_ ( \ + const vector& left, \ + VECXPR_ARG_TYPE right) \ +{ \ + typedef et::BinaryVectorOp< \ + vector, XprT, \ + _OpT_ \ + > ExprT; \ + return et::VectorXpr(ExprT(left,right.expression())); \ +} + + +/** Declare an operator taking an et::VectorXpr and a vector. */ +#define CML_VECXPR_VEC_BINOP(_op_, _OpT_) \ +template \ +inline et::VectorXpr< \ + et::BinaryVectorOp< \ + XprT, vector, _OpT_ \ + > \ +> \ + \ +_op_ ( \ + VECXPR_ARG_TYPE left, \ + const vector& right) \ +{ \ + typedef et::BinaryVectorOp< \ + XprT, vector, \ + _OpT_ \ + > ExprT; \ + return et::VectorXpr(ExprT(left.expression(),right)); \ +} + + +/** Declare an operator taking two et::VectorXpr operands. */ +#define CML_VECXPR_VECXPR_BINOP(_op_, _OpT_) \ +template \ +inline et::VectorXpr< \ + et::BinaryVectorOp< \ + XprT1, XprT2, \ + _OpT_ < \ + typename XprT1::value_type, \ + typename XprT2::value_type \ + > \ + > \ +> \ + \ +_op_ ( \ + VECXPR_ARG_TYPE_N(1) left, \ + VECXPR_ARG_TYPE_N(2) right) \ +{ \ + typedef et::BinaryVectorOp< \ + XprT1, XprT2, \ + _OpT_ < \ + typename XprT1::value_type, \ + typename XprT2::value_type> \ + > ExprT; \ + return et::VectorXpr( \ + ExprT(left.expression(),right.expression())); \ +} + + +/** Declare an operator taking a vector and a scalar. */ +#define CML_VEC_SCALAR_BINOP(_op_, _OpT_) \ +template \ +inline et::VectorXpr< \ + et::BinaryVectorOp< \ + vector, ScalarT, _OpT_ \ + > \ +> \ + \ +_op_ ( \ + const vector& left, \ + SCALAR_ARG_TYPE right) \ +{ \ + typedef et::BinaryVectorOp< \ + vector, ScalarT, _OpT_ \ + > ExprT; \ + return et::VectorXpr(ExprT(left,right)); \ +} + + +/** Declare an operator taking a scalar and a vector. */ +#define CML_SCALAR_VEC_BINOP(_op_, _OpT_) \ +template \ +inline et::VectorXpr< \ + et::BinaryVectorOp< \ + ScalarT, vector, _OpT_ \ + > \ +> \ + \ +_op_ ( \ + SCALAR_ARG_TYPE left, \ + const vector& right) \ +{ \ + typedef et::BinaryVectorOp< \ + ScalarT, vector, _OpT_ \ + > ExprT; \ + return et::VectorXpr(ExprT(left,right)); \ +} + + +/** Declare an operator taking a et::VectorXpr and a scalar. */ +#define CML_VECXPR_SCALAR_BINOP(_op_, _OpT_) \ +template \ +inline et::VectorXpr< \ + et::BinaryVectorOp< \ + XprT, ScalarT, _OpT_ \ + > \ +> \ + \ +_op_ ( \ + VECXPR_ARG_TYPE left, \ + SCALAR_ARG_TYPE right) \ +{ \ + typedef et::BinaryVectorOp< \ + XprT, ScalarT, _OpT_ \ + > ExprT; \ + return et::VectorXpr(ExprT(left.expression(),right)); \ +} + + +/** Declare an operator taking a scalar and a et::VectorXpr. */ +#define CML_SCALAR_VECXPR_BINOP(_op_, _OpT_) \ +template \ +inline et::VectorXpr< \ + et::BinaryVectorOp< \ + ScalarT, XprT, _OpT_ \ + > \ +> \ + \ +_op_ ( \ + SCALAR_ARG_TYPE left, \ + VECXPR_ARG_TYPE right) \ +{ \ + typedef et::BinaryVectorOp< \ + ScalarT, XprT, \ + _OpT_ \ + > ExprT; \ + return et::VectorXpr(ExprT(left,right.expression())); \ +} + +#endif + +// ------------------------------------------------------------------------- +// vim:ft=cpp diff --git a/Lib/Include/CML/vector/vector_comparison.h b/Lib/Include/CML/vector/vector_comparison.h new file mode 100644 index 0000000..c30a07f --- /dev/null +++ b/Lib/Include/CML/vector/vector_comparison.h @@ -0,0 +1,236 @@ +/* -*- C++ -*- ------------------------------------------------------------ + +Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/ + +The Configurable Math Library (CML) is distributed under the terms of the +Boost Software License, v1.0 (see cml/LICENSE for details). + + *-----------------------------------------------------------------------*/ +/** @file + * @brief + */ + +#ifndef vector_comparison_h +#define vector_comparison_h + +#include +#include +#include + +/* This is used below to create a more meaningful compile-time error when + * vector_comparison is not provided with vector or VectorExpr arguments: + */ +struct vector_comparison_expects_vector_args_error; + +#define CML_VEC_VEC_ORDER(_order_, _op_, _OpT_) \ +template \ +inline bool \ +_op_ ( \ + const vector& left, \ + const vector& right) \ +{ \ + return detail::vector_##_order_ (left, right, _OpT_ ()); \ +} + +#define CML_VEC_VECXPR_ORDER(_order_, _op_, _OpT_) \ +template \ +inline bool \ +_op_ ( \ + const vector& left, \ + VECXPR_ARG_TYPE right) \ +{ \ + return detail::vector_##_order_ (left, right, \ + _OpT_ ()); \ +} + +#define CML_VECXPR_VEC_ORDER(_order_, _op_, _OpT_) \ +template \ +inline bool \ +_op_ ( \ + VECXPR_ARG_TYPE left, \ + const vector& right) \ +{ \ + return detail::vector_##_order_ (left, right, \ + _OpT_ ()); \ +} + +#define CML_VECXPR_VECXPR_ORDER(_order_, _op_, _OpT_) \ +template \ +inline bool \ +_op_ ( \ + VECXPR_ARG_TYPE_N(1) left, \ + VECXPR_ARG_TYPE_N(2) right) \ +{ \ + return detail::vector_##_order_ (left, right, \ + _OpT_ < \ + typename XprT1::value_type, \ + typename XprT2::value_type>()); \ +} + + +namespace cml { +namespace detail { + +/** Vector strict weak ordering relationship. + * + * OpT must implement a strict weak order on the vector element type. + * operator< and operator> on integer and floating-point types are + * examples. + */ +template +inline bool +vector_weak_order(const LeftT& left, const RightT& right, OpT) +{ + /* Shorthand: */ + typedef et::ExprTraits left_traits; + typedef et::ExprTraits right_traits; + + /* vector_comparison() requires vector expressions: */ + CML_STATIC_REQUIRE_M( + (et::VectorExpressions::is_true), + vector_comparison_expects_vector_args_error); + /* Note: parens are required here so that the preprocessor ignores the + * commas: + */ + + typedef typename et::VectorPromote< + typename left_traits::result_type, + typename right_traits::result_type + >::type result_type; + typedef typename result_type::size_tag size_tag; + + /* Verify expression size: */ + ssize_t N = (ssize_t) et::CheckedSize(left,right,size_tag()); + for(ssize_t i = 0; i < N; ++ i) { + if(OpT().apply( + left_traits().get(left,i), + right_traits().get(right,i) + )) + { + /* If weak order (a < b) is satisfied, return true: */ + return true; + } else if(OpT().apply( + right_traits().get(right,i), + left_traits().get(left,i) + )) + { + /* If !(b < a), then return false: */ + return false; + } else { + + /* Have !(a < b) && !(b < a) <=> (a >= b && b >= a) <=> (a == b). + * so need to test next element: + */ + continue; + } + } + /* XXX Can this be unrolled in any reasonable way? */ + + /* If we get here, then left == right: */ + return false; +} + +/** Vector total order relationship. + * + * OpT must implement a total order on the vector element type. operator<= + * and operator>= on integer and floating-point types are examples. + */ +template +inline bool +vector_total_order(const LeftT& left, const RightT& right, OpT) +{ + /* Shorthand: */ + typedef et::ExprTraits left_traits; + typedef et::ExprTraits right_traits; + + /* vector_comparison() requires vector expressions: */ + CML_STATIC_REQUIRE_M( + (et::VectorExpressions::is_true), + vector_comparison_expects_vector_args_error); + /* Note: parens are required here so that the preprocessor ignores the + * commas: + */ + + typedef typename et::VectorPromote< + typename left_traits::result_type, + typename right_traits::result_type + >::type result_type; + typedef typename result_type::size_tag size_tag; + + /* Verify expression size: */ + ssize_t N = (ssize_t) et::CheckedSize(left,right,size_tag()); + for(ssize_t i = 0; i < N; ++ i) { + + /* Test total order: */ + if(OpT().apply( + left_traits().get(left,i), + right_traits().get(right,i) + )) + { + /* Automatically true if weak order (a <= b) && !(b <= a) <=> + * (a <= b) && (b > a) <=> (a < b) is satisfied: + */ + if(!OpT().apply( + right_traits().get(right,i), + left_traits().get(left,i) + )) + return true; + + /* Otherwise, have equality (a <= b) && (b <= a), so continue + * to next element: + */ + else + continue; + + } else { + + /* Total order isn't satisfied (a > b), so return false: */ + return false; + } + } + /* XXX Can this be unrolled in any reasonable way? */ + + /* Total (==) or weak (<) order was satisfied, so return true: */ + return true; +} + +} + +/* XXX There is a better way to handle these with operator traits... */ + +CML_VEC_VEC_ORDER( total_order, operator==, et::OpEqual) +CML_VECXPR_VEC_ORDER( total_order, operator==, et::OpEqual) +CML_VEC_VECXPR_ORDER( total_order, operator==, et::OpEqual) +CML_VECXPR_VECXPR_ORDER( total_order, operator==, et::OpEqual) + +CML_VEC_VEC_ORDER( weak_order, operator!=, et::OpNotEqual) +CML_VECXPR_VEC_ORDER( weak_order, operator!=, et::OpNotEqual) +CML_VEC_VECXPR_ORDER( weak_order, operator!=, et::OpNotEqual) +CML_VECXPR_VECXPR_ORDER( weak_order, operator!=, et::OpNotEqual) + +CML_VEC_VEC_ORDER( weak_order, operator<, et::OpLess) +CML_VECXPR_VEC_ORDER( weak_order, operator<, et::OpLess) +CML_VEC_VECXPR_ORDER( weak_order, operator<, et::OpLess) +CML_VECXPR_VECXPR_ORDER( weak_order, operator<, et::OpLess) + +CML_VEC_VEC_ORDER( weak_order, operator>, et::OpGreater) +CML_VECXPR_VEC_ORDER( weak_order, operator>, et::OpGreater) +CML_VEC_VECXPR_ORDER( weak_order, operator>, et::OpGreater) +CML_VECXPR_VECXPR_ORDER( weak_order, operator>, et::OpGreater) + +CML_VEC_VEC_ORDER( total_order, operator<=, et::OpLessEqual) +CML_VECXPR_VEC_ORDER( total_order, operator<=, et::OpLessEqual) +CML_VEC_VECXPR_ORDER( total_order, operator<=, et::OpLessEqual) +CML_VECXPR_VECXPR_ORDER( total_order, operator<=, et::OpLessEqual) + +CML_VEC_VEC_ORDER( total_order, operator>=, et::OpGreaterEqual) +CML_VECXPR_VEC_ORDER( total_order, operator>=, et::OpGreaterEqual) +CML_VEC_VECXPR_ORDER( total_order, operator>=, et::OpGreaterEqual) +CML_VECXPR_VECXPR_ORDER( total_order, operator>=, et::OpGreaterEqual) + +} // namespace cml + +#endif + +// ------------------------------------------------------------------------- +// vim:ft=cpp diff --git a/Lib/Include/CML/vector/vector_expr.h b/Lib/Include/CML/vector/vector_expr.h new file mode 100644 index 0000000..5919090 --- /dev/null +++ b/Lib/Include/CML/vector/vector_expr.h @@ -0,0 +1,458 @@ +/* -*- C++ -*- ------------------------------------------------------------ + +Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/ + +The Configurable Math Library (CML) is distributed under the terms of the +Boost Software License, v1.0 (see cml/LICENSE for details). + + *-----------------------------------------------------------------------*/ +/** @file + * @brief Vector linear expression classes. + */ + +#ifndef vector_expr_h +#define vector_expr_h + +#include +#include +#include +#include + +/* XXX Don't know which it should be just yet, since RVO seems to obviate + * need for a reference type. However, copy by value copies the entire + * expression tree rooted at the VectorXpr<>, so this choice is bound to + * affect performace for some compiler or another: + */ +#define VECXPR_ARG_TYPE const et::VectorXpr& +#define VECXPR_ARG_TYPE_N(_N_) const et::VectorXpr& + +//#define VECXPR_ARG_TYPE const et::VectorXpr +//#define VECXPR_ARG_TYPE_N(_N_) const et::VectorXpr + +namespace cml { +namespace et { + +/** A placeholder for a vector expression in an expression tree. */ +template +class VectorXpr +{ + public: + + typedef VectorXpr expr_type; + + /* Record ary-ness of the expression: */ + typedef typename ExprT::expr_ary expr_ary; + + /* Copy the expression by value into higher-up expressions: */ + typedef expr_type expr_const_reference; + + typedef typename ExprT::value_type value_type; + typedef vector_result_tag result_tag; + typedef typename ExprT::size_tag size_tag; + + /* Store the expression traits: */ + typedef ExprTraits expr_traits; + + /* Get the reference type: */ + typedef typename expr_traits::const_reference expr_reference; + + /* Get the result type: */ + typedef typename expr_traits::result_type result_type; + + /* For matching by assignability: */ + typedef cml::et::not_assignable_tag assignable_tag; + + /* Get the temporary type: */ + typedef typename result_type::temporary_type temporary_type; + + + public: + + /** Record result size as an enum. */ + enum { array_size = ExprT::array_size }; + + + public: + + /** Return square of the length. */ + value_type length_squared() const { + return m_expr.length_squared(); + } + + /** Return the length. */ + value_type length() const { + return m_expr.length(); + } + + /** Return the result as a normalized vector. */ + result_type normalize() const { + return m_expr.normalize(); + } + + /** Compute value at index i of the result vector. */ + value_type operator[](size_t i) const { + return m_expr[i]; + } + + + public: + + /** Return size of this expression (same as subexpression's size). */ + size_t size() const { + return m_expr.size(); + } + + /** Return reference to contained expression. */ + expr_reference expression() const { return m_expr; } + + + public: + + /** Construct from the subexpression to store. */ + explicit VectorXpr(expr_reference expr) : m_expr(expr) {} + + /** Copy constructor. */ + VectorXpr(const expr_type& e) : m_expr(e.m_expr) {} + + + protected: + + expr_reference m_expr; + + + private: + + /* Cannot be assigned to: */ + expr_type& operator=(const expr_type&); +}; + +/** Expression traits class for VectorXpr<>. */ +template +struct ExprTraits< VectorXpr > +{ + typedef VectorXpr expr_type; + typedef ExprT arg_type; + typedef typename expr_type::value_type value_type; + typedef typename expr_type::expr_const_reference const_reference; + typedef typename expr_type::result_tag result_tag; + typedef typename expr_type::size_tag size_tag; + typedef typename expr_type::result_type result_type; + typedef typename expr_type::assignable_tag assignable_tag; + typedef expr_node_tag node_tag; + + value_type get(const expr_type& v, size_t i) const { return v[i]; } + size_t size(const expr_type& e) const { return e.size(); } +}; + + +/** A unary vector expression. + * + * The operator's operator() method must take exactly one argument. + */ +template +class UnaryVectorOp +{ + public: + + typedef UnaryVectorOp expr_type; + + /* Record ary-ness of the expression: */ + typedef unary_expression expr_ary; + + /* Copy the expression by value into higher-up expressions: */ + typedef expr_type expr_const_reference; + + typedef typename OpT::value_type value_type; + typedef vector_result_tag result_tag; + typedef typename ExprT::size_tag size_tag; + + /* Store the expression traits for the subexpression: */ + typedef ExprTraits expr_traits; + + /* Reference type for the subexpression: */ + typedef typename expr_traits::const_reference expr_reference; + + /* Get the result type (same as for subexpression): */ + typedef typename expr_traits::result_type result_type; + + /* For matching by assignability: */ + typedef cml::et::not_assignable_tag assignable_tag; + + /* Get the temporary type: */ + typedef typename result_type::temporary_type temporary_type; + + + public: + + /** Record result size as an enum. */ + enum { array_size = ExprT::array_size }; + + + public: + + /** Return square of the length. */ + value_type length_squared() const { + return dot( + VectorXpr(*this), + VectorXpr(*this)); + } + + /** Return the length. */ + value_type length() const { + return std::sqrt(length_squared()); + } + + /** Return the result as a normalized vector. */ + result_type normalize() const { + result_type v(VectorXpr(*this)); + return v.normalize(); + } + + /** Compute value at index i of the result vector. */ + value_type operator[](size_t i) const { + + /* This uses the expression traits to figure out how to access the + * i'th index of the subexpression: + */ + return OpT().apply(expr_traits().get(m_expr,i)); + } + + + public: + + /** Return size of this expression (same as argument's size). */ + size_t size() const { + return m_expr.size(); + } + + /** Return reference to contained expression. */ + expr_reference expression() const { return m_expr; } + + + public: + + /** Construct from the subexpression. */ + explicit UnaryVectorOp(expr_reference expr) : m_expr(expr) {} + + /** Copy constructor. */ + UnaryVectorOp(const expr_type& e) : m_expr(e.m_expr) {} + + + protected: + + expr_reference m_expr; + + + private: + + /* Cannot be assigned to: */ + expr_type& operator=(const expr_type&); +}; + +/** Expression traits class for UnaryVectorOp<>. */ +template +struct ExprTraits< UnaryVectorOp > +{ + typedef UnaryVectorOp expr_type; + typedef ExprT arg_type; + + typedef typename expr_type::value_type value_type; + typedef typename expr_type::expr_const_reference const_reference; + typedef typename expr_type::result_tag result_tag; + typedef typename expr_type::size_tag size_tag; + typedef typename expr_type::result_type result_type; + typedef typename expr_type::assignable_tag assignable_tag; + typedef expr_node_tag node_tag; + + value_type get(const expr_type& v, size_t i) const { return v[i]; } + size_t size(const expr_type& e) const { return e.size(); } +}; + + +/** A binary vector expression. + * + * The operator's operator() method must take exactly two arguments. + */ +template +class BinaryVectorOp +{ + public: + + typedef BinaryVectorOp expr_type; + + /* Record ary-ness of the expression: */ + typedef binary_expression expr_ary; + + /* Copy the expression by value into higher-up expressions: */ + typedef expr_type expr_const_reference; + + typedef typename OpT::value_type value_type; + typedef vector_result_tag result_tag; + + /* Store the expression traits types for the two subexpressions: */ + typedef ExprTraits left_traits; + typedef ExprTraits right_traits; + + /* Reference types for the two subexpressions: */ + typedef typename left_traits::const_reference left_reference; + typedef typename right_traits::const_reference right_reference; + + /* Figure out the expression's resulting (vector) type: */ + typedef typename left_traits::result_type left_result; + typedef typename right_traits::result_type right_result; + typedef typename VectorPromote::type result_type; + typedef typename result_type::size_tag size_tag; + + /* For matching by assignability: */ + typedef cml::et::not_assignable_tag assignable_tag; + + /* Get the temporary type: */ + typedef typename result_type::temporary_type temporary_type; + + /* Define a size checker: */ + typedef GetCheckedSize checked_size; + + + public: + + /** Record result size as an enum (if applicable). */ + enum { array_size = result_type::array_size }; + + + public: + + /** Return square of the length. */ + value_type length_squared() const { + return dot( + VectorXpr(*this), + VectorXpr(*this)); + } + + /** Return the length. */ + value_type length() const { + return std::sqrt(length_squared()); + } + + /** Return the result as a normalized vector. */ + result_type normalize() const { + result_type v(VectorXpr(*this)); + return v.normalize(); + } + + /** Compute value at index i of the result vector. */ + value_type operator[](size_t i) const { + + /* This uses the expression traits to figure out how to access the + * i'th index of the two subexpressions: + */ + return OpT().apply( + left_traits().get(m_left,i), + right_traits().get(m_right,i)); + } + + + public: + + /** Return the size of the vector result. + * + * @throws std::invalid_argument if the expressions do not have the same + * size. + */ + size_t size() const { + /* Note: This actually does a check only if + * CML_CHECK_VECTOR_EXPR_SIZES is set: + */ + return CheckedSize(m_left,m_right,size_tag()); + } + + /** Return reference to left expression. */ + left_reference left_expression() const { return m_left; } + + /** Return reference to right expression. */ + right_reference right_expression() const { return m_right; } + + + public: + + /** Construct from the two subexpressions. */ + explicit BinaryVectorOp(left_reference left, right_reference right) + : m_left(left), m_right(right) {} + + /** Copy constructor. */ + BinaryVectorOp(const expr_type& e) + : m_left(e.m_left), m_right(e.m_right) {} + + + protected: + + left_reference m_left; + right_reference m_right; + + + private: + + /* This ensures that a compile-time size check is executed: */ + typename checked_size::check_type _dummy; + + + private: + + /* Cannot be assigned to: */ + expr_type& operator=(const expr_type&); +}; + +/** Expression traits class for BinaryVectorOp<>. */ +template +struct ExprTraits< BinaryVectorOp > +{ + typedef BinaryVectorOp expr_type; + typedef LeftT left_type; + typedef RightT right_type; + + typedef typename expr_type::value_type value_type; + typedef typename expr_type::expr_const_reference const_reference; + typedef typename expr_type::result_tag result_tag; + typedef typename expr_type::size_tag size_tag; + typedef typename expr_type::result_type result_type; + typedef typename expr_type::assignable_tag assignable_tag; + typedef expr_node_tag node_tag; + + value_type get(const expr_type& v, size_t i) const { return v[i]; } + size_t size(const expr_type& e) const { return e.size(); } +}; + +/* Helper struct to verify that both arguments are vector expressions: */ +template +struct VectorExpressions +{ + /* Require that both arguments are vector expressions: */ + typedef typename LeftTraits::result_tag left_result; + typedef typename RightTraits::result_tag right_result; + enum { is_true = (same_type::is_true + && same_type::is_true) }; +}; + +namespace detail { + +template inline +void Resize(VecT&,size_t,RT,MT) {} + +template inline +void Resize(VecT& v, size_t S, resizable_tag, dynamic_memory_tag) { + v.resize(S); +} + +template inline +void Resize(VecT& v, size_t S) { + Resize(v, S, typename VecT::resizing_tag(), typename VecT::memory_tag()); +} + +} // namespace detail + +} // namespace et +} // namespace cml + +#endif + +// ------------------------------------------------------------------------- +// vim:ft=cpp diff --git a/Lib/Include/CML/vector/vector_functions.h b/Lib/Include/CML/vector/vector_functions.h new file mode 100644 index 0000000..ce92371 --- /dev/null +++ b/Lib/Include/CML/vector/vector_functions.h @@ -0,0 +1,73 @@ +/* -*- C++ -*- ------------------------------------------------------------ + +Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/ + +The Configurable Math Library (CML) is distributed under the terms of the +Boost Software License, v1.0 (see cml/LICENSE for details). + + *-----------------------------------------------------------------------*/ +/** @file + * @brief + */ + +#ifndef vector_functions_h +#define vector_functions_h + +namespace cml { + +/** Squared length of a vector. */ +template +inline typename vector::value_type +length_squared(const vector& arg) +{ + return arg.length_squared(); +} + +/** Squared length of a vector expr. */ +template +inline typename XprT::value_type +length_squared(VECXPR_ARG_TYPE arg) +{ + return arg.length_squared(); +} + +/** Length of a vector. */ +template +inline typename vector::value_type +length(const vector& arg) +{ + return arg.length(); +} + +/** Length of a vector expr. */ +template +inline typename XprT::value_type +length(VECXPR_ARG_TYPE arg) +{ + return arg.length(); +} + +/** Normalize a vector. */ +template +inline vector +normalize(const vector& arg) +{ + vector result(arg); + result.normalize(); + return result; +} + +/** Normalize a vector expr. */ +template +inline typename XprT::result_type +normalize(VECXPR_ARG_TYPE arg) +{ + return arg.normalize(); +} + +} // namespace cml + +#endif + +// ------------------------------------------------------------------------- +// vim:ft=cpp diff --git a/Lib/Include/CML/vector/vector_ops.h b/Lib/Include/CML/vector/vector_ops.h new file mode 100644 index 0000000..e7920d1 --- /dev/null +++ b/Lib/Include/CML/vector/vector_ops.h @@ -0,0 +1,51 @@ +/* -*- C++ -*- ------------------------------------------------------------ + +Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/ + +The Configurable Math Library (CML) is distributed under the terms of the +Boost Software License, v1.0 (see cml/LICENSE for details). + + *-----------------------------------------------------------------------*/ +/** @file + * @brief Defines vector operators. + */ + +#ifndef vector_ops_h +#define vector_ops_h + +#include +#include +#include + +namespace cml { + +CML_VEC_UNIOP( operator+, et::OpPos) +CML_VECXPR_UNIOP( operator+, et::OpPos) + +CML_VEC_UNIOP( operator-, et::OpNeg) +CML_VECXPR_UNIOP( operator-, et::OpNeg) + +CML_VEC_VEC_BINOP( operator+, et::OpAdd) +CML_VECXPR_VEC_BINOP( operator+, et::OpAdd) +CML_VEC_VECXPR_BINOP( operator+, et::OpAdd) +CML_VECXPR_VECXPR_BINOP( operator+, et::OpAdd) + +CML_VEC_VEC_BINOP( operator-, et::OpSub) +CML_VECXPR_VEC_BINOP( operator-, et::OpSub) +CML_VEC_VECXPR_BINOP( operator-, et::OpSub) +CML_VECXPR_VECXPR_BINOP( operator-, et::OpSub) + +CML_VEC_SCALAR_BINOP( operator*, et::OpMul) +CML_SCALAR_VEC_BINOP( operator*, et::OpMul) +CML_VECXPR_SCALAR_BINOP( operator*, et::OpMul) +CML_SCALAR_VECXPR_BINOP( operator*, et::OpMul) + +CML_VEC_SCALAR_BINOP( operator/, et::OpDiv) +CML_VECXPR_SCALAR_BINOP( operator/, et::OpDiv) + +} // namespace cml + +#endif + +// ------------------------------------------------------------------------- +// vim:ft=cpp diff --git a/Lib/Include/CML/vector/vector_print.h b/Lib/Include/CML/vector/vector_print.h new file mode 100644 index 0000000..2d59431 --- /dev/null +++ b/Lib/Include/CML/vector/vector_print.h @@ -0,0 +1,47 @@ +/* -*- C++ -*- ------------------------------------------------------------ + +Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/ + +The Configurable Math Library (CML) is distributed under the terms of the +Boost Software License, v1.0 (see cml/LICENSE for details). + + *-----------------------------------------------------------------------*/ +/** @file + * @brief + */ + +#ifndef vector_print_h +#define vector_print_h + +#include + +namespace cml { + +/** Output a vector to a std::ostream. */ +template inline std::ostream& +operator<<(std::ostream& os, const vector& v) +{ + os << v[0]; + for (size_t i = 1; i < v.size(); ++i) { + os << " " << v[i]; + } + return os; +} + +/** Output a vector expression to a std::ostream. */ +template< class XprT > inline std::ostream& +operator<<(std::ostream& os, const et::VectorXpr& v) +{ + os << v[0]; + for (size_t i = 1; i < v.size(); ++i) { + os << " " << v[i]; + } + return os; +} + +} // namespace cml + +#endif + +// ------------------------------------------------------------------------- +// vim:ft=cpp diff --git a/Lib/Include/CML/vector/vector_products.h b/Lib/Include/CML/vector/vector_products.h new file mode 100644 index 0000000..89f5edc --- /dev/null +++ b/Lib/Include/CML/vector/vector_products.h @@ -0,0 +1,361 @@ +/* -*- C++ -*- ------------------------------------------------------------ + +Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/ + +The Configurable Math Library (CML) is distributed under the terms of the +Boost Software License, v1.0 (see cml/LICENSE for details). + + *-----------------------------------------------------------------------*/ +/** @file + * @brief Defines vector dot and outer products. + * + * @todo Figure out if the source or destination size type should trigger + * unrolling. May need a per-compiler compile-time option for this. + */ + +#ifndef vector_products_h +#define vector_products_h + +#include +#include +#include +#include +#include +#include + +/* This is used below to create a more meaningful compile-time error when + * dot() is not provided with vector or VectorExpr arguments: + */ +struct dot_expects_vector_args_error; + +/* This is used below to create a more meaningful compile-time error when + * perp_dot() is not provided with 2D vector or VectorExpr arguments: + */ +struct perp_dot_expects_vector_args_error; +struct perp_dot_expects_2D_vector_args_error; + +/* This is used below to create a more meaningful compile-time error when + * outer() is not provided with vector or VectorExpr arguments: + */ +struct outer_expects_vector_args_error; + +/* This is used below to create a more meaningful compile-time error when + * cross() is not provided with 3D vector or VectorExpr arguments: + */ +struct cross_expects_vector_args_error; +struct cross_expects_3D_vector_args_error; + + +namespace cml { +namespace detail { + +template +struct DotPromote +{ + /* Shorthand: */ + typedef et::ExprTraits left_traits; + typedef et::ExprTraits right_traits; + typedef typename left_traits::value_type left_value; + typedef typename right_traits::value_type right_value; + + /* Deduce the promoted scalar type: */ + typedef et::OpMul op_mul; + typedef typename et::OpAdd< + typename op_mul::value_type, + typename op_mul::value_type> op_add; + typedef typename op_add::value_type promoted_scalar; +}; + +template +struct CrossPromote +{ + /* Shorthand: */ + typedef et::ExprTraits left_traits; + typedef et::ExprTraits right_traits; + typedef typename left_traits::result_type left_type; + typedef typename right_traits::result_type right_type; + + /* Deduce the matrix result type: */ + typedef typename et::VectorPromote< + left_type,right_type>::temporary_type promoted_vector; +}; + +template +struct OuterPromote +{ + /* Shorthand: */ + typedef et::ExprTraits left_traits; + typedef et::ExprTraits right_traits; + typedef typename left_traits::result_type left_type; + typedef typename right_traits::result_type right_type; + + /* Deduce the matrix result type: */ + typedef typename et::MatrixPromote< + left_type,right_type>::temporary_type promoted_matrix; +}; + +/** Construct a dot unroller for fixed-size arrays. + * + * @note This should only be called for vectors. + * + * @sa cml::dot + */ +template +inline typename DotPromote::promoted_scalar +UnrollDot(const LeftT& left, const RightT& right, fixed_size_tag) +{ + /* Shorthand: */ + typedef DotPromote dot_helper; + + /* Compile-type vector size check: */ + typedef typename et::GetCheckedSize + ::check_type check_sizes; + + /* Get the fixed array size using the helper: */ + enum { Len = check_sizes::array_size }; + + /* Record the unroller type: */ + typedef typename dot_helper::op_mul op_mul; + typedef typename dot_helper::op_add op_add; + typedef typename et::detail::VectorAccumulateUnroller< + op_add,op_mul,LeftT,RightT>::template + Eval<0, Len-1, (Len <= CML_VECTOR_DOT_UNROLL_LIMIT)> Unroller; + /* Note: Len is the array size, so Len-1 is the last element. */ + + /* Now, call the unroller: */ + return Unroller()(left,right); +} + +/** Use a loop to compute the dot product for dynamic arrays. + * + * @note This should only be called for vectors. + * + * @sa cml::dot + */ +template +inline typename DotPromote::promoted_scalar +UnrollDot(const LeftT& left, const RightT& right, dynamic_size_tag) +{ + /* Shorthand: */ + typedef DotPromote dot_helper; + typedef et::ExprTraits left_traits; + typedef et::ExprTraits right_traits; + typedef typename dot_helper::op_mul op_mul; + typedef typename dot_helper::op_add op_add; + + /* Record the return type: */ + typedef typename dot_helper::promoted_scalar sum_type; + + /* Verify expression sizes: */ + const size_t N = et::CheckedSize(left,right,dynamic_size_tag()); + + /* Initialize the sum. Left and right must be vector expressions, so + * it's okay to use array notation here: + */ + sum_type sum(op_mul().apply(left[0],right[0])); + for(size_t i = 1; i < N; ++i) { + /* XXX This might not be optimized properly by some compilers. + * but to do anything else requires changing the requirements + * of a scalar operator, or requires defining a new class of scalar + * = operators. + */ + sum = op_add().apply(sum, op_mul().apply(left[i], right[i])); + /* Note: we don't need get(), since both arguments are required to + * be vector expressions. + */ + } + return sum; +} + +/** For cross(): compile-time check for a 3D vector. */ +template inline void +Require3D(const VecT&, fixed_size_tag) { + CML_STATIC_REQUIRE_M( + ((size_t)VecT::array_size == 3), + cross_expects_3D_vector_args_error); +} + +/** For cross(): run-time check for a 3D vector. */ +template inline void +Require3D(const VecT& v, dynamic_size_tag) { + et::GetCheckedSize() + .equal_or_fail(v.size(),size_t(3)); +} + +/** For perp_dot(): compile-time check for a 2D vector. */ +template inline void +Require2D(const VecT& v, fixed_size_tag) { + CML_STATIC_REQUIRE_M( + ((size_t)VecT::array_size == 2), + perp_dot_expects_2D_vector_args_error); +} + +/** For perp_dot(): run-time check for a 2D vector. */ +template inline void +Require2D(const VecT& v, dynamic_size_tag) { + et::GetCheckedSize() + .equal_or_fail(v.size(),size_t(2)); +} + +} // namespace detail + + +/** Vector dot (inner) product implementation. + */ +template +inline typename detail::DotPromote::promoted_scalar +dot(const LeftT& left, const RightT& right) +{ + /* Shorthand: */ + typedef detail::DotPromote dot_helper; + typedef et::ExprTraits left_traits; + typedef et::ExprTraits right_traits; + typedef typename left_traits::result_type left_type; + typedef typename right_traits::result_type right_type; + typedef typename left_traits::size_tag left_size; + typedef typename right_traits::size_tag right_size; + + /* dot() requires vector expressions: */ + CML_STATIC_REQUIRE_M( + (et::VectorExpressions::is_true), + dot_expects_vector_args_error); + /* Note: parens are required here so that the preprocessor ignores the + * commas: + */ + + /* Figure out the unroller to use (fixed or dynamic): */ + typedef typename et::VectorPromote< + left_type, right_type>::temporary_type promoted_vector; + typedef typename promoted_vector::size_tag size_tag; + + /* Call unroller: */ + return detail::UnrollDot(left,right,size_tag()); +} + +/** perp_dot() + */ +template +inline typename detail::DotPromote::promoted_scalar +perp_dot(const LeftT& left, const RightT& right) +{ + /* Shorthand: */ + typedef et::ExprTraits left_traits; + typedef et::ExprTraits right_traits; + typedef typename left_traits::result_tag left_result; + typedef typename right_traits::result_tag right_result; + + /* perp_dot() requires vector expressions: */ + CML_STATIC_REQUIRE_M( + (same_type::is_true + && same_type::is_true), + perp_dot_expects_vector_args_error); + /* Note: parens are required here so that the preprocessor ignores the + * commas. + */ + + /* Make sure arguments are 2D vectors: */ + detail::Require2D(left, typename left_traits::size_tag()); + detail::Require2D(right, typename right_traits::size_tag()); + + /* Get result type: */ + typedef typename detail::DotPromote< + LeftT,RightT>::promoted_scalar result_type; + + /* Compute and return: */ + return result_type(left[0]*right[1]-left[1]*right[0]); +} + +template +inline typename detail::CrossPromote::promoted_vector +cross(const LeftT& left, const RightT& right) +{ + /* Shorthand: */ + typedef et::ExprTraits left_traits; + typedef et::ExprTraits right_traits; + typedef typename left_traits::result_tag left_result; + typedef typename right_traits::result_tag right_result; + + /* outer() requires vector expressions: */ + CML_STATIC_REQUIRE_M( + (same_type::is_true + && same_type::is_true), + cross_expects_vector_args_error); + /* Note: parens are required here so that the preprocessor ignores the + * commas. + */ + + /* Make sure arguments are 3D vectors: */ + detail::Require3D(left, typename left_traits::size_tag()); + detail::Require3D(right, typename right_traits::size_tag()); + + /* Get result type: */ + typedef typename detail::CrossPromote< + LeftT,RightT>::promoted_vector result_type; + + /* Now, compute and return the cross product: */ + result_type result( + left[1]*right[2] - left[2]*right[1], + left[2]*right[0] - left[0]*right[2], + left[0]*right[1] - left[1]*right[0] + ); + return result; +} + +/** Return the triple product of three 3D vectors. + * + * No checking is done here, as dot() and cross() will catch any size or + * type errors. + */ + +template < class VecT_1, class VecT_2, class VecT_3 > +typename detail::DotPromote< + VecT_1, typename detail::CrossPromote< VecT_2, VecT_3 >::promoted_vector +>::promoted_scalar +triple_product(const VecT_1& v1, const VecT_2& v2, const VecT_3& v3) { + return dot(v1,cross(v2,v3)); +} + +template +inline typename detail::OuterPromote::promoted_matrix +outer(const LeftT& left, const RightT& right) +{ + /* Shorthand: */ + typedef et::ExprTraits left_traits; + typedef et::ExprTraits right_traits; + typedef typename left_traits::result_tag left_result; + typedef typename right_traits::result_tag right_result; + + /* outer() requires vector expressions: */ + CML_STATIC_REQUIRE_M( + (same_type::is_true + && same_type::is_true), + dot_expects_vector_args_error); + /* Note: parens are required here so that the preprocessor ignores the + * commas. + */ + + /* Create a matrix with the right size (resize() is a no-op for + * fixed-size matrices): + */ + typename detail::OuterPromote::promoted_matrix C; + cml::et::detail::Resize(C, left.size(), right.size()); + + /* Now, compute the outer product: */ + for(size_t i = 0; i < left.size(); ++i) { + for(size_t j = 0; j < right.size(); ++j) { + C(i,j) = left[i]*right[j]; + /* Note: both arguments are vectors, so array notation + * is okay here. + */ + } + } + + return C; +} + +} // namespace cml + +#endif + +// ------------------------------------------------------------------------- +// vim:ft=cpp diff --git a/Lib/Include/CML/vector/vector_promotions.h b/Lib/Include/CML/vector/vector_promotions.h new file mode 100644 index 0000000..49e575d --- /dev/null +++ b/Lib/Include/CML/vector/vector_promotions.h @@ -0,0 +1,77 @@ +/* -*- C++ -*- ------------------------------------------------------------ + +Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/ + +The Configurable Math Library (CML) is distributed under the terms of the +Boost Software License, v1.0 (see cml/LICENSE for details). + + *-----------------------------------------------------------------------*/ +/** @file + * @brief + * + * Defines promotions for vectors used in vector/vector or vector/scalar + * expressions. + * + * @sa BinaryVectorOp + */ + +#ifndef vector_promotions_h +#define vector_promotions_h + +#include +#include + +namespace cml { +namespace et { + +/* Default vector type promotion template. */ +template struct VectorPromote; + +/** Type promotion for two vector types. */ +template +struct VectorPromote< cml::vector, cml::vector > +{ + typedef typename ArrayPromote< + typename cml::vector::array_type, + typename cml::vector::array_type + >::type promoted_array; + + /* The deduced vector result type: */ + typedef cml::vector< + typename promoted_array::value_type, + typename promoted_array::generator_type + > type; + + /* The deduced temporary type: */ + typedef typename type::temporary_type temporary_type; +}; + +/** Type promotion for a vector and a scalar. */ +template +struct VectorPromote, S> +{ + /* The deduced vector result type (the array type is the same): */ + typedef cml::vector::type, AT> type; + + /* The deduced temporary type: */ + typedef typename type::temporary_type temporary_type; +}; + +/** Type promotion for a scalar and a vector. */ +template +struct VectorPromote > +{ + /* The deduced vector result type (the array type is the same): */ + typedef cml::vector::type, AT> type; + + /* The deduced temporary type: */ + typedef typename type::temporary_type temporary_type; +}; + +} // namespace et +} // namespace cml + +#endif + +// ------------------------------------------------------------------------- +// vim:ft=cpp diff --git a/Lib/Include/CML/vector/vector_traits.h b/Lib/Include/CML/vector/vector_traits.h new file mode 100644 index 0000000..51b4228 --- /dev/null +++ b/Lib/Include/CML/vector/vector_traits.h @@ -0,0 +1,47 @@ +/* -*- C++ -*- ------------------------------------------------------------ + +Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/ + +The Configurable Math Library (CML) is distributed under the terms of the +Boost Software License, v1.0 (see cml/LICENSE for details). + + *-----------------------------------------------------------------------*/ +/** @file + * @brief + */ + +#ifndef vector_traits_h +#define vector_traits_h + +#include + +namespace cml { +namespace et { + +/** Expression traits for a vector<> type. */ +template +struct ExprTraits< cml::vector > +{ + typedef typename cml::vector::expr_type expr_type; + typedef typename expr_type::value_type value_type; + typedef typename expr_type::expr_reference reference; + typedef typename expr_type::expr_const_reference const_reference; + typedef typename expr_type::result_tag result_tag; + typedef typename expr_type::size_tag size_tag; + typedef typename expr_type::resizing_tag resizing_tag; + typedef typename expr_type::assignable_tag assignable_tag; + typedef expr_type result_type; + typedef expr_leaf_tag node_tag; + + value_type get(const expr_type& v, size_t i) const { return v[i]; } + size_t size(const expr_type& v) const { return v.size(); } +}; + +} // namespace et +} // namespace cml + + +#endif + +// ------------------------------------------------------------------------- +// vim:ft=cpp diff --git a/Lib/Include/CML/vector/vector_unroller.h b/Lib/Include/CML/vector/vector_unroller.h new file mode 100644 index 0000000..eed6da6 --- /dev/null +++ b/Lib/Include/CML/vector/vector_unroller.h @@ -0,0 +1,259 @@ +/* -*- C++ -*- ------------------------------------------------------------ + +Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/ + +The Configurable Math Library (CML) is distributed under the terms of the +Boost Software License, v1.0 (see cml/LICENSE for details). + + *-----------------------------------------------------------------------*/ +/** @file + * @brief + * + * Defines vector unrollers. + * + * @todo Add unrolling for dynamic vectors, and for vectors longer than + * CML_VECTOR_UNROLL_LIMIT. + * + * @todo Does it make sense to unroll an assignment if either side of the + * assignment has a fixed size, or just when the target vector is fixed + * size? + */ + +#ifndef vector_unroller_h +#define vector_unroller_h + +#include +#include +#include + +#if !defined(CML_VECTOR_UNROLL_LIMIT) +#error "CML_VECTOR_UNROLL_LIMIT is undefined." +#endif + +namespace cml { +namespace et { +namespace detail { + +/** Unroll a binary assignment operator on a fixed-size vector. + * + * This uses forward iteration to make efficient use of the cache. + * + * @sa cml::vector + * @sa cml::et::OpAssign + * + * @bug Need to verify that OpT is actually an assignment operator. + */ +template +class VectorAssignmentUnroller +{ + protected: + + /* Forward declare: */ + template struct Eval; + + /* The vector type being assigned to: */ + typedef cml::vector vector_type; + + /* Record traits for the arguments: */ + typedef ExprTraits dest_traits; + typedef ExprTraits src_traits; + + /** Evaluate the binary operator for the first Len-1 elements. */ + template struct Eval { + void operator()(vector_type& dest, const SrcT& src) const { + + /* Apply to current N: */ + OpT().apply(dest[N], src_traits().get(src,N)); + /* Note: we don't need get(), since dest is a vector. */ + + /* Apply to N+1: */ + Eval()(dest, src); + } + }; + + /** Evaluate the binary operator at element Last. */ + template struct Eval { + void operator()(vector_type& dest, const SrcT& src) const { + + /* Apply to last element: */ + OpT().apply(dest[Last], src_traits().get(src,Last)); + /* Note: we don't need get(), since dest is a vector. */ + } + }; + + + /** Evaluate the binary operator using a loop. + * + * This is used when the vector's length is longer than + * CML_VECTOR_UNROLL_LIMIT + */ + template struct Eval { + void operator()(vector_type& dest, const SrcT& src) const { + for(size_t i = 0; i <= Last; ++i) { + OpT().apply(dest[i], src_traits().get(src,i)); + /* Note: we don't need get(), since dest is a vector. */ + } + } + }; + + + public: + + /** Unroll assignment to a fixed-sized vector. */ + void operator()(vector_type& dest, const SrcT& src, cml::fixed_size_tag) + { + typedef cml::vector vector_type; + enum { Len = vector_type::array_size }; + typedef typename VectorAssignmentUnroller::template + Eval<0, Len-1, (Len <= CML_VECTOR_UNROLL_LIMIT)> Unroller; + /* Note: Len is the array size, so Len-1 is the last element. */ + + /* Use a run-time check if src is a run-time sized expression: */ + typedef typename ExprTraits::size_tag src_size; + typedef typename select_if< + same_type::is_true, + dynamic_size_tag, fixed_size_tag>::result size_tag; + + /* Check the expression size (the returned size isn't needed): */ + CheckedSize(dest,src,size_tag()); + /* Note: for two fixed-size expressions, the if-statements and + * comparisons should be completely eliminated as dead code. If src + * is a dynamic-sized expression, the check will still happen. + */ + + /* Now, call the unroller: */ + Unroller()(dest,src); + } + + + private: + /* XXX Blah, a temp. hack to fix the auto-resizing stuff below. */ + size_t CheckOrResize( + vector_type& dest, const SrcT& src, cml::resizable_tag) + { +#if defined(CML_AUTOMATIC_VECTOR_RESIZE_ON_ASSIGNMENT) + /* Get the size of src. This also causes src to check its size: */ + size_t N = std::max(dest.size(),src_traits().size(src)); + + /* Set the destination vector's size: */ + cml::et::detail::Resize(dest,N); +#else + size_t N = CheckedSize(dest,src,dynamic_size_tag()); +#endif + + return N; + } + + size_t CheckOrResize( + vector_type& dest, const SrcT& src, cml::not_resizable_tag) + { + return CheckedSize(dest,src,dynamic_size_tag()); + } + /* XXX Blah, a temp. hack to fix the auto-resizing stuff below. */ + public: + + + /** Just use a loop to assign to a runtime-sized vector. */ + void operator()(vector_type& dest, const SrcT& src, cml::dynamic_size_tag) + { + /* Shorthand: */ + typedef ExprTraits src_traits; + size_t N = this->CheckOrResize( + dest,src,typename vector_type::resizing_tag()); + for(size_t i = 0; i < N; ++i) { + OpT().apply(dest[i], src_traits().get(src,i)); + /* Note: we don't need get(), since dest is a vector. */ + } + } + +}; + +/** Unroll a vector accumulation/reduction operator. + * + * This uses forward iteration to make efficient use of the cache. + */ +template +struct VectorAccumulateUnroller +{ + /* Forward declare: */ + template struct Eval; + + /* Record traits for the arguments: */ + typedef ExprTraits left_traits; + typedef ExprTraits right_traits; + + /* Figure out the return type: */ + typedef typename AccumT::value_type result_type; + + /** Evaluate for the first Len-1 elements. */ + template struct Eval { + result_type operator()( + const LeftT& left, const RightT& right) const + { + /* Apply to last value: */ + return AccumT().apply( + OpT().apply(left[N], right_traits().get(right,N)), + Eval()(left, right)); + /* Note: we don't need get(), since dest is a vector. */ + } + }; + + /** Evaluate the binary operator at element Last. */ + template struct Eval { + result_type operator()( + const LeftT& left, const RightT& right) const + { + return OpT().apply(left[Last],right_traits().get(right,Last)); + /* Note: we don't need get(), since dest is a vector. */ + } + }; + + /** Evaluate using a loop. */ + template struct Eval { + result_type operator()( + const LeftT& left, const RightT& right) const + { + result_type accum = OpT().apply(left[0],right[0]); + for(size_t i = 1; i <= Last; ++i) { + /* XXX This might not be optimized properly by some compilers, + * but to do anything else requires changing the requirements + * of a scalar operator. + */ + accum = AccumT().apply(accum, OpT().apply( + left[i],right_traits().get(right,i))); + /* Note: we don't need get(), since dest is a vector. */ + } + } + }; +}; + +} + +/** Construct an assignment unroller. + * + * The operator must be an assignment op, otherwise, this doesn't make any + * sense. + * + * @bug Need to verify that OpT is actually an assignment operator. + */ +template inline +void UnrollAssignment(cml::vector& dest, const SrcT& src) +{ + /* Record the destination vector type, and the expression traits: */ + typedef cml::vector vector_type; + + /* Record the type of the unroller: */ + typedef detail::VectorAssignmentUnroller unroller; + + /* Do the unroll call: */ + unroller()(dest, src, typename vector_type::size_tag()); + /* XXX It may make sense to unroll if either side is a fixed size. */ +} + +} // namespace et +} // namespace cml + +#endif + +// ------------------------------------------------------------------------- +// vim:ft=cpp diff --git a/Lib/Include/FMOD/fmod.h b/Lib/Include/FMOD/fmod.h new file mode 100644 index 0000000..1abd2ab --- /dev/null +++ b/Lib/Include/FMOD/fmod.h @@ -0,0 +1,2428 @@ + +/* ============================================================================================ */ +/* FMOD Ex - Main C/C++ header file. Copyright (c), Firelight Technologies Pty, Ltd. 2004-2009. */ +/* */ +/* This header is the base header for all other FMOD headers. If you are programming in C */ +/* use this exclusively, or if you are programming C++ use this in conjunction with FMOD.HPP */ +/* */ +/* ============================================================================================ */ + +#ifndef _FMOD_H +#define _FMOD_H + +/* + FMOD version number. Check this against FMOD::System::getVersion. + 0xaaaabbcc -> aaaa = major version number. bb = minor version number. cc = development version number. +*/ + +#define FMOD_VERSION 0x00043002 + +/* + Compiler specific settings. +*/ + +#if defined(__CYGWIN32__) + #define F_CDECL __cdecl + #define F_STDCALL __stdcall + #define F_DECLSPEC __declspec + #define F_DLLEXPORT ( dllexport ) +#elif (defined(WIN32) || defined(__WIN32__) || defined(_WIN64) || defined(_XBOX)) + #define F_CDECL _cdecl + #define F_STDCALL _stdcall + #define F_DECLSPEC __declspec + #define F_DLLEXPORT ( dllexport ) +#elif defined(__MACH__) + #define F_CDECL + #define F_STDCALL + #define F_DECLSPEC + #define F_DLLEXPORT __attribute__ ((visibility("default"))) +#else + #define F_STDCALL + #define F_CDECL + #define F_DECLSPEC + #define F_DLLEXPORT +#endif + +#ifdef DLL_EXPORTS + #if defined(__MACH__) + #define F_API __attribute__ ((visibility("default"))) + #else + #define F_API __declspec(dllexport) F_STDCALL + #endif +#else + #define F_API F_STDCALL +#endif + +#define F_CALLBACK F_STDCALL + +/* + FMOD types. +*/ + +typedef int FMOD_BOOL; +typedef struct FMOD_SYSTEM FMOD_SYSTEM; +typedef struct FMOD_SOUND FMOD_SOUND; +typedef struct FMOD_CHANNEL FMOD_CHANNEL; +typedef struct FMOD_CHANNELGROUP FMOD_CHANNELGROUP; +typedef struct FMOD_SOUNDGROUP FMOD_SOUNDGROUP; +typedef struct FMOD_REVERB FMOD_REVERB; +typedef struct FMOD_DSP FMOD_DSP; +typedef struct FMOD_DSPCONNECTION FMOD_DSPCONNECTION; +typedef struct FMOD_POLYGON FMOD_POLYGON; +typedef struct FMOD_GEOMETRY FMOD_GEOMETRY; +typedef struct FMOD_SYNCPOINT FMOD_SYNCPOINT; +typedef unsigned int FMOD_MODE; +typedef unsigned int FMOD_TIMEUNIT; +typedef unsigned int FMOD_INITFLAGS; +typedef unsigned int FMOD_CAPS; +typedef unsigned int FMOD_DEBUGLEVEL; +typedef unsigned int FMOD_MEMORY_TYPE; + +/* +[STRUCTURE] +[ + [DESCRIPTION] + Structure describing a point in 3D space. + + [REMARKS] + FMOD uses a left handed co-ordinate system by default. + To use a right handed co-ordinate system specify FMOD_INIT_3D_RIGHTHANDED from FMOD_INITFLAGS in System::init. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation 2, PlayStation Portable, PlayStation 3, Wii, Solaris, iPhone + + [SEE_ALSO] + System::set3DListenerAttributes + System::get3DListenerAttributes + Channel::set3DAttributes + Channel::get3DAttributes + Channel::set3DCustomRolloff + Channel::get3DCustomRolloff + Sound::set3DCustomRolloff + Sound::get3DCustomRolloff + Geometry::addPolygon + Geometry::setPolygonVertex + Geometry::getPolygonVertex + Geometry::setRotation + Geometry::getRotation + Geometry::setPosition + Geometry::getPosition + Geometry::setScale + Geometry::getScale + FMOD_INITFLAGS +] +*/ +typedef struct +{ + float x; /* X co-ordinate in 3D space. */ + float y; /* Y co-ordinate in 3D space. */ + float z; /* Z co-ordinate in 3D space. */ +} FMOD_VECTOR; + +/* +[STRUCTURE] +[ + [DESCRIPTION] + Structure describing a globally unique identifier. + + [REMARKS] + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation 2, PlayStation Portable, PlayStation 3, Wii, Solaris, iPhone + + [SEE_ALSO] + System::getDriverInfo +] +*/ +typedef struct +{ + unsigned int Data1; /* Specifies the first 8 hexadecimal digits of the GUID */ + unsigned short Data2; /* Specifies the first group of 4 hexadecimal digits. */ + unsigned short Data3; /* Specifies the second group of 4 hexadecimal digits. */ + unsigned char Data4[8]; /* Array of 8 bytes. The first 2 bytes contain the third group of 4 hexadecimal digits. The remaining 6 bytes contain the final 12 hexadecimal digits. */ +} FMOD_GUID; + + +/* +[ENUM] +[ + [DESCRIPTION] + error codes. Returned from every function. + + [REMARKS] + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation 2, PlayStation Portable, PlayStation 3, Wii, Solaris, iPhone + + [SEE_ALSO] +] +*/ +typedef enum +{ + FMOD_OK, /* No errors. */ + FMOD_ERR_ALREADYLOCKED, /* Tried to call lock a second time before unlock was called. */ + FMOD_ERR_BADCOMMAND, /* Tried to call a function on a data type that does not allow this type of functionality (ie calling Sound::lock on a streaming sound). */ + FMOD_ERR_CDDA_DRIVERS, /* Neither NTSCSI nor ASPI could be initialised. */ + FMOD_ERR_CDDA_INIT, /* An error occurred while initialising the CDDA subsystem. */ + FMOD_ERR_CDDA_INVALID_DEVICE, /* Couldn't find the specified device. */ + FMOD_ERR_CDDA_NOAUDIO, /* No audio tracks on the specified disc. */ + FMOD_ERR_CDDA_NODEVICES, /* No CD/DVD devices were found. */ + FMOD_ERR_CDDA_NODISC, /* No disc present in the specified drive. */ + FMOD_ERR_CDDA_READ, /* A CDDA read error occurred. */ + FMOD_ERR_CHANNEL_ALLOC, /* Error trying to allocate a channel. */ + FMOD_ERR_CHANNEL_STOLEN, /* The specified channel has been reused to play another sound. */ + FMOD_ERR_COM, /* A Win32 COM related error occured. COM failed to initialize or a QueryInterface failed meaning a Windows codec or driver was not installed properly. */ + FMOD_ERR_DMA, /* DMA Failure. See debug output for more information. */ + FMOD_ERR_DSP_CONNECTION, /* DSP connection error. Connection possibly caused a cyclic dependancy. Or tried to connect a tree too many units deep (more than 128). */ + FMOD_ERR_DSP_FORMAT, /* DSP Format error. A DSP unit may have attempted to connect to this network with the wrong format. */ + FMOD_ERR_DSP_NOTFOUND, /* DSP connection error. Couldn't find the DSP unit specified. */ + FMOD_ERR_DSP_RUNNING, /* DSP error. Cannot perform this operation while the network is in the middle of running. This will most likely happen if a connection or disconnection is attempted in a DSP callback. */ + FMOD_ERR_DSP_TOOMANYCONNECTIONS,/* DSP connection error. The unit being connected to or disconnected should only have 1 input or output. */ + FMOD_ERR_FILE_BAD, /* Error loading file. */ + FMOD_ERR_FILE_COULDNOTSEEK, /* Couldn't perform seek operation. This is a limitation of the medium (ie netstreams) or the file format. */ + FMOD_ERR_FILE_DISKEJECTED, /* Media was ejected while reading. */ + FMOD_ERR_FILE_EOF, /* End of file unexpectedly reached while trying to read essential data (truncated data?). */ + FMOD_ERR_FILE_NOTFOUND, /* File not found. */ + FMOD_ERR_FILE_UNWANTED, /* Unwanted file access occured. */ + FMOD_ERR_FORMAT, /* Unsupported file or audio format. */ + FMOD_ERR_HTTP, /* A HTTP error occurred. This is a catch-all for HTTP errors not listed elsewhere. */ + FMOD_ERR_HTTP_ACCESS, /* The specified resource requires authentication or is forbidden. */ + FMOD_ERR_HTTP_PROXY_AUTH, /* Proxy authentication is required to access the specified resource. */ + FMOD_ERR_HTTP_SERVER_ERROR, /* A HTTP server error occurred. */ + FMOD_ERR_HTTP_TIMEOUT, /* The HTTP request timed out. */ + FMOD_ERR_INITIALIZATION, /* FMOD was not initialized correctly to support this function. */ + FMOD_ERR_INITIALIZED, /* Cannot call this command after System::init. */ + FMOD_ERR_INTERNAL, /* An error occured that wasn't supposed to. Contact support. */ + FMOD_ERR_INVALID_ADDRESS, /* On Xbox 360, this memory address passed to FMOD must be physical, (ie allocated with XPhysicalAlloc.) */ + FMOD_ERR_INVALID_FLOAT, /* Value passed in was a NaN, Inf or denormalized float. */ + FMOD_ERR_INVALID_HANDLE, /* An invalid object handle was used. */ + FMOD_ERR_INVALID_PARAM, /* An invalid parameter was passed to this function. */ + FMOD_ERR_INVALID_POSITION, /* An invalid seek position was passed to this function. */ + FMOD_ERR_INVALID_SPEAKER, /* An invalid speaker was passed to this function based on the current speaker mode. */ + FMOD_ERR_INVALID_SYNCPOINT, /* The syncpoint did not come from this sound handle. */ + FMOD_ERR_INVALID_VECTOR, /* The vectors passed in are not unit length, or perpendicular. */ + FMOD_ERR_IRX, /* PS2 only. fmodex.irx failed to initialize. This is most likely because you forgot to load it. */ + FMOD_ERR_MAXAUDIBLE, /* Reached maximum audible playback count for this sound's soundgroup. */ + FMOD_ERR_MEMORY, /* Not enough memory or resources. */ + FMOD_ERR_MEMORY_CANTPOINT, /* Can't use FMOD_OPENMEMORY_POINT on non PCM source data, or non mp3/xma/adpcm data if FMOD_CREATECOMPRESSEDSAMPLE was used. */ + FMOD_ERR_MEMORY_IOP, /* PS2 only. Not enough memory or resources on PlayStation 2 IOP ram. */ + FMOD_ERR_MEMORY_SRAM, /* Not enough memory or resources on console sound ram. */ + FMOD_ERR_NEEDS2D, /* Tried to call a command on a 3d sound when the command was meant for 2d sound. */ + FMOD_ERR_NEEDS3D, /* Tried to call a command on a 2d sound when the command was meant for 3d sound. */ + FMOD_ERR_NEEDSHARDWARE, /* Tried to use a feature that requires hardware support. (ie trying to play a VAG compressed sound in software on PS2). */ + FMOD_ERR_NEEDSSOFTWARE, /* Tried to use a feature that requires the software engine. Software engine has either been turned off, or command was executed on a hardware channel which does not support this feature. */ + FMOD_ERR_NET_CONNECT, /* Couldn't connect to the specified host. */ + FMOD_ERR_NET_SOCKET_ERROR, /* A socket error occurred. This is a catch-all for socket-related errors not listed elsewhere. */ + FMOD_ERR_NET_URL, /* The specified URL couldn't be resolved. */ + FMOD_ERR_NET_WOULD_BLOCK, /* Operation on a non-blocking socket could not complete immediately. */ + FMOD_ERR_NOTREADY, /* Operation could not be performed because specified sound/DSP connection is not ready. */ + FMOD_ERR_OUTPUT_ALLOCATED, /* Error initializing output device, but more specifically, the output device is already in use and cannot be reused. */ + FMOD_ERR_OUTPUT_CREATEBUFFER, /* Error creating hardware sound buffer. */ + FMOD_ERR_OUTPUT_DRIVERCALL, /* A call to a standard soundcard driver failed, which could possibly mean a bug in the driver or resources were missing or exhausted. */ + FMOD_ERR_OUTPUT_ENUMERATION, /* Error enumerating the available driver list. List may be inconsistent due to a recent device addition or removal. */ + FMOD_ERR_OUTPUT_FORMAT, /* Soundcard does not support the minimum features needed for this soundsystem (16bit stereo output). */ + FMOD_ERR_OUTPUT_INIT, /* Error initializing output device. */ + FMOD_ERR_OUTPUT_NOHARDWARE, /* FMOD_HARDWARE was specified but the sound card does not have the resources necessary to play it. */ + FMOD_ERR_OUTPUT_NOSOFTWARE, /* Attempted to create a software sound but no software channels were specified in System::init. */ + FMOD_ERR_PAN, /* Panning only works with mono or stereo sound sources. */ + FMOD_ERR_PLUGIN, /* An unspecified error has been returned from a 3rd party plugin. */ + FMOD_ERR_PLUGIN_INSTANCES, /* The number of allowed instances of a plugin has been exceeded. */ + FMOD_ERR_PLUGIN_MISSING, /* A requested output, dsp unit type or codec was not available. */ + FMOD_ERR_PLUGIN_RESOURCE, /* A resource that the plugin requires cannot be found. (ie the DLS file for MIDI playback) */ + FMOD_ERR_PRELOADED, /* The specified sound is still in use by the event system, call EventSystem::unloadFSB before trying to release it. */ + FMOD_ERR_PROGRAMMERSOUND, /* The specified sound is still in use by the event system, wait for the event which is using it finish with it. */ + FMOD_ERR_RECORD, /* An error occured trying to initialize the recording device. */ + FMOD_ERR_REVERB_INSTANCE, /* Specified Instance in FMOD_REVERB_PROPERTIES couldn't be set. Most likely because it is an invalid instance number, or another application has locked the EAX4 FX slot. */ + FMOD_ERR_SUBSOUND_ALLOCATED, /* This subsound is already being used by another sound, you cannot have more than one parent to a sound. Null out the other parent's entry first. */ + FMOD_ERR_SUBSOUND_CANTMOVE, /* Shared subsounds cannot be replaced or moved from their parent stream, such as when the parent stream is an FSB file. */ + FMOD_ERR_SUBSOUND_MODE, /* The subsound's mode bits do not match with the parent sound's mode bits. See documentation for function that it was called with. */ + FMOD_ERR_SUBSOUNDS, /* The error occured because the sound referenced contains subsounds. The operation cannot be performed on a parent sound, or a parent sound was played without setting up a sentence first. */ + FMOD_ERR_TAGNOTFOUND, /* The specified tag could not be found or there are no tags. */ + FMOD_ERR_TOOMANYCHANNELS, /* The sound created exceeds the allowable input channel count. This can be increased using the maxinputchannels parameter in System::setSoftwareFormat. */ + FMOD_ERR_UNIMPLEMENTED, /* Something in FMOD hasn't been implemented when it should be! contact support! */ + FMOD_ERR_UNINITIALIZED, /* This command failed because System::init or System::setDriver was not called. */ + FMOD_ERR_UNSUPPORTED, /* A command issued was not supported by this object. Possibly a plugin without certain callbacks specified. */ + FMOD_ERR_UPDATE, /* An error caused by System::update occured. */ + FMOD_ERR_VERSION, /* The version number of this file format is not supported. */ + + FMOD_ERR_EVENT_FAILED, /* An Event failed to be retrieved, most likely due to 'just fail' being specified as the max playbacks behavior. */ + FMOD_ERR_EVENT_INFOONLY, /* Can't execute this command on an EVENT_INFOONLY event. */ + FMOD_ERR_EVENT_INTERNAL, /* An error occured that wasn't supposed to. See debug log for reason. */ + FMOD_ERR_EVENT_MAXSTREAMS, /* Event failed because 'Max streams' was hit when FMOD_EVENT_INIT_FAIL_ON_MAXSTREAMS was specified. */ + FMOD_ERR_EVENT_MISMATCH, /* FSB mismatches the FEV it was compiled with, the stream/sample mode it was meant to be created with was different, or the FEV was built for a different platform. */ + FMOD_ERR_EVENT_NAMECONFLICT, /* A category with the same name already exists. */ + FMOD_ERR_EVENT_NOTFOUND, /* The requested event, event group, event category or event property could not be found. */ + FMOD_ERR_EVENT_NEEDSSIMPLE, /* Tried to call a function on a complex event that's only supported by simple events. */ + FMOD_ERR_EVENT_GUIDCONFLICT, /* An event with the same GUID already exists. */ + FMOD_ERR_EVENT_ALREADY_LOADED, /* The specified project has already been loaded. Having multiple copies of the same project loaded simultaneously is forbidden. */ + + FMOD_ERR_MUSIC_UNINITIALIZED, /* Music system is not initialized probably because no music data is loaded. */ + FMOD_ERR_MUSIC_NOTFOUND, /* The requested music entity could not be found. */ + FMOD_ERR_MUSIC_NOCALLBACK, /* The music callback is required, but it has not been set. */ + + FMOD_RESULT_FORCEINT = 65536 /* Makes sure this enum is signed 32bit. */ +} FMOD_RESULT; + + +/* +[ENUM] +[ + [DESCRIPTION] + These output types are used with System::setOutput / System::getOutput, to choose which output method to use. + + [REMARKS] + To pass information to the driver when initializing fmod use the extradriverdata parameter in System::init for the following reasons. + - FMOD_OUTPUTTYPE_WAVWRITER - extradriverdata is a pointer to a char * filename that the wav writer will output to. + - FMOD_OUTPUTTYPE_WAVWRITER_NRT - extradriverdata is a pointer to a char * filename that the wav writer will output to. + - FMOD_OUTPUTTYPE_DSOUND - extradriverdata is a pointer to a HWND so that FMOD can set the focus on the audio for a particular window. + - FMOD_OUTPUTTYPE_PS2 - extradriverdata is a pointer to a FMOD_PS2_EXTRADRIVERDATA struct. This can be found in fmodps2.h. + - FMOD_OUTPUTTYPE_PS3 - extradriverdata is a pointer to a FMOD_PS3_EXTRADRIVERDATA struct. This can be found in fmodps3.h. + - FMOD_OUTPUTTYPE_GC - extradriverdata is a pointer to a FMOD_GC_INFO struct. This can be found in fmodgc.h. + - FMOD_OUTPUTTYPE_WII - extradriverdata is a pointer to a FMOD_WII_INFO struct. This can be found in fmodwii.h. + - FMOD_OUTPUTTYPE_ALSA - extradriverdata is a pointer to a FMOD_LINUX_EXTRADRIVERDATA struct. This can be found in fmodlinux.h. + + Currently these are the only FMOD drivers that take extra information. Other unknown plugins may have different requirements. + + Note! If FMOD_OUTPUTTYPE_WAVWRITER_NRT or FMOD_OUTPUTTYPE_NOSOUND_NRT are used, and if the System::update function is being called + very quickly (ie for a non realtime decode) it may be being called too quickly for the FMOD streamer thread to respond to. + The result will be a skipping/stuttering output in the captured audio. + + To remedy this, disable the FMOD Ex streamer thread, and use FMOD_INIT_STREAM_FROM_UPDATE to avoid skipping in the output stream, + as it will lock the mixer and the streamer together in the same thread. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation 2, PlayStation Portable, PlayStation 3, Wii, Solaris, iPhone + + [SEE_ALSO] + System::setOutput + System::getOutput + System::setSoftwareFormat + System::getSoftwareFormat + System::init + System::update + FMOD_INITFLAGS +] +*/ +typedef enum +{ + FMOD_OUTPUTTYPE_AUTODETECT, /* Picks the best output mode for the platform. This is the default. */ + + FMOD_OUTPUTTYPE_UNKNOWN, /* All - 3rd party plugin, unknown. This is for use with System::getOutput only. */ + FMOD_OUTPUTTYPE_NOSOUND, /* All - All calls in this mode succeed but make no sound. */ + FMOD_OUTPUTTYPE_WAVWRITER, /* All - Writes output to fmodoutput.wav by default. Use the 'extradriverdata' parameter in System::init, by simply passing the filename as a string, to set the wav filename. */ + FMOD_OUTPUTTYPE_NOSOUND_NRT, /* All - Non-realtime version of FMOD_OUTPUTTYPE_NOSOUND. User can drive mixer with System::update at whatever rate they want. */ + FMOD_OUTPUTTYPE_WAVWRITER_NRT, /* All - Non-realtime version of FMOD_OUTPUTTYPE_WAVWRITER. User can drive mixer with System::update at whatever rate they want. */ + + FMOD_OUTPUTTYPE_DSOUND, /* Win32/Win64 - DirectSound output. Use this to get hardware accelerated 3d audio and EAX Reverb support. (Default on Windows) */ + FMOD_OUTPUTTYPE_WINMM, /* Win32/Win64 - Windows Multimedia output. */ + FMOD_OUTPUTTYPE_OPENAL, /* Win32/Win64 - OpenAL 1.1 output. Use this for lower CPU overhead than FMOD_OUTPUTTYPE_DSOUND, and also Vista H/W support with Creative Labs cards. */ + FMOD_OUTPUTTYPE_WASAPI, /* Win32 - Windows Audio Session API. (Default on Windows Vista) */ + FMOD_OUTPUTTYPE_ASIO, /* Win32 - Low latency ASIO 2.0 driver. */ + FMOD_OUTPUTTYPE_OSS, /* Linux/Linux64/Solaris - Open Sound System output. (Default on Linux/Linux64/Solaris) */ + FMOD_OUTPUTTYPE_ALSA, /* Linux/Linux64 - Advanced Linux Sound Architecture output. */ + FMOD_OUTPUTTYPE_ESD, /* Linux/Linux64 - Enlightment Sound Daemon output. */ + FMOD_OUTPUTTYPE_COREAUDIO, /* Mac - Macintosh CoreAudio output. (Default on Mac) */ + FMOD_OUTPUTTYPE_PS2, /* PS2 - Native hardware output. (Default on PS2) */ + FMOD_OUTPUTTYPE_PS3, /* PS3 - Native hardware output. (Default on PS3) */ + FMOD_OUTPUTTYPE_XBOX360, /* Xbox 360 - Native hardware output. (Default on Xbox 360) */ + FMOD_OUTPUTTYPE_PSP, /* PSP - Native hardware output. (Default on PSP) */ + FMOD_OUTPUTTYPE_WII, /* Wii - Native hardware output. (Default on Wii) */ + + FMOD_OUTPUTTYPE_MAX, /* Maximum number of output types supported. */ + FMOD_OUTPUTTYPE_FORCEINT = 65536 /* Makes sure this enum is signed 32bit. */ +} FMOD_OUTPUTTYPE; + + +/* +[DEFINE] +[ + [NAME] + FMOD_CAPS + + [DESCRIPTION] + Bit fields to use with System::getDriverCaps to determine the capabilities of a card / output device. + + [REMARKS] + It is important to check FMOD_CAPS_HARDWARE_EMULATED on windows machines, to then adjust System::setDSPBufferSize to (1024, 10) to compensate for the higher latency. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation 2, PlayStation Portable, PlayStation 3, Wii, Solaris, iPhone + + [SEE_ALSO] + System::getDriverCaps + System::setDSPBufferSize +] +*/ +#define FMOD_CAPS_NONE 0x00000000 /* Device has no special capabilities. */ +#define FMOD_CAPS_HARDWARE 0x00000001 /* Device supports hardware mixing. */ +#define FMOD_CAPS_HARDWARE_EMULATED 0x00000002 /* User has device set to 'Hardware acceleration = off' in control panel, and now extra 200ms latency is incurred. */ +#define FMOD_CAPS_OUTPUT_MULTICHANNEL 0x00000004 /* Device can do multichannel output, ie greater than 2 channels. */ +#define FMOD_CAPS_OUTPUT_FORMAT_PCM8 0x00000008 /* Device can output to 8bit integer PCM. */ +#define FMOD_CAPS_OUTPUT_FORMAT_PCM16 0x00000010 /* Device can output to 16bit integer PCM. */ +#define FMOD_CAPS_OUTPUT_FORMAT_PCM24 0x00000020 /* Device can output to 24bit integer PCM. */ +#define FMOD_CAPS_OUTPUT_FORMAT_PCM32 0x00000040 /* Device can output to 32bit integer PCM. */ +#define FMOD_CAPS_OUTPUT_FORMAT_PCMFLOAT 0x00000080 /* Device can output to 32bit floating point PCM. */ +#define FMOD_CAPS_REVERB_EAX2 0x00000100 /* Device supports EAX2 reverb. */ +#define FMOD_CAPS_REVERB_EAX3 0x00000200 /* Device supports EAX3 reverb. */ +#define FMOD_CAPS_REVERB_EAX4 0x00000400 /* Device supports EAX4 reverb */ +#define FMOD_CAPS_REVERB_EAX5 0x00000800 /* Device supports EAX5 reverb */ +#define FMOD_CAPS_REVERB_I3DL2 0x00001000 /* Device supports I3DL2 reverb. */ +#define FMOD_CAPS_REVERB_LIMITED 0x00002000 /* Device supports some form of limited hardware reverb, maybe parameterless and only selectable by environment. */ +/* [DEFINE_END] */ + +/* +[DEFINE] +[ + [NAME] + FMOD_DEBUGLEVEL + + [DESCRIPTION] + Bit fields to use with FMOD::Debug_SetLevel / FMOD::Debug_GetLevel to control the level of tty debug output with logging versions of FMOD (fmodL). + + [REMARKS] + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation 2, PlayStation Portable, PlayStation 3, Wii, Solaris, iPhone + + [SEE_ALSO] + Debug_SetLevel + Debug_GetLevel +] +*/ +#define FMOD_DEBUG_LEVEL_NONE 0x00000000 +#define FMOD_DEBUG_LEVEL_LOG 0x00000001 +#define FMOD_DEBUG_LEVEL_ERROR 0x00000002 +#define FMOD_DEBUG_LEVEL_WARNING 0x00000004 +#define FMOD_DEBUG_LEVEL_HINT 0x00000008 +#define FMOD_DEBUG_LEVEL_ALL 0x000000FF +#define FMOD_DEBUG_TYPE_MEMORY 0x00000100 +#define FMOD_DEBUG_TYPE_THREAD 0x00000200 +#define FMOD_DEBUG_TYPE_FILE 0x00000400 +#define FMOD_DEBUG_TYPE_NET 0x00000800 +#define FMOD_DEBUG_TYPE_EVENT 0x00001000 +#define FMOD_DEBUG_TYPE_ALL 0x0000FFFF +#define FMOD_DEBUG_DISPLAY_TIMESTAMPS 0x01000000 +#define FMOD_DEBUG_DISPLAY_LINENUMBERS 0x02000000 +#define FMOD_DEBUG_DISPLAY_COMPRESS 0x04000000 +#define FMOD_DEBUG_DISPLAY_THREAD 0x08000000 +#define FMOD_DEBUG_DISPLAY_ALL 0x0F000000 +#define FMOD_DEBUG_ALL 0xFFFFFFFF +/* [DEFINE_END] */ + + +/* +[DEFINE] +[ + [NAME] + FMOD_MEMORY_TYPE + + [DESCRIPTION] + Bit fields for memory allocation type being passed into FMOD memory callbacks. + + [REMARKS] + Remember this is a bitfield. You may get more than 1 bit set (ie physical + persistent) so do not simply switch on the types! You must check each bit individually or clear out the bits that you do not want within the callback. + Bits can be excluded if you want during Memory_Initialize so that you never get them. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation 2, PlayStation Portable, PlayStation 3, Wii, Solaris, iPhone + + [SEE_ALSO] + FMOD_MEMORY_ALLOCCALLBACK + FMOD_MEMORY_REALLOCCALLBACK + FMOD_MEMORY_FREECALLBACK + Memory_Initialize + +] +*/ +#define FMOD_MEMORY_NORMAL 0x00000000 /* Standard memory. */ +#define FMOD_MEMORY_STREAM_FILE 0x00000001 /* Stream file buffer, size controllable with System::setStreamBufferSize. */ +#define FMOD_MEMORY_STREAM_DECODE 0x00000002 /* Stream decode buffer, size controllable with FMOD_CREATESOUNDEXINFO::decodebuffersize. */ +#define FMOD_MEMORY_XBOX360_PHYSICAL 0x00100000 /* Requires XPhysicalAlloc / XPhysicalFree. */ +#define FMOD_MEMORY_PERSISTENT 0x00200000 /* Persistent memory. Memory will be freed when System::release is called. */ +#define FMOD_MEMORY_SECONDARY 0x00400000 /* Secondary memory. Allocation should be in secondary memory. For example RSX on the PS3. */ +#define FMOD_MEMORY_ALL 0xFFFFFFFF + + +/* [DEFINE_END] */ + + +/* +[ENUM] +[ + [DESCRIPTION] + These are speaker types defined for use with the System::setSpeakerMode or System::getSpeakerMode command. + + [REMARKS] + These are important notes on speaker modes in regards to sounds created with FMOD_SOFTWARE. + Note below the phrase 'sound channels' is used. These are the subchannels inside a sound, they are not related and + have nothing to do with the FMOD class "Channel". + For example a mono sound has 1 sound channel, a stereo sound has 2 sound channels, and an AC3 or 6 channel wav file have 6 "sound channels". + + FMOD_SPEAKERMODE_RAW + --------------------- + This mode is for output devices that are not specifically mono/stereo/quad/surround/5.1 or 7.1, but are multichannel. + Use System::setSoftwareFormat to specify the number of speakers you want to address, otherwise it will default to 2 (stereo). + Sound channels map to speakers sequentially, so a mono sound maps to output speaker 0, stereo sound maps to output speaker 0 & 1. + The user assumes knowledge of the speaker order. FMOD_SPEAKER enumerations may not apply, so raw channel indices should be used. + Multichannel sounds map input channels to output channels 1:1. + Channel::setPan and Channel::setSpeakerMix do not work. + Speaker levels must be manually set with Channel::setSpeakerLevels. + + FMOD_SPEAKERMODE_MONO + --------------------- + This mode is for a 1 speaker arrangement. + Panning does not work in this speaker mode. + Mono, stereo and multichannel sounds have each sound channel played on the one speaker unity. + Mix behavior for multichannel sounds can be set with Channel::setSpeakerLevels. + Channel::setSpeakerMix does not work. + + FMOD_SPEAKERMODE_STEREO + ----------------------- + This mode is for 2 speaker arrangements that have a left and right speaker. + - Mono sounds default to an even distribution between left and right. They can be panned with Channel::setPan. + - Stereo sounds default to the middle, or full left in the left speaker and full right in the right speaker. + - They can be cross faded with Channel::setPan. + - Multichannel sounds have each sound channel played on each speaker at unity. + - Mix behavior for multichannel sounds can be set with Channel::setSpeakerLevels. + - Channel::setSpeakerMix works but only front left and right parameters are used, the rest are ignored. + + FMOD_SPEAKERMODE_QUAD + ------------------------ + This mode is for 4 speaker arrangements that have a front left, front right, rear left and a rear right speaker. + - Mono sounds default to an even distribution between front left and front right. They can be panned with Channel::setPan. + - Stereo sounds default to the left sound channel played on the front left, and the right sound channel played on the front right. + - They can be cross faded with Channel::setPan. + - Multichannel sounds default to all of their sound channels being played on each speaker in order of input. + - Mix behavior for multichannel sounds can be set with Channel::setSpeakerLevels. + - Channel::setSpeakerMix works but side left, side right, center and lfe are ignored. + + FMOD_SPEAKERMODE_SURROUND + ------------------------ + This mode is for 5 speaker arrangements that have a left/right/center/rear left/rear right. + - Mono sounds default to the center speaker. They can be panned with Channel::setPan. + - Stereo sounds default to the left sound channel played on the front left, and the right sound channel played on the front right. + - They can be cross faded with Channel::setPan. + - Multichannel sounds default to all of their sound channels being played on each speaker in order of input. + - Mix behavior for multichannel sounds can be set with Channel::setSpeakerLevels. + - Channel::setSpeakerMix works but side left / side right are ignored. + + FMOD_SPEAKERMODE_5POINT1 + ------------------------ + This mode is for 5.1 speaker arrangements that have a left/right/center/rear left/rear right and a subwoofer speaker. + - Mono sounds default to the center speaker. They can be panned with Channel::setPan. + - Stereo sounds default to the left sound channel played on the front left, and the right sound channel played on the front right. + - They can be cross faded with Channel::setPan. + - Multichannel sounds default to all of their sound channels being played on each speaker in order of input. + - Mix behavior for multichannel sounds can be set with Channel::setSpeakerLevels. + - Channel::setSpeakerMix works but side left / side right are ignored. + + FMOD_SPEAKERMODE_7POINT1 + ------------------------ + This mode is for 7.1 speaker arrangements that have a left/right/center/rear left/rear right/side left/side right + and a subwoofer speaker. + - Mono sounds default to the center speaker. They can be panned with Channel::setPan. + - Stereo sounds default to the left sound channel played on the front left, and the right sound channel played on the front right. + - They can be cross faded with Channel::setPan. + - Multichannel sounds default to all of their sound channels being played on each speaker in order of input. + - Mix behavior for multichannel sounds can be set with Channel::setSpeakerLevels. + - Channel::setSpeakerMix works and every parameter is used to set the balance of a sound in any speaker. + + FMOD_SPEAKERMODE_PROLOGIC + ------------------------------------------------------ + This mode is for mono, stereo, 5.1 and 7.1 speaker arrangements, as it is backwards and forwards compatible with stereo, + but to get a surround effect a Dolby Prologic or Prologic 2 hardware decoder / amplifier is needed. + Pan behavior is the same as FMOD_SPEAKERMODE_5POINT1. + + If this function is called the numoutputchannels setting in System::setSoftwareFormat is overwritten. + + For 3D sounds, panning is determined at runtime by the 3D subsystem based on the speaker mode to determine which speaker the + sound should be placed in. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation 2, PlayStation Portable, PlayStation 3, Wii, Solaris, iPhone + + [SEE_ALSO] + System::setSpeakerMode + System::getSpeakerMode + System::getDriverCaps + System::setSoftwareFormat + Channel::setSpeakerLevels +] +*/ +typedef enum +{ + FMOD_SPEAKERMODE_RAW, /* There is no specific speakermode. Sound channels are mapped in order of input to output. Use System::setSoftwareFormat to specify speaker count. See remarks for more information. */ + FMOD_SPEAKERMODE_MONO, /* The speakers are monaural. */ + FMOD_SPEAKERMODE_STEREO, /* The speakers are stereo (DEFAULT). */ + FMOD_SPEAKERMODE_QUAD, /* 4 speaker setup. This includes front left, front right, rear left, rear right. */ + FMOD_SPEAKERMODE_SURROUND, /* 5 speaker setup. This includes front left, front right, center, rear left, rear right. */ + FMOD_SPEAKERMODE_5POINT1, /* 5.1 speaker setup. This includes front left, front right, center, rear left, rear right and a subwoofer. */ + FMOD_SPEAKERMODE_7POINT1, /* 7.1 speaker setup. This includes front left, front right, center, rear left, rear right, side left, side right and a subwoofer. */ + FMOD_SPEAKERMODE_PROLOGIC, /* Stereo output, but data is encoded in a way that is picked up by a Prologic/Prologic2 decoder and split into a 5.1 speaker setup. */ + + FMOD_SPEAKERMODE_MAX, /* Maximum number of speaker modes supported. */ + FMOD_SPEAKERMODE_FORCEINT = 65536 /* Makes sure this enum is signed 32bit. */ +} FMOD_SPEAKERMODE; + + +/* +[ENUM] +[ + [DESCRIPTION] + These are speaker types defined for use with the Channel::setSpeakerLevels command. + It can also be used for speaker placement in the System::set3DSpeakerPosition command. + + [REMARKS] + If you are using FMOD_SPEAKERMODE_RAW and speaker assignments are meaningless, just cast a raw integer value to this type. + For example (FMOD_SPEAKER)7 would use the 7th speaker (also the same as FMOD_SPEAKER_SIDE_RIGHT). + Values higher than this can be used if an output system has more than 8 speaker types / output channels. 15 is the current maximum. + + NOTE: On Playstation 3 in 7.1, the extra 2 speakers are not side left/side right, they are 'surround back left'/'surround back right' which + locate the speakers behind the listener instead of to the sides like on PC. FMOD_SPEAKER_SBL/FMOD_SPEAKER_SBR are provided to make it + clearer what speaker is being addressed on that platform. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation 2, PlayStation Portable, PlayStation 3, Wii, Solaris, iPhone + + [SEE_ALSO] + FMOD_SPEAKERMODE + Channel::setSpeakerLevels + Channel::getSpeakerLevels + System::set3DSpeakerPosition + System::get3DSpeakerPosition +] +*/ +typedef enum +{ + FMOD_SPEAKER_FRONT_LEFT, + FMOD_SPEAKER_FRONT_RIGHT, + FMOD_SPEAKER_FRONT_CENTER, + FMOD_SPEAKER_LOW_FREQUENCY, + FMOD_SPEAKER_BACK_LEFT, + FMOD_SPEAKER_BACK_RIGHT, + FMOD_SPEAKER_SIDE_LEFT, + FMOD_SPEAKER_SIDE_RIGHT, + + FMOD_SPEAKER_MAX, /* Maximum number of speaker types supported. */ + FMOD_SPEAKER_MONO = FMOD_SPEAKER_FRONT_LEFT, /* For use with FMOD_SPEAKERMODE_MONO and Channel::SetSpeakerLevels. Mapped to same value as FMOD_SPEAKER_FRONT_LEFT. */ + FMOD_SPEAKER_NULL = FMOD_SPEAKER_MAX, /* A non speaker. Use this to send. */ + FMOD_SPEAKER_SBL = FMOD_SPEAKER_SIDE_LEFT, /* For use with FMOD_SPEAKERMODE_7POINT1 on PS3 where the extra speakers are surround back inside of side speakers. */ + FMOD_SPEAKER_SBR = FMOD_SPEAKER_SIDE_RIGHT, /* For use with FMOD_SPEAKERMODE_7POINT1 on PS3 where the extra speakers are surround back inside of side speakers. */ + FMOD_SPEAKER_FORCEINT = 65536 /* Makes sure this enum is signed 32bit. */ +} FMOD_SPEAKER; + + +/* +[ENUM] +[ + [DESCRIPTION] + These are plugin types defined for use with the System::getNumPlugins, + System::getPluginInfo and System::unloadPlugin functions. + + [REMARKS] + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation 2, PlayStation Portable, PlayStation 3, Wii, Solaris, iPhone + + [SEE_ALSO] + System::getNumPlugins + System::getPluginInfo + System::unloadPlugin +] +*/ +typedef enum +{ + FMOD_PLUGINTYPE_OUTPUT, /* The plugin type is an output module. FMOD mixed audio will play through one of these devices */ + FMOD_PLUGINTYPE_CODEC, /* The plugin type is a file format codec. FMOD will use these codecs to load file formats for playback. */ + FMOD_PLUGINTYPE_DSP, /* The plugin type is a DSP unit. FMOD will use these plugins as part of its DSP network to apply effects to output or generate sound in realtime. */ + + FMOD_PLUGINTYPE_MAX, /* Maximum number of plugin types supported. */ + FMOD_PLUGINTYPE_FORCEINT = 65536 /* Makes sure this enum is signed 32bit. */ +} FMOD_PLUGINTYPE; + + +/* +[DEFINE] +[ + [NAME] + FMOD_INITFLAGS + + [DESCRIPTION] + Initialization flags. Use them with System::init in the flags parameter to change various behavior. + + [REMARKS] + Use System::setAdvancedSettings to adjust settings for some of the features that are enabled by these flags. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation 2, PlayStation Portable, PlayStation 3, Wii, Solaris, iPhone + + [SEE_ALSO] + System::init + System::update + System::setAdvancedSettings + Channel::set3DOcclusion +] +*/ +#define FMOD_INIT_NORMAL 0x00000000 /* All platforms - Initialize normally */ +#define FMOD_INIT_STREAM_FROM_UPDATE 0x00000001 /* All platforms - No stream thread is created internally. Streams are driven from System::update. Mainly used with non-realtime outputs. */ +#define FMOD_INIT_3D_RIGHTHANDED 0x00000002 /* All platforms - FMOD will treat +X as right, +Y as up and +Z as backwards (towards you). */ +#define FMOD_INIT_SOFTWARE_DISABLE 0x00000004 /* All platforms - Disable software mixer to save memory. Anything created with FMOD_SOFTWARE will fail and DSP will not work. */ +#define FMOD_INIT_SOFTWARE_OCCLUSION 0x00000008 /* All platforms - All FMOD_SOFTWARE with FMOD_3D based voices will add a software lowpass filter effect into the DSP chain which is automatically used when Channel::set3DOcclusion is used or the geometry API. */ +#define FMOD_INIT_SOFTWARE_HRTF 0x00000010 /* All platforms - All FMOD_SOFTWARE with FMOD_3D based voices will add a software lowpass filter effect into the DSP chain which causes sounds to sound duller when the sound goes behind the listener. Use System::setAdvancedSettings to adjust cutoff frequency. */ +#define FMOD_INIT_SOFTWARE_REVERB_LOWMEM 0x00000040 /* All platforms - SFX reverb is run using 22/24khz delay buffers, halving the memory required. */ +#define FMOD_INIT_ENABLE_PROFILE 0x00000020 /* All platforms - Enable TCP/IP based host which allows FMOD Designer or FMOD Profiler to connect to it, and view memory, CPU and the DSP network graph in real-time. */ +#define FMOD_INIT_VOL0_BECOMES_VIRTUAL 0x00000080 /* All platforms - Any sounds that are 0 volume will go virtual and not be processed except for having their positions updated virtually. Use System::setAdvancedSettings to adjust what volume besides zero to switch to virtual at. */ +#define FMOD_INIT_WASAPI_EXCLUSIVE 0x00000100 /* Win32 Vista only - for WASAPI output - Enable exclusive access to hardware, lower latency at the expense of excluding other applications from accessing the audio hardware. */ +#define FMOD_INIT_DSOUND_HRTFNONE 0x00000200 /* Win32 only - for DirectSound output - FMOD_HARDWARE | FMOD_3D buffers use simple stereo panning/doppler/attenuation when 3D hardware acceleration is not present. */ +#define FMOD_INIT_DSOUND_HRTFLIGHT 0x00000400 /* Win32 only - for DirectSound output - FMOD_HARDWARE | FMOD_3D buffers use a slightly higher quality algorithm when 3D hardware acceleration is not present. */ +#define FMOD_INIT_DSOUND_HRTFFULL 0x00000800 /* Win32 only - for DirectSound output - FMOD_HARDWARE | FMOD_3D buffers use full quality 3D playback when 3d hardware acceleration is not present. */ +#define FMOD_INIT_PS2_DISABLECORE0REVERB 0x00010000 /* PS2 only - Disable reverb on CORE 0 to regain 256k SRAM. */ +#define FMOD_INIT_PS2_DISABLECORE1REVERB 0x00020000 /* PS2 only - Disable reverb on CORE 1 to regain 256k SRAM. */ +#define FMOD_INIT_PS2_DONTUSESCRATCHPAD 0x00040000 /* PS2 only - Disable FMOD's usage of the scratchpad. */ +#define FMOD_INIT_PS2_SWAPDMACHANNELS 0x00080000 /* PS2 only - Changes FMOD from using SPU DMA channel 0 for software mixing, and 1 for sound data upload/file streaming, to 1 and 0 respectively. */ +#define FMOD_INIT_PS3_PREFERDTS 0x00800000 /* PS3 only - Prefer DTS over Dolby Digital if both are supported. Note: 8 and 6 channel LPCM is always preferred over both DTS and Dolby Digital. */ +#define FMOD_INIT_PS3_FORCE2CHLPCM 0x01000000 /* PS3 only - Force PS3 system output mode to 2 channel LPCM. */ +#define FMOD_INIT_XBOX_REMOVEHEADROOM 0x00100000 /* Xbox only - By default DirectSound attenuates all sound by 6db to avoid clipping/distortion. CAUTION. If you use this flag you are responsible for the final mix to make sure clipping / distortion doesn't happen. */ +#define FMOD_INIT_SYSTEM_MUSICMUTENOTPAUSE 0x00200000 /* Xbox 360 / PS3 - The "music" channelgroup which by default pauses when custom 360 dashboard / PS3 BGM music is played, can be changed to mute (therefore continues playing) instead of pausing, by using this flag. */ +#define FMOD_INIT_SYNCMIXERWITHUPDATE 0x00400000 /* Win32/Wii/PS3/Xbox/Xbox 360 - FMOD Mixer thread is woken up to do a mix when System::update is called rather than waking periodically on its own timer. */ +#define FMOD_INIT_DTS_NEURALSURROUND 0x02000000 /* Win32/Mac/Linux/Solaris/PS3/Xbox360 - Use DTS Neural surround downmixing from 7.1 if speakermode set to FMOD_SPEAKERMODE_STEREO or FMOD_SPEAKERMODE_5POINT1. Always 7.1 -> 5.1 downmix for Xbox360 and PS3. Internal DSP structure will be set to 7.1. */ +#define FMOD_INIT_GEOMETRY_USECLOSEST 0x04000000 /* All platforms - With the geometry engine, only process the closest polygon rather than accumulating all polygons the sound to listener line intersects. */ +#define FMOD_INIT_DISABLE_MYEARS 0x08000000 /* Win32 - Disables MyEars HRTF 7.1 downmixing. MyEars will otherwise be disbaled if speakermode is not set to FMOD_SPEAKERMODE_STEREO or the data file is missing. */ +/* [DEFINE_END] */ + + +/* +[ENUM] +[ + [DESCRIPTION] + These definitions describe the type of song being played. + + [REMARKS] + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation 2, PlayStation Portable, PlayStation 3, Wii, Solaris, iPhone + + [SEE_ALSO] + Sound::getFormat +] +*/ +typedef enum +{ + FMOD_SOUND_TYPE_UNKNOWN, /* 3rd party / unknown plugin format. */ + FMOD_SOUND_TYPE_AAC, /* AAC. Currently unsupported. */ + FMOD_SOUND_TYPE_AIFF, /* AIFF. */ + FMOD_SOUND_TYPE_ASF, /* Microsoft Advanced Systems Format (ie WMA/ASF/WMV). */ + FMOD_SOUND_TYPE_AT3, /* Sony ATRAC 3 format */ + FMOD_SOUND_TYPE_CDDA, /* Digital CD audio. */ + FMOD_SOUND_TYPE_DLS, /* Sound font / downloadable sound bank. */ + FMOD_SOUND_TYPE_FLAC, /* FLAC lossless codec. */ + FMOD_SOUND_TYPE_FSB, /* FMOD Sample Bank. */ + FMOD_SOUND_TYPE_GCADPCM, /* GameCube ADPCM */ + FMOD_SOUND_TYPE_IT, /* Impulse Tracker. */ + FMOD_SOUND_TYPE_MIDI, /* MIDI. */ + FMOD_SOUND_TYPE_MOD, /* Protracker / Fasttracker MOD. */ + FMOD_SOUND_TYPE_MPEG, /* MP2/MP3 MPEG. */ + FMOD_SOUND_TYPE_OGGVORBIS, /* Ogg vorbis. */ + FMOD_SOUND_TYPE_PLAYLIST, /* Information only from ASX/PLS/M3U/WAX playlists */ + FMOD_SOUND_TYPE_RAW, /* Raw PCM data. */ + FMOD_SOUND_TYPE_S3M, /* ScreamTracker 3. */ + FMOD_SOUND_TYPE_SF2, /* Sound font 2 format. */ + FMOD_SOUND_TYPE_USER, /* User created sound. */ + FMOD_SOUND_TYPE_WAV, /* Microsoft WAV. */ + FMOD_SOUND_TYPE_XM, /* FastTracker 2 XM. */ + FMOD_SOUND_TYPE_XMA, /* Xbox360 XMA */ + FMOD_SOUND_TYPE_VAG, /* PlayStation 2 / PlayStation Portable adpcm VAG format. */ + + FMOD_SOUND_TYPE_MAX, /* Maximum number of sound types supported. */ + FMOD_SOUND_TYPE_FORCEINT = 65536 /* Makes sure this enum is signed 32bit. */ +} FMOD_SOUND_TYPE; + + +/* +[ENUM] +[ + [DESCRIPTION] + These definitions describe the native format of the hardware or software buffer that will be used. + + [REMARKS] + This is the format the native hardware or software buffer will be or is created in. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation 2, PlayStation Portable, PlayStation 3, Wii, Solaris, iPhone + + [SEE_ALSO] + System::createSound + Sound::getFormat +] +*/ +typedef enum +{ + FMOD_SOUND_FORMAT_NONE, /* Unitialized / unknown. */ + FMOD_SOUND_FORMAT_PCM8, /* 8bit integer PCM data. */ + FMOD_SOUND_FORMAT_PCM16, /* 16bit integer PCM data. */ + FMOD_SOUND_FORMAT_PCM24, /* 24bit integer PCM data. */ + FMOD_SOUND_FORMAT_PCM32, /* 32bit integer PCM data. */ + FMOD_SOUND_FORMAT_PCMFLOAT, /* 32bit floating point PCM data. */ + FMOD_SOUND_FORMAT_GCADPCM, /* Compressed GameCube DSP data. */ + FMOD_SOUND_FORMAT_IMAADPCM, /* Compressed IMA ADPCM / Xbox ADPCM data. */ + FMOD_SOUND_FORMAT_VAG, /* Compressed PlayStation 2 / PlayStation Portable ADPCM data. */ + FMOD_SOUND_FORMAT_XMA, /* Compressed Xbox360 data. */ + FMOD_SOUND_FORMAT_MPEG, /* Compressed MPEG layer 2 or 3 data. */ + FMOD_SOUND_FORMAT_CELT, /* Compressed CELT data. */ + + FMOD_SOUND_FORMAT_MAX, /* Maximum number of sound formats supported. */ + FMOD_SOUND_FORMAT_FORCEINT = 65536 /* Makes sure this enum is signed 32bit. */ +} FMOD_SOUND_FORMAT; + + +/* +[DEFINE] +[ + [NAME] + FMOD_MODE + + [DESCRIPTION] + Sound description bitfields, bitwise OR them together for loading and describing sounds. + + [REMARKS] + By default a sound will open as a static sound that is decompressed fully into memory to PCM. (ie equivalent of FMOD_CREATESAMPLE) + To have a sound stream instead, use FMOD_CREATESTREAM, or use the wrapper function System::createStream. + Some opening modes (ie FMOD_OPENUSER, FMOD_OPENMEMORY, FMOD_OPENMEMORY_POINT, FMOD_OPENRAW) will need extra information. + This can be provided using the FMOD_CREATESOUNDEXINFO structure. + + On Playstation 2, non VAG formats will default to FMOD_SOFTWARE if FMOD_HARDWARE is not specified. + This is due to PS2 hardware not supporting PCM data. + + Specifying FMOD_OPENMEMORY_POINT will POINT to your memory rather allocating its own sound buffers and duplicating it internally. + This means you cannot free the memory while FMOD is using it, until after Sound::release is called. + With FMOD_OPENMEMORY_POINT, for PCM formats, only WAV, FSB, and RAW are supported. For compressed formats, only those formats supported by FMOD_CREATECOMPRESSEDSAMPLE are supported. + With FMOD_OPENMEMORY_POINT and FMOD_OPENRAW or PCM, if using them together, note that you must pad the data on each side by 16 bytes. This is so fmod can modify the ends of the data for looping/interpolation/mixing purposes. If a wav file, you will need to insert silence, and then reset loop points to stop the playback from playing that silence. + With FMOD_OPENMEMORY_POINT, For Wii/PSP FMOD_HARDWARE supports this flag for the GCADPCM/VAG formats. On other platforms FMOD_SOFTWARE must be used. + + Xbox 360 memory On Xbox 360 Specifying FMOD_OPENMEMORY_POINT to a virtual memory address will cause FMOD_ERR_INVALID_ADDRESS + to be returned. Use physical memory only for this functionality. + + FMOD_LOWMEM is used on a sound if you want to minimize the memory overhead, by having FMOD not allocate memory for certain + features that are not likely to be used in a game environment. These are : + 1. Sound::getName functionality is removed. 256 bytes per sound is saved. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation 2, PlayStation Portable, PlayStation 3, Wii, Solaris, iPhone + + [SEE_ALSO] + System::createSound + System::createStream + Sound::setMode + Sound::getMode + Channel::setMode + Channel::getMode + Sound::set3DCustomRolloff + Channel::set3DCustomRolloff + Sound::getOpenState +] +*/ +#define FMOD_DEFAULT 0x00000000 /* FMOD_DEFAULT is a default sound type. Equivalent to all the defaults listed below. FMOD_LOOP_OFF, FMOD_2D, FMOD_HARDWARE. (Note - only Windows with a high spec soundcard, PS2, PSP, and Wii support FMOD_HARDWARE) */ +#define FMOD_LOOP_OFF 0x00000001 /* For non looping sounds. (DEFAULT). Overrides FMOD_LOOP_NORMAL / FMOD_LOOP_BIDI. */ +#define FMOD_LOOP_NORMAL 0x00000002 /* For forward looping sounds. */ +#define FMOD_LOOP_BIDI 0x00000004 /* For bidirectional looping sounds. (only works on software mixed static sounds). */ +#define FMOD_2D 0x00000008 /* Ignores any 3d processing. (DEFAULT). */ +#define FMOD_3D 0x00000010 /* Makes the sound positionable in 3D. Overrides FMOD_2D. */ +#define FMOD_HARDWARE 0x00000020 /* Attempts to make sounds use hardware acceleration. (DEFAULT). Note on platforms that don't support FMOD_HARDWARE (only Windows with a high spec soundcard, PS2, PSP, and Wii support FMOD_HARDWARE), this will be internally treated as FMOD_SOFTWARE. */ +#define FMOD_SOFTWARE 0x00000040 /* Makes the sound be mixed by the FMOD CPU based software mixer. Overrides FMOD_HARDWARE. Use this for FFT, DSP, compressed sample support, 2D multi-speaker support and other software related features. */ +#define FMOD_CREATESTREAM 0x00000080 /* Decompress at runtime, streaming from the source provided (ie from disk). Overrides FMOD_CREATESAMPLE and FMOD_CREATECOMPRESSEDSAMPLE. Note a stream can only be played once at a time due to a stream only having 1 stream buffer and file handle. Open multiple streams to have them play concurrently. */ +#define FMOD_CREATESAMPLE 0x00000100 /* Decompress at loadtime, decompressing or decoding whole file into memory as the target sample format (ie PCM). Fastest for FMOD_SOFTWARE based playback and most flexible. */ +#define FMOD_CREATECOMPRESSEDSAMPLE 0x00000200 /* Load MP2, MP3, IMAADPCM or XMA into memory and leave it compressed. During playback the FMOD software mixer will decode it in realtime as a 'compressed sample'. Can only be used in combination with FMOD_SOFTWARE. Overrides FMOD_CREATESAMPLE. If the sound data is not ADPCM, MPEG or XMA it will behave as if it was created with FMOD_CREATESAMPLE and decode the sound into PCM. */ +#define FMOD_OPENUSER 0x00000400 /* Opens a user created static sample or stream. Use FMOD_CREATESOUNDEXINFO to specify format and/or read callbacks. If a user created 'sample' is created with no read callback, the sample will be empty. Use Sound::lock and Sound::unlock to place sound data into the sound if this is the case. */ +#define FMOD_OPENMEMORY 0x00000800 /* "name_or_data" will be interpreted as a pointer to memory instead of filename for creating sounds. Use FMOD_CREATESOUNDEXINFO to specify length. If used with FMOD_CREATESAMPLE or FMOD_CREATECOMPRESSEDSAMPLE, FMOD duplicates the memory into its own buffers. Your own buffer can be freed after open. If used with FMOD_CREATESTREAM, FMOD will stream out of the buffer whose pointer you passed in. In this case, your own buffer should not be freed until you have finished with and released the stream.*/ +#define FMOD_OPENMEMORY_POINT 0x10000000 /* "name_or_data" will be interpreted as a pointer to memory instead of filename for creating sounds. Use FMOD_CREATESOUNDEXINFO to specify length. This differs to FMOD_OPENMEMORY in that it uses the memory as is, without duplicating the memory into its own buffers. For Wii/PSP FMOD_HARDWARE supports this flag for the GCADPCM/VAG formats. On other platforms FMOD_SOFTWARE must be used, as sound hardware on the other platforms (ie PC) cannot access main ram. Cannot be freed after open, only after Sound::release. Will not work if the data is compressed and FMOD_CREATECOMPRESSEDSAMPLE is not used. */ +#define FMOD_OPENRAW 0x00001000 /* Will ignore file format and treat as raw pcm. Use FMOD_CREATESOUNDEXINFO to specify format. Requires at least defaultfrequency, numchannels and format to be specified before it will open. Must be little endian data. */ +#define FMOD_OPENONLY 0x00002000 /* Just open the file, dont prebuffer or read. Good for fast opens for info, or when sound::readData is to be used. */ +#define FMOD_ACCURATETIME 0x00004000 /* For System::createSound - for accurate Sound::getLength/Channel::setPosition on VBR MP3, and MOD/S3M/XM/IT/MIDI files. Scans file first, so takes longer to open. FMOD_OPENONLY does not affect this. */ +#define FMOD_MPEGSEARCH 0x00008000 /* For corrupted / bad MP3 files. This will search all the way through the file until it hits a valid MPEG header. Normally only searches for 4k. */ +#define FMOD_NONBLOCKING 0x00010000 /* For opening sounds and getting streamed subsounds (seeking) asyncronously. Use Sound::getOpenState to poll the state of the sound as it opens or retrieves the subsound in the background. */ +#define FMOD_UNIQUE 0x00020000 /* Unique sound, can only be played one at a time */ +#define FMOD_3D_HEADRELATIVE 0x00040000 /* Make the sound's position, velocity and orientation relative to the listener. */ +#define FMOD_3D_WORLDRELATIVE 0x00080000 /* Make the sound's position, velocity and orientation absolute (relative to the world). (DEFAULT) */ +#define FMOD_3D_LOGROLLOFF 0x00100000 /* This sound will follow the standard logarithmic rolloff model where mindistance = full volume, maxdistance = where sound stops attenuating, and rolloff is fixed according to the global rolloff factor. (DEFAULT) */ +#define FMOD_3D_LINEARROLLOFF 0x00200000 /* This sound will follow a linear rolloff model where mindistance = full volume, maxdistance = silence. Rolloffscale is ignored. */ +#define FMOD_3D_CUSTOMROLLOFF 0x04000000 /* This sound will follow a rolloff model defined by Sound::set3DCustomRolloff / Channel::set3DCustomRolloff. */ +#define FMOD_3D_IGNOREGEOMETRY 0x40000000 /* Is not affect by geometry occlusion. If not specified in Sound::setMode, or Channel::setMode, the flag is cleared and it is affected by geometry again. */ +#define FMOD_CDDA_FORCEASPI 0x00400000 /* For CDDA sounds only - use ASPI instead of NTSCSI to access the specified CD/DVD device. */ +#define FMOD_CDDA_JITTERCORRECT 0x00800000 /* For CDDA sounds only - perform jitter correction. Jitter correction helps produce a more accurate CDDA stream at the cost of more CPU time. */ +#define FMOD_UNICODE 0x01000000 /* Filename is double-byte unicode. */ +#define FMOD_IGNORETAGS 0x02000000 /* Skips id3v2/asf/etc tag checks when opening a sound, to reduce seek/read overhead when opening files (helps with CD performance). */ +#define FMOD_LOWMEM 0x08000000 /* Removes some features from samples to give a lower memory overhead, like Sound::getName. See remarks. */ +#define FMOD_LOADSECONDARYRAM 0x20000000 /* Load sound into the secondary RAM of supported platform. On PS3, sounds will be loaded into RSX/VRAM. */ +#define FMOD_VIRTUAL_PLAYFROMSTART 0x80000000 /* For sounds that start virtual (due to being quiet or low importance), instead of swapping back to audible, and playing at the correct offset according to time, this flag makes the sound play from the start. */ + +/* [DEFINE_END] */ + + +/* +[ENUM] +[ + [DESCRIPTION] + These values describe what state a sound is in after FMOD_NONBLOCKING has been used to open it. + + [REMARKS] + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation 2, PlayStation Portable, PlayStation 3, Wii, Solaris, iPhone + + [SEE_ALSO] + Sound::getOpenState + FMOD_MODE +] +*/ +typedef enum +{ + FMOD_OPENSTATE_READY = 0, /* Opened and ready to play. */ + FMOD_OPENSTATE_LOADING, /* Initial load in progress. */ + FMOD_OPENSTATE_ERROR, /* Failed to open - file not found, out of memory etc. See return value of Sound::getOpenState for what happened. */ + FMOD_OPENSTATE_CONNECTING, /* Connecting to remote host (internet sounds only). */ + FMOD_OPENSTATE_BUFFERING, /* Buffering data. */ + FMOD_OPENSTATE_SEEKING, /* Seeking to subsound and re-flushing stream buffer. */ + FMOD_OPENSTATE_STREAMING, /* Ready and playing, but not possible to release at this time without stalling the main thread. */ + FMOD_OPENSTATE_SETPOSITION, /* Seeking within a stream to a different position. */ + + FMOD_OPENSTATE_MAX, /* Maximum number of open state types. */ + FMOD_OPENSTATE_FORCEINT = 65536 /* Makes sure this enum is signed 32bit. */ +} FMOD_OPENSTATE; + + +/* +[ENUM] +[ + [DESCRIPTION] + These flags are used with SoundGroup::setMaxAudibleBehavior to determine what happens when more sounds + are played than are specified with SoundGroup::setMaxAudible. + + [REMARKS] + When using FMOD_SOUNDGROUP_BEHAVIOR_MUTE, SoundGroup::setMuteFadeSpeed can be used to stop a sudden transition. + Instead, the time specified will be used to cross fade between the sounds that go silent and the ones that become audible. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation 2, PlayStation Portable, PlayStation 3, Wii, Solaris, iPhone + + [SEE_ALSO] + SoundGroup::setMaxAudibleBehavior + SoundGroup::getMaxAudibleBehavior + SoundGroup::setMaxAudible + SoundGroup::getMaxAudible + SoundGroup::setMuteFadeSpeed + SoundGroup::getMuteFadeSpeed +] +*/ +typedef enum +{ + FMOD_SOUNDGROUP_BEHAVIOR_FAIL, /* Any sound played that puts the sound count over the SoundGroup::setMaxAudible setting, will simply fail during System::playSound. */ + FMOD_SOUNDGROUP_BEHAVIOR_MUTE, /* Any sound played that puts the sound count over the SoundGroup::setMaxAudible setting, will be silent, then if another sound in the group stops the sound that was silent before becomes audible again. */ + FMOD_SOUNDGROUP_BEHAVIOR_STEALLOWEST, /* Any sound played that puts the sound count over the SoundGroup::setMaxAudible setting, will steal the quietest / least important sound playing in the group. */ + + FMOD_SOUNDGROUP_BEHAVIOR_MAX, /* Maximum number of open state types. */ + FMOD_SOUNDGROUP_BEHAVIOR_FORCEINT = 65536 /* Makes sure this enum is signed 32bit. */ +} FMOD_SOUNDGROUP_BEHAVIOR; + + +/* +[ENUM] +[ + [DESCRIPTION] + These callback types are used with Channel::setCallback. + + [REMARKS] + Each callback has commanddata parameters passed as int unique to the type of callback. + See reference to FMOD_CHANNEL_CALLBACK to determine what they might mean for each type of callback. + + Note! Currently the user must call System::update for these callbacks to trigger! + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation 2, PlayStation Portable, PlayStation 3, Wii, Solaris, iPhone + + [SEE_ALSO] + Channel::setCallback + FMOD_CHANNEL_CALLBACK + System::update +] +*/ +typedef enum +{ + FMOD_CHANNEL_CALLBACKTYPE_END, /* Called when a sound ends. */ + FMOD_CHANNEL_CALLBACKTYPE_VIRTUALVOICE, /* Called when a voice is swapped out or swapped in. */ + FMOD_CHANNEL_CALLBACKTYPE_SYNCPOINT, /* Called when a syncpoint is encountered. Can be from wav file markers. */ + FMOD_CHANNEL_CALLBACKTYPE_OCCLUSION, /* Called when the channel has its geometry occlusion value calculated. Can be used to clamp or change the value. */ + + FMOD_CHANNEL_CALLBACKTYPE_MAX, /* Maximum number of callback types supported. */ + FMOD_CHANNEL_CALLBACKTYPE_FORCEINT = 65536 /* Makes sure this enum is signed 32bit. */ +} FMOD_CHANNEL_CALLBACKTYPE; + + +/* +[ENUM] +[ + [DESCRIPTION] + These callback types are used with System::setCallback. + + [REMARKS] + Each callback has commanddata parameters passed as void* unique to the type of callback. + See reference to FMOD_SYSTEM_CALLBACK to determine what they might mean for each type of callback. + + Note! Using FMOD_SYSTEM_CALLBACKTYPE_DEVICELISTCHANGED (on Mac only) requires the application to be running an event loop which will allow external changes to device list to be detected by FMOD. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation 2, PlayStation Portable, PlayStation 3, Wii, Solaris, iPhone + + [SEE_ALSO] + System::setCallback + FMOD_SYSTEM_CALLBACK + System::update + DSP::addInput +] +*/ +typedef enum +{ + FMOD_SYSTEM_CALLBACKTYPE_DEVICELISTCHANGED, /* Called from System::update when the enumerated list of devices has changed. */ + FMOD_SYSTEM_CALLBACKTYPE_MEMORYALLOCATIONFAILED, /* Called directly when a memory allocation fails somewhere in FMOD. */ + FMOD_SYSTEM_CALLBACKTYPE_THREADCREATED, /* Called directly when a thread is created. */ + FMOD_SYSTEM_CALLBACKTYPE_BADDSPCONNECTION, /* Called when a bad connection was made with DSP::addInput. Usually called from mixer thread because that is where the connections are made. */ + FMOD_SYSTEM_CALLBACKTYPE_BADDSPLEVEL, /* Called when too many effects were added exceeding the maximum tree depth of 128. This is most likely caused by accidentally adding too many DSP effects. Usually called from mixer thread because that is where the connections are made. */ + + FMOD_SYSTEM_CALLBACKTYPE_MAX, /* Maximum number of callback types supported. */ + FMOD_SYSTEM_CALLBACKTYPE_FORCEINT = 65536 /* Makes sure this enum is signed 32bit. */ +} FMOD_SYSTEM_CALLBACKTYPE; + + +/* + FMOD Callbacks +*/ +typedef FMOD_RESULT (F_CALLBACK *FMOD_SYSTEM_CALLBACK) (FMOD_SYSTEM *system, FMOD_SYSTEM_CALLBACKTYPE type, void *commanddata1, void *commanddata2); + +typedef FMOD_RESULT (F_CALLBACK *FMOD_CHANNEL_CALLBACK) (FMOD_CHANNEL *channel, FMOD_CHANNEL_CALLBACKTYPE type, void *commanddata1, void *commanddata2); + +typedef FMOD_RESULT (F_CALLBACK *FMOD_SOUND_NONBLOCKCALLBACK)(FMOD_SOUND *sound, FMOD_RESULT result); +typedef FMOD_RESULT (F_CALLBACK *FMOD_SOUND_PCMREADCALLBACK)(FMOD_SOUND *sound, void *data, unsigned int datalen); +typedef FMOD_RESULT (F_CALLBACK *FMOD_SOUND_PCMSETPOSCALLBACK)(FMOD_SOUND *sound, int subsound, unsigned int position, FMOD_TIMEUNIT postype); + +typedef FMOD_RESULT (F_CALLBACK *FMOD_FILE_OPENCALLBACK) (const char *name, int unicode, unsigned int *filesize, void **handle, void **userdata); +typedef FMOD_RESULT (F_CALLBACK *FMOD_FILE_CLOSECALLBACK) (void *handle, void *userdata); +typedef FMOD_RESULT (F_CALLBACK *FMOD_FILE_READCALLBACK) (void *handle, void *buffer, unsigned int sizebytes, unsigned int *bytesread, void *userdata); +typedef FMOD_RESULT (F_CALLBACK *FMOD_FILE_SEEKCALLBACK) (void *handle, unsigned int pos, void *userdata); + +typedef void * (F_CALLBACK *FMOD_MEMORY_ALLOCCALLBACK) (unsigned int size, FMOD_MEMORY_TYPE type); +typedef void * (F_CALLBACK *FMOD_MEMORY_REALLOCCALLBACK)(void *ptr, unsigned int size, FMOD_MEMORY_TYPE type); +typedef void (F_CALLBACK *FMOD_MEMORY_FREECALLBACK) (void *ptr, FMOD_MEMORY_TYPE type); + +typedef float (F_CALLBACK *FMOD_3D_ROLLOFFCALLBACK) (FMOD_CHANNEL *channel, float distance); + + +/* +[ENUM] +[ + [DESCRIPTION] + List of windowing methods used in spectrum analysis to reduce leakage / transient signals intefering with the analysis. + This is a problem with analysis of continuous signals that only have a small portion of the signal sample (the fft window size). + Windowing the signal with a curve or triangle tapers the sides of the fft window to help alleviate this problem. + + [REMARKS] + Cyclic signals such as a sine wave that repeat their cycle in a multiple of the window size do not need windowing. + I.e. If the sine wave repeats every 1024, 512, 256 etc samples and the FMOD fft window is 1024, then the signal would not need windowing. + Not windowing is the same as FMOD_DSP_FFT_WINDOW_RECT, which is the default. + If the cycle of the signal (ie the sine wave) is not a multiple of the window size, it will cause frequency abnormalities, so a different windowing method is needed. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation 2, PlayStation Portable, PlayStation 3, Wii, Solaris, iPhone + + [SEE_ALSO] + System::getSpectrum + Channel::getSpectrum +] +*/ +typedef enum +{ + FMOD_DSP_FFT_WINDOW_RECT, /* w[n] = 1.0 */ + FMOD_DSP_FFT_WINDOW_TRIANGLE, /* w[n] = TRI(2n/N) */ + FMOD_DSP_FFT_WINDOW_HAMMING, /* w[n] = 0.54 - (0.46 * COS(n/N) ) */ + FMOD_DSP_FFT_WINDOW_HANNING, /* w[n] = 0.5 * (1.0 - COS(n/N) ) */ + FMOD_DSP_FFT_WINDOW_BLACKMAN, /* w[n] = 0.42 - (0.5 * COS(n/N) ) + (0.08 * COS(2.0 * n/N) ) */ + FMOD_DSP_FFT_WINDOW_BLACKMANHARRIS, /* w[n] = 0.35875 - (0.48829 * COS(1.0 * n/N)) + (0.14128 * COS(2.0 * n/N)) - (0.01168 * COS(3.0 * n/N)) */ + + FMOD_DSP_FFT_WINDOW_MAX, /* Maximum number of FFT window types supported. */ + FMOD_DSP_FFT_WINDOW_FORCEINT = 65536 /* Makes sure this enum is signed 32bit. */ +} FMOD_DSP_FFT_WINDOW; + + +/* +[ENUM] +[ + [DESCRIPTION] + List of interpolation types that the FMOD Ex software mixer supports. + + [REMARKS] + The default resampler type is FMOD_DSP_RESAMPLER_LINEAR. + Use System::setSoftwareFormat to tell FMOD the resampling quality you require for FMOD_SOFTWARE based sounds. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation 2, PlayStation Portable, PlayStation 3, Wii, Solaris, iPhone + + [SEE_ALSO] + System::setSoftwareFormat + System::getSoftwareFormat +] +*/ +typedef enum +{ + FMOD_DSP_RESAMPLER_NOINTERP, /* No interpolation. High frequency aliasing hiss will be audible depending on the sample rate of the sound. */ + FMOD_DSP_RESAMPLER_LINEAR, /* Linear interpolation (default method). Fast and good quality, causes very slight lowpass effect on low frequency sounds. */ + FMOD_DSP_RESAMPLER_CUBIC, /* Cubic interpolation. Slower than linear interpolation but better quality. */ + FMOD_DSP_RESAMPLER_SPLINE, /* 5 point spline interpolation. Slowest resampling method but best quality. */ + + FMOD_DSP_RESAMPLER_MAX, /* Maximum number of resample methods supported. */ + FMOD_DSP_RESAMPLER_FORCEINT = 65536 /* Makes sure this enum is signed 32bit. */ +} FMOD_DSP_RESAMPLER; + + +/* +[ENUM] +[ + [DESCRIPTION] + List of tag types that could be stored within a sound. These include id3 tags, metadata from netstreams and vorbis/asf data. + + [REMARKS] + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation 2, PlayStation Portable, PlayStation 3, Wii, Solaris, iPhone + + [SEE_ALSO] + Sound::getTag +] +*/ +typedef enum +{ + FMOD_TAGTYPE_UNKNOWN = 0, + FMOD_TAGTYPE_ID3V1, + FMOD_TAGTYPE_ID3V2, + FMOD_TAGTYPE_VORBISCOMMENT, + FMOD_TAGTYPE_SHOUTCAST, + FMOD_TAGTYPE_ICECAST, + FMOD_TAGTYPE_ASF, + FMOD_TAGTYPE_MIDI, + FMOD_TAGTYPE_PLAYLIST, + FMOD_TAGTYPE_FMOD, + FMOD_TAGTYPE_USER, + + FMOD_TAGTYPE_MAX, /* Maximum number of tag types supported. */ + FMOD_TAGTYPE_FORCEINT = 65536 /* Makes sure this enum is signed 32bit. */ +} FMOD_TAGTYPE; + + +/* +[ENUM] +[ + [DESCRIPTION] + List of data types that can be returned by Sound::getTag + + [REMARKS] + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation 2, PlayStation Portable, PlayStation 3, Wii, Solaris, iPhone + + [SEE_ALSO] + Sound::getTag +] +*/ +typedef enum +{ + FMOD_TAGDATATYPE_BINARY = 0, + FMOD_TAGDATATYPE_INT, + FMOD_TAGDATATYPE_FLOAT, + FMOD_TAGDATATYPE_STRING, + FMOD_TAGDATATYPE_STRING_UTF16, + FMOD_TAGDATATYPE_STRING_UTF16BE, + FMOD_TAGDATATYPE_STRING_UTF8, + FMOD_TAGDATATYPE_CDTOC, + + FMOD_TAGDATATYPE_MAX, /* Maximum number of tag datatypes supported. */ + FMOD_TAGDATATYPE_FORCEINT = 65536 /* Makes sure this enum is signed 32bit. */ +} FMOD_TAGDATATYPE; + + +/* +[ENUM] +[ + [DESCRIPTION] + Types of delay that can be used with Channel::setDelay / Channel::getDelay. + + [REMARKS] + If you haven't called Channel::setDelay yet, if you call Channel::getDelay with FMOD_DELAYTYPE_DSPCLOCK_START it will return the + equivalent global DSP clock value to determine when a channel started, so that you can use it for other channels to sync against. + + Use System::getDSPClock to also get the current dspclock time, a base for future calls to Channel::setDelay. + + Use FMOD_64BIT_ADD or FMOD_64BIT_SUB to add a hi/lo combination together and cope with wraparound. + + If FMOD_DELAYTYPE_END_MS is specified, the value is not treated as a 64 bit number, just the delayhi value is used and it is treated as milliseconds. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation 2, PlayStation Portable, PlayStation 3, Wii, Solaris, iPhone + + [SEE_ALSO] + Channel::setDelay + Channel::getDelay + System::getDSPClock +] +*/ +typedef enum +{ + FMOD_DELAYTYPE_END_MS, /* Delay at the end of the sound in milliseconds. Use delayhi only. Channel::isPlaying will remain true until this delay has passed even though the sound itself has stopped playing.*/ + FMOD_DELAYTYPE_DSPCLOCK_START, /* Time the sound started if Channel::getDelay is used, or if Channel::setDelay is used, the sound will delay playing until this exact tick. */ + FMOD_DELAYTYPE_DSPCLOCK_END, /* Time the sound should end. If this is non-zero, the channel will go silent at this exact tick. */ + FMOD_DELAYTYPE_DSPCLOCK_PAUSE, /* Time the sound should pause. If this is non-zero, the channel will pause at this exact tick. */ + + FMOD_DELAYTYPE_MAX, /* Maximum number of tag datatypes supported. */ + FMOD_DELAYTYPE_FORCEINT = 65536 /* Makes sure this enum is signed 32bit. */ +} FMOD_DELAYTYPE; + + +#define FMOD_64BIT_ADD(_hi1, _lo1, _hi2, _lo2) _hi1 += ((_hi2) + ((((_lo1) + (_lo2)) < (_lo1)) ? 1 : 0)); (_lo1) += (_lo2); +#define FMOD_64BIT_SUB(_hi1, _lo1, _hi2, _lo2) _hi1 -= ((_hi2) + ((((_lo1) - (_lo2)) > (_lo1)) ? 1 : 0)); (_lo1) -= (_lo2); + + +/* +[STRUCTURE] +[ + [DESCRIPTION] + Structure describing a piece of tag data. + + [REMARKS] + Members marked with [in] mean the user sets the value before passing it to the function. + Members marked with [out] mean FMOD sets the value to be used after the function exits. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation 2, PlayStation Portable, PlayStation 3, Wii, Solaris, iPhone + + [SEE_ALSO] + Sound::getTag + FMOD_TAGTYPE + FMOD_TAGDATATYPE +] +*/ +typedef struct FMOD_TAG +{ + FMOD_TAGTYPE type; /* [out] The type of this tag. */ + FMOD_TAGDATATYPE datatype; /* [out] The type of data that this tag contains */ + char *name; /* [out] The name of this tag i.e. "TITLE", "ARTIST" etc. */ + void *data; /* [out] Pointer to the tag data - its format is determined by the datatype member */ + unsigned int datalen; /* [out] Length of the data contained in this tag */ + FMOD_BOOL updated; /* [out] True if this tag has been updated since last being accessed with Sound::getTag */ +} FMOD_TAG; + + +/* +[STRUCTURE] +[ + [DESCRIPTION] + Structure describing a CD/DVD table of contents + + [REMARKS] + Members marked with [in] mean the user sets the value before passing it to the function. + Members marked with [out] mean FMOD sets the value to be used after the function exits. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation 2, PlayStation Portable, PlayStation 3, Wii, Solaris, iPhone + + [SEE_ALSO] + Sound::getTag +] +*/ +typedef struct FMOD_CDTOC +{ + int numtracks; /* [out] The number of tracks on the CD */ + int min[100]; /* [out] The start offset of each track in minutes */ + int sec[100]; /* [out] The start offset of each track in seconds */ + int frame[100]; /* [out] The start offset of each track in frames */ +} FMOD_CDTOC; + + +/* +[DEFINE] +[ + [NAME] + FMOD_TIMEUNIT + + [DESCRIPTION] + List of time types that can be returned by Sound::getLength and used with Channel::setPosition or Channel::getPosition. + + [REMARKS] + FMOD_TIMEUNIT_SENTENCE_MS, FMOD_TIMEUNIT_SENTENCE_PCM, FMOD_TIMEUNIT_SENTENCE_PCMBYTES, FMOD_TIMEUNIT_SENTENCE and FMOD_TIMEUNIT_SENTENCE_SUBSOUND are only supported by Channel functions. + Do not combine flags except FMOD_TIMEUNIT_BUFFERED. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation 2, PlayStation Portable, PlayStation 3, Wii, Solaris, iPhone + + [SEE_ALSO] + Sound::getLength + Channel::setPosition + Channel::getPosition +] +*/ +#define FMOD_TIMEUNIT_MS 0x00000001 /* Milliseconds. */ +#define FMOD_TIMEUNIT_PCM 0x00000002 /* PCM Samples, related to milliseconds * samplerate / 1000. */ +#define FMOD_TIMEUNIT_PCMBYTES 0x00000004 /* Bytes, related to PCM samples * channels * datawidth (ie 16bit = 2 bytes). */ +#define FMOD_TIMEUNIT_RAWBYTES 0x00000008 /* Raw file bytes of (compressed) sound data (does not include headers). Only used by Sound::getLength and Channel::getPosition. */ +#define FMOD_TIMEUNIT_MODORDER 0x00000100 /* MOD/S3M/XM/IT. Order in a sequenced module format. Use Sound::getFormat to determine the PCM format being decoded to. */ +#define FMOD_TIMEUNIT_MODROW 0x00000200 /* MOD/S3M/XM/IT. Current row in a sequenced module format. Sound::getLength will return the number of rows in the currently playing or seeked to pattern. */ +#define FMOD_TIMEUNIT_MODPATTERN 0x00000400 /* MOD/S3M/XM/IT. Current pattern in a sequenced module format. Sound::getLength will return the number of patterns in the song and Channel::getPosition will return the currently playing pattern. */ +#define FMOD_TIMEUNIT_SENTENCE_MS 0x00010000 /* Currently playing subsound in a sentence time in milliseconds. */ +#define FMOD_TIMEUNIT_SENTENCE_PCM 0x00020000 /* Currently playing subsound in a sentence time in PCM Samples, related to milliseconds * samplerate / 1000. */ +#define FMOD_TIMEUNIT_SENTENCE_PCMBYTES 0x00040000 /* Currently playing subsound in a sentence time in bytes, related to PCM samples * channels * datawidth (ie 16bit = 2 bytes). */ +#define FMOD_TIMEUNIT_SENTENCE 0x00080000 /* Currently playing sentence index according to the channel. */ +#define FMOD_TIMEUNIT_SENTENCE_SUBSOUND 0x00100000 /* Currently playing subsound index in a sentence. */ +#define FMOD_TIMEUNIT_BUFFERED 0x10000000 /* Time value as seen by buffered stream. This is always ahead of audible time, and is only used for processing. */ +/* [DEFINE_END] */ + + +/* +[ENUM] +[ + [DESCRIPTION] + When creating a multichannel sound, FMOD will pan them to their default speaker locations, for example a 6 channel sound will default to one channel per 5.1 output speaker. + Another example is a stereo sound. It will default to left = front left, right = front right. + + This is for sounds that are not 'default'. For example you might have a sound that is 6 channels but actually made up of 3 stereo pairs, that should all be located in front left, front right only. + + [REMARKS] + For full flexibility of speaker assignments, use Channel::setSpeakerLevels. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation 2, PlayStation Portable, PlayStation 3, Wii, Solaris, iPhone + + [SEE_ALSO] + FMOD_CREATESOUNDEXINFO + Channel::setSpeakerLevels +] +*/ +typedef enum +{ + FMOD_SPEAKERMAPTYPE_DEFAULT, /* This is the default, and just means FMOD decides which speakers it puts the source channels. */ + FMOD_SPEAKERMAPTYPE_ALLMONO, /* This means the sound is made up of all mono sounds. All voices will be panned to the front center by default in this case. */ + FMOD_SPEAKERMAPTYPE_ALLSTEREO, /* This means the sound is made up of all stereo sounds. All voices will be panned to front left and front right alternating every second channel. */ + FMOD_SPEAKERMAPTYPE_51_PROTOOLS /* Map a 5.1 sound to use protools L C R Ls Rs LFE mapping. Will return an error if not a 6 channel sound. */ +} FMOD_SPEAKERMAPTYPE; + + +/* +[STRUCTURE] +[ + [DESCRIPTION] + Use this structure with System::createSound when more control is needed over loading. + The possible reasons to use this with System::createSound are: + - Loading a file from memory. + - Loading a file from within another larger (possibly wad/pak) file, by giving the loader an offset and length. + - To create a user created / non file based sound. + - To specify a starting subsound to seek to within a multi-sample sounds (ie FSB/DLS/SF2) when created as a stream. + - To specify which subsounds to load for multi-sample sounds (ie FSB/DLS/SF2) so that memory is saved and only a subset is actually loaded/read from disk. + - To specify 'piggyback' read and seek callbacks for capture of sound data as fmod reads and decodes it. Useful for ripping decoded PCM data from sounds as they are loaded / played. + - To specify a MIDI DLS/SF2 sample set file to load when opening a MIDI file. + See below on what members to fill for each of the above types of sound you want to create. + + [REMARKS] + This structure is optional! Specify 0 or NULL in System::createSound if you don't need it! + + Members marked with [in] mean the user sets the value before passing it to the function. + Members marked with [out] mean FMOD sets the value to be used after the function exits. + + Loading a file from memory. + - Create the sound using the FMOD_OPENMEMORY flag. + - Mandatory. Specify 'length' for the size of the memory block in bytes. + - Other flags are optional. + + + Loading a file from within another larger (possibly wad/pak) file, by giving the loader an offset and length. + - Mandatory. Specify 'fileoffset' and 'length'. + - Other flags are optional. + + + To create a user created / non file based sound. + - Create the sound using the FMOD_OPENUSER flag. + - Mandatory. Specify 'defaultfrequency, 'numchannels' and 'format'. + - Other flags are optional. + + + To specify a starting subsound to seek to and flush with, within a multi-sample stream (ie FSB/DLS/SF2). + + - Mandatory. Specify 'initialsubsound'. + + + To specify which subsounds to load for multi-sample sounds (ie FSB/DLS/SF2) so that memory is saved and only a subset is actually loaded/read from disk. + + - Mandatory. Specify 'inclusionlist' and 'inclusionlistnum'. + + + To specify 'piggyback' read and seek callbacks for capture of sound data as fmod reads and decodes it. Useful for ripping decoded PCM data from sounds as they are loaded / played. + + - Mandatory. Specify 'pcmreadcallback' and 'pcmseekcallback'. + + + To specify a MIDI DLS/SF2 sample set file to load when opening a MIDI file. + + - Mandatory. Specify 'dlsname'. + + + Setting the 'decodebuffersize' is for cpu intensive codecs that may be causing stuttering, not file intensive codecs (ie those from CD or netstreams) which are normally + altered with System::setStreamBufferSize. As an example of cpu intensive codecs, an mp3 file will take more cpu to decode than a PCM wav file. + If you have a stuttering effect, then it is using more cpu than the decode buffer playback rate can keep up with. Increasing the decode buffersize will most likely solve this problem. + + + FSB codec. If inclusionlist and numsubsounds are used together, this will trigger a special mode where subsounds are shuffled down to save memory. (useful for large FSB + files where you only want to load 1 sound). There will be no gaps, ie no null subsounds. As an example, if there are 10,000 subsounds and there is an inclusionlist with only 1 entry, + and numsubsounds = 1, then subsound 0 will be that entry, and there will only be the memory allocated for 1 subsound. Previously there would still be 10,000 subsound pointers and other + associated codec entries allocated along with it multiplied by 10,000. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation 2, PlayStation Portable, PlayStation 3, Wii, Solaris, iPhone + + [SEE_ALSO] + System::createSound + System::setStreamBufferSize + FMOD_MODE + FMOD_SOUND_FORMAT + FMOD_SOUND_TYPE + FMOD_SPEAKERMAPTYPE +] +*/ +typedef struct FMOD_CREATESOUNDEXINFO +{ + int cbsize; /* [in] Size of this structure. This is used so the structure can be expanded in the future and still work on older versions of FMOD Ex. */ + unsigned int length; /* [in] Optional. Specify 0 to ignore. Size in bytes of file to load, or sound to create (in this case only if FMOD_OPENUSER is used). Required if loading from memory. If 0 is specified, then it will use the size of the file (unless loading from memory then an error will be returned). */ + unsigned int fileoffset; /* [in] Optional. Specify 0 to ignore. Offset from start of the file to start loading from. This is useful for loading files from inside big data files. */ + int numchannels; /* [in] Optional. Specify 0 to ignore. Number of channels in a sound mandatory if FMOD_OPENUSER or FMOD_OPENRAW is used. */ + int defaultfrequency; /* [in] Optional. Specify 0 to ignore. Default frequency of sound in a sound mandatory if FMOD_OPENUSER or FMOD_OPENRAW is used. Other formats use the frequency determined by the file format. */ + FMOD_SOUND_FORMAT format; /* [in] Optional. Specify 0 or FMOD_SOUND_FORMAT_NONE to ignore. Format of the sound mandatory if FMOD_OPENUSER or FMOD_OPENRAW is used. Other formats use the format determined by the file format. */ + unsigned int decodebuffersize; /* [in] Optional. Specify 0 to ignore. For streams. This determines the size of the double buffer (in PCM samples) that a stream uses. Use this for user created streams if you want to determine the size of the callback buffer passed to you. Specify 0 to use FMOD's default size which is currently equivalent to 400ms of the sound format created/loaded. */ + int initialsubsound; /* [in] Optional. Specify 0 to ignore. In a multi-sample file format such as .FSB/.DLS/.SF2, specify the initial subsound to seek to, only if FMOD_CREATESTREAM is used. */ + int numsubsounds; /* [in] Optional. Specify 0 to ignore or have no subsounds. In a sound created with FMOD_OPENUSER, specify the number of subsounds that are accessable with Sound::getSubSound. If not created with FMOD_OPENUSER, this will limit the number of subsounds loaded within a multi-subsound file. If using FSB, then if FMOD_CREATESOUNDEXINFO::inclusionlist is used, this will shuffle subsounds down so that there are not any gaps. It will mean that the indices of the sounds will be different. */ + int *inclusionlist; /* [in] Optional. Specify 0 to ignore. In a multi-sample format such as .FSB/.DLS/.SF2 it may be desirable to specify only a subset of sounds to be loaded out of the whole file. This is an array of subsound indices to load into memory when created. */ + int inclusionlistnum; /* [in] Optional. Specify 0 to ignore. This is the number of integers contained within the inclusionlist array. */ + FMOD_SOUND_PCMREADCALLBACK pcmreadcallback; /* [in] Optional. Specify 0 to ignore. Callback to 'piggyback' on FMOD's read functions and accept or even write PCM data while FMOD is opening the sound. Used for user sounds created with FMOD_OPENUSER or for capturing decoded data as FMOD reads it. */ + FMOD_SOUND_PCMSETPOSCALLBACK pcmsetposcallback; /* [in] Optional. Specify 0 to ignore. Callback for when the user calls a seeking function such as Channel::setTime or Channel::setPosition within a multi-sample sound, and for when it is opened.*/ + FMOD_SOUND_NONBLOCKCALLBACK nonblockcallback; /* [in] Optional. Specify 0 to ignore. Callback for successful completion, or error while loading a sound that used the FMOD_NONBLOCKING flag.*/ + const char *dlsname; /* [in] Optional. Specify 0 to ignore. Filename for a DLS or SF2 sample set when loading a MIDI file. If not specified, on Windows it will attempt to open /windows/system32/drivers/gm.dls or /windows/system32/drivers/etc/gm.dls, on Mac it will attempt to load /System/Library/Components/CoreAudio.component/Contents/Resources/gs_instruments.dls, otherwise the MIDI will fail to open. Current DLS support is for level 1 of the specification. */ + const char *encryptionkey; /* [in] Optional. Specify 0 to ignore. Key for encrypted FSB file. Without this key an encrypted FSB file will not load. */ + int maxpolyphony; /* [in] Optional. Specify 0 to ignore. For sequenced formats with dynamic channel allocation such as .MID and .IT, this specifies the maximum voice count allowed while playing. .IT defaults to 64. .MID defaults to 32. */ + void *userdata; /* [in] Optional. Specify 0 to ignore. This is user data to be attached to the sound during creation. Access via Sound::getUserData. Note: This is not passed to FMOD_FILE_OPENCALLBACK, that is a different userdata that is file specific. */ + FMOD_SOUND_TYPE suggestedsoundtype; /* [in] Optional. Specify 0 or FMOD_SOUND_TYPE_UNKNOWN to ignore. Instead of scanning all codec types, use this to speed up loading by making it jump straight to this codec. */ + FMOD_FILE_OPENCALLBACK useropen; /* [in] Optional. Specify 0 to ignore. Callback for opening this file. */ + FMOD_FILE_CLOSECALLBACK userclose; /* [in] Optional. Specify 0 to ignore. Callback for closing this file. */ + FMOD_FILE_READCALLBACK userread; /* [in] Optional. Specify 0 to ignore. Callback for reading from this file. */ + FMOD_FILE_SEEKCALLBACK userseek; /* [in] Optional. Specify 0 to ignore. Callback for seeking within this file. */ + FMOD_SPEAKERMAPTYPE speakermap; /* [in] Optional. Specify 0 to ignore. Use this to differ the way fmod maps multichannel sounds to speakers. See FMOD_SPEAKERMAPTYPE for more. */ + FMOD_SOUNDGROUP *initialsoundgroup; /* [in] Optional. Specify 0 to ignore. Specify a sound group if required, to put sound in as it is created. */ + unsigned int initialseekposition;/* [in] Optional. Specify 0 to ignore. For streams. Specify an initial position to seek the stream to. */ + FMOD_TIMEUNIT initialseekpostype; /* [in] Optional. Specify 0 to ignore. For streams. Specify the time unit for the position set in initialseekposition. */ + int ignoresetfilesystem;/* [in] Optional. Specify 0 to ignore. Set to 1 to use fmod's built in file system. Ignores setFileSystem callbacks and also FMOD_CREATESOUNEXINFO file callbacks. Useful for specific cases where you don't want to use your own file system but want to use fmod's file system (ie net streaming). */ +} FMOD_CREATESOUNDEXINFO; + + +/* +[STRUCTURE] +[ + [DESCRIPTION] + Structure defining a reverb environment. + + For more indepth descriptions of the reverb properties under win32, please see the EAX2 and EAX3 + documentation at http://developer.creative.com/ under the 'downloads' section. + If they do not have the EAX3 documentation, then most information can be attained from + the EAX2 documentation, as EAX3 only adds some more parameters and functionality on top of + EAX2. + + [REMARKS] + Note the default reverb properties are the same as the FMOD_PRESET_GENERIC preset. + Note that integer values that typically range from -10,000 to 1000 are represented in + decibels, and are of a logarithmic scale, not linear, wheras float values are always linear. + + The numerical values listed below are the maximum, minimum and default values for each variable respectively. + + SUPPORTED next to each parameter means the platform the parameter can be set on. Some platforms support all parameters and some don't. + EAX means hardware reverb on FMOD_OUTPUTTYPE_DSOUND on windows only (must use FMOD_HARDWARE), on soundcards that support EAX 1 to 4. + EAX4 means hardware reverb on FMOD_OUTPUTTYPE_DSOUND on windows only (must use FMOD_HARDWARE), on soundcards that support EAX 4. + I3DL2 means hardware reverb on FMOD_OUTPUTTYPE_DSOUND on windows only (must use FMOD_HARDWARE), on soundcards that support I3DL2 non EAX native reverb. + WII means Nintendo Wii hardware reverb (must use FMOD_HARDWARE). + PS2 means Playstation 2 hardware reverb (must use FMOD_HARDWARE). + SFX means FMOD SFX software reverb. This works on any platform that uses FMOD_SOFTWARE for loading sounds. + + Members marked with [in] mean the user sets the value before passing it to the function. + Members marked with [out] mean FMOD sets the value to be used after the function exits. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation 2, PlayStation Portable, PlayStation 3, Wii, Solaris, iPhone + + [SEE_ALSO] + System::setReverbProperties + System::getReverbProperties + FMOD_REVERB_PRESETS + FMOD_REVERB_FLAGS +] +*/ +typedef struct FMOD_REVERB_PROPERTIES +{ /* MIN MAX DEFAULT DESCRIPTION */ + int Instance; /* [in] 0 , 3 , 0 , Environment Instance. Simultaneous HW reverbs are possible on some platforms. (SUPPORTED:EAX4/SFX(3 instances) and Wii (2 instances)) */ + int Environment; /* [in/out] -1 , 25 , -1 , sets all listener properties. -1 = OFF. (SUPPORTED:EAX/PS2) */ + float EnvSize; /* [in/out] 1.0 , 100.0 , 7.5 , environment size in meters (SUPPORTED:EAX) */ + float EnvDiffusion; /* [in/out] 0.0 , 1.0 , 1.0 , environment diffusion (SUPPORTED:EAX) */ + int Room; /* [in/out] -10000, 0 , -1000 , room effect level (at mid frequencies) (SUPPORTED:EAX/I3DL2/SFX) */ + int RoomHF; /* [in/out] -10000, 0 , -100 , relative room effect level at high frequencies (SUPPORTED:EAX/I3DL2/SFX) */ + int RoomLF; /* [in/out] -10000, 0 , 0 , relative room effect level at low frequencies (SUPPORTED:EAX/SFX) */ + float DecayTime; /* [in/out] 0.1 , 20.0 , 1.49 , reverberation decay time at mid frequencies (SUPPORTED:EAX/I3DL2/SFX) */ + float DecayHFRatio; /* [in/out] 0.1 , 2.0 , 0.83 , high-frequency to mid-frequency decay time ratio (SUPPORTED:EAX/I3DL2/SFX) */ + float DecayLFRatio; /* [in/out] 0.1 , 2.0 , 1.0 , low-frequency to mid-frequency decay time ratio (SUPPORTED:EAX) */ + int Reflections; /* [in/out] -10000, 1000 , -2602 , early reflections level relative to room effect (SUPPORTED:EAX/I3DL2/SFX) */ + float ReflectionsDelay; /* [in/out] 0.0 , 0.3 , 0.007 , initial reflection delay time (SUPPORTED:EAX/I3DL2/SFX) */ + float ReflectionsPan[3]; /* [in/out] , , [0,0,0], early reflections panning vector (SUPPORTED:EAX) */ + int Reverb; /* [in/out] -10000, 2000 , 200 , late reverberation level relative to room effect (SUPPORTED:EAX/I3DL2/SFX) */ + float ReverbDelay; /* [in/out] 0.0 , 0.1 , 0.011 , late reverberation delay time relative to initial reflection (SUPPORTED:EAX/I3DL2/SFX) */ + float ReverbPan[3]; /* [in/out] , , [0,0,0], late reverberation panning vector (SUPPORTED:EAX) */ + float EchoTime; /* [in/out] .075 , 0.25 , 0.25 , echo time (SUPPORTED:EAX/PS2(FMOD_PRESET_PS2_ECHO/FMOD_PRESET_PS2_DELAY only) */ + float EchoDepth; /* [in/out] 0.0 , 1.0 , 0.0 , echo depth (SUPPORTED:EAX/PS2(FMOD_PRESET_PS2_ECHO only) */ + float ModulationTime; /* [in/out] 0.04 , 4.0 , 0.25 , modulation time (SUPPORTED:EAX) */ + float ModulationDepth; /* [in/out] 0.0 , 1.0 , 0.0 , modulation depth (SUPPORTED:EAX) */ + float AirAbsorptionHF; /* [in/out] -100 , 0.0 , -5.0 , change in level per meter at high frequencies (SUPPORTED:EAX) */ + float HFReference; /* [in/out] 1000.0, 20000 , 5000.0 , reference high frequency (hz) (SUPPORTED:EAX/I3DL2/SFX) */ + float LFReference; /* [in/out] 20.0 , 1000.0, 250.0 , reference low frequency (hz) (SUPPORTED:EAX/SFX) */ + float RoomRolloffFactor; /* [in/out] 0.0 , 10.0 , 0.0 , like rolloffscale in System::set3DSettings but for reverb room size effect (SUPPORTED:EAX/I3DL2) */ + float Diffusion; /* [in/out] 0.0 , 100.0 , 100.0 , Value that controls the echo density in the late reverberation decay. (SUPPORTED:I3DL2/SFX) */ + float Density; /* [in/out] 0.0 , 100.0 , 100.0 , Value that controls the modal density in the late reverberation decay (SUPPORTED:I3DL2/SFX) */ + unsigned int Flags; /* [in/out] FMOD_REVERB_FLAGS - modifies the behavior of above properties (SUPPORTED:EAX/PS2/WII) */ +} FMOD_REVERB_PROPERTIES; + + +/* +[DEFINE] +[ + [NAME] + FMOD_REVERB_FLAGS + + [DESCRIPTION] + Values for the Flags member of the FMOD_REVERB_PROPERTIES structure. + + [REMARKS] + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation 2, PlayStation Portable, PlayStation 3, Wii, Solaris, iPhone + + [SEE_ALSO] + FMOD_REVERB_PROPERTIES +] +*/ +#define FMOD_REVERB_FLAGS_DECAYTIMESCALE 0x00000001 /* 'EnvSize' affects reverberation decay time */ +#define FMOD_REVERB_FLAGS_REFLECTIONSSCALE 0x00000002 /* 'EnvSize' affects reflection level */ +#define FMOD_REVERB_FLAGS_REFLECTIONSDELAYSCALE 0x00000004 /* 'EnvSize' affects initial reflection delay time */ +#define FMOD_REVERB_FLAGS_REVERBSCALE 0x00000008 /* 'EnvSize' affects reflections level */ +#define FMOD_REVERB_FLAGS_REVERBDELAYSCALE 0x00000010 /* 'EnvSize' affects late reverberation delay time */ +#define FMOD_REVERB_FLAGS_DECAYHFLIMIT 0x00000020 /* AirAbsorptionHF affects DecayHFRatio */ +#define FMOD_REVERB_FLAGS_ECHOTIMESCALE 0x00000040 /* 'EnvSize' affects echo time */ +#define FMOD_REVERB_FLAGS_MODULATIONTIMESCALE 0x00000080 /* 'EnvSize' affects modulation time */ +#define FMOD_REVERB_FLAGS_CORE0 0x00000100 /* PS2 Only - Reverb is applied to CORE0 (hw voices 0-23) */ +#define FMOD_REVERB_FLAGS_CORE1 0x00000200 /* PS2 Only - Reverb is applied to CORE1 (hw voices 24-47) */ +#define FMOD_REVERB_FLAGS_HIGHQUALITYREVERB 0x00000400 /* GameCube/Wii. Use high quality reverb */ +#define FMOD_REVERB_FLAGS_HIGHQUALITYDPL2REVERB 0x00000800 /* GameCube/Wii. Use high quality DPL2 reverb */ + +#define FMOD_REVERB_FLAGS_DEFAULT (FMOD_REVERB_FLAGS_DECAYTIMESCALE | \ + FMOD_REVERB_FLAGS_REFLECTIONSSCALE | \ + FMOD_REVERB_FLAGS_REFLECTIONSDELAYSCALE | \ + FMOD_REVERB_FLAGS_REVERBSCALE | \ + FMOD_REVERB_FLAGS_REVERBDELAYSCALE | \ + FMOD_REVERB_FLAGS_DECAYHFLIMIT | \ + FMOD_REVERB_FLAGS_CORE0 | \ + FMOD_REVERB_FLAGS_CORE1) +/* [DEFINE_END] */ + + +/* +[DEFINE] +[ + [NAME] + FMOD_REVERB_PRESETS + + [DESCRIPTION] + A set of predefined environment PARAMETERS, created by Creative Labs + These are used to initialize an FMOD_REVERB_PROPERTIES structure statically. + ie + FMOD_REVERB_PROPERTIES prop = FMOD_PRESET_GENERIC; + + [REMARKS] + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation 2, PlayStation Portable, PlayStation 3, Wii, Solaris, iPhone + + [SEE_ALSO] + System::setReverbProperties +] +*/ +/* Inst Env Size Diffus Room RoomHF RmLF DecTm DecHF DecLF Refl RefDel RefPan Revb RevDel ReverbPan EchoTm EchDp ModTm ModDp AirAbs HFRef LFRef RRlOff Diffus Densty FLAGS */ +#define FMOD_PRESET_OFF { 0, -1, 7.5f, 1.00f, -10000, -10000, 0, 1.00f, 1.00f, 1.0f, -2602, 0.007f, { 0.0f,0.0f,0.0f }, 200, 0.011f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 0.0f, 0.0f, 0x33f } +#define FMOD_PRESET_GENERIC { 0, 0, 7.5f, 1.00f, -1000, -100, 0, 1.49f, 0.83f, 1.0f, -2602, 0.007f, { 0.0f,0.0f,0.0f }, 200, 0.011f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f } +#define FMOD_PRESET_PADDEDCELL { 0, 1, 1.4f, 1.00f, -1000, -6000, 0, 0.17f, 0.10f, 1.0f, -1204, 0.001f, { 0.0f,0.0f,0.0f }, 207, 0.002f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f } +#define FMOD_PRESET_ROOM { 0, 2, 1.9f, 1.00f, -1000, -454, 0, 0.40f, 0.83f, 1.0f, -1646, 0.002f, { 0.0f,0.0f,0.0f }, 53, 0.003f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f } +#define FMOD_PRESET_BATHROOM { 0, 3, 1.4f, 1.00f, -1000, -1200, 0, 1.49f, 0.54f, 1.0f, -370, 0.007f, { 0.0f,0.0f,0.0f }, 1030, 0.011f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 60.0f, 0x3f } +#define FMOD_PRESET_LIVINGROOM { 0, 4, 2.5f, 1.00f, -1000, -6000, 0, 0.50f, 0.10f, 1.0f, -1376, 0.003f, { 0.0f,0.0f,0.0f }, -1104, 0.004f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f } +#define FMOD_PRESET_STONEROOM { 0, 5, 11.6f, 1.00f, -1000, -300, 0, 2.31f, 0.64f, 1.0f, -711, 0.012f, { 0.0f,0.0f,0.0f }, 83, 0.017f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f } +#define FMOD_PRESET_AUDITORIUM { 0, 6, 21.6f, 1.00f, -1000, -476, 0, 4.32f, 0.59f, 1.0f, -789, 0.020f, { 0.0f,0.0f,0.0f }, -289, 0.030f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f } +#define FMOD_PRESET_CONCERTHALL { 0, 7, 19.6f, 1.00f, -1000, -500, 0, 3.92f, 0.70f, 1.0f, -1230, 0.020f, { 0.0f,0.0f,0.0f }, -2, 0.029f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f } +#define FMOD_PRESET_CAVE { 0, 8, 14.6f, 1.00f, -1000, 0, 0, 2.91f, 1.30f, 1.0f, -602, 0.015f, { 0.0f,0.0f,0.0f }, -302, 0.022f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x1f } +#define FMOD_PRESET_ARENA { 0, 9, 36.2f, 1.00f, -1000, -698, 0, 7.24f, 0.33f, 1.0f, -1166, 0.020f, { 0.0f,0.0f,0.0f }, 16, 0.030f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f } +#define FMOD_PRESET_HANGAR { 0, 10, 50.3f, 1.00f, -1000, -1000, 0, 10.05f, 0.23f, 1.0f, -602, 0.020f, { 0.0f,0.0f,0.0f }, 198, 0.030f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f } +#define FMOD_PRESET_CARPETTEDHALLWAY { 0, 11, 1.9f, 1.00f, -1000, -4000, 0, 0.30f, 0.10f, 1.0f, -1831, 0.002f, { 0.0f,0.0f,0.0f }, -1630, 0.030f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f } +#define FMOD_PRESET_HALLWAY { 0, 12, 1.8f, 1.00f, -1000, -300, 0, 1.49f, 0.59f, 1.0f, -1219, 0.007f, { 0.0f,0.0f,0.0f }, 441, 0.011f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f } +#define FMOD_PRESET_STONECORRIDOR { 0, 13, 13.5f, 1.00f, -1000, -237, 0, 2.70f, 0.79f, 1.0f, -1214, 0.013f, { 0.0f,0.0f,0.0f }, 395, 0.020f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f } +#define FMOD_PRESET_ALLEY { 0, 14, 7.5f, 0.30f, -1000, -270, 0, 1.49f, 0.86f, 1.0f, -1204, 0.007f, { 0.0f,0.0f,0.0f }, -4, 0.011f, { 0.0f,0.0f,0.0f }, 0.125f, 0.95f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f } +#define FMOD_PRESET_FOREST { 0, 15, 38.0f, 0.30f, -1000, -3300, 0, 1.49f, 0.54f, 1.0f, -2560, 0.162f, { 0.0f,0.0f,0.0f }, -229, 0.088f, { 0.0f,0.0f,0.0f }, 0.125f, 1.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 79.0f, 100.0f, 0x3f } +#define FMOD_PRESET_CITY { 0, 16, 7.5f, 0.50f, -1000, -800, 0, 1.49f, 0.67f, 1.0f, -2273, 0.007f, { 0.0f,0.0f,0.0f }, -1691, 0.011f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 50.0f, 100.0f, 0x3f } +#define FMOD_PRESET_MOUNTAINS { 0, 17, 100.0f, 0.27f, -1000, -2500, 0, 1.49f, 0.21f, 1.0f, -2780, 0.300f, { 0.0f,0.0f,0.0f }, -1434, 0.100f, { 0.0f,0.0f,0.0f }, 0.250f, 1.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 27.0f, 100.0f, 0x1f } +#define FMOD_PRESET_QUARRY { 0, 18, 17.5f, 1.00f, -1000, -1000, 0, 1.49f, 0.83f, 1.0f, -10000, 0.061f, { 0.0f,0.0f,0.0f }, 500, 0.025f, { 0.0f,0.0f,0.0f }, 0.125f, 0.70f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f } +#define FMOD_PRESET_PLAIN { 0, 19, 42.5f, 0.21f, -1000, -2000, 0, 1.49f, 0.50f, 1.0f, -2466, 0.179f, { 0.0f,0.0f,0.0f }, -1926, 0.100f, { 0.0f,0.0f,0.0f }, 0.250f, 1.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 21.0f, 100.0f, 0x3f } +#define FMOD_PRESET_PARKINGLOT { 0, 20, 8.3f, 1.00f, -1000, 0, 0, 1.65f, 1.50f, 1.0f, -1363, 0.008f, { 0.0f,0.0f,0.0f }, -1153, 0.012f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x1f } +#define FMOD_PRESET_SEWERPIPE { 0, 21, 1.7f, 0.80f, -1000, -1000, 0, 2.81f, 0.14f, 1.0f, 429, 0.014f, { 0.0f,0.0f,0.0f }, 1023, 0.021f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 80.0f, 60.0f, 0x3f } +#define FMOD_PRESET_UNDERWATER { 0, 22, 1.8f, 1.00f, -1000, -4000, 0, 1.49f, 0.10f, 1.0f, -449, 0.007f, { 0.0f,0.0f,0.0f }, 1700, 0.011f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 1.18f, 0.348f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f } + +/* Non I3DL2 presets */ + +#define FMOD_PRESET_DRUGGED { 0, 23, 1.9f, 0.50f, -1000, 0, 0, 8.39f, 1.39f, 1.0f, -115, 0.002f, { 0.0f,0.0f,0.0f }, 985, 0.030f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 1.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x1f } +#define FMOD_PRESET_DIZZY { 0, 24, 1.8f, 0.60f, -1000, -400, 0, 17.23f, 0.56f, 1.0f, -1713, 0.020f, { 0.0f,0.0f,0.0f }, -613, 0.030f, { 0.0f,0.0f,0.0f }, 0.250f, 1.00f, 0.81f, 0.310f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x1f } +#define FMOD_PRESET_PSYCHOTIC { 0, 25, 1.0f, 0.50f, -1000, -151, 0, 7.56f, 0.91f, 1.0f, -626, 0.020f, { 0.0f,0.0f,0.0f }, 774, 0.030f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 4.00f, 1.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x1f } + +/* PlayStation 2 / PlayStation Portable Only presets */ + +#define FMOD_PRESET_PS2_ROOM { 0, 1, 0, 0, 0, 0, 0, 0.0f, 0.0f, 0.0f, 0, 0.000f, { 0.0f,0.0f,0.0f }, 0, 0.000f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.00f, 0.000f, 0.0f, 0000.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0x31f } +#define FMOD_PRESET_PS2_STUDIO_A { 0, 2, 0, 0, 0, 0, 0, 0.0f, 0.0f, 0.0f, 0, 0.000f, { 0.0f,0.0f,0.0f }, 0, 0.000f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.00f, 0.000f, 0.0f, 0000.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0x31f } +#define FMOD_PRESET_PS2_STUDIO_B { 0, 3, 0, 0, 0, 0, 0, 0.0f, 0.0f, 0.0f, 0, 0.000f, { 0.0f,0.0f,0.0f }, 0, 0.000f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.00f, 0.000f, 0.0f, 0000.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0x31f } +#define FMOD_PRESET_PS2_STUDIO_C { 0, 4, 0, 0, 0, 0, 0, 0.0f, 0.0f, 0.0f, 0, 0.000f, { 0.0f,0.0f,0.0f }, 0, 0.000f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.00f, 0.000f, 0.0f, 0000.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0x31f } +#define FMOD_PRESET_PS2_HALL { 0, 5, 0, 0, 0, 0, 0, 0.0f, 0.0f, 0.0f, 0, 0.000f, { 0.0f,0.0f,0.0f }, 0, 0.000f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.00f, 0.000f, 0.0f, 0000.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0x31f } +#define FMOD_PRESET_PS2_SPACE { 0, 6, 0, 0, 0, 0, 0, 0.0f, 0.0f, 0.0f, 0, 0.000f, { 0.0f,0.0f,0.0f }, 0, 0.000f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.00f, 0.000f, 0.0f, 0000.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0x31f } +#define FMOD_PRESET_PS2_ECHO { 0, 7, 0, 0, 0, 0, 0, 0.0f, 0.0f, 0.0f, 0, 0.000f, { 0.0f,0.0f,0.0f }, 0, 0.000f, { 0.0f,0.0f,0.0f }, 0.250f, 0.75f, 0.00f, 0.000f, 0.0f, 0000.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0x31f } +#define FMOD_PRESET_PS2_DELAY { 0, 8, 0, 0, 0, 0, 0, 0.0f, 0.0f, 0.0f, 0, 0.000f, { 0.0f,0.0f,0.0f }, 0, 0.000f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.00f, 0.000f, 0.0f, 0000.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0x31f } +#define FMOD_PRESET_PS2_PIPE { 0, 9, 0, 0, 0, 0, 0, 0.0f, 0.0f, 0.0f, 0, 0.000f, { 0.0f,0.0f,0.0f }, 0, 0.000f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.00f, 0.000f, 0.0f, 0000.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0x31f } +/* [DEFINE_END] */ + + +/* +[STRUCTURE] +[ + [DESCRIPTION] + Structure defining the properties for a reverb source, related to a FMOD channel. + + For more indepth descriptions of the reverb properties under win32, please see the EAX3 + documentation at http://developer.creative.com/ under the 'downloads' section. + If they do not have the EAX3 documentation, then most information can be attained from + the EAX2 documentation, as EAX3 only adds some more parameters and functionality on top of + EAX2. + + Note the default reverb properties are the same as the FMOD_PRESET_GENERIC preset. + Note that integer values that typically range from -10,000 to 1000 are represented in + decibels, and are of a logarithmic scale, not linear, wheras float values are typically linear. + PORTABILITY: Each member has the platform it supports in braces ie (win32/Xbox). + Some reverb parameters are only supported in win32 and some only on Xbox. If all parameters are set then + the reverb should product a similar effect on either platform. + + The numerical values listed below are the maximum, minimum and default values for each variable respectively. + + [REMARKS] + SUPPORTED next to each parameter means the platform the parameter can be set on. Some platforms support all parameters and some don't. + EAX means hardware reverb on FMOD_OUTPUTTYPE_DSOUND on windows only (must use FMOD_HARDWARE), on soundcards that support EAX 1 to 4. + EAX4 means hardware reverb on FMOD_OUTPUTTYPE_DSOUND on windows only (must use FMOD_HARDWARE), on soundcards that support EAX 4. + I3DL2 means hardware reverb on FMOD_OUTPUTTYPE_DSOUND on windows only (must use FMOD_HARDWARE), on soundcards that support I3DL2 non EAX native reverb. + WII means Nintendo Wii hardware reverb (must use FMOD_HARDWARE). + PS2 means Playstation 2 hardware reverb (must use FMOD_HARDWARE). + SFX means FMOD SFX software reverb. This works on any platform that uses FMOD_SOFTWARE for loading sounds. + + + 'ConnectionPoint' Parameter. This parameter is for the FMOD software reverb only (known as SFX in the list above). + By default the dsp network connection for a channel and its reverb is between the 'SFX Reverb' unit, and the channel's wavetable/resampler/dspcodec/oscillator unit (the unit below the channel DSP head). NULL can be used for this parameter to make it use this default behaviour. + This parameter allows the user to connect the SFX reverb to somewhere else internally, for example the channel DSP head, or a related channelgroup. The event system uses this so that it can have the output of an event going to the reverb, instead of just the output of the event's channels (thereby ignoring event effects/submixes etc). + Do not use if you are unaware of DSP network connection issues. Leave it at the default of NULL instead. + + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation 2, PlayStation Portable, PlayStation 3, Wii, Solaris, iPhone + + [SEE_ALSO] + Channel::setReverbProperties + Channel::getReverbProperties + FMOD_REVERB_CHANNELFLAGS +] +*/ +typedef struct FMOD_REVERB_CHANNELPROPERTIES +{ /* MIN MAX DEFAULT DESCRIPTION */ + int Direct; /* [in/out] -10000, 1000, 0, direct path level (at low and mid frequencies) (SUPPORTED:EAX/I3DL2/SFX) */ + int DirectHF; /* [in/out] -10000, 0, 0, relative direct path level at high frequencies (SUPPORTED:EAX/I3DL2) */ + int Room; /* [in/out] -10000, 1000, 0, room effect level (at low and mid frequencies) (SUPPORTED:EAX/I3DL2/SFX) */ + int RoomHF; /* [in/out] -10000, 0, 0, relative room effect level at high frequencies (SUPPORTED:EAX/I3DL2) */ + int Obstruction; /* [in/out] -10000, 0, 0, main obstruction control (attenuation at high frequencies) (SUPPORTED:EAX/I3DL2) */ + float ObstructionLFRatio; /* [in/out] 0.0, 1.0, 0.0, obstruction low-frequency level re. main control (SUPPORTED:EAX/I3DL2) */ + int Occlusion; /* [in/out] -10000, 0, 0, main occlusion control (attenuation at high frequencies) (SUPPORTED:EAX/I3DL2) */ + float OcclusionLFRatio; /* [in/out] 0.0, 1.0, 0.25, occlusion low-frequency level re. main control (SUPPORTED:EAX/I3DL2) */ + float OcclusionRoomRatio; /* [in/out] 0.0, 10.0, 1.5, relative occlusion control for room effect (SUPPORTED:EAX only) */ + float OcclusionDirectRatio; /* [in/out] 0.0, 10.0, 1.0, relative occlusion control for direct path (SUPPORTED:EAX only) */ + int Exclusion; /* [in/out] -10000, 0, 0, main exlusion control (attenuation at high frequencies) (SUPPORTED:EAX only) */ + float ExclusionLFRatio; /* [in/out] 0.0, 1.0, 1.0, exclusion low-frequency level re. main control (SUPPORTED:EAX only) */ + int OutsideVolumeHF; /* [in/out] -10000, 0, 0, outside sound cone level at high frequencies (SUPPORTED:EAX only) */ + float DopplerFactor; /* [in/out] 0.0, 10.0, 0.0, like DS3D flDopplerFactor but per source (SUPPORTED:EAX only) */ + float RolloffFactor; /* [in/out] 0.0, 10.0, 0.0, like DS3D flRolloffFactor but per source (SUPPORTED:EAX only) */ + float RoomRolloffFactor; /* [in/out] 0.0, 10.0, 0.0, like DS3D flRolloffFactor but for room effect (SUPPORTED:EAX/I3DL2) */ + float AirAbsorptionFactor; /* [in/out] 0.0, 10.0, 1.0, multiplies AirAbsorptionHF member of FMOD_REVERB_PROPERTIES (SUPPORTED:EAX only) */ + unsigned int Flags; /* [in/out] FMOD_REVERB_CHANNELFLAGS - modifies the behavior of properties (SUPPORTED:EAX/SFX) */ + FMOD_DSP *ConnectionPoint; /* [in/out] See remarks. DSP network location to connect reverb for this channel. (SUPPORTED:SFX only).*/ +} FMOD_REVERB_CHANNELPROPERTIES; + + +/* +[DEFINE] +[ + [NAME] + FMOD_REVERB_CHANNELFLAGS + + [DESCRIPTION] + Values for the Flags member of the FMOD_REVERB_CHANNELPROPERTIES structure. + + [REMARKS] + For EAX4,EAX5 and SFX, there is support for multiple reverb environments. + Use FMOD_REVERB_CHANNELFLAGS_ENVIRONMENT0 to FMOD_REVERB_CHANNELFLAGS_ENVIRONMENT3 in the flags member + of FMOD_REVERB_CHANNELPROPERTIES to specify which environment instance(s) to target. + - If you do not specify any instance the first reverb instance will be used. + - If you specify more than one instance with getReverbProperties, the first instance will be used. + - If you specify more than one instance with setReverbProperties, it will set more than 1 instance at once. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation 2, PlayStation Portable, PlayStation 3, Wii, Solaris, iPhone + + [SEE_ALSO] + FMOD_REVERB_CHANNELPROPERTIES +] +*/ +#define FMOD_REVERB_CHANNELFLAGS_DIRECTHFAUTO 0x00000001 /* Automatic setting of 'Direct' due to distance from listener */ +#define FMOD_REVERB_CHANNELFLAGS_ROOMAUTO 0x00000002 /* Automatic setting of 'Room' due to distance from listener */ +#define FMOD_REVERB_CHANNELFLAGS_ROOMHFAUTO 0x00000004 /* Automatic setting of 'RoomHF' due to distance from listener */ +#define FMOD_REVERB_CHANNELFLAGS_INSTANCE0 0x00000010 /* EAX4/SFX/GameCube/Wii. Specify channel to target reverb instance 0. Default target. */ +#define FMOD_REVERB_CHANNELFLAGS_INSTANCE1 0x00000020 /* EAX4/SFX/GameCube/Wii. Specify channel to target reverb instance 1. */ +#define FMOD_REVERB_CHANNELFLAGS_INSTANCE2 0x00000040 /* EAX4/SFX/GameCube/Wii. Specify channel to target reverb instance 2. */ +#define FMOD_REVERB_CHANNELFLAGS_INSTANCE3 0x00000080 /* EAX5/SFX. Specify channel to target reverb instance 3. */ + +#define FMOD_REVERB_CHANNELFLAGS_DEFAULT (FMOD_REVERB_CHANNELFLAGS_DIRECTHFAUTO | \ + FMOD_REVERB_CHANNELFLAGS_ROOMAUTO| \ + FMOD_REVERB_CHANNELFLAGS_ROOMHFAUTO| \ + FMOD_REVERB_CHANNELFLAGS_INSTANCE0) +/* [DEFINE_END] */ + + +/* +[STRUCTURE] +[ + [DESCRIPTION] + Settings for advanced features like configuring memory and cpu usage for the FMOD_CREATECOMPRESSEDSAMPLE feature. + + [REMARKS] + maxMPEGcodecs / maxADPCMcodecs / maxXMAcodecs will determine the maximum cpu usage of playing realtime samples. Use this to lower potential excess cpu usage and also control memory usage. + + maxPCMcodecs is for use with PS3 only. It will determine the maximum number of PCM voices that can be played at once. This includes streams of any format and all sounds created + *without* the FMOD_CREATECOMPRESSEDSAMPLE flag. + + Memory will be allocated for codecs 'up front' (during System::init) if these values are specified as non zero. If any are zero, it allocates memory for the codec whenever a file of the type in question is loaded. So if maxMPEGcodecs is 0 for example, it will allocate memory for the mpeg codecs the first time an mp3 is loaded or an mp3 based .FSB file is loaded. + + Due to inefficient encoding techniques on certain .wav based ADPCM files, FMOD can can need an extra 29720 bytes per codec. This means for lowest memory consumption. Use FSB as it uses an optimal/small ADPCM block size. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation 2, PlayStation Portable, PlayStation 3, Wii, Solaris, iPhone + + [SEE_ALSO] + System::setAdvancedSettings + System::getAdvancedSettings + System::init + FMOD_MODE +] +*/ +typedef struct FMOD_ADVANCEDSETTINGS +{ + int cbsize; /* [in] Size of this structure. Use sizeof(FMOD_ADVANCEDSETTINGS) NOTE: This must be set before calling System::getAdvancedSettings! */ + int maxMPEGcodecs; /* [in/out] Optional. Specify 0 to ignore. For use with FMOD_CREATECOMPRESSEDSAMPLE only. Mpeg codecs consume 21,684 bytes per instance and this number will determine how many mpeg channels can be played simultaneously. Default = 16. */ + int maxADPCMcodecs; /* [in/out] Optional. Specify 0 to ignore. For use with FMOD_CREATECOMPRESSEDSAMPLE only. ADPCM codecs consume 2,136 bytes per instance (based on FSB encoded ADPCM block size - see remarks) and this number will determine how many ADPCM channels can be played simultaneously. Default = 32. */ + int maxXMAcodecs; /* [in/out] Optional. Specify 0 to ignore. For use with FMOD_CREATECOMPRESSEDSAMPLE only. XMA codecs consume 14,836 bytes per instance and this number will determine how many XMA channels can be played simultaneously. Default = 32. */ + int maxCELTcodecs; /* [in/out] Optional. Specify 0 to ignore. For use with FMOD_CREATECOMPRESSEDSAMPLE only. CELT codecs consume 11,500 bytes per instance and this number will determine how many CELT channels can be played simultaneously. Default = 16 */ + int maxPCMcodecs; /* [in/out] Optional. Specify 0 to ignore. For use with PS3 only. PCM codecs consume 12,672 bytes per instance and this number will determine how many streams and PCM voices can be played simultaneously. Default = 16 */ + int ASIONumChannels; /* [in/out] Optional. Specify 0 to ignore. Number of channels available on the ASIO device. */ + char **ASIOChannelList; /* [in/out] Optional. Specify 0 to ignore. Pointer to an array of strings (number of entries defined by ASIONumChannels) with ASIO channel names. */ + FMOD_SPEAKER *ASIOSpeakerList; /* [in/out] Optional. Specify 0 to ignore. Pointer to a list of speakers that the ASIO channels map to. This can be called after System::init to remap ASIO output. */ + int max3DReverbDSPs; /* [in/out] Optional. Specify 0 to ignore. The max number of 3d reverb DSP's in the system. (NOTE: CURRENTLY DISABLED / UNUSED) */ + float HRTFMinAngle; /* [in/out] Optional. Specify 0 to ignore. For use with FMOD_INIT_SOFTWARE_HRTF. The angle range (0-360) of a 3D sound in relation to the listener, at which the HRTF function begins to have an effect. 0 = in front of the listener. 180 = from 90 degrees to the left of the listener to 90 degrees to the right. 360 = behind the listener. Default = 180.0. */ + float HRTFMaxAngle; /* [in/out] Optional. Specify 0 to ignore. For use with FMOD_INIT_SOFTWARE_HRTF. The angle range (0-360) of a 3D sound in relation to the listener, at which the HRTF function has maximum effect. 0 = front of the listener. 180 = from 90 degrees to the left of the listener to 90 degrees to the right. 360 = behind the listener. Default = 360.0. */ + float HRTFFreq; /* [in/out] Optional. Specify 0 to ignore. For use with FMOD_INIT_SOFTWARE_HRTF. The cutoff frequency of the HRTF's lowpass filter function when at maximum effect. (i.e. at HRTFMaxAngle). Default = 4000.0. */ + float vol0virtualvol; /* [in/out] Optional. Specify 0 to ignore. For use with FMOD_INIT_VOL0_BECOMES_VIRTUAL. If this flag is used, and the volume is 0.0, then the sound will become virtual. Use this value to raise the threshold to a different point where a sound goes virtual. */ + int eventqueuesize; /* [in/out] Optional. Specify 0 to ignore. For use with FMOD Event system only. Specifies the number of slots available for simultaneous non blocking loads. Default = 32. */ + unsigned int defaultDecodeBufferSize; /* [in/out] Optional. Specify 0 to ignore. For streams. This determines the default size of the double buffer (in milliseconds) that a stream uses. Default = 400ms */ + char *debugLogFilename; /* [in/out] Optional. Specify 0 to ignore. Gives fmod's logging system a path/filename. Normally the log is placed in the same directory as the executable and called fmod.log. When using System::getAdvancedSettings, provide at least 256 bytes of memory to copy into. */ + unsigned short profileport; /* [in/out] Optional. Specify 0 to ignore. For use with FMOD_INIT_ENABLE_PROFILE. Specify the port to listen on for connections by the profiler application. */ + unsigned int geometryMaxFadeTime; /* [in/out] Optional. Specify 0 to ignore. The maximum time in miliseconds it takes for a channel to fade to the new level when its occlusion changes. */ + unsigned int maxSpectrumWaveDataBuffers; /* [in/out] Optional. Specify 0 to ignore. Tells System::init to allocate a pool of wavedata/spectrum buffers to prevent memory fragmentation, any additional buffers will be allocated normally. */ +} FMOD_ADVANCEDSETTINGS; + + +/* +[ENUM] +[ + [DESCRIPTION] + Special channel index values for FMOD functions. + + [REMARKS] + To get 'all' of the channels, use System::getMasterChannelGroup. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation 2, PlayStation Portable, PlayStation 3, Wii, Solaris, iPhone + + [SEE_ALSO] + System::playSound + System::playDSP + System::getChannel + System::getMasterChannelGroup +] +*/ +typedef enum +{ + FMOD_CHANNEL_FREE = -1, /* For a channel index, FMOD chooses a free voice using the priority system. */ + FMOD_CHANNEL_REUSE = -2 /* For a channel index, re-use the channel handle that was passed in. */ +} FMOD_CHANNELINDEX; + +#include "fmod_codec.h" +#include "fmod_dsp.h" +#include "fmod_memoryinfo.h" + +/* ========================================================================================== */ +/* FUNCTION PROTOTYPES */ +/* ========================================================================================== */ + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* + FMOD global system functions (optional). +*/ + +FMOD_RESULT F_API FMOD_Memory_Initialize (void *poolmem, int poollen, FMOD_MEMORY_ALLOCCALLBACK useralloc, FMOD_MEMORY_REALLOCCALLBACK userrealloc, FMOD_MEMORY_FREECALLBACK userfree, FMOD_MEMORY_TYPE memtypeflags); +FMOD_RESULT F_API FMOD_Memory_GetStats (int *currentalloced, int *maxalloced, FMOD_BOOL blocking); +FMOD_RESULT F_API FMOD_Debug_SetLevel (FMOD_DEBUGLEVEL level); +FMOD_RESULT F_API FMOD_Debug_GetLevel (FMOD_DEBUGLEVEL *level); +FMOD_RESULT F_API FMOD_File_SetDiskBusy (int busy); +FMOD_RESULT F_API FMOD_File_GetDiskBusy (int *busy); + +/* + FMOD System factory functions. Use this to create an FMOD System Instance. below you will see FMOD_System_Init/Close to get started. +*/ + +FMOD_RESULT F_API FMOD_System_Create (FMOD_SYSTEM **system); +FMOD_RESULT F_API FMOD_System_Release (FMOD_SYSTEM *system); + + +/* + 'System' API +*/ + +/* + Pre-init functions. +*/ + +FMOD_RESULT F_API FMOD_System_SetOutput (FMOD_SYSTEM *system, FMOD_OUTPUTTYPE output); +FMOD_RESULT F_API FMOD_System_GetOutput (FMOD_SYSTEM *system, FMOD_OUTPUTTYPE *output); +FMOD_RESULT F_API FMOD_System_GetNumDrivers (FMOD_SYSTEM *system, int *numdrivers); +FMOD_RESULT F_API FMOD_System_GetDriverInfo (FMOD_SYSTEM *system, int id, char *name, int namelen, FMOD_GUID *guid); +FMOD_RESULT F_API FMOD_System_GetDriverInfoW (FMOD_SYSTEM *system, int id, short *name, int namelen, FMOD_GUID *guid); +FMOD_RESULT F_API FMOD_System_GetDriverCaps (FMOD_SYSTEM *system, int id, FMOD_CAPS *caps, int *minfrequency, int *maxfrequency, FMOD_SPEAKERMODE *controlpanelspeakermode); +FMOD_RESULT F_API FMOD_System_SetDriver (FMOD_SYSTEM *system, int driver); +FMOD_RESULT F_API FMOD_System_GetDriver (FMOD_SYSTEM *system, int *driver); +FMOD_RESULT F_API FMOD_System_SetHardwareChannels (FMOD_SYSTEM *system, int min2d, int max2d, int min3d, int max3d); +FMOD_RESULT F_API FMOD_System_SetSoftwareChannels (FMOD_SYSTEM *system, int numsoftwarechannels); +FMOD_RESULT F_API FMOD_System_GetSoftwareChannels (FMOD_SYSTEM *system, int *numsoftwarechannels); +FMOD_RESULT F_API FMOD_System_SetSoftwareFormat (FMOD_SYSTEM *system, int samplerate, FMOD_SOUND_FORMAT format, int numoutputchannels, int maxinputchannels, FMOD_DSP_RESAMPLER resamplemethod); +FMOD_RESULT F_API FMOD_System_GetSoftwareFormat (FMOD_SYSTEM *system, int *samplerate, FMOD_SOUND_FORMAT *format, int *numoutputchannels, int *maxinputchannels, FMOD_DSP_RESAMPLER *resamplemethod, int *bits); +FMOD_RESULT F_API FMOD_System_SetDSPBufferSize (FMOD_SYSTEM *system, unsigned int bufferlength, int numbuffers); +FMOD_RESULT F_API FMOD_System_GetDSPBufferSize (FMOD_SYSTEM *system, unsigned int *bufferlength, int *numbuffers); +FMOD_RESULT F_API FMOD_System_SetFileSystem (FMOD_SYSTEM *system, FMOD_FILE_OPENCALLBACK useropen, FMOD_FILE_CLOSECALLBACK userclose, FMOD_FILE_READCALLBACK userread, FMOD_FILE_SEEKCALLBACK userseek, int blockalign); +FMOD_RESULT F_API FMOD_System_AttachFileSystem (FMOD_SYSTEM *system, FMOD_FILE_OPENCALLBACK useropen, FMOD_FILE_CLOSECALLBACK userclose, FMOD_FILE_READCALLBACK userread, FMOD_FILE_SEEKCALLBACK userseek); +FMOD_RESULT F_API FMOD_System_SetAdvancedSettings (FMOD_SYSTEM *system, FMOD_ADVANCEDSETTINGS *settings); +FMOD_RESULT F_API FMOD_System_GetAdvancedSettings (FMOD_SYSTEM *system, FMOD_ADVANCEDSETTINGS *settings); +FMOD_RESULT F_API FMOD_System_SetSpeakerMode (FMOD_SYSTEM *system, FMOD_SPEAKERMODE speakermode); +FMOD_RESULT F_API FMOD_System_GetSpeakerMode (FMOD_SYSTEM *system, FMOD_SPEAKERMODE *speakermode); +FMOD_RESULT F_API FMOD_System_SetCallback (FMOD_SYSTEM *system, FMOD_SYSTEM_CALLBACK callback); + +/* + Plug-in support +*/ + +FMOD_RESULT F_API FMOD_System_SetPluginPath (FMOD_SYSTEM *system, const char *path); +FMOD_RESULT F_API FMOD_System_LoadPlugin (FMOD_SYSTEM *system, const char *filename, unsigned int *handle, unsigned int priority); +FMOD_RESULT F_API FMOD_System_UnloadPlugin (FMOD_SYSTEM *system, unsigned int handle); +FMOD_RESULT F_API FMOD_System_GetNumPlugins (FMOD_SYSTEM *system, FMOD_PLUGINTYPE plugintype, int *numplugins); +FMOD_RESULT F_API FMOD_System_GetPluginHandle (FMOD_SYSTEM *system, FMOD_PLUGINTYPE plugintype, int index, unsigned int *handle); +FMOD_RESULT F_API FMOD_System_GetPluginInfo (FMOD_SYSTEM *system, unsigned int handle, FMOD_PLUGINTYPE *plugintype, char *name, int namelen, unsigned int *version); +FMOD_RESULT F_API FMOD_System_SetOutputByPlugin (FMOD_SYSTEM *system, unsigned int handle); +FMOD_RESULT F_API FMOD_System_GetOutputByPlugin (FMOD_SYSTEM *system, unsigned int *handle); +FMOD_RESULT F_API FMOD_System_CreateDSPByPlugin (FMOD_SYSTEM *system, unsigned int handle, FMOD_DSP **dsp); +FMOD_RESULT F_API FMOD_System_CreateCodec (FMOD_SYSTEM *system, FMOD_CODEC_DESCRIPTION *description, unsigned int priority); + +/* + Init/Close +*/ + +FMOD_RESULT F_API FMOD_System_Init (FMOD_SYSTEM *system, int maxchannels, FMOD_INITFLAGS flags, void *extradriverdata); +FMOD_RESULT F_API FMOD_System_Close (FMOD_SYSTEM *system); + +/* + General post-init system functions +*/ + +FMOD_RESULT F_API FMOD_System_Update (FMOD_SYSTEM *system); + +FMOD_RESULT F_API FMOD_System_Set3DSettings (FMOD_SYSTEM *system, float dopplerscale, float distancefactor, float rolloffscale); +FMOD_RESULT F_API FMOD_System_Get3DSettings (FMOD_SYSTEM *system, float *dopplerscale, float *distancefactor, float *rolloffscale); +FMOD_RESULT F_API FMOD_System_Set3DNumListeners (FMOD_SYSTEM *system, int numlisteners); +FMOD_RESULT F_API FMOD_System_Get3DNumListeners (FMOD_SYSTEM *system, int *numlisteners); +FMOD_RESULT F_API FMOD_System_Set3DListenerAttributes(FMOD_SYSTEM *system, int listener, const FMOD_VECTOR *pos, const FMOD_VECTOR *vel, const FMOD_VECTOR *forward, const FMOD_VECTOR *up); +FMOD_RESULT F_API FMOD_System_Get3DListenerAttributes(FMOD_SYSTEM *system, int listener, FMOD_VECTOR *pos, FMOD_VECTOR *vel, FMOD_VECTOR *forward, FMOD_VECTOR *up); +FMOD_RESULT F_API FMOD_System_Set3DRolloffCallback (FMOD_SYSTEM *system, FMOD_3D_ROLLOFFCALLBACK callback); +FMOD_RESULT F_API FMOD_System_Set3DSpeakerPosition (FMOD_SYSTEM *system, FMOD_SPEAKER speaker, float x, float y, FMOD_BOOL active); +FMOD_RESULT F_API FMOD_System_Get3DSpeakerPosition (FMOD_SYSTEM *system, FMOD_SPEAKER speaker, float *x, float *y, FMOD_BOOL *active); + +FMOD_RESULT F_API FMOD_System_SetStreamBufferSize (FMOD_SYSTEM *system, unsigned int filebuffersize, FMOD_TIMEUNIT filebuffersizetype); +FMOD_RESULT F_API FMOD_System_GetStreamBufferSize (FMOD_SYSTEM *system, unsigned int *filebuffersize, FMOD_TIMEUNIT *filebuffersizetype); + +/* + System information functions. +*/ + +FMOD_RESULT F_API FMOD_System_GetVersion (FMOD_SYSTEM *system, unsigned int *version); +FMOD_RESULT F_API FMOD_System_GetOutputHandle (FMOD_SYSTEM *system, void **handle); +FMOD_RESULT F_API FMOD_System_GetChannelsPlaying (FMOD_SYSTEM *system, int *channels); +FMOD_RESULT F_API FMOD_System_GetHardwareChannels (FMOD_SYSTEM *system, int *num2d, int *num3d, int *total); +FMOD_RESULT F_API FMOD_System_GetCPUUsage (FMOD_SYSTEM *system, float *dsp, float *stream, float *geometry, float *update, float *total); +FMOD_RESULT F_API FMOD_System_GetSoundRAM (FMOD_SYSTEM *system, int *currentalloced, int *maxalloced, int *total); +FMOD_RESULT F_API FMOD_System_GetNumCDROMDrives (FMOD_SYSTEM *system, int *numdrives); +FMOD_RESULT F_API FMOD_System_GetCDROMDriveName (FMOD_SYSTEM *system, int drive, char *drivename, int drivenamelen, char *scsiname, int scsinamelen, char *devicename, int devicenamelen); +FMOD_RESULT F_API FMOD_System_GetSpectrum (FMOD_SYSTEM *system, float *spectrumarray, int numvalues, int channeloffset, FMOD_DSP_FFT_WINDOW windowtype); +FMOD_RESULT F_API FMOD_System_GetWaveData (FMOD_SYSTEM *system, float *wavearray, int numvalues, int channeloffset); + +/* + Sound/DSP/Channel/FX creation and retrieval. +*/ + +FMOD_RESULT F_API FMOD_System_CreateSound (FMOD_SYSTEM *system, const char *name_or_data, FMOD_MODE mode, FMOD_CREATESOUNDEXINFO *exinfo, FMOD_SOUND **sound); +FMOD_RESULT F_API FMOD_System_CreateStream (FMOD_SYSTEM *system, const char *name_or_data, FMOD_MODE mode, FMOD_CREATESOUNDEXINFO *exinfo, FMOD_SOUND **sound); +FMOD_RESULT F_API FMOD_System_CreateDSP (FMOD_SYSTEM *system, FMOD_DSP_DESCRIPTION *description, FMOD_DSP **dsp); +FMOD_RESULT F_API FMOD_System_CreateDSPByType (FMOD_SYSTEM *system, FMOD_DSP_TYPE type, FMOD_DSP **dsp); +FMOD_RESULT F_API FMOD_System_CreateChannelGroup (FMOD_SYSTEM *system, const char *name, FMOD_CHANNELGROUP **channelgroup); +FMOD_RESULT F_API FMOD_System_CreateSoundGroup (FMOD_SYSTEM *system, const char *name, FMOD_SOUNDGROUP **soundgroup); +FMOD_RESULT F_API FMOD_System_CreateReverb (FMOD_SYSTEM *system, FMOD_REVERB **reverb); + +FMOD_RESULT F_API FMOD_System_PlaySound (FMOD_SYSTEM *system, FMOD_CHANNELINDEX channelid, FMOD_SOUND *sound, FMOD_BOOL paused, FMOD_CHANNEL **channel); +FMOD_RESULT F_API FMOD_System_PlayDSP (FMOD_SYSTEM *system, FMOD_CHANNELINDEX channelid, FMOD_DSP *dsp, FMOD_BOOL paused, FMOD_CHANNEL **channel); +FMOD_RESULT F_API FMOD_System_GetChannel (FMOD_SYSTEM *system, int channelid, FMOD_CHANNEL **channel); +FMOD_RESULT F_API FMOD_System_GetMasterChannelGroup (FMOD_SYSTEM *system, FMOD_CHANNELGROUP **channelgroup); +FMOD_RESULT F_API FMOD_System_GetMasterSoundGroup (FMOD_SYSTEM *system, FMOD_SOUNDGROUP **soundgroup); + +/* + Reverb API +*/ + +FMOD_RESULT F_API FMOD_System_SetReverbProperties (FMOD_SYSTEM *system, const FMOD_REVERB_PROPERTIES *prop); +FMOD_RESULT F_API FMOD_System_GetReverbProperties (FMOD_SYSTEM *system, FMOD_REVERB_PROPERTIES *prop); +FMOD_RESULT F_API FMOD_System_SetReverbAmbientProperties(FMOD_SYSTEM *system, FMOD_REVERB_PROPERTIES *prop); +FMOD_RESULT F_API FMOD_System_GetReverbAmbientProperties(FMOD_SYSTEM *system, FMOD_REVERB_PROPERTIES *prop); + +/* + System level DSP access. +*/ + +FMOD_RESULT F_API FMOD_System_GetDSPHead (FMOD_SYSTEM *system, FMOD_DSP **dsp); +FMOD_RESULT F_API FMOD_System_AddDSP (FMOD_SYSTEM *system, FMOD_DSP *dsp, FMOD_DSPCONNECTION **connection); +FMOD_RESULT F_API FMOD_System_LockDSP (FMOD_SYSTEM *system); +FMOD_RESULT F_API FMOD_System_UnlockDSP (FMOD_SYSTEM *system); +FMOD_RESULT F_API FMOD_System_GetDSPClock (FMOD_SYSTEM *system, unsigned int *hi, unsigned int *lo); + +/* + Recording API. +*/ + +FMOD_RESULT F_API FMOD_System_GetRecordNumDrivers (FMOD_SYSTEM *system, int *numdrivers); +FMOD_RESULT F_API FMOD_System_GetRecordDriverInfo (FMOD_SYSTEM *system, int id, char *name, int namelen, FMOD_GUID *guid); +FMOD_RESULT F_API FMOD_System_GetRecordDriverInfoW (FMOD_SYSTEM *system, int id, short *name, int namelen, FMOD_GUID *guid); +FMOD_RESULT F_API FMOD_System_GetRecordDriverCaps (FMOD_SYSTEM *system, int id, FMOD_CAPS *caps, int *minfrequency, int *maxfrequency); +FMOD_RESULT F_API FMOD_System_GetRecordPosition (FMOD_SYSTEM *system, int id, unsigned int *position); + +FMOD_RESULT F_API FMOD_System_RecordStart (FMOD_SYSTEM *system, int id, FMOD_SOUND *sound, FMOD_BOOL loop); +FMOD_RESULT F_API FMOD_System_RecordStop (FMOD_SYSTEM *system, int id); +FMOD_RESULT F_API FMOD_System_IsRecording (FMOD_SYSTEM *system, int id, FMOD_BOOL *recording); + +/* + Geometry API. +*/ + +FMOD_RESULT F_API FMOD_System_CreateGeometry (FMOD_SYSTEM *system, int maxpolygons, int maxvertices, FMOD_GEOMETRY **geometry); +FMOD_RESULT F_API FMOD_System_SetGeometrySettings (FMOD_SYSTEM *system, float maxworldsize); +FMOD_RESULT F_API FMOD_System_GetGeometrySettings (FMOD_SYSTEM *system, float *maxworldsize); +FMOD_RESULT F_API FMOD_System_LoadGeometry (FMOD_SYSTEM *system, const void *data, int datasize, FMOD_GEOMETRY **geometry); +FMOD_RESULT F_API FMOD_System_GetGeometryOcclusion (FMOD_SYSTEM *system, const FMOD_VECTOR *listener, const FMOD_VECTOR *source, float *direct, float *reverb); + +/* + Network functions. +*/ + +FMOD_RESULT F_API FMOD_System_SetNetworkProxy (FMOD_SYSTEM *system, const char *proxy); +FMOD_RESULT F_API FMOD_System_GetNetworkProxy (FMOD_SYSTEM *system, char *proxy, int proxylen); +FMOD_RESULT F_API FMOD_System_SetNetworkTimeout (FMOD_SYSTEM *system, int timeout); +FMOD_RESULT F_API FMOD_System_GetNetworkTimeout (FMOD_SYSTEM *system, int *timeout); + +/* + Userdata set/get. +*/ + +FMOD_RESULT F_API FMOD_System_SetUserData (FMOD_SYSTEM *system, void *userdata); +FMOD_RESULT F_API FMOD_System_GetUserData (FMOD_SYSTEM *system, void **userdata); + +FMOD_RESULT F_API FMOD_System_GetMemoryInfo (FMOD_SYSTEM *system, unsigned int memorybits, unsigned int event_memorybits, unsigned int *memoryused, FMOD_MEMORY_USAGE_DETAILS *memoryused_details); + +/* + 'Sound' API +*/ + +FMOD_RESULT F_API FMOD_Sound_Release (FMOD_SOUND *sound); +FMOD_RESULT F_API FMOD_Sound_GetSystemObject (FMOD_SOUND *sound, FMOD_SYSTEM **system); + +/* + Standard sound manipulation functions. +*/ + +FMOD_RESULT F_API FMOD_Sound_Lock (FMOD_SOUND *sound, unsigned int offset, unsigned int length, void **ptr1, void **ptr2, unsigned int *len1, unsigned int *len2); +FMOD_RESULT F_API FMOD_Sound_Unlock (FMOD_SOUND *sound, void *ptr1, void *ptr2, unsigned int len1, unsigned int len2); +FMOD_RESULT F_API FMOD_Sound_SetDefaults (FMOD_SOUND *sound, float frequency, float volume, float pan, int priority); +FMOD_RESULT F_API FMOD_Sound_GetDefaults (FMOD_SOUND *sound, float *frequency, float *volume, float *pan, int *priority); +FMOD_RESULT F_API FMOD_Sound_SetVariations (FMOD_SOUND *sound, float frequencyvar, float volumevar, float panvar); +FMOD_RESULT F_API FMOD_Sound_GetVariations (FMOD_SOUND *sound, float *frequencyvar, float *volumevar, float *panvar); +FMOD_RESULT F_API FMOD_Sound_Set3DMinMaxDistance (FMOD_SOUND *sound, float min, float max); +FMOD_RESULT F_API FMOD_Sound_Get3DMinMaxDistance (FMOD_SOUND *sound, float *min, float *max); +FMOD_RESULT F_API FMOD_Sound_Set3DConeSettings (FMOD_SOUND *sound, float insideconeangle, float outsideconeangle, float outsidevolume); +FMOD_RESULT F_API FMOD_Sound_Get3DConeSettings (FMOD_SOUND *sound, float *insideconeangle, float *outsideconeangle, float *outsidevolume); +FMOD_RESULT F_API FMOD_Sound_Set3DCustomRolloff (FMOD_SOUND *sound, FMOD_VECTOR *points, int numpoints); +FMOD_RESULT F_API FMOD_Sound_Get3DCustomRolloff (FMOD_SOUND *sound, FMOD_VECTOR **points, int *numpoints); +FMOD_RESULT F_API FMOD_Sound_SetSubSound (FMOD_SOUND *sound, int index, FMOD_SOUND *subsound); +FMOD_RESULT F_API FMOD_Sound_GetSubSound (FMOD_SOUND *sound, int index, FMOD_SOUND **subsound); +FMOD_RESULT F_API FMOD_Sound_SetSubSoundSentence (FMOD_SOUND *sound, int *subsoundlist, int numsubsounds); +FMOD_RESULT F_API FMOD_Sound_GetName (FMOD_SOUND *sound, char *name, int namelen); +FMOD_RESULT F_API FMOD_Sound_GetLength (FMOD_SOUND *sound, unsigned int *length, FMOD_TIMEUNIT lengthtype); +FMOD_RESULT F_API FMOD_Sound_GetFormat (FMOD_SOUND *sound, FMOD_SOUND_TYPE *type, FMOD_SOUND_FORMAT *format, int *channels, int *bits); +FMOD_RESULT F_API FMOD_Sound_GetNumSubSounds (FMOD_SOUND *sound, int *numsubsounds); +FMOD_RESULT F_API FMOD_Sound_GetNumTags (FMOD_SOUND *sound, int *numtags, int *numtagsupdated); +FMOD_RESULT F_API FMOD_Sound_GetTag (FMOD_SOUND *sound, const char *name, int index, FMOD_TAG *tag); +FMOD_RESULT F_API FMOD_Sound_GetOpenState (FMOD_SOUND *sound, FMOD_OPENSTATE *openstate, unsigned int *percentbuffered, FMOD_BOOL *starving); +FMOD_RESULT F_API FMOD_Sound_ReadData (FMOD_SOUND *sound, void *buffer, unsigned int lenbytes, unsigned int *read); +FMOD_RESULT F_API FMOD_Sound_SeekData (FMOD_SOUND *sound, unsigned int pcm); + +FMOD_RESULT F_API FMOD_Sound_SetSoundGroup (FMOD_SOUND *sound, FMOD_SOUNDGROUP *soundgroup); +FMOD_RESULT F_API FMOD_Sound_GetSoundGroup (FMOD_SOUND *sound, FMOD_SOUNDGROUP **soundgroup); + +/* + Synchronization point API. These points can come from markers embedded in wav files, and can also generate channel callbacks. +*/ + +FMOD_RESULT F_API FMOD_Sound_GetNumSyncPoints (FMOD_SOUND *sound, int *numsyncpoints); +FMOD_RESULT F_API FMOD_Sound_GetSyncPoint (FMOD_SOUND *sound, int index, FMOD_SYNCPOINT **point); +FMOD_RESULT F_API FMOD_Sound_GetSyncPointInfo (FMOD_SOUND *sound, FMOD_SYNCPOINT *point, char *name, int namelen, unsigned int *offset, FMOD_TIMEUNIT offsettype); +FMOD_RESULT F_API FMOD_Sound_AddSyncPoint (FMOD_SOUND *sound, unsigned int offset, FMOD_TIMEUNIT offsettype, const char *name, FMOD_SYNCPOINT **point); +FMOD_RESULT F_API FMOD_Sound_DeleteSyncPoint (FMOD_SOUND *sound, FMOD_SYNCPOINT *point); + +/* + Functions also in Channel class but here they are the 'default' to save having to change it in Channel all the time. +*/ + +FMOD_RESULT F_API FMOD_Sound_SetMode (FMOD_SOUND *sound, FMOD_MODE mode); +FMOD_RESULT F_API FMOD_Sound_GetMode (FMOD_SOUND *sound, FMOD_MODE *mode); +FMOD_RESULT F_API FMOD_Sound_SetLoopCount (FMOD_SOUND *sound, int loopcount); +FMOD_RESULT F_API FMOD_Sound_GetLoopCount (FMOD_SOUND *sound, int *loopcount); +FMOD_RESULT F_API FMOD_Sound_SetLoopPoints (FMOD_SOUND *sound, unsigned int loopstart, FMOD_TIMEUNIT loopstarttype, unsigned int loopend, FMOD_TIMEUNIT loopendtype); +FMOD_RESULT F_API FMOD_Sound_GetLoopPoints (FMOD_SOUND *sound, unsigned int *loopstart, FMOD_TIMEUNIT loopstarttype, unsigned int *loopend, FMOD_TIMEUNIT loopendtype); + +/* + For MOD/S3M/XM/IT/MID sequenced formats only. +*/ + +FMOD_RESULT F_API FMOD_Sound_GetMusicNumChannels (FMOD_SOUND *sound, int *numchannels); +FMOD_RESULT F_API FMOD_Sound_SetMusicChannelVolume (FMOD_SOUND *sound, int channel, float volume); +FMOD_RESULT F_API FMOD_Sound_GetMusicChannelVolume (FMOD_SOUND *sound, int channel, float *volume); + +/* + Userdata set/get. +*/ + +FMOD_RESULT F_API FMOD_Sound_SetUserData (FMOD_SOUND *sound, void *userdata); +FMOD_RESULT F_API FMOD_Sound_GetUserData (FMOD_SOUND *sound, void **userdata); + +FMOD_RESULT F_API FMOD_Sound_GetMemoryInfo (FMOD_SOUND *sound, unsigned int memorybits, unsigned int event_memorybits, unsigned int *memoryused, FMOD_MEMORY_USAGE_DETAILS *memoryused_details); + +/* + 'Channel' API +*/ + +FMOD_RESULT F_API FMOD_Channel_GetSystemObject (FMOD_CHANNEL *channel, FMOD_SYSTEM **system); + +FMOD_RESULT F_API FMOD_Channel_Stop (FMOD_CHANNEL *channel); +FMOD_RESULT F_API FMOD_Channel_SetPaused (FMOD_CHANNEL *channel, FMOD_BOOL paused); +FMOD_RESULT F_API FMOD_Channel_GetPaused (FMOD_CHANNEL *channel, FMOD_BOOL *paused); +FMOD_RESULT F_API FMOD_Channel_SetVolume (FMOD_CHANNEL *channel, float volume); +FMOD_RESULT F_API FMOD_Channel_GetVolume (FMOD_CHANNEL *channel, float *volume); +FMOD_RESULT F_API FMOD_Channel_SetFrequency (FMOD_CHANNEL *channel, float frequency); +FMOD_RESULT F_API FMOD_Channel_GetFrequency (FMOD_CHANNEL *channel, float *frequency); +FMOD_RESULT F_API FMOD_Channel_SetPan (FMOD_CHANNEL *channel, float pan); +FMOD_RESULT F_API FMOD_Channel_GetPan (FMOD_CHANNEL *channel, float *pan); +FMOD_RESULT F_API FMOD_Channel_SetDelay (FMOD_CHANNEL *channel, FMOD_DELAYTYPE delaytype, unsigned int delayhi, unsigned int delaylo); +FMOD_RESULT F_API FMOD_Channel_GetDelay (FMOD_CHANNEL *channel, FMOD_DELAYTYPE delaytype, unsigned int *delayhi, unsigned int *delaylo); +FMOD_RESULT F_API FMOD_Channel_SetSpeakerMix (FMOD_CHANNEL *channel, float frontleft, float frontright, float center, float lfe, float backleft, float backright, float sideleft, float sideright); +FMOD_RESULT F_API FMOD_Channel_GetSpeakerMix (FMOD_CHANNEL *channel, float *frontleft, float *frontright, float *center, float *lfe, float *backleft, float *backright, float *sideleft, float *sideright); +FMOD_RESULT F_API FMOD_Channel_SetSpeakerLevels (FMOD_CHANNEL *channel, FMOD_SPEAKER speaker, float *levels, int numlevels); +FMOD_RESULT F_API FMOD_Channel_GetSpeakerLevels (FMOD_CHANNEL *channel, FMOD_SPEAKER speaker, float *levels, int numlevels); +FMOD_RESULT F_API FMOD_Channel_SetInputChannelMix (FMOD_CHANNEL *channel, float *levels, int numlevels); +FMOD_RESULT F_API FMOD_Channel_GetInputChannelMix (FMOD_CHANNEL *channel, float *levels, int numlevels); +FMOD_RESULT F_API FMOD_Channel_SetMute (FMOD_CHANNEL *channel, FMOD_BOOL mute); +FMOD_RESULT F_API FMOD_Channel_GetMute (FMOD_CHANNEL *channel, FMOD_BOOL *mute); +FMOD_RESULT F_API FMOD_Channel_SetPriority (FMOD_CHANNEL *channel, int priority); +FMOD_RESULT F_API FMOD_Channel_GetPriority (FMOD_CHANNEL *channel, int *priority); +FMOD_RESULT F_API FMOD_Channel_SetPosition (FMOD_CHANNEL *channel, unsigned int position, FMOD_TIMEUNIT postype); +FMOD_RESULT F_API FMOD_Channel_GetPosition (FMOD_CHANNEL *channel, unsigned int *position, FMOD_TIMEUNIT postype); +FMOD_RESULT F_API FMOD_Channel_SetReverbProperties (FMOD_CHANNEL *channel, const FMOD_REVERB_CHANNELPROPERTIES *prop); +FMOD_RESULT F_API FMOD_Channel_GetReverbProperties (FMOD_CHANNEL *channel, FMOD_REVERB_CHANNELPROPERTIES *prop); +FMOD_RESULT F_API FMOD_Channel_SetLowPassGain (FMOD_CHANNEL *channel, float gain); +FMOD_RESULT F_API FMOD_Channel_GetLowPassGain (FMOD_CHANNEL *channel, float *gain); + +FMOD_RESULT F_API FMOD_Channel_SetChannelGroup (FMOD_CHANNEL *channel, FMOD_CHANNELGROUP *channelgroup); +FMOD_RESULT F_API FMOD_Channel_GetChannelGroup (FMOD_CHANNEL *channel, FMOD_CHANNELGROUP **channelgroup); +FMOD_RESULT F_API FMOD_Channel_SetCallback (FMOD_CHANNEL *channel, FMOD_CHANNEL_CALLBACK callback); + +/* + 3D functionality. +*/ + +FMOD_RESULT F_API FMOD_Channel_Set3DAttributes (FMOD_CHANNEL *channel, const FMOD_VECTOR *pos, const FMOD_VECTOR *vel); +FMOD_RESULT F_API FMOD_Channel_Get3DAttributes (FMOD_CHANNEL *channel, FMOD_VECTOR *pos, FMOD_VECTOR *vel); +FMOD_RESULT F_API FMOD_Channel_Set3DMinMaxDistance (FMOD_CHANNEL *channel, float mindistance, float maxdistance); +FMOD_RESULT F_API FMOD_Channel_Get3DMinMaxDistance (FMOD_CHANNEL *channel, float *mindistance, float *maxdistance); +FMOD_RESULT F_API FMOD_Channel_Set3DConeSettings (FMOD_CHANNEL *channel, float insideconeangle, float outsideconeangle, float outsidevolume); +FMOD_RESULT F_API FMOD_Channel_Get3DConeSettings (FMOD_CHANNEL *channel, float *insideconeangle, float *outsideconeangle, float *outsidevolume); +FMOD_RESULT F_API FMOD_Channel_Set3DConeOrientation (FMOD_CHANNEL *channel, FMOD_VECTOR *orientation); +FMOD_RESULT F_API FMOD_Channel_Get3DConeOrientation (FMOD_CHANNEL *channel, FMOD_VECTOR *orientation); +FMOD_RESULT F_API FMOD_Channel_Set3DCustomRolloff (FMOD_CHANNEL *channel, FMOD_VECTOR *points, int numpoints); +FMOD_RESULT F_API FMOD_Channel_Get3DCustomRolloff (FMOD_CHANNEL *channel, FMOD_VECTOR **points, int *numpoints); +FMOD_RESULT F_API FMOD_Channel_Set3DOcclusion (FMOD_CHANNEL *channel, float directocclusion, float reverbocclusion); +FMOD_RESULT F_API FMOD_Channel_Get3DOcclusion (FMOD_CHANNEL *channel, float *directocclusion, float *reverbocclusion); +FMOD_RESULT F_API FMOD_Channel_Set3DSpread (FMOD_CHANNEL *channel, float angle); +FMOD_RESULT F_API FMOD_Channel_Get3DSpread (FMOD_CHANNEL *channel, float *angle); +FMOD_RESULT F_API FMOD_Channel_Set3DPanLevel (FMOD_CHANNEL *channel, float level); +FMOD_RESULT F_API FMOD_Channel_Get3DPanLevel (FMOD_CHANNEL *channel, float *level); +FMOD_RESULT F_API FMOD_Channel_Set3DDopplerLevel (FMOD_CHANNEL *channel, float level); +FMOD_RESULT F_API FMOD_Channel_Get3DDopplerLevel (FMOD_CHANNEL *channel, float *level); + +/* + DSP functionality only for channels playing sounds created with FMOD_SOFTWARE. +*/ + +FMOD_RESULT F_API FMOD_Channel_GetDSPHead (FMOD_CHANNEL *channel, FMOD_DSP **dsp); +FMOD_RESULT F_API FMOD_Channel_AddDSP (FMOD_CHANNEL *channel, FMOD_DSP *dsp, FMOD_DSPCONNECTION **connection); + +/* + Information only functions. +*/ + +FMOD_RESULT F_API FMOD_Channel_IsPlaying (FMOD_CHANNEL *channel, FMOD_BOOL *isplaying); +FMOD_RESULT F_API FMOD_Channel_IsVirtual (FMOD_CHANNEL *channel, FMOD_BOOL *isvirtual); +FMOD_RESULT F_API FMOD_Channel_GetAudibility (FMOD_CHANNEL *channel, float *audibility); +FMOD_RESULT F_API FMOD_Channel_GetCurrentSound (FMOD_CHANNEL *channel, FMOD_SOUND **sound); +FMOD_RESULT F_API FMOD_Channel_GetSpectrum (FMOD_CHANNEL *channel, float *spectrumarray, int numvalues, int channeloffset, FMOD_DSP_FFT_WINDOW windowtype); +FMOD_RESULT F_API FMOD_Channel_GetWaveData (FMOD_CHANNEL *channel, float *wavearray, int numvalues, int channeloffset); +FMOD_RESULT F_API FMOD_Channel_GetIndex (FMOD_CHANNEL *channel, int *index); + +/* + Functions also found in Sound class but here they can be set per channel. +*/ + +FMOD_RESULT F_API FMOD_Channel_SetMode (FMOD_CHANNEL *channel, FMOD_MODE mode); +FMOD_RESULT F_API FMOD_Channel_GetMode (FMOD_CHANNEL *channel, FMOD_MODE *mode); +FMOD_RESULT F_API FMOD_Channel_SetLoopCount (FMOD_CHANNEL *channel, int loopcount); +FMOD_RESULT F_API FMOD_Channel_GetLoopCount (FMOD_CHANNEL *channel, int *loopcount); +FMOD_RESULT F_API FMOD_Channel_SetLoopPoints (FMOD_CHANNEL *channel, unsigned int loopstart, FMOD_TIMEUNIT loopstarttype, unsigned int loopend, FMOD_TIMEUNIT loopendtype); +FMOD_RESULT F_API FMOD_Channel_GetLoopPoints (FMOD_CHANNEL *channel, unsigned int *loopstart, FMOD_TIMEUNIT loopstarttype, unsigned int *loopend, FMOD_TIMEUNIT loopendtype); + +/* + Userdata set/get. +*/ + +FMOD_RESULT F_API FMOD_Channel_SetUserData (FMOD_CHANNEL *channel, void *userdata); +FMOD_RESULT F_API FMOD_Channel_GetUserData (FMOD_CHANNEL *channel, void **userdata); + +FMOD_RESULT F_API FMOD_Channel_GetMemoryInfo (FMOD_CHANNEL *channel, unsigned int memorybits, unsigned int event_memorybits, unsigned int *memoryused, FMOD_MEMORY_USAGE_DETAILS *memoryused_details); + +/* + 'ChannelGroup' API +*/ + +FMOD_RESULT F_API FMOD_ChannelGroup_Release (FMOD_CHANNELGROUP *channelgroup); +FMOD_RESULT F_API FMOD_ChannelGroup_GetSystemObject (FMOD_CHANNELGROUP *channelgroup, FMOD_SYSTEM **system); + +/* + Channelgroup scale values. (changes attributes relative to the channels, doesn't overwrite them) +*/ + +FMOD_RESULT F_API FMOD_ChannelGroup_SetVolume (FMOD_CHANNELGROUP *channelgroup, float volume); +FMOD_RESULT F_API FMOD_ChannelGroup_GetVolume (FMOD_CHANNELGROUP *channelgroup, float *volume); +FMOD_RESULT F_API FMOD_ChannelGroup_SetPitch (FMOD_CHANNELGROUP *channelgroup, float pitch); +FMOD_RESULT F_API FMOD_ChannelGroup_GetPitch (FMOD_CHANNELGROUP *channelgroup, float *pitch); +FMOD_RESULT F_API FMOD_ChannelGroup_Set3DOcclusion (FMOD_CHANNELGROUP *channelgroup, float directocclusion, float reverbocclusion); +FMOD_RESULT F_API FMOD_ChannelGroup_Get3DOcclusion (FMOD_CHANNELGROUP *channelgroup, float *directocclusion, float *reverbocclusion); +FMOD_RESULT F_API FMOD_ChannelGroup_SetPaused (FMOD_CHANNELGROUP *channelgroup, FMOD_BOOL paused); +FMOD_RESULT F_API FMOD_ChannelGroup_GetPaused (FMOD_CHANNELGROUP *channelgroup, FMOD_BOOL *paused); +FMOD_RESULT F_API FMOD_ChannelGroup_SetMute (FMOD_CHANNELGROUP *channelgroup, FMOD_BOOL mute); +FMOD_RESULT F_API FMOD_ChannelGroup_GetMute (FMOD_CHANNELGROUP *channelgroup, FMOD_BOOL *mute); + +/* + Channelgroup override values. (recursively overwrites whatever settings the channels had) +*/ + +FMOD_RESULT F_API FMOD_ChannelGroup_Stop (FMOD_CHANNELGROUP *channelgroup); +FMOD_RESULT F_API FMOD_ChannelGroup_OverrideVolume (FMOD_CHANNELGROUP *channelgroup, float volume); +FMOD_RESULT F_API FMOD_ChannelGroup_OverrideFrequency(FMOD_CHANNELGROUP *channelgroup, float frequency); +FMOD_RESULT F_API FMOD_ChannelGroup_OverridePan (FMOD_CHANNELGROUP *channelgroup, float pan); +FMOD_RESULT F_API FMOD_ChannelGroup_OverrideReverbProperties(FMOD_CHANNELGROUP *channelgroup, const FMOD_REVERB_CHANNELPROPERTIES *prop); +FMOD_RESULT F_API FMOD_ChannelGroup_Override3DAttributes(FMOD_CHANNELGROUP *channelgroup, const FMOD_VECTOR *pos, const FMOD_VECTOR *vel); +FMOD_RESULT F_API FMOD_ChannelGroup_OverrideSpeakerMix(FMOD_CHANNELGROUP *channelgroup, float frontleft, float frontright, float center, float lfe, float backleft, float backright, float sideleft, float sideright); + +/* + Nested channel groups. +*/ + +FMOD_RESULT F_API FMOD_ChannelGroup_AddGroup (FMOD_CHANNELGROUP *channelgroup, FMOD_CHANNELGROUP *group); +FMOD_RESULT F_API FMOD_ChannelGroup_GetNumGroups (FMOD_CHANNELGROUP *channelgroup, int *numgroups); +FMOD_RESULT F_API FMOD_ChannelGroup_GetGroup (FMOD_CHANNELGROUP *channelgroup, int index, FMOD_CHANNELGROUP **group); +FMOD_RESULT F_API FMOD_ChannelGroup_GetParentGroup (FMOD_CHANNELGROUP *channelgroup, FMOD_CHANNELGROUP **group); + +/* + DSP functionality only for channel groups playing sounds created with FMOD_SOFTWARE. +*/ + +FMOD_RESULT F_API FMOD_ChannelGroup_GetDSPHead (FMOD_CHANNELGROUP *channelgroup, FMOD_DSP **dsp); +FMOD_RESULT F_API FMOD_ChannelGroup_AddDSP (FMOD_CHANNELGROUP *channelgroup, FMOD_DSP *dsp, FMOD_DSPCONNECTION **connection); + +/* + Information only functions. +*/ + +FMOD_RESULT F_API FMOD_ChannelGroup_GetName (FMOD_CHANNELGROUP *channelgroup, char *name, int namelen); +FMOD_RESULT F_API FMOD_ChannelGroup_GetNumChannels (FMOD_CHANNELGROUP *channelgroup, int *numchannels); +FMOD_RESULT F_API FMOD_ChannelGroup_GetChannel (FMOD_CHANNELGROUP *channelgroup, int index, FMOD_CHANNEL **channel); +FMOD_RESULT F_API FMOD_ChannelGroup_GetSpectrum (FMOD_CHANNELGROUP *channelgroup, float *spectrumarray, int numvalues, int channeloffset, FMOD_DSP_FFT_WINDOW windowtype); +FMOD_RESULT F_API FMOD_ChannelGroup_GetWaveData (FMOD_CHANNELGROUP *channelgroup, float *wavearray, int numvalues, int channeloffset); + +/* + Userdata set/get. +*/ + +FMOD_RESULT F_API FMOD_ChannelGroup_SetUserData (FMOD_CHANNELGROUP *channelgroup, void *userdata); +FMOD_RESULT F_API FMOD_ChannelGroup_GetUserData (FMOD_CHANNELGROUP *channelgroup, void **userdata); + +FMOD_RESULT F_API FMOD_ChannelGroup_GetMemoryInfo (FMOD_CHANNELGROUP *channelgroup, unsigned int memorybits, unsigned int event_memorybits, unsigned int *memoryused, FMOD_MEMORY_USAGE_DETAILS *memoryused_details); + +/* + 'SoundGroup' API +*/ + +FMOD_RESULT F_API FMOD_SoundGroup_Release (FMOD_SOUNDGROUP *soundgroup); +FMOD_RESULT F_API FMOD_SoundGroup_GetSystemObject (FMOD_SOUNDGROUP *soundgroup, FMOD_SYSTEM **system); + +/* + SoundGroup control functions. +*/ + +FMOD_RESULT F_API FMOD_SoundGroup_SetMaxAudible (FMOD_SOUNDGROUP *soundgroup, int maxaudible); +FMOD_RESULT F_API FMOD_SoundGroup_GetMaxAudible (FMOD_SOUNDGROUP *soundgroup, int *maxaudible); +FMOD_RESULT F_API FMOD_SoundGroup_SetMaxAudibleBehavior(FMOD_SOUNDGROUP *soundgroup, FMOD_SOUNDGROUP_BEHAVIOR behavior); +FMOD_RESULT F_API FMOD_SoundGroup_GetMaxAudibleBehavior(FMOD_SOUNDGROUP *soundgroup, FMOD_SOUNDGROUP_BEHAVIOR *behavior); +FMOD_RESULT F_API FMOD_SoundGroup_SetMuteFadeSpeed (FMOD_SOUNDGROUP *soundgroup, float speed); +FMOD_RESULT F_API FMOD_SoundGroup_GetMuteFadeSpeed (FMOD_SOUNDGROUP *soundgroup, float *speed); +FMOD_RESULT F_API FMOD_SoundGroup_SetVolume (FMOD_SOUNDGROUP *soundgroup, float volume); +FMOD_RESULT F_API FMOD_SoundGroup_GetVolume (FMOD_SOUNDGROUP *soundgroup, float *volume); +FMOD_RESULT F_API FMOD_SoundGroup_Stop (FMOD_SOUNDGROUP *soundgroup); + +/* + Information only functions. +*/ + +FMOD_RESULT F_API FMOD_SoundGroup_GetName (FMOD_SOUNDGROUP *soundgroup, char *name, int namelen); +FMOD_RESULT F_API FMOD_SoundGroup_GetNumSounds (FMOD_SOUNDGROUP *soundgroup, int *numsounds); +FMOD_RESULT F_API FMOD_SoundGroup_GetSound (FMOD_SOUNDGROUP *soundgroup, int index, FMOD_SOUND **sound); +FMOD_RESULT F_API FMOD_SoundGroup_GetNumPlaying (FMOD_SOUNDGROUP *soundgroup, int *numplaying); + +/* + Userdata set/get. +*/ + +FMOD_RESULT F_API FMOD_SoundGroup_SetUserData (FMOD_SOUNDGROUP *soundgroup, void *userdata); +FMOD_RESULT F_API FMOD_SoundGroup_GetUserData (FMOD_SOUNDGROUP *soundgroup, void **userdata); + +FMOD_RESULT F_API FMOD_SoundGroup_GetMemoryInfo (FMOD_SOUNDGROUP *soundgroup, unsigned int memorybits, unsigned int event_memorybits, unsigned int *memoryused, FMOD_MEMORY_USAGE_DETAILS *memoryused_details); + +/* + 'DSP' API +*/ + +FMOD_RESULT F_API FMOD_DSP_Release (FMOD_DSP *dsp); +FMOD_RESULT F_API FMOD_DSP_GetSystemObject (FMOD_DSP *dsp, FMOD_SYSTEM **system); + +/* + Connection / disconnection / input and output enumeration. +*/ + +FMOD_RESULT F_API FMOD_DSP_AddInput (FMOD_DSP *dsp, FMOD_DSP *target, FMOD_DSPCONNECTION **connection); +FMOD_RESULT F_API FMOD_DSP_DisconnectFrom (FMOD_DSP *dsp, FMOD_DSP *target); +FMOD_RESULT F_API FMOD_DSP_DisconnectAll (FMOD_DSP *dsp, FMOD_BOOL inputs, FMOD_BOOL outputs); +FMOD_RESULT F_API FMOD_DSP_Remove (FMOD_DSP *dsp); +FMOD_RESULT F_API FMOD_DSP_GetNumInputs (FMOD_DSP *dsp, int *numinputs); +FMOD_RESULT F_API FMOD_DSP_GetNumOutputs (FMOD_DSP *dsp, int *numoutputs); +FMOD_RESULT F_API FMOD_DSP_GetInput (FMOD_DSP *dsp, int index, FMOD_DSP **input, FMOD_DSPCONNECTION **inputconnection); +FMOD_RESULT F_API FMOD_DSP_GetOutput (FMOD_DSP *dsp, int index, FMOD_DSP **output, FMOD_DSPCONNECTION **outputconnection); + +/* + DSP unit control. +*/ + +FMOD_RESULT F_API FMOD_DSP_SetActive (FMOD_DSP *dsp, FMOD_BOOL active); +FMOD_RESULT F_API FMOD_DSP_GetActive (FMOD_DSP *dsp, FMOD_BOOL *active); +FMOD_RESULT F_API FMOD_DSP_SetBypass (FMOD_DSP *dsp, FMOD_BOOL bypass); +FMOD_RESULT F_API FMOD_DSP_GetBypass (FMOD_DSP *dsp, FMOD_BOOL *bypass); +FMOD_RESULT F_API FMOD_DSP_SetSpeakerActive (FMOD_DSP *dsp, FMOD_SPEAKER speaker, FMOD_BOOL active); +FMOD_RESULT F_API FMOD_DSP_GetSpeakerActive (FMOD_DSP *dsp, FMOD_SPEAKER speaker, FMOD_BOOL *active); +FMOD_RESULT F_API FMOD_DSP_Reset (FMOD_DSP *dsp); + +/* + DSP parameter control. +*/ + +FMOD_RESULT F_API FMOD_DSP_SetParameter (FMOD_DSP *dsp, int index, float value); +FMOD_RESULT F_API FMOD_DSP_GetParameter (FMOD_DSP *dsp, int index, float *value, char *valuestr, int valuestrlen); +FMOD_RESULT F_API FMOD_DSP_GetNumParameters (FMOD_DSP *dsp, int *numparams); +FMOD_RESULT F_API FMOD_DSP_GetParameterInfo (FMOD_DSP *dsp, int index, char *name, char *label, char *description, int descriptionlen, float *min, float *max); +FMOD_RESULT F_API FMOD_DSP_ShowConfigDialog (FMOD_DSP *dsp, void *hwnd, FMOD_BOOL show); + +/* + DSP attributes. +*/ + +FMOD_RESULT F_API FMOD_DSP_GetInfo (FMOD_DSP *dsp, char *name, unsigned int *version, int *channels, int *configwidth, int *configheight); +FMOD_RESULT F_API FMOD_DSP_GetType (FMOD_DSP *dsp, FMOD_DSP_TYPE *type); +FMOD_RESULT F_API FMOD_DSP_SetDefaults (FMOD_DSP *dsp, float frequency, float volume, float pan, int priority); +FMOD_RESULT F_API FMOD_DSP_GetDefaults (FMOD_DSP *dsp, float *frequency, float *volume, float *pan, int *priority); + +/* + Userdata set/get. +*/ + +FMOD_RESULT F_API FMOD_DSP_SetUserData (FMOD_DSP *dsp, void *userdata); +FMOD_RESULT F_API FMOD_DSP_GetUserData (FMOD_DSP *dsp, void **userdata); + +FMOD_RESULT F_API FMOD_DSP_GetMemoryInfo (FMOD_DSP *dsp, unsigned int memorybits, unsigned int event_memorybits, unsigned int *memoryused, FMOD_MEMORY_USAGE_DETAILS *memoryused_details); + +/* + 'DSPConnection' API +*/ + +FMOD_RESULT F_API FMOD_DSPConnection_GetInput (FMOD_DSPCONNECTION *dspconnection, FMOD_DSP **input); +FMOD_RESULT F_API FMOD_DSPConnection_GetOutput (FMOD_DSPCONNECTION *dspconnection, FMOD_DSP **output); +FMOD_RESULT F_API FMOD_DSPConnection_SetMix (FMOD_DSPCONNECTION *dspconnection, float volume); +FMOD_RESULT F_API FMOD_DSPConnection_GetMix (FMOD_DSPCONNECTION *dspconnection, float *volume); +FMOD_RESULT F_API FMOD_DSPConnection_SetLevels (FMOD_DSPCONNECTION *dspconnection, FMOD_SPEAKER speaker, float *levels, int numlevels); +FMOD_RESULT F_API FMOD_DSPConnection_GetLevels (FMOD_DSPCONNECTION *dspconnection, FMOD_SPEAKER speaker, float *levels, int numlevels); + +/* + Userdata set/get. +*/ + +FMOD_RESULT F_API FMOD_DSPConnection_SetUserData (FMOD_DSPCONNECTION *dspconnection, void *userdata); +FMOD_RESULT F_API FMOD_DSPConnection_GetUserData (FMOD_DSPCONNECTION *dspconnection, void **userdata); + +FMOD_RESULT F_API FMOD_DSPConnection_GetMemoryInfo (FMOD_DSPCONNECTION *dspconnection, unsigned int memorybits, unsigned int event_memorybits, unsigned int *memoryused, FMOD_MEMORY_USAGE_DETAILS *memoryused_details); + +/* + 'Geometry' API +*/ + +FMOD_RESULT F_API FMOD_Geometry_Release (FMOD_GEOMETRY *geometry); + +/* + Polygon manipulation. +*/ + +FMOD_RESULT F_API FMOD_Geometry_AddPolygon (FMOD_GEOMETRY *geometry, float directocclusion, float reverbocclusion, FMOD_BOOL doublesided, int numvertices, const FMOD_VECTOR *vertices, int *polygonindex); +FMOD_RESULT F_API FMOD_Geometry_GetNumPolygons (FMOD_GEOMETRY *geometry, int *numpolygons); +FMOD_RESULT F_API FMOD_Geometry_GetMaxPolygons (FMOD_GEOMETRY *geometry, int *maxpolygons, int *maxvertices); +FMOD_RESULT F_API FMOD_Geometry_GetPolygonNumVertices(FMOD_GEOMETRY *geometry, int index, int *numvertices); +FMOD_RESULT F_API FMOD_Geometry_SetPolygonVertex (FMOD_GEOMETRY *geometry, int index, int vertexindex, const FMOD_VECTOR *vertex); +FMOD_RESULT F_API FMOD_Geometry_GetPolygonVertex (FMOD_GEOMETRY *geometry, int index, int vertexindex, FMOD_VECTOR *vertex); +FMOD_RESULT F_API FMOD_Geometry_SetPolygonAttributes (FMOD_GEOMETRY *geometry, int index, float directocclusion, float reverbocclusion, FMOD_BOOL doublesided); +FMOD_RESULT F_API FMOD_Geometry_GetPolygonAttributes (FMOD_GEOMETRY *geometry, int index, float *directocclusion, float *reverbocclusion, FMOD_BOOL *doublesided); + +/* + Object manipulation. +*/ + +FMOD_RESULT F_API FMOD_Geometry_SetActive (FMOD_GEOMETRY *geometry, FMOD_BOOL active); +FMOD_RESULT F_API FMOD_Geometry_GetActive (FMOD_GEOMETRY *geometry, FMOD_BOOL *active); +FMOD_RESULT F_API FMOD_Geometry_SetRotation (FMOD_GEOMETRY *geometry, const FMOD_VECTOR *forward, const FMOD_VECTOR *up); +FMOD_RESULT F_API FMOD_Geometry_GetRotation (FMOD_GEOMETRY *geometry, FMOD_VECTOR *forward, FMOD_VECTOR *up); +FMOD_RESULT F_API FMOD_Geometry_SetPosition (FMOD_GEOMETRY *geometry, const FMOD_VECTOR *position); +FMOD_RESULT F_API FMOD_Geometry_GetPosition (FMOD_GEOMETRY *geometry, FMOD_VECTOR *position); +FMOD_RESULT F_API FMOD_Geometry_SetScale (FMOD_GEOMETRY *geometry, const FMOD_VECTOR *scale); +FMOD_RESULT F_API FMOD_Geometry_GetScale (FMOD_GEOMETRY *geometry, FMOD_VECTOR *scale); +FMOD_RESULT F_API FMOD_Geometry_Save (FMOD_GEOMETRY *geometry, void *data, int *datasize); + +/* + Userdata set/get. +*/ + +FMOD_RESULT F_API FMOD_Geometry_SetUserData (FMOD_GEOMETRY *geometry, void *userdata); +FMOD_RESULT F_API FMOD_Geometry_GetUserData (FMOD_GEOMETRY *geometry, void **userdata); + +FMOD_RESULT F_API FMOD_Geometry_GetMemoryInfo (FMOD_GEOMETRY *geometry, unsigned int memorybits, unsigned int event_memorybits, unsigned int *memoryused, FMOD_MEMORY_USAGE_DETAILS *memoryused_details); + +/* + 'Reverb' API +*/ + +FMOD_RESULT F_API FMOD_Reverb_Release (FMOD_REVERB *reverb); + +/* + Reverb manipulation. +*/ + +FMOD_RESULT F_API FMOD_Reverb_Set3DAttributes (FMOD_REVERB *reverb, const FMOD_VECTOR *position, float mindistance, float maxdistance); +FMOD_RESULT F_API FMOD_Reverb_Get3DAttributes (FMOD_REVERB *reverb, FMOD_VECTOR *position, float *mindistance, float *maxdistance); +FMOD_RESULT F_API FMOD_Reverb_SetProperties (FMOD_REVERB *reverb, const FMOD_REVERB_PROPERTIES *properties); +FMOD_RESULT F_API FMOD_Reverb_GetProperties (FMOD_REVERB *reverb, FMOD_REVERB_PROPERTIES *properties); +FMOD_RESULT F_API FMOD_Reverb_SetActive (FMOD_REVERB *reverb, FMOD_BOOL active); +FMOD_RESULT F_API FMOD_Reverb_GetActive (FMOD_REVERB *reverb, FMOD_BOOL *active); + +/* + Userdata set/get. +*/ + +FMOD_RESULT F_API FMOD_Reverb_SetUserData (FMOD_REVERB *reverb, void *userdata); +FMOD_RESULT F_API FMOD_Reverb_GetUserData (FMOD_REVERB *reverb, void **userdata); + +FMOD_RESULT F_API FMOD_Reverb_GetMemoryInfo (FMOD_REVERB *reverb, unsigned int memorybits, unsigned int event_memorybits, unsigned int *memoryused, FMOD_MEMORY_USAGE_DETAILS *memoryused_details); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/Lib/Include/FMOD/fmod.hpp b/Lib/Include/FMOD/fmod.hpp new file mode 100644 index 0000000..aecf085 --- /dev/null +++ b/Lib/Include/FMOD/fmod.hpp @@ -0,0 +1,603 @@ +/* ========================================================================================== */ +/* FMOD Ex - C++ header file. Copyright (c), Firelight Technologies Pty, Ltd. 2004-2009. */ +/* */ +/* Use this header in conjunction with fmod.h (which contains all the constants / callbacks) */ +/* to develop using C++ classes. */ +/* ========================================================================================== */ + +#ifndef _FMOD_HPP +#define _FMOD_HPP + +#include "fmod.h" + +/* + Constant and defines +*/ + +/* + FMOD Namespace +*/ +namespace FMOD +{ + class System; + class Sound; + class Channel; + class ChannelGroup; + class SoundGroup; + class Reverb; + class DSP; + class DSPConnection; + class Geometry; + + /* + FMOD global system functions (optional). + */ + inline FMOD_RESULT Memory_Initialize(void *poolmem, int poollen, FMOD_MEMORY_ALLOCCALLBACK useralloc, FMOD_MEMORY_REALLOCCALLBACK userrealloc, FMOD_MEMORY_FREECALLBACK userfree, FMOD_MEMORY_TYPE memtypeflags = FMOD_MEMORY_ALL) { return FMOD_Memory_Initialize(poolmem, poollen, useralloc, userrealloc, userfree, memtypeflags); } + inline FMOD_RESULT Memory_GetStats (int *currentalloced, int *maxalloced, bool blocking = true) { return FMOD_Memory_GetStats(currentalloced, maxalloced, blocking); } + inline FMOD_RESULT Debug_SetLevel(FMOD_DEBUGLEVEL level) { return FMOD_Debug_SetLevel(level); } + inline FMOD_RESULT Debug_GetLevel(FMOD_DEBUGLEVEL *level) { return FMOD_Debug_GetLevel(level); } + inline FMOD_RESULT File_SetDiskBusy(int busy) { return FMOD_File_SetDiskBusy(busy); } + inline FMOD_RESULT File_GetDiskBusy(int *busy) { return FMOD_File_GetDiskBusy(busy); } + + /* + FMOD System factory functions. + */ + inline FMOD_RESULT System_Create(System **system) { return FMOD_System_Create((FMOD_SYSTEM **)system); } + + /* + 'System' API + */ + + class System + { + private: + + System(); /* Constructor made private so user cannot statically instance a System class. + System_Create must be used. */ + public: + + FMOD_RESULT F_API release (); + + // Pre-init functions. + FMOD_RESULT F_API setOutput (FMOD_OUTPUTTYPE output); + FMOD_RESULT F_API getOutput (FMOD_OUTPUTTYPE *output); + FMOD_RESULT F_API getNumDrivers (int *numdrivers); + FMOD_RESULT F_API getDriverInfo (int id, char *name, int namelen, FMOD_GUID *guid); + FMOD_RESULT F_API getDriverInfoW (int id, short *name, int namelen, FMOD_GUID *guid); + FMOD_RESULT F_API getDriverCaps (int id, FMOD_CAPS *caps, int *minfrequency, int *maxfrequency, FMOD_SPEAKERMODE *controlpanelspeakermode); + FMOD_RESULT F_API setDriver (int driver); + FMOD_RESULT F_API getDriver (int *driver); + FMOD_RESULT F_API setHardwareChannels (int min2d, int max2d, int min3d, int max3d); + FMOD_RESULT F_API setSoftwareChannels (int numsoftwarechannels); + FMOD_RESULT F_API getSoftwareChannels (int *numsoftwarechannels); + FMOD_RESULT F_API setSoftwareFormat (int samplerate, FMOD_SOUND_FORMAT format, int numoutputchannels, int maxinputchannels, FMOD_DSP_RESAMPLER resamplemethod); + FMOD_RESULT F_API getSoftwareFormat (int *samplerate, FMOD_SOUND_FORMAT *format, int *numoutputchannels, int *maxinputchannels, FMOD_DSP_RESAMPLER *resamplemethod, int *bits); + FMOD_RESULT F_API setDSPBufferSize (unsigned int bufferlength, int numbuffers); + FMOD_RESULT F_API getDSPBufferSize (unsigned int *bufferlength, int *numbuffers); + FMOD_RESULT F_API setFileSystem (FMOD_FILE_OPENCALLBACK useropen, FMOD_FILE_CLOSECALLBACK userclose, FMOD_FILE_READCALLBACK userread, FMOD_FILE_SEEKCALLBACK userseek, int blockalign); + FMOD_RESULT F_API attachFileSystem (FMOD_FILE_OPENCALLBACK useropen, FMOD_FILE_CLOSECALLBACK userclose, FMOD_FILE_READCALLBACK userread, FMOD_FILE_SEEKCALLBACK userseek); + FMOD_RESULT F_API setAdvancedSettings (FMOD_ADVANCEDSETTINGS *settings); + FMOD_RESULT F_API getAdvancedSettings (FMOD_ADVANCEDSETTINGS *settings); + FMOD_RESULT F_API setSpeakerMode (FMOD_SPEAKERMODE speakermode); + FMOD_RESULT F_API getSpeakerMode (FMOD_SPEAKERMODE *speakermode); + FMOD_RESULT F_API setCallback (FMOD_SYSTEM_CALLBACK callback); + + // Plug-in support + FMOD_RESULT F_API setPluginPath (const char *path); + FMOD_RESULT F_API loadPlugin (const char *filename, unsigned int *handle, unsigned int priority = 0); + FMOD_RESULT F_API unloadPlugin (unsigned int handle); + FMOD_RESULT F_API getNumPlugins (FMOD_PLUGINTYPE plugintype, int *numplugins); + FMOD_RESULT F_API getPluginHandle (FMOD_PLUGINTYPE plugintype, int index, unsigned int *handle); + FMOD_RESULT F_API getPluginInfo (unsigned int handle, FMOD_PLUGINTYPE *plugintype, char *name, int namelen, unsigned int *version); + FMOD_RESULT F_API setOutputByPlugin (unsigned int handle); + FMOD_RESULT F_API getOutputByPlugin (unsigned int *handle); + FMOD_RESULT F_API createDSPByPlugin (unsigned int handle, DSP **dsp); + FMOD_RESULT F_API createCodec (FMOD_CODEC_DESCRIPTION *description, unsigned int priority = 0); + + // Init/Close + FMOD_RESULT F_API init (int maxchannels, FMOD_INITFLAGS flags, void *extradriverdata); + FMOD_RESULT F_API close (); + + // General post-init system functions + FMOD_RESULT F_API update (); /* IMPORTANT! CALL THIS ONCE PER FRAME! */ + + FMOD_RESULT F_API set3DSettings (float dopplerscale, float distancefactor, float rolloffscale); + FMOD_RESULT F_API get3DSettings (float *dopplerscale, float *distancefactor, float *rolloffscale); + FMOD_RESULT F_API set3DNumListeners (int numlisteners); + FMOD_RESULT F_API get3DNumListeners (int *numlisteners); + FMOD_RESULT F_API set3DListenerAttributes(int listener, const FMOD_VECTOR *pos, const FMOD_VECTOR *vel, const FMOD_VECTOR *forward, const FMOD_VECTOR *up); + FMOD_RESULT F_API get3DListenerAttributes(int listener, FMOD_VECTOR *pos, FMOD_VECTOR *vel, FMOD_VECTOR *forward, FMOD_VECTOR *up); + FMOD_RESULT F_API set3DRolloffCallback (FMOD_3D_ROLLOFFCALLBACK callback); + FMOD_RESULT F_API set3DSpeakerPosition (FMOD_SPEAKER speaker, float x, float y, bool active); + FMOD_RESULT F_API get3DSpeakerPosition (FMOD_SPEAKER speaker, float *x, float *y, bool *active); + + FMOD_RESULT F_API setStreamBufferSize (unsigned int filebuffersize, FMOD_TIMEUNIT filebuffersizetype); + FMOD_RESULT F_API getStreamBufferSize (unsigned int *filebuffersize, FMOD_TIMEUNIT *filebuffersizetype); + + // System information functions. + FMOD_RESULT F_API getVersion (unsigned int *version); + FMOD_RESULT F_API getOutputHandle (void **handle); + FMOD_RESULT F_API getChannelsPlaying (int *channels); + FMOD_RESULT F_API getHardwareChannels (int *num2d, int *num3d, int *total); + FMOD_RESULT F_API getCPUUsage (float *dsp, float *stream, float *geometry, float *update, float *total); + FMOD_RESULT F_API getSoundRAM (int *currentalloced, int *maxalloced, int *total); + FMOD_RESULT F_API getNumCDROMDrives (int *numdrives); + FMOD_RESULT F_API getCDROMDriveName (int drive, char *drivename, int drivenamelen, char *scsiname, int scsinamelen, char *devicename, int devicenamelen); + FMOD_RESULT F_API getSpectrum (float *spectrumarray, int numvalues, int channeloffset, FMOD_DSP_FFT_WINDOW windowtype); + FMOD_RESULT F_API getWaveData (float *wavearray, int numvalues, int channeloffset); + + // Sound/DSP/Channel/FX creation and retrieval. + FMOD_RESULT F_API createSound (const char *name_or_data, FMOD_MODE mode, FMOD_CREATESOUNDEXINFO *exinfo, Sound **sound); + FMOD_RESULT F_API createStream (const char *name_or_data, FMOD_MODE mode, FMOD_CREATESOUNDEXINFO *exinfo, Sound **sound); + FMOD_RESULT F_API createDSP (FMOD_DSP_DESCRIPTION *description, DSP **dsp); + FMOD_RESULT F_API createDSPByType (FMOD_DSP_TYPE type, DSP **dsp); + FMOD_RESULT F_API createChannelGroup (const char *name, ChannelGroup **channelgroup); + FMOD_RESULT F_API createSoundGroup (const char *name, SoundGroup **soundgroup); + FMOD_RESULT F_API createReverb (Reverb **reverb); + + FMOD_RESULT F_API playSound (FMOD_CHANNELINDEX channelid, Sound *sound, bool paused, Channel **channel); + FMOD_RESULT F_API playDSP (FMOD_CHANNELINDEX channelid, DSP *dsp, bool paused, Channel **channel); + FMOD_RESULT F_API getChannel (int channelid, Channel **channel); + FMOD_RESULT F_API getMasterChannelGroup (ChannelGroup **channelgroup); + FMOD_RESULT F_API getMasterSoundGroup (SoundGroup **soundgroup); + + // Reverb API + FMOD_RESULT F_API setReverbProperties (const FMOD_REVERB_PROPERTIES *prop); + FMOD_RESULT F_API getReverbProperties (FMOD_REVERB_PROPERTIES *prop); + FMOD_RESULT F_API setReverbAmbientProperties(FMOD_REVERB_PROPERTIES *prop); + FMOD_RESULT F_API getReverbAmbientProperties(FMOD_REVERB_PROPERTIES *prop); + + // System level DSP access. + FMOD_RESULT F_API getDSPHead (DSP **dsp); + FMOD_RESULT F_API addDSP (DSP *dsp, DSPConnection **connection); + FMOD_RESULT F_API lockDSP (); + FMOD_RESULT F_API unlockDSP (); + FMOD_RESULT F_API getDSPClock (unsigned int *hi, unsigned int *lo); + + // Recording API. + FMOD_RESULT F_API getRecordNumDrivers (int *numdrivers); + FMOD_RESULT F_API getRecordDriverInfo (int id, char *name, int namelen, FMOD_GUID *guid); + FMOD_RESULT F_API getRecordDriverInfoW (int id, short *name, int namelen, FMOD_GUID *guid); + FMOD_RESULT F_API getRecordDriverCaps (int id, FMOD_CAPS *caps, int *minfrequency, int *maxfrequency); + FMOD_RESULT F_API getRecordPosition (int id, unsigned int *position); + + FMOD_RESULT F_API recordStart (int id, Sound *sound, bool loop); + FMOD_RESULT F_API recordStop (int id); + FMOD_RESULT F_API isRecording (int id, bool *recording); + + // Geometry API. + FMOD_RESULT F_API createGeometry (int maxpolygons, int maxvertices, Geometry **geometry); + FMOD_RESULT F_API setGeometrySettings (float maxworldsize); + FMOD_RESULT F_API getGeometrySettings (float *maxworldsize); + FMOD_RESULT F_API loadGeometry (const void *data, int datasize, Geometry **geometry); + FMOD_RESULT F_API getGeometryOcclusion (const FMOD_VECTOR *listener, const FMOD_VECTOR *source, float *direct, float *reverb); + + // Network functions. + FMOD_RESULT F_API setNetworkProxy (const char *proxy); + FMOD_RESULT F_API getNetworkProxy (char *proxy, int proxylen); + FMOD_RESULT F_API setNetworkTimeout (int timeout); + FMOD_RESULT F_API getNetworkTimeout (int *timeout); + + // Userdata set/get. + FMOD_RESULT F_API setUserData (void *userdata); + FMOD_RESULT F_API getUserData (void **userdata); + + FMOD_RESULT F_API getMemoryInfo (unsigned int memorybits, unsigned int event_memorybits, unsigned int *memoryused, FMOD_MEMORY_USAGE_DETAILS *memoryused_details); + }; + + /* + 'Sound' API + */ + class Sound + { + private: + + Sound(); /* Constructor made private so user cannot statically instance a Sound class. + Appropriate Sound creation or retrieval function must be used. */ + public: + + FMOD_RESULT F_API release (); + FMOD_RESULT F_API getSystemObject (System **system); + + // Standard sound manipulation functions. + FMOD_RESULT F_API lock (unsigned int offset, unsigned int length, void **ptr1, void **ptr2, unsigned int *len1, unsigned int *len2); + FMOD_RESULT F_API unlock (void *ptr1, void *ptr2, unsigned int len1, unsigned int len2); + FMOD_RESULT F_API setDefaults (float frequency, float volume, float pan, int priority); + FMOD_RESULT F_API getDefaults (float *frequency, float *volume, float *pan, int *priority); + FMOD_RESULT F_API setVariations (float frequencyvar, float volumevar, float panvar); + FMOD_RESULT F_API getVariations (float *frequencyvar, float *volumevar, float *panvar); + FMOD_RESULT F_API set3DMinMaxDistance (float min, float max); + FMOD_RESULT F_API get3DMinMaxDistance (float *min, float *max); + FMOD_RESULT F_API set3DConeSettings (float insideconeangle, float outsideconeangle, float outsidevolume); + FMOD_RESULT F_API get3DConeSettings (float *insideconeangle, float *outsideconeangle, float *outsidevolume); + FMOD_RESULT F_API set3DCustomRolloff (FMOD_VECTOR *points, int numpoints); + FMOD_RESULT F_API get3DCustomRolloff (FMOD_VECTOR **points, int *numpoints); + FMOD_RESULT F_API setSubSound (int index, Sound *subsound); + FMOD_RESULT F_API getSubSound (int index, Sound **subsound); + FMOD_RESULT F_API setSubSoundSentence (int *subsoundlist, int numsubsounds); + FMOD_RESULT F_API getName (char *name, int namelen); + FMOD_RESULT F_API getLength (unsigned int *length, FMOD_TIMEUNIT lengthtype); + FMOD_RESULT F_API getFormat (FMOD_SOUND_TYPE *type, FMOD_SOUND_FORMAT *format, int *channels, int *bits); + FMOD_RESULT F_API getNumSubSounds (int *numsubsounds); + FMOD_RESULT F_API getNumTags (int *numtags, int *numtagsupdated); + FMOD_RESULT F_API getTag (const char *name, int index, FMOD_TAG *tag); + FMOD_RESULT F_API getOpenState (FMOD_OPENSTATE *openstate, unsigned int *percentbuffered, bool *starving); + FMOD_RESULT F_API readData (void *buffer, unsigned int lenbytes, unsigned int *read); + FMOD_RESULT F_API seekData (unsigned int pcm); + + FMOD_RESULT F_API setSoundGroup (SoundGroup *soundgroup); + FMOD_RESULT F_API getSoundGroup (SoundGroup **soundgroup); + + // Synchronization point API. These points can come from markers embedded in wav files, and can also generate channel callbacks. + FMOD_RESULT F_API getNumSyncPoints (int *numsyncpoints); + FMOD_RESULT F_API getSyncPoint (int index, FMOD_SYNCPOINT **point); + FMOD_RESULT F_API getSyncPointInfo (FMOD_SYNCPOINT *point, char *name, int namelen, unsigned int *offset, FMOD_TIMEUNIT offsettype); + FMOD_RESULT F_API addSyncPoint (unsigned int offset, FMOD_TIMEUNIT offsettype, const char *name, FMOD_SYNCPOINT **point); + FMOD_RESULT F_API deleteSyncPoint (FMOD_SYNCPOINT *point); + + // Functions also in Channel class but here they are the 'default' to save having to change it in Channel all the time. + FMOD_RESULT F_API setMode (FMOD_MODE mode); + FMOD_RESULT F_API getMode (FMOD_MODE *mode); + FMOD_RESULT F_API setLoopCount (int loopcount); + FMOD_RESULT F_API getLoopCount (int *loopcount); + FMOD_RESULT F_API setLoopPoints (unsigned int loopstart, FMOD_TIMEUNIT loopstarttype, unsigned int loopend, FMOD_TIMEUNIT loopendtype); + FMOD_RESULT F_API getLoopPoints (unsigned int *loopstart, FMOD_TIMEUNIT loopstarttype, unsigned int *loopend, FMOD_TIMEUNIT loopendtype); + + // For MOD/S3M/XM/IT/MID sequenced formats only. + FMOD_RESULT F_API getMusicNumChannels (int *numchannels); + FMOD_RESULT F_API setMusicChannelVolume (int channel, float volume); + FMOD_RESULT F_API getMusicChannelVolume (int channel, float *volume); + + // Userdata set/get. + FMOD_RESULT F_API setUserData (void *userdata); + FMOD_RESULT F_API getUserData (void **userdata); + + FMOD_RESULT F_API getMemoryInfo (unsigned int memorybits, unsigned int event_memorybits, unsigned int *memoryused, FMOD_MEMORY_USAGE_DETAILS *memoryused_details); + }; + + /* + 'Channel' API. + */ + class Channel + { + private: + + Channel(); /* Constructor made private so user cannot statically instance a Channel class. + Appropriate Channel creation or retrieval function must be used. */ + public: + + FMOD_RESULT F_API getSystemObject (System **system); + + FMOD_RESULT F_API stop (); + FMOD_RESULT F_API setPaused (bool paused); + FMOD_RESULT F_API getPaused (bool *paused); + FMOD_RESULT F_API setVolume (float volume); + FMOD_RESULT F_API getVolume (float *volume); + FMOD_RESULT F_API setFrequency (float frequency); + FMOD_RESULT F_API getFrequency (float *frequency); + FMOD_RESULT F_API setPan (float pan); + FMOD_RESULT F_API getPan (float *pan); + FMOD_RESULT F_API setDelay (FMOD_DELAYTYPE delaytype, unsigned int delayhi, unsigned int delaylo); + FMOD_RESULT F_API getDelay (FMOD_DELAYTYPE delaytype, unsigned int *delayhi, unsigned int *delaylo); + FMOD_RESULT F_API setSpeakerMix (float frontleft, float frontright, float center, float lfe, float backleft, float backright, float sideleft, float sideright); + FMOD_RESULT F_API getSpeakerMix (float *frontleft, float *frontright, float *center, float *lfe, float *backleft, float *backright, float *sideleft, float *sideright); + FMOD_RESULT F_API setSpeakerLevels (FMOD_SPEAKER speaker, float *levels, int numlevels); + FMOD_RESULT F_API getSpeakerLevels (FMOD_SPEAKER speaker, float *levels, int numlevels); + FMOD_RESULT F_API setInputChannelMix (float *levels, int numlevels); + FMOD_RESULT F_API getInputChannelMix (float *levels, int numlevels); + FMOD_RESULT F_API setMute (bool mute); + FMOD_RESULT F_API getMute (bool *mute); + FMOD_RESULT F_API setPriority (int priority); + FMOD_RESULT F_API getPriority (int *priority); + FMOD_RESULT F_API setPosition (unsigned int position, FMOD_TIMEUNIT postype); + FMOD_RESULT F_API getPosition (unsigned int *position, FMOD_TIMEUNIT postype); + FMOD_RESULT F_API setReverbProperties (const FMOD_REVERB_CHANNELPROPERTIES *prop); + FMOD_RESULT F_API getReverbProperties (FMOD_REVERB_CHANNELPROPERTIES *prop); + FMOD_RESULT F_API setLowPassGain (float gain); + FMOD_RESULT F_API getLowPassGain (float *gain); + + FMOD_RESULT F_API setChannelGroup (ChannelGroup *channelgroup); + FMOD_RESULT F_API getChannelGroup (ChannelGroup **channelgroup); + FMOD_RESULT F_API setCallback (FMOD_CHANNEL_CALLBACK callback); + + // 3D functionality. + FMOD_RESULT F_API set3DAttributes (const FMOD_VECTOR *pos, const FMOD_VECTOR *vel); + FMOD_RESULT F_API get3DAttributes (FMOD_VECTOR *pos, FMOD_VECTOR *vel); + FMOD_RESULT F_API set3DMinMaxDistance (float mindistance, float maxdistance); + FMOD_RESULT F_API get3DMinMaxDistance (float *mindistance, float *maxdistance); + FMOD_RESULT F_API set3DConeSettings (float insideconeangle, float outsideconeangle, float outsidevolume); + FMOD_RESULT F_API get3DConeSettings (float *insideconeangle, float *outsideconeangle, float *outsidevolume); + FMOD_RESULT F_API set3DConeOrientation (FMOD_VECTOR *orientation); + FMOD_RESULT F_API get3DConeOrientation (FMOD_VECTOR *orientation); + FMOD_RESULT F_API set3DCustomRolloff (FMOD_VECTOR *points, int numpoints); + FMOD_RESULT F_API get3DCustomRolloff (FMOD_VECTOR **points, int *numpoints); + FMOD_RESULT F_API set3DOcclusion (float directocclusion, float reverbocclusion); + FMOD_RESULT F_API get3DOcclusion (float *directocclusion, float *reverbocclusion); + FMOD_RESULT F_API set3DSpread (float angle); + FMOD_RESULT F_API get3DSpread (float *angle); + FMOD_RESULT F_API set3DPanLevel (float level); + FMOD_RESULT F_API get3DPanLevel (float *level); + FMOD_RESULT F_API set3DDopplerLevel (float level); + FMOD_RESULT F_API get3DDopplerLevel (float *level); + + // DSP functionality only for channels playing sounds created with FMOD_SOFTWARE. + FMOD_RESULT F_API getDSPHead (DSP **dsp); + FMOD_RESULT F_API addDSP (DSP *dsp, DSPConnection **connection); + + // Information only functions. + FMOD_RESULT F_API isPlaying (bool *isplaying); + FMOD_RESULT F_API isVirtual (bool *isvirtual); + FMOD_RESULT F_API getAudibility (float *audibility); + FMOD_RESULT F_API getCurrentSound (Sound **sound); + FMOD_RESULT F_API getSpectrum (float *spectrumarray, int numvalues, int channeloffset, FMOD_DSP_FFT_WINDOW windowtype); + FMOD_RESULT F_API getWaveData (float *wavearray, int numvalues, int channeloffset); + FMOD_RESULT F_API getIndex (int *index); + + // Functions also found in Sound class but here they can be set per channel. + FMOD_RESULT F_API setMode (FMOD_MODE mode); + FMOD_RESULT F_API getMode (FMOD_MODE *mode); + FMOD_RESULT F_API setLoopCount (int loopcount); + FMOD_RESULT F_API getLoopCount (int *loopcount); + FMOD_RESULT F_API setLoopPoints (unsigned int loopstart, FMOD_TIMEUNIT loopstarttype, unsigned int loopend, FMOD_TIMEUNIT loopendtype); + FMOD_RESULT F_API getLoopPoints (unsigned int *loopstart, FMOD_TIMEUNIT loopstarttype, unsigned int *loopend, FMOD_TIMEUNIT loopendtype); + + // Userdata set/get. + FMOD_RESULT F_API setUserData (void *userdata); + FMOD_RESULT F_API getUserData (void **userdata); + + FMOD_RESULT F_API getMemoryInfo (unsigned int memorybits, unsigned int event_memorybits, unsigned int *memoryused, FMOD_MEMORY_USAGE_DETAILS *memoryused_details); + }; + + /* + 'ChannelGroup' API + */ + class ChannelGroup + { + private: + + ChannelGroup(); /* Constructor made private so user cannot statically instance a ChannelGroup class. + Appropriate ChannelGroup creation or retrieval function must be used. */ + public: + + FMOD_RESULT F_API release (); + FMOD_RESULT F_API getSystemObject (System **system); + + // Channelgroup scale values. (changes attributes relative to the channels, doesn't overwrite them) + FMOD_RESULT F_API setVolume (float volume); + FMOD_RESULT F_API getVolume (float *volume); + FMOD_RESULT F_API setPitch (float pitch); + FMOD_RESULT F_API getPitch (float *pitch); + FMOD_RESULT F_API set3DOcclusion (float directocclusion, float reverbocclusion); + FMOD_RESULT F_API get3DOcclusion (float *directocclusion, float *reverbocclusion); + FMOD_RESULT F_API setPaused (bool paused); + FMOD_RESULT F_API getPaused (bool *paused); + FMOD_RESULT F_API setMute (bool mute); + FMOD_RESULT F_API getMute (bool *mute); + + // Channelgroup override values. (recursively overwrites whatever settings the channels had) + FMOD_RESULT F_API stop (); + FMOD_RESULT F_API overrideVolume (float volume); + FMOD_RESULT F_API overrideFrequency (float frequency); + FMOD_RESULT F_API overridePan (float pan); + FMOD_RESULT F_API overrideReverbProperties(const FMOD_REVERB_CHANNELPROPERTIES *prop); + FMOD_RESULT F_API override3DAttributes (const FMOD_VECTOR *pos, const FMOD_VECTOR *vel); + FMOD_RESULT F_API overrideSpeakerMix (float frontleft, float frontright, float center, float lfe, float backleft, float backright, float sideleft, float sideright); + + // Nested channel groups. + FMOD_RESULT F_API addGroup (ChannelGroup *group); + FMOD_RESULT F_API getNumGroups (int *numgroups); + FMOD_RESULT F_API getGroup (int index, ChannelGroup **group); + FMOD_RESULT F_API getParentGroup (ChannelGroup **group); + + // DSP functionality only for channel groups playing sounds created with FMOD_SOFTWARE. + FMOD_RESULT F_API getDSPHead (DSP **dsp); + FMOD_RESULT F_API addDSP (DSP *dsp, DSPConnection **connection); + + // Information only functions. + FMOD_RESULT F_API getName (char *name, int namelen); + FMOD_RESULT F_API getNumChannels (int *numchannels); + FMOD_RESULT F_API getChannel (int index, Channel **channel); + FMOD_RESULT F_API getSpectrum (float *spectrumarray, int numvalues, int channeloffset, FMOD_DSP_FFT_WINDOW windowtype); + FMOD_RESULT F_API getWaveData (float *wavearray, int numvalues, int channeloffset); + + // Userdata set/get. + FMOD_RESULT F_API setUserData (void *userdata); + FMOD_RESULT F_API getUserData (void **userdata); + + FMOD_RESULT F_API getMemoryInfo (unsigned int memorybits, unsigned int event_memorybits, unsigned int *memoryused, FMOD_MEMORY_USAGE_DETAILS *memoryused_details); + }; + + /* + 'SoundGroup' API + */ + class SoundGroup + { + private: + + SoundGroup(); /* Constructor made private so user cannot statically instance a SoundGroup class. + Appropriate SoundGroup creation or retrieval function must be used. */ + public: + + FMOD_RESULT F_API release (); + FMOD_RESULT F_API getSystemObject (System **system); + + // SoundGroup control functions. + FMOD_RESULT F_API setMaxAudible (int maxaudible); + FMOD_RESULT F_API getMaxAudible (int *maxaudible); + FMOD_RESULT F_API setMaxAudibleBehavior (FMOD_SOUNDGROUP_BEHAVIOR behavior); + FMOD_RESULT F_API getMaxAudibleBehavior (FMOD_SOUNDGROUP_BEHAVIOR *behavior); + FMOD_RESULT F_API setMuteFadeSpeed (float speed); + FMOD_RESULT F_API getMuteFadeSpeed (float *speed); + FMOD_RESULT F_API setVolume (float volume); + FMOD_RESULT F_API getVolume (float *volume); + FMOD_RESULT F_API stop (); + + // Information only functions. + FMOD_RESULT F_API getName (char *name, int namelen); + FMOD_RESULT F_API getNumSounds (int *numsounds); + FMOD_RESULT F_API getSound (int index, Sound **sound); + FMOD_RESULT F_API getNumPlaying (int *numplaying); + + // Userdata set/get. + FMOD_RESULT F_API setUserData (void *userdata); + FMOD_RESULT F_API getUserData (void **userdata); + + FMOD_RESULT F_API getMemoryInfo (unsigned int memorybits, unsigned int event_memorybits, unsigned int *memoryused, FMOD_MEMORY_USAGE_DETAILS *memoryused_details); + }; + + /* + 'DSP' API + */ + class DSP + { + private: + + DSP(); /* Constructor made private so user cannot statically instance a DSP class. + Appropriate DSP creation or retrieval function must be used. */ + public: + + FMOD_RESULT F_API release (); + FMOD_RESULT F_API getSystemObject (System **system); + + // Connection / disconnection / input and output enumeration. + FMOD_RESULT F_API addInput (DSP *target, DSPConnection **connection); + FMOD_RESULT F_API disconnectFrom (DSP *target); + FMOD_RESULT F_API disconnectAll (bool inputs, bool outputs); + FMOD_RESULT F_API remove (); + FMOD_RESULT F_API getNumInputs (int *numinputs); + FMOD_RESULT F_API getNumOutputs (int *numoutputs); + FMOD_RESULT F_API getInput (int index, DSP **input, DSPConnection **inputconnection); + FMOD_RESULT F_API getOutput (int index, DSP **output, DSPConnection **outputconnection); + + // DSP unit control. + FMOD_RESULT F_API setActive (bool active); + FMOD_RESULT F_API getActive (bool *active); + FMOD_RESULT F_API setBypass (bool bypass); + FMOD_RESULT F_API getBypass (bool *bypass); + FMOD_RESULT F_API setSpeakerActive (FMOD_SPEAKER speaker, bool active); + FMOD_RESULT F_API getSpeakerActive (FMOD_SPEAKER speaker, bool *active); + FMOD_RESULT F_API reset (); + + + // DSP parameter control. + FMOD_RESULT F_API setParameter (int index, float value); + FMOD_RESULT F_API getParameter (int index, float *value, char *valuestr, int valuestrlen); + FMOD_RESULT F_API getNumParameters (int *numparams); + FMOD_RESULT F_API getParameterInfo (int index, char *name, char *label, char *description, int descriptionlen, float *min, float *max); + FMOD_RESULT F_API showConfigDialog (void *hwnd, bool show); + + // DSP attributes. + FMOD_RESULT F_API getInfo (char *name, unsigned int *version, int *channels, int *configwidth, int *configheight); + FMOD_RESULT F_API getType (FMOD_DSP_TYPE *type); + FMOD_RESULT F_API setDefaults (float frequency, float volume, float pan, int priority); + FMOD_RESULT F_API getDefaults (float *frequency, float *volume, float *pan, int *priority); + + // Userdata set/get. + FMOD_RESULT F_API setUserData (void *userdata); + FMOD_RESULT F_API getUserData (void **userdata); + + FMOD_RESULT F_API getMemoryInfo (unsigned int memorybits, unsigned int event_memorybits, unsigned int *memoryused, FMOD_MEMORY_USAGE_DETAILS *memoryused_details); + }; + + + /* + 'DSPConnection' API + */ + class DSPConnection + { + private: + + DSPConnection(); /* Constructor made private so user cannot statically instance a DSPConnection class. + Appropriate DSPConnection creation or retrieval function must be used. */ + + public: + + FMOD_RESULT F_API getInput (DSP **input); + FMOD_RESULT F_API getOutput (DSP **output); + FMOD_RESULT F_API setMix (float volume); + FMOD_RESULT F_API getMix (float *volume); + FMOD_RESULT F_API setLevels (FMOD_SPEAKER speaker, float *levels, int numlevels); + FMOD_RESULT F_API getLevels (FMOD_SPEAKER speaker, float *levels, int numlevels); + + // Userdata set/get. + FMOD_RESULT F_API setUserData (void *userdata); + FMOD_RESULT F_API getUserData (void **userdata); + + FMOD_RESULT F_API getMemoryInfo (unsigned int memorybits, unsigned int event_memorybits, unsigned int *memoryused, FMOD_MEMORY_USAGE_DETAILS *memoryused_details); + }; + + + /* + 'Geometry' API + */ + class Geometry + { + private: + + Geometry(); /* Constructor made private so user cannot statically instance a Geometry class. + Appropriate Geometry creation or retrieval function must be used. */ + + public: + + FMOD_RESULT F_API release (); + + // Polygon manipulation. + FMOD_RESULT F_API addPolygon (float directocclusion, float reverbocclusion, bool doublesided, int numvertices, const FMOD_VECTOR *vertices, int *polygonindex); + FMOD_RESULT F_API getNumPolygons (int *numpolygons); + FMOD_RESULT F_API getMaxPolygons (int *maxpolygons, int *maxvertices); + FMOD_RESULT F_API getPolygonNumVertices (int index, int *numvertices); + FMOD_RESULT F_API setPolygonVertex (int index, int vertexindex, const FMOD_VECTOR *vertex); + FMOD_RESULT F_API getPolygonVertex (int index, int vertexindex, FMOD_VECTOR *vertex); + FMOD_RESULT F_API setPolygonAttributes (int index, float directocclusion, float reverbocclusion, bool doublesided); + FMOD_RESULT F_API getPolygonAttributes (int index, float *directocclusion, float *reverbocclusion, bool *doublesided); + + // Object manipulation. + FMOD_RESULT F_API setActive (bool active); + FMOD_RESULT F_API getActive (bool *active); + FMOD_RESULT F_API setRotation (const FMOD_VECTOR *forward, const FMOD_VECTOR *up); + FMOD_RESULT F_API getRotation (FMOD_VECTOR *forward, FMOD_VECTOR *up); + FMOD_RESULT F_API setPosition (const FMOD_VECTOR *position); + FMOD_RESULT F_API getPosition (FMOD_VECTOR *position); + FMOD_RESULT F_API setScale (const FMOD_VECTOR *scale); + FMOD_RESULT F_API getScale (FMOD_VECTOR *scale); + FMOD_RESULT F_API save (void *data, int *datasize); + + // Userdata set/get. + FMOD_RESULT F_API setUserData (void *userdata); + FMOD_RESULT F_API getUserData (void **userdata); + + FMOD_RESULT F_API getMemoryInfo (unsigned int memorybits, unsigned int event_memorybits, unsigned int *memoryused, FMOD_MEMORY_USAGE_DETAILS *memoryused_details); + }; + + + /* + 'Reverb' API + */ + class Reverb + { + private: + + Reverb(); /* Constructor made private so user cannot statically instance a Reverb class. + Appropriate Reverb creation or retrieval function must be used. */ + + public: + + FMOD_RESULT F_API release (); + + // Reverb manipulation. + FMOD_RESULT F_API set3DAttributes (const FMOD_VECTOR *position, float mindistance, float maxdistance); + FMOD_RESULT F_API get3DAttributes (FMOD_VECTOR *position, float *mindistance,float *maxdistance); + FMOD_RESULT F_API setProperties (const FMOD_REVERB_PROPERTIES *properties); + FMOD_RESULT F_API getProperties (FMOD_REVERB_PROPERTIES *properties); + FMOD_RESULT F_API setActive (bool active); + FMOD_RESULT F_API getActive (bool *active); + + // Userdata set/get. + FMOD_RESULT F_API setUserData (void *userdata); + FMOD_RESULT F_API getUserData (void **userdata); + + FMOD_RESULT F_API getMemoryInfo (unsigned int memorybits, unsigned int event_memorybits, unsigned int *memoryused, FMOD_MEMORY_USAGE_DETAILS *memoryused_details); + }; +} + +#endif diff --git a/Lib/Include/FMOD/fmod_codec.h b/Lib/Include/FMOD/fmod_codec.h new file mode 100644 index 0000000..44652e9 --- /dev/null +++ b/Lib/Include/FMOD/fmod_codec.h @@ -0,0 +1,159 @@ +/* ==================================================================================================== */ +/* FMOD Ex - codec development header file. Copyright (c), Firelight Technologies Pty, Ltd. 2004-2009. */ +/* */ +/* Use this header if you are wanting to develop your own file format plugin to use with */ +/* FMOD's codec system. With this header you can make your own fileformat plugin that FMOD */ +/* can register and use. See the documentation and examples on how to make a working plugin. */ +/* */ +/* ==================================================================================================== */ + +#ifndef _FMOD_CODEC_H +#define _FMOD_CODEC_H + +typedef struct FMOD_CODEC_STATE FMOD_CODEC_STATE; +typedef struct FMOD_CODEC_WAVEFORMAT FMOD_CODEC_WAVEFORMAT; + +/* + Codec callbacks +*/ +typedef FMOD_RESULT (F_CALLBACK *FMOD_CODEC_OPENCALLBACK) (FMOD_CODEC_STATE *codec_state, FMOD_MODE usermode, FMOD_CREATESOUNDEXINFO *userexinfo); +typedef FMOD_RESULT (F_CALLBACK *FMOD_CODEC_CLOSECALLBACK) (FMOD_CODEC_STATE *codec_state); +typedef FMOD_RESULT (F_CALLBACK *FMOD_CODEC_READCALLBACK) (FMOD_CODEC_STATE *codec_state, void *buffer, unsigned int sizebytes, unsigned int *bytesread); +typedef FMOD_RESULT (F_CALLBACK *FMOD_CODEC_GETLENGTHCALLBACK) (FMOD_CODEC_STATE *codec_state, unsigned int *length, FMOD_TIMEUNIT lengthtype); +typedef FMOD_RESULT (F_CALLBACK *FMOD_CODEC_SETPOSITIONCALLBACK) (FMOD_CODEC_STATE *codec_state, int subsound, unsigned int position, FMOD_TIMEUNIT postype); +typedef FMOD_RESULT (F_CALLBACK *FMOD_CODEC_GETPOSITIONCALLBACK) (FMOD_CODEC_STATE *codec_state, unsigned int *position, FMOD_TIMEUNIT postype); +typedef FMOD_RESULT (F_CALLBACK *FMOD_CODEC_SOUNDCREATECALLBACK) (FMOD_CODEC_STATE *codec_state, int subsound, FMOD_SOUND *sound); +typedef FMOD_RESULT (F_CALLBACK *FMOD_CODEC_METADATACALLBACK) (FMOD_CODEC_STATE *codec_state, FMOD_TAGTYPE tagtype, char *name, void *data, unsigned int datalen, FMOD_TAGDATATYPE datatype, int unique); +typedef FMOD_RESULT (F_CALLBACK *FMOD_CODEC_GETWAVEFORMAT) (FMOD_CODEC_STATE *codec_state, int index, FMOD_CODEC_WAVEFORMAT *waveformat); + + +/* +[STRUCTURE] +[ + [DESCRIPTION] + When creating a codec, declare one of these and provide the relevant callbacks and name for FMOD to use when it opens and reads a file. + + [REMARKS] + Members marked with [in] mean the variable can be written to. The user can set the value. + Members marked with [out] mean the variable is modified by FMOD and is for reading purposes only. Do not change this value. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation 2, PlayStation Portable, PlayStation 3, Wii, Solaris, iPhone + + [SEE_ALSO] + FMOD_CODEC_STATE +] +*/ +typedef struct FMOD_CODEC_DESCRIPTION +{ + const char *name; /* [in] Name of the codec. */ + unsigned int version; /* [in] Plugin writer's version number. */ + int defaultasstream; /* [in] Tells FMOD to open the file as a stream when calling System::createSound, and not a static sample. Should normally be 0 (FALSE), because generally the user wants to decode the file into memory when using System::createSound. Mainly used for formats that decode for a very long time, or could use large amounts of memory when decoded. Usually sequenced formats such as mod/s3m/xm/it/midi fall into this category. It is mainly to stop users that don't know what they're doing from getting FMOD_ERR_MEMORY returned from createSound when they should have in fact called System::createStream or used FMOD_CREATESTREAM in System::createSound. */ + FMOD_TIMEUNIT timeunits; /* [in] When setposition codec is called, only these time formats will be passed to the codec. Use bitwise OR to accumulate different types. */ + FMOD_CODEC_OPENCALLBACK open; /* [in] Open callback for the codec for when FMOD tries to open a sound using this codec. */ + FMOD_CODEC_CLOSECALLBACK close; /* [in] Close callback for the codec for when FMOD tries to close a sound using this codec. */ + FMOD_CODEC_READCALLBACK read; /* [in] Read callback for the codec for when FMOD tries to read some data from the file to the destination format (specified in the open callback). */ + FMOD_CODEC_GETLENGTHCALLBACK getlength; /* [in] Callback to return the length of the song in whatever format required when Sound::getLength is called. */ + FMOD_CODEC_SETPOSITIONCALLBACK setposition; /* [in] Seek callback for the codec for when FMOD tries to seek within the file with Channel::setPosition. */ + FMOD_CODEC_GETPOSITIONCALLBACK getposition; /* [in] Tell callback for the codec for when FMOD tries to get the current position within the with Channel::getPosition. */ + FMOD_CODEC_SOUNDCREATECALLBACK soundcreate; /* [in] Sound creation callback for the codec when FMOD finishes creating the sound. (So the codec can set more parameters for the related created sound, ie loop points/mode or 3D attributes etc). */ + FMOD_CODEC_GETWAVEFORMAT getwaveformat; /* [in] Callback to tell FMOD about the waveformat of a particular subsound. This is to save memory, rather than saving 1000 FMOD_CODEC_WAVEFORMAT structures in the codec, the codec might have a more optimal way of storing this information. */ +} FMOD_CODEC_DESCRIPTION; + + +/* +[STRUCTURE] +[ + [DESCRIPTION] + Set these values marked 'in' to tell fmod what sort of sound to create. + The format, channels and frequency tell FMOD what sort of hardware buffer to create when you initialize your code. So if you wrote an MP3 codec that decoded to stereo 16bit integer PCM, you would specify FMOD_SOUND_FORMAT_PCM16, and channels would be equal to 2. + Members marked as 'out' are set by fmod. Do not modify these. Simply specify 0 for these values when declaring the structure, FMOD will fill in the values for you after creation with the correct function pointers. + + [REMARKS] + Members marked with [in] mean the variable can be written to. The user can set the value. + Members marked with [out] mean the variable is modified by FMOD and is for reading purposes only. Do not change this value. + + An FMOD file might be from disk, memory or network, however the file may be opened by the user. + + 'numsubsounds' should be 0 if the file is a normal single sound stream or sound. Examples of this would be .WAV, .WMA, .MP3, .AIFF. + 'numsubsounds' should be 1+ if the file is a container format, and does not contain wav data itself. Examples of these types would be CDDA (multiple CD tracks), FSB (contains multiple sounds), MIDI/MOD/S3M/XM/IT (contain instruments). + The arrays of format, channel, frequency, length and blockalign should point to arrays of information based on how many subsounds are in the format. If the number of subsounds is 0 then it should point to 1 of each attribute, the same as if the number of subsounds was 1. If subsounds was 100 for example, each pointer should point to an array of 100 of each attribute. + When a sound has 1 or more subsounds, you must play the individual sounds specified by first obtaining the subsound with Sound::getSubSound. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation 2, PlayStation Portable, PlayStation 3, Wii, Solaris, iPhone + + [SEE_ALSO] + FMOD_SOUND_FORMAT + FMOD_FILE_READCALLBACK + FMOD_FILE_SEEKCALLBACK + FMOD_CODEC_METADATACALLBACK + Sound::getSubSound + Sound::getNumSubSounds +] +*/ +struct FMOD_CODEC_WAVEFORMAT +{ + char name[256]; /* [in] Name of sound.*/ + FMOD_SOUND_FORMAT format; /* [in] Format for (decompressed) codec output, ie FMOD_SOUND_FORMAT_PCM8, FMOD_SOUND_FORMAT_PCM16.*/ + int channels; /* [in] Number of channels used by codec, ie mono = 1, stereo = 2. */ + int frequency; /* [in] Default frequency in hz of the codec, ie 44100. */ + unsigned int lengthbytes; /* [in] Length in bytes of the source data. */ + unsigned int lengthpcm; /* [in] Length in decompressed, PCM samples of the file, ie length in seconds * frequency. Used for Sound::getLength and for memory allocation of static decompressed sample data. */ + int blockalign; /* [in] Blockalign in decompressed, PCM samples of the optimal decode chunk size for this format. The codec read callback will be called in multiples of this value. */ + int loopstart; /* [in] Loopstart in decompressed, PCM samples of file. */ + int loopend; /* [in] Loopend in decompressed, PCM samples of file. */ + FMOD_MODE mode; /* [in] Mode to determine whether the sound should by default load as looping, non looping, 2d or 3d. */ + unsigned int channelmask; /* [in] Microsoft speaker channel mask, as defined for WAVEFORMATEXTENSIBLE and is found in ksmedia.h. Leave at 0 to play in natural speaker order. */ +}; + + +/* +[STRUCTURE] +[ + [DESCRIPTION] + Codec plugin structure that is passed into each callback. + + Set these numsubsounds and waveformat members when called in FMOD_CODEC_OPENCALLBACK to tell fmod what sort of sound to create. + + The format, channels and frequency tell FMOD what sort of hardware buffer to create when you initialize your code. So if you wrote an MP3 codec that decoded to stereo 16bit integer PCM, you would specify FMOD_SOUND_FORMAT_PCM16, and channels would be equal to 2. + + [REMARKS] + Members marked with [in] mean the variable can be written to. The user can set the value. + Members marked with [out] mean the variable is modified by FMOD and is for reading purposes only. Do not change this value. + + An FMOD file might be from disk, memory or internet, however the file may be opened by the user. + + 'numsubsounds' should be 0 if the file is a normal single sound stream or sound. Examples of this would be .WAV, .WMA, .MP3, .AIFF. + 'numsubsounds' should be 1+ if the file is a container format, and does not contain wav data itself. Examples of these types would be CDDA (multiple CD tracks), FSB (contains multiple sounds), DLS (contain instruments). + The arrays of format, channel, frequency, length and blockalign should point to arrays of information based on how many subsounds are in the format. If the number of subsounds is 0 then it should point to 1 of each attribute, the same as if the number of subsounds was 1. If subsounds was 100 for example, each pointer should point to an array of 100 of each attribute. + When a sound has 1 or more subsounds, you must play the individual sounds specified by first obtaining the subsound with Sound::getSubSound. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation 2, PlayStation Portable, PlayStation 3, Wii, Solaris, iPhone + + [SEE_ALSO] + FMOD_SOUND_FORMAT + FMOD_FILE_READCALLBACK + FMOD_FILE_SEEKCALLBACK + FMOD_CODEC_METADATACALLBACK + Sound::getSubSound + Sound::getNumSubSounds +] +*/ +struct FMOD_CODEC_STATE +{ + int numsubsounds; /* [in] Number of 'subsounds' in this sound. Anything other than 0 makes it a 'container' format (ie CDDA/DLS/FSB etc which contain 1 or more su bsounds). For most normal, single sound codec such as WAV/AIFF/MP3, this should be 0 as they are not a container for subsounds, they are the sound by itself. */ + FMOD_CODEC_WAVEFORMAT *waveformat; /* [in] Pointer to an array of format structures containing information about each sample. Can be 0 or NULL if FMOD_CODEC_GETWAVEFORMAT callback is preferred. The number of entries here must equal the number of subsounds defined in the subsound parameter. If numsubsounds = 0 then there should be 1 instance of this structure. */ + void *plugindata; /* [in] Plugin writer created data the codec author wants to attach to this object. */ + + void *filehandle; /* [out] This will return an internal FMOD file handle to use with the callbacks provided. */ + unsigned int filesize; /* [out] This will contain the size of the file in bytes. */ + FMOD_FILE_READCALLBACK fileread; /* [out] This will return a callable FMOD file function to use from codec. */ + FMOD_FILE_SEEKCALLBACK fileseek; /* [out] This will return a callable FMOD file function to use from codec. */ + FMOD_CODEC_METADATACALLBACK metadata; /* [out] This will return a callable FMOD metadata function to use from codec. */ +}; + +#endif + + diff --git a/Lib/Include/FMOD/fmod_dsp.h b/Lib/Include/FMOD/fmod_dsp.h new file mode 100644 index 0000000..1d007b7 --- /dev/null +++ b/Lib/Include/FMOD/fmod_dsp.h @@ -0,0 +1,759 @@ +/* ========================================================================================== */ +/* FMOD Ex - DSP header file. Copyright (c), Firelight Technologies Pty, Ltd. 2004-2009. */ +/* */ +/* Use this header if you are interested in delving deeper into the FMOD software mixing / */ +/* DSP engine. In this header you can find parameter structures for FMOD system reigstered */ +/* DSP effects and generators. */ +/* Also use this header if you are wanting to develop your own DSP plugin to use with FMOD's */ +/* dsp system. With this header you can make your own DSP plugin that FMOD can */ +/* register and use. See the documentation and examples on how to make a working plugin. */ +/* */ +/* ========================================================================================== */ + +#ifndef _FMOD_DSP_H +#define _FMOD_DSP_H + +typedef struct FMOD_DSP_STATE FMOD_DSP_STATE; + +/* + DSP callbacks +*/ +typedef FMOD_RESULT (F_CALLBACK *FMOD_DSP_CREATECALLBACK) (FMOD_DSP_STATE *dsp_state); +typedef FMOD_RESULT (F_CALLBACK *FMOD_DSP_RELEASECALLBACK) (FMOD_DSP_STATE *dsp_state); +typedef FMOD_RESULT (F_CALLBACK *FMOD_DSP_RESETCALLBACK) (FMOD_DSP_STATE *dsp_state); +typedef FMOD_RESULT (F_CALLBACK *FMOD_DSP_READCALLBACK) (FMOD_DSP_STATE *dsp_state, float *inbuffer, float *outbuffer, unsigned int length, int inchannels, int outchannels); +typedef FMOD_RESULT (F_CALLBACK *FMOD_DSP_SETPOSITIONCALLBACK)(FMOD_DSP_STATE *dsp_state, unsigned int pos); +typedef FMOD_RESULT (F_CALLBACK *FMOD_DSP_SETPARAMCALLBACK) (FMOD_DSP_STATE *dsp_state, int index, float value); +typedef FMOD_RESULT (F_CALLBACK *FMOD_DSP_GETPARAMCALLBACK) (FMOD_DSP_STATE *dsp_state, int index, float *value, char *valuestr); +typedef FMOD_RESULT (F_CALLBACK *FMOD_DSP_DIALOGCALLBACK) (FMOD_DSP_STATE *dsp_state, void *hwnd, int show); + +/* +[ENUM] +[ + [DESCRIPTION] + These definitions can be used for creating FMOD defined special effects or DSP units. + + [REMARKS] + To get them to be active, first create the unit, then add it somewhere into the DSP network, either at the front of the network near the soundcard unit to affect the global output (by using System::getDSPHead), or on a single channel (using Channel::getDSPHead). + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation 2, PlayStation Portable, PlayStation 3, Wii, Solaris, iPhone + + [SEE_ALSO] + System::createDSPByType +] +*/ +typedef enum +{ + FMOD_DSP_TYPE_UNKNOWN, /* This unit was created via a non FMOD plugin so has an unknown purpose. */ + FMOD_DSP_TYPE_MIXER, /* This unit does nothing but take inputs and mix them together then feed the result to the soundcard unit. */ + FMOD_DSP_TYPE_OSCILLATOR, /* This unit generates sine/square/saw/triangle or noise tones. */ + FMOD_DSP_TYPE_LOWPASS, /* This unit filters sound using a high quality, resonant lowpass filter algorithm but consumes more CPU time. */ + FMOD_DSP_TYPE_ITLOWPASS, /* This unit filters sound using a resonant lowpass filter algorithm that is used in Impulse Tracker, but with limited cutoff range (0 to 8060hz). */ + FMOD_DSP_TYPE_HIGHPASS, /* This unit filters sound using a resonant highpass filter algorithm. */ + FMOD_DSP_TYPE_ECHO, /* This unit produces an echo on the sound and fades out at the desired rate. */ + FMOD_DSP_TYPE_FLANGE, /* This unit produces a flange effect on the sound. */ + FMOD_DSP_TYPE_DISTORTION, /* This unit distorts the sound. */ + FMOD_DSP_TYPE_NORMALIZE, /* This unit normalizes or amplifies the sound to a certain level. */ + FMOD_DSP_TYPE_PARAMEQ, /* This unit attenuates or amplifies a selected frequency range. */ + FMOD_DSP_TYPE_PITCHSHIFT, /* This unit bends the pitch of a sound without changing the speed of playback. */ + FMOD_DSP_TYPE_CHORUS, /* This unit produces a chorus effect on the sound. */ + FMOD_DSP_TYPE_REVERB, /* This unit produces a reverb effect on the sound. */ + FMOD_DSP_TYPE_VSTPLUGIN, /* This unit allows the use of Steinberg VST plugins */ + FMOD_DSP_TYPE_WINAMPPLUGIN, /* This unit allows the use of Nullsoft Winamp plugins */ + FMOD_DSP_TYPE_ITECHO, /* This unit produces an echo on the sound and fades out at the desired rate as is used in Impulse Tracker. */ + FMOD_DSP_TYPE_COMPRESSOR, /* This unit implements dynamic compression (linked multichannel, wideband) */ + FMOD_DSP_TYPE_SFXREVERB, /* This unit implements SFX reverb */ + FMOD_DSP_TYPE_LOWPASS_SIMPLE, /* This unit filters sound using a simple lowpass with no resonance, but has flexible cutoff and is fast. */ + FMOD_DSP_TYPE_DELAY, /* This unit produces different delays on individual channels of the sound. */ + FMOD_DSP_TYPE_TREMOLO, /* This unit produces a tremolo / chopper effect on the sound. */ + FMOD_DSP_TYPE_FORCEINT = 65536 /* Makes sure this enum is signed 32bit. */ +} FMOD_DSP_TYPE; + + +/* +[STRUCTURE] +[ + [DESCRIPTION] + Structure to define a parameter for a DSP unit. + + [REMARKS] + Members marked with [in] mean the variable can be written to. The user can set the value. + Members marked with [out] mean the variable is modified by FMOD and is for reading purposes only. Do not change this value. + + The step parameter tells the gui or application that the parameter has a certain granularity. + For example in the example of cutoff frequency with a range from 100.0 to 22050.0 you might only want the selection to be in 10hz increments. For this you would simply use 10.0 as the step value. + For a boolean, you can use min = 0.0, max = 1.0, step = 1.0. This way the only possible values are 0.0 and 1.0. + Some applications may detect min = 0.0, max = 1.0, step = 1.0 and replace a graphical slider bar with a checkbox instead. + A step value of 1.0 would simulate integer values only. + A step value of 0.0 would mean the full floating point range is accessable. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation 2, PlayStation Portable, PlayStation 3, Wii, Solaris, iPhone + + [SEE_ALSO] + System::createDSP + DSP::setParameter +] +*/ +typedef struct FMOD_DSP_PARAMETERDESC +{ + float min; /* [in] Minimum value of the parameter (ie 100.0). */ + float max; /* [in] Maximum value of the parameter (ie 22050.0). */ + float defaultval; /* [in] Default value of parameter. */ + char name[16]; /* [in] Name of the parameter to be displayed (ie "Cutoff frequency"). */ + char label[16]; /* [in] Short string to be put next to value to denote the unit type (ie "hz"). */ + const char *description; /* [in] Description of the parameter to be displayed as a help item / tooltip for this parameter. */ +} FMOD_DSP_PARAMETERDESC; + + +/* +[STRUCTURE] +[ + [DESCRIPTION] + When creating a DSP unit, declare one of these and provide the relevant callbacks and name for FMOD to use when it creates and uses a DSP unit of this type. + + [REMARKS] + Members marked with [in] mean the variable can be written to. The user can set the value. + Members marked with [out] mean the variable is modified by FMOD and is for reading purposes only. Do not change this value. + + There are 2 different ways to change a parameter in this architecture. + One is to use DSP::setParameter / DSP::getParameter. This is platform independant and is dynamic, so new unknown plugins can have their parameters enumerated and used. + The other is to use DSP::showConfigDialog. This is platform specific and requires a GUI, and will display a dialog box to configure the plugin. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation 2, PlayStation Portable, PlayStation 3, Wii, Solaris, iPhone + + [SEE_ALSO] + System::createDSP + FMOD_DSP_STATE +] +*/ +typedef struct FMOD_DSP_DESCRIPTION +{ + char name[32]; /* [in] Name of the unit to be displayed in the network. */ + unsigned int version; /* [in] Plugin writer's version number. */ + int channels; /* [in] Number of channels. Use 0 to process whatever number of channels is currently in the network. >0 would be mostly used if the unit is a unit that only generates sound. */ + FMOD_DSP_CREATECALLBACK create; /* [in] Create callback. This is called when DSP unit is created. Can be null. */ + FMOD_DSP_RELEASECALLBACK release; /* [in] Release callback. This is called just before the unit is freed so the user can do any cleanup needed for the unit. Can be null. */ + FMOD_DSP_RESETCALLBACK reset; /* [in] Reset callback. This is called by the user to reset any history buffers that may need resetting for a filter, when it is to be used or re-used for the first time to its initial clean state. Use to avoid clicks or artifacts. */ + FMOD_DSP_READCALLBACK read; /* [in] Read callback. Processing is done here. Can be null. */ + FMOD_DSP_SETPOSITIONCALLBACK setposition; /* [in] Set position callback. This is called if the unit wants to update its position info but not process data, or reset a cursor position internally if it is reading data from a certain source. Can be null. */ + + int numparameters; /* [in] Number of parameters used in this filter. The user finds this with DSP::getNumParameters */ + FMOD_DSP_PARAMETERDESC *paramdesc; /* [in] Variable number of parameter structures. */ + FMOD_DSP_SETPARAMCALLBACK setparameter; /* [in] This is called when the user calls DSP::setParameter. Can be null. */ + FMOD_DSP_GETPARAMCALLBACK getparameter; /* [in] This is called when the user calls DSP::getParameter. Can be null. */ + FMOD_DSP_DIALOGCALLBACK config; /* [in] This is called when the user calls DSP::showConfigDialog. Can be used to display a dialog to configure the filter. Can be null. */ + int configwidth; /* [in] Width of config dialog graphic if there is one. 0 otherwise.*/ + int configheight; /* [in] Height of config dialog graphic if there is one. 0 otherwise.*/ + void *userdata; /* [in] Optional. Specify 0 to ignore. This is user data to be attached to the DSP unit during creation. Access via DSP::getUserData. */ +} FMOD_DSP_DESCRIPTION; + + +/* +[STRUCTURE] +[ + [DESCRIPTION] + DSP plugin structure that is passed into each callback. + + [REMARKS] + Members marked with [in] mean the variable can be written to. The user can set the value. + Members marked with [out] mean the variable is modified by FMOD and is for reading purposes only. Do not change this value. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation 2, PlayStation Portable, PlayStation 3, Wii, Solaris, iPhone + + [SEE_ALSO] + FMOD_DSP_DESCRIPTION +] +*/ +struct FMOD_DSP_STATE +{ + FMOD_DSP *instance; /* [out] Handle to the DSP hand the user created. Not to be modified. C++ users cast to FMOD::DSP to use. */ + void *plugindata; /* [in] Plugin writer created data the output author wants to attach to this object. */ + unsigned short speakermask; /* Specifies which speakers the DSP effect is active on */ +}; + + +/* + =================================================================================================== + + FMOD built in effect parameters. + Use DSP::setParameter with these enums for the 'index' parameter. + + =================================================================================================== +*/ + +/* +[ENUM] +[ + [DESCRIPTION] + Parameter types for the FMOD_DSP_TYPE_OSCILLATOR filter. + + [REMARKS] + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation 2, PlayStation Portable, PlayStation 3, Wii, Solaris, iPhone + + [SEE_ALSO] + DSP::setParameter + DSP::getParameter + FMOD_DSP_TYPE +] +*/ +typedef enum +{ + FMOD_DSP_OSCILLATOR_TYPE, /* Waveform type. 0 = sine. 1 = square. 2 = sawup. 3 = sawdown. 4 = triangle. 5 = noise. */ + FMOD_DSP_OSCILLATOR_RATE /* Frequency of the sinewave in hz. 1.0 to 22000.0. Default = 220.0. */ +} FMOD_DSP_OSCILLATOR; + + +/* +[ENUM] +[ + [DESCRIPTION] + Parameter types for the FMOD_DSP_TYPE_LOWPASS filter. + + [REMARKS] + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation 2, PlayStation Portable, PlayStation 3, Wii, Solaris, iPhone + + [SEE_ALSO] + DSP::setParameter + DSP::getParameter + FMOD_DSP_TYPE +] +*/ +typedef enum +{ + FMOD_DSP_LOWPASS_CUTOFF, /* Lowpass cutoff frequency in hz. 10.0 to 22000.0. Default = 5000.0. */ + FMOD_DSP_LOWPASS_RESONANCE /* Lowpass resonance Q value. 1.0 to 10.0. Default = 1.0. */ +} FMOD_DSP_LOWPASS; + + +/* +[ENUM] +[ + [DESCRIPTION] + Parameter types for the FMOD_DSP_TYPE_ITLOWPASS filter. + This is different to the default FMOD_DSP_TYPE_ITLOWPASS filter in that it uses a different quality algorithm and is + the filter used to produce the correct sounding playback in .IT files. + FMOD Ex's .IT playback uses this filter. + + [REMARKS] + Note! This filter actually has a limited cutoff frequency below the specified maximum, due to its limited design, + so for a more open range filter use FMOD_DSP_LOWPASS or if you don't mind not having resonance, + FMOD_DSP_LOWPASS_SIMPLE. + The effective maximum cutoff is about 8060hz. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation 2, PlayStation Portable, PlayStation 3, Wii, Solaris, iPhone + + [SEE_ALSO] + DSP::setParameter + DSP::getParameter + FMOD_DSP_TYPE +] +*/ +typedef enum +{ + FMOD_DSP_ITLOWPASS_CUTOFF, /* Lowpass cutoff frequency in hz. 1.0 to 22000.0. Default = 5000.0/ */ + FMOD_DSP_ITLOWPASS_RESONANCE /* Lowpass resonance Q value. 0.0 to 127.0. Default = 1.0. */ +} FMOD_DSP_ITLOWPASS; + + +/* +[ENUM] +[ + [DESCRIPTION] + Parameter types for the FMOD_DSP_TYPE_HIGHPASS filter. + + [REMARKS] + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation 2, PlayStation Portable, PlayStation 3, Wii, Solaris, iPhone + + [SEE_ALSO] + DSP::setParameter + DSP::getParameter + FMOD_DSP_TYPE +] +*/ +typedef enum +{ + FMOD_DSP_HIGHPASS_CUTOFF, /* Highpass cutoff frequency in hz. 1.0 to output 22000.0. Default = 5000.0. */ + FMOD_DSP_HIGHPASS_RESONANCE /* Highpass resonance Q value. 1.0 to 10.0. Default = 1.0. */ +} FMOD_DSP_HIGHPASS; + + +/* +[ENUM] +[ + [DESCRIPTION] + Parameter types for the FMOD_DSP_TYPE_ECHO filter. + + [REMARKS] + Note. Every time the delay is changed, the plugin re-allocates the echo buffer. This means the echo will dissapear at that time while it refills its new buffer. + Larger echo delays result in larger amounts of memory allocated. + + 'maxchannels' also dictates the amount of memory allocated. By default, the maxchannels value is 0. If FMOD is set to stereo, the echo unit will allocate enough memory for 2 channels. If it is 5.1, it will allocate enough memory for a 6 channel echo, etc. + If the echo effect is only ever applied to the global mix (ie it was added with System::addDSP), then 0 is the value to set as it will be enough to handle all speaker modes. + When the echo is added to a channel (ie Channel::addDSP) then the channel count that comes in could be anything from 1 to 8 possibly. It is only in this case where you might want to increase the channel count above the output's channel count. + If a channel echo is set to a lower number than the sound's channel count that is coming in, it will not echo the sound. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation 2, PlayStation Portable, PlayStation 3, Wii, Solaris, iPhone + + [SEE_ALSO] + DSP::setParameter + DSP::getParameter + FMOD_DSP_TYPE +] +*/ +typedef enum +{ + FMOD_DSP_ECHO_DELAY, /* Echo delay in ms. 10 to 5000. Default = 500. */ + FMOD_DSP_ECHO_DECAYRATIO, /* Echo decay per delay. 0 to 1. 1.0 = No decay, 0.0 = total decay (ie simple 1 line delay). Default = 0.5. */ + FMOD_DSP_ECHO_MAXCHANNELS, /* Maximum channels supported. 0 to 16. 0 = same as fmod's default output polyphony, 1 = mono, 2 = stereo etc. See remarks for more. Default = 0. It is suggested to leave at 0! */ + FMOD_DSP_ECHO_DRYMIX, /* Volume of original signal to pass to output. 0.0 to 1.0. Default = 1.0. */ + FMOD_DSP_ECHO_WETMIX /* Volume of echo signal to pass to output. 0.0 to 1.0. Default = 1.0. */ +} FMOD_DSP_ECHO; + + +/* +[ENUM] +[ + [DESCRIPTION] + Parameter types for the FMOD_DSP_TYPE_DELAY filter. + + [REMARKS] + Note. Every time MaxDelay is changed, the plugin re-allocates the delay buffer. This means the delay will dissapear at that time while it refills its new buffer. + A larger MaxDelay results in larger amounts of memory allocated. + Channel delays above MaxDelay will be clipped to MaxDelay and the delay buffer will not be resized. + + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation 2, PlayStation Portable, PlayStation 3, Wii, Solaris, iPhone + + [SEE_ALSO] + DSP::setParameter + DSP::getParameter + FMOD_DSP_TYPE +] +*/ +typedef enum +{ + FMOD_DSP_DELAY_CH0, /* Channel #0 Delay in ms. 0 to 10000. Default = 0. */ + FMOD_DSP_DELAY_CH1, /* Channel #1 Delay in ms. 0 to 10000. Default = 0. */ + FMOD_DSP_DELAY_CH2, /* Channel #2 Delay in ms. 0 to 10000. Default = 0. */ + FMOD_DSP_DELAY_CH3, /* Channel #3 Delay in ms. 0 to 10000. Default = 0. */ + FMOD_DSP_DELAY_CH4, /* Channel #4 Delay in ms. 0 to 10000. Default = 0. */ + FMOD_DSP_DELAY_CH5, /* Channel #5 Delay in ms. 0 to 10000. Default = 0. */ + FMOD_DSP_DELAY_CH6, /* Channel #6 Delay in ms. 0 to 10000. Default = 0. */ + FMOD_DSP_DELAY_CH7, /* Channel #7 Delay in ms. 0 to 10000. Default = 0. */ + FMOD_DSP_DELAY_CH8, /* Channel #8 Delay in ms. 0 to 10000. Default = 0. */ + FMOD_DSP_DELAY_CH9, /* Channel #9 Delay in ms. 0 to 10000. Default = 0. */ + FMOD_DSP_DELAY_CH10, /* Channel #10 Delay in ms. 0 to 10000. Default = 0. */ + FMOD_DSP_DELAY_CH11, /* Channel #11 Delay in ms. 0 to 10000. Default = 0. */ + FMOD_DSP_DELAY_CH12, /* Channel #12 Delay in ms. 0 to 10000. Default = 0. */ + FMOD_DSP_DELAY_CH13, /* Channel #13 Delay in ms. 0 to 10000. Default = 0. */ + FMOD_DSP_DELAY_CH14, /* Channel #14 Delay in ms. 0 to 10000. Default = 0. */ + FMOD_DSP_DELAY_CH15, /* Channel #15 Delay in ms. 0 to 10000. Default = 0. */ + FMOD_DSP_DELAY_MAXDELAY, /* Maximum delay in ms. 0 to 10000. Default = 10. */ +} FMOD_DSP_DELAY; + + +/* +[ENUM] +[ + [DESCRIPTION] + Parameter types for the FMOD_DSP_TYPE_FLANGE filter. + + [REMARKS] + Flange is an effect where the signal is played twice at the same time, and one copy slides back and forth creating a whooshing or flanging effect. + As there are 2 copies of the same signal, by default each signal is given 50% mix, so that the total is not louder than the original unaffected signal. + + Flange depth is a percentage of a 10ms shift from the original signal. Anything above 10ms is not considered flange because to the ear it begins to 'echo' so 10ms is the highest value possible. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation 2, PlayStation Portable, PlayStation 3, Wii, Solaris, iPhone + + [SEE_ALSO] + DSP::setParameter + DSP::getParameter + FMOD_DSP_TYPE +] +*/ +typedef enum +{ + FMOD_DSP_FLANGE_DRYMIX, /* Volume of original signal to pass to output. 0.0 to 1.0. Default = 0.45. */ + FMOD_DSP_FLANGE_WETMIX, /* Volume of flange signal to pass to output. 0.0 to 1.0. Default = 0.55. */ + FMOD_DSP_FLANGE_DEPTH, /* Flange depth. 0.01 to 1.0. Default = 1.0. */ + FMOD_DSP_FLANGE_RATE /* Flange speed in hz. 0.0 to 20.0. Default = 0.1. */ +} FMOD_DSP_FLANGE; + + +/* +[ENUM] +[ + [DESCRIPTION] + Parameter types for the FMOD_DSP_TYPE_TREMOLO filter. + + [REMARKS] + The tremolo effect varies the amplitude of a sound. Depending on the settings, this unit can produce a tremolo, chopper or auto-pan effect. + + The shape of the LFO (low freq. oscillator) can morphed between sine, triangle and sawtooth waves using the FMOD_DSP_TREMOLO_SHAPE and FMOD_DSP_TREMOLO_SKEW parameters. + FMOD_DSP_TREMOLO_DUTY and FMOD_DSP_TREMOLO_SQUARE are useful for a chopper-type effect where the first controls the on-time duration and second controls the flatness of the envelope. + FMOD_DSP_TREMOLO_SPREAD varies the LFO phase between channels to get an auto-pan effect. This works best with a sine shape LFO. + The LFO can be synchronized using the FMOD_DSP_TREMOLO_PHASE parameter which sets its instantaneous phase. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation 2, PlayStation Portable, PlayStation 3, Wii, Solaris, iPhone + + [SEE_ALSO] + DSP::setParameter + DSP::getParameter + FMOD_DSP_TYPE +] +*/ +typedef enum +{ + FMOD_DSP_TREMOLO_FREQUENCY, /* LFO frequency in Hz. 0.1 to 20. Default = 4. */ + FMOD_DSP_TREMOLO_DEPTH, /* Tremolo depth. 0 to 1. Default = 0. */ + FMOD_DSP_TREMOLO_SHAPE, /* LFO shape morph between triangle and sine. 0 to 1. Default = 0. */ + FMOD_DSP_TREMOLO_SKEW, /* Time-skewing of LFO cycle. -1 to 1. Default = 0. */ + FMOD_DSP_TREMOLO_DUTY, /* LFO on-time. 0 to 1. Default = 0.5. */ + FMOD_DSP_TREMOLO_SQUARE, /* Flatness of the LFO shape. 0 to 1. Default = 0. */ + FMOD_DSP_TREMOLO_PHASE, /* Instantaneous LFO phase. 0 to 1. Default = 0. */ + FMOD_DSP_TREMOLO_SPREAD /* Rotation / auto-pan effect. -1 to 1. Default = 0. */ +} FMOD_DSP_TREMOLO; + + +/* +[ENUM] +[ + [DESCRIPTION] + Parameter types for the FMOD_DSP_TYPE_DISTORTION filter. + + [REMARKS] + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation 2, PlayStation Portable, PlayStation 3, Wii, Solaris, iPhone + + [SEE_ALSO] + DSP::setParameter + DSP::getParameter + FMOD_DSP_TYPE +] +*/ +typedef enum +{ + FMOD_DSP_DISTORTION_LEVEL /* Distortion value. 0.0 to 1.0. Default = 0.5. */ +} FMOD_DSP_DISTORTION; + + +/* +[ENUM] +[ + [DESCRIPTION] + Parameter types for the FMOD_DSP_TYPE_NORMALIZE filter. + + [REMARKS] + Normalize amplifies the sound based on the maximum peaks within the signal. + For example if the maximum peaks in the signal were 50% of the bandwidth, it would scale the whole sound by 2. + The lower threshold value makes the normalizer ignores peaks below a certain point, to avoid over-amplification if a loud signal suddenly came in, and also to avoid amplifying to maximum things like background hiss. + + Because FMOD is a realtime audio processor, it doesn't have the luxury of knowing the peak for the whole sound (ie it can't see into the future), so it has to process data as it comes in. + To avoid very sudden changes in volume level based on small samples of new data, fmod fades towards the desired amplification which makes for smooth gain control. The fadetime parameter can control this. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation 2, PlayStation Portable, PlayStation 3, Wii, Solaris, iPhone + + [SEE_ALSO] + DSP::setParameter + DSP::getParameter + FMOD_DSP_TYPE +] +*/ +typedef enum +{ + FMOD_DSP_NORMALIZE_FADETIME, /* Time to ramp the silence to full in ms. 0.0 to 20000.0. Default = 5000.0. */ + FMOD_DSP_NORMALIZE_THRESHHOLD, /* Lower volume range threshold to ignore. 0.0 to 1.0. Default = 0.1. Raise higher to stop amplification of very quiet signals. */ + FMOD_DSP_NORMALIZE_MAXAMP /* Maximum amplification allowed. 1.0 to 100000.0. Default = 20.0. 1.0 = no amplifaction, higher values allow more boost. */ +} FMOD_DSP_NORMALIZE; + + +/* +[ENUM] +[ + [DESCRIPTION] + Parameter types for the FMOD_DSP_TYPE_PARAMEQ filter. + + [REMARKS] + Parametric EQ is a bandpass filter that attenuates or amplifies a selected frequency and its neighbouring frequencies. + + To create a multi-band EQ create multiple FMOD_DSP_TYPE_PARAMEQ units and set each unit to different frequencies, for example 1000hz, 2000hz, 4000hz, 8000hz, 16000hz with a range of 1 octave each. + + When a frequency has its gain set to 1.0, the sound will be unaffected and represents the original signal exactly. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation 2, PlayStation Portable, PlayStation 3, Wii, Solaris, iPhone + + [SEE_ALSO] + DSP::setParameter + DSP::getParameter + FMOD_DSP_TYPE +] +*/ +typedef enum +{ + FMOD_DSP_PARAMEQ_CENTER, /* Frequency center. 20.0 to 22000.0. Default = 8000.0. */ + FMOD_DSP_PARAMEQ_BANDWIDTH, /* Octave range around the center frequency to filter. 0.2 to 5.0. Default = 1.0. */ + FMOD_DSP_PARAMEQ_GAIN /* Frequency Gain. 0.05 to 3.0. Default = 1.0. */ +} FMOD_DSP_PARAMEQ; + + + +/* +[ENUM] +[ + [DESCRIPTION] + Parameter types for the FMOD_DSP_TYPE_PITCHSHIFT filter. + + [REMARKS] + This pitch shifting unit can be used to change the pitch of a sound without speeding it up or slowing it down. + It can also be used for time stretching or scaling, for example if the pitch was doubled, and the frequency of the sound was halved, the pitch of the sound would sound correct but it would be twice as slow. + + Warning! This filter is very computationally expensive! Similar to a vocoder, it requires several overlapping FFT and IFFT's to produce smooth output, and can require around 440mhz for 1 stereo 48khz signal using the default settings. + Reducing the signal to mono will half the cpu usage. + Reducing this will lower audio quality, but what settings to use are largely dependant on the sound being played. A noisy polyphonic signal will need higher fft size compared to a speaking voice for example. + + This pitch shifter is based on the pitch shifter code at http://www.dspdimension.com, written by Stephan M. Bernsee. + The original code is COPYRIGHT 1999-2003 Stephan M. Bernsee . + + 'maxchannels' dictates the amount of memory allocated. By default, the maxchannels value is 0. If FMOD is set to stereo, the pitch shift unit will allocate enough memory for 2 channels. If it is 5.1, it will allocate enough memory for a 6 channel pitch shift, etc. + If the pitch shift effect is only ever applied to the global mix (ie it was added with System::addDSP), then 0 is the value to set as it will be enough to handle all speaker modes. + When the pitch shift is added to a channel (ie Channel::addDSP) then the channel count that comes in could be anything from 1 to 8 possibly. It is only in this case where you might want to increase the channel count above the output's channel count. + If a channel pitch shift is set to a lower number than the sound's channel count that is coming in, it will not pitch shift the sound. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation 2, PlayStation Portable, PlayStation 3, Wii, Solaris, iPhone + + [SEE_ALSO] + DSP::setParameter + DSP::getParameter + FMOD_DSP_TYPE +] +*/ +typedef enum +{ + FMOD_DSP_PITCHSHIFT_PITCH, /* Pitch value. 0.5 to 2.0. Default = 1.0. 0.5 = one octave down, 2.0 = one octave up. 1.0 does not change the pitch. */ + FMOD_DSP_PITCHSHIFT_FFTSIZE, /* FFT window size. 256, 512, 1024, 2048, 4096. Default = 1024. Increase this to reduce 'smearing'. This effect is a warbling sound similar to when an mp3 is encoded at very low bitrates. */ + FMOD_DSP_PITCHSHIFT_OVERLAP, /* Removed. Do not use. FMOD now uses 4 overlaps and cannot be changed. */ + FMOD_DSP_PITCHSHIFT_MAXCHANNELS /* Maximum channels supported. 0 to 16. 0 = same as fmod's default output polyphony, 1 = mono, 2 = stereo etc. See remarks for more. Default = 0. It is suggested to leave at 0! */ +} FMOD_DSP_PITCHSHIFT; + + + +/* +[ENUM] +[ + [DESCRIPTION] + Parameter types for the FMOD_DSP_TYPE_CHORUS filter. + + [REMARKS] + Chrous is an effect where the sound is more 'spacious' due to 1 to 3 versions of the sound being played along side the original signal but with the pitch of each copy modulating on a sine wave. + This is a highly configurable chorus unit. It supports 3 taps, small and large delay times and also feedback. + This unit also could be used to do a simple echo, or a flange effect. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation 2, PlayStation Portable, PlayStation 3, Wii, Solaris, iPhone + + [SEE_ALSO] + DSP::setParameter + DSP::getParameter + FMOD_DSP_TYPE +] +*/ +typedef enum +{ + FMOD_DSP_CHORUS_DRYMIX, /* Volume of original signal to pass to output. 0.0 to 1.0. Default = 0.5. */ + FMOD_DSP_CHORUS_WETMIX1, /* Volume of 1st chorus tap. 0.0 to 1.0. Default = 0.5. */ + FMOD_DSP_CHORUS_WETMIX2, /* Volume of 2nd chorus tap. This tap is 90 degrees out of phase of the first tap. 0.0 to 1.0. Default = 0.5. */ + FMOD_DSP_CHORUS_WETMIX3, /* Volume of 3rd chorus tap. This tap is 90 degrees out of phase of the second tap. 0.0 to 1.0. Default = 0.5. */ + FMOD_DSP_CHORUS_DELAY, /* Chorus delay in ms. 0.1 to 100.0. Default = 40.0 ms. */ + FMOD_DSP_CHORUS_RATE, /* Chorus modulation rate in hz. 0.0 to 20.0. Default = 0.8 hz. */ + FMOD_DSP_CHORUS_DEPTH, /* Chorus modulation depth. 0.0 to 1.0. Default = 0.03. */ + FMOD_DSP_CHORUS_FEEDBACK /* Chorus feedback. Controls how much of the wet signal gets fed back into the chorus buffer. 0.0 to 1.0. Default = 0.0. */ +} FMOD_DSP_CHORUS; + + + +/* +[ENUM] +[ + [DESCRIPTION] + Parameter types for the FMOD_DSP_TYPE_REVERB filter. + + [REMARKS] + Based on freeverb by Jezar at Dreampoint - http://www.dreampoint.co.uk. + This reverb is limited to stereo processing only, and may be removed in the future. It is recommended to use FMOD_DSP_SFXREVERB instead which is higher quality and supports 5.1 and 7.1 output. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation 2, PlayStation Portable, PlayStation 3, Wii, Solaris, iPhone + + [SEE_ALSO] + DSP::setParameter + DSP::getParameter + FMOD_DSP_TYPE +] +*/ +typedef enum +{ + FMOD_DSP_REVERB_ROOMSIZE, /* Roomsize. 0.0 to 1.0. Default = 0.5 */ + FMOD_DSP_REVERB_DAMP, /* Damp. 0.0 to 1.0. Default = 0.5 */ + FMOD_DSP_REVERB_WETMIX, /* Wet mix. 0.0 to 1.0. Default = 0.33 */ + FMOD_DSP_REVERB_DRYMIX, /* Dry mix. 0.0 to 1.0. Default = 0.66 */ + FMOD_DSP_REVERB_WIDTH, /* Stereo width. 0.0 to 1.0. Default = 1.0 */ + FMOD_DSP_REVERB_MODE /* Mode. 0 (normal), 1 (freeze). Default = 0 */ +} FMOD_DSP_REVERB; + + +/* +[ENUM] +[ + [DESCRIPTION] + Parameter types for the FMOD_DSP_TYPE_ITECHO filter. + This is effectively a software based echo filter that emulates the DirectX DMO echo effect. Impulse tracker files can support this, and FMOD will produce the effect on ANY platform, not just those that support DirectX effects! + + [REMARKS] + Note. Every time the delay is changed, the plugin re-allocates the echo buffer. This means the echo will dissapear at that time while it refills its new buffer. + Larger echo delays result in larger amounts of memory allocated. + + As this is a stereo filter made mainly for IT playback, it is targeted for stereo signals. + With mono signals only the FMOD_DSP_ITECHO_LEFTDELAY is used. + For multichannel signals (>2) there will be no echo on those channels. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation 2, PlayStation Portable, PlayStation 3, Wii, Solaris, iPhone + + [SEE_ALSO] + DSP::SetParameter + DSP::GetParameter + FMOD_DSP_TYPE + System::addDSP +] +*/ +typedef enum +{ + FMOD_DSP_ITECHO_WETDRYMIX, /* Ratio of wet (processed) signal to dry (unprocessed) signal. Must be in the range from 0.0 through 100.0 (all wet). The default value is 50. */ + FMOD_DSP_ITECHO_FEEDBACK, /* Percentage of output fed back into input, in the range from 0.0 through 100.0. The default value is 50. */ + FMOD_DSP_ITECHO_LEFTDELAY, /* Delay for left channel, in milliseconds, in the range from 1.0 through 2000.0. The default value is 500 ms. */ + FMOD_DSP_ITECHO_RIGHTDELAY, /* Delay for right channel, in milliseconds, in the range from 1.0 through 2000.0. The default value is 500 ms. */ + FMOD_DSP_ITECHO_PANDELAY /* Value that specifies whether to swap left and right delays with each successive echo. The default value is zero, meaning no swap. Possible values are defined as 0.0 (equivalent to FALSE) and 1.0 (equivalent to TRUE). CURRENTLY NOT SUPPORTED. */ +} FMOD_DSP_ITECHO; + +/* +[ENUM] +[ + [DESCRIPTION] + Parameter types for the FMOD_DSP_TYPE_COMPRESSOR unit. + This is a simple linked multichannel software limiter that is uniform across the whole spectrum. + + [REMARKS] + The limiter is not guaranteed to catch every peak above the threshold level, + because it cannot apply gain reduction instantaneously - the time delay is + determined by the attack time. However setting the attack time too short will + distort the sound, so it is a compromise. High level peaks can be avoided by + using a short attack time - but not too short, and setting the threshold a few + decibels below the critical level. + + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation 2, PlayStation Portable, PlayStation 3, Wii, Solaris, iPhone + + [SEE_ALSO] + DSP::SetParameter + DSP::GetParameter + FMOD_DSP_TYPE + System::addDSP +] +*/ +typedef enum +{ + FMOD_DSP_COMPRESSOR_THRESHOLD, /* Threshold level (dB) in the range from -60 through 0. The default value is 0. */ + FMOD_DSP_COMPRESSOR_ATTACK, /* Gain reduction attack time (milliseconds), in the range from 10 through 200. The default value is 50. */ + FMOD_DSP_COMPRESSOR_RELEASE, /* Gain reduction release time (milliseconds), in the range from 20 through 1000. The default value is 50. */ + FMOD_DSP_COMPRESSOR_GAINMAKEUP /* Make-up gain (dB) applied after limiting, in the range from 0 through 30. The default value is 0. */ +} FMOD_DSP_COMPRESSOR; + +/* +[ENUM] +[ + [DESCRIPTION] + Parameter types for the FMOD_DSP_TYPE_SFXREVERB unit. + + [REMARKS] + This is a high quality I3DL2 based reverb which improves greatly on FMOD_DSP_REVERB. + On top of the I3DL2 property set, "Dry Level" is also included to allow the dry mix to be changed. + + These properties can be set with presets in FMOD_REVERB_PRESETS. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation 2, PlayStation Portable, PlayStation 3, Wii, Solaris, iPhone + + [SEE_ALSO] + DSP::SetParameter + DSP::GetParameter + FMOD_DSP_TYPE + System::addDSP + FMOD_REVERB_PRESETS +] +*/ +typedef enum +{ + FMOD_DSP_SFXREVERB_DRYLEVEL, /* Dry Level : Mix level of dry signal in output in mB. Ranges from -10000.0 to 0.0. Default is 0. */ + FMOD_DSP_SFXREVERB_ROOM, /* Room : Room effect level at low frequencies in mB. Ranges from -10000.0 to 0.0. Default is -10000.0. */ + FMOD_DSP_SFXREVERB_ROOMHF, /* Room HF : Room effect high-frequency level re. low frequency level in mB. Ranges from -10000.0 to 0.0. Default is 0.0. */ + FMOD_DSP_SFXREVERB_ROOMROLLOFFFACTOR, /* Room Rolloff : Like DS3D flRolloffFactor but for room effect. Ranges from 0.0 to 10.0. Default is 10.0 */ + FMOD_DSP_SFXREVERB_DECAYTIME, /* Decay Time : Reverberation decay time at low-frequencies in seconds. Ranges from 0.1 to 20.0. Default is 1.0. */ + FMOD_DSP_SFXREVERB_DECAYHFRATIO, /* Decay HF Ratio : High-frequency to low-frequency decay time ratio. Ranges from 0.1 to 2.0. Default is 0.5. */ + FMOD_DSP_SFXREVERB_REFLECTIONSLEVEL, /* Reflections : Early reflections level relative to room effect in mB. Ranges from -10000.0 to 1000.0. Default is -10000.0. */ + FMOD_DSP_SFXREVERB_REFLECTIONSDELAY, /* Reflect Delay : Delay time of first reflection in seconds. Ranges from 0.0 to 0.3. Default is 0.02. */ + FMOD_DSP_SFXREVERB_REVERBLEVEL, /* Reverb : Late reverberation level relative to room effect in mB. Ranges from -10000.0 to 2000.0. Default is 0.0. */ + FMOD_DSP_SFXREVERB_REVERBDELAY, /* Reverb Delay : Late reverberation delay time relative to first reflection in seconds. Ranges from 0.0 to 0.1. Default is 0.04. */ + FMOD_DSP_SFXREVERB_DIFFUSION, /* Diffusion : Reverberation diffusion (echo density) in percent. Ranges from 0.0 to 100.0. Default is 100.0. */ + FMOD_DSP_SFXREVERB_DENSITY, /* Density : Reverberation density (modal density) in percent. Ranges from 0.0 to 100.0. Default is 100.0. */ + FMOD_DSP_SFXREVERB_HFREFERENCE, /* HF Reference : Reference high frequency in Hz. Ranges from 20.0 to 20000.0. Default is 5000.0. */ + FMOD_DSP_SFXREVERB_ROOMLF, /* Room LF : Room effect low-frequency level in mB. Ranges from -10000.0 to 0.0. Default is 0.0. */ + FMOD_DSP_SFXREVERB_LFREFERENCE /* LF Reference : Reference low-frequency in Hz. Ranges from 20.0 to 1000.0. Default is 250.0. */ +} FMOD_DSP_SFXREVERB; + +/* +[ENUM] +[ + [DESCRIPTION] + Parameter types for the FMOD_DSP_TYPE_LOWPASS_SIMPLE filter. + This is a very simple low pass filter, based on two single-pole RC time-constant modules. + The emphasis is on speed rather than accuracy, so this should not be used for task requiring critical filtering. + + [REMARKS] + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation 2, PlayStation Portable, PlayStation 3, Wii, Solaris, iPhone + + [SEE_ALSO] + DSP::setParameter + DSP::getParameter + FMOD_DSP_TYPE +] +*/ +typedef enum +{ + FMOD_DSP_LOWPASS_SIMPLE_CUTOFF /* Lowpass cutoff frequency in hz. 10.0 to 22000.0. Default = 5000.0 */ +} FMOD_DSP_LOWPASS_SIMPLE; + +#endif + diff --git a/Lib/Include/FMOD/fmod_errors.h b/Lib/Include/FMOD/fmod_errors.h new file mode 100644 index 0000000..6c29f64 --- /dev/null +++ b/Lib/Include/FMOD/fmod_errors.h @@ -0,0 +1,125 @@ + +/* ============================================================================================== */ +/* FMOD Ex - Error string header file. Copyright (c), Firelight Technologies Pty, Ltd. 2004-2009. */ +/* */ +/* Use this header if you want to store or display a string version / english explanation of */ +/* the FMOD error codes. */ +/* */ +/* ============================================================================================== */ + +#ifndef _FMOD_ERRORS_H +#define _FMOD_ERRORS_H + +#include "fmod.h" + +#ifdef __GNUC__ +static const char *FMOD_ErrorString(FMOD_RESULT errcode) __attribute__((unused)); +#endif + +static const char *FMOD_ErrorString(FMOD_RESULT errcode) +{ + switch (errcode) + { + case FMOD_ERR_ALREADYLOCKED: return "Tried to call lock a second time before unlock was called. "; + case FMOD_ERR_BADCOMMAND: return "Tried to call a function on a data type that does not allow this type of functionality (ie calling Sound::lock on a streaming sound). "; + case FMOD_ERR_CDDA_DRIVERS: return "Neither NTSCSI nor ASPI could be initialised. "; + case FMOD_ERR_CDDA_INIT: return "An error occurred while initialising the CDDA subsystem. "; + case FMOD_ERR_CDDA_INVALID_DEVICE: return "Couldn't find the specified device. "; + case FMOD_ERR_CDDA_NOAUDIO: return "No audio tracks on the specified disc. "; + case FMOD_ERR_CDDA_NODEVICES: return "No CD/DVD devices were found. "; + case FMOD_ERR_CDDA_NODISC: return "No disc present in the specified drive. "; + case FMOD_ERR_CDDA_READ: return "A CDDA read error occurred. "; + case FMOD_ERR_CHANNEL_ALLOC: return "Error trying to allocate a channel. "; + case FMOD_ERR_CHANNEL_STOLEN: return "The specified channel has been reused to play another sound. "; + case FMOD_ERR_COM: return "A Win32 COM related error occured. COM failed to initialize or a QueryInterface failed meaning a Windows codec or driver was not installed properly. "; + case FMOD_ERR_DMA: return "DMA Failure. See debug output for more information. "; + case FMOD_ERR_DSP_CONNECTION: return "DSP connection error. Connection possibly caused a cyclic dependancy. Or tried to connect a tree too many units deep (more than 128). "; + case FMOD_ERR_DSP_FORMAT: return "DSP Format error. A DSP unit may have attempted to connect to this network with the wrong format. "; + case FMOD_ERR_DSP_NOTFOUND: return "DSP connection error. Couldn't find the DSP unit specified. "; + case FMOD_ERR_DSP_RUNNING: return "DSP error. Cannot perform this operation while the network is in the middle of running. This will most likely happen if a connection or disconnection is attempted in a DSP callback. "; + case FMOD_ERR_DSP_TOOMANYCONNECTIONS: return "DSP connection error. The unit being connected to or disconnected should only have 1 input or output. "; + case FMOD_ERR_EVENT_ALREADY_LOADED: return "The specified project has already been loaded. Having multiple copies of the same project loaded simultaneously is forbidden. "; + case FMOD_ERR_EVENT_FAILED: return "An Event failed to be retrieved, most likely due to 'just fail' being specified as the max playbacks behavior. "; + case FMOD_ERR_EVENT_GUIDCONFLICT: return "An event with the same GUID already exists. "; + case FMOD_ERR_EVENT_INFOONLY: return "Can't execute this command on an EVENT_INFOONLY event. "; + case FMOD_ERR_EVENT_INTERNAL: return "An error occured that wasn't supposed to. See debug log for reason. "; + case FMOD_ERR_EVENT_MAXSTREAMS: return "Event failed because 'Max streams' was hit when FMOD_EVENT_INIT_FAIL_ON_MAXSTREAMS was specified. "; + case FMOD_ERR_EVENT_MISMATCH: return "FSB mismatches the FEV it was compiled with, the stream/sample mode it was meant to be created with was different, or the FEV was built for a different platform. "; + case FMOD_ERR_EVENT_NAMECONFLICT: return "A category with the same name already exists. "; + case FMOD_ERR_EVENT_NEEDSSIMPLE: return "Tried to call a function on a complex event that's only supported by simple events. "; + case FMOD_ERR_EVENT_NOTFOUND: return "The requested event, event group, event category or event property could not be found. "; + case FMOD_ERR_FILE_BAD: return "Error loading file. "; + case FMOD_ERR_FILE_COULDNOTSEEK: return "Couldn't perform seek operation. This is a limitation of the medium (ie netstreams) or the file format. "; + case FMOD_ERR_FILE_DISKEJECTED: return "Media was ejected while reading. "; + case FMOD_ERR_FILE_EOF: return "End of file unexpectedly reached while trying to read essential data (truncated data?). "; + case FMOD_ERR_FILE_NOTFOUND: return "File not found. "; + case FMOD_ERR_FILE_UNWANTED: return "Unwanted file access occured. "; + case FMOD_ERR_FORMAT: return "Unsupported file or audio format. "; + case FMOD_ERR_HTTP: return "A HTTP error occurred. This is a catch-all for HTTP errors not listed elsewhere. "; + case FMOD_ERR_HTTP_ACCESS: return "The specified resource requires authentication or is forbidden. "; + case FMOD_ERR_HTTP_PROXY_AUTH: return "Proxy authentication is required to access the specified resource. "; + case FMOD_ERR_HTTP_SERVER_ERROR: return "A HTTP server error occurred. "; + case FMOD_ERR_HTTP_TIMEOUT: return "The HTTP request timed out. "; + case FMOD_ERR_INITIALIZATION: return "FMOD was not initialized correctly to support this function. "; + case FMOD_ERR_INITIALIZED: return "Cannot call this command after System::init. "; + case FMOD_ERR_INTERNAL: return "An error occured that wasn't supposed to. Contact support. "; + case FMOD_ERR_INVALID_ADDRESS: return "On Xbox 360, this memory address passed to FMOD must be physical, (ie allocated with XPhysicalAlloc.) "; + case FMOD_ERR_INVALID_FLOAT: return "Value passed in was a NaN, Inf or denormalized float. "; + case FMOD_ERR_INVALID_HANDLE: return "An invalid object handle was used. "; + case FMOD_ERR_INVALID_PARAM: return "An invalid parameter was passed to this function. "; + case FMOD_ERR_INVALID_POSITION: return "An invalid seek position was passed to this function. "; + case FMOD_ERR_INVALID_SPEAKER: return "An invalid speaker was passed to this function based on the current speaker mode. "; + case FMOD_ERR_INVALID_SYNCPOINT: return "The syncpoint did not come from this sound handle. "; + case FMOD_ERR_INVALID_VECTOR: return "The vectors passed in are not unit length, or perpendicular. "; + case FMOD_ERR_IRX: return "PS2 only. fmodex.irx failed to initialize. This is most likely because you forgot to load it. "; + case FMOD_ERR_MAXAUDIBLE: return "Reached maximum audible playback count for this sound's soundgroup. "; + case FMOD_ERR_MEMORY: return "Not enough memory or resources. "; + case FMOD_ERR_MEMORY_CANTPOINT: return "Can't use FMOD_OPENMEMORY_POINT on non PCM source data, or non mp3/xma/adpcm data if FMOD_CREATECOMPRESSEDSAMPLE was used. "; + case FMOD_ERR_MEMORY_IOP: return "PS2 only. Not enough memory or resources on PlayStation 2 IOP ram. "; + case FMOD_ERR_MEMORY_SRAM: return "Not enough memory or resources on console sound ram. "; + case FMOD_ERR_MUSIC_NOCALLBACK: return "The music callback is required, but it has not been set. "; + case FMOD_ERR_MUSIC_NOTFOUND: return "The requested music entity could not be found. "; + case FMOD_ERR_MUSIC_UNINITIALIZED: return "Music system is not initialized probably because no music data is loaded. "; + case FMOD_ERR_NEEDS2D: return "Tried to call a command on a 3d sound when the command was meant for 2d sound. "; + case FMOD_ERR_NEEDS3D: return "Tried to call a command on a 2d sound when the command was meant for 3d sound. "; + case FMOD_ERR_NEEDSHARDWARE: return "Tried to use a feature that requires hardware support. (ie trying to play a VAG compressed sound in software on PS2). "; + case FMOD_ERR_NEEDSSOFTWARE: return "Tried to use a feature that requires the software engine. Software engine has either been turned off, or command was executed on a hardware channel which does not support this feature. "; + case FMOD_ERR_NET_CONNECT: return "Couldn't connect to the specified host. "; + case FMOD_ERR_NET_SOCKET_ERROR: return "A socket error occurred. This is a catch-all for socket-related errors not listed elsewhere. "; + case FMOD_ERR_NET_URL: return "The specified URL couldn't be resolved. "; + case FMOD_ERR_NET_WOULD_BLOCK: return "Operation on a non-blocking socket could not complete immediately. "; + case FMOD_ERR_NOTREADY: return "Operation could not be performed because specified sound/DSP connection is not ready. "; + case FMOD_ERR_OUTPUT_ALLOCATED: return "Error initializing output device, but more specifically, the output device is already in use and cannot be reused. "; + case FMOD_ERR_OUTPUT_CREATEBUFFER: return "Error creating hardware sound buffer. "; + case FMOD_ERR_OUTPUT_DRIVERCALL: return "A call to a standard soundcard driver failed, which could possibly mean a bug in the driver or resources were missing or exhausted. "; + case FMOD_ERR_OUTPUT_ENUMERATION: return "Error enumerating the available driver list. List may be inconsistent due to a recent device addition or removal. "; + case FMOD_ERR_OUTPUT_FORMAT: return "Soundcard does not support the minimum features needed for this soundsystem (16bit stereo output). "; + case FMOD_ERR_OUTPUT_INIT: return "Error initializing output device. "; + case FMOD_ERR_OUTPUT_NOHARDWARE: return "FMOD_HARDWARE was specified but the sound card does not have the resources necessary to play it. "; + case FMOD_ERR_OUTPUT_NOSOFTWARE: return "Attempted to create a software sound but no software channels were specified in System::init. "; + case FMOD_ERR_PAN: return "Panning only works with mono or stereo sound sources. "; + case FMOD_ERR_PLUGIN: return "An unspecified error has been returned from a 3rd party plugin. "; + case FMOD_ERR_PLUGIN_INSTANCES: return "The number of allowed instances of a plugin has been exceeded. "; + case FMOD_ERR_PLUGIN_MISSING: return "A requested output, dsp unit type or codec was not available. "; + case FMOD_ERR_PLUGIN_RESOURCE: return "A resource that the plugin requires cannot be found. (ie the DLS file for MIDI playback) "; + case FMOD_ERR_PRELOADED: return "The specified sound is still in use by the event system, call EventSystem::unloadFSB before trying to release it. "; + case FMOD_ERR_PROGRAMMERSOUND: return "The specified sound is still in use by the event system, wait for the event which is using it finish with it. "; + case FMOD_ERR_RECORD: return "An error occured trying to initialize the recording device. "; + case FMOD_ERR_REVERB_INSTANCE: return "Specified Instance in FMOD_REVERB_PROPERTIES couldn't be set. Most likely because it is an invalid instance number, or another application has locked the EAX4 FX slot. "; + case FMOD_ERR_SUBSOUNDS: return "The error occured because the sound referenced contains subsounds. The operation cannot be performed on a parent sound, or a parent sound was played without setting up a sentence first. "; + case FMOD_ERR_SUBSOUND_ALLOCATED: return "This subsound is already being used by another sound, you cannot have more than one parent to a sound. Null out the other parent's entry first. "; + case FMOD_ERR_SUBSOUND_CANTMOVE: return "Shared subsounds cannot be replaced or moved from their parent stream, such as when the parent stream is an FSB file. "; + case FMOD_ERR_SUBSOUND_MODE: return "The subsound's mode bits do not match with the parent sound's mode bits. See documentation for function that it was called with. "; + case FMOD_ERR_TAGNOTFOUND: return "The specified tag could not be found or there are no tags. "; + case FMOD_ERR_TOOMANYCHANNELS: return "The sound created exceeds the allowable input channel count. This can be increased using the maxinputchannels parameter in System::setSoftwareFormat. "; + case FMOD_ERR_UNIMPLEMENTED: return "Something in FMOD hasn't been implemented when it should be! contact support! "; + case FMOD_ERR_UNINITIALIZED: return "This command failed because System::init or System::setDriver was not called. "; + case FMOD_ERR_UNSUPPORTED: return "A command issued was not supported by this object. Possibly a plugin without certain callbacks specified. "; + case FMOD_ERR_UPDATE: return "An error caused by System::update occured. "; + case FMOD_ERR_VERSION: return "The version number of this file format is not supported. "; + case FMOD_OK: return "No errors."; + default : return "Unknown error."; + }; +} + +#endif diff --git a/Lib/Include/FMOD/fmod_memoryinfo.h b/Lib/Include/FMOD/fmod_memoryinfo.h new file mode 100644 index 0000000..668e3ab --- /dev/null +++ b/Lib/Include/FMOD/fmod_memoryinfo.h @@ -0,0 +1,201 @@ +/* ============================================================================================= */ +/* FMOD Ex - Memory info header file. Copyright (c), Firelight Technologies Pty, Ltd. 2008-2009. */ +/* */ +/* Use this header if you are interested in getting detailed information on FMOD's memory */ +/* usage. See the documentation for more details. */ +/* */ +/* ============================================================================================= */ + +#ifndef _FMOD_MEMORYINFO_H +#define _FMOD_MEMORYINFO_H + +/* +[STRUCTURE] +[ + [DESCRIPTION] + Structure to be filled with detailed memory usage information of an FMOD object + + [REMARKS] + Every public FMOD class has a getMemoryInfo function which can be used to get detailed information on what memory resources are associated with the object in question. + On return from getMemoryInfo, each member of this structure will hold the amount of memory used for its type in bytes. + + Members marked with [in] mean the user sets the value before passing it to the function. + Members marked with [out] mean FMOD sets the value to be used after the function exits. + + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox, Xbox360, PlayStation 2, GameCube, PlayStation Portable, PlayStation 3 + + [SEE_ALSO] + System::getMemoryInfo + EventSystem::getMemoryInfo + FMOD_MEMBITS + FMOD_EVENT_MEMBITS +] +*/ +typedef struct FMOD_MEMORY_USAGE_DETAILS +{ + unsigned int other; /* [out] Memory not accounted for by other types */ + unsigned int string; /* [out] String data */ + unsigned int system; /* [out] System object and various internals */ + unsigned int plugins; /* [out] Plugin objects and internals */ + unsigned int output; /* [out] Output module object and internals */ + unsigned int channel; /* [out] Channel related memory */ + unsigned int channelgroup; /* [out] ChannelGroup objects and internals */ + unsigned int codec; /* [out] Codecs allocated for streaming */ + unsigned int file; /* [out] File buffers and structures */ + unsigned int sound; /* [out] Sound objects and internals */ + unsigned int secondaryram; /* [out] Sound data stored in secondary RAM */ + unsigned int soundgroup; /* [out] SoundGroup objects and internals */ + unsigned int streambuffer; /* [out] Stream buffer memory */ + unsigned int dspconnection; /* [out] DSPConnection objects and internals */ + unsigned int dsp; /* [out] DSP implementation objects */ + unsigned int dspcodec; /* [out] Realtime file format decoding DSP objects */ + unsigned int profile; /* [out] Profiler memory footprint. */ + unsigned int recordbuffer; /* [out] Buffer used to store recorded data from microphone */ + unsigned int reverb; /* [out] Reverb implementation objects */ + unsigned int reverbchannelprops; /* [out] Reverb channel properties structs */ + unsigned int geometry; /* [out] Geometry objects and internals */ + unsigned int syncpoint; /* [out] Sync point memory. */ + unsigned int eventsystem; /* [out] EventSystem and various internals */ + unsigned int musicsystem; /* [out] MusicSystem and various internals */ + unsigned int fev; /* [out] Definition of objects contained in all loaded projects e.g. events, groups, categories */ + unsigned int memoryfsb; /* [out] Data loaded with registerMemoryFSB */ + unsigned int eventproject; /* [out] EventProject objects and internals */ + unsigned int eventgroupi; /* [out] EventGroup objects and internals */ + unsigned int soundbankclass; /* [out] Objects used to manage wave banks */ + unsigned int soundbanklist; /* [out] Data used to manage lists of wave bank usage */ + unsigned int streaminstance; /* [out] Stream objects and internals */ + unsigned int sounddefclass; /* [out] Sound definition objects */ + unsigned int sounddefdefclass; /* [out] Sound definition static data objects */ + unsigned int sounddefpool; /* [out] Sound definition pool data */ + unsigned int reverbdef; /* [out] Reverb definition objects */ + unsigned int eventreverb; /* [out] Reverb objects */ + unsigned int userproperty; /* [out] User property objects */ + unsigned int eventinstance; /* [out] Event instance base objects */ + unsigned int eventinstance_complex; /* [out] Complex event instance objects */ + unsigned int eventinstance_simple; /* [out] Simple event instance objects */ + unsigned int eventinstance_layer; /* [out] Event layer instance objects */ + unsigned int eventinstance_sound; /* [out] Event sound instance objects */ + unsigned int eventenvelope; /* [out] Event envelope objects */ + unsigned int eventenvelopedef; /* [out] Event envelope definition objects */ + unsigned int eventparameter; /* [out] Event parameter objects */ + unsigned int eventcategory; /* [out] Event category objects */ + unsigned int eventenvelopepoint; /* [out] Event envelope point objects */ + unsigned int eventinstancepool; /* [out] Event instance pool memory */ +} FMOD_MEMORY_USAGE_DETAILS; + + +/* +[DEFINE] +[ + [NAME] + FMOD_MEMBITS + + [DESCRIPTION] + Bitfield used to request specific memory usage information from the getMemoryInfo function of every public FMOD Ex class. + Use with the "memorybits" parameter of getMemoryInfo to get information on FMOD Ex memory usage. + + [REMARKS] + Every public FMOD class has a getMemoryInfo function which can be used to get detailed information on what memory resources are associated with the object in question. + The FMOD_MEMBITS defines can be OR'd together to specify precisely what memory usage you'd like to get information on. See System::getMemoryInfo for an example. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation 2, PlayStation Portable, PlayStation 3, Wii, Solaris, iPhone + + [SEE_ALSO] + FMOD_EVENT_MEMBITS + System::getMemoryInfo +] +*/ +#define FMOD_MEMBITS_OTHER 0x00000001 /* Memory not accounted for by other types */ +#define FMOD_MEMBITS_STRING 0x00000002 /* String data */ + +#define FMOD_MEMBITS_SYSTEM 0x00000004 /* System object and various internals */ +#define FMOD_MEMBITS_PLUGINS 0x00000008 /* Plugin objects and internals */ +#define FMOD_MEMBITS_OUTPUT 0x00000010 /* Output module object and internals */ +#define FMOD_MEMBITS_CHANNEL 0x00000020 /* Channel related memory */ +#define FMOD_MEMBITS_CHANNELGROUP 0x00000040 /* ChannelGroup objects and internals */ +#define FMOD_MEMBITS_CODEC 0x00000080 /* Codecs allocated for streaming */ +#define FMOD_MEMBITS_FILE 0x00000100 /* Codecs allocated for streaming */ +#define FMOD_MEMBITS_SOUND 0x00000200 /* Sound objects and internals */ +#define FMOD_MEMBITS_SOUND_SECONDARYRAM 0x00000400 /* Sound data stored in secondary RAM */ +#define FMOD_MEMBITS_SOUNDGROUP 0x00000800 /* SoundGroup objects and internals */ +#define FMOD_MEMBITS_STREAMBUFFER 0x00001000 /* Stream buffer memory */ +#define FMOD_MEMBITS_DSPCONNECTION 0x00002000 /* DSPConnection objects and internals */ +#define FMOD_MEMBITS_DSP 0x00004000 /* DSP implementation objects */ +#define FMOD_MEMBITS_DSPCODEC 0x00008000 /* Realtime file format decoding DSP objects */ +#define FMOD_MEMBITS_PROFILE 0x00010000 /* Profiler memory footprint. */ +#define FMOD_MEMBITS_RECORDBUFFER 0x00020000 /* Buffer used to store recorded data from microphone */ +#define FMOD_MEMBITS_REVERB 0x00040000 /* Reverb implementation objects */ +#define FMOD_MEMBITS_REVERBCHANNELPROPS 0x00080000 /* Reverb channel properties structs */ +#define FMOD_MEMBITS_GEOMETRY 0x00100000 /* Geometry objects and internals */ +#define FMOD_MEMBITS_SYNCPOINT 0x00200000 /* Sync point memory. */ +#define FMOD_MEMBITS_ALL 0xffffffff /* All memory used by FMOD Ex */ +/* [DEFINE_END] */ + + +/* +[DEFINE] +[ + [NAME] + FMOD_EVENT_MEMBITS + + [DESCRIPTION] + Bitfield used to request specific memory usage information from the getMemoryInfo function of every public FMOD Event System class. + Use with the "event_memorybits" parameter of getMemoryInfo to get information on FMOD Event System memory usage. + + [REMARKS] + Every public FMOD Event System class has a getMemoryInfo function which can be used to get detailed information on what memory resources are associated with the object in question. + The FMOD_EVENT_MEMBITS defines can be OR'd together to specify precisely what memory usage you'd like to get information on. See EventSystem::getMemoryInfo for an example. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation 2, PlayStation Portable, PlayStation 3, Wii, Solaris, iPhone + + [SEE_ALSO] + FMOD_MEMBITS + System::getMemoryInfo +] +*/ +#define FMOD_EVENT_MEMBITS_EVENTSYSTEM 0x00000001 /* EventSystem and various internals */ +#define FMOD_EVENT_MEMBITS_MUSICSYSTEM 0x00000002 /* MusicSystem and various internals */ +#define FMOD_EVENT_MEMBITS_FEV 0x00000004 /* Definition of objects contained in all loaded projects e.g. events, groups, categories */ +#define FMOD_EVENT_MEMBITS_MEMORYFSB 0x00000008 /* Data loaded with registerMemoryFSB */ +#define FMOD_EVENT_MEMBITS_EVENTPROJECT 0x00000010 /* EventProject objects and internals */ +#define FMOD_EVENT_MEMBITS_EVENTGROUPI 0x00000020 /* EventGroup objects and internals */ +#define FMOD_EVENT_MEMBITS_SOUNDBANKCLASS 0x00000040 /* Objects used to manage wave banks */ +#define FMOD_EVENT_MEMBITS_SOUNDBANKLIST 0x00000080 /* Data used to manage lists of wave bank usage */ +#define FMOD_EVENT_MEMBITS_STREAMINSTANCE 0x00000100 /* Stream objects and internals */ +#define FMOD_EVENT_MEMBITS_SOUNDDEFCLASS 0x00000200 /* Sound definition objects */ +#define FMOD_EVENT_MEMBITS_SOUNDDEFDEFCLASS 0x00000400 /* Sound definition static data objects */ +#define FMOD_EVENT_MEMBITS_SOUNDDEFPOOL 0x00000800 /* Sound definition pool data */ +#define FMOD_EVENT_MEMBITS_REVERBDEF 0x00001000 /* Reverb definition objects */ +#define FMOD_EVENT_MEMBITS_EVENTREVERB 0x00002000 /* Reverb objects */ +#define FMOD_EVENT_MEMBITS_USERPROPERTY 0x00004000 /* User property objects */ +#define FMOD_EVENT_MEMBITS_EVENTINSTANCE 0x00008000 /* Event instance base objects */ +#define FMOD_EVENT_MEMBITS_EVENTINSTANCE_COMPLEX 0x00010000 /* Complex event instance objects */ +#define FMOD_EVENT_MEMBITS_EVENTINSTANCE_SIMPLE 0x00020000 /* Simple event instance objects */ +#define FMOD_EVENT_MEMBITS_EVENTINSTANCE_LAYER 0x00040000 /* Event layer instance objects */ +#define FMOD_EVENT_MEMBITS_EVENTINSTANCE_SOUND 0x00080000 /* Event sound instance objects */ +#define FMOD_EVENT_MEMBITS_EVENTENVELOPE 0x00100000 /* Event envelope objects */ +#define FMOD_EVENT_MEMBITS_EVENTENVELOPEDEF 0x00200000 /* Event envelope definition objects */ +#define FMOD_EVENT_MEMBITS_EVENTPARAMETER 0x00400000 /* Event parameter objects */ +#define FMOD_EVENT_MEMBITS_EVENTCATEGORY 0x00800000 /* Event category objects */ +#define FMOD_EVENT_MEMBITS_EVENTENVELOPEPOINT 0x01000000 /* Event envelope point object+s */ +#define FMOD_EVENT_MEMBITS_EVENTINSTANCEPOOL 0x02000000 /* Event instance pool data */ +#define FMOD_EVENT_MEMBITS_ALL 0xffffffff /* All memory used by FMOD Event System */ + +/* All event instance memory */ +#define FMOD_EVENT_MEMBITS_EVENTINSTANCE_GROUP (FMOD_EVENT_MEMBITS_EVENTINSTANCE | \ + FMOD_EVENT_MEMBITS_EVENTINSTANCE_COMPLEX | \ + FMOD_EVENT_MEMBITS_EVENTINSTANCE_SIMPLE | \ + FMOD_EVENT_MEMBITS_EVENTINSTANCE_LAYER | \ + FMOD_EVENT_MEMBITS_EVENTINSTANCE_SOUND) + +/* All sound definition memory */ +#define FMOD_EVENT_MEMBITS_SOUNDDEF_GROUP (FMOD_EVENT_MEMBITS_SOUNDDEFCLASS | \ + FMOD_EVENT_MEMBITS_SOUNDDEFDEFCLASS | \ + FMOD_EVENT_MEMBITS_SOUNDDEFPOOL) +/* [DEFINE_END] */ + +#endif diff --git a/Lib/Include/FMOD/fmod_output.h b/Lib/Include/FMOD/fmod_output.h new file mode 100644 index 0000000..167fe12 --- /dev/null +++ b/Lib/Include/FMOD/fmod_output.h @@ -0,0 +1,93 @@ +/* ==================================================================================================== */ +/* FMOD Ex - output development header file. Copyright (c), Firelight Technologies Pty, Ltd. 2004-2009. */ +/* */ +/* Use this header if you are wanting to develop your own output plugin to use with */ +/* FMOD's output system. With this header you can make your own output plugin that FMOD */ +/* can register and use. See the documentation and examples on how to make a working plugin. */ +/* */ +/* ==================================================================================================== */ + +#ifndef _FMOD_OUTPUT_H +#define _FMOD_OUTPUT_H + +#include "fmod.h" + +typedef struct FMOD_OUTPUT_STATE FMOD_OUTPUT_STATE; + +/* + Output callbacks +*/ +typedef FMOD_RESULT (F_CALLBACK *FMOD_OUTPUT_GETNUMDRIVERSCALLBACK)(FMOD_OUTPUT_STATE *output_state, int *numdrivers); +typedef FMOD_RESULT (F_CALLBACK *FMOD_OUTPUT_GETDRIVERNAMECALLBACK)(FMOD_OUTPUT_STATE *output_state, int id, char *name, int namelen); +typedef FMOD_RESULT (F_CALLBACK *FMOD_OUTPUT_GETDRIVERCAPSCALLBACK)(FMOD_OUTPUT_STATE *output_state, int id, FMOD_CAPS *caps); +typedef FMOD_RESULT (F_CALLBACK *FMOD_OUTPUT_INITCALLBACK) (FMOD_OUTPUT_STATE *output_state, int selecteddriver, FMOD_INITFLAGS flags, int *outputrate, int outputchannels, FMOD_SOUND_FORMAT *outputformat, int dspbufferlength, int dspnumbuffers, void *extradriverdata); +typedef FMOD_RESULT (F_CALLBACK *FMOD_OUTPUT_CLOSECALLBACK) (FMOD_OUTPUT_STATE *output_state); +typedef FMOD_RESULT (F_CALLBACK *FMOD_OUTPUT_UPDATECALLBACK) (FMOD_OUTPUT_STATE *output_state); +typedef FMOD_RESULT (F_CALLBACK *FMOD_OUTPUT_GETHANDLECALLBACK) (FMOD_OUTPUT_STATE *output_state, void **handle); +typedef FMOD_RESULT (F_CALLBACK *FMOD_OUTPUT_GETPOSITIONCALLBACK) (FMOD_OUTPUT_STATE *output_state, unsigned int *pcm); +typedef FMOD_RESULT (F_CALLBACK *FMOD_OUTPUT_LOCKCALLBACK) (FMOD_OUTPUT_STATE *output_state, unsigned int offset, unsigned int length, void **ptr1, void **ptr2, unsigned int *len1, unsigned int *len2); +typedef FMOD_RESULT (F_CALLBACK *FMOD_OUTPUT_UNLOCKCALLBACK) (FMOD_OUTPUT_STATE *output_state, void *ptr1, void *ptr2, unsigned int len1, unsigned int len2); +typedef FMOD_RESULT (F_CALLBACK *FMOD_OUTPUT_READFROMMIXER) (FMOD_OUTPUT_STATE *output_state, void *buffer, unsigned int length); + + +/* +[STRUCTURE] +[ + [DESCRIPTION] + When creating an output, declare one of these and provide the relevant callbacks and name for FMOD to use when it opens and reads a file of this type. + + [REMARKS] + Members marked with [in] mean the variable can be written to. The user can set the value. + Members marked with [out] mean the variable is modified by FMOD and is for reading purposes only. Do not change this value. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation 2, PlayStation Portable, PlayStation 3, Wii, Solaris, iPhone + + [SEE_ALSO] + FMOD_OUTPUT_STATE +] +*/ +typedef struct FMOD_OUTPUT_DESCRIPTION +{ + const char *name; /* [in] Name of the output. */ + unsigned int version; /* [in] Plugin writer's version number. */ + int polling; /* [in] If TRUE (non zero), this tells FMOD to start a thread and call getposition / lock / unlock for feeding data. If 0, the output is probably callback based, so all the plugin needs to do is call readfrommixer to the appropriate pointer. */ + FMOD_OUTPUT_GETNUMDRIVERSCALLBACK getnumdrivers; /* [in] For sound device enumeration. This callback is to give System::getNumDrivers somthing to return. */ + FMOD_OUTPUT_GETDRIVERNAMECALLBACK getdrivername; /* [in] For sound device enumeration. This callback is to give System::getDriverName somthing to return. */ + FMOD_OUTPUT_GETDRIVERCAPSCALLBACK getdrivercaps; /* [in] For sound device enumeration. This callback is to give System::getDriverCaps somthing to return. */ + FMOD_OUTPUT_INITCALLBACK init; /* [in] Initialization function for the output device. This is called from System::init. */ + FMOD_OUTPUT_CLOSECALLBACK close; /* [in] Cleanup / close down function for the output device. This is called from System::close. */ + FMOD_OUTPUT_UPDATECALLBACK update; /* [in] Update function that is called once a frame by the user. This is called from System::update. */ + FMOD_OUTPUT_GETHANDLECALLBACK gethandle; /* [in] This is called from System::getOutputHandle. This is just to return a pointer to the internal system device object that the system may be using.*/ + FMOD_OUTPUT_GETPOSITIONCALLBACK getposition; /* [in] This is called from the FMOD software mixer thread if 'polling' = true. This returns a position value in samples so that FMOD knows where and when to fill its buffer. */ + FMOD_OUTPUT_LOCKCALLBACK lock; /* [in] This is called from the FMOD software mixer thread if 'polling' = true. This function provides a pointer to data that FMOD can write to when software mixing. */ + FMOD_OUTPUT_UNLOCKCALLBACK unlock; /* [in] This is called from the FMOD software mixer thread if 'polling' = true. This optional function accepts the data that has been mixed and copies it or does whatever it needs to before sending it to the hardware. */ +} FMOD_OUTPUT_DESCRIPTION; + + +/* +[STRUCTURE] +[ + [DESCRIPTION] + Output plugin structure that is passed into each callback. + + [REMARKS] + Members marked with [in] mean the variable can be written to. The user can set the value. + Members marked with [out] mean the variable is modified by FMOD and is for reading purposes only. Do not change this value. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation 2, PlayStation Portable, PlayStation 3, Wii, Solaris, iPhone + + [SEE_ALSO] + FMOD_OUTPUT_DESCRIPTION +] +*/ +struct FMOD_OUTPUT_STATE +{ + void *plugindata; /* [in] Plugin writer created data the output author wants to attach to this object. */ + FMOD_OUTPUT_READFROMMIXER readfrommixer; /* [out] Function to update mixer and write the result to the provided pointer. Used from callback based output only. Polling based output uses lock/unlock/getposition. */ +}; + +#endif + + diff --git a/Lib/Include/FreeImage.h b/Lib/Include/FreeImage.h new file mode 100644 index 0000000..eab7236 --- /dev/null +++ b/Lib/Include/FreeImage.h @@ -0,0 +1,1090 @@ +// ========================================================== +// FreeImage 3 +// +// Design and implementation by +// - Floris van den Berg (flvdberg@wxs.nl) +// - Herv‰ Drolon (drolon@infonie.fr) +// +// Contributors: +// - Adam Gates (radad@xoasis.com) +// - Alex Kwak +// - Alexander Dymerets (sashad@te.net.ua) +// - Detlev Vendt (detlev.vendt@brillit.de) +// - Jan L. Nauta (jln@magentammt.com) +// - Jani Kajala (janik@remedy.fi) +// - Juergen Riecker (j.riecker@gmx.de) +// - Karl-Heinz Bussian (khbussian@moss.de) +// - Laurent Rocher (rocherl@club-internet.fr) +// - Luca Piergentili (l.pierge@terra.es) +// - Machiel ten Brinke (brinkem@uni-one.nl) +// - Markus Loibl (markus.loibl@epost.de) +// - Martin Weber (martweb@gmx.net) +// - Matthias Wandel (mwandel@rim.net) +// - Michal Novotny (michal@etc.cz) +// - Petr Pytelka (pyta@lightcomp.com) +// - Riley McNiff (rmcniff@marexgroup.com) +// - Ryan Rubley (ryan@lostreality.org) +// - Volker G„rtner (volkerg@gmx.at) +// +// This file is part of FreeImage 3 +// +// COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY +// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES +// THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE +// OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED +// CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT +// THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY +// SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL +// PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER +// THIS DISCLAIMER. +// +// Use at your own risk! +// ========================================================== + +#ifndef FREEIMAGE_H +#define FREEIMAGE_H + +// Version information ------------------------------------------------------ + +#define FREEIMAGE_MAJOR_VERSION 3 +#define FREEIMAGE_MINOR_VERSION 13 +#define FREEIMAGE_RELEASE_SERIAL 1 + +// Compiler options --------------------------------------------------------- + +#include // needed for UNICODE functions + +#if defined(FREEIMAGE_LIB) + #define DLL_API + #define DLL_CALLCONV +#else + #if defined(_WIN32) || defined(__WIN32__) + #define DLL_CALLCONV __stdcall + // The following ifdef block is the standard way of creating macros which make exporting + // from a DLL simpler. All files within this DLL are compiled with the FREEIMAGE_EXPORTS + // symbol defined on the command line. this symbol should not be defined on any project + // that uses this DLL. This way any other project whose source files include this file see + // DLL_API functions as being imported from a DLL, wheras this DLL sees symbols + // defined with this macro as being exported. + #ifdef FREEIMAGE_EXPORTS + #define DLL_API __declspec(dllexport) + #else + #define DLL_API __declspec(dllimport) + #endif // FREEIMAGE_EXPORTS + #else + // try the gcc visibility support (see http://gcc.gnu.org/wiki/Visibility) + #if defined(__GNUC__) && ((__GNUC__ >= 4) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)) + #ifndef GCC_HASCLASSVISIBILITY + #define GCC_HASCLASSVISIBILITY + #endif + #endif // __GNUC__ + #define DLL_CALLCONV + #if defined(GCC_HASCLASSVISIBILITY) + #define DLL_API __attribute__ ((visibility("default"))) + #else + #define DLL_API + #endif + #endif // WIN32 / !WIN32 +#endif // FREEIMAGE_LIB + +// Some versions of gcc may have BYTE_ORDER or __BYTE_ORDER defined +// If your big endian system isn't being detected, add an OS specific check +#if (defined(BYTE_ORDER) && BYTE_ORDER==BIG_ENDIAN) || \ + (defined(__BYTE_ORDER) && __BYTE_ORDER==__BIG_ENDIAN) || \ + defined(__BIG_ENDIAN__) +#define FREEIMAGE_BIGENDIAN +#endif // BYTE_ORDER + +// This really only affects 24 and 32 bit formats, the rest are always RGB order. +#define FREEIMAGE_COLORORDER_BGR 0 +#define FREEIMAGE_COLORORDER_RGB 1 +#if defined(FREEIMAGE_BIGENDIAN) +#define FREEIMAGE_COLORORDER FREEIMAGE_COLORORDER_RGB +#else +#define FREEIMAGE_COLORORDER FREEIMAGE_COLORORDER_BGR +#endif + +// Ensure 4-byte enums if we're using Borland C++ compilers +#if defined(__BORLANDC__) +#pragma option push -b +#endif + +// For C compatibility -------------------------------------------------------- + +#ifdef __cplusplus +#define FI_DEFAULT(x) = x +#define FI_ENUM(x) enum x +#define FI_STRUCT(x) struct x +#else +#define FI_DEFAULT(x) +#define FI_ENUM(x) typedef int x; enum x +#define FI_STRUCT(x) typedef struct x x; struct x +#endif + +// Bitmap types ------------------------------------------------------------- + +FI_STRUCT (FIBITMAP) { void *data; }; +FI_STRUCT (FIMULTIBITMAP) { void *data; }; + +// Types used in the library (directly copied from Windows) ----------------- + +#if defined(__MINGW32__) && defined(_WINDOWS_H) +#define _WINDOWS_ // prevent a bug in MinGW32 +#endif // __MINGW32__ + +#ifndef _WINDOWS_ +#define _WINDOWS_ + +#ifndef FALSE +#define FALSE 0 +#endif +#ifndef TRUE +#define TRUE 1 +#endif +#ifndef NULL +#define NULL 0 +#endif + +#ifndef SEEK_SET +#define SEEK_SET 0 +#define SEEK_CUR 1 +#define SEEK_END 2 +#endif + +#ifndef _MSC_VER +// define portable types for 32-bit / 64-bit OS +#include +typedef int32_t BOOL; +typedef uint8_t BYTE; +typedef uint16_t WORD; +typedef uint32_t DWORD; +typedef int32_t LONG; +#else +// MS is not C99 ISO compliant +typedef long BOOL; +typedef unsigned char BYTE; +typedef unsigned short WORD; +typedef unsigned long DWORD; +typedef long LONG; +#endif // _MSC_VER + +#if (defined(_WIN32) || defined(__WIN32__)) +#pragma pack(push, 1) +#else +#pragma pack(1) +#endif // WIN32 + +typedef struct tagRGBQUAD { +#if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_BGR + BYTE rgbBlue; + BYTE rgbGreen; + BYTE rgbRed; +#else + BYTE rgbRed; + BYTE rgbGreen; + BYTE rgbBlue; +#endif // FREEIMAGE_COLORORDER + BYTE rgbReserved; +} RGBQUAD; + +typedef struct tagRGBTRIPLE { +#if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_BGR + BYTE rgbtBlue; + BYTE rgbtGreen; + BYTE rgbtRed; +#else + BYTE rgbtRed; + BYTE rgbtGreen; + BYTE rgbtBlue; +#endif // FREEIMAGE_COLORORDER +} RGBTRIPLE; + +#if (defined(_WIN32) || defined(__WIN32__)) +#pragma pack(pop) +#else +#pragma pack() +#endif // WIN32 + +typedef struct tagBITMAPINFOHEADER{ + DWORD biSize; + LONG biWidth; + LONG biHeight; + WORD biPlanes; + WORD biBitCount; + DWORD biCompression; + DWORD biSizeImage; + LONG biXPelsPerMeter; + LONG biYPelsPerMeter; + DWORD biClrUsed; + DWORD biClrImportant; +} BITMAPINFOHEADER, *PBITMAPINFOHEADER; + +typedef struct tagBITMAPINFO { + BITMAPINFOHEADER bmiHeader; + RGBQUAD bmiColors[1]; +} BITMAPINFO, *PBITMAPINFO; + +#endif // _WINDOWS_ + +// Types used in the library (specific to FreeImage) ------------------------ + +#if (defined(_WIN32) || defined(__WIN32__)) +#pragma pack(push, 1) +#else +#pragma pack(1) +#endif // WIN32 + +/** 48-bit RGB +*/ +typedef struct tagFIRGB16 { + WORD red; + WORD green; + WORD blue; +} FIRGB16; + +/** 64-bit RGBA +*/ +typedef struct tagFIRGBA16 { + WORD red; + WORD green; + WORD blue; + WORD alpha; +} FIRGBA16; + +/** 96-bit RGB Float +*/ +typedef struct tagFIRGBF { + float red; + float green; + float blue; +} FIRGBF; + +/** 128-bit RGBA Float +*/ +typedef struct tagFIRGBAF { + float red; + float green; + float blue; + float alpha; +} FIRGBAF; + +/** Data structure for COMPLEX type (complex number) +*/ +typedef struct tagFICOMPLEX { + /// real part + double r; + /// imaginary part + double i; +} FICOMPLEX; + +#if (defined(_WIN32) || defined(__WIN32__)) +#pragma pack(pop) +#else +#pragma pack() +#endif // WIN32 + +// Indexes for byte arrays, masks and shifts for treating pixels as words --- +// These coincide with the order of RGBQUAD and RGBTRIPLE ------------------- + +#ifndef FREEIMAGE_BIGENDIAN +#if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_BGR +// Little Endian (x86 / MS Windows, Linux) : BGR(A) order +#define FI_RGBA_RED 2 +#define FI_RGBA_GREEN 1 +#define FI_RGBA_BLUE 0 +#define FI_RGBA_ALPHA 3 +#define FI_RGBA_RED_MASK 0x00FF0000 +#define FI_RGBA_GREEN_MASK 0x0000FF00 +#define FI_RGBA_BLUE_MASK 0x000000FF +#define FI_RGBA_ALPHA_MASK 0xFF000000 +#define FI_RGBA_RED_SHIFT 16 +#define FI_RGBA_GREEN_SHIFT 8 +#define FI_RGBA_BLUE_SHIFT 0 +#define FI_RGBA_ALPHA_SHIFT 24 +#else +// Little Endian (x86 / MaxOSX) : RGB(A) order +#define FI_RGBA_RED 0 +#define FI_RGBA_GREEN 1 +#define FI_RGBA_BLUE 2 +#define FI_RGBA_ALPHA 3 +#define FI_RGBA_RED_MASK 0x000000FF +#define FI_RGBA_GREEN_MASK 0x0000FF00 +#define FI_RGBA_BLUE_MASK 0x00FF0000 +#define FI_RGBA_ALPHA_MASK 0xFF000000 +#define FI_RGBA_RED_SHIFT 0 +#define FI_RGBA_GREEN_SHIFT 8 +#define FI_RGBA_BLUE_SHIFT 16 +#define FI_RGBA_ALPHA_SHIFT 24 +#endif // FREEIMAGE_COLORORDER +#else +#if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_BGR +// Big Endian (PPC / none) : BGR(A) order +#define FI_RGBA_RED 2 +#define FI_RGBA_GREEN 1 +#define FI_RGBA_BLUE 0 +#define FI_RGBA_ALPHA 3 +#define FI_RGBA_RED_MASK 0x0000FF00 +#define FI_RGBA_GREEN_MASK 0x00FF0000 +#define FI_RGBA_BLUE_MASK 0xFF000000 +#define FI_RGBA_ALPHA_MASK 0x000000FF +#define FI_RGBA_RED_SHIFT 8 +#define FI_RGBA_GREEN_SHIFT 16 +#define FI_RGBA_BLUE_SHIFT 24 +#define FI_RGBA_ALPHA_SHIFT 0 +#else +// Big Endian (PPC / Linux, MaxOSX) : RGB(A) order +#define FI_RGBA_RED 0 +#define FI_RGBA_GREEN 1 +#define FI_RGBA_BLUE 2 +#define FI_RGBA_ALPHA 3 +#define FI_RGBA_RED_MASK 0xFF000000 +#define FI_RGBA_GREEN_MASK 0x00FF0000 +#define FI_RGBA_BLUE_MASK 0x0000FF00 +#define FI_RGBA_ALPHA_MASK 0x000000FF +#define FI_RGBA_RED_SHIFT 24 +#define FI_RGBA_GREEN_SHIFT 16 +#define FI_RGBA_BLUE_SHIFT 8 +#define FI_RGBA_ALPHA_SHIFT 0 +#endif // FREEIMAGE_COLORORDER +#endif // FREEIMAGE_BIGENDIAN + +#define FI_RGBA_RGB_MASK (FI_RGBA_RED_MASK|FI_RGBA_GREEN_MASK|FI_RGBA_BLUE_MASK) + +// The 16bit macros only include masks and shifts, since each color element is not byte aligned + +#define FI16_555_RED_MASK 0x7C00 +#define FI16_555_GREEN_MASK 0x03E0 +#define FI16_555_BLUE_MASK 0x001F +#define FI16_555_RED_SHIFT 10 +#define FI16_555_GREEN_SHIFT 5 +#define FI16_555_BLUE_SHIFT 0 +#define FI16_565_RED_MASK 0xF800 +#define FI16_565_GREEN_MASK 0x07E0 +#define FI16_565_BLUE_MASK 0x001F +#define FI16_565_RED_SHIFT 11 +#define FI16_565_GREEN_SHIFT 5 +#define FI16_565_BLUE_SHIFT 0 + +// ICC profile support ------------------------------------------------------ + +#define FIICC_DEFAULT 0x00 +#define FIICC_COLOR_IS_CMYK 0x01 + +FI_STRUCT (FIICCPROFILE) { + WORD flags; // info flag + DWORD size; // profile's size measured in bytes + void *data; // points to a block of contiguous memory containing the profile +}; + +// Important enums ---------------------------------------------------------- + +/** I/O image format identifiers. +*/ +FI_ENUM(FREE_IMAGE_FORMAT) { + FIF_UNKNOWN = -1, + FIF_BMP = 0, + FIF_ICO = 1, + FIF_JPEG = 2, + FIF_JNG = 3, + FIF_KOALA = 4, + FIF_LBM = 5, + FIF_IFF = FIF_LBM, + FIF_MNG = 6, + FIF_PBM = 7, + FIF_PBMRAW = 8, + FIF_PCD = 9, + FIF_PCX = 10, + FIF_PGM = 11, + FIF_PGMRAW = 12, + FIF_PNG = 13, + FIF_PPM = 14, + FIF_PPMRAW = 15, + FIF_RAS = 16, + FIF_TARGA = 17, + FIF_TIFF = 18, + FIF_WBMP = 19, + FIF_PSD = 20, + FIF_CUT = 21, + FIF_XBM = 22, + FIF_XPM = 23, + FIF_DDS = 24, + FIF_GIF = 25, + FIF_HDR = 26, + FIF_FAXG3 = 27, + FIF_SGI = 28, + FIF_EXR = 29, + FIF_J2K = 30, + FIF_JP2 = 31, + FIF_PFM = 32, + FIF_PICT = 33, + FIF_RAW = 34 +}; + +/** Image type used in FreeImage. +*/ +FI_ENUM(FREE_IMAGE_TYPE) { + FIT_UNKNOWN = 0, // unknown type + FIT_BITMAP = 1, // standard image : 1-, 4-, 8-, 16-, 24-, 32-bit + FIT_UINT16 = 2, // array of unsigned short : unsigned 16-bit + FIT_INT16 = 3, // array of short : signed 16-bit + FIT_UINT32 = 4, // array of unsigned long : unsigned 32-bit + FIT_INT32 = 5, // array of long : signed 32-bit + FIT_FLOAT = 6, // array of float : 32-bit IEEE floating point + FIT_DOUBLE = 7, // array of double : 64-bit IEEE floating point + FIT_COMPLEX = 8, // array of FICOMPLEX : 2 x 64-bit IEEE floating point + FIT_RGB16 = 9, // 48-bit RGB image : 3 x 16-bit + FIT_RGBA16 = 10, // 64-bit RGBA image : 4 x 16-bit + FIT_RGBF = 11, // 96-bit RGB float image : 3 x 32-bit IEEE floating point + FIT_RGBAF = 12 // 128-bit RGBA float image : 4 x 32-bit IEEE floating point +}; + +/** Image color type used in FreeImage. +*/ +FI_ENUM(FREE_IMAGE_COLOR_TYPE) { + FIC_MINISWHITE = 0, // min value is white + FIC_MINISBLACK = 1, // min value is black + FIC_RGB = 2, // RGB color model + FIC_PALETTE = 3, // color map indexed + FIC_RGBALPHA = 4, // RGB color model with alpha channel + FIC_CMYK = 5 // CMYK color model +}; + +/** Color quantization algorithms. +Constants used in FreeImage_ColorQuantize. +*/ +FI_ENUM(FREE_IMAGE_QUANTIZE) { + FIQ_WUQUANT = 0, // Xiaolin Wu color quantization algorithm + FIQ_NNQUANT = 1 // NeuQuant neural-net quantization algorithm by Anthony Dekker +}; + +/** Dithering algorithms. +Constants used in FreeImage_Dither. +*/ +FI_ENUM(FREE_IMAGE_DITHER) { + FID_FS = 0, // Floyd & Steinberg error diffusion + FID_BAYER4x4 = 1, // Bayer ordered dispersed dot dithering (order 2 dithering matrix) + FID_BAYER8x8 = 2, // Bayer ordered dispersed dot dithering (order 3 dithering matrix) + FID_CLUSTER6x6 = 3, // Ordered clustered dot dithering (order 3 - 6x6 matrix) + FID_CLUSTER8x8 = 4, // Ordered clustered dot dithering (order 4 - 8x8 matrix) + FID_CLUSTER16x16= 5, // Ordered clustered dot dithering (order 8 - 16x16 matrix) + FID_BAYER16x16 = 6 // Bayer ordered dispersed dot dithering (order 4 dithering matrix) +}; + +/** Lossless JPEG transformations +Constants used in FreeImage_JPEGTransform +*/ +FI_ENUM(FREE_IMAGE_JPEG_OPERATION) { + FIJPEG_OP_NONE = 0, // no transformation + FIJPEG_OP_FLIP_H = 1, // horizontal flip + FIJPEG_OP_FLIP_V = 2, // vertical flip + FIJPEG_OP_TRANSPOSE = 3, // transpose across UL-to-LR axis + FIJPEG_OP_TRANSVERSE = 4, // transpose across UR-to-LL axis + FIJPEG_OP_ROTATE_90 = 5, // 90-degree clockwise rotation + FIJPEG_OP_ROTATE_180 = 6, // 180-degree rotation + FIJPEG_OP_ROTATE_270 = 7 // 270-degree clockwise (or 90 ccw) +}; + +/** Tone mapping operators. +Constants used in FreeImage_ToneMapping. +*/ +FI_ENUM(FREE_IMAGE_TMO) { + FITMO_DRAGO03 = 0, // Adaptive logarithmic mapping (F. Drago, 2003) + FITMO_REINHARD05 = 1, // Dynamic range reduction inspired by photoreceptor physiology (E. Reinhard, 2005) + FITMO_FATTAL02 = 2 // Gradient domain high dynamic range compression (R. Fattal, 2002) +}; + +/** Upsampling / downsampling filters. +Constants used in FreeImage_Rescale. +*/ +FI_ENUM(FREE_IMAGE_FILTER) { + FILTER_BOX = 0, // Box, pulse, Fourier window, 1st order (constant) b-spline + FILTER_BICUBIC = 1, // Mitchell & Netravali's two-param cubic filter + FILTER_BILINEAR = 2, // Bilinear filter + FILTER_BSPLINE = 3, // 4th order (cubic) b-spline + FILTER_CATMULLROM = 4, // Catmull-Rom spline, Overhauser spline + FILTER_LANCZOS3 = 5 // Lanczos3 filter +}; + +/** Color channels. +Constants used in color manipulation routines. +*/ +FI_ENUM(FREE_IMAGE_COLOR_CHANNEL) { + FICC_RGB = 0, // Use red, green and blue channels + FICC_RED = 1, // Use red channel + FICC_GREEN = 2, // Use green channel + FICC_BLUE = 3, // Use blue channel + FICC_ALPHA = 4, // Use alpha channel + FICC_BLACK = 5, // Use black channel + FICC_REAL = 6, // Complex images: use real part + FICC_IMAG = 7, // Complex images: use imaginary part + FICC_MAG = 8, // Complex images: use magnitude + FICC_PHASE = 9 // Complex images: use phase +}; + +// Metadata support --------------------------------------------------------- + +/** + Tag data type information (based on TIFF specifications) + + Note: RATIONALs are the ratio of two 32-bit integer values. +*/ +FI_ENUM(FREE_IMAGE_MDTYPE) { + FIDT_NOTYPE = 0, // placeholder + FIDT_BYTE = 1, // 8-bit unsigned integer + FIDT_ASCII = 2, // 8-bit bytes w/ last byte null + FIDT_SHORT = 3, // 16-bit unsigned integer + FIDT_LONG = 4, // 32-bit unsigned integer + FIDT_RATIONAL = 5, // 64-bit unsigned fraction + FIDT_SBYTE = 6, // 8-bit signed integer + FIDT_UNDEFINED = 7, // 8-bit untyped data + FIDT_SSHORT = 8, // 16-bit signed integer + FIDT_SLONG = 9, // 32-bit signed integer + FIDT_SRATIONAL = 10, // 64-bit signed fraction + FIDT_FLOAT = 11, // 32-bit IEEE floating point + FIDT_DOUBLE = 12, // 64-bit IEEE floating point + FIDT_IFD = 13, // 32-bit unsigned integer (offset) + FIDT_PALETTE = 14 // 32-bit RGBQUAD +}; + +/** + Metadata models supported by FreeImage +*/ +FI_ENUM(FREE_IMAGE_MDMODEL) { + FIMD_NODATA = -1, + FIMD_COMMENTS = 0, // single comment or keywords + FIMD_EXIF_MAIN = 1, // Exif-TIFF metadata + FIMD_EXIF_EXIF = 2, // Exif-specific metadata + FIMD_EXIF_GPS = 3, // Exif GPS metadata + FIMD_EXIF_MAKERNOTE = 4, // Exif maker note metadata + FIMD_EXIF_INTEROP = 5, // Exif interoperability metadata + FIMD_IPTC = 6, // IPTC/NAA metadata + FIMD_XMP = 7, // Abobe XMP metadata + FIMD_GEOTIFF = 8, // GeoTIFF metadata + FIMD_ANIMATION = 9, // Animation metadata + FIMD_CUSTOM = 10 // Used to attach other metadata types to a dib +}; + +/** + Handle to a metadata model +*/ +FI_STRUCT (FIMETADATA) { void *data; }; + +/** + Handle to a FreeImage tag +*/ +FI_STRUCT (FITAG) { void *data; }; + +// File IO routines --------------------------------------------------------- + +#ifndef FREEIMAGE_IO +#define FREEIMAGE_IO + +typedef void* fi_handle; +typedef unsigned (DLL_CALLCONV *FI_ReadProc) (void *buffer, unsigned size, unsigned count, fi_handle handle); +typedef unsigned (DLL_CALLCONV *FI_WriteProc) (void *buffer, unsigned size, unsigned count, fi_handle handle); +typedef int (DLL_CALLCONV *FI_SeekProc) (fi_handle handle, long offset, int origin); +typedef long (DLL_CALLCONV *FI_TellProc) (fi_handle handle); + +#if (defined(_WIN32) || defined(__WIN32__)) +#pragma pack(push, 1) +#else +#pragma pack(1) +#endif // WIN32 + +FI_STRUCT(FreeImageIO) { + FI_ReadProc read_proc; // pointer to the function used to read data + FI_WriteProc write_proc; // pointer to the function used to write data + FI_SeekProc seek_proc; // pointer to the function used to seek + FI_TellProc tell_proc; // pointer to the function used to aquire the current position +}; + +#if (defined(_WIN32) || defined(__WIN32__)) +#pragma pack(pop) +#else +#pragma pack() +#endif // WIN32 + +/** +Handle to a memory I/O stream +*/ +FI_STRUCT (FIMEMORY) { void *data; }; + +#endif // FREEIMAGE_IO + +// Plugin routines ---------------------------------------------------------- + +#ifndef PLUGINS +#define PLUGINS + +typedef const char *(DLL_CALLCONV *FI_FormatProc)(void); +typedef const char *(DLL_CALLCONV *FI_DescriptionProc)(void); +typedef const char *(DLL_CALLCONV *FI_ExtensionListProc)(void); +typedef const char *(DLL_CALLCONV *FI_RegExprProc)(void); +typedef void *(DLL_CALLCONV *FI_OpenProc)(FreeImageIO *io, fi_handle handle, BOOL read); +typedef void (DLL_CALLCONV *FI_CloseProc)(FreeImageIO *io, fi_handle handle, void *data); +typedef int (DLL_CALLCONV *FI_PageCountProc)(FreeImageIO *io, fi_handle handle, void *data); +typedef int (DLL_CALLCONV *FI_PageCapabilityProc)(FreeImageIO *io, fi_handle handle, void *data); +typedef FIBITMAP *(DLL_CALLCONV *FI_LoadProc)(FreeImageIO *io, fi_handle handle, int page, int flags, void *data); +typedef BOOL (DLL_CALLCONV *FI_SaveProc)(FreeImageIO *io, FIBITMAP *dib, fi_handle handle, int page, int flags, void *data); +typedef BOOL (DLL_CALLCONV *FI_ValidateProc)(FreeImageIO *io, fi_handle handle); +typedef const char *(DLL_CALLCONV *FI_MimeProc)(void); +typedef BOOL (DLL_CALLCONV *FI_SupportsExportBPPProc)(int bpp); +typedef BOOL (DLL_CALLCONV *FI_SupportsExportTypeProc)(FREE_IMAGE_TYPE type); +typedef BOOL (DLL_CALLCONV *FI_SupportsICCProfilesProc)(void); + +FI_STRUCT (Plugin) { + FI_FormatProc format_proc; + FI_DescriptionProc description_proc; + FI_ExtensionListProc extension_proc; + FI_RegExprProc regexpr_proc; + FI_OpenProc open_proc; + FI_CloseProc close_proc; + FI_PageCountProc pagecount_proc; + FI_PageCapabilityProc pagecapability_proc; + FI_LoadProc load_proc; + FI_SaveProc save_proc; + FI_ValidateProc validate_proc; + FI_MimeProc mime_proc; + FI_SupportsExportBPPProc supports_export_bpp_proc; + FI_SupportsExportTypeProc supports_export_type_proc; + FI_SupportsICCProfilesProc supports_icc_profiles_proc; +}; + +typedef void (DLL_CALLCONV *FI_InitProc)(Plugin *plugin, int format_id); + +#endif // PLUGINS + + +// Load / Save flag constants ----------------------------------------------- + +#define BMP_DEFAULT 0 +#define BMP_SAVE_RLE 1 +#define CUT_DEFAULT 0 +#define DDS_DEFAULT 0 +#define EXR_DEFAULT 0 // save data as half with piz-based wavelet compression +#define EXR_FLOAT 0x0001 // save data as float instead of as half (not recommended) +#define EXR_NONE 0x0002 // save with no compression +#define EXR_ZIP 0x0004 // save with zlib compression, in blocks of 16 scan lines +#define EXR_PIZ 0x0008 // save with piz-based wavelet compression +#define EXR_PXR24 0x0010 // save with lossy 24-bit float compression +#define EXR_B44 0x0020 // save with lossy 44% float compression - goes to 22% when combined with EXR_LC +#define EXR_LC 0x0040 // save images with one luminance and two chroma channels, rather than as RGB (lossy compression) +#define FAXG3_DEFAULT 0 +#define GIF_DEFAULT 0 +#define GIF_LOAD256 1 // Load the image as a 256 color image with ununsed palette entries, if it's 16 or 2 color +#define GIF_PLAYBACK 2 // 'Play' the GIF to generate each frame (as 32bpp) instead of returning raw frame data when loading +#define HDR_DEFAULT 0 +#define ICO_DEFAULT 0 +#define ICO_MAKEALPHA 1 // convert to 32bpp and create an alpha channel from the AND-mask when loading +#define IFF_DEFAULT 0 +#define J2K_DEFAULT 0 // save with a 16:1 rate +#define JP2_DEFAULT 0 // save with a 16:1 rate +#define JPEG_DEFAULT 0 // loading (see JPEG_FAST); saving (see JPEG_QUALITYGOOD|JPEG_SUBSAMPLING_420) +#define JPEG_FAST 0x0001 // load the file as fast as possible, sacrificing some quality +#define JPEG_ACCURATE 0x0002 // load the file with the best quality, sacrificing some speed +#define JPEG_CMYK 0x0004 // load separated CMYK "as is" (use | to combine with other load flags) +#define JPEG_EXIFROTATE 0x0008 // load and rotate according to Exif 'Orientation' tag if available +#define JPEG_QUALITYSUPERB 0x80 // save with superb quality (100:1) +#define JPEG_QUALITYGOOD 0x0100 // save with good quality (75:1) +#define JPEG_QUALITYNORMAL 0x0200 // save with normal quality (50:1) +#define JPEG_QUALITYAVERAGE 0x0400 // save with average quality (25:1) +#define JPEG_QUALITYBAD 0x0800 // save with bad quality (10:1) +#define JPEG_PROGRESSIVE 0x2000 // save as a progressive-JPEG (use | to combine with other save flags) +#define JPEG_SUBSAMPLING_411 0x1000 // save with high 4x1 chroma subsampling (4:1:1) +#define JPEG_SUBSAMPLING_420 0x4000 // save with medium 2x2 medium chroma subsampling (4:2:0) - default value +#define JPEG_SUBSAMPLING_422 0x8000 // save with low 2x1 chroma subsampling (4:2:2) +#define JPEG_SUBSAMPLING_444 0x10000 // save with no chroma subsampling (4:4:4) +#define KOALA_DEFAULT 0 +#define LBM_DEFAULT 0 +#define MNG_DEFAULT 0 +#define PCD_DEFAULT 0 +#define PCD_BASE 1 // load the bitmap sized 768 x 512 +#define PCD_BASEDIV4 2 // load the bitmap sized 384 x 256 +#define PCD_BASEDIV16 3 // load the bitmap sized 192 x 128 +#define PCX_DEFAULT 0 +#define PFM_DEFAULT 0 +#define PICT_DEFAULT 0 +#define PNG_DEFAULT 0 +#define PNG_IGNOREGAMMA 1 // loading: avoid gamma correction +#define PNG_Z_BEST_SPEED 0x0001 // save using ZLib level 1 compression flag (default value is 6) +#define PNG_Z_DEFAULT_COMPRESSION 0x0006 // save using ZLib level 6 compression flag (default recommended value) +#define PNG_Z_BEST_COMPRESSION 0x0009 // save using ZLib level 9 compression flag (default value is 6) +#define PNG_Z_NO_COMPRESSION 0x0100 // save without ZLib compression +#define PNG_INTERLACED 0x0200 // save using Adam7 interlacing (use | to combine with other save flags) +#define PNM_DEFAULT 0 +#define PNM_SAVE_RAW 0 // If set the writer saves in RAW format (i.e. P4, P5 or P6) +#define PNM_SAVE_ASCII 1 // If set the writer saves in ASCII format (i.e. P1, P2 or P3) +#define PSD_DEFAULT 0 +#define RAS_DEFAULT 0 +#define RAW_DEFAULT 0 // load the file as linear RGB 48-bit +#define RAW_PREVIEW 1 // try to load the embedded JPEG preview with included Exif Data or default to RGB 24-bit +#define RAW_DISPLAY 2 // load the file as RGB 24-bit +#define SGI_DEFAULT 0 +#define TARGA_DEFAULT 0 +#define TARGA_LOAD_RGB888 1 // If set the loader converts RGB555 and ARGB8888 -> RGB888. +#define TIFF_DEFAULT 0 +#define TIFF_CMYK 0x0001 // reads/stores tags for separated CMYK (use | to combine with compression flags) +#define TIFF_PACKBITS 0x0100 // save using PACKBITS compression +#define TIFF_DEFLATE 0x0200 // save using DEFLATE compression (a.k.a. ZLIB compression) +#define TIFF_ADOBE_DEFLATE 0x0400 // save using ADOBE DEFLATE compression +#define TIFF_NONE 0x0800 // save without any compression +#define TIFF_CCITTFAX3 0x1000 // save using CCITT Group 3 fax encoding +#define TIFF_CCITTFAX4 0x2000 // save using CCITT Group 4 fax encoding +#define TIFF_LZW 0x4000 // save using LZW compression +#define TIFF_JPEG 0x8000 // save using JPEG compression +#define WBMP_DEFAULT 0 +#define XBM_DEFAULT 0 +#define XPM_DEFAULT 0 + +// Background filling options --------------------------------------------------------- +// Constants used in FreeImage_FillBackground and FreeImage_EnlargeCanvas + +#define FI_COLOR_IS_RGB_COLOR 0x00 // RGBQUAD color is a RGB color (contains no valid alpha channel) +#define FI_COLOR_IS_RGBA_COLOR 0x01 // RGBQUAD color is a RGBA color (contains a valid alpha channel) +#define FI_COLOR_FIND_EQUAL_COLOR 0x02 // For palettized images: lookup equal RGB color from palette +#define FI_COLOR_ALPHA_IS_INDEX 0x04 // The color's rgbReserved member (alpha) contains the palette index to be used +#define FI_COLOR_PALETTE_SEARCH_MASK (FI_COLOR_FIND_EQUAL_COLOR | FI_COLOR_ALPHA_IS_INDEX) // No color lookup is performed + + +#ifdef __cplusplus +extern "C" { +#endif + +// Init / Error routines ---------------------------------------------------- + +DLL_API void DLL_CALLCONV FreeImage_Initialise(BOOL load_local_plugins_only FI_DEFAULT(FALSE)); +DLL_API void DLL_CALLCONV FreeImage_DeInitialise(void); + +// Version routines --------------------------------------------------------- + +DLL_API const char *DLL_CALLCONV FreeImage_GetVersion(void); +DLL_API const char *DLL_CALLCONV FreeImage_GetCopyrightMessage(void); + +// Message output functions ------------------------------------------------- + +typedef void (*FreeImage_OutputMessageFunction)(FREE_IMAGE_FORMAT fif, const char *msg); +typedef void (DLL_CALLCONV *FreeImage_OutputMessageFunctionStdCall)(FREE_IMAGE_FORMAT fif, const char *msg); + +DLL_API void DLL_CALLCONV FreeImage_SetOutputMessageStdCall(FreeImage_OutputMessageFunctionStdCall omf); +DLL_API void DLL_CALLCONV FreeImage_SetOutputMessage(FreeImage_OutputMessageFunction omf); +DLL_API void DLL_CALLCONV FreeImage_OutputMessageProc(int fif, const char *fmt, ...); + +// Allocate / Clone / Unload routines --------------------------------------- + +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_Allocate(int width, int height, int bpp, unsigned red_mask FI_DEFAULT(0), unsigned green_mask FI_DEFAULT(0), unsigned blue_mask FI_DEFAULT(0)); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_AllocateT(FREE_IMAGE_TYPE type, int width, int height, int bpp FI_DEFAULT(8), unsigned red_mask FI_DEFAULT(0), unsigned green_mask FI_DEFAULT(0), unsigned blue_mask FI_DEFAULT(0)); +DLL_API FIBITMAP * DLL_CALLCONV FreeImage_Clone(FIBITMAP *dib); +DLL_API void DLL_CALLCONV FreeImage_Unload(FIBITMAP *dib); + +// Load / Save routines ----------------------------------------------------- + +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_Load(FREE_IMAGE_FORMAT fif, const char *filename, int flags FI_DEFAULT(0)); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_LoadU(FREE_IMAGE_FORMAT fif, const wchar_t *filename, int flags FI_DEFAULT(0)); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_LoadFromHandle(FREE_IMAGE_FORMAT fif, FreeImageIO *io, fi_handle handle, int flags FI_DEFAULT(0)); +DLL_API BOOL DLL_CALLCONV FreeImage_Save(FREE_IMAGE_FORMAT fif, FIBITMAP *dib, const char *filename, int flags FI_DEFAULT(0)); +DLL_API BOOL DLL_CALLCONV FreeImage_SaveU(FREE_IMAGE_FORMAT fif, FIBITMAP *dib, const wchar_t *filename, int flags FI_DEFAULT(0)); +DLL_API BOOL DLL_CALLCONV FreeImage_SaveToHandle(FREE_IMAGE_FORMAT fif, FIBITMAP *dib, FreeImageIO *io, fi_handle handle, int flags FI_DEFAULT(0)); + +// Memory I/O stream routines ----------------------------------------------- + +DLL_API FIMEMORY *DLL_CALLCONV FreeImage_OpenMemory(BYTE *data FI_DEFAULT(0), DWORD size_in_bytes FI_DEFAULT(0)); +DLL_API void DLL_CALLCONV FreeImage_CloseMemory(FIMEMORY *stream); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_LoadFromMemory(FREE_IMAGE_FORMAT fif, FIMEMORY *stream, int flags FI_DEFAULT(0)); +DLL_API BOOL DLL_CALLCONV FreeImage_SaveToMemory(FREE_IMAGE_FORMAT fif, FIBITMAP *dib, FIMEMORY *stream, int flags FI_DEFAULT(0)); +DLL_API long DLL_CALLCONV FreeImage_TellMemory(FIMEMORY *stream); +DLL_API BOOL DLL_CALLCONV FreeImage_SeekMemory(FIMEMORY *stream, long offset, int origin); +DLL_API BOOL DLL_CALLCONV FreeImage_AcquireMemory(FIMEMORY *stream, BYTE **data, DWORD *size_in_bytes); +DLL_API unsigned DLL_CALLCONV FreeImage_ReadMemory(void *buffer, unsigned size, unsigned count, FIMEMORY *stream); +DLL_API unsigned DLL_CALLCONV FreeImage_WriteMemory(const void *buffer, unsigned size, unsigned count, FIMEMORY *stream); +DLL_API FIMULTIBITMAP *DLL_CALLCONV FreeImage_LoadMultiBitmapFromMemory(FREE_IMAGE_FORMAT fif, FIMEMORY *stream, int flags FI_DEFAULT(0)); + +// Plugin Interface --------------------------------------------------------- + +DLL_API FREE_IMAGE_FORMAT DLL_CALLCONV FreeImage_RegisterLocalPlugin(FI_InitProc proc_address, const char *format FI_DEFAULT(0), const char *description FI_DEFAULT(0), const char *extension FI_DEFAULT(0), const char *regexpr FI_DEFAULT(0)); +DLL_API FREE_IMAGE_FORMAT DLL_CALLCONV FreeImage_RegisterExternalPlugin(const char *path, const char *format FI_DEFAULT(0), const char *description FI_DEFAULT(0), const char *extension FI_DEFAULT(0), const char *regexpr FI_DEFAULT(0)); +DLL_API int DLL_CALLCONV FreeImage_GetFIFCount(void); +DLL_API int DLL_CALLCONV FreeImage_SetPluginEnabled(FREE_IMAGE_FORMAT fif, BOOL enable); +DLL_API int DLL_CALLCONV FreeImage_IsPluginEnabled(FREE_IMAGE_FORMAT fif); +DLL_API FREE_IMAGE_FORMAT DLL_CALLCONV FreeImage_GetFIFFromFormat(const char *format); +DLL_API FREE_IMAGE_FORMAT DLL_CALLCONV FreeImage_GetFIFFromMime(const char *mime); +DLL_API const char *DLL_CALLCONV FreeImage_GetFormatFromFIF(FREE_IMAGE_FORMAT fif); +DLL_API const char *DLL_CALLCONV FreeImage_GetFIFExtensionList(FREE_IMAGE_FORMAT fif); +DLL_API const char *DLL_CALLCONV FreeImage_GetFIFDescription(FREE_IMAGE_FORMAT fif); +DLL_API const char *DLL_CALLCONV FreeImage_GetFIFRegExpr(FREE_IMAGE_FORMAT fif); +DLL_API const char *DLL_CALLCONV FreeImage_GetFIFMimeType(FREE_IMAGE_FORMAT fif); +DLL_API FREE_IMAGE_FORMAT DLL_CALLCONV FreeImage_GetFIFFromFilename(const char *filename); +DLL_API FREE_IMAGE_FORMAT DLL_CALLCONV FreeImage_GetFIFFromFilenameU(const wchar_t *filename); +DLL_API BOOL DLL_CALLCONV FreeImage_FIFSupportsReading(FREE_IMAGE_FORMAT fif); +DLL_API BOOL DLL_CALLCONV FreeImage_FIFSupportsWriting(FREE_IMAGE_FORMAT fif); +DLL_API BOOL DLL_CALLCONV FreeImage_FIFSupportsExportBPP(FREE_IMAGE_FORMAT fif, int bpp); +DLL_API BOOL DLL_CALLCONV FreeImage_FIFSupportsExportType(FREE_IMAGE_FORMAT fif, FREE_IMAGE_TYPE type); +DLL_API BOOL DLL_CALLCONV FreeImage_FIFSupportsICCProfiles(FREE_IMAGE_FORMAT fif); + +// Multipaging interface ---------------------------------------------------- + +DLL_API FIMULTIBITMAP * DLL_CALLCONV FreeImage_OpenMultiBitmap(FREE_IMAGE_FORMAT fif, const char *filename, BOOL create_new, BOOL read_only, BOOL keep_cache_in_memory FI_DEFAULT(FALSE), int flags FI_DEFAULT(0)); +DLL_API FIMULTIBITMAP * DLL_CALLCONV FreeImage_OpenMultiBitmapFromHandle(FREE_IMAGE_FORMAT fif, FreeImageIO *io, fi_handle handle, int flags FI_DEFAULT(0)); +DLL_API BOOL DLL_CALLCONV FreeImage_CloseMultiBitmap(FIMULTIBITMAP *bitmap, int flags FI_DEFAULT(0)); +DLL_API int DLL_CALLCONV FreeImage_GetPageCount(FIMULTIBITMAP *bitmap); +DLL_API void DLL_CALLCONV FreeImage_AppendPage(FIMULTIBITMAP *bitmap, FIBITMAP *data); +DLL_API void DLL_CALLCONV FreeImage_InsertPage(FIMULTIBITMAP *bitmap, int page, FIBITMAP *data); +DLL_API void DLL_CALLCONV FreeImage_DeletePage(FIMULTIBITMAP *bitmap, int page); +DLL_API FIBITMAP * DLL_CALLCONV FreeImage_LockPage(FIMULTIBITMAP *bitmap, int page); +DLL_API void DLL_CALLCONV FreeImage_UnlockPage(FIMULTIBITMAP *bitmap, FIBITMAP *data, BOOL changed); +DLL_API BOOL DLL_CALLCONV FreeImage_MovePage(FIMULTIBITMAP *bitmap, int target, int source); +DLL_API BOOL DLL_CALLCONV FreeImage_GetLockedPageNumbers(FIMULTIBITMAP *bitmap, int *pages, int *count); + +// Filetype request routines ------------------------------------------------ + +DLL_API FREE_IMAGE_FORMAT DLL_CALLCONV FreeImage_GetFileType(const char *filename, int size FI_DEFAULT(0)); +DLL_API FREE_IMAGE_FORMAT DLL_CALLCONV FreeImage_GetFileTypeU(const wchar_t *filename, int size FI_DEFAULT(0)); +DLL_API FREE_IMAGE_FORMAT DLL_CALLCONV FreeImage_GetFileTypeFromHandle(FreeImageIO *io, fi_handle handle, int size FI_DEFAULT(0)); +DLL_API FREE_IMAGE_FORMAT DLL_CALLCONV FreeImage_GetFileTypeFromMemory(FIMEMORY *stream, int size FI_DEFAULT(0)); + +// Image type request routine ----------------------------------------------- + +DLL_API FREE_IMAGE_TYPE DLL_CALLCONV FreeImage_GetImageType(FIBITMAP *dib); + +// FreeImage helper routines ------------------------------------------------ + +DLL_API BOOL DLL_CALLCONV FreeImage_IsLittleEndian(void); +DLL_API BOOL DLL_CALLCONV FreeImage_LookupX11Color(const char *szColor, BYTE *nRed, BYTE *nGreen, BYTE *nBlue); +DLL_API BOOL DLL_CALLCONV FreeImage_LookupSVGColor(const char *szColor, BYTE *nRed, BYTE *nGreen, BYTE *nBlue); + +// Pixel access routines ---------------------------------------------------- + +DLL_API BYTE *DLL_CALLCONV FreeImage_GetBits(FIBITMAP *dib); +DLL_API BYTE *DLL_CALLCONV FreeImage_GetScanLine(FIBITMAP *dib, int scanline); + +DLL_API BOOL DLL_CALLCONV FreeImage_GetPixelIndex(FIBITMAP *dib, unsigned x, unsigned y, BYTE *value); +DLL_API BOOL DLL_CALLCONV FreeImage_GetPixelColor(FIBITMAP *dib, unsigned x, unsigned y, RGBQUAD *value); +DLL_API BOOL DLL_CALLCONV FreeImage_SetPixelIndex(FIBITMAP *dib, unsigned x, unsigned y, BYTE *value); +DLL_API BOOL DLL_CALLCONV FreeImage_SetPixelColor(FIBITMAP *dib, unsigned x, unsigned y, RGBQUAD *value); + +// DIB info routines -------------------------------------------------------- + +DLL_API unsigned DLL_CALLCONV FreeImage_GetColorsUsed(FIBITMAP *dib); +DLL_API unsigned DLL_CALLCONV FreeImage_GetBPP(FIBITMAP *dib); +DLL_API unsigned DLL_CALLCONV FreeImage_GetWidth(FIBITMAP *dib); +DLL_API unsigned DLL_CALLCONV FreeImage_GetHeight(FIBITMAP *dib); +DLL_API unsigned DLL_CALLCONV FreeImage_GetLine(FIBITMAP *dib); +DLL_API unsigned DLL_CALLCONV FreeImage_GetPitch(FIBITMAP *dib); +DLL_API unsigned DLL_CALLCONV FreeImage_GetDIBSize(FIBITMAP *dib); +DLL_API RGBQUAD *DLL_CALLCONV FreeImage_GetPalette(FIBITMAP *dib); + +DLL_API unsigned DLL_CALLCONV FreeImage_GetDotsPerMeterX(FIBITMAP *dib); +DLL_API unsigned DLL_CALLCONV FreeImage_GetDotsPerMeterY(FIBITMAP *dib); +DLL_API void DLL_CALLCONV FreeImage_SetDotsPerMeterX(FIBITMAP *dib, unsigned res); +DLL_API void DLL_CALLCONV FreeImage_SetDotsPerMeterY(FIBITMAP *dib, unsigned res); + +DLL_API BITMAPINFOHEADER *DLL_CALLCONV FreeImage_GetInfoHeader(FIBITMAP *dib); +DLL_API BITMAPINFO *DLL_CALLCONV FreeImage_GetInfo(FIBITMAP *dib); +DLL_API FREE_IMAGE_COLOR_TYPE DLL_CALLCONV FreeImage_GetColorType(FIBITMAP *dib); + +DLL_API unsigned DLL_CALLCONV FreeImage_GetRedMask(FIBITMAP *dib); +DLL_API unsigned DLL_CALLCONV FreeImage_GetGreenMask(FIBITMAP *dib); +DLL_API unsigned DLL_CALLCONV FreeImage_GetBlueMask(FIBITMAP *dib); + +DLL_API unsigned DLL_CALLCONV FreeImage_GetTransparencyCount(FIBITMAP *dib); +DLL_API BYTE * DLL_CALLCONV FreeImage_GetTransparencyTable(FIBITMAP *dib); +DLL_API void DLL_CALLCONV FreeImage_SetTransparent(FIBITMAP *dib, BOOL enabled); +DLL_API void DLL_CALLCONV FreeImage_SetTransparencyTable(FIBITMAP *dib, BYTE *table, int count); +DLL_API BOOL DLL_CALLCONV FreeImage_IsTransparent(FIBITMAP *dib); +DLL_API void DLL_CALLCONV FreeImage_SetTransparentIndex(FIBITMAP *dib, int index); +DLL_API int DLL_CALLCONV FreeImage_GetTransparentIndex(FIBITMAP *dib); + +DLL_API BOOL DLL_CALLCONV FreeImage_HasBackgroundColor(FIBITMAP *dib); +DLL_API BOOL DLL_CALLCONV FreeImage_GetBackgroundColor(FIBITMAP *dib, RGBQUAD *bkcolor); +DLL_API BOOL DLL_CALLCONV FreeImage_SetBackgroundColor(FIBITMAP *dib, RGBQUAD *bkcolor); + + +// ICC profile routines ----------------------------------------------------- + +DLL_API FIICCPROFILE *DLL_CALLCONV FreeImage_GetICCProfile(FIBITMAP *dib); +DLL_API FIICCPROFILE *DLL_CALLCONV FreeImage_CreateICCProfile(FIBITMAP *dib, void *data, long size); +DLL_API void DLL_CALLCONV FreeImage_DestroyICCProfile(FIBITMAP *dib); + +// Line conversion routines ------------------------------------------------- + +DLL_API void DLL_CALLCONV FreeImage_ConvertLine1To4(BYTE *target, BYTE *source, int width_in_pixels); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine8To4(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine16To4_555(BYTE *target, BYTE *source, int width_in_pixels); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine16To4_565(BYTE *target, BYTE *source, int width_in_pixels); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine24To4(BYTE *target, BYTE *source, int width_in_pixels); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine32To4(BYTE *target, BYTE *source, int width_in_pixels); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine1To8(BYTE *target, BYTE *source, int width_in_pixels); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine4To8(BYTE *target, BYTE *source, int width_in_pixels); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine16To8_555(BYTE *target, BYTE *source, int width_in_pixels); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine16To8_565(BYTE *target, BYTE *source, int width_in_pixels); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine24To8(BYTE *target, BYTE *source, int width_in_pixels); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine32To8(BYTE *target, BYTE *source, int width_in_pixels); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine1To16_555(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine4To16_555(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine8To16_555(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine16_565_To16_555(BYTE *target, BYTE *source, int width_in_pixels); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine24To16_555(BYTE *target, BYTE *source, int width_in_pixels); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine32To16_555(BYTE *target, BYTE *source, int width_in_pixels); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine1To16_565(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine4To16_565(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine8To16_565(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine16_555_To16_565(BYTE *target, BYTE *source, int width_in_pixels); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine24To16_565(BYTE *target, BYTE *source, int width_in_pixels); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine32To16_565(BYTE *target, BYTE *source, int width_in_pixels); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine1To24(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine4To24(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine8To24(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine16To24_555(BYTE *target, BYTE *source, int width_in_pixels); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine16To24_565(BYTE *target, BYTE *source, int width_in_pixels); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine32To24(BYTE *target, BYTE *source, int width_in_pixels); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine1To32(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine4To32(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine8To32(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine16To32_555(BYTE *target, BYTE *source, int width_in_pixels); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine16To32_565(BYTE *target, BYTE *source, int width_in_pixels); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine24To32(BYTE *target, BYTE *source, int width_in_pixels); + +// Smart conversion routines ------------------------------------------------ + +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_ConvertTo4Bits(FIBITMAP *dib); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_ConvertTo8Bits(FIBITMAP *dib); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_ConvertToGreyscale(FIBITMAP *dib); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_ConvertTo16Bits555(FIBITMAP *dib); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_ConvertTo16Bits565(FIBITMAP *dib); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_ConvertTo24Bits(FIBITMAP *dib); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_ConvertTo32Bits(FIBITMAP *dib); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_ColorQuantize(FIBITMAP *dib, FREE_IMAGE_QUANTIZE quantize); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_ColorQuantizeEx(FIBITMAP *dib, FREE_IMAGE_QUANTIZE quantize FI_DEFAULT(FIQ_WUQUANT), int PaletteSize FI_DEFAULT(256), int ReserveSize FI_DEFAULT(0), RGBQUAD *ReservePalette FI_DEFAULT(NULL)); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_Threshold(FIBITMAP *dib, BYTE T); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_Dither(FIBITMAP *dib, FREE_IMAGE_DITHER algorithm); + +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_ConvertFromRawBits(BYTE *bits, int width, int height, int pitch, unsigned bpp, unsigned red_mask, unsigned green_mask, unsigned blue_mask, BOOL topdown FI_DEFAULT(FALSE)); +DLL_API void DLL_CALLCONV FreeImage_ConvertToRawBits(BYTE *bits, FIBITMAP *dib, int pitch, unsigned bpp, unsigned red_mask, unsigned green_mask, unsigned blue_mask, BOOL topdown FI_DEFAULT(FALSE)); + +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_ConvertToRGBF(FIBITMAP *dib); + +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_ConvertToStandardType(FIBITMAP *src, BOOL scale_linear FI_DEFAULT(TRUE)); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_ConvertToType(FIBITMAP *src, FREE_IMAGE_TYPE dst_type, BOOL scale_linear FI_DEFAULT(TRUE)); + +// tone mapping operators +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_ToneMapping(FIBITMAP *dib, FREE_IMAGE_TMO tmo, double first_param FI_DEFAULT(0), double second_param FI_DEFAULT(0)); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_TmoDrago03(FIBITMAP *src, double gamma FI_DEFAULT(2.2), double exposure FI_DEFAULT(0)); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_TmoReinhard05(FIBITMAP *src, double intensity FI_DEFAULT(0), double contrast FI_DEFAULT(0)); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_TmoReinhard05Ex(FIBITMAP *src, double intensity FI_DEFAULT(0), double contrast FI_DEFAULT(0), double adaptation FI_DEFAULT(1), double color_correction FI_DEFAULT(0)); + +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_TmoFattal02(FIBITMAP *src, double color_saturation FI_DEFAULT(0.5), double attenuation FI_DEFAULT(0.85)); + +// ZLib interface ----------------------------------------------------------- + +DLL_API DWORD DLL_CALLCONV FreeImage_ZLibCompress(BYTE *target, DWORD target_size, BYTE *source, DWORD source_size); +DLL_API DWORD DLL_CALLCONV FreeImage_ZLibUncompress(BYTE *target, DWORD target_size, BYTE *source, DWORD source_size); +DLL_API DWORD DLL_CALLCONV FreeImage_ZLibGZip(BYTE *target, DWORD target_size, BYTE *source, DWORD source_size); +DLL_API DWORD DLL_CALLCONV FreeImage_ZLibGUnzip(BYTE *target, DWORD target_size, BYTE *source, DWORD source_size); +DLL_API DWORD DLL_CALLCONV FreeImage_ZLibCRC32(DWORD crc, BYTE *source, DWORD source_size); + +// -------------------------------------------------------------------------- +// Metadata routines -------------------------------------------------------- +// -------------------------------------------------------------------------- + +// tag creation / destruction +DLL_API FITAG *DLL_CALLCONV FreeImage_CreateTag(void); +DLL_API void DLL_CALLCONV FreeImage_DeleteTag(FITAG *tag); +DLL_API FITAG *DLL_CALLCONV FreeImage_CloneTag(FITAG *tag); + +// tag getters and setters +DLL_API const char *DLL_CALLCONV FreeImage_GetTagKey(FITAG *tag); +DLL_API const char *DLL_CALLCONV FreeImage_GetTagDescription(FITAG *tag); +DLL_API WORD DLL_CALLCONV FreeImage_GetTagID(FITAG *tag); +DLL_API FREE_IMAGE_MDTYPE DLL_CALLCONV FreeImage_GetTagType(FITAG *tag); +DLL_API DWORD DLL_CALLCONV FreeImage_GetTagCount(FITAG *tag); +DLL_API DWORD DLL_CALLCONV FreeImage_GetTagLength(FITAG *tag); +DLL_API const void *DLL_CALLCONV FreeImage_GetTagValue(FITAG *tag); + +DLL_API BOOL DLL_CALLCONV FreeImage_SetTagKey(FITAG *tag, const char *key); +DLL_API BOOL DLL_CALLCONV FreeImage_SetTagDescription(FITAG *tag, const char *description); +DLL_API BOOL DLL_CALLCONV FreeImage_SetTagID(FITAG *tag, WORD id); +DLL_API BOOL DLL_CALLCONV FreeImage_SetTagType(FITAG *tag, FREE_IMAGE_MDTYPE type); +DLL_API BOOL DLL_CALLCONV FreeImage_SetTagCount(FITAG *tag, DWORD count); +DLL_API BOOL DLL_CALLCONV FreeImage_SetTagLength(FITAG *tag, DWORD length); +DLL_API BOOL DLL_CALLCONV FreeImage_SetTagValue(FITAG *tag, const void *value); + +// iterator +DLL_API FIMETADATA *DLL_CALLCONV FreeImage_FindFirstMetadata(FREE_IMAGE_MDMODEL model, FIBITMAP *dib, FITAG **tag); +DLL_API BOOL DLL_CALLCONV FreeImage_FindNextMetadata(FIMETADATA *mdhandle, FITAG **tag); +DLL_API void DLL_CALLCONV FreeImage_FindCloseMetadata(FIMETADATA *mdhandle); + +// metadata setter and getter +DLL_API BOOL DLL_CALLCONV FreeImage_SetMetadata(FREE_IMAGE_MDMODEL model, FIBITMAP *dib, const char *key, FITAG *tag); +DLL_API BOOL DLL_CALLCONV FreeImage_GetMetadata(FREE_IMAGE_MDMODEL model, FIBITMAP *dib, const char *key, FITAG **tag); + +// helpers +DLL_API unsigned DLL_CALLCONV FreeImage_GetMetadataCount(FREE_IMAGE_MDMODEL model, FIBITMAP *dib); +DLL_API BOOL DLL_CALLCONV FreeImage_CloneMetadata(FIBITMAP *dst, FIBITMAP *src); + +// tag to C string conversion +DLL_API const char* DLL_CALLCONV FreeImage_TagToString(FREE_IMAGE_MDMODEL model, FITAG *tag, char *Make FI_DEFAULT(NULL)); + +// -------------------------------------------------------------------------- +// Image manipulation toolkit ----------------------------------------------- +// -------------------------------------------------------------------------- + +// rotation and flipping +/// @deprecated see FreeImage_Rotate +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_RotateClassic(FIBITMAP *dib, double angle); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_Rotate(FIBITMAP *dib, double angle, const void *bkcolor FI_DEFAULT(NULL)); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_RotateEx(FIBITMAP *dib, double angle, double x_shift, double y_shift, double x_origin, double y_origin, BOOL use_mask); +DLL_API BOOL DLL_CALLCONV FreeImage_FlipHorizontal(FIBITMAP *dib); +DLL_API BOOL DLL_CALLCONV FreeImage_FlipVertical(FIBITMAP *dib); +DLL_API BOOL DLL_CALLCONV FreeImage_JPEGTransform(const char *src_file, const char *dst_file, FREE_IMAGE_JPEG_OPERATION operation, BOOL perfect FI_DEFAULT(FALSE)); +DLL_API BOOL DLL_CALLCONV FreeImage_JPEGTransformU(const wchar_t *src_file, const wchar_t *dst_file, FREE_IMAGE_JPEG_OPERATION operation, BOOL perfect FI_DEFAULT(FALSE)); + +// upsampling / downsampling +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_Rescale(FIBITMAP *dib, int dst_width, int dst_height, FREE_IMAGE_FILTER filter); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_MakeThumbnail(FIBITMAP *dib, int max_pixel_size, BOOL convert FI_DEFAULT(TRUE)); + +// color manipulation routines (point operations) +DLL_API BOOL DLL_CALLCONV FreeImage_AdjustCurve(FIBITMAP *dib, BYTE *LUT, FREE_IMAGE_COLOR_CHANNEL channel); +DLL_API BOOL DLL_CALLCONV FreeImage_AdjustGamma(FIBITMAP *dib, double gamma); +DLL_API BOOL DLL_CALLCONV FreeImage_AdjustBrightness(FIBITMAP *dib, double percentage); +DLL_API BOOL DLL_CALLCONV FreeImage_AdjustContrast(FIBITMAP *dib, double percentage); +DLL_API BOOL DLL_CALLCONV FreeImage_Invert(FIBITMAP *dib); +DLL_API BOOL DLL_CALLCONV FreeImage_GetHistogram(FIBITMAP *dib, DWORD *histo, FREE_IMAGE_COLOR_CHANNEL channel FI_DEFAULT(FICC_BLACK)); +DLL_API int DLL_CALLCONV FreeImage_GetAdjustColorsLookupTable(BYTE *LUT, double brightness, double contrast, double gamma, BOOL invert); +DLL_API BOOL DLL_CALLCONV FreeImage_AdjustColors(FIBITMAP *dib, double brightness, double contrast, double gamma, BOOL invert FI_DEFAULT(FALSE)); +DLL_API unsigned DLL_CALLCONV FreeImage_ApplyColorMapping(FIBITMAP *dib, RGBQUAD *srccolors, RGBQUAD *dstcolors, unsigned count, BOOL ignore_alpha, BOOL swap); +DLL_API unsigned DLL_CALLCONV FreeImage_SwapColors(FIBITMAP *dib, RGBQUAD *color_a, RGBQUAD *color_b, BOOL ignore_alpha); +DLL_API unsigned DLL_CALLCONV FreeImage_ApplyPaletteIndexMapping(FIBITMAP *dib, BYTE *srcindices, BYTE *dstindices, unsigned count, BOOL swap); +DLL_API unsigned DLL_CALLCONV FreeImage_SwapPaletteIndices(FIBITMAP *dib, BYTE *index_a, BYTE *index_b); + +// channel processing routines +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_GetChannel(FIBITMAP *dib, FREE_IMAGE_COLOR_CHANNEL channel); +DLL_API BOOL DLL_CALLCONV FreeImage_SetChannel(FIBITMAP *dib, FIBITMAP *dib8, FREE_IMAGE_COLOR_CHANNEL channel); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_GetComplexChannel(FIBITMAP *src, FREE_IMAGE_COLOR_CHANNEL channel); +DLL_API BOOL DLL_CALLCONV FreeImage_SetComplexChannel(FIBITMAP *dst, FIBITMAP *src, FREE_IMAGE_COLOR_CHANNEL channel); + +// copy / paste / composite routines +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_Copy(FIBITMAP *dib, int left, int top, int right, int bottom); +DLL_API BOOL DLL_CALLCONV FreeImage_Paste(FIBITMAP *dst, FIBITMAP *src, int left, int top, int alpha); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_Composite(FIBITMAP *fg, BOOL useFileBkg FI_DEFAULT(FALSE), RGBQUAD *appBkColor FI_DEFAULT(NULL), FIBITMAP *bg FI_DEFAULT(NULL)); +DLL_API BOOL DLL_CALLCONV FreeImage_JPEGCrop(const char *src_file, const char *dst_file, int left, int top, int right, int bottom); +DLL_API BOOL DLL_CALLCONV FreeImage_JPEGCropU(const wchar_t *src_file, const wchar_t *dst_file, int left, int top, int right, int bottom); +DLL_API BOOL DLL_CALLCONV FreeImage_PreMultiplyWithAlpha(FIBITMAP *dib); + +// background filling routines +DLL_API BOOL DLL_CALLCONV FreeImage_FillBackground(FIBITMAP *dib, const void *color, int options FI_DEFAULT(0)); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_EnlargeCanvas(FIBITMAP *src, int left, int top, int right, int bottom, const void *color, int options FI_DEFAULT(0)); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_AllocateEx(int width, int height, int bpp, const RGBQUAD *color, int options FI_DEFAULT(0), const RGBQUAD *palette FI_DEFAULT(NULL), unsigned red_mask FI_DEFAULT(0), unsigned green_mask FI_DEFAULT(0), unsigned blue_mask FI_DEFAULT(0)); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_AllocateExT(FREE_IMAGE_TYPE type, int width, int height, int bpp, const void *color, int options FI_DEFAULT(0), const RGBQUAD *palette FI_DEFAULT(NULL), unsigned red_mask FI_DEFAULT(0), unsigned green_mask FI_DEFAULT(0), unsigned blue_mask FI_DEFAULT(0)); + +// miscellaneous algorithms +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_MultigridPoissonSolver(FIBITMAP *Laplacian, int ncycle FI_DEFAULT(3)); + +// restore the borland-specific enum size option +#if defined(__BORLANDC__) +#pragma option pop +#endif + +#ifdef __cplusplus +} +#endif + +#endif // FREEIMAGE_H diff --git a/Lib/Include/Recast.h b/Lib/Include/Recast.h new file mode 100644 index 0000000..3cc04c0 --- /dev/null +++ b/Lib/Include/Recast.h @@ -0,0 +1,1141 @@ +// +// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. +// + +#ifndef RECAST_H +#define RECAST_H + +/// The value of PI used by Recast. +static const float RC_PI = 3.14159265f; + +//DLL Support -- ptbaggett@762studios.com +#if defined(_WIN32) + #if !defined(BUILDING_DLL) + #define DLLLINKAGE __declspec(dllimport) + #else + #define DLLLINKAGE __declspec(dllexport) + #endif +#else + #define DLLLINKAGE +#endif + +/// Recast log categories. +/// @see rcContext +enum rcLogCategory +{ + RC_LOG_PROGRESS = 1, ///< A progress log entry. + RC_LOG_WARNING, ///< A warning log entry. + RC_LOG_ERROR, ///< An error log entry. +}; + +/// Recast performance timer categories. +/// @see rcContext +enum rcTimerLabel +{ + /// The user defined total time of the build. + RC_TIMER_TOTAL, + /// A user defined build time. + RC_TIMER_TEMP, + /// The time to rasterize the triangles. (See: #rcRasterizeTriangle) + RC_TIMER_RASTERIZE_TRIANGLES, + /// The time to build the compact heightfield. (See: #rcBuildCompactHeightfield) + RC_TIMER_BUILD_COMPACTHEIGHTFIELD, + /// The total time to build the contours. (See: #rcBuildContours) + RC_TIMER_BUILD_CONTOURS, + /// The time to trace the boundaries of the contours. (See: #rcBuildContours) + RC_TIMER_BUILD_CONTOURS_TRACE, + /// The time to simplify the contours. (See: #rcBuildContours) + RC_TIMER_BUILD_CONTOURS_SIMPLIFY, + /// The time to filter ledge spans. (See: #rcFilterLedgeSpans) + RC_TIMER_FILTER_BORDER, + /// The time to filter low height spans. (See: #rcFilterWalkableLowHeightSpans) + RC_TIMER_FILTER_WALKABLE, + /// The time to apply the median filter. (See: #rcMedianFilterWalkableArea) + RC_TIMER_MEDIAN_AREA, + /// The time to filter low obstacles. (See: #rcFilterLowHangingWalkableObstacles) + RC_TIMER_FILTER_LOW_OBSTACLES, + /// The time to build the polygon mesh. (See: #rcBuildPolyMesh) + RC_TIMER_BUILD_POLYMESH, + /// The time to merge polygon meshes. (See: #rcMergePolyMeshes) + RC_TIMER_MERGE_POLYMESH, + /// The time to erode the walkable area. (See: #rcErodeWalkableArea) + RC_TIMER_ERODE_AREA, + /// The time to mark a box area. (See: #rcMarkBoxArea) + RC_TIMER_MARK_BOX_AREA, + /// The time to mark a cylinder area. (See: #rcMarkCylinderArea) + RC_TIMER_MARK_CYLINDER_AREA, + /// The time to mark a convex polygon area. (See: #rcMarkConvexPolyArea) + RC_TIMER_MARK_CONVEXPOLY_AREA, + /// The total time to build the distance field. (See: #rcBuildDistanceField) + RC_TIMER_BUILD_DISTANCEFIELD, + /// The time to build the distances of the distance field. (See: #rcBuildDistanceField) + RC_TIMER_BUILD_DISTANCEFIELD_DIST, + /// The time to blur the distance field. (See: #rcBuildDistanceField) + RC_TIMER_BUILD_DISTANCEFIELD_BLUR, + /// The total time to build the regions. (See: #rcBuildRegions, #rcBuildRegionsMonotone) + RC_TIMER_BUILD_REGIONS, + /// The total time to apply the watershed algorithm. (See: #rcBuildRegions) + RC_TIMER_BUILD_REGIONS_WATERSHED, + /// The time to expand regions while applying the watershed algorithm. (See: #rcBuildRegions) + RC_TIMER_BUILD_REGIONS_EXPAND, + /// The time to flood regions while applying the watershed algorithm. (See: #rcBuildRegions) + RC_TIMER_BUILD_REGIONS_FLOOD, + /// The time to filter out small regions. (See: #rcBuildRegions, #rcBuildRegionsMonotone) + RC_TIMER_BUILD_REGIONS_FILTER, + /// The time to build heightfield layers. (See: #rcBuildHeightfieldLayers) + RC_TIMER_BUILD_LAYERS, + /// The time to build the polygon mesh detail. (See: #rcBuildPolyMeshDetail) + RC_TIMER_BUILD_POLYMESHDETAIL, + /// The time to merge polygon mesh details. (See: #rcMergePolyMeshDetails) + RC_TIMER_MERGE_POLYMESHDETAIL, + /// The maximum number of timers. (Used for iterating timers.) + RC_MAX_TIMERS +}; + +/// Provides an interface for optional logging and performance tracking of the Recast +/// build process. +/// @ingroup recast +class rcContext +{ +public: + + /// Contructor. + /// @param[in] state TRUE if the logging and performance timers should be enabled. [Default: true] + inline rcContext(bool state = true) : m_logEnabled(state), m_timerEnabled(state) {} + virtual ~rcContext() {} + + /// Enables or disables logging. + /// @param[in] state TRUE if logging should be enabled. + inline void enableLog(bool state) { m_logEnabled = state; } + + /// Clears all log entries. + inline void resetLog() { if (m_logEnabled) doResetLog(); } + + /// Logs a message. + /// @param[in] category The category of the message. + /// @param[in] format The message. + void log(const rcLogCategory category, const char* format, ...); + + /// Enables or disables the performance timers. + /// @param[in] state TRUE if timers should be enabled. + inline void enableTimer(bool state) { m_timerEnabled = state; } + + /// Clears all peformance timers. (Resets all to unused.) + inline void resetTimers() { if (m_timerEnabled) doResetTimers(); } + + /// Starts the specified performance timer. + /// @param label The category of timer. + inline void startTimer(const rcTimerLabel label) { if (m_timerEnabled) doStartTimer(label); } + + /// Stops the specified performance timer. + /// @param label The category of the timer. + inline void stopTimer(const rcTimerLabel label) { if (m_timerEnabled) doStopTimer(label); } + + /// Returns the total accumulated time of the specified performance timer. + /// @param label The category of the timer. + /// @return The accumulated time of the timer, or -1 if timers are disabled or the timer has never been started. + inline int getAccumulatedTime(const rcTimerLabel label) const { return m_timerEnabled ? doGetAccumulatedTime(label) : -1; } + +protected: + + /// Clears all log entries. + virtual void doResetLog() {} + + /// Logs a message. + /// @param[in] category The category of the message. + /// @param[in] msg The formatted message. + /// @param[in] len The length of the formatted message. + virtual void doLog(const rcLogCategory /*category*/, const char* /*msg*/, const int /*len*/) {} + + /// Clears all timers. (Resets all to unused.) + virtual void doResetTimers() {} + + /// Starts the specified performance timer. + /// @param[in] label The category of timer. + virtual void doStartTimer(const rcTimerLabel /*label*/) {} + + /// Stops the specified performance timer. + /// @param[in] label The category of the timer. + virtual void doStopTimer(const rcTimerLabel /*label*/) {} + + /// Returns the total accumulated time of the specified performance timer. + /// @param[in] label The category of the timer. + /// @return The accumulated time of the timer, or -1 if timers are disabled or the timer has never been started. + virtual int doGetAccumulatedTime(const rcTimerLabel /*label*/) const { return -1; } + + /// True if logging is enabled. + bool m_logEnabled; + + /// True if the performance timers are enabled. + bool m_timerEnabled; +}; + +/// Specifies a configuration to use when performing Recast builds. +/// @ingroup recast +struct rcConfig +{ + /// The width of the field along the x-axis. [Limit: >= 0] [Units: vx] + int width; + + /// The height of the field along the z-axis. [Limit: >= 0] [Units: vx] + int height; + + /// The width/height size of tile's on the xz-plane. [Limit: >= 0] [Units: vx] + int tileSize; + + /// The size of the non-navigable border around the heightfield. [Limit: >=0] [Units: vx] + int borderSize; + + /// The xz-plane cell size to use for fields. [Limit: > 0] [Units: wu] + float cs; + + /// The y-axis cell size to use for fields. [Limit: > 0] [Units: wu] + float ch; + + /// The minimum bounds of the field's AABB. [(x, y, z)] [Units: wu] + float bmin[3]; + + /// The maximum bounds of the field's AABB. [(x, y, z)] [Units: wu] + float bmax[3]; + + /// The maximum slope that is considered walkable. [Limits: 0 <= value < 90] [Units: Degrees] + float walkableSlopeAngle; + + /// Minimum floor to 'ceiling' height that will still allow the floor area to + /// be considered walkable. [Limit: >= 3] [Units: vx] + int walkableHeight; + + /// Maximum ledge height that is considered to still be traversable. [Limit: >=0] [Units: vx] + int walkableClimb; + + /// The distance to erode/shrink the walkable area of the heightfield away from + /// obstructions. [Limit: >=0] [Units: vx] + int walkableRadius; + + /// The maximum allowed length for contour edges along the border of the mesh. [Limit: >=0] [Units: vx] + int maxEdgeLen; + + /// The maximum distance a simplfied contour's border edges should deviate + /// the original raw contour. [Limit: >=0] [Units: wu] + float maxSimplificationError; + + /// The minimum number of cells allowed to form isolated island areas. [Limit: >=0] [Units: vx] + int minRegionArea; + + /// Any regions with a span count smaller than this value will, if possible, + /// be merged with larger regions. [Limit: >=0] [Units: vx] + int mergeRegionArea; + + /// The maximum number of vertices allowed for polygons generated during the + /// contour to polygon conversion process. [Limit: >= 3] + int maxVertsPerPoly; + + /// Sets the sampling distance to use when generating the detail mesh. + /// (For height detail only.) [Limits: 0 or >= 0.9] [Units: wu] + float detailSampleDist; + + /// The maximum distance the detail mesh surface should deviate from heightfield + /// data. (For height detail only.) [Limit: >=0] [Units: wu] + float detailSampleMaxError; +}; + +/// Defines the number of bits allocated to rcSpan::smin and rcSpan::smax. +static const int RC_SPAN_HEIGHT_BITS = 13; +/// Defines the maximum value for rcSpan::smin and rcSpan::smax. +static const int RC_SPAN_MAX_HEIGHT = (1< inline void rcSwap(T& a, T& b) { T t = a; a = b; b = t; } + +/// Returns the minimum of two values. +/// @param[in] a Value A +/// @param[in] b Value B +/// @return The minimum of the two values. +template inline T rcMin(T a, T b) { return a < b ? a : b; } + +/// Returns the maximum of two values. +/// @param[in] a Value A +/// @param[in] b Value B +/// @return The maximum of the two values. +template inline T rcMax(T a, T b) { return a > b ? a : b; } + +/// Returns the absolute value. +/// @param[in] a The value. +/// @return The absolute value of the specified value. +template inline T rcAbs(T a) { return a < 0 ? -a : a; } + +/// Returns the square of the value. +/// @param[in] a The value. +/// @return The square of the value. +template inline T rcSqr(T a) { return a*a; } + +/// Clamps the value to the specified range. +/// @param[in] v The value to clamp. +/// @param[in] mn The minimum permitted return value. +/// @param[in] mx The maximum permitted return value. +/// @return The value, clamped to the specified range. +template inline T rcClamp(T v, T mn, T mx) { return v < mn ? mn : (v > mx ? mx : v); } + +/// Returns the square root of the value. +/// @param[in] x The value. +/// @return The square root of the vlaue. +DLLLINKAGE float rcSqrt(float x); + +/// @} +/// @name Vector helper functions. +/// @{ + +/// Derives the cross product of two vectors. (@p v1 x @p v2) +/// @param[out] dest The cross product. [(x, y, z)] +/// @param[in] v1 A Vector [(x, y, z)] +/// @param[in] v2 A vector [(x, y, z)] +inline void rcVcross(float* dest, const float* v1, const float* v2) +{ + dest[0] = v1[1]*v2[2] - v1[2]*v2[1]; + dest[1] = v1[2]*v2[0] - v1[0]*v2[2]; + dest[2] = v1[0]*v2[1] - v1[1]*v2[0]; +} + +/// Derives the dot product of two vectors. (@p v1 . @p v2) +/// @param[in] v1 A Vector [(x, y, z)] +/// @param[in] v2 A vector [(x, y, z)] +/// @return The dot product. +inline float rcVdot(const float* v1, const float* v2) +{ + return v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2]; +} + +/// Performs a scaled vector addition. (@p v1 + (@p v2 * @p s)) +/// @param[out] dest The result vector. [(x, y, z)] +/// @param[in] v1 The base vector. [(x, y, z)] +/// @param[in] v2 The vector to scale and add to @p v1. [(x, y, z)] +/// @param[in] s The amount to scale @p v2 by before adding to @p v1. +inline void rcVmad(float* dest, const float* v1, const float* v2, const float s) +{ + dest[0] = v1[0]+v2[0]*s; + dest[1] = v1[1]+v2[1]*s; + dest[2] = v1[2]+v2[2]*s; +} + +/// Performs a vector addition. (@p v1 + @p v2) +/// @param[out] dest The result vector. [(x, y, z)] +/// @param[in] v1 The base vector. [(x, y, z)] +/// @param[in] v2 The vector to add to @p v1. [(x, y, z)] +inline void rcVadd(float* dest, const float* v1, const float* v2) +{ + dest[0] = v1[0]+v2[0]; + dest[1] = v1[1]+v2[1]; + dest[2] = v1[2]+v2[2]; +} + +/// Performs a vector subtraction. (@p v1 - @p v2) +/// @param[out] dest The result vector. [(x, y, z)] +/// @param[in] v1 The base vector. [(x, y, z)] +/// @param[in] v2 The vector to subtract from @p v1. [(x, y, z)] +inline void rcVsub(float* dest, const float* v1, const float* v2) +{ + dest[0] = v1[0]-v2[0]; + dest[1] = v1[1]-v2[1]; + dest[2] = v1[2]-v2[2]; +} + +/// Selects the minimum value of each element from the specified vectors. +/// @param[in,out] mn A vector. (Will be updated with the result.) [(x, y, z)] +/// @param[in] v A vector. [(x, y, z)] +inline void rcVmin(float* mn, const float* v) +{ + mn[0] = rcMin(mn[0], v[0]); + mn[1] = rcMin(mn[1], v[1]); + mn[2] = rcMin(mn[2], v[2]); +} + +/// Selects the maximum value of each element from the specified vectors. +/// @param[in,out] mx A vector. (Will be updated with the result.) [(x, y, z)] +/// @param[in] v A vector. [(x, y, z)] +inline void rcVmax(float* mx, const float* v) +{ + mx[0] = rcMax(mx[0], v[0]); + mx[1] = rcMax(mx[1], v[1]); + mx[2] = rcMax(mx[2], v[2]); +} + +/// Performs a vector copy. +/// @param[out] dest The result. [(x, y, z)] +/// @param[in] v The vector to copy. [(x, y, z)] +inline void rcVcopy(float* dest, const float* v) +{ + dest[0] = v[0]; + dest[1] = v[1]; + dest[2] = v[2]; +} + +/// Returns the distance between two points. +/// @param[in] v1 A point. [(x, y, z)] +/// @param[in] v2 A point. [(x, y, z)] +/// @return The distance between the two points. +inline float rcVdist(const float* v1, const float* v2) +{ + float dx = v2[0] - v1[0]; + float dy = v2[1] - v1[1]; + float dz = v2[2] - v1[2]; + return rcSqrt(dx*dx + dy*dy + dz*dz); +} + +/// Returns the square of the distance between two points. +/// @param[in] v1 A point. [(x, y, z)] +/// @param[in] v2 A point. [(x, y, z)] +/// @return The square of the distance between the two points. +inline float rcVdistSqr(const float* v1, const float* v2) +{ + float dx = v2[0] - v1[0]; + float dy = v2[1] - v1[1]; + float dz = v2[2] - v1[2]; + return dx*dx + dy*dy + dz*dz; +} + +/// Normalizes the vector. +/// @param[in,out] v The vector to normalize. [(x, y, z)] +inline void rcVnormalize(float* v) +{ + float d = 1.0f / rcSqrt(rcSqr(v[0]) + rcSqr(v[1]) + rcSqr(v[2])); + v[0] *= d; + v[1] *= d; + v[2] *= d; +} + +/// @} +/// @name Heightfield Functions +/// @see rcHeightfield +/// @{ + +/// Calculates the bounding box of an array of vertices. +/// @ingroup recast +/// @param[in] verts An array of vertices. [(x, y, z) * @p nv] +/// @param[in] nv The number of vertices in the @p verts array. +/// @param[out] bmin The minimum bounds of the AABB. [(x, y, z)] [Units: wu] +/// @param[out] bmax The maximum bounds of the AABB. [(x, y, z)] [Units: wu] +DLLLINKAGE void rcCalcBounds(const float* verts, int nv, float* bmin, float* bmax); + +/// Calculates the grid size based on the bounding box and grid cell size. +/// @ingroup recast +/// @param[in] bmin The minimum bounds of the AABB. [(x, y, z)] [Units: wu] +/// @param[in] bmax The maximum bounds of the AABB. [(x, y, z)] [Units: wu] +/// @param[in] cs The xz-plane cell size. [Limit: > 0] [Units: wu] +/// @param[out] w The width along the x-axis. [Limit: >= 0] [Units: vx] +/// @param[out] h The height along the z-axis. [Limit: >= 0] [Units: vx] +DLLLINKAGE void rcCalcGridSize(const float* bmin, const float* bmax, float cs, int* w, int* h); + +/// Initializes a new heightfield. +/// @ingroup recast +/// @param[in,out] ctx The build context to use during the operation. +/// @param[in,out] hf The allocated heightfield to initialize. +/// @param[in] width The width of the field along the x-axis. [Limit: >= 0] [Units: vx] +/// @param[in] height The height of the field along the z-axis. [Limit: >= 0] [Units: vx] +/// @param[in] bmin The minimum bounds of the field's AABB. [(x, y, z)] [Units: wu] +/// @param[in] bmax The maximum bounds of the field's AABB. [(x, y, z)] [Units: wu] +/// @param[in] cs The xz-plane cell size to use for the field. [Limit: > 0] [Units: wu] +/// @param[in] ch The y-axis cell size to use for field. [Limit: > 0] [Units: wu] +DLLLINKAGE bool rcCreateHeightfield(rcContext* ctx, rcHeightfield& hf, int width, int height, + const float* bmin, const float* bmax, + float cs, float ch); + +/// Sets the area id of all triangles with a slope below the specified value +/// to #RC_WALKABLE_AREA. +/// @ingroup recast +/// @param[in,out] ctx The build context to use during the operation. +/// @param[in] walkableSlopeAngle The maximum slope that is considered walkable. +/// [Limits: 0 <= value < 90] [Units: Degrees] +/// @param[in] verts The vertices. [(x, y, z) * @p nv] +/// @param[in] nv The number of vertices. +/// @param[in] tris The triangle vertex indices. [(vertA, vertB, vertC) * @p nt] +/// @param[in] nt The number of triangles. +/// @param[out] areas The triangle area ids. [Length: >= @p nt] +DLLLINKAGE void rcMarkWalkableTriangles(rcContext* ctx, const float walkableSlopeAngle, const float* verts, int nv, + const int* tris, int nt, unsigned char* areas); + +/// Sets the area id of all triangles with a slope greater than or equal to the specified value to #RC_NULL_AREA. +/// @ingroup recast +/// @param[in,out] ctx The build context to use during the operation. +/// @param[in] walkableSlopeAngle The maximum slope that is considered walkable. +/// [Limits: 0 <= value < 90] [Units: Degrees] +/// @param[in] verts The vertices. [(x, y, z) * @p nv] +/// @param[in] nv The number of vertices. +/// @param[in] tris The triangle vertex indices. [(vertA, vertB, vertC) * @p nt] +/// @param[in] nt The number of triangles. +/// @param[out] areas The triangle area ids. [Length: >= @p nt] +DLLLINKAGE void rcClearUnwalkableTriangles(rcContext* ctx, const float walkableSlopeAngle, const float* verts, int nv, + const int* tris, int nt, unsigned char* areas); + +/// Adds a span to the specified heightfield. +/// @ingroup recast +/// @param[in,out] ctx The build context to use during the operation. +/// @param[in,out] hf An initialized heightfield. +/// @param[in] x The width index where the span is to be added. +/// [Limits: 0 <= value < rcHeightfield::width] +/// @param[in] y The height index where the span is to be added. +/// [Limits: 0 <= value < rcHeightfield::height] +/// @param[in] smin The minimum height of the span. [Limit: < @p smax] [Units: vx] +/// @param[in] smax The maximum height of the span. [Limit: <= #RC_SPAN_MAX_HEIGHT] [Units: vx] +/// @param[in] area The area id of the span. [Limit: <= #RC_WALKABLE_AREA) +/// @param[in] flagMergeThr The merge theshold. [Limit: >= 0] [Units: vx] +DLLLINKAGE void rcAddSpan(rcContext* ctx, rcHeightfield& hf, const int x, const int y, + const unsigned short smin, const unsigned short smax, + const unsigned char area, const int flagMergeThr); + +/// Rasterizes a triangle into the specified heightfield. +/// @ingroup recast +/// @param[in,out] ctx The build context to use during the operation. +/// @param[in] v0 Triangle vertex 0 [(x, y, z)] +/// @param[in] v1 Triangle vertex 1 [(x, y, z)] +/// @param[in] v2 Triangle vertex 2 [(x, y, z)] +/// @param[in] area The area id of the triangle. [Limit: <= #RC_WALKABLE_AREA] +/// @param[in,out] solid An initialized heightfield. +/// @param[in] flagMergeThr The distance where the walkable flag is favored over the non-walkable flag. +/// [Limit: >= 0] [Units: vx] +DLLLINKAGE void rcRasterizeTriangle(rcContext* ctx, const float* v0, const float* v1, const float* v2, + const unsigned char area, rcHeightfield& solid, + const int flagMergeThr = 1); + +/// Rasterizes an indexed triangle mesh into the specified heightfield. +/// @ingroup recast +/// @param[in,out] ctx The build context to use during the operation. +/// @param[in] verts The vertices. [(x, y, z) * @p nv] +/// @param[in] nv The number of vertices. +/// @param[in] tris The triangle indices. [(vertA, vertB, vertC) * @p nt] +/// @param[in] areas The area id's of the triangles. [Limit: <= #RC_WALKABLE_AREA] [Size: @p nt] +/// @param[in] nt The number of triangles. +/// @param[in,out] solid An initialized heightfield. +/// @param[in] flagMergeThr The distance where the walkable flag is favored over the non-walkable flag. +/// [Limit: >= 0] [Units: vx] +DLLLINKAGE void rcRasterizeTriangles(rcContext* ctx, const float* verts, const int nv, + const int* tris, const unsigned char* areas, const int nt, + rcHeightfield& solid, const int flagMergeThr = 1); + +/// Rasterizes an indexed triangle mesh into the specified heightfield. +/// @ingroup recast +/// @param[in,out] ctx The build context to use during the operation. +/// @param[in] verts The vertices. [(x, y, z) * @p nv] +/// @param[in] nv The number of vertices. +/// @param[in] tris The triangle indices. [(vertA, vertB, vertC) * @p nt] +/// @param[in] areas The area id's of the triangles. [Limit: <= #RC_WALKABLE_AREA] [Size: @p nt] +/// @param[in] nt The number of triangles. +/// @param[in,out] solid An initialized heightfield. +/// @param[in] flagMergeThr The distance where the walkable flag is favored over the non-walkable flag. +/// [Limit: >= 0] [Units: vx] +DLLLINKAGE void rcRasterizeTriangles(rcContext* ctx, const float* verts, const int nv, + const unsigned short* tris, const unsigned char* areas, const int nt, + rcHeightfield& solid, const int flagMergeThr = 1); + +/// Rasterizes triangles into the specified heightfield. +/// @ingroup recast +/// @param[in,out] ctx The build context to use during the operation. +/// @param[in] verts The triangle vertices. [(ax, ay, az, bx, by, bz, cx, by, cx) * @p nt] +/// @param[in] areas The area id's of the triangles. [Limit: <= #RC_WALKABLE_AREA] [Size: @p nt] +/// @param[in] nt The number of triangles. +/// @param[in,out] solid An initialized heightfield. +/// @param[in] flagMergeThr The distance where the walkable flag is favored over the non-walkable flag. +/// [Limit: >= 0] [Units: vx] +DLLLINKAGE void rcRasterizeTriangles(rcContext* ctx, const float* verts, const unsigned char* areas, const int nt, + rcHeightfield& solid, const int flagMergeThr = 1); + +/// Marks non-walkable spans as walkable if their maximum is within @p walkableClimp of a walkable neihbor. +/// @ingroup recast +/// @param[in,out] ctx The build context to use during the operation. +/// @param[in] walkableClimb Maximum ledge height that is considered to still be traversable. +/// [Limit: >=0] [Units: vx] +/// @param[in,out] solid A fully built heightfield. (All spans have been added.) +DLLLINKAGE void rcFilterLowHangingWalkableObstacles(rcContext* ctx, const int walkableClimb, rcHeightfield& solid); + +/// Marks spans that are ledges as not-walkable. +/// @ingroup recast +/// @param[in,out] ctx The build context to use during the operation. +/// @param[in] walkableHeight Minimum floor to 'ceiling' height that will still allow the floor area to +/// be considered walkable. [Limit: >= 3] [Units: vx] +/// @param[in] walkableClimb Maximum ledge height that is considered to still be traversable. +/// [Limit: >=0] [Units: vx] +/// @param[in,out] solid A fully built heightfield. (All spans have been added.) +DLLLINKAGE void rcFilterLedgeSpans(rcContext* ctx, const int walkableHeight, + const int walkableClimb, rcHeightfield& solid); + +/// Marks walkable spans as not walkable if the clearence above the span is less than the specified height. +/// @ingroup recast +/// @param[in,out] ctx The build context to use during the operation. +/// @param[in] walkableHeight Minimum floor to 'ceiling' height that will still allow the floor area to +/// be considered walkable. [Limit: >= 3] [Units: vx] +/// @param[in,out] solid A fully built heightfield. (All spans have been added.) +DLLLINKAGE void rcFilterWalkableLowHeightSpans(rcContext* ctx, int walkableHeight, rcHeightfield& solid); + +/// Returns the number of spans contained in the specified heightfield. +/// @ingroup recast +/// @param[in,out] ctx The build context to use during the operation. +/// @param[in] hf An initialized heightfield. +/// @returns The number of spans in the heightfield. +DLLLINKAGE int rcGetHeightFieldSpanCount(rcContext* ctx, rcHeightfield& hf); + +/// @} +/// @name Compact Heightfield Functions +/// @see rcCompactHeightfield +/// @{ + +/// Builds a compact heightfield representing open space, from a heightfield representing solid space. +/// @ingroup recast +/// @param[in,out] ctx The build context to use during the operation. +/// @param[in] walkableHeight Minimum floor to 'ceiling' height that will still allow the floor area +/// to be considered walkable. [Limit: >= 3] [Units: vx] +/// @param[in] walkableClimb Maximum ledge height that is considered to still be traversable. +/// [Limit: >=0] [Units: vx] +/// @param[in] hf The heightfield to be compacted. +/// @param[out] chf The resulting compact heightfield. (Must be pre-allocated.) +/// @returns True if the operation completed successfully. +DLLLINKAGE bool rcBuildCompactHeightfield(rcContext* ctx, const int walkableHeight, const int walkableClimb, + rcHeightfield& hf, rcCompactHeightfield& chf); + +/// Erodes the walkable area within the heightfield by the specified radius. +/// @ingroup recast +/// @param[in,out] ctx The build context to use during the operation. +/// @param[in] radius The radius of erosion. [Limits: 0 < value < 255] [Units: vx] +/// @param[in,out] chf The populated compact heightfield to erode. +/// @returns True if the operation completed successfully. +DLLLINKAGE bool rcErodeWalkableArea(rcContext* ctx, int radius, rcCompactHeightfield& chf); + +/// Applies a median filter to walkable area types (based on area id), removing noise. +/// @ingroup recast +/// @param[in,out] ctx The build context to use during the operation. +/// @param[in,out] chf A populated compact heightfield. +/// @returns True if the operation completed successfully. +DLLLINKAGE bool rcMedianFilterWalkableArea(rcContext* ctx, rcCompactHeightfield& chf); + +/// Applies an area id to all spans within the specified bounding box. (AABB) +/// @ingroup recast +/// @param[in,out] ctx The build context to use during the operation. +/// @param[in] bmin The minimum of the bounding box. [(x, y, z)] +/// @param[in] bmax The maximum of the bounding box. [(x, y, z)] +/// @param[in] areaId The area id to apply. [Limit: <= #RC_WALKABLE_AREA] +/// @param[in,out] chf A populated compact heightfield. +DLLLINKAGE void rcMarkBoxArea(rcContext* ctx, const float* bmin, const float* bmax, unsigned char areaId, + rcCompactHeightfield& chf); + +/// Applies the area id to the all spans within the specified convex polygon. +/// @ingroup recast +/// @param[in,out] ctx The build context to use during the operation. +/// @param[in] verts The vertices of the polygon [Fomr: (x, y, z) * @p nverts] +/// @param[in] nverts The number of vertices in the polygon. +/// @param[in] hmin The height of the base of the polygon. +/// @param[in] hmax The height of the top of the polygon. +/// @param[in] areaId The area id to apply. [Limit: <= #RC_WALKABLE_AREA] +/// @param[in,out] chf A populated compact heightfield. +DLLLINKAGE void rcMarkConvexPolyArea(rcContext* ctx, const float* verts, const int nverts, + const float hmin, const float hmax, unsigned char areaId, + rcCompactHeightfield& chf); + +/// Helper function to offset voncex polygons for rcMarkConvexPolyArea. +/// @ingroup recast +/// @param[in] verts The vertices of the polygon [Form: (x, y, z) * @p nverts] +/// @param[in] nverts The number of vertices in the polygon. +/// @param[out] outVerts The offset vertices (should hold up to 2 * @p nverts) [Form: (x, y, z) * return value] +/// @param[in] maxOutVerts The max number of vertices that can be stored to @p outVerts. +/// @returns Number of vertices in the offset polygon or 0 if too few vertices in @p outVerts. +DLLLINKAGE int rcOffsetPoly(const float* verts, const int nverts, const float offset, + float* outVerts, const int maxOutVerts); + +/// Applies the area id to all spans within the specified cylinder. +/// @ingroup recast +/// @param[in,out] ctx The build context to use during the operation. +/// @param[in] pos The center of the base of the cylinder. [Form: (x, y, z)] +/// @param[in] r The radius of the cylinder. +/// @param[in] h The height of the cylinder. +/// @param[in] areaId The area id to apply. [Limit: <= #RC_WALKABLE_AREA] +/// @param[in,out] chf A populated compact heightfield. +DLLLINKAGE void rcMarkCylinderArea(rcContext* ctx, const float* pos, + const float r, const float h, unsigned char areaId, + rcCompactHeightfield& chf); + +/// Builds the distance field for the specified compact heightfield. +/// @ingroup recast +/// @param[in,out] ctx The build context to use during the operation. +/// @param[in,out] chf A populated compact heightfield. +/// @returns True if the operation completed successfully. +DLLLINKAGE bool rcBuildDistanceField(rcContext* ctx, rcCompactHeightfield& chf); + +/// Builds region data for the heightfield using watershed partitioning. +/// @ingroup recast +/// @param[in,out] ctx The build context to use during the operation. +/// @param[in,out] chf A populated compact heightfield. +/// @param[in] borderSize The size of the non-navigable border around the heightfield. +/// [Limit: >=0] [Units: vx] +/// @param[in] minRegionArea The minimum number of cells allowed to form isolated island areas. +/// [Limit: >=0] [Units: vx]. +/// @param[in] mergeRegionArea Any regions with a span count smaller than this value will, if possible, +/// be merged with larger regions. [Limit: >=0] [Units: vx] +/// @returns True if the operation completed successfully. +DLLLINKAGE bool rcBuildRegions(rcContext* ctx, rcCompactHeightfield& chf, + const int borderSize, const int minRegionArea, const int mergeRegionArea); + +/// Builds region data for the heightfield using simple monotone partitioning. +/// @ingroup recast +/// @param[in,out] ctx The build context to use during the operation. +/// @param[in,out] chf A populated compact heightfield. +/// @param[in] borderSize The size of the non-navigable border around the heightfield. +/// [Limit: >=0] [Units: vx] +/// @param[in] minRegionArea The minimum number of cells allowed to form isolated island areas. +/// [Limit: >=0] [Units: vx]. +/// @param[in] mergeRegionArea Any regions with a span count smaller than this value will, if possible, +/// be merged with larger regions. [Limit: >=0] [Units: vx] +/// @returns True if the operation completed successfully. +DLLLINKAGE bool rcBuildRegionsMonotone(rcContext* ctx, rcCompactHeightfield& chf, + const int borderSize, const int minRegionArea, const int mergeRegionArea); + + +/// Sets the neighbor connection data for the specified direction. +/// @param[in] s The span to update. +/// @param[in] dir The direction to set. [Limits: 0 <= value < 4] +/// @param[in] i The index of the neighbor span. +inline void rcSetCon(rcCompactSpan& s, int dir, int i) +{ + const unsigned int shift = (unsigned int)dir*6; + unsigned int con = s.con; + s.con = (con & ~(0x3f << shift)) | (((unsigned int)i & 0x3f) << shift); +} + +/// Gets neighbor connection data for the specified direction. +/// @param[in] s The span to check. +/// @param[in] dir The direction to check. [Limits: 0 <= value < 4] +/// @return The neighbor connection data for the specified direction, +/// or #RC_NOT_CONNECTED if there is no connection. +inline int rcGetCon(const rcCompactSpan& s, int dir) +{ + const unsigned int shift = (unsigned int)dir*6; + return (s.con >> shift) & 0x3f; +} + +/// Gets the standard width (x-axis) offset for the specified direction. +/// @param[in] dir The direction. [Limits: 0 <= value < 4] +/// @return The width offset to apply to the current cell position to move +/// in the direction. +inline int rcGetDirOffsetX(int dir) +{ + const int offset[4] = { -1, 0, 1, 0, }; + return offset[dir&0x03]; +} + +/// Gets the standard height (z-axis) offset for the specified direction. +/// @param[in] dir The direction. [Limits: 0 <= value < 4] +/// @return The height offset to apply to the current cell position to move +/// in the direction. +inline int rcGetDirOffsetY(int dir) +{ + const int offset[4] = { 0, 1, 0, -1 }; + return offset[dir&0x03]; +} + +/// @} +/// @name Layer, Contour, Polymesh, and Detail Mesh Functions +/// @see rcHeightfieldLayer, rcContourSet, rcPolyMesh, rcPolyMeshDetail +/// @{ + +/// Builds a layer set from the specified compact heightfield. +/// @ingroup recast +/// @param[in,out] ctx The build context to use during the operation. +/// @param[in] chf A fully built compact heightfield. +/// @param[in] borderSize The size of the non-navigable border around the heightfield. [Limit: >=0] +/// [Units: vx] +/// @param[in] walkableHeight Minimum floor to 'ceiling' height that will still allow the floor area +/// to be considered walkable. [Limit: >= 3] [Units: vx] +/// @param[out] lset The resulting layer set. (Must be pre-allocated.) +/// @returns True if the operation completed successfully. +DLLLINKAGE bool rcBuildHeightfieldLayers(rcContext* ctx, rcCompactHeightfield& chf, + const int borderSize, const int walkableHeight, + rcHeightfieldLayerSet& lset); + +/// Builds a contour set from the region outlines in the provided compact heightfield. +/// @ingroup recast +/// @param[in,out] ctx The build context to use during the operation. +/// @param[in] chf A fully built compact heightfield. +/// @param[in] maxError The maximum distance a simplfied contour's border edges should deviate +/// the original raw contour. [Limit: >=0] [Units: wu] +/// @param[in] maxEdgeLen The maximum allowed length for contour edges along the border of the mesh. +/// [Limit: >=0] [Units: vx] +/// @param[out] cset The resulting contour set. (Must be pre-allocated.) +/// @param[in] buildFlags The build flags. (See: #rcBuildContoursFlags) +/// @returns True if the operation completed successfully. +DLLLINKAGE bool rcBuildContours(rcContext* ctx, rcCompactHeightfield& chf, + const float maxError, const int maxEdgeLen, + rcContourSet& cset, const int flags = RC_CONTOUR_TESS_WALL_EDGES); + +/// Builds a polygon mesh from the provided contours. +/// @ingroup recast +/// @param[in,out] ctx The build context to use during the operation. +/// @param[in] cset A fully built contour set. +/// @param[in] nvp The maximum number of vertices allowed for polygons generated during the +/// contour to polygon conversion process. [Limit: >= 3] +/// @param[out] mesh The resulting polygon mesh. (Must be re-allocated.) +/// @returns True if the operation completed successfully. +DLLLINKAGE bool rcBuildPolyMesh(rcContext* ctx, rcContourSet& cset, const int nvp, rcPolyMesh& mesh); + +/// Merges multiple polygon meshes into a single mesh. +/// @ingroup recast +/// @param[in,out] ctx The build context to use during the operation. +/// @param[in] meshes An array of polygon meshes to merge. [Size: @p nmeshes] +/// @param[in] nmeshes The number of polygon meshes in the meshes array. +/// @param[in] mesh The resulting polygon mesh. (Must be pre-allocated.) +/// @returns True if the operation completed successfully. +DLLLINKAGE bool rcMergePolyMeshes(rcContext* ctx, rcPolyMesh** meshes, const int nmeshes, rcPolyMesh& mesh); + +/// Builds a detail mesh from the provided polygon mesh. +/// @ingroup recast +/// @param[in,out] ctx The build context to use during the operation. +/// @param[in] mesh A fully built polygon mesh. +/// @param[in] chf The compact heightfield used to build the polygon mesh. +/// @param[in] sampleDist Sets the distance to use when samping the heightfield. [Limit: >=0] [Units: wu] +/// @param[in] sampleMaxError The maximum distance the detail mesh surface should deviate from +/// heightfield data. [Limit: >=0] [Units: wu] +/// @param[out] dmesh The resulting detail mesh. (Must be pre-allocated.) +/// @returns True if the operation completed successfully. +DLLLINKAGE bool rcBuildPolyMeshDetail(rcContext* ctx, const rcPolyMesh& mesh, const rcCompactHeightfield& chf, + const float sampleDist, const float sampleMaxError, + rcPolyMeshDetail& dmesh); + +/// Copies the poly mesh data from src to dst. +/// @ingroup recast +/// @param[in,out] ctx The build context to use during the operation. +/// @param[in] src The source mesh to copy from. +/// @param[out] dst The resulting detail mesh. (Must be pre-allocated, must be empty mesh.) +/// @returns True if the operation completed successfully. +DLLLINKAGE bool rcCopyPolyMesh(rcContext* ctx, const rcPolyMesh& src, rcPolyMesh& dst); + +/// Merges multiple detail meshes into a single detail mesh. +/// @ingroup recast +/// @param[in,out] ctx The build context to use during the operation. +/// @param[in] meshes An array of detail meshes to merge. [Size: @p nmeshes] +/// @param[in] nmeshes The number of detail meshes in the meshes array. +/// @param[out] mesh The resulting detail mesh. (Must be pre-allocated.) +/// @returns True if the operation completed successfully. +DLLLINKAGE bool rcMergePolyMeshDetails(rcContext* ctx, rcPolyMeshDetail** meshes, const int nmeshes, rcPolyMeshDetail& mesh); + +/// @} + +#endif // RECAST_H + +/////////////////////////////////////////////////////////////////////////// + +// Due to the large amount of detail documentation for this file, +// the content normally located at the end of the header file has been separated +// out to a file in /Docs/Extern. diff --git a/Lib/Include/RecastAlloc.h b/Lib/Include/RecastAlloc.h new file mode 100644 index 0000000..f9fe7a2 --- /dev/null +++ b/Lib/Include/RecastAlloc.h @@ -0,0 +1,136 @@ +// +// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. +// + +#ifndef RECASTALLOC_H +#define RECASTALLOC_H + +//DLL Support -- ptbaggett@762studios.com +#if defined(_WIN32) + #if !defined(BUILDING_DLL) + #define DLLLINKAGE __declspec(dllimport) + #else + #define DLLLINKAGE __declspec(dllexport) + #endif +#else + #define DLLLINKAGE +#endif + + +/// Provides hint values to the memory allocator on how long the +/// memory is expected to be used. +enum rcAllocHint +{ + RC_ALLOC_PERM, ///< Memory will persist after a function call. + RC_ALLOC_TEMP ///< Memory used temporarily within a function. +}; + +/// A memory allocation function. +// @param[in] size The size, in bytes of memory, to allocate. +// @param[in] rcAllocHint A hint to the allocator on how long the memory is expected to be in use. +// @return A pointer to the beginning of the allocated memory block, or null if the allocation failed. +/// @see rcAllocSetCustom +typedef void* (rcAllocFunc)(int size, rcAllocHint hint); + +/// A memory deallocation function. +/// @param[in] ptr A pointer to a memory block previously allocated using #rcAllocFunc. +/// @see rcAllocSetCustom +typedef void (rcFreeFunc)(void* ptr); + +/// Sets the base custom allocation functions to be used by Recast. +/// @param[in] allocFunc The memory allocation function to be used by #rcAlloc +/// @param[in] freeFunc The memory de-allocation function to be used by #rcFree +DLLLINKAGE void rcAllocSetCustom(rcAllocFunc *allocFunc, rcFreeFunc *freeFunc); + +/// Allocates a memory block. +/// @param[in] size The size, in bytes of memory, to allocate. +/// @param[in] hint A hint to the allocator on how long the memory is expected to be in use. +/// @return A pointer to the beginning of the allocated memory block, or null if the allocation failed. +/// @see rcFree +DLLLINKAGE void* rcAlloc(int size, rcAllocHint hint); + +/// Deallocates a memory block. +/// @param[in] ptr A pointer to a memory block previously allocated using #rcAlloc. +/// @see rcAlloc +DLLLINKAGE void rcFree(void* ptr); + + +/// A simple dynamic array of integers. +class rcIntArray +{ + int* m_data; + int m_size, m_cap; + inline rcIntArray(const rcIntArray&); + inline rcIntArray& operator=(const rcIntArray&); +public: + + /// Constructs an instance with an initial array size of zero. + inline rcIntArray() : m_data(0), m_size(0), m_cap(0) {} + + /// Constructs an instance initialized to the specified size. + /// @param[in] n The initial size of the integer array. + inline rcIntArray(int n) : m_data(0), m_size(0), m_cap(0) { resize(n); } + inline ~rcIntArray() { rcFree(m_data); } + + /// Specifies the new size of the integer array. + /// @param[in] n The new size of the integer array. + void resize(int n); + + /// Push the specified integer onto the end of the array and increases the size by one. + /// @param[in] item The new value. + inline void push(int item) { resize(m_size+1); m_data[m_size-1] = item; } + + /// Returns the value at the end of the array and reduces the size by one. + /// @return The value at the end of the array. + inline int pop() { if (m_size > 0) m_size--; return m_data[m_size]; } + + /// The value at the specified array index. + /// @warning Does not provide overflow protection. + /// @param[in] i The index of the value. + inline const int& operator[](int i) const { return m_data[i]; } + + /// The value at the specified array index. + /// @warning Does not provide overflow protection. + /// @param[in] i The index of the value. + inline int& operator[](int i) { return m_data[i]; } + + /// The current size of the integer array. + inline int size() const { return m_size; } +}; + +/// A simple helper class used to delete an array when it goes out of scope. +/// @note This class is rarely if ever used by the end user. +template class rcScopedDelete +{ + T* ptr; + inline T* operator=(T* p); +public: + + /// Constructs an instance with a null pointer. + inline rcScopedDelete() : ptr(0) {} + + /// Constructs an instance with the specified pointer. + /// @param[in] p An pointer to an allocated array. + inline rcScopedDelete(T* p) : ptr(p) {} + inline ~rcScopedDelete() { rcFree(ptr); } + + /// The root array pointer. + /// @return The root array pointer. + inline operator T*() { return ptr; } +}; + +#endif diff --git a/Lib/Include/RecastAssert.h b/Lib/Include/RecastAssert.h new file mode 100644 index 0000000..2aca0d9 --- /dev/null +++ b/Lib/Include/RecastAssert.h @@ -0,0 +1,33 @@ +// +// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. +// + +#ifndef RECASTASSERT_H +#define RECASTASSERT_H + +// Note: This header file's only purpose is to include define assert. +// Feel free to change the file and include your own implementation instead. + +#ifdef NDEBUG +// From http://cnicholson.net/2009/02/stupid-c-tricks-adventures-in-assert/ +# define rcAssert(x) do { (void)sizeof(x); } while((void)(__LINE__==-1),false) +#else +# include +# define rcAssert assert +#endif + +#endif // RECASTASSERT_H diff --git a/Lib/Include/ZSTL/ZArray.hpp b/Lib/Include/ZSTL/ZArray.hpp new file mode 100644 index 0000000..c3b2345 --- /dev/null +++ b/Lib/Include/ZSTL/ZArray.hpp @@ -0,0 +1,1768 @@ +/* + ZArray.hpp + Author: James Russell + Chris Ertel + Created: 9/12/2010 + + Purpose: + + Templated dynamic array implementation. + + Because ZArray is a dynamic array implementation (not a dynamic vector implementation), it + makes no guarantees about the constructor / destructor behavior of individual elements. This is + to say that as elements enter and leave scope, the underlying array may not be modified and + constructs and destructors may not be called. For example, if space is reserved for 20 elements, + then 20 elements are constructed in an array of size 20. The array will not be deleted until + Reserve(0) is called on an array of size 0, which even then only guarantees that the allocator + is called and the array provided for a 'Deallocate' function call. Whether or not this deletes + the array is up to the allocator. + + Note that the default allocator stores space for a certain number of elements and does not + destruct these until the allocator itself leaves scope. + + Note: + + A visualizer for Visual Studio 2008 for this container is available in vs_visualizers.txt. + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ + +#pragma once + +#ifndef _ZARRAY_HPP +#define _ZARRAY_HPP + +#include +#include + +//Default capacity for ZArray when no capacity is defined (recommended that this be +//less than or equal to local storage count, user can define their own) +#ifndef ZARRAY_DEFAULT_CAPACITY +#define ZARRAY_DEFAULT_CAPACITY (10) +#endif + +//Resize factor for ZArray when operations are performed that require an increase in capacity +//and capacity is not specified (user can define their own, should be greater than 1.0) +#ifndef ZARRAY_CAPACITY_RESIZE_FACTOR +#define ZARRAY_CAPACITY_RESIZE_FACTOR (2.0) +#endif + +//Local storage number of elements (user can define their own) +#ifndef ZARRAY_DEFAULT_ALLOCATOR_STORAGE +#define ZARRAY_DEFAULT_ALLOCATOR_STORAGE (10) +#endif + +//Forward Declaration of ZArray +template +class ZArray; + +//Forward Declaration of ZArrayIterator +template +class ZArrayIterator; + +/* +Forward Declaration of ZArray Method Implementation Structures + +Existence of these structures allows for template specialization of +individual methods of the ZArray class. In order to specialize +a single method of ZArray, simply specialize the corresponding +method implementation structure. +*/ + +//Forward Declaration of ZArray::At struct +template +struct ZArray_AtImpl { + inline static T& Call(const ZArray& _self, size_t _index); +}; + +//Forward Declaration of ZArray::Back struct +template +struct ZArray_BackImpl { + inline static T& Call(const ZArray& _self); +}; + +//Forward Declaration of ZArray::Capacity struct +template +struct ZArray_CapacityImpl { + inline static size_t Call(const ZArray& _self); +}; + +//Forward Declaration of ZArray::Clear struct +template +struct ZArray_ClearImpl { + inline static void Call(ZArray& _self); + inline static void Call(ZArray& _self, size_t _newCapacity); +}; + +//Forward Declaration of ZArray::Copy struct +template +struct ZArray_CopyImpl { + template inline static void Call(ZArray& _self, const ZArray& _other); +}; + +//Forward Declaration of ZArray::Data struct +template +struct ZArray_DataImpl { + inline static T* Call(const ZArray& _self); +}; + +//Forward Declaration of ZArray::Empty struct +template +struct ZArray_EmptyImpl { + inline static bool Call(const ZArray& _self); +}; + +//Forward Declaration of ZArray::Equals struct +template +struct ZArray_EqualsImpl { + template inline static bool Call(const ZArray& _self, const ZArray& _other); +}; + +//Forward Declaration of ZArray::Erase struct +template +struct ZArray_EraseImpl { + inline static T Call(ZArray& _self, size_t _index); + inline static void Call(ZArray& _self, size_t _start, size_t _end); +}; + +//Forward Declaration of ZArray::Front struct +template +struct ZArray_FrontImpl { + inline static T& Call(const ZArray& _self); +}; + +//Forward Declaration of ZArray::Find struct +template +struct ZArray_FindImpl { + inline static size_t Call(const ZArray& _self, const T& elem); +}; + +//Forward Declaration of ZArray::Insert struct +template +struct ZArray_InsertImpl { + inline static void Call(ZArray& _self, size_t _index, const T& _value, size_t _count); + template inline static void Call(ZArray& _self, size_t _index, const ZArray& _other, size_t _start, size_t _count); +}; + +//Forward Declaration of ZArray::PopBack struct +template +struct ZArray_PopBackImpl { + inline static T Call(ZArray& _self); +}; + +//Forward Declaration of ZArray::PopFront struct +template +struct ZArray_PopFrontImpl { + inline static T Call(ZArray& _self); +}; + +//Forward Declaration of ZArray::PushBack struct +template +struct ZArray_PushBackImpl { + inline static void Call(ZArray& _self, const T& _value); +}; + +//Forward Declaration of ZArray::PushFront struct +template +struct ZArray_PushFrontImpl { + inline static void Call(ZArray& _self, const T& _value); +}; + +//Forward Declaration of ZArray::Reserve struct +template +struct ZArray_ReserveImpl { + inline static void Call(ZArray& _self, size_t _capacity, bool _reallocate); +}; + +//Forward Declaration of ZArray::Resize struct +template +struct ZArray_ResizeImpl { + inline static void Call(ZArray& _self, size_t _size); + inline static void Call(ZArray& _self, size_t _size, const T& _value); + inline static void Call(ZArray& _self, size_t _size, size_t _capacity, const T& _value); +}; + +//Forward Declaration of ZArray::Size struct +template +struct ZArray_SizeImpl { + inline static size_t Call(const ZArray& _self); +}; + +//Forward Declaration of ZArray::Swap struct +template +struct ZArray_SwapImpl { + template inline static void Call(ZArray& _self, ZArray& _other); +}; + +////////////////////// +/* ZArray Allocator */ +////////////////////// + +/* +ZArray Allocator class. Used to allocate arrays of a templated type +when requested by a ZArray instance. + +NOTE: This allocator keeps a set amount (N) of locally stored objects of type T. These +objects are allocated when the array is created and deallocated when the array is +destructed, and there is no way (other than specializing based on type) to cause these +local elements to destruct other than destructing the array. Reserve(0) will call +'Deallocate', but that will not destruct the elements. So, in summary, do not use the +default allocator when you have a strict requirement that Reserve(0) should deallocate +the array and call contained destructors. + +The template parameter T is the type contained the array this allocator is for. + +The template parameter N is the amount of local storage this allocator will keep +on hand. Allocations of size less than N (in number of elements) will use the locally +allocated array. + +*/ +template +class ZArrayAllocator +{ +public: + + /* + public ZArrayAllocator::Allocate + + Allocation method. + + @param _size - size of the array to allocate + @return - pointer to an array which can store at least _size values + */ + T* Allocate(size_t _size) + { + if (_size == 0) + return NULL; + + if (_size > N) + { + return ZSTL_NEW_ARRAY(T, _size); + } + else + { + return Local; + } + } + + /* + public ZArrayAllocator::Deallocate + + Deallocation method. + + @param _ptr - pointer to previously allocated memory by this allocator + @param _size - size of the memory + */ + void Deallocate(T* _ptr, size_t _size) + { + if (_ptr == NULL) + return; + + if (_ptr != &(Local[0])) + { + ZSTL_DEL_ARRAY(_ptr, _size); + } + } + +protected: + + //The local storage for the allocator + T Local[N]; +}; + +/* +Specialization of ZArrayAllocator for a 0 size local storage. Will +always allocate using ZSTL_NEW_ARRAY. +*/ +template +class ZArrayAllocator +{ +public: + //Allocates the array using ZSTL_NEW_ARRAY + T* Allocate(size_t _size) + { + return ZSTL_NEW_ARRAY(T, _size); + } + + //Deallocates the array using ZSTL_DEL_ARRAY + void Deallocate(T* _ptr, size_t _size) + { + ZSTL_DEL_ARRAY(_ptr, _size); + } +}; + +/* +Heap allocator implementation of an allocator for ZArray. Will +always allocate on the heap. +*/ +template +class ZArrayHeapAllocator +{ +public: + //Allocate on the heap + T* Allocate(size_t _size) + { + return new (std::nothrow) T[_size]; + } + + //Deallocate the heap array + void Deallocate(T* _ptr, size_t _size) + { + URFP(_size); + + delete[] _ptr; + } +}; + + +///////////////////// +/* ZArray Iterator */ +///////////////////// + +/* +Iterator class for ZArray. Can also be used to iterate a raw array of type T. + +The template parameter T is the type contained in the list this iterator is for. +*/ +template +class ZArrayIterator +{ +public: + + /* + Default constructor. + */ + ZArrayIterator() + : Array(NULL), Index(0), Size(0) + { } + + /* + Copy constructor. + + @param _other - the other iterator + */ + ZArrayIterator(const ZArrayIterator& _other) + : Array(_other.Array), Index(_other.Index), Size(_other.Size) + { CheckCurrent(); } + + /* + Parameterized Constructor. + + @param _array - the array this iterator points to + @param _index - the index into the array at which to start the iterator. + @param _size - the size of the array we are pointed to + */ + ZArrayIterator(T *_array, size_t _index, size_t _size) + : Array(_array), Index(_index), Size(_size) + { CheckCurrent(); } + + /* + public ZArrayIterator::CheckCurrent + + Check function that determines if the iterator is valid at it's current location. + + @param _endIsValid - indicates that the iterator can be at the 'end' location + @return (void) + */ + void CheckCurrent(bool _endIsValid = true) const + { + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(Array != NULL, + "Uninitialized ZArray Iterator used!"); + ZSTL_ASSERT(Index < Size + (_endIsValid ? 1 : 0), + "ZArray Iterator has gone past end of array!"); + #else + URFP(_endIsValid); + #endif + } + + /* + public ZArrayIterator::CheckNext + + Check function that determines if incrementing the iterator would be valid, + assuming it was already valid. + + @param _inc - the amount by which the iterator will be incremented + @return (void) + */ + void CheckNext(size_t _inc) const + { + #if !ZSTL_DISABLE_RUNTIME_CHECKS + //Integer overflow possible here, but not likely + ZSTL_ASSERT(Index + _inc <= Size, "ZArray Iterator has gone past end of array!"); + #else + URFP(_inc); + #endif + } + + /* + public ZArrayIterator::CheckPrevious + + Check function that determines if decrementing the iterator would be valid, + assuming it was already valid. + + @param _dec - the amount by which the iterator will be decremented + @return (void) + */ + void CheckPrevious(size_t _dec) const + { + #if !ZSTL_DISABLE_RUNTIME_CHECKS + //i.e. check that "Index - _dec >= 0", but carefully since + //these are unsigned numbers and underflow results in SIZE_MAX + ZSTL_ASSERT(Index >= _dec, "ZArray Iterator has gone past beginning of array!"); + #else + URFP(_dec); + #endif + } + + /* + public ZArrayIterator::Get + + Gets the element this iterator points to. + + @return (T&) - the element pointed to + */ + T& Get() const + { + return *(*this); + } + + /* + public ZArrayIterator::HasCurrent + + Determines if this iterator currently points to a valid element. + + @return (bool) - true if element at current position + */ + bool HasCurrent() const + { + return Index < Size; + } + + /* + public ZArrayIterator::HasNext + + Determines if this iterator has a valid element after the current element. + + @return (bool) - true if element after current, false otherwise + */ + bool HasNext() const + { + return Size != 0 && Index < Size - 1; + } + + /* + public ZArrayIterator::HasPrev + + Determines if this iterator has a valid element before the current element. + + @return (bool) - true if element before current, false otherwise + */ + bool HasPrev() const + { + return Index > 0; + } + + /* + public ZArrayIterator::Next + + Advances this iterator to the next element. + + @return (void) + @assert - if this would advance past end + */ + void Next() + { + ++(*this); + } + + /* + public ZArrayIterator::Prev + + Returns this iterator to the previous element. + + @return (void) + @assert - if this would advance past begin + */ + void Prev() + { + --(*this); + } + + //Operator Overrides + ZArrayIterator& operator ++() { CheckNext(1); Index++; return *this; } + ZArrayIterator operator ++ (int) { CheckNext(1); return ZArrayIterator(Array, Index++, Size); } + ZArrayIterator operator + (int _value) { return ZArrayIterator(Array, Index + _value, Size); } + ZArrayIterator& operator += (int _value) { CheckNext(_value); Index += _value; return *this; } + + ZArrayIterator& operator -- () { CheckPrevious(1); Index--; return *this; } + ZArrayIterator operator -- (int) { CheckPrevious(1); return ZArrayIterator(Array, Index--, Size); } + ZArrayIterator operator - (int _value) { return ZArrayIterator(Array, Index - _value, Size); } + ZArrayIterator& operator -= (int _value) { CheckPrevious(_value); Index -= _value; return *this; } + + ZArrayIterator& operator = (const ZArrayIterator &_other) { Array = _other.Array; Index = _other.Index; Size = _other.Size; CheckCurrent(); return *this; } + bool operator == (const ZArrayIterator &_other) const { return Index == _other.Index; } + bool operator != (const ZArrayIterator &_other) const { return !(Index == _other.Index); } + + bool operator < (const ZArrayIterator &_other) const { return (Index < _other.Index); } + bool operator <= (const ZArrayIterator &_other) const { return (Index <= _other.Index); } + bool operator > (const ZArrayIterator &_other) const { return (Index > _other.Index); } + bool operator >= (const ZArrayIterator &_other) const { return (Index >= _other.Index); } + + T& operator *() const { CheckCurrent(false); return Array[Index]; } + + operator size_t () const { return Index; } + +protected: + + //The array + T* Array; + + //The current index into the array + size_t Index; + + //The size of the array (at construction) + size_t Size; + +}; + +/////////////////////////// +/* ZArray Implementation */ +/////////////////////////// + +/* +Templated dynamic array implementation. + +The template parameter T is the type contained in the array. + +The template parameter A is the type of allocator to use, which must allocate +arrays of type T. +*/ +template > +class ZArray +{ +friend struct ZArray_AtImpl; +friend struct ZArray_BackImpl; +friend struct ZArray_CapacityImpl; +friend struct ZArray_ClearImpl; +friend struct ZArray_CopyImpl; +friend struct ZArray_DataImpl; +friend struct ZArray_EmptyImpl; +friend struct ZArray_EqualsImpl; +friend struct ZArray_EraseImpl; +friend struct ZArray_FrontImpl; +friend struct ZArray_FindImpl; +friend struct ZArray_InsertImpl; +friend struct ZArray_PopBackImpl; +friend struct ZArray_PopFrontImpl; +friend struct ZArray_PushBackImpl; +friend struct ZArray_ReserveImpl; +friend struct ZArray_ResizeImpl; +friend struct ZArray_SizeImpl; +friend struct ZArray_SwapImpl; +public: + /* + Typedef for ZArrayIterator (Allows ZArray::Iterator notation). + */ + typedef ZArrayIterator Iterator; + + /* + Default Constructor. + */ + ZArray() + : Array(NULL), + ArrayCapacity(ZARRAY_DEFAULT_CAPACITY), + ArraySize(0) + { + Allocate(ArrayCapacity); + CheckIntegrity(); + } + + /* + Parameterized Constructor. + + @param _capacity - the starting capacity of the array + */ + explicit ZArray(size_t _capacity) + : Array(NULL), + ArrayCapacity(_capacity), + ArraySize(0) + { + Allocate(ArrayCapacity); + + CheckIntegrity(); + } + + /* + Parameterized Constructor. Given a reference to an array with a + size that can be deduced by the compiler, will create the array + using that data. + + @param C - the length of the array + @param _data - the data to initialize with + @param _count - the length of the data + */ + template + explicit ZArray( const T (&_data)[C]) + : Array(NULL), + ArrayCapacity((size_t)(C * ZARRAY_CAPACITY_RESIZE_FACTOR)), + ArraySize(C) + { + Allocate(ArrayCapacity); + + for (size_t i = 0; i < C; i++) + Array[i] = _data[i]; + + CheckIntegrity(); + } + + /* + Parameterized Constructor. + + @param _capacity - the starting capacity of the array + @param _size - the starting size of the array + */ + ZArray(size_t _capacity, size_t _size) + : Array(NULL), + ArrayCapacity(_capacity), + ArraySize(_size) + { + Allocate(ArrayCapacity); + Resize(ArraySize); + + CheckIntegrity(); + } + + /* + Parameterized Constructor. Given a raw array and a size, will + create this array using that data. + + @param _data - the data to initialize with + @param _count - the length of the data + */ + ZArray(const T* _data, size_t _count) + : Array(NULL), + ArrayCapacity((size_t)(_count * ZARRAY_CAPACITY_RESIZE_FACTOR)), + ArraySize(_count) + { + Allocate(ArrayCapacity); + + for (size_t i = 0; i < _count; i++) + Array[i] = _data[i]; + + CheckIntegrity(); + } + + /* + Parameterized Constructor. Given a raw array and a size, will + create this array using that data. + + @param _data - the data to initialize with + @param _count - the length of the data + @param _capacity - the capacity to initialize with (must be greater than size) + */ + ZArray(const T* _data, size_t _count, size_t _capacity) + : Array(NULL), + ArrayCapacity(_capacity), + ArraySize(_count) + { + Allocate(ArrayCapacity); + + for (size_t i = 0; i < _count; i++) + Array[i] = _data[i]; + + CheckIntegrity(); + } + + /* + Copy Constructor. Makes a deep copy of the array. Even though the code + is the same as the more generic copy constructor below, the code is needed to + ensure a default copy constructor is not generated. + + @param _other - the array to copy from + */ + ZArray(const ZArray& _other) + : Array(NULL), + ArrayCapacity(_other.Capacity()), + ArraySize(_other.Size()) + { + T* data; + size_t i; + + Allocate(ArrayCapacity); + CheckIntegrity(); + + for (i = 0, data = _other.Data(); i < ArraySize; i++) + Array[i] = data[i]; + } + + /* + Copy Constructor. Makes a deep copy of the array from an array with + a different allocator type. + + @param B - the allocator type of the other array + @param _other - the array to copy from + */ + template + ZArray(const ZArray& _other) + : Array(NULL), + ArrayCapacity(_other.Capacity()), + ArraySize(_other.Size()) + { + T* data; + size_t i; + + Allocate(ArrayCapacity); + CheckIntegrity(); + + for (i = 0, data = _other.Data(); i < ArraySize; i++) + Array[i] = data[i]; + } + + /* + Slice Copy Constructor. Constructs this array as a slice of another array. + + @param B - the allocator type of the other array + @param _other - the array to copy from + */ + template + ZArray(const ZArray& _other, size_t _start, size_t _end) + : Array(NULL), + ArrayCapacity(_other.Capacity()), + ArraySize(_end - _start) + { + Allocate(ArrayCapacity); + + CheckIntegrity(); + + _other.BoundsCheck(_start, _other.Size()); + _other.BoundsCheck(_end, _other.Size() + 1); + + for (size_t i = _start; i < _end; i++) + Array[i - _start] = _other.Data()[i]; + } + + /* + Destructor. + */ + ~ZArray() + { + CheckIntegrity(); + Deallocate(Array, ArrayCapacity); + } + + /* + [] Operator overload. Gets a value from the array. Functionally equivalent to + a call to At. + + @param _index - the integer index into the array + @return (T&) - reference to a value contained in the array + @assert - if the index is out of bounds + */ + T& operator [] (size_t _index) const + { return At(_index); } + + /* + = Operator overload. Sets this array equal to the other by making + a copy. Even though the code is the same as the more generic version below, + this is needed to prevent a default assignment operator from being constructed. + + @param _other - the array to be set equal to + @return (ZArray&) - this array + */ + ZArray& operator = (const ZArray& _other) + { Copy(_other); return *this; } + + /* + = Operator overload. Sets this array equal to the other by making + a copy. + + @param _other - the array to be set equal to + @return (ZArray&) - this array + */ + template + ZArray& operator = (const ZArray& _other) + { Copy(_other); return *this; } + + /* + == Operator overload. Performs an element comparison on the two arrays. + + @param B - the type of allocator for the other array + @param _other - the array to compare to + @return (bool) - true if this array is equivalent to the other + */ + template + bool operator == (const ZArray& _other) const + { return Equals(_other); } + + /* + != Operator overload. Performs an element comparison on the two arrays. + + @param B - the type of the allocator for the other array + @param _other - the array to compare to + @return (bool) - false if this array is equivalent to the other + */ + template + bool operator != (const ZArray& _other) const + { return !Equals(_other); } + + /* + public ZArray::Allocator + + Returns a reference to the installed allocator. + + @return (A&) - the array allocator + */ + A& Allocator() + { return ArrayAllocator; } + + /* + public ZArray::At + + Gets a value from the array at a given position. + + @param _index - index into the array + @return (T&) - the value at the given index + @assert - if the index is out of bounds + */ + T& At(size_t _index) const + { return ZArray_AtImpl::Call(*this, _index); } + + /* + public ZArray::Back + + Gets a reference to the value at the back of the array. + + @return (T&) - the value at the end of the array + @assert - if the array is empty + */ + T& Back() const + { return ZArray_BackImpl::Call(*this); } + + /* + public ZArray::Begin + + Returns an iterator to the beginning of the array. + + @return (ZArray::Iterator) - Iterator with index zero + */ + Iterator Begin() + { return ZArrayIterator(Array, 0, ArraySize); } + + /* + public ZArray::BoundsCheck + + Function that checks the provided index against the provided boundary, asserting if an + out of bounds access occurs. Calls to this will be compiled out if ZSTL_DISABLE_RUNTIME_CHECKS + is not zero. + + @param _index - index + @param _boundary - the (exclusive) boundary to use for bounds checking + @return (size_t) - unsigned index into the array + @assert - if the index is not less than boundary + */ + size_t BoundsCheck(size_t _index, size_t _boundary) const + { + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(_index < _boundary, "ZArray: Out of bounds access!"); + #else + (void)_boundary; + #endif + + return _index; + } + + /* + public ZArray::Capacity + + Returns the capacity of the array, which is the number of values it can contain + before allocation is required to increase storage size. + + @return (size_t) - array capacity + */ + size_t Capacity() const + { return ZArray_CapacityImpl::Call(*this); } + + /* + public ZArray::Clear + + Clears out the array of all contained elements, keeping the currently allocated + storage. + + @return (void) + */ + void Clear() + { ZArray_ClearImpl::Call(*this); } + + /* + public ZArray::Clear + + Clears out the array of all contained elements and will ensure that the capacity is + at least as much as the provided value. Reallocates the internal storage if necessary. + + @param _newCapacity - the (minimum) capacity of the array after clearing + @return (void) + */ + void Clear(size_t _newCapacity) + { ZArray_ClearImpl::Call(*this, _newCapacity); } + + /* + public ZArray::Copy + + Makes a deep copy of the provided array. + + @param _other - the array to copy from + @return (void) + */ + template + void Copy(const ZArray& _other) + { ZArray_CopyImpl::template Call(*this, _other); } + + /* + public ZArray::Data + + Gets a pointer to the underlying array data. + + @return (T*) - pointer to the first element in the array + */ + T* Data() const + { return ZArray_DataImpl::Call(*this); } + + /* + public ZArray::Empty + + Returns true if the array is empty (size 0), false otherwise. + + @return (bool) - true if empty, false otherwise + */ + bool Empty() const + { return ZArray_EmptyImpl::Call(*this); } + + /* + public ZArray::End + + Returns an iterator to the end of the array. + + @return (ZArray::Iterator) - Iterator with index set to capacity + */ + Iterator End() + { return ZArrayIterator(Array, ArraySize, ArraySize); } + + /* + public ZArray::Equals + + Determines, with an element by element comparison, if this array is equivalent + to another. + + @param _other - the array to compare with + @return (bool) - true if equal, false otherwise + */ + template + bool Equals(const ZArray& _other) const + { return ZArray_EqualsImpl::template Call(*this, _other); } + + /* + public ZArray::Erase + + Erase function. Removes an element from the array at the given index. + + @param _index - the index at which to remove the element from the array. + @return (T) - the element removed + @assert - if the index is invalid + */ + T Erase(size_t _index) + { return ZArray_EraseImpl::Call(*this, _index); } + + /* + public ZArray::Erase + + Erase function. Removes elements from the array between the given indices. + + @param _start - the starting index + @param _end - the ending index (exclusive) + @return (void) + @assert - if the indices are invalid + */ + void Erase(size_t _start, size_t _end) + { ZArray_EraseImpl::Call(*this, _start, _end); } + + /* + public ZArray::Front + + Gets a reference to the value at the front of the array. + + @return (T&) - the value at the front of the array + @assert - if the array is empty + */ + T& Front() const + { return ZArray_FrontImpl::Call(*this); } + + /* + public ZArray::Find + + Find function. Finds the first element in the array that is equal to elem, + determined via == operator. + + @param _elem - the elem to find + @return (size_t) - the index of the first occurence of elem, ZSTL::InvalidPos if not found + */ + size_t Find(const T& _elem) + { return ZArray_FindImpl::Call(*this, _elem); } + + /* + public ZArray::Insert + + Inserts the given value at the specified location. + + @param _index - the index at which to perform the insertion + @param _value - the value to insert + @return (void) + @assert - if the index is invalid + */ + void Insert(size_t _index, const T& _value) + { ZArray_InsertImpl::Call(*this, _index, _value, 1); } + + /* + public ZArray::Insert + + Inserts the given value at the specified location the given number of times. + + @param _index - the index at which to perform the insertion + @param _value - the value to insert + @param _count - the number of times to insert _value + @return (void) + @assert - if the index is invalid + */ + void Insert(size_t _index, const T& _value, size_t _count) + { ZArray_InsertImpl::Call(*this, _index, _value, _count); } + + /* + public ZArray::Insert + + Inserts the entirety of the given array at the specified location. + + @param _index - the index at which to perform the insertion + @param _other - the array to insert values from + @return (void) + @assert - if the index is invalid + */ + template + void Insert(size_t _index, const ZArray& _other) + { ZArray_InsertImpl::template Call(*this, _index, _other, 0, _other.Size()); } + + /* + public ZArray::Insert + + Inserts data from the given array at the specified location. + + @param _index - the index at which to perform the insertion + @param _other - the array to insert values from + @param _start - the index to start getting values from + @param _count - the number of elements to insert starting at index + @return (void) + @assert - if the index is invalid or the start index is invalid + */ + template + void Insert(size_t _index, const ZArray& _other, size_t _start, size_t _count) + { ZArray_InsertImpl::template Call(*this, _index, _other, _start, _count); } + + /* + public ZArray::PopBack + + Pop function. Removes and returns the last element in the array. + + @return (T) - the last element in the array + @assert - if the array is empty + */ + T PopBack() + { return ZArray_PopBackImpl::Call(*this); } + + /* + public ZArray::PopFront + + Pop function. Removes and returns the first element in the array. This operation + requires shifting all elements in the array forward. + + @return (T) - the first element in the array + @assert - if the array is empty + */ + T PopFront() + { return ZArray_PopFrontImpl::Call(*this); } + + /* + public ZArray::PushBack + + Push function. Attaches an element to the end of the array. Will allocate + storage if necessary. + + @param _value - the element to place at the end of the array + @return (void) + */ + void PushBack(const T& _value) + { ZArray_PushBackImpl::Call(*this, _value); } + + /* + public ZArray::PushFront + + Push function. Attaches an element to the beginning of the array. This operation + requires shifting all elements in the array back. Will allocate storage if necessary. + + @param _value - the element to place at the beginning of the array + @return (void) + */ + void PushFront(const T& _value) + { ZArray_PushFrontImpl::Call(*this, _value); } + + /* + public ZArray::Reserve + + Reserves an amount of space in the vector. Allocates space if + necessary (capacity > current capacity). The array capacity cannot + be reduced in size below the number of contained elements. + + Reserve(0) is guaranteed to always deallocate the array using + the provided deallocator. + + @param _capacity - the new capacity requested + @return (void) + @assert - if capacity is less than size + */ + void Reserve(size_t _capacity) + { ZArray_ReserveImpl::Call(*this, _capacity, false); } + + /* + public ZArray::Reserve + + Reserves an amount of space in the vector. Allocates space if + necessary (capacity > current capacity). The array capacity cannot + be reduced in size below the number of contained elements. + + Reserve(0) is guaranteed to always deallocate the array using + the provided deallocator, regardless of the value of _reallocate. + + @param _capacity - the new capacity requested + @param _reallocate - if true, will always reallocate storage + @return (void) + @assert - if capacity is less than size + */ + void Reserve(size_t _capacity, bool _reallocate) + { ZArray_ReserveImpl::Call(*this, _capacity, _reallocate); } + + /* + public ZArray::Resize + + Resize function. Increases or Decreases the size of the array. + + @param _size - the new size to grow the array to + @return (void) + */ + void Resize(size_t _size) + { ZArray_ResizeImpl::Call(*this, _size); } + + /* + public ZArray::Resize + + Resize function. Increases or Decreases the size of the array and + sets new values equal to the given value. + + @param _size - the new size to grow (or shrink) the array to + @param _value - the new value to set all added values to + @return (void) + */ + void Resize(size_t _size, const T& _value) + { ZArray_ResizeImpl::Call(*this, _size, _value); } + + /* + public ZArray::Resize + + Resize function. Increases or decreases the size of the array and + reserves a new capacity (must be greater than size). Sets new values + equal to the given value. + + @param _size - the new size to grow (or shrink) the array to + @param _capacity - the new capacity to reserve (must be greater than or equal to size) + @param _value - the new value to set all added values to + @return (void) + */ + void Resize(size_t _size, size_t _capacity, const T& _value) + { ZArray_ResizeImpl::Call(*this, _size, _capacity, _value); } + + /* + public ZArray::Size + + Size function. Give the size of the array. + + @return (size_t) - the size of this array + */ + size_t Size() const + { return ZArray_SizeImpl::Call(*this); } + + /* + public ZArray::Swap + + Swaps the array contents with another array with any + local storage size. + + @param _other - the array to swap contents with + @return (void) + */ + template + void Swap(ZArray& _other) + { ZArray_SwapImpl::Call(*this, _other); } + +protected: + + //The array pointer + T *Array; + + //Allocator for the Array + A ArrayAllocator; + + //The 'size' of the raw array pointer + size_t ArrayCapacity; + + //The current number of contained elements in the array + size_t ArraySize; + + //Makes a call to the allocator and checks the result + inline void Allocate(size_t _size) + { + Array = ArrayAllocator.Allocate(_size); + + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(!(Array == NULL && _size > 0), "ZArrayAllocator failed to properly allocate array! (returned NULL with size > 0)"); + #endif + } + + //Makes a call to the allocator + inline void Deallocate(T* _array, size_t _size) + { + ArrayAllocator.Deallocate(_array, _size); + } + + //Shifts values up in the array from _start by _count + inline void ShiftUp(size_t _index, size_t _count) + { + /* + Shift elements up, but do so in reverse so that we don't just copy Array[i] to all of the higher addresses. + If you do: + + Array[i+1] = Array[i]; + + ...in a loop, then the first iteration overwrites the second value with the first, but it doesn't preserve + the second so it can be copied into the third. If you run this code on [1, 2, 3, 0], you get [1, 1, 3, 0] after the first + iteration, and then [1, 1, 1, 0] after the second iteration, and so on. + + The solution is to copy backwards. Consider an array of 100 elements: + + [1, 2, 3, ..., 100] + + ...that is to by shifted by 3 elements, starting at index 5. Then, we know that + the final array should look like: + + [1, 2, 3, 4, X, X, X, ..., 5, 6, 7, ... 100]. + + where X is undefined (in this function, it is "_value"). The number of elements that + will be shifted is 100 - 5 = 95 elements. Further more, each element will be shifted 3 + units. Let S be the size of the array (100), I be the index to start at (5), and N + be the number to shift by (3). Then, + + Since we are copying backwards, consider the final element: Array[S-1]. This element + is to be moved N units, so: + + Array[S-1 + N] = Array[S-1]; + + Add in a counter, K, that decreases the index value each loop iteration, and loop S-I times. + + Array[S-1 + N - K] = ArraySize[S-1 - K] + */ + + size_t i; + const size_t nShift = ArraySize - _index; + + //Shift elements up + for(i = 0; i < nShift; i++) + Array[ArraySize - 1 + _count - i] = Array[ArraySize - 1 - i]; + } + + //Integrity Check (used for internal debugging) + inline void CheckIntegrity() const + { + #if ZSTL_CHECK_INTEGRITY + ZSTL_ASSERT(!(Array == NULL && ArrayCapacity > 0), "ZArray Error: Array is invalid!"); + ZSTL_ASSERT(ArrayCapacity >= ArraySize, "ZArray Error: Array capacity less than size!"); + #endif + } +}; + +//////////////////////////////////////////// +/* Non-Specialized Method Implementations */ +//////////////////////////////////////////// + +template +T& ZArray_AtImpl::Call( const ZArray& _self, size_t _index ) +{ + size_t index = _self.BoundsCheck(_index, _self.ArraySize); + + return _self.Array[index]; +} + +/*************************************************************************/ + +template +T& ZArray_BackImpl::Call( const ZArray& _self ) +{ + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(_self.ArraySize > 0, "ZArray: Cannot get back element from empty array!"); + #endif + + return _self.Array[_self.ArraySize - 1]; +} + +/*************************************************************************/ + +template +size_t ZArray_CapacityImpl::Call(const ZArray& _self) +{ + //Give back our current capacity + return _self.ArrayCapacity; +} + +/*************************************************************************/ + +template +void ZArray_ClearImpl::Call(ZArray& _self) +{ + //Reset size and check integrity + _self.ArraySize = 0; + _self.CheckIntegrity(); +} + +/*************************************************************************/ + +template +void ZArray_ClearImpl::Call(ZArray& _self, size_t _newCapacity) +{ + //Reset size, reserve new capacity, then check integrity + _self.ArraySize = 0; + _self.Reserve(_newCapacity, false); + + _self.CheckIntegrity(); +} + +/*************************************************************************/ + +template template +void ZArray_CopyImpl::Call(ZArray& _self, const ZArray& _other) +{ + size_t i; + + //If both arrays point to the same data, we're done here + if (_self.Data() == _other.Data()) + return; + + //Make sure we have room, write data, and check integrity + _self.Resize(_other.Size()); + + for (i = 0; i < _other.Size(); i++) + _self.Array[i] = _other.Data()[i]; + + _self.CheckIntegrity(); +} + +/*************************************************************************/ + +template +T* ZArray_DataImpl::Call(const ZArray& _self) +{ + return _self.Array; +} + +/*************************************************************************/ + +template +bool ZArray_EmptyImpl::Call(const ZArray& _self) +{ + return _self.ArraySize == 0; +} + +/*************************************************************************/ + +template template +bool ZArray_EqualsImpl::Call(const ZArray& _self, const ZArray& _other) +{ + size_t i; + + //First see if we have the same size + if (_self.ArraySize == _other.Size()) + { + //Element wise comparison + for (i = 0; i < _self.ArraySize; i++) + { + if (!(_self.Array[i] == _other.Array[i])) + return false; + } + } + else + { + //Nope, so false + return false; + } + + return true; +} + +/*************************************************************************/ + +template +T ZArray_EraseImpl::Call(ZArray& _self, size_t _index) +{ + size_t index = _self.BoundsCheck(_index, _self.ArraySize); + + //Grab the currently held element, shift the array down, reduce size, and check integrity + T element = _self.Array[index]; + + for (size_t i = index; i + 1 < _self.ArraySize; i++) + _self.Array[i] = _self.Array[i + 1]; + + _self.ArraySize--; + _self.CheckIntegrity(); + + return element; +} + +/*************************************************************************/ + +template +void ZArray_EraseImpl::Call(ZArray& _self, size_t _start, size_t _end) +{ + if (_start == _end) + return; + + size_t start = _self.BoundsCheck(_start, _self.ArraySize); + size_t end = _self.BoundsCheck(_end, _self.ArraySize + 1); + + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(start <= end, "ZArray: cannot erase with start < end!"); + #endif + + //Copy the elements down, compute new size, and check integrity + for (size_t idx = start; idx + (end - start) < _self.ArraySize; idx++) + _self.Array[idx] = _self.Array[idx + (end - start)]; + + _self.ArraySize = _self.ArraySize - (end - start); + _self.CheckIntegrity(); +} + +/*************************************************************************/ + +template +T& ZArray_FrontImpl::Call( const ZArray& _self ) +{ + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(_self.ArraySize > 0, "ZArray: Cannot get front element from empty array!"); + #endif + + return _self.Array[0]; +} + +/*************************************************************************/ + +template +size_t ZArray_FindImpl::Call( const ZArray& _self, const T& _elem ) +{ + for (size_t i = 0; i < _self.ArraySize; i++) { + if (_self.Array[i] == _elem) { + return i; + } + } + + return ZSTL::InvalidPos; +} + +/*************************************************************************/ + +template +void ZArray_InsertImpl::Call(ZArray& _self, size_t _index, const T& _value, size_t _count) +{ + //Get our insertion index (we allow past end to indicate insert at 'end') + size_t index = _self.BoundsCheck(_index, _self.ArraySize + 1); + + const size_t newSize = _self.ArraySize + _count; + + //Reserve enough space for the new elements + if (newSize > _self.ArrayCapacity) + _self.Reserve(newSize); + + //Shift up existing elements + _self.ShiftUp(index, _count); + + //Insert new values + for (size_t i = 0; i < _count; i++) + _self.Array[index + i] = _value; + + //Increase our array size + _self.ArraySize += _count; + + //We are non const, so check + _self.CheckIntegrity(); +} + +/*************************************************************************/ + +template template +void ZArray_InsertImpl::Call(ZArray& _self, size_t _index, const ZArray& _other, size_t _start, size_t _count) +{ + //Get our indices (once again, allowed to go past end to indicate 'append') + size_t index = _self.BoundsCheck(_index, _self.ArraySize + 1); + size_t start = _other.BoundsCheck(_start, _other.Size() + 1); + + _other.BoundsCheck(_start + _count, _other.Size() + 1); //This will do a bounds check on other + + const size_t newSize = _self.ArraySize + _count; + + //Make sure we have enough space + if (newSize > _self.ArrayCapacity) + _self.Reserve( newSize ); + + //Shift elements up + _self.ShiftUp(index, _count); + + //Copy in the data from the other + for (size_t i = 0; i < _count; i++) + _self.Array[index + i] = _other.Data()[start + i]; + + //Set our new size + _self.ArraySize = newSize; + + //We are non-const, so check + _self.CheckIntegrity(); +} + +/*************************************************************************/ + +template +T ZArray_PopBackImpl::Call(ZArray& _self) +{ + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(_self.ArraySize > 0, "ZArray: Cannot pop from array with no elements!"); + #endif + + //Grab the last element in the array and decrease our array size + return _self.Array[--(_self.ArraySize)]; +} + +/*************************************************************************/ + +template +T ZArray_PopFrontImpl::Call(ZArray& _self) +{ + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(_self.ArraySize > 0, "ZArray: Cannot pop from array with no elements!"); + #endif + + //Just use our erase function + return _self.Erase(0); +} + +/*************************************************************************/ + +template +void ZArray_PushBackImpl::Call(ZArray& _self, const T& _value) +{ + //See if we need more space + if (_self.ArraySize >= _self.ArrayCapacity) + _self.Reserve((size_t)((float)_self.ArrayCapacity * ZARRAY_CAPACITY_RESIZE_FACTOR) + 1 ); //Calls CheckIntegrity + + //Add in the element + _self.Array[(_self.ArraySize)++] = _value; +} + +/*************************************************************************/ + +template +void ZArray_PushFrontImpl::Call(ZArray& _self, const T& _value) +{ + //Just use the insert function + return _self.Insert(0, _value, 1); +} + +/*************************************************************************/ + +template +void ZArray_ReserveImpl::Call(ZArray& _self, size_t _capacity, bool _reallocate) +{ + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(_capacity >= _self.ArraySize, "ZArray: Cannot reserve capacity less than array size!"); + #endif + + //Special case for reserve 0 + if (_capacity == 0) + { + _self.Deallocate(_self.Array, _self.ArrayCapacity); + _self.Array = NULL; + _self.ArrayCapacity = 0; + return; + } + + //See if we actually need to increase our capacity + if (!_reallocate && _capacity <= _self.ArrayCapacity) + return; + + //Set our temp array + T* temp = _self.Array; + + //Allocate an array + _self.Allocate(_capacity); + + //Make sure we aren't doing something pointless here + if (temp == _self.Array) + { + _self.ArrayCapacity = _capacity; + return; + } + + //Copy the data + for (size_t i = 0; i < _self.ArraySize; i++) + _self.Array[i] = temp[i]; + + //Deallocate the temporary (old) array + _self.Deallocate(temp, _self.ArrayCapacity); + + //Set our new capacity + _self.ArrayCapacity = _capacity; + + //non-const, so check integrity + _self.CheckIntegrity(); +} + +/*************************************************************************/ + +template +void ZArray_ResizeImpl::Call(ZArray& _self, size_t _size) +{ + //Check to see if we need more space, change our size, and check integrity + if (_size > _self.ArrayCapacity) + _self.Reserve(_size); + + _self.ArraySize = _size; + _self.CheckIntegrity(); +} + +/*************************************************************************/ + +template +void ZArray_ResizeImpl::Call(ZArray& _self, size_t _size, const T& _value) +{ + //See if we need more space, copy in the new value, change our size, and check integrity + if (_size > _self.ArrayCapacity) + _self.Reserve(_size); + + for (size_t i = _self.ArraySize; i < _size; i++) + _self.Array[i] = _value; + + _self.ArraySize = _size; + _self.CheckIntegrity(); +} + +/*************************************************************************/ + +template +void ZArray_ResizeImpl::Call(ZArray& _self, size_t _size, size_t _capacity, const T& _value) +{ + _self.Reserve(_capacity); + + //See if we need more space, copy in the new value, change our size, and check integrity + if (_size > _self.ArrayCapacity) + _self.Reserve(_size); + + for (size_t i = _self.ArraySize; i < _size; i++) + _self.Array[i] = _value; + + _self.ArraySize = _size; + _self.CheckIntegrity(); +} + +/*************************************************************************/ + +template +size_t ZArray_SizeImpl::Call(const ZArray& _self) +{ + return _self.ArraySize; +} + +/*************************************************************************/ + +template template +void ZArray_SwapImpl::Call(ZArray& _self, ZArray& _other) +{ + T tempElement; + size_t i; + size_t smallerSize; + + // Arrays are same size. + if (_self.ArraySize == _other.ArraySize) + { + for (i = 0; i < _self.ArraySize; i++) + { + tempElement = _other[i]; + _other[i] = _self[i]; + _self[i] = tempElement; + } + return; + } + // Self is larger than other. + else if (_self.ArraySize > _other.ArraySize) + { + smallerSize = _other.ArraySize; + + // Swap all of the smaller array's elements + for (i = 0; i < smallerSize; i++) + { + tempElement = _other[i]; + _other[i] = _self[i]; + _self[i] = tempElement; + } + + // Resize smaller array to be larger. + _other.Reserve(_self.ArraySize); + for (i = smallerSize; i < _self.ArraySize; i++) + _other.PushBack(_self[i]); + + // Truncate our array. + _self.Resize(smallerSize); + } + else + { + smallerSize = _self.ArraySize; + + // Swap all of the smaller array's elements + for (i = 0; i < smallerSize; i++) + { + tempElement = _other[i]; + _other[i] = _self[i]; + _self[i] = tempElement; + } + + // Resize smaller array to be larger. + _self.Reserve(_other.ArraySize); + for (i = smallerSize; i < _other.ArraySize; i++) + _self.PushBack(_other[i]); + + // Truncate our array. + _other.Resize(smallerSize); + } + + //Check integrity on both arrays + _self.CheckIntegrity(); + _other.CheckIntegrity(); +} + +#endif diff --git a/Lib/Include/ZSTL/ZArrayAlgo.hpp b/Lib/Include/ZSTL/ZArrayAlgo.hpp new file mode 100644 index 0000000..30021ce --- /dev/null +++ b/Lib/Include/ZSTL/ZArrayAlgo.hpp @@ -0,0 +1,2842 @@ +/* + ZArrayAlgo.hpp + Author: James Russell + Created: 1/12/2012 + + Purpose: + + Generalized algorithm implementations for use with ZArray. + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ + +#pragma once + +#ifndef _ZARRAYALGO_HPP +#define _ZARRAYALGO_HPP + +#include +#include + +namespace ZArrayAlgo +{ + //Forward Declaration of FindFirst + template + size_t FindFirst(const ZArray& _array, const T& _value, size_t _start, size_t _end); + + //Forward Declaration of FindSub + template + size_t FindSub(const ZArray& _array, size_t _s1, size_t _e1, const ZArray& _other, size_t _s2, size_t _e2); + + //Forward Declaration of Unique + template + size_t Unique(ZArray& _array, size_t _start, size_t _end); + + /* + public ZArrayAlgo::Append + + Appends the specified range of one array to another. + + @param T - the type held by the array + @param A - the allocator type of the array + @param B - the allocator type of the other array + @param _array - the array to append to + @param _other - the array to append to the end of _array + @param _start - the starting index of _other + @param _end - the ending index of _other (exclusive) + @return (void) + @assert - if _end < _start + if _start or _end out of bounds + */ + template + void Append(ZArray& _array, const ZArray& _other, size_t _start, size_t _end) + { + if (_start == _end) + return; + + const size_t start = _other.BoundsCheck(_start, _other.Size()); + const size_t end = _other.BoundsCheck(_end, _other.Size() + 1); // 1 to allow indexing of end + + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(start <= end, "ZArrayAlgo::Append - Cannot append with end < start!"); + #endif + + const size_t initialSize = _array.Size(); + const size_t delta = end - start; + + _array.Resize(_array.Size() + delta); + + for (size_t i = 0; i < delta; i++) + _array.Data()[initialSize + i] = _other.Data()[start + i]; + } + + /* + public ZArrayAlgo::Append + + Appends one array to another. + + @param T - the type held by the array + @param A - the allocator type of the array + @param B - the allocator type of the other array + @param _array - the array to append to + @param _other - the array to append to the end of _array + @return (void) + */ + template + void Append(ZArray& _array, const ZArray& _other) + { + Append(_array, _other, 0, _other.Size()); + } + + /* + public ZArrayAlgo::Apply + + Maps the provided unary functor over the array between the given indices, mutating in place. + + @param F - unary functor [(T&) -> void] used to operate on array[i] + @param T - the type held by the array + @param A - the allocator type of the array + @param _array - the array to map the function over + @param _functor - instance of the unary functor F + @param _start - the index to start looking at + @param _end - the end index (exclusive) + @return (void) + @assert - if _end < _start + if _start or _end out of bounds + */ + template + void Apply(ZArray& _array, F _functor, size_t _start, size_t _end) + { + if (_start == _end) + return; + + const size_t start = _array.BoundsCheck(_start, _array.Size()); + const size_t end = _array.BoundsCheck(_end, _array.Size() + 1); // 1 to allow indexing of end + + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(start <= end, "ZArrayAlgo::Map - Cannot map with end < start!"); + #endif + + for (size_t i = start; i < end; i++) + _functor(_array.Data()[i]); + } + + /* + public ZArrayAlgo::Apply + + Maps the provided unary functor over the array, mutating in place. + + @param F - unary functor [(T&) -> void] used to operate on array[i] + @param T - the type held by the array + @param A - the allocator type of the array + @param _array - the array to map the function over + @param _functor - instance of the unary functor F + @return (void) + */ + template + void Apply(ZArray& _array, F _functor) + { + Apply(_array, _functor, 0, _array.Size()); + } + + /* + public ZArrayAlgo::Concatenate + + Concatenates sections of two arrays and returns a new array. + + @param T - the type held by the array + @param A - the allocator type of the array + @param B - the allocator type of the other array + @param _array - the first array + @param _s1 - the start index on the first array + @param _e1 - the ending index on the first array (exclusive) + @param _other - the array that will be + @param _s2 - the start index on the second array + @param _e2 - the end index on the second array (exclusive) + @return (ZArray) + @assert - if _s1 < _e1 or _s2 < _e2 + if _s1, _e1, _s2, or _e2 out of bounds + */ + template + ZArray Concatenate(const ZArray& _array, size_t _s1, size_t _e1, const ZArray& _other, size_t _s2, size_t _e2) + { + if (_s1 == _e1) + return _other; + else if (_s2 == _e2) + return _array; + + const size_t s1 = _array.BoundsCheck(_s1, _array.Size()); + const size_t e1 = _array.BoundsCheck(_e1, _array.Size() + 1); // 1 to allow indexing of end + + const size_t s2 = _other.BoundsCheck(_s2, _other.Size()); + const size_t e2 = _other.BoundsCheck(_e2, _other.Size() + 1); // 1 to allow indexing of end + + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(s1 <= e1, "ZArrayAlgo::Merge - Cannot merge with e1 < s1!"); + ZSTL_ASSERT(s2 <= e2, "ZArrayAlgo::Merge - Cannot merge with e2 < s2!"); + #endif + + const size_t delta1 = e1 - s1; + const size_t delta2 = e2 - s2; + + const size_t newSize = delta1 + delta2; + + if (newSize == 0) + return ZArray(); + + ZArray ret(&_array.Data()[s1], delta1, newSize); + + ret.Resize(newSize); + + for (size_t i = 0; i < delta2; i++) + ret.Data()[delta1 + i] = _other.Data()[s2 + i]; + + return ret; + } + + /* + public ZArrayAlgo::Concatenate + + Concatenates an array to another and returns a new array. + + @param T - the type held by the array + @param A - the allocator type of the array + @param B - the allocator type of the other array + @param _array - the first array + @param _other - the second array + @return (ZArray) - the result of concatenation + */ + template + ZArray Concatenate(const ZArray& _array, const ZArray& _other) + { + return Concatenate(_array, 0, _array.Size(), _other, 0, _other.Size()); + } + + /* + public ZArrayAlgo::Contains + + Determines if the array contains the given value between the given indices. + + @param T - the type held by the array + @param A - the allocator type of the array + @param _array - the array to check for the value + @param _value - the value to search for + @param _start - the index to start searching at + @param _end - the end index (exclusive) + @return (bool) - true if found, false otherwise + @assert - if _end < _start + if _start or _end out of bounds + */ + template + bool Contains(const ZArray& _array, const T& _value, size_t _start, size_t _end) + { + return FindFirst(_array, _value, _start, _end) != ZSTL::InvalidPos; + } + + /* + public ZArrayAlgo::Contains + + Determines if the array contains the given value. + + @param T - the type held by the array + @param A - the allocator type of the array + @param _array - the array to check for the value + @param _value - the value to search for + @return (bool) - true if found, false otherwise + */ + template + bool Contains(const ZArray& _array, const T& _value) + { + return Contains(_array, _value, 0, _array.Size()); + } + + /* + public ZArrayAlgo::ContainsSub + + Determines if the array contains the given sub array. + + @param T - the type held by the array + @param A - the allocator type of the array + @param B - the allocator type of the other array + @param _array - the array to check for the value + @param _other - the sub array to search for + @param _start - the starting index + @param _end - the ending index (exclusive) + @return (bool) - true if found, false otherwise + @assert - if _end < _start + if _start or _end out of bounds + */ + template + bool ContainsSub(const ZArray& _array, size_t _s1, size_t _e1, const ZArray& _other, size_t _s2, size_t _e2) + { + return FindSub(_array, _s1, _e1, _other, _s2, _e2) != ZSTL::InvalidPos; + } + + /* + public ZArrayAlgo::ContainsSub + + Determines if the array contains the given sub array. + + @param T - the type held by the array + @param A - the allocator type of the array + @param B - the allocator type of the other array + @param _array - the array to check for the value + @param _other - the sub array to search for + @return (bool) - true if found, false otherwise + */ + template + bool ContainsSub(const ZArray& _array, const ZArray& _other) + { + return ContainsSub(_array, 0, _array.Size(), _other, 0, _other.Size()); + } + + /* + public ZArrayAlgo::Copy + + Copies a number of given elements into the given range of the provided array, + from the provided range in the other array. + + @param T - the type held by the array + @param A - the allocator type of the array + @param B - the allocator type of the other array + @param _array - the array to copy data into + @param _s1 - the starting index to copy to + @param _e1 - the ending index to copy to (exclusive) + @param _other - the array to copy data from + @param _s2 - the starting index to copy from + @param _e2 - the ending index to copy to (exclusive) + @return (void) + @assert - if _s1, _e1, _s2, or _e2 out of bounds + if _e1 < _s1 or _e2 < _s2 + */ + template + void Copy(ZArray& _array, size_t _s1, size_t _e1, const ZArray& _other, size_t _s2, size_t _e2) + { + if (_s1 == _e1 || _s2 == _e2) + return; + + const size_t s1 = _array.BoundsCheck(_s1, _array.Size()); + const size_t e1 = _array.BoundsCheck(_e1, _array.Size() + 1); // 1 to allow indexing of end + + const size_t s2 = _other.BoundsCheck(_s2, _other.Size()); + const size_t e2 = _other.BoundsCheck(_e2, _other.Size() + 1); // 1 to allow indexing of end + + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(s1 <= e1, "ZArrayAlgo::Copy - Cannot copy with e1 < s1!"); + ZSTL_ASSERT(s2 <= e2, "ZArrayAlgo::Copy - Cannot copy with e2 < s2!"); + #endif + + size_t i, j; + + for (i = s1, j = s2; i < e1 && j < e2; i++, j++) + _array.Data()[i] = _other.Data()[j]; + } + + /* + public ZArrayAlgo::Copy + + Copies the elements of one array into the other. + + @param T - the type held by the array + @param A - the allocator type of the array + @param B - the allocator type of the other array + @param _array - the array to copy data into + @param _other - the array to copy data from + @param _count - the number of elements to copy + @return (void) + @assert - if _count > array size or other size + */ + template + void Copy(ZArray& _array, const ZArray& _other) + { + return Copy(_array, 0, _array.Size(), _other, 0, _other.Size()); + } + + /* + public ZArrayAlgo::Count + + Returns the number of occurrences of the given value in the given range of the + provided array. + + @param T - the type held by the array + @param A - the allocator type of the array + @param _array - the array to count in + @param _value - the value to search for + @param _start - the index to start at + @param _end - the ending index (exclusive) + @return (size_t) - the number of occurrences of _value at and after _index + @assert - if _end < _start + if _start or _end out of bounds + */ + template + size_t Count(const ZArray& _array, const T& _value, size_t _start, size_t _end) + { + if (_start == _end) + return 0; + + const size_t start = _array.BoundsCheck(_start, _array.Size()); + const size_t end = _array.BoundsCheck(_end, _array.Size() + 1); // 1 to allow indexing of end + + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(start <= end, "ZArrayAlgo::Count - Cannot count with end < start!"); + #endif + + size_t count = 0; + + for (size_t i = start; i < end; i++) + { + if (_array.Data()[i] == _value) + count++; + } + + return count; + } + + /* + public ZArrayAlgo::Count + + Returns the number of occurrences of the given value in the array. + + @param T - the type held by the array + @param A - the allocator type of the array + @param _array - the array to count in + @param _value - the value to search for + @return (size_t) - the number of occurrences of _value at and after _index + */ + template + size_t Count(const ZArray& _array, const T& _value) + { + return Count(_array, _value, 0, _array.Size()); + } + + /* + public ZArrayAlgo::EndsWith + + Used to determine if the given region of the provided array ends with the contents of the + given region of the other array. + + @param T - the type held by the array + @param A - the allocator type of the array + @param B - the allocator type of the other array + @param _array - the array to check + @param _s1 - the starting index to check against + @param _e1 - the ending index to check against (exclusive) + @param _other - the array to check from + @param _s2 - the starting index to check from + @param _e2 - the ending index to check to (exclusive) + @return (bool) - true if the array ends with the provided values, false otherwise + @assert - if _s1, _e1, _s2, or _e2 out of bounds + if _e1 < _s1 or _e2 < _s2 + */ + template + bool EndsWith(const ZArray& _array, size_t _s1, size_t _e1, const ZArray& _other, size_t _s2, size_t _e2) + { + return FindSub(_array, _s1, _e1, _other, _s2, _e2) == (_e1 - (_e2 - _s2)); + } + + + /* + public ZArrayAlgo::EndsWith + + Used to determine if the provided array ends with the values contained in the other array. + + @param T - the type held by the array + @param A - the allocator type of the array + @param B - the allocator type of the other array + @param _array - the array to check + @param _other - the array to check from + @return (bool) - true if the array ends with the provided values, false otherwise + */ + template + bool EndsWith(const ZArray& _array, const ZArray& _other) + { + return EndsWith(_array, 0, _array.Size(), _other, 0, _other.Size()); + } + + /* + public ZArrayAlgo::Equal + + Determines if the arrays are equivalent in the given subsections, up to the length of the shortest + subsection. + + @param T - the type held by the array + @param A - the allocator type of the array + @param B - the allocator type of the other array + @param _array - the array to compare + @param _s1 - the starting index to compare + @param _e1 - the ending index to compare (exclusive) + @param _other - the array to compare against + @param _s2 - the starting index to compare against + @param _e2 - the ending index to compare against (exclusive) + @return (bool) - true if ranges are equivalent, false otherwise + @assert - if _s1, _e1, _s2, or _e2 out of bounds + if _e1 < _s1 or _e2 < _s2 + */ + template + bool Equal(const ZArray& _array, size_t _s1, size_t _e1, const ZArray& _other, size_t _s2, size_t _e2) + { + if (_s1 == _e1 || _s2 == _e2) + return false; + + const size_t s1 = _array.BoundsCheck(_s1, _array.Size()); + const size_t e1 = _array.BoundsCheck(_e1, _array.Size() + 1); // 1 to allow indexing of end + + const size_t s2 = _other.BoundsCheck(_s2, _other.Size()); + const size_t e2 = _other.BoundsCheck(_e2, _other.Size() + 1); // 1 to allow indexing of end + + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(s1 <= e1, "ZArrayAlgo::Equal - Cannot compare with e1 < s1!"); + ZSTL_ASSERT(s2 <= e2, "ZArrayAlgo::Equal - Cannot compare with e2 < s2!"); + #endif + + size_t i, j; + + for (i = s1, j = s2; i < e1 && j < e2; i++, j++) + if (!(_array.Data()[i] == _other.Data()[j])) + return false; + + return true; + } + + /* + public ZArrayAlgo::Equal + + Determines if the arrays are equal in both size and contents. + + @param _array - the array to check + @param _other - the array to check against + @return (bool) - true if equivalent, false otherwise + */ + template + bool Equal(const ZArray& _array, const ZArray& _other) + { + return _array.Equals(_other); + } + + /* + public ZArrayAlgo::Fill + + Fills a section of the array full of a given value. + + @param T - the type held by the array + @param A - the allocator type of the array + @param _array - the array to fill full of values + @param _value - the value to fill into the array + @param _start - the starting index + @param _end - the ending index (exclusive) + @return (void) + @assert - if _end < _start + if _start or _end out of bounds + */ + template + void Fill(ZArray& _array, const T& _value, size_t _start, size_t _end) + { + if (_start == _end) + return; + + const size_t start = _array.BoundsCheck(_start, _array.Size()); + const size_t end = _array.BoundsCheck(_end, _array.Size() + 1); // 1 to allow indexing of end + + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(start <= end, "ZArrayAlgo::Fill - Cannot fill with end < start!"); + #endif + + for (size_t i = start; i < end; i++) + _array.Data()[i] = _value; + } + + /* + public ZArrayAlgo::Fill + + Fills the array full of the given value. + + @param T - the type held by the array + @param A - the allocator type of the array + @param _array - the array to fill full of values + @param _value - the value to fill into the array + @return (void) + */ + template + void Fill(ZArray& _array, const T& _value) + { + Fill(_array, _value, 0, _array.Size()); + } + + /* + public ZArrayAlgo::Find + + Finds the Nth occurrence of a value in the provided region of the array. + + @param T - the type held by the array + @param A - the allocator type of the array + @param _array - the array to search + @param _value - the value to find + @param _count - the number of occurrences which should be skipped (meaning an index to the (N+1)th occurrence is returned) + @param _start - the starting index + @param _end - the ending index (exclusive) + @return (size_t) - index of the (N+1)th occurrence + @assert - if _end < _start + if _start or _end out of bounds + */ + template + size_t Find(const ZArray& _array, const T& _value, size_t _count, size_t _start, size_t _end) + { + if (_start == _end) + return ZSTL::InvalidPos; + + const size_t start = _array.BoundsCheck(_start, _array.Size()); + const size_t end = _array.BoundsCheck(_end, _array.Size() + 1); // 1 to allow indexing of end + + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(start <= end, "ZArrayAlgo::Find - Cannot find with end < start!"); + #endif + + size_t j = _count; + + for (size_t i = start; i < end; i++) + { + if(_array.Data()[i] == _value) + { + if (j == 0) + return i; + j--; + } + } + + return ZSTL::InvalidPos; + } + + /* + public ZArrayAlgo::Find + + Finds the Nth occurrence of a value in the array. + + @param T - the type held by the array + @param A - the allocator type of the array + @param _array - the array to search + @param _value - the value to find + @param _count - the number of occurrences which should be skipped (meaning an index to the (N+1)th occurrence is returned) + @return (size_t) - index of the (N+1)th occurrence + */ + template + size_t Find(const ZArray&_array, const T& _value, size_t _count) + { + return Find(_array, _value, _count, 0, _array.Size()); + } + + /* + public ZArrayAlgo::FindAll + + Finds all the things in the array of the provided value and returns their indices. + Note that this will return the indices in order of appearance in the searched array. + + @param _array - the list to search through + @param _value - the value to search for + @param _start - the starting index (inclusive) to search from + @param _end - the ending index (exclusive) to search from + @return (ZArray) - array of indices where values appeared (empty list of none found) + @assert - if _end < _start + if _start or _end out of bounds + */ + template + ZArray FindAll(const ZArray& _array, const T& _value, size_t _start, size_t _end) + { + ZArray locations(_array.Size() + 1); + + if (_start == _end) + return locations; + + const size_t start = _array.BoundsCheck(_start, _array.Size()); + const size_t end = _array.BoundsCheck(_end, _array.Size() + 1); // 1 to allow indexing of end + + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(start <= end, "ZArrayAlgo::Fill - Cannot fill with end < start!"); + #endif + + for (size_t i = start; i < end; i++) + { + if (_array.Data()[i] == _value) + locations.PushBack(i); + } + + return locations; + } + + /* + public ZArrayAlgo::FindAll + + Finds all the things in the array of the provided value and returns their indices. + Note that this will return the indices in order of appearance in the searched array. + + @param _array - the list to search through + @param _value - the value to search for + @return (ZArray) - array of indices where values appeared (empty list of none found) + */ + template + ZArray FindAll(const ZArray& _array, const T& _value) + { + return ZArrayAlgo::FindAll(_array, _value, 0, _array.Size()); + } + + /* + public ZArrayAlgo::FindAllOf + + Finds all the things in the given region of the array that are equal to one + of the provided values and returns their indices. Note that this will return + the indices in order of appearance in the searched array. + + @param _array - the list to search through + @param _value - the values to search for + @param _array - the array to compare + @param _s1 - the starting index to search + @param _e1 - the ending index to search (exclusive) + @param _other - the array to compare against + @param _s2 - the starting index to find + @param _e2 - the ending index to find (exclusive) + @return (ZArray) - array of indices where values appeared (empty of none found) + @assert - if _s1, _e1, _s2, or _e2 out of bounds + if _e1 < _s1 or _e2 < _s2 + */ + template + ZArray FindAllOf(const ZArray& _array, size_t _s1, size_t _e1, const ZArray& _values, size_t _s2, size_t _e2) + { + ZArray locations(_array.Size() + 1); + + if (_s1 == _e1 || _s2 == _e2) + return locations; + + const size_t s1 = _array.BoundsCheck(_s1, _array.Size()); + const size_t e1 = _array.BoundsCheck(_e1, _array.Size() + 1); // 1 to allow indexing of end + + const size_t s2 = _values.BoundsCheck(_s2, _values.Size()); + const size_t e2 = _values.BoundsCheck(_e2, _values.Size() + 1); // 1 to allow indexing of end + + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(s1 <= e1, "ZArrayAlgo::FindAllOf - Cannot find with e1 < s1!"); + ZSTL_ASSERT(s2 <= e2, "ZArrayAlgo::FindAllOf - Cannot find with e2 < s2!"); + #endif + + for (size_t i = s1; i < e1; i++) + { + for (size_t j = s2; j < e2; j++) + { + if ( _array.Data()[i] == _values.Data()[j] ) + { + locations.PushBack(i); + break; + } + } + } + + return locations; + } + + /* + public ZArrayAlgo::FindAllOf + + Finds all the things in the array that are equal to one of the provided values and returns their indices. + Note that this will return the indices in order of appearance in the searched array. + @param _array - the list to search through + @param _value - the values to search for + @return (ZArray) - array of indices where values appeared (empty of none found) + */ + template + ZArray FindAllOf(const ZArray& _array, const ZArray& _values) + { + return FindAllOf(_array, 0, _array.Size(), _values, 0, _values.Size()); + } + + /* + public ZArrayAlgo::FindIf + + Finds a value in the provided range of the array that evaluates a unary functor to true. + + @param F - unary functor [(const T&) -> bool] used to test array[i] + @param T - the type held by the array + @param A - the allocator type of the array + @param _array - the array to find elements in + @param _functor - instance of the unary functor F to test with + @param _end - the end index (exclusive) + @return (size_t) - the first instance that evaluates to true from _functor (ZSTL::InvalidPos if not found) + @assert - if _end < _start + if _start or _end out of bounds + */ + template + size_t FindIf(const ZArray& _array, F _functor, size_t _start, size_t _end) + { + if (_start == _end) + return 0; + + const size_t start = _array.BoundsCheck(_start, _array.Size()); + const size_t end = _array.BoundsCheck(_end, _array.Size() + 1); // 1 to allow indexing of end + + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(start <= end, "ZArrayAlgo::Find - Cannot find with end < start!"); + #endif + + for (size_t i = start; i < end; i++) + { + if (_functor(_array.Data()[i])) + return i; + } + + return ZSTL::InvalidPos; + } + + /* + public ZArrayAlgo::FindIf + + Finds a value in the array that evaluates a unary functor to true. + + @param F - unary functor [(const T&) -> bool] used to test array[i] + @param T - the type held by the array + @param A - the allocator type of the array + @param _array - the array to find elements in + @param _functor - instance of the unary functor F to test with + @return (size_t) - the first instance that evaluates to true from _functor (ZSTL::InvalidPos if not found) + */ + template + size_t FindIf(const ZArray& _array, F _functor) + { + return FindIf(_array, _functor, 0, _array.Size()); + } + + /* + public ZArrayAlgo::FindFirst + + Looks for the first occurrence of the value between the specified indices. + + @param T - the type held by the array + @param A - the allocator type of the array + @param _array - the array to find elements in + @param _value - the value to look for + @param _start - the index to start looking at + @param _end - the end index (exclusive) + @return (size_t) - the index of the first match (ZSTL::InvalidPos if not found) + @assert - if _end < _start + if _start or _end out of bounds + */ + template + size_t FindFirst(const ZArray& _array, const T& _value, size_t _start, size_t _end) + { + if (_start == _end) + return ZSTL::InvalidPos; + + const size_t start = _array.BoundsCheck(_start, _array.Size()); + const size_t end = _array.BoundsCheck(_end, _array.Size() + 1); + + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(start <= end, "ZArrayAlgo::FindFirstOf - Cannot find with end < start!"); + #endif + + for (size_t i = start; i < end; i++) + { + if (_array.Data()[i] == _value) + return i; + } + + return ZSTL::InvalidPos; + } + + /* + public ZArrayAlgo::FindFirst + + Looks for the first occurrence of the specified value in the given array. + + @param T - the type held by the array + @param A - the allocator type of the array + @param _array - the array to find elements in + @param _value - the value to look for + @return (size_t) - the index of the first match (ZSTL::InvalidPos if not found) + */ + template + size_t FindFirst(const ZArray& _array, const T& _value) + { + return FindFirst(_array, _value, 0, _array.Size()); + } + + /* + public ZArrayAlgo::FindFirstOf + + Looks for the first occurrence of one of the given values between the specified indices. + + @param T - the type held by the array + @param A - the allocator type of the array + @param B - the allocator type for the values array + @param _array - the array to find elements in + @param _s1 - the starting index in array + @param _e1 - the ending index in array (exclusive) + @param _values - the values to look for + @param _s2 - the starting index in values + @param _e2 - the ending index in values (exclusive) + @return (size_t) - the index of the first match (ZSTL::InvalidPos if not found) + @assert - if _s1, _e1, _s2, or _e2 out of bounds + if _e1 < _s1 or _e2 < _s2 + */ + template + size_t FindFirstOf(const ZArray& _array, size_t _s1, size_t _e1, const ZArray& _values, size_t _s2, size_t _e2) + { + if (_s1 == _e1 || _s2 == _e2) + return ZSTL::InvalidPos; + + const size_t s1 = _array.BoundsCheck(_s1, _array.Size()); + const size_t e1 = _array.BoundsCheck(_e1, _array.Size() + 1); // 1 to allow indexing of end + + const size_t s2 = _values.BoundsCheck(_s2, _values.Size()); + const size_t e2 = _values.BoundsCheck(_e2, _values.Size() + 1); // 1 to allow indexing of end + + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(s1 <= e1, "ZArrayAlgo::FindFirstOf - Cannot find with e1 < s1!"); + ZSTL_ASSERT(s2 <= e2, "ZArrayAlgo::FindFirstOf - Cannot find with e2 < s2!"); + #endif + + for (size_t i = s1; i < e1; i++) + { + for (size_t j = s2; j < e2; j++) + { + if ( _array.Data()[i] == _values.Data()[j] ) + return i; + } + } + + return ZSTL::InvalidPos; + } + + /* + public ZArrayAlgo::FindFirstOf + + Looks for the first occurrence of one of the specified values in the given array. + + @param T - the type held by the array + @param A - the allocator type of the array + @param B - the allocator type for the values array + @param _array - the array to find elements in + @param _values - the values to look for + @return (size_t) - the index of the first match (ZSTL::InvalidPos if not found) + */ + template + size_t FindFirstOf(const ZArray& _array, const ZArray& _values) + { + return FindFirstOf(_array, 0, _array.Size(), _values, 0, _values.Size()); + } + + /* + public ZArrayAlgo::FindFirstNot + + Looks for the first occurrence of a value that is not the provided value between the specified + indices. + + @param T - the type held by the array + @param A - the allocator type of the array + @param _array - the array to find elements in + @param _value - the value to avoid + @param _start - the index to start looking at + @param _end - the end index (exclusive) + @return (size_t) - the index of the first non-match (ZSTL::InvalidPos if not found) + @assert - if _end < _start + if _start or _end out of bounds + */ + template + size_t FindFirstNot(const ZArray& _array, const T& _value, size_t _start, size_t _end) + { + if (_start == _end) + return ZSTL::InvalidPos; + + const size_t start = _array.BoundsCheck(_start, _array.Size()); + const size_t end = _array.BoundsCheck(_end, _array.Size() + 1); // 1 to allow indexing of end + + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(start <= end, "ZArrayAlgo::FindFirstNot - Cannot find with end < start!"); + #endif + + for (size_t i = start; i < end; i++) + { + if (!(_array.Data()[i] == _value)) + return i; + } + + return ZSTL::InvalidPos; + } + + /* + public ZArrayAlgo::FindFirstNot + + Looks for the first occurrence of a value that is not the provided value in the given array. + + @param T - the type held by the array + @param A - the allocator type of the array + @param _array - the array to find elements in + @param _value - the value to avoid + @return (size_t) - the index of the first non-match (ZSTL::InvalidPos if not found) + */ + template + size_t FindFirstNot(const ZArray& _array, const T& _value) + { + return FindFirstNot(_array, _value, 0, _array.Size()); + } + + /* + public ZArrayAlgo::FindFirstNotOf + + Looks for the first occurrence of a value that is not one of the provided values between the + specified indices. + + @param T - the type held by the array + @param A - the allocator type of the array + @param B - the allocator type for the values array + @param _array - the array to find elements in + @param _s1 - the starting index in array + @param _e1 - the ending index in array (exclusive) + @param _values - the values to avoid + @param _s2 - the starting index in values + @param _e2 - the ending index in values (exclusive) + @return (size_t) - the index of the first non-match (ZSTL::InvalidPos if not found) + @assert - if _s1, _e1, _s2, or _e2 out of bounds + if _e1 < _s1 or _e2 < _s2 + */ + template + size_t FindFirstNotOf(const ZArray& _array, size_t _s1, size_t _e1, const ZArray& _values, size_t _s2, size_t _e2) + { + if (_s1 == _e1 || _s2 == _e2) + return ZSTL::InvalidPos; + + const size_t s1 = _array.BoundsCheck(_s1, _array.Size()); + const size_t e1 = _array.BoundsCheck(_e1, _array.Size() + 1); // 1 to allow indexing of end + + const size_t s2 = _values.BoundsCheck(_s2, _values.Size()); + const size_t e2 = _values.BoundsCheck(_e2, _values.Size() + 1); // 1 to allow indexing of end + + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(s1 <= e1, "ZArrayAlgo::FindFirstNotOf - Cannot find with e1 < s1!"); + ZSTL_ASSERT(s2 <= e2, "ZArrayAlgo::FindFirstNotOf - Cannot find with e2 < s2!"); + #endif + + for (size_t i = s1; i < e1; i++) + { + for (size_t j = s2; j < e2; j++) + { + if ( _array.Data()[i] == _values.Data()[j] ) + break; + + if (j == e2 - 1) + return i; + } + } + + return ZSTL::InvalidPos; + } + + /* + public ZArrayAlgo::FindFirstNotOf + + Looks for the first occurrence of a value that is not one of the provided values in the given array. + + @param T - the type held by the array + @param A - the allocator type of the array + @param B - the allocator type for the values array + @param _array - the array to find elements in + @param _values - the values to avoid + @return (size_t) - the index of the first non-match (ZSTL::InvalidPos if not found) + */ + template + size_t FindFirstNotOf(const ZArray& _array, const ZArray& _values) + { + return FindFirstNotOf(_array, 0, _array.Size(), _values, 0, _values.Size()); + } + + /* + public ZArrayAlgo::FindLast + + Finds the last occurrence of the specified value in the array between the given + indices. + + @param T - the type held by the array + @param A - the allocator type of the array + @param _array - the array to find elements in + @param _value - the value to find + @param _start - the index to start looking at + @param _end - the end index (exclusive) + @return (size_t) - the final occurrence of _value in the array (ZSTL::InvalidPos if not found) + @assert - if _end < _start + if _start or _end out of bounds + */ + template + size_t FindLast(const ZArray& _array, const T& _value, size_t _start, size_t _end) + { + if (_start == _end) + return ZSTL::InvalidPos; + + const size_t start = _array.BoundsCheck(_start, _array.Size()); + const size_t end = _array.BoundsCheck(_end, _array.Size() + 1); // 1 to allow indexing of end + + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(start <= end, "ZArrayAlgo::FindLast - Cannot find with end < start!"); + #endif + + for (size_t i = end; i > start; i--) + { + if (_array.Data()[i - 1] == _value) + return i - 1; + } + + return ZSTL::InvalidPos; + } + + /* + public ZArrayAlgo::FindLast + + Finds the last occurrence of the specified value in the array. + + @param T - the type held by the array + @param A - the allocator type of the array + @param _array - the array to find elements in + @param _value - the value to find + @return (size_t) - the final occurrence of _value in the array (ZSTL::InvalidPos if not found) + */ + template + size_t FindLast(const ZArray& _array, const T& _value) + { + return FindLast(_array, _value, 0, _array.Size()); + } + + /* + public ZArrayAlgo::FindLastOf + + Finds the last occurrence of one of the specified values in the array between the given + indices. + + @param T - the type held by the array + @param A - the allocator type of the array + @param B - the allocator type for the values array + @param _array - the array to find elements in + @param _s1 - the starting index in array + @param _e1 - the ending index in array (exclusive) + @param _values - the values to look for + @param _s2 - the starting index in values + @param _e2 - the ending index in values (exclusive) + @return (size_t) - the index of the last match (ZSTL::InvalidPos if not found) + @assert - if _s1, _e1, _s2, or _e2 out of bounds + if _e1 < _s1 or _e2 < _s2 + */ + template + size_t FindLastOf(const ZArray& _array, size_t _s1, size_t _e1, const ZArray& _values, size_t _s2, size_t _e2) + { + if (_s1 == _e1 || _s2 == _e2) + return ZSTL::InvalidPos; + + const size_t s1 = _array.BoundsCheck(_s1, _array.Size()); + const size_t e1 = _array.BoundsCheck(_e1, _array.Size() + 1); // 1 to allow indexing of end + + const size_t s2 = _values.BoundsCheck(_s2, _values.Size()); + const size_t e2 = _values.BoundsCheck(_e2, _values.Size() + 1); // 1 to allow indexing of end + + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(s1 <= e1, "ZArrayAlgo::FindFirstNotOf - Cannot find with e1 < s1!"); + ZSTL_ASSERT(s2 <= e2, "ZArrayAlgo::FindFirstNotOf - Cannot find with e2 < s2!"); + #endif + + for (size_t i = e1; i > s1; i--) + { + for (size_t j = s2; j < e2; j++) + { + if (_array.Data()[i - 1] == _values.Data()[j]) + return i - 1; + } + } + + return ZSTL::InvalidPos; + } + + /* + public ZArrayAlgo::FindLastOf + + Finds the last occurrence of one of the specified values in the array. + + @param T - the type held by the array + @param A - the allocator type of the array + @param B - the allocator type for the values array + @param _array - the array to find elements in + @param _value - the value to find + @return (size_t) - the final occurrence of _value in the array (ZSTL::InvalidPos if not found) + */ + template + size_t FindLastOf(const ZArray& _array, const ZArray& _values) + { + return FindLastOf(_array, 0, _array.Size(), _values, 0, _values.Size()); + } + + /* + public ZArrayAlgo::FindLastNot + + Finds the last occurrence of a value that is not the specified value in the array. between the given + indices. + + @param T - the type held by the array + @param A - the allocator type of the array + @param _array - the array to find elements in + @param _value - the value to avoid + @param _start - the index to start looking at + @param _end - the end index (exclusive) + @return (size_t) - the final occurrence of a non-match in the array (ZSTL::InvalidPos if not found) + @assert - if _end < _start + if _start or _end out of bounds + */ + template + size_t FindLastNot(const ZArray& _array, const T& _value, size_t _start, size_t _end) + { + if (_start == _end) + return ZSTL::InvalidPos; + + const size_t start = _array.BoundsCheck(_start, _array.Size()); + const size_t end = _array.BoundsCheck(_end, _array.Size() + 1); // 1 to allow indexing of end + + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(start <= end, "ZArrayAlgo::FindLastNotOf - Cannot find with end < start!"); + #endif + + for (size_t i = end; i > start; i--) + { + if (!(_array.Data()[i - 1] == _value)) + return i - 1; + } + + return ZSTL::InvalidPos; + } + + /* + public ZArrayAlgo::FindLastNot + + Finds the last occurrence of a value that is not the specified value in the array. + + @param T - the type held by the array + @param A - the allocator type of the array + @param _array - the array to find elements in + @param _value - the value to avoid + @return (size_t) - the final occurrence of a non-match in the array (ZSTL::InvalidPos if not found) + */ + template + size_t FindLastNot(const ZArray& _array, const T& _value) + { + return FindLastNot(_array, _value, 0, _array.Size()); + } + + /* + public ZArrayAlgo::FindLastNotOf + + Finds the last occurrence of a value that is not one of the specified values in the array between + the given indices. + + @param T - the type held by the array + @param A - the allocator type of the array + @param B - the allocator type for the values array + @param _array - the array to find elements in + @param _s1 - the starting index in array + @param _e1 - the ending index in array (exclusive) + @param _values - the values to avoid + @param _s2 - the starting index in values + @param _e2 - the ending index in values (exclusive) + @return (size_t) - the index of the last non0match (ZSTL::InvalidPos if not found) + @assert - if _s1, _e1, _s2, or _e2 out of bounds + if _e1 < _s1 or _e2 < _s2 + */ + template + size_t FindLastNotOf(const ZArray& _array, size_t _s1, size_t _e1, const ZArray& _values, size_t _s2, size_t _e2) + { + if (_s1 == _e1 || _s2 == _e2) + return ZSTL::InvalidPos; + + const size_t s1 = _array.BoundsCheck(_s1, _array.Size()); + const size_t e1 = _array.BoundsCheck(_e1, _array.Size() + 1); // 1 to allow indexing of end + + const size_t s2 = _values.BoundsCheck(_s2, _values.Size()); + const size_t e2 = _values.BoundsCheck(_e2, _values.Size() + 1); // 1 to allow indexing of end + + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(s1 <= e1, "ZArrayAlgo::FindFirstNotOf - Cannot find with e1 < s1!"); + ZSTL_ASSERT(s2 <= e2, "ZArrayAlgo::FindFirstNotOf - Cannot find with e2 < s2!"); + #endif + + for (size_t i = e1; i > s1; i--) + { + for (size_t j = s2; j < e2; j++) + { + if (_array.Data()[i - 1] == _values.Data()[j]) + break; + + if (j == e2 - 1) + return i - 1; + } + } + + return ZSTL::InvalidPos; + } + + /* + public ZArrayAlgo::FindLastNotOf + + Finds the last occurrence of a value that is not one of the specified values in the array. + + @param T - the type held by the array + @param A - the allocator type of the array + @param B - the allocator type of the values array + @param _array - the array to find elements in + @param _values - the values to avoid + @return (size_t) - the final occurrence of a non-match in the array (ZSTL::InvalidPos if not found) + */ + template + size_t FindLastNotOf(const ZArray& _array, const ZArray& _values) + { + return FindLastNotOf(_array, 0, _array.Size(), _values, 0, _values.Size()); + } + + /* + public ZArrayAlgo::FindSub + + Looks for the first occurrence of a sub array within the given array in the given region. + + @param T - the type held by the array + @param A - the allocator type of the array + @param B - the allocator type of the other array + @param _array - the array to search in + @param _s1 - the starting index in _array + @param _e1 - the ending index in _array (exclusive) + @param _other - the values to search for + @param _s2 - the starting index in _other + @param _e2 - the ending index in _other (exclusive) + @return (size_t) - index to the first occurrence of the sub array + @assert - if _s1, _e1, _s2, or _e2 out of bounds + if _e1 < _s1 or _e2 < _s2 + */ + template + size_t FindSub(const ZArray& _array, size_t _s1, size_t _e1, const ZArray& _other, size_t _s2, size_t _e2) + { + if (_s1 == _e1 || _s2 == _e2) + return ZSTL::InvalidPos; + + const size_t s1 = _array.BoundsCheck(_s1, _array.Size()); + const size_t e1 = _array.BoundsCheck(_e1, _array.Size() + 1); // 1 to allow indexing of end + + const size_t s2 = _other.BoundsCheck(_s2, _other.Size()); + const size_t e2 = _other.BoundsCheck(_e2, _other.Size() + 1); // 1 to allow indexing of end + + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(s1 <= e1, "ZArrayAlgo::FindSub - Cannot compare with e1 < s1!"); + ZSTL_ASSERT(s2 <= e2, "ZArrayAlgo::FindSub - Cannot compare with e2 < s2!"); + #endif + + // easy case: subarray is empty + if (_other.Empty()) + return ZSTL::InvalidPos; + + // easy case: subarray can't fit into array + if ( _array.Size() <= e2 - s2) + return ZSTL::InvalidPos; + + // easy case: subarray can't fit into region of array + if ( e1 - s1 < e2 - s2) + return ZSTL::InvalidPos; + + for (size_t i = s1; i <= e1 - (e2 - s2); i++) + { + if (_array.Data()[i] == _other.Data()[s2]) + { + // short-circuit if matching just one thing + if (e2 - s2 == 1) + return i; + + size_t arrayOffset = i + 1; + // matched first element, so now try the ccccombo + for (size_t j = s2 + 1; j < e2; j++) + { + if (_array.Data()[arrayOffset] != _other.Data()[j]) + break; + + if ((arrayOffset+1) - i == e2 - s2) + return i; + arrayOffset++; // won't overrun due to (_array.Size() <= e2-s2) constraint + } + } + } + + return ZSTL::InvalidPos; + } + + /* + public ZArrayAlgo::FindSub + + Looks for the first occurrence of a sub array within the given array. + + @param T - the type held by the array + @param A - the allocator type of the array + @param B - the allocator type of the other array + @param _array - the array to look in + @param _other - the sub array to look for + @return (size_t) - index to the first occurrence of the sub array + */ + template + size_t FindSub(const ZArray& _array, const ZArray& _other) + { + return FindSub(_array, 0, _array.Size(), _other, 0, _other.Size()); + } + + /* + public ZArrayAlgo::FoldLeft + + Executes an iterative fold left on the provided array in the given region. + + Given an initial value V, an array region containing [ 1, 2, 3, 4 ] and a functor that emulates the + + operation, fold left produces the following result: + + FoldLeft( [ 1, 2, 3, 4 ], (+), V ) -> ( ( (V + 1) + 2 ) + 3 ) + 4 + + @param F - binary functor [(const T&, const T&) -> T] for the fold operation + @param V - the initial value type and accumulated type + @param T - the type held by the array + @param A - the allocator type of the array + @param _array - the array to accumulate on + @param _functor - instance of the binary functor F to test with + @param _initialValue - the initial value for the fold operation + @param _start - the starting index + @param _end - the ending index (exclusive) + @return (V) - the accumulated value + @assert - if _end < _start + if _start or _end out of bounds + */ + template + V FoldLeft(const ZArray& _array, F _functor, V _initialValue, size_t _start, size_t _end ) + { + if (_start == _end) + return _initialValue; + + const size_t start = _array.BoundsCheck(_start, _array.Size()); + const size_t end = _array.BoundsCheck(_end, _array.Size() + 1); // 1 to allow indexing of end + + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(start <= end, "ZArrayAlgo::FoldLeft - Cannot fold with end < start!"); + #endif + + for (size_t i = start; i < end; i++) + _initialValue = _functor(_initialValue, _array.Data()[i]); + + return _initialValue; + } + + /* + public ZArrayAlgo::FoldLeft + + Executes an iterative fold left on the provided array. + + Given an initial value V, an array containing [ 1, 2, 3, 4 ] and a functor that emulates the + + operation, fold left produces the following result: + + FoldLeft( [ 1, 2, 3, 4 ], (+), V ) -> ( ( (V + 1) + 2 ) + 3 ) + 4 + + @param F - binary functor [(const T&, const T&) -> T] used for the fold operation + @param V - the initial value type and accumulated type + @param T - the type held by the array + @param A - the allocator type of the array + @param _array - the array to accumulate on + @param _functor - instance of the binary functor F to test with + @param _initialValue - the initial value for the fold operation + @return (V) - the accumulated value + */ + template + V FoldLeft(const ZArray& _array, F _functor, V _initialValue) + { + return FoldLeft(_array, _functor, _initialValue, 0, _array.Size()); + } + + /* + public ZArrayAlgo::FoldRight + + Executes an iterative fold right on the provided array in the given region. + + Given an initial value V, an array region containing [ 1, 2, 3, 4 ] and a functor that emulates the + + operation, fold right produces the following result: + + FoldRight( [ 1, 2, 3, 4 ], (+), V ) -> 1 + ( 2 + ( 3 + ( 4 + V ) ) ) + + @param F - binary functor [(const T&, const T&) -> T] for the fold operation + @param V - the initial value type and accumulated type + @param T - the type held by the array + @param A - the allocator type of the array + @param _array - the array to accumulate on + @param _functor - instance of the binary functor F to test with + @param _initialValue - the initial value for the fold operation + @param _start - the starting index + @param _end - the ending index (exclusive) + @return (V) - the accumulated value + @assert - if _end < _start + if _start or _end out of bounds + */ + template + V FoldRight(const ZArray& _array, F _functor, V _initialValue, size_t _start, size_t _end ) + { + if (_start == _end) + return _initialValue; + + const size_t start = _array.BoundsCheck(_start, _array.Size()); + const size_t end = _array.BoundsCheck(_end, _array.Size() + 1); // 1 to allow indexing of end + + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(start <= end, "ZArrayAlgo::FoldLeft - Cannot fold with end < start!"); + #endif + + for (size_t i = end; i > start; i--) + _initialValue = _functor(_array.Data()[i - 1], _initialValue); + + return _initialValue; + } + + /* + public ZArrayAlgo::FoldRight + + Executes an iterative fold right on the provided array. + + Given an initial value V, an array containing [ 1, 2, 3, 4 ] and a functor that emulates the + + operation, fold right produces the following result: + + FoldRight( [ 1, 2, 3, 4 ], (+), V ) -> 1 + ( 2 + ( 3 + ( 4 + V ) ) ) + + @param F - binary functor [(const T&, const T&) -> T] used for the fold operation + the first argument is the value at the current point in the array + the second argument is the current accumulated value + @param V - the initial value type and accumulated type + @param T - the type held by the array + @param A - the allocator type of the array + @param _array - the array to accumulate on + @param _functor - instance of the binary functor F to test with + @param _initialValue - the initial value for the fold operation + @return (V) - the accumulated value + */ + template + V FoldRight(const ZArray& _array, F _functor, V _initialValue) + { + return FoldRight(_array, _functor, _initialValue, 0, _array.Size()); + } + + /* + public ZArrayAlgo::Generate + + Fills the given region of the array with values generated from the provided generator functor. + + @param F - binary functor [(size_t, size_t) -> T] used to generate + the first argument is the current number in the generated sequence + the second argument is the number of generations remaining + @param T - the type held by the array + @param A - the allocator type of the array + @param _array - the array to generate values for + @param _functor - instance of the binary functor GF to generate values with + @param _start - the starting index + @param _end - the ending index (exclusive) + @return (void) + @assert - if _end < _start + if _start or _end out of bounds + */ + template + void Generate(ZArray& _array, GF _generator, size_t _start, size_t _end) + { + if (_start == _end) + return; + + const size_t start = _array.BoundsCheck(_start, _array.Size()); + const size_t end = _array.BoundsCheck(_end, _array.Size() + 1); // 1 to allow indexing of end + + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(start <= end, "ZArrayAlgo::FindLastNotOf - Cannot find with end < start!"); + #endif + + for (size_t i = start; i < end; i++) + _array.Data()[i] = _generator( i - start, end - start); + } + + /* + public ZArrayAlgo::Generate + + Fills the array with values generated from the provided generator functor. + + @param F - binary functor [(size_t, size_t) -> T] used to generate + the first argument is the current number in the generated sequence + the second argument is the number of generations remaining + @param T - the type held by the array + @param A - the allocator type of the array + @param _array - the array to generate values for + @param _functor - instance of the binary functor GF to generate values with + @return (void) + */ + template + void Generate(ZArray& _array, GF _generator) + { + ZArrayAlgo::Generate( _array, _generator, 0, _array.Size()); + } + + /* + public ZArrayAlgo::Map + + Maps the provided functor over the array between the given indices, returning a + transformed array and leaving the original array intact. + + @param F - the unary functor ([T&] -> void) to transform the array with + @param T - the type held by the array + @param A - the allocator type of the array + @param _array - the array to transform + @param _functor - instance of the unary functor F to operate on + @param _start - the starting index + @param _end - the ending index (exclusive) + @return (ZArray) the transformed array + @assert - if _end < _start + if _start or _end out of bounds + */ + template + ZArray Map(const ZArray& _array, F _functor, size_t _start, size_t _end) + { + const size_t start = _array.BoundsCheck(_start, _array.Size()); + const size_t end = _array.BoundsCheck(_end, _array.Size() + 1); // 1 to allow indexing of end + + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(start <= end, "ZArrayAlgo::Map - Cannot transform with end < start!"); + #endif + + ZArray ret(&_array.Data()[start], end - start); + + for (size_t i = 0; i < end - start ; i++) + _functor(ret.Data()[i]); + + return ret; + } + + /* + public ZArrayAlgo::Map + + Maps the provided functor over the array, returning a transformed array and leaving the + original array intact. + + @param F - the unary functor ([T&] -> void) to transform the array with + @param T - the type held by the array + @param A - the allocator type of the array + @param _array - the array to transform + @param _functor - instance of the unary functor F to operate on + @return (ZArray) the transformed array + */ + template + ZArray Map(const ZArray& _array, F _functor) + { + return Map(_array, _functor, 0, _array.Size()); + } + + /* + public ZArrayAlgo::Max + + Function to find the index of the first instance of the max value of an array. + + @param _array - the array to find the max of + @param _comparator - the comparator to use when determining maximum + @param _start - the starting index (inclusive) to begin searching for the maximum from + @param _end - the ending index (exclusive) for the search + @return (size_t) - the index of the maximum value + */ + template + size_t Max(const ZArray& _array, CF _comparator, size_t _start, size_t _end) + { + if (_start == _end) + return ZSTL::InvalidPos; + + const size_t start = _array.BoundsCheck(_start, _array.Size()); + const size_t end = _array.BoundsCheck(_end, _array.Size() + 1); // 1 to allow indexing of end + + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(start <= end, "ZArrayAlgo::Max - Cannot remove with end < start!"); + ZSTL_ASSERT(_array.Empty() == false, "ZArrayAlgo::Max - Cannot find min of empty array!\n"); + #endif + + size_t maxIndex = start; + for (size_t i = start; i < end; i++) + { + if ( _comparator( _array[maxIndex], _array[i]) < 0) + maxIndex = i; + } + + return maxIndex; + } + + /* + public ZArrayAlgo::Max + + Function to find the index of the first instance of the max value of an array. + + @param _array - the array to find the max of + @return (size_t) - the index of the maximum value + */ + template + size_t Max(const ZArray& _array) + { + return Max(_array, ZComparator(), 0, _array.Size()); + } + + /* + public ZArrayAlgo::Max + + Function to find the index of the first instance of the max value of an array. + + @param _array - the array to find the max of + @param _comparator - the comparator to use when determining maximum + @return (size_t) - the index of the maximum value + */ + template + size_t Max(const ZArray& _array, CF _comparator) + { + return Max(_array, _comparator, 0, _array.Size()); + } + + /* + public ZArrayAlgo::Max + + Function to find the index of the first instance of the max value of an array. + + @param _array - the array to find the max of + @param _start - the starting index (inclusive) to begin searching for the maximum from + @param _end - the ending index (exclusive) for the search + @return (size_t) - the index of the maximum value + */ + template + size_t Max(const ZArray& _array, size_t _start, size_t _end) + { + return Max(_array, ZComparator(), _start, _end); + } + + /* + public ZArrayAlgo::Min + + Function to find the index of the first instance of the min value of an array. + + @param _array - the array to find the min of + @param _comparator - the comparator to use when determining minimum + @param _start - the starting index (inclusive) to begin searching for the minimum from + @param _end - the ending index (exclusive) for the search + @return (size_t) - the index of the minimum value + */ + template + size_t Min(const ZArray& _array, CF _comparator, size_t _start, size_t _end) + { + if (_start == _end) + return ZSTL::InvalidPos; + + const size_t start = _array.BoundsCheck(_start, _array.Size()); + const size_t end = _array.BoundsCheck(_end, _array.Size() + 1); // 1 to allow indexing of end + + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(start <= end, "ZArrayAlgo::Min - Cannot remove with end < start!"); + ZSTL_ASSERT(_array.Empty() == false, "ZArrayAlgo::Min - Cannot find min of empty array!\n"); + #endif + + size_t maxIndex = start; + for (size_t i = start; i < end; i++) + { + if ( _comparator( _array[maxIndex], _array[i]) > 0) + maxIndex = i; + } + + return maxIndex; + } + + /* + public ZArrayAlgo::Min + + Function to find the index of the first instance of the min value of an array. + + @param _array - the array to find the min of + @return (size_t) - the index of the minimum value + */ + template + size_t Min(const ZArray& _array) + { + return Min(_array, ZComparator(), 0, _array.Size()); + } + + /* + public ZArrayAlgo::Min + + Function to find the index of the first instance of the min value of an array. + + @param _array - the array to find the min of + @param _comparator - the comparator to use when determining minimum + @return (size_t) - the index of the minimum value + */ + template + size_t Min(const ZArray& _array, CF _comparator) + { + return Min(_array, _comparator, 0, _array.Size()); + } + + /* + public ZArrayAlgo::Min + + Function to find the index of the first instance of the min value of an array. + + @param _array - the array to find the min of + @param _start - the starting index (inclusive) to begin searching for the minimum from + @param _end - the ending index (exclusive) for the search + @return (size_t) - the index of the minimum value + */ + template + size_t Min(const ZArray& _array, size_t _start, size_t _end) + { + return Min(_array, ZComparator(), _start, _end); + } + + /* + public ZArrayUtil::Remove + + Removes the first occurrence of the given element in the given range. + + @param T - the type held by the array + @param A - the allocator type of the array + @param _array - the array to remove elements from + @param _value - the value to remove + @param _start - the index to start at + @param _end - the ending index (exclusive) + @return (size_t) - the index at which the first occurrence was removed from, ZSTL::InvalidPos if no occurrence + @assert - if _end < _start + if _start or _end out of bounds + */ + template + size_t Remove(ZArray& _array, const T& _value, size_t _start, size_t _end) + { + if (_start == _end) + return ZSTL::InvalidPos; + + const size_t start = _array.BoundsCheck(_start, _array.Size()); + const size_t end = _array.BoundsCheck(_end, _array.Size() + 1); // 1 to allow indexing of end + + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(start <= end, "ZArrayAlgo::Remove - Cannot remove with end < start!"); + #endif + + for (size_t i = start; i < end; i++) + { + if (_array.Data()[i] == _value) + { + _array.Erase(i); + return i; + } + } + + return ZSTL::InvalidPos; + } + + /* + public ZArrayUtil::Remove + + Removes the first occurrence of the given element in the array. + + @param T - the type held by the array + @param A - the allocator type of the array + @param _array - the array to remove elements from + @param _element - the element to remove + @return (size_t) - the index at which the first occurrence was removed from, ZSTL::InvalidPos if no occurrence + */ + template + size_t Remove(ZArray& _array, const T& _element) + { + return Remove(_array, _element, 0, _array.Size()); + } + + /* + public ZArrayUtil::RemoveAll + + Removes all occurrences of the given element in the given range. + + @param T - the type held by the array + @param A - the allocator type of the array + @param _array - the array to remove elements from + @param _value - the value to remove + @param _start - the index to start at + @param _end - the ending index (exclusive) + @return (size_t) - number of occurrences removed + @assert - if _end < _start + if _start or _end out of bounds + */ + template + size_t RemoveAll(ZArray& _array, const T& _value, size_t _start, size_t _end) + { + if (_start == _end) + return 0; + + size_t count = 0; + + const size_t start = _array.BoundsCheck(_start, _array.Size()); + const size_t end = _array.BoundsCheck(_end, _array.Size() + 1); // 1 to allow indexing of end + + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(start <= end, "ZArrayAlgo::RemoveAll - Cannot remove with end < start!"); + #endif + + for (size_t i = end; i > start; i--) + { + if (_array.Data()[i - 1] == _value) + { + _array.Erase(i - 1); + count++; + } + } + + return count; + } + + /* + public ZArrayUtil::RemoveAll + + Removes all occurrences of the given element from the array. + + @param T - the type held by the array + @param A - the allocator type of the array + @param _array - the array to remove elements from + @param _value - the value to remove + @return (size_t) - number of occurrences removed + */ + template + size_t RemoveAll(ZArray& _array, const T& _value) + { + return RemoveAll(_array, _value, 0, _array.Size()); + } + + /* + public ZArrayAlgo::RemoveIf + + Removes elements from the array in the given range when the provided unary functor evaluates + to true. + + @param F - unary functor ([const T&] -> bool) used to test elements + @param T - the type held by the array + @param A - the allocator type of the array + @param _array - the array to remove elements from + @param _functor - functor instance of F used to evaluate elements + @param _start - the index to start at + @param _end - the ending index (exclusive) + @return (size_t) - the number of elements removed + @assert - if _end < _start + if _start or _end out of bounds + */ + template + size_t RemoveIf(ZArray& _array, F _functor, size_t _start, size_t _end) + { + if (_start == _end) + return 0; + + size_t count = 0; + + const size_t start = _array.BoundsCheck(_start, _array.Size()); + const size_t end = _array.BoundsCheck(_end, _array.Size() + 1); // 1 to allow indexing of end + + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(start <= end, "ZArrayAlgo::RemoveIf - Cannot remove with end < start!"); + #endif + + size_t toCheck = end - start; + size_t i = end-1; + while (toCheck > 0) + { + if (_functor(_array.Data()[i])) + { + _array.Erase(i); + count++; + } + i--; + toCheck--; + } + + return count; + } + + /* + public ZArrayAlgo::RemoveIf + + Removes elements from the array when the provided unary functor evaluates + to true. + + @param F - unary functor ([const T&] -> bool) used to test elements + @param T - the type held by the array + @param A - the allocator type of the array + @param _array - the array to remove elements from + @param _functor - functor instance of F used to evaluate elements + @return (size_t) - the number of elements removed + */ + template + size_t RemoveIf(ZArray& _array, F _functor) + { + return RemoveIf(_array, _functor, 0, _array.Size()); + } + + /* + public ZArrayAlgo::RemoveUpTo + + Removes up to the provided number of occurrences of a value from the array in + the specified range. + + @param T - the type held by the array + @param A - the allocator type of the array + @param _array - the array to remove elements from + @param _value - the value to look for + @param _count - the maximum number of times to remove the value + @param _start - the index to start at + @param _end - the ending index (exclusive) + @return (size_t) - the number of occurrences removed + @assert - if _end < _start + if _start or _end out of bounds + */ + template + size_t RemoveUpTo(ZArray& _array, const T& _value, size_t _count, size_t _start, size_t _end) + { + if (_start == _end) + return 0; + + size_t count = 0; + + const size_t start = _array.BoundsCheck(_start, _array.Size()); + const size_t end = _array.BoundsCheck(_end, _array.Size() + 1); // 1 to allow indexing of end + + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(start <= end, "ZArrayAlgo::RemoveUpTo - Cannot remove with end < start!"); + #endif + + for (size_t i = end - 1; i < end && i >= start&& count < _count; i--) + { + if (_array.Data()[i] == _value) + { + _array.Erase(i); + count++; + } + } + + return count; + } + + /* + public ZArrayAlgo::RemoveUpTo + + Removes up to the provided number of occurrences of a value from the array. + + @param T - the type held by the array + @param A - the allocator type of the array + @param _array - the array to remove elements from + @param _value - the value to look for + @param _count - the maximum number of times to remove the value + @return (size_t) - the number of occurrences removed + */ + template + size_t RemoveUpTo(ZArray& _array, const T& _value, size_t _count) + { + return RemoveUpTo(_array, _value, _count, 0, _array.Size()); + } + + /* + public ZArrayAlgo::Replace + + Finds and replaces all occurrences of the provided element with another in the given region. + + @param T - the type held by the array + @param A - the allocator type of the array + @param _array - the array to replace values in + @param _value - the value to look for + @param _newValue - the value to replace with + @param _start - the starting index + @param _end - the ending index (exclusive) + @return (size_t) - the number of values replaced + @assert - if _end < _start + if _start or _end out of bounds + */ + template + size_t Replace(ZArray& _array, const T& _value, const T& _newValue, size_t _start, size_t _end) + { + if (_start == _end) + return 0; + + size_t count = 0; + + const size_t start = _array.BoundsCheck(_start, _array.Size()); + const size_t end = _array.BoundsCheck(_end, _array.Size() + 1); // 1 to allow indexing of end + + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(start <= end, "ZArrayAlgo::Replace - Cannot replace with end < start!"); + #endif + + for (size_t i = start; i < end; i++) + { + if (_array.Data()[i] == _value) + { + _array.Data()[i] = _newValue; + count++; + } + } + + return count; + } + + /* + public ZArrayAlgo::Replace + + Finds and replaces all occurrences of the provided element with another. + + @param T - the type held by the array + @param A - the allocator type of the array + @param _array - the array to replace values in + @param _value - the value to look for + @param _newValue - the value to replace with + @return (size_t) - the number of values replaced + */ + template + size_t Replace(ZArray& _array, const T& _value, const T& _newValue) + { + return Replace(_array, _value, _newValue, 0, _array.Size()); + } + + /* + public ZArrayAlgo::ReplaceIf + + Replaces values in the array when the provided unary functor evaluates to true within + the given range. + + @param F - unary functor ([const &] -> bool) to use to evaluate elements + @param T - the type held by the array + @param A - the allocator type of the array + @param _array - the array to replace elements in + @param _functor - instance of unary functor F to use + @param _newValue - the value to replace with + @param _start - the starting index + @param _end - the ending index (exclusive) + @return (size_t) - the number of replaced elements + @assert - if _end < _start + if _start or _end out of bounds + */ + template + size_t ReplaceIf(ZArray& _array, F _functor, const T& _newValue, size_t _start, size_t _end) + { + if (_start == _end) + return 0; + + size_t count = 0; + + const size_t start = _array.BoundsCheck(_start, _array.Size()); + const size_t end = _array.BoundsCheck(_end, _array.Size() + 1); // 1 to allow indexing of end + + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(start <= end, "ZArrayAlgo::ReplaceIf - Cannot replace with end < start!"); + #endif + + for (size_t i = start; i < end; i++) + { + if (_functor(_array.Data()[i])) + { + _array.Data()[i] = _newValue; + count++; + } + } + + return count; + } + + /* + public ZArrayAlgo::ReplaceIf + + Replaces values in the array when the provided unary functor evaluates to true. + + @param F - unary functor ([const &] -> bool) to use to evaluate elements + @param T - the type held by the array + @param A - the allocator type of the array + @param _array - the array to replace elements in + @param _functor - instance of unary functor F to use + @param _newValue - the value to replace with + @return (size_t) - the number of replaced elements + */ + template + size_t ReplaceIf(ZArray& _array, F _functor, const T& _newValue) + { + return ReplaceIf(_array, _functor, _newValue, 0, _array.Size()); + } + + /* + public ZArrayAlgo::Reverse + + Reverses an array in place between the given indices. + + @param T - the type held by the array + @param A - the allocator type of the array + @param _array - the array to reverse + @param _start - the starting index + @param _end - the ending index (exclusive) + @return (void) + */ + template + void Reverse(ZArray& _array, size_t _start, size_t _end) + { + if (_start == _end) + return; + + T temp; + + const size_t start = _array.BoundsCheck(_start, _array.Size()); + const size_t end = _array.BoundsCheck(_end, _array.Size() + 1); // 1 to allow indexing of end + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(start <= end, "ZArrayAlgo::Reverse - Cannot reverse with end < start!"); + #endif + + if (start == end) + return; + + // note that the assert above and the _start == _end protect this from crashing for start = end = 0 + for (size_t i = start, j = end - 1; i < j; i++, j--) + { + temp = _array.Data()[i]; + _array.Data()[i] = _array.Data()[j]; + _array.Data()[j] = temp; + } + } + + /* + public ZArrayAlgo::Reverse + + Reverses an array in place. + + @param T - the type held by the array + @param A - the allocator type of the array + @param _array - the array to reverse + @return (void) + */ + template + void Reverse(ZArray& _array) + { + Reverse(_array, 0, _array.Size()); + } + + /* + public ZArrayAlgo::Rotate + + Function to shift an array so that a given element is at the front. + + [ 0 1 2 3 4 5] --> [ 3 4 5 0 1 2 3] + ^ pivot point + + @param _array - array to pivot + @param _pivot - index to pivot (inclusive) + @param _start - starting index (inclusive) of array slice to rotate + @param _end - ending index (exclusive) of array slice to rotate + @return (void) + @assert - if _pivot, _start, or _end out of bounds + if _pivot >= end + if _pivot < _start + */ + template + void Rotate(ZArray& _array, size_t _pivot, size_t _start, size_t _end) + { + if (_start == _end) + return; + + const size_t start = _array.BoundsCheck(_start, _array.Size()); + const size_t pivot = _array.BoundsCheck(_pivot, _array.Size()); + const size_t end = _array.BoundsCheck(_end, _array.Size() + 1); // 1 to allow indexing of end + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(start <= end, "ZArrayAlgo::Reverse - Cannot reverse with end < start!"); + ZSTL_ASSERT(pivot >= start, "ZArrayAlgo::Rotate - Cannot rotate with pivot before start!"); + ZSTL_ASSERT(pivot < end, "ZArrayAlgo::Rotate - Cannot rotate with pivot past end!"); + #endif + + ZArray temp(_array.Size()); + + // copy everything before the part to rotate + for (size_t i = 0; i < _start; i++) + temp.PushBack(_array.Data()[i]); + + // copy everything including and after the pivot + for (size_t i = pivot; i < end ; i++) + temp.PushBack(_array.Data()[i]); + + // copy everything up to the pivot + for (size_t i = start; i < pivot; i++) + temp.PushBack(_array.Data()[i]); + + // copy everything left after the end section + for (size_t i = _end; i < _array.Size(); i++) + temp.PushBack(_array.Data()[i]); + + _array.Copy(temp); + } + + /* + public ZArrayAlgo::Rotate + + Function to shift an array so that a given element is at the front. + + [ 0 1 2 3 4 5] --> [ 3 4 5 0 1 2 3] + ^ pivot point + + @param _array - array to pivot + @param _pivot - index to pivot (inclusive) + @return (void) + @assert - if _pivot out of bounds + */ + template + void Rotate(ZArray& _array, size_t _pivot) + { + return ZArrayAlgo::Rotate(_array, _pivot, 0, _array.Size()); + } + + /* + public ZArrayAlgo::SetIntersection + + Function to compute the intersection of two arrays. + + [ A B C ] ^ [ C D E ] -> [ C ] + + @param _array - first array + @param _s1 - starting index (inclusive) of first array + @param _e1 - ending index (exclusive) of first array + @param _other - second array + @param _s2 - starting index (inclusive) of second array + @param _e2 - starting index (exclusive) of second array + @return (ZArray) - array with unique elements from the intersection of the two arrays + @assert - if s1 > e1 + if s2 > e2 + if s1, e1, s2, e2 out of bounds + */ + template + ZArray SetIntersection(const ZArray& _array, size_t _s1, size_t _e1, const ZArray& _other, size_t _s2, size_t _e2) + { + if (_s1 == _e1 || _s2 == _e2) + return ZArray(); + + const size_t s1 = _array.BoundsCheck(_s1, _array.Size()); + const size_t e1 = _array.BoundsCheck(_e1, _array.Size() + 1); // 1 to allow indexing of end + const size_t s2 = _other.BoundsCheck(_s2, _other.Size()); + const size_t e2 = _other.BoundsCheck(_e2, _other.Size() + 1); // 1 to allow indexing of end + + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(s1 <= e1, "ZArrayAlgo::SetUnion - Cannot accumulate with first list end < start!"); + ZSTL_ASSERT(s2 <= e2, "ZArrayAlgo::SetUnion - Cannot accumulate with second list end < start!"); + #endif + + ZArray ret(e1-s1,e1-s1); + Copy(ret, 0, e1-s1, _array, s1, e1); + Unique(ret, 0, ret.Size()); + + for (size_t i = ret.Size(); i > 0; i--) + { + if (Contains(_other, ret.Data()[(i-1)], s2, e2) == false) + ret.Erase(i-1); + } + + return ret; + } + + /* + public ZArrayAlgo::SetIntersection + + Function to compute the intersection of two arrays. + + [ A B C ] ^ [ C D E ] -> [ C ] + + @param _array - first array + @param _other - second array + @return (ZArray) - array with unique elements from the intersection of the two arrays + */ + template + ZArray SetIntersection(const ZArray& _array, const ZArray& _other) + { + return SetIntersection(_array, 0, _array.Size(), _other, 0, _other.Size()); + } + + /* + public ZArrayAlgo::SetUnion + + Function to compute the union of two arrays. + + [ A B C ] U [ C D E ] -> [ A B C D E] + + @param _array - first array + @param _s1 - starting index (inclusive) of first array + @param _e1 - ending index (exclusive) of first array + @param _other - second array + @param _s2 - starting index (inclusive) of second array + @param _e2 - starting index (exclusive) of second array + @return (ZArray) - array with unique elements from the union of the two arrays + @assert - if s1 > e1 + if s2 > e2 + if s1, e1, s2, e2 out of bounds + */ + template + ZArray SetUnion(const ZArray& _array, size_t _s1, size_t _e1, const ZArray& _other, size_t _s2, size_t _e2) + { + if (_s1 == _e1) + return _other; + else if (_s2 == _e2) + return _array; + + ZArray ret; + + const size_t s1 = _array.BoundsCheck(_s1, _array.Size()); + const size_t e1 = _array.BoundsCheck(_e1, _array.Size() + 1); // 1 to allow indexing of end + const size_t s2 = _other.BoundsCheck(_s2, _other.Size()); + const size_t e2 = _other.BoundsCheck(_e2, _other.Size() + 1); // 1 to allow indexing of end + + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(s1 <= e1, "ZArrayAlgo::SetUnion - Cannot accumulate with first list end < start!"); + ZSTL_ASSERT(s2 <= e2, "ZArrayAlgo::SetUnion - Cannot accumulate with second list end < start!"); + #endif + + for (size_t i = _s1; i < _e1; i++) + { + if (Contains(ret, _array[i]) == false) + ret.PushBack(_array[i]); + } + + for (size_t i = _s2; i < _e2; i++) + { + if (Contains(ret, _other[i]) == false) + ret.PushBack(_other[i]); + } + + return ret; + } + + /* + public ZArrayAlgo::SetUnion + + Function to compute the union of two arrays. + + [ A B C ] U [ C D E ] -> [ A B C D E] + + @param _array - first array + @param _other - second array + @return (ZArray) - array with unique elements from the union of the two arrays + */ + template + ZArray SetUnion(const ZArray& _array, const ZArray& _other) + { + return SetUnion(_array, 0, _array.Size(), _other, 0, _other.Size()); + } + + /* + public ZArrayAlgo::Slice + + Removes a section of the provided array and returns a new array containing the + data. + + @param T - the type held by the array + @param A - the allocator type of the array + @param _array - the array to excise data from + @param _start - the index to start at + @param _end - the ending index (exclusive) + @return (ZArray) - the array slice + @assert - if _end < _start + if _start or _end out of bounds + */ + template + ZArray Slice(ZArray& _array, size_t _start, size_t _end) + { + if (_start == _end) + return ZArray(); + + ZArray ret(_array, _start, _end); + + _array.Erase(_start, _end); + + return ret; + } + + /* + public ZArrayAlgo::Sort + + Sorts an array in place using the provided comparator and algorithm between the given indices. + + @param CF - the comparator functor to use [(const T&, const T&) -> int] that compares values + returns negative value if first value < second value + returns positive value if first value > second value + returns 0 if first value == second value + @param AF - the algorithm functor to use [(CF&, T*, size_t) -> void] that sorts the array + @param T - the type held by the array + @param A - the allocator type of the array + @param _array - the array to sort + @param _comparator - the comparator used to sort the contained values + @param _algorithm - the array sort algorithm to use to sort the array + @param _start - the starting index + @param _end - the ending index (exclusive) + @return (void) + @assert - if _end < _start + if _start or _end out of bounds + */ + template + void Sort(ZArray& _array, CF _comparator, AF _algorithm, size_t _start, size_t _end) + { + if (_start == _end) + return; + + const size_t start = _array.BoundsCheck(_start, _array.Size()); + const size_t end = _array.BoundsCheck(_end, _array.Size() + 1); // 1 to allow indexing of end + + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(start <= end, "ZArrayAlgo::Sort - Cannot sort with end < start!"); + #endif + + const size_t sliceSize = end - start; + + _algorithm(_comparator, &_array.Data()[start], sliceSize); + } + + /* + public ZArrayAlgo::Sort + + Sorts an array in place using the default comparator (uses operator <) and a non-stable + quick sort. + + @param T - the type held by the array + @param A - the allocator type of the array + @param _array - the array to sort + @return (void) + */ + template + void Sort(ZArray& _array) + { + ZComparator comparator; + ZArrayQuickSort algorithm; + + Sort(_array, comparator, algorithm, 0, _array.Size()); + } + + /* + public ZArrayAlgo::Sort + + Sorts an array in place using the default comparator (uses operator <) and + uses a non-stable quick sort between the given indices. + + @param T - the type held by the array + @param A - the allocator type of the array + @param _array - the array to sort + @param _start - the starting index + @param _end - the ending index (exclusive) + @return (void) + @assert - if _end < _start + if _start or _end out of bounds + */ + template + void Sort(ZArray& _array, size_t _start, size_t _end) + { + ZComparator comparator; + ZArrayQuickSort algorithm; + + Sort(_array, comparator, algorithm, _start, _end); + } + + /* + public ZArrayAlgo::Sort + + Sorts an array in place using the provided comparator and a non-stable quick sort algorithm. + + @param CF - the comparator functor to use [(const T&, const T&) -> int] that compares values + returns negative value if first value < second value + returns positive value if first value > second value + returns 0 if first value == second value + @param T - the type held by the array + @param A - the allocator type of the array + @param _array - the array to sort + @param _comparator - the comparator used to sort the contained values + @return (void) + */ + template + void Sort(ZArray& _array, CF _comparator) + { + ZArrayQuickSort algorithm; + + Sort(_array, _comparator, algorithm, 0, _array.Size()); + } + + /* + public ZArrayAlgo::Split + + Splits a range of the array into a set of arrays at locations that have a value contained in the provided + set of delimiters. The delimiters are consumed from the array in the process. The array is split + only up to the provided number of times. + + @param T - the type held by the array + @param A - the allocator type of the array + @param B - the allocator type of the delimiter array + @param _array - the array to split + @param _delimiters - the set of delimiter values to split on + @param _count - the maximum number of times to split the array + @param _start - the starting index + @param _end - the ending index (exclusive) + @return (ZArray< ZArray >) - array of subsections of the original array + @assert - if _end < _start + if _start or _end out of bounds + */ + template + ZArray< ZArray > Split(const ZArray& _array, const ZArray& _values, size_t _count, size_t _start, size_t _end) + { + ZArray< ZArray > sections(_array.Size() + 1); + + if (_start == _end) + return sections; + + const size_t start = _array.BoundsCheck(_start, _array.Size()); + const size_t end = _array.BoundsCheck(_end, _array.Size() + 1); // 1 to allow indexing of end + + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(start <= end, "ZArrayAlgo::Split - Cannot split with end < start!"); + #endif + + //Location of the previous delimiter + size_t previous = start; + + for (size_t i = start; i < end; i++) + { + if (sections.Size() == _count) //Break out if we have reached our count limit + break; + + for (size_t j = 0; j < _values.Size(); j++) + { + if ( _array.Data()[i] == _values.Data()[j] ) + { + if (i > previous) //If we have more than just one of the delimiters + sections.PushBack( ZArray(_array, previous, i) ); + + previous = i + 1; + break; + } + } + } + + if (previous != end) //Add the final section + sections.PushBack( ZArray(_array, previous, end) ); + + return sections; + } + + /* + public ZArrayAlgo::Split + + Splits the array into a set of arrays at locations that have a value contained in the provided + set of delimiters. The delimiters are consumed from the array in the process. The array is split + only up to the provided number of times. + + @param T - the type held by the array + @param A - the allocator type of the array + @param B - the allocator type of the delimiter array + @param _array - the array to split + @param _delimiters - the set of delimiter values to split on + @param _count - the maximum number of times to split the array + @return (ZArray< ZArray >) - array of subsections of the original array + */ + template + ZArray< ZArray > Split(const ZArray& _array, const ZArray& _delimiters, size_t _count) + { + return Split(_array, _delimiters, _count, 0, _array.Size()); + } + + /* + public ZArrayAlgo::Split + + Splits the array into a set of arrays at locations that have a value contained in the provided + set of delimiters. The delimiters are consumed from the array in the process. + + @param T - the type held by the array + @param A - the allocator type of the array + @param B - the allocator type of the delimiter array + @param _array - the array to split + @param _delimiters - the set of delimiter values to split on + @return (ZArray< ZArray >) - array of subsections of the original array + */ + template + ZArray< ZArray > Split(const ZArray& _array, const ZArray& _delimiters) + { + return Split(_array, _delimiters, _array.Size(), 0, _array.Size()); + } + + /* + public ZArrayAlgo::StartsWith + + Used to determine if the given region of the provided array starts with the contents of the + given region of the other array. + + @param T - the type held by the array + @param A - the allocator type of the array + @param B - the allocator type of the other array + @param _array - the array to check + @param _s1 - the starting index to check against + @param _e1 - the ending index to check against (exclusive) + @param _other - the array to check from + @param _s2 - the starting index to check from + @param _e2 - the ending index to check to (exclusive) + @return (bool) - true if the array starts with the provided values, false otherwise + @assert - if _s1, _e1, _s2, or _e2 out of bounds + if _e1 < _s1 or _e2 < _s2 + */ + template + bool StartsWith(const ZArray& _array, size_t _s1, size_t _e1, const ZArray& _other, size_t _s2, size_t _e2) + { + return FindSub(_array, _s1, _e1, _other, _s2, _e2) == _s1; + } + + /* + public ZArrayAlgo::StartsWith + + Used to determine if the provided array starts with the contents of the other array. + + @param T - the type held by the array + @param A - the allocator type of the array + @param B - the allocator type of the other array + @param _array - the array to check + @param _other - the array to check from + @return (bool) - true if the array ends with the provided values, false otherwise + */ + template + bool StartsWith(const ZArray& _array, const ZArray& _other) + { + return StartsWith(_array, 0, _array.Size(), _other, 0, _other.Size()); + } + + /* + public ZArrayAlgo::Sum + + Returns the result of summing (via operator +) all the elements within a range in the array. + + @param V - the initial value type and sum type + @param T - the type held by the array + @param A - the allocator type of the array + @param _array - the array to accumulate on + @param _initialValue - the initial value for the accumulation + @param _start - the starting index + @param _end - the ending index (exclusive) + @return (V) - the accumulated value + @assert - if _end < _start + if _start or _end out of bounds + */ + template + V Sum(const ZArray& _array, V _initialValue, size_t _start, size_t _end) + { + if (_start == _end) + return _initialValue; + + const size_t start = _array.BoundsCheck(_start, _array.Size()); + const size_t end = _array.BoundsCheck(_end, _array.Size() + 1); // 1 to allow indexing of end + + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(start <= end, "ZArrayAlgo::Accumulate - Cannot accumulate with end < start!"); + #endif + + for (size_t i = start; i < end; i++) + _initialValue = _initialValue + _array.Data()[i]; + + return _initialValue; + } + + /* + public ZArrayAlgo::Sum + + Returns the result of summing (via operator +) all the elements in the array. + + @param V - the initial value type and sum type + @param T - the type held by the array + @param A - the allocator type of the array + @param _array - the array to accumulate on + @param _initialValue - the initial value for the accumulation + @return (V) - the accumulated value + */ + template + V Sum(const ZArray& _array, V _initialValue) + { + return Sum(_array, _initialValue, 0, _array.Size()); + } + + /* + public ZArrayUtil::SwapElements + + Swaps the values in two indices to this array. + + @param T - the type held by the array + @param A - the allocator type of the array + @param _array - the array to swap elements in + @param _i - the first value + @param _j - the second value + @return (void) + @assert - if _i or _j are out of bounds + */ + template + void SwapElements(ZArray& _array, size_t _start, size_t _end) + { + if (_start == _end) + return; + + const size_t i = _array.BoundsCheck(_start, _array.Size()); + const size_t j = _array.BoundsCheck(_end, _array.Size()); + + T temp = _array.Data()[i]; + _array.Data()[i] = _array.Data()[j]; + _array.Data()[j] = temp; + } + + /* + public ZArrayAlgo::Unique + + Makes all the values in an array unique within the given range. + + @param T - the type held by the array + @param A - the allocator type of the array + @param _array - the array to make full of unique values + @param _start - the starting index + @param _end - the ending index (exclusive) + @return (size_t) - the number of values removed + @assert - if _end < _start + if _start or _end out of bounds + */ + template + size_t Unique(ZArray& _array, size_t _start, size_t _end) + { + if (_start == _end) + return 0; + + const size_t start = _array.BoundsCheck(_start, _array.Size()); + const size_t end = _array.BoundsCheck(_end, _array.Size() + 1); // 1 to allow indexing of end + + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(start <= end, "ZArrayAlgo::Unique - Cannot make unique with end < start!"); + #endif + + size_t removed = 0; + + for (size_t i = start; i < end - removed; i++) + { + for (size_t j = end - removed - 1; j > i; j--) + { + if (_array.Data()[i] == _array.Data()[j]) + { + removed++; + _array.Erase(j); + } + } + } + return removed; + } + + /* + public ZArrayAlgo::Unique + + Makes all the values in an array unique. + + @param T - the type held by the array + @param A - the allocator type of the array + @param _array - the array to make full of unique values + @return (size_t) - the number of values removed + */ + template + size_t Unique(ZArray& _array) + { + return Unique(_array, 0, _array.Size()); + } +} + +#endif diff --git a/Lib/Include/ZSTL/ZBasicString.hpp b/Lib/Include/ZSTL/ZBasicString.hpp new file mode 100644 index 0000000..b569912 --- /dev/null +++ b/Lib/Include/ZSTL/ZBasicString.hpp @@ -0,0 +1,855 @@ +/* + ZBasicString.hpp + Author: James Russell + Created: 12/25/2011 + + Purpose: + + Basic ASCII string implementation. + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ + +#pragma once + +#ifndef _ZBASICSTRING_HPP +#define _ZBASICSTRING_HPP + +#include + +#include //for strcmp, memset, memmove +#include //for isspace, tolower +#include //for sprintf + +#include //for ostream + +/* + * Turns out that _stricmp is a Windows specific function. + * strcasecmp() appears to be POSIX compliant. + */ +#ifndef _WIN32 +#include +#endif + +//Null Terminator Definition +#define ZBASICSTRING_NULL_TERMINATOR ((char)'\0') + +//Default Capacity for a ZBasicString (not including the null terminator) +#ifndef ZBASICSTRING_DEFAULT_CAPACITY +#define ZBASICSTRING_DEFAULT_CAPACITY (127) +#endif + +//Default buffer size for a ZBasicString +#ifndef ZBASICSTRING_DEFAULT_ALLOCATOR_STORAGE +#define ZBASICSTRING_DEFAULT_ALLOCATOR_STORAGE (128) +#endif + +/* +Dynamic ASCII string implementation. + +The template parameter A is the array allocator that will be used by the underlying array +that stores our characters. It should allocate arrays of type 'char'. +*/ +template > +class ZBasicString +{ +protected: + //Array used to hold the characters + ZArray StringArray; + + //Integrity check + inline void CheckIntegrity() + { + #if ZSTL_CHECK_INTEGRITY + + ZSTL_ASSERT(StringArray.Size() > 0, "StringArray is empty with no null terminator!"); + ZSTL_ASSERT(StringArray[Length()] == ZBASICSTRING_NULL_TERMINATOR, "StringArray has no null terminator!"); + + #endif //ZSTL_CHECK_INTEGRITY + } + +public: + /* + Default constructor. Constructs an empty string. + */ + ZBasicString() + : StringArray(ZBASICSTRING_DEFAULT_CAPACITY + 1) + { + //Make sure we have our null terminator + StringArray.PushBack(ZBASICSTRING_NULL_TERMINATOR); + CheckIntegrity(); + } + + /* + Parameterized constructor. Constructs an empty string with the + specified capacity (not including the null terminator). + */ + explicit ZBasicString(size_t _capacity) + : StringArray(_capacity + 1) + { + //Make sure we have our null terminator + StringArray.PushBack(ZBASICSTRING_NULL_TERMINATOR); + CheckIntegrity(); + } + + /* + Parameterized constructor. This constructor will initialize a copy of + the provided null-terminated string. + + @param _string - the null-terminated string to initialize to + */ + ZBasicString(const char *_string) + : StringArray( _string != NULL ? strlen(_string) + 1 : 1) + { + //Set the string array size equal to the starting capacity, copy, and set null terminator + StringArray.Resize(StringArray.Capacity()); + memmove(StringArray.Data(), _string, Length() * sizeof(char)); + StringArray.Data()[Length()] = ZBASICSTRING_NULL_TERMINATOR; + CheckIntegrity(); + } + + /* + Parameterized constructor. This constructor will initialize a copy of the provided + string, but it will only copy in as many characters as defined. The null terminator + at the end is not required. + + If a null terminator is present before the end of the string, the string will be + shortened such that the first encountered null terminator is at the end of the string. + + @param _string - the string to initialize to + @param _count - the number of chars in the string + */ + ZBasicString(const char *_string, const size_t _count) + : StringArray(_string, _count, _count + 1) + { + StringArray.PushBack(ZBASICSTRING_NULL_TERMINATOR); + StringArray.Resize(strlen(StringArray.Data()) + 1); + + CheckIntegrity(); + } + + /* + Parameterized constructor. This constructor will initialize a string from the character + data contained in the provided array. The null terminator at the end is not required. + + If a null terminator is present before the end of the string, the string will be + shortened such that the first encountered null terminator is at the end of the string. + + @param _array - the provided character array to use as a string + */ + template + explicit ZBasicString(const ZArray& _array) + : StringArray(_array.Data(), _array.Size(), _array.Capacity() + 1) + { + StringArray.PushBack(ZBASICSTRING_NULL_TERMINATOR); + StringArray.Resize(strlen(StringArray.Data()) + 1); + + CheckIntegrity(); + } + + /* + Copy constructor. + + @param _other - the other string + */ + ZBasicString(const ZBasicString& _other) + : StringArray(_other.Array()) + { + CheckIntegrity(); + } + + /* + Copy constructor. Used when the allocator type for the + other string is different. + + @param B - the allocator type of the other string + @param _other - the other string + */ + template + ZBasicString(const ZBasicString& _other) + : StringArray(_other.Array()) + { + CheckIntegrity(); + } + + /* + Slice Copy constructor. Constructs this string as a slice of another. + + @param B - the allocator type of the other string + @param _other - the other string + */ + template + ZBasicString(const ZBasicString& _other, size_t _start, size_t _end) + : StringArray(_other.Array(), _start, _end) + { + if (_start == _end || StringArray.Back() != ZBASICSTRING_NULL_TERMINATOR) + StringArray.PushBack(ZBASICSTRING_NULL_TERMINATOR); + + CheckIntegrity(); + } + + /* + Destructor. + */ + ~ZBasicString() + { + CheckIntegrity(); + } + + /* + [] operator overload. Allows indexing into the characters of this string. + Equivalent to a call to At. + + @param _index - integer index into the string + @return (char&) - character at the given index + @assert - if the index is out of bounds + */ + char& operator [] (const size_t _index) const + { return At(_index); } + + /* + = operator overload. Makes this string equivalent to the other. Equivalent + to a call to Copy. + + @param _other - the string to set this equal to + @return (ZBasicString&) - this string + */ + ZBasicString& operator = (const ZBasicString& _other) + { Copy(_other); return *this; } + + /* + = operator overload. Makes this string equivalent to the other. Used when the underlying + allocator type is different. Equivalent to a call to Copy. + + @param B - the allocator type for the other string + @param _other - the string to set this equal to + @return (ZBasicString&) - this string + */ + template + ZBasicString& operator = (const ZBasicString& _other) + { Copy(_other); return *this; } + + //C-String Implementation of operator = + ZBasicString& operator = (const char* _other) + { Copy(_other); return *this; } + + /* + == operator overload. Determines if this string is equal to another. Equivalent + to a call to Equals. + + @param _other - the string to compare to + @return (bool) - true if equal, false otherwise + */ + template + bool operator == (const ZBasicString& _other) const + { return Equals(_other); } + + //C-String Implementation of operator == + bool operator == (const char* _other) const + { return Equals(_other); } + + /* + != operator overload. Determines if this string is not equal to another. + Equivalent to a call to !Equals. + + @param B - the allocator type for the other string + @param _other - the string to compare to + @return (bool) - true if not equal, false otherwise + */ + template + bool operator != (const ZBasicString& _other) const + { return !Equals(_other); } + + //C-String Implementation of operator != + bool operator != (const char* _other) const + { return !Equals(_other); } + + /* + < operator overload. Lexographically compares strings. + + @param B - the allocator type for the other string + @param _other - the string to compare to + @return (bool) - true if less than, false otherwise + */ + template + bool operator < (const ZBasicString& _other) const + { return Compare(_other) < 0; } + + //C-String implementation of operator < + bool operator < (const char* _other) const + { return Compare(_other); } + + /* + < operator overload. Lexographically compares strings. Equivalent to a call + to Compare. + + @param B - the allocator type for the other string + @param _other - the string to compare to + @return (bool) - true if less than, false otherwise + */ + template + bool operator <= (const ZBasicString& _other) const + { return Compare(_other) <= 0; } + + /* + + operator overload. Returns a string that is the concatenation of this + string and the provided string. + + @param B - the allocator type for the other string + @param _other - the string to append + @return (ZBasicString) - a string that is this string appended with _other + */ + template + ZBasicString operator + (const ZBasicString& _other) const + { ZBasicString ret(*this); ret.Insert(ret.Length(), _other); return ret; } + + //C-String implementation of operator + + ZBasicString operator + (const char *_other) const + { ZBasicString ret(*this); ret.Insert(ret.Length(), _other); return ret; } + + /* + + operator overload. Returns a string that is the concatenation of this + string and the provided char. + + @param _c - the character to append + @return (ZBasicString) - a string that is this string appended with _c + */ + ZBasicString operator + (const char& _c) const + { ZBasicString ret(*this); ret.PushBack(_c); return ret; } + + /* + += operator overload. Inserts the given string at the end of this string. Equivalent + to a call to Insert. + + @param B - the allocator type for the other string + @param _other - the string to append + @return (ZBasicString&) - this string + */ + template + ZBasicString& operator += (const ZBasicString& _other) + { Insert(Length(), _other); return *this; } + + //C-String Implementation of operator += + ZBasicString& operator += (const char *_other) + { Insert(Length(), _other); return *this; } + + /* + += operator overload. Pushes a character onto this string. Equivalent to a call to + PushBack. + + @param _c - the character to append + @return (ZBasicString&) - this string + */ + ZBasicString& operator += (const char& _c) + { PushBack(_c); return *this; } + + /* + ZHashValue value override. Uses the Java 6 string hash function. Equivalent to a call + to Hash. + + @return (ZHashValue) - hash code for this string + */ + operator ZHashValue () const + { return Hash(); } + + /* + public ZBasicString::Allocator + + Gets the allocator set on this string. + + @return (A&) - the allocator instance + */ + A& Allocator() + { + return StringArray.Allocator(); + } + + /* + public ZBasicString::Array + + Gets this string's backing ZArray. The last character in the array is guaranteed to + be ZBASICSTRING_NULL_TERMINATOR. Try to keep it that way. + + @return (ZArray&) - the string as a ZArray. + */ + const ZArray& Array() const + { + return StringArray; + } + + /* + public ZBasicString::At + + Gets the character at the given signed index. Passing in an index of -1 will return + the last character, not the null terminator. + + @param _index - the index + @return (char) - the character at the provided index + @assert - if the index is out of bounds + */ + char& At(const size_t _index) const + { + return StringArray.Data()[BoundsCheck(_index, Length())]; + } + + /* + public ZBasicString::Back + + Gets a reference to the character at the back of the string. + + @return (char&) - the character at the end of the string + @assert - if the string is empty + */ + char& Back() const + { + return StringArray.Data()[BoundsCheck(Length() - 1, Length())]; + } + + /* + public ZBasicString::BoundsCheck + + Bounds checks the provided index against the provided boundary, ensuring it is less + than and asserting if an out of bounds access occurs. Calls to this will be compiled + out if ZSTL_DISABLE_RUNTIME_CHECKS is not zero. + + @param _index - the index to convert + @param _boundary - the boundary to bounds check against + @return (size_t) - the unsigned index + @assert - if the index is not less than boundary + */ + size_t BoundsCheck(const size_t _index, const size_t _boundary) const + { + return StringArray.BoundsCheck( _index, _boundary ); + } + + /* + public ZBasicString::Capacity + + Returns the capacity of this string. + + @return (size_t) - capacity of the string + */ + size_t Capacity() const + { + return StringArray.Capacity() - 1; + } + + /* + public ZBasicString::Clear + + Clears out the string to the empty string. + + @return (void) + */ + void Clear() + { + StringArray.Clear(); + StringArray.PushBack(ZBASICSTRING_NULL_TERMINATOR); + } + + /* + public ZBasicString::Clear + + Clears out the string to the empty string and ensures the capacity of + the string to the provided capacity. Will reallocate if necessary. + + @param _newCapacity - the new capacity to use + @return (void) + */ + void Clear(size_t _newCapacity) + { + StringArray.Clear(_newCapacity + 1); + StringArray.PushBack(ZBASICSTRING_NULL_TERMINATOR); + } + + /* + public ZBasicString::Compare + + Lexicographically compares this string with another. + + @param B - the other string allocator type + @param _other - the other string + @return (int) - zero if lexicographically equivalent, less than zero if this < _other, + greater than zero if this > _other + */ + template + int Compare(const ZBasicString& _other) const + { + return strcmp(StringArray.Data(), _other.Data()); + } + + //C-String Implementation of Compare + int Compare(const char *_other) const + { + return strcmp(StringArray.Data(), _other); + } + + /* + public ZBasicString::Copy + + Copies the given string data into this string. + + @param B - the other string allocator type + @param _other - the other string + @return (void) + */ + template + void Copy(const ZBasicString& _other) + { + StringArray.Resize(_other.Length() + 1); + StringArray.Copy(_other.Array()); + } + + //C-String Implementation of Copy + void Copy(const char* _other) + { Copy(ZBasicString(_other)); } + + /* + public ZBasicString::Data + + Gets the character data from this string (NULL terminated C-style string). + + @return (char*) - this string as a char* + */ + char* Data() const + { + return StringArray.Data(); + } + + /* + public ZBasicString::Empty + + Determines if the string is the empty string. + + @return (bool) - true if the string is empty string, false otherwise + */ + bool Empty() const + { + return StringArray.Data()[0] == ZBASICSTRING_NULL_TERMINATOR; + } + + /* + public ZBasicString::Equals + + Determines if this string is lexicographically equivalent to another. + + @param B - the allocator type of the other + @param _other - the other string + @return (bool) - true if equivalent, false otherwise + */ + template + bool Equals(const ZBasicString& _other) const + { + return Compare(_other) == 0; + } + + //C-String Implementation of Equals + bool Equals(const char *_other) const + { return Compare(_other) == 0; } + + /* + public ZBasicString::Erase + + Erase function. Erases the character at the provided index. + + @param _index - the index of the character to erase + @return (void) + */ + void Erase(const size_t _index) + { + size_t index = BoundsCheck(_index, Length()); + Erase(index, index + 1); + } + + /* + public ZBasicString::Erase + + Erase function. Erases characters between the given indices. + + @param _start - the starting index + @param __end - the ending index index (exclusive) + @return (void) + @assert - if _start or _end out of bounds + if _end < _start + */ + void Erase(const size_t _start, const size_t _end) + { + if (_start == _end) + return; + + size_t start = BoundsCheck(_start, Length()); + size_t end = BoundsCheck(_end, Length() + 1); + + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(start <= end, "ZBasicString: Cannot erase with _end < _start!"); + #endif + + StringArray.Erase(start, end); + + CheckIntegrity(); + } + + /* + public ZBasicString::Front + + Gets a reference to the character at the front of the string. + + @return (char&) - the character at the front of the string + @assert - if the string is empty + */ + char& Front() const + { + return StringArray.Data()[BoundsCheck(0, Length())]; + } + + /* + public ZBasicString::Hash + + Returns a hash value for the string. Uses the Java 6 string hashing method. + This does not include the null terminator of the string. + + @return (ZHashValue) - the hash value for the string + */ + ZHashValue Hash() const + { + size_t i; + ZHashValue hash; + + for (hash = 0, i = 0; i < Length(); i++) + hash = (hash << 5) - hash + (StringArray.Data())[i]; + + return hash; + } + + /* + public ZBasicString::Insert + + Insert function. Inserts a character into this string. + + @param _index - index to insert at + @param _char - character to insert + @return (void) + @assert - if index is invalid + */ + void Insert(const size_t _index, const char& _char) + { + size_t index = BoundsCheck(_index, Length() + 1); + + StringArray.Insert(index, _char); + + CheckIntegrity(); + } + + /* + public ZBasicString::Insert + + Insert function. Inserts a string into this string. + + @param _index - index to insert at + @param _other - string to insert + @return (void) + @assert - if index is invalid + */ + void Insert(const size_t _index, const ZBasicString& _other) + { + size_t index = BoundsCheck(_index, Length() + 1); + + StringArray.Insert(index, _other.Array(), 0, _other.Length()); + + CheckIntegrity(); + } + + /* + public ZBasicString::Length + + Gives the length of the string, not including the null terminator. + + @return (size_t) - length of the string + */ + size_t Length() const + { + return StringArray.Size() - 1; + } + + /* + public ZBasicString::Pop + + Pops a character off the string. + + @return (char) - the character removed from the string + @assert - if the string is empty + */ + char PopBack() + { + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(!Empty(), "ZBasicString: PopBack called on empty string!"); + #endif + + return StringArray.Erase(StringArray.Size() - 2); + } + + /* + public ZBasicString::PopFront + + Pops a character off of the beginning of the string. + + @return (char) + @assert - if the string is empty + */ + char PopFront() + { + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(!Empty(), "ZBasicString: PopBack called on empty string!"); + #endif + + return StringArray.PopFront(); + } + + /* + public ZBasicString::PushBack + + Pushes a character onto the string. Will allocate storage if necessary. + + @param _char - character to push onto the string + @return (void) + */ + void PushBack(const char& _char) + { + StringArray.PushBack(ZBASICSTRING_NULL_TERMINATOR); + StringArray.At(StringArray.Size() - 2) = _char; + } + + /* + public ZBasicString::PushFront + + Pushes a character onto the beginning of the string. Will allocate storage + if necessary. + + @param _char - the character to push onto the string + @return (void) + */ + void PushFront(const char& _char) + { + StringArray.PushFront(_char); + }; + + /* + public ZBasicString::Reserve + + Changes the capacity of this string, reserving space in the underlying array for the + provided number of characters and the null terminator. + + @param _capacity - the capacity to use + @return (void) + @assert - if the capacity is less than current size + */ + void Reserve(size_t _capacity) + { + StringArray.Reserve(_capacity + 1); + } + + /* + public ZBasicString::Resize + + Resizes this string. If the string size is shrunk, removes the excess characters. If + the string size is grown, the whitespace character is appended that many times. Will + allocate storage if necessary. + + @param _newSize - the new size of the string + @return (void) + */ + void Resize(size_t _newSize) + { + Resize(_newSize, ' '); + } + + /* + public ZBasicString::Resize + + Resizes this string. If the string size is shrunk, removes the excess characters. If + the string size is grown, the provided character is appended that many times. Will + allocate storage if necessary. + + @param _newSize - the new size of this string + @param _value - the value to append if size increases + @return (void) + */ + void Resize(size_t _newSize, const char& _value) + { + StringArray.PopBack(); //Remove null terminator + StringArray.Resize(_newSize + 1, _value); //Include room to replace the null terminator + StringArray.At(this->Length()) = ZBASICSTRING_NULL_TERMINATOR; + CheckIntegrity(); + } + + /* + public ZBasicString::Swap + + Swap operation, which swaps string content. + + @param B - the allocator type of the other string + @param _other - string to swap contents with + @return (void) + */ + template + void Swap(ZBasicString& _other) + { + StringArray.Swap(_other.StringArray); + CheckIntegrity(); + } +}; + +/////////////////////////////////////////// +/* Non-Member Functions for ZBasicString */ +/////////////////////////////////////////// + +/* +Non member addition function. Allows adding a const char* to a ZBasicString +with the CString as the right side of the operator. + +@param _lhs - string to append to the left side +@param _rhs - char * to append to +@return - a string that is the concatenation of _lhs with _rhs +*/ +template +ZBasicString operator + (const ZBasicString& _lhs, const char *_rhs) +{ + return _lhs + ZBasicString(_rhs); +} + +/* +Non member addition function. Allows adding a ZBasicString to a const char * +with the CString as the left side of the operator. + +@param _lhs - char * to append to +@param _rhs - string to append to the left side +@return - a string that is the concatenation of _lhs with _rhs +*/ +template +ZBasicString operator + (const char *_lhs, const ZBasicString& _rhs) +{ + return ZBasicString(_lhs) + _rhs; +} + +/* +Output stream operator overload for ZBasicString. Needed to ensure ZBasicString +behaves as expected when trying to use std::cout or std::cerr. + +@param _os - the output stream +@param _str - the basic string +@return - the output stream provided +*/ +template +std::ostream& operator << (std::ostream& _os, const ZBasicString& _str) +{ + _os << _str.Data(); return _os; +} + +#endif diff --git a/Lib/Include/ZSTL/ZBasicStringAlgo.hpp b/Lib/Include/ZSTL/ZBasicStringAlgo.hpp new file mode 100644 index 0000000..d79cbc3 --- /dev/null +++ b/Lib/Include/ZSTL/ZBasicStringAlgo.hpp @@ -0,0 +1,2439 @@ +/* + ZStringUtil.hpp + Author: James Russell + Created: 1/12/2012 + + Purpose: + + Contains additional methods for manipulation and use of ZBasicString. + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ + +#pragma once + +#ifndef _ZBASICSTRINGALGO_HPP +#define _ZBASICSTRINGALGO_HPP + +#include +#include + +#include //for strcmp, memset, memmove +#include //for sprintf +#include //for va_start, va_end + +namespace ZBasicStringAlgo +{ + //Forward Declaration of FindFirst + template + size_t FindFirst(const ZBasicString& _string, const char& _char, size_t _start, size_t _end); + + template + size_t FindFirst(const ZBasicString& _string, const char& _char); + + //Forward Declaration of FindSub + template + size_t FindSub(const ZBasicString& _string, size_t _s1, size_t _e1, const ZBasicString& _substring, size_t _s2, size_t _e2); + + //Forward Declaration of TrimLeft + template + size_t TrimLeft(ZBasicString& _string, size_t _start, size_t _end); + + //Forward Declaration of TrimRight + template + size_t TrimRight(ZBasicString& _string, size_t _start, size_t _end); + + /* + public ZBasicStringAlgo::Append + + Appends a range of a string to the provided one. + + @param A - allocator type for this string + @param B - the allocator type for the other string + @param _string - the string to append to + @param _other - string to append + @param _start - the starting index of the other string + @param _end - the ending index of the other string (exclusive) + @return (void) + @assert - if _end < _start + if _start of _end out of bounds + */ + template + void Append(ZBasicString& _string, const ZBasicString& _other, size_t _start, size_t _end) + { + if (_start == _end) + return; + + const size_t start = _other.BoundsCheck(_start, _other.Length()); + const size_t end = _other.BoundsCheck(_end, _other.Length() + 1); + + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(start <= end, "ZBasicStringAlgo::Append - Cannot append with end < start!"); + #endif + + ZArray& stringArray = const_cast< ZArray& >(_string.Array()); + + stringArray.PopBack(); + + ZArrayAlgo::Append(stringArray, _other.Array(), start, end); + + stringArray.PushBack(ZBASICSTRING_NULL_TERMINATOR); + } + + /* + public ZBasicStringAlgo::Append + + Appends a string to the provided one. + + @param A - allocator type for this string + @param B - the allocator type for the other string + @param _string - the string to append to + @param _other - string to append + @return (ZBasicString&) - this provided string, after appending + */ + template + void Append(ZBasicString& _string, const ZBasicString& _other) + { + return Append(_string, _other, 0, _other.Length()); + } + + //Append C-String Implementation + template + void Append(ZBasicString& _string, const char *_other) + { return Append(_string, ZBasicString(_other)); } + + //Append C-String Implementation + template + void Append(ZBasicString& _string, const char *_other, size_t _start, size_t _end) + { return Append(_string, ZBasicString(_other), _start, _end); } + + /* + public ZBasicStringAlgo::BuildNumeric + + Builds a string from an integer or floating point type using the given format string, so + this equivalent to calling snprintf with the provided format string and number. + + @param A - the allocator type for the string + @param N - the numeric type to build from (int, double, etc.) + @param _string - the string to build + @param _fmt - the format string to use (any format string valid for _number) + @param _number - the number to use + @param + */ + template + void BuildNumeric(ZBasicString& _string, const char* _fmt, N _number) + { + ZSTL_ASSERT(_fmt != NULL, "BuildNumeric() given null format string!\n"); + _string.Clear(); + + int len = -1; + #ifdef _MSC_VER + #pragma warning(push) + #pragma warning(disable:4996) + len = _snprintf(NULL,0,_fmt,_number); + #pragma warning(pop) + #else + char temp = ' '; + len = snprintf(&temp,0,_fmt,_number); + #endif + + ZSTL_ASSERT(len > 0, "BuildNumeric() would've made bad printf!\n"); + _string.Resize(len, ZBASICSTRING_NULL_TERMINATOR); + + #ifdef _MSC_VER + #pragma warning(push) + #pragma warning(disable:4996) + // note that ZString has one more in the data array, set to the terminator, so this is okay. + _snprintf(_string.Data(), (_string.Length()) * sizeof(char), _fmt, _number); + #pragma warning(pop) + #else + // for GNU et al, though we need to fake out their null-terminator safety + snprintf(_string.Data(), (_string.Length() + 1) * sizeof(char), _fmt, _number); + #endif + } + + /* + public ZBasicStringAlgo::BuildNumeric + + Builds a string from a double-precision float. This is equivalent to using + snprintf with a format string of %f. + + @param A - the allocator type for the string + @param _string - the string to build + @param _number - the number to use + @return (void) + */ + template + void BuildNumeric(ZBasicString& _string, double _number) + { + return BuildNumeric(_string, "%f", _number); + } + + /* + public ZBasicStringAlgo::BuildNumeric + + Builds a string from an integer. This is equivalent to using + snprintf with a format string of %i. + + @param A - the allocator type of the string + @param _string - the string to build + @param _number - the number to use + @return (void) + */ + template + void BuildNumeric(ZBasicString& _string, int _number) + { + return BuildNumeric(_string, "%i", _number); + } + + /* + public ZBasicStringAlgo::BuildPrintf + + Builds a basic string using printf-style formatted output. + + @param A - the allocator type of the string + @param _string - the string to build (cleared by this function before building) + @param _fmt - the null-terminated printf format string + @param ... - the variable arguments for the format string + @return (void) + */ + template + void BuildPrintf(ZBasicString& _string, const char *_fmt, ...) + { + ZSTL_ASSERT(_fmt != NULL, "BuildPrintf() given null format string!\n"); + va_list args; + va_start(args, _fmt); + + _string.Clear(); + + //MSVC's implementation of vsnprintf() family contradicts C standard on return value. It returns -1 if too small, when it should return the number of characters + #if defined(_MSC_VER) || defined(_WIN32) //TODO: Really, we meant MSVCRTxx.dll, i.e. Microsoft VC runtime + _string.Resize(128); + int result; + do + { + result = _vsnprintf_s(_string.Data(), _string.Length()+1, _TRUNCATE, _fmt, args); //NOTE: 2nd param is size of buffer, not number chars. Therefore, we give it +1 + + //Not enough space? -> Increase string size + if(result < 0) + _string.Resize( _string.Length() * 2); + else //Success, trim extra characters + _string.Resize((size_t)result); + + } while (result < 0); + + #else //Rest of the world can follow the C standard thankfully (right?) + char temp[1]; + int len = vsnprintf(temp, sizeof(temp), _fmt, args); //C standard says 2nd param is sizeof(buffer), not number of chars + //Return is -1 on error, OR number of characters in size + + ZSTL_ASSERT(len >= 0, "BuildPrintf() given bad format string!\n"); + _string.Resize((size_t)len, ZBASICSTRING_NULL_TERMINATOR); + va_end(args); + + va_start(args,_fmt); + len = vsnprintf(_string.Data(), _string.Length()+1, _fmt, args); + #endif + + va_end(args); + } + + /* + public ZBasicString<>::BuildRepeat + + Constructs a ZBasicString by repeating the given null-terminated string the given number of times. + + @param A - the allocator type of the string + @param _string - the string to build (cleared by this function before building) + @param _repeatString - the string to repeat + @param _count - the number of times to repeat it + @return (void) + */ + template + void BuildRepeat(ZBasicString& _string, const char *_repeatString, size_t _count) + { + size_t i; + + + size_t len = strlen(_repeatString); + + _string.Resize(len * _count); //Resize() includes space for NULL terminator + + + char* data = _string.Data(); + for (i = 0; i < _count; i++) + { + memcpy(data, _repeatString, len); + data += len; + } + *data = '\0'; + } + + /* + public ZBasicStringAlgo::Contains + + Determines if the provided string contains the given character between the given + indices. + + @param A - allocator type for this string + @param _string - the string to check + @param _c - the character to look for + @param _start - the starting index + @param _end - the ending index (exclusive) + @return (bool) - true if the string contains this character, false otherwise + @assert - if _end < _start + if _start of _end out of bounds + */ + template + bool Contains(const ZBasicString& _string, const char _char, size_t _start, size_t _end) + { + if (_start == _end) + return false; + + const size_t start = _string.BoundsCheck(_start, _string.Length()); + const size_t end = _string.BoundsCheck(_end, _string.Length() + 1); + + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(start <= end, "ZBasicStringAlgo::Contains - Cannot check with end < start!"); + #endif + + return ZArrayAlgo::Contains(_string.Array(), _char, start, end); + } + + /* + public ZBasicStringAlgo::Contains + + Determines if the provided string contains the given character. + + @param A - allocator type for this string + @param _string - the string to check + @param _c - the character to look for + @return (bool) - true if the string contains this character, false otherwise + */ + template + bool Contains(const ZBasicString& _string, const char _char) + { + return Contains(_string, _char, 0, _string.Length()); + } + + /* + public ZBasicStringAlgo::ContainsSub + + Determines if the provided string contains the provided substring in the given ranges. + + @param A - allocator type of the string + @param B - allocator type for the substring + @param _string - the string to check + @param _s1 - the starting index in the string + @param _e1 - the ending index in the string (exclusive) + @param _substring - the substring to look for + @param _s2 - the starting index in the substring + @param _e2 - the ending index in the string (exclusive) + @return (bool) - true if the string contains the substring, false otherwise + @assert - if _s1 < _e1 or _s2 < _e2 + if _s1, _e1, _s2, or _e2 out of bounds + */ + template + bool ContainsSub(const ZBasicString& _string, size_t _s1, size_t _e1, const ZBasicString& _substring, size_t _s2, size_t _e2) + { + if (_s1 == _e1 || _s2 == _e2) + return false; + + const size_t s1 = _string.BoundsCheck(_s1, _string.Length()); + const size_t e1 = _string.BoundsCheck(_e1, _string.Length() + 1); + + const size_t s2 = _substring.BoundsCheck(_s2, _substring.Length()); + const size_t e2 = _substring.BoundsCheck(_e2, _substring.Length() + 1); + + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(s1 <= e1, "ZBasicStringAlgo::ContainsSub - Cannot check with end < start!"); + ZSTL_ASSERT(s2 <= e2, "ZBasicStringAlgo::ContainsSub - Cannot check with end < start!"); + #endif + + return ZArrayAlgo::ContainsSub(_string.Array(), s1, e1, _substring.Array(), s2, e2); + } + + /* + public ZBasicStringAlgo::ContainsSub + + Determines if the provided string contains the provided substring. + + @param A - allocator type of the string + @param B - allocator type for the substring + @param _string - the string to check + @param _substring - the substring to look for + @return (bool) - true if the string contains the substring, false otherwise + */ + template + bool ContainsSub(const ZBasicString& _string, const ZBasicString& _substring) + { + return ContainsSub(_string, 0, _string.Length(), _substring, 0, _substring.Length()); + } + + //ContainsSub C-String Implementation + template + bool ContainsSub(const ZBasicString& _string, const char* _other) + { return ContainsSub(_string, ZBasicString(_other)); } + + //ContainsSub C-String Implementation + template + bool ContainsSub(const ZBasicString& _string, size_t _s1, size_t _e1, const char* _other, size_t _s2, size_t _e2) + { return ContainsSub(_string, _s1, _e1, ZBasicString(_other), _s2, _e2); } + + /* + public ZBasicStringAlgo::Copy + + Copies the values in the range provided from the given string into the range + provided in another. The maximum number of characters copied is equal to the + minimum of (_e1 - _s1) or (_e2 - _s2). + + @param A - allocator type for the destination string + @param B - allocator type for the source string + @param _destination - the destination string + @param _s1 - the starting index for the destination string + @param _e1 - the ending index for the destination string (exclusive) + @param _source - the source string + @param _s2 - the starting index for the source string + @param _e2 - the ending index for the source string (exclusive) + @return (void) + @assert - if _s1 < _e1 or _s2 < _e2 + if _s1, _e1, _s2, or _e2 out of bounds + */ + template + void Copy(ZBasicString& _destination, size_t _s1, size_t _e1, const ZBasicString& _source, size_t _s2, size_t _e2) + { + if (_s1 == _e1 || _s2 == _e2) + return; + + const size_t s1 = _destination.BoundsCheck(_s1, _destination.Length()); + const size_t e1 = _destination.BoundsCheck(_e1, _destination.Length() + 1); + + const size_t s2 = _source.BoundsCheck(_s2, _source.Length()); + const size_t e2 = _source.BoundsCheck(_e2, _source.Length() + 1); + + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(s1 <= e1, "ZBasicStringAlgo::Copy - Cannot copy with end < start!"); + ZSTL_ASSERT(s2 <= e2, "ZBasicStringAlgo::Copy - Cannot copy with end < start!"); + #endif + + ZArray& stringArray = const_cast< ZArray& >(_destination.Array()); + + ZArrayAlgo::Copy(stringArray, s1, e1, _source.Array(), s2, e2); + } + + /* + public ZBasicStringAlgo::Copy + + Copies the characters from a source string into a destination string. The maximum number of + characters copied is equal to the length of the shorter string. + + @param A - allocator type for the destination string + @param B - allocator type for the source string + @param _destination - the destination string + @param _source - the source string + @return (void) + */ + template + void Copy(ZBasicString& _destination, const ZBasicString& _source) + { + Copy(_destination, 0, _destination.Length(), _source, 0, _source.Length()); + } + + //Copy C-String Implementation + template + void Copy(ZBasicString& _destination, size_t _s1, size_t _e1, const char* _source, size_t _s2, size_t _e2) + { Copy(_destination, _s1, _e1, ZBasicString(_source), _s2, _e2); } + + //Copy C-String Implementation + template + void Copy(ZBasicString& _destination, const char* _source) + { Copy(_destination, ZBasicString(_source)); } + + /* + public ZBasicStringAlgo::EndsWith + + Determines if the provided range of the given string ends with the values specified in the provided + range of another string. + + @param A - allocator type for the string + @param B - allocator type for the other string + @param _string - the string to check + @param _s1 - the starting index for the destination string + @param _e1 - the ending index for the destination string (exclusive) + @param _other - the string to compare against + @param _s2 - the starting index for the source string + @param _e2 - the ending index for the source string (exclusive) + @return (bool) - true if the string ends with the provided value, false otherwise + @assert - if _s1 < _e1 or _s2 < _e2 + if _s1, _e1, _s2, or _e2 out of bounds + */ + template + bool EndsWith(const ZBasicString& _string, size_t _s1, size_t _e1, const ZBasicString& _other, size_t _s2, size_t _e2) + { + if (_s1 == _e1 || _s2 == _e2) + return false; + + const size_t s1 = _string.BoundsCheck(_s1, _string.Length()); + const size_t e1 = _string.BoundsCheck(_e1, _string.Length() + 1); + + const size_t s2 = _other.BoundsCheck(_s2, _other.Length()); + const size_t e2 = _other.BoundsCheck(_e2, _other.Length() + 1); + + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(s1 <= e1, "ZBasicStringAlgo::EndsWith - Cannot check with end < start!"); + ZSTL_ASSERT(s2 <= e2, "ZBasicStringAlgo::EndsWith - Cannot check with end < start!"); + #endif + + return ZArrayAlgo::EndsWith(_string.Array(), s1, e1, _other.Array(), s2, e2); + } + + /* + public ZBasicStringAlgo::EndsWith + + Determines if the provided string ends with the another string. + + @param A - allocator type for the string + @param B - allocator type for the other string + @param _string - the string to check + @param _s1 - the starting index for the destination string + @param _e1 - the ending index for the destination string (exclusive) + @param _other - the string to compare against + @param _s2 - the starting index for the source string + @param _e2 - the ending index for the source string (exclusive) + @return (bool) - true if the string ends with the provided value, false otherwise + @assert - if _s1 < _e1 or _s2 < _e2 + if _s1, _e1, _s2, or _e2 out of bounds + */ + template + bool EndsWith(const ZBasicString& _string, const ZBasicString& _other) + { + return EndsWith(_string, 0, _string.Length(), _other, 0, _other.Length()); + } + + //EndsWith C-String Implementation + template + bool EndsWith(const ZBasicString& _string, const char* _substring) + { return EndsWith(_string, ZBasicString(_substring)); } + + //EndsWith C-String Implementation + template + bool EndsWith(const ZBasicString& _string, size_t _s1, size_t _e1, const char* _substring, size_t _s2, size_t _e2) + { return EndsWith(_string, _s1, _e1, ZBasicString(_substring), _s2, _e2); } + + /* + public ZBasicStringAlgo::Equal + + Determines if the given range of the provided string is equal to the given range + of another string. The maximum number of characters compared is equal to the + minimum of (_e1 - _s1) or (_e2 - _s2). + + If provided a range of zero on both strings, the answer is always true. + + @param A - allocator type for the string + @param B - allocator type for the other string + @param _string - the string to check + @param _s1 - the starting index for the destination string + @param _e1 - the ending index for the destination string (exclusive) + @param _other - the string to compare against + @param _s2 - the starting index for the source string + @param _e2 - the ending index for the source string (exclusive) + @return (bool) - true if the string equals the provided value, false otherwise + @assert - if _s1 < _e1 or _s2 < _e2 + if _s1, _e1, _s2, or _e2 out of bounds + */ + template + bool Equal(const ZBasicString& _string, size_t _s1, size_t _e1, const ZBasicString& _other, size_t _s2, size_t _e2) + { + if (_e1 - _s1 == 0 && _e2 - _s2 == 0) { + return true; + } + + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(_s1 <= _e1, "ZBasicStringAlgo::Equal - Cannot compare with end < start!"); + ZSTL_ASSERT(_s2 <= _e2, "ZBasicStringAlgo::Equal - Cannot compare with end < start!"); + #endif + + const size_t s1 = _string.BoundsCheck(_s1, _string.Length()); + const size_t e1 = _string.BoundsCheck(_e1, _string.Length() + 1); + + const size_t s2 = _other.BoundsCheck(_s2, _other.Length()); + const size_t e2 = _other.BoundsCheck(_e2, _other.Length() + 1); + + + return ZArrayAlgo::Equal(_string.Array(), s1, e1, _other.Array(), s2, e2); + } + + /* + public ZBasicStringAlgo::Equal + + Determines if the given string is equal to the other string. The maximum number + of characters compared is equal to the length of the shorter string. + + @param A - allocator type for the string + @param B - allocator type for the other string + @param _string - the string to check + @param _s1 - the starting index for the destination string + @param _e1 - the ending index for the destination string (exclusive) + @param _other - the string to compare against + @param _s2 - the starting index for the source string + @param _e2 - the ending index for the source string (exclusive) + @return (bool) - true if the string equals the provided value, false otherwise + */ + template + bool Equal(const ZBasicString& _string, const ZBasicString& _other) + { + return Equal(_string, 0, _string.Length(), _other, 0, _other.Length()); + } + + //Equal C-String Implementation + template + bool Equal(const ZBasicString& _string, const char* _other) + { return Equal(_string, ZBasicString(_other)); } + + //Equal C-String Implementation + template + bool Equal(const ZBasicString& _string, size_t _s1, const char* _other, size_t _s2, size_t _count) + { return Equal(_string, _s1, ZBasicString(_other), _s2, _count); } + + /* + public ZBasicStringAlgo::EqualIgnoreCase + + Determines if the given range of the provided string is equal to the given range + of another string, ignoring the character case. The maximum number of characters + compared is equal to the minimum of (_e1 - _s1) or (_e2 - _s2). + + If provided a range of zero on both strings, the answer is always true. + + @param A - allocator type for the string + @param B - allocator type for the other string + @param _string - the string to check + @param _s1 - the starting index for the destination string + @param _e1 - the ending index for the destination string (exclusive) + @param _other - the string to compare against + @param _s2 - the starting index for the source string + @param _e2 - the ending index for the source string (exclusive) + @return (bool) - true if the string equals the provided value ignoring case, false otherwise + @assert - if _s1 < _e1 or _s2 < _e2 + if _s1, _e1, _s2, or _e2 out of bounds + */ + template + bool EqualIgnoreCase(const ZBasicString& _string, size_t _s1, size_t _e1, const ZBasicString& _other, size_t _s2, size_t _e2) + { + if (_e1 - _s1 == 0 && _e2 - _s2 == 0) { + return true; + } + + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(_s1 <= _e1, "ZBasicStringAlgo::Equal - Cannot compare with end < start!"); + ZSTL_ASSERT(_s2 <= _e2, "ZBasicStringAlgo::Equal - Cannot compare with end < start!"); + #endif + + const size_t s1 = _string.BoundsCheck(_s1, _string.Length()); + const size_t e1 = _string.BoundsCheck(_e1, _string.Length() + 1); + + const size_t s2 = _other.BoundsCheck(_s2, _other.Length()); + const size_t e2 = _other.BoundsCheck(_e2, _other.Length() + 1); + + size_t i, j; + + for (i = s1, j = s2; i < e1 && j < e2; i++, j++) + { + if ( tolower(_string.Data()[i]) != tolower(_other.Data()[j]) ) + return false; + } + + return true; + } + + /* + public ZBasicStringAlgo::EqualIgnoreCase + + Determines if the given string is equal to the other string ignoring character + case. The maximum number of characters compared is equal to the length of the + shorter string. + + @param A - allocator type for the string + @param B - allocator type for the other string + @param _string - the string to check + @param _s1 - the starting index for the destination string + @param _e1 - the ending index for the destination string (exclusive) + @param _other - the string to compare against + @param _s2 - the starting index for the source string + @param _e2 - the ending index for the source string (exclusive) + @return (bool) - true if the string equals the provided value ignoring character case, false otherwise + */ + template + bool EqualIgnoreCase(const ZBasicString& _string, const ZBasicString& _other) + { + return EqualIgnoreCase(_string, 0, _string.Length(), _other, 0, _other.Length()); + } + + //EqualIgnoreCase C-String Implementation + template + bool EqualIgnoreCase(const ZBasicString& _string, const char* _other) + { return EqualIgnoreCase(_string, ZBasicString(_other)); } + + //EqualIgnoreCase C-String Implementation + template + bool EqualIgnoreCase(const ZBasicString& _string, size_t _s1, size_t _e1, const char* _other, size_t _s2, size_t _e2) + { return EqualIgnoreCase(_string, _s1, _e1, ZBasicString(_other), _s2, _e2); } + + /* + public ZBasicStringAlgo::Fill + + Fills the provided region of the given string with the provided value. + + @param A - the allocator type for the string + @param _string - the string to fill + @param _value - the value to fill with + @param _start - the starting index + @param _end - the ending index (exclusive) + @return (void) + @assert - if _end < _start + if _start of _end out of bounds + */ + template + void Fill(ZBasicString& _string, const char& _value, size_t _start, size_t _end) + { + if (_start == _end) { + return; + } + + const size_t start = _string.BoundsCheck(_start, _string.Length()); + const size_t end = _string.BoundsCheck(_end, _string.Length() + 1); + + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(start <= end, "ZBasicStringAlgo::Fill - Cannot fill with end < start!"); + #endif + + ZArray& stringArray = const_cast< ZArray& >(_string.Array()); + + ZArrayAlgo::Fill(stringArray, _value, start, end); + } + + /* + public ZBasicStringAlgo::Fill + + Fills the string full of the provided character value. + + @param A - the allocator type for the string + @param _string - the string to fill + @param _value - the value to fill with + @return (void) + */ + template + void Fill(ZBasicString& _string, const char& _value) + { + Fill(_string, _value, 0, _string.Length()); + } + + /* + public ZBasicStringAlgo::Find + + Finds the Nth occurrence of a character in the provided region of the string. + + @param A - the allocator type for the string + @param _string - the string to search + @param _value - the value to find + @param _count - the number of occurrences which would be skipped (meaning an index to the (N+1)th occurrence is returned) + @param _start - the starting index + @param _end - the ending index (exclusive) + @return (size_t) - the index of the Nth occurrence (ZBasicString::InvalidPos if not found) + @assert - if _end < _start + if _start of _end out of bounds + */ + template + size_t Find(const ZBasicString& _string, const char& _value, size_t _count, size_t _start, size_t _end) + { + if (_start == _end) + return ZSTL::InvalidPos; + + const size_t start = _string.BoundsCheck(_start, _string.Length()); + const size_t end = _string.BoundsCheck(_end, _string.Length() + 1); + + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(start <= end, "ZBasicStringAlgo::Find - Cannot find with end < start!"); + #endif + + return ZArrayAlgo::Find(_string.Array(), _value, _count, start, end); + } + + /* + public ZBasicStringAlgo::Find + + Finds the Nth occurrence of a character in the provided string. + + @param A - the allocator type for the string + @param _string - the string to search + @param _value - the value to find + @param _count - the number of occurrences which would be skipped (meaning an index to the (N+1)th occurrence is returned) + @return (size_t) - the index of the Nth occurrence (ZBasicString::InvalidPos if not found) + */ + template + size_t Find(const ZBasicString&_string, const char& _value, size_t _count) + { + return Find(_string, _value, _count, 0, _string.Length()); + } + + /* + public ZBasicStringAlgo::FindAll + + Finds all occurrences of the provided character in the given region in the string. + + @param A - the allocator type of the string + @param _string - the string to search + @param _char - the character to look for + @param _start - the starting index + @param _end - the ending index (exclusive) + @return (ZArray) - array of indices to all occurrences of the character + @assert - if _end < _start + if _start of _end out of bounds + */ + template + ZArray FindAll(const ZBasicString& _string, const char& _char, size_t _start, size_t _end) + { + if (_start == _end) + return ZArray(); + + const size_t start = _string.BoundsCheck(_start, _string.Length()); + const size_t end = _string.BoundsCheck(_end, _string.Length() + 1); + + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(start <= end, "ZBasicStringAlgo::FindAll - Cannot find with end < start!"); + #endif + + return ZArrayAlgo::FindAll(_string.Array(), _char, start, end); + } + + /* + public ZBasicStringAlgo::FindAll + + Finds all occurrences of the provided character in the given string. + + @param A - the allocator type of the string + @param _string - the string to search + @param _char - the character to look for + @return (ZArray) - array of indices to all occurrences of the character + @assert - if _end < _start + if _start of _end out of bounds + */ + template + ZArray FindAll(const ZBasicString& _string, const char& _char) + { + return FindAll(_string, _char, 0, _string.Length()); + } + + /* + public ZBasicStringAlgo::FindAllOf + + Finds all occurrences of any of the given characters in the given region. + + @param A - the allocator type of the string + @param B - the allocator type of the values string + @param _string - the string to search + @param _s1 - the starting index in the string + @param _e1 - the ending index in the string (exclusive) + @param _values - the values to look for + @param _s2 - the starting index in the values string + @param _e2 - the ending index in the values string (exclusive) + @return (ZArray) - array of indices to all occurrences of one of the provided characters + @assert - if _s1 < _e1 or _s2 < _e2 + if _s1, _e1, _s2, or _e2 out of bounds + */ + template + ZArray FindAllOf(const ZBasicString& _string, size_t _s1, size_t _e1, const ZBasicString& _values, size_t _s2, size_t _e2) + { + if (_s1 == _e1 || _s2 == _e2) + return ZArray(); + + const size_t s1 = _string.BoundsCheck(_s1, _string.Length()); + const size_t e1 = _string.BoundsCheck(_e1, _string.Length() + 1); + + const size_t s2 = _string.BoundsCheck(_s2, _values.Length()); + const size_t e2 = _string.BoundsCheck(_e2, _values.Length() + 1); + + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(s1 <= e1, "ZBasicStringAlgo::FindAllOf - Cannot find with end < start!"); + ZSTL_ASSERT(s2 <= e2, "ZBasicStringAlgo::FindAllOf - Cannot find with end < start!"); + #endif + + return ZArrayAlgo::FindAllOf(_string.Array(), s1, e1, _values.Array(), s2, e2); + } + + /* + public ZBasicStringAlgo::FindAllOf + + Finds all occurrences of any of the given characters. + + @param A - the allocator type of the string + @param B - the allocator type of the values string + @param _string - the string to search + @param _values - the values to look for + @return (ZArray) - array of indices to all occurrences of one of the provided characters + */ + template + ZArray FindAllOf(const ZBasicString& _string, const ZBasicString& _values) + { + return FindAllOf(_string, 0, _string.Length(), _values, 0, _values.Length()); + } + + //FindAllOf C-String Implementation + template + ZArray FindAllOf(const ZBasicString& _string, size_t _s1, size_t _e1, const char* _values, size_t _s2, size_t _e2) + { + return FindAllOf(_string, _s1, _e1, ZBasicString(_values), _s2, _e2); + } + + //FindAllOf C-String Implementation + template + ZArray FindAllOf(const ZBasicString& _string, const char* _values) + { + return FindAllOf(_string, ZBasicString(_values)); + } + + /* + public ZBasicStringAlgo::FindFirst + + Finds the first occurrence of the provided value in the given region. + + @param A - the allocator type for the string + @param _string - the string to search + @param _char - the character to search for + @param _start - the starting index + @param _end - the ending index (exclusive) + @return (size_t) - the first occurrence of the given value (ZSTL::InvalidPos if not found) + @assert - if _end < _start + if _start of _end out of bounds + */ + template + size_t FindFirst(const ZBasicString& _string, const char& _char, size_t _start, size_t _end) + { + if (_start == _end) + return ZSTL::InvalidPos; + + const size_t start = _string.BoundsCheck(_start, _string.Length()); + const size_t end = _string.BoundsCheck(_end, _string.Length() + 1); + + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(start <= end, "ZBasicStringAlgo::FindFirst - Cannot find with end < start!"); + #endif + + return ZArrayAlgo::FindFirst(_string.Array(), _char, start, end); + } + + /* + public ZBasicStringAlgo::FindFirst + + Finds the first occurrence of the provided value. + + @param A - the allocator type for the string + @param _string - the string to search + @param _char - the character to search for + @return (size_t) - the first occurrence of the given value (ZSTL::InvalidPos if not found) + */ + template + size_t FindFirst(const ZBasicString& _string, const char& _char) + { + return FindFirst(_string, _char, 0, _string.Length()); + } + + /* + public ZBasicStringAlgo::FindFirstOf + + Finds the first occurrence of a set of values in the provided region of a string. + + @param A - the allocator type for the string + @param B - the allocator type for the values string + @param _string - the string to search in + @param _s1 - the starting index in the string + @param _e1 - the ending index in the string (exclusive) + @param _delimiters - the delimiters to search for + @param _s2 - the starting index in the delimiters string + @param _e2 - the ending index in the delimiters string (exclusive) + @return (size_t) - the index of the first occurrence of one of the delimiters (ZBasicString::InvalidPos if not found) + @assert - if _s1 < _e1 or _s2 < _e2 + if _s1, _e1, _s2, or _e2 out of bounds + */ + template + size_t FindFirstOf(const ZBasicString& _string, size_t _s1, size_t _e1, const ZBasicString& _delimiters, size_t _s2, size_t _e2) + { + if (_s1 == _e1 || _s2 == _e2) + return ZSTL::InvalidPos; + + const size_t s1 = _string.BoundsCheck(_s1, _string.Length()); + const size_t e1 = _string.BoundsCheck(_e1, _string.Length() + 1); + + const size_t s2 = _string.BoundsCheck(_s2, _delimiters.Length()); + const size_t e2 = _string.BoundsCheck(_e2, _delimiters.Length() + 1); + + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(s1 <= e1, "ZBasicStringAlgo::FindFirstOf - Cannot find with end < start!"); + ZSTL_ASSERT(s2 <= e2, "ZBasicStringAlgo::FindFirstOf - Cannot find with end < start!"); + #endif + + return ZArrayAlgo::FindFirstOf(_string.Array(), s1, e1, _delimiters.Array(), s2, e2); + } + + //FindFirstOf C-String Implementation + template + size_t FindFirstOf(const ZBasicString& _string, const ZBasicString& _values, size_t _start, size_t _end) + { return FindFirstOf(_string, 0, _string.Length(), ZBasicString(_values), _start, _end); } + + /* + public ZBasicStringAlgo::FindFirstOf + + Finds the first occurrence of a set of values in the provided region + + @param A - the allocator type for the string + @param B - the allocator type for the values string + @param _string - the string to search in + @param _delimiters - the decimeters to search for + @return (size_t) - the index of the first occurrence of one of the delimiters (ZBasicString::InvalidPos if not found) + */ + template + size_t FindFirstOf(const ZBasicString& _string, const ZBasicString& _delimiters) + { + return FindFirstOf(_string, 0, _string.Length(), _delimiters, 0, _delimiters.Length()); + } + + //FindFirstOf C-String Implementation + template + size_t FindFirstOf(const ZBasicString& _string, const char* _delimiters) + { return FindFirstOf(_string, ZBasicString(_delimiters)); } + + //FindFirstOf C-String Implementation + template + size_t FindFirstOf(const ZBasicString& _string, size_t _s1, size_t _e1, const char* _delimiters, size_t _s2, size_t _e2) + { return FindFirstOf(_string, _s1, _e1, ZBasicString(_delimiters), _s2, _e2); } + + /* + public ZBasicStringAlgo::FindFirstNot + + Finds the first occurrence of a value that is not the provided value in the given + region of the string. + + @param A - the allocator type of the string + @param _string - the string to search + @param _char - the character to avoid + @param _start - the starting index + @param _end - the ending index (exclusive) + @return (size_t) - the index of the first value that is not the provided value (ZBasicString::InvalidPos if not found) + @assert - if _end < _start + if _start of _end out of bounds + */ + template + size_t FindFirstNot(const ZBasicString& _string, const char& _char, size_t _start, size_t _end) + { + if (_start == _end) + return ZSTL::InvalidPos; + + const size_t start = _string.BoundsCheck(_start, _string.Length()); + const size_t end = _string.BoundsCheck(_end, _string.Length() + 1); + + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(start <= end, "ZBasicStringAlgo::FindFirstNot - Cannot find with end < start!"); + #endif + + return ZArrayAlgo::FindFirstNot(_string.Array(), _char, start, end); + } + + /* + public ZBasicStringAlgo::FindFirstNot + + Finds the first occurrence of a value that is not the provided value in the given + region of the string. + + @param A - the allocator type of the string + @param _string - the string to search + @param _char - the character to avoid + @return (size_t) - the index of the first value that is not the provided value (ZBasicString::InvalidPos if not found) + */ + template + size_t FindFirstNot(const ZBasicString& _string, const char& _char) + { + return FindFirstNot(_string, _char, 0, _string.Length()); + } + + /* + public ZBasicStringAlgo::FindFirstNotOf + + Finds the first occurrence of a value that is not one of a set of values + in the provided region of a string. + + @param A - the allocator type for the string + @param B - the allocator type for the values string + @param _string - the string to search in + @param _s1 - the starting index in the string + @param _e1 - the ending index in the string (exclusive) + @param _delimiters - the delimiters to avoid + @param _s2 - the starting index in the delimiters string + @param _e2 - the ending index in the delimiters string (exclusive) + @return (size_t) - the index of the first occurrence of a value that is not one of the delimiters (ZBasicString::InvalidPos if not found) + @assert - if _s1 < _e1 or _s2 < _e2 + if _s1, _e1, _s2, or _e2 out of bounds + */ + template + size_t FindFirstNotOf(const ZBasicString& _string, size_t _s1, size_t _e1, const ZBasicString& _delimiters, size_t _s2, size_t _e2) + { + if (_s1 == _e1 || _s2 == _e2) + return ZSTL::InvalidPos; + + const size_t s1 = _string.BoundsCheck(_s1, _string.Length()); + const size_t e1 = _string.BoundsCheck(_e1, _string.Length() + 1); + + const size_t s2 = _string.BoundsCheck(_s2, _delimiters.Length()); + const size_t e2 = _string.BoundsCheck(_e2, _delimiters.Length() + 1); + + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(s1 <= e1, "ZBasicStringAlgo::FindFirstNotOf - Cannot find with end < start!"); + ZSTL_ASSERT(s2 <= e2, "ZBasicStringAlgo::FindFirstNotOf - Cannot find with end < start!"); + #endif + + return ZArrayAlgo::FindFirstNotOf(_string.Array(), s1, e1, _delimiters.Array(), s2, e2); + } + + /* + public ZBasicStringAlgo::FindFirstNotOf + + Finds the first occurrence of a value that is not one of a set of values + in the provided region of a string. + + @param A - the allocator type for the string + @param B - the allocator type for the values string + @param _string - the string to search in + @param _delimiters - the delimiters to avoid + @return (size_t) - the index of the first occurrence of a value that is not one of the delimiters (ZBasicString::InvalidPos if not found) + */ + template + size_t FindFirstNotOf(const ZBasicString& _string, const ZBasicString& _delimiters) + { + return FindFirstNotOf(_string, 0, _string.Length(), _delimiters, 0, _delimiters.Length()); + } + + //FindFirstNotOf C-String Implementation + template + size_t FindFirstNotOf(const ZBasicString& _string, const char* _delimiters) + { return FindFirstNotOf(_string, ZBasicString(_delimiters)); } + + //FindFirstNotOf C-String Implementation + template + size_t FindFirstNotOf(const ZBasicString& _string, size_t _s1, size_t _e1, const char* _delimiters, size_t _s2, size_t _e2) + { return FindFirstNotOf(_string, _s1, _e1, ZBasicString(_delimiters), _s2, _e2); } + + /* + public ZBasicStringAlgo::FindLast + + Finds the last occurrence of the specified value in the given range of the string. + + @param A - the allocator type of the string + @param _string - the string to search + @param _char - the value to find + @param _start - the starting index + @param _end - the ending index (exclusive) + @return (size_t) - the index of hte last occurence of the specified value (ZBasicString::InvalidPos if not found) + @assert - if _end < _start + if _start of _end out of bounds + */ + template + size_t FindLast(const ZBasicString& _string, const char& _char, size_t _start, size_t _end) + { + if (_start == _end) + return ZSTL::InvalidPos; + + const size_t start = _string.BoundsCheck(_start, _string.Length()); + const size_t end = _string.BoundsCheck(_end, _string.Length() + 1); // 1 to allow indexing of end + + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(start <= end, "ZBasicStringAlgo::FindLast - Cannot find with end < start!"); + #endif + + return ZArrayAlgo::FindLast(_string.Array(), _char, start, end); + } + + /* + public ZBasicStringAlgo::FindLast + + Finds the last occurrence of the specified value in the string. + + @param A - the allocator type for the string + @param _string - the string to search + @param _char - the value to find + @return (size_t) - index of the last occurrence (ZBasicString::InvalidPos if not found) + */ + template + size_t FindLast(const ZBasicString& _string, const char& _char) + { + return FindLast(_string, _char, 0, _string.Length()); + } + + /* + public ZBasicStringAlgo::FindLastOf + + Finds the last occurrence of a set of values in the provided region of a string. + + @param A - the allocator type for the string + @param B - the allocator type for the values string + @param _string - the string to search in + @param _s1 - the starting index in the string + @param _e1 - the ending index in the string (exclusive) + @param _delimiters - the delimiters to search for + @param _s2 - the starting index in the delimiters string + @param _e2 - the ending index in the delimiters string (exclusive) + @return (size_t) - the index of the last occurrence of one of the delimiters (ZBasicString::InvalidPos if not found) + @assert - if _s1 < _e1 or _s2 < _e2 + if _s1, _e1, _s2, or _e2 out of bounds + */ + template + size_t FindLastOf(const ZBasicString& _string, size_t _s1, size_t _e1, const ZBasicString& _values, size_t _s2, size_t _e2) + { + if (_s1 == _e1 || _s2 == _e2) + return ZSTL::InvalidPos; + + const size_t s1 = _string.BoundsCheck(_s1, _string.Length()); + const size_t e1 = _string.BoundsCheck(_e1, _string.Length() + 1); // 1 to allow indexing of end + + const size_t s2 = _values.BoundsCheck(_s2, _values.Length()); + const size_t e2 = _values.BoundsCheck(_e2, _values.Length() + 1); // 1 to allow indexing of end + + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(s1 <= e1, "ZBasicStringAlgo::FindLastOf - Cannot find with e1 < s1!"); + ZSTL_ASSERT(s2 <= e2, "ZBasicStringAlgo::FindLasttOf - Cannot find with e2 < s2!"); + #endif + + return ZArrayAlgo::FindLastOf(_string.Array(), s1, e1, _values.Array(), s2, e2); + } + + /* + public ZBasicStringAlgo::FindLastOf + + Finds the last occurrence of a set of values in the provided string. + + @param A - the allocator type for the string + @param B - the allocator type for the values string + @param _string - the string to search in + @param _delimiters - the delimiters to search for + @return (size_t) - the index of the last occurrence of one of the delimiters (ZBasicString::InvalidPos if not found) + */ + template + size_t FindLastOf(const ZBasicString& _string, const ZBasicString& _values) + { + return FindLastOf(_string, 0, _string.Length(), _values, 0, _values.Length()); + } + + //FindLastOf C-String Implementation + template + size_t FindLastOf(const ZBasicString& _string, size_t _s1, size_t _e1, const char* _values, size_t _s2, size_t _e2) + { + return FindLastOf(_string, _s1, _e1, ZBasicString(_values), _s2, _e2); + } + + //FindLastOf C-String Implementation + template + size_t FindLastOf(const ZBasicString& _string, const char* _values) + { + return FindLastOf(_string, ZBasicString(_values)); + } + + /* + public ZBasicStringAlgo::FindLastNot + + Finds the last occurrence of a value that is not the provided value in the given + region of the string. + + @param A - the allocator type of the string + @param _string - the string to search + @param _char - the character to avoid + @param _start - the starting index + @param _end - the ending index (exclusive) + @return (size_t) - the index of the last value that is not the provided value (ZBasicString::InvalidPos if not found) + @assert - if _end < _start + if _start of _end out of bounds + */ + template + size_t FindLastNot(const ZBasicString& _string, const char& _char, size_t _start, size_t _end) + { + if (_start == _end) + return ZSTL::InvalidPos; + + const size_t start = _string.BoundsCheck(_start, _string.Length()); + const size_t end = _string.BoundsCheck(_end, _string.Length() + 1); // 1 to allow indexing of end + + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(start <= end, "ZBasicStringAlgo::FindLastNot - Cannot find with end < start!"); + #endif + + return ZArrayAlgo::FindLastNot(_string.Array(), _char, start, end); + } + + /* + public ZBasicStringAlgo::FindLastNot + + Finds the last occurrence of a value that is not the provided value in the given string. + + @param A - the allocator type of the string + @param _string - the string to search + @param _char - the character to avoid + @return (size_t) - the index of the last value that is not the provided value (ZBasicString::InvalidPos if not found) + */ + template + size_t FindLastNot(const ZBasicString& _string, const char& _char) + { + return FindLastNot(_string, _char, 0, _string.Length()); + } + + /* + public ZBasicStringAlgo::FindLastNotOf + + Finds the last occurrence of a value that is not one of a set of values + in the provided region of a string. + + @param A - the allocator type for the string + @param B - the allocator type for the values string + @param _string - the string to search in + @param _s1 - the starting index in the string + @param _e1 - the ending index in the string (exclusive) + @param _delimiters - the delimiters to avoid + @param _s2 - the starting index in the delimiters string + @param _e2 - the ending index in the delimiters string (exclusive) + @return (size_t) - the index of the last occurrence of a value that is not one of the delimiters (ZBasicString::InvalidPos if not found) + @assert - if _s1 < _e1 or _s2 < _e2 + if _s1, _e1, _s2, or _e2 out of bounds + */ + template + size_t FindLastNotOf(const ZBasicString& _string, size_t _s1, size_t _e1, const ZBasicString& _values, size_t _s2, size_t _e2) + { + if (_s1 == _e1 || _s2 == _e2) + return ZSTL::InvalidPos; + + const size_t s1 = _string.BoundsCheck(_s1, _string.Length()); + const size_t e1 = _string.BoundsCheck(_e1, _string.Length() + 1); // 1 to allow indexing of end + + const size_t s2 = _values.BoundsCheck(_s2, _values.Length()); + const size_t e2 = _values.BoundsCheck(_e2, _values.Length() + 1); // 1 to allow indexing of end + + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(s1 <= e1, "ZBasicStringAlgo::FindLastNotOf - Cannot find with e1 < s1!"); + ZSTL_ASSERT(s2 <= e2, "ZBasicStringAlgo::FindLastNotOf - Cannot find with e2 < s2!"); + #endif + + return ZArrayAlgo::FindLastNotOf(_string.Array(), s1, e1, _values.Array(), s2, e2); + } + + /* + public ZBasicStringAlgo::FindLastNotOf + + Finds the last occurrence of a value that is not one of a set of values + in the provided region of a string. + + @param A - the allocator type for the string + @param B - the allocator type for the values string + @param _string - the string to search in + @param _delimiters - the delimiters to avoid + @return (size_t) - the index of the last occurrence of a value that is not one of the delimiters (ZBasicString::InvalidPos if not found) + */ + template + size_t FindLastNotOf(const ZBasicString& _string, const ZBasicString& _values) + { + return FindLastNotOf(_string, 0, _string.Length(), _values, 0, _values.Length()); + } + + //FindLastNotOf C-String Implementation + template + size_t FindLastNotOf(const ZBasicString& _string, size_t _s1, size_t _e1, const char* _values, size_t _s2, size_t _e2) + { + return FindLastNotOf(_string, _s1, _e1, ZBasicString(_values), _s2, _e2); + } + + //FindLastNotOf C-String Implementation + template + size_t FindLastNotOf(const ZBasicString& _string, const char* _values) + { + return FindLastNotOf(_string, ZBasicString(_values)); + } + + /* + public ZBasicStringAlgo::FindSub + + Finds the first occurrence of a substring in the provided region in the string. + + @param A - the allocator type for the string + @param B - the allocator type for the substring + @param _string - the string to search in + @param _s1 - the starting index + @param _e1 - the ending index (exclusive) + @param _substring - the substring to search for + @param _s2 - the starting index in the substring + @param _e2 - the ending index in the substring + @return (size_t) - the index of the first occurrence of the substring (ZBasicString::InvalidPos if not found) + @assert - if _s1 < _e1 or _s2 < _e2 + if _s1, _e1, _s2, or _e2 out of bounds + */ + template + size_t FindSub(const ZBasicString& _string, size_t _s1, size_t _e1, const ZBasicString& _substring, size_t _s2, size_t _e2) + { + if (_s1 == _e1 || _s2 == _e2) + return ZSTL::InvalidPos; + + const size_t s1 = _string.BoundsCheck(_s1, _string.Length()); + const size_t e1 = _string.BoundsCheck(_e1, _string.Length() + 1); + + const size_t s2 = _string.BoundsCheck(_s2, _substring.Length()); + const size_t e2 = _string.BoundsCheck(_e2, _substring.Length() + 1); + + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(s1 <= e1, "ZBasicStringAlgo::FindSub - Cannot find with end < start!"); + ZSTL_ASSERT(s2 <= e2, "ZBasicStringAlgo::FindSub - Cannot find with end < start!"); + #endif + + return ZArrayAlgo::FindSub(_string.Array(), s1, e1, _substring.Array(), s2, e2); + } + + /* + public ZBasicStringAlgo::FindSub + + Finds the first occurrence of a substring in the provided string. + + @param A - the allocator type for the string + @param B - the allocator type for the substring + @param _string - the string to search in + @param _substring - the substring to search for + @return (size_t) - the index of the first occurrence of the substring (ZBasicString::InvalidPos if not found) + */ + template + size_t FindSub(const ZBasicString& _string, const ZBasicString& _substring) + { + return FindSub(_string, 0, _string.Length(), _substring, 0, _substring.Length()); + } + + //FindSub C-String Implementation + template + size_t FindSub(const ZBasicString& _string, const char* _substring) + { return FindSub(_string, ZBasicString(_substring)); } + + //FindSub C-String Implementation + template + size_t FindSub(const ZBasicString& _string, size_t _s1, size_t _e1, const char* _substring, size_t _s2, size_t _e2) + { return FindSub(_string, _s1, _e1, ZBasicString(_substring), _s2, _e2); } + + /* + public ZBasicString::IsNumeric + + Determines if a range of this string represents a numeric quantity. + + @param A - the allocator type for the string + @param _string - the string to check + @param _start - the starting point + @param _end - the ending point (exclusive) + @return (bool) - true if this string is numeric, false otherwise + @assert - if _end < _start + if _start of _end out of bounds + */ + template + bool IsNumeric(const ZBasicString& _string, size_t _start, size_t _end) + { + if (_start == _end) + return false; + + const size_t start = _string.BoundsCheck(_start, _string.Length()); + const size_t end = _string.BoundsCheck(_end, _string.Length() + 1); + + bool digitSeen = false; + bool decimalPointSeen = false; + + const char* string = _string.Array().Data(); + + //Ensure we see [-]?[0-9]+[.]?[0-9]* + // * := 0 or more times + // + := 1 or more times + // ? := 0 or 1 times + + //May begin with '-' or digit. + if(string[start] != '-') + { + if(!isdigit(string[start])) + return false; + + digitSeen = true; + } + + /* + Algorithm: Since we know we have either seen a digit or negative sign, + scan for more digits and an optional decimal point, allowing only + a single decimal point. If we terminate the loop before seeing a single + digit, and we didn't see one before checking for the negative sign, then + return false. + */ + for(size_t i = start+ 1; i < end; i++) + { + //Not a digit? + if(!isdigit(string[i])) + { + //Only allow 1 decimal point + if(!decimalPointSeen && string[i] == '.') + { + decimalPointSeen = true; + continue; + } + + //Not numeric + return false; + } + else + digitSeen = true; + } + + //Must have seen at least one digit for this to be considered numeric. + return digitSeen; + } + + /* + public ZBasicStringAlgo::IsNumeric + + Determines if this string represents a numeric quantity. + + @param A - the allocator type for the string + @param _string - the string to check + @return (bool) - true if this string is numeric, false otherwise + */ + template + bool IsNumeric(const ZBasicString& _string) + { + return IsNumeric(_string, 0, _string.Length()); + } + + /* + public ZBasicStringAlgo::IsNumeric + + Returns the numeric integer value of this string. Empty strings are treated as + zero. + + @param A - the allocator type for the string + @param _string - the string to convert to an integer value + @param _start - the starting index for the string + @param _end - the ending index for the string + @return (int) - the integer value of the string + */ + template + int NumericInt(const ZBasicString& _string, size_t _start, size_t _end) + { + if (_start == _end) { + return 0; + } + + const size_t start = _string.BoundsCheck(_start, _string.Length()); + const size_t end = _string.BoundsCheck(_end, _string.Length() + 1); + + char tmp = _string.Data()[end]; + + _string.Data()[end] = ZBASICSTRING_NULL_TERMINATOR; //Don't worry, we'll put it back + + int val = atoi(_string.Data() + start); + + _string.Data()[end] = tmp; + + return val; + } + + /* + + */ + template + int NumericInt(const ZBasicString& _string) + { + return NumericInt(_string, 0, _string.Length()); + } + + /* + + */ + template + double NumericDouble(const ZBasicString& _string, size_t _start, size_t _end) + { + const size_t start = _string.BoundsCheck(_start, _string.Length()); + const size_t end = _string.BoundsCheck(_end, _string.Length() + 1); + + char tmp = _string.Data()[end]; + + _string.Data()[end] = ZBASICSTRING_NULL_TERMINATOR; //Don't worry, we'll put it back + + double val = atof(_string.Data() + start); + + _string.Data()[end] = tmp; + + return val; + } + + /* + + */ + template + double NumericDouble(const ZBasicString& _string) + { + return NumericDouble(_string, 0, _string.Length()); + } + + /* + + */ + template + float NumericFloat(const ZBasicString& _string, size_t _start, size_t _end) + { + return (float)NumericDouble(_string, _start, _end); + } + + /* + + */ + template + float NumericFloat(const ZBasicString& _string) + { + return NumericFloat(_string, 0, _string.Length()); + } + + + /* + public ZBasicStringAlgo::Remove + + Removes the first occurrence of a provided character from the given region in this string. + + @param A - the allocator type for the string + @param _string - the string to remove characters from + @param _char - the character to remove + @param _start - the starting index + @param _end - the ending index (exclusive) + @return (size_t) - the index of the first removed character (ZBasicString::InvalidPos if none removed) + @assert - if _end < _start + if _start of _end out of bounds + */ + template + size_t Remove(ZBasicString& _string, const char& _char, size_t _start, size_t _end) + { + if (_start == _end) + return ZSTL::InvalidPos; + + const size_t start = _string.BoundsCheck(_start, _string.Length()); + const size_t end = _string.BoundsCheck(_end, _string.Length() + 1); + + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(start <= end, "ZBasicStringAlgo::Remove - Cannot remove with end < start!"); + #endif + + ZArray& stringArray = const_cast< ZArray& >(_string.Array()); + + return ZArrayAlgo::Remove(stringArray, _char, start, end); + } + + /* + public ZBasicStringAlgo::Remove + + Removes the first occurrence of a provided character from this string. + + @param A - the allocator type for the string + @param _string - the string to remove characters from + @param _char - the character to remove + @return (size_t) the index of the first removed character (ZBasicString::InvalidPos if none removed) + */ + template + size_t Remove(ZBasicString& _string, const char& _char) + { + return Remove(_string, _char, 0, _string.Length()); + } + + /* + public ZBasicStringAlgo::RemoveAll + + Removes all occurrences of a provided character from this string in the given region. + + @param A - the allocator type for the string + @param _string - the string to remove characters from + @param _char - the character to remove + @param _start - the starting index + @param _end - the ending index (exclusive) + @return (size_t) - the number of characters removed + @assert - if _end < _start + if _start of _end out of bounds + */ + template + size_t RemoveAll(ZBasicString& _string, const char& _char, size_t _start, size_t _end) + { + if (_start == _end) + return 0; + + const size_t start = _string.BoundsCheck(_start, _string.Length()); + const size_t end = _string.BoundsCheck(_end, _string.Length() + 1); + + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(start <= end, "ZBasicStringAlgo::RemoveAll - Cannot remove with end < start!"); + #endif + + ZArray& stringArray = const_cast< ZArray& >(_string.Array()); + + return ZArrayAlgo::RemoveAll(stringArray, _char, start, end); + } + + + /* + public ZBasicStringAlgo::RemoveAll + + Removes all occurrences of a provided character from this string. + + @param A - the allocator type for the string + @param _string - the string to remove characters from + @param _char - the character to remove + @return (size_t) - the number of characters removed + */ + template + size_t RemoveAll(ZBasicString& _string, const char& _char) + { + return RemoveAll(_string, _char, 0, _string.Length()); + } + + /* + public ZBasicStringAlgo::RemoveUpTo + + Removes up to the provided number of occurrences of a character from the string in + the specified range. + + @param A - the allocator type of the string + @param _string - the string to remove elements from + @param _char - the char to look for + @param _count - the maximum number of times to remove the char + @param _start - the index to start at + @param _end - the ending index (exclusive) + @return (size_t) - the number of occurrences removed + @assert - if _end < _start + if _start or _end out of bounds + */ + template + size_t RemoveUpTo(ZBasicString& _string, const char& _char, size_t _count, size_t _start, size_t _end) + { + if (_start == _end || _count == 0) + return 0; + + const size_t start = _string.BoundsCheck(_start, _string.Length()); + const size_t end = _string.BoundsCheck(_end, _string.Length() + 1); // 1 to allow indexing of end + + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(start <= end, "ZBasicStringAlgo::RemoveUpTo - Cannot remove with end < start!"); + #endif + + ZArray& stringArray = const_cast< ZArray& >(_string.Array()); + + return ZArrayAlgo::RemoveUpTo(stringArray, _char, _count, start, end); + } + + /* + public ZBasicStringAlgo::RemoveUpTo + + Removes up to the provided number of occurrences of a character from the string. + + @param A - the allocator type of the string + @param _string - the _string to remove elements from + @param _char - the character to look for + @param _count - the maximum number of times to remove the char + @return (size_t) - the number of occurrences removed + */ + template + size_t RemoveUpTo(ZBasicString& _string, const char& _char, size_t _count) + { + return RemoveUpTo(_string, _char, _count, 0, _string.Length()); + } + + /* + public ZBasicStringAlgo::Replace + + Finds and replaces all occurrences of the provided character with another in the given region. + + @param A - the allocator type of the string + @param _string - the string to replace chars in + @param _char - the char to look for + @param _newValue - the char to replace with + @param _start - the starting index + @param _end - the ending index (exclusive) + @return (size_t) - the number of chars replaced + @assert - if _end < _start + if _start or _end out of bounds + */ + template + size_t Replace(ZBasicString& _string, const char& _char, const char& _newChar, size_t _start, size_t _end) + { + if (_start == _end) + return 0; + + const size_t start = _string.BoundsCheck(_start, _string.Length()); + const size_t end = _string.BoundsCheck(_end, _string.Length() + 1); // 1 to allow indexing of end + + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(start <= end, "ZBasicStringAlgo::Replace - Cannot replace with end < start!"); + #endif + + ZArray& stringArray = const_cast< ZArray& >(_string.Array()); + + return ZArrayAlgo::Replace(stringArray, _char, _newChar, start, end); + } + + /* + public ZBasicStringAlgo::Replace + + Finds and replaces all occurrences of the provided character with another. + + @param T - the type held by the string + @param A - the allocator type of the string + @param _string - the string to replace chars in + @param _char - the char to look for + @param _newValue - the char to replace with + @return (size_t) - the number of chars replaced + */ + template + size_t Replace(ZBasicString& _string, const char& _char, const char& _newChar) + { + return Replace(_string, _char, _newChar, 0, _string.Length()); + } + + /* + public ZBasicStringAlgo::Reverse + + Reverses an string in place between the given indices. + + @param A - the allocator type of the string + @param _string - the string to reverse + @param _start - the starting index + @param _end - the ending index (exclusive) + @return (void) + @assert - if _end < _start + if _start or _end out of bounds + */ + template + void Reverse(ZBasicString& _string, size_t _start, size_t _end) + { + if (_start == _end) + return; + + const size_t start = _string.BoundsCheck(_start, _string.Length()); + const size_t end = _string.BoundsCheck(_end, _string.Length() + 1); // 1 to allow indexing of end + + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(start <= end, "ZBasicStringAlgo::Reverse - Cannot reverse with end < start!"); + #endif + + ZArray& stringArray = const_cast< ZArray& >(_string.Array()); + + ZArrayAlgo::Reverse(stringArray, start, end); + } + + /* + public ZBasicStringAlgo::Reverse + + Reverses an string in place. + + @param A - the allocator type of the string + @param _string - the string to reverse + @return (void) + */ + template + void Reverse(ZBasicString& _string) + { + Reverse(_string, 0, _string.Length()); + } + + /* + public ZBasicStringAlgo::Slice + + Removes and returns a given region of a string as a new string. + + @param A - the allocator type of the string + @param _string - the string to slice + @param _start - the starting index + @param _end - the ending index (exclusive) + @return (ZBasicString) - the removed region + @assert - if _end < _start + if _start or _end out of bounds + */ + template + ZBasicString Slice(ZBasicString& _string, size_t _start, size_t _end) + { + if (_start == _end) + return ZBasicString(); + + const size_t start = _string.BoundsCheck(_start, _string.Length()); + const size_t end = _string.BoundsCheck(_end, _string.Length() + 1); + + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(start <= end, "ZBasicStringAlgo::Slice - Cannot slice with end < start!"); + #endif + + ZArray& stringArray = const_cast&>(_string.Array()); + + ZArray slice = ZArrayAlgo::Slice(stringArray, start, end); + slice.PushBack('\0'); + return ZBasicString(slice); + } + + /* + public ZBasicStringAlgo::Split + + Splits the provided range of the given string into a set of strings anywhere a + delimiter occurs up to a maximum number of times. This will omit empty strings, + such as those caused by having two or more delimiters adjacent. + + @param A - the allocator type of the string + @param B - the allocator type for the delimiter string + @param _string - the string to split + @param _delimiters - the delimiters to split on + @param _count - the maximum number of times to split + @param _start - the starting index + @param _end - the ending index (exclusive) + @return (ZArray< ZBasicString >) - array of strings + @assert - if _end < _start + if _start or _end out of bounds + */ + template + ZArray< ZBasicString > Split(const ZBasicString& _string, const ZBasicString& _delimiters, size_t _count, size_t _start, size_t _end) + { + if (_start == _end || _count == 0) + return ZArray< ZBasicString >(); + + ZArray< ZBasicString > sections(_string.Length() + 1); + + const size_t start = _string.BoundsCheck(_start, _string.Length()); + const size_t end = _string.BoundsCheck(_end, _string.Length() + 1); // 1 to allow indexing of end + + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(start <= end, "ZBasicStringAlgo::Split - Cannot split with end < start!"); + #endif + + size_t previous = start; + + for (size_t i = start; i < end ; i++) + { + for (size_t j = 0; j < _delimiters.Length(); j++) + { + if ( _string.Data()[i] == _delimiters.Data()[j] ) + { + if (i > previous) //If we have more than just one of the delimiters + { + ZBasicString section = ZBasicString(_string, previous, i); + sections.PushBack( section ); + } + + if (sections.Size() == _count ) //Break out if we have reached our count limit + { + previous = i + 1; + goto breakOut; // we need to leave at this point + break; + } + previous = i + 1; + break; + } + } + } + +breakOut: // breakout from hitting our split count + if (previous != end) //Add the final section if we don't end on a delimiter + sections.PushBack( ZBasicString(_string, previous, end) ); + + return sections; + } + + /* + public ZBasicStringAlgo::Split + + Splits the given string into a set of strings anywhere a delimiter occurs up + to a maximum number of times. This will omit empty strings, such as those + caused by having two or more delimiters adjacent. + + @param A - the allocator type of the string + @param B - the allocator type for the delimiter string + @param _string - the string to split + @param _delimiters - the delimiters to split on + @param _count - the maximum number of times to split + @return (ZArray< ZBasicString >) - array of strings + */ + template + ZArray< ZBasicString > Split(const ZBasicString& _string, const ZBasicString& _delims, size_t _count) + { + return Split(_string, _delims, _count, 0, _string.Length()); + } + + /* + public ZBasicStringAlgo::Split + + Splits the given string into a set of strings anywhere a delimiter occurs. + This will omit empty strings, such as those caused by having two or more + delimiters adjacent. + + @param A - the allocator type of the string + @param B - the allocator type for the delimiter string + @param _string - the string to split + @param _delimiters - the delimiters to split on + @param _count - the maximum number of times to split + @return (ZArray< ZBasicString >) - array of strings + */ + template + ZArray< ZBasicString > Split(const ZBasicString& _string, const ZBasicString& _delims) + { + return Split(_string, _delims, _string.Length(), 0, _string.Length()); + } + + //Split C-String Implementation + template + ZArray< ZBasicString > Split(const ZBasicString& _string, const char* _delims) + { return Split(_string, ZBasicString(_delims)); } + + //Split C-String Implementation + template + ZArray< ZBasicString > Split(const ZBasicString& _string, const char* _delims, size_t _count) + { return Split(_string, ZBasicString(_delims), _count); } + + //Split C-String Implementation + template + ZArray< ZBasicString > Split(const ZBasicString& _string, const char* _delims, size_t _count, size_t _start, size_t _end) + { return Split(_string, ZBasicString(_delims), _count, _start, _end); } + + /* + public ZBasicStringAlgo::StartsWith + + Determines if the provided region of a string starts with the given region of a substring. + + @param A - the allocator type for the string + @param B - the allocator type for the substring + @param _string - the string to check + @param _s1 - the starting index for the string + @param _e1 - the ending index for the string (exclusive) + @param _substring - the substring to check + @param _s2 - the starting index for the substring + @param _e2 - the ending index for the substring (exclusive) + @return (bool) - true if the string starts with the given substring, false otherwise + @assert - if _s1 < _e1 or _s2 < _e2 + if _s1, _e1, _s2, or _e2 out of bounds + */ + template + bool StartsWith(const ZBasicString& _string, size_t _s1, size_t _e1, const ZBasicString& _substring, size_t _s2, size_t _e2) + { + if (_s1 == _e1 || _s2 == _e2) + return false; + + const size_t s1 = _string.BoundsCheck(_s1, _string.Length()); + const size_t e1 = _string.BoundsCheck(_e1, _string.Length() + 1); + + const size_t s2 = _string.BoundsCheck(_s2, _substring.Length()); + const size_t e2 = _string.BoundsCheck(_e2, _substring.Length() + 1); + + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(s1 <= e1, "ZBasicStringAlgo::StartsWith - Cannot check with end < start!"); + ZSTL_ASSERT(s2 <= e2, "ZBasicStringAlgo::StartsWith - Cannot check with end < start!"); + #endif + + // easy check: can substring fit into string? + if (e1 - s1 < e2 - s2) + return false; + + return ZArrayAlgo::StartsWith(_string.Array(), s1, e1, _substring.Array(), s2, e2); + } + + /* + public ZBasicStringAlgo::StartsWith + + Determines if the provided string starts with the given substring. + + @param A - the allocator type for the string + @param B - the allocator type for the substring + @param _string - the string to check + @param _substring - the substring to check + @return (bool) - true if the string starts with the given substring, false otherwise + */ + template + bool StartsWith(const ZBasicString& _string, const ZBasicString& _substring) + { + return StartsWith(_string, 0, _string.Length(), _substring, 0, _substring.Length()); + } + + //StartsWith C-String Implementation + template + bool StartsWith(const ZBasicString& _string, const char *_substring) + { return StartsWith(_string, ZBasicString(_substring)); } + + //StartsWith C-String Implementation + template + bool StartsWith(const ZBasicString& _string, size_t _s1, size_t _e1, const char* _substring, size_t _s2, size_t _e2) + { return StartsWith(_string, _s1, _e1, ZBasicString(_substring), _s2, _e2); } + + /* + public ZBasicStringAlgo::Strip + + Removes all whitespace from the provided region of a string. + + @param A - the allocator type of the string + @param _string - the string to strip + @param _start - the starting index + @param _end - the ending index (exclusive) + @return (size_t) - the number of whitespace characters removed + @assert - if _end < _start + if _start or _end out of bounds + */ + template + size_t Strip(ZBasicString& _string, size_t _start, size_t _end) + { + if (_start == _end) + return 0; + + const size_t start = _string.BoundsCheck(_start, _string.Length()); + const size_t end = _string.BoundsCheck(_end, _string.Length() + 1); + + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(start <= end, "ZBasicStringAlgo::Strip - Cannot strip whitepsace with end < start!"); + #endif + + ZArray& stringArray = const_cast< ZArray& >(_string.Array()); + + size_t removed = 0; + + // remove spaces + removed += ZArrayAlgo::RemoveAll(stringArray, ' ', start, end); + + // remove tabs (remember that you have to decrement the end counter to stay in bounds) + removed += ZArrayAlgo::RemoveAll(stringArray, '\t', start, end - removed); + + return removed; + } + + /* + public ZBasicStringAlgo::Strip + + Removes all whitespace from the provided string. + + @param A - the allocator type of the string + @param _string - the string to strip + @return (size_t) - the number of whitespace characters removed + */ + template + size_t Strip(ZBasicString& _string) + { + + return Strip(_string, 0, _string.Length()); + } + + /* + public ZBasicString::Tokenize + + Tokenize function, which returns the next token in this string up to + the delimiter, consuming the occurrence of the delimiter in the process. + This may emit empty strings, such as those caused by having two or + more delimiters adjacent. + + @param A - the allocator type of the string + @param _delims - the delimiters to look for + @return (ZBasicString) - the token + */ + template + ZBasicString Tokenize(ZBasicString& _string, const ZBasicString& _delims) + { + if (_string.Empty()) + return ZBasicString(); + + if (_delims.Empty()) + { + ZBasicString ret = _string; + _string.Clear(); + return ret; + } + + size_t tokend = ZSTL::InvalidPos; + size_t i, j; + ZBasicString token; + + for(i = 0; i < _string.Length(); i++) + { + for (j = 0; j < _delims.Length(); j++) + { + if (_string.At(i) == _delims.At(j)) + { + tokend = i; + i = _string.Length() - 1; // forces us to break out of the outer loop + break; + } + } + } + + // we found no delimiters :( + if (tokend == ZSTL::InvalidPos) + { + token = _string; + _string.Clear(); + return token; + } + + // we found a delimiter first + if (tokend == 0) + { + _string.Erase(0); + return ZBasicString(); + } + + //Grab that token + token = ZBasicString(_string,0,tokend); + + //Erase that token from this string + _string.Erase(0, tokend + 1); + + //Return the token + return token; + } + + //Tokenize C-String Implementation + template + ZBasicString Tokenize(ZBasicString& _string, const char *_delims) + { return Tokenize(_string, ZBasicString(_delims)); } + + /* + public ZBasicStringAlgo::ToLower + + Changes the provided region of the given string into all lowercase letters. + + @param A - the allocator type of the string + @param _string - the string to mutate + @param _start - the starting index + @param _end - the ending index (exclusive) + @return (void) + @assert - if _end < _start + if _start or _end out of bounds + */ + template + void ToLower(ZBasicString& _string, size_t _start, size_t _end) + { + if (_start == _end) + return; + + const size_t start = _string.BoundsCheck(_start, _string.Length()); + const size_t end = _string.BoundsCheck(_end, _string.Length() + 1); + + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(start <= end, "ZBasicStringAlgo::ToLower - Cannot lower with end < start!"); + #endif + + for (size_t i = start; i < end; i++) + _string.Data()[i] = (char)tolower(_string.Data()[i]); + } + + /* + public ZBasicStringAlgo::ToLower + + Changes the provided string into all lowercase letters. + + @param A - the allocator type of the string + @param _string - the string to mutate + @return (void) + */ + template + void ToLower(ZBasicString& _string) + { + ToLower(_string, 0, _string.Length()); + } + + /* + public ZBasicStringAlgo::ToUpper + + Changes the provided region of the given string into all uppercase letters. + + @param A - the allocator type of the string + @param _string - the string to mutate + @param _start - the starting index + @param _end - the ending index (exclusive) + @return (void) + @assert - if _end < _start + if _start or _end out of bounds + */ + template + void ToUpper(ZBasicString& _string, size_t _start, size_t _end) + { + if (_start == _end) + return; + + const size_t start = _string.BoundsCheck(_start, _string.Length()); + const size_t end = _string.BoundsCheck(_end, _string.Length() + 1); + + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(start <= end, "ZBasicStringAlgo::ToUpper - Cannot upper with end < start!"); + #endif + + for (size_t i = start; i < end; i++) + _string.Data()[i] = (char)toupper(_string.Data()[i]); + } + + /* + public ZBasicStringAlgo::ToUpper + + Changes the provided region of the given string into all uppercase letters. + + @param A - the allocator type of the string + @param _string - the string to mutate + @return (void) + */ + template + void ToUpper(ZBasicString& _string) + { + ToUpper(_string, 0, _string.Length()); + } + + /* + public ZBasicStringAlgo::TrimLeft + + Trims all the whitespace from the left (front) of the provided region of a string. + + @param A - the allocator type for the string + @param _string - the string to trim + @param _start - the starting index + @param _end - the ending index (exclusive) + @return (size_t) - the number of whitespace characters removed + @assert - if _end < _start + if _start or _end out of bounds + */ + template + size_t TrimLeft(ZBasicString& _string, size_t _start, size_t _end) + { + if (_start == _end) + return 0; + + size_t i; + + const size_t start = _string.BoundsCheck(_start, _string.Length()); + const size_t end = _string.BoundsCheck(_end, _string.Length() + 1); + + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(start <= end, "ZBasicStringAlgo::TrimLeft - Cannot trim with end < start!"); + #endif + + for (i = start; i < end; i++) + { + if (!isspace(_string.Data()[i])) + break; + } + + _string.Erase(start, i); + + return (i - start); + } + + /* + public ZBasicString::TrimLeft + + Removes all whitespace from the left side (front) of this string. + + @param A - the allocator type for the string + @param _string - the string to trim whitespace from + @return (size_t) - the number of whitespace characters removed + */ + template + size_t TrimLeft(ZBasicString& _string) + { + return TrimLeft(_string, 0, _string.Length()); + } + + /* + public ZBasicStringAlgo::TrimLeft + + Trims all the whitespace from the right (back) of the provided region of a string. + + @param A - the allocator type for the string + @param _string - the string to trim + @param _start - the starting index + @param _end - the ending index (exclusive) + @return (size_t) - the number of whitespace characters removed + @assert - if _end < _start + if _start or _end out of bounds + */ + template + size_t TrimRight(ZBasicString& _string, size_t _start, size_t _end) + { + if (_start == _end) + return 0; + + size_t i; + + const size_t start = _string.BoundsCheck(_start, _string.Length()); + const size_t end = _string.BoundsCheck(_end, _string.Length() + 1); + + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(start <= end, "ZBasicStringAlgo::TrimRight - Cannot trim with end < start!"); + #endif + + //Remove any character that is a space character as determined by isspace + for (i = end; i > start; i--) + { + if (!isspace(_string.Data()[i - 1])) + break; + } + + _string.Erase(i, end); + + return (end - i); + } + + /* + public ZBasicString::TrimRight + + Removes all whitespace from the right side (back) of this string. + + @param _string - the string to trim whitespace from + @return (size_t) - the number of whitespace characters removed + */ + template + size_t TrimRight(ZBasicString& _string) + { + return TrimRight(_string, 0, _string.Length()); + } + + /* + public ZBasicStringAlgo::Trim + + Trims all the whitespace from both the left (front) and right (back) sides of the + given region of a string. + + @param A - the allocator type for the string + @param _string - the string to trim + @param _start - the starting index + @param _end - the ending index (exclusive) + @return (size_t) - the number of whitespace characters removed + @assert - if _end < _start + if _start or _end out of bounds + */ + template + size_t Trim(ZBasicString& _string, size_t _start, size_t _end) + { + if (_start == _end) + return 0; + + size_t removed = TrimRight(_string, _start, _end); + + return removed + TrimLeft(_string, _start, _end - removed); + } + + /* + public ZBasicString::Trim + + Removes all whitespace from both left and right side of this string. + + @param A - the allocator type of the string + @param _string - the string to trim whitespace from + @return (size_t) - the number of whitespace characters removed + */ + template + size_t Trim(ZBasicString& _string) + { + if (_string.Empty()) + return 0; + + return TrimLeft(_string) + TrimRight(_string); + } + + +}; + +#endif diff --git a/Lib/Include/ZSTL/ZHashMap.hpp b/Lib/Include/ZSTL/ZHashMap.hpp new file mode 100644 index 0000000..9fa7e9c --- /dev/null +++ b/Lib/Include/ZSTL/ZHashMap.hpp @@ -0,0 +1,1230 @@ +/* + ZHashMap.hpp + Author: James Russell + Created: 12/24/2011 + + Purpose: + + Templated hash map implementation. + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ + +#pragma once + +#ifndef _ZHASHMAP_HPP +#define _ZHASHMAP_HPP + +#include +#include +#include + +//Default number of buckets +#ifndef ZHASHMAP_DEFAULT_BUCKETS +#define ZHASHMAP_DEFAULT_BUCKETS (31) +#endif + +//Default load factor for the HashMap (expressed as an integer percentage LF / 100) +#ifndef ZHASHMAP_DEFAULT_LOADFACTOR +#define ZHASHMAP_DEFAULT_LOADFACTOR (75) +#endif + +//Factor by which HashMap grows when loadfactor is exceeded +#ifndef ZHASHMAP_DEFAULT_GROWFACTOR +#define ZHASHMAP_DEFAULT_GROWFACTOR (2.0) +#endif + +//Number of nodes for the lists stored locally (safe since we never splice) +#ifndef ZHASHMAP_DEFAULT_LOCAL_NODES +#define ZHASHMAP_DEFAULT_LOCAL_NODES (10) +#endif + +//Forward Declaration of ZHashMap +template < typename K, typename V, typename HT, typename H, size_t LF, typename LA, typename AA > +class ZHashMap; + +//Forward Declaration of ZHashMapIterator +template +class ZHashMapIterator; + +/* +Forward Declaration of ZHashMap Method Implementation Structures + +Existence of these structures allows for template specialization of +individual methods of the ZHashMap class. In order to specialize +a single method of ZHashMap, simply specialize the corresponding +method implementation structure. +*/ + +//Forward Declaration of ZHashMap::Clear struct +template +struct ZHashMap_ClearImpl { + inline static void Call(ZHashMap& _self); +}; + +//Forward Declaration of ZHashMap::ContainsKey struct +template +struct ZHashMap_ContainsKeyImpl { + inline static bool Call(const ZHashMap& _self, const K& _key); +}; + +//Forward Declaration of ZHashMap::ContainsValue struct +template +struct ZHashMap_ContainsValueImpl { + inline static bool Call(const ZHashMap& _self, const V& _value); +}; + +//Forward Declaration of ZHashMap::Empty struct +template +struct ZHashMap_EmptyImpl { + inline static bool Call(const ZHashMap& _self); +}; + +//Forward Declaration of ZHashMap::Erase struct +template +struct ZHashMap_EraseImpl { + inline static void Call(ZHashMap& _self, const K& _key); + inline static void Call(ZHashMap& _self, ZHashMapIterator& _itr); +}; + +//Forward Declaration of ZHashMap::Get struct +template +struct ZHashMap_GetImpl { + inline static V& Call(const ZHashMap& _self, const K& _key); +}; + +//Forward Declaration of ZHashMap::Put struct +template +struct ZHashMap_PutImpl { + inline static void Call(ZHashMap& _self, const K& _key); + inline static void Call(ZHashMap& _self, const K& _key, const V& _value); +}; + +//Forward Declaration of ZHashMap::Resize struct +template +struct ZHashMap_ResizeImpl { + inline static void Call(ZHashMap& _self, size_t _buckets); +}; + +//Forward Declaration of ZHashMap::Size struct +template +struct ZHashMap_SizeImpl { + inline static size_t Call(const ZHashMap& _self); +}; + +/////////////////////////////////////// +/* Hash Comparator, Hasher, HashNode */ +/////////////////////////////////////// + +/* +Hash comparator class, which compares elements with the == operator. +*/ +template +struct ZHashComparator +{ + ZHashComparator() { } //Silence Sun C++ warnings about uninitialized structs + + //operator overload which returns true if equivalent (as per ==), false otherwise + bool operator () (const T& _a, const T& _b) const + { + if ((T)_a == (T)_b) + return true; + else + return false; + } +}; + +/* +Hasher class, which produces hash values of objects for use in ZHashMap. + +The template parameter T is the type we will be hashing. +The template parameter HT is the hash type that is computed. +*/ +template +class ZHasher +{ +public: + //Comparator for use with equals and less than + ZHashComparator Comp; + + //Default hash function, which attempts to cast the object as a hash value + HT Hash(const T& _obj) const + { + return (HT)(uintptr_t)_obj; //Since 'HT' may be 32-bit, but '_obj' may be a pointer, this can cause compile errors. + } + + //Default comparison function, which compares objects (should return 0 if not equal, !0 otherwise) + int Equals(const T& _first, const T& _second) const + { + return Comp(_first, _second); + } +}; + +/* +Hash node structure, which contains a key, a value, and the pre-computed hash for +the key as well as the hash mod (bucket). This node is stored within a ZListNode +for hash chaining. + +The template parameter K is the key type. +The template parameter V is the value type. +The template parameter HT is the hash type. +*/ +template +struct ZHashNode +{ + ZHashNode() { } //Silence Sun C++ warnings about uninitialized structs + + K Key; //The contained key + V Value; //The contained value + HT Hash; //The hash of the key + size_t HashMod; //The hash mod number of buckets (gives bucket) +}; + +/////////////////////// +/* ZHashMap Iterator */ +/////////////////////// + +/* +Iterator for ZHashMap. + +The template parameter K is the key type. +The template parameter V is the value type. +The template parameter HT is the hash type. +*/ +template +class ZHashMapIterator +{ +private: + //The current node we are pointing to + ZListNode< ZHashNode > *Node; + + //The end node of the map + ZListNode< ZHashNode > *EndNode; + +public: + /* + Default Constructor. + */ + ZHashMapIterator() + : Node(NULL), EndNode(NULL) { } + + /* + Useful constructor. + + @param _node - the node we are to begin iterating at + */ + ZHashMapIterator(ZListNode< ZHashNode >* _node, ZListNode< ZHashNode >* _endNode) + : Node(_node), EndNode(_endNode) { } + + /* + Copy Constructor. + + @param _other - the other iterator + */ + ZHashMapIterator(const ZHashMapIterator& _other) + : Node(_other.Node), EndNode(_other.EndNode) { } + + /* + public ZHashMapIterator::CheckNodeCurrent + + Node check function that does not allow the current node to point to NULL. + + @return (void) + */ + void CheckNodeCurrent() const + { + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(Node != NULL, "ZHashMap Iterator Invalid!"); + #endif + } + + /* + public ZHashMapIterator::CheckNodeNext + + Node check function that does not allow Node to be 'End' + + @return (void) + */ + void CheckNodeNext() const + { + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(Node != NULL && Node != EndNode, "ZHashMap Iterator Next Invalid!"); + #endif + } + + /* + public ZHashMapIterator::CheckNodePrevious + + Node check function that does not allow Node to be 'Begin' + + @return (void) + */ + void CheckNodePrevious() const + { + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(Node != NULL && Node->Previous != EndNode, "ZHashMap Iterator Previous Invalid!"); + #endif + } + + /* + public ZHashMapIterator::GetNode + + Gets the node that this iterator is currently pointed at. + + @return (ZListNode*) - the node we are currently pointed at + */ + ZListNode< ZHashNode >* GetNode() const + { return Node; } + + /* + public ZHashMapIterator::SetNode + + Sets the current node for this iterator. Useful for when the + underlying list changes state. + + @param _node - the node to point this iterator at + @return (void) + */ + void SetNode(ZListNode< ZHashNode >* _node) + { Node = _node; } + + /* + public ZHashMapIterator::GetKey + + Gets the key this iterator points to. + + @return (const K&) - the key pointed to + */ + const K& GetKey() const + { CheckNodeCurrent(); return Node->Element.Key; } + + /* + public ZHashMapIterator::GetValue + + Gets the value this iterator points to. + + @return (V&) - the value pointed to + */ + V& GetValue() const + { CheckNodeCurrent(); return Node->Element.Value; } + + /* + public ZHashMapIterator::HasCurrent + + Determines if this iterator currently points to a valid element. + + @return (bool) - true if element at current position + */ + bool HasCurrent() const + { return Node != NULL && Node != EndNode; } + + /* + public ZHashMapIterator::HasNext + + Determines if this iterator has a valid element after the current element. + + @return (bool) - true if element after current, false otherwise + */ + bool HasNext() const + { return Node != NULL && Node != EndNode && Node->Next != EndNode; } + + /* + public ZHashMapIterator::HasPrev + + Determines if this iterator has a valid element before the current element. + + @return (bool) - true if element before current, false otherwise + */ + bool HasPrev() const + { return Node != NULL && Node->Previous != EndNode; } + + /* + public ZHashMapIterator::Next + + Advances this iterator to the next element. + + @return (void) + @assert - if this would advance past end + */ + void Next() + { ++(*this); } + + /* + public ZHashMapIterator::Prev + + Returns this iterator to the previous element. + + @return (void) + @assert - if this would advance past begin + */ + void Prev() + { --(*this); } + + /* + public ZHashMapIterator::SetValue + + Sets the value mapped to the given key. + + @return (void) + @assert - if this is the end node + */ + void SetValue(const V& _value) + { CheckNodeCurrent(); Node->Element.Value = _value; } + + + //Operator overrides + ZHashMapIterator& operator ++ () { CheckNodeNext(); Node = Node->Next; return *this; } + ZHashMapIterator operator ++ (int) { ZListNode< ZHashNode > *node = Node; CheckNodeNext(); Node = Node->Next; return ZHashMapIterator(node, EndNode); } + ZHashMapIterator operator + (int _value) { ZHashMapIterator itr(*this); for (int i = 0; i < _value; i++) ++itr; return itr; } + ZHashMapIterator& operator += (int _value) { for (int i = 0; i < _value; i++) ++(*this); return *this; } + + ZHashMapIterator& operator -- () { CheckNodePrevious(); Node = Node->Previous; return *this; } + ZHashMapIterator operator -- (int) { ZListNode< ZHashNode > *node = Node; CheckNodePrevious(); Node = Node->Previous; return ZHashMapIterator(node, EndNode); } + ZHashMapIterator operator - (int _value) { ZHashMapIterator itr(*this); for (int i = _value; i > 0; i--) --itr; return itr; } + ZHashMapIterator& operator -= (int _value) { for (int i = 0; i < _value; i--) --(*this); return *this; } + + ZHashMapIterator& operator = (const ZHashMapIterator &_other) { Node = _other.Node; EndNode = _other.EndNode; return *this; } + bool operator == (const ZHashMapIterator& _other) const { return (Node == _other.Node) && (EndNode == _other.EndNode); } + bool operator != (const ZHashMapIterator& _other) const { return !( (*this)==_other ); } + + const ZHashNode& operator * () const { CheckNodeCurrent(); return Node->Element; } +}; + +///////////////////////////// +/* ZHashMap Implementation */ +///////////////////////////// + +/* +Templated dynamic hash map implementation. Uses chained hashing and (optional) load factor +balancing to ensure it behaves gracefully even under heavy load. This implementation does +not maintain order between keys. + +The template parameter K is the key type, which must be hashable. + +The template parameter V is the value type, which need not be hashable. + +The template parameter HT is the hash type. This should generally correspond to something +like a 32-bit or 64-bit unsigned integer. It must be compatible with the modulo operator. + +The template parameter H is the hasher type, which defaults to the ZHasher for K using hash type +HT. The hasher must expose the same methods as ZHasher (Hash, Equals). + +The template parameter LF is the load factor of the hash map given as an integral value between +0 (hashmap will not resize) and 100. Load factor is then computed as (double)(LF / 100). Whenever +the current load factor exceeds this value, the number of buckets is increased (map is resized). + +The template parameter LA is the allocator type to use for list nodes. It must allocate ZListNode +instances containing type ZHashNode. + +The template parameter AA is the allocator type to pass along to the contained ZArray. It must allocate +arrays of type ZListNode< ZHashNode< K, V > >*. +*/ +template , size_t LF = ZHASHMAP_DEFAULT_LOADFACTOR, + typename LA = ZListPooledAllocator< ZHashNode, ZHASHMAP_DEFAULT_LOCAL_NODES >, + typename AA = ZArrayAllocator< ZListNode< ZHashNode >*, ZHASHMAP_DEFAULT_BUCKETS> > +class ZHashMap +{ +friend struct ZHashMap_ClearImpl; +friend struct ZHashMap_ContainsKeyImpl; +friend struct ZHashMap_ContainsValueImpl; +friend struct ZHashMap_EmptyImpl; +friend struct ZHashMap_EraseImpl; +friend struct ZHashMap_GetImpl; +friend struct ZHashMap_PutImpl; +friend struct ZHashMap_ResizeImpl; +friend struct ZHashMap_SizeImpl; + +private: + H Hasher; //The hasher for our keys + LA NodeAllocator; //Allocator for chained hashing + size_t ElementCount; //The element count + + ZArray< ZListNode< ZHashNode >*, AA> Map; //The map + ZListNode< ZHashNode > EmptyNode; //The end node for the hash map + + //Resizes and copies the HashMap if we exceed LoadFactor (LF of 0 indicates we should not resize) + inline void CheckLoadFactor() + { + //This will evaluate to false if LF == 0, true if LF > 0 (done to avoid C4127) + if ((void)LF,LF) + { + double currentLoadFactor = LoadFactor(); + + if (currentLoadFactor > ((double)LF / (double)100.0)) + Resize((size_t)((double)Map.Size() * ZHASHMAP_DEFAULT_GROWFACTOR)); + } + } + + //Gets a bucket given a hash code + inline size_t GetBucket(HT _hash) const + { + return _hash % Map.Size(); + } + +public: + /* + Iterator type for ZHashMap. Allows ZHashMap::Iterator notation. + */ + typedef ZHashMapIterator< K, V, HT > Iterator; + + /* + Default Constructor. + */ + ZHashMap() + : ElementCount(0), Map(ZHASHMAP_DEFAULT_BUCKETS) + { + EmptyNode.Next = &EmptyNode; + EmptyNode.Previous = &EmptyNode; + + Map.Resize(ZHASHMAP_DEFAULT_BUCKETS, NULL); + } + + /* + Parameterized Constructor. + + @param _buckets - the number of buckets the hashmap should use + */ + ZHashMap(size_t _buckets) + : ElementCount(0), Map(_buckets) + { + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(_buckets > 0, "Cannot make ZHashMap with no buckets!"); + #endif + + EmptyNode.Next = &EmptyNode; + EmptyNode.Previous = &EmptyNode; + + Map.Resize(_buckets, NULL); + } + + /* + Copy constructor. + + @param _other - the other hash map + */ + ZHashMap(const ZHashMap& _other) + : ElementCount(_other.Size()), Map(_other.Size()) + { + EmptyNode.Next = &EmptyNode; + EmptyNode.Previous = &EmptyNode; + + Map.Resize(_other.Size(), NULL); + + for (typename ZHashMap::Iterator itr = _other.Begin(); itr != _other.End(); ++itr) + Put((*itr).Key, (*itr).Value); + } + + /* + Copy constructor that can copy hash maps with other template types. Key + and Value type must be the same. + + @param _other - the other hash map + */ + template + ZHashMap(const ZHashMap& _other) + : ElementCount(_other.Size()), Map(_other.Size()) + { + EmptyNode.Next = &EmptyNode; + EmptyNode.Previous = &EmptyNode; + + Map.Resize(_other.Map.Size(), NULL); + + for (typename ZHashMap::Iterator itr = _other.Begin(); itr != _other.End(); ++itr) + Put((*itr).Key, (*itr).Value); + } + + /* + = operator overload. Makes a copy of another hash map. This version is needed to + override the default version. + + @param _other - the other hash map + @return (ZHashMap) - this hash map + */ + ZHashMap& operator = (const ZHashMap& _other) + { + Clear(); + + ElementCount = _other.ElementCount; + Map.Resize(_other.Map.Size()); + + EmptyNode.Next = &EmptyNode; + EmptyNode.Previous = &EmptyNode; + + for (typename ZHashMap::Iterator itr = _other.Begin(); itr != _other.End(); ++itr) { + Put((*itr).Key, (*itr).Value); + } + + return *this; + } + + /* + = operator overload. + + @param _other - the other hash map + @return (ZHashMap) - this hash map + */ + template + ZHashMap& operator = (const ZHashMap& _other) + { + Clear(); + + ElementCount = _other.ElementCount; + Map.Resize(_other.Map.Size()()); + + EmptyNode.Next = &EmptyNode; + EmptyNode.Previous = &EmptyNode; + + for (typename ZHashMap::Iterator itr = _other.Begin(); itr != _other.End(); ++itr) { + Put((*itr).Key, (*itr).Value); + } + + return *this; + } + + /* + public ZHashMap::operator[] + + Gets a value from the map. Functionally resembles the 'Get' operation but will + create a default constructed value if not assigned. + + @param _key - the key to lookup + @return (V&) - the value mapped to _key + */ + V& operator [] (const K& _key) + { if (!ContainsKey(_key)) Put(_key, V()); return Get(_key); } + + /* + public ZHashMap::Begin + + Gets an iterator to the first element in the hash map. Keep in mind + that hash map elements are unordered. + + @return (ZHashMap::Iterator) - iterator to the first element + */ + Iterator Begin() const + { return ZHashMapIterator< K, V, HT >(const_cast >* >(&EmptyNode)->Next, + const_cast >* >(&EmptyNode)); } + + /* + public ZHashMap::Clear + + Clears the hash map of all keys and values. + + @return (void) + */ + void Clear() + { ZHashMap_ClearImpl::Call(*this); } + + /* + public ZHashMap::ContainsKey + + Determines if the hash map contains the given key. + + @param _key - the key to check + @return (bool) - boolean indicating if the hash map contains the key + */ + bool ContainsKey(const K& _key) const + { return ZHashMap_ContainsKeyImpl::Call(*this, _key); } + + /* + public ZHashMap::ContainsValue + + Determines if the hash map contains the given value. + + @param _value - the value to check for + @return (bool) - boolean indicating if the hash map contains the value + */ + bool ContainsValue(const V& _value) const + { return ZHashMap_ContainsValueImpl::Call(*this, _value); } + + /* + public ZHashMap::Empty + + Indicates whether or not the hash map is empty. + + @return (bool) - boolean indicating the hash map is empty (free of keys and values) + */ + bool Empty() const + { return ZHashMap_EmptyImpl::Call(*this); } + + /* + public ZHashMap::End + + Gets an iterator to the end node in the hash map. Keep in mind + that hash map elements are unordered. + + @return (ZHashMap::Iterator) - iterator to the end node + */ + Iterator End() const + { return ZHashMapIterator< K, V, HT >(const_cast >* >(&EmptyNode), + const_cast >* >(&EmptyNode)); } + + /* + public ZHashMap::Erase + + Removes the associated key and mapped value. + + @param _key - the key to lookup + @return (void) - this hash map + @assert - if the key is not mapped + */ + void Erase(const K& _key) + { ZHashMap_EraseImpl::Call(*this, _key); } + + /* + public ZHashMap::Erase + + Removes the key and mapped value given by the iterator. This version is more + efficient than the key-only version because no hash lookup is performed. + + @param _itr - iterator to the hash node to remove + @return (void) + @assert - if it is the end iterator + */ + void Erase(Iterator& _itr) + { ZHashMap_EraseImpl::Call(*this, _itr); } + + /* + public ZHashMap::Find + + Returns an iterator to the element mapped to the given key. Will return + the End() iterator if not mapped. + + @param _key - the key to look up + @return (ZHashMap::Iterator) - iterator to the element, + End() if not found + */ + Iterator Find(const K& _key) const + { + HT hash = Hasher.Hash(_key); + size_t bucket = GetBucket(hash); + + ZListNode< ZHashNode >* node = Map.Data()[bucket]; + + while (node != NULL && node != &EmptyNode && node->Element.HashMod == bucket) + { + if (node->Element.Hash == hash && Hasher.Equals(_key, node->Element.Key) != 0) + return Iterator(node, const_cast< ZListNode< ZHashNode > *>(&EmptyNode)); + + node = node->Next; + } + + return End(); + } + + /* + public ZHashMap::Get + + Gets the value mapped to the given key. + + @param _key - the key to look up + @return (V&) - the value mapped to _key + @assert - if the key is not present in the map + */ + V& Get(const K& _key) const + { return ZHashMap_GetImpl::Call(*this, _key); } + + /* + public ZHashMap::Keys + + Gets a list of keys in the map. Uses the method 'PushBack' to add the + keys. + + @param C - the container type to push the keys into, which must contain + type K and have a 'PushBack' method + @param _container - the container to put the keys into + @return - ZList containing all the keys in the map + */ + template + void Keys(C& _container) const + { + Iterator itr = Begin(); + + while (itr.HasCurrent()) + { + _container.PushBack((*itr).Key); + itr.Next(); + } + } + + /* + public ZHashMap::LoadFactor + + Returns the current load factor of the hash map, as determined by number + of elements over number of buckets. + + @return (double) - the load factor + */ + double LoadFactor() const + { + return (double)ElementCount / (double)Map.Size(); + } + + /* + public ZHashMap::Mappings + + Gets a list of all the key value mappings in the hash map. Adds pairs of + mappings using 'PushBack'. + + @param C - the container type to push the keys into, which must contain + type ZPair and have a 'PushBack' method + @param _container - the container to put the keys into + @return (ZList>)- list of key-value pairs + */ + template + void Mappings(C& _container) const + { + Iterator itr = Begin(); + + while (itr.HasCurrent()) + { + _container.PushBack(ZPair((*itr).Key, (*itr).Value)); + itr.Next(); + } + } + + /* + public ZHashMap::Put + + Puts the given key into the map with a default constructed value of type V. + + @param _key - the key to place in the map + */ + void Put(const K& _key) + { return ZHashMap_PutImpl::Call(*this, _key); } + + /* + public ZHashMap::Put + + Puts the given key and value combination into the hash map. + + @param _key - the key to associate with _value + @param _value - the value to lookup using _key + */ + void Put(const K& _key, const V& _value) + { return ZHashMap_PutImpl::Call(*this, _key, _value); } + + /* + public ZHashMap::Resize + + Sets the number of buckets the hashmap will use. Existing elements will be re-hashed into the map. + + @param _buckets - number of buckets to use + @return (ZHashMap&) - this map + */ + void Resize(size_t _buckets) + { ZHashMap_ResizeImpl::Call(*this, _buckets); } + + /* + public ZHashMap::Size + + Returns the number of mapped key-value pairs in the map. + + @return (size_t) - the number of key value pairs + */ + size_t Size() const + { return ZHashMap_SizeImpl::Call(*this); } + + /* + public ZHashMap::Values + + Gets a list of values in the map. + + @param C - the container type to push the keys into, which must contain + type V and have a 'PushBack' method + @param _container - the container to put the keys into + @return (ZList)- ZList containing all the values in the map + */ + template + void Values(C& _container) const + { + Iterator itr = Begin(); + + while (itr.HasCurrent()) + { + _container.PushBack((*itr).Value); + itr.Next(); + } + } +}; + +//////////////////////////////////////////// +/* Non-Specialized Method Implementations */ +//////////////////////////////////////////// + +template +void ZHashMap_ClearImpl::Call(ZHashMap& _self) +{ + ZListNode< ZHashNode >* node = _self.EmptyNode.Next; + + while (node != &_self.EmptyNode) + { + node = node->Next; + _self.NodeAllocator.Deallocate(node->Previous); + } + + for (size_t i = 0; i < _self.Map.Size(); i++) + _self.Map.Data()[i] = NULL; + + _self.EmptyNode.Next = &_self.EmptyNode; + _self.EmptyNode.Previous = &_self.EmptyNode; + + _self.ElementCount = 0; +} + +/*************************************************************************/ + +template +bool ZHashMap_ContainsKeyImpl::Call(const ZHashMap& _self, const K& _key) +{ + HT hash = _self.Hasher.Hash(_key); + size_t bucket = _self.GetBucket(hash); + + ZListNode< ZHashNode >* node = _self.Map.Data()[bucket]; + + while (node != NULL && node != &_self.EmptyNode && node->Element.HashMod == bucket) + { + if (node->Element.Hash == hash && _self.Hasher.Equals(_key, node->Element.Key) != 0) + return true; + + node = node->Next; + } + + return false; +} + +/*************************************************************************/ + +template +bool ZHashMap_ContainsValueImpl::Call(const ZHashMap& _self, const V& _value) +{ + typename ZHashMap::Iterator itr = _self.Begin(); + + while (itr.HasCurrent()) + { + if ((*itr).Value == _value) + return true; + + itr.Next(); + } + + return false; +} + +/*************************************************************************/ + +template +bool ZHashMap_EmptyImpl::Call(const ZHashMap& _self) +{ + return _self.ElementCount == 0; +} + +/*************************************************************************/ + +template +void ZHashMap_EraseImpl::Call(ZHashMap& _self, const K& _key) +{ + HT hash = _self.Hasher.Hash(_key); + size_t bucket = _self.GetBucket(hash); + + ZListNode< ZHashNode >* node = _self.Map.Data()[bucket]; + + while (node != NULL && node != &_self.EmptyNode && node->Element.HashMod == bucket) + { + if (node->Element.Hash == hash && _self.Hasher.Equals(_key, node->Element.Key) != 0) + { + ZListNode< ZHashNode >* prevNode = node->Previous; + ZListNode< ZHashNode >* nextNode = node->Next; + + prevNode->Next = nextNode; + nextNode->Previous = prevNode; + + //If the bucket maps to this node, it must change (either Next or NULL) + if (_self.Map.Data()[bucket] == node) + { + if (nextNode->Element.HashMod == bucket) + _self.Map.Data()[bucket] = nextNode; + else + _self.Map.Data()[bucket] = NULL; + } + + _self.NodeAllocator.Deallocate(node); + _self.ElementCount--; + + return; + } + + node = node->Next; + } +} + +/*************************************************************************/ + +template +void ZHashMap_EraseImpl::Call(ZHashMap& _self, ZHashMapIterator& _itr) +{ + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(_itr != _self.End(), "ZHashMap: Cannot Erase End iterator!"); + #endif + + ZListNode< ZHashNode >* node = _itr.GetNode(); + ZListNode< ZHashNode >* prevNode = node->Previous; + ZListNode< ZHashNode >* nextNode = node->Next; + + size_t bucket = node->Element.HashMod; + + prevNode->Next = nextNode; + nextNode->Previous = prevNode; + + //If the bucket maps to this node, it must change (either Next or NULL) + if (_self.Map.Data()[node->Element.HashMod] == node) + { + if (nextNode->Element.HashMod == bucket) + _self.Map.Data()[bucket] = nextNode; + else + _self.Map.Data()[bucket] = NULL; + } + + _self.NodeAllocator.Deallocate(node); + _self.ElementCount--; +} + + +/*************************************************************************/ + +template +V& ZHashMap_GetImpl::Call(const ZHashMap& _self, const K& _key) +{ + HT hash = _self.Hasher.Hash(_key); + size_t bucket = _self.GetBucket(hash); + + ZListNode< ZHashNode >* node = _self.Map.Data()[bucket]; + + while (node != NULL && node != &_self.EmptyNode && node->Element.HashMod == bucket) + { + if (node->Element.Hash == hash && _self.Hasher.Equals(_key, node->Element.Key) != 0) + return node->Element.Value; + + node = node->Next; + } + + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ERROR("ZHashMap: Get could not find value!"); + #endif + + //If the runtime assert is ignored and we continue, return ref to a static local variable + //This is effectively 'undefined' behavior + static V val; + + return val; +} + +/*************************************************************************/ + +template +void ZHashMap_PutImpl::Call(ZHashMap& _self, const K& _key) +{ + _self.CheckLoadFactor(); + + HT hash = _self.Hasher.Hash(_key); + size_t bucket = _self.GetBucket(hash); + + ZListNode< ZHashNode >* node = _self.Map.Data()[bucket]; + + if (node == NULL) + { + //Empty bucket, so search for the next node + for (size_t i = bucket + 1; i < _self.Map.Size(); i++) + { + node = _self.Map.Data()[i]; + + if (node != NULL) + break; + } + + //No node was found, so use the empty node + if (node == NULL) + node = &_self.EmptyNode; + } + else + { + //Non-empty bucket, so see if we are already mapped + while (node->Element.HashMod == bucket) + { + if (node->Element.Hash == hash && _self.Hasher.Equals(_key, node->Element.Key) != 0) + return; + + node = node->Next; + } + } + + //Not mapped, so insert (node is currently one past where we should be) + ZListNode< ZHashNode >* newNode = _self.NodeAllocator.Allocate(); + + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(newNode != NULL, "ZHashMap: Unable to allocate hash node!"); + #endif + + //If the bucket has NULL linkage, set it + if (_self.Map.Data()[bucket] == NULL) + _self.Map.Data()[bucket] = newNode; + + newNode->Next = node; + newNode->Previous = node->Previous; + newNode->Element.Key = _key; + newNode->Element.Value = V(); //Be sure to default construct the value instance + newNode->Element.Hash = hash; + newNode->Element.HashMod = bucket; + + newNode->Previous->Next = newNode; + newNode->Next->Previous = newNode; + + _self.ElementCount++; +} + +/*************************************************************************/ + +template +void ZHashMap_PutImpl::Call(ZHashMap& _self, const K& _key, const V& _value) +{ + _self.CheckLoadFactor(); + + HT hash = _self.Hasher.Hash(_key); + size_t bucket = _self.GetBucket(hash); + + ZListNode< ZHashNode >* node = _self.Map.Data()[bucket]; + + if (node == NULL) + { + //Empty bucket, so search for the next node + for (size_t i = bucket + 1; i < _self.Map.Size(); i++) + { + node = _self.Map.Data()[i]; + + if (node != NULL) + break; + } + + //No node was found, so use the empty node + if (node == NULL) + node = &_self.EmptyNode; + } + else + { + //Non-empty bucket, so see if we are already mapped + while (node->Element.HashMod == bucket) + { + if (node->Element.Hash == hash && _self.Hasher.Equals(_key, node->Element.Key) != 0) + { + node->Element.Value = _value; + return; + } + + node = node->Next; + } + } + + //Not mapped, so insert (node is currently one past where we should be) + ZListNode< ZHashNode >* newNode = _self.NodeAllocator.Allocate(); + + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(newNode != NULL, "ZHashMap: Unable to allocate hash node!"); + #endif + + //If the bucket has NULL linkage, set it + if (_self.Map.Data()[bucket] == NULL) + _self.Map.Data()[bucket] = newNode; + + newNode->Next = node; + newNode->Previous = node->Previous; + newNode->Element.Key = _key; + newNode->Element.Value = _value; + newNode->Element.Hash = hash; + newNode->Element.HashMod = bucket; + + newNode->Previous->Next = newNode; + newNode->Next->Previous = newNode; + + _self.ElementCount++; +} + +/*************************************************************************/ + +template +void ZHashMap_ResizeImpl::Call(ZHashMap& _self, size_t _buckets) +{ + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(_buckets > 0, "ZHashMap: Unable to resize to zero buckets!"); + #endif + + //Get a pointer to the first non-empty element (which may itself be the empty element) + ZListNode< ZHashNode >* node = _self.EmptyNode.Next; + + //Clear out the map completely + for (size_t i = 0; i < _self.Map.Size(); i++) + _self.Map.Data()[i] = NULL; + + _self.EmptyNode.Next = &_self.EmptyNode; + _self.EmptyNode.Previous = &_self.EmptyNode; + + _self.Map.Resize(_buckets, NULL); + + //Loop through our previous nodes and place them back in the map in their new spots + while (node != &_self.EmptyNode) + { + //Compute new bucket + node->Element.HashMod = node->Element.Hash % _buckets; + + //Determine where we should be placing this node + ZListNode< ZHashNode >* curNode = node; + ZListNode< ZHashNode >* nextNode = _self.Map.Data()[node->Element.HashMod]; + + //Get the next node to place now, before we scribble the pointers + node = curNode->Next; + + //If the bucket has NULL linkage, next node + if (nextNode == NULL) + { + //Empty bucket, so search for the next nextNode + for (size_t i = curNode->Element.HashMod + 1; i < _self.Map.Size(); i++) + { + nextNode = _self.Map.Data()[i]; + + if (nextNode != NULL) + break; + } + + //No nextNode was found, so use the empty nextNode + if (nextNode == NULL) + nextNode = &_self.EmptyNode; + } + + //Reestablish linkage + curNode->Next = nextNode; + curNode->Previous = nextNode->Previous; + + curNode->Previous->Next = curNode; + curNode->Next->Previous = curNode; + + //Since we are pushing front, this always means we set the pointer + _self.Map.Data()[curNode->Element.HashMod] = curNode; + } +} + +/*************************************************************************/ + +template +size_t ZHashMap_SizeImpl::Call(const ZHashMap& _self) +{ + return _self.ElementCount; +} + +#endif diff --git a/Lib/Include/ZSTL/ZList.hpp b/Lib/Include/ZSTL/ZList.hpp new file mode 100644 index 0000000..2f5b286 --- /dev/null +++ b/Lib/Include/ZSTL/ZList.hpp @@ -0,0 +1,1554 @@ +/* + ZList.hpp + Author: James Russell + Created: 9/12/2011 + + Purpose: + + Templated doubly-linked list implementation. + + A primary difference between ZList and ZArray is that ZList (rather, the default allocators for + ZList) make an absolute guarantee about scoped allocation / deallocation of objects. This + means that a ZList using any of the default allocators is guaranteed to construct and destruct + list nodes as needed, and this means element constructors and destructors will be called as + elements are allocated and deallocated. + + This guarantee goes out the window when a custom allocator is used, and it becomes up to the + implementor to meet or disregard this guarantee as desired. The list will, however, always + call out to the allocator whenever a node is needed, guaranteeing that the allocator is still + called as elements enter and leave scope. + + Note: + + A visualizer for Visual Studio 2008 for this container is available in vs_visualizers.txt. + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ + +#pragma once + +#ifndef _ZLIST_HPP +#define _ZLIST_HPP + +#include +#include + +//Forward Declaration of ZList +template +class ZList; + +//Forward Declaration of ZListIterator +template +class ZListIterator; + +/* +Forward Declaration of ZList Method Implementation Structures + +Existence of these structures allows for template specialization of +individual methods of the ZList class. In order to specialize +a single method of ZList, simply specialize the corresponding +method implementation structure. +*/ + +//Forward Declaration of ZList::At struct +template +struct ZList_AtImpl { + inline static ZListIterator Call(const ZList& _self, size_t _index); +}; + +//Forward Declaration of ZList::Back struct +template +struct ZList_BackImpl { + inline static T& Call(const ZList& _self); +}; + +//Forward Declaration of ZList::Clear struct +template +struct ZList_ClearImpl { + inline static void Call(ZList& _self, ZListIterator& _itr); +}; + +//Forward Declaration of ZList::Copy struct +template +struct ZList_CopyImpl { + template inline static void Call(ZList& _self, const ZList& _other); +}; + +//Forward Declaration of ZList::Empty struct +template +struct ZList_EmptyImpl { + inline static bool Call(const ZList& _self); +}; + +//Forward Declaration of ZList::Equals struct +template +struct ZList_EqualsImpl { + template inline static bool Call(const ZList& _self, const ZList& _other); +}; + +//Forward Declaration of ZList::Erase struct +template +struct ZList_EraseImpl { + inline static T Call(ZList& _self, ZListIterator& _itr); + inline static void Call(ZList& _self, ZListIterator& _start, const ZListIterator& _end); +}; + +//Forward Declaration of ZList::Find struct +template +struct ZList_FindImpl { + inline static ZListIterator Call(const ZList& _self, const T& _elem); +}; + +//Forward Declaration of ZList::Front struct +template +struct ZList_FrontImpl { + inline static T& Call(const ZList& _self); +}; + +//Forward Declaration of ZList::Insert struct +template +struct ZList_InsertImpl { + inline static void Call(ZList& _self, const ZListIterator& _itr, const T& _value); + inline static void Call(ZList& _self, const ZListIterator& _itr, const ZListIterator& _start, const ZListIterator& _end); +}; + +//Forward Declaration of ZList::PopBack struct +template +struct ZList_PopBackImpl { + inline static T Call(ZList& _self); +}; + +//Forward Declaration of ZList::PopFront struct +template +struct ZList_PopFrontImpl { + inline static T Call(ZList& _self); +}; + +//Forward Declaration of ZList::PushBack struct +template +struct ZList_PushBackImpl { + inline static void Call(ZList& _self, const T& _value); +}; + +//Forward Declaration of ZList::PushFront struct +template +struct ZList_PushFrontImpl { + inline static void Call(ZList& _self, const T& _value); +}; + +//Forward Declaration of ZList::Size struct +template +struct ZList_SizeImpl { + inline static size_t Call(const ZList& _self); +}; + +//Forward Declaration of ZList::Splice struct +template +struct ZList_SpliceImpl { + inline static void Call(ZList& _self, const ZListIterator& _itr, ZList& _other, const ZListIterator& _start, const ZListIterator& _end); +}; + +//Forward Declaration of ZList::Swap struct +template +struct ZList_SwapImpl { + inline static void Call(ZList& _self, ZList& _other); +}; + +//Forward Declaration of ZList::SwapNodes struct +template +struct ZList_SwapNodesImpl { + inline static void Call(ZList& _self, const ZListIterator& _i, const ZListIterator& _j); +}; + +////////////////////// +/* ZList Allocators */ +////////////////////// + +/* +Allocator for ZList. Handles allocation of nodes of the templated type. + +The template parameter T is the type contained in the list this allocator is for. +*/ +template +class ZListAllocator +{ +public: + /* + public ZListAllocator::Allocate + + Allocator function which allocates a ZListNode. + + @return - an allocated ZListNode + */ + ZListNode* Allocate() + { + return ZSTL_NEW(ZListNode); + } + + /* + public ZListAllocator::Deallocate + + Deallocation function which deallocates a previously allocated ZListNode. + + @param _node - node to deallocate + */ + void Deallocate(ZListNode* _node) + { + ZSTL_DEL(_node); + } +}; + +/* +Alternate allocator for ZList Handles allocation of nodes of the templated type, +and uses local storage to avoid allocations whenever possible. + +Note: This allocator is NOT suitable for a list that is later spliced using + ZList::Splice or has nodes swapped using ZList::Swap or ZList::SwapNodes. + It will cause errors when local nodes are deallocated by the other list's + allocator. + +The template parameter T is the type contained in the list this allocator is for. +*/ +template +class ZListPooledAllocator +{ +private: + //Local storage space for nodes + char Local[N * sizeof(ZListNode)]; + + //Pointer storage for nodes (if available) + ZListNode* Nodes[N]; + + //Our current node index + size_t NodeIndex; + +public: + + /* + Default constructor, which initializes local storage. + */ + ZListPooledAllocator() + : NodeIndex(0) + { + uintptr_t ptr = (uintptr_t)&Local[0]; + for (size_t i = 0; i < N; i++) + { + Nodes[i] = (ZListNode*)ptr; + ptr += sizeof(ZListNode); + } + } + + /* + public ZListPooledAllocator::Allocate + + Allocator function which allocates a ZListNode. + + @return - an allocated ZListNode + */ + ZListNode* Allocate() + { + if (NodeIndex < N) + { + ZListNode* node = Nodes[NodeIndex]; + Nodes[NodeIndex++] = NULL; + return new (node) ZListNode(); + } + + return ZSTL_NEW(ZListNode); + } + + /* + public ZListPooledAllocator::Deallocate + + Deallocation function which deallocates a previously allocated ZListNode. + + @param _node - node to deallocate + */ + void Deallocate(ZListNode* _node) + { + const uintptr_t nodePtr = (uintptr_t)_node; + const uintptr_t poolLower = (uintptr_t)&Local[0]; + const uintptr_t poolUpper = poolLower + (N-1)*sizeof(ZListNode); + + if (nodePtr >= poolLower && nodePtr <= poolUpper) + { + ZSTL_ASSERT((nodePtr - poolLower) % sizeof(ZListNode) == 0, "Node is not aligned to this list, check for address corruption"); + + Nodes[--NodeIndex] = _node; + _node->~ZListNode(); + } + else + { + ZSTL_DEL(_node); + } + } +}; + +//////////////////// +/* ZList Iterator */ +//////////////////// + +/* +Iterator class for ZList. + +The template parameter T is the type contained in the list this iterator is for. +*/ +template +class ZListIterator +{ +public: + /* + Default Constructor. + */ + ZListIterator() + : Node(NULL), EndNode(NULL) { } + + /* + Useful constructor. + + @param _node - the node we are to begin iterating at + */ + ZListIterator(ZListNode* _node, ZListNode* _endNode) + : Node(_node), EndNode(_endNode) { } + + /* + Copy Constructor. + + @param _other - the other iterator + */ + ZListIterator(const ZListIterator& _other) + : Node(_other.Node), EndNode(_other.EndNode) { } + + /* + public ZListIterator::CheckNodeCurrent + + Node check function that does not allow the current node to + point to NULL or to 'End'. + + @return (void) + @assert - if the node is NULL + */ + void CheckNodeCurrent() const + { + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(Node != NULL && Node != EndNode, "ZList Iterator Invalid!"); + #endif + } + + /* + public ZListIterator::CheckNodeNext + + Node check function that does not allow Node to be 'End' + + @return (void) + */ + void CheckNodeNext() const + { + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(Node != NULL && Node != EndNode, "ZList Iterator Next Invalid!"); + #endif + } + + /* + public ZListIterator::CheckNodePrevious + + Node check function that does not allow Node to be 'Begin' + + @return (void) + */ + void CheckNodePrevious() const + { + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(Node != NULL && Node->Previous != EndNode, "ZList Iterator Previous Invalid!"); + #endif + } + + /* + public ZListIterator::GetNode + + Gets the node that this iterator is currently pointed at. + + @return (ZListNode*) - the node we are currently pointed at + */ + ZListNode* GetNode() const + { return Node; } + + /* + public ZListIterator::SetNode + + Sets the current node for this iterator. Useful for when the + underlying list changes state. + + @param _node - the node to point this iterator at + @return (void) + */ + void SetNode(ZListNode* _node) + { Node = _node; } + + /* + public ZListIterator::Get + + Gets the element this iterator points to. + + @return (T&) - the element pointed to + */ + T& Get() const + { return *(*this); } + + /* + public ZListIterator::HasCurrent + + Determines if this iterator currently points to a valid element. + + @return (bool) - true if element at current position + */ + bool HasCurrent() const + { return Node != NULL && Node != EndNode; } + + /* + public ZListIterator::HasNext + + Determines if this iterator has a valid element after the current element. + + @return (bool) - true if element after current, false otherwise + */ + bool HasNext() const + { return Node != NULL && Node != EndNode && Node->Next != EndNode; } + + /* + public ZListIterator::HasPrev + + Determines if this iterator has a valid element before the current element. + + @return (bool) - true if element before current, false otherwise + */ + bool HasPrev() const + { return Node != NULL && Node->Previous != EndNode; } + + /* + public ZListIterator::Next + + Advances this iterator to the next element. + + @return (void) + @assert - if this would advance past end + */ + void Next() + { ++(*this); } + + /* + public ZListIterator::Prev + + Returns this iterator to the previous element. + + @return (void) + @assert - if this would advance past begin + */ + void Prev() + { --(*this); } + + //Operator overrides + ZListIterator& operator ++() { CheckNodeNext(); Node = Node->Next; return *this; } + ZListIterator operator ++ (int) { ZListNode *node = Node; CheckNodeNext(); Node = Node->Next; return ZListIterator(node, EndNode); } + ZListIterator operator + (int _value) { ZListIterator itr(*this); for (int i = 0; i < _value; i++) ++itr; return itr; } + ZListIterator& operator += (int _value) { for (int i = 0; i < _value; i++) ++(*this); return *this; } + + ZListIterator& operator -- () { CheckNodePrevious(); Node = Node->Previous; return *this; } + ZListIterator operator -- (int) { ZListNode *node = Node; CheckNodePrevious(); Node = Node->Previous; return ZListIterator(node, EndNode); } + ZListIterator operator - (int _value) { ZListIterator itr(*this); for (int i = _value; i > 0; i--) --itr; return itr; } + ZListIterator& operator -=(int _value) { for (int i = 0; i < _value; i--) --(*this); return *this; } + + ZListIterator& operator = (const ZListIterator &_other) { Node = _other.Node; EndNode = _other.EndNode; return *this; } + bool operator == (const ZListIterator& _other) const { return (Node == _other.Node) && (EndNode == _other.EndNode); } + bool operator !=(const ZListIterator& _other) const { return !( (*this)==_other ); } + + T& operator *() const { CheckNodeCurrent(); return Node->Element; } + +private: + //The current node we are pointing to + ZListNode *Node; + + //The end node of the list + ZListNode *EndNode; +}; + +////////////////////////// +/* ZList Implementation */ +////////////////////////// + +/* +List implementation for ZEngine. + +ZList takes a single template parameter, which is the contained type. The allocator is +passed in at construction, which allows the allocator to be decoupled from the list container. + +The template parameter T is the type to be contained in the list. +*/ +template > +class ZList +{ +friend struct ZList_AtImpl; +friend struct ZList_BackImpl; +friend struct ZList_ClearImpl; +friend struct ZList_CopyImpl; +friend struct ZList_EmptyImpl; +friend struct ZList_EqualsImpl; +friend struct ZList_EraseImpl; +friend struct ZList_FindImpl; +friend struct ZList_FrontImpl; +friend struct ZList_InsertImpl; +friend struct ZList_PopBackImpl; +friend struct ZList_PopFrontImpl; +friend struct ZList_PushBackImpl; +friend struct ZList_PushFrontImpl; +friend struct ZList_SizeImpl; +friend struct ZList_SpliceImpl; +friend struct ZList_SwapImpl; +friend struct ZList_SwapNodesImpl; + +protected: + /* + Our empty list node. + + EmptyNode.Next is always the first node in the list (itself if empty). + EmptyNode.Previous is always the last node in the list (itself if empty). + */ + ZListNode EmptyNode; + + //Allocator for the list + A ListAllocator; + + //Allocate function + inline ZListNode* AllocateNode() + { + ZListNode* node = ListAllocator.Allocate(); + + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(node != NULL, "ZList allocator failed to allocate node!"); + #endif + + return node; + } + + //Deallocate function + inline void DeallocateNode(ZListNode *_node) + { + ListAllocator.Deallocate(_node); + } + + //Integrity Check (used for internal debugging) + inline void CheckIntegrity() const + { + #if ZSTL_CHECK_INTEGRITY + + ZListNode* current; + ZListNode* previous; + + current = EmptyNode.Next; + previous = current->Previous; + + ZSTL_ASSERT(previous == &EmptyNode, "First linkage invalid!"); + + for(;;) //Stupid MSVC warning + { + ZSTL_ASSERT(current != NULL, "ZList Error: Contains invalid linkage pointers!"); + + previous = current; + current = current->Next; + + if (current == &EmptyNode) + break; + } + + ZSTL_ASSERT(previous == EmptyNode.Previous, "ZList Error: Last linkage invalid!"); + + #endif //ZSTL_CHECK_INTEGRITY + } + +public: + /* + Typedef for ZListIterator (allows for ZList::Iterator notation). + */ + typedef ZListIterator Iterator; + + /* + Default Constructor. + */ + ZList() + { + EmptyNode.Next = &EmptyNode; + EmptyNode.Previous = &EmptyNode; + + CheckIntegrity(); + } + + /* + Sub-List Constructor. Constructs a list containing the elements between two given iterators. + + @param _begin - the iterator at which to start the list + @param _end - the iterator at which to end the list (exclusive) + */ + ZList(const ZListIterator& _begin, const ZListIterator& _end) + { + typename ZList::Iterator itr; + + EmptyNode.Next = &EmptyNode; + EmptyNode.Previous = &EmptyNode; + + for (itr = _begin; itr != _end; ++itr) + PushBack((*itr)); + + CheckIntegrity(); + } + + /* + Copy Constructor. Makes a copy of the other list. Needed to prevent + the default copy constructor from being generated. + + @param _other - the other list to copy. + */ + ZList(const ZList& _other) + { + typename ZList::Iterator itr; + + EmptyNode.Next = &EmptyNode; + EmptyNode.Previous = &EmptyNode; + + _other.CheckIntegrity(); + + for (itr = _other.Begin(); itr != _other.End(); ++itr) + PushBack((*itr)); + + CheckIntegrity(); + } + + /* + Copy constructor. Makes a copy of the other list. + + @param B - the allocator type of the other list + @param _other - the other list to copy + */ + template + ZList(const ZList& _other) + { + typename ZList::Iterator itr; + + EmptyNode.Next = &EmptyNode; + EmptyNode.Previous = &EmptyNode; + + for (itr = _other.Begin(); itr != _other.End(); ++itr) + PushBack((*itr)); + + CheckIntegrity(); + } + + /* + Destructor. + */ + ~ZList() + { + Clear(); + } + + /* + [] Operator overload. Equivalent to a call to At. + + @param _index - index into the list + @return (ZList::Iterator) - iterator to the given index + */ + Iterator operator [] (size_t _index) const + { return At(_index); } + + /* + = Operator overload. Equivalent to a call to Copy. Needed to prevent + a default assignment operator from being created. + + @param _other - the other list to copy. + @return (void) + */ + ZList& operator = (const ZList& _other) + { Copy(_other); return *this; } + + /* + = Operator overload. Equivalent to a call to Copy. + + @param _other - the other list to copy. + @return (void) + */ + template + ZList& operator = (const ZList& _other) + { Copy(_other); return *this; } + + /* + == Operator overload. Equivalent to a call to Equals. + + @param B - the allocator type of the other list + @param _other - the list to compare against + @return (bool) - true if they are equal, false otherwise + */ + template + bool operator == (const ZList& _other) const + { return Equals(_other); } + + /* + != Operator overload. Equivalent to !Equals. + + @param B - the allocator type of the other list + @param _other - the list to compare against + @return (bool) - true if they are not equal, false if they are + */ + template + bool operator != (const ZList& _other) const + { return !Equals(_other); } + + /* + public ZList::Allocator + + Returns a reference to the current allocator. + + @return (A&) - reference to the held allocator + */ + A& Allocator() + { return ListAllocator; } + + /* + public ZList::At + + Gets an iterator to a specific index in the list. + + @param _index - the index + @return (Iterator&) - iterator to the indexed element + @assert - if the index is past the end of the list + */ + Iterator At(size_t _index) const + { return ZList_AtImpl::Call(*this, _index); } + + /* + public ZList::Back + + Gets a reference to the value at the back of the list. + + @return (T&) - last element in the list + @assert - if the list is empty + */ + T& Back() const + { return ZList_BackImpl::Call(*this); } + + /* + public ZList::Begin + + Gets an iterator to the beginning of the list. + + @return (ZList::Iterator) - iterator pointing to the first list node + */ + Iterator Begin() const + { return ZListIterator(const_cast*>(EmptyNode.Next), const_cast*>(&EmptyNode)); } + + /* + public ZList::Clear + + Clears the list. + + @return (void) + */ + void Clear() + { typename ZList::Iterator temp = Begin(); return Clear(temp); } + + /* + public ZList::Clear + + Clears the list after a specific iterator location. The given iterator is set + to the end of the list after this call. + + @param - _itr - the iterator + @return (void) + */ + void Clear(Iterator& _itr) + { return ZList_ClearImpl::Call(*this, _itr); } + + /* + public ZList::Copy + + Copies the contents of another list into this list. + + @param _other - the list to copy from + @return (void) + */ + template + void Copy(const ZList& _other) + { return ZList_CopyImpl::template Call(*this, _other); } + + /* + public ZList::Empty + + O(1) operation that determines if the list is empty. + + @return (bool) - true if the list has no elements, false otherwise + */ + bool Empty() const + { return ZList_EmptyImpl::Call(*this); } + + /* + public ZList::End + + Gets an iterator to the 'end' node, which is one element past + the last element in the list. + + @return (ZList::Iterator) - iterator pointing to the 'end' node + */ + Iterator End() const + { return ZListIterator(const_cast*>(&EmptyNode), const_cast*>(&EmptyNode)); } + + /* + public ZList::Equals + + Does an element-by-element comparison to determine equivalence. + + @param B - the type of the allocator used by the other list + @param _other - the list to compare against + @return (bool) - true if the lists are equivalent, false otherwise + */ + template + bool Equals(const ZList& _other) const + { return ZList_EqualsImpl::Call(*this, _other); } + + /* + public ZList::Erase + + Removes a value from the list at the specified location. + + @param _itr - the iterator location to remove the value from (incremented after this call) + @return (T) - the removed value + @assert - if the iterator is invalid + */ + T Erase(Iterator& _itr) + { return ZList_EraseImpl::Call(*this, _itr); } + + /* + public ZList::Erase + + Removes a range of values from the list. + + @param _from - the iterator location to start at (set to _to after this call) + @param _to - the iterator location to end at (exclusive) + @return (void) + @assert - if the iterator is invalid + */ + void Erase(Iterator& _from, const Iterator& _to) + { return ZList_EraseImpl::Call(*this, _from, _to); } + + /* + public ZList::Find + + Finds the first occurrence of the element in the list, as determined by + the == operator. + + @param _elem - the element to find + @return (Iterator) - iterator to first occurrence of the element, or ZSTL::invalidPos if not found + */ + Iterator Find(const T& _elem) const + { return ZList_FindImpl::Call(*this, _elem); } + + /* + public ZList::Front + + Gets a reference to the value at the front of the list. + + @return (T&) - first value in the list + @assert - if the list is empty + */ + T& Front() const + { return ZList_FrontImpl::Call(*this); } + + /* + public ZList::Insert + + Inserts a value at the specified location in the list. As _itr is + not modified, it will point to the first node after the inserted value. + + @param _itr - iterator to the location to insert the value + @param _value - the value to add to the beginning of the list + @return (void) + @assert - if the iterator is invalid + */ + void Insert(const ZListIterator& _itr, const T& _value) + { return ZList_InsertImpl::Call(*this, _itr, _value); } + + /* + public ZList::Insert + + Inserts the values between the provided iterators at the specified + location. As _itr is not modified, it will point to the first node + after the inserted values. + + @param _itr - iterator to the location to insert the values + @param _start - the starting iterator to the values to insert + @param _end - the ending iterator (exclusive) + @return (void) + */ + void Insert(const ZListIterator& _itr, const ZListIterator& _start, const ZListIterator& _end) + { return ZList_InsertImpl::Call(*this, _itr, _start, _end); } + + /* + public ZList::PopBack + + Pops a value from the end of the list. + + @return (T) - the value at the back of the list + @assert - if the list is empty + */ + T PopBack() + { return ZList_PopBackImpl::Call(*this); } + + /* + public ZList::PopFront + + Removes and returns the value from the beginning of the list. + + @return (T) - the value at the front of the list + @assert - if the list is empty + */ + T PopFront() + { return ZList_PopFrontImpl::Call(*this); } + + /* + public ZList::PushBack + + Pushes a value onto the back of the list. Calls out to the allocator + to allocate new nodes. + + @param _value - the value to place in the list + @return (void) + */ + void PushBack(const T& _value) + { return ZList_PushBackImpl::Call(*this, _value); } + + /* + public ZList::PushFront + + Pushes a value onto the front of the list. Calls out to the allocator + to allocate new nodes. + + @param _value - the value to place in the list + @return (void) + */ + void PushFront(const T& _value) + { return ZList_PushFrontImpl::Call(*this, _value); } + + /* + public ZList::Size + + O(n) operation that gives the size of the list. + + @return (size_t) - list length (number of contained elements) + */ + size_t Size() const + { return ZList_SizeImpl::Call(*this); } + + /* + public ZList::Splice + + Splices the contents of another list between the given iterators + into this list. This avoids assignment operator calls on the contained + elements, but does modify the list pointed to by the given iterators + (removes the nodes) and requires that an allocator of type A be able + to deallocate nodes made by other allocators of type A. + + The passed in iterators are not modified, meaning that _start will point + to the first inserted node in this list, the _end iterator will point + to the same element in the node provider list, and _itr will point to the + first element after the inserted nodes. + + @param _itr - the position to insert the values at + @param _other - the list the nodes are removed from (must be passed to ensure allocator equivalence) + @param _start - the starting iterator + @param _end - the ending iterator (exclusive) + @return (void) + @assert - if allocator type A cannot deallocate nodes made by another instance of A (determined by Allocator ==) + */ + void Splice(const ZListIterator& _itr, ZList& _other, const ZListIterator& _start, const ZListIterator& _end) + { return ZList_SpliceImpl::Call(*this, _itr, _other, _start, _end); } + + /* + public ZList::Swap + + Swaps the contents of this list with the contents of another. + + @param _other - the list to swap contents with + @return (void) + */ + void Swap(ZList& _other) + { return ZList_SwapImpl::Call(*this, _other); } + + /* + public ZList::SwapNodes + + Swaps the actual nodes at the given positions. Avoids an assignment operator call + on the elements contained. The iterators are not modified, meaning they now point + to each other's locations after the call. + + @param _i - iterator to the first element + @param _j - iterator to the second element + @return (void) + @assert - if the iterators are invalid + */ + void SwapNodes(const ZListIterator& _i, const ZListIterator& _j) + { return ZList_SwapNodesImpl::Call(*this, _i, _j); } +}; + +//////////////////////////////////////////// +/* Non-Specialized Method Implementations */ +//////////////////////////////////////////// + +template +ZListIterator ZList_AtImpl::Call(const ZList& _self, size_t _index) + +{ + size_t i; + ZListIterator itr; + + for (i = 0, itr = _self.Begin(); i < _index; i++) + ++itr; + + return itr; +} + +/*************************************************************************/ + +template +T& ZList_BackImpl::Call(const ZList& _self) +{ + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(!_self.Empty(), "ZList: No back element present!"); + #endif + + return _self.EmptyNode.Previous->Element; +} + +/*************************************************************************/ + +template +void ZList_ClearImpl::Call(ZList& _self, ZListIterator& _itr) +{ + ZListNode* next; + ZListNode* current = _itr.GetNode(); + + _self.CheckIntegrity(); + + //Early out + if (_self.Empty()) + return; + + //If we are the starting node, be sure to reset the EmptyNode.Next pointer + if (current == _self.EmptyNode.Next) + _self.EmptyNode.Next = &_self.EmptyNode; + + //This is always true + _self.EmptyNode.Previous = current->Previous; + current->Previous->Next = &_self.EmptyNode; + + //Iterate and deallocate the nodes + while (current != &_self.EmptyNode) + { + next = current->Next; + _self.DeallocateNode(current); + current = next; + } + + //Set the node on the iterator equal to the end node + _itr.SetNode(&_self.EmptyNode); + + _self.CheckIntegrity(); +} + +/*************************************************************************/ + +template template +void ZList_CopyImpl::Call(ZList& _self, const ZList& _other) +{ + typename ZList::Iterator itr1; + typename ZList::Iterator itr2; + + if (&_self == &_other) + return; + + //Assign as much as we can to avoid allocation calls with PushBack + for (itr1 = _self.Begin(), itr2 = _other.Begin(); itr2 != _other.End(); ++itr2) + { + if (itr1 != _self.End()) + { + (*itr1++) = (*itr2); + } + else + { + _self.PushBack((*itr2)); + } + } + + _self.Clear(itr1); +} + +/*************************************************************************/ + +template +bool ZList_EmptyImpl::Call(const ZList& _self) +{ + //Just need to check the EmptyNode.Next pointer + return (_self.EmptyNode.Next == &_self.EmptyNode); +} + +/*************************************************************************/ + +template template +bool ZList_EqualsImpl::Call(const ZList& _self, const ZList& _other) +{ + typename ZList::Iterator itr1; + typename ZList::Iterator itr2; + + if (&_self == &_other) + return true; + + //Make sure we are element-wise equivalent up to the end of either list + for (itr1 = _self.Begin(), itr2 = _other.Begin(); itr1 != _self.End() && itr2 != _other.End(); ++itr1, ++itr2) + { + if ((*itr1) != (*itr2)) + return false; + } + + //Then make sure we have reached the end of both lists + if (itr1 == _self.End() && itr2 == _other.End()) + return true; + + return false; +} + +/*************************************************************************/ + +template +T ZList_EraseImpl::Call(ZList& _self, ZListIterator& _itr) +{ + T elem; + ZListNode *node = _itr.GetNode(); + + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(node != NULL, "ZList: Iterator is invalid!"); + ZSTL_ASSERT(node != &_self.EmptyNode, "ZList: Cannot erase end node!"); + #endif + + //Increment the iterator to the next list node to keep the iterator valid + ++_itr; + + //Rearrange the pointers + node->Previous->Next = node->Next; + node->Next->Previous = node->Previous; + + elem = node->Element; + + _self.DeallocateNode(node); + + _self.CheckIntegrity(); + + return elem; +} + +/*************************************************************************/ + +template +void ZList_EraseImpl::Call(ZList& _self, ZListIterator& _start, const ZListIterator& _end) +{ + ZListNode *nodeStart = _start.GetNode(); + ZListNode *nodeEnd = _end.GetNode(); + + ZListNode *curNode; + ZListNode *prevNode; + + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(nodeStart != NULL && nodeEnd != NULL, "ZList: Cannot erase with invalid iterator!"); + ZSTL_ASSERT(nodeStart != &_self.EmptyNode, "ZList: Cannot erase end node!"); + #endif + + //Rearrange the pointers + nodeStart->Previous->Next = nodeEnd; + nodeEnd->Previous = nodeStart->Previous; + + //Erase each element between from and to + curNode = nodeStart; + prevNode = NULL; + + while (curNode != nodeEnd) + { + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(curNode != &_self.EmptyNode, "ZList: Cannot erase end node!"); + #endif + + prevNode = curNode; + curNode = curNode->Next; + + _self.DeallocateNode(prevNode); + } + + _start = _end; +} + +/*************************************************************************/ + +template +ZListIterator ZList_FindImpl::Call(const ZList& _self, const T& _elem) +{ + ZListIterator localItr = _self.Begin(); + ZListIterator end = _self.End(); + + //For each element, insert into the list at the given location + while (localItr != end) + { + if ((*localItr) == _elem) { + return localItr; + } + ++localItr; + } + + return ZSTL::InvalidPos; +} + +/*************************************************************************/ + +template +T& ZList_FrontImpl::Call(const ZList& _self) +{ + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(!_self.Empty(), "ZList: No front element in list!"); + #endif + + return _self.EmptyNode.Next->Element; +} + +/*************************************************************************/ + +template +void ZList_InsertImpl::Call(ZList& _self, const ZListIterator& _itr, const T& _value) +{ + ZListNode *node = _itr.GetNode(); + ZListNode *newNode = _self.AllocateNode(); + + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(node != NULL, "ZList: Iterator is invalid!"); + #endif + + //Set our data + newNode->Element = _value; + + //Swap the pointers + newNode->Next = node; + newNode->Previous = node->Previous; + + node->Previous->Next = newNode; + node->Previous = newNode; + + _self.CheckIntegrity(); +} + +/*************************************************************************/ + +template +void ZList_InsertImpl::Call(ZList& _self, const ZListIterator& _itr, const ZListIterator& _start, const ZListIterator& _end) +{ + ZListIterator localItr = _start; + + //For each element, insert into the list at the given location + while (localItr != _end) + { + _self.Insert(_itr, *localItr); + ++localItr; + } +} + +/*************************************************************************/ + +template +T ZList_PopBackImpl::Call(ZList& _self) +{ + T elem; + ZListNode *node; + + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(!_self.Empty(), "ZList: Cannot pop from back of empty list!"); + #endif + + //Grab the element at the back of the list + node = _self.EmptyNode.Previous; + + //Remove the node from the list + node->Previous->Next = &_self.EmptyNode; + _self.EmptyNode.Previous = node->Previous; + + //Get the element value + elem = node->Element; + + //Deallocate and then return + _self.DeallocateNode(node); + + _self.CheckIntegrity(); + + return elem; +} + +/*************************************************************************/ + +template +T ZList_PopFrontImpl::Call(ZList& _self) +{ + T elem; + ZListNode *node; + + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(!_self.Empty(), "ZList: Cannot pop from front of empty list!"); + #endif + + //Grab the element at the front of the list + node = _self.EmptyNode.Next; + + //Remove the node from the list + node->Next->Previous = node->Previous; + node->Previous->Next = node->Next; + + //Get the element value + elem = node->Element; + + //Deallocate and then return + _self.DeallocateNode(node); + + _self.CheckIntegrity(); + + return elem; +} + +/*************************************************************************/ + +template +void ZList_PushBackImpl::Call(ZList& _self, const T& _value) +{ + //Get us a new node + ZListNode *node = _self.AllocateNode(); + + //Set the value + node->Element = _value; + + //Set some pointers + node->Next = &_self.EmptyNode; + node->Previous = _self.EmptyNode.Previous; + + _self.EmptyNode.Previous->Next = node; + _self.EmptyNode.Previous = node; + + _self.CheckIntegrity(); +} + +/*************************************************************************/ + +template +void ZList_PushFrontImpl::Call(ZList& _self, const T& _value) +{ + //Get us a new node + ZListNode *node = _self.AllocateNode(); + + //Set the value + node->Element = _value; + + //Set some pointers + node->Next = _self.EmptyNode.Next; + node->Previous = &_self.EmptyNode; + + node->Next->Previous = node; + _self.EmptyNode.Next = node; + + _self.CheckIntegrity(); +} + +/*************************************************************************/ + +template +size_t ZList_SizeImpl::Call(const ZList& _self) +{ + size_t i; + ZListNode *node; + + //Iterate and count + i = 0; + for (node = _self.EmptyNode.Next; node != &_self.EmptyNode; node = node->Next) + i++; + + return i; +} + +/*************************************************************************/ + +template +void ZList_SpliceImpl::Call(ZList& _self, const ZListIterator& _itr, ZList& _other, const ZListIterator& _start, const ZListIterator& _end) +{ + ZListNode *node = _itr.GetNode(); + ZListNode *startNode = _start.GetNode(); + ZListNode *endNode = _end.GetNode(); + + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(node != NULL, "ZList: Iterator is invalid!"); + ZSTL_ASSERT(startNode != NULL, "ZList: Start Iterator is invalid!"); + ZSTL_ASSERT(endNode != NULL, "ZList: End Iterator is invalid!"); + #endif + + //Look for easy ways out of this + if (startNode == endNode) + return; + + if (_other.Empty()) //This has the convenient side effect of checking to ensure allocators are of the same type + return; + + /* + + Nope, gotta do this the hard way. So, we have the following. + + This List: + ? <-> A <-> B <-> ? + + Other List: + ? <-> C <-> D <-?-> E <-> F <-> ? + + node is node B. startNode is node D. endNode is node F. It is entirely possible + that node E is also node D - but the algorithm should not care. + + After Splice, we should have the following. + + This List: + ? <-> A <-> D <-?-> E <-> B <-> ? + + Other List: + ? <-> C <-> F <-> ? + + */ + + ZListNode *nodeA, *nodeB, *nodeC, *nodeD, *nodeE, *nodeF; + + nodeB = node; + nodeD = startNode; + nodeF = endNode; + nodeA = nodeB->Previous; + nodeE = nodeF->Previous; + nodeC = nodeD->Previous; + + nodeA->Next = nodeD; + nodeD->Previous = nodeA; + + nodeB->Previous = nodeE; + nodeE->Next = nodeB; + + nodeF->Previous = nodeC; + nodeC->Next = nodeF; + + _self.CheckIntegrity(); + + return; +} + +/*************************************************************************/ + +template +void ZList_SwapImpl::Call(ZList& _self, ZList& _other) +{ + ZListNode* tempNode; + + if (_self.Empty() && _other.Empty()) + { + //Nothing to do here + } + else if (_self.Empty() && !_other.Empty()) + { + //Simple swap + _self.EmptyNode.Next = _other.EmptyNode.Next; + _self.EmptyNode.Previous = _other.EmptyNode.Previous; + _self.EmptyNode.Next->Previous = &_self.EmptyNode; + _self.EmptyNode.Previous->Next = &_self.EmptyNode; + + _other.EmptyNode.Next = &_other.EmptyNode; + _other.EmptyNode.Previous = &_other.EmptyNode; + } + else if (!_self.Empty() && _other.Empty()) + { + //Again, simple swap + _other.EmptyNode.Next = _self.EmptyNode.Next; + _other.EmptyNode.Previous = _self.EmptyNode.Previous; + _other.EmptyNode.Next->Previous = &_other.EmptyNode; + _other.EmptyNode.Previous->Next = &_other.EmptyNode; + + _self.EmptyNode.Next = &_self.EmptyNode; + _self.EmptyNode.Previous = &_self.EmptyNode; + } + else + { + //Swap the empty node pointers around + tempNode = _self.EmptyNode.Next; + + _self.EmptyNode.Next = _other.EmptyNode.Next; + _other.EmptyNode.Next = tempNode; + + tempNode = _self.EmptyNode.Previous; + + _self.EmptyNode.Previous = _other.EmptyNode.Previous; + _other.EmptyNode.Previous = tempNode; + + //Now correct the element pointers + _self.EmptyNode.Next->Previous = &_self.EmptyNode; + _self.EmptyNode.Previous->Next = &_self.EmptyNode; + + _other.EmptyNode.Next->Previous = &_other.EmptyNode; + _other.EmptyNode.Previous->Next = &_other.EmptyNode; + } + + _self.CheckIntegrity(); + _other.CheckIntegrity(); +} + +/*************************************************************************/ + +template +void ZList_SwapNodesImpl::Call(ZList& _self, const ZListIterator& _i, const ZListIterator& _j) +{ + URFP(_self); + + ZListNode *tempNode; + ZListNode *iNode = _i.GetNode(); + ZListNode *jNode = _j.GetNode(); + + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(iNode != NULL, "ZList: _i Iterator is invalid!"); + ZSTL_ASSERT(jNode != NULL, "ZList: _j Iterator is invalid!"); + #endif + + //Early out + if (iNode == jNode) + return; + + //Swap pointers around + tempNode = iNode->Next; + + iNode->Next = jNode->Next; + jNode->Next = tempNode; + + iNode->Next->Previous = iNode; + jNode->Next->Previous = jNode; + + tempNode = iNode->Previous; + + iNode->Previous = jNode->Previous; + jNode->Previous = tempNode; + + iNode->Previous->Next = iNode; + jNode->Previous->Next = jNode; +} + +#endif diff --git a/Lib/Include/ZSTL/ZListAlgo.hpp b/Lib/Include/ZSTL/ZListAlgo.hpp new file mode 100644 index 0000000..cfeb5e8 --- /dev/null +++ b/Lib/Include/ZSTL/ZListAlgo.hpp @@ -0,0 +1,802 @@ +/* + ZListAlgo.hpp + Author: James Russell + Created: 1/12/2012 + + Purpose: + + Generalized algorithm implementations for use with ZList. + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ + +#pragma once + +#ifndef _ZLISTALGO_HPP +#define _ZLISTALGO_HPP + +#include + +namespace ZListAlgo +{ + /* + public ZListAlgo::Append + + Appends a range of one list's elements to the back of another. + + @param T - the type held by the list + @param A - the allocator used by the list + @param B - the allocator type used by the other list + @param _list - list to append elements to + @param _other - list to get elements from + @param _start - the starting iterator + @param _end - the ending iterator (exclusive) + @return (void) + @assert - if _start, _end don't belong to _other + */ + template + void Append(ZList& _list, const ZList& _other, const ZListIterator& _start, const ZListIterator& _end) + { + URFP(_other); + typename ZList::Iterator itr; + for (itr = _start; itr !=_end; ++itr) + _list.PushBack(*itr); + } + + /* + public ZListAlgo::Append + + Appends one list's elements to the back of another. + + @param T - the type held by the list + @param A - the allocator used by the list + @param B - the allocator type used by the other list + @param _list - list to append elements to + @param _other - list to get elements from + @return (void) + */ + template + void Append(ZList& _list, const ZList& _other) + { + Append(_list,_other, _other.Begin(), _other.End()); + } + + + /* + public ZListAlgo::Concatenate + + Function to concatenate ranges of two lists together and returns the result. + + @param _list - the first list to concatenate + @param _listStart - the starting iterator for _list + @param _listEnd - the ending iterator for _list (exclusive) + @param _other - the second list to concatenate + @param _otherStart - the starting iterator for _other + @param _otherEnd - the second iterator for _other (exclusive) + @return (ZList) - concatenated list with copies of elements from lists. + */ + template + ZList Concatenate(const ZList& _list, const ZListIterator& _listStart, const ZListIterator& _listEnd, + const ZList& _other, const ZListIterator& _otherStart, const ZListIterator& _otherEnd) + { + URFP(_list); //TODO: Need to check to ensure _listStart, _listEnd iterate _list + URFP(_other); //TODO: Need to check to ensure _otherStart, _otherEnd iterate _other + + ZListIterator litr; + ZListIterator oitr; + + ZList ret; + + for (litr = _listStart; litr != _listEnd; ++litr) + ret.PushBack(*litr); + + for (oitr = _otherStart; oitr != _otherEnd; ++oitr) + ret.PushBack(*oitr); + + return ret; + } + + /* + public ZListAlgo::Concatenate + + Function to concatenate two lists together. + + @param _list - the first list to concatenate + @param _other - the second list to concatenate + @return (ZList) - list of form [list, other], made of copies of their elements + */ + template + ZList Concatenate(const ZList& _list, const ZList& _other) + { + return Concatenate(_list, _list.Begin(), _list.End(), _other, _other.Begin(), _other.End()); + } + + /* + public ZListAlgo::Contains + + Determines if the list contains the given value between the given iterators. + + @param T - the type held by the list + @param A - the allocator used by the list + @param _list - the list to search in + @param _value - the value to look for + @param _start - the starting iterator + @param _end - the ending iterator (exclusive) + @return (bool) - true if the range contains the value, false otherwise + */ + template + bool Contains(const ZList& _list, const T& _value, const ZListIterator& _start, const ZListIterator& _end) + { + URFP(_list); //TODO: Need to check to ensure _start, _end iterate _list + + ZListIterator itr; + + for (itr = _start; itr != _end; ++itr) + { + if (*itr == _value) + return true; + } + + return false; + } + + /* + public ZListAlgo::Count + + Counts the number of occurrences of a value in the list between the given iterators. + + @param T - the type held by the list + @param A - the allocator used by the list + @param _list - the list to count elements in + @param _value - the value to look for + @param _start - the starting iterator + @param _end - the ending iterator (exclusive) + @return (size_t) - the number of occurrences of the value + */ + template + size_t Count(const ZList& _list, const T& _value, const ZListIterator& _start, const ZListIterator& _end) + { + URFP(_list); //TODO: Need to check to ensure _start, _end iterate _list + + size_t i; + typename ZList::Iterator itr; + + for (i = 0, itr = _start; itr != _end; ++itr) + { + if ((*itr) == _value) + i++; + } + + return i; + } + + /* + public ZListAlgo::Count + + Counts the number of occurrences of a value in the list. + + @param T - the type held by the list + @param A - the allocator used by the list + @param _list - the list to count elements in + @param _value - the value to look for + @return (size_t) - the number of occurrences of the value + */ + template + size_t Count(const ZList& _list, const T& _value) + { + return Count(_list, _value, _list.Begin(), _list.End()); + } + + + /* + public ZListAlgo::Excise + + Excises a region from a list and returns it. + + @param T - the type held by the list + @param A - the allocator used by the list + @param _list - the list to excise a region from + @param _start - the starting iterator + @param _end - the ending iterator (exclusive) + @return (ZList) - the excised region + */ + template + ZList Excise(ZList& _list, const ZListIterator& _start, const ZListIterator& _end) + { + URFP(_list); //TODO: Need to check to ensure _start, _end iterate _list + + ZList ret; + ZListIterator itr; + + itr = _start; + + while (itr != _end) + ret.PushBack(_list.Erase(itr)); + + return ret; + } + + /* + public ZListAlgo::FindFirstOf + + Searches for the first occurrence of the specified value in the list between + the given iterators. + + @param T - the type held by the list + @param A - the allocator used by the list + @param _list - the list to search in + @param _value - the value to search for + @param _start - the starting iterator + @param _end - the ending iterator (exclusive) + @return (ZListIterator) - the iterator location where the value is found (_end if not found) + */ + template + ZListIterator FindFirst(const ZList& _list, const T& _value, const ZListIterator& _start, const ZListIterator& _end) + { + URFP(_list); //TODO: Need to check to ensure _start, _end iterate _list + + ZListIterator itr; + + for (itr = _start; itr != _end; ++itr) + if ((*itr) == _value) + return itr; + + return _list.End(); + } + + /* + public ZListAlgo::FindFirstOf + + Searches for the first occurrence of the specified value in the list. + + @param T - the type held by the list + @param A - the allocator used by the list + @param _list - the list to search in + @param _value - the value to search for + @return (ZListIterator) - the iterator location where the value is found (_end if not found) + */ + template + ZListIterator FindFirst(const ZList& _list, const T& _value) + { + return FindFirst(_list, _value, _list.Begin(), _list.End()); + } + + + /* + public ZListAlgo::Contains + + Determines if the list contains the given value. + + @param T - the type held by the list + @param A - the allocator used by the list + @param _list - the list to search in + @param _value - the value to look for + @return (bool) - true if the list contains the value, false otherwise + */ + template + bool Contains(const ZList& _list, const T& _value) + { + return FindFirst(_list, _value) != _list.End(); + } + + /* + public ZListAlgo::FirstNotOf + + Function to find the first occurrence of a value that is not the given value in the given range and + returns an iterator to it. + + @param T - the type held by the list + @param A - the allocator used by the list + @param _list - the list to search in + @param _value - the value to avoid + @param _start - the starting iterator + @param _end - the ending iterator (exclusive) + @return (ZListIterator) - iterator pointing at the first non-match (_end if not found) + */ + template + ZListIterator FirstNotOf(const ZList& _list, const T& _value, const ZListIterator& _start, const ZListIterator& _end) + { + URFP(_list); //TODO: Need to check to ensure _start, _end iterate _list + + ZListIterator itr; + + for (itr = _start; itr != _end; ++itr) + if (!(*itr == _value)) + break; + + return itr; + } + + /* + public ZListAlgo::FirstNotOf + + Function to find the first occurrence of a value that is not the given value and + returns an iterator to it. + + @param T - the type held by the list + @param A - the allocator used by the list + @param _list - the list to search in + @param _value - the value to search for the first nonoccurence of + @return (ZListIterator) - iterator pointing at the first non-match (_end if not found) + */ + template + ZListIterator FirstNotOf(const ZList& _list, const T& _value) + { + return FirstNotOf(_list, _value, _list.Begin(), _list.End()); + } + + /* + public ZListAlgo::Prepend + + Appends copies of a range of a list's elements to the front of another list. + + @param T - the type held by the list + @param A - the allocator used by the list + @param B - the allocator type of the other list + @param _list - list to append elements to + @param _other - list to get elements from + @param _start - the starting iterator + @param _end - the ending iterator (exclusive) + @return (void) + */ + template + void Prepend(ZList& _list, const ZList& _other, const ZListIterator& _start, const ZListIterator& _end) + { + URFP(_other); + _list.Insert(_list.Begin(), _start, _end); + } + + /* + public ZListAlgo::Prepend + + Appends copies of a list's elements to the front of another list. + + @param T - the type held by the list + @param A - the allocator used by the list + @param B - the allocator type of the other list + @param _list - list to append elements to + @param _other - list to get elements from + @return (void) + */ + template + void Prepend(ZList& _list, const ZList& _other) + { + Prepend(_list, _other, _other.Begin(), _other.End()); + } + + /* + public ZListAlgo::Remove + + Removes the first occurrence of the specified value from the list starting at + the given iterator location. + + @param T - the type held by the list + @param A - the allocator used by the list + @param _list - the list to remove elements from + @param _value - the value to remove + @param _start - the starting iterator + @param _end - the ending iterator (exclusive) + @return (ZListIterator) - iterator to the position after the removed element + */ + template + ZListIterator Remove(ZList& _list, const T& _value, const ZListIterator& _start, const ZListIterator& _end) + { + URFP(_list); //TODO: Need to check to ensure _start, _end iterate _list + + ZListIterator itr = _start; + + while (itr != _end) + { + if ((*itr) == _value) + { + _list.Erase(itr); + return itr; + } + + ++itr; + } + + return _list.End(); + } + + /* + public ZListAlgo::Remove + + Removes the first occurrence of the specified value from the list. + + @param T - the type held by the list + @param A - the allocator used by the list + @param _list - the list to remove elements from + @param _value - the value to remove + @return (ZListIterator) - iterator to the position after the removed element + */ + template + ZListIterator Remove(ZList& _list, const T& _value) + { + return Remove(_list, _value, _list.Begin(), _list.End()); + } + + + /* + public ZListAlgo::RemoveAll + + Removes all occurrences of the specified value from the list between the given iterators. + + @param T - the type held by the list + @param A - the allocator used by the list + @param _list - the list to remove elements from + @param _value - the value to remove + @param _start - the starting iterator + @param _end - the ending iterator (exclusive) + @return (size_t) - the number of elements removed + */ + template + size_t RemoveAll(ZList& _list, const T& _value, const ZListIterator& _start, const ZListIterator& _end) + { + URFP(_list); //TODO: Need to check to ensure _start, _end iterate _list + + size_t removed = 0; + ZListIterator temp = _start; + + while (temp != _end) + { + if (*temp == _value) + { + _list.Erase(temp); + removed++; + } + else + { + ++temp; //Erase will increment above + } + } + + return removed; + } + + /* + public ZListAlgo::RemoveAll + + Removes all occurrences of the specified value from the list. + + @param T - the type held by the list + @param A - the allocator used by the list + @param _list - the list to remove elements from + @param _value - the value to remove + @return (size_t) - the number of elements removed + */ + template + size_t RemoveAll(ZList& _list, const T& _value) + { + return RemoveAll(_list, _value, _list.Begin(), _list.End()); + } + + + /* + public ZListAlgo::Reverse + + Reverses the elements of a list in a given range. + + @param T - the type held by the list + @param A - the allocator used by the list + @param _list - the list to reverse a range on + @param _start - the starting iterator + @param _end - the ending iterator (exclusive) + @return (void) + */ + template + void Reverse(ZList& _list, const ZListIterator& _start, const ZListIterator& _end) + { + if (_list.Size() < 2) + return; + + ZListIterator start = _start; + ZListIterator end = _end; + end.Prev(); + T temp; + + while (start != end) + { + temp = *start; + *start = *end; + *end = temp; + + if (start.GetNode()->Next == end.GetNode() && end.GetNode()->Previous == start.GetNode()) + break; + if (start.GetNode()->Next == end.GetNode()->Previous) + break; + ++start; + --end; + } + } + + /* + public ZListAlgo::Reverse + + Reverses the elements in a list. + + @param T - the type held by the list + @param A - the allocator used by the list + @param _list - the list to reverse + @return (void) + */ + template + void Reverse(ZList& _list) + { + Reverse(_list, _list.Begin(), _list.End()); + } + + + /* + public ZListAlgo::ReverseNodes + + Reverses the elements of a list in a given range. Use when operator = for the + contained element is expensive. + + @param T - the type held by the list + @param A - the allocator used by the list + @param _list - the list to reverse a range on + @param _start - the starting iterator + @param _end - the ending iterator (exclusive) + @return (void) + */ + template + void ReverseNodes(ZList& _list, const ZListIterator& _start, const ZListIterator& _end) + { + URFP(_list); //TODO: Need to check to ensure _start, _end iterate _list + + ZListNode* startBoundNode = _start.GetNode()->Previous; + ZListNode* endBoundNode = _end.GetNode(); + ZListNode* currNode = _start.GetNode(); + + ZListNode* temp; + + // don't reverse sublist of only 1 element + if (currNode == endBoundNode->Previous) + return; + + // setup the start node and end boundary + startBoundNode->Next = endBoundNode->Previous; + endBoundNode->Previous = currNode; + + // swap node next and prev pointers + while (currNode != endBoundNode) + { + temp = currNode->Next; + ZSTL_ASSERT(temp != NULL, "temp null in Reverse!()\n"); + currNode->Next = currNode->Previous; + currNode->Previous = temp; + currNode = temp; + } + + // setup the end node and the first boundary + currNode->Previous = startBoundNode; + + // setup the first node and the end boundary + currNode = _start.GetNode(); + currNode->Next = endBoundNode; + } + + /* + public ZListAlgo::ReverseNodes + + Reverses the nodes in a given list. Use when operator = for the + contained element is expensive. + + @param T - the type held by the list + @param A - the allocator used by the list + @param _list - the list to reverse + @return (void) + */ + template + void ReverseNodes(ZList& _list) + { + ReverseNodes(_list, _list.Begin(), _list.End()); + } + + + /* + public ZListAlgo::Slice + + Gets a copy of the elements in a subset of a list. + + @param T - the type held by the list + @param A - the allocator used by the list + @param _list - the list to get a slice from + @param _start - the beginning (inclusive) of the slice + @param _end - the end (exclusive) of the slice + @return (ZList) - slice list + */ + template + ZList Slice(const ZList& _list, const ZListIterator& _start, const ZListIterator& _end) + { + URFP(_list); //TODO: Need to check to ensure _start, _end iterate _list + + return ZList(_start, _end); + } + + /* + public ZListAlgo::Sort + + Sorts the provided list in place between the given iterators using the provided comparator and algorithm. + + @param CF - binary comparator functor to use [(const T&, const T&) -> int] that compares values + returns negative value if first value < second value + returns positive value if first value > second value + returns 0 if first value == second value + @param AF - ternary algorithm functor to use [(CF&, ZListNode*, ZListNode*) -> void] that sorts the list + the first argument is a reference to the provided comparator + the second argument is a pointer to the starting node + the third argument is a pointer to the ending node (exclusive) + @param T - the type held by the list + @param A - the allocator used by the list + @param _list - the list to sort + @param _comparator - the comparator function used to compare the values + @param _algorithm - the algorithm to use to sort the list + @param _start - the starting iterator + @param _end - the ending iterator (exclusive) + @return (void) + */ + template + void Sort(ZList& _list, CF _comparator, AF _algorithm, ZListIterator& _start, ZListIterator& _end) + { + URFP(_list); //TODO: ensure that start/end came from list + _algorithm(_comparator, _start.GetNode(), _end.GetNode()); + } + + /* + public ZListAlgo::Sort + + Sorts the provided list in place using the default comparator (uses operator <) and + a non-stable merge sort. + + @param T - the type held by the list + @param A - the allocator used by the list + @param _list - the list to sort + @return (void) + */ + template + void Sort(ZList& _list) + { + ZComparator comparator; + ZListMergeSort algorithm; + + ZListIterator start = _list.Begin(); + ZListIterator end = _list.End(); + + Sort(_list, comparator, algorithm, start, end); + } + + /* + public ZListAlgo::Sort + + Sorts the provided list in place between the given iterators using the default + comparator (uses operator <) and a non-stable merge sort. + + @param T - the type held by the list + @param A - the allocator used by the list + @param _list - the list to sort + @param _start - the starting iterator + @param _end - the ending iterator (exclusive) + @return (void) + */ + template + void Sort(ZList& _list, ZListIterator& _start, ZListIterator& _end) + { + ZComparator comparator; + ZListMergeSort algorithm; + Sort(_list, comparator, algorithm, _start, _end); + } + + /* + public ZListAlgo::Sort + + Sorts the provided list in place using the provided comparator and a + non-stable merge sort. + + @param CF - binary comparator functor to use [(const T&, const T&) -> int] that compares values + returns negative value if first value < second value + returns positive value if first value > second value + returns 0 if first value == second value + @param T - the type held by the list + @param A - the allocator used by the list + @param _list - the list to sort + @param _comparator - the comparator function used to compare the values + @return (void) + */ + template + void Sort(ZList& _list, CF _comparator) + { + ZListMergeSort algorithm; + ZListIterator begin = _list.Begin(); + ZListIterator end = _list.End(); + Sort(_list, _comparator, algorithm, begin, end); + } + + /* + public ZListAlgo::Sort + + Sorts the provided list in place using the provided comparator and algorithm. + + @param CF - binary comparator functor to use [(const T&, const T&) -> int] that compares values + returns negative value if first value < second value + returns positive value if first value > second value + returns 0 if first value == second value + @param AF - ternary algorithm functor to use [(CF&, ZListNode*, ZListNode*) -> void] that sorts the list + the first argument is a reference to the provided comparator + the second argument is a pointer to the starting node + the third argument is a pointer to the ending node (exclusive) + @param T - the type held by the list + @param A - the allocator used by the list + @param _list - the list to sort + @param _comparator - the comparator function used to compare the values + @param _algorithm - the algorithm to use to sort the list + @return (void) + */ + template + void Sort(ZList& _list, CF _comparator, AF _algorithm) + { + ZListIterator begin = _list.Begin(); + ZListIterator end = _list.End(); + Sort(_list, _comparator, _algorithm, begin, end); + } + + + /* + public ZListAlgo::Split + + Splits the list at the specified location. The provided list is modified to be the first half, + the returned list is the second half. + + @param T - the type held by the list + @param A - the allocator used by the list + @param _list - the list to split + @param _itr - iterator location to split (invalidated by this call) + @return (ZList) - the split second half of the list + */ + template + ZList Split(ZList& _list, const ZListIterator& _itr) + { + URFP(_list); //TODO: Need to check to ensure _itr iterates _list + + ZListIterator itr = _itr; + + ZList splitList(itr, _list.End()); + + _list.Clear(itr); + + return splitList; + } + + /* + public ZListAlgo::SwapElements + + Swaps the elements at two locations in this list. Both iterators are modified + to point to new nodes, but they remain at the same location. + + @param T - the type held by the list + @param A - the allocator used by the list + @param _itr1 - iterator to the first element + @param _itr2 - iterator to the second element + @return (void) + */ + template + void SwapElements(ZList& _list, const ZListIterator& _itr1, const ZListIterator& _itr2) + { + URFP(_list); //TODO: Need to check to ensure _itr1, _itr2 iterates _list + + T temp = *_itr2; + *_itr2 = *_itr1; + *_itr1 = temp; + } +} + +#endif + diff --git a/Lib/Include/ZSTL/ZPair.hpp b/Lib/Include/ZSTL/ZPair.hpp new file mode 100644 index 0000000..bac139c --- /dev/null +++ b/Lib/Include/ZSTL/ZPair.hpp @@ -0,0 +1,206 @@ +/* + ZPair.hpp + Author: James Russell + Created: 9/12/2011 + + Purpose: + + Templated tuple implementation. + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ + +#pragma once + +#ifndef _ZPAIR_HPP +#define _ZPAIR_HPP + +#include + +//Forward Declaration of ZPair +template +class ZPair; + +/* +Forward Declaration of ZPair Method Implementation Structures + +Existence of these structures allows for template specialization of +individual methods of the ZPair class. In order to specialize +a single method of ZPair for a function, simply specialize the corresponding +method implementation structure. +*/ + +//Forward Declaration of ZPair::operator < struct +template +struct ZPair_OperatorLessThanImpl { + inline static bool Call(const ZPair& _self, const ZPair& _other); +}; + +//Forward Declaration of ZPair::operator = struct +template +struct ZPair_OperatorEqualsAssignImpl { + inline static ZPair& Call(ZPair& _self, const ZPair& _other); +}; + +//Forward Declaration of ZPair::operator == struct +template +struct ZPair_OperatorEqualsCompareImpl { + inline static bool Call(const ZPair& _self, const ZPair& _other); +}; + +//Forward Declaration of ZPair::operator != struct +template +struct ZPair_OperatorNotEqualImpl { + inline static bool Call(const ZPair& _self, const ZPair& _other); +}; + +//Forward Declaration of ZPair::Swap struct +template +struct ZPair_SwapImpl { + inline static ZPair Call(const ZPair& _self); +}; + +/* +Dynamic tuple implementation. + +The template parameter T1 is the type of the first contained value. + +The template parameter T2 is the type of the second contained value. +*/ +template +class ZPair +{ +friend struct ZPair_OperatorLessThanImpl; +friend struct ZPair_OperatorEqualsAssignImpl; +friend struct ZPair_OperatorEqualsCompareImpl; +friend struct ZPair_OperatorNotEqualImpl; +friend struct ZPair_SwapImpl; + +public: + //The first value + T1 First; + + //The second value + T2 Second; + + /* + Default constructor. + */ + ZPair() + : First(), Second() { } + + /* + Copy constructor. + + @param _other - the other pair + */ + ZPair(const ZPair& _other) + : First(_other.First), Second(_other.Second) { } + + /* + Parameterized constructor. + + @param _first - the first value + @param _second - the second value + */ + ZPair(const T1& _first, const T2& _second) + : First(_first), Second(_second) { } + + /* + operator < override, used to ensure ZPair can be compared using the default ZComparator. + + @param _other - the other pair + @return (bool) - true if this ZPair is less than the other, false otherwise + */ + bool operator < (const ZPair& _other) const + { return ZPair_OperatorLessThanImpl::Call(*this, _other); } + + /* + operator = override, used to assign the ZPair to another. + + @param _other - the other pair + @return (ZPair&) - this pair + */ + ZPair& operator = (const ZPair& _other) + { return ZPair_OperatorEqualsAssignImpl::Call(*this, _other); } + + /* + operator == override. + + @param _other - the other pair + @return (bool) - true if this pair is equal to the other, false otherwise + */ + bool operator == (const ZPair& _other) const + { return ZPair_OperatorEqualsCompareImpl::Call(*this, _other); } + + /* + operator != override. + + @param _other - the other pair + @return (bool) - true if this pair is not equal to the other, false otherwise + */ + bool operator != (const ZPair& _other) const + { return ZPair_OperatorNotEqualImpl::Call(*this, _other); } + + /* + public ZPair::Swap + + Returns another pair that is has swapped the first and second values of this pair. + + @return (ZPair) - a pair with swapped first/second values + */ + ZPair Swap() const + { return ZPair_SwapImpl::Call(*this); } +}; + +//////////////////////////////////////////// +/* Non-Specialized Method Implementations */ +//////////////////////////////////////////// + +template +bool ZPair_OperatorLessThanImpl::Call( const ZPair& _self, const ZPair& _other ) +{ + if (_self.First < _other.First) + return true; + + return (_self.Second < _other.Second); +} + +template +ZPair& ZPair_OperatorEqualsAssignImpl::Call( ZPair& _self, const ZPair& _other ) +{ + _self.First = _other.First; + _self.Second = _other.Second; + + return _self; +} + +template +bool ZPair_OperatorEqualsCompareImpl::Call( const ZPair& _self, const ZPair& _other ) +{ + if (_self.First == _other.First && _self.Second == _other.Second) + return true; + + return false; +} + +template +bool ZPair_OperatorNotEqualImpl::Call( const ZPair& _self, const ZPair& _other ) +{ + return !(_self == _other); +} + +template +ZPair ZPair_SwapImpl::Call( const ZPair& _self ) +{ + return ZPair(_self.Second, _self.First); +} + +#endif diff --git a/Lib/Include/ZSTL/ZRingBuffer.hpp b/Lib/Include/ZSTL/ZRingBuffer.hpp new file mode 100644 index 0000000..e5cb3b5 --- /dev/null +++ b/Lib/Include/ZSTL/ZRingBuffer.hpp @@ -0,0 +1,1378 @@ +/* + ZRingBuffer.hpp + Author: Chris Ertel + James Russell + Created: 12/01/2011 + + Purpose: + + Templated array-backed resizable circular buffer implementation. + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ + +#pragma once + +#ifndef _ZRINGBUFFER_HPP +#define _ZRINGBUFFER_HPP + +#include + +//Default local storage for ring buffer +#ifndef ZRINGBUFFER_DEFAULT_LOCAL_STORAGE +#define ZRINGBUFFER_DEFAULT_LOCAL_STORAGE (100) +#endif + +//Default capacity for ring buffer +#ifndef ZRINGBUFFER_DEFAULT_CAPACITY +#define ZRINGBUFFER_DEFAULT_CAPACITY (100) +#endif + +//Resize factor for ZRingBuffer when operations are performed that require an increase in capacity +#ifndef ZRINGBUFFER_CAPACITY_RESIZE_FACTOR +#define ZRINGBUFFER_CAPACITY_RESIZE_FACTOR (2.0) +#endif + +//////////////////////////////// +/* ZRingBuffer Implementation */ +//////////////////////////////// + +//Forward declaration of ZRingBuffer +template +class ZRingBuffer; + +/* +Forward Declaration of ZRingBuffer Method Implementation Structures + +Existence of these structures allows for template specialization of +individual methods of the ZRingBuffer class. In order to specialize +a single method of ZRingBuffer, simply specialize the corresponding +method implementation structure. +*/ + +//Forward declaration of ZRingBuffer::At struct +template +struct ZRingBuffer_AtImpl { + inline static T& Call( const ZRingBuffer& _self, const size_t _index); +}; + +//Forward declaration of ZRingBuffer::Back struct +template +struct ZRingBuffer_BackImpl { + inline static T& Call( const ZRingBuffer& _self ); +}; + +//Forward declaration of ZRingBuffer::Capacity struct +template +struct ZRingBuffer_CapacityImpl { + inline static size_t Call( const ZRingBuffer& _self ); +}; + +//Forward declaration of ZRingBuffer::Clear struct +template +struct ZRingBuffer_ClearImpl { + inline static void Call( ZRingBuffer& _self ); + inline static void Call( ZRingBuffer& _self, size_t _newCapacity ); +}; + +//Forward declaration of ZRingBuffer::Copy struct +template +struct ZRingBuffer_CopyImpl { + template inline static void Call( ZRingBuffer& _self, const ZRingBuffer& _other ); +}; + +//Forward declaration of ZRingBuffer::Empty struct +template +struct ZRingBuffer_EmptyImpl { + inline static bool Call( const ZRingBuffer& _self ); +}; + +//Forward declaration of ZRingBuffer::Equals struct +template +struct ZRingBuffer_EqualsImpl { + template inline static bool Call( const ZRingBuffer& _self, const ZRingBuffer& _other ); +}; + +//Forward declaration of ZRingBuffer::Erase struct +template +struct ZRingBuffer_EraseImpl { + inline static T Call( ZRingBuffer& _self, size_t _index); + inline static void Call( ZRingBuffer& _self, size_t _i, size_t _j ); +}; + +//Forward declaration of ZRingBuffer::Front struct +template +struct ZRingBuffer_FrontImpl { + inline static T& Call( const ZRingBuffer& _self ); +}; + +//Forward declaration of ZRingBuffer::Full struct +template +struct ZRingBuffer_FullImpl { + inline static bool Call( const ZRingBuffer& _self ); +}; + +//Forward declaration of ZRingBuffer::Insert struct +template +struct ZRingBuffer_InsertImpl { + inline static void Call ( ZRingBuffer& _self, size_t _index, const T& _value, size_t _count ); + template inline static void Call( ZRingBuffer& _self, size_t _index, const ZArray& _array, size_t _start, size_t _count ); + template inline static void Call( ZRingBuffer& _self, size_t _index, const ZRingBuffer& _other, size_t _start, size_t _count ); +}; + +//Forward declaration of ZRingBuffer::PopBack struct +template +struct ZRingBuffer_PopBackImpl { + inline static T Call( ZRingBuffer& _self ); +}; + +//Forward declaration of ZRingBuffer::PopFront struct +template +struct ZRingBuffer_PopFrontImpl { + inline static T Call( ZRingBuffer& _self ); +}; + +//Forward declaration of ZRingBuffer::PushBack struct +template +struct ZRingBuffer_PushBackImpl { + inline static void Call( ZRingBuffer& _self, const T& _value ); +}; + +//Forward declaration of ZRingBuffer::PushFront struct +template +struct ZRingBuffer_PushFrontImpl { + inline static void Call( ZRingBuffer& _self, const T& _value ); +}; + +//Forward declaration of ZRingBuffer::Reserve struct +template +struct ZRingBuffer_ReserveImpl { + inline static void Call( ZRingBuffer& _self, size_t _newCapacity ); +}; + +//Forward declaration of ZRingBuffer::Size struct +template +struct ZRingBuffer_SizeImpl { + inline static size_t Call( const ZRingBuffer& _self ); +}; + +//Forward declaration of ZRingBuffer::TryPushBack struct +template +struct ZRingBuffer_TryPushBackImpl { + inline static bool Call( ZRingBuffer& _self, const T& _value ); +}; + +//Forward declaration of ZRingBuffer::TryPushFront struct +template +struct ZRingBuffer_TryPushFrontImpl { + inline static bool Call( ZRingBuffer& _self, const T& _value ); +}; + +///////////////////////////////////////// +/* ZRingBuffer Overflow Policy Structs */ +///////////////////////////////////////// + +//When used for template parameter P, then overflow is never checked for +struct ZRingBuffer_OverflowUnsafe {}; + +//When used for template parameter P, then overflow causes an assert +struct ZRingBuffer_OverflowAssert {}; + +//When used for template parameter P, then overflow is ignored and the new element is dropped +struct ZRingBuffer_OverflowIgnore {}; + +//When used for template parameter P, then overflow causes the front element to be dropped +struct ZRingBuffer_OverflowDropFront {}; + +//When used for template parameter P, then overflow causes the back element to be dropped +struct ZRingBuffer_OverflowDropBack {}; + +//When used for template parameter P, then overflow causes the current element to be overwritten +struct ZRingBuffer_OverflowOverwrite {}; + +//When used for template parameter P, then overflow evicts the first element (PushBack) or last element (PushFront) +struct ZRingBuffer_OverflowEvict {}; + +//When used for template parameter P, then overflow causes the storage to grow +struct ZRingBuffer_OverflowGrow {}; + +///////////////////////////// +/* ZRingBuffer Declaration */ +///////////////////////////// + +/* +Templated array-backed circular buffer implementation. + +The template parameter T is the type contained in the buffer. + +The template parameter P is the overflow policy for the ring buffer. Overflow only occurs during +push and pop operations - other methods of adding (such as insert) to the ring buffer will always grow the +buffer. + +The template parameter A is the allocator that will be used by the underlying array. +*/ +template > +class ZRingBuffer +{ +friend struct ZRingBuffer_AtImpl; +friend struct ZRingBuffer_BackImpl; +friend struct ZRingBuffer_CapacityImpl; +friend struct ZRingBuffer_ClearImpl; +friend struct ZRingBuffer_CopyImpl; +friend struct ZRingBuffer_EmptyImpl; +friend struct ZRingBuffer_EqualsImpl; +friend struct ZRingBuffer_EraseImpl; +friend struct ZRingBuffer_FrontImpl; +friend struct ZRingBuffer_FullImpl; +friend struct ZRingBuffer_InsertImpl; +friend struct ZRingBuffer_PopBackImpl; +friend struct ZRingBuffer_PopFrontImpl; +friend struct ZRingBuffer_PushBackImpl; +friend struct ZRingBuffer_PushFrontImpl; +friend struct ZRingBuffer_ReserveImpl; +friend struct ZRingBuffer_SizeImpl; +friend struct ZRingBuffer_TryPushFrontImpl; +friend struct ZRingBuffer_TryPushBackImpl; + +protected: + //Backing array of the ring buffer + ZArray Buffer; + + //Current number of elements in the ring buffer + size_t BufferSize; + + //Index into the backing array of the front element of the ring buffer + size_t FrontIndex; + + //Index into the backing array of the back element of the ring buffer + size_t BackIndex; + + //Aligns the buffer with front index at zero + inline void AlignBuffer() + { + //If FrontIndex is set to zero, then we are aligned + if (FrontIndex == 0) + return; + + ZArray copy(Buffer.Capacity()); + + copy.Resize(Buffer.Size()); + + for (size_t num = 0; num < (size_t)BufferSize; num++) + copy.Data()[num] = At(num); + + Buffer = copy; + FrontIndex = 0; + BackIndex = BufferSize - 1; + } + + //Integrity Check + inline void CheckIntegrity() const + { + #if ZSTL_CHECK_INTEGRITY + ZSTL_ASSERT(FrontIndex < Buffer.Size(), "ZRingBuffer Error: Front index exceeds capacity!"); + ZSTL_ASSERT(BackIndex < Buffer.Size(), "ZRingBuffer Error: Back index exceeds capacity!"); + #endif + } + + //Decrements the BackIndex (decreases size) + inline ZRingBuffer& DecrementBack() + { + //The back index does not move if we remove the last element + if (BufferSize != 1) + { + if (BackIndex == 0) + BackIndex = Buffer.Size() - 1; + else + BackIndex--; + } + + BufferSize--; + + return *this; + } + + //Decrements the FrontIndex (increases size) + inline ZRingBuffer& DecrementFront() + { + //The first element push does not require moving the back index + if (BufferSize != 0) + { + if (FrontIndex == 0) + FrontIndex = Buffer.Size() - 1; + else + FrontIndex--; + } + + BufferSize++; + + return *this; + } + + //Increments the BackIndex (increases size) + inline ZRingBuffer& IncrementBack() + { + //The first element push does not require moving the back index + if (BufferSize != 0) + { + if (BackIndex == Buffer.Size() - 1) + BackIndex = 0; + else + BackIndex++; + } + + BufferSize++; + + return *this; + } + + //Increments the FrontIndex (decreases size) + inline ZRingBuffer& IncrementFront() + { + //The front index does not move if we remove the last element + if (BufferSize != 1) + { + if (FrontIndex == Buffer.Size() - 1) + FrontIndex = 0; + else + FrontIndex++; + } + + BufferSize--; + + return *this; + } + +public: + /* + Default constructor. Initializes an empty ring buffer with a default capacity. + */ + ZRingBuffer() + : Buffer(ZRINGBUFFER_DEFAULT_CAPACITY), + BufferSize(0), FrontIndex(0), BackIndex(0) + { Buffer.Resize(ZRINGBUFFER_DEFAULT_CAPACITY); } + + /* + Parameterized constructor for ZRingBuffer. Initializes empty, but allows specification of capacity. + + @param _capacity - initial capacity for the ring buffer + */ + ZRingBuffer(size_t _capacity) + : Buffer(_capacity), + BufferSize(0), FrontIndex(0), BackIndex(0) + { Buffer.Resize(_capacity); } + + /* + Parameterized constructor to use for ZRingBuffer. Allows default assignment of + contained elements. The starting size of the buffer is equal to the array size. The + starting capacity of the buffer is equal to the array capacity. + + @param _storage - ZArray containing default set of elements + */ + ZRingBuffer(const ZArray& _storage) + : Buffer(_storage), + BufferSize(_storage.Size()), FrontIndex(0), BackIndex(_storage.Size() - 1) + { Buffer.Resize(_storage.Capacity()); } + + /* + Destructor. + */ + ~ZRingBuffer() { } + + /* + [] Operator overload. Gets a value from the buffer. Equivalent to + a call to At. + + @param _index - the integer index into the buffer + @return (T&) - reference to a value contained in the buffer + */ + T& operator [] (const size_t _index) const + { return At(_index); } + + /* + = Operator overload. Sets this buffer equal to the other by making + a copy. Equivalent to a call to Copy. + + Even though the code is the same as the more generic version below, + this is needed to prevent a default assignment operator from being constructed. + + @param _other - the buffer to be set equal to + @return (void) + */ + ZRingBuffer& operator = (const ZRingBuffer& _other) + { Copy(_other); return *this; } + + /* + = Operator overload. Sets this buffer equal to the other by making + a copy. Equivalent to a call to Copy. + + @param _other - the buffer to be set equal to + @return (void) + */ + template + ZRingBuffer& operator = (const ZRingBuffer& _other) + { Copy(_other); return *this; } + + /* + == Operator overload. Performs an element comparison on the two buffers. + Equivalent to a call to Equals. + + @param B - the type of allocator for the other buffer + @param _other - the buffer to compare to + @return (bool) - true if this buffer is equivalent to the other + */ + template + bool operator == (const ZRingBuffer& _other) const + { return Equals(_other); } + + /* + != Operator overload. Performs an element comparison on the two buffers. + Equivalent to a call to !Equals. + + @param B - the type of the allocator for the other buffer + @param _other - the buffer to compare to + @return (bool) - false if this buffer is equivalent to the other + */ + template + bool operator != (const ZRingBuffer& _other) const + { return !Equals(_other); } + + /* + public ZRingBuffer::Actual + + Function that gives an actual index into the underlying array given an index into + the ring buffer. Will also perform bounds checking and assert if out of bounds. + + @param _index - index + @return (size_t) - unsigned index into the backing array + */ + size_t ActualIndex(size_t _index) const + { + size_t index; + + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(_index < BufferSize, "ZRingBuffer: Out of bounds access!"); + #endif + + index = ((size_t)_index + FrontIndex) % Buffer.Size(); + + #if !ZSTL_DISABLE_RUNTIME_CHECKS + + if (FrontIndex < BackIndex) + { + ZSTL_ASSERT(((index >= FrontIndex) && (index <= BackIndex)), "ZRingBuffer: Out of bounds access!"); + } + else //FrontIndex >= BackIndex + { + ZSTL_ASSERT(((index >= FrontIndex) || (index <= BackIndex)), "ZRingBuffer: Out of bounds access!"); + } + + #endif + + return index; + } + + /* + public ZRingBuffer::Allocator + + Gets a reference to the allocator used by this buffer. + + @return (A&) - the allocator used by this buffer + */ + A& Allocator() + { return Buffer.Allocator(); } + + /* + public ZRingBuffer::Array + + Gets a reference to the array that backs this buffer. The elements are not guaranteed to + be stored in order. + + @return (ZArray&) - the array backing this buffer + */ + const ZArray& Array() const + { return Buffer; } + + /* + public ZRingBuffer::At + + Gets a reference to the element indexed by the provided index. The index 0 refers + to the front element in the buffer, the index 1 the following, and so on up to the back + element. This allows random access of the buffer, though more overhead is involved than + random access of ZArray. + + @param _index - index into the buffer + @return (T&) - element at the indexed location + @assert - if _index is out of bounds + */ + T& At(const size_t _index) const + { return ZRingBuffer_AtImpl::Call(*this, _index); } + + /* + public ZRingBuffer::Back + + Gets a reference to the back element of the buffer. + + @return (T&) - reference to back element in buffer + @assert - if the buffer is empty + */ + T& Back() const + { return ZRingBuffer_BackImpl::Call(*this); } + + /* + public ZRingBuffer::Capacity + + Gets the capacity of the ring buffer, which is the maximum number of elements that + can be stored before a resize is required. + + @return (size_t) - the capacity of the ring buffer + */ + size_t Capacity() const + { return ZRingBuffer_CapacityImpl::Call(*this); } + + /* + public ZRingBuffer::Clear + + Clears out all elements from the buffer, keeping the currently allocated storage. + + @return (void) + */ + void Clear() + { ZRingBuffer_ClearImpl::Call(*this); } + + /* + public ZRingBuffer::Clear + + Clears out all elements from the buffer and will ensure that the capacity is + at least as much as the provided value. Reallocates the internal storage if necessary. + + @param _newCapacity - the new capacity value + @return (void) + */ + void Clear(size_t _newCapacity) + { ZRingBuffer_ClearImpl::Call(*this, _newCapacity); } + + /* + public ZRingBuffer::Copy + + Copies the contents of another buffer into this one. + + @param O - overflow policy for the other buffer + @param B - allocator type for the other buffer + @param _other - the ring buffer to copy + @return (void) + */ + template + void Copy(const ZRingBuffer& _other) + { ZRingBuffer_CopyImpl::template Call(*this, _other); } + + /* + public ZRingBuffer::Empty + + Tests whether or not the ring buffer is empty. + + @return (bool) - true is empty, false if not empty + */ + bool Empty() const + { return ZRingBuffer_EmptyImpl::Call(*this); } + + /* + public ZRingBuffer::Equals + + Tests whether or not this buffer is equivalent to another. The two are considered + equivalent if they contain equivalent elements in the same order. + + @param O - overflow policy for the other buffer + @param B - allocator type for the other buffer + @param _other - the other buffer + @return (bool) - true if equal, false otherwise + */ + template + bool Equals(const ZRingBuffer& _other) + { return ZRingBuffer_EqualsImpl::template Call(*this, _other); } + + /* + public ZRingBuffer::Erase + + Erases a value present in the buffer at the given index. + + @param _index - the index at which to remove the element from the array + @return (T) - the element removed + @assert - if the index is out of range + */ + T Erase(size_t _index) + { return ZRingBuffer_EraseImpl::Call(*this, _index); } + + /* + public ZRingBuffer::Erase + + Erase function. Removes elements from the buffer between the given indices. + + @param _i - first index + @param _j - second index (exclusive) + @return (void) + @assert - if either index is out of range or if _j < _i + */ + void Erase(size_t _i, size_t _j) + { ZRingBuffer_EraseImpl::Call(*this, _i, _j); } + + /* + public ZRingBuffer::Front + + Gets a reference to the front element of the buffer. + + @return (T&) - reference to front element in buffer. + @assert - if the buffer is empty + */ + T& Front() const + { return ZRingBuffer_FrontImpl::Call(*this); } + + /* + public ZRingBuffer::Full + + Tests whether or not the ring buffer is full. If full, the overflow policy + determines what is done whenever any operation that adds elements to the + buffer. + + @return (bool) - true if full, false if not full + */ + bool Full() const + { return ZRingBuffer_FullImpl::Call(*this); } + + /* + public ZRingBuffer::Insert + + Inserts the given value at the specified location. Ring buffers are + not well suited to perform this operation quickly, so use sparingly. + + @param _index - the index at which to perform the insertion + @param _value - the value to insert + @return (void) + @assert - if _index is out of range + */ + void Insert(size_t _index, const T& _value) + { ZRingBuffer_InsertImpl::Call(*this, _index, _value, 1); } + + /* + public ZRingBuffer::Insert + + Inserts the given value at the specified location. Ring buffers are + not well suited to perform this operation quickly, so use sparingly. + + @param _index - the index at which to perform the insertion + @param _value - the value to insert + @param _count - the number of times to insert _value + @return (void) + @assert - if _index is out of range + */ + void Insert(size_t _index, const T& _value, size_t _count) + { ZRingBuffer_InsertImpl::Call(*this, _index, _value, _count); } + + /* + public ZRingBuffer::Insert + + Inserts the given array at the specified location. Copies + the values into the buffer. Ring buffers are not well suited + to perform this operation quickly, so use sparingly. + + @param _index - the index at which to perform the insertion + @param _array - the array to insert + @return (void) + @assert - if _index is out of range + */ + template + void Insert(size_t _index, const ZArray& _array) + { ZRingBuffer_InsertImpl::template Call(*this, _index, _array, 0, _array.Size()); } + + /* + public ZRingBuffer::Insert + + Inserts data from the given array at the specified location. Copies + the values into the buffer. Ring buffers are not well suited + to perform this operation quickly, so use sparingly. + + @param _index - the index at which to perform the insertion + @param _array - the array to insert + @param _start - the index to start getting values from + @param _count - the number of values to get + @return (void) + @assert - if _index is out of range + */ + template + void Insert(size_t _index, const ZArray& _array, size_t _start, size_t _count) + { ZRingBuffer_InsertImpl::template Call(*this, _index, _array, _start, _count); } + + /* + public ZRingBuffer::Insert + + Inserts the given buffer at the specified location. Copies + the values into the buffer. Ring buffers are not well suited + to perform this operation quickly, so use sparingly. + + @param O - overflow policy for the other buffer + @param B - allocator type for the other buffer + @param _index - the index at which to perform the insertion + @param _other - the buffer to insert + @return (void) + @assert - if _index is out of range + */ + template + void Insert(size_t _index, const ZRingBuffer& _other) + { ZRingBuffer_InsertImpl::template Call(*this, _index, _other, 0, _other.Size()); } + + /* + public ZRingBuffer::Insert + + Inserts data from the given buffer at the specified location. Copies + the values into the buffer. Ring buffers are not well suited + to perform this operation quickly, so use sparingly. + + @param O - overflow policy for the other buffer + @param B - allocator type for the other buffer + @param _index - the index at which to perform the insertion + @param _other - the buffer to insert + @param _start - the index to start getting values from + @param _count - the number of values to get + @return (void) + @assert - if _index is out of range + */ + template + void Insert(size_t _index, const ZRingBuffer& _other, size_t _start, size_t _count) + { ZRingBuffer_InsertImpl::template Call(*this, _index, _other, _start, _count); } + + /* + public ZRingBuffer::PopBack + + Function to pop the back element off of the ring buffer. + + @return (T) - the back element in the buffer + @assert - if the buffer is empty + */ + T PopBack() + { return ZRingBuffer_PopBackImpl::Call(*this); } + + /* + public ZRingBuffer::PopFront + + Function to pop the front element off of the ring buffer. + + @return (T) - the front element in the buffer + @assert - if the buffer is empty + */ + T PopFront() + { return ZRingBuffer_PopFrontImpl::Call(*this); } + + /* + public ZRingBuffer::PushBack + + Pushes an element onto the back of this ring buffer. + + @param _value - element to push onto back of ring buffer + @return (void) + @assert - if the buffer is full + */ + void PushBack(const T& _value) + { ZRingBuffer_PushBackImpl::Call(*this, _value); } + + /* + public ZRingBuffer::PushFront + + Pushes an element onto the front of this ring buffer. + + @param _value - element to push onto front of ring buffer + @return (void) + @assert - if the buffer is full + */ + void PushFront(const T& _value) + { ZRingBuffer_PushFrontImpl::Call(*this, _value); } + + /* + public ZRingBuffer::Reserve + + Changes the capacity of the backing array to accommodate the given size. Existing items in the + buffer remain in order and unaffected, though copy assignment may be required. + + @param _newCapacity - new capacity to reserve in ring buffer + @return (void) + @assert - if the new capacity is smaller than the current size + */ + void Reserve(size_t _newCapacity) + { ZRingBuffer_ReserveImpl::Call(*this, _newCapacity); } + + /* + public ZRingBuffer::Size + + Gets the size of the ring buffer, which is the current number of contained elements. + + @return (size_t) - the number of elements in the ring buffer. + */ + size_t Size() const + { return ZRingBuffer_SizeImpl::Call(*this); } + + /* + public ZRingBuffer::TryPushFront + + Tries to push an element onto the ring buffer, returning success or failure. + + If the element is unable to be pushed onto the buffer, no change is made to the buffer. + + @param _value - element to push onto front of ring buffer. + @return (bool) - true if push was successful, false if not. + */ + bool TryPushFront(const T& _value) + { return ZRingBuffer_TryPushFrontImpl::Call(*this, _value); } + + /* + public ZRingBuffer::TryPushBack + + Tries to push an element onto the ring buffer, returning success or failure. + + If the element is unable to be pushed onto the buffer, no change is made to the buffer. + + @param _value - element to push onto the back of the ring buffer. + @return (bool) - true if push was successful, false if not. + */ + bool TryPushBack(const T& _value) + { return ZRingBuffer_TryPushBackImpl::Call(*this, _value); } +}; + +//////////////////////////////////////////// +/* Non-Specialized Method Implementations */ +//////////////////////////////////////////// + +template +T& ZRingBuffer_AtImpl::Call(const ZRingBuffer& _self, const size_t _index) +{ + return _self.Buffer.Data()[_self.ActualIndex(_index)]; //Bounds checking will be done by ActualIndex +} + +/*************************************************************************/ + +template +T& ZRingBuffer_BackImpl::Call(const ZRingBuffer& _self) +{ + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT( _self.BufferSize > 0, "ZRingBuffer::Back() called with no elements present!"); + #endif + + return _self.Buffer.Data()[_self.BackIndex]; +} + +/*************************************************************************/ + +template +size_t ZRingBuffer_CapacityImpl::Call(const ZRingBuffer& _self) +{ + return _self.Buffer.Size(); +} + +/*************************************************************************/ + +template +void ZRingBuffer_ClearImpl::Call( ZRingBuffer& _self ) +{ + _self.BufferSize = 0; + _self.FrontIndex = 0; + _self.BackIndex = 0; +} + +/*************************************************************************/ + +template +void ZRingBuffer_ClearImpl::Call( ZRingBuffer& _self, size_t _newCapacity ) +{ + _self.Buffer.Resize(_newCapacity); + + _self.BufferSize = 0; + _self.FrontIndex = 0; + _self.BackIndex = 0; +} + +/*************************************************************************/ + +template template +void ZRingBuffer_CopyImpl::Call( ZRingBuffer& _self, const ZRingBuffer& _other ) +{ + _self.Buffer.Copy(_other.Buffer); + + _self.BufferSize = _other.BufferSize; + _self.FrontIndex = _other.FrontIndex; + _self.BackIndex = _other.BackIndex; +} + +/*************************************************************************/ + +template +bool ZRingBuffer_EmptyImpl::Call(const ZRingBuffer& _self) +{ + return _self.BufferSize == 0; +} + +/*************************************************************************/ + +template template +bool ZRingBuffer_EqualsImpl::Call( const ZRingBuffer& _self, const ZRingBuffer& _other ) +{ + size_t i; + + //Easy out #1 + if (&_self == &_other) + return true; + + //Easy out #2 + if (_self.Size() != _other.Size()) + return false; + + //Element by element comparison + for (i = 0; i < _self.Size(); i++) + { + if (_self.At(i) != _other.At(i)) + return false; + } + + return true; +} + +/*************************************************************************/ + +template +T ZRingBuffer_EraseImpl::Call(ZRingBuffer& _self, const size_t _index) +{ + //We are going to do this in a very naive fashion, as this container is not intended for these + //kinds of operations anyhow. Anyone who wishes to optimize this at a later date is welcome. + + _self.AlignBuffer(); + + _self.BufferSize--; + _self.BackIndex--; + + return _self.Buffer.Erase(_index); +} + +/*************************************************************************/ + +template +void ZRingBuffer_EraseImpl::Call( ZRingBuffer& _self, size_t _i, size_t _j ) +{ + //We are going to do this in a very naive fashion, as this container is not intended for these + //kinds of operations anyhow. Anyone who wishes to optimize this at a later date is welcome. + + size_t count; + + _self.AlignBuffer(); + + count = (size_t)(_j - _i); + + _self.BufferSize = _self.BufferSize - count; + _self.BackIndex = _self.BackIndex - count; + + _self.Buffer.Erase(_i, _j); +} + +/*************************************************************************/ + +template +T& ZRingBuffer_FrontImpl::Call(const ZRingBuffer& _self) +{ + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT( _self.BufferSize > 0, "ZRingBuffer::Front() called with no elements present!"); + #endif + + return _self.Buffer.Data()[_self.FrontIndex]; +} + +/*************************************************************************/ + +template +bool ZRingBuffer_FullImpl::Call(const ZRingBuffer& _self) +{ + return _self.BufferSize == _self.Buffer.Size(); +} + +/*************************************************************************/ + +template +void ZRingBuffer_InsertImpl::Call( ZRingBuffer& _self, size_t _index, const T& _value, size_t _count ) +{ + //We are going to do this in a very naive fashion, as this container is not intended for these + //kinds of operations anyhow. Anyone who wishes to optimize this at a later date is welcome. + + _self.AlignBuffer(); + + _self.Buffer.Insert(_index, _value, _count); + _self.Buffer.Resize(_self.Buffer.Capacity()); //In case the insert caused a grow + + _self.BackIndex = _self.BackIndex + _count; + _self.BufferSize = _self.BufferSize + _count; +} + +/*************************************************************************/ + +template template +void ZRingBuffer_InsertImpl::Call( ZRingBuffer& _self, size_t _index, const ZArray& _array, size_t _start, size_t _count ) +{ + //We are going to do this in a very naive fashion, as this container is not intended for these + //kinds of operations anyhow. Anyone who wishes to optimize this at a later date is welcome. + + _self.AlignBuffer(); + + _self.Buffer.Insert(_index, _array, _start, _count); + _self.Buffer.Resize(_self.Buffer.Capacity()); //In case the insert caused a grow + + _self.BackIndex = _self.BackIndex + _count; + _self.BufferSize = _self.BufferSize + _count; +} + +/*************************************************************************/ + +template template +void ZRingBuffer_InsertImpl::Call( ZRingBuffer& _self, size_t _index, const ZRingBuffer& _other, size_t _start, size_t _count ) +{ + //We are going to do this in a very naive fashion, as this container is not intended for these + //kinds of operations anyhow. Anyone who wishes to optimize this at a later date is welcome. + + ZRingBuffer copy(_other); + + copy.AlignBuffer(); + _self.AlignBuffer(); + + _self.Buffer.Insert(_index, copy.Array(), _start, _count); + _self.Buffer.Resize(_self.Buffer.Capacity()); //In case the insert caused a grow + + _self.BackIndex = _self.BackIndex + _count; + _self.BufferSize = _self.BufferSize + _count; +} + +/*************************************************************************/ + +template +T ZRingBuffer_PopBackImpl::Call(ZRingBuffer& _self) +{ + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT( _self.BufferSize > 0, "ZRingBuffer::PopBack() caused underflow!"); + #endif + + size_t index = _self.BackIndex; + + _self.DecrementBack(); + + _self.CheckIntegrity(); + + return _self.Buffer.Data()[index]; +} + +/*************************************************************************/ + +template +T ZRingBuffer_PopFrontImpl::Call(ZRingBuffer& _self) +{ + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT( _self.BufferSize > 0, "ZRingBuffer::PopFront() caused underflow!"); + #endif + + size_t index = _self.FrontIndex; + + _self.IncrementFront(); + + _self.CheckIntegrity(); + + return _self.Buffer.Data()[index]; +} + +/*************************************************************************/ + +template +void ZRingBuffer_PushBackImpl::Call(ZRingBuffer& _self, const T& _value) +{ + URFP(_self); URFP(_value); + P::UnimplementedMethod; //This will cause a compiler error if P is of invalid type +} + +/*************************************************************************/ + +template +struct ZRingBuffer_PushBackImpl { + inline static void Call(ZRingBuffer& _self, const T& _value) + { + _self.IncrementBack().Buffer.Data()[_self.BackIndex] = _value; + } +}; + +/*************************************************************************/ + +template +struct ZRingBuffer_PushBackImpl { + inline static void Call(ZRingBuffer& _self, const T& _value) + { + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT( _self.BufferSize < _self.Buffer.Size(), "ZRingBuffer::PushBack() caused overflow!"); + #endif + + _self.IncrementBack().Buffer.Data()[_self.BackIndex] = _value; + } +}; + +/*************************************************************************/ + +template +struct ZRingBuffer_PushBackImpl { + inline static void Call(ZRingBuffer& _self, const T& _value) + { + //See if we should be ignoring this call + if (_self.Full()) + return; + + _self.IncrementBack().Buffer.Data()[_self.BackIndex] = _value; + } +}; + +/*************************************************************************/ + +template +struct ZRingBuffer_PushBackImpl { + inline static void Call(ZRingBuffer& _self, const T& _value) + { + //See if we need to drop the back element + if (_self.Full()) + _self.DecrementBack(); + + _self.IncrementBack().Buffer.Data()[_self.BackIndex] = _value; + } +}; + +/*************************************************************************/ + +template +struct ZRingBuffer_PushBackImpl { + inline static void Call(ZRingBuffer& _self, const T& _value) + { + //See if we need to drop the front element + if (_self.Full()) + _self.IncrementFront(); + + _self.IncrementBack().Buffer.Data()[_self.BackIndex] = _value; + } +}; + +/*************************************************************************/ + +template +struct ZRingBuffer_PushBackImpl { + inline static void Call(ZRingBuffer& _self, const T& _value) + { + //See if we need to overwrite the current element + if (_self.Full()) + _self.Buffer.Data()[_self.BackIndex] = _value; + else + _self.IncrementBack().Buffer.Data()[_self.BackIndex] = _value; + } +}; + +/*************************************************************************/ + +template +struct ZRingBuffer_PushBackImpl { + inline static void Call(ZRingBuffer& _self, const T& _value) + { + //See if we need to evict the opposite element + if (_self.Full()) + _self.IncrementFront(); + + _self.IncrementBack().Buffer.Data()[_self.BackIndex] = _value; + } +}; + +/*************************************************************************/ + +template +struct ZRingBuffer_PushBackImpl { + inline static void Call(ZRingBuffer& _self, const T& _value) + { + //See if we need to reserve more space + if (_self.Full()) + _self.Reserve((size_t)(_self.BufferSize * ZRINGBUFFER_CAPACITY_RESIZE_FACTOR)); + + _self.IncrementBack().Buffer.Data()[_self.BackIndex] = _value; + } +}; + +/*************************************************************************/ + +template +void ZRingBuffer_PushFrontImpl::Call(ZRingBuffer& _self, const T& _value) +{ + URFP(_self); URFP(_value); + P::UnimplementedMethod; //This will cause a compiler error if P is of invalid type +} + +/*************************************************************************/ + +template +struct ZRingBuffer_PushFrontImpl { + inline static void Call(ZRingBuffer& _self, const T& _value) + { + _self.DecrementFront().Buffer.Data()[_self.FrontIndex] = _value; + } +}; + +/*************************************************************************/ + +template +struct ZRingBuffer_PushFrontImpl { + inline static void Call(ZRingBuffer& _self, const T& _value) + { + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT( _self.BufferSize < _self.Buffer.Size(), "ZRingBuffer::PushFront() caused overflow!"); + #endif + + _self.DecrementFront().Buffer.Data()[_self.FrontIndex] = _value; + } +}; + +/*************************************************************************/ + +template +struct ZRingBuffer_PushFrontImpl { + inline static void Call(ZRingBuffer& _self, const T& _value) + { + //See if we should be ignoring this call + if (_self.Full()) + return; + + _self.DecrementFront().Buffer.Data()[_self.FrontIndex] = _value; + } +}; + +/*************************************************************************/ + +template +struct ZRingBuffer_PushFrontImpl { + inline static void Call(ZRingBuffer& _self, const T& _value) + { + //See if we need to drop the back element + if (_self.Full()) + _self.DecrementBack(); + + _self.DecrementFront().Buffer.Data()[_self.FrontIndex] = _value; + } +}; + +/*************************************************************************/ + +template +struct ZRingBuffer_PushFrontImpl { + inline static void Call(ZRingBuffer& _self, const T& _value) + { + //See if we need to drop the front element + if (_self.Full()) + _self.IncrementFront(); + + _self.DecrementFront().Buffer.Data()[_self.FrontIndex] = _value; + } +}; + +/*************************************************************************/ + +template +struct ZRingBuffer_PushFrontImpl { + inline static void Call(ZRingBuffer& _self, const T& _value) + { + //See if we need to overwrite the current element + if (_self.Full()) + _self.Buffer.Data()[_self.FrontIndex] = _value; + else + _self.DecrementFront().Buffer.Data()[_self.FrontIndex] = _value; + } +}; + +/*************************************************************************/ + +template +struct ZRingBuffer_PushFrontImpl { + inline static void Call(ZRingBuffer& _self, const T& _value) + { + //See if we need to evict the opposite element + if (_self.Full()) + _self.DecrementBack(); + + _self.DecrementFront().Buffer.Data()[_self.FrontIndex] = _value; + } +}; + +/*************************************************************************/ + +template +struct ZRingBuffer_PushFrontImpl { + inline static void Call(ZRingBuffer& _self, const T& _value) + { + //See if we need to reserve more space + if (_self.Full()) + _self.Reserve((size_t)(_self.BufferSize * ZRINGBUFFER_CAPACITY_RESIZE_FACTOR)); + + _self.DecrementFront().Buffer.Data()[_self.FrontIndex] = _value; + } +}; + +/*************************************************************************/ + +template +void ZRingBuffer_ReserveImpl::Call(ZRingBuffer& _self, size_t _newCapacity) +{ + //If the new and current capacities are equal, do nothing. + if (_self.Buffer.Size() == _newCapacity) + return; + + //If the new capacity is smaller than the current size, assert. + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT( _newCapacity >= _self.BufferSize, "ZRingBuffer::Reserve() called with new capacity below size!"); + #endif + + //Align the buffer + _self.AlignBuffer(); + + //Resize the buffer + _self.Buffer.Resize(_newCapacity); +} + +/*************************************************************************/ + +template +size_t ZRingBuffer_SizeImpl::Call(const ZRingBuffer& _self) +{ + return _self.BufferSize; +} + +/*************************************************************************/ + +template +bool ZRingBuffer_TryPushFrontImpl::Call(ZRingBuffer& _self, const T& _value) +{ + if (_self.Full()) + return false; + + _self.PushFront(_value); + + return true; +} + +/*************************************************************************/ + +template +bool ZRingBuffer_TryPushBackImpl::Call(ZRingBuffer& _self, const T& _value) +{ + if (_self.Full()) + return false; + + _self.PushBack(_value); + + return true; +} + +#endif diff --git a/Lib/Include/ZSTL/ZSTL.hpp b/Lib/Include/ZSTL/ZSTL.hpp new file mode 100644 index 0000000..665b540 --- /dev/null +++ b/Lib/Include/ZSTL/ZSTL.hpp @@ -0,0 +1,55 @@ +/* + ZSTL.hpp + Author: James Russell + Created: 12/26/2011 + + Purpose: + + Header file for ZSTL that includes all ZSTL containers. Container utility libraries + are not included - these must be included individually. + + Defining the following features to 1 enables the feature on all ZSTL containers. Defining + to 0 disables the feature (default behavior if undefined). + + ZSTL_CHECK_INTEGRITY + Checks integrity of the ZSTL containers after allocations or if non-const functions are called. + Used for debugging ZSTL. Useful if new methods are added. + + ZSTL_DISABLE_RUNTIME_CHECKS + Disables runtime bounds and error checking on ZSTL containers, iterators, and algorithms. + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ + +#pragma once + +#ifndef _ZSTL_HPP +#define _ZSTL_HPP + +/* Version number constants for ZSTL */ +#define ZSTL_VERSION_MAJOR 0x01 +#define ZSTL_VERSION_MINOR 0x01 +#define ZSTL_VERSION_PATCH 0x0000 +#define ZSTL_VERSION (ZSTL_VERSION_MAJOR << 24) | (ZSTL_VERSION_MINOR << 16) | (ZSTL_VERSION_PATCH) + +#define ZSTL_VERSION_STRING "1.1.0" + +/* The ZSTL headers */ +#include "ZSTLInvalidPos.hpp" +#include "ZSTLCommon.hpp" +#include "ZPair.hpp" +#include "ZArray.hpp" +#include "ZList.hpp" +#include "ZHashMap.hpp" +#include "ZRingBuffer.hpp" +#include "ZString.hpp" + + +#endif diff --git a/Lib/Include/ZSTL/ZSTLCommon.hpp b/Lib/Include/ZSTL/ZSTLCommon.hpp new file mode 100644 index 0000000..5dbb40c --- /dev/null +++ b/Lib/Include/ZSTL/ZSTLCommon.hpp @@ -0,0 +1,383 @@ +/* + ZSTLCommon.hpp + Author: James Russell + Created: 9/13/2011 + + Purpose: + + Common include file used by all ZSTL components. + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ + +#pragma once + +#ifndef _ZSTLCOMMON_HPP +#define _ZSTLCOMMON_HPP + +#include //Need this for our int types +#include //This gives us (std::nothrow) +#include //This gives us assert +#include //This gives us a definition for NULL + +//Hash Value Type +typedef uint64_t ZHashValue; + +//Used to get rid of the (/W4 or -Wall) warning 'Unreferenced Formal Parameter' +#ifndef URFP +#define URFP(x) ((void)x) +#endif + +//Default allocation macro used by ZSTL default allocators +#ifndef ZSTL_NEW +#define ZSTL_NEW(_type) new (std::nothrow) _type() +#endif + +//Default delete macro used by ZSTL default allocators +#ifndef ZSTL_DEL +#define ZSTL_DEL(_object) delete _object +#endif + +//Default array allocation macro used by ZSTL default allocators +#ifndef ZSTL_NEW_ARRAY +#define ZSTL_NEW_ARRAY(_type, _size) new (std::nothrow) _type[_size] +#endif + +//Default array delete macro used by ZSTL default allocators +#ifndef ZSTL_DEL_ARRAY +#define ZSTL_DEL_ARRAY(_ptr, _size) ((void)_size); delete[] _ptr +#endif + +//Default assert macro used by ZSTL +#ifndef ZSTL_ASSERT +#define ZSTL_ASSERT(condition, message) (assert(condition && message)) +#endif + +//Error condition macro used by ZSTL +#ifndef ZSTL_ERROR +#define ZSTL_ERROR(message) (assert(0 && message)) +#endif + +//Swap used in array quicksort (takes array, first index, second index) +#define ZSTL_ARRAY_ELEMENT_SWAP(_a, _i, _j) temp = _a[_j]; _a[_j] = _a[_i]; _a[_i] = temp + +//Push used in list mergesort (takes list node and new node) +#define ZSTL_LIST_ELEMENT_PUSH(_l, _n) if (_l == NULL) { _l = _n; } else { _l->Next = _n; _n->Previous = _l; _l = _n; } + +/* +public BoundsCheck + +Function that checks the provided index against the provided boundary, asserting if an +out of bounds access occurs. Calls to this will be compiled out if ZSTL_DISABLE_RUNTIME_CHECKS +is not zero. + +@param I - the type of index +@param _index - index to check +@param _boundary - the (exclusive) boundary to use for bounds checking +@return (size_t) - unsigned index +@assert - if the index is not less than boundary +*/ +template +size_t BoundsCheck(I _index, I _boundary) +{ + #if !ZSTL_DISABLE_RUNTIME_CHECKS + ZSTL_ASSERT(_index < _boundary, "ZSTL: Out of bounds access!"); + #endif + + return (size_t)_index; +} + +/* +Node class, which is used by ZList to contain list data and previous / next pointers. Could +be used by other classes that also need basic list-like functionality. + +The template parameter T is the type contained by the list node. +*/ +template +struct ZListNode +{ + //Default Constructor + ZListNode() + : Next(NULL), Previous(NULL), Element() { } + + //Parameterized Constructor + ZListNode(ZListNode* _next, ZListNode* _previous) + : Next(_next), Previous(_previous), Element() { } + + //Parameterized Constructor + ZListNode(ZListNode* _next, ZListNode* _previous, const T& _value) + : Next(_next), Previous(_previous), Element(_value) { } + + //The next node + ZListNode* Next; + + //The previous node + ZListNode* Previous; + + //The contained element + T Element; + +}; + +/* +Comparator functor, used when a delegate is needed to provide comparison information on +elements. This implementation uses operator < on elements. + +The template parameter T is the type we will be comparing to each other. +*/ +template +struct ZComparator +{ + ZComparator() { } //Silence Sun C++ warnings about uninitialized structs + + //operator overload which returns -1 if a < b, 0 if a == b, and 1 if a > b + int operator () (const T& _a, const T& _b) const + { + if (_a < _b) + { + return -1; + } + else if (_b < _a) + { + return 1; + } + else + { + return 0; + } + } +}; + +/* +Array quicksort functor. Uses a recursive in-place sort. This implementation is +not a stable sort. + +The template parameter T is the type contained by the array we will be sorting. +*/ +template +struct ZArrayQuickSort +{ + ZArrayQuickSort() { } //Silence Sun C++ warnings about uninitialized structs + + //Helper function which partitions the array + template + inline size_t Partition(CF& _comparator, T* _array, size_t _left, size_t _right, size_t _pivot) + { + size_t i, j; + T temp; + + //Get the value at the pivot point + T pivotValue = _array[_pivot]; + + //Move pivot to end + ZSTL_ARRAY_ELEMENT_SWAP(_array, _pivot, _right); + + //Check values from left up to pivot + for (i = _left, j = _left; i < _right; i++) + { + //If less than the pivot value + if (_comparator(_array[i], pivotValue) < 0) + { + //Swap back and increment our 'target' index j + ZSTL_ARRAY_ELEMENT_SWAP(_array, i, j); + j++; + } + } + + //Move pivot to final location (all values with index < j are < pivotValue) + ZSTL_ARRAY_ELEMENT_SWAP(_array, j, _right); + + return j; + } + + //Helper function which performs the sorting + template + void QuickSort(CF& _comparator, T* _array, size_t _left, size_t _right) + { + size_t pivot; + + if (_right > _left) + { + //Center pivot point (guarded against overflow) + pivot = _left + (_right - _left) / 2; + + //Get our next pivot after partitioning around the current + pivot = Partition(_comparator, _array, _left, _right, pivot); + + //Sort the left partition + if (pivot != 0) + QuickSort(_comparator, _array, _left, pivot - 1); + + //Sort the right partition + QuickSort(_comparator, _array, pivot + 1, _right); + } + } + + //Functor operator () override + template + void operator () (CF& _comparator, T* _array, size_t _size) + { + QuickSort(_comparator, _array, 0, _size - 1); + } +}; + +/* +List merge sort functor. This implementation is a 'stable' sort. + +The template parameter T is the type contained by the underlying list we will be sorting. +*/ +template +struct ZListMergeSort +{ + ZListMergeSort() { } //Silence Sun C++ warnings about initialized structs + + //Special 'Len' function which uses no end node + inline size_t Length(ZListNode* _list) + { + size_t i = 0; + ZListNode* node; + + //for (i = 0, node = _list; node != NULL; i++, node = node->Next); + + node = _list; + while (node != NULL) + { + node = node->Next; + i++; + } + + return i; + } + + //Helper function which merges two lists, returns the last node + template + inline ZListNode* Merge(CF& _comparator, ZListNode* _left, ZListNode* _right) + { + ZListNode* merged = NULL; + + //While left and right still have elements + while (_left != NULL && _right != NULL) + { + //Compare first elements + if (_comparator(_left->Element, _right->Element) < 0) + { + //Add the left element + ZSTL_LIST_ELEMENT_PUSH(merged, _left); + _left = _left->Next; + } + else + { + //Add the right element + ZSTL_LIST_ELEMENT_PUSH(merged, _right); + _right = _right->Next; + } + } + + //While the left still has elements + while (_left != NULL) + { + //Add them + ZSTL_LIST_ELEMENT_PUSH(merged, _left); + _left = _left->Next; + } + + //While the right still has elements + while (_right != NULL) + { + //Add them + ZSTL_LIST_ELEMENT_PUSH(merged, _right); + _right = _right->Next; + } + + //Return the end node + return merged; + } + + //Helper function which merge sorts a list, returns the last node + template + inline ZListNode* MergeSort(CF& _comparator, ZListNode* _start) + { + size_t i; + size_t middle; + + ZListNode* left; + ZListNode* right; + + //If none or one element + if (_start == NULL || _start->Next == NULL) + return _start; + + //Determine midpoint + middle = Length(_start) / 2; + + //Set our left and right + left = right = _start; + + //Set right to midpoint + for (i = 0; i < middle; i++) + right = right->Next; + + //Seperate the list + right->Previous->Next = NULL; + right->Previous = NULL; + + //Sort left and right recursively + MergeSort(_comparator, left); + MergeSort(_comparator, right); + + //Set back our left list pointer + while (left != NULL && left->Previous != NULL) + left = left->Previous; + + //Set back our right list pointer + while (right != NULL && right->Previous != NULL) + right = right->Previous; + + //Return the last node from the merged lists + return Merge(_comparator, left, right); + } + + //Functor operator () override + template + void operator () (CF& _comparator, ZListNode* _start, ZListNode* _end) + { + ZListNode* prev; + + //Check to see if list is empty + if (_start == _end) + return; + + //Get the node before the starting node + prev = _start->Previous; + + //Split the end node off + _end->Previous->Next = NULL; + _start->Previous = NULL; + //Reset the end node back + _end->Previous = MergeSort(_comparator, _start); + + //Attach + _end->Previous->Next = _end; + + //Reattach the node before _start + if (prev != NULL) + { + ZListNode* current = _end; + + while (current->Previous != NULL) + current = current->Previous; + + current->Previous = prev; + prev->Next = current; + } + } +}; + +#endif diff --git a/Lib/Include/ZSTL/ZSTLInvalidPos.hpp b/Lib/Include/ZSTL/ZSTLInvalidPos.hpp new file mode 100644 index 0000000..e7676fe --- /dev/null +++ b/Lib/Include/ZSTL/ZSTLInvalidPos.hpp @@ -0,0 +1,66 @@ +/* + ZSTLInvalidPos.hpp + Author: James Russell + Created: 12/27/2012 + + Purpose: + + Header file for ZSTL::InvalidPos, which includes only a single definition for + the 'InvalidPos' structure. This acts as a common return value for most containers + wherein the return would be an invalid index or iterator. + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ + +#pragma once + +#ifndef _ZSTLINVALIDPOS_HPP +#define _ZSTLINVALIDPOS_HPP + +#include // size_t, NULL + +//Predeclare ZListIterator type +template class ZListIterator; + +/* The ZSTL namespace */ +namespace ZSTL +{ + //Invalid Object structure, used to indicate an invalid position on many different types of containers + struct _InvalidObject + { + //Implicit cast to size_t + operator size_t () const + { return ((size_t)-1); } + + //Implicit (and templated) cast to ZListIterator + template + operator ZListIterator () const + { return ZListIterator(NULL, NULL); } + }; + + /* + Indicator used to check when an algorithm has returned an invalid position or iterator. + Many algorithms return an index or iterator that needs to be checked against an 'invalid' + return, such as 'FindFirstOf' returning a size_t value for arrays and an iterator + for lists. + + This structure can be used to check against all types of returns. + + if (ZArrayAlgo::FindFirstOf(...) != ZSTL::InvalidPos) + ... + + if (ZListAlgo::FindFirstOf(...) != ZSTL::InvalidPos) + ... + */ + const static _InvalidObject InvalidPos = _InvalidObject(); +} + +#endif + diff --git a/Lib/Include/ZSTL/ZString.hpp b/Lib/Include/ZSTL/ZString.hpp new file mode 100644 index 0000000..b9504c4 --- /dev/null +++ b/Lib/Include/ZSTL/ZString.hpp @@ -0,0 +1,35 @@ +/* + ZBasicString.hpp + Author: James Russell + Created: 9/12/2011 + + Purpose: + + String header, which will include string implementations and typedef + the standard string implementation. + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ + +#pragma once + +#ifndef _ZSTRING_HPP +#define _ZSTRING_HPP + +#include //Dynamic ASCII String +#include //Algo methods for ZBasicString + +//This typedef indicates what our base string type will be +typedef ZBasicString<> ZString; + +//Temporary hack used to make ZStringAlgo -> ZBasicStringAlgo until ZStringAlgo +#define ZStringAlgo ZBasicStringAlgo + +#endif diff --git a/Lib/Include/assimp/Compiler/poppack1.h b/Lib/Include/assimp/Compiler/poppack1.h new file mode 100644 index 0000000..e033bc1 --- /dev/null +++ b/Lib/Include/assimp/Compiler/poppack1.h @@ -0,0 +1,22 @@ + +// =============================================================================== +// May be included multiple times - resets structure packing to the defaults +// for all supported compilers. Reverts the changes made by #include +// +// Currently this works on the following compilers: +// MSVC 7,8,9 +// GCC +// BORLAND (complains about 'pack state changed but not reverted', but works) +// =============================================================================== + +#ifndef AI_PUSHPACK_IS_DEFINED +# error pushpack1.h must be included after poppack1.h +#endif + +// reset packing to the original value +#if defined(_MSC_VER) || defined(__BORLANDC__) || defined (__BCPLUSPLUS__) +# pragma pack( pop ) +#endif +#undef PACK_STRUCT + +#undef AI_PUSHPACK_IS_DEFINED diff --git a/Lib/Include/assimp/Compiler/pushpack1.h b/Lib/Include/assimp/Compiler/pushpack1.h new file mode 100644 index 0000000..2471b7c --- /dev/null +++ b/Lib/Include/assimp/Compiler/pushpack1.h @@ -0,0 +1,41 @@ + + +// =============================================================================== +// May be included multiple times - sets structure packing to 1 +// for all supported compilers. #include reverts the changes. +// +// Currently this works on the following compilers: +// MSVC 7,8,9 +// GCC +// BORLAND (complains about 'pack state changed but not reverted', but works) +// +// +// USAGE: +// +// struct StructToBePacked { +// } PACK_STRUCT; +// +// =============================================================================== + +#ifdef AI_PUSHPACK_IS_DEFINED +# error poppack1.h must be included after pushpack1.h +#endif + +#if defined(_MSC_VER) || defined(__BORLANDC__) || defined (__BCPLUSPLUS__) +# pragma pack(push,1) +# define PACK_STRUCT +#elif defined( __GNUC__ ) +# define PACK_STRUCT __attribute__((packed)) +#else +# error Compiler not supported +#endif + +#if defined(_MSC_VER) + +// C4103: Packing was changed after the inclusion of the header, propably missing #pragma pop +# pragma warning (disable : 4103) +#endif + +#define AI_PUSHPACK_IS_DEFINED + + diff --git a/Lib/Include/assimp/DefaultLogger.hpp b/Lib/Include/assimp/DefaultLogger.hpp new file mode 100644 index 0000000..390363d --- /dev/null +++ b/Lib/Include/assimp/DefaultLogger.hpp @@ -0,0 +1,190 @@ +/* +Open Asset Import Library (assimp) +---------------------------------------------------------------------- + +Copyright (c) 2006-2012, assimp team +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the +following conditions are met: + +* Redistributions of source code must retain the above + copyright notice, this list of conditions and the + following disclaimer. + +* Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other + materials provided with the distribution. + +* Neither the name of the assimp team, nor the names of its + contributors may be used to endorse or promote products + derived from this software without specific prior + written permission of the assimp team. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"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 COPYRIGHT +OWNER OR CONTRIBUTORS 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. + +---------------------------------------------------------------------- +*/ +/** @file DefaultLogger.h +*/ + +#ifndef INCLUDED_AI_DEFAULTLOGGER +#define INCLUDED_AI_DEFAULTLOGGER + +#include "Logger.hpp" +#include "LogStream.hpp" +#include "NullLogger.hpp" +#include + +namespace Assimp { +// ------------------------------------------------------------------------------------ +class IOStream; +struct LogStreamInfo; + +/** default name of logfile */ +#define ASSIMP_DEFAULT_LOG_NAME "AssimpLog.txt" + +// ------------------------------------------------------------------------------------ +/** @brief CPP-API: Primary logging facility of Assimp. + * + * The library stores its primary #Logger as a static member of this class. + * #get() returns this primary logger. By default the underlying implementation is + * just a #NullLogger which rejects all log messages. By calling #create(), logging + * is turned on. To capture the log output multiple log streams (#LogStream) can be + * attach to the logger. Some default streams for common streaming locations (such as + * a file, std::cout, OutputDebugString()) are also provided. + * + * If you wish to customize the logging at an even deeper level supply your own + * implementation of #Logger to #set(). + * @note The whole logging stuff causes a small extra overhead for all imports. */ +class ASSIMP_API DefaultLogger : + public Logger { + +public: + + // ---------------------------------------------------------------------- + /** @brief Creates a logging instance. + * @param name Name for log file. Only valid in combination + * with the aiDefaultLogStream_FILE flag. + * @param severity Log severity, VERBOSE turns on debug messages + * @param defStreams Default log streams to be attached. Any bitwise + * combination of the aiDefaultLogStream enumerated values. + * If #aiDefaultLogStream_FILE is specified but an empty string is + * passed for 'name', no log file is created at all. + * @param io IOSystem to be used to open external files (such as the + * log file). Pass NULL to rely on the default implementation. + * This replaces the default #NullLogger with a #DefaultLogger instance. */ + static Logger *create(const char* name = ASSIMP_DEFAULT_LOG_NAME, + LogSeverity severity = NORMAL, + unsigned int defStreams = aiDefaultLogStream_DEBUGGER | aiDefaultLogStream_FILE, + IOSystem* io = NULL); + + // ---------------------------------------------------------------------- + /** @brief Setup a custom #Logger implementation. + * + * Use this if the provided #DefaultLogger class doesn't fit into + * your needs. If the provided message formatting is OK for you, + * it's much easier to use #create() and to attach your own custom + * output streams to it. + * @param logger Pass NULL to setup a default NullLogger*/ + static void set (Logger *logger); + + // ---------------------------------------------------------------------- + /** @brief Getter for singleton instance + * @return Only instance. This is never null, but it could be a + * NullLogger. Use isNullLogger to check this.*/ + static Logger *get(); + + // ---------------------------------------------------------------------- + /** @brief Return whether a #NullLogger is currently active + * @return true if the current logger is a #NullLogger. + * Use create() or set() to setup a logger that does actually do + * something else than just rejecting all log messages. */ + static bool isNullLogger(); + + // ---------------------------------------------------------------------- + /** @brief Kills the current singleton logger and replaces it with a + * #NullLogger instance. */ + static void kill(); + + // ---------------------------------------------------------------------- + /** @copydoc Logger::attachStream */ + bool attachStream(LogStream *pStream, + unsigned int severity); + + // ---------------------------------------------------------------------- + /** @copydoc Logger::detatchStream */ + bool detatchStream(LogStream *pStream, + unsigned int severity); + + +private: + + // ---------------------------------------------------------------------- + /** @briefPrivate construction for internal use by create(). + * @param severity Logging granularity */ + DefaultLogger(LogSeverity severity); + + // ---------------------------------------------------------------------- + /** @briefDestructor */ + ~DefaultLogger(); + +private: + + /** @brief Logs debug infos, only been written when severity level VERBOSE is set */ + void OnDebug(const char* message); + + /** @brief Logs an info message */ + void OnInfo(const char* message); + + /** @brief Logs a warning message */ + void OnWarn(const char* message); + + /** @brief Logs an error message */ + void OnError(const char* message); + + // ---------------------------------------------------------------------- + /** @brief Writes a message to all streams */ + void WriteToStreams(const char* message, ErrorSeverity ErrorSev ); + + // ---------------------------------------------------------------------- + /** @brief Returns the thread id. + * @note This is an OS specific feature, if not supported, a + * zero will be returned. + */ + unsigned int GetThreadID(); + +private: + // Aliases for stream container + typedef std::vector StreamArray; + typedef std::vector::iterator StreamIt; + typedef std::vector::const_iterator ConstStreamIt; + + //! only logging instance + static Logger *m_pLogger; + static NullLogger s_pNullLogger; + + //! Attached streams + StreamArray m_StreamArray; + + bool noRepeatMsg; + char lastMsg[MAX_LOG_MESSAGE_LENGTH*2]; + size_t lastLen; +}; +// ------------------------------------------------------------------------------------ + +} // Namespace Assimp + +#endif // !! INCLUDED_AI_DEFAULTLOGGER diff --git a/Lib/Include/assimp/Exporter.hpp b/Lib/Include/assimp/Exporter.hpp new file mode 100644 index 0000000..662730f --- /dev/null +++ b/Lib/Include/assimp/Exporter.hpp @@ -0,0 +1,304 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2011, assimp team + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following +conditions are met: + +* Redistributions of source code must retain the above +copyright notice, this list of conditions and the +following disclaimer. + +* Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the +following disclaimer in the documentation and/or other +materials provided with the distribution. + +* Neither the name of the assimp team, nor the names of its +contributors may be used to endorse or promote products +derived from this software without specific prior +written permission of the assimp team. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"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 COPYRIGHT +OWNER OR CONTRIBUTORS 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. +--------------------------------------------------------------------------- +*/ + +/** @file export.hpp +* @brief Defines the CPP-API for the Assimp export interface +*/ +#ifndef AI_EXPORT_HPP_INC +#define AI_EXPORT_HPP_INC + +#ifndef ASSIMP_BUILD_NO_EXPORT + +#include "cexport.h" + +namespace Assimp { + class ExporterPimpl; + + +// ---------------------------------------------------------------------------------- +/** CPP-API: The Exporter class forms an C++ interface to the export functionality + * of the Open Asset Import Library. Note that the export interface is available + * only if Assimp has been built with ASSIMP_BUILD_NO_EXPORT not defined. + * + * The interface is modelled after the importer interface and mostly + * symmetric. The same rules for threading etc. apply. + * + * In a nutshell, there are two export interfaces: #Export, which writes the + * output file(s) either to the regular file system or to a user-supplied + * #IOSystem, and #ExportToBlob which returns a linked list of memory + * buffers (blob), each referring to one output file (in most cases + * there will be only one output file of course, but this extra complexity is + * needed since Assimp aims at supporting a wide range of file formats). + * + * #ExportToBlob is especially useful if you intend to work + * with the data in-memory. +*/ +class ASSIMP_API Exporter + // TODO: causes good ol' base class has no dll interface warning +//#ifdef __cplusplus +// : public boost::noncopyable +//#endif // __cplusplus +{ +public: + + /** Function pointer type of a Export worker function */ + typedef void (*fpExportFunc)(const char*,IOSystem*,const aiScene*); + + /** Internal description of an Assimp export format option */ + struct ExportFormatEntry + { + /// Public description structure to be returned by aiGetExportFormatDescription() + aiExportFormatDesc mDescription; + + // Worker function to do the actual exporting + fpExportFunc mExportFunction; + + // Postprocessing steps to be executed PRIOR to invoking mExportFunction + unsigned int mEnforcePP; + + // Constructor to fill all entries + ExportFormatEntry( const char* pId, const char* pDesc, const char* pExtension, fpExportFunc pFunction, unsigned int pEnforcePP = 0u) + { + mDescription.id = pId; + mDescription.description = pDesc; + mDescription.fileExtension = pExtension; + mExportFunction = pFunction; + mEnforcePP = pEnforcePP; + } + + ExportFormatEntry() : mExportFunction(), mEnforcePP() {} + }; + + +public: + + + Exporter(); + ~Exporter(); + +public: + + + // ------------------------------------------------------------------- + /** Supplies a custom IO handler to the exporter to use to open and + * access files. + * + * If you need #Export to use custom IO logic to access the files, + * you need to supply a custom implementation of IOSystem and + * IOFile to the exporter. + * + * #Exporter takes ownership of the object and will destroy it + * afterwards. The previously assigned handler will be deleted. + * Pass NULL to take again ownership of your IOSystem and reset Assimp + * to use its default implementation, which uses plain file IO. + * + * @param pIOHandler The IO handler to be used in all file accesses + * of the Importer. */ + void SetIOHandler( IOSystem* pIOHandler); + + // ------------------------------------------------------------------- + /** Retrieves the IO handler that is currently set. + * You can use #IsDefaultIOHandler() to check whether the returned + * interface is the default IO handler provided by ASSIMP. The default + * handler is active as long the application doesn't supply its own + * custom IO handler via #SetIOHandler(). + * @return A valid IOSystem interface, never NULL. */ + IOSystem* GetIOHandler() const; + + // ------------------------------------------------------------------- + /** Checks whether a default IO handler is active + * A default handler is active as long the application doesn't + * supply its own custom IO handler via #SetIOHandler(). + * @return true by default */ + bool IsDefaultIOHandler() const; + + + + // ------------------------------------------------------------------- + /** Exports the given scene to a chosen file format. Returns the exported + * data as a binary blob which you can write into a file or something. + * When you're done with the data, simply let the #Exporter instance go + * out of scope to have it released automatically. + * @param pScene The scene to export. Stays in possession of the caller, + * is not changed by the function. + * @param pFormatId ID string to specify to which format you want to + * export to. Use + * #GetExportFormatCount / #GetExportFormatDescription to learn which + * export formats are available. + * @param pPreprocessing See the documentation for #Export + * @return the exported data or NULL in case of error. + * @note If the Exporter instance did already hold a blob from + * a previous call to #ExportToBlob, it will be disposed. + * Any IO handlers set via #SetIOHandler are ignored here.*/ + const aiExportDataBlob* ExportToBlob( const aiScene* pScene, const char* pFormatId, unsigned int pPreprocessing = 0u ); + inline const aiExportDataBlob* ExportToBlob( const aiScene* pScene, const std::string& pFormatId, unsigned int pPreprocessing = 0u ); + + + // ------------------------------------------------------------------- + /** Convenience function to export directly to a file. Use + * #SetIOSystem to supply a custom IOSystem to gain fine-grained control + * about the output data flow of the export process. + * @param pBlob A data blob obtained from a previous call to #aiExportScene. Must not be NULL. + * @param pPath Full target file name. Target must be accessible. + * @param pPreprocessing Accepts any choice of the #aiPostProcessing enumerated + * flags, but in reality only a subset of them makes sense here. Specifying + * 'preprocessing' flags is useful if the input scene does not conform to + * Assimp's default conventions as specified in the @link data Data Structures Page @endlink. + * In short, this means the geometry data should use a right-handed coordinate systems, face + * winding should be counter-clockwise and the UV coordinate origin is assumed to be in + * the upper left. The #aiProcess_MakeLeftHanded, #aiProcess_FlipUVs and + * #aiProcess_FlipWindingOrder flags are used in the import side to allow users + * to have those defaults automatically adapted to their conventions. Specifying those flags + * for exporting has the opposite effect, respectively. Some other of the + * #aiPostProcessSteps enumerated values may be useful as well, but you'll need + * to try out what their effect on the exported file is. Many formats impose + * their own restrictions on the structure of the geometry stored therein, + * so some preprocessing may have little or no effect at all, or may be + * redundant as exporters would apply them anyhow. A good example + * is triangulation - whilst you can enforce it by specifying + * the #aiProcess_Triangulate flag, most export formats support only + * triangulate data so they would run the step even if it wasn't requested. + * @return AI_SUCCESS if everything was fine. */ + aiReturn Export( const aiScene* pScene, const char* pFormatId, const char* pPath, unsigned int pPreprocessing = 0u); + inline aiReturn Export( const aiScene* pScene, const std::string& pFormatId, const std::string& pPath, unsigned int pPreprocessing = 0u); + + + // ------------------------------------------------------------------- + /** Returns an error description of an error that occurred in #Export + * or #ExportToBlob + * + * Returns an empty string if no error occurred. + * @return A description of the last error, an empty string if no + * error occurred. The string is never NULL. + * + * @note The returned function remains valid until one of the + * following methods is called: #Export, #ExportToBlob, #FreeBlob */ + const char* GetErrorString() const; + + + // ------------------------------------------------------------------- + /** Return the blob obtained from the last call to #ExportToBlob */ + const aiExportDataBlob* GetBlob() const; + + + // ------------------------------------------------------------------- + /** Orphan the blob from the last call to #ExportToBlob. This means + * the caller takes ownership and is thus responsible for calling + * the C API function #aiReleaseExportBlob to release it. */ + const aiExportDataBlob* GetOrphanedBlob() const; + + + // ------------------------------------------------------------------- + /** Frees the current blob. + * + * The function does nothing if no blob has previously been + * previously produced via #ExportToBlob. #FreeBlob is called + * automatically by the destructor. The only reason to call + * it manually would be to reclain as much storage as possible + * without giving up the #Exporter instance yet. */ + void FreeBlob( ); + + + // ------------------------------------------------------------------- + /** Returns the number of export file formats available in the current + * Assimp build. Use #Exporter::GetExportFormatDescription to + * retrieve infos of a specific export format */ + size_t GetExportFormatCount() const; + + + // ------------------------------------------------------------------- + /** Returns a description of the nth export file format. Use # + * #Exporter::GetExportFormatCount to learn how many export + * formats are supported. + * @param pIndex Index of the export format to retrieve information + * for. Valid range is 0 to #Exporter::GetExportFormatCount + * @return A description of that specific export format. + * NULL if pIndex is out of range. */ + const aiExportFormatDesc* GetExportFormatDescription( size_t pIndex ) const; + + + // ------------------------------------------------------------------- + /** Register a custom exporter. Custom export formats are limited to + * to the current #Exporter instance and do not affect the + * library globally. + * @param desc Exporter description. + * @return aiReturn_SUCCESS if the export format was successfully + * registered. A common cause that would prevent an exporter + * from being registered is that its format id is already + * occupied by another format. */ + aiReturn RegisterExporter(const ExportFormatEntry& desc); + + + // ------------------------------------------------------------------- + /** Remove an export format previously registered with #RegisterExporter + * from the #Exporter instance (this can also be used to drop + * builtin exporters because those are implicitly registered + * using #RegisterExporter). + * @param id Format id to be unregistered, this refers to the + * 'id' field of #aiExportFormatDesc. + * @note Calling this method on a format description not yet registered + * has no effect.*/ + void UnregisterExporter(const char* id); + + +protected: + + // Just because we don't want you to know how we're hacking around. + ExporterPimpl* pimpl; +}; + + +// ---------------------------------------------------------------------------------- +inline const aiExportDataBlob* Exporter :: ExportToBlob( const aiScene* pScene, const std::string& pFormatId,unsigned int pPreprocessing ) +{ + return ExportToBlob(pScene,pFormatId.c_str(),pPreprocessing); +} + +// ---------------------------------------------------------------------------------- +inline aiReturn Exporter :: Export( const aiScene* pScene, const std::string& pFormatId, const std::string& pPath, unsigned int pPreprocessing ) +{ + return Export(pScene,pFormatId.c_str(),pPath.c_str(),pPreprocessing); +} + +} // namespace Assimp +#endif // ASSIMP_BUILD_NO_EXPORT +#endif // AI_EXPORT_HPP_INC + diff --git a/Lib/Include/assimp/IOStream.hpp b/Lib/Include/assimp/IOStream.hpp new file mode 100644 index 0000000..592b157 --- /dev/null +++ b/Lib/Include/assimp/IOStream.hpp @@ -0,0 +1,135 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2012, assimp team + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following +conditions are met: + +* Redistributions of source code must retain the above + copyright notice, this list of conditions and the + following disclaimer. + +* Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other + materials provided with the distribution. + +* Neither the name of the assimp team, nor the names of its + contributors may be used to endorse or promote products + derived from this software without specific prior + written permission of the assimp team. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"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 COPYRIGHT +OWNER OR CONTRIBUTORS 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. +--------------------------------------------------------------------------- +*/ +/** @file IOStream.h + * @brief File I/O wrappers for C++. + */ + +#ifndef AI_IOSTREAM_H_INC +#define AI_IOSTREAM_H_INC + +#include "types.h" + +#ifndef __cplusplus +# error This header requires C++ to be used. aiFileIO.h is the \ + corresponding C interface. +#endif + +namespace Assimp { + +// ---------------------------------------------------------------------------------- +/** @brief CPP-API: Class to handle file I/O for C++ + * + * Derive an own implementation from this interface to provide custom IO handling + * to the Importer. If you implement this interface, be sure to also provide an + * implementation for IOSystem that creates instances of your custom IO class. +*/ +class ASSIMP_API IOStream : public Intern::AllocateFromAssimpHeap +{ +protected: + /** Constructor protected, use IOSystem::Open() to create an instance. */ + IOStream(void); + +public: + // ------------------------------------------------------------------- + /** @brief Destructor. Deleting the object closes the underlying file, + * alternatively you may use IOSystem::Close() to release the file. + */ + virtual ~IOStream(); + + // ------------------------------------------------------------------- + /** @brief Read from the file + * + * See fread() for more details + * This fails for write-only files */ + virtual size_t Read(void* pvBuffer, + size_t pSize, + size_t pCount) = 0; + + // ------------------------------------------------------------------- + /** @brief Write to the file + * + * See fwrite() for more details + * This fails for read-only files */ + virtual size_t Write(const void* pvBuffer, + size_t pSize, + size_t pCount) = 0; + + // ------------------------------------------------------------------- + /** @brief Set the read/write cursor of the file + * + * Note that the offset is _negative_ for aiOrigin_END. + * See fseek() for more details */ + virtual aiReturn Seek(size_t pOffset, + aiOrigin pOrigin) = 0; + + // ------------------------------------------------------------------- + /** @brief Get the current position of the read/write cursor + * + * See ftell() for more details */ + virtual size_t Tell() const = 0; + + // ------------------------------------------------------------------- + /** @brief Returns filesize + * Returns the filesize. */ + virtual size_t FileSize() const = 0; + + // ------------------------------------------------------------------- + /** @brief Flush the contents of the file buffer (for writers) + * See fflush() for more details. + */ + virtual void Flush() = 0; +}; //! class IOStream + +// ---------------------------------------------------------------------------------- +inline IOStream::IOStream() +{ + // empty +} + +// ---------------------------------------------------------------------------------- +inline IOStream::~IOStream() +{ + // empty +} +// ---------------------------------------------------------------------------------- +} //!namespace Assimp + +#endif //!!AI_IOSTREAM_H_INC diff --git a/Lib/Include/assimp/IOSystem.hpp b/Lib/Include/assimp/IOSystem.hpp new file mode 100644 index 0000000..5854668 --- /dev/null +++ b/Lib/Include/assimp/IOSystem.hpp @@ -0,0 +1,222 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2012, assimp team + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following +conditions are met: + +* Redistributions of source code must retain the above + copyright notice, this list of conditions and the + following disclaimer. + +* Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other + materials provided with the distribution. + +* Neither the name of the assimp team, nor the names of its + contributors may be used to endorse or promote products + derived from this software without specific prior + written permission of the assimp team. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"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 COPYRIGHT +OWNER OR CONTRIBUTORS 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. +--------------------------------------------------------------------------- +*/ + +/** @file IOSystem.h + * @brief File system wrapper for C++. Inherit this class to supply + * custom file handling logic to the Import library. +*/ + +#ifndef AI_IOSYSTEM_H_INC +#define AI_IOSYSTEM_H_INC + +#ifndef __cplusplus +# error This header requires C++ to be used. aiFileIO.h is the \ + corresponding C interface. +#endif + +#include "types.h" +namespace Assimp { +class IOStream; + +// --------------------------------------------------------------------------- +/** @brief CPP-API: Interface to the file system. + * + * Derive an own implementation from this interface to supply custom file handling + * to the importer library. If you implement this interface, you also want to + * supply a custom implementation for IOStream. + * + * @see Importer::SetIOHandler() */ +class ASSIMP_API IOSystem : public Intern::AllocateFromAssimpHeap +{ +public: + + // ------------------------------------------------------------------- + /** @brief Default constructor. + * + * Create an instance of your derived class and assign it to an + * #Assimp::Importer instance by calling Importer::SetIOHandler(). + */ + IOSystem(); + + // ------------------------------------------------------------------- + /** @brief Virtual destructor. + * + * It is safe to be called from within DLL Assimp, we're constructed + * on Assimp's heap. + */ + virtual ~IOSystem(); + + +public: + + // ------------------------------------------------------------------- + /** @brief For backward compatibility + * @see Exists(const char*) + */ + AI_FORCE_INLINE bool Exists( const std::string& pFile) const; + + // ------------------------------------------------------------------- + /** @brief Tests for the existence of a file at the given path. + * + * @param pFile Path to the file + * @return true if there is a file with this path, else false. + */ + + virtual bool Exists( const char* pFile) const = 0; + + + + // ------------------------------------------------------------------- + /** @brief Returns the system specific directory separator + * @return System specific directory separator + */ + virtual char getOsSeparator() const = 0; + + + // ------------------------------------------------------------------- + /** @brief Open a new file with a given path. + * + * When the access to the file is finished, call Close() to release + * all associated resources (or the virtual dtor of the IOStream). + * + * @param pFile Path to the file + * @param pMode Desired file I/O mode. Required are: "wb", "w", "wt", + * "rb", "r", "rt". + * + * @return New IOStream interface allowing the lib to access + * the underlying file. + * @note When implementing this class to provide custom IO handling, + * you probably have to supply an own implementation of IOStream as well. + */ + virtual IOStream* Open(const char* pFile, + const char* pMode = "rb") = 0; + + // ------------------------------------------------------------------- + /** @brief For backward compatibility + * @see Open(const char*, const char*) + */ + inline IOStream* Open(const std::string& pFile, + const std::string& pMode = std::string("rb")); + + + + // ------------------------------------------------------------------- + /** @brief Closes the given file and releases all resources + * associated with it. + * @param pFile The file instance previously created by Open(). + */ + virtual void Close( IOStream* pFile) = 0; + + // ------------------------------------------------------------------- + /** @brief Compares two paths and check whether the point to + * identical files. + * + * The dummy implementation of this virtual member performs a + * case-insensitive comparison of the given strings. The default IO + * system implementation uses OS mechanisms to convert relative into + * absolute paths, so the result can be trusted. + * @param one First file + * @param second Second file + * @return true if the paths point to the same file. The file needn't + * be existing, however. + */ + virtual bool ComparePaths (const char* one, + const char* second) const; + + // ------------------------------------------------------------------- + /** @brief For backward compatibility + * @see ComparePaths(const char*, const char*) + */ + inline bool ComparePaths (const std::string& one, + const std::string& second) const; +}; + +// ---------------------------------------------------------------------------- +AI_FORCE_INLINE IOSystem::IOSystem() +{ + // empty +} + +// ---------------------------------------------------------------------------- +AI_FORCE_INLINE IOSystem::~IOSystem() +{ + // empty +} + +// ---------------------------------------------------------------------------- +// For compatibility, the interface of some functions taking a std::string was +// changed to const char* to avoid crashes between binary incompatible STL +// versions. This code her is inlined, so it shouldn't cause any problems. +// ---------------------------------------------------------------------------- + +// ---------------------------------------------------------------------------- +AI_FORCE_INLINE IOStream* IOSystem::Open(const std::string& pFile, + const std::string& pMode) +{ + // NOTE: + // For compatibility, interface was changed to const char* to + // avoid crashes between binary incompatible STL versions + return Open(pFile.c_str(),pMode.c_str()); +} + +// ---------------------------------------------------------------------------- +AI_FORCE_INLINE bool IOSystem::Exists( const std::string& pFile) const +{ + // NOTE: + // For compatibility, interface was changed to const char* to + // avoid crashes between binary incompatible STL versions + return Exists(pFile.c_str()); +} + +// ---------------------------------------------------------------------------- +inline bool IOSystem::ComparePaths (const std::string& one, + const std::string& second) const +{ + // NOTE: + // For compatibility, interface was changed to const char* to + // avoid crashes between binary incompatible STL versions + return ComparePaths(one.c_str(),second.c_str()); +} + +// ---------------------------------------------------------------------------- +} //!ns Assimp + +#endif //AI_IOSYSTEM_H_INC diff --git a/Lib/Include/assimp/Importer.hpp b/Lib/Include/assimp/Importer.hpp new file mode 100644 index 0000000..db127b4 --- /dev/null +++ b/Lib/Include/assimp/Importer.hpp @@ -0,0 +1,642 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2012, assimp team + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following +conditions are met: + +* Redistributions of source code must retain the above + copyright notice, this list of conditions and the + following disclaimer. + +* Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other + materials provided with the distribution. + +* Neither the name of the assimp team, nor the names of its + contributors may be used to endorse or promote products + derived from this software without specific prior + written permission of the assimp team. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"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 COPYRIGHT +OWNER OR CONTRIBUTORS 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. +--------------------------------------------------------------------------- +*/ + +/** @file assimp.hpp + * @brief Defines the C++-API to the Open Asset Import Library. + */ +#ifndef INCLUDED_AI_ASSIMP_HPP +#define INCLUDED_AI_ASSIMP_HPP + +#ifndef __cplusplus +# error This header requires C++ to be used. Use assimp.h for plain C. +#endif + +// Public ASSIMP data structures +#include "types.h" +#include "config.h" + +namespace Assimp { + // ======================================================================= + // Public interface to Assimp + class Importer; + class Exporter; // export.hpp + class IOStream; + class IOSystem; + class ProgressHandler; + + // ======================================================================= + // Plugin development + // + // Include the following headers for the declarations: + // BaseImporter.h + // BaseProcess.h + class BaseImporter; + class BaseProcess; + class SharedPostProcessInfo; + class BatchLoader; + + // ======================================================================= + // Holy stuff, only for members of the high council of the Jedi. + class ImporterPimpl; + class ExporterPimpl; // export.hpp +} //! namespace Assimp + +#define AI_PROPERTY_WAS_NOT_EXISTING 0xffffffff + +struct aiScene; + +// importerdesc.h +struct aiImporterDesc; + +/** @namespace Assimp Assimp's CPP-API and all internal APIs */ +namespace Assimp { + +// ---------------------------------------------------------------------------------- +/** CPP-API: The Importer class forms an C++ interface to the functionality of the +* Open Asset Import Library. +* +* Create an object of this class and call ReadFile() to import a file. +* If the import succeeds, the function returns a pointer to the imported data. +* The data remains property of the object, it is intended to be accessed +* read-only. The imported data will be destroyed along with the Importer +* object. If the import fails, ReadFile() returns a NULL pointer. In this +* case you can retrieve a human-readable error description be calling +* GetErrorString(). You can call ReadFile() multiple times with a single Importer +* instance. Actually, constructing Importer objects involves quite many +* allocations and may take some time, so it's better to reuse them as often as +* possible. +* +* If you need the Importer to do custom file handling to access the files, +* implement IOSystem and IOStream and supply an instance of your custom +* IOSystem implementation by calling SetIOHandler() before calling ReadFile(). +* If you do not assign a custion IO handler, a default handler using the +* standard C++ IO logic will be used. +* +* @note One Importer instance is not thread-safe. If you use multiple +* threads for loading, each thread should maintain its own Importer instance. +*/ +class ASSIMP_API Importer { + +public: + + // ------------------------------------------------------------------- + /** Constructor. Creates an empty importer object. + * + * Call ReadFile() to start the import process. The configuration + * property table is initially empty. + */ + Importer(); + + // ------------------------------------------------------------------- + /** Copy constructor. + * + * This copies the configuration properties of another Importer. + * If this Importer owns a scene it won't be copied. + * Call ReadFile() to start the import process. + */ + Importer(const Importer& other); + + // ------------------------------------------------------------------- + /** Destructor. The object kept ownership of the imported data, + * which now will be destroyed along with the object. + */ + ~Importer(); + + + // ------------------------------------------------------------------- + /** Registers a new loader. + * + * @param pImp Importer to be added. The Importer instance takes + * ownership of the pointer, so it will be automatically deleted + * with the Importer instance. + * @return AI_SUCCESS if the loader has been added. The registration + * fails if there is already a loader for a specific file extension. + */ + aiReturn RegisterLoader(BaseImporter* pImp); + + // ------------------------------------------------------------------- + /** Unregisters a loader. + * + * @param pImp Importer to be unregistered. + * @return AI_SUCCESS if the loader has been removed. The function + * fails if the loader is currently in use (this could happen + * if the #Importer instance is used by more than one thread) or + * if it has not yet been registered. + */ + aiReturn UnregisterLoader(BaseImporter* pImp); + + // ------------------------------------------------------------------- + /** Registers a new post-process step. + * + * At the moment, there's a small limitation: new post processing + * steps are added to end of the list, or in other words, executed + * last, after all built-in steps. + * @param pImp Post-process step to be added. The Importer instance + * takes ownership of the pointer, so it will be automatically + * deleted with the Importer instance. + * @return AI_SUCCESS if the step has been added correctly. + */ + aiReturn RegisterPPStep(BaseProcess* pImp); + + // ------------------------------------------------------------------- + /** Unregisters a post-process step. + * + * @param pImp Step to be unregistered. + * @return AI_SUCCESS if the step has been removed. The function + * fails if the step is currently in use (this could happen + * if the #Importer instance is used by more than one thread) or + * if it has not yet been registered. + */ + aiReturn UnregisterPPStep(BaseProcess* pImp); + + + // ------------------------------------------------------------------- + /** Set an integer configuration property. + * @param szName Name of the property. All supported properties + * are defined in the aiConfig.g header (all constants share the + * prefix AI_CONFIG_XXX and are simple strings). + * @param iValue New value of the property + * @param bWasExisting Optional pointer to receive true if the + * property was set before. The new value replaces the previous value + * in this case. + * @note Property of different types (float, int, string ..) are kept + * on different stacks, so calling SetPropertyInteger() for a + * floating-point property has no effect - the loader will call + * GetPropertyFloat() to read the property, but it won't be there. + */ + void SetPropertyInteger(const char* szName, int iValue, + bool* bWasExisting = NULL); + + // ------------------------------------------------------------------- + /** Set a boolean configuration property. Boolean properties + * are stored on the integer stack internally so it's possible + * to set them via #SetPropertyBool and query them with + * #GetPropertyBool and vice versa. + * @see SetPropertyInteger() + */ + void SetPropertyBool(const char* szName, bool value, bool* bWasExisting = NULL) { + SetPropertyInteger(szName,value,bWasExisting); + } + + // ------------------------------------------------------------------- + /** Set a floating-point configuration property. + * @see SetPropertyInteger() + */ + void SetPropertyFloat(const char* szName, float fValue, + bool* bWasExisting = NULL); + + // ------------------------------------------------------------------- + /** Set a string configuration property. + * @see SetPropertyInteger() + */ + void SetPropertyString(const char* szName, const std::string& sValue, + bool* bWasExisting = NULL); + + // ------------------------------------------------------------------- + /** Get a configuration property. + * @param szName Name of the property. All supported properties + * are defined in the aiConfig.g header (all constants share the + * prefix AI_CONFIG_XXX). + * @param iErrorReturn Value that is returned if the property + * is not found. + * @return Current value of the property + * @note Property of different types (float, int, string ..) are kept + * on different lists, so calling SetPropertyInteger() for a + * floating-point property has no effect - the loader will call + * GetPropertyFloat() to read the property, but it won't be there. + */ + int GetPropertyInteger(const char* szName, + int iErrorReturn = 0xffffffff) const; + + // ------------------------------------------------------------------- + /** Get a boolean configuration property. Boolean properties + * are stored on the integer stack internally so it's possible + * to set them via #SetPropertyBool and query them with + * #GetPropertyBool and vice versa. + * @see GetPropertyInteger() + */ + bool GetPropertyBool(const char* szName, bool bErrorReturn = false) const { + return GetPropertyInteger(szName,bErrorReturn)!=0; + } + + // ------------------------------------------------------------------- + /** Get a floating-point configuration property + * @see GetPropertyInteger() + */ + float GetPropertyFloat(const char* szName, + float fErrorReturn = 10e10f) const; + + // ------------------------------------------------------------------- + /** Get a string configuration property + * + * The return value remains valid until the property is modified. + * @see GetPropertyInteger() + */ + const std::string& GetPropertyString(const char* szName, + const std::string& sErrorReturn = "") const; + + // ------------------------------------------------------------------- + /** Supplies a custom IO handler to the importer to use to open and + * access files. If you need the importer to use custion IO logic to + * access the files, you need to provide a custom implementation of + * IOSystem and IOFile to the importer. Then create an instance of + * your custion IOSystem implementation and supply it by this function. + * + * The Importer takes ownership of the object and will destroy it + * afterwards. The previously assigned handler will be deleted. + * Pass NULL to take again ownership of your IOSystem and reset Assimp + * to use its default implementation. + * + * @param pIOHandler The IO handler to be used in all file accesses + * of the Importer. + */ + void SetIOHandler( IOSystem* pIOHandler); + + // ------------------------------------------------------------------- + /** Retrieves the IO handler that is currently set. + * You can use #IsDefaultIOHandler() to check whether the returned + * interface is the default IO handler provided by ASSIMP. The default + * handler is active as long the application doesn't supply its own + * custom IO handler via #SetIOHandler(). + * @return A valid IOSystem interface, never NULL. + */ + IOSystem* GetIOHandler() const; + + // ------------------------------------------------------------------- + /** Checks whether a default IO handler is active + * A default handler is active as long the application doesn't + * supply its own custom IO handler via #SetIOHandler(). + * @return true by default + */ + bool IsDefaultIOHandler() const; + + // ------------------------------------------------------------------- + /** Supplies a custom progress handler to the importer. This + * interface exposes a #Update() callback, which is called + * more or less periodically (please don't sue us if it + * isn't as periodically as you'd like it to have ...). + * This can be used to implement progress bars and loading + * timeouts. + * @param pHandler Progress callback interface. Pass NULL to + * disable progress reporting. + * @note Progress handlers can be used to abort the loading + * at almost any time.*/ + void SetProgressHandler ( ProgressHandler* pHandler ); + + // ------------------------------------------------------------------- + /** Retrieves the progress handler that is currently set. + * You can use #IsDefaultProgressHandler() to check whether the returned + * interface is the default handler provided by ASSIMP. The default + * handler is active as long the application doesn't supply its own + * custom handler via #SetProgressHandler(). + * @return A valid ProgressHandler interface, never NULL. + */ + ProgressHandler* GetProgressHandler() const; + + // ------------------------------------------------------------------- + /** Checks whether a default progress handler is active + * A default handler is active as long the application doesn't + * supply its own custom progress handler via #SetProgressHandler(). + * @return true by default + */ + bool IsDefaultProgressHandler() const; + + // ------------------------------------------------------------------- + /** @brief Check whether a given set of postprocessing flags + * is supported. + * + * Some flags are mutually exclusive, others are probably + * not available because your excluded them from your + * Assimp builds. Calling this function is recommended if + * you're unsure. + * + * @param pFlags Bitwise combination of the aiPostProcess flags. + * @return true if this flag combination is fine. + */ + bool ValidateFlags(unsigned int pFlags) const; + + // ------------------------------------------------------------------- + /** Reads the given file and returns its contents if successful. + * + * If the call succeeds, the contents of the file are returned as a + * pointer to an aiScene object. The returned data is intended to be + * read-only, the importer object keeps ownership of the data and will + * destroy it upon destruction. If the import fails, NULL is returned. + * A human-readable error description can be retrieved by calling + * GetErrorString(). The previous scene will be deleted during this call. + * @param pFile Path and filename to the file to be imported. + * @param pFlags Optional post processing steps to be executed after + * a successful import. Provide a bitwise combination of the + * #aiPostProcessSteps flags. If you wish to inspect the imported + * scene first in order to fine-tune your post-processing setup, + * consider to use #ApplyPostProcessing(). + * @return A pointer to the imported data, NULL if the import failed. + * The pointer to the scene remains in possession of the Importer + * instance. Use GetOrphanedScene() to take ownership of it. + * + * @note Assimp is able to determine the file format of a file + * automatically. + */ + const aiScene* ReadFile( + const char* pFile, + unsigned int pFlags); + + // ------------------------------------------------------------------- + /** Reads the given file from a memory buffer and returns its + * contents if successful. + * + * If the call succeeds, the contents of the file are returned as a + * pointer to an aiScene object. The returned data is intended to be + * read-only, the importer object keeps ownership of the data and will + * destroy it upon destruction. If the import fails, NULL is returned. + * A human-readable error description can be retrieved by calling + * GetErrorString(). The previous scene will be deleted during this call. + * Calling this method doesn't affect the active IOSystem. + * @param pBuffer Pointer to the file data + * @param pLength Length of pBuffer, in bytes + * @param pFlags Optional post processing steps to be executed after + * a successful import. Provide a bitwise combination of the + * #aiPostProcessSteps flags. If you wish to inspect the imported + * scene first in order to fine-tune your post-processing setup, + * consider to use #ApplyPostProcessing(). + * @param pHint An additional hint to the library. If this is a non + * empty string, the library looks for a loader to support + * the file extension specified by pHint and passes the file to + * the first matching loader. If this loader is unable to completely + * the request, the library continues and tries to determine the + * file format on its own, a task that may or may not be successful. + * Check the return value, and you'll know ... + * @return A pointer to the imported data, NULL if the import failed. + * The pointer to the scene remains in possession of the Importer + * instance. Use GetOrphanedScene() to take ownership of it. + * + * @note This is a straightforward way to decode models from memory + * buffers, but it doesn't handle model formats spreading their + * data across multiple files or even directories. Examples include + * OBJ or MD3, which outsource parts of their material stuff into + * external scripts. If you need the full functionality, provide + * a custom IOSystem to make Assimp find these files. + */ + const aiScene* ReadFileFromMemory( + const void* pBuffer, + size_t pLength, + unsigned int pFlags, + const char* pHint = ""); + + // ------------------------------------------------------------------- + /** Apply post-processing to an already-imported scene. + * + * This is strictly equivalent to calling #ReadFile() with the same + * flags. However, you can use this separate function to inspect + * the imported scene first to fine-tune your post-processing setup. + * @param pFlags Provide a bitwise combination of the + * #aiPostProcessSteps flags. + * @return A pointer to the post-processed data. This is still the + * same as the pointer returned by #ReadFile(). However, if + * post-processing fails, the scene could now be NULL. + * That's quite a rare case, post processing steps are not really + * designed to 'fail'. To be exact, the #aiProcess_ValidateDS + * flag is currently the only post processing step which can actually + * cause the scene to be reset to NULL. + * + * @note The method does nothing if no scene is currently bound + * to the #Importer instance. */ + const aiScene* ApplyPostProcessing(unsigned int pFlags); + + // ------------------------------------------------------------------- + /** @brief Reads the given file and returns its contents if successful. + * + * This function is provided for backward compatibility. + * See the const char* version for detailled docs. + * @see ReadFile(const char*, pFlags) */ + const aiScene* ReadFile( + const std::string& pFile, + unsigned int pFlags); + + // ------------------------------------------------------------------- + /** Frees the current scene. + * + * The function does nothing if no scene has previously been + * read via ReadFile(). FreeScene() is called automatically by the + * destructor and ReadFile() itself. */ + void FreeScene( ); + + // ------------------------------------------------------------------- + /** Returns an error description of an error that occurred in ReadFile(). + * + * Returns an empty string if no error occurred. + * @return A description of the last error, an empty string if no + * error occurred. The string is never NULL. + * + * @note The returned function remains valid until one of the + * following methods is called: #ReadFile(), #FreeScene(). */ + const char* GetErrorString() const; + + // ------------------------------------------------------------------- + /** Returns the scene loaded by the last successful call to ReadFile() + * + * @return Current scene or NULL if there is currently no scene loaded */ + const aiScene* GetScene() const; + + // ------------------------------------------------------------------- + /** Returns the scene loaded by the last successful call to ReadFile() + * and releases the scene from the ownership of the Importer + * instance. The application is now responsible for deleting the + * scene. Any further calls to GetScene() or GetOrphanedScene() + * will return NULL - until a new scene has been loaded via ReadFile(). + * + * @return Current scene or NULL if there is currently no scene loaded + * @note Use this method with maximal caution, and only if you have to. + * By design, aiScene's are exclusively maintained, allocated and + * deallocated by Assimp and no one else. The reasoning behind this + * is the golden rule that deallocations should always be done + * by the module that did the original allocation because heaps + * are not necessarily shared. GetOrphanedScene() enforces you + * to delete the returned scene by yourself, but this will only + * be fine if and only if you're using the same heap as assimp. + * On Windows, it's typically fine provided everything is linked + * against the multithreaded-dll version of the runtime library. + * It will work as well for static linkage with Assimp.*/ + aiScene* GetOrphanedScene(); + + + + + // ------------------------------------------------------------------- + /** Returns whether a given file extension is supported by ASSIMP. + * + * @param szExtension Extension to be checked. + * Must include a trailing dot '.'. Example: ".3ds", ".md3". + * Cases-insensitive. + * @return true if the extension is supported, false otherwise */ + bool IsExtensionSupported(const char* szExtension) const; + + // ------------------------------------------------------------------- + /** @brief Returns whether a given file extension is supported by ASSIMP. + * + * This function is provided for backward compatibility. + * See the const char* version for detailed and up-to-date docs. + * @see IsExtensionSupported(const char*) */ + inline bool IsExtensionSupported(const std::string& szExtension) const; + + // ------------------------------------------------------------------- + /** Get a full list of all file extensions supported by ASSIMP. + * + * If a file extension is contained in the list this does of course not + * mean that ASSIMP is able to load all files with this extension --- + * it simply means there is an importer loaded which claims to handle + * files with this file extension. + * @param szOut String to receive the extension list. + * Format of the list: "*.3ds;*.obj;*.dae". This is useful for + * use with the WinAPI call GetOpenFileName(Ex). */ + void GetExtensionList(aiString& szOut) const; + + // ------------------------------------------------------------------- + /** @brief Get a full list of all file extensions supported by ASSIMP. + * + * This function is provided for backward compatibility. + * See the aiString version for detailed and up-to-date docs. + * @see GetExtensionList(aiString&)*/ + inline void GetExtensionList(std::string& szOut) const; + + // ------------------------------------------------------------------- + /** Get the number of importrs currently registered with Assimp. */ + size_t GetImporterCount() const; + + // ------------------------------------------------------------------- + /** Get meta data for the importer corresponding to a specific index.. + * + * For the declaration of #aiImporterDesc, include . + * @param index Index to query, must be within [0,GetImporterCount()) + * @return Importer meta data structure, NULL if the index does not + * exist or if the importer doesn't offer meta information ( + * importers may do this at the cost of being hated by their peers).*/ + const aiImporterDesc* GetImporterInfo(size_t index) const; + + // ------------------------------------------------------------------- + /** Find the importer corresponding to a specific index. + * + * @param index Index to query, must be within [0,GetImporterCount()) + * @return Importer instance. NULL if the index does not + * exist. */ + BaseImporter* GetImporter(size_t index) const; + + // ------------------------------------------------------------------- + /** Find the importer corresponding to a specific file extension. + * + * This is quite similar to #IsExtensionSupported except a + * BaseImporter instance is returned. + * @param szExtension Extension to check for. The following formats + * are recognized (BAH being the file extension): "BAH" (comparison + * is case-insensitive), ".bah", "*.bah" (wild card and dot + * characters at the beginning of the extension are skipped). + * @return NULL if no importer is found*/ + BaseImporter* GetImporter (const char* szExtension) const; + + // ------------------------------------------------------------------- + /** Find the importer index corresponding to a specific file extension. + * + * @param szExtension Extension to check for. The following formats + * are recognized (BAH being the file extension): "BAH" (comparison + * is case-insensitive), ".bah", "*.bah" (wild card and dot + * characters at the beginning of the extension are skipped). + * @return (size_t)-1 if no importer is found */ + size_t GetImporterIndex (const char* szExtension) const; + + + + + // ------------------------------------------------------------------- + /** Returns the storage allocated by ASSIMP to hold the scene data + * in memory. + * + * This refers to the currently loaded file, see #ReadFile(). + * @param in Data structure to be filled. + * @note The returned memory statistics refer to the actual + * size of the use data of the aiScene. Heap-related overhead + * is (naturally) not included.*/ + void GetMemoryRequirements(aiMemoryInfo& in) const; + + // ------------------------------------------------------------------- + /** Enables "extra verbose" mode. + * + * 'Extra verbose' means the data structure is validated after *every* + * single post processing step to make sure everyone modifies the data + * structure in a well-defined manner. This is a debug feature and not + * intended for use in production environments. */ + void SetExtraVerbose(bool bDo); + + + // ------------------------------------------------------------------- + /** Private, do not use. */ + ImporterPimpl* Pimpl() { return pimpl; }; + const ImporterPimpl* Pimpl() const { return pimpl; }; + +protected: + + // Just because we don't want you to know how we're hacking around. + ImporterPimpl* pimpl; +}; //! class Importer + + +// ---------------------------------------------------------------------------- +// For compatibility, the interface of some functions taking a std::string was +// changed to const char* to avoid crashes between binary incompatible STL +// versions. This code her is inlined, so it shouldn't cause any problems. +// ---------------------------------------------------------------------------- + +// ---------------------------------------------------------------------------- +AI_FORCE_INLINE const aiScene* Importer::ReadFile( const std::string& pFile,unsigned int pFlags){ + return ReadFile(pFile.c_str(),pFlags); +} +// ---------------------------------------------------------------------------- +AI_FORCE_INLINE void Importer::GetExtensionList(std::string& szOut) const { + aiString s; + GetExtensionList(s); + szOut = s.data; +} +// ---------------------------------------------------------------------------- +AI_FORCE_INLINE bool Importer::IsExtensionSupported(const std::string& szExtension) const { + return IsExtensionSupported(szExtension.c_str()); +} + +} // !namespace Assimp +#endif // INCLUDED_AI_ASSIMP_HPP diff --git a/Lib/Include/assimp/LogStream.hpp b/Lib/Include/assimp/LogStream.hpp new file mode 100644 index 0000000..8bcb41d --- /dev/null +++ b/Lib/Include/assimp/LogStream.hpp @@ -0,0 +1,93 @@ +/* +Open Asset Import Library (assimp) +---------------------------------------------------------------------- + +Copyright (c) 2006-2012, assimp team +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the +following conditions are met: + +* Redistributions of source code must retain the above + copyright notice, this list of conditions and the + following disclaimer. + +* Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other + materials provided with the distribution. + +* Neither the name of the assimp team, nor the names of its + contributors may be used to endorse or promote products + derived from this software without specific prior + written permission of the assimp team. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"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 COPYRIGHT +OWNER OR CONTRIBUTORS 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. + +---------------------------------------------------------------------- +*/ + +/** @file LogStream.h + * @brief Abstract base class 'LogStream', representing an output log stream. + */ +#ifndef INCLUDED_AI_LOGSTREAM_H +#define INCLUDED_AI_LOGSTREAM_H +#include "types.h" +namespace Assimp { +class IOSystem; + +// ------------------------------------------------------------------------------------ +/** @brief CPP-API: Abstract interface for log stream implementations. + * + * Several default implementations are provided, see #aiDefaultLogStream for more + * details. Writing your own implementation of LogStream is just necessary if these + * are not enough for your purpose. */ +class ASSIMP_API LogStream + : public Intern::AllocateFromAssimpHeap { +protected: + /** @brief Default constructor */ + LogStream() { + } +public: + /** @brief Virtual destructor */ + virtual ~LogStream() { + } + + // ------------------------------------------------------------------- + /** @brief Overwrite this for your own output methods + * + * Log messages *may* consist of multiple lines and you shouldn't + * expect a consistent formatting. If you want custom formatting + * (e.g. generate HTML), supply a custom instance of Logger to + * #DefaultLogger:set(). Usually you can *expect* that a log message + * is exactly one line and terminated with a single \n character. + * @param message Message to be written */ + virtual void write(const char* message) = 0; + + // ------------------------------------------------------------------- + /** @brief Creates a default log stream + * @param streams Type of the default stream + * @param name For aiDefaultLogStream_FILE: name of the output file + * @param io For aiDefaultLogStream_FILE: IOSystem to be used to open the output + * file. Pass NULL for the default implementation. + * @return New LogStream instance. */ + static LogStream* createDefaultStream(aiDefaultLogStream stream, + const char* name = "AssimpLog.txt", + IOSystem* io = NULL); + +}; // !class LogStream +// ------------------------------------------------------------------------------------ +} // Namespace Assimp + +#endif diff --git a/Lib/Include/assimp/Logger.hpp b/Lib/Include/assimp/Logger.hpp new file mode 100644 index 0000000..f780533 --- /dev/null +++ b/Lib/Include/assimp/Logger.hpp @@ -0,0 +1,262 @@ +/* +Open Asset Import Library (assimp) +---------------------------------------------------------------------- + +Copyright (c) 2006-2012, assimp team +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the +following conditions are met: + +* Redistributions of source code must retain the above + copyright notice, this list of conditions and the + following disclaimer. + +* Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other + materials provided with the distribution. + +* Neither the name of the assimp team, nor the names of its + contributors may be used to endorse or promote products + derived from this software without specific prior + written permission of the assimp team. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"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 COPYRIGHT +OWNER OR CONTRIBUTORS 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. + +---------------------------------------------------------------------- +*/ + +/** @file Logger.hpp + * @brief Abstract base class 'Logger', base of the logging system. + */ +#ifndef INCLUDED_AI_LOGGER_H +#define INCLUDED_AI_LOGGER_H + +#include "types.h" +namespace Assimp { +class LogStream; + +// Maximum length of a log message. Longer messages are rejected. +#define MAX_LOG_MESSAGE_LENGTH 1024u + +// ---------------------------------------------------------------------------------- +/** @brief CPP-API: Abstract interface for logger implementations. + * Assimp provides a default implementation and uses it for almost all + * logging stuff ('DefaultLogger'). This class defines just basic logging + * behaviour and is not of interest for you. Instead, take a look at #DefaultLogger. */ +class ASSIMP_API Logger + : public Intern::AllocateFromAssimpHeap { +public: + + // ---------------------------------------------------------------------- + /** @enum LogSeverity + * @brief Log severity to describe the granularity of logging. + */ + enum LogSeverity + { + NORMAL, //!< Normal granularity of logging + VERBOSE //!< Debug infos will be logged, too + }; + + // ---------------------------------------------------------------------- + /** @enum ErrorSeverity + * @brief Description for severity of a log message. + * + * Every LogStream has a bitwise combination of these flags. + * A LogStream doesn't receive any messages of a specific type + * if it doesn't specify the corresponding ErrorSeverity flag. + */ + enum ErrorSeverity + { + Debugging = 1, //!< Debug log message + Info = 2, //!< Info log message + Warn = 4, //!< Warn log message + Err = 8 //!< Error log message + }; + +public: + + /** @brief Virtual destructor */ + virtual ~Logger(); + + // ---------------------------------------------------------------------- + /** @brief Writes a debug message + * @param message Debug message*/ + void debug(const char* message); + inline void debug(const std::string &message); + + // ---------------------------------------------------------------------- + /** @brief Writes a info message + * @param message Info message*/ + void info(const char* message); + inline void info(const std::string &message); + + // ---------------------------------------------------------------------- + /** @brief Writes a warning message + * @param message Warn message*/ + void warn(const char* message); + inline void warn(const std::string &message); + + // ---------------------------------------------------------------------- + /** @brief Writes an error message + * @param message Error message*/ + void error(const char* message); + inline void error(const std::string &message); + + // ---------------------------------------------------------------------- + /** @brief Set a new log severity. + * @param log_severity New severity for logging*/ + void setLogSeverity(LogSeverity log_severity); + + // ---------------------------------------------------------------------- + /** @brief Get the current log severity*/ + LogSeverity getLogSeverity() const; + + // ---------------------------------------------------------------------- + /** @brief Attach a new log-stream + * + * The logger takes ownership of the stream and is responsible + * for its destruction (which is done using ::delete when the logger + * itself is destroyed). Call detachStream to detach a stream and to + * gain ownership of it again. + * @param pStream Log-stream to attach + * @param severity Message filter, specified which types of log + * messages are dispatched to the stream. Provide a bitwise + * combination of the ErrorSeverity flags. + * @return true if the stream has been attached, false otherwise.*/ + virtual bool attachStream(LogStream *pStream, + unsigned int severity = Debugging | Err | Warn | Info) = 0; + + // ---------------------------------------------------------------------- + /** @brief Detach a still attached stream from the logger (or + * modify the filter flags bits) + * @param pStream Log-stream instance for detaching + * @param severity Provide a bitwise combination of the ErrorSeverity + * flags. This value is &~ed with the current flags of the stream, + * if the result is 0 the stream is detached from the Logger and + * the caller retakes the possession of the stream. + * @return true if the stream has been detached, false otherwise.*/ + virtual bool detatchStream(LogStream *pStream, + unsigned int severity = Debugging | Err | Warn | Info) = 0; + +protected: + + /** Default constructor */ + Logger(); + + /** Construction with a given log severity */ + Logger(LogSeverity severity); + + // ---------------------------------------------------------------------- + /** @brief Called as a request to write a specific debug message + * @param message Debug message. Never longer than + * MAX_LOG_MESSAGE_LENGTH characters (excluding the '0'). + * @note The message string is only valid until the scope of + * the function is left. + */ + virtual void OnDebug(const char* message)= 0; + + // ---------------------------------------------------------------------- + /** @brief Called as a request to write a specific info message + * @param message Info message. Never longer than + * MAX_LOG_MESSAGE_LENGTH characters (ecxluding the '0'). + * @note The message string is only valid until the scope of + * the function is left. + */ + virtual void OnInfo(const char* message) = 0; + + // ---------------------------------------------------------------------- + /** @brief Called as a request to write a specific warn message + * @param message Warn message. Never longer than + * MAX_LOG_MESSAGE_LENGTH characters (exluding the '0'). + * @note The message string is only valid until the scope of + * the function is left. + */ + virtual void OnWarn(const char* essage) = 0; + + // ---------------------------------------------------------------------- + /** @brief Called as a request to write a specific error message + * @param message Error message. Never longer than + * MAX_LOG_MESSAGE_LENGTH characters (exluding the '0'). + * @note The message string is only valid until the scope of + * the function is left. + */ + virtual void OnError(const char* message) = 0; + +protected: + + //! Logger severity + LogSeverity m_Severity; +}; + +// ---------------------------------------------------------------------------------- +// Default constructor +inline Logger::Logger() { + setLogSeverity(NORMAL); +} + +// ---------------------------------------------------------------------------------- +// Virtual destructor +inline Logger::~Logger() +{ +} + +// ---------------------------------------------------------------------------------- +// Construction with given logging severity +inline Logger::Logger(LogSeverity severity) { + setLogSeverity(severity); +} + +// ---------------------------------------------------------------------------------- +// Log severity setter +inline void Logger::setLogSeverity(LogSeverity log_severity){ + m_Severity = log_severity; +} + +// ---------------------------------------------------------------------------------- +// Log severity getter +inline Logger::LogSeverity Logger::getLogSeverity() const { + return m_Severity; +} + +// ---------------------------------------------------------------------------------- +inline void Logger::debug(const std::string &message) +{ + return debug(message.c_str()); +} + +// ---------------------------------------------------------------------------------- +inline void Logger::error(const std::string &message) +{ + return error(message.c_str()); +} + +// ---------------------------------------------------------------------------------- +inline void Logger::warn(const std::string &message) +{ + return warn(message.c_str()); +} + +// ---------------------------------------------------------------------------------- +inline void Logger::info(const std::string &message) +{ + return info(message.c_str()); +} + +// ---------------------------------------------------------------------------------- + +} // Namespace Assimp + +#endif // !! INCLUDED_AI_LOGGER_H diff --git a/Lib/Include/assimp/NullLogger.hpp b/Lib/Include/assimp/NullLogger.hpp new file mode 100644 index 0000000..e87584a --- /dev/null +++ b/Lib/Include/assimp/NullLogger.hpp @@ -0,0 +1,95 @@ +/* +Open Asset Import Library (assimp) +---------------------------------------------------------------------- + +Copyright (c) 2006-2012, assimp team +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the +following conditions are met: + +* Redistributions of source code must retain the above + copyright notice, this list of conditions and the + following disclaimer. + +* Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other + materials provided with the distribution. + +* Neither the name of the assimp team, nor the names of its + contributors may be used to endorse or promote products + derived from this software without specific prior + written permission of the assimp team. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"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 COPYRIGHT +OWNER OR CONTRIBUTORS 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. + +---------------------------------------------------------------------- +*/ + +/** @file NullLogger.h + * @brief Dummy logger +*/ + +#ifndef INCLUDED_AI_NULLLOGGER_H +#define INCLUDED_AI_NULLLOGGER_H + +#include "Logger.hpp" +namespace Assimp { +// --------------------------------------------------------------------------- +/** @brief CPP-API: Empty logging implementation. + * + * Does nothing! Used by default if the application hasn't requested a + * custom logger via #DefaultLogger::set() or #DefaultLogger::create(); */ +class ASSIMP_API NullLogger + : public Logger { + +public: + + /** @brief Logs a debug message */ + void OnDebug(const char* message) { + (void)message; //this avoids compiler warnings + } + + /** @brief Logs an info message */ + void OnInfo(const char* message) { + (void)message; //this avoids compiler warnings + } + + /** @brief Logs a warning message */ + void OnWarn(const char* message) { + (void)message; //this avoids compiler warnings + } + + /** @brief Logs an error message */ + void OnError(const char* message) { + (void)message; //this avoids compiler warnings + } + + /** @brief Detach a still attached stream from logger */ + bool attachStream(LogStream *pStream, unsigned int severity) { + (void)pStream; (void)severity; //this avoids compiler warnings + return false; + } + + /** @brief Detach a still attached stream from logger */ + bool detatchStream(LogStream *pStream, unsigned int severity) { + (void)pStream; (void)severity; //this avoids compiler warnings + return false; + } + +private: +}; +} +#endif // !! AI_NULLLOGGER_H_INCLUDED diff --git a/Lib/Include/assimp/ProgressHandler.hpp b/Lib/Include/assimp/ProgressHandler.hpp new file mode 100644 index 0000000..f2c927d --- /dev/null +++ b/Lib/Include/assimp/ProgressHandler.hpp @@ -0,0 +1,93 @@ +/* +Open Asset Import Library (assimp) +---------------------------------------------------------------------- + +Copyright (c) 2006-2012, assimp team +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the +following conditions are met: + +* Redistributions of source code must retain the above + copyright notice, this list of conditions and the + following disclaimer. + +* Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other + materials provided with the distribution. + +* Neither the name of the assimp team, nor the names of its + contributors may be used to endorse or promote products + derived from this software without specific prior + written permission of the assimp team. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"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 COPYRIGHT +OWNER OR CONTRIBUTORS 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. + +---------------------------------------------------------------------- +*/ + +/** @file ProgressHandler.h + * @brief Abstract base class 'ProgressHandler'. + */ +#ifndef INCLUDED_AI_PROGRESSHANDLER_H +#define INCLUDED_AI_PROGRESSHANDLER_H +#include "types.h" +namespace Assimp { + +// ------------------------------------------------------------------------------------ +/** @brief CPP-API: Abstract interface for custom progress report receivers. + * + * Each #Importer instance maintains its own #ProgressHandler. The default + * implementation provided by Assimp doesn't do anything at all. */ +class ASSIMP_API ProgressHandler + : public Intern::AllocateFromAssimpHeap { +protected: + /** @brief Default constructor */ + ProgressHandler () { + } +public: + /** @brief Virtual destructor */ + virtual ~ProgressHandler () { + } + + // ------------------------------------------------------------------- + /** @brief Progress callback. + * @param percentage An estimate of the current loading progress, + * in percent. Or -1.f if such an estimate is not available. + * + * There are restriction on what you may do from within your + * implementation of this method: no exceptions may be thrown and no + * non-const #Importer methods may be called. It is + * not generally possible to predict the number of callbacks + * fired during a single import. + * + * @return Return false to abort loading at the next possible + * occasion (loaders and Assimp are generally allowed to perform + * all needed cleanup tasks prior to returning control to the + * caller). If the loading is aborted, #Importer::ReadFile() + * returns always NULL. + * + * @note Currently, percentage is always -1.f because there is + * no reliable way to compute it. + * */ + virtual bool Update(float percentage = -1.f) = 0; + + + +}; // !class ProgressHandler +// ------------------------------------------------------------------------------------ +} // Namespace Assimp + +#endif diff --git a/Lib/Include/assimp/ai_assert.h b/Lib/Include/assimp/ai_assert.h new file mode 100644 index 0000000..29ac7a0 --- /dev/null +++ b/Lib/Include/assimp/ai_assert.h @@ -0,0 +1,14 @@ +/** @file assert.h + */ +#ifndef AI_DEBUG_H_INC +#define AI_DEBUG_H_INC + +#ifdef _DEBUG +# include +# define ai_assert(expression) assert(expression) +#else +# define ai_assert(expression) +#endif + + +#endif diff --git a/Lib/Include/assimp/anim.h b/Lib/Include/assimp/anim.h new file mode 100644 index 0000000..abc13ba --- /dev/null +++ b/Lib/Include/assimp/anim.h @@ -0,0 +1,484 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2012, assimp team + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following +conditions are met: + +* Redistributions of source code must retain the above + copyright notice, this list of conditions and the + following disclaimer. + +* Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other + materials provided with the distribution. + +* Neither the name of the assimp team, nor the names of its + contributors may be used to endorse or promote products + derived from this software without specific prior + written permission of the assimp team. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"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 COPYRIGHT +OWNER OR CONTRIBUTORS 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. +--------------------------------------------------------------------------- +*/ + +/** @file anim.h + * @brief Defines the data structures in which the imported animations + * are returned. + */ +#ifndef AI_ANIM_H_INC +#define AI_ANIM_H_INC + +#include "types.h" +#include "quaternion.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// --------------------------------------------------------------------------- +/** A time-value pair specifying a certain 3D vector for the given time. */ +struct aiVectorKey +{ + /** The time of this key */ + double mTime; + + /** The value of this key */ + C_STRUCT aiVector3D mValue; + +#ifdef __cplusplus + + //! Default constructor + aiVectorKey(){} + + //! Construction from a given time and key value + aiVectorKey(double time, const aiVector3D& value) + : mTime (time) + , mValue (value) + {} + + + typedef aiVector3D elem_type; + + // Comparison operators. For use with std::find(); + bool operator == (const aiVectorKey& o) const { + return o.mValue == this->mValue; + } + bool operator != (const aiVectorKey& o) const { + return o.mValue != this->mValue; + } + + // Relational operators. For use with std::sort(); + bool operator < (const aiVectorKey& o) const { + return mTime < o.mTime; + } + bool operator > (const aiVectorKey& o) const { + return mTime > o.mTime; + } +#endif +}; + +// --------------------------------------------------------------------------- +/** A time-value pair specifying a rotation for the given time. + * Rotations are expressed with quaternions. */ +struct aiQuatKey +{ + /** The time of this key */ + double mTime; + + /** The value of this key */ + C_STRUCT aiQuaternion mValue; + +#ifdef __cplusplus + aiQuatKey(){ + } + + /** Construction from a given time and key value */ + aiQuatKey(double time, const aiQuaternion& value) + : mTime (time) + , mValue (value) + {} + + typedef aiQuaternion elem_type; + + // Comparison operators. For use with std::find(); + bool operator == (const aiQuatKey& o) const { + return o.mValue == this->mValue; + } + bool operator != (const aiQuatKey& o) const { + return o.mValue != this->mValue; + } + + // Relational operators. For use with std::sort(); + bool operator < (const aiQuatKey& o) const { + return mTime < o.mTime; + } + bool operator > (const aiQuatKey& o) const { + return mTime > o.mTime; + } +#endif +}; + +// --------------------------------------------------------------------------- +/** Binds a anim mesh to a specific point in time. */ +struct aiMeshKey +{ + /** The time of this key */ + double mTime; + + /** Index into the aiMesh::mAnimMeshes array of the + * mesh coresponding to the #aiMeshAnim hosting this + * key frame. The referenced anim mesh is evaluated + * according to the rules defined in the docs for #aiAnimMesh.*/ + unsigned int mValue; + +#ifdef __cplusplus + + aiMeshKey() { + } + + /** Construction from a given time and key value */ + aiMeshKey(double time, const unsigned int value) + : mTime (time) + , mValue (value) + {} + + typedef unsigned int elem_type; + + // Comparison operators. For use with std::find(); + bool operator == (const aiMeshKey& o) const { + return o.mValue == this->mValue; + } + bool operator != (const aiMeshKey& o) const { + return o.mValue != this->mValue; + } + + // Relational operators. For use with std::sort(); + bool operator < (const aiMeshKey& o) const { + return mTime < o.mTime; + } + bool operator > (const aiMeshKey& o) const { + return mTime > o.mTime; + } + +#endif +}; + +// --------------------------------------------------------------------------- +/** Defines how an animation channel behaves outside the defined time + * range. This corresponds to aiNodeAnim::mPreState and + * aiNodeAnim::mPostState.*/ +enum aiAnimBehaviour +{ + /** The value from the default node transformation is taken*/ + aiAnimBehaviour_DEFAULT = 0x0, + + /** The nearest key value is used without interpolation */ + aiAnimBehaviour_CONSTANT = 0x1, + + /** The value of the nearest two keys is linearly + * extrapolated for the current time value.*/ + aiAnimBehaviour_LINEAR = 0x2, + + /** The animation is repeated. + * + * If the animation key go from n to m and the current + * time is t, use the value at (t-n) % (|m-n|).*/ + aiAnimBehaviour_REPEAT = 0x3, + + + + /** This value is not used, it is just here to force the + * the compiler to map this enum to a 32 Bit integer */ +#ifndef SWIG + _aiAnimBehaviour_Force32Bit = 0x8fffffff +#endif +}; + +// --------------------------------------------------------------------------- +/** Describes the animation of a single node. The name specifies the + * bone/node which is affected by this animation channel. The keyframes + * are given in three separate series of values, one each for position, + * rotation and scaling. The transformation matrix computed from these + * values replaces the node's original transformation matrix at a + * specific time. + * This means all keys are absolute and not relative to the bone default pose. + * The order in which the transformations are applied is + * - as usual - scaling, rotation, translation. + * + * @note All keys are returned in their correct, chronological order. + * Duplicate keys don't pass the validation step. Most likely there + * will be no negative time values, but they are not forbidden also ( so + * implementations need to cope with them! ) */ +struct aiNodeAnim +{ + /** The name of the node affected by this animation. The node + * must exist and it must be unique.*/ + C_STRUCT aiString mNodeName; + + /** The number of position keys */ + unsigned int mNumPositionKeys; + + /** The position keys of this animation channel. Positions are + * specified as 3D vector. The array is mNumPositionKeys in size. + * + * If there are position keys, there will also be at least one + * scaling and one rotation key.*/ + C_STRUCT aiVectorKey* mPositionKeys; + + /** The number of rotation keys */ + unsigned int mNumRotationKeys; + + /** The rotation keys of this animation channel. Rotations are + * given as quaternions, which are 4D vectors. The array is + * mNumRotationKeys in size. + * + * If there are rotation keys, there will also be at least one + * scaling and one position key. */ + C_STRUCT aiQuatKey* mRotationKeys; + + + /** The number of scaling keys */ + unsigned int mNumScalingKeys; + + /** The scaling keys of this animation channel. Scalings are + * specified as 3D vector. The array is mNumScalingKeys in size. + * + * If there are scaling keys, there will also be at least one + * position and one rotation key.*/ + C_STRUCT aiVectorKey* mScalingKeys; + + + /** Defines how the animation behaves before the first + * key is encountered. + * + * The default value is aiAnimBehaviour_DEFAULT (the original + * transformation matrix of the affected node is used).*/ + C_ENUM aiAnimBehaviour mPreState; + + /** Defines how the animation behaves after the last + * key was processed. + * + * The default value is aiAnimBehaviour_DEFAULT (the original + * transformation matrix of the affected node is taken).*/ + C_ENUM aiAnimBehaviour mPostState; + +#ifdef __cplusplus + aiNodeAnim() + { + mNumPositionKeys = 0; mPositionKeys = NULL; + mNumRotationKeys = 0; mRotationKeys = NULL; + mNumScalingKeys = 0; mScalingKeys = NULL; + + mPreState = mPostState = aiAnimBehaviour_DEFAULT; + } + + ~aiNodeAnim() + { + delete [] mPositionKeys; + delete [] mRotationKeys; + delete [] mScalingKeys; + } +#endif // __cplusplus +}; + +// --------------------------------------------------------------------------- +/** Describes vertex-based animations for a single mesh or a group of + * meshes. Meshes carry the animation data for each frame in their + * aiMesh::mAnimMeshes array. The purpose of aiMeshAnim is to + * define keyframes linking each mesh attachment to a particular + * point in time. */ +struct aiMeshAnim +{ + /** Name of the mesh to be animated. An empty string is not allowed, + * animated meshes need to be named (not necessarily uniquely, + * the name can basically serve as wildcard to select a group + * of meshes with similar animation setup)*/ + C_STRUCT aiString mName; + + /** Size of the #mKeys array. Must be 1, at least. */ + unsigned int mNumKeys; + + /** Key frames of the animation. May not be NULL. */ + C_STRUCT aiMeshKey* mKeys; + +#ifdef __cplusplus + + aiMeshAnim() + : mNumKeys() + , mKeys() + {} + + ~aiMeshAnim() + { + delete[] mKeys; + } + +#endif +}; + +// --------------------------------------------------------------------------- +/** An animation consists of keyframe data for a number of nodes. For + * each node affected by the animation a separate series of data is given.*/ +struct aiAnimation +{ + /** The name of the animation. If the modeling package this data was + * exported from does support only a single animation channel, this + * name is usually empty (length is zero). */ + C_STRUCT aiString mName; + + /** Duration of the animation in ticks. */ + double mDuration; + + /** Ticks per second. 0 if not specified in the imported file */ + double mTicksPerSecond; + + /** The number of bone animation channels. Each channel affects + * a single node. */ + unsigned int mNumChannels; + + /** The node animation channels. Each channel affects a single node. + * The array is mNumChannels in size. */ + C_STRUCT aiNodeAnim** mChannels; + + + /** The number of mesh animation channels. Each channel affects + * a single mesh and defines vertex-based animation. */ + unsigned int mNumMeshChannels; + + /** The mesh animation channels. Each channel affects a single mesh. + * The array is mNumMeshChannels in size. */ + C_STRUCT aiMeshAnim** mMeshChannels; + +#ifdef __cplusplus + aiAnimation() + : mDuration(-1.) + , mTicksPerSecond() + , mNumChannels() + , mChannels() + , mNumMeshChannels() + , mMeshChannels() + { + } + + ~aiAnimation() + { + // DO NOT REMOVE THIS ADDITIONAL CHECK + if (mNumChannels && mChannels) { + for( unsigned int a = 0; a < mNumChannels; a++) { + delete mChannels[a]; + } + + delete [] mChannels; + } + if (mNumMeshChannels && mMeshChannels) { + for( unsigned int a = 0; a < mNumMeshChannels; a++) { + delete mMeshChannels[a]; + } + + delete [] mMeshChannels; + } + } +#endif // __cplusplus +}; + +#ifdef __cplusplus +} + + +// some C++ utilities for inter- and extrapolation +namespace Assimp { + +// --------------------------------------------------------------------------- +/** @brief CPP-API: Utility class to simplify interpolations of various data types. + * + * The type of interpolation is choosen automatically depending on the + * types of the arguments. */ +template +struct Interpolator +{ + // ------------------------------------------------------------------ + /** @brief Get the result of the interpolation between a,b. + * + * The interpolation algorithm depends on the type of the operands. + * aiQuaternion's and aiQuatKey's SLERP, the rest does a simple + * linear interpolation. */ + void operator () (T& out,const T& a, const T& b, float d) const { + out = a + (b-a)*d; + } +}; // ! Interpolator + +//! @cond Never + +template <> +struct Interpolator { + void operator () (aiQuaternion& out,const aiQuaternion& a, + const aiQuaternion& b, float d) const + { + aiQuaternion::Interpolate(out,a,b,d); + } +}; // ! Interpolator + +template <> +struct Interpolator { + void operator () (unsigned int& out,unsigned int a, + unsigned int b, float d) const + { + out = d>0.5f ? b : a; + } +}; // ! Interpolator + +template <> +struct Interpolator { + void operator () (aiVector3D& out,const aiVectorKey& a, + const aiVectorKey& b, float d) const + { + Interpolator ipl; + ipl(out,a.mValue,b.mValue,d); + } +}; // ! Interpolator + +template <> +struct Interpolator { + void operator () (aiQuaternion& out, const aiQuatKey a, + const aiQuatKey& b, float d) const + { + Interpolator ipl; + ipl(out,a.mValue,b.mValue,d); + } +}; // ! Interpolator + +template <> +struct Interpolator { + void operator () (unsigned int& out, const aiMeshKey a, + const aiMeshKey& b, float d) const + { + Interpolator ipl; + ipl(out,a.mValue,b.mValue,d); + } +}; // ! Interpolator + +//! @endcond +} // ! end namespace Assimp + + + +#endif // __cplusplus +#endif // AI_ANIM_H_INC diff --git a/Lib/Include/assimp/camera.h b/Lib/Include/assimp/camera.h new file mode 100644 index 0000000..78d3a9e --- /dev/null +++ b/Lib/Include/assimp/camera.h @@ -0,0 +1,223 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2012, assimp team + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following +conditions are met: + +* Redistributions of source code must retain the above + copyright notice, this list of conditions and the + following disclaimer. + +* Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other + materials provided with the distribution. + +* Neither the name of the assimp team, nor the names of its + contributors may be used to endorse or promote products + derived from this software without specific prior + written permission of the assimp team. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"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 COPYRIGHT +OWNER OR CONTRIBUTORS 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. +--------------------------------------------------------------------------- +*/ + +/** @file camera.h + * @brief Defines the aiCamera data structure + */ + +#ifndef AI_CAMERA_H_INC +#define AI_CAMERA_H_INC + +#include "types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// --------------------------------------------------------------------------- +/** Helper structure to describe a virtual camera. + * + * Cameras have a representation in the node graph and can be animated. + * An important aspect is that the camera itself is also part of the + * scenegraph. This means, any values such as the look-at vector are not + * *absolute*, they're relative to the coordinate system defined + * by the node which corresponds to the camera. This allows for camera + * animations. For static cameras parameters like the 'look-at' or 'up' vectors + * are usually specified directly in aiCamera, but beware, they could also + * be encoded in the node transformation. The following (pseudo)code sample + * shows how to do it:

    + * @code + * // Get the camera matrix for a camera at a specific time + * // if the node hierarchy for the camera does not contain + * // at least one animated node this is a static computation + * get-camera-matrix (node sceneRoot, camera cam) : matrix + * { + * node cnd = find-node-for-camera(cam) + * matrix cmt = identity() + * + * // as usual - get the absolute camera transformation for this frame + * for each node nd in hierarchy from sceneRoot to cnd + * matrix cur + * if (is-animated(nd)) + * cur = eval-animation(nd) + * else cur = nd->mTransformation; + * cmt = mult-matrices( cmt, cur ) + * end for + * + * // now multiply with the camera's own local transform + * cam = mult-matrices (cam, get-camera-matrix(cmt) ) + * } + * @endcode + * + * @note some file formats (such as 3DS, ASE) export a "target point" - + * the point the camera is looking at (it can even be animated). Assimp + * writes the target point as a subnode of the camera's main node, + * called ".Target". However this is just additional information + * then the transformation tracks of the camera main node make the + * camera already look in the right direction. + * +*/ +struct aiCamera +{ + /** The name of the camera. + * + * There must be a node in the scenegraph with the same name. + * This node specifies the position of the camera in the scene + * hierarchy and can be animated. + */ + C_STRUCT aiString mName; + + /** Position of the camera relative to the coordinate space + * defined by the corresponding node. + * + * The default value is 0|0|0. + */ + C_STRUCT aiVector3D mPosition; + + + /** 'Up' - vector of the camera coordinate system relative to + * the coordinate space defined by the corresponding node. + * + * The 'right' vector of the camera coordinate system is + * the cross product of the up and lookAt vectors. + * The default value is 0|1|0. The vector + * may be normalized, but it needn't. + */ + C_STRUCT aiVector3D mUp; + + + /** 'LookAt' - vector of the camera coordinate system relative to + * the coordinate space defined by the corresponding node. + * + * This is the viewing direction of the user. + * The default value is 0|0|1. The vector + * may be normalized, but it needn't. + */ + C_STRUCT aiVector3D mLookAt; + + + /** Half horizontal field of view angle, in radians. + * + * The field of view angle is the angle between the center + * line of the screen and the left or right border. + * The default value is 1/4PI. + */ + float mHorizontalFOV; + + /** Distance of the near clipping plane from the camera. + * + * The value may not be 0.f (for arithmetic reasons to prevent + * a division through zero). The default value is 0.1f. + */ + float mClipPlaneNear; + + /** Distance of the far clipping plane from the camera. + * + * The far clipping plane must, of course, be further away than the + * near clipping plane. The default value is 1000.f. The ratio + * between the near and the far plane should not be too + * large (between 1000-10000 should be ok) to avoid floating-point + * inaccuracies which could lead to z-fighting. + */ + float mClipPlaneFar; + + + /** Screen aspect ratio. + * + * This is the ration between the width and the height of the + * screen. Typical values are 4/3, 1/2 or 1/1. This value is + * 0 if the aspect ratio is not defined in the source file. + * 0 is also the default value. + */ + float mAspect; + +#ifdef __cplusplus + + aiCamera() + : mUp (0.f,1.f,0.f) + , mLookAt (0.f,0.f,1.f) + , mHorizontalFOV (0.25f * (float)AI_MATH_PI) + , mClipPlaneNear (0.1f) + , mClipPlaneFar (1000.f) + , mAspect (0.f) + {} + + /** @brief Get a *right-handed* camera matrix from me + * @param out Camera matrix to be filled + */ + void GetCameraMatrix (aiMatrix4x4& out) const + { + /** todo: test ... should work, but i'm not absolutely sure */ + + /** We don't know whether these vectors are already normalized ...*/ + aiVector3D zaxis = mLookAt; zaxis.Normalize(); + aiVector3D yaxis = mUp; yaxis.Normalize(); + aiVector3D xaxis = mUp^mLookAt; xaxis.Normalize(); + + out.a4 = -(xaxis * mPosition); + out.b4 = -(yaxis * mPosition); + out.c4 = -(zaxis * mPosition); + + out.a1 = xaxis.x; + out.a2 = xaxis.y; + out.a3 = xaxis.z; + + out.b1 = yaxis.x; + out.b2 = yaxis.y; + out.b3 = yaxis.z; + + out.c1 = zaxis.x; + out.c2 = zaxis.y; + out.c3 = zaxis.z; + + out.d1 = out.d2 = out.d3 = 0.f; + out.d4 = 1.f; + } + +#endif +}; + + +#ifdef __cplusplus +} +#endif + +#endif // AI_CAMERA_H_INC diff --git a/Lib/Include/assimp/cexport.h b/Lib/Include/assimp/cexport.h new file mode 100644 index 0000000..b044dfd --- /dev/null +++ b/Lib/Include/assimp/cexport.h @@ -0,0 +1,242 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2011, assimp team + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following +conditions are met: + +* Redistributions of source code must retain the above +copyright notice, this list of conditions and the +following disclaimer. + +* Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the +following disclaimer in the documentation and/or other +materials provided with the distribution. + +* Neither the name of the assimp team, nor the names of its +contributors may be used to endorse or promote products +derived from this software without specific prior +written permission of the assimp team. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"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 COPYRIGHT +OWNER OR CONTRIBUTORS 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. +--------------------------------------------------------------------------- +*/ + +/** @file cexport.h +* @brief Defines the C-API for the Assimp export interface +*/ +#ifndef AI_EXPORT_H_INC +#define AI_EXPORT_H_INC + +#ifndef ASSIMP_BUILD_NO_EXPORT + +#include "types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct aiScene; // aiScene.h +struct aiFileIO; // aiFileIO.h + +// -------------------------------------------------------------------------------- +/** Describes an file format which Assimp can export to. Use #aiGetExportFormatCount() to +* learn how many export formats the current Assimp build supports and #aiGetExportFormatDescription() +* to retrieve a description of an export format option. +*/ +struct aiExportFormatDesc +{ + /// a short string ID to uniquely identify the export format. Use this ID string to + /// specify which file format you want to export to when calling #aiExportScene(). + /// Example: "dae" or "obj" + const char* id; + + /// A short description of the file format to present to users. Useful if you want + /// to allow the user to select an export format. + const char* description; + + /// Recommended file extension for the exported file in lower case. + const char* fileExtension; +}; + + +// -------------------------------------------------------------------------------- +/** Returns the number of export file formats available in the current Assimp build. + * Use aiGetExportFormatDescription() to retrieve infos of a specific export format. + */ +ASSIMP_API size_t aiGetExportFormatCount(void); + + +// -------------------------------------------------------------------------------- +/** Returns a description of the nth export file format. Use #aiGetExportFormatCount() + * to learn how many export formats are supported. + * @param pIndex Index of the export format to retrieve information for. Valid range is + * 0 to #aiGetExportFormatCount() + * @return A description of that specific export format. NULL if pIndex is out of range. + */ +ASSIMP_API const C_STRUCT aiExportFormatDesc* aiGetExportFormatDescription( size_t pIndex); + + +// -------------------------------------------------------------------------------- +/** Create a modifyable copy of a scene. + * This is useful to import files via Assimp, change their topology and + * export them again. Since the scene returned by the various importer functions + * is const, a modifyable copy is needed. + * @param pIn Valid scene to be copied + * @param pOut Receives a modifyable copy of the scene. + */ +ASSIMP_API void aiCopyScene(const C_STRUCT aiScene* pIn, + C_STRUCT aiScene** pOut); + +// -------------------------------------------------------------------------------- +/** Exports the given scene to a chosen file format and writes the result file(s) to disk. +* @param pScene The scene to export. Stays in possession of the caller, is not changed by the function. +* The scene is expected to conform to Assimp's Importer output format as specified +* in the @link data Data Structures Page @endlink. In short, this means the model data +* should use a right-handed coordinate systems, face winding should be counter-clockwise +* and the UV coordinate origin is assumed to be in the upper left. If your input data +* uses different conventions, have a look at the last parameter. +* @param pFormatId ID string to specify to which format you want to export to. Use +* aiGetExportFormatCount() / aiGetExportFormatDescription() to learn which export formats are available. +* @param pFileName Output file to write +* @param pIO custom IO implementation to be used. Use this if you use your own storage methods. +* If none is supplied, a default implementation using standard file IO is used. Note that +* #aiExportSceneToBlob is provided as convenience function to export to memory buffers. +* @param pPreprocessing Accepts any choice of the #aiPostProcessing enumerated +* flags, but in reality only a subset of them makes sense here. Specifying +* 'preprocessing' flags is useful if the input scene does not conform to +* Assimp's default conventions as specified in the @link data Data Structures Page @endlink. +* In short, this means the geometry data should use a right-handed coordinate systems, face +* winding should be counter-clockwise and the UV coordinate origin is assumed to be in +* the upper left. The #aiProcess_MakeLeftHanded, #aiProcess_FlipUVs and +* #aiProcess_FlipWindingOrder flags are used in the import side to allow users +* to have those defaults automatically adapted to their conventions. Specifying those flags +* for exporting has the opposite effect, respectively. Some other of the +* #aiPostProcessSteps enumerated values may be useful as well, but you'll need +* to try out what their effect on the exported file is. Many formats impose +* their own restrictions on the structure of the geometry stored therein, +* so some preprocessing may have little or no effect at all, or may be +* redundant as exporters would apply them anyhow. A good example +* is triangulation - whilst you can enforce it by specifying +* the #aiProcess_Triangulate flag, most export formats support only +* triangulate data so they would run the step anyway. +* @return a status code indicating the result of the export +*/ +ASSIMP_API aiReturn aiExportScene( const C_STRUCT aiScene* pScene, + const char* pFormatId, + const char* pFileName, + unsigned int pPreprocessing); + + +// -------------------------------------------------------------------------------- +/** Exports the given scene to a chosen file format using custom IO logic supplied by you. +* @param pScene The scene to export. Stays in possession of the caller, is not changed by the function. +* @param pFormatId ID string to specify to which format you want to export to. Use +* aiGetExportFormatCount() / aiGetExportFormatDescription() to learn which export formats are available. +* @param pFileName Output file to write +* @param pIO custom IO implementation to be used. Use this if you use your own storage methods. +* If none is supplied, a default implementation using standard file IO is used. Note that +* #aiExportSceneToBlob is provided as convenience function to export to memory buffers. +* @param pPreprocessing Please see the documentation for #aiExportScene +* @return a status code indicating the result of the export +* @note Include for the definition of #aiFileIO. +*/ +ASSIMP_API aiReturn aiExportSceneEx( const C_STRUCT aiScene* pScene, + const char* pFormatId, + const char* pFileName, + C_STRUCT aiFileIO* pIO, + unsigned int pPreprocessing ); + + +// -------------------------------------------------------------------------------- +/** Describes a blob of exported scene data. Use #aiExportSceneToBlob() to create a blob containing an +* exported scene. The memory referred by this structure is owned by Assimp. Use #aiReleaseExportedFile() +* to free its resources. Don't try to free the memory on your side - it will crash for most build configurations +* due to conflicting heaps. +* +* Blobs can be nested - each blob may reference another blob, which may in turn reference another blob and so on. +* This is used when exporters write more than one output file for a given #aiScene. See the remarks for +* #aiExportDataBlob::name for more information. +*/ +struct aiExportDataBlob +{ + /// Size of the data in bytes + size_t size; + + /// The data. + void* data; + + /** Name of the blob. An empty string always + indicates the first (and primary) blob, + which contains the actual file data. + Any other blobs are auxiliary files produced + by exporters (i.e. material files). Existence + of such files depends on the file format. Most + formats don't split assets across multiple files. + + If used, blob names usually contain the file + extension that should be used when writing + the data to disc. + */ + aiString name; + + /** Pointer to the next blob in the chain or NULL if there is none. */ + aiExportDataBlob * next; + +#ifdef __cplusplus + /// Default constructor + aiExportDataBlob() { size = 0; data = next = NULL; } + /// Releases the data + ~aiExportDataBlob() { delete [] static_cast( data ); delete next; } + +private: + // no copying + aiExportDataBlob(const aiExportDataBlob& ); + aiExportDataBlob& operator= (const aiExportDataBlob& ); +#endif // __cplusplus +}; + +// -------------------------------------------------------------------------------- +/** Exports the given scene to a chosen file format. Returns the exported data as a binary blob which +* you can write into a file or something. When you're done with the data, use #aiReleaseExportBlob() +* to free the resources associated with the export. +* @param pScene The scene to export. Stays in possession of the caller, is not changed by the function. +* @param pFormatId ID string to specify to which format you want to export to. Use +* #aiGetExportFormatCount() / #aiGetExportFormatDescription() to learn which export formats are available. +* @param pPreprocessing Please see the documentation for #aiExportScene +* @return the exported data or NULL in case of error +*/ +ASSIMP_API const C_STRUCT aiExportDataBlob* aiExportSceneToBlob( const C_STRUCT aiScene* pScene, const char* pFormatId, unsigned int pPreprocessing ); + + +// -------------------------------------------------------------------------------- +/** Releases the memory associated with the given exported data. Use this function to free a data blob +* returned by aiExportScene(). +* @param pData the data blob returned by #aiExportSceneToBlob +*/ +ASSIMP_API C_STRUCT void aiReleaseExportBlob( const C_STRUCT aiExportDataBlob* pData ); + +#ifdef __cplusplus +} +#endif + +#endif // ASSIMP_BUILD_NO_EXPORT +#endif // AI_EXPORT_H_INC + diff --git a/Lib/Include/assimp/cfileio.h b/Lib/Include/assimp/cfileio.h new file mode 100644 index 0000000..83145e7 --- /dev/null +++ b/Lib/Include/assimp/cfileio.h @@ -0,0 +1,135 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2012, assimp team + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following +conditions are met: + +* Redistributions of source code must retain the above + copyright notice, this list of conditions and the + following disclaimer. + +* Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other + materials provided with the distribution. + +* Neither the name of the assimp team, nor the names of its + contributors may be used to endorse or promote products + derived from this software without specific prior + written permission of the assimp team. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"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 COPYRIGHT +OWNER OR CONTRIBUTORS 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. +--------------------------------------------------------------------------- +*/ + +/** @file aiFileIO.h + * @brief Defines generic C routines to access memory-mapped files + */ +#ifndef AI_FILEIO_H_INC +#define AI_FILEIO_H_INC + +#include "types.h" +#ifdef __cplusplus +extern "C" { +#endif +struct aiFileIO; +struct aiFile; + +// aiFile callbacks +typedef size_t (*aiFileWriteProc) (C_STRUCT aiFile*, const char*, size_t, size_t); +typedef size_t (*aiFileReadProc) (C_STRUCT aiFile*, char*, size_t,size_t); +typedef size_t (*aiFileTellProc) (C_STRUCT aiFile*); +typedef void (*aiFileFlushProc) (C_STRUCT aiFile*); +typedef aiReturn (*aiFileSeek)(C_STRUCT aiFile*, size_t, aiOrigin); + +// aiFileIO callbacks +typedef aiFile* (*aiFileOpenProc) (C_STRUCT aiFileIO*, const char*, const char*); +typedef void (*aiFileCloseProc) (C_STRUCT aiFileIO*, C_STRUCT aiFile*); + +// Represents user-defined data +typedef char* aiUserData; + +// ---------------------------------------------------------------------------------- +/** @brief C-API: File system callbacks + * + * Provided are functions to open and close files. Supply a custom structure to + * the import function. If you don't, a default implementation is used. Use custom + * file systems to enable reading from other sources, such as ZIPs + * or memory locations. */ +struct aiFileIO +{ + /** Function used to open a new file + */ + aiFileOpenProc OpenProc; + + /** Function used to close an existing file + */ + aiFileCloseProc CloseProc; + + /** User-defined, opaque data */ + aiUserData UserData; +}; + +// ---------------------------------------------------------------------------------- +/** @brief C-API: File callbacks + * + * Actually, it's a data structure to wrap a set of fXXXX (e.g fopen) + * replacement functions. + * + * The default implementation of the functions utilizes the fXXX functions from + * the CRT. However, you can supply a custom implementation to Assimp by + * delivering a custom aiFileIO. Use this to enable reading from other sources, + * such as ZIP archives or memory locations. */ +struct aiFile +{ + /** Callback to read from a file */ + aiFileReadProc ReadProc; + + /** Callback to write to a file */ + aiFileWriteProc WriteProc; + + /** Callback to retrieve the current position of + * the file cursor (ftell()) + */ + aiFileTellProc TellProc; + + /** Callback to retrieve the size of the file, + * in bytes + */ + aiFileTellProc FileSizeProc; + + /** Callback to set the current position + * of the file cursor (fseek()) + */ + aiFileSeek SeekProc; + + /** Callback to flush the file contents + */ + aiFileFlushProc FlushProc; + + /** User-defined, opaque data + */ + aiUserData UserData; +}; + +#ifdef __cplusplus +} +#endif +#endif // AI_FILEIO_H_INC diff --git a/Lib/Include/assimp/cimport.h b/Lib/Include/assimp/cimport.h new file mode 100644 index 0000000..e859386 --- /dev/null +++ b/Lib/Include/assimp/cimport.h @@ -0,0 +1,493 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2012, assimp team + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following +conditions are met: + +* Redistributions of source code must retain the above + copyright notice, this list of conditions and the + following disclaimer. + +* Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other + materials provided with the distribution. + +* Neither the name of the assimp team, nor the names of its + contributors may be used to endorse or promote products + derived from this software without specific prior + written permission of the assimp team. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"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 COPYRIGHT +OWNER OR CONTRIBUTORS 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. +--------------------------------------------------------------------------- +*/ + +/** @file assimp.h + * @brief Defines the C-API to the Open Asset Import Library. + */ +#ifndef AI_ASSIMP_H_INC +#define AI_ASSIMP_H_INC +#include "types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct aiScene; // aiScene.h +struct aiFileIO; // aiFileIO.h +typedef void (*aiLogStreamCallback)(const char* /* message */, char* /* user */); + +// -------------------------------------------------------------------------------- +/** C-API: Represents a log stream. A log stream receives all log messages and + * streams them _somewhere_. + * @see aiGetPredefinedLogStream + * @see aiAttachLogStream + * @see aiDetachLogStream */ +// -------------------------------------------------------------------------------- +struct aiLogStream +{ + /** callback to be called */ + aiLogStreamCallback callback; + + /** user data to be passed to the callback */ + char* user; +}; + + +// -------------------------------------------------------------------------------- +/** C-API: Represents an opaque set of settings to be used during importing. + * @see aiCreatePropertyStore + * @see aiReleasePropertyStore + * @see aiImportFileExWithProperties + * @see aiSetPropertyInteger + * @see aiSetPropertyFloat + * @see aiSetPropertyString + */ +// -------------------------------------------------------------------------------- +struct aiPropertyStore { char sentinel; }; + +/** Our own C boolean type */ +typedef int aiBool; + +#define AI_FALSE 0 +#define AI_TRUE 1 + +// -------------------------------------------------------------------------------- +/** Reads the given file and returns its content. + * + * If the call succeeds, the imported data is returned in an aiScene structure. + * The data is intended to be read-only, it stays property of the ASSIMP + * library and will be stable until aiReleaseImport() is called. After you're + * done with it, call aiReleaseImport() to free the resources associated with + * this file. If the import fails, NULL is returned instead. Call + * aiGetErrorString() to retrieve a human-readable error text. + * @param pFile Path and filename of the file to be imported, + * expected to be a null-terminated c-string. NULL is not a valid value. + * @param pFlags Optional post processing steps to be executed after + * a successful import. Provide a bitwise combination of the + * #aiPostProcessSteps flags. + * @return Pointer to the imported data or NULL if the import failed. + */ +ASSIMP_API const C_STRUCT aiScene* aiImportFile( + const char* pFile, + unsigned int pFlags); + +// -------------------------------------------------------------------------------- +/** Reads the given file using user-defined I/O functions and returns + * its content. + * + * If the call succeeds, the imported data is returned in an aiScene structure. + * The data is intended to be read-only, it stays property of the ASSIMP + * library and will be stable until aiReleaseImport() is called. After you're + * done with it, call aiReleaseImport() to free the resources associated with + * this file. If the import fails, NULL is returned instead. Call + * aiGetErrorString() to retrieve a human-readable error text. + * @param pFile Path and filename of the file to be imported, + * expected to be a null-terminated c-string. NULL is not a valid value. + * @param pFlags Optional post processing steps to be executed after + * a successful import. Provide a bitwise combination of the + * #aiPostProcessSteps flags. + * @param pFS aiFileIO structure. Will be used to open the model file itself + * and any other files the loader needs to open. Pass NULL to use the default + * implementation. + * @return Pointer to the imported data or NULL if the import failed. + * @note Include for the definition of #aiFileIO. + */ +ASSIMP_API const C_STRUCT aiScene* aiImportFileEx( + const char* pFile, + unsigned int pFlags, + C_STRUCT aiFileIO* pFS); + +// -------------------------------------------------------------------------------- +/** Same as #aiImportFileEx, but adds an extra parameter containing importer settings. + * + * @param pProps #aiPropertyStore instance containing import settings. + * @see aiImportFileEx + */ +ASSIMP_API const C_STRUCT aiScene* aiImportFileExWithProperties( + const char* pFile, + unsigned int pFlags, + C_STRUCT aiFileIO* pFS, + const C_STRUCT aiPropertyStore* pProps); + +// -------------------------------------------------------------------------------- +/** Reads the given file from a given memory buffer, + * + * If the call succeeds, the contents of the file are returned as a pointer to an + * aiScene object. The returned data is intended to be read-only, the importer keeps + * ownership of the data and will destroy it upon destruction. If the import fails, + * NULL is returned. + * A human-readable error description can be retrieved by calling aiGetErrorString(). + * @param pBuffer Pointer to the file data + * @param pLength Length of pBuffer, in bytes + * @param pFlags Optional post processing steps to be executed after + * a successful import. Provide a bitwise combination of the + * #aiPostProcessSteps flags. If you wish to inspect the imported + * scene first in order to fine-tune your post-processing setup, + * consider to use #aiApplyPostProcessing(). + * @param pHint An additional hint to the library. If this is a non empty string, + * the library looks for a loader to support the file extension specified by pHint + * and passes the file to the first matching loader. If this loader is unable to + * completely the request, the library continues and tries to determine the file + * format on its own, a task that may or may not be successful. + * Check the return value, and you'll know ... + * @return A pointer to the imported data, NULL if the import failed. + * + * @note This is a straightforward way to decode models from memory buffers, but it + * doesn't handle model formats spreading their data across multiple files or even + * directories. Examples include OBJ or MD3, which outsource parts of their material + * stuff into external scripts. If you need the full functionality, provide a custom + * IOSystem to make Assimp find these files. + */ +ASSIMP_API const C_STRUCT aiScene* aiImportFileFromMemory( + const char* pBuffer, + unsigned int pLength, + unsigned int pFlags, + const char* pHint); + +// -------------------------------------------------------------------------------- +/** Same as #aiImportFileFromMemory, but adds an extra parameter containing importer settings. + * + * @param pProps #aiPropertyStore instance containing import settings. + * @see aiImportFileFromMemory + */ +ASSIMP_API const C_STRUCT aiScene* aiImportFileFromMemoryWithProperties( + const char* pBuffer, + unsigned int pLength, + unsigned int pFlags, + const char* pHint, + const C_STRUCT aiPropertyStore* pProps); + +// -------------------------------------------------------------------------------- +/** Apply post-processing to an already-imported scene. + * + * This is strictly equivalent to calling #aiImportFile()/#aiImportFileEx with the + * same flags. However, you can use this separate function to inspect the imported + * scene first to fine-tune your post-processing setup. + * @param pScene Scene to work on. + * @param pFlags Provide a bitwise combination of the #aiPostProcessSteps flags. + * @return A pointer to the post-processed data. Post processing is done in-place, + * meaning this is still the same #aiScene which you passed for pScene. However, + * _if_ post-processing failed, the scene could now be NULL. That's quite a rare + * case, post processing steps are not really designed to 'fail'. To be exact, + * the #aiProcess_ValidateDS flag is currently the only post processing step + * which can actually cause the scene to be reset to NULL. + */ +ASSIMP_API const C_STRUCT aiScene* aiApplyPostProcessing( + const C_STRUCT aiScene* pScene, + unsigned int pFlags); + +// -------------------------------------------------------------------------------- +/** Get one of the predefine log streams. This is the quick'n'easy solution to + * access Assimp's log system. Attaching a log stream can slightly reduce Assimp's + * overall import performance. + * + * Usage is rather simple (this will stream the log to a file, named log.txt, and + * the stdout stream of the process: + * @code + * struct aiLogStream c; + * c = aiGetPredefinedLogStream(aiDefaultLogStream_FILE,"log.txt"); + * aiAttachLogStream(&c); + * c = aiGetPredefinedLogStream(aiDefaultLogStream_STDOUT,NULL); + * aiAttachLogStream(&c); + * @endcode + * + * @param pStreams One of the #aiDefaultLogStream enumerated values. + * @param file Solely for the #aiDefaultLogStream_FILE flag: specifies the file to write to. + * Pass NULL for all other flags. + * @return The log stream. callback is set to NULL if something went wrong. + */ +ASSIMP_API C_STRUCT aiLogStream aiGetPredefinedLogStream( + C_ENUM aiDefaultLogStream pStreams, + const char* file); + +// -------------------------------------------------------------------------------- +/** Attach a custom log stream to the libraries' logging system. + * + * Attaching a log stream can slightly reduce Assimp's overall import + * performance. Multiple log-streams can be attached. + * @param stream Describes the new log stream. + * @note To ensure proepr destruction of the logging system, you need to manually + * call aiDetachLogStream() on every single log stream you attach. + * Alternatively (for the lazy folks) #aiDetachAllLogStreams is provided. + */ +ASSIMP_API void aiAttachLogStream( + const C_STRUCT aiLogStream* stream); + +// -------------------------------------------------------------------------------- +/** Enable verbose logging. Verbose logging includes debug-related stuff and + * detailed import statistics. This can have severe impact on import performance + * and memory consumption. However, it might be useful to find out why a file + * didn't read correctly. + * @param d AI_TRUE or AI_FALSE, your decision. + */ +ASSIMP_API void aiEnableVerboseLogging(aiBool d); + +// -------------------------------------------------------------------------------- +/** Detach a custom log stream from the libraries' logging system. + * + * This is the counterpart of #aiAttachPredefinedLogStream. If you attached a stream, + * don't forget to detach it again. + * @param stream The log stream to be detached. + * @return AI_SUCCESS if the log stream has been detached successfully. + * @see aiDetachAllLogStreams + */ +ASSIMP_API C_ENUM aiReturn aiDetachLogStream( + const C_STRUCT aiLogStream* stream); + +// -------------------------------------------------------------------------------- +/** Detach all active log streams from the libraries' logging system. + * This ensures that the logging system is terminated properly and all + * resources allocated by it are actually freed. If you attached a stream, + * don't forget to detach it again. + * @see aiAttachLogStream + * @see aiDetachLogStream + */ +ASSIMP_API void aiDetachAllLogStreams(void); + +// -------------------------------------------------------------------------------- +/** Releases all resources associated with the given import process. + * + * Call this function after you're done with the imported data. + * @param pScene The imported data to release. NULL is a valid value. + */ +ASSIMP_API void aiReleaseImport( + const C_STRUCT aiScene* pScene); + +// -------------------------------------------------------------------------------- +/** Returns the error text of the last failed import process. + * + * @return A textual description of the error that occurred at the last + * import process. NULL if there was no error. There can't be an error if you + * got a non-NULL #aiScene from #aiImportFile/#aiImportFileEx/#aiApplyPostProcessing. + */ +ASSIMP_API const char* aiGetErrorString(); + +// -------------------------------------------------------------------------------- +/** Returns whether a given file extension is supported by ASSIMP + * + * @param szExtension Extension for which the function queries support for. + * Must include a leading dot '.'. Example: ".3ds", ".md3" + * @return AI_TRUE if the file extension is supported. + */ +ASSIMP_API aiBool aiIsExtensionSupported( + const char* szExtension); + +// -------------------------------------------------------------------------------- +/** Get a list of all file extensions supported by ASSIMP. + * + * If a file extension is contained in the list this does, of course, not + * mean that ASSIMP is able to load all files with this extension. + * @param szOut String to receive the extension list. + * Format of the list: "*.3ds;*.obj;*.dae". NULL is not a valid parameter. + */ +ASSIMP_API void aiGetExtensionList( + C_STRUCT aiString* szOut); + +// -------------------------------------------------------------------------------- +/** Get the approximated storage required by an imported asset + * @param pIn Input asset. + * @param in Data structure to be filled. + */ +ASSIMP_API void aiGetMemoryRequirements( + const C_STRUCT aiScene* pIn, + C_STRUCT aiMemoryInfo* in); + + + +// -------------------------------------------------------------------------------- +/** Create an empty property store. Property stores are used to collect import + * settings. + * @return New property store. Property stores need to be manually destroyed using + * the #aiReleasePropertyStore API function. + */ +ASSIMP_API C_STRUCT aiPropertyStore* aiCreatePropertyStore(void); + +// -------------------------------------------------------------------------------- +/** Delete a property store. + * @param p Property store to be deleted. + */ +ASSIMP_API void aiReleasePropertyStore(C_STRUCT aiPropertyStore* p); + +// -------------------------------------------------------------------------------- +/** Set an integer property. + * + * This is the C-version of #Assimp::Importer::SetPropertyInteger(). In the C + * interface, properties are always shared by all imports. It is not possible to + * specify them per import. + * + * @param szName Name of the configuration property to be set. All supported + * public properties are defined in the config.h header file (#AI_CONFIG_XXX). + * @param value New value for the property + */ +ASSIMP_API void aiSetImportPropertyInteger( + C_STRUCT aiPropertyStore* store, + const char* szName, + int value); + +// -------------------------------------------------------------------------------- +/** Set a floating-point property. + * + * This is the C-version of #Assimp::Importer::SetPropertyFloat(). In the C + * interface, properties are always shared by all imports. It is not possible to + * specify them per import. + * + * @param szName Name of the configuration property to be set. All supported + * public properties are defined in the config.h header file (#AI_CONFIG_XXX). + * @param value New value for the property + */ +ASSIMP_API void aiSetImportPropertyFloat( + C_STRUCT aiPropertyStore* store, + const char* szName, + float value); + +// -------------------------------------------------------------------------------- +/** Set a string property. + * + * This is the C-version of #Assimp::Importer::SetPropertyString(). In the C + * interface, properties are always shared by all imports. It is not possible to + * specify them per import. + * + * @param property store to modify. Use #aiCreatePropertyStore to obtain a store. + * @param szName Name of the configuration property to be set. All supported + * public properties are defined in the config.h header file (#AI_CONFIG_XXX). + * @param value New value for the property + */ +ASSIMP_API void aiSetImportPropertyString( + C_STRUCT aiPropertyStore* store, + const char* szName, + const C_STRUCT aiString* st); + +// -------------------------------------------------------------------------------- +/** Construct a quaternion from a 3x3 rotation matrix. + * @param quat Receives the output quaternion. + * @param mat Matrix to 'quaternionize'. + * @see aiQuaternion(const aiMatrix3x3& pRotMatrix) + */ +ASSIMP_API void aiCreateQuaternionFromMatrix( + C_STRUCT aiQuaternion* quat, + const C_STRUCT aiMatrix3x3* mat); + +// -------------------------------------------------------------------------------- +/** Decompose a transformation matrix into its rotational, translational and + * scaling components. + * + * @param mat Matrix to decompose + * @param scaling Receives the scaling component + * @param rotation Receives the rotational component + * @param position Receives the translational component. + * @see aiMatrix4x4::Decompose (aiVector3D&, aiQuaternion&, aiVector3D&) const; + */ +ASSIMP_API void aiDecomposeMatrix( + const C_STRUCT aiMatrix4x4* mat, + C_STRUCT aiVector3D* scaling, + C_STRUCT aiQuaternion* rotation, + C_STRUCT aiVector3D* position); + +// -------------------------------------------------------------------------------- +/** Transpose a 4x4 matrix. + * @param mat Pointer to the matrix to be transposed + */ +ASSIMP_API void aiTransposeMatrix4( + C_STRUCT aiMatrix4x4* mat); + +// -------------------------------------------------------------------------------- +/** Transpose a 3x3 matrix. + * @param mat Pointer to the matrix to be transposed + */ +ASSIMP_API void aiTransposeMatrix3( + C_STRUCT aiMatrix3x3* mat); + +// -------------------------------------------------------------------------------- +/** Transform a vector by a 3x3 matrix + * @param vec Vector to be transformed. + * @param mat Matrix to transform the vector with. + */ +ASSIMP_API void aiTransformVecByMatrix3( + C_STRUCT aiVector3D* vec, + const C_STRUCT aiMatrix3x3* mat); + +// -------------------------------------------------------------------------------- +/** Transform a vector by a 4x4 matrix + * @param vec Vector to be transformed. + * @param mat Matrix to transform the vector with. + */ +ASSIMP_API void aiTransformVecByMatrix4( + C_STRUCT aiVector3D* vec, + const C_STRUCT aiMatrix4x4* mat); + +// -------------------------------------------------------------------------------- +/** Multiply two 4x4 matrices. + * @param dst First factor, receives result. + * @param src Matrix to be multiplied with 'dst'. + */ +ASSIMP_API void aiMultiplyMatrix4( + C_STRUCT aiMatrix4x4* dst, + const C_STRUCT aiMatrix4x4* src); + +// -------------------------------------------------------------------------------- +/** Multiply two 3x3 matrices. + * @param dst First factor, receives result. + * @param src Matrix to be multiplied with 'dst'. + */ +ASSIMP_API void aiMultiplyMatrix3( + C_STRUCT aiMatrix3x3* dst, + const C_STRUCT aiMatrix3x3* src); + +// -------------------------------------------------------------------------------- +/** Get a 3x3 identity matrix. + * @param mat Matrix to receive its personal identity + */ +ASSIMP_API void aiIdentityMatrix3( + C_STRUCT aiMatrix3x3* mat); + +// -------------------------------------------------------------------------------- +/** Get a 4x4 identity matrix. + * @param mat Matrix to receive its personal identity + */ +ASSIMP_API void aiIdentityMatrix4( + C_STRUCT aiMatrix4x4* mat); + + +#ifdef __cplusplus +} +#endif + +#endif // AI_ASSIMP_H_INC diff --git a/Lib/Include/assimp/color4.h b/Lib/Include/assimp/color4.h new file mode 100644 index 0000000..b6a798f --- /dev/null +++ b/Lib/Include/assimp/color4.h @@ -0,0 +1,103 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2012, assimp team + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following +conditions are met: + +* Redistributions of source code must retain the above + copyright notice, this list of conditions and the + following disclaimer. + +* Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other + materials provided with the distribution. + +* Neither the name of the assimp team, nor the names of its + contributors may be used to endorse or promote products + derived from this software without specific prior + written permission of the assimp team. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"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 COPYRIGHT +OWNER OR CONTRIBUTORS 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. +--------------------------------------------------------------------------- +*/ +/** @file aiColor4D.h + * @brief RGBA color structure, including operators when compiling in C++ + */ +#ifndef AI_COLOR4D_H_INC +#define AI_COLOR4D_H_INC + +#include "./Compiler/pushpack1.h" + +#ifdef __cplusplus + +// ---------------------------------------------------------------------------------- +/** Represents a color in Red-Green-Blue space including an +* alpha component. Color values range from 0 to 1. */ +// ---------------------------------------------------------------------------------- +template +class aiColor4t +{ +public: + aiColor4t () : r(), g(), b(), a() {} + aiColor4t (TReal _r, TReal _g, TReal _b, TReal _a) + : r(_r), g(_g), b(_b), a(_a) {} + aiColor4t (TReal _r) : r(_r), g(_r), b(_r), a(_r) {} + aiColor4t (const aiColor4t& o) + : r(o.r), g(o.g), b(o.b), a(o.a) {} + +public: + // combined operators + const aiColor4t& operator += (const aiColor4t& o); + const aiColor4t& operator -= (const aiColor4t& o); + const aiColor4t& operator *= (TReal f); + const aiColor4t& operator /= (TReal f); + +public: + // comparison + bool operator == (const aiColor4t& other) const; + bool operator != (const aiColor4t& other) const; + + // color tuple access, rgba order + inline TReal operator[](unsigned int i) const; + inline TReal& operator[](unsigned int i); + + /** check whether a color is (close to) black */ + inline bool IsBlack() const; + +public: + + // Red, green, blue and alpha color values + TReal r, g, b, a; +} PACK_STRUCT; // !struct aiColor4D + +typedef aiColor4t aiColor4D; + +#else + +struct aiColor4D { + float r, g, b, a; +} PACK_STRUCT; + +#endif // __cplusplus + +#include "./Compiler/poppack1.h" + +#endif // AI_COLOR4D_H_INC diff --git a/Lib/Include/assimp/color4.inl b/Lib/Include/assimp/color4.inl new file mode 100644 index 0000000..1e30b8e --- /dev/null +++ b/Lib/Include/assimp/color4.inl @@ -0,0 +1,165 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2012, assimp team + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following +conditions are met: + +* Redistributions of source code must retain the above + copyright notice, this list of conditions and the + following disclaimer. + +* Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other + materials provided with the distribution. + +* Neither the name of the assimp team, nor the names of its + contributors may be used to endorse or promote products + derived from this software without specific prior + written permission of the assimp team. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"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 COPYRIGHT +OWNER OR CONTRIBUTORS 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. +--------------------------------------------------------------------------- +*/ + +/** @file aiColor4D.inl + * @brief Inline implementation of aiColor4t operators + */ +#ifndef AI_COLOR4D_INL_INC +#define AI_COLOR4D_INL_INC + +#ifdef __cplusplus +#include "color4.h" + +// ------------------------------------------------------------------------------------------------ +template +AI_FORCE_INLINE const aiColor4t& aiColor4t::operator += (const aiColor4t& o) { + r += o.r; g += o.g; b += o.b; a += o.a; + return *this; +} +// ------------------------------------------------------------------------------------------------ +template +AI_FORCE_INLINE const aiColor4t& aiColor4t::operator -= (const aiColor4t& o) { + r -= o.r; g -= o.g; b -= o.b; a -= o.a; + return *this; +} +// ------------------------------------------------------------------------------------------------ +template +AI_FORCE_INLINE const aiColor4t& aiColor4t::operator *= (TReal f) { + r *= f; g *= f; b *= f; a *= f; + return *this; +} +// ------------------------------------------------------------------------------------------------ +template +AI_FORCE_INLINE const aiColor4t& aiColor4t::operator /= (TReal f) { + r /= f; g /= f; b /= f; a /= f; + return *this; +} +// ------------------------------------------------------------------------------------------------ +template +AI_FORCE_INLINE TReal aiColor4t::operator[](unsigned int i) const { + return *(&r + i); +} +// ------------------------------------------------------------------------------------------------ +template +AI_FORCE_INLINE TReal& aiColor4t::operator[](unsigned int i) { + return *(&r + i); +} +// ------------------------------------------------------------------------------------------------ +template +AI_FORCE_INLINE bool aiColor4t::operator== (const aiColor4t& other) const { + return r == other.r && g == other.g && b == other.b && a == other.a; +} +// ------------------------------------------------------------------------------------------------ +template +AI_FORCE_INLINE bool aiColor4t::operator!= (const aiColor4t& other) const { + return r != other.r || g != other.g || b != other.b || a != other.a; +} +// ------------------------------------------------------------------------------------------------ +template +AI_FORCE_INLINE aiColor4t operator + (const aiColor4t& v1, const aiColor4t& v2) { + return aiColor4t( v1.r + v2.r, v1.g + v2.g, v1.b + v2.b, v1.a + v2.a); +} +// ------------------------------------------------------------------------------------------------ +template +AI_FORCE_INLINE aiColor4t operator - (const aiColor4t& v1, const aiColor4t& v2) { + return aiColor4t( v1.r - v2.r, v1.g - v2.g, v1.b - v2.b, v1.a - v2.a); +} +// ------------------------------------------------------------------------------------------------ +template +AI_FORCE_INLINE aiColor4t operator * (const aiColor4t& v1, const aiColor4t& v2) { + return aiColor4t( v1.r * v2.r, v1.g * v2.g, v1.b * v2.b, v1.a * v2.a); +} +// ------------------------------------------------------------------------------------------------ +template +AI_FORCE_INLINE aiColor4t operator / (const aiColor4t& v1, const aiColor4t& v2) { + return aiColor4t( v1.r / v2.r, v1.g / v2.g, v1.b / v2.b, v1.a / v2.a); +} +// ------------------------------------------------------------------------------------------------ +template +AI_FORCE_INLINE aiColor4t operator * ( TReal f, const aiColor4t& v) { + return aiColor4t( f*v.r, f*v.g, f*v.b, f*v.a); +} +// ------------------------------------------------------------------------------------------------ +template +AI_FORCE_INLINE aiColor4t operator * ( const aiColor4t& v, TReal f) { + return aiColor4t( f*v.r, f*v.g, f*v.b, f*v.a); +} +// ------------------------------------------------------------------------------------------------ +template +AI_FORCE_INLINE aiColor4t operator / ( const aiColor4t& v, TReal f) { + return v * (1/f); +} +// ------------------------------------------------------------------------------------------------ +template +AI_FORCE_INLINE aiColor4t operator / ( TReal f,const aiColor4t& v) { + return aiColor4t(f,f,f,f)/v; +} +// ------------------------------------------------------------------------------------------------ +template +AI_FORCE_INLINE aiColor4t operator + ( const aiColor4t& v, TReal f) { + return aiColor4t( f+v.r, f+v.g, f+v.b, f+v.a); +} +// ------------------------------------------------------------------------------------------------ +template +AI_FORCE_INLINE aiColor4t operator - ( const aiColor4t& v, TReal f) { + return aiColor4t( v.r-f, v.g-f, v.b-f, v.a-f); +} +// ------------------------------------------------------------------------------------------------ +template +AI_FORCE_INLINE aiColor4t operator + ( TReal f, const aiColor4t& v) { + return aiColor4t( f+v.r, f+v.g, f+v.b, f+v.a); +} +// ------------------------------------------------------------------------------------------------ +template +AI_FORCE_INLINE aiColor4t operator - ( TReal f, const aiColor4t& v) { + return aiColor4t( f-v.r, f-v.g, f-v.b, f-v.a); +} + +// ------------------------------------------------------------------------------------------------ +template +inline bool aiColor4t :: IsBlack() const { + // The alpha component doesn't care here. black is black. + static const TReal epsilon = 10e-3f; + return fabs( r ) < epsilon && fabs( g ) < epsilon && fabs( b ) < epsilon; +} + +#endif // __cplusplus +#endif // AI_VECTOR3D_INL_INC diff --git a/Lib/Include/assimp/config.h b/Lib/Include/assimp/config.h new file mode 100644 index 0000000..63075bd --- /dev/null +++ b/Lib/Include/assimp/config.h @@ -0,0 +1,738 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2012, assimp team + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following +conditions are met: + +* Redistributions of source code must retain the above + copyright notice, this list of conditions and the + following disclaimer. + +* Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other + materials provided with the distribution. + +* Neither the name of the assimp team, nor the names of its + contributors may be used to endorse or promote products + derived from this software without specific prior + written permission of the assimp team. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"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 COPYRIGHT +OWNER OR CONTRIBUTORS 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. +--------------------------------------------------------------------------- +*/ + +/** @file config.h + * @brief Defines constants for configurable properties for the library + * + * Typically these properties are set via + * #Assimp::Importer::SetPropertyFloat, + * #Assimp::Importer::SetPropertyInteger or + * #Assimp::Importer::SetPropertyString, + * depending on the data type of a property. All properties have a + * default value. See the doc for the mentioned methods for more details. + * + *

    + * The corresponding functions for use with the plain-c API are: + * #aiSetImportPropertyInteger, + * #aiSetImportPropertyFloat, + * #aiSetImportPropertyString + */ +#ifndef INCLUDED_AI_CONFIG_H +#define INCLUDED_AI_CONFIG_H + + +// ########################################################################### +// LIBRARY SETTINGS +// General, global settings +// ########################################################################### + +// --------------------------------------------------------------------------- +/** @brief Enables time measurements. + * + * If enabled, measures the time needed for each part of the loading + * process (i.e. IO time, importing, postprocessing, ..) and dumps + * these timings to the DefaultLogger. See the @link perf Performance + * Page@endlink for more information on this topic. + * + * Property type: bool. Default value: false. + */ +#define AI_CONFIG_GLOB_MEASURE_TIME \ + "GLOB_MEASURE_TIME" + +# if 0 // not implemented yet +// --------------------------------------------------------------------------- +/** @brief Set Assimp's multithreading policy. + * + * This setting is ignored if Assimp was built without boost.thread + * support (ASSIMP_BUILD_NO_THREADING, which is implied by ASSIMP_BUILD_BOOST_WORKAROUND). + * Possible values are: -1 to let Assimp decide what to do, 0 to disable + * multithreading entirely and any number larger than 0 to force a specific + * number of threads. Assimp is always free to ignore this settings, which is + * merely a hint. Usually, the default value (-1) will be fine. However, if + * Assimp is used concurrently from multiple user threads, it might be useful + * to limit each Importer instance to a specific number of cores. + * + * For more information, see the @link threading Threading page@endlink. + * Property type: int, default value: -1. + */ +#define AI_CONFIG_GLOB_MULTITHREADING \ + "GLOB_MULTITHREADING" +#endif + +// ########################################################################### +// POST PROCESSING SETTINGS +// Various stuff to fine-tune the behavior of a specific post processing step. +// ########################################################################### + + +// --------------------------------------------------------------------------- +/** @brief Maximum bone count per mesh for the SplitbyBoneCount step. + * + * Meshes are split until the maximum number of bones is reached. The default + * value is AI_SBBC_DEFAULT_MAX_BONES, which may be altered at + * compile-time. + * Property data type: integer. + */ +// --------------------------------------------------------------------------- +#define AI_CONFIG_PP_SBBC_MAX_BONES \ + "PP_SBBC_MAX_BONES" + + +// default limit for bone count +#if (!defined AI_SBBC_DEFAULT_MAX_BONES) +# define AI_SBBC_DEFAULT_MAX_BONES 60 +#endif + + +// --------------------------------------------------------------------------- +/** @brief Specifies the maximum angle that may be between two vertex tangents + * that their tangents and bi-tangents are smoothed. + * + * This applies to the CalcTangentSpace-Step. The angle is specified + * in degrees. The maximum value is 175. + * Property type: float. Default value: 45 degrees + */ +#define AI_CONFIG_PP_CT_MAX_SMOOTHING_ANGLE \ + "PP_CT_MAX_SMOOTHING_ANGLE" + +// --------------------------------------------------------------------------- +/** @brief Source UV channel for tangent space computation. + * + * The specified channel must exist or an error will be raised. + * Property type: integer. Default value: 0 + */ +// --------------------------------------------------------------------------- +#define AI_CONFIG_PP_CT_TEXTURE_CHANNEL_INDEX \ + "PP_CT_TEXTURE_CHANNEL_INDEX" + +// --------------------------------------------------------------------------- +/** @brief Specifies the maximum angle that may be between two face normals + * at the same vertex position that their are smoothed together. + * + * Sometimes referred to as 'crease angle'. + * This applies to the GenSmoothNormals-Step. The angle is specified + * in degrees, so 180 is PI. The default value is 175 degrees (all vertex + * normals are smoothed). The maximum value is 175, too. Property type: float. + * Warning: setting this option may cause a severe loss of performance. The + * performance is unaffected if the #AI_CONFIG_FAVOUR_SPEED flag is set but + * the output quality may be reduced. + */ +#define AI_CONFIG_PP_GSN_MAX_SMOOTHING_ANGLE \ + "PP_GSN_MAX_SMOOTHING_ANGLE" + +// --------------------------------------------------------------------------- +/** @brief Sets the colormap (= palette) to be used to decode embedded + * textures in MDL (Quake or 3DGS) files. + * + * This must be a valid path to a file. The file is 768 (256*3) bytes + * large and contains RGB triplets for each of the 256 palette entries. + * The default value is colormap.lmp. If the file is not found, + * a default palette (from Quake 1) is used. + * Property type: string. + */ +#define AI_CONFIG_IMPORT_MDL_COLORMAP \ + "IMPORT_MDL_COLORMAP" + +// --------------------------------------------------------------------------- +/** @brief Configures the #aiProcess_RemoveRedundantMaterials step to + * keep materials matching a name in a given list. + * + * This is a list of 1 to n strings, ' ' serves as delimiter character. + * Identifiers containing whitespaces must be enclosed in *single* + * quotation marks. For example: + * "keep-me and_me_to anotherMaterialToBeKept \'name with whitespace\'". + * If a material matches on of these names, it will not be modified or + * removed by the postprocessing step nor will other materials be replaced + * by a reference to it.
    + * This option might be useful if you are using some magic material names + * to pass additional semantics through the content pipeline. This ensures + * they won't be optimized away, but a general optimization is still + * performed for materials not contained in the list. + * Property type: String. Default value: n/a + * @note Linefeeds, tabs or carriage returns are treated as whitespace. + * Material names are case sensitive. + */ +#define AI_CONFIG_PP_RRM_EXCLUDE_LIST \ + "PP_RRM_EXCLUDE_LIST" + +// --------------------------------------------------------------------------- +/** @brief Configures the #aiProcess_PretransformVertices step to + * keep the scene hierarchy. Meshes are moved to worldspace, but + * no optimization is performed (read: meshes with equal materials are not + * joined. The total number of meshes won't change). + * + * This option could be of use for you if the scene hierarchy contains + * important additional information which you intend to parse. + * For rendering, you can still render all meshes in the scene without + * any transformations. + * Property type: bool. Default value: false. + */ +#define AI_CONFIG_PP_PTV_KEEP_HIERARCHY \ + "PP_PTV_KEEP_HIERARCHY" + +// --------------------------------------------------------------------------- +/** @brief Configures the #aiProcess_PretransformVertices step to normalize + * all vertex components into the [-1,1] range. That is, a bounding box + * for the whole scene is computed, the maximum component is taken and all + * meshes are scaled appropriately (uniformly of course!). + * This might be useful if you don't know the spatial dimension of the input + * data*/ +#define AI_CONFIG_PP_PTV_NORMALIZE \ + "PP_PTV_NORMALIZE" + +// --------------------------------------------------------------------------- +/** @brief Configures the #aiProcess_FindDegenerates step to + * remove degenerated primitives from the import - immediately. + * + * The default behaviour converts degenerated triangles to lines and + * degenerated lines to points. See the documentation to the + * #aiProcess_FindDegenerates step for a detailed example of the various ways + * to get rid of these lines and points if you don't want them. + * Property type: bool. Default value: false. + */ +#define AI_CONFIG_PP_FD_REMOVE \ + "PP_FD_REMOVE" + +// --------------------------------------------------------------------------- +/** @brief Configures the #aiProcess_OptimizeGraph step to preserve nodes + * matching a name in a given list. + * + * This is a list of 1 to n strings, ' ' serves as delimiter character. + * Identifiers containing whitespaces must be enclosed in *single* + * quotation marks. For example: + * "keep-me and_me_to anotherNodeToBeKept \'name with whitespace\'". + * If a node matches on of these names, it will not be modified or + * removed by the postprocessing step.
    + * This option might be useful if you are using some magic node names + * to pass additional semantics through the content pipeline. This ensures + * they won't be optimized away, but a general optimization is still + * performed for nodes not contained in the list. + * Property type: String. Default value: n/a + * @note Linefeeds, tabs or carriage returns are treated as whitespace. + * Node names are case sensitive. + */ +#define AI_CONFIG_PP_OG_EXCLUDE_LIST \ + "PP_OG_EXCLUDE_LIST" + +// --------------------------------------------------------------------------- +/** @brief Set the maximum number of triangles in a mesh. + * + * This is used by the "SplitLargeMeshes" PostProcess-Step to determine + * whether a mesh must be split or not. + * @note The default value is AI_SLM_DEFAULT_MAX_TRIANGLES + * Property type: integer. + */ +#define AI_CONFIG_PP_SLM_TRIANGLE_LIMIT \ + "PP_SLM_TRIANGLE_LIMIT" + +// default value for AI_CONFIG_PP_SLM_TRIANGLE_LIMIT +#if (!defined AI_SLM_DEFAULT_MAX_TRIANGLES) +# define AI_SLM_DEFAULT_MAX_TRIANGLES 1000000 +#endif + +// --------------------------------------------------------------------------- +/** @brief Set the maximum number of vertices in a mesh. + * + * This is used by the "SplitLargeMeshes" PostProcess-Step to determine + * whether a mesh must be split or not. + * @note The default value is AI_SLM_DEFAULT_MAX_VERTICES + * Property type: integer. + */ +#define AI_CONFIG_PP_SLM_VERTEX_LIMIT \ + "PP_SLM_VERTEX_LIMIT" + +// default value for AI_CONFIG_PP_SLM_VERTEX_LIMIT +#if (!defined AI_SLM_DEFAULT_MAX_VERTICES) +# define AI_SLM_DEFAULT_MAX_VERTICES 1000000 +#endif + +// --------------------------------------------------------------------------- +/** @brief Set the maximum number of bones affecting a single vertex + * + * This is used by the #aiProcess_LimitBoneWeights PostProcess-Step. + * @note The default value is AI_LBW_MAX_WEIGHTS + * Property type: integer.*/ +#define AI_CONFIG_PP_LBW_MAX_WEIGHTS \ + "PP_LBW_MAX_WEIGHTS" + +// default value for AI_CONFIG_PP_LBW_MAX_WEIGHTS +#if (!defined AI_LMW_MAX_WEIGHTS) +# define AI_LMW_MAX_WEIGHTS 0x4 +#endif // !! AI_LMW_MAX_WEIGHTS + +// --------------------------------------------------------------------------- +/** @brief Lower the deboning threshold in order to remove more bones. + * + * This is used by the #aiProcess_Debone PostProcess-Step. + * @note The default value is AI_DEBONE_THRESHOLD + * Property type: float.*/ +#define AI_CONFIG_PP_DB_THRESHOLD \ + "PP_DB_THRESHOLD" + +// default value for AI_CONFIG_PP_LBW_MAX_WEIGHTS +#if (!defined AI_DEBONE_THRESHOLD) +# define AI_DEBONE_THRESHOLD 1.0f +#endif // !! AI_DEBONE_THRESHOLD + +// --------------------------------------------------------------------------- +/** @brief Require all bones qualify for deboning before removing any + * + * This is used by the #aiProcess_Debone PostProcess-Step. + * @note The default value is 0 + * Property type: bool.*/ +#define AI_CONFIG_PP_DB_ALL_OR_NONE \ + "PP_DB_ALL_OR_NONE" + +/** @brief Default value for the #AI_CONFIG_PP_ICL_PTCACHE_SIZE property + */ +#ifndef PP_ICL_PTCACHE_SIZE +# define PP_ICL_PTCACHE_SIZE 12 +#endif + +// --------------------------------------------------------------------------- +/** @brief Set the size of the post-transform vertex cache to optimize the + * vertices for. This configures the #aiProcess_ImproveCacheLocality step. + * + * The size is given in vertices. Of course you can't know how the vertex + * format will exactly look like after the import returns, but you can still + * guess what your meshes will probably have. + * @note The default value is #PP_ICL_PTCACHE_SIZE. That results in slight + * performance improvements for most nVidia/AMD cards since 2002. + * Property type: integer. + */ +#define AI_CONFIG_PP_ICL_PTCACHE_SIZE "PP_ICL_PTCACHE_SIZE" + +// --------------------------------------------------------------------------- +/** @brief Enumerates components of the aiScene and aiMesh data structures + * that can be excluded from the import using the #aiPrpcess_RemoveComponent step. + * + * See the documentation to #aiProcess_RemoveComponent for more details. + */ +enum aiComponent +{ + /** Normal vectors */ +#ifdef SWIG + aiComponent_NORMALS = 0x2, +#else + aiComponent_NORMALS = 0x2u, +#endif + + /** Tangents and bitangents go always together ... */ +#ifdef SWIG + aiComponent_TANGENTS_AND_BITANGENTS = 0x4, +#else + aiComponent_TANGENTS_AND_BITANGENTS = 0x4u, +#endif + + /** ALL color sets + * Use aiComponent_COLORn(N) to specify the N'th set */ + aiComponent_COLORS = 0x8, + + /** ALL texture UV sets + * aiComponent_TEXCOORDn(N) to specify the N'th set */ + aiComponent_TEXCOORDS = 0x10, + + /** Removes all bone weights from all meshes. + * The scenegraph nodes corresponding to the bones are NOT removed. + * use the #aiProcess_OptimizeGraph step to do this */ + aiComponent_BONEWEIGHTS = 0x20, + + /** Removes all node animations (aiScene::mAnimations). + * The corresponding scenegraph nodes are NOT removed. + * use the #aiProcess_OptimizeGraph step to do this */ + aiComponent_ANIMATIONS = 0x40, + + /** Removes all embedded textures (aiScene::mTextures) */ + aiComponent_TEXTURES = 0x80, + + /** Removes all light sources (aiScene::mLights). + * The corresponding scenegraph nodes are NOT removed. + * use the #aiProcess_OptimizeGraph step to do this */ + aiComponent_LIGHTS = 0x100, + + /** Removes all light sources (aiScene::mCameras). + * The corresponding scenegraph nodes are NOT removed. + * use the #aiProcess_OptimizeGraph step to do this */ + aiComponent_CAMERAS = 0x200, + + /** Removes all meshes (aiScene::mMeshes). */ + aiComponent_MESHES = 0x400, + + /** Removes all materials. One default material will + * be generated, so aiScene::mNumMaterials will be 1. */ + aiComponent_MATERIALS = 0x800, + + + /** This value is not used. It is just there to force the + * compiler to map this enum to a 32 Bit integer. */ +#ifndef SWIG + _aiComponent_Force32Bit = 0x9fffffff +#endif +}; + +// Remove a specific color channel 'n' +#define aiComponent_COLORSn(n) (1u << (n+20u)) + +// Remove a specific UV channel 'n' +#define aiComponent_TEXCOORDSn(n) (1u << (n+25u)) + +// --------------------------------------------------------------------------- +/** @brief Input parameter to the #aiProcess_RemoveComponent step: + * Specifies the parts of the data structure to be removed. + * + * See the documentation to this step for further details. The property + * is expected to be an integer, a bitwise combination of the + * #aiComponent flags defined above in this header. The default + * value is 0. Important: if no valid mesh is remaining after the + * step has been executed (e.g you thought it was funny to specify ALL + * of the flags defined above) the import FAILS. Mainly because there is + * no data to work on anymore ... + */ +#define AI_CONFIG_PP_RVC_FLAGS \ + "PP_RVC_FLAGS" + +// --------------------------------------------------------------------------- +/** @brief Input parameter to the #aiProcess_SortByPType step: + * Specifies which primitive types are removed by the step. + * + * This is a bitwise combination of the aiPrimitiveType flags. + * Specifying all of them is illegal, of course. A typical use would + * be to exclude all line and point meshes from the import. This + * is an integer property, its default value is 0. + */ +#define AI_CONFIG_PP_SBP_REMOVE \ + "PP_SBP_REMOVE" + +// --------------------------------------------------------------------------- +/** @brief Input parameter to the #aiProcess_FindInvalidData step: + * Specifies the floating-point accuracy for animation values. The step + * checks for animation tracks where all frame values are absolutely equal + * and removes them. This tweakable controls the epsilon for floating-point + * comparisons - two keys are considered equal if the invariant + * abs(n0-n1)>epsilon holds true for all vector respectively quaternion + * components. The default value is 0.f - comparisons are exact then. + */ +#define AI_CONFIG_PP_FID_ANIM_ACCURACY \ + "PP_FID_ANIM_ACCURACY" + + +// TransformUVCoords evaluates UV scalings +#define AI_UVTRAFO_SCALING 0x1 + +// TransformUVCoords evaluates UV rotations +#define AI_UVTRAFO_ROTATION 0x2 + +// TransformUVCoords evaluates UV translation +#define AI_UVTRAFO_TRANSLATION 0x4 + +// Everything baked together -> default value +#define AI_UVTRAFO_ALL (AI_UVTRAFO_SCALING | AI_UVTRAFO_ROTATION | AI_UVTRAFO_TRANSLATION) + +// --------------------------------------------------------------------------- +/** @brief Input parameter to the #aiProcess_TransformUVCoords step: + * Specifies which UV transformations are evaluated. + * + * This is a bitwise combination of the AI_UVTRAFO_XXX flags (integer + * property, of course). By default all transformations are enabled + * (AI_UVTRAFO_ALL). + */ +#define AI_CONFIG_PP_TUV_EVALUATE \ + "PP_TUV_EVALUATE" + +// --------------------------------------------------------------------------- +/** @brief A hint to assimp to favour speed against import quality. + * + * Enabling this option may result in faster loading, but it needn't. + * It represents just a hint to loaders and post-processing steps to use + * faster code paths, if possible. + * This property is expected to be an integer, != 0 stands for true. + * The default value is 0. + */ +#define AI_CONFIG_FAVOUR_SPEED \ + "FAVOUR_SPEED" + + +// ########################################################################### +// IMPORTER SETTINGS +// Various stuff to fine-tune the behaviour of specific importer plugins. +// ########################################################################### + + +// --------------------------------------------------------------------------- +/** @brief Set the vertex animation keyframe to be imported + * + * ASSIMP does not support vertex keyframes (only bone animation is supported). + * The library reads only one frame of models with vertex animations. + * By default this is the first frame. + * \note The default value is 0. This option applies to all importers. + * However, it is also possible to override the global setting + * for a specific loader. You can use the AI_CONFIG_IMPORT_XXX_KEYFRAME + * options (where XXX is a placeholder for the file format for which you + * want to override the global setting). + * Property type: integer. + */ +#define AI_CONFIG_IMPORT_GLOBAL_KEYFRAME "IMPORT_GLOBAL_KEYFRAME" + +#define AI_CONFIG_IMPORT_MD3_KEYFRAME "IMPORT_MD3_KEYFRAME" +#define AI_CONFIG_IMPORT_MD2_KEYFRAME "IMPORT_MD2_KEYFRAME" +#define AI_CONFIG_IMPORT_MDL_KEYFRAME "IMPORT_MDL_KEYFRAME" +#define AI_CONFIG_IMPORT_MDC_KEYFRAME "IMPORT_MDC_KEYFRAME" +#define AI_CONFIG_IMPORT_SMD_KEYFRAME "IMPORT_SMD_KEYFRAME" +#define AI_CONFIG_IMPORT_UNREAL_KEYFRAME "IMPORT_UNREAL_KEYFRAME" + + +// --------------------------------------------------------------------------- +/** @brief Configures the AC loader to collect all surfaces which have the + * "Backface cull" flag set in separate meshes. + * + * Property type: bool. Default value: true. + */ +#define AI_CONFIG_IMPORT_AC_SEPARATE_BFCULL \ + "IMPORT_AC_SEPARATE_BFCULL" + +// --------------------------------------------------------------------------- +/** @brief Configures whether the AC loader evaluates subdivision surfaces ( + * indicated by the presence of the 'subdiv' attribute in the file). By + * default, Assimp performs the subdivision using the standard + * Catmull-Clark algorithm + * + * * Property type: bool. Default value: true. + */ +#define AI_CONFIG_IMPORT_AC_EVAL_SUBDIVISION \ + "IMPORT_AC_EVAL_SUBDIVISION" + +// --------------------------------------------------------------------------- +/** @brief Configures the UNREAL 3D loader to separate faces with different + * surface flags (e.g. two-sided vs. single-sided). + * + * * Property type: bool. Default value: true. + */ +#define AI_CONFIG_IMPORT_UNREAL_HANDLE_FLAGS \ + "UNREAL_HANDLE_FLAGS" + +// --------------------------------------------------------------------------- +/** @brief Configures the terragen import plugin to compute uv's for + * terrains, if not given. Furthermore a default texture is assigned. + * + * UV coordinates for terrains are so simple to compute that you'll usually + * want to compute them on your own, if you need them. This option is intended + * for model viewers which want to offer an easy way to apply textures to + * terrains. + * * Property type: bool. Default value: false. + */ +#define AI_CONFIG_IMPORT_TER_MAKE_UVS \ + "IMPORT_TER_MAKE_UVS" + +// --------------------------------------------------------------------------- +/** @brief Configures the ASE loader to always reconstruct normal vectors + * basing on the smoothing groups loaded from the file. + * + * Some ASE files have carry invalid normals, other don't. + * * Property type: bool. Default value: true. + */ +#define AI_CONFIG_IMPORT_ASE_RECONSTRUCT_NORMALS \ + "IMPORT_ASE_RECONSTRUCT_NORMALS" + +// --------------------------------------------------------------------------- +/** @brief Configures the M3D loader to detect and process multi-part + * Quake player models. + * + * These models usually consist of 3 files, lower.md3, upper.md3 and + * head.md3. If this property is set to true, Assimp will try to load and + * combine all three files if one of them is loaded. + * Property type: bool. Default value: true. + */ +#define AI_CONFIG_IMPORT_MD3_HANDLE_MULTIPART \ + "IMPORT_MD3_HANDLE_MULTIPART" + +// --------------------------------------------------------------------------- +/** @brief Tells the MD3 loader which skin files to load. + * + * When loading MD3 files, Assimp checks whether a file + * _.skin is existing. These files are used by + * Quake III to be able to assign different skins (e.g. red and blue team) + * to models. 'default', 'red', 'blue' are typical skin names. + * Property type: String. Default value: "default". + */ +#define AI_CONFIG_IMPORT_MD3_SKIN_NAME \ + "IMPORT_MD3_SKIN_NAME" + +// --------------------------------------------------------------------------- +/** @brief Specify the Quake 3 shader file to be used for a particular + * MD3 file. This can also be a search path. + * + * By default Assimp's behaviour is as follows: If a MD3 file + * /models///.md3 is + * loaded, the library tries to locate the corresponding shader file in + * /scripts/.shader. This property overrides this + * behaviour. It can either specify a full path to the shader to be loaded + * or alternatively the path (relative or absolute) to the directory where + * the shaders for all MD3s to be loaded reside. Assimp attempts to open + *
    /.shader first, /.shader + * is the fallback file. Note that should have a terminal (back)slash. + * Property type: String. Default value: n/a. + */ +#define AI_CONFIG_IMPORT_MD3_SHADER_SRC \ + "IMPORT_MD3_SHADER_SRC" + +// --------------------------------------------------------------------------- +/** @brief Configures the LWO loader to load just one layer from the model. + * + * LWO files consist of layers and in some cases it could be useful to load + * only one of them. This property can be either a string - which specifies + * the name of the layer - or an integer - the index of the layer. If the + * property is not set the whole LWO model is loaded. Loading fails if the + * requested layer is not available. The layer index is zero-based and the + * layer name may not be empty.
    + * Property type: Integer. Default value: all layers are loaded. + */ +#define AI_CONFIG_IMPORT_LWO_ONE_LAYER_ONLY \ + "IMPORT_LWO_ONE_LAYER_ONLY" + +// --------------------------------------------------------------------------- +/** @brief Configures the MD5 loader to not load the MD5ANIM file for + * a MD5MESH file automatically. + * + * The default strategy is to look for a file with the same name but the + * MD5ANIM extension in the same directory. If it is found, it is loaded + * and combined with the MD5MESH file. This configuration option can be + * used to disable this behaviour. + * + * * Property type: bool. Default value: false. + */ +#define AI_CONFIG_IMPORT_MD5_NO_ANIM_AUTOLOAD \ + "IMPORT_MD5_NO_ANIM_AUTOLOAD" + +// --------------------------------------------------------------------------- +/** @brief Defines the begin of the time range for which the LWS loader + * evaluates animations and computes aiNodeAnim's. + * + * Assimp provides full conversion of LightWave's envelope system, including + * pre and post conditions. The loader computes linearly subsampled animation + * chanels with the frame rate given in the LWS file. This property defines + * the start time. Note: animation channels are only generated if a node + * has at least one envelope with more tan one key assigned. This property. + * is given in frames, '0' is the first frame. By default, if this property + * is not set, the importer takes the animation start from the input LWS + * file ('FirstFrame' line)
    + * Property type: Integer. Default value: taken from file. + * + * @see AI_CONFIG_IMPORT_LWS_ANIM_END - end of the imported time range + */ +#define AI_CONFIG_IMPORT_LWS_ANIM_START \ + "IMPORT_LWS_ANIM_START" +#define AI_CONFIG_IMPORT_LWS_ANIM_END \ + "IMPORT_LWS_ANIM_END" + +// --------------------------------------------------------------------------- +/** @brief Defines the output frame rate of the IRR loader. + * + * IRR animations are difficult to convert for Assimp and there will + * always be a loss of quality. This setting defines how many keys per second + * are returned by the converter.
    + * Property type: integer. Default value: 100 + */ +#define AI_CONFIG_IMPORT_IRR_ANIM_FPS \ + "IMPORT_IRR_ANIM_FPS" + + +// --------------------------------------------------------------------------- +/** @brief Ogre Importer will try to load this Materialfile. + * + * Ogre Meshes contain only the MaterialName, not the MaterialFile. If there + * is no material file with the same name as the material, Ogre Importer will + * try to load this file and search the material in it. + *
    + * Property type: String. Default value: guessed. + */ +#define AI_CONFIG_IMPORT_OGRE_MATERIAL_FILE "IMPORT_OGRE_MATERIAL_FILE" + + +// --------------------------------------------------------------------------- +/** @brief Ogre Importer detect the texture usage from its filename + * + * Normally, a texture is loaded as a colormap, if no target is specified in the + * materialfile. Is this switch is enabled, texture names ending with _n, _l, _s + * are used as normalmaps, lightmaps or specularmaps. + *
    + * Property type: Bool. Default value: false. + */ +#define AI_CONFIG_IMPORT_OGRE_TEXTURETYPE_FROM_FILENAME "IMPORT_OGRE_TEXTURETYPE_FROM_FILENAME" + + + +// --------------------------------------------------------------------------- +/** @brief Specifies whether the IFC loader skips over IfcSpace elements. + * + * IfcSpace elements (and their geometric representations) are used to + * represent, well, free space in a building storey.
    + * Property type: Bool. Default value: true. + */ +#define AI_CONFIG_IMPORT_IFC_SKIP_SPACE_REPRESENTATIONS "IMPORT_IFC_SKIP_SPACE_REPRESENTATIONS" + + +// --------------------------------------------------------------------------- +/** @brief Specifies whether the IFC loader skips over + * shape representations of type 'Curve2D'. + * + * A lot of files contain both a faceted mesh representation and a outline + * with a presentation type of 'Curve2D'. Currently Assimp doesn't convert those, + * so turning this option off just clutters the log with errors.
    + * Property type: Bool. Default value: true. + */ +#define AI_CONFIG_IMPORT_IFC_SKIP_CURVE_REPRESENTATIONS "IMPORT_IFC_SKIP_CURVE_REPRESENTATIONS" + +// --------------------------------------------------------------------------- +/** @brief Specifies whether the IFC loader will use its own, custom triangulation + * algorithm to triangulate wall and floor meshes. + * + * If this property is set to false, walls will be either triangulated by + * #aiProcess_Triangulate or will be passed through as huge polygons with + * faked holes (i.e. holes that are connected with the outer boundary using + * a dummy edge). It is highly recommended to set this property to true + * if you want triangulated data because #aiProcess_Triangulate is known to + * have problems with the kind of polygons that the IFC loader spits out for + * complicated meshes. + * Property type: Bool. Default value: true. + */ +#define AI_CONFIG_IMPORT_IFC_CUSTOM_TRIANGULATION "IMPORT_IFC_CUSTOM_TRIANGULATION" + +#endif // !! AI_CONFIG_H_INC diff --git a/Lib/Include/assimp/defs.h b/Lib/Include/assimp/defs.h new file mode 100644 index 0000000..86fbf95 --- /dev/null +++ b/Lib/Include/assimp/defs.h @@ -0,0 +1,259 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2012, assimp team + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following +conditions are met: + +* Redistributions of source code must retain the above + copyright notice, this list of conditions and the + following disclaimer. + +* Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other + materials provided with the distribution. + +* Neither the name of the assimp team, nor the names of its + contributors may be used to endorse or promote products + derived from this software without specific prior + written permission of the assimp team. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"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 COPYRIGHT +OWNER OR CONTRIBUTORS 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. +--------------------------------------------------------------------------- +*/ + +/** @file aiDefines.h + * @brief Assimp build configuration setup. See the notes in the comment + * blocks to find out how to customize _your_ Assimp build. + */ + +#ifndef INCLUDED_AI_DEFINES_H +#define INCLUDED_AI_DEFINES_H + + ////////////////////////////////////////////////////////////////////////// + /* Define ASSIMP_BUILD_NO_XX_IMPORTER to disable a specific + * file format loader. The loader is be excluded from the + * build in this case. 'XX' stands for the most common file + * extension of the file format. E.g.: + * ASSIMP_BUILD_NO_X_IMPORTER disables the X loader. + * + * If you're unsure about that, take a look at the implementation of the + * import plugin you wish to disable. You'll find the right define in the + * first lines of the corresponding unit. + * + * Other (mixed) configuration switches are listed here: + * ASSIMP_BUILD_NO_COMPRESSED_X + * - Disable support for compressed X files + * ASSIMP_BUILD_NO_COMPRESSED_BLEND + * - Disable support for compressed Blender files*/ + ////////////////////////////////////////////////////////////////////////// + +#ifndef ASSIMP_BUILD_NO_COMPRESSED_X +# define ASSIMP_BUILD_NEED_Z_INFLATE +#endif + +#ifndef ASSIMP_BUILD_NO_COMPRESSED_BLEND +# define ASSIMP_BUILD_NEED_Z_INFLATE +#endif + + ////////////////////////////////////////////////////////////////////////// + /* Define ASSIMP_BUILD_NO_XX_PROCESS to disable a specific + * post processing step. This is the current list of process names ('XX'): + * CALCTANGENTS + * JOINVERTICES + * TRIANGULATE + * GENFACENORMALS + * GENVERTEXNORMALS + * REMOVEVC + * SPLITLARGEMESHES + * PRETRANSFORMVERTICES + * LIMITBONEWEIGHTS + * VALIDATEDS + * IMPROVECACHELOCALITY + * FIXINFACINGNORMALS + * REMOVE_REDUNDANTMATERIALS + * OPTIMIZEGRAPH + * SORTBYPTYPE + * FINDINVALIDDATA + * TRANSFORMTEXCOORDS + * GENUVCOORDS + * ENTITYMESHBUILDER + * MAKELEFTHANDED + * FLIPUVS + * FLIPWINDINGORDER + * OPTIMIZEMESHES + * OPTIMIZEANIMS + * OPTIMIZEGRAPH + * GENENTITYMESHES + * FIXTEXTUREPATHS */ + ////////////////////////////////////////////////////////////////////////// + +#ifdef _MSC_VER +# undef ASSIMP_API + + ////////////////////////////////////////////////////////////////////////// + /* Define 'ASSIMP_BUILD_DLL_EXPORT' to build a DLL of the library */ + ////////////////////////////////////////////////////////////////////////// +# ifdef ASSIMP_BUILD_DLL_EXPORT +# define ASSIMP_API __declspec(dllexport) +# define ASSIMP_API_WINONLY __declspec(dllexport) +# pragma warning (disable : 4251) + + ////////////////////////////////////////////////////////////////////////// + /* Define 'ASSIMP_DLL' before including Assimp to link to ASSIMP in + * an external DLL under Windows. Default is static linkage. */ + ////////////////////////////////////////////////////////////////////////// +# elif (defined ASSIMP_DLL) +# define ASSIMP_API __declspec(dllimport) +# define ASSIMP_API_WINONLY __declspec(dllimport) +# else +# define ASSIMP_API +# define ASSIMP_API_WINONLY +# endif + + /* Force the compiler to inline a function, if possible + */ +# define AI_FORCE_INLINE __forceinline + + /* Tells the compiler that a function never returns. Used in code analysis + * to skip dead paths (e.g. after an assertion evaluated to false). */ +# define AI_WONT_RETURN __declspec(noreturn) +#else + +# define AI_WONT_RETURN + +# define ASSIMP_API __attribute__ ((visibility("default"))) +# define ASSIMP_API_WINONLY +# define AI_FORCE_INLINE inline +#endif // (defined _MSC_VER) + +#ifdef __cplusplus + /* No explicit 'struct' and 'enum' tags for C++, this keeps showing up + * in doxydocs. + */ +# define C_STRUCT +# define C_ENUM +#else + ////////////////////////////////////////////////////////////////////////// + /* To build the documentation, make sure ASSIMP_DOXYGEN_BUILD + * is defined by Doxygen's preprocessor. The corresponding + * entries in the DOXYFILE are: */ + ////////////////////////////////////////////////////////////////////////// +#if 0 + ENABLE_PREPROCESSING = YES + MACRO_EXPANSION = YES + EXPAND_ONLY_PREDEF = YES + SEARCH_INCLUDES = YES + INCLUDE_PATH = + INCLUDE_FILE_PATTERNS = + PREDEFINED = ASSIMP_DOXYGEN_BUILD=1 + EXPAND_AS_DEFINED = C_STRUCT C_ENUM + SKIP_FUNCTION_MACROS = YES +#endif + ////////////////////////////////////////////////////////////////////////// + /* Doxygen gets confused if we use c-struct typedefs to avoid + * the explicit 'struct' notation. This trick here has the same + * effect as the TYPEDEF_HIDES_STRUCT option, but we don't need + * to typedef all structs/enums. */ + ////////////////////////////////////////////////////////////////////////// +# if (defined ASSIMP_DOXYGEN_BUILD) +# define C_STRUCT +# define C_ENUM +# else +# define C_STRUCT struct +# define C_ENUM enum +# endif +#endif + +#if (defined(__BORLANDC__) || defined (__BCPLUSPLUS__)) +#error Currently, Borland is unsupported. Feel free to port Assimp. + +// "W8059 Packgr÷že der Struktur ge„ndert" + +#endif + ////////////////////////////////////////////////////////////////////////// + /* Define 'ASSIMP_BUILD_BOOST_WORKAROUND' to compile assimp + * without boost. This is done by using a few workaround + * classes and brings some limitations (e.g. some logging won't be done, + * the library won't utilize threads or be threadsafe at all). + * This implies the 'ASSIMP_BUILD_SINGLETHREADED' setting. */ + ////////////////////////////////////////////////////////////////////////// +#ifdef ASSIMP_BUILD_BOOST_WORKAROUND + + // threading support requires boost +#ifndef ASSIMP_BUILD_SINGLETHREADED +# define ASSIMP_BUILD_SINGLETHREADED +#endif + +#endif // !! ASSIMP_BUILD_BOOST_WORKAROUND + + ////////////////////////////////////////////////////////////////////////// + /* Define ASSIMP_BUILD_SINGLETHREADED to compile assimp + * without threading support. The library doesn't utilize + * threads then and is itself not threadsafe. + * If this flag is specified boost::threads is *not* required. */ + ////////////////////////////////////////////////////////////////////////// +#ifndef ASSIMP_BUILD_SINGLETHREADED +# define ASSIMP_BUILD_SINGLETHREADED +#endif + +#ifndef ASSIMP_BUILD_SINGLETHREADED +# define AI_C_THREADSAFE +#endif // !! ASSIMP_BUILD_SINGLETHREADED + +#ifdef _DEBUG +# define ASSIMP_BUILD_DEBUG +#endif + + ////////////////////////////////////////////////////////////////////////// + /* Useful constants */ + ////////////////////////////////////////////////////////////////////////// + +/* This is PI. Hi PI. */ +#define AI_MATH_PI (3.141592653589793238462643383279 ) +#define AI_MATH_TWO_PI (AI_MATH_PI * 2.0) +#define AI_MATH_HALF_PI (AI_MATH_PI * 0.5) + +/* And this is to avoid endless casts to float */ +#define AI_MATH_PI_F (3.1415926538f) +#define AI_MATH_TWO_PI_F (AI_MATH_PI_F * 2.0f) +#define AI_MATH_HALF_PI_F (AI_MATH_PI_F * 0.5f) + +/* Tiny macro to convert from radians to degrees and back */ +#define AI_DEG_TO_RAD(x) (x*0.0174532925f) +#define AI_RAD_TO_DEG(x) (x*57.2957795f) + +/* Support for big-endian builds */ +#if defined(__BYTE_ORDER__) +# if (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) +# if !defined(__BIG_ENDIAN__) +# define __BIG_ENDIAN__ +# endif +# else /* little endian */ +# if defined (__BIG_ENDIAN__) +# undef __BIG_ENDIAN__ +# endif +# endif +#endif +#if defined(__BIG_ENDIAN__) +# define AI_BUILD_BIG_ENDIAN +#endif + +#endif // !! INCLUDED_AI_DEFINES_H diff --git a/Lib/Include/assimp/importerdesc.h b/Lib/Include/assimp/importerdesc.h new file mode 100644 index 0000000..0d93c3f --- /dev/null +++ b/Lib/Include/assimp/importerdesc.h @@ -0,0 +1,136 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2012, assimp team + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following +conditions are met: + +* Redistributions of source code must retain the above + copyright notice, this list of conditions and the + following disclaimer. + +* Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other + materials provided with the distribution. + +* Neither the name of the assimp team, nor the names of its + contributors may be used to endorse or promote products + derived from this software without specific prior + written permission of the assimp team. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"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 COPYRIGHT +OWNER OR CONTRIBUTORS 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. +--------------------------------------------------------------------------- +*/ + +/** @file importerdesc.h + * @brief #aiImporterFlags, aiImporterDesc implementation. + */ +#ifndef INCLUDED_AI_IMPORTER_DESC_H +#define INCLUDED_AI_IMPORTER_DESC_H + + +/** Mixed set of flags for #aiImporterDesc, indicating some features + * common to many importers*/ +enum aiImporterFlags +{ + /** Indicates that there is a textual encoding of the + * file format; and that it is supported.*/ + aiImporterFlags_SupportTextFlavour = 0x1, + + /** Indicates that there is a binary encoding of the + * file format; and that it is supported.*/ + aiImporterFlags_SupportBinaryFlavour = 0x2, + + /** Indicates that there is a compressed encoding of the + * file format; and that it is supported.*/ + aiImporterFlags_SupportCompressedFlavour = 0x4, + + /** Indicates that the importer reads only a very particular + * subset of the file format. This happens commonly for + * declarative or procedural formats which cannot easily + * be mapped to #aiScene */ + aiImporterFlags_LimitedSupport = 0x8, + + /** Indicates that the importer is highly experimental and + * should be used with care. This only happens for trunk + * (i.e. SVN) versions, experimental code is not included + * in releases. */ + aiImporterFlags_Experimental = 0x10, +}; + + +/** Meta information about a particular importer. Importers need to fill + * this structure, but they can freely decide how talkative they are. + * A common use case for loader meta info is a user interface + * in which the user can choose between various import/export file + * formats. Building such an UI by hand means a lot of maintenance + * as importers/exporters are added to Assimp, so it might be useful + * to have a common mechanism to query some rough importer + * characteristics. */ +struct aiImporterDesc +{ + /** Full name of the importer (i.e. Blender3D importer)*/ + const char* mName; + + /** Original author (left blank if unknown or whole assimp team) */ + const char* mAuthor; + + /** Current maintainer, left blank if the author maintains */ + const char* mMaintainer; + + /** Implementation comments, i.e. unimplemented features*/ + const char* mComments; + + /** Any combination of the #aiLoaderFlags enumerated values. + These flags indicate some characteristics common to many + importers. */ + unsigned int mFlags; + + /** Minimum format version that can be loaded im major.minor format, + both are set to 0 if there is either no version scheme + or if the loader doesn't care. */ + unsigned int mMinMajor; + unsigned int mMinMinor; + + /** Maximum format version that can be loaded im major.minor format, + both are set to 0 if there is either no version scheme + or if the loader doesn't care. Loaders that expect to be + forward-compatible to potential future format versions should + indicate zero, otherwise they should specify the current + maximum version.*/ + unsigned int mMaxMajor; + unsigned int mMaxMinor; + + /** List of file extensions this importer can handle. + List entries are separated by space characters. + All entries are lower case without a leading dot (i.e. + "xml dae" would be a valid value. Note that multiple + importers may respond to the same file extension - + assimp calls all importers in the order in which they + are registered and each importer gets the opportunity + to load the file until one importer "claims" the file. Apart + from file extension checks, importers typically use + other methods to quickly reject files (i.e. magic + words) so this does not mean that common or generic + file extensions such as XML would be tediously slow. */ + const char* mFileExtensions; +}; + +#endif diff --git a/Lib/Include/assimp/light.h b/Lib/Include/assimp/light.h new file mode 100644 index 0000000..64a21aa --- /dev/null +++ b/Lib/Include/assimp/light.h @@ -0,0 +1,233 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2012, assimp team + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following +conditions are met: + +* Redistributions of source code must retain the above + copyright notice, this list of conditions and the + following disclaimer. + +* Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other + materials provided with the distribution. + +* Neither the name of the assimp team, nor the names of its + contributors may be used to endorse or promote products + derived from this software without specific prior + written permission of the assimp team. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"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 COPYRIGHT +OWNER OR CONTRIBUTORS 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. +--------------------------------------------------------------------------- +*/ + +/** @file light.h + * @brief Defines the aiLight data structure + */ + +#ifndef __AI_LIGHT_H_INC__ +#define __AI_LIGHT_H_INC__ + +#include "types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// --------------------------------------------------------------------------- +/** Enumerates all supported types of light sources. + */ +enum aiLightSourceType +{ + aiLightSource_UNDEFINED = 0x0, + + //! A directional light source has a well-defined direction + //! but is infinitely far away. That's quite a good + //! approximation for sun light. + aiLightSource_DIRECTIONAL = 0x1, + + //! A point light source has a well-defined position + //! in space but no direction - it emits light in all + //! directions. A normal bulb is a point light. + aiLightSource_POINT = 0x2, + + //! A spot light source emits light in a specific + //! angle. It has a position and a direction it is pointing to. + //! A good example for a spot light is a light spot in + //! sport arenas. + aiLightSource_SPOT = 0x3, + + + /** This value is not used. It is just there to force the + * compiler to map this enum to a 32 Bit integer. + */ +#ifndef SWIG + _aiLightSource_Force32Bit = 0x9fffffff +#endif +}; + +// --------------------------------------------------------------------------- +/** Helper structure to describe a light source. + * + * Assimp supports multiple sorts of light sources, including + * directional, point and spot lights. All of them are defined with just + * a single structure and distinguished by their parameters. + * Note - some file formats (such as 3DS, ASE) export a "target point" - + * the point a spot light is looking at (it can even be animated). Assimp + * writes the target point as a subnode of a spotlights's main node, + * called ".Target". However, this is just additional information + * then, the transformation tracks of the main node make the + * spot light already point in the right direction. +*/ +struct aiLight +{ + /** The name of the light source. + * + * There must be a node in the scenegraph with the same name. + * This node specifies the position of the light in the scene + * hierarchy and can be animated. + */ + C_STRUCT aiString mName; + + /** The type of the light source. + * + * aiLightSource_UNDEFINED is not a valid value for this member. + */ + C_ENUM aiLightSourceType mType; + + /** Position of the light source in space. Relative to the + * transformation of the node corresponding to the light. + * + * The position is undefined for directional lights. + */ + C_STRUCT aiVector3D mPosition; + + /** Direction of the light source in space. Relative to the + * transformation of the node corresponding to the light. + * + * The direction is undefined for point lights. The vector + * may be normalized, but it needn't. + */ + C_STRUCT aiVector3D mDirection; + + /** Constant light attenuation factor. + * + * The intensity of the light source at a given distance 'd' from + * the light's position is + * @code + * Atten = 1/( att0 + att1 * d + att2 * d*d) + * @endcode + * This member corresponds to the att0 variable in the equation. + * Naturally undefined for directional lights. + */ + float mAttenuationConstant; + + /** Linear light attenuation factor. + * + * The intensity of the light source at a given distance 'd' from + * the light's position is + * @code + * Atten = 1/( att0 + att1 * d + att2 * d*d) + * @endcode + * This member corresponds to the att1 variable in the equation. + * Naturally undefined for directional lights. + */ + float mAttenuationLinear; + + /** Quadratic light attenuation factor. + * + * The intensity of the light source at a given distance 'd' from + * the light's position is + * @code + * Atten = 1/( att0 + att1 * d + att2 * d*d) + * @endcode + * This member corresponds to the att2 variable in the equation. + * Naturally undefined for directional lights. + */ + float mAttenuationQuadratic; + + /** Diffuse color of the light source + * + * The diffuse light color is multiplied with the diffuse + * material color to obtain the final color that contributes + * to the diffuse shading term. + */ + C_STRUCT aiColor3D mColorDiffuse; + + /** Specular color of the light source + * + * The specular light color is multiplied with the specular + * material color to obtain the final color that contributes + * to the specular shading term. + */ + C_STRUCT aiColor3D mColorSpecular; + + /** Ambient color of the light source + * + * The ambient light color is multiplied with the ambient + * material color to obtain the final color that contributes + * to the ambient shading term. Most renderers will ignore + * this value it, is just a remaining of the fixed-function pipeline + * that is still supported by quite many file formats. + */ + C_STRUCT aiColor3D mColorAmbient; + + /** Inner angle of a spot light's light cone. + * + * The spot light has maximum influence on objects inside this + * angle. The angle is given in radians. It is 2PI for point + * lights and undefined for directional lights. + */ + float mAngleInnerCone; + + /** Outer angle of a spot light's light cone. + * + * The spot light does not affect objects outside this angle. + * The angle is given in radians. It is 2PI for point lights and + * undefined for directional lights. The outer angle must be + * greater than or equal to the inner angle. + * It is assumed that the application uses a smooth + * interpolation between the inner and the outer cone of the + * spot light. + */ + float mAngleOuterCone; + +#ifdef __cplusplus + + aiLight() + : mType (aiLightSource_UNDEFINED) + , mAttenuationConstant (0.f) + , mAttenuationLinear (1.f) + , mAttenuationQuadratic (0.f) + , mAngleInnerCone ((float)AI_MATH_TWO_PI) + , mAngleOuterCone ((float)AI_MATH_TWO_PI) + { + } + +#endif +}; + +#ifdef __cplusplus +} +#endif + + +#endif // !! __AI_LIGHT_H_INC__ diff --git a/Lib/Include/assimp/material.h b/Lib/Include/assimp/material.h new file mode 100644 index 0000000..39844de --- /dev/null +++ b/Lib/Include/assimp/material.h @@ -0,0 +1,1491 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2012, assimp team + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following +conditions are met: + +* Redistributions of source code must retain the above + copyright notice, this list of conditions and the + following disclaimer. + +* Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other + materials provided with the distribution. + +* Neither the name of the assimp team, nor the names of its + contributors may be used to endorse or promote products + derived from this software without specific prior + written permission of the assimp team. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"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 COPYRIGHT +OWNER OR CONTRIBUTORS 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. +--------------------------------------------------------------------------- +*/ + +/** @file material.h + * @brief Defines the material system of the library + */ + +#ifndef AI_MATERIAL_H_INC +#define AI_MATERIAL_H_INC + +#include "types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// Name for default materials (2nd is used if meshes have UV coords) +#define AI_DEFAULT_MATERIAL_NAME "DefaultMaterial" + +// --------------------------------------------------------------------------- +/** @brief Defines how the Nth texture of a specific type is combined with + * the result of all previous layers. + * + * Example (left: key, right: value):
    + * @code + * DiffColor0 - gray + * DiffTextureOp0 - aiTextureOpMultiply + * DiffTexture0 - tex1.png + * DiffTextureOp0 - aiTextureOpAdd + * DiffTexture1 - tex2.png + * @endcode + * Written as equation, the final diffuse term for a specific pixel would be: + * @code + * diffFinal = DiffColor0 * sampleTex(DiffTexture0,UV0) + + * sampleTex(DiffTexture1,UV0) * diffContrib; + * @endcode + * where 'diffContrib' is the intensity of the incoming light for that pixel. + */ +enum aiTextureOp +{ + /** T = T1 * T2 */ + aiTextureOp_Multiply = 0x0, + + /** T = T1 + T2 */ + aiTextureOp_Add = 0x1, + + /** T = T1 - T2 */ + aiTextureOp_Subtract = 0x2, + + /** T = T1 / T2 */ + aiTextureOp_Divide = 0x3, + + /** T = (T1 + T2) - (T1 * T2) */ + aiTextureOp_SmoothAdd = 0x4, + + /** T = T1 + (T2-0.5) */ + aiTextureOp_SignedAdd = 0x5, + + + /** @cond never + * This value is not used. It forces the compiler to use at least + * 32 Bit integers to represent this enum. + */ +#ifndef SWIG + _aiTextureOp_Force32Bit = 0x9fffffff +#endif + //! @endcond +}; + +// --------------------------------------------------------------------------- +/** @brief Defines how UV coordinates outside the [0...1] range are handled. + * + * Commonly refered to as 'wrapping mode'. + */ +enum aiTextureMapMode +{ + /** A texture coordinate u|v is translated to u%1|v%1 + */ + aiTextureMapMode_Wrap = 0x0, + + /** Texture coordinates outside [0...1] + * are clamped to the nearest valid value. + */ + aiTextureMapMode_Clamp = 0x1, + + /** If the texture coordinates for a pixel are outside [0...1] + * the texture is not applied to that pixel + */ + aiTextureMapMode_Decal = 0x3, + + /** A texture coordinate u|v becomes u%1|v%1 if (u-(u%1))%2 is zero and + * 1-(u%1)|1-(v%1) otherwise + */ + aiTextureMapMode_Mirror = 0x2, + + /** @cond never + * This value is not used. It forces the compiler to use at least + * 32 Bit integers to represent this enum. + */ +#ifndef SWIG + _aiTextureMapMode_Force32Bit = 0x9fffffff +#endif + //! @endcond +}; + +// --------------------------------------------------------------------------- +/** @brief Defines how the mapping coords for a texture are generated. + * + * Real-time applications typically require full UV coordinates, so the use of + * the aiProcess_GenUVCoords step is highly recommended. It generates proper + * UV channels for non-UV mapped objects, as long as an accurate description + * how the mapping should look like (e.g spherical) is given. + * See the #AI_MATKEY_MAPPING property for more details. + */ +enum aiTextureMapping +{ + /** The mapping coordinates are taken from an UV channel. + * + * The #AI_MATKEY_UVWSRC key specifies from which UV channel + * the texture coordinates are to be taken from (remember, + * meshes can have more than one UV channel). + */ + aiTextureMapping_UV = 0x0, + + /** Spherical mapping */ + aiTextureMapping_SPHERE = 0x1, + + /** Cylindrical mapping */ + aiTextureMapping_CYLINDER = 0x2, + + /** Cubic mapping */ + aiTextureMapping_BOX = 0x3, + + /** Planar mapping */ + aiTextureMapping_PLANE = 0x4, + + /** Undefined mapping. Have fun. */ + aiTextureMapping_OTHER = 0x5, + + + /** @cond never + * This value is not used. It forces the compiler to use at least + * 32 Bit integers to represent this enum. + */ +#ifndef SWIG + _aiTextureMapping_Force32Bit = 0x9fffffff +#endif + //! @endcond +}; + +// --------------------------------------------------------------------------- +/** @brief Defines the purpose of a texture + * + * This is a very difficult topic. Different 3D packages support different + * kinds of textures. For very common texture types, such as bumpmaps, the + * rendering results depend on implementation details in the rendering + * pipelines of these applications. Assimp loads all texture references from + * the model file and tries to determine which of the predefined texture + * types below is the best choice to match the original use of the texture + * as closely as possible.
    + * + * In content pipelines you'll usually define how textures have to be handled, + * and the artists working on models have to conform to this specification, + * regardless which 3D tool they're using. + */ +enum aiTextureType +{ + /** Dummy value. + * + * No texture, but the value to be used as 'texture semantic' + * (#aiMaterialProperty::mSemantic) for all material properties + * *not* related to textures. + */ + aiTextureType_NONE = 0x0, + + + + /** The texture is combined with the result of the diffuse + * lighting equation. + */ + aiTextureType_DIFFUSE = 0x1, + + /** The texture is combined with the result of the specular + * lighting equation. + */ + aiTextureType_SPECULAR = 0x2, + + /** The texture is combined with the result of the ambient + * lighting equation. + */ + aiTextureType_AMBIENT = 0x3, + + /** The texture is added to the result of the lighting + * calculation. It isn't influenced by incoming light. + */ + aiTextureType_EMISSIVE = 0x4, + + /** The texture is a height map. + * + * By convention, higher gray-scale values stand for + * higher elevations from the base height. + */ + aiTextureType_HEIGHT = 0x5, + + /** The texture is a (tangent space) normal-map. + * + * Again, there are several conventions for tangent-space + * normal maps. Assimp does (intentionally) not + * distinguish here. + */ + aiTextureType_NORMALS = 0x6, + + /** The texture defines the glossiness of the material. + * + * The glossiness is in fact the exponent of the specular + * (phong) lighting equation. Usually there is a conversion + * function defined to map the linear color values in the + * texture to a suitable exponent. Have fun. + */ + aiTextureType_SHININESS = 0x7, + + /** The texture defines per-pixel opacity. + * + * Usually 'white' means opaque and 'black' means + * 'transparency'. Or quite the opposite. Have fun. + */ + aiTextureType_OPACITY = 0x8, + + /** Displacement texture + * + * The exact purpose and format is application-dependent. + * Higher color values stand for higher vertex displacements. + */ + aiTextureType_DISPLACEMENT = 0x9, + + /** Lightmap texture (aka Ambient Occlusion) + * + * Both 'Lightmaps' and dedicated 'ambient occlusion maps' are + * covered by this material property. The texture contains a + * scaling value for the final color value of a pixel. Its + * intensity is not affected by incoming light. + */ + aiTextureType_LIGHTMAP = 0xA, + + /** Reflection texture + * + * Contains the color of a perfect mirror reflection. + * Rarely used, almost never for real-time applications. + */ + aiTextureType_REFLECTION = 0xB, + + /** Unknown texture + * + * A texture reference that does not match any of the definitions + * above is considered to be 'unknown'. It is still imported, + * but is excluded from any further postprocessing. + */ + aiTextureType_UNKNOWN = 0xC, + + + /** @cond never + * This value is not used. It forces the compiler to use at least + * 32 Bit integers to represent this enum. + */ +#ifndef SWIG + _aiTextureType_Force32Bit = 0x9fffffff +#endif + //! @endcond +}; + +#define AI_TEXTURE_TYPE_MAX aiTextureType_UNKNOWN + +// --------------------------------------------------------------------------- +/** @brief Defines all shading models supported by the library + * + * The list of shading modes has been taken from Blender. + * See Blender documentation for more information. The API does + * not distinguish between "specular" and "diffuse" shaders (thus the + * specular term for diffuse shading models like Oren-Nayar remains + * undefined).
    + * Again, this value is just a hint. Assimp tries to select the shader whose + * most common implementation matches the original rendering results of the + * 3D modeller which wrote a particular model as closely as possible. + */ +enum aiShadingMode +{ + /** Flat shading. Shading is done on per-face base, + * diffuse only. Also known as 'faceted shading'. + */ + aiShadingMode_Flat = 0x1, + + /** Simple Gouraud shading. + */ + aiShadingMode_Gouraud = 0x2, + + /** Phong-Shading - + */ + aiShadingMode_Phong = 0x3, + + /** Phong-Blinn-Shading + */ + aiShadingMode_Blinn = 0x4, + + /** Toon-Shading per pixel + * + * Also known as 'comic' shader. + */ + aiShadingMode_Toon = 0x5, + + /** OrenNayar-Shading per pixel + * + * Extension to standard Lambertian shading, taking the + * roughness of the material into account + */ + aiShadingMode_OrenNayar = 0x6, + + /** Minnaert-Shading per pixel + * + * Extension to standard Lambertian shading, taking the + * "darkness" of the material into account + */ + aiShadingMode_Minnaert = 0x7, + + /** CookTorrance-Shading per pixel + * + * Special shader for metallic surfaces. + */ + aiShadingMode_CookTorrance = 0x8, + + /** No shading at all. Constant light influence of 1.0. + */ + aiShadingMode_NoShading = 0x9, + + /** Fresnel shading + */ + aiShadingMode_Fresnel = 0xa, + + + /** @cond never + * This value is not used. It forces the compiler to use at least + * 32 Bit integers to represent this enum. + */ +#ifndef SWIG + _aiShadingMode_Force32Bit = 0x9fffffff +#endif + //! @endcond +}; + + +// --------------------------------------------------------------------------- +/** @brief Defines some mixed flags for a particular texture. + * + * Usually you'll instruct your cg artists how textures have to look like ... + * and how they will be processed in your application. However, if you use + * Assimp for completely generic loading purposes you might also need to + * process these flags in order to display as many 'unknown' 3D models as + * possible correctly. + * + * This corresponds to the #AI_MATKEY_TEXFLAGS property. +*/ +enum aiTextureFlags +{ + /** The texture's color values have to be inverted (componentwise 1-n) + */ + aiTextureFlags_Invert = 0x1, + + /** Explicit request to the application to process the alpha channel + * of the texture. + * + * Mutually exclusive with #aiTextureFlags_IgnoreAlpha. These + * flags are set if the library can say for sure that the alpha + * channel is used/is not used. If the model format does not + * define this, it is left to the application to decide whether + * the texture alpha channel - if any - is evaluated or not. + */ + aiTextureFlags_UseAlpha = 0x2, + + /** Explicit request to the application to ignore the alpha channel + * of the texture. + * + * Mutually exclusive with #aiTextureFlags_UseAlpha. + */ + aiTextureFlags_IgnoreAlpha = 0x4, + + /** @cond never + * This value is not used. It forces the compiler to use at least + * 32 Bit integers to represent this enum. + */ +#ifndef SWIG + _aiTextureFlags_Force32Bit = 0x9fffffff +#endif + //! @endcond +}; + + +// --------------------------------------------------------------------------- +/** @brief Defines alpha-blend flags. + * + * If you're familiar with OpenGL or D3D, these flags aren't new to you. + * They define *how* the final color value of a pixel is computed, basing + * on the previous color at that pixel and the new color value from the + * material. + * The blend formula is: + * @code + * SourceColor * SourceBlend + DestColor * DestBlend + * @endcode + * where is the previous color in the framebuffer at this + * position and is the material colro before the transparency + * calculation.
    + * This corresponds to the #AI_MATKEY_BLEND_FUNC property. +*/ +enum aiBlendMode +{ + /** + * Formula: + * @code + * SourceColor*SourceAlpha + DestColor*(1-SourceAlpha) + * @endcode + */ + aiBlendMode_Default = 0x0, + + /** Additive blending + * + * Formula: + * @code + * SourceColor*1 + DestColor*1 + * @endcode + */ + aiBlendMode_Additive = 0x1, + + // we don't need more for the moment, but we might need them + // in future versions ... + + /** @cond never + * This value is not used. It forces the compiler to use at least + * 32 Bit integers to represent this enum. + */ +#ifndef SWIG + _aiBlendMode_Force32Bit = 0x9fffffff +#endif + //! @endcond +}; + + +#include "./Compiler/pushpack1.h" + +// --------------------------------------------------------------------------- +/** @brief Defines how an UV channel is transformed. + * + * This is just a helper structure for the #AI_MATKEY_UVTRANSFORM key. + * See its documentation for more details. + * + * Typically you'll want to build a matrix of this information. However, + * we keep separate scaling/translation/rotation values to make it + * easier to process and optimize UV transformations internally. + */ +struct aiUVTransform +{ + /** Translation on the u and v axes. + * + * The default value is (0|0). + */ + C_STRUCT aiVector2D mTranslation; + + /** Scaling on the u and v axes. + * + * The default value is (1|1). + */ + C_STRUCT aiVector2D mScaling; + + /** Rotation - in counter-clockwise direction. + * + * The rotation angle is specified in radians. The + * rotation center is 0.5f|0.5f. The default value + * 0.f. + */ + float mRotation; + + +#ifdef __cplusplus + aiUVTransform() + : mScaling (1.f,1.f) + , mRotation (0.f) + { + // nothing to be done here ... + } +#endif + +} PACK_STRUCT; + +#include "./Compiler/poppack1.h" + +//! @cond AI_DOX_INCLUDE_INTERNAL +// --------------------------------------------------------------------------- +/** @brief A very primitive RTTI system for the contents of material + * properties. + */ +enum aiPropertyTypeInfo +{ + /** Array of single-precision (32 Bit) floats + * + * It is possible to use aiGetMaterialInteger[Array]() (or the C++-API + * aiMaterial::Get()) to query properties stored in floating-point format. + * The material system performs the type conversion automatically. + */ + aiPTI_Float = 0x1, + + /** The material property is an aiString. + * + * Arrays of strings aren't possible, aiGetMaterialString() (or the + * C++-API aiMaterial::Get()) *must* be used to query a string property. + */ + aiPTI_String = 0x3, + + /** Array of (32 Bit) integers + * + * It is possible to use aiGetMaterialFloat[Array]() (or the C++-API + * aiMaterial::Get()) to query properties stored in integer format. + * The material system performs the type conversion automatically. + */ + aiPTI_Integer = 0x4, + + + /** Simple binary buffer, content undefined. Not convertible to anything. + */ + aiPTI_Buffer = 0x5, + + + /** This value is not used. It is just there to force the + * compiler to map this enum to a 32 Bit integer. + */ +#ifndef SWIG + _aiPTI_Force32Bit = 0x9fffffff +#endif +}; + +// --------------------------------------------------------------------------- +/** @brief Data structure for a single material property + * + * As an user, you'll probably never need to deal with this data structure. + * Just use the provided aiGetMaterialXXX() or aiMaterial::Get() family + * of functions to query material properties easily. Processing them + * manually is faster, but it is not the recommended way. It isn't worth + * the effort.
    + * Material property names follow a simple scheme: + * @code + * $ + * ? + * A public property, there must be corresponding AI_MATKEY_XXX define + * 2nd: Public, but ignored by the #aiProcess_RemoveRedundantMaterials + * post-processing step. + * ~ + * A temporary property for internal use. + * @endcode + * @see aiMaterial + */ +struct aiMaterialProperty +{ + /** Specifies the name of the property (key) + * Keys are generally case insensitive. + */ + C_STRUCT aiString mKey; + + /** Textures: Specifies their exact usage semantic. + * For non-texture properties, this member is always 0 + * (or, better-said, #aiTextureType_NONE). + */ + unsigned int mSemantic; + + /** Textures: Specifies the index of the texture. + * For non-texture properties, this member is always 0. + */ + unsigned int mIndex; + + /** Size of the buffer mData is pointing to, in bytes. + * This value may not be 0. + */ + unsigned int mDataLength; + + /** Type information for the property. + * + * Defines the data layout inside the data buffer. This is used + * by the library internally to perform debug checks and to + * utilize proper type conversions. + * (It's probably a hacky solution, but it works.) + */ + C_ENUM aiPropertyTypeInfo mType; + + /** Binary buffer to hold the property's value. + * The size of the buffer is always mDataLength. + */ + char* mData; + +#ifdef __cplusplus + + aiMaterialProperty() { + mData = NULL; + mIndex = mSemantic = 0; + } + + ~aiMaterialProperty() { + delete[] mData; + } + +#endif +}; +//! @endcond + +#ifdef __cplusplus +} // We need to leave the "C" block here to allow template member functions +#endif + +// --------------------------------------------------------------------------- +/** @brief Data structure for a material +* +* Material data is stored using a key-value structure. A single key-value +* pair is called a 'material property'. C++ users should use the provided +* member functions of aiMaterial to process material properties, C users +* have to stick with the aiMaterialGetXXX family of unbound functions. +* The library defines a set of standard keys (AI_MATKEY_XXX). +*/ +struct ASSIMP_API aiMaterial +{ + +#ifdef __cplusplus + +public: + + aiMaterial(); + ~aiMaterial(); + + // ------------------------------------------------------------------- + /** @brief Retrieve an array of Type values with a specific key + * from the material + * + * @param pKey Key to search for. One of the AI_MATKEY_XXX constants. + * @param type .. set by AI_MATKEY_XXX + * @param idx .. set by AI_MATKEY_XXX + * @param pOut Pointer to a buffer to receive the result. + * @param pMax Specifies the size of the given buffer, in Type's. + * Receives the number of values (not bytes!) read. + * NULL is a valid value for this parameter. + */ + template + aiReturn Get(const char* pKey,unsigned int type, + unsigned int idx, Type* pOut, unsigned int* pMax) const; + + // ------------------------------------------------------------------- + /** @brief Retrieve a Type value with a specific key + * from the material + * + * @param pKey Key to search for. One of the AI_MATKEY_XXX constants. + * @param type Specifies the type of the texture to be retrieved ( + * e.g. diffuse, specular, height map ...) + * @param idx Index of the texture to be retrieved. + * @param pOut Reference to receive the output value + */ + template + aiReturn Get(const char* pKey,unsigned int type, + unsigned int idx,Type& pOut) const; + + // ------------------------------------------------------------------- + /** Get the number of textures for a particular texture type. + * @param type Texture type to check for + * @return Number of textures for this type. + * @note A texture can be easily queried using #GetTexture() */ + unsigned int GetTextureCount(aiTextureType type) const; + + // ------------------------------------------------------------------- + /** Helper function to get all parameters pertaining to a + * particular texture slot from a material. + * + * This function is provided just for convenience, you could also + * read the single material properties manually. + * @param type Specifies the type of the texture to be retrieved ( + * e.g. diffuse, specular, height map ...) + * @param index Index of the texture to be retrieved. The function fails + * if there is no texture of that type with this index. + * #GetTextureCount() can be used to determine the number of textures + * per texture type. + * @param path Receives the path to the texture. + * NULL is a valid value. + * @param mapping The texture mapping. + * NULL is allowed as value. + * @param uvindex Receives the UV index of the texture. + * NULL is a valid value. + * @param blend Receives the blend factor for the texture + * NULL is a valid value. + * @param op Receives the texture operation to be performed between + * this texture and the previous texture. NULL is allowed as value. + * @param mapmode Receives the mapping modes to be used for the texture. + * The parameter may be NULL but if it is a valid pointer it MUST + * point to an array of 3 aiTextureMapMode's (one for each + * axis: UVW order (=XYZ)). + */ + // ------------------------------------------------------------------- + aiReturn GetTexture(aiTextureType type, + unsigned int index, + C_STRUCT aiString* path, + aiTextureMapping* mapping = NULL, + unsigned int* uvindex = NULL, + float* blend = NULL, + aiTextureOp* op = NULL, + aiTextureMapMode* mapmode = NULL) const; + + + // Setters + + + // ------------------------------------------------------------------------------ + /** @brief Add a property with a given key and type info to the material + * structure + * + * @param pInput Pointer to input data + * @param pSizeInBytes Size of input data + * @param pKey Key/Usage of the property (AI_MATKEY_XXX) + * @param type Set by the AI_MATKEY_XXX macro + * @param index Set by the AI_MATKEY_XXX macro + * @param pType Type information hint */ + aiReturn AddBinaryProperty (const void* pInput, + unsigned int pSizeInBytes, + const char* pKey, + unsigned int type , + unsigned int index , + aiPropertyTypeInfo pType); + + // ------------------------------------------------------------------------------ + /** @brief Add a string property with a given key and type info to the + * material structure + * + * @param pInput Input string + * @param pKey Key/Usage of the property (AI_MATKEY_XXX) + * @param type Set by the AI_MATKEY_XXX macro + * @param index Set by the AI_MATKEY_XXX macro */ + aiReturn AddProperty (const aiString* pInput, + const char* pKey, + unsigned int type = 0, + unsigned int index = 0); + + // ------------------------------------------------------------------------------ + /** @brief Add a property with a given key to the material structure + * @param pInput Pointer to the input data + * @param pNumValues Number of values in the array + * @param pKey Key/Usage of the property (AI_MATKEY_XXX) + * @param type Set by the AI_MATKEY_XXX macro + * @param index Set by the AI_MATKEY_XXX macro */ + template + aiReturn AddProperty (const TYPE* pInput, + unsigned int pNumValues, + const char* pKey, + unsigned int type = 0, + unsigned int index = 0); + + // ------------------------------------------------------------------------------ + /** @brief Remove a given key from the list. + * + * The function fails if the key isn't found + * @param pKey Key to be deleted */ + aiReturn RemoveProperty (const char* pKey, + unsigned int type = 0, + unsigned int index = 0); + + // ------------------------------------------------------------------------------ + /** @brief Removes all properties from the material. + * + * The data array remains allocated so adding new properties is quite fast. */ + void Clear(); + + // ------------------------------------------------------------------------------ + /** Copy the property list of a material + * @param pcDest Destination material + * @param pcSrc Source material + */ + static void CopyPropertyList(aiMaterial* pcDest, + const aiMaterial* pcSrc); + + +#endif + + /** List of all material properties loaded. */ + C_STRUCT aiMaterialProperty** mProperties; + + /** Number of properties in the data base */ + unsigned int mNumProperties; + + /** Storage allocated */ + unsigned int mNumAllocated; +}; + +// Go back to extern "C" again +#ifdef __cplusplus +extern "C" { +#endif + +// --------------------------------------------------------------------------- +#define AI_MATKEY_NAME "?mat.name",0,0 +#define AI_MATKEY_TWOSIDED "$mat.twosided",0,0 +#define AI_MATKEY_SHADING_MODEL "$mat.shadingm",0,0 +#define AI_MATKEY_ENABLE_WIREFRAME "$mat.wireframe",0,0 +#define AI_MATKEY_BLEND_FUNC "$mat.blend",0,0 +#define AI_MATKEY_OPACITY "$mat.opacity",0,0 +#define AI_MATKEY_BUMPSCALING "$mat.bumpscaling",0,0 +#define AI_MATKEY_SHININESS "$mat.shininess",0,0 +#define AI_MATKEY_REFLECTIVITY "$mat.reflectivity",0,0 +#define AI_MATKEY_SHININESS_STRENGTH "$mat.shinpercent",0,0 +#define AI_MATKEY_REFRACTI "$mat.refracti",0,0 +#define AI_MATKEY_COLOR_DIFFUSE "$clr.diffuse",0,0 +#define AI_MATKEY_COLOR_AMBIENT "$clr.ambient",0,0 +#define AI_MATKEY_COLOR_SPECULAR "$clr.specular",0,0 +#define AI_MATKEY_COLOR_EMISSIVE "$clr.emissive",0,0 +#define AI_MATKEY_COLOR_TRANSPARENT "$clr.transparent",0,0 +#define AI_MATKEY_COLOR_REFLECTIVE "$clr.reflective",0,0 +#define AI_MATKEY_GLOBAL_BACKGROUND_IMAGE "?bg.global",0,0 + +// --------------------------------------------------------------------------- +// Pure key names for all texture-related properties +//! @cond MATS_DOC_FULL +#define _AI_MATKEY_TEXTURE_BASE "$tex.file" +#define _AI_MATKEY_UVWSRC_BASE "$tex.uvwsrc" +#define _AI_MATKEY_TEXOP_BASE "$tex.op" +#define _AI_MATKEY_MAPPING_BASE "$tex.mapping" +#define _AI_MATKEY_TEXBLEND_BASE "$tex.blend" +#define _AI_MATKEY_MAPPINGMODE_U_BASE "$tex.mapmodeu" +#define _AI_MATKEY_MAPPINGMODE_V_BASE "$tex.mapmodev" +#define _AI_MATKEY_TEXMAP_AXIS_BASE "$tex.mapaxis" +#define _AI_MATKEY_UVTRANSFORM_BASE "$tex.uvtrafo" +#define _AI_MATKEY_TEXFLAGS_BASE "$tex.flags" +//! @endcond + +// --------------------------------------------------------------------------- +#define AI_MATKEY_TEXTURE(type, N) _AI_MATKEY_TEXTURE_BASE,type,N + +// For backward compatibility and simplicity +//! @cond MATS_DOC_FULL +#define AI_MATKEY_TEXTURE_DIFFUSE(N) \ + AI_MATKEY_TEXTURE(aiTextureType_DIFFUSE,N) + +#define AI_MATKEY_TEXTURE_SPECULAR(N) \ + AI_MATKEY_TEXTURE(aiTextureType_SPECULAR,N) + +#define AI_MATKEY_TEXTURE_AMBIENT(N) \ + AI_MATKEY_TEXTURE(aiTextureType_AMBIENT,N) + +#define AI_MATKEY_TEXTURE_EMISSIVE(N) \ + AI_MATKEY_TEXTURE(aiTextureType_EMISSIVE,N) + +#define AI_MATKEY_TEXTURE_NORMALS(N) \ + AI_MATKEY_TEXTURE(aiTextureType_NORMALS,N) + +#define AI_MATKEY_TEXTURE_HEIGHT(N) \ + AI_MATKEY_TEXTURE(aiTextureType_HEIGHT,N) + +#define AI_MATKEY_TEXTURE_SHININESS(N) \ + AI_MATKEY_TEXTURE(aiTextureType_SHININESS,N) + +#define AI_MATKEY_TEXTURE_OPACITY(N) \ + AI_MATKEY_TEXTURE(aiTextureType_OPACITY,N) + +#define AI_MATKEY_TEXTURE_DISPLACEMENT(N) \ + AI_MATKEY_TEXTURE(aiTextureType_DISPLACEMENT,N) + +#define AI_MATKEY_TEXTURE_LIGHTMAP(N) \ + AI_MATKEY_TEXTURE(aiTextureType_LIGHTMAP,N) + +#define AI_MATKEY_TEXTURE_REFLECTION(N) \ + AI_MATKEY_TEXTURE(aiTextureType_REFLECTION,N) + +//! @endcond + +// --------------------------------------------------------------------------- +#define AI_MATKEY_UVWSRC(type, N) _AI_MATKEY_UVWSRC_BASE,type,N + +// For backward compatibility and simplicity +//! @cond MATS_DOC_FULL +#define AI_MATKEY_UVWSRC_DIFFUSE(N) \ + AI_MATKEY_UVWSRC(aiTextureType_DIFFUSE,N) + +#define AI_MATKEY_UVWSRC_SPECULAR(N) \ + AI_MATKEY_UVWSRC(aiTextureType_SPECULAR,N) + +#define AI_MATKEY_UVWSRC_AMBIENT(N) \ + AI_MATKEY_UVWSRC(aiTextureType_AMBIENT,N) + +#define AI_MATKEY_UVWSRC_EMISSIVE(N) \ + AI_MATKEY_UVWSRC(aiTextureType_EMISSIVE,N) + +#define AI_MATKEY_UVWSRC_NORMALS(N) \ + AI_MATKEY_UVWSRC(aiTextureType_NORMALS,N) + +#define AI_MATKEY_UVWSRC_HEIGHT(N) \ + AI_MATKEY_UVWSRC(aiTextureType_HEIGHT,N) + +#define AI_MATKEY_UVWSRC_SHININESS(N) \ + AI_MATKEY_UVWSRC(aiTextureType_SHININESS,N) + +#define AI_MATKEY_UVWSRC_OPACITY(N) \ + AI_MATKEY_UVWSRC(aiTextureType_OPACITY,N) + +#define AI_MATKEY_UVWSRC_DISPLACEMENT(N) \ + AI_MATKEY_UVWSRC(aiTextureType_DISPLACEMENT,N) + +#define AI_MATKEY_UVWSRC_LIGHTMAP(N) \ + AI_MATKEY_UVWSRC(aiTextureType_LIGHTMAP,N) + +#define AI_MATKEY_UVWSRC_REFLECTION(N) \ + AI_MATKEY_UVWSRC(aiTextureType_REFLECTION,N) + +//! @endcond +// --------------------------------------------------------------------------- +#define AI_MATKEY_TEXOP(type, N) _AI_MATKEY_TEXOP_BASE,type,N + +// For backward compatibility and simplicity +//! @cond MATS_DOC_FULL +#define AI_MATKEY_TEXOP_DIFFUSE(N) \ + AI_MATKEY_TEXOP(aiTextureType_DIFFUSE,N) + +#define AI_MATKEY_TEXOP_SPECULAR(N) \ + AI_MATKEY_TEXOP(aiTextureType_SPECULAR,N) + +#define AI_MATKEY_TEXOP_AMBIENT(N) \ + AI_MATKEY_TEXOP(aiTextureType_AMBIENT,N) + +#define AI_MATKEY_TEXOP_EMISSIVE(N) \ + AI_MATKEY_TEXOP(aiTextureType_EMISSIVE,N) + +#define AI_MATKEY_TEXOP_NORMALS(N) \ + AI_MATKEY_TEXOP(aiTextureType_NORMALS,N) + +#define AI_MATKEY_TEXOP_HEIGHT(N) \ + AI_MATKEY_TEXOP(aiTextureType_HEIGHT,N) + +#define AI_MATKEY_TEXOP_SHININESS(N) \ + AI_MATKEY_TEXOP(aiTextureType_SHININESS,N) + +#define AI_MATKEY_TEXOP_OPACITY(N) \ + AI_MATKEY_TEXOP(aiTextureType_OPACITY,N) + +#define AI_MATKEY_TEXOP_DISPLACEMENT(N) \ + AI_MATKEY_TEXOP(aiTextureType_DISPLACEMENT,N) + +#define AI_MATKEY_TEXOP_LIGHTMAP(N) \ + AI_MATKEY_TEXOP(aiTextureType_LIGHTMAP,N) + +#define AI_MATKEY_TEXOP_REFLECTION(N) \ + AI_MATKEY_TEXOP(aiTextureType_REFLECTION,N) + +//! @endcond +// --------------------------------------------------------------------------- +#define AI_MATKEY_MAPPING(type, N) _AI_MATKEY_MAPPING_BASE,type,N + +// For backward compatibility and simplicity +//! @cond MATS_DOC_FULL +#define AI_MATKEY_MAPPING_DIFFUSE(N) \ + AI_MATKEY_MAPPING(aiTextureType_DIFFUSE,N) + +#define AI_MATKEY_MAPPING_SPECULAR(N) \ + AI_MATKEY_MAPPING(aiTextureType_SPECULAR,N) + +#define AI_MATKEY_MAPPING_AMBIENT(N) \ + AI_MATKEY_MAPPING(aiTextureType_AMBIENT,N) + +#define AI_MATKEY_MAPPING_EMISSIVE(N) \ + AI_MATKEY_MAPPING(aiTextureType_EMISSIVE,N) + +#define AI_MATKEY_MAPPING_NORMALS(N) \ + AI_MATKEY_MAPPING(aiTextureType_NORMALS,N) + +#define AI_MATKEY_MAPPING_HEIGHT(N) \ + AI_MATKEY_MAPPING(aiTextureType_HEIGHT,N) + +#define AI_MATKEY_MAPPING_SHININESS(N) \ + AI_MATKEY_MAPPING(aiTextureType_SHININESS,N) + +#define AI_MATKEY_MAPPING_OPACITY(N) \ + AI_MATKEY_MAPPING(aiTextureType_OPACITY,N) + +#define AI_MATKEY_MAPPING_DISPLACEMENT(N) \ + AI_MATKEY_MAPPING(aiTextureType_DISPLACEMENT,N) + +#define AI_MATKEY_MAPPING_LIGHTMAP(N) \ + AI_MATKEY_MAPPING(aiTextureType_LIGHTMAP,N) + +#define AI_MATKEY_MAPPING_REFLECTION(N) \ + AI_MATKEY_MAPPING(aiTextureType_REFLECTION,N) + +//! @endcond +// --------------------------------------------------------------------------- +#define AI_MATKEY_TEXBLEND(type, N) _AI_MATKEY_TEXBLEND_BASE,type,N + +// For backward compatibility and simplicity +//! @cond MATS_DOC_FULL +#define AI_MATKEY_TEXBLEND_DIFFUSE(N) \ + AI_MATKEY_TEXBLEND(aiTextureType_DIFFUSE,N) + +#define AI_MATKEY_TEXBLEND_SPECULAR(N) \ + AI_MATKEY_TEXBLEND(aiTextureType_SPECULAR,N) + +#define AI_MATKEY_TEXBLEND_AMBIENT(N) \ + AI_MATKEY_TEXBLEND(aiTextureType_AMBIENT,N) + +#define AI_MATKEY_TEXBLEND_EMISSIVE(N) \ + AI_MATKEY_TEXBLEND(aiTextureType_EMISSIVE,N) + +#define AI_MATKEY_TEXBLEND_NORMALS(N) \ + AI_MATKEY_TEXBLEND(aiTextureType_NORMALS,N) + +#define AI_MATKEY_TEXBLEND_HEIGHT(N) \ + AI_MATKEY_TEXBLEND(aiTextureType_HEIGHT,N) + +#define AI_MATKEY_TEXBLEND_SHININESS(N) \ + AI_MATKEY_TEXBLEND(aiTextureType_SHININESS,N) + +#define AI_MATKEY_TEXBLEND_OPACITY(N) \ + AI_MATKEY_TEXBLEND(aiTextureType_OPACITY,N) + +#define AI_MATKEY_TEXBLEND_DISPLACEMENT(N) \ + AI_MATKEY_TEXBLEND(aiTextureType_DISPLACEMENT,N) + +#define AI_MATKEY_TEXBLEND_LIGHTMAP(N) \ + AI_MATKEY_TEXBLEND(aiTextureType_LIGHTMAP,N) + +#define AI_MATKEY_TEXBLEND_REFLECTION(N) \ + AI_MATKEY_TEXBLEND(aiTextureType_REFLECTION,N) + +//! @endcond +// --------------------------------------------------------------------------- +#define AI_MATKEY_MAPPINGMODE_U(type, N) _AI_MATKEY_MAPPINGMODE_U_BASE,type,N + +// For backward compatibility and simplicity +//! @cond MATS_DOC_FULL +#define AI_MATKEY_MAPPINGMODE_U_DIFFUSE(N) \ + AI_MATKEY_MAPPINGMODE_U(aiTextureType_DIFFUSE,N) + +#define AI_MATKEY_MAPPINGMODE_U_SPECULAR(N) \ + AI_MATKEY_MAPPINGMODE_U(aiTextureType_SPECULAR,N) + +#define AI_MATKEY_MAPPINGMODE_U_AMBIENT(N) \ + AI_MATKEY_MAPPINGMODE_U(aiTextureType_AMBIENT,N) + +#define AI_MATKEY_MAPPINGMODE_U_EMISSIVE(N) \ + AI_MATKEY_MAPPINGMODE_U(aiTextureType_EMISSIVE,N) + +#define AI_MATKEY_MAPPINGMODE_U_NORMALS(N) \ + AI_MATKEY_MAPPINGMODE_U(aiTextureType_NORMALS,N) + +#define AI_MATKEY_MAPPINGMODE_U_HEIGHT(N) \ + AI_MATKEY_MAPPINGMODE_U(aiTextureType_HEIGHT,N) + +#define AI_MATKEY_MAPPINGMODE_U_SHININESS(N) \ + AI_MATKEY_MAPPINGMODE_U(aiTextureType_SHININESS,N) + +#define AI_MATKEY_MAPPINGMODE_U_OPACITY(N) \ + AI_MATKEY_MAPPINGMODE_U(aiTextureType_OPACITY,N) + +#define AI_MATKEY_MAPPINGMODE_U_DISPLACEMENT(N) \ + AI_MATKEY_MAPPINGMODE_U(aiTextureType_DISPLACEMENT,N) + +#define AI_MATKEY_MAPPINGMODE_U_LIGHTMAP(N) \ + AI_MATKEY_MAPPINGMODE_U(aiTextureType_LIGHTMAP,N) + +#define AI_MATKEY_MAPPINGMODE_U_REFLECTION(N) \ + AI_MATKEY_MAPPINGMODE_U(aiTextureType_REFLECTION,N) + +//! @endcond +// --------------------------------------------------------------------------- +#define AI_MATKEY_MAPPINGMODE_V(type, N) _AI_MATKEY_MAPPINGMODE_V_BASE,type,N + +// For backward compatibility and simplicity +//! @cond MATS_DOC_FULL +#define AI_MATKEY_MAPPINGMODE_V_DIFFUSE(N) \ + AI_MATKEY_MAPPINGMODE_V(aiTextureType_DIFFUSE,N) + +#define AI_MATKEY_MAPPINGMODE_V_SPECULAR(N) \ + AI_MATKEY_MAPPINGMODE_V(aiTextureType_SPECULAR,N) + +#define AI_MATKEY_MAPPINGMODE_V_AMBIENT(N) \ + AI_MATKEY_MAPPINGMODE_V(aiTextureType_AMBIENT,N) + +#define AI_MATKEY_MAPPINGMODE_V_EMISSIVE(N) \ + AI_MATKEY_MAPPINGMODE_V(aiTextureType_EMISSIVE,N) + +#define AI_MATKEY_MAPPINGMODE_V_NORMALS(N) \ + AI_MATKEY_MAPPINGMODE_V(aiTextureType_NORMALS,N) + +#define AI_MATKEY_MAPPINGMODE_V_HEIGHT(N) \ + AI_MATKEY_MAPPINGMODE_V(aiTextureType_HEIGHT,N) + +#define AI_MATKEY_MAPPINGMODE_V_SHININESS(N) \ + AI_MATKEY_MAPPINGMODE_V(aiTextureType_SHININESS,N) + +#define AI_MATKEY_MAPPINGMODE_V_OPACITY(N) \ + AI_MATKEY_MAPPINGMODE_V(aiTextureType_OPACITY,N) + +#define AI_MATKEY_MAPPINGMODE_V_DISPLACEMENT(N) \ + AI_MATKEY_MAPPINGMODE_V(aiTextureType_DISPLACEMENT,N) + +#define AI_MATKEY_MAPPINGMODE_V_LIGHTMAP(N) \ + AI_MATKEY_MAPPINGMODE_V(aiTextureType_LIGHTMAP,N) + +#define AI_MATKEY_MAPPINGMODE_V_REFLECTION(N) \ + AI_MATKEY_MAPPINGMODE_V(aiTextureType_REFLECTION,N) + +//! @endcond +// --------------------------------------------------------------------------- +#define AI_MATKEY_TEXMAP_AXIS(type, N) _AI_MATKEY_TEXMAP_AXIS_BASE,type,N + +// For backward compatibility and simplicity +//! @cond MATS_DOC_FULL +#define AI_MATKEY_TEXMAP_AXIS_DIFFUSE(N) \ + AI_MATKEY_TEXMAP_AXIS(aiTextureType_DIFFUSE,N) + +#define AI_MATKEY_TEXMAP_AXIS_SPECULAR(N) \ + AI_MATKEY_TEXMAP_AXIS(aiTextureType_SPECULAR,N) + +#define AI_MATKEY_TEXMAP_AXIS_AMBIENT(N) \ + AI_MATKEY_TEXMAP_AXIS(aiTextureType_AMBIENT,N) + +#define AI_MATKEY_TEXMAP_AXIS_EMISSIVE(N) \ + AI_MATKEY_TEXMAP_AXIS(aiTextureType_EMISSIVE,N) + +#define AI_MATKEY_TEXMAP_AXIS_NORMALS(N) \ + AI_MATKEY_TEXMAP_AXIS(aiTextureType_NORMALS,N) + +#define AI_MATKEY_TEXMAP_AXIS_HEIGHT(N) \ + AI_MATKEY_TEXMAP_AXIS(aiTextureType_HEIGHT,N) + +#define AI_MATKEY_TEXMAP_AXIS_SHININESS(N) \ + AI_MATKEY_TEXMAP_AXIS(aiTextureType_SHININESS,N) + +#define AI_MATKEY_TEXMAP_AXIS_OPACITY(N) \ + AI_MATKEY_TEXMAP_AXIS(aiTextureType_OPACITY,N) + +#define AI_MATKEY_TEXMAP_AXIS_DISPLACEMENT(N) \ + AI_MATKEY_TEXMAP_AXIS(aiTextureType_DISPLACEMENT,N) + +#define AI_MATKEY_TEXMAP_AXIS_LIGHTMAP(N) \ + AI_MATKEY_TEXMAP_AXIS(aiTextureType_LIGHTMAP,N) + +#define AI_MATKEY_TEXMAP_AXIS_REFLECTION(N) \ + AI_MATKEY_TEXMAP_AXIS(aiTextureType_REFLECTION,N) + +//! @endcond +// --------------------------------------------------------------------------- +#define AI_MATKEY_UVTRANSFORM(type, N) _AI_MATKEY_UVTRANSFORM_BASE,type,N + +// For backward compatibility and simplicity +//! @cond MATS_DOC_FULL +#define AI_MATKEY_UVTRANSFORM_DIFFUSE(N) \ + AI_MATKEY_UVTRANSFORM(aiTextureType_DIFFUSE,N) + +#define AI_MATKEY_UVTRANSFORM_SPECULAR(N) \ + AI_MATKEY_UVTRANSFORM(aiTextureType_SPECULAR,N) + +#define AI_MATKEY_UVTRANSFORM_AMBIENT(N) \ + AI_MATKEY_UVTRANSFORM(aiTextureType_AMBIENT,N) + +#define AI_MATKEY_UVTRANSFORM_EMISSIVE(N) \ + AI_MATKEY_UVTRANSFORM(aiTextureType_EMISSIVE,N) + +#define AI_MATKEY_UVTRANSFORM_NORMALS(N) \ + AI_MATKEY_UVTRANSFORM(aiTextureType_NORMALS,N) + +#define AI_MATKEY_UVTRANSFORM_HEIGHT(N) \ + AI_MATKEY_UVTRANSFORM(aiTextureType_HEIGHT,N) + +#define AI_MATKEY_UVTRANSFORM_SHININESS(N) \ + AI_MATKEY_UVTRANSFORM(aiTextureType_SHININESS,N) + +#define AI_MATKEY_UVTRANSFORM_OPACITY(N) \ + AI_MATKEY_UVTRANSFORM(aiTextureType_OPACITY,N) + +#define AI_MATKEY_UVTRANSFORM_DISPLACEMENT(N) \ + AI_MATKEY_UVTRANSFORM(aiTextureType_DISPLACEMENT,N) + +#define AI_MATKEY_UVTRANSFORM_LIGHTMAP(N) \ + AI_MATKEY_UVTRANSFORM(aiTextureType_LIGHTMAP,N) + +#define AI_MATKEY_UVTRANSFORM_REFLECTION(N) \ + AI_MATKEY_UVTRANSFORM(aiTextureType_REFLECTION,N) + +#define AI_MATKEY_UVTRANSFORM_UNKNOWN(N) \ + AI_MATKEY_UVTRANSFORM(aiTextureType_UNKNOWN,N) + +//! @endcond +// --------------------------------------------------------------------------- +#define AI_MATKEY_TEXFLAGS(type, N) _AI_MATKEY_TEXFLAGS_BASE,type,N + +// For backward compatibility and simplicity +//! @cond MATS_DOC_FULL +#define AI_MATKEY_TEXFLAGS_DIFFUSE(N) \ + AI_MATKEY_TEXFLAGS(aiTextureType_DIFFUSE,N) + +#define AI_MATKEY_TEXFLAGS_SPECULAR(N) \ + AI_MATKEY_TEXFLAGS(aiTextureType_SPECULAR,N) + +#define AI_MATKEY_TEXFLAGS_AMBIENT(N) \ + AI_MATKEY_TEXFLAGS(aiTextureType_AMBIENT,N) + +#define AI_MATKEY_TEXFLAGS_EMISSIVE(N) \ + AI_MATKEY_TEXFLAGS(aiTextureType_EMISSIVE,N) + +#define AI_MATKEY_TEXFLAGS_NORMALS(N) \ + AI_MATKEY_TEXFLAGS(aiTextureType_NORMALS,N) + +#define AI_MATKEY_TEXFLAGS_HEIGHT(N) \ + AI_MATKEY_TEXFLAGS(aiTextureType_HEIGHT,N) + +#define AI_MATKEY_TEXFLAGS_SHININESS(N) \ + AI_MATKEY_TEXFLAGS(aiTextureType_SHININESS,N) + +#define AI_MATKEY_TEXFLAGS_OPACITY(N) \ + AI_MATKEY_TEXFLAGS(aiTextureType_OPACITY,N) + +#define AI_MATKEY_TEXFLAGS_DISPLACEMENT(N) \ + AI_MATKEY_TEXFLAGS(aiTextureType_DISPLACEMENT,N) + +#define AI_MATKEY_TEXFLAGS_LIGHTMAP(N) \ + AI_MATKEY_TEXFLAGS(aiTextureType_LIGHTMAP,N) + +#define AI_MATKEY_TEXFLAGS_REFLECTION(N) \ + AI_MATKEY_TEXFLAGS(aiTextureType_REFLECTION,N) + +#define AI_MATKEY_TEXFLAGS_UNKNOWN(N) \ + AI_MATKEY_TEXFLAGS(aiTextureType_UNKNOWN,N) + +// --------------------------------------------------------------------------- +/** @brief Retrieve a material property with a specific key from the material + * + * @param pMat Pointer to the input material. May not be NULL + * @param pKey Key to search for. One of the AI_MATKEY_XXX constants. + * @param type Specifies the type of the texture to be retrieved ( + * e.g. diffuse, specular, height map ...) + * @param index Index of the texture to be retrieved. + * @param pPropOut Pointer to receive a pointer to a valid aiMaterialProperty + * structure or NULL if the key has not been found. */ +// --------------------------------------------------------------------------- +ASSIMP_API C_ENUM aiReturn aiGetMaterialProperty( + const C_STRUCT aiMaterial* pMat, + const char* pKey, + unsigned int type, + unsigned int index, + const C_STRUCT aiMaterialProperty** pPropOut); + +// --------------------------------------------------------------------------- +/** @brief Retrieve an array of float values with a specific key + * from the material + * + * Pass one of the AI_MATKEY_XXX constants for the last three parameters (the + * example reads the #AI_MATKEY_UVTRANSFORM property of the first diffuse texture) + * @code + * aiUVTransform trafo; + * unsigned int max = sizeof(aiUVTransform); + * if (AI_SUCCESS != aiGetMaterialFloatArray(mat, AI_MATKEY_UVTRANSFORM(aiTextureType_DIFFUSE,0), + * (float*)&trafo, &max) || sizeof(aiUVTransform) != max) + * { + * // error handling + * } + * @endcode + * + * @param pMat Pointer to the input material. May not be NULL + * @param pKey Key to search for. One of the AI_MATKEY_XXX constants. + * @param pOut Pointer to a buffer to receive the result. + * @param pMax Specifies the size of the given buffer, in float's. + * Receives the number of values (not bytes!) read. + * @param type (see the code sample above) + * @param index (see the code sample above) + * @return Specifies whether the key has been found. If not, the output + * arrays remains unmodified and pMax is set to 0.*/ +// --------------------------------------------------------------------------- +ASSIMP_API C_ENUM aiReturn aiGetMaterialFloatArray( + const C_STRUCT aiMaterial* pMat, + const char* pKey, + unsigned int type, + unsigned int index, + float* pOut, + unsigned int* pMax); + + +#ifdef __cplusplus + +// --------------------------------------------------------------------------- +/** @brief Retrieve a single float property with a specific key from the material. +* +* Pass one of the AI_MATKEY_XXX constants for the last three parameters (the +* example reads the #AI_MATKEY_SHININESS_STRENGTH property of the first diffuse texture) +* @code +* float specStrength = 1.f; // default value, remains unmodified if we fail. +* aiGetMaterialFloat(mat, AI_MATKEY_SHININESS_STRENGTH, +* (float*)&specStrength); +* @endcode +* +* @param pMat Pointer to the input material. May not be NULL +* @param pKey Key to search for. One of the AI_MATKEY_XXX constants. +* @param pOut Receives the output float. +* @param type (see the code sample above) +* @param index (see the code sample above) +* @return Specifies whether the key has been found. If not, the output +* float remains unmodified.*/ +// --------------------------------------------------------------------------- +inline aiReturn aiGetMaterialFloat(const aiMaterial* pMat, + const char* pKey, + unsigned int type, + unsigned int index, + float* pOut) +{ + return aiGetMaterialFloatArray(pMat,pKey,type,index,pOut,(unsigned int*)0x0); +} + +#else + +// Use our friend, the C preprocessor +#define aiGetMaterialFloat (pMat, type, index, pKey, pOut) \ + aiGetMaterialFloatArray(pMat, type, index, pKey, pOut, NULL) + +#endif //!__cplusplus + + +// --------------------------------------------------------------------------- +/** @brief Retrieve an array of integer values with a specific key + * from a material + * + * See the sample for aiGetMaterialFloatArray for more information.*/ +ASSIMP_API C_ENUM aiReturn aiGetMaterialIntegerArray(const C_STRUCT aiMaterial* pMat, + const char* pKey, + unsigned int type, + unsigned int index, + int* pOut, + unsigned int* pMax); + + +#ifdef __cplusplus + +// --------------------------------------------------------------------------- +/** @brief Retrieve an integer property with a specific key from a material + * + * See the sample for aiGetMaterialFloat for more information.*/ +// --------------------------------------------------------------------------- +inline aiReturn aiGetMaterialInteger(const C_STRUCT aiMaterial* pMat, + const char* pKey, + unsigned int type, + unsigned int index, + int* pOut) +{ + return aiGetMaterialIntegerArray(pMat,pKey,type,index,pOut,(unsigned int*)0x0); +} + +#else + +// use our friend, the C preprocessor +#define aiGetMaterialInteger (pMat, type, index, pKey, pOut) \ + aiGetMaterialIntegerArray(pMat, type, index, pKey, pOut, NULL) + +#endif //!__cplusplus + + + +// --------------------------------------------------------------------------- +/** @brief Retrieve a color value from the material property table +* +* See the sample for aiGetMaterialFloat for more information*/ +// --------------------------------------------------------------------------- +ASSIMP_API C_ENUM aiReturn aiGetMaterialColor(const C_STRUCT aiMaterial* pMat, + const char* pKey, + unsigned int type, + unsigned int index, + C_STRUCT aiColor4D* pOut); + + +// --------------------------------------------------------------------------- +/** @brief Retrieve a string from the material property table +* +* See the sample for aiGetMaterialFloat for more information.*/ +// --------------------------------------------------------------------------- +ASSIMP_API C_ENUM aiReturn aiGetMaterialString(const C_STRUCT aiMaterial* pMat, + const char* pKey, + unsigned int type, + unsigned int index, + C_STRUCT aiString* pOut); + +// --------------------------------------------------------------------------- +/** Get the number of textures for a particular texture type. + * @param[in] pMat Pointer to the input material. May not be NULL + * @param type Texture type to check for + * @return Number of textures for this type. + * @note A texture can be easily queried using #aiGetMaterialTexture() */ +// --------------------------------------------------------------------------- +ASSIMP_API unsigned int aiGetMaterialTextureCount(const C_STRUCT aiMaterial* pMat, + C_ENUM aiTextureType type); + +// --------------------------------------------------------------------------- +/** @brief Helper function to get all values pertaining to a particular + * texture slot from a material structure. + * + * This function is provided just for convenience. You could also read the + * texture by parsing all of its properties manually. This function bundles + * all of them in a huge function monster. + * + * @param[in] mat Pointer to the input material. May not be NULL + * @param[in] type Specifies the texture stack to read from (e.g. diffuse, + * specular, height map ...). + * @param[in] index Index of the texture. The function fails if the + * requested index is not available for this texture type. + * #aiGetMaterialTextureCount() can be used to determine the number of + * textures in a particular texture stack. + * @param[out] path Receives the output path + * This parameter must be non-null. + * @param mapping The texture mapping mode to be used. + * Pass NULL if you're not interested in this information. + * @param[out] uvindex For UV-mapped textures: receives the index of the UV + * source channel. Unmodified otherwise. + * Pass NULL if you're not interested in this information. + * @param[out] blend Receives the blend factor for the texture + * Pass NULL if you're not interested in this information. + * @param[out] op Receives the texture blend operation to be perform between + * this texture and the previous texture. + * Pass NULL if you're not interested in this information. + * @param[out] mapmode Receives the mapping modes to be used for the texture. + * Pass NULL if you're not interested in this information. Otherwise, + * pass a pointer to an array of two aiTextureMapMode's (one for each + * axis, UV order). + * @return AI_SUCCESS on success, otherwise something else. Have fun.*/ +// --------------------------------------------------------------------------- +#ifdef __cplusplus +ASSIMP_API aiReturn aiGetMaterialTexture(const C_STRUCT aiMaterial* mat, + aiTextureType type, + unsigned int index, + aiString* path, + aiTextureMapping* mapping = NULL, + unsigned int* uvindex = NULL, + float* blend = NULL, + aiTextureOp* op = NULL, + aiTextureMapMode* mapmode = NULL, + unsigned int* flags = NULL); +#else +C_ENUM aiReturn aiGetMaterialTexture(const C_STRUCT aiMaterial* mat, + C_ENUM aiTextureType type, + unsigned int index, + C_STRUCT aiString* path, + C_ENUM aiTextureMapping* mapping /*= NULL*/, + unsigned int* uvindex /*= NULL*/, + float* blend /*= NULL*/, + C_ENUM aiTextureOp* op /*= NULL*/, + C_ENUM aiTextureMapMode* mapmode /*= NULL*/, + unsigned int* flags /*= NULL*/); +#endif // !#ifdef __cplusplus + +#ifdef __cplusplus +} + +#include "material.inl" + +#endif //!__cplusplus +#endif //!!AI_MATERIAL_H_INC diff --git a/Lib/Include/assimp/material.inl b/Lib/Include/assimp/material.inl new file mode 100644 index 0000000..3052083 --- /dev/null +++ b/Lib/Include/assimp/material.inl @@ -0,0 +1,276 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2012, assimp team + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following +conditions are met: + +* Redistributions of source code must retain the above + copyright notice, this list of conditions and the + following disclaimer. + +* Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other + materials provided with the distribution. + +* Neither the name of the assimp team, nor the names of its + contributors may be used to endorse or promote products + derived from this software without specific prior + written permission of the assimp team. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"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 COPYRIGHT +OWNER OR CONTRIBUTORS 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. +--------------------------------------------------------------------------- +*/ + +/** @file aiMaterial.inl + * @brief Defines the C++ getters for the material system + */ + +#ifndef AI_MATERIAL_INL_INC +#define AI_MATERIAL_INL_INC + +//! @cond never + +// --------------------------------------------------------------------------- +inline aiReturn aiMaterial::GetTexture( aiTextureType type, + unsigned int index, + C_STRUCT aiString* path, + aiTextureMapping* mapping /*= NULL*/, + unsigned int* uvindex /*= NULL*/, + float* blend /*= NULL*/, + aiTextureOp* op /*= NULL*/, + aiTextureMapMode* mapmode /*= NULL*/) const +{ + return ::aiGetMaterialTexture(this,type,index,path,mapping,uvindex,blend,op,mapmode); +} + +// --------------------------------------------------------------------------- +inline unsigned int aiMaterial::GetTextureCount(aiTextureType type) const +{ + return ::aiGetMaterialTextureCount(this,type); +} + +// --------------------------------------------------------------------------- +template +inline aiReturn aiMaterial::Get(const char* pKey,unsigned int type, + unsigned int idx, Type* pOut, + unsigned int* pMax) const +{ + unsigned int iNum = pMax ? *pMax : 1; + + const aiMaterialProperty* prop; + const aiReturn ret = ::aiGetMaterialProperty(this,pKey,type,idx, + (const aiMaterialProperty**)&prop); + if ( AI_SUCCESS == ret ) { + + if (prop->mDataLength < sizeof(Type)*iNum) { + return AI_FAILURE; + } + + if (prop->mType != aiPTI_Buffer) { + return AI_FAILURE; + } + + iNum = std::min((size_t)iNum,prop->mDataLength / sizeof(Type)); + memcpy(pOut,prop->mData,iNum * sizeof(Type)); + if (pMax) { + *pMax = iNum; + } + } + return ret; +} + +// --------------------------------------------------------------------------- +template +inline aiReturn aiMaterial::Get(const char* pKey,unsigned int type, + unsigned int idx,Type& pOut) const +{ + const aiMaterialProperty* prop; + const aiReturn ret = ::aiGetMaterialProperty(this,pKey,type,idx, + (const aiMaterialProperty**)&prop); + if ( AI_SUCCESS == ret ) { + + if (prop->mDataLength < sizeof(Type)) { + return AI_FAILURE; + } + + if (prop->mType != aiPTI_Buffer) { + return AI_FAILURE; + } + + memcpy(&pOut,prop->mData,sizeof(Type)); + } + return ret; +} + +// --------------------------------------------------------------------------- +template <> +inline aiReturn aiMaterial::Get(const char* pKey,unsigned int type, + unsigned int idx,float* pOut, + unsigned int* pMax) const +{ + return ::aiGetMaterialFloatArray(this,pKey,type,idx,pOut,pMax); +} +// --------------------------------------------------------------------------- +template <> +inline aiReturn aiMaterial::Get(const char* pKey,unsigned int type, + unsigned int idx,int* pOut, + unsigned int* pMax) const +{ + return ::aiGetMaterialIntegerArray(this,pKey,type,idx,pOut,pMax); +} +// --------------------------------------------------------------------------- +template <> +inline aiReturn aiMaterial::Get(const char* pKey,unsigned int type, + unsigned int idx,float& pOut) const +{ + return aiGetMaterialFloat(this,pKey,type,idx,&pOut); +} +// --------------------------------------------------------------------------- +template <> +inline aiReturn aiMaterial::Get(const char* pKey,unsigned int type, + unsigned int idx,int& pOut) const +{ + return aiGetMaterialInteger(this,pKey,type,idx,&pOut); +} +// --------------------------------------------------------------------------- +template <> +inline aiReturn aiMaterial::Get(const char* pKey,unsigned int type, + unsigned int idx,aiColor4D& pOut) const +{ + return aiGetMaterialColor(this,pKey,type,idx,&pOut); +} +// --------------------------------------------------------------------------- +template <> +inline aiReturn aiMaterial::Get(const char* pKey,unsigned int type, + unsigned int idx,aiColor3D& pOut) const +{ + aiColor4D c; + const aiReturn ret = aiGetMaterialColor(this,pKey,type,idx,&c); + pOut = aiColor3D(c.r,c.g,c.b); + return ret; +} +// --------------------------------------------------------------------------- +template <> +inline aiReturn aiMaterial::Get(const char* pKey,unsigned int type, + unsigned int idx,aiString& pOut) const +{ + return aiGetMaterialString(this,pKey,type,idx,&pOut); +} + + +#ifndef ASSIMP_BUILD_NO_EXPORT + +// --------------------------------------------------------------------------- +template +aiReturn aiMaterial::AddProperty (const TYPE* pInput, + const unsigned int pNumValues, + const char* pKey, + unsigned int type, + unsigned int index) +{ + return AddBinaryProperty((const void*)pInput, + pNumValues * sizeof(TYPE), + pKey,type,index,aiPTI_Buffer); +} + +// --------------------------------------------------------------------------- +template<> +inline aiReturn aiMaterial::AddProperty (const float* pInput, + const unsigned int pNumValues, + const char* pKey, + unsigned int type, + unsigned int index) +{ + return AddBinaryProperty((const void*)pInput, + pNumValues * sizeof(float), + pKey,type,index,aiPTI_Float); +} + +// --------------------------------------------------------------------------- +template<> +inline aiReturn aiMaterial::AddProperty (const aiUVTransform* pInput, + const unsigned int pNumValues, + const char* pKey, + unsigned int type, + unsigned int index) +{ + return AddBinaryProperty((const void*)pInput, + pNumValues * sizeof(aiUVTransform), + pKey,type,index,aiPTI_Float); +} + +// --------------------------------------------------------------------------- +template<> +inline aiReturn aiMaterial::AddProperty (const aiColor4D* pInput, + const unsigned int pNumValues, + const char* pKey, + unsigned int type, + unsigned int index) +{ + return AddBinaryProperty((const void*)pInput, + pNumValues * sizeof(aiColor4D), + pKey,type,index,aiPTI_Float); +} + +// --------------------------------------------------------------------------- +template<> +inline aiReturn aiMaterial::AddProperty (const aiColor3D* pInput, + const unsigned int pNumValues, + const char* pKey, + unsigned int type, + unsigned int index) +{ + return AddBinaryProperty((const void*)pInput, + pNumValues * sizeof(aiColor3D), + pKey,type,index,aiPTI_Float); +} + +// --------------------------------------------------------------------------- +template<> +inline aiReturn aiMaterial::AddProperty (const aiVector3D* pInput, + const unsigned int pNumValues, + const char* pKey, + unsigned int type, + unsigned int index) +{ + return AddBinaryProperty((const void*)pInput, + pNumValues * sizeof(aiVector3D), + pKey,type,index,aiPTI_Float); +} + +// --------------------------------------------------------------------------- +template<> +inline aiReturn aiMaterial::AddProperty (const int* pInput, + const unsigned int pNumValues, + const char* pKey, + unsigned int type, + unsigned int index) +{ + return AddBinaryProperty((const void*)pInput, + pNumValues * sizeof(int), + pKey,type,index,aiPTI_Integer); +} + +#endif + +//! @endcond + +#endif //! AI_MATERIAL_INL_INC diff --git a/Lib/Include/assimp/matrix3x3.h b/Lib/Include/assimp/matrix3x3.h new file mode 100644 index 0000000..afd1967 --- /dev/null +++ b/Lib/Include/assimp/matrix3x3.h @@ -0,0 +1,183 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2012, assimp team + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following +conditions are met: + +* Redistributions of source code must retain the above + copyright notice, this list of conditions and the + following disclaimer. + +* Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other + materials provided with the distribution. + +* Neither the name of the assimp team, nor the names of its + contributors may be used to endorse or promote products + derived from this software without specific prior + written permission of the assimp team. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"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 COPYRIGHT +OWNER OR CONTRIBUTORS 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. +--------------------------------------------------------------------------- +*/ + +/** @file matrix3x3.h + * @brief Definition of a 3x3 matrix, including operators when compiling in C++ + */ +#ifndef AI_MATRIX3x3_H_INC +#define AI_MATRIX3x3_H_INC + +#include "./Compiler/pushpack1.h" + +#ifdef __cplusplus + +template class aiMatrix4x4t; +template class aiVector2t; + +// --------------------------------------------------------------------------- +/** @brief Represents a row-major 3x3 matrix + * + * There's much confusion about matrix layouts (column vs. row order). + * This is *always* a row-major matrix. Not even with the + * #aiProcess_ConvertToLeftHanded flag, which absolutely does not affect + * matrix order - it just affects the handedness of the coordinate system + * defined thereby. + */ +template +class aiMatrix3x3t +{ +public: + + aiMatrix3x3t () : + a1(static_cast(1.0f)), a2(), a3(), + b1(), b2(static_cast(1.0f)), b3(), + c1(), c2(), c3(static_cast(1.0f)) {} + + aiMatrix3x3t ( TReal _a1, TReal _a2, TReal _a3, + TReal _b1, TReal _b2, TReal _b3, + TReal _c1, TReal _c2, TReal _c3) : + a1(_a1), a2(_a2), a3(_a3), + b1(_b1), b2(_b2), b3(_b3), + c1(_c1), c2(_c2), c3(_c3) + {} + +public: + + // matrix multiplication. + aiMatrix3x3t& operator *= (const aiMatrix3x3t& m); + aiMatrix3x3t operator * (const aiMatrix3x3t& m) const; + + // array access operators + TReal* operator[] (unsigned int p_iIndex); + const TReal* operator[] (unsigned int p_iIndex) const; + + // comparison operators + bool operator== (const aiMatrix4x4t m) const; + bool operator!= (const aiMatrix4x4t m) const; + + template + operator aiMatrix3x3t () const; + +public: + + // ------------------------------------------------------------------- + /** @brief Construction from a 4x4 matrix. The remaining parts + * of the matrix are ignored. + */ + explicit aiMatrix3x3t( const aiMatrix4x4t& pMatrix); + + // ------------------------------------------------------------------- + /** @brief Transpose the matrix + */ + aiMatrix3x3t& Transpose(); + + // ------------------------------------------------------------------- + /** @brief Invert the matrix. + * If the matrix is not invertible all elements are set to qnan. + * Beware, use (f != f) to check whether a TReal f is qnan. + */ + aiMatrix3x3t& Inverse(); + TReal Determinant() const; + +public: + // ------------------------------------------------------------------- + /** @brief Returns a rotation matrix for a rotation around z + * @param a Rotation angle, in radians + * @param out Receives the output matrix + * @return Reference to the output matrix + */ + static aiMatrix3x3t& RotationZ(TReal a, aiMatrix3x3t& out); + + // ------------------------------------------------------------------- + /** @brief Returns a rotation matrix for a rotation around + * an arbitrary axis. + * + * @param a Rotation angle, in radians + * @param axis Axis to rotate around + * @param out To be filled + */ + static aiMatrix3x3t& Rotation( TReal a, + const aiVector3t& axis, aiMatrix3x3t& out); + + // ------------------------------------------------------------------- + /** @brief Returns a translation matrix + * @param v Translation vector + * @param out Receives the output matrix + * @return Reference to the output matrix + */ + static aiMatrix3x3t& Translation( const aiVector2t& v, aiMatrix3x3t& out); + + // ------------------------------------------------------------------- + /** @brief A function for creating a rotation matrix that rotates a + * vector called "from" into another vector called "to". + * Input : from[3], to[3] which both must be *normalized* non-zero vectors + * Output: mtx[3][3] -- a 3x3 matrix in colum-major form + * Authors: Tomas M÷ller, John Hughes + * "Efficiently Building a Matrix to Rotate One Vector to Another" + * Journal of Graphics Tools, 4(4):1-4, 1999 + */ + static aiMatrix3x3t& FromToMatrix(const aiVector3t& from, + const aiVector3t& to, aiMatrix3x3t& out); + +public: + + + TReal a1, a2, a3; + TReal b1, b2, b3; + TReal c1, c2, c3; +} PACK_STRUCT; + +typedef aiMatrix3x3t aiMatrix3x3; + +#else + +struct aiMatrix3x3 { + + float a1, a2, a3; + float b1, b2, b3; + float c1, c2, c3; +} PACK_STRUCT; + +#endif + +#include "./Compiler/poppack1.h" + +#endif // AI_MATRIX3x3_H_INC diff --git a/Lib/Include/assimp/matrix3x3.inl b/Lib/Include/assimp/matrix3x3.inl new file mode 100644 index 0000000..9a21595 --- /dev/null +++ b/Lib/Include/assimp/matrix3x3.inl @@ -0,0 +1,316 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2012, assimp team + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following +conditions are met: + +* Redistributions of source code must retain the above + copyright notice, this list of conditions and the + following disclaimer. + +* Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other + materials provided with the distribution. + +* Neither the name of the assimp team, nor the names of its + contributors may be used to endorse or promote products + derived from this software without specific prior + written permission of the assimp team. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"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 COPYRIGHT +OWNER OR CONTRIBUTORS 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. +--------------------------------------------------------------------------- +*/ + +/** @file aiMatrix3x3.inl + * @brief Inline implementation of the 3x3 matrix operators + */ +#ifndef AI_MATRIX3x3_INL_INC +#define AI_MATRIX3x3_INL_INC + +#ifdef __cplusplus +#include "matrix3x3.h" + +#include "matrix4x4.h" +#include +#include + +// ------------------------------------------------------------------------------------------------ +// Construction from a 4x4 matrix. The remaining parts of the matrix are ignored. +template +inline aiMatrix3x3t::aiMatrix3x3t( const aiMatrix4x4t& pMatrix) +{ + a1 = pMatrix.a1; a2 = pMatrix.a2; a3 = pMatrix.a3; + b1 = pMatrix.b1; b2 = pMatrix.b2; b3 = pMatrix.b3; + c1 = pMatrix.c1; c2 = pMatrix.c2; c3 = pMatrix.c3; +} + +// ------------------------------------------------------------------------------------------------ +template +inline aiMatrix3x3t& aiMatrix3x3t::operator *= (const aiMatrix3x3t& m) +{ + *this = aiMatrix3x3t(m.a1 * a1 + m.b1 * a2 + m.c1 * a3, + m.a2 * a1 + m.b2 * a2 + m.c2 * a3, + m.a3 * a1 + m.b3 * a2 + m.c3 * a3, + m.a1 * b1 + m.b1 * b2 + m.c1 * b3, + m.a2 * b1 + m.b2 * b2 + m.c2 * b3, + m.a3 * b1 + m.b3 * b2 + m.c3 * b3, + m.a1 * c1 + m.b1 * c2 + m.c1 * c3, + m.a2 * c1 + m.b2 * c2 + m.c2 * c3, + m.a3 * c1 + m.b3 * c2 + m.c3 * c3); + return *this; +} + +// ------------------------------------------------------------------------------------------------ +template +template +aiMatrix3x3t::operator aiMatrix3x3t () const +{ + return aiMatrix3x3t(static_cast(a1),static_cast(a2),static_cast(a3), + static_cast(b1),static_cast(b2),static_cast(b3), + static_cast(c1),static_cast(c2),static_cast(c3)); +} + +// ------------------------------------------------------------------------------------------------ +template +inline aiMatrix3x3t aiMatrix3x3t::operator* (const aiMatrix3x3t& m) const +{ + aiMatrix3x3t temp( *this); + temp *= m; + return temp; +} + +// ------------------------------------------------------------------------------------------------ +template +inline TReal* aiMatrix3x3t::operator[] (unsigned int p_iIndex) +{ + return &this->a1 + p_iIndex * 3; +} + +// ------------------------------------------------------------------------------------------------ +template +inline const TReal* aiMatrix3x3t::operator[] (unsigned int p_iIndex) const +{ + return &this->a1 + p_iIndex * 3; +} + +// ------------------------------------------------------------------------------------------------ +template +inline bool aiMatrix3x3t::operator== (const aiMatrix4x4t m) const +{ + return a1 == m.a1 && a2 == m.a2 && a3 == m.a3 && + b1 == m.b1 && b2 == m.b2 && b3 == m.b3 && + c1 == m.c1 && c2 == m.c2 && c3 == m.c3; +} + +// ------------------------------------------------------------------------------------------------ +template +inline bool aiMatrix3x3t::operator!= (const aiMatrix4x4t m) const +{ + return !(*this == m); +} + +// ------------------------------------------------------------------------------------------------ +template +inline aiMatrix3x3t& aiMatrix3x3t::Transpose() +{ + // (TReal&) don't remove, GCC complains cause of packed fields + std::swap( (TReal&)a2, (TReal&)b1); + std::swap( (TReal&)a3, (TReal&)c1); + std::swap( (TReal&)b3, (TReal&)c2); + return *this; +} + +// ---------------------------------------------------------------------------------------- +template +inline TReal aiMatrix3x3t::Determinant() const +{ + return a1*b2*c3 - a1*b3*c2 + a2*b3*c1 - a2*b1*c3 + a3*b1*c2 - a3*b2*c1; +} + +// ---------------------------------------------------------------------------------------- +template +inline aiMatrix3x3t& aiMatrix3x3t::Inverse() +{ + // Compute the reciprocal determinant + TReal det = Determinant(); + if(det == static_cast(0.0)) + { + // Matrix not invertible. Setting all elements to nan is not really + // correct in a mathematical sense; but at least qnans are easy to + // spot. XXX we might throw an exception instead, which would + // be even much better to spot :/. + const TReal nan = std::numeric_limits::quiet_NaN(); + *this = aiMatrix3x3t( nan,nan,nan,nan,nan,nan,nan,nan,nan); + + return *this; + } + + TReal invdet = static_cast(1.0) / det; + + aiMatrix3x3t res; + res.a1 = invdet * (b2 * c3 - b3 * c2); + res.a2 = -invdet * (a2 * c3 - a3 * c2); + res.a3 = invdet * (a2 * b3 - a3 * b2); + res.b1 = -invdet * (b1 * c3 - b3 * c1); + res.b2 = invdet * (a1 * c3 - a3 * c1); + res.b3 = -invdet * (a1 * b3 - a3 * b1); + res.c1 = invdet * (b1 * c2 - b2 * c1); + res.c2 = -invdet * (a1 * c2 - a2 * c1); + res.c3 = invdet * (a1 * b2 - a2 * b1); + *this = res; + + return *this; +} + +// ------------------------------------------------------------------------------------------------ +template +inline aiMatrix3x3t& aiMatrix3x3t::RotationZ(TReal a, aiMatrix3x3t& out) +{ + out.a1 = out.b2 = ::cos(a); + out.b1 = ::sin(a); + out.a2 = - out.b1; + + out.a3 = out.b3 = out.c1 = out.c2 = 0.f; + out.c3 = 1.f; + + return out; +} + +// ------------------------------------------------------------------------------------------------ +// Returns a rotation matrix for a rotation around an arbitrary axis. +template +inline aiMatrix3x3t& aiMatrix3x3t::Rotation( TReal a, const aiVector3t& axis, aiMatrix3x3t& out) +{ + TReal c = cos( a), s = sin( a), t = 1 - c; + TReal x = axis.x, y = axis.y, z = axis.z; + + // Many thanks to MathWorld and Wikipedia + out.a1 = t*x*x + c; out.a2 = t*x*y - s*z; out.a3 = t*x*z + s*y; + out.b1 = t*x*y + s*z; out.b2 = t*y*y + c; out.b3 = t*y*z - s*x; + out.c1 = t*x*z - s*y; out.c2 = t*y*z + s*x; out.c3 = t*z*z + c; + + return out; +} + +// ------------------------------------------------------------------------------------------------ +template +inline aiMatrix3x3t& aiMatrix3x3t::Translation( const aiVector2t& v, aiMatrix3x3t& out) +{ + out = aiMatrix3x3t(); + out.a3 = v.x; + out.b3 = v.y; + return out; +} + +// ---------------------------------------------------------------------------------------- +/** A function for creating a rotation matrix that rotates a vector called + * "from" into another vector called "to". + * Input : from[3], to[3] which both must be *normalized* non-zero vectors + * Output: mtx[3][3] -- a 3x3 matrix in colum-major form + * Authors: Tomas Möller, John Hughes + * "Efficiently Building a Matrix to Rotate One Vector to Another" + * Journal of Graphics Tools, 4(4):1-4, 1999 + */ +// ---------------------------------------------------------------------------------------- +template +inline aiMatrix3x3t& aiMatrix3x3t::FromToMatrix(const aiVector3t& from, + const aiVector3t& to, aiMatrix3x3t& mtx) +{ + const TReal e = from * to; + const TReal f = (e < 0)? -e:e; + + if (f > static_cast(1.0) - static_cast(0.00001)) /* "from" and "to"-vector almost parallel */ + { + aiVector3D u,v; /* temporary storage vectors */ + aiVector3D x; /* vector most nearly orthogonal to "from" */ + + x.x = (from.x > 0.0)? from.x : -from.x; + x.y = (from.y > 0.0)? from.y : -from.y; + x.z = (from.z > 0.0)? from.z : -from.z; + + if (x.x < x.y) + { + if (x.x < x.z) + { + x.x = static_cast(1.0); x.y = x.z = static_cast(0.0); + } + else + { + x.z = static_cast(1.0); x.y = x.z = static_cast(0.0); + } + } + else + { + if (x.y < x.z) + { + x.y = static_cast(1.0); x.x = x.z = static_cast(0.0); + } + else + { + x.z = static_cast(1.0); x.x = x.y = static_cast(0.0); + } + } + + u.x = x.x - from.x; u.y = x.y - from.y; u.z = x.z - from.z; + v.x = x.x - to.x; v.y = x.y - to.y; v.z = x.z - to.z; + + const TReal c1 = static_cast(2.0) / (u * u); + const TReal c2 = static_cast(2.0) / (v * v); + const TReal c3 = c1 * c2 * (u * v); + + for (unsigned int i = 0; i < 3; i++) + { + for (unsigned int j = 0; j < 3; j++) + { + mtx[i][j] = - c1 * u[i] * u[j] - c2 * v[i] * v[j] + + c3 * v[i] * u[j]; + } + mtx[i][i] += static_cast(1.0); + } + } + else /* the most common case, unless "from"="to", or "from"=-"to" */ + { + const aiVector3D v = from ^ to; + /* ... use this hand optimized version (9 mults less) */ + const TReal h = static_cast(1.0)/(static_cast(1.0) + e); /* optimization by Gottfried Chen */ + const TReal hvx = h * v.x; + const TReal hvz = h * v.z; + const TReal hvxy = hvx * v.y; + const TReal hvxz = hvx * v.z; + const TReal hvyz = hvz * v.y; + mtx[0][0] = e + hvx * v.x; + mtx[0][1] = hvxy - v.z; + mtx[0][2] = hvxz + v.y; + + mtx[1][0] = hvxy + v.z; + mtx[1][1] = e + h * v.y * v.y; + mtx[1][2] = hvyz - v.x; + + mtx[2][0] = hvxz - v.y; + mtx[2][1] = hvyz + v.x; + mtx[2][2] = e + hvz * v.z; + } + return mtx; +} + + +#endif // __cplusplus +#endif // AI_MATRIX3x3_INL_INC diff --git a/Lib/Include/assimp/matrix4x4.h b/Lib/Include/assimp/matrix4x4.h new file mode 100644 index 0000000..90f72be --- /dev/null +++ b/Lib/Include/assimp/matrix4x4.h @@ -0,0 +1,238 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2012, assimp team + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following +conditions are met: + +* Redistributions of source code must retain the above + copyright notice, this list of conditions and the + following disclaimer. + +* Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other + materials provided with the distribution. + +* Neither the name of the assimp team, nor the names of its + contributors may be used to endorse or promote products + derived from this software without specific prior + written permission of the assimp team. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"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 COPYRIGHT +OWNER OR CONTRIBUTORS 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. +--------------------------------------------------------------------------- +*/ +/** @file matrix4x4.h + * @brief 4x4 matrix structure, including operators when compiling in C++ + */ +#ifndef AI_MATRIX4X4_H_INC +#define AI_MATRIX4X4_H_INC + +#include "./Compiler/pushpack1.h" + +#ifdef __cplusplus + +template class aiMatrix3x3t; +template class aiQuaterniont; + +// --------------------------------------------------------------------------- +/** @brief Represents a row-major 4x4 matrix, use this for homogeneous + * coordinates. + * + * There's much confusion about matrix layouts (column vs. row order). + * This is *always* a row-major matrix. Not even with the + * #aiProcess_ConvertToLeftHanded flag, which absolutely does not affect + * matrix order - it just affects the handedness of the coordinate system + * defined thereby. + */ +template +class aiMatrix4x4t +{ +public: + + /** set to identity */ + aiMatrix4x4t (); + + /** construction from single values */ + aiMatrix4x4t ( TReal _a1, TReal _a2, TReal _a3, TReal _a4, + TReal _b1, TReal _b2, TReal _b3, TReal _b4, + TReal _c1, TReal _c2, TReal _c3, TReal _c4, + TReal _d1, TReal _d2, TReal _d3, TReal _d4); + + + /** construction from 3x3 matrix, remaining elements are set to identity */ + explicit aiMatrix4x4t( const aiMatrix3x3t& m); + +public: + + // array access operators + TReal* operator[] (unsigned int p_iIndex); + const TReal* operator[] (unsigned int p_iIndex) const; + + // comparison operators + bool operator== (const aiMatrix4x4t m) const; + bool operator!= (const aiMatrix4x4t m) const; + + // matrix multiplication. + aiMatrix4x4t& operator *= (const aiMatrix4x4t& m); + aiMatrix4x4t operator * (const aiMatrix4x4t& m) const; + + template + operator aiMatrix4x4t () const; + +public: + + // ------------------------------------------------------------------- + /** @brief Transpose the matrix */ + aiMatrix4x4t& Transpose(); + + // ------------------------------------------------------------------- + /** @brief Invert the matrix. + * If the matrix is not invertible all elements are set to qnan. + * Beware, use (f != f) to check whether a TReal f is qnan. + */ + aiMatrix4x4t& Inverse(); + TReal Determinant() const; + + + // ------------------------------------------------------------------- + /** @brief Returns true of the matrix is the identity matrix. + * The check is performed against a not so small epsilon. + */ + inline bool IsIdentity() const; + + // ------------------------------------------------------------------- + /** @brief Decompose a trafo matrix into its original components + * @param scaling Receives the output scaling for the x,y,z axes + * @param rotation Receives the output rotation as a hamilton + * quaternion + * @param position Receives the output position for the x,y,z axes + */ + void Decompose (aiVector3t& scaling, aiQuaterniont& rotation, + aiVector3t& position) const; + + // ------------------------------------------------------------------- + /** @brief Decompose a trafo matrix with no scaling into its + * original components + * @param rotation Receives the output rotation as a hamilton + * quaternion + * @param position Receives the output position for the x,y,z axes + */ + void DecomposeNoScaling (aiQuaterniont& rotation, + aiVector3t& position) const; + + + // ------------------------------------------------------------------- + /** @brief Creates a trafo matrix from a set of euler angles + * @param x Rotation angle for the x-axis, in radians + * @param y Rotation angle for the y-axis, in radians + * @param z Rotation angle for the z-axis, in radians + */ + aiMatrix4x4t& FromEulerAnglesXYZ(TReal x, TReal y, TReal z); + aiMatrix4x4t& FromEulerAnglesXYZ(const aiVector3t& blubb); + +public: + // ------------------------------------------------------------------- + /** @brief Returns a rotation matrix for a rotation around the x axis + * @param a Rotation angle, in radians + * @param out Receives the output matrix + * @return Reference to the output matrix + */ + static aiMatrix4x4t& RotationX(TReal a, aiMatrix4x4t& out); + + // ------------------------------------------------------------------- + /** @brief Returns a rotation matrix for a rotation around the y axis + * @param a Rotation angle, in radians + * @param out Receives the output matrix + * @return Reference to the output matrix + */ + static aiMatrix4x4t& RotationY(TReal a, aiMatrix4x4t& out); + + // ------------------------------------------------------------------- + /** @brief Returns a rotation matrix for a rotation around the z axis + * @param a Rotation angle, in radians + * @param out Receives the output matrix + * @return Reference to the output matrix + */ + static aiMatrix4x4t& RotationZ(TReal a, aiMatrix4x4t& out); + + // ------------------------------------------------------------------- + /** Returns a rotation matrix for a rotation around an arbitrary axis. + * @param a Rotation angle, in radians + * @param axis Rotation axis, should be a normalized vector. + * @param out Receives the output matrix + * @return Reference to the output matrix + */ + static aiMatrix4x4t& Rotation(TReal a, const aiVector3t& axis, + aiMatrix4x4t& out); + + // ------------------------------------------------------------------- + /** @brief Returns a translation matrix + * @param v Translation vector + * @param out Receives the output matrix + * @return Reference to the output matrix + */ + static aiMatrix4x4t& Translation( const aiVector3t& v, aiMatrix4x4t& out); + + // ------------------------------------------------------------------- + /** @brief Returns a scaling matrix + * @param v Scaling vector + * @param out Receives the output matrix + * @return Reference to the output matrix + */ + static aiMatrix4x4t& Scaling( const aiVector3t& v, aiMatrix4x4t& out); + + // ------------------------------------------------------------------- + /** @brief A function for creating a rotation matrix that rotates a + * vector called "from" into another vector called "to". + * Input : from[3], to[3] which both must be *normalized* non-zero vectors + * Output: mtx[3][3] -- a 3x3 matrix in colum-major form + * Authors: Tomas M÷ller, John Hughes + * "Efficiently Building a Matrix to Rotate One Vector to Another" + * Journal of Graphics Tools, 4(4):1-4, 1999 + */ + static aiMatrix4x4t& FromToMatrix(const aiVector3t& from, + const aiVector3t& to, aiMatrix4x4t& out); + +public: + + TReal a1, a2, a3, a4; + TReal b1, b2, b3, b4; + TReal c1, c2, c3, c4; + TReal d1, d2, d3, d4; + +} PACK_STRUCT; + +typedef aiMatrix4x4t aiMatrix4x4; + +#else + +struct aiMatrix4x4 { + float a1, a2, a3, a4; + float b1, b2, b3, b4; + float c1, c2, c3, c4; + float d1, d2, d3, d4; +}; + + +#endif // __cplusplus + +#include "./Compiler/poppack1.h" + +#endif // AI_MATRIX4X4_H_INC diff --git a/Lib/Include/assimp/matrix4x4.inl b/Lib/Include/assimp/matrix4x4.inl new file mode 100644 index 0000000..3cddb3a --- /dev/null +++ b/Lib/Include/assimp/matrix4x4.inl @@ -0,0 +1,485 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2012, assimp team + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following +conditions are met: + +* Redistributions of source code must retain the above + copyright notice, this list of conditions and the + following disclaimer. + +* Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other + materials provided with the distribution. + +* Neither the name of the assimp team, nor the names of its + contributors may be used to endorse or promote products + derived from this software without specific prior + written permission of the assimp team. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"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 COPYRIGHT +OWNER OR CONTRIBUTORS 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. +--------------------------------------------------------------------------- +*/ + +/** @file aiMatrix4x4t.inl + * @brief Inline implementation of the 4x4 matrix operators + */ +#ifndef AI_MATRIX4x4_INL_INC +#define AI_MATRIX4x4_INL_INC + +#ifdef __cplusplus + +#include "matrix4x4.h" +#include "matrix3x3.h" +#include "quaternion.h" + +#include +#include +#include + +// ---------------------------------------------------------------------------------------- +template +aiMatrix4x4t ::aiMatrix4x4t () : + a1(1.0f), a2(), a3(), a4(), + b1(), b2(1.0f), b3(), b4(), + c1(), c2(), c3(1.0f), c4(), + d1(), d2(), d3(), d4(1.0f) +{ + +} + +// ---------------------------------------------------------------------------------------- +template +aiMatrix4x4t ::aiMatrix4x4t (TReal _a1, TReal _a2, TReal _a3, TReal _a4, + TReal _b1, TReal _b2, TReal _b3, TReal _b4, + TReal _c1, TReal _c2, TReal _c3, TReal _c4, + TReal _d1, TReal _d2, TReal _d3, TReal _d4) : + a1(_a1), a2(_a2), a3(_a3), a4(_a4), + b1(_b1), b2(_b2), b3(_b3), b4(_b4), + c1(_c1), c2(_c2), c3(_c3), c4(_c4), + d1(_d1), d2(_d2), d3(_d3), d4(_d4) +{ + +} + +// ------------------------------------------------------------------------------------------------ +template +template +aiMatrix4x4t::operator aiMatrix4x4t () const +{ + return aiMatrix4x4t(static_cast(a1),static_cast(a2),static_cast(a3),static_cast(a4), + static_cast(b1),static_cast(b2),static_cast(b3),static_cast(b4), + static_cast(c1),static_cast(c2),static_cast(c3),static_cast(c4), + static_cast(d1),static_cast(d2),static_cast(d3),static_cast(d4)); +} + + +// ---------------------------------------------------------------------------------------- +template +inline aiMatrix4x4t::aiMatrix4x4t (const aiMatrix3x3t& m) +{ + a1 = m.a1; a2 = m.a2; a3 = m.a3; a4 = static_cast(0.0); + b1 = m.b1; b2 = m.b2; b3 = m.b3; b4 = static_cast(0.0); + c1 = m.c1; c2 = m.c2; c3 = m.c3; c4 = static_cast(0.0); + d1 = static_cast(0.0); d2 = static_cast(0.0); d3 = static_cast(0.0); d4 = static_cast(1.0); +} + +// ---------------------------------------------------------------------------------------- +template +inline aiMatrix4x4t& aiMatrix4x4t::operator *= (const aiMatrix4x4t& m) +{ + *this = aiMatrix4x4t( + m.a1 * a1 + m.b1 * a2 + m.c1 * a3 + m.d1 * a4, + m.a2 * a1 + m.b2 * a2 + m.c2 * a3 + m.d2 * a4, + m.a3 * a1 + m.b3 * a2 + m.c3 * a3 + m.d3 * a4, + m.a4 * a1 + m.b4 * a2 + m.c4 * a3 + m.d4 * a4, + m.a1 * b1 + m.b1 * b2 + m.c1 * b3 + m.d1 * b4, + m.a2 * b1 + m.b2 * b2 + m.c2 * b3 + m.d2 * b4, + m.a3 * b1 + m.b3 * b2 + m.c3 * b3 + m.d3 * b4, + m.a4 * b1 + m.b4 * b2 + m.c4 * b3 + m.d4 * b4, + m.a1 * c1 + m.b1 * c2 + m.c1 * c3 + m.d1 * c4, + m.a2 * c1 + m.b2 * c2 + m.c2 * c3 + m.d2 * c4, + m.a3 * c1 + m.b3 * c2 + m.c3 * c3 + m.d3 * c4, + m.a4 * c1 + m.b4 * c2 + m.c4 * c3 + m.d4 * c4, + m.a1 * d1 + m.b1 * d2 + m.c1 * d3 + m.d1 * d4, + m.a2 * d1 + m.b2 * d2 + m.c2 * d3 + m.d2 * d4, + m.a3 * d1 + m.b3 * d2 + m.c3 * d3 + m.d3 * d4, + m.a4 * d1 + m.b4 * d2 + m.c4 * d3 + m.d4 * d4); + return *this; +} + +// ---------------------------------------------------------------------------------------- +template +inline aiMatrix4x4t aiMatrix4x4t::operator* (const aiMatrix4x4t& m) const +{ + aiMatrix4x4t temp( *this); + temp *= m; + return temp; +} + + +// ---------------------------------------------------------------------------------------- +template +inline aiMatrix4x4t& aiMatrix4x4t::Transpose() +{ + // (TReal&) don't remove, GCC complains cause of packed fields + std::swap( (TReal&)b1, (TReal&)a2); + std::swap( (TReal&)c1, (TReal&)a3); + std::swap( (TReal&)c2, (TReal&)b3); + std::swap( (TReal&)d1, (TReal&)a4); + std::swap( (TReal&)d2, (TReal&)b4); + std::swap( (TReal&)d3, (TReal&)c4); + return *this; +} + + +// ---------------------------------------------------------------------------------------- +template +inline TReal aiMatrix4x4t::Determinant() const +{ + return a1*b2*c3*d4 - a1*b2*c4*d3 + a1*b3*c4*d2 - a1*b3*c2*d4 + + a1*b4*c2*d3 - a1*b4*c3*d2 - a2*b3*c4*d1 + a2*b3*c1*d4 + - a2*b4*c1*d3 + a2*b4*c3*d1 - a2*b1*c3*d4 + a2*b1*c4*d3 + + a3*b4*c1*d2 - a3*b4*c2*d1 + a3*b1*c2*d4 - a3*b1*c4*d2 + + a3*b2*c4*d1 - a3*b2*c1*d4 - a4*b1*c2*d3 + a4*b1*c3*d2 + - a4*b2*c3*d1 + a4*b2*c1*d3 - a4*b3*c1*d2 + a4*b3*c2*d1; +} + +// ---------------------------------------------------------------------------------------- +template +inline aiMatrix4x4t& aiMatrix4x4t::Inverse() +{ + // Compute the reciprocal determinant + const TReal det = Determinant(); + if(det == static_cast(0.0)) + { + // Matrix not invertible. Setting all elements to nan is not really + // correct in a mathematical sense but it is easy to debug for the + // programmer. + const TReal nan = std::numeric_limits::quiet_NaN(); + *this = aiMatrix4x4t( + nan,nan,nan,nan, + nan,nan,nan,nan, + nan,nan,nan,nan, + nan,nan,nan,nan); + + return *this; + } + + const TReal invdet = static_cast(1.0) / det; + + aiMatrix4x4t res; + res.a1 = invdet * (b2 * (c3 * d4 - c4 * d3) + b3 * (c4 * d2 - c2 * d4) + b4 * (c2 * d3 - c3 * d2)); + res.a2 = -invdet * (a2 * (c3 * d4 - c4 * d3) + a3 * (c4 * d2 - c2 * d4) + a4 * (c2 * d3 - c3 * d2)); + res.a3 = invdet * (a2 * (b3 * d4 - b4 * d3) + a3 * (b4 * d2 - b2 * d4) + a4 * (b2 * d3 - b3 * d2)); + res.a4 = -invdet * (a2 * (b3 * c4 - b4 * c3) + a3 * (b4 * c2 - b2 * c4) + a4 * (b2 * c3 - b3 * c2)); + res.b1 = -invdet * (b1 * (c3 * d4 - c4 * d3) + b3 * (c4 * d1 - c1 * d4) + b4 * (c1 * d3 - c3 * d1)); + res.b2 = invdet * (a1 * (c3 * d4 - c4 * d3) + a3 * (c4 * d1 - c1 * d4) + a4 * (c1 * d3 - c3 * d1)); + res.b3 = -invdet * (a1 * (b3 * d4 - b4 * d3) + a3 * (b4 * d1 - b1 * d4) + a4 * (b1 * d3 - b3 * d1)); + res.b4 = invdet * (a1 * (b3 * c4 - b4 * c3) + a3 * (b4 * c1 - b1 * c4) + a4 * (b1 * c3 - b3 * c1)); + res.c1 = invdet * (b1 * (c2 * d4 - c4 * d2) + b2 * (c4 * d1 - c1 * d4) + b4 * (c1 * d2 - c2 * d1)); + res.c2 = -invdet * (a1 * (c2 * d4 - c4 * d2) + a2 * (c4 * d1 - c1 * d4) + a4 * (c1 * d2 - c2 * d1)); + res.c3 = invdet * (a1 * (b2 * d4 - b4 * d2) + a2 * (b4 * d1 - b1 * d4) + a4 * (b1 * d2 - b2 * d1)); + res.c4 = -invdet * (a1 * (b2 * c4 - b4 * c2) + a2 * (b4 * c1 - b1 * c4) + a4 * (b1 * c2 - b2 * c1)); + res.d1 = -invdet * (b1 * (c2 * d3 - c3 * d2) + b2 * (c3 * d1 - c1 * d3) + b3 * (c1 * d2 - c2 * d1)); + res.d2 = invdet * (a1 * (c2 * d3 - c3 * d2) + a2 * (c3 * d1 - c1 * d3) + a3 * (c1 * d2 - c2 * d1)); + res.d3 = -invdet * (a1 * (b2 * d3 - b3 * d2) + a2 * (b3 * d1 - b1 * d3) + a3 * (b1 * d2 - b2 * d1)); + res.d4 = invdet * (a1 * (b2 * c3 - b3 * c2) + a2 * (b3 * c1 - b1 * c3) + a3 * (b1 * c2 - b2 * c1)); + *this = res; + + return *this; +} + +// ---------------------------------------------------------------------------------------- +template +inline TReal* aiMatrix4x4t::operator[](unsigned int p_iIndex) +{ + // XXX this is UB. Has been for years. The fact that it works now does not make it better. + return &this->a1 + p_iIndex * 4; +} + +// ---------------------------------------------------------------------------------------- +template +inline const TReal* aiMatrix4x4t::operator[](unsigned int p_iIndex) const +{ + // XXX same + return &this->a1 + p_iIndex * 4; +} + +// ---------------------------------------------------------------------------------------- +template +inline bool aiMatrix4x4t::operator== (const aiMatrix4x4t m) const +{ + return (a1 == m.a1 && a2 == m.a2 && a3 == m.a3 && a4 == m.a4 && + b1 == m.b1 && b2 == m.b2 && b3 == m.b3 && b4 == m.b4 && + c1 == m.c1 && c2 == m.c2 && c3 == m.c3 && c4 == m.c4 && + d1 == m.d1 && d2 == m.d2 && d3 == m.d3 && d4 == m.d4); +} + +// ---------------------------------------------------------------------------------------- +template +inline bool aiMatrix4x4t::operator!= (const aiMatrix4x4t m) const +{ + return !(*this == m); +} + +// ---------------------------------------------------------------------------------------- +template +inline void aiMatrix4x4t::Decompose (aiVector3t& scaling, aiQuaterniont& rotation, + aiVector3t& position) const +{ + const aiMatrix4x4t& _this = *this; + + // extract translation + position.x = _this[0][3]; + position.y = _this[1][3]; + position.z = _this[2][3]; + + // extract the rows of the matrix + aiVector3t vRows[3] = { + aiVector3t(_this[0][0],_this[1][0],_this[2][0]), + aiVector3t(_this[0][1],_this[1][1],_this[2][1]), + aiVector3t(_this[0][2],_this[1][2],_this[2][2]) + }; + + // extract the scaling factors + scaling.x = vRows[0].Length(); + scaling.y = vRows[1].Length(); + scaling.z = vRows[2].Length(); + + // and the sign of the scaling + if (Determinant() < 0) { + scaling.x = -scaling.x; + scaling.y = -scaling.y; + scaling.z = -scaling.z; + } + + // and remove all scaling from the matrix + if(scaling.x) + { + vRows[0] /= scaling.x; + } + if(scaling.y) + { + vRows[1] /= scaling.y; + } + if(scaling.z) + { + vRows[2] /= scaling.z; + } + + // build a 3x3 rotation matrix + aiMatrix3x3t m(vRows[0].x,vRows[1].x,vRows[2].x, + vRows[0].y,vRows[1].y,vRows[2].y, + vRows[0].z,vRows[1].z,vRows[2].z); + + // and generate the rotation quaternion from it + rotation = aiQuaterniont(m); +} + +// ---------------------------------------------------------------------------------------- +template +inline void aiMatrix4x4t::DecomposeNoScaling (aiQuaterniont& rotation, + aiVector3t& position) const +{ + const aiMatrix4x4t& _this = *this; + + // extract translation + position.x = _this[0][3]; + position.y = _this[1][3]; + position.z = _this[2][3]; + + // extract rotation + rotation = aiQuaterniont((aiMatrix3x3t)_this); +} + +// ---------------------------------------------------------------------------------------- +template +inline aiMatrix4x4t& aiMatrix4x4t::FromEulerAnglesXYZ(const aiVector3t& blubb) +{ + return FromEulerAnglesXYZ(blubb.x,blubb.y,blubb.z); +} + +// ---------------------------------------------------------------------------------------- +template +inline aiMatrix4x4t& aiMatrix4x4t::FromEulerAnglesXYZ(TReal x, TReal y, TReal z) +{ + aiMatrix4x4t& _this = *this; + + TReal cr = cos( x ); + TReal sr = sin( x ); + TReal cp = cos( y ); + TReal sp = sin( y ); + TReal cy = cos( z ); + TReal sy = sin( z ); + + _this.a1 = cp*cy ; + _this.a2 = cp*sy; + _this.a3 = -sp ; + + TReal srsp = sr*sp; + TReal crsp = cr*sp; + + _this.b1 = srsp*cy-cr*sy ; + _this.b2 = srsp*sy+cr*cy ; + _this.b3 = sr*cp ; + + _this.c1 = crsp*cy+sr*sy ; + _this.c2 = crsp*sy-sr*cy ; + _this.c3 = cr*cp ; + + return *this; +} + +// ---------------------------------------------------------------------------------------- +template +inline bool aiMatrix4x4t::IsIdentity() const +{ + // Use a small epsilon to solve floating-point inaccuracies + const static TReal epsilon = 10e-3f; + + return (a2 <= epsilon && a2 >= -epsilon && + a3 <= epsilon && a3 >= -epsilon && + a4 <= epsilon && a4 >= -epsilon && + b1 <= epsilon && b1 >= -epsilon && + b3 <= epsilon && b3 >= -epsilon && + b4 <= epsilon && b4 >= -epsilon && + c1 <= epsilon && c1 >= -epsilon && + c2 <= epsilon && c2 >= -epsilon && + c4 <= epsilon && c4 >= -epsilon && + d1 <= epsilon && d1 >= -epsilon && + d2 <= epsilon && d2 >= -epsilon && + d3 <= epsilon && d3 >= -epsilon && + a1 <= 1.f+epsilon && a1 >= 1.f-epsilon && + b2 <= 1.f+epsilon && b2 >= 1.f-epsilon && + c3 <= 1.f+epsilon && c3 >= 1.f-epsilon && + d4 <= 1.f+epsilon && d4 >= 1.f-epsilon); +} + +// ---------------------------------------------------------------------------------------- +template +inline aiMatrix4x4t& aiMatrix4x4t::RotationX(TReal a, aiMatrix4x4t& out) +{ + /* + | 1 0 0 0 | + M = | 0 cos(A) -sin(A) 0 | + | 0 sin(A) cos(A) 0 | + | 0 0 0 1 | */ + out = aiMatrix4x4t(); + out.b2 = out.c3 = cos(a); + out.b3 = -(out.c2 = sin(a)); + return out; +} + +// ---------------------------------------------------------------------------------------- +template +inline aiMatrix4x4t& aiMatrix4x4t::RotationY(TReal a, aiMatrix4x4t& out) +{ + /* + | cos(A) 0 sin(A) 0 | + M = | 0 1 0 0 | + | -sin(A) 0 cos(A) 0 | + | 0 0 0 1 | + */ + out = aiMatrix4x4t(); + out.a1 = out.c3 = cos(a); + out.c1 = -(out.a3 = sin(a)); + return out; +} + +// ---------------------------------------------------------------------------------------- +template +inline aiMatrix4x4t& aiMatrix4x4t::RotationZ(TReal a, aiMatrix4x4t& out) +{ + /* + | cos(A) -sin(A) 0 0 | + M = | sin(A) cos(A) 0 0 | + | 0 0 1 0 | + | 0 0 0 1 | */ + out = aiMatrix4x4t(); + out.a1 = out.b2 = cos(a); + out.a2 = -(out.b1 = sin(a)); + return out; +} + +// ---------------------------------------------------------------------------------------- +// Returns a rotation matrix for a rotation around an arbitrary axis. +template +inline aiMatrix4x4t& aiMatrix4x4t::Rotation( TReal a, const aiVector3t& axis, aiMatrix4x4t& out) +{ + TReal c = cos( a), s = sin( a), t = 1 - c; + TReal x = axis.x, y = axis.y, z = axis.z; + + // Many thanks to MathWorld and Wikipedia + out.a1 = t*x*x + c; out.a2 = t*x*y - s*z; out.a3 = t*x*z + s*y; + out.b1 = t*x*y + s*z; out.b2 = t*y*y + c; out.b3 = t*y*z - s*x; + out.c1 = t*x*z - s*y; out.c2 = t*y*z + s*x; out.c3 = t*z*z + c; + out.a4 = out.b4 = out.c4 = static_cast(0.0); + out.d1 = out.d2 = out.d3 = static_cast(0.0); + out.d4 = static_cast(1.0); + + return out; +} + +// ---------------------------------------------------------------------------------------- +template +inline aiMatrix4x4t& aiMatrix4x4t::Translation( const aiVector3t& v, aiMatrix4x4t& out) +{ + out = aiMatrix4x4t(); + out.a4 = v.x; + out.b4 = v.y; + out.c4 = v.z; + return out; +} + +// ---------------------------------------------------------------------------------------- +template +inline aiMatrix4x4t& aiMatrix4x4t::Scaling( const aiVector3t& v, aiMatrix4x4t& out) +{ + out = aiMatrix4x4t(); + out.a1 = v.x; + out.b2 = v.y; + out.c3 = v.z; + return out; +} + +// ---------------------------------------------------------------------------------------- +/** A function for creating a rotation matrix that rotates a vector called + * "from" into another vector called "to". + * Input : from[3], to[3] which both must be *normalized* non-zero vectors + * Output: mtx[3][3] -- a 3x3 matrix in colum-major form + * Authors: Tomas Möller, John Hughes + * "Efficiently Building a Matrix to Rotate One Vector to Another" + * Journal of Graphics Tools, 4(4):1-4, 1999 + */ +// ---------------------------------------------------------------------------------------- +template +inline aiMatrix4x4t& aiMatrix4x4t::FromToMatrix(const aiVector3t& from, + const aiVector3t& to, aiMatrix4x4t& mtx) +{ + aiMatrix3x3t m3; + aiMatrix3x3t::FromToMatrix(from,to,m3); + mtx = aiMatrix4x4t(m3); + return mtx; +} + +#endif // __cplusplus +#endif // AI_MATRIX4x4_INL_INC diff --git a/Lib/Include/assimp/mesh.h b/Lib/Include/assimp/mesh.h new file mode 100644 index 0000000..0f867fe --- /dev/null +++ b/Lib/Include/assimp/mesh.h @@ -0,0 +1,734 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2012, assimp team + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following +conditions are met: + +* Redistributions of source code must retain the above + copyright notice, this list of conditions and the + following disclaimer. + +* Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other + materials provided with the distribution. + +* Neither the name of the assimp team, nor the names of its + contributors may be used to endorse or promote products + derived from this software without specific prior + written permission of the assimp team. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"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 COPYRIGHT +OWNER OR CONTRIBUTORS 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. +--------------------------------------------------------------------------- +*/ + +/** @file mesh.h + * @brief Declares the data structures in which the imported geometry is + returned by ASSIMP: aiMesh, aiFace and aiBone data structures. + */ +#ifndef INCLUDED_AI_MESH_H +#define INCLUDED_AI_MESH_H + +#include "types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// --------------------------------------------------------------------------- +// Limits. These values are required to match the settings Assimp was +// compiled against. Therfore, do not redefine them unless you build the +// library from source using the same definitions. +// --------------------------------------------------------------------------- + +/** @def AI_MAX_FACE_INDICES + * Maximum number of indices per face (polygon). */ + +#ifndef AI_MAX_FACE_INDICES +# define AI_MAX_FACE_INDICES 0x7fff +#endif + +/** @def AI_MAX_BONE_WEIGHTS + * Maximum number of indices per face (polygon). */ + +#ifndef AI_MAX_BONE_WEIGHTS +# define AI_MAX_BONE_WEIGHTS 0x7fffffff +#endif + +/** @def AI_MAX_VERTICES + * Maximum number of vertices per mesh. */ + +#ifndef AI_MAX_VERTICES +# define AI_MAX_VERTICES 0x7fffffff +#endif + +/** @def AI_MAX_FACES + * Maximum number of faces per mesh. */ + +#ifndef AI_MAX_FACES +# define AI_MAX_FACES 0x7fffffff +#endif + +/** @def AI_MAX_NUMBER_OF_COLOR_SETS + * Supported number of vertex color sets per mesh. */ + +#ifndef AI_MAX_NUMBER_OF_COLOR_SETS +# define AI_MAX_NUMBER_OF_COLOR_SETS 0x8 +#endif // !! AI_MAX_NUMBER_OF_COLOR_SETS + +/** @def AI_MAX_NUMBER_OF_TEXTURECOORDS + * Supported number of texture coord sets (UV(W) channels) per mesh */ + +#ifndef AI_MAX_NUMBER_OF_TEXTURECOORDS +# define AI_MAX_NUMBER_OF_TEXTURECOORDS 0x8 +#endif // !! AI_MAX_NUMBER_OF_TEXTURECOORDS + +// --------------------------------------------------------------------------- +/** @brief A single face in a mesh, referring to multiple vertices. + * + * If mNumIndices is 3, we call the face 'triangle', for mNumIndices > 3 + * it's called 'polygon' (hey, that's just a definition!). + *
    + * aiMesh::mPrimitiveTypes can be queried to quickly examine which types of + * primitive are actually present in a mesh. The #aiProcess_SortByPType flag + * executes a special post-processing algorithm which splits meshes with + * *different* primitive types mixed up (e.g. lines and triangles) in several + * 'clean' submeshes. Furthermore there is a configuration option ( + * #AI_CONFIG_PP_SBP_REMOVE) to force #aiProcess_SortByPType to remove + * specific kinds of primitives from the imported scene, completely and forever. + * In many cases you'll probably want to set this setting to + * @code + * aiPrimitiveType_LINE|aiPrimitiveType_POINT + * @endcode + * Together with the #aiProcess_Triangulate flag you can then be sure that + * #aiFace::mNumIndices is always 3. + * @note Take a look at the @link data Data Structures page @endlink for + * more information on the layout and winding order of a face. + */ +struct aiFace +{ + //! Number of indices defining this face. + //! The maximum value for this member is #AI_MAX_FACE_INDICES. + unsigned int mNumIndices; + + //! Pointer to the indices array. Size of the array is given in numIndices. + unsigned int* mIndices; + +#ifdef __cplusplus + + //! Default constructor + aiFace() + { + mNumIndices = 0; mIndices = NULL; + } + + //! Default destructor. Delete the index array + ~aiFace() + { + delete [] mIndices; + } + + //! Copy constructor. Copy the index array + aiFace( const aiFace& o) + { + mIndices = NULL; + *this = o; + } + + //! Assignment operator. Copy the index array + const aiFace& operator = ( const aiFace& o) + { + if (&o == this) + return *this; + + delete[] mIndices; + mNumIndices = o.mNumIndices; + mIndices = new unsigned int[mNumIndices]; + ::memcpy( mIndices, o.mIndices, mNumIndices * sizeof( unsigned int)); + return *this; + } + + //! Comparison operator. Checks whether the index array + //! of two faces is identical + bool operator== (const aiFace& o) const + { + if (mIndices == o.mIndices)return true; + else if (mIndices && mNumIndices == o.mNumIndices) + { + for (unsigned int i = 0;i < this->mNumIndices;++i) + if (mIndices[i] != o.mIndices[i])return false; + return true; + } + return false; + } + + //! Inverse comparison operator. Checks whether the index + //! array of two faces is NOT identical + bool operator != (const aiFace& o) const + { + return !(*this == o); + } +#endif // __cplusplus +}; // struct aiFace + + +// --------------------------------------------------------------------------- +/** @brief A single influence of a bone on a vertex. + */ +struct aiVertexWeight +{ + //! Index of the vertex which is influenced by the bone. + unsigned int mVertexId; + + //! The strength of the influence in the range (0...1). + //! The influence from all bones at one vertex amounts to 1. + float mWeight; + +#ifdef __cplusplus + + //! Default constructor + aiVertexWeight() { } + + //! Initialisation from a given index and vertex weight factor + //! \param pID ID + //! \param pWeight Vertex weight factor + aiVertexWeight( unsigned int pID, float pWeight) + : mVertexId( pID), mWeight( pWeight) + { /* nothing to do here */ } + +#endif // __cplusplus +}; + + +// --------------------------------------------------------------------------- +/** @brief A single bone of a mesh. + * + * A bone has a name by which it can be found in the frame hierarchy and by + * which it can be addressed by animations. In addition it has a number of + * influences on vertices. + */ +struct aiBone +{ + //! The name of the bone. + C_STRUCT aiString mName; + + //! The number of vertices affected by this bone + //! The maximum value for this member is #AI_MAX_BONE_WEIGHTS. + unsigned int mNumWeights; + + //! The vertices affected by this bone + C_STRUCT aiVertexWeight* mWeights; + + //! Matrix that transforms from mesh space to bone space in bind pose + C_STRUCT aiMatrix4x4 mOffsetMatrix; + +#ifdef __cplusplus + + //! Default constructor + aiBone() + { + mNumWeights = 0; mWeights = NULL; + } + + //! Copy constructor + aiBone(const aiBone& other) + { + mNumWeights = other.mNumWeights; + mOffsetMatrix = other.mOffsetMatrix; + mName = other.mName; + + if (other.mWeights && other.mNumWeights) + { + mWeights = new aiVertexWeight[mNumWeights]; + ::memcpy(mWeights,other.mWeights,mNumWeights * sizeof(aiVertexWeight)); + } + } + + //! Destructor - deletes the array of vertex weights + ~aiBone() + { + delete [] mWeights; + } +#endif // __cplusplus +}; + + +// --------------------------------------------------------------------------- +/** @brief Enumerates the types of geometric primitives supported by Assimp. + * + * @see aiFace Face data structure + * @see aiProcess_SortByPType Per-primitive sorting of meshes + * @see aiProcess_Triangulate Automatic triangulation + * @see AI_CONFIG_PP_SBP_REMOVE Removal of specific primitive types. + */ +enum aiPrimitiveType +{ + /** A point primitive. + * + * This is just a single vertex in the virtual world, + * #aiFace contains just one index for such a primitive. + */ + aiPrimitiveType_POINT = 0x1, + + /** A line primitive. + * + * This is a line defined through a start and an end position. + * #aiFace contains exactly two indices for such a primitive. + */ + aiPrimitiveType_LINE = 0x2, + + /** A triangular primitive. + * + * A triangle consists of three indices. + */ + aiPrimitiveType_TRIANGLE = 0x4, + + /** A higher-level polygon with more than 3 edges. + * + * A triangle is a polygon, but polygon in this context means + * "all polygons that are not triangles". The "Triangulate"-Step + * is provided for your convenience, it splits all polygons in + * triangles (which are much easier to handle). + */ + aiPrimitiveType_POLYGON = 0x8, + + + /** This value is not used. It is just here to force the + * compiler to map this enum to a 32 Bit integer. + */ +#ifndef SWIG + _aiPrimitiveType_Force32Bit = 0x9fffffff +#endif +}; //! enum aiPrimitiveType + +// Get the #aiPrimitiveType flag for a specific number of face indices +#define AI_PRIMITIVE_TYPE_FOR_N_INDICES(n) \ + ((n) > 3 ? aiPrimitiveType_POLYGON : (aiPrimitiveType)(1u << ((n)-1))) + + + +// --------------------------------------------------------------------------- +/** @brief NOT CURRENTLY IN USE. An AnimMesh is an attachment to an #aiMesh stores per-vertex + * animations for a particular frame. + * + * You may think of an #aiAnimMesh as a `patch` for the host mesh, which + * replaces only certain vertex data streams at a particular time. + * Each mesh stores n attached attached meshes (#aiMesh::mAnimMeshes). + * The actual relationship between the time line and anim meshes is + * established by #aiMeshAnim, which references singular mesh attachments + * by their ID and binds them to a time offset. +*/ +struct aiAnimMesh +{ + /** Replacement for aiMesh::mVertices. If this array is non-NULL, + * it *must* contain mNumVertices entries. The corresponding + * array in the host mesh must be non-NULL as well - animation + * meshes may neither add or nor remove vertex components (if + * a replacement array is NULL and the corresponding source + * array is not, the source data is taken instead)*/ + C_STRUCT aiVector3D* mVertices; + + /** Replacement for aiMesh::mNormals. */ + C_STRUCT aiVector3D* mNormals; + + /** Replacement for aiMesh::mTangents. */ + C_STRUCT aiVector3D* mTangents; + + /** Replacement for aiMesh::mBitangents. */ + C_STRUCT aiVector3D* mBitangents; + + /** Replacement for aiMesh::mColors */ + C_STRUCT aiColor4D* mColors[AI_MAX_NUMBER_OF_COLOR_SETS]; + + /** Replacement for aiMesh::mTextureCoords */ + C_STRUCT aiVector3D* mTextureCoords[AI_MAX_NUMBER_OF_TEXTURECOORDS]; + + /** The number of vertices in the aiAnimMesh, and thus the length of all + * the member arrays. + * + * This has always the same value as the mNumVertices property in the + * corresponding aiMesh. It is duplicated here merely to make the length + * of the member arrays accessible even if the aiMesh is not known, e.g. + * from language bindings. + */ + unsigned int mNumVertices; + +#ifdef __cplusplus + + aiAnimMesh() + : mVertices() + , mNormals() + , mTangents() + , mBitangents() + { + // fixme consider moving this to the ctor initializer list as well + for( unsigned int a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; a++){ + mTextureCoords[a] = NULL; + } + for( unsigned int a = 0; a < AI_MAX_NUMBER_OF_COLOR_SETS; a++) { + mColors[a] = NULL; + } + } + + ~aiAnimMesh() + { + delete [] mVertices; + delete [] mNormals; + delete [] mTangents; + delete [] mBitangents; + for( unsigned int a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; a++) { + delete [] mTextureCoords[a]; + } + for( unsigned int a = 0; a < AI_MAX_NUMBER_OF_COLOR_SETS; a++) { + delete [] mColors[a]; + } + } + + /** Check whether the anim mesh overrides the vertex positions + * of its host mesh*/ + bool HasPositions() const { + return mVertices != NULL; + } + + /** Check whether the anim mesh overrides the vertex normals + * of its host mesh*/ + bool HasNormals() const { + return mNormals != NULL; + } + + /** Check whether the anim mesh overrides the vertex tangents + * and bitangents of its host mesh. As for aiMesh, + * tangents and bitangents always go together. */ + bool HasTangentsAndBitangents() const { + return mTangents != NULL; + } + + /** Check whether the anim mesh overrides a particular + * set of vertex colors on his host mesh. + * @param pIndex 0= AI_MAX_NUMBER_OF_COLOR_SETS ? false : mColors[pIndex] != NULL; + } + + /** Check whether the anim mesh overrides a particular + * set of texture coordinates on his host mesh. + * @param pIndex 0= AI_MAX_NUMBER_OF_TEXTURECOORDS ? false : mTextureCoords[pIndex] != NULL; + } + +#endif +}; + + +// --------------------------------------------------------------------------- +/** @brief A mesh represents a geometry or model with a single material. +* +* It usually consists of a number of vertices and a series of primitives/faces +* referencing the vertices. In addition there might be a series of bones, each +* of them addressing a number of vertices with a certain weight. Vertex data +* is presented in channels with each channel containing a single per-vertex +* information such as a set of texture coords or a normal vector. +* If a data pointer is non-null, the corresponding data stream is present. +* From C++-programs you can also use the comfort functions Has*() to +* test for the presence of various data streams. +* +* A Mesh uses only a single material which is referenced by a material ID. +* @note The mPositions member is usually not optional. However, vertex positions +* *could* be missing if the #AI_SCENE_FLAGS_INCOMPLETE flag is set in +* @code +* aiScene::mFlags +* @endcode +*/ +struct aiMesh +{ + /** Bitwise combination of the members of the #aiPrimitiveType enum. + * This specifies which types of primitives are present in the mesh. + * The "SortByPrimitiveType"-Step can be used to make sure the + * output meshes consist of one primitive type each. + */ + unsigned int mPrimitiveTypes; + + /** The number of vertices in this mesh. + * This is also the size of all of the per-vertex data arrays. + * The maximum value for this member is #AI_MAX_VERTICES. + */ + unsigned int mNumVertices; + + /** The number of primitives (triangles, polygons, lines) in this mesh. + * This is also the size of the mFaces array. + * The maximum value for this member is #AI_MAX_FACES. + */ + unsigned int mNumFaces; + + /** Vertex positions. + * This array is always present in a mesh. The array is + * mNumVertices in size. + */ + C_STRUCT aiVector3D* mVertices; + + /** Vertex normals. + * The array contains normalized vectors, NULL if not present. + * The array is mNumVertices in size. Normals are undefined for + * point and line primitives. A mesh consisting of points and + * lines only may not have normal vectors. Meshes with mixed + * primitive types (i.e. lines and triangles) may have normals, + * but the normals for vertices that are only referenced by + * point or line primitives are undefined and set to QNaN (WARN: + * qNaN compares to inequal to *everything*, even to qNaN itself. + * Using code like this to check whether a field is qnan is: + * @code + * #define IS_QNAN(f) (f != f) + * @endcode + * still dangerous because even 1.f == 1.f could evaluate to false! ( + * remember the subtleties of IEEE754 artithmetics). Use stuff like + * @c fpclassify instead. + * @note Normal vectors computed by Assimp are always unit-length. + * However, this needn't apply for normals that have been taken + * directly from the model file. + */ + C_STRUCT aiVector3D* mNormals; + + /** Vertex tangents. + * The tangent of a vertex points in the direction of the positive + * X texture axis. The array contains normalized vectors, NULL if + * not present. The array is mNumVertices in size. A mesh consisting + * of points and lines only may not have normal vectors. Meshes with + * mixed primitive types (i.e. lines and triangles) may have + * normals, but the normals for vertices that are only referenced by + * point or line primitives are undefined and set to qNaN. See + * the #mNormals member for a detailled discussion of qNaNs. + * @note If the mesh contains tangents, it automatically also + * contains bitangents. + */ + C_STRUCT aiVector3D* mTangents; + + /** Vertex bitangents. + * The bitangent of a vertex points in the direction of the positive + * Y texture axis. The array contains normalized vectors, NULL if not + * present. The array is mNumVertices in size. + * @note If the mesh contains tangents, it automatically also contains + * bitangents. + */ + C_STRUCT aiVector3D* mBitangents; + + /** Vertex color sets. + * A mesh may contain 0 to #AI_MAX_NUMBER_OF_COLOR_SETS vertex + * colors per vertex. NULL if not present. Each array is + * mNumVertices in size if present. + */ + C_STRUCT aiColor4D* mColors[AI_MAX_NUMBER_OF_COLOR_SETS]; + + /** Vertex texture coords, also known as UV channels. + * A mesh may contain 0 to AI_MAX_NUMBER_OF_TEXTURECOORDS per + * vertex. NULL if not present. The array is mNumVertices in size. + */ + C_STRUCT aiVector3D* mTextureCoords[AI_MAX_NUMBER_OF_TEXTURECOORDS]; + + /** Specifies the number of components for a given UV channel. + * Up to three channels are supported (UVW, for accessing volume + * or cube maps). If the value is 2 for a given channel n, the + * component p.z of mTextureCoords[n][p] is set to 0.0f. + * If the value is 1 for a given channel, p.y is set to 0.0f, too. + * @note 4D coords are not supported + */ + unsigned int mNumUVComponents[AI_MAX_NUMBER_OF_TEXTURECOORDS]; + + /** The faces the mesh is constructed from. + * Each face refers to a number of vertices by their indices. + * This array is always present in a mesh, its size is given + * in mNumFaces. If the #AI_SCENE_FLAGS_NON_VERBOSE_FORMAT + * is NOT set each face references an unique set of vertices. + */ + C_STRUCT aiFace* mFaces; + + /** The number of bones this mesh contains. + * Can be 0, in which case the mBones array is NULL. + */ + unsigned int mNumBones; + + /** The bones of this mesh. + * A bone consists of a name by which it can be found in the + * frame hierarchy and a set of vertex weights. + */ + C_STRUCT aiBone** mBones; + + /** The material used by this mesh. + * A mesh does use only a single material. If an imported model uses + * multiple materials, the import splits up the mesh. Use this value + * as index into the scene's material list. + */ + unsigned int mMaterialIndex; + + /** Name of the mesh. Meshes can be named, but this is not a + * requirement and leaving this field empty is totally fine. + * There are mainly three uses for mesh names: + * - some formats name nodes and meshes independently. + * - importers tend to split meshes up to meet the + * one-material-per-mesh requirement. Assigning + * the same (dummy) name to each of the result meshes + * aids the caller at recovering the original mesh + * partitioning. + * - Vertex animations refer to meshes by their names. + **/ + C_STRUCT aiString mName; + + + /** NOT CURRENTLY IN USE. The number of attachment meshes */ + unsigned int mNumAnimMeshes; + + /** NOT CURRENTLY IN USE. Attachment meshes for this mesh, for vertex-based animation. + * Attachment meshes carry replacement data for some of the + * mesh'es vertex components (usually positions, normals). */ + C_STRUCT aiAnimMesh** mAnimMeshes; + + +#ifdef __cplusplus + + //! Default constructor. Initializes all members to 0 + aiMesh() + { + mNumVertices = 0; + mNumFaces = 0; + + mNumAnimMeshes = 0; + + mPrimitiveTypes = 0; + mVertices = NULL; mFaces = NULL; + mNormals = NULL; mTangents = NULL; + mBitangents = NULL; + mAnimMeshes = NULL; + + for( unsigned int a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; a++) + { + mNumUVComponents[a] = 0; + mTextureCoords[a] = NULL; + } + for( unsigned int a = 0; a < AI_MAX_NUMBER_OF_COLOR_SETS; a++) + mColors[a] = NULL; + mNumBones = 0; mBones = NULL; + mMaterialIndex = 0; + mNumAnimMeshes = 0; + mAnimMeshes = NULL; + } + + //! Deletes all storage allocated for the mesh + ~aiMesh() + { + delete [] mVertices; + delete [] mNormals; + delete [] mTangents; + delete [] mBitangents; + for( unsigned int a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; a++) { + delete [] mTextureCoords[a]; + } + for( unsigned int a = 0; a < AI_MAX_NUMBER_OF_COLOR_SETS; a++) { + delete [] mColors[a]; + } + + // DO NOT REMOVE THIS ADDITIONAL CHECK + if (mNumBones && mBones) { + for( unsigned int a = 0; a < mNumBones; a++) { + delete mBones[a]; + } + delete [] mBones; + } + + if (mNumAnimMeshes && mAnimMeshes) { + for( unsigned int a = 0; a < mNumAnimMeshes; a++) { + delete mAnimMeshes[a]; + } + delete [] mAnimMeshes; + } + + delete [] mFaces; + } + + //! Check whether the mesh contains positions. Provided no special + //! scene flags are set (such as #AI_SCENE_FLAGS_ANIM_SKELETON_ONLY), + //! this will always be true + bool HasPositions() const + { return mVertices != NULL && mNumVertices > 0; } + + //! Check whether the mesh contains faces. If no special scene flags + //! are set this should always return true + bool HasFaces() const + { return mFaces != NULL && mNumFaces > 0; } + + //! Check whether the mesh contains normal vectors + bool HasNormals() const + { return mNormals != NULL && mNumVertices > 0; } + + //! Check whether the mesh contains tangent and bitangent vectors + //! It is not possible that it contains tangents and no bitangents + //! (or the other way round). The existence of one of them + //! implies that the second is there, too. + bool HasTangentsAndBitangents() const + { return mTangents != NULL && mBitangents != NULL && mNumVertices > 0; } + + //! Check whether the mesh contains a vertex color set + //! \param pIndex Index of the vertex color set + bool HasVertexColors( unsigned int pIndex) const + { + if( pIndex >= AI_MAX_NUMBER_OF_COLOR_SETS) + return false; + else + return mColors[pIndex] != NULL && mNumVertices > 0; + } + + //! Check whether the mesh contains a texture coordinate set + //! \param pIndex Index of the texture coordinates set + bool HasTextureCoords( unsigned int pIndex) const + { + if( pIndex >= AI_MAX_NUMBER_OF_TEXTURECOORDS) + return false; + else + return mTextureCoords[pIndex] != NULL && mNumVertices > 0; + } + + //! Get the number of UV channels the mesh contains + unsigned int GetNumUVChannels() const + { + unsigned int n = 0; + while (n < AI_MAX_NUMBER_OF_TEXTURECOORDS && mTextureCoords[n])++n; + return n; + } + + //! Get the number of vertex color channels the mesh contains + unsigned int GetNumColorChannels() const + { + unsigned int n = 0; + while (n < AI_MAX_NUMBER_OF_COLOR_SETS && mColors[n])++n; + return n; + } + + //! Check whether the mesh contains bones + inline bool HasBones() const + { return mBones != NULL && mNumBones > 0; } + +#endif // __cplusplus +}; + + +#ifdef __cplusplus +} +#endif //! extern "C" +#endif // __AI_MESH_H_INC + diff --git a/Lib/Include/assimp/postprocess.h b/Lib/Include/assimp/postprocess.h new file mode 100644 index 0000000..26060a7 --- /dev/null +++ b/Lib/Include/assimp/postprocess.h @@ -0,0 +1,631 @@ +/* +Open Asset Import Library (assimp) +---------------------------------------------------------------------- + +Copyright (c) 2006-2012, assimp team +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the +following conditions are met: + +* Redistributions of source code must retain the above + copyright notice, this list of conditions and the + following disclaimer. + +* Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other + materials provided with the distribution. + +* Neither the name of the assimp team, nor the names of its + contributors may be used to endorse or promote products + derived from this software without specific prior + written permission of the assimp team. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"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 COPYRIGHT +OWNER OR CONTRIBUTORS 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. + +---------------------------------------------------------------------- +*/ + +/** @file postprocess.h + * @brief Definitions for import post processing steps + */ +#ifndef AI_POSTPROCESS_H_INC +#define AI_POSTPROCESS_H_INC + +#include "types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// ----------------------------------------------------------------------------------- +/** @enum aiPostProcessSteps + * @brief Defines the flags for all possible post processing steps. + * + * @see Importer::ReadFile + * @see aiImportFile + * @see aiImportFileEx + */ +// ----------------------------------------------------------------------------------- +enum aiPostProcessSteps +{ + + // ------------------------------------------------------------------------- + /**
    Calculates the tangents and bitangents for the imported meshes. + * + * Does nothing if a mesh does not have normals. You might want this post + * processing step to be executed if you plan to use tangent space calculations + * such as normal mapping applied to the meshes. There's a config setting, + * #AI_CONFIG_PP_CT_MAX_SMOOTHING_ANGLE, which allows you to specify + * a maximum smoothing angle for the algorithm. However, usually you'll + * want to leave it at the default value. + */ + aiProcess_CalcTangentSpace = 0x1, + + // ------------------------------------------------------------------------- + /**
    Identifies and joins identical vertex data sets within all + * imported meshes. + * + * After this step is run, each mesh contains unique vertices, + * so a vertex may be used by multiple faces. You usually want + * to use this post processing step. If your application deals with + * indexed geometry, this step is compulsory or you'll just waste rendering + * time. If this flag is not specified, no vertices are referenced by + * more than one face and no index buffer is required for rendering. + */ + aiProcess_JoinIdenticalVertices = 0x2, + + // ------------------------------------------------------------------------- + /**
    Converts all the imported data to a left-handed coordinate space. + * + * By default the data is returned in a right-handed coordinate space (which + * OpenGL prefers). In this space, +X points to the right, + * +Z points towards the viewer, and +Y points upwards. In the DirectX + * coordinate space +X points to the right, +Y points upwards, and +Z points + * away from the viewer. + * + * You'll probably want to consider this flag if you use Direct3D for + * rendering. The #aiProcess_ConvertToLeftHanded flag supersedes this + * setting and bundles all conversions typically required for D3D-based + * applications. + */ + aiProcess_MakeLeftHanded = 0x4, + + // ------------------------------------------------------------------------- + /**
    Triangulates all faces of all meshes. + * + * By default the imported mesh data might contain faces with more than 3 + * indices. For rendering you'll usually want all faces to be triangles. + * This post processing step splits up faces with more than 3 indices into + * triangles. Line and point primitives are *not* modified! If you want + * 'triangles only' with no other kinds of primitives, try the following + * solution: + *
      + *
    • Specify both #aiProcess_Triangulate and #aiProcess_SortByPType
    • + * Ignore all point and line meshes when you process assimp's output + *
    + */ + aiProcess_Triangulate = 0x8, + + // ------------------------------------------------------------------------- + /**
    Removes some parts of the data structure (animations, materials, + * light sources, cameras, textures, vertex components). + * + * The components to be removed are specified in a separate + * configuration option, #AI_CONFIG_PP_RVC_FLAGS. This is quite useful + * if you don't need all parts of the output structure. Vertex colors + * are rarely used today for example... Calling this step to remove unneeded + * data from the pipeline as early as possible results in increased + * performance and a more optimized output data structure. + * This step is also useful if you want to force Assimp to recompute + * normals or tangents. The corresponding steps don't recompute them if + * they're already there (loaded from the source asset). By using this + * step you can make sure they are NOT there. + * + * This flag is a poor one, mainly because its purpose is usually + * misunderstood. Consider the following case: a 3D model has been exported + * from a CAD app, and it has per-face vertex colors. Vertex positions can't be + * shared, thus the #aiProcess_JoinIdenticalVertices step fails to + * optimize the data because of these nasty little vertex colors. + * Most apps don't even process them, so it's all for nothing. By using + * this step, unneeded components are excluded as early as possible + * thus opening more room for internal optimizations. + */ + aiProcess_RemoveComponent = 0x10, + + // ------------------------------------------------------------------------- + /**
    Generates normals for all faces of all meshes. + * + * This is ignored if normals are already there at the time this flag + * is evaluated. Model importers try to load them from the source file, so + * they're usually already there. Face normals are shared between all points + * of a single face, so a single point can have multiple normals, which + * forces the library to duplicate vertices in some cases. + * #aiProcess_JoinIdenticalVertices is *senseless* then. + * + * This flag may not be specified together with #aiProcess_GenSmoothNormals. + */ + aiProcess_GenNormals = 0x20, + + // ------------------------------------------------------------------------- + /**
    Generates smooth normals for all vertices in the mesh. + * + * This is ignored if normals are already there at the time this flag + * is evaluated. Model importers try to load them from the source file, so + * they're usually already there. + * + * This flag may not be specified together with + * #aiProcess_GenNormals. There's a configuration option, + * #AI_CONFIG_PP_GSN_MAX_SMOOTHING_ANGLE which allows you to specify + * an angle maximum for the normal smoothing algorithm. Normals exceeding + * this limit are not smoothed, resulting in a 'hard' seam between two faces. + * Using a decent angle here (e.g. 80 degrees) results in very good visual + * appearance. + */ + aiProcess_GenSmoothNormals = 0x40, + + // ------------------------------------------------------------------------- + /**
    Splits large meshes into smaller sub-meshes. + * + * This is quite useful for real-time rendering, where the number of triangles + * which can be maximally processed in a single draw-call is limited + * by the video driver/hardware. The maximum vertex buffer is usually limited + * too. Both requirements can be met with this step: you may specify both a + * triangle and vertex limit for a single mesh. + * + * The split limits can (and should!) be set through the + * #AI_CONFIG_PP_SLM_VERTEX_LIMIT and #AI_CONFIG_PP_SLM_TRIANGLE_LIMIT + * settings. The default values are #AI_SLM_DEFAULT_MAX_VERTICES and + * #AI_SLM_DEFAULT_MAX_TRIANGLES. + * + * Note that splitting is generally a time-consuming task, but only if there's + * something to split. The use of this step is recommended for most users. + */ + aiProcess_SplitLargeMeshes = 0x80, + + // ------------------------------------------------------------------------- + /**
    Removes the node graph and pre-transforms all vertices with + * the local transformation matrices of their nodes. + * + * The output scene still contains nodes, however there is only a + * root node with children, each one referencing only one mesh, + * and each mesh referencing one material. For rendering, you can + * simply render all meshes in order - you don't need to pay + * attention to local transformations and the node hierarchy. + * Animations are removed during this step. + * This step is intended for applications without a scenegraph. + * The step CAN cause some problems: if e.g. a mesh of the asset + * contains normals and another, using the same material index, does not, + * they will be brought together, but the first meshes's part of + * the normal list is zeroed. However, these artifacts are rare. + * @note The #AI_CONFIG_PP_PTV_NORMALIZE configuration property + * can be set to normalize the scene's spatial dimension to the -1...1 + * range. + */ + aiProcess_PreTransformVertices = 0x100, + + // ------------------------------------------------------------------------- + /**
    Limits the number of bones simultaneously affecting a single vertex + * to a maximum value. + * + * If any vertex is affected by more than the maximum number of bones, the least + * important vertex weights are removed and the remaining vertex weights are + * renormalized so that the weights still sum up to 1. + * The default bone weight limit is 4 (defined as #AI_LMW_MAX_WEIGHTS in + * config.h), but you can use the #AI_CONFIG_PP_LBW_MAX_WEIGHTS setting to + * supply your own limit to the post processing step. + * + * If you intend to perform the skinning in hardware, this post processing + * step might be of interest to you. + */ + aiProcess_LimitBoneWeights = 0x200, + + // ------------------------------------------------------------------------- + /**
    Validates the imported scene data structure. + * This makes sure that all indices are valid, all animations and + * bones are linked correctly, all material references are correct .. etc. + * + * It is recommended that you capture Assimp's log output if you use this flag, + * so you can easily find out what's wrong if a file fails the + * validation. The validator is quite strict and will find *all* + * inconsistencies in the data structure... It is recommended that plugin + * developers use it to debug their loaders. There are two types of + * validation failures: + *
      + *
    • Error: There's something wrong with the imported data. Further + * postprocessing is not possible and the data is not usable at all. + * The import fails. #Importer::GetErrorString() or #aiGetErrorString() + * carry the error message around.
    • + *
    • Warning: There are some minor issues (e.g. 1000000 animation + * keyframes with the same time), but further postprocessing and use + * of the data structure is still safe. Warning details are written + * to the log file, #AI_SCENE_FLAGS_VALIDATION_WARNING is set + * in #aiScene::mFlags
    • + *
    + * + * This post-processing step is not time-consuming. Its use is not + * compulsory, but recommended. + */ + aiProcess_ValidateDataStructure = 0x400, + + // ------------------------------------------------------------------------- + /**
    Reorders triangles for better vertex cache locality. + * + * The step tries to improve the ACMR (average post-transform vertex cache + * miss ratio) for all meshes. The implementation runs in O(n) and is + * roughly based on the 'tipsify' algorithm (see
    this + * paper). + * + * If you intend to render huge models in hardware, this step might + * be of interest to you. The #AI_CONFIG_PP_ICL_PTCACHE_SIZEconfig + * setting can be used to fine-tune the cache optimization. + */ + aiProcess_ImproveCacheLocality = 0x800, + + // ------------------------------------------------------------------------- + /**
    Searches for redundant/unreferenced materials and removes them. + * + * This is especially useful in combination with the + * #aiProcess_PretransformVertices and #aiProcess_OptimizeMeshes flags. + * Both join small meshes with equal characteristics, but they can't do + * their work if two meshes have different materials. Because several + * material settings are lost during Assimp's import filters, + * (and because many exporters don't check for redundant materials), huge + * models often have materials which are are defined several times with + * exactly the same settings. + * + * Several material settings not contributing to the final appearance of + * a surface are ignored in all comparisons (e.g. the material name). + * So, if you're passing additional information through the + * content pipeline (probably using *magic* material names), don't + * specify this flag. Alternatively take a look at the + * #AI_CONFIG_PP_RRM_EXCLUDE_LIST setting. + */ + aiProcess_RemoveRedundantMaterials = 0x1000, + + // ------------------------------------------------------------------------- + /**
    This step tries to determine which meshes have normal vectors + * that are facing inwards and inverts them. + * + * The algorithm is simple but effective: + * the bounding box of all vertices + their normals is compared against + * the volume of the bounding box of all vertices without their normals. + * This works well for most objects, problems might occur with planar + * surfaces. However, the step tries to filter such cases. + * The step inverts all in-facing normals. Generally it is recommended + * to enable this step, although the result is not always correct. + */ + aiProcess_FixInfacingNormals = 0x2000, + + // ------------------------------------------------------------------------- + /**
    This step splits meshes with more than one primitive type in + * homogeneous sub-meshes. + * + * The step is executed after the triangulation step. After the step + * returns, just one bit is set in aiMesh::mPrimitiveTypes. This is + * especially useful for real-time rendering where point and line + * primitives are often ignored or rendered separately. + * You can use the #AI_CONFIG_PP_SBP_REMOVE option to specify which + * primitive types you need. This can be used to easily exclude + * lines and points, which are rarely used, from the import. + */ + aiProcess_SortByPType = 0x8000, + + // ------------------------------------------------------------------------- + /**
    This step searches all meshes for degenerate primitives and + * converts them to proper lines or points. + * + * A face is 'degenerate' if one or more of its points are identical. + * To have the degenerate stuff not only detected and collapsed but + * removed, try one of the following procedures: + *
    1. (if you support lines and points for rendering but don't + * want the degenerates)
    + *
      + *
    • Specify the #aiProcess_FindDegenerates flag. + *
    • + *
    • Set the AI_CONFIG_PP_FD_REMOVE option to 1. This will + * cause the step to remove degenerate triangles from the import + * as soon as they're detected. They won't pass any further + * pipeline steps. + *
    • + *
    + *
    2.(if you don't support lines and points at all)
    + *
      + *
    • Specify the #aiProcess_FindDegenerates flag. + *
    • + *
    • Specify the #aiProcess_SortByPType flag. This moves line and + * point primitives to separate meshes. + *
    • + *
    • Set the AI_CONFIG_PP_SBP_REMOVE option to + * @code aiPrimitiveType_POINTS | aiPrimitiveType_LINES + * @endcode to cause SortByPType to reject point + * and line meshes from the scene. + *
    • + *
    + * @note Degenerate polygons are not necessarily evil and that's why + * they're not removed by default. There are several file formats which + * don't support lines or points, and some exporters bypass the + * format specification and write them as degenerate triangles instead. + */ + aiProcess_FindDegenerates = 0x10000, + + // ------------------------------------------------------------------------- + /**
    This step searches all meshes for invalid data, such as zeroed + * normal vectors or invalid UV coords and removes/fixes them. This is + * intended to get rid of some common exporter errors. + * + * This is especially useful for normals. If they are invalid, and + * the step recognizes this, they will be removed and can later + * be recomputed, i.e. by the #aiProcess_GenSmoothNormals flag.
    + * The step will also remove meshes that are infinitely small and reduce + * animation tracks consisting of hundreds if redundant keys to a single + * key. The AI_CONFIG_PP_FID_ANIM_ACCURACY config property decides + * the accuracy of the check for duplicate animation tracks. + */ + aiProcess_FindInvalidData = 0x20000, + + // ------------------------------------------------------------------------- + /**
    This step converts non-UV mappings (such as spherical or + * cylindrical mapping) to proper texture coordinate channels. + * + * Most applications will support UV mapping only, so you will + * probably want to specify this step in every case. Note that Assimp is not + * always able to match the original mapping implementation of the + * 3D app which produced a model perfectly. It's always better to let the + * modelling app compute the UV channels - 3ds max, Maya, Blender, + * LightWave, and Modo do this for example. + * + * @note If this step is not requested, you'll need to process the + * #AI_MATKEY_MAPPING material property in order to display all assets + * properly. + */ + aiProcess_GenUVCoords = 0x40000, + + // ------------------------------------------------------------------------- + /**
    This step applies per-texture UV transformations and bakes + * them into stand-alone vtexture coordinate channels. + * + * UV transformations are specified per-texture - see the + * #AI_MATKEY_UVTRANSFORM material key for more information. + * This step processes all textures with + * transformed input UV coordinates and generates a new (pre-transformed) UV channel + * which replaces the old channel. Most applications won't support UV + * transformations, so you will probably want to specify this step. + * + * @note UV transformations are usually implemented in real-time apps by + * transforming texture coordinates at vertex shader stage with a 3x3 + * (homogenous) transformation matrix. + */ + aiProcess_TransformUVCoords = 0x80000, + + // ------------------------------------------------------------------------- + /**
    This step searches for duplicate meshes and replaces them + * with references to the first mesh. + * + * This step takes a while, so don't use it if speed is a concern. + * Its main purpose is to workaround the fact that many export + * file formats don't support instanced meshes, so exporters need to + * duplicate meshes. This step removes the duplicates again. Please + * note that Assimp does not currently support per-node material + * assignment to meshes, which means that identical meshes with + * different materials are currently *not* joined, although this is + * planned for future versions. + */ + aiProcess_FindInstances = 0x100000, + + // ------------------------------------------------------------------------- + /**
    A postprocessing step to reduce the number of meshes. + * + * This will, in fact, reduce the number of draw calls. + * + * This is a very effective optimization and is recommended to be used + * together with #aiProcess_OptimizeGraph, if possible. The flag is fully + * compatible with both #aiProcess_SplitLargeMeshes and #aiProcess_SortByPType. + */ + aiProcess_OptimizeMeshes = 0x200000, + + + // ------------------------------------------------------------------------- + /**
    A postprocessing step to optimize the scene hierarchy. + * + * Nodes without animations, bones, lights or cameras assigned are + * collapsed and joined. + * + * Node names can be lost during this step. If you use special 'tag nodes' + * to pass additional information through your content pipeline, use the + * #AI_CONFIG_PP_OG_EXCLUDE_LIST setting to specify a list of node + * names you want to be kept. Nodes matching one of the names in this list won't + * be touched or modified. + * + * Use this flag with caution. Most simple files will be collapsed to a + * single node, so complex hierarchies are usually completely lost. This is not + * useful for editor environments, but probably a very effective + * optimization if you just want to get the model data, convert it to your + * own format, and render it as fast as possible. + * + * This flag is designed to be used with #aiProcess_OptimizeMeshes for best + * results. + * + * @note 'Crappy' scenes with thousands of extremely small meshes packed + * in deeply nested nodes exist for almost all file formats. + * #aiProcess_OptimizeMeshes in combination with #aiProcess_OptimizeGraph + * usually fixes them all and makes them renderable. + */ + aiProcess_OptimizeGraph = 0x400000, + + // ------------------------------------------------------------------------- + /**
    This step flips all UV coordinates along the y-axis and adjusts + * material settings and bitangents accordingly. + * + * Output UV coordinate system: + * @code + * 0y|0y ---------- 1x|0y + * | | + * | | + * | | + * 0x|1y ---------- 1x|1y + * @endcode + * + * You'll probably want to consider this flag if you use Direct3D for + * rendering. The #aiProcess_ConvertToLeftHanded flag supersedes this + * setting and bundles all conversions typically required for D3D-based + * applications. + */ + aiProcess_FlipUVs = 0x800000, + + // ------------------------------------------------------------------------- + /**
    This step adjusts the output face winding order to be CW. + * + * The default face winding order is counter clockwise (CCW). + * + * Output face order: + * @code + * x2 + * + * x0 + * x1 + * @endcode + */ + aiProcess_FlipWindingOrder = 0x1000000, + + // ------------------------------------------------------------------------- + /**
    This step splits meshes with many bones into sub-meshes so that each + * su-bmesh has fewer or as many bones as a given limit. + */ + aiProcess_SplitByBoneCount = 0x2000000, + + // ------------------------------------------------------------------------- + /**
    This step removes bones losslessly or according to some threshold. + * + * In some cases (i.e. formats that require it) exporters are forced to + * assign dummy bone weights to otherwise static meshes assigned to + * animated meshes. Full, weight-based skinning is expensive while + * animating nodes is extremely cheap, so this step is offered to clean up + * the data in that regard. + * + * Use #AI_CONFIG_PP_DB_THRESHOLD to control this. + * Use #AI_CONFIG_PP_DB_ALL_OR_NONE if you want bones removed if and + * only if all bones within the scene qualify for removal. + */ + aiProcess_Debone = 0x4000000 + + // aiProcess_GenEntityMeshes = 0x100000, + // aiProcess_OptimizeAnimations = 0x200000 + // aiProcess_FixTexturePaths = 0x200000 +}; + + +// --------------------------------------------------------------------------------------- +/** @def aiProcess_ConvertToLeftHanded + * @brief Shortcut flag for Direct3D-based applications. + * + * Supersedes the #aiProcess_MakeLeftHanded and #aiProcess_FlipUVs and + * #aiProcess_FlipWindingOrder flags. + * The output data matches Direct3D's conventions: left-handed geometry, upper-left + * origin for UV coordinates and finally clockwise face order, suitable for CCW culling. + * + * @deprecated + */ +#define aiProcess_ConvertToLeftHanded ( \ + aiProcess_MakeLeftHanded | \ + aiProcess_FlipUVs | \ + aiProcess_FlipWindingOrder | \ + 0 ) + + +// --------------------------------------------------------------------------------------- +/** @def aiProcessPreset_TargetRealtimeUse_Fast + * @brief Default postprocess configuration optimizing the data for real-time rendering. + * + * Applications would want to use this preset to load models on end-user PCs, + * maybe for direct use in game. + * + * If you're using DirectX, don't forget to combine this value with + * the #aiProcess_ConvertToLeftHanded step. If you don't support UV transformations + * in your application apply the #aiProcess_TransformUVCoords step, too. + * @note Please take the time to read the docs for the steps enabled by this preset. + * Some of them offer further configurable properties, while some of them might not be of + * use for you so it might be better to not specify them. + */ +#define aiProcessPreset_TargetRealtime_Fast ( \ + aiProcess_CalcTangentSpace | \ + aiProcess_GenNormals | \ + aiProcess_JoinIdenticalVertices | \ + aiProcess_Triangulate | \ + aiProcess_GenUVCoords | \ + aiProcess_SortByPType | \ + 0 ) + + // --------------------------------------------------------------------------------------- + /** @def aiProcessPreset_TargetRealtime_Quality + * @brief Default postprocess configuration optimizing the data for real-time rendering. + * + * Unlike #aiProcessPreset_TargetRealtime_Fast, this configuration + * performs some extra optimizations to improve rendering speed and + * to minimize memory usage. It could be a good choice for a level editor + * environment where import speed is not so important. + * + * If you're using DirectX, don't forget to combine this value with + * the #aiProcess_ConvertToLeftHanded step. If you don't support UV transformations + * in your application apply the #aiProcess_TransformUVCoords step, too. + * @note Please take the time to read the docs for the steps enabled by this preset. + * Some of them offer further configurable properties, while some of them might not be + * of use for you so it might be better to not specify them. + */ +#define aiProcessPreset_TargetRealtime_Quality ( \ + aiProcess_CalcTangentSpace | \ + aiProcess_GenSmoothNormals | \ + aiProcess_JoinIdenticalVertices | \ + aiProcess_ImproveCacheLocality | \ + aiProcess_LimitBoneWeights | \ + aiProcess_RemoveRedundantMaterials | \ + aiProcess_SplitLargeMeshes | \ + aiProcess_Triangulate | \ + aiProcess_GenUVCoords | \ + aiProcess_SortByPType | \ + aiProcess_FindDegenerates | \ + aiProcess_FindInvalidData | \ + 0 ) + + // --------------------------------------------------------------------------------------- + /** @def aiProcessPreset_TargetRealtime_MaxQuality + * @brief Default postprocess configuration optimizing the data for real-time rendering. + * + * This preset enables almost every optimization step to achieve perfectly + * optimized data. It's your choice for level editor environments where import speed + * is not important. + * + * If you're using DirectX, don't forget to combine this value with + * the #aiProcess_ConvertToLeftHanded step. If you don't support UV transformations + * in your application, apply the #aiProcess_TransformUVCoords step, too. + * @note Please take the time to read the docs for the steps enabled by this preset. + * Some of them offer further configurable properties, while some of them might not be + * of use for you so it might be better to not specify them. + */ +#define aiProcessPreset_TargetRealtime_MaxQuality ( \ + aiProcessPreset_TargetRealtime_Quality | \ + aiProcess_FindInstances | \ + aiProcess_ValidateDataStructure | \ + aiProcess_OptimizeMeshes | \ + aiProcess_Debone | \ + 0 ) + + +#ifdef __cplusplus +} // end of extern "C" +#endif + +#endif // AI_POSTPROCESS_H_INC \ No newline at end of file diff --git a/Lib/Include/assimp/quaternion.h b/Lib/Include/assimp/quaternion.h new file mode 100644 index 0000000..580e141 --- /dev/null +++ b/Lib/Include/assimp/quaternion.h @@ -0,0 +1,124 @@ +/* +Open Asset Import Library (assimp) +---------------------------------------------------------------------- + +Copyright (c) 2006-2012, assimp team +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the +following conditions are met: + +* Redistributions of source code must retain the above + copyright notice, this list of conditions and the + following disclaimer. + +* Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other + materials provided with the distribution. + +* Neither the name of the assimp team, nor the names of its + contributors may be used to endorse or promote products + derived from this software without specific prior + written permission of the assimp team. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"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 COPYRIGHT +OWNER OR CONTRIBUTORS 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. + +---------------------------------------------------------------------- +*/ + +/** @file quaternion.h + * @brief Quaternion structure, including operators when compiling in C++ + */ +#ifndef AI_QUATERNION_H_INC +#define AI_QUATERNION_H_INC + +#ifdef __cplusplus + +template class aiVector3t; +template class aiMatrix3x3t; + +// --------------------------------------------------------------------------- +/** Represents a quaternion in a 4D vector. */ +template +class aiQuaterniont +{ +public: + aiQuaterniont() : w(), x(), y(), z() {} + aiQuaterniont(TReal w, TReal x, TReal y, TReal z) + : w(w), x(x), y(y), z(z) {} + + /** Construct from rotation matrix. Result is undefined if the matrix is not orthonormal. */ + aiQuaterniont( const aiMatrix3x3t& pRotMatrix); + + /** Construct from euler angles */ + aiQuaterniont( TReal rotx, TReal roty, TReal rotz); + + /** Construct from an axis-angle pair */ + aiQuaterniont( aiVector3t axis, TReal angle); + + /** Construct from a normalized quaternion stored in a vec3 */ + aiQuaterniont( aiVector3t normalized); + + /** Returns a matrix representation of the quaternion */ + aiMatrix3x3t GetMatrix() const; + +public: + + bool operator== (const aiQuaterniont& o) const; + bool operator!= (const aiQuaterniont& o) const; + +public: + + /** Normalize the quaternion */ + aiQuaterniont& Normalize(); + + /** Compute quaternion conjugate */ + aiQuaterniont& Conjugate (); + + /** Rotate a point by this quaternion */ + aiVector3t Rotate (const aiVector3t& in); + + /** Multiply two quaternions */ + aiQuaterniont operator* (const aiQuaterniont& two) const; + +public: + + /** Performs a spherical interpolation between two quaternions and writes the result into the third. + * @param pOut Target object to received the interpolated rotation. + * @param pStart Start rotation of the interpolation at factor == 0. + * @param pEnd End rotation, factor == 1. + * @param pFactor Interpolation factor between 0 and 1. Values outside of this range yield undefined results. + */ + static void Interpolate( aiQuaterniont& pOut, const aiQuaterniont& pStart, + const aiQuaterniont& pEnd, TReal pFactor); + +public: + + //! w,x,y,z components of the quaternion + TReal w, x, y, z; +} ; + +typedef aiQuaterniont aiQuaternion; + +#else + +struct aiQuaternion { + float w, x, y, z; +}; + +#endif + + +#endif // AI_QUATERNION_H_INC diff --git a/Lib/Include/assimp/quaternion.inl b/Lib/Include/assimp/quaternion.inl new file mode 100644 index 0000000..03f247f --- /dev/null +++ b/Lib/Include/assimp/quaternion.inl @@ -0,0 +1,274 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2012, assimp team + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following +conditions are met: + +* Redistributions of source code must retain the above + copyright notice, this list of conditions and the + following disclaimer. + +* Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other + materials provided with the distribution. + +* Neither the name of the assimp team, nor the names of its + contributors may be used to endorse or promote products + derived from this software without specific prior + written permission of the assimp team. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"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 COPYRIGHT +OWNER OR CONTRIBUTORS 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. +--------------------------------------------------------------------------- +*/ + +/** @file aiQuaterniont.inl + * @brief Inline implementation of aiQuaterniont operators + */ +#ifndef AI_QUATERNION_INL_INC +#define AI_QUATERNION_INL_INC + +#ifdef __cplusplus +#include "quaternion.h" + +// --------------------------------------------------------------------------- +template +bool aiQuaterniont::operator== (const aiQuaterniont& o) const +{ + return x == o.x && y == o.y && z == o.z && w == o.w; +} + +// --------------------------------------------------------------------------- +template +bool aiQuaterniont::operator!= (const aiQuaterniont& o) const +{ + return !(*this == o); +} + + + +// --------------------------------------------------------------------------- +// Constructs a quaternion from a rotation matrix +template +inline aiQuaterniont::aiQuaterniont( const aiMatrix3x3t &pRotMatrix) +{ + TReal t = 1 + pRotMatrix.a1 + pRotMatrix.b2 + pRotMatrix.c3; + + // large enough + if( t > static_cast(0.001)) + { + TReal s = sqrt( t) * static_cast(2.0); + x = (pRotMatrix.c2 - pRotMatrix.b3) / s; + y = (pRotMatrix.a3 - pRotMatrix.c1) / s; + z = (pRotMatrix.b1 - pRotMatrix.a2) / s; + w = static_cast(0.25) * s; + } // else we have to check several cases + else if( pRotMatrix.a1 > pRotMatrix.b2 && pRotMatrix.a1 > pRotMatrix.c3 ) + { + // Column 0: + TReal s = sqrt( static_cast(1.0) + pRotMatrix.a1 - pRotMatrix.b2 - pRotMatrix.c3) * static_cast(2.0); + x = static_cast(0.25) * s; + y = (pRotMatrix.b1 + pRotMatrix.a2) / s; + z = (pRotMatrix.a3 + pRotMatrix.c1) / s; + w = (pRotMatrix.c2 - pRotMatrix.b3) / s; + } + else if( pRotMatrix.b2 > pRotMatrix.c3) + { + // Column 1: + TReal s = sqrt( static_cast(1.0) + pRotMatrix.b2 - pRotMatrix.a1 - pRotMatrix.c3) * static_cast(2.0); + x = (pRotMatrix.b1 + pRotMatrix.a2) / s; + y = static_cast(0.25) * s; + z = (pRotMatrix.c2 + pRotMatrix.b3) / s; + w = (pRotMatrix.a3 - pRotMatrix.c1) / s; + } else + { + // Column 2: + TReal s = sqrt( static_cast(1.0) + pRotMatrix.c3 - pRotMatrix.a1 - pRotMatrix.b2) * static_cast(2.0); + x = (pRotMatrix.a3 + pRotMatrix.c1) / s; + y = (pRotMatrix.c2 + pRotMatrix.b3) / s; + z = static_cast(0.25) * s; + w = (pRotMatrix.b1 - pRotMatrix.a2) / s; + } +} + +// --------------------------------------------------------------------------- +// Construction from euler angles +template +inline aiQuaterniont::aiQuaterniont( TReal fPitch, TReal fYaw, TReal fRoll ) +{ + const TReal fSinPitch(sin(fPitch*static_cast(0.5))); + const TReal fCosPitch(cos(fPitch*static_cast(0.5))); + const TReal fSinYaw(sin(fYaw*static_cast(0.5))); + const TReal fCosYaw(cos(fYaw*static_cast(0.5))); + const TReal fSinRoll(sin(fRoll*static_cast(0.5))); + const TReal fCosRoll(cos(fRoll*static_cast(0.5))); + const TReal fCosPitchCosYaw(fCosPitch*fCosYaw); + const TReal fSinPitchSinYaw(fSinPitch*fSinYaw); + x = fSinRoll * fCosPitchCosYaw - fCosRoll * fSinPitchSinYaw; + y = fCosRoll * fSinPitch * fCosYaw + fSinRoll * fCosPitch * fSinYaw; + z = fCosRoll * fCosPitch * fSinYaw - fSinRoll * fSinPitch * fCosYaw; + w = fCosRoll * fCosPitchCosYaw + fSinRoll * fSinPitchSinYaw; +} + +// --------------------------------------------------------------------------- +// Returns a matrix representation of the quaternion +template +inline aiMatrix3x3t aiQuaterniont::GetMatrix() const +{ + aiMatrix3x3t resMatrix; + resMatrix.a1 = static_cast(1.0) - static_cast(2.0) * (y * y + z * z); + resMatrix.a2 = static_cast(2.0) * (x * y - z * w); + resMatrix.a3 = static_cast(2.0) * (x * z + y * w); + resMatrix.b1 = static_cast(2.0) * (x * y + z * w); + resMatrix.b2 = static_cast(1.0) - static_cast(2.0) * (x * x + z * z); + resMatrix.b3 = static_cast(2.0) * (y * z - x * w); + resMatrix.c1 = static_cast(2.0) * (x * z - y * w); + resMatrix.c2 = static_cast(2.0) * (y * z + x * w); + resMatrix.c3 = static_cast(1.0) - static_cast(2.0) * (x * x + y * y); + + return resMatrix; +} + +// --------------------------------------------------------------------------- +// Construction from an axis-angle pair +template +inline aiQuaterniont::aiQuaterniont( aiVector3t axis, TReal angle) +{ + axis.Normalize(); + + const TReal sin_a = sin( angle / 2 ); + const TReal cos_a = cos( angle / 2 ); + x = axis.x * sin_a; + y = axis.y * sin_a; + z = axis.z * sin_a; + w = cos_a; +} +// --------------------------------------------------------------------------- +// Construction from am existing, normalized quaternion +template +inline aiQuaterniont::aiQuaterniont( aiVector3t normalized) +{ + x = normalized.x; + y = normalized.y; + z = normalized.z; + + const TReal t = static_cast(1.0) - (x*x) - (y*y) - (z*z); + + if (t < static_cast(0.0)) { + w = static_cast(0.0); + } + else w = sqrt (t); +} + +// --------------------------------------------------------------------------- +// Performs a spherical interpolation between two quaternions +// Implementation adopted from the gmtl project. All others I found on the net fail in some cases. +// Congrats, gmtl! +template +inline void aiQuaterniont::Interpolate( aiQuaterniont& pOut, const aiQuaterniont& pStart, const aiQuaterniont& pEnd, TReal pFactor) +{ + // calc cosine theta + TReal cosom = pStart.x * pEnd.x + pStart.y * pEnd.y + pStart.z * pEnd.z + pStart.w * pEnd.w; + + // adjust signs (if necessary) + aiQuaterniont end = pEnd; + if( cosom < static_cast(0.0)) + { + cosom = -cosom; + end.x = -end.x; // Reverse all signs + end.y = -end.y; + end.z = -end.z; + end.w = -end.w; + } + + // Calculate coefficients + TReal sclp, sclq; + if( (static_cast(1.0) - cosom) > static_cast(0.0001)) // 0.0001 -> some epsillon + { + // Standard case (slerp) + TReal omega, sinom; + omega = acos( cosom); // extract theta from dot product's cos theta + sinom = sin( omega); + sclp = sin( (static_cast(1.0) - pFactor) * omega) / sinom; + sclq = sin( pFactor * omega) / sinom; + } else + { + // Very close, do linear interp (because it's faster) + sclp = static_cast(1.0) - pFactor; + sclq = pFactor; + } + + pOut.x = sclp * pStart.x + sclq * end.x; + pOut.y = sclp * pStart.y + sclq * end.y; + pOut.z = sclp * pStart.z + sclq * end.z; + pOut.w = sclp * pStart.w + sclq * end.w; +} + +// --------------------------------------------------------------------------- +template +inline aiQuaterniont& aiQuaterniont::Normalize() +{ + // compute the magnitude and divide through it + const TReal mag = sqrt(x*x + y*y + z*z + w*w); + if (mag) + { + const TReal invMag = static_cast(1.0)/mag; + x *= invMag; + y *= invMag; + z *= invMag; + w *= invMag; + } + return *this; +} + +// --------------------------------------------------------------------------- +template +inline aiQuaterniont aiQuaterniont::operator* (const aiQuaterniont& t) const +{ + return aiQuaterniont(w*t.w - x*t.x - y*t.y - z*t.z, + w*t.x + x*t.w + y*t.z - z*t.y, + w*t.y + y*t.w + z*t.x - x*t.z, + w*t.z + z*t.w + x*t.y - y*t.x); +} + +// --------------------------------------------------------------------------- +template +inline aiQuaterniont& aiQuaterniont::Conjugate () +{ + x = -x; + y = -y; + z = -z; + return *this; +} + +// --------------------------------------------------------------------------- +template +inline aiVector3t aiQuaterniont::Rotate (const aiVector3t& v) +{ + aiQuaterniont q2(0.f,v.x,v.y,v.z), q = *this, qinv = q; + q.Conjugate(); + + q = q*q2*qinv; + return aiVector3t(q.x,q.y,q.z); + +} + +#endif +#endif diff --git a/Lib/Include/assimp/scene.h b/Lib/Include/assimp/scene.h new file mode 100644 index 0000000..1d95925 --- /dev/null +++ b/Lib/Include/assimp/scene.h @@ -0,0 +1,378 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2012, assimp team + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following +conditions are met: + +* Redistributions of source code must retain the above + copyright notice, this list of conditions and the + following disclaimer. + +* Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other + materials provided with the distribution. + +* Neither the name of the assimp team, nor the names of its + contributors may be used to endorse or promote products + derived from this software without specific prior + written permission of the assimp team. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"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 COPYRIGHT +OWNER OR CONTRIBUTORS 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. +--------------------------------------------------------------------------- +*/ + +/** @file aiScene.h + * @brief Defines the data structures in which the imported scene is returned. + */ +#ifndef __AI_SCENE_H_INC__ +#define __AI_SCENE_H_INC__ + +#include "types.h" +#include "texture.h" +#include "mesh.h" +#include "light.h" +#include "camera.h" +#include "material.h" +#include "anim.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// ------------------------------------------------------------------------------- +/** A node in the imported hierarchy. + * + * Each node has name, a parent node (except for the root node), + * a transformation relative to its parent and possibly several child nodes. + * Simple file formats don't support hierarchical structures - for these formats + * the imported scene does consist of only a single root node without children. + */ +// ------------------------------------------------------------------------------- +struct aiNode +{ + /** The name of the node. + * + * The name might be empty (length of zero) but all nodes which + * need to be accessed afterwards by bones or anims are usually named. + * Multiple nodes may have the same name, but nodes which are accessed + * by bones (see #aiBone and #aiMesh::mBones) *must* be unique. + * + * Cameras and lights are assigned to a specific node name - if there + * are multiple nodes with this name, they're assigned to each of them. + *
    + * There are no limitations regarding the characters contained in + * this text. You should be able to handle stuff like whitespace, tabs, + * linefeeds, quotation marks, ampersands, ... . + */ + C_STRUCT aiString mName; + + /** The transformation relative to the node's parent. */ + C_STRUCT aiMatrix4x4 mTransformation; + + /** Parent node. NULL if this node is the root node. */ + C_STRUCT aiNode* mParent; + + /** The number of child nodes of this node. */ + unsigned int mNumChildren; + + /** The child nodes of this node. NULL if mNumChildren is 0. */ + C_STRUCT aiNode** mChildren; + + /** The number of meshes of this node. */ + unsigned int mNumMeshes; + + /** The meshes of this node. Each entry is an index into the mesh */ + unsigned int* mMeshes; + +#ifdef __cplusplus + /** Constructor */ + aiNode() + { + // set all members to zero by default + mParent = NULL; + mNumChildren = 0; mChildren = NULL; + mNumMeshes = 0; mMeshes = NULL; + } + + /** Construction from a specific name */ + aiNode(const std::string& name) + { + // set all members to zero by default + mParent = NULL; + mNumChildren = 0; mChildren = NULL; + mNumMeshes = 0; mMeshes = NULL; + mName = name; + } + + /** Destructor */ + ~aiNode() + { + // delete all children recursively + // to make sure we won't crash if the data is invalid ... + if (mChildren && mNumChildren) + { + for( unsigned int a = 0; a < mNumChildren; a++) + delete mChildren[a]; + } + delete [] mChildren; + delete [] mMeshes; + } + + /** Searches for a node with a specific name, beginning at this + * nodes. Normally you will call this method on the root node + * of the scene. + * + * @param name Name to search for + * @return NULL or a valid Node if the search was successful. + */ + inline aiNode* FindNode(const aiString& name) + { + return FindNode(name.data); + } + + /** @override + */ + inline aiNode* FindNode(const char* name) + { + if (!::strcmp( mName.data,name))return this; + for (unsigned int i = 0; i < mNumChildren;++i) + { + aiNode* p = mChildren[i]->FindNode(name); + if (p)return p; + } + // there is definitely no sub node with this name + return NULL; + } + +#endif // __cplusplus +}; + + +// ------------------------------------------------------------------------------- +/** @def AI_SCENE_FLAGS_INCOMPLETE + * Specifies that the scene data structure that was imported is not complete. + * This flag bypasses some internal validations and allows the import + * of animation skeletons, material libraries or camera animation paths + * using Assimp. Most applications won't support such data. + */ +#define AI_SCENE_FLAGS_INCOMPLETE 0x1 + +/** @def AI_SCENE_FLAGS_VALIDATED + * This flag is set by the validation postprocess-step (aiPostProcess_ValidateDS) + * if the validation is successful. In a validated scene you can be sure that + * any cross references in the data structure (e.g. vertex indices) are valid. + */ +#define AI_SCENE_FLAGS_VALIDATED 0x2 + +/** @def AI_SCENE_FLAGS_VALIDATION_WARNING + * This flag is set by the validation postprocess-step (aiPostProcess_ValidateDS) + * if the validation is successful but some issues have been found. + * This can for example mean that a texture that does not exist is referenced + * by a material or that the bone weights for a vertex don't sum to 1.0 ... . + * In most cases you should still be able to use the import. This flag could + * be useful for applications which don't capture Assimp's log output. + */ +#define AI_SCENE_FLAGS_VALIDATION_WARNING 0x4 + +/** @def AI_SCENE_FLAGS_NON_VERBOSE_FORMAT + * This flag is currently only set by the aiProcess_JoinIdenticalVertices step. + * It indicates that the vertices of the output meshes aren't in the internal + * verbose format anymore. In the verbose format all vertices are unique, + * no vertex is ever referenced by more than one face. + */ +#define AI_SCENE_FLAGS_NON_VERBOSE_FORMAT 0x8 + + /** @def AI_SCENE_FLAGS_TERRAIN + * Denotes pure height-map terrain data. Pure terrains usually consist of quads, + * sometimes triangles, in a regular grid. The x,y coordinates of all vertex + * positions refer to the x,y coordinates on the terrain height map, the z-axis + * stores the elevation at a specific point. + * + * TER (Terragen) and HMP (3D Game Studio) are height map formats. + * @note Assimp is probably not the best choice for loading *huge* terrains - + * fully triangulated data takes extremely much free store and should be avoided + * as long as possible (typically you'll do the triangulation when you actually + * need to render it). + */ +#define AI_SCENE_FLAGS_TERRAIN 0x10 + + +// ------------------------------------------------------------------------------- +/** The root structure of the imported data. + * + * Everything that was imported from the given file can be accessed from here. + * Objects of this class are generally maintained and owned by Assimp, not + * by the caller. You shouldn't want to instance it, nor should you ever try to + * delete a given scene on your own. + */ +// ------------------------------------------------------------------------------- +struct aiScene +{ + + /** Any combination of the AI_SCENE_FLAGS_XXX flags. By default + * this value is 0, no flags are set. Most applications will + * want to reject all scenes with the AI_SCENE_FLAGS_INCOMPLETE + * bit set. + */ + unsigned int mFlags; + + + /** The root node of the hierarchy. + * + * There will always be at least the root node if the import + * was successful (and no special flags have been set). + * Presence of further nodes depends on the format and content + * of the imported file. + */ + C_STRUCT aiNode* mRootNode; + + + + /** The number of meshes in the scene. */ + unsigned int mNumMeshes; + + /** The array of meshes. + * + * Use the indices given in the aiNode structure to access + * this array. The array is mNumMeshes in size. If the + * AI_SCENE_FLAGS_INCOMPLETE flag is not set there will always + * be at least ONE material. + */ + C_STRUCT aiMesh** mMeshes; + + + + /** The number of materials in the scene. */ + unsigned int mNumMaterials; + + /** The array of materials. + * + * Use the index given in each aiMesh structure to access this + * array. The array is mNumMaterials in size. If the + * AI_SCENE_FLAGS_INCOMPLETE flag is not set there will always + * be at least ONE material. + */ + C_STRUCT aiMaterial** mMaterials; + + + + /** The number of animations in the scene. */ + unsigned int mNumAnimations; + + /** The array of animations. + * + * All animations imported from the given file are listed here. + * The array is mNumAnimations in size. + */ + C_STRUCT aiAnimation** mAnimations; + + + + /** The number of textures embedded into the file */ + unsigned int mNumTextures; + + /** The array of embedded textures. + * + * Not many file formats embed their textures into the file. + * An example is Quake's MDL format (which is also used by + * some GameStudio versions) + */ + C_STRUCT aiTexture** mTextures; + + + /** The number of light sources in the scene. Light sources + * are fully optional, in most cases this attribute will be 0 + */ + unsigned int mNumLights; + + /** The array of light sources. + * + * All light sources imported from the given file are + * listed here. The array is mNumLights in size. + */ + C_STRUCT aiLight** mLights; + + + /** The number of cameras in the scene. Cameras + * are fully optional, in most cases this attribute will be 0 + */ + unsigned int mNumCameras; + + /** The array of cameras. + * + * All cameras imported from the given file are listed here. + * The array is mNumCameras in size. The first camera in the + * array (if existing) is the default camera view into + * the scene. + */ + C_STRUCT aiCamera** mCameras; + +#ifdef __cplusplus + + //! Default constructor - set everything to 0/NULL + aiScene(); + + //! Destructor + ~aiScene(); + + //! Check whether the scene contains meshes + //! Unless no special scene flags are set this will always be true. + inline bool HasMeshes() const + { return mMeshes != NULL && mNumMeshes > 0; } + + //! Check whether the scene contains materials + //! Unless no special scene flags are set this will always be true. + inline bool HasMaterials() const + { return mMaterials != NULL && mNumMaterials > 0; } + + //! Check whether the scene contains lights + inline bool HasLights() const + { return mLights != NULL && mNumLights > 0; } + + //! Check whether the scene contains textures + inline bool HasTextures() const + { return mTextures != NULL && mNumTextures > 0; } + + //! Check whether the scene contains cameras + inline bool HasCameras() const + { return mCameras != NULL && mNumCameras > 0; } + + //! Check whether the scene contains animations + inline bool HasAnimations() const + { return mAnimations != NULL && mNumAnimations > 0; } + +#endif // __cplusplus + + + /** Internal data, do not touch */ +#ifdef __cplusplus + void* mPrivate; +#else + char* mPrivate; +#endif + +}; + +#ifdef __cplusplus +} //! namespace Assimp +#endif + +#endif // __AI_SCENE_H_INC__ diff --git a/Lib/Include/assimp/texture.h b/Lib/Include/assimp/texture.h new file mode 100644 index 0000000..27b9318 --- /dev/null +++ b/Lib/Include/assimp/texture.h @@ -0,0 +1,197 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2012, assimp team + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following +conditions are met: + +* Redistributions of source code must retain the above + copyright notice, this list of conditions and the + following disclaimer. + +* Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other + materials provided with the distribution. + +* Neither the name of the assimp team, nor the names of its + contributors may be used to endorse or promote products + derived from this software without specific prior + written permission of the assimp team. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"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 COPYRIGHT +OWNER OR CONTRIBUTORS 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. +--------------------------------------------------------------------------- +*/ + +/** @file texture.h + * @brief Defines texture helper structures for the library + * + * Used for file formats which embed their textures into the model file. + * Supported are both normal textures, which are stored as uncompressed + * pixels, and "compressed" textures, which are stored in a file format + * such as PNG or TGA. + */ + +#ifndef AI_TEXTURE_H_INC +#define AI_TEXTURE_H_INC + +#include "types.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +// -------------------------------------------------------------------------------- +/** @def AI_MAKE_EMBEDDED_TEXNAME + * Used to build the reserved path name used by the material system to + * reference textures that are embedded into their corresponding + * model files. The parameter specifies the index of the texture + * (zero-based, in the aiScene::mTextures array) + */ +#if (!defined AI_MAKE_EMBEDDED_TEXNAME) +# define AI_MAKE_EMBEDDED_TEXNAME(_n_) "*" # _n_ +#endif + + +#include "./Compiler/pushpack1.h" + +// -------------------------------------------------------------------------------- +/** @brief Helper structure to represent a texel in a ARGB8888 format +* +* Used by aiTexture. +*/ +struct aiTexel +{ + unsigned char b,g,r,a; + +#ifdef __cplusplus + //! Comparison operator + bool operator== (const aiTexel& other) const + { + return b == other.b && r == other.r && + g == other.g && a == other.a; + } + + //! Inverse comparison operator + bool operator!= (const aiTexel& other) const + { + return b != other.b || r != other.r || + g != other.g || a != other.a; + } + + //! Conversion to a floating-point 4d color + operator aiColor4D() const + { + return aiColor4D(r/255.f,g/255.f,b/255.f,a/255.f); + } +#endif // __cplusplus + +} PACK_STRUCT; + +#include "./Compiler/poppack1.h" + +// -------------------------------------------------------------------------------- +/** Helper structure to describe an embedded texture + * + * Normally textures are contained in external files but some file formats embed + * them directly in the model file. There are two types of embedded textures: + * 1. Uncompressed textures. The color data is given in an uncompressed format. + * 2. Compressed textures stored in a file format like png or jpg. The raw file + * bytes are given so the application must utilize an image decoder (e.g. DevIL) to + * get access to the actual color data. + */ +struct aiTexture +{ + /** Width of the texture, in pixels + * + * If mHeight is zero the texture is compressed in a format + * like JPEG. In this case mWidth specifies the size of the + * memory area pcData is pointing to, in bytes. + */ + unsigned int mWidth; + + /** Height of the texture, in pixels + * + * If this value is zero, pcData points to an compressed texture + * in any format (e.g. JPEG). + */ + unsigned int mHeight; + + /** A hint from the loader to make it easier for applications + * to determine the type of embedded compressed textures. + * + * If mHeight != 0 this member is undefined. Otherwise it + * is set set to '\\0\\0\\0\\0' if the loader has no additional + * information about the texture file format used OR the + * file extension of the format without a trailing dot. If there + * are multiple file extensions for a format, the shortest + * extension is chosen (JPEG maps to 'jpg', not to 'jpeg'). + * E.g. 'dds\\0', 'pcx\\0', 'jpg\\0'. All characters are lower-case. + * The fourth character will always be '\\0'. + */ + char achFormatHint[4]; + + /** Data of the texture. + * + * Points to an array of mWidth * mHeight aiTexel's. + * The format of the texture data is always ARGB8888 to + * make the implementation for user of the library as easy + * as possible. If mHeight = 0 this is a pointer to a memory + * buffer of size mWidth containing the compressed texture + * data. Good luck, have fun! + */ + C_STRUCT aiTexel* pcData; + +#ifdef __cplusplus + + //! For compressed textures (mHeight == 0): compare the + //! format hint against a given string. + //! @param s Input string. 3 characters are maximally processed. + //! Example values: "jpg", "png" + //! @return true if the given string matches the format hint + bool CheckFormat(const char* s) const + { + return (0 == ::strncmp(achFormatHint,s,3)); + } + + // Construction + aiTexture () + : mWidth (0) + , mHeight (0) + , pcData (NULL) + { + achFormatHint[0] = achFormatHint[1] = 0; + achFormatHint[2] = achFormatHint[3] = 0; + } + + // Destruction + ~aiTexture () + { + delete[] pcData; + } +#endif +}; + + +#ifdef __cplusplus +} +#endif + +#endif // AI_TEXTURE_H_INC diff --git a/Lib/Include/assimp/types.h b/Lib/Include/assimp/types.h new file mode 100644 index 0000000..c593b6d --- /dev/null +++ b/Lib/Include/assimp/types.h @@ -0,0 +1,499 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2012, assimp team + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following +conditions are met: + +* Redistributions of source code must retain the above + copyright notice, this list of conditions and the + following disclaimer. + +* Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other + materials provided with the distribution. + +* Neither the name of the assimp team, nor the names of its + contributors may be used to endorse or promote products + derived from this software without specific prior + written permission of the assimp team. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"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 COPYRIGHT +OWNER OR CONTRIBUTORS 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. +--------------------------------------------------------------------------- +*/ + +/** @file types.h + * Basic data types and primitives, such as vectors or colors. + */ +#ifndef AI_TYPES_H_INC +#define AI_TYPES_H_INC + +// Some runtime headers +#include +#include +#include +#include + +// Our compile configuration +#include "defs.h" + +// Some types moved to separate header due to size of operators +#include "vector3.h" +#include "vector2.h" +#include "color4.h" +#include "matrix3x3.h" +#include "matrix4x4.h" +#include "quaternion.h" + +#ifdef __cplusplus +#include // for std::nothrow_t +#include // for aiString::Set(const std::string&) + +namespace Assimp { + //! @cond never +namespace Intern { + // -------------------------------------------------------------------- + /** @brief Internal helper class to utilize our internal new/delete + * routines for allocating object of this and derived classes. + * + * By doing this you can safely share class objects between Assimp + * and the application - it works even over DLL boundaries. A good + * example is the #IOSystem where the application allocates its custom + * #IOSystem, then calls #Importer::SetIOSystem(). When the Importer + * destructs, Assimp calls operator delete on the stored #IOSystem. + * If it lies on a different heap than Assimp is working with, + * the application is determined to crash. + */ + // -------------------------------------------------------------------- +#ifndef SWIG + struct ASSIMP_API AllocateFromAssimpHeap { + // http://www.gotw.ca/publications/mill15.htm + + // new/delete overload + void *operator new ( size_t num_bytes) /* throw( std::bad_alloc ) */; + void *operator new ( size_t num_bytes, const std::nothrow_t& ) throw(); + void operator delete ( void* data); + + // array new/delete overload + void *operator new[] ( size_t num_bytes) /* throw( std::bad_alloc ) */; + void *operator new[] ( size_t num_bytes, const std::nothrow_t& ) throw(); + void operator delete[] ( void* data); + + }; // struct AllocateFromAssimpHeap +#endif +} // namespace Intern + //! @endcond +} // namespace Assimp + +extern "C" { +#endif + +/** Maximum dimension for strings, ASSIMP strings are zero terminated. */ +#ifdef __cplusplus +const size_t MAXLEN = 1024; +#else +# define MAXLEN 1024 +#endif + +#include "./Compiler/pushpack1.h" + +// ---------------------------------------------------------------------------------- +/** Represents a plane in a three-dimensional, euclidean space +*/ +struct aiPlane +{ +#ifdef __cplusplus + aiPlane () : a(0.f), b(0.f), c(0.f), d(0.f) {} + aiPlane (float _a, float _b, float _c, float _d) + : a(_a), b(_b), c(_c), d(_d) {} + + aiPlane (const aiPlane& o) : a(o.a), b(o.b), c(o.c), d(o.d) {} + +#endif // !__cplusplus + + //! Plane equation + float a,b,c,d; +} PACK_STRUCT; // !struct aiPlane + +// ---------------------------------------------------------------------------------- +/** Represents a ray +*/ +struct aiRay +{ +#ifdef __cplusplus + aiRay () {} + aiRay (const aiVector3D& _pos, const aiVector3D& _dir) + : pos(_pos), dir(_dir) {} + + aiRay (const aiRay& o) : pos (o.pos), dir (o.dir) {} + +#endif // !__cplusplus + + //! Position and direction of the ray + C_STRUCT aiVector3D pos, dir; +} PACK_STRUCT; // !struct aiRay + +// ---------------------------------------------------------------------------------- +/** Represents a color in Red-Green-Blue space. +*/ +struct aiColor3D +{ +#ifdef __cplusplus + aiColor3D () : r(0.0f), g(0.0f), b(0.0f) {} + aiColor3D (float _r, float _g, float _b) : r(_r), g(_g), b(_b) {} + aiColor3D (float _r) : r(_r), g(_r), b(_r) {} + aiColor3D (const aiColor3D& o) : r(o.r), g(o.g), b(o.b) {} + + /** Component-wise comparison */ + // TODO: add epsilon? + bool operator == (const aiColor3D& other) const + {return r == other.r && g == other.g && b == other.b;} + + /** Component-wise inverse comparison */ + // TODO: add epsilon? + bool operator != (const aiColor3D& other) const + {return r != other.r || g != other.g || b != other.b;} + + /** Component-wise addition */ + aiColor3D operator+(const aiColor3D& c) const { + return aiColor3D(r+c.r,g+c.g,b+c.b); + } + + /** Component-wise subtraction */ + aiColor3D operator-(const aiColor3D& c) const { + return aiColor3D(r+c.r,g+c.g,b+c.b); + } + + /** Component-wise multiplication */ + aiColor3D operator*(const aiColor3D& c) const { + return aiColor3D(r*c.r,g*c.g,b*c.b); + } + + /** Multiply with a scalar */ + aiColor3D operator*(float f) const { + return aiColor3D(r*f,g*f,b*f); + } + + /** Access a specific color component */ + float operator[](unsigned int i) const { + return *(&r + i); + } + + /** Access a specific color component */ + float& operator[](unsigned int i) { + return *(&r + i); + } + + /** Check whether a color is black */ + bool IsBlack() const { + static const float epsilon = 10e-3f; + return fabs( r ) < epsilon && fabs( g ) < epsilon && fabs( b ) < epsilon; + } + +#endif // !__cplusplus + + //! Red, green and blue color values + float r, g, b; +} PACK_STRUCT; // !struct aiColor3D +#include "./Compiler/poppack1.h" + +// ---------------------------------------------------------------------------------- +/** Represents an UTF-8 string, zero byte terminated. + * + * The character set of an aiString is explicitly defined to be UTF-8. This Unicode + * transformation was chosen in the belief that most strings in 3d files are limited + * to ASCII, thus the character set needed to be strictly ASCII compatible. + * + * Most text file loaders provide proper Unicode input file handling, special unicode + * characters are correctly transcoded to UTF8 and are kept throughout the libraries' + * import pipeline. + * + * For most applications, it will be absolutely sufficient to interpret the + * aiString as ASCII data and work with it as one would work with a plain char*. + * Windows users in need of proper support for i.e asian characters can use the + * #MultiByteToWideChar(), #WideCharToMultiByte() WinAPI functionality to convert the + * UTF-8 strings to their working character set (i.e. MBCS, WideChar). + * + * We use this representation instead of std::string to be C-compatible. The + * (binary) length of such a string is limited to MAXLEN characters (including the + * the terminating zero). +*/ +struct aiString +{ +#ifdef __cplusplus + /** Default constructor, the string is set to have zero length */ + aiString() : + length(0) + { + data[0] = '\0'; + +#ifdef _DEBUG + // Debug build: overwrite the string on its full length with ESC (27) + memset(data+1,27,MAXLEN-1); +#endif + } + + /** Copy constructor */ + aiString(const aiString& rOther) : + length(rOther.length) + { + // Crop the string to the maximum length + length = length>=MAXLEN?MAXLEN-1:length; + memcpy( data, rOther.data, length); + data[length] = '\0'; + } + + /** Constructor from std::string */ + explicit aiString(const std::string& pString) : + length(pString.length()) + { + length = length>=MAXLEN?MAXLEN-1:length; + memcpy( data, pString.c_str(), length); + data[length] = '\0'; + } + + /** Copy a std::string to the aiString */ + void Set( const std::string& pString) { + if( pString.length() > MAXLEN - 1) { + return; + } + length = pString.length(); + memcpy( data, pString.c_str(), length); + data[length] = 0; + } + + /** Copy a const char* to the aiString */ + void Set( const char* sz) { + const size_t len = ::strlen(sz); + if( len > MAXLEN - 1) { + return; + } + length = len; + memcpy( data, sz, len); + data[len] = 0; + } + + /** Assign a const char* to the string */ + aiString& operator = (const char* sz) { + Set(sz); + return *this; + } + + /** Assign a cstd::string to the string */ + aiString& operator = ( const std::string& pString) { + Set(pString); + return *this; + } + + /** Comparison operator */ + bool operator==(const aiString& other) const { + return (length == other.length && 0 == memcmp(data,other.data,length)); + } + + /** Inverse comparison operator */ + bool operator!=(const aiString& other) const { + return (length != other.length || 0 != memcmp(data,other.data,length)); + } + + /** Append a string to the string */ + void Append (const char* app) { + const size_t len = strlen(app); + if (!len) { + return; + } + if (length + len >= MAXLEN) { + return; + } + + memcpy(&data[length],app,len+1); + length += len; + } + + /** Clear the string - reset its length to zero */ + void Clear () { + length = 0; + data[0] = '\0'; + +#ifdef _DEBUG + // Debug build: overwrite the string on its full length with ESC (27) + memset(data+1,27,MAXLEN-1); +#endif + } + + /** Returns a pointer to the underlying zero-terminated array of characters */ + const char* C_Str() const { + return data; + } + +#endif // !__cplusplus + + /** Binary length of the string excluding the terminal 0. This is NOT the + * logical length of strings containing UTF-8 multibyte sequences! It's + * the number of bytes from the beginning of the string to its end.*/ + size_t length; + + /** String buffer. Size limit is MAXLEN */ + char data[MAXLEN]; +} ; // !struct aiString + + +// ---------------------------------------------------------------------------------- +/** Standard return type for some library functions. + * Rarely used, and if, mostly in the C API. + */ +enum aiReturn +{ + /** Indicates that a function was successful */ + aiReturn_SUCCESS = 0x0, + + /** Indicates that a function failed */ + aiReturn_FAILURE = -0x1, + + /** Indicates that not enough memory was available + * to perform the requested operation + */ + aiReturn_OUTOFMEMORY = -0x3, + + /** @cond never + * Force 32-bit size enum + */ + _AI_ENFORCE_ENUM_SIZE = 0x7fffffff +}; // !enum aiReturn + +// just for backwards compatibility, don't use these constants anymore +#define AI_SUCCESS aiReturn_SUCCESS +#define AI_FAILURE aiReturn_FAILURE +#define AI_OUTOFMEMORY aiReturn_OUTOFMEMORY + +// ---------------------------------------------------------------------------------- +/** Seek origins (for the virtual file system API). + * Much cooler than using SEEK_SET, SEEK_CUR or SEEK_END. + */ +enum aiOrigin +{ + /** Beginning of the file */ + aiOrigin_SET = 0x0, + + /** Current position of the file pointer */ + aiOrigin_CUR = 0x1, + + /** End of the file, offsets must be negative */ + aiOrigin_END = 0x2, + + /** @cond never + * Force 32-bit size enum + */ + _AI_ORIGIN_ENFORCE_ENUM_SIZE = 0x7fffffff +}; // !enum aiOrigin + +// ---------------------------------------------------------------------------------- +/** @brief Enumerates predefined log streaming destinations. + * Logging to these streams can be enabled with a single call to + * #LogStream::createDefaultStream or #aiAttachPredefinedLogStream(), + * respectively. + */ +enum aiDefaultLogStream +{ + /** Stream the log to a file */ + aiDefaultLogStream_FILE = 0x1, + + /** Stream the log to std::cout */ + aiDefaultLogStream_STDOUT = 0x2, + + /** Stream the log to std::cerr */ + aiDefaultLogStream_STDERR = 0x4, + + /** MSVC only: Stream the log the the debugger + * (this relies on OutputDebugString from the Win32 SDK) + */ + aiDefaultLogStream_DEBUGGER = 0x8, + + /** @cond never + * Force 32-bit size enum + */ + _AI_DLS_ENFORCE_ENUM_SIZE = 0x7fffffff +}; // !enum aiDefaultLogStream + +// just for backwards compatibility, don't use these constants anymore +#define DLS_FILE aiDefaultLogStream_FILE +#define DLS_STDOUT aiDefaultLogStream_STDOUT +#define DLS_STDERR aiDefaultLogStream_STDERR +#define DLS_DEBUGGER aiDefaultLogStream_DEBUGGER + +// ---------------------------------------------------------------------------------- +/** Stores the memory requirements for different components (e.g. meshes, materials, + * animations) of an import. All sizes are in bytes. + * @see Importer::GetMemoryRequirements() +*/ +struct aiMemoryInfo +{ +#ifdef __cplusplus + + /** Default constructor */ + aiMemoryInfo() + : textures (0) + , materials (0) + , meshes (0) + , nodes (0) + , animations (0) + , cameras (0) + , lights (0) + , total (0) + {} + +#endif + + /** Storage allocated for texture data */ + unsigned int textures; + + /** Storage allocated for material data */ + unsigned int materials; + + /** Storage allocated for mesh data */ + unsigned int meshes; + + /** Storage allocated for node data */ + unsigned int nodes; + + /** Storage allocated for animation data */ + unsigned int animations; + + /** Storage allocated for camera data */ + unsigned int cameras; + + /** Storage allocated for light data */ + unsigned int lights; + + /** Total storage allocated for the full import. */ + unsigned int total; +}; // !struct aiMemoryInfo + +#ifdef __cplusplus +} +#endif //! __cplusplus + +// Include implementation files +#include "vector2.inl" +#include "vector3.inl" +#include "color4.inl" +#include "quaternion.inl" +#include "matrix3x3.inl" +#include "matrix4x4.inl" +#endif diff --git a/Lib/Include/assimp/vector2.h b/Lib/Include/assimp/vector2.h new file mode 100644 index 0000000..800db4b --- /dev/null +++ b/Lib/Include/assimp/vector2.h @@ -0,0 +1,107 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2012, assimp team + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following +conditions are met: + +* Redistributions of source code must retain the above + copyright notice, this list of conditions and the + following disclaimer. + +* Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other + materials provided with the distribution. + +* Neither the name of the assimp team, nor the names of its + contributors may be used to endorse or promote products + derived from this software without specific prior + written permission of the assimp team. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"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 COPYRIGHT +OWNER OR CONTRIBUTORS 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. +--------------------------------------------------------------------------- +*/ +/** @file aiVector2t.h + * @brief 2D vector structure, including operators when compiling in C++ + */ +#ifndef AI_VECTOR2D_H_INC +#define AI_VECTOR2D_H_INC + +#include + +#include "./Compiler/pushpack1.h" + +// ---------------------------------------------------------------------------------- +/** Represents a two-dimensional vector. + */ + +#ifdef __cplusplus +template +class aiVector2t +{ +public: + + aiVector2t () : x(), y() {} + aiVector2t (TReal _x, TReal _y) : x(_x), y(_y) {} + explicit aiVector2t (TReal _xyz) : x(_xyz), y(_xyz) {} + aiVector2t (const aiVector2t& o) : x(o.x), y(o.y) {} + +public: + + void Set( TReal pX, TReal pY); + TReal SquareLength() const ; + TReal Length() const ; + aiVector2t& Normalize(); + +public: + + const aiVector2t& operator += (const aiVector2t& o); + const aiVector2t& operator -= (const aiVector2t& o); + const aiVector2t& operator *= (TReal f); + const aiVector2t& operator /= (TReal f); + + TReal operator[](unsigned int i) const; + TReal& operator[](unsigned int i); + + bool operator== (const aiVector2t& other) const; + bool operator!= (const aiVector2t& other) const; + + aiVector2t& operator= (TReal f); + const aiVector2t SymMul(const aiVector2t& o); + + template + operator aiVector2t () const; + + TReal x, y; +} PACK_STRUCT; + +typedef aiVector2t aiVector2D; + +#else + +struct aiVector2D { + float x,y; +}; + +#endif // __cplusplus + +#include "./Compiler/poppack1.h" + +#endif // AI_VECTOR2D_H_INC diff --git a/Lib/Include/assimp/vector2.inl b/Lib/Include/assimp/vector2.inl new file mode 100644 index 0000000..adee690 --- /dev/null +++ b/Lib/Include/assimp/vector2.inl @@ -0,0 +1,214 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2012, assimp team + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following +conditions are met: + +* Redistributions of source code must retain the above + copyright notice, this list of conditions and the + following disclaimer. + +* Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other + materials provided with the distribution. + +* Neither the name of the assimp team, nor the names of its + contributors may be used to endorse or promote products + derived from this software without specific prior + written permission of the assimp team. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"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 COPYRIGHT +OWNER OR CONTRIBUTORS 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. +--------------------------------------------------------------------------- +*/ + +/** @file aiVector2D.inl + * @brief Inline implementation of aiVector2t operators + */ +#ifndef AI_VECTOR2D_INL_INC +#define AI_VECTOR2D_INL_INC + +#ifdef __cplusplus +#include "vector2.h" + +// ------------------------------------------------------------------------------------------------ +template +template +aiVector2t::operator aiVector2t () const { + return aiVector2t(static_cast(x),static_cast(y)); +} +// ------------------------------------------------------------------------------------------------ +template +void aiVector2t::Set( TReal pX, TReal pY) { + x = pX; y = pY; +} + +// ------------------------------------------------------------------------------------------------ +template +TReal aiVector2t::SquareLength() const { + return x*x + y*y; +} + +// ------------------------------------------------------------------------------------------------ +template +TReal aiVector2t::Length() const { + return ::sqrt( SquareLength()); +} + +// ------------------------------------------------------------------------------------------------ +template +aiVector2t& aiVector2t::Normalize() { + *this /= Length(); + return *this; +} + +// ------------------------------------------------------------------------------------------------ +template +const aiVector2t& aiVector2t::operator += (const aiVector2t& o) { + x += o.x; y += o.y; + return *this; +} + +// ------------------------------------------------------------------------------------------------ +template +const aiVector2t& aiVector2t::operator -= (const aiVector2t& o) { + x -= o.x; y -= o.y; + return *this; +} + +// ------------------------------------------------------------------------------------------------ +template +const aiVector2t& aiVector2t::operator *= (TReal f) { + x *= f; y *= f; + return *this; +} + +// ------------------------------------------------------------------------------------------------ +template +const aiVector2t& aiVector2t::operator /= (TReal f) { + x /= f; y /= f; + return *this; +} + +// ------------------------------------------------------------------------------------------------ +template +TReal aiVector2t::operator[](unsigned int i) const { + return *(&x + i); +} + +// ------------------------------------------------------------------------------------------------ +template +TReal& aiVector2t::operator[](unsigned int i) { + return *(&x + i); +} + +// ------------------------------------------------------------------------------------------------ +template +bool aiVector2t::operator== (const aiVector2t& other) const { + return x == other.x && y == other.y; +} + +// ------------------------------------------------------------------------------------------------ +template +bool aiVector2t::operator!= (const aiVector2t& other) const { + return x != other.x || y != other.y; +} + +// ------------------------------------------------------------------------------------------------ +template +aiVector2t& aiVector2t::operator= (TReal f) { + x = y = f; + return *this; +} + +// ------------------------------------------------------------------------------------------------ +template +const aiVector2t aiVector2t::SymMul(const aiVector2t& o) { + return aiVector2t(x*o.x,y*o.y); +} + + +// ------------------------------------------------------------------------------------------------ +// symmetric addition +template +inline aiVector2t operator + (const aiVector2t& v1, const aiVector2t& v2) +{ + return aiVector2t( v1.x + v2.x, v1.y + v2.y); +} + +// ------------------------------------------------------------------------------------------------ +// symmetric subtraction +template +inline aiVector2t operator - (const aiVector2t& v1, const aiVector2t& v2) +{ + return aiVector2t( v1.x - v2.x, v1.y - v2.y); +} + +// ------------------------------------------------------------------------------------------------ +// scalar product +template +inline TReal operator * (const aiVector2t& v1, const aiVector2t& v2) +{ + return v1.x*v2.x + v1.y*v2.y; +} + +// ------------------------------------------------------------------------------------------------ +// scalar multiplication +template +inline aiVector2t operator * ( TReal f, const aiVector2t& v) +{ + return aiVector2t( f*v.x, f*v.y); +} + +// ------------------------------------------------------------------------------------------------ +// and the other way around +template +inline aiVector2t operator * ( const aiVector2t& v, TReal f) +{ + return aiVector2t( f*v.x, f*v.y); +} + +// ------------------------------------------------------------------------------------------------ +// scalar division +template +inline aiVector2t operator / ( const aiVector2t& v, TReal f) +{ + + return v * (1/f); +} + +// ------------------------------------------------------------------------------------------------ +// vector division +template +inline aiVector2t operator / ( const aiVector2t& v, const aiVector2t& v2) +{ + return aiVector2t(v.x / v2.x,v.y / v2.y); +} + +// ------------------------------------------------------------------------------------------------ +// vector negation +template +inline aiVector2t operator - ( const aiVector2t& v) +{ + return aiVector2t( -v.x, -v.y); +} + +#endif +#endif diff --git a/Lib/Include/assimp/vector3.h b/Lib/Include/assimp/vector3.h new file mode 100644 index 0000000..9b84b7b --- /dev/null +++ b/Lib/Include/assimp/vector3.h @@ -0,0 +1,143 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2012, assimp team + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following +conditions are met: + +* Redistributions of source code must retain the above + copyright notice, this list of conditions and the + following disclaimer. + +* Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other + materials provided with the distribution. + +* Neither the name of the assimp team, nor the names of its + contributors may be used to endorse or promote products + derived from this software without specific prior + written permission of the assimp team. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"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 COPYRIGHT +OWNER OR CONTRIBUTORS 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. +--------------------------------------------------------------------------- +*/ +/** @file aiVector3D.h + * @brief 3D vector structure, including operators when compiling in C++ + */ +#ifndef AI_VECTOR3D_H_INC +#define AI_VECTOR3D_H_INC + +#include + + +#include "./Compiler/pushpack1.h" + +#ifdef __cplusplus + +template class aiMatrix3x3t; +template class aiMatrix4x4t; + +// --------------------------------------------------------------------------- +/** Represents a three-dimensional vector. */ +template +class aiVector3t +{ +public: + + aiVector3t () : x(), y(), z() {} + aiVector3t (TReal _x, TReal _y, TReal _z) : x(_x), y(_y), z(_z) {} + explicit aiVector3t (TReal _xyz) : x(_xyz), y(_xyz), z(_xyz) {} + aiVector3t (const aiVector3t& o) : x(o.x), y(o.y), z(o.z) {} + +public: + + // combined operators + const aiVector3t& operator += (const aiVector3t& o); + const aiVector3t& operator -= (const aiVector3t& o); + const aiVector3t& operator *= (TReal f); + const aiVector3t& operator /= (TReal f); + + // transform vector by matrix + aiVector3t& operator *= (const aiMatrix3x3t& mat); + aiVector3t& operator *= (const aiMatrix4x4t& mat); + + // access a single element + TReal operator[](unsigned int i) const; + TReal& operator[](unsigned int i); + + // comparison + bool operator== (const aiVector3t& other) const; + bool operator!= (const aiVector3t& other) const; + + template + operator aiVector3t () const; + +public: + + /** @brief Set the components of a vector + * @param pX X component + * @param pY Y component + * @param pZ Z component */ + void Set( TReal pX, TReal pY, TReal pZ); + + /** @brief Get the squared length of the vector + * @return Square length */ + TReal SquareLength() const; + + + /** @brief Get the length of the vector + * @return length */ + TReal Length() const; + + + /** @brief Normalize the vector */ + aiVector3t& Normalize(); + + + /** @brief Componentwise multiplication of two vectors + * + * Note that vec*vec yields the dot product. + * @param o Second factor */ + const aiVector3t SymMul(const aiVector3t& o); + + TReal x, y, z; +} PACK_STRUCT; + + +typedef aiVector3t aiVector3D; + +#else + +struct aiVector3D { + + float x,y,z; +} PACK_STRUCT; + +#endif // __cplusplus + +#include "./Compiler/poppack1.h" + +#ifdef __cplusplus + + + +#endif // __cplusplus + +#endif // AI_VECTOR3D_H_INC diff --git a/Lib/Include/assimp/vector3.inl b/Lib/Include/assimp/vector3.inl new file mode 100644 index 0000000..8938458 --- /dev/null +++ b/Lib/Include/assimp/vector3.inl @@ -0,0 +1,212 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2012, assimp team + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following +conditions are met: + +* Redistributions of source code must retain the above + copyright notice, this list of conditions and the + following disclaimer. + +* Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other + materials provided with the distribution. + +* Neither the name of the assimp team, nor the names of its + contributors may be used to endorse or promote products + derived from this software without specific prior + written permission of the assimp team. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"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 COPYRIGHT +OWNER OR CONTRIBUTORS 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. +--------------------------------------------------------------------------- +*/ + +/** @file aiVector3D.inl + * @brief Inline implementation of aiVector3t operators + */ +#ifndef AI_VECTOR3D_INL_INC +#define AI_VECTOR3D_INL_INC + +#ifdef __cplusplus +#include "vector3.h" + +// ------------------------------------------------------------------------------------------------ +/** Transformation of a vector by a 3x3 matrix */ +template +inline aiVector3t operator * (const aiMatrix3x3t& pMatrix, const aiVector3t& pVector) +{ + aiVector3t res; + res.x = pMatrix.a1 * pVector.x + pMatrix.a2 * pVector.y + pMatrix.a3 * pVector.z; + res.y = pMatrix.b1 * pVector.x + pMatrix.b2 * pVector.y + pMatrix.b3 * pVector.z; + res.z = pMatrix.c1 * pVector.x + pMatrix.c2 * pVector.y + pMatrix.c3 * pVector.z; + return res; +} + +// ------------------------------------------------------------------------------------------------ +/** Transformation of a vector by a 4x4 matrix */ +template +inline aiVector3t operator * (const aiMatrix4x4t& pMatrix, const aiVector3t& pVector) +{ + aiVector3t res; + res.x = pMatrix.a1 * pVector.x + pMatrix.a2 * pVector.y + pMatrix.a3 * pVector.z + pMatrix.a4; + res.y = pMatrix.b1 * pVector.x + pMatrix.b2 * pVector.y + pMatrix.b3 * pVector.z + pMatrix.b4; + res.z = pMatrix.c1 * pVector.x + pMatrix.c2 * pVector.y + pMatrix.c3 * pVector.z + pMatrix.c4; + return res; +} +// ------------------------------------------------------------------------------------------------ +template +template +aiVector3t::operator aiVector3t () const { + return aiVector3t(static_cast(x),static_cast(y),static_cast(z)); +} +// ------------------------------------------------------------------------------------------------ +template +AI_FORCE_INLINE void aiVector3t::Set( TReal pX, TReal pY, TReal pZ) { + x = pX; y = pY; z = pZ; +} +// ------------------------------------------------------------------------------------------------ +template +AI_FORCE_INLINE TReal aiVector3t::SquareLength() const { + return x*x + y*y + z*z; +} +// ------------------------------------------------------------------------------------------------ +template +AI_FORCE_INLINE TReal aiVector3t::Length() const { + return sqrt( SquareLength()); +} +// ------------------------------------------------------------------------------------------------ +template +AI_FORCE_INLINE aiVector3t& aiVector3t::Normalize() { + *this /= Length(); return *this; +} +// ------------------------------------------------------------------------------------------------ +template +AI_FORCE_INLINE const aiVector3t& aiVector3t::operator += (const aiVector3t& o) { + x += o.x; y += o.y; z += o.z; return *this; +} +// ------------------------------------------------------------------------------------------------ +template +AI_FORCE_INLINE const aiVector3t& aiVector3t::operator -= (const aiVector3t& o) { + x -= o.x; y -= o.y; z -= o.z; return *this; +} +// ------------------------------------------------------------------------------------------------ +template +AI_FORCE_INLINE const aiVector3t& aiVector3t::operator *= (TReal f) { + x *= f; y *= f; z *= f; return *this; +} +// ------------------------------------------------------------------------------------------------ +template +AI_FORCE_INLINE const aiVector3t& aiVector3t::operator /= (TReal f) { + x /= f; y /= f; z /= f; return *this; +} +// ------------------------------------------------------------------------------------------------ +template +AI_FORCE_INLINE aiVector3t& aiVector3t::operator *= (const aiMatrix3x3t& mat){ + return(*this = mat * (*this)); +} +// ------------------------------------------------------------------------------------------------ +template +AI_FORCE_INLINE aiVector3t& aiVector3t::operator *= (const aiMatrix4x4t& mat){ + return(*this = mat * (*this)); +} +// ------------------------------------------------------------------------------------------------ +template +AI_FORCE_INLINE TReal aiVector3t::operator[](unsigned int i) const { + return *(&x + i); +} +// ------------------------------------------------------------------------------------------------ +template +AI_FORCE_INLINE TReal& aiVector3t::operator[](unsigned int i) { + return *(&x + i); +} +// ------------------------------------------------------------------------------------------------ +template +AI_FORCE_INLINE bool aiVector3t::operator== (const aiVector3t& other) const { + return x == other.x && y == other.y && z == other.z; +} +// ------------------------------------------------------------------------------------------------ +template +AI_FORCE_INLINE bool aiVector3t::operator!= (const aiVector3t& other) const { + return x != other.x || y != other.y || z != other.z; +} +// ------------------------------------------------------------------------------------------------ +template +AI_FORCE_INLINE const aiVector3t aiVector3t::SymMul(const aiVector3t& o) { + return aiVector3t(x*o.x,y*o.y,z*o.z); +} +// ------------------------------------------------------------------------------------------------ +// symmetric addition +template +AI_FORCE_INLINE aiVector3t operator + (const aiVector3t& v1, const aiVector3t& v2) { + return aiVector3t( v1.x + v2.x, v1.y + v2.y, v1.z + v2.z); +} +// ------------------------------------------------------------------------------------------------ +// symmetric subtraction +template +AI_FORCE_INLINE aiVector3t operator - (const aiVector3t& v1, const aiVector3t& v2) { + return aiVector3t( v1.x - v2.x, v1.y - v2.y, v1.z - v2.z); +} +// ------------------------------------------------------------------------------------------------ +// scalar product +template +AI_FORCE_INLINE TReal operator * (const aiVector3t& v1, const aiVector3t& v2) { + return v1.x*v2.x + v1.y*v2.y + v1.z*v2.z; +} +// ------------------------------------------------------------------------------------------------ +// scalar multiplication +template +AI_FORCE_INLINE aiVector3t operator * ( TReal f, const aiVector3t& v) { + return aiVector3t( f*v.x, f*v.y, f*v.z); +} +// ------------------------------------------------------------------------------------------------ +// and the other way around +template +AI_FORCE_INLINE aiVector3t operator * ( const aiVector3t& v, TReal f) { + return aiVector3t( f*v.x, f*v.y, f*v.z); +} +// ------------------------------------------------------------------------------------------------ +// scalar division +template +AI_FORCE_INLINE aiVector3t operator / ( const aiVector3t& v, TReal f) { + return v * (1/f); +} +// ------------------------------------------------------------------------------------------------ +// vector division +template +AI_FORCE_INLINE aiVector3t operator / ( const aiVector3t& v, const aiVector3t& v2) { + return aiVector3t(v.x / v2.x,v.y / v2.y,v.z / v2.z); +} +// ------------------------------------------------------------------------------------------------ +// cross product +template +AI_FORCE_INLINE aiVector3t operator ^ ( const aiVector3t& v1, const aiVector3t& v2) { + return aiVector3t( v1.y*v2.z - v1.z*v2.y, v1.z*v2.x - v1.x*v2.z, v1.x*v2.y - v1.y*v2.x); +} +// ------------------------------------------------------------------------------------------------ +// vector negation +template +AI_FORCE_INLINE aiVector3t operator - ( const aiVector3t& v) { + return aiVector3t( -v.x, -v.y, -v.z); +} + + +#endif // __cplusplus +#endif // AI_VECTOR3D_INL_INC diff --git a/Lib/Include/assimp/version.h b/Lib/Include/assimp/version.h new file mode 100644 index 0000000..620d63f --- /dev/null +++ b/Lib/Include/assimp/version.h @@ -0,0 +1,104 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2012, assimp team + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following +conditions are met: + +* Redistributions of source code must retain the above + copyright notice, this list of conditions and the + following disclaimer. + +* Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other + materials provided with the distribution. + +* Neither the name of the assimp team, nor the names of its + contributors may be used to endorse or promote products + derived from this software without specific prior + written permission of the assimp team. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"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 COPYRIGHT +OWNER OR CONTRIBUTORS 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. +--------------------------------------------------------------------------- +*/ + +/** @file aiVersion.h + * @brief Functions to query the version of the Assimp runtime, check + * compile flags, ... + */ +#ifndef INCLUDED_AI_VERSION_H +#define INCLUDED_AI_VERSION_H + +#ifdef __cplusplus +extern "C" { +#endif + +// --------------------------------------------------------------------------- +/** @brief Returns a string with legal copyright and licensing information + * about Assimp. The string may include multiple lines. + * @return Pointer to static string. + */ +ASSIMP_API const char* aiGetLegalString (void); + +// --------------------------------------------------------------------------- +/** @brief Returns the current minor version number of Assimp. + * @return Minor version of the Assimp runtime the application was + * linked/built against + */ +ASSIMP_API unsigned int aiGetVersionMinor (void); + +// --------------------------------------------------------------------------- +/** @brief Returns the current major version number of Assimp. + * @return Major version of the Assimp runtime the application was + * linked/built against + */ +ASSIMP_API unsigned int aiGetVersionMajor (void); + +// --------------------------------------------------------------------------- +/** @brief Returns the repository revision of the Assimp runtime. + * @return SVN Repository revision number of the Assimp runtime the + * application was linked/built against + */ +ASSIMP_API unsigned int aiGetVersionRevision (void); + + +//! Assimp was compiled as a shared object (Windows: DLL) +#define ASSIMP_CFLAGS_SHARED 0x1 +//! Assimp was compiled against STLport +#define ASSIMP_CFLAGS_STLPORT 0x2 +//! Assimp was compiled as a debug build +#define ASSIMP_CFLAGS_DEBUG 0x4 + +//! Assimp was compiled with ASSIMP_BUILD_BOOST_WORKAROUND defined +#define ASSIMP_CFLAGS_NOBOOST 0x8 +//! Assimp was compiled with ASSIMP_BUILD_SINGLETHREADED defined +#define ASSIMP_CFLAGS_SINGLETHREADED 0x10 + +// --------------------------------------------------------------------------- +/** @brief Returns assimp's compile flags + * @return Any bitwise combination of the ASSIMP_CFLAGS_xxx constants. + */ +ASSIMP_API unsigned int aiGetCompileFlags (void); + +#ifdef __cplusplus +} // end extern "C" +#endif + +#endif // !! #ifndef INCLUDED_AI_VERSION_H diff --git a/Lib/Include/enet/callbacks.h b/Lib/Include/enet/callbacks.h new file mode 100644 index 0000000..340a4a9 --- /dev/null +++ b/Lib/Include/enet/callbacks.h @@ -0,0 +1,27 @@ +/** + @file callbacks.h + @brief ENet callbacks +*/ +#ifndef __ENET_CALLBACKS_H__ +#define __ENET_CALLBACKS_H__ + +#include + +typedef struct _ENetCallbacks +{ + void * (ENET_CALLBACK * malloc) (size_t size); + void (ENET_CALLBACK * free) (void * memory); + void (ENET_CALLBACK * no_memory) (void); +} ENetCallbacks; + +/** @defgroup callbacks ENet internal callbacks + @{ + @ingroup private +*/ +extern void * enet_malloc (size_t); +extern void enet_free (void *); + +/** @} */ + +#endif /* __ENET_CALLBACKS_H__ */ + diff --git a/Lib/Include/enet/enet.h b/Lib/Include/enet/enet.h new file mode 100644 index 0000000..4dda551 --- /dev/null +++ b/Lib/Include/enet/enet.h @@ -0,0 +1,587 @@ +/** + @file enet.h + @brief ENet public header file +*/ +#ifndef __ENET_ENET_H__ +#define __ENET_ENET_H__ + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include + +#ifdef _WIN32 +#include "enet/win32.h" +#else +#include "enet/unix.h" +#endif + +#include "enet/types.h" +#include "enet/protocol.h" +#include "enet/list.h" +#include "enet/callbacks.h" + +#define ENET_VERSION_MAJOR 1 +#define ENET_VERSION_MINOR 3 +#define ENET_VERSION_PATCH 10 +#define ENET_VERSION_CREATE(major, minor, patch) (((major)<<16) | ((minor)<<8) | (patch)) +#define ENET_VERSION_GET_MAJOR(version) (((version)>>16)&0xFF) +#define ENET_VERSION_GET_MINOR(version) (((version)>>8)&0xFF) +#define ENET_VERSION_GET_PATCH(version) ((version)&0xFF) +#define ENET_VERSION ENET_VERSION_CREATE(ENET_VERSION_MAJOR, ENET_VERSION_MINOR, ENET_VERSION_PATCH) + +typedef enet_uint32 ENetVersion; + +struct _ENetHost; +struct _ENetEvent; +struct _ENetPacket; + +typedef enum _ENetSocketType +{ + ENET_SOCKET_TYPE_STREAM = 1, + ENET_SOCKET_TYPE_DATAGRAM = 2 +} ENetSocketType; + +typedef enum _ENetSocketWait +{ + ENET_SOCKET_WAIT_NONE = 0, + ENET_SOCKET_WAIT_SEND = (1 << 0), + ENET_SOCKET_WAIT_RECEIVE = (1 << 1), + ENET_SOCKET_WAIT_INTERRUPT = (1 << 2) +} ENetSocketWait; + +typedef enum _ENetSocketOption +{ + ENET_SOCKOPT_NONBLOCK = 1, + ENET_SOCKOPT_BROADCAST = 2, + ENET_SOCKOPT_RCVBUF = 3, + ENET_SOCKOPT_SNDBUF = 4, + ENET_SOCKOPT_REUSEADDR = 5, + ENET_SOCKOPT_RCVTIMEO = 6, + ENET_SOCKOPT_SNDTIMEO = 7, + ENET_SOCKOPT_ERROR = 8, + ENET_SOCKOPT_NODELAY = 9 +} ENetSocketOption; + +typedef enum _ENetSocketShutdown +{ + ENET_SOCKET_SHUTDOWN_READ = 0, + ENET_SOCKET_SHUTDOWN_WRITE = 1, + ENET_SOCKET_SHUTDOWN_READ_WRITE = 2 +} ENetSocketShutdown; + +#define ENET_HOST_ANY 0 +#define ENET_HOST_BROADCAST 0xFFFFFFFFU +#define ENET_PORT_ANY 0 + +/** + * Portable internet address structure. + * + * The host must be specified in network byte-order, and the port must be in host + * byte-order. The constant ENET_HOST_ANY may be used to specify the default + * server host. The constant ENET_HOST_BROADCAST may be used to specify the + * broadcast address (255.255.255.255). This makes sense for enet_host_connect, + * but not for enet_host_create. Once a server responds to a broadcast, the + * address is updated from ENET_HOST_BROADCAST to the server's actual IP address. + */ +typedef struct _ENetAddress +{ + enet_uint32 host; + enet_uint16 port; +} ENetAddress; + +/** + * Packet flag bit constants. + * + * The host must be specified in network byte-order, and the port must be in + * host byte-order. The constant ENET_HOST_ANY may be used to specify the + * default server host. + + @sa ENetPacket +*/ +typedef enum _ENetPacketFlag +{ + /** packet must be received by the target peer and resend attempts should be + * made until the packet is delivered */ + ENET_PACKET_FLAG_RELIABLE = (1 << 0), + /** packet will not be sequenced with other packets + * not supported for reliable packets + */ + ENET_PACKET_FLAG_UNSEQUENCED = (1 << 1), + /** packet will not allocate data, and user must supply it instead */ + ENET_PACKET_FLAG_NO_ALLOCATE = (1 << 2), + /** packet will be fragmented using unreliable (instead of reliable) sends + * if it exceeds the MTU */ + ENET_PACKET_FLAG_UNRELIABLE_FRAGMENT = (1 << 3), + + /** whether the packet has been sent from all queues it has been entered into */ + ENET_PACKET_FLAG_SENT = (1<<8) +} ENetPacketFlag; + +typedef void (ENET_CALLBACK * ENetPacketFreeCallback) (struct _ENetPacket *); + +/** + * ENet packet structure. + * + * An ENet data packet that may be sent to or received from a peer. The shown + * fields should only be read and never modified. The data field contains the + * allocated data for the packet. The dataLength fields specifies the length + * of the allocated data. The flags field is either 0 (specifying no flags), + * or a bitwise-or of any combination of the following flags: + * + * ENET_PACKET_FLAG_RELIABLE - packet must be received by the target peer + * and resend attempts should be made until the packet is delivered + * + * ENET_PACKET_FLAG_UNSEQUENCED - packet will not be sequenced with other packets + * (not supported for reliable packets) + * + * ENET_PACKET_FLAG_NO_ALLOCATE - packet will not allocate data, and user must supply it instead + + @sa ENetPacketFlag + */ +typedef struct _ENetPacket +{ + size_t referenceCount; /**< internal use only */ + enet_uint32 flags; /**< bitwise-or of ENetPacketFlag constants */ + enet_uint8 * data; /**< allocated data for packet */ + size_t dataLength; /**< length of data */ + ENetPacketFreeCallback freeCallback; /**< function to be called when the packet is no longer in use */ + void * userData; /**< application private data, may be freely modified */ +} ENetPacket; + +typedef struct _ENetAcknowledgement +{ + ENetListNode acknowledgementList; + enet_uint32 sentTime; + ENetProtocol command; +} ENetAcknowledgement; + +typedef struct _ENetOutgoingCommand +{ + ENetListNode outgoingCommandList; + enet_uint16 reliableSequenceNumber; + enet_uint16 unreliableSequenceNumber; + enet_uint32 sentTime; + enet_uint32 roundTripTimeout; + enet_uint32 roundTripTimeoutLimit; + enet_uint32 fragmentOffset; + enet_uint16 fragmentLength; + enet_uint16 sendAttempts; + ENetProtocol command; + ENetPacket * packet; +} ENetOutgoingCommand; + +typedef struct _ENetIncomingCommand +{ + ENetListNode incomingCommandList; + enet_uint16 reliableSequenceNumber; + enet_uint16 unreliableSequenceNumber; + ENetProtocol command; + enet_uint32 fragmentCount; + enet_uint32 fragmentsRemaining; + enet_uint32 * fragments; + ENetPacket * packet; +} ENetIncomingCommand; + +typedef enum _ENetPeerState +{ + ENET_PEER_STATE_DISCONNECTED = 0, + ENET_PEER_STATE_CONNECTING = 1, + ENET_PEER_STATE_ACKNOWLEDGING_CONNECT = 2, + ENET_PEER_STATE_CONNECTION_PENDING = 3, + ENET_PEER_STATE_CONNECTION_SUCCEEDED = 4, + ENET_PEER_STATE_CONNECTED = 5, + ENET_PEER_STATE_DISCONNECT_LATER = 6, + ENET_PEER_STATE_DISCONNECTING = 7, + ENET_PEER_STATE_ACKNOWLEDGING_DISCONNECT = 8, + ENET_PEER_STATE_ZOMBIE = 9 +} ENetPeerState; + +#ifndef ENET_BUFFER_MAXIMUM +#define ENET_BUFFER_MAXIMUM (1 + 2 * ENET_PROTOCOL_MAXIMUM_PACKET_COMMANDS) +#endif + +enum +{ + ENET_HOST_RECEIVE_BUFFER_SIZE = 256 * 1024, + ENET_HOST_SEND_BUFFER_SIZE = 256 * 1024, + ENET_HOST_BANDWIDTH_THROTTLE_INTERVAL = 1000, + ENET_HOST_DEFAULT_MTU = 1400, + + ENET_PEER_DEFAULT_ROUND_TRIP_TIME = 500, + ENET_PEER_DEFAULT_PACKET_THROTTLE = 32, + ENET_PEER_PACKET_THROTTLE_SCALE = 32, + ENET_PEER_PACKET_THROTTLE_COUNTER = 7, + ENET_PEER_PACKET_THROTTLE_ACCELERATION = 2, + ENET_PEER_PACKET_THROTTLE_DECELERATION = 2, + ENET_PEER_PACKET_THROTTLE_INTERVAL = 5000, + ENET_PEER_PACKET_LOSS_SCALE = (1 << 16), + ENET_PEER_PACKET_LOSS_INTERVAL = 10000, + ENET_PEER_WINDOW_SIZE_SCALE = 64 * 1024, + ENET_PEER_TIMEOUT_LIMIT = 32, + ENET_PEER_TIMEOUT_MINIMUM = 5000, + ENET_PEER_TIMEOUT_MAXIMUM = 30000, + ENET_PEER_PING_INTERVAL = 500, + ENET_PEER_UNSEQUENCED_WINDOWS = 64, + ENET_PEER_UNSEQUENCED_WINDOW_SIZE = 1024, + ENET_PEER_FREE_UNSEQUENCED_WINDOWS = 32, + ENET_PEER_RELIABLE_WINDOWS = 16, + ENET_PEER_RELIABLE_WINDOW_SIZE = 0x1000, + ENET_PEER_FREE_RELIABLE_WINDOWS = 8 +}; + +typedef struct _ENetChannel +{ + enet_uint16 outgoingReliableSequenceNumber; + enet_uint16 outgoingUnreliableSequenceNumber; + enet_uint16 usedReliableWindows; + enet_uint16 reliableWindows [ENET_PEER_RELIABLE_WINDOWS]; + enet_uint16 incomingReliableSequenceNumber; + enet_uint16 incomingUnreliableSequenceNumber; + ENetList incomingReliableCommands; + ENetList incomingUnreliableCommands; +} ENetChannel; + +/** + * An ENet peer which data packets may be sent or received from. + * + * No fields should be modified unless otherwise specified. + */ +typedef struct _ENetPeer +{ + ENetListNode dispatchList; + struct _ENetHost * host; + enet_uint16 outgoingPeerID; + enet_uint16 incomingPeerID; + enet_uint32 connectID; + enet_uint8 outgoingSessionID; + enet_uint8 incomingSessionID; + ENetAddress address; /**< Internet address of the peer */ + void * data; /**< Application private data, may be freely modified */ + ENetPeerState state; + ENetChannel * channels; + size_t channelCount; /**< Number of channels allocated for communication with peer */ + enet_uint32 incomingBandwidth; /**< Downstream bandwidth of the client in bytes/second */ + enet_uint32 outgoingBandwidth; /**< Upstream bandwidth of the client in bytes/second */ + enet_uint32 incomingBandwidthThrottleEpoch; + enet_uint32 outgoingBandwidthThrottleEpoch; + enet_uint32 incomingDataTotal; + enet_uint32 outgoingDataTotal; + enet_uint32 lastSendTime; + enet_uint32 lastReceiveTime; + enet_uint32 nextTimeout; + enet_uint32 earliestTimeout; + enet_uint32 packetLossEpoch; + enet_uint32 packetsSent; + enet_uint32 packetsLost; + enet_uint32 packetLoss; /**< mean packet loss of reliable packets as a ratio with respect to the constant ENET_PEER_PACKET_LOSS_SCALE */ + enet_uint32 packetLossVariance; + enet_uint32 packetThrottle; + enet_uint32 packetThrottleLimit; + enet_uint32 packetThrottleCounter; + enet_uint32 packetThrottleEpoch; + enet_uint32 packetThrottleAcceleration; + enet_uint32 packetThrottleDeceleration; + enet_uint32 packetThrottleInterval; + enet_uint32 pingInterval; + enet_uint32 timeoutLimit; + enet_uint32 timeoutMinimum; + enet_uint32 timeoutMaximum; + enet_uint32 lastRoundTripTime; + enet_uint32 lowestRoundTripTime; + enet_uint32 lastRoundTripTimeVariance; + enet_uint32 highestRoundTripTimeVariance; + enet_uint32 roundTripTime; /**< mean round trip time (RTT), in milliseconds, between sending a reliable packet and receiving its acknowledgement */ + enet_uint32 roundTripTimeVariance; + enet_uint32 mtu; + enet_uint32 windowSize; + enet_uint32 reliableDataInTransit; + enet_uint16 outgoingReliableSequenceNumber; + ENetList acknowledgements; + ENetList sentReliableCommands; + ENetList sentUnreliableCommands; + ENetList outgoingReliableCommands; + ENetList outgoingUnreliableCommands; + ENetList dispatchedCommands; + int needsDispatch; + enet_uint16 incomingUnsequencedGroup; + enet_uint16 outgoingUnsequencedGroup; + enet_uint32 unsequencedWindow [ENET_PEER_UNSEQUENCED_WINDOW_SIZE / 32]; + enet_uint32 eventData; +} ENetPeer; + +/** An ENet packet compressor for compressing UDP packets before socket sends or receives. + */ +typedef struct _ENetCompressor +{ + /** Context data for the compressor. Must be non-NULL. */ + void * context; + /** Compresses from inBuffers[0:inBufferCount-1], containing inLimit bytes, to outData, outputting at most outLimit bytes. Should return 0 on failure. */ + size_t (ENET_CALLBACK * compress) (void * context, const ENetBuffer * inBuffers, size_t inBufferCount, size_t inLimit, enet_uint8 * outData, size_t outLimit); + /** Decompresses from inData, containing inLimit bytes, to outData, outputting at most outLimit bytes. Should return 0 on failure. */ + size_t (ENET_CALLBACK * decompress) (void * context, const enet_uint8 * inData, size_t inLimit, enet_uint8 * outData, size_t outLimit); + /** Destroys the context when compression is disabled or the host is destroyed. May be NULL. */ + void (ENET_CALLBACK * destroy) (void * context); +} ENetCompressor; + +/** Callback that computes the checksum of the data held in buffers[0:bufferCount-1] */ +typedef enet_uint32 (ENET_CALLBACK * ENetChecksumCallback) (const ENetBuffer * buffers, size_t bufferCount); + +/** Callback for intercepting received raw UDP packets. Should return 1 to intercept, 0 to ignore, or -1 to propagate an error. */ +typedef int (ENET_CALLBACK * ENetInterceptCallback) (struct _ENetHost * host, struct _ENetEvent * event); + +/** An ENet host for communicating with peers. + * + * No fields should be modified unless otherwise stated. + + @sa enet_host_create() + @sa enet_host_destroy() + @sa enet_host_connect() + @sa enet_host_service() + @sa enet_host_flush() + @sa enet_host_broadcast() + @sa enet_host_compress() + @sa enet_host_compress_with_range_coder() + @sa enet_host_channel_limit() + @sa enet_host_bandwidth_limit() + @sa enet_host_bandwidth_throttle() + */ +typedef struct _ENetHost +{ + ENetSocket socket; + ENetAddress address; /**< Internet address of the host */ + enet_uint32 incomingBandwidth; /**< downstream bandwidth of the host */ + enet_uint32 outgoingBandwidth; /**< upstream bandwidth of the host */ + enet_uint32 bandwidthThrottleEpoch; + enet_uint32 mtu; + enet_uint32 randomSeed; + int recalculateBandwidthLimits; + ENetPeer * peers; /**< array of peers allocated for this host */ + size_t peerCount; /**< number of peers allocated for this host */ + size_t channelLimit; /**< maximum number of channels allowed for connected peers */ + enet_uint32 serviceTime; + ENetList dispatchQueue; + int continueSending; + size_t packetSize; + enet_uint16 headerFlags; + ENetProtocol commands [ENET_PROTOCOL_MAXIMUM_PACKET_COMMANDS]; + size_t commandCount; + ENetBuffer buffers [ENET_BUFFER_MAXIMUM]; + size_t bufferCount; + ENetChecksumCallback checksum; /**< callback the user can set to enable packet checksums for this host */ + ENetCompressor compressor; + enet_uint8 packetData [2][ENET_PROTOCOL_MAXIMUM_MTU]; + ENetAddress receivedAddress; + enet_uint8 * receivedData; + size_t receivedDataLength; + enet_uint32 totalSentData; /**< total data sent, user should reset to 0 as needed to prevent overflow */ + enet_uint32 totalSentPackets; /**< total UDP packets sent, user should reset to 0 as needed to prevent overflow */ + enet_uint32 totalReceivedData; /**< total data received, user should reset to 0 as needed to prevent overflow */ + enet_uint32 totalReceivedPackets; /**< total UDP packets received, user should reset to 0 as needed to prevent overflow */ + ENetInterceptCallback intercept; /**< callback the user can set to intercept received raw UDP packets */ + size_t connectedPeers; + size_t bandwidthLimitedPeers; + size_t duplicatePeers; /**< optional number of allowed peers from duplicate IPs, defaults to ENET_PROTOCOL_MAXIMUM_PEER_ID */ +} ENetHost; + +/** + * An ENet event type, as specified in @ref ENetEvent. + */ +typedef enum _ENetEventType +{ + /** no event occurred within the specified time limit */ + ENET_EVENT_TYPE_NONE = 0, + + /** a connection request initiated by enet_host_connect has completed. + * The peer field contains the peer which successfully connected. + */ + ENET_EVENT_TYPE_CONNECT = 1, + + /** a peer has disconnected. This event is generated on a successful + * completion of a disconnect initiated by enet_pper_disconnect, if + * a peer has timed out, or if a connection request intialized by + * enet_host_connect has timed out. The peer field contains the peer + * which disconnected. The data field contains user supplied data + * describing the disconnection, or 0, if none is available. + */ + ENET_EVENT_TYPE_DISCONNECT = 2, + + /** a packet has been received from a peer. The peer field specifies the + * peer which sent the packet. The channelID field specifies the channel + * number upon which the packet was received. The packet field contains + * the packet that was received; this packet must be destroyed with + * enet_packet_destroy after use. + */ + ENET_EVENT_TYPE_RECEIVE = 3 +} ENetEventType; + +/** + * An ENet event as returned by enet_host_service(). + + @sa enet_host_service + */ +typedef struct _ENetEvent +{ + ENetEventType type; /**< type of the event */ + ENetPeer * peer; /**< peer that generated a connect, disconnect or receive event */ + enet_uint8 channelID; /**< channel on the peer that generated the event, if appropriate */ + enet_uint32 data; /**< data associated with the event, if appropriate */ + ENetPacket * packet; /**< packet associated with the event, if appropriate */ +} ENetEvent; + +/** @defgroup global ENet global functions + @{ +*/ + +/** + Initializes ENet globally. Must be called prior to using any functions in + ENet. + @returns 0 on success, < 0 on failure +*/ +ENET_API int enet_initialize (void); + +/** + Initializes ENet globally and supplies user-overridden callbacks. Must be called prior to using any functions in ENet. Do not use enet_initialize() if you use this variant. Make sure the ENetCallbacks structure is zeroed out so that any additional callbacks added in future versions will be properly ignored. + + @param version the constant ENET_VERSION should be supplied so ENet knows which version of ENetCallbacks struct to use + @param inits user-overriden callbacks where any NULL callbacks will use ENet's defaults + @returns 0 on success, < 0 on failure +*/ +ENET_API int enet_initialize_with_callbacks (ENetVersion version, const ENetCallbacks * inits); + +/** + Shuts down ENet globally. Should be called when a program that has + initialized ENet exits. +*/ +ENET_API void enet_deinitialize (void); + +/** + Gives the linked version of the ENet library. + @returns the version number +*/ +ENET_API ENetVersion enet_linked_version (void); + +/** @} */ + +/** @defgroup private ENet private implementation functions */ + +/** + Returns the wall-time in milliseconds. Its initial value is unspecified + unless otherwise set. + */ +ENET_API enet_uint32 enet_time_get (void); +/** + Sets the current wall-time in milliseconds. + */ +ENET_API void enet_time_set (enet_uint32); + +/** @defgroup socket ENet socket functions + @{ +*/ +ENET_API ENetSocket enet_socket_create (ENetSocketType); +ENET_API int enet_socket_bind (ENetSocket, const ENetAddress *); +ENET_API int enet_socket_get_address (ENetSocket, ENetAddress *); +ENET_API int enet_socket_listen (ENetSocket, int); +ENET_API ENetSocket enet_socket_accept (ENetSocket, ENetAddress *); +ENET_API int enet_socket_connect (ENetSocket, const ENetAddress *); +ENET_API int enet_socket_send (ENetSocket, const ENetAddress *, const ENetBuffer *, size_t); +ENET_API int enet_socket_receive (ENetSocket, ENetAddress *, ENetBuffer *, size_t); +ENET_API int enet_socket_wait (ENetSocket, enet_uint32 *, enet_uint32); +ENET_API int enet_socket_set_option (ENetSocket, ENetSocketOption, int); +ENET_API int enet_socket_get_option (ENetSocket, ENetSocketOption, int *); +ENET_API int enet_socket_shutdown (ENetSocket, ENetSocketShutdown); +ENET_API void enet_socket_destroy (ENetSocket); +ENET_API int enet_socketset_select (ENetSocket, ENetSocketSet *, ENetSocketSet *, enet_uint32); + +/** @} */ + +/** @defgroup Address ENet address functions + @{ +*/ +/** Attempts to resolve the host named by the parameter hostName and sets + the host field in the address parameter if successful. + @param address destination to store resolved address + @param hostName host name to lookup + @retval 0 on success + @retval < 0 on failure + @returns the address of the given hostName in address on success +*/ +ENET_API int enet_address_set_host (ENetAddress * address, const char * hostName); + +/** Gives the printable form of the ip address specified in the address parameter. + @param address address printed + @param hostName destination for name, must not be NULL + @param nameLength maximum length of hostName. + @returns the null-terminated name of the host in hostName on success + @retval 0 on success + @retval < 0 on failure +*/ +ENET_API int enet_address_get_host_ip (const ENetAddress * address, char * hostName, size_t nameLength); + +/** Attempts to do a reverse lookup of the host field in the address parameter. + @param address address used for reverse lookup + @param hostName destination for name, must not be NULL + @param nameLength maximum length of hostName. + @returns the null-terminated name of the host in hostName on success + @retval 0 on success + @retval < 0 on failure +*/ +ENET_API int enet_address_get_host (const ENetAddress * address, char * hostName, size_t nameLength); + +/** @} */ + +ENET_API ENetPacket * enet_packet_create (const void *, size_t, enet_uint32); +ENET_API void enet_packet_destroy (ENetPacket *); +ENET_API int enet_packet_resize (ENetPacket *, size_t); +ENET_API enet_uint32 enet_crc32 (const ENetBuffer *, size_t); + +ENET_API ENetHost * enet_host_create (const ENetAddress *, size_t, size_t, enet_uint32, enet_uint32); +ENET_API void enet_host_destroy (ENetHost *); +ENET_API ENetPeer * enet_host_connect (ENetHost *, const ENetAddress *, size_t, enet_uint32); +ENET_API int enet_host_check_events (ENetHost *, ENetEvent *); +ENET_API int enet_host_service (ENetHost *, ENetEvent *, enet_uint32); +ENET_API void enet_host_flush (ENetHost *); +ENET_API void enet_host_broadcast (ENetHost *, enet_uint8, ENetPacket *); +ENET_API void enet_host_compress (ENetHost *, const ENetCompressor *); +ENET_API int enet_host_compress_with_range_coder (ENetHost * host); +ENET_API void enet_host_channel_limit (ENetHost *, size_t); +ENET_API void enet_host_bandwidth_limit (ENetHost *, enet_uint32, enet_uint32); +extern void enet_host_bandwidth_throttle (ENetHost *); +extern enet_uint32 enet_host_random_seed (void); + +ENET_API int enet_peer_send (ENetPeer *, enet_uint8, ENetPacket *); +ENET_API ENetPacket * enet_peer_receive (ENetPeer *, enet_uint8 * channelID); +ENET_API void enet_peer_ping (ENetPeer *); +ENET_API void enet_peer_ping_interval (ENetPeer *, enet_uint32); +ENET_API void enet_peer_timeout (ENetPeer *, enet_uint32, enet_uint32, enet_uint32); +ENET_API void enet_peer_reset (ENetPeer *); +ENET_API void enet_peer_disconnect (ENetPeer *, enet_uint32); +ENET_API void enet_peer_disconnect_now (ENetPeer *, enet_uint32); +ENET_API void enet_peer_disconnect_later (ENetPeer *, enet_uint32); +ENET_API void enet_peer_throttle_configure (ENetPeer *, enet_uint32, enet_uint32, enet_uint32); +extern int enet_peer_throttle (ENetPeer *, enet_uint32); +extern void enet_peer_reset_queues (ENetPeer *); +extern void enet_peer_setup_outgoing_command (ENetPeer *, ENetOutgoingCommand *); +extern ENetOutgoingCommand * enet_peer_queue_outgoing_command (ENetPeer *, const ENetProtocol *, ENetPacket *, enet_uint32, enet_uint16); +extern ENetIncomingCommand * enet_peer_queue_incoming_command (ENetPeer *, const ENetProtocol *, ENetPacket *, enet_uint32); +extern ENetAcknowledgement * enet_peer_queue_acknowledgement (ENetPeer *, const ENetProtocol *, enet_uint16); +extern void enet_peer_dispatch_incoming_unreliable_commands (ENetPeer *, ENetChannel *); +extern void enet_peer_dispatch_incoming_reliable_commands (ENetPeer *, ENetChannel *); +extern void enet_peer_on_connect (ENetPeer *); +extern void enet_peer_on_disconnect (ENetPeer *); + +ENET_API void * enet_range_coder_create (void); +ENET_API void enet_range_coder_destroy (void *); +ENET_API size_t enet_range_coder_compress (void *, const ENetBuffer *, size_t, size_t, enet_uint8 *, size_t); +ENET_API size_t enet_range_coder_decompress (void *, const enet_uint8 *, size_t, enet_uint8 *, size_t); + +extern size_t enet_protocol_command_size (enet_uint8); + +#ifdef __cplusplus +} +#endif + +#endif /* __ENET_ENET_H__ */ + diff --git a/Lib/Include/enet/list.h b/Lib/Include/enet/list.h new file mode 100644 index 0000000..d7b2600 --- /dev/null +++ b/Lib/Include/enet/list.h @@ -0,0 +1,43 @@ +/** + @file list.h + @brief ENet list management +*/ +#ifndef __ENET_LIST_H__ +#define __ENET_LIST_H__ + +#include + +typedef struct _ENetListNode +{ + struct _ENetListNode * next; + struct _ENetListNode * previous; +} ENetListNode; + +typedef ENetListNode * ENetListIterator; + +typedef struct _ENetList +{ + ENetListNode sentinel; +} ENetList; + +extern void enet_list_clear (ENetList *); + +extern ENetListIterator enet_list_insert (ENetListIterator, void *); +extern void * enet_list_remove (ENetListIterator); +extern ENetListIterator enet_list_move (ENetListIterator, void *, void *); + +extern size_t enet_list_size (ENetList *); + +#define enet_list_begin(list) ((list) -> sentinel.next) +#define enet_list_end(list) (& (list) -> sentinel) + +#define enet_list_empty(list) (enet_list_begin (list) == enet_list_end (list)) + +#define enet_list_next(iterator) ((iterator) -> next) +#define enet_list_previous(iterator) ((iterator) -> previous) + +#define enet_list_front(list) ((void *) (list) -> sentinel.next) +#define enet_list_back(list) ((void *) (list) -> sentinel.previous) + +#endif /* __ENET_LIST_H__ */ + diff --git a/Lib/Include/enet/protocol.h b/Lib/Include/enet/protocol.h new file mode 100644 index 0000000..b8f8416 --- /dev/null +++ b/Lib/Include/enet/protocol.h @@ -0,0 +1,199 @@ +/** + @file protocol.h + @brief ENet protocol +*/ +#ifndef __ENET_PROTOCOL_H__ +#define __ENET_PROTOCOL_H__ + +#include "enet/types.h" + +enum +{ + ENET_PROTOCOL_MINIMUM_MTU = 576, + ENET_PROTOCOL_MAXIMUM_MTU = 4096, + ENET_PROTOCOL_MAXIMUM_PACKET_COMMANDS = 32, + ENET_PROTOCOL_MINIMUM_WINDOW_SIZE = 4096, + ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE = 65536, + ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT = 1, + ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT = 255, + ENET_PROTOCOL_MAXIMUM_PEER_ID = 0xFFF, + ENET_PROTOCOL_MAXIMUM_PACKET_SIZE = 1024 * 1024 * 1024, + ENET_PROTOCOL_MAXIMUM_FRAGMENT_COUNT = 1024 * 1024 +}; + +typedef enum _ENetProtocolCommand +{ + ENET_PROTOCOL_COMMAND_NONE = 0, + ENET_PROTOCOL_COMMAND_ACKNOWLEDGE = 1, + ENET_PROTOCOL_COMMAND_CONNECT = 2, + ENET_PROTOCOL_COMMAND_VERIFY_CONNECT = 3, + ENET_PROTOCOL_COMMAND_DISCONNECT = 4, + ENET_PROTOCOL_COMMAND_PING = 5, + ENET_PROTOCOL_COMMAND_SEND_RELIABLE = 6, + ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE = 7, + ENET_PROTOCOL_COMMAND_SEND_FRAGMENT = 8, + ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED = 9, + ENET_PROTOCOL_COMMAND_BANDWIDTH_LIMIT = 10, + ENET_PROTOCOL_COMMAND_THROTTLE_CONFIGURE = 11, + ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE_FRAGMENT = 12, + ENET_PROTOCOL_COMMAND_COUNT = 13, + + ENET_PROTOCOL_COMMAND_MASK = 0x0F +} ENetProtocolCommand; + +typedef enum _ENetProtocolFlag +{ + ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE = (1 << 7), + ENET_PROTOCOL_COMMAND_FLAG_UNSEQUENCED = (1 << 6), + + ENET_PROTOCOL_HEADER_FLAG_COMPRESSED = (1 << 14), + ENET_PROTOCOL_HEADER_FLAG_SENT_TIME = (1 << 15), + ENET_PROTOCOL_HEADER_FLAG_MASK = ENET_PROTOCOL_HEADER_FLAG_COMPRESSED | ENET_PROTOCOL_HEADER_FLAG_SENT_TIME, + + ENET_PROTOCOL_HEADER_SESSION_MASK = (3 << 12), + ENET_PROTOCOL_HEADER_SESSION_SHIFT = 12 +} ENetProtocolFlag; + +#ifdef _MSC_VER_ +#pragma pack(push, 1) +#define ENET_PACKED +#elif defined(__GNUC__) || defined(__clang__) +#define ENET_PACKED __attribute__ ((packed)) +#else +#define ENET_PACKED +#endif + +typedef struct _ENetProtocolHeader +{ + enet_uint16 peerID; + enet_uint16 sentTime; +} ENET_PACKED ENetProtocolHeader; + +typedef struct _ENetProtocolCommandHeader +{ + enet_uint8 command; + enet_uint8 channelID; + enet_uint16 reliableSequenceNumber; +} ENET_PACKED ENetProtocolCommandHeader; + +typedef struct _ENetProtocolAcknowledge +{ + ENetProtocolCommandHeader header; + enet_uint16 receivedReliableSequenceNumber; + enet_uint16 receivedSentTime; +} ENET_PACKED ENetProtocolAcknowledge; + +typedef struct _ENetProtocolConnect +{ + ENetProtocolCommandHeader header; + enet_uint16 outgoingPeerID; + enet_uint8 incomingSessionID; + enet_uint8 outgoingSessionID; + enet_uint32 mtu; + enet_uint32 windowSize; + enet_uint32 channelCount; + enet_uint32 incomingBandwidth; + enet_uint32 outgoingBandwidth; + enet_uint32 packetThrottleInterval; + enet_uint32 packetThrottleAcceleration; + enet_uint32 packetThrottleDeceleration; + enet_uint32 connectID; + enet_uint32 data; +} ENET_PACKED ENetProtocolConnect; + +typedef struct _ENetProtocolVerifyConnect +{ + ENetProtocolCommandHeader header; + enet_uint16 outgoingPeerID; + enet_uint8 incomingSessionID; + enet_uint8 outgoingSessionID; + enet_uint32 mtu; + enet_uint32 windowSize; + enet_uint32 channelCount; + enet_uint32 incomingBandwidth; + enet_uint32 outgoingBandwidth; + enet_uint32 packetThrottleInterval; + enet_uint32 packetThrottleAcceleration; + enet_uint32 packetThrottleDeceleration; + enet_uint32 connectID; +} ENET_PACKED ENetProtocolVerifyConnect; + +typedef struct _ENetProtocolBandwidthLimit +{ + ENetProtocolCommandHeader header; + enet_uint32 incomingBandwidth; + enet_uint32 outgoingBandwidth; +} ENET_PACKED ENetProtocolBandwidthLimit; + +typedef struct _ENetProtocolThrottleConfigure +{ + ENetProtocolCommandHeader header; + enet_uint32 packetThrottleInterval; + enet_uint32 packetThrottleAcceleration; + enet_uint32 packetThrottleDeceleration; +} ENET_PACKED ENetProtocolThrottleConfigure; + +typedef struct _ENetProtocolDisconnect +{ + ENetProtocolCommandHeader header; + enet_uint32 data; +} ENET_PACKED ENetProtocolDisconnect; + +typedef struct _ENetProtocolPing +{ + ENetProtocolCommandHeader header; +} ENET_PACKED ENetProtocolPing; + +typedef struct _ENetProtocolSendReliable +{ + ENetProtocolCommandHeader header; + enet_uint16 dataLength; +} ENET_PACKED ENetProtocolSendReliable; + +typedef struct _ENetProtocolSendUnreliable +{ + ENetProtocolCommandHeader header; + enet_uint16 unreliableSequenceNumber; + enet_uint16 dataLength; +} ENET_PACKED ENetProtocolSendUnreliable; + +typedef struct _ENetProtocolSendUnsequenced +{ + ENetProtocolCommandHeader header; + enet_uint16 unsequencedGroup; + enet_uint16 dataLength; +} ENET_PACKED ENetProtocolSendUnsequenced; + +typedef struct _ENetProtocolSendFragment +{ + ENetProtocolCommandHeader header; + enet_uint16 startSequenceNumber; + enet_uint16 dataLength; + enet_uint32 fragmentCount; + enet_uint32 fragmentNumber; + enet_uint32 totalLength; + enet_uint32 fragmentOffset; +} ENET_PACKED ENetProtocolSendFragment; + +typedef union _ENetProtocol +{ + ENetProtocolCommandHeader header; + ENetProtocolAcknowledge acknowledge; + ENetProtocolConnect connect; + ENetProtocolVerifyConnect verifyConnect; + ENetProtocolDisconnect disconnect; + ENetProtocolPing ping; + ENetProtocolSendReliable sendReliable; + ENetProtocolSendUnreliable sendUnreliable; + ENetProtocolSendUnsequenced sendUnsequenced; + ENetProtocolSendFragment sendFragment; + ENetProtocolBandwidthLimit bandwidthLimit; + ENetProtocolThrottleConfigure throttleConfigure; +} ENET_PACKED ENetProtocol; + +#ifdef _MSC_VER_ +#pragma pack(pop) +#endif + +#endif /* __ENET_PROTOCOL_H__ */ + diff --git a/Lib/Include/enet/time.h b/Lib/Include/enet/time.h new file mode 100644 index 0000000..c82a546 --- /dev/null +++ b/Lib/Include/enet/time.h @@ -0,0 +1,18 @@ +/** + @file time.h + @brief ENet time constants and macros +*/ +#ifndef __ENET_TIME_H__ +#define __ENET_TIME_H__ + +#define ENET_TIME_OVERFLOW 86400000 + +#define ENET_TIME_LESS(a, b) ((a) - (b) >= ENET_TIME_OVERFLOW) +#define ENET_TIME_GREATER(a, b) ((b) - (a) >= ENET_TIME_OVERFLOW) +#define ENET_TIME_LESS_EQUAL(a, b) (! ENET_TIME_GREATER (a, b)) +#define ENET_TIME_GREATER_EQUAL(a, b) (! ENET_TIME_LESS (a, b)) + +#define ENET_TIME_DIFFERENCE(a, b) ((a) - (b) >= ENET_TIME_OVERFLOW ? (b) - (a) : (a) - (b)) + +#endif /* __ENET_TIME_H__ */ + diff --git a/Lib/Include/enet/types.h b/Lib/Include/enet/types.h new file mode 100644 index 0000000..ab010a4 --- /dev/null +++ b/Lib/Include/enet/types.h @@ -0,0 +1,13 @@ +/** + @file types.h + @brief type definitions for ENet +*/ +#ifndef __ENET_TYPES_H__ +#define __ENET_TYPES_H__ + +typedef unsigned char enet_uint8; /**< unsigned 8-bit type */ +typedef unsigned short enet_uint16; /**< unsigned 16-bit type */ +typedef unsigned int enet_uint32; /**< unsigned 32-bit type */ + +#endif /* __ENET_TYPES_H__ */ + diff --git a/Lib/Include/enet/unix.h b/Lib/Include/enet/unix.h new file mode 100644 index 0000000..9683c09 --- /dev/null +++ b/Lib/Include/enet/unix.h @@ -0,0 +1,47 @@ +/** + @file unix.h + @brief ENet Unix header +*/ +#ifndef __ENET_UNIX_H__ +#define __ENET_UNIX_H__ + +#include +#include +#include +#include +#include +#include + +#ifdef MSG_MAXIOVLEN +#define ENET_BUFFER_MAXIMUM MSG_MAXIOVLEN +#endif + +typedef int ENetSocket; + +#define ENET_SOCKET_NULL -1 + +#define ENET_HOST_TO_NET_16(value) (htons (value)) /**< macro that converts host to net byte-order of a 16-bit value */ +#define ENET_HOST_TO_NET_32(value) (htonl (value)) /**< macro that converts host to net byte-order of a 32-bit value */ + +#define ENET_NET_TO_HOST_16(value) (ntohs (value)) /**< macro that converts net to host byte-order of a 16-bit value */ +#define ENET_NET_TO_HOST_32(value) (ntohl (value)) /**< macro that converts net to host byte-order of a 32-bit value */ + +typedef struct +{ + void * data; + size_t dataLength; +} ENetBuffer; + +#define ENET_CALLBACK + +#define ENET_API extern + +typedef fd_set ENetSocketSet; + +#define ENET_SOCKETSET_EMPTY(sockset) FD_ZERO (& (sockset)) +#define ENET_SOCKETSET_ADD(sockset, socket) FD_SET (socket, & (sockset)) +#define ENET_SOCKETSET_REMOVE(sockset, socket) FD_CLEAR (socket, & (sockset)) +#define ENET_SOCKETSET_CHECK(sockset, socket) FD_ISSET (socket, & (sockset)) + +#endif /* __ENET_UNIX_H__ */ + diff --git a/Lib/Include/enet/utility.h b/Lib/Include/enet/utility.h new file mode 100644 index 0000000..e48a476 --- /dev/null +++ b/Lib/Include/enet/utility.h @@ -0,0 +1,12 @@ +/** + @file utility.h + @brief ENet utility header +*/ +#ifndef __ENET_UTILITY_H__ +#define __ENET_UTILITY_H__ + +#define ENET_MAX(x, y) ((x) > (y) ? (x) : (y)) +#define ENET_MIN(x, y) ((x) < (y) ? (x) : (y)) + +#endif /* __ENET_UTILITY_H__ */ + diff --git a/Lib/Include/enet/win32.h b/Lib/Include/enet/win32.h new file mode 100644 index 0000000..126cb74 --- /dev/null +++ b/Lib/Include/enet/win32.h @@ -0,0 +1,60 @@ +/** + @file win32.h + @brief ENet Win32 header +*/ +#ifndef __ENET_WIN32_H__ +#define __ENET_WIN32_H__ + +#ifdef _MSC_VER +#ifdef ENET_BUILDING_LIB +#pragma warning (disable: 4996) // 'strncpy' was declared deprecated +#pragma warning (disable: 4267) // size_t to int conversion +#pragma warning (disable: 4244) // 64bit to 32bit int +#pragma warning (disable: 4018) // signed/unsigned mismatch +#pragma warning (disable: 4146) // unary minus operator applied to unsigned type +#endif +#endif + +#include +#include + +typedef SOCKET ENetSocket; + +#define ENET_SOCKET_NULL INVALID_SOCKET + +#define ENET_HOST_TO_NET_16(value) (htons (value)) +#define ENET_HOST_TO_NET_32(value) (htonl (value)) + +#define ENET_NET_TO_HOST_16(value) (ntohs (value)) +#define ENET_NET_TO_HOST_32(value) (ntohl (value)) + +typedef struct +{ + size_t dataLength; + void * data; +} ENetBuffer; + +#define ENET_CALLBACK __cdecl + +#define ENET_DLL 1 /* Added by Patrick Baggett */ + +#ifdef ENET_DLL +#ifdef ENET_BUILDING_LIB +#define ENET_API __declspec( dllexport ) +#else +#define ENET_API __declspec( dllimport ) +#endif /* ENET_BUILDING_LIB */ +#else /* !ENET_DLL */ +#define ENET_API extern +#endif /* ENET_DLL */ + +typedef fd_set ENetSocketSet; + +#define ENET_SOCKETSET_EMPTY(sockset) FD_ZERO (& (sockset)) +#define ENET_SOCKETSET_ADD(sockset, socket) FD_SET (socket, & (sockset)) +#define ENET_SOCKETSET_REMOVE(sockset, socket) FD_CLEAR (socket, & (sockset)) +#define ENET_SOCKETSET_CHECK(sockset, socket) FD_ISSET (socket, & (sockset)) + +#endif /* __ENET_WIN32_H__ */ + + diff --git a/Lib/Include/freetype/config/ftconfig.h b/Lib/Include/freetype/config/ftconfig.h new file mode 100644 index 0000000..cbe30f2 --- /dev/null +++ b/Lib/Include/freetype/config/ftconfig.h @@ -0,0 +1,528 @@ +/***************************************************************************/ +/* */ +/* ftconfig.h */ +/* */ +/* ANSI-specific configuration file (specification only). */ +/* */ +/* Copyright 1996-2001, 2002, 2003, 2004, 2006, 2007, 2008, 2010 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + + /*************************************************************************/ + /* */ + /* This header file contains a number of macro definitions that are used */ + /* by the rest of the engine. Most of the macros here are automatically */ + /* determined at compile time, and you should not need to change it to */ + /* port FreeType, except to compile the library with a non-ANSI */ + /* compiler. */ + /* */ + /* Note however that if some specific modifications are needed, we */ + /* advise you to place a modified copy in your build directory. */ + /* */ + /* The build directory is usually `freetype/builds/', and */ + /* contains system-specific files that are always included first when */ + /* building the library. */ + /* */ + /* This ANSI version should stay in `include/freetype/config'. */ + /* */ + /*************************************************************************/ + +#ifndef __FTCONFIG_H__ +#define __FTCONFIG_H__ + +#include +#include FT_CONFIG_OPTIONS_H +#include FT_CONFIG_STANDARD_LIBRARY_H + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /* */ + /* PLATFORM-SPECIFIC CONFIGURATION MACROS */ + /* */ + /* These macros can be toggled to suit a specific system. The current */ + /* ones are defaults used to compile FreeType in an ANSI C environment */ + /* (16bit compilers are also supported). Copy this file to your own */ + /* `freetype/builds/' directory, and edit it to port the engine. */ + /* */ + /*************************************************************************/ + + + /* There are systems (like the Texas Instruments 'C54x) where a `char' */ + /* has 16 bits. ANSI C says that sizeof(char) is always 1. Since an */ + /* `int' has 16 bits also for this system, sizeof(int) gives 1 which */ + /* is probably unexpected. */ + /* */ + /* `CHAR_BIT' (defined in limits.h) gives the number of bits in a */ + /* `char' type. */ + +#ifndef FT_CHAR_BIT +#define FT_CHAR_BIT CHAR_BIT +#endif + + + /* The size of an `int' type. */ +#if FT_UINT_MAX == 0xFFFFUL +#define FT_SIZEOF_INT (16 / FT_CHAR_BIT) +#elif FT_UINT_MAX == 0xFFFFFFFFUL +#define FT_SIZEOF_INT (32 / FT_CHAR_BIT) +#elif FT_UINT_MAX > 0xFFFFFFFFUL && FT_UINT_MAX == 0xFFFFFFFFFFFFFFFFUL +#define FT_SIZEOF_INT (64 / FT_CHAR_BIT) +#else +#error "Unsupported size of `int' type!" +#endif + + /* The size of a `long' type. A five-byte `long' (as used e.g. on the */ + /* DM642) is recognized but avoided. */ +#if FT_ULONG_MAX == 0xFFFFFFFFUL +#define FT_SIZEOF_LONG (32 / FT_CHAR_BIT) +#elif FT_ULONG_MAX > 0xFFFFFFFFUL && FT_ULONG_MAX == 0xFFFFFFFFFFUL +#define FT_SIZEOF_LONG (32 / FT_CHAR_BIT) +#elif FT_ULONG_MAX > 0xFFFFFFFFUL && FT_ULONG_MAX == 0xFFFFFFFFFFFFFFFFUL +#define FT_SIZEOF_LONG (64 / FT_CHAR_BIT) +#else +#error "Unsupported size of `long' type!" +#endif + + + /* Preferred alignment of data */ +#define FT_ALIGNMENT 8 + + + /* FT_UNUSED is a macro used to indicate that a given parameter is not */ + /* used -- this is only used to get rid of unpleasant compiler warnings */ +#ifndef FT_UNUSED +#define FT_UNUSED( arg ) ( (arg) = (arg) ) +#endif + + + /*************************************************************************/ + /* */ + /* AUTOMATIC CONFIGURATION MACROS */ + /* */ + /* These macros are computed from the ones defined above. Don't touch */ + /* their definition, unless you know precisely what you are doing. No */ + /* porter should need to mess with them. */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* Mac support */ + /* */ + /* This is the only necessary change, so it is defined here instead */ + /* providing a new configuration file. */ + /* */ +#if ( defined( __APPLE__ ) && !defined( DARWIN_NO_CARBON ) ) || \ + ( defined( __MWERKS__ ) && defined( macintosh ) ) + /* no Carbon frameworks for 64bit 10.4.x */ +#include "AvailabilityMacros.h" +#if defined( __LP64__ ) && \ + ( MAC_OS_X_VERSION_MIN_REQUIRED <= MAC_OS_X_VERSION_10_4 ) +#define DARWIN_NO_CARBON 1 +#else +#define FT_MACINTOSH 1 +#endif + +#elif defined( __SC__ ) || defined( __MRC__ ) + /* Classic MacOS compilers */ +#include "ConditionalMacros.h" +#if TARGET_OS_MAC +#define FT_MACINTOSH 1 +#endif + +#endif + + + /*************************************************************************/ + /* */ + /*
    */ + /* basic_types */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* */ + /* FT_Int16 */ + /* */ + /* */ + /* A typedef for a 16bit signed integer type. */ + /* */ + typedef signed short FT_Int16; + + + /*************************************************************************/ + /* */ + /* */ + /* FT_UInt16 */ + /* */ + /* */ + /* A typedef for a 16bit unsigned integer type. */ + /* */ + typedef unsigned short FT_UInt16; + + /* */ + + + /* this #if 0 ... #endif clause is for documentation purposes */ +#if 0 + + /*************************************************************************/ + /* */ + /* */ + /* FT_Int32 */ + /* */ + /* */ + /* A typedef for a 32bit signed integer type. The size depends on */ + /* the configuration. */ + /* */ + typedef signed XXX FT_Int32; + + + /*************************************************************************/ + /* */ + /* */ + /* FT_UInt32 */ + /* */ + /* A typedef for a 32bit unsigned integer type. The size depends on */ + /* the configuration. */ + /* */ + typedef unsigned XXX FT_UInt32; + + /* */ + +#endif + +#if FT_SIZEOF_INT == (32 / FT_CHAR_BIT) + + typedef signed int FT_Int32; + typedef unsigned int FT_UInt32; + +#elif FT_SIZEOF_LONG == (32 / FT_CHAR_BIT) + + typedef signed long FT_Int32; + typedef unsigned long FT_UInt32; + +#else +#error "no 32bit type found -- please check your configuration files" +#endif + + + /* look up an integer type that is at least 32 bits */ +#if FT_SIZEOF_INT >= (32 / FT_CHAR_BIT) + + typedef int FT_Fast; + typedef unsigned int FT_UFast; + +#elif FT_SIZEOF_LONG >= (32 / FT_CHAR_BIT) + + typedef long FT_Fast; + typedef unsigned long FT_UFast; + +#endif + + + /* determine whether we have a 64-bit int type for platforms without */ + /* Autoconf */ +#if FT_SIZEOF_LONG == (64 / FT_CHAR_BIT) + + /* FT_LONG64 must be defined if a 64-bit type is available */ +#define FT_LONG64 +#define FT_INT64 long + +#elif defined( _MSC_VER ) && _MSC_VER >= 900 /* Visual C++ (and Intel C++) */ + + /* this compiler provides the __int64 type */ +#define FT_LONG64 +#define FT_INT64 __int64 + +#elif defined( __BORLANDC__ ) /* Borland C++ */ + + /* XXXX: We should probably check the value of __BORLANDC__ in order */ + /* to test the compiler version. */ + + /* this compiler provides the __int64 type */ +#define FT_LONG64 +#define FT_INT64 __int64 + +#elif defined( __WATCOMC__ ) /* Watcom C++ */ + + /* Watcom doesn't provide 64-bit data types */ + +#elif defined( __MWERKS__ ) /* Metrowerks CodeWarrior */ + +#define FT_LONG64 +#define FT_INT64 long long int + +#elif defined( __GNUC__ ) + + /* GCC provides the `long long' type */ +#define FT_LONG64 +#define FT_INT64 long long int + +#endif /* FT_SIZEOF_LONG == (64 / FT_CHAR_BIT) */ + + + /*************************************************************************/ + /* */ + /* A 64-bit data type will create compilation problems if you compile */ + /* in strict ANSI mode. To avoid them, we disable its use if __STDC__ */ + /* is defined. You can however ignore this rule by defining the */ + /* FT_CONFIG_OPTION_FORCE_INT64 configuration macro. */ + /* */ +#if defined( FT_LONG64 ) && !defined( FT_CONFIG_OPTION_FORCE_INT64 ) + +#ifdef __STDC__ + + /* undefine the 64-bit macros in strict ANSI compilation mode */ +#undef FT_LONG64 +#undef FT_INT64 + +#endif /* __STDC__ */ + +#endif /* FT_LONG64 && !FT_CONFIG_OPTION_FORCE_INT64 */ + + +#define FT_BEGIN_STMNT do { +#define FT_END_STMNT } while ( 0 ) +#define FT_DUMMY_STMNT FT_BEGIN_STMNT FT_END_STMNT + + +#ifndef FT_CONFIG_OPTION_NO_ASSEMBLER + /* Provide assembler fragments for performance-critical functions. */ + /* These must be defined `static __inline__' with GCC. */ + +#if defined( __CC_ARM ) || defined( __ARMCC__ ) /* RVCT */ +#define FT_MULFIX_ASSEMBLER FT_MulFix_arm + + /* documentation is in freetype.h */ + + static __inline FT_Int32 + FT_MulFix_arm( FT_Int32 a, + FT_Int32 b ) + { + register FT_Int32 t, t2; + + + __asm + { + smull t2, t, b, a /* (lo=t2,hi=t) = a*b */ + mov a, t, asr #31 /* a = (hi >> 31) */ + add a, a, #0x8000 /* a += 0x8000 */ + adds t2, t2, a /* t2 += a */ + adc t, t, #0 /* t += carry */ + mov a, t2, lsr #16 /* a = t2 >> 16 */ + orr a, a, t, lsl #16 /* a |= t << 16 */ + } + return a; + } + +#endif /* __CC_ARM || __ARMCC__ */ + + +#ifdef __GNUC__ + +#if defined( __arm__ ) && !defined( __thumb__ ) && \ + !( defined( __CC_ARM ) || defined( __ARMCC__ ) ) +#define FT_MULFIX_ASSEMBLER FT_MulFix_arm + + /* documentation is in freetype.h */ + + static __inline__ FT_Int32 + FT_MulFix_arm( FT_Int32 a, + FT_Int32 b ) + { + register FT_Int32 t, t2; + + + asm __volatile__ ( + "smull %1, %2, %4, %3\n\t" /* (lo=%1,hi=%2) = a*b */ + "mov %0, %2, asr #31\n\t" /* %0 = (hi >> 31) */ + "add %0, %0, #0x8000\n\t" /* %0 += 0x8000 */ + "adds %1, %1, %0\n\t" /* %1 += %0 */ + "adc %2, %2, #0\n\t" /* %2 += carry */ + "mov %0, %1, lsr #16\n\t" /* %0 = %1 >> 16 */ + "orr %0, %2, lsl #16\n\t" /* %0 |= %2 << 16 */ + : "=r"(a), "=&r"(t2), "=&r"(t) + : "r"(a), "r"(b) ); + return a; + } + +#endif /* __arm__ && !__thumb__ && !( __CC_ARM || __ARMCC__ ) */ + +#if defined( __i386__ ) +#define FT_MULFIX_ASSEMBLER FT_MulFix_i386 + + /* documentation is in freetype.h */ + + static __inline__ FT_Int32 + FT_MulFix_i386( FT_Int32 a, + FT_Int32 b ) + { + register FT_Int32 result; + + + __asm__ __volatile__ ( + "imul %%edx\n" + "movl %%edx, %%ecx\n" + "sarl $31, %%ecx\n" + "addl $0x8000, %%ecx\n" + "addl %%ecx, %%eax\n" + "adcl $0, %%edx\n" + "shrl $16, %%eax\n" + "shll $16, %%edx\n" + "addl %%edx, %%eax\n" + : "=a"(result), "=d"(b) + : "a"(a), "d"(b) + : "%ecx", "cc" ); + return result; + } + +#endif /* i386 */ + +#endif /* __GNUC__ */ + +#endif /* !FT_CONFIG_OPTION_NO_ASSEMBLER */ + + +#ifdef FT_CONFIG_OPTION_INLINE_MULFIX +#ifdef FT_MULFIX_ASSEMBLER +#define FT_MULFIX_INLINED FT_MULFIX_ASSEMBLER +#endif +#endif + + +#ifdef FT_MAKE_OPTION_SINGLE_OBJECT + +#define FT_LOCAL( x ) static x +#define FT_LOCAL_DEF( x ) static x + +#else + +#ifdef __cplusplus +#define FT_LOCAL( x ) extern "C" x +#define FT_LOCAL_DEF( x ) extern "C" x +#else +#define FT_LOCAL( x ) extern x +#define FT_LOCAL_DEF( x ) x +#endif + +#endif /* FT_MAKE_OPTION_SINGLE_OBJECT */ + + +#ifndef FT_BASE + +#ifdef __cplusplus +#define FT_BASE( x ) extern "C" x +#else +#define FT_BASE( x ) extern x +#endif + +#endif /* !FT_BASE */ + + +#ifndef FT_BASE_DEF + +#ifdef __cplusplus +#define FT_BASE_DEF( x ) x +#else +#define FT_BASE_DEF( x ) x +#endif + +#endif /* !FT_BASE_DEF */ + + +#ifndef FT_EXPORT + +#ifdef __cplusplus +#define FT_EXPORT( x ) extern "C" x +#else +#define FT_EXPORT( x ) extern x +#endif + +#endif /* !FT_EXPORT */ + + +#ifndef FT_EXPORT_DEF + +#ifdef __cplusplus +#define FT_EXPORT_DEF( x ) extern "C" x +#else +#define FT_EXPORT_DEF( x ) extern x +#endif + +#endif /* !FT_EXPORT_DEF */ + + +#ifndef FT_EXPORT_VAR + +#ifdef __cplusplus +#define FT_EXPORT_VAR( x ) extern "C" x +#else +#define FT_EXPORT_VAR( x ) extern x +#endif + +#endif /* !FT_EXPORT_VAR */ + + /* The following macros are needed to compile the library with a */ + /* C++ compiler and with 16bit compilers. */ + /* */ + + /* This is special. Within C++, you must specify `extern "C"' for */ + /* functions which are used via function pointers, and you also */ + /* must do that for structures which contain function pointers to */ + /* assure C linkage -- it's not possible to have (local) anonymous */ + /* functions which are accessed by (global) function pointers. */ + /* */ + /* */ + /* FT_CALLBACK_DEF is used to _define_ a callback function. */ + /* */ + /* FT_CALLBACK_TABLE is used to _declare_ a constant variable that */ + /* contains pointers to callback functions. */ + /* */ + /* FT_CALLBACK_TABLE_DEF is used to _define_ a constant variable */ + /* that contains pointers to callback functions. */ + /* */ + /* */ + /* Some 16bit compilers have to redefine these macros to insert */ + /* the infamous `_cdecl' or `__fastcall' declarations. */ + /* */ +#ifndef FT_CALLBACK_DEF +#ifdef __cplusplus +#define FT_CALLBACK_DEF( x ) extern "C" x +#else +#define FT_CALLBACK_DEF( x ) static x +#endif +#endif /* FT_CALLBACK_DEF */ + +#ifndef FT_CALLBACK_TABLE +#ifdef __cplusplus +#define FT_CALLBACK_TABLE extern "C" +#define FT_CALLBACK_TABLE_DEF extern "C" +#else +#define FT_CALLBACK_TABLE extern +#define FT_CALLBACK_TABLE_DEF /* nothing */ +#endif +#endif /* FT_CALLBACK_TABLE */ + + +FT_END_HEADER + + +#endif /* __FTCONFIG_H__ */ + + +/* END */ diff --git a/Lib/Include/freetype/config/ftheader.h b/Lib/Include/freetype/config/ftheader.h new file mode 100644 index 0000000..b63945d --- /dev/null +++ b/Lib/Include/freetype/config/ftheader.h @@ -0,0 +1,780 @@ +/***************************************************************************/ +/* */ +/* ftheader.h */ +/* */ +/* Build macros of the FreeType 2 library. */ +/* */ +/* Copyright 1996-2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + +#ifndef __FT_HEADER_H__ +#define __FT_HEADER_H__ + + + /*@***********************************************************************/ + /* */ + /* */ + /* FT_BEGIN_HEADER */ + /* */ + /* */ + /* This macro is used in association with @FT_END_HEADER in header */ + /* files to ensure that the declarations within are properly */ + /* encapsulated in an `extern "C" { .. }' block when included from a */ + /* C++ compiler. */ + /* */ +#ifdef __cplusplus +#define FT_BEGIN_HEADER extern "C" { +#else +#define FT_BEGIN_HEADER /* nothing */ +#endif + + + /*@***********************************************************************/ + /* */ + /* */ + /* FT_END_HEADER */ + /* */ + /* */ + /* This macro is used in association with @FT_BEGIN_HEADER in header */ + /* files to ensure that the declarations within are properly */ + /* encapsulated in an `extern "C" { .. }' block when included from a */ + /* C++ compiler. */ + /* */ +#ifdef __cplusplus +#define FT_END_HEADER } +#else +#define FT_END_HEADER /* nothing */ +#endif + + + /*************************************************************************/ + /* */ + /* Aliases for the FreeType 2 public and configuration files. */ + /* */ + /*************************************************************************/ + + /*************************************************************************/ + /* */ + /*
    */ + /* header_file_macros */ + /* */ + /* */ + /* Header File Macros */ + /* */ + /* <Abstract> */ + /* Macro definitions used to #include specific header files. */ + /* */ + /* <Description> */ + /* The following macros are defined to the name of specific */ + /* FreeType~2 header files. They can be used directly in #include */ + /* statements as in: */ + /* */ + /* { */ + /* #include FT_FREETYPE_H */ + /* #include FT_MULTIPLE_MASTERS_H */ + /* #include FT_GLYPH_H */ + /* } */ + /* */ + /* There are several reasons why we are now using macros to name */ + /* public header files. The first one is that such macros are not */ + /* limited to the infamous 8.3~naming rule required by DOS (and */ + /* `FT_MULTIPLE_MASTERS_H' is a lot more meaningful than `ftmm.h'). */ + /* */ + /* The second reason is that it allows for more flexibility in the */ + /* way FreeType~2 is installed on a given system. */ + /* */ + /*************************************************************************/ + + + /* configuration files */ + + /************************************************************************* + * + * @macro: + * FT_CONFIG_CONFIG_H + * + * @description: + * A macro used in #include statements to name the file containing + * FreeType~2 configuration data. + * + */ +#ifndef FT_CONFIG_CONFIG_H +#define FT_CONFIG_CONFIG_H <freetype/config/ftconfig.h> +#endif + + + /************************************************************************* + * + * @macro: + * FT_CONFIG_STANDARD_LIBRARY_H + * + * @description: + * A macro used in #include statements to name the file containing + * FreeType~2 interface to the standard C library functions. + * + */ +#ifndef FT_CONFIG_STANDARD_LIBRARY_H +#define FT_CONFIG_STANDARD_LIBRARY_H <freetype/config/ftstdlib.h> +#endif + + + /************************************************************************* + * + * @macro: + * FT_CONFIG_OPTIONS_H + * + * @description: + * A macro used in #include statements to name the file containing + * FreeType~2 project-specific configuration options. + * + */ +#ifndef FT_CONFIG_OPTIONS_H +#define FT_CONFIG_OPTIONS_H <freetype/config/ftoption.h> +#endif + + + /************************************************************************* + * + * @macro: + * FT_CONFIG_MODULES_H + * + * @description: + * A macro used in #include statements to name the file containing the + * list of FreeType~2 modules that are statically linked to new library + * instances in @FT_Init_FreeType. + * + */ +#ifndef FT_CONFIG_MODULES_H +#define FT_CONFIG_MODULES_H <freetype/config/ftmodule.h> +#endif + + /* */ + + /* public headers */ + + /************************************************************************* + * + * @macro: + * FT_FREETYPE_H + * + * @description: + * A macro used in #include statements to name the file containing the + * base FreeType~2 API. + * + */ +#define FT_FREETYPE_H <freetype/freetype.h> + + + /************************************************************************* + * + * @macro: + * FT_ERRORS_H + * + * @description: + * A macro used in #include statements to name the file containing the + * list of FreeType~2 error codes (and messages). + * + * It is included by @FT_FREETYPE_H. + * + */ +#define FT_ERRORS_H <freetype/fterrors.h> + + + /************************************************************************* + * + * @macro: + * FT_MODULE_ERRORS_H + * + * @description: + * A macro used in #include statements to name the file containing the + * list of FreeType~2 module error offsets (and messages). + * + */ +#define FT_MODULE_ERRORS_H <freetype/ftmoderr.h> + + + /************************************************************************* + * + * @macro: + * FT_SYSTEM_H + * + * @description: + * A macro used in #include statements to name the file containing the + * FreeType~2 interface to low-level operations (i.e., memory management + * and stream i/o). + * + * It is included by @FT_FREETYPE_H. + * + */ +#define FT_SYSTEM_H <freetype/ftsystem.h> + + + /************************************************************************* + * + * @macro: + * FT_IMAGE_H + * + * @description: + * A macro used in #include statements to name the file containing type + * definitions related to glyph images (i.e., bitmaps, outlines, + * scan-converter parameters). + * + * It is included by @FT_FREETYPE_H. + * + */ +#define FT_IMAGE_H <freetype/ftimage.h> + + + /************************************************************************* + * + * @macro: + * FT_TYPES_H + * + * @description: + * A macro used in #include statements to name the file containing the + * basic data types defined by FreeType~2. + * + * It is included by @FT_FREETYPE_H. + * + */ +#define FT_TYPES_H <freetype/fttypes.h> + + + /************************************************************************* + * + * @macro: + * FT_LIST_H + * + * @description: + * A macro used in #include statements to name the file containing the + * list management API of FreeType~2. + * + * (Most applications will never need to include this file.) + * + */ +#define FT_LIST_H <freetype/ftlist.h> + + + /************************************************************************* + * + * @macro: + * FT_OUTLINE_H + * + * @description: + * A macro used in #include statements to name the file containing the + * scalable outline management API of FreeType~2. + * + */ +#define FT_OUTLINE_H <freetype/ftoutln.h> + + + /************************************************************************* + * + * @macro: + * FT_SIZES_H + * + * @description: + * A macro used in #include statements to name the file containing the + * API which manages multiple @FT_Size objects per face. + * + */ +#define FT_SIZES_H <freetype/ftsizes.h> + + + /************************************************************************* + * + * @macro: + * FT_MODULE_H + * + * @description: + * A macro used in #include statements to name the file containing the + * module management API of FreeType~2. + * + */ +#define FT_MODULE_H <freetype/ftmodapi.h> + + + /************************************************************************* + * + * @macro: + * FT_RENDER_H + * + * @description: + * A macro used in #include statements to name the file containing the + * renderer module management API of FreeType~2. + * + */ +#define FT_RENDER_H <freetype/ftrender.h> + + + /************************************************************************* + * + * @macro: + * FT_TYPE1_TABLES_H + * + * @description: + * A macro used in #include statements to name the file containing the + * types and API specific to the Type~1 format. + * + */ +#define FT_TYPE1_TABLES_H <freetype/t1tables.h> + + + /************************************************************************* + * + * @macro: + * FT_TRUETYPE_IDS_H + * + * @description: + * A macro used in #include statements to name the file containing the + * enumeration values which identify name strings, languages, encodings, + * etc. This file really contains a _large_ set of constant macro + * definitions, taken from the TrueType and OpenType specifications. + * + */ +#define FT_TRUETYPE_IDS_H <freetype/ttnameid.h> + + + /************************************************************************* + * + * @macro: + * FT_TRUETYPE_TABLES_H + * + * @description: + * A macro used in #include statements to name the file containing the + * types and API specific to the TrueType (as well as OpenType) format. + * + */ +#define FT_TRUETYPE_TABLES_H <freetype/tttables.h> + + + /************************************************************************* + * + * @macro: + * FT_TRUETYPE_TAGS_H + * + * @description: + * A macro used in #include statements to name the file containing the + * definitions of TrueType four-byte `tags' which identify blocks in + * SFNT-based font formats (i.e., TrueType and OpenType). + * + */ +#define FT_TRUETYPE_TAGS_H <freetype/tttags.h> + + + /************************************************************************* + * + * @macro: + * FT_BDF_H + * + * @description: + * A macro used in #include statements to name the file containing the + * definitions of an API which accesses BDF-specific strings from a + * face. + * + */ +#define FT_BDF_H <freetype/ftbdf.h> + + + /************************************************************************* + * + * @macro: + * FT_CID_H + * + * @description: + * A macro used in #include statements to name the file containing the + * definitions of an API which access CID font information from a + * face. + * + */ +#define FT_CID_H <freetype/ftcid.h> + + + /************************************************************************* + * + * @macro: + * FT_GZIP_H + * + * @description: + * A macro used in #include statements to name the file containing the + * definitions of an API which supports gzip-compressed files. + * + */ +#define FT_GZIP_H <freetype/ftgzip.h> + + + /************************************************************************* + * + * @macro: + * FT_LZW_H + * + * @description: + * A macro used in #include statements to name the file containing the + * definitions of an API which supports LZW-compressed files. + * + */ +#define FT_LZW_H <freetype/ftlzw.h> + + + /************************************************************************* + * + * @macro: + * FT_WINFONTS_H + * + * @description: + * A macro used in #include statements to name the file containing the + * definitions of an API which supports Windows FNT files. + * + */ +#define FT_WINFONTS_H <freetype/ftwinfnt.h> + + + /************************************************************************* + * + * @macro: + * FT_GLYPH_H + * + * @description: + * A macro used in #include statements to name the file containing the + * API of the optional glyph management component. + * + */ +#define FT_GLYPH_H <freetype/ftglyph.h> + + + /************************************************************************* + * + * @macro: + * FT_BITMAP_H + * + * @description: + * A macro used in #include statements to name the file containing the + * API of the optional bitmap conversion component. + * + */ +#define FT_BITMAP_H <freetype/ftbitmap.h> + + + /************************************************************************* + * + * @macro: + * FT_BBOX_H + * + * @description: + * A macro used in #include statements to name the file containing the + * API of the optional exact bounding box computation routines. + * + */ +#define FT_BBOX_H <freetype/ftbbox.h> + + + /************************************************************************* + * + * @macro: + * FT_CACHE_H + * + * @description: + * A macro used in #include statements to name the file containing the + * API of the optional FreeType~2 cache sub-system. + * + */ +#define FT_CACHE_H <freetype/ftcache.h> + + + /************************************************************************* + * + * @macro: + * FT_CACHE_IMAGE_H + * + * @description: + * A macro used in #include statements to name the file containing the + * `glyph image' API of the FreeType~2 cache sub-system. + * + * It is used to define a cache for @FT_Glyph elements. You can also + * use the API defined in @FT_CACHE_SMALL_BITMAPS_H if you only need to + * store small glyph bitmaps, as it will use less memory. + * + * This macro is deprecated. Simply include @FT_CACHE_H to have all + * glyph image-related cache declarations. + * + */ +#define FT_CACHE_IMAGE_H FT_CACHE_H + + + /************************************************************************* + * + * @macro: + * FT_CACHE_SMALL_BITMAPS_H + * + * @description: + * A macro used in #include statements to name the file containing the + * `small bitmaps' API of the FreeType~2 cache sub-system. + * + * It is used to define a cache for small glyph bitmaps in a relatively + * memory-efficient way. You can also use the API defined in + * @FT_CACHE_IMAGE_H if you want to cache arbitrary glyph images, + * including scalable outlines. + * + * This macro is deprecated. Simply include @FT_CACHE_H to have all + * small bitmaps-related cache declarations. + * + */ +#define FT_CACHE_SMALL_BITMAPS_H FT_CACHE_H + + + /************************************************************************* + * + * @macro: + * FT_CACHE_CHARMAP_H + * + * @description: + * A macro used in #include statements to name the file containing the + * `charmap' API of the FreeType~2 cache sub-system. + * + * This macro is deprecated. Simply include @FT_CACHE_H to have all + * charmap-based cache declarations. + * + */ +#define FT_CACHE_CHARMAP_H FT_CACHE_H + + + /************************************************************************* + * + * @macro: + * FT_MAC_H + * + * @description: + * A macro used in #include statements to name the file containing the + * Macintosh-specific FreeType~2 API. The latter is used to access + * fonts embedded in resource forks. + * + * This header file must be explicitly included by client applications + * compiled on the Mac (note that the base API still works though). + * + */ +#define FT_MAC_H <freetype/ftmac.h> + + + /************************************************************************* + * + * @macro: + * FT_MULTIPLE_MASTERS_H + * + * @description: + * A macro used in #include statements to name the file containing the + * optional multiple-masters management API of FreeType~2. + * + */ +#define FT_MULTIPLE_MASTERS_H <freetype/ftmm.h> + + + /************************************************************************* + * + * @macro: + * FT_SFNT_NAMES_H + * + * @description: + * A macro used in #include statements to name the file containing the + * optional FreeType~2 API which accesses embedded `name' strings in + * SFNT-based font formats (i.e., TrueType and OpenType). + * + */ +#define FT_SFNT_NAMES_H <freetype/ftsnames.h> + + + /************************************************************************* + * + * @macro: + * FT_OPENTYPE_VALIDATE_H + * + * @description: + * A macro used in #include statements to name the file containing the + * optional FreeType~2 API which validates OpenType tables (BASE, GDEF, + * GPOS, GSUB, JSTF). + * + */ +#define FT_OPENTYPE_VALIDATE_H <freetype/ftotval.h> + + + /************************************************************************* + * + * @macro: + * FT_GX_VALIDATE_H + * + * @description: + * A macro used in #include statements to name the file containing the + * optional FreeType~2 API which validates TrueTypeGX/AAT tables (feat, + * mort, morx, bsln, just, kern, opbd, trak, prop). + * + */ +#define FT_GX_VALIDATE_H <freetype/ftgxval.h> + + + /************************************************************************* + * + * @macro: + * FT_PFR_H + * + * @description: + * A macro used in #include statements to name the file containing the + * FreeType~2 API which accesses PFR-specific data. + * + */ +#define FT_PFR_H <freetype/ftpfr.h> + + + /************************************************************************* + * + * @macro: + * FT_STROKER_H + * + * @description: + * A macro used in #include statements to name the file containing the + * FreeType~2 API which provides functions to stroke outline paths. + */ +#define FT_STROKER_H <freetype/ftstroke.h> + + + /************************************************************************* + * + * @macro: + * FT_SYNTHESIS_H + * + * @description: + * A macro used in #include statements to name the file containing the + * FreeType~2 API which performs artificial obliquing and emboldening. + */ +#define FT_SYNTHESIS_H <freetype/ftsynth.h> + + + /************************************************************************* + * + * @macro: + * FT_XFREE86_H + * + * @description: + * A macro used in #include statements to name the file containing the + * FreeType~2 API which provides functions specific to the XFree86 and + * X.Org X11 servers. + */ +#define FT_XFREE86_H <freetype/ftxf86.h> + + + /************************************************************************* + * + * @macro: + * FT_TRIGONOMETRY_H + * + * @description: + * A macro used in #include statements to name the file containing the + * FreeType~2 API which performs trigonometric computations (e.g., + * cosines and arc tangents). + */ +#define FT_TRIGONOMETRY_H <freetype/fttrigon.h> + + + /************************************************************************* + * + * @macro: + * FT_LCD_FILTER_H + * + * @description: + * A macro used in #include statements to name the file containing the + * FreeType~2 API which performs color filtering for subpixel rendering. + */ +#define FT_LCD_FILTER_H <freetype/ftlcdfil.h> + + + /************************************************************************* + * + * @macro: + * FT_UNPATENTED_HINTING_H + * + * @description: + * A macro used in #include statements to name the file containing the + * FreeType~2 API which performs color filtering for subpixel rendering. + */ +#define FT_UNPATENTED_HINTING_H <freetype/ttunpat.h> + + + /************************************************************************* + * + * @macro: + * FT_INCREMENTAL_H + * + * @description: + * A macro used in #include statements to name the file containing the + * FreeType~2 API which performs color filtering for subpixel rendering. + */ +#define FT_INCREMENTAL_H <freetype/ftincrem.h> + + + /************************************************************************* + * + * @macro: + * FT_GASP_H + * + * @description: + * A macro used in #include statements to name the file containing the + * FreeType~2 API which returns entries from the TrueType GASP table. + */ +#define FT_GASP_H <freetype/ftgasp.h> + + + /************************************************************************* + * + * @macro: + * FT_ADVANCES_H + * + * @description: + * A macro used in #include statements to name the file containing the + * FreeType~2 API which returns individual and ranged glyph advances. + */ +#define FT_ADVANCES_H <freetype/ftadvanc.h> + + + /* */ + +#define FT_ERROR_DEFINITIONS_H <freetype/fterrdef.h> + + + /* The internals of the cache sub-system are no longer exposed. We */ + /* default to FT_CACHE_H at the moment just in case, but we know of */ + /* no rogue client that uses them. */ + /* */ +#define FT_CACHE_MANAGER_H <freetype/ftcache.h> +#define FT_CACHE_INTERNAL_MRU_H <freetype/ftcache.h> +#define FT_CACHE_INTERNAL_MANAGER_H <freetype/ftcache.h> +#define FT_CACHE_INTERNAL_CACHE_H <freetype/ftcache.h> +#define FT_CACHE_INTERNAL_GLYPH_H <freetype/ftcache.h> +#define FT_CACHE_INTERNAL_IMAGE_H <freetype/ftcache.h> +#define FT_CACHE_INTERNAL_SBITS_H <freetype/ftcache.h> + + +#define FT_INCREMENTAL_H <freetype/ftincrem.h> + +#define FT_TRUETYPE_UNPATENTED_H <freetype/ttunpat.h> + + + /* + * Include internal headers definitions from <freetype/internal/...> + * only when building the library. + */ +#ifdef FT2_BUILD_LIBRARY +#define FT_INTERNAL_INTERNAL_H <freetype/internal/internal.h> +#include FT_INTERNAL_INTERNAL_H +#endif /* FT2_BUILD_LIBRARY */ + + +#endif /* __FT2_BUILD_H__ */ + + +/* END */ diff --git a/Lib/Include/freetype/config/ftmodule.h b/Lib/Include/freetype/config/ftmodule.h new file mode 100644 index 0000000..76d271a --- /dev/null +++ b/Lib/Include/freetype/config/ftmodule.h @@ -0,0 +1,32 @@ +/* + * This file registers the FreeType modules compiled into the library. + * + * If you use GNU make, this file IS NOT USED! Instead, it is created in + * the objects directory (normally `<topdir>/objs/') based on information + * from `<topdir>/modules.cfg'. + * + * Please read `docs/INSTALL.ANY' and `docs/CUSTOMIZE' how to compile + * FreeType without GNU make. + * + */ + +FT_USE_MODULE( FT_Module_Class, autofit_module_class ) +FT_USE_MODULE( FT_Driver_ClassRec, tt_driver_class ) +FT_USE_MODULE( FT_Driver_ClassRec, t1_driver_class ) +FT_USE_MODULE( FT_Driver_ClassRec, cff_driver_class ) +FT_USE_MODULE( FT_Driver_ClassRec, t1cid_driver_class ) +FT_USE_MODULE( FT_Driver_ClassRec, pfr_driver_class ) +FT_USE_MODULE( FT_Driver_ClassRec, t42_driver_class ) +FT_USE_MODULE( FT_Driver_ClassRec, winfnt_driver_class ) +FT_USE_MODULE( FT_Driver_ClassRec, pcf_driver_class ) +FT_USE_MODULE( FT_Module_Class, psaux_module_class ) +FT_USE_MODULE( FT_Module_Class, psnames_module_class ) +FT_USE_MODULE( FT_Module_Class, pshinter_module_class ) +FT_USE_MODULE( FT_Renderer_Class, ft_raster1_renderer_class ) +FT_USE_MODULE( FT_Module_Class, sfnt_module_class ) +FT_USE_MODULE( FT_Renderer_Class, ft_smooth_renderer_class ) +FT_USE_MODULE( FT_Renderer_Class, ft_smooth_lcd_renderer_class ) +FT_USE_MODULE( FT_Renderer_Class, ft_smooth_lcdv_renderer_class ) +FT_USE_MODULE( FT_Driver_ClassRec, bdf_driver_class ) + +/* EOF */ diff --git a/Lib/Include/freetype/config/ftoption.h b/Lib/Include/freetype/config/ftoption.h new file mode 100644 index 0000000..2b46259 --- /dev/null +++ b/Lib/Include/freetype/config/ftoption.h @@ -0,0 +1,733 @@ +/***************************************************************************/ +/* */ +/* ftoption.h */ +/* */ +/* User-selectable configuration macros (specification only). */ +/* */ +/* Copyright 1996-2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, */ +/* 2010 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef __FTOPTION_H__ +#define __FTOPTION_H__ + + +#include <ft2build.h> + + +FT_BEGIN_HEADER + + /*************************************************************************/ + /* */ + /* USER-SELECTABLE CONFIGURATION MACROS */ + /* */ + /* This file contains the default configuration macro definitions for */ + /* a standard build of the FreeType library. There are three ways to */ + /* use this file to build project-specific versions of the library: */ + /* */ + /* - You can modify this file by hand, but this is not recommended in */ + /* cases where you would like to build several versions of the */ + /* library from a single source directory. */ + /* */ + /* - You can put a copy of this file in your build directory, more */ + /* precisely in `$BUILD/freetype/config/ftoption.h', where `$BUILD' */ + /* is the name of a directory that is included _before_ the FreeType */ + /* include path during compilation. */ + /* */ + /* The default FreeType Makefiles and Jamfiles use the build */ + /* directory `builds/<system>' by default, but you can easily change */ + /* that for your own projects. */ + /* */ + /* - Copy the file <ft2build.h> to `$BUILD/ft2build.h' and modify it */ + /* slightly to pre-define the macro FT_CONFIG_OPTIONS_H used to */ + /* locate this file during the build. For example, */ + /* */ + /* #define FT_CONFIG_OPTIONS_H <myftoptions.h> */ + /* #include <freetype/config/ftheader.h> */ + /* */ + /* will use `$BUILD/myftoptions.h' instead of this file for macro */ + /* definitions. */ + /* */ + /* Note also that you can similarly pre-define the macro */ + /* FT_CONFIG_MODULES_H used to locate the file listing of the modules */ + /* that are statically linked to the library at compile time. By */ + /* default, this file is <freetype/config/ftmodule.h>. */ + /* */ + /* We highly recommend using the third method whenever possible. */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** G E N E R A L F R E E T Y P E 2 C O N F I G U R A T I O N ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* Uncomment the line below if you want to activate sub-pixel rendering */ + /* (a.k.a. LCD rendering, or ClearType) in this build of the library. */ + /* */ + /* Note that this feature is covered by several Microsoft patents */ + /* and should not be activated in any default build of the library. */ + /* */ + /* This macro has no impact on the FreeType API, only on its */ + /* _implementation_. For example, using FT_RENDER_MODE_LCD when calling */ + /* FT_Render_Glyph still generates a bitmap that is 3 times wider than */ + /* the original size in case this macro isn't defined; however, each */ + /* triplet of subpixels has R=G=B. */ + /* */ + /* This is done to allow FreeType clients to run unmodified, forcing */ + /* them to display normal gray-level anti-aliased glyphs. */ + /* */ +/* #define FT_CONFIG_OPTION_SUBPIXEL_RENDERING */ + + + /*************************************************************************/ + /* */ + /* Many compilers provide a non-ANSI 64-bit data type that can be used */ + /* by FreeType to speed up some computations. However, this will create */ + /* some problems when compiling the library in strict ANSI mode. */ + /* */ + /* For this reason, the use of 64-bit integers is normally disabled when */ + /* the __STDC__ macro is defined. You can however disable this by */ + /* defining the macro FT_CONFIG_OPTION_FORCE_INT64 here. */ + /* */ + /* For most compilers, this will only create compilation warnings when */ + /* building the library. */ + /* */ + /* ObNote: The compiler-specific 64-bit integers are detected in the */ + /* file `ftconfig.h' either statically or through the */ + /* `configure' script on supported platforms. */ + /* */ +#undef FT_CONFIG_OPTION_FORCE_INT64 + + + /*************************************************************************/ + /* */ + /* If this macro is defined, do not try to use an assembler version of */ + /* performance-critical functions (e.g. FT_MulFix). You should only do */ + /* that to verify that the assembler function works properly, or to */ + /* execute benchmark tests of the various implementations. */ +/* #define FT_CONFIG_OPTION_NO_ASSEMBLER */ + + + /*************************************************************************/ + /* */ + /* If this macro is defined, try to use an inlined assembler version of */ + /* the `FT_MulFix' function, which is a `hotspot' when loading and */ + /* hinting glyphs, and which should be executed as fast as possible. */ + /* */ + /* Note that if your compiler or CPU is not supported, this will default */ + /* to the standard and portable implementation found in `ftcalc.c'. */ + /* */ +#define FT_CONFIG_OPTION_INLINE_MULFIX + + + /*************************************************************************/ + /* */ + /* LZW-compressed file support. */ + /* */ + /* FreeType now handles font files that have been compressed with the */ + /* `compress' program. This is mostly used to parse many of the PCF */ + /* files that come with various X11 distributions. The implementation */ + /* uses NetBSD's `zopen' to partially uncompress the file on the fly */ + /* (see src/lzw/ftgzip.c). */ + /* */ + /* Define this macro if you want to enable this `feature'. */ + /* */ +#define FT_CONFIG_OPTION_USE_LZW + + + /*************************************************************************/ + /* */ + /* Gzip-compressed file support. */ + /* */ + /* FreeType now handles font files that have been compressed with the */ + /* `gzip' program. This is mostly used to parse many of the PCF files */ + /* that come with XFree86. The implementation uses `zlib' to */ + /* partially uncompress the file on the fly (see src/gzip/ftgzip.c). */ + /* */ + /* Define this macro if you want to enable this `feature'. See also */ + /* the macro FT_CONFIG_OPTION_SYSTEM_ZLIB below. */ + /* */ +#define FT_CONFIG_OPTION_USE_ZLIB + + + /*************************************************************************/ + /* */ + /* ZLib library selection */ + /* */ + /* This macro is only used when FT_CONFIG_OPTION_USE_ZLIB is defined. */ + /* It allows FreeType's `ftgzip' component to link to the system's */ + /* installation of the ZLib library. This is useful on systems like */ + /* Unix or VMS where it generally is already available. */ + /* */ + /* If you let it undefined, the component will use its own copy */ + /* of the zlib sources instead. These have been modified to be */ + /* included directly within the component and *not* export external */ + /* function names. This allows you to link any program with FreeType */ + /* _and_ ZLib without linking conflicts. */ + /* */ + /* Do not #undef this macro here since the build system might define */ + /* it for certain configurations only. */ + /* */ +/* #define FT_CONFIG_OPTION_SYSTEM_ZLIB */ + + + /*************************************************************************/ + /* */ + /* DLL export compilation */ + /* */ + /* When compiling FreeType as a DLL, some systems/compilers need a */ + /* special keyword in front OR after the return type of function */ + /* declarations. */ + /* */ + /* Two macros are used within the FreeType source code to define */ + /* exported library functions: FT_EXPORT and FT_EXPORT_DEF. */ + /* */ + /* FT_EXPORT( return_type ) */ + /* */ + /* is used in a function declaration, as in */ + /* */ + /* FT_EXPORT( FT_Error ) */ + /* FT_Init_FreeType( FT_Library* alibrary ); */ + /* */ + /* */ + /* FT_EXPORT_DEF( return_type ) */ + /* */ + /* is used in a function definition, as in */ + /* */ + /* FT_EXPORT_DEF( FT_Error ) */ + /* FT_Init_FreeType( FT_Library* alibrary ) */ + /* { */ + /* ... some code ... */ + /* return FT_Err_Ok; */ + /* } */ + /* */ + /* You can provide your own implementation of FT_EXPORT and */ + /* FT_EXPORT_DEF here if you want. If you leave them undefined, they */ + /* will be later automatically defined as `extern return_type' to */ + /* allow normal compilation. */ + /* */ + /* Do not #undef these macros here since the build system might define */ + /* them for certain configurations only. */ + /* */ +/* #define FT_EXPORT(x) extern x */ +/* #define FT_EXPORT_DEF(x) x */ + + + /*************************************************************************/ + /* */ + /* Glyph Postscript Names handling */ + /* */ + /* By default, FreeType 2 is compiled with the `psnames' module. This */ + /* module is in charge of converting a glyph name string into a */ + /* Unicode value, or return a Macintosh standard glyph name for the */ + /* use with the TrueType `post' table. */ + /* */ + /* Undefine this macro if you do not want `psnames' compiled in your */ + /* build of FreeType. This has the following effects: */ + /* */ + /* - The TrueType driver will provide its own set of glyph names, */ + /* if you build it to support postscript names in the TrueType */ + /* `post' table. */ + /* */ + /* - The Type 1 driver will not be able to synthesize a Unicode */ + /* charmap out of the glyphs found in the fonts. */ + /* */ + /* You would normally undefine this configuration macro when building */ + /* a version of FreeType that doesn't contain a Type 1 or CFF driver. */ + /* */ +#define FT_CONFIG_OPTION_POSTSCRIPT_NAMES + + + /*************************************************************************/ + /* */ + /* Postscript Names to Unicode Values support */ + /* */ + /* By default, FreeType 2 is built with the `PSNames' module compiled */ + /* in. Among other things, the module is used to convert a glyph name */ + /* into a Unicode value. This is especially useful in order to */ + /* synthesize on the fly a Unicode charmap from the CFF/Type 1 driver */ + /* through a big table named the `Adobe Glyph List' (AGL). */ + /* */ + /* Undefine this macro if you do not want the Adobe Glyph List */ + /* compiled in your `PSNames' module. The Type 1 driver will not be */ + /* able to synthesize a Unicode charmap out of the glyphs found in the */ + /* fonts. */ + /* */ +#define FT_CONFIG_OPTION_ADOBE_GLYPH_LIST + + + /*************************************************************************/ + /* */ + /* Support for Mac fonts */ + /* */ + /* Define this macro if you want support for outline fonts in Mac */ + /* format (mac dfont, mac resource, macbinary containing a mac */ + /* resource) on non-Mac platforms. */ + /* */ + /* Note that the `FOND' resource isn't checked. */ + /* */ +#define FT_CONFIG_OPTION_MAC_FONTS + + + /*************************************************************************/ + /* */ + /* Guessing methods to access embedded resource forks */ + /* */ + /* Enable extra Mac fonts support on non-Mac platforms (e.g. */ + /* GNU/Linux). */ + /* */ + /* Resource forks which include fonts data are stored sometimes in */ + /* locations which users or developers don't expected. In some cases, */ + /* resource forks start with some offset from the head of a file. In */ + /* other cases, the actual resource fork is stored in file different */ + /* from what the user specifies. If this option is activated, */ + /* FreeType tries to guess whether such offsets or different file */ + /* names must be used. */ + /* */ + /* Note that normal, direct access of resource forks is controlled via */ + /* the FT_CONFIG_OPTION_MAC_FONTS option. */ + /* */ +#ifdef FT_CONFIG_OPTION_MAC_FONTS +#define FT_CONFIG_OPTION_GUESSING_EMBEDDED_RFORK +#endif + + + /*************************************************************************/ + /* */ + /* Allow the use of FT_Incremental_Interface to load typefaces that */ + /* contain no glyph data, but supply it via a callback function. */ + /* This is required by clients supporting document formats which */ + /* supply font data incrementally as the document is parsed, such */ + /* as the Ghostscript interpreter for the PostScript language. */ + /* */ +#define FT_CONFIG_OPTION_INCREMENTAL + + + /*************************************************************************/ + /* */ + /* The size in bytes of the render pool used by the scan-line converter */ + /* to do all of its work. */ + /* */ + /* This must be greater than 4KByte if you use FreeType to rasterize */ + /* glyphs; otherwise, you may set it to zero to avoid unnecessary */ + /* allocation of the render pool. */ + /* */ +#define FT_RENDER_POOL_SIZE 16384L + + + /*************************************************************************/ + /* */ + /* FT_MAX_MODULES */ + /* */ + /* The maximum number of modules that can be registered in a single */ + /* FreeType library object. 32 is the default. */ + /* */ +#define FT_MAX_MODULES 32 + + + /*************************************************************************/ + /* */ + /* Debug level */ + /* */ + /* FreeType can be compiled in debug or trace mode. In debug mode, */ + /* errors are reported through the `ftdebug' component. In trace */ + /* mode, additional messages are sent to the standard output during */ + /* execution. */ + /* */ + /* Define FT_DEBUG_LEVEL_ERROR to build the library in debug mode. */ + /* Define FT_DEBUG_LEVEL_TRACE to build it in trace mode. */ + /* */ + /* Don't define any of these macros to compile in `release' mode! */ + /* */ + /* Do not #undef these macros here since the build system might define */ + /* them for certain configurations only. */ + /* */ +/* #define FT_DEBUG_LEVEL_ERROR */ +/* #define FT_DEBUG_LEVEL_TRACE */ + + + /*************************************************************************/ + /* */ + /* Memory Debugging */ + /* */ + /* FreeType now comes with an integrated memory debugger that is */ + /* capable of detecting simple errors like memory leaks or double */ + /* deletes. To compile it within your build of the library, you */ + /* should define FT_DEBUG_MEMORY here. */ + /* */ + /* Note that the memory debugger is only activated at runtime when */ + /* when the _environment_ variable `FT2_DEBUG_MEMORY' is defined also! */ + /* */ + /* Do not #undef this macro here since the build system might define */ + /* it for certain configurations only. */ + /* */ +/* #define FT_DEBUG_MEMORY */ + + + /*************************************************************************/ + /* */ + /* Module errors */ + /* */ + /* If this macro is set (which is _not_ the default), the higher byte */ + /* of an error code gives the module in which the error has occurred, */ + /* while the lower byte is the real error code. */ + /* */ + /* Setting this macro makes sense for debugging purposes only, since */ + /* it would break source compatibility of certain programs that use */ + /* FreeType 2. */ + /* */ + /* More details can be found in the files ftmoderr.h and fterrors.h. */ + /* */ +#undef FT_CONFIG_OPTION_USE_MODULE_ERRORS + + + /*************************************************************************/ + /* */ + /* Position Independent Code */ + /* */ + /* If this macro is set (which is _not_ the default), FreeType2 will */ + /* avoid creating constants that require address fixups. Instead the */ + /* constants will be moved into a struct and additional intialization */ + /* code will be used. */ + /* */ + /* Setting this macro is needed for systems that prohibit address */ + /* fixups, such as BREW. */ + /* */ +/* #define FT_CONFIG_OPTION_PIC */ + + + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** S F N T D R I V E R C O N F I G U R A T I O N ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* Define TT_CONFIG_OPTION_EMBEDDED_BITMAPS if you want to support */ + /* embedded bitmaps in all formats using the SFNT module (namely */ + /* TrueType & OpenType). */ + /* */ +#define TT_CONFIG_OPTION_EMBEDDED_BITMAPS + + + /*************************************************************************/ + /* */ + /* Define TT_CONFIG_OPTION_POSTSCRIPT_NAMES if you want to be able to */ + /* load and enumerate the glyph Postscript names in a TrueType or */ + /* OpenType file. */ + /* */ + /* Note that when you do not compile the `PSNames' module by undefining */ + /* the above FT_CONFIG_OPTION_POSTSCRIPT_NAMES, the `sfnt' module will */ + /* contain additional code used to read the PS Names table from a font. */ + /* */ + /* (By default, the module uses `PSNames' to extract glyph names.) */ + /* */ +#define TT_CONFIG_OPTION_POSTSCRIPT_NAMES + + + /*************************************************************************/ + /* */ + /* Define TT_CONFIG_OPTION_SFNT_NAMES if your applications need to */ + /* access the internal name table in a SFNT-based format like TrueType */ + /* or OpenType. The name table contains various strings used to */ + /* describe the font, like family name, copyright, version, etc. It */ + /* does not contain any glyph name though. */ + /* */ + /* Accessing SFNT names is done through the functions declared in */ + /* `freetype/ftsnames.h'. */ + /* */ +#define TT_CONFIG_OPTION_SFNT_NAMES + + + /*************************************************************************/ + /* */ + /* TrueType CMap support */ + /* */ + /* Here you can fine-tune which TrueType CMap table format shall be */ + /* supported. */ +#define TT_CONFIG_CMAP_FORMAT_0 +#define TT_CONFIG_CMAP_FORMAT_2 +#define TT_CONFIG_CMAP_FORMAT_4 +#define TT_CONFIG_CMAP_FORMAT_6 +#define TT_CONFIG_CMAP_FORMAT_8 +#define TT_CONFIG_CMAP_FORMAT_10 +#define TT_CONFIG_CMAP_FORMAT_12 +#define TT_CONFIG_CMAP_FORMAT_13 +#define TT_CONFIG_CMAP_FORMAT_14 + + + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** T R U E T Y P E D R I V E R C O N F I G U R A T I O N ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + + /*************************************************************************/ + /* */ + /* Define TT_CONFIG_OPTION_BYTECODE_INTERPRETER if you want to compile */ + /* a bytecode interpreter in the TrueType driver. */ + /* */ + /* By undefining this, you will only compile the code necessary to load */ + /* TrueType glyphs without hinting. */ + /* */ + /* Do not #undef this macro here, since the build system might */ + /* define it for certain configurations only. */ + /* */ +#define TT_CONFIG_OPTION_BYTECODE_INTERPRETER + + + /*************************************************************************/ + /* */ + /* If you define TT_CONFIG_OPTION_UNPATENTED_HINTING, a special version */ + /* of the TrueType bytecode interpreter is used that doesn't implement */ + /* any of the patented opcodes and algorithms. The patents related to */ + /* TrueType hinting have expired worldwide since May 2010; this option */ + /* is now deprecated. */ + /* */ + /* Note that the TT_CONFIG_OPTION_UNPATENTED_HINTING macro is *ignored* */ + /* if you define TT_CONFIG_OPTION_BYTECODE_INTERPRETER; in other words, */ + /* either define TT_CONFIG_OPTION_BYTECODE_INTERPRETER or */ + /* TT_CONFIG_OPTION_UNPATENTED_HINTING but not both at the same time. */ + /* */ + /* This macro is only useful for a small number of font files (mostly */ + /* for Asian scripts) that require bytecode interpretation to properly */ + /* load glyphs. For all other fonts, this produces unpleasant results, */ + /* thus the unpatented interpreter is never used to load glyphs from */ + /* TrueType fonts unless one of the following two options is used. */ + /* */ + /* - The unpatented interpreter is explicitly activated by the user */ + /* through the FT_PARAM_TAG_UNPATENTED_HINTING parameter tag */ + /* when opening the FT_Face. */ + /* */ + /* - FreeType detects that the FT_Face corresponds to one of the */ + /* `trick' fonts (e.g., `Mingliu') it knows about. The font engine */ + /* contains a hard-coded list of font names and other matching */ + /* parameters (see function `tt_face_init' in file */ + /* `src/truetype/ttobjs.c'). */ + /* */ + /* Here a sample code snippet for using FT_PARAM_TAG_UNPATENTED_HINTING. */ + /* */ + /* { */ + /* FT_Parameter parameter; */ + /* FT_Open_Args open_args; */ + /* */ + /* */ + /* parameter.tag = FT_PARAM_TAG_UNPATENTED_HINTING; */ + /* */ + /* open_args.flags = FT_OPEN_PATHNAME | FT_OPEN_PARAMS; */ + /* open_args.pathname = my_font_pathname; */ + /* open_args.num_params = 1; */ + /* open_args.params = ¶meter; */ + /* */ + /* error = FT_Open_Face( library, &open_args, index, &face ); */ + /* ... */ + /* } */ + /* */ +/* #define TT_CONFIG_OPTION_UNPATENTED_HINTING */ + + + /*************************************************************************/ + /* */ + /* Define TT_CONFIG_OPTION_INTERPRETER_SWITCH to compile the TrueType */ + /* bytecode interpreter with a huge switch statement, rather than a call */ + /* table. This results in smaller and faster code for a number of */ + /* architectures. */ + /* */ + /* Note however that on some compiler/processor combinations, undefining */ + /* this macro will generate faster, though larger, code. */ + /* */ +#define TT_CONFIG_OPTION_INTERPRETER_SWITCH + + + /*************************************************************************/ + /* */ + /* Define TT_CONFIG_OPTION_COMPONENT_OFFSET_SCALED to compile the */ + /* TrueType glyph loader to use Apple's definition of how to handle */ + /* component offsets in composite glyphs. */ + /* */ + /* Apple and MS disagree on the default behavior of component offsets */ + /* in composites. Apple says that they should be scaled by the scaling */ + /* factors in the transformation matrix (roughly, it's more complex) */ + /* while MS says they should not. OpenType defines two bits in the */ + /* composite flags array which can be used to disambiguate, but old */ + /* fonts will not have them. */ + /* */ + /* http://partners.adobe.com/asn/developer/opentype/glyf.html */ + /* http://fonts.apple.com/TTRefMan/RM06/Chap6glyf.html */ + /* */ +#undef TT_CONFIG_OPTION_COMPONENT_OFFSET_SCALED + + + /*************************************************************************/ + /* */ + /* Define TT_CONFIG_OPTION_GX_VAR_SUPPORT if you want to include */ + /* support for Apple's distortable font technology (fvar, gvar, cvar, */ + /* and avar tables). This has many similarities to Type 1 Multiple */ + /* Masters support. */ + /* */ +#define TT_CONFIG_OPTION_GX_VAR_SUPPORT + + + /*************************************************************************/ + /* */ + /* Define TT_CONFIG_OPTION_BDF if you want to include support for */ + /* an embedded `BDF ' table within SFNT-based bitmap formats. */ + /* */ +#define TT_CONFIG_OPTION_BDF + + + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** T Y P E 1 D R I V E R C O N F I G U R A T I O N ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* T1_MAX_DICT_DEPTH is the maximal depth of nest dictionaries and */ + /* arrays in the Type 1 stream (see t1load.c). A minimum of 4 is */ + /* required. */ + /* */ +#define T1_MAX_DICT_DEPTH 5 + + + /*************************************************************************/ + /* */ + /* T1_MAX_SUBRS_CALLS details the maximum number of nested sub-routine */ + /* calls during glyph loading. */ + /* */ +#define T1_MAX_SUBRS_CALLS 16 + + + /*************************************************************************/ + /* */ + /* T1_MAX_CHARSTRING_OPERANDS is the charstring stack's capacity. A */ + /* minimum of 16 is required. */ + /* */ + /* The Chinese font MingTiEG-Medium (CNS 11643 character set) needs 256. */ + /* */ +#define T1_MAX_CHARSTRINGS_OPERANDS 256 + + + /*************************************************************************/ + /* */ + /* Define this configuration macro if you want to prevent the */ + /* compilation of `t1afm', which is in charge of reading Type 1 AFM */ + /* files into an existing face. Note that if set, the T1 driver will be */ + /* unable to produce kerning distances. */ + /* */ +#undef T1_CONFIG_OPTION_NO_AFM + + + /*************************************************************************/ + /* */ + /* Define this configuration macro if you want to prevent the */ + /* compilation of the Multiple Masters font support in the Type 1 */ + /* driver. */ + /* */ +#undef T1_CONFIG_OPTION_NO_MM_SUPPORT + + + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** A U T O F I T M O D U L E C O N F I G U R A T I O N ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* Compile autofit module with CJK (Chinese, Japanese, Korean) script */ + /* support. */ + /* */ +#define AF_CONFIG_OPTION_CJK + + /*************************************************************************/ + /* */ + /* Compile autofit module with Indic script support. */ + /* */ +#define AF_CONFIG_OPTION_INDIC + + /* */ + + + /* + * Define this variable if you want to keep the layout of internal + * structures that was used prior to FreeType 2.2. This also compiles in + * a few obsolete functions to avoid linking problems on typical Unix + * distributions. + * + * For embedded systems or building a new distribution from scratch, it + * is recommended to disable the macro since it reduces the library's code + * size and activates a few memory-saving optimizations as well. + */ +#define FT_CONFIG_OPTION_OLD_INTERNALS + + + /* + * To detect legacy cache-lookup call from a rogue client (<= 2.1.7), + * we restrict the number of charmaps in a font. The current API of + * FTC_CMapCache_Lookup() takes cmap_index & charcode, but old API + * takes charcode only. To determine the passed value is for cmap_index + * or charcode, the possible cmap_index is restricted not to exceed + * the minimum possible charcode by a rogue client. It is also very + * unlikely that a rogue client is interested in Unicode values 0 to 15. + * + * NOTE: The original threshold was 4 deduced from popular number of + * cmap subtables in UCS-4 TrueType fonts, but now it is not + * irregular for OpenType fonts to have more than 4 subtables, + * because variation selector subtables are available for Apple + * and Microsoft platforms. + */ + +#ifdef FT_CONFIG_OPTION_OLD_INTERNALS +#define FT_MAX_CHARMAP_CACHEABLE 15 +#endif + + + /* + * This macro is defined if either unpatented or native TrueType + * hinting is requested by the definitions above. + */ +#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER +#define TT_USE_BYTECODE_INTERPRETER +#undef TT_CONFIG_OPTION_UNPATENTED_HINTING +#elif defined TT_CONFIG_OPTION_UNPATENTED_HINTING +#define TT_USE_BYTECODE_INTERPRETER +#endif + +FT_END_HEADER + + +#endif /* __FTOPTION_H__ */ + + +/* END */ diff --git a/Lib/Include/freetype/config/ftstdlib.h b/Lib/Include/freetype/config/ftstdlib.h new file mode 100644 index 0000000..30ec14e --- /dev/null +++ b/Lib/Include/freetype/config/ftstdlib.h @@ -0,0 +1,173 @@ +/***************************************************************************/ +/* */ +/* ftstdlib.h */ +/* */ +/* ANSI-specific library and header configuration file (specification */ +/* only). */ +/* */ +/* Copyright 2002, 2003, 2004, 2005, 2006, 2007, 2009 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + + /*************************************************************************/ + /* */ + /* This file is used to group all #includes to the ANSI C library that */ + /* FreeType normally requires. It also defines macros to rename the */ + /* standard functions within the FreeType source code. */ + /* */ + /* Load a file which defines __FTSTDLIB_H__ before this one to override */ + /* it. */ + /* */ + /*************************************************************************/ + + +#ifndef __FTSTDLIB_H__ +#define __FTSTDLIB_H__ + + +#include <stddef.h> + +#define ft_ptrdiff_t ptrdiff_t + + + /**********************************************************************/ + /* */ + /* integer limits */ + /* */ + /* UINT_MAX and ULONG_MAX are used to automatically compute the size */ + /* of `int' and `long' in bytes at compile-time. So far, this works */ + /* for all platforms the library has been tested on. */ + /* */ + /* Note that on the extremely rare platforms that do not provide */ + /* integer types that are _exactly_ 16 and 32 bits wide (e.g. some */ + /* old Crays where `int' is 36 bits), we do not make any guarantee */ + /* about the correct behaviour of FT2 with all fonts. */ + /* */ + /* In these case, `ftconfig.h' will refuse to compile anyway with a */ + /* message like `couldn't find 32-bit type' or something similar. */ + /* */ + /**********************************************************************/ + + +#include <limits.h> + +#define FT_CHAR_BIT CHAR_BIT +#define FT_INT_MAX INT_MAX +#define FT_INT_MIN INT_MIN +#define FT_UINT_MAX UINT_MAX +#define FT_ULONG_MAX ULONG_MAX + + + /**********************************************************************/ + /* */ + /* character and string processing */ + /* */ + /**********************************************************************/ + + +#include <string.h> + +#define ft_memchr memchr +#define ft_memcmp memcmp +#define ft_memcpy memcpy +#define ft_memmove memmove +#define ft_memset memset +#define ft_strcat strcat +#define ft_strcmp strcmp +#define ft_strcpy strcpy +#define ft_strlen strlen +#define ft_strncmp strncmp +#define ft_strncpy strncpy +#define ft_strrchr strrchr +#define ft_strstr strstr + + + /**********************************************************************/ + /* */ + /* file handling */ + /* */ + /**********************************************************************/ + + +#include <stdio.h> + +#define FT_FILE FILE +#define ft_fclose fclose +#define ft_fopen fopen +#define ft_fread fread +#define ft_fseek fseek +#define ft_ftell ftell +#define ft_sprintf sprintf + + + /**********************************************************************/ + /* */ + /* sorting */ + /* */ + /**********************************************************************/ + + +#include <stdlib.h> + +#define ft_qsort qsort + + + /**********************************************************************/ + /* */ + /* memory allocation */ + /* */ + /**********************************************************************/ + + +#define ft_scalloc calloc +#define ft_sfree free +#define ft_smalloc malloc +#define ft_srealloc realloc + + + /**********************************************************************/ + /* */ + /* miscellaneous */ + /* */ + /**********************************************************************/ + + +#define ft_atol atol +#define ft_labs labs + + + /**********************************************************************/ + /* */ + /* execution control */ + /* */ + /**********************************************************************/ + + +#include <setjmp.h> + +#define ft_jmp_buf jmp_buf /* note: this cannot be a typedef since */ + /* jmp_buf is defined as a macro */ + /* on certain platforms */ + +#define ft_longjmp longjmp +#define ft_setjmp( b ) setjmp( *(jmp_buf*) &(b) ) /* same thing here */ + + + /* the following is only used for debugging purposes, i.e., if */ + /* FT_DEBUG_LEVEL_ERROR or FT_DEBUG_LEVEL_TRACE are defined */ + +#include <stdarg.h> + + +#endif /* __FTSTDLIB_H__ */ + + +/* END */ diff --git a/Lib/Include/freetype/freetype.h b/Lib/Include/freetype/freetype.h new file mode 100644 index 0000000..70c3900 --- /dev/null +++ b/Lib/Include/freetype/freetype.h @@ -0,0 +1,3919 @@ +/***************************************************************************/ +/* */ +/* freetype.h */ +/* */ +/* FreeType high-level API and common types (specification only). */ +/* */ +/* Copyright 1996-2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, */ +/* 2010 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef FT_FREETYPE_H +#error "`ft2build.h' hasn't been included yet!" +#error "Please always use macros to include FreeType header files." +#error "Example:" +#error " #include <ft2build.h>" +#error " #include FT_FREETYPE_H" +#endif + + +#ifndef __FREETYPE_H__ +#define __FREETYPE_H__ + + +#include <ft2build.h> +#include FT_CONFIG_CONFIG_H +#include FT_ERRORS_H +#include FT_TYPES_H + + +FT_BEGIN_HEADER + + + + /*************************************************************************/ + /* */ + /* <Section> */ + /* user_allocation */ + /* */ + /* <Title> */ + /* User allocation */ + /* */ + /* <Abstract> */ + /* How client applications should allocate FreeType data structures. */ + /* */ + /* <Description> */ + /* FreeType assumes that structures allocated by the user and passed */ + /* as arguments are zeroed out except for the actual data. In other */ + /* words, it is recommended to use `calloc' (or variants of it) */ + /* instead of `malloc' for allocation. */ + /* */ + /*************************************************************************/ + + + + /*************************************************************************/ + /*************************************************************************/ + /* */ + /* B A S I C T Y P E S */ + /* */ + /*************************************************************************/ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* <Section> */ + /* base_interface */ + /* */ + /* <Title> */ + /* Base Interface */ + /* */ + /* <Abstract> */ + /* The FreeType~2 base font interface. */ + /* */ + /* <Description> */ + /* This section describes the public high-level API of FreeType~2. */ + /* */ + /* <Order> */ + /* FT_Library */ + /* FT_Face */ + /* FT_Size */ + /* FT_GlyphSlot */ + /* FT_CharMap */ + /* FT_Encoding */ + /* */ + /* FT_FaceRec */ + /* */ + /* FT_FACE_FLAG_SCALABLE */ + /* FT_FACE_FLAG_FIXED_SIZES */ + /* FT_FACE_FLAG_FIXED_WIDTH */ + /* FT_FACE_FLAG_HORIZONTAL */ + /* FT_FACE_FLAG_VERTICAL */ + /* FT_FACE_FLAG_SFNT */ + /* FT_FACE_FLAG_KERNING */ + /* FT_FACE_FLAG_MULTIPLE_MASTERS */ + /* FT_FACE_FLAG_GLYPH_NAMES */ + /* FT_FACE_FLAG_EXTERNAL_STREAM */ + /* FT_FACE_FLAG_FAST_GLYPHS */ + /* FT_FACE_FLAG_HINTER */ + /* */ + /* FT_STYLE_FLAG_BOLD */ + /* FT_STYLE_FLAG_ITALIC */ + /* */ + /* FT_SizeRec */ + /* FT_Size_Metrics */ + /* */ + /* FT_GlyphSlotRec */ + /* FT_Glyph_Metrics */ + /* FT_SubGlyph */ + /* */ + /* FT_Bitmap_Size */ + /* */ + /* FT_Init_FreeType */ + /* FT_Done_FreeType */ + /* */ + /* FT_New_Face */ + /* FT_Done_Face */ + /* FT_New_Memory_Face */ + /* FT_Open_Face */ + /* FT_Open_Args */ + /* FT_Parameter */ + /* FT_Attach_File */ + /* FT_Attach_Stream */ + /* */ + /* FT_Set_Char_Size */ + /* FT_Set_Pixel_Sizes */ + /* FT_Request_Size */ + /* FT_Select_Size */ + /* FT_Size_Request_Type */ + /* FT_Size_Request */ + /* FT_Set_Transform */ + /* FT_Load_Glyph */ + /* FT_Get_Char_Index */ + /* FT_Get_Name_Index */ + /* FT_Load_Char */ + /* */ + /* FT_OPEN_MEMORY */ + /* FT_OPEN_STREAM */ + /* FT_OPEN_PATHNAME */ + /* FT_OPEN_DRIVER */ + /* FT_OPEN_PARAMS */ + /* */ + /* FT_LOAD_DEFAULT */ + /* FT_LOAD_RENDER */ + /* FT_LOAD_MONOCHROME */ + /* FT_LOAD_LINEAR_DESIGN */ + /* FT_LOAD_NO_SCALE */ + /* FT_LOAD_NO_HINTING */ + /* FT_LOAD_NO_BITMAP */ + /* FT_LOAD_CROP_BITMAP */ + /* */ + /* FT_LOAD_VERTICAL_LAYOUT */ + /* FT_LOAD_IGNORE_TRANSFORM */ + /* FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH */ + /* FT_LOAD_FORCE_AUTOHINT */ + /* FT_LOAD_NO_RECURSE */ + /* FT_LOAD_PEDANTIC */ + /* */ + /* FT_LOAD_TARGET_NORMAL */ + /* FT_LOAD_TARGET_LIGHT */ + /* FT_LOAD_TARGET_MONO */ + /* FT_LOAD_TARGET_LCD */ + /* FT_LOAD_TARGET_LCD_V */ + /* */ + /* FT_Render_Glyph */ + /* FT_Render_Mode */ + /* FT_Get_Kerning */ + /* FT_Kerning_Mode */ + /* FT_Get_Track_Kerning */ + /* FT_Get_Glyph_Name */ + /* FT_Get_Postscript_Name */ + /* */ + /* FT_CharMapRec */ + /* FT_Select_Charmap */ + /* FT_Set_Charmap */ + /* FT_Get_Charmap_Index */ + /* */ + /* FT_FSTYPE_INSTALLABLE_EMBEDDING */ + /* FT_FSTYPE_RESTRICTED_LICENSE_EMBEDDING */ + /* FT_FSTYPE_PREVIEW_AND_PRINT_EMBEDDING */ + /* FT_FSTYPE_EDITABLE_EMBEDDING */ + /* FT_FSTYPE_NO_SUBSETTING */ + /* FT_FSTYPE_BITMAP_EMBEDDING_ONLY */ + /* */ + /* FT_Get_FSType_Flags */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_Glyph_Metrics */ + /* */ + /* <Description> */ + /* A structure used to model the metrics of a single glyph. The */ + /* values are expressed in 26.6 fractional pixel format; if the flag */ + /* @FT_LOAD_NO_SCALE has been used while loading the glyph, values */ + /* are expressed in font units instead. */ + /* */ + /* <Fields> */ + /* width :: */ + /* The glyph's width. */ + /* */ + /* height :: */ + /* The glyph's height. */ + /* */ + /* horiBearingX :: */ + /* Left side bearing for horizontal layout. */ + /* */ + /* horiBearingY :: */ + /* Top side bearing for horizontal layout. */ + /* */ + /* horiAdvance :: */ + /* Advance width for horizontal layout. */ + /* */ + /* vertBearingX :: */ + /* Left side bearing for vertical layout. */ + /* */ + /* vertBearingY :: */ + /* Top side bearing for vertical layout. */ + /* */ + /* vertAdvance :: */ + /* Advance height for vertical layout. */ + /* */ + /* <Note> */ + /* If not disabled with @FT_LOAD_NO_HINTING, the values represent */ + /* dimensions of the hinted glyph (in case hinting is applicable). */ + /* */ + typedef struct FT_Glyph_Metrics_ + { + FT_Pos width; + FT_Pos height; + + FT_Pos horiBearingX; + FT_Pos horiBearingY; + FT_Pos horiAdvance; + + FT_Pos vertBearingX; + FT_Pos vertBearingY; + FT_Pos vertAdvance; + + } FT_Glyph_Metrics; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_Bitmap_Size */ + /* */ + /* <Description> */ + /* This structure models the metrics of a bitmap strike (i.e., a set */ + /* of glyphs for a given point size and resolution) in a bitmap font. */ + /* It is used for the `available_sizes' field of @FT_Face. */ + /* */ + /* <Fields> */ + /* height :: The vertical distance, in pixels, between two */ + /* consecutive baselines. It is always positive. */ + /* */ + /* width :: The average width, in pixels, of all glyphs in the */ + /* strike. */ + /* */ + /* size :: The nominal size of the strike in 26.6 fractional */ + /* points. This field is not very useful. */ + /* */ + /* x_ppem :: The horizontal ppem (nominal width) in 26.6 fractional */ + /* pixels. */ + /* */ + /* y_ppem :: The vertical ppem (nominal height) in 26.6 fractional */ + /* pixels. */ + /* */ + /* <Note> */ + /* Windows FNT: */ + /* The nominal size given in a FNT font is not reliable. Thus when */ + /* the driver finds it incorrect, it sets `size' to some calculated */ + /* values and sets `x_ppem' and `y_ppem' to the pixel width and */ + /* height given in the font, respectively. */ + /* */ + /* TrueType embedded bitmaps: */ + /* `size', `width', and `height' values are not contained in the */ + /* bitmap strike itself. They are computed from the global font */ + /* parameters. */ + /* */ + typedef struct FT_Bitmap_Size_ + { + FT_Short height; + FT_Short width; + + FT_Pos size; + + FT_Pos x_ppem; + FT_Pos y_ppem; + + } FT_Bitmap_Size; + + + /*************************************************************************/ + /*************************************************************************/ + /* */ + /* O B J E C T C L A S S E S */ + /* */ + /*************************************************************************/ + /*************************************************************************/ + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_Library */ + /* */ + /* <Description> */ + /* A handle to a FreeType library instance. Each `library' is */ + /* completely independent from the others; it is the `root' of a set */ + /* of objects like fonts, faces, sizes, etc. */ + /* */ + /* It also embeds a memory manager (see @FT_Memory), as well as a */ + /* scan-line converter object (see @FT_Raster). */ + /* */ + /* For multi-threading applications each thread should have its own */ + /* FT_Library object. */ + /* */ + /* <Note> */ + /* Library objects are normally created by @FT_Init_FreeType, and */ + /* destroyed with @FT_Done_FreeType. */ + /* */ + typedef struct FT_LibraryRec_ *FT_Library; + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_Module */ + /* */ + /* <Description> */ + /* A handle to a given FreeType module object. Each module can be a */ + /* font driver, a renderer, or anything else that provides services */ + /* to the formers. */ + /* */ + typedef struct FT_ModuleRec_* FT_Module; + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_Driver */ + /* */ + /* <Description> */ + /* A handle to a given FreeType font driver object. Each font driver */ + /* is a special module capable of creating faces from font files. */ + /* */ + typedef struct FT_DriverRec_* FT_Driver; + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_Renderer */ + /* */ + /* <Description> */ + /* A handle to a given FreeType renderer. A renderer is a special */ + /* module in charge of converting a glyph image to a bitmap, when */ + /* necessary. Each renderer supports a given glyph image format, and */ + /* one or more target surface depths. */ + /* */ + typedef struct FT_RendererRec_* FT_Renderer; + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_Face */ + /* */ + /* <Description> */ + /* A handle to a given typographic face object. A face object models */ + /* a given typeface, in a given style. */ + /* */ + /* <Note> */ + /* Each face object also owns a single @FT_GlyphSlot object, as well */ + /* as one or more @FT_Size objects. */ + /* */ + /* Use @FT_New_Face or @FT_Open_Face to create a new face object from */ + /* a given filepathname or a custom input stream. */ + /* */ + /* Use @FT_Done_Face to destroy it (along with its slot and sizes). */ + /* */ + /* <Also> */ + /* See @FT_FaceRec for the publicly accessible fields of a given face */ + /* object. */ + /* */ + typedef struct FT_FaceRec_* FT_Face; + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_Size */ + /* */ + /* <Description> */ + /* A handle to an object used to model a face scaled to a given */ + /* character size. */ + /* */ + /* <Note> */ + /* Each @FT_Face has an _active_ @FT_Size object that is used by */ + /* functions like @FT_Load_Glyph to determine the scaling */ + /* transformation which is used to load and hint glyphs and metrics. */ + /* */ + /* You can use @FT_Set_Char_Size, @FT_Set_Pixel_Sizes, */ + /* @FT_Request_Size or even @FT_Select_Size to change the content */ + /* (i.e., the scaling values) of the active @FT_Size. */ + /* */ + /* You can use @FT_New_Size to create additional size objects for a */ + /* given @FT_Face, but they won't be used by other functions until */ + /* you activate it through @FT_Activate_Size. Only one size can be */ + /* activated at any given time per face. */ + /* */ + /* <Also> */ + /* See @FT_SizeRec for the publicly accessible fields of a given size */ + /* object. */ + /* */ + typedef struct FT_SizeRec_* FT_Size; + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_GlyphSlot */ + /* */ + /* <Description> */ + /* A handle to a given `glyph slot'. A slot is a container where it */ + /* is possible to load any of the glyphs contained in its parent */ + /* face. */ + /* */ + /* In other words, each time you call @FT_Load_Glyph or */ + /* @FT_Load_Char, the slot's content is erased by the new glyph data, */ + /* i.e., the glyph's metrics, its image (bitmap or outline), and */ + /* other control information. */ + /* */ + /* <Also> */ + /* See @FT_GlyphSlotRec for the publicly accessible glyph fields. */ + /* */ + typedef struct FT_GlyphSlotRec_* FT_GlyphSlot; + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_CharMap */ + /* */ + /* <Description> */ + /* A handle to a given character map. A charmap is used to translate */ + /* character codes in a given encoding into glyph indexes for its */ + /* parent's face. Some font formats may provide several charmaps per */ + /* font. */ + /* */ + /* Each face object owns zero or more charmaps, but only one of them */ + /* can be `active' and used by @FT_Get_Char_Index or @FT_Load_Char. */ + /* */ + /* The list of available charmaps in a face is available through the */ + /* `face->num_charmaps' and `face->charmaps' fields of @FT_FaceRec. */ + /* */ + /* The currently active charmap is available as `face->charmap'. */ + /* You should call @FT_Set_Charmap to change it. */ + /* */ + /* <Note> */ + /* When a new face is created (either through @FT_New_Face or */ + /* @FT_Open_Face), the library looks for a Unicode charmap within */ + /* the list and automatically activates it. */ + /* */ + /* <Also> */ + /* See @FT_CharMapRec for the publicly accessible fields of a given */ + /* character map. */ + /* */ + typedef struct FT_CharMapRec_* FT_CharMap; + + + /*************************************************************************/ + /* */ + /* <Macro> */ + /* FT_ENC_TAG */ + /* */ + /* <Description> */ + /* This macro converts four-letter tags into an unsigned long. It is */ + /* used to define `encoding' identifiers (see @FT_Encoding). */ + /* */ + /* <Note> */ + /* Since many 16-bit compilers don't like 32-bit enumerations, you */ + /* should redefine this macro in case of problems to something like */ + /* this: */ + /* */ + /* { */ + /* #define FT_ENC_TAG( value, a, b, c, d ) value */ + /* } */ + /* */ + /* to get a simple enumeration without assigning special numbers. */ + /* */ + +#ifndef FT_ENC_TAG +#define FT_ENC_TAG( value, a, b, c, d ) \ + value = ( ( (FT_UInt32)(a) << 24 ) | \ + ( (FT_UInt32)(b) << 16 ) | \ + ( (FT_UInt32)(c) << 8 ) | \ + (FT_UInt32)(d) ) + +#endif /* FT_ENC_TAG */ + + + /*************************************************************************/ + /* */ + /* <Enum> */ + /* FT_Encoding */ + /* */ + /* <Description> */ + /* An enumeration used to specify character sets supported by */ + /* charmaps. Used in the @FT_Select_Charmap API function. */ + /* */ + /* <Note> */ + /* Despite the name, this enumeration lists specific character */ + /* repertories (i.e., charsets), and not text encoding methods (e.g., */ + /* UTF-8, UTF-16, etc.). */ + /* */ + /* Other encodings might be defined in the future. */ + /* */ + /* <Values> */ + /* FT_ENCODING_NONE :: */ + /* The encoding value~0 is reserved. */ + /* */ + /* FT_ENCODING_UNICODE :: */ + /* Corresponds to the Unicode character set. This value covers */ + /* all versions of the Unicode repertoire, including ASCII and */ + /* Latin-1. Most fonts include a Unicode charmap, but not all */ + /* of them. */ + /* */ + /* For example, if you want to access Unicode value U+1F028 (and */ + /* the font contains it), use value 0x1F028 as the input value for */ + /* @FT_Get_Char_Index. */ + /* */ + /* FT_ENCODING_MS_SYMBOL :: */ + /* Corresponds to the Microsoft Symbol encoding, used to encode */ + /* mathematical symbols in the 32..255 character code range. For */ + /* more information, see `http://www.ceviz.net/symbol.htm'. */ + /* */ + /* FT_ENCODING_SJIS :: */ + /* Corresponds to Japanese SJIS encoding. More info at */ + /* at `http://langsupport.japanreference.com/encoding.shtml'. */ + /* See note on multi-byte encodings below. */ + /* */ + /* FT_ENCODING_GB2312 :: */ + /* Corresponds to an encoding system for Simplified Chinese as used */ + /* used in mainland China. */ + /* */ + /* FT_ENCODING_BIG5 :: */ + /* Corresponds to an encoding system for Traditional Chinese as */ + /* used in Taiwan and Hong Kong. */ + /* */ + /* FT_ENCODING_WANSUNG :: */ + /* Corresponds to the Korean encoding system known as Wansung. */ + /* For more information see */ + /* `http://www.microsoft.com/typography/unicode/949.txt'. */ + /* */ + /* FT_ENCODING_JOHAB :: */ + /* The Korean standard character set (KS~C 5601-1992), which */ + /* corresponds to MS Windows code page 1361. This character set */ + /* includes all possible Hangeul character combinations. */ + /* */ + /* FT_ENCODING_ADOBE_LATIN_1 :: */ + /* Corresponds to a Latin-1 encoding as defined in a Type~1 */ + /* PostScript font. It is limited to 256 character codes. */ + /* */ + /* FT_ENCODING_ADOBE_STANDARD :: */ + /* Corresponds to the Adobe Standard encoding, as found in Type~1, */ + /* CFF, and OpenType/CFF fonts. It is limited to 256 character */ + /* codes. */ + /* */ + /* FT_ENCODING_ADOBE_EXPERT :: */ + /* Corresponds to the Adobe Expert encoding, as found in Type~1, */ + /* CFF, and OpenType/CFF fonts. It is limited to 256 character */ + /* codes. */ + /* */ + /* FT_ENCODING_ADOBE_CUSTOM :: */ + /* Corresponds to a custom encoding, as found in Type~1, CFF, and */ + /* OpenType/CFF fonts. It is limited to 256 character codes. */ + /* */ + /* FT_ENCODING_APPLE_ROMAN :: */ + /* Corresponds to the 8-bit Apple roman encoding. Many TrueType */ + /* and OpenType fonts contain a charmap for this encoding, since */ + /* older versions of Mac OS are able to use it. */ + /* */ + /* FT_ENCODING_OLD_LATIN_2 :: */ + /* This value is deprecated and was never used nor reported by */ + /* FreeType. Don't use or test for it. */ + /* */ + /* FT_ENCODING_MS_SJIS :: */ + /* Same as FT_ENCODING_SJIS. Deprecated. */ + /* */ + /* FT_ENCODING_MS_GB2312 :: */ + /* Same as FT_ENCODING_GB2312. Deprecated. */ + /* */ + /* FT_ENCODING_MS_BIG5 :: */ + /* Same as FT_ENCODING_BIG5. Deprecated. */ + /* */ + /* FT_ENCODING_MS_WANSUNG :: */ + /* Same as FT_ENCODING_WANSUNG. Deprecated. */ + /* */ + /* FT_ENCODING_MS_JOHAB :: */ + /* Same as FT_ENCODING_JOHAB. Deprecated. */ + /* */ + /* <Note> */ + /* By default, FreeType automatically synthesizes a Unicode charmap */ + /* for PostScript fonts, using their glyph names dictionaries. */ + /* However, it also reports the encodings defined explicitly in the */ + /* font file, for the cases when they are needed, with the Adobe */ + /* values as well. */ + /* */ + /* FT_ENCODING_NONE is set by the BDF and PCF drivers if the charmap */ + /* is neither Unicode nor ISO-8859-1 (otherwise it is set to */ + /* FT_ENCODING_UNICODE). Use @FT_Get_BDF_Charset_ID to find out */ + /* which encoding is really present. If, for example, the */ + /* `cs_registry' field is `KOI8' and the `cs_encoding' field is `R', */ + /* the font is encoded in KOI8-R. */ + /* */ + /* FT_ENCODING_NONE is always set (with a single exception) by the */ + /* winfonts driver. Use @FT_Get_WinFNT_Header and examine the */ + /* `charset' field of the @FT_WinFNT_HeaderRec structure to find out */ + /* which encoding is really present. For example, */ + /* @FT_WinFNT_ID_CP1251 (204) means Windows code page 1251 (for */ + /* Russian). */ + /* */ + /* FT_ENCODING_NONE is set if `platform_id' is @TT_PLATFORM_MACINTOSH */ + /* and `encoding_id' is not @TT_MAC_ID_ROMAN (otherwise it is set to */ + /* FT_ENCODING_APPLE_ROMAN). */ + /* */ + /* If `platform_id' is @TT_PLATFORM_MACINTOSH, use the function */ + /* @FT_Get_CMap_Language_ID to query the Mac language ID which may */ + /* be needed to be able to distinguish Apple encoding variants. See */ + /* */ + /* http://www.unicode.org/Public/MAPPINGS/VENDORS/APPLE/README.TXT */ + /* */ + /* to get an idea how to do that. Basically, if the language ID */ + /* is~0, don't use it, otherwise subtract 1 from the language ID. */ + /* Then examine `encoding_id'. If, for example, `encoding_id' is */ + /* @TT_MAC_ID_ROMAN and the language ID (minus~1) is */ + /* `TT_MAC_LANGID_GREEK', it is the Greek encoding, not Roman. */ + /* @TT_MAC_ID_ARABIC with `TT_MAC_LANGID_FARSI' means the Farsi */ + /* variant the Arabic encoding. */ + /* */ + typedef enum FT_Encoding_ + { + FT_ENC_TAG( FT_ENCODING_NONE, 0, 0, 0, 0 ), + + FT_ENC_TAG( FT_ENCODING_MS_SYMBOL, 's', 'y', 'm', 'b' ), + FT_ENC_TAG( FT_ENCODING_UNICODE, 'u', 'n', 'i', 'c' ), + + FT_ENC_TAG( FT_ENCODING_SJIS, 's', 'j', 'i', 's' ), + FT_ENC_TAG( FT_ENCODING_GB2312, 'g', 'b', ' ', ' ' ), + FT_ENC_TAG( FT_ENCODING_BIG5, 'b', 'i', 'g', '5' ), + FT_ENC_TAG( FT_ENCODING_WANSUNG, 'w', 'a', 'n', 's' ), + FT_ENC_TAG( FT_ENCODING_JOHAB, 'j', 'o', 'h', 'a' ), + + /* for backwards compatibility */ + FT_ENCODING_MS_SJIS = FT_ENCODING_SJIS, + FT_ENCODING_MS_GB2312 = FT_ENCODING_GB2312, + FT_ENCODING_MS_BIG5 = FT_ENCODING_BIG5, + FT_ENCODING_MS_WANSUNG = FT_ENCODING_WANSUNG, + FT_ENCODING_MS_JOHAB = FT_ENCODING_JOHAB, + + FT_ENC_TAG( FT_ENCODING_ADOBE_STANDARD, 'A', 'D', 'O', 'B' ), + FT_ENC_TAG( FT_ENCODING_ADOBE_EXPERT, 'A', 'D', 'B', 'E' ), + FT_ENC_TAG( FT_ENCODING_ADOBE_CUSTOM, 'A', 'D', 'B', 'C' ), + FT_ENC_TAG( FT_ENCODING_ADOBE_LATIN_1, 'l', 'a', 't', '1' ), + + FT_ENC_TAG( FT_ENCODING_OLD_LATIN_2, 'l', 'a', 't', '2' ), + + FT_ENC_TAG( FT_ENCODING_APPLE_ROMAN, 'a', 'r', 'm', 'n' ) + + } FT_Encoding; + + + /*************************************************************************/ + /* */ + /* <Enum> */ + /* ft_encoding_xxx */ + /* */ + /* <Description> */ + /* These constants are deprecated; use the corresponding @FT_Encoding */ + /* values instead. */ + /* */ +#define ft_encoding_none FT_ENCODING_NONE +#define ft_encoding_unicode FT_ENCODING_UNICODE +#define ft_encoding_symbol FT_ENCODING_MS_SYMBOL +#define ft_encoding_latin_1 FT_ENCODING_ADOBE_LATIN_1 +#define ft_encoding_latin_2 FT_ENCODING_OLD_LATIN_2 +#define ft_encoding_sjis FT_ENCODING_SJIS +#define ft_encoding_gb2312 FT_ENCODING_GB2312 +#define ft_encoding_big5 FT_ENCODING_BIG5 +#define ft_encoding_wansung FT_ENCODING_WANSUNG +#define ft_encoding_johab FT_ENCODING_JOHAB + +#define ft_encoding_adobe_standard FT_ENCODING_ADOBE_STANDARD +#define ft_encoding_adobe_expert FT_ENCODING_ADOBE_EXPERT +#define ft_encoding_adobe_custom FT_ENCODING_ADOBE_CUSTOM +#define ft_encoding_apple_roman FT_ENCODING_APPLE_ROMAN + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_CharMapRec */ + /* */ + /* <Description> */ + /* The base charmap structure. */ + /* */ + /* <Fields> */ + /* face :: A handle to the parent face object. */ + /* */ + /* encoding :: An @FT_Encoding tag identifying the charmap. Use */ + /* this with @FT_Select_Charmap. */ + /* */ + /* platform_id :: An ID number describing the platform for the */ + /* following encoding ID. This comes directly from */ + /* the TrueType specification and should be emulated */ + /* for other formats. */ + /* */ + /* encoding_id :: A platform specific encoding number. This also */ + /* comes from the TrueType specification and should be */ + /* emulated similarly. */ + /* */ + typedef struct FT_CharMapRec_ + { + FT_Face face; + FT_Encoding encoding; + FT_UShort platform_id; + FT_UShort encoding_id; + + } FT_CharMapRec; + + + /*************************************************************************/ + /*************************************************************************/ + /* */ + /* B A S E O B J E C T C L A S S E S */ + /* */ + /*************************************************************************/ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_Face_Internal */ + /* */ + /* <Description> */ + /* An opaque handle to an `FT_Face_InternalRec' structure, used to */ + /* model private data of a given @FT_Face object. */ + /* */ + /* This structure might change between releases of FreeType~2 and is */ + /* not generally available to client applications. */ + /* */ + typedef struct FT_Face_InternalRec_* FT_Face_Internal; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_FaceRec */ + /* */ + /* <Description> */ + /* FreeType root face class structure. A face object models a */ + /* typeface in a font file. */ + /* */ + /* <Fields> */ + /* num_faces :: The number of faces in the font file. Some */ + /* font formats can have multiple faces in */ + /* a font file. */ + /* */ + /* face_index :: The index of the face in the font file. It */ + /* is set to~0 if there is only one face in */ + /* the font file. */ + /* */ + /* face_flags :: A set of bit flags that give important */ + /* information about the face; see */ + /* @FT_FACE_FLAG_XXX for the details. */ + /* */ + /* style_flags :: A set of bit flags indicating the style of */ + /* the face; see @FT_STYLE_FLAG_XXX for the */ + /* details. */ + /* */ + /* num_glyphs :: The number of glyphs in the face. If the */ + /* face is scalable and has sbits (see */ + /* `num_fixed_sizes'), it is set to the number */ + /* of outline glyphs. */ + /* */ + /* For CID-keyed fonts, this value gives the */ + /* highest CID used in the font. */ + /* */ + /* family_name :: The face's family name. This is an ASCII */ + /* string, usually in English, which describes */ + /* the typeface's family (like `Times New */ + /* Roman', `Bodoni', `Garamond', etc). This */ + /* is a least common denominator used to list */ + /* fonts. Some formats (TrueType & OpenType) */ + /* provide localized and Unicode versions of */ + /* this string. Applications should use the */ + /* format specific interface to access them. */ + /* Can be NULL (e.g., in fonts embedded in a */ + /* PDF file). */ + /* */ + /* style_name :: The face's style name. This is an ASCII */ + /* string, usually in English, which describes */ + /* the typeface's style (like `Italic', */ + /* `Bold', `Condensed', etc). Not all font */ + /* formats provide a style name, so this field */ + /* is optional, and can be set to NULL. As */ + /* for `family_name', some formats provide */ + /* localized and Unicode versions of this */ + /* string. Applications should use the format */ + /* specific interface to access them. */ + /* */ + /* num_fixed_sizes :: The number of bitmap strikes in the face. */ + /* Even if the face is scalable, there might */ + /* still be bitmap strikes, which are called */ + /* `sbits' in that case. */ + /* */ + /* available_sizes :: An array of @FT_Bitmap_Size for all bitmap */ + /* strikes in the face. It is set to NULL if */ + /* there is no bitmap strike. */ + /* */ + /* num_charmaps :: The number of charmaps in the face. */ + /* */ + /* charmaps :: An array of the charmaps of the face. */ + /* */ + /* generic :: A field reserved for client uses. See the */ + /* @FT_Generic type description. */ + /* */ + /* bbox :: The font bounding box. Coordinates are */ + /* expressed in font units (see */ + /* `units_per_EM'). The box is large enough */ + /* to contain any glyph from the font. Thus, */ + /* `bbox.yMax' can be seen as the `maximal */ + /* ascender', and `bbox.yMin' as the `minimal */ + /* descender'. Only relevant for scalable */ + /* formats. */ + /* */ + /* Note that the bounding box might be off by */ + /* (at least) one pixel for hinted fonts. See */ + /* @FT_Size_Metrics for further discussion. */ + /* */ + /* units_per_EM :: The number of font units per EM square for */ + /* this face. This is typically 2048 for */ + /* TrueType fonts, and 1000 for Type~1 fonts. */ + /* Only relevant for scalable formats. */ + /* */ + /* ascender :: The typographic ascender of the face, */ + /* expressed in font units. For font formats */ + /* not having this information, it is set to */ + /* `bbox.yMax'. Only relevant for scalable */ + /* formats. */ + /* */ + /* descender :: The typographic descender of the face, */ + /* expressed in font units. For font formats */ + /* not having this information, it is set to */ + /* `bbox.yMin'. Note that this field is */ + /* usually negative. Only relevant for */ + /* scalable formats. */ + /* */ + /* height :: The height is the vertical distance */ + /* between two consecutive baselines, */ + /* expressed in font units. It is always */ + /* positive. Only relevant for scalable */ + /* formats. */ + /* */ + /* max_advance_width :: The maximal advance width, in font units, */ + /* for all glyphs in this face. This can be */ + /* used to make word wrapping computations */ + /* faster. Only relevant for scalable */ + /* formats. */ + /* */ + /* max_advance_height :: The maximal advance height, in font units, */ + /* for all glyphs in this face. This is only */ + /* relevant for vertical layouts, and is set */ + /* to `height' for fonts that do not provide */ + /* vertical metrics. Only relevant for */ + /* scalable formats. */ + /* */ + /* underline_position :: The position, in font units, of the */ + /* underline line for this face. It is the */ + /* center of the underlining stem. Only */ + /* relevant for scalable formats. */ + /* */ + /* underline_thickness :: The thickness, in font units, of the */ + /* underline for this face. Only relevant for */ + /* scalable formats. */ + /* */ + /* glyph :: The face's associated glyph slot(s). */ + /* */ + /* size :: The current active size for this face. */ + /* */ + /* charmap :: The current active charmap for this face. */ + /* */ + /* <Note> */ + /* Fields may be changed after a call to @FT_Attach_File or */ + /* @FT_Attach_Stream. */ + /* */ + typedef struct FT_FaceRec_ + { + FT_Long num_faces; + FT_Long face_index; + + FT_Long face_flags; + FT_Long style_flags; + + FT_Long num_glyphs; + + FT_String* family_name; + FT_String* style_name; + + FT_Int num_fixed_sizes; + FT_Bitmap_Size* available_sizes; + + FT_Int num_charmaps; + FT_CharMap* charmaps; + + FT_Generic generic; + + /*# The following member variables (down to `underline_thickness') */ + /*# are only relevant to scalable outlines; cf. @FT_Bitmap_Size */ + /*# for bitmap fonts. */ + FT_BBox bbox; + + FT_UShort units_per_EM; + FT_Short ascender; + FT_Short descender; + FT_Short height; + + FT_Short max_advance_width; + FT_Short max_advance_height; + + FT_Short underline_position; + FT_Short underline_thickness; + + FT_GlyphSlot glyph; + FT_Size size; + FT_CharMap charmap; + + /*@private begin */ + + FT_Driver driver; + FT_Memory memory; + FT_Stream stream; + + FT_ListRec sizes_list; + + FT_Generic autohint; + void* extensions; + + FT_Face_Internal internal; + + /*@private end */ + + } FT_FaceRec; + + + /*************************************************************************/ + /* */ + /* <Enum> */ + /* FT_FACE_FLAG_XXX */ + /* */ + /* <Description> */ + /* A list of bit flags used in the `face_flags' field of the */ + /* @FT_FaceRec structure. They inform client applications of */ + /* properties of the corresponding face. */ + /* */ + /* <Values> */ + /* FT_FACE_FLAG_SCALABLE :: */ + /* Indicates that the face contains outline glyphs. This doesn't */ + /* prevent bitmap strikes, i.e., a face can have both this and */ + /* and @FT_FACE_FLAG_FIXED_SIZES set. */ + /* */ + /* FT_FACE_FLAG_FIXED_SIZES :: */ + /* Indicates that the face contains bitmap strikes. See also the */ + /* `num_fixed_sizes' and `available_sizes' fields of @FT_FaceRec. */ + /* */ + /* FT_FACE_FLAG_FIXED_WIDTH :: */ + /* Indicates that the face contains fixed-width characters (like */ + /* Courier, Lucido, MonoType, etc.). */ + /* */ + /* FT_FACE_FLAG_SFNT :: */ + /* Indicates that the face uses the `sfnt' storage scheme. For */ + /* now, this means TrueType and OpenType. */ + /* */ + /* FT_FACE_FLAG_HORIZONTAL :: */ + /* Indicates that the face contains horizontal glyph metrics. This */ + /* should be set for all common formats. */ + /* */ + /* FT_FACE_FLAG_VERTICAL :: */ + /* Indicates that the face contains vertical glyph metrics. This */ + /* is only available in some formats, not all of them. */ + /* */ + /* FT_FACE_FLAG_KERNING :: */ + /* Indicates that the face contains kerning information. If set, */ + /* the kerning distance can be retrieved through the function */ + /* @FT_Get_Kerning. Otherwise the function always return the */ + /* vector (0,0). Note that FreeType doesn't handle kerning data */ + /* from the `GPOS' table (as present in some OpenType fonts). */ + /* */ + /* FT_FACE_FLAG_FAST_GLYPHS :: */ + /* THIS FLAG IS DEPRECATED. DO NOT USE OR TEST IT. */ + /* */ + /* FT_FACE_FLAG_MULTIPLE_MASTERS :: */ + /* Indicates that the font contains multiple masters and is capable */ + /* of interpolating between them. See the multiple-masters */ + /* specific API for details. */ + /* */ + /* FT_FACE_FLAG_GLYPH_NAMES :: */ + /* Indicates that the font contains glyph names that can be */ + /* retrieved through @FT_Get_Glyph_Name. Note that some TrueType */ + /* fonts contain broken glyph name tables. Use the function */ + /* @FT_Has_PS_Glyph_Names when needed. */ + /* */ + /* FT_FACE_FLAG_EXTERNAL_STREAM :: */ + /* Used internally by FreeType to indicate that a face's stream was */ + /* provided by the client application and should not be destroyed */ + /* when @FT_Done_Face is called. Don't read or test this flag. */ + /* */ + /* FT_FACE_FLAG_HINTER :: */ + /* Set if the font driver has a hinting machine of its own. For */ + /* example, with TrueType fonts, it makes sense to use data from */ + /* the SFNT `gasp' table only if the native TrueType hinting engine */ + /* (with the bytecode interpreter) is available and active. */ + /* */ + /* FT_FACE_FLAG_CID_KEYED :: */ + /* Set if the font is CID-keyed. In that case, the font is not */ + /* accessed by glyph indices but by CID values. For subsetted */ + /* CID-keyed fonts this has the consequence that not all index */ + /* values are a valid argument to FT_Load_Glyph. Only the CID */ + /* values for which corresponding glyphs in the subsetted font */ + /* exist make FT_Load_Glyph return successfully; in all other cases */ + /* you get an `FT_Err_Invalid_Argument' error. */ + /* */ + /* Note that CID-keyed fonts which are in an SFNT wrapper don't */ + /* have this flag set since the glyphs are accessed in the normal */ + /* way (using contiguous indices); the `CID-ness' isn't visible to */ + /* the application. */ + /* */ + /* FT_FACE_FLAG_TRICKY :: */ + /* Set if the font is `tricky', this is, it always needs the */ + /* font format's native hinting engine to get a reasonable result. */ + /* A typical example is the Chinese font `mingli.ttf' which uses */ + /* TrueType bytecode instructions to move and scale all of its */ + /* subglyphs. */ + /* */ + /* It is not possible to autohint such fonts using */ + /* @FT_LOAD_FORCE_AUTOHINT; it will also ignore */ + /* @FT_LOAD_NO_HINTING. You have to set both FT_LOAD_NO_HINTING */ + /* and @FT_LOAD_NO_AUTOHINT to really disable hinting; however, you */ + /* probably never want this except for demonstration purposes. */ + /* */ + /* Currently, there are six TrueType fonts in the list of tricky */ + /* fonts; they are hard-coded in file `ttobjs.c'. */ + /* */ +#define FT_FACE_FLAG_SCALABLE ( 1L << 0 ) +#define FT_FACE_FLAG_FIXED_SIZES ( 1L << 1 ) +#define FT_FACE_FLAG_FIXED_WIDTH ( 1L << 2 ) +#define FT_FACE_FLAG_SFNT ( 1L << 3 ) +#define FT_FACE_FLAG_HORIZONTAL ( 1L << 4 ) +#define FT_FACE_FLAG_VERTICAL ( 1L << 5 ) +#define FT_FACE_FLAG_KERNING ( 1L << 6 ) +#define FT_FACE_FLAG_FAST_GLYPHS ( 1L << 7 ) +#define FT_FACE_FLAG_MULTIPLE_MASTERS ( 1L << 8 ) +#define FT_FACE_FLAG_GLYPH_NAMES ( 1L << 9 ) +#define FT_FACE_FLAG_EXTERNAL_STREAM ( 1L << 10 ) +#define FT_FACE_FLAG_HINTER ( 1L << 11 ) +#define FT_FACE_FLAG_CID_KEYED ( 1L << 12 ) +#define FT_FACE_FLAG_TRICKY ( 1L << 13 ) + + + /************************************************************************* + * + * @macro: + * FT_HAS_HORIZONTAL( face ) + * + * @description: + * A macro that returns true whenever a face object contains + * horizontal metrics (this is true for all font formats though). + * + * @also: + * @FT_HAS_VERTICAL can be used to check for vertical metrics. + * + */ +#define FT_HAS_HORIZONTAL( face ) \ + ( face->face_flags & FT_FACE_FLAG_HORIZONTAL ) + + + /************************************************************************* + * + * @macro: + * FT_HAS_VERTICAL( face ) + * + * @description: + * A macro that returns true whenever a face object contains vertical + * metrics. + * + */ +#define FT_HAS_VERTICAL( face ) \ + ( face->face_flags & FT_FACE_FLAG_VERTICAL ) + + + /************************************************************************* + * + * @macro: + * FT_HAS_KERNING( face ) + * + * @description: + * A macro that returns true whenever a face object contains kerning + * data that can be accessed with @FT_Get_Kerning. + * + */ +#define FT_HAS_KERNING( face ) \ + ( face->face_flags & FT_FACE_FLAG_KERNING ) + + + /************************************************************************* + * + * @macro: + * FT_IS_SCALABLE( face ) + * + * @description: + * A macro that returns true whenever a face object contains a scalable + * font face (true for TrueType, Type~1, Type~42, CID, OpenType/CFF, + * and PFR font formats. + * + */ +#define FT_IS_SCALABLE( face ) \ + ( face->face_flags & FT_FACE_FLAG_SCALABLE ) + + + /************************************************************************* + * + * @macro: + * FT_IS_SFNT( face ) + * + * @description: + * A macro that returns true whenever a face object contains a font + * whose format is based on the SFNT storage scheme. This usually + * means: TrueType fonts, OpenType fonts, as well as SFNT-based embedded + * bitmap fonts. + * + * If this macro is true, all functions defined in @FT_SFNT_NAMES_H and + * @FT_TRUETYPE_TABLES_H are available. + * + */ +#define FT_IS_SFNT( face ) \ + ( face->face_flags & FT_FACE_FLAG_SFNT ) + + + /************************************************************************* + * + * @macro: + * FT_IS_FIXED_WIDTH( face ) + * + * @description: + * A macro that returns true whenever a face object contains a font face + * that contains fixed-width (or `monospace', `fixed-pitch', etc.) + * glyphs. + * + */ +#define FT_IS_FIXED_WIDTH( face ) \ + ( face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ) + + + /************************************************************************* + * + * @macro: + * FT_HAS_FIXED_SIZES( face ) + * + * @description: + * A macro that returns true whenever a face object contains some + * embedded bitmaps. See the `available_sizes' field of the + * @FT_FaceRec structure. + * + */ +#define FT_HAS_FIXED_SIZES( face ) \ + ( face->face_flags & FT_FACE_FLAG_FIXED_SIZES ) + + + /************************************************************************* + * + * @macro: + * FT_HAS_FAST_GLYPHS( face ) + * + * @description: + * Deprecated. + * + */ +#define FT_HAS_FAST_GLYPHS( face ) 0 + + + /************************************************************************* + * + * @macro: + * FT_HAS_GLYPH_NAMES( face ) + * + * @description: + * A macro that returns true whenever a face object contains some glyph + * names that can be accessed through @FT_Get_Glyph_Name. + * + */ +#define FT_HAS_GLYPH_NAMES( face ) \ + ( face->face_flags & FT_FACE_FLAG_GLYPH_NAMES ) + + + /************************************************************************* + * + * @macro: + * FT_HAS_MULTIPLE_MASTERS( face ) + * + * @description: + * A macro that returns true whenever a face object contains some + * multiple masters. The functions provided by @FT_MULTIPLE_MASTERS_H + * are then available to choose the exact design you want. + * + */ +#define FT_HAS_MULTIPLE_MASTERS( face ) \ + ( face->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS ) + + + /************************************************************************* + * + * @macro: + * FT_IS_CID_KEYED( face ) + * + * @description: + * A macro that returns true whenever a face object contains a CID-keyed + * font. See the discussion of @FT_FACE_FLAG_CID_KEYED for more + * details. + * + * If this macro is true, all functions defined in @FT_CID_H are + * available. + * + */ +#define FT_IS_CID_KEYED( face ) \ + ( face->face_flags & FT_FACE_FLAG_CID_KEYED ) + + + /************************************************************************* + * + * @macro: + * FT_IS_TRICKY( face ) + * + * @description: + * A macro that returns true whenever a face represents a `tricky' font. + * See the discussion of @FT_FACE_FLAG_TRICKY for more details. + * + */ +#define FT_IS_TRICKY( face ) \ + ( face->face_flags & FT_FACE_FLAG_TRICKY ) + + + /*************************************************************************/ + /* */ + /* <Const> */ + /* FT_STYLE_FLAG_XXX */ + /* */ + /* <Description> */ + /* A list of bit-flags used to indicate the style of a given face. */ + /* These are used in the `style_flags' field of @FT_FaceRec. */ + /* */ + /* <Values> */ + /* FT_STYLE_FLAG_ITALIC :: */ + /* Indicates that a given face style is italic or oblique. */ + /* */ + /* FT_STYLE_FLAG_BOLD :: */ + /* Indicates that a given face is bold. */ + /* */ + /* <Note> */ + /* The style information as provided by FreeType is very basic. More */ + /* details are beyond the scope and should be done on a higher level */ + /* (for example, by analyzing various fields of the `OS/2' table in */ + /* SFNT based fonts). */ + /* */ +#define FT_STYLE_FLAG_ITALIC ( 1 << 0 ) +#define FT_STYLE_FLAG_BOLD ( 1 << 1 ) + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_Size_Internal */ + /* */ + /* <Description> */ + /* An opaque handle to an `FT_Size_InternalRec' structure, used to */ + /* model private data of a given @FT_Size object. */ + /* */ + typedef struct FT_Size_InternalRec_* FT_Size_Internal; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_Size_Metrics */ + /* */ + /* <Description> */ + /* The size metrics structure gives the metrics of a size object. */ + /* */ + /* <Fields> */ + /* x_ppem :: The width of the scaled EM square in pixels, hence */ + /* the term `ppem' (pixels per EM). It is also */ + /* referred to as `nominal width'. */ + /* */ + /* y_ppem :: The height of the scaled EM square in pixels, */ + /* hence the term `ppem' (pixels per EM). It is also */ + /* referred to as `nominal height'. */ + /* */ + /* x_scale :: A 16.16 fractional scaling value used to convert */ + /* horizontal metrics from font units to 26.6 */ + /* fractional pixels. Only relevant for scalable */ + /* font formats. */ + /* */ + /* y_scale :: A 16.16 fractional scaling value used to convert */ + /* vertical metrics from font units to 26.6 */ + /* fractional pixels. Only relevant for scalable */ + /* font formats. */ + /* */ + /* ascender :: The ascender in 26.6 fractional pixels. See */ + /* @FT_FaceRec for the details. */ + /* */ + /* descender :: The descender in 26.6 fractional pixels. See */ + /* @FT_FaceRec for the details. */ + /* */ + /* height :: The height in 26.6 fractional pixels. See */ + /* @FT_FaceRec for the details. */ + /* */ + /* max_advance :: The maximal advance width in 26.6 fractional */ + /* pixels. See @FT_FaceRec for the details. */ + /* */ + /* <Note> */ + /* The scaling values, if relevant, are determined first during a */ + /* size changing operation. The remaining fields are then set by the */ + /* driver. For scalable formats, they are usually set to scaled */ + /* values of the corresponding fields in @FT_FaceRec. */ + /* */ + /* Note that due to glyph hinting, these values might not be exact */ + /* for certain fonts. Thus they must be treated as unreliable */ + /* with an error margin of at least one pixel! */ + /* */ + /* Indeed, the only way to get the exact metrics is to render _all_ */ + /* glyphs. As this would be a definite performance hit, it is up to */ + /* client applications to perform such computations. */ + /* */ + /* The FT_Size_Metrics structure is valid for bitmap fonts also. */ + /* */ + typedef struct FT_Size_Metrics_ + { + FT_UShort x_ppem; /* horizontal pixels per EM */ + FT_UShort y_ppem; /* vertical pixels per EM */ + + FT_Fixed x_scale; /* scaling values used to convert font */ + FT_Fixed y_scale; /* units to 26.6 fractional pixels */ + + FT_Pos ascender; /* ascender in 26.6 frac. pixels */ + FT_Pos descender; /* descender in 26.6 frac. pixels */ + FT_Pos height; /* text height in 26.6 frac. pixels */ + FT_Pos max_advance; /* max horizontal advance, in 26.6 pixels */ + + } FT_Size_Metrics; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_SizeRec */ + /* */ + /* <Description> */ + /* FreeType root size class structure. A size object models a face */ + /* object at a given size. */ + /* */ + /* <Fields> */ + /* face :: Handle to the parent face object. */ + /* */ + /* generic :: A typeless pointer, which is unused by the FreeType */ + /* library or any of its drivers. It can be used by */ + /* client applications to link their own data to each size */ + /* object. */ + /* */ + /* metrics :: Metrics for this size object. This field is read-only. */ + /* */ + typedef struct FT_SizeRec_ + { + FT_Face face; /* parent face object */ + FT_Generic generic; /* generic pointer for client uses */ + FT_Size_Metrics metrics; /* size metrics */ + FT_Size_Internal internal; + + } FT_SizeRec; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_SubGlyph */ + /* */ + /* <Description> */ + /* The subglyph structure is an internal object used to describe */ + /* subglyphs (for example, in the case of composites). */ + /* */ + /* <Note> */ + /* The subglyph implementation is not part of the high-level API, */ + /* hence the forward structure declaration. */ + /* */ + /* You can however retrieve subglyph information with */ + /* @FT_Get_SubGlyph_Info. */ + /* */ + typedef struct FT_SubGlyphRec_* FT_SubGlyph; + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_Slot_Internal */ + /* */ + /* <Description> */ + /* An opaque handle to an `FT_Slot_InternalRec' structure, used to */ + /* model private data of a given @FT_GlyphSlot object. */ + /* */ + typedef struct FT_Slot_InternalRec_* FT_Slot_Internal; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_GlyphSlotRec */ + /* */ + /* <Description> */ + /* FreeType root glyph slot class structure. A glyph slot is a */ + /* container where individual glyphs can be loaded, be they in */ + /* outline or bitmap format. */ + /* */ + /* <Fields> */ + /* library :: A handle to the FreeType library instance */ + /* this slot belongs to. */ + /* */ + /* face :: A handle to the parent face object. */ + /* */ + /* next :: In some cases (like some font tools), several */ + /* glyph slots per face object can be a good */ + /* thing. As this is rare, the glyph slots are */ + /* listed through a direct, single-linked list */ + /* using its `next' field. */ + /* */ + /* generic :: A typeless pointer which is unused by the */ + /* FreeType library or any of its drivers. It */ + /* can be used by client applications to link */ + /* their own data to each glyph slot object. */ + /* */ + /* metrics :: The metrics of the last loaded glyph in the */ + /* slot. The returned values depend on the last */ + /* load flags (see the @FT_Load_Glyph API */ + /* function) and can be expressed either in 26.6 */ + /* fractional pixels or font units. */ + /* */ + /* Note that even when the glyph image is */ + /* transformed, the metrics are not. */ + /* */ + /* linearHoriAdvance :: The advance width of the unhinted glyph. */ + /* Its value is expressed in 16.16 fractional */ + /* pixels, unless @FT_LOAD_LINEAR_DESIGN is set */ + /* when loading the glyph. This field can be */ + /* important to perform correct WYSIWYG layout. */ + /* Only relevant for outline glyphs. */ + /* */ + /* linearVertAdvance :: The advance height of the unhinted glyph. */ + /* Its value is expressed in 16.16 fractional */ + /* pixels, unless @FT_LOAD_LINEAR_DESIGN is set */ + /* when loading the glyph. This field can be */ + /* important to perform correct WYSIWYG layout. */ + /* Only relevant for outline glyphs. */ + /* */ + /* advance :: This shorthand is, depending on */ + /* @FT_LOAD_IGNORE_TRANSFORM, the transformed */ + /* advance width for the glyph (in 26.6 */ + /* fractional pixel format). As specified with */ + /* @FT_LOAD_VERTICAL_LAYOUT, it uses either the */ + /* `horiAdvance' or the `vertAdvance' value of */ + /* `metrics' field. */ + /* */ + /* format :: This field indicates the format of the image */ + /* contained in the glyph slot. Typically */ + /* @FT_GLYPH_FORMAT_BITMAP, */ + /* @FT_GLYPH_FORMAT_OUTLINE, or */ + /* @FT_GLYPH_FORMAT_COMPOSITE, but others are */ + /* possible. */ + /* */ + /* bitmap :: This field is used as a bitmap descriptor */ + /* when the slot format is */ + /* @FT_GLYPH_FORMAT_BITMAP. Note that the */ + /* address and content of the bitmap buffer can */ + /* change between calls of @FT_Load_Glyph and a */ + /* few other functions. */ + /* */ + /* bitmap_left :: This is the bitmap's left bearing expressed */ + /* in integer pixels. Of course, this is only */ + /* valid if the format is */ + /* @FT_GLYPH_FORMAT_BITMAP. */ + /* */ + /* bitmap_top :: This is the bitmap's top bearing expressed in */ + /* integer pixels. Remember that this is the */ + /* distance from the baseline to the top-most */ + /* glyph scanline, upwards y~coordinates being */ + /* *positive*. */ + /* */ + /* outline :: The outline descriptor for the current glyph */ + /* image if its format is */ + /* @FT_GLYPH_FORMAT_OUTLINE. Once a glyph is */ + /* loaded, `outline' can be transformed, */ + /* distorted, embolded, etc. However, it must */ + /* not be freed. */ + /* */ + /* num_subglyphs :: The number of subglyphs in a composite glyph. */ + /* This field is only valid for the composite */ + /* glyph format that should normally only be */ + /* loaded with the @FT_LOAD_NO_RECURSE flag. */ + /* For now this is internal to FreeType. */ + /* */ + /* subglyphs :: An array of subglyph descriptors for */ + /* composite glyphs. There are `num_subglyphs' */ + /* elements in there. Currently internal to */ + /* FreeType. */ + /* */ + /* control_data :: Certain font drivers can also return the */ + /* control data for a given glyph image (e.g. */ + /* TrueType bytecode, Type~1 charstrings, etc.). */ + /* This field is a pointer to such data. */ + /* */ + /* control_len :: This is the length in bytes of the control */ + /* data. */ + /* */ + /* other :: Really wicked formats can use this pointer to */ + /* present their own glyph image to client */ + /* applications. Note that the application */ + /* needs to know about the image format. */ + /* */ + /* lsb_delta :: The difference between hinted and unhinted */ + /* left side bearing while autohinting is */ + /* active. Zero otherwise. */ + /* */ + /* rsb_delta :: The difference between hinted and unhinted */ + /* right side bearing while autohinting is */ + /* active. Zero otherwise. */ + /* */ + /* <Note> */ + /* If @FT_Load_Glyph is called with default flags (see */ + /* @FT_LOAD_DEFAULT) the glyph image is loaded in the glyph slot in */ + /* its native format (e.g., an outline glyph for TrueType and Type~1 */ + /* formats). */ + /* */ + /* This image can later be converted into a bitmap by calling */ + /* @FT_Render_Glyph. This function finds the current renderer for */ + /* the native image's format, then invokes it. */ + /* */ + /* The renderer is in charge of transforming the native image through */ + /* the slot's face transformation fields, then converting it into a */ + /* bitmap that is returned in `slot->bitmap'. */ + /* */ + /* Note that `slot->bitmap_left' and `slot->bitmap_top' are also used */ + /* to specify the position of the bitmap relative to the current pen */ + /* position (e.g., coordinates (0,0) on the baseline). Of course, */ + /* `slot->format' is also changed to @FT_GLYPH_FORMAT_BITMAP. */ + /* */ + /* <Note> */ + /* Here a small pseudo code fragment which shows how to use */ + /* `lsb_delta' and `rsb_delta': */ + /* */ + /* { */ + /* FT_Pos origin_x = 0; */ + /* FT_Pos prev_rsb_delta = 0; */ + /* */ + /* */ + /* for all glyphs do */ + /* <compute kern between current and previous glyph and add it to */ + /* `origin_x'> */ + /* */ + /* <load glyph with `FT_Load_Glyph'> */ + /* */ + /* if ( prev_rsb_delta - face->glyph->lsb_delta >= 32 ) */ + /* origin_x -= 64; */ + /* else if ( prev_rsb_delta - face->glyph->lsb_delta < -32 ) */ + /* origin_x += 64; */ + /* */ + /* prev_rsb_delta = face->glyph->rsb_delta; */ + /* */ + /* <save glyph image, or render glyph, or ...> */ + /* */ + /* origin_x += face->glyph->advance.x; */ + /* endfor */ + /* } */ + /* */ + typedef struct FT_GlyphSlotRec_ + { + FT_Library library; + FT_Face face; + FT_GlyphSlot next; + FT_UInt reserved; /* retained for binary compatibility */ + FT_Generic generic; + + FT_Glyph_Metrics metrics; + FT_Fixed linearHoriAdvance; + FT_Fixed linearVertAdvance; + FT_Vector advance; + + FT_Glyph_Format format; + + FT_Bitmap bitmap; + FT_Int bitmap_left; + FT_Int bitmap_top; + + FT_Outline outline; + + FT_UInt num_subglyphs; + FT_SubGlyph subglyphs; + + void* control_data; + long control_len; + + FT_Pos lsb_delta; + FT_Pos rsb_delta; + + void* other; + + FT_Slot_Internal internal; + + } FT_GlyphSlotRec; + + + /*************************************************************************/ + /*************************************************************************/ + /* */ + /* F U N C T I O N S */ + /* */ + /*************************************************************************/ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Init_FreeType */ + /* */ + /* <Description> */ + /* Initialize a new FreeType library object. The set of modules */ + /* that are registered by this function is determined at build time. */ + /* */ + /* <Output> */ + /* alibrary :: A handle to a new library object. */ + /* */ + /* <Return> */ + /* FreeType error code. 0~means success. */ + /* */ + /* <Note> */ + /* In case you want to provide your own memory allocating routines, */ + /* use @FT_New_Library instead, followed by a call to */ + /* @FT_Add_Default_Modules (or a series of calls to @FT_Add_Module). */ + /* */ + FT_EXPORT( FT_Error ) + FT_Init_FreeType( FT_Library *alibrary ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Done_FreeType */ + /* */ + /* <Description> */ + /* Destroy a given FreeType library object and all of its children, */ + /* including resources, drivers, faces, sizes, etc. */ + /* */ + /* <Input> */ + /* library :: A handle to the target library object. */ + /* */ + /* <Return> */ + /* FreeType error code. 0~means success. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Done_FreeType( FT_Library library ); + + + /*************************************************************************/ + /* */ + /* <Enum> */ + /* FT_OPEN_XXX */ + /* */ + /* <Description> */ + /* A list of bit-field constants used within the `flags' field of the */ + /* @FT_Open_Args structure. */ + /* */ + /* <Values> */ + /* FT_OPEN_MEMORY :: This is a memory-based stream. */ + /* */ + /* FT_OPEN_STREAM :: Copy the stream from the `stream' field. */ + /* */ + /* FT_OPEN_PATHNAME :: Create a new input stream from a C~path */ + /* name. */ + /* */ + /* FT_OPEN_DRIVER :: Use the `driver' field. */ + /* */ + /* FT_OPEN_PARAMS :: Use the `num_params' and `params' fields. */ + /* */ + /* ft_open_memory :: Deprecated; use @FT_OPEN_MEMORY instead. */ + /* */ + /* ft_open_stream :: Deprecated; use @FT_OPEN_STREAM instead. */ + /* */ + /* ft_open_pathname :: Deprecated; use @FT_OPEN_PATHNAME instead. */ + /* */ + /* ft_open_driver :: Deprecated; use @FT_OPEN_DRIVER instead. */ + /* */ + /* ft_open_params :: Deprecated; use @FT_OPEN_PARAMS instead. */ + /* */ + /* <Note> */ + /* The `FT_OPEN_MEMORY', `FT_OPEN_STREAM', and `FT_OPEN_PATHNAME' */ + /* flags are mutually exclusive. */ + /* */ +#define FT_OPEN_MEMORY 0x1 +#define FT_OPEN_STREAM 0x2 +#define FT_OPEN_PATHNAME 0x4 +#define FT_OPEN_DRIVER 0x8 +#define FT_OPEN_PARAMS 0x10 + +#define ft_open_memory FT_OPEN_MEMORY /* deprecated */ +#define ft_open_stream FT_OPEN_STREAM /* deprecated */ +#define ft_open_pathname FT_OPEN_PATHNAME /* deprecated */ +#define ft_open_driver FT_OPEN_DRIVER /* deprecated */ +#define ft_open_params FT_OPEN_PARAMS /* deprecated */ + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_Parameter */ + /* */ + /* <Description> */ + /* A simple structure used to pass more or less generic parameters to */ + /* @FT_Open_Face. */ + /* */ + /* <Fields> */ + /* tag :: A four-byte identification tag. */ + /* */ + /* data :: A pointer to the parameter data. */ + /* */ + /* <Note> */ + /* The ID and function of parameters are driver-specific. See the */ + /* various FT_PARAM_TAG_XXX flags for more information. */ + /* */ + typedef struct FT_Parameter_ + { + FT_ULong tag; + FT_Pointer data; + + } FT_Parameter; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_Open_Args */ + /* */ + /* <Description> */ + /* A structure used to indicate how to open a new font file or */ + /* stream. A pointer to such a structure can be used as a parameter */ + /* for the functions @FT_Open_Face and @FT_Attach_Stream. */ + /* */ + /* <Fields> */ + /* flags :: A set of bit flags indicating how to use the */ + /* structure. */ + /* */ + /* memory_base :: The first byte of the file in memory. */ + /* */ + /* memory_size :: The size in bytes of the file in memory. */ + /* */ + /* pathname :: A pointer to an 8-bit file pathname. */ + /* */ + /* stream :: A handle to a source stream object. */ + /* */ + /* driver :: This field is exclusively used by @FT_Open_Face; */ + /* it simply specifies the font driver to use to open */ + /* the face. If set to~0, FreeType tries to load the */ + /* face with each one of the drivers in its list. */ + /* */ + /* num_params :: The number of extra parameters. */ + /* */ + /* params :: Extra parameters passed to the font driver when */ + /* opening a new face. */ + /* */ + /* <Note> */ + /* The stream type is determined by the contents of `flags' which */ + /* are tested in the following order by @FT_Open_Face: */ + /* */ + /* If the `FT_OPEN_MEMORY' bit is set, assume that this is a */ + /* memory file of `memory_size' bytes, located at `memory_address'. */ + /* The data are are not copied, and the client is responsible for */ + /* releasing and destroying them _after_ the corresponding call to */ + /* @FT_Done_Face. */ + /* */ + /* Otherwise, if the `FT_OPEN_STREAM' bit is set, assume that a */ + /* custom input stream `stream' is used. */ + /* */ + /* Otherwise, if the `FT_OPEN_PATHNAME' bit is set, assume that this */ + /* is a normal file and use `pathname' to open it. */ + /* */ + /* If the `FT_OPEN_DRIVER' bit is set, @FT_Open_Face only tries to */ + /* open the file with the driver whose handler is in `driver'. */ + /* */ + /* If the `FT_OPEN_PARAMS' bit is set, the parameters given by */ + /* `num_params' and `params' is used. They are ignored otherwise. */ + /* */ + /* Ideally, both the `pathname' and `params' fields should be tagged */ + /* as `const'; this is missing for API backwards compatibility. In */ + /* other words, applications should treat them as read-only. */ + /* */ + typedef struct FT_Open_Args_ + { + FT_UInt flags; + const FT_Byte* memory_base; + FT_Long memory_size; + FT_String* pathname; + FT_Stream stream; + FT_Module driver; + FT_Int num_params; + FT_Parameter* params; + + } FT_Open_Args; + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_New_Face */ + /* */ + /* <Description> */ + /* This function calls @FT_Open_Face to open a font by its pathname. */ + /* */ + /* <InOut> */ + /* library :: A handle to the library resource. */ + /* */ + /* <Input> */ + /* pathname :: A path to the font file. */ + /* */ + /* face_index :: The index of the face within the font. The first */ + /* face has index~0. */ + /* */ + /* <Output> */ + /* aface :: A handle to a new face object. If `face_index' is */ + /* greater than or equal to zero, it must be non-NULL. */ + /* See @FT_Open_Face for more details. */ + /* */ + /* <Return> */ + /* FreeType error code. 0~means success. */ + /* */ + FT_EXPORT( FT_Error ) + FT_New_Face( FT_Library library, + const char* filepathname, + FT_Long face_index, + FT_Face *aface ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_New_Memory_Face */ + /* */ + /* <Description> */ + /* This function calls @FT_Open_Face to open a font which has been */ + /* loaded into memory. */ + /* */ + /* <InOut> */ + /* library :: A handle to the library resource. */ + /* */ + /* <Input> */ + /* file_base :: A pointer to the beginning of the font data. */ + /* */ + /* file_size :: The size of the memory chunk used by the font data. */ + /* */ + /* face_index :: The index of the face within the font. The first */ + /* face has index~0. */ + /* */ + /* <Output> */ + /* aface :: A handle to a new face object. If `face_index' is */ + /* greater than or equal to zero, it must be non-NULL. */ + /* See @FT_Open_Face for more details. */ + /* */ + /* <Return> */ + /* FreeType error code. 0~means success. */ + /* */ + /* <Note> */ + /* You must not deallocate the memory before calling @FT_Done_Face. */ + /* */ + FT_EXPORT( FT_Error ) + FT_New_Memory_Face( FT_Library library, + const FT_Byte* file_base, + FT_Long file_size, + FT_Long face_index, + FT_Face *aface ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Open_Face */ + /* */ + /* <Description> */ + /* Create a face object from a given resource described by */ + /* @FT_Open_Args. */ + /* */ + /* <InOut> */ + /* library :: A handle to the library resource. */ + /* */ + /* <Input> */ + /* args :: A pointer to an `FT_Open_Args' structure which must */ + /* be filled by the caller. */ + /* */ + /* face_index :: The index of the face within the font. The first */ + /* face has index~0. */ + /* */ + /* <Output> */ + /* aface :: A handle to a new face object. If `face_index' is */ + /* greater than or equal to zero, it must be non-NULL. */ + /* See note below. */ + /* */ + /* <Return> */ + /* FreeType error code. 0~means success. */ + /* */ + /* <Note> */ + /* Unlike FreeType 1.x, this function automatically creates a glyph */ + /* slot for the face object which can be accessed directly through */ + /* `face->glyph'. */ + /* */ + /* FT_Open_Face can be used to quickly check whether the font */ + /* format of a given font resource is supported by FreeType. If the */ + /* `face_index' field is negative, the function's return value is~0 */ + /* if the font format is recognized, or non-zero otherwise; */ + /* the function returns a more or less empty face handle in `*aface' */ + /* (if `aface' isn't NULL). The only useful field in this special */ + /* case is `face->num_faces' which gives the number of faces within */ + /* the font file. After examination, the returned @FT_Face structure */ + /* should be deallocated with a call to @FT_Done_Face. */ + /* */ + /* Each new face object created with this function also owns a */ + /* default @FT_Size object, accessible as `face->size'. */ + /* */ + /* See the discussion of reference counters in the description of */ + /* @FT_Reference_Face. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Open_Face( FT_Library library, + const FT_Open_Args* args, + FT_Long face_index, + FT_Face *aface ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Attach_File */ + /* */ + /* <Description> */ + /* This function calls @FT_Attach_Stream to attach a file. */ + /* */ + /* <InOut> */ + /* face :: The target face object. */ + /* */ + /* <Input> */ + /* filepathname :: The pathname. */ + /* */ + /* <Return> */ + /* FreeType error code. 0~means success. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Attach_File( FT_Face face, + const char* filepathname ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Attach_Stream */ + /* */ + /* <Description> */ + /* `Attach' data to a face object. Normally, this is used to read */ + /* additional information for the face object. For example, you can */ + /* attach an AFM file that comes with a Type~1 font to get the */ + /* kerning values and other metrics. */ + /* */ + /* <InOut> */ + /* face :: The target face object. */ + /* */ + /* <Input> */ + /* parameters :: A pointer to @FT_Open_Args which must be filled by */ + /* the caller. */ + /* */ + /* <Return> */ + /* FreeType error code. 0~means success. */ + /* */ + /* <Note> */ + /* The meaning of the `attach' (i.e., what really happens when the */ + /* new file is read) is not fixed by FreeType itself. It really */ + /* depends on the font format (and thus the font driver). */ + /* */ + /* Client applications are expected to know what they are doing */ + /* when invoking this function. Most drivers simply do not implement */ + /* file attachments. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Attach_Stream( FT_Face face, + FT_Open_Args* parameters ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Reference_Face */ + /* */ + /* <Description> */ + /* A counter gets initialized to~1 at the time an @FT_Face structure */ + /* is created. This function increments the counter. @FT_Done_Face */ + /* then only destroys a face if the counter is~1, otherwise it simply */ + /* decrements the counter. */ + /* */ + /* This function helps in managing life-cycles of structures which */ + /* reference @FT_Face objects. */ + /* */ + /* <Input> */ + /* face :: A handle to a target face object. */ + /* */ + /* <Return> */ + /* FreeType error code. 0~means success. */ + /* */ + /* <Since> */ + /* 2.4.2 */ + /* */ + FT_EXPORT( FT_Error ) + FT_Reference_Face( FT_Face face ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Done_Face */ + /* */ + /* <Description> */ + /* Discard a given face object, as well as all of its child slots and */ + /* sizes. */ + /* */ + /* <Input> */ + /* face :: A handle to a target face object. */ + /* */ + /* <Return> */ + /* FreeType error code. 0~means success. */ + /* */ + /* <Note> */ + /* See the discussion of reference counters in the description of */ + /* @FT_Reference_Face. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Done_Face( FT_Face face ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Select_Size */ + /* */ + /* <Description> */ + /* Select a bitmap strike. */ + /* */ + /* <InOut> */ + /* face :: A handle to a target face object. */ + /* */ + /* <Input> */ + /* strike_index :: The index of the bitmap strike in the */ + /* `available_sizes' field of @FT_FaceRec structure. */ + /* */ + /* <Return> */ + /* FreeType error code. 0~means success. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Select_Size( FT_Face face, + FT_Int strike_index ); + + + /*************************************************************************/ + /* */ + /* <Enum> */ + /* FT_Size_Request_Type */ + /* */ + /* <Description> */ + /* An enumeration type that lists the supported size request types. */ + /* */ + /* <Values> */ + /* FT_SIZE_REQUEST_TYPE_NOMINAL :: */ + /* The nominal size. The `units_per_EM' field of @FT_FaceRec is */ + /* used to determine both scaling values. */ + /* */ + /* FT_SIZE_REQUEST_TYPE_REAL_DIM :: */ + /* The real dimension. The sum of the the `Ascender' and (minus */ + /* of) the `Descender' fields of @FT_FaceRec are used to determine */ + /* both scaling values. */ + /* */ + /* FT_SIZE_REQUEST_TYPE_BBOX :: */ + /* The font bounding box. The width and height of the `bbox' field */ + /* of @FT_FaceRec are used to determine the horizontal and vertical */ + /* scaling value, respectively. */ + /* */ + /* FT_SIZE_REQUEST_TYPE_CELL :: */ + /* The `max_advance_width' field of @FT_FaceRec is used to */ + /* determine the horizontal scaling value; the vertical scaling */ + /* value is determined the same way as */ + /* @FT_SIZE_REQUEST_TYPE_REAL_DIM does. Finally, both scaling */ + /* values are set to the smaller one. This type is useful if you */ + /* want to specify the font size for, say, a window of a given */ + /* dimension and 80x24 cells. */ + /* */ + /* FT_SIZE_REQUEST_TYPE_SCALES :: */ + /* Specify the scaling values directly. */ + /* */ + /* <Note> */ + /* The above descriptions only apply to scalable formats. For bitmap */ + /* formats, the behaviour is up to the driver. */ + /* */ + /* See the note section of @FT_Size_Metrics if you wonder how size */ + /* requesting relates to scaling values. */ + /* */ + typedef enum FT_Size_Request_Type_ + { + FT_SIZE_REQUEST_TYPE_NOMINAL, + FT_SIZE_REQUEST_TYPE_REAL_DIM, + FT_SIZE_REQUEST_TYPE_BBOX, + FT_SIZE_REQUEST_TYPE_CELL, + FT_SIZE_REQUEST_TYPE_SCALES, + + FT_SIZE_REQUEST_TYPE_MAX + + } FT_Size_Request_Type; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_Size_RequestRec */ + /* */ + /* <Description> */ + /* A structure used to model a size request. */ + /* */ + /* <Fields> */ + /* type :: See @FT_Size_Request_Type. */ + /* */ + /* width :: The desired width. */ + /* */ + /* height :: The desired height. */ + /* */ + /* horiResolution :: The horizontal resolution. If set to zero, */ + /* `width' is treated as a 26.6 fractional pixel */ + /* value. */ + /* */ + /* vertResolution :: The vertical resolution. If set to zero, */ + /* `height' is treated as a 26.6 fractional pixel */ + /* value. */ + /* */ + /* <Note> */ + /* If `width' is zero, then the horizontal scaling value is set equal */ + /* to the vertical scaling value, and vice versa. */ + /* */ + typedef struct FT_Size_RequestRec_ + { + FT_Size_Request_Type type; + FT_Long width; + FT_Long height; + FT_UInt horiResolution; + FT_UInt vertResolution; + + } FT_Size_RequestRec; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_Size_Request */ + /* */ + /* <Description> */ + /* A handle to a size request structure. */ + /* */ + typedef struct FT_Size_RequestRec_ *FT_Size_Request; + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Request_Size */ + /* */ + /* <Description> */ + /* Resize the scale of the active @FT_Size object in a face. */ + /* */ + /* <InOut> */ + /* face :: A handle to a target face object. */ + /* */ + /* <Input> */ + /* req :: A pointer to a @FT_Size_RequestRec. */ + /* */ + /* <Return> */ + /* FreeType error code. 0~means success. */ + /* */ + /* <Note> */ + /* Although drivers may select the bitmap strike matching the */ + /* request, you should not rely on this if you intend to select a */ + /* particular bitmap strike. Use @FT_Select_Size instead in that */ + /* case. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Request_Size( FT_Face face, + FT_Size_Request req ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Set_Char_Size */ + /* */ + /* <Description> */ + /* This function calls @FT_Request_Size to request the nominal size */ + /* (in points). */ + /* */ + /* <InOut> */ + /* face :: A handle to a target face object. */ + /* */ + /* <Input> */ + /* char_width :: The nominal width, in 26.6 fractional points. */ + /* */ + /* char_height :: The nominal height, in 26.6 fractional points. */ + /* */ + /* horz_resolution :: The horizontal resolution in dpi. */ + /* */ + /* vert_resolution :: The vertical resolution in dpi. */ + /* */ + /* <Return> */ + /* FreeType error code. 0~means success. */ + /* */ + /* <Note> */ + /* If either the character width or height is zero, it is set equal */ + /* to the other value. */ + /* */ + /* If either the horizontal or vertical resolution is zero, it is set */ + /* equal to the other value. */ + /* */ + /* A character width or height smaller than 1pt is set to 1pt; if */ + /* both resolution values are zero, they are set to 72dpi. */ + /* */ + /* Don't use this function if you are using the FreeType cache API. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Set_Char_Size( FT_Face face, + FT_F26Dot6 char_width, + FT_F26Dot6 char_height, + FT_UInt horz_resolution, + FT_UInt vert_resolution ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Set_Pixel_Sizes */ + /* */ + /* <Description> */ + /* This function calls @FT_Request_Size to request the nominal size */ + /* (in pixels). */ + /* */ + /* <InOut> */ + /* face :: A handle to the target face object. */ + /* */ + /* <Input> */ + /* pixel_width :: The nominal width, in pixels. */ + /* */ + /* pixel_height :: The nominal height, in pixels. */ + /* */ + /* <Return> */ + /* FreeType error code. 0~means success. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Set_Pixel_Sizes( FT_Face face, + FT_UInt pixel_width, + FT_UInt pixel_height ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Load_Glyph */ + /* */ + /* <Description> */ + /* A function used to load a single glyph into the glyph slot of a */ + /* face object. */ + /* */ + /* <InOut> */ + /* face :: A handle to the target face object where the glyph */ + /* is loaded. */ + /* */ + /* <Input> */ + /* glyph_index :: The index of the glyph in the font file. For */ + /* CID-keyed fonts (either in PS or in CFF format) */ + /* this argument specifies the CID value. */ + /* */ + /* load_flags :: A flag indicating what to load for this glyph. The */ + /* @FT_LOAD_XXX constants can be used to control the */ + /* glyph loading process (e.g., whether the outline */ + /* should be scaled, whether to load bitmaps or not, */ + /* whether to hint the outline, etc). */ + /* */ + /* <Return> */ + /* FreeType error code. 0~means success. */ + /* */ + /* <Note> */ + /* The loaded glyph may be transformed. See @FT_Set_Transform for */ + /* the details. */ + /* */ + /* For subsetted CID-keyed fonts, `FT_Err_Invalid_Argument' is */ + /* returned for invalid CID values (this is, for CID values which */ + /* don't have a corresponding glyph in the font). See the discussion */ + /* of the @FT_FACE_FLAG_CID_KEYED flag for more details. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Load_Glyph( FT_Face face, + FT_UInt glyph_index, + FT_Int32 load_flags ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Load_Char */ + /* */ + /* <Description> */ + /* A function used to load a single glyph into the glyph slot of a */ + /* face object, according to its character code. */ + /* */ + /* <InOut> */ + /* face :: A handle to a target face object where the glyph */ + /* is loaded. */ + /* */ + /* <Input> */ + /* char_code :: The glyph's character code, according to the */ + /* current charmap used in the face. */ + /* */ + /* load_flags :: A flag indicating what to load for this glyph. The */ + /* @FT_LOAD_XXX constants can be used to control the */ + /* glyph loading process (e.g., whether the outline */ + /* should be scaled, whether to load bitmaps or not, */ + /* whether to hint the outline, etc). */ + /* */ + /* <Return> */ + /* FreeType error code. 0~means success. */ + /* */ + /* <Note> */ + /* This function simply calls @FT_Get_Char_Index and @FT_Load_Glyph. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Load_Char( FT_Face face, + FT_ULong char_code, + FT_Int32 load_flags ); + + + /************************************************************************* + * + * @enum: + * FT_LOAD_XXX + * + * @description: + * A list of bit-field constants used with @FT_Load_Glyph to indicate + * what kind of operations to perform during glyph loading. + * + * @values: + * FT_LOAD_DEFAULT :: + * Corresponding to~0, this value is used as the default glyph load + * operation. In this case, the following happens: + * + * 1. FreeType looks for a bitmap for the glyph corresponding to the + * face's current size. If one is found, the function returns. + * The bitmap data can be accessed from the glyph slot (see note + * below). + * + * 2. If no embedded bitmap is searched or found, FreeType looks for a + * scalable outline. If one is found, it is loaded from the font + * file, scaled to device pixels, then `hinted' to the pixel grid + * in order to optimize it. The outline data can be accessed from + * the glyph slot (see note below). + * + * Note that by default, the glyph loader doesn't render outlines into + * bitmaps. The following flags are used to modify this default + * behaviour to more specific and useful cases. + * + * FT_LOAD_NO_SCALE :: + * Don't scale the outline glyph loaded, but keep it in font units. + * + * This flag implies @FT_LOAD_NO_HINTING and @FT_LOAD_NO_BITMAP, and + * unsets @FT_LOAD_RENDER. + * + * FT_LOAD_NO_HINTING :: + * Disable hinting. This generally generates `blurrier' bitmap glyph + * when the glyph is rendered in any of the anti-aliased modes. See + * also the note below. + * + * This flag is implied by @FT_LOAD_NO_SCALE. + * + * FT_LOAD_RENDER :: + * Call @FT_Render_Glyph after the glyph is loaded. By default, the + * glyph is rendered in @FT_RENDER_MODE_NORMAL mode. This can be + * overridden by @FT_LOAD_TARGET_XXX or @FT_LOAD_MONOCHROME. + * + * This flag is unset by @FT_LOAD_NO_SCALE. + * + * FT_LOAD_NO_BITMAP :: + * Ignore bitmap strikes when loading. Bitmap-only fonts ignore this + * flag. + * + * @FT_LOAD_NO_SCALE always sets this flag. + * + * FT_LOAD_VERTICAL_LAYOUT :: + * Load the glyph for vertical text layout. _Don't_ use it as it is + * problematic currently. + * + * FT_LOAD_FORCE_AUTOHINT :: + * Indicates that the auto-hinter is preferred over the font's native + * hinter. See also the note below. + * + * FT_LOAD_CROP_BITMAP :: + * Indicates that the font driver should crop the loaded bitmap glyph + * (i.e., remove all space around its black bits). Not all drivers + * implement this. + * + * FT_LOAD_PEDANTIC :: + * Indicates that the font driver should perform pedantic verifications + * during glyph loading. This is mostly used to detect broken glyphs + * in fonts. By default, FreeType tries to handle broken fonts also. + * + * FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH :: + * Indicates that the font driver should ignore the global advance + * width defined in the font. By default, that value is used as the + * advance width for all glyphs when the face has + * @FT_FACE_FLAG_FIXED_WIDTH set. + * + * This flag exists for historical reasons (to support buggy CJK + * fonts). + * + * FT_LOAD_NO_RECURSE :: + * This flag is only used internally. It merely indicates that the + * font driver should not load composite glyphs recursively. Instead, + * it should set the `num_subglyph' and `subglyphs' values of the + * glyph slot accordingly, and set `glyph->format' to + * @FT_GLYPH_FORMAT_COMPOSITE. + * + * The description of sub-glyphs is not available to client + * applications for now. + * + * This flag implies @FT_LOAD_NO_SCALE and @FT_LOAD_IGNORE_TRANSFORM. + * + * FT_LOAD_IGNORE_TRANSFORM :: + * Indicates that the transform matrix set by @FT_Set_Transform should + * be ignored. + * + * FT_LOAD_MONOCHROME :: + * This flag is used with @FT_LOAD_RENDER to indicate that you want to + * render an outline glyph to a 1-bit monochrome bitmap glyph, with + * 8~pixels packed into each byte of the bitmap data. + * + * Note that this has no effect on the hinting algorithm used. You + * should rather use @FT_LOAD_TARGET_MONO so that the + * monochrome-optimized hinting algorithm is used. + * + * FT_LOAD_LINEAR_DESIGN :: + * Indicates that the `linearHoriAdvance' and `linearVertAdvance' + * fields of @FT_GlyphSlotRec should be kept in font units. See + * @FT_GlyphSlotRec for details. + * + * FT_LOAD_NO_AUTOHINT :: + * Disable auto-hinter. See also the note below. + * + * @note: + * By default, hinting is enabled and the font's native hinter (see + * @FT_FACE_FLAG_HINTER) is preferred over the auto-hinter. You can + * disable hinting by setting @FT_LOAD_NO_HINTING or change the + * precedence by setting @FT_LOAD_FORCE_AUTOHINT. You can also set + * @FT_LOAD_NO_AUTOHINT in case you don't want the auto-hinter to be + * used at all. + * + * See the description of @FT_FACE_FLAG_TRICKY for a special exception + * (affecting only a handful of Asian fonts). + * + * Besides deciding which hinter to use, you can also decide which + * hinting algorithm to use. See @FT_LOAD_TARGET_XXX for details. + * + */ +#define FT_LOAD_DEFAULT 0x0 +#define FT_LOAD_NO_SCALE 0x1 +#define FT_LOAD_NO_HINTING 0x2 +#define FT_LOAD_RENDER 0x4 +#define FT_LOAD_NO_BITMAP 0x8 +#define FT_LOAD_VERTICAL_LAYOUT 0x10 +#define FT_LOAD_FORCE_AUTOHINT 0x20 +#define FT_LOAD_CROP_BITMAP 0x40 +#define FT_LOAD_PEDANTIC 0x80 +#define FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH 0x200 +#define FT_LOAD_NO_RECURSE 0x400 +#define FT_LOAD_IGNORE_TRANSFORM 0x800 +#define FT_LOAD_MONOCHROME 0x1000 +#define FT_LOAD_LINEAR_DESIGN 0x2000 +#define FT_LOAD_NO_AUTOHINT 0x8000U + + /* */ + + /* used internally only by certain font drivers! */ +#define FT_LOAD_ADVANCE_ONLY 0x100 +#define FT_LOAD_SBITS_ONLY 0x4000 + + + /************************************************************************** + * + * @enum: + * FT_LOAD_TARGET_XXX + * + * @description: + * A list of values that are used to select a specific hinting algorithm + * to use by the hinter. You should OR one of these values to your + * `load_flags' when calling @FT_Load_Glyph. + * + * Note that font's native hinters may ignore the hinting algorithm you + * have specified (e.g., the TrueType bytecode interpreter). You can set + * @FT_LOAD_FORCE_AUTOHINT to ensure that the auto-hinter is used. + * + * Also note that @FT_LOAD_TARGET_LIGHT is an exception, in that it + * always implies @FT_LOAD_FORCE_AUTOHINT. + * + * @values: + * FT_LOAD_TARGET_NORMAL :: + * This corresponds to the default hinting algorithm, optimized for + * standard gray-level rendering. For monochrome output, use + * @FT_LOAD_TARGET_MONO instead. + * + * FT_LOAD_TARGET_LIGHT :: + * A lighter hinting algorithm for non-monochrome modes. Many + * generated glyphs are more fuzzy but better resemble its original + * shape. A bit like rendering on Mac OS~X. + * + * As a special exception, this target implies @FT_LOAD_FORCE_AUTOHINT. + * + * FT_LOAD_TARGET_MONO :: + * Strong hinting algorithm that should only be used for monochrome + * output. The result is probably unpleasant if the glyph is rendered + * in non-monochrome modes. + * + * FT_LOAD_TARGET_LCD :: + * A variant of @FT_LOAD_TARGET_NORMAL optimized for horizontally + * decimated LCD displays. + * + * FT_LOAD_TARGET_LCD_V :: + * A variant of @FT_LOAD_TARGET_NORMAL optimized for vertically + * decimated LCD displays. + * + * @note: + * You should use only _one_ of the FT_LOAD_TARGET_XXX values in your + * `load_flags'. They can't be ORed. + * + * If @FT_LOAD_RENDER is also set, the glyph is rendered in the + * corresponding mode (i.e., the mode which matches the used algorithm + * best) unless @FT_LOAD_MONOCHROME is set. + * + * You can use a hinting algorithm that doesn't correspond to the same + * rendering mode. As an example, it is possible to use the `light' + * hinting algorithm and have the results rendered in horizontal LCD + * pixel mode, with code like + * + * { + * FT_Load_Glyph( face, glyph_index, + * load_flags | FT_LOAD_TARGET_LIGHT ); + * + * FT_Render_Glyph( face->glyph, FT_RENDER_MODE_LCD ); + * } + * + */ +#define FT_LOAD_TARGET_( x ) ( (FT_Int32)( (x) & 15 ) << 16 ) + +#define FT_LOAD_TARGET_NORMAL FT_LOAD_TARGET_( FT_RENDER_MODE_NORMAL ) +#define FT_LOAD_TARGET_LIGHT FT_LOAD_TARGET_( FT_RENDER_MODE_LIGHT ) +#define FT_LOAD_TARGET_MONO FT_LOAD_TARGET_( FT_RENDER_MODE_MONO ) +#define FT_LOAD_TARGET_LCD FT_LOAD_TARGET_( FT_RENDER_MODE_LCD ) +#define FT_LOAD_TARGET_LCD_V FT_LOAD_TARGET_( FT_RENDER_MODE_LCD_V ) + + + /************************************************************************** + * + * @macro: + * FT_LOAD_TARGET_MODE + * + * @description: + * Return the @FT_Render_Mode corresponding to a given + * @FT_LOAD_TARGET_XXX value. + * + */ +#define FT_LOAD_TARGET_MODE( x ) ( (FT_Render_Mode)( ( (x) >> 16 ) & 15 ) ) + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Set_Transform */ + /* */ + /* <Description> */ + /* A function used to set the transformation that is applied to glyph */ + /* images when they are loaded into a glyph slot through */ + /* @FT_Load_Glyph. */ + /* */ + /* <InOut> */ + /* face :: A handle to the source face object. */ + /* */ + /* <Input> */ + /* matrix :: A pointer to the transformation's 2x2 matrix. Use~0 for */ + /* the identity matrix. */ + /* delta :: A pointer to the translation vector. Use~0 for the null */ + /* vector. */ + /* */ + /* <Note> */ + /* The transformation is only applied to scalable image formats after */ + /* the glyph has been loaded. It means that hinting is unaltered by */ + /* the transformation and is performed on the character size given in */ + /* the last call to @FT_Set_Char_Size or @FT_Set_Pixel_Sizes. */ + /* */ + /* Note that this also transforms the `face.glyph.advance' field, but */ + /* *not* the values in `face.glyph.metrics'. */ + /* */ + FT_EXPORT( void ) + FT_Set_Transform( FT_Face face, + FT_Matrix* matrix, + FT_Vector* delta ); + + + /*************************************************************************/ + /* */ + /* <Enum> */ + /* FT_Render_Mode */ + /* */ + /* <Description> */ + /* An enumeration type that lists the render modes supported by */ + /* FreeType~2. Each mode corresponds to a specific type of scanline */ + /* conversion performed on the outline. */ + /* */ + /* For bitmap fonts and embedded bitmaps the `bitmap->pixel_mode' */ + /* field in the @FT_GlyphSlotRec structure gives the format of the */ + /* returned bitmap. */ + /* */ + /* All modes except @FT_RENDER_MODE_MONO use 256 levels of opacity. */ + /* */ + /* <Values> */ + /* FT_RENDER_MODE_NORMAL :: */ + /* This is the default render mode; it corresponds to 8-bit */ + /* anti-aliased bitmaps. */ + /* */ + /* FT_RENDER_MODE_LIGHT :: */ + /* This is equivalent to @FT_RENDER_MODE_NORMAL. It is only */ + /* defined as a separate value because render modes are also used */ + /* indirectly to define hinting algorithm selectors. See */ + /* @FT_LOAD_TARGET_XXX for details. */ + /* */ + /* FT_RENDER_MODE_MONO :: */ + /* This mode corresponds to 1-bit bitmaps (with 2~levels of */ + /* opacity). */ + /* */ + /* FT_RENDER_MODE_LCD :: */ + /* This mode corresponds to horizontal RGB and BGR sub-pixel */ + /* displays like LCD screens. It produces 8-bit bitmaps that are */ + /* 3~times the width of the original glyph outline in pixels, and */ + /* which use the @FT_PIXEL_MODE_LCD mode. */ + /* */ + /* FT_RENDER_MODE_LCD_V :: */ + /* This mode corresponds to vertical RGB and BGR sub-pixel displays */ + /* (like PDA screens, rotated LCD displays, etc.). It produces */ + /* 8-bit bitmaps that are 3~times the height of the original */ + /* glyph outline in pixels and use the @FT_PIXEL_MODE_LCD_V mode. */ + /* */ + /* <Note> */ + /* The LCD-optimized glyph bitmaps produced by FT_Render_Glyph can be */ + /* filtered to reduce color-fringes by using @FT_Library_SetLcdFilter */ + /* (not active in the default builds). It is up to the caller to */ + /* either call @FT_Library_SetLcdFilter (if available) or do the */ + /* filtering itself. */ + /* */ + /* The selected render mode only affects vector glyphs of a font. */ + /* Embedded bitmaps often have a different pixel mode like */ + /* @FT_PIXEL_MODE_MONO. You can use @FT_Bitmap_Convert to transform */ + /* them into 8-bit pixmaps. */ + /* */ + typedef enum FT_Render_Mode_ + { + FT_RENDER_MODE_NORMAL = 0, + FT_RENDER_MODE_LIGHT, + FT_RENDER_MODE_MONO, + FT_RENDER_MODE_LCD, + FT_RENDER_MODE_LCD_V, + + FT_RENDER_MODE_MAX + + } FT_Render_Mode; + + + /*************************************************************************/ + /* */ + /* <Enum> */ + /* ft_render_mode_xxx */ + /* */ + /* <Description> */ + /* These constants are deprecated. Use the corresponding */ + /* @FT_Render_Mode values instead. */ + /* */ + /* <Values> */ + /* ft_render_mode_normal :: see @FT_RENDER_MODE_NORMAL */ + /* ft_render_mode_mono :: see @FT_RENDER_MODE_MONO */ + /* */ +#define ft_render_mode_normal FT_RENDER_MODE_NORMAL +#define ft_render_mode_mono FT_RENDER_MODE_MONO + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Render_Glyph */ + /* */ + /* <Description> */ + /* Convert a given glyph image to a bitmap. It does so by inspecting */ + /* the glyph image format, finding the relevant renderer, and */ + /* invoking it. */ + /* */ + /* <InOut> */ + /* slot :: A handle to the glyph slot containing the image to */ + /* convert. */ + /* */ + /* <Input> */ + /* render_mode :: This is the render mode used to render the glyph */ + /* image into a bitmap. See @FT_Render_Mode for a */ + /* list of possible values. */ + /* */ + /* <Return> */ + /* FreeType error code. 0~means success. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Render_Glyph( FT_GlyphSlot slot, + FT_Render_Mode render_mode ); + + + /*************************************************************************/ + /* */ + /* <Enum> */ + /* FT_Kerning_Mode */ + /* */ + /* <Description> */ + /* An enumeration used to specify which kerning values to return in */ + /* @FT_Get_Kerning. */ + /* */ + /* <Values> */ + /* FT_KERNING_DEFAULT :: Return scaled and grid-fitted kerning */ + /* distances (value is~0). */ + /* */ + /* FT_KERNING_UNFITTED :: Return scaled but un-grid-fitted kerning */ + /* distances. */ + /* */ + /* FT_KERNING_UNSCALED :: Return the kerning vector in original font */ + /* units. */ + /* */ + typedef enum FT_Kerning_Mode_ + { + FT_KERNING_DEFAULT = 0, + FT_KERNING_UNFITTED, + FT_KERNING_UNSCALED + + } FT_Kerning_Mode; + + + /*************************************************************************/ + /* */ + /* <Const> */ + /* ft_kerning_default */ + /* */ + /* <Description> */ + /* This constant is deprecated. Please use @FT_KERNING_DEFAULT */ + /* instead. */ + /* */ +#define ft_kerning_default FT_KERNING_DEFAULT + + + /*************************************************************************/ + /* */ + /* <Const> */ + /* ft_kerning_unfitted */ + /* */ + /* <Description> */ + /* This constant is deprecated. Please use @FT_KERNING_UNFITTED */ + /* instead. */ + /* */ +#define ft_kerning_unfitted FT_KERNING_UNFITTED + + + /*************************************************************************/ + /* */ + /* <Const> */ + /* ft_kerning_unscaled */ + /* */ + /* <Description> */ + /* This constant is deprecated. Please use @FT_KERNING_UNSCALED */ + /* instead. */ + /* */ +#define ft_kerning_unscaled FT_KERNING_UNSCALED + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Get_Kerning */ + /* */ + /* <Description> */ + /* Return the kerning vector between two glyphs of a same face. */ + /* */ + /* <Input> */ + /* face :: A handle to a source face object. */ + /* */ + /* left_glyph :: The index of the left glyph in the kern pair. */ + /* */ + /* right_glyph :: The index of the right glyph in the kern pair. */ + /* */ + /* kern_mode :: See @FT_Kerning_Mode for more information. */ + /* Determines the scale and dimension of the returned */ + /* kerning vector. */ + /* */ + /* <Output> */ + /* akerning :: The kerning vector. This is either in font units */ + /* or in pixels (26.6 format) for scalable formats, */ + /* and in pixels for fixed-sizes formats. */ + /* */ + /* <Return> */ + /* FreeType error code. 0~means success. */ + /* */ + /* <Note> */ + /* Only horizontal layouts (left-to-right & right-to-left) are */ + /* supported by this method. Other layouts, or more sophisticated */ + /* kernings, are out of the scope of this API function -- they can be */ + /* implemented through format-specific interfaces. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Get_Kerning( FT_Face face, + FT_UInt left_glyph, + FT_UInt right_glyph, + FT_UInt kern_mode, + FT_Vector *akerning ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Get_Track_Kerning */ + /* */ + /* <Description> */ + /* Return the track kerning for a given face object at a given size. */ + /* */ + /* <Input> */ + /* face :: A handle to a source face object. */ + /* */ + /* point_size :: The point size in 16.16 fractional points. */ + /* */ + /* degree :: The degree of tightness. */ + /* */ + /* <Output> */ + /* akerning :: The kerning in 16.16 fractional points. */ + /* */ + /* <Return> */ + /* FreeType error code. 0~means success. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Get_Track_Kerning( FT_Face face, + FT_Fixed point_size, + FT_Int degree, + FT_Fixed* akerning ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Get_Glyph_Name */ + /* */ + /* <Description> */ + /* Retrieve the ASCII name of a given glyph in a face. This only */ + /* works for those faces where @FT_HAS_GLYPH_NAMES(face) returns~1. */ + /* */ + /* <Input> */ + /* face :: A handle to a source face object. */ + /* */ + /* glyph_index :: The glyph index. */ + /* */ + /* buffer_max :: The maximal number of bytes available in the */ + /* buffer. */ + /* */ + /* <Output> */ + /* buffer :: A pointer to a target buffer where the name is */ + /* copied to. */ + /* */ + /* <Return> */ + /* FreeType error code. 0~means success. */ + /* */ + /* <Note> */ + /* An error is returned if the face doesn't provide glyph names or if */ + /* the glyph index is invalid. In all cases of failure, the first */ + /* byte of `buffer' is set to~0 to indicate an empty name. */ + /* */ + /* The glyph name is truncated to fit within the buffer if it is too */ + /* long. The returned string is always zero-terminated. */ + /* */ + /* This function is not compiled within the library if the config */ + /* macro `FT_CONFIG_OPTION_NO_GLYPH_NAMES' is defined in */ + /* `include/freetype/config/ftoptions.h'. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Get_Glyph_Name( FT_Face face, + FT_UInt glyph_index, + FT_Pointer buffer, + FT_UInt buffer_max ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Get_Postscript_Name */ + /* */ + /* <Description> */ + /* Retrieve the ASCII PostScript name of a given face, if available. */ + /* This only works with PostScript and TrueType fonts. */ + /* */ + /* <Input> */ + /* face :: A handle to the source face object. */ + /* */ + /* <Return> */ + /* A pointer to the face's PostScript name. NULL if unavailable. */ + /* */ + /* <Note> */ + /* The returned pointer is owned by the face and is destroyed with */ + /* it. */ + /* */ + FT_EXPORT( const char* ) + FT_Get_Postscript_Name( FT_Face face ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Select_Charmap */ + /* */ + /* <Description> */ + /* Select a given charmap by its encoding tag (as listed in */ + /* `freetype.h'). */ + /* */ + /* <InOut> */ + /* face :: A handle to the source face object. */ + /* */ + /* <Input> */ + /* encoding :: A handle to the selected encoding. */ + /* */ + /* <Return> */ + /* FreeType error code. 0~means success. */ + /* */ + /* <Note> */ + /* This function returns an error if no charmap in the face */ + /* corresponds to the encoding queried here. */ + /* */ + /* Because many fonts contain more than a single cmap for Unicode */ + /* encoding, this function has some special code to select the one */ + /* which covers Unicode best (`best' in the sense that a UCS-4 cmap */ + /* is preferred to a UCS-2 cmap). It is thus preferable to */ + /* @FT_Set_Charmap in this case. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Select_Charmap( FT_Face face, + FT_Encoding encoding ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Set_Charmap */ + /* */ + /* <Description> */ + /* Select a given charmap for character code to glyph index mapping. */ + /* */ + /* <InOut> */ + /* face :: A handle to the source face object. */ + /* */ + /* <Input> */ + /* charmap :: A handle to the selected charmap. */ + /* */ + /* <Return> */ + /* FreeType error code. 0~means success. */ + /* */ + /* <Note> */ + /* This function returns an error if the charmap is not part of */ + /* the face (i.e., if it is not listed in the `face->charmaps' */ + /* table). */ + /* */ + /* It also fails if a type~14 charmap is selected. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Set_Charmap( FT_Face face, + FT_CharMap charmap ); + + + /************************************************************************* + * + * @function: + * FT_Get_Charmap_Index + * + * @description: + * Retrieve index of a given charmap. + * + * @input: + * charmap :: + * A handle to a charmap. + * + * @return: + * The index into the array of character maps within the face to which + * `charmap' belongs. If an error occurs, -1 is returned. + * + */ + FT_EXPORT( FT_Int ) + FT_Get_Charmap_Index( FT_CharMap charmap ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Get_Char_Index */ + /* */ + /* <Description> */ + /* Return the glyph index of a given character code. This function */ + /* uses a charmap object to do the mapping. */ + /* */ + /* <Input> */ + /* face :: A handle to the source face object. */ + /* */ + /* charcode :: The character code. */ + /* */ + /* <Return> */ + /* The glyph index. 0~means `undefined character code'. */ + /* */ + /* <Note> */ + /* If you use FreeType to manipulate the contents of font files */ + /* directly, be aware that the glyph index returned by this function */ + /* doesn't always correspond to the internal indices used within */ + /* the file. This is done to ensure that value~0 always corresponds */ + /* to the `missing glyph'. */ + /* */ + FT_EXPORT( FT_UInt ) + FT_Get_Char_Index( FT_Face face, + FT_ULong charcode ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Get_First_Char */ + /* */ + /* <Description> */ + /* This function is used to return the first character code in the */ + /* current charmap of a given face. It also returns the */ + /* corresponding glyph index. */ + /* */ + /* <Input> */ + /* face :: A handle to the source face object. */ + /* */ + /* <Output> */ + /* agindex :: Glyph index of first character code. 0~if charmap is */ + /* empty. */ + /* */ + /* <Return> */ + /* The charmap's first character code. */ + /* */ + /* <Note> */ + /* You should use this function with @FT_Get_Next_Char to be able to */ + /* parse all character codes available in a given charmap. The code */ + /* should look like this: */ + /* */ + /* { */ + /* FT_ULong charcode; */ + /* FT_UInt gindex; */ + /* */ + /* */ + /* charcode = FT_Get_First_Char( face, &gindex ); */ + /* while ( gindex != 0 ) */ + /* { */ + /* ... do something with (charcode,gindex) pair ... */ + /* */ + /* charcode = FT_Get_Next_Char( face, charcode, &gindex ); */ + /* } */ + /* } */ + /* */ + /* Note that `*agindex' is set to~0 if the charmap is empty. The */ + /* result itself can be~0 in two cases: if the charmap is empty or */ + /* if the value~0 is the first valid character code. */ + /* */ + FT_EXPORT( FT_ULong ) + FT_Get_First_Char( FT_Face face, + FT_UInt *agindex ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Get_Next_Char */ + /* */ + /* <Description> */ + /* This function is used to return the next character code in the */ + /* current charmap of a given face following the value `char_code', */ + /* as well as the corresponding glyph index. */ + /* */ + /* <Input> */ + /* face :: A handle to the source face object. */ + /* char_code :: The starting character code. */ + /* */ + /* <Output> */ + /* agindex :: Glyph index of next character code. 0~if charmap */ + /* is empty. */ + /* */ + /* <Return> */ + /* The charmap's next character code. */ + /* */ + /* <Note> */ + /* You should use this function with @FT_Get_First_Char to walk */ + /* over all character codes available in a given charmap. See the */ + /* note for this function for a simple code example. */ + /* */ + /* Note that `*agindex' is set to~0 when there are no more codes in */ + /* the charmap. */ + /* */ + FT_EXPORT( FT_ULong ) + FT_Get_Next_Char( FT_Face face, + FT_ULong char_code, + FT_UInt *agindex ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Get_Name_Index */ + /* */ + /* <Description> */ + /* Return the glyph index of a given glyph name. This function uses */ + /* driver specific objects to do the translation. */ + /* */ + /* <Input> */ + /* face :: A handle to the source face object. */ + /* */ + /* glyph_name :: The glyph name. */ + /* */ + /* <Return> */ + /* The glyph index. 0~means `undefined character code'. */ + /* */ + FT_EXPORT( FT_UInt ) + FT_Get_Name_Index( FT_Face face, + FT_String* glyph_name ); + + + /************************************************************************* + * + * @macro: + * FT_SUBGLYPH_FLAG_XXX + * + * @description: + * A list of constants used to describe subglyphs. Please refer to the + * TrueType specification for the meaning of the various flags. + * + * @values: + * FT_SUBGLYPH_FLAG_ARGS_ARE_WORDS :: + * FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES :: + * FT_SUBGLYPH_FLAG_ROUND_XY_TO_GRID :: + * FT_SUBGLYPH_FLAG_SCALE :: + * FT_SUBGLYPH_FLAG_XY_SCALE :: + * FT_SUBGLYPH_FLAG_2X2 :: + * FT_SUBGLYPH_FLAG_USE_MY_METRICS :: + * + */ +#define FT_SUBGLYPH_FLAG_ARGS_ARE_WORDS 1 +#define FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES 2 +#define FT_SUBGLYPH_FLAG_ROUND_XY_TO_GRID 4 +#define FT_SUBGLYPH_FLAG_SCALE 8 +#define FT_SUBGLYPH_FLAG_XY_SCALE 0x40 +#define FT_SUBGLYPH_FLAG_2X2 0x80 +#define FT_SUBGLYPH_FLAG_USE_MY_METRICS 0x200 + + + /************************************************************************* + * + * @func: + * FT_Get_SubGlyph_Info + * + * @description: + * Retrieve a description of a given subglyph. Only use it if + * `glyph->format' is @FT_GLYPH_FORMAT_COMPOSITE; an error is + * returned otherwise. + * + * @input: + * glyph :: + * The source glyph slot. + * + * sub_index :: + * The index of the subglyph. Must be less than + * `glyph->num_subglyphs'. + * + * @output: + * p_index :: + * The glyph index of the subglyph. + * + * p_flags :: + * The subglyph flags, see @FT_SUBGLYPH_FLAG_XXX. + * + * p_arg1 :: + * The subglyph's first argument (if any). + * + * p_arg2 :: + * The subglyph's second argument (if any). + * + * p_transform :: + * The subglyph transformation (if any). + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * The values of `*p_arg1', `*p_arg2', and `*p_transform' must be + * interpreted depending on the flags returned in `*p_flags'. See the + * TrueType specification for details. + * + */ + FT_EXPORT( FT_Error ) + FT_Get_SubGlyph_Info( FT_GlyphSlot glyph, + FT_UInt sub_index, + FT_Int *p_index, + FT_UInt *p_flags, + FT_Int *p_arg1, + FT_Int *p_arg2, + FT_Matrix *p_transform ); + + + /*************************************************************************/ + /* */ + /* <Enum> */ + /* FT_FSTYPE_XXX */ + /* */ + /* <Description> */ + /* A list of bit flags used in the `fsType' field of the OS/2 table */ + /* in a TrueType or OpenType font and the `FSType' entry in a */ + /* PostScript font. These bit flags are returned by */ + /* @FT_Get_FSType_Flags; they inform client applications of embedding */ + /* and subsetting restrictions associated with a font. */ + /* */ + /* See http://www.adobe.com/devnet/acrobat/pdfs/FontPolicies.pdf for */ + /* more details. */ + /* */ + /* <Values> */ + /* FT_FSTYPE_INSTALLABLE_EMBEDDING :: */ + /* Fonts with no fsType bit set may be embedded and permanently */ + /* installed on the remote system by an application. */ + /* */ + /* FT_FSTYPE_RESTRICTED_LICENSE_EMBEDDING :: */ + /* Fonts that have only this bit set must not be modified, embedded */ + /* or exchanged in any manner without first obtaining permission of */ + /* the font software copyright owner. */ + /* */ + /* FT_FSTYPE_PREVIEW_AND_PRINT_EMBEDDING :: */ + /* If this bit is set, the font may be embedded and temporarily */ + /* loaded on the remote system. Documents containing Preview & */ + /* Print fonts must be opened `read-only'; no edits can be applied */ + /* to the document. */ + /* */ + /* FT_FSTYPE_EDITABLE_EMBEDDING :: */ + /* If this bit is set, the font may be embedded but must only be */ + /* installed temporarily on other systems. In contrast to Preview */ + /* & Print fonts, documents containing editable fonts may be opened */ + /* for reading, editing is permitted, and changes may be saved. */ + /* */ + /* FT_FSTYPE_NO_SUBSETTING :: */ + /* If this bit is set, the font may not be subsetted prior to */ + /* embedding. */ + /* */ + /* FT_FSTYPE_BITMAP_EMBEDDING_ONLY :: */ + /* If this bit is set, only bitmaps contained in the font may be */ + /* embedded; no outline data may be embedded. If there are no */ + /* bitmaps available in the font, then the font is unembeddable. */ + /* */ + /* <Note> */ + /* While the fsType flags can indicate that a font may be embedded, a */ + /* license with the font vendor may be separately required to use the */ + /* font in this way. */ + /* */ +#define FT_FSTYPE_INSTALLABLE_EMBEDDING 0x0000 +#define FT_FSTYPE_RESTRICTED_LICENSE_EMBEDDING 0x0002 +#define FT_FSTYPE_PREVIEW_AND_PRINT_EMBEDDING 0x0004 +#define FT_FSTYPE_EDITABLE_EMBEDDING 0x0008 +#define FT_FSTYPE_NO_SUBSETTING 0x0100 +#define FT_FSTYPE_BITMAP_EMBEDDING_ONLY 0x0200 + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Get_FSType_Flags */ + /* */ + /* <Description> */ + /* Return the fsType flags for a font. */ + /* */ + /* <Input> */ + /* face :: A handle to the source face object. */ + /* */ + /* <Return> */ + /* The fsType flags, @FT_FSTYPE_XXX. */ + /* */ + /* <Note> */ + /* Use this function rather than directly reading the `fs_type' field */ + /* in the @PS_FontInfoRec structure which is only guaranteed to */ + /* return the correct results for Type~1 fonts. */ + /* */ + FT_EXPORT( FT_UShort ) + FT_Get_FSType_Flags( FT_Face face ); + + + /*************************************************************************/ + /* */ + /* <Section> */ + /* glyph_variants */ + /* */ + /* <Title> */ + /* Glyph Variants */ + /* */ + /* <Abstract> */ + /* The FreeType~2 interface to Unicode Ideographic Variation */ + /* Sequences (IVS), using the SFNT cmap format~14. */ + /* */ + /* <Description> */ + /* Many CJK characters have variant forms. They are a sort of grey */ + /* area somewhere between being totally irrelevant and semantically */ + /* distinct; for this reason, the Unicode consortium decided to */ + /* introduce Ideographic Variation Sequences (IVS), consisting of a */ + /* Unicode base character and one of 240 variant selectors */ + /* (U+E0100-U+E01EF), instead of further extending the already huge */ + /* code range for CJK characters. */ + /* */ + /* An IVS is registered and unique; for further details please refer */ + /* to Unicode Technical Report #37, the Ideographic Variation */ + /* Database. To date (October 2007), the character with the most */ + /* variants is U+908A, having 8~such IVS. */ + /* */ + /* Adobe and MS decided to support IVS with a new cmap subtable */ + /* (format~14). It is an odd subtable because it is not a mapping of */ + /* input code points to glyphs, but contains lists of all variants */ + /* supported by the font. */ + /* */ + /* A variant may be either `default' or `non-default'. A default */ + /* variant is the one you will get for that code point if you look it */ + /* up in the standard Unicode cmap. A non-default variant is a */ + /* different glyph. */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Face_GetCharVariantIndex */ + /* */ + /* <Description> */ + /* Return the glyph index of a given character code as modified by */ + /* the variation selector. */ + /* */ + /* <Input> */ + /* face :: */ + /* A handle to the source face object. */ + /* */ + /* charcode :: */ + /* The character code point in Unicode. */ + /* */ + /* variantSelector :: */ + /* The Unicode code point of the variation selector. */ + /* */ + /* <Return> */ + /* The glyph index. 0~means either `undefined character code', or */ + /* `undefined selector code', or `no variation selector cmap */ + /* subtable', or `current CharMap is not Unicode'. */ + /* */ + /* <Note> */ + /* If you use FreeType to manipulate the contents of font files */ + /* directly, be aware that the glyph index returned by this function */ + /* doesn't always correspond to the internal indices used within */ + /* the file. This is done to ensure that value~0 always corresponds */ + /* to the `missing glyph'. */ + /* */ + /* This function is only meaningful if */ + /* a) the font has a variation selector cmap sub table, */ + /* and */ + /* b) the current charmap has a Unicode encoding. */ + /* */ + /* <Since> */ + /* 2.3.6 */ + /* */ + FT_EXPORT( FT_UInt ) + FT_Face_GetCharVariantIndex( FT_Face face, + FT_ULong charcode, + FT_ULong variantSelector ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Face_GetCharVariantIsDefault */ + /* */ + /* <Description> */ + /* Check whether this variant of this Unicode character is the one to */ + /* be found in the `cmap'. */ + /* */ + /* <Input> */ + /* face :: */ + /* A handle to the source face object. */ + /* */ + /* charcode :: */ + /* The character codepoint in Unicode. */ + /* */ + /* variantSelector :: */ + /* The Unicode codepoint of the variation selector. */ + /* */ + /* <Return> */ + /* 1~if found in the standard (Unicode) cmap, 0~if found in the */ + /* variation selector cmap, or -1 if it is not a variant. */ + /* */ + /* <Note> */ + /* This function is only meaningful if the font has a variation */ + /* selector cmap subtable. */ + /* */ + /* <Since> */ + /* 2.3.6 */ + /* */ + FT_EXPORT( FT_Int ) + FT_Face_GetCharVariantIsDefault( FT_Face face, + FT_ULong charcode, + FT_ULong variantSelector ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Face_GetVariantSelectors */ + /* */ + /* <Description> */ + /* Return a zero-terminated list of Unicode variant selectors found */ + /* in the font. */ + /* */ + /* <Input> */ + /* face :: */ + /* A handle to the source face object. */ + /* */ + /* <Return> */ + /* A pointer to an array of selector code points, or NULL if there is */ + /* no valid variant selector cmap subtable. */ + /* */ + /* <Note> */ + /* The last item in the array is~0; the array is owned by the */ + /* @FT_Face object but can be overwritten or released on the next */ + /* call to a FreeType function. */ + /* */ + /* <Since> */ + /* 2.3.6 */ + /* */ + FT_EXPORT( FT_UInt32* ) + FT_Face_GetVariantSelectors( FT_Face face ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Face_GetVariantsOfChar */ + /* */ + /* <Description> */ + /* Return a zero-terminated list of Unicode variant selectors found */ + /* for the specified character code. */ + /* */ + /* <Input> */ + /* face :: */ + /* A handle to the source face object. */ + /* */ + /* charcode :: */ + /* The character codepoint in Unicode. */ + /* */ + /* <Return> */ + /* A pointer to an array of variant selector code points which are */ + /* active for the given character, or NULL if the corresponding list */ + /* is empty. */ + /* */ + /* <Note> */ + /* The last item in the array is~0; the array is owned by the */ + /* @FT_Face object but can be overwritten or released on the next */ + /* call to a FreeType function. */ + /* */ + /* <Since> */ + /* 2.3.6 */ + /* */ + FT_EXPORT( FT_UInt32* ) + FT_Face_GetVariantsOfChar( FT_Face face, + FT_ULong charcode ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Face_GetCharsOfVariant */ + /* */ + /* <Description> */ + /* Return a zero-terminated list of Unicode character codes found for */ + /* the specified variant selector. */ + /* */ + /* <Input> */ + /* face :: */ + /* A handle to the source face object. */ + /* */ + /* variantSelector :: */ + /* The variant selector code point in Unicode. */ + /* */ + /* <Return> */ + /* A list of all the code points which are specified by this selector */ + /* (both default and non-default codes are returned) or NULL if there */ + /* is no valid cmap or the variant selector is invalid. */ + /* */ + /* <Note> */ + /* The last item in the array is~0; the array is owned by the */ + /* @FT_Face object but can be overwritten or released on the next */ + /* call to a FreeType function. */ + /* */ + /* <Since> */ + /* 2.3.6 */ + /* */ + FT_EXPORT( FT_UInt32* ) + FT_Face_GetCharsOfVariant( FT_Face face, + FT_ULong variantSelector ); + + + /*************************************************************************/ + /* */ + /* <Section> */ + /* computations */ + /* */ + /* <Title> */ + /* Computations */ + /* */ + /* <Abstract> */ + /* Crunching fixed numbers and vectors. */ + /* */ + /* <Description> */ + /* This section contains various functions used to perform */ + /* computations on 16.16 fixed-float numbers or 2d vectors. */ + /* */ + /* <Order> */ + /* FT_MulDiv */ + /* FT_MulFix */ + /* FT_DivFix */ + /* FT_RoundFix */ + /* FT_CeilFix */ + /* FT_FloorFix */ + /* FT_Vector_Transform */ + /* FT_Matrix_Multiply */ + /* FT_Matrix_Invert */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_MulDiv */ + /* */ + /* <Description> */ + /* A very simple function used to perform the computation `(a*b)/c' */ + /* with maximal accuracy (it uses a 64-bit intermediate integer */ + /* whenever necessary). */ + /* */ + /* This function isn't necessarily as fast as some processor specific */ + /* operations, but is at least completely portable. */ + /* */ + /* <Input> */ + /* a :: The first multiplier. */ + /* b :: The second multiplier. */ + /* c :: The divisor. */ + /* */ + /* <Return> */ + /* The result of `(a*b)/c'. This function never traps when trying to */ + /* divide by zero; it simply returns `MaxInt' or `MinInt' depending */ + /* on the signs of `a' and `b'. */ + /* */ + FT_EXPORT( FT_Long ) + FT_MulDiv( FT_Long a, + FT_Long b, + FT_Long c ); + + + /* */ + + /* The following #if 0 ... #endif is for the documentation formatter, */ + /* hiding the internal `FT_MULFIX_INLINED' macro. */ + +#if 0 + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_MulFix */ + /* */ + /* <Description> */ + /* A very simple function used to perform the computation */ + /* `(a*b)/0x10000' with maximal accuracy. Most of the time this is */ + /* used to multiply a given value by a 16.16 fixed float factor. */ + /* */ + /* <Input> */ + /* a :: The first multiplier. */ + /* b :: The second multiplier. Use a 16.16 factor here whenever */ + /* possible (see note below). */ + /* */ + /* <Return> */ + /* The result of `(a*b)/0x10000'. */ + /* */ + /* <Note> */ + /* This function has been optimized for the case where the absolute */ + /* value of `a' is less than 2048, and `b' is a 16.16 scaling factor. */ + /* As this happens mainly when scaling from notional units to */ + /* fractional pixels in FreeType, it resulted in noticeable speed */ + /* improvements between versions 2.x and 1.x. */ + /* */ + /* As a conclusion, always try to place a 16.16 factor as the */ + /* _second_ argument of this function; this can make a great */ + /* difference. */ + /* */ + FT_EXPORT( FT_Long ) + FT_MulFix( FT_Long a, + FT_Long b ); + + /* */ +#endif + +#ifdef FT_MULFIX_INLINED +#define FT_MulFix( a, b ) FT_MULFIX_INLINED( a, b ) +#else + FT_EXPORT( FT_Long ) + FT_MulFix( FT_Long a, + FT_Long b ); +#endif + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_DivFix */ + /* */ + /* <Description> */ + /* A very simple function used to perform the computation */ + /* `(a*0x10000)/b' with maximal accuracy. Most of the time, this is */ + /* used to divide a given value by a 16.16 fixed float factor. */ + /* */ + /* <Input> */ + /* a :: The first multiplier. */ + /* b :: The second multiplier. Use a 16.16 factor here whenever */ + /* possible (see note below). */ + /* */ + /* <Return> */ + /* The result of `(a*0x10000)/b'. */ + /* */ + /* <Note> */ + /* The optimization for FT_DivFix() is simple: If (a~<<~16) fits in */ + /* 32~bits, then the division is computed directly. Otherwise, we */ + /* use a specialized version of @FT_MulDiv. */ + /* */ + FT_EXPORT( FT_Long ) + FT_DivFix( FT_Long a, + FT_Long b ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_RoundFix */ + /* */ + /* <Description> */ + /* A very simple function used to round a 16.16 fixed number. */ + /* */ + /* <Input> */ + /* a :: The number to be rounded. */ + /* */ + /* <Return> */ + /* The result of `(a + 0x8000) & -0x10000'. */ + /* */ + FT_EXPORT( FT_Fixed ) + FT_RoundFix( FT_Fixed a ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_CeilFix */ + /* */ + /* <Description> */ + /* A very simple function used to compute the ceiling function of a */ + /* 16.16 fixed number. */ + /* */ + /* <Input> */ + /* a :: The number for which the ceiling function is to be computed. */ + /* */ + /* <Return> */ + /* The result of `(a + 0x10000 - 1) & -0x10000'. */ + /* */ + FT_EXPORT( FT_Fixed ) + FT_CeilFix( FT_Fixed a ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_FloorFix */ + /* */ + /* <Description> */ + /* A very simple function used to compute the floor function of a */ + /* 16.16 fixed number. */ + /* */ + /* <Input> */ + /* a :: The number for which the floor function is to be computed. */ + /* */ + /* <Return> */ + /* The result of `a & -0x10000'. */ + /* */ + FT_EXPORT( FT_Fixed ) + FT_FloorFix( FT_Fixed a ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Vector_Transform */ + /* */ + /* <Description> */ + /* Transform a single vector through a 2x2 matrix. */ + /* */ + /* <InOut> */ + /* vector :: The target vector to transform. */ + /* */ + /* <Input> */ + /* matrix :: A pointer to the source 2x2 matrix. */ + /* */ + /* <Note> */ + /* The result is undefined if either `vector' or `matrix' is invalid. */ + /* */ + FT_EXPORT( void ) + FT_Vector_Transform( FT_Vector* vec, + const FT_Matrix* matrix ); + + + /*************************************************************************/ + /* */ + /* <Section> */ + /* version */ + /* */ + /* <Title> */ + /* FreeType Version */ + /* */ + /* <Abstract> */ + /* Functions and macros related to FreeType versions. */ + /* */ + /* <Description> */ + /* Note that those functions and macros are of limited use because */ + /* even a new release of FreeType with only documentation changes */ + /* increases the version number. */ + /* */ + /*************************************************************************/ + + + /************************************************************************* + * + * @enum: + * FREETYPE_XXX + * + * @description: + * These three macros identify the FreeType source code version. + * Use @FT_Library_Version to access them at runtime. + * + * @values: + * FREETYPE_MAJOR :: The major version number. + * FREETYPE_MINOR :: The minor version number. + * FREETYPE_PATCH :: The patch level. + * + * @note: + * The version number of FreeType if built as a dynamic link library + * with the `libtool' package is _not_ controlled by these three + * macros. + * + */ +#define FREETYPE_MAJOR 2 +#define FREETYPE_MINOR 4 +#define FREETYPE_PATCH 4 + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Library_Version */ + /* */ + /* <Description> */ + /* Return the version of the FreeType library being used. This is */ + /* useful when dynamically linking to the library, since one cannot */ + /* use the macros @FREETYPE_MAJOR, @FREETYPE_MINOR, and */ + /* @FREETYPE_PATCH. */ + /* */ + /* <Input> */ + /* library :: A source library handle. */ + /* */ + /* <Output> */ + /* amajor :: The major version number. */ + /* */ + /* aminor :: The minor version number. */ + /* */ + /* apatch :: The patch version number. */ + /* */ + /* <Note> */ + /* The reason why this function takes a `library' argument is because */ + /* certain programs implement library initialization in a custom way */ + /* that doesn't use @FT_Init_FreeType. */ + /* */ + /* In such cases, the library version might not be available before */ + /* the library object has been created. */ + /* */ + FT_EXPORT( void ) + FT_Library_Version( FT_Library library, + FT_Int *amajor, + FT_Int *aminor, + FT_Int *apatch ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Face_CheckTrueTypePatents */ + /* */ + /* <Description> */ + /* Parse all bytecode instructions of a TrueType font file to check */ + /* whether any of the patented opcodes are used. This is only useful */ + /* if you want to be able to use the unpatented hinter with */ + /* fonts that do *not* use these opcodes. */ + /* */ + /* Note that this function parses *all* glyph instructions in the */ + /* font file, which may be slow. */ + /* */ + /* <Input> */ + /* face :: A face handle. */ + /* */ + /* <Return> */ + /* 1~if this is a TrueType font that uses one of the patented */ + /* opcodes, 0~otherwise. */ + /* */ + /* <Note> */ + /* Since May 2010, TrueType hinting is no longer patented. */ + /* */ + /* <Since> */ + /* 2.3.5 */ + /* */ + FT_EXPORT( FT_Bool ) + FT_Face_CheckTrueTypePatents( FT_Face face ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Face_SetUnpatentedHinting */ + /* */ + /* <Description> */ + /* Enable or disable the unpatented hinter for a given face. */ + /* Only enable it if you have determined that the face doesn't */ + /* use any patented opcodes (see @FT_Face_CheckTrueTypePatents). */ + /* */ + /* <Input> */ + /* face :: A face handle. */ + /* */ + /* value :: New boolean setting. */ + /* */ + /* <Return> */ + /* The old setting value. This will always be false if this is not */ + /* an SFNT font, or if the unpatented hinter is not compiled in this */ + /* instance of the library. */ + /* */ + /* <Note> */ + /* Since May 2010, TrueType hinting is no longer patented. */ + /* */ + /* <Since> */ + /* 2.3.5 */ + /* */ + FT_EXPORT( FT_Bool ) + FT_Face_SetUnpatentedHinting( FT_Face face, + FT_Bool value ); + + /* */ + + +FT_END_HEADER + +#endif /* __FREETYPE_H__ */ + + +/* END */ diff --git a/Lib/Include/freetype/ftadvanc.h b/Lib/Include/freetype/ftadvanc.h new file mode 100644 index 0000000..b2451be --- /dev/null +++ b/Lib/Include/freetype/ftadvanc.h @@ -0,0 +1,179 @@ +/***************************************************************************/ +/* */ +/* ftadvanc.h */ +/* */ +/* Quick computation of advance widths (specification only). */ +/* */ +/* Copyright 2008 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef __FTADVANC_H__ +#define __FTADVANC_H__ + + +#include <ft2build.h> +#include FT_FREETYPE_H + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + + /************************************************************************** + * + * @section: + * quick_advance + * + * @title: + * Quick retrieval of advance values + * + * @abstract: + * Retrieve horizontal and vertical advance values without processing + * glyph outlines, if possible. + * + * @description: + * This section contains functions to quickly extract advance values + * without handling glyph outlines, if possible. + */ + + + /*************************************************************************/ + /* */ + /* <Const> */ + /* FT_ADVANCE_FLAG_FAST_ONLY */ + /* */ + /* <Description> */ + /* A bit-flag to be OR-ed with the `flags' parameter of the */ + /* @FT_Get_Advance and @FT_Get_Advances functions. */ + /* */ + /* If set, it indicates that you want these functions to fail if the */ + /* corresponding hinting mode or font driver doesn't allow for very */ + /* quick advance computation. */ + /* */ + /* Typically, glyphs which are either unscaled, unhinted, bitmapped, */ + /* or light-hinted can have their advance width computed very */ + /* quickly. */ + /* */ + /* Normal and bytecode hinted modes, which require loading, scaling, */ + /* and hinting of the glyph outline, are extremely slow by */ + /* comparison. */ + /* */ +#define FT_ADVANCE_FLAG_FAST_ONLY 0x20000000UL + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Get_Advance */ + /* */ + /* <Description> */ + /* Retrieve the advance value of a given glyph outline in an */ + /* @FT_Face. By default, the unhinted advance is returned in font */ + /* units. */ + /* */ + /* <Input> */ + /* face :: The source @FT_Face handle. */ + /* */ + /* gindex :: The glyph index. */ + /* */ + /* load_flags :: A set of bit flags similar to those used when */ + /* calling @FT_Load_Glyph, used to determine what kind */ + /* of advances you need. */ + /* <Output> */ + /* padvance :: The advance value, in either font units or 16.16 */ + /* format. */ + /* */ + /* If @FT_LOAD_VERTICAL_LAYOUT is set, this is the */ + /* vertical advance corresponding to a vertical layout. */ + /* Otherwise, it is the horizontal advance in a */ + /* horizontal layout. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + /* <Note> */ + /* This function may fail if you use @FT_ADVANCE_FLAG_FAST_ONLY and */ + /* if the corresponding font backend doesn't have a quick way to */ + /* retrieve the advances. */ + /* */ + /* A scaled advance is returned in 16.16 format but isn't transformed */ + /* by the affine transformation specified by @FT_Set_Transform. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Get_Advance( FT_Face face, + FT_UInt gindex, + FT_Int32 load_flags, + FT_Fixed *padvance ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Get_Advances */ + /* */ + /* <Description> */ + /* Retrieve the advance values of several glyph outlines in an */ + /* @FT_Face. By default, the unhinted advances are returned in font */ + /* units. */ + /* */ + /* <Input> */ + /* face :: The source @FT_Face handle. */ + /* */ + /* start :: The first glyph index. */ + /* */ + /* count :: The number of advance values you want to retrieve. */ + /* */ + /* load_flags :: A set of bit flags similar to those used when */ + /* calling @FT_Load_Glyph. */ + /* */ + /* <Output> */ + /* padvance :: The advances, in either font units or 16.16 format. */ + /* This array must contain at least `count' elements. */ + /* */ + /* If @FT_LOAD_VERTICAL_LAYOUT is set, these are the */ + /* vertical advances corresponding to a vertical layout. */ + /* Otherwise, they are the horizontal advances in a */ + /* horizontal layout. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + /* <Note> */ + /* This function may fail if you use @FT_ADVANCE_FLAG_FAST_ONLY and */ + /* if the corresponding font backend doesn't have a quick way to */ + /* retrieve the advances. */ + /* */ + /* Scaled advances are returned in 16.16 format but aren't */ + /* transformed by the affine transformation specified by */ + /* @FT_Set_Transform. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Get_Advances( FT_Face face, + FT_UInt start, + FT_UInt count, + FT_Int32 load_flags, + FT_Fixed *padvances ); + +/* */ + + +FT_END_HEADER + +#endif /* __FTADVANC_H__ */ + + +/* END */ diff --git a/Lib/Include/freetype/ftbbox.h b/Lib/Include/freetype/ftbbox.h new file mode 100644 index 0000000..a7b9f82 --- /dev/null +++ b/Lib/Include/freetype/ftbbox.h @@ -0,0 +1,94 @@ +/***************************************************************************/ +/* */ +/* ftbbox.h */ +/* */ +/* FreeType exact bbox computation (specification). */ +/* */ +/* Copyright 1996-2001, 2003, 2007 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + + /*************************************************************************/ + /* */ + /* This component has a _single_ role: to compute exact outline bounding */ + /* boxes. */ + /* */ + /* It is separated from the rest of the engine for various technical */ + /* reasons. It may well be integrated in `ftoutln' later. */ + /* */ + /*************************************************************************/ + + +#ifndef __FTBBOX_H__ +#define __FTBBOX_H__ + + +#include <ft2build.h> +#include FT_FREETYPE_H + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /* */ + /* <Section> */ + /* outline_processing */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Outline_Get_BBox */ + /* */ + /* <Description> */ + /* Compute the exact bounding box of an outline. This is slower */ + /* than computing the control box. However, it uses an advanced */ + /* algorithm which returns _very_ quickly when the two boxes */ + /* coincide. Otherwise, the outline BȨzier arcs are traversed to */ + /* extract their extrema. */ + /* */ + /* <Input> */ + /* outline :: A pointer to the source outline. */ + /* */ + /* <Output> */ + /* abbox :: The outline's exact bounding box. */ + /* */ + /* <Return> */ + /* FreeType error code. 0~means success. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Outline_Get_BBox( FT_Outline* outline, + FT_BBox *abbox ); + + + /* */ + + +FT_END_HEADER + +#endif /* __FTBBOX_H__ */ + + +/* END */ + + +/* Local Variables: */ +/* coding: utf-8 */ +/* End: */ diff --git a/Lib/Include/freetype/ftbdf.h b/Lib/Include/freetype/ftbdf.h new file mode 100644 index 0000000..4f8baf8 --- /dev/null +++ b/Lib/Include/freetype/ftbdf.h @@ -0,0 +1,209 @@ +/***************************************************************************/ +/* */ +/* ftbdf.h */ +/* */ +/* FreeType API for accessing BDF-specific strings (specification). */ +/* */ +/* Copyright 2002, 2003, 2004, 2006, 2009 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef __FTBDF_H__ +#define __FTBDF_H__ + +#include <ft2build.h> +#include FT_FREETYPE_H + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /* */ + /* <Section> */ + /* bdf_fonts */ + /* */ + /* <Title> */ + /* BDF and PCF Files */ + /* */ + /* <Abstract> */ + /* BDF and PCF specific API. */ + /* */ + /* <Description> */ + /* This section contains the declaration of functions specific to BDF */ + /* and PCF fonts. */ + /* */ + /*************************************************************************/ + + + /********************************************************************** + * + * @enum: + * FT_PropertyType + * + * @description: + * A list of BDF property types. + * + * @values: + * BDF_PROPERTY_TYPE_NONE :: + * Value~0 is used to indicate a missing property. + * + * BDF_PROPERTY_TYPE_ATOM :: + * Property is a string atom. + * + * BDF_PROPERTY_TYPE_INTEGER :: + * Property is a 32-bit signed integer. + * + * BDF_PROPERTY_TYPE_CARDINAL :: + * Property is a 32-bit unsigned integer. + */ + typedef enum BDF_PropertyType_ + { + BDF_PROPERTY_TYPE_NONE = 0, + BDF_PROPERTY_TYPE_ATOM = 1, + BDF_PROPERTY_TYPE_INTEGER = 2, + BDF_PROPERTY_TYPE_CARDINAL = 3 + + } BDF_PropertyType; + + + /********************************************************************** + * + * @type: + * BDF_Property + * + * @description: + * A handle to a @BDF_PropertyRec structure to model a given + * BDF/PCF property. + */ + typedef struct BDF_PropertyRec_* BDF_Property; + + + /********************************************************************** + * + * @struct: + * BDF_PropertyRec + * + * @description: + * This structure models a given BDF/PCF property. + * + * @fields: + * type :: + * The property type. + * + * u.atom :: + * The atom string, if type is @BDF_PROPERTY_TYPE_ATOM. + * + * u.integer :: + * A signed integer, if type is @BDF_PROPERTY_TYPE_INTEGER. + * + * u.cardinal :: + * An unsigned integer, if type is @BDF_PROPERTY_TYPE_CARDINAL. + */ + typedef struct BDF_PropertyRec_ + { + BDF_PropertyType type; + union { + const char* atom; + FT_Int32 integer; + FT_UInt32 cardinal; + + } u; + + } BDF_PropertyRec; + + + /********************************************************************** + * + * @function: + * FT_Get_BDF_Charset_ID + * + * @description: + * Retrieve a BDF font character set identity, according to + * the BDF specification. + * + * @input: + * face :: + * A handle to the input face. + * + * @output: + * acharset_encoding :: + * Charset encoding, as a C~string, owned by the face. + * + * acharset_registry :: + * Charset registry, as a C~string, owned by the face. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * This function only works with BDF faces, returning an error otherwise. + */ + FT_EXPORT( FT_Error ) + FT_Get_BDF_Charset_ID( FT_Face face, + const char* *acharset_encoding, + const char* *acharset_registry ); + + + /********************************************************************** + * + * @function: + * FT_Get_BDF_Property + * + * @description: + * Retrieve a BDF property from a BDF or PCF font file. + * + * @input: + * face :: A handle to the input face. + * + * name :: The property name. + * + * @output: + * aproperty :: The property. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * This function works with BDF _and_ PCF fonts. It returns an error + * otherwise. It also returns an error if the property is not in the + * font. + * + * A `property' is a either key-value pair within the STARTPROPERTIES + * ... ENDPROPERTIES block of a BDF font or a key-value pair from the + * `info->props' array within a `FontRec' structure of a PCF font. + * + * Integer properties are always stored as `signed' within PCF fonts; + * consequently, @BDF_PROPERTY_TYPE_CARDINAL is a possible return value + * for BDF fonts only. + * + * In case of error, `aproperty->type' is always set to + * @BDF_PROPERTY_TYPE_NONE. + */ + FT_EXPORT( FT_Error ) + FT_Get_BDF_Property( FT_Face face, + const char* prop_name, + BDF_PropertyRec *aproperty ); + + /* */ + +FT_END_HEADER + +#endif /* __FTBDF_H__ */ + + +/* END */ diff --git a/Lib/Include/freetype/ftbitmap.h b/Lib/Include/freetype/ftbitmap.h new file mode 100644 index 0000000..9274236 --- /dev/null +++ b/Lib/Include/freetype/ftbitmap.h @@ -0,0 +1,227 @@ +/***************************************************************************/ +/* */ +/* ftbitmap.h */ +/* */ +/* FreeType utility functions for bitmaps (specification). */ +/* */ +/* Copyright 2004, 2005, 2006, 2008 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef __FTBITMAP_H__ +#define __FTBITMAP_H__ + + +#include <ft2build.h> +#include FT_FREETYPE_H + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /* */ + /* <Section> */ + /* bitmap_handling */ + /* */ + /* <Title> */ + /* Bitmap Handling */ + /* */ + /* <Abstract> */ + /* Handling FT_Bitmap objects. */ + /* */ + /* <Description> */ + /* This section contains functions for converting FT_Bitmap objects. */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Bitmap_New */ + /* */ + /* <Description> */ + /* Initialize a pointer to an @FT_Bitmap structure. */ + /* */ + /* <InOut> */ + /* abitmap :: A pointer to the bitmap structure. */ + /* */ + FT_EXPORT( void ) + FT_Bitmap_New( FT_Bitmap *abitmap ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Bitmap_Copy */ + /* */ + /* <Description> */ + /* Copy a bitmap into another one. */ + /* */ + /* <Input> */ + /* library :: A handle to a library object. */ + /* */ + /* source :: A handle to the source bitmap. */ + /* */ + /* <Output> */ + /* target :: A handle to the target bitmap. */ + /* */ + /* <Return> */ + /* FreeType error code. 0~means success. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Bitmap_Copy( FT_Library library, + const FT_Bitmap *source, + FT_Bitmap *target); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Bitmap_Embolden */ + /* */ + /* <Description> */ + /* Embolden a bitmap. The new bitmap will be about `xStrength' */ + /* pixels wider and `yStrength' pixels higher. The left and bottom */ + /* borders are kept unchanged. */ + /* */ + /* <Input> */ + /* library :: A handle to a library object. */ + /* */ + /* xStrength :: How strong the glyph is emboldened horizontally. */ + /* Expressed in 26.6 pixel format. */ + /* */ + /* yStrength :: How strong the glyph is emboldened vertically. */ + /* Expressed in 26.6 pixel format. */ + /* */ + /* <InOut> */ + /* bitmap :: A handle to the target bitmap. */ + /* */ + /* <Return> */ + /* FreeType error code. 0~means success. */ + /* */ + /* <Note> */ + /* The current implementation restricts `xStrength' to be less than */ + /* or equal to~8 if bitmap is of pixel_mode @FT_PIXEL_MODE_MONO. */ + /* */ + /* If you want to embolden the bitmap owned by a @FT_GlyphSlotRec, */ + /* you should call @FT_GlyphSlot_Own_Bitmap on the slot first. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Bitmap_Embolden( FT_Library library, + FT_Bitmap* bitmap, + FT_Pos xStrength, + FT_Pos yStrength ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Bitmap_Convert */ + /* */ + /* <Description> */ + /* Convert a bitmap object with depth 1bpp, 2bpp, 4bpp, or 8bpp to a */ + /* bitmap object with depth 8bpp, making the number of used bytes per */ + /* line (a.k.a. the `pitch') a multiple of `alignment'. */ + /* */ + /* <Input> */ + /* library :: A handle to a library object. */ + /* */ + /* source :: The source bitmap. */ + /* */ + /* alignment :: The pitch of the bitmap is a multiple of this */ + /* parameter. Common values are 1, 2, or 4. */ + /* */ + /* <Output> */ + /* target :: The target bitmap. */ + /* */ + /* <Return> */ + /* FreeType error code. 0~means success. */ + /* */ + /* <Note> */ + /* It is possible to call @FT_Bitmap_Convert multiple times without */ + /* calling @FT_Bitmap_Done (the memory is simply reallocated). */ + /* */ + /* Use @FT_Bitmap_Done to finally remove the bitmap object. */ + /* */ + /* The `library' argument is taken to have access to FreeType's */ + /* memory handling functions. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Bitmap_Convert( FT_Library library, + const FT_Bitmap *source, + FT_Bitmap *target, + FT_Int alignment ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_GlyphSlot_Own_Bitmap */ + /* */ + /* <Description> */ + /* Make sure that a glyph slot owns `slot->bitmap'. */ + /* */ + /* <Input> */ + /* slot :: The glyph slot. */ + /* */ + /* <Return> */ + /* FreeType error code. 0~means success. */ + /* */ + /* <Note> */ + /* This function is to be used in combination with */ + /* @FT_Bitmap_Embolden. */ + /* */ + FT_EXPORT( FT_Error ) + FT_GlyphSlot_Own_Bitmap( FT_GlyphSlot slot ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Bitmap_Done */ + /* */ + /* <Description> */ + /* Destroy a bitmap object created with @FT_Bitmap_New. */ + /* */ + /* <Input> */ + /* library :: A handle to a library object. */ + /* */ + /* bitmap :: The bitmap object to be freed. */ + /* */ + /* <Return> */ + /* FreeType error code. 0~means success. */ + /* */ + /* <Note> */ + /* The `library' argument is taken to have access to FreeType's */ + /* memory handling functions. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Bitmap_Done( FT_Library library, + FT_Bitmap *bitmap ); + + + /* */ + + +FT_END_HEADER + +#endif /* __FTBITMAP_H__ */ + + +/* END */ diff --git a/Lib/Include/freetype/ftcache.h b/Lib/Include/freetype/ftcache.h new file mode 100644 index 0000000..6af5306 --- /dev/null +++ b/Lib/Include/freetype/ftcache.h @@ -0,0 +1,1140 @@ +/***************************************************************************/ +/* */ +/* ftcache.h */ +/* */ +/* FreeType Cache subsystem (specification). */ +/* */ +/* Copyright 1996-2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2010 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef __FTCACHE_H__ +#define __FTCACHE_H__ + + +#include <ft2build.h> +#include FT_GLYPH_H + + +FT_BEGIN_HEADER + + + /************************************************************************* + * + * <Section> + * cache_subsystem + * + * <Title> + * Cache Sub-System + * + * <Abstract> + * How to cache face, size, and glyph data with FreeType~2. + * + * <Description> + * This section describes the FreeType~2 cache sub-system, which is used + * to limit the number of concurrently opened @FT_Face and @FT_Size + * objects, as well as caching information like character maps and glyph + * images while limiting their maximum memory usage. + * + * Note that all types and functions begin with the `FTC_' prefix. + * + * The cache is highly portable and thus doesn't know anything about the + * fonts installed on your system, or how to access them. This implies + * the following scheme: + * + * First, available or installed font faces are uniquely identified by + * @FTC_FaceID values, provided to the cache by the client. Note that + * the cache only stores and compares these values, and doesn't try to + * interpret them in any way. + * + * Second, the cache calls, only when needed, a client-provided function + * to convert an @FTC_FaceID into a new @FT_Face object. The latter is + * then completely managed by the cache, including its termination + * through @FT_Done_Face. To monitor termination of face objects, the + * finalizer callback in the `generic' field of the @FT_Face object can + * be used, which might also be used to store the @FTC_FaceID of the + * face. + * + * Clients are free to map face IDs to anything else. The most simple + * usage is to associate them to a (pathname,face_index) pair that is + * used to call @FT_New_Face. However, more complex schemes are also + * possible. + * + * Note that for the cache to work correctly, the face ID values must be + * *persistent*, which means that the contents they point to should not + * change at runtime, or that their value should not become invalid. + * + * If this is unavoidable (e.g., when a font is uninstalled at runtime), + * you should call @FTC_Manager_RemoveFaceID as soon as possible, to let + * the cache get rid of any references to the old @FTC_FaceID it may + * keep internally. Failure to do so will lead to incorrect behaviour + * or even crashes. + * + * To use the cache, start with calling @FTC_Manager_New to create a new + * @FTC_Manager object, which models a single cache instance. You can + * then look up @FT_Face and @FT_Size objects with + * @FTC_Manager_LookupFace and @FTC_Manager_LookupSize, respectively. + * + * If you want to use the charmap caching, call @FTC_CMapCache_New, then + * later use @FTC_CMapCache_Lookup to perform the equivalent of + * @FT_Get_Char_Index, only much faster. + * + * If you want to use the @FT_Glyph caching, call @FTC_ImageCache, then + * later use @FTC_ImageCache_Lookup to retrieve the corresponding + * @FT_Glyph objects from the cache. + * + * If you need lots of small bitmaps, it is much more memory efficient + * to call @FTC_SBitCache_New followed by @FTC_SBitCache_Lookup. This + * returns @FTC_SBitRec structures, which are used to store small + * bitmaps directly. (A small bitmap is one whose metrics and + * dimensions all fit into 8-bit integers). + * + * We hope to also provide a kerning cache in the near future. + * + * + * <Order> + * FTC_Manager + * FTC_FaceID + * FTC_Face_Requester + * + * FTC_Manager_New + * FTC_Manager_Reset + * FTC_Manager_Done + * FTC_Manager_LookupFace + * FTC_Manager_LookupSize + * FTC_Manager_RemoveFaceID + * + * FTC_Node + * FTC_Node_Unref + * + * FTC_ImageCache + * FTC_ImageCache_New + * FTC_ImageCache_Lookup + * + * FTC_SBit + * FTC_SBitCache + * FTC_SBitCache_New + * FTC_SBitCache_Lookup + * + * FTC_CMapCache + * FTC_CMapCache_New + * FTC_CMapCache_Lookup + * + *************************************************************************/ + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** BASIC TYPE DEFINITIONS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + /************************************************************************* + * + * @type: FTC_FaceID + * + * @description: + * An opaque pointer type that is used to identity face objects. The + * contents of such objects is application-dependent. + * + * These pointers are typically used to point to a user-defined + * structure containing a font file path, and face index. + * + * @note: + * Never use NULL as a valid @FTC_FaceID. + * + * Face IDs are passed by the client to the cache manager, which calls, + * when needed, the @FTC_Face_Requester to translate them into new + * @FT_Face objects. + * + * If the content of a given face ID changes at runtime, or if the value + * becomes invalid (e.g., when uninstalling a font), you should + * immediately call @FTC_Manager_RemoveFaceID before any other cache + * function. + * + * Failure to do so will result in incorrect behaviour or even + * memory leaks and crashes. + */ + typedef FT_Pointer FTC_FaceID; + + + /************************************************************************ + * + * @functype: + * FTC_Face_Requester + * + * @description: + * A callback function provided by client applications. It is used by + * the cache manager to translate a given @FTC_FaceID into a new valid + * @FT_Face object, on demand. + * + * <Input> + * face_id :: + * The face ID to resolve. + * + * library :: + * A handle to a FreeType library object. + * + * req_data :: + * Application-provided request data (see note below). + * + * <Output> + * aface :: + * A new @FT_Face handle. + * + * <Return> + * FreeType error code. 0~means success. + * + * <Note> + * The third parameter `req_data' is the same as the one passed by the + * client when @FTC_Manager_New is called. + * + * The face requester should not perform funny things on the returned + * face object, like creating a new @FT_Size for it, or setting a + * transformation through @FT_Set_Transform! + */ + typedef FT_Error + (*FTC_Face_Requester)( FTC_FaceID face_id, + FT_Library library, + FT_Pointer request_data, + FT_Face* aface ); + + /* */ + +#ifdef FT_CONFIG_OPTION_OLD_INTERNALS + + /* these macros are incompatible with LLP64, should not be used */ + +#define FT_POINTER_TO_ULONG( p ) ( (FT_ULong)(FT_Pointer)(p) ) + +#define FTC_FACE_ID_HASH( i ) \ + ((FT_UInt32)(( FT_POINTER_TO_ULONG( i ) >> 3 ) ^ \ + ( FT_POINTER_TO_ULONG( i ) << 7 ) ) ) + +#endif /* FT_CONFIG_OPTION_OLD_INTERNALS */ + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** CACHE MANAGER OBJECT *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FTC_Manager */ + /* */ + /* <Description> */ + /* This object corresponds to one instance of the cache-subsystem. */ + /* It is used to cache one or more @FT_Face objects, along with */ + /* corresponding @FT_Size objects. */ + /* */ + /* The manager intentionally limits the total number of opened */ + /* @FT_Face and @FT_Size objects to control memory usage. See the */ + /* `max_faces' and `max_sizes' parameters of @FTC_Manager_New. */ + /* */ + /* The manager is also used to cache `nodes' of various types while */ + /* limiting their total memory usage. */ + /* */ + /* All limitations are enforced by keeping lists of managed objects */ + /* in most-recently-used order, and flushing old nodes to make room */ + /* for new ones. */ + /* */ + typedef struct FTC_ManagerRec_* FTC_Manager; + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FTC_Node */ + /* */ + /* <Description> */ + /* An opaque handle to a cache node object. Each cache node is */ + /* reference-counted. A node with a count of~0 might be flushed */ + /* out of a full cache whenever a lookup request is performed. */ + /* */ + /* If you look up nodes, you have the ability to `acquire' them, */ + /* i.e., to increment their reference count. This will prevent the */ + /* node from being flushed out of the cache until you explicitly */ + /* `release' it (see @FTC_Node_Unref). */ + /* */ + /* See also @FTC_SBitCache_Lookup and @FTC_ImageCache_Lookup. */ + /* */ + typedef struct FTC_NodeRec_* FTC_Node; + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FTC_Manager_New */ + /* */ + /* <Description> */ + /* Create a new cache manager. */ + /* */ + /* <Input> */ + /* library :: The parent FreeType library handle to use. */ + /* */ + /* max_faces :: Maximum number of opened @FT_Face objects managed by */ + /* this cache instance. Use~0 for defaults. */ + /* */ + /* max_sizes :: Maximum number of opened @FT_Size objects managed by */ + /* this cache instance. Use~0 for defaults. */ + /* */ + /* max_bytes :: Maximum number of bytes to use for cached data nodes. */ + /* Use~0 for defaults. Note that this value does not */ + /* account for managed @FT_Face and @FT_Size objects. */ + /* */ + /* requester :: An application-provided callback used to translate */ + /* face IDs into real @FT_Face objects. */ + /* */ + /* req_data :: A generic pointer that is passed to the requester */ + /* each time it is called (see @FTC_Face_Requester). */ + /* */ + /* <Output> */ + /* amanager :: A handle to a new manager object. 0~in case of */ + /* failure. */ + /* */ + /* <Return> */ + /* FreeType error code. 0~means success. */ + /* */ + FT_EXPORT( FT_Error ) + FTC_Manager_New( FT_Library library, + FT_UInt max_faces, + FT_UInt max_sizes, + FT_ULong max_bytes, + FTC_Face_Requester requester, + FT_Pointer req_data, + FTC_Manager *amanager ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FTC_Manager_Reset */ + /* */ + /* <Description> */ + /* Empty a given cache manager. This simply gets rid of all the */ + /* currently cached @FT_Face and @FT_Size objects within the manager. */ + /* */ + /* <InOut> */ + /* manager :: A handle to the manager. */ + /* */ + FT_EXPORT( void ) + FTC_Manager_Reset( FTC_Manager manager ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FTC_Manager_Done */ + /* */ + /* <Description> */ + /* Destroy a given manager after emptying it. */ + /* */ + /* <Input> */ + /* manager :: A handle to the target cache manager object. */ + /* */ + FT_EXPORT( void ) + FTC_Manager_Done( FTC_Manager manager ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FTC_Manager_LookupFace */ + /* */ + /* <Description> */ + /* Retrieve the @FT_Face object that corresponds to a given face ID */ + /* through a cache manager. */ + /* */ + /* <Input> */ + /* manager :: A handle to the cache manager. */ + /* */ + /* face_id :: The ID of the face object. */ + /* */ + /* <Output> */ + /* aface :: A handle to the face object. */ + /* */ + /* <Return> */ + /* FreeType error code. 0~means success. */ + /* */ + /* <Note> */ + /* The returned @FT_Face object is always owned by the manager. You */ + /* should never try to discard it yourself. */ + /* */ + /* The @FT_Face object doesn't necessarily have a current size object */ + /* (i.e., face->size can be 0). If you need a specific `font size', */ + /* use @FTC_Manager_LookupSize instead. */ + /* */ + /* Never change the face's transformation matrix (i.e., never call */ + /* the @FT_Set_Transform function) on a returned face! If you need */ + /* to transform glyphs, do it yourself after glyph loading. */ + /* */ + /* When you perform a lookup, out-of-memory errors are detected */ + /* _within_ the lookup and force incremental flushes of the cache */ + /* until enough memory is released for the lookup to succeed. */ + /* */ + /* If a lookup fails with `FT_Err_Out_Of_Memory' the cache has */ + /* already been completely flushed, and still no memory was available */ + /* for the operation. */ + /* */ + FT_EXPORT( FT_Error ) + FTC_Manager_LookupFace( FTC_Manager manager, + FTC_FaceID face_id, + FT_Face *aface ); + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FTC_ScalerRec */ + /* */ + /* <Description> */ + /* A structure used to describe a given character size in either */ + /* pixels or points to the cache manager. See */ + /* @FTC_Manager_LookupSize. */ + /* */ + /* <Fields> */ + /* face_id :: The source face ID. */ + /* */ + /* width :: The character width. */ + /* */ + /* height :: The character height. */ + /* */ + /* pixel :: A Boolean. If 1, the `width' and `height' fields are */ + /* interpreted as integer pixel character sizes. */ + /* Otherwise, they are expressed as 1/64th of points. */ + /* */ + /* x_res :: Only used when `pixel' is value~0 to indicate the */ + /* horizontal resolution in dpi. */ + /* */ + /* y_res :: Only used when `pixel' is value~0 to indicate the */ + /* vertical resolution in dpi. */ + /* */ + /* <Note> */ + /* This type is mainly used to retrieve @FT_Size objects through the */ + /* cache manager. */ + /* */ + typedef struct FTC_ScalerRec_ + { + FTC_FaceID face_id; + FT_UInt width; + FT_UInt height; + FT_Int pixel; + FT_UInt x_res; + FT_UInt y_res; + + } FTC_ScalerRec; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FTC_Scaler */ + /* */ + /* <Description> */ + /* A handle to an @FTC_ScalerRec structure. */ + /* */ + typedef struct FTC_ScalerRec_* FTC_Scaler; + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FTC_Manager_LookupSize */ + /* */ + /* <Description> */ + /* Retrieve the @FT_Size object that corresponds to a given */ + /* @FTC_ScalerRec pointer through a cache manager. */ + /* */ + /* <Input> */ + /* manager :: A handle to the cache manager. */ + /* */ + /* scaler :: A scaler handle. */ + /* */ + /* <Output> */ + /* asize :: A handle to the size object. */ + /* */ + /* <Return> */ + /* FreeType error code. 0~means success. */ + /* */ + /* <Note> */ + /* The returned @FT_Size object is always owned by the manager. You */ + /* should never try to discard it by yourself. */ + /* */ + /* You can access the parent @FT_Face object simply as `size->face' */ + /* if you need it. Note that this object is also owned by the */ + /* manager. */ + /* */ + /* <Note> */ + /* When you perform a lookup, out-of-memory errors are detected */ + /* _within_ the lookup and force incremental flushes of the cache */ + /* until enough memory is released for the lookup to succeed. */ + /* */ + /* If a lookup fails with `FT_Err_Out_Of_Memory' the cache has */ + /* already been completely flushed, and still no memory is available */ + /* for the operation. */ + /* */ + FT_EXPORT( FT_Error ) + FTC_Manager_LookupSize( FTC_Manager manager, + FTC_Scaler scaler, + FT_Size *asize ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FTC_Node_Unref */ + /* */ + /* <Description> */ + /* Decrement a cache node's internal reference count. When the count */ + /* reaches 0, it is not destroyed but becomes eligible for subsequent */ + /* cache flushes. */ + /* */ + /* <Input> */ + /* node :: The cache node handle. */ + /* */ + /* manager :: The cache manager handle. */ + /* */ + FT_EXPORT( void ) + FTC_Node_Unref( FTC_Node node, + FTC_Manager manager ); + + + /************************************************************************* + * + * @function: + * FTC_Manager_RemoveFaceID + * + * @description: + * A special function used to indicate to the cache manager that + * a given @FTC_FaceID is no longer valid, either because its + * content changed, or because it was deallocated or uninstalled. + * + * @input: + * manager :: + * The cache manager handle. + * + * face_id :: + * The @FTC_FaceID to be removed. + * + * @note: + * This function flushes all nodes from the cache corresponding to this + * `face_id', with the exception of nodes with a non-null reference + * count. + * + * Such nodes are however modified internally so as to never appear + * in later lookups with the same `face_id' value, and to be immediately + * destroyed when released by all their users. + * + */ + FT_EXPORT( void ) + FTC_Manager_RemoveFaceID( FTC_Manager manager, + FTC_FaceID face_id ); + + + /*************************************************************************/ + /* */ + /* <Section> */ + /* cache_subsystem */ + /* */ + /*************************************************************************/ + + /************************************************************************* + * + * @type: + * FTC_CMapCache + * + * @description: + * An opaque handle used to model a charmap cache. This cache is to + * hold character codes -> glyph indices mappings. + * + */ + typedef struct FTC_CMapCacheRec_* FTC_CMapCache; + + + /************************************************************************* + * + * @function: + * FTC_CMapCache_New + * + * @description: + * Create a new charmap cache. + * + * @input: + * manager :: + * A handle to the cache manager. + * + * @output: + * acache :: + * A new cache handle. NULL in case of error. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * Like all other caches, this one will be destroyed with the cache + * manager. + * + */ + FT_EXPORT( FT_Error ) + FTC_CMapCache_New( FTC_Manager manager, + FTC_CMapCache *acache ); + + + /************************************************************************ + * + * @function: + * FTC_CMapCache_Lookup + * + * @description: + * Translate a character code into a glyph index, using the charmap + * cache. + * + * @input: + * cache :: + * A charmap cache handle. + * + * face_id :: + * The source face ID. + * + * cmap_index :: + * The index of the charmap in the source face. Any negative value + * means to use the cache @FT_Face's default charmap. + * + * char_code :: + * The character code (in the corresponding charmap). + * + * @return: + * Glyph index. 0~means `no glyph'. + * + */ + FT_EXPORT( FT_UInt ) + FTC_CMapCache_Lookup( FTC_CMapCache cache, + FTC_FaceID face_id, + FT_Int cmap_index, + FT_UInt32 char_code ); + + + /*************************************************************************/ + /* */ + /* <Section> */ + /* cache_subsystem */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** IMAGE CACHE OBJECT *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + /************************************************************************* + * + * @struct: + * FTC_ImageTypeRec + * + * @description: + * A structure used to model the type of images in a glyph cache. + * + * @fields: + * face_id :: + * The face ID. + * + * width :: + * The width in pixels. + * + * height :: + * The height in pixels. + * + * flags :: + * The load flags, as in @FT_Load_Glyph. + * + */ + typedef struct FTC_ImageTypeRec_ + { + FTC_FaceID face_id; + FT_Int width; + FT_Int height; + FT_Int32 flags; + + } FTC_ImageTypeRec; + + + /************************************************************************* + * + * @type: + * FTC_ImageType + * + * @description: + * A handle to an @FTC_ImageTypeRec structure. + * + */ + typedef struct FTC_ImageTypeRec_* FTC_ImageType; + + + /* */ + + +#define FTC_IMAGE_TYPE_COMPARE( d1, d2 ) \ + ( (d1)->face_id == (d2)->face_id && \ + (d1)->width == (d2)->width && \ + (d1)->flags == (d2)->flags ) + +#ifdef FT_CONFIG_OPTION_OLD_INTERNALS + + /* this macro is incompatible with LLP64, should not be used */ + +#define FTC_IMAGE_TYPE_HASH( d ) \ + (FT_UFast)( FTC_FACE_ID_HASH( (d)->face_id ) ^ \ + ( (d)->width << 8 ) ^ (d)->height ^ \ + ( (d)->flags << 4 ) ) + +#endif /* FT_CONFIG_OPTION_OLD_INTERNALS */ + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FTC_ImageCache */ + /* */ + /* <Description> */ + /* A handle to an glyph image cache object. They are designed to */ + /* hold many distinct glyph images while not exceeding a certain */ + /* memory threshold. */ + /* */ + typedef struct FTC_ImageCacheRec_* FTC_ImageCache; + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FTC_ImageCache_New */ + /* */ + /* <Description> */ + /* Create a new glyph image cache. */ + /* */ + /* <Input> */ + /* manager :: The parent manager for the image cache. */ + /* */ + /* <Output> */ + /* acache :: A handle to the new glyph image cache object. */ + /* */ + /* <Return> */ + /* FreeType error code. 0~means success. */ + /* */ + FT_EXPORT( FT_Error ) + FTC_ImageCache_New( FTC_Manager manager, + FTC_ImageCache *acache ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FTC_ImageCache_Lookup */ + /* */ + /* <Description> */ + /* Retrieve a given glyph image from a glyph image cache. */ + /* */ + /* <Input> */ + /* cache :: A handle to the source glyph image cache. */ + /* */ + /* type :: A pointer to a glyph image type descriptor. */ + /* */ + /* gindex :: The glyph index to retrieve. */ + /* */ + /* <Output> */ + /* aglyph :: The corresponding @FT_Glyph object. 0~in case of */ + /* failure. */ + /* */ + /* anode :: Used to return the address of of the corresponding cache */ + /* node after incrementing its reference count (see note */ + /* below). */ + /* */ + /* <Return> */ + /* FreeType error code. 0~means success. */ + /* */ + /* <Note> */ + /* The returned glyph is owned and managed by the glyph image cache. */ + /* Never try to transform or discard it manually! You can however */ + /* create a copy with @FT_Glyph_Copy and modify the new one. */ + /* */ + /* If `anode' is _not_ NULL, it receives the address of the cache */ + /* node containing the glyph image, after increasing its reference */ + /* count. This ensures that the node (as well as the @FT_Glyph) will */ + /* always be kept in the cache until you call @FTC_Node_Unref to */ + /* `release' it. */ + /* */ + /* If `anode' is NULL, the cache node is left unchanged, which means */ + /* that the @FT_Glyph could be flushed out of the cache on the next */ + /* call to one of the caching sub-system APIs. Don't assume that it */ + /* is persistent! */ + /* */ + FT_EXPORT( FT_Error ) + FTC_ImageCache_Lookup( FTC_ImageCache cache, + FTC_ImageType type, + FT_UInt gindex, + FT_Glyph *aglyph, + FTC_Node *anode ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FTC_ImageCache_LookupScaler */ + /* */ + /* <Description> */ + /* A variant of @FTC_ImageCache_Lookup that uses an @FTC_ScalerRec */ + /* to specify the face ID and its size. */ + /* */ + /* <Input> */ + /* cache :: A handle to the source glyph image cache. */ + /* */ + /* scaler :: A pointer to a scaler descriptor. */ + /* */ + /* load_flags :: The corresponding load flags. */ + /* */ + /* gindex :: The glyph index to retrieve. */ + /* */ + /* <Output> */ + /* aglyph :: The corresponding @FT_Glyph object. 0~in case of */ + /* failure. */ + /* */ + /* anode :: Used to return the address of of the corresponding */ + /* cache node after incrementing its reference count */ + /* (see note below). */ + /* */ + /* <Return> */ + /* FreeType error code. 0~means success. */ + /* */ + /* <Note> */ + /* The returned glyph is owned and managed by the glyph image cache. */ + /* Never try to transform or discard it manually! You can however */ + /* create a copy with @FT_Glyph_Copy and modify the new one. */ + /* */ + /* If `anode' is _not_ NULL, it receives the address of the cache */ + /* node containing the glyph image, after increasing its reference */ + /* count. This ensures that the node (as well as the @FT_Glyph) will */ + /* always be kept in the cache until you call @FTC_Node_Unref to */ + /* `release' it. */ + /* */ + /* If `anode' is NULL, the cache node is left unchanged, which means */ + /* that the @FT_Glyph could be flushed out of the cache on the next */ + /* call to one of the caching sub-system APIs. Don't assume that it */ + /* is persistent! */ + /* */ + /* Calls to @FT_Set_Char_Size and friends have no effect on cached */ + /* glyphs; you should always use the FreeType cache API instead. */ + /* */ + FT_EXPORT( FT_Error ) + FTC_ImageCache_LookupScaler( FTC_ImageCache cache, + FTC_Scaler scaler, + FT_ULong load_flags, + FT_UInt gindex, + FT_Glyph *aglyph, + FTC_Node *anode ); + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FTC_SBit */ + /* */ + /* <Description> */ + /* A handle to a small bitmap descriptor. See the @FTC_SBitRec */ + /* structure for details. */ + /* */ + typedef struct FTC_SBitRec_* FTC_SBit; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FTC_SBitRec */ + /* */ + /* <Description> */ + /* A very compact structure used to describe a small glyph bitmap. */ + /* */ + /* <Fields> */ + /* width :: The bitmap width in pixels. */ + /* */ + /* height :: The bitmap height in pixels. */ + /* */ + /* left :: The horizontal distance from the pen position to the */ + /* left bitmap border (a.k.a. `left side bearing', or */ + /* `lsb'). */ + /* */ + /* top :: The vertical distance from the pen position (on the */ + /* baseline) to the upper bitmap border (a.k.a. `top */ + /* side bearing'). The distance is positive for upwards */ + /* y~coordinates. */ + /* */ + /* format :: The format of the glyph bitmap (monochrome or gray). */ + /* */ + /* max_grays :: Maximum gray level value (in the range 1 to~255). */ + /* */ + /* pitch :: The number of bytes per bitmap line. May be positive */ + /* or negative. */ + /* */ + /* xadvance :: The horizontal advance width in pixels. */ + /* */ + /* yadvance :: The vertical advance height in pixels. */ + /* */ + /* buffer :: A pointer to the bitmap pixels. */ + /* */ + typedef struct FTC_SBitRec_ + { + FT_Byte width; + FT_Byte height; + FT_Char left; + FT_Char top; + + FT_Byte format; + FT_Byte max_grays; + FT_Short pitch; + FT_Char xadvance; + FT_Char yadvance; + + FT_Byte* buffer; + + } FTC_SBitRec; + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FTC_SBitCache */ + /* */ + /* <Description> */ + /* A handle to a small bitmap cache. These are special cache objects */ + /* used to store small glyph bitmaps (and anti-aliased pixmaps) in a */ + /* much more efficient way than the traditional glyph image cache */ + /* implemented by @FTC_ImageCache. */ + /* */ + typedef struct FTC_SBitCacheRec_* FTC_SBitCache; + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FTC_SBitCache_New */ + /* */ + /* <Description> */ + /* Create a new cache to store small glyph bitmaps. */ + /* */ + /* <Input> */ + /* manager :: A handle to the source cache manager. */ + /* */ + /* <Output> */ + /* acache :: A handle to the new sbit cache. NULL in case of error. */ + /* */ + /* <Return> */ + /* FreeType error code. 0~means success. */ + /* */ + FT_EXPORT( FT_Error ) + FTC_SBitCache_New( FTC_Manager manager, + FTC_SBitCache *acache ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FTC_SBitCache_Lookup */ + /* */ + /* <Description> */ + /* Look up a given small glyph bitmap in a given sbit cache and */ + /* `lock' it to prevent its flushing from the cache until needed. */ + /* */ + /* <Input> */ + /* cache :: A handle to the source sbit cache. */ + /* */ + /* type :: A pointer to the glyph image type descriptor. */ + /* */ + /* gindex :: The glyph index. */ + /* */ + /* <Output> */ + /* sbit :: A handle to a small bitmap descriptor. */ + /* */ + /* anode :: Used to return the address of of the corresponding cache */ + /* node after incrementing its reference count (see note */ + /* below). */ + /* */ + /* <Return> */ + /* FreeType error code. 0~means success. */ + /* */ + /* <Note> */ + /* The small bitmap descriptor and its bit buffer are owned by the */ + /* cache and should never be freed by the application. They might */ + /* as well disappear from memory on the next cache lookup, so don't */ + /* treat them as persistent data. */ + /* */ + /* The descriptor's `buffer' field is set to~0 to indicate a missing */ + /* glyph bitmap. */ + /* */ + /* If `anode' is _not_ NULL, it receives the address of the cache */ + /* node containing the bitmap, after increasing its reference count. */ + /* This ensures that the node (as well as the image) will always be */ + /* kept in the cache until you call @FTC_Node_Unref to `release' it. */ + /* */ + /* If `anode' is NULL, the cache node is left unchanged, which means */ + /* that the bitmap could be flushed out of the cache on the next */ + /* call to one of the caching sub-system APIs. Don't assume that it */ + /* is persistent! */ + /* */ + FT_EXPORT( FT_Error ) + FTC_SBitCache_Lookup( FTC_SBitCache cache, + FTC_ImageType type, + FT_UInt gindex, + FTC_SBit *sbit, + FTC_Node *anode ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FTC_SBitCache_LookupScaler */ + /* */ + /* <Description> */ + /* A variant of @FTC_SBitCache_Lookup that uses an @FTC_ScalerRec */ + /* to specify the face ID and its size. */ + /* */ + /* <Input> */ + /* cache :: A handle to the source sbit cache. */ + /* */ + /* scaler :: A pointer to the scaler descriptor. */ + /* */ + /* load_flags :: The corresponding load flags. */ + /* */ + /* gindex :: The glyph index. */ + /* */ + /* <Output> */ + /* sbit :: A handle to a small bitmap descriptor. */ + /* */ + /* anode :: Used to return the address of of the corresponding */ + /* cache node after incrementing its reference count */ + /* (see note below). */ + /* */ + /* <Return> */ + /* FreeType error code. 0~means success. */ + /* */ + /* <Note> */ + /* The small bitmap descriptor and its bit buffer are owned by the */ + /* cache and should never be freed by the application. They might */ + /* as well disappear from memory on the next cache lookup, so don't */ + /* treat them as persistent data. */ + /* */ + /* The descriptor's `buffer' field is set to~0 to indicate a missing */ + /* glyph bitmap. */ + /* */ + /* If `anode' is _not_ NULL, it receives the address of the cache */ + /* node containing the bitmap, after increasing its reference count. */ + /* This ensures that the node (as well as the image) will always be */ + /* kept in the cache until you call @FTC_Node_Unref to `release' it. */ + /* */ + /* If `anode' is NULL, the cache node is left unchanged, which means */ + /* that the bitmap could be flushed out of the cache on the next */ + /* call to one of the caching sub-system APIs. Don't assume that it */ + /* is persistent! */ + /* */ + FT_EXPORT( FT_Error ) + FTC_SBitCache_LookupScaler( FTC_SBitCache cache, + FTC_Scaler scaler, + FT_ULong load_flags, + FT_UInt gindex, + FTC_SBit *sbit, + FTC_Node *anode ); + + + /* */ + +#ifdef FT_CONFIG_OPTION_OLD_INTERNALS + + /*@***********************************************************************/ + /* */ + /* <Struct> */ + /* FTC_FontRec */ + /* */ + /* <Description> */ + /* A simple structure used to describe a given `font' to the cache */ + /* manager. Note that a `font' is the combination of a given face */ + /* with a given character size. */ + /* */ + /* <Fields> */ + /* face_id :: The ID of the face to use. */ + /* */ + /* pix_width :: The character width in integer pixels. */ + /* */ + /* pix_height :: The character height in integer pixels. */ + /* */ + typedef struct FTC_FontRec_ + { + FTC_FaceID face_id; + FT_UShort pix_width; + FT_UShort pix_height; + + } FTC_FontRec; + + + /* */ + + +#define FTC_FONT_COMPARE( f1, f2 ) \ + ( (f1)->face_id == (f2)->face_id && \ + (f1)->pix_width == (f2)->pix_width && \ + (f1)->pix_height == (f2)->pix_height ) + + /* this macro is incompatible with LLP64, should not be used */ +#define FTC_FONT_HASH( f ) \ + (FT_UInt32)( FTC_FACE_ID_HASH((f)->face_id) ^ \ + ((f)->pix_width << 8) ^ \ + ((f)->pix_height) ) + + typedef FTC_FontRec* FTC_Font; + + + FT_EXPORT( FT_Error ) + FTC_Manager_Lookup_Face( FTC_Manager manager, + FTC_FaceID face_id, + FT_Face *aface ); + + FT_EXPORT( FT_Error ) + FTC_Manager_Lookup_Size( FTC_Manager manager, + FTC_Font font, + FT_Face *aface, + FT_Size *asize ); + +#endif /* FT_CONFIG_OPTION_OLD_INTERNALS */ + + + /* */ + +FT_END_HEADER + +#endif /* __FTCACHE_H__ */ + + +/* END */ diff --git a/Lib/Include/freetype/ftchapters.h b/Lib/Include/freetype/ftchapters.h new file mode 100644 index 0000000..7775a6b --- /dev/null +++ b/Lib/Include/freetype/ftchapters.h @@ -0,0 +1,103 @@ +/***************************************************************************/ +/* */ +/* This file defines the structure of the FreeType reference. */ +/* It is used by the python script which generates the HTML files. */ +/* */ +/***************************************************************************/ + + +/***************************************************************************/ +/* */ +/* <Chapter> */ +/* general_remarks */ +/* */ +/* <Title> */ +/* General Remarks */ +/* */ +/* <Sections> */ +/* user_allocation */ +/* */ +/***************************************************************************/ + + +/***************************************************************************/ +/* */ +/* <Chapter> */ +/* core_api */ +/* */ +/* <Title> */ +/* Core API */ +/* */ +/* <Sections> */ +/* version */ +/* basic_types */ +/* base_interface */ +/* glyph_variants */ +/* glyph_management */ +/* mac_specific */ +/* sizes_management */ +/* header_file_macros */ +/* */ +/***************************************************************************/ + + +/***************************************************************************/ +/* */ +/* <Chapter> */ +/* format_specific */ +/* */ +/* <Title> */ +/* Format-Specific API */ +/* */ +/* <Sections> */ +/* multiple_masters */ +/* truetype_tables */ +/* type1_tables */ +/* sfnt_names */ +/* bdf_fonts */ +/* cid_fonts */ +/* pfr_fonts */ +/* winfnt_fonts */ +/* font_formats */ +/* gasp_table */ +/* */ +/***************************************************************************/ + + +/***************************************************************************/ +/* */ +/* <Chapter> */ +/* cache_subsystem */ +/* */ +/* <Title> */ +/* Cache Sub-System */ +/* */ +/* <Sections> */ +/* cache_subsystem */ +/* */ +/***************************************************************************/ + + +/***************************************************************************/ +/* */ +/* <Chapter> */ +/* support_api */ +/* */ +/* <Title> */ +/* Support API */ +/* */ +/* <Sections> */ +/* computations */ +/* list_processing */ +/* outline_processing */ +/* quick_advance */ +/* bitmap_handling */ +/* raster */ +/* glyph_stroker */ +/* system_interface */ +/* module_management */ +/* gzip */ +/* lzw */ +/* lcd_filtering */ +/* */ +/***************************************************************************/ diff --git a/Lib/Include/freetype/ftcid.h b/Lib/Include/freetype/ftcid.h new file mode 100644 index 0000000..203a30c --- /dev/null +++ b/Lib/Include/freetype/ftcid.h @@ -0,0 +1,166 @@ +/***************************************************************************/ +/* */ +/* ftcid.h */ +/* */ +/* FreeType API for accessing CID font information (specification). */ +/* */ +/* Copyright 2007, 2009 by Dereg Clegg, Michael Toftdal. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef __FTCID_H__ +#define __FTCID_H__ + +#include <ft2build.h> +#include FT_FREETYPE_H + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /* */ + /* <Section> */ + /* cid_fonts */ + /* */ + /* <Title> */ + /* CID Fonts */ + /* */ + /* <Abstract> */ + /* CID-keyed font specific API. */ + /* */ + /* <Description> */ + /* This section contains the declaration of CID-keyed font specific */ + /* functions. */ + /* */ + /*************************************************************************/ + + + /********************************************************************** + * + * @function: + * FT_Get_CID_Registry_Ordering_Supplement + * + * @description: + * Retrieve the Registry/Ordering/Supplement triple (also known as the + * "R/O/S") from a CID-keyed font. + * + * @input: + * face :: + * A handle to the input face. + * + * @output: + * registry :: + * The registry, as a C~string, owned by the face. + * + * ordering :: + * The ordering, as a C~string, owned by the face. + * + * supplement :: + * The supplement. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * This function only works with CID faces, returning an error + * otherwise. + * + * @since: + * 2.3.6 + */ + FT_EXPORT( FT_Error ) + FT_Get_CID_Registry_Ordering_Supplement( FT_Face face, + const char* *registry, + const char* *ordering, + FT_Int *supplement); + + + /********************************************************************** + * + * @function: + * FT_Get_CID_Is_Internally_CID_Keyed + * + * @description: + * Retrieve the type of the input face, CID keyed or not. In + * constrast to the @FT_IS_CID_KEYED macro this function returns + * successfully also for CID-keyed fonts in an SNFT wrapper. + * + * @input: + * face :: + * A handle to the input face. + * + * @output: + * is_cid :: + * The type of the face as an @FT_Bool. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * This function only works with CID faces and OpenType fonts, + * returning an error otherwise. + * + * @since: + * 2.3.9 + */ + FT_EXPORT( FT_Error ) + FT_Get_CID_Is_Internally_CID_Keyed( FT_Face face, + FT_Bool *is_cid ); + + + /********************************************************************** + * + * @function: + * FT_Get_CID_From_Glyph_Index + * + * @description: + * Retrieve the CID of the input glyph index. + * + * @input: + * face :: + * A handle to the input face. + * + * glyph_index :: + * The input glyph index. + * + * @output: + * cid :: + * The CID as an @FT_UInt. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * This function only works with CID faces and OpenType fonts, + * returning an error otherwise. + * + * @since: + * 2.3.9 + */ + FT_EXPORT( FT_Error ) + FT_Get_CID_From_Glyph_Index( FT_Face face, + FT_UInt glyph_index, + FT_UInt *cid ); + + /* */ + +FT_END_HEADER + +#endif /* __FTCID_H__ */ + + +/* END */ diff --git a/Lib/Include/freetype/fterrdef.h b/Lib/Include/freetype/fterrdef.h new file mode 100644 index 0000000..bf52220 --- /dev/null +++ b/Lib/Include/freetype/fterrdef.h @@ -0,0 +1,244 @@ +/***************************************************************************/ +/* */ +/* fterrdef.h */ +/* */ +/* FreeType error codes (specification). */ +/* */ +/* Copyright 2002, 2004, 2006, 2007, 2010 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + + /*******************************************************************/ + /*******************************************************************/ + /***** *****/ + /***** LIST OF ERROR CODES/MESSAGES *****/ + /***** *****/ + /*******************************************************************/ + /*******************************************************************/ + + + /* You need to define both FT_ERRORDEF_ and FT_NOERRORDEF_ before */ + /* including this file. */ + + + /* generic errors */ + + FT_NOERRORDEF_( Ok, 0x00, \ + "no error" ) + + FT_ERRORDEF_( Cannot_Open_Resource, 0x01, \ + "cannot open resource" ) + FT_ERRORDEF_( Unknown_File_Format, 0x02, \ + "unknown file format" ) + FT_ERRORDEF_( Invalid_File_Format, 0x03, \ + "broken file" ) + FT_ERRORDEF_( Invalid_Version, 0x04, \ + "invalid FreeType version" ) + FT_ERRORDEF_( Lower_Module_Version, 0x05, \ + "module version is too low" ) + FT_ERRORDEF_( Invalid_Argument, 0x06, \ + "invalid argument" ) + FT_ERRORDEF_( Unimplemented_Feature, 0x07, \ + "unimplemented feature" ) + FT_ERRORDEF_( Invalid_Table, 0x08, \ + "broken table" ) + FT_ERRORDEF_( Invalid_Offset, 0x09, \ + "broken offset within table" ) + FT_ERRORDEF_( Array_Too_Large, 0x0A, \ + "array allocation size too large" ) + + /* glyph/character errors */ + + FT_ERRORDEF_( Invalid_Glyph_Index, 0x10, \ + "invalid glyph index" ) + FT_ERRORDEF_( Invalid_Character_Code, 0x11, \ + "invalid character code" ) + FT_ERRORDEF_( Invalid_Glyph_Format, 0x12, \ + "unsupported glyph image format" ) + FT_ERRORDEF_( Cannot_Render_Glyph, 0x13, \ + "cannot render this glyph format" ) + FT_ERRORDEF_( Invalid_Outline, 0x14, \ + "invalid outline" ) + FT_ERRORDEF_( Invalid_Composite, 0x15, \ + "invalid composite glyph" ) + FT_ERRORDEF_( Too_Many_Hints, 0x16, \ + "too many hints" ) + FT_ERRORDEF_( Invalid_Pixel_Size, 0x17, \ + "invalid pixel size" ) + + /* handle errors */ + + FT_ERRORDEF_( Invalid_Handle, 0x20, \ + "invalid object handle" ) + FT_ERRORDEF_( Invalid_Library_Handle, 0x21, \ + "invalid library handle" ) + FT_ERRORDEF_( Invalid_Driver_Handle, 0x22, \ + "invalid module handle" ) + FT_ERRORDEF_( Invalid_Face_Handle, 0x23, \ + "invalid face handle" ) + FT_ERRORDEF_( Invalid_Size_Handle, 0x24, \ + "invalid size handle" ) + FT_ERRORDEF_( Invalid_Slot_Handle, 0x25, \ + "invalid glyph slot handle" ) + FT_ERRORDEF_( Invalid_CharMap_Handle, 0x26, \ + "invalid charmap handle" ) + FT_ERRORDEF_( Invalid_Cache_Handle, 0x27, \ + "invalid cache manager handle" ) + FT_ERRORDEF_( Invalid_Stream_Handle, 0x28, \ + "invalid stream handle" ) + + /* driver errors */ + + FT_ERRORDEF_( Too_Many_Drivers, 0x30, \ + "too many modules" ) + FT_ERRORDEF_( Too_Many_Extensions, 0x31, \ + "too many extensions" ) + + /* memory errors */ + + FT_ERRORDEF_( Out_Of_Memory, 0x40, \ + "out of memory" ) + FT_ERRORDEF_( Unlisted_Object, 0x41, \ + "unlisted object" ) + + /* stream errors */ + + FT_ERRORDEF_( Cannot_Open_Stream, 0x51, \ + "cannot open stream" ) + FT_ERRORDEF_( Invalid_Stream_Seek, 0x52, \ + "invalid stream seek" ) + FT_ERRORDEF_( Invalid_Stream_Skip, 0x53, \ + "invalid stream skip" ) + FT_ERRORDEF_( Invalid_Stream_Read, 0x54, \ + "invalid stream read" ) + FT_ERRORDEF_( Invalid_Stream_Operation, 0x55, \ + "invalid stream operation" ) + FT_ERRORDEF_( Invalid_Frame_Operation, 0x56, \ + "invalid frame operation" ) + FT_ERRORDEF_( Nested_Frame_Access, 0x57, \ + "nested frame access" ) + FT_ERRORDEF_( Invalid_Frame_Read, 0x58, \ + "invalid frame read" ) + + /* raster errors */ + + FT_ERRORDEF_( Raster_Uninitialized, 0x60, \ + "raster uninitialized" ) + FT_ERRORDEF_( Raster_Corrupted, 0x61, \ + "raster corrupted" ) + FT_ERRORDEF_( Raster_Overflow, 0x62, \ + "raster overflow" ) + FT_ERRORDEF_( Raster_Negative_Height, 0x63, \ + "negative height while rastering" ) + + /* cache errors */ + + FT_ERRORDEF_( Too_Many_Caches, 0x70, \ + "too many registered caches" ) + + /* TrueType and SFNT errors */ + + FT_ERRORDEF_( Invalid_Opcode, 0x80, \ + "invalid opcode" ) + FT_ERRORDEF_( Too_Few_Arguments, 0x81, \ + "too few arguments" ) + FT_ERRORDEF_( Stack_Overflow, 0x82, \ + "stack overflow" ) + FT_ERRORDEF_( Code_Overflow, 0x83, \ + "code overflow" ) + FT_ERRORDEF_( Bad_Argument, 0x84, \ + "bad argument" ) + FT_ERRORDEF_( Divide_By_Zero, 0x85, \ + "division by zero" ) + FT_ERRORDEF_( Invalid_Reference, 0x86, \ + "invalid reference" ) + FT_ERRORDEF_( Debug_OpCode, 0x87, \ + "found debug opcode" ) + FT_ERRORDEF_( ENDF_In_Exec_Stream, 0x88, \ + "found ENDF opcode in execution stream" ) + FT_ERRORDEF_( Nested_DEFS, 0x89, \ + "nested DEFS" ) + FT_ERRORDEF_( Invalid_CodeRange, 0x8A, \ + "invalid code range" ) + FT_ERRORDEF_( Execution_Too_Long, 0x8B, \ + "execution context too long" ) + FT_ERRORDEF_( Too_Many_Function_Defs, 0x8C, \ + "too many function definitions" ) + FT_ERRORDEF_( Too_Many_Instruction_Defs, 0x8D, \ + "too many instruction definitions" ) + FT_ERRORDEF_( Table_Missing, 0x8E, \ + "SFNT font table missing" ) + FT_ERRORDEF_( Horiz_Header_Missing, 0x8F, \ + "horizontal header (hhea) table missing" ) + FT_ERRORDEF_( Locations_Missing, 0x90, \ + "locations (loca) table missing" ) + FT_ERRORDEF_( Name_Table_Missing, 0x91, \ + "name table missing" ) + FT_ERRORDEF_( CMap_Table_Missing, 0x92, \ + "character map (cmap) table missing" ) + FT_ERRORDEF_( Hmtx_Table_Missing, 0x93, \ + "horizontal metrics (hmtx) table missing" ) + FT_ERRORDEF_( Post_Table_Missing, 0x94, \ + "PostScript (post) table missing" ) + FT_ERRORDEF_( Invalid_Horiz_Metrics, 0x95, \ + "invalid horizontal metrics" ) + FT_ERRORDEF_( Invalid_CharMap_Format, 0x96, \ + "invalid character map (cmap) format" ) + FT_ERRORDEF_( Invalid_PPem, 0x97, \ + "invalid ppem value" ) + FT_ERRORDEF_( Invalid_Vert_Metrics, 0x98, \ + "invalid vertical metrics" ) + FT_ERRORDEF_( Could_Not_Find_Context, 0x99, \ + "could not find context" ) + FT_ERRORDEF_( Invalid_Post_Table_Format, 0x9A, \ + "invalid PostScript (post) table format" ) + FT_ERRORDEF_( Invalid_Post_Table, 0x9B, \ + "invalid PostScript (post) table" ) + + /* CFF, CID, and Type 1 errors */ + + FT_ERRORDEF_( Syntax_Error, 0xA0, \ + "opcode syntax error" ) + FT_ERRORDEF_( Stack_Underflow, 0xA1, \ + "argument stack underflow" ) + FT_ERRORDEF_( Ignore, 0xA2, \ + "ignore" ) + FT_ERRORDEF_( No_Unicode_Glyph_Name, 0xA3, \ + "no Unicode glyph name found" ) + + + /* BDF errors */ + + FT_ERRORDEF_( Missing_Startfont_Field, 0xB0, \ + "`STARTFONT' field missing" ) + FT_ERRORDEF_( Missing_Font_Field, 0xB1, \ + "`FONT' field missing" ) + FT_ERRORDEF_( Missing_Size_Field, 0xB2, \ + "`SIZE' field missing" ) + FT_ERRORDEF_( Missing_Fontboundingbox_Field, 0xB3, \ + "`FONTBOUNDINGBOX' field missing" ) + FT_ERRORDEF_( Missing_Chars_Field, 0xB4, \ + "`CHARS' field missing" ) + FT_ERRORDEF_( Missing_Startchar_Field, 0xB5, \ + "`STARTCHAR' field missing" ) + FT_ERRORDEF_( Missing_Encoding_Field, 0xB6, \ + "`ENCODING' field missing" ) + FT_ERRORDEF_( Missing_Bbx_Field, 0xB7, \ + "`BBX' field missing" ) + FT_ERRORDEF_( Bbx_Too_Big, 0xB8, \ + "`BBX' too big" ) + FT_ERRORDEF_( Corrupted_Font_Header, 0xB9, \ + "Font header corrupted or missing fields" ) + FT_ERRORDEF_( Corrupted_Font_Glyphs, 0xBA, \ + "Font glyphs corrupted or missing fields" ) + + +/* END */ diff --git a/Lib/Include/freetype/fterrors.h b/Lib/Include/freetype/fterrors.h new file mode 100644 index 0000000..6600dad --- /dev/null +++ b/Lib/Include/freetype/fterrors.h @@ -0,0 +1,206 @@ +/***************************************************************************/ +/* */ +/* fterrors.h */ +/* */ +/* FreeType error code handling (specification). */ +/* */ +/* Copyright 1996-2001, 2002, 2004, 2007 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + + /*************************************************************************/ + /* */ + /* This special header file is used to define the handling of FT2 */ + /* enumeration constants. It can also be used to generate error message */ + /* strings with a small macro trick explained below. */ + /* */ + /* I - Error Formats */ + /* ----------------- */ + /* */ + /* The configuration macro FT_CONFIG_OPTION_USE_MODULE_ERRORS can be */ + /* defined in ftoption.h in order to make the higher byte indicate */ + /* the module where the error has happened (this is not compatible */ + /* with standard builds of FreeType 2). You can then use the macro */ + /* FT_ERROR_BASE macro to extract the generic error code from an */ + /* FT_Error value. */ + /* */ + /* */ + /* II - Error Message strings */ + /* -------------------------- */ + /* */ + /* The error definitions below are made through special macros that */ + /* allow client applications to build a table of error message strings */ + /* if they need it. The strings are not included in a normal build of */ + /* FreeType 2 to save space (most client applications do not use */ + /* them). */ + /* */ + /* To do so, you have to define the following macros before including */ + /* this file: */ + /* */ + /* FT_ERROR_START_LIST :: */ + /* This macro is called before anything else to define the start of */ + /* the error list. It is followed by several FT_ERROR_DEF calls */ + /* (see below). */ + /* */ + /* FT_ERROR_DEF( e, v, s ) :: */ + /* This macro is called to define one single error. */ + /* `e' is the error code identifier (e.g. FT_Err_Invalid_Argument). */ + /* `v' is the error numerical value. */ + /* `s' is the corresponding error string. */ + /* */ + /* FT_ERROR_END_LIST :: */ + /* This macro ends the list. */ + /* */ + /* Additionally, you have to undefine __FTERRORS_H__ before #including */ + /* this file. */ + /* */ + /* Here is a simple example: */ + /* */ + /* { */ + /* #undef __FTERRORS_H__ */ + /* #define FT_ERRORDEF( e, v, s ) { e, s }, */ + /* #define FT_ERROR_START_LIST { */ + /* #define FT_ERROR_END_LIST { 0, 0 } }; */ + /* */ + /* const struct */ + /* { */ + /* int err_code; */ + /* const char* err_msg; */ + /* } ft_errors[] = */ + /* */ + /* #include FT_ERRORS_H */ + /* } */ + /* */ + /*************************************************************************/ + + +#ifndef __FTERRORS_H__ +#define __FTERRORS_H__ + + + /* include module base error codes */ +#include FT_MODULE_ERRORS_H + + + /*******************************************************************/ + /*******************************************************************/ + /***** *****/ + /***** SETUP MACROS *****/ + /***** *****/ + /*******************************************************************/ + /*******************************************************************/ + + +#undef FT_NEED_EXTERN_C + +#undef FT_ERR_XCAT +#undef FT_ERR_CAT + +#define FT_ERR_XCAT( x, y ) x ## y +#define FT_ERR_CAT( x, y ) FT_ERR_XCAT( x, y ) + + + /* FT_ERR_PREFIX is used as a prefix for error identifiers. */ + /* By default, we use `FT_Err_'. */ + /* */ +#ifndef FT_ERR_PREFIX +#define FT_ERR_PREFIX FT_Err_ +#endif + + + /* FT_ERR_BASE is used as the base for module-specific errors. */ + /* */ +#ifdef FT_CONFIG_OPTION_USE_MODULE_ERRORS + +#ifndef FT_ERR_BASE +#define FT_ERR_BASE FT_Mod_Err_Base +#endif + +#else + +#undef FT_ERR_BASE +#define FT_ERR_BASE 0 + +#endif /* FT_CONFIG_OPTION_USE_MODULE_ERRORS */ + + + /* If FT_ERRORDEF is not defined, we need to define a simple */ + /* enumeration type. */ + /* */ +#ifndef FT_ERRORDEF + +#define FT_ERRORDEF( e, v, s ) e = v, +#define FT_ERROR_START_LIST enum { +#define FT_ERROR_END_LIST FT_ERR_CAT( FT_ERR_PREFIX, Max ) }; + +#ifdef __cplusplus +#define FT_NEED_EXTERN_C + extern "C" { +#endif + +#endif /* !FT_ERRORDEF */ + + + /* this macro is used to define an error */ +#define FT_ERRORDEF_( e, v, s ) \ + FT_ERRORDEF( FT_ERR_CAT( FT_ERR_PREFIX, e ), v + FT_ERR_BASE, s ) + + /* this is only used for <module>_Err_Ok, which must be 0! */ +#define FT_NOERRORDEF_( e, v, s ) \ + FT_ERRORDEF( FT_ERR_CAT( FT_ERR_PREFIX, e ), v, s ) + + +#ifdef FT_ERROR_START_LIST + FT_ERROR_START_LIST +#endif + + + /* now include the error codes */ +#include FT_ERROR_DEFINITIONS_H + + +#ifdef FT_ERROR_END_LIST + FT_ERROR_END_LIST +#endif + + + /*******************************************************************/ + /*******************************************************************/ + /***** *****/ + /***** SIMPLE CLEANUP *****/ + /***** *****/ + /*******************************************************************/ + /*******************************************************************/ + +#ifdef FT_NEED_EXTERN_C + } +#endif + +#undef FT_ERROR_START_LIST +#undef FT_ERROR_END_LIST + +#undef FT_ERRORDEF +#undef FT_ERRORDEF_ +#undef FT_NOERRORDEF_ + +#undef FT_NEED_EXTERN_C +#undef FT_ERR_CONCAT +#undef FT_ERR_BASE + + /* FT_KEEP_ERR_PREFIX is needed for ftvalid.h */ +#ifndef FT_KEEP_ERR_PREFIX +#undef FT_ERR_PREFIX +#endif + +#endif /* __FTERRORS_H__ */ + + +/* END */ diff --git a/Lib/Include/freetype/ftgasp.h b/Lib/Include/freetype/ftgasp.h new file mode 100644 index 0000000..91a769e --- /dev/null +++ b/Lib/Include/freetype/ftgasp.h @@ -0,0 +1,120 @@ +/***************************************************************************/ +/* */ +/* ftgasp.h */ +/* */ +/* Access of TrueType's `gasp' table (specification). */ +/* */ +/* Copyright 2007, 2008 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef _FT_GASP_H_ +#define _FT_GASP_H_ + +#include <ft2build.h> +#include FT_FREETYPE_H + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + + /*************************************************************************** + * + * @section: + * gasp_table + * + * @title: + * Gasp Table + * + * @abstract: + * Retrieving TrueType `gasp' table entries. + * + * @description: + * The function @FT_Get_Gasp can be used to query a TrueType or OpenType + * font for specific entries in its `gasp' table, if any. This is + * mainly useful when implementing native TrueType hinting with the + * bytecode interpreter to duplicate the Windows text rendering results. + */ + + /************************************************************************* + * + * @enum: + * FT_GASP_XXX + * + * @description: + * A list of values and/or bit-flags returned by the @FT_Get_Gasp + * function. + * + * @values: + * FT_GASP_NO_TABLE :: + * This special value means that there is no GASP table in this face. + * It is up to the client to decide what to do. + * + * FT_GASP_DO_GRIDFIT :: + * Grid-fitting and hinting should be performed at the specified ppem. + * This *really* means TrueType bytecode interpretation. + * + * FT_GASP_DO_GRAY :: + * Anti-aliased rendering should be performed at the specified ppem. + * + * FT_GASP_SYMMETRIC_SMOOTHING :: + * Smoothing along multiple axes must be used with ClearType. + * + * FT_GASP_SYMMETRIC_GRIDFIT :: + * Grid-fitting must be used with ClearType's symmetric smoothing. + * + * @note: + * `ClearType' is Microsoft's implementation of LCD rendering, partly + * protected by patents. + * + * @since: + * 2.3.0 + */ +#define FT_GASP_NO_TABLE -1 +#define FT_GASP_DO_GRIDFIT 0x01 +#define FT_GASP_DO_GRAY 0x02 +#define FT_GASP_SYMMETRIC_SMOOTHING 0x08 +#define FT_GASP_SYMMETRIC_GRIDFIT 0x10 + + + /************************************************************************* + * + * @func: + * FT_Get_Gasp + * + * @description: + * Read the `gasp' table from a TrueType or OpenType font file and + * return the entry corresponding to a given character pixel size. + * + * @input: + * face :: The source face handle. + * ppem :: The vertical character pixel size. + * + * @return: + * Bit flags (see @FT_GASP_XXX), or @FT_GASP_NO_TABLE if there is no + * `gasp' table in the face. + * + * @since: + * 2.3.0 + */ + FT_EXPORT( FT_Int ) + FT_Get_Gasp( FT_Face face, + FT_UInt ppem ); + +/* */ + +#endif /* _FT_GASP_H_ */ + + +/* END */ diff --git a/Lib/Include/freetype/ftglyph.h b/Lib/Include/freetype/ftglyph.h new file mode 100644 index 0000000..9b5c2eb --- /dev/null +++ b/Lib/Include/freetype/ftglyph.h @@ -0,0 +1,613 @@ +/***************************************************************************/ +/* */ +/* ftglyph.h */ +/* */ +/* FreeType convenience functions to handle glyphs (specification). */ +/* */ +/* Copyright 1996-2001, 2002, 2003, 2006, 2008, 2009 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + + /*************************************************************************/ + /* */ + /* This file contains the definition of several convenience functions */ + /* that can be used by client applications to easily retrieve glyph */ + /* bitmaps and outlines from a given face. */ + /* */ + /* These functions should be optional if you are writing a font server */ + /* or text layout engine on top of FreeType. However, they are pretty */ + /* handy for many other simple uses of the library. */ + /* */ + /*************************************************************************/ + + +#ifndef __FTGLYPH_H__ +#define __FTGLYPH_H__ + + +#include <ft2build.h> +#include FT_FREETYPE_H + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /* */ + /* <Section> */ + /* glyph_management */ + /* */ + /* <Title> */ + /* Glyph Management */ + /* */ + /* <Abstract> */ + /* Generic interface to manage individual glyph data. */ + /* */ + /* <Description> */ + /* This section contains definitions used to manage glyph data */ + /* through generic FT_Glyph objects. Each of them can contain a */ + /* bitmap, a vector outline, or even images in other formats. */ + /* */ + /*************************************************************************/ + + + /* forward declaration to a private type */ + typedef struct FT_Glyph_Class_ FT_Glyph_Class; + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_Glyph */ + /* */ + /* <Description> */ + /* Handle to an object used to model generic glyph images. It is a */ + /* pointer to the @FT_GlyphRec structure and can contain a glyph */ + /* bitmap or pointer. */ + /* */ + /* <Note> */ + /* Glyph objects are not owned by the library. You must thus release */ + /* them manually (through @FT_Done_Glyph) _before_ calling */ + /* @FT_Done_FreeType. */ + /* */ + typedef struct FT_GlyphRec_* FT_Glyph; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_GlyphRec */ + /* */ + /* <Description> */ + /* The root glyph structure contains a given glyph image plus its */ + /* advance width in 16.16 fixed float format. */ + /* */ + /* <Fields> */ + /* library :: A handle to the FreeType library object. */ + /* */ + /* clazz :: A pointer to the glyph's class. Private. */ + /* */ + /* format :: The format of the glyph's image. */ + /* */ + /* advance :: A 16.16 vector that gives the glyph's advance width. */ + /* */ + typedef struct FT_GlyphRec_ + { + FT_Library library; + const FT_Glyph_Class* clazz; + FT_Glyph_Format format; + FT_Vector advance; + + } FT_GlyphRec; + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_BitmapGlyph */ + /* */ + /* <Description> */ + /* A handle to an object used to model a bitmap glyph image. This is */ + /* a sub-class of @FT_Glyph, and a pointer to @FT_BitmapGlyphRec. */ + /* */ + typedef struct FT_BitmapGlyphRec_* FT_BitmapGlyph; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_BitmapGlyphRec */ + /* */ + /* <Description> */ + /* A structure used for bitmap glyph images. This really is a */ + /* `sub-class' of @FT_GlyphRec. */ + /* */ + /* <Fields> */ + /* root :: The root @FT_Glyph fields. */ + /* */ + /* left :: The left-side bearing, i.e., the horizontal distance */ + /* from the current pen position to the left border of the */ + /* glyph bitmap. */ + /* */ + /* top :: The top-side bearing, i.e., the vertical distance from */ + /* the current pen position to the top border of the glyph */ + /* bitmap. This distance is positive for upwards~y! */ + /* */ + /* bitmap :: A descriptor for the bitmap. */ + /* */ + /* <Note> */ + /* You can typecast an @FT_Glyph to @FT_BitmapGlyph if you have */ + /* `glyph->format == FT_GLYPH_FORMAT_BITMAP'. This lets you access */ + /* the bitmap's contents easily. */ + /* */ + /* The corresponding pixel buffer is always owned by @FT_BitmapGlyph */ + /* and is thus created and destroyed with it. */ + /* */ + typedef struct FT_BitmapGlyphRec_ + { + FT_GlyphRec root; + FT_Int left; + FT_Int top; + FT_Bitmap bitmap; + + } FT_BitmapGlyphRec; + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_OutlineGlyph */ + /* */ + /* <Description> */ + /* A handle to an object used to model an outline glyph image. This */ + /* is a sub-class of @FT_Glyph, and a pointer to @FT_OutlineGlyphRec. */ + /* */ + typedef struct FT_OutlineGlyphRec_* FT_OutlineGlyph; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_OutlineGlyphRec */ + /* */ + /* <Description> */ + /* A structure used for outline (vectorial) glyph images. This */ + /* really is a `sub-class' of @FT_GlyphRec. */ + /* */ + /* <Fields> */ + /* root :: The root @FT_Glyph fields. */ + /* */ + /* outline :: A descriptor for the outline. */ + /* */ + /* <Note> */ + /* You can typecast an @FT_Glyph to @FT_OutlineGlyph if you have */ + /* `glyph->format == FT_GLYPH_FORMAT_OUTLINE'. This lets you access */ + /* the outline's content easily. */ + /* */ + /* As the outline is extracted from a glyph slot, its coordinates are */ + /* expressed normally in 26.6 pixels, unless the flag */ + /* @FT_LOAD_NO_SCALE was used in @FT_Load_Glyph() or @FT_Load_Char(). */ + /* */ + /* The outline's tables are always owned by the object and are */ + /* destroyed with it. */ + /* */ + typedef struct FT_OutlineGlyphRec_ + { + FT_GlyphRec root; + FT_Outline outline; + + } FT_OutlineGlyphRec; + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Get_Glyph */ + /* */ + /* <Description> */ + /* A function used to extract a glyph image from a slot. Note that */ + /* the created @FT_Glyph object must be released with @FT_Done_Glyph. */ + /* */ + /* <Input> */ + /* slot :: A handle to the source glyph slot. */ + /* */ + /* <Output> */ + /* aglyph :: A handle to the glyph object. */ + /* */ + /* <Return> */ + /* FreeType error code. 0~means success. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Get_Glyph( FT_GlyphSlot slot, + FT_Glyph *aglyph ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Glyph_Copy */ + /* */ + /* <Description> */ + /* A function used to copy a glyph image. Note that the created */ + /* @FT_Glyph object must be released with @FT_Done_Glyph. */ + /* */ + /* <Input> */ + /* source :: A handle to the source glyph object. */ + /* */ + /* <Output> */ + /* target :: A handle to the target glyph object. 0~in case of */ + /* error. */ + /* */ + /* <Return> */ + /* FreeType error code. 0~means success. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Glyph_Copy( FT_Glyph source, + FT_Glyph *target ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Glyph_Transform */ + /* */ + /* <Description> */ + /* Transform a glyph image if its format is scalable. */ + /* */ + /* <InOut> */ + /* glyph :: A handle to the target glyph object. */ + /* */ + /* <Input> */ + /* matrix :: A pointer to a 2x2 matrix to apply. */ + /* */ + /* delta :: A pointer to a 2d vector to apply. Coordinates are */ + /* expressed in 1/64th of a pixel. */ + /* */ + /* <Return> */ + /* FreeType error code (if not 0, the glyph format is not scalable). */ + /* */ + /* <Note> */ + /* The 2x2 transformation matrix is also applied to the glyph's */ + /* advance vector. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Glyph_Transform( FT_Glyph glyph, + FT_Matrix* matrix, + FT_Vector* delta ); + + + /*************************************************************************/ + /* */ + /* <Enum> */ + /* FT_Glyph_BBox_Mode */ + /* */ + /* <Description> */ + /* The mode how the values of @FT_Glyph_Get_CBox are returned. */ + /* */ + /* <Values> */ + /* FT_GLYPH_BBOX_UNSCALED :: */ + /* Return unscaled font units. */ + /* */ + /* FT_GLYPH_BBOX_SUBPIXELS :: */ + /* Return unfitted 26.6 coordinates. */ + /* */ + /* FT_GLYPH_BBOX_GRIDFIT :: */ + /* Return grid-fitted 26.6 coordinates. */ + /* */ + /* FT_GLYPH_BBOX_TRUNCATE :: */ + /* Return coordinates in integer pixels. */ + /* */ + /* FT_GLYPH_BBOX_PIXELS :: */ + /* Return grid-fitted pixel coordinates. */ + /* */ + typedef enum FT_Glyph_BBox_Mode_ + { + FT_GLYPH_BBOX_UNSCALED = 0, + FT_GLYPH_BBOX_SUBPIXELS = 0, + FT_GLYPH_BBOX_GRIDFIT = 1, + FT_GLYPH_BBOX_TRUNCATE = 2, + FT_GLYPH_BBOX_PIXELS = 3 + + } FT_Glyph_BBox_Mode; + + + /*************************************************************************/ + /* */ + /* <Enum> */ + /* ft_glyph_bbox_xxx */ + /* */ + /* <Description> */ + /* These constants are deprecated. Use the corresponding */ + /* @FT_Glyph_BBox_Mode values instead. */ + /* */ + /* <Values> */ + /* ft_glyph_bbox_unscaled :: See @FT_GLYPH_BBOX_UNSCALED. */ + /* ft_glyph_bbox_subpixels :: See @FT_GLYPH_BBOX_SUBPIXELS. */ + /* ft_glyph_bbox_gridfit :: See @FT_GLYPH_BBOX_GRIDFIT. */ + /* ft_glyph_bbox_truncate :: See @FT_GLYPH_BBOX_TRUNCATE. */ + /* ft_glyph_bbox_pixels :: See @FT_GLYPH_BBOX_PIXELS. */ + /* */ +#define ft_glyph_bbox_unscaled FT_GLYPH_BBOX_UNSCALED +#define ft_glyph_bbox_subpixels FT_GLYPH_BBOX_SUBPIXELS +#define ft_glyph_bbox_gridfit FT_GLYPH_BBOX_GRIDFIT +#define ft_glyph_bbox_truncate FT_GLYPH_BBOX_TRUNCATE +#define ft_glyph_bbox_pixels FT_GLYPH_BBOX_PIXELS + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Glyph_Get_CBox */ + /* */ + /* <Description> */ + /* Return a glyph's `control box'. The control box encloses all the */ + /* outline's points, including BȨzier control points. Though it */ + /* coincides with the exact bounding box for most glyphs, it can be */ + /* slightly larger in some situations (like when rotating an outline */ + /* which contains BȨzier outside arcs). */ + /* */ + /* Computing the control box is very fast, while getting the bounding */ + /* box can take much more time as it needs to walk over all segments */ + /* and arcs in the outline. To get the latter, you can use the */ + /* `ftbbox' component which is dedicated to this single task. */ + /* */ + /* <Input> */ + /* glyph :: A handle to the source glyph object. */ + /* */ + /* mode :: The mode which indicates how to interpret the returned */ + /* bounding box values. */ + /* */ + /* <Output> */ + /* acbox :: The glyph coordinate bounding box. Coordinates are */ + /* expressed in 1/64th of pixels if it is grid-fitted. */ + /* */ + /* <Note> */ + /* Coordinates are relative to the glyph origin, using the y~upwards */ + /* convention. */ + /* */ + /* If the glyph has been loaded with @FT_LOAD_NO_SCALE, `bbox_mode' */ + /* must be set to @FT_GLYPH_BBOX_UNSCALED to get unscaled font */ + /* units in 26.6 pixel format. The value @FT_GLYPH_BBOX_SUBPIXELS */ + /* is another name for this constant. */ + /* */ + /* Note that the maximum coordinates are exclusive, which means that */ + /* one can compute the width and height of the glyph image (be it in */ + /* integer or 26.6 pixels) as: */ + /* */ + /* { */ + /* width = bbox.xMax - bbox.xMin; */ + /* height = bbox.yMax - bbox.yMin; */ + /* } */ + /* */ + /* Note also that for 26.6 coordinates, if `bbox_mode' is set to */ + /* @FT_GLYPH_BBOX_GRIDFIT, the coordinates will also be grid-fitted, */ + /* which corresponds to: */ + /* */ + /* { */ + /* bbox.xMin = FLOOR(bbox.xMin); */ + /* bbox.yMin = FLOOR(bbox.yMin); */ + /* bbox.xMax = CEILING(bbox.xMax); */ + /* bbox.yMax = CEILING(bbox.yMax); */ + /* } */ + /* */ + /* To get the bbox in pixel coordinates, set `bbox_mode' to */ + /* @FT_GLYPH_BBOX_TRUNCATE. */ + /* */ + /* To get the bbox in grid-fitted pixel coordinates, set `bbox_mode' */ + /* to @FT_GLYPH_BBOX_PIXELS. */ + /* */ + FT_EXPORT( void ) + FT_Glyph_Get_CBox( FT_Glyph glyph, + FT_UInt bbox_mode, + FT_BBox *acbox ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Glyph_To_Bitmap */ + /* */ + /* <Description> */ + /* Convert a given glyph object to a bitmap glyph object. */ + /* */ + /* <InOut> */ + /* the_glyph :: A pointer to a handle to the target glyph. */ + /* */ + /* <Input> */ + /* render_mode :: An enumeration that describes how the data is */ + /* rendered. */ + /* */ + /* origin :: A pointer to a vector used to translate the glyph */ + /* image before rendering. Can be~0 (if no */ + /* translation). The origin is expressed in */ + /* 26.6 pixels. */ + /* */ + /* destroy :: A boolean that indicates that the original glyph */ + /* image should be destroyed by this function. It is */ + /* never destroyed in case of error. */ + /* */ + /* <Return> */ + /* FreeType error code. 0~means success. */ + /* */ + /* <Note> */ + /* This function does nothing if the glyph format isn't scalable. */ + /* */ + /* The glyph image is translated with the `origin' vector before */ + /* rendering. */ + /* */ + /* The first parameter is a pointer to an @FT_Glyph handle, that will */ + /* be _replaced_ by this function (with newly allocated data). */ + /* Typically, you would use (omitting error handling): */ + /* */ + /* */ + /* { */ + /* FT_Glyph glyph; */ + /* FT_BitmapGlyph glyph_bitmap; */ + /* */ + /* */ + /* // load glyph */ + /* error = FT_Load_Char( face, glyph_index, FT_LOAD_DEFAUT ); */ + /* */ + /* // extract glyph image */ + /* error = FT_Get_Glyph( face->glyph, &glyph ); */ + /* */ + /* // convert to a bitmap (default render mode + destroying old) */ + /* if ( glyph->format != FT_GLYPH_FORMAT_BITMAP ) */ + /* { */ + /* error = FT_Glyph_To_Bitmap( &glyph, FT_RENDER_MODE_NORMAL, */ + /* 0, 1 ); */ + /* if ( error ) // `glyph' unchanged */ + /* ... */ + /* } */ + /* */ + /* // access bitmap content by typecasting */ + /* glyph_bitmap = (FT_BitmapGlyph)glyph; */ + /* */ + /* // do funny stuff with it, like blitting/drawing */ + /* ... */ + /* */ + /* // discard glyph image (bitmap or not) */ + /* FT_Done_Glyph( glyph ); */ + /* } */ + /* */ + /* */ + /* Here another example, again without error handling: */ + /* */ + /* */ + /* { */ + /* FT_Glyph glyphs[MAX_GLYPHS] */ + /* */ + /* */ + /* ... */ + /* */ + /* for ( idx = 0; i < MAX_GLYPHS; i++ ) */ + /* error = FT_Load_Glyph( face, idx, FT_LOAD_DEFAULT ) || */ + /* FT_Get_Glyph ( face->glyph, &glyph[idx] ); */ + /* */ + /* ... */ + /* */ + /* for ( idx = 0; i < MAX_GLYPHS; i++ ) */ + /* { */ + /* FT_Glyph bitmap = glyphs[idx]; */ + /* */ + /* */ + /* ... */ + /* */ + /* // after this call, `bitmap' no longer points into */ + /* // the `glyphs' array (and the old value isn't destroyed) */ + /* FT_Glyph_To_Bitmap( &bitmap, FT_RENDER_MODE_MONO, 0, 0 ); */ + /* */ + /* ... */ + /* */ + /* FT_Done_Glyph( bitmap ); */ + /* } */ + /* */ + /* ... */ + /* */ + /* for ( idx = 0; i < MAX_GLYPHS; i++ ) */ + /* FT_Done_Glyph( glyphs[idx] ); */ + /* } */ + /* */ + FT_EXPORT( FT_Error ) + FT_Glyph_To_Bitmap( FT_Glyph* the_glyph, + FT_Render_Mode render_mode, + FT_Vector* origin, + FT_Bool destroy ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Done_Glyph */ + /* */ + /* <Description> */ + /* Destroy a given glyph. */ + /* */ + /* <Input> */ + /* glyph :: A handle to the target glyph object. */ + /* */ + FT_EXPORT( void ) + FT_Done_Glyph( FT_Glyph glyph ); + + /* */ + + + /* other helpful functions */ + + /*************************************************************************/ + /* */ + /* <Section> */ + /* computations */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Matrix_Multiply */ + /* */ + /* <Description> */ + /* Perform the matrix operation `b = a*b'. */ + /* */ + /* <Input> */ + /* a :: A pointer to matrix `a'. */ + /* */ + /* <InOut> */ + /* b :: A pointer to matrix `b'. */ + /* */ + /* <Note> */ + /* The result is undefined if either `a' or `b' is zero. */ + /* */ + FT_EXPORT( void ) + FT_Matrix_Multiply( const FT_Matrix* a, + FT_Matrix* b ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Matrix_Invert */ + /* */ + /* <Description> */ + /* Invert a 2x2 matrix. Return an error if it can't be inverted. */ + /* */ + /* <InOut> */ + /* matrix :: A pointer to the target matrix. Remains untouched in */ + /* case of error. */ + /* */ + /* <Return> */ + /* FreeType error code. 0~means success. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Matrix_Invert( FT_Matrix* matrix ); + + + /* */ + + +FT_END_HEADER + +#endif /* __FTGLYPH_H__ */ + + +/* END */ + + +/* Local Variables: */ +/* coding: utf-8 */ +/* End: */ diff --git a/Lib/Include/freetype/ftgxval.h b/Lib/Include/freetype/ftgxval.h new file mode 100644 index 0000000..497015c --- /dev/null +++ b/Lib/Include/freetype/ftgxval.h @@ -0,0 +1,358 @@ +/***************************************************************************/ +/* */ +/* ftgxval.h */ +/* */ +/* FreeType API for validating TrueTypeGX/AAT tables (specification). */ +/* */ +/* Copyright 2004, 2005, 2006 by */ +/* Masatake YAMATO, Redhat K.K, */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + +/***************************************************************************/ +/* */ +/* gxvalid is derived from both gxlayout module and otvalid module. */ +/* Development of gxlayout is supported by the Information-technology */ +/* Promotion Agency(IPA), Japan. */ +/* */ +/***************************************************************************/ + + +#ifndef __FTGXVAL_H__ +#define __FTGXVAL_H__ + +#include <ft2build.h> +#include FT_FREETYPE_H + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /* */ + /* <Section> */ + /* gx_validation */ + /* */ + /* <Title> */ + /* TrueTypeGX/AAT Validation */ + /* */ + /* <Abstract> */ + /* An API to validate TrueTypeGX/AAT tables. */ + /* */ + /* <Description> */ + /* This section contains the declaration of functions to validate */ + /* some TrueTypeGX tables (feat, mort, morx, bsln, just, kern, opbd, */ + /* trak, prop, lcar). */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* */ + /* Warning: Use FT_VALIDATE_XXX to validate a table. */ + /* Following definitions are for gxvalid developers. */ + /* */ + /* */ + /*************************************************************************/ + +#define FT_VALIDATE_feat_INDEX 0 +#define FT_VALIDATE_mort_INDEX 1 +#define FT_VALIDATE_morx_INDEX 2 +#define FT_VALIDATE_bsln_INDEX 3 +#define FT_VALIDATE_just_INDEX 4 +#define FT_VALIDATE_kern_INDEX 5 +#define FT_VALIDATE_opbd_INDEX 6 +#define FT_VALIDATE_trak_INDEX 7 +#define FT_VALIDATE_prop_INDEX 8 +#define FT_VALIDATE_lcar_INDEX 9 +#define FT_VALIDATE_GX_LAST_INDEX FT_VALIDATE_lcar_INDEX + + + /************************************************************************* + * + * @macro: + * FT_VALIDATE_GX_LENGTH + * + * @description: + * The number of tables checked in this module. Use it as a parameter + * for the `table-length' argument of function @FT_TrueTypeGX_Validate. + */ +#define FT_VALIDATE_GX_LENGTH (FT_VALIDATE_GX_LAST_INDEX + 1) + + /* */ + + /* Up to 0x1000 is used by otvalid. + Ox2xxx is reserved for feature OT extension. */ +#define FT_VALIDATE_GX_START 0x4000 +#define FT_VALIDATE_GX_BITFIELD( tag ) \ + ( FT_VALIDATE_GX_START << FT_VALIDATE_##tag##_INDEX ) + + + /********************************************************************** + * + * @enum: + * FT_VALIDATE_GXXXX + * + * @description: + * A list of bit-field constants used with @FT_TrueTypeGX_Validate to + * indicate which TrueTypeGX/AAT Type tables should be validated. + * + * @values: + * FT_VALIDATE_feat :: + * Validate `feat' table. + * + * FT_VALIDATE_mort :: + * Validate `mort' table. + * + * FT_VALIDATE_morx :: + * Validate `morx' table. + * + * FT_VALIDATE_bsln :: + * Validate `bsln' table. + * + * FT_VALIDATE_just :: + * Validate `just' table. + * + * FT_VALIDATE_kern :: + * Validate `kern' table. + * + * FT_VALIDATE_opbd :: + * Validate `opbd' table. + * + * FT_VALIDATE_trak :: + * Validate `trak' table. + * + * FT_VALIDATE_prop :: + * Validate `prop' table. + * + * FT_VALIDATE_lcar :: + * Validate `lcar' table. + * + * FT_VALIDATE_GX :: + * Validate all TrueTypeGX tables (feat, mort, morx, bsln, just, kern, + * opbd, trak, prop and lcar). + * + */ + +#define FT_VALIDATE_feat FT_VALIDATE_GX_BITFIELD( feat ) +#define FT_VALIDATE_mort FT_VALIDATE_GX_BITFIELD( mort ) +#define FT_VALIDATE_morx FT_VALIDATE_GX_BITFIELD( morx ) +#define FT_VALIDATE_bsln FT_VALIDATE_GX_BITFIELD( bsln ) +#define FT_VALIDATE_just FT_VALIDATE_GX_BITFIELD( just ) +#define FT_VALIDATE_kern FT_VALIDATE_GX_BITFIELD( kern ) +#define FT_VALIDATE_opbd FT_VALIDATE_GX_BITFIELD( opbd ) +#define FT_VALIDATE_trak FT_VALIDATE_GX_BITFIELD( trak ) +#define FT_VALIDATE_prop FT_VALIDATE_GX_BITFIELD( prop ) +#define FT_VALIDATE_lcar FT_VALIDATE_GX_BITFIELD( lcar ) + +#define FT_VALIDATE_GX ( FT_VALIDATE_feat | \ + FT_VALIDATE_mort | \ + FT_VALIDATE_morx | \ + FT_VALIDATE_bsln | \ + FT_VALIDATE_just | \ + FT_VALIDATE_kern | \ + FT_VALIDATE_opbd | \ + FT_VALIDATE_trak | \ + FT_VALIDATE_prop | \ + FT_VALIDATE_lcar ) + + + /* */ + + /********************************************************************** + * + * @function: + * FT_TrueTypeGX_Validate + * + * @description: + * Validate various TrueTypeGX tables to assure that all offsets and + * indices are valid. The idea is that a higher-level library which + * actually does the text layout can access those tables without + * error checking (which can be quite time consuming). + * + * @input: + * face :: + * A handle to the input face. + * + * validation_flags :: + * A bit field which specifies the tables to be validated. See + * @FT_VALIDATE_GXXXX for possible values. + * + * table_length :: + * The size of the `tables' array. Normally, @FT_VALIDATE_GX_LENGTH + * should be passed. + * + * @output: + * tables :: + * The array where all validated sfnt tables are stored. + * The array itself must be allocated by a client. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * This function only works with TrueTypeGX fonts, returning an error + * otherwise. + * + * After use, the application should deallocate the buffers pointed to by + * each `tables' element, by calling @FT_TrueTypeGX_Free. A NULL value + * indicates that the table either doesn't exist in the font, the + * application hasn't asked for validation, or the validator doesn't have + * the ability to validate the sfnt table. + */ + FT_EXPORT( FT_Error ) + FT_TrueTypeGX_Validate( FT_Face face, + FT_UInt validation_flags, + FT_Bytes tables[FT_VALIDATE_GX_LENGTH], + FT_UInt table_length ); + + + /* */ + + /********************************************************************** + * + * @function: + * FT_TrueTypeGX_Free + * + * @description: + * Free the buffer allocated by TrueTypeGX validator. + * + * @input: + * face :: + * A handle to the input face. + * + * table :: + * The pointer to the buffer allocated by + * @FT_TrueTypeGX_Validate. + * + * @note: + * This function must be used to free the buffer allocated by + * @FT_TrueTypeGX_Validate only. + */ + FT_EXPORT( void ) + FT_TrueTypeGX_Free( FT_Face face, + FT_Bytes table ); + + + /* */ + + /********************************************************************** + * + * @enum: + * FT_VALIDATE_CKERNXXX + * + * @description: + * A list of bit-field constants used with @FT_ClassicKern_Validate + * to indicate the classic kern dialect or dialects. If the selected + * type doesn't fit, @FT_ClassicKern_Validate regards the table as + * invalid. + * + * @values: + * FT_VALIDATE_MS :: + * Handle the `kern' table as a classic Microsoft kern table. + * + * FT_VALIDATE_APPLE :: + * Handle the `kern' table as a classic Apple kern table. + * + * FT_VALIDATE_CKERN :: + * Handle the `kern' as either classic Apple or Microsoft kern table. + */ +#define FT_VALIDATE_MS ( FT_VALIDATE_GX_START << 0 ) +#define FT_VALIDATE_APPLE ( FT_VALIDATE_GX_START << 1 ) + +#define FT_VALIDATE_CKERN ( FT_VALIDATE_MS | FT_VALIDATE_APPLE ) + + + /* */ + + /********************************************************************** + * + * @function: + * FT_ClassicKern_Validate + * + * @description: + * Validate classic (16-bit format) kern table to assure that the offsets + * and indices are valid. The idea is that a higher-level library which + * actually does the text layout can access those tables without error + * checking (which can be quite time consuming). + * + * The `kern' table validator in @FT_TrueTypeGX_Validate deals with both + * the new 32-bit format and the classic 16-bit format, while + * FT_ClassicKern_Validate only supports the classic 16-bit format. + * + * @input: + * face :: + * A handle to the input face. + * + * validation_flags :: + * A bit field which specifies the dialect to be validated. See + * @FT_VALIDATE_CKERNXXX for possible values. + * + * @output: + * ckern_table :: + * A pointer to the kern table. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * After use, the application should deallocate the buffers pointed to by + * `ckern_table', by calling @FT_ClassicKern_Free. A NULL value + * indicates that the table doesn't exist in the font. + */ + FT_EXPORT( FT_Error ) + FT_ClassicKern_Validate( FT_Face face, + FT_UInt validation_flags, + FT_Bytes *ckern_table ); + + + /* */ + + /********************************************************************** + * + * @function: + * FT_ClassicKern_Free + * + * @description: + * Free the buffer allocated by classic Kern validator. + * + * @input: + * face :: + * A handle to the input face. + * + * table :: + * The pointer to the buffer that is allocated by + * @FT_ClassicKern_Validate. + * + * @note: + * This function must be used to free the buffer allocated by + * @FT_ClassicKern_Validate only. + */ + FT_EXPORT( void ) + FT_ClassicKern_Free( FT_Face face, + FT_Bytes table ); + + + /* */ + + +FT_END_HEADER + +#endif /* __FTGXVAL_H__ */ + + +/* END */ diff --git a/Lib/Include/freetype/ftgzip.h b/Lib/Include/freetype/ftgzip.h new file mode 100644 index 0000000..acbc4f0 --- /dev/null +++ b/Lib/Include/freetype/ftgzip.h @@ -0,0 +1,102 @@ +/***************************************************************************/ +/* */ +/* ftgzip.h */ +/* */ +/* Gzip-compressed stream support. */ +/* */ +/* Copyright 2002, 2003, 2004, 2006 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef __FTGZIP_H__ +#define __FTGZIP_H__ + +#include <ft2build.h> +#include FT_FREETYPE_H + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + /*************************************************************************/ + /* */ + /* <Section> */ + /* gzip */ + /* */ + /* <Title> */ + /* GZIP Streams */ + /* */ + /* <Abstract> */ + /* Using gzip-compressed font files. */ + /* */ + /* <Description> */ + /* This section contains the declaration of Gzip-specific functions. */ + /* */ + /*************************************************************************/ + + + /************************************************************************ + * + * @function: + * FT_Stream_OpenGzip + * + * @description: + * Open a new stream to parse gzip-compressed font files. This is + * mainly used to support the compressed `*.pcf.gz' fonts that come + * with XFree86. + * + * @input: + * stream :: + * The target embedding stream. + * + * source :: + * The source stream. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * The source stream must be opened _before_ calling this function. + * + * Calling the internal function `FT_Stream_Close' on the new stream will + * *not* call `FT_Stream_Close' on the source stream. None of the stream + * objects will be released to the heap. + * + * The stream implementation is very basic and resets the decompression + * process each time seeking backwards is needed within the stream. + * + * In certain builds of the library, gzip compression recognition is + * automatically handled when calling @FT_New_Face or @FT_Open_Face. + * This means that if no font driver is capable of handling the raw + * compressed file, the library will try to open a gzipped stream from + * it and re-open the face with it. + * + * This function may return `FT_Err_Unimplemented_Feature' if your build + * of FreeType was not compiled with zlib support. + */ + FT_EXPORT( FT_Error ) + FT_Stream_OpenGzip( FT_Stream stream, + FT_Stream source ); + + /* */ + + +FT_END_HEADER + +#endif /* __FTGZIP_H__ */ + + +/* END */ diff --git a/Lib/Include/freetype/ftimage.h b/Lib/Include/freetype/ftimage.h new file mode 100644 index 0000000..8c00f41 --- /dev/null +++ b/Lib/Include/freetype/ftimage.h @@ -0,0 +1,1313 @@ +/***************************************************************************/ +/* */ +/* ftimage.h */ +/* */ +/* FreeType glyph image formats and default raster interface */ +/* (specification). */ +/* */ +/* Copyright 1996-2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, */ +/* 2010 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + /*************************************************************************/ + /* */ + /* Note: A `raster' is simply a scan-line converter, used to render */ + /* FT_Outlines into FT_Bitmaps. */ + /* */ + /*************************************************************************/ + + +#ifndef __FTIMAGE_H__ +#define __FTIMAGE_H__ + + + /* _STANDALONE_ is from ftgrays.c */ +#ifndef _STANDALONE_ +#include <ft2build.h> +#endif + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /* */ + /* <Section> */ + /* basic_types */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_Pos */ + /* */ + /* <Description> */ + /* The type FT_Pos is used to store vectorial coordinates. Depending */ + /* on the context, these can represent distances in integer font */ + /* units, or 16.16, or 26.6 fixed float pixel coordinates. */ + /* */ + typedef signed long FT_Pos; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_Vector */ + /* */ + /* <Description> */ + /* A simple structure used to store a 2D vector; coordinates are of */ + /* the FT_Pos type. */ + /* */ + /* <Fields> */ + /* x :: The horizontal coordinate. */ + /* y :: The vertical coordinate. */ + /* */ + typedef struct FT_Vector_ + { + FT_Pos x; + FT_Pos y; + + } FT_Vector; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_BBox */ + /* */ + /* <Description> */ + /* A structure used to hold an outline's bounding box, i.e., the */ + /* coordinates of its extrema in the horizontal and vertical */ + /* directions. */ + /* */ + /* <Fields> */ + /* xMin :: The horizontal minimum (left-most). */ + /* */ + /* yMin :: The vertical minimum (bottom-most). */ + /* */ + /* xMax :: The horizontal maximum (right-most). */ + /* */ + /* yMax :: The vertical maximum (top-most). */ + /* */ + /* <Note> */ + /* The bounding box is specified with the coordinates of the lower */ + /* left and the upper right corner. In PostScript, those values are */ + /* often called (llx,lly) and (urx,ury), respectively. */ + /* */ + /* If `yMin' is negative, this value gives the glyph's descender. */ + /* Otherwise, the glyph doesn't descend below the baseline. */ + /* Similarly, if `ymax' is positive, this value gives the glyph's */ + /* ascender. */ + /* */ + /* `xMin' gives the horizontal distance from the glyph's origin to */ + /* the left edge of the glyph's bounding box. If `xMin' is negative, */ + /* the glyph extends to the left of the origin. */ + /* */ + typedef struct FT_BBox_ + { + FT_Pos xMin, yMin; + FT_Pos xMax, yMax; + + } FT_BBox; + + + /*************************************************************************/ + /* */ + /* <Enum> */ + /* FT_Pixel_Mode */ + /* */ + /* <Description> */ + /* An enumeration type used to describe the format of pixels in a */ + /* given bitmap. Note that additional formats may be added in the */ + /* future. */ + /* */ + /* <Values> */ + /* FT_PIXEL_MODE_NONE :: */ + /* Value~0 is reserved. */ + /* */ + /* FT_PIXEL_MODE_MONO :: */ + /* A monochrome bitmap, using 1~bit per pixel. Note that pixels */ + /* are stored in most-significant order (MSB), which means that */ + /* the left-most pixel in a byte has value 128. */ + /* */ + /* FT_PIXEL_MODE_GRAY :: */ + /* An 8-bit bitmap, generally used to represent anti-aliased glyph */ + /* images. Each pixel is stored in one byte. Note that the number */ + /* of `gray' levels is stored in the `num_grays' field of the */ + /* @FT_Bitmap structure (it generally is 256). */ + /* */ + /* FT_PIXEL_MODE_GRAY2 :: */ + /* A 2-bit per pixel bitmap, used to represent embedded */ + /* anti-aliased bitmaps in font files according to the OpenType */ + /* specification. We haven't found a single font using this */ + /* format, however. */ + /* */ + /* FT_PIXEL_MODE_GRAY4 :: */ + /* A 4-bit per pixel bitmap, representing embedded anti-aliased */ + /* bitmaps in font files according to the OpenType specification. */ + /* We haven't found a single font using this format, however. */ + /* */ + /* FT_PIXEL_MODE_LCD :: */ + /* An 8-bit bitmap, representing RGB or BGR decimated glyph images */ + /* used for display on LCD displays; the bitmap is three times */ + /* wider than the original glyph image. See also */ + /* @FT_RENDER_MODE_LCD. */ + /* */ + /* FT_PIXEL_MODE_LCD_V :: */ + /* An 8-bit bitmap, representing RGB or BGR decimated glyph images */ + /* used for display on rotated LCD displays; the bitmap is three */ + /* times taller than the original glyph image. See also */ + /* @FT_RENDER_MODE_LCD_V. */ + /* */ + typedef enum FT_Pixel_Mode_ + { + FT_PIXEL_MODE_NONE = 0, + FT_PIXEL_MODE_MONO, + FT_PIXEL_MODE_GRAY, + FT_PIXEL_MODE_GRAY2, + FT_PIXEL_MODE_GRAY4, + FT_PIXEL_MODE_LCD, + FT_PIXEL_MODE_LCD_V, + + FT_PIXEL_MODE_MAX /* do not remove */ + + } FT_Pixel_Mode; + + + /*************************************************************************/ + /* */ + /* <Enum> */ + /* ft_pixel_mode_xxx */ + /* */ + /* <Description> */ + /* A list of deprecated constants. Use the corresponding */ + /* @FT_Pixel_Mode values instead. */ + /* */ + /* <Values> */ + /* ft_pixel_mode_none :: See @FT_PIXEL_MODE_NONE. */ + /* ft_pixel_mode_mono :: See @FT_PIXEL_MODE_MONO. */ + /* ft_pixel_mode_grays :: See @FT_PIXEL_MODE_GRAY. */ + /* ft_pixel_mode_pal2 :: See @FT_PIXEL_MODE_GRAY2. */ + /* ft_pixel_mode_pal4 :: See @FT_PIXEL_MODE_GRAY4. */ + /* */ +#define ft_pixel_mode_none FT_PIXEL_MODE_NONE +#define ft_pixel_mode_mono FT_PIXEL_MODE_MONO +#define ft_pixel_mode_grays FT_PIXEL_MODE_GRAY +#define ft_pixel_mode_pal2 FT_PIXEL_MODE_GRAY2 +#define ft_pixel_mode_pal4 FT_PIXEL_MODE_GRAY4 + + /* */ + +#if 0 + + /*************************************************************************/ + /* */ + /* <Enum> */ + /* FT_Palette_Mode */ + /* */ + /* <Description> */ + /* THIS TYPE IS DEPRECATED. DO NOT USE IT! */ + /* */ + /* An enumeration type to describe the format of a bitmap palette, */ + /* used with ft_pixel_mode_pal4 and ft_pixel_mode_pal8. */ + /* */ + /* <Values> */ + /* ft_palette_mode_rgb :: The palette is an array of 3-byte RGB */ + /* records. */ + /* */ + /* ft_palette_mode_rgba :: The palette is an array of 4-byte RGBA */ + /* records. */ + /* */ + /* <Note> */ + /* As ft_pixel_mode_pal2, pal4 and pal8 are currently unused by */ + /* FreeType, these types are not handled by the library itself. */ + /* */ + typedef enum FT_Palette_Mode_ + { + ft_palette_mode_rgb = 0, + ft_palette_mode_rgba, + + ft_palette_mode_max /* do not remove */ + + } FT_Palette_Mode; + + /* */ + +#endif + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_Bitmap */ + /* */ + /* <Description> */ + /* A structure used to describe a bitmap or pixmap to the raster. */ + /* Note that we now manage pixmaps of various depths through the */ + /* `pixel_mode' field. */ + /* */ + /* <Fields> */ + /* rows :: The number of bitmap rows. */ + /* */ + /* width :: The number of pixels in bitmap row. */ + /* */ + /* pitch :: The pitch's absolute value is the number of bytes */ + /* taken by one bitmap row, including padding. */ + /* However, the pitch is positive when the bitmap has */ + /* a `down' flow, and negative when it has an `up' */ + /* flow. In all cases, the pitch is an offset to add */ + /* to a bitmap pointer in order to go down one row. */ + /* */ + /* Note that `padding' means the alignment of a */ + /* bitmap to a byte border, and FreeType functions */ + /* normally align to the smallest possible integer */ + /* value. */ + /* */ + /* For the B/W rasterizer, `pitch' is always an even */ + /* number. */ + /* */ + /* To change the pitch of a bitmap (say, to make it a */ + /* multiple of 4), use @FT_Bitmap_Convert. */ + /* Alternatively, you might use callback functions to */ + /* directly render to the application's surface; see */ + /* the file `example2.cpp' in the tutorial for a */ + /* demonstration. */ + /* */ + /* buffer :: A typeless pointer to the bitmap buffer. This */ + /* value should be aligned on 32-bit boundaries in */ + /* most cases. */ + /* */ + /* num_grays :: This field is only used with */ + /* @FT_PIXEL_MODE_GRAY; it gives the number of gray */ + /* levels used in the bitmap. */ + /* */ + /* pixel_mode :: The pixel mode, i.e., how pixel bits are stored. */ + /* See @FT_Pixel_Mode for possible values. */ + /* */ + /* palette_mode :: This field is intended for paletted pixel modes; */ + /* it indicates how the palette is stored. Not */ + /* used currently. */ + /* */ + /* palette :: A typeless pointer to the bitmap palette; this */ + /* field is intended for paletted pixel modes. Not */ + /* used currently. */ + /* */ + /* <Note> */ + /* For now, the only pixel modes supported by FreeType are mono and */ + /* grays. However, drivers might be added in the future to support */ + /* more `colorful' options. */ + /* */ + typedef struct FT_Bitmap_ + { + int rows; + int width; + int pitch; + unsigned char* buffer; + short num_grays; + char pixel_mode; + char palette_mode; + void* palette; + + } FT_Bitmap; + + + /*************************************************************************/ + /* */ + /* <Section> */ + /* outline_processing */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_Outline */ + /* */ + /* <Description> */ + /* This structure is used to describe an outline to the scan-line */ + /* converter. */ + /* */ + /* <Fields> */ + /* n_contours :: The number of contours in the outline. */ + /* */ + /* n_points :: The number of points in the outline. */ + /* */ + /* points :: A pointer to an array of `n_points' @FT_Vector */ + /* elements, giving the outline's point coordinates. */ + /* */ + /* tags :: A pointer to an array of `n_points' chars, giving */ + /* each outline point's type. */ + /* */ + /* If bit~0 is unset, the point is `off' the curve, */ + /* i.e., a BȨzier control point, while it is `on' if */ + /* set. */ + /* */ + /* Bit~1 is meaningful for `off' points only. If set, */ + /* it indicates a third-order BȨzier arc control point; */ + /* and a second-order control point if unset. */ + /* */ + /* If bit~2 is set, bits 5-7 contain the drop-out mode */ + /* (as defined in the OpenType specification; the value */ + /* is the same as the argument to the SCANMODE */ + /* instruction). */ + /* */ + /* Bits 3 and~4 are reserved for internal purposes. */ + /* */ + /* contours :: An array of `n_contours' shorts, giving the end */ + /* point of each contour within the outline. For */ + /* example, the first contour is defined by the points */ + /* `0' to `contours[0]', the second one is defined by */ + /* the points `contours[0]+1' to `contours[1]', etc. */ + /* */ + /* flags :: A set of bit flags used to characterize the outline */ + /* and give hints to the scan-converter and hinter on */ + /* how to convert/grid-fit it. See @FT_OUTLINE_FLAGS. */ + /* */ + /* <Note> */ + /* The B/W rasterizer only checks bit~2 in the `tags' array for the */ + /* first point of each contour. The drop-out mode as given with */ + /* @FT_OUTLINE_IGNORE_DROPOUTS, @FT_OUTLINE_SMART_DROPOUTS, and */ + /* @FT_OUTLINE_INCLUDE_STUBS in `flags' is then overridden. */ + /* */ + typedef struct FT_Outline_ + { + short n_contours; /* number of contours in glyph */ + short n_points; /* number of points in the glyph */ + + FT_Vector* points; /* the outline's points */ + char* tags; /* the points flags */ + short* contours; /* the contour end points */ + + int flags; /* outline masks */ + + } FT_Outline; + + /* Following limits must be consistent with */ + /* FT_Outline.{n_contours,n_points} */ +#define FT_OUTLINE_CONTOURS_MAX SHRT_MAX +#define FT_OUTLINE_POINTS_MAX SHRT_MAX + + + /*************************************************************************/ + /* */ + /* <Enum> */ + /* FT_OUTLINE_FLAGS */ + /* */ + /* <Description> */ + /* A list of bit-field constants use for the flags in an outline's */ + /* `flags' field. */ + /* */ + /* <Values> */ + /* FT_OUTLINE_NONE :: */ + /* Value~0 is reserved. */ + /* */ + /* FT_OUTLINE_OWNER :: */ + /* If set, this flag indicates that the outline's field arrays */ + /* (i.e., `points', `flags', and `contours') are `owned' by the */ + /* outline object, and should thus be freed when it is destroyed. */ + /* */ + /* FT_OUTLINE_EVEN_ODD_FILL :: */ + /* By default, outlines are filled using the non-zero winding rule. */ + /* If set to 1, the outline will be filled using the even-odd fill */ + /* rule (only works with the smooth rasterizer). */ + /* */ + /* FT_OUTLINE_REVERSE_FILL :: */ + /* By default, outside contours of an outline are oriented in */ + /* clock-wise direction, as defined in the TrueType specification. */ + /* This flag is set if the outline uses the opposite direction */ + /* (typically for Type~1 fonts). This flag is ignored by the scan */ + /* converter. */ + /* */ + /* FT_OUTLINE_IGNORE_DROPOUTS :: */ + /* By default, the scan converter will try to detect drop-outs in */ + /* an outline and correct the glyph bitmap to ensure consistent */ + /* shape continuity. If set, this flag hints the scan-line */ + /* converter to ignore such cases. See below for more information. */ + /* */ + /* FT_OUTLINE_SMART_DROPOUTS :: */ + /* Select smart dropout control. If unset, use simple dropout */ + /* control. Ignored if @FT_OUTLINE_IGNORE_DROPOUTS is set. See */ + /* below for more information. */ + /* */ + /* FT_OUTLINE_INCLUDE_STUBS :: */ + /* If set, turn pixels on for `stubs', otherwise exclude them. */ + /* Ignored if @FT_OUTLINE_IGNORE_DROPOUTS is set. See below for */ + /* more information. */ + /* */ + /* FT_OUTLINE_HIGH_PRECISION :: */ + /* This flag indicates that the scan-line converter should try to */ + /* convert this outline to bitmaps with the highest possible */ + /* quality. It is typically set for small character sizes. Note */ + /* that this is only a hint that might be completely ignored by a */ + /* given scan-converter. */ + /* */ + /* FT_OUTLINE_SINGLE_PASS :: */ + /* This flag is set to force a given scan-converter to only use a */ + /* single pass over the outline to render a bitmap glyph image. */ + /* Normally, it is set for very large character sizes. It is only */ + /* a hint that might be completely ignored by a given */ + /* scan-converter. */ + /* */ + /* <Note> */ + /* The flags @FT_OUTLINE_IGNORE_DROPOUTS, @FT_OUTLINE_SMART_DROPOUTS, */ + /* and @FT_OUTLINE_INCLUDE_STUBS are ignored by the smooth */ + /* rasterizer. */ + /* */ + /* There exists a second mechanism to pass the drop-out mode to the */ + /* B/W rasterizer; see the `tags' field in @FT_Outline. */ + /* */ + /* Please refer to the description of the `SCANTYPE' instruction in */ + /* the OpenType specification (in file `ttinst1.doc') how simple */ + /* drop-outs, smart drop-outs, and stubs are defined. */ + /* */ +#define FT_OUTLINE_NONE 0x0 +#define FT_OUTLINE_OWNER 0x1 +#define FT_OUTLINE_EVEN_ODD_FILL 0x2 +#define FT_OUTLINE_REVERSE_FILL 0x4 +#define FT_OUTLINE_IGNORE_DROPOUTS 0x8 +#define FT_OUTLINE_SMART_DROPOUTS 0x10 +#define FT_OUTLINE_INCLUDE_STUBS 0x20 + +#define FT_OUTLINE_HIGH_PRECISION 0x100 +#define FT_OUTLINE_SINGLE_PASS 0x200 + + + /************************************************************************* + * + * @enum: + * ft_outline_flags + * + * @description: + * These constants are deprecated. Please use the corresponding + * @FT_OUTLINE_FLAGS values. + * + * @values: + * ft_outline_none :: See @FT_OUTLINE_NONE. + * ft_outline_owner :: See @FT_OUTLINE_OWNER. + * ft_outline_even_odd_fill :: See @FT_OUTLINE_EVEN_ODD_FILL. + * ft_outline_reverse_fill :: See @FT_OUTLINE_REVERSE_FILL. + * ft_outline_ignore_dropouts :: See @FT_OUTLINE_IGNORE_DROPOUTS. + * ft_outline_high_precision :: See @FT_OUTLINE_HIGH_PRECISION. + * ft_outline_single_pass :: See @FT_OUTLINE_SINGLE_PASS. + */ +#define ft_outline_none FT_OUTLINE_NONE +#define ft_outline_owner FT_OUTLINE_OWNER +#define ft_outline_even_odd_fill FT_OUTLINE_EVEN_ODD_FILL +#define ft_outline_reverse_fill FT_OUTLINE_REVERSE_FILL +#define ft_outline_ignore_dropouts FT_OUTLINE_IGNORE_DROPOUTS +#define ft_outline_high_precision FT_OUTLINE_HIGH_PRECISION +#define ft_outline_single_pass FT_OUTLINE_SINGLE_PASS + + /* */ + +#define FT_CURVE_TAG( flag ) ( flag & 3 ) + +#define FT_CURVE_TAG_ON 1 +#define FT_CURVE_TAG_CONIC 0 +#define FT_CURVE_TAG_CUBIC 2 + +#define FT_CURVE_TAG_HAS_SCANMODE 4 + +#define FT_CURVE_TAG_TOUCH_X 8 /* reserved for the TrueType hinter */ +#define FT_CURVE_TAG_TOUCH_Y 16 /* reserved for the TrueType hinter */ + +#define FT_CURVE_TAG_TOUCH_BOTH ( FT_CURVE_TAG_TOUCH_X | \ + FT_CURVE_TAG_TOUCH_Y ) + +#define FT_Curve_Tag_On FT_CURVE_TAG_ON +#define FT_Curve_Tag_Conic FT_CURVE_TAG_CONIC +#define FT_Curve_Tag_Cubic FT_CURVE_TAG_CUBIC +#define FT_Curve_Tag_Touch_X FT_CURVE_TAG_TOUCH_X +#define FT_Curve_Tag_Touch_Y FT_CURVE_TAG_TOUCH_Y + + + /*************************************************************************/ + /* */ + /* <FuncType> */ + /* FT_Outline_MoveToFunc */ + /* */ + /* <Description> */ + /* A function pointer type used to describe the signature of a `move */ + /* to' function during outline walking/decomposition. */ + /* */ + /* A `move to' is emitted to start a new contour in an outline. */ + /* */ + /* <Input> */ + /* to :: A pointer to the target point of the `move to'. */ + /* */ + /* user :: A typeless pointer which is passed from the caller of the */ + /* decomposition function. */ + /* */ + /* <Return> */ + /* Error code. 0~means success. */ + /* */ + typedef int + (*FT_Outline_MoveToFunc)( const FT_Vector* to, + void* user ); + +#define FT_Outline_MoveTo_Func FT_Outline_MoveToFunc + + + /*************************************************************************/ + /* */ + /* <FuncType> */ + /* FT_Outline_LineToFunc */ + /* */ + /* <Description> */ + /* A function pointer type used to describe the signature of a `line */ + /* to' function during outline walking/decomposition. */ + /* */ + /* A `line to' is emitted to indicate a segment in the outline. */ + /* */ + /* <Input> */ + /* to :: A pointer to the target point of the `line to'. */ + /* */ + /* user :: A typeless pointer which is passed from the caller of the */ + /* decomposition function. */ + /* */ + /* <Return> */ + /* Error code. 0~means success. */ + /* */ + typedef int + (*FT_Outline_LineToFunc)( const FT_Vector* to, + void* user ); + +#define FT_Outline_LineTo_Func FT_Outline_LineToFunc + + + /*************************************************************************/ + /* */ + /* <FuncType> */ + /* FT_Outline_ConicToFunc */ + /* */ + /* <Description> */ + /* A function pointer type used to describe the signature of a `conic */ + /* to' function during outline walking or decomposition. */ + /* */ + /* A `conic to' is emitted to indicate a second-order BȨzier arc in */ + /* the outline. */ + /* */ + /* <Input> */ + /* control :: An intermediate control point between the last position */ + /* and the new target in `to'. */ + /* */ + /* to :: A pointer to the target end point of the conic arc. */ + /* */ + /* user :: A typeless pointer which is passed from the caller of */ + /* the decomposition function. */ + /* */ + /* <Return> */ + /* Error code. 0~means success. */ + /* */ + typedef int + (*FT_Outline_ConicToFunc)( const FT_Vector* control, + const FT_Vector* to, + void* user ); + +#define FT_Outline_ConicTo_Func FT_Outline_ConicToFunc + + + /*************************************************************************/ + /* */ + /* <FuncType> */ + /* FT_Outline_CubicToFunc */ + /* */ + /* <Description> */ + /* A function pointer type used to describe the signature of a `cubic */ + /* to' function during outline walking or decomposition. */ + /* */ + /* A `cubic to' is emitted to indicate a third-order BȨzier arc. */ + /* */ + /* <Input> */ + /* control1 :: A pointer to the first BȨzier control point. */ + /* */ + /* control2 :: A pointer to the second BȨzier control point. */ + /* */ + /* to :: A pointer to the target end point. */ + /* */ + /* user :: A typeless pointer which is passed from the caller of */ + /* the decomposition function. */ + /* */ + /* <Return> */ + /* Error code. 0~means success. */ + /* */ + typedef int + (*FT_Outline_CubicToFunc)( const FT_Vector* control1, + const FT_Vector* control2, + const FT_Vector* to, + void* user ); + +#define FT_Outline_CubicTo_Func FT_Outline_CubicToFunc + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_Outline_Funcs */ + /* */ + /* <Description> */ + /* A structure to hold various function pointers used during outline */ + /* decomposition in order to emit segments, conic, and cubic BȨziers. */ + /* */ + /* <Fields> */ + /* move_to :: The `move to' emitter. */ + /* */ + /* line_to :: The segment emitter. */ + /* */ + /* conic_to :: The second-order BȨzier arc emitter. */ + /* */ + /* cubic_to :: The third-order BȨzier arc emitter. */ + /* */ + /* shift :: The shift that is applied to coordinates before they */ + /* are sent to the emitter. */ + /* */ + /* delta :: The delta that is applied to coordinates before they */ + /* are sent to the emitter, but after the shift. */ + /* */ + /* <Note> */ + /* The point coordinates sent to the emitters are the transformed */ + /* version of the original coordinates (this is important for high */ + /* accuracy during scan-conversion). The transformation is simple: */ + /* */ + /* { */ + /* x' = (x << shift) - delta */ + /* y' = (x << shift) - delta */ + /* } */ + /* */ + /* Set the values of `shift' and `delta' to~0 to get the original */ + /* point coordinates. */ + /* */ + typedef struct FT_Outline_Funcs_ + { + FT_Outline_MoveToFunc move_to; + FT_Outline_LineToFunc line_to; + FT_Outline_ConicToFunc conic_to; + FT_Outline_CubicToFunc cubic_to; + + int shift; + FT_Pos delta; + + } FT_Outline_Funcs; + + + /*************************************************************************/ + /* */ + /* <Section> */ + /* basic_types */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* <Macro> */ + /* FT_IMAGE_TAG */ + /* */ + /* <Description> */ + /* This macro converts four-letter tags to an unsigned long type. */ + /* */ + /* <Note> */ + /* Since many 16-bit compilers don't like 32-bit enumerations, you */ + /* should redefine this macro in case of problems to something like */ + /* this: */ + /* */ + /* { */ + /* #define FT_IMAGE_TAG( value, _x1, _x2, _x3, _x4 ) value */ + /* } */ + /* */ + /* to get a simple enumeration without assigning special numbers. */ + /* */ +#ifndef FT_IMAGE_TAG +#define FT_IMAGE_TAG( value, _x1, _x2, _x3, _x4 ) \ + value = ( ( (unsigned long)_x1 << 24 ) | \ + ( (unsigned long)_x2 << 16 ) | \ + ( (unsigned long)_x3 << 8 ) | \ + (unsigned long)_x4 ) +#endif /* FT_IMAGE_TAG */ + + + /*************************************************************************/ + /* */ + /* <Enum> */ + /* FT_Glyph_Format */ + /* */ + /* <Description> */ + /* An enumeration type used to describe the format of a given glyph */ + /* image. Note that this version of FreeType only supports two image */ + /* formats, even though future font drivers will be able to register */ + /* their own format. */ + /* */ + /* <Values> */ + /* FT_GLYPH_FORMAT_NONE :: */ + /* The value~0 is reserved. */ + /* */ + /* FT_GLYPH_FORMAT_COMPOSITE :: */ + /* The glyph image is a composite of several other images. This */ + /* format is _only_ used with @FT_LOAD_NO_RECURSE, and is used to */ + /* report compound glyphs (like accented characters). */ + /* */ + /* FT_GLYPH_FORMAT_BITMAP :: */ + /* The glyph image is a bitmap, and can be described as an */ + /* @FT_Bitmap. You generally need to access the `bitmap' field of */ + /* the @FT_GlyphSlotRec structure to read it. */ + /* */ + /* FT_GLYPH_FORMAT_OUTLINE :: */ + /* The glyph image is a vectorial outline made of line segments */ + /* and BȨzier arcs; it can be described as an @FT_Outline; you */ + /* generally want to access the `outline' field of the */ + /* @FT_GlyphSlotRec structure to read it. */ + /* */ + /* FT_GLYPH_FORMAT_PLOTTER :: */ + /* The glyph image is a vectorial path with no inside and outside */ + /* contours. Some Type~1 fonts, like those in the Hershey family, */ + /* contain glyphs in this format. These are described as */ + /* @FT_Outline, but FreeType isn't currently capable of rendering */ + /* them correctly. */ + /* */ + typedef enum FT_Glyph_Format_ + { + FT_IMAGE_TAG( FT_GLYPH_FORMAT_NONE, 0, 0, 0, 0 ), + + FT_IMAGE_TAG( FT_GLYPH_FORMAT_COMPOSITE, 'c', 'o', 'm', 'p' ), + FT_IMAGE_TAG( FT_GLYPH_FORMAT_BITMAP, 'b', 'i', 't', 's' ), + FT_IMAGE_TAG( FT_GLYPH_FORMAT_OUTLINE, 'o', 'u', 't', 'l' ), + FT_IMAGE_TAG( FT_GLYPH_FORMAT_PLOTTER, 'p', 'l', 'o', 't' ) + + } FT_Glyph_Format; + + + /*************************************************************************/ + /* */ + /* <Enum> */ + /* ft_glyph_format_xxx */ + /* */ + /* <Description> */ + /* A list of deprecated constants. Use the corresponding */ + /* @FT_Glyph_Format values instead. */ + /* */ + /* <Values> */ + /* ft_glyph_format_none :: See @FT_GLYPH_FORMAT_NONE. */ + /* ft_glyph_format_composite :: See @FT_GLYPH_FORMAT_COMPOSITE. */ + /* ft_glyph_format_bitmap :: See @FT_GLYPH_FORMAT_BITMAP. */ + /* ft_glyph_format_outline :: See @FT_GLYPH_FORMAT_OUTLINE. */ + /* ft_glyph_format_plotter :: See @FT_GLYPH_FORMAT_PLOTTER. */ + /* */ +#define ft_glyph_format_none FT_GLYPH_FORMAT_NONE +#define ft_glyph_format_composite FT_GLYPH_FORMAT_COMPOSITE +#define ft_glyph_format_bitmap FT_GLYPH_FORMAT_BITMAP +#define ft_glyph_format_outline FT_GLYPH_FORMAT_OUTLINE +#define ft_glyph_format_plotter FT_GLYPH_FORMAT_PLOTTER + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** R A S T E R D E F I N I T I O N S *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* A raster is a scan converter, in charge of rendering an outline into */ + /* a a bitmap. This section contains the public API for rasters. */ + /* */ + /* Note that in FreeType 2, all rasters are now encapsulated within */ + /* specific modules called `renderers'. See `freetype/ftrender.h' for */ + /* more details on renderers. */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* <Section> */ + /* raster */ + /* */ + /* <Title> */ + /* Scanline Converter */ + /* */ + /* <Abstract> */ + /* How vectorial outlines are converted into bitmaps and pixmaps. */ + /* */ + /* <Description> */ + /* This section contains technical definitions. */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_Raster */ + /* */ + /* <Description> */ + /* A handle (pointer) to a raster object. Each object can be used */ + /* independently to convert an outline into a bitmap or pixmap. */ + /* */ + typedef struct FT_RasterRec_* FT_Raster; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_Span */ + /* */ + /* <Description> */ + /* A structure used to model a single span of gray (or black) pixels */ + /* when rendering a monochrome or anti-aliased bitmap. */ + /* */ + /* <Fields> */ + /* x :: The span's horizontal start position. */ + /* */ + /* len :: The span's length in pixels. */ + /* */ + /* coverage :: The span color/coverage, ranging from 0 (background) */ + /* to 255 (foreground). Only used for anti-aliased */ + /* rendering. */ + /* */ + /* <Note> */ + /* This structure is used by the span drawing callback type named */ + /* @FT_SpanFunc which takes the y~coordinate of the span as a */ + /* a parameter. */ + /* */ + /* The coverage value is always between 0 and 255. If you want less */ + /* gray values, the callback function has to reduce them. */ + /* */ + typedef struct FT_Span_ + { + short x; + unsigned short len; + unsigned char coverage; + + } FT_Span; + + + /*************************************************************************/ + /* */ + /* <FuncType> */ + /* FT_SpanFunc */ + /* */ + /* <Description> */ + /* A function used as a call-back by the anti-aliased renderer in */ + /* order to let client applications draw themselves the gray pixel */ + /* spans on each scan line. */ + /* */ + /* <Input> */ + /* y :: The scanline's y~coordinate. */ + /* */ + /* count :: The number of spans to draw on this scanline. */ + /* */ + /* spans :: A table of `count' spans to draw on the scanline. */ + /* */ + /* user :: User-supplied data that is passed to the callback. */ + /* */ + /* <Note> */ + /* This callback allows client applications to directly render the */ + /* gray spans of the anti-aliased bitmap to any kind of surfaces. */ + /* */ + /* This can be used to write anti-aliased outlines directly to a */ + /* given background bitmap, and even perform translucency. */ + /* */ + /* Note that the `count' field cannot be greater than a fixed value */ + /* defined by the `FT_MAX_GRAY_SPANS' configuration macro in */ + /* `ftoption.h'. By default, this value is set to~32, which means */ + /* that if there are more than 32~spans on a given scanline, the */ + /* callback is called several times with the same `y' parameter in */ + /* order to draw all callbacks. */ + /* */ + /* Otherwise, the callback is only called once per scan-line, and */ + /* only for those scanlines that do have `gray' pixels on them. */ + /* */ + typedef void + (*FT_SpanFunc)( int y, + int count, + const FT_Span* spans, + void* user ); + +#define FT_Raster_Span_Func FT_SpanFunc + + + /*************************************************************************/ + /* */ + /* <FuncType> */ + /* FT_Raster_BitTest_Func */ + /* */ + /* <Description> */ + /* THIS TYPE IS DEPRECATED. DO NOT USE IT. */ + /* */ + /* A function used as a call-back by the monochrome scan-converter */ + /* to test whether a given target pixel is already set to the drawing */ + /* `color'. These tests are crucial to implement drop-out control */ + /* per-se the TrueType spec. */ + /* */ + /* <Input> */ + /* y :: The pixel's y~coordinate. */ + /* */ + /* x :: The pixel's x~coordinate. */ + /* */ + /* user :: User-supplied data that is passed to the callback. */ + /* */ + /* <Return> */ + /* 1~if the pixel is `set', 0~otherwise. */ + /* */ + typedef int + (*FT_Raster_BitTest_Func)( int y, + int x, + void* user ); + + + /*************************************************************************/ + /* */ + /* <FuncType> */ + /* FT_Raster_BitSet_Func */ + /* */ + /* <Description> */ + /* THIS TYPE IS DEPRECATED. DO NOT USE IT. */ + /* */ + /* A function used as a call-back by the monochrome scan-converter */ + /* to set an individual target pixel. This is crucial to implement */ + /* drop-out control according to the TrueType specification. */ + /* */ + /* <Input> */ + /* y :: The pixel's y~coordinate. */ + /* */ + /* x :: The pixel's x~coordinate. */ + /* */ + /* user :: User-supplied data that is passed to the callback. */ + /* */ + /* <Return> */ + /* 1~if the pixel is `set', 0~otherwise. */ + /* */ + typedef void + (*FT_Raster_BitSet_Func)( int y, + int x, + void* user ); + + + /*************************************************************************/ + /* */ + /* <Enum> */ + /* FT_RASTER_FLAG_XXX */ + /* */ + /* <Description> */ + /* A list of bit flag constants as used in the `flags' field of a */ + /* @FT_Raster_Params structure. */ + /* */ + /* <Values> */ + /* FT_RASTER_FLAG_DEFAULT :: This value is 0. */ + /* */ + /* FT_RASTER_FLAG_AA :: This flag is set to indicate that an */ + /* anti-aliased glyph image should be */ + /* generated. Otherwise, it will be */ + /* monochrome (1-bit). */ + /* */ + /* FT_RASTER_FLAG_DIRECT :: This flag is set to indicate direct */ + /* rendering. In this mode, client */ + /* applications must provide their own span */ + /* callback. This lets them directly */ + /* draw or compose over an existing bitmap. */ + /* If this bit is not set, the target */ + /* pixmap's buffer _must_ be zeroed before */ + /* rendering. */ + /* */ + /* Note that for now, direct rendering is */ + /* only possible with anti-aliased glyphs. */ + /* */ + /* FT_RASTER_FLAG_CLIP :: This flag is only used in direct */ + /* rendering mode. If set, the output will */ + /* be clipped to a box specified in the */ + /* `clip_box' field of the */ + /* @FT_Raster_Params structure. */ + /* */ + /* Note that by default, the glyph bitmap */ + /* is clipped to the target pixmap, except */ + /* in direct rendering mode where all spans */ + /* are generated if no clipping box is set. */ + /* */ +#define FT_RASTER_FLAG_DEFAULT 0x0 +#define FT_RASTER_FLAG_AA 0x1 +#define FT_RASTER_FLAG_DIRECT 0x2 +#define FT_RASTER_FLAG_CLIP 0x4 + + /* deprecated */ +#define ft_raster_flag_default FT_RASTER_FLAG_DEFAULT +#define ft_raster_flag_aa FT_RASTER_FLAG_AA +#define ft_raster_flag_direct FT_RASTER_FLAG_DIRECT +#define ft_raster_flag_clip FT_RASTER_FLAG_CLIP + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_Raster_Params */ + /* */ + /* <Description> */ + /* A structure to hold the arguments used by a raster's render */ + /* function. */ + /* */ + /* <Fields> */ + /* target :: The target bitmap. */ + /* */ + /* source :: A pointer to the source glyph image (e.g., an */ + /* @FT_Outline). */ + /* */ + /* flags :: The rendering flags. */ + /* */ + /* gray_spans :: The gray span drawing callback. */ + /* */ + /* black_spans :: The black span drawing callback. UNIMPLEMENTED! */ + /* */ + /* bit_test :: The bit test callback. UNIMPLEMENTED! */ + /* */ + /* bit_set :: The bit set callback. UNIMPLEMENTED! */ + /* */ + /* user :: User-supplied data that is passed to each drawing */ + /* callback. */ + /* */ + /* clip_box :: An optional clipping box. It is only used in */ + /* direct rendering mode. Note that coordinates here */ + /* should be expressed in _integer_ pixels (and not in */ + /* 26.6 fixed-point units). */ + /* */ + /* <Note> */ + /* An anti-aliased glyph bitmap is drawn if the @FT_RASTER_FLAG_AA */ + /* bit flag is set in the `flags' field, otherwise a monochrome */ + /* bitmap is generated. */ + /* */ + /* If the @FT_RASTER_FLAG_DIRECT bit flag is set in `flags', the */ + /* raster will call the `gray_spans' callback to draw gray pixel */ + /* spans, in the case of an aa glyph bitmap, it will call */ + /* `black_spans', and `bit_test' and `bit_set' in the case of a */ + /* monochrome bitmap. This allows direct composition over a */ + /* pre-existing bitmap through user-provided callbacks to perform the */ + /* span drawing/composition. */ + /* */ + /* Note that the `bit_test' and `bit_set' callbacks are required when */ + /* rendering a monochrome bitmap, as they are crucial to implement */ + /* correct drop-out control as defined in the TrueType specification. */ + /* */ + typedef struct FT_Raster_Params_ + { + const FT_Bitmap* target; + const void* source; + int flags; + FT_SpanFunc gray_spans; + FT_SpanFunc black_spans; /* doesn't work! */ + FT_Raster_BitTest_Func bit_test; /* doesn't work! */ + FT_Raster_BitSet_Func bit_set; /* doesn't work! */ + void* user; + FT_BBox clip_box; + + } FT_Raster_Params; + + + /*************************************************************************/ + /* */ + /* <FuncType> */ + /* FT_Raster_NewFunc */ + /* */ + /* <Description> */ + /* A function used to create a new raster object. */ + /* */ + /* <Input> */ + /* memory :: A handle to the memory allocator. */ + /* */ + /* <Output> */ + /* raster :: A handle to the new raster object. */ + /* */ + /* <Return> */ + /* Error code. 0~means success. */ + /* */ + /* <Note> */ + /* The `memory' parameter is a typeless pointer in order to avoid */ + /* un-wanted dependencies on the rest of the FreeType code. In */ + /* practice, it is an @FT_Memory object, i.e., a handle to the */ + /* standard FreeType memory allocator. However, this field can be */ + /* completely ignored by a given raster implementation. */ + /* */ + typedef int + (*FT_Raster_NewFunc)( void* memory, + FT_Raster* raster ); + +#define FT_Raster_New_Func FT_Raster_NewFunc + + + /*************************************************************************/ + /* */ + /* <FuncType> */ + /* FT_Raster_DoneFunc */ + /* */ + /* <Description> */ + /* A function used to destroy a given raster object. */ + /* */ + /* <Input> */ + /* raster :: A handle to the raster object. */ + /* */ + typedef void + (*FT_Raster_DoneFunc)( FT_Raster raster ); + +#define FT_Raster_Done_Func FT_Raster_DoneFunc + + + /*************************************************************************/ + /* */ + /* <FuncType> */ + /* FT_Raster_ResetFunc */ + /* */ + /* <Description> */ + /* FreeType provides an area of memory called the `render pool', */ + /* available to all registered rasters. This pool can be freely used */ + /* during a given scan-conversion but is shared by all rasters. Its */ + /* content is thus transient. */ + /* */ + /* This function is called each time the render pool changes, or just */ + /* after a new raster object is created. */ + /* */ + /* <Input> */ + /* raster :: A handle to the new raster object. */ + /* */ + /* pool_base :: The address in memory of the render pool. */ + /* */ + /* pool_size :: The size in bytes of the render pool. */ + /* */ + /* <Note> */ + /* Rasters can ignore the render pool and rely on dynamic memory */ + /* allocation if they want to (a handle to the memory allocator is */ + /* passed to the raster constructor). However, this is not */ + /* recommended for efficiency purposes. */ + /* */ + typedef void + (*FT_Raster_ResetFunc)( FT_Raster raster, + unsigned char* pool_base, + unsigned long pool_size ); + +#define FT_Raster_Reset_Func FT_Raster_ResetFunc + + + /*************************************************************************/ + /* */ + /* <FuncType> */ + /* FT_Raster_SetModeFunc */ + /* */ + /* <Description> */ + /* This function is a generic facility to change modes or attributes */ + /* in a given raster. This can be used for debugging purposes, or */ + /* simply to allow implementation-specific `features' in a given */ + /* raster module. */ + /* */ + /* <Input> */ + /* raster :: A handle to the new raster object. */ + /* */ + /* mode :: A 4-byte tag used to name the mode or property. */ + /* */ + /* args :: A pointer to the new mode/property to use. */ + /* */ + typedef int + (*FT_Raster_SetModeFunc)( FT_Raster raster, + unsigned long mode, + void* args ); + +#define FT_Raster_Set_Mode_Func FT_Raster_SetModeFunc + + + /*************************************************************************/ + /* */ + /* <FuncType> */ + /* FT_Raster_RenderFunc */ + /* */ + /* <Description> */ + /* Invoke a given raster to scan-convert a given glyph image into a */ + /* target bitmap. */ + /* */ + /* <Input> */ + /* raster :: A handle to the raster object. */ + /* */ + /* params :: A pointer to an @FT_Raster_Params structure used to */ + /* store the rendering parameters. */ + /* */ + /* <Return> */ + /* Error code. 0~means success. */ + /* */ + /* <Note> */ + /* The exact format of the source image depends on the raster's glyph */ + /* format defined in its @FT_Raster_Funcs structure. It can be an */ + /* @FT_Outline or anything else in order to support a large array of */ + /* glyph formats. */ + /* */ + /* Note also that the render function can fail and return a */ + /* `FT_Err_Unimplemented_Feature' error code if the raster used does */ + /* not support direct composition. */ + /* */ + /* XXX: For now, the standard raster doesn't support direct */ + /* composition but this should change for the final release (see */ + /* the files `demos/src/ftgrays.c' and `demos/src/ftgrays2.c' */ + /* for examples of distinct implementations which support direct */ + /* composition). */ + /* */ + typedef int + (*FT_Raster_RenderFunc)( FT_Raster raster, + const FT_Raster_Params* params ); + +#define FT_Raster_Render_Func FT_Raster_RenderFunc + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_Raster_Funcs */ + /* */ + /* <Description> */ + /* A structure used to describe a given raster class to the library. */ + /* */ + /* <Fields> */ + /* glyph_format :: The supported glyph format for this raster. */ + /* */ + /* raster_new :: The raster constructor. */ + /* */ + /* raster_reset :: Used to reset the render pool within the raster. */ + /* */ + /* raster_render :: A function to render a glyph into a given bitmap. */ + /* */ + /* raster_done :: The raster destructor. */ + /* */ + typedef struct FT_Raster_Funcs_ + { + FT_Glyph_Format glyph_format; + FT_Raster_NewFunc raster_new; + FT_Raster_ResetFunc raster_reset; + FT_Raster_SetModeFunc raster_set_mode; + FT_Raster_RenderFunc raster_render; + FT_Raster_DoneFunc raster_done; + + } FT_Raster_Funcs; + + + /* */ + + +FT_END_HEADER + +#endif /* __FTIMAGE_H__ */ + + +/* END */ + + +/* Local Variables: */ +/* coding: utf-8 */ +/* End: */ diff --git a/Lib/Include/freetype/ftincrem.h b/Lib/Include/freetype/ftincrem.h new file mode 100644 index 0000000..aaf689f --- /dev/null +++ b/Lib/Include/freetype/ftincrem.h @@ -0,0 +1,353 @@ +/***************************************************************************/ +/* */ +/* ftincrem.h */ +/* */ +/* FreeType incremental loading (specification). */ +/* */ +/* Copyright 2002, 2003, 2006, 2007, 2008, 2010 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef __FTINCREM_H__ +#define __FTINCREM_H__ + +#include <ft2build.h> +#include FT_FREETYPE_H + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + /*************************************************************************** + * + * @section: + * incremental + * + * @title: + * Incremental Loading + * + * @abstract: + * Custom Glyph Loading. + * + * @description: + * This section contains various functions used to perform so-called + * `incremental' glyph loading. This is a mode where all glyphs loaded + * from a given @FT_Face are provided by the client application, + * + * Apart from that, all other tables are loaded normally from the font + * file. This mode is useful when FreeType is used within another + * engine, e.g., a PostScript Imaging Processor. + * + * To enable this mode, you must use @FT_Open_Face, passing an + * @FT_Parameter with the @FT_PARAM_TAG_INCREMENTAL tag and an + * @FT_Incremental_Interface value. See the comments for + * @FT_Incremental_InterfaceRec for an example. + * + */ + + + /*************************************************************************** + * + * @type: + * FT_Incremental + * + * @description: + * An opaque type describing a user-provided object used to implement + * `incremental' glyph loading within FreeType. This is used to support + * embedded fonts in certain environments (e.g., PostScript interpreters), + * where the glyph data isn't in the font file, or must be overridden by + * different values. + * + * @note: + * It is up to client applications to create and implement @FT_Incremental + * objects, as long as they provide implementations for the methods + * @FT_Incremental_GetGlyphDataFunc, @FT_Incremental_FreeGlyphDataFunc + * and @FT_Incremental_GetGlyphMetricsFunc. + * + * See the description of @FT_Incremental_InterfaceRec to understand how + * to use incremental objects with FreeType. + * + */ + typedef struct FT_IncrementalRec_* FT_Incremental; + + + /*************************************************************************** + * + * @struct: + * FT_Incremental_MetricsRec + * + * @description: + * A small structure used to contain the basic glyph metrics returned + * by the @FT_Incremental_GetGlyphMetricsFunc method. + * + * @fields: + * bearing_x :: + * Left bearing, in font units. + * + * bearing_y :: + * Top bearing, in font units. + * + * advance :: + * Horizontal component of glyph advance, in font units. + * + * advance_v :: + * Vertical component of glyph advance, in font units. + * + * @note: + * These correspond to horizontal or vertical metrics depending on the + * value of the `vertical' argument to the function + * @FT_Incremental_GetGlyphMetricsFunc. + * + */ + typedef struct FT_Incremental_MetricsRec_ + { + FT_Long bearing_x; + FT_Long bearing_y; + FT_Long advance; + FT_Long advance_v; /* since 2.3.12 */ + + } FT_Incremental_MetricsRec; + + + /*************************************************************************** + * + * @struct: + * FT_Incremental_Metrics + * + * @description: + * A handle to an @FT_Incremental_MetricsRec structure. + * + */ + typedef struct FT_Incremental_MetricsRec_* FT_Incremental_Metrics; + + + /*************************************************************************** + * + * @type: + * FT_Incremental_GetGlyphDataFunc + * + * @description: + * A function called by FreeType to access a given glyph's data bytes + * during @FT_Load_Glyph or @FT_Load_Char if incremental loading is + * enabled. + * + * Note that the format of the glyph's data bytes depends on the font + * file format. For TrueType, it must correspond to the raw bytes within + * the `glyf' table. For PostScript formats, it must correspond to the + * *unencrypted* charstring bytes, without any `lenIV' header. It is + * undefined for any other format. + * + * @input: + * incremental :: + * Handle to an opaque @FT_Incremental handle provided by the client + * application. + * + * glyph_index :: + * Index of relevant glyph. + * + * @output: + * adata :: + * A structure describing the returned glyph data bytes (which will be + * accessed as a read-only byte block). + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * If this function returns successfully the method + * @FT_Incremental_FreeGlyphDataFunc will be called later to release + * the data bytes. + * + * Nested calls to @FT_Incremental_GetGlyphDataFunc can happen for + * compound glyphs. + * + */ + typedef FT_Error + (*FT_Incremental_GetGlyphDataFunc)( FT_Incremental incremental, + FT_UInt glyph_index, + FT_Data* adata ); + + + /*************************************************************************** + * + * @type: + * FT_Incremental_FreeGlyphDataFunc + * + * @description: + * A function used to release the glyph data bytes returned by a + * successful call to @FT_Incremental_GetGlyphDataFunc. + * + * @input: + * incremental :: + * A handle to an opaque @FT_Incremental handle provided by the client + * application. + * + * data :: + * A structure describing the glyph data bytes (which will be accessed + * as a read-only byte block). + * + */ + typedef void + (*FT_Incremental_FreeGlyphDataFunc)( FT_Incremental incremental, + FT_Data* data ); + + + /*************************************************************************** + * + * @type: + * FT_Incremental_GetGlyphMetricsFunc + * + * @description: + * A function used to retrieve the basic metrics of a given glyph index + * before accessing its data. This is necessary because, in certain + * formats like TrueType, the metrics are stored in a different place from + * the glyph images proper. + * + * @input: + * incremental :: + * A handle to an opaque @FT_Incremental handle provided by the client + * application. + * + * glyph_index :: + * Index of relevant glyph. + * + * vertical :: + * If true, return vertical metrics. + * + * ametrics :: + * This parameter is used for both input and output. + * The original glyph metrics, if any, in font units. If metrics are + * not available all the values must be set to zero. + * + * @output: + * ametrics :: + * The replacement glyph metrics in font units. + * + */ + typedef FT_Error + (*FT_Incremental_GetGlyphMetricsFunc) + ( FT_Incremental incremental, + FT_UInt glyph_index, + FT_Bool vertical, + FT_Incremental_MetricsRec *ametrics ); + + + /************************************************************************** + * + * @struct: + * FT_Incremental_FuncsRec + * + * @description: + * A table of functions for accessing fonts that load data + * incrementally. Used in @FT_Incremental_InterfaceRec. + * + * @fields: + * get_glyph_data :: + * The function to get glyph data. Must not be null. + * + * free_glyph_data :: + * The function to release glyph data. Must not be null. + * + * get_glyph_metrics :: + * The function to get glyph metrics. May be null if the font does + * not provide overriding glyph metrics. + * + */ + typedef struct FT_Incremental_FuncsRec_ + { + FT_Incremental_GetGlyphDataFunc get_glyph_data; + FT_Incremental_FreeGlyphDataFunc free_glyph_data; + FT_Incremental_GetGlyphMetricsFunc get_glyph_metrics; + + } FT_Incremental_FuncsRec; + + + /*************************************************************************** + * + * @struct: + * FT_Incremental_InterfaceRec + * + * @description: + * A structure to be used with @FT_Open_Face to indicate that the user + * wants to support incremental glyph loading. You should use it with + * @FT_PARAM_TAG_INCREMENTAL as in the following example: + * + * { + * FT_Incremental_InterfaceRec inc_int; + * FT_Parameter parameter; + * FT_Open_Args open_args; + * + * + * // set up incremental descriptor + * inc_int.funcs = my_funcs; + * inc_int.object = my_object; + * + * // set up optional parameter + * parameter.tag = FT_PARAM_TAG_INCREMENTAL; + * parameter.data = &inc_int; + * + * // set up FT_Open_Args structure + * open_args.flags = FT_OPEN_PATHNAME | FT_OPEN_PARAMS; + * open_args.pathname = my_font_pathname; + * open_args.num_params = 1; + * open_args.params = ¶meter; // we use one optional argument + * + * // open the font + * error = FT_Open_Face( library, &open_args, index, &face ); + * ... + * } + * + */ + typedef struct FT_Incremental_InterfaceRec_ + { + const FT_Incremental_FuncsRec* funcs; + FT_Incremental object; + + } FT_Incremental_InterfaceRec; + + + /*************************************************************************** + * + * @type: + * FT_Incremental_Interface + * + * @description: + * A pointer to an @FT_Incremental_InterfaceRec structure. + * + */ + typedef FT_Incremental_InterfaceRec* FT_Incremental_Interface; + + + /*************************************************************************** + * + * @constant: + * FT_PARAM_TAG_INCREMENTAL + * + * @description: + * A constant used as the tag of @FT_Parameter structures to indicate + * an incremental loading object to be used by FreeType. + * + */ +#define FT_PARAM_TAG_INCREMENTAL FT_MAKE_TAG( 'i', 'n', 'c', 'r' ) + + /* */ + +FT_END_HEADER + +#endif /* __FTINCREM_H__ */ + + +/* END */ diff --git a/Lib/Include/freetype/ftlcdfil.h b/Lib/Include/freetype/ftlcdfil.h new file mode 100644 index 0000000..0b55ebe --- /dev/null +++ b/Lib/Include/freetype/ftlcdfil.h @@ -0,0 +1,213 @@ +/***************************************************************************/ +/* */ +/* ftlcdfil.h */ +/* */ +/* FreeType API for color filtering of subpixel bitmap glyphs */ +/* (specification). */ +/* */ +/* Copyright 2006, 2007, 2008, 2010 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef __FT_LCD_FILTER_H__ +#define __FT_LCD_FILTER_H__ + +#include <ft2build.h> +#include FT_FREETYPE_H + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + /*************************************************************************** + * + * @section: + * lcd_filtering + * + * @title: + * LCD Filtering + * + * @abstract: + * Reduce color fringes of LCD-optimized bitmaps. + * + * @description: + * The @FT_Library_SetLcdFilter API can be used to specify a low-pass + * filter which is then applied to LCD-optimized bitmaps generated + * through @FT_Render_Glyph. This is useful to reduce color fringes + * which would occur with unfiltered rendering. + * + * Note that no filter is active by default, and that this function is + * *not* implemented in default builds of the library. You need to + * #define FT_CONFIG_OPTION_SUBPIXEL_RENDERING in your `ftoption.h' file + * in order to activate it. + */ + + + /**************************************************************************** + * + * @enum: + * FT_LcdFilter + * + * @description: + * A list of values to identify various types of LCD filters. + * + * @values: + * FT_LCD_FILTER_NONE :: + * Do not perform filtering. When used with subpixel rendering, this + * results in sometimes severe color fringes. + * + * FT_LCD_FILTER_DEFAULT :: + * The default filter reduces color fringes considerably, at the cost + * of a slight blurriness in the output. + * + * FT_LCD_FILTER_LIGHT :: + * The light filter is a variant that produces less blurriness at the + * cost of slightly more color fringes than the default one. It might + * be better, depending on taste, your monitor, or your personal vision. + * + * FT_LCD_FILTER_LEGACY :: + * This filter corresponds to the original libXft color filter. It + * provides high contrast output but can exhibit really bad color + * fringes if glyphs are not extremely well hinted to the pixel grid. + * In other words, it only works well if the TrueType bytecode + * interpreter is enabled *and* high-quality hinted fonts are used. + * + * This filter is only provided for comparison purposes, and might be + * disabled or stay unsupported in the future. + * + * @since: + * 2.3.0 + */ + typedef enum FT_LcdFilter_ + { + FT_LCD_FILTER_NONE = 0, + FT_LCD_FILTER_DEFAULT = 1, + FT_LCD_FILTER_LIGHT = 2, + FT_LCD_FILTER_LEGACY = 16, + + FT_LCD_FILTER_MAX /* do not remove */ + + } FT_LcdFilter; + + + /************************************************************************** + * + * @func: + * FT_Library_SetLcdFilter + * + * @description: + * This function is used to apply color filtering to LCD decimated + * bitmaps, like the ones used when calling @FT_Render_Glyph with + * @FT_RENDER_MODE_LCD or @FT_RENDER_MODE_LCD_V. + * + * @input: + * library :: + * A handle to the target library instance. + * + * filter :: + * The filter type. + * + * You can use @FT_LCD_FILTER_NONE here to disable this feature, or + * @FT_LCD_FILTER_DEFAULT to use a default filter that should work + * well on most LCD screens. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * This feature is always disabled by default. Clients must make an + * explicit call to this function with a `filter' value other than + * @FT_LCD_FILTER_NONE in order to enable it. + * + * Due to *PATENTS* covering subpixel rendering, this function doesn't + * do anything except returning `FT_Err_Unimplemented_Feature' if the + * configuration macro FT_CONFIG_OPTION_SUBPIXEL_RENDERING is not + * defined in your build of the library, which should correspond to all + * default builds of FreeType. + * + * The filter affects glyph bitmaps rendered through @FT_Render_Glyph, + * @FT_Outline_Get_Bitmap, @FT_Load_Glyph, and @FT_Load_Char. + * + * It does _not_ affect the output of @FT_Outline_Render and + * @FT_Outline_Get_Bitmap. + * + * If this feature is activated, the dimensions of LCD glyph bitmaps are + * either larger or taller than the dimensions of the corresponding + * outline with regards to the pixel grid. For example, for + * @FT_RENDER_MODE_LCD, the filter adds up to 3~pixels to the left, and + * up to 3~pixels to the right. + * + * The bitmap offset values are adjusted correctly, so clients shouldn't + * need to modify their layout and glyph positioning code when enabling + * the filter. + * + * @since: + * 2.3.0 + */ + FT_EXPORT( FT_Error ) + FT_Library_SetLcdFilter( FT_Library library, + FT_LcdFilter filter ); + + + /************************************************************************** + * + * @func: + * FT_Library_SetLcdFilterWeights + * + * @description: + * Use this function to override the filter weights selected by + * @FT_Library_SetLcdFilter. By default, FreeType uses the quintuple + * (0x00, 0x55, 0x56, 0x55, 0x00) for FT_LCD_FILTER_LIGHT, and (0x10, + * 0x40, 0x70, 0x40, 0x10) for FT_LCD_FILTER_DEFAULT and + * FT_LCD_FILTER_LEGACY. + * + * @input: + * library :: + * A handle to the target library instance. + * + * weights :: + * A pointer to an array; the function copies the first five bytes and + * uses them to specify the filter weights. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * Due to *PATENTS* covering subpixel rendering, this function doesn't + * do anything except returning `FT_Err_Unimplemented_Feature' if the + * configuration macro FT_CONFIG_OPTION_SUBPIXEL_RENDERING is not + * defined in your build of the library, which should correspond to all + * default builds of FreeType. + * + * This function must be called after @FT_Library_SetLcdFilter to have + * any effect. + * + * @since: + * 2.4.0 + */ + FT_EXPORT( FT_Error ) + FT_Library_SetLcdFilterWeights( FT_Library library, + unsigned char *weights ); + + /* */ + + +FT_END_HEADER + +#endif /* __FT_LCD_FILTER_H__ */ + + +/* END */ diff --git a/Lib/Include/freetype/ftlist.h b/Lib/Include/freetype/ftlist.h new file mode 100644 index 0000000..bb6f7f1 --- /dev/null +++ b/Lib/Include/freetype/ftlist.h @@ -0,0 +1,277 @@ +/***************************************************************************/ +/* */ +/* ftlist.h */ +/* */ +/* Generic list support for FreeType (specification). */ +/* */ +/* Copyright 1996-2001, 2003, 2007, 2010 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + + /*************************************************************************/ + /* */ + /* This file implements functions relative to list processing. Its */ + /* data structures are defined in `freetype.h'. */ + /* */ + /*************************************************************************/ + + +#ifndef __FTLIST_H__ +#define __FTLIST_H__ + + +#include <ft2build.h> +#include FT_FREETYPE_H + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /* */ + /* <Section> */ + /* list_processing */ + /* */ + /* <Title> */ + /* List Processing */ + /* */ + /* <Abstract> */ + /* Simple management of lists. */ + /* */ + /* <Description> */ + /* This section contains various definitions related to list */ + /* processing using doubly-linked nodes. */ + /* */ + /* <Order> */ + /* FT_List */ + /* FT_ListNode */ + /* FT_ListRec */ + /* FT_ListNodeRec */ + /* */ + /* FT_List_Add */ + /* FT_List_Insert */ + /* FT_List_Find */ + /* FT_List_Remove */ + /* FT_List_Up */ + /* FT_List_Iterate */ + /* FT_List_Iterator */ + /* FT_List_Finalize */ + /* FT_List_Destructor */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_List_Find */ + /* */ + /* <Description> */ + /* Find the list node for a given listed object. */ + /* */ + /* <Input> */ + /* list :: A pointer to the parent list. */ + /* data :: The address of the listed object. */ + /* */ + /* <Return> */ + /* List node. NULL if it wasn't found. */ + /* */ + FT_EXPORT( FT_ListNode ) + FT_List_Find( FT_List list, + void* data ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_List_Add */ + /* */ + /* <Description> */ + /* Append an element to the end of a list. */ + /* */ + /* <InOut> */ + /* list :: A pointer to the parent list. */ + /* node :: The node to append. */ + /* */ + FT_EXPORT( void ) + FT_List_Add( FT_List list, + FT_ListNode node ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_List_Insert */ + /* */ + /* <Description> */ + /* Insert an element at the head of a list. */ + /* */ + /* <InOut> */ + /* list :: A pointer to parent list. */ + /* node :: The node to insert. */ + /* */ + FT_EXPORT( void ) + FT_List_Insert( FT_List list, + FT_ListNode node ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_List_Remove */ + /* */ + /* <Description> */ + /* Remove a node from a list. This function doesn't check whether */ + /* the node is in the list! */ + /* */ + /* <Input> */ + /* node :: The node to remove. */ + /* */ + /* <InOut> */ + /* list :: A pointer to the parent list. */ + /* */ + FT_EXPORT( void ) + FT_List_Remove( FT_List list, + FT_ListNode node ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_List_Up */ + /* */ + /* <Description> */ + /* Move a node to the head/top of a list. Used to maintain LRU */ + /* lists. */ + /* */ + /* <InOut> */ + /* list :: A pointer to the parent list. */ + /* node :: The node to move. */ + /* */ + FT_EXPORT( void ) + FT_List_Up( FT_List list, + FT_ListNode node ); + + + /*************************************************************************/ + /* */ + /* <FuncType> */ + /* FT_List_Iterator */ + /* */ + /* <Description> */ + /* An FT_List iterator function which is called during a list parse */ + /* by @FT_List_Iterate. */ + /* */ + /* <Input> */ + /* node :: The current iteration list node. */ + /* */ + /* user :: A typeless pointer passed to @FT_List_Iterate. */ + /* Can be used to point to the iteration's state. */ + /* */ + typedef FT_Error + (*FT_List_Iterator)( FT_ListNode node, + void* user ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_List_Iterate */ + /* */ + /* <Description> */ + /* Parse a list and calls a given iterator function on each element. */ + /* Note that parsing is stopped as soon as one of the iterator calls */ + /* returns a non-zero value. */ + /* */ + /* <Input> */ + /* list :: A handle to the list. */ + /* iterator :: An iterator function, called on each node of the list. */ + /* user :: A user-supplied field which is passed as the second */ + /* argument to the iterator. */ + /* */ + /* <Return> */ + /* The result (a FreeType error code) of the last iterator call. */ + /* */ + FT_EXPORT( FT_Error ) + FT_List_Iterate( FT_List list, + FT_List_Iterator iterator, + void* user ); + + + /*************************************************************************/ + /* */ + /* <FuncType> */ + /* FT_List_Destructor */ + /* */ + /* <Description> */ + /* An @FT_List iterator function which is called during a list */ + /* finalization by @FT_List_Finalize to destroy all elements in a */ + /* given list. */ + /* */ + /* <Input> */ + /* system :: The current system object. */ + /* */ + /* data :: The current object to destroy. */ + /* */ + /* user :: A typeless pointer passed to @FT_List_Iterate. It can */ + /* be used to point to the iteration's state. */ + /* */ + typedef void + (*FT_List_Destructor)( FT_Memory memory, + void* data, + void* user ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_List_Finalize */ + /* */ + /* <Description> */ + /* Destroy all elements in the list as well as the list itself. */ + /* */ + /* <Input> */ + /* list :: A handle to the list. */ + /* */ + /* destroy :: A list destructor that will be applied to each element */ + /* of the list. */ + /* */ + /* memory :: The current memory object which handles deallocation. */ + /* */ + /* user :: A user-supplied field which is passed as the last */ + /* argument to the destructor. */ + /* */ + /* <Note> */ + /* This function expects that all nodes added by @FT_List_Add or */ + /* @FT_List_Insert have been dynamically allocated. */ + /* */ + FT_EXPORT( void ) + FT_List_Finalize( FT_List list, + FT_List_Destructor destroy, + FT_Memory memory, + void* user ); + + + /* */ + + +FT_END_HEADER + +#endif /* __FTLIST_H__ */ + + +/* END */ diff --git a/Lib/Include/freetype/ftlzw.h b/Lib/Include/freetype/ftlzw.h new file mode 100644 index 0000000..00d4016 --- /dev/null +++ b/Lib/Include/freetype/ftlzw.h @@ -0,0 +1,99 @@ +/***************************************************************************/ +/* */ +/* ftlzw.h */ +/* */ +/* LZW-compressed stream support. */ +/* */ +/* Copyright 2004, 2006 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef __FTLZW_H__ +#define __FTLZW_H__ + +#include <ft2build.h> +#include FT_FREETYPE_H + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + /*************************************************************************/ + /* */ + /* <Section> */ + /* lzw */ + /* */ + /* <Title> */ + /* LZW Streams */ + /* */ + /* <Abstract> */ + /* Using LZW-compressed font files. */ + /* */ + /* <Description> */ + /* This section contains the declaration of LZW-specific functions. */ + /* */ + /*************************************************************************/ + + /************************************************************************ + * + * @function: + * FT_Stream_OpenLZW + * + * @description: + * Open a new stream to parse LZW-compressed font files. This is + * mainly used to support the compressed `*.pcf.Z' fonts that come + * with XFree86. + * + * @input: + * stream :: The target embedding stream. + * + * source :: The source stream. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * The source stream must be opened _before_ calling this function. + * + * Calling the internal function `FT_Stream_Close' on the new stream will + * *not* call `FT_Stream_Close' on the source stream. None of the stream + * objects will be released to the heap. + * + * The stream implementation is very basic and resets the decompression + * process each time seeking backwards is needed within the stream + * + * In certain builds of the library, LZW compression recognition is + * automatically handled when calling @FT_New_Face or @FT_Open_Face. + * This means that if no font driver is capable of handling the raw + * compressed file, the library will try to open a LZW stream from it + * and re-open the face with it. + * + * This function may return `FT_Err_Unimplemented_Feature' if your build + * of FreeType was not compiled with LZW support. + */ + FT_EXPORT( FT_Error ) + FT_Stream_OpenLZW( FT_Stream stream, + FT_Stream source ); + + /* */ + + +FT_END_HEADER + +#endif /* __FTLZW_H__ */ + + +/* END */ diff --git a/Lib/Include/freetype/ftmac.h b/Lib/Include/freetype/ftmac.h new file mode 100644 index 0000000..ab5bab5 --- /dev/null +++ b/Lib/Include/freetype/ftmac.h @@ -0,0 +1,274 @@ +/***************************************************************************/ +/* */ +/* ftmac.h */ +/* */ +/* Additional Mac-specific API. */ +/* */ +/* Copyright 1996-2001, 2004, 2006, 2007 by */ +/* Just van Rossum, David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +/***************************************************************************/ +/* */ +/* NOTE: Include this file after <freetype/freetype.h> and after any */ +/* Mac-specific headers (because this header uses Mac types such as */ +/* Handle, FSSpec, FSRef, etc.) */ +/* */ +/***************************************************************************/ + + +#ifndef __FTMAC_H__ +#define __FTMAC_H__ + + +#include <ft2build.h> + + +FT_BEGIN_HEADER + + +/* gcc-3.4.1 and later can warn about functions tagged as deprecated */ +#ifndef FT_DEPRECATED_ATTRIBUTE +#if defined(__GNUC__) && \ + ((__GNUC__ >= 4) || ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 1))) +#define FT_DEPRECATED_ATTRIBUTE __attribute__((deprecated)) +#else +#define FT_DEPRECATED_ATTRIBUTE +#endif +#endif + + + /*************************************************************************/ + /* */ + /* <Section> */ + /* mac_specific */ + /* */ + /* <Title> */ + /* Mac Specific Interface */ + /* */ + /* <Abstract> */ + /* Only available on the Macintosh. */ + /* */ + /* <Description> */ + /* The following definitions are only available if FreeType is */ + /* compiled on a Macintosh. */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_New_Face_From_FOND */ + /* */ + /* <Description> */ + /* Create a new face object from a FOND resource. */ + /* */ + /* <InOut> */ + /* library :: A handle to the library resource. */ + /* */ + /* <Input> */ + /* fond :: A FOND resource. */ + /* */ + /* face_index :: Only supported for the -1 `sanity check' special */ + /* case. */ + /* */ + /* <Output> */ + /* aface :: A handle to a new face object. */ + /* */ + /* <Return> */ + /* FreeType error code. 0~means success. */ + /* */ + /* <Notes> */ + /* This function can be used to create @FT_Face objects from fonts */ + /* that are installed in the system as follows. */ + /* */ + /* { */ + /* fond = GetResource( 'FOND', fontName ); */ + /* error = FT_New_Face_From_FOND( library, fond, 0, &face ); */ + /* } */ + /* */ + FT_EXPORT( FT_Error ) + FT_New_Face_From_FOND( FT_Library library, + Handle fond, + FT_Long face_index, + FT_Face *aface ) + FT_DEPRECATED_ATTRIBUTE; + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_GetFile_From_Mac_Name */ + /* */ + /* <Description> */ + /* Return an FSSpec for the disk file containing the named font. */ + /* */ + /* <Input> */ + /* fontName :: Mac OS name of the font (e.g., Times New Roman */ + /* Bold). */ + /* */ + /* <Output> */ + /* pathSpec :: FSSpec to the file. For passing to */ + /* @FT_New_Face_From_FSSpec. */ + /* */ + /* face_index :: Index of the face. For passing to */ + /* @FT_New_Face_From_FSSpec. */ + /* */ + /* <Return> */ + /* FreeType error code. 0~means success. */ + /* */ + FT_EXPORT( FT_Error ) + FT_GetFile_From_Mac_Name( const char* fontName, + FSSpec* pathSpec, + FT_Long* face_index ) + FT_DEPRECATED_ATTRIBUTE; + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_GetFile_From_Mac_ATS_Name */ + /* */ + /* <Description> */ + /* Return an FSSpec for the disk file containing the named font. */ + /* */ + /* <Input> */ + /* fontName :: Mac OS name of the font in ATS framework. */ + /* */ + /* <Output> */ + /* pathSpec :: FSSpec to the file. For passing to */ + /* @FT_New_Face_From_FSSpec. */ + /* */ + /* face_index :: Index of the face. For passing to */ + /* @FT_New_Face_From_FSSpec. */ + /* */ + /* <Return> */ + /* FreeType error code. 0~means success. */ + /* */ + FT_EXPORT( FT_Error ) + FT_GetFile_From_Mac_ATS_Name( const char* fontName, + FSSpec* pathSpec, + FT_Long* face_index ) + FT_DEPRECATED_ATTRIBUTE; + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_GetFilePath_From_Mac_ATS_Name */ + /* */ + /* <Description> */ + /* Return a pathname of the disk file and face index for given font */ + /* name which is handled by ATS framework. */ + /* */ + /* <Input> */ + /* fontName :: Mac OS name of the font in ATS framework. */ + /* */ + /* <Output> */ + /* path :: Buffer to store pathname of the file. For passing */ + /* to @FT_New_Face. The client must allocate this */ + /* buffer before calling this function. */ + /* */ + /* maxPathSize :: Lengths of the buffer `path' that client allocated. */ + /* */ + /* face_index :: Index of the face. For passing to @FT_New_Face. */ + /* */ + /* <Return> */ + /* FreeType error code. 0~means success. */ + /* */ + FT_EXPORT( FT_Error ) + FT_GetFilePath_From_Mac_ATS_Name( const char* fontName, + UInt8* path, + UInt32 maxPathSize, + FT_Long* face_index ) + FT_DEPRECATED_ATTRIBUTE; + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_New_Face_From_FSSpec */ + /* */ + /* <Description> */ + /* Create a new face object from a given resource and typeface index */ + /* using an FSSpec to the font file. */ + /* */ + /* <InOut> */ + /* library :: A handle to the library resource. */ + /* */ + /* <Input> */ + /* spec :: FSSpec to the font file. */ + /* */ + /* face_index :: The index of the face within the resource. The */ + /* first face has index~0. */ + /* <Output> */ + /* aface :: A handle to a new face object. */ + /* */ + /* <Return> */ + /* FreeType error code. 0~means success. */ + /* */ + /* <Note> */ + /* @FT_New_Face_From_FSSpec is identical to @FT_New_Face except */ + /* it accepts an FSSpec instead of a path. */ + /* */ + FT_EXPORT( FT_Error ) + FT_New_Face_From_FSSpec( FT_Library library, + const FSSpec *spec, + FT_Long face_index, + FT_Face *aface ) + FT_DEPRECATED_ATTRIBUTE; + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_New_Face_From_FSRef */ + /* */ + /* <Description> */ + /* Create a new face object from a given resource and typeface index */ + /* using an FSRef to the font file. */ + /* */ + /* <InOut> */ + /* library :: A handle to the library resource. */ + /* */ + /* <Input> */ + /* spec :: FSRef to the font file. */ + /* */ + /* face_index :: The index of the face within the resource. The */ + /* first face has index~0. */ + /* <Output> */ + /* aface :: A handle to a new face object. */ + /* */ + /* <Return> */ + /* FreeType error code. 0~means success. */ + /* */ + /* <Note> */ + /* @FT_New_Face_From_FSRef is identical to @FT_New_Face except */ + /* it accepts an FSRef instead of a path. */ + /* */ + FT_EXPORT( FT_Error ) + FT_New_Face_From_FSRef( FT_Library library, + const FSRef *ref, + FT_Long face_index, + FT_Face *aface ) + FT_DEPRECATED_ATTRIBUTE; + + /* */ + + +FT_END_HEADER + + +#endif /* __FTMAC_H__ */ + + +/* END */ diff --git a/Lib/Include/freetype/ftmm.h b/Lib/Include/freetype/ftmm.h new file mode 100644 index 0000000..3aefb9e --- /dev/null +++ b/Lib/Include/freetype/ftmm.h @@ -0,0 +1,378 @@ +/***************************************************************************/ +/* */ +/* ftmm.h */ +/* */ +/* FreeType Multiple Master font interface (specification). */ +/* */ +/* Copyright 1996-2001, 2003, 2004, 2006, 2009 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef __FTMM_H__ +#define __FTMM_H__ + + +#include <ft2build.h> +#include FT_TYPE1_TABLES_H + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /* */ + /* <Section> */ + /* multiple_masters */ + /* */ + /* <Title> */ + /* Multiple Masters */ + /* */ + /* <Abstract> */ + /* How to manage Multiple Masters fonts. */ + /* */ + /* <Description> */ + /* The following types and functions are used to manage Multiple */ + /* Master fonts, i.e., the selection of specific design instances by */ + /* setting design axis coordinates. */ + /* */ + /* George Williams has extended this interface to make it work with */ + /* both Type~1 Multiple Masters fonts and GX distortable (var) */ + /* fonts. Some of these routines only work with MM fonts, others */ + /* will work with both types. They are similar enough that a */ + /* consistent interface makes sense. */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_MM_Axis */ + /* */ + /* <Description> */ + /* A simple structure used to model a given axis in design space for */ + /* Multiple Masters fonts. */ + /* */ + /* This structure can't be used for GX var fonts. */ + /* */ + /* <Fields> */ + /* name :: The axis's name. */ + /* */ + /* minimum :: The axis's minimum design coordinate. */ + /* */ + /* maximum :: The axis's maximum design coordinate. */ + /* */ + typedef struct FT_MM_Axis_ + { + FT_String* name; + FT_Long minimum; + FT_Long maximum; + + } FT_MM_Axis; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_Multi_Master */ + /* */ + /* <Description> */ + /* A structure used to model the axes and space of a Multiple Masters */ + /* font. */ + /* */ + /* This structure can't be used for GX var fonts. */ + /* */ + /* <Fields> */ + /* num_axis :: Number of axes. Cannot exceed~4. */ + /* */ + /* num_designs :: Number of designs; should be normally 2^num_axis */ + /* even though the Type~1 specification strangely */ + /* allows for intermediate designs to be present. This */ + /* number cannot exceed~16. */ + /* */ + /* axis :: A table of axis descriptors. */ + /* */ + typedef struct FT_Multi_Master_ + { + FT_UInt num_axis; + FT_UInt num_designs; + FT_MM_Axis axis[T1_MAX_MM_AXIS]; + + } FT_Multi_Master; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_Var_Axis */ + /* */ + /* <Description> */ + /* A simple structure used to model a given axis in design space for */ + /* Multiple Masters and GX var fonts. */ + /* */ + /* <Fields> */ + /* name :: The axis's name. */ + /* Not always meaningful for GX. */ + /* */ + /* minimum :: The axis's minimum design coordinate. */ + /* */ + /* def :: The axis's default design coordinate. */ + /* FreeType computes meaningful default values for MM; it */ + /* is then an integer value, not in 16.16 format. */ + /* */ + /* maximum :: The axis's maximum design coordinate. */ + /* */ + /* tag :: The axis's tag (the GX equivalent to `name'). */ + /* FreeType provides default values for MM if possible. */ + /* */ + /* strid :: The entry in `name' table (another GX version of */ + /* `name'). */ + /* Not meaningful for MM. */ + /* */ + typedef struct FT_Var_Axis_ + { + FT_String* name; + + FT_Fixed minimum; + FT_Fixed def; + FT_Fixed maximum; + + FT_ULong tag; + FT_UInt strid; + + } FT_Var_Axis; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_Var_Named_Style */ + /* */ + /* <Description> */ + /* A simple structure used to model a named style in a GX var font. */ + /* */ + /* This structure can't be used for MM fonts. */ + /* */ + /* <Fields> */ + /* coords :: The design coordinates for this style. */ + /* This is an array with one entry for each axis. */ + /* */ + /* strid :: The entry in `name' table identifying this style. */ + /* */ + typedef struct FT_Var_Named_Style_ + { + FT_Fixed* coords; + FT_UInt strid; + + } FT_Var_Named_Style; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_MM_Var */ + /* */ + /* <Description> */ + /* A structure used to model the axes and space of a Multiple Masters */ + /* or GX var distortable font. */ + /* */ + /* Some fields are specific to one format and not to the other. */ + /* */ + /* <Fields> */ + /* num_axis :: The number of axes. The maximum value is~4 for */ + /* MM; no limit in GX. */ + /* */ + /* num_designs :: The number of designs; should be normally */ + /* 2^num_axis for MM fonts. Not meaningful for GX */ + /* (where every glyph could have a different */ + /* number of designs). */ + /* */ + /* num_namedstyles :: The number of named styles; only meaningful for */ + /* GX which allows certain design coordinates to */ + /* have a string ID (in the `name' table) */ + /* associated with them. The font can tell the */ + /* user that, for example, Weight=1.5 is `Bold'. */ + /* */ + /* axis :: A table of axis descriptors. */ + /* GX fonts contain slightly more data than MM. */ + /* */ + /* namedstyles :: A table of named styles. */ + /* Only meaningful with GX. */ + /* */ + typedef struct FT_MM_Var_ + { + FT_UInt num_axis; + FT_UInt num_designs; + FT_UInt num_namedstyles; + FT_Var_Axis* axis; + FT_Var_Named_Style* namedstyle; + + } FT_MM_Var; + + + /* */ + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Get_Multi_Master */ + /* */ + /* <Description> */ + /* Retrieve the Multiple Master descriptor of a given font. */ + /* */ + /* This function can't be used with GX fonts. */ + /* */ + /* <Input> */ + /* face :: A handle to the source face. */ + /* */ + /* <Output> */ + /* amaster :: The Multiple Masters descriptor. */ + /* */ + /* <Return> */ + /* FreeType error code. 0~means success. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Get_Multi_Master( FT_Face face, + FT_Multi_Master *amaster ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Get_MM_Var */ + /* */ + /* <Description> */ + /* Retrieve the Multiple Master/GX var descriptor of a given font. */ + /* */ + /* <Input> */ + /* face :: A handle to the source face. */ + /* */ + /* <Output> */ + /* amaster :: The Multiple Masters/GX var descriptor. */ + /* Allocates a data structure, which the user must free */ + /* (a single call to FT_FREE will do it). */ + /* */ + /* <Return> */ + /* FreeType error code. 0~means success. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Get_MM_Var( FT_Face face, + FT_MM_Var* *amaster ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Set_MM_Design_Coordinates */ + /* */ + /* <Description> */ + /* For Multiple Masters fonts, choose an interpolated font design */ + /* through design coordinates. */ + /* */ + /* This function can't be used with GX fonts. */ + /* */ + /* <InOut> */ + /* face :: A handle to the source face. */ + /* */ + /* <Input> */ + /* num_coords :: The number of design coordinates (must be equal to */ + /* the number of axes in the font). */ + /* */ + /* coords :: An array of design coordinates. */ + /* */ + /* <Return> */ + /* FreeType error code. 0~means success. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Set_MM_Design_Coordinates( FT_Face face, + FT_UInt num_coords, + FT_Long* coords ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Set_Var_Design_Coordinates */ + /* */ + /* <Description> */ + /* For Multiple Master or GX Var fonts, choose an interpolated font */ + /* design through design coordinates. */ + /* */ + /* <InOut> */ + /* face :: A handle to the source face. */ + /* */ + /* <Input> */ + /* num_coords :: The number of design coordinates (must be equal to */ + /* the number of axes in the font). */ + /* */ + /* coords :: An array of design coordinates. */ + /* */ + /* <Return> */ + /* FreeType error code. 0~means success. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Set_Var_Design_Coordinates( FT_Face face, + FT_UInt num_coords, + FT_Fixed* coords ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Set_MM_Blend_Coordinates */ + /* */ + /* <Description> */ + /* For Multiple Masters and GX var fonts, choose an interpolated font */ + /* design through normalized blend coordinates. */ + /* */ + /* <InOut> */ + /* face :: A handle to the source face. */ + /* */ + /* <Input> */ + /* num_coords :: The number of design coordinates (must be equal to */ + /* the number of axes in the font). */ + /* */ + /* coords :: The design coordinates array (each element must be */ + /* between 0 and 1.0). */ + /* */ + /* <Return> */ + /* FreeType error code. 0~means success. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Set_MM_Blend_Coordinates( FT_Face face, + FT_UInt num_coords, + FT_Fixed* coords ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Set_Var_Blend_Coordinates */ + /* */ + /* <Description> */ + /* This is another name of @FT_Set_MM_Blend_Coordinates. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Set_Var_Blend_Coordinates( FT_Face face, + FT_UInt num_coords, + FT_Fixed* coords ); + + + /* */ + + +FT_END_HEADER + +#endif /* __FTMM_H__ */ + + +/* END */ diff --git a/Lib/Include/freetype/ftmodapi.h b/Lib/Include/freetype/ftmodapi.h new file mode 100644 index 0000000..8f2e017 --- /dev/null +++ b/Lib/Include/freetype/ftmodapi.h @@ -0,0 +1,483 @@ +/***************************************************************************/ +/* */ +/* ftmodapi.h */ +/* */ +/* FreeType modules public interface (specification). */ +/* */ +/* Copyright 1996-2001, 2002, 2003, 2006, 2008, 2009, 2010 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef __FTMODAPI_H__ +#define __FTMODAPI_H__ + + +#include <ft2build.h> +#include FT_FREETYPE_H + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /* */ + /* <Section> */ + /* module_management */ + /* */ + /* <Title> */ + /* Module Management */ + /* */ + /* <Abstract> */ + /* How to add, upgrade, and remove modules from FreeType. */ + /* */ + /* <Description> */ + /* The definitions below are used to manage modules within FreeType. */ + /* Modules can be added, upgraded, and removed at runtime. */ + /* */ + /*************************************************************************/ + + + /* module bit flags */ +#define FT_MODULE_FONT_DRIVER 1 /* this module is a font driver */ +#define FT_MODULE_RENDERER 2 /* this module is a renderer */ +#define FT_MODULE_HINTER 4 /* this module is a glyph hinter */ +#define FT_MODULE_STYLER 8 /* this module is a styler */ + +#define FT_MODULE_DRIVER_SCALABLE 0x100 /* the driver supports */ + /* scalable fonts */ +#define FT_MODULE_DRIVER_NO_OUTLINES 0x200 /* the driver does not */ + /* support vector outlines */ +#define FT_MODULE_DRIVER_HAS_HINTER 0x400 /* the driver provides its */ + /* own hinter */ + + + /* deprecated values */ +#define ft_module_font_driver FT_MODULE_FONT_DRIVER +#define ft_module_renderer FT_MODULE_RENDERER +#define ft_module_hinter FT_MODULE_HINTER +#define ft_module_styler FT_MODULE_STYLER + +#define ft_module_driver_scalable FT_MODULE_DRIVER_SCALABLE +#define ft_module_driver_no_outlines FT_MODULE_DRIVER_NO_OUTLINES +#define ft_module_driver_has_hinter FT_MODULE_DRIVER_HAS_HINTER + + + typedef FT_Pointer FT_Module_Interface; + + + /*************************************************************************/ + /* */ + /* <FuncType> */ + /* FT_Module_Constructor */ + /* */ + /* <Description> */ + /* A function used to initialize (not create) a new module object. */ + /* */ + /* <Input> */ + /* module :: The module to initialize. */ + /* */ + typedef FT_Error + (*FT_Module_Constructor)( FT_Module module ); + + + /*************************************************************************/ + /* */ + /* <FuncType> */ + /* FT_Module_Destructor */ + /* */ + /* <Description> */ + /* A function used to finalize (not destroy) a given module object. */ + /* */ + /* <Input> */ + /* module :: The module to finalize. */ + /* */ + typedef void + (*FT_Module_Destructor)( FT_Module module ); + + + /*************************************************************************/ + /* */ + /* <FuncType> */ + /* FT_Module_Requester */ + /* */ + /* <Description> */ + /* A function used to query a given module for a specific interface. */ + /* */ + /* <Input> */ + /* module :: The module to finalize. */ + /* */ + /* name :: The name of the interface in the module. */ + /* */ + typedef FT_Module_Interface + (*FT_Module_Requester)( FT_Module module, + const char* name ); + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_Module_Class */ + /* */ + /* <Description> */ + /* The module class descriptor. */ + /* */ + /* <Fields> */ + /* module_flags :: Bit flags describing the module. */ + /* */ + /* module_size :: The size of one module object/instance in */ + /* bytes. */ + /* */ + /* module_name :: The name of the module. */ + /* */ + /* module_version :: The version, as a 16.16 fixed number */ + /* (major.minor). */ + /* */ + /* module_requires :: The version of FreeType this module requires, */ + /* as a 16.16 fixed number (major.minor). Starts */ + /* at version 2.0, i.e., 0x20000. */ + /* */ + /* module_init :: The initializing function. */ + /* */ + /* module_done :: The finalizing function. */ + /* */ + /* get_interface :: The interface requesting function. */ + /* */ + typedef struct FT_Module_Class_ + { + FT_ULong module_flags; + FT_Long module_size; + const FT_String* module_name; + FT_Fixed module_version; + FT_Fixed module_requires; + + const void* module_interface; + + FT_Module_Constructor module_init; + FT_Module_Destructor module_done; + FT_Module_Requester get_interface; + + } FT_Module_Class; + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Add_Module */ + /* */ + /* <Description> */ + /* Add a new module to a given library instance. */ + /* */ + /* <InOut> */ + /* library :: A handle to the library object. */ + /* */ + /* <Input> */ + /* clazz :: A pointer to class descriptor for the module. */ + /* */ + /* <Return> */ + /* FreeType error code. 0~means success. */ + /* */ + /* <Note> */ + /* An error will be returned if a module already exists by that name, */ + /* or if the module requires a version of FreeType that is too great. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Add_Module( FT_Library library, + const FT_Module_Class* clazz ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Get_Module */ + /* */ + /* <Description> */ + /* Find a module by its name. */ + /* */ + /* <Input> */ + /* library :: A handle to the library object. */ + /* */ + /* module_name :: The module's name (as an ASCII string). */ + /* */ + /* <Return> */ + /* A module handle. 0~if none was found. */ + /* */ + /* <Note> */ + /* FreeType's internal modules aren't documented very well, and you */ + /* should look up the source code for details. */ + /* */ + FT_EXPORT( FT_Module ) + FT_Get_Module( FT_Library library, + const char* module_name ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Remove_Module */ + /* */ + /* <Description> */ + /* Remove a given module from a library instance. */ + /* */ + /* <InOut> */ + /* library :: A handle to a library object. */ + /* */ + /* <Input> */ + /* module :: A handle to a module object. */ + /* */ + /* <Return> */ + /* FreeType error code. 0~means success. */ + /* */ + /* <Note> */ + /* The module object is destroyed by the function in case of success. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Remove_Module( FT_Library library, + FT_Module module ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Reference_Library */ + /* */ + /* <Description> */ + /* A counter gets initialized to~1 at the time an @FT_Library */ + /* structure is created. This function increments the counter. */ + /* @FT_Done_Library then only destroys a library if the counter is~1, */ + /* otherwise it simply decrements the counter. */ + /* */ + /* This function helps in managing life-cycles of structures which */ + /* reference @FT_Library objects. */ + /* */ + /* <Input> */ + /* library :: A handle to a target library object. */ + /* */ + /* <Return> */ + /* FreeType error code. 0~means success. */ + /* */ + /* <Since> */ + /* 2.4.2 */ + /* */ + FT_EXPORT( FT_Error ) + FT_Reference_Library( FT_Library library ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_New_Library */ + /* */ + /* <Description> */ + /* This function is used to create a new FreeType library instance */ + /* from a given memory object. It is thus possible to use libraries */ + /* with distinct memory allocators within the same program. */ + /* */ + /* Normally, you would call this function (followed by a call to */ + /* @FT_Add_Default_Modules or a series of calls to @FT_Add_Module) */ + /* instead of @FT_Init_FreeType to initialize the FreeType library. */ + /* */ + /* Don't use @FT_Done_FreeType but @FT_Done_Library to destroy a */ + /* library instance. */ + /* */ + /* <Input> */ + /* memory :: A handle to the original memory object. */ + /* */ + /* <Output> */ + /* alibrary :: A pointer to handle of a new library object. */ + /* */ + /* <Return> */ + /* FreeType error code. 0~means success. */ + /* */ + /* <Note> */ + /* See the discussion of reference counters in the description of */ + /* @FT_Reference_Library. */ + /* */ + FT_EXPORT( FT_Error ) + FT_New_Library( FT_Memory memory, + FT_Library *alibrary ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Done_Library */ + /* */ + /* <Description> */ + /* Discard a given library object. This closes all drivers and */ + /* discards all resource objects. */ + /* */ + /* <Input> */ + /* library :: A handle to the target library. */ + /* */ + /* <Return> */ + /* FreeType error code. 0~means success. */ + /* */ + /* <Note> */ + /* See the discussion of reference counters in the description of */ + /* @FT_Reference_Library. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Done_Library( FT_Library library ); + +/* */ + + typedef void + (*FT_DebugHook_Func)( void* arg ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Set_Debug_Hook */ + /* */ + /* <Description> */ + /* Set a debug hook function for debugging the interpreter of a font */ + /* format. */ + /* */ + /* <InOut> */ + /* library :: A handle to the library object. */ + /* */ + /* <Input> */ + /* hook_index :: The index of the debug hook. You should use the */ + /* values defined in `ftobjs.h', e.g., */ + /* `FT_DEBUG_HOOK_TRUETYPE'. */ + /* */ + /* debug_hook :: The function used to debug the interpreter. */ + /* */ + /* <Note> */ + /* Currently, four debug hook slots are available, but only two (for */ + /* the TrueType and the Type~1 interpreter) are defined. */ + /* */ + /* Since the internal headers of FreeType are no longer installed, */ + /* the symbol `FT_DEBUG_HOOK_TRUETYPE' isn't available publicly. */ + /* This is a bug and will be fixed in a forthcoming release. */ + /* */ + FT_EXPORT( void ) + FT_Set_Debug_Hook( FT_Library library, + FT_UInt hook_index, + FT_DebugHook_Func debug_hook ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Add_Default_Modules */ + /* */ + /* <Description> */ + /* Add the set of default drivers to a given library object. */ + /* This is only useful when you create a library object with */ + /* @FT_New_Library (usually to plug a custom memory manager). */ + /* */ + /* <InOut> */ + /* library :: A handle to a new library object. */ + /* */ + FT_EXPORT( void ) + FT_Add_Default_Modules( FT_Library library ); + + + + /************************************************************************** + * + * @section: + * truetype_engine + * + * @title: + * The TrueType Engine + * + * @abstract: + * TrueType bytecode support. + * + * @description: + * This section contains a function used to query the level of TrueType + * bytecode support compiled in this version of the library. + * + */ + + + /************************************************************************** + * + * @enum: + * FT_TrueTypeEngineType + * + * @description: + * A list of values describing which kind of TrueType bytecode + * engine is implemented in a given FT_Library instance. It is used + * by the @FT_Get_TrueType_Engine_Type function. + * + * @values: + * FT_TRUETYPE_ENGINE_TYPE_NONE :: + * The library doesn't implement any kind of bytecode interpreter. + * + * FT_TRUETYPE_ENGINE_TYPE_UNPATENTED :: + * The library implements a bytecode interpreter that doesn't + * support the patented operations of the TrueType virtual machine. + * + * Its main use is to load certain Asian fonts which position and + * scale glyph components with bytecode instructions. It produces + * bad output for most other fonts. + * + * FT_TRUETYPE_ENGINE_TYPE_PATENTED :: + * The library implements a bytecode interpreter that covers + * the full instruction set of the TrueType virtual machine (this + * was governed by patents until May 2010, hence the name). + * + * @since: + * 2.2 + * + */ + typedef enum FT_TrueTypeEngineType_ + { + FT_TRUETYPE_ENGINE_TYPE_NONE = 0, + FT_TRUETYPE_ENGINE_TYPE_UNPATENTED, + FT_TRUETYPE_ENGINE_TYPE_PATENTED + + } FT_TrueTypeEngineType; + + + /************************************************************************** + * + * @func: + * FT_Get_TrueType_Engine_Type + * + * @description: + * Return an @FT_TrueTypeEngineType value to indicate which level of + * the TrueType virtual machine a given library instance supports. + * + * @input: + * library :: + * A library instance. + * + * @return: + * A value indicating which level is supported. + * + * @since: + * 2.2 + * + */ + FT_EXPORT( FT_TrueTypeEngineType ) + FT_Get_TrueType_Engine_Type( FT_Library library ); + + + /* */ + + +FT_END_HEADER + +#endif /* __FTMODAPI_H__ */ + + +/* END */ diff --git a/Lib/Include/freetype/ftmoderr.h b/Lib/Include/freetype/ftmoderr.h new file mode 100644 index 0000000..b0115dd --- /dev/null +++ b/Lib/Include/freetype/ftmoderr.h @@ -0,0 +1,155 @@ +/***************************************************************************/ +/* */ +/* ftmoderr.h */ +/* */ +/* FreeType module error offsets (specification). */ +/* */ +/* Copyright 2001, 2002, 2003, 2004, 2005 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + + /*************************************************************************/ + /* */ + /* This file is used to define the FreeType module error offsets. */ + /* */ + /* The lower byte gives the error code, the higher byte gives the */ + /* module. The base module has error offset 0. For example, the error */ + /* `FT_Err_Invalid_File_Format' has value 0x003, the error */ + /* `TT_Err_Invalid_File_Format' has value 0x1103, the error */ + /* `T1_Err_Invalid_File_Format' has value 0x1203, etc. */ + /* */ + /* Undefine the macro FT_CONFIG_OPTION_USE_MODULE_ERRORS in ftoption.h */ + /* to make the higher byte always zero (disabling the module error */ + /* mechanism). */ + /* */ + /* It can also be used to create a module error message table easily */ + /* with something like */ + /* */ + /* { */ + /* #undef __FTMODERR_H__ */ + /* #define FT_MODERRDEF( e, v, s ) { FT_Mod_Err_ ## e, s }, */ + /* #define FT_MODERR_START_LIST { */ + /* #define FT_MODERR_END_LIST { 0, 0 } }; */ + /* */ + /* const struct */ + /* { */ + /* int mod_err_offset; */ + /* const char* mod_err_msg */ + /* } ft_mod_errors[] = */ + /* */ + /* #include FT_MODULE_ERRORS_H */ + /* } */ + /* */ + /* To use such a table, all errors must be ANDed with 0xFF00 to remove */ + /* the error code. */ + /* */ + /*************************************************************************/ + + +#ifndef __FTMODERR_H__ +#define __FTMODERR_H__ + + + /*******************************************************************/ + /*******************************************************************/ + /***** *****/ + /***** SETUP MACROS *****/ + /***** *****/ + /*******************************************************************/ + /*******************************************************************/ + + +#undef FT_NEED_EXTERN_C + +#ifndef FT_MODERRDEF + +#ifdef FT_CONFIG_OPTION_USE_MODULE_ERRORS +#define FT_MODERRDEF( e, v, s ) FT_Mod_Err_ ## e = v, +#else +#define FT_MODERRDEF( e, v, s ) FT_Mod_Err_ ## e = 0, +#endif + +#define FT_MODERR_START_LIST enum { +#define FT_MODERR_END_LIST FT_Mod_Err_Max }; + +#ifdef __cplusplus +#define FT_NEED_EXTERN_C + extern "C" { +#endif + +#endif /* !FT_MODERRDEF */ + + + /*******************************************************************/ + /*******************************************************************/ + /***** *****/ + /***** LIST MODULE ERROR BASES *****/ + /***** *****/ + /*******************************************************************/ + /*******************************************************************/ + + +#ifdef FT_MODERR_START_LIST + FT_MODERR_START_LIST +#endif + + + FT_MODERRDEF( Base, 0x000, "base module" ) + FT_MODERRDEF( Autofit, 0x100, "autofitter module" ) + FT_MODERRDEF( BDF, 0x200, "BDF module" ) + FT_MODERRDEF( Cache, 0x300, "cache module" ) + FT_MODERRDEF( CFF, 0x400, "CFF module" ) + FT_MODERRDEF( CID, 0x500, "CID module" ) + FT_MODERRDEF( Gzip, 0x600, "Gzip module" ) + FT_MODERRDEF( LZW, 0x700, "LZW module" ) + FT_MODERRDEF( OTvalid, 0x800, "OpenType validation module" ) + FT_MODERRDEF( PCF, 0x900, "PCF module" ) + FT_MODERRDEF( PFR, 0xA00, "PFR module" ) + FT_MODERRDEF( PSaux, 0xB00, "PS auxiliary module" ) + FT_MODERRDEF( PShinter, 0xC00, "PS hinter module" ) + FT_MODERRDEF( PSnames, 0xD00, "PS names module" ) + FT_MODERRDEF( Raster, 0xE00, "raster module" ) + FT_MODERRDEF( SFNT, 0xF00, "SFNT module" ) + FT_MODERRDEF( Smooth, 0x1000, "smooth raster module" ) + FT_MODERRDEF( TrueType, 0x1100, "TrueType module" ) + FT_MODERRDEF( Type1, 0x1200, "Type 1 module" ) + FT_MODERRDEF( Type42, 0x1300, "Type 42 module" ) + FT_MODERRDEF( Winfonts, 0x1400, "Windows FON/FNT module" ) + + +#ifdef FT_MODERR_END_LIST + FT_MODERR_END_LIST +#endif + + + /*******************************************************************/ + /*******************************************************************/ + /***** *****/ + /***** CLEANUP *****/ + /***** *****/ + /*******************************************************************/ + /*******************************************************************/ + + +#ifdef FT_NEED_EXTERN_C + } +#endif + +#undef FT_MODERR_START_LIST +#undef FT_MODERR_END_LIST +#undef FT_MODERRDEF +#undef FT_NEED_EXTERN_C + + +#endif /* __FTMODERR_H__ */ + + +/* END */ diff --git a/Lib/Include/freetype/ftotval.h b/Lib/Include/freetype/ftotval.h new file mode 100644 index 0000000..027f2e8 --- /dev/null +++ b/Lib/Include/freetype/ftotval.h @@ -0,0 +1,203 @@ +/***************************************************************************/ +/* */ +/* ftotval.h */ +/* */ +/* FreeType API for validating OpenType tables (specification). */ +/* */ +/* Copyright 2004, 2005, 2006, 2007 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +/***************************************************************************/ +/* */ +/* */ +/* Warning: This module might be moved to a different library in the */ +/* future to avoid a tight dependency between FreeType and the */ +/* OpenType specification. */ +/* */ +/* */ +/***************************************************************************/ + + +#ifndef __FTOTVAL_H__ +#define __FTOTVAL_H__ + +#include <ft2build.h> +#include FT_FREETYPE_H + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /* */ + /* <Section> */ + /* ot_validation */ + /* */ + /* <Title> */ + /* OpenType Validation */ + /* */ + /* <Abstract> */ + /* An API to validate OpenType tables. */ + /* */ + /* <Description> */ + /* This section contains the declaration of functions to validate */ + /* some OpenType tables (BASE, GDEF, GPOS, GSUB, JSTF, MATH). */ + /* */ + /*************************************************************************/ + + + /********************************************************************** + * + * @enum: + * FT_VALIDATE_OTXXX + * + * @description: + * A list of bit-field constants used with @FT_OpenType_Validate to + * indicate which OpenType tables should be validated. + * + * @values: + * FT_VALIDATE_BASE :: + * Validate BASE table. + * + * FT_VALIDATE_GDEF :: + * Validate GDEF table. + * + * FT_VALIDATE_GPOS :: + * Validate GPOS table. + * + * FT_VALIDATE_GSUB :: + * Validate GSUB table. + * + * FT_VALIDATE_JSTF :: + * Validate JSTF table. + * + * FT_VALIDATE_MATH :: + * Validate MATH table. + * + * FT_VALIDATE_OT :: + * Validate all OpenType tables (BASE, GDEF, GPOS, GSUB, JSTF, MATH). + * + */ +#define FT_VALIDATE_BASE 0x0100 +#define FT_VALIDATE_GDEF 0x0200 +#define FT_VALIDATE_GPOS 0x0400 +#define FT_VALIDATE_GSUB 0x0800 +#define FT_VALIDATE_JSTF 0x1000 +#define FT_VALIDATE_MATH 0x2000 + +#define FT_VALIDATE_OT FT_VALIDATE_BASE | \ + FT_VALIDATE_GDEF | \ + FT_VALIDATE_GPOS | \ + FT_VALIDATE_GSUB | \ + FT_VALIDATE_JSTF | \ + FT_VALIDATE_MATH + + /* */ + + /********************************************************************** + * + * @function: + * FT_OpenType_Validate + * + * @description: + * Validate various OpenType tables to assure that all offsets and + * indices are valid. The idea is that a higher-level library which + * actually does the text layout can access those tables without + * error checking (which can be quite time consuming). + * + * @input: + * face :: + * A handle to the input face. + * + * validation_flags :: + * A bit field which specifies the tables to be validated. See + * @FT_VALIDATE_OTXXX for possible values. + * + * @output: + * BASE_table :: + * A pointer to the BASE table. + * + * GDEF_table :: + * A pointer to the GDEF table. + * + * GPOS_table :: + * A pointer to the GPOS table. + * + * GSUB_table :: + * A pointer to the GSUB table. + * + * JSTF_table :: + * A pointer to the JSTF table. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * This function only works with OpenType fonts, returning an error + * otherwise. + * + * After use, the application should deallocate the five tables with + * @FT_OpenType_Free. A NULL value indicates that the table either + * doesn't exist in the font, or the application hasn't asked for + * validation. + */ + FT_EXPORT( FT_Error ) + FT_OpenType_Validate( FT_Face face, + FT_UInt validation_flags, + FT_Bytes *BASE_table, + FT_Bytes *GDEF_table, + FT_Bytes *GPOS_table, + FT_Bytes *GSUB_table, + FT_Bytes *JSTF_table ); + + /* */ + + /********************************************************************** + * + * @function: + * FT_OpenType_Free + * + * @description: + * Free the buffer allocated by OpenType validator. + * + * @input: + * face :: + * A handle to the input face. + * + * table :: + * The pointer to the buffer that is allocated by + * @FT_OpenType_Validate. + * + * @note: + * This function must be used to free the buffer allocated by + * @FT_OpenType_Validate only. + */ + FT_EXPORT( void ) + FT_OpenType_Free( FT_Face face, + FT_Bytes table ); + + + /* */ + + +FT_END_HEADER + +#endif /* __FTOTVAL_H__ */ + + +/* END */ diff --git a/Lib/Include/freetype/ftoutln.h b/Lib/Include/freetype/ftoutln.h new file mode 100644 index 0000000..f3a2ad0 --- /dev/null +++ b/Lib/Include/freetype/ftoutln.h @@ -0,0 +1,537 @@ +/***************************************************************************/ +/* */ +/* ftoutln.h */ +/* */ +/* Support for the FT_Outline type used to store glyph shapes of */ +/* most scalable font formats (specification). */ +/* */ +/* Copyright 1996-2001, 2002, 2003, 2005, 2006, 2007, 2008, 2009, 2010 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef __FTOUTLN_H__ +#define __FTOUTLN_H__ + + +#include <ft2build.h> +#include FT_FREETYPE_H + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /* */ + /* <Section> */ + /* outline_processing */ + /* */ + /* <Title> */ + /* Outline Processing */ + /* */ + /* <Abstract> */ + /* Functions to create, transform, and render vectorial glyph images. */ + /* */ + /* <Description> */ + /* This section contains routines used to create and destroy scalable */ + /* glyph images known as `outlines'. These can also be measured, */ + /* transformed, and converted into bitmaps and pixmaps. */ + /* */ + /* <Order> */ + /* FT_Outline */ + /* FT_OUTLINE_FLAGS */ + /* FT_Outline_New */ + /* FT_Outline_Done */ + /* FT_Outline_Copy */ + /* FT_Outline_Translate */ + /* FT_Outline_Transform */ + /* FT_Outline_Embolden */ + /* FT_Outline_Reverse */ + /* FT_Outline_Check */ + /* */ + /* FT_Outline_Get_CBox */ + /* FT_Outline_Get_BBox */ + /* */ + /* FT_Outline_Get_Bitmap */ + /* FT_Outline_Render */ + /* */ + /* FT_Outline_Decompose */ + /* FT_Outline_Funcs */ + /* FT_Outline_MoveTo_Func */ + /* FT_Outline_LineTo_Func */ + /* FT_Outline_ConicTo_Func */ + /* FT_Outline_CubicTo_Func */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Outline_Decompose */ + /* */ + /* <Description> */ + /* Walk over an outline's structure to decompose it into individual */ + /* segments and BȨzier arcs. This function also emits `move to' */ + /* operations to indicate the start of new contours in the outline. */ + /* */ + /* <Input> */ + /* outline :: A pointer to the source target. */ + /* */ + /* func_interface :: A table of `emitters', i.e., function pointers */ + /* called during decomposition to indicate path */ + /* operations. */ + /* */ + /* <InOut> */ + /* user :: A typeless pointer which is passed to each */ + /* emitter during the decomposition. It can be */ + /* used to store the state during the */ + /* decomposition. */ + /* */ + /* <Return> */ + /* FreeType error code. 0~means success. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Outline_Decompose( FT_Outline* outline, + const FT_Outline_Funcs* func_interface, + void* user ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Outline_New */ + /* */ + /* <Description> */ + /* Create a new outline of a given size. */ + /* */ + /* <Input> */ + /* library :: A handle to the library object from where the */ + /* outline is allocated. Note however that the new */ + /* outline will *not* necessarily be *freed*, when */ + /* destroying the library, by @FT_Done_FreeType. */ + /* */ + /* numPoints :: The maximal number of points within the outline. */ + /* */ + /* numContours :: The maximal number of contours within the outline. */ + /* */ + /* <Output> */ + /* anoutline :: A handle to the new outline. */ + /* */ + /* <Return> */ + /* FreeType error code. 0~means success. */ + /* */ + /* <Note> */ + /* The reason why this function takes a `library' parameter is simply */ + /* to use the library's memory allocator. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Outline_New( FT_Library library, + FT_UInt numPoints, + FT_Int numContours, + FT_Outline *anoutline ); + + + FT_EXPORT( FT_Error ) + FT_Outline_New_Internal( FT_Memory memory, + FT_UInt numPoints, + FT_Int numContours, + FT_Outline *anoutline ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Outline_Done */ + /* */ + /* <Description> */ + /* Destroy an outline created with @FT_Outline_New. */ + /* */ + /* <Input> */ + /* library :: A handle of the library object used to allocate the */ + /* outline. */ + /* */ + /* outline :: A pointer to the outline object to be discarded. */ + /* */ + /* <Return> */ + /* FreeType error code. 0~means success. */ + /* */ + /* <Note> */ + /* If the outline's `owner' field is not set, only the outline */ + /* descriptor will be released. */ + /* */ + /* The reason why this function takes an `library' parameter is */ + /* simply to use ft_mem_free(). */ + /* */ + FT_EXPORT( FT_Error ) + FT_Outline_Done( FT_Library library, + FT_Outline* outline ); + + + FT_EXPORT( FT_Error ) + FT_Outline_Done_Internal( FT_Memory memory, + FT_Outline* outline ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Outline_Check */ + /* */ + /* <Description> */ + /* Check the contents of an outline descriptor. */ + /* */ + /* <Input> */ + /* outline :: A handle to a source outline. */ + /* */ + /* <Return> */ + /* FreeType error code. 0~means success. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Outline_Check( FT_Outline* outline ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Outline_Get_CBox */ + /* */ + /* <Description> */ + /* Return an outline's `control box'. The control box encloses all */ + /* the outline's points, including BȨzier control points. Though it */ + /* coincides with the exact bounding box for most glyphs, it can be */ + /* slightly larger in some situations (like when rotating an outline */ + /* which contains BȨzier outside arcs). */ + /* */ + /* Computing the control box is very fast, while getting the bounding */ + /* box can take much more time as it needs to walk over all segments */ + /* and arcs in the outline. To get the latter, you can use the */ + /* `ftbbox' component which is dedicated to this single task. */ + /* */ + /* <Input> */ + /* outline :: A pointer to the source outline descriptor. */ + /* */ + /* <Output> */ + /* acbox :: The outline's control box. */ + /* */ + FT_EXPORT( void ) + FT_Outline_Get_CBox( const FT_Outline* outline, + FT_BBox *acbox ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Outline_Translate */ + /* */ + /* <Description> */ + /* Apply a simple translation to the points of an outline. */ + /* */ + /* <InOut> */ + /* outline :: A pointer to the target outline descriptor. */ + /* */ + /* <Input> */ + /* xOffset :: The horizontal offset. */ + /* */ + /* yOffset :: The vertical offset. */ + /* */ + FT_EXPORT( void ) + FT_Outline_Translate( const FT_Outline* outline, + FT_Pos xOffset, + FT_Pos yOffset ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Outline_Copy */ + /* */ + /* <Description> */ + /* Copy an outline into another one. Both objects must have the */ + /* same sizes (number of points & number of contours) when this */ + /* function is called. */ + /* */ + /* <Input> */ + /* source :: A handle to the source outline. */ + /* */ + /* <Output> */ + /* target :: A handle to the target outline. */ + /* */ + /* <Return> */ + /* FreeType error code. 0~means success. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Outline_Copy( const FT_Outline* source, + FT_Outline *target ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Outline_Transform */ + /* */ + /* <Description> */ + /* Apply a simple 2x2 matrix to all of an outline's points. Useful */ + /* for applying rotations, slanting, flipping, etc. */ + /* */ + /* <InOut> */ + /* outline :: A pointer to the target outline descriptor. */ + /* */ + /* <Input> */ + /* matrix :: A pointer to the transformation matrix. */ + /* */ + /* <Note> */ + /* You can use @FT_Outline_Translate if you need to translate the */ + /* outline's points. */ + /* */ + FT_EXPORT( void ) + FT_Outline_Transform( const FT_Outline* outline, + const FT_Matrix* matrix ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Outline_Embolden */ + /* */ + /* <Description> */ + /* Embolden an outline. The new outline will be at most 4~times */ + /* `strength' pixels wider and higher. You may think of the left and */ + /* bottom borders as unchanged. */ + /* */ + /* Negative `strength' values to reduce the outline thickness are */ + /* possible also. */ + /* */ + /* <InOut> */ + /* outline :: A handle to the target outline. */ + /* */ + /* <Input> */ + /* strength :: How strong the glyph is emboldened. Expressed in */ + /* 26.6 pixel format. */ + /* */ + /* <Return> */ + /* FreeType error code. 0~means success. */ + /* */ + /* <Note> */ + /* The used algorithm to increase or decrease the thickness of the */ + /* glyph doesn't change the number of points; this means that certain */ + /* situations like acute angles or intersections are sometimes */ + /* handled incorrectly. */ + /* */ + /* If you need `better' metrics values you should call */ + /* @FT_Outline_Get_CBox ot @FT_Outline_Get_BBox. */ + /* */ + /* Example call: */ + /* */ + /* { */ + /* FT_Load_Glyph( face, index, FT_LOAD_DEFAULT ); */ + /* if ( face->slot->format == FT_GLYPH_FORMAT_OUTLINE ) */ + /* FT_Outline_Embolden( &face->slot->outline, strength ); */ + /* } */ + /* */ + FT_EXPORT( FT_Error ) + FT_Outline_Embolden( FT_Outline* outline, + FT_Pos strength ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Outline_Reverse */ + /* */ + /* <Description> */ + /* Reverse the drawing direction of an outline. This is used to */ + /* ensure consistent fill conventions for mirrored glyphs. */ + /* */ + /* <InOut> */ + /* outline :: A pointer to the target outline descriptor. */ + /* */ + /* <Note> */ + /* This function toggles the bit flag @FT_OUTLINE_REVERSE_FILL in */ + /* the outline's `flags' field. */ + /* */ + /* It shouldn't be used by a normal client application, unless it */ + /* knows what it is doing. */ + /* */ + FT_EXPORT( void ) + FT_Outline_Reverse( FT_Outline* outline ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Outline_Get_Bitmap */ + /* */ + /* <Description> */ + /* Render an outline within a bitmap. The outline's image is simply */ + /* OR-ed to the target bitmap. */ + /* */ + /* <Input> */ + /* library :: A handle to a FreeType library object. */ + /* */ + /* outline :: A pointer to the source outline descriptor. */ + /* */ + /* <InOut> */ + /* abitmap :: A pointer to the target bitmap descriptor. */ + /* */ + /* <Return> */ + /* FreeType error code. 0~means success. */ + /* */ + /* <Note> */ + /* This function does NOT CREATE the bitmap, it only renders an */ + /* outline image within the one you pass to it! Consequently, the */ + /* various fields in `abitmap' should be set accordingly. */ + /* */ + /* It will use the raster corresponding to the default glyph format. */ + /* */ + /* The value of the `num_grays' field in `abitmap' is ignored. If */ + /* you select the gray-level rasterizer, and you want less than 256 */ + /* gray levels, you have to use @FT_Outline_Render directly. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Outline_Get_Bitmap( FT_Library library, + FT_Outline* outline, + const FT_Bitmap *abitmap ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Outline_Render */ + /* */ + /* <Description> */ + /* Render an outline within a bitmap using the current scan-convert. */ + /* This function uses an @FT_Raster_Params structure as an argument, */ + /* allowing advanced features like direct composition, translucency, */ + /* etc. */ + /* */ + /* <Input> */ + /* library :: A handle to a FreeType library object. */ + /* */ + /* outline :: A pointer to the source outline descriptor. */ + /* */ + /* <InOut> */ + /* params :: A pointer to an @FT_Raster_Params structure used to */ + /* describe the rendering operation. */ + /* */ + /* <Return> */ + /* FreeType error code. 0~means success. */ + /* */ + /* <Note> */ + /* You should know what you are doing and how @FT_Raster_Params works */ + /* to use this function. */ + /* */ + /* The field `params.source' will be set to `outline' before the scan */ + /* converter is called, which means that the value you give to it is */ + /* actually ignored. */ + /* */ + /* The gray-level rasterizer always uses 256 gray levels. If you */ + /* want less gray levels, you have to provide your own span callback. */ + /* See the @FT_RASTER_FLAG_DIRECT value of the `flags' field in the */ + /* @FT_Raster_Params structure for more details. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Outline_Render( FT_Library library, + FT_Outline* outline, + FT_Raster_Params* params ); + + + /************************************************************************** + * + * @enum: + * FT_Orientation + * + * @description: + * A list of values used to describe an outline's contour orientation. + * + * The TrueType and PostScript specifications use different conventions + * to determine whether outline contours should be filled or unfilled. + * + * @values: + * FT_ORIENTATION_TRUETYPE :: + * According to the TrueType specification, clockwise contours must + * be filled, and counter-clockwise ones must be unfilled. + * + * FT_ORIENTATION_POSTSCRIPT :: + * According to the PostScript specification, counter-clockwise contours + * must be filled, and clockwise ones must be unfilled. + * + * FT_ORIENTATION_FILL_RIGHT :: + * This is identical to @FT_ORIENTATION_TRUETYPE, but is used to + * remember that in TrueType, everything that is to the right of + * the drawing direction of a contour must be filled. + * + * FT_ORIENTATION_FILL_LEFT :: + * This is identical to @FT_ORIENTATION_POSTSCRIPT, but is used to + * remember that in PostScript, everything that is to the left of + * the drawing direction of a contour must be filled. + * + * FT_ORIENTATION_NONE :: + * The orientation cannot be determined. That is, different parts of + * the glyph have different orientation. + * + */ + typedef enum FT_Orientation_ + { + FT_ORIENTATION_TRUETYPE = 0, + FT_ORIENTATION_POSTSCRIPT = 1, + FT_ORIENTATION_FILL_RIGHT = FT_ORIENTATION_TRUETYPE, + FT_ORIENTATION_FILL_LEFT = FT_ORIENTATION_POSTSCRIPT, + FT_ORIENTATION_NONE + + } FT_Orientation; + + + /************************************************************************** + * + * @function: + * FT_Outline_Get_Orientation + * + * @description: + * This function analyzes a glyph outline and tries to compute its + * fill orientation (see @FT_Orientation). This is done by computing + * the direction of each global horizontal and/or vertical extrema + * within the outline. + * + * Note that this will return @FT_ORIENTATION_TRUETYPE for empty + * outlines. + * + * @input: + * outline :: + * A handle to the source outline. + * + * @return: + * The orientation. + * + */ + FT_EXPORT( FT_Orientation ) + FT_Outline_Get_Orientation( FT_Outline* outline ); + + + /* */ + + +FT_END_HEADER + +#endif /* __FTOUTLN_H__ */ + + +/* END */ + + +/* Local Variables: */ +/* coding: utf-8 */ +/* End: */ diff --git a/Lib/Include/freetype/ftpfr.h b/Lib/Include/freetype/ftpfr.h new file mode 100644 index 0000000..0b7b7d4 --- /dev/null +++ b/Lib/Include/freetype/ftpfr.h @@ -0,0 +1,172 @@ +/***************************************************************************/ +/* */ +/* ftpfr.h */ +/* */ +/* FreeType API for accessing PFR-specific data (specification only). */ +/* */ +/* Copyright 2002, 2003, 2004, 2006, 2008, 2009 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef __FTPFR_H__ +#define __FTPFR_H__ + +#include <ft2build.h> +#include FT_FREETYPE_H + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /* */ + /* <Section> */ + /* pfr_fonts */ + /* */ + /* <Title> */ + /* PFR Fonts */ + /* */ + /* <Abstract> */ + /* PFR/TrueDoc specific API. */ + /* */ + /* <Description> */ + /* This section contains the declaration of PFR-specific functions. */ + /* */ + /*************************************************************************/ + + + /********************************************************************** + * + * @function: + * FT_Get_PFR_Metrics + * + * @description: + * Return the outline and metrics resolutions of a given PFR face. + * + * @input: + * face :: Handle to the input face. It can be a non-PFR face. + * + * @output: + * aoutline_resolution :: + * Outline resolution. This is equivalent to `face->units_per_EM' + * for non-PFR fonts. Optional (parameter can be NULL). + * + * ametrics_resolution :: + * Metrics resolution. This is equivalent to `outline_resolution' + * for non-PFR fonts. Optional (parameter can be NULL). + * + * ametrics_x_scale :: + * A 16.16 fixed-point number used to scale distance expressed + * in metrics units to device sub-pixels. This is equivalent to + * `face->size->x_scale', but for metrics only. Optional (parameter + * can be NULL). + * + * ametrics_y_scale :: + * Same as `ametrics_x_scale' but for the vertical direction. + * optional (parameter can be NULL). + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * If the input face is not a PFR, this function will return an error. + * However, in all cases, it will return valid values. + */ + FT_EXPORT( FT_Error ) + FT_Get_PFR_Metrics( FT_Face face, + FT_UInt *aoutline_resolution, + FT_UInt *ametrics_resolution, + FT_Fixed *ametrics_x_scale, + FT_Fixed *ametrics_y_scale ); + + + /********************************************************************** + * + * @function: + * FT_Get_PFR_Kerning + * + * @description: + * Return the kerning pair corresponding to two glyphs in a PFR face. + * The distance is expressed in metrics units, unlike the result of + * @FT_Get_Kerning. + * + * @input: + * face :: A handle to the input face. + * + * left :: Index of the left glyph. + * + * right :: Index of the right glyph. + * + * @output: + * avector :: A kerning vector. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * This function always return distances in original PFR metrics + * units. This is unlike @FT_Get_Kerning with the @FT_KERNING_UNSCALED + * mode, which always returns distances converted to outline units. + * + * You can use the value of the `x_scale' and `y_scale' parameters + * returned by @FT_Get_PFR_Metrics to scale these to device sub-pixels. + */ + FT_EXPORT( FT_Error ) + FT_Get_PFR_Kerning( FT_Face face, + FT_UInt left, + FT_UInt right, + FT_Vector *avector ); + + + /********************************************************************** + * + * @function: + * FT_Get_PFR_Advance + * + * @description: + * Return a given glyph advance, expressed in original metrics units, + * from a PFR font. + * + * @input: + * face :: A handle to the input face. + * + * gindex :: The glyph index. + * + * @output: + * aadvance :: The glyph advance in metrics units. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * You can use the `x_scale' or `y_scale' results of @FT_Get_PFR_Metrics + * to convert the advance to device sub-pixels (i.e., 1/64th of pixels). + */ + FT_EXPORT( FT_Error ) + FT_Get_PFR_Advance( FT_Face face, + FT_UInt gindex, + FT_Pos *aadvance ); + + /* */ + + +FT_END_HEADER + +#endif /* __FTPFR_H__ */ + + +/* END */ diff --git a/Lib/Include/freetype/ftrender.h b/Lib/Include/freetype/ftrender.h new file mode 100644 index 0000000..e06a814 --- /dev/null +++ b/Lib/Include/freetype/ftrender.h @@ -0,0 +1,230 @@ +/***************************************************************************/ +/* */ +/* ftrender.h */ +/* */ +/* FreeType renderer modules public interface (specification). */ +/* */ +/* Copyright 1996-2001, 2005, 2006, 2010 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef __FTRENDER_H__ +#define __FTRENDER_H__ + + +#include <ft2build.h> +#include FT_MODULE_H +#include FT_GLYPH_H + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /* */ + /* <Section> */ + /* module_management */ + /* */ + /*************************************************************************/ + + + /* create a new glyph object */ + typedef FT_Error + (*FT_Glyph_InitFunc)( FT_Glyph glyph, + FT_GlyphSlot slot ); + + /* destroys a given glyph object */ + typedef void + (*FT_Glyph_DoneFunc)( FT_Glyph glyph ); + + typedef void + (*FT_Glyph_TransformFunc)( FT_Glyph glyph, + const FT_Matrix* matrix, + const FT_Vector* delta ); + + typedef void + (*FT_Glyph_GetBBoxFunc)( FT_Glyph glyph, + FT_BBox* abbox ); + + typedef FT_Error + (*FT_Glyph_CopyFunc)( FT_Glyph source, + FT_Glyph target ); + + typedef FT_Error + (*FT_Glyph_PrepareFunc)( FT_Glyph glyph, + FT_GlyphSlot slot ); + +/* deprecated */ +#define FT_Glyph_Init_Func FT_Glyph_InitFunc +#define FT_Glyph_Done_Func FT_Glyph_DoneFunc +#define FT_Glyph_Transform_Func FT_Glyph_TransformFunc +#define FT_Glyph_BBox_Func FT_Glyph_GetBBoxFunc +#define FT_Glyph_Copy_Func FT_Glyph_CopyFunc +#define FT_Glyph_Prepare_Func FT_Glyph_PrepareFunc + + + struct FT_Glyph_Class_ + { + FT_Long glyph_size; + FT_Glyph_Format glyph_format; + FT_Glyph_InitFunc glyph_init; + FT_Glyph_DoneFunc glyph_done; + FT_Glyph_CopyFunc glyph_copy; + FT_Glyph_TransformFunc glyph_transform; + FT_Glyph_GetBBoxFunc glyph_bbox; + FT_Glyph_PrepareFunc glyph_prepare; + }; + + + typedef FT_Error + (*FT_Renderer_RenderFunc)( FT_Renderer renderer, + FT_GlyphSlot slot, + FT_UInt mode, + const FT_Vector* origin ); + + typedef FT_Error + (*FT_Renderer_TransformFunc)( FT_Renderer renderer, + FT_GlyphSlot slot, + const FT_Matrix* matrix, + const FT_Vector* delta ); + + + typedef void + (*FT_Renderer_GetCBoxFunc)( FT_Renderer renderer, + FT_GlyphSlot slot, + FT_BBox* cbox ); + + + typedef FT_Error + (*FT_Renderer_SetModeFunc)( FT_Renderer renderer, + FT_ULong mode_tag, + FT_Pointer mode_ptr ); + +/* deprecated identifiers */ +#define FTRenderer_render FT_Renderer_RenderFunc +#define FTRenderer_transform FT_Renderer_TransformFunc +#define FTRenderer_getCBox FT_Renderer_GetCBoxFunc +#define FTRenderer_setMode FT_Renderer_SetModeFunc + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_Renderer_Class */ + /* */ + /* <Description> */ + /* The renderer module class descriptor. */ + /* */ + /* <Fields> */ + /* root :: The root @FT_Module_Class fields. */ + /* */ + /* glyph_format :: The glyph image format this renderer handles. */ + /* */ + /* render_glyph :: A method used to render the image that is in a */ + /* given glyph slot into a bitmap. */ + /* */ + /* transform_glyph :: A method used to transform the image that is in */ + /* a given glyph slot. */ + /* */ + /* get_glyph_cbox :: A method used to access the glyph's cbox. */ + /* */ + /* set_mode :: A method used to pass additional parameters. */ + /* */ + /* raster_class :: For @FT_GLYPH_FORMAT_OUTLINE renderers only. */ + /* This is a pointer to its raster's class. */ + /* */ + typedef struct FT_Renderer_Class_ + { + FT_Module_Class root; + + FT_Glyph_Format glyph_format; + + FT_Renderer_RenderFunc render_glyph; + FT_Renderer_TransformFunc transform_glyph; + FT_Renderer_GetCBoxFunc get_glyph_cbox; + FT_Renderer_SetModeFunc set_mode; + + FT_Raster_Funcs* raster_class; + + } FT_Renderer_Class; + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Get_Renderer */ + /* */ + /* <Description> */ + /* Retrieve the current renderer for a given glyph format. */ + /* */ + /* <Input> */ + /* library :: A handle to the library object. */ + /* */ + /* format :: The glyph format. */ + /* */ + /* <Return> */ + /* A renderer handle. 0~if none found. */ + /* */ + /* <Note> */ + /* An error will be returned if a module already exists by that name, */ + /* or if the module requires a version of FreeType that is too great. */ + /* */ + /* To add a new renderer, simply use @FT_Add_Module. To retrieve a */ + /* renderer by its name, use @FT_Get_Module. */ + /* */ + FT_EXPORT( FT_Renderer ) + FT_Get_Renderer( FT_Library library, + FT_Glyph_Format format ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Set_Renderer */ + /* */ + /* <Description> */ + /* Set the current renderer to use, and set additional mode. */ + /* */ + /* <InOut> */ + /* library :: A handle to the library object. */ + /* */ + /* <Input> */ + /* renderer :: A handle to the renderer object. */ + /* */ + /* num_params :: The number of additional parameters. */ + /* */ + /* parameters :: Additional parameters. */ + /* */ + /* <Return> */ + /* FreeType error code. 0~means success. */ + /* */ + /* <Note> */ + /* In case of success, the renderer will be used to convert glyph */ + /* images in the renderer's known format into bitmaps. */ + /* */ + /* This doesn't change the current renderer for other formats. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Set_Renderer( FT_Library library, + FT_Renderer renderer, + FT_UInt num_params, + FT_Parameter* parameters ); + + + /* */ + + +FT_END_HEADER + +#endif /* __FTRENDER_H__ */ + + +/* END */ diff --git a/Lib/Include/freetype/ftsizes.h b/Lib/Include/freetype/ftsizes.h new file mode 100644 index 0000000..3e548cc --- /dev/null +++ b/Lib/Include/freetype/ftsizes.h @@ -0,0 +1,159 @@ +/***************************************************************************/ +/* */ +/* ftsizes.h */ +/* */ +/* FreeType size objects management (specification). */ +/* */ +/* Copyright 1996-2001, 2003, 2004, 2006, 2009 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + + /*************************************************************************/ + /* */ + /* Typical application would normally not need to use these functions. */ + /* However, they have been placed in a public API for the rare cases */ + /* where they are needed. */ + /* */ + /*************************************************************************/ + + +#ifndef __FTSIZES_H__ +#define __FTSIZES_H__ + + +#include <ft2build.h> +#include FT_FREETYPE_H + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /* */ + /* <Section> */ + /* sizes_management */ + /* */ + /* <Title> */ + /* Size Management */ + /* */ + /* <Abstract> */ + /* Managing multiple sizes per face. */ + /* */ + /* <Description> */ + /* When creating a new face object (e.g., with @FT_New_Face), an */ + /* @FT_Size object is automatically created and used to store all */ + /* pixel-size dependent information, available in the `face->size' */ + /* field. */ + /* */ + /* It is however possible to create more sizes for a given face, */ + /* mostly in order to manage several character pixel sizes of the */ + /* same font family and style. See @FT_New_Size and @FT_Done_Size. */ + /* */ + /* Note that @FT_Set_Pixel_Sizes and @FT_Set_Char_Size only */ + /* modify the contents of the current `active' size; you thus need */ + /* to use @FT_Activate_Size to change it. */ + /* */ + /* 99% of applications won't need the functions provided here, */ + /* especially if they use the caching sub-system, so be cautious */ + /* when using these. */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_New_Size */ + /* */ + /* <Description> */ + /* Create a new size object from a given face object. */ + /* */ + /* <Input> */ + /* face :: A handle to a parent face object. */ + /* */ + /* <Output> */ + /* asize :: A handle to a new size object. */ + /* */ + /* <Return> */ + /* FreeType error code. 0~means success. */ + /* */ + /* <Note> */ + /* You need to call @FT_Activate_Size in order to select the new size */ + /* for upcoming calls to @FT_Set_Pixel_Sizes, @FT_Set_Char_Size, */ + /* @FT_Load_Glyph, @FT_Load_Char, etc. */ + /* */ + FT_EXPORT( FT_Error ) + FT_New_Size( FT_Face face, + FT_Size* size ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Done_Size */ + /* */ + /* <Description> */ + /* Discard a given size object. Note that @FT_Done_Face */ + /* automatically discards all size objects allocated with */ + /* @FT_New_Size. */ + /* */ + /* <Input> */ + /* size :: A handle to a target size object. */ + /* */ + /* <Return> */ + /* FreeType error code. 0~means success. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Done_Size( FT_Size size ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Activate_Size */ + /* */ + /* <Description> */ + /* Even though it is possible to create several size objects for a */ + /* given face (see @FT_New_Size for details), functions like */ + /* @FT_Load_Glyph or @FT_Load_Char only use the one which has been */ + /* activated last to determine the `current character pixel size'. */ + /* */ + /* This function can be used to `activate' a previously created size */ + /* object. */ + /* */ + /* <Input> */ + /* size :: A handle to a target size object. */ + /* */ + /* <Return> */ + /* FreeType error code. 0~means success. */ + /* */ + /* <Note> */ + /* If `face' is the size's parent face object, this function changes */ + /* the value of `face->size' to the input size handle. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Activate_Size( FT_Size size ); + + /* */ + + +FT_END_HEADER + +#endif /* __FTSIZES_H__ */ + + +/* END */ diff --git a/Lib/Include/freetype/ftsnames.h b/Lib/Include/freetype/ftsnames.h new file mode 100644 index 0000000..485e4e1 --- /dev/null +++ b/Lib/Include/freetype/ftsnames.h @@ -0,0 +1,200 @@ +/***************************************************************************/ +/* */ +/* ftsnames.h */ +/* */ +/* Simple interface to access SFNT name tables (which are used */ +/* to hold font names, copyright info, notices, etc.) (specification). */ +/* */ +/* This is _not_ used to retrieve glyph names! */ +/* */ +/* Copyright 1996-2001, 2002, 2003, 2006, 2009, 2010 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef __FT_SFNT_NAMES_H__ +#define __FT_SFNT_NAMES_H__ + + +#include <ft2build.h> +#include FT_FREETYPE_H + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /* */ + /* <Section> */ + /* sfnt_names */ + /* */ + /* <Title> */ + /* SFNT Names */ + /* */ + /* <Abstract> */ + /* Access the names embedded in TrueType and OpenType files. */ + /* */ + /* <Description> */ + /* The TrueType and OpenType specifications allow the inclusion of */ + /* a special `names table' in font files. This table contains */ + /* textual (and internationalized) information regarding the font, */ + /* like family name, copyright, version, etc. */ + /* */ + /* The definitions below are used to access them if available. */ + /* */ + /* Note that this has nothing to do with glyph names! */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_SfntName */ + /* */ + /* <Description> */ + /* A structure used to model an SFNT `name' table entry. */ + /* */ + /* <Fields> */ + /* platform_id :: The platform ID for `string'. */ + /* */ + /* encoding_id :: The encoding ID for `string'. */ + /* */ + /* language_id :: The language ID for `string'. */ + /* */ + /* name_id :: An identifier for `string'. */ + /* */ + /* string :: The `name' string. Note that its format differs */ + /* depending on the (platform,encoding) pair. It can */ + /* be a Pascal String, a UTF-16 one, etc. */ + /* */ + /* Generally speaking, the string is not */ + /* zero-terminated. Please refer to the TrueType */ + /* specification for details. */ + /* */ + /* string_len :: The length of `string' in bytes. */ + /* */ + /* <Note> */ + /* Possible values for `platform_id', `encoding_id', `language_id', */ + /* and `name_id' are given in the file `ttnameid.h'. For details */ + /* please refer to the TrueType or OpenType specification. */ + /* */ + /* See also @TT_PLATFORM_XXX, @TT_APPLE_ID_XXX, @TT_MAC_ID_XXX, */ + /* @TT_ISO_ID_XXX, and @TT_MS_ID_XXX. */ + /* */ + typedef struct FT_SfntName_ + { + FT_UShort platform_id; + FT_UShort encoding_id; + FT_UShort language_id; + FT_UShort name_id; + + FT_Byte* string; /* this string is *not* null-terminated! */ + FT_UInt string_len; /* in bytes */ + + } FT_SfntName; + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Get_Sfnt_Name_Count */ + /* */ + /* <Description> */ + /* Retrieve the number of name strings in the SFNT `name' table. */ + /* */ + /* <Input> */ + /* face :: A handle to the source face. */ + /* */ + /* <Return> */ + /* The number of strings in the `name' table. */ + /* */ + FT_EXPORT( FT_UInt ) + FT_Get_Sfnt_Name_Count( FT_Face face ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Get_Sfnt_Name */ + /* */ + /* <Description> */ + /* Retrieve a string of the SFNT `name' table for a given index. */ + /* */ + /* <Input> */ + /* face :: A handle to the source face. */ + /* */ + /* idx :: The index of the `name' string. */ + /* */ + /* <Output> */ + /* aname :: The indexed @FT_SfntName structure. */ + /* */ + /* <Return> */ + /* FreeType error code. 0~means success. */ + /* */ + /* <Note> */ + /* The `string' array returned in the `aname' structure is not */ + /* null-terminated. The application should deallocate it if it is no */ + /* longer in use. */ + /* */ + /* Use @FT_Get_Sfnt_Name_Count to get the total number of available */ + /* `name' table entries, then do a loop until you get the right */ + /* platform, encoding, and name ID. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Get_Sfnt_Name( FT_Face face, + FT_UInt idx, + FT_SfntName *aname ); + + + /*************************************************************************** + * + * @constant: + * FT_PARAM_TAG_IGNORE_PREFERRED_FAMILY + * + * @description: + * A constant used as the tag of @FT_Parameter structures to make + * FT_Open_Face() ignore preferred family subfamily names in `name' + * table since OpenType version 1.4. For backwards compatibility with + * legacy systems which has 4-face-per-family restriction. + * + */ +#define FT_PARAM_TAG_IGNORE_PREFERRED_FAMILY FT_MAKE_TAG( 'i', 'g', 'p', 'f' ) + + + /*************************************************************************** + * + * @constant: + * FT_PARAM_TAG_IGNORE_PREFERRED_SUBFAMILY + * + * @description: + * A constant used as the tag of @FT_Parameter structures to make + * FT_Open_Face() ignore preferred subfamily names in `name' table since + * OpenType version 1.4. For backwards compatibility with legacy + * systems which has 4-face-per-family restriction. + * + */ +#define FT_PARAM_TAG_IGNORE_PREFERRED_SUBFAMILY FT_MAKE_TAG( 'i', 'g', 'p', 's' ) + + /* */ + + +FT_END_HEADER + +#endif /* __FT_SFNT_NAMES_H__ */ + + +/* END */ diff --git a/Lib/Include/freetype/ftstroke.h b/Lib/Include/freetype/ftstroke.h new file mode 100644 index 0000000..02baa9c --- /dev/null +++ b/Lib/Include/freetype/ftstroke.h @@ -0,0 +1,716 @@ +/***************************************************************************/ +/* */ +/* ftstroke.h */ +/* */ +/* FreeType path stroker (specification). */ +/* */ +/* Copyright 2002, 2003, 2004, 2005, 2006, 2008, 2009 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef __FT_STROKE_H__ +#define __FT_STROKE_H__ + +#include <ft2build.h> +#include FT_OUTLINE_H +#include FT_GLYPH_H + + +FT_BEGIN_HEADER + + + /************************************************************************ + * + * @section: + * glyph_stroker + * + * @title: + * Glyph Stroker + * + * @abstract: + * Generating bordered and stroked glyphs. + * + * @description: + * This component generates stroked outlines of a given vectorial + * glyph. It also allows you to retrieve the `outside' and/or the + * `inside' borders of the stroke. + * + * This can be useful to generate `bordered' glyph, i.e., glyphs + * displayed with a coloured (and anti-aliased) border around their + * shape. + */ + + + /************************************************************** + * + * @type: + * FT_Stroker + * + * @description: + * Opaque handler to a path stroker object. + */ + typedef struct FT_StrokerRec_* FT_Stroker; + + + /************************************************************** + * + * @enum: + * FT_Stroker_LineJoin + * + * @description: + * These values determine how two joining lines are rendered + * in a stroker. + * + * @values: + * FT_STROKER_LINEJOIN_ROUND :: + * Used to render rounded line joins. Circular arcs are used + * to join two lines smoothly. + * + * FT_STROKER_LINEJOIN_BEVEL :: + * Used to render beveled line joins; i.e., the two joining lines + * are extended until they intersect. + * + * FT_STROKER_LINEJOIN_MITER :: + * Same as beveled rendering, except that an additional line + * break is added if the angle between the two joining lines + * is too closed (this is useful to avoid unpleasant spikes + * in beveled rendering). + */ + typedef enum FT_Stroker_LineJoin_ + { + FT_STROKER_LINEJOIN_ROUND = 0, + FT_STROKER_LINEJOIN_BEVEL, + FT_STROKER_LINEJOIN_MITER + + } FT_Stroker_LineJoin; + + + /************************************************************** + * + * @enum: + * FT_Stroker_LineCap + * + * @description: + * These values determine how the end of opened sub-paths are + * rendered in a stroke. + * + * @values: + * FT_STROKER_LINECAP_BUTT :: + * The end of lines is rendered as a full stop on the last + * point itself. + * + * FT_STROKER_LINECAP_ROUND :: + * The end of lines is rendered as a half-circle around the + * last point. + * + * FT_STROKER_LINECAP_SQUARE :: + * The end of lines is rendered as a square around the + * last point. + */ + typedef enum FT_Stroker_LineCap_ + { + FT_STROKER_LINECAP_BUTT = 0, + FT_STROKER_LINECAP_ROUND, + FT_STROKER_LINECAP_SQUARE + + } FT_Stroker_LineCap; + + + /************************************************************** + * + * @enum: + * FT_StrokerBorder + * + * @description: + * These values are used to select a given stroke border + * in @FT_Stroker_GetBorderCounts and @FT_Stroker_ExportBorder. + * + * @values: + * FT_STROKER_BORDER_LEFT :: + * Select the left border, relative to the drawing direction. + * + * FT_STROKER_BORDER_RIGHT :: + * Select the right border, relative to the drawing direction. + * + * @note: + * Applications are generally interested in the `inside' and `outside' + * borders. However, there is no direct mapping between these and the + * `left' and `right' ones, since this really depends on the glyph's + * drawing orientation, which varies between font formats. + * + * You can however use @FT_Outline_GetInsideBorder and + * @FT_Outline_GetOutsideBorder to get these. + */ + typedef enum FT_StrokerBorder_ + { + FT_STROKER_BORDER_LEFT = 0, + FT_STROKER_BORDER_RIGHT + + } FT_StrokerBorder; + + + /************************************************************** + * + * @function: + * FT_Outline_GetInsideBorder + * + * @description: + * Retrieve the @FT_StrokerBorder value corresponding to the + * `inside' borders of a given outline. + * + * @input: + * outline :: + * The source outline handle. + * + * @return: + * The border index. @FT_STROKER_BORDER_RIGHT for empty or invalid + * outlines. + */ + FT_EXPORT( FT_StrokerBorder ) + FT_Outline_GetInsideBorder( FT_Outline* outline ); + + + /************************************************************** + * + * @function: + * FT_Outline_GetOutsideBorder + * + * @description: + * Retrieve the @FT_StrokerBorder value corresponding to the + * `outside' borders of a given outline. + * + * @input: + * outline :: + * The source outline handle. + * + * @return: + * The border index. @FT_STROKER_BORDER_LEFT for empty or invalid + * outlines. + */ + FT_EXPORT( FT_StrokerBorder ) + FT_Outline_GetOutsideBorder( FT_Outline* outline ); + + + /************************************************************** + * + * @function: + * FT_Stroker_New + * + * @description: + * Create a new stroker object. + * + * @input: + * library :: + * FreeType library handle. + * + * @output: + * astroker :: + * A new stroker object handle. NULL in case of error. + * + * @return: + * FreeType error code. 0~means success. + */ + FT_EXPORT( FT_Error ) + FT_Stroker_New( FT_Library library, + FT_Stroker *astroker ); + + + /************************************************************** + * + * @function: + * FT_Stroker_Set + * + * @description: + * Reset a stroker object's attributes. + * + * @input: + * stroker :: + * The target stroker handle. + * + * radius :: + * The border radius. + * + * line_cap :: + * The line cap style. + * + * line_join :: + * The line join style. + * + * miter_limit :: + * The miter limit for the FT_STROKER_LINEJOIN_MITER style, + * expressed as 16.16 fixed point value. + * + * @note: + * The radius is expressed in the same units as the outline + * coordinates. + */ + FT_EXPORT( void ) + FT_Stroker_Set( FT_Stroker stroker, + FT_Fixed radius, + FT_Stroker_LineCap line_cap, + FT_Stroker_LineJoin line_join, + FT_Fixed miter_limit ); + + + /************************************************************** + * + * @function: + * FT_Stroker_Rewind + * + * @description: + * Reset a stroker object without changing its attributes. + * You should call this function before beginning a new + * series of calls to @FT_Stroker_BeginSubPath or + * @FT_Stroker_EndSubPath. + * + * @input: + * stroker :: + * The target stroker handle. + */ + FT_EXPORT( void ) + FT_Stroker_Rewind( FT_Stroker stroker ); + + + /************************************************************** + * + * @function: + * FT_Stroker_ParseOutline + * + * @description: + * A convenience function used to parse a whole outline with + * the stroker. The resulting outline(s) can be retrieved + * later by functions like @FT_Stroker_GetCounts and @FT_Stroker_Export. + * + * @input: + * stroker :: + * The target stroker handle. + * + * outline :: + * The source outline. + * + * opened :: + * A boolean. If~1, the outline is treated as an open path instead + * of a closed one. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * If `opened' is~0 (the default), the outline is treated as a closed + * path, and the stroker generates two distinct `border' outlines. + * + * If `opened' is~1, the outline is processed as an open path, and the + * stroker generates a single `stroke' outline. + * + * This function calls @FT_Stroker_Rewind automatically. + */ + FT_EXPORT( FT_Error ) + FT_Stroker_ParseOutline( FT_Stroker stroker, + FT_Outline* outline, + FT_Bool opened ); + + + /************************************************************** + * + * @function: + * FT_Stroker_BeginSubPath + * + * @description: + * Start a new sub-path in the stroker. + * + * @input: + * stroker :: + * The target stroker handle. + * + * to :: + * A pointer to the start vector. + * + * open :: + * A boolean. If~1, the sub-path is treated as an open one. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * This function is useful when you need to stroke a path that is + * not stored as an @FT_Outline object. + */ + FT_EXPORT( FT_Error ) + FT_Stroker_BeginSubPath( FT_Stroker stroker, + FT_Vector* to, + FT_Bool open ); + + + /************************************************************** + * + * @function: + * FT_Stroker_EndSubPath + * + * @description: + * Close the current sub-path in the stroker. + * + * @input: + * stroker :: + * The target stroker handle. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * You should call this function after @FT_Stroker_BeginSubPath. + * If the subpath was not `opened', this function `draws' a + * single line segment to the start position when needed. + */ + FT_EXPORT( FT_Error ) + FT_Stroker_EndSubPath( FT_Stroker stroker ); + + + /************************************************************** + * + * @function: + * FT_Stroker_LineTo + * + * @description: + * `Draw' a single line segment in the stroker's current sub-path, + * from the last position. + * + * @input: + * stroker :: + * The target stroker handle. + * + * to :: + * A pointer to the destination point. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * You should call this function between @FT_Stroker_BeginSubPath and + * @FT_Stroker_EndSubPath. + */ + FT_EXPORT( FT_Error ) + FT_Stroker_LineTo( FT_Stroker stroker, + FT_Vector* to ); + + + /************************************************************** + * + * @function: + * FT_Stroker_ConicTo + * + * @description: + * `Draw' a single quadratic BȨzier in the stroker's current sub-path, + * from the last position. + * + * @input: + * stroker :: + * The target stroker handle. + * + * control :: + * A pointer to a BȨzier control point. + * + * to :: + * A pointer to the destination point. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * You should call this function between @FT_Stroker_BeginSubPath and + * @FT_Stroker_EndSubPath. + */ + FT_EXPORT( FT_Error ) + FT_Stroker_ConicTo( FT_Stroker stroker, + FT_Vector* control, + FT_Vector* to ); + + + /************************************************************** + * + * @function: + * FT_Stroker_CubicTo + * + * @description: + * `Draw' a single cubic BȨzier in the stroker's current sub-path, + * from the last position. + * + * @input: + * stroker :: + * The target stroker handle. + * + * control1 :: + * A pointer to the first BȨzier control point. + * + * control2 :: + * A pointer to second BȨzier control point. + * + * to :: + * A pointer to the destination point. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * You should call this function between @FT_Stroker_BeginSubPath and + * @FT_Stroker_EndSubPath. + */ + FT_EXPORT( FT_Error ) + FT_Stroker_CubicTo( FT_Stroker stroker, + FT_Vector* control1, + FT_Vector* control2, + FT_Vector* to ); + + + /************************************************************** + * + * @function: + * FT_Stroker_GetBorderCounts + * + * @description: + * Call this function once you have finished parsing your paths + * with the stroker. It returns the number of points and + * contours necessary to export one of the `border' or `stroke' + * outlines generated by the stroker. + * + * @input: + * stroker :: + * The target stroker handle. + * + * border :: + * The border index. + * + * @output: + * anum_points :: + * The number of points. + * + * anum_contours :: + * The number of contours. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * When an outline, or a sub-path, is `closed', the stroker generates + * two independent `border' outlines, named `left' and `right'. + * + * When the outline, or a sub-path, is `opened', the stroker merges + * the `border' outlines with caps. The `left' border receives all + * points, while the `right' border becomes empty. + * + * Use the function @FT_Stroker_GetCounts instead if you want to + * retrieve the counts associated to both borders. + */ + FT_EXPORT( FT_Error ) + FT_Stroker_GetBorderCounts( FT_Stroker stroker, + FT_StrokerBorder border, + FT_UInt *anum_points, + FT_UInt *anum_contours ); + + + /************************************************************** + * + * @function: + * FT_Stroker_ExportBorder + * + * @description: + * Call this function after @FT_Stroker_GetBorderCounts to + * export the corresponding border to your own @FT_Outline + * structure. + * + * Note that this function appends the border points and + * contours to your outline, but does not try to resize its + * arrays. + * + * @input: + * stroker :: + * The target stroker handle. + * + * border :: + * The border index. + * + * outline :: + * The target outline handle. + * + * @note: + * Always call this function after @FT_Stroker_GetBorderCounts to + * get sure that there is enough room in your @FT_Outline object to + * receive all new data. + * + * When an outline, or a sub-path, is `closed', the stroker generates + * two independent `border' outlines, named `left' and `right' + * + * When the outline, or a sub-path, is `opened', the stroker merges + * the `border' outlines with caps. The `left' border receives all + * points, while the `right' border becomes empty. + * + * Use the function @FT_Stroker_Export instead if you want to + * retrieve all borders at once. + */ + FT_EXPORT( void ) + FT_Stroker_ExportBorder( FT_Stroker stroker, + FT_StrokerBorder border, + FT_Outline* outline ); + + + /************************************************************** + * + * @function: + * FT_Stroker_GetCounts + * + * @description: + * Call this function once you have finished parsing your paths + * with the stroker. It returns the number of points and + * contours necessary to export all points/borders from the stroked + * outline/path. + * + * @input: + * stroker :: + * The target stroker handle. + * + * @output: + * anum_points :: + * The number of points. + * + * anum_contours :: + * The number of contours. + * + * @return: + * FreeType error code. 0~means success. + */ + FT_EXPORT( FT_Error ) + FT_Stroker_GetCounts( FT_Stroker stroker, + FT_UInt *anum_points, + FT_UInt *anum_contours ); + + + /************************************************************** + * + * @function: + * FT_Stroker_Export + * + * @description: + * Call this function after @FT_Stroker_GetBorderCounts to + * export all borders to your own @FT_Outline structure. + * + * Note that this function appends the border points and + * contours to your outline, but does not try to resize its + * arrays. + * + * @input: + * stroker :: + * The target stroker handle. + * + * outline :: + * The target outline handle. + */ + FT_EXPORT( void ) + FT_Stroker_Export( FT_Stroker stroker, + FT_Outline* outline ); + + + /************************************************************** + * + * @function: + * FT_Stroker_Done + * + * @description: + * Destroy a stroker object. + * + * @input: + * stroker :: + * A stroker handle. Can be NULL. + */ + FT_EXPORT( void ) + FT_Stroker_Done( FT_Stroker stroker ); + + + /************************************************************** + * + * @function: + * FT_Glyph_Stroke + * + * @description: + * Stroke a given outline glyph object with a given stroker. + * + * @inout: + * pglyph :: + * Source glyph handle on input, new glyph handle on output. + * + * @input: + * stroker :: + * A stroker handle. + * + * destroy :: + * A Boolean. If~1, the source glyph object is destroyed + * on success. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * The source glyph is untouched in case of error. + */ + FT_EXPORT( FT_Error ) + FT_Glyph_Stroke( FT_Glyph *pglyph, + FT_Stroker stroker, + FT_Bool destroy ); + + + /************************************************************** + * + * @function: + * FT_Glyph_StrokeBorder + * + * @description: + * Stroke a given outline glyph object with a given stroker, but + * only return either its inside or outside border. + * + * @inout: + * pglyph :: + * Source glyph handle on input, new glyph handle on output. + * + * @input: + * stroker :: + * A stroker handle. + * + * inside :: + * A Boolean. If~1, return the inside border, otherwise + * the outside border. + * + * destroy :: + * A Boolean. If~1, the source glyph object is destroyed + * on success. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * The source glyph is untouched in case of error. + */ + FT_EXPORT( FT_Error ) + FT_Glyph_StrokeBorder( FT_Glyph *pglyph, + FT_Stroker stroker, + FT_Bool inside, + FT_Bool destroy ); + + /* */ + +FT_END_HEADER + +#endif /* __FT_STROKE_H__ */ + + +/* END */ + + +/* Local Variables: */ +/* coding: utf-8 */ +/* End: */ diff --git a/Lib/Include/freetype/ftsynth.h b/Lib/Include/freetype/ftsynth.h new file mode 100644 index 0000000..a068b79 --- /dev/null +++ b/Lib/Include/freetype/ftsynth.h @@ -0,0 +1,80 @@ +/***************************************************************************/ +/* */ +/* ftsynth.h */ +/* */ +/* FreeType synthesizing code for emboldening and slanting */ +/* (specification). */ +/* */ +/* Copyright 2000-2001, 2003, 2006, 2008 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /********* *********/ + /********* WARNING, THIS IS ALPHA CODE! THIS API *********/ + /********* IS DUE TO CHANGE UNTIL STRICTLY NOTIFIED BY THE *********/ + /********* FREETYPE DEVELOPMENT TEAM *********/ + /********* *********/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + /* Main reason for not lifting the functions in this module to a */ + /* `standard' API is that the used parameters for emboldening and */ + /* slanting are not configurable. Consider the functions as a */ + /* code resource which should be copied into the application and */ + /* adapted to the particular needs. */ + + +#ifndef __FTSYNTH_H__ +#define __FTSYNTH_H__ + + +#include <ft2build.h> +#include FT_FREETYPE_H + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + /* Embolden a glyph by a `reasonable' value (which is highly a matter of */ + /* taste). This function is actually a convenience function, providing */ + /* a wrapper for @FT_Outline_Embolden and @FT_Bitmap_Embolden. */ + /* */ + /* For emboldened outlines the metrics are estimates only; if you need */ + /* precise values you should call @FT_Outline_Get_CBox. */ + FT_EXPORT( void ) + FT_GlyphSlot_Embolden( FT_GlyphSlot slot ); + + /* Slant an outline glyph to the right by about 12 degrees. */ + FT_EXPORT( void ) + FT_GlyphSlot_Oblique( FT_GlyphSlot slot ); + + /* */ + +FT_END_HEADER + +#endif /* __FTSYNTH_H__ */ + + +/* END */ diff --git a/Lib/Include/freetype/ftsystem.h b/Lib/Include/freetype/ftsystem.h new file mode 100644 index 0000000..e07460c --- /dev/null +++ b/Lib/Include/freetype/ftsystem.h @@ -0,0 +1,347 @@ +/***************************************************************************/ +/* */ +/* ftsystem.h */ +/* */ +/* FreeType low-level system interface definition (specification). */ +/* */ +/* Copyright 1996-2001, 2002, 2005, 2010 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef __FTSYSTEM_H__ +#define __FTSYSTEM_H__ + + +#include <ft2build.h> + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /* */ + /* <Section> */ + /* system_interface */ + /* */ + /* <Title> */ + /* System Interface */ + /* */ + /* <Abstract> */ + /* How FreeType manages memory and i/o. */ + /* */ + /* <Description> */ + /* This section contains various definitions related to memory */ + /* management and i/o access. You need to understand this */ + /* information if you want to use a custom memory manager or you own */ + /* i/o streams. */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* M E M O R Y M A N A G E M E N T */ + /* */ + /*************************************************************************/ + + + /************************************************************************* + * + * @type: + * FT_Memory + * + * @description: + * A handle to a given memory manager object, defined with an + * @FT_MemoryRec structure. + * + */ + typedef struct FT_MemoryRec_* FT_Memory; + + + /************************************************************************* + * + * @functype: + * FT_Alloc_Func + * + * @description: + * A function used to allocate `size' bytes from `memory'. + * + * @input: + * memory :: + * A handle to the source memory manager. + * + * size :: + * The size in bytes to allocate. + * + * @return: + * Address of new memory block. 0~in case of failure. + * + */ + typedef void* + (*FT_Alloc_Func)( FT_Memory memory, + long size ); + + + /************************************************************************* + * + * @functype: + * FT_Free_Func + * + * @description: + * A function used to release a given block of memory. + * + * @input: + * memory :: + * A handle to the source memory manager. + * + * block :: + * The address of the target memory block. + * + */ + typedef void + (*FT_Free_Func)( FT_Memory memory, + void* block ); + + + /************************************************************************* + * + * @functype: + * FT_Realloc_Func + * + * @description: + * A function used to re-allocate a given block of memory. + * + * @input: + * memory :: + * A handle to the source memory manager. + * + * cur_size :: + * The block's current size in bytes. + * + * new_size :: + * The block's requested new size. + * + * block :: + * The block's current address. + * + * @return: + * New block address. 0~in case of memory shortage. + * + * @note: + * In case of error, the old block must still be available. + * + */ + typedef void* + (*FT_Realloc_Func)( FT_Memory memory, + long cur_size, + long new_size, + void* block ); + + + /************************************************************************* + * + * @struct: + * FT_MemoryRec + * + * @description: + * A structure used to describe a given memory manager to FreeType~2. + * + * @fields: + * user :: + * A generic typeless pointer for user data. + * + * alloc :: + * A pointer type to an allocation function. + * + * free :: + * A pointer type to an memory freeing function. + * + * realloc :: + * A pointer type to a reallocation function. + * + */ + struct FT_MemoryRec_ + { + void* user; + FT_Alloc_Func alloc; + FT_Free_Func free; + FT_Realloc_Func realloc; + }; + + + /*************************************************************************/ + /* */ + /* I / O M A N A G E M E N T */ + /* */ + /*************************************************************************/ + + + /************************************************************************* + * + * @type: + * FT_Stream + * + * @description: + * A handle to an input stream. + * + */ + typedef struct FT_StreamRec_* FT_Stream; + + + /************************************************************************* + * + * @struct: + * FT_StreamDesc + * + * @description: + * A union type used to store either a long or a pointer. This is used + * to store a file descriptor or a `FILE*' in an input stream. + * + */ + typedef union FT_StreamDesc_ + { + long value; + void* pointer; + + } FT_StreamDesc; + + + /************************************************************************* + * + * @functype: + * FT_Stream_IoFunc + * + * @description: + * A function used to seek and read data from a given input stream. + * + * @input: + * stream :: + * A handle to the source stream. + * + * offset :: + * The offset of read in stream (always from start). + * + * buffer :: + * The address of the read buffer. + * + * count :: + * The number of bytes to read from the stream. + * + * @return: + * The number of bytes effectively read by the stream. + * + * @note: + * This function might be called to perform a seek or skip operation + * with a `count' of~0. A non-zero return value then indicates an + * error. + * + */ + typedef unsigned long + (*FT_Stream_IoFunc)( FT_Stream stream, + unsigned long offset, + unsigned char* buffer, + unsigned long count ); + + + /************************************************************************* + * + * @functype: + * FT_Stream_CloseFunc + * + * @description: + * A function used to close a given input stream. + * + * @input: + * stream :: + * A handle to the target stream. + * + */ + typedef void + (*FT_Stream_CloseFunc)( FT_Stream stream ); + + + /************************************************************************* + * + * @struct: + * FT_StreamRec + * + * @description: + * A structure used to describe an input stream. + * + * @input: + * base :: + * For memory-based streams, this is the address of the first stream + * byte in memory. This field should always be set to NULL for + * disk-based streams. + * + * size :: + * The stream size in bytes. + * + * pos :: + * The current position within the stream. + * + * descriptor :: + * This field is a union that can hold an integer or a pointer. It is + * used by stream implementations to store file descriptors or `FILE*' + * pointers. + * + * pathname :: + * This field is completely ignored by FreeType. However, it is often + * useful during debugging to use it to store the stream's filename + * (where available). + * + * read :: + * The stream's input function. + * + * close :: + * The stream's close function. + * + * memory :: + * The memory manager to use to preload frames. This is set + * internally by FreeType and shouldn't be touched by stream + * implementations. + * + * cursor :: + * This field is set and used internally by FreeType when parsing + * frames. + * + * limit :: + * This field is set and used internally by FreeType when parsing + * frames. + * + */ + typedef struct FT_StreamRec_ + { + unsigned char* base; + unsigned long size; + unsigned long pos; + + FT_StreamDesc descriptor; + FT_StreamDesc pathname; + FT_Stream_IoFunc read; + FT_Stream_CloseFunc close; + + FT_Memory memory; + unsigned char* cursor; + unsigned char* limit; + + } FT_StreamRec; + + + /* */ + + +FT_END_HEADER + +#endif /* __FTSYSTEM_H__ */ + + +/* END */ diff --git a/Lib/Include/freetype/fttrigon.h b/Lib/Include/freetype/fttrigon.h new file mode 100644 index 0000000..6b77d2e --- /dev/null +++ b/Lib/Include/freetype/fttrigon.h @@ -0,0 +1,350 @@ +/***************************************************************************/ +/* */ +/* fttrigon.h */ +/* */ +/* FreeType trigonometric functions (specification). */ +/* */ +/* Copyright 2001, 2003, 2005, 2007 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef __FTTRIGON_H__ +#define __FTTRIGON_H__ + +#include FT_FREETYPE_H + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /* */ + /* <Section> */ + /* computations */ + /* */ + /*************************************************************************/ + + + /************************************************************************* + * + * @type: + * FT_Angle + * + * @description: + * This type is used to model angle values in FreeType. Note that the + * angle is a 16.16 fixed float value expressed in degrees. + * + */ + typedef FT_Fixed FT_Angle; + + + /************************************************************************* + * + * @macro: + * FT_ANGLE_PI + * + * @description: + * The angle pi expressed in @FT_Angle units. + * + */ +#define FT_ANGLE_PI ( 180L << 16 ) + + + /************************************************************************* + * + * @macro: + * FT_ANGLE_2PI + * + * @description: + * The angle 2*pi expressed in @FT_Angle units. + * + */ +#define FT_ANGLE_2PI ( FT_ANGLE_PI * 2 ) + + + /************************************************************************* + * + * @macro: + * FT_ANGLE_PI2 + * + * @description: + * The angle pi/2 expressed in @FT_Angle units. + * + */ +#define FT_ANGLE_PI2 ( FT_ANGLE_PI / 2 ) + + + /************************************************************************* + * + * @macro: + * FT_ANGLE_PI4 + * + * @description: + * The angle pi/4 expressed in @FT_Angle units. + * + */ +#define FT_ANGLE_PI4 ( FT_ANGLE_PI / 4 ) + + + /************************************************************************* + * + * @function: + * FT_Sin + * + * @description: + * Return the sinus of a given angle in fixed point format. + * + * @input: + * angle :: + * The input angle. + * + * @return: + * The sinus value. + * + * @note: + * If you need both the sinus and cosinus for a given angle, use the + * function @FT_Vector_Unit. + * + */ + FT_EXPORT( FT_Fixed ) + FT_Sin( FT_Angle angle ); + + + /************************************************************************* + * + * @function: + * FT_Cos + * + * @description: + * Return the cosinus of a given angle in fixed point format. + * + * @input: + * angle :: + * The input angle. + * + * @return: + * The cosinus value. + * + * @note: + * If you need both the sinus and cosinus for a given angle, use the + * function @FT_Vector_Unit. + * + */ + FT_EXPORT( FT_Fixed ) + FT_Cos( FT_Angle angle ); + + + /************************************************************************* + * + * @function: + * FT_Tan + * + * @description: + * Return the tangent of a given angle in fixed point format. + * + * @input: + * angle :: + * The input angle. + * + * @return: + * The tangent value. + * + */ + FT_EXPORT( FT_Fixed ) + FT_Tan( FT_Angle angle ); + + + /************************************************************************* + * + * @function: + * FT_Atan2 + * + * @description: + * Return the arc-tangent corresponding to a given vector (x,y) in + * the 2d plane. + * + * @input: + * x :: + * The horizontal vector coordinate. + * + * y :: + * The vertical vector coordinate. + * + * @return: + * The arc-tangent value (i.e. angle). + * + */ + FT_EXPORT( FT_Angle ) + FT_Atan2( FT_Fixed x, + FT_Fixed y ); + + + /************************************************************************* + * + * @function: + * FT_Angle_Diff + * + * @description: + * Return the difference between two angles. The result is always + * constrained to the ]-PI..PI] interval. + * + * @input: + * angle1 :: + * First angle. + * + * angle2 :: + * Second angle. + * + * @return: + * Constrained value of `value2-value1'. + * + */ + FT_EXPORT( FT_Angle ) + FT_Angle_Diff( FT_Angle angle1, + FT_Angle angle2 ); + + + /************************************************************************* + * + * @function: + * FT_Vector_Unit + * + * @description: + * Return the unit vector corresponding to a given angle. After the + * call, the value of `vec.x' will be `sin(angle)', and the value of + * `vec.y' will be `cos(angle)'. + * + * This function is useful to retrieve both the sinus and cosinus of a + * given angle quickly. + * + * @output: + * vec :: + * The address of target vector. + * + * @input: + * angle :: + * The address of angle. + * + */ + FT_EXPORT( void ) + FT_Vector_Unit( FT_Vector* vec, + FT_Angle angle ); + + + /************************************************************************* + * + * @function: + * FT_Vector_Rotate + * + * @description: + * Rotate a vector by a given angle. + * + * @inout: + * vec :: + * The address of target vector. + * + * @input: + * angle :: + * The address of angle. + * + */ + FT_EXPORT( void ) + FT_Vector_Rotate( FT_Vector* vec, + FT_Angle angle ); + + + /************************************************************************* + * + * @function: + * FT_Vector_Length + * + * @description: + * Return the length of a given vector. + * + * @input: + * vec :: + * The address of target vector. + * + * @return: + * The vector length, expressed in the same units that the original + * vector coordinates. + * + */ + FT_EXPORT( FT_Fixed ) + FT_Vector_Length( FT_Vector* vec ); + + + /************************************************************************* + * + * @function: + * FT_Vector_Polarize + * + * @description: + * Compute both the length and angle of a given vector. + * + * @input: + * vec :: + * The address of source vector. + * + * @output: + * length :: + * The vector length. + * + * angle :: + * The vector angle. + * + */ + FT_EXPORT( void ) + FT_Vector_Polarize( FT_Vector* vec, + FT_Fixed *length, + FT_Angle *angle ); + + + /************************************************************************* + * + * @function: + * FT_Vector_From_Polar + * + * @description: + * Compute vector coordinates from a length and angle. + * + * @output: + * vec :: + * The address of source vector. + * + * @input: + * length :: + * The vector length. + * + * angle :: + * The vector angle. + * + */ + FT_EXPORT( void ) + FT_Vector_From_Polar( FT_Vector* vec, + FT_Fixed length, + FT_Angle angle ); + + /* */ + + +FT_END_HEADER + +#endif /* __FTTRIGON_H__ */ + + +/* END */ diff --git a/Lib/Include/freetype/fttypes.h b/Lib/Include/freetype/fttypes.h new file mode 100644 index 0000000..a57ffa6 --- /dev/null +++ b/Lib/Include/freetype/fttypes.h @@ -0,0 +1,588 @@ +/***************************************************************************/ +/* */ +/* fttypes.h */ +/* */ +/* FreeType simple types definitions (specification only). */ +/* */ +/* Copyright 1996-2001, 2002, 2004, 2006, 2007, 2008 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef __FTTYPES_H__ +#define __FTTYPES_H__ + + +#include <ft2build.h> +#include FT_CONFIG_CONFIG_H +#include FT_SYSTEM_H +#include FT_IMAGE_H + +#include <stddef.h> + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /* */ + /* <Section> */ + /* basic_types */ + /* */ + /* <Title> */ + /* Basic Data Types */ + /* */ + /* <Abstract> */ + /* The basic data types defined by the library. */ + /* */ + /* <Description> */ + /* This section contains the basic data types defined by FreeType~2, */ + /* ranging from simple scalar types to bitmap descriptors. More */ + /* font-specific structures are defined in a different section. */ + /* */ + /* <Order> */ + /* FT_Byte */ + /* FT_Bytes */ + /* FT_Char */ + /* FT_Int */ + /* FT_UInt */ + /* FT_Int16 */ + /* FT_UInt16 */ + /* FT_Int32 */ + /* FT_UInt32 */ + /* FT_Short */ + /* FT_UShort */ + /* FT_Long */ + /* FT_ULong */ + /* FT_Bool */ + /* FT_Offset */ + /* FT_PtrDist */ + /* FT_String */ + /* FT_Tag */ + /* FT_Error */ + /* FT_Fixed */ + /* FT_Pointer */ + /* FT_Pos */ + /* FT_Vector */ + /* FT_BBox */ + /* FT_Matrix */ + /* FT_FWord */ + /* FT_UFWord */ + /* FT_F2Dot14 */ + /* FT_UnitVector */ + /* FT_F26Dot6 */ + /* */ + /* */ + /* FT_Generic */ + /* FT_Generic_Finalizer */ + /* */ + /* FT_Bitmap */ + /* FT_Pixel_Mode */ + /* FT_Palette_Mode */ + /* FT_Glyph_Format */ + /* FT_IMAGE_TAG */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_Bool */ + /* */ + /* <Description> */ + /* A typedef of unsigned char, used for simple booleans. As usual, */ + /* values 1 and~0 represent true and false, respectively. */ + /* */ + typedef unsigned char FT_Bool; + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_FWord */ + /* */ + /* <Description> */ + /* A signed 16-bit integer used to store a distance in original font */ + /* units. */ + /* */ + typedef signed short FT_FWord; /* distance in FUnits */ + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_UFWord */ + /* */ + /* <Description> */ + /* An unsigned 16-bit integer used to store a distance in original */ + /* font units. */ + /* */ + typedef unsigned short FT_UFWord; /* unsigned distance */ + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_Char */ + /* */ + /* <Description> */ + /* A simple typedef for the _signed_ char type. */ + /* */ + typedef signed char FT_Char; + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_Byte */ + /* */ + /* <Description> */ + /* A simple typedef for the _unsigned_ char type. */ + /* */ + typedef unsigned char FT_Byte; + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_Bytes */ + /* */ + /* <Description> */ + /* A typedef for constant memory areas. */ + /* */ + typedef const FT_Byte* FT_Bytes; + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_Tag */ + /* */ + /* <Description> */ + /* A typedef for 32-bit tags (as used in the SFNT format). */ + /* */ + typedef FT_UInt32 FT_Tag; + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_String */ + /* */ + /* <Description> */ + /* A simple typedef for the char type, usually used for strings. */ + /* */ + typedef char FT_String; + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_Short */ + /* */ + /* <Description> */ + /* A typedef for signed short. */ + /* */ + typedef signed short FT_Short; + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_UShort */ + /* */ + /* <Description> */ + /* A typedef for unsigned short. */ + /* */ + typedef unsigned short FT_UShort; + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_Int */ + /* */ + /* <Description> */ + /* A typedef for the int type. */ + /* */ + typedef signed int FT_Int; + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_UInt */ + /* */ + /* <Description> */ + /* A typedef for the unsigned int type. */ + /* */ + typedef unsigned int FT_UInt; + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_Long */ + /* */ + /* <Description> */ + /* A typedef for signed long. */ + /* */ + typedef signed long FT_Long; + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_ULong */ + /* */ + /* <Description> */ + /* A typedef for unsigned long. */ + /* */ + typedef unsigned long FT_ULong; + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_F2Dot14 */ + /* */ + /* <Description> */ + /* A signed 2.14 fixed float type used for unit vectors. */ + /* */ + typedef signed short FT_F2Dot14; + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_F26Dot6 */ + /* */ + /* <Description> */ + /* A signed 26.6 fixed float type used for vectorial pixel */ + /* coordinates. */ + /* */ + typedef signed long FT_F26Dot6; + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_Fixed */ + /* */ + /* <Description> */ + /* This type is used to store 16.16 fixed float values, like scaling */ + /* values or matrix coefficients. */ + /* */ + typedef signed long FT_Fixed; + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_Error */ + /* */ + /* <Description> */ + /* The FreeType error code type. A value of~0 is always interpreted */ + /* as a successful operation. */ + /* */ + typedef int FT_Error; + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_Pointer */ + /* */ + /* <Description> */ + /* A simple typedef for a typeless pointer. */ + /* */ + typedef void* FT_Pointer; + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_Offset */ + /* */ + /* <Description> */ + /* This is equivalent to the ANSI~C `size_t' type, i.e., the largest */ + /* _unsigned_ integer type used to express a file size or position, */ + /* or a memory block size. */ + /* */ + typedef size_t FT_Offset; + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_PtrDist */ + /* */ + /* <Description> */ + /* This is equivalent to the ANSI~C `ptrdiff_t' type, i.e., the */ + /* largest _signed_ integer type used to express the distance */ + /* between two pointers. */ + /* */ + typedef ft_ptrdiff_t FT_PtrDist; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_UnitVector */ + /* */ + /* <Description> */ + /* A simple structure used to store a 2D vector unit vector. Uses */ + /* FT_F2Dot14 types. */ + /* */ + /* <Fields> */ + /* x :: Horizontal coordinate. */ + /* */ + /* y :: Vertical coordinate. */ + /* */ + typedef struct FT_UnitVector_ + { + FT_F2Dot14 x; + FT_F2Dot14 y; + + } FT_UnitVector; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_Matrix */ + /* */ + /* <Description> */ + /* A simple structure used to store a 2x2 matrix. Coefficients are */ + /* in 16.16 fixed float format. The computation performed is: */ + /* */ + /* { */ + /* x' = x*xx + y*xy */ + /* y' = x*yx + y*yy */ + /* } */ + /* */ + /* <Fields> */ + /* xx :: Matrix coefficient. */ + /* */ + /* xy :: Matrix coefficient. */ + /* */ + /* yx :: Matrix coefficient. */ + /* */ + /* yy :: Matrix coefficient. */ + /* */ + typedef struct FT_Matrix_ + { + FT_Fixed xx, xy; + FT_Fixed yx, yy; + + } FT_Matrix; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_Data */ + /* */ + /* <Description> */ + /* Read-only binary data represented as a pointer and a length. */ + /* */ + /* <Fields> */ + /* pointer :: The data. */ + /* */ + /* length :: The length of the data in bytes. */ + /* */ + typedef struct FT_Data_ + { + const FT_Byte* pointer; + FT_Int length; + + } FT_Data; + + + /*************************************************************************/ + /* */ + /* <FuncType> */ + /* FT_Generic_Finalizer */ + /* */ + /* <Description> */ + /* Describe a function used to destroy the `client' data of any */ + /* FreeType object. See the description of the @FT_Generic type for */ + /* details of usage. */ + /* */ + /* <Input> */ + /* The address of the FreeType object which is under finalization. */ + /* Its client data is accessed through its `generic' field. */ + /* */ + typedef void (*FT_Generic_Finalizer)(void* object); + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_Generic */ + /* */ + /* <Description> */ + /* Client applications often need to associate their own data to a */ + /* variety of FreeType core objects. For example, a text layout API */ + /* might want to associate a glyph cache to a given size object. */ + /* */ + /* Most FreeType object contains a `generic' field, of type */ + /* FT_Generic, which usage is left to client applications and font */ + /* servers. */ + /* */ + /* It can be used to store a pointer to client-specific data, as well */ + /* as the address of a `finalizer' function, which will be called by */ + /* FreeType when the object is destroyed (for example, the previous */ + /* client example would put the address of the glyph cache destructor */ + /* in the `finalizer' field). */ + /* */ + /* <Fields> */ + /* data :: A typeless pointer to any client-specified data. This */ + /* field is completely ignored by the FreeType library. */ + /* */ + /* finalizer :: A pointer to a `generic finalizer' function, which */ + /* will be called when the object is destroyed. If this */ + /* field is set to NULL, no code will be called. */ + /* */ + typedef struct FT_Generic_ + { + void* data; + FT_Generic_Finalizer finalizer; + + } FT_Generic; + + + /*************************************************************************/ + /* */ + /* <Macro> */ + /* FT_MAKE_TAG */ + /* */ + /* <Description> */ + /* This macro converts four-letter tags which are used to label */ + /* TrueType tables into an unsigned long to be used within FreeType. */ + /* */ + /* <Note> */ + /* The produced values *must* be 32-bit integers. Don't redefine */ + /* this macro. */ + /* */ +#define FT_MAKE_TAG( _x1, _x2, _x3, _x4 ) \ + (FT_Tag) \ + ( ( (FT_ULong)_x1 << 24 ) | \ + ( (FT_ULong)_x2 << 16 ) | \ + ( (FT_ULong)_x3 << 8 ) | \ + (FT_ULong)_x4 ) + + + /*************************************************************************/ + /*************************************************************************/ + /* */ + /* L I S T M A N A G E M E N T */ + /* */ + /*************************************************************************/ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* <Section> */ + /* list_processing */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_ListNode */ + /* */ + /* <Description> */ + /* Many elements and objects in FreeType are listed through an */ + /* @FT_List record (see @FT_ListRec). As its name suggests, an */ + /* FT_ListNode is a handle to a single list element. */ + /* */ + typedef struct FT_ListNodeRec_* FT_ListNode; + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* FT_List */ + /* */ + /* <Description> */ + /* A handle to a list record (see @FT_ListRec). */ + /* */ + typedef struct FT_ListRec_* FT_List; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_ListNodeRec */ + /* */ + /* <Description> */ + /* A structure used to hold a single list element. */ + /* */ + /* <Fields> */ + /* prev :: The previous element in the list. NULL if first. */ + /* */ + /* next :: The next element in the list. NULL if last. */ + /* */ + /* data :: A typeless pointer to the listed object. */ + /* */ + typedef struct FT_ListNodeRec_ + { + FT_ListNode prev; + FT_ListNode next; + void* data; + + } FT_ListNodeRec; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_ListRec */ + /* */ + /* <Description> */ + /* A structure used to hold a simple doubly-linked list. These are */ + /* used in many parts of FreeType. */ + /* */ + /* <Fields> */ + /* head :: The head (first element) of doubly-linked list. */ + /* */ + /* tail :: The tail (last element) of doubly-linked list. */ + /* */ + typedef struct FT_ListRec_ + { + FT_ListNode head; + FT_ListNode tail; + + } FT_ListRec; + + + /* */ + +#define FT_IS_EMPTY( list ) ( (list).head == 0 ) + + /* return base error code (without module-specific prefix) */ +#define FT_ERROR_BASE( x ) ( (x) & 0xFF ) + + /* return module error code */ +#define FT_ERROR_MODULE( x ) ( (x) & 0xFF00U ) + +#define FT_BOOL( x ) ( (FT_Bool)( x ) ) + +FT_END_HEADER + +#endif /* __FTTYPES_H__ */ + + +/* END */ diff --git a/Lib/Include/freetype/ftwinfnt.h b/Lib/Include/freetype/ftwinfnt.h new file mode 100644 index 0000000..8ed9b33 --- /dev/null +++ b/Lib/Include/freetype/ftwinfnt.h @@ -0,0 +1,274 @@ +/***************************************************************************/ +/* */ +/* ftwinfnt.h */ +/* */ +/* FreeType API for accessing Windows fnt-specific data. */ +/* */ +/* Copyright 2003, 2004, 2008 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef __FTWINFNT_H__ +#define __FTWINFNT_H__ + +#include <ft2build.h> +#include FT_FREETYPE_H + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /* */ + /* <Section> */ + /* winfnt_fonts */ + /* */ + /* <Title> */ + /* Window FNT Files */ + /* */ + /* <Abstract> */ + /* Windows FNT specific API. */ + /* */ + /* <Description> */ + /* This section contains the declaration of Windows FNT specific */ + /* functions. */ + /* */ + /*************************************************************************/ + + + /************************************************************************* + * + * @enum: + * FT_WinFNT_ID_XXX + * + * @description: + * A list of valid values for the `charset' byte in + * @FT_WinFNT_HeaderRec. Exact mapping tables for the various cpXXXX + * encodings (except for cp1361) can be found at ftp://ftp.unicode.org + * in the MAPPINGS/VENDORS/MICSFT/WINDOWS subdirectory. cp1361 is + * roughly a superset of MAPPINGS/OBSOLETE/EASTASIA/KSC/JOHAB.TXT. + * + * @values: + * FT_WinFNT_ID_DEFAULT :: + * This is used for font enumeration and font creation as a + * `don't care' value. Valid font files don't contain this value. + * When querying for information about the character set of the font + * that is currently selected into a specified device context, this + * return value (of the related Windows API) simply denotes failure. + * + * FT_WinFNT_ID_SYMBOL :: + * There is no known mapping table available. + * + * FT_WinFNT_ID_MAC :: + * Mac Roman encoding. + * + * FT_WinFNT_ID_OEM :: + * From Michael Pȵttgen <michael@poettgen.de>: + * + * The `Windows Font Mapping' article says that FT_WinFNT_ID_OEM + * is used for the charset of vector fonts, like `modern.fon', + * `roman.fon', and `script.fon' on Windows. + * + * The `CreateFont' documentation says: The FT_WinFNT_ID_OEM value + * specifies a character set that is operating-system dependent. + * + * The `IFIMETRICS' documentation from the `Windows Driver + * Development Kit' says: This font supports an OEM-specific + * character set. The OEM character set is system dependent. + * + * In general OEM, as opposed to ANSI (i.e., cp1252), denotes the + * second default codepage that most international versions of + * Windows have. It is one of the OEM codepages from + * + * http://www.microsoft.com/globaldev/reference/cphome.mspx, + * + * and is used for the `DOS boxes', to support legacy applications. + * A German Windows version for example usually uses ANSI codepage + * 1252 and OEM codepage 850. + * + * FT_WinFNT_ID_CP874 :: + * A superset of Thai TIS 620 and ISO 8859-11. + * + * FT_WinFNT_ID_CP932 :: + * A superset of Japanese Shift-JIS (with minor deviations). + * + * FT_WinFNT_ID_CP936 :: + * A superset of simplified Chinese GB 2312-1980 (with different + * ordering and minor deviations). + * + * FT_WinFNT_ID_CP949 :: + * A superset of Korean Hangul KS~C 5601-1987 (with different + * ordering and minor deviations). + * + * FT_WinFNT_ID_CP950 :: + * A superset of traditional Chinese Big~5 ETen (with different + * ordering and minor deviations). + * + * FT_WinFNT_ID_CP1250 :: + * A superset of East European ISO 8859-2 (with slightly different + * ordering). + * + * FT_WinFNT_ID_CP1251 :: + * A superset of Russian ISO 8859-5 (with different ordering). + * + * FT_WinFNT_ID_CP1252 :: + * ANSI encoding. A superset of ISO 8859-1. + * + * FT_WinFNT_ID_CP1253 :: + * A superset of Greek ISO 8859-7 (with minor modifications). + * + * FT_WinFNT_ID_CP1254 :: + * A superset of Turkish ISO 8859-9. + * + * FT_WinFNT_ID_CP1255 :: + * A superset of Hebrew ISO 8859-8 (with some modifications). + * + * FT_WinFNT_ID_CP1256 :: + * A superset of Arabic ISO 8859-6 (with different ordering). + * + * FT_WinFNT_ID_CP1257 :: + * A superset of Baltic ISO 8859-13 (with some deviations). + * + * FT_WinFNT_ID_CP1258 :: + * For Vietnamese. This encoding doesn't cover all necessary + * characters. + * + * FT_WinFNT_ID_CP1361 :: + * Korean (Johab). + */ + +#define FT_WinFNT_ID_CP1252 0 +#define FT_WinFNT_ID_DEFAULT 1 +#define FT_WinFNT_ID_SYMBOL 2 +#define FT_WinFNT_ID_MAC 77 +#define FT_WinFNT_ID_CP932 128 +#define FT_WinFNT_ID_CP949 129 +#define FT_WinFNT_ID_CP1361 130 +#define FT_WinFNT_ID_CP936 134 +#define FT_WinFNT_ID_CP950 136 +#define FT_WinFNT_ID_CP1253 161 +#define FT_WinFNT_ID_CP1254 162 +#define FT_WinFNT_ID_CP1258 163 +#define FT_WinFNT_ID_CP1255 177 +#define FT_WinFNT_ID_CP1256 178 +#define FT_WinFNT_ID_CP1257 186 +#define FT_WinFNT_ID_CP1251 204 +#define FT_WinFNT_ID_CP874 222 +#define FT_WinFNT_ID_CP1250 238 +#define FT_WinFNT_ID_OEM 255 + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_WinFNT_HeaderRec */ + /* */ + /* <Description> */ + /* Windows FNT Header info. */ + /* */ + typedef struct FT_WinFNT_HeaderRec_ + { + FT_UShort version; + FT_ULong file_size; + FT_Byte copyright[60]; + FT_UShort file_type; + FT_UShort nominal_point_size; + FT_UShort vertical_resolution; + FT_UShort horizontal_resolution; + FT_UShort ascent; + FT_UShort internal_leading; + FT_UShort external_leading; + FT_Byte italic; + FT_Byte underline; + FT_Byte strike_out; + FT_UShort weight; + FT_Byte charset; + FT_UShort pixel_width; + FT_UShort pixel_height; + FT_Byte pitch_and_family; + FT_UShort avg_width; + FT_UShort max_width; + FT_Byte first_char; + FT_Byte last_char; + FT_Byte default_char; + FT_Byte break_char; + FT_UShort bytes_per_row; + FT_ULong device_offset; + FT_ULong face_name_offset; + FT_ULong bits_pointer; + FT_ULong bits_offset; + FT_Byte reserved; + FT_ULong flags; + FT_UShort A_space; + FT_UShort B_space; + FT_UShort C_space; + FT_UShort color_table_offset; + FT_ULong reserved1[4]; + + } FT_WinFNT_HeaderRec; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_WinFNT_Header */ + /* */ + /* <Description> */ + /* A handle to an @FT_WinFNT_HeaderRec structure. */ + /* */ + typedef struct FT_WinFNT_HeaderRec_* FT_WinFNT_Header; + + + /********************************************************************** + * + * @function: + * FT_Get_WinFNT_Header + * + * @description: + * Retrieve a Windows FNT font info header. + * + * @input: + * face :: A handle to the input face. + * + * @output: + * aheader :: The WinFNT header. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * This function only works with Windows FNT faces, returning an error + * otherwise. + */ + FT_EXPORT( FT_Error ) + FT_Get_WinFNT_Header( FT_Face face, + FT_WinFNT_HeaderRec *aheader ); + + + /* */ + +FT_END_HEADER + +#endif /* __FTWINFNT_H__ */ + + +/* END */ + + +/* Local Variables: */ +/* coding: utf-8 */ +/* End: */ diff --git a/Lib/Include/freetype/ftxf86.h b/Lib/Include/freetype/ftxf86.h new file mode 100644 index 0000000..8c68afd --- /dev/null +++ b/Lib/Include/freetype/ftxf86.h @@ -0,0 +1,83 @@ +/***************************************************************************/ +/* */ +/* ftxf86.h */ +/* */ +/* Support functions for X11. */ +/* */ +/* Copyright 2002, 2003, 2004, 2006, 2007 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef __FTXF86_H__ +#define __FTXF86_H__ + +#include <ft2build.h> +#include FT_FREETYPE_H + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /* */ + /* <Section> */ + /* font_formats */ + /* */ + /* <Title> */ + /* Font Formats */ + /* */ + /* <Abstract> */ + /* Getting the font format. */ + /* */ + /* <Description> */ + /* The single function in this section can be used to get the font */ + /* format. Note that this information is not needed normally; */ + /* however, there are special cases (like in PDF devices) where it is */ + /* important to differentiate, in spite of FreeType's uniform API. */ + /* */ + /* This function is in the X11/xf86 namespace for historical reasons */ + /* and in no way depends on that windowing system. */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Get_X11_Font_Format */ + /* */ + /* <Description> */ + /* Return a string describing the format of a given face, using values */ + /* which can be used as an X11 FONT_PROPERTY. Possible values are */ + /* `TrueType', `Type~1', `BDF', `PCF', `Type~42', `CID~Type~1', `CFF', */ + /* `PFR', and `Windows~FNT'. */ + /* */ + /* <Input> */ + /* face :: */ + /* Input face handle. */ + /* */ + /* <Return> */ + /* Font format string. NULL in case of error. */ + /* */ + FT_EXPORT( const char* ) + FT_Get_X11_Font_Format( FT_Face face ); + + /* */ + +FT_END_HEADER + +#endif /* __FTXF86_H__ */ diff --git a/Lib/Include/freetype/internal/autohint.h b/Lib/Include/freetype/internal/autohint.h new file mode 100644 index 0000000..7e3a08a --- /dev/null +++ b/Lib/Include/freetype/internal/autohint.h @@ -0,0 +1,231 @@ +/***************************************************************************/ +/* */ +/* autohint.h */ +/* */ +/* High-level `autohint' module-specific interface (specification). */ +/* */ +/* Copyright 1996-2001, 2002, 2007 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + + /*************************************************************************/ + /* */ + /* The auto-hinter is used to load and automatically hint glyphs if a */ + /* format-specific hinter isn't available. */ + /* */ + /*************************************************************************/ + + +#ifndef __AUTOHINT_H__ +#define __AUTOHINT_H__ + + + /*************************************************************************/ + /* */ + /* A small technical note regarding automatic hinting in order to */ + /* clarify this module interface. */ + /* */ + /* An automatic hinter might compute two kinds of data for a given face: */ + /* */ + /* - global hints: Usually some metrics that describe global properties */ + /* of the face. It is computed by scanning more or less */ + /* aggressively the glyphs in the face, and thus can be */ + /* very slow to compute (even if the size of global */ + /* hints is really small). */ + /* */ + /* - glyph hints: These describe some important features of the glyph */ + /* outline, as well as how to align them. They are */ + /* generally much faster to compute than global hints. */ + /* */ + /* The current FreeType auto-hinter does a pretty good job while */ + /* performing fast computations for both global and glyph hints. */ + /* However, we might be interested in introducing more complex and */ + /* powerful algorithms in the future, like the one described in the John */ + /* D. Hobby paper, which unfortunately requires a lot more horsepower. */ + /* */ + /* Because a sufficiently sophisticated font management system would */ + /* typically implement an LRU cache of opened face objects to reduce */ + /* memory usage, it is a good idea to be able to avoid recomputing */ + /* global hints every time the same face is re-opened. */ + /* */ + /* We thus provide the ability to cache global hints outside of the face */ + /* object, in order to speed up font re-opening time. Of course, this */ + /* feature is purely optional, so most client programs won't even notice */ + /* it. */ + /* */ + /* I initially thought that it would be a good idea to cache the glyph */ + /* hints too. However, my general idea now is that if you really need */ + /* to cache these too, you are simply in need of a new font format, */ + /* where all this information could be stored within the font file and */ + /* decoded on the fly. */ + /* */ + /*************************************************************************/ + + +#include <ft2build.h> +#include FT_FREETYPE_H + + +FT_BEGIN_HEADER + + + typedef struct FT_AutoHinterRec_ *FT_AutoHinter; + + + /*************************************************************************/ + /* */ + /* <FuncType> */ + /* FT_AutoHinter_GlobalGetFunc */ + /* */ + /* <Description> */ + /* Retrieves the global hints computed for a given face object the */ + /* resulting data is dissociated from the face and will survive a */ + /* call to FT_Done_Face(). It must be discarded through the API */ + /* FT_AutoHinter_GlobalDoneFunc(). */ + /* */ + /* <Input> */ + /* hinter :: A handle to the source auto-hinter. */ + /* */ + /* face :: A handle to the source face object. */ + /* */ + /* <Output> */ + /* global_hints :: A typeless pointer to the global hints. */ + /* */ + /* global_len :: The size in bytes of the global hints. */ + /* */ + typedef void + (*FT_AutoHinter_GlobalGetFunc)( FT_AutoHinter hinter, + FT_Face face, + void** global_hints, + long* global_len ); + + + /*************************************************************************/ + /* */ + /* <FuncType> */ + /* FT_AutoHinter_GlobalDoneFunc */ + /* */ + /* <Description> */ + /* Discards the global hints retrieved through */ + /* FT_AutoHinter_GlobalGetFunc(). This is the only way these hints */ + /* are freed from memory. */ + /* */ + /* <Input> */ + /* hinter :: A handle to the auto-hinter module. */ + /* */ + /* global :: A pointer to retrieved global hints to discard. */ + /* */ + typedef void + (*FT_AutoHinter_GlobalDoneFunc)( FT_AutoHinter hinter, + void* global ); + + + /*************************************************************************/ + /* */ + /* <FuncType> */ + /* FT_AutoHinter_GlobalResetFunc */ + /* */ + /* <Description> */ + /* This function is used to recompute the global metrics in a given */ + /* font. This is useful when global font data changes (e.g. Multiple */ + /* Masters fonts where blend coordinates change). */ + /* */ + /* <Input> */ + /* hinter :: A handle to the source auto-hinter. */ + /* */ + /* face :: A handle to the face. */ + /* */ + typedef void + (*FT_AutoHinter_GlobalResetFunc)( FT_AutoHinter hinter, + FT_Face face ); + + + /*************************************************************************/ + /* */ + /* <FuncType> */ + /* FT_AutoHinter_GlyphLoadFunc */ + /* */ + /* <Description> */ + /* This function is used to load, scale, and automatically hint a */ + /* glyph from a given face. */ + /* */ + /* <Input> */ + /* face :: A handle to the face. */ + /* */ + /* glyph_index :: The glyph index. */ + /* */ + /* load_flags :: The load flags. */ + /* */ + /* <Note> */ + /* This function is capable of loading composite glyphs by hinting */ + /* each sub-glyph independently (which improves quality). */ + /* */ + /* It will call the font driver with FT_Load_Glyph(), with */ + /* FT_LOAD_NO_SCALE set. */ + /* */ + typedef FT_Error + (*FT_AutoHinter_GlyphLoadFunc)( FT_AutoHinter hinter, + FT_GlyphSlot slot, + FT_Size size, + FT_UInt glyph_index, + FT_Int32 load_flags ); + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_AutoHinter_ServiceRec */ + /* */ + /* <Description> */ + /* The auto-hinter module's interface. */ + /* */ + typedef struct FT_AutoHinter_ServiceRec_ + { + FT_AutoHinter_GlobalResetFunc reset_face; + FT_AutoHinter_GlobalGetFunc get_global_hints; + FT_AutoHinter_GlobalDoneFunc done_global_hints; + FT_AutoHinter_GlyphLoadFunc load_glyph; + + } FT_AutoHinter_ServiceRec, *FT_AutoHinter_Service; + +#ifndef FT_CONFIG_OPTION_PIC + +#define FT_DEFINE_AUTOHINTER_SERVICE(class_, reset_face_, get_global_hints_, \ + done_global_hints_, load_glyph_) \ + FT_CALLBACK_TABLE_DEF \ + const FT_AutoHinter_ServiceRec class_ = \ + { \ + reset_face_, get_global_hints_, done_global_hints_, load_glyph_ \ + }; + +#else /* FT_CONFIG_OPTION_PIC */ + +#define FT_DEFINE_AUTOHINTER_SERVICE(class_, reset_face_, get_global_hints_, \ + done_global_hints_, load_glyph_) \ + void \ + FT_Init_Class_##class_( FT_Library library, \ + FT_AutoHinter_ServiceRec* clazz) \ + { \ + FT_UNUSED(library); \ + clazz->reset_face = reset_face_; \ + clazz->get_global_hints = get_global_hints_; \ + clazz->done_global_hints = done_global_hints_; \ + clazz->load_glyph = load_glyph_; \ + } + +#endif /* FT_CONFIG_OPTION_PIC */ + +FT_END_HEADER + +#endif /* __AUTOHINT_H__ */ + + +/* END */ diff --git a/Lib/Include/freetype/internal/ftcalc.h b/Lib/Include/freetype/internal/ftcalc.h new file mode 100644 index 0000000..f8b4324 --- /dev/null +++ b/Lib/Include/freetype/internal/ftcalc.h @@ -0,0 +1,179 @@ +/***************************************************************************/ +/* */ +/* ftcalc.h */ +/* */ +/* Arithmetic computations (specification). */ +/* */ +/* Copyright 1996-2001, 2002, 2003, 2004, 2005, 2006, 2008, 2009 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef __FTCALC_H__ +#define __FTCALC_H__ + + +#include <ft2build.h> +#include FT_FREETYPE_H + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_FixedSqrt */ + /* */ + /* <Description> */ + /* Computes the square root of a 16.16 fixed point value. */ + /* */ + /* <Input> */ + /* x :: The value to compute the root for. */ + /* */ + /* <Return> */ + /* The result of `sqrt(x)'. */ + /* */ + /* <Note> */ + /* This function is not very fast. */ + /* */ + FT_BASE( FT_Int32 ) + FT_SqrtFixed( FT_Int32 x ); + + +#ifdef FT_CONFIG_OPTION_OLD_INTERNALS + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Sqrt32 */ + /* */ + /* <Description> */ + /* Computes the square root of an Int32 integer (which will be */ + /* handled as an unsigned long value). */ + /* */ + /* <Input> */ + /* x :: The value to compute the root for. */ + /* */ + /* <Return> */ + /* The result of `sqrt(x)'. */ + /* */ + FT_EXPORT( FT_Int32 ) + FT_Sqrt32( FT_Int32 x ); + +#endif /* FT_CONFIG_OPTION_OLD_INTERNALS */ + + + /*************************************************************************/ + /* */ + /* FT_MulDiv() and FT_MulFix() are declared in freetype.h. */ + /* */ + /*************************************************************************/ + + +#ifdef TT_USE_BYTECODE_INTERPRETER + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_MulDiv_No_Round */ + /* */ + /* <Description> */ + /* A very simple function used to perform the computation `(a*b)/c' */ + /* (without rounding) with maximal accuracy (it uses a 64-bit */ + /* intermediate integer whenever necessary). */ + /* */ + /* This function isn't necessarily as fast as some processor specific */ + /* operations, but is at least completely portable. */ + /* */ + /* <Input> */ + /* a :: The first multiplier. */ + /* b :: The second multiplier. */ + /* c :: The divisor. */ + /* */ + /* <Return> */ + /* The result of `(a*b)/c'. This function never traps when trying to */ + /* divide by zero; it simply returns `MaxInt' or `MinInt' depending */ + /* on the signs of `a' and `b'. */ + /* */ + FT_BASE( FT_Long ) + FT_MulDiv_No_Round( FT_Long a, + FT_Long b, + FT_Long c ); + +#endif /* TT_USE_BYTECODE_INTERPRETER */ + + + /* + * A variant of FT_Matrix_Multiply which scales its result afterwards. + * The idea is that both `a' and `b' are scaled by factors of 10 so that + * the values are as precise as possible to get a correct result during + * the 64bit multiplication. Let `sa' and `sb' be the scaling factors of + * `a' and `b', respectively, then the scaling factor of the result is + * `sa*sb'. + */ + FT_BASE( void ) + FT_Matrix_Multiply_Scaled( const FT_Matrix* a, + FT_Matrix *b, + FT_Long scaling ); + + + /* + * A variant of FT_Vector_Transform. See comments for + * FT_Matrix_Multiply_Scaled. + */ + + FT_BASE( void ) + FT_Vector_Transform_Scaled( FT_Vector* vector, + const FT_Matrix* matrix, + FT_Long scaling ); + + + /* + * Return -1, 0, or +1, depending on the orientation of a given corner. + * We use the Cartesian coordinate system, with positive vertical values + * going upwards. The function returns +1 if the corner turns to the + * left, -1 to the right, and 0 for undecidable cases. + */ + FT_BASE( FT_Int ) + ft_corner_orientation( FT_Pos in_x, + FT_Pos in_y, + FT_Pos out_x, + FT_Pos out_y ); + + /* + * Return TRUE if a corner is flat or nearly flat. This is equivalent to + * saying that the angle difference between the `in' and `out' vectors is + * very small. + */ + FT_BASE( FT_Int ) + ft_corner_is_flat( FT_Pos in_x, + FT_Pos in_y, + FT_Pos out_x, + FT_Pos out_y ); + + +#define INT_TO_F26DOT6( x ) ( (FT_Long)(x) << 6 ) +#define INT_TO_F2DOT14( x ) ( (FT_Long)(x) << 14 ) +#define INT_TO_FIXED( x ) ( (FT_Long)(x) << 16 ) +#define F2DOT14_TO_FIXED( x ) ( (FT_Long)(x) << 2 ) +#define FLOAT_TO_FIXED( x ) ( (FT_Long)( x * 65536.0 ) ) +#define FIXED_TO_INT( x ) ( FT_RoundFix( x ) >> 16 ) + +#define ROUND_F26DOT6( x ) ( x >= 0 ? ( ( (x) + 32 ) & -64 ) \ + : ( -( ( 32 - (x) ) & -64 ) ) ) + + +FT_END_HEADER + +#endif /* __FTCALC_H__ */ + + +/* END */ diff --git a/Lib/Include/freetype/internal/ftdebug.h b/Lib/Include/freetype/internal/ftdebug.h new file mode 100644 index 0000000..7baae35 --- /dev/null +++ b/Lib/Include/freetype/internal/ftdebug.h @@ -0,0 +1,250 @@ +/***************************************************************************/ +/* */ +/* ftdebug.h */ +/* */ +/* Debugging and logging component (specification). */ +/* */ +/* Copyright 1996-2001, 2002, 2004, 2006, 2007, 2008, 2009 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/* */ +/* IMPORTANT: A description of FreeType's debugging support can be */ +/* found in `docs/DEBUG.TXT'. Read it if you need to use or */ +/* understand this code. */ +/* */ +/***************************************************************************/ + + +#ifndef __FTDEBUG_H__ +#define __FTDEBUG_H__ + + +#include <ft2build.h> +#include FT_CONFIG_CONFIG_H +#include FT_FREETYPE_H + + +FT_BEGIN_HEADER + + + /* force the definition of FT_DEBUG_LEVEL_ERROR if FT_DEBUG_LEVEL_TRACE */ + /* is already defined; this simplifies the following #ifdefs */ + /* */ +#ifdef FT_DEBUG_LEVEL_TRACE +#undef FT_DEBUG_LEVEL_ERROR +#define FT_DEBUG_LEVEL_ERROR +#endif + + + /*************************************************************************/ + /* */ + /* Define the trace enums as well as the trace levels array when they */ + /* are needed. */ + /* */ + /*************************************************************************/ + +#ifdef FT_DEBUG_LEVEL_TRACE + +#define FT_TRACE_DEF( x ) trace_ ## x , + + /* defining the enumeration */ + typedef enum FT_Trace_ + { +#include FT_INTERNAL_TRACE_H + trace_count + + } FT_Trace; + + + /* defining the array of trace levels, provided by `src/base/ftdebug.c' */ + extern int ft_trace_levels[trace_count]; + +#undef FT_TRACE_DEF + +#endif /* FT_DEBUG_LEVEL_TRACE */ + + + /*************************************************************************/ + /* */ + /* Define the FT_TRACE macro */ + /* */ + /* IMPORTANT! */ + /* */ + /* Each component must define the macro FT_COMPONENT to a valid FT_Trace */ + /* value before using any TRACE macro. */ + /* */ + /*************************************************************************/ + +#ifdef FT_DEBUG_LEVEL_TRACE + +#define FT_TRACE( level, varformat ) \ + do \ + { \ + if ( ft_trace_levels[FT_COMPONENT] >= level ) \ + FT_Message varformat; \ + } while ( 0 ) + +#else /* !FT_DEBUG_LEVEL_TRACE */ + +#define FT_TRACE( level, varformat ) do { } while ( 0 ) /* nothing */ + +#endif /* !FT_DEBUG_LEVEL_TRACE */ + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Trace_Get_Count */ + /* */ + /* <Description> */ + /* Return the number of available trace components. */ + /* */ + /* <Return> */ + /* The number of trace components. 0 if FreeType 2 is not built with */ + /* FT_DEBUG_LEVEL_TRACE definition. */ + /* */ + /* <Note> */ + /* This function may be useful if you want to access elements of */ + /* the internal `ft_trace_levels' array by an index. */ + /* */ + FT_BASE( FT_Int ) + FT_Trace_Get_Count( void ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Trace_Get_Name */ + /* */ + /* <Description> */ + /* Return the name of a trace component. */ + /* */ + /* <Input> */ + /* The index of the trace component. */ + /* */ + /* <Return> */ + /* The name of the trace component. This is a statically allocated */ + /* C string, so do not free it after use. NULL if FreeType 2 is not */ + /* built with FT_DEBUG_LEVEL_TRACE definition. */ + /* */ + /* <Note> */ + /* Use @FT_Trace_Get_Count to get the number of available trace */ + /* components. */ + /* */ + /* This function may be useful if you want to control FreeType 2's */ + /* debug level in your application. */ + /* */ + FT_BASE( const char * ) + FT_Trace_Get_Name( FT_Int idx ); + + + /*************************************************************************/ + /* */ + /* You need two opening and closing parentheses! */ + /* */ + /* Example: FT_TRACE0(( "Value is %i", foo )) */ + /* */ + /* Output of the FT_TRACEX macros is sent to stderr. */ + /* */ + /*************************************************************************/ + +#define FT_TRACE0( varformat ) FT_TRACE( 0, varformat ) +#define FT_TRACE1( varformat ) FT_TRACE( 1, varformat ) +#define FT_TRACE2( varformat ) FT_TRACE( 2, varformat ) +#define FT_TRACE3( varformat ) FT_TRACE( 3, varformat ) +#define FT_TRACE4( varformat ) FT_TRACE( 4, varformat ) +#define FT_TRACE5( varformat ) FT_TRACE( 5, varformat ) +#define FT_TRACE6( varformat ) FT_TRACE( 6, varformat ) +#define FT_TRACE7( varformat ) FT_TRACE( 7, varformat ) + + + /*************************************************************************/ + /* */ + /* Define the FT_ERROR macro. */ + /* */ + /* Output of this macro is sent to stderr. */ + /* */ + /*************************************************************************/ + +#ifdef FT_DEBUG_LEVEL_ERROR + +#define FT_ERROR( varformat ) FT_Message varformat + +#else /* !FT_DEBUG_LEVEL_ERROR */ + +#define FT_ERROR( varformat ) do { } while ( 0 ) /* nothing */ + +#endif /* !FT_DEBUG_LEVEL_ERROR */ + + + /*************************************************************************/ + /* */ + /* Define the FT_ASSERT macro. */ + /* */ + /*************************************************************************/ + +#ifdef FT_DEBUG_LEVEL_ERROR + +#define FT_ASSERT( condition ) \ + do \ + { \ + if ( !( condition ) ) \ + FT_Panic( "assertion failed on line %d of file %s\n", \ + __LINE__, __FILE__ ); \ + } while ( 0 ) + +#else /* !FT_DEBUG_LEVEL_ERROR */ + +#define FT_ASSERT( condition ) do { } while ( 0 ) + +#endif /* !FT_DEBUG_LEVEL_ERROR */ + + + /*************************************************************************/ + /* */ + /* Define `FT_Message' and `FT_Panic' when needed. */ + /* */ + /*************************************************************************/ + +#ifdef FT_DEBUG_LEVEL_ERROR + +#include "stdio.h" /* for vfprintf() */ + + /* print a message */ + FT_BASE( void ) + FT_Message( const char* fmt, + ... ); + + /* print a message and exit */ + FT_BASE( void ) + FT_Panic( const char* fmt, + ... ); + +#endif /* FT_DEBUG_LEVEL_ERROR */ + + + FT_BASE( void ) + ft_debug_init( void ); + + +#if defined( _MSC_VER ) /* Visual C++ (and Intel C++) */ + + /* We disable the warning `conditional expression is constant' here */ + /* in order to compile cleanly with the maximum level of warnings. */ +#pragma warning( disable : 4127 ) + +#endif /* _MSC_VER */ + + +FT_END_HEADER + +#endif /* __FTDEBUG_H__ */ + + +/* END */ diff --git a/Lib/Include/freetype/internal/ftdriver.h b/Lib/Include/freetype/internal/ftdriver.h new file mode 100644 index 0000000..1d06997 --- /dev/null +++ b/Lib/Include/freetype/internal/ftdriver.h @@ -0,0 +1,422 @@ +/***************************************************************************/ +/* */ +/* ftdriver.h */ +/* */ +/* FreeType font driver interface (specification). */ +/* */ +/* Copyright 1996-2001, 2002, 2003, 2006, 2008 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef __FTDRIVER_H__ +#define __FTDRIVER_H__ + + +#include <ft2build.h> +#include FT_MODULE_H + + +FT_BEGIN_HEADER + + + typedef FT_Error + (*FT_Face_InitFunc)( FT_Stream stream, + FT_Face face, + FT_Int typeface_index, + FT_Int num_params, + FT_Parameter* parameters ); + + typedef void + (*FT_Face_DoneFunc)( FT_Face face ); + + + typedef FT_Error + (*FT_Size_InitFunc)( FT_Size size ); + + typedef void + (*FT_Size_DoneFunc)( FT_Size size ); + + + typedef FT_Error + (*FT_Slot_InitFunc)( FT_GlyphSlot slot ); + + typedef void + (*FT_Slot_DoneFunc)( FT_GlyphSlot slot ); + + + typedef FT_Error + (*FT_Size_RequestFunc)( FT_Size size, + FT_Size_Request req ); + + typedef FT_Error + (*FT_Size_SelectFunc)( FT_Size size, + FT_ULong size_index ); + +#ifdef FT_CONFIG_OPTION_OLD_INTERNALS + + typedef FT_Error + (*FT_Size_ResetPointsFunc)( FT_Size size, + FT_F26Dot6 char_width, + FT_F26Dot6 char_height, + FT_UInt horz_resolution, + FT_UInt vert_resolution ); + + typedef FT_Error + (*FT_Size_ResetPixelsFunc)( FT_Size size, + FT_UInt pixel_width, + FT_UInt pixel_height ); + +#endif /* FT_CONFIG_OPTION_OLD_INTERNALS */ + + typedef FT_Error + (*FT_Slot_LoadFunc)( FT_GlyphSlot slot, + FT_Size size, + FT_UInt glyph_index, + FT_Int32 load_flags ); + + + typedef FT_UInt + (*FT_CharMap_CharIndexFunc)( FT_CharMap charmap, + FT_Long charcode ); + + typedef FT_Long + (*FT_CharMap_CharNextFunc)( FT_CharMap charmap, + FT_Long charcode ); + + + typedef FT_Error + (*FT_Face_GetKerningFunc)( FT_Face face, + FT_UInt left_glyph, + FT_UInt right_glyph, + FT_Vector* kerning ); + + + typedef FT_Error + (*FT_Face_AttachFunc)( FT_Face face, + FT_Stream stream ); + + + typedef FT_Error + (*FT_Face_GetAdvancesFunc)( FT_Face face, + FT_UInt first, + FT_UInt count, + FT_Int32 flags, + FT_Fixed* advances ); + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_Driver_ClassRec */ + /* */ + /* <Description> */ + /* The font driver class. This structure mostly contains pointers to */ + /* driver methods. */ + /* */ + /* <Fields> */ + /* root :: The parent module. */ + /* */ + /* face_object_size :: The size of a face object in bytes. */ + /* */ + /* size_object_size :: The size of a size object in bytes. */ + /* */ + /* slot_object_size :: The size of a glyph object in bytes. */ + /* */ + /* init_face :: The format-specific face constructor. */ + /* */ + /* done_face :: The format-specific face destructor. */ + /* */ + /* init_size :: The format-specific size constructor. */ + /* */ + /* done_size :: The format-specific size destructor. */ + /* */ + /* init_slot :: The format-specific slot constructor. */ + /* */ + /* done_slot :: The format-specific slot destructor. */ + /* */ + /* */ + /* load_glyph :: A function handle to load a glyph to a slot. */ + /* This field is mandatory! */ + /* */ + /* get_kerning :: A function handle to return the unscaled */ + /* kerning for a given pair of glyphs. Can be */ + /* set to 0 if the format doesn't support */ + /* kerning. */ + /* */ + /* attach_file :: This function handle is used to read */ + /* additional data for a face from another */ + /* file/stream. For example, this can be used to */ + /* add data from AFM or PFM files on a Type 1 */ + /* face, or a CIDMap on a CID-keyed face. */ + /* */ + /* get_advances :: A function handle used to return advance */ + /* widths of `count' glyphs (in font units), */ + /* starting at `first'. The `vertical' flag must */ + /* be set to get vertical advance heights. The */ + /* `advances' buffer is caller-allocated. */ + /* Currently not implemented. The idea of this */ + /* function is to be able to perform */ + /* device-independent text layout without loading */ + /* a single glyph image. */ + /* */ + /* request_size :: A handle to a function used to request the new */ + /* character size. Can be set to 0 if the */ + /* scaling done in the base layer suffices. */ + /* */ + /* select_size :: A handle to a function used to select a new */ + /* fixed size. It is used only if */ + /* @FT_FACE_FLAG_FIXED_SIZES is set. Can be set */ + /* to 0 if the scaling done in the base layer */ + /* suffices. */ + /* <Note> */ + /* Most function pointers, with the exception of `load_glyph', can be */ + /* set to 0 to indicate a default behaviour. */ + /* */ + typedef struct FT_Driver_ClassRec_ + { + FT_Module_Class root; + + FT_Long face_object_size; + FT_Long size_object_size; + FT_Long slot_object_size; + + FT_Face_InitFunc init_face; + FT_Face_DoneFunc done_face; + + FT_Size_InitFunc init_size; + FT_Size_DoneFunc done_size; + + FT_Slot_InitFunc init_slot; + FT_Slot_DoneFunc done_slot; + +#ifdef FT_CONFIG_OPTION_OLD_INTERNALS + + FT_Size_ResetPointsFunc set_char_sizes; + FT_Size_ResetPixelsFunc set_pixel_sizes; + +#endif /* FT_CONFIG_OPTION_OLD_INTERNALS */ + + FT_Slot_LoadFunc load_glyph; + + FT_Face_GetKerningFunc get_kerning; + FT_Face_AttachFunc attach_file; + FT_Face_GetAdvancesFunc get_advances; + + /* since version 2.2 */ + FT_Size_RequestFunc request_size; + FT_Size_SelectFunc select_size; + + } FT_Driver_ClassRec, *FT_Driver_Class; + + + /* + * The following functions are used as stubs for `set_char_sizes' and + * `set_pixel_sizes'; the code uses `request_size' and `select_size' + * functions instead. + * + * Implementation is in `src/base/ftobjs.c'. + */ +#ifdef FT_CONFIG_OPTION_OLD_INTERNALS + + FT_BASE( FT_Error ) + ft_stub_set_char_sizes( FT_Size size, + FT_F26Dot6 width, + FT_F26Dot6 height, + FT_UInt horz_res, + FT_UInt vert_res ); + + FT_BASE( FT_Error ) + ft_stub_set_pixel_sizes( FT_Size size, + FT_UInt width, + FT_UInt height ); + +#endif /* FT_CONFIG_OPTION_OLD_INTERNALS */ + + /*************************************************************************/ + /* */ + /* <Macro> */ + /* FT_DECLARE_DRIVER */ + /* */ + /* <Description> */ + /* Used to create a forward declaration of a */ + /* FT_Driver_ClassRec stract instance. */ + /* */ + /* <Macro> */ + /* FT_DEFINE_DRIVER */ + /* */ + /* <Description> */ + /* Used to initialize an instance of FT_Driver_ClassRec struct. */ + /* */ + /* When FT_CONFIG_OPTION_PIC is defined a Create funtion will need */ + /* to called with a pointer where the allocated stracture is returned.*/ + /* And when it is no longer needed a Destroy function needs */ + /* to be called to release that allocation. */ + /* fcinit.c (ft_create_default_module_classes) already contains */ + /* a mechanism to call these functions for the default modules */ + /* described in ftmodule.h */ + /* */ + /* Notice that the created Create and Destroy functions call */ + /* pic_init and pic_free function to allow you to manually allocate */ + /* and initialize any additional global data, like module specific */ + /* interface, and put them in the global pic container defined in */ + /* ftpic.h. if you don't need them just implement the functions as */ + /* empty to resolve the link error. */ + /* */ + /* When FT_CONFIG_OPTION_PIC is not defined the struct will be */ + /* allocated in the global scope (or the scope where the macro */ + /* is used). */ + /* */ +#ifndef FT_CONFIG_OPTION_PIC + +#ifdef FT_CONFIG_OPTION_OLD_INTERNALS +#define FT_DEFINE_DRIVERS_OLD_INTERNALS(a_,b_) \ + a_, b_, +#else + #define FT_DEFINE_DRIVERS_OLD_INTERNALS(a_,b_) +#endif + +#define FT_DECLARE_DRIVER(class_) \ + FT_CALLBACK_TABLE \ + const FT_Driver_ClassRec class_; + +#define FT_DEFINE_DRIVER(class_, \ + flags_, size_, name_, version_, requires_, \ + interface_, init_, done_, get_interface_, \ + face_object_size_, size_object_size_, \ + slot_object_size_, init_face_, done_face_, \ + init_size_, done_size_, init_slot_, done_slot_, \ + old_set_char_sizes_, old_set_pixel_sizes_, \ + load_glyph_, get_kerning_, attach_file_, \ + get_advances_, request_size_, select_size_ ) \ + FT_CALLBACK_TABLE_DEF \ + const FT_Driver_ClassRec class_ = \ + { \ + FT_DEFINE_ROOT_MODULE(flags_,size_,name_,version_,requires_,interface_, \ + init_,done_,get_interface_) \ + \ + face_object_size_, \ + size_object_size_, \ + slot_object_size_, \ + \ + init_face_, \ + done_face_, \ + \ + init_size_, \ + done_size_, \ + \ + init_slot_, \ + done_slot_, \ + \ + FT_DEFINE_DRIVERS_OLD_INTERNALS(old_set_char_sizes_, old_set_pixel_sizes_) \ + \ + load_glyph_, \ + \ + get_kerning_, \ + attach_file_, \ + get_advances_, \ + \ + request_size_, \ + select_size_ \ + }; + +#else /* FT_CONFIG_OPTION_PIC */ + +#ifdef FT_CONFIG_OPTION_OLD_INTERNALS +#define FT_DEFINE_DRIVERS_OLD_INTERNALS(a_,b_) \ + clazz->set_char_sizes = a_; \ + clazz->set_pixel_sizes = b_; +#else + #define FT_DEFINE_DRIVERS_OLD_INTERNALS(a_,b_) +#endif + +#define FT_DECLARE_DRIVER(class_) FT_DECLARE_MODULE(class_) + +#define FT_DEFINE_DRIVER(class_, \ + flags_, size_, name_, version_, requires_, \ + interface_, init_, done_, get_interface_, \ + face_object_size_, size_object_size_, \ + slot_object_size_, init_face_, done_face_, \ + init_size_, done_size_, init_slot_, done_slot_, \ + old_set_char_sizes_, old_set_pixel_sizes_, \ + load_glyph_, get_kerning_, attach_file_, \ + get_advances_, request_size_, select_size_ ) \ + void class_##_pic_free( FT_Library library ); \ + FT_Error class_##_pic_init( FT_Library library ); \ + \ + void \ + FT_Destroy_Class_##class_( FT_Library library, \ + FT_Module_Class* clazz ) \ + { \ + FT_Memory memory = library->memory; \ + FT_Driver_Class dclazz = (FT_Driver_Class)clazz; \ + class_##_pic_free( library ); \ + if ( dclazz ) \ + FT_FREE( dclazz ); \ + } \ + \ + FT_Error \ + FT_Create_Class_##class_( FT_Library library, \ + FT_Module_Class** output_class ) \ + { \ + FT_Driver_Class clazz; \ + FT_Error error; \ + FT_Memory memory = library->memory; \ + \ + if ( FT_ALLOC( clazz, sizeof(*clazz) ) ) \ + return error; \ + \ + error = class_##_pic_init( library ); \ + if(error) \ + { \ + FT_FREE( clazz ); \ + return error; \ + } \ + \ + FT_DEFINE_ROOT_MODULE(flags_,size_,name_,version_,requires_,interface_, \ + init_,done_,get_interface_) \ + \ + clazz->face_object_size = face_object_size_; \ + clazz->size_object_size = size_object_size_; \ + clazz->slot_object_size = slot_object_size_; \ + \ + clazz->init_face = init_face_; \ + clazz->done_face = done_face_; \ + \ + clazz->init_size = init_size_; \ + clazz->done_size = done_size_; \ + \ + clazz->init_slot = init_slot_; \ + clazz->done_slot = done_slot_; \ + \ + FT_DEFINE_DRIVERS_OLD_INTERNALS(old_set_char_sizes_, old_set_pixel_sizes_) \ + \ + clazz->load_glyph = load_glyph_; \ + \ + clazz->get_kerning = get_kerning_; \ + clazz->attach_file = attach_file_; \ + clazz->get_advances = get_advances_; \ + \ + clazz->request_size = request_size_; \ + clazz->select_size = select_size_; \ + \ + *output_class = (FT_Module_Class*)clazz; \ + return FT_Err_Ok; \ + } + + +#endif /* FT_CONFIG_OPTION_PIC */ + +FT_END_HEADER + +#endif /* __FTDRIVER_H__ */ + + +/* END */ diff --git a/Lib/Include/freetype/internal/ftgloadr.h b/Lib/Include/freetype/internal/ftgloadr.h new file mode 100644 index 0000000..ce4dc6c --- /dev/null +++ b/Lib/Include/freetype/internal/ftgloadr.h @@ -0,0 +1,168 @@ +/***************************************************************************/ +/* */ +/* ftgloadr.h */ +/* */ +/* The FreeType glyph loader (specification). */ +/* */ +/* Copyright 2002, 2003, 2005, 2006 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef __FTGLOADR_H__ +#define __FTGLOADR_H__ + + +#include <ft2build.h> +#include FT_FREETYPE_H + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_GlyphLoader */ + /* */ + /* <Description> */ + /* The glyph loader is an internal object used to load several glyphs */ + /* together (for example, in the case of composites). */ + /* */ + /* <Note> */ + /* The glyph loader implementation is not part of the high-level API, */ + /* hence the forward structure declaration. */ + /* */ + typedef struct FT_GlyphLoaderRec_* FT_GlyphLoader ; + + +#if 0 /* moved to freetype.h in version 2.2 */ +#define FT_SUBGLYPH_FLAG_ARGS_ARE_WORDS 1 +#define FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES 2 +#define FT_SUBGLYPH_FLAG_ROUND_XY_TO_GRID 4 +#define FT_SUBGLYPH_FLAG_SCALE 8 +#define FT_SUBGLYPH_FLAG_XY_SCALE 0x40 +#define FT_SUBGLYPH_FLAG_2X2 0x80 +#define FT_SUBGLYPH_FLAG_USE_MY_METRICS 0x200 +#endif + + + typedef struct FT_SubGlyphRec_ + { + FT_Int index; + FT_UShort flags; + FT_Int arg1; + FT_Int arg2; + FT_Matrix transform; + + } FT_SubGlyphRec; + + + typedef struct FT_GlyphLoadRec_ + { + FT_Outline outline; /* outline */ + FT_Vector* extra_points; /* extra points table */ + FT_Vector* extra_points2; /* second extra points table */ + FT_UInt num_subglyphs; /* number of subglyphs */ + FT_SubGlyph subglyphs; /* subglyphs */ + + } FT_GlyphLoadRec, *FT_GlyphLoad; + + + typedef struct FT_GlyphLoaderRec_ + { + FT_Memory memory; + FT_UInt max_points; + FT_UInt max_contours; + FT_UInt max_subglyphs; + FT_Bool use_extra; + + FT_GlyphLoadRec base; + FT_GlyphLoadRec current; + + void* other; /* for possible future extension? */ + + } FT_GlyphLoaderRec; + + + /* create new empty glyph loader */ + FT_BASE( FT_Error ) + FT_GlyphLoader_New( FT_Memory memory, + FT_GlyphLoader *aloader ); + + /* add an extra points table to a glyph loader */ + FT_BASE( FT_Error ) + FT_GlyphLoader_CreateExtra( FT_GlyphLoader loader ); + + /* destroy a glyph loader */ + FT_BASE( void ) + FT_GlyphLoader_Done( FT_GlyphLoader loader ); + + /* reset a glyph loader (frees everything int it) */ + FT_BASE( void ) + FT_GlyphLoader_Reset( FT_GlyphLoader loader ); + + /* rewind a glyph loader */ + FT_BASE( void ) + FT_GlyphLoader_Rewind( FT_GlyphLoader loader ); + + /* check that there is enough space to add `n_points' and `n_contours' */ + /* to the glyph loader */ + FT_BASE( FT_Error ) + FT_GlyphLoader_CheckPoints( FT_GlyphLoader loader, + FT_UInt n_points, + FT_UInt n_contours ); + + +#define FT_GLYPHLOADER_CHECK_P( _loader, _count ) \ + ( (_count) == 0 || ((_loader)->base.outline.n_points + \ + (_loader)->current.outline.n_points + \ + (unsigned long)(_count)) <= (_loader)->max_points ) + +#define FT_GLYPHLOADER_CHECK_C( _loader, _count ) \ + ( (_count) == 0 || ((_loader)->base.outline.n_contours + \ + (_loader)->current.outline.n_contours + \ + (unsigned long)(_count)) <= (_loader)->max_contours ) + +#define FT_GLYPHLOADER_CHECK_POINTS( _loader, _points,_contours ) \ + ( ( FT_GLYPHLOADER_CHECK_P( _loader, _points ) && \ + FT_GLYPHLOADER_CHECK_C( _loader, _contours ) ) \ + ? 0 \ + : FT_GlyphLoader_CheckPoints( (_loader), (_points), (_contours) ) ) + + + /* check that there is enough space to add `n_subs' sub-glyphs to */ + /* a glyph loader */ + FT_BASE( FT_Error ) + FT_GlyphLoader_CheckSubGlyphs( FT_GlyphLoader loader, + FT_UInt n_subs ); + + /* prepare a glyph loader, i.e. empty the current glyph */ + FT_BASE( void ) + FT_GlyphLoader_Prepare( FT_GlyphLoader loader ); + + /* add the current glyph to the base glyph */ + FT_BASE( void ) + FT_GlyphLoader_Add( FT_GlyphLoader loader ); + + /* copy points from one glyph loader to another */ + FT_BASE( FT_Error ) + FT_GlyphLoader_CopyPoints( FT_GlyphLoader target, + FT_GlyphLoader source ); + + /* */ + + +FT_END_HEADER + +#endif /* __FTGLOADR_H__ */ + + +/* END */ diff --git a/Lib/Include/freetype/internal/ftmemory.h b/Lib/Include/freetype/internal/ftmemory.h new file mode 100644 index 0000000..026aa63 --- /dev/null +++ b/Lib/Include/freetype/internal/ftmemory.h @@ -0,0 +1,380 @@ +/***************************************************************************/ +/* */ +/* ftmemory.h */ +/* */ +/* The FreeType memory management macros (specification). */ +/* */ +/* Copyright 1996-2001, 2002, 2004, 2005, 2006, 2007, 2010 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef __FTMEMORY_H__ +#define __FTMEMORY_H__ + + +#include <ft2build.h> +#include FT_CONFIG_CONFIG_H +#include FT_TYPES_H + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /* */ + /* <Macro> */ + /* FT_SET_ERROR */ + /* */ + /* <Description> */ + /* This macro is used to set an implicit `error' variable to a given */ + /* expression's value (usually a function call), and convert it to a */ + /* boolean which is set whenever the value is != 0. */ + /* */ +#undef FT_SET_ERROR +#define FT_SET_ERROR( expression ) \ + ( ( error = (expression) ) != 0 ) + + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** ****/ + /**** M E M O R Y ****/ + /**** ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + /* + * C++ refuses to handle statements like p = (void*)anything, with `p' a + * typed pointer. Since we don't have a `typeof' operator in standard + * C++, we have to use a template to emulate it. + */ + +#ifdef __cplusplus + + extern "C++" + template <typename T> inline T* + cplusplus_typeof( T*, + void *v ) + { + return static_cast <T*> ( v ); + } + +#define FT_ASSIGNP( p, val ) (p) = cplusplus_typeof( (p), (val) ) + +#else + +#define FT_ASSIGNP( p, val ) (p) = (val) + +#endif + + + +#ifdef FT_DEBUG_MEMORY + + FT_BASE( const char* ) _ft_debug_file; + FT_BASE( long ) _ft_debug_lineno; + +#define FT_DEBUG_INNER( exp ) ( _ft_debug_file = __FILE__, \ + _ft_debug_lineno = __LINE__, \ + (exp) ) + +#define FT_ASSIGNP_INNER( p, exp ) ( _ft_debug_file = __FILE__, \ + _ft_debug_lineno = __LINE__, \ + FT_ASSIGNP( p, exp ) ) + +#else /* !FT_DEBUG_MEMORY */ + +#define FT_DEBUG_INNER( exp ) (exp) +#define FT_ASSIGNP_INNER( p, exp ) FT_ASSIGNP( p, exp ) + +#endif /* !FT_DEBUG_MEMORY */ + + + /* + * The allocation functions return a pointer, and the error code + * is written to through the `p_error' parameter. See below for + * for documentation. + */ + + FT_BASE( FT_Pointer ) + ft_mem_alloc( FT_Memory memory, + FT_Long size, + FT_Error *p_error ); + + FT_BASE( FT_Pointer ) + ft_mem_qalloc( FT_Memory memory, + FT_Long size, + FT_Error *p_error ); + + FT_BASE( FT_Pointer ) + ft_mem_realloc( FT_Memory memory, + FT_Long item_size, + FT_Long cur_count, + FT_Long new_count, + void* block, + FT_Error *p_error ); + + FT_BASE( FT_Pointer ) + ft_mem_qrealloc( FT_Memory memory, + FT_Long item_size, + FT_Long cur_count, + FT_Long new_count, + void* block, + FT_Error *p_error ); + + FT_BASE( void ) + ft_mem_free( FT_Memory memory, + const void* P ); + + +#define FT_MEM_ALLOC( ptr, size ) \ + FT_ASSIGNP_INNER( ptr, ft_mem_alloc( memory, (size), &error ) ) + +#define FT_MEM_FREE( ptr ) \ + FT_BEGIN_STMNT \ + ft_mem_free( memory, (ptr) ); \ + (ptr) = NULL; \ + FT_END_STMNT + +#define FT_MEM_NEW( ptr ) \ + FT_MEM_ALLOC( ptr, sizeof ( *(ptr) ) ) + +#define FT_MEM_REALLOC( ptr, cursz, newsz ) \ + FT_ASSIGNP_INNER( ptr, ft_mem_realloc( memory, 1, \ + (cursz), (newsz), \ + (ptr), &error ) ) + +#define FT_MEM_QALLOC( ptr, size ) \ + FT_ASSIGNP_INNER( ptr, ft_mem_qalloc( memory, (size), &error ) ) + +#define FT_MEM_QNEW( ptr ) \ + FT_MEM_QALLOC( ptr, sizeof ( *(ptr) ) ) + +#define FT_MEM_QREALLOC( ptr, cursz, newsz ) \ + FT_ASSIGNP_INNER( ptr, ft_mem_qrealloc( memory, 1, \ + (cursz), (newsz), \ + (ptr), &error ) ) + +#define FT_MEM_QRENEW_ARRAY( ptr, cursz, newsz ) \ + FT_ASSIGNP_INNER( ptr, ft_mem_qrealloc( memory, sizeof ( *(ptr) ), \ + (cursz), (newsz), \ + (ptr), &error ) ) + +#define FT_MEM_ALLOC_MULT( ptr, count, item_size ) \ + FT_ASSIGNP_INNER( ptr, ft_mem_realloc( memory, (item_size), \ + 0, (count), \ + NULL, &error ) ) + +#define FT_MEM_REALLOC_MULT( ptr, oldcnt, newcnt, itmsz ) \ + FT_ASSIGNP_INNER( ptr, ft_mem_realloc( memory, (itmsz), \ + (oldcnt), (newcnt), \ + (ptr), &error ) ) + +#define FT_MEM_QALLOC_MULT( ptr, count, item_size ) \ + FT_ASSIGNP_INNER( ptr, ft_mem_qrealloc( memory, (item_size), \ + 0, (count), \ + NULL, &error ) ) + +#define FT_MEM_QREALLOC_MULT( ptr, oldcnt, newcnt, itmsz) \ + FT_ASSIGNP_INNER( ptr, ft_mem_qrealloc( memory, (itmsz), \ + (oldcnt), (newcnt), \ + (ptr), &error ) ) + + +#define FT_MEM_SET_ERROR( cond ) ( (cond), error != 0 ) + + +#define FT_MEM_SET( dest, byte, count ) ft_memset( dest, byte, count ) + +#define FT_MEM_COPY( dest, source, count ) ft_memcpy( dest, source, count ) + +#define FT_MEM_MOVE( dest, source, count ) ft_memmove( dest, source, count ) + + +#define FT_MEM_ZERO( dest, count ) FT_MEM_SET( dest, 0, count ) + +#define FT_ZERO( p ) FT_MEM_ZERO( p, sizeof ( *(p) ) ) + + +#define FT_ARRAY_ZERO( dest, count ) \ + FT_MEM_ZERO( dest, (count) * sizeof ( *(dest) ) ) + +#define FT_ARRAY_COPY( dest, source, count ) \ + FT_MEM_COPY( dest, source, (count) * sizeof ( *(dest) ) ) + +#define FT_ARRAY_MOVE( dest, source, count ) \ + FT_MEM_MOVE( dest, source, (count) * sizeof ( *(dest) ) ) + + + /* + * Return the maximum number of addressable elements in an array. + * We limit ourselves to INT_MAX, rather than UINT_MAX, to avoid + * any problems. + */ +#define FT_ARRAY_MAX( ptr ) ( FT_INT_MAX / sizeof ( *(ptr) ) ) + +#define FT_ARRAY_CHECK( ptr, count ) ( (count) <= FT_ARRAY_MAX( ptr ) ) + + + /*************************************************************************/ + /* */ + /* The following functions macros expect that their pointer argument is */ + /* _typed_ in order to automatically compute array element sizes. */ + /* */ + +#define FT_MEM_NEW_ARRAY( ptr, count ) \ + FT_ASSIGNP_INNER( ptr, ft_mem_realloc( memory, sizeof ( *(ptr) ), \ + 0, (count), \ + NULL, &error ) ) + +#define FT_MEM_RENEW_ARRAY( ptr, cursz, newsz ) \ + FT_ASSIGNP_INNER( ptr, ft_mem_realloc( memory, sizeof ( *(ptr) ), \ + (cursz), (newsz), \ + (ptr), &error ) ) + +#define FT_MEM_QNEW_ARRAY( ptr, count ) \ + FT_ASSIGNP_INNER( ptr, ft_mem_qrealloc( memory, sizeof ( *(ptr) ), \ + 0, (count), \ + NULL, &error ) ) + +#define FT_MEM_QRENEW_ARRAY( ptr, cursz, newsz ) \ + FT_ASSIGNP_INNER( ptr, ft_mem_qrealloc( memory, sizeof ( *(ptr) ), \ + (cursz), (newsz), \ + (ptr), &error ) ) + + +#define FT_ALLOC( ptr, size ) \ + FT_MEM_SET_ERROR( FT_MEM_ALLOC( ptr, size ) ) + +#define FT_REALLOC( ptr, cursz, newsz ) \ + FT_MEM_SET_ERROR( FT_MEM_REALLOC( ptr, cursz, newsz ) ) + +#define FT_ALLOC_MULT( ptr, count, item_size ) \ + FT_MEM_SET_ERROR( FT_MEM_ALLOC_MULT( ptr, count, item_size ) ) + +#define FT_REALLOC_MULT( ptr, oldcnt, newcnt, itmsz ) \ + FT_MEM_SET_ERROR( FT_MEM_REALLOC_MULT( ptr, oldcnt, \ + newcnt, itmsz ) ) + +#define FT_QALLOC( ptr, size ) \ + FT_MEM_SET_ERROR( FT_MEM_QALLOC( ptr, size ) ) + +#define FT_QREALLOC( ptr, cursz, newsz ) \ + FT_MEM_SET_ERROR( FT_MEM_QREALLOC( ptr, cursz, newsz ) ) + +#define FT_QALLOC_MULT( ptr, count, item_size ) \ + FT_MEM_SET_ERROR( FT_MEM_QALLOC_MULT( ptr, count, item_size ) ) + +#define FT_QREALLOC_MULT( ptr, oldcnt, newcnt, itmsz ) \ + FT_MEM_SET_ERROR( FT_MEM_QREALLOC_MULT( ptr, oldcnt, \ + newcnt, itmsz ) ) + +#define FT_FREE( ptr ) FT_MEM_FREE( ptr ) + +#define FT_NEW( ptr ) FT_MEM_SET_ERROR( FT_MEM_NEW( ptr ) ) + +#define FT_NEW_ARRAY( ptr, count ) \ + FT_MEM_SET_ERROR( FT_MEM_NEW_ARRAY( ptr, count ) ) + +#define FT_RENEW_ARRAY( ptr, curcnt, newcnt ) \ + FT_MEM_SET_ERROR( FT_MEM_RENEW_ARRAY( ptr, curcnt, newcnt ) ) + +#define FT_QNEW( ptr ) \ + FT_MEM_SET_ERROR( FT_MEM_QNEW( ptr ) ) + +#define FT_QNEW_ARRAY( ptr, count ) \ + FT_MEM_SET_ERROR( FT_MEM_NEW_ARRAY( ptr, count ) ) + +#define FT_QRENEW_ARRAY( ptr, curcnt, newcnt ) \ + FT_MEM_SET_ERROR( FT_MEM_RENEW_ARRAY( ptr, curcnt, newcnt ) ) + + +#ifdef FT_CONFIG_OPTION_OLD_INTERNALS + + FT_BASE( FT_Error ) + FT_Alloc( FT_Memory memory, + FT_Long size, + void* *P ); + + FT_BASE( FT_Error ) + FT_QAlloc( FT_Memory memory, + FT_Long size, + void* *p ); + + FT_BASE( FT_Error ) + FT_Realloc( FT_Memory memory, + FT_Long current, + FT_Long size, + void* *P ); + + FT_BASE( FT_Error ) + FT_QRealloc( FT_Memory memory, + FT_Long current, + FT_Long size, + void* *p ); + + FT_BASE( void ) + FT_Free( FT_Memory memory, + void* *P ); + +#endif /* FT_CONFIG_OPTION_OLD_INTERNALS */ + + + FT_BASE( FT_Pointer ) + ft_mem_strdup( FT_Memory memory, + const char* str, + FT_Error *p_error ); + + FT_BASE( FT_Pointer ) + ft_mem_dup( FT_Memory memory, + const void* address, + FT_ULong size, + FT_Error *p_error ); + +#define FT_MEM_STRDUP( dst, str ) \ + (dst) = (char*)ft_mem_strdup( memory, (const char*)(str), &error ) + +#define FT_STRDUP( dst, str ) \ + FT_MEM_SET_ERROR( FT_MEM_STRDUP( dst, str ) ) + +#define FT_MEM_DUP( dst, address, size ) \ + (dst) = ft_mem_dup( memory, (address), (FT_ULong)(size), &error ) + +#define FT_DUP( dst, address, size ) \ + FT_MEM_SET_ERROR( FT_MEM_DUP( dst, address, size ) ) + + + /* Return >= 1 if a truncation occurs. */ + /* Return 0 if the source string fits the buffer. */ + /* This is *not* the same as strlcpy(). */ + FT_BASE( FT_Int ) + ft_mem_strcpyn( char* dst, + const char* src, + FT_ULong size ); + +#define FT_STRCPYN( dst, src, size ) \ + ft_mem_strcpyn( (char*)dst, (const char*)(src), (FT_ULong)(size) ) + + /* */ + + +FT_END_HEADER + +#endif /* __FTMEMORY_H__ */ + + +/* END */ diff --git a/Lib/Include/freetype/internal/ftobjs.h b/Lib/Include/freetype/internal/ftobjs.h new file mode 100644 index 0000000..670eb78 --- /dev/null +++ b/Lib/Include/freetype/internal/ftobjs.h @@ -0,0 +1,1428 @@ +/***************************************************************************/ +/* */ +/* ftobjs.h */ +/* */ +/* The FreeType private base classes (specification). */ +/* */ +/* Copyright 1996-2001, 2002, 2003, 2004, 2005, 2006, 2008, 2010 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + + /*************************************************************************/ + /* */ + /* This file contains the definition of all internal FreeType classes. */ + /* */ + /*************************************************************************/ + + +#ifndef __FTOBJS_H__ +#define __FTOBJS_H__ + +#include <ft2build.h> +#include FT_RENDER_H +#include FT_SIZES_H +#include FT_LCD_FILTER_H +#include FT_INTERNAL_MEMORY_H +#include FT_INTERNAL_GLYPH_LOADER_H +#include FT_INTERNAL_DRIVER_H +#include FT_INTERNAL_AUTOHINT_H +#include FT_INTERNAL_SERVICE_H +#include FT_INTERNAL_PIC_H + +#ifdef FT_CONFIG_OPTION_INCREMENTAL +#include FT_INCREMENTAL_H +#endif + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /* */ + /* Some generic definitions. */ + /* */ +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +#ifndef NULL +#define NULL (void*)0 +#endif + + + /*************************************************************************/ + /* */ + /* The min and max functions missing in C. As usual, be careful not to */ + /* write things like FT_MIN( a++, b++ ) to avoid side effects. */ + /* */ +#define FT_MIN( a, b ) ( (a) < (b) ? (a) : (b) ) +#define FT_MAX( a, b ) ( (a) > (b) ? (a) : (b) ) + +#define FT_ABS( a ) ( (a) < 0 ? -(a) : (a) ) + + +#define FT_PAD_FLOOR( x, n ) ( (x) & ~((n)-1) ) +#define FT_PAD_ROUND( x, n ) FT_PAD_FLOOR( (x) + ((n)/2), n ) +#define FT_PAD_CEIL( x, n ) FT_PAD_FLOOR( (x) + ((n)-1), n ) + +#define FT_PIX_FLOOR( x ) ( (x) & ~63 ) +#define FT_PIX_ROUND( x ) FT_PIX_FLOOR( (x) + 32 ) +#define FT_PIX_CEIL( x ) FT_PIX_FLOOR( (x) + 63 ) + + + /* + * Return the highest power of 2 that is <= value; this correspond to + * the highest bit in a given 32-bit value. + */ + FT_BASE( FT_UInt32 ) + ft_highpow2( FT_UInt32 value ); + + + /* + * character classification functions -- since these are used to parse + * font files, we must not use those in <ctypes.h> which are + * locale-dependent + */ +#define ft_isdigit( x ) ( ( (unsigned)(x) - '0' ) < 10U ) + +#define ft_isxdigit( x ) ( ( (unsigned)(x) - '0' ) < 10U || \ + ( (unsigned)(x) - 'a' ) < 6U || \ + ( (unsigned)(x) - 'A' ) < 6U ) + + /* the next two macros assume ASCII representation */ +#define ft_isupper( x ) ( ( (unsigned)(x) - 'A' ) < 26U ) +#define ft_islower( x ) ( ( (unsigned)(x) - 'a' ) < 26U ) + +#define ft_isalpha( x ) ( ft_isupper( x ) || ft_islower( x ) ) +#define ft_isalnum( x ) ( ft_isdigit( x ) || ft_isalpha( x ) ) + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** ****/ + /**** C H A R M A P S ****/ + /**** ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + /* handle to internal charmap object */ + typedef struct FT_CMapRec_* FT_CMap; + + /* handle to charmap class structure */ + typedef const struct FT_CMap_ClassRec_* FT_CMap_Class; + + /* internal charmap object structure */ + typedef struct FT_CMapRec_ + { + FT_CharMapRec charmap; + FT_CMap_Class clazz; + + } FT_CMapRec; + + /* typecase any pointer to a charmap handle */ +#define FT_CMAP( x ) ((FT_CMap)( x )) + + /* obvious macros */ +#define FT_CMAP_PLATFORM_ID( x ) FT_CMAP( x )->charmap.platform_id +#define FT_CMAP_ENCODING_ID( x ) FT_CMAP( x )->charmap.encoding_id +#define FT_CMAP_ENCODING( x ) FT_CMAP( x )->charmap.encoding +#define FT_CMAP_FACE( x ) FT_CMAP( x )->charmap.face + + + /* class method definitions */ + typedef FT_Error + (*FT_CMap_InitFunc)( FT_CMap cmap, + FT_Pointer init_data ); + + typedef void + (*FT_CMap_DoneFunc)( FT_CMap cmap ); + + typedef FT_UInt + (*FT_CMap_CharIndexFunc)( FT_CMap cmap, + FT_UInt32 char_code ); + + typedef FT_UInt + (*FT_CMap_CharNextFunc)( FT_CMap cmap, + FT_UInt32 *achar_code ); + + typedef FT_UInt + (*FT_CMap_CharVarIndexFunc)( FT_CMap cmap, + FT_CMap unicode_cmap, + FT_UInt32 char_code, + FT_UInt32 variant_selector ); + + typedef FT_Bool + (*FT_CMap_CharVarIsDefaultFunc)( FT_CMap cmap, + FT_UInt32 char_code, + FT_UInt32 variant_selector ); + + typedef FT_UInt32 * + (*FT_CMap_VariantListFunc)( FT_CMap cmap, + FT_Memory mem ); + + typedef FT_UInt32 * + (*FT_CMap_CharVariantListFunc)( FT_CMap cmap, + FT_Memory mem, + FT_UInt32 char_code ); + + typedef FT_UInt32 * + (*FT_CMap_VariantCharListFunc)( FT_CMap cmap, + FT_Memory mem, + FT_UInt32 variant_selector ); + + + typedef struct FT_CMap_ClassRec_ + { + FT_ULong size; + FT_CMap_InitFunc init; + FT_CMap_DoneFunc done; + FT_CMap_CharIndexFunc char_index; + FT_CMap_CharNextFunc char_next; + + /* Subsequent entries are special ones for format 14 -- the variant */ + /* selector subtable which behaves like no other */ + + FT_CMap_CharVarIndexFunc char_var_index; + FT_CMap_CharVarIsDefaultFunc char_var_default; + FT_CMap_VariantListFunc variant_list; + FT_CMap_CharVariantListFunc charvariant_list; + FT_CMap_VariantCharListFunc variantchar_list; + + } FT_CMap_ClassRec; + +#ifndef FT_CONFIG_OPTION_PIC + +#define FT_DECLARE_CMAP_CLASS(class_) \ + FT_CALLBACK_TABLE const FT_CMap_ClassRec class_; + +#define FT_DEFINE_CMAP_CLASS(class_, size_, init_, done_, char_index_, \ + char_next_, char_var_index_, char_var_default_, variant_list_, \ + charvariant_list_, variantchar_list_) \ + FT_CALLBACK_TABLE_DEF \ + const FT_CMap_ClassRec class_ = \ + { \ + size_, init_, done_, char_index_, char_next_, char_var_index_, \ + char_var_default_, variant_list_, charvariant_list_, variantchar_list_ \ + }; +#else /* FT_CONFIG_OPTION_PIC */ + +#define FT_DECLARE_CMAP_CLASS(class_) \ + void FT_Init_Class_##class_( FT_Library library, FT_CMap_ClassRec* clazz); + +#define FT_DEFINE_CMAP_CLASS(class_, size_, init_, done_, char_index_, \ + char_next_, char_var_index_, char_var_default_, variant_list_, \ + charvariant_list_, variantchar_list_) \ + void \ + FT_Init_Class_##class_( FT_Library library, \ + FT_CMap_ClassRec* clazz) \ + { \ + FT_UNUSED(library); \ + clazz->size = size_; \ + clazz->init = init_; \ + clazz->done = done_; \ + clazz->char_index = char_index_; \ + clazz->char_next = char_next_; \ + clazz->char_var_index = char_var_index_; \ + clazz->char_var_default = char_var_default_; \ + clazz->variant_list = variant_list_; \ + clazz->charvariant_list = charvariant_list_; \ + clazz->variantchar_list = variantchar_list_; \ + } +#endif /* FT_CONFIG_OPTION_PIC */ + + /* create a new charmap and add it to charmap->face */ + FT_BASE( FT_Error ) + FT_CMap_New( FT_CMap_Class clazz, + FT_Pointer init_data, + FT_CharMap charmap, + FT_CMap *acmap ); + + /* destroy a charmap and remove it from face's list */ + FT_BASE( void ) + FT_CMap_Done( FT_CMap cmap ); + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_Face_InternalRec */ + /* */ + /* <Description> */ + /* This structure contains the internal fields of each FT_Face */ + /* object. These fields may change between different releases of */ + /* FreeType. */ + /* */ + /* <Fields> */ + /* max_points :: */ + /* The maximal number of points used to store the vectorial outline */ + /* of any glyph in this face. If this value cannot be known in */ + /* advance, or if the face isn't scalable, this should be set to 0. */ + /* Only relevant for scalable formats. */ + /* */ + /* max_contours :: */ + /* The maximal number of contours used to store the vectorial */ + /* outline of any glyph in this face. If this value cannot be */ + /* known in advance, or if the face isn't scalable, this should be */ + /* set to 0. Only relevant for scalable formats. */ + /* */ + /* transform_matrix :: */ + /* A 2x2 matrix of 16.16 coefficients used to transform glyph */ + /* outlines after they are loaded from the font. Only used by the */ + /* convenience functions. */ + /* */ + /* transform_delta :: */ + /* A translation vector used to transform glyph outlines after they */ + /* are loaded from the font. Only used by the convenience */ + /* functions. */ + /* */ + /* transform_flags :: */ + /* Some flags used to classify the transform. Only used by the */ + /* convenience functions. */ + /* */ + /* services :: */ + /* A cache for frequently used services. It should be only */ + /* accessed with the macro `FT_FACE_LOOKUP_SERVICE'. */ + /* */ + /* incremental_interface :: */ + /* If non-null, the interface through which glyph data and metrics */ + /* are loaded incrementally for faces that do not provide all of */ + /* this data when first opened. This field exists only if */ + /* @FT_CONFIG_OPTION_INCREMENTAL is defined. */ + /* */ + /* ignore_unpatented_hinter :: */ + /* This boolean flag instructs the glyph loader to ignore the */ + /* native font hinter, if one is found. This is exclusively used */ + /* in the case when the unpatented hinter is compiled within the */ + /* library. */ + /* */ + /* refcount :: */ + /* A counter initialized to~1 at the time an @FT_Face structure is */ + /* created. @FT_Reference_Face increments this counter, and */ + /* @FT_Done_Face only destroys a face if the counter is~1, */ + /* otherwise it simply decrements it. */ + /* */ + typedef struct FT_Face_InternalRec_ + { +#ifdef FT_CONFIG_OPTION_OLD_INTERNALS + FT_UShort reserved1; + FT_Short reserved2; +#endif + FT_Matrix transform_matrix; + FT_Vector transform_delta; + FT_Int transform_flags; + + FT_ServiceCacheRec services; + +#ifdef FT_CONFIG_OPTION_INCREMENTAL + FT_Incremental_InterfaceRec* incremental_interface; +#endif + + FT_Bool ignore_unpatented_hinter; + FT_UInt refcount; + + } FT_Face_InternalRec; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_Slot_InternalRec */ + /* */ + /* <Description> */ + /* This structure contains the internal fields of each FT_GlyphSlot */ + /* object. These fields may change between different releases of */ + /* FreeType. */ + /* */ + /* <Fields> */ + /* loader :: The glyph loader object used to load outlines */ + /* into the glyph slot. */ + /* */ + /* flags :: Possible values are zero or */ + /* FT_GLYPH_OWN_BITMAP. The latter indicates */ + /* that the FT_GlyphSlot structure owns the */ + /* bitmap buffer. */ + /* */ + /* glyph_transformed :: Boolean. Set to TRUE when the loaded glyph */ + /* must be transformed through a specific */ + /* font transformation. This is _not_ the same */ + /* as the face transform set through */ + /* FT_Set_Transform(). */ + /* */ + /* glyph_matrix :: The 2x2 matrix corresponding to the glyph */ + /* transformation, if necessary. */ + /* */ + /* glyph_delta :: The 2d translation vector corresponding to */ + /* the glyph transformation, if necessary. */ + /* */ + /* glyph_hints :: Format-specific glyph hints management. */ + /* */ + +#define FT_GLYPH_OWN_BITMAP 0x1 + + typedef struct FT_Slot_InternalRec_ + { + FT_GlyphLoader loader; + FT_UInt flags; + FT_Bool glyph_transformed; + FT_Matrix glyph_matrix; + FT_Vector glyph_delta; + void* glyph_hints; + + } FT_GlyphSlot_InternalRec; + + +#if 0 + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_Size_InternalRec */ + /* */ + /* <Description> */ + /* This structure contains the internal fields of each FT_Size */ + /* object. Currently, it's empty. */ + /* */ + /*************************************************************************/ + + typedef struct FT_Size_InternalRec_ + { + /* empty */ + + } FT_Size_InternalRec; + +#endif + + + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** ****/ + /**** M O D U L E S ****/ + /**** ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_ModuleRec */ + /* */ + /* <Description> */ + /* A module object instance. */ + /* */ + /* <Fields> */ + /* clazz :: A pointer to the module's class. */ + /* */ + /* library :: A handle to the parent library object. */ + /* */ + /* memory :: A handle to the memory manager. */ + /* */ + /* generic :: A generic structure for user-level extensibility (?). */ + /* */ + typedef struct FT_ModuleRec_ + { + FT_Module_Class* clazz; + FT_Library library; + FT_Memory memory; + FT_Generic generic; + + } FT_ModuleRec; + + + /* typecast an object to a FT_Module */ +#define FT_MODULE( x ) ((FT_Module)( x )) +#define FT_MODULE_CLASS( x ) FT_MODULE( x )->clazz +#define FT_MODULE_LIBRARY( x ) FT_MODULE( x )->library +#define FT_MODULE_MEMORY( x ) FT_MODULE( x )->memory + + +#define FT_MODULE_IS_DRIVER( x ) ( FT_MODULE_CLASS( x )->module_flags & \ + FT_MODULE_FONT_DRIVER ) + +#define FT_MODULE_IS_RENDERER( x ) ( FT_MODULE_CLASS( x )->module_flags & \ + FT_MODULE_RENDERER ) + +#define FT_MODULE_IS_HINTER( x ) ( FT_MODULE_CLASS( x )->module_flags & \ + FT_MODULE_HINTER ) + +#define FT_MODULE_IS_STYLER( x ) ( FT_MODULE_CLASS( x )->module_flags & \ + FT_MODULE_STYLER ) + +#define FT_DRIVER_IS_SCALABLE( x ) ( FT_MODULE_CLASS( x )->module_flags & \ + FT_MODULE_DRIVER_SCALABLE ) + +#define FT_DRIVER_USES_OUTLINES( x ) !( FT_MODULE_CLASS( x )->module_flags & \ + FT_MODULE_DRIVER_NO_OUTLINES ) + +#define FT_DRIVER_HAS_HINTER( x ) ( FT_MODULE_CLASS( x )->module_flags & \ + FT_MODULE_DRIVER_HAS_HINTER ) + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Get_Module_Interface */ + /* */ + /* <Description> */ + /* Finds a module and returns its specific interface as a typeless */ + /* pointer. */ + /* */ + /* <Input> */ + /* library :: A handle to the library object. */ + /* */ + /* module_name :: The module's name (as an ASCII string). */ + /* */ + /* <Return> */ + /* A module-specific interface if available, 0 otherwise. */ + /* */ + /* <Note> */ + /* You should better be familiar with FreeType internals to know */ + /* which module to look for, and what its interface is :-) */ + /* */ + FT_BASE( const void* ) + FT_Get_Module_Interface( FT_Library library, + const char* mod_name ); + + FT_BASE( FT_Pointer ) + ft_module_get_service( FT_Module module, + const char* service_id ); + + /* */ + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** ****/ + /**** FACE, SIZE & GLYPH SLOT OBJECTS ****/ + /**** ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + /* a few macros used to perform easy typecasts with minimal brain damage */ + +#define FT_FACE( x ) ((FT_Face)(x)) +#define FT_SIZE( x ) ((FT_Size)(x)) +#define FT_SLOT( x ) ((FT_GlyphSlot)(x)) + +#define FT_FACE_DRIVER( x ) FT_FACE( x )->driver +#define FT_FACE_LIBRARY( x ) FT_FACE_DRIVER( x )->root.library +#define FT_FACE_MEMORY( x ) FT_FACE( x )->memory +#define FT_FACE_STREAM( x ) FT_FACE( x )->stream + +#define FT_SIZE_FACE( x ) FT_SIZE( x )->face +#define FT_SLOT_FACE( x ) FT_SLOT( x )->face + +#define FT_FACE_SLOT( x ) FT_FACE( x )->glyph +#define FT_FACE_SIZE( x ) FT_FACE( x )->size + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_New_GlyphSlot */ + /* */ + /* <Description> */ + /* It is sometimes useful to have more than one glyph slot for a */ + /* given face object. This function is used to create additional */ + /* slots. All of them are automatically discarded when the face is */ + /* destroyed. */ + /* */ + /* <Input> */ + /* face :: A handle to a parent face object. */ + /* */ + /* <Output> */ + /* aslot :: A handle to a new glyph slot object. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + FT_BASE( FT_Error ) + FT_New_GlyphSlot( FT_Face face, + FT_GlyphSlot *aslot ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Done_GlyphSlot */ + /* */ + /* <Description> */ + /* Destroys a given glyph slot. Remember however that all slots are */ + /* automatically destroyed with its parent. Using this function is */ + /* not always mandatory. */ + /* */ + /* <Input> */ + /* slot :: A handle to a target glyph slot. */ + /* */ + FT_BASE( void ) + FT_Done_GlyphSlot( FT_GlyphSlot slot ); + + /* */ + +#define FT_REQUEST_WIDTH( req ) \ + ( (req)->horiResolution \ + ? (FT_Pos)( (req)->width * (req)->horiResolution + 36 ) / 72 \ + : (req)->width ) + +#define FT_REQUEST_HEIGHT( req ) \ + ( (req)->vertResolution \ + ? (FT_Pos)( (req)->height * (req)->vertResolution + 36 ) / 72 \ + : (req)->height ) + + + /* Set the metrics according to a bitmap strike. */ + FT_BASE( void ) + FT_Select_Metrics( FT_Face face, + FT_ULong strike_index ); + + + /* Set the metrics according to a size request. */ + FT_BASE( void ) + FT_Request_Metrics( FT_Face face, + FT_Size_Request req ); + + + /* Match a size request against `available_sizes'. */ + FT_BASE( FT_Error ) + FT_Match_Size( FT_Face face, + FT_Size_Request req, + FT_Bool ignore_width, + FT_ULong* size_index ); + + + /* Use the horizontal metrics to synthesize the vertical metrics. */ + /* If `advance' is zero, it is also synthesized. */ + FT_BASE( void ) + ft_synthesize_vertical_metrics( FT_Glyph_Metrics* metrics, + FT_Pos advance ); + + + /* Free the bitmap of a given glyphslot when needed (i.e., only when it */ + /* was allocated with ft_glyphslot_alloc_bitmap). */ + FT_BASE( void ) + ft_glyphslot_free_bitmap( FT_GlyphSlot slot ); + + + /* Allocate a new bitmap buffer in a glyph slot. */ + FT_BASE( FT_Error ) + ft_glyphslot_alloc_bitmap( FT_GlyphSlot slot, + FT_ULong size ); + + + /* Set the bitmap buffer in a glyph slot to a given pointer. The buffer */ + /* will not be freed by a later call to ft_glyphslot_free_bitmap. */ + FT_BASE( void ) + ft_glyphslot_set_bitmap( FT_GlyphSlot slot, + FT_Byte* buffer ); + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** ****/ + /**** R E N D E R E R S ****/ + /**** ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + +#define FT_RENDERER( x ) ((FT_Renderer)( x )) +#define FT_GLYPH( x ) ((FT_Glyph)( x )) +#define FT_BITMAP_GLYPH( x ) ((FT_BitmapGlyph)( x )) +#define FT_OUTLINE_GLYPH( x ) ((FT_OutlineGlyph)( x )) + + + typedef struct FT_RendererRec_ + { + FT_ModuleRec root; + FT_Renderer_Class* clazz; + FT_Glyph_Format glyph_format; + FT_Glyph_Class glyph_class; + + FT_Raster raster; + FT_Raster_Render_Func raster_render; + FT_Renderer_RenderFunc render; + + } FT_RendererRec; + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** ****/ + /**** F O N T D R I V E R S ****/ + /**** ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + /* typecast a module into a driver easily */ +#define FT_DRIVER( x ) ((FT_Driver)(x)) + + /* typecast a module as a driver, and get its driver class */ +#define FT_DRIVER_CLASS( x ) FT_DRIVER( x )->clazz + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_DriverRec */ + /* */ + /* <Description> */ + /* The root font driver class. A font driver is responsible for */ + /* managing and loading font files of a given format. */ + /* */ + /* <Fields> */ + /* root :: Contains the fields of the root module class. */ + /* */ + /* clazz :: A pointer to the font driver's class. Note that */ + /* this is NOT root.clazz. `class' wasn't used */ + /* as it is a reserved word in C++. */ + /* */ + /* faces_list :: The list of faces currently opened by this */ + /* driver. */ + /* */ + /* extensions :: A typeless pointer to the driver's extensions */ + /* registry, if they are supported through the */ + /* configuration macro FT_CONFIG_OPTION_EXTENSIONS. */ + /* */ + /* glyph_loader :: The glyph loader for all faces managed by this */ + /* driver. This object isn't defined for unscalable */ + /* formats. */ + /* */ + typedef struct FT_DriverRec_ + { + FT_ModuleRec root; + FT_Driver_Class clazz; + + FT_ListRec faces_list; + void* extensions; + + FT_GlyphLoader glyph_loader; + + } FT_DriverRec; + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** ****/ + /**** L I B R A R I E S ****/ + /**** ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + /* This hook is used by the TrueType debugger. It must be set to an */ + /* alternate truetype bytecode interpreter function. */ +#define FT_DEBUG_HOOK_TRUETYPE 0 + + + /* Set this debug hook to a non-null pointer to force unpatented hinting */ + /* for all faces when both TT_USE_BYTECODE_INTERPRETER and */ + /* TT_CONFIG_OPTION_UNPATENTED_HINTING are defined. This is only used */ + /* during debugging. */ +#define FT_DEBUG_HOOK_UNPATENTED_HINTING 1 + + + typedef void (*FT_Bitmap_LcdFilterFunc)( FT_Bitmap* bitmap, + FT_Render_Mode render_mode, + FT_Library library ); + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* FT_LibraryRec */ + /* */ + /* <Description> */ + /* The FreeType library class. This is the root of all FreeType */ + /* data. Use FT_New_Library() to create a library object, and */ + /* FT_Done_Library() to discard it and all child objects. */ + /* */ + /* <Fields> */ + /* memory :: The library's memory object. Manages memory */ + /* allocation. */ + /* */ + /* generic :: Client data variable. Used to extend the */ + /* Library class by higher levels and clients. */ + /* */ + /* version_major :: The major version number of the library. */ + /* */ + /* version_minor :: The minor version number of the library. */ + /* */ + /* version_patch :: The current patch level of the library. */ + /* */ + /* num_modules :: The number of modules currently registered */ + /* within this library. This is set to 0 for new */ + /* libraries. New modules are added through the */ + /* FT_Add_Module() API function. */ + /* */ + /* modules :: A table used to store handles to the currently */ + /* registered modules. Note that each font driver */ + /* contains a list of its opened faces. */ + /* */ + /* renderers :: The list of renderers currently registered */ + /* within the library. */ + /* */ + /* cur_renderer :: The current outline renderer. This is a */ + /* shortcut used to avoid parsing the list on */ + /* each call to FT_Outline_Render(). It is a */ + /* handle to the current renderer for the */ + /* FT_GLYPH_FORMAT_OUTLINE format. */ + /* */ + /* auto_hinter :: XXX */ + /* */ + /* raster_pool :: The raster object's render pool. This can */ + /* ideally be changed dynamically at run-time. */ + /* */ + /* raster_pool_size :: The size of the render pool in bytes. */ + /* */ + /* debug_hooks :: XXX */ + /* */ + /* lcd_filter :: If subpixel rendering is activated, the */ + /* selected LCD filter mode. */ + /* */ + /* lcd_extra :: If subpixel rendering is activated, the number */ + /* of extra pixels needed for the LCD filter. */ + /* */ + /* lcd_weights :: If subpixel rendering is activated, the LCD */ + /* filter weights, if any. */ + /* */ + /* lcd_filter_func :: If subpixel rendering is activated, the LCD */ + /* filtering callback function. */ + /* */ + /* pic_container :: Contains global structs and tables, instead */ + /* of defining them globallly. */ + /* */ + /* refcount :: A counter initialized to~1 at the time an */ + /* @FT_Library structure is created. */ + /* @FT_Reference_Library increments this counter, */ + /* and @FT_Done_Library only destroys a library */ + /* if the counter is~1, otherwise it simply */ + /* decrements it. */ + /* */ + typedef struct FT_LibraryRec_ + { + FT_Memory memory; /* library's memory manager */ + + FT_Generic generic; + + FT_Int version_major; + FT_Int version_minor; + FT_Int version_patch; + + FT_UInt num_modules; + FT_Module modules[FT_MAX_MODULES]; /* module objects */ + + FT_ListRec renderers; /* list of renderers */ + FT_Renderer cur_renderer; /* current outline renderer */ + FT_Module auto_hinter; + + FT_Byte* raster_pool; /* scan-line conversion */ + /* render pool */ + FT_ULong raster_pool_size; /* size of render pool in bytes */ + + FT_DebugHook_Func debug_hooks[4]; + +#ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING + FT_LcdFilter lcd_filter; + FT_Int lcd_extra; /* number of extra pixels */ + FT_Byte lcd_weights[7]; /* filter weights, if any */ + FT_Bitmap_LcdFilterFunc lcd_filter_func; /* filtering callback */ +#endif + +#ifdef FT_CONFIG_OPTION_PIC + FT_PIC_Container pic_container; +#endif + + FT_UInt refcount; + + } FT_LibraryRec; + + + FT_BASE( FT_Renderer ) + FT_Lookup_Renderer( FT_Library library, + FT_Glyph_Format format, + FT_ListNode* node ); + + FT_BASE( FT_Error ) + FT_Render_Glyph_Internal( FT_Library library, + FT_GlyphSlot slot, + FT_Render_Mode render_mode ); + + typedef const char* + (*FT_Face_GetPostscriptNameFunc)( FT_Face face ); + + typedef FT_Error + (*FT_Face_GetGlyphNameFunc)( FT_Face face, + FT_UInt glyph_index, + FT_Pointer buffer, + FT_UInt buffer_max ); + + typedef FT_UInt + (*FT_Face_GetGlyphNameIndexFunc)( FT_Face face, + FT_String* glyph_name ); + + +#ifndef FT_CONFIG_OPTION_NO_DEFAULT_SYSTEM + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_New_Memory */ + /* */ + /* <Description> */ + /* Creates a new memory object. */ + /* */ + /* <Return> */ + /* A pointer to the new memory object. 0 in case of error. */ + /* */ + FT_BASE( FT_Memory ) + FT_New_Memory( void ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Done_Memory */ + /* */ + /* <Description> */ + /* Discards memory manager. */ + /* */ + /* <Input> */ + /* memory :: A handle to the memory manager. */ + /* */ + FT_BASE( void ) + FT_Done_Memory( FT_Memory memory ); + +#endif /* !FT_CONFIG_OPTION_NO_DEFAULT_SYSTEM */ + + + /* Define default raster's interface. The default raster is located in */ + /* `src/base/ftraster.c'. */ + /* */ + /* Client applications can register new rasters through the */ + /* FT_Set_Raster() API. */ + +#ifndef FT_NO_DEFAULT_RASTER + FT_EXPORT_VAR( FT_Raster_Funcs ) ft_default_raster; +#endif + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** ****/ + /**** PIC-Support Macros for ftimage.h ****/ + /**** ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* <Macro> */ + /* FT_DEFINE_OUTLINE_FUNCS */ + /* */ + /* <Description> */ + /* Used to initialize an instance of FT_Outline_Funcs struct. */ + /* When FT_CONFIG_OPTION_PIC is defined an init funtion will need to */ + /* called with a pre-allocated stracture to be filled. */ + /* When FT_CONFIG_OPTION_PIC is not defined the struct will be */ + /* allocated in the global scope (or the scope where the macro */ + /* is used). */ + /* */ +#ifndef FT_CONFIG_OPTION_PIC + +#define FT_DEFINE_OUTLINE_FUNCS(class_, move_to_, line_to_, conic_to_, \ + cubic_to_, shift_, delta_) \ + static const FT_Outline_Funcs class_ = \ + { \ + move_to_, line_to_, conic_to_, cubic_to_, shift_, delta_ \ + }; + +#else /* FT_CONFIG_OPTION_PIC */ + +#define FT_DEFINE_OUTLINE_FUNCS(class_, move_to_, line_to_, conic_to_, \ + cubic_to_, shift_, delta_) \ + static FT_Error \ + Init_Class_##class_( FT_Outline_Funcs* clazz ) \ + { \ + clazz->move_to = move_to_; \ + clazz->line_to = line_to_; \ + clazz->conic_to = conic_to_; \ + clazz->cubic_to = cubic_to_; \ + clazz->shift = shift_; \ + clazz->delta = delta_; \ + return FT_Err_Ok; \ + } + +#endif /* FT_CONFIG_OPTION_PIC */ + + /*************************************************************************/ + /* */ + /* <Macro> */ + /* FT_DEFINE_RASTER_FUNCS */ + /* */ + /* <Description> */ + /* Used to initialize an instance of FT_Raster_Funcs struct. */ + /* When FT_CONFIG_OPTION_PIC is defined an init funtion will need to */ + /* called with a pre-allocated stracture to be filled. */ + /* When FT_CONFIG_OPTION_PIC is not defined the struct will be */ + /* allocated in the global scope (or the scope where the macro */ + /* is used). */ + /* */ +#ifndef FT_CONFIG_OPTION_PIC + +#define FT_DEFINE_RASTER_FUNCS(class_, glyph_format_, raster_new_, \ + raster_reset_, raster_set_mode_, \ + raster_render_, raster_done_) \ + const FT_Raster_Funcs class_ = \ + { \ + glyph_format_, raster_new_, raster_reset_, \ + raster_set_mode_, raster_render_, raster_done_ \ + }; + +#else /* FT_CONFIG_OPTION_PIC */ + +#define FT_DEFINE_RASTER_FUNCS(class_, glyph_format_, raster_new_, \ + raster_reset_, raster_set_mode_, raster_render_, raster_done_) \ + void \ + FT_Init_Class_##class_( FT_Raster_Funcs* clazz ) \ + { \ + clazz->glyph_format = glyph_format_; \ + clazz->raster_new = raster_new_; \ + clazz->raster_reset = raster_reset_; \ + clazz->raster_set_mode = raster_set_mode_; \ + clazz->raster_render = raster_render_; \ + clazz->raster_done = raster_done_; \ + } + +#endif /* FT_CONFIG_OPTION_PIC */ + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** ****/ + /**** PIC-Support Macros for ftrender.h ****/ + /**** ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + + /*************************************************************************/ + /* */ + /* <Macro> */ + /* FT_DEFINE_GLYPH */ + /* */ + /* <Description> */ + /* Used to initialize an instance of FT_Glyph_Class struct. */ + /* When FT_CONFIG_OPTION_PIC is defined an init funtion will need to */ + /* called with a pre-allocated stracture to be filled. */ + /* When FT_CONFIG_OPTION_PIC is not defined the struct will be */ + /* allocated in the global scope (or the scope where the macro */ + /* is used). */ + /* */ +#ifndef FT_CONFIG_OPTION_PIC + +#define FT_DEFINE_GLYPH(class_, size_, format_, init_, done_, copy_, \ + transform_, bbox_, prepare_) \ + FT_CALLBACK_TABLE_DEF \ + const FT_Glyph_Class class_ = \ + { \ + size_, format_, init_, done_, copy_, transform_, bbox_, prepare_ \ + }; + +#else /* FT_CONFIG_OPTION_PIC */ + +#define FT_DEFINE_GLYPH(class_, size_, format_, init_, done_, copy_, \ + transform_, bbox_, prepare_) \ + void \ + FT_Init_Class_##class_( FT_Glyph_Class* clazz ) \ + { \ + clazz->glyph_size = size_; \ + clazz->glyph_format = format_; \ + clazz->glyph_init = init_; \ + clazz->glyph_done = done_; \ + clazz->glyph_copy = copy_; \ + clazz->glyph_transform = transform_; \ + clazz->glyph_bbox = bbox_; \ + clazz->glyph_prepare = prepare_; \ + } + +#endif /* FT_CONFIG_OPTION_PIC */ + + /*************************************************************************/ + /* */ + /* <Macro> */ + /* FT_DECLARE_RENDERER */ + /* */ + /* <Description> */ + /* Used to create a forward declaration of a */ + /* FT_Renderer_Class stract instance. */ + /* */ + /* <Macro> */ + /* FT_DEFINE_RENDERER */ + /* */ + /* <Description> */ + /* Used to initialize an instance of FT_Renderer_Class struct. */ + /* */ + /* When FT_CONFIG_OPTION_PIC is defined a Create funtion will need */ + /* to called with a pointer where the allocated stracture is returned.*/ + /* And when it is no longer needed a Destroy function needs */ + /* to be called to release that allocation. */ + /* fcinit.c (ft_create_default_module_classes) already contains */ + /* a mechanism to call these functions for the default modules */ + /* described in ftmodule.h */ + /* */ + /* Notice that the created Create and Destroy functions call */ + /* pic_init and pic_free function to allow you to manually allocate */ + /* and initialize any additional global data, like module specific */ + /* interface, and put them in the global pic container defined in */ + /* ftpic.h. if you don't need them just implement the functions as */ + /* empty to resolve the link error. */ + /* */ + /* When FT_CONFIG_OPTION_PIC is not defined the struct will be */ + /* allocated in the global scope (or the scope where the macro */ + /* is used). */ + /* */ +#ifndef FT_CONFIG_OPTION_PIC + +#define FT_DECLARE_RENDERER(class_) \ + FT_EXPORT_VAR( const FT_Renderer_Class ) class_; + +#define FT_DEFINE_RENDERER(class_, \ + flags_, size_, name_, version_, requires_, \ + interface_, init_, done_, get_interface_, \ + glyph_format_, render_glyph_, transform_glyph_, \ + get_glyph_cbox_, set_mode_, raster_class_ ) \ + FT_CALLBACK_TABLE_DEF \ + const FT_Renderer_Class class_ = \ + { \ + FT_DEFINE_ROOT_MODULE(flags_,size_,name_,version_,requires_, \ + interface_,init_,done_,get_interface_) \ + glyph_format_, \ + \ + render_glyph_, \ + transform_glyph_, \ + get_glyph_cbox_, \ + set_mode_, \ + \ + raster_class_ \ + }; + +#else /* FT_CONFIG_OPTION_PIC */ + +#define FT_DECLARE_RENDERER(class_) FT_DECLARE_MODULE(class_) + +#define FT_DEFINE_RENDERER(class_, \ + flags_, size_, name_, version_, requires_, \ + interface_, init_, done_, get_interface_, \ + glyph_format_, render_glyph_, transform_glyph_, \ + get_glyph_cbox_, set_mode_, raster_class_ ) \ + void class_##_pic_free( FT_Library library ); \ + FT_Error class_##_pic_init( FT_Library library ); \ + \ + void \ + FT_Destroy_Class_##class_( FT_Library library, \ + FT_Module_Class* clazz ) \ + { \ + FT_Renderer_Class* rclazz = (FT_Renderer_Class*)clazz; \ + FT_Memory memory = library->memory; \ + class_##_pic_free( library ); \ + if ( rclazz ) \ + FT_FREE( rclazz ); \ + } \ + \ + FT_Error \ + FT_Create_Class_##class_( FT_Library library, \ + FT_Module_Class** output_class ) \ + { \ + FT_Renderer_Class* clazz; \ + FT_Error error; \ + FT_Memory memory = library->memory; \ + \ + if ( FT_ALLOC( clazz, sizeof(*clazz) ) ) \ + return error; \ + \ + error = class_##_pic_init( library ); \ + if(error) \ + { \ + FT_FREE( clazz ); \ + return error; \ + } \ + \ + FT_DEFINE_ROOT_MODULE(flags_,size_,name_,version_,requires_, \ + interface_,init_,done_,get_interface_) \ + \ + clazz->glyph_format = glyph_format_; \ + \ + clazz->render_glyph = render_glyph_; \ + clazz->transform_glyph = transform_glyph_; \ + clazz->get_glyph_cbox = get_glyph_cbox_; \ + clazz->set_mode = set_mode_; \ + \ + clazz->raster_class = raster_class_; \ + \ + *output_class = (FT_Module_Class*)clazz; \ + return FT_Err_Ok; \ + } + + + +#endif /* FT_CONFIG_OPTION_PIC */ + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** ****/ + /**** PIC-Support Macros for ftmodapi.h ****/ + /**** ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + +#ifdef FT_CONFIG_OPTION_PIC + + /*************************************************************************/ + /* */ + /* <FuncType> */ + /* FT_Module_Creator */ + /* */ + /* <Description> */ + /* A function used to create (allocate) a new module class object. */ + /* The object's members are initialized, but the module itself is */ + /* not. */ + /* */ + /* <Input> */ + /* memory :: A handle to the memory manager. */ + /* output_class :: Initialized with the newly allocated class. */ + /* */ + typedef FT_Error + (*FT_Module_Creator)( FT_Memory memory, + FT_Module_Class** output_class ); + + /*************************************************************************/ + /* */ + /* <FuncType> */ + /* FT_Module_Destroyer */ + /* */ + /* <Description> */ + /* A function used to destroy (deallocate) a module class object. */ + /* */ + /* <Input> */ + /* memory :: A handle to the memory manager. */ + /* clazz :: Module class to destroy. */ + /* */ + typedef void + (*FT_Module_Destroyer)( FT_Memory memory, + FT_Module_Class* clazz ); + +#endif + + /*************************************************************************/ + /* */ + /* <Macro> */ + /* FT_DECLARE_MODULE */ + /* */ + /* <Description> */ + /* Used to create a forward declaration of a */ + /* FT_Module_Class stract instance. */ + /* */ + /* <Macro> */ + /* FT_DEFINE_MODULE */ + /* */ + /* <Description> */ + /* Used to initialize an instance of FT_Module_Class struct. */ + /* */ + /* When FT_CONFIG_OPTION_PIC is defined a Create funtion will need */ + /* to called with a pointer where the allocated stracture is returned.*/ + /* And when it is no longer needed a Destroy function needs */ + /* to be called to release that allocation. */ + /* fcinit.c (ft_create_default_module_classes) already contains */ + /* a mechanism to call these functions for the default modules */ + /* described in ftmodule.h */ + /* */ + /* Notice that the created Create and Destroy functions call */ + /* pic_init and pic_free function to allow you to manually allocate */ + /* and initialize any additional global data, like module specific */ + /* interface, and put them in the global pic container defined in */ + /* ftpic.h. if you don't need them just implement the functions as */ + /* empty to resolve the link error. */ + /* */ + /* When FT_CONFIG_OPTION_PIC is not defined the struct will be */ + /* allocated in the global scope (or the scope where the macro */ + /* is used). */ + /* */ + /* <Macro> */ + /* FT_DEFINE_ROOT_MODULE */ + /* */ + /* <Description> */ + /* Used to initialize an instance of FT_Module_Class struct inside */ + /* another stract that contains it or in a function that initializes */ + /* that containing stract */ + /* */ +#ifndef FT_CONFIG_OPTION_PIC + +#define FT_DECLARE_MODULE(class_) \ + FT_CALLBACK_TABLE \ + const FT_Module_Class class_; \ + +#define FT_DEFINE_ROOT_MODULE(flags_, size_, name_, version_, requires_, \ + interface_, init_, done_, get_interface_) \ + { \ + flags_, \ + size_, \ + \ + name_, \ + version_, \ + requires_, \ + \ + interface_, \ + \ + init_, \ + done_, \ + get_interface_, \ + }, + +#define FT_DEFINE_MODULE(class_, flags_, size_, name_, version_, requires_, \ + interface_, init_, done_, get_interface_) \ + FT_CALLBACK_TABLE_DEF \ + const FT_Module_Class class_ = \ + { \ + flags_, \ + size_, \ + \ + name_, \ + version_, \ + requires_, \ + \ + interface_, \ + \ + init_, \ + done_, \ + get_interface_, \ + }; + + +#else /* FT_CONFIG_OPTION_PIC */ + +#define FT_DECLARE_MODULE(class_) \ + FT_Error FT_Create_Class_##class_( FT_Library library, \ + FT_Module_Class** output_class ); \ + void FT_Destroy_Class_##class_( FT_Library library, \ + FT_Module_Class* clazz ); + +#define FT_DEFINE_ROOT_MODULE(flags_, size_, name_, version_, requires_, \ + interface_, init_, done_, get_interface_) \ + clazz->root.module_flags = flags_; \ + clazz->root.module_size = size_; \ + clazz->root.module_name = name_; \ + clazz->root.module_version = version_; \ + clazz->root.module_requires = requires_; \ + \ + clazz->root.module_interface = interface_; \ + \ + clazz->root.module_init = init_; \ + clazz->root.module_done = done_; \ + clazz->root.get_interface = get_interface_; + +#define FT_DEFINE_MODULE(class_, flags_, size_, name_, version_, requires_, \ + interface_, init_, done_, get_interface_) \ + void class_##_pic_free( FT_Library library ); \ + FT_Error class_##_pic_init( FT_Library library ); \ + \ + void \ + FT_Destroy_Class_##class_( FT_Library library, \ + FT_Module_Class* clazz ) \ + { \ + FT_Memory memory = library->memory; \ + class_##_pic_free( library ); \ + if ( clazz ) \ + FT_FREE( clazz ); \ + } \ + \ + FT_Error \ + FT_Create_Class_##class_( FT_Library library, \ + FT_Module_Class** output_class ) \ + { \ + FT_Memory memory = library->memory; \ + FT_Module_Class* clazz; \ + FT_Error error; \ + \ + if ( FT_ALLOC( clazz, sizeof(*clazz) ) ) \ + return error; \ + error = class_##_pic_init( library ); \ + if(error) \ + { \ + FT_FREE( clazz ); \ + return error; \ + } \ + \ + clazz->module_flags = flags_; \ + clazz->module_size = size_; \ + clazz->module_name = name_; \ + clazz->module_version = version_; \ + clazz->module_requires = requires_; \ + \ + clazz->module_interface = interface_; \ + \ + clazz->module_init = init_; \ + clazz->module_done = done_; \ + clazz->get_interface = get_interface_; \ + \ + *output_class = clazz; \ + return FT_Err_Ok; \ + } + +#endif /* FT_CONFIG_OPTION_PIC */ + + +FT_END_HEADER + +#endif /* __FTOBJS_H__ */ + + +/* END */ diff --git a/Lib/Include/freetype/internal/ftpic.h b/Lib/Include/freetype/internal/ftpic.h new file mode 100644 index 0000000..1b31957 --- /dev/null +++ b/Lib/Include/freetype/internal/ftpic.h @@ -0,0 +1,67 @@ +/***************************************************************************/ +/* */ +/* ftpic.h */ +/* */ +/* The FreeType position independent code services (declaration). */ +/* */ +/* Copyright 2009 by */ +/* Oran Agra and Mickey Gabel. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + /*************************************************************************/ + /* */ + /* Modules that ordinarily have const global data that need address */ + /* can instead define pointers here. */ + /* */ + /*************************************************************************/ + + +#ifndef __FTPIC_H__ +#define __FTPIC_H__ + + +FT_BEGIN_HEADER + +#ifdef FT_CONFIG_OPTION_PIC + + typedef struct FT_PIC_Container_ + { + /* pic containers for base */ + void* base; + /* pic containers for modules */ + void* autofit; + void* cff; + void* pshinter; + void* psnames; + void* raster; + void* sfnt; + void* smooth; + void* truetype; + } FT_PIC_Container; + + /* Initialize the various function tables, structs, etc. stored in the container. */ + FT_BASE( FT_Error ) + ft_pic_container_init( FT_Library library ); + + + /* Destroy the contents of the container. */ + FT_BASE( void ) + ft_pic_container_destroy( FT_Library library ); + +#endif /* FT_CONFIG_OPTION_PIC */ + + /* */ + +FT_END_HEADER + +#endif /* __FTPIC_H__ */ + + +/* END */ diff --git a/Lib/Include/freetype/internal/ftrfork.h b/Lib/Include/freetype/internal/ftrfork.h new file mode 100644 index 0000000..aa573c8 --- /dev/null +++ b/Lib/Include/freetype/internal/ftrfork.h @@ -0,0 +1,196 @@ +/***************************************************************************/ +/* */ +/* ftrfork.h */ +/* */ +/* Embedded resource forks accessor (specification). */ +/* */ +/* Copyright 2004, 2006, 2007 by */ +/* Masatake YAMATO and Redhat K.K. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + +/***************************************************************************/ +/* Development of the code in this file is support of */ +/* Information-technology Promotion Agency, Japan. */ +/***************************************************************************/ + + +#ifndef __FTRFORK_H__ +#define __FTRFORK_H__ + + +#include <ft2build.h> +#include FT_INTERNAL_OBJECTS_H + + +FT_BEGIN_HEADER + + + /* Number of guessing rules supported in `FT_Raccess_Guess'. */ + /* Don't forget to increment the number if you add a new guessing rule. */ +#define FT_RACCESS_N_RULES 9 + + + /* A structure to describe a reference in a resource by its resource ID */ + /* and internal offset. The `POST' resource expects to be concatenated */ + /* by the order of resource IDs instead of its appearance in the file. */ + + typedef struct FT_RFork_Ref_ + { + FT_UShort res_id; + FT_ULong offset; + + } FT_RFork_Ref; + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Raccess_Guess */ + /* */ + /* <Description> */ + /* Guess a file name and offset where the actual resource fork is */ + /* stored. The macro FT_RACCESS_N_RULES holds the number of */ + /* guessing rules; the guessed result for the Nth rule is */ + /* represented as a triplet: a new file name (new_names[N]), a file */ + /* offset (offsets[N]), and an error code (errors[N]). */ + /* */ + /* <Input> */ + /* library :: */ + /* A FreeType library instance. */ + /* */ + /* stream :: */ + /* A file stream containing the resource fork. */ + /* */ + /* base_name :: */ + /* The (base) file name of the resource fork used for some */ + /* guessing rules. */ + /* */ + /* <Output> */ + /* new_names :: */ + /* An array of guessed file names in which the resource forks may */ + /* exist. If `new_names[N]' is NULL, the guessed file name is */ + /* equal to `base_name'. */ + /* */ + /* offsets :: */ + /* An array of guessed file offsets. `offsets[N]' holds the file */ + /* offset of the possible start of the resource fork in file */ + /* `new_names[N]'. */ + /* */ + /* errors :: */ + /* An array of FreeType error codes. `errors[N]' is the error */ + /* code of Nth guessing rule function. If `errors[N]' is not */ + /* FT_Err_Ok, `new_names[N]' and `offsets[N]' are meaningless. */ + /* */ + FT_BASE( void ) + FT_Raccess_Guess( FT_Library library, + FT_Stream stream, + char* base_name, + char** new_names, + FT_Long* offsets, + FT_Error* errors ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Raccess_Get_HeaderInfo */ + /* */ + /* <Description> */ + /* Get the information from the header of resource fork. The */ + /* information includes the file offset where the resource map */ + /* starts, and the file offset where the resource data starts. */ + /* `FT_Raccess_Get_DataOffsets' requires these two data. */ + /* */ + /* <Input> */ + /* library :: */ + /* A FreeType library instance. */ + /* */ + /* stream :: */ + /* A file stream containing the resource fork. */ + /* */ + /* rfork_offset :: */ + /* The file offset where the resource fork starts. */ + /* */ + /* <Output> */ + /* map_offset :: */ + /* The file offset where the resource map starts. */ + /* */ + /* rdata_pos :: */ + /* The file offset where the resource data starts. */ + /* */ + /* <Return> */ + /* FreeType error code. FT_Err_Ok means success. */ + /* */ + FT_BASE( FT_Error ) + FT_Raccess_Get_HeaderInfo( FT_Library library, + FT_Stream stream, + FT_Long rfork_offset, + FT_Long *map_offset, + FT_Long *rdata_pos ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Raccess_Get_DataOffsets */ + /* */ + /* <Description> */ + /* Get the data offsets for a tag in a resource fork. Offsets are */ + /* stored in an array because, in some cases, resources in a resource */ + /* fork have the same tag. */ + /* */ + /* <Input> */ + /* library :: */ + /* A FreeType library instance. */ + /* */ + /* stream :: */ + /* A file stream containing the resource fork. */ + /* */ + /* map_offset :: */ + /* The file offset where the resource map starts. */ + /* */ + /* rdata_pos :: */ + /* The file offset where the resource data starts. */ + /* */ + /* tag :: */ + /* The resource tag. */ + /* */ + /* <Output> */ + /* offsets :: */ + /* The stream offsets for the resource data specified by `tag'. */ + /* This array is allocated by the function, so you have to call */ + /* @ft_mem_free after use. */ + /* */ + /* count :: */ + /* The length of offsets array. */ + /* */ + /* <Return> */ + /* FreeType error code. FT_Err_Ok means success. */ + /* */ + /* <Note> */ + /* Normally you should use `FT_Raccess_Get_HeaderInfo' to get the */ + /* value for `map_offset' and `rdata_pos'. */ + /* */ + FT_BASE( FT_Error ) + FT_Raccess_Get_DataOffsets( FT_Library library, + FT_Stream stream, + FT_Long map_offset, + FT_Long rdata_pos, + FT_Long tag, + FT_Long **offsets, + FT_Long *count ); + + +FT_END_HEADER + +#endif /* __FTRFORK_H__ */ + + +/* END */ diff --git a/Lib/Include/freetype/internal/ftserv.h b/Lib/Include/freetype/internal/ftserv.h new file mode 100644 index 0000000..569b9f7 --- /dev/null +++ b/Lib/Include/freetype/internal/ftserv.h @@ -0,0 +1,620 @@ +/***************************************************************************/ +/* */ +/* ftserv.h */ +/* */ +/* The FreeType services (specification only). */ +/* */ +/* Copyright 2003, 2004, 2005, 2006, 2007 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + /*************************************************************************/ + /* */ + /* Each module can export one or more `services'. Each service is */ + /* identified by a constant string and modeled by a pointer; the latter */ + /* generally corresponds to a structure containing function pointers. */ + /* */ + /* Note that a service's data cannot be a mere function pointer because */ + /* in C it is possible that function pointers might be implemented */ + /* differently than data pointers (e.g. 48 bits instead of 32). */ + /* */ + /*************************************************************************/ + + +#ifndef __FTSERV_H__ +#define __FTSERV_H__ + + +FT_BEGIN_HEADER + +#if defined( _MSC_VER ) /* Visual C++ (and Intel C++) */ + + /* we disable the warning `conditional expression is constant' here */ + /* in order to compile cleanly with the maximum level of warnings */ +#pragma warning( disable : 4127 ) + +#endif /* _MSC_VER */ + + /* + * @macro: + * FT_FACE_FIND_SERVICE + * + * @description: + * This macro is used to look up a service from a face's driver module. + * + * @input: + * face :: + * The source face handle. + * + * id :: + * A string describing the service as defined in the service's + * header files (e.g. FT_SERVICE_ID_MULTI_MASTERS which expands to + * `multi-masters'). It is automatically prefixed with + * `FT_SERVICE_ID_'. + * + * @output: + * ptr :: + * A variable that receives the service pointer. Will be NULL + * if not found. + */ +#ifdef __cplusplus + +#define FT_FACE_FIND_SERVICE( face, ptr, id ) \ + FT_BEGIN_STMNT \ + FT_Module module = FT_MODULE( FT_FACE( face )->driver ); \ + FT_Pointer _tmp_ = NULL; \ + FT_Pointer* _pptr_ = (FT_Pointer*)&(ptr); \ + \ + \ + if ( module->clazz->get_interface ) \ + _tmp_ = module->clazz->get_interface( module, FT_SERVICE_ID_ ## id ); \ + *_pptr_ = _tmp_; \ + FT_END_STMNT + +#else /* !C++ */ + +#define FT_FACE_FIND_SERVICE( face, ptr, id ) \ + FT_BEGIN_STMNT \ + FT_Module module = FT_MODULE( FT_FACE( face )->driver ); \ + FT_Pointer _tmp_ = NULL; \ + \ + if ( module->clazz->get_interface ) \ + _tmp_ = module->clazz->get_interface( module, FT_SERVICE_ID_ ## id ); \ + ptr = _tmp_; \ + FT_END_STMNT + +#endif /* !C++ */ + + /* + * @macro: + * FT_FACE_FIND_GLOBAL_SERVICE + * + * @description: + * This macro is used to look up a service from all modules. + * + * @input: + * face :: + * The source face handle. + * + * id :: + * A string describing the service as defined in the service's + * header files (e.g. FT_SERVICE_ID_MULTI_MASTERS which expands to + * `multi-masters'). It is automatically prefixed with + * `FT_SERVICE_ID_'. + * + * @output: + * ptr :: + * A variable that receives the service pointer. Will be NULL + * if not found. + */ +#ifdef __cplusplus + +#define FT_FACE_FIND_GLOBAL_SERVICE( face, ptr, id ) \ + FT_BEGIN_STMNT \ + FT_Module module = FT_MODULE( FT_FACE( face )->driver ); \ + FT_Pointer _tmp_; \ + FT_Pointer* _pptr_ = (FT_Pointer*)&(ptr); \ + \ + \ + _tmp_ = ft_module_get_service( module, FT_SERVICE_ID_ ## id ); \ + *_pptr_ = _tmp_; \ + FT_END_STMNT + +#else /* !C++ */ + +#define FT_FACE_FIND_GLOBAL_SERVICE( face, ptr, id ) \ + FT_BEGIN_STMNT \ + FT_Module module = FT_MODULE( FT_FACE( face )->driver ); \ + FT_Pointer _tmp_; \ + \ + \ + _tmp_ = ft_module_get_service( module, FT_SERVICE_ID_ ## id ); \ + ptr = _tmp_; \ + FT_END_STMNT + +#endif /* !C++ */ + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** S E R V I C E D E S C R I P T O R S *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* + * The following structure is used to _describe_ a given service + * to the library. This is useful to build simple static service lists. + */ + typedef struct FT_ServiceDescRec_ + { + const char* serv_id; /* service name */ + const void* serv_data; /* service pointer/data */ + + } FT_ServiceDescRec; + + typedef const FT_ServiceDescRec* FT_ServiceDesc; + + /*************************************************************************/ + /* */ + /* <Macro> */ + /* FT_DEFINE_SERVICEDESCREC1 .. FT_DEFINE_SERVICEDESCREC6 */ + /* */ + /* <Description> */ + /* Used to initialize an array of FT_ServiceDescRec structs. */ + /* */ + /* When FT_CONFIG_OPTION_PIC is defined a Create funtion will need */ + /* to called with a pointer where the allocated array is returned. */ + /* And when it is no longer needed a Destroy function needs */ + /* to be called to release that allocation. */ + /* */ + /* These functions should be manyally called from the pic_init and */ + /* pic_free functions of your module (see FT_DEFINE_MODULE) */ + /* */ + /* When FT_CONFIG_OPTION_PIC is not defined the array will be */ + /* allocated in the global scope (or the scope where the macro */ + /* is used). */ + /* */ +#ifndef FT_CONFIG_OPTION_PIC + +#define FT_DEFINE_SERVICEDESCREC1(class_, serv_id_1, serv_data_1) \ + static const FT_ServiceDescRec class_[] = \ + { \ + {serv_id_1, serv_data_1}, \ + {NULL, NULL} \ + }; +#define FT_DEFINE_SERVICEDESCREC2(class_, serv_id_1, serv_data_1, \ + serv_id_2, serv_data_2) \ + static const FT_ServiceDescRec class_[] = \ + { \ + {serv_id_1, serv_data_1}, \ + {serv_id_2, serv_data_2}, \ + {NULL, NULL} \ + }; +#define FT_DEFINE_SERVICEDESCREC3(class_, serv_id_1, serv_data_1, \ + serv_id_2, serv_data_2, serv_id_3, serv_data_3) \ + static const FT_ServiceDescRec class_[] = \ + { \ + {serv_id_1, serv_data_1}, \ + {serv_id_2, serv_data_2}, \ + {serv_id_3, serv_data_3}, \ + {NULL, NULL} \ + }; +#define FT_DEFINE_SERVICEDESCREC4(class_, serv_id_1, serv_data_1, \ + serv_id_2, serv_data_2, serv_id_3, serv_data_3, \ + serv_id_4, serv_data_4) \ + static const FT_ServiceDescRec class_[] = \ + { \ + {serv_id_1, serv_data_1}, \ + {serv_id_2, serv_data_2}, \ + {serv_id_3, serv_data_3}, \ + {serv_id_4, serv_data_4}, \ + {NULL, NULL} \ + }; +#define FT_DEFINE_SERVICEDESCREC5(class_, serv_id_1, serv_data_1, \ + serv_id_2, serv_data_2, serv_id_3, serv_data_3, \ + serv_id_4, serv_data_4, serv_id_5, serv_data_5) \ + static const FT_ServiceDescRec class_[] = \ + { \ + {serv_id_1, serv_data_1}, \ + {serv_id_2, serv_data_2}, \ + {serv_id_3, serv_data_3}, \ + {serv_id_4, serv_data_4}, \ + {serv_id_5, serv_data_5}, \ + {NULL, NULL} \ + }; +#define FT_DEFINE_SERVICEDESCREC6(class_, serv_id_1, serv_data_1, \ + serv_id_2, serv_data_2, serv_id_3, serv_data_3, \ + serv_id_4, serv_data_4, serv_id_5, serv_data_5, \ + serv_id_6, serv_data_6) \ + static const FT_ServiceDescRec class_[] = \ + { \ + {serv_id_1, serv_data_1}, \ + {serv_id_2, serv_data_2}, \ + {serv_id_3, serv_data_3}, \ + {serv_id_4, serv_data_4}, \ + {serv_id_5, serv_data_5}, \ + {serv_id_6, serv_data_6}, \ + {NULL, NULL} \ + }; + +#else /* FT_CONFIG_OPTION_PIC */ + +#define FT_DEFINE_SERVICEDESCREC1(class_, serv_id_1, serv_data_1) \ + void \ + FT_Destroy_Class_##class_( FT_Library library, \ + FT_ServiceDescRec* clazz ) \ + { \ + FT_Memory memory = library->memory; \ + if ( clazz ) \ + FT_FREE( clazz ); \ + } \ + \ + FT_Error \ + FT_Create_Class_##class_( FT_Library library, \ + FT_ServiceDescRec** output_class) \ + { \ + FT_ServiceDescRec* clazz; \ + FT_Error error; \ + FT_Memory memory = library->memory; \ + \ + if ( FT_ALLOC( clazz, sizeof(*clazz)*2 ) ) \ + return error; \ + clazz[0].serv_id = serv_id_1; \ + clazz[0].serv_data = serv_data_1; \ + clazz[1].serv_id = NULL; \ + clazz[1].serv_data = NULL; \ + *output_class = clazz; \ + return FT_Err_Ok; \ + } + +#define FT_DEFINE_SERVICEDESCREC2(class_, serv_id_1, serv_data_1, \ + serv_id_2, serv_data_2) \ + void \ + FT_Destroy_Class_##class_( FT_Library library, \ + FT_ServiceDescRec* clazz ) \ + { \ + FT_Memory memory = library->memory; \ + if ( clazz ) \ + FT_FREE( clazz ); \ + } \ + \ + FT_Error \ + FT_Create_Class_##class_( FT_Library library, \ + FT_ServiceDescRec** output_class) \ + { \ + FT_ServiceDescRec* clazz; \ + FT_Error error; \ + FT_Memory memory = library->memory; \ + \ + if ( FT_ALLOC( clazz, sizeof(*clazz)*3 ) ) \ + return error; \ + clazz[0].serv_id = serv_id_1; \ + clazz[0].serv_data = serv_data_1; \ + clazz[1].serv_id = serv_id_2; \ + clazz[1].serv_data = serv_data_2; \ + clazz[2].serv_id = NULL; \ + clazz[2].serv_data = NULL; \ + *output_class = clazz; \ + return FT_Err_Ok; \ + } + +#define FT_DEFINE_SERVICEDESCREC3(class_, serv_id_1, serv_data_1, \ + serv_id_2, serv_data_2, serv_id_3, serv_data_3) \ + void \ + FT_Destroy_Class_##class_( FT_Library library, \ + FT_ServiceDescRec* clazz ) \ + { \ + FT_Memory memory = library->memory; \ + if ( clazz ) \ + FT_FREE( clazz ); \ + } \ + \ + FT_Error \ + FT_Create_Class_##class_( FT_Library library, \ + FT_ServiceDescRec** output_class) \ + { \ + FT_ServiceDescRec* clazz; \ + FT_Error error; \ + FT_Memory memory = library->memory; \ + \ + if ( FT_ALLOC( clazz, sizeof(*clazz)*4 ) ) \ + return error; \ + clazz[0].serv_id = serv_id_1; \ + clazz[0].serv_data = serv_data_1; \ + clazz[1].serv_id = serv_id_2; \ + clazz[1].serv_data = serv_data_2; \ + clazz[2].serv_id = serv_id_3; \ + clazz[2].serv_data = serv_data_3; \ + clazz[3].serv_id = NULL; \ + clazz[3].serv_data = NULL; \ + *output_class = clazz; \ + return FT_Err_Ok; \ + } + +#define FT_DEFINE_SERVICEDESCREC4(class_, serv_id_1, serv_data_1, \ + serv_id_2, serv_data_2, serv_id_3, serv_data_3, \ + serv_id_4, serv_data_4) \ + void \ + FT_Destroy_Class_##class_( FT_Library library, \ + FT_ServiceDescRec* clazz ) \ + { \ + FT_Memory memory = library->memory; \ + if ( clazz ) \ + FT_FREE( clazz ); \ + } \ + \ + FT_Error \ + FT_Create_Class_##class_( FT_Library library, \ + FT_ServiceDescRec** output_class) \ + { \ + FT_ServiceDescRec* clazz; \ + FT_Error error; \ + FT_Memory memory = library->memory; \ + \ + if ( FT_ALLOC( clazz, sizeof(*clazz)*5 ) ) \ + return error; \ + clazz[0].serv_id = serv_id_1; \ + clazz[0].serv_data = serv_data_1; \ + clazz[1].serv_id = serv_id_2; \ + clazz[1].serv_data = serv_data_2; \ + clazz[2].serv_id = serv_id_3; \ + clazz[2].serv_data = serv_data_3; \ + clazz[3].serv_id = serv_id_4; \ + clazz[3].serv_data = serv_data_4; \ + clazz[4].serv_id = NULL; \ + clazz[4].serv_data = NULL; \ + *output_class = clazz; \ + return FT_Err_Ok; \ + } + +#define FT_DEFINE_SERVICEDESCREC5(class_, serv_id_1, serv_data_1, \ + serv_id_2, serv_data_2, serv_id_3, serv_data_3, serv_id_4, \ + serv_data_4, serv_id_5, serv_data_5) \ + void \ + FT_Destroy_Class_##class_( FT_Library library, \ + FT_ServiceDescRec* clazz ) \ + { \ + FT_Memory memory = library->memory; \ + if ( clazz ) \ + FT_FREE( clazz ); \ + } \ + \ + FT_Error \ + FT_Create_Class_##class_( FT_Library library, \ + FT_ServiceDescRec** output_class) \ + { \ + FT_ServiceDescRec* clazz; \ + FT_Error error; \ + FT_Memory memory = library->memory; \ + \ + if ( FT_ALLOC( clazz, sizeof(*clazz)*6 ) ) \ + return error; \ + clazz[0].serv_id = serv_id_1; \ + clazz[0].serv_data = serv_data_1; \ + clazz[1].serv_id = serv_id_2; \ + clazz[1].serv_data = serv_data_2; \ + clazz[2].serv_id = serv_id_3; \ + clazz[2].serv_data = serv_data_3; \ + clazz[3].serv_id = serv_id_4; \ + clazz[3].serv_data = serv_data_4; \ + clazz[4].serv_id = serv_id_5; \ + clazz[4].serv_data = serv_data_5; \ + clazz[5].serv_id = NULL; \ + clazz[5].serv_data = NULL; \ + *output_class = clazz; \ + return FT_Err_Ok; \ + } + +#define FT_DEFINE_SERVICEDESCREC6(class_, serv_id_1, serv_data_1, \ + serv_id_2, serv_data_2, serv_id_3, serv_data_3, \ + serv_id_4, serv_data_4, serv_id_5, serv_data_5, \ + serv_id_6, serv_data_6) \ + void \ + FT_Destroy_Class_##class_( FT_Library library, \ + FT_ServiceDescRec* clazz ) \ + { \ + FT_Memory memory = library->memory; \ + if ( clazz ) \ + FT_FREE( clazz ); \ + } \ + \ + FT_Error \ + FT_Create_Class_##class_( FT_Library library, \ + FT_ServiceDescRec** output_class) \ + { \ + FT_ServiceDescRec* clazz; \ + FT_Error error; \ + FT_Memory memory = library->memory; \ + \ + if ( FT_ALLOC( clazz, sizeof(*clazz)*7 ) ) \ + return error; \ + clazz[0].serv_id = serv_id_1; \ + clazz[0].serv_data = serv_data_1; \ + clazz[1].serv_id = serv_id_2; \ + clazz[1].serv_data = serv_data_2; \ + clazz[2].serv_id = serv_id_3; \ + clazz[2].serv_data = serv_data_3; \ + clazz[3].serv_id = serv_id_4; \ + clazz[3].serv_data = serv_data_4; \ + clazz[4].serv_id = serv_id_5; \ + clazz[4].serv_data = serv_data_5; \ + clazz[5].serv_id = serv_id_6; \ + clazz[5].serv_data = serv_data_6; \ + clazz[6].serv_id = NULL; \ + clazz[6].serv_data = NULL; \ + *output_class = clazz; \ + return FT_Err_Ok; \ + } +#endif /* FT_CONFIG_OPTION_PIC */ + + /* + * Parse a list of FT_ServiceDescRec descriptors and look for + * a specific service by ID. Note that the last element in the + * array must be { NULL, NULL }, and that the function should + * return NULL if the service isn't available. + * + * This function can be used by modules to implement their + * `get_service' method. + */ + FT_BASE( FT_Pointer ) + ft_service_list_lookup( FT_ServiceDesc service_descriptors, + const char* service_id ); + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** S E R V I C E S C A C H E *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* + * This structure is used to store a cache for several frequently used + * services. It is the type of `face->internal->services'. You + * should only use FT_FACE_LOOKUP_SERVICE to access it. + * + * All fields should have the type FT_Pointer to relax compilation + * dependencies. We assume the developer isn't completely stupid. + * + * Each field must be named `service_XXXX' where `XXX' corresponds to + * the correct FT_SERVICE_ID_XXXX macro. See the definition of + * FT_FACE_LOOKUP_SERVICE below how this is implemented. + * + */ + typedef struct FT_ServiceCacheRec_ + { + FT_Pointer service_POSTSCRIPT_FONT_NAME; + FT_Pointer service_MULTI_MASTERS; + FT_Pointer service_GLYPH_DICT; + FT_Pointer service_PFR_METRICS; + FT_Pointer service_WINFNT; + + } FT_ServiceCacheRec, *FT_ServiceCache; + + + /* + * A magic number used within the services cache. + */ +#define FT_SERVICE_UNAVAILABLE ((FT_Pointer)-2) /* magic number */ + + + /* + * @macro: + * FT_FACE_LOOKUP_SERVICE + * + * @description: + * This macro is used to lookup a service from a face's driver module + * using its cache. + * + * @input: + * face:: + * The source face handle containing the cache. + * + * field :: + * The field name in the cache. + * + * id :: + * The service ID. + * + * @output: + * ptr :: + * A variable receiving the service data. NULL if not available. + */ +#ifdef __cplusplus + +#define FT_FACE_LOOKUP_SERVICE( face, ptr, id ) \ + FT_BEGIN_STMNT \ + FT_Pointer svc; \ + FT_Pointer* Pptr = (FT_Pointer*)&(ptr); \ + \ + \ + svc = FT_FACE( face )->internal->services. service_ ## id; \ + if ( svc == FT_SERVICE_UNAVAILABLE ) \ + svc = NULL; \ + else if ( svc == NULL ) \ + { \ + FT_FACE_FIND_SERVICE( face, svc, id ); \ + \ + FT_FACE( face )->internal->services. service_ ## id = \ + (FT_Pointer)( svc != NULL ? svc \ + : FT_SERVICE_UNAVAILABLE ); \ + } \ + *Pptr = svc; \ + FT_END_STMNT + +#else /* !C++ */ + +#define FT_FACE_LOOKUP_SERVICE( face, ptr, id ) \ + FT_BEGIN_STMNT \ + FT_Pointer svc; \ + \ + \ + svc = FT_FACE( face )->internal->services. service_ ## id; \ + if ( svc == FT_SERVICE_UNAVAILABLE ) \ + svc = NULL; \ + else if ( svc == NULL ) \ + { \ + FT_FACE_FIND_SERVICE( face, svc, id ); \ + \ + FT_FACE( face )->internal->services. service_ ## id = \ + (FT_Pointer)( svc != NULL ? svc \ + : FT_SERVICE_UNAVAILABLE ); \ + } \ + ptr = svc; \ + FT_END_STMNT + +#endif /* !C++ */ + + /* + * A macro used to define new service structure types. + */ + +#define FT_DEFINE_SERVICE( name ) \ + typedef struct FT_Service_ ## name ## Rec_ \ + FT_Service_ ## name ## Rec ; \ + typedef struct FT_Service_ ## name ## Rec_ \ + const * FT_Service_ ## name ; \ + struct FT_Service_ ## name ## Rec_ + + /* */ + + /* + * The header files containing the services. + */ + +#define FT_SERVICE_BDF_H <freetype/internal/services/svbdf.h> +#define FT_SERVICE_CID_H <freetype/internal/services/svcid.h> +#define FT_SERVICE_GLYPH_DICT_H <freetype/internal/services/svgldict.h> +#define FT_SERVICE_GX_VALIDATE_H <freetype/internal/services/svgxval.h> +#define FT_SERVICE_KERNING_H <freetype/internal/services/svkern.h> +#define FT_SERVICE_MULTIPLE_MASTERS_H <freetype/internal/services/svmm.h> +#define FT_SERVICE_OPENTYPE_VALIDATE_H <freetype/internal/services/svotval.h> +#define FT_SERVICE_PFR_H <freetype/internal/services/svpfr.h> +#define FT_SERVICE_POSTSCRIPT_CMAPS_H <freetype/internal/services/svpscmap.h> +#define FT_SERVICE_POSTSCRIPT_INFO_H <freetype/internal/services/svpsinfo.h> +#define FT_SERVICE_POSTSCRIPT_NAME_H <freetype/internal/services/svpostnm.h> +#define FT_SERVICE_SFNT_H <freetype/internal/services/svsfnt.h> +#define FT_SERVICE_TRUETYPE_ENGINE_H <freetype/internal/services/svtteng.h> +#define FT_SERVICE_TT_CMAP_H <freetype/internal/services/svttcmap.h> +#define FT_SERVICE_WINFNT_H <freetype/internal/services/svwinfnt.h> +#define FT_SERVICE_XFREE86_NAME_H <freetype/internal/services/svxf86nm.h> +#define FT_SERVICE_TRUETYPE_GLYF_H <freetype/internal/services/svttglyf.h> + + /* */ + +FT_END_HEADER + +#endif /* __FTSERV_H__ */ + + +/* END */ diff --git a/Lib/Include/freetype/internal/ftstream.h b/Lib/Include/freetype/internal/ftstream.h new file mode 100644 index 0000000..a91eb72 --- /dev/null +++ b/Lib/Include/freetype/internal/ftstream.h @@ -0,0 +1,539 @@ +/***************************************************************************/ +/* */ +/* ftstream.h */ +/* */ +/* Stream handling (specification). */ +/* */ +/* Copyright 1996-2001, 2002, 2004, 2005, 2006 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef __FTSTREAM_H__ +#define __FTSTREAM_H__ + + +#include <ft2build.h> +#include FT_SYSTEM_H +#include FT_INTERNAL_OBJECTS_H + + +FT_BEGIN_HEADER + + + /* format of an 8-bit frame_op value: */ + /* */ + /* bit 76543210 */ + /* xxxxxxes */ + /* */ + /* s is set to 1 if the value is signed. */ + /* e is set to 1 if the value is little-endian. */ + /* xxx is a command. */ + +#define FT_FRAME_OP_SHIFT 2 +#define FT_FRAME_OP_SIGNED 1 +#define FT_FRAME_OP_LITTLE 2 +#define FT_FRAME_OP_COMMAND( x ) ( x >> FT_FRAME_OP_SHIFT ) + +#define FT_MAKE_FRAME_OP( command, little, sign ) \ + ( ( command << FT_FRAME_OP_SHIFT ) | ( little << 1 ) | sign ) + +#define FT_FRAME_OP_END 0 +#define FT_FRAME_OP_START 1 /* start a new frame */ +#define FT_FRAME_OP_BYTE 2 /* read 1-byte value */ +#define FT_FRAME_OP_SHORT 3 /* read 2-byte value */ +#define FT_FRAME_OP_LONG 4 /* read 4-byte value */ +#define FT_FRAME_OP_OFF3 5 /* read 3-byte value */ +#define FT_FRAME_OP_BYTES 6 /* read a bytes sequence */ + + + typedef enum FT_Frame_Op_ + { + ft_frame_end = 0, + ft_frame_start = FT_MAKE_FRAME_OP( FT_FRAME_OP_START, 0, 0 ), + + ft_frame_byte = FT_MAKE_FRAME_OP( FT_FRAME_OP_BYTE, 0, 0 ), + ft_frame_schar = FT_MAKE_FRAME_OP( FT_FRAME_OP_BYTE, 0, 1 ), + + ft_frame_ushort_be = FT_MAKE_FRAME_OP( FT_FRAME_OP_SHORT, 0, 0 ), + ft_frame_short_be = FT_MAKE_FRAME_OP( FT_FRAME_OP_SHORT, 0, 1 ), + ft_frame_ushort_le = FT_MAKE_FRAME_OP( FT_FRAME_OP_SHORT, 1, 0 ), + ft_frame_short_le = FT_MAKE_FRAME_OP( FT_FRAME_OP_SHORT, 1, 1 ), + + ft_frame_ulong_be = FT_MAKE_FRAME_OP( FT_FRAME_OP_LONG, 0, 0 ), + ft_frame_long_be = FT_MAKE_FRAME_OP( FT_FRAME_OP_LONG, 0, 1 ), + ft_frame_ulong_le = FT_MAKE_FRAME_OP( FT_FRAME_OP_LONG, 1, 0 ), + ft_frame_long_le = FT_MAKE_FRAME_OP( FT_FRAME_OP_LONG, 1, 1 ), + + ft_frame_uoff3_be = FT_MAKE_FRAME_OP( FT_FRAME_OP_OFF3, 0, 0 ), + ft_frame_off3_be = FT_MAKE_FRAME_OP( FT_FRAME_OP_OFF3, 0, 1 ), + ft_frame_uoff3_le = FT_MAKE_FRAME_OP( FT_FRAME_OP_OFF3, 1, 0 ), + ft_frame_off3_le = FT_MAKE_FRAME_OP( FT_FRAME_OP_OFF3, 1, 1 ), + + ft_frame_bytes = FT_MAKE_FRAME_OP( FT_FRAME_OP_BYTES, 0, 0 ), + ft_frame_skip = FT_MAKE_FRAME_OP( FT_FRAME_OP_BYTES, 0, 1 ) + + } FT_Frame_Op; + + + typedef struct FT_Frame_Field_ + { + FT_Byte value; + FT_Byte size; + FT_UShort offset; + + } FT_Frame_Field; + + + /* Construct an FT_Frame_Field out of a structure type and a field name. */ + /* The structure type must be set in the FT_STRUCTURE macro before */ + /* calling the FT_FRAME_START() macro. */ + /* */ +#define FT_FIELD_SIZE( f ) \ + (FT_Byte)sizeof ( ((FT_STRUCTURE*)0)->f ) + +#define FT_FIELD_SIZE_DELTA( f ) \ + (FT_Byte)sizeof ( ((FT_STRUCTURE*)0)->f[0] ) + +#define FT_FIELD_OFFSET( f ) \ + (FT_UShort)( offsetof( FT_STRUCTURE, f ) ) + +#define FT_FRAME_FIELD( frame_op, field ) \ + { \ + frame_op, \ + FT_FIELD_SIZE( field ), \ + FT_FIELD_OFFSET( field ) \ + } + +#define FT_MAKE_EMPTY_FIELD( frame_op ) { frame_op, 0, 0 } + +#define FT_FRAME_START( size ) { ft_frame_start, 0, size } +#define FT_FRAME_END { ft_frame_end, 0, 0 } + +#define FT_FRAME_LONG( f ) FT_FRAME_FIELD( ft_frame_long_be, f ) +#define FT_FRAME_ULONG( f ) FT_FRAME_FIELD( ft_frame_ulong_be, f ) +#define FT_FRAME_SHORT( f ) FT_FRAME_FIELD( ft_frame_short_be, f ) +#define FT_FRAME_USHORT( f ) FT_FRAME_FIELD( ft_frame_ushort_be, f ) +#define FT_FRAME_OFF3( f ) FT_FRAME_FIELD( ft_frame_off3_be, f ) +#define FT_FRAME_UOFF3( f ) FT_FRAME_FIELD( ft_frame_uoff3_be, f ) +#define FT_FRAME_BYTE( f ) FT_FRAME_FIELD( ft_frame_byte, f ) +#define FT_FRAME_CHAR( f ) FT_FRAME_FIELD( ft_frame_schar, f ) + +#define FT_FRAME_LONG_LE( f ) FT_FRAME_FIELD( ft_frame_long_le, f ) +#define FT_FRAME_ULONG_LE( f ) FT_FRAME_FIELD( ft_frame_ulong_le, f ) +#define FT_FRAME_SHORT_LE( f ) FT_FRAME_FIELD( ft_frame_short_le, f ) +#define FT_FRAME_USHORT_LE( f ) FT_FRAME_FIELD( ft_frame_ushort_le, f ) +#define FT_FRAME_OFF3_LE( f ) FT_FRAME_FIELD( ft_frame_off3_le, f ) +#define FT_FRAME_UOFF3_LE( f ) FT_FRAME_FIELD( ft_frame_uoff3_le, f ) + +#define FT_FRAME_SKIP_LONG { ft_frame_long_be, 0, 0 } +#define FT_FRAME_SKIP_SHORT { ft_frame_short_be, 0, 0 } +#define FT_FRAME_SKIP_BYTE { ft_frame_byte, 0, 0 } + +#define FT_FRAME_BYTES( field, count ) \ + { \ + ft_frame_bytes, \ + count, \ + FT_FIELD_OFFSET( field ) \ + } + +#define FT_FRAME_SKIP_BYTES( count ) { ft_frame_skip, count, 0 } + + + /*************************************************************************/ + /* */ + /* Integer extraction macros -- the `buffer' parameter must ALWAYS be of */ + /* type `char*' or equivalent (1-byte elements). */ + /* */ + +#define FT_BYTE_( p, i ) ( ((const FT_Byte*)(p))[(i)] ) +#define FT_INT8_( p, i ) ( ((const FT_Char*)(p))[(i)] ) + +#define FT_INT16( x ) ( (FT_Int16)(x) ) +#define FT_UINT16( x ) ( (FT_UInt16)(x) ) +#define FT_INT32( x ) ( (FT_Int32)(x) ) +#define FT_UINT32( x ) ( (FT_UInt32)(x) ) + +#define FT_BYTE_I16( p, i, s ) ( FT_INT16( FT_BYTE_( p, i ) ) << (s) ) +#define FT_BYTE_U16( p, i, s ) ( FT_UINT16( FT_BYTE_( p, i ) ) << (s) ) +#define FT_BYTE_I32( p, i, s ) ( FT_INT32( FT_BYTE_( p, i ) ) << (s) ) +#define FT_BYTE_U32( p, i, s ) ( FT_UINT32( FT_BYTE_( p, i ) ) << (s) ) + +#define FT_INT8_I16( p, i, s ) ( FT_INT16( FT_INT8_( p, i ) ) << (s) ) +#define FT_INT8_U16( p, i, s ) ( FT_UINT16( FT_INT8_( p, i ) ) << (s) ) +#define FT_INT8_I32( p, i, s ) ( FT_INT32( FT_INT8_( p, i ) ) << (s) ) +#define FT_INT8_U32( p, i, s ) ( FT_UINT32( FT_INT8_( p, i ) ) << (s) ) + + +#define FT_PEEK_SHORT( p ) FT_INT16( FT_INT8_I16( p, 0, 8) | \ + FT_BYTE_I16( p, 1, 0) ) + +#define FT_PEEK_USHORT( p ) FT_UINT16( FT_BYTE_U16( p, 0, 8 ) | \ + FT_BYTE_U16( p, 1, 0 ) ) + +#define FT_PEEK_LONG( p ) FT_INT32( FT_INT8_I32( p, 0, 24 ) | \ + FT_BYTE_I32( p, 1, 16 ) | \ + FT_BYTE_I32( p, 2, 8 ) | \ + FT_BYTE_I32( p, 3, 0 ) ) + +#define FT_PEEK_ULONG( p ) FT_UINT32( FT_BYTE_U32( p, 0, 24 ) | \ + FT_BYTE_U32( p, 1, 16 ) | \ + FT_BYTE_U32( p, 2, 8 ) | \ + FT_BYTE_U32( p, 3, 0 ) ) + +#define FT_PEEK_OFF3( p ) FT_INT32( FT_INT8_I32( p, 0, 16 ) | \ + FT_BYTE_I32( p, 1, 8 ) | \ + FT_BYTE_I32( p, 2, 0 ) ) + +#define FT_PEEK_UOFF3( p ) FT_UINT32( FT_BYTE_U32( p, 0, 16 ) | \ + FT_BYTE_U32( p, 1, 8 ) | \ + FT_BYTE_U32( p, 2, 0 ) ) + +#define FT_PEEK_SHORT_LE( p ) FT_INT16( FT_INT8_I16( p, 1, 8 ) | \ + FT_BYTE_I16( p, 0, 0 ) ) + +#define FT_PEEK_USHORT_LE( p ) FT_UINT16( FT_BYTE_U16( p, 1, 8 ) | \ + FT_BYTE_U16( p, 0, 0 ) ) + +#define FT_PEEK_LONG_LE( p ) FT_INT32( FT_INT8_I32( p, 3, 24 ) | \ + FT_BYTE_I32( p, 2, 16 ) | \ + FT_BYTE_I32( p, 1, 8 ) | \ + FT_BYTE_I32( p, 0, 0 ) ) + +#define FT_PEEK_ULONG_LE( p ) FT_UINT32( FT_BYTE_U32( p, 3, 24 ) | \ + FT_BYTE_U32( p, 2, 16 ) | \ + FT_BYTE_U32( p, 1, 8 ) | \ + FT_BYTE_U32( p, 0, 0 ) ) + +#define FT_PEEK_OFF3_LE( p ) FT_INT32( FT_INT8_I32( p, 2, 16 ) | \ + FT_BYTE_I32( p, 1, 8 ) | \ + FT_BYTE_I32( p, 0, 0 ) ) + +#define FT_PEEK_UOFF3_LE( p ) FT_UINT32( FT_BYTE_U32( p, 2, 16 ) | \ + FT_BYTE_U32( p, 1, 8 ) | \ + FT_BYTE_U32( p, 0, 0 ) ) + + +#define FT_NEXT_CHAR( buffer ) \ + ( (signed char)*buffer++ ) + +#define FT_NEXT_BYTE( buffer ) \ + ( (unsigned char)*buffer++ ) + +#define FT_NEXT_SHORT( buffer ) \ + ( (short)( buffer += 2, FT_PEEK_SHORT( buffer - 2 ) ) ) + +#define FT_NEXT_USHORT( buffer ) \ + ( (unsigned short)( buffer += 2, FT_PEEK_USHORT( buffer - 2 ) ) ) + +#define FT_NEXT_OFF3( buffer ) \ + ( (long)( buffer += 3, FT_PEEK_OFF3( buffer - 3 ) ) ) + +#define FT_NEXT_UOFF3( buffer ) \ + ( (unsigned long)( buffer += 3, FT_PEEK_UOFF3( buffer - 3 ) ) ) + +#define FT_NEXT_LONG( buffer ) \ + ( (long)( buffer += 4, FT_PEEK_LONG( buffer - 4 ) ) ) + +#define FT_NEXT_ULONG( buffer ) \ + ( (unsigned long)( buffer += 4, FT_PEEK_ULONG( buffer - 4 ) ) ) + + +#define FT_NEXT_SHORT_LE( buffer ) \ + ( (short)( buffer += 2, FT_PEEK_SHORT_LE( buffer - 2 ) ) ) + +#define FT_NEXT_USHORT_LE( buffer ) \ + ( (unsigned short)( buffer += 2, FT_PEEK_USHORT_LE( buffer - 2 ) ) ) + +#define FT_NEXT_OFF3_LE( buffer ) \ + ( (long)( buffer += 3, FT_PEEK_OFF3_LE( buffer - 3 ) ) ) + +#define FT_NEXT_UOFF3_LE( buffer ) \ + ( (unsigned long)( buffer += 3, FT_PEEK_UOFF3_LE( buffer - 3 ) ) ) + +#define FT_NEXT_LONG_LE( buffer ) \ + ( (long)( buffer += 4, FT_PEEK_LONG_LE( buffer - 4 ) ) ) + +#define FT_NEXT_ULONG_LE( buffer ) \ + ( (unsigned long)( buffer += 4, FT_PEEK_ULONG_LE( buffer - 4 ) ) ) + + + /*************************************************************************/ + /* */ + /* Each GET_xxxx() macro uses an implicit `stream' variable. */ + /* */ +#if 0 +#define FT_GET_MACRO( type ) FT_NEXT_ ## type ( stream->cursor ) + +#define FT_GET_CHAR() FT_GET_MACRO( CHAR ) +#define FT_GET_BYTE() FT_GET_MACRO( BYTE ) +#define FT_GET_SHORT() FT_GET_MACRO( SHORT ) +#define FT_GET_USHORT() FT_GET_MACRO( USHORT ) +#define FT_GET_OFF3() FT_GET_MACRO( OFF3 ) +#define FT_GET_UOFF3() FT_GET_MACRO( UOFF3 ) +#define FT_GET_LONG() FT_GET_MACRO( LONG ) +#define FT_GET_ULONG() FT_GET_MACRO( ULONG ) +#define FT_GET_TAG4() FT_GET_MACRO( ULONG ) + +#define FT_GET_SHORT_LE() FT_GET_MACRO( SHORT_LE ) +#define FT_GET_USHORT_LE() FT_GET_MACRO( USHORT_LE ) +#define FT_GET_LONG_LE() FT_GET_MACRO( LONG_LE ) +#define FT_GET_ULONG_LE() FT_GET_MACRO( ULONG_LE ) + +#else +#define FT_GET_MACRO( func, type ) ( (type)func( stream ) ) + +#define FT_GET_CHAR() FT_GET_MACRO( FT_Stream_GetChar, FT_Char ) +#define FT_GET_BYTE() FT_GET_MACRO( FT_Stream_GetChar, FT_Byte ) +#define FT_GET_SHORT() FT_GET_MACRO( FT_Stream_GetShort, FT_Short ) +#define FT_GET_USHORT() FT_GET_MACRO( FT_Stream_GetShort, FT_UShort ) +#define FT_GET_OFF3() FT_GET_MACRO( FT_Stream_GetOffset, FT_Long ) +#define FT_GET_UOFF3() FT_GET_MACRO( FT_Stream_GetOffset, FT_ULong ) +#define FT_GET_LONG() FT_GET_MACRO( FT_Stream_GetLong, FT_Long ) +#define FT_GET_ULONG() FT_GET_MACRO( FT_Stream_GetLong, FT_ULong ) +#define FT_GET_TAG4() FT_GET_MACRO( FT_Stream_GetLong, FT_ULong ) + +#define FT_GET_SHORT_LE() FT_GET_MACRO( FT_Stream_GetShortLE, FT_Short ) +#define FT_GET_USHORT_LE() FT_GET_MACRO( FT_Stream_GetShortLE, FT_UShort ) +#define FT_GET_LONG_LE() FT_GET_MACRO( FT_Stream_GetLongLE, FT_Long ) +#define FT_GET_ULONG_LE() FT_GET_MACRO( FT_Stream_GetLongLE, FT_ULong ) +#endif + +#define FT_READ_MACRO( func, type, var ) \ + ( var = (type)func( stream, &error ), \ + error != FT_Err_Ok ) + +#define FT_READ_BYTE( var ) FT_READ_MACRO( FT_Stream_ReadChar, FT_Byte, var ) +#define FT_READ_CHAR( var ) FT_READ_MACRO( FT_Stream_ReadChar, FT_Char, var ) +#define FT_READ_SHORT( var ) FT_READ_MACRO( FT_Stream_ReadShort, FT_Short, var ) +#define FT_READ_USHORT( var ) FT_READ_MACRO( FT_Stream_ReadShort, FT_UShort, var ) +#define FT_READ_OFF3( var ) FT_READ_MACRO( FT_Stream_ReadOffset, FT_Long, var ) +#define FT_READ_UOFF3( var ) FT_READ_MACRO( FT_Stream_ReadOffset, FT_ULong, var ) +#define FT_READ_LONG( var ) FT_READ_MACRO( FT_Stream_ReadLong, FT_Long, var ) +#define FT_READ_ULONG( var ) FT_READ_MACRO( FT_Stream_ReadLong, FT_ULong, var ) + +#define FT_READ_SHORT_LE( var ) FT_READ_MACRO( FT_Stream_ReadShortLE, FT_Short, var ) +#define FT_READ_USHORT_LE( var ) FT_READ_MACRO( FT_Stream_ReadShortLE, FT_UShort, var ) +#define FT_READ_LONG_LE( var ) FT_READ_MACRO( FT_Stream_ReadLongLE, FT_Long, var ) +#define FT_READ_ULONG_LE( var ) FT_READ_MACRO( FT_Stream_ReadLongLE, FT_ULong, var ) + + +#ifndef FT_CONFIG_OPTION_NO_DEFAULT_SYSTEM + + /* initialize a stream for reading a regular system stream */ + FT_BASE( FT_Error ) + FT_Stream_Open( FT_Stream stream, + const char* filepathname ); + +#endif /* FT_CONFIG_OPTION_NO_DEFAULT_SYSTEM */ + + + /* create a new (input) stream from an FT_Open_Args structure */ + FT_BASE( FT_Error ) + FT_Stream_New( FT_Library library, + const FT_Open_Args* args, + FT_Stream *astream ); + + /* free a stream */ + FT_BASE( void ) + FT_Stream_Free( FT_Stream stream, + FT_Int external ); + + /* initialize a stream for reading in-memory data */ + FT_BASE( void ) + FT_Stream_OpenMemory( FT_Stream stream, + const FT_Byte* base, + FT_ULong size ); + + /* close a stream (does not destroy the stream structure) */ + FT_BASE( void ) + FT_Stream_Close( FT_Stream stream ); + + + /* seek within a stream. position is relative to start of stream */ + FT_BASE( FT_Error ) + FT_Stream_Seek( FT_Stream stream, + FT_ULong pos ); + + /* skip bytes in a stream */ + FT_BASE( FT_Error ) + FT_Stream_Skip( FT_Stream stream, + FT_Long distance ); + + /* return current stream position */ + FT_BASE( FT_Long ) + FT_Stream_Pos( FT_Stream stream ); + + /* read bytes from a stream into a user-allocated buffer, returns an */ + /* error if not all bytes could be read. */ + FT_BASE( FT_Error ) + FT_Stream_Read( FT_Stream stream, + FT_Byte* buffer, + FT_ULong count ); + + /* read bytes from a stream at a given position */ + FT_BASE( FT_Error ) + FT_Stream_ReadAt( FT_Stream stream, + FT_ULong pos, + FT_Byte* buffer, + FT_ULong count ); + + /* try to read bytes at the end of a stream; return number of bytes */ + /* really available */ + FT_BASE( FT_ULong ) + FT_Stream_TryRead( FT_Stream stream, + FT_Byte* buffer, + FT_ULong count ); + + /* Enter a frame of `count' consecutive bytes in a stream. Returns an */ + /* error if the frame could not be read/accessed. The caller can use */ + /* the FT_Stream_Get_XXX functions to retrieve frame data without */ + /* error checks. */ + /* */ + /* You must _always_ call FT_Stream_ExitFrame() once you have entered */ + /* a stream frame! */ + /* */ + FT_BASE( FT_Error ) + FT_Stream_EnterFrame( FT_Stream stream, + FT_ULong count ); + + /* exit a stream frame */ + FT_BASE( void ) + FT_Stream_ExitFrame( FT_Stream stream ); + + /* Extract a stream frame. If the stream is disk-based, a heap block */ + /* is allocated and the frame bytes are read into it. If the stream */ + /* is memory-based, this function simply set a pointer to the data. */ + /* */ + /* Useful to optimize access to memory-based streams transparently. */ + /* */ + /* All extracted frames must be `freed' with a call to the function */ + /* FT_Stream_ReleaseFrame(). */ + /* */ + FT_BASE( FT_Error ) + FT_Stream_ExtractFrame( FT_Stream stream, + FT_ULong count, + FT_Byte** pbytes ); + + /* release an extract frame (see FT_Stream_ExtractFrame) */ + FT_BASE( void ) + FT_Stream_ReleaseFrame( FT_Stream stream, + FT_Byte** pbytes ); + + /* read a byte from an entered frame */ + FT_BASE( FT_Char ) + FT_Stream_GetChar( FT_Stream stream ); + + /* read a 16-bit big-endian integer from an entered frame */ + FT_BASE( FT_Short ) + FT_Stream_GetShort( FT_Stream stream ); + + /* read a 24-bit big-endian integer from an entered frame */ + FT_BASE( FT_Long ) + FT_Stream_GetOffset( FT_Stream stream ); + + /* read a 32-bit big-endian integer from an entered frame */ + FT_BASE( FT_Long ) + FT_Stream_GetLong( FT_Stream stream ); + + /* read a 16-bit little-endian integer from an entered frame */ + FT_BASE( FT_Short ) + FT_Stream_GetShortLE( FT_Stream stream ); + + /* read a 32-bit little-endian integer from an entered frame */ + FT_BASE( FT_Long ) + FT_Stream_GetLongLE( FT_Stream stream ); + + + /* read a byte from a stream */ + FT_BASE( FT_Char ) + FT_Stream_ReadChar( FT_Stream stream, + FT_Error* error ); + + /* read a 16-bit big-endian integer from a stream */ + FT_BASE( FT_Short ) + FT_Stream_ReadShort( FT_Stream stream, + FT_Error* error ); + + /* read a 24-bit big-endian integer from a stream */ + FT_BASE( FT_Long ) + FT_Stream_ReadOffset( FT_Stream stream, + FT_Error* error ); + + /* read a 32-bit big-endian integer from a stream */ + FT_BASE( FT_Long ) + FT_Stream_ReadLong( FT_Stream stream, + FT_Error* error ); + + /* read a 16-bit little-endian integer from a stream */ + FT_BASE( FT_Short ) + FT_Stream_ReadShortLE( FT_Stream stream, + FT_Error* error ); + + /* read a 32-bit little-endian integer from a stream */ + FT_BASE( FT_Long ) + FT_Stream_ReadLongLE( FT_Stream stream, + FT_Error* error ); + + /* Read a structure from a stream. The structure must be described */ + /* by an array of FT_Frame_Field records. */ + FT_BASE( FT_Error ) + FT_Stream_ReadFields( FT_Stream stream, + const FT_Frame_Field* fields, + void* structure ); + + +#define FT_STREAM_POS() \ + FT_Stream_Pos( stream ) + +#define FT_STREAM_SEEK( position ) \ + FT_SET_ERROR( FT_Stream_Seek( stream, position ) ) + +#define FT_STREAM_SKIP( distance ) \ + FT_SET_ERROR( FT_Stream_Skip( stream, distance ) ) + +#define FT_STREAM_READ( buffer, count ) \ + FT_SET_ERROR( FT_Stream_Read( stream, \ + (FT_Byte*)buffer, \ + count ) ) + +#define FT_STREAM_READ_AT( position, buffer, count ) \ + FT_SET_ERROR( FT_Stream_ReadAt( stream, \ + position, \ + (FT_Byte*)buffer, \ + count ) ) + +#define FT_STREAM_READ_FIELDS( fields, object ) \ + FT_SET_ERROR( FT_Stream_ReadFields( stream, fields, object ) ) + + +#define FT_FRAME_ENTER( size ) \ + FT_SET_ERROR( \ + FT_DEBUG_INNER( FT_Stream_EnterFrame( stream, size ) ) ) + +#define FT_FRAME_EXIT() \ + FT_DEBUG_INNER( FT_Stream_ExitFrame( stream ) ) + +#define FT_FRAME_EXTRACT( size, bytes ) \ + FT_SET_ERROR( \ + FT_DEBUG_INNER( FT_Stream_ExtractFrame( stream, size, \ + (FT_Byte**)&(bytes) ) ) ) + +#define FT_FRAME_RELEASE( bytes ) \ + FT_DEBUG_INNER( FT_Stream_ReleaseFrame( stream, \ + (FT_Byte**)&(bytes) ) ) + + +FT_END_HEADER + +#endif /* __FTSTREAM_H__ */ + + +/* END */ diff --git a/Lib/Include/freetype/internal/fttrace.h b/Lib/Include/freetype/internal/fttrace.h new file mode 100644 index 0000000..e9b383a --- /dev/null +++ b/Lib/Include/freetype/internal/fttrace.h @@ -0,0 +1,139 @@ +/***************************************************************************/ +/* */ +/* fttrace.h */ +/* */ +/* Tracing handling (specification only). */ +/* */ +/* Copyright 2002, 2004, 2005, 2006, 2007 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + + /* definitions of trace levels for FreeType 2 */ + + /* the first level must always be `trace_any' */ +FT_TRACE_DEF( any ) + + /* base components */ +FT_TRACE_DEF( calc ) /* calculations (ftcalc.c) */ +FT_TRACE_DEF( memory ) /* memory manager (ftobjs.c) */ +FT_TRACE_DEF( stream ) /* stream manager (ftstream.c) */ +FT_TRACE_DEF( io ) /* i/o interface (ftsystem.c) */ +FT_TRACE_DEF( list ) /* list management (ftlist.c) */ +FT_TRACE_DEF( init ) /* initialization (ftinit.c) */ +FT_TRACE_DEF( objs ) /* base objects (ftobjs.c) */ +FT_TRACE_DEF( outline ) /* outline management (ftoutln.c) */ +FT_TRACE_DEF( glyph ) /* glyph management (ftglyph.c) */ +FT_TRACE_DEF( gloader ) /* glyph loader (ftgloadr.c) */ + +FT_TRACE_DEF( raster ) /* monochrome rasterizer (ftraster.c) */ +FT_TRACE_DEF( smooth ) /* anti-aliasing raster (ftgrays.c) */ +FT_TRACE_DEF( mm ) /* MM interface (ftmm.c) */ +FT_TRACE_DEF( raccess ) /* resource fork accessor (ftrfork.c) */ +FT_TRACE_DEF( synth ) /* bold/slant synthesizer (ftsynth.c) */ + + /* Cache sub-system */ +FT_TRACE_DEF( cache ) /* cache sub-system (ftcache.c, etc.) */ + + /* SFNT driver components */ +FT_TRACE_DEF( sfdriver ) /* SFNT font driver (sfdriver.c) */ +FT_TRACE_DEF( sfobjs ) /* SFNT object handler (sfobjs.c) */ +FT_TRACE_DEF( ttcmap ) /* charmap handler (ttcmap.c) */ +FT_TRACE_DEF( ttkern ) /* kerning handler (ttkern.c) */ +FT_TRACE_DEF( ttload ) /* basic TrueType tables (ttload.c) */ +FT_TRACE_DEF( ttmtx ) /* metrics-related tables (ttmtx.c) */ +FT_TRACE_DEF( ttpost ) /* PS table processing (ttpost.c) */ +FT_TRACE_DEF( ttsbit ) /* TrueType sbit handling (ttsbit.c) */ +FT_TRACE_DEF( ttbdf ) /* TrueType embedded BDF (ttbdf.c) */ + + /* TrueType driver components */ +FT_TRACE_DEF( ttdriver ) /* TT font driver (ttdriver.c) */ +FT_TRACE_DEF( ttgload ) /* TT glyph loader (ttgload.c) */ +FT_TRACE_DEF( ttinterp ) /* bytecode interpreter (ttinterp.c) */ +FT_TRACE_DEF( ttobjs ) /* TT objects manager (ttobjs.c) */ +FT_TRACE_DEF( ttpload ) /* TT data/program loader (ttpload.c) */ +FT_TRACE_DEF( ttgxvar ) /* TrueType GX var handler (ttgxvar.c) */ + + /* Type 1 driver components */ +FT_TRACE_DEF( t1afm ) +FT_TRACE_DEF( t1driver ) +FT_TRACE_DEF( t1gload ) +FT_TRACE_DEF( t1hint ) +FT_TRACE_DEF( t1load ) +FT_TRACE_DEF( t1objs ) +FT_TRACE_DEF( t1parse ) + + /* PostScript helper module `psaux' */ +FT_TRACE_DEF( t1decode ) +FT_TRACE_DEF( psobjs ) + + /* PostScript hinting module `pshinter' */ +FT_TRACE_DEF( pshrec ) +FT_TRACE_DEF( pshalgo1 ) +FT_TRACE_DEF( pshalgo2 ) + + /* Type 2 driver components */ +FT_TRACE_DEF( cffdriver ) +FT_TRACE_DEF( cffgload ) +FT_TRACE_DEF( cffload ) +FT_TRACE_DEF( cffobjs ) +FT_TRACE_DEF( cffparse ) + + /* Type 42 driver component */ +FT_TRACE_DEF( t42 ) + + /* CID driver components */ +FT_TRACE_DEF( cidafm ) +FT_TRACE_DEF( ciddriver ) +FT_TRACE_DEF( cidgload ) +FT_TRACE_DEF( cidload ) +FT_TRACE_DEF( cidobjs ) +FT_TRACE_DEF( cidparse ) + + /* Windows font component */ +FT_TRACE_DEF( winfnt ) + + /* PCF font components */ +FT_TRACE_DEF( pcfdriver ) +FT_TRACE_DEF( pcfread ) + + /* BDF font components */ +FT_TRACE_DEF( bdfdriver ) +FT_TRACE_DEF( bdflib ) + + /* PFR font component */ +FT_TRACE_DEF( pfr ) + + /* OpenType validation components */ +FT_TRACE_DEF( otvmodule ) +FT_TRACE_DEF( otvcommon ) +FT_TRACE_DEF( otvbase ) +FT_TRACE_DEF( otvgdef ) +FT_TRACE_DEF( otvgpos ) +FT_TRACE_DEF( otvgsub ) +FT_TRACE_DEF( otvjstf ) +FT_TRACE_DEF( otvmath ) + + /* TrueTypeGX/AAT validation components */ +FT_TRACE_DEF( gxvmodule ) +FT_TRACE_DEF( gxvcommon ) +FT_TRACE_DEF( gxvfeat ) +FT_TRACE_DEF( gxvmort ) +FT_TRACE_DEF( gxvmorx ) +FT_TRACE_DEF( gxvbsln ) +FT_TRACE_DEF( gxvjust ) +FT_TRACE_DEF( gxvkern ) +FT_TRACE_DEF( gxvopbd ) +FT_TRACE_DEF( gxvtrak ) +FT_TRACE_DEF( gxvprop ) +FT_TRACE_DEF( gxvlcar ) + + +/* END */ diff --git a/Lib/Include/freetype/internal/ftvalid.h b/Lib/Include/freetype/internal/ftvalid.h new file mode 100644 index 0000000..00cd85e --- /dev/null +++ b/Lib/Include/freetype/internal/ftvalid.h @@ -0,0 +1,150 @@ +/***************************************************************************/ +/* */ +/* ftvalid.h */ +/* */ +/* FreeType validation support (specification). */ +/* */ +/* Copyright 2004 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef __FTVALID_H__ +#define __FTVALID_H__ + +#include <ft2build.h> +#include FT_CONFIG_STANDARD_LIBRARY_H /* for ft_setjmp and ft_longjmp */ + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** ****/ + /**** V A L I D A T I O N ****/ + /**** ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + /* handle to a validation object */ + typedef struct FT_ValidatorRec_ volatile* FT_Validator; + + + /*************************************************************************/ + /* */ + /* There are three distinct validation levels defined here: */ + /* */ + /* FT_VALIDATE_DEFAULT :: */ + /* A table that passes this validation level can be used reliably by */ + /* FreeType. It generally means that all offsets have been checked to */ + /* prevent out-of-bound reads, that array counts are correct, etc. */ + /* */ + /* FT_VALIDATE_TIGHT :: */ + /* A table that passes this validation level can be used reliably and */ + /* doesn't contain invalid data. For example, a charmap table that */ + /* returns invalid glyph indices will not pass, even though it can */ + /* be used with FreeType in default mode (the library will simply */ + /* return an error later when trying to load the glyph). */ + /* */ + /* It also checks that fields which must be a multiple of 2, 4, or 8, */ + /* don't have incorrect values, etc. */ + /* */ + /* FT_VALIDATE_PARANOID :: */ + /* Only for font debugging. Checks that a table follows the */ + /* specification by 100%. Very few fonts will be able to pass this */ + /* level anyway but it can be useful for certain tools like font */ + /* editors/converters. */ + /* */ + typedef enum FT_ValidationLevel_ + { + FT_VALIDATE_DEFAULT = 0, + FT_VALIDATE_TIGHT, + FT_VALIDATE_PARANOID + + } FT_ValidationLevel; + + + /* validator structure */ + typedef struct FT_ValidatorRec_ + { + const FT_Byte* base; /* address of table in memory */ + const FT_Byte* limit; /* `base' + sizeof(table) in memory */ + FT_ValidationLevel level; /* validation level */ + FT_Error error; /* error returned. 0 means success */ + + ft_jmp_buf jump_buffer; /* used for exception handling */ + + } FT_ValidatorRec; + + +#define FT_VALIDATOR( x ) ((FT_Validator)( x )) + + + FT_BASE( void ) + ft_validator_init( FT_Validator valid, + const FT_Byte* base, + const FT_Byte* limit, + FT_ValidationLevel level ); + + /* Do not use this. It's broken and will cause your validator to crash */ + /* if you run it on an invalid font. */ + FT_BASE( FT_Int ) + ft_validator_run( FT_Validator valid ); + + /* Sets the error field in a validator, then calls `longjmp' to return */ + /* to high-level caller. Using `setjmp/longjmp' avoids many stupid */ + /* error checks within the validation routines. */ + /* */ + FT_BASE( void ) + ft_validator_error( FT_Validator valid, + FT_Error error ); + + + /* Calls ft_validate_error. Assumes that the `valid' local variable */ + /* holds a pointer to the current validator object. */ + /* */ + /* Use preprocessor prescan to pass FT_ERR_PREFIX. */ + /* */ +#define FT_INVALID( _prefix, _error ) FT_INVALID_( _prefix, _error ) +#define FT_INVALID_( _prefix, _error ) \ + ft_validator_error( valid, _prefix ## _error ) + + /* called when a broken table is detected */ +#define FT_INVALID_TOO_SHORT \ + FT_INVALID( FT_ERR_PREFIX, Invalid_Table ) + + /* called when an invalid offset is detected */ +#define FT_INVALID_OFFSET \ + FT_INVALID( FT_ERR_PREFIX, Invalid_Offset ) + + /* called when an invalid format/value is detected */ +#define FT_INVALID_FORMAT \ + FT_INVALID( FT_ERR_PREFIX, Invalid_Table ) + + /* called when an invalid glyph index is detected */ +#define FT_INVALID_GLYPH_ID \ + FT_INVALID( FT_ERR_PREFIX, Invalid_Glyph_Index ) + + /* called when an invalid field value is detected */ +#define FT_INVALID_DATA \ + FT_INVALID( FT_ERR_PREFIX, Invalid_Table ) + + +FT_END_HEADER + +#endif /* __FTVALID_H__ */ + + +/* END */ diff --git a/Lib/Include/freetype/internal/internal.h b/Lib/Include/freetype/internal/internal.h new file mode 100644 index 0000000..f500a65 --- /dev/null +++ b/Lib/Include/freetype/internal/internal.h @@ -0,0 +1,51 @@ +/***************************************************************************/ +/* */ +/* internal.h */ +/* */ +/* Internal header files (specification only). */ +/* */ +/* Copyright 1996-2001, 2002, 2003, 2004 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + + /*************************************************************************/ + /* */ + /* This file is automatically included by `ft2build.h'. */ + /* Do not include it manually! */ + /* */ + /*************************************************************************/ + + +#define FT_INTERNAL_OBJECTS_H <freetype/internal/ftobjs.h> +#define FT_INTERNAL_PIC_H <freetype/internal/ftpic.h> +#define FT_INTERNAL_STREAM_H <freetype/internal/ftstream.h> +#define FT_INTERNAL_MEMORY_H <freetype/internal/ftmemory.h> +#define FT_INTERNAL_DEBUG_H <freetype/internal/ftdebug.h> +#define FT_INTERNAL_CALC_H <freetype/internal/ftcalc.h> +#define FT_INTERNAL_DRIVER_H <freetype/internal/ftdriver.h> +#define FT_INTERNAL_TRACE_H <freetype/internal/fttrace.h> +#define FT_INTERNAL_GLYPH_LOADER_H <freetype/internal/ftgloadr.h> +#define FT_INTERNAL_SFNT_H <freetype/internal/sfnt.h> +#define FT_INTERNAL_SERVICE_H <freetype/internal/ftserv.h> +#define FT_INTERNAL_RFORK_H <freetype/internal/ftrfork.h> +#define FT_INTERNAL_VALIDATE_H <freetype/internal/ftvalid.h> + +#define FT_INTERNAL_TRUETYPE_TYPES_H <freetype/internal/tttypes.h> +#define FT_INTERNAL_TYPE1_TYPES_H <freetype/internal/t1types.h> + +#define FT_INTERNAL_POSTSCRIPT_AUX_H <freetype/internal/psaux.h> +#define FT_INTERNAL_POSTSCRIPT_HINTS_H <freetype/internal/pshints.h> +#define FT_INTERNAL_POSTSCRIPT_GLOBALS_H <freetype/internal/psglobal.h> + +#define FT_INTERNAL_AUTOHINT_H <freetype/internal/autohint.h> + + +/* END */ diff --git a/Lib/Include/freetype/internal/pcftypes.h b/Lib/Include/freetype/internal/pcftypes.h new file mode 100644 index 0000000..382796f --- /dev/null +++ b/Lib/Include/freetype/internal/pcftypes.h @@ -0,0 +1,56 @@ +/* pcftypes.h + + FreeType font driver for pcf fonts + + Copyright (C) 2000, 2001, 2002 by + Francesco Zappa Nardelli + +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 +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 SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + + +#ifndef __PCFTYPES_H__ +#define __PCFTYPES_H__ + + +#include <ft2build.h> +#include FT_FREETYPE_H + + +FT_BEGIN_HEADER + + + typedef struct PCF_Public_FaceRec_ + { + FT_FaceRec root; + FT_StreamRec gzip_stream; + FT_Stream gzip_source; + + char* charset_encoding; + char* charset_registry; + + } PCF_Public_FaceRec, *PCF_Public_Face; + + +FT_END_HEADER + +#endif /* __PCFTYPES_H__ */ + + +/* END */ diff --git a/Lib/Include/freetype/internal/psaux.h b/Lib/Include/freetype/internal/psaux.h new file mode 100644 index 0000000..a96e0df --- /dev/null +++ b/Lib/Include/freetype/internal/psaux.h @@ -0,0 +1,873 @@ +/***************************************************************************/ +/* */ +/* psaux.h */ +/* */ +/* Auxiliary functions and data structures related to PostScript fonts */ +/* (specification). */ +/* */ +/* Copyright 1996-2001, 2002, 2003, 2004, 2006, 2008, 2009 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef __PSAUX_H__ +#define __PSAUX_H__ + + +#include <ft2build.h> +#include FT_INTERNAL_OBJECTS_H +#include FT_INTERNAL_TYPE1_TYPES_H +#include FT_SERVICE_POSTSCRIPT_CMAPS_H + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** T1_TABLE *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + typedef struct PS_TableRec_* PS_Table; + typedef const struct PS_Table_FuncsRec_* PS_Table_Funcs; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* PS_Table_FuncsRec */ + /* */ + /* <Description> */ + /* A set of function pointers to manage PS_Table objects. */ + /* */ + /* <Fields> */ + /* table_init :: Used to initialize a table. */ + /* */ + /* table_done :: Finalizes resp. destroy a given table. */ + /* */ + /* table_add :: Adds a new object to a table. */ + /* */ + /* table_release :: Releases table data, then finalizes it. */ + /* */ + typedef struct PS_Table_FuncsRec_ + { + FT_Error + (*init)( PS_Table table, + FT_Int count, + FT_Memory memory ); + + void + (*done)( PS_Table table ); + + FT_Error + (*add)( PS_Table table, + FT_Int idx, + void* object, + FT_PtrDist length ); + + void + (*release)( PS_Table table ); + + } PS_Table_FuncsRec; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* PS_TableRec */ + /* */ + /* <Description> */ + /* A PS_Table is a simple object used to store an array of objects in */ + /* a single memory block. */ + /* */ + /* <Fields> */ + /* block :: The address in memory of the growheap's block. This */ + /* can change between two object adds, due to */ + /* reallocation. */ + /* */ + /* cursor :: The current top of the grow heap within its block. */ + /* */ + /* capacity :: The current size of the heap block. Increments by */ + /* 1kByte chunks. */ + /* */ + /* max_elems :: The maximum number of elements in table. */ + /* */ + /* num_elems :: The current number of elements in table. */ + /* */ + /* elements :: A table of element addresses within the block. */ + /* */ + /* lengths :: A table of element sizes within the block. */ + /* */ + /* memory :: The object used for memory operations */ + /* (alloc/realloc). */ + /* */ + /* funcs :: A table of method pointers for this object. */ + /* */ + typedef struct PS_TableRec_ + { + FT_Byte* block; /* current memory block */ + FT_Offset cursor; /* current cursor in memory block */ + FT_Offset capacity; /* current size of memory block */ + FT_Long init; + + FT_Int max_elems; + FT_Int num_elems; + FT_Byte** elements; /* addresses of table elements */ + FT_PtrDist* lengths; /* lengths of table elements */ + + FT_Memory memory; + PS_Table_FuncsRec funcs; + + } PS_TableRec; + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** T1 FIELDS & TOKENS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + typedef struct PS_ParserRec_* PS_Parser; + + typedef struct T1_TokenRec_* T1_Token; + + typedef struct T1_FieldRec_* T1_Field; + + + /* simple enumeration type used to identify token types */ + typedef enum T1_TokenType_ + { + T1_TOKEN_TYPE_NONE = 0, + T1_TOKEN_TYPE_ANY, + T1_TOKEN_TYPE_STRING, + T1_TOKEN_TYPE_ARRAY, + T1_TOKEN_TYPE_KEY, /* aka `name' */ + + /* do not remove */ + T1_TOKEN_TYPE_MAX + + } T1_TokenType; + + + /* a simple structure used to identify tokens */ + typedef struct T1_TokenRec_ + { + FT_Byte* start; /* first character of token in input stream */ + FT_Byte* limit; /* first character after the token */ + T1_TokenType type; /* type of token */ + + } T1_TokenRec; + + + /* enumeration type used to identify object fields */ + typedef enum T1_FieldType_ + { + T1_FIELD_TYPE_NONE = 0, + T1_FIELD_TYPE_BOOL, + T1_FIELD_TYPE_INTEGER, + T1_FIELD_TYPE_FIXED, + T1_FIELD_TYPE_FIXED_1000, + T1_FIELD_TYPE_STRING, + T1_FIELD_TYPE_KEY, + T1_FIELD_TYPE_BBOX, + T1_FIELD_TYPE_INTEGER_ARRAY, + T1_FIELD_TYPE_FIXED_ARRAY, + T1_FIELD_TYPE_CALLBACK, + + /* do not remove */ + T1_FIELD_TYPE_MAX + + } T1_FieldType; + + + typedef enum T1_FieldLocation_ + { + T1_FIELD_LOCATION_CID_INFO, + T1_FIELD_LOCATION_FONT_DICT, + T1_FIELD_LOCATION_FONT_EXTRA, + T1_FIELD_LOCATION_FONT_INFO, + T1_FIELD_LOCATION_PRIVATE, + T1_FIELD_LOCATION_BBOX, + T1_FIELD_LOCATION_LOADER, + T1_FIELD_LOCATION_FACE, + T1_FIELD_LOCATION_BLEND, + + /* do not remove */ + T1_FIELD_LOCATION_MAX + + } T1_FieldLocation; + + + typedef void + (*T1_Field_ParseFunc)( FT_Face face, + FT_Pointer parser ); + + + /* structure type used to model object fields */ + typedef struct T1_FieldRec_ + { + const char* ident; /* field identifier */ + T1_FieldLocation location; + T1_FieldType type; /* type of field */ + T1_Field_ParseFunc reader; + FT_UInt offset; /* offset of field in object */ + FT_Byte size; /* size of field in bytes */ + FT_UInt array_max; /* maximal number of elements for */ + /* array */ + FT_UInt count_offset; /* offset of element count for */ + /* arrays; must not be zero if in */ + /* use -- in other words, a */ + /* `num_FOO' element must not */ + /* start the used structure if we */ + /* parse a `FOO' array */ + FT_UInt dict; /* where we expect it */ + } T1_FieldRec; + +#define T1_FIELD_DICT_FONTDICT ( 1 << 0 ) /* also FontInfo and FDArray */ +#define T1_FIELD_DICT_PRIVATE ( 1 << 1 ) + + + +#define T1_NEW_SIMPLE_FIELD( _ident, _type, _fname, _dict ) \ + { \ + _ident, T1CODE, _type, \ + 0, \ + FT_FIELD_OFFSET( _fname ), \ + FT_FIELD_SIZE( _fname ), \ + 0, 0, \ + _dict \ + }, + +#define T1_NEW_CALLBACK_FIELD( _ident, _reader, _dict ) \ + { \ + _ident, T1CODE, T1_FIELD_TYPE_CALLBACK, \ + (T1_Field_ParseFunc)_reader, \ + 0, 0, \ + 0, 0, \ + _dict \ + }, + +#define T1_NEW_TABLE_FIELD( _ident, _type, _fname, _max, _dict ) \ + { \ + _ident, T1CODE, _type, \ + 0, \ + FT_FIELD_OFFSET( _fname ), \ + FT_FIELD_SIZE_DELTA( _fname ), \ + _max, \ + FT_FIELD_OFFSET( num_ ## _fname ), \ + _dict \ + }, + +#define T1_NEW_TABLE_FIELD2( _ident, _type, _fname, _max, _dict ) \ + { \ + _ident, T1CODE, _type, \ + 0, \ + FT_FIELD_OFFSET( _fname ), \ + FT_FIELD_SIZE_DELTA( _fname ), \ + _max, 0, \ + _dict \ + }, + + +#define T1_FIELD_BOOL( _ident, _fname, _dict ) \ + T1_NEW_SIMPLE_FIELD( _ident, T1_FIELD_TYPE_BOOL, _fname, _dict ) + +#define T1_FIELD_NUM( _ident, _fname, _dict ) \ + T1_NEW_SIMPLE_FIELD( _ident, T1_FIELD_TYPE_INTEGER, _fname, _dict ) + +#define T1_FIELD_FIXED( _ident, _fname, _dict ) \ + T1_NEW_SIMPLE_FIELD( _ident, T1_FIELD_TYPE_FIXED, _fname, _dict ) + +#define T1_FIELD_FIXED_1000( _ident, _fname, _dict ) \ + T1_NEW_SIMPLE_FIELD( _ident, T1_FIELD_TYPE_FIXED_1000, _fname, \ + _dict ) + +#define T1_FIELD_STRING( _ident, _fname, _dict ) \ + T1_NEW_SIMPLE_FIELD( _ident, T1_FIELD_TYPE_STRING, _fname, _dict ) + +#define T1_FIELD_KEY( _ident, _fname, _dict ) \ + T1_NEW_SIMPLE_FIELD( _ident, T1_FIELD_TYPE_KEY, _fname, _dict ) + +#define T1_FIELD_BBOX( _ident, _fname, _dict ) \ + T1_NEW_SIMPLE_FIELD( _ident, T1_FIELD_TYPE_BBOX, _fname, _dict ) + + +#define T1_FIELD_NUM_TABLE( _ident, _fname, _fmax, _dict ) \ + T1_NEW_TABLE_FIELD( _ident, T1_FIELD_TYPE_INTEGER_ARRAY, \ + _fname, _fmax, _dict ) + +#define T1_FIELD_FIXED_TABLE( _ident, _fname, _fmax, _dict ) \ + T1_NEW_TABLE_FIELD( _ident, T1_FIELD_TYPE_FIXED_ARRAY, \ + _fname, _fmax, _dict ) + +#define T1_FIELD_NUM_TABLE2( _ident, _fname, _fmax, _dict ) \ + T1_NEW_TABLE_FIELD2( _ident, T1_FIELD_TYPE_INTEGER_ARRAY, \ + _fname, _fmax, _dict ) + +#define T1_FIELD_FIXED_TABLE2( _ident, _fname, _fmax, _dict ) \ + T1_NEW_TABLE_FIELD2( _ident, T1_FIELD_TYPE_FIXED_ARRAY, \ + _fname, _fmax, _dict ) + +#define T1_FIELD_CALLBACK( _ident, _name, _dict ) \ + T1_NEW_CALLBACK_FIELD( _ident, _name, _dict ) + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** T1 PARSER *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + typedef const struct PS_Parser_FuncsRec_* PS_Parser_Funcs; + + typedef struct PS_Parser_FuncsRec_ + { + void + (*init)( PS_Parser parser, + FT_Byte* base, + FT_Byte* limit, + FT_Memory memory ); + + void + (*done)( PS_Parser parser ); + + void + (*skip_spaces)( PS_Parser parser ); + void + (*skip_PS_token)( PS_Parser parser ); + + FT_Long + (*to_int)( PS_Parser parser ); + FT_Fixed + (*to_fixed)( PS_Parser parser, + FT_Int power_ten ); + + FT_Error + (*to_bytes)( PS_Parser parser, + FT_Byte* bytes, + FT_Offset max_bytes, + FT_Long* pnum_bytes, + FT_Bool delimiters ); + + FT_Int + (*to_coord_array)( PS_Parser parser, + FT_Int max_coords, + FT_Short* coords ); + FT_Int + (*to_fixed_array)( PS_Parser parser, + FT_Int max_values, + FT_Fixed* values, + FT_Int power_ten ); + + void + (*to_token)( PS_Parser parser, + T1_Token token ); + void + (*to_token_array)( PS_Parser parser, + T1_Token tokens, + FT_UInt max_tokens, + FT_Int* pnum_tokens ); + + FT_Error + (*load_field)( PS_Parser parser, + const T1_Field field, + void** objects, + FT_UInt max_objects, + FT_ULong* pflags ); + + FT_Error + (*load_field_table)( PS_Parser parser, + const T1_Field field, + void** objects, + FT_UInt max_objects, + FT_ULong* pflags ); + + } PS_Parser_FuncsRec; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* PS_ParserRec */ + /* */ + /* <Description> */ + /* A PS_Parser is an object used to parse a Type 1 font very quickly. */ + /* */ + /* <Fields> */ + /* cursor :: The current position in the text. */ + /* */ + /* base :: Start of the processed text. */ + /* */ + /* limit :: End of the processed text. */ + /* */ + /* error :: The last error returned. */ + /* */ + /* memory :: The object used for memory operations (alloc/realloc). */ + /* */ + /* funcs :: A table of functions for the parser. */ + /* */ + typedef struct PS_ParserRec_ + { + FT_Byte* cursor; + FT_Byte* base; + FT_Byte* limit; + FT_Error error; + FT_Memory memory; + + PS_Parser_FuncsRec funcs; + + } PS_ParserRec; + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** T1 BUILDER *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + typedef struct T1_BuilderRec_* T1_Builder; + + + typedef FT_Error + (*T1_Builder_Check_Points_Func)( T1_Builder builder, + FT_Int count ); + + typedef void + (*T1_Builder_Add_Point_Func)( T1_Builder builder, + FT_Pos x, + FT_Pos y, + FT_Byte flag ); + + typedef FT_Error + (*T1_Builder_Add_Point1_Func)( T1_Builder builder, + FT_Pos x, + FT_Pos y ); + + typedef FT_Error + (*T1_Builder_Add_Contour_Func)( T1_Builder builder ); + + typedef FT_Error + (*T1_Builder_Start_Point_Func)( T1_Builder builder, + FT_Pos x, + FT_Pos y ); + + typedef void + (*T1_Builder_Close_Contour_Func)( T1_Builder builder ); + + + typedef const struct T1_Builder_FuncsRec_* T1_Builder_Funcs; + + typedef struct T1_Builder_FuncsRec_ + { + void + (*init)( T1_Builder builder, + FT_Face face, + FT_Size size, + FT_GlyphSlot slot, + FT_Bool hinting ); + + void + (*done)( T1_Builder builder ); + + T1_Builder_Check_Points_Func check_points; + T1_Builder_Add_Point_Func add_point; + T1_Builder_Add_Point1_Func add_point1; + T1_Builder_Add_Contour_Func add_contour; + T1_Builder_Start_Point_Func start_point; + T1_Builder_Close_Contour_Func close_contour; + + } T1_Builder_FuncsRec; + + + /* an enumeration type to handle charstring parsing states */ + typedef enum T1_ParseState_ + { + T1_Parse_Start, + T1_Parse_Have_Width, + T1_Parse_Have_Moveto, + T1_Parse_Have_Path + + } T1_ParseState; + + + /*************************************************************************/ + /* */ + /* <Structure> */ + /* T1_BuilderRec */ + /* */ + /* <Description> */ + /* A structure used during glyph loading to store its outline. */ + /* */ + /* <Fields> */ + /* memory :: The current memory object. */ + /* */ + /* face :: The current face object. */ + /* */ + /* glyph :: The current glyph slot. */ + /* */ + /* loader :: XXX */ + /* */ + /* base :: The base glyph outline. */ + /* */ + /* current :: The current glyph outline. */ + /* */ + /* max_points :: maximum points in builder outline */ + /* */ + /* max_contours :: Maximal number of contours in builder outline. */ + /* */ + /* pos_x :: The horizontal translation (if composite glyph). */ + /* */ + /* pos_y :: The vertical translation (if composite glyph). */ + /* */ + /* left_bearing :: The left side bearing point. */ + /* */ + /* advance :: The horizontal advance vector. */ + /* */ + /* bbox :: Unused. */ + /* */ + /* parse_state :: An enumeration which controls the charstring */ + /* parsing state. */ + /* */ + /* load_points :: If this flag is not set, no points are loaded. */ + /* */ + /* no_recurse :: Set but not used. */ + /* */ + /* metrics_only :: A boolean indicating that we only want to compute */ + /* the metrics of a given glyph, not load all of its */ + /* points. */ + /* */ + /* funcs :: An array of function pointers for the builder. */ + /* */ + typedef struct T1_BuilderRec_ + { + FT_Memory memory; + FT_Face face; + FT_GlyphSlot glyph; + FT_GlyphLoader loader; + FT_Outline* base; + FT_Outline* current; + + FT_Pos pos_x; + FT_Pos pos_y; + + FT_Vector left_bearing; + FT_Vector advance; + + FT_BBox bbox; /* bounding box */ + T1_ParseState parse_state; + FT_Bool load_points; + FT_Bool no_recurse; + + FT_Bool metrics_only; + + void* hints_funcs; /* hinter-specific */ + void* hints_globals; /* hinter-specific */ + + T1_Builder_FuncsRec funcs; + + } T1_BuilderRec; + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** T1 DECODER *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + +#if 0 + + /*************************************************************************/ + /* */ + /* T1_MAX_SUBRS_CALLS details the maximum number of nested sub-routine */ + /* calls during glyph loading. */ + /* */ +#define T1_MAX_SUBRS_CALLS 8 + + + /*************************************************************************/ + /* */ + /* T1_MAX_CHARSTRING_OPERANDS is the charstring stack's capacity. A */ + /* minimum of 16 is required. */ + /* */ +#define T1_MAX_CHARSTRINGS_OPERANDS 32 + +#endif /* 0 */ + + + typedef struct T1_Decoder_ZoneRec_ + { + FT_Byte* cursor; + FT_Byte* base; + FT_Byte* limit; + + } T1_Decoder_ZoneRec, *T1_Decoder_Zone; + + + typedef struct T1_DecoderRec_* T1_Decoder; + typedef const struct T1_Decoder_FuncsRec_* T1_Decoder_Funcs; + + + typedef FT_Error + (*T1_Decoder_Callback)( T1_Decoder decoder, + FT_UInt glyph_index ); + + + typedef struct T1_Decoder_FuncsRec_ + { + FT_Error + (*init)( T1_Decoder decoder, + FT_Face face, + FT_Size size, + FT_GlyphSlot slot, + FT_Byte** glyph_names, + PS_Blend blend, + FT_Bool hinting, + FT_Render_Mode hint_mode, + T1_Decoder_Callback callback ); + + void + (*done)( T1_Decoder decoder ); + + FT_Error + (*parse_charstrings)( T1_Decoder decoder, + FT_Byte* base, + FT_UInt len ); + + } T1_Decoder_FuncsRec; + + + typedef struct T1_DecoderRec_ + { + T1_BuilderRec builder; + + FT_Long stack[T1_MAX_CHARSTRINGS_OPERANDS]; + FT_Long* top; + + T1_Decoder_ZoneRec zones[T1_MAX_SUBRS_CALLS + 1]; + T1_Decoder_Zone zone; + + FT_Service_PsCMaps psnames; /* for seac */ + FT_UInt num_glyphs; + FT_Byte** glyph_names; + + FT_Int lenIV; /* internal for sub routine calls */ + FT_UInt num_subrs; + FT_Byte** subrs; + FT_PtrDist* subrs_len; /* array of subrs length (optional) */ + + FT_Matrix font_matrix; + FT_Vector font_offset; + + FT_Int flex_state; + FT_Int num_flex_vectors; + FT_Vector flex_vectors[7]; + + PS_Blend blend; /* for multiple master support */ + + FT_Render_Mode hint_mode; + + T1_Decoder_Callback parse_callback; + T1_Decoder_FuncsRec funcs; + + FT_Long* buildchar; + FT_UInt len_buildchar; + + FT_Bool seac; + + } T1_DecoderRec; + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** AFM PARSER *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + typedef struct AFM_ParserRec_* AFM_Parser; + + typedef struct AFM_Parser_FuncsRec_ + { + FT_Error + (*init)( AFM_Parser parser, + FT_Memory memory, + FT_Byte* base, + FT_Byte* limit ); + + void + (*done)( AFM_Parser parser ); + + FT_Error + (*parse)( AFM_Parser parser ); + + } AFM_Parser_FuncsRec; + + + typedef struct AFM_StreamRec_* AFM_Stream; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* AFM_ParserRec */ + /* */ + /* <Description> */ + /* An AFM_Parser is a parser for the AFM files. */ + /* */ + /* <Fields> */ + /* memory :: The object used for memory operations (alloc and */ + /* realloc). */ + /* */ + /* stream :: This is an opaque object. */ + /* */ + /* FontInfo :: The result will be stored here. */ + /* */ + /* get_index :: A user provided function to get a glyph index by its */ + /* name. */ + /* */ + typedef struct AFM_ParserRec_ + { + FT_Memory memory; + AFM_Stream stream; + + AFM_FontInfo FontInfo; + + FT_Int + (*get_index)( const char* name, + FT_Offset len, + void* user_data ); + + void* user_data; + + } AFM_ParserRec; + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** TYPE1 CHARMAPS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + typedef const struct T1_CMap_ClassesRec_* T1_CMap_Classes; + + typedef struct T1_CMap_ClassesRec_ + { + FT_CMap_Class standard; + FT_CMap_Class expert; + FT_CMap_Class custom; + FT_CMap_Class unicode; + + } T1_CMap_ClassesRec; + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** PSAux Module Interface *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + typedef struct PSAux_ServiceRec_ + { + /* don't use `PS_Table_Funcs' and friends to avoid compiler warnings */ + const PS_Table_FuncsRec* ps_table_funcs; + const PS_Parser_FuncsRec* ps_parser_funcs; + const T1_Builder_FuncsRec* t1_builder_funcs; + const T1_Decoder_FuncsRec* t1_decoder_funcs; + + void + (*t1_decrypt)( FT_Byte* buffer, + FT_Offset length, + FT_UShort seed ); + + T1_CMap_Classes t1_cmap_classes; + + /* fields after this comment line were added after version 2.1.10 */ + const AFM_Parser_FuncsRec* afm_parser_funcs; + + } PSAux_ServiceRec, *PSAux_Service; + + /* backwards-compatible type definition */ + typedef PSAux_ServiceRec PSAux_Interface; + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** Some convenience functions *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + +#define IS_PS_NEWLINE( ch ) \ + ( (ch) == '\r' || \ + (ch) == '\n' ) + +#define IS_PS_SPACE( ch ) \ + ( (ch) == ' ' || \ + IS_PS_NEWLINE( ch ) || \ + (ch) == '\t' || \ + (ch) == '\f' || \ + (ch) == '\0' ) + +#define IS_PS_SPECIAL( ch ) \ + ( (ch) == '/' || \ + (ch) == '(' || (ch) == ')' || \ + (ch) == '<' || (ch) == '>' || \ + (ch) == '[' || (ch) == ']' || \ + (ch) == '{' || (ch) == '}' || \ + (ch) == '%' ) + +#define IS_PS_DELIM( ch ) \ + ( IS_PS_SPACE( ch ) || \ + IS_PS_SPECIAL( ch ) ) + +#define IS_PS_DIGIT( ch ) \ + ( (ch) >= '0' && (ch) <= '9' ) + +#define IS_PS_XDIGIT( ch ) \ + ( IS_PS_DIGIT( ch ) || \ + ( (ch) >= 'A' && (ch) <= 'F' ) || \ + ( (ch) >= 'a' && (ch) <= 'f' ) ) + +#define IS_PS_BASE85( ch ) \ + ( (ch) >= '!' && (ch) <= 'u' ) + +#define IS_PS_TOKEN( cur, limit, token ) \ + ( (char)(cur)[0] == (token)[0] && \ + ( (cur) + sizeof ( (token) ) == (limit) || \ + ( (cur) + sizeof( (token) ) < (limit) && \ + IS_PS_DELIM( (cur)[sizeof ( (token) ) - 1] ) ) ) && \ + ft_strncmp( (char*)(cur), (token), sizeof ( (token) ) - 1 ) == 0 ) + + +FT_END_HEADER + +#endif /* __PSAUX_H__ */ + + +/* END */ diff --git a/Lib/Include/freetype/internal/pshints.h b/Lib/Include/freetype/internal/pshints.h new file mode 100644 index 0000000..0c35765 --- /dev/null +++ b/Lib/Include/freetype/internal/pshints.h @@ -0,0 +1,712 @@ +/***************************************************************************/ +/* */ +/* pshints.h */ +/* */ +/* Interface to Postscript-specific (Type 1 and Type 2) hints */ +/* recorders (specification only). These are used to support native */ +/* T1/T2 hints in the `type1', `cid', and `cff' font drivers. */ +/* */ +/* Copyright 2001, 2002, 2003, 2005, 2006, 2007, 2009 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef __PSHINTS_H__ +#define __PSHINTS_H__ + + +#include <ft2build.h> +#include FT_FREETYPE_H +#include FT_TYPE1_TABLES_H + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** INTERNAL REPRESENTATION OF GLOBALS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + typedef struct PSH_GlobalsRec_* PSH_Globals; + + typedef FT_Error + (*PSH_Globals_NewFunc)( FT_Memory memory, + T1_Private* private_dict, + PSH_Globals* aglobals ); + + typedef FT_Error + (*PSH_Globals_SetScaleFunc)( PSH_Globals globals, + FT_Fixed x_scale, + FT_Fixed y_scale, + FT_Fixed x_delta, + FT_Fixed y_delta ); + + typedef void + (*PSH_Globals_DestroyFunc)( PSH_Globals globals ); + + + typedef struct PSH_Globals_FuncsRec_ + { + PSH_Globals_NewFunc create; + PSH_Globals_SetScaleFunc set_scale; + PSH_Globals_DestroyFunc destroy; + + } PSH_Globals_FuncsRec, *PSH_Globals_Funcs; + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** PUBLIC TYPE 1 HINTS RECORDER *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /************************************************************************* + * + * @type: + * T1_Hints + * + * @description: + * This is a handle to an opaque structure used to record glyph hints + * from a Type 1 character glyph character string. + * + * The methods used to operate on this object are defined by the + * @T1_Hints_FuncsRec structure. Recording glyph hints is normally + * achieved through the following scheme: + * + * - Open a new hint recording session by calling the `open' method. + * This rewinds the recorder and prepare it for new input. + * + * - For each hint found in the glyph charstring, call the corresponding + * method (`stem', `stem3', or `reset'). Note that these functions do + * not return an error code. + * + * - Close the recording session by calling the `close' method. It + * returns an error code if the hints were invalid or something + * strange happened (e.g., memory shortage). + * + * The hints accumulated in the object can later be used by the + * PostScript hinter. + * + */ + typedef struct T1_HintsRec_* T1_Hints; + + + /************************************************************************* + * + * @type: + * T1_Hints_Funcs + * + * @description: + * A pointer to the @T1_Hints_FuncsRec structure that defines the API of + * a given @T1_Hints object. + * + */ + typedef const struct T1_Hints_FuncsRec_* T1_Hints_Funcs; + + + /************************************************************************* + * + * @functype: + * T1_Hints_OpenFunc + * + * @description: + * A method of the @T1_Hints class used to prepare it for a new Type 1 + * hints recording session. + * + * @input: + * hints :: + * A handle to the Type 1 hints recorder. + * + * @note: + * You should always call the @T1_Hints_CloseFunc method in order to + * close an opened recording session. + * + */ + typedef void + (*T1_Hints_OpenFunc)( T1_Hints hints ); + + + /************************************************************************* + * + * @functype: + * T1_Hints_SetStemFunc + * + * @description: + * A method of the @T1_Hints class used to record a new horizontal or + * vertical stem. This corresponds to the Type 1 `hstem' and `vstem' + * operators. + * + * @input: + * hints :: + * A handle to the Type 1 hints recorder. + * + * dimension :: + * 0 for horizontal stems (hstem), 1 for vertical ones (vstem). + * + * coords :: + * Array of 2 coordinates in 16.16 format, used as (position,length) + * stem descriptor. + * + * @note: + * Use vertical coordinates (y) for horizontal stems (dim=0). Use + * horizontal coordinates (x) for vertical stems (dim=1). + * + * `coords[0]' is the absolute stem position (lowest coordinate); + * `coords[1]' is the length. + * + * The length can be negative, in which case it must be either -20 or + * -21. It is interpreted as a `ghost' stem, according to the Type 1 + * specification. + * + * If the length is -21 (corresponding to a bottom ghost stem), then + * the real stem position is `coords[0]+coords[1]'. + * + */ + typedef void + (*T1_Hints_SetStemFunc)( T1_Hints hints, + FT_UInt dimension, + FT_Fixed* coords ); + + + /************************************************************************* + * + * @functype: + * T1_Hints_SetStem3Func + * + * @description: + * A method of the @T1_Hints class used to record three + * counter-controlled horizontal or vertical stems at once. + * + * @input: + * hints :: + * A handle to the Type 1 hints recorder. + * + * dimension :: + * 0 for horizontal stems, 1 for vertical ones. + * + * coords :: + * An array of 6 values in 16.16 format, holding 3 (position,length) + * pairs for the counter-controlled stems. + * + * @note: + * Use vertical coordinates (y) for horizontal stems (dim=0). Use + * horizontal coordinates (x) for vertical stems (dim=1). + * + * The lengths cannot be negative (ghost stems are never + * counter-controlled). + * + */ + typedef void + (*T1_Hints_SetStem3Func)( T1_Hints hints, + FT_UInt dimension, + FT_Fixed* coords ); + + + /************************************************************************* + * + * @functype: + * T1_Hints_ResetFunc + * + * @description: + * A method of the @T1_Hints class used to reset the stems hints in a + * recording session. + * + * @input: + * hints :: + * A handle to the Type 1 hints recorder. + * + * end_point :: + * The index of the last point in the input glyph in which the + * previously defined hints apply. + * + */ + typedef void + (*T1_Hints_ResetFunc)( T1_Hints hints, + FT_UInt end_point ); + + + /************************************************************************* + * + * @functype: + * T1_Hints_CloseFunc + * + * @description: + * A method of the @T1_Hints class used to close a hint recording + * session. + * + * @input: + * hints :: + * A handle to the Type 1 hints recorder. + * + * end_point :: + * The index of the last point in the input glyph. + * + * @return: + * FreeType error code. 0 means success. + * + * @note: + * The error code is set to indicate that an error occurred during the + * recording session. + * + */ + typedef FT_Error + (*T1_Hints_CloseFunc)( T1_Hints hints, + FT_UInt end_point ); + + + /************************************************************************* + * + * @functype: + * T1_Hints_ApplyFunc + * + * @description: + * A method of the @T1_Hints class used to apply hints to the + * corresponding glyph outline. Must be called once all hints have been + * recorded. + * + * @input: + * hints :: + * A handle to the Type 1 hints recorder. + * + * outline :: + * A pointer to the target outline descriptor. + * + * globals :: + * The hinter globals for this font. + * + * hint_mode :: + * Hinting information. + * + * @return: + * FreeType error code. 0 means success. + * + * @note: + * On input, all points within the outline are in font coordinates. On + * output, they are in 1/64th of pixels. + * + * The scaling transformation is taken from the `globals' object which + * must correspond to the same font as the glyph. + * + */ + typedef FT_Error + (*T1_Hints_ApplyFunc)( T1_Hints hints, + FT_Outline* outline, + PSH_Globals globals, + FT_Render_Mode hint_mode ); + + + /************************************************************************* + * + * @struct: + * T1_Hints_FuncsRec + * + * @description: + * The structure used to provide the API to @T1_Hints objects. + * + * @fields: + * hints :: + * A handle to the T1 Hints recorder. + * + * open :: + * The function to open a recording session. + * + * close :: + * The function to close a recording session. + * + * stem :: + * The function to set a simple stem. + * + * stem3 :: + * The function to set counter-controlled stems. + * + * reset :: + * The function to reset stem hints. + * + * apply :: + * The function to apply the hints to the corresponding glyph outline. + * + */ + typedef struct T1_Hints_FuncsRec_ + { + T1_Hints hints; + T1_Hints_OpenFunc open; + T1_Hints_CloseFunc close; + T1_Hints_SetStemFunc stem; + T1_Hints_SetStem3Func stem3; + T1_Hints_ResetFunc reset; + T1_Hints_ApplyFunc apply; + + } T1_Hints_FuncsRec; + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** PUBLIC TYPE 2 HINTS RECORDER *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /************************************************************************* + * + * @type: + * T2_Hints + * + * @description: + * This is a handle to an opaque structure used to record glyph hints + * from a Type 2 character glyph character string. + * + * The methods used to operate on this object are defined by the + * @T2_Hints_FuncsRec structure. Recording glyph hints is normally + * achieved through the following scheme: + * + * - Open a new hint recording session by calling the `open' method. + * This rewinds the recorder and prepare it for new input. + * + * - For each hint found in the glyph charstring, call the corresponding + * method (`stems', `hintmask', `counters'). Note that these + * functions do not return an error code. + * + * - Close the recording session by calling the `close' method. It + * returns an error code if the hints were invalid or something + * strange happened (e.g., memory shortage). + * + * The hints accumulated in the object can later be used by the + * Postscript hinter. + * + */ + typedef struct T2_HintsRec_* T2_Hints; + + + /************************************************************************* + * + * @type: + * T2_Hints_Funcs + * + * @description: + * A pointer to the @T2_Hints_FuncsRec structure that defines the API of + * a given @T2_Hints object. + * + */ + typedef const struct T2_Hints_FuncsRec_* T2_Hints_Funcs; + + + /************************************************************************* + * + * @functype: + * T2_Hints_OpenFunc + * + * @description: + * A method of the @T2_Hints class used to prepare it for a new Type 2 + * hints recording session. + * + * @input: + * hints :: + * A handle to the Type 2 hints recorder. + * + * @note: + * You should always call the @T2_Hints_CloseFunc method in order to + * close an opened recording session. + * + */ + typedef void + (*T2_Hints_OpenFunc)( T2_Hints hints ); + + + /************************************************************************* + * + * @functype: + * T2_Hints_StemsFunc + * + * @description: + * A method of the @T2_Hints class used to set the table of stems in + * either the vertical or horizontal dimension. Equivalent to the + * `hstem', `vstem', `hstemhm', and `vstemhm' Type 2 operators. + * + * @input: + * hints :: + * A handle to the Type 2 hints recorder. + * + * dimension :: + * 0 for horizontal stems (hstem), 1 for vertical ones (vstem). + * + * count :: + * The number of stems. + * + * coords :: + * An array of `count' (position,length) pairs in 16.16 format. + * + * @note: + * Use vertical coordinates (y) for horizontal stems (dim=0). Use + * horizontal coordinates (x) for vertical stems (dim=1). + * + * There are `2*count' elements in the `coords' array. Each even + * element is an absolute position in font units, each odd element is a + * length in font units. + * + * A length can be negative, in which case it must be either -20 or + * -21. It is interpreted as a `ghost' stem, according to the Type 1 + * specification. + * + */ + typedef void + (*T2_Hints_StemsFunc)( T2_Hints hints, + FT_UInt dimension, + FT_UInt count, + FT_Fixed* coordinates ); + + + /************************************************************************* + * + * @functype: + * T2_Hints_MaskFunc + * + * @description: + * A method of the @T2_Hints class used to set a given hintmask (this + * corresponds to the `hintmask' Type 2 operator). + * + * @input: + * hints :: + * A handle to the Type 2 hints recorder. + * + * end_point :: + * The glyph index of the last point to which the previously defined + * or activated hints apply. + * + * bit_count :: + * The number of bits in the hint mask. + * + * bytes :: + * An array of bytes modelling the hint mask. + * + * @note: + * If the hintmask starts the charstring (before any glyph point + * definition), the value of `end_point' should be 0. + * + * `bit_count' is the number of meaningful bits in the `bytes' array; it + * must be equal to the total number of hints defined so far (i.e., + * horizontal+verticals). + * + * The `bytes' array can come directly from the Type 2 charstring and + * respects the same format. + * + */ + typedef void + (*T2_Hints_MaskFunc)( T2_Hints hints, + FT_UInt end_point, + FT_UInt bit_count, + const FT_Byte* bytes ); + + + /************************************************************************* + * + * @functype: + * T2_Hints_CounterFunc + * + * @description: + * A method of the @T2_Hints class used to set a given counter mask + * (this corresponds to the `hintmask' Type 2 operator). + * + * @input: + * hints :: + * A handle to the Type 2 hints recorder. + * + * end_point :: + * A glyph index of the last point to which the previously defined or + * active hints apply. + * + * bit_count :: + * The number of bits in the hint mask. + * + * bytes :: + * An array of bytes modelling the hint mask. + * + * @note: + * If the hintmask starts the charstring (before any glyph point + * definition), the value of `end_point' should be 0. + * + * `bit_count' is the number of meaningful bits in the `bytes' array; it + * must be equal to the total number of hints defined so far (i.e., + * horizontal+verticals). + * + * The `bytes' array can come directly from the Type 2 charstring and + * respects the same format. + * + */ + typedef void + (*T2_Hints_CounterFunc)( T2_Hints hints, + FT_UInt bit_count, + const FT_Byte* bytes ); + + + /************************************************************************* + * + * @functype: + * T2_Hints_CloseFunc + * + * @description: + * A method of the @T2_Hints class used to close a hint recording + * session. + * + * @input: + * hints :: + * A handle to the Type 2 hints recorder. + * + * end_point :: + * The index of the last point in the input glyph. + * + * @return: + * FreeType error code. 0 means success. + * + * @note: + * The error code is set to indicate that an error occurred during the + * recording session. + * + */ + typedef FT_Error + (*T2_Hints_CloseFunc)( T2_Hints hints, + FT_UInt end_point ); + + + /************************************************************************* + * + * @functype: + * T2_Hints_ApplyFunc + * + * @description: + * A method of the @T2_Hints class used to apply hints to the + * corresponding glyph outline. Must be called after the `close' + * method. + * + * @input: + * hints :: + * A handle to the Type 2 hints recorder. + * + * outline :: + * A pointer to the target outline descriptor. + * + * globals :: + * The hinter globals for this font. + * + * hint_mode :: + * Hinting information. + * + * @return: + * FreeType error code. 0 means success. + * + * @note: + * On input, all points within the outline are in font coordinates. On + * output, they are in 1/64th of pixels. + * + * The scaling transformation is taken from the `globals' object which + * must correspond to the same font than the glyph. + * + */ + typedef FT_Error + (*T2_Hints_ApplyFunc)( T2_Hints hints, + FT_Outline* outline, + PSH_Globals globals, + FT_Render_Mode hint_mode ); + + + /************************************************************************* + * + * @struct: + * T2_Hints_FuncsRec + * + * @description: + * The structure used to provide the API to @T2_Hints objects. + * + * @fields: + * hints :: + * A handle to the T2 hints recorder object. + * + * open :: + * The function to open a recording session. + * + * close :: + * The function to close a recording session. + * + * stems :: + * The function to set the dimension's stems table. + * + * hintmask :: + * The function to set hint masks. + * + * counter :: + * The function to set counter masks. + * + * apply :: + * The function to apply the hints on the corresponding glyph outline. + * + */ + typedef struct T2_Hints_FuncsRec_ + { + T2_Hints hints; + T2_Hints_OpenFunc open; + T2_Hints_CloseFunc close; + T2_Hints_StemsFunc stems; + T2_Hints_MaskFunc hintmask; + T2_Hints_CounterFunc counter; + T2_Hints_ApplyFunc apply; + + } T2_Hints_FuncsRec; + + + /* */ + + + typedef struct PSHinter_Interface_ + { + PSH_Globals_Funcs (*get_globals_funcs)( FT_Module module ); + T1_Hints_Funcs (*get_t1_funcs) ( FT_Module module ); + T2_Hints_Funcs (*get_t2_funcs) ( FT_Module module ); + + } PSHinter_Interface; + + typedef PSHinter_Interface* PSHinter_Service; + +#ifndef FT_CONFIG_OPTION_PIC + +#define FT_DEFINE_PSHINTER_INTERFACE(class_, get_globals_funcs_, \ + get_t1_funcs_, get_t2_funcs_) \ + static const PSHinter_Interface class_ = \ + { \ + get_globals_funcs_, get_t1_funcs_, get_t2_funcs_ \ + }; + +#else /* FT_CONFIG_OPTION_PIC */ + +#define FT_DEFINE_PSHINTER_INTERFACE(class_, get_globals_funcs_, \ + get_t1_funcs_, get_t2_funcs_) \ + void \ + FT_Init_Class_##class_( FT_Library library, \ + PSHinter_Interface* clazz) \ + { \ + FT_UNUSED(library); \ + clazz->get_globals_funcs = get_globals_funcs_; \ + clazz->get_t1_funcs = get_t1_funcs_; \ + clazz->get_t2_funcs = get_t2_funcs_; \ + } + +#endif /* FT_CONFIG_OPTION_PIC */ + +FT_END_HEADER + +#endif /* __PSHINTS_H__ */ + + +/* END */ diff --git a/Lib/Include/freetype/internal/services/svbdf.h b/Lib/Include/freetype/internal/services/svbdf.h new file mode 100644 index 0000000..9264239 --- /dev/null +++ b/Lib/Include/freetype/internal/services/svbdf.h @@ -0,0 +1,77 @@ +/***************************************************************************/ +/* */ +/* svbdf.h */ +/* */ +/* The FreeType BDF services (specification). */ +/* */ +/* Copyright 2003 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef __SVBDF_H__ +#define __SVBDF_H__ + +#include FT_BDF_H +#include FT_INTERNAL_SERVICE_H + + +FT_BEGIN_HEADER + + +#define FT_SERVICE_ID_BDF "bdf" + + typedef FT_Error + (*FT_BDF_GetCharsetIdFunc)( FT_Face face, + const char* *acharset_encoding, + const char* *acharset_registry ); + + typedef FT_Error + (*FT_BDF_GetPropertyFunc)( FT_Face face, + const char* prop_name, + BDF_PropertyRec *aproperty ); + + + FT_DEFINE_SERVICE( BDF ) + { + FT_BDF_GetCharsetIdFunc get_charset_id; + FT_BDF_GetPropertyFunc get_property; + }; + +#ifndef FT_CONFIG_OPTION_PIC + +#define FT_DEFINE_SERVICE_BDFRec(class_, get_charset_id_, get_property_) \ + static const FT_Service_BDFRec class_ = \ + { \ + get_charset_id_, get_property_ \ + }; + +#else /* FT_CONFIG_OPTION_PIC */ + +#define FT_DEFINE_SERVICE_BDFRec(class_, get_charset_id_, get_property_) \ + void \ + FT_Init_Class_##class_( FT_Service_BDFRec* clazz ) \ + { \ + clazz->get_charset_id = get_charset_id_; \ + clazz->get_property = get_property_; \ + } + +#endif /* FT_CONFIG_OPTION_PIC */ + + /* */ + + +FT_END_HEADER + + +#endif /* __SVBDF_H__ */ + + +/* END */ diff --git a/Lib/Include/freetype/internal/services/svcid.h b/Lib/Include/freetype/internal/services/svcid.h new file mode 100644 index 0000000..9b874b5 --- /dev/null +++ b/Lib/Include/freetype/internal/services/svcid.h @@ -0,0 +1,83 @@ +/***************************************************************************/ +/* */ +/* svcid.h */ +/* */ +/* The FreeType CID font services (specification). */ +/* */ +/* Copyright 2007, 2009 by Derek Clegg, Michael Toftdal. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef __SVCID_H__ +#define __SVCID_H__ + +#include FT_INTERNAL_SERVICE_H + + +FT_BEGIN_HEADER + + +#define FT_SERVICE_ID_CID "CID" + + typedef FT_Error + (*FT_CID_GetRegistryOrderingSupplementFunc)( FT_Face face, + const char* *registry, + const char* *ordering, + FT_Int *supplement ); + typedef FT_Error + (*FT_CID_GetIsInternallyCIDKeyedFunc)( FT_Face face, + FT_Bool *is_cid ); + typedef FT_Error + (*FT_CID_GetCIDFromGlyphIndexFunc)( FT_Face face, + FT_UInt glyph_index, + FT_UInt *cid ); + + FT_DEFINE_SERVICE( CID ) + { + FT_CID_GetRegistryOrderingSupplementFunc get_ros; + FT_CID_GetIsInternallyCIDKeyedFunc get_is_cid; + FT_CID_GetCIDFromGlyphIndexFunc get_cid_from_glyph_index; + }; + +#ifndef FT_CONFIG_OPTION_PIC + +#define FT_DEFINE_SERVICE_CIDREC(class_, get_ros_, \ + get_is_cid_, get_cid_from_glyph_index_ ) \ + static const FT_Service_CIDRec class_ = \ + { \ + get_ros_, get_is_cid_, get_cid_from_glyph_index_ \ + }; + +#else /* FT_CONFIG_OPTION_PIC */ + +#define FT_DEFINE_SERVICE_CIDREC(class_, get_ros_, \ + get_is_cid_, get_cid_from_glyph_index_ ) \ + void \ + FT_Init_Class_##class_( FT_Library library, \ + FT_Service_CIDRec* clazz) \ + { \ + FT_UNUSED(library); \ + clazz->get_ros = get_ros_; \ + clazz->get_is_cid = get_is_cid_; \ + clazz->get_cid_from_glyph_index = get_cid_from_glyph_index_; \ + } + +#endif /* FT_CONFIG_OPTION_PIC */ + + /* */ + + +FT_END_HEADER + + +#endif /* __SVCID_H__ */ + + +/* END */ diff --git a/Lib/Include/freetype/internal/services/svgldict.h b/Lib/Include/freetype/internal/services/svgldict.h new file mode 100644 index 0000000..d66a41d --- /dev/null +++ b/Lib/Include/freetype/internal/services/svgldict.h @@ -0,0 +1,82 @@ +/***************************************************************************/ +/* */ +/* svgldict.h */ +/* */ +/* The FreeType glyph dictionary services (specification). */ +/* */ +/* Copyright 2003 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef __SVGLDICT_H__ +#define __SVGLDICT_H__ + +#include FT_INTERNAL_SERVICE_H + + +FT_BEGIN_HEADER + + + /* + * A service used to retrieve glyph names, as well as to find the + * index of a given glyph name in a font. + * + */ + +#define FT_SERVICE_ID_GLYPH_DICT "glyph-dict" + + + typedef FT_Error + (*FT_GlyphDict_GetNameFunc)( FT_Face face, + FT_UInt glyph_index, + FT_Pointer buffer, + FT_UInt buffer_max ); + + typedef FT_UInt + (*FT_GlyphDict_NameIndexFunc)( FT_Face face, + FT_String* glyph_name ); + + + FT_DEFINE_SERVICE( GlyphDict ) + { + FT_GlyphDict_GetNameFunc get_name; + FT_GlyphDict_NameIndexFunc name_index; /* optional */ + }; + +#ifndef FT_CONFIG_OPTION_PIC + +#define FT_DEFINE_SERVICE_GLYPHDICTREC(class_, get_name_, name_index_) \ + static const FT_Service_GlyphDictRec class_ = \ + { \ + get_name_, name_index_ \ + }; + +#else /* FT_CONFIG_OPTION_PIC */ + +#define FT_DEFINE_SERVICE_GLYPHDICTREC(class_, get_name_, name_index_) \ + void \ + FT_Init_Class_##class_( FT_Library library, \ + FT_Service_GlyphDictRec* clazz) \ + { \ + FT_UNUSED(library); \ + clazz->get_name = get_name_; \ + clazz->name_index = name_index_; \ + } + +#endif /* FT_CONFIG_OPTION_PIC */ + + /* */ + + +FT_END_HEADER + + +#endif /* __SVGLDICT_H__ */ diff --git a/Lib/Include/freetype/internal/services/svgxval.h b/Lib/Include/freetype/internal/services/svgxval.h new file mode 100644 index 0000000..2cdab50 --- /dev/null +++ b/Lib/Include/freetype/internal/services/svgxval.h @@ -0,0 +1,72 @@ +/***************************************************************************/ +/* */ +/* svgxval.h */ +/* */ +/* FreeType API for validating TrueTypeGX/AAT tables (specification). */ +/* */ +/* Copyright 2004, 2005 by */ +/* Masatake YAMATO, Red Hat K.K., */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + +/***************************************************************************/ +/* */ +/* gxvalid is derived from both gxlayout module and otvalid module. */ +/* Development of gxlayout is supported by the Information-technology */ +/* Promotion Agency(IPA), Japan. */ +/* */ +/***************************************************************************/ + + +#ifndef __SVGXVAL_H__ +#define __SVGXVAL_H__ + +#include FT_GX_VALIDATE_H +#include FT_INTERNAL_VALIDATE_H + +FT_BEGIN_HEADER + + +#define FT_SERVICE_ID_GX_VALIDATE "truetypegx-validate" +#define FT_SERVICE_ID_CLASSICKERN_VALIDATE "classickern-validate" + + typedef FT_Error + (*gxv_validate_func)( FT_Face face, + FT_UInt gx_flags, + FT_Bytes tables[FT_VALIDATE_GX_LENGTH], + FT_UInt table_length ); + + + typedef FT_Error + (*ckern_validate_func)( FT_Face face, + FT_UInt ckern_flags, + FT_Bytes *ckern_table ); + + + FT_DEFINE_SERVICE( GXvalidate ) + { + gxv_validate_func validate; + }; + + FT_DEFINE_SERVICE( CKERNvalidate ) + { + ckern_validate_func validate; + }; + + /* */ + + +FT_END_HEADER + + +#endif /* __SVGXVAL_H__ */ + + +/* END */ diff --git a/Lib/Include/freetype/internal/services/svkern.h b/Lib/Include/freetype/internal/services/svkern.h new file mode 100644 index 0000000..1488adf --- /dev/null +++ b/Lib/Include/freetype/internal/services/svkern.h @@ -0,0 +1,51 @@ +/***************************************************************************/ +/* */ +/* svkern.h */ +/* */ +/* The FreeType Kerning service (specification). */ +/* */ +/* Copyright 2006 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef __SVKERN_H__ +#define __SVKERN_H__ + +#include FT_INTERNAL_SERVICE_H +#include FT_TRUETYPE_TABLES_H + + +FT_BEGIN_HEADER + +#define FT_SERVICE_ID_KERNING "kerning" + + + typedef FT_Error + (*FT_Kerning_TrackGetFunc)( FT_Face face, + FT_Fixed point_size, + FT_Int degree, + FT_Fixed* akerning ); + + FT_DEFINE_SERVICE( Kerning ) + { + FT_Kerning_TrackGetFunc get_track; + }; + + /* */ + + +FT_END_HEADER + + +#endif /* __SVKERN_H__ */ + + +/* END */ diff --git a/Lib/Include/freetype/internal/services/svmm.h b/Lib/Include/freetype/internal/services/svmm.h new file mode 100644 index 0000000..66e1da2 --- /dev/null +++ b/Lib/Include/freetype/internal/services/svmm.h @@ -0,0 +1,104 @@ +/***************************************************************************/ +/* */ +/* svmm.h */ +/* */ +/* The FreeType Multiple Masters and GX var services (specification). */ +/* */ +/* Copyright 2003, 2004 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef __SVMM_H__ +#define __SVMM_H__ + +#include FT_INTERNAL_SERVICE_H + + +FT_BEGIN_HEADER + + + /* + * A service used to manage multiple-masters data in a given face. + * + * See the related APIs in `ftmm.h' (FT_MULTIPLE_MASTERS_H). + * + */ + +#define FT_SERVICE_ID_MULTI_MASTERS "multi-masters" + + + typedef FT_Error + (*FT_Get_MM_Func)( FT_Face face, + FT_Multi_Master* master ); + + typedef FT_Error + (*FT_Get_MM_Var_Func)( FT_Face face, + FT_MM_Var* *master ); + + typedef FT_Error + (*FT_Set_MM_Design_Func)( FT_Face face, + FT_UInt num_coords, + FT_Long* coords ); + + typedef FT_Error + (*FT_Set_Var_Design_Func)( FT_Face face, + FT_UInt num_coords, + FT_Fixed* coords ); + + typedef FT_Error + (*FT_Set_MM_Blend_Func)( FT_Face face, + FT_UInt num_coords, + FT_Long* coords ); + + + FT_DEFINE_SERVICE( MultiMasters ) + { + FT_Get_MM_Func get_mm; + FT_Set_MM_Design_Func set_mm_design; + FT_Set_MM_Blend_Func set_mm_blend; + FT_Get_MM_Var_Func get_mm_var; + FT_Set_Var_Design_Func set_var_design; + }; + +#ifndef FT_CONFIG_OPTION_PIC + +#define FT_DEFINE_SERVICE_MULTIMASTERSREC(class_, get_mm_, set_mm_design_, \ + set_mm_blend_, get_mm_var_, set_var_design_) \ + static const FT_Service_MultiMastersRec class_ = \ + { \ + get_mm_, set_mm_design_, set_mm_blend_, get_mm_var_, set_var_design_ \ + }; + +#else /* FT_CONFIG_OPTION_PIC */ + +#define FT_DEFINE_SERVICE_MULTIMASTERSREC(class_, get_mm_, set_mm_design_, \ + set_mm_blend_, get_mm_var_, set_var_design_) \ + void \ + FT_Init_Class_##class_( FT_Service_MultiMastersRec* clazz ) \ + { \ + clazz->get_mm = get_mm_; \ + clazz->set_mm_design = set_mm_design_; \ + clazz->set_mm_blend = set_mm_blend_; \ + clazz->get_mm_var = get_mm_var_; \ + clazz->set_var_design = set_var_design_; \ + } + +#endif /* FT_CONFIG_OPTION_PIC */ + + /* */ + + +FT_END_HEADER + +#endif /* __SVMM_H__ */ + + +/* END */ diff --git a/Lib/Include/freetype/internal/services/svotval.h b/Lib/Include/freetype/internal/services/svotval.h new file mode 100644 index 0000000..970bbd5 --- /dev/null +++ b/Lib/Include/freetype/internal/services/svotval.h @@ -0,0 +1,55 @@ +/***************************************************************************/ +/* */ +/* svotval.h */ +/* */ +/* The FreeType OpenType validation service (specification). */ +/* */ +/* Copyright 2004, 2006 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef __SVOTVAL_H__ +#define __SVOTVAL_H__ + +#include FT_OPENTYPE_VALIDATE_H +#include FT_INTERNAL_VALIDATE_H + +FT_BEGIN_HEADER + + +#define FT_SERVICE_ID_OPENTYPE_VALIDATE "opentype-validate" + + + typedef FT_Error + (*otv_validate_func)( FT_Face volatile face, + FT_UInt ot_flags, + FT_Bytes *base, + FT_Bytes *gdef, + FT_Bytes *gpos, + FT_Bytes *gsub, + FT_Bytes *jstf ); + + + FT_DEFINE_SERVICE( OTvalidate ) + { + otv_validate_func validate; + }; + + /* */ + + +FT_END_HEADER + + +#endif /* __SVOTVAL_H__ */ + + +/* END */ diff --git a/Lib/Include/freetype/internal/services/svpfr.h b/Lib/Include/freetype/internal/services/svpfr.h new file mode 100644 index 0000000..462786f --- /dev/null +++ b/Lib/Include/freetype/internal/services/svpfr.h @@ -0,0 +1,66 @@ +/***************************************************************************/ +/* */ +/* svpfr.h */ +/* */ +/* Internal PFR service functions (specification). */ +/* */ +/* Copyright 2003, 2006 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef __SVPFR_H__ +#define __SVPFR_H__ + +#include FT_PFR_H +#include FT_INTERNAL_SERVICE_H + + +FT_BEGIN_HEADER + + +#define FT_SERVICE_ID_PFR_METRICS "pfr-metrics" + + + typedef FT_Error + (*FT_PFR_GetMetricsFunc)( FT_Face face, + FT_UInt *aoutline, + FT_UInt *ametrics, + FT_Fixed *ax_scale, + FT_Fixed *ay_scale ); + + typedef FT_Error + (*FT_PFR_GetKerningFunc)( FT_Face face, + FT_UInt left, + FT_UInt right, + FT_Vector *avector ); + + typedef FT_Error + (*FT_PFR_GetAdvanceFunc)( FT_Face face, + FT_UInt gindex, + FT_Pos *aadvance ); + + + FT_DEFINE_SERVICE( PfrMetrics ) + { + FT_PFR_GetMetricsFunc get_metrics; + FT_PFR_GetKerningFunc get_kerning; + FT_PFR_GetAdvanceFunc get_advance; + + }; + + /* */ + +FT_END_HEADER + +#endif /* __SVPFR_H__ */ + + +/* END */ diff --git a/Lib/Include/freetype/internal/services/svpostnm.h b/Lib/Include/freetype/internal/services/svpostnm.h new file mode 100644 index 0000000..106c54f --- /dev/null +++ b/Lib/Include/freetype/internal/services/svpostnm.h @@ -0,0 +1,79 @@ +/***************************************************************************/ +/* */ +/* svpostnm.h */ +/* */ +/* The FreeType PostScript name services (specification). */ +/* */ +/* Copyright 2003, 2007 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef __SVPOSTNM_H__ +#define __SVPOSTNM_H__ + +#include FT_INTERNAL_SERVICE_H + + +FT_BEGIN_HEADER + + /* + * A trivial service used to retrieve the PostScript name of a given + * font when available. The `get_name' field should never be NULL. + * + * The corresponding function can return NULL to indicate that the + * PostScript name is not available. + * + * The name is owned by the face and will be destroyed with it. + */ + +#define FT_SERVICE_ID_POSTSCRIPT_FONT_NAME "postscript-font-name" + + + typedef const char* + (*FT_PsName_GetFunc)( FT_Face face ); + + + FT_DEFINE_SERVICE( PsFontName ) + { + FT_PsName_GetFunc get_ps_font_name; + }; + +#ifndef FT_CONFIG_OPTION_PIC + +#define FT_DEFINE_SERVICE_PSFONTNAMEREC(class_, get_ps_font_name_) \ + static const FT_Service_PsFontNameRec class_ = \ + { \ + get_ps_font_name_ \ + }; + +#else /* FT_CONFIG_OPTION_PIC */ + +#define FT_DEFINE_SERVICE_PSFONTNAMEREC(class_, get_ps_font_name_) \ + void \ + FT_Init_Class_##class_( FT_Library library, \ + FT_Service_PsFontNameRec* clazz) \ + { \ + FT_UNUSED(library); \ + clazz->get_ps_font_name = get_ps_font_name_; \ + } + +#endif /* FT_CONFIG_OPTION_PIC */ + + /* */ + + +FT_END_HEADER + + +#endif /* __SVPOSTNM_H__ */ + + +/* END */ diff --git a/Lib/Include/freetype/internal/services/svpscmap.h b/Lib/Include/freetype/internal/services/svpscmap.h new file mode 100644 index 0000000..961030c --- /dev/null +++ b/Lib/Include/freetype/internal/services/svpscmap.h @@ -0,0 +1,164 @@ +/***************************************************************************/ +/* */ +/* svpscmap.h */ +/* */ +/* The FreeType PostScript charmap service (specification). */ +/* */ +/* Copyright 2003, 2006 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef __SVPSCMAP_H__ +#define __SVPSCMAP_H__ + +#include FT_INTERNAL_OBJECTS_H + + +FT_BEGIN_HEADER + + +#define FT_SERVICE_ID_POSTSCRIPT_CMAPS "postscript-cmaps" + + + /* + * Adobe glyph name to unicode value. + */ + typedef FT_UInt32 + (*PS_Unicode_ValueFunc)( const char* glyph_name ); + + /* + * Macintosh name id to glyph name. NULL if invalid index. + */ + typedef const char* + (*PS_Macintosh_NameFunc)( FT_UInt name_index ); + + /* + * Adobe standard string ID to glyph name. NULL if invalid index. + */ + typedef const char* + (*PS_Adobe_Std_StringsFunc)( FT_UInt string_index ); + + + /* + * Simple unicode -> glyph index charmap built from font glyph names + * table. + */ + typedef struct PS_UniMap_ + { + FT_UInt32 unicode; /* bit 31 set: is glyph variant */ + FT_UInt glyph_index; + + } PS_UniMap; + + + typedef struct PS_UnicodesRec_* PS_Unicodes; + + typedef struct PS_UnicodesRec_ + { + FT_CMapRec cmap; + FT_UInt num_maps; + PS_UniMap* maps; + + } PS_UnicodesRec; + + + /* + * A function which returns a glyph name for a given index. Returns + * NULL if invalid index. + */ + typedef const char* + (*PS_GetGlyphNameFunc)( FT_Pointer data, + FT_UInt string_index ); + + /* + * A function used to release the glyph name returned by + * PS_GetGlyphNameFunc, when needed + */ + typedef void + (*PS_FreeGlyphNameFunc)( FT_Pointer data, + const char* name ); + + typedef FT_Error + (*PS_Unicodes_InitFunc)( FT_Memory memory, + PS_Unicodes unicodes, + FT_UInt num_glyphs, + PS_GetGlyphNameFunc get_glyph_name, + PS_FreeGlyphNameFunc free_glyph_name, + FT_Pointer glyph_data ); + + typedef FT_UInt + (*PS_Unicodes_CharIndexFunc)( PS_Unicodes unicodes, + FT_UInt32 unicode ); + + typedef FT_UInt32 + (*PS_Unicodes_CharNextFunc)( PS_Unicodes unicodes, + FT_UInt32 *unicode ); + + + FT_DEFINE_SERVICE( PsCMaps ) + { + PS_Unicode_ValueFunc unicode_value; + + PS_Unicodes_InitFunc unicodes_init; + PS_Unicodes_CharIndexFunc unicodes_char_index; + PS_Unicodes_CharNextFunc unicodes_char_next; + + PS_Macintosh_NameFunc macintosh_name; + PS_Adobe_Std_StringsFunc adobe_std_strings; + const unsigned short* adobe_std_encoding; + const unsigned short* adobe_expert_encoding; + }; + + +#ifndef FT_CONFIG_OPTION_PIC + +#define FT_DEFINE_SERVICE_PSCMAPSREC(class_, unicode_value_, unicodes_init_, \ + unicodes_char_index_, unicodes_char_next_, macintosh_name_, \ + adobe_std_strings_, adobe_std_encoding_, adobe_expert_encoding_) \ + static const FT_Service_PsCMapsRec class_ = \ + { \ + unicode_value_, unicodes_init_, \ + unicodes_char_index_, unicodes_char_next_, macintosh_name_, \ + adobe_std_strings_, adobe_std_encoding_, adobe_expert_encoding_ \ + }; + +#else /* FT_CONFIG_OPTION_PIC */ + +#define FT_DEFINE_SERVICE_PSCMAPSREC(class_, unicode_value_, unicodes_init_, \ + unicodes_char_index_, unicodes_char_next_, macintosh_name_, \ + adobe_std_strings_, adobe_std_encoding_, adobe_expert_encoding_) \ + void \ + FT_Init_Class_##class_( FT_Library library, \ + FT_Service_PsCMapsRec* clazz) \ + { \ + FT_UNUSED(library); \ + clazz->unicode_value = unicode_value_; \ + clazz->unicodes_init = unicodes_init_; \ + clazz->unicodes_char_index = unicodes_char_index_; \ + clazz->unicodes_char_next = unicodes_char_next_; \ + clazz->macintosh_name = macintosh_name_; \ + clazz->adobe_std_strings = adobe_std_strings_; \ + clazz->adobe_std_encoding = adobe_std_encoding_; \ + clazz->adobe_expert_encoding = adobe_expert_encoding_; \ + } + +#endif /* FT_CONFIG_OPTION_PIC */ + + /* */ + + +FT_END_HEADER + + +#endif /* __SVPSCMAP_H__ */ + + +/* END */ diff --git a/Lib/Include/freetype/internal/services/svpsinfo.h b/Lib/Include/freetype/internal/services/svpsinfo.h new file mode 100644 index 0000000..91ba91e --- /dev/null +++ b/Lib/Include/freetype/internal/services/svpsinfo.h @@ -0,0 +1,92 @@ +/***************************************************************************/ +/* */ +/* svpsinfo.h */ +/* */ +/* The FreeType PostScript info service (specification). */ +/* */ +/* Copyright 2003, 2004, 2009 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef __SVPSINFO_H__ +#define __SVPSINFO_H__ + +#include FT_INTERNAL_SERVICE_H +#include FT_INTERNAL_TYPE1_TYPES_H + + +FT_BEGIN_HEADER + + +#define FT_SERVICE_ID_POSTSCRIPT_INFO "postscript-info" + + + typedef FT_Error + (*PS_GetFontInfoFunc)( FT_Face face, + PS_FontInfoRec* afont_info ); + + typedef FT_Error + (*PS_GetFontExtraFunc)( FT_Face face, + PS_FontExtraRec* afont_extra ); + + typedef FT_Int + (*PS_HasGlyphNamesFunc)( FT_Face face ); + + typedef FT_Error + (*PS_GetFontPrivateFunc)( FT_Face face, + PS_PrivateRec* afont_private ); + + + FT_DEFINE_SERVICE( PsInfo ) + { + PS_GetFontInfoFunc ps_get_font_info; + PS_GetFontExtraFunc ps_get_font_extra; + PS_HasGlyphNamesFunc ps_has_glyph_names; + PS_GetFontPrivateFunc ps_get_font_private; + }; + +#ifndef FT_CONFIG_OPTION_PIC + +#define FT_DEFINE_SERVICE_PSINFOREC(class_, get_font_info_, \ + ps_get_font_extra_, has_glyph_names_, get_font_private_) \ + static const FT_Service_PsInfoRec class_ = \ + { \ + get_font_info_, ps_get_font_extra_, has_glyph_names_, \ + get_font_private_ \ + }; + +#else /* FT_CONFIG_OPTION_PIC */ + +#define FT_DEFINE_SERVICE_PSINFOREC(class_, get_font_info_, \ + ps_get_font_extra_, has_glyph_names_, get_font_private_) \ + void \ + FT_Init_Class_##class_( FT_Library library, \ + FT_Service_PsInfoRec* clazz) \ + { \ + FT_UNUSED(library); \ + clazz->ps_get_font_info = get_font_info_; \ + clazz->ps_get_font_extra = ps_get_font_extra_; \ + clazz->ps_has_glyph_names = has_glyph_names_; \ + clazz->ps_get_font_private = get_font_private_; \ + } + +#endif /* FT_CONFIG_OPTION_PIC */ + + /* */ + + +FT_END_HEADER + + +#endif /* __SVPSINFO_H__ */ + + +/* END */ diff --git a/Lib/Include/freetype/internal/services/svsfnt.h b/Lib/Include/freetype/internal/services/svsfnt.h new file mode 100644 index 0000000..30bb162 --- /dev/null +++ b/Lib/Include/freetype/internal/services/svsfnt.h @@ -0,0 +1,102 @@ +/***************************************************************************/ +/* */ +/* svsfnt.h */ +/* */ +/* The FreeType SFNT table loading service (specification). */ +/* */ +/* Copyright 2003, 2004 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef __SVSFNT_H__ +#define __SVSFNT_H__ + +#include FT_INTERNAL_SERVICE_H +#include FT_TRUETYPE_TABLES_H + + +FT_BEGIN_HEADER + + + /* + * SFNT table loading service. + */ + +#define FT_SERVICE_ID_SFNT_TABLE "sfnt-table" + + + /* + * Used to implement FT_Load_Sfnt_Table(). + */ + typedef FT_Error + (*FT_SFNT_TableLoadFunc)( FT_Face face, + FT_ULong tag, + FT_Long offset, + FT_Byte* buffer, + FT_ULong* length ); + + /* + * Used to implement FT_Get_Sfnt_Table(). + */ + typedef void* + (*FT_SFNT_TableGetFunc)( FT_Face face, + FT_Sfnt_Tag tag ); + + + /* + * Used to implement FT_Sfnt_Table_Info(). + */ + typedef FT_Error + (*FT_SFNT_TableInfoFunc)( FT_Face face, + FT_UInt idx, + FT_ULong *tag, + FT_ULong *offset, + FT_ULong *length ); + + + FT_DEFINE_SERVICE( SFNT_Table ) + { + FT_SFNT_TableLoadFunc load_table; + FT_SFNT_TableGetFunc get_table; + FT_SFNT_TableInfoFunc table_info; + }; + +#ifndef FT_CONFIG_OPTION_PIC + +#define FT_DEFINE_SERVICE_SFNT_TABLEREC(class_, load_, get_, info_) \ + static const FT_Service_SFNT_TableRec class_ = \ + { \ + load_, get_, info_ \ + }; + +#else /* FT_CONFIG_OPTION_PIC */ + +#define FT_DEFINE_SERVICE_SFNT_TABLEREC(class_, load_, get_, info_) \ + void \ + FT_Init_Class_##class_( FT_Service_SFNT_TableRec* clazz ) \ + { \ + clazz->load_table = load_; \ + clazz->get_table = get_; \ + clazz->table_info = info_; \ + } + +#endif /* FT_CONFIG_OPTION_PIC */ + + /* */ + + +FT_END_HEADER + + +#endif /* __SVSFNT_H__ */ + + +/* END */ diff --git a/Lib/Include/freetype/internal/services/svttcmap.h b/Lib/Include/freetype/internal/services/svttcmap.h new file mode 100644 index 0000000..8af0035 --- /dev/null +++ b/Lib/Include/freetype/internal/services/svttcmap.h @@ -0,0 +1,106 @@ +/***************************************************************************/ +/* */ +/* svttcmap.h */ +/* */ +/* The FreeType TrueType/sfnt cmap extra information service. */ +/* */ +/* Copyright 2003 by */ +/* Masatake YAMATO, Redhat K.K. */ +/* */ +/* Copyright 2003, 2008 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + +/* Development of this service is support of + Information-technology Promotion Agency, Japan. */ + +#ifndef __SVTTCMAP_H__ +#define __SVTTCMAP_H__ + +#include FT_INTERNAL_SERVICE_H +#include FT_TRUETYPE_TABLES_H + + +FT_BEGIN_HEADER + + +#define FT_SERVICE_ID_TT_CMAP "tt-cmaps" + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* TT_CMapInfo */ + /* */ + /* <Description> */ + /* A structure used to store TrueType/sfnt specific cmap information */ + /* which is not covered by the generic @FT_CharMap structure. This */ + /* structure can be accessed with the @FT_Get_TT_CMap_Info function. */ + /* */ + /* <Fields> */ + /* language :: */ + /* The language ID used in Mac fonts. Definitions of values are in */ + /* freetype/ttnameid.h. */ + /* */ + /* format :: */ + /* The cmap format. OpenType 1.5 defines the formats 0 (byte */ + /* encoding table), 2~(high-byte mapping through table), 4~(segment */ + /* mapping to delta values), 6~(trimmed table mapping), 8~(mixed */ + /* 16-bit and 32-bit coverage), 10~(trimmed array), 12~(segmented */ + /* coverage), and 14 (Unicode Variation Sequences). */ + /* */ + typedef struct TT_CMapInfo_ + { + FT_ULong language; + FT_Long format; + + } TT_CMapInfo; + + + typedef FT_Error + (*TT_CMap_Info_GetFunc)( FT_CharMap charmap, + TT_CMapInfo *cmap_info ); + + + FT_DEFINE_SERVICE( TTCMaps ) + { + TT_CMap_Info_GetFunc get_cmap_info; + }; + +#ifndef FT_CONFIG_OPTION_PIC + +#define FT_DEFINE_SERVICE_TTCMAPSREC(class_, get_cmap_info_) \ + static const FT_Service_TTCMapsRec class_ = \ + { \ + get_cmap_info_ \ + }; + +#else /* FT_CONFIG_OPTION_PIC */ + +#define FT_DEFINE_SERVICE_TTCMAPSREC(class_, get_cmap_info_) \ + void \ + FT_Init_Class_##class_( FT_Library library, \ + FT_Service_TTCMapsRec* clazz) \ + { \ + FT_UNUSED(library); \ + clazz->get_cmap_info = get_cmap_info_; \ + } + +#endif /* FT_CONFIG_OPTION_PIC */ + + /* */ + + +FT_END_HEADER + +#endif /* __SVTTCMAP_H__ */ + + +/* END */ diff --git a/Lib/Include/freetype/internal/services/svtteng.h b/Lib/Include/freetype/internal/services/svtteng.h new file mode 100644 index 0000000..58e02a6 --- /dev/null +++ b/Lib/Include/freetype/internal/services/svtteng.h @@ -0,0 +1,53 @@ +/***************************************************************************/ +/* */ +/* svtteng.h */ +/* */ +/* The FreeType TrueType engine query service (specification). */ +/* */ +/* Copyright 2006 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef __SVTTENG_H__ +#define __SVTTENG_H__ + +#include FT_INTERNAL_SERVICE_H +#include FT_MODULE_H + + +FT_BEGIN_HEADER + + + /* + * SFNT table loading service. + */ + +#define FT_SERVICE_ID_TRUETYPE_ENGINE "truetype-engine" + + /* + * Used to implement FT_Get_TrueType_Engine_Type + */ + + FT_DEFINE_SERVICE( TrueTypeEngine ) + { + FT_TrueTypeEngineType engine_type; + }; + + /* */ + + +FT_END_HEADER + + +#endif /* __SVTTENG_H__ */ + + +/* END */ diff --git a/Lib/Include/freetype/internal/services/svttglyf.h b/Lib/Include/freetype/internal/services/svttglyf.h new file mode 100644 index 0000000..ab2dc9a --- /dev/null +++ b/Lib/Include/freetype/internal/services/svttglyf.h @@ -0,0 +1,67 @@ +/***************************************************************************/ +/* */ +/* svttglyf.h */ +/* */ +/* The FreeType TrueType glyph service. */ +/* */ +/* Copyright 2007 by David Turner. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + +#ifndef __SVTTGLYF_H__ +#define __SVTTGLYF_H__ + +#include FT_INTERNAL_SERVICE_H +#include FT_TRUETYPE_TABLES_H + + +FT_BEGIN_HEADER + + +#define FT_SERVICE_ID_TT_GLYF "tt-glyf" + + + typedef FT_ULong + (*TT_Glyf_GetLocationFunc)( FT_Face face, + FT_UInt gindex, + FT_ULong *psize ); + + FT_DEFINE_SERVICE( TTGlyf ) + { + TT_Glyf_GetLocationFunc get_location; + }; + +#ifndef FT_CONFIG_OPTION_PIC + +#define FT_DEFINE_SERVICE_TTGLYFREC(class_, get_location_ ) \ + static const FT_Service_TTGlyfRec class_ = \ + { \ + get_location_ \ + }; + +#else /* FT_CONFIG_OPTION_PIC */ + +#define FT_DEFINE_SERVICE_TTGLYFREC(class_, get_location_ ) \ + void \ + FT_Init_Class_##class_( FT_Service_TTGlyfRec* clazz ) \ + { \ + clazz->get_location = get_location_; \ + } + +#endif /* FT_CONFIG_OPTION_PIC */ + + /* */ + + +FT_END_HEADER + +#endif /* __SVTTGLYF_H__ */ + + +/* END */ diff --git a/Lib/Include/freetype/internal/services/svwinfnt.h b/Lib/Include/freetype/internal/services/svwinfnt.h new file mode 100644 index 0000000..57f7765 --- /dev/null +++ b/Lib/Include/freetype/internal/services/svwinfnt.h @@ -0,0 +1,50 @@ +/***************************************************************************/ +/* */ +/* svwinfnt.h */ +/* */ +/* The FreeType Windows FNT/FONT service (specification). */ +/* */ +/* Copyright 2003 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef __SVWINFNT_H__ +#define __SVWINFNT_H__ + +#include FT_INTERNAL_SERVICE_H +#include FT_WINFONTS_H + + +FT_BEGIN_HEADER + + +#define FT_SERVICE_ID_WINFNT "winfonts" + + typedef FT_Error + (*FT_WinFnt_GetHeaderFunc)( FT_Face face, + FT_WinFNT_HeaderRec *aheader ); + + + FT_DEFINE_SERVICE( WinFnt ) + { + FT_WinFnt_GetHeaderFunc get_header; + }; + + /* */ + + +FT_END_HEADER + + +#endif /* __SVWINFNT_H__ */ + + +/* END */ diff --git a/Lib/Include/freetype/internal/services/svxf86nm.h b/Lib/Include/freetype/internal/services/svxf86nm.h new file mode 100644 index 0000000..ca5d884 --- /dev/null +++ b/Lib/Include/freetype/internal/services/svxf86nm.h @@ -0,0 +1,55 @@ +/***************************************************************************/ +/* */ +/* svxf86nm.h */ +/* */ +/* The FreeType XFree86 services (specification only). */ +/* */ +/* Copyright 2003 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef __SVXF86NM_H__ +#define __SVXF86NM_H__ + +#include FT_INTERNAL_SERVICE_H + + +FT_BEGIN_HEADER + + + /* + * A trivial service used to return the name of a face's font driver, + * according to the XFree86 nomenclature. Note that the service data + * is a simple constant string pointer. + */ + +#define FT_SERVICE_ID_XF86_NAME "xf86-driver-name" + +#define FT_XF86_FORMAT_TRUETYPE "TrueType" +#define FT_XF86_FORMAT_TYPE_1 "Type 1" +#define FT_XF86_FORMAT_BDF "BDF" +#define FT_XF86_FORMAT_PCF "PCF" +#define FT_XF86_FORMAT_TYPE_42 "Type 42" +#define FT_XF86_FORMAT_CID "CID Type 1" +#define FT_XF86_FORMAT_CFF "CFF" +#define FT_XF86_FORMAT_PFR "PFR" +#define FT_XF86_FORMAT_WINFNT "Windows FNT" + + /* */ + + +FT_END_HEADER + + +#endif /* __SVXF86NM_H__ */ + + +/* END */ diff --git a/Lib/Include/freetype/internal/sfnt.h b/Lib/Include/freetype/internal/sfnt.h new file mode 100644 index 0000000..6326deb --- /dev/null +++ b/Lib/Include/freetype/internal/sfnt.h @@ -0,0 +1,897 @@ +/***************************************************************************/ +/* */ +/* sfnt.h */ +/* */ +/* High-level `sfnt' driver interface (specification). */ +/* */ +/* Copyright 1996-2001, 2002, 2003, 2004, 2005, 2006 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef __SFNT_H__ +#define __SFNT_H__ + + +#include <ft2build.h> +#include FT_INTERNAL_DRIVER_H +#include FT_INTERNAL_TRUETYPE_TYPES_H + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /* */ + /* <FuncType> */ + /* TT_Init_Face_Func */ + /* */ + /* <Description> */ + /* First part of the SFNT face object initialization. This finds */ + /* the face in a SFNT file or collection, and load its format tag in */ + /* face->format_tag. */ + /* */ + /* <Input> */ + /* stream :: The input stream. */ + /* */ + /* face :: A handle to the target face object. */ + /* */ + /* face_index :: The index of the TrueType font, if we are opening a */ + /* collection. */ + /* */ + /* num_params :: The number of additional parameters. */ + /* */ + /* params :: Optional additional parameters. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + /* <Note> */ + /* The stream cursor must be at the font file's origin. */ + /* */ + /* This function recognizes fonts embedded in a `TrueType */ + /* collection'. */ + /* */ + /* Once the format tag has been validated by the font driver, it */ + /* should then call the TT_Load_Face_Func() callback to read the rest */ + /* of the SFNT tables in the object. */ + /* */ + typedef FT_Error + (*TT_Init_Face_Func)( FT_Stream stream, + TT_Face face, + FT_Int face_index, + FT_Int num_params, + FT_Parameter* params ); + + + /*************************************************************************/ + /* */ + /* <FuncType> */ + /* TT_Load_Face_Func */ + /* */ + /* <Description> */ + /* Second part of the SFNT face object initialization. This loads */ + /* the common SFNT tables (head, OS/2, maxp, metrics, etc.) in the */ + /* face object. */ + /* */ + /* <Input> */ + /* stream :: The input stream. */ + /* */ + /* face :: A handle to the target face object. */ + /* */ + /* face_index :: The index of the TrueType font, if we are opening a */ + /* collection. */ + /* */ + /* num_params :: The number of additional parameters. */ + /* */ + /* params :: Optional additional parameters. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + /* <Note> */ + /* This function must be called after TT_Init_Face_Func(). */ + /* */ + typedef FT_Error + (*TT_Load_Face_Func)( FT_Stream stream, + TT_Face face, + FT_Int face_index, + FT_Int num_params, + FT_Parameter* params ); + + + /*************************************************************************/ + /* */ + /* <FuncType> */ + /* TT_Done_Face_Func */ + /* */ + /* <Description> */ + /* A callback used to delete the common SFNT data from a face. */ + /* */ + /* <Input> */ + /* face :: A handle to the target face object. */ + /* */ + /* <Note> */ + /* This function does NOT destroy the face object. */ + /* */ + typedef void + (*TT_Done_Face_Func)( TT_Face face ); + + +#ifdef FT_CONFIG_OPTION_OLD_INTERNALS + + /*************************************************************************/ + /* */ + /* <FuncType> */ + /* TT_Load_SFNT_HeaderRec_Func */ + /* */ + /* <Description> */ + /* Loads the header of a SFNT font file. Supports collections. */ + /* */ + /* <Input> */ + /* face :: A handle to the target face object. */ + /* */ + /* stream :: The input stream. */ + /* */ + /* face_index :: The index of the TrueType font, if we are opening a */ + /* collection. */ + /* */ + /* <Output> */ + /* sfnt :: The SFNT header. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + /* <Note> */ + /* The stream cursor must be at the font file's origin. */ + /* */ + /* This function recognizes fonts embedded in a `TrueType */ + /* collection'. */ + /* */ + /* This function checks that the header is valid by looking at the */ + /* values of `search_range', `entry_selector', and `range_shift'. */ + /* */ + typedef FT_Error + (*TT_Load_SFNT_HeaderRec_Func)( TT_Face face, + FT_Stream stream, + FT_Long face_index, + SFNT_Header sfnt ); + + + /*************************************************************************/ + /* */ + /* <FuncType> */ + /* TT_Load_Directory_Func */ + /* */ + /* <Description> */ + /* Loads the table directory into a face object. */ + /* */ + /* <Input> */ + /* face :: A handle to the target face object. */ + /* */ + /* stream :: The input stream. */ + /* */ + /* sfnt :: The SFNT header. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + /* <Note> */ + /* The stream cursor must be on the first byte after the 4-byte font */ + /* format tag. This is the case just after a call to */ + /* TT_Load_Format_Tag(). */ + /* */ + typedef FT_Error + (*TT_Load_Directory_Func)( TT_Face face, + FT_Stream stream, + SFNT_Header sfnt ); + +#endif /* FT_CONFIG_OPTION_OLD_INTERNALS */ + + + /*************************************************************************/ + /* */ + /* <FuncType> */ + /* TT_Load_Any_Func */ + /* */ + /* <Description> */ + /* Load any font table into client memory. */ + /* */ + /* <Input> */ + /* face :: The face object to look for. */ + /* */ + /* tag :: The tag of table to load. Use the value 0 if you want */ + /* to access the whole font file, else set this parameter */ + /* to a valid TrueType table tag that you can forge with */ + /* the MAKE_TT_TAG macro. */ + /* */ + /* offset :: The starting offset in the table (or the file if */ + /* tag == 0). */ + /* */ + /* length :: The address of the decision variable: */ + /* */ + /* If length == NULL: */ + /* Loads the whole table. Returns an error if */ + /* `offset' == 0! */ + /* */ + /* If *length == 0: */ + /* Exits immediately; returning the length of the given */ + /* table or of the font file, depending on the value of */ + /* `tag'. */ + /* */ + /* If *length != 0: */ + /* Loads the next `length' bytes of table or font, */ + /* starting at offset `offset' (in table or font too). */ + /* */ + /* <Output> */ + /* buffer :: The address of target buffer. */ + /* */ + /* <Return> */ + /* TrueType error code. 0 means success. */ + /* */ + typedef FT_Error + (*TT_Load_Any_Func)( TT_Face face, + FT_ULong tag, + FT_Long offset, + FT_Byte *buffer, + FT_ULong* length ); + + + /*************************************************************************/ + /* */ + /* <FuncType> */ + /* TT_Find_SBit_Image_Func */ + /* */ + /* <Description> */ + /* Check whether an embedded bitmap (an `sbit') exists for a given */ + /* glyph, at a given strike. */ + /* */ + /* <Input> */ + /* face :: The target face object. */ + /* */ + /* glyph_index :: The glyph index. */ + /* */ + /* strike_index :: The current strike index. */ + /* */ + /* <Output> */ + /* arange :: The SBit range containing the glyph index. */ + /* */ + /* astrike :: The SBit strike containing the glyph index. */ + /* */ + /* aglyph_offset :: The offset of the glyph data in `EBDT' table. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. Returns */ + /* SFNT_Err_Invalid_Argument if no sbit exists for the requested */ + /* glyph. */ + /* */ + typedef FT_Error + (*TT_Find_SBit_Image_Func)( TT_Face face, + FT_UInt glyph_index, + FT_ULong strike_index, + TT_SBit_Range *arange, + TT_SBit_Strike *astrike, + FT_ULong *aglyph_offset ); + + + /*************************************************************************/ + /* */ + /* <FuncType> */ + /* TT_Load_SBit_Metrics_Func */ + /* */ + /* <Description> */ + /* Get the big metrics for a given embedded bitmap. */ + /* */ + /* <Input> */ + /* stream :: The input stream. */ + /* */ + /* range :: The SBit range containing the glyph. */ + /* */ + /* <Output> */ + /* big_metrics :: A big SBit metrics structure for the glyph. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + /* <Note> */ + /* The stream cursor must be positioned at the glyph's offset within */ + /* the `EBDT' table before the call. */ + /* */ + /* If the image format uses variable metrics, the stream cursor is */ + /* positioned just after the metrics header in the `EBDT' table on */ + /* function exit. */ + /* */ + typedef FT_Error + (*TT_Load_SBit_Metrics_Func)( FT_Stream stream, + TT_SBit_Range range, + TT_SBit_Metrics metrics ); + + + /*************************************************************************/ + /* */ + /* <FuncType> */ + /* TT_Load_SBit_Image_Func */ + /* */ + /* <Description> */ + /* Load a given glyph sbit image from the font resource. This also */ + /* returns its metrics. */ + /* */ + /* <Input> */ + /* face :: */ + /* The target face object. */ + /* */ + /* strike_index :: */ + /* The strike index. */ + /* */ + /* glyph_index :: */ + /* The current glyph index. */ + /* */ + /* load_flags :: */ + /* The current load flags. */ + /* */ + /* stream :: */ + /* The input stream. */ + /* */ + /* <Output> */ + /* amap :: */ + /* The target pixmap. */ + /* */ + /* ametrics :: */ + /* A big sbit metrics structure for the glyph image. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. Returns an error if no */ + /* glyph sbit exists for the index. */ + /* */ + /* <Note> */ + /* The `map.buffer' field is always freed before the glyph is loaded. */ + /* */ + typedef FT_Error + (*TT_Load_SBit_Image_Func)( TT_Face face, + FT_ULong strike_index, + FT_UInt glyph_index, + FT_UInt load_flags, + FT_Stream stream, + FT_Bitmap *amap, + TT_SBit_MetricsRec *ametrics ); + + +#ifdef FT_CONFIG_OPTION_OLD_INTERNALS + + /*************************************************************************/ + /* */ + /* <FuncType> */ + /* TT_Set_SBit_Strike_OldFunc */ + /* */ + /* <Description> */ + /* Select an sbit strike for a given size request. */ + /* */ + /* <Input> */ + /* face :: The target face object. */ + /* */ + /* req :: The size request. */ + /* */ + /* <Output> */ + /* astrike_index :: The index of the sbit strike. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. Returns an error if no */ + /* sbit strike exists for the selected ppem values. */ + /* */ + typedef FT_Error + (*TT_Set_SBit_Strike_OldFunc)( TT_Face face, + FT_UInt x_ppem, + FT_UInt y_ppem, + FT_ULong* astrike_index ); + + + /*************************************************************************/ + /* */ + /* <FuncType> */ + /* TT_CharMap_Load_Func */ + /* */ + /* <Description> */ + /* Loads a given TrueType character map into memory. */ + /* */ + /* <Input> */ + /* face :: A handle to the parent face object. */ + /* */ + /* stream :: A handle to the current stream object. */ + /* */ + /* <InOut> */ + /* cmap :: A pointer to a cmap object. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + /* <Note> */ + /* The function assumes that the stream is already in use (i.e., */ + /* opened). In case of error, all partially allocated tables are */ + /* released. */ + /* */ + typedef FT_Error + (*TT_CharMap_Load_Func)( TT_Face face, + void* cmap, + FT_Stream input ); + + + /*************************************************************************/ + /* */ + /* <FuncType> */ + /* TT_CharMap_Free_Func */ + /* */ + /* <Description> */ + /* Destroys a character mapping table. */ + /* */ + /* <Input> */ + /* face :: A handle to the parent face object. */ + /* */ + /* cmap :: A handle to a cmap object. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + typedef FT_Error + (*TT_CharMap_Free_Func)( TT_Face face, + void* cmap ); + +#endif /* FT_CONFIG_OPTION_OLD_INTERNALS */ + + + /*************************************************************************/ + /* */ + /* <FuncType> */ + /* TT_Set_SBit_Strike_Func */ + /* */ + /* <Description> */ + /* Select an sbit strike for a given size request. */ + /* */ + /* <Input> */ + /* face :: The target face object. */ + /* */ + /* req :: The size request. */ + /* */ + /* <Output> */ + /* astrike_index :: The index of the sbit strike. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. Returns an error if no */ + /* sbit strike exists for the selected ppem values. */ + /* */ + typedef FT_Error + (*TT_Set_SBit_Strike_Func)( TT_Face face, + FT_Size_Request req, + FT_ULong* astrike_index ); + + + /*************************************************************************/ + /* */ + /* <FuncType> */ + /* TT_Load_Strike_Metrics_Func */ + /* */ + /* <Description> */ + /* Load the metrics of a given strike. */ + /* */ + /* <Input> */ + /* face :: The target face object. */ + /* */ + /* strike_index :: The strike index. */ + /* */ + /* <Output> */ + /* metrics :: the metrics of the strike. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. Returns an error if no */ + /* such sbit strike exists. */ + /* */ + typedef FT_Error + (*TT_Load_Strike_Metrics_Func)( TT_Face face, + FT_ULong strike_index, + FT_Size_Metrics* metrics ); + + + /*************************************************************************/ + /* */ + /* <FuncType> */ + /* TT_Get_PS_Name_Func */ + /* */ + /* <Description> */ + /* Get the PostScript glyph name of a glyph. */ + /* */ + /* <Input> */ + /* idx :: The glyph index. */ + /* */ + /* PSname :: The address of a string pointer. Will be NULL in case */ + /* of error, otherwise it is a pointer to the glyph name. */ + /* */ + /* You must not modify the returned string! */ + /* */ + /* <Output> */ + /* FreeType error code. 0 means success. */ + /* */ + typedef FT_Error + (*TT_Get_PS_Name_Func)( TT_Face face, + FT_UInt idx, + FT_String** PSname ); + + + /*************************************************************************/ + /* */ + /* <FuncType> */ + /* TT_Load_Metrics_Func */ + /* */ + /* <Description> */ + /* Load a metrics table, which is a table with a horizontal and a */ + /* vertical version. */ + /* */ + /* <Input> */ + /* face :: A handle to the target face object. */ + /* */ + /* stream :: The input stream. */ + /* */ + /* vertical :: A boolean flag. If set, load the vertical one. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + typedef FT_Error + (*TT_Load_Metrics_Func)( TT_Face face, + FT_Stream stream, + FT_Bool vertical ); + + + /*************************************************************************/ + /* */ + /* <FuncType> */ + /* TT_Get_Metrics_Func */ + /* */ + /* <Description> */ + /* Load the horizontal or vertical header in a face object. */ + /* */ + /* <Input> */ + /* face :: A handle to the target face object. */ + /* */ + /* stream :: The input stream. */ + /* */ + /* vertical :: A boolean flag. If set, load vertical metrics. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + typedef FT_Error + (*TT_Get_Metrics_Func)( TT_Face face, + FT_Bool vertical, + FT_UInt gindex, + FT_Short* abearing, + FT_UShort* aadvance ); + + + /*************************************************************************/ + /* */ + /* <FuncType> */ + /* TT_Load_Table_Func */ + /* */ + /* <Description> */ + /* Load a given TrueType table. */ + /* */ + /* <Input> */ + /* face :: A handle to the target face object. */ + /* */ + /* stream :: The input stream. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + /* <Note> */ + /* The function uses `face->goto_table' to seek the stream to the */ + /* start of the table, except while loading the font directory. */ + /* */ + typedef FT_Error + (*TT_Load_Table_Func)( TT_Face face, + FT_Stream stream ); + + + /*************************************************************************/ + /* */ + /* <FuncType> */ + /* TT_Free_Table_Func */ + /* */ + /* <Description> */ + /* Free a given TrueType table. */ + /* */ + /* <Input> */ + /* face :: A handle to the target face object. */ + /* */ + typedef void + (*TT_Free_Table_Func)( TT_Face face ); + + + /* + * @functype: + * TT_Face_GetKerningFunc + * + * @description: + * Return the horizontal kerning value between two glyphs. + * + * @input: + * face :: A handle to the source face object. + * left_glyph :: The left glyph index. + * right_glyph :: The right glyph index. + * + * @return: + * The kerning value in font units. + */ + typedef FT_Int + (*TT_Face_GetKerningFunc)( TT_Face face, + FT_UInt left_glyph, + FT_UInt right_glyph ); + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* SFNT_Interface */ + /* */ + /* <Description> */ + /* This structure holds pointers to the functions used to load and */ + /* free the basic tables that are required in a `sfnt' font file. */ + /* */ + /* <Fields> */ + /* Check the various xxx_Func() descriptions for details. */ + /* */ + typedef struct SFNT_Interface_ + { + TT_Loader_GotoTableFunc goto_table; + + TT_Init_Face_Func init_face; + TT_Load_Face_Func load_face; + TT_Done_Face_Func done_face; + FT_Module_Requester get_interface; + + TT_Load_Any_Func load_any; + +#ifdef FT_CONFIG_OPTION_OLD_INTERNALS + TT_Load_SFNT_HeaderRec_Func load_sfnt_header; + TT_Load_Directory_Func load_directory; +#endif + + /* these functions are called by `load_face' but they can also */ + /* be called from external modules, if there is a need to do so */ + TT_Load_Table_Func load_head; + TT_Load_Metrics_Func load_hhea; + TT_Load_Table_Func load_cmap; + TT_Load_Table_Func load_maxp; + TT_Load_Table_Func load_os2; + TT_Load_Table_Func load_post; + + TT_Load_Table_Func load_name; + TT_Free_Table_Func free_name; + + /* optional tables */ +#ifdef FT_CONFIG_OPTION_OLD_INTERNALS + TT_Load_Table_Func load_hdmx_stub; + TT_Free_Table_Func free_hdmx_stub; +#endif + + /* this field was called `load_kerning' up to version 2.1.10 */ + TT_Load_Table_Func load_kern; + + TT_Load_Table_Func load_gasp; + TT_Load_Table_Func load_pclt; + + /* see `ttload.h'; this field was called `load_bitmap_header' up to */ + /* version 2.1.10 */ + TT_Load_Table_Func load_bhed; + +#ifdef FT_CONFIG_OPTION_OLD_INTERNALS + + /* see `ttsbit.h' */ + TT_Set_SBit_Strike_OldFunc set_sbit_strike_stub; + TT_Load_Table_Func load_sbits_stub; + + /* + * The following two fields appeared in version 2.1.8, and were placed + * between `load_sbits' and `load_sbit_image'. We support them as a + * special exception since they are used by Xfont library within the + * X.Org xserver, and because the probability that other rogue clients + * use the other version 2.1.7 fields below is _extremely_ low. + * + * Note that this forces us to disable an interesting memory-saving + * optimization though... + */ + + TT_Find_SBit_Image_Func find_sbit_image; + TT_Load_SBit_Metrics_Func load_sbit_metrics; + +#endif + + TT_Load_SBit_Image_Func load_sbit_image; + +#ifdef FT_CONFIG_OPTION_OLD_INTERNALS + TT_Free_Table_Func free_sbits_stub; +#endif + + /* see `ttpost.h' */ + TT_Get_PS_Name_Func get_psname; + TT_Free_Table_Func free_psnames; + +#ifdef FT_CONFIG_OPTION_OLD_INTERNALS + TT_CharMap_Load_Func load_charmap_stub; + TT_CharMap_Free_Func free_charmap_stub; +#endif + + /* starting here, the structure differs from version 2.1.7 */ + + /* this field was introduced in version 2.1.8, named `get_psname' */ + TT_Face_GetKerningFunc get_kerning; + + /* new elements introduced after version 2.1.10 */ + + /* load the font directory, i.e., the offset table and */ + /* the table directory */ + TT_Load_Table_Func load_font_dir; + TT_Load_Metrics_Func load_hmtx; + + TT_Load_Table_Func load_eblc; + TT_Free_Table_Func free_eblc; + + TT_Set_SBit_Strike_Func set_sbit_strike; + TT_Load_Strike_Metrics_Func load_strike_metrics; + + TT_Get_Metrics_Func get_metrics; + + } SFNT_Interface; + + + /* transitional */ + typedef SFNT_Interface* SFNT_Service; + +#ifndef FT_CONFIG_OPTION_PIC + +#ifdef FT_CONFIG_OPTION_OLD_INTERNALS +#define FT_DEFINE_DRIVERS_OLD_INTERNAL(a) \ + a, +#else + #define FT_DEFINE_DRIVERS_OLD_INTERNAL(a) +#endif +#define FT_INTERNAL(a) \ + a, + +#define FT_DEFINE_SFNT_INTERFACE(class_, \ + goto_table_, init_face_, load_face_, done_face_, get_interface_, \ + load_any_, load_sfnt_header_, load_directory_, load_head_, \ + load_hhea_, load_cmap_, load_maxp_, load_os2_, load_post_, \ + load_name_, free_name_, load_hdmx_stub_, free_hdmx_stub_, \ + load_kern_, load_gasp_, load_pclt_, load_bhed_, \ + set_sbit_strike_stub_, load_sbits_stub_, find_sbit_image_, \ + load_sbit_metrics_, load_sbit_image_, free_sbits_stub_, \ + get_psname_, free_psnames_, load_charmap_stub_, free_charmap_stub_, \ + get_kerning_, load_font_dir_, load_hmtx_, load_eblc_, free_eblc_, \ + set_sbit_strike_, load_strike_metrics_, get_metrics_ ) \ + static const SFNT_Interface class_ = \ + { \ + FT_INTERNAL(goto_table_) \ + FT_INTERNAL(init_face_) \ + FT_INTERNAL(load_face_) \ + FT_INTERNAL(done_face_) \ + FT_INTERNAL(get_interface_) \ + FT_INTERNAL(load_any_) \ + FT_DEFINE_DRIVERS_OLD_INTERNAL(load_sfnt_header_) \ + FT_DEFINE_DRIVERS_OLD_INTERNAL(load_directory_) \ + FT_INTERNAL(load_head_) \ + FT_INTERNAL(load_hhea_) \ + FT_INTERNAL(load_cmap_) \ + FT_INTERNAL(load_maxp_) \ + FT_INTERNAL(load_os2_) \ + FT_INTERNAL(load_post_) \ + FT_INTERNAL(load_name_) \ + FT_INTERNAL(free_name_) \ + FT_DEFINE_DRIVERS_OLD_INTERNAL(load_hdmx_stub_) \ + FT_DEFINE_DRIVERS_OLD_INTERNAL(free_hdmx_stub_) \ + FT_INTERNAL(load_kern_) \ + FT_INTERNAL(load_gasp_) \ + FT_INTERNAL(load_pclt_) \ + FT_INTERNAL(load_bhed_) \ + FT_DEFINE_DRIVERS_OLD_INTERNAL(set_sbit_strike_stub_) \ + FT_DEFINE_DRIVERS_OLD_INTERNAL(load_sbits_stub_) \ + FT_DEFINE_DRIVERS_OLD_INTERNAL(find_sbit_image_) \ + FT_DEFINE_DRIVERS_OLD_INTERNAL(load_sbit_metrics_) \ + FT_INTERNAL(load_sbit_image_) \ + FT_DEFINE_DRIVERS_OLD_INTERNAL(free_sbits_stub_) \ + FT_INTERNAL(get_psname_) \ + FT_INTERNAL(free_psnames_) \ + FT_DEFINE_DRIVERS_OLD_INTERNAL(load_charmap_stub_) \ + FT_DEFINE_DRIVERS_OLD_INTERNAL(free_charmap_stub_) \ + FT_INTERNAL(get_kerning_) \ + FT_INTERNAL(load_font_dir_) \ + FT_INTERNAL(load_hmtx_) \ + FT_INTERNAL(load_eblc_) \ + FT_INTERNAL(free_eblc_) \ + FT_INTERNAL(set_sbit_strike_) \ + FT_INTERNAL(load_strike_metrics_) \ + FT_INTERNAL(get_metrics_) \ + }; + +#else /* FT_CONFIG_OPTION_PIC */ + +#ifdef FT_CONFIG_OPTION_OLD_INTERNALS +#define FT_DEFINE_DRIVERS_OLD_INTERNAL(a, a_) \ + clazz->a = a_; +#else + #define FT_DEFINE_DRIVERS_OLD_INTERNAL(a, a_) +#endif +#define FT_INTERNAL(a, a_) \ + clazz->a = a_; + +#define FT_DEFINE_SFNT_INTERFACE(class_, \ + goto_table_, init_face_, load_face_, done_face_, get_interface_, \ + load_any_, load_sfnt_header_, load_directory_, load_head_, \ + load_hhea_, load_cmap_, load_maxp_, load_os2_, load_post_, \ + load_name_, free_name_, load_hdmx_stub_, free_hdmx_stub_, \ + load_kern_, load_gasp_, load_pclt_, load_bhed_, \ + set_sbit_strike_stub_, load_sbits_stub_, find_sbit_image_, \ + load_sbit_metrics_, load_sbit_image_, free_sbits_stub_, \ + get_psname_, free_psnames_, load_charmap_stub_, free_charmap_stub_, \ + get_kerning_, load_font_dir_, load_hmtx_, load_eblc_, free_eblc_, \ + set_sbit_strike_, load_strike_metrics_, get_metrics_ ) \ + void \ + FT_Init_Class_##class_( FT_Library library, SFNT_Interface* clazz ) \ + { \ + FT_UNUSED(library); \ + FT_INTERNAL(goto_table,goto_table_) \ + FT_INTERNAL(init_face,init_face_) \ + FT_INTERNAL(load_face,load_face_) \ + FT_INTERNAL(done_face,done_face_) \ + FT_INTERNAL(get_interface,get_interface_) \ + FT_INTERNAL(load_any,load_any_) \ + FT_DEFINE_DRIVERS_OLD_INTERNAL(load_sfnt_header,load_sfnt_header_) \ + FT_DEFINE_DRIVERS_OLD_INTERNAL(load_directory,load_directory_) \ + FT_INTERNAL(load_head,load_head_) \ + FT_INTERNAL(load_hhea,load_hhea_) \ + FT_INTERNAL(load_cmap,load_cmap_) \ + FT_INTERNAL(load_maxp,load_maxp_) \ + FT_INTERNAL(load_os2,load_os2_) \ + FT_INTERNAL(load_post,load_post_) \ + FT_INTERNAL(load_name,load_name_) \ + FT_INTERNAL(free_name,free_name_) \ + FT_DEFINE_DRIVERS_OLD_INTERNAL(load_hdmx_stub,load_hdmx_stub_) \ + FT_DEFINE_DRIVERS_OLD_INTERNAL(free_hdmx_stub,free_hdmx_stub_) \ + FT_INTERNAL(load_kern,load_kern_) \ + FT_INTERNAL(load_gasp,load_gasp_) \ + FT_INTERNAL(load_pclt,load_pclt_) \ + FT_INTERNAL(load_bhed,load_bhed_) \ + FT_DEFINE_DRIVERS_OLD_INTERNAL(set_sbit_strike_stub,set_sbit_strike_stub_) \ + FT_DEFINE_DRIVERS_OLD_INTERNAL(load_sbits_stub,load_sbits_stub_) \ + FT_DEFINE_DRIVERS_OLD_INTERNAL(find_sbit_image,find_sbit_image_) \ + FT_DEFINE_DRIVERS_OLD_INTERNAL(load_sbit_metrics,load_sbit_metrics_) \ + FT_INTERNAL(load_sbit_image,load_sbit_image_) \ + FT_DEFINE_DRIVERS_OLD_INTERNAL(free_sbits_stub,free_sbits_stub_) \ + FT_INTERNAL(get_psname,get_psname_) \ + FT_INTERNAL(free_psnames,free_psnames_) \ + FT_DEFINE_DRIVERS_OLD_INTERNAL(load_charmap_stub,load_charmap_stub_) \ + FT_DEFINE_DRIVERS_OLD_INTERNAL(free_charmap_stub,free_charmap_stub_) \ + FT_INTERNAL(get_kerning,get_kerning_) \ + FT_INTERNAL(load_font_dir,load_font_dir_) \ + FT_INTERNAL(load_hmtx,load_hmtx_) \ + FT_INTERNAL(load_eblc,load_eblc_) \ + FT_INTERNAL(free_eblc,free_eblc_) \ + FT_INTERNAL(set_sbit_strike,set_sbit_strike_) \ + FT_INTERNAL(load_strike_metrics,load_strike_metrics_) \ + FT_INTERNAL(get_metrics,get_metrics_) \ + } + +#endif /* FT_CONFIG_OPTION_PIC */ + +FT_END_HEADER + +#endif /* __SFNT_H__ */ + + +/* END */ diff --git a/Lib/Include/freetype/internal/t1types.h b/Lib/Include/freetype/internal/t1types.h new file mode 100644 index 0000000..5f73063 --- /dev/null +++ b/Lib/Include/freetype/internal/t1types.h @@ -0,0 +1,270 @@ +/***************************************************************************/ +/* */ +/* t1types.h */ +/* */ +/* Basic Type1/Type2 type definitions and interface (specification */ +/* only). */ +/* */ +/* Copyright 1996-2001, 2002, 2003, 2004, 2006, 2008, 2009 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef __T1TYPES_H__ +#define __T1TYPES_H__ + + +#include <ft2build.h> +#include FT_TYPE1_TABLES_H +#include FT_INTERNAL_POSTSCRIPT_HINTS_H +#include FT_INTERNAL_SERVICE_H +#include FT_SERVICE_POSTSCRIPT_CMAPS_H + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /*** ***/ + /*** ***/ + /*** REQUIRED TYPE1/TYPE2 TABLES DEFINITIONS ***/ + /*** ***/ + /*** ***/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* T1_EncodingRec */ + /* */ + /* <Description> */ + /* A structure modeling a custom encoding. */ + /* */ + /* <Fields> */ + /* num_chars :: The number of character codes in the encoding. */ + /* Usually 256. */ + /* */ + /* code_first :: The lowest valid character code in the encoding. */ + /* */ + /* code_last :: The highest valid character code in the encoding */ + /* + 1. When equal to code_first there are no valid */ + /* character codes. */ + /* */ + /* char_index :: An array of corresponding glyph indices. */ + /* */ + /* char_name :: An array of corresponding glyph names. */ + /* */ + typedef struct T1_EncodingRecRec_ + { + FT_Int num_chars; + FT_Int code_first; + FT_Int code_last; + + FT_UShort* char_index; + FT_String** char_name; + + } T1_EncodingRec, *T1_Encoding; + + + typedef enum T1_EncodingType_ + { + T1_ENCODING_TYPE_NONE = 0, + T1_ENCODING_TYPE_ARRAY, + T1_ENCODING_TYPE_STANDARD, + T1_ENCODING_TYPE_ISOLATIN1, + T1_ENCODING_TYPE_EXPERT + + } T1_EncodingType; + + + /* used to hold extra data of PS_FontInfoRec that + * cannot be stored in the publicly defined structure. + * + * Note these can't be blended with multiple-masters. + */ + typedef struct PS_FontExtraRec_ + { + FT_UShort fs_type; + + } PS_FontExtraRec; + + + typedef struct T1_FontRec_ + { + PS_FontInfoRec font_info; /* font info dictionary */ + PS_FontExtraRec font_extra; /* font info extra fields */ + PS_PrivateRec private_dict; /* private dictionary */ + FT_String* font_name; /* top-level dictionary */ + + T1_EncodingType encoding_type; + T1_EncodingRec encoding; + + FT_Byte* subrs_block; + FT_Byte* charstrings_block; + FT_Byte* glyph_names_block; + + FT_Int num_subrs; + FT_Byte** subrs; + FT_PtrDist* subrs_len; + + FT_Int num_glyphs; + FT_String** glyph_names; /* array of glyph names */ + FT_Byte** charstrings; /* array of glyph charstrings */ + FT_PtrDist* charstrings_len; + + FT_Byte paint_type; + FT_Byte font_type; + FT_Matrix font_matrix; + FT_Vector font_offset; + FT_BBox font_bbox; + FT_Long font_id; + + FT_Fixed stroke_width; + + } T1_FontRec, *T1_Font; + + + typedef struct CID_SubrsRec_ + { + FT_UInt num_subrs; + FT_Byte** code; + + } CID_SubrsRec, *CID_Subrs; + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /*** ***/ + /*** ***/ + /*** AFM FONT INFORMATION STRUCTURES ***/ + /*** ***/ + /*** ***/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + typedef struct AFM_TrackKernRec_ + { + FT_Int degree; + FT_Fixed min_ptsize; + FT_Fixed min_kern; + FT_Fixed max_ptsize; + FT_Fixed max_kern; + + } AFM_TrackKernRec, *AFM_TrackKern; + + typedef struct AFM_KernPairRec_ + { + FT_Int index1; + FT_Int index2; + FT_Int x; + FT_Int y; + + } AFM_KernPairRec, *AFM_KernPair; + + typedef struct AFM_FontInfoRec_ + { + FT_Bool IsCIDFont; + FT_BBox FontBBox; + FT_Fixed Ascender; + FT_Fixed Descender; + AFM_TrackKern TrackKerns; /* free if non-NULL */ + FT_Int NumTrackKern; + AFM_KernPair KernPairs; /* free if non-NULL */ + FT_Int NumKernPair; + + } AFM_FontInfoRec, *AFM_FontInfo; + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /*** ***/ + /*** ***/ + /*** ORIGINAL T1_FACE CLASS DEFINITION ***/ + /*** ***/ + /*** ***/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + typedef struct T1_FaceRec_* T1_Face; + typedef struct CID_FaceRec_* CID_Face; + + + typedef struct T1_FaceRec_ + { + FT_FaceRec root; + T1_FontRec type1; + const void* psnames; + const void* psaux; + const void* afm_data; + FT_CharMapRec charmaprecs[2]; + FT_CharMap charmaps[2]; + +#ifdef FT_CONFIG_OPTION_OLD_INTERNALS + PS_Unicodes unicode_map; +#endif + + /* support for Multiple Masters fonts */ + PS_Blend blend; + + /* undocumented, optional: indices of subroutines that express */ + /* the NormalizeDesignVector and the ConvertDesignVector procedure, */ + /* respectively, as Type 2 charstrings; -1 if keywords not present */ + FT_Int ndv_idx; + FT_Int cdv_idx; + + /* undocumented, optional: has the same meaning as len_buildchar */ + /* for Type 2 fonts; manipulated by othersubrs 19, 24, and 25 */ + FT_UInt len_buildchar; + FT_Long* buildchar; + + /* since version 2.1 - interface to PostScript hinter */ + const void* pshinter; + + } T1_FaceRec; + + + typedef struct CID_FaceRec_ + { + FT_FaceRec root; + void* psnames; + void* psaux; + CID_FaceInfoRec cid; + PS_FontExtraRec font_extra; +#if 0 + void* afm_data; +#endif + CID_Subrs subrs; + + /* since version 2.1 - interface to PostScript hinter */ + void* pshinter; + + /* since version 2.1.8, but was originally positioned after `afm_data' */ + FT_Byte* binary_data; /* used if hex data has been converted */ + FT_Stream cid_stream; + + } CID_FaceRec; + + +FT_END_HEADER + +#endif /* __T1TYPES_H__ */ + + +/* END */ diff --git a/Lib/Include/freetype/internal/tttypes.h b/Lib/Include/freetype/internal/tttypes.h new file mode 100644 index 0000000..acbb863 --- /dev/null +++ b/Lib/Include/freetype/internal/tttypes.h @@ -0,0 +1,1543 @@ +/***************************************************************************/ +/* */ +/* tttypes.h */ +/* */ +/* Basic SFNT/TrueType type definitions and interface (specification */ +/* only). */ +/* */ +/* Copyright 1996-2001, 2002, 2004, 2005, 2006, 2007, 2008 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef __TTTYPES_H__ +#define __TTTYPES_H__ + + +#include <ft2build.h> +#include FT_TRUETYPE_TABLES_H +#include FT_INTERNAL_OBJECTS_H + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT +#include FT_MULTIPLE_MASTERS_H +#endif + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /*** ***/ + /*** ***/ + /*** REQUIRED TRUETYPE/OPENTYPE TABLES DEFINITIONS ***/ + /*** ***/ + /*** ***/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* TTC_HeaderRec */ + /* */ + /* <Description> */ + /* TrueType collection header. This table contains the offsets of */ + /* the font headers of each distinct TrueType face in the file. */ + /* */ + /* <Fields> */ + /* tag :: Must be `ttc ' to indicate a TrueType collection. */ + /* */ + /* version :: The version number. */ + /* */ + /* count :: The number of faces in the collection. The */ + /* specification says this should be an unsigned long, but */ + /* we use a signed long since we need the value -1 for */ + /* specific purposes. */ + /* */ + /* offsets :: The offsets of the font headers, one per face. */ + /* */ + typedef struct TTC_HeaderRec_ + { + FT_ULong tag; + FT_Fixed version; + FT_Long count; + FT_ULong* offsets; + + } TTC_HeaderRec; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* SFNT_HeaderRec */ + /* */ + /* <Description> */ + /* SFNT file format header. */ + /* */ + /* <Fields> */ + /* format_tag :: The font format tag. */ + /* */ + /* num_tables :: The number of tables in file. */ + /* */ + /* search_range :: Must be `16 * (max power of 2 <= num_tables)'. */ + /* */ + /* entry_selector :: Must be log2 of `search_range / 16'. */ + /* */ + /* range_shift :: Must be `num_tables * 16 - search_range'. */ + /* */ + typedef struct SFNT_HeaderRec_ + { + FT_ULong format_tag; + FT_UShort num_tables; + FT_UShort search_range; + FT_UShort entry_selector; + FT_UShort range_shift; + + FT_ULong offset; /* not in file */ + + } SFNT_HeaderRec, *SFNT_Header; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* TT_TableRec */ + /* */ + /* <Description> */ + /* This structure describes a given table of a TrueType font. */ + /* */ + /* <Fields> */ + /* Tag :: A four-bytes tag describing the table. */ + /* */ + /* CheckSum :: The table checksum. This value can be ignored. */ + /* */ + /* Offset :: The offset of the table from the start of the TrueType */ + /* font in its resource. */ + /* */ + /* Length :: The table length (in bytes). */ + /* */ + typedef struct TT_TableRec_ + { + FT_ULong Tag; /* table type */ + FT_ULong CheckSum; /* table checksum */ + FT_ULong Offset; /* table file offset */ + FT_ULong Length; /* table length */ + + } TT_TableRec, *TT_Table; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* TT_LongMetricsRec */ + /* */ + /* <Description> */ + /* A structure modeling the long metrics of the `hmtx' and `vmtx' */ + /* TrueType tables. The values are expressed in font units. */ + /* */ + /* <Fields> */ + /* advance :: The advance width or height for the glyph. */ + /* */ + /* bearing :: The left-side or top-side bearing for the glyph. */ + /* */ + typedef struct TT_LongMetricsRec_ + { + FT_UShort advance; + FT_Short bearing; + + } TT_LongMetricsRec, *TT_LongMetrics; + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* TT_ShortMetrics */ + /* */ + /* <Description> */ + /* A simple type to model the short metrics of the `hmtx' and `vmtx' */ + /* tables. */ + /* */ + typedef FT_Short TT_ShortMetrics; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* TT_NameEntryRec */ + /* */ + /* <Description> */ + /* A structure modeling TrueType name records. Name records are used */ + /* to store important strings like family name, style name, */ + /* copyright, etc. in _localized_ versions (i.e., language, encoding, */ + /* etc). */ + /* */ + /* <Fields> */ + /* platformID :: The ID of the name's encoding platform. */ + /* */ + /* encodingID :: The platform-specific ID for the name's encoding. */ + /* */ + /* languageID :: The platform-specific ID for the name's language. */ + /* */ + /* nameID :: The ID specifying what kind of name this is. */ + /* */ + /* stringLength :: The length of the string in bytes. */ + /* */ + /* stringOffset :: The offset to the string in the `name' table. */ + /* */ + /* string :: A pointer to the string's bytes. Note that these */ + /* are usually UTF-16 encoded characters. */ + /* */ + typedef struct TT_NameEntryRec_ + { + FT_UShort platformID; + FT_UShort encodingID; + FT_UShort languageID; + FT_UShort nameID; + FT_UShort stringLength; + FT_ULong stringOffset; + + /* this last field is not defined in the spec */ + /* but used by the FreeType engine */ + + FT_Byte* string; + + } TT_NameEntryRec, *TT_NameEntry; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* TT_NameTableRec */ + /* */ + /* <Description> */ + /* A structure modeling the TrueType name table. */ + /* */ + /* <Fields> */ + /* format :: The format of the name table. */ + /* */ + /* numNameRecords :: The number of names in table. */ + /* */ + /* storageOffset :: The offset of the name table in the `name' */ + /* TrueType table. */ + /* */ + /* names :: An array of name records. */ + /* */ + /* stream :: the file's input stream. */ + /* */ + typedef struct TT_NameTableRec_ + { + FT_UShort format; + FT_UInt numNameRecords; + FT_UInt storageOffset; + TT_NameEntryRec* names; + FT_Stream stream; + + } TT_NameTableRec, *TT_NameTable; + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /*** ***/ + /*** ***/ + /*** OPTIONAL TRUETYPE/OPENTYPE TABLES DEFINITIONS ***/ + /*** ***/ + /*** ***/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* TT_GaspRangeRec */ + /* */ + /* <Description> */ + /* A tiny structure used to model a gasp range according to the */ + /* TrueType specification. */ + /* */ + /* <Fields> */ + /* maxPPEM :: The maximum ppem value to which `gaspFlag' applies. */ + /* */ + /* gaspFlag :: A flag describing the grid-fitting and anti-aliasing */ + /* modes to be used. */ + /* */ + typedef struct TT_GaspRangeRec_ + { + FT_UShort maxPPEM; + FT_UShort gaspFlag; + + } TT_GaspRangeRec, *TT_GaspRange; + + +#define TT_GASP_GRIDFIT 0x01 +#define TT_GASP_DOGRAY 0x02 + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* TT_GaspRec */ + /* */ + /* <Description> */ + /* A structure modeling the TrueType `gasp' table used to specify */ + /* grid-fitting and anti-aliasing behaviour. */ + /* */ + /* <Fields> */ + /* version :: The version number. */ + /* */ + /* numRanges :: The number of gasp ranges in table. */ + /* */ + /* gaspRanges :: An array of gasp ranges. */ + /* */ + typedef struct TT_Gasp_ + { + FT_UShort version; + FT_UShort numRanges; + TT_GaspRange gaspRanges; + + } TT_GaspRec; + + +#ifdef FT_CONFIG_OPTION_OLD_INTERNALS + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* TT_HdmxEntryRec */ + /* */ + /* <Description> */ + /* A small structure used to model the pre-computed widths of a given */ + /* size. They are found in the `hdmx' table. */ + /* */ + /* <Fields> */ + /* ppem :: The pixels per EM value at which these metrics apply. */ + /* */ + /* max_width :: The maximum advance width for this metric. */ + /* */ + /* widths :: An array of widths. Note: These are 8-bit bytes. */ + /* */ + typedef struct TT_HdmxEntryRec_ + { + FT_Byte ppem; + FT_Byte max_width; + FT_Byte* widths; + + } TT_HdmxEntryRec, *TT_HdmxEntry; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* TT_HdmxRec */ + /* */ + /* <Description> */ + /* A structure used to model the `hdmx' table, which contains */ + /* pre-computed widths for a set of given sizes/dimensions. */ + /* */ + /* <Fields> */ + /* version :: The version number. */ + /* */ + /* num_records :: The number of hdmx records. */ + /* */ + /* records :: An array of hdmx records. */ + /* */ + typedef struct TT_HdmxRec_ + { + FT_UShort version; + FT_Short num_records; + TT_HdmxEntry records; + + } TT_HdmxRec, *TT_Hdmx; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* TT_Kern0_PairRec */ + /* */ + /* <Description> */ + /* A structure used to model a kerning pair for the kerning table */ + /* format 0. The engine now loads this table if it finds one in the */ + /* font file. */ + /* */ + /* <Fields> */ + /* left :: The index of the left glyph in pair. */ + /* */ + /* right :: The index of the right glyph in pair. */ + /* */ + /* value :: The kerning distance. A positive value spaces the */ + /* glyphs, a negative one makes them closer. */ + /* */ + typedef struct TT_Kern0_PairRec_ + { + FT_UShort left; /* index of left glyph in pair */ + FT_UShort right; /* index of right glyph in pair */ + FT_FWord value; /* kerning value */ + + } TT_Kern0_PairRec, *TT_Kern0_Pair; + +#endif /* FT_CONFIG_OPTION_OLD_INTERNALS */ + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /*** ***/ + /*** ***/ + /*** EMBEDDED BITMAPS SUPPORT ***/ + /*** ***/ + /*** ***/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* TT_SBit_MetricsRec */ + /* */ + /* <Description> */ + /* A structure used to hold the big metrics of a given glyph bitmap */ + /* in a TrueType or OpenType font. These are usually found in the */ + /* `EBDT' (Microsoft) or `bloc' (Apple) table. */ + /* */ + /* <Fields> */ + /* height :: The glyph height in pixels. */ + /* */ + /* width :: The glyph width in pixels. */ + /* */ + /* horiBearingX :: The horizontal left bearing. */ + /* */ + /* horiBearingY :: The horizontal top bearing. */ + /* */ + /* horiAdvance :: The horizontal advance. */ + /* */ + /* vertBearingX :: The vertical left bearing. */ + /* */ + /* vertBearingY :: The vertical top bearing. */ + /* */ + /* vertAdvance :: The vertical advance. */ + /* */ + typedef struct TT_SBit_MetricsRec_ + { + FT_Byte height; + FT_Byte width; + + FT_Char horiBearingX; + FT_Char horiBearingY; + FT_Byte horiAdvance; + + FT_Char vertBearingX; + FT_Char vertBearingY; + FT_Byte vertAdvance; + + } TT_SBit_MetricsRec, *TT_SBit_Metrics; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* TT_SBit_SmallMetricsRec */ + /* */ + /* <Description> */ + /* A structure used to hold the small metrics of a given glyph bitmap */ + /* in a TrueType or OpenType font. These are usually found in the */ + /* `EBDT' (Microsoft) or the `bdat' (Apple) table. */ + /* */ + /* <Fields> */ + /* height :: The glyph height in pixels. */ + /* */ + /* width :: The glyph width in pixels. */ + /* */ + /* bearingX :: The left-side bearing. */ + /* */ + /* bearingY :: The top-side bearing. */ + /* */ + /* advance :: The advance width or height. */ + /* */ + typedef struct TT_SBit_Small_Metrics_ + { + FT_Byte height; + FT_Byte width; + + FT_Char bearingX; + FT_Char bearingY; + FT_Byte advance; + + } TT_SBit_SmallMetricsRec, *TT_SBit_SmallMetrics; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* TT_SBit_LineMetricsRec */ + /* */ + /* <Description> */ + /* A structure used to describe the text line metrics of a given */ + /* bitmap strike, for either a horizontal or vertical layout. */ + /* */ + /* <Fields> */ + /* ascender :: The ascender in pixels. */ + /* */ + /* descender :: The descender in pixels. */ + /* */ + /* max_width :: The maximum glyph width in pixels. */ + /* */ + /* caret_slope_enumerator :: Rise of the caret slope, typically set */ + /* to 1 for non-italic fonts. */ + /* */ + /* caret_slope_denominator :: Rise of the caret slope, typically set */ + /* to 0 for non-italic fonts. */ + /* */ + /* caret_offset :: Offset in pixels to move the caret for */ + /* proper positioning. */ + /* */ + /* min_origin_SB :: Minimum of horiBearingX (resp. */ + /* vertBearingY). */ + /* min_advance_SB :: Minimum of */ + /* */ + /* horizontal advance - */ + /* ( horiBearingX + width ) */ + /* */ + /* resp. */ + /* */ + /* vertical advance - */ + /* ( vertBearingY + height ) */ + /* */ + /* max_before_BL :: Maximum of horiBearingY (resp. */ + /* vertBearingY). */ + /* */ + /* min_after_BL :: Minimum of */ + /* */ + /* horiBearingY - height */ + /* */ + /* resp. */ + /* */ + /* vertBearingX - width */ + /* */ + /* pads :: Unused (to make the size of the record */ + /* a multiple of 32 bits. */ + /* */ + typedef struct TT_SBit_LineMetricsRec_ + { + FT_Char ascender; + FT_Char descender; + FT_Byte max_width; + FT_Char caret_slope_numerator; + FT_Char caret_slope_denominator; + FT_Char caret_offset; + FT_Char min_origin_SB; + FT_Char min_advance_SB; + FT_Char max_before_BL; + FT_Char min_after_BL; + FT_Char pads[2]; + + } TT_SBit_LineMetricsRec, *TT_SBit_LineMetrics; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* TT_SBit_RangeRec */ + /* */ + /* <Description> */ + /* A TrueType/OpenType subIndexTable as defined in the `EBLC' */ + /* (Microsoft) or `bloc' (Apple) tables. */ + /* */ + /* <Fields> */ + /* first_glyph :: The first glyph index in the range. */ + /* */ + /* last_glyph :: The last glyph index in the range. */ + /* */ + /* index_format :: The format of index table. Valid values are 1 */ + /* to 5. */ + /* */ + /* image_format :: The format of `EBDT' image data. */ + /* */ + /* image_offset :: The offset to image data in `EBDT'. */ + /* */ + /* image_size :: For index formats 2 and 5. This is the size in */ + /* bytes of each glyph bitmap. */ + /* */ + /* big_metrics :: For index formats 2 and 5. This is the big */ + /* metrics for each glyph bitmap. */ + /* */ + /* num_glyphs :: For index formats 4 and 5. This is the number of */ + /* glyphs in the code array. */ + /* */ + /* glyph_offsets :: For index formats 1 and 3. */ + /* */ + /* glyph_codes :: For index formats 4 and 5. */ + /* */ + /* table_offset :: The offset of the index table in the `EBLC' */ + /* table. Only used during strike loading. */ + /* */ + typedef struct TT_SBit_RangeRec_ + { + FT_UShort first_glyph; + FT_UShort last_glyph; + + FT_UShort index_format; + FT_UShort image_format; + FT_ULong image_offset; + + FT_ULong image_size; + TT_SBit_MetricsRec metrics; + FT_ULong num_glyphs; + + FT_ULong* glyph_offsets; + FT_UShort* glyph_codes; + + FT_ULong table_offset; + + } TT_SBit_RangeRec, *TT_SBit_Range; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* TT_SBit_StrikeRec */ + /* */ + /* <Description> */ + /* A structure used describe a given bitmap strike in the `EBLC' */ + /* (Microsoft) or `bloc' (Apple) tables. */ + /* */ + /* <Fields> */ + /* num_index_ranges :: The number of index ranges. */ + /* */ + /* index_ranges :: An array of glyph index ranges. */ + /* */ + /* color_ref :: Unused. `color_ref' is put in for future */ + /* enhancements, but these fields are already */ + /* in use by other platforms (e.g. Newton). */ + /* For details, please see */ + /* */ + /* http://fonts.apple.com/ */ + /* TTRefMan/RM06/Chap6bloc.html */ + /* */ + /* hori :: The line metrics for horizontal layouts. */ + /* */ + /* vert :: The line metrics for vertical layouts. */ + /* */ + /* start_glyph :: The lowest glyph index for this strike. */ + /* */ + /* end_glyph :: The highest glyph index for this strike. */ + /* */ + /* x_ppem :: The number of horizontal pixels per EM. */ + /* */ + /* y_ppem :: The number of vertical pixels per EM. */ + /* */ + /* bit_depth :: The bit depth. Valid values are 1, 2, 4, */ + /* and 8. */ + /* */ + /* flags :: Is this a vertical or horizontal strike? For */ + /* details, please see */ + /* */ + /* http://fonts.apple.com/ */ + /* TTRefMan/RM06/Chap6bloc.html */ + /* */ + typedef struct TT_SBit_StrikeRec_ + { + FT_Int num_ranges; + TT_SBit_Range sbit_ranges; + FT_ULong ranges_offset; + + FT_ULong color_ref; + + TT_SBit_LineMetricsRec hori; + TT_SBit_LineMetricsRec vert; + + FT_UShort start_glyph; + FT_UShort end_glyph; + + FT_Byte x_ppem; + FT_Byte y_ppem; + + FT_Byte bit_depth; + FT_Char flags; + + } TT_SBit_StrikeRec, *TT_SBit_Strike; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* TT_SBit_ComponentRec */ + /* */ + /* <Description> */ + /* A simple structure to describe a compound sbit element. */ + /* */ + /* <Fields> */ + /* glyph_code :: The element's glyph index. */ + /* */ + /* x_offset :: The element's left bearing. */ + /* */ + /* y_offset :: The element's top bearing. */ + /* */ + typedef struct TT_SBit_ComponentRec_ + { + FT_UShort glyph_code; + FT_Char x_offset; + FT_Char y_offset; + + } TT_SBit_ComponentRec, *TT_SBit_Component; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* TT_SBit_ScaleRec */ + /* */ + /* <Description> */ + /* A structure used describe a given bitmap scaling table, as defined */ + /* in the `EBSC' table. */ + /* */ + /* <Fields> */ + /* hori :: The horizontal line metrics. */ + /* */ + /* vert :: The vertical line metrics. */ + /* */ + /* x_ppem :: The number of horizontal pixels per EM. */ + /* */ + /* y_ppem :: The number of vertical pixels per EM. */ + /* */ + /* x_ppem_substitute :: Substitution x_ppem value. */ + /* */ + /* y_ppem_substitute :: Substitution y_ppem value. */ + /* */ + typedef struct TT_SBit_ScaleRec_ + { + TT_SBit_LineMetricsRec hori; + TT_SBit_LineMetricsRec vert; + + FT_Byte x_ppem; + FT_Byte y_ppem; + + FT_Byte x_ppem_substitute; + FT_Byte y_ppem_substitute; + + } TT_SBit_ScaleRec, *TT_SBit_Scale; + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /*** ***/ + /*** ***/ + /*** POSTSCRIPT GLYPH NAMES SUPPORT ***/ + /*** ***/ + /*** ***/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* TT_Post_20Rec */ + /* */ + /* <Description> */ + /* Postscript names sub-table, format 2.0. Stores the PS name of */ + /* each glyph in the font face. */ + /* */ + /* <Fields> */ + /* num_glyphs :: The number of named glyphs in the table. */ + /* */ + /* num_names :: The number of PS names stored in the table. */ + /* */ + /* glyph_indices :: The indices of the glyphs in the names arrays. */ + /* */ + /* glyph_names :: The PS names not in Mac Encoding. */ + /* */ + typedef struct TT_Post_20Rec_ + { + FT_UShort num_glyphs; + FT_UShort num_names; + FT_UShort* glyph_indices; + FT_Char** glyph_names; + + } TT_Post_20Rec, *TT_Post_20; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* TT_Post_25Rec */ + /* */ + /* <Description> */ + /* Postscript names sub-table, format 2.5. Stores the PS name of */ + /* each glyph in the font face. */ + /* */ + /* <Fields> */ + /* num_glyphs :: The number of glyphs in the table. */ + /* */ + /* offsets :: An array of signed offsets in a normal Mac */ + /* Postscript name encoding. */ + /* */ + typedef struct TT_Post_25_ + { + FT_UShort num_glyphs; + FT_Char* offsets; + + } TT_Post_25Rec, *TT_Post_25; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* TT_Post_NamesRec */ + /* */ + /* <Description> */ + /* Postscript names table, either format 2.0 or 2.5. */ + /* */ + /* <Fields> */ + /* loaded :: A flag to indicate whether the PS names are loaded. */ + /* */ + /* format_20 :: The sub-table used for format 2.0. */ + /* */ + /* format_25 :: The sub-table used for format 2.5. */ + /* */ + typedef struct TT_Post_NamesRec_ + { + FT_Bool loaded; + + union + { + TT_Post_20Rec format_20; + TT_Post_25Rec format_25; + + } names; + + } TT_Post_NamesRec, *TT_Post_Names; + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /*** ***/ + /*** ***/ + /*** GX VARIATION TABLE SUPPORT ***/ + /*** ***/ + /*** ***/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + typedef struct GX_BlendRec_ *GX_Blend; +#endif + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /*** ***/ + /*** ***/ + /*** EMBEDDED BDF PROPERTIES TABLE SUPPORT ***/ + /*** ***/ + /*** ***/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + /* + * These types are used to support a `BDF ' table that isn't part of the + * official TrueType specification. It is mainly used in SFNT-based + * bitmap fonts that were generated from a set of BDF fonts. + * + * The format of the table is as follows. + * + * USHORT version `BDF ' table version number, should be 0x0001. + * USHORT strikeCount Number of strikes (bitmap sizes) in this table. + * ULONG stringTable Offset (from start of BDF table) to string + * table. + * + * This is followed by an array of `strikeCount' descriptors, having the + * following format. + * + * USHORT ppem Vertical pixels per EM for this strike. + * USHORT numItems Number of items for this strike (properties and + * atoms). Maximum is 255. + * + * This array in turn is followed by `strikeCount' value sets. Each + * `value set' is an array of `numItems' items with the following format. + * + * ULONG item_name Offset in string table to item name. + * USHORT item_type The item type. Possible values are + * 0 => string (e.g., COMMENT) + * 1 => atom (e.g., FONT or even SIZE) + * 2 => int32 + * 3 => uint32 + * 0x10 => A flag to indicate a properties. This + * is ORed with the above values. + * ULONG item_value For strings => Offset into string table without + * the corresponding double quotes. + * For atoms => Offset into string table. + * For integers => Direct value. + * + * All strings in the string table consist of bytes and are + * zero-terminated. + * + */ + +#ifdef TT_CONFIG_OPTION_BDF + + typedef struct TT_BDFRec_ + { + FT_Byte* table; + FT_Byte* table_end; + FT_Byte* strings; + FT_ULong strings_size; + FT_UInt num_strikes; + FT_Bool loaded; + + } TT_BDFRec, *TT_BDF; + +#endif /* TT_CONFIG_OPTION_BDF */ + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /*** ***/ + /*** ***/ + /*** ORIGINAL TT_FACE CLASS DEFINITION ***/ + /*** ***/ + /*** ***/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* This structure/class is defined here because it is common to the */ + /* following formats: TTF, OpenType-TT, and OpenType-CFF. */ + /* */ + /* Note, however, that the classes TT_Size and TT_GlyphSlot are not */ + /* shared between font drivers, and are thus defined in `ttobjs.h'. */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* <Type> */ + /* TT_Face */ + /* */ + /* <Description> */ + /* A handle to a TrueType face/font object. A TT_Face encapsulates */ + /* the resolution and scaling independent parts of a TrueType font */ + /* resource. */ + /* */ + /* <Note> */ + /* The TT_Face structure is also used as a `parent class' for the */ + /* OpenType-CFF class (T2_Face). */ + /* */ + typedef struct TT_FaceRec_* TT_Face; + + + /* a function type used for the truetype bytecode interpreter hooks */ + typedef FT_Error + (*TT_Interpreter)( void* exec_context ); + + /* forward declaration */ + typedef struct TT_LoaderRec_* TT_Loader; + + + /*************************************************************************/ + /* */ + /* <FuncType> */ + /* TT_Loader_GotoTableFunc */ + /* */ + /* <Description> */ + /* Seeks a stream to the start of a given TrueType table. */ + /* */ + /* <Input> */ + /* face :: A handle to the target face object. */ + /* */ + /* tag :: A 4-byte tag used to name the table. */ + /* */ + /* stream :: The input stream. */ + /* */ + /* <Output> */ + /* length :: The length of the table in bytes. Set to 0 if not */ + /* needed. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + /* <Note> */ + /* The stream cursor must be at the font file's origin. */ + /* */ + typedef FT_Error + (*TT_Loader_GotoTableFunc)( TT_Face face, + FT_ULong tag, + FT_Stream stream, + FT_ULong* length ); + + + /*************************************************************************/ + /* */ + /* <FuncType> */ + /* TT_Loader_StartGlyphFunc */ + /* */ + /* <Description> */ + /* Seeks a stream to the start of a given glyph element, and opens a */ + /* frame for it. */ + /* */ + /* <Input> */ + /* loader :: The current TrueType glyph loader object. */ + /* */ + /* glyph index :: The index of the glyph to access. */ + /* */ + /* offset :: The offset of the glyph according to the */ + /* `locations' table. */ + /* */ + /* byte_count :: The size of the frame in bytes. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + /* <Note> */ + /* This function is normally equivalent to FT_STREAM_SEEK(offset) */ + /* followed by FT_FRAME_ENTER(byte_count) with the loader's stream, */ + /* but alternative formats (e.g. compressed ones) might use something */ + /* different. */ + /* */ + typedef FT_Error + (*TT_Loader_StartGlyphFunc)( TT_Loader loader, + FT_UInt glyph_index, + FT_ULong offset, + FT_UInt byte_count ); + + + /*************************************************************************/ + /* */ + /* <FuncType> */ + /* TT_Loader_ReadGlyphFunc */ + /* */ + /* <Description> */ + /* Reads one glyph element (its header, a simple glyph, or a */ + /* composite) from the loader's current stream frame. */ + /* */ + /* <Input> */ + /* loader :: The current TrueType glyph loader object. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + typedef FT_Error + (*TT_Loader_ReadGlyphFunc)( TT_Loader loader ); + + + /*************************************************************************/ + /* */ + /* <FuncType> */ + /* TT_Loader_EndGlyphFunc */ + /* */ + /* <Description> */ + /* Closes the current loader stream frame for the glyph. */ + /* */ + /* <Input> */ + /* loader :: The current TrueType glyph loader object. */ + /* */ + typedef void + (*TT_Loader_EndGlyphFunc)( TT_Loader loader ); + + + /*************************************************************************/ + /* */ + /* TrueType Face Type */ + /* */ + /* <Struct> */ + /* TT_Face */ + /* */ + /* <Description> */ + /* The TrueType face class. These objects model the resolution and */ + /* point-size independent data found in a TrueType font file. */ + /* */ + /* <Fields> */ + /* root :: The base FT_Face structure, managed by the */ + /* base layer. */ + /* */ + /* ttc_header :: The TrueType collection header, used when */ + /* the file is a `ttc' rather than a `ttf'. */ + /* For ordinary font files, the field */ + /* `ttc_header.count' is set to 0. */ + /* */ + /* format_tag :: The font format tag. */ + /* */ + /* num_tables :: The number of TrueType tables in this font */ + /* file. */ + /* */ + /* dir_tables :: The directory of TrueType tables for this */ + /* font file. */ + /* */ + /* header :: The font's font header (`head' table). */ + /* Read on font opening. */ + /* */ + /* horizontal :: The font's horizontal header (`hhea' */ + /* table). This field also contains the */ + /* associated horizontal metrics table */ + /* (`hmtx'). */ + /* */ + /* max_profile :: The font's maximum profile table. Read on */ + /* font opening. Note that some maximum */ + /* values cannot be taken directly from this */ + /* table. We thus define additional fields */ + /* below to hold the computed maxima. */ + /* */ + /* vertical_info :: A boolean which is set when the font file */ + /* contains vertical metrics. If not, the */ + /* value of the `vertical' field is */ + /* undefined. */ + /* */ + /* vertical :: The font's vertical header (`vhea' table). */ + /* This field also contains the associated */ + /* vertical metrics table (`vmtx'), if found. */ + /* IMPORTANT: The contents of this field is */ + /* undefined if the `verticalInfo' field is */ + /* unset. */ + /* */ + /* num_names :: The number of name records within this */ + /* TrueType font. */ + /* */ + /* name_table :: The table of name records (`name'). */ + /* */ + /* os2 :: The font's OS/2 table (`OS/2'). */ + /* */ + /* postscript :: The font's PostScript table (`post' */ + /* table). The PostScript glyph names are */ + /* not loaded by the driver on face opening. */ + /* See the `ttpost' module for more details. */ + /* */ + /* cmap_table :: Address of the face's `cmap' SFNT table */ + /* in memory (it's an extracted frame). */ + /* */ + /* cmap_size :: The size in bytes of the `cmap_table' */ + /* described above. */ + /* */ + /* goto_table :: A function called by each TrueType table */ + /* loader to position a stream's cursor to */ + /* the start of a given table according to */ + /* its tag. It defaults to TT_Goto_Face but */ + /* can be different for strange formats (e.g. */ + /* Type 42). */ + /* */ + /* access_glyph_frame :: A function used to access the frame of a */ + /* given glyph within the face's font file. */ + /* */ + /* forget_glyph_frame :: A function used to forget the frame of a */ + /* given glyph when all data has been loaded. */ + /* */ + /* read_glyph_header :: A function used to read a glyph header. */ + /* It must be called between an `access' and */ + /* `forget'. */ + /* */ + /* read_simple_glyph :: A function used to read a simple glyph. */ + /* It must be called after the header was */ + /* read, and before the `forget'. */ + /* */ + /* read_composite_glyph :: A function used to read a composite glyph. */ + /* It must be called after the header was */ + /* read, and before the `forget'. */ + /* */ + /* sfnt :: A pointer to the SFNT service. */ + /* */ + /* psnames :: A pointer to the PostScript names service. */ + /* */ + /* hdmx :: The face's horizontal device metrics */ + /* (`hdmx' table). This table is optional in */ + /* TrueType/OpenType fonts. */ + /* */ + /* gasp :: The grid-fitting and scaling properties */ + /* table (`gasp'). This table is optional in */ + /* TrueType/OpenType fonts. */ + /* */ + /* pclt :: The `pclt' SFNT table. */ + /* */ + /* num_sbit_strikes :: The number of sbit strikes, i.e., bitmap */ + /* sizes, embedded in this font. */ + /* */ + /* sbit_strikes :: An array of sbit strikes embedded in this */ + /* font. This table is optional in a */ + /* TrueType/OpenType font. */ + /* */ + /* num_sbit_scales :: The number of sbit scales for this font. */ + /* */ + /* sbit_scales :: Array of sbit scales embedded in this */ + /* font. This table is optional in a */ + /* TrueType/OpenType font. */ + /* */ + /* postscript_names :: A table used to store the Postscript names */ + /* of the glyphs for this font. See the */ + /* file `ttconfig.h' for comments on the */ + /* TT_CONFIG_OPTION_POSTSCRIPT_NAMES option. */ + /* */ + /* num_locations :: The number of glyph locations in this */ + /* TrueType file. This should be */ + /* identical to the number of glyphs. */ + /* Ignored for Type 2 fonts. */ + /* */ + /* glyph_locations :: An array of longs. These are offsets to */ + /* glyph data within the `glyf' table. */ + /* Ignored for Type 2 font faces. */ + /* */ + /* glyf_len :: The length of the `glyf' table. Needed */ + /* for malformed `loca' tables. */ + /* */ + /* font_program_size :: Size in bytecodes of the face's font */ + /* program. 0 if none defined. Ignored for */ + /* Type 2 fonts. */ + /* */ + /* font_program :: The face's font program (bytecode stream) */ + /* executed at load time, also used during */ + /* glyph rendering. Comes from the `fpgm' */ + /* table. Ignored for Type 2 font fonts. */ + /* */ + /* cvt_program_size :: The size in bytecodes of the face's cvt */ + /* program. Ignored for Type 2 fonts. */ + /* */ + /* cvt_program :: The face's cvt program (bytecode stream) */ + /* executed each time an instance/size is */ + /* changed/reset. Comes from the `prep' */ + /* table. Ignored for Type 2 fonts. */ + /* */ + /* cvt_size :: Size of the control value table (in */ + /* entries). Ignored for Type 2 fonts. */ + /* */ + /* cvt :: The face's original control value table. */ + /* Coordinates are expressed in unscaled font */ + /* units. Comes from the `cvt ' table. */ + /* Ignored for Type 2 fonts. */ + /* */ + /* num_kern_pairs :: The number of kerning pairs present in the */ + /* font file. The engine only loads the */ + /* first horizontal format 0 kern table it */ + /* finds in the font file. Ignored for */ + /* Type 2 fonts. */ + /* */ + /* kern_table_index :: The index of the kerning table in the font */ + /* kerning directory. Ignored for Type 2 */ + /* fonts. */ + /* */ + /* interpreter :: A pointer to the TrueType bytecode */ + /* interpreters field is also used to hook */ + /* the debugger in `ttdebug'. */ + /* */ + /* unpatented_hinting :: If true, use only unpatented methods in */ + /* the bytecode interpreter. */ + /* */ + /* doblend :: A boolean which is set if the font should */ + /* be blended (this is for GX var). */ + /* */ + /* blend :: Contains the data needed to control GX */ + /* variation tables (rather like Multiple */ + /* Master data). */ + /* */ + /* extra :: Reserved for third-party font drivers. */ + /* */ + /* postscript_name :: The PS name of the font. Used by the */ + /* postscript name service. */ + /* */ + typedef struct TT_FaceRec_ + { + FT_FaceRec root; + + TTC_HeaderRec ttc_header; + + FT_ULong format_tag; + FT_UShort num_tables; + TT_Table dir_tables; + + TT_Header header; /* TrueType header table */ + TT_HoriHeader horizontal; /* TrueType horizontal header */ + + TT_MaxProfile max_profile; +#ifdef FT_CONFIG_OPTION_OLD_INTERNALS + FT_ULong max_components; /* stubbed to 0 */ +#endif + + FT_Bool vertical_info; + TT_VertHeader vertical; /* TT Vertical header, if present */ + + FT_UShort num_names; /* number of name records */ + TT_NameTableRec name_table; /* name table */ + + TT_OS2 os2; /* TrueType OS/2 table */ + TT_Postscript postscript; /* TrueType Postscript table */ + + FT_Byte* cmap_table; /* extracted `cmap' table */ + FT_ULong cmap_size; + + TT_Loader_GotoTableFunc goto_table; + + TT_Loader_StartGlyphFunc access_glyph_frame; + TT_Loader_EndGlyphFunc forget_glyph_frame; + TT_Loader_ReadGlyphFunc read_glyph_header; + TT_Loader_ReadGlyphFunc read_simple_glyph; + TT_Loader_ReadGlyphFunc read_composite_glyph; + + /* a typeless pointer to the SFNT_Interface table used to load */ + /* the basic TrueType tables in the face object */ + void* sfnt; + + /* a typeless pointer to the FT_Service_PsCMapsRec table used to */ + /* handle glyph names <-> unicode & Mac values */ + void* psnames; + + + /***********************************************************************/ + /* */ + /* Optional TrueType/OpenType tables */ + /* */ + /***********************************************************************/ + + /* horizontal device metrics */ +#ifdef FT_CONFIG_OPTION_OLD_INTERNALS + TT_HdmxRec hdmx; +#endif + + /* grid-fitting and scaling table */ + TT_GaspRec gasp; /* the `gasp' table */ + + /* PCL 5 table */ + TT_PCLT pclt; + + /* embedded bitmaps support */ +#ifdef FT_CONFIG_OPTION_OLD_INTERNALS + FT_ULong num_sbit_strikes; + TT_SBit_Strike sbit_strikes; +#endif + + FT_ULong num_sbit_scales; + TT_SBit_Scale sbit_scales; + + /* postscript names table */ + TT_Post_NamesRec postscript_names; + + + /***********************************************************************/ + /* */ + /* TrueType-specific fields (ignored by the OTF-Type2 driver) */ + /* */ + /***********************************************************************/ + + /* the glyph locations */ +#ifdef FT_CONFIG_OPTION_OLD_INTERNALS + FT_UShort num_locations_stub; + FT_Long* glyph_locations_stub; +#endif + + /* the font program, if any */ + FT_ULong font_program_size; + FT_Byte* font_program; + + /* the cvt program, if any */ + FT_ULong cvt_program_size; + FT_Byte* cvt_program; + + /* the original, unscaled, control value table */ + FT_ULong cvt_size; + FT_Short* cvt; + +#ifdef FT_CONFIG_OPTION_OLD_INTERNALS + /* the format 0 kerning table, if any */ + FT_Int num_kern_pairs; + FT_Int kern_table_index; + TT_Kern0_Pair kern_pairs; +#endif + + /* A pointer to the bytecode interpreter to use. This is also */ + /* used to hook the debugger for the `ttdebug' utility. */ + TT_Interpreter interpreter; + +#ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING + /* Use unpatented hinting only. */ + FT_Bool unpatented_hinting; +#endif + + /***********************************************************************/ + /* */ + /* Other tables or fields. This is used by derivative formats like */ + /* OpenType. */ + /* */ + /***********************************************************************/ + + FT_Generic extra; + + const char* postscript_name; + + /* since version 2.1.8, but was originally placed after */ + /* `glyph_locations_stub' */ + FT_ULong glyf_len; + + /* since version 2.1.8, but was originally placed before `extra' */ +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + FT_Bool doblend; + GX_Blend blend; +#endif + + /* since version 2.2 */ + + FT_Byte* horz_metrics; + FT_ULong horz_metrics_size; + + FT_Byte* vert_metrics; + FT_ULong vert_metrics_size; + + FT_ULong num_locations; /* in broken TTF, gid > 0xFFFF */ + FT_Byte* glyph_locations; + + FT_Byte* hdmx_table; + FT_ULong hdmx_table_size; + FT_UInt hdmx_record_count; + FT_ULong hdmx_record_size; + FT_Byte* hdmx_record_sizes; + + FT_Byte* sbit_table; + FT_ULong sbit_table_size; + FT_UInt sbit_num_strikes; + + FT_Byte* kern_table; + FT_ULong kern_table_size; + FT_UInt num_kern_tables; + FT_UInt32 kern_avail_bits; + FT_UInt32 kern_order_bits; + +#ifdef TT_CONFIG_OPTION_BDF + TT_BDFRec bdf; +#endif /* TT_CONFIG_OPTION_BDF */ + + /* since 2.3.0 */ + FT_ULong horz_metrics_offset; + FT_ULong vert_metrics_offset; + + } TT_FaceRec; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* TT_GlyphZoneRec */ + /* */ + /* <Description> */ + /* A glyph zone is used to load, scale and hint glyph outline */ + /* coordinates. */ + /* */ + /* <Fields> */ + /* memory :: A handle to the memory manager. */ + /* */ + /* max_points :: The maximal size in points of the zone. */ + /* */ + /* max_contours :: Max size in links contours of the zone. */ + /* */ + /* n_points :: The current number of points in the zone. */ + /* */ + /* n_contours :: The current number of contours in the zone. */ + /* */ + /* org :: The original glyph coordinates (font */ + /* units/scaled). */ + /* */ + /* cur :: The current glyph coordinates (scaled/hinted). */ + /* */ + /* tags :: The point control tags. */ + /* */ + /* contours :: The contours end points. */ + /* */ + /* first_point :: Offset of the current subglyph's first point. */ + /* */ + typedef struct TT_GlyphZoneRec_ + { + FT_Memory memory; + FT_UShort max_points; + FT_UShort max_contours; + FT_UShort n_points; /* number of points in zone */ + FT_Short n_contours; /* number of contours */ + + FT_Vector* org; /* original point coordinates */ + FT_Vector* cur; /* current point coordinates */ + FT_Vector* orus; /* original (unscaled) point coordinates */ + + FT_Byte* tags; /* current touch flags */ + FT_UShort* contours; /* contour end points */ + + FT_UShort first_point; /* offset of first (#0) point */ + + } TT_GlyphZoneRec, *TT_GlyphZone; + + + /* handle to execution context */ + typedef struct TT_ExecContextRec_* TT_ExecContext; + + /* glyph loader structure */ + typedef struct TT_LoaderRec_ + { + FT_Face face; + FT_Size size; + FT_GlyphSlot glyph; + FT_GlyphLoader gloader; + + FT_ULong load_flags; + FT_UInt glyph_index; + + FT_Stream stream; + FT_Int byte_len; + + FT_Short n_contours; + FT_BBox bbox; + FT_Int left_bearing; + FT_Int advance; + FT_Int linear; + FT_Bool linear_def; + FT_Bool preserve_pps; + FT_Vector pp1; + FT_Vector pp2; + + FT_ULong glyf_offset; + + /* the zone where we load our glyphs */ + TT_GlyphZoneRec base; + TT_GlyphZoneRec zone; + + TT_ExecContext exec; + FT_Byte* instructions; + FT_ULong ins_pos; + + /* for possible extensibility in other formats */ + void* other; + + /* since version 2.1.8 */ + FT_Int top_bearing; + FT_Int vadvance; + FT_Vector pp3; + FT_Vector pp4; + + /* since version 2.2.1 */ + FT_Byte* cursor; + FT_Byte* limit; + + } TT_LoaderRec; + + +FT_END_HEADER + +#endif /* __TTTYPES_H__ */ + + +/* END */ diff --git a/Lib/Include/freetype/t1tables.h b/Lib/Include/freetype/t1tables.h new file mode 100644 index 0000000..5e2a393 --- /dev/null +++ b/Lib/Include/freetype/t1tables.h @@ -0,0 +1,504 @@ +/***************************************************************************/ +/* */ +/* t1tables.h */ +/* */ +/* Basic Type 1/Type 2 tables definitions and interface (specification */ +/* only). */ +/* */ +/* Copyright 1996-2001, 2002, 2003, 2004, 2006, 2008, 2009 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef __T1TABLES_H__ +#define __T1TABLES_H__ + + +#include <ft2build.h> +#include FT_FREETYPE_H + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /* */ + /* <Section> */ + /* type1_tables */ + /* */ + /* <Title> */ + /* Type 1 Tables */ + /* */ + /* <Abstract> */ + /* Type~1 (PostScript) specific font tables. */ + /* */ + /* <Description> */ + /* This section contains the definition of Type 1-specific tables, */ + /* including structures related to other PostScript font formats. */ + /* */ + /*************************************************************************/ + + + /* Note that we separate font data in PS_FontInfoRec and PS_PrivateRec */ + /* structures in order to support Multiple Master fonts. */ + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* PS_FontInfoRec */ + /* */ + /* <Description> */ + /* A structure used to model a Type~1 or Type~2 FontInfo dictionary. */ + /* Note that for Multiple Master fonts, each instance has its own */ + /* FontInfo dictionary. */ + /* */ + typedef struct PS_FontInfoRec_ + { + FT_String* version; + FT_String* notice; + FT_String* full_name; + FT_String* family_name; + FT_String* weight; + FT_Long italic_angle; + FT_Bool is_fixed_pitch; + FT_Short underline_position; + FT_UShort underline_thickness; + + } PS_FontInfoRec; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* PS_FontInfo */ + /* */ + /* <Description> */ + /* A handle to a @PS_FontInfoRec structure. */ + /* */ + typedef struct PS_FontInfoRec_* PS_FontInfo; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* T1_FontInfo */ + /* */ + /* <Description> */ + /* This type is equivalent to @PS_FontInfoRec. It is deprecated but */ + /* kept to maintain source compatibility between various versions of */ + /* FreeType. */ + /* */ + typedef PS_FontInfoRec T1_FontInfo; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* PS_PrivateRec */ + /* */ + /* <Description> */ + /* A structure used to model a Type~1 or Type~2 private dictionary. */ + /* Note that for Multiple Master fonts, each instance has its own */ + /* Private dictionary. */ + /* */ + typedef struct PS_PrivateRec_ + { + FT_Int unique_id; + FT_Int lenIV; + + FT_Byte num_blue_values; + FT_Byte num_other_blues; + FT_Byte num_family_blues; + FT_Byte num_family_other_blues; + + FT_Short blue_values[14]; + FT_Short other_blues[10]; + + FT_Short family_blues [14]; + FT_Short family_other_blues[10]; + + FT_Fixed blue_scale; + FT_Int blue_shift; + FT_Int blue_fuzz; + + FT_UShort standard_width[1]; + FT_UShort standard_height[1]; + + FT_Byte num_snap_widths; + FT_Byte num_snap_heights; + FT_Bool force_bold; + FT_Bool round_stem_up; + + FT_Short snap_widths [13]; /* including std width */ + FT_Short snap_heights[13]; /* including std height */ + + FT_Fixed expansion_factor; + + FT_Long language_group; + FT_Long password; + + FT_Short min_feature[2]; + + } PS_PrivateRec; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* PS_Private */ + /* */ + /* <Description> */ + /* A handle to a @PS_PrivateRec structure. */ + /* */ + typedef struct PS_PrivateRec_* PS_Private; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* T1_Private */ + /* */ + /* <Description> */ + /* This type is equivalent to @PS_PrivateRec. It is deprecated but */ + /* kept to maintain source compatibility between various versions of */ + /* FreeType. */ + /* */ + typedef PS_PrivateRec T1_Private; + + + /*************************************************************************/ + /* */ + /* <Enum> */ + /* T1_Blend_Flags */ + /* */ + /* <Description> */ + /* A set of flags used to indicate which fields are present in a */ + /* given blend dictionary (font info or private). Used to support */ + /* Multiple Masters fonts. */ + /* */ + typedef enum T1_Blend_Flags_ + { + /*# required fields in a FontInfo blend dictionary */ + T1_BLEND_UNDERLINE_POSITION = 0, + T1_BLEND_UNDERLINE_THICKNESS, + T1_BLEND_ITALIC_ANGLE, + + /*# required fields in a Private blend dictionary */ + T1_BLEND_BLUE_VALUES, + T1_BLEND_OTHER_BLUES, + T1_BLEND_STANDARD_WIDTH, + T1_BLEND_STANDARD_HEIGHT, + T1_BLEND_STEM_SNAP_WIDTHS, + T1_BLEND_STEM_SNAP_HEIGHTS, + T1_BLEND_BLUE_SCALE, + T1_BLEND_BLUE_SHIFT, + T1_BLEND_FAMILY_BLUES, + T1_BLEND_FAMILY_OTHER_BLUES, + T1_BLEND_FORCE_BOLD, + + /*# never remove */ + T1_BLEND_MAX + + } T1_Blend_Flags; + + /* */ + + + /*# backwards compatible definitions */ +#define t1_blend_underline_position T1_BLEND_UNDERLINE_POSITION +#define t1_blend_underline_thickness T1_BLEND_UNDERLINE_THICKNESS +#define t1_blend_italic_angle T1_BLEND_ITALIC_ANGLE +#define t1_blend_blue_values T1_BLEND_BLUE_VALUES +#define t1_blend_other_blues T1_BLEND_OTHER_BLUES +#define t1_blend_standard_widths T1_BLEND_STANDARD_WIDTH +#define t1_blend_standard_height T1_BLEND_STANDARD_HEIGHT +#define t1_blend_stem_snap_widths T1_BLEND_STEM_SNAP_WIDTHS +#define t1_blend_stem_snap_heights T1_BLEND_STEM_SNAP_HEIGHTS +#define t1_blend_blue_scale T1_BLEND_BLUE_SCALE +#define t1_blend_blue_shift T1_BLEND_BLUE_SHIFT +#define t1_blend_family_blues T1_BLEND_FAMILY_BLUES +#define t1_blend_family_other_blues T1_BLEND_FAMILY_OTHER_BLUES +#define t1_blend_force_bold T1_BLEND_FORCE_BOLD +#define t1_blend_max T1_BLEND_MAX + + + /* maximum number of Multiple Masters designs, as defined in the spec */ +#define T1_MAX_MM_DESIGNS 16 + + /* maximum number of Multiple Masters axes, as defined in the spec */ +#define T1_MAX_MM_AXIS 4 + + /* maximum number of elements in a design map */ +#define T1_MAX_MM_MAP_POINTS 20 + + + /* this structure is used to store the BlendDesignMap entry for an axis */ + typedef struct PS_DesignMap_ + { + FT_Byte num_points; + FT_Long* design_points; + FT_Fixed* blend_points; + + } PS_DesignMapRec, *PS_DesignMap; + + /* backwards-compatible definition */ + typedef PS_DesignMapRec T1_DesignMap; + + + typedef struct PS_BlendRec_ + { + FT_UInt num_designs; + FT_UInt num_axis; + + FT_String* axis_names[T1_MAX_MM_AXIS]; + FT_Fixed* design_pos[T1_MAX_MM_DESIGNS]; + PS_DesignMapRec design_map[T1_MAX_MM_AXIS]; + + FT_Fixed* weight_vector; + FT_Fixed* default_weight_vector; + + PS_FontInfo font_infos[T1_MAX_MM_DESIGNS + 1]; + PS_Private privates [T1_MAX_MM_DESIGNS + 1]; + + FT_ULong blend_bitflags; + + FT_BBox* bboxes [T1_MAX_MM_DESIGNS + 1]; + + /* since 2.3.0 */ + + /* undocumented, optional: the default design instance; */ + /* corresponds to default_weight_vector -- */ + /* num_default_design_vector == 0 means it is not present */ + /* in the font and associated metrics files */ + FT_UInt default_design_vector[T1_MAX_MM_DESIGNS]; + FT_UInt num_default_design_vector; + + } PS_BlendRec, *PS_Blend; + + + /* backwards-compatible definition */ + typedef PS_BlendRec T1_Blend; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* CID_FaceDictRec */ + /* */ + /* <Description> */ + /* A structure used to represent data in a CID top-level dictionary. */ + /* */ + typedef struct CID_FaceDictRec_ + { + PS_PrivateRec private_dict; + + FT_UInt len_buildchar; + FT_Fixed forcebold_threshold; + FT_Pos stroke_width; + FT_Fixed expansion_factor; + + FT_Byte paint_type; + FT_Byte font_type; + FT_Matrix font_matrix; + FT_Vector font_offset; + + FT_UInt num_subrs; + FT_ULong subrmap_offset; + FT_Int sd_bytes; + + } CID_FaceDictRec; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* CID_FaceDict */ + /* */ + /* <Description> */ + /* A handle to a @CID_FaceDictRec structure. */ + /* */ + typedef struct CID_FaceDictRec_* CID_FaceDict; + + /* */ + + + /* backwards-compatible definition */ + typedef CID_FaceDictRec CID_FontDict; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* CID_FaceInfoRec */ + /* */ + /* <Description> */ + /* A structure used to represent CID Face information. */ + /* */ + typedef struct CID_FaceInfoRec_ + { + FT_String* cid_font_name; + FT_Fixed cid_version; + FT_Int cid_font_type; + + FT_String* registry; + FT_String* ordering; + FT_Int supplement; + + PS_FontInfoRec font_info; + FT_BBox font_bbox; + FT_ULong uid_base; + + FT_Int num_xuid; + FT_ULong xuid[16]; + + FT_ULong cidmap_offset; + FT_Int fd_bytes; + FT_Int gd_bytes; + FT_ULong cid_count; + + FT_Int num_dicts; + CID_FaceDict font_dicts; + + FT_ULong data_offset; + + } CID_FaceInfoRec; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* CID_FaceInfo */ + /* */ + /* <Description> */ + /* A handle to a @CID_FaceInfoRec structure. */ + /* */ + typedef struct CID_FaceInfoRec_* CID_FaceInfo; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* CID_Info */ + /* */ + /* <Description> */ + /* This type is equivalent to @CID_FaceInfoRec. It is deprecated but */ + /* kept to maintain source compatibility between various versions of */ + /* FreeType. */ + /* */ + typedef CID_FaceInfoRec CID_Info; + + + /************************************************************************ + * + * @function: + * FT_Has_PS_Glyph_Names + * + * @description: + * Return true if a given face provides reliable PostScript glyph + * names. This is similar to using the @FT_HAS_GLYPH_NAMES macro, + * except that certain fonts (mostly TrueType) contain incorrect + * glyph name tables. + * + * When this function returns true, the caller is sure that the glyph + * names returned by @FT_Get_Glyph_Name are reliable. + * + * @input: + * face :: + * face handle + * + * @return: + * Boolean. True if glyph names are reliable. + * + */ + FT_EXPORT( FT_Int ) + FT_Has_PS_Glyph_Names( FT_Face face ); + + + /************************************************************************ + * + * @function: + * FT_Get_PS_Font_Info + * + * @description: + * Retrieve the @PS_FontInfoRec structure corresponding to a given + * PostScript font. + * + * @input: + * face :: + * PostScript face handle. + * + * @output: + * afont_info :: + * Output font info structure pointer. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * The string pointers within the font info structure are owned by + * the face and don't need to be freed by the caller. + * + * If the font's format is not PostScript-based, this function will + * return the `FT_Err_Invalid_Argument' error code. + * + */ + FT_EXPORT( FT_Error ) + FT_Get_PS_Font_Info( FT_Face face, + PS_FontInfo afont_info ); + + + /************************************************************************ + * + * @function: + * FT_Get_PS_Font_Private + * + * @description: + * Retrieve the @PS_PrivateRec structure corresponding to a given + * PostScript font. + * + * @input: + * face :: + * PostScript face handle. + * + * @output: + * afont_private :: + * Output private dictionary structure pointer. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * The string pointers within the @PS_PrivateRec structure are owned by + * the face and don't need to be freed by the caller. + * + * If the font's format is not PostScript-based, this function returns + * the `FT_Err_Invalid_Argument' error code. + * + */ + FT_EXPORT( FT_Error ) + FT_Get_PS_Font_Private( FT_Face face, + PS_Private afont_private ); + + /* */ + + +FT_END_HEADER + +#endif /* __T1TABLES_H__ */ + + +/* END */ diff --git a/Lib/Include/freetype/ttnameid.h b/Lib/Include/freetype/ttnameid.h new file mode 100644 index 0000000..66aef04 --- /dev/null +++ b/Lib/Include/freetype/ttnameid.h @@ -0,0 +1,1247 @@ +/***************************************************************************/ +/* */ +/* ttnameid.h */ +/* */ +/* TrueType name ID definitions (specification only). */ +/* */ +/* Copyright 1996-2002, 2003, 2004, 2006, 2007, 2008 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef __TTNAMEID_H__ +#define __TTNAMEID_H__ + + +#include <ft2build.h> + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /* */ + /* <Section> */ + /* truetype_tables */ + /* */ + + + /*************************************************************************/ + /* */ + /* Possible values for the `platform' identifier code in the name */ + /* records of the TTF `name' table. */ + /* */ + /*************************************************************************/ + + + /*********************************************************************** + * + * @enum: + * TT_PLATFORM_XXX + * + * @description: + * A list of valid values for the `platform_id' identifier code in + * @FT_CharMapRec and @FT_SfntName structures. + * + * @values: + * TT_PLATFORM_APPLE_UNICODE :: + * Used by Apple to indicate a Unicode character map and/or name entry. + * See @TT_APPLE_ID_XXX for corresponding `encoding_id' values. Note + * that name entries in this format are coded as big-endian UCS-2 + * character codes _only_. + * + * TT_PLATFORM_MACINTOSH :: + * Used by Apple to indicate a MacOS-specific charmap and/or name entry. + * See @TT_MAC_ID_XXX for corresponding `encoding_id' values. Note that + * most TrueType fonts contain an Apple roman charmap to be usable on + * MacOS systems (even if they contain a Microsoft charmap as well). + * + * TT_PLATFORM_ISO :: + * This value was used to specify ISO/IEC 10646 charmaps. It is however + * now deprecated. See @TT_ISO_ID_XXX for a list of corresponding + * `encoding_id' values. + * + * TT_PLATFORM_MICROSOFT :: + * Used by Microsoft to indicate Windows-specific charmaps. See + * @TT_MS_ID_XXX for a list of corresponding `encoding_id' values. + * Note that most fonts contain a Unicode charmap using + * (TT_PLATFORM_MICROSOFT, @TT_MS_ID_UNICODE_CS). + * + * TT_PLATFORM_CUSTOM :: + * Used to indicate application-specific charmaps. + * + * TT_PLATFORM_ADOBE :: + * This value isn't part of any font format specification, but is used + * by FreeType to report Adobe-specific charmaps in an @FT_CharMapRec + * structure. See @TT_ADOBE_ID_XXX. + */ + +#define TT_PLATFORM_APPLE_UNICODE 0 +#define TT_PLATFORM_MACINTOSH 1 +#define TT_PLATFORM_ISO 2 /* deprecated */ +#define TT_PLATFORM_MICROSOFT 3 +#define TT_PLATFORM_CUSTOM 4 +#define TT_PLATFORM_ADOBE 7 /* artificial */ + + + /*********************************************************************** + * + * @enum: + * TT_APPLE_ID_XXX + * + * @description: + * A list of valid values for the `encoding_id' for + * @TT_PLATFORM_APPLE_UNICODE charmaps and name entries. + * + * @values: + * TT_APPLE_ID_DEFAULT :: + * Unicode version 1.0. + * + * TT_APPLE_ID_UNICODE_1_1 :: + * Unicode 1.1; specifies Hangul characters starting at U+34xx. + * + * TT_APPLE_ID_ISO_10646 :: + * Deprecated (identical to preceding). + * + * TT_APPLE_ID_UNICODE_2_0 :: + * Unicode 2.0 and beyond (UTF-16 BMP only). + * + * TT_APPLE_ID_UNICODE_32 :: + * Unicode 3.1 and beyond, using UTF-32. + * + * TT_APPLE_ID_VARIANT_SELECTOR :: + * From Adobe, not Apple. Not a normal cmap. Specifies variations + * on a real cmap. + */ + +#define TT_APPLE_ID_DEFAULT 0 /* Unicode 1.0 */ +#define TT_APPLE_ID_UNICODE_1_1 1 /* specify Hangul at U+34xx */ +#define TT_APPLE_ID_ISO_10646 2 /* deprecated */ +#define TT_APPLE_ID_UNICODE_2_0 3 /* or later */ +#define TT_APPLE_ID_UNICODE_32 4 /* 2.0 or later, full repertoire */ +#define TT_APPLE_ID_VARIANT_SELECTOR 5 /* variation selector data */ + + + /*********************************************************************** + * + * @enum: + * TT_MAC_ID_XXX + * + * @description: + * A list of valid values for the `encoding_id' for + * @TT_PLATFORM_MACINTOSH charmaps and name entries. + * + * @values: + * TT_MAC_ID_ROMAN :: + * TT_MAC_ID_JAPANESE :: + * TT_MAC_ID_TRADITIONAL_CHINESE :: + * TT_MAC_ID_KOREAN :: + * TT_MAC_ID_ARABIC :: + * TT_MAC_ID_HEBREW :: + * TT_MAC_ID_GREEK :: + * TT_MAC_ID_RUSSIAN :: + * TT_MAC_ID_RSYMBOL :: + * TT_MAC_ID_DEVANAGARI :: + * TT_MAC_ID_GURMUKHI :: + * TT_MAC_ID_GUJARATI :: + * TT_MAC_ID_ORIYA :: + * TT_MAC_ID_BENGALI :: + * TT_MAC_ID_TAMIL :: + * TT_MAC_ID_TELUGU :: + * TT_MAC_ID_KANNADA :: + * TT_MAC_ID_MALAYALAM :: + * TT_MAC_ID_SINHALESE :: + * TT_MAC_ID_BURMESE :: + * TT_MAC_ID_KHMER :: + * TT_MAC_ID_THAI :: + * TT_MAC_ID_LAOTIAN :: + * TT_MAC_ID_GEORGIAN :: + * TT_MAC_ID_ARMENIAN :: + * TT_MAC_ID_MALDIVIAN :: + * TT_MAC_ID_SIMPLIFIED_CHINESE :: + * TT_MAC_ID_TIBETAN :: + * TT_MAC_ID_MONGOLIAN :: + * TT_MAC_ID_GEEZ :: + * TT_MAC_ID_SLAVIC :: + * TT_MAC_ID_VIETNAMESE :: + * TT_MAC_ID_SINDHI :: + * TT_MAC_ID_UNINTERP :: + */ + +#define TT_MAC_ID_ROMAN 0 +#define TT_MAC_ID_JAPANESE 1 +#define TT_MAC_ID_TRADITIONAL_CHINESE 2 +#define TT_MAC_ID_KOREAN 3 +#define TT_MAC_ID_ARABIC 4 +#define TT_MAC_ID_HEBREW 5 +#define TT_MAC_ID_GREEK 6 +#define TT_MAC_ID_RUSSIAN 7 +#define TT_MAC_ID_RSYMBOL 8 +#define TT_MAC_ID_DEVANAGARI 9 +#define TT_MAC_ID_GURMUKHI 10 +#define TT_MAC_ID_GUJARATI 11 +#define TT_MAC_ID_ORIYA 12 +#define TT_MAC_ID_BENGALI 13 +#define TT_MAC_ID_TAMIL 14 +#define TT_MAC_ID_TELUGU 15 +#define TT_MAC_ID_KANNADA 16 +#define TT_MAC_ID_MALAYALAM 17 +#define TT_MAC_ID_SINHALESE 18 +#define TT_MAC_ID_BURMESE 19 +#define TT_MAC_ID_KHMER 20 +#define TT_MAC_ID_THAI 21 +#define TT_MAC_ID_LAOTIAN 22 +#define TT_MAC_ID_GEORGIAN 23 +#define TT_MAC_ID_ARMENIAN 24 +#define TT_MAC_ID_MALDIVIAN 25 +#define TT_MAC_ID_SIMPLIFIED_CHINESE 25 +#define TT_MAC_ID_TIBETAN 26 +#define TT_MAC_ID_MONGOLIAN 27 +#define TT_MAC_ID_GEEZ 28 +#define TT_MAC_ID_SLAVIC 29 +#define TT_MAC_ID_VIETNAMESE 30 +#define TT_MAC_ID_SINDHI 31 +#define TT_MAC_ID_UNINTERP 32 + + + /*********************************************************************** + * + * @enum: + * TT_ISO_ID_XXX + * + * @description: + * A list of valid values for the `encoding_id' for + * @TT_PLATFORM_ISO charmaps and name entries. + * + * Their use is now deprecated. + * + * @values: + * TT_ISO_ID_7BIT_ASCII :: + * ASCII. + * TT_ISO_ID_10646 :: + * ISO/10646. + * TT_ISO_ID_8859_1 :: + * Also known as Latin-1. + */ + +#define TT_ISO_ID_7BIT_ASCII 0 +#define TT_ISO_ID_10646 1 +#define TT_ISO_ID_8859_1 2 + + + /*********************************************************************** + * + * @enum: + * TT_MS_ID_XXX + * + * @description: + * A list of valid values for the `encoding_id' for + * @TT_PLATFORM_MICROSOFT charmaps and name entries. + * + * @values: + * TT_MS_ID_SYMBOL_CS :: + * Corresponds to Microsoft symbol encoding. See + * @FT_ENCODING_MS_SYMBOL. + * + * TT_MS_ID_UNICODE_CS :: + * Corresponds to a Microsoft WGL4 charmap, matching Unicode. See + * @FT_ENCODING_UNICODE. + * + * TT_MS_ID_SJIS :: + * Corresponds to SJIS Japanese encoding. See @FT_ENCODING_SJIS. + * + * TT_MS_ID_GB2312 :: + * Corresponds to Simplified Chinese as used in Mainland China. See + * @FT_ENCODING_GB2312. + * + * TT_MS_ID_BIG_5 :: + * Corresponds to Traditional Chinese as used in Taiwan and Hong Kong. + * See @FT_ENCODING_BIG5. + * + * TT_MS_ID_WANSUNG :: + * Corresponds to Korean Wansung encoding. See @FT_ENCODING_WANSUNG. + * + * TT_MS_ID_JOHAB :: + * Corresponds to Johab encoding. See @FT_ENCODING_JOHAB. + * + * TT_MS_ID_UCS_4 :: + * Corresponds to UCS-4 or UTF-32 charmaps. This has been added to + * the OpenType specification version 1.4 (mid-2001.) + */ + +#define TT_MS_ID_SYMBOL_CS 0 +#define TT_MS_ID_UNICODE_CS 1 +#define TT_MS_ID_SJIS 2 +#define TT_MS_ID_GB2312 3 +#define TT_MS_ID_BIG_5 4 +#define TT_MS_ID_WANSUNG 5 +#define TT_MS_ID_JOHAB 6 +#define TT_MS_ID_UCS_4 10 + + + /*********************************************************************** + * + * @enum: + * TT_ADOBE_ID_XXX + * + * @description: + * A list of valid values for the `encoding_id' for + * @TT_PLATFORM_ADOBE charmaps. This is a FreeType-specific extension! + * + * @values: + * TT_ADOBE_ID_STANDARD :: + * Adobe standard encoding. + * TT_ADOBE_ID_EXPERT :: + * Adobe expert encoding. + * TT_ADOBE_ID_CUSTOM :: + * Adobe custom encoding. + * TT_ADOBE_ID_LATIN_1 :: + * Adobe Latin~1 encoding. + */ + +#define TT_ADOBE_ID_STANDARD 0 +#define TT_ADOBE_ID_EXPERT 1 +#define TT_ADOBE_ID_CUSTOM 2 +#define TT_ADOBE_ID_LATIN_1 3 + + + /*************************************************************************/ + /* */ + /* Possible values of the language identifier field in the name records */ + /* of the TTF `name' table if the `platform' identifier code is */ + /* TT_PLATFORM_MACINTOSH. */ + /* */ + /* The canonical source for the Apple assigned Language ID's is at */ + /* */ + /* http://fonts.apple.com/TTRefMan/RM06/Chap6name.html */ + /* */ +#define TT_MAC_LANGID_ENGLISH 0 +#define TT_MAC_LANGID_FRENCH 1 +#define TT_MAC_LANGID_GERMAN 2 +#define TT_MAC_LANGID_ITALIAN 3 +#define TT_MAC_LANGID_DUTCH 4 +#define TT_MAC_LANGID_SWEDISH 5 +#define TT_MAC_LANGID_SPANISH 6 +#define TT_MAC_LANGID_DANISH 7 +#define TT_MAC_LANGID_PORTUGUESE 8 +#define TT_MAC_LANGID_NORWEGIAN 9 +#define TT_MAC_LANGID_HEBREW 10 +#define TT_MAC_LANGID_JAPANESE 11 +#define TT_MAC_LANGID_ARABIC 12 +#define TT_MAC_LANGID_FINNISH 13 +#define TT_MAC_LANGID_GREEK 14 +#define TT_MAC_LANGID_ICELANDIC 15 +#define TT_MAC_LANGID_MALTESE 16 +#define TT_MAC_LANGID_TURKISH 17 +#define TT_MAC_LANGID_CROATIAN 18 +#define TT_MAC_LANGID_CHINESE_TRADITIONAL 19 +#define TT_MAC_LANGID_URDU 20 +#define TT_MAC_LANGID_HINDI 21 +#define TT_MAC_LANGID_THAI 22 +#define TT_MAC_LANGID_KOREAN 23 +#define TT_MAC_LANGID_LITHUANIAN 24 +#define TT_MAC_LANGID_POLISH 25 +#define TT_MAC_LANGID_HUNGARIAN 26 +#define TT_MAC_LANGID_ESTONIAN 27 +#define TT_MAC_LANGID_LETTISH 28 +#define TT_MAC_LANGID_SAAMISK 29 +#define TT_MAC_LANGID_FAEROESE 30 +#define TT_MAC_LANGID_FARSI 31 +#define TT_MAC_LANGID_RUSSIAN 32 +#define TT_MAC_LANGID_CHINESE_SIMPLIFIED 33 +#define TT_MAC_LANGID_FLEMISH 34 +#define TT_MAC_LANGID_IRISH 35 +#define TT_MAC_LANGID_ALBANIAN 36 +#define TT_MAC_LANGID_ROMANIAN 37 +#define TT_MAC_LANGID_CZECH 38 +#define TT_MAC_LANGID_SLOVAK 39 +#define TT_MAC_LANGID_SLOVENIAN 40 +#define TT_MAC_LANGID_YIDDISH 41 +#define TT_MAC_LANGID_SERBIAN 42 +#define TT_MAC_LANGID_MACEDONIAN 43 +#define TT_MAC_LANGID_BULGARIAN 44 +#define TT_MAC_LANGID_UKRAINIAN 45 +#define TT_MAC_LANGID_BYELORUSSIAN 46 +#define TT_MAC_LANGID_UZBEK 47 +#define TT_MAC_LANGID_KAZAKH 48 +#define TT_MAC_LANGID_AZERBAIJANI 49 +#define TT_MAC_LANGID_AZERBAIJANI_CYRILLIC_SCRIPT 49 +#define TT_MAC_LANGID_AZERBAIJANI_ARABIC_SCRIPT 50 +#define TT_MAC_LANGID_ARMENIAN 51 +#define TT_MAC_LANGID_GEORGIAN 52 +#define TT_MAC_LANGID_MOLDAVIAN 53 +#define TT_MAC_LANGID_KIRGHIZ 54 +#define TT_MAC_LANGID_TAJIKI 55 +#define TT_MAC_LANGID_TURKMEN 56 +#define TT_MAC_LANGID_MONGOLIAN 57 +#define TT_MAC_LANGID_MONGOLIAN_MONGOLIAN_SCRIPT 57 +#define TT_MAC_LANGID_MONGOLIAN_CYRILLIC_SCRIPT 58 +#define TT_MAC_LANGID_PASHTO 59 +#define TT_MAC_LANGID_KURDISH 60 +#define TT_MAC_LANGID_KASHMIRI 61 +#define TT_MAC_LANGID_SINDHI 62 +#define TT_MAC_LANGID_TIBETAN 63 +#define TT_MAC_LANGID_NEPALI 64 +#define TT_MAC_LANGID_SANSKRIT 65 +#define TT_MAC_LANGID_MARATHI 66 +#define TT_MAC_LANGID_BENGALI 67 +#define TT_MAC_LANGID_ASSAMESE 68 +#define TT_MAC_LANGID_GUJARATI 69 +#define TT_MAC_LANGID_PUNJABI 70 +#define TT_MAC_LANGID_ORIYA 71 +#define TT_MAC_LANGID_MALAYALAM 72 +#define TT_MAC_LANGID_KANNADA 73 +#define TT_MAC_LANGID_TAMIL 74 +#define TT_MAC_LANGID_TELUGU 75 +#define TT_MAC_LANGID_SINHALESE 76 +#define TT_MAC_LANGID_BURMESE 77 +#define TT_MAC_LANGID_KHMER 78 +#define TT_MAC_LANGID_LAO 79 +#define TT_MAC_LANGID_VIETNAMESE 80 +#define TT_MAC_LANGID_INDONESIAN 81 +#define TT_MAC_LANGID_TAGALOG 82 +#define TT_MAC_LANGID_MALAY_ROMAN_SCRIPT 83 +#define TT_MAC_LANGID_MALAY_ARABIC_SCRIPT 84 +#define TT_MAC_LANGID_AMHARIC 85 +#define TT_MAC_LANGID_TIGRINYA 86 +#define TT_MAC_LANGID_GALLA 87 +#define TT_MAC_LANGID_SOMALI 88 +#define TT_MAC_LANGID_SWAHILI 89 +#define TT_MAC_LANGID_RUANDA 90 +#define TT_MAC_LANGID_RUNDI 91 +#define TT_MAC_LANGID_CHEWA 92 +#define TT_MAC_LANGID_MALAGASY 93 +#define TT_MAC_LANGID_ESPERANTO 94 +#define TT_MAC_LANGID_WELSH 128 +#define TT_MAC_LANGID_BASQUE 129 +#define TT_MAC_LANGID_CATALAN 130 +#define TT_MAC_LANGID_LATIN 131 +#define TT_MAC_LANGID_QUECHUA 132 +#define TT_MAC_LANGID_GUARANI 133 +#define TT_MAC_LANGID_AYMARA 134 +#define TT_MAC_LANGID_TATAR 135 +#define TT_MAC_LANGID_UIGHUR 136 +#define TT_MAC_LANGID_DZONGKHA 137 +#define TT_MAC_LANGID_JAVANESE 138 +#define TT_MAC_LANGID_SUNDANESE 139 + + +#if 0 /* these seem to be errors that have been dropped */ + +#define TT_MAC_LANGID_SCOTTISH_GAELIC 140 +#define TT_MAC_LANGID_IRISH_GAELIC 141 + +#endif + + + /* The following codes are new as of 2000-03-10 */ +#define TT_MAC_LANGID_GALICIAN 140 +#define TT_MAC_LANGID_AFRIKAANS 141 +#define TT_MAC_LANGID_BRETON 142 +#define TT_MAC_LANGID_INUKTITUT 143 +#define TT_MAC_LANGID_SCOTTISH_GAELIC 144 +#define TT_MAC_LANGID_MANX_GAELIC 145 +#define TT_MAC_LANGID_IRISH_GAELIC 146 +#define TT_MAC_LANGID_TONGAN 147 +#define TT_MAC_LANGID_GREEK_POLYTONIC 148 +#define TT_MAC_LANGID_GREELANDIC 149 +#define TT_MAC_LANGID_AZERBAIJANI_ROMAN_SCRIPT 150 + + + /*************************************************************************/ + /* */ + /* Possible values of the language identifier field in the name records */ + /* of the TTF `name' table if the `platform' identifier code is */ + /* TT_PLATFORM_MICROSOFT. */ + /* */ + /* The canonical source for the MS assigned LCID's (seems to) be at */ + /* */ + /* http://www.microsoft.com/globaldev/reference/lcid-all.mspx */ + /* */ + /* It used to be at various places, among them */ + /* */ + /* http://www.microsoft.com/typography/OTSPEC/lcid-cp.txt */ + /* http://www.microsoft.com/globaldev/reference/loclanghome.asp */ + /* http://support.microsoft.com/support/kb/articles/Q224/8/04.ASP */ + /* http://msdn.microsoft.com/library/en-us/passport25/ */ + /* NET_Passport_VBScript_Documentation/Single_Sign_In/ */ + /* Advanced_Single_Sign_In/Localization_and_LCIDs.asp */ + /* */ + /* Hopefully, it seems now that the Globaldev site prevails... */ + /* (updated by Antoine, 2004-02-17) */ + +#define TT_MS_LANGID_ARABIC_GENERAL 0x0001 +#define TT_MS_LANGID_ARABIC_SAUDI_ARABIA 0x0401 +#define TT_MS_LANGID_ARABIC_IRAQ 0x0801 +#define TT_MS_LANGID_ARABIC_EGYPT 0x0c01 +#define TT_MS_LANGID_ARABIC_LIBYA 0x1001 +#define TT_MS_LANGID_ARABIC_ALGERIA 0x1401 +#define TT_MS_LANGID_ARABIC_MOROCCO 0x1801 +#define TT_MS_LANGID_ARABIC_TUNISIA 0x1c01 +#define TT_MS_LANGID_ARABIC_OMAN 0x2001 +#define TT_MS_LANGID_ARABIC_YEMEN 0x2401 +#define TT_MS_LANGID_ARABIC_SYRIA 0x2801 +#define TT_MS_LANGID_ARABIC_JORDAN 0x2c01 +#define TT_MS_LANGID_ARABIC_LEBANON 0x3001 +#define TT_MS_LANGID_ARABIC_KUWAIT 0x3401 +#define TT_MS_LANGID_ARABIC_UAE 0x3801 +#define TT_MS_LANGID_ARABIC_BAHRAIN 0x3c01 +#define TT_MS_LANGID_ARABIC_QATAR 0x4001 +#define TT_MS_LANGID_BULGARIAN_BULGARIA 0x0402 +#define TT_MS_LANGID_CATALAN_SPAIN 0x0403 +#define TT_MS_LANGID_CHINESE_GENERAL 0x0004 +#define TT_MS_LANGID_CHINESE_TAIWAN 0x0404 +#define TT_MS_LANGID_CHINESE_PRC 0x0804 +#define TT_MS_LANGID_CHINESE_HONG_KONG 0x0c04 +#define TT_MS_LANGID_CHINESE_SINGAPORE 0x1004 + +#if 1 /* this looks like the correct value */ +#define TT_MS_LANGID_CHINESE_MACAU 0x1404 +#else /* but beware, Microsoft may change its mind... + the most recent Word reference has the following: */ +#define TT_MS_LANGID_CHINESE_MACAU TT_MS_LANGID_CHINESE_HONG_KONG +#endif + +#if 0 /* used only with .NET `cultures'; commented out */ +#define TT_MS_LANGID_CHINESE_TRADITIONAL 0x7C04 +#endif + +#define TT_MS_LANGID_CZECH_CZECH_REPUBLIC 0x0405 +#define TT_MS_LANGID_DANISH_DENMARK 0x0406 +#define TT_MS_LANGID_GERMAN_GERMANY 0x0407 +#define TT_MS_LANGID_GERMAN_SWITZERLAND 0x0807 +#define TT_MS_LANGID_GERMAN_AUSTRIA 0x0c07 +#define TT_MS_LANGID_GERMAN_LUXEMBOURG 0x1007 +#define TT_MS_LANGID_GERMAN_LIECHTENSTEI 0x1407 +#define TT_MS_LANGID_GREEK_GREECE 0x0408 + + /* don't ask what this one means... It is commented out currently. */ +#if 0 +#define TT_MS_LANGID_GREEK_GREECE2 0x2008 +#endif + +#define TT_MS_LANGID_ENGLISH_GENERAL 0x0009 +#define TT_MS_LANGID_ENGLISH_UNITED_STATES 0x0409 +#define TT_MS_LANGID_ENGLISH_UNITED_KINGDOM 0x0809 +#define TT_MS_LANGID_ENGLISH_AUSTRALIA 0x0c09 +#define TT_MS_LANGID_ENGLISH_CANADA 0x1009 +#define TT_MS_LANGID_ENGLISH_NEW_ZEALAND 0x1409 +#define TT_MS_LANGID_ENGLISH_IRELAND 0x1809 +#define TT_MS_LANGID_ENGLISH_SOUTH_AFRICA 0x1c09 +#define TT_MS_LANGID_ENGLISH_JAMAICA 0x2009 +#define TT_MS_LANGID_ENGLISH_CARIBBEAN 0x2409 +#define TT_MS_LANGID_ENGLISH_BELIZE 0x2809 +#define TT_MS_LANGID_ENGLISH_TRINIDAD 0x2c09 +#define TT_MS_LANGID_ENGLISH_ZIMBABWE 0x3009 +#define TT_MS_LANGID_ENGLISH_PHILIPPINES 0x3409 +#define TT_MS_LANGID_ENGLISH_INDONESIA 0x3809 +#define TT_MS_LANGID_ENGLISH_HONG_KONG 0x3c09 +#define TT_MS_LANGID_ENGLISH_INDIA 0x4009 +#define TT_MS_LANGID_ENGLISH_MALAYSIA 0x4409 +#define TT_MS_LANGID_ENGLISH_SINGAPORE 0x4809 +#define TT_MS_LANGID_SPANISH_SPAIN_TRADITIONAL_SORT 0x040a +#define TT_MS_LANGID_SPANISH_MEXICO 0x080a +#define TT_MS_LANGID_SPANISH_SPAIN_INTERNATIONAL_SORT 0x0c0a +#define TT_MS_LANGID_SPANISH_GUATEMALA 0x100a +#define TT_MS_LANGID_SPANISH_COSTA_RICA 0x140a +#define TT_MS_LANGID_SPANISH_PANAMA 0x180a +#define TT_MS_LANGID_SPANISH_DOMINICAN_REPUBLIC 0x1c0a +#define TT_MS_LANGID_SPANISH_VENEZUELA 0x200a +#define TT_MS_LANGID_SPANISH_COLOMBIA 0x240a +#define TT_MS_LANGID_SPANISH_PERU 0x280a +#define TT_MS_LANGID_SPANISH_ARGENTINA 0x2c0a +#define TT_MS_LANGID_SPANISH_ECUADOR 0x300a +#define TT_MS_LANGID_SPANISH_CHILE 0x340a +#define TT_MS_LANGID_SPANISH_URUGUAY 0x380a +#define TT_MS_LANGID_SPANISH_PARAGUAY 0x3c0a +#define TT_MS_LANGID_SPANISH_BOLIVIA 0x400a +#define TT_MS_LANGID_SPANISH_EL_SALVADOR 0x440a +#define TT_MS_LANGID_SPANISH_HONDURAS 0x480a +#define TT_MS_LANGID_SPANISH_NICARAGUA 0x4c0a +#define TT_MS_LANGID_SPANISH_PUERTO_RICO 0x500a +#define TT_MS_LANGID_SPANISH_UNITED_STATES 0x540a + /* The following ID blatantly violate MS specs by using a */ + /* sublanguage > 0x1F. */ +#define TT_MS_LANGID_SPANISH_LATIN_AMERICA 0xE40aU +#define TT_MS_LANGID_FINNISH_FINLAND 0x040b +#define TT_MS_LANGID_FRENCH_FRANCE 0x040c +#define TT_MS_LANGID_FRENCH_BELGIUM 0x080c +#define TT_MS_LANGID_FRENCH_CANADA 0x0c0c +#define TT_MS_LANGID_FRENCH_SWITZERLAND 0x100c +#define TT_MS_LANGID_FRENCH_LUXEMBOURG 0x140c +#define TT_MS_LANGID_FRENCH_MONACO 0x180c +#define TT_MS_LANGID_FRENCH_WEST_INDIES 0x1c0c +#define TT_MS_LANGID_FRENCH_REUNION 0x200c +#define TT_MS_LANGID_FRENCH_CONGO 0x240c + /* which was formerly: */ +#define TT_MS_LANGID_FRENCH_ZAIRE TT_MS_LANGID_FRENCH_CONGO +#define TT_MS_LANGID_FRENCH_SENEGAL 0x280c +#define TT_MS_LANGID_FRENCH_CAMEROON 0x2c0c +#define TT_MS_LANGID_FRENCH_COTE_D_IVOIRE 0x300c +#define TT_MS_LANGID_FRENCH_MALI 0x340c +#define TT_MS_LANGID_FRENCH_MOROCCO 0x380c +#define TT_MS_LANGID_FRENCH_HAITI 0x3c0c + /* and another violation of the spec (see 0xE40aU) */ +#define TT_MS_LANGID_FRENCH_NORTH_AFRICA 0xE40cU +#define TT_MS_LANGID_HEBREW_ISRAEL 0x040d +#define TT_MS_LANGID_HUNGARIAN_HUNGARY 0x040e +#define TT_MS_LANGID_ICELANDIC_ICELAND 0x040f +#define TT_MS_LANGID_ITALIAN_ITALY 0x0410 +#define TT_MS_LANGID_ITALIAN_SWITZERLAND 0x0810 +#define TT_MS_LANGID_JAPANESE_JAPAN 0x0411 +#define TT_MS_LANGID_KOREAN_EXTENDED_WANSUNG_KOREA 0x0412 +#define TT_MS_LANGID_KOREAN_JOHAB_KOREA 0x0812 +#define TT_MS_LANGID_DUTCH_NETHERLANDS 0x0413 +#define TT_MS_LANGID_DUTCH_BELGIUM 0x0813 +#define TT_MS_LANGID_NORWEGIAN_NORWAY_BOKMAL 0x0414 +#define TT_MS_LANGID_NORWEGIAN_NORWAY_NYNORSK 0x0814 +#define TT_MS_LANGID_POLISH_POLAND 0x0415 +#define TT_MS_LANGID_PORTUGUESE_BRAZIL 0x0416 +#define TT_MS_LANGID_PORTUGUESE_PORTUGAL 0x0816 +#define TT_MS_LANGID_RHAETO_ROMANIC_SWITZERLAND 0x0417 +#define TT_MS_LANGID_ROMANIAN_ROMANIA 0x0418 +#define TT_MS_LANGID_MOLDAVIAN_MOLDAVIA 0x0818 +#define TT_MS_LANGID_RUSSIAN_RUSSIA 0x0419 +#define TT_MS_LANGID_RUSSIAN_MOLDAVIA 0x0819 +#define TT_MS_LANGID_CROATIAN_CROATIA 0x041a +#define TT_MS_LANGID_SERBIAN_SERBIA_LATIN 0x081a +#define TT_MS_LANGID_SERBIAN_SERBIA_CYRILLIC 0x0c1a + +#if 0 /* this used to be this value, but it looks like we were wrong */ +#define TT_MS_LANGID_BOSNIAN_BOSNIA_HERZEGOVINA 0x101a +#else /* current sources say */ +#define TT_MS_LANGID_CROATIAN_BOSNIA_HERZEGOVINA 0x101a +#define TT_MS_LANGID_BOSNIAN_BOSNIA_HERZEGOVINA 0x141a + /* and XPsp2 Platform SDK added (2004-07-26) */ + /* Names are shortened to be significant within 40 chars. */ +#define TT_MS_LANGID_SERBIAN_BOSNIA_HERZ_LATIN 0x181a +#define TT_MS_LANGID_SERBIAN_BOSNIA_HERZ_CYRILLIC 0x181a +#endif + +#define TT_MS_LANGID_SLOVAK_SLOVAKIA 0x041b +#define TT_MS_LANGID_ALBANIAN_ALBANIA 0x041c +#define TT_MS_LANGID_SWEDISH_SWEDEN 0x041d +#define TT_MS_LANGID_SWEDISH_FINLAND 0x081d +#define TT_MS_LANGID_THAI_THAILAND 0x041e +#define TT_MS_LANGID_TURKISH_TURKEY 0x041f +#define TT_MS_LANGID_URDU_PAKISTAN 0x0420 +#define TT_MS_LANGID_URDU_INDIA 0x0820 +#define TT_MS_LANGID_INDONESIAN_INDONESIA 0x0421 +#define TT_MS_LANGID_UKRAINIAN_UKRAINE 0x0422 +#define TT_MS_LANGID_BELARUSIAN_BELARUS 0x0423 +#define TT_MS_LANGID_SLOVENE_SLOVENIA 0x0424 +#define TT_MS_LANGID_ESTONIAN_ESTONIA 0x0425 +#define TT_MS_LANGID_LATVIAN_LATVIA 0x0426 +#define TT_MS_LANGID_LITHUANIAN_LITHUANIA 0x0427 +#define TT_MS_LANGID_CLASSIC_LITHUANIAN_LITHUANIA 0x0827 +#define TT_MS_LANGID_TAJIK_TAJIKISTAN 0x0428 +#define TT_MS_LANGID_FARSI_IRAN 0x0429 +#define TT_MS_LANGID_VIETNAMESE_VIET_NAM 0x042a +#define TT_MS_LANGID_ARMENIAN_ARMENIA 0x042b +#define TT_MS_LANGID_AZERI_AZERBAIJAN_LATIN 0x042c +#define TT_MS_LANGID_AZERI_AZERBAIJAN_CYRILLIC 0x082c +#define TT_MS_LANGID_BASQUE_SPAIN 0x042d +#define TT_MS_LANGID_SORBIAN_GERMANY 0x042e +#define TT_MS_LANGID_MACEDONIAN_MACEDONIA 0x042f +#define TT_MS_LANGID_SUTU_SOUTH_AFRICA 0x0430 +#define TT_MS_LANGID_TSONGA_SOUTH_AFRICA 0x0431 +#define TT_MS_LANGID_TSWANA_SOUTH_AFRICA 0x0432 +#define TT_MS_LANGID_VENDA_SOUTH_AFRICA 0x0433 +#define TT_MS_LANGID_XHOSA_SOUTH_AFRICA 0x0434 +#define TT_MS_LANGID_ZULU_SOUTH_AFRICA 0x0435 +#define TT_MS_LANGID_AFRIKAANS_SOUTH_AFRICA 0x0436 +#define TT_MS_LANGID_GEORGIAN_GEORGIA 0x0437 +#define TT_MS_LANGID_FAEROESE_FAEROE_ISLANDS 0x0438 +#define TT_MS_LANGID_HINDI_INDIA 0x0439 +#define TT_MS_LANGID_MALTESE_MALTA 0x043a + /* Added by XPsp2 Platform SDK (2004-07-26) */ +#define TT_MS_LANGID_SAMI_NORTHERN_NORWAY 0x043b +#define TT_MS_LANGID_SAMI_NORTHERN_SWEDEN 0x083b +#define TT_MS_LANGID_SAMI_NORTHERN_FINLAND 0x0C3b +#define TT_MS_LANGID_SAMI_LULE_NORWAY 0x103b +#define TT_MS_LANGID_SAMI_LULE_SWEDEN 0x143b +#define TT_MS_LANGID_SAMI_SOUTHERN_NORWAY 0x183b +#define TT_MS_LANGID_SAMI_SOUTHERN_SWEDEN 0x1C3b +#define TT_MS_LANGID_SAMI_SKOLT_FINLAND 0x203b +#define TT_MS_LANGID_SAMI_INARI_FINLAND 0x243b + /* ... and we also keep our old identifier... */ +#define TT_MS_LANGID_SAAMI_LAPONIA 0x043b + +#if 0 /* this seems to be a previous inversion */ +#define TT_MS_LANGID_IRISH_GAELIC_IRELAND 0x043c +#define TT_MS_LANGID_SCOTTISH_GAELIC_UNITED_KINGDOM 0x083c +#else +#define TT_MS_LANGID_SCOTTISH_GAELIC_UNITED_KINGDOM 0x083c +#define TT_MS_LANGID_IRISH_GAELIC_IRELAND 0x043c +#endif + +#define TT_MS_LANGID_YIDDISH_GERMANY 0x043d +#define TT_MS_LANGID_MALAY_MALAYSIA 0x043e +#define TT_MS_LANGID_MALAY_BRUNEI_DARUSSALAM 0x083e +#define TT_MS_LANGID_KAZAK_KAZAKSTAN 0x043f +#define TT_MS_LANGID_KIRGHIZ_KIRGHIZSTAN /* Cyrillic*/ 0x0440 + /* alias declared in Windows 2000 */ +#define TT_MS_LANGID_KIRGHIZ_KIRGHIZ_REPUBLIC \ + TT_MS_LANGID_KIRGHIZ_KIRGHIZSTAN + +#define TT_MS_LANGID_SWAHILI_KENYA 0x0441 +#define TT_MS_LANGID_TURKMEN_TURKMENISTAN 0x0442 +#define TT_MS_LANGID_UZBEK_UZBEKISTAN_LATIN 0x0443 +#define TT_MS_LANGID_UZBEK_UZBEKISTAN_CYRILLIC 0x0843 +#define TT_MS_LANGID_TATAR_TATARSTAN 0x0444 +#define TT_MS_LANGID_BENGALI_INDIA 0x0445 +#define TT_MS_LANGID_BENGALI_BANGLADESH 0x0845 +#define TT_MS_LANGID_PUNJABI_INDIA 0x0446 +#define TT_MS_LANGID_PUNJABI_ARABIC_PAKISTAN 0x0846 +#define TT_MS_LANGID_GUJARATI_INDIA 0x0447 +#define TT_MS_LANGID_ORIYA_INDIA 0x0448 +#define TT_MS_LANGID_TAMIL_INDIA 0x0449 +#define TT_MS_LANGID_TELUGU_INDIA 0x044a +#define TT_MS_LANGID_KANNADA_INDIA 0x044b +#define TT_MS_LANGID_MALAYALAM_INDIA 0x044c +#define TT_MS_LANGID_ASSAMESE_INDIA 0x044d +#define TT_MS_LANGID_MARATHI_INDIA 0x044e +#define TT_MS_LANGID_SANSKRIT_INDIA 0x044f +#define TT_MS_LANGID_MONGOLIAN_MONGOLIA /* Cyrillic */ 0x0450 +#define TT_MS_LANGID_MONGOLIAN_MONGOLIA_MONGOLIAN 0x0850 +#define TT_MS_LANGID_TIBETAN_CHINA 0x0451 + /* Don't use the next constant! It has */ + /* (1) the wrong spelling (Dzonghka) */ + /* (2) Microsoft doesn't officially define it -- */ + /* at least it is not in the List of Local */ + /* ID Values. */ + /* (3) Dzongkha is not the same language as */ + /* Tibetan, so merging it is wrong anyway. */ + /* */ + /* TT_MS_LANGID_TIBETAN_BHUTAN is correct, BTW. */ +#define TT_MS_LANGID_DZONGHKA_BHUTAN 0x0851 + +#if 0 + /* the following used to be defined */ +#define TT_MS_LANGID_TIBETAN_BHUTAN 0x0451 + /* ... but it was changed; */ +#else + /* So we will continue to #define it, but with the correct value */ +#define TT_MS_LANGID_TIBETAN_BHUTAN TT_MS_LANGID_DZONGHKA_BHUTAN +#endif + +#define TT_MS_LANGID_WELSH_WALES 0x0452 +#define TT_MS_LANGID_KHMER_CAMBODIA 0x0453 +#define TT_MS_LANGID_LAO_LAOS 0x0454 +#define TT_MS_LANGID_BURMESE_MYANMAR 0x0455 +#define TT_MS_LANGID_GALICIAN_SPAIN 0x0456 +#define TT_MS_LANGID_KONKANI_INDIA 0x0457 +#define TT_MS_LANGID_MANIPURI_INDIA /* Bengali */ 0x0458 +#define TT_MS_LANGID_SINDHI_INDIA /* Arabic */ 0x0459 +#define TT_MS_LANGID_SINDHI_PAKISTAN 0x0859 + /* Missing a LCID for Sindhi in Devanagari script */ +#define TT_MS_LANGID_SYRIAC_SYRIA 0x045a +#define TT_MS_LANGID_SINHALESE_SRI_LANKA 0x045b +#define TT_MS_LANGID_CHEROKEE_UNITED_STATES 0x045c +#define TT_MS_LANGID_INUKTITUT_CANADA 0x045d +#define TT_MS_LANGID_AMHARIC_ETHIOPIA 0x045e +#define TT_MS_LANGID_TAMAZIGHT_MOROCCO /* Arabic */ 0x045f +#define TT_MS_LANGID_TAMAZIGHT_MOROCCO_LATIN 0x085f + /* Missing a LCID for Tifinagh script */ +#define TT_MS_LANGID_KASHMIRI_PAKISTAN /* Arabic */ 0x0460 + /* Spelled this way by XPsp2 Platform SDK (2004-07-26) */ + /* script is yet unclear... might be Arabic, Nagari or Sharada */ +#define TT_MS_LANGID_KASHMIRI_SASIA 0x0860 + /* ... and aliased (by MS) for compatibility reasons. */ +#define TT_MS_LANGID_KASHMIRI_INDIA TT_MS_LANGID_KASHMIRI_SASIA +#define TT_MS_LANGID_NEPALI_NEPAL 0x0461 +#define TT_MS_LANGID_NEPALI_INDIA 0x0861 +#define TT_MS_LANGID_FRISIAN_NETHERLANDS 0x0462 +#define TT_MS_LANGID_PASHTO_AFGHANISTAN 0x0463 +#define TT_MS_LANGID_FILIPINO_PHILIPPINES 0x0464 +#define TT_MS_LANGID_DHIVEHI_MALDIVES 0x0465 + /* alias declared in Windows 2000 */ +#define TT_MS_LANGID_DIVEHI_MALDIVES TT_MS_LANGID_DHIVEHI_MALDIVES +#define TT_MS_LANGID_EDO_NIGERIA 0x0466 +#define TT_MS_LANGID_FULFULDE_NIGERIA 0x0467 +#define TT_MS_LANGID_HAUSA_NIGERIA 0x0468 +#define TT_MS_LANGID_IBIBIO_NIGERIA 0x0469 +#define TT_MS_LANGID_YORUBA_NIGERIA 0x046a +#define TT_MS_LANGID_QUECHUA_BOLIVIA 0x046b +#define TT_MS_LANGID_QUECHUA_ECUADOR 0x086b +#define TT_MS_LANGID_QUECHUA_PERU 0x0c6b +#define TT_MS_LANGID_SEPEDI_SOUTH_AFRICA 0x046c + /* Also spelled by XPsp2 Platform SDK (2004-07-26) */ +#define TT_MS_LANGID_SOTHO_SOUTHERN_SOUTH_AFRICA \ + TT_MS_LANGID_SEPEDI_SOUTH_AFRICA + /* language codes 0x046d, 0x046e and 0x046f are (still) unknown. */ +#define TT_MS_LANGID_IGBO_NIGERIA 0x0470 +#define TT_MS_LANGID_KANURI_NIGERIA 0x0471 +#define TT_MS_LANGID_OROMO_ETHIOPIA 0x0472 +#define TT_MS_LANGID_TIGRIGNA_ETHIOPIA 0x0473 +#define TT_MS_LANGID_TIGRIGNA_ERYTHREA 0x0873 + /* also spelled in the `Passport SDK' list as: */ +#define TT_MS_LANGID_TIGRIGNA_ERYTREA TT_MS_LANGID_TIGRIGNA_ERYTHREA +#define TT_MS_LANGID_GUARANI_PARAGUAY 0x0474 +#define TT_MS_LANGID_HAWAIIAN_UNITED_STATES 0x0475 +#define TT_MS_LANGID_LATIN 0x0476 +#define TT_MS_LANGID_SOMALI_SOMALIA 0x0477 + /* Note: Yi does not have a (proper) ISO 639-2 code, since it is mostly */ + /* not written (but OTOH the peculiar writing system is worth */ + /* studying). */ +#define TT_MS_LANGID_YI_CHINA 0x0478 +#define TT_MS_LANGID_PAPIAMENTU_NETHERLANDS_ANTILLES 0x0479 + /* language codes from 0x047a to 0x047f are (still) unknown. */ +#define TT_MS_LANGID_UIGHUR_CHINA 0x0480 +#define TT_MS_LANGID_MAORI_NEW_ZEALAND 0x0481 + +#if 0 /* not deemed useful for fonts */ +#define TT_MS_LANGID_HUMAN_INTERFACE_DEVICE 0x04ff +#endif + + + /*************************************************************************/ + /* */ + /* Possible values of the `name' identifier field in the name records of */ + /* the TTF `name' table. These values are platform independent. */ + /* */ +#define TT_NAME_ID_COPYRIGHT 0 +#define TT_NAME_ID_FONT_FAMILY 1 +#define TT_NAME_ID_FONT_SUBFAMILY 2 +#define TT_NAME_ID_UNIQUE_ID 3 +#define TT_NAME_ID_FULL_NAME 4 +#define TT_NAME_ID_VERSION_STRING 5 +#define TT_NAME_ID_PS_NAME 6 +#define TT_NAME_ID_TRADEMARK 7 + + /* the following values are from the OpenType spec */ +#define TT_NAME_ID_MANUFACTURER 8 +#define TT_NAME_ID_DESIGNER 9 +#define TT_NAME_ID_DESCRIPTION 10 +#define TT_NAME_ID_VENDOR_URL 11 +#define TT_NAME_ID_DESIGNER_URL 12 +#define TT_NAME_ID_LICENSE 13 +#define TT_NAME_ID_LICENSE_URL 14 + /* number 15 is reserved */ +#define TT_NAME_ID_PREFERRED_FAMILY 16 +#define TT_NAME_ID_PREFERRED_SUBFAMILY 17 +#define TT_NAME_ID_MAC_FULL_NAME 18 + + /* The following code is new as of 2000-01-21 */ +#define TT_NAME_ID_SAMPLE_TEXT 19 + + /* This is new in OpenType 1.3 */ +#define TT_NAME_ID_CID_FINDFONT_NAME 20 + + /* This is new in OpenType 1.5 */ +#define TT_NAME_ID_WWS_FAMILY 21 +#define TT_NAME_ID_WWS_SUBFAMILY 22 + + + /*************************************************************************/ + /* */ + /* Bit mask values for the Unicode Ranges from the TTF `OS2 ' table. */ + /* */ + /* Updated 08-Nov-2008. */ + /* */ + + /* Bit 0 Basic Latin */ +#define TT_UCR_BASIC_LATIN (1L << 0) /* U+0020-U+007E */ + /* Bit 1 C1 Controls and Latin-1 Supplement */ +#define TT_UCR_LATIN1_SUPPLEMENT (1L << 1) /* U+0080-U+00FF */ + /* Bit 2 Latin Extended-A */ +#define TT_UCR_LATIN_EXTENDED_A (1L << 2) /* U+0100-U+017F */ + /* Bit 3 Latin Extended-B */ +#define TT_UCR_LATIN_EXTENDED_B (1L << 3) /* U+0180-U+024F */ + /* Bit 4 IPA Extensions */ + /* Phonetic Extensions */ + /* Phonetic Extensions Supplement */ +#define TT_UCR_IPA_EXTENSIONS (1L << 4) /* U+0250-U+02AF */ + /* U+1D00-U+1D7F */ + /* U+1D80-U+1DBF */ + /* Bit 5 Spacing Modifier Letters */ + /* Modifier Tone Letters */ +#define TT_UCR_SPACING_MODIFIER (1L << 5) /* U+02B0-U+02FF */ + /* U+A700-U+A71F */ + /* Bit 6 Combining Diacritical Marks */ + /* Combining Diacritical Marks Supplement */ +#define TT_UCR_COMBINING_DIACRITICS (1L << 6) /* U+0300-U+036F */ + /* U+1DC0-U+1DFF */ + /* Bit 7 Greek and Coptic */ +#define TT_UCR_GREEK (1L << 7) /* U+0370-U+03FF */ + /* Bit 8 Coptic */ +#define TT_UCR_COPTIC (1L << 8) /* U+2C80-U+2CFF */ + /* Bit 9 Cyrillic */ + /* Cyrillic Supplement */ + /* Cyrillic Extended-A */ + /* Cyrillic Extended-B */ +#define TT_UCR_CYRILLIC (1L << 9) /* U+0400-U+04FF */ + /* U+0500-U+052F */ + /* U+2DE0-U+2DFF */ + /* U+A640-U+A69F */ + /* Bit 10 Armenian */ +#define TT_UCR_ARMENIAN (1L << 10) /* U+0530-U+058F */ + /* Bit 11 Hebrew */ +#define TT_UCR_HEBREW (1L << 11) /* U+0590-U+05FF */ + /* Bit 12 Vai */ +#define TT_UCR_VAI (1L << 12) /* U+A500-U+A63F */ + /* Bit 13 Arabic */ + /* Arabic Supplement */ +#define TT_UCR_ARABIC (1L << 13) /* U+0600-U+06FF */ + /* U+0750-U+077F */ + /* Bit 14 NKo */ +#define TT_UCR_NKO (1L << 14) /* U+07C0-U+07FF */ + /* Bit 15 Devanagari */ +#define TT_UCR_DEVANAGARI (1L << 15) /* U+0900-U+097F */ + /* Bit 16 Bengali */ +#define TT_UCR_BENGALI (1L << 16) /* U+0980-U+09FF */ + /* Bit 17 Gurmukhi */ +#define TT_UCR_GURMUKHI (1L << 17) /* U+0A00-U+0A7F */ + /* Bit 18 Gujarati */ +#define TT_UCR_GUJARATI (1L << 18) /* U+0A80-U+0AFF */ + /* Bit 19 Oriya */ +#define TT_UCR_ORIYA (1L << 19) /* U+0B00-U+0B7F */ + /* Bit 20 Tamil */ +#define TT_UCR_TAMIL (1L << 20) /* U+0B80-U+0BFF */ + /* Bit 21 Telugu */ +#define TT_UCR_TELUGU (1L << 21) /* U+0C00-U+0C7F */ + /* Bit 22 Kannada */ +#define TT_UCR_KANNADA (1L << 22) /* U+0C80-U+0CFF */ + /* Bit 23 Malayalam */ +#define TT_UCR_MALAYALAM (1L << 23) /* U+0D00-U+0D7F */ + /* Bit 24 Thai */ +#define TT_UCR_THAI (1L << 24) /* U+0E00-U+0E7F */ + /* Bit 25 Lao */ +#define TT_UCR_LAO (1L << 25) /* U+0E80-U+0EFF */ + /* Bit 26 Georgian */ + /* Georgian Supplement */ +#define TT_UCR_GEORGIAN (1L << 26) /* U+10A0-U+10FF */ + /* U+2D00-U+2D2F */ + /* Bit 27 Balinese */ +#define TT_UCR_BALINESE (1L << 27) /* U+1B00-U+1B7F */ + /* Bit 28 Hangul Jamo */ +#define TT_UCR_HANGUL_JAMO (1L << 28) /* U+1100-U+11FF */ + /* Bit 29 Latin Extended Additional */ + /* Latin Extended-C */ + /* Latin Extended-D */ +#define TT_UCR_LATIN_EXTENDED_ADDITIONAL (1L << 29) /* U+1E00-U+1EFF */ + /* U+2C60-U+2C7F */ + /* U+A720-U+A7FF */ + /* Bit 30 Greek Extended */ +#define TT_UCR_GREEK_EXTENDED (1L << 30) /* U+1F00-U+1FFF */ + /* Bit 31 General Punctuation */ + /* Supplemental Punctuation */ +#define TT_UCR_GENERAL_PUNCTUATION (1L << 31) /* U+2000-U+206F */ + /* U+2E00-U+2E7F */ + /* Bit 32 Superscripts And Subscripts */ +#define TT_UCR_SUPERSCRIPTS_SUBSCRIPTS (1L << 0) /* U+2070-U+209F */ + /* Bit 33 Currency Symbols */ +#define TT_UCR_CURRENCY_SYMBOLS (1L << 1) /* U+20A0-U+20CF */ + /* Bit 34 Combining Diacritical Marks For Symbols */ +#define TT_UCR_COMBINING_DIACRITICS_SYMB (1L << 2) /* U+20D0-U+20FF */ + /* Bit 35 Letterlike Symbols */ +#define TT_UCR_LETTERLIKE_SYMBOLS (1L << 3) /* U+2100-U+214F */ + /* Bit 36 Number Forms */ +#define TT_UCR_NUMBER_FORMS (1L << 4) /* U+2150-U+218F */ + /* Bit 37 Arrows */ + /* Supplemental Arrows-A */ + /* Supplemental Arrows-B */ + /* Miscellaneous Symbols and Arrows */ +#define TT_UCR_ARROWS (1L << 5) /* U+2190-U+21FF */ + /* U+27F0-U+27FF */ + /* U+2900-U+297F */ + /* U+2B00-U+2BFF */ + /* Bit 38 Mathematical Operators */ + /* Supplemental Mathematical Operators */ + /* Miscellaneous Mathematical Symbols-A */ + /* Miscellaneous Mathematical Symbols-B */ +#define TT_UCR_MATHEMATICAL_OPERATORS (1L << 6) /* U+2200-U+22FF */ + /* U+2A00-U+2AFF */ + /* U+27C0-U+27EF */ + /* U+2980-U+29FF */ + /* Bit 39 Miscellaneous Technical */ +#define TT_UCR_MISCELLANEOUS_TECHNICAL (1L << 7) /* U+2300-U+23FF */ + /* Bit 40 Control Pictures */ +#define TT_UCR_CONTROL_PICTURES (1L << 8) /* U+2400-U+243F */ + /* Bit 41 Optical Character Recognition */ +#define TT_UCR_OCR (1L << 9) /* U+2440-U+245F */ + /* Bit 42 Enclosed Alphanumerics */ +#define TT_UCR_ENCLOSED_ALPHANUMERICS (1L << 10) /* U+2460-U+24FF */ + /* Bit 43 Box Drawing */ +#define TT_UCR_BOX_DRAWING (1L << 11) /* U+2500-U+257F */ + /* Bit 44 Block Elements */ +#define TT_UCR_BLOCK_ELEMENTS (1L << 12) /* U+2580-U+259F */ + /* Bit 45 Geometric Shapes */ +#define TT_UCR_GEOMETRIC_SHAPES (1L << 13) /* U+25A0-U+25FF */ + /* Bit 46 Miscellaneous Symbols */ +#define TT_UCR_MISCELLANEOUS_SYMBOLS (1L << 14) /* U+2600-U+26FF */ + /* Bit 47 Dingbats */ +#define TT_UCR_DINGBATS (1L << 15) /* U+2700-U+27BF */ + /* Bit 48 CJK Symbols and Punctuation */ +#define TT_UCR_CJK_SYMBOLS (1L << 16) /* U+3000-U+303F */ + /* Bit 49 Hiragana */ +#define TT_UCR_HIRAGANA (1L << 17) /* U+3040-U+309F */ + /* Bit 50 Katakana */ + /* Katakana Phonetic Extensions */ +#define TT_UCR_KATAKANA (1L << 18) /* U+30A0-U+30FF */ + /* U+31F0-U+31FF */ + /* Bit 51 Bopomofo */ + /* Bopomofo Extended */ +#define TT_UCR_BOPOMOFO (1L << 19) /* U+3100-U+312F */ + /* U+31A0-U+31BF */ + /* Bit 52 Hangul Compatibility Jamo */ +#define TT_UCR_HANGUL_COMPATIBILITY_JAMO (1L << 20) /* U+3130-U+318F */ + /* Bit 53 Phags-Pa */ +#define TT_UCR_CJK_MISC (1L << 21) /* U+A840-U+A87F */ +#define TT_UCR_KANBUN TT_UCR_CJK_MISC /* deprecated */ +#define TT_UCR_PHAGSPA + /* Bit 54 Enclosed CJK Letters and Months */ +#define TT_UCR_ENCLOSED_CJK_LETTERS_MONTHS (1L << 22) /* U+3200-U+32FF */ + /* Bit 55 CJK Compatibility */ +#define TT_UCR_CJK_COMPATIBILITY (1L << 23) /* U+3300-U+33FF */ + /* Bit 56 Hangul Syllables */ +#define TT_UCR_HANGUL (1L << 24) /* U+AC00-U+D7A3 */ + /* Bit 57 High Surrogates */ + /* High Private Use Surrogates */ + /* Low Surrogates */ + /* */ + /* According to OpenType specs v.1.3+, */ + /* setting bit 57 implies that there is */ + /* at least one codepoint beyond the */ + /* Basic Multilingual Plane that is */ + /* supported by this font. So it really */ + /* means >= U+10000 */ +#define TT_UCR_SURROGATES (1L << 25) /* U+D800-U+DB7F */ + /* U+DB80-U+DBFF */ + /* U+DC00-U+DFFF */ +#define TT_UCR_NON_PLANE_0 TT_UCR_SURROGATES + /* Bit 58 Phoenician */ +#define TT_UCR_PHOENICIAN (1L << 26) /*U+10900-U+1091F*/ + /* Bit 59 CJK Unified Ideographs */ + /* CJK Radicals Supplement */ + /* Kangxi Radicals */ + /* Ideographic Description Characters */ + /* CJK Unified Ideographs Extension A */ + /* CJK Unified Ideographs Extension B */ + /* Kanbun */ +#define TT_UCR_CJK_UNIFIED_IDEOGRAPHS (1L << 27) /* U+4E00-U+9FFF */ + /* U+2E80-U+2EFF */ + /* U+2F00-U+2FDF */ + /* U+2FF0-U+2FFF */ + /* U+3400-U+4DB5 */ + /*U+20000-U+2A6DF*/ + /* U+3190-U+319F */ + /* Bit 60 Private Use */ +#define TT_UCR_PRIVATE_USE (1L << 28) /* U+E000-U+F8FF */ + /* Bit 61 CJK Strokes */ + /* CJK Compatibility Ideographs */ + /* CJK Compatibility Ideographs Supplement */ +#define TT_UCR_CJK_COMPATIBILITY_IDEOGRAPHS (1L << 29) /* U+31C0-U+31EF */ + /* U+F900-U+FAFF */ + /*U+2F800-U+2FA1F*/ + /* Bit 62 Alphabetic Presentation Forms */ +#define TT_UCR_ALPHABETIC_PRESENTATION_FORMS (1L << 30) /* U+FB00-U+FB4F */ + /* Bit 63 Arabic Presentation Forms-A */ +#define TT_UCR_ARABIC_PRESENTATIONS_A (1L << 31) /* U+FB50-U+FDFF */ + /* Bit 64 Combining Half Marks */ +#define TT_UCR_COMBINING_HALF_MARKS (1L << 0) /* U+FE20-U+FE2F */ + /* Bit 65 Vertical forms */ + /* CJK Compatibility Forms */ +#define TT_UCR_CJK_COMPATIBILITY_FORMS (1L << 1) /* U+FE10-U+FE1F */ + /* U+FE30-U+FE4F */ + /* Bit 66 Small Form Variants */ +#define TT_UCR_SMALL_FORM_VARIANTS (1L << 2) /* U+FE50-U+FE6F */ + /* Bit 67 Arabic Presentation Forms-B */ +#define TT_UCR_ARABIC_PRESENTATIONS_B (1L << 3) /* U+FE70-U+FEFE */ + /* Bit 68 Halfwidth and Fullwidth Forms */ +#define TT_UCR_HALFWIDTH_FULLWIDTH_FORMS (1L << 4) /* U+FF00-U+FFEF */ + /* Bit 69 Specials */ +#define TT_UCR_SPECIALS (1L << 5) /* U+FFF0-U+FFFD */ + /* Bit 70 Tibetan */ +#define TT_UCR_TIBETAN (1L << 6) /* U+0F00-U+0FFF */ + /* Bit 71 Syriac */ +#define TT_UCR_SYRIAC (1L << 7) /* U+0700-U+074F */ + /* Bit 72 Thaana */ +#define TT_UCR_THAANA (1L << 8) /* U+0780-U+07BF */ + /* Bit 73 Sinhala */ +#define TT_UCR_SINHALA (1L << 9) /* U+0D80-U+0DFF */ + /* Bit 74 Myanmar */ +#define TT_UCR_MYANMAR (1L << 10) /* U+1000-U+109F */ + /* Bit 75 Ethiopic */ + /* Ethiopic Supplement */ + /* Ethiopic Extended */ +#define TT_UCR_ETHIOPIC (1L << 11) /* U+1200-U+137F */ + /* U+1380-U+139F */ + /* U+2D80-U+2DDF */ + /* Bit 76 Cherokee */ +#define TT_UCR_CHEROKEE (1L << 12) /* U+13A0-U+13FF */ + /* Bit 77 Unified Canadian Aboriginal Syllabics */ +#define TT_UCR_CANADIAN_ABORIGINAL_SYLLABICS (1L << 13) /* U+1400-U+167F */ + /* Bit 78 Ogham */ +#define TT_UCR_OGHAM (1L << 14) /* U+1680-U+169F */ + /* Bit 79 Runic */ +#define TT_UCR_RUNIC (1L << 15) /* U+16A0-U+16FF */ + /* Bit 80 Khmer */ + /* Khmer Symbols */ +#define TT_UCR_KHMER (1L << 16) /* U+1780-U+17FF */ + /* U+19E0-U+19FF */ + /* Bit 81 Mongolian */ +#define TT_UCR_MONGOLIAN (1L << 17) /* U+1800-U+18AF */ + /* Bit 82 Braille Patterns */ +#define TT_UCR_BRAILLE (1L << 18) /* U+2800-U+28FF */ + /* Bit 83 Yi Syllables */ + /* Yi Radicals */ +#define TT_UCR_YI (1L << 19) /* U+A000-U+A48F */ + /* U+A490-U+A4CF */ + /* Bit 84 Tagalog */ + /* Hanunoo */ + /* Buhid */ + /* Tagbanwa */ +#define TT_UCR_PHILIPPINE (1L << 20) /* U+1700-U+171F */ + /* U+1720-U+173F */ + /* U+1740-U+175F */ + /* U+1760-U+177F */ + /* Bit 85 Old Italic */ +#define TT_UCR_OLD_ITALIC (1L << 21) /*U+10300-U+1032F*/ + /* Bit 86 Gothic */ +#define TT_UCR_GOTHIC (1L << 22) /*U+10330-U+1034F*/ + /* Bit 87 Deseret */ +#define TT_UCR_DESERET (1L << 23) /*U+10400-U+1044F*/ + /* Bit 88 Byzantine Musical Symbols */ + /* Musical Symbols */ + /* Ancient Greek Musical Notation */ +#define TT_UCR_MUSICAL_SYMBOLS (1L << 24) /*U+1D000-U+1D0FF*/ + /*U+1D100-U+1D1FF*/ + /*U+1D200-U+1D24F*/ + /* Bit 89 Mathematical Alphanumeric Symbols */ +#define TT_UCR_MATH_ALPHANUMERIC_SYMBOLS (1L << 25) /*U+1D400-U+1D7FF*/ + /* Bit 90 Private Use (plane 15) */ + /* Private Use (plane 16) */ +#define TT_UCR_PRIVATE_USE_SUPPLEMENTARY (1L << 26) /*U+F0000-U+FFFFD*/ + /*U+100000-U+10FFFD*/ + /* Bit 91 Variation Selectors */ + /* Variation Selectors Supplement */ +#define TT_UCR_VARIATION_SELECTORS (1L << 27) /* U+FE00-U+FE0F */ + /*U+E0100-U+E01EF*/ + /* Bit 92 Tags */ +#define TT_UCR_TAGS (1L << 28) /*U+E0000-U+E007F*/ + /* Bit 93 Limbu */ +#define TT_UCR_LIMBU (1L << 29) /* U+1900-U+194F */ + /* Bit 94 Tai Le */ +#define TT_UCR_TAI_LE (1L << 30) /* U+1950-U+197F */ + /* Bit 95 New Tai Lue */ +#define TT_UCR_NEW_TAI_LUE (1L << 31) /* U+1980-U+19DF */ + /* Bit 96 Buginese */ +#define TT_UCR_BUGINESE (1L << 0) /* U+1A00-U+1A1F */ + /* Bit 97 Glagolitic */ +#define TT_UCR_GLAGOLITIC (1L << 1) /* U+2C00-U+2C5F */ + /* Bit 98 Tifinagh */ +#define TT_UCR_TIFINAGH (1L << 2) /* U+2D30-U+2D7F */ + /* Bit 99 Yijing Hexagram Symbols */ +#define TT_UCR_YIJING (1L << 3) /* U+4DC0-U+4DFF */ + /* Bit 100 Syloti Nagri */ +#define TT_UCR_SYLOTI_NAGRI (1L << 4) /* U+A800-U+A82F */ + /* Bit 101 Linear B Syllabary */ + /* Linear B Ideograms */ + /* Aegean Numbers */ +#define TT_UCR_LINEAR_B (1L << 5) /*U+10000-U+1007F*/ + /*U+10080-U+100FF*/ + /*U+10100-U+1013F*/ + /* Bit 102 Ancient Greek Numbers */ +#define TT_UCR_ANCIENT_GREEK_NUMBERS (1L << 6) /*U+10140-U+1018F*/ + /* Bit 103 Ugaritic */ +#define TT_UCR_UGARITIC (1L << 7) /*U+10380-U+1039F*/ + /* Bit 104 Old Persian */ +#define TT_UCR_OLD_PERSIAN (1L << 8) /*U+103A0-U+103DF*/ + /* Bit 105 Shavian */ +#define TT_UCR_SHAVIAN (1L << 9) /*U+10450-U+1047F*/ + /* Bit 106 Osmanya */ +#define TT_UCR_OSMANYA (1L << 10) /*U+10480-U+104AF*/ + /* Bit 107 Cypriot Syllabary */ +#define TT_UCR_CYPRIOT_SYLLABARY (1L << 11) /*U+10800-U+1083F*/ + /* Bit 108 Kharoshthi */ +#define TT_UCR_KHAROSHTHI (1L << 12) /*U+10A00-U+10A5F*/ + /* Bit 109 Tai Xuan Jing Symbols */ +#define TT_UCR_TAI_XUAN_JING (1L << 13) /*U+1D300-U+1D35F*/ + /* Bit 110 Cuneiform */ + /* Cuneiform Numbers and Punctuation */ +#define TT_UCR_CUNEIFORM (1L << 14) /*U+12000-U+123FF*/ + /*U+12400-U+1247F*/ + /* Bit 111 Counting Rod Numerals */ +#define TT_UCR_COUNTING_ROD_NUMERALS (1L << 15) /*U+1D360-U+1D37F*/ + /* Bit 112 Sundanese */ +#define TT_UCR_SUNDANESE (1L << 16) /* U+1B80-U+1BBF */ + /* Bit 113 Lepcha */ +#define TT_UCR_LEPCHA (1L << 17) /* U+1C00-U+1C4F */ + /* Bit 114 Ol Chiki */ +#define TT_UCR_OL_CHIKI (1L << 18) /* U+1C50-U+1C7F */ + /* Bit 115 Saurashtra */ +#define TT_UCR_SAURASHTRA (1L << 19) /* U+A880-U+A8DF */ + /* Bit 116 Kayah Li */ +#define TT_UCR_KAYAH_LI (1L << 20) /* U+A900-U+A92F */ + /* Bit 117 Rejang */ +#define TT_UCR_REJANG (1L << 21) /* U+A930-U+A95F */ + /* Bit 118 Cham */ +#define TT_UCR_CHAM (1L << 22) /* U+AA00-U+AA5F */ + /* Bit 119 Ancient Symbols */ +#define TT_UCR_ANCIENT_SYMBOLS (1L << 23) /*U+10190-U+101CF*/ + /* Bit 120 Phaistos Disc */ +#define TT_UCR_PHAISTOS_DISC (1L << 24) /*U+101D0-U+101FF*/ + /* Bit 121 Carian */ + /* Lycian */ + /* Lydian */ +#define TT_UCR_OLD_ANATOLIAN (1L << 25) /*U+102A0-U+102DF*/ + /*U+10280-U+1029F*/ + /*U+10920-U+1093F*/ + /* Bit 122 Domino Tiles */ + /* Mahjong Tiles */ +#define TT_UCR_GAME_TILES (1L << 26) /*U+1F030-U+1F09F*/ + /*U+1F000-U+1F02F*/ + /* Bit 123-127 Reserved for process-internal usage */ + + + /*************************************************************************/ + /* */ + /* Some compilers have a very limited length of identifiers. */ + /* */ +#if defined( __TURBOC__ ) && __TURBOC__ < 0x0410 || defined( __PACIFIC__ ) +#define HAVE_LIMIT_ON_IDENTS +#endif + + +#ifndef HAVE_LIMIT_ON_IDENTS + + + /*************************************************************************/ + /* */ + /* Here some alias #defines in order to be clearer. */ + /* */ + /* These are not always #defined to stay within the 31~character limit */ + /* which some compilers have. */ + /* */ + /* Credits go to Dave Hoo <dhoo@flash.net> for pointing out that modern */ + /* Borland compilers (read: from BC++ 3.1 on) can increase this limit. */ + /* If you get a warning with such a compiler, use the -i40 switch. */ + /* */ +#define TT_UCR_ARABIC_PRESENTATION_FORMS_A \ + TT_UCR_ARABIC_PRESENTATIONS_A +#define TT_UCR_ARABIC_PRESENTATION_FORMS_B \ + TT_UCR_ARABIC_PRESENTATIONS_B + +#define TT_UCR_COMBINING_DIACRITICAL_MARKS \ + TT_UCR_COMBINING_DIACRITICS +#define TT_UCR_COMBINING_DIACRITICAL_MARKS_SYMB \ + TT_UCR_COMBINING_DIACRITICS_SYMB + + +#endif /* !HAVE_LIMIT_ON_IDENTS */ + + +FT_END_HEADER + +#endif /* __TTNAMEID_H__ */ + + +/* END */ diff --git a/Lib/Include/freetype/tttables.h b/Lib/Include/freetype/tttables.h new file mode 100644 index 0000000..4610e50 --- /dev/null +++ b/Lib/Include/freetype/tttables.h @@ -0,0 +1,759 @@ +/***************************************************************************/ +/* */ +/* tttables.h */ +/* */ +/* Basic SFNT/TrueType tables definitions and interface */ +/* (specification only). */ +/* */ +/* Copyright 1996-2001, 2002, 2003, 2004, 2005, 2008, 2009, 2010 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef __TTTABLES_H__ +#define __TTTABLES_H__ + + +#include <ft2build.h> +#include FT_FREETYPE_H + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + /*************************************************************************/ + /* */ + /* <Section> */ + /* truetype_tables */ + /* */ + /* <Title> */ + /* TrueType Tables */ + /* */ + /* <Abstract> */ + /* TrueType specific table types and functions. */ + /* */ + /* <Description> */ + /* This section contains the definition of TrueType-specific tables */ + /* as well as some routines used to access and process them. */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* TT_Header */ + /* */ + /* <Description> */ + /* A structure used to model a TrueType font header table. All */ + /* fields follow the TrueType specification. */ + /* */ + typedef struct TT_Header_ + { + FT_Fixed Table_Version; + FT_Fixed Font_Revision; + + FT_Long CheckSum_Adjust; + FT_Long Magic_Number; + + FT_UShort Flags; + FT_UShort Units_Per_EM; + + FT_Long Created [2]; + FT_Long Modified[2]; + + FT_Short xMin; + FT_Short yMin; + FT_Short xMax; + FT_Short yMax; + + FT_UShort Mac_Style; + FT_UShort Lowest_Rec_PPEM; + + FT_Short Font_Direction; + FT_Short Index_To_Loc_Format; + FT_Short Glyph_Data_Format; + + } TT_Header; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* TT_HoriHeader */ + /* */ + /* <Description> */ + /* A structure used to model a TrueType horizontal header, the `hhea' */ + /* table, as well as the corresponding horizontal metrics table, */ + /* i.e., the `hmtx' table. */ + /* */ + /* <Fields> */ + /* Version :: The table version. */ + /* */ + /* Ascender :: The font's ascender, i.e., the distance */ + /* from the baseline to the top-most of all */ + /* glyph points found in the font. */ + /* */ + /* This value is invalid in many fonts, as */ + /* it is usually set by the font designer, */ + /* and often reflects only a portion of the */ + /* glyphs found in the font (maybe ASCII). */ + /* */ + /* You should use the `sTypoAscender' field */ + /* of the OS/2 table instead if you want */ + /* the correct one. */ + /* */ + /* Descender :: The font's descender, i.e., the distance */ + /* from the baseline to the bottom-most of */ + /* all glyph points found in the font. It */ + /* is negative. */ + /* */ + /* This value is invalid in many fonts, as */ + /* it is usually set by the font designer, */ + /* and often reflects only a portion of the */ + /* glyphs found in the font (maybe ASCII). */ + /* */ + /* You should use the `sTypoDescender' */ + /* field of the OS/2 table instead if you */ + /* want the correct one. */ + /* */ + /* Line_Gap :: The font's line gap, i.e., the distance */ + /* to add to the ascender and descender to */ + /* get the BTB, i.e., the */ + /* baseline-to-baseline distance for the */ + /* font. */ + /* */ + /* advance_Width_Max :: This field is the maximum of all advance */ + /* widths found in the font. It can be */ + /* used to compute the maximum width of an */ + /* arbitrary string of text. */ + /* */ + /* min_Left_Side_Bearing :: The minimum left side bearing of all */ + /* glyphs within the font. */ + /* */ + /* min_Right_Side_Bearing :: The minimum right side bearing of all */ + /* glyphs within the font. */ + /* */ + /* xMax_Extent :: The maximum horizontal extent (i.e., the */ + /* `width' of a glyph's bounding box) for */ + /* all glyphs in the font. */ + /* */ + /* caret_Slope_Rise :: The rise coefficient of the cursor's */ + /* slope of the cursor (slope=rise/run). */ + /* */ + /* caret_Slope_Run :: The run coefficient of the cursor's */ + /* slope. */ + /* */ + /* Reserved :: 8~reserved bytes. */ + /* */ + /* metric_Data_Format :: Always~0. */ + /* */ + /* number_Of_HMetrics :: Number of HMetrics entries in the `hmtx' */ + /* table -- this value can be smaller than */ + /* the total number of glyphs in the font. */ + /* */ + /* long_metrics :: A pointer into the `hmtx' table. */ + /* */ + /* short_metrics :: A pointer into the `hmtx' table. */ + /* */ + /* <Note> */ + /* IMPORTANT: The TT_HoriHeader and TT_VertHeader structures should */ + /* be identical except for the names of their fields which */ + /* are different. */ + /* */ + /* This ensures that a single function in the `ttload' */ + /* module is able to read both the horizontal and vertical */ + /* headers. */ + /* */ + typedef struct TT_HoriHeader_ + { + FT_Fixed Version; + FT_Short Ascender; + FT_Short Descender; + FT_Short Line_Gap; + + FT_UShort advance_Width_Max; /* advance width maximum */ + + FT_Short min_Left_Side_Bearing; /* minimum left-sb */ + FT_Short min_Right_Side_Bearing; /* minimum right-sb */ + FT_Short xMax_Extent; /* xmax extents */ + FT_Short caret_Slope_Rise; + FT_Short caret_Slope_Run; + FT_Short caret_Offset; + + FT_Short Reserved[4]; + + FT_Short metric_Data_Format; + FT_UShort number_Of_HMetrics; + + /* The following fields are not defined by the TrueType specification */ + /* but they are used to connect the metrics header to the relevant */ + /* `HMTX' table. */ + + void* long_metrics; + void* short_metrics; + + } TT_HoriHeader; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* TT_VertHeader */ + /* */ + /* <Description> */ + /* A structure used to model a TrueType vertical header, the `vhea' */ + /* table, as well as the corresponding vertical metrics table, i.e., */ + /* the `vmtx' table. */ + /* */ + /* <Fields> */ + /* Version :: The table version. */ + /* */ + /* Ascender :: The font's ascender, i.e., the distance */ + /* from the baseline to the top-most of */ + /* all glyph points found in the font. */ + /* */ + /* This value is invalid in many fonts, as */ + /* it is usually set by the font designer, */ + /* and often reflects only a portion of */ + /* the glyphs found in the font (maybe */ + /* ASCII). */ + /* */ + /* You should use the `sTypoAscender' */ + /* field of the OS/2 table instead if you */ + /* want the correct one. */ + /* */ + /* Descender :: The font's descender, i.e., the */ + /* distance from the baseline to the */ + /* bottom-most of all glyph points found */ + /* in the font. It is negative. */ + /* */ + /* This value is invalid in many fonts, as */ + /* it is usually set by the font designer, */ + /* and often reflects only a portion of */ + /* the glyphs found in the font (maybe */ + /* ASCII). */ + /* */ + /* You should use the `sTypoDescender' */ + /* field of the OS/2 table instead if you */ + /* want the correct one. */ + /* */ + /* Line_Gap :: The font's line gap, i.e., the distance */ + /* to add to the ascender and descender to */ + /* get the BTB, i.e., the */ + /* baseline-to-baseline distance for the */ + /* font. */ + /* */ + /* advance_Height_Max :: This field is the maximum of all */ + /* advance heights found in the font. It */ + /* can be used to compute the maximum */ + /* height of an arbitrary string of text. */ + /* */ + /* min_Top_Side_Bearing :: The minimum top side bearing of all */ + /* glyphs within the font. */ + /* */ + /* min_Bottom_Side_Bearing :: The minimum bottom side bearing of all */ + /* glyphs within the font. */ + /* */ + /* yMax_Extent :: The maximum vertical extent (i.e., the */ + /* `height' of a glyph's bounding box) for */ + /* all glyphs in the font. */ + /* */ + /* caret_Slope_Rise :: The rise coefficient of the cursor's */ + /* slope of the cursor (slope=rise/run). */ + /* */ + /* caret_Slope_Run :: The run coefficient of the cursor's */ + /* slope. */ + /* */ + /* caret_Offset :: The cursor's offset for slanted fonts. */ + /* This value is `reserved' in vmtx */ + /* version 1.0. */ + /* */ + /* Reserved :: 8~reserved bytes. */ + /* */ + /* metric_Data_Format :: Always~0. */ + /* */ + /* number_Of_HMetrics :: Number of VMetrics entries in the */ + /* `vmtx' table -- this value can be */ + /* smaller than the total number of glyphs */ + /* in the font. */ + /* */ + /* long_metrics :: A pointer into the `vmtx' table. */ + /* */ + /* short_metrics :: A pointer into the `vmtx' table. */ + /* */ + /* <Note> */ + /* IMPORTANT: The TT_HoriHeader and TT_VertHeader structures should */ + /* be identical except for the names of their fields which */ + /* are different. */ + /* */ + /* This ensures that a single function in the `ttload' */ + /* module is able to read both the horizontal and vertical */ + /* headers. */ + /* */ + typedef struct TT_VertHeader_ + { + FT_Fixed Version; + FT_Short Ascender; + FT_Short Descender; + FT_Short Line_Gap; + + FT_UShort advance_Height_Max; /* advance height maximum */ + + FT_Short min_Top_Side_Bearing; /* minimum left-sb or top-sb */ + FT_Short min_Bottom_Side_Bearing; /* minimum right-sb or bottom-sb */ + FT_Short yMax_Extent; /* xmax or ymax extents */ + FT_Short caret_Slope_Rise; + FT_Short caret_Slope_Run; + FT_Short caret_Offset; + + FT_Short Reserved[4]; + + FT_Short metric_Data_Format; + FT_UShort number_Of_VMetrics; + + /* The following fields are not defined by the TrueType specification */ + /* but they're used to connect the metrics header to the relevant */ + /* `HMTX' or `VMTX' table. */ + + void* long_metrics; + void* short_metrics; + + } TT_VertHeader; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* TT_OS2 */ + /* */ + /* <Description> */ + /* A structure used to model a TrueType OS/2 table. This is the long */ + /* table version. All fields comply to the TrueType specification. */ + /* */ + /* Note that we now support old Mac fonts which do not include an */ + /* OS/2 table. In this case, the `version' field is always set to */ + /* 0xFFFF. */ + /* */ + typedef struct TT_OS2_ + { + FT_UShort version; /* 0x0001 - more or 0xFFFF */ + FT_Short xAvgCharWidth; + FT_UShort usWeightClass; + FT_UShort usWidthClass; + FT_Short fsType; + FT_Short ySubscriptXSize; + FT_Short ySubscriptYSize; + FT_Short ySubscriptXOffset; + FT_Short ySubscriptYOffset; + FT_Short ySuperscriptXSize; + FT_Short ySuperscriptYSize; + FT_Short ySuperscriptXOffset; + FT_Short ySuperscriptYOffset; + FT_Short yStrikeoutSize; + FT_Short yStrikeoutPosition; + FT_Short sFamilyClass; + + FT_Byte panose[10]; + + FT_ULong ulUnicodeRange1; /* Bits 0-31 */ + FT_ULong ulUnicodeRange2; /* Bits 32-63 */ + FT_ULong ulUnicodeRange3; /* Bits 64-95 */ + FT_ULong ulUnicodeRange4; /* Bits 96-127 */ + + FT_Char achVendID[4]; + + FT_UShort fsSelection; + FT_UShort usFirstCharIndex; + FT_UShort usLastCharIndex; + FT_Short sTypoAscender; + FT_Short sTypoDescender; + FT_Short sTypoLineGap; + FT_UShort usWinAscent; + FT_UShort usWinDescent; + + /* only version 1 tables: */ + + FT_ULong ulCodePageRange1; /* Bits 0-31 */ + FT_ULong ulCodePageRange2; /* Bits 32-63 */ + + /* only version 2 tables: */ + + FT_Short sxHeight; + FT_Short sCapHeight; + FT_UShort usDefaultChar; + FT_UShort usBreakChar; + FT_UShort usMaxContext; + + } TT_OS2; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* TT_Postscript */ + /* */ + /* <Description> */ + /* A structure used to model a TrueType PostScript table. All fields */ + /* comply to the TrueType specification. This structure does not */ + /* reference the PostScript glyph names, which can be nevertheless */ + /* accessed with the `ttpost' module. */ + /* */ + typedef struct TT_Postscript_ + { + FT_Fixed FormatType; + FT_Fixed italicAngle; + FT_Short underlinePosition; + FT_Short underlineThickness; + FT_ULong isFixedPitch; + FT_ULong minMemType42; + FT_ULong maxMemType42; + FT_ULong minMemType1; + FT_ULong maxMemType1; + + /* Glyph names follow in the file, but we don't */ + /* load them by default. See the ttpost.c file. */ + + } TT_Postscript; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* TT_PCLT */ + /* */ + /* <Description> */ + /* A structure used to model a TrueType PCLT table. All fields */ + /* comply to the TrueType specification. */ + /* */ + typedef struct TT_PCLT_ + { + FT_Fixed Version; + FT_ULong FontNumber; + FT_UShort Pitch; + FT_UShort xHeight; + FT_UShort Style; + FT_UShort TypeFamily; + FT_UShort CapHeight; + FT_UShort SymbolSet; + FT_Char TypeFace[16]; + FT_Char CharacterComplement[8]; + FT_Char FileName[6]; + FT_Char StrokeWeight; + FT_Char WidthType; + FT_Byte SerifStyle; + FT_Byte Reserved; + + } TT_PCLT; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* TT_MaxProfile */ + /* */ + /* <Description> */ + /* The maximum profile is a table containing many max values which */ + /* can be used to pre-allocate arrays. This ensures that no memory */ + /* allocation occurs during a glyph load. */ + /* */ + /* <Fields> */ + /* version :: The version number. */ + /* */ + /* numGlyphs :: The number of glyphs in this TrueType */ + /* font. */ + /* */ + /* maxPoints :: The maximum number of points in a */ + /* non-composite TrueType glyph. See also */ + /* the structure element */ + /* `maxCompositePoints'. */ + /* */ + /* maxContours :: The maximum number of contours in a */ + /* non-composite TrueType glyph. See also */ + /* the structure element */ + /* `maxCompositeContours'. */ + /* */ + /* maxCompositePoints :: The maximum number of points in a */ + /* composite TrueType glyph. See also the */ + /* structure element `maxPoints'. */ + /* */ + /* maxCompositeContours :: The maximum number of contours in a */ + /* composite TrueType glyph. See also the */ + /* structure element `maxContours'. */ + /* */ + /* maxZones :: The maximum number of zones used for */ + /* glyph hinting. */ + /* */ + /* maxTwilightPoints :: The maximum number of points in the */ + /* twilight zone used for glyph hinting. */ + /* */ + /* maxStorage :: The maximum number of elements in the */ + /* storage area used for glyph hinting. */ + /* */ + /* maxFunctionDefs :: The maximum number of function */ + /* definitions in the TrueType bytecode for */ + /* this font. */ + /* */ + /* maxInstructionDefs :: The maximum number of instruction */ + /* definitions in the TrueType bytecode for */ + /* this font. */ + /* */ + /* maxStackElements :: The maximum number of stack elements used */ + /* during bytecode interpretation. */ + /* */ + /* maxSizeOfInstructions :: The maximum number of TrueType opcodes */ + /* used for glyph hinting. */ + /* */ + /* maxComponentElements :: The maximum number of simple (i.e., non- */ + /* composite) glyphs in a composite glyph. */ + /* */ + /* maxComponentDepth :: The maximum nesting depth of composite */ + /* glyphs. */ + /* */ + /* <Note> */ + /* This structure is only used during font loading. */ + /* */ + typedef struct TT_MaxProfile_ + { + FT_Fixed version; + FT_UShort numGlyphs; + FT_UShort maxPoints; + FT_UShort maxContours; + FT_UShort maxCompositePoints; + FT_UShort maxCompositeContours; + FT_UShort maxZones; + FT_UShort maxTwilightPoints; + FT_UShort maxStorage; + FT_UShort maxFunctionDefs; + FT_UShort maxInstructionDefs; + FT_UShort maxStackElements; + FT_UShort maxSizeOfInstructions; + FT_UShort maxComponentElements; + FT_UShort maxComponentDepth; + + } TT_MaxProfile; + + + /*************************************************************************/ + /* */ + /* <Enum> */ + /* FT_Sfnt_Tag */ + /* */ + /* <Description> */ + /* An enumeration used to specify the index of an SFNT table. */ + /* Used in the @FT_Get_Sfnt_Table API function. */ + /* */ + typedef enum FT_Sfnt_Tag_ + { + ft_sfnt_head = 0, /* TT_Header */ + ft_sfnt_maxp = 1, /* TT_MaxProfile */ + ft_sfnt_os2 = 2, /* TT_OS2 */ + ft_sfnt_hhea = 3, /* TT_HoriHeader */ + ft_sfnt_vhea = 4, /* TT_VertHeader */ + ft_sfnt_post = 5, /* TT_Postscript */ + ft_sfnt_pclt = 6, /* TT_PCLT */ + + sfnt_max /* internal end mark */ + + } FT_Sfnt_Tag; + + /* */ + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Get_Sfnt_Table */ + /* */ + /* <Description> */ + /* Return a pointer to a given SFNT table within a face. */ + /* */ + /* <Input> */ + /* face :: A handle to the source. */ + /* */ + /* tag :: The index of the SFNT table. */ + /* */ + /* <Return> */ + /* A type-less pointer to the table. This will be~0 in case of */ + /* error, or if the corresponding table was not found *OR* loaded */ + /* from the file. */ + /* */ + /* Use a typecast according to `tag' to access the structure */ + /* elements. */ + /* */ + /* <Note> */ + /* The table is owned by the face object and disappears with it. */ + /* */ + /* This function is only useful to access SFNT tables that are loaded */ + /* by the sfnt, truetype, and opentype drivers. See @FT_Sfnt_Tag for */ + /* a list. */ + /* */ + FT_EXPORT( void* ) + FT_Get_Sfnt_Table( FT_Face face, + FT_Sfnt_Tag tag ); + + + /************************************************************************** + * + * @function: + * FT_Load_Sfnt_Table + * + * @description: + * Load any font table into client memory. + * + * @input: + * face :: + * A handle to the source face. + * + * tag :: + * The four-byte tag of the table to load. Use the value~0 if you want + * to access the whole font file. Otherwise, you can use one of the + * definitions found in the @FT_TRUETYPE_TAGS_H file, or forge a new + * one with @FT_MAKE_TAG. + * + * offset :: + * The starting offset in the table (or file if tag == 0). + * + * @output: + * buffer :: + * The target buffer address. The client must ensure that the memory + * array is big enough to hold the data. + * + * @inout: + * length :: + * If the `length' parameter is NULL, then try to load the whole table. + * Return an error code if it fails. + * + * Else, if `*length' is~0, exit immediately while returning the + * table's (or file) full size in it. + * + * Else the number of bytes to read from the table or file, from the + * starting offset. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * If you need to determine the table's length you should first call this + * function with `*length' set to~0, as in the following example: + * + * { + * FT_ULong length = 0; + * + * + * error = FT_Load_Sfnt_Table( face, tag, 0, NULL, &length ); + * if ( error ) { ... table does not exist ... } + * + * buffer = malloc( length ); + * if ( buffer == NULL ) { ... not enough memory ... } + * + * error = FT_Load_Sfnt_Table( face, tag, 0, buffer, &length ); + * if ( error ) { ... could not load table ... } + * } + */ + FT_EXPORT( FT_Error ) + FT_Load_Sfnt_Table( FT_Face face, + FT_ULong tag, + FT_Long offset, + FT_Byte* buffer, + FT_ULong* length ); + + + /************************************************************************** + * + * @function: + * FT_Sfnt_Table_Info + * + * @description: + * Return information on an SFNT table. + * + * @input: + * face :: + * A handle to the source face. + * + * table_index :: + * The index of an SFNT table. The function returns + * FT_Err_Table_Missing for an invalid value. + * + * @output: + * tag :: + * The name tag of the SFNT table. + * + * length :: + * The length of the SFNT table. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * SFNT tables with length zero are treated as missing. + * + */ + FT_EXPORT( FT_Error ) + FT_Sfnt_Table_Info( FT_Face face, + FT_UInt table_index, + FT_ULong *tag, + FT_ULong *length ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Get_CMap_Language_ID */ + /* */ + /* <Description> */ + /* Return TrueType/sfnt specific cmap language ID. Definitions of */ + /* language ID values are in `freetype/ttnameid.h'. */ + /* */ + /* <Input> */ + /* charmap :: */ + /* The target charmap. */ + /* */ + /* <Return> */ + /* The language ID of `charmap'. If `charmap' doesn't belong to a */ + /* TrueType/sfnt face, just return~0 as the default value. */ + /* */ + FT_EXPORT( FT_ULong ) + FT_Get_CMap_Language_ID( FT_CharMap charmap ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Get_CMap_Format */ + /* */ + /* <Description> */ + /* Return TrueType/sfnt specific cmap format. */ + /* */ + /* <Input> */ + /* charmap :: */ + /* The target charmap. */ + /* */ + /* <Return> */ + /* The format of `charmap'. If `charmap' doesn't belong to a */ + /* TrueType/sfnt face, return -1. */ + /* */ + FT_EXPORT( FT_Long ) + FT_Get_CMap_Format( FT_CharMap charmap ); + + /* */ + + +FT_END_HEADER + +#endif /* __TTTABLES_H__ */ + + +/* END */ diff --git a/Lib/Include/freetype/tttags.h b/Lib/Include/freetype/tttags.h new file mode 100644 index 0000000..307ce4b --- /dev/null +++ b/Lib/Include/freetype/tttags.h @@ -0,0 +1,107 @@ +/***************************************************************************/ +/* */ +/* tttags.h */ +/* */ +/* Tags for TrueType and OpenType tables (specification only). */ +/* */ +/* Copyright 1996-2001, 2004, 2005, 2007, 2008 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef __TTAGS_H__ +#define __TTAGS_H__ + + +#include <ft2build.h> +#include FT_FREETYPE_H + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + +#define TTAG_avar FT_MAKE_TAG( 'a', 'v', 'a', 'r' ) +#define TTAG_BASE FT_MAKE_TAG( 'B', 'A', 'S', 'E' ) +#define TTAG_bdat FT_MAKE_TAG( 'b', 'd', 'a', 't' ) +#define TTAG_BDF FT_MAKE_TAG( 'B', 'D', 'F', ' ' ) +#define TTAG_bhed FT_MAKE_TAG( 'b', 'h', 'e', 'd' ) +#define TTAG_bloc FT_MAKE_TAG( 'b', 'l', 'o', 'c' ) +#define TTAG_bsln FT_MAKE_TAG( 'b', 's', 'l', 'n' ) +#define TTAG_CFF FT_MAKE_TAG( 'C', 'F', 'F', ' ' ) +#define TTAG_CID FT_MAKE_TAG( 'C', 'I', 'D', ' ' ) +#define TTAG_cmap FT_MAKE_TAG( 'c', 'm', 'a', 'p' ) +#define TTAG_cvar FT_MAKE_TAG( 'c', 'v', 'a', 'r' ) +#define TTAG_cvt FT_MAKE_TAG( 'c', 'v', 't', ' ' ) +#define TTAG_DSIG FT_MAKE_TAG( 'D', 'S', 'I', 'G' ) +#define TTAG_EBDT FT_MAKE_TAG( 'E', 'B', 'D', 'T' ) +#define TTAG_EBLC FT_MAKE_TAG( 'E', 'B', 'L', 'C' ) +#define TTAG_EBSC FT_MAKE_TAG( 'E', 'B', 'S', 'C' ) +#define TTAG_feat FT_MAKE_TAG( 'f', 'e', 'a', 't' ) +#define TTAG_FOND FT_MAKE_TAG( 'F', 'O', 'N', 'D' ) +#define TTAG_fpgm FT_MAKE_TAG( 'f', 'p', 'g', 'm' ) +#define TTAG_fvar FT_MAKE_TAG( 'f', 'v', 'a', 'r' ) +#define TTAG_gasp FT_MAKE_TAG( 'g', 'a', 's', 'p' ) +#define TTAG_GDEF FT_MAKE_TAG( 'G', 'D', 'E', 'F' ) +#define TTAG_glyf FT_MAKE_TAG( 'g', 'l', 'y', 'f' ) +#define TTAG_GPOS FT_MAKE_TAG( 'G', 'P', 'O', 'S' ) +#define TTAG_GSUB FT_MAKE_TAG( 'G', 'S', 'U', 'B' ) +#define TTAG_gvar FT_MAKE_TAG( 'g', 'v', 'a', 'r' ) +#define TTAG_hdmx FT_MAKE_TAG( 'h', 'd', 'm', 'x' ) +#define TTAG_head FT_MAKE_TAG( 'h', 'e', 'a', 'd' ) +#define TTAG_hhea FT_MAKE_TAG( 'h', 'h', 'e', 'a' ) +#define TTAG_hmtx FT_MAKE_TAG( 'h', 'm', 't', 'x' ) +#define TTAG_JSTF FT_MAKE_TAG( 'J', 'S', 'T', 'F' ) +#define TTAG_just FT_MAKE_TAG( 'j', 'u', 's', 't' ) +#define TTAG_kern FT_MAKE_TAG( 'k', 'e', 'r', 'n' ) +#define TTAG_lcar FT_MAKE_TAG( 'l', 'c', 'a', 'r' ) +#define TTAG_loca FT_MAKE_TAG( 'l', 'o', 'c', 'a' ) +#define TTAG_LTSH FT_MAKE_TAG( 'L', 'T', 'S', 'H' ) +#define TTAG_LWFN FT_MAKE_TAG( 'L', 'W', 'F', 'N' ) +#define TTAG_MATH FT_MAKE_TAG( 'M', 'A', 'T', 'H' ) +#define TTAG_maxp FT_MAKE_TAG( 'm', 'a', 'x', 'p' ) +#define TTAG_META FT_MAKE_TAG( 'M', 'E', 'T', 'A' ) +#define TTAG_MMFX FT_MAKE_TAG( 'M', 'M', 'F', 'X' ) +#define TTAG_MMSD FT_MAKE_TAG( 'M', 'M', 'S', 'D' ) +#define TTAG_mort FT_MAKE_TAG( 'm', 'o', 'r', 't' ) +#define TTAG_morx FT_MAKE_TAG( 'm', 'o', 'r', 'x' ) +#define TTAG_name FT_MAKE_TAG( 'n', 'a', 'm', 'e' ) +#define TTAG_opbd FT_MAKE_TAG( 'o', 'p', 'b', 'd' ) +#define TTAG_OS2 FT_MAKE_TAG( 'O', 'S', '/', '2' ) +#define TTAG_OTTO FT_MAKE_TAG( 'O', 'T', 'T', 'O' ) +#define TTAG_PCLT FT_MAKE_TAG( 'P', 'C', 'L', 'T' ) +#define TTAG_POST FT_MAKE_TAG( 'P', 'O', 'S', 'T' ) +#define TTAG_post FT_MAKE_TAG( 'p', 'o', 's', 't' ) +#define TTAG_prep FT_MAKE_TAG( 'p', 'r', 'e', 'p' ) +#define TTAG_prop FT_MAKE_TAG( 'p', 'r', 'o', 'p' ) +#define TTAG_sfnt FT_MAKE_TAG( 's', 'f', 'n', 't' ) +#define TTAG_SING FT_MAKE_TAG( 'S', 'I', 'N', 'G' ) +#define TTAG_trak FT_MAKE_TAG( 't', 'r', 'a', 'k' ) +#define TTAG_true FT_MAKE_TAG( 't', 'r', 'u', 'e' ) +#define TTAG_ttc FT_MAKE_TAG( 't', 't', 'c', ' ' ) +#define TTAG_ttcf FT_MAKE_TAG( 't', 't', 'c', 'f' ) +#define TTAG_TYP1 FT_MAKE_TAG( 'T', 'Y', 'P', '1' ) +#define TTAG_typ1 FT_MAKE_TAG( 't', 'y', 'p', '1' ) +#define TTAG_VDMX FT_MAKE_TAG( 'V', 'D', 'M', 'X' ) +#define TTAG_vhea FT_MAKE_TAG( 'v', 'h', 'e', 'a' ) +#define TTAG_vmtx FT_MAKE_TAG( 'v', 'm', 't', 'x' ) + + +FT_END_HEADER + +#endif /* __TTAGS_H__ */ + + +/* END */ diff --git a/Lib/Include/freetype/ttunpat.h b/Lib/Include/freetype/ttunpat.h new file mode 100644 index 0000000..a016275 --- /dev/null +++ b/Lib/Include/freetype/ttunpat.h @@ -0,0 +1,59 @@ +/***************************************************************************/ +/* */ +/* ttunpat.h */ +/* */ +/* Definitions for the unpatented TrueType hinting system */ +/* */ +/* Copyright 2003, 2006 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* Written by Graham Asher <graham.asher@btinternet.com> */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef __TTUNPAT_H__ +#define __TTUNPAT_H__ + + +#include <ft2build.h> +#include FT_FREETYPE_H + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + + /*************************************************************************** + * + * @constant: + * FT_PARAM_TAG_UNPATENTED_HINTING + * + * @description: + * A constant used as the tag of an @FT_Parameter structure to indicate + * that unpatented methods only should be used by the TrueType bytecode + * interpreter for a typeface opened by @FT_Open_Face. + * + */ +#define FT_PARAM_TAG_UNPATENTED_HINTING FT_MAKE_TAG( 'u', 'n', 'p', 'a' ) + + /* */ + +FT_END_HEADER + + +#endif /* __TTUNPAT_H__ */ + + +/* END */ diff --git a/Lib/Include/ft2build.h b/Lib/Include/ft2build.h new file mode 100644 index 0000000..923d887 --- /dev/null +++ b/Lib/Include/ft2build.h @@ -0,0 +1,39 @@ +/***************************************************************************/ +/* */ +/* ft2build.h */ +/* */ +/* FreeType 2 build and setup macros. */ +/* (Generic version) */ +/* */ +/* Copyright 1996-2001, 2006 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + + /*************************************************************************/ + /* */ + /* This file corresponds to the default `ft2build.h' file for */ + /* FreeType 2. It uses the `freetype' include root. */ + /* */ + /* Note that specific platforms might use a different configuration. */ + /* See builds/unix/ft2unix.h for an example. */ + /* */ + /*************************************************************************/ + + +#ifndef __FT2_BUILD_GENERIC_H__ +#define __FT2_BUILD_GENERIC_H__ + +#include <freetype/config/ftheader.h> + +#endif /* __FT2_BUILD_GENERIC_H__ */ + + +/* END */ diff --git a/Lib/Include/jansson.h b/Lib/Include/jansson.h new file mode 100644 index 0000000..352c6ce --- /dev/null +++ b/Lib/Include/jansson.h @@ -0,0 +1,273 @@ +/* + * Copyright (c) 2009-2012 Petri Lehtinen <petri@digip.org> + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#ifndef JANSSON_H +#define JANSSON_H + +#include <stdio.h> +#include <stdlib.h> /* for size_t */ +#include <stdarg.h> + +#include <jansson_config.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* version */ + +#define JANSSON_MAJOR_VERSION 2 +#define JANSSON_MINOR_VERSION 4 +#define JANSSON_MICRO_VERSION 0 + +/* Micro version is omitted if it's 0 */ +#define JANSSON_VERSION "2.4" + +/* Version as a 3-byte hex number, e.g. 0x010201 == 1.2.1. Use this + for numeric comparisons, e.g. #if JANSSON_VERSION_HEX >= ... */ +#define JANSSON_VERSION_HEX ((JANSSON_MAJOR_VERSION << 16) | \ + (JANSSON_MINOR_VERSION << 8) | \ + (JANSSON_MICRO_VERSION << 0)) + + +/* types */ + +typedef enum { + JSON_OBJECT, + JSON_ARRAY, + JSON_STRING, + JSON_INTEGER, + JSON_REAL, + JSON_TRUE, + JSON_FALSE, + JSON_NULL +} json_type; + +typedef struct { + json_type type; + size_t refcount; +} json_t; + +#if JSON_INTEGER_IS_LONG_LONG +#ifdef _WIN32 +#define JSON_INTEGER_FORMAT "I64d" +#else +#define JSON_INTEGER_FORMAT "lld" +#endif +typedef long long json_int_t; +#else +#define JSON_INTEGER_FORMAT "ld" +typedef long json_int_t; +#endif /* JSON_INTEGER_IS_LONG_LONG */ + +#define json_typeof(json) ((json)->type) +#define json_is_object(json) (json && json_typeof(json) == JSON_OBJECT) +#define json_is_array(json) (json && json_typeof(json) == JSON_ARRAY) +#define json_is_string(json) (json && json_typeof(json) == JSON_STRING) +#define json_is_integer(json) (json && json_typeof(json) == JSON_INTEGER) +#define json_is_real(json) (json && json_typeof(json) == JSON_REAL) +#define json_is_number(json) (json_is_integer(json) || json_is_real(json)) +#define json_is_true(json) (json && json_typeof(json) == JSON_TRUE) +#define json_is_false(json) (json && json_typeof(json) == JSON_FALSE) +#define json_is_boolean(json) (json_is_true(json) || json_is_false(json)) +#define json_is_null(json) (json && json_typeof(json) == JSON_NULL) + +/* construction, destruction, reference counting */ + +json_t *json_object(void); +json_t *json_array(void); +json_t *json_string(const char *value); +json_t *json_string_nocheck(const char *value); +json_t *json_integer(json_int_t value); +json_t *json_real(double value); +json_t *json_true(void); +json_t *json_false(void); +#define json_boolean(val) ((val) ? json_true() : json_false()) +json_t *json_null(void); + +static JSON_INLINE +json_t *json_incref(json_t *json) +{ + if(json && json->refcount != (size_t)-1) + ++json->refcount; + return json; +} + +/* do not call json_delete directly */ +void json_delete(json_t *json); + +static JSON_INLINE +void json_decref(json_t *json) +{ + if(json && json->refcount != (size_t)-1 && --json->refcount == 0) + json_delete(json); +} + + +/* error reporting */ + +#define JSON_ERROR_TEXT_LENGTH 160 +#define JSON_ERROR_SOURCE_LENGTH 80 + +typedef struct { + int line; + int column; + int position; + char source[JSON_ERROR_SOURCE_LENGTH]; + char text[JSON_ERROR_TEXT_LENGTH]; +} json_error_t; + + +/* getters, setters, manipulation */ + +size_t json_object_size(const json_t *object); +json_t *json_object_get(const json_t *object, const char *key); +int json_object_set_new(json_t *object, const char *key, json_t *value); +int json_object_set_new_nocheck(json_t *object, const char *key, json_t *value); +int json_object_del(json_t *object, const char *key); +int json_object_clear(json_t *object); +int json_object_update(json_t *object, json_t *other); +int json_object_update_existing(json_t *object, json_t *other); +int json_object_update_missing(json_t *object, json_t *other); +void *json_object_iter(json_t *object); +void *json_object_iter_at(json_t *object, const char *key); +void *json_object_key_to_iter(const char *key); +void *json_object_iter_next(json_t *object, void *iter); +const char *json_object_iter_key(void *iter); +json_t *json_object_iter_value(void *iter); +int json_object_iter_set_new(json_t *object, void *iter, json_t *value); + +#define json_object_foreach(object, key, value) \ + for(key = json_object_iter_key(json_object_iter(object)); \ + key && (value = json_object_iter_value(json_object_key_to_iter(key))); \ + key = json_object_iter_key(json_object_iter_next(object, json_object_key_to_iter(key)))) + +static JSON_INLINE +int json_object_set(json_t *object, const char *key, json_t *value) +{ + return json_object_set_new(object, key, json_incref(value)); +} + +static JSON_INLINE +int json_object_set_nocheck(json_t *object, const char *key, json_t *value) +{ + return json_object_set_new_nocheck(object, key, json_incref(value)); +} + +static JSON_INLINE +int json_object_iter_set(json_t *object, void *iter, json_t *value) +{ + return json_object_iter_set_new(object, iter, json_incref(value)); +} + +size_t json_array_size(const json_t *array); +json_t *json_array_get(const json_t *array, size_t index); +int json_array_set_new(json_t *array, size_t index, json_t *value); +int json_array_append_new(json_t *array, json_t *value); +int json_array_insert_new(json_t *array, size_t index, json_t *value); +int json_array_remove(json_t *array, size_t index); +int json_array_clear(json_t *array); +int json_array_extend(json_t *array, json_t *other); + +static JSON_INLINE +int json_array_set(json_t *array, size_t index, json_t *value) +{ + return json_array_set_new(array, index, json_incref(value)); +} + +static JSON_INLINE +int json_array_append(json_t *array, json_t *value) +{ + return json_array_append_new(array, json_incref(value)); +} + +static JSON_INLINE +int json_array_insert(json_t *array, size_t index, json_t *value) +{ + return json_array_insert_new(array, index, json_incref(value)); +} + +const char *json_string_value(const json_t *string); +json_int_t json_integer_value(const json_t *integer); +double json_real_value(const json_t *real); +double json_number_value(const json_t *json); + +int json_string_set(json_t *string, const char *value); +int json_string_set_nocheck(json_t *string, const char *value); +int json_integer_set(json_t *integer, json_int_t value); +int json_real_set(json_t *real, double value); + + +/* pack, unpack */ + +json_t *json_pack(const char *fmt, ...); +json_t *json_pack_ex(json_error_t *error, size_t flags, const char *fmt, ...); +json_t *json_vpack_ex(json_error_t *error, size_t flags, const char *fmt, va_list ap); + +#define JSON_VALIDATE_ONLY 0x1 +#define JSON_STRICT 0x2 + +int json_unpack(json_t *root, const char *fmt, ...); +int json_unpack_ex(json_t *root, json_error_t *error, size_t flags, const char *fmt, ...); +int json_vunpack_ex(json_t *root, json_error_t *error, size_t flags, const char *fmt, va_list ap); + + +/* equality */ + +int json_equal(json_t *value1, json_t *value2); + + +/* copying */ + +json_t *json_copy(json_t *value); +json_t *json_deep_copy(json_t *value); + + +/* decoding */ + +#define JSON_REJECT_DUPLICATES 0x1 +#define JSON_DISABLE_EOF_CHECK 0x2 +#define JSON_DECODE_ANY 0x4 + +typedef size_t (*json_load_callback_t)(void *buffer, size_t buflen, void *data); + +json_t *json_loads(const char *input, size_t flags, json_error_t *error); +json_t *json_loadb(const char *buffer, size_t buflen, size_t flags, json_error_t *error); +json_t *json_loadf(FILE *input, size_t flags, json_error_t *error); +json_t *json_load_file(const char *path, size_t flags, json_error_t *error); +json_t *json_load_callback(json_load_callback_t callback, void *data, size_t flags, json_error_t *error); + + +/* encoding */ + +#define JSON_INDENT(n) (n & 0x1F) +#define JSON_COMPACT 0x20 +#define JSON_ENSURE_ASCII 0x40 +#define JSON_SORT_KEYS 0x80 +#define JSON_PRESERVE_ORDER 0x100 +#define JSON_ENCODE_ANY 0x200 +#define JSON_ESCAPE_SLASH 0x400 + +typedef int (*json_dump_callback_t)(const char *buffer, size_t size, void *data); + +char *json_dumps(const json_t *json, size_t flags); +int json_dumpf(const json_t *json, FILE *output, size_t flags); +int json_dump_file(const json_t *json, const char *path, size_t flags); +int json_dump_callback(const json_t *json, json_dump_callback_t callback, void *data, size_t flags); + +/* custom memory allocation */ + +typedef void *(*json_malloc_t)(size_t); +typedef void (*json_free_t)(void *); + +void json_set_alloc_funcs(json_malloc_t malloc_fn, json_free_t free_fn); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Lib/Include/jansson_config.h b/Lib/Include/jansson_config.h new file mode 100644 index 0000000..fc8e5ea --- /dev/null +++ b/Lib/Include/jansson_config.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2010-2012 Petri Lehtinen <petri@digip.org> + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + * + * + * This file specifies a part of the site-specific configuration for + * Jansson, namely those things that affect the public API in + * jansson.h. + * + * The configure script copies this file to jansson_config.h and + * replaces @var@ substitutions by values that fit your system. If you + * cannot run the configure script, you can do the value substitution + * by hand. + */ + +#ifndef JANSSON_CONFIG_H +#define JANSSON_CONFIG_H + +/* If your compiler supports the inline keyword in C, JSON_INLINE is + defined to `inline', otherwise empty. In C++, the inline is always + supported. */ +#ifdef __cplusplus +#define JSON_INLINE inline +#else +#define JSON_INLINE __inline +#endif + +/* If your compiler supports the `long long` type and the strtoll() + library function, JSON_INTEGER_IS_LONG_LONG is defined to 1, + otherwise to 0. */ +#define JSON_INTEGER_IS_LONG_LONG 1 + +/* If locale.h and localeconv() are available, define to 1, + otherwise to 0. */ +#define JSON_HAVE_LOCALECONV 1 + +#endif diff --git a/Lib/Include/lua.h b/Lib/Include/lua.h new file mode 100644 index 0000000..a3a3a70 --- /dev/null +++ b/Lib/Include/lua.h @@ -0,0 +1,439 @@ +/* +** $Id: lua.h,v 1.283 2012/04/20 13:18:26 roberto Exp $ +** Lua - A Scripting Language +** Lua.org, PUC-Rio, Brazil (http://www.lua.org) +** See Copyright Notice at the end of this file +*/ + + +#ifndef lua_h +#define lua_h + +#include <stdarg.h> +#include <stddef.h> + + +#include "luaconf.h" + + +#define LUA_VERSION_MAJOR "5" +#define LUA_VERSION_MINOR "2" +#define LUA_VERSION_NUM 502 +#define LUA_VERSION_RELEASE "1" + +#define LUA_VERSION "Lua " LUA_VERSION_MAJOR "." LUA_VERSION_MINOR +#define LUA_RELEASE LUA_VERSION "." LUA_VERSION_RELEASE +#define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2012 Lua.org, PUC-Rio" +#define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo, W. Celes" + + +/* mark for precompiled code ('<esc>Lua') */ +#define LUA_SIGNATURE "\033Lua" + +/* option for multiple returns in 'lua_pcall' and 'lua_call' */ +#define LUA_MULTRET (-1) + + +/* +** pseudo-indices +*/ +#define LUA_REGISTRYINDEX LUAI_FIRSTPSEUDOIDX +#define lua_upvalueindex(i) (LUA_REGISTRYINDEX - (i)) + + +/* thread status */ +#define LUA_OK 0 +#define LUA_YIELD 1 +#define LUA_ERRRUN 2 +#define LUA_ERRSYNTAX 3 +#define LUA_ERRMEM 4 +#define LUA_ERRGCMM 5 +#define LUA_ERRERR 6 + + +typedef struct lua_State lua_State; + +typedef int (*lua_CFunction) (lua_State *L); + + +/* +** functions that read/write blocks when loading/dumping Lua chunks +*/ +typedef const char * (*lua_Reader) (lua_State *L, void *ud, size_t *sz); + +typedef int (*lua_Writer) (lua_State *L, const void* p, size_t sz, void* ud); + + +/* +** prototype for memory-allocation functions +*/ +typedef void * (*lua_Alloc) (void *ud, void *ptr, size_t osize, size_t nsize); + + +/* +** basic types +*/ +#define LUA_TNONE (-1) + +#define LUA_TNIL 0 +#define LUA_TBOOLEAN 1 +#define LUA_TLIGHTUSERDATA 2 +#define LUA_TNUMBER 3 +#define LUA_TSTRING 4 +#define LUA_TTABLE 5 +#define LUA_TFUNCTION 6 +#define LUA_TUSERDATA 7 +#define LUA_TTHREAD 8 + +#define LUA_NUMTAGS 9 + + + +/* minimum Lua stack available to a C function */ +#define LUA_MINSTACK 20 + + +/* predefined values in the registry */ +#define LUA_RIDX_MAINTHREAD 1 +#define LUA_RIDX_GLOBALS 2 +#define LUA_RIDX_LAST LUA_RIDX_GLOBALS + + +/* type of numbers in Lua */ +typedef LUA_NUMBER lua_Number; + + +/* type for integer functions */ +typedef LUA_INTEGER lua_Integer; + +/* unsigned integer type */ +typedef LUA_UNSIGNED lua_Unsigned; + + + +/* +** generic extra include file +*/ +#if defined(LUA_USER_H) +#include LUA_USER_H +#endif + + + +/* +** state manipulation +*/ +LUA_API lua_State *(lua_newstate) (lua_Alloc f, void *ud); +LUA_API void (lua_close) (lua_State *L); +LUA_API lua_State *(lua_newthread) (lua_State *L); + +LUA_API lua_CFunction (lua_atpanic) (lua_State *L, lua_CFunction panicf); + + +LUA_API const lua_Number *(lua_version) (lua_State *L); + + +/* +** basic stack manipulation +*/ +LUA_API int (lua_absindex) (lua_State *L, int idx); +LUA_API int (lua_gettop) (lua_State *L); +LUA_API void (lua_settop) (lua_State *L, int idx); +LUA_API void (lua_pushvalue) (lua_State *L, int idx); +LUA_API void (lua_remove) (lua_State *L, int idx); +LUA_API void (lua_insert) (lua_State *L, int idx); +LUA_API void (lua_replace) (lua_State *L, int idx); +LUA_API void (lua_copy) (lua_State *L, int fromidx, int toidx); +LUA_API int (lua_checkstack) (lua_State *L, int sz); + +LUA_API void (lua_xmove) (lua_State *from, lua_State *to, int n); + + +/* +** access functions (stack -> C) +*/ + +LUA_API int (lua_isnumber) (lua_State *L, int idx); +LUA_API int (lua_isstring) (lua_State *L, int idx); +LUA_API int (lua_iscfunction) (lua_State *L, int idx); +LUA_API int (lua_isuserdata) (lua_State *L, int idx); +LUA_API int (lua_type) (lua_State *L, int idx); +LUA_API const char *(lua_typename) (lua_State *L, int tp); + +LUA_API lua_Number (lua_tonumberx) (lua_State *L, int idx, int *isnum); +LUA_API lua_Integer (lua_tointegerx) (lua_State *L, int idx, int *isnum); +LUA_API lua_Unsigned (lua_tounsignedx) (lua_State *L, int idx, int *isnum); +LUA_API int (lua_toboolean) (lua_State *L, int idx); +LUA_API const char *(lua_tolstring) (lua_State *L, int idx, size_t *len); +LUA_API size_t (lua_rawlen) (lua_State *L, int idx); +LUA_API lua_CFunction (lua_tocfunction) (lua_State *L, int idx); +LUA_API void *(lua_touserdata) (lua_State *L, int idx); +LUA_API lua_State *(lua_tothread) (lua_State *L, int idx); +LUA_API const void *(lua_topointer) (lua_State *L, int idx); + + +/* +** Comparison and arithmetic functions +*/ + +#define LUA_OPADD 0 /* ORDER TM */ +#define LUA_OPSUB 1 +#define LUA_OPMUL 2 +#define LUA_OPDIV 3 +#define LUA_OPMOD 4 +#define LUA_OPPOW 5 +#define LUA_OPUNM 6 + +LUA_API void (lua_arith) (lua_State *L, int op); + +#define LUA_OPEQ 0 +#define LUA_OPLT 1 +#define LUA_OPLE 2 + +LUA_API int (lua_rawequal) (lua_State *L, int idx1, int idx2); +LUA_API int (lua_compare) (lua_State *L, int idx1, int idx2, int op); + + +/* +** push functions (C -> stack) +*/ +LUA_API void (lua_pushnil) (lua_State *L); +LUA_API void (lua_pushnumber) (lua_State *L, lua_Number n); +LUA_API void (lua_pushinteger) (lua_State *L, lua_Integer n); +LUA_API void (lua_pushunsigned) (lua_State *L, lua_Unsigned n); +LUA_API const char *(lua_pushlstring) (lua_State *L, const char *s, size_t l); +LUA_API const char *(lua_pushstring) (lua_State *L, const char *s); +LUA_API const char *(lua_pushvfstring) (lua_State *L, const char *fmt, + va_list argp); +LUA_API const char *(lua_pushfstring) (lua_State *L, const char *fmt, ...); +LUA_API void (lua_pushcclosure) (lua_State *L, lua_CFunction fn, int n); +LUA_API void (lua_pushboolean) (lua_State *L, int b); +LUA_API void (lua_pushlightuserdata) (lua_State *L, void *p); +LUA_API int (lua_pushthread) (lua_State *L); + + +/* +** get functions (Lua -> stack) +*/ +LUA_API void (lua_getglobal) (lua_State *L, const char *var); +LUA_API void (lua_gettable) (lua_State *L, int idx); +LUA_API void (lua_getfield) (lua_State *L, int idx, const char *k); +LUA_API void (lua_rawget) (lua_State *L, int idx); +LUA_API void (lua_rawgeti) (lua_State *L, int idx, int n); +LUA_API void (lua_rawgetp) (lua_State *L, int idx, const void *p); +LUA_API void (lua_createtable) (lua_State *L, int narr, int nrec); +LUA_API void *(lua_newuserdata) (lua_State *L, size_t sz); +LUA_API int (lua_getmetatable) (lua_State *L, int objindex); +LUA_API void (lua_getuservalue) (lua_State *L, int idx); + + +/* +** set functions (stack -> Lua) +*/ +LUA_API void (lua_setglobal) (lua_State *L, const char *var); +LUA_API void (lua_settable) (lua_State *L, int idx); +LUA_API void (lua_setfield) (lua_State *L, int idx, const char *k); +LUA_API void (lua_rawset) (lua_State *L, int idx); +LUA_API void (lua_rawseti) (lua_State *L, int idx, int n); +LUA_API void (lua_rawsetp) (lua_State *L, int idx, const void *p); +LUA_API int (lua_setmetatable) (lua_State *L, int objindex); +LUA_API void (lua_setuservalue) (lua_State *L, int idx); + + +/* +** 'load' and 'call' functions (load and run Lua code) +*/ +LUA_API void (lua_callk) (lua_State *L, int nargs, int nresults, int ctx, + lua_CFunction k); +#define lua_call(L,n,r) lua_callk(L, (n), (r), 0, NULL) + +LUA_API int (lua_getctx) (lua_State *L, int *ctx); + +LUA_API int (lua_pcallk) (lua_State *L, int nargs, int nresults, int errfunc, + int ctx, lua_CFunction k); +#define lua_pcall(L,n,r,f) lua_pcallk(L, (n), (r), (f), 0, NULL) + +LUA_API int (lua_load) (lua_State *L, lua_Reader reader, void *dt, + const char *chunkname, + const char *mode); + +LUA_API int (lua_dump) (lua_State *L, lua_Writer writer, void *data); + + +/* +** coroutine functions +*/ +LUA_API int (lua_yieldk) (lua_State *L, int nresults, int ctx, + lua_CFunction k); +#define lua_yield(L,n) lua_yieldk(L, (n), 0, NULL) +LUA_API int (lua_resume) (lua_State *L, lua_State *from, int narg); +LUA_API int (lua_status) (lua_State *L); + +/* +** garbage-collection function and options +*/ + +#define LUA_GCSTOP 0 +#define LUA_GCRESTART 1 +#define LUA_GCCOLLECT 2 +#define LUA_GCCOUNT 3 +#define LUA_GCCOUNTB 4 +#define LUA_GCSTEP 5 +#define LUA_GCSETPAUSE 6 +#define LUA_GCSETSTEPMUL 7 +#define LUA_GCSETMAJORINC 8 +#define LUA_GCISRUNNING 9 +#define LUA_GCGEN 10 +#define LUA_GCINC 11 + +LUA_API int (lua_gc) (lua_State *L, int what, int data); + + +/* +** miscellaneous functions +*/ + +LUA_API int (lua_error) (lua_State *L); + +LUA_API int (lua_next) (lua_State *L, int idx); + +LUA_API void (lua_concat) (lua_State *L, int n); +LUA_API void (lua_len) (lua_State *L, int idx); + +LUA_API lua_Alloc (lua_getallocf) (lua_State *L, void **ud); +LUA_API void (lua_setallocf) (lua_State *L, lua_Alloc f, void *ud); + + + +/* +** =============================================================== +** some useful macros +** =============================================================== +*/ + +#define lua_tonumber(L,i) lua_tonumberx(L,i,NULL) +#define lua_tointeger(L,i) lua_tointegerx(L,i,NULL) +#define lua_tounsigned(L,i) lua_tounsignedx(L,i,NULL) + +#define lua_pop(L,n) lua_settop(L, -(n)-1) + +#define lua_newtable(L) lua_createtable(L, 0, 0) + +#define lua_register(L,n,f) (lua_pushcfunction(L, (f)), lua_setglobal(L, (n))) + +#define lua_pushcfunction(L,f) lua_pushcclosure(L, (f), 0) + +#define lua_isfunction(L,n) (lua_type(L, (n)) == LUA_TFUNCTION) +#define lua_istable(L,n) (lua_type(L, (n)) == LUA_TTABLE) +#define lua_islightuserdata(L,n) (lua_type(L, (n)) == LUA_TLIGHTUSERDATA) +#define lua_isnil(L,n) (lua_type(L, (n)) == LUA_TNIL) +#define lua_isboolean(L,n) (lua_type(L, (n)) == LUA_TBOOLEAN) +#define lua_isthread(L,n) (lua_type(L, (n)) == LUA_TTHREAD) +#define lua_isnone(L,n) (lua_type(L, (n)) == LUA_TNONE) +#define lua_isnoneornil(L, n) (lua_type(L, (n)) <= 0) + +#define lua_pushliteral(L, s) \ + lua_pushlstring(L, "" s, (sizeof(s)/sizeof(char))-1) + +#define lua_pushglobaltable(L) \ + lua_rawgeti(L, LUA_REGISTRYINDEX, LUA_RIDX_GLOBALS) + +#define lua_tostring(L,i) lua_tolstring(L, (i), NULL) + + + +/* +** {====================================================================== +** Debug API +** ======================================================================= +*/ + + +/* +** Event codes +*/ +#define LUA_HOOKCALL 0 +#define LUA_HOOKRET 1 +#define LUA_HOOKLINE 2 +#define LUA_HOOKCOUNT 3 +#define LUA_HOOKTAILCALL 4 + + +/* +** Event masks +*/ +#define LUA_MASKCALL (1 << LUA_HOOKCALL) +#define LUA_MASKRET (1 << LUA_HOOKRET) +#define LUA_MASKLINE (1 << LUA_HOOKLINE) +#define LUA_MASKCOUNT (1 << LUA_HOOKCOUNT) + +typedef struct lua_Debug lua_Debug; /* activation record */ + + +/* Functions to be called by the debugger in specific events */ +typedef void (*lua_Hook) (lua_State *L, lua_Debug *ar); + + +LUA_API int (lua_getstack) (lua_State *L, int level, lua_Debug *ar); +LUA_API int (lua_getinfo) (lua_State *L, const char *what, lua_Debug *ar); +LUA_API const char *(lua_getlocal) (lua_State *L, const lua_Debug *ar, int n); +LUA_API const char *(lua_setlocal) (lua_State *L, const lua_Debug *ar, int n); +LUA_API const char *(lua_getupvalue) (lua_State *L, int funcindex, int n); +LUA_API const char *(lua_setupvalue) (lua_State *L, int funcindex, int n); + +LUA_API void *(lua_upvalueid) (lua_State *L, int fidx, int n); +LUA_API void (lua_upvaluejoin) (lua_State *L, int fidx1, int n1, + int fidx2, int n2); + +LUA_API int (lua_sethook) (lua_State *L, lua_Hook func, int mask, int count); +LUA_API lua_Hook (lua_gethook) (lua_State *L); +LUA_API int (lua_gethookmask) (lua_State *L); +LUA_API int (lua_gethookcount) (lua_State *L); + + +struct lua_Debug { + int event; + const char *name; /* (n) */ + const char *namewhat; /* (n) 'global', 'local', 'field', 'method' */ + const char *what; /* (S) 'Lua', 'C', 'main', 'tail' */ + const char *source; /* (S) */ + int currentline; /* (l) */ + int linedefined; /* (S) */ + int lastlinedefined; /* (S) */ + unsigned char nups; /* (u) number of upvalues */ + unsigned char nparams;/* (u) number of parameters */ + char isvararg; /* (u) */ + char istailcall; /* (t) */ + char short_src[LUA_IDSIZE]; /* (S) */ + /* private part */ + struct CallInfo *i_ci; /* active function */ +}; + +/* }====================================================================== */ + + +/****************************************************************************** +* Copyright (C) 1994-2012 Lua.org, PUC-Rio. +* +* 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 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 +* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +******************************************************************************/ + + +#endif diff --git a/Lib/Include/lua.hpp b/Lib/Include/lua.hpp new file mode 100644 index 0000000..2326f1c --- /dev/null +++ b/Lib/Include/lua.hpp @@ -0,0 +1,8 @@ +// lua.hpp +// Lua header files for C++ +// <<extern "C">> not supplied automatically because Lua also compiles as C++ + +extern "C" { +#include "lua.h" +#include "lualib.h" +} diff --git a/Lib/Include/luaconf.h b/Lib/Include/luaconf.h new file mode 100644 index 0000000..c5a1b2d --- /dev/null +++ b/Lib/Include/luaconf.h @@ -0,0 +1,547 @@ +/* +** $Id: luaconf.h,v 1.172 2012/05/11 14:14:42 roberto Exp $ +** Configuration file for Lua +** See Copyright Notice in lua.h +*/ + + +#ifndef lconfig_h +#define lconfig_h + +#include <limits.h> +#include <stddef.h> + + +/* +** ================================================================== +** Search for "@@" to find all configurable definitions. +** =================================================================== +*/ + +#define LUA_BUILD_AS_DLL 1 + +/* +@@ LUA_ANSI controls the use of non-ansi features. +** CHANGE it (define it) if you want Lua to avoid the use of any +** non-ansi feature or library. +*/ +#if !defined(LUA_ANSI) && defined(__STRICT_ANSI__) +#define LUA_ANSI +#endif + + +#if !defined(LUA_ANSI) && defined(_WIN32) && !defined(_WIN32_WCE) +#define LUA_WIN /* enable goodies for regular Windows platforms */ +#endif + +#if defined(LUA_WIN) +#define LUA_DL_DLL +#define LUA_USE_AFORMAT /* assume 'printf' handles 'aA' specifiers */ +#endif + + + +#if defined(LUA_USE_LINUX) +#define LUA_USE_POSIX +#define LUA_USE_DLOPEN /* needs an extra library: -ldl */ +#define LUA_USE_READLINE /* needs some extra libraries */ +#define LUA_USE_STRTODHEX /* assume 'strtod' handles hexa formats */ +#define LUA_USE_AFORMAT /* assume 'printf' handles 'aA' specifiers */ +#define LUA_USE_LONGLONG /* assume support for long long */ +#endif + +#if defined(LUA_USE_MACOSX) +#define LUA_USE_POSIX +#define LUA_USE_DLOPEN /* does not need -ldl */ +#define LUA_USE_READLINE /* needs an extra library: -lreadline */ +#define LUA_USE_STRTODHEX /* assume 'strtod' handles hexa formats */ +#define LUA_USE_AFORMAT /* assume 'printf' handles 'aA' specifiers */ +#define LUA_USE_LONGLONG /* assume support for long long */ +#endif + + + +/* +@@ LUA_USE_POSIX includes all functionality listed as X/Open System +@* Interfaces Extension (XSI). +** CHANGE it (define it) if your system is XSI compatible. +*/ +#if defined(LUA_USE_POSIX) +#define LUA_USE_MKSTEMP +#define LUA_USE_ISATTY +#define LUA_USE_POPEN +#define LUA_USE_ULONGJMP +#define LUA_USE_GMTIME_R +#endif + + + +/* +@@ LUA_PATH_DEFAULT is the default path that Lua uses to look for +@* Lua libraries. +@@ LUA_CPATH_DEFAULT is the default path that Lua uses to look for +@* C libraries. +** CHANGE them if your machine has a non-conventional directory +** hierarchy or if you want to install your libraries in +** non-conventional directories. +*/ +#if defined(_WIN32) /* { */ +/* +** In Windows, any exclamation mark ('!') in the path is replaced by the +** path of the directory of the executable file of the current process. +*/ +#define LUA_LDIR "!\\lua\\" +#define LUA_CDIR "!\\" +#define LUA_PATH_DEFAULT \ + LUA_LDIR"?.lua;" LUA_LDIR"?\\init.lua;" \ + LUA_CDIR"?.lua;" LUA_CDIR"?\\init.lua;" ".\\?.lua" +#define LUA_CPATH_DEFAULT \ + LUA_CDIR"?.dll;" LUA_CDIR"loadall.dll;" ".\\?.dll" + +#else /* }{ */ + +#define LUA_VDIR LUA_VERSION_MAJOR "." LUA_VERSION_MINOR "/" +#define LUA_ROOT "/usr/local/" +#define LUA_LDIR LUA_ROOT "share/lua/" LUA_VDIR +#define LUA_CDIR LUA_ROOT "lib/lua/" LUA_VDIR +#define LUA_PATH_DEFAULT \ + LUA_LDIR"?.lua;" LUA_LDIR"?/init.lua;" \ + LUA_CDIR"?.lua;" LUA_CDIR"?/init.lua;" "./?.lua" +#define LUA_CPATH_DEFAULT \ + LUA_CDIR"?.so;" LUA_CDIR"loadall.so;" "./?.so" +#endif /* } */ + + +/* +@@ LUA_DIRSEP is the directory separator (for submodules). +** CHANGE it if your machine does not use "/" as the directory separator +** and is not Windows. (On Windows Lua automatically uses "\".) +*/ +#if defined(_WIN32) +#define LUA_DIRSEP "\\" +#else +#define LUA_DIRSEP "/" +#endif + + +/* +@@ LUA_ENV is the name of the variable that holds the current +@@ environment, used to access global names. +** CHANGE it if you do not like this name. +*/ +#define LUA_ENV "_ENV" + + +/* +@@ LUA_API is a mark for all core API functions. +@@ LUALIB_API is a mark for all auxiliary library functions. +@@ LUAMOD_API is a mark for all standard library opening functions. +** CHANGE them if you need to define those functions in some special way. +** For instance, if you want to create one Windows DLL with the core and +** the libraries, you may want to use the following definition (define +** LUA_BUILD_AS_DLL to get it). +*/ +#if defined(LUA_BUILD_AS_DLL) && defined(_WIN32) /* { */ + +#if defined(LUA_CORE) || defined(LUA_LIB) /* { */ +#define LUA_API __declspec(dllexport) +#else /* }{ */ +#define LUA_API __declspec(dllimport) +#endif /* } */ + +#else /* }{ */ + +#define LUA_API extern + +#endif /* } */ + + +/* more often than not the libs go together with the core */ +#define LUALIB_API LUA_API +#define LUAMOD_API LUALIB_API + + +/* +@@ LUAI_FUNC is a mark for all extern functions that are not to be +@* exported to outside modules. +@@ LUAI_DDEF and LUAI_DDEC are marks for all extern (const) variables +@* that are not to be exported to outside modules (LUAI_DDEF for +@* definitions and LUAI_DDEC for declarations). +** CHANGE them if you need to mark them in some special way. Elf/gcc +** (versions 3.2 and later) mark them as "hidden" to optimize access +** when Lua is compiled as a shared library. Not all elf targets support +** this attribute. Unfortunately, gcc does not offer a way to check +** whether the target offers that support, and those without support +** give a warning about it. To avoid these warnings, change to the +** default definition. +*/ +#if defined(__GNUC__) && ((__GNUC__*100 + __GNUC_MINOR__) >= 302) && \ + defined(__ELF__) /* { */ +#define LUAI_FUNC __attribute__((visibility("hidden"))) extern +#define LUAI_DDEC LUAI_FUNC +#define LUAI_DDEF /* empty */ + +#else /* }{ */ +#define LUAI_FUNC extern +#define LUAI_DDEC extern +#define LUAI_DDEF /* empty */ +#endif /* } */ + + + +/* +@@ LUA_QL describes how error messages quote program elements. +** CHANGE it if you want a different appearance. +*/ +#define LUA_QL(x) "'" x "'" +#define LUA_QS LUA_QL("%s") + + +/* +@@ LUA_IDSIZE gives the maximum size for the description of the source +@* of a function in debug information. +** CHANGE it if you want a different size. +*/ +#define LUA_IDSIZE 60 + + +/* +@@ luai_writestring/luai_writeline define how 'print' prints its results. +** They are only used in libraries and the stand-alone program. (The #if +** avoids including 'stdio.h' everywhere.) +*/ +#if defined(LUA_LIB) || defined(lua_c) +#include <stdio.h> +#define luai_writestring(s,l) fwrite((s), sizeof(char), (l), stdout) +#define luai_writeline() (luai_writestring("\n", 1), fflush(stdout)) +#endif + +/* +@@ luai_writestringerror defines how to print error messages. +** (A format string with one argument is enough for Lua...) +*/ +#define luai_writestringerror(s,p) \ + (fprintf(stderr, (s), (p)), fflush(stderr)) + + +/* +@@ LUAI_MAXSHORTLEN is the maximum length for short strings, that is, +** strings that are internalized. (Cannot be smaller than reserved words +** or tags for metamethods, as these strings must be internalized; +** #("function") = 8, #("__newindex") = 10.) +*/ +#define LUAI_MAXSHORTLEN 40 + + + +/* +** {================================================================== +** Compatibility with previous versions +** =================================================================== +*/ + +/* +@@ LUA_COMPAT_ALL controls all compatibility options. +** You can define it to get all options, or change specific options +** to fit your specific needs. +*/ +#if defined(LUA_COMPAT_ALL) /* { */ + +/* +@@ LUA_COMPAT_UNPACK controls the presence of global 'unpack'. +** You can replace it with 'table.unpack'. +*/ +#define LUA_COMPAT_UNPACK + +/* +@@ LUA_COMPAT_LOADERS controls the presence of table 'package.loaders'. +** You can replace it with 'package.searchers'. +*/ +#define LUA_COMPAT_LOADERS + +/* +@@ macro 'lua_cpcall' emulates deprecated function lua_cpcall. +** You can call your C function directly (with light C functions). +*/ +#define lua_cpcall(L,f,u) \ + (lua_pushcfunction(L, (f)), \ + lua_pushlightuserdata(L,(u)), \ + lua_pcall(L,1,0,0)) + + +/* +@@ LUA_COMPAT_LOG10 defines the function 'log10' in the math library. +** You can rewrite 'log10(x)' as 'log(x, 10)'. +*/ +#define LUA_COMPAT_LOG10 + +/* +@@ LUA_COMPAT_LOADSTRING defines the function 'loadstring' in the base +** library. You can rewrite 'loadstring(s)' as 'load(s)'. +*/ +#define LUA_COMPAT_LOADSTRING + +/* +@@ LUA_COMPAT_MAXN defines the function 'maxn' in the table library. +*/ +#define LUA_COMPAT_MAXN + +/* +@@ The following macros supply trivial compatibility for some +** changes in the API. The macros themselves document how to +** change your code to avoid using them. +*/ +#define lua_strlen(L,i) lua_rawlen(L, (i)) + +#define lua_objlen(L,i) lua_rawlen(L, (i)) + +#define lua_equal(L,idx1,idx2) lua_compare(L,(idx1),(idx2),LUA_OPEQ) +#define lua_lessthan(L,idx1,idx2) lua_compare(L,(idx1),(idx2),LUA_OPLT) + +/* +@@ LUA_COMPAT_MODULE controls compatibility with previous +** module functions 'module' (Lua) and 'luaL_register' (C). +*/ +#define LUA_COMPAT_MODULE + +#endif /* } */ + +/* }================================================================== */ + + + +/* +@@ LUAI_BITSINT defines the number of bits in an int. +** CHANGE here if Lua cannot automatically detect the number of bits of +** your machine. Probably you do not need to change this. +*/ +/* avoid overflows in comparison */ +#if INT_MAX-20 < 32760 /* { */ +#define LUAI_BITSINT 16 +#elif INT_MAX > 2147483640L /* }{ */ +/* int has at least 32 bits */ +#define LUAI_BITSINT 32 +#else /* }{ */ +#error "you must define LUA_BITSINT with number of bits in an integer" +#endif /* } */ + + +/* +@@ LUA_INT32 is an signed integer with exactly 32 bits. +@@ LUAI_UMEM is an unsigned integer big enough to count the total +@* memory used by Lua. +@@ LUAI_MEM is a signed integer big enough to count the total memory +@* used by Lua. +** CHANGE here if for some weird reason the default definitions are not +** good enough for your machine. Probably you do not need to change +** this. +*/ +#if LUAI_BITSINT >= 32 /* { */ +#define LUA_INT32 int +#define LUAI_UMEM size_t +#define LUAI_MEM ptrdiff_t +#else /* }{ */ +/* 16-bit ints */ +#define LUA_INT32 long +#define LUAI_UMEM unsigned long +#define LUAI_MEM long +#endif /* } */ + + +/* +@@ LUAI_MAXSTACK limits the size of the Lua stack. +** CHANGE it if you need a different limit. This limit is arbitrary; +** its only purpose is to stop Lua to consume unlimited stack +** space (and to reserve some numbers for pseudo-indices). +*/ +#if LUAI_BITSINT >= 32 +#define LUAI_MAXSTACK 1000000 +#else +#define LUAI_MAXSTACK 15000 +#endif + +/* reserve some space for error handling */ +#define LUAI_FIRSTPSEUDOIDX (-LUAI_MAXSTACK - 1000) + + + + +/* +@@ LUAL_BUFFERSIZE is the buffer size used by the lauxlib buffer system. +** CHANGE it if it uses too much C-stack space. +*/ +#define LUAL_BUFFERSIZE BUFSIZ + + + + +/* +** {================================================================== +@@ LUA_NUMBER is the type of numbers in Lua. +** CHANGE the following definitions only if you want to build Lua +** with a number type different from double. You may also need to +** change lua_number2int & lua_number2integer. +** =================================================================== +*/ + +#define LUA_NUMBER_DOUBLE +#define LUA_NUMBER double + +/* +@@ LUAI_UACNUMBER is the result of an 'usual argument conversion' +@* over a number. +*/ +#define LUAI_UACNUMBER double + + +/* +@@ LUA_NUMBER_SCAN is the format for reading numbers. +@@ LUA_NUMBER_FMT is the format for writing numbers. +@@ lua_number2str converts a number to a string. +@@ LUAI_MAXNUMBER2STR is maximum size of previous conversion. +*/ +#define LUA_NUMBER_SCAN "%lf" +#define LUA_NUMBER_FMT "%.14g" +#define lua_number2str(s,n) sprintf((s), LUA_NUMBER_FMT, (n)) +#define LUAI_MAXNUMBER2STR 32 /* 16 digits, sign, point, and \0 */ + + +/* +@@ lua_str2number converts a decimal numeric string to a number. +@@ lua_strx2number converts an hexadecimal numeric string to a number. +** In C99, 'strtod' do both conversions. C89, however, has no function +** to convert floating hexadecimal strings to numbers. For these +** systems, you can leave 'lua_strx2number' undefined and Lua will +** provide its own implementation. +*/ +#define lua_str2number(s,p) strtod((s), (p)) + +#if defined(LUA_USE_STRTODHEX) +#define lua_strx2number(s,p) strtod((s), (p)) +#endif + + +/* +@@ The luai_num* macros define the primitive operations over numbers. +*/ + +/* the following operations need the math library */ +#if defined(lobject_c) || defined(lvm_c) +#include <math.h> +#define luai_nummod(L,a,b) ((a) - floor((a)/(b))*(b)) +#define luai_numpow(L,a,b) (pow(a,b)) +#endif + +/* these are quite standard operations */ +#if defined(LUA_CORE) +#define luai_numadd(L,a,b) ((a)+(b)) +#define luai_numsub(L,a,b) ((a)-(b)) +#define luai_nummul(L,a,b) ((a)*(b)) +#define luai_numdiv(L,a,b) ((a)/(b)) +#define luai_numunm(L,a) (-(a)) +#define luai_numeq(a,b) ((a)==(b)) +#define luai_numlt(L,a,b) ((a)<(b)) +#define luai_numle(L,a,b) ((a)<=(b)) +#define luai_numisnan(L,a) (!luai_numeq((a), (a))) +#endif + + + +/* +@@ LUA_INTEGER is the integral type used by lua_pushinteger/lua_tointeger. +** CHANGE that if ptrdiff_t is not adequate on your machine. (On most +** machines, ptrdiff_t gives a good choice between int or long.) +*/ +#define LUA_INTEGER ptrdiff_t + +/* +@@ LUA_UNSIGNED is the integral type used by lua_pushunsigned/lua_tounsigned. +** It must have at least 32 bits. +*/ +#define LUA_UNSIGNED unsigned LUA_INT32 + + + +/* +** Some tricks with doubles +*/ + +#if defined(LUA_CORE) && \ + defined(LUA_NUMBER_DOUBLE) && !defined(LUA_ANSI) /* { */ +/* +** The next definitions activate some tricks to speed up the +** conversion from doubles to integer types, mainly to LUA_UNSIGNED. +** +@@ MS_ASMTRICK uses Microsoft assembler to avoid clashes with a +** DirectX idiosyncrasy. +** +@@ LUA_IEEE754TRICK uses a trick that should work on any machine +** using IEEE754 with a 32-bit integer type. +** +@@ LUA_IEEELL extends the trick to LUA_INTEGER; should only be +** defined when LUA_INTEGER is a 32-bit integer. +** +@@ LUA_IEEEENDIAN is the endianness of doubles in your machine +** (0 for little endian, 1 for big endian); if not defined, Lua will +** check it dynamically for LUA_IEEE754TRICK (but not for LUA_NANTRICK). +** +@@ LUA_NANTRICK controls the use of a trick to pack all types into +** a single double value, using NaN values to represent non-number +** values. The trick only works on 32-bit machines (ints and pointers +** are 32-bit values) with numbers represented as IEEE 754-2008 doubles +** with conventional endianess (12345678 or 87654321), in CPUs that do +** not produce signaling NaN values (all NaNs are quiet). +*/ + +/* Microsoft compiler on a Pentium (32 bit) ? */ +#if defined(LUA_WIN) && defined(_MSC_VER) && defined(_M_IX86) /* { */ + +#define MS_ASMTRICK +#define LUA_IEEEENDIAN 0 +#define LUA_NANTRICK + + +/* pentium 32 bits? */ +#elif defined(__i386__) || defined(__i386) || defined(__X86__) /* }{ */ + +#define LUA_IEEE754TRICK +#define LUA_IEEELL +#define LUA_IEEEENDIAN 0 +#define LUA_NANTRICK + +/* pentium 64 bits? */ +#elif defined(__x86_64) /* }{ */ + +#define LUA_IEEE754TRICK +#define LUA_IEEEENDIAN 0 + +#elif defined(__POWERPC__) || defined(__ppc__) /* }{ */ + +#define LUA_IEEE754TRICK +#define LUA_IEEEENDIAN 1 + +#else /* }{ */ + +/* assume IEEE754 and a 32-bit integer type */ +#define LUA_IEEE754TRICK + +#endif /* } */ + +#endif /* } */ + +/* }================================================================== */ + + + + +/* =================================================================== */ + +/* +** Local configuration. You can use this space to add your redefinitions +** without modifying the main part of the file. +*/ + + + +#endif + diff --git a/Lib/Include/lualib.h b/Lib/Include/lualib.h new file mode 100644 index 0000000..9fd126b --- /dev/null +++ b/Lib/Include/lualib.h @@ -0,0 +1,55 @@ +/* +** $Id: lualib.h,v 1.43 2011/12/08 12:11:37 roberto Exp $ +** Lua standard libraries +** See Copyright Notice in lua.h +*/ + + +#ifndef lualib_h +#define lualib_h + +#include "lua.h" + + + +LUAMOD_API int (luaopen_base) (lua_State *L); + +#define LUA_COLIBNAME "coroutine" +LUAMOD_API int (luaopen_coroutine) (lua_State *L); + +#define LUA_TABLIBNAME "table" +LUAMOD_API int (luaopen_table) (lua_State *L); + +#define LUA_IOLIBNAME "io" +LUAMOD_API int (luaopen_io) (lua_State *L); + +#define LUA_OSLIBNAME "os" +LUAMOD_API int (luaopen_os) (lua_State *L); + +#define LUA_STRLIBNAME "string" +LUAMOD_API int (luaopen_string) (lua_State *L); + +#define LUA_BITLIBNAME "bit32" +LUAMOD_API int (luaopen_bit32) (lua_State *L); + +#define LUA_MATHLIBNAME "math" +LUAMOD_API int (luaopen_math) (lua_State *L); + +#define LUA_DBLIBNAME "debug" +LUAMOD_API int (luaopen_debug) (lua_State *L); + +#define LUA_LOADLIBNAME "package" +LUAMOD_API int (luaopen_package) (lua_State *L); + + +/* open all previous libraries */ +LUALIB_API void (luaL_openlibs) (lua_State *L); + + + +#if !defined(lua_assert) +#define lua_assert(x) ((void)0) +#endif + + +#endif diff --git a/Lib/Include/physfs.h b/Lib/Include/physfs.h new file mode 100644 index 0000000..5bb26b8 --- /dev/null +++ b/Lib/Include/physfs.h @@ -0,0 +1,2395 @@ +/** + * \file physfs.h + * + * Main header file for PhysicsFS. + */ + +/** + * \mainpage PhysicsFS + * + * The latest version of PhysicsFS can be found at: + * http://icculus.org/physfs/ + * + * PhysicsFS; a portable, flexible file i/o abstraction. + * + * This API gives you access to a system file system in ways superior to the + * stdio or system i/o calls. The brief benefits: + * + * - It's portable. + * - It's safe. No file access is permitted outside the specified dirs. + * - It's flexible. Archives (.ZIP files) can be used transparently as + * directory structures. + * + * This system is largely inspired by Quake 3's PK3 files and the related + * fs_* cvars. If you've ever tinkered with these, then this API will be + * familiar to you. + * + * With PhysicsFS, you have a single writing directory and multiple + * directories (the "search path") for reading. You can think of this as a + * filesystem within a filesystem. If (on Windows) you were to set the + * writing directory to "C:\MyGame\MyWritingDirectory", then no PHYSFS calls + * could touch anything above this directory, including the "C:\MyGame" and + * "C:\" directories. This prevents an application's internal scripting + * language from piddling over c:\\config.sys, for example. If you'd rather + * give PHYSFS full access to the system's REAL file system, set the writing + * dir to "C:\", but that's generally A Bad Thing for several reasons. + * + * Drive letters are hidden in PhysicsFS once you set up your initial paths. + * The search path creates a single, hierarchical directory structure. + * Not only does this lend itself well to general abstraction with archives, + * it also gives better support to operating systems like MacOS and Unix. + * Generally speaking, you shouldn't ever hardcode a drive letter; not only + * does this hurt portability to non-Microsoft OSes, but it limits your win32 + * users to a single drive, too. Use the PhysicsFS abstraction functions and + * allow user-defined configuration options, too. When opening a file, you + * specify it like it was on a Unix filesystem: if you want to write to + * "C:\MyGame\MyConfigFiles\game.cfg", then you might set the write dir to + * "C:\MyGame" and then open "MyConfigFiles/game.cfg". This gives an + * abstraction across all platforms. Specifying a file in this way is termed + * "platform-independent notation" in this documentation. Specifying a + * a filename in a form such as "C:\mydir\myfile" or + * "MacOS hard drive:My Directory:My File" is termed "platform-dependent + * notation". The only time you use platform-dependent notation is when + * setting up your write directory and search path; after that, all file + * access into those directories are done with platform-independent notation. + * + * All files opened for writing are opened in relation to the write directory, + * which is the root of the writable filesystem. When opening a file for + * reading, PhysicsFS goes through the search path. This is NOT the + * same thing as the PATH environment variable. An application using + * PhysicsFS specifies directories to be searched which may be actual + * directories, or archive files that contain files and subdirectories of + * their own. See the end of these docs for currently supported archive + * formats. + * + * Once the search path is defined, you may open files for reading. If you've + * got the following search path defined (to use a win32 example again): + * + * - C:\\mygame + * - C:\\mygame\\myuserfiles + * - D:\\mygamescdromdatafiles + * - C:\\mygame\\installeddatafiles.zip + * + * Then a call to PHYSFS_openRead("textfiles/myfile.txt") (note the directory + * separator, lack of drive letter, and lack of dir separator at the start of + * the string; this is platform-independent notation) will check for + * C:\\mygame\\textfiles\\myfile.txt, then + * C:\\mygame\\myuserfiles\\textfiles\\myfile.txt, then + * D:\\mygamescdromdatafiles\\textfiles\\myfile.txt, then, finally, for + * textfiles\\myfile.txt inside of C:\\mygame\\installeddatafiles.zip. + * Remember that most archive types and platform filesystems store their + * filenames in a case-sensitive manner, so you should be careful to specify + * it correctly. + * + * Files opened through PhysicsFS may NOT contain "." or ".." or ":" as dir + * elements. Not only are these meaningless on MacOS Classic and/or Unix, + * they are a security hole. Also, symbolic links (which can be found in + * some archive types and directly in the filesystem on Unix platforms) are + * NOT followed until you call PHYSFS_permitSymbolicLinks(). That's left to + * your own discretion, as following a symlink can allow for access outside + * the write dir and search paths. For portability, there is no mechanism for + * creating new symlinks in PhysicsFS. + * + * The write dir is not included in the search path unless you specifically + * add it. While you CAN change the write dir as many times as you like, + * you should probably set it once and stick to it. Remember that your + * program will not have permission to write in every directory on Unix and + * NT systems. + * + * All files are opened in binary mode; there is no endline conversion for + * textfiles. Other than that, PhysicsFS has some convenience functions for + * platform-independence. There is a function to tell you the current + * platform's dir separator ("\\" on windows, "/" on Unix, ":" on MacOS), + * which is needed only to set up your search/write paths. There is a + * function to tell you what CD-ROM drives contain accessible discs, and a + * function to recommend a good search path, etc. + * + * A recommended order for the search path is the write dir, then the base dir, + * then the cdrom dir, then any archives discovered. Quake 3 does something + * like this, but moves the archives to the start of the search path. Build + * Engine games, like Duke Nukem 3D and Blood, place the archives last, and + * use the base dir for both searching and writing. There is a helper + * function (PHYSFS_setSaneConfig()) that puts together a basic configuration + * for you, based on a few parameters. Also see the comments on + * PHYSFS_getBaseDir(), and PHYSFS_getUserDir() for info on what those + * are and how they can help you determine an optimal search path. + * + * PhysicsFS 2.0 adds the concept of "mounting" archives to arbitrary points + * in the search path. If a zipfile contains "maps/level.map" and you mount + * that archive at "mods/mymod", then you would have to open + * "mods/mymod/maps/level.map" to access the file, even though "mods/mymod" + * isn't actually specified in the .zip file. Unlike the Unix mentality of + * mounting a filesystem, "mods/mymod" doesn't actually have to exist when + * mounting the zipfile. It's a "virtual" directory. The mounting mechanism + * allows the developer to seperate archives in the tree and avoid trampling + * over files when added new archives, such as including mod support in a + * game...keeping external content on a tight leash in this manner can be of + * utmost importance to some applications. + * + * PhysicsFS is mostly thread safe. The error messages returned by + * PHYSFS_getLastError are unique by thread, and library-state-setting + * functions are mutex'd. For efficiency, individual file accesses are + * not locked, so you can not safely read/write/seek/close/etc the same + * file from two threads at the same time. Other race conditions are bugs + * that should be reported/patched. + * + * While you CAN use stdio/syscall file access in a program that has PHYSFS_* + * calls, doing so is not recommended, and you can not use system + * filehandles with PhysicsFS and vice versa. + * + * Note that archives need not be named as such: if you have a ZIP file and + * rename it with a .PKG extension, the file will still be recognized as a + * ZIP archive by PhysicsFS; the file's contents are used to determine its + * type where possible. + * + * Currently supported archive types: + * - .ZIP (pkZip/WinZip/Info-ZIP compatible) + * - .GRP (Build Engine groupfile archives) + * - .PAK (Quake I/II archive format) + * - .HOG (Descent I/II HOG file archives) + * - .MVL (Descent II movielib archives) + * - .WAD (DOOM engine archives) + * + * + * String policy for PhysicsFS 2.0 and later: + * + * PhysicsFS 1.0 could only deal with null-terminated ASCII strings. All high + * ASCII chars resulted in undefined behaviour, and there was no Unicode + * support at all. PhysicsFS 2.0 supports Unicode without breaking binary + * compatibility with the 1.0 API by using UTF-8 encoding of all strings + * passed in and out of the library. + * + * All strings passed through PhysicsFS are in null-terminated UTF-8 format. + * This means that if all you care about is English (ASCII characters <= 127) + * then you just use regular C strings. If you care about Unicode (and you + * should!) then you need to figure out what your platform wants, needs, and + * offers. If you are on Windows and build with Unicode support, your TCHAR + * strings are two bytes per character (this is called "UCS-2 encoding"). You + * should convert them to UTF-8 before handing them to PhysicsFS with + * PHYSFS_utf8FromUcs2(). If you're using Unix or Mac OS X, your wchar_t + * strings are four bytes per character ("UCS-4 encoding"). Use + * PHYSFS_utf8FromUcs4(). Mac OS X can give you UTF-8 directly from a + * CFString, and many Unixes generally give you C strings in UTF-8 format + * everywhere. If you have a single-byte high ASCII charset, like so-many + * European "codepages" you may be out of luck. We'll convert from "Latin1" + * to UTF-8 only, and never back to Latin1. If you're above ASCII 127, all + * bets are off: move to Unicode or use your platform's facilities. Passing a + * C string with high-ASCII data that isn't UTF-8 encoded will NOT do what + * you expect! + * + * Naturally, there's also PHYSFS_utf8ToUcs2() and PHYSFS_utf8ToUcs4() to get + * data back into a format you like. Behind the scenes, PhysicsFS will use + * Unicode where possible: the UTF-8 strings on Windows will be converted + * and used with the multibyte Windows APIs, for example. + * + * PhysicsFS offers basic encoding conversion support, but not a whole string + * library. Get your stuff into whatever format you can work with. + * + * Some platforms and archivers don't offer full Unicode support behind the + * scenes. For example, OS/2 only offers "codepages" and the filesystem + * itself doesn't support multibyte encodings. We make an earnest effort to + * convert to/from the current locale here, but all bets are off if + * you want to hand an arbitrary Japanese character through to these systems. + * Modern OSes (Mac OS X, Linux, Windows, PocketPC, etc) should all be fine. + * Many game-specific archivers are seriously unprepared for Unicode (the + * Descent HOG/MVL and Build Engine GRP archivers, for example, only offer a + * DOS 8.3 filename, for example). Nothing can be done for these, but they + * tend to be legacy formats for existing content that was all ASCII (and + * thus, valid UTF-8) anyhow. Other formats, like .ZIP, don't explicitly + * offer Unicode support, but unofficially expect filenames to be UTF-8 + * encoded, and thus Just Work. Most everything does the right thing without + * bothering you, but it's good to be aware of these nuances in case they + * don't. + * + * + * Other stuff: + * + * Please see the file LICENSE.txt in the source's root directory for licensing + * and redistribution rights. + * + * Please see the file CREDITS.txt in the source's root directory for a more or + * less complete list of who's responsible for this. + * + * \author Ryan C. Gordon. + */ + +#ifndef _INCLUDE_PHYSFS_H_ +#define _INCLUDE_PHYSFS_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef DOXYGEN_SHOULD_IGNORE_THIS +#if (defined _MSC_VER) +#define __EXPORT__ __declspec(dllexport) +#elif (__GNUC__ >= 3) +#define __EXPORT__ __attribute__((visibility("default"))) +#else +#define __EXPORT__ +#endif +#endif /* DOXYGEN_SHOULD_IGNORE_THIS */ + +/** + * \typedef PHYSFS_uint8 + * \brief An unsigned, 8-bit integer type. + */ +typedef unsigned char PHYSFS_uint8; + +/** + * \typedef PHYSFS_sint8 + * \brief A signed, 8-bit integer type. + */ +typedef signed char PHYSFS_sint8; + +/** + * \typedef PHYSFS_uint16 + * \brief An unsigned, 16-bit integer type. + */ +typedef unsigned short PHYSFS_uint16; + +/** + * \typedef PHYSFS_sint16 + * \brief A signed, 16-bit integer type. + */ +typedef signed short PHYSFS_sint16; + +/** + * \typedef PHYSFS_uint32 + * \brief An unsigned, 32-bit integer type. + */ +typedef unsigned int PHYSFS_uint32; + +/** + * \typedef PHYSFS_sint32 + * \brief A signed, 32-bit integer type. + */ +typedef signed int PHYSFS_sint32; + +/** + * \typedef PHYSFS_uint64 + * \brief An unsigned, 64-bit integer type. + * \warning on platforms without any sort of 64-bit datatype, this is + * equivalent to PHYSFS_uint32! + */ + +/** + * \typedef PHYSFS_sint64 + * \brief A signed, 64-bit integer type. + * \warning on platforms without any sort of 64-bit datatype, this is + * equivalent to PHYSFS_sint32! + */ + + +#if (defined PHYSFS_NO_64BIT_SUPPORT) /* oh well. */ +typedef PHYSFS_uint32 PHYSFS_uint64; +typedef PHYSFS_sint32 PHYSFS_sint64; +#elif (defined _MSC_VER) +typedef signed __int64 PHYSFS_sint64; +typedef unsigned __int64 PHYSFS_uint64; +#else +typedef unsigned long long PHYSFS_uint64; +typedef signed long long PHYSFS_sint64; +#endif + + +#ifndef DOXYGEN_SHOULD_IGNORE_THIS +/* Make sure the types really have the right sizes */ +#define PHYSFS_COMPILE_TIME_ASSERT(name, x) \ + typedef int PHYSFS_dummy_ ## name[(x) * 2 - 1] + +PHYSFS_COMPILE_TIME_ASSERT(uint8, sizeof(PHYSFS_uint8) == 1); +PHYSFS_COMPILE_TIME_ASSERT(sint8, sizeof(PHYSFS_sint8) == 1); +PHYSFS_COMPILE_TIME_ASSERT(uint16, sizeof(PHYSFS_uint16) == 2); +PHYSFS_COMPILE_TIME_ASSERT(sint16, sizeof(PHYSFS_sint16) == 2); +PHYSFS_COMPILE_TIME_ASSERT(uint32, sizeof(PHYSFS_uint32) == 4); +PHYSFS_COMPILE_TIME_ASSERT(sint32, sizeof(PHYSFS_sint32) == 4); + +#ifndef PHYSFS_NO_64BIT_SUPPORT +PHYSFS_COMPILE_TIME_ASSERT(uint64, sizeof(PHYSFS_uint64) == 8); +PHYSFS_COMPILE_TIME_ASSERT(sint64, sizeof(PHYSFS_sint64) == 8); +#endif + +#undef PHYSFS_COMPILE_TIME_ASSERT + +#endif /* DOXYGEN_SHOULD_IGNORE_THIS */ + + +/** + * \struct PHYSFS_File + * \brief A PhysicsFS file handle. + * + * You get a pointer to one of these when you open a file for reading, + * writing, or appending via PhysicsFS. + * + * As you can see from the lack of meaningful fields, you should treat this + * as opaque data. Don't try to manipulate the file handle, just pass the + * pointer you got, unmolested, to various PhysicsFS APIs. + * + * \sa PHYSFS_openRead + * \sa PHYSFS_openWrite + * \sa PHYSFS_openAppend + * \sa PHYSFS_close + * \sa PHYSFS_read + * \sa PHYSFS_write + * \sa PHYSFS_seek + * \sa PHYSFS_tell + * \sa PHYSFS_eof + * \sa PHYSFS_setBuffer + * \sa PHYSFS_flush + */ +typedef struct PHYSFS_File +{ + void *opaque; /**< That's all you get. Don't touch. */ +} PHYSFS_File; + + +/** + * \def PHYSFS_file + * \brief 1.0 API compatibility define. + * + * PHYSFS_file is identical to PHYSFS_File. This #define is here for backwards + * compatibility with the 1.0 API, which had an inconsistent capitalization + * convention in this case. New code should use PHYSFS_File, as this #define + * may go away someday. + * + * \sa PHYSFS_File + */ +#define PHYSFS_file PHYSFS_File + + +/** + * \struct PHYSFS_ArchiveInfo + * \brief Information on various PhysicsFS-supported archives. + * + * This structure gives you details on what sort of archives are supported + * by this implementation of PhysicsFS. Archives tend to be things like + * ZIP files and such. + * + * \warning Not all binaries are created equal! PhysicsFS can be built with + * or without support for various archives. You can check with + * PHYSFS_supportedArchiveTypes() to see if your archive type is + * supported. + * + * \sa PHYSFS_supportedArchiveTypes + */ +typedef struct PHYSFS_ArchiveInfo +{ + const char *extension; /**< Archive file extension: "ZIP", for example. */ + const char *description; /**< Human-readable archive description. */ + const char *author; /**< Person who did support for this archive. */ + const char *url; /**< URL related to this archive */ +} PHYSFS_ArchiveInfo; + + +/** + * \struct PHYSFS_Version + * \brief Information the version of PhysicsFS in use. + * + * Represents the library's version as three levels: major revision + * (increments with massive changes, additions, and enhancements), + * minor revision (increments with backwards-compatible changes to the + * major revision), and patchlevel (increments with fixes to the minor + * revision). + * + * \sa PHYSFS_VERSION + * \sa PHYSFS_getLinkedVersion + */ +typedef struct PHYSFS_Version +{ + PHYSFS_uint8 major; /**< major revision */ + PHYSFS_uint8 minor; /**< minor revision */ + PHYSFS_uint8 patch; /**< patchlevel */ +} PHYSFS_Version; + +#ifndef DOXYGEN_SHOULD_IGNORE_THIS +#define PHYSFS_VER_MAJOR 2 +#define PHYSFS_VER_MINOR 0 +#define PHYSFS_VER_PATCH 1 +#endif /* DOXYGEN_SHOULD_IGNORE_THIS */ + + +/* PhysicsFS state stuff ... */ + +/** + * \def PHYSFS_VERSION(x) + * \brief Macro to determine PhysicsFS version program was compiled against. + * + * This macro fills in a PHYSFS_Version structure with the version of the + * library you compiled against. This is determined by what header the + * compiler uses. Note that if you dynamically linked the library, you might + * have a slightly newer or older version at runtime. That version can be + * determined with PHYSFS_getLinkedVersion(), which, unlike PHYSFS_VERSION, + * is not a macro. + * + * \param x A pointer to a PHYSFS_Version struct to initialize. + * + * \sa PHYSFS_Version + * \sa PHYSFS_getLinkedVersion + */ +#define PHYSFS_VERSION(x) \ +{ \ + (x)->major = PHYSFS_VER_MAJOR; \ + (x)->minor = PHYSFS_VER_MINOR; \ + (x)->patch = PHYSFS_VER_PATCH; \ +} + + +/** + * \fn void PHYSFS_getLinkedVersion(PHYSFS_Version *ver) + * \brief Get the version of PhysicsFS that is linked against your program. + * + * If you are using a shared library (DLL) version of PhysFS, then it is + * possible that it will be different than the version you compiled against. + * + * This is a real function; the macro PHYSFS_VERSION tells you what version + * of PhysFS you compiled against: + * + * \code + * PHYSFS_Version compiled; + * PHYSFS_Version linked; + * + * PHYSFS_VERSION(&compiled); + * PHYSFS_getLinkedVersion(&linked); + * printf("We compiled against PhysFS version %d.%d.%d ...\n", + * compiled.major, compiled.minor, compiled.patch); + * printf("But we linked against PhysFS version %d.%d.%d.\n", + * linked.major, linked.minor, linked.patch); + * \endcode + * + * This function may be called safely at any time, even before PHYSFS_init(). + * + * \sa PHYSFS_VERSION + */ +__EXPORT__ void PHYSFS_getLinkedVersion(PHYSFS_Version *ver); + + +/** + * \fn int PHYSFS_init(const char *argv0) + * \brief Initialize the PhysicsFS library. + * + * This must be called before any other PhysicsFS function. + * + * This should be called prior to any attempts to change your process's + * current working directory. + * + * \param argv0 the argv[0] string passed to your program's mainline. + * This may be NULL on most platforms (such as ones without a + * standard main() function), but you should always try to pass + * something in here. Unix-like systems such as Linux _need_ to + * pass argv[0] from main() in here. + * \return nonzero on success, zero on error. Specifics of the error can be + * gleaned from PHYSFS_getLastError(). + * + * \sa PHYSFS_deinit + * \sa PHYSFS_isInit + */ +__EXPORT__ int PHYSFS_init(const char *argv0); + + +/** + * \fn int PHYSFS_deinit(void) + * \brief Deinitialize the PhysicsFS library. + * + * This closes any files opened via PhysicsFS, blanks the search/write paths, + * frees memory, and invalidates all of your file handles. + * + * Note that this call can FAIL if there's a file open for writing that + * refuses to close (for example, the underlying operating system was + * buffering writes to network filesystem, and the fileserver has crashed, + * or a hard drive has failed, etc). It is usually best to close all write + * handles yourself before calling this function, so that you can gracefully + * handle a specific failure. + * + * Once successfully deinitialized, PHYSFS_init() can be called again to + * restart the subsystem. All default API states are restored at this + * point, with the exception of any custom allocator you might have + * specified, which survives between initializations. + * + * \return nonzero on success, zero on error. Specifics of the error can be + * gleaned from PHYSFS_getLastError(). If failure, state of PhysFS is + * undefined, and probably badly screwed up. + * + * \sa PHYSFS_init + * \sa PHYSFS_isInit + */ +__EXPORT__ int PHYSFS_deinit(void); + + +/** + * \fn const PHYSFS_ArchiveInfo **PHYSFS_supportedArchiveTypes(void) + * \brief Get a list of supported archive types. + * + * Get a list of archive types supported by this implementation of PhysicFS. + * These are the file formats usable for search path entries. This is for + * informational purposes only. Note that the extension listed is merely + * convention: if we list "ZIP", you can open a PkZip-compatible archive + * with an extension of "XYZ", if you like. + * + * The returned value is an array of pointers to PHYSFS_ArchiveInfo structures, + * with a NULL entry to signify the end of the list: + * + * \code + * PHYSFS_ArchiveInfo **i; + * + * for (i = PHYSFS_supportedArchiveTypes(); *i != NULL; i++) + * { + * printf("Supported archive: [%s], which is [%s].\n", + * (*i)->extension, (*i)->description); + * } + * \endcode + * + * The return values are pointers to static internal memory, and should + * be considered READ ONLY, and never freed. + * + * \return READ ONLY Null-terminated array of READ ONLY structures. + */ +__EXPORT__ const PHYSFS_ArchiveInfo **PHYSFS_supportedArchiveTypes(void); + + +/** + * \fn void PHYSFS_freeList(void *listVar) + * \brief Deallocate resources of lists returned by PhysicsFS. + * + * Certain PhysicsFS functions return lists of information that are + * dynamically allocated. Use this function to free those resources. + * + * \param listVar List of information specified as freeable by this function. + * + * \sa PHYSFS_getCdRomDirs + * \sa PHYSFS_enumerateFiles + * \sa PHYSFS_getSearchPath + */ +__EXPORT__ void PHYSFS_freeList(void *listVar); + + +/** + * \fn const char *PHYSFS_getLastError(void) + * \brief Get human-readable error information. + * + * Get the last PhysicsFS error message as a human-readable, null-terminated + * string. This will be NULL if there's been no error since the last call to + * this function. The pointer returned by this call points to an internal + * buffer. Each thread has a unique error state associated with it, but each + * time a new error message is set, it will overwrite the previous one + * associated with that thread. It is safe to call this function at anytime, + * even before PHYSFS_init(). + * + * It is not wise to expect a specific string of characters here, since the + * error message may be localized into an unfamiliar language. These strings + * are meant to be passed on directly to the user. + * + * \return READ ONLY string of last error message. + */ +__EXPORT__ const char *PHYSFS_getLastError(void); + + +/** + * \fn const char *PHYSFS_getDirSeparator(void) + * \brief Get platform-dependent dir separator string. + * + * This returns "\\" on win32, "/" on Unix, and ":" on MacOS. It may be more + * than one character, depending on the platform, and your code should take + * that into account. Note that this is only useful for setting up the + * search/write paths, since access into those dirs always use '/' + * (platform-independent notation) to separate directories. This is also + * handy for getting platform-independent access when using stdio calls. + * + * \return READ ONLY null-terminated string of platform's dir separator. + */ +__EXPORT__ const char *PHYSFS_getDirSeparator(void); + + +/** + * \fn void PHYSFS_permitSymbolicLinks(int allow) + * \brief Enable or disable following of symbolic links. + * + * Some physical filesystems and archives contain files that are just pointers + * to other files. On the physical filesystem, opening such a link will + * (transparently) open the file that is pointed to. + * + * By default, PhysicsFS will check if a file is really a symlink during open + * calls and fail if it is. Otherwise, the link could take you outside the + * write and search paths, and compromise security. + * + * If you want to take that risk, call this function with a non-zero parameter. + * Note that this is more for sandboxing a program's scripting language, in + * case untrusted scripts try to compromise the system. Generally speaking, + * a user could very well have a legitimate reason to set up a symlink, so + * unless you feel there's a specific danger in allowing them, you should + * permit them. + * + * Symlinks are only explicitly checked when dealing with filenames + * in platform-independent notation. That is, when setting up your + * search and write paths, etc, symlinks are never checked for. + * + * Symbolic link permission can be enabled or disabled at any time after + * you've called PHYSFS_init(), and is disabled by default. + * + * \param allow nonzero to permit symlinks, zero to deny linking. + * + * \sa PHYSFS_symbolicLinksPermitted + */ +__EXPORT__ void PHYSFS_permitSymbolicLinks(int allow); + + +/* !!! FIXME: const this? */ +/** + * \fn char **PHYSFS_getCdRomDirs(void) + * \brief Get an array of paths to available CD-ROM drives. + * + * The dirs returned are platform-dependent ("D:\" on Win32, "/cdrom" or + * whatnot on Unix). Dirs are only returned if there is a disc ready and + * accessible in the drive. So if you've got two drives (D: and E:), and only + * E: has a disc in it, then that's all you get. If the user inserts a disc + * in D: and you call this function again, you get both drives. If, on a + * Unix box, the user unmounts a disc and remounts it elsewhere, the next + * call to this function will reflect that change. + * + * This function refers to "CD-ROM" media, but it really means "inserted disc + * media," such as DVD-ROM, HD-DVD, CDRW, and Blu-Ray discs. It looks for + * filesystems, and as such won't report an audio CD, unless there's a + * mounted filesystem track on it. + * + * The returned value is an array of strings, with a NULL entry to signify the + * end of the list: + * + * \code + * char **cds = PHYSFS_getCdRomDirs(); + * char **i; + * + * for (i = cds; *i != NULL; i++) + * printf("cdrom dir [%s] is available.\n", *i); + * + * PHYSFS_freeList(cds); + * \endcode + * + * This call may block while drives spin up. Be forewarned. + * + * When you are done with the returned information, you may dispose of the + * resources by calling PHYSFS_freeList() with the returned pointer. + * + * \return Null-terminated array of null-terminated strings. + * + * \sa PHYSFS_getCdRomDirsCallback + */ +__EXPORT__ char **PHYSFS_getCdRomDirs(void); + + +/** + * \fn const char *PHYSFS_getBaseDir(void) + * \brief Get the path where the application resides. + * + * Helper function. + * + * Get the "base dir". This is the directory where the application was run + * from, which is probably the installation directory, and may or may not + * be the process's current working directory. + * + * You should probably use the base dir in your search path. + * + * \return READ ONLY string of base dir in platform-dependent notation. + * + * \sa PHYSFS_getUserDir + */ +__EXPORT__ const char *PHYSFS_getBaseDir(void); + + +/** + * \fn const char *PHYSFS_getUserDir(void) + * \brief Get the path where user's home directory resides. + * + * Helper function. + * + * Get the "user dir". This is meant to be a suggestion of where a specific + * user of the system can store files. On Unix, this is her home directory. + * On systems with no concept of multiple home directories (MacOS, win95), + * this will default to something like "C:\mybasedir\users\username" + * where "username" will either be the login name, or "default" if the + * platform doesn't support multiple users, either. + * + * You should probably use the user dir as the basis for your write dir, and + * also put it near the beginning of your search path. + * + * \return READ ONLY string of user dir in platform-dependent notation. + * + * \sa PHYSFS_getBaseDir + */ +__EXPORT__ const char *PHYSFS_getUserDir(void); + + +/** + * \fn const char *PHYSFS_getWriteDir(void) + * \brief Get path where PhysicsFS will allow file writing. + * + * Get the current write dir. The default write dir is NULL. + * + * \return READ ONLY string of write dir in platform-dependent notation, + * OR NULL IF NO WRITE PATH IS CURRENTLY SET. + * + * \sa PHYSFS_setWriteDir + */ +__EXPORT__ const char *PHYSFS_getWriteDir(void); + + +/** + * \fn int PHYSFS_setWriteDir(const char *newDir) + * \brief Tell PhysicsFS where it may write files. + * + * Set a new write dir. This will override the previous setting. + * + * This call will fail (and fail to change the write dir) if the current + * write dir still has files open in it. + * + * \param newDir The new directory to be the root of the write dir, + * specified in platform-dependent notation. Setting to NULL + * disables the write dir, so no files can be opened for + * writing via PhysicsFS. + * \return non-zero on success, zero on failure. All attempts to open a file + * for writing via PhysicsFS will fail until this call succeeds. + * Specifics of the error can be gleaned from PHYSFS_getLastError(). + * + * \sa PHYSFS_getWriteDir + */ +__EXPORT__ int PHYSFS_setWriteDir(const char *newDir); + + +/** + * \fn int PHYSFS_addToSearchPath(const char *newDir, int appendToPath) + * \brief Add an archive or directory to the search path. + * + * This is a legacy call in PhysicsFS 2.0, equivalent to: + * PHYSFS_mount(newDir, NULL, appendToPath); + * + * You must use this and not PHYSFS_mount if binary compatibility with + * PhysicsFS 1.0 is important (which it may not be for many people). + * + * \sa PHYSFS_mount + * \sa PHYSFS_removeFromSearchPath + * \sa PHYSFS_getSearchPath + */ +__EXPORT__ int PHYSFS_addToSearchPath(const char *newDir, int appendToPath); + + +/** + * \fn int PHYSFS_removeFromSearchPath(const char *oldDir) + * \brief Remove a directory or archive from the search path. + * + * This must be a (case-sensitive) match to a dir or archive already in the + * search path, specified in platform-dependent notation. + * + * This call will fail (and fail to remove from the path) if the element still + * has files open in it. + * + * \param oldDir dir/archive to remove. + * \return nonzero on success, zero on failure. + * Specifics of the error can be gleaned from PHYSFS_getLastError(). + * + * \sa PHYSFS_addToSearchPath + * \sa PHYSFS_getSearchPath + */ +__EXPORT__ int PHYSFS_removeFromSearchPath(const char *oldDir); + + +/** + * \fn char **PHYSFS_getSearchPath(void) + * \brief Get the current search path. + * + * The default search path is an empty list. + * + * The returned value is an array of strings, with a NULL entry to signify the + * end of the list: + * + * \code + * char **i; + * + * for (i = PHYSFS_getSearchPath(); *i != NULL; i++) + * printf("[%s] is in the search path.\n", *i); + * \endcode + * + * When you are done with the returned information, you may dispose of the + * resources by calling PHYSFS_freeList() with the returned pointer. + * + * \return Null-terminated array of null-terminated strings. NULL if there + * was a problem (read: OUT OF MEMORY). + * + * \sa PHYSFS_getSearchPathCallback + * \sa PHYSFS_addToSearchPath + * \sa PHYSFS_removeFromSearchPath + */ +__EXPORT__ char **PHYSFS_getSearchPath(void); + + +/** + * \fn int PHYSFS_setSaneConfig(const char *organization, const char *appName, const char *archiveExt, int includeCdRoms, int archivesFirst) + * \brief Set up sane, default paths. + * + * Helper function. + * + * The write dir will be set to "userdir/.organization/appName", which is + * created if it doesn't exist. + * + * The above is sufficient to make sure your program's configuration directory + * is separated from other clutter, and platform-independent. The period + * before "mygame" even hides the directory on Unix systems. + * + * The search path will be: + * + * - The Write Dir (created if it doesn't exist) + * - The Base Dir (PHYSFS_getBaseDir()) + * - All found CD-ROM dirs (optionally) + * + * These directories are then searched for files ending with the extension + * (archiveExt), which, if they are valid and supported archives, will also + * be added to the search path. If you specified "PKG" for (archiveExt), and + * there's a file named data.PKG in the base dir, it'll be checked. Archives + * can either be appended or prepended to the search path in alphabetical + * order, regardless of which directories they were found in. + * + * All of this can be accomplished from the application, but this just does it + * all for you. Feel free to add more to the search path manually, too. + * + * \param organization Name of your company/group/etc to be used as a + * dirname, so keep it small, and no-frills. + * + * \param appName Program-specific name of your program, to separate it + * from other programs using PhysicsFS. + * + * \param archiveExt File extension used by your program to specify an + * archive. For example, Quake 3 uses "pk3", even though + * they are just zipfiles. Specify NULL to not dig out + * archives automatically. Do not specify the '.' char; + * If you want to look for ZIP files, specify "ZIP" and + * not ".ZIP" ... the archive search is case-insensitive. + * + * \param includeCdRoms Non-zero to include CD-ROMs in the search path, and + * (if (archiveExt) != NULL) search them for archives. + * This may cause a significant amount of blocking + * while discs are accessed, and if there are no discs + * in the drive (or even not mounted on Unix systems), + * then they may not be made available anyhow. You may + * want to specify zero and handle the disc setup + * yourself. + * + * \param archivesFirst Non-zero to prepend the archives to the search path. + * Zero to append them. Ignored if !(archiveExt). + * + * \return nonzero on success, zero on error. Specifics of the error can be + * gleaned from PHYSFS_getLastError(). + */ +__EXPORT__ int PHYSFS_setSaneConfig(const char *organization, + const char *appName, + const char *archiveExt, + int includeCdRoms, + int archivesFirst); + + +/* Directory management stuff ... */ + +/** + * \fn int PHYSFS_mkdir(const char *dirName) + * \brief Create a directory. + * + * This is specified in platform-independent notation in relation to the + * write dir. All missing parent directories are also created if they + * don't exist. + * + * So if you've got the write dir set to "C:\mygame\writedir" and call + * PHYSFS_mkdir("downloads/maps") then the directories + * "C:\mygame\writedir\downloads" and "C:\mygame\writedir\downloads\maps" + * will be created if possible. If the creation of "maps" fails after we + * have successfully created "downloads", then the function leaves the + * created directory behind and reports failure. + * + * \param dirName New dir to create. + * \return nonzero on success, zero on error. Specifics of the error can be + * gleaned from PHYSFS_getLastError(). + * + * \sa PHYSFS_delete + */ +__EXPORT__ int PHYSFS_mkdir(const char *dirName); + + +/** + * \fn int PHYSFS_delete(const char *filename) + * \brief Delete a file or directory. + * + * (filename) is specified in platform-independent notation in relation to the + * write dir. + * + * A directory must be empty before this call can delete it. + * + * Deleting a symlink will remove the link, not what it points to, regardless + * of whether you "permitSymLinks" or not. + * + * So if you've got the write dir set to "C:\mygame\writedir" and call + * PHYSFS_delete("downloads/maps/level1.map") then the file + * "C:\mygame\writedir\downloads\maps\level1.map" is removed from the + * physical filesystem, if it exists and the operating system permits the + * deletion. + * + * Note that on Unix systems, deleting a file may be successful, but the + * actual file won't be removed until all processes that have an open + * filehandle to it (including your program) close their handles. + * + * Chances are, the bits that make up the file still exist, they are just + * made available to be written over at a later point. Don't consider this + * a security method or anything. :) + * + * \param filename Filename to delete. + * \return nonzero on success, zero on error. Specifics of the error can be + * gleaned from PHYSFS_getLastError(). + */ +__EXPORT__ int PHYSFS_delete(const char *filename); + + +/** + * \fn const char *PHYSFS_getRealDir(const char *filename) + * \brief Figure out where in the search path a file resides. + * + * The file is specified in platform-independent notation. The returned + * filename will be the element of the search path where the file was found, + * which may be a directory, or an archive. Even if there are multiple + * matches in different parts of the search path, only the first one found + * is used, just like when opening a file. + * + * So, if you look for "maps/level1.map", and C:\\mygame is in your search + * path and C:\\mygame\\maps\\level1.map exists, then "C:\mygame" is returned. + * + * If a any part of a match is a symbolic link, and you've not explicitly + * permitted symlinks, then it will be ignored, and the search for a match + * will continue. + * + * If you specify a fake directory that only exists as a mount point, it'll + * be associated with the first archive mounted there, even though that + * directory isn't necessarily contained in a real archive. + * + * \param filename file to look for. + * \return READ ONLY string of element of search path containing the + * the file in question. NULL if not found. + */ +__EXPORT__ const char *PHYSFS_getRealDir(const char *filename); + + +/** + * \fn char **PHYSFS_enumerateFiles(const char *dir) + * \brief Get a file listing of a search path's directory. + * + * Matching directories are interpolated. That is, if "C:\mydir" is in the + * search path and contains a directory "savegames" that contains "x.sav", + * "y.sav", and "z.sav", and there is also a "C:\userdir" in the search path + * that has a "savegames" subdirectory with "w.sav", then the following code: + * + * \code + * char **rc = PHYSFS_enumerateFiles("savegames"); + * char **i; + * + * for (i = rc; *i != NULL; i++) + * printf(" * We've got [%s].\n", *i); + * + * PHYSFS_freeList(rc); + * \endcode + * + * \...will print: + * + * \verbatim + * We've got [x.sav]. + * We've got [y.sav]. + * We've got [z.sav]. + * We've got [w.sav].\endverbatim + * + * Feel free to sort the list however you like. We only promise there will + * be no duplicates, but not what order the final list will come back in. + * + * Don't forget to call PHYSFS_freeList() with the return value from this + * function when you are done with it. + * + * \param dir directory in platform-independent notation to enumerate. + * \return Null-terminated array of null-terminated strings. + * + * \sa PHYSFS_enumerateFilesCallback + */ +__EXPORT__ char **PHYSFS_enumerateFiles(const char *dir); + + +/** + * \fn int PHYSFS_exists(const char *fname) + * \brief Determine if a file exists in the search path. + * + * Reports true if there is an entry anywhere in the search path by the + * name of (fname). + * + * Note that entries that are symlinks are ignored if + * PHYSFS_permitSymbolicLinks(1) hasn't been called, so you + * might end up further down in the search path than expected. + * + * \param fname filename in platform-independent notation. + * \return non-zero if filename exists. zero otherwise. + * + * \sa PHYSFS_isDirectory + * \sa PHYSFS_isSymbolicLink + */ +__EXPORT__ int PHYSFS_exists(const char *fname); + + +/** + * \fn int PHYSFS_isDirectory(const char *fname) + * \brief Determine if a file in the search path is really a directory. + * + * Determine if the first occurence of (fname) in the search path is + * really a directory entry. + * + * Note that entries that are symlinks are ignored if + * PHYSFS_permitSymbolicLinks(1) hasn't been called, so you + * might end up further down in the search path than expected. + * + * \param fname filename in platform-independent notation. + * \return non-zero if filename exists and is a directory. zero otherwise. + * + * \sa PHYSFS_exists + * \sa PHYSFS_isSymbolicLink + */ +__EXPORT__ int PHYSFS_isDirectory(const char *fname); + + +/** + * \fn int PHYSFS_isSymbolicLink(const char *fname) + * \brief Determine if a file in the search path is really a symbolic link. + * + * Determine if the first occurence of (fname) in the search path is + * really a symbolic link. + * + * Note that entries that are symlinks are ignored if + * PHYSFS_permitSymbolicLinks(1) hasn't been called, and as such, + * this function will always return 0 in that case. + * + * \param fname filename in platform-independent notation. + * \return non-zero if filename exists and is a symlink. zero otherwise. + * + * \sa PHYSFS_exists + * \sa PHYSFS_isDirectory + */ +__EXPORT__ int PHYSFS_isSymbolicLink(const char *fname); + + +/** + * \fn PHYSFS_sint64 PHYSFS_getLastModTime(const char *filename) + * \brief Get the last modification time of a file. + * + * The modtime is returned as a number of seconds since the epoch + * (Jan 1, 1970). The exact derivation and accuracy of this time depends on + * the particular archiver. If there is no reasonable way to obtain this + * information for a particular archiver, or there was some sort of error, + * this function returns (-1). + * + * \param filename filename to check, in platform-independent notation. + * \return last modified time of the file. -1 if it can't be determined. + */ +__EXPORT__ PHYSFS_sint64 PHYSFS_getLastModTime(const char *filename); + + +/* i/o stuff... */ + +/** + * \fn PHYSFS_File *PHYSFS_openWrite(const char *filename) + * \brief Open a file for writing. + * + * Open a file for writing, in platform-independent notation and in relation + * to the write dir as the root of the writable filesystem. The specified + * file is created if it doesn't exist. If it does exist, it is truncated to + * zero bytes, and the writing offset is set to the start. + * + * Note that entries that are symlinks are ignored if + * PHYSFS_permitSymbolicLinks(1) hasn't been called, and opening a + * symlink with this function will fail in such a case. + * + * \param filename File to open. + * \return A valid PhysicsFS filehandle on success, NULL on error. Specifics + * of the error can be gleaned from PHYSFS_getLastError(). + * + * \sa PHYSFS_openRead + * \sa PHYSFS_openAppend + * \sa PHYSFS_write + * \sa PHYSFS_close + */ +__EXPORT__ PHYSFS_File *PHYSFS_openWrite(const char *filename); + + +/** + * \fn PHYSFS_File *PHYSFS_openAppend(const char *filename) + * \brief Open a file for appending. + * + * Open a file for writing, in platform-independent notation and in relation + * to the write dir as the root of the writable filesystem. The specified + * file is created if it doesn't exist. If it does exist, the writing offset + * is set to the end of the file, so the first write will be the byte after + * the end. + * + * Note that entries that are symlinks are ignored if + * PHYSFS_permitSymbolicLinks(1) hasn't been called, and opening a + * symlink with this function will fail in such a case. + * + * \param filename File to open. + * \return A valid PhysicsFS filehandle on success, NULL on error. Specifics + * of the error can be gleaned from PHYSFS_getLastError(). + * + * \sa PHYSFS_openRead + * \sa PHYSFS_openWrite + * \sa PHYSFS_write + * \sa PHYSFS_close + */ +__EXPORT__ PHYSFS_File *PHYSFS_openAppend(const char *filename); + + +/** + * \fn PHYSFS_File *PHYSFS_openRead(const char *filename) + * \brief Open a file for reading. + * + * Open a file for reading, in platform-independent notation. The search path + * is checked one at a time until a matching file is found, in which case an + * abstract filehandle is associated with it, and reading may be done. + * The reading offset is set to the first byte of the file. + * + * Note that entries that are symlinks are ignored if + * PHYSFS_permitSymbolicLinks(1) hasn't been called, and opening a + * symlink with this function will fail in such a case. + * + * \param filename File to open. + * \return A valid PhysicsFS filehandle on success, NULL on error. Specifics + * of the error can be gleaned from PHYSFS_getLastError(). + * + * \sa PHYSFS_openWrite + * \sa PHYSFS_openAppend + * \sa PHYSFS_read + * \sa PHYSFS_close + */ +__EXPORT__ PHYSFS_File *PHYSFS_openRead(const char *filename); + + +/** + * \fn int PHYSFS_close(PHYSFS_File *handle) + * \brief Close a PhysicsFS filehandle. + * + * This call is capable of failing if the operating system was buffering + * writes to the physical media, and, now forced to write those changes to + * physical media, can not store the data for some reason. In such a case, + * the filehandle stays open. A well-written program should ALWAYS check the + * return value from the close call in addition to every writing call! + * + * \param handle handle returned from PHYSFS_open*(). + * \return nonzero on success, zero on error. Specifics of the error can be + * gleaned from PHYSFS_getLastError(). + * + * \sa PHYSFS_openRead + * \sa PHYSFS_openWrite + * \sa PHYSFS_openAppend + */ +__EXPORT__ int PHYSFS_close(PHYSFS_File *handle); + + +/** + * \fn PHYSFS_sint64 PHYSFS_read(PHYSFS_File *handle, void *buffer, PHYSFS_uint32 objSize, PHYSFS_uint32 objCount) + * \brief Read data from a PhysicsFS filehandle + * + * The file must be opened for reading. + * + * \param handle handle returned from PHYSFS_openRead(). + * \param buffer buffer to store read data into. + * \param objSize size in bytes of objects being read from (handle). + * \param objCount number of (objSize) objects to read from (handle). + * \return number of objects read. PHYSFS_getLastError() can shed light on + * the reason this might be < (objCount), as can PHYSFS_eof(). + * -1 if complete failure. + * + * \sa PHYSFS_eof + */ +__EXPORT__ PHYSFS_sint64 PHYSFS_read(PHYSFS_File *handle, + void *buffer, + PHYSFS_uint32 objSize, + PHYSFS_uint32 objCount); + +/** + * \fn PHYSFS_sint64 PHYSFS_write(PHYSFS_File *handle, const void *buffer, PHYSFS_uint32 objSize, PHYSFS_uint32 objCount) + * \brief Write data to a PhysicsFS filehandle + * + * The file must be opened for writing. + * + * \param handle retval from PHYSFS_openWrite() or PHYSFS_openAppend(). + * \param buffer buffer to store read data into. + * \param objSize size in bytes of objects being read from (handle). + * \param objCount number of (objSize) objects to read from (handle). + * \return number of objects written. PHYSFS_getLastError() can shed light on + * the reason this might be < (objCount). -1 if complete failure. + */ +__EXPORT__ PHYSFS_sint64 PHYSFS_write(PHYSFS_File *handle, + const void *buffer, + PHYSFS_uint32 objSize, + PHYSFS_uint32 objCount); + + +/* File position stuff... */ + +/** + * \fn int PHYSFS_eof(PHYSFS_File *handle) + * \brief Check for end-of-file state on a PhysicsFS filehandle. + * + * Determine if the end of file has been reached in a PhysicsFS filehandle. + * + * \param handle handle returned from PHYSFS_openRead(). + * \return nonzero if EOF, zero if not. + * + * \sa PHYSFS_read + * \sa PHYSFS_tell + */ +__EXPORT__ int PHYSFS_eof(PHYSFS_File *handle); + + +/** + * \fn PHYSFS_sint64 PHYSFS_tell(PHYSFS_File *handle) + * \brief Determine current position within a PhysicsFS filehandle. + * + * \param handle handle returned from PHYSFS_open*(). + * \return offset in bytes from start of file. -1 if error occurred. + * Specifics of the error can be gleaned from PHYSFS_getLastError(). + * + * \sa PHYSFS_seek + */ +__EXPORT__ PHYSFS_sint64 PHYSFS_tell(PHYSFS_File *handle); + + +/** + * \fn int PHYSFS_seek(PHYSFS_File *handle, PHYSFS_uint64 pos) + * \brief Seek to a new position within a PhysicsFS filehandle. + * + * The next read or write will occur at that place. Seeking past the + * beginning or end of the file is not allowed, and causes an error. + * + * \param handle handle returned from PHYSFS_open*(). + * \param pos number of bytes from start of file to seek to. + * \return nonzero on success, zero on error. Specifics of the error can be + * gleaned from PHYSFS_getLastError(). + * + * \sa PHYSFS_tell + */ +__EXPORT__ int PHYSFS_seek(PHYSFS_File *handle, PHYSFS_uint64 pos); + + +/** + * \fn PHYSFS_sint64 PHYSFS_fileLength(PHYSFS_File *handle) + * \brief Get total length of a file in bytes. + * + * Note that if the file size can't be determined (since the archive is + * "streamed" or whatnot) than this will report (-1). Also note that if + * another process/thread is writing to this file at the same time, then + * the information this function supplies could be incorrect before you + * get it. Use with caution, or better yet, don't use at all. + * + * \param handle handle returned from PHYSFS_open*(). + * \return size in bytes of the file. -1 if can't be determined. + * + * \sa PHYSFS_tell + * \sa PHYSFS_seek + */ +__EXPORT__ PHYSFS_sint64 PHYSFS_fileLength(PHYSFS_File *handle); + + +/* Buffering stuff... */ + +/** + * \fn int PHYSFS_setBuffer(PHYSFS_File *handle, PHYSFS_uint64 bufsize) + * \brief Set up buffering for a PhysicsFS file handle. + * + * Define an i/o buffer for a file handle. A memory block of (bufsize) bytes + * will be allocated and associated with (handle). + * + * For files opened for reading, up to (bufsize) bytes are read from (handle) + * and stored in the internal buffer. Calls to PHYSFS_read() will pull + * from this buffer until it is empty, and then refill it for more reading. + * Note that compressed files, like ZIP archives, will decompress while + * buffering, so this can be handy for offsetting CPU-intensive operations. + * The buffer isn't filled until you do your next read. + * + * For files opened for writing, data will be buffered to memory until the + * buffer is full or the buffer is flushed. Closing a handle implicitly + * causes a flush...check your return values! + * + * Seeking, etc transparently accounts for buffering. + * + * You can resize an existing buffer by calling this function more than once + * on the same file. Setting the buffer size to zero will free an existing + * buffer. + * + * PhysicsFS file handles are unbuffered by default. + * + * Please check the return value of this function! Failures can include + * not being able to seek backwards in a read-only file when removing the + * buffer, not being able to allocate the buffer, and not being able to + * flush the buffer to disk, among other unexpected problems. + * + * \param handle handle returned from PHYSFS_open*(). + * \param bufsize size, in bytes, of buffer to allocate. + * \return nonzero if successful, zero on error. + * + * \sa PHYSFS_flush + * \sa PHYSFS_read + * \sa PHYSFS_write + * \sa PHYSFS_close + */ +__EXPORT__ int PHYSFS_setBuffer(PHYSFS_File *handle, PHYSFS_uint64 bufsize); + + +/** + * \fn int PHYSFS_flush(PHYSFS_File *handle) + * \brief Flush a buffered PhysicsFS file handle. + * + * For buffered files opened for writing, this will put the current contents + * of the buffer to disk and flag the buffer as empty if possible. + * + * For buffered files opened for reading or unbuffered files, this is a safe + * no-op, and will report success. + * + * \param handle handle returned from PHYSFS_open*(). + * \return nonzero if successful, zero on error. + * + * \sa PHYSFS_setBuffer + * \sa PHYSFS_close + */ +__EXPORT__ int PHYSFS_flush(PHYSFS_File *handle); + + +/* Byteorder stuff... */ + +/** + * \fn PHYSFS_sint16 PHYSFS_swapSLE16(PHYSFS_sint16 val) + * \brief Swap littleendian signed 16 to platform's native byte order. + * + * Take a 16-bit signed value in littleendian format and convert it to + * the platform's native byte order. + * + * \param val value to convert + * \return converted value. + */ +__EXPORT__ PHYSFS_sint16 PHYSFS_swapSLE16(PHYSFS_sint16 val); + + +/** + * \fn PHYSFS_uint16 PHYSFS_swapULE16(PHYSFS_uint16 val) + * \brief Swap littleendian unsigned 16 to platform's native byte order. + * + * Take a 16-bit unsigned value in littleendian format and convert it to + * the platform's native byte order. + * + * \param val value to convert + * \return converted value. + */ +__EXPORT__ PHYSFS_uint16 PHYSFS_swapULE16(PHYSFS_uint16 val); + +/** + * \fn PHYSFS_sint32 PHYSFS_swapSLE32(PHYSFS_sint32 val) + * \brief Swap littleendian signed 32 to platform's native byte order. + * + * Take a 32-bit signed value in littleendian format and convert it to + * the platform's native byte order. + * + * \param val value to convert + * \return converted value. + */ +__EXPORT__ PHYSFS_sint32 PHYSFS_swapSLE32(PHYSFS_sint32 val); + + +/** + * \fn PHYSFS_uint32 PHYSFS_swapULE32(PHYSFS_uint32 val) + * \brief Swap littleendian unsigned 32 to platform's native byte order. + * + * Take a 32-bit unsigned value in littleendian format and convert it to + * the platform's native byte order. + * + * \param val value to convert + * \return converted value. + */ +__EXPORT__ PHYSFS_uint32 PHYSFS_swapULE32(PHYSFS_uint32 val); + +/** + * \fn PHYSFS_sint64 PHYSFS_swapSLE64(PHYSFS_sint64 val) + * \brief Swap littleendian signed 64 to platform's native byte order. + * + * Take a 64-bit signed value in littleendian format and convert it to + * the platform's native byte order. + * + * \param val value to convert + * \return converted value. + * + * \warning Remember, PHYSFS_uint64 is only 32 bits on platforms without + * any sort of 64-bit support. + */ +__EXPORT__ PHYSFS_sint64 PHYSFS_swapSLE64(PHYSFS_sint64 val); + + +/** + * \fn PHYSFS_uint64 PHYSFS_swapULE64(PHYSFS_uint64 val) + * \brief Swap littleendian unsigned 64 to platform's native byte order. + * + * Take a 64-bit unsigned value in littleendian format and convert it to + * the platform's native byte order. + * + * \param val value to convert + * \return converted value. + * + * \warning Remember, PHYSFS_uint64 is only 32 bits on platforms without + * any sort of 64-bit support. + */ +__EXPORT__ PHYSFS_uint64 PHYSFS_swapULE64(PHYSFS_uint64 val); + + +/** + * \fn PHYSFS_sint16 PHYSFS_swapSBE16(PHYSFS_sint16 val) + * \brief Swap bigendian signed 16 to platform's native byte order. + * + * Take a 16-bit signed value in bigendian format and convert it to + * the platform's native byte order. + * + * \param val value to convert + * \return converted value. + */ +__EXPORT__ PHYSFS_sint16 PHYSFS_swapSBE16(PHYSFS_sint16 val); + + +/** + * \fn PHYSFS_uint16 PHYSFS_swapUBE16(PHYSFS_uint16 val) + * \brief Swap bigendian unsigned 16 to platform's native byte order. + * + * Take a 16-bit unsigned value in bigendian format and convert it to + * the platform's native byte order. + * + * \param val value to convert + * \return converted value. + */ +__EXPORT__ PHYSFS_uint16 PHYSFS_swapUBE16(PHYSFS_uint16 val); + +/** + * \fn PHYSFS_sint32 PHYSFS_swapSBE32(PHYSFS_sint32 val) + * \brief Swap bigendian signed 32 to platform's native byte order. + * + * Take a 32-bit signed value in bigendian format and convert it to + * the platform's native byte order. + * + * \param val value to convert + * \return converted value. + */ +__EXPORT__ PHYSFS_sint32 PHYSFS_swapSBE32(PHYSFS_sint32 val); + + +/** + * \fn PHYSFS_uint32 PHYSFS_swapUBE32(PHYSFS_uint32 val) + * \brief Swap bigendian unsigned 32 to platform's native byte order. + * + * Take a 32-bit unsigned value in bigendian format and convert it to + * the platform's native byte order. + * + * \param val value to convert + * \return converted value. + */ +__EXPORT__ PHYSFS_uint32 PHYSFS_swapUBE32(PHYSFS_uint32 val); + + +/** + * \fn PHYSFS_sint64 PHYSFS_swapSBE64(PHYSFS_sint64 val) + * \brief Swap bigendian signed 64 to platform's native byte order. + * + * Take a 64-bit signed value in bigendian format and convert it to + * the platform's native byte order. + * + * \param val value to convert + * \return converted value. + * + * \warning Remember, PHYSFS_uint64 is only 32 bits on platforms without + * any sort of 64-bit support. + */ +__EXPORT__ PHYSFS_sint64 PHYSFS_swapSBE64(PHYSFS_sint64 val); + + +/** + * \fn PHYSFS_uint64 PHYSFS_swapUBE64(PHYSFS_uint64 val) + * \brief Swap bigendian unsigned 64 to platform's native byte order. + * + * Take a 64-bit unsigned value in bigendian format and convert it to + * the platform's native byte order. + * + * \param val value to convert + * \return converted value. + * + * \warning Remember, PHYSFS_uint64 is only 32 bits on platforms without + * any sort of 64-bit support. + */ +__EXPORT__ PHYSFS_uint64 PHYSFS_swapUBE64(PHYSFS_uint64 val); + + +/** + * \fn int PHYSFS_readSLE16(PHYSFS_File *file, PHYSFS_sint16 *val) + * \brief Read and convert a signed 16-bit littleendian value. + * + * Convenience function. Read a signed 16-bit littleendian value from a + * file and convert it to the platform's native byte order. + * + * \param file PhysicsFS file handle from which to read. + * \param val pointer to where value should be stored. + * \return zero on failure, non-zero on success. If successful, (*val) will + * store the result. On failure, you can find out what went wrong + * from PHYSFS_getLastError(). + */ +__EXPORT__ int PHYSFS_readSLE16(PHYSFS_File *file, PHYSFS_sint16 *val); + + +/** + * \fn int PHYSFS_readULE16(PHYSFS_File *file, PHYSFS_uint16 *val) + * \brief Read and convert an unsigned 16-bit littleendian value. + * + * Convenience function. Read an unsigned 16-bit littleendian value from a + * file and convert it to the platform's native byte order. + * + * \param file PhysicsFS file handle from which to read. + * \param val pointer to where value should be stored. + * \return zero on failure, non-zero on success. If successful, (*val) will + * store the result. On failure, you can find out what went wrong + * from PHYSFS_getLastError(). + * + */ +__EXPORT__ int PHYSFS_readULE16(PHYSFS_File *file, PHYSFS_uint16 *val); + + +/** + * \fn int PHYSFS_readSBE16(PHYSFS_File *file, PHYSFS_sint16 *val) + * \brief Read and convert a signed 16-bit bigendian value. + * + * Convenience function. Read a signed 16-bit bigendian value from a + * file and convert it to the platform's native byte order. + * + * \param file PhysicsFS file handle from which to read. + * \param val pointer to where value should be stored. + * \return zero on failure, non-zero on success. If successful, (*val) will + * store the result. On failure, you can find out what went wrong + * from PHYSFS_getLastError(). + */ +__EXPORT__ int PHYSFS_readSBE16(PHYSFS_File *file, PHYSFS_sint16 *val); + + +/** + * \fn int PHYSFS_readUBE16(PHYSFS_File *file, PHYSFS_uint16 *val) + * \brief Read and convert an unsigned 16-bit bigendian value. + * + * Convenience function. Read an unsigned 16-bit bigendian value from a + * file and convert it to the platform's native byte order. + * + * \param file PhysicsFS file handle from which to read. + * \param val pointer to where value should be stored. + * \return zero on failure, non-zero on success. If successful, (*val) will + * store the result. On failure, you can find out what went wrong + * from PHYSFS_getLastError(). + * + */ +__EXPORT__ int PHYSFS_readUBE16(PHYSFS_File *file, PHYSFS_uint16 *val); + + +/** + * \fn int PHYSFS_readSLE32(PHYSFS_File *file, PHYSFS_sint32 *val) + * \brief Read and convert a signed 32-bit littleendian value. + * + * Convenience function. Read a signed 32-bit littleendian value from a + * file and convert it to the platform's native byte order. + * + * \param file PhysicsFS file handle from which to read. + * \param val pointer to where value should be stored. + * \return zero on failure, non-zero on success. If successful, (*val) will + * store the result. On failure, you can find out what went wrong + * from PHYSFS_getLastError(). + */ +__EXPORT__ int PHYSFS_readSLE32(PHYSFS_File *file, PHYSFS_sint32 *val); + + +/** + * \fn int PHYSFS_readULE32(PHYSFS_File *file, PHYSFS_uint32 *val) + * \brief Read and convert an unsigned 32-bit littleendian value. + * + * Convenience function. Read an unsigned 32-bit littleendian value from a + * file and convert it to the platform's native byte order. + * + * \param file PhysicsFS file handle from which to read. + * \param val pointer to where value should be stored. + * \return zero on failure, non-zero on success. If successful, (*val) will + * store the result. On failure, you can find out what went wrong + * from PHYSFS_getLastError(). + * + */ +__EXPORT__ int PHYSFS_readULE32(PHYSFS_File *file, PHYSFS_uint32 *val); + + +/** + * \fn int PHYSFS_readSBE32(PHYSFS_File *file, PHYSFS_sint32 *val) + * \brief Read and convert a signed 32-bit bigendian value. + * + * Convenience function. Read a signed 32-bit bigendian value from a + * file and convert it to the platform's native byte order. + * + * \param file PhysicsFS file handle from which to read. + * \param val pointer to where value should be stored. + * \return zero on failure, non-zero on success. If successful, (*val) will + * store the result. On failure, you can find out what went wrong + * from PHYSFS_getLastError(). + */ +__EXPORT__ int PHYSFS_readSBE32(PHYSFS_File *file, PHYSFS_sint32 *val); + + +/** + * \fn int PHYSFS_readUBE32(PHYSFS_File *file, PHYSFS_uint32 *val) + * \brief Read and convert an unsigned 32-bit bigendian value. + * + * Convenience function. Read an unsigned 32-bit bigendian value from a + * file and convert it to the platform's native byte order. + * + * \param file PhysicsFS file handle from which to read. + * \param val pointer to where value should be stored. + * \return zero on failure, non-zero on success. If successful, (*val) will + * store the result. On failure, you can find out what went wrong + * from PHYSFS_getLastError(). + * + */ +__EXPORT__ int PHYSFS_readUBE32(PHYSFS_File *file, PHYSFS_uint32 *val); + + +/** + * \fn int PHYSFS_readSLE64(PHYSFS_File *file, PHYSFS_sint64 *val) + * \brief Read and convert a signed 64-bit littleendian value. + * + * Convenience function. Read a signed 64-bit littleendian value from a + * file and convert it to the platform's native byte order. + * + * \param file PhysicsFS file handle from which to read. + * \param val pointer to where value should be stored. + * \return zero on failure, non-zero on success. If successful, (*val) will + * store the result. On failure, you can find out what went wrong + * from PHYSFS_getLastError(). + * + * \warning Remember, PHYSFS_sint64 is only 32 bits on platforms without + * any sort of 64-bit support. + */ +__EXPORT__ int PHYSFS_readSLE64(PHYSFS_File *file, PHYSFS_sint64 *val); + + +/** + * \fn int PHYSFS_readULE64(PHYSFS_File *file, PHYSFS_uint64 *val) + * \brief Read and convert an unsigned 64-bit littleendian value. + * + * Convenience function. Read an unsigned 64-bit littleendian value from a + * file and convert it to the platform's native byte order. + * + * \param file PhysicsFS file handle from which to read. + * \param val pointer to where value should be stored. + * \return zero on failure, non-zero on success. If successful, (*val) will + * store the result. On failure, you can find out what went wrong + * from PHYSFS_getLastError(). + * + * \warning Remember, PHYSFS_uint64 is only 32 bits on platforms without + * any sort of 64-bit support. + */ +__EXPORT__ int PHYSFS_readULE64(PHYSFS_File *file, PHYSFS_uint64 *val); + + +/** + * \fn int PHYSFS_readSBE64(PHYSFS_File *file, PHYSFS_sint64 *val) + * \brief Read and convert a signed 64-bit bigendian value. + * + * Convenience function. Read a signed 64-bit bigendian value from a + * file and convert it to the platform's native byte order. + * + * \param file PhysicsFS file handle from which to read. + * \param val pointer to where value should be stored. + * \return zero on failure, non-zero on success. If successful, (*val) will + * store the result. On failure, you can find out what went wrong + * from PHYSFS_getLastError(). + * + * \warning Remember, PHYSFS_sint64 is only 32 bits on platforms without + * any sort of 64-bit support. + */ +__EXPORT__ int PHYSFS_readSBE64(PHYSFS_File *file, PHYSFS_sint64 *val); + + +/** + * \fn int PHYSFS_readUBE64(PHYSFS_File *file, PHYSFS_uint64 *val) + * \brief Read and convert an unsigned 64-bit bigendian value. + * + * Convenience function. Read an unsigned 64-bit bigendian value from a + * file and convert it to the platform's native byte order. + * + * \param file PhysicsFS file handle from which to read. + * \param val pointer to where value should be stored. + * \return zero on failure, non-zero on success. If successful, (*val) will + * store the result. On failure, you can find out what went wrong + * from PHYSFS_getLastError(). + * + * \warning Remember, PHYSFS_uint64 is only 32 bits on platforms without + * any sort of 64-bit support. + */ +__EXPORT__ int PHYSFS_readUBE64(PHYSFS_File *file, PHYSFS_uint64 *val); + + +/** + * \fn int PHYSFS_writeSLE16(PHYSFS_File *file, PHYSFS_sint16 val) + * \brief Convert and write a signed 16-bit littleendian value. + * + * Convenience function. Convert a signed 16-bit value from the platform's + * native byte order to littleendian and write it to a file. + * + * \param file PhysicsFS file handle to which to write. + * \param val Value to convert and write. + * \return zero on failure, non-zero on success. On failure, you can + * find out what went wrong from PHYSFS_getLastError(). + */ +__EXPORT__ int PHYSFS_writeSLE16(PHYSFS_File *file, PHYSFS_sint16 val); + + +/** + * \fn int PHYSFS_writeULE16(PHYSFS_File *file, PHYSFS_uint16 val) + * \brief Convert and write an unsigned 16-bit littleendian value. + * + * Convenience function. Convert an unsigned 16-bit value from the platform's + * native byte order to littleendian and write it to a file. + * + * \param file PhysicsFS file handle to which to write. + * \param val Value to convert and write. + * \return zero on failure, non-zero on success. On failure, you can + * find out what went wrong from PHYSFS_getLastError(). + */ +__EXPORT__ int PHYSFS_writeULE16(PHYSFS_File *file, PHYSFS_uint16 val); + + +/** + * \fn int PHYSFS_writeSBE16(PHYSFS_File *file, PHYSFS_sint16 val) + * \brief Convert and write a signed 16-bit bigendian value. + * + * Convenience function. Convert a signed 16-bit value from the platform's + * native byte order to bigendian and write it to a file. + * + * \param file PhysicsFS file handle to which to write. + * \param val Value to convert and write. + * \return zero on failure, non-zero on success. On failure, you can + * find out what went wrong from PHYSFS_getLastError(). + */ +__EXPORT__ int PHYSFS_writeSBE16(PHYSFS_File *file, PHYSFS_sint16 val); + + +/** + * \fn int PHYSFS_writeUBE16(PHYSFS_File *file, PHYSFS_uint16 val) + * \brief Convert and write an unsigned 16-bit bigendian value. + * + * Convenience function. Convert an unsigned 16-bit value from the platform's + * native byte order to bigendian and write it to a file. + * + * \param file PhysicsFS file handle to which to write. + * \param val Value to convert and write. + * \return zero on failure, non-zero on success. On failure, you can + * find out what went wrong from PHYSFS_getLastError(). + */ +__EXPORT__ int PHYSFS_writeUBE16(PHYSFS_File *file, PHYSFS_uint16 val); + + +/** + * \fn int PHYSFS_writeSLE32(PHYSFS_File *file, PHYSFS_sint32 val) + * \brief Convert and write a signed 32-bit littleendian value. + * + * Convenience function. Convert a signed 32-bit value from the platform's + * native byte order to littleendian and write it to a file. + * + * \param file PhysicsFS file handle to which to write. + * \param val Value to convert and write. + * \return zero on failure, non-zero on success. On failure, you can + * find out what went wrong from PHYSFS_getLastError(). + */ +__EXPORT__ int PHYSFS_writeSLE32(PHYSFS_File *file, PHYSFS_sint32 val); + + +/** + * \fn int PHYSFS_writeULE32(PHYSFS_File *file, PHYSFS_uint32 val) + * \brief Convert and write an unsigned 32-bit littleendian value. + * + * Convenience function. Convert an unsigned 32-bit value from the platform's + * native byte order to littleendian and write it to a file. + * + * \param file PhysicsFS file handle to which to write. + * \param val Value to convert and write. + * \return zero on failure, non-zero on success. On failure, you can + * find out what went wrong from PHYSFS_getLastError(). + */ +__EXPORT__ int PHYSFS_writeULE32(PHYSFS_File *file, PHYSFS_uint32 val); + + +/** + * \fn int PHYSFS_writeSBE32(PHYSFS_File *file, PHYSFS_sint32 val) + * \brief Convert and write a signed 32-bit bigendian value. + * + * Convenience function. Convert a signed 32-bit value from the platform's + * native byte order to bigendian and write it to a file. + * + * \param file PhysicsFS file handle to which to write. + * \param val Value to convert and write. + * \return zero on failure, non-zero on success. On failure, you can + * find out what went wrong from PHYSFS_getLastError(). + */ +__EXPORT__ int PHYSFS_writeSBE32(PHYSFS_File *file, PHYSFS_sint32 val); + + +/** + * \fn int PHYSFS_writeUBE32(PHYSFS_File *file, PHYSFS_uint32 val) + * \brief Convert and write an unsigned 32-bit bigendian value. + * + * Convenience function. Convert an unsigned 32-bit value from the platform's + * native byte order to bigendian and write it to a file. + * + * \param file PhysicsFS file handle to which to write. + * \param val Value to convert and write. + * \return zero on failure, non-zero on success. On failure, you can + * find out what went wrong from PHYSFS_getLastError(). + */ +__EXPORT__ int PHYSFS_writeUBE32(PHYSFS_File *file, PHYSFS_uint32 val); + + +/** + * \fn int PHYSFS_writeSLE64(PHYSFS_File *file, PHYSFS_sint64 val) + * \brief Convert and write a signed 64-bit littleendian value. + * + * Convenience function. Convert a signed 64-bit value from the platform's + * native byte order to littleendian and write it to a file. + * + * \param file PhysicsFS file handle to which to write. + * \param val Value to convert and write. + * \return zero on failure, non-zero on success. On failure, you can + * find out what went wrong from PHYSFS_getLastError(). + * + * \warning Remember, PHYSFS_uint64 is only 32 bits on platforms without + * any sort of 64-bit support. + */ +__EXPORT__ int PHYSFS_writeSLE64(PHYSFS_File *file, PHYSFS_sint64 val); + + +/** + * \fn int PHYSFS_writeULE64(PHYSFS_File *file, PHYSFS_uint64 val) + * \brief Convert and write an unsigned 64-bit littleendian value. + * + * Convenience function. Convert an unsigned 64-bit value from the platform's + * native byte order to littleendian and write it to a file. + * + * \param file PhysicsFS file handle to which to write. + * \param val Value to convert and write. + * \return zero on failure, non-zero on success. On failure, you can + * find out what went wrong from PHYSFS_getLastError(). + * + * \warning Remember, PHYSFS_uint64 is only 32 bits on platforms without + * any sort of 64-bit support. + */ +__EXPORT__ int PHYSFS_writeULE64(PHYSFS_File *file, PHYSFS_uint64 val); + + +/** + * \fn int PHYSFS_writeSBE64(PHYSFS_File *file, PHYSFS_sint64 val) + * \brief Convert and write a signed 64-bit bigending value. + * + * Convenience function. Convert a signed 64-bit value from the platform's + * native byte order to bigendian and write it to a file. + * + * \param file PhysicsFS file handle to which to write. + * \param val Value to convert and write. + * \return zero on failure, non-zero on success. On failure, you can + * find out what went wrong from PHYSFS_getLastError(). + * + * \warning Remember, PHYSFS_uint64 is only 32 bits on platforms without + * any sort of 64-bit support. + */ +__EXPORT__ int PHYSFS_writeSBE64(PHYSFS_File *file, PHYSFS_sint64 val); + + +/** + * \fn int PHYSFS_writeUBE64(PHYSFS_File *file, PHYSFS_uint64 val) + * \brief Convert and write an unsigned 64-bit bigendian value. + * + * Convenience function. Convert an unsigned 64-bit value from the platform's + * native byte order to bigendian and write it to a file. + * + * \param file PhysicsFS file handle to which to write. + * \param val Value to convert and write. + * \return zero on failure, non-zero on success. On failure, you can + * find out what went wrong from PHYSFS_getLastError(). + * + * \warning Remember, PHYSFS_uint64 is only 32 bits on platforms without + * any sort of 64-bit support. + */ +__EXPORT__ int PHYSFS_writeUBE64(PHYSFS_File *file, PHYSFS_uint64 val); + + +/* Everything above this line is part of the PhysicsFS 1.0 API. */ + +/** + * \fn int PHYSFS_isInit(void) + * \brief Determine if the PhysicsFS library is initialized. + * + * Once PHYSFS_init() returns successfully, this will return non-zero. + * Before a successful PHYSFS_init() and after PHYSFS_deinit() returns + * successfully, this will return zero. This function is safe to call at + * any time. + * + * \return non-zero if library is initialized, zero if library is not. + * + * \sa PHYSFS_init + * \sa PHYSFS_deinit + */ +__EXPORT__ int PHYSFS_isInit(void); + + +/** + * \fn int PHYSFS_symbolicLinksPermitted(void) + * \brief Determine if the symbolic links are permitted. + * + * This reports the setting from the last call to PHYSFS_permitSymbolicLinks(). + * If PHYSFS_permitSymbolicLinks() hasn't been called since the library was + * last initialized, symbolic links are implicitly disabled. + * + * \return non-zero if symlinks are permitted, zero if not. + * + * \sa PHYSFS_permitSymbolicLinks + */ +__EXPORT__ int PHYSFS_symbolicLinksPermitted(void); + + +/** + * \struct PHYSFS_Allocator + * \brief PhysicsFS allocation function pointers. + * + * (This is for limited, hardcore use. If you don't immediately see a need + * for it, you can probably ignore this forever.) + * + * You create one of these structures for use with PHYSFS_setAllocator. + * Allocators are assumed to be reentrant by the caller; please mutex + * accordingly. + * + * Allocations are always discussed in 64-bits, for future expansion...we're + * on the cusp of a 64-bit transition, and we'll probably be allocating 6 + * gigabytes like it's nothing sooner or later, and I don't want to change + * this again at that point. If you're on a 32-bit platform and have to + * downcast, it's okay to return NULL if the allocation is greater than + * 4 gigabytes, since you'd have to do so anyhow. + * + * \sa PHYSFS_setAllocator + */ +typedef struct PHYSFS_Allocator +{ + int (*Init)(void); /**< Initialize. Can be NULL. Zero on failure. */ + void (*Deinit)(void); /**< Deinitialize your allocator. Can be NULL. */ + void *(*Malloc)(PHYSFS_uint64); /**< Allocate like malloc(). */ + void *(*Realloc)(void *, PHYSFS_uint64); /**< Reallocate like realloc(). */ + void (*Free)(void *); /**< Free memory from Malloc or Realloc. */ +} PHYSFS_Allocator; + + +/** + * \fn int PHYSFS_setAllocator(const PHYSFS_Allocator *allocator) + * \brief Hook your own allocation routines into PhysicsFS. + * + * (This is for limited, hardcore use. If you don't immediately see a need + * for it, you can probably ignore this forever.) + * + * By default, PhysicsFS will use whatever is reasonable for a platform + * to manage dynamic memory (usually ANSI C malloc/realloc/calloc/free, but + * some platforms might use something else), but in some uncommon cases, the + * app might want more control over the library's memory management. This + * lets you redirect PhysicsFS to use your own allocation routines instead. + * You can only call this function before PHYSFS_init(); if the library is + * initialized, it'll reject your efforts to change the allocator mid-stream. + * You may call this function after PHYSFS_deinit() if you are willing to + * shut down the library and restart it with a new allocator; this is a safe + * and supported operation. The allocator remains intact between deinit/init + * calls. If you want to return to the platform's default allocator, pass a + * NULL in here. + * + * If you aren't immediately sure what to do with this function, you can + * safely ignore it altogether. + * + * \param allocator Structure containing your allocator's entry points. + * \return zero on failure, non-zero on success. This call only fails + * when used between PHYSFS_init() and PHYSFS_deinit() calls. + */ +__EXPORT__ int PHYSFS_setAllocator(const PHYSFS_Allocator *allocator); + + +/** + * \fn int PHYSFS_mount(const char *newDir, const char *mountPoint, int appendToPath) + * \brief Add an archive or directory to the search path. + * + * If this is a duplicate, the entry is not added again, even though the + * function succeeds. You may not add the same archive to two different + * mountpoints: duplicate checking is done against the archive and not the + * mountpoint. + * + * When you mount an archive, it is added to a virtual file system...all files + * in all of the archives are interpolated into a single hierachical file + * tree. Two archives mounted at the same place (or an archive with files + * overlapping another mountpoint) may have overlapping files: in such a case, + * the file earliest in the search path is selected, and the other files are + * inaccessible to the application. This allows archives to be used to + * override previous revisions; you can use the mounting mechanism to place + * archives at a specific point in the file tree and prevent overlap; this + * is useful for downloadable mods that might trample over application data + * or each other, for example. + * + * The mountpoint does not need to exist prior to mounting, which is different + * than those familiar with the Unix concept of "mounting" may not expect. + * As well, more than one archive can be mounted to the same mountpoint, or + * mountpoints and archive contents can overlap...the interpolation mechanism + * still functions as usual. + * + * \param newDir directory or archive to add to the path, in + * platform-dependent notation. + * \param mountPoint Location in the interpolated tree that this archive + * will be "mounted", in platform-independent notation. + * NULL or "" is equivalent to "/". + * \param appendToPath nonzero to append to search path, zero to prepend. + * \return nonzero if added to path, zero on failure (bogus archive, dir + * missing, etc). Specifics of the error can be + * gleaned from PHYSFS_getLastError(). + * + * \sa PHYSFS_removeFromSearchPath + * \sa PHYSFS_getSearchPath + * \sa PHYSFS_getMountPoint + */ +__EXPORT__ int PHYSFS_mount(const char *newDir, const char *mountPoint, int appendToPath); + +/** + * \fn int PHYSFS_getMountPoint(const char *dir) + * \brief Determine a mounted archive's mountpoint. + * + * You give this function the name of an archive or dir you successfully + * added to the search path, and it reports the location in the interpolated + * tree where it is mounted. Files mounted with a NULL mountpoint or through + * PHYSFS_addToSearchPath() will report "/". The return value is READ ONLY + * and valid until the archive is removed from the search path. + * + * \param dir directory or archive previously added to the path, in + * platform-dependent notation. This must match the string + * used when adding, even if your string would also reference + * the same file with a different string of characters. + * \return READ-ONLY string of mount point if added to path, NULL on failure + * (bogus archive, etc) Specifics of the error can be gleaned from + * PHYSFS_getLastError(). + * + * \sa PHYSFS_removeFromSearchPath + * \sa PHYSFS_getSearchPath + * \sa PHYSFS_getMountPoint + */ +__EXPORT__ const char *PHYSFS_getMountPoint(const char *dir); + + +/** + * \typedef PHYSFS_StringCallback + * \brief Function signature for callbacks that report strings. + * + * These are used to report a list of strings to an original caller, one + * string per callback. All strings are UTF-8 encoded. Functions should not + * try to modify or free the string's memory. + * + * These callbacks are used, starting in PhysicsFS 1.1, as an alternative to + * functions that would return lists that need to be cleaned up with + * PHYSFS_freeList(). The callback means that the library doesn't need to + * allocate an entire list and all the strings up front. + * + * Be aware that promises data ordering in the list versions are not + * necessarily so in the callback versions. Check the documentation on + * specific APIs, but strings may not be sorted as you expect. + * + * \param data User-defined data pointer, passed through from the API + * that eventually called the callback. + * \param str The string data about which the callback is meant to inform. + * + * \sa PHYSFS_getCdRomDirsCallback + * \sa PHYSFS_getSearchPathCallback + */ +typedef void (*PHYSFS_StringCallback)(void *data, const char *str); + + +/** + * \typedef PHYSFS_EnumFilesCallback + * \brief Function signature for callbacks that enumerate files. + * + * These are used to report a list of directory entries to an original caller, + * one file/dir/symlink per callback. All strings are UTF-8 encoded. + * Functions should not try to modify or free any string's memory. + * + * These callbacks are used, starting in PhysicsFS 1.1, as an alternative to + * functions that would return lists that need to be cleaned up with + * PHYSFS_freeList(). The callback means that the library doesn't need to + * allocate an entire list and all the strings up front. + * + * Be aware that promises data ordering in the list versions are not + * necessarily so in the callback versions. Check the documentation on + * specific APIs, but strings may not be sorted as you expect. + * + * \param data User-defined data pointer, passed through from the API + * that eventually called the callback. + * \param origdir A string containing the full path, in platform-independent + * notation, of the directory containing this file. In most + * cases, this is the directory on which you requested + * enumeration, passed in the callback for your convenience. + * \param fname The filename that is being enumerated. It may not be in + * alphabetical order compared to other callbacks that have + * fired, and it will not contain the full path. You can + * recreate the fullpath with $origdir/$fname ... The file + * can be a subdirectory, a file, a symlink, etc. + * + * \sa PHYSFS_enumerateFilesCallback + */ +typedef void (*PHYSFS_EnumFilesCallback)(void *data, const char *origdir, + const char *fname); + + +/** + * \fn void PHYSFS_getCdRomDirsCallback(PHYSFS_StringCallback c, void *d) + * \brief Enumerate CD-ROM directories, using an application-defined callback. + * + * Internally, PHYSFS_getCdRomDirs() just calls this function and then builds + * a list before returning to the application, so functionality is identical + * except for how the information is represented to the application. + * + * Unlike PHYSFS_getCdRomDirs(), this function does not return an array. + * Rather, it calls a function specified by the application once per + * detected disc: + * + * \code + * + * static void foundDisc(void *data, const char *cddir) + * { + * printf("cdrom dir [%s] is available.\n", cddir); + * } + * + * // ... + * PHYSFS_getCdRomDirsCallback(foundDisc, NULL); + * \endcode + * + * This call may block while drives spin up. Be forewarned. + * + * \param c Callback function to notify about detected drives. + * \param d Application-defined data passed to callback. Can be NULL. + * + * \sa PHYSFS_StringCallback + * \sa PHYSFS_getCdRomDirs + */ +__EXPORT__ void PHYSFS_getCdRomDirsCallback(PHYSFS_StringCallback c, void *d); + + +/** + * \fn void PHYSFS_getSearchPathCallback(PHYSFS_StringCallback c, void *d) + * \brief Enumerate the search path, using an application-defined callback. + * + * Internally, PHYSFS_getSearchPath() just calls this function and then builds + * a list before returning to the application, so functionality is identical + * except for how the information is represented to the application. + * + * Unlike PHYSFS_getSearchPath(), this function does not return an array. + * Rather, it calls a function specified by the application once per + * element of the search path: + * + * \code + * + * static void printSearchPath(void *data, const char *pathItem) + * { + * printf("[%s] is in the search path.\n", pathItem); + * } + * + * // ... + * PHYSFS_getSearchPathCallback(printSearchPath, NULL); + * \endcode + * + * Elements of the search path are reported in order search priority, so the + * first archive/dir that would be examined when looking for a file is the + * first element passed through the callback. + * + * \param c Callback function to notify about search path elements. + * \param d Application-defined data passed to callback. Can be NULL. + * + * \sa PHYSFS_StringCallback + * \sa PHYSFS_getSearchPath + */ +__EXPORT__ void PHYSFS_getSearchPathCallback(PHYSFS_StringCallback c, void *d); + + +/** + * \fn void PHYSFS_enumerateFilesCallback(const char *dir, PHYSFS_EnumFilesCallback c, void *d) + * \brief Get a file listing of a search path's directory, using an application-defined callback. + * + * Internally, PHYSFS_enumerateFiles() just calls this function and then builds + * a list before returning to the application, so functionality is identical + * except for how the information is represented to the application. + * + * Unlike PHYSFS_enumerateFiles(), this function does not return an array. + * Rather, it calls a function specified by the application once per + * element of the search path: + * + * \code + * + * static void printDir(void *data, const char *origdir, const char *fname) + * { + * printf(" * We've got [%s] in [%s].\n", fname, origdir); + * } + * + * // ... + * PHYSFS_enumerateFilesCallback("/some/path", printDir, NULL); + * \endcode + * + * Items sent to the callback are not guaranteed to be in any order whatsoever. + * There is no sorting done at this level, and if you need that, you should + * probably use PHYSFS_enumerateFiles() instead, which guarantees + * alphabetical sorting. This form reports whatever is discovered in each + * archive before moving on to the next. Even within one archive, we can't + * guarantee what order it will discover data. <em>Any sorting you find in + * these callbacks is just pure luck. Do not rely on it.</em> + * + * \param dir Directory, in platform-independent notation, to enumerate. + * \param c Callback function to notify about search path elements. + * \param d Application-defined data passed to callback. Can be NULL. + * + * \sa PHYSFS_EnumFilesCallback + * \sa PHYSFS_enumerateFiles + */ +__EXPORT__ void PHYSFS_enumerateFilesCallback(const char *dir, + PHYSFS_EnumFilesCallback c, + void *d); + +/** + * \fn void PHYSFS_utf8FromUcs4(const PHYSFS_uint32 *src, char *dst, PHYSFS_uint64 len) + * \brief Convert a UCS-4 string to a UTF-8 string. + * + * UCS-4 strings are 32-bits per character: \c wchar_t on Unix. + * + * To ensure that the destination buffer is large enough for the conversion, + * please allocate a buffer that is the same size as the source buffer. UTF-8 + * never uses more than 32-bits per character, so while it may shrink a UCS-4 + * string, it will never expand it. + * + * Strings that don't fit in the destination buffer will be truncated, but + * will always be null-terminated and never have an incomplete UTF-8 + * sequence at the end. + * + * \param src Null-terminated source string in UCS-4 format. + * \param dst Buffer to store converted UTF-8 string. + * \param len Size, in bytes, of destination buffer. + */ +__EXPORT__ void PHYSFS_utf8FromUcs4(const PHYSFS_uint32 *src, char *dst, + PHYSFS_uint64 len); + +/** + * \fn void PHYSFS_utf8ToUcs4(const char *src, PHYSFS_uint32 *dst, PHYSFS_uint64 len) + * \brief Convert a UTF-8 string to a UCS-4 string. + * + * UCS-4 strings are 32-bits per character: \c wchar_t on Unix. + * + * To ensure that the destination buffer is large enough for the conversion, + * please allocate a buffer that is four times the size of the source buffer. + * UTF-8 uses from one to four bytes per character, but UCS-4 always uses + * four, so an entirely low-ASCII string will quadruple in size! + * + * Strings that don't fit in the destination buffer will be truncated, but + * will always be null-terminated and never have an incomplete UCS-4 + * sequence at the end. + * + * \param src Null-terminated source string in UTF-8 format. + * \param dst Buffer to store converted UCS-4 string. + * \param len Size, in bytes, of destination buffer. + */ +__EXPORT__ void PHYSFS_utf8ToUcs4(const char *src, PHYSFS_uint32 *dst, + PHYSFS_uint64 len); + +/** + * \fn void PHYSFS_utf8FromUcs2(const PHYSFS_uint16 *src, char *dst, PHYSFS_uint64 len) + * \brief Convert a UCS-2 string to a UTF-8 string. + * + * UCS-2 strings are 16-bits per character: \c TCHAR on Windows, when building + * with Unicode support. + * + * To ensure that the destination buffer is large enough for the conversion, + * please allocate a buffer that is double the size of the source buffer. + * UTF-8 never uses more than 32-bits per character, so while it may shrink + * a UCS-2 string, it may also expand it. + * + * Strings that don't fit in the destination buffer will be truncated, but + * will always be null-terminated and never have an incomplete UTF-8 + * sequence at the end. + * + * Please note that UCS-2 is not UTF-16; we do not support the "surrogate" + * values at this time. + * + * \param src Null-terminated source string in UCS-2 format. + * \param dst Buffer to store converted UTF-8 string. + * \param len Size, in bytes, of destination buffer. + */ +__EXPORT__ void PHYSFS_utf8FromUcs2(const PHYSFS_uint16 *src, char *dst, + PHYSFS_uint64 len); + +/** + * \fn PHYSFS_utf8ToUcs2(const char *src, PHYSFS_uint16 *dst, PHYSFS_uint64 len) + * \brief Convert a UTF-8 string to a UCS-2 string. + * + * UCS-2 strings are 16-bits per character: \c TCHAR on Windows, when building + * with Unicode support. + * + * To ensure that the destination buffer is large enough for the conversion, + * please allocate a buffer that is double the size of the source buffer. + * UTF-8 uses from one to four bytes per character, but UCS-2 always uses + * two, so an entirely low-ASCII string will double in size! + * + * Strings that don't fit in the destination buffer will be truncated, but + * will always be null-terminated and never have an incomplete UCS-2 + * sequence at the end. + * + * Please note that UCS-2 is not UTF-16; we do not support the "surrogate" + * values at this time. + * + * \param src Null-terminated source string in UTF-8 format. + * \param dst Buffer to store converted UCS-2 string. + * \param len Size, in bytes, of destination buffer. + */ +__EXPORT__ void PHYSFS_utf8ToUcs2(const char *src, PHYSFS_uint16 *dst, + PHYSFS_uint64 len); + +/** + * \fn void PHYSFS_utf8FromLatin1(const char *src, char *dst, PHYSFS_uint64 len) + * \brief Convert a UTF-8 string to a Latin1 string. + * + * Latin1 strings are 8-bits per character: a popular "high ASCII" + * encoding. + * + * To ensure that the destination buffer is large enough for the conversion, + * please allocate a buffer that is double the size of the source buffer. + * UTF-8 expands latin1 codepoints over 127 from 1 to 2 bytes, so the string + * may grow in some cases. + * + * Strings that don't fit in the destination buffer will be truncated, but + * will always be null-terminated and never have an incomplete UTF-8 + * sequence at the end. + * + * Please note that we do not supply a UTF-8 to Latin1 converter, since Latin1 + * can't express most Unicode codepoints. It's a legacy encoding; you should + * be converting away from it at all times. + * + * \param src Null-terminated source string in Latin1 format. + * \param dst Buffer to store converted UTF-8 string. + * \param len Size, in bytes, of destination buffer. + */ +__EXPORT__ void PHYSFS_utf8FromLatin1(const char *src, char *dst, + PHYSFS_uint64 len); + +/* Everything above this line is part of the PhysicsFS 2.0 API. */ + + +#ifdef __cplusplus +} +#endif + +#endif /* !defined _INCLUDE_PHYSFS_H_ */ + +/* end of physfs.h ... */ + diff --git a/Lib/Include/pstdbool.h b/Lib/Include/pstdbool.h new file mode 100644 index 0000000..a420e4d --- /dev/null +++ b/Lib/Include/pstdbool.h @@ -0,0 +1,60 @@ +/* + pstdbool.h + Author: Chris Ertel <crertel@762studios.com> + + Purpose: <stdbool.h> replacement for data types. NOT C99 COMPLIANT YET. + + Notes: Macros were derived from spec at ( http://pubs.opengroup.org/onlinepubs/007904875/basedefs/stdbool.h.html ). + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. +*/ + +#ifndef _PSTDBOOL_H +#define _PSTDBOOL_H + +/* + To make this file a no-op, simply do #define PSTDBOOL_OK. On platforms that have <stdbool.h>, + best efforts are made to include them. +*/ + +/* If the user is calling this from a C++ compiler, they probably don't need to be using this. */ +#ifndef __cplusplus + + +#if !defined(PSTDBOOL_OK) && __STDC__ && (__STDC_VERSION__ >= 199901L) + + /* Compiler reports C99 available, so just use <stdbool.h> */ + #include <stdbool.h> + +#elif !defined(PSTDBOOL_OK) && (defined(_MSC_VER) || (defined(__SUNPRO_C) && !defined(_STDC_C99))) + /* Visual Studio on Windows */ + /* SunC in C90 mode gives an error if stdbool.h is included */ + #undef true + #undef false + #undef bool + + /* SunC 12.3 treats _Bool as a keyword, not a typedef, even in C90 mode */ + #if !defined(__SUNPRO_C) + typedef int _Bool; + #endif + + #define bool _Bool + #define true (1) + #define false (0) + #define __bool_true_false_are_defined 1 + +#elif !defined(PSTDBOOL_OK) && (defined(__GNUC__) || defined(__SUNPRO_C)) + + /* Definitely provided by the compiler */ + #include <stdbool.h> + +#endif + +#endif + +#endif + diff --git a/Lib/Include/rapidxml/rapidxml.hpp b/Lib/Include/rapidxml/rapidxml.hpp new file mode 100644 index 0000000..9a2653b --- /dev/null +++ b/Lib/Include/rapidxml/rapidxml.hpp @@ -0,0 +1,2774 @@ +#ifndef RAPIDXML_HPP_INCLUDED +#define RAPIDXML_HPP_INCLUDED + +// Copyright (C) 2006, 2009 Marcin Kalicinski +// Version 1.13 +// Revision $DateTime: 2009/05/13 01:46:17 $ +//! \file rapidxml.hpp This file contains rapidxml parser and DOM implementation + +// If standard library is disabled, user must provide implementations of required functions and typedefs +#if !defined(RAPIDXML_NO_STDLIB) + #include <cstdlib> // For std::size_t + #include <cassert> // For assert + #include <new> // For placement new +#endif + +// On MSVC, disable "conditional expression is constant" warning (level 4). +// This warning is almost impossible to avoid with certain types of templated code +#ifdef _MSC_VER + #pragma warning(push) + #pragma warning(disable:4127) // Conditional expression is constant +#endif + +/////////////////////////////////////////////////////////////////////////// +// RAPIDXML_PARSE_ERROR + +#if defined(RAPIDXML_NO_EXCEPTIONS) + +#define RAPIDXML_PARSE_ERROR(what, where, arg) { parse_error_handler(what, where, arg); } + +namespace rapidxml +{ + //! When exceptions are disabled by defining RAPIDXML_NO_EXCEPTIONS, + //! this function is called to notify user about the error. + //! It must be defined by the user. + //! + //! A very simple definition might look like that: + //! <pre> + //! void %rapidxml::%parse_error_handler(const char *what, void *where) + //! { + //! std::cout << "Parse error: " << what << "\n"; + //! std::abort(); + //! } + //! </pre> + //! \param what Human readable description of the error. + //! \param where Pointer to character data where error was detected. + void parse_error_handler(const char *what, void *where, void* arg); +} + +#else + +#include <exception> // For std::exception + +#define RAPIDXML_PARSE_ERROR(what, where, arg) throw parse_error(what, where) + +namespace rapidxml +{ + + //! Parse error exception. + //! This exception is thrown by the parser when an error occurs. + //! Use what() function to get human-readable error message. + //! Use where() function to get a pointer to position within source text where error was detected. + //! <br><br> + //! If throwing exceptions by the parser is undesirable, + //! it can be disabled by defining RAPIDXML_NO_EXCEPTIONS macro before rapidxml.hpp is included. + //! This will cause the parser to call rapidxml::parse_error_handler() function instead of throwing an exception. + //! This function must be defined by the user. + //! <br><br> + //! This class derives from <code>std::exception</code> class. + class parse_error: public std::exception + { + + public: + + //! Constructs parse error + parse_error(const char *what, void *where) + : m_what(what) + , m_where(where) + { + } + + //! Gets human readable description of error. + //! \return Pointer to null terminated description of the error. + virtual const char *what() const throw() + { + return m_what; + } + + //! Gets pointer to character data where error happened. + //! Ch should be the same as char type of xml_document that produced the error. + //! \return Pointer to location within the parsed string where error occured. + template<class Ch> + Ch *where() const + { + return reinterpret_cast<Ch *>(m_where); + } + + private: + + const char *m_what; + void *m_where; + + }; +} + +#endif + +/////////////////////////////////////////////////////////////////////////// +// Pool sizes + +#ifndef RAPIDXML_STATIC_POOL_SIZE + // Size of static memory block of memory_pool. + // Define RAPIDXML_STATIC_POOL_SIZE before including rapidxml.hpp if you want to override the default value. + // No dynamic memory allocations are performed by memory_pool until static memory is exhausted. + #define RAPIDXML_STATIC_POOL_SIZE (64 * 1024) +#endif + +#ifndef RAPIDXML_DYNAMIC_POOL_SIZE + // Size of dynamic memory block of memory_pool. + // Define RAPIDXML_DYNAMIC_POOL_SIZE before including rapidxml.hpp if you want to override the default value. + // After the static block is exhausted, dynamic blocks with approximately this size are allocated by memory_pool. + #define RAPIDXML_DYNAMIC_POOL_SIZE (64 * 1024) +#endif + +#ifndef RAPIDXML_ALIGNMENT + // Memory allocation alignment. + // Define RAPIDXML_ALIGNMENT before including rapidxml.hpp if you want to override the default value, which is the size of pointer. + // All memory allocations for nodes, attributes and strings will be aligned to this value. + // This must be a power of 2 and at least 1, otherwise memory_pool will not work. + #define RAPIDXML_ALIGNMENT sizeof(void *) +#endif + +namespace rapidxml +{ + // Forward declarations + template<class Ch> class xml_node; + template<class Ch> class xml_attribute; + template<class Ch> class xml_document; + + //! Enumeration listing all node types produced by the parser. + //! Use xml_node::type() function to query node type. + enum node_type + { + node_document, //!< A document node. Name and value are empty. + node_element, //!< An element node. Name contains element name. Value contains text of first data node. + node_data, //!< A data node. Name is empty. Value contains data text. + node_cdata, //!< A CDATA node. Name is empty. Value contains data text. + node_comment, //!< A comment node. Name is empty. Value contains comment text. + node_declaration, //!< A declaration node. Name and value are empty. Declaration parameters (version, encoding and standalone) are in node attributes. + node_doctype, //!< A DOCTYPE node. Name is empty. Value contains DOCTYPE text. + node_pi, //!< A PI node. Name contains target. Value contains instructions. + + node_empty //!< An empty node. This is used to signal (internally) that parsing should not return a node. Value contains empty string. + }; + + /////////////////////////////////////////////////////////////////////// + // Parsing flags + + //! Parse flag instructing the parser to not create data nodes. + //! Text of first data node will still be placed in value of parent element, unless rapidxml::parse_no_element_values flag is also specified. + //! Can be combined with other flags by use of | operator. + //! <br><br> + //! See xml_document::parse() function. + const int parse_no_data_nodes = 0x1; + + //! Parse flag instructing the parser to not use text of first data node as a value of parent element. + //! Can be combined with other flags by use of | operator. + //! Note that child data nodes of element node take precendence over its value when printing. + //! That is, if element has one or more child data nodes <em>and</em> a value, the value will be ignored. + //! Use rapidxml::parse_no_data_nodes flag to prevent creation of data nodes if you want to manipulate data using values of elements. + //! <br><br> + //! See xml_document::parse() function. + const int parse_no_element_values = 0x2; + + //! Parse flag instructing the parser to not place zero terminators after strings in the source text. + //! By default zero terminators are placed, modifying source text. + //! Can be combined with other flags by use of | operator. + //! <br><br> + //! See xml_document::parse() function. + const int parse_no_string_terminators = 0x4; + + //! Parse flag instructing the parser to not translate entities in the source text. + //! By default entities are translated, modifying source text. + //! Can be combined with other flags by use of | operator. + //! <br><br> + //! See xml_document::parse() function. + const int parse_no_entity_translation = 0x8; + + //! Parse flag instructing the parser to disable UTF-8 handling and assume plain 8 bit characters. + //! By default, UTF-8 handling is enabled. + //! Can be combined with other flags by use of | operator. + //! <br><br> + //! See xml_document::parse() function. + const int parse_no_utf8 = 0x10; + + //! Parse flag instructing the parser to create XML declaration node. + //! By default, declaration node is not created. + //! Can be combined with other flags by use of | operator. + //! <br><br> + //! See xml_document::parse() function. + const int parse_declaration_node = 0x20; + + //! Parse flag instructing the parser to create comments nodes. + //! By default, comment nodes are not created. + //! Can be combined with other flags by use of | operator. + //! <br><br> + //! See xml_document::parse() function. + const int parse_comment_nodes = 0x40; + + //! Parse flag instructing the parser to create DOCTYPE node. + //! By default, doctype node is not created. + //! Although W3C specification allows at most one DOCTYPE node, RapidXml will silently accept documents with more than one. + //! Can be combined with other flags by use of | operator. + //! <br><br> + //! See xml_document::parse() function. + const int parse_doctype_node = 0x80; + + //! Parse flag instructing the parser to create PI nodes. + //! By default, PI nodes are not created. + //! Can be combined with other flags by use of | operator. + //! <br><br> + //! See xml_document::parse() function. + const int parse_pi_nodes = 0x100; + + //! Parse flag instructing the parser to validate closing tag names. + //! If not set, name inside closing tag is irrelevant to the parser. + //! By default, closing tags are not validated. + //! Can be combined with other flags by use of | operator. + //! <br><br> + //! See xml_document::parse() function. + const int parse_validate_closing_tags = 0x200; + + //! Parse flag instructing the parser to trim all leading and trailing whitespace of data nodes. + //! By default, whitespace is not trimmed. + //! This flag does not cause the parser to modify source text. + //! Can be combined with other flags by use of | operator. + //! <br><br> + //! See xml_document::parse() function. + const int parse_trim_whitespace = 0x400; + + //! Parse flag instructing the parser to condense all whitespace runs of data nodes to a single space character. + //! Trimming of leading and trailing whitespace of data is controlled by rapidxml::parse_trim_whitespace flag. + //! By default, whitespace is not normalized. + //! If this flag is specified, source text will be modified. + //! Can be combined with other flags by use of | operator. + //! <br><br> + //! See xml_document::parse() function. + const int parse_normalize_whitespace = 0x800; + + // Compound flags + + //! Parse flags which represent default behaviour of the parser. + //! This is always equal to 0, so that all other flags can be simply ored together. + //! Normally there is no need to inconveniently disable flags by anding with their negated (~) values. + //! This also means that meaning of each flag is a <i>negation</i> of the default setting. + //! For example, if flag name is rapidxml::parse_no_utf8, it means that utf-8 is <i>enabled</i> by default, + //! and using the flag will disable it. + //! <br><br> + //! See xml_document::parse() function. + const int parse_default = 0; + + //! A combination of parse flags that forbids any modifications of the source text. + //! This also results in faster parsing. However, note that the following will occur: + //! <ul> + //! <li>names and values of nodes will not be zero terminated, you have to use xml_base::name_size() and xml_base::value_size() functions to determine where name and value ends</li> + //! <li>entities will not be translated</li> + //! <li>whitespace will not be normalized</li> + //! </ul> + //! See xml_document::parse() function. + const int parse_non_destructive = parse_no_string_terminators | parse_no_entity_translation; + + //! A combination of parse flags resulting in fastest possible parsing, without sacrificing important data. + //! <br><br> + //! See xml_document::parse() function. + const int parse_fastest = parse_non_destructive | parse_no_data_nodes; + + //! A combination of parse flags resulting in largest amount of data being extracted. + //! This usually results in slowest parsing. + //! <br><br> + //! See xml_document::parse() function. + const int parse_full = parse_declaration_node | parse_comment_nodes | parse_doctype_node | parse_pi_nodes | parse_validate_closing_tags; + + /////////////////////////////////////////////////////////////////////// + // Internals + + //! \cond internal + namespace internal + { + + // Struct that contains lookup tables for the parser + // It must be a template to allow correct linking (because it has static data members, which are defined in a header file). + template<int Dummy> + struct lookup_tables + { + static const unsigned char lookup_whitespace[256]; // Whitespace table + static const unsigned char lookup_node_name[256]; // Node name table + static const unsigned char lookup_text[256]; // Text table + static const unsigned char lookup_text_pure_no_ws[256]; // Text table + static const unsigned char lookup_text_pure_with_ws[256]; // Text table + static const unsigned char lookup_attribute_name[256]; // Attribute name table + static const unsigned char lookup_attribute_data_1[256]; // Attribute data table with single quote + static const unsigned char lookup_attribute_data_1_pure[256]; // Attribute data table with single quote + static const unsigned char lookup_attribute_data_2[256]; // Attribute data table with double quotes + static const unsigned char lookup_attribute_data_2_pure[256]; // Attribute data table with double quotes + static const unsigned char lookup_digits[256]; // Digits + static const unsigned char lookup_upcase[256]; // To uppercase conversion table for ASCII characters + }; + + // Find length of the string + template<class Ch> + inline std::size_t measure(const Ch *p) + { + const Ch *tmp = p; + while (*tmp) + ++tmp; + return tmp - p; + } + + // Compare strings for equality + template<class Ch> + inline bool compare(const Ch *p1, std::size_t size1, const Ch *p2, std::size_t size2, bool case_sensitive) + { + if (size1 != size2) + return false; + if (case_sensitive) + { + for (const Ch *end = p1 + size1; p1 < end; ++p1, ++p2) + if (*p1 != *p2) + return false; + } + else + { + for (const Ch *end = p1 + size1; p1 < end; ++p1, ++p2) + if (lookup_tables<0>::lookup_upcase[static_cast<unsigned char>(*p1)] != lookup_tables<0>::lookup_upcase[static_cast<unsigned char>(*p2)]) + return false; + } + return true; + } + } + //! \endcond + + /////////////////////////////////////////////////////////////////////// + // Memory pool + + //! This class is used by the parser to create new nodes and attributes, without overheads of dynamic memory allocation. + //! In most cases, you will not need to use this class directly. + //! However, if you need to create nodes manually or modify names/values of nodes, + //! you are encouraged to use memory_pool of relevant xml_document to allocate the memory. + //! Not only is this faster than allocating them by using <code>new</code> operator, + //! but also their lifetime will be tied to the lifetime of document, + //! possibly simplyfing memory management. + //! <br><br> + //! Call allocate_node() or allocate_attribute() functions to obtain new nodes or attributes from the pool. + //! You can also call allocate_string() function to allocate strings. + //! Such strings can then be used as names or values of nodes without worrying about their lifetime. + //! Note that there is no <code>free()</code> function -- all allocations are freed at once when clear() function is called, + //! or when the pool is destroyed. + //! <br><br> + //! It is also possible to create a standalone memory_pool, and use it + //! to allocate nodes, whose lifetime will not be tied to any document. + //! <br><br> + //! Pool maintains <code>RAPIDXML_STATIC_POOL_SIZE</code> bytes of statically allocated memory. + //! Until static memory is exhausted, no dynamic memory allocations are done. + //! When static memory is exhausted, pool allocates additional blocks of memory of size <code>RAPIDXML_DYNAMIC_POOL_SIZE</code> each, + //! by using global <code>new[]</code> and <code>delete[]</code> operators. + //! This behaviour can be changed by setting custom allocation routines. + //! Use set_allocator() function to set them. + //! <br><br> + //! Allocations for nodes, attributes and strings are aligned at <code>RAPIDXML_ALIGNMENT</code> bytes. + //! This value defaults to the size of pointer on target architecture. + //! <br><br> + //! To obtain absolutely top performance from the parser, + //! it is important that all nodes are allocated from a single, contiguous block of memory. + //! Otherwise, cache misses when jumping between two (or more) disjoint blocks of memory can slow down parsing quite considerably. + //! If required, you can tweak <code>RAPIDXML_STATIC_POOL_SIZE</code>, <code>RAPIDXML_DYNAMIC_POOL_SIZE</code> and <code>RAPIDXML_ALIGNMENT</code> + //! to obtain best wasted memory to performance compromise. + //! To do it, define their values before rapidxml.hpp file is included. + //! \param Ch Character type of created nodes. + template<class Ch = char> + class memory_pool + { + + public: + + //! \cond internal + typedef void *(alloc_func)(std::size_t); // Type of user-defined function used to allocate memory + typedef void (free_func)(void *); // Type of user-defined function used to free memory + //! \endcond + + //! Constructs empty pool with default allocator functions. + memory_pool(void *error_arg) + : m_alloc_func(0) + , m_free_func(0) + , m_error_arg(error_arg) + { + init(); + } + + //! Destroys pool and frees all the memory. + //! This causes memory occupied by nodes allocated by the pool to be freed. + //! Nodes allocated from the pool are no longer valid. + ~memory_pool() + { + clear(); + } + + //! Allocates a new node from the pool, and optionally assigns name and value to it. + //! If the allocation request cannot be accomodated, this function will throw <code>std::bad_alloc</code>. + //! If exceptions are disabled by defining RAPIDXML_NO_EXCEPTIONS, this function + //! will call rapidxml::parse_error_handler() function. + //! \param type Type of node to create. + //! \param name Name to assign to the node, or 0 to assign no name. + //! \param value Value to assign to the node, or 0 to assign no value. + //! \param name_size Size of name to assign, or 0 to automatically calculate size from name string. + //! \param value_size Size of value to assign, or 0 to automatically calculate size from value string. + //! \return Pointer to allocated node. This pointer will never be NULL. + xml_node<Ch> *allocate_node(node_type type, + const Ch *name = 0, const Ch *value = 0, + std::size_t name_size = 0, std::size_t value_size = 0) + { + void *memory = allocate_aligned(sizeof(xml_node<Ch>)); + + if (memory == NULL) + return NULL; + + xml_node<Ch> *node = new(memory) xml_node<Ch>(type); + if (name) + { + if (name_size > 0) + node->name(name, name_size); + else + node->name(name); + } + if (value) + { + if (value_size > 0) + node->value(value, value_size); + else + node->value(value); + } + return node; + } + + //! Allocates a new attribute from the pool, and optionally assigns name and value to it. + //! If the allocation request cannot be accomodated, this function will throw <code>std::bad_alloc</code>. + //! If exceptions are disabled by defining RAPIDXML_NO_EXCEPTIONS, this function + //! will call rapidxml::parse_error_handler() function. + //! \param name Name to assign to the attribute, or 0 to assign no name. + //! \param value Value to assign to the attribute, or 0 to assign no value. + //! \param name_size Size of name to assign, or 0 to automatically calculate size from name string. + //! \param value_size Size of value to assign, or 0 to automatically calculate size from value string. + //! \return Pointer to allocated attribute. This pointer will never be NULL. + xml_attribute<Ch> *allocate_attribute(const Ch *name = 0, const Ch *value = 0, + std::size_t name_size = 0, std::size_t value_size = 0) + { + void *memory = allocate_aligned(sizeof(xml_attribute<Ch>)); + + if (memory == NULL) + return NULL; + + xml_attribute<Ch> *attribute = new(memory) xml_attribute<Ch>; + if (name) + { + if (name_size > 0) + attribute->name(name, name_size); + else + attribute->name(name); + } + if (value) + { + if (value_size > 0) + attribute->value(value, value_size); + else + attribute->value(value); + } + return attribute; + } + + //! Allocates a char array of given size from the pool, and optionally copies a given string to it. + //! If the allocation request cannot be accomodated, this function will throw <code>std::bad_alloc</code>. + //! If exceptions are disabled by defining RAPIDXML_NO_EXCEPTIONS, this function + //! will call rapidxml::parse_error_handler() function. + //! \param source String to initialize the allocated memory with, or 0 to not initialize it. + //! \param size Number of characters to allocate, or zero to calculate it automatically from source string length; if size is 0, source string must be specified and null terminated. + //! \return Pointer to allocated char array. This pointer will never be NULL. + Ch *allocate_string(const Ch *source = 0, std::size_t size = 0) + { + assert(source || size); // Either source or size (or both) must be specified + if (size == 0) + size = internal::measure(source) + 1; + Ch *result = static_cast<Ch *>(allocate_aligned(size * sizeof(Ch))); + + if (result == NULL) + return NULL; + + if (source) + for (std::size_t i = 0; i < size; ++i) + result[i] = source[i]; + return result; + } + + //! Clones an xml_node and its hierarchy of child nodes and attributes. + //! Nodes and attributes are allocated from this memory pool. + //! Names and values are not cloned, they are shared between the clone and the source. + //! Result node can be optionally specified as a second parameter, + //! in which case its contents will be replaced with cloned source node. + //! This is useful when you want to clone entire document. + //! \param source Node to clone. + //! \param result Node to put results in, or 0 to automatically allocate result node + //! \return Pointer to cloned node. This pointer will never be NULL. + xml_node<Ch> *clone_node(const xml_node<Ch> *source, xml_node<Ch> *result = 0) + { + // Prepare result node + if (result) + { + result->remove_all_attributes(); + result->remove_all_nodes(); + result->type(source->type()); + } + else + result = allocate_node(source->type()); + + if (result == NULL) + return NULL; + + // Clone name and value + result->name(source->name(), source->name_size()); + result->value(source->value(), source->value_size()); + + // Clone child nodes and attributes + for (xml_node<Ch> *child = source->first_node(); child; child = child->next_sibling()) + { + xml_node<Ch> *new_node = clone_node(child); + + if (new_node == NULL) + return NULL; + + result->append_node(new_node); + } + for (xml_attribute<Ch> *attr = source->first_attribute(); attr; attr = attr->next_attribute()) + { + xml_attribute<Ch> *new_attr = allocate_attribute(attr->name(), attr->value(), attr->name_size(), attr->value_size()); + + if (new_attr == NULL) + return NULL; + + result->append_attribute(new_attr); + } + + return result; + } + + //! Clears the pool. + //! This causes memory occupied by nodes allocated by the pool to be freed. + //! Any nodes or strings allocated from the pool will no longer be valid. + void clear() + { + while (m_begin != m_static_memory) + { + char *previous_begin = reinterpret_cast<header *>(align(m_begin))->previous_begin; + if (m_free_func) + m_free_func(m_begin); + else + delete[] m_begin; + m_begin = previous_begin; + } + init(); + } + + //! Sets or resets the user-defined memory allocation functions for the pool. + //! This can only be called when no memory is allocated from the pool yet, otherwise results are undefined. + //! Allocation function must not return invalid pointer on failure. It should either throw, + //! stop the program, or use <code>longjmp()</code> function to pass control to other place of program. + //! If it returns invalid pointer, results are undefined. + //! <br><br> + //! User defined allocation functions must have the following forms: + //! <br><code> + //! <br>void *allocate(std::size_t size); + //! <br>void free(void *pointer); + //! </code><br> + //! \param af Allocation function, or 0 to restore default function + //! \param ff Free function, or 0 to restore default function + void set_allocator(alloc_func *af, free_func *ff) + { + assert(m_begin == m_static_memory && m_ptr == align(m_begin)); // Verify that no memory is allocated yet + m_alloc_func = af; + m_free_func = ff; + } + + private: + + struct header + { + char *previous_begin; + }; + + void init() + { + m_begin = m_static_memory; + m_ptr = align(m_begin); + m_end = m_static_memory + sizeof(m_static_memory); + } + + char *align(char *ptr) + { + std::size_t alignment = ((RAPIDXML_ALIGNMENT - (std::size_t(ptr) & (RAPIDXML_ALIGNMENT - 1))) & (RAPIDXML_ALIGNMENT - 1)); + return ptr + alignment; + } + + char *allocate_raw(std::size_t size) + { + // Allocate + void *memory; + if (m_alloc_func) // Allocate memory using either user-specified allocation function or global operator new[] + { + memory = m_alloc_func(size); + assert(memory); // Allocator is not allowed to return 0, on failure it must either throw, stop the program or use longjmp + } + else + { + memory = new char[size]; +#ifdef RAPIDXML_NO_EXCEPTIONS + if (!memory) // If exceptions are disabled, verify memory allocation, because new will not be able to throw bad_alloc + { + RAPIDXML_PARSE_ERROR("out of memory", 0, m_error_arg); + return NULL; + } +#endif + } + return static_cast<char *>(memory); + } + + void *allocate_aligned(std::size_t size) + { + // Calculate aligned pointer + char *result = align(m_ptr); + + // If not enough memory left in current pool, allocate a new pool + if (result + size > m_end) + { + // Calculate required pool size (may be bigger than RAPIDXML_DYNAMIC_POOL_SIZE) + std::size_t pool_size = RAPIDXML_DYNAMIC_POOL_SIZE; + if (pool_size < size) + pool_size = size; + + // Allocate + std::size_t alloc_size = sizeof(header) + (2 * RAPIDXML_ALIGNMENT - 2) + pool_size; // 2 alignments required in worst case: one for header, one for actual allocation + char *raw_memory = allocate_raw(alloc_size); + + if (raw_memory == NULL) + return NULL; + + // Setup new pool in allocated memory + char *pool = align(raw_memory); + header *new_header = reinterpret_cast<header *>(pool); + new_header->previous_begin = m_begin; + m_begin = raw_memory; + m_ptr = pool + sizeof(header); + m_end = raw_memory + alloc_size; + + // Calculate aligned pointer again using new pool + result = align(m_ptr); + } + + // Update pool and return aligned pointer + m_ptr = result + size; + return result; + } + + char *m_begin; // Start of raw memory making up current pool + char *m_ptr; // First free byte in current pool + char *m_end; // One past last available byte in current pool + char m_static_memory[RAPIDXML_STATIC_POOL_SIZE]; // Static raw memory + alloc_func *m_alloc_func; // Allocator function, or 0 if default is to be used + free_func *m_free_func; // Free function, or 0 if default is to be used + + protected: + void *m_error_arg; // Argument to pass to the error handler + }; + + /////////////////////////////////////////////////////////////////////////// + // XML base + + //! Base class for xml_node and xml_attribute implementing common functions: + //! name(), name_size(), value(), value_size() and parent(). + //! \param Ch Character type to use + template<class Ch = char> + class xml_base + { + + public: + + /////////////////////////////////////////////////////////////////////////// + // Construction & destruction + + // Construct a base with empty name, value and parent + xml_base() + : m_name(0) + , m_value(0) + , m_parent(0) + { + } + + /////////////////////////////////////////////////////////////////////////// + // Node data access + + //! Gets name of the node. + //! Interpretation of name depends on type of node. + //! Note that name will not be zero-terminated if rapidxml::parse_no_string_terminators option was selected during parse. + //! <br><br> + //! Use name_size() function to determine length of the name. + //! \return Name of node, or empty string if node has no name. + Ch *name() const + { + return m_name ? m_name : nullstr(); + } + + //! Gets size of node name, not including terminator character. + //! This function works correctly irrespective of whether name is or is not zero terminated. + //! \return Size of node name, in characters. + std::size_t name_size() const + { + return m_name ? m_name_size : 0; + } + + //! Gets value of node. + //! Interpretation of value depends on type of node. + //! Note that value will not be zero-terminated if rapidxml::parse_no_string_terminators option was selected during parse. + //! <br><br> + //! Use value_size() function to determine length of the value. + //! \return Value of node, or empty string if node has no value. + Ch *value() const + { + return m_value ? m_value : nullstr(); + } + + //! Gets size of node value, not including terminator character. + //! This function works correctly irrespective of whether value is or is not zero terminated. + //! \return Size of node value, in characters. + std::size_t value_size() const + { + return m_value ? m_value_size : 0; + } + + /////////////////////////////////////////////////////////////////////////// + // Node modification + + //! Sets name of node to a non zero-terminated string. + //! See \ref ownership_of_strings. + //! <br><br> + //! Note that node does not own its name or value, it only stores a pointer to it. + //! It will not delete or otherwise free the pointer on destruction. + //! It is reponsibility of the user to properly manage lifetime of the string. + //! The easiest way to achieve it is to use memory_pool of the document to allocate the string - + //! on destruction of the document the string will be automatically freed. + //! <br><br> + //! Size of name must be specified separately, because name does not have to be zero terminated. + //! Use name(const Ch *) function to have the length automatically calculated (string must be zero terminated). + //! \param name Name of node to set. Does not have to be zero terminated. + //! \param size Size of name, in characters. This does not include zero terminator, if one is present. + void name(const Ch *name, std::size_t size) + { + m_name = const_cast<Ch *>(name); + m_name_size = size; + } + + //! Sets name of node to a zero-terminated string. + //! See also \ref ownership_of_strings and xml_node::name(const Ch *, std::size_t). + //! \param name Name of node to set. Must be zero terminated. + void name(const Ch *name) + { + this->name(name, internal::measure(name)); + } + + //! Sets value of node to a non zero-terminated string. + //! See \ref ownership_of_strings. + //! <br><br> + //! Note that node does not own its name or value, it only stores a pointer to it. + //! It will not delete or otherwise free the pointer on destruction. + //! It is reponsibility of the user to properly manage lifetime of the string. + //! The easiest way to achieve it is to use memory_pool of the document to allocate the string - + //! on destruction of the document the string will be automatically freed. + //! <br><br> + //! Size of value must be specified separately, because it does not have to be zero terminated. + //! Use value(const Ch *) function to have the length automatically calculated (string must be zero terminated). + //! <br><br> + //! If an element has a child node of type node_data, it will take precedence over element value when printing. + //! If you want to manipulate data of elements using values, use parser flag rapidxml::parse_no_data_nodes to prevent creation of data nodes by the parser. + //! \param value value of node to set. Does not have to be zero terminated. + //! \param size Size of value, in characters. This does not include zero terminator, if one is present. + void value(const Ch *value, std::size_t size) + { + m_value = const_cast<Ch *>(value); + m_value_size = size; + } + + //! Sets value of node to a zero-terminated string. + //! See also \ref ownership_of_strings and xml_node::value(const Ch *, std::size_t). + //! \param value Vame of node to set. Must be zero terminated. + void value(const Ch *value) + { + this->value(value, internal::measure(value)); + } + + /////////////////////////////////////////////////////////////////////////// + // Related nodes access + + //! Gets node parent. + //! \return Pointer to parent node, or 0 if there is no parent. + xml_node<Ch> *parent() const + { + return m_parent; + } + + protected: + + // Return empty string + static Ch *nullstr() + { + static Ch zero = Ch('\0'); + return &zero; + } + + Ch *m_name; // Name of node, or 0 if no name + Ch *m_value; // Value of node, or 0 if no value + std::size_t m_name_size; // Length of node name, or undefined of no name + std::size_t m_value_size; // Length of node value, or undefined if no value + xml_node<Ch> *m_parent; // Pointer to parent node, or 0 if none + + }; + + //! Class representing attribute node of XML document. + //! Each attribute has name and value strings, which are available through name() and value() functions (inherited from xml_base). + //! Note that after parse, both name and value of attribute will point to interior of source text used for parsing. + //! Thus, this text must persist in memory for the lifetime of attribute. + //! \param Ch Character type to use. + template<class Ch = char> + class xml_attribute: public xml_base<Ch> + { + + friend class xml_node<Ch>; + + public: + + /////////////////////////////////////////////////////////////////////////// + // Construction & destruction + + //! Constructs an empty attribute with the specified type. + //! Consider using memory_pool of appropriate xml_document if allocating attributes manually. + xml_attribute() + { + } + + /////////////////////////////////////////////////////////////////////////// + // Related nodes access + + //! Gets document of which attribute is a child. + //! \return Pointer to document that contains this attribute, or 0 if there is no parent document. + xml_document<Ch> *document() const + { + if (xml_node<Ch> *node = this->parent()) + { + while (node->parent()) + node = node->parent(); + return node->type() == node_document ? static_cast<xml_document<Ch> *>(node) : 0; + } + else + return NULL; + } + + //! Gets previous attribute, optionally matching attribute name. + //! \param name Name of attribute to find, or 0 to return previous attribute regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero + //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string + //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters + //! \return Pointer to found attribute, or 0 if not found. + xml_attribute<Ch> *previous_attribute(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const + { + if (name) + { + if (name_size == 0) + name_size = internal::measure(name); + for (xml_attribute<Ch> *attribute = m_prev_attribute; attribute; attribute = attribute->m_prev_attribute) + if (internal::compare(attribute->name(), attribute->name_size(), name, name_size, case_sensitive)) + return attribute; + return NULL; + } + else + return this->m_parent ? m_prev_attribute : 0; + } + + //! Gets next attribute, optionally matching attribute name. + //! \param name Name of attribute to find, or 0 to return next attribute regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero + //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string + //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters + //! \return Pointer to found attribute, or 0 if not found. + xml_attribute<Ch> *next_attribute(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const + { + if (name) + { + if (name_size == 0) + name_size = internal::measure(name); + for (xml_attribute<Ch> *attribute = m_next_attribute; attribute; attribute = attribute->m_next_attribute) + if (internal::compare(attribute->name(), attribute->name_size(), name, name_size, case_sensitive)) + return attribute; + return NULL; + } + else + return this->m_parent ? m_next_attribute : 0; + } + + private: + + xml_attribute<Ch> *m_prev_attribute; // Pointer to previous sibling of attribute, or 0 if none; only valid if parent is non-zero + xml_attribute<Ch> *m_next_attribute; // Pointer to next sibling of attribute, or 0 if none; only valid if parent is non-zero + + }; + + /////////////////////////////////////////////////////////////////////////// + // XML node + + //! Class representing a node of XML document. + //! Each node may have associated name and value strings, which are available through name() and value() functions. + //! Interpretation of name and value depends on type of the node. + //! Type of node can be determined by using type() function. + //! <br><br> + //! Note that after parse, both name and value of node, if any, will point interior of source text used for parsing. + //! Thus, this text must persist in the memory for the lifetime of node. + //! \param Ch Character type to use. + template<class Ch = char> + class xml_node: public xml_base<Ch> + { + + public: + + /////////////////////////////////////////////////////////////////////////// + // Construction & destruction + + //! Constructs an empty node with the specified type. + //! Consider using memory_pool of appropriate document to allocate nodes manually. + //! \param type Type of node to construct. + xml_node(node_type type) + : m_type(type) + , m_first_node(0) + , m_first_attribute(0) + { + } + + /////////////////////////////////////////////////////////////////////////// + // Node data access + + //! Gets type of node. + //! \return Type of node. + node_type type() const + { + return m_type; + } + + /////////////////////////////////////////////////////////////////////////// + // Related nodes access + + //! Gets document of which node is a child. + //! \return Pointer to document that contains this node, or 0 if there is no parent document. + xml_document<Ch> *document() const + { + xml_node<Ch> *node = const_cast<xml_node<Ch> *>(this); + while (node->parent()) + node = node->parent(); + return node->type() == node_document ? static_cast<xml_document<Ch> *>(node) : 0; + } + + //! Gets first child node, optionally matching node name. + //! \param name Name of child to find, or 0 to return first child regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero + //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string + //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters + //! \return Pointer to found child, or 0 if not found. + xml_node<Ch> *first_node(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const + { + if (name) + { + if (name_size == 0) + name_size = internal::measure(name); + for (xml_node<Ch> *child = m_first_node; child; child = child->next_sibling()) + if (internal::compare(child->name(), child->name_size(), name, name_size, case_sensitive)) + return child; + return NULL; + } + else + return m_first_node; + } + + //! Gets last child node, optionally matching node name. + //! Behaviour is undefined if node has no children. + //! Use first_node() to test if node has children. + //! \param name Name of child to find, or 0 to return last child regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero + //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string + //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters + //! \return Pointer to found child, or 0 if not found. + xml_node<Ch> *last_node(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const + { + assert(m_first_node); // Cannot query for last child if node has no children + if (name) + { + if (name_size == 0) + name_size = internal::measure(name); + for (xml_node<Ch> *child = m_last_node; child; child = child->previous_sibling()) + if (internal::compare(child->name(), child->name_size(), name, name_size, case_sensitive)) + return child; + return NULL; + } + else + return m_last_node; + } + + //! Gets previous sibling node, optionally matching node name. + //! Behaviour is undefined if node has no parent. + //! Use parent() to test if node has a parent. + //! \param name Name of sibling to find, or 0 to return previous sibling regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero + //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string + //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters + //! \return Pointer to found sibling, or 0 if not found. + xml_node<Ch> *previous_sibling(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const + { + assert(this->m_parent); // Cannot query for siblings if node has no parent + if (name) + { + if (name_size == 0) + name_size = internal::measure(name); + for (xml_node<Ch> *sibling = m_prev_sibling; sibling; sibling = sibling->m_prev_sibling) + if (internal::compare(sibling->name(), sibling->name_size(), name, name_size, case_sensitive)) + return sibling; + return NULL; + } + else + return m_prev_sibling; + } + + //! Gets next sibling node, optionally matching node name. + //! Behaviour is undefined if node has no parent. + //! Use parent() to test if node has a parent. + //! \param name Name of sibling to find, or 0 to return next sibling regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero + //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string + //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters + //! \return Pointer to found sibling, or 0 if not found. + xml_node<Ch> *next_sibling(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const + { + assert(this->m_parent); // Cannot query for siblings if node has no parent + if (name) + { + if (name_size == 0) + name_size = internal::measure(name); + for (xml_node<Ch> *sibling = m_next_sibling; sibling; sibling = sibling->m_next_sibling) + if (internal::compare(sibling->name(), sibling->name_size(), name, name_size, case_sensitive)) + return sibling; + return NULL; + } + else + return m_next_sibling; + } + + //! Gets first attribute of node, optionally matching attribute name. + //! \param name Name of attribute to find, or 0 to return first attribute regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero + //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string + //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters + //! \return Pointer to found attribute, or 0 if not found. + xml_attribute<Ch> *first_attribute(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const + { + if (name) + { + if (name_size == 0) + name_size = internal::measure(name); + for (xml_attribute<Ch> *attribute = m_first_attribute; attribute; attribute = attribute->m_next_attribute) + if (internal::compare(attribute->name(), attribute->name_size(), name, name_size, case_sensitive)) + return attribute; + return NULL; + } + else + return m_first_attribute; + } + + //! Gets last attribute of node, optionally matching attribute name. + //! \param name Name of attribute to find, or 0 to return last attribute regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero + //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string + //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters + //! \return Pointer to found attribute, or 0 if not found. + xml_attribute<Ch> *last_attribute(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const + { + if (name) + { + if (name_size == 0) + name_size = internal::measure(name); + for (xml_attribute<Ch> *attribute = m_last_attribute; attribute; attribute = attribute->m_prev_attribute) + if (internal::compare(attribute->name(), attribute->name_size(), name, name_size, case_sensitive)) + return attribute; + return NULL; + } + else + return m_first_attribute ? m_last_attribute : 0; + } + + /////////////////////////////////////////////////////////////////////////// + // Node modification + + //! Sets type of node. + //! \param type Type of node to set. + void type(node_type type) + { + m_type = type; + } + + /////////////////////////////////////////////////////////////////////////// + // Node manipulation + + //! Prepends a new child node. + //! The prepended child becomes the first child, and all existing children are moved one position back. + //! \param child Node to prepend. + void prepend_node(xml_node<Ch> *child) + { + assert(child && !child->parent() && child->type() != node_document); + if (first_node()) + { + child->m_next_sibling = m_first_node; + m_first_node->m_prev_sibling = child; + } + else + { + child->m_next_sibling = 0; + m_last_node = child; + } + m_first_node = child; + child->m_parent = this; + child->m_prev_sibling = 0; + } + + //! Appends a new child node. + //! The appended child becomes the last child. + //! \param child Node to append. + void append_node(xml_node<Ch> *child) + { + assert(child && !child->parent() && child->type() != node_document); + if (first_node()) + { + child->m_prev_sibling = m_last_node; + m_last_node->m_next_sibling = child; + } + else + { + child->m_prev_sibling = 0; + m_first_node = child; + } + m_last_node = child; + child->m_parent = this; + child->m_next_sibling = 0; + } + + //! Inserts a new child node at specified place inside the node. + //! All children after and including the specified node are moved one position back. + //! \param where Place where to insert the child, or 0 to insert at the back. + //! \param child Node to insert. + void insert_node(xml_node<Ch> *where, xml_node<Ch> *child) + { + assert(!where || where->parent() == this); + assert(child && !child->parent() && child->type() != node_document); + if (where == m_first_node) + prepend_node(child); + else if (where == 0) + append_node(child); + else + { + child->m_prev_sibling = where->m_prev_sibling; + child->m_next_sibling = where; + where->m_prev_sibling->m_next_sibling = child; + where->m_prev_sibling = child; + child->m_parent = this; + } + } + + //! Removes first child node. + //! If node has no children, behaviour is undefined. + //! Use first_node() to test if node has children. + void remove_first_node() + { + assert(first_node()); + xml_node<Ch> *child = m_first_node; + m_first_node = child->m_next_sibling; + if (child->m_next_sibling) + child->m_next_sibling->m_prev_sibling = 0; + else + m_last_node = 0; + child->m_parent = 0; + } + + //! Removes last child of the node. + //! If node has no children, behaviour is undefined. + //! Use first_node() to test if node has children. + void remove_last_node() + { + assert(first_node()); + xml_node<Ch> *child = m_last_node; + if (child->m_prev_sibling) + { + m_last_node = child->m_prev_sibling; + child->m_prev_sibling->m_next_sibling = 0; + } + else + m_first_node = 0; + child->m_parent = 0; + } + + //! Removes specified child from the node + // \param where Pointer to child to be removed. + void remove_node(xml_node<Ch> *where) + { + assert(where && where->parent() == this); + assert(first_node()); + if (where == m_first_node) + remove_first_node(); + else if (where == m_last_node) + remove_last_node(); + else + { + where->m_prev_sibling->m_next_sibling = where->m_next_sibling; + where->m_next_sibling->m_prev_sibling = where->m_prev_sibling; + where->m_parent = 0; + } + } + + //! Removes all child nodes (but not attributes). + void remove_all_nodes() + { + for (xml_node<Ch> *node = first_node(); node; node = node->m_next_sibling) + node->m_parent = 0; + m_first_node = 0; + } + + //! Prepends a new attribute to the node. + //! \param attribute Attribute to prepend. + void prepend_attribute(xml_attribute<Ch> *attribute) + { + assert(attribute && !attribute->parent()); + if (first_attribute()) + { + attribute->m_next_attribute = m_first_attribute; + m_first_attribute->m_prev_attribute = attribute; + } + else + { + attribute->m_next_attribute = 0; + m_last_attribute = attribute; + } + m_first_attribute = attribute; + attribute->m_parent = this; + attribute->m_prev_attribute = 0; + } + + //! Appends a new attribute to the node. + //! \param attribute Attribute to append. + void append_attribute(xml_attribute<Ch> *attribute) + { + assert(attribute && !attribute->parent()); + if (first_attribute()) + { + attribute->m_prev_attribute = m_last_attribute; + m_last_attribute->m_next_attribute = attribute; + } + else + { + attribute->m_prev_attribute = 0; + m_first_attribute = attribute; + } + m_last_attribute = attribute; + attribute->m_parent = this; + attribute->m_next_attribute = 0; + } + + //! Inserts a new attribute at specified place inside the node. + //! All attributes after and including the specified attribute are moved one position back. + //! \param where Place where to insert the attribute, or 0 to insert at the back. + //! \param attribute Attribute to insert. + void insert_attribute(xml_attribute<Ch> *where, xml_attribute<Ch> *attribute) + { + assert(!where || where->parent() == this); + assert(attribute && !attribute->parent()); + if (where == m_first_attribute) + prepend_attribute(attribute); + else if (where == 0) + append_attribute(attribute); + else + { + attribute->m_prev_attribute = where->m_prev_attribute; + attribute->m_next_attribute = where; + where->m_prev_attribute->m_next_attribute = attribute; + where->m_prev_attribute = attribute; + attribute->m_parent = this; + } + } + + //! Removes first attribute of the node. + //! If node has no attributes, behaviour is undefined. + //! Use first_attribute() to test if node has attributes. + void remove_first_attribute() + { + assert(first_attribute()); + xml_attribute<Ch> *attribute = m_first_attribute; + if (attribute->m_next_attribute) + { + attribute->m_next_attribute->m_prev_attribute = 0; + } + else + m_last_attribute = 0; + attribute->m_parent = 0; + m_first_attribute = attribute->m_next_attribute; + } + + //! Removes last attribute of the node. + //! If node has no attributes, behaviour is undefined. + //! Use first_attribute() to test if node has attributes. + void remove_last_attribute() + { + assert(first_attribute()); + xml_attribute<Ch> *attribute = m_last_attribute; + if (attribute->m_prev_attribute) + { + attribute->m_prev_attribute->m_next_attribute = 0; + m_last_attribute = attribute->m_prev_attribute; + } + else + m_first_attribute = 0; + attribute->m_parent = 0; + } + + //! Removes specified attribute from node. + //! \param where Pointer to attribute to be removed. + void remove_attribute(xml_attribute<Ch> *where) + { + assert(first_attribute() && where->parent() == this); + if (where == m_first_attribute) + remove_first_attribute(); + else if (where == m_last_attribute) + remove_last_attribute(); + else + { + where->m_prev_attribute->m_next_attribute = where->m_next_attribute; + where->m_next_attribute->m_prev_attribute = where->m_prev_attribute; + where->m_parent = 0; + } + } + + //! Removes all attributes of node. + void remove_all_attributes() + { + for (xml_attribute<Ch> *attribute = first_attribute(); attribute; attribute = attribute->m_next_attribute) + attribute->m_parent = 0; + m_first_attribute = 0; + } + + private: + + /////////////////////////////////////////////////////////////////////////// + // Restrictions + + // No copying + xml_node(const xml_node &); + void operator =(const xml_node &); + + /////////////////////////////////////////////////////////////////////////// + // Data members + + // Note that some of the pointers below have UNDEFINED values if certain other pointers are 0. + // This is required for maximum performance, as it allows the parser to omit initialization of + // unneded/redundant values. + // + // The rules are as follows: + // 1. first_node and first_attribute contain valid pointers, or 0 if node has no children/attributes respectively + // 2. last_node and last_attribute are valid only if node has at least one child/attribute respectively, otherwise they contain garbage + // 3. prev_sibling and next_sibling are valid only if node has a parent, otherwise they contain garbage + + node_type m_type; // Type of node; always valid + xml_node<Ch> *m_first_node; // Pointer to first child node, or 0 if none; always valid + xml_node<Ch> *m_last_node; // Pointer to last child node, or 0 if none; this value is only valid if m_first_node is non-zero + xml_attribute<Ch> *m_first_attribute; // Pointer to first attribute of node, or 0 if none; always valid + xml_attribute<Ch> *m_last_attribute; // Pointer to last attribute of node, or 0 if none; this value is only valid if m_first_attribute is non-zero + xml_node<Ch> *m_prev_sibling; // Pointer to previous sibling of node, or 0 if none; this value is only valid if m_parent is non-zero + xml_node<Ch> *m_next_sibling; // Pointer to next sibling of node, or 0 if none; this value is only valid if m_parent is non-zero + + }; + + /////////////////////////////////////////////////////////////////////////// + // XML document + + //! This class represents root of the DOM hierarchy. + //! It is also an xml_node and a memory_pool through public inheritance. + //! Use parse() function to build a DOM tree from a zero-terminated XML text string. + //! parse() function allocates memory for nodes and attributes by using functions of xml_document, + //! which are inherited from memory_pool. + //! To access root node of the document, use the document itself, as if it was an xml_node. + //! \param Ch Character type to use. + template<class Ch = char> + class xml_document: public xml_node<Ch>, public memory_pool<Ch> + { + + public: + + //! Constructs empty XML document with NULL parse error argument + xml_document() + : xml_node<Ch>(node_document) + , memory_pool<Ch>(NULL) + , m_empty_node(node_empty) + { + } + + //!Constructs empty XML document with a given parse error argument + xml_document(void *error_arg) + : xml_node<Ch>(node_document) + , memory_pool<Ch>(error_arg) + , m_empty_node(node_empty), + m_error_arg(error_arg) + { + } + + //! Parses zero-terminated XML string according to given flags. + //! Passed string will be modified by the parser, unless rapidxml::parse_non_destructive flag is used. + //! The string must persist for the lifetime of the document. + //! In case of error, rapidxml::parse_error exception will be thrown. + //! <br><br> + //! If you want to parse contents of a file, you must first load the file into the memory, and pass pointer to its beginning. + //! Make sure that data is zero-terminated. + //! <br><br> + //! Document can be parsed into multiple times. + //! Each new call to parse removes previous nodes and attributes (if any), but does not clear memory pool. + //! \param text XML data to parse; pointer is non-const to denote fact that this data may be modified by the parser. + template<int Flags> + bool parse(Ch *text) + { + assert(text); + + // Remove current contents + this->remove_all_nodes(); + this->remove_all_attributes(); + + // Parse BOM, if any + parse_bom<Flags>(text); + + // Parse children + while (1) + { + // Skip whitespace before node + skip<whitespace_pred, Flags>(text); + if (*text == 0) + break; + + // Parse and append new child + if (*text == Ch('<')) + { + ++text; // Skip '<' + xml_node<Ch> *node = parse_node<Flags>(text); + + if (node == NULL) + return false; + else if (node != &m_empty_node) + this->append_node(node); + } + else + { + RAPIDXML_PARSE_ERROR("expected <", text, m_error_arg); + return false; + } + } + + return true; + } + + //! Clears the document by deleting all nodes and clearing the memory pool. + //! All nodes owned by document pool are destroyed. + void clear() + { + this->remove_all_nodes(); + this->remove_all_attributes(); + memory_pool<Ch>::clear(); + } + + private: + + /////////////////////////////////////////////////////////////////////// + // Internal character utility functions + + // Detect whitespace character + struct whitespace_pred + { + static unsigned char test(Ch ch) + { + return internal::lookup_tables<0>::lookup_whitespace[static_cast<unsigned char>(ch)]; + } + }; + + // Detect node name character + struct node_name_pred + { + static unsigned char test(Ch ch) + { + return internal::lookup_tables<0>::lookup_node_name[static_cast<unsigned char>(ch)]; + } + }; + + // Detect attribute name character + struct attribute_name_pred + { + static unsigned char test(Ch ch) + { + return internal::lookup_tables<0>::lookup_attribute_name[static_cast<unsigned char>(ch)]; + } + }; + + // Detect text character (PCDATA) + struct text_pred + { + static unsigned char test(Ch ch) + { + return internal::lookup_tables<0>::lookup_text[static_cast<unsigned char>(ch)]; + } + }; + + // Detect text character (PCDATA) that does not require processing + struct text_pure_no_ws_pred + { + static unsigned char test(Ch ch) + { + return internal::lookup_tables<0>::lookup_text_pure_no_ws[static_cast<unsigned char>(ch)]; + } + }; + + // Detect text character (PCDATA) that does not require processing + struct text_pure_with_ws_pred + { + static unsigned char test(Ch ch) + { + return internal::lookup_tables<0>::lookup_text_pure_with_ws[static_cast<unsigned char>(ch)]; + } + }; + + // Detect attribute value character + template<Ch Quote> + struct attribute_value_pred + { + static unsigned char test(Ch ch) + { + if (Quote == Ch('\'')) + return internal::lookup_tables<0>::lookup_attribute_data_1[static_cast<unsigned char>(ch)]; + if (Quote == Ch('\"')) + return internal::lookup_tables<0>::lookup_attribute_data_2[static_cast<unsigned char>(ch)]; + return NULL; // Should never be executed, to avoid warnings on Comeau + } + }; + + // Detect attribute value character + template<Ch Quote> + struct attribute_value_pure_pred + { + static unsigned char test(Ch ch) + { + if (Quote == Ch('\'')) + return internal::lookup_tables<0>::lookup_attribute_data_1_pure[static_cast<unsigned char>(ch)]; + if (Quote == Ch('\"')) + return internal::lookup_tables<0>::lookup_attribute_data_2_pure[static_cast<unsigned char>(ch)]; + return NULL; // Should never be executed, to avoid warnings on Comeau + } + }; + + // Insert coded character, using UTF8 or 8-bit ASCII + template<int Flags> + static bool insert_coded_character(Ch *&text, unsigned long code, void *error_arg) + { + if (Flags & parse_no_utf8) + { + // Insert 8-bit ASCII character + // Todo: possibly verify that code is less than 256 and use replacement char otherwise? + text[0] = static_cast<unsigned char>(code); + text += 1; + } + else + { + // Insert UTF8 sequence + if (code < 0x80) // 1 byte sequence + { + text[0] = static_cast<unsigned char>(code); + text += 1; + } + else if (code < 0x800) // 2 byte sequence + { + text[1] = static_cast<unsigned char>((code | 0x80) & 0xBF); code >>= 6; + text[0] = static_cast<unsigned char>(code | 0xC0); + text += 2; + } + else if (code < 0x10000) // 3 byte sequence + { + text[2] = static_cast<unsigned char>((code | 0x80) & 0xBF); code >>= 6; + text[1] = static_cast<unsigned char>((code | 0x80) & 0xBF); code >>= 6; + text[0] = static_cast<unsigned char>(code | 0xE0); + text += 3; + } + else if (code < 0x110000) // 4 byte sequence + { + text[3] = static_cast<unsigned char>((code | 0x80) & 0xBF); code >>= 6; + text[2] = static_cast<unsigned char>((code | 0x80) & 0xBF); code >>= 6; + text[1] = static_cast<unsigned char>((code | 0x80) & 0xBF); code >>= 6; + text[0] = static_cast<unsigned char>(code | 0xF0); + text += 4; + } + else // Invalid, only codes up to 0x10FFFF are allowed in Unicode + { + RAPIDXML_PARSE_ERROR("invalid numeric character entity", text, error_arg); + return false; + } + } + + return true; + } + + // Skip characters until predicate evaluates to true + template<class StopPred, int Flags> + static void skip(Ch *&text) + { + Ch *tmp = text; + while (StopPred::test(*tmp)) + ++tmp; + text = tmp; + } + + // Skip characters until predicate evaluates to true while doing the following: + // - replacing XML character entity references with proper characters (' & " < > &#...;) + // - condensing whitespace sequences to single space character + template<class StopPred, class StopPredPure, int Flags> + static Ch *skip_and_expand_character_refs(Ch *&text, void* error_arg) + { + // If entity translation, whitespace condense and whitespace trimming is disabled, use plain skip + if (Flags & parse_no_entity_translation && + !(Flags & parse_normalize_whitespace) && + !(Flags & parse_trim_whitespace)) + { + skip<StopPred, Flags>(text); + return text; + } + + // Use simple skip until first modification is detected + skip<StopPredPure, Flags>(text); + + // Use translation skip + Ch *src = text; + Ch *dest = src; + while (StopPred::test(*src)) + { + // If entity translation is enabled + if (!(Flags & parse_no_entity_translation)) + { + // Test if replacement is needed + if (src[0] == Ch('&')) + { + switch (src[1]) + { + + // & ' + case Ch('a'): + if (src[2] == Ch('m') && src[3] == Ch('p') && src[4] == Ch(';')) + { + *dest = Ch('&'); + ++dest; + src += 5; + continue; + } + if (src[2] == Ch('p') && src[3] == Ch('o') && src[4] == Ch('s') && src[5] == Ch(';')) + { + *dest = Ch('\''); + ++dest; + src += 6; + continue; + } + break; + + // " + case Ch('q'): + if (src[2] == Ch('u') && src[3] == Ch('o') && src[4] == Ch('t') && src[5] == Ch(';')) + { + *dest = Ch('"'); + ++dest; + src += 6; + continue; + } + break; + + // > + case Ch('g'): + if (src[2] == Ch('t') && src[3] == Ch(';')) + { + *dest = Ch('>'); + ++dest; + src += 4; + continue; + } + break; + + // < + case Ch('l'): + if (src[2] == Ch('t') && src[3] == Ch(';')) + { + *dest = Ch('<'); + ++dest; + src += 4; + continue; + } + break; + + // &#...; - assumes ASCII + case Ch('#'): + if (src[2] == Ch('x')) + { + unsigned long code = 0; + src += 3; // Skip &#x + while (1) + { + unsigned char digit = internal::lookup_tables<0>::lookup_digits[static_cast<unsigned char>(*src)]; + if (digit == 0xFF) + break; + code = code * 16 + digit; + ++src; + } + if (!insert_coded_character<Flags>(dest, code, error_arg)) // Put character in output + return NULL; + } + else + { + unsigned long code = 0; + src += 2; // Skip &# + while (1) + { + unsigned char digit = internal::lookup_tables<0>::lookup_digits[static_cast<unsigned char>(*src)]; + if (digit == 0xFF) + break; + code = code * 10 + digit; + ++src; + } + if (!insert_coded_character<Flags>(dest, code, error_arg)) // Put character in output + return NULL; + } + if (*src == Ch(';')) + ++src; + else + { + RAPIDXML_PARSE_ERROR("expected ;", src, error_arg); + return NULL; + } + continue; + + // Something else + default: + // Ignore, just copy '&' verbatim + break; + + } + } + } + + // If whitespace condensing is enabled + if (Flags & parse_normalize_whitespace) + { + // Test if condensing is needed + if (whitespace_pred::test(*src)) + { + *dest = Ch(' '); ++dest; // Put single space in dest + ++src; // Skip first whitespace char + // Skip remaining whitespace chars + while (whitespace_pred::test(*src)) + ++src; + continue; + } + } + + // No replacement, only copy character + *dest++ = *src++; + + } + + // Return new end + text = src; + return dest; + + } + + /////////////////////////////////////////////////////////////////////// + // Internal parsing functions + + // Parse BOM, if any + template<int Flags> + void parse_bom(Ch *&text) + { + // UTF-8? + if (static_cast<unsigned char>(text[0]) == 0xEF && + static_cast<unsigned char>(text[1]) == 0xBB && + static_cast<unsigned char>(text[2]) == 0xBF) + { + text += 3; // Skup utf-8 bom + } + } + + // Parse XML declaration (<?xml...) + template<int Flags> + xml_node<Ch> *parse_xml_declaration(Ch *&text) + { + // If parsing of declaration is disabled + if (!(Flags & parse_declaration_node)) + { + // Skip until end of declaration + while (text[0] != Ch('?') || text[1] != Ch('>')) + { + if (!text[0]) + { + RAPIDXML_PARSE_ERROR("unexpected end of data", text, m_error_arg); + return NULL; + } + ++text; + } + text += 2; // Skip '?>' + return &m_empty_node; + } + + // Create declaration + xml_node<Ch> *declaration = this->allocate_node(node_declaration); + + if (declaration == NULL) + return NULL; + + // Skip whitespace before attributes or ?> + skip<whitespace_pred, Flags>(text); + + // Parse declaration attributes + if (!parse_node_attributes<Flags>(text, declaration)) + return NULL; + + // Skip ?> + if (text[0] != Ch('?') || text[1] != Ch('>')) + { + RAPIDXML_PARSE_ERROR("expected ?>", text, m_error_arg); + return NULL; + } + text += 2; + + return declaration; + } + + // Parse XML comment (<!--...) + template<int Flags> + xml_node<Ch> *parse_comment(Ch *&text) + { + // If parsing of comments is disabled + if (!(Flags & parse_comment_nodes)) + { + // Skip until end of comment + while (text[0] != Ch('-') || text[1] != Ch('-') || text[2] != Ch('>')) + { + if (!text[0]) + { + RAPIDXML_PARSE_ERROR("unexpected end of data", text, m_error_arg); + return NULL; + } + ++text; + } + text += 3; // Skip '-->' + return &m_empty_node; // Do not produce comment node + } + + // Remember value start + Ch *value = text; + + // Skip until end of comment + while (text[0] != Ch('-') || text[1] != Ch('-') || text[2] != Ch('>')) + { + if (!text[0]) + { + RAPIDXML_PARSE_ERROR("unexpected end of data", text, m_error_arg); + return NULL; + } + ++text; + } + + // Create comment node + xml_node<Ch> *comment = this->allocate_node(node_comment); + + if (comment == NULL) + return NULL; + + comment->value(value, text - value); + + // Place zero terminator after comment value + if (!(Flags & parse_no_string_terminators)) + *text = Ch('\0'); + + text += 3; // Skip '-->' + return comment; + } + + // Parse DOCTYPE + template<int Flags> + xml_node<Ch> *parse_doctype(Ch *&text) + { + // Remember value start + Ch *value = text; + + // Skip to > + while (*text != Ch('>')) + { + // Determine character type + switch (*text) + { + + // If '[' encountered, scan for matching ending ']' using naive algorithm with depth + // This works for all W3C test files except for 2 most wicked + case Ch('['): + { + ++text; // Skip '[' + int depth = 1; + while (depth > 0) + { + switch (*text) + { + case Ch('['): ++depth; break; + case Ch(']'): --depth; break; + case 0: + RAPIDXML_PARSE_ERROR("unexpected end of data", text, m_error_arg); + return NULL; + } + ++text; + } + break; + } + + // Error on end of text + case Ch('\0'): + RAPIDXML_PARSE_ERROR("unexpected end of data", text, m_error_arg); + return NULL; + + // Other character, skip it + default: + ++text; + + } + } + + // If DOCTYPE nodes enabled + if (Flags & parse_doctype_node) + { + // Create a new doctype node + xml_node<Ch> *doctype = this->allocate_node(node_doctype); + + if (doctype == NULL) + return NULL; + + doctype->value(value, text - value); + + // Place zero terminator after value + if (!(Flags & parse_no_string_terminators)) + *text = Ch('\0'); + + text += 1; // skip '>' + return doctype; + } + else + { + text += 1; // skip '>' + return &m_empty_node; + } + + } + + // Parse PI + template<int Flags> + xml_node<Ch> *parse_pi(Ch *&text) + { + // If creation of PI nodes is enabled + if (Flags & parse_pi_nodes) + { + // Create pi node + xml_node<Ch> *pi = this->allocate_node(node_pi); + + if (pi == NULL) + return NULL; + + // Extract PI target name + Ch *name = text; + skip<node_name_pred, Flags>(text); + if (text == name) + { + RAPIDXML_PARSE_ERROR("expected PI target", text, m_error_arg); + return NULL; + } + pi->name(name, text - name); + + // Skip whitespace between pi target and pi + skip<whitespace_pred, Flags>(text); + + // Remember start of pi + Ch *value = text; + + // Skip to '?>' + while (text[0] != Ch('?') || text[1] != Ch('>')) + { + if (*text == Ch('\0')) + { + RAPIDXML_PARSE_ERROR("unexpected end of data", text, m_error_arg); + return NULL; + } + ++text; + } + + // Set pi value (verbatim, no entity expansion or whitespace normalization) + pi->value(value, text - value); + + // Place zero terminator after name and value + if (!(Flags & parse_no_string_terminators)) + { + pi->name()[pi->name_size()] = Ch('\0'); + pi->value()[pi->value_size()] = Ch('\0'); + } + + text += 2; // Skip '?>' + return pi; + } + else + { + // Skip to '?>' + while (text[0] != Ch('?') || text[1] != Ch('>')) + { + if (*text == Ch('\0')) + { + RAPIDXML_PARSE_ERROR("unexpected end of data", text, m_error_arg); + return NULL; + } + ++text; + } + text += 2; // Skip '?>' + return &m_empty_node; + } + } + + // Parse and append data + // Returns true if an error has not occured. + // Places the end character in *end_character. + // This is necessary because this character might have been overwritten by a terminating 0 + template<int Flags> + bool parse_and_append_data(xml_node<Ch> *node, Ch *&text, Ch *contents_start, Ch *end_character) + { + // Backup to contents start if whitespace trimming is disabled + if (!(Flags & parse_trim_whitespace)) + text = contents_start; + + // Skip until end of data + Ch *value = text, *end; + if (Flags & parse_normalize_whitespace) + end = skip_and_expand_character_refs<text_pred, text_pure_with_ws_pred, Flags>(text, m_error_arg); + else + end = skip_and_expand_character_refs<text_pred, text_pure_no_ws_pred, Flags>(text, m_error_arg); + + if (end == NULL) + return false; + + // Trim trailing whitespace if flag is set; leading was already trimmed by whitespace skip after > + if (Flags & parse_trim_whitespace) + { + if (Flags & parse_normalize_whitespace) + { + // Whitespace is already condensed to single space characters by skipping function, so just trim 1 char off the end + if (*(end - 1) == Ch(' ')) + --end; + } + else + { + // Backup until non-whitespace character is found + while (whitespace_pred::test(*(end - 1))) + --end; + } + } + + // If characters are still left between end and value (this test is only necessary if normalization is enabled) + // Create new data node + if (!(Flags & parse_no_data_nodes)) + { + xml_node<Ch> *data = this->allocate_node(node_data); + data->value(value, end - value); + node->append_node(data); + } + + // Add data to parent node if no data exists yet + if (!(Flags & parse_no_element_values)) + if (*node->value() == Ch('\0')) + node->value(value, end - value); + + // Place zero terminator after value + if (!(Flags & parse_no_string_terminators)) + { + Ch ch = *text; + *end = Ch('\0'); + + *end_character = ch; // This is required because zero terminator overwritten it + return true; + } + + // Return character that ends data + *end_character = *text; + + return true; + } + + // Parse CDATA + template<int Flags> + xml_node<Ch> *parse_cdata(Ch *&text) + { + // If CDATA is disabled + if (Flags & parse_no_data_nodes) + { + // Skip until end of cdata + while (text[0] != Ch(']') || text[1] != Ch(']') || text[2] != Ch('>')) + { + if (!text[0]) + { + RAPIDXML_PARSE_ERROR("unexpected end of data", text, m_error_arg); + return NULL; + } + ++text; + } + text += 3; // Skip ]]> + return &m_empty_node; // Do not produce CDATA node + } + + // Skip until end of cdata + Ch *value = text; + while (text[0] != Ch(']') || text[1] != Ch(']') || text[2] != Ch('>')) + { + if (!text[0]) + { + RAPIDXML_PARSE_ERROR("unexpected end of data", text, m_error_arg); + return NULL; + } + ++text; + } + + // Create new cdata node + xml_node<Ch> *cdata = this->allocate_node(node_cdata); + + if (cdata == NULL) + return NULL; + + cdata->value(value, text - value); + + // Place zero terminator after value + if (!(Flags & parse_no_string_terminators)) + *text = Ch('\0'); + + text += 3; // Skip ]]> + return cdata; + } + + // Parse element node + template<int Flags> + xml_node<Ch> *parse_element(Ch *&text) + { + // Create element node + xml_node<Ch> *element = this->allocate_node(node_element); + + if (element == NULL) + return NULL; + + // Extract element name + Ch *name = text; + skip<node_name_pred, Flags>(text); + if (text == name) + { + RAPIDXML_PARSE_ERROR("expected element name", text, m_error_arg); + return NULL; + } + element->name(name, text - name); + + // Skip whitespace between element name and attributes or > + skip<whitespace_pred, Flags>(text); + + // Parse attributes, if any + if (!parse_node_attributes<Flags>(text, element)) + return NULL; + + // Determine ending type + if (*text == Ch('>')) + { + ++text; + if (!parse_node_contents<Flags>(text, element)) + return NULL; + } + else if (*text == Ch('/')) + { + ++text; + if (*text != Ch('>')) + { + RAPIDXML_PARSE_ERROR("expected >", text, m_error_arg); + return NULL; + } + ++text; + } + else + { + RAPIDXML_PARSE_ERROR("expected >", text, m_error_arg); + return NULL; + } + + // Place zero terminator after name + if (!(Flags & parse_no_string_terminators)) + element->name()[element->name_size()] = Ch('\0'); + + // Return parsed element + return element; + } + + // Determine node type, and parse it + template<int Flags> + xml_node<Ch> *parse_node(Ch *&text) + { + // Parse proper node type + switch (text[0]) + { + + // <... + default: + // Parse and append element node + return parse_element<Flags>(text); + + // <?... + case Ch('?'): + ++text; // Skip ? + if ((text[0] == Ch('x') || text[0] == Ch('X')) && + (text[1] == Ch('m') || text[1] == Ch('M')) && + (text[2] == Ch('l') || text[2] == Ch('L')) && + whitespace_pred::test(text[3])) + { + // '<?xml ' - xml declaration + text += 4; // Skip 'xml ' + return parse_xml_declaration<Flags>(text); + } + else + { + // Parse PI + return parse_pi<Flags>(text); + } + + // <!... + case Ch('!'): + + // Parse proper subset of <! node + switch (text[1]) + { + + // <!- + case Ch('-'): + if (text[2] == Ch('-')) + { + // '<!--' - xml comment + text += 3; // Skip '!--' + return parse_comment<Flags>(text); + } + break; + + // <![ + case Ch('['): + if (text[2] == Ch('C') && text[3] == Ch('D') && text[4] == Ch('A') && + text[5] == Ch('T') && text[6] == Ch('A') && text[7] == Ch('[')) + { + // '<![CDATA[' - cdata + text += 8; // Skip '![CDATA[' + return parse_cdata<Flags>(text); + } + break; + + // <!D + case Ch('D'): + if (text[2] == Ch('O') && text[3] == Ch('C') && text[4] == Ch('T') && + text[5] == Ch('Y') && text[6] == Ch('P') && text[7] == Ch('E') && + whitespace_pred::test(text[8])) + { + // '<!DOCTYPE ' - doctype + text += 9; // skip '!DOCTYPE ' + return parse_doctype<Flags>(text); + } + + } // switch + + // Attempt to skip other, unrecognized node types starting with <! + ++text; // Skip ! + while (*text != Ch('>')) + { + if (*text == 0) + { + RAPIDXML_PARSE_ERROR("unexpected end of data", text, m_error_arg); + return NULL; + } + ++text; + } + ++text; // Skip '>' + return &m_empty_node; // No node recognized + } + } + + // Parse contents of the node - children, data etc. + template<int Flags> + bool parse_node_contents(Ch *&text, xml_node<Ch> *node) + { + // For all children and text + while (1) + { + // Skip whitespace between > and node contents + Ch *contents_start = text; // Store start of node contents before whitespace is skipped + skip<whitespace_pred, Flags>(text); + Ch next_char = *text; + + // After data nodes, instead of continuing the loop, control jumps here. + // This is because zero termination inside parse_and_append_data() function + // would wreak havoc with the above code. + // Also, skipping whitespace after data nodes is unnecessary. + after_data_node: + + // Determine what comes next: node closing, child node, data node, or 0? + switch (next_char) + { + + // Node closing or child node + case Ch('<'): + if (text[1] == Ch('/')) + { + // Node closing + text += 2; // Skip '</' + if (Flags & parse_validate_closing_tags) + { + // Skip and validate closing tag name + Ch *closing_name = text; + skip<node_name_pred, Flags>(text); + if (!internal::compare(node->name(), node->name_size(), closing_name, text - closing_name, true)) + { + RAPIDXML_PARSE_ERROR("invalid closing tag name", text, m_error_arg); + return false; + } + } + else + { + // No validation, just skip name + skip<node_name_pred, Flags>(text); + } + // Skip remaining whitespace after node name + skip<whitespace_pred, Flags>(text); + if (*text != Ch('>')) + { + RAPIDXML_PARSE_ERROR("expected >", text, m_error_arg); + return false; + } + ++text; // Skip '>' + return true; // Node closed, finished parsing contents + } + else + { + // Child node + ++text; // Skip '<' + xml_node<Ch> *child = parse_node<Flags>(text); + + if (child == NULL) + return NULL; + else if (child != &m_empty_node) + node->append_node(child); + } + break; + + // End of data - error + case Ch('\0'): + RAPIDXML_PARSE_ERROR("unexpected end of data", text, m_error_arg); + return NULL; + + // Data node + default: + if (!parse_and_append_data<Flags>(node, text, contents_start, &next_char)) + return NULL; + + goto after_data_node; // Bypass regular processing after data nodes + + } + } + + return true; + } + + // Parse XML attributes of the node + template<int Flags> + bool parse_node_attributes(Ch *&text, xml_node<Ch> *node) + { + // For all attributes + while (attribute_name_pred::test(*text)) + { + // Extract attribute name + Ch *name = text; + ++text; // Skip first character of attribute name + skip<attribute_name_pred, Flags>(text); + if (text == name) + { + RAPIDXML_PARSE_ERROR("expected attribute name", name, m_error_arg); + return false; + } + + // Create new attribute + xml_attribute<Ch> *attribute = this->allocate_attribute(); + + if (attribute == NULL) + return false; + + attribute->name(name, text - name); + node->append_attribute(attribute); + + // Skip whitespace after attribute name + skip<whitespace_pred, Flags>(text); + + // Skip = + if (*text != Ch('=')) + { + RAPIDXML_PARSE_ERROR("expected =", text, m_error_arg); + return false; + } + ++text; + + // Add terminating zero after name + if (!(Flags & parse_no_string_terminators)) + attribute->name()[attribute->name_size()] = 0; + + // Skip whitespace after = + skip<whitespace_pred, Flags>(text); + + // Skip quote and remember if it was ' or " + Ch quote = *text; + if (quote != Ch('\'') && quote != Ch('"')) + { + RAPIDXML_PARSE_ERROR("expected ' or \"", text, m_error_arg); + return false; + } + ++text; + + // Extract attribute value and expand char refs in it + Ch *value = text, *end; + const int AttFlags = Flags & ~parse_normalize_whitespace; // No whitespace normalization in attributes + if (quote == Ch('\'')) + end = skip_and_expand_character_refs<attribute_value_pred<Ch('\'')>, attribute_value_pure_pred<Ch('\'')>, AttFlags>(text, m_error_arg); + else + end = skip_and_expand_character_refs<attribute_value_pred<Ch('"')>, attribute_value_pure_pred<Ch('"')>, AttFlags>(text, m_error_arg); + + if (end == NULL) + return false; + + // Set attribute value + attribute->value(value, end - value); + + // Make sure that end quote is present + if (*text != quote) + { + RAPIDXML_PARSE_ERROR("expected ' or \"", text, m_error_arg); + return false; + } + ++text; // Skip quote + + // Add terminating zero after value + if (!(Flags & parse_no_string_terminators)) + attribute->value()[attribute->value_size()] = 0; + + // Skip whitespace after attribute value + skip<whitespace_pred, Flags>(text); + } + + return true; + } + + private: + xml_node<Ch> m_empty_node; //We use this &m_empty_node to indicate that we parsed an 'empty' node (such as a comment) + void* m_error_arg; + }; + + //! \cond internal + namespace internal + { + + // Whitespace (space \n \r \t) + template<int Dummy> + const unsigned char lookup_tables<Dummy>::lookup_whitespace[256] = + { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, // 0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1 + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 4 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 5 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 6 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 7 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // A + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // B + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // C + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // D + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // E + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // F + }; + + // Node name (anything but space \n \r \t / > ? \0) + template<int Dummy> + const unsigned char lookup_tables<Dummy>::lookup_node_name[256] = + { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, // 0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, // 2 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, // 3 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F + }; + + // Text (i.e. PCDATA) (anything but < \0) + template<int Dummy> + const unsigned char lookup_tables<Dummy>::lookup_text[256] = + { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 2 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, // 3 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F + }; + + // Text (i.e. PCDATA) that does not require processing when ws normalization is disabled + // (anything but < \0 &) + template<int Dummy> + const unsigned char lookup_tables<Dummy>::lookup_text_pure_no_ws[256] = + { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 + 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 2 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, // 3 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F + }; + + // Text (i.e. PCDATA) that does not require processing when ws normalizationis is enabled + // (anything but < \0 & space \n \r \t) + template<int Dummy> + const unsigned char lookup_tables<Dummy>::lookup_text_pure_with_ws[256] = + { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, // 0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 + 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 2 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, // 3 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F + }; + + // Attribute name (anything but space \n \r \t / < > = ? ! \0) + template<int Dummy> + const unsigned char lookup_tables<Dummy>::lookup_attribute_name[256] = + { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, // 0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 + 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, // 2 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, // 3 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F + }; + + // Attribute data with single quote (anything but ' \0) + template<int Dummy> + const unsigned char lookup_tables<Dummy>::lookup_attribute_data_1[256] = + { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0 + 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, 1, 1, 1, 1, 1, 1, 1, 1, // 2 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 3 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F + }; + + // Attribute data with single quote that does not require processing (anything but ' \0 &) + template<int Dummy> + const unsigned char lookup_tables<Dummy>::lookup_attribute_data_1_pure[256] = + { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0 + 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, 1, 1, 1, 1, 1, 1, 1, 1, // 2 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 3 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F + }; + + // Attribute data with double quote (anything but " \0) + template<int Dummy> + const unsigned char lookup_tables<Dummy>::lookup_attribute_data_2[256] = + { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 + 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 2 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 3 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F + }; + + // Attribute data with double quote that does not require processing (anything but " \0 &) + template<int Dummy> + const unsigned char lookup_tables<Dummy>::lookup_attribute_data_2_pure[256] = + { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 + 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 2 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 3 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F + }; + + // Digits (dec and hex, 255 denotes end of numeric character reference) + template<int Dummy> + const unsigned char lookup_tables<Dummy>::lookup_digits[256] = + { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // 0 + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // 1 + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // 2 + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,255,255,255,255,255,255, // 3 + 255, 10, 11, 12, 13, 14, 15,255,255,255,255,255,255,255,255,255, // 4 + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // 5 + 255, 10, 11, 12, 13, 14, 15,255,255,255,255,255,255,255,255,255, // 6 + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // 7 + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // 8 + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // 9 + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // A + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // B + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // C + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // D + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // E + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255 // F + }; + + // Upper case conversion + template<int Dummy> + const unsigned char lookup_tables<Dummy>::lookup_upcase[256] = + { + // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A B C D E F + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, // 0 + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, // 1 + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, // 2 + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, // 3 + 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, // 4 + 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, // 5 + 96, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, // 6 + 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 123,124,125,126,127, // 7 + 128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, // 8 + 144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159, // 9 + 160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175, // A + 176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191, // B + 192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207, // C + 208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223, // D + 224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239, // E + 240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255 // F + }; + } + //! \endcond + +} + +// Undefine internal macros +#undef RAPIDXML_PARSE_ERROR + +// On MSVC, restore warnings state +#ifdef _MSC_VER + #pragma warning(pop) +#endif + +#endif diff --git a/Lib/Include/rapidxml/rapidxml_iterators.hpp b/Lib/Include/rapidxml/rapidxml_iterators.hpp new file mode 100644 index 0000000..52ebc29 --- /dev/null +++ b/Lib/Include/rapidxml/rapidxml_iterators.hpp @@ -0,0 +1,174 @@ +#ifndef RAPIDXML_ITERATORS_HPP_INCLUDED +#define RAPIDXML_ITERATORS_HPP_INCLUDED + +// Copyright (C) 2006, 2009 Marcin Kalicinski +// Version 1.13 +// Revision $DateTime: 2009/05/13 01:46:17 $ +//! \file rapidxml_iterators.hpp This file contains rapidxml iterators + +#include "rapidxml.hpp" + +namespace rapidxml +{ + + //! Iterator of child nodes of xml_node + template<class Ch> + class node_iterator + { + + public: + + typedef typename xml_node<Ch> value_type; + typedef typename xml_node<Ch> &reference; + typedef typename xml_node<Ch> *pointer; + typedef std::ptrdiff_t difference_type; + typedef std::bidirectional_iterator_tag iterator_category; + + node_iterator() + : m_node(0) + { + } + + node_iterator(xml_node<Ch> *node) + : m_node(node->first_node()) + { + } + + reference operator *() const + { + assert(m_node); + return *m_node; + } + + pointer operator->() const + { + assert(m_node); + return m_node; + } + + node_iterator& operator++() + { + assert(m_node); + m_node = m_node->next_sibling(); + return *this; + } + + node_iterator operator++(int) + { + node_iterator tmp = *this; + ++this; + return tmp; + } + + node_iterator& operator--() + { + assert(m_node && m_node->previous_sibling()); + m_node = m_node->previous_sibling(); + return *this; + } + + node_iterator operator--(int) + { + node_iterator tmp = *this; + ++this; + return tmp; + } + + bool operator ==(const node_iterator<Ch> &rhs) + { + return m_node == rhs.m_node; + } + + bool operator !=(const node_iterator<Ch> &rhs) + { + return m_node != rhs.m_node; + } + + private: + + xml_node<Ch> *m_node; + + }; + + //! Iterator of child attributes of xml_node + template<class Ch> + class attribute_iterator + { + + public: + + typedef typename xml_attribute<Ch> value_type; + typedef typename xml_attribute<Ch> &reference; + typedef typename xml_attribute<Ch> *pointer; + typedef std::ptrdiff_t difference_type; + typedef std::bidirectional_iterator_tag iterator_category; + + attribute_iterator() + : m_attribute(0) + { + } + + attribute_iterator(xml_node<Ch> *node) + : m_attribute(node->first_attribute()) + { + } + + reference operator *() const + { + assert(m_attribute); + return *m_attribute; + } + + pointer operator->() const + { + assert(m_attribute); + return m_attribute; + } + + attribute_iterator& operator++() + { + assert(m_attribute); + m_attribute = m_attribute->next_attribute(); + return *this; + } + + attribute_iterator operator++(int) + { + attribute_iterator tmp = *this; + ++this; + return tmp; + } + + attribute_iterator& operator--() + { + assert(m_attribute && m_attribute->previous_attribute()); + m_attribute = m_attribute->previous_attribute(); + return *this; + } + + attribute_iterator operator--(int) + { + attribute_iterator tmp = *this; + ++this; + return tmp; + } + + bool operator ==(const attribute_iterator<Ch> &rhs) + { + return m_attribute == rhs.m_attribute; + } + + bool operator !=(const attribute_iterator<Ch> &rhs) + { + return m_attribute != rhs.m_attribute; + } + + private: + + xml_attribute<Ch> *m_attribute; + + }; + +} + +#endif diff --git a/Lib/Include/rapidxml/rapidxml_print.hpp b/Lib/Include/rapidxml/rapidxml_print.hpp new file mode 100644 index 0000000..0ae2b14 --- /dev/null +++ b/Lib/Include/rapidxml/rapidxml_print.hpp @@ -0,0 +1,421 @@ +#ifndef RAPIDXML_PRINT_HPP_INCLUDED +#define RAPIDXML_PRINT_HPP_INCLUDED + +// Copyright (C) 2006, 2009 Marcin Kalicinski +// Version 1.13 +// Revision $DateTime: 2009/05/13 01:46:17 $ +//! \file rapidxml_print.hpp This file contains rapidxml printer implementation + +#include "rapidxml.hpp" + +// Only include streams if not disabled +#ifndef RAPIDXML_NO_STREAMS + #include <ostream> + #include <iterator> +#endif + +namespace rapidxml +{ + + /////////////////////////////////////////////////////////////////////// + // Printing flags + + const int print_no_indenting = 0x1; //!< Printer flag instructing the printer to suppress indenting of XML. See print() function. + + /////////////////////////////////////////////////////////////////////// + // Internal + + //! \cond internal + namespace internal + { + + /////////////////////////////////////////////////////////////////////////// + // Internal character operations + + // Copy characters from given range to given output iterator + template<class OutIt, class Ch> + inline OutIt copy_chars(const Ch *begin, const Ch *end, OutIt out) + { + while (begin != end) + *out++ = *begin++; + return out; + } + + // Copy characters from given range to given output iterator and expand + // characters into references (< > ' " &) + template<class OutIt, class Ch> + inline OutIt copy_and_expand_chars(const Ch *begin, const Ch *end, Ch noexpand, OutIt out) + { + while (begin != end) + { + if (*begin == noexpand) + { + *out++ = *begin; // No expansion, copy character + } + else + { + switch (*begin) + { + case Ch('<'): + *out++ = Ch('&'); *out++ = Ch('l'); *out++ = Ch('t'); *out++ = Ch(';'); + break; + case Ch('>'): + *out++ = Ch('&'); *out++ = Ch('g'); *out++ = Ch('t'); *out++ = Ch(';'); + break; + case Ch('\''): + *out++ = Ch('&'); *out++ = Ch('a'); *out++ = Ch('p'); *out++ = Ch('o'); *out++ = Ch('s'); *out++ = Ch(';'); + break; + case Ch('"'): + *out++ = Ch('&'); *out++ = Ch('q'); *out++ = Ch('u'); *out++ = Ch('o'); *out++ = Ch('t'); *out++ = Ch(';'); + break; + case Ch('&'): + *out++ = Ch('&'); *out++ = Ch('a'); *out++ = Ch('m'); *out++ = Ch('p'); *out++ = Ch(';'); + break; + default: + *out++ = *begin; // No expansion, copy character + } + } + ++begin; // Step to next character + } + return out; + } + + // Fill given output iterator with repetitions of the same character + template<class OutIt, class Ch> + inline OutIt fill_chars(OutIt out, int n, Ch ch) + { + for (int i = 0; i < n; ++i) + *out++ = ch; + return out; + } + + // Find character + template<class Ch, Ch ch> + inline bool find_char(const Ch *begin, const Ch *end) + { + while (begin != end) + if (*begin++ == ch) + return true; + return false; + } + + /////////////////////////////////////////////////////////////////////////// + // Internal printing operations + + // Print node + template<class OutIt, class Ch> + inline OutIt print_node(OutIt out, const xml_node<Ch> *node, int flags, int indent) + { + // Print proper node type + switch (node->type()) + { + + // Document + case node_document: + out = print_children(out, node, flags, indent); + break; + + // Element + case node_element: + out = print_element_node(out, node, flags, indent); + break; + + // Data + case node_data: + out = print_data_node(out, node, flags, indent); + break; + + // CDATA + case node_cdata: + out = print_cdata_node(out, node, flags, indent); + break; + + // Declaration + case node_declaration: + out = print_declaration_node(out, node, flags, indent); + break; + + // Comment + case node_comment: + out = print_comment_node(out, node, flags, indent); + break; + + // Doctype + case node_doctype: + out = print_doctype_node(out, node, flags, indent); + break; + + // Pi + case node_pi: + out = print_pi_node(out, node, flags, indent); + break; + + // Unknown + default: + assert(0); + break; + } + + // If indenting not disabled, add line break after node + if (!(flags & print_no_indenting)) + *out = Ch('\n'), ++out; + + // Return modified iterator + return out; + } + + // Print children of the node + template<class OutIt, class Ch> + inline OutIt print_children(OutIt out, const xml_node<Ch> *node, int flags, int indent) + { + for (xml_node<Ch> *child = node->first_node(); child; child = child->next_sibling()) + out = print_node(out, child, flags, indent); + return out; + } + + // Print attributes of the node + template<class OutIt, class Ch> + inline OutIt print_attributes(OutIt out, const xml_node<Ch> *node, int flags) + { + for (xml_attribute<Ch> *attribute = node->first_attribute(); attribute; attribute = attribute->next_attribute()) + { + if (attribute->name() && attribute->value()) + { + // Print attribute name + *out = Ch(' '), ++out; + out = copy_chars(attribute->name(), attribute->name() + attribute->name_size(), out); + *out = Ch('='), ++out; + // Print attribute value using appropriate quote type + if (find_char<Ch, Ch('"')>(attribute->value(), attribute->value() + attribute->value_size())) + { + *out = Ch('\''), ++out; + out = copy_and_expand_chars(attribute->value(), attribute->value() + attribute->value_size(), Ch('"'), out); + *out = Ch('\''), ++out; + } + else + { + *out = Ch('"'), ++out; + out = copy_and_expand_chars(attribute->value(), attribute->value() + attribute->value_size(), Ch('\''), out); + *out = Ch('"'), ++out; + } + } + } + return out; + } + + // Print data node + template<class OutIt, class Ch> + inline OutIt print_data_node(OutIt out, const xml_node<Ch> *node, int flags, int indent) + { + assert(node->type() == node_data); + if (!(flags & print_no_indenting)) + out = fill_chars(out, indent, Ch('\t')); + out = copy_and_expand_chars(node->value(), node->value() + node->value_size(), Ch(0), out); + return out; + } + + // Print data node + template<class OutIt, class Ch> + inline OutIt print_cdata_node(OutIt out, const xml_node<Ch> *node, int flags, int indent) + { + assert(node->type() == node_cdata); + if (!(flags & print_no_indenting)) + out = fill_chars(out, indent, Ch('\t')); + *out = Ch('<'); ++out; + *out = Ch('!'); ++out; + *out = Ch('['); ++out; + *out = Ch('C'); ++out; + *out = Ch('D'); ++out; + *out = Ch('A'); ++out; + *out = Ch('T'); ++out; + *out = Ch('A'); ++out; + *out = Ch('['); ++out; + out = copy_chars(node->value(), node->value() + node->value_size(), out); + *out = Ch(']'); ++out; + *out = Ch(']'); ++out; + *out = Ch('>'); ++out; + return out; + } + + // Print element node + template<class OutIt, class Ch> + inline OutIt print_element_node(OutIt out, const xml_node<Ch> *node, int flags, int indent) + { + assert(node->type() == node_element); + + // Print element name and attributes, if any + if (!(flags & print_no_indenting)) + out = fill_chars(out, indent, Ch('\t')); + *out = Ch('<'), ++out; + out = copy_chars(node->name(), node->name() + node->name_size(), out); + out = print_attributes(out, node, flags); + + // If node is childless + if (node->value_size() == 0 && !node->first_node()) + { + // Print childless node tag ending + *out = Ch('/'), ++out; + *out = Ch('>'), ++out; + } + else + { + // Print normal node tag ending + *out = Ch('>'), ++out; + + // Test if node contains a single data node only (and no other nodes) + xml_node<Ch> *child = node->first_node(); + if (!child) + { + // If node has no children, only print its value without indenting + out = copy_and_expand_chars(node->value(), node->value() + node->value_size(), Ch(0), out); + } + else if (child->next_sibling() == 0 && child->type() == node_data) + { + // If node has a sole data child, only print its value without indenting + out = copy_and_expand_chars(child->value(), child->value() + child->value_size(), Ch(0), out); + } + else + { + // Print all children with full indenting + if (!(flags & print_no_indenting)) + *out = Ch('\n'), ++out; + out = print_children(out, node, flags, indent + 1); + if (!(flags & print_no_indenting)) + out = fill_chars(out, indent, Ch('\t')); + } + + // Print node end + *out = Ch('<'), ++out; + *out = Ch('/'), ++out; + out = copy_chars(node->name(), node->name() + node->name_size(), out); + *out = Ch('>'), ++out; + } + return out; + } + + // Print declaration node + template<class OutIt, class Ch> + inline OutIt print_declaration_node(OutIt out, const xml_node<Ch> *node, int flags, int indent) + { + // Print declaration start + if (!(flags & print_no_indenting)) + out = fill_chars(out, indent, Ch('\t')); + *out = Ch('<'), ++out; + *out = Ch('?'), ++out; + *out = Ch('x'), ++out; + *out = Ch('m'), ++out; + *out = Ch('l'), ++out; + + // Print attributes + out = print_attributes(out, node, flags); + + // Print declaration end + *out = Ch('?'), ++out; + *out = Ch('>'), ++out; + + return out; + } + + // Print comment node + template<class OutIt, class Ch> + inline OutIt print_comment_node(OutIt out, const xml_node<Ch> *node, int flags, int indent) + { + assert(node->type() == node_comment); + if (!(flags & print_no_indenting)) + out = fill_chars(out, indent, Ch('\t')); + *out = Ch('<'), ++out; + *out = Ch('!'), ++out; + *out = Ch('-'), ++out; + *out = Ch('-'), ++out; + out = copy_chars(node->value(), node->value() + node->value_size(), out); + *out = Ch('-'), ++out; + *out = Ch('-'), ++out; + *out = Ch('>'), ++out; + return out; + } + + // Print doctype node + template<class OutIt, class Ch> + inline OutIt print_doctype_node(OutIt out, const xml_node<Ch> *node, int flags, int indent) + { + assert(node->type() == node_doctype); + if (!(flags & print_no_indenting)) + out = fill_chars(out, indent, Ch('\t')); + *out = Ch('<'), ++out; + *out = Ch('!'), ++out; + *out = Ch('D'), ++out; + *out = Ch('O'), ++out; + *out = Ch('C'), ++out; + *out = Ch('T'), ++out; + *out = Ch('Y'), ++out; + *out = Ch('P'), ++out; + *out = Ch('E'), ++out; + *out = Ch(' '), ++out; + out = copy_chars(node->value(), node->value() + node->value_size(), out); + *out = Ch('>'), ++out; + return out; + } + + // Print pi node + template<class OutIt, class Ch> + inline OutIt print_pi_node(OutIt out, const xml_node<Ch> *node, int flags, int indent) + { + assert(node->type() == node_pi); + if (!(flags & print_no_indenting)) + out = fill_chars(out, indent, Ch('\t')); + *out = Ch('<'), ++out; + *out = Ch('?'), ++out; + out = copy_chars(node->name(), node->name() + node->name_size(), out); + *out = Ch(' '), ++out; + out = copy_chars(node->value(), node->value() + node->value_size(), out); + *out = Ch('?'), ++out; + *out = Ch('>'), ++out; + return out; + } + + } + //! \endcond + + /////////////////////////////////////////////////////////////////////////// + // Printing + + //! Prints XML to given output iterator. + //! \param out Output iterator to print to. + //! \param node Node to be printed. Pass xml_document to print entire document. + //! \param flags Flags controlling how XML is printed. + //! \return Output iterator pointing to position immediately after last character of printed text. + template<class OutIt, class Ch> + inline OutIt print(OutIt out, const xml_node<Ch> &node, int flags = 0) + { + return internal::print_node(out, &node, flags, 0); + } + +#ifndef RAPIDXML_NO_STREAMS + + //! Prints XML to given output stream. + //! \param out Output stream to print to. + //! \param node Node to be printed. Pass xml_document to print entire document. + //! \param flags Flags controlling how XML is printed. + //! \return Output stream. + template<class Ch> + inline std::basic_ostream<Ch> &print(std::basic_ostream<Ch> &out, const xml_node<Ch> &node, int flags = 0) + { + print(std::ostream_iterator<Ch>(out), node, flags); + return out; + } + + //! Prints formatted XML to given output stream. Uses default printing flags. Use print() function to customize printing process. + //! \param out Output stream to print to. + //! \param node Node to be printed. + //! \return Output stream. + template<class Ch> + inline std::basic_ostream<Ch> &operator <<(std::basic_ostream<Ch> &out, const xml_node<Ch> &node) + { + return print(out, node); + } + +#endif + +} + +#endif diff --git a/Lib/Include/rapidxml/rapidxml_utils.hpp b/Lib/Include/rapidxml/rapidxml_utils.hpp new file mode 100644 index 0000000..37c2953 --- /dev/null +++ b/Lib/Include/rapidxml/rapidxml_utils.hpp @@ -0,0 +1,122 @@ +#ifndef RAPIDXML_UTILS_HPP_INCLUDED +#define RAPIDXML_UTILS_HPP_INCLUDED + +// Copyright (C) 2006, 2009 Marcin Kalicinski +// Version 1.13 +// Revision $DateTime: 2009/05/13 01:46:17 $ +//! \file rapidxml_utils.hpp This file contains high-level rapidxml utilities that can be useful +//! in certain simple scenarios. They should probably not be used if maximizing performance is the main objective. + +#include "rapidxml.hpp" +#include <vector> +#include <string> +#include <fstream> +#include <stdexcept> + +namespace rapidxml +{ + + //! Represents data loaded from a file + template<class Ch = char> + class file + { + + public: + + //! Loads file into the memory. Data will be automatically destroyed by the destructor. + //! \param filename Filename to load. + file(const char *filename) + { + using namespace std; + + // Open stream + basic_ifstream<Ch> stream(filename, ios::binary); + if (!stream) + throw runtime_error(string("cannot open file ") + filename); + stream.unsetf(ios::skipws); + + // Determine stream size + stream.seekg(0, ios::end); + size_t size = stream.tellg(); + stream.seekg(0); + + // Load data and add terminating 0 + m_data.resize(size + 1); + stream.read(&m_data.front(), static_cast<streamsize>(size)); + m_data[size] = 0; + } + + //! Loads file into the memory. Data will be automatically destroyed by the destructor + //! \param stream Stream to load from + file(std::basic_istream<Ch> &stream) + { + using namespace std; + + // Load data and add terminating 0 + stream.unsetf(ios::skipws); + m_data.assign(istreambuf_iterator<Ch>(stream), istreambuf_iterator<Ch>()); + if (stream.fail() || stream.bad()) + throw runtime_error("error reading stream"); + m_data.push_back(0); + } + + //! Gets file data. + //! \return Pointer to data of file. + Ch *data() + { + return &m_data.front(); + } + + //! Gets file data. + //! \return Pointer to data of file. + const Ch *data() const + { + return &m_data.front(); + } + + //! Gets file data size. + //! \return Size of file data, in characters. + std::size_t size() const + { + return m_data.size(); + } + + private: + + std::vector<Ch> m_data; // File data + + }; + + //! Counts children of node. Time complexity is O(n). + //! \return Number of children of node + template<class Ch> + inline std::size_t count_children(xml_node<Ch> *node) + { + xml_node<Ch> *child = node->first_node(); + std::size_t count = 0; + while (child) + { + ++count; + child = child->next_sibling(); + } + return count; + } + + //! Counts attributes of node. Time complexity is O(n). + //! \return Number of attributes of node + template<class Ch> + inline std::size_t count_attributes(xml_node<Ch> *node) + { + xml_attribute<Ch> *attr = node->first_attribute(); + std::size_t count = 0; + while (attr) + { + ++count; + attr = attr->next_attribute(); + } + return count; + } + +} + +#endif diff --git a/Lib/Include/zconf.h b/Lib/Include/zconf.h new file mode 100644 index 0000000..80be12c --- /dev/null +++ b/Lib/Include/zconf.h @@ -0,0 +1,507 @@ +/* zconf.h -- configuration of the zlib compression library + * Copyright (C) 1995-2012 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#ifndef ZCONF_H +#define ZCONF_H + +#define ZLIB_DLL +/* + * 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_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 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 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 <windows.h> + /* 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 + +/* ./configure may #define Z_U4 here */ + +#if !defined(Z_U4) && !defined(Z_SOLO) && defined(STDC) +# include <limits.h> +# if (UINT_MAX == 0xffffffffUL) +# define Z_U4 unsigned +# else +# if (ULONG_MAX == 0xffffffffUL) +# define Z_U4 unsigned long +# else +# if (USHRT_MAX == 0xffffffffUL) +# define Z_U4 unsigned short +# endif +# endif +# 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 <sys/types.h> /* for off_t */ +# endif +#endif + +#ifdef _WIN32 +# include <stddef.h> /* for wchar_t */ +#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 <unistd.h> /* for SEEK_*, off_t, and _LFS64_LARGEFILE */ +# ifdef VMS +# include <unixio.h> /* 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/Lib/Include/zlib.h b/Lib/Include/zlib.h new file mode 100644 index 0000000..3edf3ac --- /dev/null +++ b/Lib/Include/zlib.h @@ -0,0 +1,1744 @@ +/* zlib.h -- interface of the 'zlib' general purpose compression library + version 1.2.7, May 2nd, 2012 + + Copyright (C) 1995-2012 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.7" +#define ZLIB_VERNUM 0x1270 +#define ZLIB_VER_MAJOR 1 +#define ZLIB_VER_MINOR 2 +#define ZLIB_VER_REVISION 7 +#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 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 occurences 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 *, 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 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. This + function 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 + +#ifdef __cplusplus +} +#endif + +#endif /* ZLIB_H */ diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..d7a7739 --- /dev/null +++ b/Makefile @@ -0,0 +1,206 @@ +# Makefile +# Author: Patrick Baggett <ptbaggett@762studios.com> +# Created: 12/20/2011 +# +# Purpose: +# +# Main makefile for 762 Studios. Requires GNU Make +# +# License: +# +# This program is free software. It comes without any warranty, to +# the extent permitted by applicable law. You can redistribute it +# and/or modify it under the terms of the Do What The Fuck You Want +# To Public License, Version 2, as published by Sam Hocevar. See +# http://sam.zoy.org/wtfpl/COPYING for more details. + +ROOTDIR := $(shell pwd) + +.PHONY: atomic concurrency crypto math random os net zutil ztestsuite catandmouse rubeconvert gltest + +# This sets flags for the type of compiler in use. +# Sets IS_GCC, IS_ICC or IS_CC. +include BuildConfig/DetectCompiler.rules + +#Detect platform (OS + architecture) +# -> This sets $OS and $ARCH for us. +include BuildConfig/DetectPlatform.rules + +#Include platform specific build rules +include BuildConfig/Makefile.$(OS).$(ARCH) + +#Detect libraries associated with this platform +LIB_RULES ?=Libs +include BuildConfig/Detect$(LIB_RULES).rules + +PLATFORM := $(OS)-$(ARCH) + +#Make distribution folder for libs +DIST ?= $(ROOTDIR)/Bin/$(ARCH) +$(shell mkdir -p $(DIST)) + +override LDFLAGS += $(OS_LDFLAGS) +override CXXFLAGS += $(OS_CXXFLAGS) -I$(ROOTDIR)/Include -I$(ROOTDIR)/Lib/Include +override CFLAGS += $(OS_CFLAGS) -I$(ROOTDIR)/Include -I$(ROOTDIR)/Lib/Include + +export #Make sure sub-makes get the variables + +release: + @echo Building ZEngine in \"Release\" mode for $(PLATFORM) + $(MAKE) -C libsst-atomic TARGET=release + $(MAKE) -C libsst-concurrency TARGET=release + $(MAKE) -C libsst-os TARGET=release + $(MAKE) -C libsst-crypto TARGET=release + $(MAKE) -C libsst-random TARGET=release + $(MAKE) -C libsst-math TARGET=release all + $(MAKE) -C libsst-net TARGET=release + $(MAKE) -C libsst-glapi TARGET=release + $(MAKE) -C libsst-wm TARGET=release + $(MAKE) -C ZUtil TARGET=release + $(MAKE) -C ZNet TARGET=release + $(MAKE) -C ZTestSuite TARGET=release + $(MAKE) -C "Test App - LSystem" TARGET=release + $(MAKE) -C "Test App - WM" TARGET=release + +debug: + @echo Building ZEngine in \"Debug\" mode for $(PLATFORM) + $(MAKE) -C libsst-atomic CFLAGS="$(CFLAGS) -g -D_DEBUG" TARGET=debug + $(MAKE) -C libsst-concurrency CFLAGS="$(CFLAGS) -g -D_DEBUG" TARGET=debug + $(MAKE) -C libsst-os CFLAGS="$(CFLAGS) -g -D_DEBUG" TARGET=debug + $(MAKE) -C libsst-crypto CFLAGS="$(CFLAGS) -g -D_DEBUG" TARGET=debug + $(MAKE) -C libsst-random CFLAGS="$(CFLAGS) -g -D_DEBUG" TARGET=debug + $(MAKE) -C libsst-math CFLAGS="$(CFLAGS) -g -D_DEBUG" TARGET=debug all + $(MAKE) -C libsst-net CFLAGS="$(CFLAGS) -g -D_DEBUG" TARGET=debug + $(MAKE) -C libsst-glapi CFLAGS="$(CFLAGS) -g -D_DEBUG" TARGET=debug + $(MAKE) -C libsst-wm CFLAGS="$(CFLAGS) -g -D_DEBUG" TARGET=debug + $(MAKE) -C ZUtil CXXFLAGS="$(CXXFLAGS) -g -D_DEBUG" TARGET=debug + $(MAKE) -C ZNet CXXFLAGS="$(CXXFLAGS) -g -D_DEBUG" TARGET=debug + $(MAKE) -C ZTestSuite CXXFLAGS="$(CXXFLAGS) -g -D_DEBUG" TARGET=debug + $(MAKE) -C "Test App - LSystem" CXXFLAGS="$(CXXFLAGS) -g -D_DEBUG" TARGET=debug + $(MAKE) -C "Test App - WM" CFLAGS="$(CFLAGS) -g -D_DEBUG" TARGET=debug + +clean: + @echo Cleaning ZEngine. + $(MAKE) -C libsst-atomic clean + $(MAKE) -C libsst-concurrency clean + $(MAKE) -C libsst-os clean + $(MAKE) -C libsst-crypto clean + $(MAKE) -C libsst-random clean + $(MAKE) -C libsst-math clean + $(MAKE) -C libsst-net clean + $(MAKE) -C libsst-glapi clean + $(MAKE) -C libsst-wm clean + $(MAKE) -C ZUtil clean + $(MAKE) -C ZTestSuite clean + $(MAKE) -C ZNet clean + $(MAKE) -C "Test App - LSystem" clean + $(MAKE) -C "Test App - WM" clean + $(MAKE) -C CatAndMouse clean + $(MAKE) -C Salvage clean + +cleanall: clean + $(MAKE) -C libsst-math code + +math: + @echo Building libsst-$@ in \"Debug\" mode for $(PLATFORM) + $(MAKE) -C libsst-$@ CFLAGS="$(CFLAGS)" TARGET=release all + +atomic: + @echo Building libsst-$@ in \"Debug\" mode for $(PLATFORM) + $(MAKE) -C libsst-$@ CFLAGS="$(CFLAGS)" TARGET=release + +os: + @echo Building libsst-$@ in \"Debug\" mode for $(PLATFORM) + $(MAKE) -C libsst-$@ CFLAGS="$(CFLAGS)" TARGET=release + +crypto: + @echo Building libsst-$@ in \"Debug\" mode for $(PLATFORM) + $(MAKE) -C libsst-$@ CFLAGS="$(CFLAGS)" TARGET=release + +random: + @echo Building libsst-$@ in \"Debug\" mode for $(PLATFORM) + $(MAKE) -C libsst-$@ CFLAGS="$(CFLAGS)" TARGET=release + +concurrency: + @echo Building libsst-$@ in \"Debug\" mode for $(PLATFORM) + $(MAKE) -C libsst-$@ CFLAGS="$(CFLAGS)" TARGET=release + +net: + @echo Building libsst-$@ in \"Debug\" mode for $(PLATFORM) + $(MAKE) -C libsst-$@ CFLAGS="$(CFLAGS)" TARGET=release + +glapi: + @echo Building libsst-$@ in \"Debug\" mode for $(PLATFORM) + $(MAKE) -C libsst-$@ CFLAGS="$(CFLAGS)" TARGET=release + +wm: + @echo Building libsst-$@ in \"Release\" mode for $(PLATFORM) + $(MAKE) -C libsst-$@ CFLAGS="$(CFLAGS)" TARGET=release + +wm-debug: debug + @echo Building libsst-wm in \"Debug\" mode for $(PLATFORM) + $(MAKE) -C libsst-wm CFLAGS="$(CFLAGS) -g -D_DEBUG" TARGET=debug + +clobber: + @echo Cleaning All Auto-Generated Code + $(MAKE) -C libsst-math code + +ztestsuite: math atomic os crypto random concurrency net zutil + @echo Building $@ in \"Debug\" mode for $(PLATFORM) + $(MAKE) -C ZTestSuite CXXFLAGS="$(CXXFLAGS)" TARGET=release + +zutil: + @echo Building $@ in \"Release\" mode for $(PLATFORM) + $(MAKE) -C ZUtil CFLAGS="$(CFLAGS)" TARGET=release + +znet: + @echo Building $@ in \"Release\" mode for $(PLATFORM) + $(MAKE) -C ZNet CFLAGS="$(CFLAGS)" TARGET=release + +lsystem: + @echo Building $@ in \"Debug\" mode for $(PLATFORM) + $(MAKE) -C "Test App - LSystem" CXXFLAGS="$(CXXFLAGS)" TARGET=release + +wm-test: + @echo Building $@ in \"Release\" mode for $(PLATFORM) + $(MAKE) -C "Test App - WM" TARGET=release + +rubeconvert: + @echo "Building RUBEConvert" + $(MAKE) -C RUBEConvert TARGET=release + +gltest: + @echo "Building gltest" + $(MAKE) -C gltest TARGET=release + +gltest-debug: debug + @echo "Build gltest debug" + $(MAKE) -C gltest CFLAGS="$(CFLAGS) -g -D_DEBUG" TARGET=debug + +cm-debug: debug + @echo Building Cat and Mouse Debug Client + $(MAKE) -C CatAndMouse TARGET=debug + +cm-release: release + @echo Building Cat and Mouse Release Client + $(MAKE) -C CatAndMouse TARGET=release + +cm-ded-debug: debug + @echo Building Cat and Mouse Debug Dedicated Server + $(MAKE) -C CatAndMouse TARGET=ded-debug + +cm-ded-release: release + @echo Building Cat and Mouse Release Dedicated Server + $(MAKE) -C CatAndMouse TARGET=ded-release + +salvage-debug: debug + @echo Building Salvage Debug Mode for $(PLATFORM) + $(MAKE) -C Salvage TARGET=debug + +salvage-release: release + @echo Building Salvage Release Mode for $(PLATFORM) + $(MAKE) -C Salvage TARGET=release + + +all: release debug + diff --git a/README.md b/README.md new file mode 100644 index 0000000..ffb9ced --- /dev/null +++ b/README.md @@ -0,0 +1,79 @@ +# libsst / ZEngine + +**Version 0.6.0** | **762 Studios** | **WTFPL v2** + +A cross-platform C++ game engine library providing low-level system +abstractions, math, networking, rendering, and an entity-component simulation +framework. Originally developed circa 2011-2013. + +## Modules + +### Low-level C libraries (`libsst-*`) + +| Module | Description | +|---|---| +| **libsst-atomic** | Atomic operations for lock-free programming | +| **libsst-concurrency** | Threads, mutexes, events, semaphores, read-write locks, TLS | +| **libsst-crypto** | Hash functions and cryptographic utilities | +| **libsst-glapi** | OpenGL 3.3 context management and function loading | +| **libsst-math** | Vectors (2/3/4), matrices (2x2/3x3/4x4), geometry, transforms | +| **libsst-net** | Cross-platform socket abstraction (TCP/UDP) | +| **libsst-os** | File I/O, memory mapping, dynamic libraries, timing, CPU info | +| **libsst-random** | Mersenne Twister, CMWC, small PRNG, simplex noise | +| **libsst-wm** | Window creation, input events, OpenGL context, display modes | + +### High-level C++ libraries + +| Module | Description | +|---|---| +| **ZUtil** | RAII wrappers around libsst, custom containers (ZArray, ZList, ZHashMap, ZRingBuffer, ZString), smart pointers, serialization (JSON, XML, INI, binary), logging, slab allocation, task streams | +| **ZNet** | Client/server networking built on enet with packet channels, bandwidth metering, and peer management | +| **ZRenderer** | OpenGL rendering abstraction: shaders, textures, data buffers, render targets, render state | +| **ZRendererUtil** | Font rendering, particle systems, static mesh loading (assimp), tessellation, camera, transform hierarchies | +| **ZSimulation** | Entity-component framework with fixed-timestep updates, entity messaging, property buffers, and network synchronization | + +## Platform support + +- **OS:** Windows, Linux, macOS, Solaris, Android, Raspberry Pi +- **Architectures:** x86, x86-64, ARM, IA64, MIPS, PPC, SPARC +- **Compilers:** GCC, ICC, MSVC, Sun Pro + +## Building (GNU Make, non-Windows) + +```sh +make release # release build for detected platform +make debug # debug build +make clean # clean artifacts +``` + +Output goes to `Bin/<arch>/`. + +## Third-party dependencies + +Bundled under `Lib/Include/`: + +- Box2D (physics) +- CML (configurable math) +- OpenAL / FMOD (audio) +- assimp (model import) +- enet (reliable UDP) +- FreeType (font rasterization) +- RapidXML (XML parsing) +- ZSTL (custom STL containers) + +## Tests + +```sh +make ztestsuite +``` + +Covers math types, containers, memory allocation, smart pointers, I/O, +concurrency, random number generation, and noise. + +## Authors + +James Russell, Patrick Baggett, Chris Ertel, and contributors at 762 Studios. + +## License + +[WTFPL v2](http://www.wtfpl.net/) -- Do What The Fuck You Want To Public License. diff --git a/ZNet/Makefile b/ZNet/Makefile new file mode 100644 index 0000000..2bbf21d --- /dev/null +++ b/ZNet/Makefile @@ -0,0 +1,34 @@ +# ZNet/Makefile +# Makefile for ZNet, requires GNU "make" + +BINNAME := $(DIST)/libZNet.a +ifeq ($(TARGET),debug) + BINNAME := $(subst .a,_d.a, $(BINNAME)) +endif + +SRC := \ + ZNetBandwidthMeter.cpp \ + ZNetClient.cpp \ + ZNetHost.cpp \ + ZNetPacketChannel.cpp \ + ZNetPeer.cpp \ + ZNetPrivate.cpp \ + ZNetServer.cpp + +OBJ := $(addprefix obj/$(ARCH)/$(TARGET)/,$(subst .cpp,.o,$(SRC)) ) + +$(shell mkdir -p obj/$(ARCH)/$(TARGET)) + +$(BINNAME): $(OBJ) + $(AR) cru $@ $+ + $(RANLIB) $@ + +# CLEAN +clean: + @-rm -r -f obj $(DIST)/libZNet*.a + + +# *.cpp files to *.o files +obj/$(ARCH)/$(TARGET)/%.o: %.cpp + @echo CXX $@ + @$(CXX) $(CXXFLAGS) -c $*.cpp -o obj/$(ARCH)/$(TARGET)/$*.o diff --git a/ZNet/ZNet.vcxproj b/ZNet/ZNet.vcxproj new file mode 100644 index 0000000..f672b84 --- /dev/null +++ b/ZNet/ZNet.vcxproj @@ -0,0 +1,200 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup Label="ProjectConfigurations"> + <ProjectConfiguration Include="Debug|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectGuid>{76D72C18-B505-4D8C-B146-5348F6E5CA12}</ProjectGuid> + <RootNamespace>ZNet</RootNamespace> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> + <ConfigurationType>StaticLibrary</ConfigurationType> + <UseDebugLibraries>true</UseDebugLibraries> + <PlatformToolset>v110</PlatformToolset> + <CharacterSet>MultiByte</CharacterSet> + <WholeProgramOptimization>true</WholeProgramOptimization> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> + <ConfigurationType>StaticLibrary</ConfigurationType> + <UseDebugLibraries>true</UseDebugLibraries> + <PlatformToolset>v110</PlatformToolset> + <CharacterSet>MultiByte</CharacterSet> + <WholeProgramOptimization>true</WholeProgramOptimization> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> + <ConfigurationType>StaticLibrary</ConfigurationType> + <UseDebugLibraries>false</UseDebugLibraries> + <PlatformToolset>v110</PlatformToolset> + <WholeProgramOptimization>true</WholeProgramOptimization> + <CharacterSet>MultiByte</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> + <ConfigurationType>StaticLibrary</ConfigurationType> + <UseDebugLibraries>false</UseDebugLibraries> + <PlatformToolset>v110</PlatformToolset> + <WholeProgramOptimization>true</WholeProgramOptimization> + <CharacterSet>MultiByte</CharacterSet> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <ImportGroup Label="ExtensionSettings"> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <PropertyGroup Label="UserMacros" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <IncludePath>$(SolutionDir)Include;$(SolutionDir)Lib\Include;$(IncludePath)</IncludePath> + <OutDir>$(SolutionDir)Bin\x86\</OutDir> + <IntDir>$(SolutionDir)Intermediate\$(Configuration)\$(Platform)\$(ProjectName)\</IntDir> + <TargetName>$(ProjectName)-debug</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <IncludePath>$(SolutionDir)Include;$(SolutionDir)Lib\Include;$(IncludePath)</IncludePath> + <OutDir>$(SolutionDir)Bin\x86\</OutDir> + <IntDir>$(SolutionDir)Intermediate\$(Configuration)\$(Platform)\$(ProjectName)\</IntDir> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <IncludePath>$(SolutionDir)Include;$(SolutionDir)Lib\Include;$(IncludePath)</IncludePath> + <OutDir>$(SolutionDir)Bin\x64\</OutDir> + <IntDir>$(SolutionDir)Intermediate\$(Configuration)\$(Platform)\$(ProjectName)\</IntDir> + <TargetName>$(ProjectName)-debug</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <IncludePath>$(SolutionDir)Include;$(SolutionDir)Lib\Include;$(IncludePath)</IncludePath> + <OutDir>$(SolutionDir)Bin\x64\</OutDir> + <IntDir>$(SolutionDir)Intermediate\$(Configuration)\$(Platform)\$(ProjectName)\</IntDir> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <WarningLevel>Level4</WarningLevel> + <Optimization>Disabled</Optimization> + <StringPooling>true</StringPooling> + <MinimalRebuild>false</MinimalRebuild> + <ExceptionHandling>false</ExceptionHandling> + <BufferSecurityCheck>false</BufferSecurityCheck> + <CreateHotpatchableImage>false</CreateHotpatchableImage> + <RuntimeTypeInfo>false</RuntimeTypeInfo> + <OpenMPSupport>false</OpenMPSupport> + <MultiProcessorCompilation>true</MultiProcessorCompilation> + <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> + </ClCompile> + <Link> + <GenerateDebugInformation>true</GenerateDebugInformation> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ClCompile> + <WarningLevel>Level4</WarningLevel> + <Optimization>Disabled</Optimization> + <StringPooling>true</StringPooling> + <MinimalRebuild>false</MinimalRebuild> + <ExceptionHandling>false</ExceptionHandling> + <BufferSecurityCheck>false</BufferSecurityCheck> + <CreateHotpatchableImage>false</CreateHotpatchableImage> + <RuntimeTypeInfo>false</RuntimeTypeInfo> + <OpenMPSupport>false</OpenMPSupport> + <MultiProcessorCompilation>true</MultiProcessorCompilation> + </ClCompile> + <Link> + <GenerateDebugInformation>true</GenerateDebugInformation> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <WarningLevel>Level4</WarningLevel> + <Optimization>MaxSpeed</Optimization> + <FunctionLevelLinking>true</FunctionLevelLinking> + <IntrinsicFunctions>true</IntrinsicFunctions> + <StringPooling>true</StringPooling> + <ExceptionHandling>false</ExceptionHandling> + <BufferSecurityCheck>false</BufferSecurityCheck> + <CreateHotpatchableImage>false</CreateHotpatchableImage> + <RuntimeTypeInfo>false</RuntimeTypeInfo> + <OpenMPSupport>false</OpenMPSupport> + <MultiProcessorCompilation>true</MultiProcessorCompilation> + <DebugInformationFormat>None</DebugInformationFormat> + </ClCompile> + <Link> + <GenerateDebugInformation>true</GenerateDebugInformation> + <EnableCOMDATFolding>true</EnableCOMDATFolding> + <OptimizeReferences>true</OptimizeReferences> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ClCompile> + <WarningLevel>Level4</WarningLevel> + <Optimization>MaxSpeed</Optimization> + <FunctionLevelLinking>true</FunctionLevelLinking> + <IntrinsicFunctions>true</IntrinsicFunctions> + <StringPooling>true</StringPooling> + <ExceptionHandling>false</ExceptionHandling> + <BufferSecurityCheck>false</BufferSecurityCheck> + <CreateHotpatchableImage>false</CreateHotpatchableImage> + <RuntimeTypeInfo>false</RuntimeTypeInfo> + <OpenMPSupport>false</OpenMPSupport> + <MultiProcessorCompilation>true</MultiProcessorCompilation> + <DebugInformationFormat>None</DebugInformationFormat> + </ClCompile> + <Link> + <GenerateDebugInformation>true</GenerateDebugInformation> + <EnableCOMDATFolding>true</EnableCOMDATFolding> + <OptimizeReferences>true</OptimizeReferences> + </Link> + </ItemDefinitionGroup> + <ItemGroup> + <ClInclude Include="..\Include\ZNet\ZNet.hpp" /> + <ClInclude Include="..\Include\ZNet\ZNetBandwidthMeter.hpp" /> + <ClInclude Include="..\Include\ZNet\ZNetClient.hpp" /> + <ClInclude Include="..\Include\ZNet\ZNetConsts.hpp" /> + <ClInclude Include="..\Include\ZNet\ZNetEvent.hpp" /> + <ClInclude Include="..\Include\ZNet\ZNetHost.hpp" /> + <ClInclude Include="..\Include\ZNet\ZNetPacket.hpp" /> + <ClInclude Include="..\Include\ZNet\ZNetPacketChannel.hpp" /> + <ClInclude Include="..\Include\ZNet\ZNetPeer.hpp" /> + <ClInclude Include="..\Include\ZNet\ZNetServer.hpp" /> + <ClInclude Include="..\Include\ZNet\ZNetUtil.hpp" /> + <ClInclude Include="ZNetPrivate.hpp" /> + </ItemGroup> + <ItemGroup> + <ClCompile Include="ZNetBandwidthMeter.cpp" /> + <ClCompile Include="ZNetClient.cpp" /> + <ClCompile Include="ZNetHost.cpp" /> + <ClCompile Include="ZNetPacketChannel.cpp" /> + <ClCompile Include="ZNetPeer.cpp" /> + <ClCompile Include="ZNetPrivate.cpp" /> + <ClCompile Include="ZNetServer.cpp" /> + </ItemGroup> + <ItemGroup> + <ProjectReference Include="..\libsst-net\libsst-net.vcxproj"> + <Project>{e6679a2f-6c8e-4555-9228-6929c734cef4}</Project> + </ProjectReference> + </ItemGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> + <ImportGroup Label="ExtensionTargets"> + </ImportGroup> +</Project> \ No newline at end of file diff --git a/ZNet/ZNet.vcxproj.filters b/ZNet/ZNet.vcxproj.filters new file mode 100644 index 0000000..8e65b25 --- /dev/null +++ b/ZNet/ZNet.vcxproj.filters @@ -0,0 +1,78 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup> + <Filter Include="Source Files"> + <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier> + <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions> + </Filter> + <Filter Include="Header Files"> + <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier> + <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> + </Filter> + <Filter Include="Resource Files"> + <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier> + <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions> + </Filter> + </ItemGroup> + <ItemGroup> + <ClInclude Include="..\Include\ZNet\ZNet.hpp"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\Include\ZNet\ZNetPacket.hpp"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\Include\ZNet\ZNetConsts.hpp"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\Include\ZNet\ZNetEvent.hpp"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\Include\ZNet\ZNetUtil.hpp"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\Include\ZNet\ZNetPacketChannel.hpp"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\Include\ZNet\ZNetBandwidthMeter.hpp"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="ZNetPrivate.hpp"> + <Filter>Source Files</Filter> + </ClInclude> + <ClInclude Include="..\Include\ZNet\ZNetHost.hpp"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\Include\ZNet\ZNetClient.hpp"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\Include\ZNet\ZNetServer.hpp"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\Include\ZNet\ZNetPeer.hpp"> + <Filter>Header Files</Filter> + </ClInclude> + </ItemGroup> + <ItemGroup> + <ClCompile Include="ZNetHost.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="ZNetPeer.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="ZNetPacketChannel.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="ZNetBandwidthMeter.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="ZNetServer.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="ZNetClient.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="ZNetPrivate.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> +</Project> \ No newline at end of file diff --git a/ZNet/ZNetBandwidthMeter.cpp b/ZNet/ZNetBandwidthMeter.cpp new file mode 100644 index 0000000..ccf7d10 --- /dev/null +++ b/ZNet/ZNetBandwidthMeter.cpp @@ -0,0 +1,86 @@ +/* + ZNetBandwidthMeter.cpp + Author: Patrick Baggett <ptbaggett@762studios.com> + Created: 7/10/2013 + + Purpose: + + ** NOT PART OF PUBLIC SDK ** + This class is not part of the public SDK; its fields and methods are not present + in the documentation and cannot be guaranteed in future revisions. + ** NOT PART OF PUBLIC SDK ** + + Bandwidth metering using a simple token bucket algorithm. A single value is + metered, so a incoming / outgoing each need an instance. + + License: + + Copyright 2013, 762 Studios +*/ + +#include <ZNet/ZNetBandwidthMeter.hpp> + +/*************************************************************************/ + +void ZNetBandwidthMeter::SetLimit(uint32_t newLimit) +{ + limit = newLimit; + + //Clamp existing token bucket + if(tokens > newLimit) + tokens = newLimit; + +} + +/*************************************************************************/ + +void ZNetBandwidthMeter::Reset(uint64_t newStartTime) +{ + lastTime = newStartTime; + tokens = limit; +} + +/*************************************************************************/ + +bool ZNetBandwidthMeter::TryAllocate(uint32_t bytes) +{ + if(bytes <= tokens) + { + tokens -= bytes; + return true; + } + + //Not enough + return false; +} + +/*************************************************************************/ + +void ZNetBandwidthMeter::Update(uint64_t newTime) +{ + //Sanity check -- the time _did_ monotonically increase, right? + if(newTime > lastTime) + { + uint32_t delta = (uint32_t)(newTime - lastTime); + + //If less than a second has passed... + if(delta < 1000) + { + //We could do: delta / 1000.0 * limit, but that involves int -> float conversions + //instead we do u32 x u32 = u64 multiply and divide by 1000, keeping it all in fixed + //point happiness. Because delta < 1000, dividing by 1000 should put it back in the + //range of a u32. + uint32_t amount = (uint64_t)delta * (uint64_t)limit / 1000; + + //Add newly generated tokens, but clamp to the limit. + tokens += amount; + if(tokens > limit) + tokens = limit; + } + else //More than a second, so restore all tokens + tokens = limit; + + //Save this as the new time + lastTime = newTime; + } +} diff --git a/ZNet/ZNetClient.cpp b/ZNet/ZNetClient.cpp new file mode 100644 index 0000000..b3e579b --- /dev/null +++ b/ZNet/ZNetClient.cpp @@ -0,0 +1,268 @@ +/* + ZNetClient.cpp + Author: Patrick Baggett <ptbaggett@762studios.com> + Created: 7/18/2013 + + Purpose: + + ZNetClient -- extends ZNetHost to provide a client + + License: + + Copyright 2013, 762 Studios +*/ + +#include <ZNet/ZNetClient.hpp> +#include <ZNet/ZNetPacket.hpp> +#include <SST/SST_Assert.h> +#include <SST/SST_Endian.h> +#include <SST/SST_Time.h> +#include "ZNetPrivate.hpp" + +#include <stdio.h> //HACKHACK printf + +ZNetClient::ZNetClient() +{ + connectedFlag = false; +} + +ZNetClient::~ZNetClient() +{ + +} + +/*************************************************************************/ + +int ZNetClient::Update() +{ + bool hitError = false; + uint8_t data[9000]; + + //Only update if we've got a server + if(server.GetState() != STATE_UNCONNECTED) + { + SST_Socket s = server.GetSocket(); + SST_NetResult res; + do + { + SST_NetAddress sender; + size_t nrReceived; + + res = SST_Net_RecvFrom(s, data, sizeof(data), 0, &sender, &nrReceived); + + if(res == SSTNETRESULT_SUCCESS) + { + //OK, so is the packet from the server? If not, ignore it + if(SST_Net_AddressCompare(&sender, server.GetNetAddress()) != 0) + continue; + + HandlePacket(data, (uint32_t)nrReceived); + } + else if(res == SSTNETRESULT_WOULDBLOCK) + break; + else + hitError = true; + + } while(res == SSTNETRESULT_SUCCESS); + } + static const char* str[] = {"UNCONNECTED", "HANDSHAKE", "CONNECTED", "SERVING"}; + printf("MY STATE: %s / %u ack\n", str[server.GetState()], server.GetPacketChannel(0)->GetLocalAck()); + + + //Send all channel data to server + if(!this->SendToPeer(&server)) + hitError = true; + + //Send acks + server.SendAcksForAllChannels(); + server.ProcessLocalAcks(); + + if(hitError) + return -1; + + return HasEvent() ? 1 : 0; +} + +/*************************************************************************/ + +bool ZNetClient::Connect(SST_Socket s, SST_NetAddress* addr, uint32_t nrChannels, uint32_t userData) +{ + SST_OS_DebugAssert(s != 0, "Invalid socket"); + SST_OS_DebugAssert(addr != NULL, "Invalid address"); + SST_OS_DebugAssert(server.GetState() == STATE_UNCONNECTED, "Must be unconnected, use Reset() first"); + + if(nrChannels == 0 || nrChannels > UINT8_MAX) + return false; + + + if(!server.Initialize(this, addr, s, nrChannels)) + return false; + + if(SST_Net_SetNonblock(s, 1) != SSTNETRESULT_SUCCESS) + return false; + + //CONNECT always occurs on ZNET_SYSCHANNEL + ZNetPacketChannel* channel = server.GetPacketChannel(ZNET_SYSCHANNEL); + + userData = ZNetPrivate::ZNetByteOrder32(userData); + + //Create a packet, copying the userdata + ZNetPacket* packet = this->CreatePacket((void*)&userData, sizeof(userData), 0); + if(packet == NULL) + return false; + + if(!channel->QueueForSending(packet, ZNETCMD_CONNECT)) + { + packet->ReleaseReference(); + return false; + } + + //We're done with this + packet->ReleaseReference(); + + //Note that we're trying! + server.SetState(STATE_HANDSHAKE); + return true; +} + +/*************************************************************************/ + +void ZNetClient::HandlePacket(const uint8_t* data, uint32_t dataSize) +{ + ZBinaryBufferReader reader(data, dataSize, ZNET_BYTEORDER); + static int COUNT = 0; + + printf("(%u) Handling packet of %u length", ++COUNT, dataSize); + //Valid packet header? + if(!ZNetPrivate::ParseWirePacketHeader(&reader)) + { + printf("...but it is invalid\n"); + return; + } + + ZNetPrivate::ZNetMessageContainer container; + + int retval; + uint64_t now = SST_OS_GetMilliTime(); + bool wasValid = true; + do + { + retval = ZNetPrivate::ReadNextMessage(&reader, &container); + printf("ReadNextMessage(): %d\n", retval); + if(retval > 0) + { + switch(container.command) + { + //Server sent how far it is. We can safely act on this now because it does not generate any events. + //ACKs themselves do not utilize sequence numbers (they always have 0) + case ZNETCMD_ACK: + { + printf("ZNETCMD_ACK: CH %u: highestRecv = %u, highestSent = %u\n", container.channel, container.parsed.ack.highestReceived, container.parsed.ack.highestSent); + //Ensure it is a valid ack + if(container.channel < server.GetNumberChannels()) + { + ZNetPacketChannel* channel = server.GetPacketChannel(container.channel); + int32_t currentPing = server.GetPing(); + + //Update ACKs, calculating an adjusted ping + channel->UpdateRemoteAck(container.parsed.ack.highestReceived, ¤tPing); + //server.SetPing(currentPing); + server.SetPing(75); + } + else + wasValid = false; + break; + } + + //Server sent data. + case ZNETCMD_DATA: + { + printf("ZNETCMD_DATA found, ch = %u, length = %u, offset = %u, maxSize = %u\n", + container.channel, container.parsed.data.length, container.parsed.data.offset, + container.parsed.data.maxSize); + if(container.channel < server.GetNumberChannels()) + { + ZNetPacketChannel* ch = server.GetPacketChannel(container.channel); + + ch->QueueData(&container); + } + else + wasValid = false; + + + break; + } + + //Server sent a connection response + case ZNETCMD_CONNRESP: + { + printf("ZNETCMD_CONNRESP: code = %u\n", container.parsed.connect.userdata); + if(container.channel == ZNET_SYSCHANNEL) + { + const uint32_t reasonCode = container.parsed.connect.userdata; //slightly less typing + + //TODO: flags? can have server full!!! + + + //Accepted? + if(reasonCode == 0) + { + if(server.GetState() == STATE_HANDSHAKE) + { + //OK, we're good + server.SetState(STATE_CONNECTED); + + ZNetEvent ev; + ev.packet = NULL; + ev.userdata = reasonCode; + ev.remote = &server; + ev.type = ZNETEVENT_CONNECT; + this->AddEvent(&ev); + } + + //We got it, mark that we did. + server.GetPacketChannel(ZNET_SYSCHANNEL)->UpdateLocalAck(container.sequence); + } + else //Not accepted. In this case, the server doesn't consider us a client, so no acks required. + { + ZNetEvent ev; + + ev.packet = NULL; + ev.userdata = reasonCode; + ev.remote = &server; + ev.type = ZNETEVENT_DISCONNECT; + + this->AddEvent(&ev); + + //TODO: clear out CONNECT command + + } + } // if on system channel + else //else not accepted. + wasValid = false; + break; + } + + case ZNETCMD_DISCONNECT: + SST_OS_DebugError("Not yet implemented!"); + break; + + //Ignore this command, it doesn't make any sense as a client + case ZNETCMD_CONNECT: + default: + wasValid = false; + break; + + } + } + + } while(retval > 0); + + //If all was valid, update last received time + if(wasValid) + server.SetLastReceived(now); + + + + +} \ No newline at end of file diff --git a/ZNet/ZNetHost.cpp b/ZNet/ZNetHost.cpp new file mode 100644 index 0000000..423c613 --- /dev/null +++ b/ZNet/ZNetHost.cpp @@ -0,0 +1,145 @@ +/* + ZNetHost.cpp + Author: Patrick Baggett <ptbaggett@762studios.com> + Created: 6/4/2013 + + Purpose: + + ZNet host class, represents the local system + + License: + + Copyright 2013, 762 Studios +*/ + +#include <ZNet/ZNetHost.hpp> +#include <ZNet/ZNetPacket.hpp> +#include <ZNet/ZNetConsts.hpp> +#include <ZNet/ZNetPeer.hpp> +#include <SST/SST_Alloc.h> //SST_OS_Alloca() +#include "ZNetPrivate.hpp" + +#include <SST/SST_OS.h> +#include <ZUtil/ZBinaryBufferReader.hpp> + +#include <stdio.h> //HACKHACK + +/*************************************************************************/ + +ZNetHost::ZNetHost() +{ + mtu = ZNET_MTU_IPV4SAFE; //Safe, but small MTU as a default + dropChance = 0; +} + +/*************************************************************************/ + +ZNetPacket* ZNetHost::CreatePacket(const void* initData, uint32_t dataSize, uint32_t flags) +{ + ZNetPacket* packet; + + //Validate that ONLY legitimate bits are set + if(flags != 0) + return NULL; + + //Allocate packet structure + data + packet = (ZNetPacket*)malloc(sizeof(ZNetPacket) + dataSize); + if(packet == NULL) + return NULL; + + packet->flags = flags; + packet->dataSize = dataSize; + packet->refCount = 1; + + if(initData != NULL) + memcpy(packet->GetData(), initData, dataSize); + + return packet; +} + +/*************************************************************************/ + +bool ZNetHost::GetNextEvent(ZNetEvent* eventReturn) +{ + if(!events.Empty()) + { + *eventReturn = events.PopFront(); + return true; + } + + return false; +} + +/*************************************************************************/ + +bool ZNetHost::SendToPeer(ZNetPeer* peer) +{ + uint8_t* data = (uint8_t*)SST_OS_Alloca(GetMTU()); + bool unsent = false; + + //TODO: No bandwidth allocations done here + //TODO: send in round-robin fashion across channels + + ZBinaryBufferWriter writer(data, GetMTU(), ZNET_BYTEORDER); + ZNetPrivate::WriteWirePacketHeader(&writer); + + //OUTER LOOP: for each channel + for(uint32_t i=0; i<peer->GetNumberChannels(); i++) + { + ZNetPacketChannel* channel = peer->GetPacketChannel(i); + bool moreInChannel = true; + uint32_t index = 0; + uint32_t newIndex; + uint32_t nrWritten; + + //INNER LOOP: fill buffer with channel data + do + { + uint32_t remain = mtu - (uint32_t)writer.GetOffset(); + + if(!channel->FillBuffer((uint8_t*)writer.GetBufferWriteAddress(), remain, index, &newIndex, &nrWritten))//TODO: update to make use of ZBinaryBufferWriter interface + { + //Buffer is full, send now + index = newIndex; + writer.SeekForward(nrWritten); + if(!ZNetPrivate::SendAll(peer->GetSocket(), peer->GetNetAddress(), data, (uint32_t)writer.GetOffset())) + { + printf("SendToPeer FAILED %u bytes\n", (uint32_t)writer.GetOffset()); + return false; + } + printf("SendToPeer -> Sent %u bytes\n", (uint32_t)writer.GetOffset()); + + //Restart! + writer.Rewind(); + ZNetPrivate::WriteWirePacketHeader(&writer); + unsent = false; + } + else //Done with this channel + { + if(nrWritten > 0 && !unsent) + { + unsent = true; + writer.SeekForward(nrWritten); + } + moreInChannel = false; + + } + + } while(moreInChannel); + + } + + //Any unsent data? + if(unsent) + { + //Then send it! + if(!ZNetPrivate::SendAll(peer->GetSocket(), peer->GetNetAddress(), data, (uint32_t)writer.GetOffset())) + { + printf("SendToPeer FAILED %u bytes\n", (uint32_t)writer.GetOffset()); + return false; + } + printf("SendToPeer -> Sent %u bytes\n", (uint32_t)writer.GetOffset()); + } + + return true; +} diff --git a/ZNet/ZNetPacketChannel.cpp b/ZNet/ZNetPacketChannel.cpp new file mode 100644 index 0000000..54075d5 --- /dev/null +++ b/ZNet/ZNetPacketChannel.cpp @@ -0,0 +1,506 @@ +/* + ZNetPacketChannel.cpp + Author: Patrick Baggett <ptbaggett@762studios.com> + Created: 6/14/2013 + + Purpose: + + ** NOT PART OF PUBLIC SDK ** + This class is not part of the public SDK; its fields and methods are not present + in the documentation and cannot be guaranteed in future revisions. + ** NOT PART OF PUBLIC SDK ** + + Queue of incoming and outgoing packets. + + License: + + Copyright 2013, 762 Studios +*/ + +/*************************************************************************/ + +#include <ZNet/ZNetPacketChannel.hpp> +#include <ZNet/ZNetPacket.hpp> +#include <ZNet/ZNetHost.hpp> +#include <ZUtil/ZBinaryBufferWriter.hpp> +#include <ZSTL/ZListAlgo.hpp> +#include <SST/SST_OS.h> +#include "ZNetPrivate.hpp" + +/*************************************************************************/ + +bool ZNetPacketChannel::QueueForSending(ZNetPacket* packet, uint32_t command) +{ + printf("QueueForSending(): This sequence = %u\n", this->nextSequenceNumber); + + //Check for a packet overflow + if(packetCount+1 > overflowLimit) + { + printf("ZNetPacketChannel::QueueForSending(): Packet channel overflow!\n"); + return false; + } + + //Since we're keeping this packet in this channel, increase its reference count + packet->AddReference(); + + //Wrap this packet with some metadata + ZNetQueuedPacket qp; + qp.timeSent = 0; + qp.packet = packet; + qp.command = command; + qp.subsequence = 0; + qp.sequence = this->nextSequenceNumber; + + + //Next sequence + this->nextSequenceNumber++; + + packets.PushBack(qp); + + return true; +} + +/*************************************************************************/ + +bool ZNetPacketChannel::FillBuffer(uint8_t* buffer, uint32_t bufferSize, uint32_t packetStartIndex, uint32_t* restartIndexReturn, uint32_t* bytesWritten) +{ + ZList<ZNetQueuedPacket>::Iterator it = packets.Begin(); + uint32_t bufferSpaceRemaining = bufferSize; + uint32_t nrWritten = 0; + + //Skip to appropriate point in the list + while(packetStartIndex > 0) + { + ++it; + --packetStartIndex; + } + + ZBinaryBufferWriter writer(buffer, bufferSize, ZNET_BYTEORDER); + + //Write packets + uint64_t now = SST_OS_GetMilliTime(); + do + { + //Nothing to do? + if(it == packets.End()) + break; + + ZNetQueuedPacket& qp = it.Get(); + uint32_t payloadSpace = bufferSpaceRemaining - ZNET_WIRESIZE_MESSAGE_HEADER; //This is how much payload we can handle. + + //No space for a payload? + if(payloadSpace == 0) + break; + + /* + All packets other than DATA are actually quite small, and as such they are not fragmented -- either + they fit into the buffer or they don't. The data packets can easily exceed an MTU. Because of that, + they are fragmented at the byte level using the subsequence value. This allows us to fully fill MTU- + sized packets as often as possible, however, it requires some special handling because fields are + inserted into the front that vary in size. + */ + + uint8_t* packetData; + uint32_t sendSize = 0; //MSVC 2012 complains about uninitialized + + //Data packets are somewhat special + if(qp.command == ZNETCMD_DATA) + { + SST_OS_DebugAssert(sendSize > 0, "Data packet has been fully confirmed, but still attempting to send?"); + const uint32_t leftToSend = qp.packet->dataSize - qp.subsequence; + const uint32_t dataOverhead = 3*ZNetPrivate::PackedIntegerSize(qp.packet->dataSize); //3 fields, see ZNetPrivate.hpp + + //Not enough space? + if(dataOverhead >= payloadSpace) + break; + + //Subtract overhead from payload to get how much payload we can really deliver. + payloadSpace -= dataOverhead; + + //Can we fit all of the remaining data in this packet? + if(leftToSend < payloadSpace) + sendSize = leftToSend; + else + sendSize = payloadSpace; //No, so just send as much as we can + + + printf("Sending %u bytes of ZNETCMD_DATA payload\n", sendSize); + packetData = (qp.packet->GetData() + qp.subsequence); + } + else + { + packetData = qp.packet->GetData(); + sendSize = qp.packet->dataSize; + printf("Sending %u bytes of regular (non-ZNETCMD_DATA)\n", sendSize); + } + qp.timeSent = now; + + SST_OS_DebugAssert(sendSize != 0, "Should not have 0-sized value"); + + //Write the header and then the data + ZNetPrivate::WriteWireMessageHeader(&writer, this->channelId, qp.packet->flags, qp.command, qp.sequence); + writer.WriteU8Array(packetData, sendSize); + + + //Record stats and advance to next packet + nrWritten += (sendSize + ZNET_WIRESIZE_MESSAGE_HEADER); //i.e. payload + header + packetStartIndex++; + bufferSpaceRemaining -= (sendSize + ZNET_WIRESIZE_MESSAGE_HEADER); + ++it; + } while(bufferSpaceRemaining > 0); + + bool allDone = (it == packets.End()); + + //If a restart is needed, record where we left off. + if(!allDone) + *restartIndexReturn = packetStartIndex; + + //Save the number of bytes written + *bytesWritten = nrWritten; + + return allDone; +} + +/*************************************************************************/ + +void ZNetPacketChannel::Deinitialize() +{ + + //Unreference all packets and remove them from queues + for(ZList<ZNetQueuedPacket>::Iterator it=packets.Begin(); it.HasCurrent(); it.Next()) + it.Get().packet->ReleaseReference(); + packets.Clear(); + + for(ZList<ZNetDataReassemblyPacket>::Iterator it=reassembly.Begin(); it.HasCurrent(); it.Next()) + it.Get().packet->ReleaseReference(); + reassembly.Clear(); + + for(ZList<ZNetQueuedPacket>::Iterator it=assembled.Begin(); it.HasCurrent(); it.Next()) + it.Get().packet->ReleaseReference(); + assembled.Clear(); + + + +} + +/*************************************************************************/ + +void ZNetPacketChannel::UpdateRemoteAck(uint16_t newHighest, int32_t* pingAdjust) +{ + printf("ZNetPacketChannel::UpdateRemoteAck(): current ack = %u, newHighest = %u\n", remoteAck, newHighest); + //Nothing new + if(newHighest == remoteAck) + return; + + uint16_t ackCount; + + //Wrap around + if(newHighest < remoteAck) + { + /* + In a wrap around, we exceed the the fixed point notation of the next sequence number. To + handle it, we count from where we are at to the highest possible value, then add the new + local number -- this is the number of packets to dequeue. For example, if our window was + 100 and we were at 97, then "ack 4" means that 98, 99, 100, 1, 2, 3, 4 were received. We + compute it as 100 - 97 + 4 == 7. + */ + ackCount = UINT16_MAX - remoteAck + newHighest; + } + else + ackCount = newHighest - remoteAck; + + printf("AckCount = %u\n", ackCount); + if(ackCount > 0) + { + //Freeze time value now + uint64_t now = SST_OS_GetMilliTime(); + int32_t currentPing = *pingAdjust; + + while(ackCount > 0 && !packets.Empty()) + { + ZNetQueuedPacket& qp = packets.Front(); + + + //Does this packet have a valid timeSent? + if(qp.timeSent != 0) + { + + //Find out how much the RTT differs from the ping + int32_t delta = currentPing - ((int32_t)(now - qp.timeSent)); + //Adjust ping by a fraction of RTT to smooth it out. + currentPing += delta / 10; + } + + qp.packet->ReleaseReference(); + packets.PopFront(); + printf("Removed a packet!\n"); + ackCount--; + this->packetCount--; + } + + //Save updated ping + *pingAdjust = currentPing; + } + + //Because malicious clients can send anything, don't explode if this packet suggests + //that we remove more than exist. + //TODO: maybe log it? probably can help with debugging + printf("Possibly wrong sequencing - this tells us to ACK more than we've sent\n"); +} + +/*************************************************************************/ + +bool ZNetPacketChannel::QueueLocally(const ZNetPacketChannel::ZNetQueuedPacket* toQueue) +{ + uint16_t seq = toQueue->sequence; + + ZList<ZNetQueuedPacket>::Iterator it = assembled.Begin(); + + while(it.HasCurrent()) + { + ZNetQueuedPacket& qp = it.Get(); + + if(ZNetPrivate::SequenceAfter(seq, qp.sequence)) //Incoming packet sequence number is after this packet + it.Next(); + else if(ZNetPrivate::SequenceAfter(qp.sequence, seq)) //Incoming packet sequence number is before this packet + { + ZNetQueuedPacket newEntry; + + newEntry.command = toQueue->command; + newEntry.sequence = toQueue->sequence; + newEntry.subsequence = toQueue->subsequence; + newEntry.packet = toQueue->packet; + newEntry.timeSent = toQueue->timeSent; + + //Add it in + assembled.Insert(it, newEntry); + break; + } + else if(qp.sequence == seq) //Overwrite old data + { + if(qp.packet != NULL) + { + qp.packet->ReleaseReference(); + qp.packet = toQueue->packet; + } + break; + } + } //end + + + + //Doesn't appear to be valid + return false; +} + +/*************************************************************************/ + +bool ZNetPacketChannel::QueueData(ZNetPrivate::ZNetMessageContainer* data) +{ + ZList<ZNetDataReassemblyPacket>::Iterator it = reassembly.Begin(); + + /* + Check for invalid offsets into packet. + + The second and third checks look redundant, but for extremely large + values, summing them can wrap to a smaller value, e.g. 0xFFFFFFFF + 0x0003 + will give 0x0002, and crash later when copying / allocating memory. + */ + if(data->parsed.data.offset + data->parsed.data.length > data->parsed.data.maxSize || + data->parsed.data.offset >= data->parsed.data.maxSize || + data->parsed.data.length >= data->parsed.data.maxSize) + return false; + + //If whole data logical packet was received + if(data->parsed.data.length == data->parsed.data.maxSize) + { + if(data->parsed.data.offset == 0) + { + ZNetQueuedPacket qp; + ZNetPacket* packet = GetHost()->CreatePacket(data->parsed.data.data, data->parsed.data.length, 0); + + if(packet == NULL)//Out of memory + return false; + + qp.command = ZNETCMD_DATA; + qp.packet = packet; + qp.sequence = data->sequence; + qp.timeSent = SST_OS_GetMilliTime(); + qp.subsequence = 0; //field not used + return this->QueueLocally(&qp); + } + else + return false; //invalid packet + + } + + //Required reassembly + while(it.HasNext()) + { + ZNetDataReassemblyPacket& reasm = it.Get(); + + //If the new packet comes after this packet, try next + if(ZNetPrivate::SequenceAfter(data->sequence, reasm.sequence)) + { + it.Next(); + continue; + } + + + if(reasm.sequence == data->sequence) + { + SST_OS_DebugAssert(reasm.packet != NULL, "Should not have NULL packet here"); + const uint32_t maxSize = reasm.packet->dataSize; + + //TODO: when done debugging, remove this assert as untrusted input should not cause a crash + SST_OS_DebugAssert(maxSize == data->parsed.data.maxSize, "Does not match."); + if(maxSize != data->parsed.data.maxSize) + return false; + + const uint32_t begin = data->parsed.data.offset; + const uint32_t end = begin + data->parsed.data.length; + + //Does this packet contain data that can be appended directly? + if(begin <= reasm.subsequence && end > reasm.subsequence) + { + uint8_t* rawbits = reasm.packet->GetData(); //Get raw logical packet + + /* Copy from the subsequence point to the end point. This can be less than the incoming amount: + + reasm.subsequence = 3 + + filled + xxxxxxxxx + [0][1][2][3][4][5][6][7][8] + ^-----^ + new packet. offset = 2, length = 3. + + In this case, we copy only `end - subsequence` == 5 - 3 == 2 bytes. + */ + memcpy(rawbits+reasm.subsequence, data->parsed.data.data, end - reasm.subsequence); + reasm.subsequence = end; + + //Packet is fully assembled + if(end == maxSize) + { + ZNetQueuedPacket qp; + qp.command = ZNETCMD_DATA; + qp.packet = reasm.packet; + qp.sequence = data->sequence; + qp.timeSent = SST_OS_GetMilliTime(); + qp.subsequence = 0; //field not used + return this->QueueLocally(&qp); + } + } + + + } + else //This packet comes before it.Get() + { + ZNetDataReassemblyPacket newAssembly; + + ZNetPacket* packet = GetHost()->CreatePacket(NULL, data->parsed.data.maxSize, 0); + if(packet == NULL) + return false; + + //Copy when offset is zero, otherwise, the other side is going to do a resend + //anyways. + if(data->parsed.data.offset == 0) + { + memcpy(packet->GetData(), data->parsed.data.data, data->parsed.data.length); + newAssembly.subsequence = data->parsed.data.length; + } + else + newAssembly.subsequence = 0; + newAssembly.packet = packet; + newAssembly.sequence = data->sequence; + + //Insert before 'it' + reassembly.Insert(it, newAssembly); + } + } + + return true; +} + +/*************************************************************************/ + +void ZNetPacketChannel::UpdateLocalAck(uint16_t seq) +{ + + sequencesFound.PushBack(seq); +} + +/*************************************************************************/ + +void ZNetPacketChannel::ProcessLocalAcks() +{ + ZListAlgo::Sort(sequencesFound); + + ZList<uint16_t>::Iterator it = sequencesFound.Begin(); + int32_t firstFound = -1; //This is the first value found before wraparounds + + /* + We want to find consecutive values starting at "localAck" and continuing. This takes two + passes because there can be a wrap around and the data is sorted ascending, but values + lower than "localAck" logically come _after_ it due to the wraparound. + + In the first pass, we ignore wraparounds (i.e. localAck > seq). We check to see + if the next is expected value of localAck+1. If it is, we bump the counter and check the + next number. Stop when the list is reached or a discontinuity found. + + In the second pass, we handle wraparounds, stopping when we reach the first value accepted + in pass 1. + */ + + //PASS 1: handling pre-wrap arounds + while(it.HasCurrent()) + { + uint16_t thisSeq = it.Get(); + + //Skip smaller values as they are wraparound values + if(thisSeq > localAck) + { + if(localAck+1 == thisSeq) //because > operator succeeded, we know that localAck+1 cannot overflow + { + if(firstFound == -1) + firstFound = (int32_t)thisSeq; + + printf("Acked a packet!\n"); + localAck++; + } + else + { + //discontinuity, stop here + sequencesFound.Clear(); + return; + } + + } + + //Next value + it.Next(); + } + + //If we made it here, we didn't hit any discontinuities (or the list was empty) + + //PASS 2: handling wrap arounds + it = sequencesFound.Begin(); + while(it.HasCurrent() && it.Get() != (uint16_t)firstFound) + { + uint16_t thisSeq = it.Get(); + + if(thisSeq != (uint16_t)firstFound && //stop when we hit the first value we processed in pass 1 + thisSeq == localAck+1)//localAck+1 may wraparound now + { + printf("(WRAP) Acked a packet!\n"); + localAck++; + } + else //discontinuity hit + break; + + } + + //Now, remove all acks + sequencesFound.Clear(); +} \ No newline at end of file diff --git a/ZNet/ZNetPeer.cpp b/ZNet/ZNetPeer.cpp new file mode 100644 index 0000000..9c155fa --- /dev/null +++ b/ZNet/ZNetPeer.cpp @@ -0,0 +1,156 @@ +/* + ZNetPeer.cpp + Author: Patrick Baggett <ptbaggett@762studios.com> + Created: 7/18/2013 + + Purpose: + + ZNet peer class, representing a remote host + + License: + + Copyright 2013, 762 Studios +*/ + +/*************************************************************************/ + +#include <ZNet/ZNetPeer.hpp> +#include <ZNet/ZNetPacketChannel.hpp> +#include <ZNet/ZNetHost.hpp> +#include "ZNetPrivate.hpp" +#include <SST/SST_OS.h> +#include <new> + + +/*************************************************************************/ + +ZNetPeer::ZNetPeer() +{ + lastValidIncoming = 0; + lastOutgoingAck = 0; + socketCopy = 0; + channels = NULL; + userdata = NULL; + nrChannels = 0; + ping = -1; + state = STATE_UNCONNECTED; +} + +/*************************************************************************/ + +bool ZNetPeer::Initialize(ZNetHost* _host, const SST_NetAddress* newAddr, SST_Socket s, uint32_t _nrChannels) +{ + SST_OS_DebugAssert(_host != NULL, "Host may not be NULL"); + SST_OS_DebugAssert(channels == NULL, "This should have been NULL; memory leak!"); + + channels = new(std::nothrow) ZNetPacketChannel[_nrChannels]; + if(channels == NULL) + return false; + + //Initialize channel ID (new[] doesn't allow non-default constructors) + for(uint32_t i=0; i<_nrChannels; i++) + { + channels[i].SetChannelId(i); + channels[i].SetHost(_host); + } + + //Store other properties + memcpy(&addr, newAddr, sizeof(SST_NetAddress)); + nrChannels = _nrChannels; + socketCopy = s; + userdata = NULL; + lastValidIncoming = SST_OS_GetMilliTime(); + state = STATE_HANDSHAKE; + + //OK + return true; +} + +/*************************************************************************/ + +void ZNetPeer::Deinitialize() +{ + for(uint32_t i=0; i<nrChannels; i++) + channels[i].Deinitialize(); + + delete[] channels; +} + +/*************************************************************************/ + +ZNetPacketChannel* ZNetPeer::GetPacketChannel(uint32_t chId) +{ + //Really, this is trivial, but I don't want asserts to be conditional on whether + //the user of the API has enabled them vs how the library was built. + SST_OS_DebugAssert(chId < nrChannels, "Invalid channel number"); + + return &channels[chId]; +} + +/*************************************************************************/ + +void ZNetPeer::ProcessLocalAcks() +{ + for(uint32_t i=0; i<nrChannels; i++) + channels[i].ProcessLocalAcks(); +} + +/*************************************************************************/ + +void ZNetPeer::SendAcksForAllChannels() +{ + uint8_t data[9000]; + uint32_t mtu = this->GetPacketChannel(ZNET_SYSCHANNEL)->GetHost()->GetMTU(); + bool unsent = true; + + uint64_t now = SST_OS_GetMilliTime(); + + //TODO: maybe not the best idea...? it will start out by sending an ACK 0...kinda silly I guess + if(lastOutgoingAck == 0 || + ((ping > 0) && (now > lastOutgoingAck + (uint64_t)ping) && (now - lastOutgoingAck > 50)) ) //TODO: does a minimum ack latency of 50 make any sense? in the cases where ping is realllly low (e.g. <= 1msec) don't need to spam? + { + lastOutgoingAck = now; + } + else + return; + + + ZBinaryBufferWriter writer(data, mtu, ZNET_BYTEORDER); + + //Write the write header + ZNetPrivate::WriteWirePacketHeader(&writer); + + //Write an ACK point for each channel + for(uint32_t i=0; i<nrChannels; i++) + { + ZNetPacketChannel* channel = GetPacketChannel(i); + uint32_t remain = mtu - (uint32_t)writer.GetOffset(); + + //Can we fit another ack? + if(remain > ZNetPrivate::WireSizeForSimpleCommand(ZNETCMD_ACK)) + { + //TODO: flags?? + ZNetPrivate::WriteWireMessageHeader(&writer, i, 0, ZNETCMD_ACK, 0); + + writer.WriteU16(channel->GetLocalAck()); + writer.WriteU16(channel->GetHighestSent()); + + unsent = true; + } + else + { + ZNetPrivate::SendAll(socketCopy, &addr, data, (uint32_t)writer.GetOffset()); + unsent = false; + + //Restart + writer.Rewind(); + ZNetPrivate::WriteWirePacketHeader(&writer); + } + + } + + if(unsent) + ZNetPrivate::SendAll(socketCopy, &addr, data, (uint32_t)writer.GetOffset()); +} + +/*************************************************************************/ diff --git a/ZNet/ZNetPrivate.cpp b/ZNet/ZNetPrivate.cpp new file mode 100644 index 0000000..6265d82 --- /dev/null +++ b/ZNet/ZNetPrivate.cpp @@ -0,0 +1,174 @@ +/* + ZNetPrivate.cpp + Author: Patrick Baggett <ptbaggett@762studios.com> + Created: 7/19/2013 + + Purpose: + + ZNet private functions and definitions + + License: + + Copyright 2013, 762 Studios +*/ + +#include "ZNetPrivate.hpp" +#include <ZNet/ZNetPeer.hpp> +#include <SST/SST_Assert.h> + +/*************************************************************************/ + +bool ZNetPrivate::ParseWirePacketHeader(ZBinaryBufferReader* reader) +{ + //Packet is absolutely too small to have any useful data (i.e. size < minimum overhead) + if(reader->GetLength() < ZNET_WIRESIZE_PACKET_MINIMUM) + return false; + + if(reader->ReadU8() != ZNET_MAGIC) + return false; + + return true; +} + +/*************************************************************************/ + +void ZNetPrivate::WriteWirePacketHeader(ZBinaryBufferWriter* writer) +{ + writer->WriteU8(ZNET_MAGIC); +} + +/*************************************************************************/ + +void ZNetPrivate::WriteWireMessageHeader(ZBinaryBufferWriter* writer, uint32_t channel, uint32_t flags, uint32_t command, uint16_t sequenceNumber) +{ + uint8_t merged = (uint8_t)(((flags & 0x0F) << 4) | (command & 0x0F)); + + writer->WriteU8((uint8_t)channel); + writer->WriteU8(merged); + writer->WriteU16(sequenceNumber); +} + +/*************************************************************************/ + +bool ZNetPrivate::SendAll(SST_Socket s, const SST_NetAddress* addr, uint8_t* data, uint32_t length) +{ + size_t totalSent; + if(SST_Net_SendTo(s, data, length, 0, addr, &totalSent) == SSTNETRESULT_SUCCESS) + { + //Return true if and only if all data was sent + return ((uint32_t)totalSent == length); + } + + //Failed to send at all... :( + return false; +} + +/*************************************************************************/ + +int ZNetPrivate::ReadNextMessage(ZBinaryBufferReader* reader, ZNetPrivate::ZNetMessageContainer* msgReturn) +{ + if(reader->GetLength() - reader->GetOffset() == 0) + return 0; + if(!reader->CanRead(ZNET_WIRESIZE_MESSAGE_HEADER)) + return -1; //error in stream + + //Read channel + msgReturn->channel = reader->ReadU8(); + + //Read command+flags (merged 8-bit value) + uint8_t cmdAndFlags = reader->ReadU8(); + + msgReturn->command = (cmdAndFlags & 0x0F) >> 0; + msgReturn->flags = (cmdAndFlags & 0xF0) >> 4; + + msgReturn->sequence = reader->ReadU16(); + + //Validate the command is OK + if(!ZNetPrivate::IsValidCommand(msgReturn->command)) + return -1; + + //TODO: validate flags for each command. + + //Ensure we can read at least the minimum number of bytes required for the command + if(!reader->CanRead(ZNetPrivate::MinimumSizeForCommand(msgReturn->command))) + return -1; + + switch(msgReturn->command) + { + case ZNETCMD_CONNECT: + case ZNETCMD_DISCONNECT: + case ZNETCMD_CONNRESP: + { + msgReturn->parsed.connect.userdata = reader->ReadU32(); + break; + } + + + case ZNETCMD_DATA: + { + if(msgReturn->flags & ZNETCMDFLAGS_LEN8) + { + msgReturn->parsed.data.offset = reader->ReadU8(); + msgReturn->parsed.data.maxSize = reader->ReadU8(); + msgReturn->parsed.data.length = reader->ReadU8(); + } + else if(msgReturn->flags & ZNETCMDFLAGS_LEN16) + { + msgReturn->parsed.data.offset = reader->ReadU16(); + msgReturn->parsed.data.maxSize = reader->ReadU16(); + msgReturn->parsed.data.length = reader->ReadU16(); + } + else if(msgReturn->flags & ZNETCMDFLAGS_LEN32) + { + msgReturn->parsed.data.offset = reader->ReadU32(); + msgReturn->parsed.data.maxSize = reader->ReadU32(); + msgReturn->parsed.data.length = reader->ReadU32(); + } + msgReturn->parsed.data.data = (uint8_t*)reader->GetBufferReadAddress(); + + //Verify access + if(!reader->CanRead(msgReturn->parsed.data.length)) + return -1; + break; + } + + case ZNETCMD_ACK: + { + msgReturn->parsed.ack.highestReceived = reader->ReadU16(); + msgReturn->parsed.ack.highestSent = reader->ReadU16(); + + //Read 8-bit, 16-bit, or 32-bit subsequence + if(msgReturn->flags & ZNETCMDFLAGS_LEN8) + msgReturn->parsed.ack.subsequence = reader->ReadU8(); + else if(msgReturn->flags & ZNETCMDFLAGS_LEN16) + msgReturn->parsed.ack.subsequence = reader->ReadU16(); + else if(msgReturn->flags & ZNETCMDFLAGS_LEN32) + msgReturn->parsed.ack.subsequence = reader->ReadU32(); + break; + } + } + + //Read a full message + return 1; +} + +/*************************************************************************/ + +uint32_t ZNetPrivate::MinimumSizeForCommand(uint32_t command) +{ + uint32_t size; + switch(command) + { + case ZNETCMD_CONNECT: size = sizeof(uint32_t); break; + case ZNETCMD_DATA: size = sizeof(uint8_t)*3; break; + case ZNETCMD_DISCONNECT: size = sizeof(uint32_t); break; + case ZNETCMD_ACK: size = 2*sizeof(uint16_t); break; + case ZNETCMD_CONNRESP: size = sizeof(uint32_t); break; + default: + SST_OS_DebugError("Should not reach here"); + size = UINT32_MAX; + break; + } + + return size; +} diff --git a/ZNet/ZNetPrivate.hpp b/ZNet/ZNetPrivate.hpp new file mode 100644 index 0000000..db12b4e --- /dev/null +++ b/ZNet/ZNetPrivate.hpp @@ -0,0 +1,243 @@ +/* + ZNetPrivate.hpp + Author: Patrick Baggett <ptbaggett@762studios.com> + Created: 7/19/2013 + + Purpose: + + ZNet private functions and definitions + + License: + + Copyright 2013, 762 Studios +*/ + +#pragma once + +#ifndef _ZNETPRIVATE_HPP +#define _ZNETPRIVATE_HPP + +#include <ZUtil/ZBinaryBufferReader.hpp> +#include <ZUtil/ZBinaryBufferWriter.hpp> +#include <SST/SST_Net.h> + +//======================================== +// Wire format constants +//======================================== + +#define ZNET_BYTEORDER SST_BIG_ENDIAN //< Global byte order for all of ZNet + + +#define ZNET_MAGIC 0x5A //'Z' in ASCII (i.e. uppercase zed) + +#define ZNET_SYSCHANNEL 0x00u //System channel + +#define ZNETCMD_CONNECT 0x00u //Connect request, sent from client to server +#define ZNETCMD_DATA 0x01u //Data packet (or fragment of one) +#define ZNETCMD_DISCONNECT 0x02u //Disconnect request +#define ZNETCMD_ACK 0x03u //Acknowledge a range of packets, possibly including a subsequence value +#define ZNETCMD_CONNRESP 0x04u //Connection response, send from server to client +#define ZNETCMD_MAX 0x05u //First invalid value + +//For ZNETCMD_ACK/DATA, the "flag" field will be set to one of these values. +#define ZNETCMDFLAGS_LEN8 0x00u +#define ZNETCMDFLAGS_LEN16 0x01u +#define ZNETCMDFLAGS_LEN32 0x02u + +#define ZNETCMDFLAGS_FULL 0x01u + +/* + Wire Format + + RAW PACKET { + u8 ZNET_MAGIC + [ messages ] + } + + + MESSAGE { + u8 channel + u4 flags + u4 cmd + u16 seq + [ message data ] + } + + CONNECT MESSAGE { + u32 userdata + } + + DATA MESSAGE { + [if flags == ZNETCMDFLAGS_LEN8] + u8 offset + u8 max + u8 length + [if flags == ZNETCMDFLAGS_LEN16] + u16 offset + u16 max + u16 length + [if flags == ZNETCMDFLAGS_LEN32] + u32 offset + u32 max + u32 length + + u8 data[ length ] + } + + DISCONNECT MESSAGE { + u32 userdata + } + + ACK MESSAGE { + u16 highestAcked : I have received up to this point + u16 localSequence : I have sent up to this point + + [if flags == ZNETCMDFLAGS_LEN8] + u8 subsequence8 + [if flags == ZNETCMDFLAGS_LEN16] + u16 subsequence16 + [if flags == ZNETCMDFLAGS_LEN32] + u32 subsequence32 + + } + + +*/ + +#define ZNET_WIRESIZE_PACKET_HEADER (sizeof(uint8_t)) //< Size of a packet header (overhead) +#define ZNET_WIRESIZE_MESSAGE_HEADER (2*sizeof(uint8_t) + sizeof(uint16_t)) //< Size of a message header (overhead) + +#define ZNET_WIRESIZE_PACKET_MINIMUM ZNET_WIRESIZE_PACKET_HEADER + ZNET_WIRESIZE_MESSAGE_HEADER + +class ZNetPeer; + +namespace ZNetPrivate +{ + + //Used for CONNECT, DISCONNECT, CONNRESP + struct ZNetMessageConnect + { + uint32_t userdata; + }; + + //Used for ACK, ACKSUBSEQ + struct ZNetMessageAck + { + uint32_t subsequence; + uint16_t highestReceived; //Highest contiguous sequence remote host has received + uint16_t highestSent; //Highest local sequence remote host has sent + }; + + struct ZNetMessagePing + { + uint32_t token; + }; + + //Used for DATA8, DATA16, DATA32 + struct ZNetMessageData + { + uint8_t* data; //Pointer within the packet + uint32_t offset; //Offset into reassembly buffer + uint32_t maxSize; //Maximum size of reassembled packet + uint32_t length; //Length of this packet + }; + + union ZNetMessage + { + ZNetMessageConnect connect; + ZNetMessageAck ack; + ZNetMessageData data; + ZNetMessagePing ping; + }; + + struct ZNetMessageContainer + { + uint32_t channel; + uint32_t command; + uint32_t flags; + uint16_t sequence; + ZNetMessage parsed; + }; + + /* + ZNetPrivate::ParseWirePacketHeader() + + Parses the wire format packet header and returns true/false if successful. + + @param reader - The reader set to the first byte of the packet in the proper byte order + @return (bool) - True if the header is valid, false if not. + */ + bool ParseWirePacketHeader(ZBinaryBufferReader* reader); + + void WriteWirePacketHeader(ZBinaryBufferWriter* writer); + + void WriteWireMessageHeader(ZBinaryBufferWriter* writer, uint32_t channel, uint32_t flags, uint32_t command, uint16_t sequenceNumber); + + bool SendAll(SST_Socket s, const SST_NetAddress* addr, uint8_t* data, uint32_t length); + + /* + ZNetPrivate::ReadNextMessage() + + Attempt to parse the next message from a stream. + + @param reader - The binary reader + @param msgReturn - The parsed message (only when returning > 0) + @return (int) - < 0: error in stream. 0: end of stream. > 0 successfully parsed message + */ + int ReadNextMessage(ZBinaryBufferReader* reader, ZNetPrivate::ZNetMessageContainer* msgReturn); + + /* + ZNetPrivate::MinimumSizeForCommand() + + Gets the minimum size (in bytes) of a command's payload. + + @return (uint32_t) - The number of bytes + */ + uint32_t MinimumSizeForCommand(uint32_t command); + + /* + ZNetPrivate::WireSizeForCommand() + + Gets the approximate size for a simple command. This means packet header + message header + payload + + @return (uint32_t) - The number of bytes + */ + inline uint32_t WireSizeForSimpleCommand(uint32_t command) { return MinimumSizeForCommand(command) + ZNET_WIRESIZE_PACKET_MINIMUM; } + + /* + ZNetPrivate::SequenceAfter() + + Checks if seq1 comes after seq2, taking into account sequence number wraps. + + @param seq1 - The sequence number to check + @param seq2 - The existing sequence number + @return (bool) - True if seq1 comes after seq2, false if seq2 comes first or equals seq1 + */ + inline bool SequenceAfter(uint16_t seq1, uint16_t seq2) + { + return ((seq2 > seq1) && (seq2 - seq1 > UINT16_MAX/2)) || ((seq1 > seq2) && (seq1 - seq2 <= UINT16_MAX/2)); + } + + inline uint32_t PackedIntegerSize(uint32_t value) + { + if(value <= UINT8_MAX) return sizeof(uint8_t); + if(value <= UINT16_MAX) return sizeof(uint16_t); + + return sizeof(uint32_t); + } + + void SendPingCommand(bool isReply, uint32_t givenToken, ZNetPeer* peer); + + inline bool IsValidCommand(uint32_t command) { return (command < ZNETCMD_MAX); } + + inline uint32_t ZNetByteOrder32(uint32_t v) + { + #if (SST_BYTEORDER_HOST != ZNET_BYTEORDER) + v = SST_OS_ByteSwap32(v); + #endif + return v; + } +} + +#endif + diff --git a/ZNet/ZNetServer.cpp b/ZNet/ZNetServer.cpp new file mode 100644 index 0000000..9a85f14 --- /dev/null +++ b/ZNet/ZNetServer.cpp @@ -0,0 +1,403 @@ +/* + ZNetServer.cpp + Author: Patrick Baggett <ptbaggett@762studios.com> + Created: 7/18/2013 + + Purpose: + + ZNetServer -- extends ZNetHost to provide a server + + License: + + Copyright 2013, 762 Studios +*/ + +/*************************************************************************/ + +#include <ZNet/ZNetServer.hpp> +#include <ZNet/ZNetPeer.hpp> +#include <ZNet/ZNetPacket.hpp> +#include <ZUtil/ZBinaryBufferReader.hpp> +#include <SST/SST_Assert.h> //assertions +#include <SST/SST_Time.h> +#include <new> //std::nothrow + +#include "ZNetPrivate.hpp" + + +#include <stdio.h> //TEMP + +/*************************************************************************/ + +ZNetServer::ZNetServer() +{ + connectCallback = (ZNetConnectCallback)NULL; + callbackParam = NULL; + peers = NULL; + maxClients = 0; + clientCount = 0; + listenFlag = false; + + for(size_t i=0; i<ZNET_MAX_SERVER_SOCKETS; i++) + sockets[i] = 0; +} + +ZNetServer::~ZNetServer() +{ + delete[] peers; + + for(uint32_t i=0; i<ZNET_MAX_SERVER_SOCKETS; i++) + { + if(sockets[i] != 0) + SST_Net_Close(sockets[i]); + } +} + +/*************************************************************************/ + +bool ZNetServer::Initialize(uint32_t _maxClients, uint32_t _channelCount) +{ + SST_OS_DebugAssert(_maxClients > 0, "Peer count must be at least one"); + SST_OS_DebugAssert(_channelCount > 0, "Channel count must be at least one"); + + //Allocate peer classes + peers = new(std::nothrow) ZNetPeer[_maxClients]; + if(peers == NULL) + return false; + + this->maxClients = _maxClients; + this->channelCount = _channelCount; + + return true; +} + +/*************************************************************************/ + +bool ZNetServer::AddSocket(SST_Socket s) +{ + if(s == 0) + return false; + + //Scan for empty/already existing + for(uint32_t i=0; i<ZNET_MAX_SERVER_SOCKETS; i++) + { + //Already added? + if(sockets[i] == s) + return true; + else if(sockets[i] == 0) //Empty slot? + { + //Enable non-blocking mode + //TODO: once libsst-net support socket sets, use those and update API to support wait times + if(SST_Net_SetNonblock(s, 1) != SSTNETRESULT_SUCCESS) + return false; + + sockets[i] = s; + return true; + } + } + + return false; +} + +/*************************************************************************/ + +int ZNetServer::Update() +{ + bool hitError = false; + + uint64_t now = SST_OS_GetMilliTime(); + + //Update bandwidth allocation + outBW.Update(now); + + //Check for packets from each socket + for(size_t i=0; i<ZNET_MAX_SERVER_SOCKETS; i++) + { + SST_NetAddress sender; + size_t nrRecv; + uint8_t data[9000]; //On IP networks, jumbo packet size are canonically 9000 bytes. + + //Empty socket slot + if(sockets[i] == 0) + continue; + + //Empty network packet queue + SST_NetResult res; + do + { + res = SST_Net_RecvFrom(sockets[i], data, sizeof(data), 0, &sender, &nrRecv); + + //It is common that no data is available. In this case simply go to the next socket + if(res == SSTNETRESULT_WOULDBLOCK) + break; + if(res == SSTNETRESULT_SUCCESS) + this->HandlePacket(sockets[i], &sender, data, (uint32_t)nrRecv); + else if(res == SSTNETRESULT_WOULDBLOCK) + break; + else + hitError = true; + + } while(res == SSTNETRESULT_SUCCESS); + + } + + //TODO: kind of hacky, refactor. should be able to share a lot of code with client + now = SST_OS_GetMilliTime(); //since we could have processed a lot of data, update timestamp + for(uint32_t i=0; i<maxClients; i++) + { + ZNetPeer* peer = &peers[i]; + if(peer->GetState() != STATE_UNCONNECTED) + { + + if(!this->SendToPeer(peer)) + hitError = true; + + //printf("Peer %p has %u packets queued\n" + peer->SendAcksForAllChannels(); + peer->ProcessLocalAcks(); + } + } + + + + if(hitError) + return -1; + + return (HasEvent() ? 1 : 0); +} + +/*************************************************************************/ + +void ZNetServer::SendPacket(ZNetPacket* packet, ZNetPeer* peer, uint8_t channelId) +{ + SST_OS_DebugAssert(packet != NULL, "Cannot send NULL packet"); + SST_OS_DebugAssert(peer != NULL, "Cannot send to NULL peer"); + SST_OS_DebugAssert(peer >= this->peers && peer <= &this->peers[maxClients], "Peer pointer isn't part of this group!"); + + ZNetPacketChannel* channel = peer->GetPacketChannel(channelId); //GetPacketChannel() does assertion checks for valid channels + channel->QueueForSending(packet, ZNETCMD_DATA); + +} + +/*************************************************************************/ + +void ZNetServer::BroadcastPacket(ZNetPacket* packet, uint8_t channelId) +{ + SST_OS_DebugAssert(packet != NULL, "Cannot send NULL packet"); + + for(uint32_t i=0; i<maxClients; i++) + { + if(peers[i].GetState() == STATE_CONNECTED) + { + peers[i].GetPacketChannel(channelId)->QueueForSending(packet, ZNETCMD_DATA); + } + } + +} + +/*************************************************************************/ + +void ZNetServer::HandlePacket(SST_Socket s, const SST_NetAddress* addr, const uint8_t* data, uint32_t dataSize) +{ + ZNetPeer* peer = PeerForAddress(addr); + ZBinaryBufferReader reader(data, dataSize, ZNET_BYTEORDER); + + //basically: assert if peer != NULL then state != unconnected. otherwise, don't test anything + SST_OS_DebugAssert(peer != NULL ? (peer->GetState() != STATE_UNCONNECTED) : true, "Peer state is invalid"); + + + //printf("Handling packet of %u length", dataSize); + + //Valid packet header? + if(!ZNetPrivate::ParseWirePacketHeader(&reader)) + { + printf("...but it is invalid\n"); + return; + } + //printf("\n"); + + + ZNetPrivate::ZNetMessageContainer container; + + int retval; + uint64_t now = SST_OS_GetMilliTime(); + bool wasValid = true; + do + { + retval = ZNetPrivate::ReadNextMessage(&reader, &container); + if(retval > 0) + { + switch(container.command) + { + //============================================================== + //Data received + case ZNETCMD_DATA: + { + printf("ZNETCMD_DATA found, ch = %u, length = %u, offset = %u, maxSize = %u\n", + container.channel, container.parsed.data.length, container.parsed.data.offset, + container.parsed.data.maxSize); + + if(container.channel < peer->GetNumberChannels()) + { + ZNetPacketChannel* ch = peer->GetPacketChannel(container.channel); + + ch->QueueData(&container); + } + + + break; + } + + //============================================================== + //A new client wants to connect. + case ZNETCMD_CONNECT: + { + printf("ZNETCMD_CONNECT, peer = %p\n", peer); + //No peer yet + if(peer == NULL) + { + peer = FindEmptyPeerSlot(); + printf("Empty peer slot == %p\n", peer); + if(peer != NULL) + { + uint32_t clientFilterUserData; + + //Any callback function? + if(this->connectCallback) + clientFilterUserData = connectCallback(addr, container.parsed.connect.userdata, callbackParam); + else + clientFilterUserData = 0; //default to success + + //If the client passed the filter + if(clientFilterUserData == 0) + { + printf("New client connected!\n"); + ZNetPacket* packet = this->CreatePacket(NULL, sizeof(uint32_t), 0); + if(packet != NULL) + { + memset(packet->GetData(), 0, sizeof(uint32_t)); + + if(peer->Initialize(this, addr, s, this->channelCount)) + { + printf("Queueing ZNETCMD_CONNRESP"); + peer->GetPacketChannel(ZNET_SYSCHANNEL)->QueueForSending(packet, ZNETCMD_CONNRESP); + packet->ReleaseReference(); + + ZNetEvent ev; + + ev.packet = NULL; + ev.userdata = container.parsed.connect.userdata; + ev.remote = peer; + ev.type = ZNETEVENT_CONNECT; + + AddEvent(&ev); + } + } + } + else //Did not pass the filter. Directly send a response since we won't be using channels. + this->TrySendConnResp(s, addr, clientFilterUserData, 0); + } + else //Server is full + { + //It's non-critical, so if we don't have the BW, ignore it + this->TrySendConnResp(s, addr, 0, ZNETCMDFLAGS_FULL); + } + + } // else peer is known + /* + There is no "else{}" after this. If the peer is already known to us, that means + we've already queued a ZNETCMD_CONNRESP command in return. Once the remote host + receives it, they will stop spamming us with CONNECT. + */ + + break; + } //case CONNECT + //============================================================== + + //Client sent how far it is. We can safely act on this now because it does not generate any events. + //ACKs themselves do not utilize sequence numbers (they always have 0) + case ZNETCMD_ACK: + { + printf("ZNETCMD_ACK: CH %u: highestRecv = %u, highestSent = %u\n", container.channel, container.parsed.ack.highestReceived, container.parsed.ack.highestSent); + //Ensure it is a valid ack + if(container.channel < peer->GetNumberChannels()) + { + ZNetPacketChannel* channel = peer->GetPacketChannel(container.channel); + int32_t currentPing = peer->GetPing(); + + //Update ACKs, calculating an adjusted ping + channel->UpdateRemoteAck(container.parsed.ack.highestReceived, ¤tPing); + peer->SetPing(currentPing); + } + else + wasValid = false; + break; + } + + default: + SST_OS_DebugError("Not yet implemented!"); + break; + + } + } + + } while(retval > 0); + + //If all was valid, update last received time + if(wasValid && peer) + peer->SetLastReceived(now); + +} + +/*************************************************************************/ + +void ZNetServer::TrySendConnResp(SST_Socket s, const SST_NetAddress* addr, uint32_t reasonCode, uint32_t flags) +{ + if(outBW.TryAllocate(ZNetPrivate::WireSizeForSimpleCommand(ZNETCMD_CONNRESP))) + { + uint8_t data[128]; + + ZBinaryBufferWriter writer(data, sizeof(data), ZNET_BYTEORDER); + + ZNetPrivate::WriteWirePacketHeader(&writer); + ZNetPrivate::WriteWireMessageHeader(&writer, 0, flags, ZNETCMD_CONNRESP, 0); //always ch0seq0 + writer.WriteU32(reasonCode); + + //Send packet + ZNetPrivate::SendAll(s, addr, data, (uint32_t)writer.GetOffset()); + } +} + +/*************************************************************************/ + +ZNetPeer* ZNetServer::PeerForAddress(const SST_NetAddress* addr) const +{ + //TODO: At some point (maxClients > K), a hashtable would be faster. Unfortunately, ZHashMap does not have an allocation failure policy + + for(uint32_t i=0; i<maxClients; i++) + { + ZNetPeer* peer = &peers[i]; + + if(peer->GetState() != STATE_UNCONNECTED) + { + if(SST_Net_AddressCompare(peer->GetNetAddress(), addr) == 0) + return peer; + } + } + + //Does not match anyone + return NULL; +} + +/*************************************************************************/ + +ZNetPeer* ZNetServer::FindEmptyPeerSlot() +{ + for(uint32_t i=0; i<maxClients; i++) + { + if(peers[i].GetState() == STATE_UNCONNECTED) + return &peers[i]; + } + + return NULL; +} \ No newline at end of file diff --git a/ZNet/obj/x86-64/release/ZNetBandwidthMeter.o b/ZNet/obj/x86-64/release/ZNetBandwidthMeter.o new file mode 100644 index 0000000000000000000000000000000000000000..466e321bc37128db564dae8e14ca10946fd92df8 GIT binary patch literal 1944 zcmb<-^>JfjWMqH=Mg}_u1P><4z;J^F!FB*M9T>P7I2b}bI-h!U*8b=${o>K>`lCDa zOJ@KFnB~A@?fRvR3(N+I@=S<53{&mVS^5Da;n5xX!J|_E#O#J>>kL3v2Qw9HR*@7~ zodb`y>zB?$Aa-W}&km4dU$gE2ISFq53y;py2Oiz7FFd*#Jgi+G@HbCmU|{g*c6|WW z2NKpi)On%P^+#jvkLSz`4CM*kp+7(xx*a$=4|wpeKjd-n1+&Ml^WTFXFP(iv!Q=ZQ zkIoAo2Vbysy8Z#H3*hN?{lf@y#f#1W9;gtQa^SE$R3-;zg1rQif6a%=2k|_*Lmzl_ z3QUMS%;4_qY^9(PnpB!sQmSC8XQF4IYgP*88P*w^=^2>lnQ21A6^slF%?!*8EJ6MS zVG$6)z`(#*6~w?;A;2ij!_F~*k%2*m0fIr&dLY7)PoRy-nU^h-hn)i|X9E&vU|`Sy z(J=XBgnSH0oPmMC0z|{)ixKiQAaMo;hHW4kCeO4Hq5vd@1%slCh2i6WEK&^2SW_MY z12Y2?HsuV=49qyhS#gN7;Sfhk+)xz~3=9lHNbUiLAp--0HB=nN2ZtR414A@aJPfKI z9A*p*3{6n+KBzc2tU&B2ztj?^#JrU9%#@N0-_(-SBE95-0*3e~KSK*lIg8-b5}(Z6 z%o5iuTuMxXQj1edTyt^B8ybcbRXXP6<R>SVq~bQlEVLj6q#zgMNCpN42nCJ-<XC`| z0Ss_)Sa>9$sfUF}1DZH2JQ(zfD|1T{lNj`hONt<L28>mbT2aEFmy%eL$e@>0T+E=C zoS&PUnpeW0mzQ6Xs^{((s#{!=n4Ha^SCpEQsF#`%pH`HZn+mmwGD;ehrx+L*&{GV| z-!7npjAR9J*nor;q59ENXbYM?kXjH%7glFrU;yP)a`o##?Kc1!j)Y<Mn<9yUm@xZc zG)NxC2Fb(lPHciuyI^WSv=>wiJzNez_0Iq)Lc$=wB5@g985kHqxe^xMFgXQ~AOiyf zES+&e;|Qi7ly5<51sOo)28e}<8=(3_P=%3lIz$5GOmw${WFnw~3Lpgx3=CY*ctW=y W<Sz8M1L?1T3N8k5kTBFZxCj8aiWy}9 literal 0 HcmV?d00001 diff --git a/ZNet/obj/x86-64/release/ZNetClient.o b/ZNet/obj/x86-64/release/ZNetClient.o new file mode 100644 index 0000000000000000000000000000000000000000..892978e443b9695c18758d7d7409271dfe45b63b GIT binary patch literal 31968 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 De;8AO literal 0 HcmV?d00001 diff --git a/ZNet/obj/x86-64/release/ZNetHost.o b/ZNet/obj/x86-64/release/ZNetHost.o new file mode 100644 index 0000000000000000000000000000000000000000..452ee274ea9150880f8a186c29fe8bef12649dc2 GIT binary patch literal 17032 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 XEH?WSpi8w~pzRo#!65r!Y!D3qP`JvZ literal 0 HcmV?d00001 diff --git a/ZNet/obj/x86-64/release/ZNetPacketChannel.o b/ZNet/obj/x86-64/release/ZNetPacketChannel.o new file mode 100644 index 0000000000000000000000000000000000000000..6fff3ab9754c03026f110498ab26d3200491e2d1 GIT binary patch literal 74416 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 literal 0 HcmV?d00001 diff --git a/ZNet/obj/x86-64/release/ZNetPeer.o b/ZNet/obj/x86-64/release/ZNetPeer.o new file mode 100644 index 0000000000000000000000000000000000000000..d7e9953d2937abd0b073c8568e1e6376598a77ba GIT binary patch literal 41312 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 literal 0 HcmV?d00001 diff --git a/ZNet/obj/x86-64/release/ZNetPrivate.o b/ZNet/obj/x86-64/release/ZNetPrivate.o new file mode 100644 index 0000000000000000000000000000000000000000..d7d95975ee792ab857dbc98efbc317e238d10bc3 GIT binary patch literal 6216 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 literal 0 HcmV?d00001 diff --git a/ZNet/obj/x86-64/release/ZNetServer.o b/ZNet/obj/x86-64/release/ZNetServer.o new file mode 100644 index 0000000000000000000000000000000000000000..54d7d250b92ffb637c72bfb59c43953fd2f77a07 GIT binary patch literal 37768 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�#U3bqhoztnPt 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 RLXZPN20}5&J}47R0RX&VQHKBk literal 0 HcmV?d00001 diff --git a/ZTestSuite/FileSystemTestDir/ZFileSystemTest-001.txt b/ZTestSuite/FileSystemTestDir/ZFileSystemTest-001.txt new file mode 100644 index 0000000..f2ba8f8 --- /dev/null +++ b/ZTestSuite/FileSystemTestDir/ZFileSystemTest-001.txt @@ -0,0 +1 @@ +abc \ No newline at end of file diff --git a/ZTestSuite/FileSystemTestDir/ZFileSystemTest-002 b/ZTestSuite/FileSystemTestDir/ZFileSystemTest-002 new file mode 100644 index 0000000..d7186c1 --- /dev/null +++ b/ZTestSuite/FileSystemTestDir/ZFileSystemTest-002 @@ -0,0 +1,4 @@ +test +this is +a +test \ No newline at end of file diff --git a/ZTestSuite/FileSystemTestDir/ZFileSystemTest-7z.zep b/ZTestSuite/FileSystemTestDir/ZFileSystemTest-7z.zep new file mode 100644 index 0000000000000000000000000000000000000000..13a91f6adc178fed074a502da94a8c53c82a0408 GIT binary patch literal 127 zcmXr7+Ou9=hJo4S_Sy@)3=j|mp%{MlDm-VfnCs!XBWk5!$aMw=Miw>(MowM^c5X%n zMrCG3M%Gvc21W)RZUzo6#^+D(%wk|*WfT-;NMR^tNM^`pC}z-OC}F5zC}Ch=5aD8E Vn9{TP?fcWG8AaI`85F>l006W$8P)&* literal 0 HcmV?d00001 diff --git a/ZTestSuite/FileSystemTestDir/ZFileSystemTest-ZIP.zep b/ZTestSuite/FileSystemTestDir/ZFileSystemTest-ZIP.zep new file mode 100644 index 0000000000000000000000000000000000000000..79ecf5eb673b3155daee2c969207ef1570cdc975 GIT binary patch literal 282 zcmWIWW@Zs#U|`^2m^jtbZuUhpK2Zh+1~CQ(24MyUhA6kpoYdgT;*!+dkksN5T>}Fn zZBJdjhflRmp3n(9q4Vsi7t5wbB?g!&3=CCMJ?#!Ts+ck}Fff3yI95{(^-3yA5|fex zycwB97;xLqz`(%3$e;kCu$p6pFaW#NAe|5c+^`w|c1VCXD;r2569W@N8v_GF9f-pK E0PSWv{{R30 literal 0 HcmV?d00001 diff --git a/ZTestSuite/FileSystemTestDir/test1.xml b/ZTestSuite/FileSystemTestDir/test1.xml new file mode 100644 index 0000000..d9e7cd5 --- /dev/null +++ b/ZTestSuite/FileSystemTestDir/test1.xml @@ -0,0 +1,40 @@ +<?xml version="1.0"?> +<building> + <assetInfo> + <version specRev="1" /> + <authoring name="Chris Ertel" email="cre1@www.762studios.com" copyright="Copyright 2010" license="CCSA"/> + <title string="ZomCo office"/> + <validationFlags unique="false" maxSeen="12" /> + </assetInfo> + + <assetDependencies> + <dependency package="textures\houseWalls"/> + <dependency package="textures\houseFloors"/> + <dependency package="objects\houseAppliances"/> + </assetDependencies> + + <construction> + <walls> + <wallSegment wallType="Stucco3" fromSpot="3,3" toSpot="3,6" baseAltitude="0" wallHeight="2"/> + </walls> + + <floors> + <floorSegment floorType="Stucco3" NWCorner="3,3" SECorner="6,6" baseAltitude="0" /> + </floors> + + <ceilings> + <ceilingSegment ceilingType="Stucco3" NWCorner="3,3" SECorner="6,6" baseAltitude="0" /> + </ceilings> + </construction> + + <layout> + <space spaceType="Living room" NWCorner="3,3" SECorner="6,6" baseAltitude="0" height="3"/> + <space spaceType="Kitchen" NWCorner="3,3" SECorner="6,6" baseAltitude="0" height="3"/> + <space spaceType="Bed room" NWCorner="3,3" SECorner="6,6" baseAltitude="0" height="3"/> + </layout> + + <furnishings> + <object name="smallLamp" pos="24.42,43.32,239.15" rot=".4324 .24232 .12342 .23432" /> + <object name="book" pos="24.42,43.32,239.15" rot=".4234 .4323 .12364 .8654" /> + </furnishings> +</building> \ No newline at end of file diff --git a/ZTestSuite/FileSystemTestDir/testAttributes.xml b/ZTestSuite/FileSystemTestDir/testAttributes.xml new file mode 100644 index 0000000..5ab083f --- /dev/null +++ b/ZTestSuite/FileSystemTestDir/testAttributes.xml @@ -0,0 +1,18 @@ +<?xml version="1.0" ?> +<!-- +This is a sample XML file for testing attributes. + +It has multiple elements, testing string, real, integer, body text, and boolean attributes. +--> +<collection> + <speech> + "For score and seven years ago, our forefathers in order to form a more perfect union brought + forth on this Earth a great nation." + </speech> + <speech author="Nixon, D." published="1860" approvalRating=".5" veracity="false"> + "I am not a crook." + </speech> + <speech author="Chaplin, Charlie" published="1860" approvalRating="3" veracity="bogus"/> + <speech author="" published="bogus" approvalRating="bogus" veracity="bogus"> + </speech> +</collection> \ No newline at end of file diff --git a/ZTestSuite/FileSystemTestDir/writedir/FileWriteTest b/ZTestSuite/FileSystemTestDir/writedir/FileWriteTest new file mode 100644 index 0000000..325c6c6 --- /dev/null +++ b/ZTestSuite/FileSystemTestDir/writedir/FileWriteTest @@ -0,0 +1 @@ +ABCDEFG \ No newline at end of file diff --git a/ZTestSuite/FileSystemTestDir/writedir/ZRegistryTestWrite.ini b/ZTestSuite/FileSystemTestDir/writedir/ZRegistryTestWrite.ini new file mode 100644 index 0000000..f9347c5 --- /dev/null +++ b/ZTestSuite/FileSystemTestDir/writedir/ZRegistryTestWrite.ini @@ -0,0 +1,4 @@ +[Header1] +Variable1=Value1 +Variable2=Value2 + diff --git a/ZTestSuite/Makefile b/ZTestSuite/Makefile new file mode 100644 index 0000000..8436f31 --- /dev/null +++ b/ZTestSuite/Makefile @@ -0,0 +1,112 @@ +# Test App - Util/Makefile +# Makefile for Util, requires GNU "make" +.PHONY: release debug + +#Required libraries +REQ_LIBS := libZUtil.a libsst-concurrency.a libsst-os.a libsst-atomic.a libsst-crypto.a libsst-random.a libsst-math.a + +#Name of binary +BINNAME := ZTestSuite.bin + +#In debug mode, use debug versions of libraries +ifeq ($(TARGET),debug) + REQ_LIBS := $(foreach lib,$(REQ_LIBS), $(subst .a,_d.a, $(lib))) + BINNAME := $(subst .bin,_d.bin, $(BINNAME)) +endif + +# Generate the lib names with the full dist name. +# This is only used for dependency checking +REQ_LIBS_DIST := $(foreach lib,$(REQ_LIBS), $(DIST)/$(lib)) + +#Generate LDFLAGS for $REQ_LIBS: "libfoo.a" becomes "-lfoo" +REQ_LIBS_LDFLAGS := $(foreach lib,$(REQ_LIBS), $(subst lib,-l,$(lib))) +REQ_LIBS_LDFLAGS := -L$(DIST) $(foreach lib,$(REQ_LIBS_LDFLAGS), $(subst .a,,$(lib))) + +override LDFLAGS := $(subst noop,noop, -L.. $(REQ_LIBS_LDFLAGS) $(LDFLAGS)) $(ZENGINE_BASE_LIBS) + +SRC = \ + Test-SST_Atomic.cpp \ + Test-SST_Endian.cpp \ + Test-SST_SafeArithmetic.cpp \ + Test-SST_FileSys.cpp \ + Test-ZAlloc.cpp \ + Test-ZAllocWindow.cpp \ + Test-ZArrayAlgo.cpp \ + Test-ZArray.cpp \ + Test-ZAssert.cpp \ + Test-ZBasicStringAlgo.cpp \ + Test-ZBasicString.cpp \ + Test-ZConcurrency.cpp \ + Test-ZHashMap.cpp \ + Test-ZIniReader.cpp \ + Test-ZIniWriter.cpp \ + Test-ZJSONReader.cpp \ + Test-ZJSONWriter.cpp \ + Test-ZKVTree.cpp \ + Test-ZListAlgo.cpp \ + Test-ZList.cpp \ + Test-ZName.cpp \ + Test-ZRandomGenerator.cpp \ + Test-ZReferenceCounter.cpp \ + Test-ZRegistry.cpp \ + Test-ZRingBuffer.cpp \ + Test-ZSimplexNoise.cpp \ + Test-ZSlabAllocator.cpp \ + Test-ZSmartPointer.cpp \ + Test-ZTaskStream.cpp \ + Test-ZWeakPointer.cpp \ + Test-ZXMLReader.cpp \ + Test-ZXMLWriter.cpp \ + ZTestSuiteMain.cpp \ + ZUnitTest.cpp + + +SRC+= \ + Test-SST_Mat22d.cpp \ + Test-SST_Mat22f.cpp \ + Test-SST_Mat22i.cpp \ + Test-SST_Mat22u.cpp \ + Test-SST_Mat33d.cpp \ + Test-SST_Mat33f.cpp \ + Test-SST_Mat33i.cpp \ + Test-SST_Mat33u.cpp \ + Test-SST_Mat44d.cpp \ + Test-SST_Mat44f.cpp \ + Test-SST_Mat44i.cpp \ + Test-SST_Mat44u.cpp \ + Test-SST_Vec2d.cpp \ + Test-SST_Vec2f.cpp \ + Test-SST_Vec2i.cpp \ + Test-SST_Vec2u.cpp \ + Test-SST_Vec3d.cpp \ + Test-SST_Vec3f.cpp \ + Test-SST_Vec3i.cpp \ + Test-SST_Vec3u.cpp \ + Test-SST_Vec4d.cpp \ + Test-SST_Vec4f.cpp \ + Test-SST_Vec4i.cpp \ + Test-SST_Vec4u.cpp \ + Test-SST_Transform.cpp \ + Test-SST_Geo.cpp +# Test-SST_Net.cpp + + + +OBJ := $(addprefix obj/$(ARCH)/$(TARGET)/,$(subst .cpp,.o,$(SRC)) ) +$(shell mkdir -p obj/$(ARCH)/$(TARGET)) + +all: $(BINNAME) + +# CLEAN +clean: + @-rm -r -f obj ZTestSuite*.bin + +$(BINNAME): $(OBJ) $(REQ_LIBS_DIST) + @echo LD $@ + $(CXX) $+ $(LDFLAGS) -o $@ + +# *.cpp files to *.o files +obj/$(ARCH)/$(TARGET)/%.o: %.cpp + @echo CXX $@ + @$(CXX) $(CXXFLAGS) -I../Include -I../Lib/Include -c $< -o $@ + diff --git a/ZTestSuite/Test-SST_Atomic.cpp b/ZTestSuite/Test-SST_Atomic.cpp new file mode 100644 index 0000000..c0d8fa3 --- /dev/null +++ b/ZTestSuite/Test-SST_Atomic.cpp @@ -0,0 +1,430 @@ +#include "ZUnitTest.hpp" + +#include <SST/SST_Atomic.h> + +#include <stdio.h> +#include <stdlib.h> + +static const char* testAdd(); +static const char* testAddPtr(); +static const char* testAnd(); +static const char* testOr(); +static const char* testXor(); +static const char* testNot(); + +static const char* testAddRet(); +static const char* testAddPtrRet(); +static const char* testAndRet(); +static const char* testOrRet(); +static const char* testXorRet(); +static const char* testNotRet(); + +static const char* testXadd(); +static const char* testXaddPtr(); +static const char* testXchg(); +static const char* testXchgPtr(); +static const char* testCAS(); +static const char* testCASPtr(); + +static const char* testLdAq(); +static const char* testLdAqPtr(); +static const char* testStRel(); +static const char* testStRelPtr(); + + +//List of unit tests +ZUnitTest SST_AtomicUnitTests[] = +{ + { "SST_Atomic: AtomicAdd()", testAdd }, + { "SST_Atomic: AtomicAddPtr()", testAddPtr }, + { "SST_Atomic: AtomicAnd()", testAnd }, + { "SST_Atomic: AtomicOr()", testOr }, + { "SST_Atomic: AtomicXor()", testXor }, + { "SST_Atomic: AtomicNot()", testNot }, + + { "SST_Atomic: AtomicAdd()", testAddRet }, + { "SST_Atomic: AtomicAddPtr()", testAddPtrRet }, + { "SST_Atomic: AtomicAnd()", testAndRet }, + { "SST_Atomic: AtomicOr()", testOrRet }, + { "SST_Atomic: AtomicXor()", testXorRet }, + { "SST_Atomic: AtomicNot()", testNotRet }, + + { "SST_Atomic: AtomicXadd()", testXadd }, + { "SST_Atomic: AtomicXaddPtr()", testXaddPtr }, + { "SST_Atomic: AtomicXchg()", testXchg }, + { "SST_Atomic: AtomicXchgPtr()", testXchgPtr }, + { "SST_Atomic: AtomicCAS()", testCAS }, + { "SST_Atomic: AtomicCASPtr()", testCASPtr }, + + { "SST_Atomic: AtomicLoadAcquire()", testLdAq }, + { "SST_Atomic: AtomicLoadAcquirePtr()", testLdAqPtr }, + { "SST_Atomic: AtomicStoreRelease()", testStRel }, + { "SST_Atomic: AtomicStoreReleasePtr()", testStRelPtr }, +}; + +DECLARE_ZTESTBLOCK(SST_Atomic); + +/*************************************************************************/ + +static const char* testAdd() +{ + int v = 0x100; + + SST_Atomic_Add(&v, 0x50); + + TASSERT(v == 0x150, "Add() computed incorrect value"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* testAddPtr() +{ + char data[64]; + volatile void* ptr = (void*)&data; + + + for(size_t i=0; i<sizeof(data)/sizeof(char); i++) + data[i] = (char)(i&0xFF); + + SST_Atomic_AddPtr(&ptr, 32); + + TASSERT(ptr == &data[32], "AddPtr() computed incorrect value"); + + //Check for corruption in the array + for(size_t i=0; i<sizeof(data)/sizeof(char); i++) + TASSERT(data[i] == (char)(i&0xFF), "AddPtr() corrupted what was being pointed to!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* testAnd() +{ + int x = 0xAABBCCDD; + + SST_Atomic_And(&x, 0xFF00FF00); + + TASSERT(x == (int)0xAA00CC00, "And() computed incorrect value"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* testOr() +{ + int x = 0xAA00CC00; + + SST_Atomic_Or(&x, 0x00220033); + + TASSERT(x == (int)0xAA22CC33, "Or() computed incorrect value"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* testXor() +{ + int x = 0xAA00CC00; + + SST_Atomic_Xor(&x, 0x0022CC33); + + TASSERT(x == (int)0xAA220033, "Xor() computed incorrect value"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* testNot() +{ + int x = 0xFF00FF00; + + SST_Atomic_Not(&x); + + TASSERT(x == (int)0x00FF00FF, "Not() computed incorrect value"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* testAddRet() +{ + int v = 0x100; + + int retval = SST_Atomic_AddReturn(&v, 0x50); + + TASSERT(retval == 0x150, "AddReturn() returned incorrect value"); + TASSERT(v == 0x150, "AddReturn() computed incorrect value"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* testAddPtrRet() +{ + char data[64]; + volatile void* ptr = (void*)&data; + + + for(size_t i=0; i<sizeof(data)/sizeof(char); i++) + data[i] = (char)(i&0xFF); + + void* retval = SST_Atomic_AddPtrReturn(&ptr, 32); + + TASSERT(retval == &data[32], "AddPtrReturn() returned incorrect value"); + TASSERT(ptr == &data[32], "AddPtrReturn() computed incorrect value"); + + //Check for corruption in the array + for(size_t i=0; i<sizeof(data)/sizeof(char); i++) + TASSERT(data[i] == (char)(i&0xFF), "AddPtrReturn() corrupted what was being pointed to!"); + + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* testAndRet() +{ + int x = 0xAABBCCDD; + + int retval = SST_Atomic_AndReturn(&x, 0xFF00FF00); + + TASSERT(retval == (int)0xAA00CC00, "AndReturn() returned incorrect value"); + TASSERT(x == (int)0xAA00CC00, "AndReturn() computed incorrect value"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* testOrRet() +{ + int x = 0xAA00CC00; + + int retval = SST_Atomic_OrReturn(&x, 0x00220033); + + TASSERT(retval == (int)0xAA22CC33, "OrReturn() returned incorrect value"); + TASSERT(x == (int)0xAA22CC33, "OrReturn() computed incorrect value"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* testXorRet() +{ + int x = 0xAA00CC00; + + int retval = SST_Atomic_XorReturn(&x, 0x0022CC33); + + TASSERT(retval == (int)0xAA220033, "XorReturn() returned incorrect value"); + TASSERT(x == (int)0xAA220033, "XorReturn() computed incorrect value"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* testNotRet() +{ + int x = 0xFF00FF00; + + int retval = SST_Atomic_NotReturn(&x); + + TASSERT(retval == (int)0x00FF00FF, "NotReturn() returned incorrect value"); + TASSERT(x == (int)0x00FF00FF, "NotReturn() computed incorrect value"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* testXadd() +{ + int x = 0x100; + + int old = SST_Atomic_ExchangeAdd(&x, 0x50); + + TASSERT(old == 0x100, "ExchangeAdd() returned incorrect original value"); + TASSERT(x == (int)0x150, "ExchangeAdd() computed incorrect value"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* testXaddPtr() +{ + char data[64]; + volatile void* ptr = (void*)&data[0]; + + + for(size_t i=0; i<sizeof(data)/sizeof(char); i++) + data[i] = (char)(i&0xFF); + + void* old = SST_Atomic_ExchangeAddPtr(&ptr, 32); + + TASSERT(old == &data[0], "ExchangeAddPtr() returned incorrect original value"); + TASSERT(ptr == &data[32], "ExchangeAddPtr() computed incorrect value"); + + //Check for corruption in the array + for(size_t i=0; i<sizeof(data)/sizeof(char); i++) + TASSERT(data[i] == (char)(i&0xFF), "ExchangeAddPtr() corrupted what was being pointed to!"); + + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* testXchg() +{ + int x = 0x100; + + int old = SST_Atomic_Exchange(&x, 0x50); + + TASSERT(old == 0x100, "Exchange() returned incorrect original value"); + TASSERT(x == (int)0x50, "Exchange() stored incorrect value"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* testXchgPtr() +{ + char data[64]; + volatile void* ptr = (void*)&data[0]; + + for(size_t i=0; i<sizeof(data)/sizeof(char); i++) + data[i] = (char)(i&0xFF); + + void* old = SST_Atomic_ExchangePtr(&ptr, &data[32]); + + TASSERT(old == &data[0], "ExchangePtr() returned incorrect original value"); + TASSERT(ptr == &data[32], "ExchangePtr() stored incorrect value"); + + //Check for corruption in the array + for(size_t i=0; i<sizeof(data)/sizeof(char); i++) + TASSERT(data[i] == (char)(i&0xFF), "ExchangePtr() corrupted what was being pointed to!"); + + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* testCAS() +{ + int x = 0x100; + int old; + + //Test fail compare + old = SST_Atomic_CAS(&x, 0x50, 0xAABBCCDD); + TASSERT(old == 0x100, "CAS() returned incorrect original value on compare fail"); + TASSERT(x == (int)0x100, "CAS() modified value on compare fail"); + + //Test successful compare + old = SST_Atomic_CAS(&x, 0x100, 0xAABBCCDD); + TASSERT(old == 0x100, "CAS() returned incorrect original value on compare success"); + TASSERT(x == (int)0xAABBCCDD, "CAS() did not correctly store on compare success"); + + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* testCASPtr() +{ + char data[64]; + volatile void* ptr = (void*)&data[0]; + void* old; + + for(size_t i=0; i<sizeof(data)/sizeof(char); i++) + data[i] = (char)(i&0xFF); + + //Failed comparison of ptr (data[0]) vs data[32] + old = SST_Atomic_CASPtr(&ptr, &data[32], &data[16]); + TASSERT(old == &data[0], "CASPtr() returned incorrect original value on compare fail"); + TASSERT(ptr == &data[0], "CASPtr() stored incorrect value on compare fail"); + + //Check for corruption in the array + for(size_t i=0; i<sizeof(data)/sizeof(char); i++) + TASSERT(data[i] == (char)(i&0xFF), "CASPtr() corrupted what was being pointed to on compare fail!"); + + //Successful comparison + old = SST_Atomic_CASPtr(&ptr, &data[0], &data[16]); + TASSERT(old == &data[0], "CASPtr() returned incorrect original value on compare success"); + TASSERT(ptr == &data[16], "CASPtr() stored incorrect value on compare success"); + + //Check for corruption in the array + for(size_t i=0; i<sizeof(data)/sizeof(char); i++) + TASSERT(data[i] == (char)(i&0xFF), "CASPtr() corrupted what was being pointed to on compare success!"); + + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* testLdAq() +{ + volatile int v = 50; + + TASSERT(SST_Atomic_LoadAcquire(&v) == 50, "Returned wrong value from load"); + + TASSERT(v == 50, "Load modified value!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* testLdAqPtr() +{ + volatile void* value = (void*)testLdAqPtr; + + TASSERT(SST_Atomic_LoadAcquirePtr(&value) == (void*)testLdAqPtr, "Returned wrong value from load pointer"); + + TASSERT(value == (void*)testLdAqPtr, "Load modified value!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* testStRel() +{ + volatile int v = 0xAABBCCDD; + + SST_Atomic_StoreRelease(&v, 0x11223344); + + TASSERT(v == 0x11223344, "Store did not properly store the value!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* testStRelPtr() +{ + volatile void* v = (void*)testStRelPtr; + + SST_Atomic_StoreReleasePtr(&v, (void*)testLdAqPtr); + + TASSERT(v == (void*)testLdAqPtr, "Store did not properly store the value!"); + + return ZTEST_SUCCESS; + +} + +/*************************************************************************/ diff --git a/ZTestSuite/Test-SST_Endian.cpp b/ZTestSuite/Test-SST_Endian.cpp new file mode 100644 index 0000000..f74d53b --- /dev/null +++ b/ZTestSuite/Test-SST_Endian.cpp @@ -0,0 +1,219 @@ +/* + Test-SST_Endian.cpp + Author: Patrick Baggett <ptbaggett@762studios.com> + Created: 4/18/2012 + + Purpose: + + Tests libsst-os byte swapping functions + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ + +#include "ZUnitTest.hpp" + +#include <SST/SST_Endian.h> + +static const char* testHostEndian(); +static const char* testBswap16(); +static const char* testBswap32(); +static const char* testBswap64(); +static const char* testHost2BE(); +static const char* testHost2LE(); +static const char* testBE2Host(); +static const char* testLE2Host(); + +#if SST_COMPILER == SST_COMPILER_MSVC +#pragma warning(push) +#pragma warning(disable:4127) +#endif + +//List of unit tests +ZUnitTest SST_EndianUnitTests[] = +{ + { "SST_Endian: GetHostEndianness()", testHostEndian }, + { "SST_Endian: ByteSwap16()", testBswap16 }, + { "SST_Endian: ByteSwap32()", testBswap32 }, + { "SST_Endian: ByteSwap64()", testBswap64 }, + { "SST_Endian: HostToBE[16/32/64]()", testHost2BE }, + { "SST_Endian: HostToLE[16/32/64]()", testHost2LE }, + { "SST_Endian: BEToHost[16/32/64]()", testBE2Host }, + { "SST_Endian: LEToHost[16/32/64]()", testLE2Host } +}; + +DECLARE_ZTESTBLOCK(SST_Endian); + +/*************************************************************************/ + +static const char* testHostEndian() +{ + #if defined(SST_BYTEORDER_LITTLE_ENDIAN) + const SST_ByteOrder compileTimeEndianness = SST_LITTLE_ENDIAN; + #else + const SST_ByteOrder compileTimeEndianness = SST_BIG_ENDIAN; + #endif + + TASSERT(compileTimeEndianness == SST_OS_GetHostEndianness(), "Compile-time byte-order does not match runtime byte-order"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* testBswap16() +{ + const uint16_t v1 = 0xAABB; + const uint16_t v2 = 0xBBAA; + + TASSERT(SST_OS_ByteSwap16(v1) == v2, "ByteSwap16() does not swap properly"); + + + TASSERT(SST_OS_ByteSwap16(SST_OS_ByteSwap16(v1)) == v1, "ByteSwap16() 2x doesn't return same value"); + + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* testBswap32() +{ + const uint32_t v1 = 0xAABBCCDD; + const uint32_t v2 = 0xDDCCBBAA; + + TASSERT(SST_OS_ByteSwap32(v1) == v2, "ByteSwap32() does not swap properly"); + + + TASSERT(SST_OS_ByteSwap32(SST_OS_ByteSwap32(v1)) == v1, "ByteSwap32() 2x doesn't return same value"); + + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* testBswap64() +{ + const uint64_t v1 = 0xAABBCCDD00112233ull; + const uint64_t v2 = 0x33221100DDCCBBAAull; + + TASSERT(SST_OS_ByteSwap64(v1) == v2, "ByteSwap64() does not swap properly"); + + + TASSERT(SST_OS_ByteSwap64(SST_OS_ByteSwap64(v1)) == v1, "ByteSwap64() 2x doesn't return same value"); + + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* testHost2BE() +{ + const uint16_t a1 = 0xAABB; + const uint32_t b1 = 0xAABBCCDD; + const uint64_t c1 = 0xAABBCCDD00112233ull; + + #if defined(SST_BYTEORDER_LITTLE_ENDIAN) + const uint16_t a2 = 0xBBAA; + const uint32_t b2 = 0xDDCCBBAA; + const uint64_t c2 = 0x33221100DDCCBBAAull; + #else + const uint16_t a2 = a1; + const uint32_t b2 = b1; + const uint64_t c2 = c1; + #endif + + TASSERT(SST_OS_HostToBE16(a1) == a2, "HostToBE16() incorrect"); + TASSERT(SST_OS_HostToBE32(b1) == b2, "HostToBE32() incorrect"); + TASSERT(SST_OS_HostToBE64(c1) == c2, "HostToBE64() incorrect"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* testHost2LE() +{ + const uint16_t a1 = 0xAABB; + const uint32_t b1 = 0xAABBCCDD; + const uint64_t c1 = 0xAABBCCDD00112233ull; + + #if defined(SST_BYTEORDER_LITTLE_ENDIAN) + const uint16_t a2 = a1; + const uint32_t b2 = b1; + const uint64_t c2 = c1; + #else + const uint16_t a2 = 0xBBAA; + const uint32_t b2 = 0xDDCCBBAA; + const uint64_t c2 = 0x33221100DDCCBBAAull; + #endif + + + TASSERT(SST_OS_HostToLE16(a1) == a2, "HostToLE16() incorrect"); + TASSERT(SST_OS_HostToLE32(b1) == b2, "HostToLE32() incorrect"); + TASSERT(SST_OS_HostToLE64(c1) == c2, "HostToLE64() incorrect"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* testBE2Host() +{ + const uint16_t a1 = 0xAABB; + const uint32_t b1 = 0xAABBCCDD; + const uint64_t c1 = 0xAABBCCDD00112233ull; + + #if defined(SST_BYTEORDER_LITTLE_ENDIAN) + const uint16_t a2 = 0xBBAA; + const uint32_t b2 = 0xDDCCBBAA; + const uint64_t c2 = 0x33221100DDCCBBAAull; + #else + const uint16_t a2 = a1; + const uint32_t b2 = b1; + const uint64_t c2 = c1; + #endif + + TASSERT(SST_OS_BEToHost16(a1) == a2, "BEToHost16() incorrect"); + TASSERT(SST_OS_BEToHost32(b1) == b2, "BEToHost32() incorrect"); + TASSERT(SST_OS_BEToHost64(c1) == c2, "BEToHost64() incorrect"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* testLE2Host() +{ + const uint16_t a1 = 0xAABB; + const uint32_t b1 = 0xAABBCCDD; + const uint64_t c1 = 0xAABBCCDD00112233ull; + + #if defined(SST_BYTEORDER_LITTLE_ENDIAN) + const uint16_t a2 = a1; + const uint32_t b2 = b1; + const uint64_t c2 = c1; + #else + const uint16_t a2 = 0xBBAA; + const uint32_t b2 = 0xDDCCBBAA; + const uint64_t c2 = 0x33221100DDCCBBAAull; + #endif + + TASSERT(SST_OS_LEToHost16(a1) == a2, "LEToHost16() incorrect"); + TASSERT(SST_OS_LEToHost32(b1) == b2, "LEToHost32() incorrect"); + TASSERT(SST_OS_LEToHost64(c1) == c2, "LEToHost64() incorrect"); + + return ZTEST_SUCCESS; +} + +#if SST_COMPILER == SST_COMPILER_MSVC +#pragma warning(pop) +#endif diff --git a/ZTestSuite/Test-SST_FileSys.cpp b/ZTestSuite/Test-SST_FileSys.cpp new file mode 100644 index 0000000..2fd44fb --- /dev/null +++ b/ZTestSuite/Test-SST_FileSys.cpp @@ -0,0 +1,274 @@ +/* + Test-SST_FileSys.cpp + Author: Patrick Baggett <ptbaggett@762studios.com> + Created: 3/29/2012 + + Purpose: + + Tests libsst-os file system functions + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ + +#include "ZUnitTest.hpp" + +#include <SST/SST_FileSys.h> +#include <stdio.h> +#include <stdlib.h> + +static const char* testOpenBad(); +static const char* testOpenGood(); +static const char* testOpenOnFile(); +static const char* testOpenOnFile(); +static const char* testOpenEmpty(); +static const char* testReadNonEmpty(); +static const char* testReadEmpty(); + +//List of unit tests +ZUnitTest SST_FileSysUnitTests[] = +{ + { "SST_FileSys: OpenDirectory() on non-existent directory", testOpenBad }, + { "SST_FileSys: OpenDirectory() on valid directory with files", testOpenGood }, + { "SST_FileSys: OpenDirectory() on a file", testOpenOnFile }, + { "SST_FileSys: OpenDirectory() on a empty directory", testOpenEmpty }, + { "SST_FileSys: ReadNextDirectoryEntry() on valid directory with files", testReadNonEmpty }, + { "SST_FileSys: ReadNextDirectoryEntry() on empty directory", testReadEmpty } +}; + +DECLARE_ZTESTBLOCK(SST_FileSys); + + +/* + These tests assume a working environment that consists of: + + ./sst_fs/file1.txt (size == 32 bytes) + ./sst_fs/file2.txt (size == 0 bytes) + ./sst_fs/dir1/ + ./sst_fs/dir2/ + + +*/ + +/*************************************************************************/ + +static const char* testOpenBad() +{ + SST_Dir dir = SST_OS_OpenDirectory("./sst_fsxxxxdoesntexist"); + + if(dir != NULL) + { + SST_OS_CloseDirectory(dir); + return "Returned non-null on non-existent directory"; + } + + //Should fail due to trailing slash + dir = SST_OS_OpenDirectory("./sst_fs/"); + if(dir != NULL) + { + SST_OS_CloseDirectory(dir); + return "Returned non-null on directory that ends with a trailing slash"; + } + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* testOpenGood() +{ + SST_Dir dir = SST_OS_OpenDirectory("./sst_fs"); + + TASSERT(dir != NULL, "Returned NULL on valid directory"); + + SST_OS_CloseDirectory(dir); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* testOpenOnFile() +{ + SST_Dir dir = SST_OS_OpenDirectory("./sst_fs/file1.txt"); + + if(dir != NULL) + { + SST_OS_CloseDirectory(dir); + return "Returned non-null when opening a file"; + } + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* testOpenEmpty() +{ + SST_Dir dir = SST_OS_OpenDirectory("./sst_fs/dir1"); + + TASSERT(dir != NULL, "Returned null when opening empty directory"); + + SST_OS_CloseDirectory(dir); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* testReadNonEmpty() +{ + SST_Dir dir = SST_OS_OpenDirectory("./sst_fs"); + SST_FileInfo info; + size_t nrFoundCorrectly = 0; + + #define NR_VALID 4 + static char errorbuf[1024]; + const char* validFiles[NR_VALID] = + { + "file1.txt", + "file2.txt", + "dir1", + "dir2" + }; + + const bool validFileIsDir[NR_VALID] = + { + false, /* file1.txt is not a directory */ + false, /* file2.txt is not a directory */ + true, /* dir1 is a directory */ + true /* dir2 is a directory */ + }; + + const uint64_t validFileSize[NR_VALID] = + { + 32, /* file1.txt == 32 bytes */ + 0, /* file2.txt = 0 bytes */ + 0, /* not examined */ + 0 /* not examined */ + }; + + TASSERT(dir != NULL, "Returned NULL on valid directory"); + + int OK; + do + { + OK = SST_OS_ReadNextDirectoryEntry(dir, &info); + + + + if(OK) + { + //OK, ignore version control stuff + if(strcmp(info.name, ".svn") == 0) + continue; + + //Check for "." -- should not exist + if(strcmp(info.name, ".") == 0) + { + SST_OS_CloseDirectory(dir); + return "Found \".\" entry, but these should be remove by API"; + } + + //Check for ".." -- should not exist + if(strcmp(info.name, "..") == 0) + { + SST_OS_CloseDirectory(dir); + return "Found \"..\" entry, but these should be remove by API"; + } + + //Check if we've already found all the files required -- we shouldn't find any more + if(nrFoundCorrectly == NR_VALID) + { + SST_OS_CloseDirectory(dir); + sprintf(errorbuf, "Already found all required files (%d of them) but found another file %s (ensure test filesystem is OK, then retest)", NR_VALID, info.name); + return errorbuf; + } + + //Try to find a filename match with validFiles[] + size_t i; + for(i=0; i<NR_VALID; i++) + { + //Does it match? + if(strcmp(info.name, validFiles[i]) == 0) + { + bool isDir = (info.isDir != 0); + + if(isDir == validFileIsDir[i]) + { + //If this is a file, then check its size + if(!isDir) + { + if(validFileSize[i] == info.size) + { + nrFoundCorrectly++; + break; + } + else + { + sprintf(errorbuf, "The directory entry for %s says it is %u bytes, but it should be %u", + info.name, + (unsigned int)info.size, + (unsigned int)validFileSize[i]); + + SST_OS_CloseDirectory(dir); + return errorbuf; + } + } + else + { + nrFoundCorrectly++; + break; + } + + } + else + { + sprintf(errorbuf, "The directory entry for %s says it is a %s, but it should be a %s", + info.name, + (isDir? "directory" : "file"), + (validFileIsDir[i]? "directory" : "file")); + + SST_OS_CloseDirectory(dir); + return errorbuf; + } + } + } + + //Check if no filenames matched + if(i == NR_VALID) + { + + sprintf(errorbuf, "Found invalid file %s (ensure test filesystem is OK, then retest)", info.name); + SST_OS_CloseDirectory(dir); + return errorbuf; + } + + } //if OK + } while(OK); + + //Ensure all necessary files were found correctly + if(nrFoundCorrectly != NR_VALID) + { + SST_OS_CloseDirectory(dir); + sprintf(errorbuf, "Only %d/%d entries were found in this directory", nrFoundCorrectly, NR_VALID); + return errorbuf; + } + + #undef NR_VALID + + SST_OS_CloseDirectory(dir); + return ZTEST_SUCCESS; +} + + +static const char* testReadEmpty() +{ + return ZTEST_SUCCESS; +} \ No newline at end of file diff --git a/ZTestSuite/Test-SST_Geo.cpp b/ZTestSuite/Test-SST_Geo.cpp new file mode 100644 index 0000000..ef2ccd8 --- /dev/null +++ b/ZTestSuite/Test-SST_Geo.cpp @@ -0,0 +1,344 @@ +/* + Test-SST_Geo.cpp +Author: Charles Lena <cmlena@762studios.com> +Created: 2/22/2013 + +Purpose: + +Tests to ensure that the math geo routines function accurately. +*/ + +#include "ZUnitTest.hpp" +#include <stdio.h> +#include <stdlib.h> +#include <climits> +#include <cfloat> +#include <cmath> +#include <SST/SST_Math.h> +#include <SST/SST_Geo.h> + +inline bool fpcomp(float typed_1, float typed_2, float tol = FLT_EPSILON) +{ + return (std::abs(typed_1 - typed_2) <= tol); +} +inline bool dpcomp(double typed_1, double typed_2, double tol = DBL_EPSILON) +{ + return (std::abs(typed_1 - typed_2) <= tol); +} +static const char* testSST_Geo_Intersect(); +static const char* testSST_Geo_RayPlaneIntersectionF(); +static const char* testSST_Geo_RayPlaneIntersectionD(); + +//List of unit tests +ZUnitTest SST_Math_GeoUnitTests[] = +{ +{"testSST_Geo_Intersect", testSST_Geo_Intersect}, +{"testSST_Geo_RayPlaneIntersectionF", testSST_Geo_RayPlaneIntersectionF}, +{"testSST_Geo_RayPlaneIntersectionD", testSST_Geo_RayPlaneIntersectionD}, +}; + +DECLARE_ZTESTBLOCK(SST_Math_Geo); + +// ======================================= +/* +*/ +#if SST_COMPILER == SST_COMPILER_MSVC +#pragma warning(push) +#pragma warning(disable:4127) +#endif +static const char* testSST_Geo_Intersect(){ + // + #define SET_LINE1(ax1,ay1,ax2,ay2) (Line1_Point1).v[0]=ax1; (Line1_Point1).v[1]=ay1; (Line1_Point2).v[0]=ax2; (Line1_Point2).v[1]=ay2 + #define SET_LINE2(ax1,ay1,ax2,ay2) (Line2_Point1).v[0]=ax1; (Line2_Point1).v[1]=ay1; (Line2_Point2).v[0]=ax2; (Line2_Point2).v[1]=ay2 + SST_Vec2f Line1_Point1, Line1_Point2, Line2_Point1, Line2_Point2; // our input test points + SST_Vec2f overlaps[2]; // will be our output argument + + // Intersection test - perpendicular lines sharing no points + SET_LINE1(0.f,0.f,0.f,1.f); + SET_LINE2(1.f,0.f,2.f,0.f); + TASSERT(SST2DLINESEGINTERSECT_NONE==SST_Geo_2DSegmentSegmentIntersectionF(&Line1_Point1,&Line1_Point2,&Line2_Point1,&Line2_Point2,overlaps),"Shouldn't intersect"); + + // Intersection test - perpendicular lines sharing no points - flipped + SET_LINE2(0.f,0.f,0.f,1.f); + SET_LINE1(1.f,0.f,2.f,0.f); + TASSERT(SST2DLINESEGINTERSECT_NONE==SST_Geo_2DSegmentSegmentIntersectionF(&Line1_Point1,&Line1_Point2,&Line2_Point1,&Line2_Point2,overlaps),"Shouldn't intersect - flipped"); + + // SST_Geo_2DSegmentSegmentIntersectionFion test - perpendicular lines sharing internal point + SET_LINE1(0.f,0.f,1.f,0.f); + SET_LINE2(.5f,-1.f,.5f,1.f); + TASSERT(SST2DLINESEGINTERSECT_POINT==SST_Geo_2DSegmentSegmentIntersectionF(&Line1_Point1,&Line1_Point2,&Line2_Point1,&Line2_Point2,overlaps),"Should intersect"); + + // SST_Geo_2DSegmentSegmentIntersectionFion test - perpendicular lines sharing internal point + SET_LINE2(0.f,0.f,1.f,0.f); + SET_LINE1(.5f,-1.f,.5f,1.f); + TASSERT(SST2DLINESEGINTERSECT_POINT==SST_Geo_2DSegmentSegmentIntersectionF(&Line1_Point1,&Line1_Point2,&Line2_Point1,&Line2_Point2,overlaps),"Should intersect - flipped"); + + // SST_Geo_2DSegmentSegmentIntersectionFion test - perpendicular lines sharing internal-bound 1-2 + SET_LINE1(0.f,0.f,1.f,0.f); + SET_LINE2(.5f,0.f,.5f,1.f); + TASSERT(SST2DLINESEGINTERSECT_POINT==SST_Geo_2DSegmentSegmentIntersectionF(&Line1_Point1,&Line1_Point2,&Line2_Point1,&Line2_Point2,overlaps),"Should intersect - flipped"); + + // SST_Geo_2DSegmentSegmentIntersectionFion test - perpendicular lines sharing internal-bound 1-1 + SET_LINE1(0.f,0.f,1.f,0.f); + SET_LINE2(.5f,1.f,.5f,0.f); + TASSERT(SST2DLINESEGINTERSECT_POINT==SST_Geo_2DSegmentSegmentIntersectionF(&Line1_Point1,&Line1_Point2,&Line2_Point1,&Line2_Point2,overlaps),"Should intersect - flipped"); + + // SST_Geo_2DSegmentSegmentIntersectionFion test - perpendicular lines sharing internal-bound 2-2 + SET_LINE2(0.f,0.f,1.f,0.f); + SET_LINE1(.5f,0.f,.5f,1.f); + TASSERT(SST2DLINESEGINTERSECT_POINT==SST_Geo_2DSegmentSegmentIntersectionF(&Line1_Point1,&Line1_Point2,&Line2_Point1,&Line2_Point2,overlaps),"Should intersect - flipped"); + + // SST_Geo_2DSegmentSegmentIntersectionFion test - perpendicular lines sharing bound point 2-1 + SET_LINE2(0.f,0.f,1.f,0.f); + SET_LINE1(.5f,1.f,.5f,0.f); + TASSERT(SST2DLINESEGINTERSECT_POINT==SST_Geo_2DSegmentSegmentIntersectionF(&Line1_Point1,&Line1_Point2,&Line2_Point1,&Line2_Point2,overlaps),"Should intersect - flipped"); + + // SST_Geo_2DSegmentSegmentIntersectionFion test - perpendicular lines sharing bound point 1-1 + SET_LINE1(0.f,0.f,0.f,1.f); + SET_LINE2(0.f,0.f,1.f,0.f); + TASSERT(SST2DLINESEGINTERSECT_POINT==SST_Geo_2DSegmentSegmentIntersectionF(&Line1_Point1,&Line1_Point2,&Line2_Point1,&Line2_Point2,overlaps),"Should intersect - flipped"); + + // SST_Geo_2DSegmentSegmentIntersectionFion test - perpendicular lines sharing bound point 1-2 + SET_LINE2(0.f,0.f,0.f,1.f); + SET_LINE1(0.f,0.f,1.f,0.f); + TASSERT(SST2DLINESEGINTERSECT_POINT==SST_Geo_2DSegmentSegmentIntersectionF(&Line1_Point1,&Line1_Point2,&Line2_Point1,&Line2_Point2,overlaps),"Should intersect - flipped"); + + // SST_Geo_2DSegmentSegmentIntersectionFion test - perpendicular lines sharing bound point 2-1 + SET_LINE1(0.f,0.f,0.f,1.f); + SET_LINE2(1.f,0.f,0.f,0.f); + TASSERT(SST2DLINESEGINTERSECT_POINT==SST_Geo_2DSegmentSegmentIntersectionF(&Line1_Point1,&Line1_Point2,&Line2_Point1,&Line2_Point2,overlaps),"Should intersect - flipped"); + + // SST_Geo_2DSegmentSegmentIntersectionFion test - perpendicular lines sharing bound point 2-2 + SET_LINE2(0.f,0.f,0.f,1.f); + SET_LINE1(1.f,0.f,0.f,0.f); + TASSERT(SST2DLINESEGINTERSECT_POINT==SST_Geo_2DSegmentSegmentIntersectionF(&Line1_Point1,&Line1_Point2,&Line2_Point1,&Line2_Point2,overlaps),"Should intersect - flipped"); + + // SST_Geo_2DSegmentSegmentIntersectionFion test - pi/4 oriented lines sharing no points + SET_LINE1(0.f,0.f,1.f,0.f); + SET_LINE2(0.f,1.f,2.f,2.f); + TASSERT(SST2DLINESEGINTERSECT_NONE==SST_Geo_2DSegmentSegmentIntersectionF(&Line1_Point1,&Line1_Point2,&Line2_Point1,&Line2_Point2,overlaps),"Shouldn't intersect"); + + // SST_Geo_2DSegmentSegmentIntersectionFion test - pi/4 oriented lines sharing internal point + SET_LINE1(0.f,0.f,1.f,0.f); + SET_LINE2(-1.f,-1.f,1.f,1.f); + TASSERT(SST2DLINESEGINTERSECT_POINT==SST_Geo_2DSegmentSegmentIntersectionF(&Line1_Point1,&Line1_Point2,&Line2_Point1,&Line2_Point2,overlaps),"Should intersect"); + + // SST_Geo_2DSegmentSegmentIntersectionFion test - pi/4 oriented lines sharing internal point + SET_LINE2(0.f,0.f,1.f,0.f); + SET_LINE1(-1.f,-1.f,1.f,1.f); + TASSERT(SST2DLINESEGINTERSECT_POINT==SST_Geo_2DSegmentSegmentIntersectionF(&Line1_Point1,&Line1_Point2,&Line2_Point1,&Line2_Point2,overlaps),"Should intersect"); + + // SST_Geo_2DSegmentSegmentIntersectionFion test - pi/4 oriented lines sharing internal point + SET_LINE1(0.f,0.f,1.f,0.f); + SET_LINE2( 1.f, 1.f,-1.f,-1.f); + TASSERT(SST2DLINESEGINTERSECT_POINT==SST_Geo_2DSegmentSegmentIntersectionF(&Line1_Point1,&Line1_Point2,&Line2_Point1,&Line2_Point2,overlaps),"Should intersect"); + + // SST_Geo_2DSegmentSegmentIntersectionFion test - pi/4 oriented lines sharing internal point + SET_LINE1(1.f,0.f,0.f,0.f); + SET_LINE2( 1.f, 1.f,-1.f,-1.f); + TASSERT(SST2DLINESEGINTERSECT_POINT==SST_Geo_2DSegmentSegmentIntersectionF(&Line1_Point1,&Line1_Point2,&Line2_Point1,&Line2_Point2,overlaps),"Should intersect"); + + // SST_Geo_2DSegmentSegmentIntersectionFion test - pi/4 oriented lines sharing internal point + SET_LINE1(1.f,0.f,0.f,0.f); + SET_LINE2(-1.f,-1.f, 1.f, 1.f); + TASSERT(SST2DLINESEGINTERSECT_POINT==SST_Geo_2DSegmentSegmentIntersectionF(&Line1_Point1,&Line1_Point2,&Line2_Point1,&Line2_Point2,overlaps),"Should intersect"); + + // SST_Geo_2DSegmentSegmentIntersectionFion test - pi/4 oriented lines sharing bound point - 1,2,B,1,1 + SET_LINE1(0.f,0.f,1.f,0.f); + SET_LINE2(0.f,0.f,1.f,1.f); + TASSERT(SST2DLINESEGINTERSECT_POINT==SST_Geo_2DSegmentSegmentIntersectionF(&Line1_Point1,&Line1_Point2,&Line2_Point1,&Line2_Point2,overlaps),"Should intersect"); + + // SST_Geo_2DSegmentSegmentIntersectionFion test - pi/4 oriented lines sharing bound point- 2,1,B,1,1 + SET_LINE2(0.f,0.f,1.f,0.f); + SET_LINE1(0.f,0.f,1.f,1.f); + TASSERT(SST2DLINESEGINTERSECT_POINT==SST_Geo_2DSegmentSegmentIntersectionF(&Line1_Point1,&Line1_Point2,&Line2_Point1,&Line2_Point2,overlaps),"Should intersect"); + + // SST_Geo_2DSegmentSegmentIntersectionFion test - pi/4 oriented lines sharing bound point- 1,2,B,2,2 + SET_LINE1(1.f,0.f,0.f,0.f); + SET_LINE2(1.f,1.f,0.f,0.f); + TASSERT(SST2DLINESEGINTERSECT_POINT==SST_Geo_2DSegmentSegmentIntersectionF(&Line1_Point1,&Line1_Point2,&Line2_Point1,&Line2_Point2,overlaps),"Should intersect"); + + // SST_Geo_2DSegmentSegmentIntersectionFion test - pi/4 oriented lines sharing bound point- 2,1,B,2,2 + SET_LINE2(1.f,0.f,0.f,0.f); + SET_LINE1(1.f,1.f,0.f,0.f); + TASSERT(SST2DLINESEGINTERSECT_POINT==SST_Geo_2DSegmentSegmentIntersectionF(&Line1_Point1,&Line1_Point2,&Line2_Point1,&Line2_Point2,overlaps),"Should intersect"); + + // SST_Geo_2DSegmentSegmentIntersectionFion test - pi/4 oriented lines sharing bound point- 1,2,B,1,2 + SET_LINE2(0.f,0.f,1.f,0.f); + SET_LINE1(1.f,1.f,0.f,0.f); + TASSERT(SST2DLINESEGINTERSECT_POINT==SST_Geo_2DSegmentSegmentIntersectionF(&Line1_Point1,&Line1_Point2,&Line2_Point1,&Line2_Point2,overlaps),"Should intersect"); + + // SST_Geo_2DSegmentSegmentIntersectionFion test - parallel linesegs sharing no points on the line EW + SET_LINE1(0.f,0.f,1.f,0.f); + SET_LINE2(-1.f,1.f,0.f,1.f); + TASSERT(SST2DLINESEGINTERSECT_NONE==SST_Geo_2DSegmentSegmentIntersectionF(&Line1_Point1,&Line1_Point2,&Line2_Point1,&Line2_Point2,overlaps),"Should intersect"); + + // SST_Geo_2DSegmentSegmentIntersectionFion test - parallel linesegs sharing no points on the line EW + SET_LINE1(0.f,0.f,0.f,1.f); + SET_LINE2(1.f,-1.f,1.f,0.f); + TASSERT(SST2DLINESEGINTERSECT_NONE==SST_Geo_2DSegmentSegmentIntersectionF(&Line1_Point1,&Line1_Point2,&Line2_Point1,&Line2_Point2,overlaps),"Should intersect"); + + // SST_Geo_2DSegmentSegmentIntersectionFion test - parallel colinear lines sharing no points NS + SET_LINE1(0.f,0.f,0.f,1.f); + SET_LINE2(1.f,0.f,1.f,1.f); + TASSERT(SST2DLINESEGINTERSECT_NONE==SST_Geo_2DSegmentSegmentIntersectionF(&Line1_Point1,&Line1_Point2,&Line2_Point1,&Line2_Point2,overlaps),"Should intersect"); + + // SST_Geo_2DSegmentSegmentIntersectionFion test - parallel colinear lines sharing no points NS + SET_LINE2(0.f,0.f,0.f,1.f); + SET_LINE1(1.f,0.f,1.f,1.f); + TASSERT(SST2DLINESEGINTERSECT_NONE==SST_Geo_2DSegmentSegmentIntersectionF(&Line1_Point1,&Line1_Point2,&Line2_Point1,&Line2_Point2,overlaps),"Should intersect"); + + // SST_Geo_2DSegmentSegmentIntersectionFion test - parallel lines sharing one line inside the other + SET_LINE1(0.f,0.f,0.f,1.f); + SET_LINE2(0.f,-.5f,0.f,1.5f); + TASSERT(SST2DLINESEGINTERSECT_OVERLAP==SST_Geo_2DSegmentSegmentIntersectionF(&Line1_Point1,&Line1_Point2,&Line2_Point1,&Line2_Point2,overlaps),"Should intersect"); + + // SST_Geo_2DSegmentSegmentIntersectionFion test - parallel lines sharing one line inside the other + SET_LINE2(0.f,0.f,0.f,1.f); + SET_LINE1(0.f,-.5f,0.f,1.5f); + TASSERT(SST2DLINESEGINTERSECT_OVERLAP==SST_Geo_2DSegmentSegmentIntersectionF(&Line1_Point1,&Line1_Point2,&Line2_Point1,&Line2_Point2,overlaps),"Should intersect"); + + // SST_Geo_2DSegmentSegmentIntersectionFion test - parallel lines sharing some number of points > 1 + SET_LINE1(0.f,0.f,0.f,1.f); + SET_LINE2(0.f,.5f,0.f,1.5f); + TASSERT(SST2DLINESEGINTERSECT_OVERLAP==SST_Geo_2DSegmentSegmentIntersectionF(&Line1_Point1,&Line1_Point2,&Line2_Point1,&Line2_Point2,overlaps),"Should intersect"); + + // SST_Geo_2DSegmentSegmentIntersectionFion test - parallel lines sharing some number of points > 1 + SET_LINE2(0.f,0.f,0.f,1.f); + SET_LINE1(0.f,.5f,0.f,1.5f); + TASSERT(SST2DLINESEGINTERSECT_OVERLAP==SST_Geo_2DSegmentSegmentIntersectionF(&Line1_Point1,&Line1_Point2,&Line2_Point1,&Line2_Point2,overlaps),"Should intersect"); + + // SST_Geo_2DSegmentSegmentIntersectionFion test - parallel lines sharing exactly 1 point + SET_LINE1(0.f,0.f,0.f,1.f); + SET_LINE2(0.f,1.f,0.f,2.f); + TASSERT(SST2DLINESEGINTERSECT_POINT==SST_Geo_2DSegmentSegmentIntersectionF(&Line1_Point1,&Line1_Point2,&Line2_Point1,&Line2_Point2,overlaps),"Should intersect"); + + // SST_Geo_2DSegmentSegmentIntersectionFion test - parallel lines sharing exactly 1 point + SET_LINE2(0.f,0.f,0.f,1.f); + SET_LINE1(0.f,1.f,0.f,2.f); + TASSERT(SST2DLINESEGINTERSECT_POINT==SST_Geo_2DSegmentSegmentIntersectionF(&Line1_Point1,&Line1_Point2,&Line2_Point1,&Line2_Point2,overlaps),"Should intersect"); + + // SST_Geo_2DSegmentSegmentIntersectionFion test - parallel lines sharing exactly 1 point + SET_LINE1(0.f,0.f,0.f,1.f); + SET_LINE2(0.f,2.f,0.f,1.f); + TASSERT(SST2DLINESEGINTERSECT_POINT==SST_Geo_2DSegmentSegmentIntersectionF(&Line1_Point1,&Line1_Point2,&Line2_Point1,&Line2_Point2,overlaps),"Should intersect"); + + // SST_Geo_2DSegmentSegmentIntersectionFion test - parallel lines sharing exactly 1 point + SET_LINE1(0.f,1.f,0.f,0.f); + SET_LINE2(0.f,2.f,0.f,1.f); + TASSERT(SST2DLINESEGINTERSECT_POINT==SST_Geo_2DSegmentSegmentIntersectionF(&Line1_Point1,&Line1_Point2,&Line2_Point1,&Line2_Point2,overlaps),"Should intersect"); + + // SST_Geo_2DSegmentSegmentIntersectionFion test - parallel lines sharing exactly 1 point + SET_LINE1(0.f,1.f,0.f,0.f); + SET_LINE2(0.f,1.f,0.f,2.f); + TASSERT(SST2DLINESEGINTERSECT_POINT==SST_Geo_2DSegmentSegmentIntersectionF(&Line1_Point1,&Line1_Point2,&Line2_Point1,&Line2_Point2,overlaps),"Should intersect"); + + #undef SET_LINE1 + #undef SET_LINE2 + return ZTEST_SUCCESS; +} +static const char* testSST_Geo_RayPlaneIntersectionF(){ + /* Triangle ABC */ +#define SET_VEC3(a,x,y,z) (a).v[0]=x; (a).v[1]=y; (a).v[2]=z +#define COMPARE_VEC3(vec1,vec2,tol) (( std::abs(vec1.x-vec2.x)+std::abs(vec1.y-vec2.y)+std::abs(vec1.z-vec2.z) ) < tol) + SST_Vec3f A, B, C; + SET_VEC3(A,1.0f,0.0f,0.0f); + SET_VEC3(B,0.0f,1.0f,0.0f); + SET_VEC3(C,0.0f,0.0f,1.0f); + /* Origin point for rays */ + SST_Vec3f ray_point; + SET_VEC3(ray_point,1.0f,1.0f,1.0f); + SST_Vec3f ray, intersect, answer; + SET_VEC3(ray,-1.0f,-1.0f,-1.0f); + + bool inTriangle = false; + inTriangle = SST_Geo_RayPlaneIntersectionF(&ray,&ray_point,&A,&B,&C,&intersect); + /* Also, should intersect at some point which I don't know! heheheh */ + TASSERT(inTriangle,"Test1 - Should have intersected!"); + + SET_VEC3(ray,-1.0f,-1.0f,0.0f); + SET_VEC3(answer,0.0f,0.0f,1.0f); + inTriangle = SST_Geo_RayPlaneIntersectionF(&ray,&ray_point,&A,&B,&C,&intersect); + /* Also, should intersect at some point which I don't know! heheheh */ + TASSERT(COMPARE_VEC3(intersect,answer,1.0e-6),"Test 2 - Incorrect Intersection point!"); + TASSERT(inTriangle,"Test 2 - Should have intersected!"); + + SET_VEC3(ray,0.0f,-1.0f,-1.0f); + SET_VEC3(answer,1.0f,0.0f,0.0f); + inTriangle = SST_Geo_RayPlaneIntersectionF(&ray,&ray_point,&A,&B,&C,&intersect); + /* Also, should intersect at some point which I don't know! heheheh */ + TASSERT(COMPARE_VEC3(intersect,answer,1.0e-6),"Test 3 - Incorrect Intersection point!"); + TASSERT(inTriangle,"Test 3 - Should have intersected!"); + + SET_VEC3(ray,-1.0f,0.0f,-1.0f); + SET_VEC3(answer,0.0f,1.0f,0.0f); + inTriangle = SST_Geo_RayPlaneIntersectionF(&ray,&ray_point,&A,&B,&C,&intersect); + /* Also, should intersect at some point which I don't know! heheheh */ + TASSERT(COMPARE_VEC3(intersect,answer,1.0e-6),"Test 4 - Incorrect Intersection point!"); + TASSERT(inTriangle,"Test 4 - Should have intersected!"); + + SET_VEC3(A, 0.0f,0.0f,0.0f); + SET_VEC3(B, 1.0f,0.0f,0.0f); + SET_VEC3(C, 0.0f,1.0f,0.0f); + SET_VEC3(ray_point, 1.0f,1.0f,1.0f); + SET_VEC3(ray,0.0f,0.0f,-1.0f); + SET_VEC3(answer,1.0f,1.0f,0.0f); + inTriangle = SST_Geo_RayPlaneIntersectionF(&ray,&ray_point,&A,&B,&C,&intersect); + TASSERT(COMPARE_VEC3(intersect,answer,1.0e-6),"Test 4 - Incorrect Plane Intersection point!"); + TASSERT(!inTriangle,"Test 4 - Should have not intersected (with triangle)!"); + return ZTEST_SUCCESS; +} +static const char* testSST_Geo_RayPlaneIntersectionD(){ +#define SET_VEC3(a,x,y,z) (a).v[0]=x; (a).v[1]=y; (a).v[2]=z +#define COMPARE_VEC3(vec1,vec2,tol) (( std::abs(vec1.x-vec2.x)+std::abs(vec1.y-vec2.y)+std::abs(vec1.z-vec2.z) ) < tol) + SST_Vec3d A, B, C; + SET_VEC3(A,1.0,0.0,0.0); + SET_VEC3(B,0.0,1.0,0.0); + SET_VEC3(C,0.0,0.0,1.0); + /* Origin point for rays */ + SST_Vec3d ray_point; + SET_VEC3(ray_point,1.0,1.0,1.0); + SST_Vec3d ray, intersect, answer; + SET_VEC3(ray,-1.0,-1.0,-1.0); + + bool inTriangle = false; + inTriangle = SST_Geo_RayPlaneIntersectionD(&ray,&ray_point,&A,&B,&C,&intersect); + /* Also, should intersect at some point which I don't know! heheheh */ + TASSERT(inTriangle,"Test1 - Should have intersected!"); + + SET_VEC3(ray,-1.0,-1.0,0.0); + SET_VEC3(answer,0.0,0.0,1.0); + inTriangle = SST_Geo_RayPlaneIntersectionD(&ray,&ray_point,&A,&B,&C,&intersect); + /* Also, should intersect at some point which I don't know! heheheh */ + TASSERT(COMPARE_VEC3(intersect,answer,1.0e-6),"Test 2 - Incorrect Intersection point!"); + TASSERT(inTriangle,"Test 2 - Should have intersected!"); + + SET_VEC3(ray,0.0,-1.0,-1.0); + SET_VEC3(answer,1.0,0.0,0.0); + inTriangle = SST_Geo_RayPlaneIntersectionD(&ray,&ray_point,&A,&B,&C,&intersect); + /* Also, should intersect at some point which I don't know! heheheh */ + TASSERT(COMPARE_VEC3(intersect,answer,1.0e-6),"Test 3 - Incorrect Intersection point!"); + TASSERT(inTriangle,"Test 3 - Should have intersected!"); + + SET_VEC3(ray,-1.0,0.0,-1.0); + SET_VEC3(answer,0.0,1.0,0.0); + inTriangle = SST_Geo_RayPlaneIntersectionD(&ray,&ray_point,&A,&B,&C,&intersect); + /* Also, should intersect at some point which I don't know! heheheh */ + TASSERT(COMPARE_VEC3(intersect,answer,1.0e-6),"Test 4 - Incorrect Intersection point!"); + TASSERT(inTriangle,"Test 4 - Should have intersected!"); + + SET_VEC3(A, 0.0,0.0,0.0); + SET_VEC3(B, 1.0,0.0,0.0); + SET_VEC3(C, 0.0,1.0,0.0); + SET_VEC3(ray_point, 1.0,1.0,1.0); + SET_VEC3(ray,0.0,0.0,-1.0); + SET_VEC3(answer,1.0,1.0,0.0); + inTriangle = SST_Geo_RayPlaneIntersectionD(&ray,&ray_point,&A,&B,&C,&intersect); + TASSERT(COMPARE_VEC3(intersect,answer,1.0e-6),"Test 4 - Incorrect Plane Intersection point!"); + TASSERT(!inTriangle,"Test 4 - Should have not intersected (with triangle)!"); + + return ZTEST_SUCCESS; +} +#if SST_COMPILER == SST_COMPILER_MSVC +#pragma warning(pop) +#endif diff --git a/ZTestSuite/Test-SST_Mat22d.cpp b/ZTestSuite/Test-SST_Mat22d.cpp new file mode 100644 index 0000000..c3fd511 --- /dev/null +++ b/ZTestSuite/Test-SST_Mat22d.cpp @@ -0,0 +1,679 @@ +/* + AUTOMATICALLY GENERATED FILE - DO NOT EDIT! + Please change MatrixNxN.py and re-run it +*/ +/* Generated with ./MatrixNxN.py n = 2, TYPE = double */ + +#include "ZUnitTest.hpp" +#include <float.h> +#include <math.h> +#include <stdlib.h> +#include <stdio.h> +#include <SST/SST_Mat22.h> +#include <SST/SST_Vec2.h> + + + + +static const char* testSST_Math_Mat22dAdd(); +static const char* testSST_Math_Mat22dAddLocal(); +static const char* testSST_Math_Mat22dSubtract(); +static const char* testSST_Math_Mat22dSubtractLocal(); +static const char* testSST_Math_Mat22dMultiplyElementwise(); +static const char* testSST_Math_Mat22dMultiplyElementwiseLocal(); +static const char* testSST_Math_Mat22dMultiplyScalar(); +static const char* testSST_Math_Mat22dMultiplyScalarLocal(); +static const char* testSST_Math_Mat22dMultiplyMatrix(); +static const char* testSST_Math_Mat22dMultiplyMatrixLocal(); +static const char* testSST_Math_Mat22dMultiplyVector(); +static const char* testSST_Math_Mat22dMultiplyVectorLocal(); +static const char* testSST_Math_Mat22dTranspose(); +static const char* testSST_Math_Mat22dTransposeLocal(); +static const char* testSST_Math_Mat22dDeterminant(); +static const char* testSST_Math_Mat22dCheckOrthonormal(); +static const char* testSST_Math_Mat22dInvert(); +static const char* testSST_Math_Mat22dInvertLocal(); +static const char* testSST_Math_Mat22dCreateLU(); +static const char* testSST_Math_Mat22dCreateLULocal(); +static const char* testSST_Math_Mat22dApplyLUMat(); +static const char* testSST_Math_Mat22dApplyLUMatLocal(); +static const char* testSST_Math_Mat22dApplyLUVec(); +static const char* testSST_Math_Mat22dApplyLUVecLocal(); +// List of unit tests +ZUnitTest SST_Math_Mat22dUnitTests[] = +{ +{ "testSST_Math_Mat22dAdd " , testSST_Math_Mat22dAdd }, +{ "testSST_Math_Mat22dAddLocal " , testSST_Math_Mat22dAddLocal }, +{ "testSST_Math_Mat22dSubtract " , testSST_Math_Mat22dSubtract }, +{ "testSST_Math_Mat22dSubtractLocal " , testSST_Math_Mat22dSubtractLocal }, +{ "testSST_Math_Mat22dMultiplyElementwise " , testSST_Math_Mat22dMultiplyElementwise }, +{ "testSST_Math_Mat22dMultiplyElementwiseLocal " , testSST_Math_Mat22dMultiplyElementwiseLocal }, +{ "testSST_Math_Mat22dMultiplyScalar " , testSST_Math_Mat22dMultiplyScalar }, +{ "testSST_Math_Mat22dMultiplyScalarLocal " , testSST_Math_Mat22dMultiplyScalarLocal }, +{ "testSST_Math_Mat22dMultiplyMatrix " , testSST_Math_Mat22dMultiplyMatrix }, +{ "testSST_Math_Mat22dMultiplyMatrixLocal " , testSST_Math_Mat22dMultiplyMatrixLocal }, +{ "testSST_Math_Mat22dMultiplyVector " , testSST_Math_Mat22dMultiplyVector }, +{ "testSST_Math_Mat22dMultiplyVectorLocal " , testSST_Math_Mat22dMultiplyVectorLocal }, +{ "testSST_Math_Mat22dDeterminant " , testSST_Math_Mat22dDeterminant }, +{ "testSST_Math_Mat22dCheckOrthonormal " , testSST_Math_Mat22dCheckOrthonormal }, +{ "testSST_Math_Mat22dInvert " , testSST_Math_Mat22dInvert }, +{ "testSST_Math_Mat22dInvertLocal " , testSST_Math_Mat22dInvertLocal }, +{ "testSST_Math_Mat22dCreateLU " , testSST_Math_Mat22dCreateLU }, +{ "testSST_Math_Mat22dCreateLULocal " , testSST_Math_Mat22dCreateLULocal }, +{ "testSST_Math_Mat22dApplyLUMat " , testSST_Math_Mat22dApplyLUMat }, +{ "testSST_Math_Mat22dApplyLUMatLocal " , testSST_Math_Mat22dApplyLUMatLocal }, +{ "testSST_Math_Mat22dApplyLUVec " , testSST_Math_Mat22dApplyLUVec }, +{ "testSST_Math_Mat22dApplyLUVecLocal " , testSST_Math_Mat22dApplyLUVecLocal }, +{ "testSST_Math_Mat22dTranspose " , testSST_Math_Mat22dTranspose }, +{ "testSST_Math_Mat22dTransposeLocal " , testSST_Math_Mat22dTransposeLocal } +}; +DECLARE_ZTESTBLOCK(SST_Math_Mat22d) + +/******************************************************************************/ + +static const char* testSST_Math_Mat22dAdd(){ + SST_Mat22d X; /* 2 x 2 matrix */ + SST_Mat22d Y; /* 2 x 2 matrix */ + SST_Mat22d A; /* 2 x 2 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = -13.000000000000000; + X.v[1] = 3.000000000000000; + X.v[2] = 3.000000000000000; + X.v[3] = 11.000000000000000; + Y.v[0] = -20.000000000000000; + Y.v[1] = 12.000000000000000; + Y.v[2] = 2.000000000000000; + Y.v[3] = -6.000000000000000; +/* +[[-13. 3.] + [ 3. 11.]] +[[-20. 2.] + [ 12. -6.]] +[[-33. 5.] + [ 15. 5.]] +*/ + SST_Math_Mat22dAdd(&X,&Y,&A); + TASSERT(fabs((A.v[0])-( -33.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a11 failed!"); + TASSERT(fabs((A.v[2])-( 5.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a12 failed!"); + TASSERT(fabs((A.v[1])-( 15.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a21 failed!"); + TASSERT(fabs((A.v[3])-( 5.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a22 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat22dAddLocal(){ + SST_Mat22d X; /* 2 x 2 matrix */ + SST_Mat22d Y; /* 2 x 2 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = 6.000000000000000; + X.v[1] = -18.000000000000000; + X.v[2] = 11.000000000000000; + X.v[3] = -16.000000000000000; + Y.v[0] = -1.000000000000000; + Y.v[1] = 12.000000000000000; + Y.v[2] = 14.000000000000000; + Y.v[3] = -5.000000000000000; +/* +[[ 6. 11.] + [-18. -16.]] +[[ -1. 14.] + [ 12. -5.]] +[[ 5. 25.] + [ -6. -21.]] +*/ + SST_Math_Mat22dAddLocal(&X,&Y); /* for accuracy */ + TASSERT(fabs((X.v[0])-( 5.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a11 failed!"); + TASSERT(fabs((X.v[2])-( 25.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a12 failed!"); + TASSERT(fabs((X.v[1])-( -6.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a21 failed!"); + TASSERT(fabs((X.v[3])-( -21.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a22 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat22dSubtract(){ + SST_Mat22d X; /* 2 x 2 matrix */ + SST_Mat22d Y; /* 2 x 2 matrix */ + SST_Mat22d A; /* 2 x 2 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = -5.000000000000000; + X.v[1] = -10.000000000000000; + X.v[2] = 6.000000000000000; + X.v[3] = 10.000000000000000; + Y.v[0] = -16.000000000000000; + Y.v[1] = 0.000000000000000; + Y.v[2] = -4.000000000000000; + Y.v[3] = -5.000000000000000; +/* +[[ -5. 6.] + [-10. 10.]] +[[-16. -4.] + [ 0. -5.]] +[[ 11. 10.] + [-10. 15.]] +*/ + SST_Math_Mat22dSubtract(&X,&Y,&A); + TASSERT(fabs((A.v[0])-( 11.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a11 failed!"); + TASSERT(fabs((A.v[2])-( 10.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a12 failed!"); + TASSERT(fabs((A.v[1])-( -10.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a21 failed!"); + TASSERT(fabs((A.v[3])-( 15.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a22 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat22dSubtractLocal(){ + SST_Mat22d X; /* 2 x 2 matrix */ + SST_Mat22d Y; /* 2 x 2 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = -7.000000000000000; + X.v[1] = 3.000000000000000; + X.v[2] = 4.000000000000000; + X.v[3] = -16.000000000000000; + Y.v[0] = 6.000000000000000; + Y.v[1] = 5.000000000000000; + Y.v[2] = -12.000000000000000; + Y.v[3] = -20.000000000000000; +/* +[[ -7. 4.] + [ 3. -16.]] +[[ 6. -12.] + [ 5. -20.]] +[[-13. 16.] + [ -2. 4.]] +*/ + SST_Math_Mat22dSubtractLocal(&X,&Y); /* for accuracy */ + TASSERT(fabs((X.v[0])-( -13.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a11 failed!"); + TASSERT(fabs((X.v[2])-( 16.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a12 failed!"); + TASSERT(fabs((X.v[1])-( -2.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a21 failed!"); + TASSERT(fabs((X.v[3])-( 4.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a22 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat22dMultiplyElementwise(){ + SST_Mat22d X; /* 2 x 2 matrix */ + SST_Mat22d Y; /* 2 x 2 matrix */ + SST_Mat22d A; /* 2 x 2 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = -12.000000000000000; + X.v[1] = 7.000000000000000; + X.v[2] = 6.000000000000000; + X.v[3] = -2.000000000000000; + Y.v[0] = -14.000000000000000; + Y.v[1] = 2.000000000000000; + Y.v[2] = -12.000000000000000; + Y.v[3] = -3.000000000000000; +/* +[[-12. 6.] + [ 7. -2.]] +[[-14. -12.] + [ 2. -3.]] +[[ 168. -72.] + [ 14. 6.]] +*/ + SST_Math_Mat22dMultiplyElementwise(&X, &Y, &A); + TASSERT(fabs((A.v[0])-( 168.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a11 failed!"); + TASSERT(fabs((A.v[2])-( -72.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a12 failed!"); + TASSERT(fabs((A.v[1])-( 14.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a21 failed!"); + TASSERT(fabs((A.v[3])-( 6.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a22 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat22dMultiplyElementwiseLocal(){ + SST_Mat22d X; /* 2 x 2 matrix */ + SST_Mat22d Y; /* 2 x 2 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = -11.000000000000000; + X.v[1] = 4.000000000000000; + X.v[2] = 17.000000000000000; + X.v[3] = -6.000000000000000; + Y.v[0] = 9.000000000000000; + Y.v[1] = -19.000000000000000; + Y.v[2] = -7.000000000000000; + Y.v[3] = 9.000000000000000; +/* +[[-11. 17.] + [ 4. -6.]] +[[ 9. -7.] + [-19. 9.]] +[[ -99. -119.] + [ -76. -54.]] +*/ + SST_Math_Mat22dMultiplyElementwiseLocal(&X,&Y); + TASSERT(fabs((X.v[0])-( -99.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a11 failed!"); + TASSERT(fabs((X.v[2])-( -119.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a12 failed!"); + TASSERT(fabs((X.v[1])-( -76.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a21 failed!"); + TASSERT(fabs((X.v[3])-( -54.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a22 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat22dMultiplyScalar(){ + SST_Mat22d X; /* 2 x 2 matrix */ + SST_Mat22d A; /* 2 x 2 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = 0.000000000000000; + X.v[1] = 7.000000000000000; + X.v[2] = 10.000000000000000; + X.v[3] = -15.000000000000000; +/* +[[ 0. 10.] + [ 7. -15.]] +[[ 0. 20.] + [ 14. -30.]] +*/ + SST_Math_Mat22dMultiplyScalar(&X, 2.000000000000000,&A); + TASSERT(fabs((A.v[0])-( 0.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a11 failed!"); + TASSERT(fabs((A.v[2])-( 20.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a12 failed!"); + TASSERT(fabs((A.v[1])-( 14.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a21 failed!"); + TASSERT(fabs((A.v[3])-( -30.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a22 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat22dMultiplyScalarLocal(){ + SST_Mat22d X; /* 2 x 2 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = -16.000000000000000; + X.v[1] = -7.000000000000000; + X.v[2] = -14.000000000000000; + X.v[3] = 14.000000000000000; +/* +[[-16. -14.] + [ -7. 14.]] +[[-32. -28.] + [-14. 28.]] +*/ + SST_Math_Mat22dMultiplyScalarLocal(&X, 2.000000000000000); + TASSERT(fabs((X.v[0])-( -32.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a11 failed!"); + TASSERT(fabs((X.v[2])-( -28.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a12 failed!"); + TASSERT(fabs((X.v[1])-( -14.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a21 failed!"); + TASSERT(fabs((X.v[3])-( 28.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a22 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat22dMultiplyMatrix(){ + SST_Mat22d X; /* 2 x 2 matrix */ + SST_Mat22d Y; /* 2 x 2 matrix */ + SST_Mat22d A; /* 2 x 2 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = 19.000000000000000; + X.v[1] = -14.000000000000000; + X.v[2] = -18.000000000000000; + X.v[3] = -16.000000000000000; + Y.v[0] = -11.000000000000000; + Y.v[1] = 11.000000000000000; + Y.v[2] = 19.000000000000000; + Y.v[3] = -19.000000000000000; +/* +X +[[ 19. -18.] + [-14. -16.]] +Y +[[-11. 19.] + [ 11. -19.]] +[[-407. 703.] + [ -22. 38.]] +*/ + SST_Math_Mat22dMultiplyMatrix(&X,&Y,&A); + TASSERT(fabs((A.v[0])-( -407.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a11 failed!"); + TASSERT(fabs((A.v[2])-( 703.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a12 failed!"); + TASSERT(fabs((A.v[1])-( -22.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a21 failed!"); + TASSERT(fabs((A.v[3])-( 38.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a22 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat22dMultiplyMatrixLocal(){ + SST_Mat22d X; /* 2 x 2 matrix */ + SST_Mat22d Y; /* 2 x 2 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = 4.000000000000000; + X.v[1] = -12.000000000000000; + X.v[2] = 6.000000000000000; + X.v[3] = 16.000000000000000; + Y.v[0] = -6.000000000000000; + Y.v[1] = -11.000000000000000; + Y.v[2] = -19.000000000000000; + Y.v[3] = -6.000000000000000; +/* +X +[[ 4. 6.] + [-12. 16.]] +Y +[[ -6. -19.] + [-11. -6.]] +X +[[ -90. -112.] + [-104. 132.]] +*/ + SST_Math_Mat22dMultiplyMatrixLocal(&X,&Y); + TASSERT(fabs((X.v[0])-( -90.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a11 failed!"); + TASSERT(fabs((X.v[2])-( -112.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a12 failed!"); + TASSERT(fabs((X.v[1])-( -104.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a21 failed!"); + TASSERT(fabs((X.v[3])-( 132.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a22 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat22dMultiplyVector(){ + SST_Mat22d X; /* 2 x 2 matrix */ + SST_Vec2d v; /* 2 vector */ + SST_Vec2d w; /* 2 vector */ +/* Resetting test vectors / mats */ + v.v[0] = 9.000000000000000; + v.v[1] = -10.000000000000000; + X.v[0] = 4.000000000000000; + X.v[1] = 5.000000000000000; + X.v[2] = -2.000000000000000; + X.v[3] = -8.000000000000000; +/* +X +[[ 4. -2.] + [ 5. -8.]] +v +[ 9. -10.] +w +[ 56. 125.] +*/ + SST_Math_Mat22dMultiplyVector(&X,&v,&w); + TASSERT(fabs((w.v[0])-( 56.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry .v[0] failed!"); + TASSERT(fabs((w.v[1])-( 125.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry .v[1] failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat22dMultiplyVectorLocal(){ + SST_Mat22d X; /* 2 x 2 matrix */ + SST_Vec2d v; /* 2 vector */ +/* Resetting test vectors / mats */ + v.v[0] = -5.000000000000000; + v.v[1] = -14.000000000000000; + X.v[0] = -13.000000000000000; + X.v[1] = -18.000000000000000; + X.v[2] = 18.000000000000000; + X.v[3] = 18.000000000000000; +/* +X +[[-13. 18.] + [-18. 18.]] +v +[ -5. -14.] +v +[-187. -162.] +*/ + SST_Math_Mat22dMultiplyVectorLocal(&X,&v); + TASSERT(fabs((v.v[0])-( -187.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry .v[0] failed!"); + TASSERT(fabs((v.v[1])-( -162.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry .v[1] failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat22dTranspose(){ + SST_Mat22d X; /* 2 x 2 matrix */ + SST_Mat22d A; /* 2 x 2 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = 5.000000000000000; + X.v[1] = 10.000000000000000; + X.v[2] = -2.000000000000000; + X.v[3] = 17.000000000000000; + SST_Math_Mat22dTranspose(&X,&A); + TASSERT(fabs((A.v[0])-( 5.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a11 failed!"); + TASSERT(fabs((A.v[2])-( 10.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a12 failed!"); + TASSERT(fabs((A.v[1])-( -2.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a21 failed!"); + TASSERT(fabs((A.v[3])-( 17.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a22 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat22dTransposeLocal(){ + SST_Mat22d X; /* 2 x 2 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = 7.000000000000000; + X.v[1] = 13.000000000000000; + X.v[2] = -16.000000000000000; + X.v[3] = 1.000000000000000; + SST_Math_Mat22dTransposeLocal(&X); + TASSERT(fabs((X.v[0])-( 7.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a11 failed!"); + TASSERT(fabs((X.v[2])-( 13.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a12 failed!"); + TASSERT(fabs((X.v[1])-( -16.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a21 failed!"); + TASSERT(fabs((X.v[3])-( 1.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a22 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat22dCheckOrthonormal(){ + SST_Mat22d X; /* 2 x 2 matrix */ + SST_Mat22d Y; /* 2 x 2 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = -17.000000000000000; + X.v[1] = -20.000000000000000; + X.v[2] = -3.000000000000000; + X.v[3] = -2.000000000000000; + Y.v[0] = 6.000000000000000; + Y.v[1] = 16.000000000000000; + Y.v[2] = 12.000000000000000; + Y.v[3] = 17.000000000000000; +/* +[[-0.64764842 -0.76193932] + [-0.76193932 0.64764842]] +[[ 1.00000000e+00 1.66533454e-16] + [ 1.66533454e-16 1.00000000e+00]] +*/ +/* Set X to orthogonal matrix Q */ + X.v[0] = (double) -0.647648420095541; + X.v[1] = (double) -0.761939317759459; + X.v[2] = (double) -0.761939317759459; + X.v[3] = (double) 0.647648420095540; +/* Check Positive Test */ + TASSERT(SST_Math_Mat22dCheckOrthonormal(&X),"CheckOrthonormal failed when it should have passed"); +/* Check Negative Test */ + TASSERT(!SST_Math_Mat22dCheckOrthonormal(&Y),"CheckOrthonormal succeeded when it should have failed"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat22dDeterminant(){ + SST_Mat22d X; /* 2 x 2 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = -14.000000000000000; + X.v[1] = 0.000000000000000; + X.v[2] = -17.000000000000000; + X.v[3] = 9.000000000000000; +/* det(X) = +-126.0 + */ + double result = SST_Math_Mat22dDeterminant(&X); + TASSERT(fabs( (result)/( -126.000000000000000) - 1.000000000000000 ) <= 100*DBL_EPSILON,"Determinant failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat22dInvert(){ + SST_Mat22d X; /* 2 x 2 matrix */ + SST_Mat22d B; /* 2 x 2 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = -9.000000000000000; + X.v[1] = -16.000000000000000; + X.v[2] = 9.000000000000000; + X.v[3] = -15.000000000000000; +/* +[[-0.05376344 -0.03225806] + [ 0.05734767 -0.03225806]] +*/ + SST_Math_Mat22dInvert(&X,&B); + TASSERT(fabs((B.v[0])-( -0.053763440860215)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a11 failed!"); + TASSERT(fabs((B.v[1])-( 0.057347670250896)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a21 failed!"); + TASSERT(fabs((B.v[2])-( -0.032258064516129)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a12 failed!"); + TASSERT(fabs((B.v[3])-( -0.032258064516129)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a22 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat22dInvertLocal(){ + SST_Mat22d X; /* 2 x 2 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = -10.000000000000000; + X.v[1] = 15.000000000000000; + X.v[2] = -5.000000000000000; + X.v[3] = -8.000000000000000; +/* +() +[[-0.0516129 0.03225806] + [-0.09677419 -0.06451613]] +*/ + SST_Math_Mat22dInvertLocal(&X); + TASSERT(fabs((X.v[0])-( -0.051612903225806)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a11 failed!"); + TASSERT(fabs((X.v[1])-( -0.096774193548387)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a21 failed!"); + TASSERT(fabs((X.v[2])-( 0.032258064516129)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a12 failed!"); + TASSERT(fabs((X.v[3])-( -0.064516129032258)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a22 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat22dCreateLU(){ + SST_Mat22d X; /* 2 x 2 matrix */ + SST_Mat22d LU; /* 2 x 2 matrix */ + X.v[0] = 2.000000000000000; + X.v[1] = -3.000000000000000; + X.v[2] = -1.000000000000000; + X.v[3] = 1.000000000000000; + SST_Math_Mat22dCreateLU(&X,&LU); +/* +[[ 2 -1] + [-3 1]] +*/ +/* +[[ 2. 0. ] + [-3. -0.5]] +*/ +/* +[[ 1. -0.5] + [ 0. 1. ]] +*/ + TASSERT(fabs((LU.v[0])-( 2.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"L:Entry A_a11 failed!"); + TASSERT(fabs((LU.v[2])-( -0.500000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"U:Entry B_a12 failed!"); + TASSERT(fabs((LU.v[1])-( -3.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"L:Entry A_a21 failed!"); + TASSERT(fabs((LU.v[3])-( -0.500000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"L:Entry A_a22 failed!"); + return ZTEST_SUCCESS; +} +static const char* testSST_Math_Mat22dCreateLULocal(){ + SST_Mat22d X; /* 2 x 2 matrix */ + X.v[0] = 2.000000000000000; + X.v[1] = -3.000000000000000; + X.v[2] = -1.000000000000000; + X.v[3] = 1.000000000000000; + SST_Math_Mat22dCreateLULocal(&X); + TASSERT(fabs((X.v[0])-( 2.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"L:Entry A_a11 failed!"); + TASSERT(fabs((X.v[2])-( -0.500000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"U:Entry B_a12 failed!"); + TASSERT(fabs((X.v[1])-( -3.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"L:Entry A_a21 failed!"); + TASSERT(fabs((X.v[3])-( -0.500000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"L:Entry A_a22 failed!"); + return ZTEST_SUCCESS; +} +static const char* testSST_Math_Mat22dApplyLUMat(){ + SST_Mat22d X; /* 2 x 2 matrix */ + SST_Mat22d LU; /* 2 x 2 matrix */ + SST_Mat22d I; /* 2 x 2 matrix */ + X.v[0] = 2.000000000000000; + X.v[1] = -3.000000000000000; + X.v[2] = -1.000000000000000; + X.v[3] = 1.000000000000000; + SST_Math_Mat22dCreateLU(&X,&LU); +/* +[[ 2 -1] + [-3 1]] +*/ +/* +[[ 2. 0. ] + [-3. -0.5]] +*/ +/* +[[ 1. -0.5] + [ 0. 1. ]] +*/ + TASSERT(fabs((LU.v[0])-( 2.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"L:Entry A_a11 failed!"); + TASSERT(fabs((LU.v[2])-( -0.500000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"U:Entry B_a12 failed!"); + TASSERT(fabs((LU.v[1])-( -3.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"L:Entry A_a21 failed!"); + TASSERT(fabs((LU.v[3])-( -0.500000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"L:Entry A_a22 failed!"); + SST_Math_Mat22dApplyLUMat(&LU,&X,&I); + TASSERT(fabs((I.v[0])-( 1.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"I:Entry I_a11 failed!"); + TASSERT(fabs((I.v[1])-( 0.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"I:Entry I_a21 failed!"); + TASSERT(fabs((I.v[2])-( 0.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"I:Entry I_a12 failed!"); + TASSERT(fabs((I.v[3])-( 1.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"I:Entry I_a22 failed!"); + return ZTEST_SUCCESS; +} +static const char* testSST_Math_Mat22dApplyLUMatLocal(){ + SST_Mat22d X; /* 2 x 2 matrix */ + SST_Mat22d Xinv; /* 2 x 2 matrix */ + X.v[0] = 2.000000000000000; + X.v[1] = -3.000000000000000; + X.v[2] = -1.000000000000000; + X.v[3] = 1.000000000000000; + Xinv.v[0] = 2.000000000000000; + Xinv.v[1] = -3.000000000000000; + Xinv.v[2] = -1.000000000000000; + Xinv.v[3] = 1.000000000000000; + SST_Math_Mat22dCreateLULocal(&X); + TASSERT(fabs((X.v[0])-( 2.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"L:Entry A_a11 failed!"); + TASSERT(fabs((X.v[2])-( -0.500000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"U:Entry B_a12 failed!"); + TASSERT(fabs((X.v[1])-( -3.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"L:Entry A_a21 failed!"); + TASSERT(fabs((X.v[3])-( -0.500000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"L:Entry A_a22 failed!"); + SST_Math_Mat22dApplyLUMatLocal(&X,&Xinv); + TASSERT(fabs((Xinv.v[0])-( 1.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Xinv:Entry Xinv_a11 failed!"); + TASSERT(fabs((Xinv.v[1])-( 0.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Xinv:Entry Xinv_a21 failed!"); + TASSERT(fabs((Xinv.v[2])-( 0.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Xinv:Entry Xinv_a12 failed!"); + TASSERT(fabs((Xinv.v[3])-( 1.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Xinv:Entry Xinv_a22 failed!"); + return ZTEST_SUCCESS; +} +static const char* testSST_Math_Mat22dApplyLUVec(){ + SST_Mat22d X; /* 2 x 2 matrix */ + SST_Mat22d LU; /* 2 x 2 matrix */ + SST_Vec2d b; /* 2 x 2 vector */ + SST_Vec2d x; /* 2 x 2 vector */ + X.v[0] = 2.000000000000000; + X.v[1] = -3.000000000000000; + X.v[2] = -1.000000000000000; + X.v[3] = 1.000000000000000; + b.v[0] = 2.000000000000000; + b.v[1] = -1.000000000000000; + SST_Math_Mat22dCreateLU(&X,&LU); + SST_Math_Mat22dApplyLUVec(&LU,&b,&x); + TASSERT(fabs((x.v[0])-( -1.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"x:Entry x_a1 failed!"); + TASSERT(fabs((x.v[1])-( -3.999999999999999)) <=100*DBL_EPSILON /* yes this is bad */,"x:Entry x_a2 failed!"); + return ZTEST_SUCCESS; +} +static const char* testSST_Math_Mat22dApplyLUVecLocal(){ + SST_Mat22d X; /* 2 x 2 matrix */ + SST_Mat22d LU; /* 2 x 2 matrix */ + SST_Vec2d b; /* 2 x 2 vector */ + X.v[0] = 2.000000000000000; + X.v[1] = -3.000000000000000; + X.v[2] = -1.000000000000000; + X.v[3] = 1.000000000000000; + b.v[0] = 2.000000000000000; + b.v[1] = -1.000000000000000; + SST_Math_Mat22dCreateLU(&X,&LU); + SST_Math_Mat22dApplyLUVecLocal(&LU,&b); + TASSERT(fabs((b.v[0])-( -1.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"x:Entry x_a1 failed!"); + TASSERT(fabs((b.v[1])-( -3.999999999999999)) <=100*DBL_EPSILON /* yes this is bad */,"x:Entry x_a2 failed!"); + return ZTEST_SUCCESS; +} diff --git a/ZTestSuite/Test-SST_Mat22f.cpp b/ZTestSuite/Test-SST_Mat22f.cpp new file mode 100644 index 0000000..b54a1e5 --- /dev/null +++ b/ZTestSuite/Test-SST_Mat22f.cpp @@ -0,0 +1,679 @@ +/* + AUTOMATICALLY GENERATED FILE - DO NOT EDIT! + Please change MatrixNxN.py and re-run it +*/ +/* Generated with ./MatrixNxN.py n = 2, TYPE = float */ + +#include "ZUnitTest.hpp" +#include <float.h> +#include <math.h> +#include <stdlib.h> +#include <stdio.h> +#include <SST/SST_Mat22.h> +#include <SST/SST_Vec2.h> + + + + +static const char* testSST_Math_Mat22fAdd(); +static const char* testSST_Math_Mat22fAddLocal(); +static const char* testSST_Math_Mat22fSubtract(); +static const char* testSST_Math_Mat22fSubtractLocal(); +static const char* testSST_Math_Mat22fMultiplyElementwise(); +static const char* testSST_Math_Mat22fMultiplyElementwiseLocal(); +static const char* testSST_Math_Mat22fMultiplyScalar(); +static const char* testSST_Math_Mat22fMultiplyScalarLocal(); +static const char* testSST_Math_Mat22fMultiplyMatrix(); +static const char* testSST_Math_Mat22fMultiplyMatrixLocal(); +static const char* testSST_Math_Mat22fMultiplyVector(); +static const char* testSST_Math_Mat22fMultiplyVectorLocal(); +static const char* testSST_Math_Mat22fTranspose(); +static const char* testSST_Math_Mat22fTransposeLocal(); +static const char* testSST_Math_Mat22fDeterminant(); +static const char* testSST_Math_Mat22fCheckOrthonormal(); +static const char* testSST_Math_Mat22fInvert(); +static const char* testSST_Math_Mat22fInvertLocal(); +static const char* testSST_Math_Mat22fCreateLU(); +static const char* testSST_Math_Mat22fCreateLULocal(); +static const char* testSST_Math_Mat22fApplyLUMat(); +static const char* testSST_Math_Mat22fApplyLUMatLocal(); +static const char* testSST_Math_Mat22fApplyLUVec(); +static const char* testSST_Math_Mat22fApplyLUVecLocal(); +// List of unit tests +ZUnitTest SST_Math_Mat22fUnitTests[] = +{ +{ "testSST_Math_Mat22fAdd " , testSST_Math_Mat22fAdd }, +{ "testSST_Math_Mat22fAddLocal " , testSST_Math_Mat22fAddLocal }, +{ "testSST_Math_Mat22fSubtract " , testSST_Math_Mat22fSubtract }, +{ "testSST_Math_Mat22fSubtractLocal " , testSST_Math_Mat22fSubtractLocal }, +{ "testSST_Math_Mat22fMultiplyElementwise " , testSST_Math_Mat22fMultiplyElementwise }, +{ "testSST_Math_Mat22fMultiplyElementwiseLocal " , testSST_Math_Mat22fMultiplyElementwiseLocal }, +{ "testSST_Math_Mat22fMultiplyScalar " , testSST_Math_Mat22fMultiplyScalar }, +{ "testSST_Math_Mat22fMultiplyScalarLocal " , testSST_Math_Mat22fMultiplyScalarLocal }, +{ "testSST_Math_Mat22fMultiplyMatrix " , testSST_Math_Mat22fMultiplyMatrix }, +{ "testSST_Math_Mat22fMultiplyMatrixLocal " , testSST_Math_Mat22fMultiplyMatrixLocal }, +{ "testSST_Math_Mat22fMultiplyVector " , testSST_Math_Mat22fMultiplyVector }, +{ "testSST_Math_Mat22fMultiplyVectorLocal " , testSST_Math_Mat22fMultiplyVectorLocal }, +{ "testSST_Math_Mat22fDeterminant " , testSST_Math_Mat22fDeterminant }, +{ "testSST_Math_Mat22fCheckOrthonormal " , testSST_Math_Mat22fCheckOrthonormal }, +{ "testSST_Math_Mat22fInvert " , testSST_Math_Mat22fInvert }, +{ "testSST_Math_Mat22fInvertLocal " , testSST_Math_Mat22fInvertLocal }, +{ "testSST_Math_Mat22fCreateLU " , testSST_Math_Mat22fCreateLU }, +{ "testSST_Math_Mat22fCreateLULocal " , testSST_Math_Mat22fCreateLULocal }, +{ "testSST_Math_Mat22fApplyLUMat " , testSST_Math_Mat22fApplyLUMat }, +{ "testSST_Math_Mat22fApplyLUMatLocal " , testSST_Math_Mat22fApplyLUMatLocal }, +{ "testSST_Math_Mat22fApplyLUVec " , testSST_Math_Mat22fApplyLUVec }, +{ "testSST_Math_Mat22fApplyLUVecLocal " , testSST_Math_Mat22fApplyLUVecLocal }, +{ "testSST_Math_Mat22fTranspose " , testSST_Math_Mat22fTranspose }, +{ "testSST_Math_Mat22fTransposeLocal " , testSST_Math_Mat22fTransposeLocal } +}; +DECLARE_ZTESTBLOCK(SST_Math_Mat22f) + +/******************************************************************************/ + +static const char* testSST_Math_Mat22fAdd(){ + SST_Mat22f X; /* 2 x 2 matrix */ + SST_Mat22f Y; /* 2 x 2 matrix */ + SST_Mat22f A; /* 2 x 2 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = 1.000000f; + X.v[1] = 19.000000f; + X.v[2] = 3.000000f; + X.v[3] = -13.000000f; + Y.v[0] = -13.000000f; + Y.v[1] = -4.000000f; + Y.v[2] = -18.000000f; + Y.v[3] = 19.000000f; +/* +[[ 1. 3.] + [ 19. -13.]] +[[-13. -18.] + [ -4. 19.]] +[[-12. -15.] + [ 15. 6.]] +*/ + SST_Math_Mat22fAdd(&X,&Y,&A); + TASSERT(fabsf((A.v[0])-(-12.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a11 failed!"); + TASSERT(fabsf((A.v[2])-(-15.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a12 failed!"); + TASSERT(fabsf((A.v[1])-(15.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a21 failed!"); + TASSERT(fabsf((A.v[3])-(6.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a22 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat22fAddLocal(){ + SST_Mat22f X; /* 2 x 2 matrix */ + SST_Mat22f Y; /* 2 x 2 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = -16.000000f; + X.v[1] = 15.000000f; + X.v[2] = 16.000000f; + X.v[3] = 9.000000f; + Y.v[0] = 12.000000f; + Y.v[1] = -11.000000f; + Y.v[2] = 6.000000f; + Y.v[3] = 6.000000f; +/* +[[-16. 16.] + [ 15. 9.]] +[[ 12. 6.] + [-11. 6.]] +[[ -4. 22.] + [ 4. 15.]] +*/ + SST_Math_Mat22fAddLocal(&X,&Y); /* for accuracy */ + TASSERT(fabsf((X.v[0])-(-4.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a11 failed!"); + TASSERT(fabsf((X.v[2])-(22.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a12 failed!"); + TASSERT(fabsf((X.v[1])-(4.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a21 failed!"); + TASSERT(fabsf((X.v[3])-(15.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a22 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat22fSubtract(){ + SST_Mat22f X; /* 2 x 2 matrix */ + SST_Mat22f Y; /* 2 x 2 matrix */ + SST_Mat22f A; /* 2 x 2 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = -17.000000f; + X.v[1] = 0.000000f; + X.v[2] = -20.000000f; + X.v[3] = -13.000000f; + Y.v[0] = -15.000000f; + Y.v[1] = 9.000000f; + Y.v[2] = -19.000000f; + Y.v[3] = -6.000000f; +/* +[[-17. -20.] + [ 0. -13.]] +[[-15. -19.] + [ 9. -6.]] +[[-2. -1.] + [-9. -7.]] +*/ + SST_Math_Mat22fSubtract(&X,&Y,&A); + TASSERT(fabsf((A.v[0])-(-2.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a11 failed!"); + TASSERT(fabsf((A.v[2])-(-1.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a12 failed!"); + TASSERT(fabsf((A.v[1])-(-9.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a21 failed!"); + TASSERT(fabsf((A.v[3])-(-7.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a22 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat22fSubtractLocal(){ + SST_Mat22f X; /* 2 x 2 matrix */ + SST_Mat22f Y; /* 2 x 2 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = -3.000000f; + X.v[1] = -20.000000f; + X.v[2] = -3.000000f; + X.v[3] = 2.000000f; + Y.v[0] = 17.000000f; + Y.v[1] = -16.000000f; + Y.v[2] = -14.000000f; + Y.v[3] = 8.000000f; +/* +[[ -3. -3.] + [-20. 2.]] +[[ 17. -14.] + [-16. 8.]] +[[-20. 11.] + [ -4. -6.]] +*/ + SST_Math_Mat22fSubtractLocal(&X,&Y); /* for accuracy */ + TASSERT(fabsf((X.v[0])-(-20.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a11 failed!"); + TASSERT(fabsf((X.v[2])-(11.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a12 failed!"); + TASSERT(fabsf((X.v[1])-(-4.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a21 failed!"); + TASSERT(fabsf((X.v[3])-(-6.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a22 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat22fMultiplyElementwise(){ + SST_Mat22f X; /* 2 x 2 matrix */ + SST_Mat22f Y; /* 2 x 2 matrix */ + SST_Mat22f A; /* 2 x 2 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = -8.000000f; + X.v[1] = -16.000000f; + X.v[2] = -17.000000f; + X.v[3] = 8.000000f; + Y.v[0] = -7.000000f; + Y.v[1] = -8.000000f; + Y.v[2] = -5.000000f; + Y.v[3] = -16.000000f; +/* +[[ -8. -17.] + [-16. 8.]] +[[ -7. -5.] + [ -8. -16.]] +[[ 56. 85.] + [ 128. -128.]] +*/ + SST_Math_Mat22fMultiplyElementwise(&X, &Y, &A); + TASSERT(fabsf((A.v[0])-(56.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a11 failed!"); + TASSERT(fabsf((A.v[2])-(85.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a12 failed!"); + TASSERT(fabsf((A.v[1])-(128.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a21 failed!"); + TASSERT(fabsf((A.v[3])-(-128.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a22 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat22fMultiplyElementwiseLocal(){ + SST_Mat22f X; /* 2 x 2 matrix */ + SST_Mat22f Y; /* 2 x 2 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = -6.000000f; + X.v[1] = 16.000000f; + X.v[2] = -1.000000f; + X.v[3] = 7.000000f; + Y.v[0] = 8.000000f; + Y.v[1] = -1.000000f; + Y.v[2] = 5.000000f; + Y.v[3] = -11.000000f; +/* +[[ -6. -1.] + [ 16. 7.]] +[[ 8. 5.] + [ -1. -11.]] +[[-48. -5.] + [-16. -77.]] +*/ + SST_Math_Mat22fMultiplyElementwiseLocal(&X,&Y); + TASSERT(fabsf((X.v[0])-(-48.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a11 failed!"); + TASSERT(fabsf((X.v[2])-(-5.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a12 failed!"); + TASSERT(fabsf((X.v[1])-(-16.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a21 failed!"); + TASSERT(fabsf((X.v[3])-(-77.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a22 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat22fMultiplyScalar(){ + SST_Mat22f X; /* 2 x 2 matrix */ + SST_Mat22f A; /* 2 x 2 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = 11.000000f; + X.v[1] = -16.000000f; + X.v[2] = 12.000000f; + X.v[3] = -8.000000f; +/* +[[ 11. 12.] + [-16. -8.]] +[[ 22. 24.] + [-32. -16.]] +*/ + SST_Math_Mat22fMultiplyScalar(&X,2.000000f,&A); + TASSERT(fabsf((A.v[0])-(22.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a11 failed!"); + TASSERT(fabsf((A.v[2])-(24.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a12 failed!"); + TASSERT(fabsf((A.v[1])-(-32.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a21 failed!"); + TASSERT(fabsf((A.v[3])-(-16.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a22 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat22fMultiplyScalarLocal(){ + SST_Mat22f X; /* 2 x 2 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = 19.000000f; + X.v[1] = -6.000000f; + X.v[2] = 18.000000f; + X.v[3] = -3.000000f; +/* +[[ 19. 18.] + [ -6. -3.]] +[[ 38. 36.] + [-12. -6.]] +*/ + SST_Math_Mat22fMultiplyScalarLocal(&X,2.000000f); + TASSERT(fabsf((X.v[0])-(38.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a11 failed!"); + TASSERT(fabsf((X.v[2])-(36.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a12 failed!"); + TASSERT(fabsf((X.v[1])-(-12.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a21 failed!"); + TASSERT(fabsf((X.v[3])-(-6.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a22 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat22fMultiplyMatrix(){ + SST_Mat22f X; /* 2 x 2 matrix */ + SST_Mat22f Y; /* 2 x 2 matrix */ + SST_Mat22f A; /* 2 x 2 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = -6.000000f; + X.v[1] = -17.000000f; + X.v[2] = 1.000000f; + X.v[3] = 1.000000f; + Y.v[0] = -7.000000f; + Y.v[1] = 18.000000f; + Y.v[2] = 19.000000f; + Y.v[3] = 13.000000f; +/* +X +[[ -6. 1.] + [-17. 1.]] +Y +[[ -7. 19.] + [ 18. 13.]] +[[ 60. -101.] + [ 137. -310.]] +*/ + SST_Math_Mat22fMultiplyMatrix(&X,&Y,&A); + TASSERT(fabsf((A.v[0])-(60.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a11 failed!"); + TASSERT(fabsf((A.v[2])-(-101.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a12 failed!"); + TASSERT(fabsf((A.v[1])-(137.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a21 failed!"); + TASSERT(fabsf((A.v[3])-(-310.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a22 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat22fMultiplyMatrixLocal(){ + SST_Mat22f X; /* 2 x 2 matrix */ + SST_Mat22f Y; /* 2 x 2 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = 15.000000f; + X.v[1] = -15.000000f; + X.v[2] = -1.000000f; + X.v[3] = -2.000000f; + Y.v[0] = -15.000000f; + Y.v[1] = -16.000000f; + Y.v[2] = -7.000000f; + Y.v[3] = 7.000000f; +/* +X +[[ 15. -1.] + [-15. -2.]] +Y +[[-15. -7.] + [-16. 7.]] +X +[[-209. -112.] + [ 257. 91.]] +*/ + SST_Math_Mat22fMultiplyMatrixLocal(&X,&Y); + TASSERT(fabsf((X.v[0])-(-209.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a11 failed!"); + TASSERT(fabsf((X.v[2])-(-112.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a12 failed!"); + TASSERT(fabsf((X.v[1])-(257.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a21 failed!"); + TASSERT(fabsf((X.v[3])-(91.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a22 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat22fMultiplyVector(){ + SST_Mat22f X; /* 2 x 2 matrix */ + SST_Vec2f v; /* 2 vector */ + SST_Vec2f w; /* 2 vector */ +/* Resetting test vectors / mats */ + v.v[0] = -14.000000f; + v.v[1] = -14.000000f; + X.v[0] = 10.000000f; + X.v[1] = -8.000000f; + X.v[2] = 13.000000f; + X.v[3] = -9.000000f; +/* +X +[[ 10. 13.] + [ -8. -9.]] +v +[-14. -14.] +w +[-322. 238.] +*/ + SST_Math_Mat22fMultiplyVector(&X,&v,&w); + TASSERT(fabsf((w.v[0])-(-322.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry .v[0] failed!"); + TASSERT(fabsf((w.v[1])-(238.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry .v[1] failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat22fMultiplyVectorLocal(){ + SST_Mat22f X; /* 2 x 2 matrix */ + SST_Vec2f v; /* 2 vector */ +/* Resetting test vectors / mats */ + v.v[0] = 10.000000f; + v.v[1] = 18.000000f; + X.v[0] = -14.000000f; + X.v[1] = 10.000000f; + X.v[2] = 17.000000f; + X.v[3] = -15.000000f; +/* +X +[[-14. 17.] + [ 10. -15.]] +v +[ 10. 18.] +v +[ 166. -170.] +*/ + SST_Math_Mat22fMultiplyVectorLocal(&X,&v); + TASSERT(fabsf((v.v[0])-(166.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry .v[0] failed!"); + TASSERT(fabsf((v.v[1])-(-170.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry .v[1] failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat22fTranspose(){ + SST_Mat22f X; /* 2 x 2 matrix */ + SST_Mat22f A; /* 2 x 2 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = -14.000000f; + X.v[1] = -9.000000f; + X.v[2] = 11.000000f; + X.v[3] = -5.000000f; + SST_Math_Mat22fTranspose(&X,&A); + TASSERT(fabsf((A.v[0])-(-14.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a11 failed!"); + TASSERT(fabsf((A.v[2])-(-9.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a12 failed!"); + TASSERT(fabsf((A.v[1])-(11.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a21 failed!"); + TASSERT(fabsf((A.v[3])-(-5.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a22 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat22fTransposeLocal(){ + SST_Mat22f X; /* 2 x 2 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = -17.000000f; + X.v[1] = 14.000000f; + X.v[2] = 17.000000f; + X.v[3] = -1.000000f; + SST_Math_Mat22fTransposeLocal(&X); + TASSERT(fabsf((X.v[0])-(-17.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a11 failed!"); + TASSERT(fabsf((X.v[2])-(14.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a12 failed!"); + TASSERT(fabsf((X.v[1])-(17.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a21 failed!"); + TASSERT(fabsf((X.v[3])-(-1.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a22 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat22fCheckOrthonormal(){ + SST_Mat22f X; /* 2 x 2 matrix */ + SST_Mat22f Y; /* 2 x 2 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = -19.000000f; + X.v[1] = 2.000000f; + X.v[2] = -10.000000f; + X.v[3] = -3.000000f; + Y.v[0] = 12.000000f; + Y.v[1] = -18.000000f; + Y.v[2] = 1.000000f; + Y.v[3] = -3.000000f; +/* +[[-0.99450547 0.10468479] + [ 0.10468479 0.99450547]] +[[ 1. 0.] + [ 0. 1.]] +*/ +/* Set X to orthogonal matrix Q */ + X.v[0] = (float)-0.994505f; + X.v[1] = (float)0.104685f; + X.v[2] = (float)0.104685f; + X.v[3] = (float)0.994505f; +/* Check Positive Test */ + TASSERT(SST_Math_Mat22fCheckOrthonormal(&X),"CheckOrthonormal failed when it should have passed"); +/* Check Negative Test */ + TASSERT(!SST_Math_Mat22fCheckOrthonormal(&Y),"CheckOrthonormal succeeded when it should have failed"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat22fDeterminant(){ + SST_Mat22f X; /* 2 x 2 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = -16.000000f; + X.v[1] = -6.000000f; + X.v[2] = 11.000000f; + X.v[3] = -15.000000f; +/* det(X) = +306.0 + */ + float result = SST_Math_Mat22fDeterminant(&X); + TASSERT(fabsf( (result)/(306.000000f) - 1.000000f ) <= 100*FLT_EPSILON,"Determinant failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat22fInvert(){ + SST_Mat22f X; /* 2 x 2 matrix */ + SST_Mat22f B; /* 2 x 2 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = 11.000000f; + X.v[1] = -16.000000f; + X.v[2] = 7.000000f; + X.v[3] = -1.000000f; +/* +[[-0.00990099 -0.06930693] + [ 0.15841584 0.10891089]] +*/ + SST_Math_Mat22fInvert(&X,&B); + TASSERT(fabsf((B.v[0])-(-0.009901f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a11 failed!"); + TASSERT(fabsf((B.v[1])-(0.158416f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a21 failed!"); + TASSERT(fabsf((B.v[2])-(-0.069307f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a12 failed!"); + TASSERT(fabsf((B.v[3])-(0.108911f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a22 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat22fInvertLocal(){ + SST_Mat22f X; /* 2 x 2 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = -2.000000f; + X.v[1] = 1.000000f; + X.v[2] = 14.000000f; + X.v[3] = -4.000000f; +/* +() +[[ 0.66666669 2.33333325] + [ 0.16666667 0.33333334]] +*/ + SST_Math_Mat22fInvertLocal(&X); + TASSERT(fabsf((X.v[0])-(0.666667f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a11 failed!"); + TASSERT(fabsf((X.v[1])-(0.166667f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a21 failed!"); + TASSERT(fabsf((X.v[2])-(2.333333f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a12 failed!"); + TASSERT(fabsf((X.v[3])-(0.333333f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a22 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat22fCreateLU(){ + SST_Mat22f X; /* 2 x 2 matrix */ + SST_Mat22f LU; /* 2 x 2 matrix */ + X.v[0] = 2.000000f; + X.v[1] = -3.000000f; + X.v[2] = -1.000000f; + X.v[3] = 1.000000f; + SST_Math_Mat22fCreateLU(&X,&LU); +/* +[[ 2 -1] + [-3 1]] +*/ +/* +[[ 2. 0. ] + [-3. -0.5]] +*/ +/* +[[ 1. -0.5] + [ 0. 1. ]] +*/ + TASSERT(fabsf((LU.v[0])-(2.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"L:Entry A_a11 failed!"); + TASSERT(fabsf((LU.v[2])-(-0.500000f)) <=100*FLT_EPSILON /* yes this is bad */,"U:Entry B_a12 failed!"); + TASSERT(fabsf((LU.v[1])-(-3.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"L:Entry A_a21 failed!"); + TASSERT(fabsf((LU.v[3])-(-0.500000f)) <=100*FLT_EPSILON /* yes this is bad */,"L:Entry A_a22 failed!"); + return ZTEST_SUCCESS; +} +static const char* testSST_Math_Mat22fCreateLULocal(){ + SST_Mat22f X; /* 2 x 2 matrix */ + X.v[0] = 2.000000f; + X.v[1] = -3.000000f; + X.v[2] = -1.000000f; + X.v[3] = 1.000000f; + SST_Math_Mat22fCreateLULocal(&X); + TASSERT(fabsf((X.v[0])-(2.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"L:Entry A_a11 failed!"); + TASSERT(fabsf((X.v[2])-(-0.500000f)) <=100*FLT_EPSILON /* yes this is bad */,"U:Entry B_a12 failed!"); + TASSERT(fabsf((X.v[1])-(-3.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"L:Entry A_a21 failed!"); + TASSERT(fabsf((X.v[3])-(-0.500000f)) <=100*FLT_EPSILON /* yes this is bad */,"L:Entry A_a22 failed!"); + return ZTEST_SUCCESS; +} +static const char* testSST_Math_Mat22fApplyLUMat(){ + SST_Mat22f X; /* 2 x 2 matrix */ + SST_Mat22f LU; /* 2 x 2 matrix */ + SST_Mat22f I; /* 2 x 2 matrix */ + X.v[0] = 2.000000f; + X.v[1] = -3.000000f; + X.v[2] = -1.000000f; + X.v[3] = 1.000000f; + SST_Math_Mat22fCreateLU(&X,&LU); +/* +[[ 2 -1] + [-3 1]] +*/ +/* +[[ 2. 0. ] + [-3. -0.5]] +*/ +/* +[[ 1. -0.5] + [ 0. 1. ]] +*/ + TASSERT(fabsf((LU.v[0])-(2.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"L:Entry A_a11 failed!"); + TASSERT(fabsf((LU.v[2])-(-0.500000f)) <=100*FLT_EPSILON /* yes this is bad */,"U:Entry B_a12 failed!"); + TASSERT(fabsf((LU.v[1])-(-3.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"L:Entry A_a21 failed!"); + TASSERT(fabsf((LU.v[3])-(-0.500000f)) <=100*FLT_EPSILON /* yes this is bad */,"L:Entry A_a22 failed!"); + SST_Math_Mat22fApplyLUMat(&LU,&X,&I); + TASSERT(fabsf((I.v[0])-(1.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"I:Entry I_a11 failed!"); + TASSERT(fabsf((I.v[1])-(0.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"I:Entry I_a21 failed!"); + TASSERT(fabsf((I.v[2])-(0.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"I:Entry I_a12 failed!"); + TASSERT(fabsf((I.v[3])-(1.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"I:Entry I_a22 failed!"); + return ZTEST_SUCCESS; +} +static const char* testSST_Math_Mat22fApplyLUMatLocal(){ + SST_Mat22f X; /* 2 x 2 matrix */ + SST_Mat22f Xinv; /* 2 x 2 matrix */ + X.v[0] = 2.000000f; + X.v[1] = -3.000000f; + X.v[2] = -1.000000f; + X.v[3] = 1.000000f; + Xinv.v[0] = 2.000000f; + Xinv.v[1] = -3.000000f; + Xinv.v[2] = -1.000000f; + Xinv.v[3] = 1.000000f; + SST_Math_Mat22fCreateLULocal(&X); + TASSERT(fabsf((X.v[0])-(2.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"L:Entry A_a11 failed!"); + TASSERT(fabsf((X.v[2])-(-0.500000f)) <=100*FLT_EPSILON /* yes this is bad */,"U:Entry B_a12 failed!"); + TASSERT(fabsf((X.v[1])-(-3.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"L:Entry A_a21 failed!"); + TASSERT(fabsf((X.v[3])-(-0.500000f)) <=100*FLT_EPSILON /* yes this is bad */,"L:Entry A_a22 failed!"); + SST_Math_Mat22fApplyLUMatLocal(&X,&Xinv); + TASSERT(fabsf((Xinv.v[0])-(1.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Xinv:Entry Xinv_a11 failed!"); + TASSERT(fabsf((Xinv.v[1])-(0.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Xinv:Entry Xinv_a21 failed!"); + TASSERT(fabsf((Xinv.v[2])-(0.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Xinv:Entry Xinv_a12 failed!"); + TASSERT(fabsf((Xinv.v[3])-(1.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Xinv:Entry Xinv_a22 failed!"); + return ZTEST_SUCCESS; +} +static const char* testSST_Math_Mat22fApplyLUVec(){ + SST_Mat22f X; /* 2 x 2 matrix */ + SST_Mat22f LU; /* 2 x 2 matrix */ + SST_Vec2f b; /* 2 x 2 vector */ + SST_Vec2f x; /* 2 x 2 vector */ + X.v[0] = 2.000000f; + X.v[1] = -3.000000f; + X.v[2] = -1.000000f; + X.v[3] = 1.000000f; + b.v[0] = 2.000000f; + b.v[1] = -1.000000f; + SST_Math_Mat22fCreateLU(&X,&LU); + SST_Math_Mat22fApplyLUVec(&LU,&b,&x); + TASSERT(fabsf((x.v[0])-(-1.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"x:Entry x_a1 failed!"); + TASSERT(fabsf((x.v[1])-(-4.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"x:Entry x_a2 failed!"); + return ZTEST_SUCCESS; +} +static const char* testSST_Math_Mat22fApplyLUVecLocal(){ + SST_Mat22f X; /* 2 x 2 matrix */ + SST_Mat22f LU; /* 2 x 2 matrix */ + SST_Vec2f b; /* 2 x 2 vector */ + X.v[0] = 2.000000f; + X.v[1] = -3.000000f; + X.v[2] = -1.000000f; + X.v[3] = 1.000000f; + b.v[0] = 2.000000f; + b.v[1] = -1.000000f; + SST_Math_Mat22fCreateLU(&X,&LU); + SST_Math_Mat22fApplyLUVecLocal(&LU,&b); + TASSERT(fabsf((b.v[0])-(-1.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"x:Entry x_a1 failed!"); + TASSERT(fabsf((b.v[1])-(-4.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"x:Entry x_a2 failed!"); + return ZTEST_SUCCESS; +} diff --git a/ZTestSuite/Test-SST_Mat22i.cpp b/ZTestSuite/Test-SST_Mat22i.cpp new file mode 100644 index 0000000..4673ea9 --- /dev/null +++ b/ZTestSuite/Test-SST_Mat22i.cpp @@ -0,0 +1,490 @@ +/* + AUTOMATICALLY GENERATED FILE - DO NOT EDIT! + Please change MatrixNxN.py and re-run it +*/ +/* Generated with ./MatrixNxN.py n = 2, TYPE = int */ + +#include "ZUnitTest.hpp" +#include <float.h> +#include <math.h> +#include <stdlib.h> +#include <stdio.h> +#include <SST/SST_Mat22.h> +#include <SST/SST_Vec2.h> + + + + +static const char* testSST_Math_Mat22iAdd(); +static const char* testSST_Math_Mat22iAddLocal(); +static const char* testSST_Math_Mat22iSubtract(); +static const char* testSST_Math_Mat22iSubtractLocal(); +static const char* testSST_Math_Mat22iMultiplyElementwise(); +static const char* testSST_Math_Mat22iMultiplyElementwiseLocal(); +static const char* testSST_Math_Mat22iMultiplyScalar(); +static const char* testSST_Math_Mat22iMultiplyScalarLocal(); +static const char* testSST_Math_Mat22iMultiplyMatrix(); +static const char* testSST_Math_Mat22iMultiplyMatrixLocal(); +static const char* testSST_Math_Mat22iMultiplyVector(); +static const char* testSST_Math_Mat22iMultiplyVectorLocal(); +static const char* testSST_Math_Mat22iTranspose(); +static const char* testSST_Math_Mat22iTransposeLocal(); +static const char* testSST_Math_Mat22iDeterminant(); +static const char* testSST_Math_Mat22iCheckOrthonormal(); +// List of unit tests +ZUnitTest SST_Math_Mat22iUnitTests[] = +{ +{ "testSST_Math_Mat22iAdd " , testSST_Math_Mat22iAdd }, +{ "testSST_Math_Mat22iAddLocal " , testSST_Math_Mat22iAddLocal }, +{ "testSST_Math_Mat22iSubtract " , testSST_Math_Mat22iSubtract }, +{ "testSST_Math_Mat22iSubtractLocal " , testSST_Math_Mat22iSubtractLocal }, +{ "testSST_Math_Mat22iMultiplyElementwise " , testSST_Math_Mat22iMultiplyElementwise }, +{ "testSST_Math_Mat22iMultiplyElementwiseLocal " , testSST_Math_Mat22iMultiplyElementwiseLocal }, +{ "testSST_Math_Mat22iMultiplyScalar " , testSST_Math_Mat22iMultiplyScalar }, +{ "testSST_Math_Mat22iMultiplyScalarLocal " , testSST_Math_Mat22iMultiplyScalarLocal }, +{ "testSST_Math_Mat22iMultiplyMatrix " , testSST_Math_Mat22iMultiplyMatrix }, +{ "testSST_Math_Mat22iMultiplyMatrixLocal " , testSST_Math_Mat22iMultiplyMatrixLocal }, +{ "testSST_Math_Mat22iMultiplyVector " , testSST_Math_Mat22iMultiplyVector }, +{ "testSST_Math_Mat22iMultiplyVectorLocal " , testSST_Math_Mat22iMultiplyVectorLocal }, +{ "testSST_Math_Mat22iDeterminant " , testSST_Math_Mat22iDeterminant }, +{ "testSST_Math_Mat22iCheckOrthonormal " , testSST_Math_Mat22iCheckOrthonormal }, +{ "testSST_Math_Mat22iTranspose " , testSST_Math_Mat22iTranspose }, +{ "testSST_Math_Mat22iTransposeLocal " , testSST_Math_Mat22iTransposeLocal } +}; +DECLARE_ZTESTBLOCK(SST_Math_Mat22i) + +/******************************************************************************/ + +static const char* testSST_Math_Mat22iAdd(){ + SST_Mat22i X; /* 2 x 2 matrix */ + SST_Mat22i Y; /* 2 x 2 matrix */ + SST_Mat22i A; /* 2 x 2 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = 15; + X.v[1] = -18; + X.v[2] = -14; + X.v[3] = -20; + Y.v[0] = -7; + Y.v[1] = 7; + Y.v[2] = 4; + Y.v[3] = 14; +/* +[[ 15 -14] + [-18 -20]] +[[-7 4] + [ 7 14]] +[[ 8 -10] + [-11 -6]] +*/ + SST_Math_Mat22iAdd(&X,&Y,&A); + TASSERT((A.v[0])==(8),"Entry _a11 failed!"); + TASSERT((A.v[2])==(-10),"Entry _a12 failed!"); + TASSERT((A.v[1])==(-11),"Entry _a21 failed!"); + TASSERT((A.v[3])==(-6),"Entry _a22 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat22iAddLocal(){ + SST_Mat22i X; /* 2 x 2 matrix */ + SST_Mat22i Y; /* 2 x 2 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = 14; + X.v[1] = -8; + X.v[2] = -19; + X.v[3] = 11; + Y.v[0] = -20; + Y.v[1] = -10; + Y.v[2] = 13; + Y.v[3] = 17; +/* +[[ 14 -19] + [ -8 11]] +[[-20 13] + [-10 17]] +[[ -6 -6] + [-18 28]] +*/ + SST_Math_Mat22iAddLocal(&X,&Y); /* for accuracy */ + TASSERT((X.v[0])==(-6),"Entry _a11 failed!"); + TASSERT((X.v[2])==(-6),"Entry _a12 failed!"); + TASSERT((X.v[1])==(-18),"Entry _a21 failed!"); + TASSERT((X.v[3])==(28),"Entry _a22 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat22iSubtract(){ + SST_Mat22i X; /* 2 x 2 matrix */ + SST_Mat22i Y; /* 2 x 2 matrix */ + SST_Mat22i A; /* 2 x 2 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = 14; + X.v[1] = -16; + X.v[2] = -9; + X.v[3] = -14; + Y.v[0] = 13; + Y.v[1] = 11; + Y.v[2] = 9; + Y.v[3] = -7; +/* +[[ 14 -9] + [-16 -14]] +[[13 9] + [11 -7]] +[[ 1 -18] + [-27 -7]] +*/ + SST_Math_Mat22iSubtract(&X,&Y,&A); + TASSERT((A.v[0])==(1),"Entry _a11 failed!"); + TASSERT((A.v[2])==(-18),"Entry _a12 failed!"); + TASSERT((A.v[1])==(-27),"Entry _a21 failed!"); + TASSERT((A.v[3])==(-7),"Entry _a22 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat22iSubtractLocal(){ + SST_Mat22i X; /* 2 x 2 matrix */ + SST_Mat22i Y; /* 2 x 2 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = 19; + X.v[1] = 18; + X.v[2] = -16; + X.v[3] = -13; + Y.v[0] = 12; + Y.v[1] = 6; + Y.v[2] = 2; + Y.v[3] = -6; +/* +[[ 19 -16] + [ 18 -13]] +[[12 2] + [ 6 -6]] +[[ 7 -18] + [ 12 -7]] +*/ + SST_Math_Mat22iSubtractLocal(&X,&Y); /* for accuracy */ + TASSERT((X.v[0])==(7),"Entry _a11 failed!"); + TASSERT((X.v[2])==(-18),"Entry _a12 failed!"); + TASSERT((X.v[1])==(12),"Entry _a21 failed!"); + TASSERT((X.v[3])==(-7),"Entry _a22 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat22iMultiplyElementwise(){ + SST_Mat22i X; /* 2 x 2 matrix */ + SST_Mat22i Y; /* 2 x 2 matrix */ + SST_Mat22i A; /* 2 x 2 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = 13; + X.v[1] = -2; + X.v[2] = -20; + X.v[3] = 18; + Y.v[0] = 2; + Y.v[1] = 14; + Y.v[2] = -5; + Y.v[3] = 16; +/* +[[ 13 -20] + [ -2 18]] +[[ 2 -5] + [14 16]] +[[ 26 100] + [-28 288]] +*/ + SST_Math_Mat22iMultiplyElementwise(&X, &Y, &A); + TASSERT((A.v[0])==(26),"Entry _a11 failed!"); + TASSERT((A.v[2])==(100),"Entry _a12 failed!"); + TASSERT((A.v[1])==(-28),"Entry _a21 failed!"); + TASSERT((A.v[3])==(288),"Entry _a22 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat22iMultiplyElementwiseLocal(){ + SST_Mat22i X; /* 2 x 2 matrix */ + SST_Mat22i Y; /* 2 x 2 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = -11; + X.v[1] = 10; + X.v[2] = 12; + X.v[3] = -3; + Y.v[0] = -19; + Y.v[1] = 2; + Y.v[2] = 7; + Y.v[3] = -4; +/* +[[-11 12] + [ 10 -3]] +[[-19 7] + [ 2 -4]] +[[209 84] + [ 20 12]] +*/ + SST_Math_Mat22iMultiplyElementwiseLocal(&X,&Y); + TASSERT((X.v[0])==(209),"Entry _a11 failed!"); + TASSERT((X.v[2])==(84),"Entry _a12 failed!"); + TASSERT((X.v[1])==(20),"Entry _a21 failed!"); + TASSERT((X.v[3])==(12),"Entry _a22 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat22iMultiplyScalar(){ + SST_Mat22i X; /* 2 x 2 matrix */ + SST_Mat22i A; /* 2 x 2 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = -1; + X.v[1] = -17; + X.v[2] = -14; + X.v[3] = -8; +/* +[[ -1 -14] + [-17 -8]] +[[ -2 -28] + [-34 -16]] +*/ + SST_Math_Mat22iMultiplyScalar(&X,2,&A); + TASSERT((A.v[0])==(-2),"Entry _a11 failed!"); + TASSERT((A.v[2])==(-28),"Entry _a12 failed!"); + TASSERT((A.v[1])==(-34),"Entry _a21 failed!"); + TASSERT((A.v[3])==(-16),"Entry _a22 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat22iMultiplyScalarLocal(){ + SST_Mat22i X; /* 2 x 2 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = 9; + X.v[1] = -1; + X.v[2] = -9; + X.v[3] = 4; +/* +[[ 9 -9] + [-1 4]] +[[ 18 -18] + [ -2 8]] +*/ + SST_Math_Mat22iMultiplyScalarLocal(&X,2); + TASSERT((X.v[0])==(18),"Entry _a11 failed!"); + TASSERT((X.v[2])==(-18),"Entry _a12 failed!"); + TASSERT((X.v[1])==(-2),"Entry _a21 failed!"); + TASSERT((X.v[3])==(8),"Entry _a22 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat22iMultiplyMatrix(){ + SST_Mat22i X; /* 2 x 2 matrix */ + SST_Mat22i Y; /* 2 x 2 matrix */ + SST_Mat22i A; /* 2 x 2 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = -20; + X.v[1] = 0; + X.v[2] = -1; + X.v[3] = -1; + Y.v[0] = -9; + Y.v[1] = -10; + Y.v[2] = 18; + Y.v[3] = -1; +/* +X +[[-20 -1] + [ 0 -1]] +Y +[[ -9 18] + [-10 -1]] +[[ 190 -359] + [ 10 1]] +*/ + SST_Math_Mat22iMultiplyMatrix(&X,&Y,&A); + TASSERT((A.v[0])==(190),"Entry _a11 failed!"); + TASSERT((A.v[2])==(-359),"Entry _a12 failed!"); + TASSERT((A.v[1])==(10),"Entry _a21 failed!"); + TASSERT((A.v[3])==(1),"Entry _a22 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat22iMultiplyMatrixLocal(){ + SST_Mat22i X; /* 2 x 2 matrix */ + SST_Mat22i Y; /* 2 x 2 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = 19; + X.v[1] = 18; + X.v[2] = 5; + X.v[3] = -14; + Y.v[0] = -18; + Y.v[1] = 19; + Y.v[2] = -14; + Y.v[3] = 4; +/* +X +[[ 19 5] + [ 18 -14]] +Y +[[-18 -14] + [ 19 4]] +X +[[-247 -246] + [-590 -308]] +*/ + SST_Math_Mat22iMultiplyMatrixLocal(&X,&Y); + TASSERT((X.v[0])==(-247),"Entry _a11 failed!"); + TASSERT((X.v[2])==(-246),"Entry _a12 failed!"); + TASSERT((X.v[1])==(-590),"Entry _a21 failed!"); + TASSERT((X.v[3])==(-308),"Entry _a22 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat22iMultiplyVector(){ + SST_Mat22i X; /* 2 x 2 matrix */ + SST_Vec2i v; /* 2 vector */ + SST_Vec2i w; /* 2 vector */ +/* Resetting test vectors / mats */ + v.v[0] = -9; + v.v[1] = 16; + X.v[0] = -2; + X.v[1] = -3; + X.v[2] = -17; + X.v[3] = 5; +/* +X +[[ -2 -17] + [ -3 5]] +v +[-9 16] +w +[-254 107] +*/ + SST_Math_Mat22iMultiplyVector(&X,&v,&w); + TASSERT((w.v[0])==(-254),"Entry .v[0] failed!"); + TASSERT((w.v[1])==(107),"Entry .v[1] failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat22iMultiplyVectorLocal(){ + SST_Mat22i X; /* 2 x 2 matrix */ + SST_Vec2i v; /* 2 vector */ +/* Resetting test vectors / mats */ + v.v[0] = -2; + v.v[1] = -4; + X.v[0] = 10; + X.v[1] = 5; + X.v[2] = 13; + X.v[3] = 8; +/* +X +[[10 13] + [ 5 8]] +v +[-2 -4] +v +[-72 -42] +*/ + SST_Math_Mat22iMultiplyVectorLocal(&X,&v); + TASSERT((v.v[0])==(-72),"Entry .v[0] failed!"); + TASSERT((v.v[1])==(-42),"Entry .v[1] failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat22iTranspose(){ + SST_Mat22i X; /* 2 x 2 matrix */ + SST_Mat22i A; /* 2 x 2 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = 5; + X.v[1] = -17; + X.v[2] = 3; + X.v[3] = 1; + SST_Math_Mat22iTranspose(&X,&A); + TASSERT((A.v[0])==(5),"Entry _a11 failed!"); + TASSERT((A.v[2])==(-17),"Entry _a12 failed!"); + TASSERT((A.v[1])==(3),"Entry _a21 failed!"); + TASSERT((A.v[3])==(1),"Entry _a22 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat22iTransposeLocal(){ + SST_Mat22i X; /* 2 x 2 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = -11; + X.v[1] = -17; + X.v[2] = -11; + X.v[3] = 17; + SST_Math_Mat22iTransposeLocal(&X); + TASSERT((X.v[0])==(-11),"Entry _a11 failed!"); + TASSERT((X.v[2])==(-17),"Entry _a12 failed!"); + TASSERT((X.v[1])==(-11),"Entry _a21 failed!"); + TASSERT((X.v[3])==(17),"Entry _a22 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat22iCheckOrthonormal(){ + SST_Mat22i X; /* 2 x 2 matrix */ + SST_Mat22i Y; /* 2 x 2 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = 6; + X.v[1] = -11; + X.v[2] = 15; + X.v[3] = 2; + Y.v[0] = 15; + Y.v[1] = -3; + Y.v[2] = 18; + Y.v[3] = 0; +X.v[0] = (int)1; +X.v[1] = (int)0; +X.v[2] = (int)0; +X.v[3] = (int)1; +Y.v[0] = (int)1; +Y.v[1] = (int)0; +Y.v[2] = (int)0; +Y.v[3] = (int)1; +Y.v[1] = (int)1; /* Will cause Y to be fail */ +/* Check Positive Test */ + TASSERT(SST_Math_Mat22iCheckOrthonormal(&X),"CheckOrthonormal failed when it should have passed"); +/* Check Negative Test */ + TASSERT(!SST_Math_Mat22iCheckOrthonormal(&Y),"CheckOrthonormal succeeded when it should have failed"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat22iDeterminant(){ + SST_Mat22i X; /* 2 x 2 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = 10; + X.v[1] = -7; + X.v[2] = -6; + X.v[3] = 3; +/* det(X) = +-12.0 + */ + int result = SST_Math_Mat22iDeterminant(&X); + TASSERT(abs( (result)/(-12) - 1 ) <= 100*0,"Determinant failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + diff --git a/ZTestSuite/Test-SST_Mat22u.cpp b/ZTestSuite/Test-SST_Mat22u.cpp new file mode 100644 index 0000000..aed7e33 --- /dev/null +++ b/ZTestSuite/Test-SST_Mat22u.cpp @@ -0,0 +1,439 @@ +/* + AUTOMATICALLY GENERATED FILE - DO NOT EDIT! + Please change MatrixNxN.py and re-run it +*/ +/* Generated with ./MatrixNxN.py n = 2, TYPE = unsigned int */ + +#include "ZUnitTest.hpp" +#include <float.h> +#include <math.h> +#include <stdlib.h> +#include <stdio.h> +#include <SST/SST_Mat22.h> +#include <SST/SST_Vec2.h> + + + + +static const char* testSST_Math_Mat22uAdd(); +static const char* testSST_Math_Mat22uAddLocal(); +static const char* testSST_Math_Mat22uSubtract(); +static const char* testSST_Math_Mat22uSubtractLocal(); +static const char* testSST_Math_Mat22uMultiplyElementwise(); +static const char* testSST_Math_Mat22uMultiplyElementwiseLocal(); +static const char* testSST_Math_Mat22uMultiplyScalar(); +static const char* testSST_Math_Mat22uMultiplyScalarLocal(); +static const char* testSST_Math_Mat22uMultiplyMatrix(); +static const char* testSST_Math_Mat22uMultiplyMatrixLocal(); +static const char* testSST_Math_Mat22uMultiplyVector(); +static const char* testSST_Math_Mat22uMultiplyVectorLocal(); +static const char* testSST_Math_Mat22uTranspose(); +static const char* testSST_Math_Mat22uTransposeLocal(); +// List of unit tests +ZUnitTest SST_Math_Mat22uUnitTests[] = +{ +{ "testSST_Math_Mat22uAdd " , testSST_Math_Mat22uAdd }, +{ "testSST_Math_Mat22uAddLocal " , testSST_Math_Mat22uAddLocal }, +{ "testSST_Math_Mat22uSubtract " , testSST_Math_Mat22uSubtract }, +{ "testSST_Math_Mat22uSubtractLocal " , testSST_Math_Mat22uSubtractLocal }, +{ "testSST_Math_Mat22uMultiplyElementwise " , testSST_Math_Mat22uMultiplyElementwise }, +{ "testSST_Math_Mat22uMultiplyElementwiseLocal " , testSST_Math_Mat22uMultiplyElementwiseLocal }, +{ "testSST_Math_Mat22uMultiplyScalar " , testSST_Math_Mat22uMultiplyScalar }, +{ "testSST_Math_Mat22uMultiplyScalarLocal " , testSST_Math_Mat22uMultiplyScalarLocal }, +{ "testSST_Math_Mat22uMultiplyMatrix " , testSST_Math_Mat22uMultiplyMatrix }, +{ "testSST_Math_Mat22uMultiplyMatrixLocal " , testSST_Math_Mat22uMultiplyMatrixLocal }, +{ "testSST_Math_Mat22uMultiplyVector " , testSST_Math_Mat22uMultiplyVector }, +{ "testSST_Math_Mat22uMultiplyVectorLocal " , testSST_Math_Mat22uMultiplyVectorLocal }, +{ "testSST_Math_Mat22uTranspose " , testSST_Math_Mat22uTranspose }, +{ "testSST_Math_Mat22uTransposeLocal " , testSST_Math_Mat22uTransposeLocal } +}; +DECLARE_ZTESTBLOCK(SST_Math_Mat22u) + +/******************************************************************************/ + +static const char* testSST_Math_Mat22uAdd(){ + SST_Mat22u X; /* 2 x 2 matrix */ + SST_Mat22u Y; /* 2 x 2 matrix */ + SST_Mat22u A; /* 2 x 2 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = 36; + X.v[1] = 5; + X.v[2] = 15; + X.v[3] = 7; + Y.v[0] = 36; + Y.v[1] = 7; + Y.v[2] = 31; + Y.v[3] = 33; +/* +[[36 15] + [ 5 7]] +[[36 31] + [ 7 33]] +[[72 46] + [12 40]] +*/ + SST_Math_Mat22uAdd(&X,&Y,&A); + TASSERT((A.v[0])==(72),"Entry _a11 failed!"); + TASSERT((A.v[2])==(46),"Entry _a12 failed!"); + TASSERT((A.v[1])==(12),"Entry _a21 failed!"); + TASSERT((A.v[3])==(40),"Entry _a22 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat22uAddLocal(){ + SST_Mat22u X; /* 2 x 2 matrix */ + SST_Mat22u Y; /* 2 x 2 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = 23; + X.v[1] = 38; + X.v[2] = 10; + X.v[3] = 27; + Y.v[0] = 16; + Y.v[1] = 5; + Y.v[2] = 21; + Y.v[3] = 11; +/* +[[23 10] + [38 27]] +[[16 21] + [ 5 11]] +[[39 31] + [43 38]] +*/ + SST_Math_Mat22uAddLocal(&X,&Y); /* for accuracy */ + TASSERT((X.v[0])==(39),"Entry _a11 failed!"); + TASSERT((X.v[2])==(31),"Entry _a12 failed!"); + TASSERT((X.v[1])==(43),"Entry _a21 failed!"); + TASSERT((X.v[3])==(38),"Entry _a22 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat22uSubtract(){ + SST_Mat22u X; /* 2 x 2 matrix */ + SST_Mat22u Y; /* 2 x 2 matrix */ + SST_Mat22u A; /* 2 x 2 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = 16; + X.v[1] = 26; + X.v[2] = 12; + X.v[3] = 28; + Y.v[0] = 0; + Y.v[1] = 23; + Y.v[2] = 19; + Y.v[3] = 36; +/* +[[16 12] + [26 28]] +[[ 0 19] + [23 36]] +[[ 16 4294967289] + [ 3 4294967288]] +*/ + SST_Math_Mat22uSubtract(&X,&Y,&A); + TASSERT((A.v[0])==(16),"Entry _a11 failed!"); + TASSERT((A.v[2])==(4294967289),"Entry _a12 failed!"); + TASSERT((A.v[1])==(3),"Entry _a21 failed!"); + TASSERT((A.v[3])==(4294967288),"Entry _a22 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat22uSubtractLocal(){ + SST_Mat22u X; /* 2 x 2 matrix */ + SST_Mat22u Y; /* 2 x 2 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = 10; + X.v[1] = 13; + X.v[2] = 29; + X.v[3] = 24; + Y.v[0] = 21; + Y.v[1] = 30; + Y.v[2] = 18; + Y.v[3] = 7; +/* +[[10 29] + [13 24]] +[[21 18] + [30 7]] +[[4294967285 11] + [4294967279 17]] +*/ + SST_Math_Mat22uSubtractLocal(&X,&Y); /* for accuracy */ + TASSERT((X.v[0])==(4294967285),"Entry _a11 failed!"); + TASSERT((X.v[2])==(11),"Entry _a12 failed!"); + TASSERT((X.v[1])==(4294967279),"Entry _a21 failed!"); + TASSERT((X.v[3])==(17),"Entry _a22 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat22uMultiplyElementwise(){ + SST_Mat22u X; /* 2 x 2 matrix */ + SST_Mat22u Y; /* 2 x 2 matrix */ + SST_Mat22u A; /* 2 x 2 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = 6; + X.v[1] = 9; + X.v[2] = 36; + X.v[3] = 17; + Y.v[0] = 0; + Y.v[1] = 19; + Y.v[2] = 38; + Y.v[3] = 19; +/* +[[ 6 36] + [ 9 17]] +[[ 0 38] + [19 19]] +[[ 0 1368] + [ 171 323]] +*/ + SST_Math_Mat22uMultiplyElementwise(&X, &Y, &A); + TASSERT((A.v[0])==(0),"Entry _a11 failed!"); + TASSERT((A.v[2])==(1368),"Entry _a12 failed!"); + TASSERT((A.v[1])==(171),"Entry _a21 failed!"); + TASSERT((A.v[3])==(323),"Entry _a22 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat22uMultiplyElementwiseLocal(){ + SST_Mat22u X; /* 2 x 2 matrix */ + SST_Mat22u Y; /* 2 x 2 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = 24; + X.v[1] = 20; + X.v[2] = 28; + X.v[3] = 37; + Y.v[0] = 25; + Y.v[1] = 9; + Y.v[2] = 21; + Y.v[3] = 38; +/* +[[24 28] + [20 37]] +[[25 21] + [ 9 38]] +[[ 600 588] + [ 180 1406]] +*/ + SST_Math_Mat22uMultiplyElementwiseLocal(&X,&Y); + TASSERT((X.v[0])==(600),"Entry _a11 failed!"); + TASSERT((X.v[2])==(588),"Entry _a12 failed!"); + TASSERT((X.v[1])==(180),"Entry _a21 failed!"); + TASSERT((X.v[3])==(1406),"Entry _a22 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat22uMultiplyScalar(){ + SST_Mat22u X; /* 2 x 2 matrix */ + SST_Mat22u A; /* 2 x 2 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = 33; + X.v[1] = 2; + X.v[2] = 24; + X.v[3] = 39; +/* +[[33 24] + [ 2 39]] +[[66 48] + [ 4 78]] +*/ + SST_Math_Mat22uMultiplyScalar(&X,2,&A); + TASSERT((A.v[0])==(66),"Entry _a11 failed!"); + TASSERT((A.v[2])==(48),"Entry _a12 failed!"); + TASSERT((A.v[1])==(4),"Entry _a21 failed!"); + TASSERT((A.v[3])==(78),"Entry _a22 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat22uMultiplyScalarLocal(){ + SST_Mat22u X; /* 2 x 2 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = 11; + X.v[1] = 22; + X.v[2] = 3; + X.v[3] = 13; +/* +[[11 3] + [22 13]] +[[22 6] + [44 26]] +*/ + SST_Math_Mat22uMultiplyScalarLocal(&X,2); + TASSERT((X.v[0])==(22),"Entry _a11 failed!"); + TASSERT((X.v[2])==(6),"Entry _a12 failed!"); + TASSERT((X.v[1])==(44),"Entry _a21 failed!"); + TASSERT((X.v[3])==(26),"Entry _a22 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat22uMultiplyMatrix(){ + SST_Mat22u X; /* 2 x 2 matrix */ + SST_Mat22u Y; /* 2 x 2 matrix */ + SST_Mat22u A; /* 2 x 2 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = 36; + X.v[1] = 18; + X.v[2] = 29; + X.v[3] = 14; + Y.v[0] = 6; + Y.v[1] = 17; + Y.v[2] = 31; + Y.v[3] = 8; +/* +X +[[36 29] + [18 14]] +Y +[[ 6 31] + [17 8]] +[[ 709 1348] + [ 346 670]] +*/ + SST_Math_Mat22uMultiplyMatrix(&X,&Y,&A); + TASSERT((A.v[0])==(709),"Entry _a11 failed!"); + TASSERT((A.v[2])==(1348),"Entry _a12 failed!"); + TASSERT((A.v[1])==(346),"Entry _a21 failed!"); + TASSERT((A.v[3])==(670),"Entry _a22 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat22uMultiplyMatrixLocal(){ + SST_Mat22u X; /* 2 x 2 matrix */ + SST_Mat22u Y; /* 2 x 2 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = 30; + X.v[1] = 6; + X.v[2] = 13; + X.v[3] = 33; + Y.v[0] = 20; + Y.v[1] = 24; + Y.v[2] = 2; + Y.v[3] = 2; +/* +X +[[30 13] + [ 6 33]] +Y +[[20 2] + [24 2]] +X +[[912 86] + [912 78]] +*/ + SST_Math_Mat22uMultiplyMatrixLocal(&X,&Y); + TASSERT((X.v[0])==(912),"Entry _a11 failed!"); + TASSERT((X.v[2])==(86),"Entry _a12 failed!"); + TASSERT((X.v[1])==(912),"Entry _a21 failed!"); + TASSERT((X.v[3])==(78),"Entry _a22 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat22uMultiplyVector(){ + SST_Mat22u X; /* 2 x 2 matrix */ + SST_Vec2u v; /* 2 vector */ + SST_Vec2u w; /* 2 vector */ +/* Resetting test vectors / mats */ + v.v[0] = 21; + v.v[1] = 34; + X.v[0] = 34; + X.v[1] = 39; + X.v[2] = 28; + X.v[3] = 7; +/* +X +[[34 28] + [39 7]] +v +[21 34] +w +[1666 1057] +*/ + SST_Math_Mat22uMultiplyVector(&X,&v,&w); + TASSERT((w.v[0])==(1666),"Entry .v[0] failed!"); + TASSERT((w.v[1])==(1057),"Entry .v[1] failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat22uMultiplyVectorLocal(){ + SST_Mat22u X; /* 2 x 2 matrix */ + SST_Vec2u v; /* 2 vector */ +/* Resetting test vectors / mats */ + v.v[0] = 9; + v.v[1] = 29; + X.v[0] = 35; + X.v[1] = 4; + X.v[2] = 30; + X.v[3] = 22; +/* +X +[[35 30] + [ 4 22]] +v +[ 9 29] +v +[1185 674] +*/ + SST_Math_Mat22uMultiplyVectorLocal(&X,&v); + TASSERT((v.v[0])==(1185),"Entry .v[0] failed!"); + TASSERT((v.v[1])==(674),"Entry .v[1] failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat22uTranspose(){ + SST_Mat22u X; /* 2 x 2 matrix */ + SST_Mat22u A; /* 2 x 2 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = 19; + X.v[1] = 39; + X.v[2] = 14; + X.v[3] = 38; + SST_Math_Mat22uTranspose(&X,&A); + TASSERT((A.v[0])==(19),"Entry _a11 failed!"); + TASSERT((A.v[2])==(39),"Entry _a12 failed!"); + TASSERT((A.v[1])==(14),"Entry _a21 failed!"); + TASSERT((A.v[3])==(38),"Entry _a22 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat22uTransposeLocal(){ + SST_Mat22u X; /* 2 x 2 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = 34; + X.v[1] = 36; + X.v[2] = 12; + X.v[3] = 8; + SST_Math_Mat22uTransposeLocal(&X); + TASSERT((X.v[0])==(34),"Entry _a11 failed!"); + TASSERT((X.v[2])==(36),"Entry _a12 failed!"); + TASSERT((X.v[1])==(12),"Entry _a21 failed!"); + TASSERT((X.v[3])==(8),"Entry _a22 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + diff --git a/ZTestSuite/Test-SST_Mat33d.cpp b/ZTestSuite/Test-SST_Mat33d.cpp new file mode 100644 index 0000000..dabfc23 --- /dev/null +++ b/ZTestSuite/Test-SST_Mat33d.cpp @@ -0,0 +1,1002 @@ +/* + AUTOMATICALLY GENERATED FILE - DO NOT EDIT! + Please change MatrixNxN.py and re-run it +*/ +/* Generated with ./MatrixNxN.py n = 3, TYPE = double */ + +#include "ZUnitTest.hpp" +#include <float.h> +#include <math.h> +#include <stdlib.h> +#include <stdio.h> +#include <SST/SST_Mat33.h> +#include <SST/SST_Vec3.h> + + + + +static const char* testSST_Math_Mat33dAdd(); +static const char* testSST_Math_Mat33dAddLocal(); +static const char* testSST_Math_Mat33dSubtract(); +static const char* testSST_Math_Mat33dSubtractLocal(); +static const char* testSST_Math_Mat33dMultiplyElementwise(); +static const char* testSST_Math_Mat33dMultiplyElementwiseLocal(); +static const char* testSST_Math_Mat33dMultiplyScalar(); +static const char* testSST_Math_Mat33dMultiplyScalarLocal(); +static const char* testSST_Math_Mat33dMultiplyMatrix(); +static const char* testSST_Math_Mat33dMultiplyMatrixLocal(); +static const char* testSST_Math_Mat33dMultiplyVector(); +static const char* testSST_Math_Mat33dMultiplyVectorLocal(); +static const char* testSST_Math_Mat33dTranspose(); +static const char* testSST_Math_Mat33dTransposeLocal(); +static const char* testSST_Math_Mat33dDeterminant(); +static const char* testSST_Math_Mat33dCheckOrthonormal(); +static const char* testSST_Math_Mat33dInvert(); +static const char* testSST_Math_Mat33dInvertLocal(); +static const char* testSST_Math_Mat33dCreateLU(); +static const char* testSST_Math_Mat33dCreateLULocal(); +static const char* testSST_Math_Mat33dApplyLUMat(); +static const char* testSST_Math_Mat33dApplyLUMatLocal(); +static const char* testSST_Math_Mat33dApplyLUVec(); +static const char* testSST_Math_Mat33dApplyLUVecLocal(); +// List of unit tests +ZUnitTest SST_Math_Mat33dUnitTests[] = +{ +{ "testSST_Math_Mat33dAdd " , testSST_Math_Mat33dAdd }, +{ "testSST_Math_Mat33dAddLocal " , testSST_Math_Mat33dAddLocal }, +{ "testSST_Math_Mat33dSubtract " , testSST_Math_Mat33dSubtract }, +{ "testSST_Math_Mat33dSubtractLocal " , testSST_Math_Mat33dSubtractLocal }, +{ "testSST_Math_Mat33dMultiplyElementwise " , testSST_Math_Mat33dMultiplyElementwise }, +{ "testSST_Math_Mat33dMultiplyElementwiseLocal " , testSST_Math_Mat33dMultiplyElementwiseLocal }, +{ "testSST_Math_Mat33dMultiplyScalar " , testSST_Math_Mat33dMultiplyScalar }, +{ "testSST_Math_Mat33dMultiplyScalarLocal " , testSST_Math_Mat33dMultiplyScalarLocal }, +{ "testSST_Math_Mat33dMultiplyMatrix " , testSST_Math_Mat33dMultiplyMatrix }, +{ "testSST_Math_Mat33dMultiplyMatrixLocal " , testSST_Math_Mat33dMultiplyMatrixLocal }, +{ "testSST_Math_Mat33dMultiplyVector " , testSST_Math_Mat33dMultiplyVector }, +{ "testSST_Math_Mat33dMultiplyVectorLocal " , testSST_Math_Mat33dMultiplyVectorLocal }, +{ "testSST_Math_Mat33dDeterminant " , testSST_Math_Mat33dDeterminant }, +{ "testSST_Math_Mat33dCheckOrthonormal " , testSST_Math_Mat33dCheckOrthonormal }, +{ "testSST_Math_Mat33dInvert " , testSST_Math_Mat33dInvert }, +{ "testSST_Math_Mat33dInvertLocal " , testSST_Math_Mat33dInvertLocal }, +{ "testSST_Math_Mat33dCreateLU " , testSST_Math_Mat33dCreateLU }, +{ "testSST_Math_Mat33dCreateLULocal " , testSST_Math_Mat33dCreateLULocal }, +{ "testSST_Math_Mat33dApplyLUMat " , testSST_Math_Mat33dApplyLUMat }, +{ "testSST_Math_Mat33dApplyLUMatLocal " , testSST_Math_Mat33dApplyLUMatLocal }, +{ "testSST_Math_Mat33dApplyLUVec " , testSST_Math_Mat33dApplyLUVec }, +{ "testSST_Math_Mat33dApplyLUVecLocal " , testSST_Math_Mat33dApplyLUVecLocal }, +{ "testSST_Math_Mat33dTranspose " , testSST_Math_Mat33dTranspose }, +{ "testSST_Math_Mat33dTransposeLocal " , testSST_Math_Mat33dTransposeLocal } +}; +DECLARE_ZTESTBLOCK(SST_Math_Mat33d) + +/******************************************************************************/ + +static const char* testSST_Math_Mat33dAdd(){ + SST_Mat33d X; /* 3 x 3 matrix */ + SST_Mat33d Y; /* 3 x 3 matrix */ + SST_Mat33d A; /* 3 x 3 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = -5.000000000000000; + X.v[1] = 9.000000000000000; + X.v[2] = 5.000000000000000; + X.v[3] = 14.000000000000000; + X.v[4] = -11.000000000000000; + X.v[5] = -1.000000000000000; + X.v[6] = 3.000000000000000; + X.v[7] = -18.000000000000000; + X.v[8] = -20.000000000000000; + Y.v[0] = -14.000000000000000; + Y.v[1] = -7.000000000000000; + Y.v[2] = 1.000000000000000; + Y.v[3] = -4.000000000000000; + Y.v[4] = 3.000000000000000; + Y.v[5] = -12.000000000000000; + Y.v[6] = -14.000000000000000; + Y.v[7] = 11.000000000000000; + Y.v[8] = -3.000000000000000; +/* +[[ -5. 14. 3.] + [ 9. -11. -18.] + [ 5. -1. -20.]] +[[-14. -4. -14.] + [ -7. 3. 11.] + [ 1. -12. -3.]] +[[-19. 10. -11.] + [ 2. -8. -7.] + [ 6. -13. -23.]] +*/ + SST_Math_Mat33dAdd(&X,&Y,&A); + TASSERT(fabs((A.v[0])-( -19.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a11 failed!"); + TASSERT(fabs((A.v[3])-( 10.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a12 failed!"); + TASSERT(fabs((A.v[6])-( -11.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a13 failed!"); + TASSERT(fabs((A.v[1])-( 2.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a21 failed!"); + TASSERT(fabs((A.v[4])-( -8.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a22 failed!"); + TASSERT(fabs((A.v[7])-( -7.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a23 failed!"); + TASSERT(fabs((A.v[2])-( 6.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a31 failed!"); + TASSERT(fabs((A.v[5])-( -13.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a32 failed!"); + TASSERT(fabs((A.v[8])-( -23.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a33 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat33dAddLocal(){ + SST_Mat33d X; /* 3 x 3 matrix */ + SST_Mat33d Y; /* 3 x 3 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = 3.000000000000000; + X.v[1] = 14.000000000000000; + X.v[2] = 8.000000000000000; + X.v[3] = 10.000000000000000; + X.v[4] = 16.000000000000000; + X.v[5] = 3.000000000000000; + X.v[6] = -3.000000000000000; + X.v[7] = -10.000000000000000; + X.v[8] = -4.000000000000000; + Y.v[0] = 19.000000000000000; + Y.v[1] = 16.000000000000000; + Y.v[2] = -2.000000000000000; + Y.v[3] = 3.000000000000000; + Y.v[4] = -20.000000000000000; + Y.v[5] = 3.000000000000000; + Y.v[6] = 5.000000000000000; + Y.v[7] = -1.000000000000000; + Y.v[8] = 18.000000000000000; +/* +[[ 3. 10. -3.] + [ 14. 16. -10.] + [ 8. 3. -4.]] +[[ 19. 3. 5.] + [ 16. -20. -1.] + [ -2. 3. 18.]] +[[ 22. 13. 2.] + [ 30. -4. -11.] + [ 6. 6. 14.]] +*/ + SST_Math_Mat33dAddLocal(&X,&Y); /* for accuracy */ + TASSERT(fabs((X.v[0])-( 22.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a11 failed!"); + TASSERT(fabs((X.v[3])-( 13.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a12 failed!"); + TASSERT(fabs((X.v[6])-( 2.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a13 failed!"); + TASSERT(fabs((X.v[1])-( 30.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a21 failed!"); + TASSERT(fabs((X.v[4])-( -4.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a22 failed!"); + TASSERT(fabs((X.v[7])-( -11.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a23 failed!"); + TASSERT(fabs((X.v[2])-( 6.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a31 failed!"); + TASSERT(fabs((X.v[5])-( 6.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a32 failed!"); + TASSERT(fabs((X.v[8])-( 14.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a33 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat33dSubtract(){ + SST_Mat33d X; /* 3 x 3 matrix */ + SST_Mat33d Y; /* 3 x 3 matrix */ + SST_Mat33d A; /* 3 x 3 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = -3.000000000000000; + X.v[1] = 12.000000000000000; + X.v[2] = -20.000000000000000; + X.v[3] = 3.000000000000000; + X.v[4] = -11.000000000000000; + X.v[5] = -16.000000000000000; + X.v[6] = 2.000000000000000; + X.v[7] = -18.000000000000000; + X.v[8] = 11.000000000000000; + Y.v[0] = -14.000000000000000; + Y.v[1] = -9.000000000000000; + Y.v[2] = 10.000000000000000; + Y.v[3] = 13.000000000000000; + Y.v[4] = -8.000000000000000; + Y.v[5] = -17.000000000000000; + Y.v[6] = -9.000000000000000; + Y.v[7] = 13.000000000000000; + Y.v[8] = -14.000000000000000; +/* +[[ -3. 3. 2.] + [ 12. -11. -18.] + [-20. -16. 11.]] +[[-14. 13. -9.] + [ -9. -8. 13.] + [ 10. -17. -14.]] +[[ 11. -10. 11.] + [ 21. -3. -31.] + [-30. 1. 25.]] +*/ + SST_Math_Mat33dSubtract(&X,&Y,&A); + TASSERT(fabs((A.v[0])-( 11.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a11 failed!"); + TASSERT(fabs((A.v[3])-( -10.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a12 failed!"); + TASSERT(fabs((A.v[6])-( 11.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a13 failed!"); + TASSERT(fabs((A.v[1])-( 21.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a21 failed!"); + TASSERT(fabs((A.v[4])-( -3.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a22 failed!"); + TASSERT(fabs((A.v[7])-( -31.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a23 failed!"); + TASSERT(fabs((A.v[2])-( -30.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a31 failed!"); + TASSERT(fabs((A.v[5])-( 1.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a32 failed!"); + TASSERT(fabs((A.v[8])-( 25.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a33 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat33dSubtractLocal(){ + SST_Mat33d X; /* 3 x 3 matrix */ + SST_Mat33d Y; /* 3 x 3 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = 10.000000000000000; + X.v[1] = 0.000000000000000; + X.v[2] = 18.000000000000000; + X.v[3] = 10.000000000000000; + X.v[4] = -4.000000000000000; + X.v[5] = -8.000000000000000; + X.v[6] = 16.000000000000000; + X.v[7] = 7.000000000000000; + X.v[8] = -4.000000000000000; + Y.v[0] = 1.000000000000000; + Y.v[1] = 9.000000000000000; + Y.v[2] = 17.000000000000000; + Y.v[3] = -1.000000000000000; + Y.v[4] = 17.000000000000000; + Y.v[5] = 5.000000000000000; + Y.v[6] = -18.000000000000000; + Y.v[7] = -6.000000000000000; + Y.v[8] = -10.000000000000000; +/* +[[ 10. 10. 16.] + [ 0. -4. 7.] + [ 18. -8. -4.]] +[[ 1. -1. -18.] + [ 9. 17. -6.] + [ 17. 5. -10.]] +[[ 9. 11. 34.] + [ -9. -21. 13.] + [ 1. -13. 6.]] +*/ + SST_Math_Mat33dSubtractLocal(&X,&Y); /* for accuracy */ + TASSERT(fabs((X.v[0])-( 9.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a11 failed!"); + TASSERT(fabs((X.v[3])-( 11.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a12 failed!"); + TASSERT(fabs((X.v[6])-( 34.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a13 failed!"); + TASSERT(fabs((X.v[1])-( -9.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a21 failed!"); + TASSERT(fabs((X.v[4])-( -21.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a22 failed!"); + TASSERT(fabs((X.v[7])-( 13.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a23 failed!"); + TASSERT(fabs((X.v[2])-( 1.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a31 failed!"); + TASSERT(fabs((X.v[5])-( -13.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a32 failed!"); + TASSERT(fabs((X.v[8])-( 6.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a33 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat33dMultiplyElementwise(){ + SST_Mat33d X; /* 3 x 3 matrix */ + SST_Mat33d Y; /* 3 x 3 matrix */ + SST_Mat33d A; /* 3 x 3 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = -14.000000000000000; + X.v[1] = -6.000000000000000; + X.v[2] = -11.000000000000000; + X.v[3] = 14.000000000000000; + X.v[4] = -19.000000000000000; + X.v[5] = 8.000000000000000; + X.v[6] = -19.000000000000000; + X.v[7] = 9.000000000000000; + X.v[8] = -10.000000000000000; + Y.v[0] = 11.000000000000000; + Y.v[1] = 13.000000000000000; + Y.v[2] = 12.000000000000000; + Y.v[3] = 2.000000000000000; + Y.v[4] = 7.000000000000000; + Y.v[5] = -13.000000000000000; + Y.v[6] = -7.000000000000000; + Y.v[7] = 19.000000000000000; + Y.v[8] = -6.000000000000000; +/* +[[-14. 14. -19.] + [ -6. -19. 9.] + [-11. 8. -10.]] +[[ 11. 2. -7.] + [ 13. 7. 19.] + [ 12. -13. -6.]] +[[-154. 28. 133.] + [ -78. -133. 171.] + [-132. -104. 60.]] +*/ + SST_Math_Mat33dMultiplyElementwise(&X, &Y, &A); + TASSERT(fabs((A.v[0])-( -154.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a11 failed!"); + TASSERT(fabs((A.v[3])-( 28.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a12 failed!"); + TASSERT(fabs((A.v[6])-( 133.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a13 failed!"); + TASSERT(fabs((A.v[1])-( -78.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a21 failed!"); + TASSERT(fabs((A.v[4])-( -133.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a22 failed!"); + TASSERT(fabs((A.v[7])-( 171.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a23 failed!"); + TASSERT(fabs((A.v[2])-( -132.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a31 failed!"); + TASSERT(fabs((A.v[5])-( -104.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a32 failed!"); + TASSERT(fabs((A.v[8])-( 60.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a33 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat33dMultiplyElementwiseLocal(){ + SST_Mat33d X; /* 3 x 3 matrix */ + SST_Mat33d Y; /* 3 x 3 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = -17.000000000000000; + X.v[1] = -1.000000000000000; + X.v[2] = -16.000000000000000; + X.v[3] = -13.000000000000000; + X.v[4] = 10.000000000000000; + X.v[5] = -17.000000000000000; + X.v[6] = 19.000000000000000; + X.v[7] = -11.000000000000000; + X.v[8] = -2.000000000000000; + Y.v[0] = -19.000000000000000; + Y.v[1] = -5.000000000000000; + Y.v[2] = 5.000000000000000; + Y.v[3] = 19.000000000000000; + Y.v[4] = 6.000000000000000; + Y.v[5] = -19.000000000000000; + Y.v[6] = -15.000000000000000; + Y.v[7] = -19.000000000000000; + Y.v[8] = -13.000000000000000; +/* +[[-17. -13. 19.] + [ -1. 10. -11.] + [-16. -17. -2.]] +[[-19. 19. -15.] + [ -5. 6. -19.] + [ 5. -19. -13.]] +[[ 323. -247. -285.] + [ 5. 60. 209.] + [ -80. 323. 26.]] +*/ + SST_Math_Mat33dMultiplyElementwiseLocal(&X,&Y); + TASSERT(fabs((X.v[0])-( 323.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a11 failed!"); + TASSERT(fabs((X.v[3])-( -247.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a12 failed!"); + TASSERT(fabs((X.v[6])-( -285.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a13 failed!"); + TASSERT(fabs((X.v[1])-( 5.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a21 failed!"); + TASSERT(fabs((X.v[4])-( 60.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a22 failed!"); + TASSERT(fabs((X.v[7])-( 209.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a23 failed!"); + TASSERT(fabs((X.v[2])-( -80.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a31 failed!"); + TASSERT(fabs((X.v[5])-( 323.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a32 failed!"); + TASSERT(fabs((X.v[8])-( 26.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a33 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat33dMultiplyScalar(){ + SST_Mat33d X; /* 3 x 3 matrix */ + SST_Mat33d A; /* 3 x 3 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = -13.000000000000000; + X.v[1] = -5.000000000000000; + X.v[2] = -18.000000000000000; + X.v[3] = 1.000000000000000; + X.v[4] = -18.000000000000000; + X.v[5] = 13.000000000000000; + X.v[6] = 13.000000000000000; + X.v[7] = -15.000000000000000; + X.v[8] = -17.000000000000000; +/* +[[-13. 1. 13.] + [ -5. -18. -15.] + [-18. 13. -17.]] +[[-26. 2. 26.] + [-10. -36. -30.] + [-36. 26. -34.]] +*/ + SST_Math_Mat33dMultiplyScalar(&X, 2.000000000000000,&A); + TASSERT(fabs((A.v[0])-( -26.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a11 failed!"); + TASSERT(fabs((A.v[3])-( 2.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a12 failed!"); + TASSERT(fabs((A.v[6])-( 26.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a13 failed!"); + TASSERT(fabs((A.v[1])-( -10.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a21 failed!"); + TASSERT(fabs((A.v[4])-( -36.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a22 failed!"); + TASSERT(fabs((A.v[7])-( -30.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a23 failed!"); + TASSERT(fabs((A.v[2])-( -36.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a31 failed!"); + TASSERT(fabs((A.v[5])-( 26.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a32 failed!"); + TASSERT(fabs((A.v[8])-( -34.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a33 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat33dMultiplyScalarLocal(){ + SST_Mat33d X; /* 3 x 3 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = 6.000000000000000; + X.v[1] = -19.000000000000000; + X.v[2] = 17.000000000000000; + X.v[3] = -17.000000000000000; + X.v[4] = -10.000000000000000; + X.v[5] = 12.000000000000000; + X.v[6] = -14.000000000000000; + X.v[7] = -1.000000000000000; + X.v[8] = -4.000000000000000; +/* +[[ 6. -17. -14.] + [-19. -10. -1.] + [ 17. 12. -4.]] +[[ 12. -34. -28.] + [-38. -20. -2.] + [ 34. 24. -8.]] +*/ + SST_Math_Mat33dMultiplyScalarLocal(&X, 2.000000000000000); + TASSERT(fabs((X.v[0])-( 12.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a11 failed!"); + TASSERT(fabs((X.v[3])-( -34.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a12 failed!"); + TASSERT(fabs((X.v[6])-( -28.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a13 failed!"); + TASSERT(fabs((X.v[1])-( -38.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a21 failed!"); + TASSERT(fabs((X.v[4])-( -20.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a22 failed!"); + TASSERT(fabs((X.v[7])-( -2.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a23 failed!"); + TASSERT(fabs((X.v[2])-( 34.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a31 failed!"); + TASSERT(fabs((X.v[5])-( 24.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a32 failed!"); + TASSERT(fabs((X.v[8])-( -8.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a33 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat33dMultiplyMatrix(){ + SST_Mat33d X; /* 3 x 3 matrix */ + SST_Mat33d Y; /* 3 x 3 matrix */ + SST_Mat33d A; /* 3 x 3 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = 14.000000000000000; + X.v[1] = 5.000000000000000; + X.v[2] = 15.000000000000000; + X.v[3] = -3.000000000000000; + X.v[4] = -16.000000000000000; + X.v[5] = 4.000000000000000; + X.v[6] = 12.000000000000000; + X.v[7] = 6.000000000000000; + X.v[8] = -4.000000000000000; + Y.v[0] = 13.000000000000000; + Y.v[1] = 0.000000000000000; + Y.v[2] = 0.000000000000000; + Y.v[3] = -17.000000000000000; + Y.v[4] = -9.000000000000000; + Y.v[5] = -12.000000000000000; + Y.v[6] = 2.000000000000000; + Y.v[7] = -5.000000000000000; + Y.v[8] = -14.000000000000000; +/* +X +[[ 14. -3. 12.] + [ 5. -16. 6.] + [ 15. 4. -4.]] +Y +[[ 13. -17. 2.] + [ 0. -9. -5.] + [ 0. -12. -14.]] +[[ 182. -355. -125.] + [ 65. -13. 6.] + [ 195. -243. 66.]] +*/ + SST_Math_Mat33dMultiplyMatrix(&X,&Y,&A); + TASSERT(fabs((A.v[0])-( 182.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a11 failed!"); + TASSERT(fabs((A.v[3])-( -355.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a12 failed!"); + TASSERT(fabs((A.v[6])-( -125.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a13 failed!"); + TASSERT(fabs((A.v[1])-( 65.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a21 failed!"); + TASSERT(fabs((A.v[4])-( -13.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a22 failed!"); + TASSERT(fabs((A.v[7])-( 6.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a23 failed!"); + TASSERT(fabs((A.v[2])-( 195.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a31 failed!"); + TASSERT(fabs((A.v[5])-( -243.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a32 failed!"); + TASSERT(fabs((A.v[8])-( 66.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a33 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat33dMultiplyMatrixLocal(){ + SST_Mat33d X; /* 3 x 3 matrix */ + SST_Mat33d Y; /* 3 x 3 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = 11.000000000000000; + X.v[1] = -13.000000000000000; + X.v[2] = -4.000000000000000; + X.v[3] = 13.000000000000000; + X.v[4] = 2.000000000000000; + X.v[5] = -18.000000000000000; + X.v[6] = -15.000000000000000; + X.v[7] = 4.000000000000000; + X.v[8] = -10.000000000000000; + Y.v[0] = -1.000000000000000; + Y.v[1] = -12.000000000000000; + Y.v[2] = 4.000000000000000; + Y.v[3] = -11.000000000000000; + Y.v[4] = 13.000000000000000; + Y.v[5] = -8.000000000000000; + Y.v[6] = 13.000000000000000; + Y.v[7] = 19.000000000000000; + Y.v[8] = -14.000000000000000; +/* +X +[[ 11. 13. -15.] + [-13. 2. 4.] + [ -4. -18. -10.]] +Y +[[ -1. -11. 13.] + [-12. 13. 19.] + [ 4. -8. -14.]] +X +[[-227. 168. 600.] + [ 5. 137. -187.] + [ 180. -110. -254.]] +*/ + SST_Math_Mat33dMultiplyMatrixLocal(&X,&Y); + TASSERT(fabs((X.v[0])-( -227.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a11 failed!"); + TASSERT(fabs((X.v[3])-( 168.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a12 failed!"); + TASSERT(fabs((X.v[6])-( 600.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a13 failed!"); + TASSERT(fabs((X.v[1])-( 5.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a21 failed!"); + TASSERT(fabs((X.v[4])-( 137.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a22 failed!"); + TASSERT(fabs((X.v[7])-( -187.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a23 failed!"); + TASSERT(fabs((X.v[2])-( 180.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a31 failed!"); + TASSERT(fabs((X.v[5])-( -110.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a32 failed!"); + TASSERT(fabs((X.v[8])-( -254.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a33 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat33dMultiplyVector(){ + SST_Mat33d X; /* 3 x 3 matrix */ + SST_Vec3d v; /* 3 vector */ + SST_Vec3d w; /* 3 vector */ +/* Resetting test vectors / mats */ + v.v[0] = 7.000000000000000; + v.v[1] = -10.000000000000000; + v.v[2] = 4.000000000000000; + X.v[0] = 13.000000000000000; + X.v[1] = -7.000000000000000; + X.v[2] = -8.000000000000000; + X.v[3] = -1.000000000000000; + X.v[4] = 16.000000000000000; + X.v[5] = -8.000000000000000; + X.v[6] = -14.000000000000000; + X.v[7] = 0.000000000000000; + X.v[8] = 9.000000000000000; +/* +X +[[ 13. -1. -14.] + [ -7. 16. 0.] + [ -8. -8. 9.]] +v +[ 7. -10. 4.] +w +[ 45. -209. 60.] +*/ + SST_Math_Mat33dMultiplyVector(&X,&v,&w); + TASSERT(fabs((w.v[0])-( 45.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry .v[0] failed!"); + TASSERT(fabs((w.v[1])-( -209.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry .v[1] failed!"); + TASSERT(fabs((w.v[2])-( 60.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry .v[2] failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat33dMultiplyVectorLocal(){ + SST_Mat33d X; /* 3 x 3 matrix */ + SST_Vec3d v; /* 3 vector */ +/* Resetting test vectors / mats */ + v.v[0] = -16.000000000000000; + v.v[1] = -20.000000000000000; + v.v[2] = -11.000000000000000; + X.v[0] = -7.000000000000000; + X.v[1] = -3.000000000000000; + X.v[2] = -14.000000000000000; + X.v[3] = 6.000000000000000; + X.v[4] = -1.000000000000000; + X.v[5] = 7.000000000000000; + X.v[6] = -18.000000000000000; + X.v[7] = -7.000000000000000; + X.v[8] = -2.000000000000000; +/* +X +[[ -7. 6. -18.] + [ -3. -1. -7.] + [-14. 7. -2.]] +v +[-16. -20. -11.] +v +[ 190. 145. 106.] +*/ + SST_Math_Mat33dMultiplyVectorLocal(&X,&v); + TASSERT(fabs((v.v[0])-( 190.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry .v[0] failed!"); + TASSERT(fabs((v.v[1])-( 145.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry .v[1] failed!"); + TASSERT(fabs((v.v[2])-( 106.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry .v[2] failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat33dTranspose(){ + SST_Mat33d X; /* 3 x 3 matrix */ + SST_Mat33d A; /* 3 x 3 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = -1.000000000000000; + X.v[1] = 19.000000000000000; + X.v[2] = 10.000000000000000; + X.v[3] = -15.000000000000000; + X.v[4] = 17.000000000000000; + X.v[5] = 2.000000000000000; + X.v[6] = 18.000000000000000; + X.v[7] = 13.000000000000000; + X.v[8] = -20.000000000000000; + SST_Math_Mat33dTranspose(&X,&A); + TASSERT(fabs((A.v[0])-( -1.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a11 failed!"); + TASSERT(fabs((A.v[3])-( 19.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a12 failed!"); + TASSERT(fabs((A.v[6])-( 10.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a13 failed!"); + TASSERT(fabs((A.v[1])-( -15.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a21 failed!"); + TASSERT(fabs((A.v[4])-( 17.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a22 failed!"); + TASSERT(fabs((A.v[7])-( 2.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a23 failed!"); + TASSERT(fabs((A.v[2])-( 18.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a31 failed!"); + TASSERT(fabs((A.v[5])-( 13.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a32 failed!"); + TASSERT(fabs((A.v[8])-( -20.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a33 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat33dTransposeLocal(){ + SST_Mat33d X; /* 3 x 3 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = 14.000000000000000; + X.v[1] = -13.000000000000000; + X.v[2] = 13.000000000000000; + X.v[3] = 5.000000000000000; + X.v[4] = -15.000000000000000; + X.v[5] = 16.000000000000000; + X.v[6] = 17.000000000000000; + X.v[7] = -15.000000000000000; + X.v[8] = -5.000000000000000; + SST_Math_Mat33dTransposeLocal(&X); + TASSERT(fabs((X.v[0])-( 14.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a11 failed!"); + TASSERT(fabs((X.v[3])-( -13.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a12 failed!"); + TASSERT(fabs((X.v[6])-( 13.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a13 failed!"); + TASSERT(fabs((X.v[1])-( 5.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a21 failed!"); + TASSERT(fabs((X.v[4])-( -15.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a22 failed!"); + TASSERT(fabs((X.v[7])-( 16.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a23 failed!"); + TASSERT(fabs((X.v[2])-( 17.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a31 failed!"); + TASSERT(fabs((X.v[5])-( -15.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a32 failed!"); + TASSERT(fabs((X.v[8])-( -5.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a33 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat33dCheckOrthonormal(){ + SST_Mat33d X; /* 3 x 3 matrix */ + SST_Mat33d Y; /* 3 x 3 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = -16.000000000000000; + X.v[1] = 5.000000000000000; + X.v[2] = -10.000000000000000; + X.v[3] = 1.000000000000000; + X.v[4] = -8.000000000000000; + X.v[5] = 0.000000000000000; + X.v[6] = -7.000000000000000; + X.v[7] = -11.000000000000000; + X.v[8] = -5.000000000000000; + Y.v[0] = 8.000000000000000; + Y.v[1] = 11.000000000000000; + Y.v[2] = -17.000000000000000; + Y.v[3] = -6.000000000000000; + Y.v[4] = 5.000000000000000; + Y.v[5] = 9.000000000000000; + Y.v[6] = -9.000000000000000; + Y.v[7] = -4.000000000000000; + Y.v[8] = -9.000000000000000; +/* +[[-0.81970483 -0.17940169 -0.54396601] + [ 0.25615776 -0.96424052 -0.06799575] + [-0.51231552 -0.19507756 0.83634775]] +[[ 1.00000000e+00 -1.38777878e-17 0.00000000e+00] + [ -1.38777878e-17 1.00000000e+00 -2.77555756e-17] + [ 0.00000000e+00 -2.77555756e-17 1.00000000e+00]] +*/ +/* Set X to orthogonal matrix Q */ + X.v[0] = (double) -0.819704831325696; + X.v[1] = (double) 0.256157759789280; + X.v[2] = (double) -0.512315519578560; + X.v[3] = (double) -0.179401686289200; + X.v[4] = (double) -0.964240519705837; + X.v[5] = (double) -0.195077561790198; + X.v[6] = (double) -0.543966014065129; + X.v[7] = (double) -0.067995751758141; + X.v[8] = (double) 0.836347746625135; +/* Check Positive Test */ + TASSERT(SST_Math_Mat33dCheckOrthonormal(&X),"CheckOrthonormal failed when it should have passed"); +/* Check Negative Test */ + TASSERT(!SST_Math_Mat33dCheckOrthonormal(&Y),"CheckOrthonormal succeeded when it should have failed"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat33dDeterminant(){ + SST_Mat33d X; /* 3 x 3 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = -3.000000000000000; + X.v[1] = 13.000000000000000; + X.v[2] = 1.000000000000000; + X.v[3] = 0.000000000000000; + X.v[4] = 2.000000000000000; + X.v[5] = -6.000000000000000; + X.v[6] = 2.000000000000000; + X.v[7] = -12.000000000000000; + X.v[8] = 19.000000000000000; +/* det(X) = +-58.0 + */ + double result = SST_Math_Mat33dDeterminant(&X); + TASSERT(fabs( (result)/( -57.999999999999986) - 1.000000000000000 ) <= 100*DBL_EPSILON,"Determinant failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat33dInvert(){ + SST_Mat33d X; /* 3 x 3 matrix */ + SST_Mat33d B; /* 3 x 3 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = -14.000000000000000; + X.v[1] = -2.000000000000000; + X.v[2] = 7.000000000000000; + X.v[3] = 13.000000000000000; + X.v[4] = 17.000000000000000; + X.v[5] = 1.000000000000000; + X.v[6] = 8.000000000000000; + X.v[7] = 5.000000000000000; + X.v[8] = -6.000000000000000; +/* +[[-0.12907117 0.10373945 -0.08564536] + [ 0.02774427 0.03377563 0.06513872] + [-0.14595899 0.12665862 -0.25572979]] +*/ + SST_Math_Mat33dInvert(&X,&B); + TASSERT(fabs((B.v[0])-( -0.129071170084439)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a11 failed!"); + TASSERT(fabs((B.v[1])-( 0.027744270205066)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a21 failed!"); + TASSERT(fabs((B.v[2])-( -0.145958986731001)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a31 failed!"); + TASSERT(fabs((B.v[3])-( 0.103739445114596)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a12 failed!"); + TASSERT(fabs((B.v[4])-( 0.033775633293124)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a22 failed!"); + TASSERT(fabs((B.v[5])-( 0.126658624849216)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a32 failed!"); + TASSERT(fabs((B.v[6])-( -0.085645355850422)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a13 failed!"); + TASSERT(fabs((B.v[7])-( 0.065138721351025)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a23 failed!"); + TASSERT(fabs((B.v[8])-( -0.255729794933655)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a33 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat33dInvertLocal(){ + SST_Mat33d X; /* 3 x 3 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = 17.000000000000000; + X.v[1] = 9.000000000000000; + X.v[2] = 15.000000000000000; + X.v[3] = 7.000000000000000; + X.v[4] = 6.000000000000000; + X.v[5] = -11.000000000000000; + X.v[6] = -15.000000000000000; + X.v[7] = 3.000000000000000; + X.v[8] = 3.000000000000000; +/* +() +[[ 0.01332288 0.03761755 0.02899687] + [ 0.00470219 0.07210031 -0.04858934] + [-0.04937304 0.07628004 0.01018809]] +*/ + SST_Math_Mat33dInvertLocal(&X); + TASSERT(fabs((X.v[0])-( 0.013322884012539)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a11 failed!"); + TASSERT(fabs((X.v[1])-( 0.004702194357367)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a21 failed!"); + TASSERT(fabs((X.v[2])-( -0.049373040752351)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a31 failed!"); + TASSERT(fabs((X.v[3])-( 0.037617554858934)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a12 failed!"); + TASSERT(fabs((X.v[4])-( 0.072100313479624)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a22 failed!"); + TASSERT(fabs((X.v[5])-( 0.076280041797283)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a32 failed!"); + TASSERT(fabs((X.v[6])-( 0.028996865203762)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a13 failed!"); + TASSERT(fabs((X.v[7])-( -0.048589341692790)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a23 failed!"); + TASSERT(fabs((X.v[8])-( 0.010188087774295)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a33 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat33dCreateLU(){ + SST_Mat33d X; /* 3 x 3 matrix */ + SST_Mat33d LU; /* 3 x 3 matrix */ + X.v[0] = 2.000000000000000; + X.v[1] = 1.000000000000000; + X.v[2] = 0.000000000000000; + X.v[3] = -1.000000000000000; + X.v[4] = 0.000000000000000; + X.v[5] = 2.000000000000000; + X.v[6] = -1.000000000000000; + X.v[7] = -1.000000000000000; + X.v[8] = 1.000000000000000; + SST_Math_Mat33dCreateLU(&X,&LU); +/* +[[ 2 -1 -1] + [ 1 0 -1] + [ 0 2 1]] +*/ +/* +[[ 2. 0. 0. ] + [ 1. 0.5 0. ] + [ 0. 2. 3. ]] +*/ +/* +[[ 1. -0.5 -0.5] + [ 0. 1. -1. ] + [ 0. 0. 1. ]] +*/ + TASSERT(fabs((LU.v[0])-( 2.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"L:Entry A_a11 failed!"); + TASSERT(fabs((LU.v[3])-( -0.500000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"U:Entry B_a12 failed!"); + TASSERT(fabs((LU.v[6])-( -0.500000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"U:Entry B_a13 failed!"); + TASSERT(fabs((LU.v[1])-( 1.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"L:Entry A_a21 failed!"); + TASSERT(fabs((LU.v[4])-( 0.500000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"L:Entry A_a22 failed!"); + TASSERT(fabs((LU.v[7])-( -1.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"U:Entry B_a23 failed!"); + TASSERT(fabs((LU.v[2])-( 0.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"L:Entry A_a31 failed!"); + TASSERT(fabs((LU.v[5])-( 2.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"L:Entry A_a32 failed!"); + TASSERT(fabs((LU.v[8])-( 3.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"L:Entry A_a33 failed!"); + return ZTEST_SUCCESS; +} +static const char* testSST_Math_Mat33dCreateLULocal(){ + SST_Mat33d X; /* 3 x 3 matrix */ + X.v[0] = 2.000000000000000; + X.v[1] = 1.000000000000000; + X.v[2] = 0.000000000000000; + X.v[3] = -1.000000000000000; + X.v[4] = 0.000000000000000; + X.v[5] = 2.000000000000000; + X.v[6] = -1.000000000000000; + X.v[7] = -1.000000000000000; + X.v[8] = 1.000000000000000; + SST_Math_Mat33dCreateLULocal(&X); + TASSERT(fabs((X.v[0])-( 2.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"L:Entry A_a11 failed!"); + TASSERT(fabs((X.v[3])-( -0.500000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"U:Entry B_a12 failed!"); + TASSERT(fabs((X.v[6])-( -0.500000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"U:Entry B_a13 failed!"); + TASSERT(fabs((X.v[1])-( 1.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"L:Entry A_a21 failed!"); + TASSERT(fabs((X.v[4])-( 0.500000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"L:Entry A_a22 failed!"); + TASSERT(fabs((X.v[7])-( -1.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"U:Entry B_a23 failed!"); + TASSERT(fabs((X.v[2])-( 0.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"L:Entry A_a31 failed!"); + TASSERT(fabs((X.v[5])-( 2.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"L:Entry A_a32 failed!"); + TASSERT(fabs((X.v[8])-( 3.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"L:Entry A_a33 failed!"); + return ZTEST_SUCCESS; +} +static const char* testSST_Math_Mat33dApplyLUMat(){ + SST_Mat33d X; /* 3 x 3 matrix */ + SST_Mat33d LU; /* 3 x 3 matrix */ + SST_Mat33d I; /* 3 x 3 matrix */ + X.v[0] = 2.000000000000000; + X.v[1] = 1.000000000000000; + X.v[2] = 0.000000000000000; + X.v[3] = -1.000000000000000; + X.v[4] = 0.000000000000000; + X.v[5] = 2.000000000000000; + X.v[6] = -1.000000000000000; + X.v[7] = -1.000000000000000; + X.v[8] = 1.000000000000000; + SST_Math_Mat33dCreateLU(&X,&LU); +/* +[[ 2 -1 -1] + [ 1 0 -1] + [ 0 2 1]] +*/ +/* +[[ 2. 0. 0. ] + [ 1. 0.5 0. ] + [ 0. 2. 3. ]] +*/ +/* +[[ 1. -0.5 -0.5] + [ 0. 1. -1. ] + [ 0. 0. 1. ]] +*/ + TASSERT(fabs((LU.v[0])-( 2.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"L:Entry A_a11 failed!"); + TASSERT(fabs((LU.v[3])-( -0.500000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"U:Entry B_a12 failed!"); + TASSERT(fabs((LU.v[6])-( -0.500000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"U:Entry B_a13 failed!"); + TASSERT(fabs((LU.v[1])-( 1.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"L:Entry A_a21 failed!"); + TASSERT(fabs((LU.v[4])-( 0.500000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"L:Entry A_a22 failed!"); + TASSERT(fabs((LU.v[7])-( -1.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"U:Entry B_a23 failed!"); + TASSERT(fabs((LU.v[2])-( 0.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"L:Entry A_a31 failed!"); + TASSERT(fabs((LU.v[5])-( 2.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"L:Entry A_a32 failed!"); + TASSERT(fabs((LU.v[8])-( 3.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"L:Entry A_a33 failed!"); + SST_Math_Mat33dApplyLUMat(&LU,&X,&I); + TASSERT(fabs((I.v[0])-( 1.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"I:Entry I_a11 failed!"); + TASSERT(fabs((I.v[1])-( 0.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"I:Entry I_a21 failed!"); + TASSERT(fabs((I.v[2])-( 0.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"I:Entry I_a31 failed!"); + TASSERT(fabs((I.v[3])-( 0.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"I:Entry I_a12 failed!"); + TASSERT(fabs((I.v[4])-( 1.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"I:Entry I_a22 failed!"); + TASSERT(fabs((I.v[5])-( 0.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"I:Entry I_a32 failed!"); + TASSERT(fabs((I.v[6])-( 0.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"I:Entry I_a13 failed!"); + TASSERT(fabs((I.v[7])-( 0.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"I:Entry I_a23 failed!"); + TASSERT(fabs((I.v[8])-( 1.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"I:Entry I_a33 failed!"); + return ZTEST_SUCCESS; +} +static const char* testSST_Math_Mat33dApplyLUMatLocal(){ + SST_Mat33d X; /* 3 x 3 matrix */ + SST_Mat33d Xinv; /* 3 x 3 matrix */ + X.v[0] = 2.000000000000000; + X.v[1] = 1.000000000000000; + X.v[2] = 0.000000000000000; + X.v[3] = -1.000000000000000; + X.v[4] = 0.000000000000000; + X.v[5] = 2.000000000000000; + X.v[6] = -1.000000000000000; + X.v[7] = -1.000000000000000; + X.v[8] = 1.000000000000000; + Xinv.v[0] = 2.000000000000000; + Xinv.v[1] = 1.000000000000000; + Xinv.v[2] = 0.000000000000000; + Xinv.v[3] = -1.000000000000000; + Xinv.v[4] = 0.000000000000000; + Xinv.v[5] = 2.000000000000000; + Xinv.v[6] = -1.000000000000000; + Xinv.v[7] = -1.000000000000000; + Xinv.v[8] = 1.000000000000000; + SST_Math_Mat33dCreateLULocal(&X); + TASSERT(fabs((X.v[0])-( 2.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"L:Entry A_a11 failed!"); + TASSERT(fabs((X.v[3])-( -0.500000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"U:Entry B_a12 failed!"); + TASSERT(fabs((X.v[6])-( -0.500000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"U:Entry B_a13 failed!"); + TASSERT(fabs((X.v[1])-( 1.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"L:Entry A_a21 failed!"); + TASSERT(fabs((X.v[4])-( 0.500000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"L:Entry A_a22 failed!"); + TASSERT(fabs((X.v[7])-( -1.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"U:Entry B_a23 failed!"); + TASSERT(fabs((X.v[2])-( 0.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"L:Entry A_a31 failed!"); + TASSERT(fabs((X.v[5])-( 2.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"L:Entry A_a32 failed!"); + TASSERT(fabs((X.v[8])-( 3.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"L:Entry A_a33 failed!"); + SST_Math_Mat33dApplyLUMatLocal(&X,&Xinv); + TASSERT(fabs((Xinv.v[0])-( 1.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Xinv:Entry Xinv_a11 failed!"); + TASSERT(fabs((Xinv.v[1])-( 0.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Xinv:Entry Xinv_a21 failed!"); + TASSERT(fabs((Xinv.v[2])-( 0.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Xinv:Entry Xinv_a31 failed!"); + TASSERT(fabs((Xinv.v[3])-( 0.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Xinv:Entry Xinv_a12 failed!"); + TASSERT(fabs((Xinv.v[4])-( 1.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Xinv:Entry Xinv_a22 failed!"); + TASSERT(fabs((Xinv.v[5])-( 0.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Xinv:Entry Xinv_a32 failed!"); + TASSERT(fabs((Xinv.v[6])-( 0.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Xinv:Entry Xinv_a13 failed!"); + TASSERT(fabs((Xinv.v[7])-( 0.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Xinv:Entry Xinv_a23 failed!"); + TASSERT(fabs((Xinv.v[8])-( 1.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Xinv:Entry Xinv_a33 failed!"); + return ZTEST_SUCCESS; +} +static const char* testSST_Math_Mat33dApplyLUVec(){ + SST_Mat33d X; /* 3 x 3 matrix */ + SST_Mat33d LU; /* 3 x 3 matrix */ + SST_Vec3d b; /* 3 x 3 vector */ + SST_Vec3d x; /* 3 x 3 vector */ + X.v[0] = 2.000000000000000; + X.v[1] = 1.000000000000000; + X.v[2] = 0.000000000000000; + X.v[3] = -1.000000000000000; + X.v[4] = 0.000000000000000; + X.v[5] = 2.000000000000000; + X.v[6] = -1.000000000000000; + X.v[7] = -1.000000000000000; + X.v[8] = 1.000000000000000; + b.v[0] = 2.000000000000000; + b.v[1] = -1.000000000000000; + b.v[2] = 1.000000000000000; + SST_Math_Mat33dCreateLU(&X,&LU); + SST_Math_Mat33dApplyLUVec(&LU,&b,&x); + TASSERT(fabs((x.v[0])-( 2.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"x:Entry x_a1 failed!"); + TASSERT(fabs((x.v[1])-( -1.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"x:Entry x_a2 failed!"); + TASSERT(fabs((x.v[2])-( 3.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"x:Entry x_a3 failed!"); + return ZTEST_SUCCESS; +} +static const char* testSST_Math_Mat33dApplyLUVecLocal(){ + SST_Mat33d X; /* 3 x 3 matrix */ + SST_Mat33d LU; /* 3 x 3 matrix */ + SST_Vec3d b; /* 3 x 3 vector */ + X.v[0] = 2.000000000000000; + X.v[1] = 1.000000000000000; + X.v[2] = 0.000000000000000; + X.v[3] = -1.000000000000000; + X.v[4] = 0.000000000000000; + X.v[5] = 2.000000000000000; + X.v[6] = -1.000000000000000; + X.v[7] = -1.000000000000000; + X.v[8] = 1.000000000000000; + b.v[0] = 2.000000000000000; + b.v[1] = -1.000000000000000; + b.v[2] = 1.000000000000000; + SST_Math_Mat33dCreateLU(&X,&LU); + SST_Math_Mat33dApplyLUVecLocal(&LU,&b); + TASSERT(fabs((b.v[0])-( 2.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"x:Entry x_a1 failed!"); + TASSERT(fabs((b.v[1])-( -1.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"x:Entry x_a2 failed!"); + TASSERT(fabs((b.v[2])-( 3.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"x:Entry x_a3 failed!"); + return ZTEST_SUCCESS; +} diff --git a/ZTestSuite/Test-SST_Mat33f.cpp b/ZTestSuite/Test-SST_Mat33f.cpp new file mode 100644 index 0000000..8fd301f --- /dev/null +++ b/ZTestSuite/Test-SST_Mat33f.cpp @@ -0,0 +1,1002 @@ +/* + AUTOMATICALLY GENERATED FILE - DO NOT EDIT! + Please change MatrixNxN.py and re-run it +*/ +/* Generated with ./MatrixNxN.py n = 3, TYPE = float */ + +#include "ZUnitTest.hpp" +#include <float.h> +#include <math.h> +#include <stdlib.h> +#include <stdio.h> +#include <SST/SST_Mat33.h> +#include <SST/SST_Vec3.h> + + + + +static const char* testSST_Math_Mat33fAdd(); +static const char* testSST_Math_Mat33fAddLocal(); +static const char* testSST_Math_Mat33fSubtract(); +static const char* testSST_Math_Mat33fSubtractLocal(); +static const char* testSST_Math_Mat33fMultiplyElementwise(); +static const char* testSST_Math_Mat33fMultiplyElementwiseLocal(); +static const char* testSST_Math_Mat33fMultiplyScalar(); +static const char* testSST_Math_Mat33fMultiplyScalarLocal(); +static const char* testSST_Math_Mat33fMultiplyMatrix(); +static const char* testSST_Math_Mat33fMultiplyMatrixLocal(); +static const char* testSST_Math_Mat33fMultiplyVector(); +static const char* testSST_Math_Mat33fMultiplyVectorLocal(); +static const char* testSST_Math_Mat33fTranspose(); +static const char* testSST_Math_Mat33fTransposeLocal(); +static const char* testSST_Math_Mat33fDeterminant(); +static const char* testSST_Math_Mat33fCheckOrthonormal(); +static const char* testSST_Math_Mat33fInvert(); +static const char* testSST_Math_Mat33fInvertLocal(); +static const char* testSST_Math_Mat33fCreateLU(); +static const char* testSST_Math_Mat33fCreateLULocal(); +static const char* testSST_Math_Mat33fApplyLUMat(); +static const char* testSST_Math_Mat33fApplyLUMatLocal(); +static const char* testSST_Math_Mat33fApplyLUVec(); +static const char* testSST_Math_Mat33fApplyLUVecLocal(); +// List of unit tests +ZUnitTest SST_Math_Mat33fUnitTests[] = +{ +{ "testSST_Math_Mat33fAdd " , testSST_Math_Mat33fAdd }, +{ "testSST_Math_Mat33fAddLocal " , testSST_Math_Mat33fAddLocal }, +{ "testSST_Math_Mat33fSubtract " , testSST_Math_Mat33fSubtract }, +{ "testSST_Math_Mat33fSubtractLocal " , testSST_Math_Mat33fSubtractLocal }, +{ "testSST_Math_Mat33fMultiplyElementwise " , testSST_Math_Mat33fMultiplyElementwise }, +{ "testSST_Math_Mat33fMultiplyElementwiseLocal " , testSST_Math_Mat33fMultiplyElementwiseLocal }, +{ "testSST_Math_Mat33fMultiplyScalar " , testSST_Math_Mat33fMultiplyScalar }, +{ "testSST_Math_Mat33fMultiplyScalarLocal " , testSST_Math_Mat33fMultiplyScalarLocal }, +{ "testSST_Math_Mat33fMultiplyMatrix " , testSST_Math_Mat33fMultiplyMatrix }, +{ "testSST_Math_Mat33fMultiplyMatrixLocal " , testSST_Math_Mat33fMultiplyMatrixLocal }, +{ "testSST_Math_Mat33fMultiplyVector " , testSST_Math_Mat33fMultiplyVector }, +{ "testSST_Math_Mat33fMultiplyVectorLocal " , testSST_Math_Mat33fMultiplyVectorLocal }, +{ "testSST_Math_Mat33fDeterminant " , testSST_Math_Mat33fDeterminant }, +{ "testSST_Math_Mat33fCheckOrthonormal " , testSST_Math_Mat33fCheckOrthonormal }, +{ "testSST_Math_Mat33fInvert " , testSST_Math_Mat33fInvert }, +{ "testSST_Math_Mat33fInvertLocal " , testSST_Math_Mat33fInvertLocal }, +{ "testSST_Math_Mat33fCreateLU " , testSST_Math_Mat33fCreateLU }, +{ "testSST_Math_Mat33fCreateLULocal " , testSST_Math_Mat33fCreateLULocal }, +{ "testSST_Math_Mat33fApplyLUMat " , testSST_Math_Mat33fApplyLUMat }, +{ "testSST_Math_Mat33fApplyLUMatLocal " , testSST_Math_Mat33fApplyLUMatLocal }, +{ "testSST_Math_Mat33fApplyLUVec " , testSST_Math_Mat33fApplyLUVec }, +{ "testSST_Math_Mat33fApplyLUVecLocal " , testSST_Math_Mat33fApplyLUVecLocal }, +{ "testSST_Math_Mat33fTranspose " , testSST_Math_Mat33fTranspose }, +{ "testSST_Math_Mat33fTransposeLocal " , testSST_Math_Mat33fTransposeLocal } +}; +DECLARE_ZTESTBLOCK(SST_Math_Mat33f) + +/******************************************************************************/ + +static const char* testSST_Math_Mat33fAdd(){ + SST_Mat33f X; /* 3 x 3 matrix */ + SST_Mat33f Y; /* 3 x 3 matrix */ + SST_Mat33f A; /* 3 x 3 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = 4.000000f; + X.v[1] = -13.000000f; + X.v[2] = 19.000000f; + X.v[3] = 16.000000f; + X.v[4] = -3.000000f; + X.v[5] = 8.000000f; + X.v[6] = 9.000000f; + X.v[7] = -4.000000f; + X.v[8] = 2.000000f; + Y.v[0] = -14.000000f; + Y.v[1] = -17.000000f; + Y.v[2] = 1.000000f; + Y.v[3] = 7.000000f; + Y.v[4] = 19.000000f; + Y.v[5] = -16.000000f; + Y.v[6] = -16.000000f; + Y.v[7] = -5.000000f; + Y.v[8] = -7.000000f; +/* +[[ 4. 16. 9.] + [-13. -3. -4.] + [ 19. 8. 2.]] +[[-14. 7. -16.] + [-17. 19. -5.] + [ 1. -16. -7.]] +[[-10. 23. -7.] + [-30. 16. -9.] + [ 20. -8. -5.]] +*/ + SST_Math_Mat33fAdd(&X,&Y,&A); + TASSERT(fabsf((A.v[0])-(-10.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a11 failed!"); + TASSERT(fabsf((A.v[3])-(23.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a12 failed!"); + TASSERT(fabsf((A.v[6])-(-7.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a13 failed!"); + TASSERT(fabsf((A.v[1])-(-30.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a21 failed!"); + TASSERT(fabsf((A.v[4])-(16.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a22 failed!"); + TASSERT(fabsf((A.v[7])-(-9.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a23 failed!"); + TASSERT(fabsf((A.v[2])-(20.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a31 failed!"); + TASSERT(fabsf((A.v[5])-(-8.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a32 failed!"); + TASSERT(fabsf((A.v[8])-(-5.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a33 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat33fAddLocal(){ + SST_Mat33f X; /* 3 x 3 matrix */ + SST_Mat33f Y; /* 3 x 3 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = -8.000000f; + X.v[1] = 1.000000f; + X.v[2] = -3.000000f; + X.v[3] = 19.000000f; + X.v[4] = -13.000000f; + X.v[5] = 17.000000f; + X.v[6] = 18.000000f; + X.v[7] = 5.000000f; + X.v[8] = -1.000000f; + Y.v[0] = 4.000000f; + Y.v[1] = -18.000000f; + Y.v[2] = 16.000000f; + Y.v[3] = -11.000000f; + Y.v[4] = 8.000000f; + Y.v[5] = 10.000000f; + Y.v[6] = 17.000000f; + Y.v[7] = -18.000000f; + Y.v[8] = 3.000000f; +/* +[[ -8. 19. 18.] + [ 1. -13. 5.] + [ -3. 17. -1.]] +[[ 4. -11. 17.] + [-18. 8. -18.] + [ 16. 10. 3.]] +[[ -4. 8. 35.] + [-17. -5. -13.] + [ 13. 27. 2.]] +*/ + SST_Math_Mat33fAddLocal(&X,&Y); /* for accuracy */ + TASSERT(fabsf((X.v[0])-(-4.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a11 failed!"); + TASSERT(fabsf((X.v[3])-(8.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a12 failed!"); + TASSERT(fabsf((X.v[6])-(35.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a13 failed!"); + TASSERT(fabsf((X.v[1])-(-17.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a21 failed!"); + TASSERT(fabsf((X.v[4])-(-5.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a22 failed!"); + TASSERT(fabsf((X.v[7])-(-13.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a23 failed!"); + TASSERT(fabsf((X.v[2])-(13.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a31 failed!"); + TASSERT(fabsf((X.v[5])-(27.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a32 failed!"); + TASSERT(fabsf((X.v[8])-(2.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a33 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat33fSubtract(){ + SST_Mat33f X; /* 3 x 3 matrix */ + SST_Mat33f Y; /* 3 x 3 matrix */ + SST_Mat33f A; /* 3 x 3 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = 14.000000f; + X.v[1] = 7.000000f; + X.v[2] = -17.000000f; + X.v[3] = 15.000000f; + X.v[4] = -1.000000f; + X.v[5] = 11.000000f; + X.v[6] = -2.000000f; + X.v[7] = -10.000000f; + X.v[8] = 14.000000f; + Y.v[0] = 10.000000f; + Y.v[1] = 18.000000f; + Y.v[2] = 8.000000f; + Y.v[3] = -17.000000f; + Y.v[4] = -14.000000f; + Y.v[5] = -8.000000f; + Y.v[6] = 12.000000f; + Y.v[7] = -10.000000f; + Y.v[8] = 1.000000f; +/* +[[ 14. 15. -2.] + [ 7. -1. -10.] + [-17. 11. 14.]] +[[ 10. -17. 12.] + [ 18. -14. -10.] + [ 8. -8. 1.]] +[[ 4. 32. -14.] + [-11. 13. 0.] + [-25. 19. 13.]] +*/ + SST_Math_Mat33fSubtract(&X,&Y,&A); + TASSERT(fabsf((A.v[0])-(4.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a11 failed!"); + TASSERT(fabsf((A.v[3])-(32.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a12 failed!"); + TASSERT(fabsf((A.v[6])-(-14.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a13 failed!"); + TASSERT(fabsf((A.v[1])-(-11.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a21 failed!"); + TASSERT(fabsf((A.v[4])-(13.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a22 failed!"); + TASSERT(fabsf((A.v[7])-(0.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a23 failed!"); + TASSERT(fabsf((A.v[2])-(-25.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a31 failed!"); + TASSERT(fabsf((A.v[5])-(19.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a32 failed!"); + TASSERT(fabsf((A.v[8])-(13.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a33 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat33fSubtractLocal(){ + SST_Mat33f X; /* 3 x 3 matrix */ + SST_Mat33f Y; /* 3 x 3 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = -16.000000f; + X.v[1] = 15.000000f; + X.v[2] = -15.000000f; + X.v[3] = -7.000000f; + X.v[4] = 19.000000f; + X.v[5] = 3.000000f; + X.v[6] = -12.000000f; + X.v[7] = 4.000000f; + X.v[8] = -11.000000f; + Y.v[0] = 2.000000f; + Y.v[1] = -20.000000f; + Y.v[2] = 1.000000f; + Y.v[3] = 10.000000f; + Y.v[4] = -10.000000f; + Y.v[5] = 17.000000f; + Y.v[6] = 0.000000f; + Y.v[7] = -20.000000f; + Y.v[8] = -18.000000f; +/* +[[-16. -7. -12.] + [ 15. 19. 4.] + [-15. 3. -11.]] +[[ 2. 10. 0.] + [-20. -10. -20.] + [ 1. 17. -18.]] +[[-18. -17. -12.] + [ 35. 29. 24.] + [-16. -14. 7.]] +*/ + SST_Math_Mat33fSubtractLocal(&X,&Y); /* for accuracy */ + TASSERT(fabsf((X.v[0])-(-18.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a11 failed!"); + TASSERT(fabsf((X.v[3])-(-17.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a12 failed!"); + TASSERT(fabsf((X.v[6])-(-12.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a13 failed!"); + TASSERT(fabsf((X.v[1])-(35.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a21 failed!"); + TASSERT(fabsf((X.v[4])-(29.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a22 failed!"); + TASSERT(fabsf((X.v[7])-(24.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a23 failed!"); + TASSERT(fabsf((X.v[2])-(-16.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a31 failed!"); + TASSERT(fabsf((X.v[5])-(-14.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a32 failed!"); + TASSERT(fabsf((X.v[8])-(7.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a33 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat33fMultiplyElementwise(){ + SST_Mat33f X; /* 3 x 3 matrix */ + SST_Mat33f Y; /* 3 x 3 matrix */ + SST_Mat33f A; /* 3 x 3 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = -13.000000f; + X.v[1] = -17.000000f; + X.v[2] = -10.000000f; + X.v[3] = 13.000000f; + X.v[4] = 4.000000f; + X.v[5] = 1.000000f; + X.v[6] = -1.000000f; + X.v[7] = 4.000000f; + X.v[8] = -8.000000f; + Y.v[0] = 11.000000f; + Y.v[1] = 9.000000f; + Y.v[2] = 4.000000f; + Y.v[3] = 3.000000f; + Y.v[4] = -6.000000f; + Y.v[5] = -11.000000f; + Y.v[6] = -6.000000f; + Y.v[7] = 14.000000f; + Y.v[8] = 17.000000f; +/* +[[-13. 13. -1.] + [-17. 4. 4.] + [-10. 1. -8.]] +[[ 11. 3. -6.] + [ 9. -6. 14.] + [ 4. -11. 17.]] +[[-143. 39. 6.] + [-153. -24. 56.] + [ -40. -11. -136.]] +*/ + SST_Math_Mat33fMultiplyElementwise(&X, &Y, &A); + TASSERT(fabsf((A.v[0])-(-143.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a11 failed!"); + TASSERT(fabsf((A.v[3])-(39.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a12 failed!"); + TASSERT(fabsf((A.v[6])-(6.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a13 failed!"); + TASSERT(fabsf((A.v[1])-(-153.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a21 failed!"); + TASSERT(fabsf((A.v[4])-(-24.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a22 failed!"); + TASSERT(fabsf((A.v[7])-(56.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a23 failed!"); + TASSERT(fabsf((A.v[2])-(-40.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a31 failed!"); + TASSERT(fabsf((A.v[5])-(-11.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a32 failed!"); + TASSERT(fabsf((A.v[8])-(-136.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a33 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat33fMultiplyElementwiseLocal(){ + SST_Mat33f X; /* 3 x 3 matrix */ + SST_Mat33f Y; /* 3 x 3 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = 3.000000f; + X.v[1] = -19.000000f; + X.v[2] = 9.000000f; + X.v[3] = 4.000000f; + X.v[4] = -8.000000f; + X.v[5] = -7.000000f; + X.v[6] = -16.000000f; + X.v[7] = 8.000000f; + X.v[8] = 0.000000f; + Y.v[0] = 1.000000f; + Y.v[1] = 0.000000f; + Y.v[2] = -9.000000f; + Y.v[3] = -6.000000f; + Y.v[4] = -7.000000f; + Y.v[5] = -2.000000f; + Y.v[6] = 17.000000f; + Y.v[7] = 19.000000f; + Y.v[8] = -16.000000f; +/* +[[ 3. 4. -16.] + [-19. -8. 8.] + [ 9. -7. 0.]] +[[ 1. -6. 17.] + [ 0. -7. 19.] + [ -9. -2. -16.]] +[[ 3. -24. -272.] + [ -0. 56. 152.] + [ -81. 14. -0.]] +*/ + SST_Math_Mat33fMultiplyElementwiseLocal(&X,&Y); + TASSERT(fabsf((X.v[0])-(3.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a11 failed!"); + TASSERT(fabsf((X.v[3])-(-24.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a12 failed!"); + TASSERT(fabsf((X.v[6])-(-272.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a13 failed!"); + TASSERT(fabsf((X.v[1])-(-0.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a21 failed!"); + TASSERT(fabsf((X.v[4])-(56.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a22 failed!"); + TASSERT(fabsf((X.v[7])-(152.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a23 failed!"); + TASSERT(fabsf((X.v[2])-(-81.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a31 failed!"); + TASSERT(fabsf((X.v[5])-(14.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a32 failed!"); + TASSERT(fabsf((X.v[8])-(-0.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a33 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat33fMultiplyScalar(){ + SST_Mat33f X; /* 3 x 3 matrix */ + SST_Mat33f A; /* 3 x 3 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = -9.000000f; + X.v[1] = -10.000000f; + X.v[2] = 19.000000f; + X.v[3] = -15.000000f; + X.v[4] = 6.000000f; + X.v[5] = -8.000000f; + X.v[6] = -13.000000f; + X.v[7] = 7.000000f; + X.v[8] = 15.000000f; +/* +[[ -9. -15. -13.] + [-10. 6. 7.] + [ 19. -8. 15.]] +[[-18. -30. -26.] + [-20. 12. 14.] + [ 38. -16. 30.]] +*/ + SST_Math_Mat33fMultiplyScalar(&X,2.000000f,&A); + TASSERT(fabsf((A.v[0])-(-18.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a11 failed!"); + TASSERT(fabsf((A.v[3])-(-30.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a12 failed!"); + TASSERT(fabsf((A.v[6])-(-26.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a13 failed!"); + TASSERT(fabsf((A.v[1])-(-20.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a21 failed!"); + TASSERT(fabsf((A.v[4])-(12.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a22 failed!"); + TASSERT(fabsf((A.v[7])-(14.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a23 failed!"); + TASSERT(fabsf((A.v[2])-(38.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a31 failed!"); + TASSERT(fabsf((A.v[5])-(-16.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a32 failed!"); + TASSERT(fabsf((A.v[8])-(30.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a33 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat33fMultiplyScalarLocal(){ + SST_Mat33f X; /* 3 x 3 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = 4.000000f; + X.v[1] = 9.000000f; + X.v[2] = 1.000000f; + X.v[3] = -7.000000f; + X.v[4] = 15.000000f; + X.v[5] = 17.000000f; + X.v[6] = 12.000000f; + X.v[7] = -2.000000f; + X.v[8] = 11.000000f; +/* +[[ 4. -7. 12.] + [ 9. 15. -2.] + [ 1. 17. 11.]] +[[ 8. -14. 24.] + [ 18. 30. -4.] + [ 2. 34. 22.]] +*/ + SST_Math_Mat33fMultiplyScalarLocal(&X,2.000000f); + TASSERT(fabsf((X.v[0])-(8.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a11 failed!"); + TASSERT(fabsf((X.v[3])-(-14.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a12 failed!"); + TASSERT(fabsf((X.v[6])-(24.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a13 failed!"); + TASSERT(fabsf((X.v[1])-(18.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a21 failed!"); + TASSERT(fabsf((X.v[4])-(30.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a22 failed!"); + TASSERT(fabsf((X.v[7])-(-4.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a23 failed!"); + TASSERT(fabsf((X.v[2])-(2.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a31 failed!"); + TASSERT(fabsf((X.v[5])-(34.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a32 failed!"); + TASSERT(fabsf((X.v[8])-(22.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a33 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat33fMultiplyMatrix(){ + SST_Mat33f X; /* 3 x 3 matrix */ + SST_Mat33f Y; /* 3 x 3 matrix */ + SST_Mat33f A; /* 3 x 3 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = 10.000000f; + X.v[1] = -19.000000f; + X.v[2] = -19.000000f; + X.v[3] = 2.000000f; + X.v[4] = 18.000000f; + X.v[5] = -5.000000f; + X.v[6] = 9.000000f; + X.v[7] = -2.000000f; + X.v[8] = 4.000000f; + Y.v[0] = -20.000000f; + Y.v[1] = -18.000000f; + Y.v[2] = -7.000000f; + Y.v[3] = 18.000000f; + Y.v[4] = 15.000000f; + Y.v[5] = -11.000000f; + Y.v[6] = 15.000000f; + Y.v[7] = -13.000000f; + Y.v[8] = 3.000000f; +/* +X +[[ 10. 2. 9.] + [-19. 18. -2.] + [-19. -5. 4.]] +Y +[[-20. 18. 15.] + [-18. 15. -13.] + [ -7. -11. 3.]] +[[-299. 111. 151.] + [ 70. -50. -525.] + [ 442. -461. -208.]] +*/ + SST_Math_Mat33fMultiplyMatrix(&X,&Y,&A); + TASSERT(fabsf((A.v[0])-(-299.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a11 failed!"); + TASSERT(fabsf((A.v[3])-(111.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a12 failed!"); + TASSERT(fabsf((A.v[6])-(151.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a13 failed!"); + TASSERT(fabsf((A.v[1])-(70.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a21 failed!"); + TASSERT(fabsf((A.v[4])-(-50.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a22 failed!"); + TASSERT(fabsf((A.v[7])-(-525.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a23 failed!"); + TASSERT(fabsf((A.v[2])-(442.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a31 failed!"); + TASSERT(fabsf((A.v[5])-(-461.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a32 failed!"); + TASSERT(fabsf((A.v[8])-(-208.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a33 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat33fMultiplyMatrixLocal(){ + SST_Mat33f X; /* 3 x 3 matrix */ + SST_Mat33f Y; /* 3 x 3 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = -16.000000f; + X.v[1] = -13.000000f; + X.v[2] = 3.000000f; + X.v[3] = -2.000000f; + X.v[4] = -15.000000f; + X.v[5] = -13.000000f; + X.v[6] = -7.000000f; + X.v[7] = 7.000000f; + X.v[8] = 13.000000f; + Y.v[0] = -18.000000f; + Y.v[1] = -11.000000f; + Y.v[2] = -11.000000f; + Y.v[3] = -20.000000f; + Y.v[4] = -7.000000f; + Y.v[5] = 3.000000f; + Y.v[6] = 6.000000f; + Y.v[7] = 2.000000f; + Y.v[8] = -15.000000f; +/* +X +[[-16. -2. -7.] + [-13. -15. 7.] + [ 3. -13. 13.]] +Y +[[-18. -20. 6.] + [-11. -7. 2.] + [-11. 3. -15.]] +X +[[ 387. 313. 5.] + [ 322. 386. -213.] + [ -54. 70. -203.]] +*/ + SST_Math_Mat33fMultiplyMatrixLocal(&X,&Y); + TASSERT(fabsf((X.v[0])-(387.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a11 failed!"); + TASSERT(fabsf((X.v[3])-(313.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a12 failed!"); + TASSERT(fabsf((X.v[6])-(5.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a13 failed!"); + TASSERT(fabsf((X.v[1])-(322.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a21 failed!"); + TASSERT(fabsf((X.v[4])-(386.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a22 failed!"); + TASSERT(fabsf((X.v[7])-(-213.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a23 failed!"); + TASSERT(fabsf((X.v[2])-(-54.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a31 failed!"); + TASSERT(fabsf((X.v[5])-(70.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a32 failed!"); + TASSERT(fabsf((X.v[8])-(-203.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a33 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat33fMultiplyVector(){ + SST_Mat33f X; /* 3 x 3 matrix */ + SST_Vec3f v; /* 3 vector */ + SST_Vec3f w; /* 3 vector */ +/* Resetting test vectors / mats */ + v.v[0] = 7.000000f; + v.v[1] = -1.000000f; + v.v[2] = 16.000000f; + X.v[0] = 3.000000f; + X.v[1] = -5.000000f; + X.v[2] = 6.000000f; + X.v[3] = -12.000000f; + X.v[4] = -11.000000f; + X.v[5] = -12.000000f; + X.v[6] = -19.000000f; + X.v[7] = -13.000000f; + X.v[8] = 7.000000f; +/* +X +[[ 3. -12. -19.] + [ -5. -11. -13.] + [ 6. -12. 7.]] +v +[ 7. -1. 16.] +w +[-271. -232. 166.] +*/ + SST_Math_Mat33fMultiplyVector(&X,&v,&w); + TASSERT(fabsf((w.v[0])-(-271.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry .v[0] failed!"); + TASSERT(fabsf((w.v[1])-(-232.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry .v[1] failed!"); + TASSERT(fabsf((w.v[2])-(166.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry .v[2] failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat33fMultiplyVectorLocal(){ + SST_Mat33f X; /* 3 x 3 matrix */ + SST_Vec3f v; /* 3 vector */ +/* Resetting test vectors / mats */ + v.v[0] = 14.000000f; + v.v[1] = 17.000000f; + v.v[2] = 17.000000f; + X.v[0] = 5.000000f; + X.v[1] = -20.000000f; + X.v[2] = -1.000000f; + X.v[3] = 10.000000f; + X.v[4] = 14.000000f; + X.v[5] = 8.000000f; + X.v[6] = 0.000000f; + X.v[7] = 19.000000f; + X.v[8] = 5.000000f; +/* +X +[[ 5. 10. 0.] + [-20. 14. 19.] + [ -1. 8. 5.]] +v +[ 14. 17. 17.] +v +[ 240. 281. 207.] +*/ + SST_Math_Mat33fMultiplyVectorLocal(&X,&v); + TASSERT(fabsf((v.v[0])-(240.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry .v[0] failed!"); + TASSERT(fabsf((v.v[1])-(281.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry .v[1] failed!"); + TASSERT(fabsf((v.v[2])-(207.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry .v[2] failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat33fTranspose(){ + SST_Mat33f X; /* 3 x 3 matrix */ + SST_Mat33f A; /* 3 x 3 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = 0.000000f; + X.v[1] = -14.000000f; + X.v[2] = 2.000000f; + X.v[3] = -15.000000f; + X.v[4] = 4.000000f; + X.v[5] = 14.000000f; + X.v[6] = 13.000000f; + X.v[7] = -5.000000f; + X.v[8] = 4.000000f; + SST_Math_Mat33fTranspose(&X,&A); + TASSERT(fabsf((A.v[0])-(0.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a11 failed!"); + TASSERT(fabsf((A.v[3])-(-14.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a12 failed!"); + TASSERT(fabsf((A.v[6])-(2.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a13 failed!"); + TASSERT(fabsf((A.v[1])-(-15.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a21 failed!"); + TASSERT(fabsf((A.v[4])-(4.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a22 failed!"); + TASSERT(fabsf((A.v[7])-(14.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a23 failed!"); + TASSERT(fabsf((A.v[2])-(13.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a31 failed!"); + TASSERT(fabsf((A.v[5])-(-5.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a32 failed!"); + TASSERT(fabsf((A.v[8])-(4.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a33 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat33fTransposeLocal(){ + SST_Mat33f X; /* 3 x 3 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = -6.000000f; + X.v[1] = -14.000000f; + X.v[2] = 12.000000f; + X.v[3] = -19.000000f; + X.v[4] = 14.000000f; + X.v[5] = 17.000000f; + X.v[6] = -14.000000f; + X.v[7] = -10.000000f; + X.v[8] = 11.000000f; + SST_Math_Mat33fTransposeLocal(&X); + TASSERT(fabsf((X.v[0])-(-6.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a11 failed!"); + TASSERT(fabsf((X.v[3])-(-14.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a12 failed!"); + TASSERT(fabsf((X.v[6])-(12.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a13 failed!"); + TASSERT(fabsf((X.v[1])-(-19.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a21 failed!"); + TASSERT(fabsf((X.v[4])-(14.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a22 failed!"); + TASSERT(fabsf((X.v[7])-(17.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a23 failed!"); + TASSERT(fabsf((X.v[2])-(-14.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a31 failed!"); + TASSERT(fabsf((X.v[5])-(-10.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a32 failed!"); + TASSERT(fabsf((X.v[8])-(11.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a33 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat33fCheckOrthonormal(){ + SST_Mat33f X; /* 3 x 3 matrix */ + SST_Mat33f Y; /* 3 x 3 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = 11.000000f; + X.v[1] = -18.000000f; + X.v[2] = 18.000000f; + X.v[3] = 11.000000f; + X.v[4] = 17.000000f; + X.v[5] = 9.000000f; + X.v[6] = 7.000000f; + X.v[7] = 0.000000f; + X.v[8] = -10.000000f; + Y.v[0] = -20.000000f; + Y.v[1] = -5.000000f; + Y.v[2] = 10.000000f; + Y.v[3] = 14.000000f; + Y.v[4] = -11.000000f; + Y.v[5] = -2.000000f; + Y.v[6] = -10.000000f; + Y.v[7] = 9.000000f; + Y.v[8] = 6.000000f; +/* +[[-0.39667013 -0.5116291 -0.76216042] + [ 0.64909661 -0.7434243 0.16122624] + [-0.64909661 -0.43076208 0.62699091]] +[[ 1.00000000e+00 -2.98023224e-08 -2.98023224e-08] + [ -2.98023224e-08 1.00000000e+00 2.98023224e-08] + [ -2.98023224e-08 2.98023224e-08 1.00000000e+00]] +*/ +/* Set X to orthogonal matrix Q */ + X.v[0] = (float)-0.396670f; + X.v[1] = (float)0.649097f; + X.v[2] = (float)-0.649097f; + X.v[3] = (float)-0.511629f; + X.v[4] = (float)-0.743424f; + X.v[5] = (float)-0.430762f; + X.v[6] = (float)-0.762160f; + X.v[7] = (float)0.161226f; + X.v[8] = (float)0.626991f; +/* Check Positive Test */ + TASSERT(SST_Math_Mat33fCheckOrthonormal(&X),"CheckOrthonormal failed when it should have passed"); +/* Check Negative Test */ + TASSERT(!SST_Math_Mat33fCheckOrthonormal(&Y),"CheckOrthonormal succeeded when it should have failed"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat33fDeterminant(){ + SST_Mat33f X; /* 3 x 3 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = -8.000000f; + X.v[1] = -11.000000f; + X.v[2] = 15.000000f; + X.v[3] = -1.000000f; + X.v[4] = 1.000000f; + X.v[5] = -3.000000f; + X.v[6] = 4.000000f; + X.v[7] = -11.000000f; + X.v[8] = 19.000000f; +/* det(X) = +140.0 + */ + float result = SST_Math_Mat33fDeterminant(&X); + TASSERT(fabsf( (result)/(140.000000f) - 1.000000f ) <= 100*FLT_EPSILON,"Determinant failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat33fInvert(){ + SST_Mat33f X; /* 3 x 3 matrix */ + SST_Mat33f B; /* 3 x 3 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = -16.000000f; + X.v[1] = 7.000000f; + X.v[2] = -12.000000f; + X.v[3] = -14.000000f; + X.v[4] = 0.000000f; + X.v[5] = -10.000000f; + X.v[6] = 19.000000f; + X.v[7] = 10.000000f; + X.v[8] = -4.000000f; +/* +[[-0.06090134 0.1498173 0.08526187] + [ 0.05602923 -0.17783192 -0.17844093] + [ 0.04263094 -0.00487211 -0.05968331]] +*/ + SST_Math_Mat33fInvert(&X,&B); + TASSERT(fabsf((B.v[0])-(-0.060901f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a11 failed!"); + TASSERT(fabsf((B.v[1])-(0.056029f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a21 failed!"); + TASSERT(fabsf((B.v[2])-(0.042631f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a31 failed!"); + TASSERT(fabsf((B.v[3])-(0.149817f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a12 failed!"); + TASSERT(fabsf((B.v[4])-(-0.177832f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a22 failed!"); + TASSERT(fabsf((B.v[5])-(-0.004872f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a32 failed!"); + TASSERT(fabsf((B.v[6])-(0.085262f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a13 failed!"); + TASSERT(fabsf((B.v[7])-(-0.178441f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a23 failed!"); + TASSERT(fabsf((B.v[8])-(-0.059683f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a33 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat33fInvertLocal(){ + SST_Mat33f X; /* 3 x 3 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = 13.000000f; + X.v[1] = -16.000000f; + X.v[2] = 2.000000f; + X.v[3] = 15.000000f; + X.v[4] = -3.000000f; + X.v[5] = -8.000000f; + X.v[6] = -18.000000f; + X.v[7] = 15.000000f; + X.v[8] = -5.000000f; +/* +() +[[-0.09594883 -0.15565032 -0.12153518] + [ 0.0355366 0.02061123 -0.06609808] + [-0.0952381 -0.0952381 -0.14285715]] +*/ + SST_Math_Mat33fInvertLocal(&X); + TASSERT(fabsf((X.v[0])-(-0.095949f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a11 failed!"); + TASSERT(fabsf((X.v[1])-(0.035537f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a21 failed!"); + TASSERT(fabsf((X.v[2])-(-0.095238f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a31 failed!"); + TASSERT(fabsf((X.v[3])-(-0.155650f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a12 failed!"); + TASSERT(fabsf((X.v[4])-(0.020611f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a22 failed!"); + TASSERT(fabsf((X.v[5])-(-0.095238f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a32 failed!"); + TASSERT(fabsf((X.v[6])-(-0.121535f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a13 failed!"); + TASSERT(fabsf((X.v[7])-(-0.066098f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a23 failed!"); + TASSERT(fabsf((X.v[8])-(-0.142857f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a33 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat33fCreateLU(){ + SST_Mat33f X; /* 3 x 3 matrix */ + SST_Mat33f LU; /* 3 x 3 matrix */ + X.v[0] = 2.000000f; + X.v[1] = 1.000000f; + X.v[2] = 0.000000f; + X.v[3] = -1.000000f; + X.v[4] = 0.000000f; + X.v[5] = 2.000000f; + X.v[6] = -1.000000f; + X.v[7] = -1.000000f; + X.v[8] = 1.000000f; + SST_Math_Mat33fCreateLU(&X,&LU); +/* +[[ 2 -1 -1] + [ 1 0 -1] + [ 0 2 1]] +*/ +/* +[[ 2. 0. 0. ] + [ 1. 0.5 0. ] + [ 0. 2. 3. ]] +*/ +/* +[[ 1. -0.5 -0.5] + [ 0. 1. -1. ] + [ 0. 0. 1. ]] +*/ + TASSERT(fabsf((LU.v[0])-(2.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"L:Entry A_a11 failed!"); + TASSERT(fabsf((LU.v[3])-(-0.500000f)) <=100*FLT_EPSILON /* yes this is bad */,"U:Entry B_a12 failed!"); + TASSERT(fabsf((LU.v[6])-(-0.500000f)) <=100*FLT_EPSILON /* yes this is bad */,"U:Entry B_a13 failed!"); + TASSERT(fabsf((LU.v[1])-(1.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"L:Entry A_a21 failed!"); + TASSERT(fabsf((LU.v[4])-(0.500000f)) <=100*FLT_EPSILON /* yes this is bad */,"L:Entry A_a22 failed!"); + TASSERT(fabsf((LU.v[7])-(-1.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"U:Entry B_a23 failed!"); + TASSERT(fabsf((LU.v[2])-(0.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"L:Entry A_a31 failed!"); + TASSERT(fabsf((LU.v[5])-(2.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"L:Entry A_a32 failed!"); + TASSERT(fabsf((LU.v[8])-(3.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"L:Entry A_a33 failed!"); + return ZTEST_SUCCESS; +} +static const char* testSST_Math_Mat33fCreateLULocal(){ + SST_Mat33f X; /* 3 x 3 matrix */ + X.v[0] = 2.000000f; + X.v[1] = 1.000000f; + X.v[2] = 0.000000f; + X.v[3] = -1.000000f; + X.v[4] = 0.000000f; + X.v[5] = 2.000000f; + X.v[6] = -1.000000f; + X.v[7] = -1.000000f; + X.v[8] = 1.000000f; + SST_Math_Mat33fCreateLULocal(&X); + TASSERT(fabsf((X.v[0])-(2.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"L:Entry A_a11 failed!"); + TASSERT(fabsf((X.v[3])-(-0.500000f)) <=100*FLT_EPSILON /* yes this is bad */,"U:Entry B_a12 failed!"); + TASSERT(fabsf((X.v[6])-(-0.500000f)) <=100*FLT_EPSILON /* yes this is bad */,"U:Entry B_a13 failed!"); + TASSERT(fabsf((X.v[1])-(1.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"L:Entry A_a21 failed!"); + TASSERT(fabsf((X.v[4])-(0.500000f)) <=100*FLT_EPSILON /* yes this is bad */,"L:Entry A_a22 failed!"); + TASSERT(fabsf((X.v[7])-(-1.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"U:Entry B_a23 failed!"); + TASSERT(fabsf((X.v[2])-(0.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"L:Entry A_a31 failed!"); + TASSERT(fabsf((X.v[5])-(2.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"L:Entry A_a32 failed!"); + TASSERT(fabsf((X.v[8])-(3.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"L:Entry A_a33 failed!"); + return ZTEST_SUCCESS; +} +static const char* testSST_Math_Mat33fApplyLUMat(){ + SST_Mat33f X; /* 3 x 3 matrix */ + SST_Mat33f LU; /* 3 x 3 matrix */ + SST_Mat33f I; /* 3 x 3 matrix */ + X.v[0] = 2.000000f; + X.v[1] = 1.000000f; + X.v[2] = 0.000000f; + X.v[3] = -1.000000f; + X.v[4] = 0.000000f; + X.v[5] = 2.000000f; + X.v[6] = -1.000000f; + X.v[7] = -1.000000f; + X.v[8] = 1.000000f; + SST_Math_Mat33fCreateLU(&X,&LU); +/* +[[ 2 -1 -1] + [ 1 0 -1] + [ 0 2 1]] +*/ +/* +[[ 2. 0. 0. ] + [ 1. 0.5 0. ] + [ 0. 2. 3. ]] +*/ +/* +[[ 1. -0.5 -0.5] + [ 0. 1. -1. ] + [ 0. 0. 1. ]] +*/ + TASSERT(fabsf((LU.v[0])-(2.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"L:Entry A_a11 failed!"); + TASSERT(fabsf((LU.v[3])-(-0.500000f)) <=100*FLT_EPSILON /* yes this is bad */,"U:Entry B_a12 failed!"); + TASSERT(fabsf((LU.v[6])-(-0.500000f)) <=100*FLT_EPSILON /* yes this is bad */,"U:Entry B_a13 failed!"); + TASSERT(fabsf((LU.v[1])-(1.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"L:Entry A_a21 failed!"); + TASSERT(fabsf((LU.v[4])-(0.500000f)) <=100*FLT_EPSILON /* yes this is bad */,"L:Entry A_a22 failed!"); + TASSERT(fabsf((LU.v[7])-(-1.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"U:Entry B_a23 failed!"); + TASSERT(fabsf((LU.v[2])-(0.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"L:Entry A_a31 failed!"); + TASSERT(fabsf((LU.v[5])-(2.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"L:Entry A_a32 failed!"); + TASSERT(fabsf((LU.v[8])-(3.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"L:Entry A_a33 failed!"); + SST_Math_Mat33fApplyLUMat(&LU,&X,&I); + TASSERT(fabsf((I.v[0])-(1.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"I:Entry I_a11 failed!"); + TASSERT(fabsf((I.v[1])-(0.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"I:Entry I_a21 failed!"); + TASSERT(fabsf((I.v[2])-(0.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"I:Entry I_a31 failed!"); + TASSERT(fabsf((I.v[3])-(0.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"I:Entry I_a12 failed!"); + TASSERT(fabsf((I.v[4])-(1.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"I:Entry I_a22 failed!"); + TASSERT(fabsf((I.v[5])-(0.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"I:Entry I_a32 failed!"); + TASSERT(fabsf((I.v[6])-(0.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"I:Entry I_a13 failed!"); + TASSERT(fabsf((I.v[7])-(0.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"I:Entry I_a23 failed!"); + TASSERT(fabsf((I.v[8])-(1.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"I:Entry I_a33 failed!"); + return ZTEST_SUCCESS; +} +static const char* testSST_Math_Mat33fApplyLUMatLocal(){ + SST_Mat33f X; /* 3 x 3 matrix */ + SST_Mat33f Xinv; /* 3 x 3 matrix */ + X.v[0] = 2.000000f; + X.v[1] = 1.000000f; + X.v[2] = 0.000000f; + X.v[3] = -1.000000f; + X.v[4] = 0.000000f; + X.v[5] = 2.000000f; + X.v[6] = -1.000000f; + X.v[7] = -1.000000f; + X.v[8] = 1.000000f; + Xinv.v[0] = 2.000000f; + Xinv.v[1] = 1.000000f; + Xinv.v[2] = 0.000000f; + Xinv.v[3] = -1.000000f; + Xinv.v[4] = 0.000000f; + Xinv.v[5] = 2.000000f; + Xinv.v[6] = -1.000000f; + Xinv.v[7] = -1.000000f; + Xinv.v[8] = 1.000000f; + SST_Math_Mat33fCreateLULocal(&X); + TASSERT(fabsf((X.v[0])-(2.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"L:Entry A_a11 failed!"); + TASSERT(fabsf((X.v[3])-(-0.500000f)) <=100*FLT_EPSILON /* yes this is bad */,"U:Entry B_a12 failed!"); + TASSERT(fabsf((X.v[6])-(-0.500000f)) <=100*FLT_EPSILON /* yes this is bad */,"U:Entry B_a13 failed!"); + TASSERT(fabsf((X.v[1])-(1.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"L:Entry A_a21 failed!"); + TASSERT(fabsf((X.v[4])-(0.500000f)) <=100*FLT_EPSILON /* yes this is bad */,"L:Entry A_a22 failed!"); + TASSERT(fabsf((X.v[7])-(-1.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"U:Entry B_a23 failed!"); + TASSERT(fabsf((X.v[2])-(0.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"L:Entry A_a31 failed!"); + TASSERT(fabsf((X.v[5])-(2.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"L:Entry A_a32 failed!"); + TASSERT(fabsf((X.v[8])-(3.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"L:Entry A_a33 failed!"); + SST_Math_Mat33fApplyLUMatLocal(&X,&Xinv); + TASSERT(fabsf((Xinv.v[0])-(1.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Xinv:Entry Xinv_a11 failed!"); + TASSERT(fabsf((Xinv.v[1])-(0.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Xinv:Entry Xinv_a21 failed!"); + TASSERT(fabsf((Xinv.v[2])-(0.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Xinv:Entry Xinv_a31 failed!"); + TASSERT(fabsf((Xinv.v[3])-(0.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Xinv:Entry Xinv_a12 failed!"); + TASSERT(fabsf((Xinv.v[4])-(1.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Xinv:Entry Xinv_a22 failed!"); + TASSERT(fabsf((Xinv.v[5])-(0.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Xinv:Entry Xinv_a32 failed!"); + TASSERT(fabsf((Xinv.v[6])-(0.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Xinv:Entry Xinv_a13 failed!"); + TASSERT(fabsf((Xinv.v[7])-(0.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Xinv:Entry Xinv_a23 failed!"); + TASSERT(fabsf((Xinv.v[8])-(1.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Xinv:Entry Xinv_a33 failed!"); + return ZTEST_SUCCESS; +} +static const char* testSST_Math_Mat33fApplyLUVec(){ + SST_Mat33f X; /* 3 x 3 matrix */ + SST_Mat33f LU; /* 3 x 3 matrix */ + SST_Vec3f b; /* 3 x 3 vector */ + SST_Vec3f x; /* 3 x 3 vector */ + X.v[0] = 2.000000f; + X.v[1] = 1.000000f; + X.v[2] = 0.000000f; + X.v[3] = -1.000000f; + X.v[4] = 0.000000f; + X.v[5] = 2.000000f; + X.v[6] = -1.000000f; + X.v[7] = -1.000000f; + X.v[8] = 1.000000f; + b.v[0] = 2.000000f; + b.v[1] = -1.000000f; + b.v[2] = 1.000000f; + SST_Math_Mat33fCreateLU(&X,&LU); + SST_Math_Mat33fApplyLUVec(&LU,&b,&x); + TASSERT(fabsf((x.v[0])-(2.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"x:Entry x_a1 failed!"); + TASSERT(fabsf((x.v[1])-(-1.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"x:Entry x_a2 failed!"); + TASSERT(fabsf((x.v[2])-(3.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"x:Entry x_a3 failed!"); + return ZTEST_SUCCESS; +} +static const char* testSST_Math_Mat33fApplyLUVecLocal(){ + SST_Mat33f X; /* 3 x 3 matrix */ + SST_Mat33f LU; /* 3 x 3 matrix */ + SST_Vec3f b; /* 3 x 3 vector */ + X.v[0] = 2.000000f; + X.v[1] = 1.000000f; + X.v[2] = 0.000000f; + X.v[3] = -1.000000f; + X.v[4] = 0.000000f; + X.v[5] = 2.000000f; + X.v[6] = -1.000000f; + X.v[7] = -1.000000f; + X.v[8] = 1.000000f; + b.v[0] = 2.000000f; + b.v[1] = -1.000000f; + b.v[2] = 1.000000f; + SST_Math_Mat33fCreateLU(&X,&LU); + SST_Math_Mat33fApplyLUVecLocal(&LU,&b); + TASSERT(fabsf((b.v[0])-(2.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"x:Entry x_a1 failed!"); + TASSERT(fabsf((b.v[1])-(-1.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"x:Entry x_a2 failed!"); + TASSERT(fabsf((b.v[2])-(3.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"x:Entry x_a3 failed!"); + return ZTEST_SUCCESS; +} diff --git a/ZTestSuite/Test-SST_Mat33i.cpp b/ZTestSuite/Test-SST_Mat33i.cpp new file mode 100644 index 0000000..9bdbc47 --- /dev/null +++ b/ZTestSuite/Test-SST_Mat33i.cpp @@ -0,0 +1,719 @@ +/* + AUTOMATICALLY GENERATED FILE - DO NOT EDIT! + Please change MatrixNxN.py and re-run it +*/ +/* Generated with ./MatrixNxN.py n = 3, TYPE = int */ + +#include "ZUnitTest.hpp" +#include <float.h> +#include <math.h> +#include <stdlib.h> +#include <stdio.h> +#include <SST/SST_Mat33.h> +#include <SST/SST_Vec3.h> + + + + +static const char* testSST_Math_Mat33iAdd(); +static const char* testSST_Math_Mat33iAddLocal(); +static const char* testSST_Math_Mat33iSubtract(); +static const char* testSST_Math_Mat33iSubtractLocal(); +static const char* testSST_Math_Mat33iMultiplyElementwise(); +static const char* testSST_Math_Mat33iMultiplyElementwiseLocal(); +static const char* testSST_Math_Mat33iMultiplyScalar(); +static const char* testSST_Math_Mat33iMultiplyScalarLocal(); +static const char* testSST_Math_Mat33iMultiplyMatrix(); +static const char* testSST_Math_Mat33iMultiplyMatrixLocal(); +static const char* testSST_Math_Mat33iMultiplyVector(); +static const char* testSST_Math_Mat33iMultiplyVectorLocal(); +static const char* testSST_Math_Mat33iTranspose(); +static const char* testSST_Math_Mat33iTransposeLocal(); +static const char* testSST_Math_Mat33iDeterminant(); +static const char* testSST_Math_Mat33iCheckOrthonormal(); +// List of unit tests +ZUnitTest SST_Math_Mat33iUnitTests[] = +{ +{ "testSST_Math_Mat33iAdd " , testSST_Math_Mat33iAdd }, +{ "testSST_Math_Mat33iAddLocal " , testSST_Math_Mat33iAddLocal }, +{ "testSST_Math_Mat33iSubtract " , testSST_Math_Mat33iSubtract }, +{ "testSST_Math_Mat33iSubtractLocal " , testSST_Math_Mat33iSubtractLocal }, +{ "testSST_Math_Mat33iMultiplyElementwise " , testSST_Math_Mat33iMultiplyElementwise }, +{ "testSST_Math_Mat33iMultiplyElementwiseLocal " , testSST_Math_Mat33iMultiplyElementwiseLocal }, +{ "testSST_Math_Mat33iMultiplyScalar " , testSST_Math_Mat33iMultiplyScalar }, +{ "testSST_Math_Mat33iMultiplyScalarLocal " , testSST_Math_Mat33iMultiplyScalarLocal }, +{ "testSST_Math_Mat33iMultiplyMatrix " , testSST_Math_Mat33iMultiplyMatrix }, +{ "testSST_Math_Mat33iMultiplyMatrixLocal " , testSST_Math_Mat33iMultiplyMatrixLocal }, +{ "testSST_Math_Mat33iMultiplyVector " , testSST_Math_Mat33iMultiplyVector }, +{ "testSST_Math_Mat33iMultiplyVectorLocal " , testSST_Math_Mat33iMultiplyVectorLocal }, +{ "testSST_Math_Mat33iDeterminant " , testSST_Math_Mat33iDeterminant }, +{ "testSST_Math_Mat33iCheckOrthonormal " , testSST_Math_Mat33iCheckOrthonormal }, +{ "testSST_Math_Mat33iTranspose " , testSST_Math_Mat33iTranspose }, +{ "testSST_Math_Mat33iTransposeLocal " , testSST_Math_Mat33iTransposeLocal } +}; +DECLARE_ZTESTBLOCK(SST_Math_Mat33i) + +/******************************************************************************/ + +static const char* testSST_Math_Mat33iAdd(){ + SST_Mat33i X; /* 3 x 3 matrix */ + SST_Mat33i Y; /* 3 x 3 matrix */ + SST_Mat33i A; /* 3 x 3 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = -17; + X.v[1] = 4; + X.v[2] = -20; + X.v[3] = -10; + X.v[4] = 8; + X.v[5] = -5; + X.v[6] = 13; + X.v[7] = -5; + X.v[8] = 7; + Y.v[0] = 1; + Y.v[1] = -7; + Y.v[2] = -9; + Y.v[3] = 2; + Y.v[4] = -13; + Y.v[5] = -20; + Y.v[6] = -10; + Y.v[7] = -16; + Y.v[8] = -4; +/* +[[-17 -10 13] + [ 4 8 -5] + [-20 -5 7]] +[[ 1 2 -10] + [ -7 -13 -16] + [ -9 -20 -4]] +[[-16 -8 3] + [ -3 -5 -21] + [-29 -25 3]] +*/ + SST_Math_Mat33iAdd(&X,&Y,&A); + TASSERT((A.v[0])==(-16),"Entry _a11 failed!"); + TASSERT((A.v[3])==(-8),"Entry _a12 failed!"); + TASSERT((A.v[6])==(3),"Entry _a13 failed!"); + TASSERT((A.v[1])==(-3),"Entry _a21 failed!"); + TASSERT((A.v[4])==(-5),"Entry _a22 failed!"); + TASSERT((A.v[7])==(-21),"Entry _a23 failed!"); + TASSERT((A.v[2])==(-29),"Entry _a31 failed!"); + TASSERT((A.v[5])==(-25),"Entry _a32 failed!"); + TASSERT((A.v[8])==(3),"Entry _a33 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat33iAddLocal(){ + SST_Mat33i X; /* 3 x 3 matrix */ + SST_Mat33i Y; /* 3 x 3 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = 15; + X.v[1] = -6; + X.v[2] = 0; + X.v[3] = 13; + X.v[4] = -15; + X.v[5] = -16; + X.v[6] = 18; + X.v[7] = -16; + X.v[8] = 9; + Y.v[0] = 5; + Y.v[1] = 11; + Y.v[2] = -12; + Y.v[3] = 2; + Y.v[4] = 7; + Y.v[5] = -1; + Y.v[6] = -9; + Y.v[7] = 11; + Y.v[8] = -1; +/* +[[ 15 13 18] + [ -6 -15 -16] + [ 0 -16 9]] +[[ 5 2 -9] + [ 11 7 11] + [-12 -1 -1]] +[[ 20 15 9] + [ 5 -8 -5] + [-12 -17 8]] +*/ + SST_Math_Mat33iAddLocal(&X,&Y); /* for accuracy */ + TASSERT((X.v[0])==(20),"Entry _a11 failed!"); + TASSERT((X.v[3])==(15),"Entry _a12 failed!"); + TASSERT((X.v[6])==(9),"Entry _a13 failed!"); + TASSERT((X.v[1])==(5),"Entry _a21 failed!"); + TASSERT((X.v[4])==(-8),"Entry _a22 failed!"); + TASSERT((X.v[7])==(-5),"Entry _a23 failed!"); + TASSERT((X.v[2])==(-12),"Entry _a31 failed!"); + TASSERT((X.v[5])==(-17),"Entry _a32 failed!"); + TASSERT((X.v[8])==(8),"Entry _a33 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat33iSubtract(){ + SST_Mat33i X; /* 3 x 3 matrix */ + SST_Mat33i Y; /* 3 x 3 matrix */ + SST_Mat33i A; /* 3 x 3 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = 9; + X.v[1] = -2; + X.v[2] = 19; + X.v[3] = -12; + X.v[4] = 14; + X.v[5] = 18; + X.v[6] = -9; + X.v[7] = 17; + X.v[8] = -15; + Y.v[0] = -16; + Y.v[1] = 11; + Y.v[2] = 3; + Y.v[3] = -18; + Y.v[4] = 12; + Y.v[5] = -11; + Y.v[6] = 16; + Y.v[7] = -19; + Y.v[8] = 3; +/* +[[ 9 -12 -9] + [ -2 14 17] + [ 19 18 -15]] +[[-16 -18 16] + [ 11 12 -19] + [ 3 -11 3]] +[[ 25 6 -25] + [-13 2 36] + [ 16 29 -18]] +*/ + SST_Math_Mat33iSubtract(&X,&Y,&A); + TASSERT((A.v[0])==(25),"Entry _a11 failed!"); + TASSERT((A.v[3])==(6),"Entry _a12 failed!"); + TASSERT((A.v[6])==(-25),"Entry _a13 failed!"); + TASSERT((A.v[1])==(-13),"Entry _a21 failed!"); + TASSERT((A.v[4])==(2),"Entry _a22 failed!"); + TASSERT((A.v[7])==(36),"Entry _a23 failed!"); + TASSERT((A.v[2])==(16),"Entry _a31 failed!"); + TASSERT((A.v[5])==(29),"Entry _a32 failed!"); + TASSERT((A.v[8])==(-18),"Entry _a33 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat33iSubtractLocal(){ + SST_Mat33i X; /* 3 x 3 matrix */ + SST_Mat33i Y; /* 3 x 3 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = -1; + X.v[1] = 3; + X.v[2] = 11; + X.v[3] = 18; + X.v[4] = -1; + X.v[5] = -17; + X.v[6] = -8; + X.v[7] = -10; + X.v[8] = -13; + Y.v[0] = -6; + Y.v[1] = 6; + Y.v[2] = -20; + Y.v[3] = -19; + Y.v[4] = 8; + Y.v[5] = -10; + Y.v[6] = 15; + Y.v[7] = 9; + Y.v[8] = 1; +/* +[[ -1 18 -8] + [ 3 -1 -10] + [ 11 -17 -13]] +[[ -6 -19 15] + [ 6 8 9] + [-20 -10 1]] +[[ 5 37 -23] + [ -3 -9 -19] + [ 31 -7 -14]] +*/ + SST_Math_Mat33iSubtractLocal(&X,&Y); /* for accuracy */ + TASSERT((X.v[0])==(5),"Entry _a11 failed!"); + TASSERT((X.v[3])==(37),"Entry _a12 failed!"); + TASSERT((X.v[6])==(-23),"Entry _a13 failed!"); + TASSERT((X.v[1])==(-3),"Entry _a21 failed!"); + TASSERT((X.v[4])==(-9),"Entry _a22 failed!"); + TASSERT((X.v[7])==(-19),"Entry _a23 failed!"); + TASSERT((X.v[2])==(31),"Entry _a31 failed!"); + TASSERT((X.v[5])==(-7),"Entry _a32 failed!"); + TASSERT((X.v[8])==(-14),"Entry _a33 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat33iMultiplyElementwise(){ + SST_Mat33i X; /* 3 x 3 matrix */ + SST_Mat33i Y; /* 3 x 3 matrix */ + SST_Mat33i A; /* 3 x 3 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = -1; + X.v[1] = 16; + X.v[2] = 16; + X.v[3] = -17; + X.v[4] = 1; + X.v[5] = 1; + X.v[6] = 8; + X.v[7] = 2; + X.v[8] = -7; + Y.v[0] = 5; + Y.v[1] = -14; + Y.v[2] = 17; + Y.v[3] = -13; + Y.v[4] = 19; + Y.v[5] = -15; + Y.v[6] = 19; + Y.v[7] = -7; + Y.v[8] = 2; +/* +[[ -1 -17 8] + [ 16 1 2] + [ 16 1 -7]] +[[ 5 -13 19] + [-14 19 -7] + [ 17 -15 2]] +[[ -5 221 152] + [-224 19 -14] + [ 272 -15 -14]] +*/ + SST_Math_Mat33iMultiplyElementwise(&X, &Y, &A); + TASSERT((A.v[0])==(-5),"Entry _a11 failed!"); + TASSERT((A.v[3])==(221),"Entry _a12 failed!"); + TASSERT((A.v[6])==(152),"Entry _a13 failed!"); + TASSERT((A.v[1])==(-224),"Entry _a21 failed!"); + TASSERT((A.v[4])==(19),"Entry _a22 failed!"); + TASSERT((A.v[7])==(-14),"Entry _a23 failed!"); + TASSERT((A.v[2])==(272),"Entry _a31 failed!"); + TASSERT((A.v[5])==(-15),"Entry _a32 failed!"); + TASSERT((A.v[8])==(-14),"Entry _a33 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat33iMultiplyElementwiseLocal(){ + SST_Mat33i X; /* 3 x 3 matrix */ + SST_Mat33i Y; /* 3 x 3 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = -14; + X.v[1] = -2; + X.v[2] = 4; + X.v[3] = -18; + X.v[4] = -9; + X.v[5] = 0; + X.v[6] = -10; + X.v[7] = 17; + X.v[8] = -20; + Y.v[0] = -8; + Y.v[1] = -9; + Y.v[2] = 3; + Y.v[3] = 15; + Y.v[4] = -15; + Y.v[5] = 2; + Y.v[6] = 3; + Y.v[7] = 2; + Y.v[8] = -4; +/* +[[-14 -18 -10] + [ -2 -9 17] + [ 4 0 -20]] +[[ -8 15 3] + [ -9 -15 2] + [ 3 2 -4]] +[[ 112 -270 -30] + [ 18 135 34] + [ 12 0 80]] +*/ + SST_Math_Mat33iMultiplyElementwiseLocal(&X,&Y); + TASSERT((X.v[0])==(112),"Entry _a11 failed!"); + TASSERT((X.v[3])==(-270),"Entry _a12 failed!"); + TASSERT((X.v[6])==(-30),"Entry _a13 failed!"); + TASSERT((X.v[1])==(18),"Entry _a21 failed!"); + TASSERT((X.v[4])==(135),"Entry _a22 failed!"); + TASSERT((X.v[7])==(34),"Entry _a23 failed!"); + TASSERT((X.v[2])==(12),"Entry _a31 failed!"); + TASSERT((X.v[5])==(0),"Entry _a32 failed!"); + TASSERT((X.v[8])==(80),"Entry _a33 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat33iMultiplyScalar(){ + SST_Mat33i X; /* 3 x 3 matrix */ + SST_Mat33i A; /* 3 x 3 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = 12; + X.v[1] = -10; + X.v[2] = -13; + X.v[3] = -16; + X.v[4] = -5; + X.v[5] = -5; + X.v[6] = -5; + X.v[7] = 15; + X.v[8] = 16; +/* +[[ 12 -16 -5] + [-10 -5 15] + [-13 -5 16]] +[[ 24 -32 -10] + [-20 -10 30] + [-26 -10 32]] +*/ + SST_Math_Mat33iMultiplyScalar(&X,2,&A); + TASSERT((A.v[0])==(24),"Entry _a11 failed!"); + TASSERT((A.v[3])==(-32),"Entry _a12 failed!"); + TASSERT((A.v[6])==(-10),"Entry _a13 failed!"); + TASSERT((A.v[1])==(-20),"Entry _a21 failed!"); + TASSERT((A.v[4])==(-10),"Entry _a22 failed!"); + TASSERT((A.v[7])==(30),"Entry _a23 failed!"); + TASSERT((A.v[2])==(-26),"Entry _a31 failed!"); + TASSERT((A.v[5])==(-10),"Entry _a32 failed!"); + TASSERT((A.v[8])==(32),"Entry _a33 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat33iMultiplyScalarLocal(){ + SST_Mat33i X; /* 3 x 3 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = 0; + X.v[1] = -4; + X.v[2] = 13; + X.v[3] = -9; + X.v[4] = -20; + X.v[5] = -15; + X.v[6] = 1; + X.v[7] = 2; + X.v[8] = 9; +/* +[[ 0 -9 1] + [ -4 -20 2] + [ 13 -15 9]] +[[ 0 -18 2] + [ -8 -40 4] + [ 26 -30 18]] +*/ + SST_Math_Mat33iMultiplyScalarLocal(&X,2); + TASSERT((X.v[0])==(0),"Entry _a11 failed!"); + TASSERT((X.v[3])==(-18),"Entry _a12 failed!"); + TASSERT((X.v[6])==(2),"Entry _a13 failed!"); + TASSERT((X.v[1])==(-8),"Entry _a21 failed!"); + TASSERT((X.v[4])==(-40),"Entry _a22 failed!"); + TASSERT((X.v[7])==(4),"Entry _a23 failed!"); + TASSERT((X.v[2])==(26),"Entry _a31 failed!"); + TASSERT((X.v[5])==(-30),"Entry _a32 failed!"); + TASSERT((X.v[8])==(18),"Entry _a33 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat33iMultiplyMatrix(){ + SST_Mat33i X; /* 3 x 3 matrix */ + SST_Mat33i Y; /* 3 x 3 matrix */ + SST_Mat33i A; /* 3 x 3 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = -8; + X.v[1] = 7; + X.v[2] = -9; + X.v[3] = 1; + X.v[4] = 10; + X.v[5] = -15; + X.v[6] = -6; + X.v[7] = 1; + X.v[8] = 4; + Y.v[0] = -15; + Y.v[1] = 11; + Y.v[2] = -10; + Y.v[3] = 12; + Y.v[4] = 11; + Y.v[5] = 16; + Y.v[6] = 0; + Y.v[7] = -14; + Y.v[8] = -5; +/* +X +[[ -8 1 -6] + [ 7 10 1] + [ -9 -15 4]] +Y +[[-15 12 0] + [ 11 11 -14] + [-10 16 -5]] +[[ 191 -181 16] + [ -5 210 -145] + [ -70 -209 190]] +*/ + SST_Math_Mat33iMultiplyMatrix(&X,&Y,&A); + TASSERT((A.v[0])==(191),"Entry _a11 failed!"); + TASSERT((A.v[3])==(-181),"Entry _a12 failed!"); + TASSERT((A.v[6])==(16),"Entry _a13 failed!"); + TASSERT((A.v[1])==(-5),"Entry _a21 failed!"); + TASSERT((A.v[4])==(210),"Entry _a22 failed!"); + TASSERT((A.v[7])==(-145),"Entry _a23 failed!"); + TASSERT((A.v[2])==(-70),"Entry _a31 failed!"); + TASSERT((A.v[5])==(-209),"Entry _a32 failed!"); + TASSERT((A.v[8])==(190),"Entry _a33 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat33iMultiplyMatrixLocal(){ + SST_Mat33i X; /* 3 x 3 matrix */ + SST_Mat33i Y; /* 3 x 3 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = -20; + X.v[1] = 13; + X.v[2] = 14; + X.v[3] = -4; + X.v[4] = 19; + X.v[5] = -3; + X.v[6] = 16; + X.v[7] = 19; + X.v[8] = -9; + Y.v[0] = -19; + Y.v[1] = -8; + Y.v[2] = -5; + Y.v[3] = -19; + Y.v[4] = -2; + Y.v[5] = -10; + Y.v[6] = -16; + Y.v[7] = 17; + Y.v[8] = -9; +/* +X +[[-20 -4 16] + [ 13 19 19] + [ 14 -3 -9]] +Y +[[-19 -19 -16] + [ -8 -2 17] + [ -5 -10 -9]] +X +[[ 332 228 108] + [-494 -475 -56] + [-197 -170 -194]] +*/ + SST_Math_Mat33iMultiplyMatrixLocal(&X,&Y); + TASSERT((X.v[0])==(332),"Entry _a11 failed!"); + TASSERT((X.v[3])==(228),"Entry _a12 failed!"); + TASSERT((X.v[6])==(108),"Entry _a13 failed!"); + TASSERT((X.v[1])==(-494),"Entry _a21 failed!"); + TASSERT((X.v[4])==(-475),"Entry _a22 failed!"); + TASSERT((X.v[7])==(-56),"Entry _a23 failed!"); + TASSERT((X.v[2])==(-197),"Entry _a31 failed!"); + TASSERT((X.v[5])==(-170),"Entry _a32 failed!"); + TASSERT((X.v[8])==(-194),"Entry _a33 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat33iMultiplyVector(){ + SST_Mat33i X; /* 3 x 3 matrix */ + SST_Vec3i v; /* 3 vector */ + SST_Vec3i w; /* 3 vector */ +/* Resetting test vectors / mats */ + v.v[0] = 7; + v.v[1] = 11; + v.v[2] = -14; + X.v[0] = 2; + X.v[1] = 2; + X.v[2] = -11; + X.v[3] = -6; + X.v[4] = 12; + X.v[5] = -13; + X.v[6] = -4; + X.v[7] = -20; + X.v[8] = 15; +/* +X +[[ 2 -6 -4] + [ 2 12 -20] + [-11 -13 15]] +v +[ 7 11 -14] +w +[ 4 426 -430] +*/ + SST_Math_Mat33iMultiplyVector(&X,&v,&w); + TASSERT((w.v[0])==(4),"Entry .v[0] failed!"); + TASSERT((w.v[1])==(426),"Entry .v[1] failed!"); + TASSERT((w.v[2])==(-430),"Entry .v[2] failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat33iMultiplyVectorLocal(){ + SST_Mat33i X; /* 3 x 3 matrix */ + SST_Vec3i v; /* 3 vector */ +/* Resetting test vectors / mats */ + v.v[0] = 19; + v.v[1] = 2; + v.v[2] = -20; + X.v[0] = -13; + X.v[1] = 14; + X.v[2] = 2; + X.v[3] = 10; + X.v[4] = 19; + X.v[5] = 11; + X.v[6] = 15; + X.v[7] = -10; + X.v[8] = -7; +/* +X +[[-13 10 15] + [ 14 19 -10] + [ 2 11 -7]] +v +[ 19 2 -20] +v +[-527 504 200] +*/ + SST_Math_Mat33iMultiplyVectorLocal(&X,&v); + TASSERT((v.v[0])==(-527),"Entry .v[0] failed!"); + TASSERT((v.v[1])==(504),"Entry .v[1] failed!"); + TASSERT((v.v[2])==(200),"Entry .v[2] failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat33iTranspose(){ + SST_Mat33i X; /* 3 x 3 matrix */ + SST_Mat33i A; /* 3 x 3 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = 8; + X.v[1] = -13; + X.v[2] = 2; + X.v[3] = 1; + X.v[4] = -17; + X.v[5] = -16; + X.v[6] = -16; + X.v[7] = -5; + X.v[8] = 13; + SST_Math_Mat33iTranspose(&X,&A); + TASSERT((A.v[0])==(8),"Entry _a11 failed!"); + TASSERT((A.v[3])==(-13),"Entry _a12 failed!"); + TASSERT((A.v[6])==(2),"Entry _a13 failed!"); + TASSERT((A.v[1])==(1),"Entry _a21 failed!"); + TASSERT((A.v[4])==(-17),"Entry _a22 failed!"); + TASSERT((A.v[7])==(-16),"Entry _a23 failed!"); + TASSERT((A.v[2])==(-16),"Entry _a31 failed!"); + TASSERT((A.v[5])==(-5),"Entry _a32 failed!"); + TASSERT((A.v[8])==(13),"Entry _a33 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat33iTransposeLocal(){ + SST_Mat33i X; /* 3 x 3 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = -19; + X.v[1] = -4; + X.v[2] = 14; + X.v[3] = -2; + X.v[4] = 18; + X.v[5] = -4; + X.v[6] = -2; + X.v[7] = 2; + X.v[8] = 10; + SST_Math_Mat33iTransposeLocal(&X); + TASSERT((X.v[0])==(-19),"Entry _a11 failed!"); + TASSERT((X.v[3])==(-4),"Entry _a12 failed!"); + TASSERT((X.v[6])==(14),"Entry _a13 failed!"); + TASSERT((X.v[1])==(-2),"Entry _a21 failed!"); + TASSERT((X.v[4])==(18),"Entry _a22 failed!"); + TASSERT((X.v[7])==(-4),"Entry _a23 failed!"); + TASSERT((X.v[2])==(-2),"Entry _a31 failed!"); + TASSERT((X.v[5])==(2),"Entry _a32 failed!"); + TASSERT((X.v[8])==(10),"Entry _a33 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat33iCheckOrthonormal(){ + SST_Mat33i X; /* 3 x 3 matrix */ + SST_Mat33i Y; /* 3 x 3 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = 14; + X.v[1] = 1; + X.v[2] = 8; + X.v[3] = 12; + X.v[4] = -9; + X.v[5] = -1; + X.v[6] = -16; + X.v[7] = 11; + X.v[8] = 3; + Y.v[0] = -19; + Y.v[1] = 6; + Y.v[2] = 12; + Y.v[3] = 2; + Y.v[4] = -1; + Y.v[5] = -1; + Y.v[6] = -11; + Y.v[7] = -8; + Y.v[8] = 19; +X.v[0] = (int)1; +X.v[1] = (int)0; +X.v[2] = (int)0; +X.v[3] = (int)0; +X.v[4] = (int)1; +X.v[5] = (int)0; +X.v[6] = (int)0; +X.v[7] = (int)0; +X.v[8] = (int)1; +Y.v[0] = (int)1; +Y.v[1] = (int)0; +Y.v[2] = (int)0; +Y.v[3] = (int)0; +Y.v[4] = (int)1; +Y.v[5] = (int)0; +Y.v[6] = (int)0; +Y.v[7] = (int)0; +Y.v[8] = (int)1; +Y.v[2] = (int)1; /* Will cause Y to be fail */ +/* Check Positive Test */ + TASSERT(SST_Math_Mat33iCheckOrthonormal(&X),"CheckOrthonormal failed when it should have passed"); +/* Check Negative Test */ + TASSERT(!SST_Math_Mat33iCheckOrthonormal(&Y),"CheckOrthonormal succeeded when it should have failed"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat33iDeterminant(){ + SST_Mat33i X; /* 3 x 3 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = 16; + X.v[1] = 9; + X.v[2] = -17; + X.v[3] = -20; + X.v[4] = 13; + X.v[5] = 6; + X.v[6] = -6; + X.v[7] = -20; + X.v[8] = 10; +/* det(X) = +-2650.0 + */ + int result = SST_Math_Mat33iDeterminant(&X); + TASSERT(abs( (result)/(-2650) - 1 ) <= 100*0,"Determinant failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + diff --git a/ZTestSuite/Test-SST_Mat33u.cpp b/ZTestSuite/Test-SST_Mat33u.cpp new file mode 100644 index 0000000..afa3901 --- /dev/null +++ b/ZTestSuite/Test-SST_Mat33u.cpp @@ -0,0 +1,643 @@ +/* + AUTOMATICALLY GENERATED FILE - DO NOT EDIT! + Please change MatrixNxN.py and re-run it +*/ +/* Generated with ./MatrixNxN.py n = 3, TYPE = unsigned int */ + +#include "ZUnitTest.hpp" +#include <float.h> +#include <math.h> +#include <stdlib.h> +#include <stdio.h> +#include <SST/SST_Mat33.h> +#include <SST/SST_Vec3.h> + + + + +static const char* testSST_Math_Mat33uAdd(); +static const char* testSST_Math_Mat33uAddLocal(); +static const char* testSST_Math_Mat33uSubtract(); +static const char* testSST_Math_Mat33uSubtractLocal(); +static const char* testSST_Math_Mat33uMultiplyElementwise(); +static const char* testSST_Math_Mat33uMultiplyElementwiseLocal(); +static const char* testSST_Math_Mat33uMultiplyScalar(); +static const char* testSST_Math_Mat33uMultiplyScalarLocal(); +static const char* testSST_Math_Mat33uMultiplyMatrix(); +static const char* testSST_Math_Mat33uMultiplyMatrixLocal(); +static const char* testSST_Math_Mat33uMultiplyVector(); +static const char* testSST_Math_Mat33uMultiplyVectorLocal(); +static const char* testSST_Math_Mat33uTranspose(); +static const char* testSST_Math_Mat33uTransposeLocal(); +// List of unit tests +ZUnitTest SST_Math_Mat33uUnitTests[] = +{ +{ "testSST_Math_Mat33uAdd " , testSST_Math_Mat33uAdd }, +{ "testSST_Math_Mat33uAddLocal " , testSST_Math_Mat33uAddLocal }, +{ "testSST_Math_Mat33uSubtract " , testSST_Math_Mat33uSubtract }, +{ "testSST_Math_Mat33uSubtractLocal " , testSST_Math_Mat33uSubtractLocal }, +{ "testSST_Math_Mat33uMultiplyElementwise " , testSST_Math_Mat33uMultiplyElementwise }, +{ "testSST_Math_Mat33uMultiplyElementwiseLocal " , testSST_Math_Mat33uMultiplyElementwiseLocal }, +{ "testSST_Math_Mat33uMultiplyScalar " , testSST_Math_Mat33uMultiplyScalar }, +{ "testSST_Math_Mat33uMultiplyScalarLocal " , testSST_Math_Mat33uMultiplyScalarLocal }, +{ "testSST_Math_Mat33uMultiplyMatrix " , testSST_Math_Mat33uMultiplyMatrix }, +{ "testSST_Math_Mat33uMultiplyMatrixLocal " , testSST_Math_Mat33uMultiplyMatrixLocal }, +{ "testSST_Math_Mat33uMultiplyVector " , testSST_Math_Mat33uMultiplyVector }, +{ "testSST_Math_Mat33uMultiplyVectorLocal " , testSST_Math_Mat33uMultiplyVectorLocal }, +{ "testSST_Math_Mat33uTranspose " , testSST_Math_Mat33uTranspose }, +{ "testSST_Math_Mat33uTransposeLocal " , testSST_Math_Mat33uTransposeLocal } +}; +DECLARE_ZTESTBLOCK(SST_Math_Mat33u) + +/******************************************************************************/ + +static const char* testSST_Math_Mat33uAdd(){ + SST_Mat33u X; /* 3 x 3 matrix */ + SST_Mat33u Y; /* 3 x 3 matrix */ + SST_Mat33u A; /* 3 x 3 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = 35; + X.v[1] = 11; + X.v[2] = 6; + X.v[3] = 32; + X.v[4] = 1; + X.v[5] = 19; + X.v[6] = 34; + X.v[7] = 1; + X.v[8] = 12; + Y.v[0] = 9; + Y.v[1] = 27; + Y.v[2] = 33; + Y.v[3] = 11; + Y.v[4] = 12; + Y.v[5] = 6; + Y.v[6] = 8; + Y.v[7] = 22; + Y.v[8] = 11; +/* +[[35 32 34] + [11 1 1] + [ 6 19 12]] +[[ 9 11 8] + [27 12 22] + [33 6 11]] +[[44 43 42] + [38 13 23] + [39 25 23]] +*/ + SST_Math_Mat33uAdd(&X,&Y,&A); + TASSERT((A.v[0])==(44),"Entry _a11 failed!"); + TASSERT((A.v[3])==(43),"Entry _a12 failed!"); + TASSERT((A.v[6])==(42),"Entry _a13 failed!"); + TASSERT((A.v[1])==(38),"Entry _a21 failed!"); + TASSERT((A.v[4])==(13),"Entry _a22 failed!"); + TASSERT((A.v[7])==(23),"Entry _a23 failed!"); + TASSERT((A.v[2])==(39),"Entry _a31 failed!"); + TASSERT((A.v[5])==(25),"Entry _a32 failed!"); + TASSERT((A.v[8])==(23),"Entry _a33 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat33uAddLocal(){ + SST_Mat33u X; /* 3 x 3 matrix */ + SST_Mat33u Y; /* 3 x 3 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = 25; + X.v[1] = 11; + X.v[2] = 26; + X.v[3] = 39; + X.v[4] = 33; + X.v[5] = 33; + X.v[6] = 1; + X.v[7] = 15; + X.v[8] = 31; + Y.v[0] = 12; + Y.v[1] = 38; + Y.v[2] = 35; + Y.v[3] = 12; + Y.v[4] = 11; + Y.v[5] = 15; + Y.v[6] = 8; + Y.v[7] = 0; + Y.v[8] = 25; +/* +[[25 39 1] + [11 33 15] + [26 33 31]] +[[12 12 8] + [38 11 0] + [35 15 25]] +[[37 51 9] + [49 44 15] + [61 48 56]] +*/ + SST_Math_Mat33uAddLocal(&X,&Y); /* for accuracy */ + TASSERT((X.v[0])==(37),"Entry _a11 failed!"); + TASSERT((X.v[3])==(51),"Entry _a12 failed!"); + TASSERT((X.v[6])==(9),"Entry _a13 failed!"); + TASSERT((X.v[1])==(49),"Entry _a21 failed!"); + TASSERT((X.v[4])==(44),"Entry _a22 failed!"); + TASSERT((X.v[7])==(15),"Entry _a23 failed!"); + TASSERT((X.v[2])==(61),"Entry _a31 failed!"); + TASSERT((X.v[5])==(48),"Entry _a32 failed!"); + TASSERT((X.v[8])==(56),"Entry _a33 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat33uSubtract(){ + SST_Mat33u X; /* 3 x 3 matrix */ + SST_Mat33u Y; /* 3 x 3 matrix */ + SST_Mat33u A; /* 3 x 3 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = 33; + X.v[1] = 15; + X.v[2] = 17; + X.v[3] = 4; + X.v[4] = 1; + X.v[5] = 30; + X.v[6] = 29; + X.v[7] = 18; + X.v[8] = 31; + Y.v[0] = 0; + Y.v[1] = 19; + Y.v[2] = 12; + Y.v[3] = 37; + Y.v[4] = 35; + Y.v[5] = 2; + Y.v[6] = 6; + Y.v[7] = 15; + Y.v[8] = 1; +/* +[[33 4 29] + [15 1 18] + [17 30 31]] +[[ 0 37 6] + [19 35 15] + [12 2 1]] +[[ 33 4294967263 23] + [4294967292 4294967262 3] + [ 5 28 30]] +*/ + SST_Math_Mat33uSubtract(&X,&Y,&A); + TASSERT((A.v[0])==(33),"Entry _a11 failed!"); + TASSERT((A.v[3])==(4294967263),"Entry _a12 failed!"); + TASSERT((A.v[6])==(23),"Entry _a13 failed!"); + TASSERT((A.v[1])==(4294967292),"Entry _a21 failed!"); + TASSERT((A.v[4])==(4294967262),"Entry _a22 failed!"); + TASSERT((A.v[7])==(3),"Entry _a23 failed!"); + TASSERT((A.v[2])==(5),"Entry _a31 failed!"); + TASSERT((A.v[5])==(28),"Entry _a32 failed!"); + TASSERT((A.v[8])==(30),"Entry _a33 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat33uSubtractLocal(){ + SST_Mat33u X; /* 3 x 3 matrix */ + SST_Mat33u Y; /* 3 x 3 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = 4; + X.v[1] = 1; + X.v[2] = 17; + X.v[3] = 16; + X.v[4] = 33; + X.v[5] = 38; + X.v[6] = 20; + X.v[7] = 33; + X.v[8] = 33; + Y.v[0] = 22; + Y.v[1] = 8; + Y.v[2] = 15; + Y.v[3] = 11; + Y.v[4] = 8; + Y.v[5] = 28; + Y.v[6] = 29; + Y.v[7] = 22; + Y.v[8] = 19; +/* +[[ 4 16 20] + [ 1 33 33] + [17 38 33]] +[[22 11 29] + [ 8 8 22] + [15 28 19]] +[[4294967278 5 4294967287] + [4294967289 25 11] + [ 2 10 14]] +*/ + SST_Math_Mat33uSubtractLocal(&X,&Y); /* for accuracy */ + TASSERT((X.v[0])==(4294967278),"Entry _a11 failed!"); + TASSERT((X.v[3])==(5),"Entry _a12 failed!"); + TASSERT((X.v[6])==(4294967287),"Entry _a13 failed!"); + TASSERT((X.v[1])==(4294967289),"Entry _a21 failed!"); + TASSERT((X.v[4])==(25),"Entry _a22 failed!"); + TASSERT((X.v[7])==(11),"Entry _a23 failed!"); + TASSERT((X.v[2])==(2),"Entry _a31 failed!"); + TASSERT((X.v[5])==(10),"Entry _a32 failed!"); + TASSERT((X.v[8])==(14),"Entry _a33 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat33uMultiplyElementwise(){ + SST_Mat33u X; /* 3 x 3 matrix */ + SST_Mat33u Y; /* 3 x 3 matrix */ + SST_Mat33u A; /* 3 x 3 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = 19; + X.v[1] = 5; + X.v[2] = 16; + X.v[3] = 27; + X.v[4] = 15; + X.v[5] = 28; + X.v[6] = 1; + X.v[7] = 12; + X.v[8] = 28; + Y.v[0] = 13; + Y.v[1] = 5; + Y.v[2] = 30; + Y.v[3] = 6; + Y.v[4] = 39; + Y.v[5] = 38; + Y.v[6] = 30; + Y.v[7] = 12; + Y.v[8] = 35; +/* +[[19 27 1] + [ 5 15 12] + [16 28 28]] +[[13 6 30] + [ 5 39 12] + [30 38 35]] +[[ 247 162 30] + [ 25 585 144] + [ 480 1064 980]] +*/ + SST_Math_Mat33uMultiplyElementwise(&X, &Y, &A); + TASSERT((A.v[0])==(247),"Entry _a11 failed!"); + TASSERT((A.v[3])==(162),"Entry _a12 failed!"); + TASSERT((A.v[6])==(30),"Entry _a13 failed!"); + TASSERT((A.v[1])==(25),"Entry _a21 failed!"); + TASSERT((A.v[4])==(585),"Entry _a22 failed!"); + TASSERT((A.v[7])==(144),"Entry _a23 failed!"); + TASSERT((A.v[2])==(480),"Entry _a31 failed!"); + TASSERT((A.v[5])==(1064),"Entry _a32 failed!"); + TASSERT((A.v[8])==(980),"Entry _a33 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat33uMultiplyElementwiseLocal(){ + SST_Mat33u X; /* 3 x 3 matrix */ + SST_Mat33u Y; /* 3 x 3 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = 27; + X.v[1] = 10; + X.v[2] = 15; + X.v[3] = 38; + X.v[4] = 0; + X.v[5] = 3; + X.v[6] = 10; + X.v[7] = 5; + X.v[8] = 13; + Y.v[0] = 35; + Y.v[1] = 25; + Y.v[2] = 12; + Y.v[3] = 12; + Y.v[4] = 23; + Y.v[5] = 35; + Y.v[6] = 5; + Y.v[7] = 38; + Y.v[8] = 26; +/* +[[27 38 10] + [10 0 5] + [15 3 13]] +[[35 12 5] + [25 23 38] + [12 35 26]] +[[945 456 50] + [250 0 190] + [180 105 338]] +*/ + SST_Math_Mat33uMultiplyElementwiseLocal(&X,&Y); + TASSERT((X.v[0])==(945),"Entry _a11 failed!"); + TASSERT((X.v[3])==(456),"Entry _a12 failed!"); + TASSERT((X.v[6])==(50),"Entry _a13 failed!"); + TASSERT((X.v[1])==(250),"Entry _a21 failed!"); + TASSERT((X.v[4])==(0),"Entry _a22 failed!"); + TASSERT((X.v[7])==(190),"Entry _a23 failed!"); + TASSERT((X.v[2])==(180),"Entry _a31 failed!"); + TASSERT((X.v[5])==(105),"Entry _a32 failed!"); + TASSERT((X.v[8])==(338),"Entry _a33 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat33uMultiplyScalar(){ + SST_Mat33u X; /* 3 x 3 matrix */ + SST_Mat33u A; /* 3 x 3 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = 24; + X.v[1] = 11; + X.v[2] = 1; + X.v[3] = 22; + X.v[4] = 0; + X.v[5] = 17; + X.v[6] = 22; + X.v[7] = 36; + X.v[8] = 27; +/* +[[24 22 22] + [11 0 36] + [ 1 17 27]] +[[48 44 44] + [22 0 72] + [ 2 34 54]] +*/ + SST_Math_Mat33uMultiplyScalar(&X,2,&A); + TASSERT((A.v[0])==(48),"Entry _a11 failed!"); + TASSERT((A.v[3])==(44),"Entry _a12 failed!"); + TASSERT((A.v[6])==(44),"Entry _a13 failed!"); + TASSERT((A.v[1])==(22),"Entry _a21 failed!"); + TASSERT((A.v[4])==(0),"Entry _a22 failed!"); + TASSERT((A.v[7])==(72),"Entry _a23 failed!"); + TASSERT((A.v[2])==(2),"Entry _a31 failed!"); + TASSERT((A.v[5])==(34),"Entry _a32 failed!"); + TASSERT((A.v[8])==(54),"Entry _a33 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat33uMultiplyScalarLocal(){ + SST_Mat33u X; /* 3 x 3 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = 12; + X.v[1] = 19; + X.v[2] = 9; + X.v[3] = 30; + X.v[4] = 31; + X.v[5] = 2; + X.v[6] = 38; + X.v[7] = 7; + X.v[8] = 0; +/* +[[12 30 38] + [19 31 7] + [ 9 2 0]] +[[24 60 76] + [38 62 14] + [18 4 0]] +*/ + SST_Math_Mat33uMultiplyScalarLocal(&X,2); + TASSERT((X.v[0])==(24),"Entry _a11 failed!"); + TASSERT((X.v[3])==(60),"Entry _a12 failed!"); + TASSERT((X.v[6])==(76),"Entry _a13 failed!"); + TASSERT((X.v[1])==(38),"Entry _a21 failed!"); + TASSERT((X.v[4])==(62),"Entry _a22 failed!"); + TASSERT((X.v[7])==(14),"Entry _a23 failed!"); + TASSERT((X.v[2])==(18),"Entry _a31 failed!"); + TASSERT((X.v[5])==(4),"Entry _a32 failed!"); + TASSERT((X.v[8])==(0),"Entry _a33 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat33uMultiplyMatrix(){ + SST_Mat33u X; /* 3 x 3 matrix */ + SST_Mat33u Y; /* 3 x 3 matrix */ + SST_Mat33u A; /* 3 x 3 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = 1; + X.v[1] = 26; + X.v[2] = 39; + X.v[3] = 24; + X.v[4] = 30; + X.v[5] = 23; + X.v[6] = 27; + X.v[7] = 11; + X.v[8] = 27; + Y.v[0] = 26; + Y.v[1] = 21; + Y.v[2] = 4; + Y.v[3] = 32; + Y.v[4] = 32; + Y.v[5] = 37; + Y.v[6] = 25; + Y.v[7] = 10; + Y.v[8] = 32; +/* +X +[[ 1 24 27] + [26 30 11] + [39 23 27]] +Y +[[26 32 25] + [21 32 10] + [ 4 37 32]] +[[ 638 1799 1129] + [1350 2199 1302] + [1605 2983 2069]] +*/ + SST_Math_Mat33uMultiplyMatrix(&X,&Y,&A); + TASSERT((A.v[0])==(638),"Entry _a11 failed!"); + TASSERT((A.v[3])==(1799),"Entry _a12 failed!"); + TASSERT((A.v[6])==(1129),"Entry _a13 failed!"); + TASSERT((A.v[1])==(1350),"Entry _a21 failed!"); + TASSERT((A.v[4])==(2199),"Entry _a22 failed!"); + TASSERT((A.v[7])==(1302),"Entry _a23 failed!"); + TASSERT((A.v[2])==(1605),"Entry _a31 failed!"); + TASSERT((A.v[5])==(2983),"Entry _a32 failed!"); + TASSERT((A.v[8])==(2069),"Entry _a33 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat33uMultiplyMatrixLocal(){ + SST_Mat33u X; /* 3 x 3 matrix */ + SST_Mat33u Y; /* 3 x 3 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = 12; + X.v[1] = 31; + X.v[2] = 4; + X.v[3] = 25; + X.v[4] = 35; + X.v[5] = 0; + X.v[6] = 11; + X.v[7] = 9; + X.v[8] = 37; + Y.v[0] = 16; + Y.v[1] = 5; + Y.v[2] = 12; + Y.v[3] = 3; + Y.v[4] = 8; + Y.v[5] = 33; + Y.v[6] = 30; + Y.v[7] = 5; + Y.v[8] = 11; +/* +X +[[12 25 11] + [31 35 9] + [ 4 0 37]] +Y +[[16 3 30] + [ 5 8 5] + [12 33 11]] +X +[[ 449 599 606] + [ 779 670 1204] + [ 508 1233 527]] +*/ + SST_Math_Mat33uMultiplyMatrixLocal(&X,&Y); + TASSERT((X.v[0])==(449),"Entry _a11 failed!"); + TASSERT((X.v[3])==(599),"Entry _a12 failed!"); + TASSERT((X.v[6])==(606),"Entry _a13 failed!"); + TASSERT((X.v[1])==(779),"Entry _a21 failed!"); + TASSERT((X.v[4])==(670),"Entry _a22 failed!"); + TASSERT((X.v[7])==(1204),"Entry _a23 failed!"); + TASSERT((X.v[2])==(508),"Entry _a31 failed!"); + TASSERT((X.v[5])==(1233),"Entry _a32 failed!"); + TASSERT((X.v[8])==(527),"Entry _a33 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat33uMultiplyVector(){ + SST_Mat33u X; /* 3 x 3 matrix */ + SST_Vec3u v; /* 3 vector */ + SST_Vec3u w; /* 3 vector */ +/* Resetting test vectors / mats */ + v.v[0] = 34; + v.v[1] = 0; + v.v[2] = 26; + X.v[0] = 19; + X.v[1] = 33; + X.v[2] = 4; + X.v[3] = 21; + X.v[4] = 12; + X.v[5] = 32; + X.v[6] = 10; + X.v[7] = 24; + X.v[8] = 21; +/* +X +[[19 21 10] + [33 12 24] + [ 4 32 21]] +v +[34 0 26] +w +[ 906 1746 682] +*/ + SST_Math_Mat33uMultiplyVector(&X,&v,&w); + TASSERT((w.v[0])==(906),"Entry .v[0] failed!"); + TASSERT((w.v[1])==(1746),"Entry .v[1] failed!"); + TASSERT((w.v[2])==(682),"Entry .v[2] failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat33uMultiplyVectorLocal(){ + SST_Mat33u X; /* 3 x 3 matrix */ + SST_Vec3u v; /* 3 vector */ +/* Resetting test vectors / mats */ + v.v[0] = 16; + v.v[1] = 36; + v.v[2] = 13; + X.v[0] = 37; + X.v[1] = 27; + X.v[2] = 8; + X.v[3] = 25; + X.v[4] = 12; + X.v[5] = 19; + X.v[6] = 24; + X.v[7] = 17; + X.v[8] = 19; +/* +X +[[37 25 24] + [27 12 17] + [ 8 19 19]] +v +[16 36 13] +v +[1804 1085 1059] +*/ + SST_Math_Mat33uMultiplyVectorLocal(&X,&v); + TASSERT((v.v[0])==(1804),"Entry .v[0] failed!"); + TASSERT((v.v[1])==(1085),"Entry .v[1] failed!"); + TASSERT((v.v[2])==(1059),"Entry .v[2] failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat33uTranspose(){ + SST_Mat33u X; /* 3 x 3 matrix */ + SST_Mat33u A; /* 3 x 3 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = 13; + X.v[1] = 16; + X.v[2] = 26; + X.v[3] = 24; + X.v[4] = 39; + X.v[5] = 24; + X.v[6] = 16; + X.v[7] = 12; + X.v[8] = 13; + SST_Math_Mat33uTranspose(&X,&A); + TASSERT((A.v[0])==(13),"Entry _a11 failed!"); + TASSERT((A.v[3])==(16),"Entry _a12 failed!"); + TASSERT((A.v[6])==(26),"Entry _a13 failed!"); + TASSERT((A.v[1])==(24),"Entry _a21 failed!"); + TASSERT((A.v[4])==(39),"Entry _a22 failed!"); + TASSERT((A.v[7])==(24),"Entry _a23 failed!"); + TASSERT((A.v[2])==(16),"Entry _a31 failed!"); + TASSERT((A.v[5])==(12),"Entry _a32 failed!"); + TASSERT((A.v[8])==(13),"Entry _a33 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat33uTransposeLocal(){ + SST_Mat33u X; /* 3 x 3 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = 35; + X.v[1] = 15; + X.v[2] = 2; + X.v[3] = 17; + X.v[4] = 31; + X.v[5] = 13; + X.v[6] = 22; + X.v[7] = 14; + X.v[8] = 21; + SST_Math_Mat33uTransposeLocal(&X); + TASSERT((X.v[0])==(35),"Entry _a11 failed!"); + TASSERT((X.v[3])==(15),"Entry _a12 failed!"); + TASSERT((X.v[6])==(2),"Entry _a13 failed!"); + TASSERT((X.v[1])==(17),"Entry _a21 failed!"); + TASSERT((X.v[4])==(31),"Entry _a22 failed!"); + TASSERT((X.v[7])==(13),"Entry _a23 failed!"); + TASSERT((X.v[2])==(22),"Entry _a31 failed!"); + TASSERT((X.v[5])==(14),"Entry _a32 failed!"); + TASSERT((X.v[8])==(21),"Entry _a33 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + diff --git a/ZTestSuite/Test-SST_Mat44d.cpp b/ZTestSuite/Test-SST_Mat44d.cpp new file mode 100644 index 0000000..32bd7e2 --- /dev/null +++ b/ZTestSuite/Test-SST_Mat44d.cpp @@ -0,0 +1,1435 @@ +/* + AUTOMATICALLY GENERATED FILE - DO NOT EDIT! + Please change MatrixNxN.py and re-run it +*/ +/* Generated with ./MatrixNxN.py n = 4, TYPE = double */ + +#include "ZUnitTest.hpp" +#include <float.h> +#include <math.h> +#include <stdlib.h> +#include <stdio.h> +#include <SST/SST_Mat44.h> +#include <SST/SST_Vec4.h> + + + + +static const char* testSST_Math_Mat44dAdd(); +static const char* testSST_Math_Mat44dAddLocal(); +static const char* testSST_Math_Mat44dSubtract(); +static const char* testSST_Math_Mat44dSubtractLocal(); +static const char* testSST_Math_Mat44dMultiplyElementwise(); +static const char* testSST_Math_Mat44dMultiplyElementwiseLocal(); +static const char* testSST_Math_Mat44dMultiplyScalar(); +static const char* testSST_Math_Mat44dMultiplyScalarLocal(); +static const char* testSST_Math_Mat44dMultiplyMatrix(); +static const char* testSST_Math_Mat44dMultiplyMatrixLocal(); +static const char* testSST_Math_Mat44dMultiplyVector(); +static const char* testSST_Math_Mat44dMultiplyVectorLocal(); +static const char* testSST_Math_Mat44dTranspose(); +static const char* testSST_Math_Mat44dTransposeLocal(); +static const char* testSST_Math_Mat44dDeterminant(); +static const char* testSST_Math_Mat44dCheckOrthonormal(); +static const char* testSST_Math_Mat44dInvert(); +static const char* testSST_Math_Mat44dInvertLocal(); +static const char* testSST_Math_Mat44dCreateLU(); +static const char* testSST_Math_Mat44dCreateLULocal(); +static const char* testSST_Math_Mat44dApplyLUMat(); +static const char* testSST_Math_Mat44dApplyLUMatLocal(); +static const char* testSST_Math_Mat44dApplyLUVec(); +static const char* testSST_Math_Mat44dApplyLUVecLocal(); +// List of unit tests +ZUnitTest SST_Math_Mat44dUnitTests[] = +{ +{ "testSST_Math_Mat44dAdd " , testSST_Math_Mat44dAdd }, +{ "testSST_Math_Mat44dAddLocal " , testSST_Math_Mat44dAddLocal }, +{ "testSST_Math_Mat44dSubtract " , testSST_Math_Mat44dSubtract }, +{ "testSST_Math_Mat44dSubtractLocal " , testSST_Math_Mat44dSubtractLocal }, +{ "testSST_Math_Mat44dMultiplyElementwise " , testSST_Math_Mat44dMultiplyElementwise }, +{ "testSST_Math_Mat44dMultiplyElementwiseLocal " , testSST_Math_Mat44dMultiplyElementwiseLocal }, +{ "testSST_Math_Mat44dMultiplyScalar " , testSST_Math_Mat44dMultiplyScalar }, +{ "testSST_Math_Mat44dMultiplyScalarLocal " , testSST_Math_Mat44dMultiplyScalarLocal }, +{ "testSST_Math_Mat44dMultiplyMatrix " , testSST_Math_Mat44dMultiplyMatrix }, +{ "testSST_Math_Mat44dMultiplyMatrixLocal " , testSST_Math_Mat44dMultiplyMatrixLocal }, +{ "testSST_Math_Mat44dMultiplyVector " , testSST_Math_Mat44dMultiplyVector }, +{ "testSST_Math_Mat44dMultiplyVectorLocal " , testSST_Math_Mat44dMultiplyVectorLocal }, +{ "testSST_Math_Mat44dDeterminant " , testSST_Math_Mat44dDeterminant }, +{ "testSST_Math_Mat44dCheckOrthonormal " , testSST_Math_Mat44dCheckOrthonormal }, +{ "testSST_Math_Mat44dInvert " , testSST_Math_Mat44dInvert }, +{ "testSST_Math_Mat44dInvertLocal " , testSST_Math_Mat44dInvertLocal }, +{ "testSST_Math_Mat44dCreateLU " , testSST_Math_Mat44dCreateLU }, +{ "testSST_Math_Mat44dCreateLULocal " , testSST_Math_Mat44dCreateLULocal }, +{ "testSST_Math_Mat44dApplyLUMat " , testSST_Math_Mat44dApplyLUMat }, +{ "testSST_Math_Mat44dApplyLUMatLocal " , testSST_Math_Mat44dApplyLUMatLocal }, +{ "testSST_Math_Mat44dApplyLUVec " , testSST_Math_Mat44dApplyLUVec }, +{ "testSST_Math_Mat44dApplyLUVecLocal " , testSST_Math_Mat44dApplyLUVecLocal }, +{ "testSST_Math_Mat44dTranspose " , testSST_Math_Mat44dTranspose }, +{ "testSST_Math_Mat44dTransposeLocal " , testSST_Math_Mat44dTransposeLocal } +}; +DECLARE_ZTESTBLOCK(SST_Math_Mat44d) + +/******************************************************************************/ + +static const char* testSST_Math_Mat44dAdd(){ + SST_Mat44d X; /* 4 x 4 matrix */ + SST_Mat44d Y; /* 4 x 4 matrix */ + SST_Mat44d A; /* 4 x 4 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = -1.000000000000000; + X.v[1] = 19.000000000000000; + X.v[2] = 5.000000000000000; + X.v[3] = -2.000000000000000; + X.v[4] = -18.000000000000000; + X.v[5] = 7.000000000000000; + X.v[6] = 13.000000000000000; + X.v[7] = -10.000000000000000; + X.v[8] = -8.000000000000000; + X.v[9] = -20.000000000000000; + X.v[10] = 3.000000000000000; + X.v[11] = -8.000000000000000; + X.v[12] = 15.000000000000000; + X.v[13] = -6.000000000000000; + X.v[14] = 7.000000000000000; + X.v[15] = 16.000000000000000; + Y.v[0] = 18.000000000000000; + Y.v[1] = 8.000000000000000; + Y.v[2] = 1.000000000000000; + Y.v[3] = 16.000000000000000; + Y.v[4] = 15.000000000000000; + Y.v[5] = 11.000000000000000; + Y.v[6] = -12.000000000000000; + Y.v[7] = 14.000000000000000; + Y.v[8] = 11.000000000000000; + Y.v[9] = -5.000000000000000; + Y.v[10] = -18.000000000000000; + Y.v[11] = 8.000000000000000; + Y.v[12] = -4.000000000000000; + Y.v[13] = -7.000000000000000; + Y.v[14] = 14.000000000000000; + Y.v[15] = -15.000000000000000; +/* +[[ -1. -18. -8. 15.] + [ 19. 7. -20. -6.] + [ 5. 13. 3. 7.] + [ -2. -10. -8. 16.]] +[[ 18. 15. 11. -4.] + [ 8. 11. -5. -7.] + [ 1. -12. -18. 14.] + [ 16. 14. 8. -15.]] +[[ 17. -3. 3. 11.] + [ 27. 18. -25. -13.] + [ 6. 1. -15. 21.] + [ 14. 4. 0. 1.]] +*/ + SST_Math_Mat44dAdd(&X,&Y,&A); + TASSERT(fabs((A.v[0])-( 17.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a11 failed!"); + TASSERT(fabs((A.v[4])-( -3.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a12 failed!"); + TASSERT(fabs((A.v[8])-( 3.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a13 failed!"); + TASSERT(fabs((A.v[12])-( 11.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a14 failed!"); + TASSERT(fabs((A.v[1])-( 27.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a21 failed!"); + TASSERT(fabs((A.v[5])-( 18.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a22 failed!"); + TASSERT(fabs((A.v[9])-( -25.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a23 failed!"); + TASSERT(fabs((A.v[13])-( -13.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a24 failed!"); + TASSERT(fabs((A.v[2])-( 6.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a31 failed!"); + TASSERT(fabs((A.v[6])-( 1.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a32 failed!"); + TASSERT(fabs((A.v[10])-( -15.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a33 failed!"); + TASSERT(fabs((A.v[14])-( 21.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a34 failed!"); + TASSERT(fabs((A.v[3])-( 14.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a41 failed!"); + TASSERT(fabs((A.v[7])-( 4.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a42 failed!"); + TASSERT(fabs((A.v[11])-( 0.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a43 failed!"); + TASSERT(fabs((A.v[15])-( 1.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a44 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat44dAddLocal(){ + SST_Mat44d X; /* 4 x 4 matrix */ + SST_Mat44d Y; /* 4 x 4 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = -10.000000000000000; + X.v[1] = -8.000000000000000; + X.v[2] = -5.000000000000000; + X.v[3] = 19.000000000000000; + X.v[4] = -1.000000000000000; + X.v[5] = -15.000000000000000; + X.v[6] = -5.000000000000000; + X.v[7] = -17.000000000000000; + X.v[8] = -14.000000000000000; + X.v[9] = 15.000000000000000; + X.v[10] = 6.000000000000000; + X.v[11] = -13.000000000000000; + X.v[12] = 14.000000000000000; + X.v[13] = -5.000000000000000; + X.v[14] = -5.000000000000000; + X.v[15] = -14.000000000000000; + Y.v[0] = -5.000000000000000; + Y.v[1] = -8.000000000000000; + Y.v[2] = 12.000000000000000; + Y.v[3] = -18.000000000000000; + Y.v[4] = -15.000000000000000; + Y.v[5] = -14.000000000000000; + Y.v[6] = -3.000000000000000; + Y.v[7] = -5.000000000000000; + Y.v[8] = 17.000000000000000; + Y.v[9] = -16.000000000000000; + Y.v[10] = 16.000000000000000; + Y.v[11] = -7.000000000000000; + Y.v[12] = -3.000000000000000; + Y.v[13] = 4.000000000000000; + Y.v[14] = -9.000000000000000; + Y.v[15] = 9.000000000000000; +/* +[[-10. -1. -14. 14.] + [ -8. -15. 15. -5.] + [ -5. -5. 6. -5.] + [ 19. -17. -13. -14.]] +[[ -5. -15. 17. -3.] + [ -8. -14. -16. 4.] + [ 12. -3. 16. -9.] + [-18. -5. -7. 9.]] +[[-15. -16. 3. 11.] + [-16. -29. -1. -1.] + [ 7. -8. 22. -14.] + [ 1. -22. -20. -5.]] +*/ + SST_Math_Mat44dAddLocal(&X,&Y); /* for accuracy */ + TASSERT(fabs((X.v[0])-( -15.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a11 failed!"); + TASSERT(fabs((X.v[4])-( -16.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a12 failed!"); + TASSERT(fabs((X.v[8])-( 3.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a13 failed!"); + TASSERT(fabs((X.v[12])-( 11.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a14 failed!"); + TASSERT(fabs((X.v[1])-( -16.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a21 failed!"); + TASSERT(fabs((X.v[5])-( -29.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a22 failed!"); + TASSERT(fabs((X.v[9])-( -1.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a23 failed!"); + TASSERT(fabs((X.v[13])-( -1.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a24 failed!"); + TASSERT(fabs((X.v[2])-( 7.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a31 failed!"); + TASSERT(fabs((X.v[6])-( -8.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a32 failed!"); + TASSERT(fabs((X.v[10])-( 22.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a33 failed!"); + TASSERT(fabs((X.v[14])-( -14.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a34 failed!"); + TASSERT(fabs((X.v[3])-( 1.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a41 failed!"); + TASSERT(fabs((X.v[7])-( -22.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a42 failed!"); + TASSERT(fabs((X.v[11])-( -20.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a43 failed!"); + TASSERT(fabs((X.v[15])-( -5.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a44 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat44dSubtract(){ + SST_Mat44d X; /* 4 x 4 matrix */ + SST_Mat44d Y; /* 4 x 4 matrix */ + SST_Mat44d A; /* 4 x 4 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = -11.000000000000000; + X.v[1] = 13.000000000000000; + X.v[2] = 7.000000000000000; + X.v[3] = -14.000000000000000; + X.v[4] = 8.000000000000000; + X.v[5] = 6.000000000000000; + X.v[6] = -14.000000000000000; + X.v[7] = 4.000000000000000; + X.v[8] = 15.000000000000000; + X.v[9] = 17.000000000000000; + X.v[10] = -12.000000000000000; + X.v[11] = 14.000000000000000; + X.v[12] = -1.000000000000000; + X.v[13] = 8.000000000000000; + X.v[14] = -5.000000000000000; + X.v[15] = -12.000000000000000; + Y.v[0] = -1.000000000000000; + Y.v[1] = -17.000000000000000; + Y.v[2] = -4.000000000000000; + Y.v[3] = -16.000000000000000; + Y.v[4] = 7.000000000000000; + Y.v[5] = -6.000000000000000; + Y.v[6] = -1.000000000000000; + Y.v[7] = 2.000000000000000; + Y.v[8] = 1.000000000000000; + Y.v[9] = -15.000000000000000; + Y.v[10] = -6.000000000000000; + Y.v[11] = 5.000000000000000; + Y.v[12] = -1.000000000000000; + Y.v[13] = -19.000000000000000; + Y.v[14] = -5.000000000000000; + Y.v[15] = -20.000000000000000; +/* +[[-11. 8. 15. -1.] + [ 13. 6. 17. 8.] + [ 7. -14. -12. -5.] + [-14. 4. 14. -12.]] +[[ -1. 7. 1. -1.] + [-17. -6. -15. -19.] + [ -4. -1. -6. -5.] + [-16. 2. 5. -20.]] +[[-10. 1. 14. 0.] + [ 30. 12. 32. 27.] + [ 11. -13. -6. 0.] + [ 2. 2. 9. 8.]] +*/ + SST_Math_Mat44dSubtract(&X,&Y,&A); + TASSERT(fabs((A.v[0])-( -10.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a11 failed!"); + TASSERT(fabs((A.v[4])-( 1.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a12 failed!"); + TASSERT(fabs((A.v[8])-( 14.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a13 failed!"); + TASSERT(fabs((A.v[12])-( 0.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a14 failed!"); + TASSERT(fabs((A.v[1])-( 30.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a21 failed!"); + TASSERT(fabs((A.v[5])-( 12.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a22 failed!"); + TASSERT(fabs((A.v[9])-( 32.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a23 failed!"); + TASSERT(fabs((A.v[13])-( 27.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a24 failed!"); + TASSERT(fabs((A.v[2])-( 11.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a31 failed!"); + TASSERT(fabs((A.v[6])-( -13.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a32 failed!"); + TASSERT(fabs((A.v[10])-( -6.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a33 failed!"); + TASSERT(fabs((A.v[14])-( 0.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a34 failed!"); + TASSERT(fabs((A.v[3])-( 2.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a41 failed!"); + TASSERT(fabs((A.v[7])-( 2.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a42 failed!"); + TASSERT(fabs((A.v[11])-( 9.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a43 failed!"); + TASSERT(fabs((A.v[15])-( 8.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a44 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat44dSubtractLocal(){ + SST_Mat44d X; /* 4 x 4 matrix */ + SST_Mat44d Y; /* 4 x 4 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = 17.000000000000000; + X.v[1] = -19.000000000000000; + X.v[2] = -12.000000000000000; + X.v[3] = 8.000000000000000; + X.v[4] = -8.000000000000000; + X.v[5] = -16.000000000000000; + X.v[6] = 7.000000000000000; + X.v[7] = 2.000000000000000; + X.v[8] = -2.000000000000000; + X.v[9] = 3.000000000000000; + X.v[10] = -12.000000000000000; + X.v[11] = -11.000000000000000; + X.v[12] = -6.000000000000000; + X.v[13] = -20.000000000000000; + X.v[14] = 5.000000000000000; + X.v[15] = -17.000000000000000; + Y.v[0] = -7.000000000000000; + Y.v[1] = 18.000000000000000; + Y.v[2] = -18.000000000000000; + Y.v[3] = 15.000000000000000; + Y.v[4] = -14.000000000000000; + Y.v[5] = -19.000000000000000; + Y.v[6] = -14.000000000000000; + Y.v[7] = 8.000000000000000; + Y.v[8] = 3.000000000000000; + Y.v[9] = 8.000000000000000; + Y.v[10] = -5.000000000000000; + Y.v[11] = 10.000000000000000; + Y.v[12] = 13.000000000000000; + Y.v[13] = 3.000000000000000; + Y.v[14] = -5.000000000000000; + Y.v[15] = 15.000000000000000; +/* +[[ 17. -8. -2. -6.] + [-19. -16. 3. -20.] + [-12. 7. -12. 5.] + [ 8. 2. -11. -17.]] +[[ -7. -14. 3. 13.] + [ 18. -19. 8. 3.] + [-18. -14. -5. -5.] + [ 15. 8. 10. 15.]] +[[ 24. 6. -5. -19.] + [-37. 3. -5. -23.] + [ 6. 21. -7. 10.] + [ -7. -6. -21. -32.]] +*/ + SST_Math_Mat44dSubtractLocal(&X,&Y); /* for accuracy */ + TASSERT(fabs((X.v[0])-( 24.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a11 failed!"); + TASSERT(fabs((X.v[4])-( 6.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a12 failed!"); + TASSERT(fabs((X.v[8])-( -5.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a13 failed!"); + TASSERT(fabs((X.v[12])-( -19.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a14 failed!"); + TASSERT(fabs((X.v[1])-( -37.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a21 failed!"); + TASSERT(fabs((X.v[5])-( 3.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a22 failed!"); + TASSERT(fabs((X.v[9])-( -5.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a23 failed!"); + TASSERT(fabs((X.v[13])-( -23.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a24 failed!"); + TASSERT(fabs((X.v[2])-( 6.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a31 failed!"); + TASSERT(fabs((X.v[6])-( 21.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a32 failed!"); + TASSERT(fabs((X.v[10])-( -7.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a33 failed!"); + TASSERT(fabs((X.v[14])-( 10.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a34 failed!"); + TASSERT(fabs((X.v[3])-( -7.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a41 failed!"); + TASSERT(fabs((X.v[7])-( -6.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a42 failed!"); + TASSERT(fabs((X.v[11])-( -21.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a43 failed!"); + TASSERT(fabs((X.v[15])-( -32.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a44 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat44dMultiplyElementwise(){ + SST_Mat44d X; /* 4 x 4 matrix */ + SST_Mat44d Y; /* 4 x 4 matrix */ + SST_Mat44d A; /* 4 x 4 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = 9.000000000000000; + X.v[1] = 9.000000000000000; + X.v[2] = -5.000000000000000; + X.v[3] = -10.000000000000000; + X.v[4] = 2.000000000000000; + X.v[5] = -13.000000000000000; + X.v[6] = 17.000000000000000; + X.v[7] = 17.000000000000000; + X.v[8] = 16.000000000000000; + X.v[9] = 1.000000000000000; + X.v[10] = -20.000000000000000; + X.v[11] = -15.000000000000000; + X.v[12] = 7.000000000000000; + X.v[13] = 6.000000000000000; + X.v[14] = 18.000000000000000; + X.v[15] = 0.000000000000000; + Y.v[0] = 8.000000000000000; + Y.v[1] = 5.000000000000000; + Y.v[2] = 16.000000000000000; + Y.v[3] = -9.000000000000000; + Y.v[4] = -5.000000000000000; + Y.v[5] = -9.000000000000000; + Y.v[6] = -8.000000000000000; + Y.v[7] = -17.000000000000000; + Y.v[8] = 8.000000000000000; + Y.v[9] = 17.000000000000000; + Y.v[10] = 19.000000000000000; + Y.v[11] = -14.000000000000000; + Y.v[12] = 15.000000000000000; + Y.v[13] = -1.000000000000000; + Y.v[14] = 14.000000000000000; + Y.v[15] = 2.000000000000000; +/* +[[ 9. 2. 16. 7.] + [ 9. -13. 1. 6.] + [ -5. 17. -20. 18.] + [-10. 17. -15. 0.]] +[[ 8. -5. 8. 15.] + [ 5. -9. 17. -1.] + [ 16. -8. 19. 14.] + [ -9. -17. -14. 2.]] +[[ 72. -10. 128. 105.] + [ 45. 117. 17. -6.] + [ -80. -136. -380. 252.] + [ 90. -289. 210. 0.]] +*/ + SST_Math_Mat44dMultiplyElementwise(&X, &Y, &A); + TASSERT(fabs((A.v[0])-( 72.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a11 failed!"); + TASSERT(fabs((A.v[4])-( -10.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a12 failed!"); + TASSERT(fabs((A.v[8])-( 128.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a13 failed!"); + TASSERT(fabs((A.v[12])-( 105.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a14 failed!"); + TASSERT(fabs((A.v[1])-( 45.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a21 failed!"); + TASSERT(fabs((A.v[5])-( 117.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a22 failed!"); + TASSERT(fabs((A.v[9])-( 17.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a23 failed!"); + TASSERT(fabs((A.v[13])-( -6.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a24 failed!"); + TASSERT(fabs((A.v[2])-( -80.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a31 failed!"); + TASSERT(fabs((A.v[6])-( -136.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a32 failed!"); + TASSERT(fabs((A.v[10])-( -380.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a33 failed!"); + TASSERT(fabs((A.v[14])-( 252.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a34 failed!"); + TASSERT(fabs((A.v[3])-( 90.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a41 failed!"); + TASSERT(fabs((A.v[7])-( -289.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a42 failed!"); + TASSERT(fabs((A.v[11])-( 210.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a43 failed!"); + TASSERT(fabs((A.v[15])-( 0.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a44 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat44dMultiplyElementwiseLocal(){ + SST_Mat44d X; /* 4 x 4 matrix */ + SST_Mat44d Y; /* 4 x 4 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = -1.000000000000000; + X.v[1] = 14.000000000000000; + X.v[2] = -8.000000000000000; + X.v[3] = -12.000000000000000; + X.v[4] = -4.000000000000000; + X.v[5] = -3.000000000000000; + X.v[6] = 10.000000000000000; + X.v[7] = 16.000000000000000; + X.v[8] = 0.000000000000000; + X.v[9] = -13.000000000000000; + X.v[10] = -3.000000000000000; + X.v[11] = -20.000000000000000; + X.v[12] = 4.000000000000000; + X.v[13] = -19.000000000000000; + X.v[14] = -18.000000000000000; + X.v[15] = -14.000000000000000; + Y.v[0] = -7.000000000000000; + Y.v[1] = -7.000000000000000; + Y.v[2] = -1.000000000000000; + Y.v[3] = -13.000000000000000; + Y.v[4] = 12.000000000000000; + Y.v[5] = -18.000000000000000; + Y.v[6] = -7.000000000000000; + Y.v[7] = 5.000000000000000; + Y.v[8] = -11.000000000000000; + Y.v[9] = -17.000000000000000; + Y.v[10] = -14.000000000000000; + Y.v[11] = -5.000000000000000; + Y.v[12] = 2.000000000000000; + Y.v[13] = 4.000000000000000; + Y.v[14] = -15.000000000000000; + Y.v[15] = -15.000000000000000; +/* +[[ -1. -4. 0. 4.] + [ 14. -3. -13. -19.] + [ -8. 10. -3. -18.] + [-12. 16. -20. -14.]] +[[ -7. 12. -11. 2.] + [ -7. -18. -17. 4.] + [ -1. -7. -14. -15.] + [-13. 5. -5. -15.]] +[[ 7. -48. -0. 8.] + [ -98. 54. 221. -76.] + [ 8. -70. 42. 270.] + [ 156. 80. 100. 210.]] +*/ + SST_Math_Mat44dMultiplyElementwiseLocal(&X,&Y); + TASSERT(fabs((X.v[0])-( 7.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a11 failed!"); + TASSERT(fabs((X.v[4])-( -48.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a12 failed!"); + TASSERT(fabs((X.v[8])-( -0.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a13 failed!"); + TASSERT(fabs((X.v[12])-( 8.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a14 failed!"); + TASSERT(fabs((X.v[1])-( -98.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a21 failed!"); + TASSERT(fabs((X.v[5])-( 54.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a22 failed!"); + TASSERT(fabs((X.v[9])-( 221.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a23 failed!"); + TASSERT(fabs((X.v[13])-( -76.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a24 failed!"); + TASSERT(fabs((X.v[2])-( 8.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a31 failed!"); + TASSERT(fabs((X.v[6])-( -70.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a32 failed!"); + TASSERT(fabs((X.v[10])-( 42.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a33 failed!"); + TASSERT(fabs((X.v[14])-( 270.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a34 failed!"); + TASSERT(fabs((X.v[3])-( 156.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a41 failed!"); + TASSERT(fabs((X.v[7])-( 80.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a42 failed!"); + TASSERT(fabs((X.v[11])-( 100.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a43 failed!"); + TASSERT(fabs((X.v[15])-( 210.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a44 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat44dMultiplyScalar(){ + SST_Mat44d X; /* 4 x 4 matrix */ + SST_Mat44d A; /* 4 x 4 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = -11.000000000000000; + X.v[1] = 8.000000000000000; + X.v[2] = 9.000000000000000; + X.v[3] = 8.000000000000000; + X.v[4] = -1.000000000000000; + X.v[5] = -8.000000000000000; + X.v[6] = -20.000000000000000; + X.v[7] = 9.000000000000000; + X.v[8] = 16.000000000000000; + X.v[9] = -2.000000000000000; + X.v[10] = -13.000000000000000; + X.v[11] = -3.000000000000000; + X.v[12] = -7.000000000000000; + X.v[13] = -8.000000000000000; + X.v[14] = 14.000000000000000; + X.v[15] = -9.000000000000000; +/* +[[-11. -1. 16. -7.] + [ 8. -8. -2. -8.] + [ 9. -20. -13. 14.] + [ 8. 9. -3. -9.]] +[[-22. -2. 32. -14.] + [ 16. -16. -4. -16.] + [ 18. -40. -26. 28.] + [ 16. 18. -6. -18.]] +*/ + SST_Math_Mat44dMultiplyScalar(&X, 2.000000000000000,&A); + TASSERT(fabs((A.v[0])-( -22.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a11 failed!"); + TASSERT(fabs((A.v[4])-( -2.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a12 failed!"); + TASSERT(fabs((A.v[8])-( 32.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a13 failed!"); + TASSERT(fabs((A.v[12])-( -14.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a14 failed!"); + TASSERT(fabs((A.v[1])-( 16.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a21 failed!"); + TASSERT(fabs((A.v[5])-( -16.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a22 failed!"); + TASSERT(fabs((A.v[9])-( -4.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a23 failed!"); + TASSERT(fabs((A.v[13])-( -16.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a24 failed!"); + TASSERT(fabs((A.v[2])-( 18.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a31 failed!"); + TASSERT(fabs((A.v[6])-( -40.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a32 failed!"); + TASSERT(fabs((A.v[10])-( -26.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a33 failed!"); + TASSERT(fabs((A.v[14])-( 28.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a34 failed!"); + TASSERT(fabs((A.v[3])-( 16.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a41 failed!"); + TASSERT(fabs((A.v[7])-( 18.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a42 failed!"); + TASSERT(fabs((A.v[11])-( -6.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a43 failed!"); + TASSERT(fabs((A.v[15])-( -18.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a44 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat44dMultiplyScalarLocal(){ + SST_Mat44d X; /* 4 x 4 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = -14.000000000000000; + X.v[1] = 7.000000000000000; + X.v[2] = -15.000000000000000; + X.v[3] = 10.000000000000000; + X.v[4] = 1.000000000000000; + X.v[5] = -12.000000000000000; + X.v[6] = 3.000000000000000; + X.v[7] = -1.000000000000000; + X.v[8] = -7.000000000000000; + X.v[9] = 19.000000000000000; + X.v[10] = -15.000000000000000; + X.v[11] = 3.000000000000000; + X.v[12] = -1.000000000000000; + X.v[13] = -4.000000000000000; + X.v[14] = 2.000000000000000; + X.v[15] = 4.000000000000000; +/* +[[-14. 1. -7. -1.] + [ 7. -12. 19. -4.] + [-15. 3. -15. 2.] + [ 10. -1. 3. 4.]] +[[-28. 2. -14. -2.] + [ 14. -24. 38. -8.] + [-30. 6. -30. 4.] + [ 20. -2. 6. 8.]] +*/ + SST_Math_Mat44dMultiplyScalarLocal(&X, 2.000000000000000); + TASSERT(fabs((X.v[0])-( -28.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a11 failed!"); + TASSERT(fabs((X.v[4])-( 2.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a12 failed!"); + TASSERT(fabs((X.v[8])-( -14.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a13 failed!"); + TASSERT(fabs((X.v[12])-( -2.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a14 failed!"); + TASSERT(fabs((X.v[1])-( 14.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a21 failed!"); + TASSERT(fabs((X.v[5])-( -24.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a22 failed!"); + TASSERT(fabs((X.v[9])-( 38.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a23 failed!"); + TASSERT(fabs((X.v[13])-( -8.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a24 failed!"); + TASSERT(fabs((X.v[2])-( -30.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a31 failed!"); + TASSERT(fabs((X.v[6])-( 6.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a32 failed!"); + TASSERT(fabs((X.v[10])-( -30.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a33 failed!"); + TASSERT(fabs((X.v[14])-( 4.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a34 failed!"); + TASSERT(fabs((X.v[3])-( 20.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a41 failed!"); + TASSERT(fabs((X.v[7])-( -2.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a42 failed!"); + TASSERT(fabs((X.v[11])-( 6.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a43 failed!"); + TASSERT(fabs((X.v[15])-( 8.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a44 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat44dMultiplyMatrix(){ + SST_Mat44d X; /* 4 x 4 matrix */ + SST_Mat44d Y; /* 4 x 4 matrix */ + SST_Mat44d A; /* 4 x 4 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = -9.000000000000000; + X.v[1] = 11.000000000000000; + X.v[2] = -6.000000000000000; + X.v[3] = -4.000000000000000; + X.v[4] = 18.000000000000000; + X.v[5] = 3.000000000000000; + X.v[6] = 18.000000000000000; + X.v[7] = -17.000000000000000; + X.v[8] = -12.000000000000000; + X.v[9] = 14.000000000000000; + X.v[10] = -2.000000000000000; + X.v[11] = 8.000000000000000; + X.v[12] = 0.000000000000000; + X.v[13] = -13.000000000000000; + X.v[14] = 11.000000000000000; + X.v[15] = 0.000000000000000; + Y.v[0] = 11.000000000000000; + Y.v[1] = -16.000000000000000; + Y.v[2] = 11.000000000000000; + Y.v[3] = -20.000000000000000; + Y.v[4] = -7.000000000000000; + Y.v[5] = -3.000000000000000; + Y.v[6] = 9.000000000000000; + Y.v[7] = 16.000000000000000; + Y.v[8] = 5.000000000000000; + Y.v[9] = -9.000000000000000; + Y.v[10] = -7.000000000000000; + Y.v[11] = -19.000000000000000; + Y.v[12] = -5.000000000000000; + Y.v[13] = 19.000000000000000; + Y.v[14] = 10.000000000000000; + Y.v[15] = 6.000000000000000; +/* +X +[[ -9. 18. -12. 0.] + [ 11. 3. 14. -13.] + [ -6. 18. -2. 11.] + [ -4. -17. 8. 0.]] +Y +[[ 11. -7. 5. -5.] + [-16. -3. -9. 19.] + [ 11. 9. -7. 10.] + [-20. 16. -19. 6.]] +[[-519. -99. -123. 267.] + [ 487. -168. 177. 64.] + [-596. 146. -387. 418.] + [ 316. 151. 77. -223.]] +*/ + SST_Math_Mat44dMultiplyMatrix(&X,&Y,&A); + TASSERT(fabs((A.v[0])-( -519.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a11 failed!"); + TASSERT(fabs((A.v[4])-( -99.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a12 failed!"); + TASSERT(fabs((A.v[8])-( -123.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a13 failed!"); + TASSERT(fabs((A.v[12])-( 267.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a14 failed!"); + TASSERT(fabs((A.v[1])-( 487.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a21 failed!"); + TASSERT(fabs((A.v[5])-( -168.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a22 failed!"); + TASSERT(fabs((A.v[9])-( 177.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a23 failed!"); + TASSERT(fabs((A.v[13])-( 64.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a24 failed!"); + TASSERT(fabs((A.v[2])-( -596.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a31 failed!"); + TASSERT(fabs((A.v[6])-( 146.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a32 failed!"); + TASSERT(fabs((A.v[10])-( -387.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a33 failed!"); + TASSERT(fabs((A.v[14])-( 418.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a34 failed!"); + TASSERT(fabs((A.v[3])-( 316.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a41 failed!"); + TASSERT(fabs((A.v[7])-( 151.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a42 failed!"); + TASSERT(fabs((A.v[11])-( 77.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a43 failed!"); + TASSERT(fabs((A.v[15])-( -223.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a44 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat44dMultiplyMatrixLocal(){ + SST_Mat44d X; /* 4 x 4 matrix */ + SST_Mat44d Y; /* 4 x 4 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = -14.000000000000000; + X.v[1] = 0.000000000000000; + X.v[2] = -17.000000000000000; + X.v[3] = -11.000000000000000; + X.v[4] = -20.000000000000000; + X.v[5] = 3.000000000000000; + X.v[6] = -6.000000000000000; + X.v[7] = 11.000000000000000; + X.v[8] = 13.000000000000000; + X.v[9] = 7.000000000000000; + X.v[10] = -9.000000000000000; + X.v[11] = 12.000000000000000; + X.v[12] = -18.000000000000000; + X.v[13] = -18.000000000000000; + X.v[14] = -3.000000000000000; + X.v[15] = -4.000000000000000; + Y.v[0] = 0.000000000000000; + Y.v[1] = -10.000000000000000; + Y.v[2] = 7.000000000000000; + Y.v[3] = 5.000000000000000; + Y.v[4] = -15.000000000000000; + Y.v[5] = -14.000000000000000; + Y.v[6] = 19.000000000000000; + Y.v[7] = 17.000000000000000; + Y.v[8] = 0.000000000000000; + Y.v[9] = -8.000000000000000; + Y.v[10] = 16.000000000000000; + Y.v[11] = -5.000000000000000; + Y.v[12] = -12.000000000000000; + Y.v[13] = 19.000000000000000; + Y.v[14] = -8.000000000000000; + Y.v[15] = 3.000000000000000; +/* +X +[[-14. -20. 13. -18.] + [ 0. 3. 7. -18.] + [-17. -6. -9. -3.] + [-11. 11. 12. -4.]] +Y +[[ 0. -15. 0. -12.] + [-10. -14. -8. 19.] + [ 7. 19. 16. -8.] + [ 5. 17. -5. 3.]] +X +[[ 201. 431. 458. -370.] + [ -71. -215. 178. -53.] + [ -18. 117. -81. 153.] + [ -46. 171. 124. 233.]] +*/ + SST_Math_Mat44dMultiplyMatrixLocal(&X,&Y); + TASSERT(fabs((X.v[0])-( 201.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a11 failed!"); + TASSERT(fabs((X.v[4])-( 431.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a12 failed!"); + TASSERT(fabs((X.v[8])-( 458.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a13 failed!"); + TASSERT(fabs((X.v[12])-( -370.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a14 failed!"); + TASSERT(fabs((X.v[1])-( -71.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a21 failed!"); + TASSERT(fabs((X.v[5])-( -215.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a22 failed!"); + TASSERT(fabs((X.v[9])-( 178.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a23 failed!"); + TASSERT(fabs((X.v[13])-( -53.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a24 failed!"); + TASSERT(fabs((X.v[2])-( -18.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a31 failed!"); + TASSERT(fabs((X.v[6])-( 117.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a32 failed!"); + TASSERT(fabs((X.v[10])-( -81.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a33 failed!"); + TASSERT(fabs((X.v[14])-( 153.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a34 failed!"); + TASSERT(fabs((X.v[3])-( -46.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a41 failed!"); + TASSERT(fabs((X.v[7])-( 171.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a42 failed!"); + TASSERT(fabs((X.v[11])-( 124.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a43 failed!"); + TASSERT(fabs((X.v[15])-( 233.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a44 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat44dMultiplyVector(){ + SST_Mat44d X; /* 4 x 4 matrix */ + SST_Vec4d v; /* 4 vector */ + SST_Vec4d w; /* 4 vector */ +/* Resetting test vectors / mats */ + v.v[0] = -9.000000000000000; + v.v[1] = 10.000000000000000; + v.v[2] = -9.000000000000000; + v.v[3] = -15.000000000000000; + X.v[0] = 2.000000000000000; + X.v[1] = -9.000000000000000; + X.v[2] = 7.000000000000000; + X.v[3] = -3.000000000000000; + X.v[4] = -16.000000000000000; + X.v[5] = -9.000000000000000; + X.v[6] = 19.000000000000000; + X.v[7] = -11.000000000000000; + X.v[8] = -15.000000000000000; + X.v[9] = -4.000000000000000; + X.v[10] = 5.000000000000000; + X.v[11] = -17.000000000000000; + X.v[12] = 5.000000000000000; + X.v[13] = 17.000000000000000; + X.v[14] = 11.000000000000000; + X.v[15] = 4.000000000000000; +/* +X +[[ 2. -16. -15. 5.] + [ -9. -9. -4. 17.] + [ 7. 19. 5. 11.] + [ -3. -11. -17. 4.]] +v +[ -9. 10. -9. -15.] +w +[-118. -228. -83. 10.] +*/ + SST_Math_Mat44dMultiplyVector(&X,&v,&w); + TASSERT(fabs((w.v[0])-( -118.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry .v[0] failed!"); + TASSERT(fabs((w.v[1])-( -228.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry .v[1] failed!"); + TASSERT(fabs((w.v[2])-( -83.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry .v[2] failed!"); + TASSERT(fabs((w.v[3])-( 10.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry .v[3] failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat44dMultiplyVectorLocal(){ + SST_Mat44d X; /* 4 x 4 matrix */ + SST_Vec4d v; /* 4 vector */ +/* Resetting test vectors / mats */ + v.v[0] = -5.000000000000000; + v.v[1] = 3.000000000000000; + v.v[2] = 11.000000000000000; + v.v[3] = -4.000000000000000; + X.v[0] = -12.000000000000000; + X.v[1] = -8.000000000000000; + X.v[2] = -4.000000000000000; + X.v[3] = 19.000000000000000; + X.v[4] = -17.000000000000000; + X.v[5] = -1.000000000000000; + X.v[6] = -9.000000000000000; + X.v[7] = 7.000000000000000; + X.v[8] = 4.000000000000000; + X.v[9] = 3.000000000000000; + X.v[10] = 9.000000000000000; + X.v[11] = -13.000000000000000; + X.v[12] = 8.000000000000000; + X.v[13] = -14.000000000000000; + X.v[14] = -13.000000000000000; + X.v[15] = 8.000000000000000; +/* +X +[[-12. -17. 4. 8.] + [ -8. -1. 3. -14.] + [ -4. -9. 9. -13.] + [ 19. 7. -13. 8.]] +v +[ -5. 3. 11. -4.] +v +[ 21. 126. 144. -249.] +*/ + SST_Math_Mat44dMultiplyVectorLocal(&X,&v); + TASSERT(fabs((v.v[0])-( 21.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry .v[0] failed!"); + TASSERT(fabs((v.v[1])-( 126.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry .v[1] failed!"); + TASSERT(fabs((v.v[2])-( 144.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry .v[2] failed!"); + TASSERT(fabs((v.v[3])-( -249.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry .v[3] failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat44dTranspose(){ + SST_Mat44d X; /* 4 x 4 matrix */ + SST_Mat44d A; /* 4 x 4 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = -4.000000000000000; + X.v[1] = 16.000000000000000; + X.v[2] = -4.000000000000000; + X.v[3] = 3.000000000000000; + X.v[4] = -13.000000000000000; + X.v[5] = 2.000000000000000; + X.v[6] = 15.000000000000000; + X.v[7] = -17.000000000000000; + X.v[8] = 1.000000000000000; + X.v[9] = 9.000000000000000; + X.v[10] = -5.000000000000000; + X.v[11] = 4.000000000000000; + X.v[12] = -19.000000000000000; + X.v[13] = -17.000000000000000; + X.v[14] = 7.000000000000000; + X.v[15] = -10.000000000000000; + SST_Math_Mat44dTranspose(&X,&A); + TASSERT(fabs((A.v[0])-( -4.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a11 failed!"); + TASSERT(fabs((A.v[4])-( 16.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a12 failed!"); + TASSERT(fabs((A.v[8])-( -4.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a13 failed!"); + TASSERT(fabs((A.v[12])-( 3.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a14 failed!"); + TASSERT(fabs((A.v[1])-( -13.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a21 failed!"); + TASSERT(fabs((A.v[5])-( 2.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a22 failed!"); + TASSERT(fabs((A.v[9])-( 15.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a23 failed!"); + TASSERT(fabs((A.v[13])-( -17.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a24 failed!"); + TASSERT(fabs((A.v[2])-( 1.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a31 failed!"); + TASSERT(fabs((A.v[6])-( 9.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a32 failed!"); + TASSERT(fabs((A.v[10])-( -5.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a33 failed!"); + TASSERT(fabs((A.v[14])-( 4.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a34 failed!"); + TASSERT(fabs((A.v[3])-( -19.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a41 failed!"); + TASSERT(fabs((A.v[7])-( -17.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a42 failed!"); + TASSERT(fabs((A.v[11])-( 7.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a43 failed!"); + TASSERT(fabs((A.v[15])-( -10.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a44 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat44dTransposeLocal(){ + SST_Mat44d X; /* 4 x 4 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = 18.000000000000000; + X.v[1] = 9.000000000000000; + X.v[2] = 5.000000000000000; + X.v[3] = 10.000000000000000; + X.v[4] = 15.000000000000000; + X.v[5] = -18.000000000000000; + X.v[6] = 9.000000000000000; + X.v[7] = -5.000000000000000; + X.v[8] = -14.000000000000000; + X.v[9] = 13.000000000000000; + X.v[10] = -16.000000000000000; + X.v[11] = 3.000000000000000; + X.v[12] = -13.000000000000000; + X.v[13] = 2.000000000000000; + X.v[14] = -15.000000000000000; + X.v[15] = -4.000000000000000; + SST_Math_Mat44dTransposeLocal(&X); + TASSERT(fabs((X.v[0])-( 18.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a11 failed!"); + TASSERT(fabs((X.v[4])-( 9.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a12 failed!"); + TASSERT(fabs((X.v[8])-( 5.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a13 failed!"); + TASSERT(fabs((X.v[12])-( 10.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a14 failed!"); + TASSERT(fabs((X.v[1])-( 15.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a21 failed!"); + TASSERT(fabs((X.v[5])-( -18.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a22 failed!"); + TASSERT(fabs((X.v[9])-( 9.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a23 failed!"); + TASSERT(fabs((X.v[13])-( -5.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a24 failed!"); + TASSERT(fabs((X.v[2])-( -14.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a31 failed!"); + TASSERT(fabs((X.v[6])-( 13.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a32 failed!"); + TASSERT(fabs((X.v[10])-( -16.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a33 failed!"); + TASSERT(fabs((X.v[14])-( 3.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a34 failed!"); + TASSERT(fabs((X.v[3])-( -13.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a41 failed!"); + TASSERT(fabs((X.v[7])-( 2.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a42 failed!"); + TASSERT(fabs((X.v[11])-( -15.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a43 failed!"); + TASSERT(fabs((X.v[15])-( -4.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a44 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat44dCheckOrthonormal(){ + SST_Mat44d X; /* 4 x 4 matrix */ + SST_Mat44d Y; /* 4 x 4 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = 13.000000000000000; + X.v[1] = 5.000000000000000; + X.v[2] = 6.000000000000000; + X.v[3] = -8.000000000000000; + X.v[4] = -13.000000000000000; + X.v[5] = 0.000000000000000; + X.v[6] = 0.000000000000000; + X.v[7] = 18.000000000000000; + X.v[8] = -9.000000000000000; + X.v[9] = 18.000000000000000; + X.v[10] = -2.000000000000000; + X.v[11] = -4.000000000000000; + X.v[12] = 5.000000000000000; + X.v[13] = -8.000000000000000; + X.v[14] = 9.000000000000000; + X.v[15] = 4.000000000000000; + Y.v[0] = 3.000000000000000; + Y.v[1] = 15.000000000000000; + Y.v[2] = 15.000000000000000; + Y.v[3] = -8.000000000000000; + Y.v[4] = 12.000000000000000; + Y.v[5] = 17.000000000000000; + Y.v[6] = -10.000000000000000; + Y.v[7] = -11.000000000000000; + Y.v[8] = 15.000000000000000; + Y.v[9] = 12.000000000000000; + Y.v[10] = -7.000000000000000; + Y.v[11] = 11.000000000000000; + Y.v[12] = -10.000000000000000; + Y.v[13] = 15.000000000000000; + Y.v[14] = 3.000000000000000; + Y.v[15] = 13.000000000000000; +/* +[[-0.7581754 -0.06646594 -0.43576095 0.48048387] + [-0.29160592 -0.42113034 0.82701602 0.23164571] + [-0.34992711 -0.5053564 -0.16465295 -0.7713983 ] + [ 0.46656947 -0.75023091 -0.31471624 0.34701613]] +[[ 1.00000000e+00 0.00000000e+00 0.00000000e+00 8.32667268e-17] + [ 0.00000000e+00 1.00000000e+00 -1.38777878e-16 -5.55111512e-17] + [ 0.00000000e+00 -1.38777878e-16 1.00000000e+00 -4.16333634e-17] + [ 8.32667268e-17 -5.55111512e-17 -4.16333634e-17 1.00000000e+00]] +*/ +/* Set X to orthogonal matrix Q */ + X.v[0] = (double) -0.758175396575746; + X.v[1] = (double) -0.291605921759902; + X.v[2] = (double) -0.349927106111883; + X.v[3] = (double) 0.466569474815844; + X.v[4] = (double) -0.066465938150304; + X.v[5] = (double) -0.421130336863261; + X.v[6] = (double) -0.505356404235913; + X.v[7] = (double) -0.750230913210716; + X.v[8] = (double) -0.435760946151503; + X.v[9] = (double) 0.827016017354744; + X.v[10] = (double) -0.164652949650292; + X.v[11] = (double) -0.314716238887197; + X.v[12] = (double) 0.480483865392125; + X.v[13] = (double) 0.231645705349122; + X.v[14] = (double) -0.771398296133308; + X.v[15] = (double) 0.347016125005424; +/* Check Positive Test */ + TASSERT(SST_Math_Mat44dCheckOrthonormal(&X),"CheckOrthonormal failed when it should have passed"); +/* Check Negative Test */ + TASSERT(!SST_Math_Mat44dCheckOrthonormal(&Y),"CheckOrthonormal succeeded when it should have failed"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat44dDeterminant(){ + SST_Mat44d X; /* 4 x 4 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = 13.000000000000000; + X.v[1] = 1.000000000000000; + X.v[2] = -13.000000000000000; + X.v[3] = 12.000000000000000; + X.v[4] = 0.000000000000000; + X.v[5] = 15.000000000000000; + X.v[6] = -16.000000000000000; + X.v[7] = 15.000000000000000; + X.v[8] = 1.000000000000000; + X.v[9] = -15.000000000000000; + X.v[10] = 0.000000000000000; + X.v[11] = -7.000000000000000; + X.v[12] = -20.000000000000000; + X.v[13] = -18.000000000000000; + X.v[14] = -17.000000000000000; + X.v[15] = 18.000000000000000; +/* det(X) = +-79537.0 + */ + double result = SST_Math_Mat44dDeterminant(&X); + TASSERT(fabs( (result)/( -79537.000000000087311) - 1.000000000000000 ) <= 100*DBL_EPSILON,"Determinant failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat44dInvert(){ + SST_Mat44d X; /* 4 x 4 matrix */ + SST_Mat44d B; /* 4 x 4 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = 18.000000000000000; + X.v[1] = -3.000000000000000; + X.v[2] = -18.000000000000000; + X.v[3] = 6.000000000000000; + X.v[4] = 18.000000000000000; + X.v[5] = 7.000000000000000; + X.v[6] = 3.000000000000000; + X.v[7] = 17.000000000000000; + X.v[8] = -19.000000000000000; + X.v[9] = 4.000000000000000; + X.v[10] = 1.000000000000000; + X.v[11] = -5.000000000000000; + X.v[12] = -19.000000000000000; + X.v[13] = -5.000000000000000; + X.v[14] = -13.000000000000000; + X.v[15] = 19.000000000000000; +/* +[[ 0.0105392 0.04187555 -0.05804834 -0.0181582 ] + [ 0.00640294 0.06154762 0.00476498 0.02585993] + [-0.02178984 0.1316325 -0.05109942 -0.02211247] + [-0.01479128 -0.03365265 0.00062044 0.02940884]] +*/ + SST_Math_Mat44dInvert(&X,&B); + TASSERT(fabs((B.v[0])-( 0.010539203520789)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a11 failed!"); + TASSERT(fabs((B.v[1])-( 0.006402938402740)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a21 failed!"); + TASSERT(fabs((B.v[2])-( -0.021789844641882)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a31 failed!"); + TASSERT(fabs((B.v[3])-( -0.014791284062143)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a41 failed!"); + TASSERT(fabs((B.v[4])-( 0.041875548055128)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a12 failed!"); + TASSERT(fabs((B.v[5])-( 0.061547624956569)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a22 failed!"); + TASSERT(fabs((B.v[6])-( 0.131632501116792)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a32 failed!"); + TASSERT(fabs((B.v[7])-( -0.033652653000447)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a42 failed!"); + TASSERT(fabs((B.v[8])-( -0.058048344666700)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a13 failed!"); + TASSERT(fabs((B.v[9])-( 0.004764977415992)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a23 failed!"); + TASSERT(fabs((B.v[10])-( -0.051099419268377)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a33 failed!"); + TASSERT(fabs((B.v[11])-( 0.000620439767707)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a43 failed!"); + TASSERT(fabs((B.v[12])-( -0.018158203868235)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a14 failed!"); + TASSERT(fabs((B.v[13])-( 0.025859929518042)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a24 failed!"); + TASSERT(fabs((B.v[14])-( -0.022112473321090)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a34 failed!"); + TASSERT(fabs((B.v[15])-( 0.029408844989328)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a44 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat44dInvertLocal(){ + SST_Mat44d X; /* 4 x 4 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = -14.000000000000000; + X.v[1] = 12.000000000000000; + X.v[2] = 19.000000000000000; + X.v[3] = -7.000000000000000; + X.v[4] = 5.000000000000000; + X.v[5] = -17.000000000000000; + X.v[6] = -4.000000000000000; + X.v[7] = 11.000000000000000; + X.v[8] = 8.000000000000000; + X.v[9] = -8.000000000000000; + X.v[10] = -20.000000000000000; + X.v[11] = 7.000000000000000; + X.v[12] = 12.000000000000000; + X.v[13] = 16.000000000000000; + X.v[14] = 2.000000000000000; + X.v[15] = 13.000000000000000; +/* +() +[[-0.14091124 0.03012476 -0.03403348 0.09823121] + [-0.02590019 -0.03284902 0.02400505 0.06064435] + [-0.12723073 0.03756712 -0.08634713 0.08449147] + [ 0.01454912 0.0237879 0.00785692 0.03300695]] +*/ + SST_Math_Mat44dInvertLocal(&X); + TASSERT(fabs((X.v[0])-( -0.140911244472521)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a11 failed!"); + TASSERT(fabs((X.v[1])-( -0.025900189513582)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a21 failed!"); + TASSERT(fabs((X.v[2])-( -0.127230732785850)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a31 failed!"); + TASSERT(fabs((X.v[3])-( 0.014549115603285)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a41 failed!"); + TASSERT(fabs((X.v[4])-( 0.030124763108023)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a12 failed!"); + TASSERT(fabs((X.v[5])-( -0.032849020846494)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a22 failed!"); + TASSERT(fabs((X.v[6])-( 0.037567119393557)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a32 failed!"); + TASSERT(fabs((X.v[7])-( 0.023787902716361)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a42 failed!"); + TASSERT(fabs((X.v[8])-( -0.034033480732786)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a13 failed!"); + TASSERT(fabs((X.v[9])-( 0.024005053695515)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a23 failed!"); + TASSERT(fabs((X.v[10])-( -0.086347125710676)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a33 failed!"); + TASSERT(fabs((X.v[11])-( 0.007856917245736)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a43 failed!"); + TASSERT(fabs((X.v[12])-( 0.098231206569804)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a14 failed!"); + TASSERT(fabs((X.v[13])-( 0.060644346178143)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a24 failed!"); + TASSERT(fabs((X.v[14])-( 0.084491471888819)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a34 failed!"); + TASSERT(fabs((X.v[15])-( 0.033006948831333)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _a44 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat44dCreateLU(){ + SST_Mat44d X; /* 4 x 4 matrix */ + SST_Mat44d LU; /* 4 x 4 matrix */ + X.v[0] = 2.000000000000000; + X.v[1] = 1.000000000000000; + X.v[2] = 0.000000000000000; + X.v[3] = 4.000000000000000; + X.v[4] = -1.000000000000000; + X.v[5] = 0.000000000000000; + X.v[6] = 2.000000000000000; + X.v[7] = 2.000000000000000; + X.v[8] = -1.000000000000000; + X.v[9] = -1.000000000000000; + X.v[10] = 1.000000000000000; + X.v[11] = 0.000000000000000; + X.v[12] = 1.000000000000000; + X.v[13] = 2.000000000000000; + X.v[14] = 1.000000000000000; + X.v[15] = 0.000000000000000; + SST_Math_Mat44dCreateLU(&X,&LU); +/* +[[ 2 -1 -1 1] + [ 1 0 -1 2] + [ 0 2 1 1] + [ 4 2 0 0]] +*/ +/* +[[ 2. 0. 0. 0. ] + [ 1. 0.5 0. 0. ] + [ 0. 2. 3. 0. ] + [ 4. 4. 6. -4. ]] +*/ +/* +[[ 1. -0.5 -0.5 0.5 ] + [ 0. 1. -1. 3. ] + [ 0. 0. 1. -1.66666667] + [ 0. 0. 0. 1. ]] +*/ + TASSERT(fabs((LU.v[0])-( 2.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"L:Entry A_a11 failed!"); + TASSERT(fabs((LU.v[4])-( -0.500000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"U:Entry B_a12 failed!"); + TASSERT(fabs((LU.v[8])-( -0.500000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"U:Entry B_a13 failed!"); + TASSERT(fabs((LU.v[12])-( 0.500000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"U:Entry B_a14 failed!"); + TASSERT(fabs((LU.v[1])-( 1.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"L:Entry A_a21 failed!"); + TASSERT(fabs((LU.v[5])-( 0.500000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"L:Entry A_a22 failed!"); + TASSERT(fabs((LU.v[9])-( -1.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"U:Entry B_a23 failed!"); + TASSERT(fabs((LU.v[13])-( 3.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"U:Entry B_a24 failed!"); + TASSERT(fabs((LU.v[2])-( 0.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"L:Entry A_a31 failed!"); + TASSERT(fabs((LU.v[6])-( 2.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"L:Entry A_a32 failed!"); + TASSERT(fabs((LU.v[10])-( 3.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"L:Entry A_a33 failed!"); + TASSERT(fabs((LU.v[14])-( -1.666666666666670)) <=100*DBL_EPSILON /* yes this is bad */,"U:Entry B_a34 failed!"); + TASSERT(fabs((LU.v[3])-( 4.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"L:Entry A_a41 failed!"); + TASSERT(fabs((LU.v[7])-( 4.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"L:Entry A_a42 failed!"); + TASSERT(fabs((LU.v[11])-( 6.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"L:Entry A_a43 failed!"); + TASSERT(fabs((LU.v[15])-( -4.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"L:Entry A_a44 failed!"); + return ZTEST_SUCCESS; +} +static const char* testSST_Math_Mat44dCreateLULocal(){ + SST_Mat44d X; /* 4 x 4 matrix */ + X.v[0] = 2.000000000000000; + X.v[1] = 1.000000000000000; + X.v[2] = 0.000000000000000; + X.v[3] = 4.000000000000000; + X.v[4] = -1.000000000000000; + X.v[5] = 0.000000000000000; + X.v[6] = 2.000000000000000; + X.v[7] = 2.000000000000000; + X.v[8] = -1.000000000000000; + X.v[9] = -1.000000000000000; + X.v[10] = 1.000000000000000; + X.v[11] = 0.000000000000000; + X.v[12] = 1.000000000000000; + X.v[13] = 2.000000000000000; + X.v[14] = 1.000000000000000; + X.v[15] = 0.000000000000000; + SST_Math_Mat44dCreateLULocal(&X); + TASSERT(fabs((X.v[0])-( 2.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"L:Entry A_a11 failed!"); + TASSERT(fabs((X.v[4])-( -0.500000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"U:Entry B_a12 failed!"); + TASSERT(fabs((X.v[8])-( -0.500000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"U:Entry B_a13 failed!"); + TASSERT(fabs((X.v[12])-( 0.500000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"U:Entry B_a14 failed!"); + TASSERT(fabs((X.v[1])-( 1.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"L:Entry A_a21 failed!"); + TASSERT(fabs((X.v[5])-( 0.500000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"L:Entry A_a22 failed!"); + TASSERT(fabs((X.v[9])-( -1.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"U:Entry B_a23 failed!"); + TASSERT(fabs((X.v[13])-( 3.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"U:Entry B_a24 failed!"); + TASSERT(fabs((X.v[2])-( 0.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"L:Entry A_a31 failed!"); + TASSERT(fabs((X.v[6])-( 2.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"L:Entry A_a32 failed!"); + TASSERT(fabs((X.v[10])-( 3.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"L:Entry A_a33 failed!"); + TASSERT(fabs((X.v[14])-( -1.666666666666670)) <=100*DBL_EPSILON /* yes this is bad */,"U:Entry B_a34 failed!"); + TASSERT(fabs((X.v[3])-( 4.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"L:Entry A_a41 failed!"); + TASSERT(fabs((X.v[7])-( 4.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"L:Entry A_a42 failed!"); + TASSERT(fabs((X.v[11])-( 6.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"L:Entry A_a43 failed!"); + TASSERT(fabs((X.v[15])-( -4.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"L:Entry A_a44 failed!"); + return ZTEST_SUCCESS; +} +static const char* testSST_Math_Mat44dApplyLUMat(){ + SST_Mat44d X; /* 4 x 4 matrix */ + SST_Mat44d LU; /* 4 x 4 matrix */ + SST_Mat44d I; /* 4 x 4 matrix */ + X.v[0] = 2.000000000000000; + X.v[1] = 1.000000000000000; + X.v[2] = 0.000000000000000; + X.v[3] = 4.000000000000000; + X.v[4] = -1.000000000000000; + X.v[5] = 0.000000000000000; + X.v[6] = 2.000000000000000; + X.v[7] = 2.000000000000000; + X.v[8] = -1.000000000000000; + X.v[9] = -1.000000000000000; + X.v[10] = 1.000000000000000; + X.v[11] = 0.000000000000000; + X.v[12] = 1.000000000000000; + X.v[13] = 2.000000000000000; + X.v[14] = 1.000000000000000; + X.v[15] = 0.000000000000000; + SST_Math_Mat44dCreateLU(&X,&LU); +/* +[[ 2 -1 -1 1] + [ 1 0 -1 2] + [ 0 2 1 1] + [ 4 2 0 0]] +*/ +/* +[[ 2. 0. 0. 0. ] + [ 1. 0.5 0. 0. ] + [ 0. 2. 3. 0. ] + [ 4. 4. 6. -4. ]] +*/ +/* +[[ 1. -0.5 -0.5 0.5 ] + [ 0. 1. -1. 3. ] + [ 0. 0. 1. -1.66666667] + [ 0. 0. 0. 1. ]] +*/ + TASSERT(fabs((LU.v[0])-( 2.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"L:Entry A_a11 failed!"); + TASSERT(fabs((LU.v[4])-( -0.500000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"U:Entry B_a12 failed!"); + TASSERT(fabs((LU.v[8])-( -0.500000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"U:Entry B_a13 failed!"); + TASSERT(fabs((LU.v[12])-( 0.500000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"U:Entry B_a14 failed!"); + TASSERT(fabs((LU.v[1])-( 1.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"L:Entry A_a21 failed!"); + TASSERT(fabs((LU.v[5])-( 0.500000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"L:Entry A_a22 failed!"); + TASSERT(fabs((LU.v[9])-( -1.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"U:Entry B_a23 failed!"); + TASSERT(fabs((LU.v[13])-( 3.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"U:Entry B_a24 failed!"); + TASSERT(fabs((LU.v[2])-( 0.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"L:Entry A_a31 failed!"); + TASSERT(fabs((LU.v[6])-( 2.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"L:Entry A_a32 failed!"); + TASSERT(fabs((LU.v[10])-( 3.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"L:Entry A_a33 failed!"); + TASSERT(fabs((LU.v[14])-( -1.666666666666670)) <=100*DBL_EPSILON /* yes this is bad */,"U:Entry B_a34 failed!"); + TASSERT(fabs((LU.v[3])-( 4.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"L:Entry A_a41 failed!"); + TASSERT(fabs((LU.v[7])-( 4.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"L:Entry A_a42 failed!"); + TASSERT(fabs((LU.v[11])-( 6.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"L:Entry A_a43 failed!"); + TASSERT(fabs((LU.v[15])-( -4.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"L:Entry A_a44 failed!"); + SST_Math_Mat44dApplyLUMat(&LU,&X,&I); + TASSERT(fabs((I.v[0])-( 1.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"I:Entry I_a11 failed!"); + TASSERT(fabs((I.v[1])-( 0.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"I:Entry I_a21 failed!"); + TASSERT(fabs((I.v[2])-( 0.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"I:Entry I_a31 failed!"); + TASSERT(fabs((I.v[3])-( 0.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"I:Entry I_a41 failed!"); + TASSERT(fabs((I.v[4])-( 0.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"I:Entry I_a12 failed!"); + TASSERT(fabs((I.v[5])-( 1.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"I:Entry I_a22 failed!"); + TASSERT(fabs((I.v[6])-( 0.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"I:Entry I_a32 failed!"); + TASSERT(fabs((I.v[7])-( 0.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"I:Entry I_a42 failed!"); + TASSERT(fabs((I.v[8])-( 0.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"I:Entry I_a13 failed!"); + TASSERT(fabs((I.v[9])-( 0.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"I:Entry I_a23 failed!"); + TASSERT(fabs((I.v[10])-( 1.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"I:Entry I_a33 failed!"); + TASSERT(fabs((I.v[11])-( 0.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"I:Entry I_a43 failed!"); + TASSERT(fabs((I.v[12])-( 0.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"I:Entry I_a14 failed!"); + TASSERT(fabs((I.v[13])-( 0.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"I:Entry I_a24 failed!"); + TASSERT(fabs((I.v[14])-( 0.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"I:Entry I_a34 failed!"); + TASSERT(fabs((I.v[15])-( 1.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"I:Entry I_a44 failed!"); + return ZTEST_SUCCESS; +} +static const char* testSST_Math_Mat44dApplyLUMatLocal(){ + SST_Mat44d X; /* 4 x 4 matrix */ + SST_Mat44d Xinv; /* 4 x 4 matrix */ + X.v[0] = 2.000000000000000; + X.v[1] = 1.000000000000000; + X.v[2] = 0.000000000000000; + X.v[3] = 4.000000000000000; + X.v[4] = -1.000000000000000; + X.v[5] = 0.000000000000000; + X.v[6] = 2.000000000000000; + X.v[7] = 2.000000000000000; + X.v[8] = -1.000000000000000; + X.v[9] = -1.000000000000000; + X.v[10] = 1.000000000000000; + X.v[11] = 0.000000000000000; + X.v[12] = 1.000000000000000; + X.v[13] = 2.000000000000000; + X.v[14] = 1.000000000000000; + X.v[15] = 0.000000000000000; + Xinv.v[0] = 2.000000000000000; + Xinv.v[1] = 1.000000000000000; + Xinv.v[2] = 0.000000000000000; + Xinv.v[3] = 4.000000000000000; + Xinv.v[4] = -1.000000000000000; + Xinv.v[5] = 0.000000000000000; + Xinv.v[6] = 2.000000000000000; + Xinv.v[7] = 2.000000000000000; + Xinv.v[8] = -1.000000000000000; + Xinv.v[9] = -1.000000000000000; + Xinv.v[10] = 1.000000000000000; + Xinv.v[11] = 0.000000000000000; + Xinv.v[12] = 1.000000000000000; + Xinv.v[13] = 2.000000000000000; + Xinv.v[14] = 1.000000000000000; + Xinv.v[15] = 0.000000000000000; + SST_Math_Mat44dCreateLULocal(&X); + TASSERT(fabs((X.v[0])-( 2.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"L:Entry A_a11 failed!"); + TASSERT(fabs((X.v[4])-( -0.500000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"U:Entry B_a12 failed!"); + TASSERT(fabs((X.v[8])-( -0.500000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"U:Entry B_a13 failed!"); + TASSERT(fabs((X.v[12])-( 0.500000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"U:Entry B_a14 failed!"); + TASSERT(fabs((X.v[1])-( 1.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"L:Entry A_a21 failed!"); + TASSERT(fabs((X.v[5])-( 0.500000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"L:Entry A_a22 failed!"); + TASSERT(fabs((X.v[9])-( -1.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"U:Entry B_a23 failed!"); + TASSERT(fabs((X.v[13])-( 3.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"U:Entry B_a24 failed!"); + TASSERT(fabs((X.v[2])-( 0.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"L:Entry A_a31 failed!"); + TASSERT(fabs((X.v[6])-( 2.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"L:Entry A_a32 failed!"); + TASSERT(fabs((X.v[10])-( 3.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"L:Entry A_a33 failed!"); + TASSERT(fabs((X.v[14])-( -1.666666666666670)) <=100*DBL_EPSILON /* yes this is bad */,"U:Entry B_a34 failed!"); + TASSERT(fabs((X.v[3])-( 4.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"L:Entry A_a41 failed!"); + TASSERT(fabs((X.v[7])-( 4.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"L:Entry A_a42 failed!"); + TASSERT(fabs((X.v[11])-( 6.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"L:Entry A_a43 failed!"); + TASSERT(fabs((X.v[15])-( -4.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"L:Entry A_a44 failed!"); + SST_Math_Mat44dApplyLUMatLocal(&X,&Xinv); + TASSERT(fabs((Xinv.v[0])-( 1.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Xinv:Entry Xinv_a11 failed!"); + TASSERT(fabs((Xinv.v[1])-( 0.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Xinv:Entry Xinv_a21 failed!"); + TASSERT(fabs((Xinv.v[2])-( 0.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Xinv:Entry Xinv_a31 failed!"); + TASSERT(fabs((Xinv.v[3])-( 0.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Xinv:Entry Xinv_a41 failed!"); + TASSERT(fabs((Xinv.v[4])-( 0.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Xinv:Entry Xinv_a12 failed!"); + TASSERT(fabs((Xinv.v[5])-( 1.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Xinv:Entry Xinv_a22 failed!"); + TASSERT(fabs((Xinv.v[6])-( 0.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Xinv:Entry Xinv_a32 failed!"); + TASSERT(fabs((Xinv.v[7])-( 0.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Xinv:Entry Xinv_a42 failed!"); + TASSERT(fabs((Xinv.v[8])-( 0.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Xinv:Entry Xinv_a13 failed!"); + TASSERT(fabs((Xinv.v[9])-( 0.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Xinv:Entry Xinv_a23 failed!"); + TASSERT(fabs((Xinv.v[10])-( 1.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Xinv:Entry Xinv_a33 failed!"); + TASSERT(fabs((Xinv.v[11])-( 0.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Xinv:Entry Xinv_a43 failed!"); + TASSERT(fabs((Xinv.v[12])-( 0.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Xinv:Entry Xinv_a14 failed!"); + TASSERT(fabs((Xinv.v[13])-( 0.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Xinv:Entry Xinv_a24 failed!"); + TASSERT(fabs((Xinv.v[14])-( 0.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Xinv:Entry Xinv_a34 failed!"); + TASSERT(fabs((Xinv.v[15])-( 1.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Xinv:Entry Xinv_a44 failed!"); + return ZTEST_SUCCESS; +} +static const char* testSST_Math_Mat44dApplyLUVec(){ + SST_Mat44d X; /* 4 x 4 matrix */ + SST_Mat44d LU; /* 4 x 4 matrix */ + SST_Vec4d b; /* 4 x 4 vector */ + SST_Vec4d x; /* 4 x 4 vector */ + X.v[0] = 2.000000000000000; + X.v[1] = 1.000000000000000; + X.v[2] = 0.000000000000000; + X.v[3] = 4.000000000000000; + X.v[4] = -1.000000000000000; + X.v[5] = 0.000000000000000; + X.v[6] = 2.000000000000000; + X.v[7] = 2.000000000000000; + X.v[8] = -1.000000000000000; + X.v[9] = -1.000000000000000; + X.v[10] = 1.000000000000000; + X.v[11] = 0.000000000000000; + X.v[12] = 1.000000000000000; + X.v[13] = 2.000000000000000; + X.v[14] = 1.000000000000000; + X.v[15] = 0.000000000000000; + b.v[0] = 2.000000000000000; + b.v[1] = -1.000000000000000; + b.v[2] = 1.000000000000000; + b.v[3] = 1.000000000000000; + SST_Math_Mat44dCreateLU(&X,&LU); + SST_Math_Mat44dApplyLUVec(&LU,&b,&x); + TASSERT(fabs((x.v[0])-( 1.583333333333333)) <=100*DBL_EPSILON /* yes this is bad */,"x:Entry x_a1 failed!"); + TASSERT(fabs((x.v[1])-( -2.666666666666667)) <=100*DBL_EPSILON /* yes this is bad */,"x:Entry x_a2 failed!"); + TASSERT(fabs((x.v[2])-( 5.083333333333333)) <=100*DBL_EPSILON /* yes this is bad */,"x:Entry x_a3 failed!"); + TASSERT(fabs((x.v[3])-( 1.250000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"x:Entry x_a4 failed!"); + return ZTEST_SUCCESS; +} +static const char* testSST_Math_Mat44dApplyLUVecLocal(){ + SST_Mat44d X; /* 4 x 4 matrix */ + SST_Mat44d LU; /* 4 x 4 matrix */ + SST_Vec4d b; /* 4 x 4 vector */ + X.v[0] = 2.000000000000000; + X.v[1] = 1.000000000000000; + X.v[2] = 0.000000000000000; + X.v[3] = 4.000000000000000; + X.v[4] = -1.000000000000000; + X.v[5] = 0.000000000000000; + X.v[6] = 2.000000000000000; + X.v[7] = 2.000000000000000; + X.v[8] = -1.000000000000000; + X.v[9] = -1.000000000000000; + X.v[10] = 1.000000000000000; + X.v[11] = 0.000000000000000; + X.v[12] = 1.000000000000000; + X.v[13] = 2.000000000000000; + X.v[14] = 1.000000000000000; + X.v[15] = 0.000000000000000; + b.v[0] = 2.000000000000000; + b.v[1] = -1.000000000000000; + b.v[2] = 1.000000000000000; + b.v[3] = 1.000000000000000; + SST_Math_Mat44dCreateLU(&X,&LU); + SST_Math_Mat44dApplyLUVecLocal(&LU,&b); + TASSERT(fabs((b.v[0])-( 1.583333333333333)) <=100*DBL_EPSILON /* yes this is bad */,"x:Entry x_a1 failed!"); + TASSERT(fabs((b.v[1])-( -2.666666666666667)) <=100*DBL_EPSILON /* yes this is bad */,"x:Entry x_a2 failed!"); + TASSERT(fabs((b.v[2])-( 5.083333333333333)) <=100*DBL_EPSILON /* yes this is bad */,"x:Entry x_a3 failed!"); + TASSERT(fabs((b.v[3])-( 1.250000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"x:Entry x_a4 failed!"); + return ZTEST_SUCCESS; +} diff --git a/ZTestSuite/Test-SST_Mat44f.cpp b/ZTestSuite/Test-SST_Mat44f.cpp new file mode 100644 index 0000000..0bdabdc --- /dev/null +++ b/ZTestSuite/Test-SST_Mat44f.cpp @@ -0,0 +1,1435 @@ +/* + AUTOMATICALLY GENERATED FILE - DO NOT EDIT! + Please change MatrixNxN.py and re-run it +*/ +/* Generated with ./MatrixNxN.py n = 4, TYPE = float */ + +#include "ZUnitTest.hpp" +#include <float.h> +#include <math.h> +#include <stdlib.h> +#include <stdio.h> +#include <SST/SST_Mat44.h> +#include <SST/SST_Vec4.h> + + + + +static const char* testSST_Math_Mat44fAdd(); +static const char* testSST_Math_Mat44fAddLocal(); +static const char* testSST_Math_Mat44fSubtract(); +static const char* testSST_Math_Mat44fSubtractLocal(); +static const char* testSST_Math_Mat44fMultiplyElementwise(); +static const char* testSST_Math_Mat44fMultiplyElementwiseLocal(); +static const char* testSST_Math_Mat44fMultiplyScalar(); +static const char* testSST_Math_Mat44fMultiplyScalarLocal(); +static const char* testSST_Math_Mat44fMultiplyMatrix(); +static const char* testSST_Math_Mat44fMultiplyMatrixLocal(); +static const char* testSST_Math_Mat44fMultiplyVector(); +static const char* testSST_Math_Mat44fMultiplyVectorLocal(); +static const char* testSST_Math_Mat44fTranspose(); +static const char* testSST_Math_Mat44fTransposeLocal(); +static const char* testSST_Math_Mat44fDeterminant(); +static const char* testSST_Math_Mat44fCheckOrthonormal(); +static const char* testSST_Math_Mat44fInvert(); +static const char* testSST_Math_Mat44fInvertLocal(); +static const char* testSST_Math_Mat44fCreateLU(); +static const char* testSST_Math_Mat44fCreateLULocal(); +static const char* testSST_Math_Mat44fApplyLUMat(); +static const char* testSST_Math_Mat44fApplyLUMatLocal(); +static const char* testSST_Math_Mat44fApplyLUVec(); +static const char* testSST_Math_Mat44fApplyLUVecLocal(); +// List of unit tests +ZUnitTest SST_Math_Mat44fUnitTests[] = +{ +{ "testSST_Math_Mat44fAdd " , testSST_Math_Mat44fAdd }, +{ "testSST_Math_Mat44fAddLocal " , testSST_Math_Mat44fAddLocal }, +{ "testSST_Math_Mat44fSubtract " , testSST_Math_Mat44fSubtract }, +{ "testSST_Math_Mat44fSubtractLocal " , testSST_Math_Mat44fSubtractLocal }, +{ "testSST_Math_Mat44fMultiplyElementwise " , testSST_Math_Mat44fMultiplyElementwise }, +{ "testSST_Math_Mat44fMultiplyElementwiseLocal " , testSST_Math_Mat44fMultiplyElementwiseLocal }, +{ "testSST_Math_Mat44fMultiplyScalar " , testSST_Math_Mat44fMultiplyScalar }, +{ "testSST_Math_Mat44fMultiplyScalarLocal " , testSST_Math_Mat44fMultiplyScalarLocal }, +{ "testSST_Math_Mat44fMultiplyMatrix " , testSST_Math_Mat44fMultiplyMatrix }, +{ "testSST_Math_Mat44fMultiplyMatrixLocal " , testSST_Math_Mat44fMultiplyMatrixLocal }, +{ "testSST_Math_Mat44fMultiplyVector " , testSST_Math_Mat44fMultiplyVector }, +{ "testSST_Math_Mat44fMultiplyVectorLocal " , testSST_Math_Mat44fMultiplyVectorLocal }, +{ "testSST_Math_Mat44fDeterminant " , testSST_Math_Mat44fDeterminant }, +{ "testSST_Math_Mat44fCheckOrthonormal " , testSST_Math_Mat44fCheckOrthonormal }, +{ "testSST_Math_Mat44fInvert " , testSST_Math_Mat44fInvert }, +{ "testSST_Math_Mat44fInvertLocal " , testSST_Math_Mat44fInvertLocal }, +{ "testSST_Math_Mat44fCreateLU " , testSST_Math_Mat44fCreateLU }, +{ "testSST_Math_Mat44fCreateLULocal " , testSST_Math_Mat44fCreateLULocal }, +{ "testSST_Math_Mat44fApplyLUMat " , testSST_Math_Mat44fApplyLUMat }, +{ "testSST_Math_Mat44fApplyLUMatLocal " , testSST_Math_Mat44fApplyLUMatLocal }, +{ "testSST_Math_Mat44fApplyLUVec " , testSST_Math_Mat44fApplyLUVec }, +{ "testSST_Math_Mat44fApplyLUVecLocal " , testSST_Math_Mat44fApplyLUVecLocal }, +{ "testSST_Math_Mat44fTranspose " , testSST_Math_Mat44fTranspose }, +{ "testSST_Math_Mat44fTransposeLocal " , testSST_Math_Mat44fTransposeLocal } +}; +DECLARE_ZTESTBLOCK(SST_Math_Mat44f) + +/******************************************************************************/ + +static const char* testSST_Math_Mat44fAdd(){ + SST_Mat44f X; /* 4 x 4 matrix */ + SST_Mat44f Y; /* 4 x 4 matrix */ + SST_Mat44f A; /* 4 x 4 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = 3.000000f; + X.v[1] = -19.000000f; + X.v[2] = -16.000000f; + X.v[3] = 9.000000f; + X.v[4] = 4.000000f; + X.v[5] = -8.000000f; + X.v[6] = 13.000000f; + X.v[7] = 4.000000f; + X.v[8] = 11.000000f; + X.v[9] = 16.000000f; + X.v[10] = -14.000000f; + X.v[11] = 12.000000f; + X.v[12] = -19.000000f; + X.v[13] = 4.000000f; + X.v[14] = -10.000000f; + X.v[15] = 0.000000f; + Y.v[0] = 6.000000f; + Y.v[1] = -6.000000f; + Y.v[2] = -19.000000f; + Y.v[3] = 11.000000f; + Y.v[4] = -10.000000f; + Y.v[5] = 17.000000f; + Y.v[6] = 6.000000f; + Y.v[7] = -18.000000f; + Y.v[8] = -2.000000f; + Y.v[9] = -16.000000f; + Y.v[10] = -3.000000f; + Y.v[11] = -17.000000f; + Y.v[12] = -2.000000f; + Y.v[13] = -18.000000f; + Y.v[14] = 1.000000f; + Y.v[15] = -17.000000f; +/* +[[ 3. 4. 11. -19.] + [-19. -8. 16. 4.] + [-16. 13. -14. -10.] + [ 9. 4. 12. 0.]] +[[ 6. -10. -2. -2.] + [ -6. 17. -16. -18.] + [-19. 6. -3. 1.] + [ 11. -18. -17. -17.]] +[[ 9. -6. 9. -21.] + [-25. 9. 0. -14.] + [-35. 19. -17. -9.] + [ 20. -14. -5. -17.]] +*/ + SST_Math_Mat44fAdd(&X,&Y,&A); + TASSERT(fabsf((A.v[0])-(9.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a11 failed!"); + TASSERT(fabsf((A.v[4])-(-6.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a12 failed!"); + TASSERT(fabsf((A.v[8])-(9.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a13 failed!"); + TASSERT(fabsf((A.v[12])-(-21.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a14 failed!"); + TASSERT(fabsf((A.v[1])-(-25.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a21 failed!"); + TASSERT(fabsf((A.v[5])-(9.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a22 failed!"); + TASSERT(fabsf((A.v[9])-(0.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a23 failed!"); + TASSERT(fabsf((A.v[13])-(-14.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a24 failed!"); + TASSERT(fabsf((A.v[2])-(-35.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a31 failed!"); + TASSERT(fabsf((A.v[6])-(19.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a32 failed!"); + TASSERT(fabsf((A.v[10])-(-17.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a33 failed!"); + TASSERT(fabsf((A.v[14])-(-9.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a34 failed!"); + TASSERT(fabsf((A.v[3])-(20.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a41 failed!"); + TASSERT(fabsf((A.v[7])-(-14.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a42 failed!"); + TASSERT(fabsf((A.v[11])-(-5.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a43 failed!"); + TASSERT(fabsf((A.v[15])-(-17.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a44 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat44fAddLocal(){ + SST_Mat44f X; /* 4 x 4 matrix */ + SST_Mat44f Y; /* 4 x 4 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = 0.000000f; + X.v[1] = -6.000000f; + X.v[2] = 16.000000f; + X.v[3] = 19.000000f; + X.v[4] = 2.000000f; + X.v[5] = -2.000000f; + X.v[6] = -7.000000f; + X.v[7] = 10.000000f; + X.v[8] = 13.000000f; + X.v[9] = 19.000000f; + X.v[10] = -11.000000f; + X.v[11] = -5.000000f; + X.v[12] = 18.000000f; + X.v[13] = -3.000000f; + X.v[14] = 18.000000f; + X.v[15] = 19.000000f; + Y.v[0] = 8.000000f; + Y.v[1] = 1.000000f; + Y.v[2] = -12.000000f; + Y.v[3] = 7.000000f; + Y.v[4] = 6.000000f; + Y.v[5] = 18.000000f; + Y.v[6] = -6.000000f; + Y.v[7] = 19.000000f; + Y.v[8] = -10.000000f; + Y.v[9] = -10.000000f; + Y.v[10] = 15.000000f; + Y.v[11] = 3.000000f; + Y.v[12] = 1.000000f; + Y.v[13] = -14.000000f; + Y.v[14] = 6.000000f; + Y.v[15] = 3.000000f; +/* +[[ 0. 2. 13. 18.] + [ -6. -2. 19. -3.] + [ 16. -7. -11. 18.] + [ 19. 10. -5. 19.]] +[[ 8. 6. -10. 1.] + [ 1. 18. -10. -14.] + [-12. -6. 15. 6.] + [ 7. 19. 3. 3.]] +[[ 8. 8. 3. 19.] + [ -5. 16. 9. -17.] + [ 4. -13. 4. 24.] + [ 26. 29. -2. 22.]] +*/ + SST_Math_Mat44fAddLocal(&X,&Y); /* for accuracy */ + TASSERT(fabsf((X.v[0])-(8.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a11 failed!"); + TASSERT(fabsf((X.v[4])-(8.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a12 failed!"); + TASSERT(fabsf((X.v[8])-(3.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a13 failed!"); + TASSERT(fabsf((X.v[12])-(19.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a14 failed!"); + TASSERT(fabsf((X.v[1])-(-5.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a21 failed!"); + TASSERT(fabsf((X.v[5])-(16.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a22 failed!"); + TASSERT(fabsf((X.v[9])-(9.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a23 failed!"); + TASSERT(fabsf((X.v[13])-(-17.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a24 failed!"); + TASSERT(fabsf((X.v[2])-(4.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a31 failed!"); + TASSERT(fabsf((X.v[6])-(-13.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a32 failed!"); + TASSERT(fabsf((X.v[10])-(4.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a33 failed!"); + TASSERT(fabsf((X.v[14])-(24.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a34 failed!"); + TASSERT(fabsf((X.v[3])-(26.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a41 failed!"); + TASSERT(fabsf((X.v[7])-(29.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a42 failed!"); + TASSERT(fabsf((X.v[11])-(-2.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a43 failed!"); + TASSERT(fabsf((X.v[15])-(22.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a44 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat44fSubtract(){ + SST_Mat44f X; /* 4 x 4 matrix */ + SST_Mat44f Y; /* 4 x 4 matrix */ + SST_Mat44f A; /* 4 x 4 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = 3.000000f; + X.v[1] = 15.000000f; + X.v[2] = 0.000000f; + X.v[3] = 3.000000f; + X.v[4] = 7.000000f; + X.v[5] = -17.000000f; + X.v[6] = -20.000000f; + X.v[7] = -16.000000f; + X.v[8] = 1.000000f; + X.v[9] = 2.000000f; + X.v[10] = 4.000000f; + X.v[11] = 3.000000f; + X.v[12] = 0.000000f; + X.v[13] = -12.000000f; + X.v[14] = 0.000000f; + X.v[15] = -6.000000f; + Y.v[0] = -11.000000f; + Y.v[1] = -4.000000f; + Y.v[2] = -13.000000f; + Y.v[3] = -9.000000f; + Y.v[4] = 8.000000f; + Y.v[5] = 8.000000f; + Y.v[6] = 17.000000f; + Y.v[7] = -11.000000f; + Y.v[8] = 5.000000f; + Y.v[9] = -9.000000f; + Y.v[10] = 10.000000f; + Y.v[11] = -18.000000f; + Y.v[12] = 16.000000f; + Y.v[13] = -12.000000f; + Y.v[14] = -14.000000f; + Y.v[15] = -9.000000f; +/* +[[ 3. 7. 1. 0.] + [ 15. -17. 2. -12.] + [ 0. -20. 4. 0.] + [ 3. -16. 3. -6.]] +[[-11. 8. 5. 16.] + [ -4. 8. -9. -12.] + [-13. 17. 10. -14.] + [ -9. -11. -18. -9.]] +[[ 14. -1. -4. -16.] + [ 19. -25. 11. 0.] + [ 13. -37. -6. 14.] + [ 12. -5. 21. 3.]] +*/ + SST_Math_Mat44fSubtract(&X,&Y,&A); + TASSERT(fabsf((A.v[0])-(14.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a11 failed!"); + TASSERT(fabsf((A.v[4])-(-1.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a12 failed!"); + TASSERT(fabsf((A.v[8])-(-4.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a13 failed!"); + TASSERT(fabsf((A.v[12])-(-16.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a14 failed!"); + TASSERT(fabsf((A.v[1])-(19.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a21 failed!"); + TASSERT(fabsf((A.v[5])-(-25.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a22 failed!"); + TASSERT(fabsf((A.v[9])-(11.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a23 failed!"); + TASSERT(fabsf((A.v[13])-(0.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a24 failed!"); + TASSERT(fabsf((A.v[2])-(13.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a31 failed!"); + TASSERT(fabsf((A.v[6])-(-37.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a32 failed!"); + TASSERT(fabsf((A.v[10])-(-6.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a33 failed!"); + TASSERT(fabsf((A.v[14])-(14.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a34 failed!"); + TASSERT(fabsf((A.v[3])-(12.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a41 failed!"); + TASSERT(fabsf((A.v[7])-(-5.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a42 failed!"); + TASSERT(fabsf((A.v[11])-(21.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a43 failed!"); + TASSERT(fabsf((A.v[15])-(3.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a44 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat44fSubtractLocal(){ + SST_Mat44f X; /* 4 x 4 matrix */ + SST_Mat44f Y; /* 4 x 4 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = -17.000000f; + X.v[1] = 2.000000f; + X.v[2] = 19.000000f; + X.v[3] = -9.000000f; + X.v[4] = 12.000000f; + X.v[5] = -10.000000f; + X.v[6] = -16.000000f; + X.v[7] = -7.000000f; + X.v[8] = -15.000000f; + X.v[9] = -17.000000f; + X.v[10] = -7.000000f; + X.v[11] = 5.000000f; + X.v[12] = 15.000000f; + X.v[13] = -11.000000f; + X.v[14] = 16.000000f; + X.v[15] = 13.000000f; + Y.v[0] = -9.000000f; + Y.v[1] = -9.000000f; + Y.v[2] = -11.000000f; + Y.v[3] = -12.000000f; + Y.v[4] = 14.000000f; + Y.v[5] = -17.000000f; + Y.v[6] = -6.000000f; + Y.v[7] = -9.000000f; + Y.v[8] = -14.000000f; + Y.v[9] = -17.000000f; + Y.v[10] = 7.000000f; + Y.v[11] = 6.000000f; + Y.v[12] = -17.000000f; + Y.v[13] = -5.000000f; + Y.v[14] = -2.000000f; + Y.v[15] = 6.000000f; +/* +[[-17. 12. -15. 15.] + [ 2. -10. -17. -11.] + [ 19. -16. -7. 16.] + [ -9. -7. 5. 13.]] +[[ -9. 14. -14. -17.] + [ -9. -17. -17. -5.] + [-11. -6. 7. -2.] + [-12. -9. 6. 6.]] +[[ -8. -2. -1. 32.] + [ 11. 7. 0. -6.] + [ 30. -10. -14. 18.] + [ 3. 2. -1. 7.]] +*/ + SST_Math_Mat44fSubtractLocal(&X,&Y); /* for accuracy */ + TASSERT(fabsf((X.v[0])-(-8.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a11 failed!"); + TASSERT(fabsf((X.v[4])-(-2.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a12 failed!"); + TASSERT(fabsf((X.v[8])-(-1.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a13 failed!"); + TASSERT(fabsf((X.v[12])-(32.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a14 failed!"); + TASSERT(fabsf((X.v[1])-(11.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a21 failed!"); + TASSERT(fabsf((X.v[5])-(7.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a22 failed!"); + TASSERT(fabsf((X.v[9])-(0.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a23 failed!"); + TASSERT(fabsf((X.v[13])-(-6.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a24 failed!"); + TASSERT(fabsf((X.v[2])-(30.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a31 failed!"); + TASSERT(fabsf((X.v[6])-(-10.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a32 failed!"); + TASSERT(fabsf((X.v[10])-(-14.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a33 failed!"); + TASSERT(fabsf((X.v[14])-(18.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a34 failed!"); + TASSERT(fabsf((X.v[3])-(3.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a41 failed!"); + TASSERT(fabsf((X.v[7])-(2.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a42 failed!"); + TASSERT(fabsf((X.v[11])-(-1.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a43 failed!"); + TASSERT(fabsf((X.v[15])-(7.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a44 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat44fMultiplyElementwise(){ + SST_Mat44f X; /* 4 x 4 matrix */ + SST_Mat44f Y; /* 4 x 4 matrix */ + SST_Mat44f A; /* 4 x 4 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = -17.000000f; + X.v[1] = -15.000000f; + X.v[2] = 19.000000f; + X.v[3] = -18.000000f; + X.v[4] = -18.000000f; + X.v[5] = 6.000000f; + X.v[6] = -1.000000f; + X.v[7] = 8.000000f; + X.v[8] = -11.000000f; + X.v[9] = -19.000000f; + X.v[10] = -17.000000f; + X.v[11] = -12.000000f; + X.v[12] = -4.000000f; + X.v[13] = 1.000000f; + X.v[14] = 9.000000f; + X.v[15] = 0.000000f; + Y.v[0] = 2.000000f; + Y.v[1] = 10.000000f; + Y.v[2] = -12.000000f; + Y.v[3] = 1.000000f; + Y.v[4] = -8.000000f; + Y.v[5] = 3.000000f; + Y.v[6] = -16.000000f; + Y.v[7] = -5.000000f; + Y.v[8] = -13.000000f; + Y.v[9] = -18.000000f; + Y.v[10] = -1.000000f; + Y.v[11] = -15.000000f; + Y.v[12] = 4.000000f; + Y.v[13] = -17.000000f; + Y.v[14] = 4.000000f; + Y.v[15] = -7.000000f; +/* +[[-17. -18. -11. -4.] + [-15. 6. -19. 1.] + [ 19. -1. -17. 9.] + [-18. 8. -12. 0.]] +[[ 2. -8. -13. 4.] + [ 10. 3. -18. -17.] + [-12. -16. -1. 4.] + [ 1. -5. -15. -7.]] +[[ -34. 144. 143. -16.] + [-150. 18. 342. -17.] + [-228. 16. 17. 36.] + [ -18. -40. 180. -0.]] +*/ + SST_Math_Mat44fMultiplyElementwise(&X, &Y, &A); + TASSERT(fabsf((A.v[0])-(-34.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a11 failed!"); + TASSERT(fabsf((A.v[4])-(144.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a12 failed!"); + TASSERT(fabsf((A.v[8])-(143.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a13 failed!"); + TASSERT(fabsf((A.v[12])-(-16.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a14 failed!"); + TASSERT(fabsf((A.v[1])-(-150.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a21 failed!"); + TASSERT(fabsf((A.v[5])-(18.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a22 failed!"); + TASSERT(fabsf((A.v[9])-(342.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a23 failed!"); + TASSERT(fabsf((A.v[13])-(-17.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a24 failed!"); + TASSERT(fabsf((A.v[2])-(-228.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a31 failed!"); + TASSERT(fabsf((A.v[6])-(16.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a32 failed!"); + TASSERT(fabsf((A.v[10])-(17.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a33 failed!"); + TASSERT(fabsf((A.v[14])-(36.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a34 failed!"); + TASSERT(fabsf((A.v[3])-(-18.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a41 failed!"); + TASSERT(fabsf((A.v[7])-(-40.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a42 failed!"); + TASSERT(fabsf((A.v[11])-(180.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a43 failed!"); + TASSERT(fabsf((A.v[15])-(-0.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a44 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat44fMultiplyElementwiseLocal(){ + SST_Mat44f X; /* 4 x 4 matrix */ + SST_Mat44f Y; /* 4 x 4 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = 11.000000f; + X.v[1] = -1.000000f; + X.v[2] = -19.000000f; + X.v[3] = 2.000000f; + X.v[4] = -17.000000f; + X.v[5] = 5.000000f; + X.v[6] = -3.000000f; + X.v[7] = -8.000000f; + X.v[8] = 3.000000f; + X.v[9] = 11.000000f; + X.v[10] = 7.000000f; + X.v[11] = -16.000000f; + X.v[12] = -17.000000f; + X.v[13] = -19.000000f; + X.v[14] = 12.000000f; + X.v[15] = 18.000000f; + Y.v[0] = -6.000000f; + Y.v[1] = 10.000000f; + Y.v[2] = -19.000000f; + Y.v[3] = -7.000000f; + Y.v[4] = 0.000000f; + Y.v[5] = -5.000000f; + Y.v[6] = 8.000000f; + Y.v[7] = -15.000000f; + Y.v[8] = -5.000000f; + Y.v[9] = 13.000000f; + Y.v[10] = 7.000000f; + Y.v[11] = 9.000000f; + Y.v[12] = -7.000000f; + Y.v[13] = 17.000000f; + Y.v[14] = -6.000000f; + Y.v[15] = 8.000000f; +/* +[[ 11. -17. 3. -17.] + [ -1. 5. 11. -19.] + [-19. -3. 7. 12.] + [ 2. -8. -16. 18.]] +[[ -6. 0. -5. -7.] + [ 10. -5. 13. 17.] + [-19. 8. 7. -6.] + [ -7. -15. 9. 8.]] +[[ -66. -0. -15. 119.] + [ -10. -25. 143. -323.] + [ 361. -24. 49. -72.] + [ -14. 120. -144. 144.]] +*/ + SST_Math_Mat44fMultiplyElementwiseLocal(&X,&Y); + TASSERT(fabsf((X.v[0])-(-66.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a11 failed!"); + TASSERT(fabsf((X.v[4])-(-0.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a12 failed!"); + TASSERT(fabsf((X.v[8])-(-15.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a13 failed!"); + TASSERT(fabsf((X.v[12])-(119.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a14 failed!"); + TASSERT(fabsf((X.v[1])-(-10.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a21 failed!"); + TASSERT(fabsf((X.v[5])-(-25.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a22 failed!"); + TASSERT(fabsf((X.v[9])-(143.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a23 failed!"); + TASSERT(fabsf((X.v[13])-(-323.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a24 failed!"); + TASSERT(fabsf((X.v[2])-(361.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a31 failed!"); + TASSERT(fabsf((X.v[6])-(-24.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a32 failed!"); + TASSERT(fabsf((X.v[10])-(49.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a33 failed!"); + TASSERT(fabsf((X.v[14])-(-72.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a34 failed!"); + TASSERT(fabsf((X.v[3])-(-14.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a41 failed!"); + TASSERT(fabsf((X.v[7])-(120.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a42 failed!"); + TASSERT(fabsf((X.v[11])-(-144.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a43 failed!"); + TASSERT(fabsf((X.v[15])-(144.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a44 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat44fMultiplyScalar(){ + SST_Mat44f X; /* 4 x 4 matrix */ + SST_Mat44f A; /* 4 x 4 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = 12.000000f; + X.v[1] = 5.000000f; + X.v[2] = 17.000000f; + X.v[3] = -19.000000f; + X.v[4] = -18.000000f; + X.v[5] = -1.000000f; + X.v[6] = -13.000000f; + X.v[7] = -9.000000f; + X.v[8] = 0.000000f; + X.v[9] = -17.000000f; + X.v[10] = 4.000000f; + X.v[11] = -11.000000f; + X.v[12] = 14.000000f; + X.v[13] = -14.000000f; + X.v[14] = 15.000000f; + X.v[15] = -12.000000f; +/* +[[ 12. -18. 0. 14.] + [ 5. -1. -17. -14.] + [ 17. -13. 4. 15.] + [-19. -9. -11. -12.]] +[[ 24. -36. 0. 28.] + [ 10. -2. -34. -28.] + [ 34. -26. 8. 30.] + [-38. -18. -22. -24.]] +*/ + SST_Math_Mat44fMultiplyScalar(&X,2.000000f,&A); + TASSERT(fabsf((A.v[0])-(24.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a11 failed!"); + TASSERT(fabsf((A.v[4])-(-36.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a12 failed!"); + TASSERT(fabsf((A.v[8])-(0.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a13 failed!"); + TASSERT(fabsf((A.v[12])-(28.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a14 failed!"); + TASSERT(fabsf((A.v[1])-(10.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a21 failed!"); + TASSERT(fabsf((A.v[5])-(-2.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a22 failed!"); + TASSERT(fabsf((A.v[9])-(-34.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a23 failed!"); + TASSERT(fabsf((A.v[13])-(-28.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a24 failed!"); + TASSERT(fabsf((A.v[2])-(34.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a31 failed!"); + TASSERT(fabsf((A.v[6])-(-26.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a32 failed!"); + TASSERT(fabsf((A.v[10])-(8.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a33 failed!"); + TASSERT(fabsf((A.v[14])-(30.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a34 failed!"); + TASSERT(fabsf((A.v[3])-(-38.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a41 failed!"); + TASSERT(fabsf((A.v[7])-(-18.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a42 failed!"); + TASSERT(fabsf((A.v[11])-(-22.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a43 failed!"); + TASSERT(fabsf((A.v[15])-(-24.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a44 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat44fMultiplyScalarLocal(){ + SST_Mat44f X; /* 4 x 4 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = -18.000000f; + X.v[1] = 8.000000f; + X.v[2] = -11.000000f; + X.v[3] = -10.000000f; + X.v[4] = 1.000000f; + X.v[5] = -18.000000f; + X.v[6] = 4.000000f; + X.v[7] = 4.000000f; + X.v[8] = -6.000000f; + X.v[9] = 6.000000f; + X.v[10] = -13.000000f; + X.v[11] = -2.000000f; + X.v[12] = -8.000000f; + X.v[13] = -8.000000f; + X.v[14] = 3.000000f; + X.v[15] = 8.000000f; +/* +[[-18. 1. -6. -8.] + [ 8. -18. 6. -8.] + [-11. 4. -13. 3.] + [-10. 4. -2. 8.]] +[[-36. 2. -12. -16.] + [ 16. -36. 12. -16.] + [-22. 8. -26. 6.] + [-20. 8. -4. 16.]] +*/ + SST_Math_Mat44fMultiplyScalarLocal(&X,2.000000f); + TASSERT(fabsf((X.v[0])-(-36.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a11 failed!"); + TASSERT(fabsf((X.v[4])-(2.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a12 failed!"); + TASSERT(fabsf((X.v[8])-(-12.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a13 failed!"); + TASSERT(fabsf((X.v[12])-(-16.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a14 failed!"); + TASSERT(fabsf((X.v[1])-(16.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a21 failed!"); + TASSERT(fabsf((X.v[5])-(-36.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a22 failed!"); + TASSERT(fabsf((X.v[9])-(12.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a23 failed!"); + TASSERT(fabsf((X.v[13])-(-16.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a24 failed!"); + TASSERT(fabsf((X.v[2])-(-22.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a31 failed!"); + TASSERT(fabsf((X.v[6])-(8.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a32 failed!"); + TASSERT(fabsf((X.v[10])-(-26.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a33 failed!"); + TASSERT(fabsf((X.v[14])-(6.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a34 failed!"); + TASSERT(fabsf((X.v[3])-(-20.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a41 failed!"); + TASSERT(fabsf((X.v[7])-(8.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a42 failed!"); + TASSERT(fabsf((X.v[11])-(-4.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a43 failed!"); + TASSERT(fabsf((X.v[15])-(16.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a44 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat44fMultiplyMatrix(){ + SST_Mat44f X; /* 4 x 4 matrix */ + SST_Mat44f Y; /* 4 x 4 matrix */ + SST_Mat44f A; /* 4 x 4 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = -8.000000f; + X.v[1] = -19.000000f; + X.v[2] = -18.000000f; + X.v[3] = 1.000000f; + X.v[4] = -9.000000f; + X.v[5] = 18.000000f; + X.v[6] = 14.000000f; + X.v[7] = -16.000000f; + X.v[8] = -19.000000f; + X.v[9] = 3.000000f; + X.v[10] = -15.000000f; + X.v[11] = 8.000000f; + X.v[12] = 7.000000f; + X.v[13] = -5.000000f; + X.v[14] = 11.000000f; + X.v[15] = 17.000000f; + Y.v[0] = 2.000000f; + Y.v[1] = -15.000000f; + Y.v[2] = -1.000000f; + Y.v[3] = -3.000000f; + Y.v[4] = 9.000000f; + Y.v[5] = 11.000000f; + Y.v[6] = -1.000000f; + Y.v[7] = 1.000000f; + Y.v[8] = -4.000000f; + Y.v[9] = 5.000000f; + Y.v[10] = -18.000000f; + Y.v[11] = -2.000000f; + Y.v[12] = -14.000000f; + Y.v[13] = -12.000000f; + Y.v[14] = -3.000000f; + Y.v[15] = -13.000000f; +/* +X +[[ -8. -9. -19. 7.] + [-19. 18. 3. -5.] + [-18. 14. -15. 11.] + [ 1. -16. 8. 17.]] +Y +[[ 2. 9. -4. -14.] + [-15. 11. 5. -12.] + [ -1. -1. -18. -3.] + [ -3. 1. -2. -13.]] +[[ 117. -145. 315. 186.] + [-296. 19. 122. 106.] + [-264. 18. 390. -14.] + [ 183. -158. -262. -67.]] +*/ + SST_Math_Mat44fMultiplyMatrix(&X,&Y,&A); + TASSERT(fabsf((A.v[0])-(117.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a11 failed!"); + TASSERT(fabsf((A.v[4])-(-145.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a12 failed!"); + TASSERT(fabsf((A.v[8])-(315.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a13 failed!"); + TASSERT(fabsf((A.v[12])-(186.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a14 failed!"); + TASSERT(fabsf((A.v[1])-(-296.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a21 failed!"); + TASSERT(fabsf((A.v[5])-(19.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a22 failed!"); + TASSERT(fabsf((A.v[9])-(122.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a23 failed!"); + TASSERT(fabsf((A.v[13])-(106.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a24 failed!"); + TASSERT(fabsf((A.v[2])-(-264.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a31 failed!"); + TASSERT(fabsf((A.v[6])-(18.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a32 failed!"); + TASSERT(fabsf((A.v[10])-(390.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a33 failed!"); + TASSERT(fabsf((A.v[14])-(-14.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a34 failed!"); + TASSERT(fabsf((A.v[3])-(183.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a41 failed!"); + TASSERT(fabsf((A.v[7])-(-158.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a42 failed!"); + TASSERT(fabsf((A.v[11])-(-262.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a43 failed!"); + TASSERT(fabsf((A.v[15])-(-67.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a44 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat44fMultiplyMatrixLocal(){ + SST_Mat44f X; /* 4 x 4 matrix */ + SST_Mat44f Y; /* 4 x 4 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = 2.000000f; + X.v[1] = -8.000000f; + X.v[2] = 4.000000f; + X.v[3] = -9.000000f; + X.v[4] = 9.000000f; + X.v[5] = 4.000000f; + X.v[6] = 12.000000f; + X.v[7] = -18.000000f; + X.v[8] = -5.000000f; + X.v[9] = 1.000000f; + X.v[10] = 0.000000f; + X.v[11] = -3.000000f; + X.v[12] = -10.000000f; + X.v[13] = -8.000000f; + X.v[14] = 18.000000f; + X.v[15] = 18.000000f; + Y.v[0] = 16.000000f; + Y.v[1] = -2.000000f; + Y.v[2] = -18.000000f; + Y.v[3] = -20.000000f; + Y.v[4] = -17.000000f; + Y.v[5] = 8.000000f; + Y.v[6] = -18.000000f; + Y.v[7] = -6.000000f; + Y.v[8] = 9.000000f; + Y.v[9] = 17.000000f; + Y.v[10] = 0.000000f; + Y.v[11] = -6.000000f; + Y.v[12] = 1.000000f; + Y.v[13] = 2.000000f; + Y.v[14] = -6.000000f; + Y.v[15] = 18.000000f; +/* +X +[[ 2. 9. -5. -10.] + [ -8. 4. 1. -8.] + [ 4. 12. 0. 18.] + [ -9. -18. -3. 18.]] +Y +[[ 16. -17. 9. 1.] + [ -2. 8. 17. 2.] + [-18. -18. 0. -6.] + [-20. -6. -6. 18.]] +X +[[ 304. 188. 231. -130.] + [ 6. 198. 44. -150.] + [-320. -80. 132. 352.] + [-414. -45. -495. 297.]] +*/ + SST_Math_Mat44fMultiplyMatrixLocal(&X,&Y); + TASSERT(fabsf((X.v[0])-(304.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a11 failed!"); + TASSERT(fabsf((X.v[4])-(188.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a12 failed!"); + TASSERT(fabsf((X.v[8])-(231.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a13 failed!"); + TASSERT(fabsf((X.v[12])-(-130.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a14 failed!"); + TASSERT(fabsf((X.v[1])-(6.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a21 failed!"); + TASSERT(fabsf((X.v[5])-(198.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a22 failed!"); + TASSERT(fabsf((X.v[9])-(44.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a23 failed!"); + TASSERT(fabsf((X.v[13])-(-150.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a24 failed!"); + TASSERT(fabsf((X.v[2])-(-320.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a31 failed!"); + TASSERT(fabsf((X.v[6])-(-80.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a32 failed!"); + TASSERT(fabsf((X.v[10])-(132.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a33 failed!"); + TASSERT(fabsf((X.v[14])-(352.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a34 failed!"); + TASSERT(fabsf((X.v[3])-(-414.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a41 failed!"); + TASSERT(fabsf((X.v[7])-(-45.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a42 failed!"); + TASSERT(fabsf((X.v[11])-(-495.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a43 failed!"); + TASSERT(fabsf((X.v[15])-(297.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a44 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat44fMultiplyVector(){ + SST_Mat44f X; /* 4 x 4 matrix */ + SST_Vec4f v; /* 4 vector */ + SST_Vec4f w; /* 4 vector */ +/* Resetting test vectors / mats */ + v.v[0] = 13.000000f; + v.v[1] = 7.000000f; + v.v[2] = 11.000000f; + v.v[3] = 14.000000f; + X.v[0] = -8.000000f; + X.v[1] = -12.000000f; + X.v[2] = 18.000000f; + X.v[3] = -14.000000f; + X.v[4] = 13.000000f; + X.v[5] = -19.000000f; + X.v[6] = 10.000000f; + X.v[7] = -8.000000f; + X.v[8] = -20.000000f; + X.v[9] = -10.000000f; + X.v[10] = 13.000000f; + X.v[11] = -1.000000f; + X.v[12] = -14.000000f; + X.v[13] = -12.000000f; + X.v[14] = 1.000000f; + X.v[15] = -11.000000f; +/* +X +[[ -8. 13. -20. -14.] + [-12. -19. -10. -12.] + [ 18. 10. 13. 1.] + [-14. -8. -1. -11.]] +v +[ 13. 7. 11. 14.] +w +[-429. -567. 461. -403.] +*/ + SST_Math_Mat44fMultiplyVector(&X,&v,&w); + TASSERT(fabsf((w.v[0])-(-429.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry .v[0] failed!"); + TASSERT(fabsf((w.v[1])-(-567.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry .v[1] failed!"); + TASSERT(fabsf((w.v[2])-(461.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry .v[2] failed!"); + TASSERT(fabsf((w.v[3])-(-403.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry .v[3] failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat44fMultiplyVectorLocal(){ + SST_Mat44f X; /* 4 x 4 matrix */ + SST_Vec4f v; /* 4 vector */ +/* Resetting test vectors / mats */ + v.v[0] = 11.000000f; + v.v[1] = 4.000000f; + v.v[2] = -15.000000f; + v.v[3] = -19.000000f; + X.v[0] = 3.000000f; + X.v[1] = -4.000000f; + X.v[2] = 12.000000f; + X.v[3] = 19.000000f; + X.v[4] = 4.000000f; + X.v[5] = 17.000000f; + X.v[6] = 4.000000f; + X.v[7] = 3.000000f; + X.v[8] = 14.000000f; + X.v[9] = 8.000000f; + X.v[10] = 4.000000f; + X.v[11] = 17.000000f; + X.v[12] = 15.000000f; + X.v[13] = -4.000000f; + X.v[14] = -7.000000f; + X.v[15] = 17.000000f; +/* +X +[[ 3. 4. 14. 15.] + [ -4. 17. 8. -4.] + [ 12. 4. 4. -7.] + [ 19. 3. 17. 17.]] +v +[ 11. 4. -15. -19.] +v +[-446. -20. 221. -357.] +*/ + SST_Math_Mat44fMultiplyVectorLocal(&X,&v); + TASSERT(fabsf((v.v[0])-(-446.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry .v[0] failed!"); + TASSERT(fabsf((v.v[1])-(-20.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry .v[1] failed!"); + TASSERT(fabsf((v.v[2])-(221.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry .v[2] failed!"); + TASSERT(fabsf((v.v[3])-(-357.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry .v[3] failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat44fTranspose(){ + SST_Mat44f X; /* 4 x 4 matrix */ + SST_Mat44f A; /* 4 x 4 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = -5.000000f; + X.v[1] = 18.000000f; + X.v[2] = -7.000000f; + X.v[3] = -18.000000f; + X.v[4] = 11.000000f; + X.v[5] = -10.000000f; + X.v[6] = -9.000000f; + X.v[7] = -10.000000f; + X.v[8] = 14.000000f; + X.v[9] = -11.000000f; + X.v[10] = 12.000000f; + X.v[11] = 18.000000f; + X.v[12] = -14.000000f; + X.v[13] = -15.000000f; + X.v[14] = 6.000000f; + X.v[15] = -13.000000f; + SST_Math_Mat44fTranspose(&X,&A); + TASSERT(fabsf((A.v[0])-(-5.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a11 failed!"); + TASSERT(fabsf((A.v[4])-(18.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a12 failed!"); + TASSERT(fabsf((A.v[8])-(-7.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a13 failed!"); + TASSERT(fabsf((A.v[12])-(-18.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a14 failed!"); + TASSERT(fabsf((A.v[1])-(11.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a21 failed!"); + TASSERT(fabsf((A.v[5])-(-10.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a22 failed!"); + TASSERT(fabsf((A.v[9])-(-9.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a23 failed!"); + TASSERT(fabsf((A.v[13])-(-10.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a24 failed!"); + TASSERT(fabsf((A.v[2])-(14.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a31 failed!"); + TASSERT(fabsf((A.v[6])-(-11.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a32 failed!"); + TASSERT(fabsf((A.v[10])-(12.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a33 failed!"); + TASSERT(fabsf((A.v[14])-(18.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a34 failed!"); + TASSERT(fabsf((A.v[3])-(-14.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a41 failed!"); + TASSERT(fabsf((A.v[7])-(-15.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a42 failed!"); + TASSERT(fabsf((A.v[11])-(6.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a43 failed!"); + TASSERT(fabsf((A.v[15])-(-13.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a44 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat44fTransposeLocal(){ + SST_Mat44f X; /* 4 x 4 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = 19.000000f; + X.v[1] = 5.000000f; + X.v[2] = -16.000000f; + X.v[3] = -14.000000f; + X.v[4] = -17.000000f; + X.v[5] = 19.000000f; + X.v[6] = -10.000000f; + X.v[7] = -20.000000f; + X.v[8] = 15.000000f; + X.v[9] = 15.000000f; + X.v[10] = -5.000000f; + X.v[11] = -18.000000f; + X.v[12] = -17.000000f; + X.v[13] = 17.000000f; + X.v[14] = 2.000000f; + X.v[15] = 16.000000f; + SST_Math_Mat44fTransposeLocal(&X); + TASSERT(fabsf((X.v[0])-(19.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a11 failed!"); + TASSERT(fabsf((X.v[4])-(5.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a12 failed!"); + TASSERT(fabsf((X.v[8])-(-16.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a13 failed!"); + TASSERT(fabsf((X.v[12])-(-14.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a14 failed!"); + TASSERT(fabsf((X.v[1])-(-17.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a21 failed!"); + TASSERT(fabsf((X.v[5])-(19.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a22 failed!"); + TASSERT(fabsf((X.v[9])-(-10.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a23 failed!"); + TASSERT(fabsf((X.v[13])-(-20.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a24 failed!"); + TASSERT(fabsf((X.v[2])-(15.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a31 failed!"); + TASSERT(fabsf((X.v[6])-(15.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a32 failed!"); + TASSERT(fabsf((X.v[10])-(-5.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a33 failed!"); + TASSERT(fabsf((X.v[14])-(-18.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a34 failed!"); + TASSERT(fabsf((X.v[3])-(-17.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a41 failed!"); + TASSERT(fabsf((X.v[7])-(17.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a42 failed!"); + TASSERT(fabsf((X.v[11])-(2.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a43 failed!"); + TASSERT(fabsf((X.v[15])-(16.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a44 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat44fCheckOrthonormal(){ + SST_Mat44f X; /* 4 x 4 matrix */ + SST_Mat44f Y; /* 4 x 4 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = 6.000000f; + X.v[1] = 3.000000f; + X.v[2] = -16.000000f; + X.v[3] = 11.000000f; + X.v[4] = -20.000000f; + X.v[5] = 0.000000f; + X.v[6] = 14.000000f; + X.v[7] = 12.000000f; + X.v[8] = 3.000000f; + X.v[9] = -12.000000f; + X.v[10] = -16.000000f; + X.v[11] = 6.000000f; + X.v[12] = 3.000000f; + X.v[13] = 13.000000f; + X.v[14] = 10.000000f; + X.v[15] = 1.000000f; + Y.v[0] = -12.000000f; + Y.v[1] = 0.000000f; + Y.v[2] = -1.000000f; + Y.v[3] = -6.000000f; + Y.v[4] = 18.000000f; + Y.v[5] = 9.000000f; + Y.v[6] = -13.000000f; + Y.v[7] = -1.000000f; + Y.v[8] = -4.000000f; + Y.v[9] = -4.000000f; + Y.v[10] = 12.000000f; + Y.v[11] = 19.000000f; + Y.v[12] = -13.000000f; + Y.v[13] = -4.000000f; + Y.v[14] = 2.000000f; + Y.v[15] = 10.000000f; +/* +[[-0.29207543 0.67485899 -0.19610436 0.64869124] + [-0.14603771 -0.05987867 -0.94425398 -0.2889151 ] + [ 0.77886784 -0.23687853 -0.26374456 0.51738989] + [-0.53547162 -0.69632494 -0.01913862 0.47753054]] +[[ 1.00000000e+00 -2.98023224e-08 -2.42143869e-08 5.96046448e-08] + [ -2.98023224e-08 1.00000000e+00 1.49011612e-08 -2.98023224e-08] + [ -2.42143869e-08 1.49011612e-08 9.99999940e-01 7.45058060e-09] + [ 5.96046448e-08 -2.98023224e-08 7.45058060e-09 1.00000000e+00]] +*/ +/* Set X to orthogonal matrix Q */ + X.v[0] = (float)-0.292075f; + X.v[1] = (float)-0.146038f; + X.v[2] = (float)0.778868f; + X.v[3] = (float)-0.535472f; + X.v[4] = (float)0.674859f; + X.v[5] = (float)-0.059879f; + X.v[6] = (float)-0.236879f; + X.v[7] = (float)-0.696325f; + X.v[8] = (float)-0.196104f; + X.v[9] = (float)-0.944254f; + X.v[10] = (float)-0.263745f; + X.v[11] = (float)-0.019139f; + X.v[12] = (float)0.648691f; + X.v[13] = (float)-0.288915f; + X.v[14] = (float)0.517390f; + X.v[15] = (float)0.477531f; +/* Check Positive Test */ + TASSERT(SST_Math_Mat44fCheckOrthonormal(&X),"CheckOrthonormal failed when it should have passed"); +/* Check Negative Test */ + TASSERT(!SST_Math_Mat44fCheckOrthonormal(&Y),"CheckOrthonormal succeeded when it should have failed"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat44fDeterminant(){ + SST_Mat44f X; /* 4 x 4 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = -6.000000f; + X.v[1] = -8.000000f; + X.v[2] = 17.000000f; + X.v[3] = -17.000000f; + X.v[4] = 3.000000f; + X.v[5] = -1.000000f; + X.v[6] = 14.000000f; + X.v[7] = -17.000000f; + X.v[8] = 5.000000f; + X.v[9] = 12.000000f; + X.v[10] = -1.000000f; + X.v[11] = 16.000000f; + X.v[12] = 18.000000f; + X.v[13] = 13.000000f; + X.v[14] = 0.000000f; + X.v[15] = 13.000000f; +/* det(X) = +21323.0 + */ + float result = SST_Math_Mat44fDeterminant(&X); + TASSERT(fabsf( (result)/(21323.000000f) - 1.000000f ) <= 100*FLT_EPSILON,"Determinant failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat44fInvert(){ + SST_Mat44f X; /* 4 x 4 matrix */ + SST_Mat44f B; /* 4 x 4 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = -19.000000f; + X.v[1] = 3.000000f; + X.v[2] = 17.000000f; + X.v[3] = 5.000000f; + X.v[4] = -2.000000f; + X.v[5] = 16.000000f; + X.v[6] = 14.000000f; + X.v[7] = 3.000000f; + X.v[8] = -1.000000f; + X.v[9] = -11.000000f; + X.v[10] = -16.000000f; + X.v[11] = -7.000000f; + X.v[12] = 5.000000f; + X.v[13] = 12.000000f; + X.v[14] = 9.000000f; + X.v[15] = 9.000000f; +/* +[[-0.05553644 -0.000757 -0.01768633 0.04954924] + [-0.03282637 0.0999243 -0.02904136 -0.08595417] + [-0.11416971 0.12112036 -0.17018788 0.07212167] + [-0.04700296 0.06131718 -0.11286215 0.16832978]] +*/ + SST_Math_Mat44fInvert(&X,&B); + TASSERT(fabsf((B.v[0])-(-0.055536f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a11 failed!"); + TASSERT(fabsf((B.v[1])-(-0.032826f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a21 failed!"); + TASSERT(fabsf((B.v[2])-(-0.114170f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a31 failed!"); + TASSERT(fabsf((B.v[3])-(-0.047003f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a41 failed!"); + TASSERT(fabsf((B.v[4])-(-0.000757f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a12 failed!"); + TASSERT(fabsf((B.v[5])-(0.099924f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a22 failed!"); + TASSERT(fabsf((B.v[6])-(0.121120f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a32 failed!"); + TASSERT(fabsf((B.v[7])-(0.061317f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a42 failed!"); + TASSERT(fabsf((B.v[8])-(-0.017686f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a13 failed!"); + TASSERT(fabsf((B.v[9])-(-0.029041f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a23 failed!"); + TASSERT(fabsf((B.v[10])-(-0.170188f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a33 failed!"); + TASSERT(fabsf((B.v[11])-(-0.112862f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a43 failed!"); + TASSERT(fabsf((B.v[12])-(0.049549f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a14 failed!"); + TASSERT(fabsf((B.v[13])-(-0.085954f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a24 failed!"); + TASSERT(fabsf((B.v[14])-(0.072122f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a34 failed!"); + TASSERT(fabsf((B.v[15])-(0.168330f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a44 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat44fInvertLocal(){ + SST_Mat44f X; /* 4 x 4 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = 1.000000f; + X.v[1] = 7.000000f; + X.v[2] = 9.000000f; + X.v[3] = -2.000000f; + X.v[4] = 10.000000f; + X.v[5] = -3.000000f; + X.v[6] = -10.000000f; + X.v[7] = 8.000000f; + X.v[8] = -2.000000f; + X.v[9] = -2.000000f; + X.v[10] = -9.000000f; + X.v[11] = 16.000000f; + X.v[12] = 7.000000f; + X.v[13] = 2.000000f; + X.v[14] = -9.000000f; + X.v[15] = 3.000000f; +/* +() +[[ 0.04525488 0.0651752 0.06680968 0.05138421] + [ 0.11124732 -0.10389213 0.07845541 0.04505057] + [-0.04341608 0.03228113 -0.00766166 0.05679845] + [-0.03493717 0.14832976 -0.12381244 -0.05547043]] +*/ + SST_Math_Mat44fInvertLocal(&X); + TASSERT(fabsf((X.v[0])-(0.045255f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a11 failed!"); + TASSERT(fabsf((X.v[1])-(0.111247f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a21 failed!"); + TASSERT(fabsf((X.v[2])-(-0.043416f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a31 failed!"); + TASSERT(fabsf((X.v[3])-(-0.034937f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a41 failed!"); + TASSERT(fabsf((X.v[4])-(0.065175f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a12 failed!"); + TASSERT(fabsf((X.v[5])-(-0.103892f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a22 failed!"); + TASSERT(fabsf((X.v[6])-(0.032281f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a32 failed!"); + TASSERT(fabsf((X.v[7])-(0.148330f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a42 failed!"); + TASSERT(fabsf((X.v[8])-(0.066810f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a13 failed!"); + TASSERT(fabsf((X.v[9])-(0.078455f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a23 failed!"); + TASSERT(fabsf((X.v[10])-(-0.007662f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a33 failed!"); + TASSERT(fabsf((X.v[11])-(-0.123812f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a43 failed!"); + TASSERT(fabsf((X.v[12])-(0.051384f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a14 failed!"); + TASSERT(fabsf((X.v[13])-(0.045051f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a24 failed!"); + TASSERT(fabsf((X.v[14])-(0.056798f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a34 failed!"); + TASSERT(fabsf((X.v[15])-(-0.055470f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _a44 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat44fCreateLU(){ + SST_Mat44f X; /* 4 x 4 matrix */ + SST_Mat44f LU; /* 4 x 4 matrix */ + X.v[0] = 2.000000f; + X.v[1] = 1.000000f; + X.v[2] = 0.000000f; + X.v[3] = 4.000000f; + X.v[4] = -1.000000f; + X.v[5] = 0.000000f; + X.v[6] = 2.000000f; + X.v[7] = 2.000000f; + X.v[8] = -1.000000f; + X.v[9] = -1.000000f; + X.v[10] = 1.000000f; + X.v[11] = 0.000000f; + X.v[12] = 1.000000f; + X.v[13] = 2.000000f; + X.v[14] = 1.000000f; + X.v[15] = 0.000000f; + SST_Math_Mat44fCreateLU(&X,&LU); +/* +[[ 2 -1 -1 1] + [ 1 0 -1 2] + [ 0 2 1 1] + [ 4 2 0 0]] +*/ +/* +[[ 2. 0. 0. 0. ] + [ 1. 0.5 0. 0. ] + [ 0. 2. 3. 0. ] + [ 4. 4. 6. -4. ]] +*/ +/* +[[ 1. -0.5 -0.5 0.5 ] + [ 0. 1. -1. 3. ] + [ 0. 0. 1. -1.66666667] + [ 0. 0. 0. 1. ]] +*/ + TASSERT(fabsf((LU.v[0])-(2.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"L:Entry A_a11 failed!"); + TASSERT(fabsf((LU.v[4])-(-0.500000f)) <=100*FLT_EPSILON /* yes this is bad */,"U:Entry B_a12 failed!"); + TASSERT(fabsf((LU.v[8])-(-0.500000f)) <=100*FLT_EPSILON /* yes this is bad */,"U:Entry B_a13 failed!"); + TASSERT(fabsf((LU.v[12])-(0.500000f)) <=100*FLT_EPSILON /* yes this is bad */,"U:Entry B_a14 failed!"); + TASSERT(fabsf((LU.v[1])-(1.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"L:Entry A_a21 failed!"); + TASSERT(fabsf((LU.v[5])-(0.500000f)) <=100*FLT_EPSILON /* yes this is bad */,"L:Entry A_a22 failed!"); + TASSERT(fabsf((LU.v[9])-(-1.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"U:Entry B_a23 failed!"); + TASSERT(fabsf((LU.v[13])-(3.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"U:Entry B_a24 failed!"); + TASSERT(fabsf((LU.v[2])-(0.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"L:Entry A_a31 failed!"); + TASSERT(fabsf((LU.v[6])-(2.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"L:Entry A_a32 failed!"); + TASSERT(fabsf((LU.v[10])-(3.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"L:Entry A_a33 failed!"); + TASSERT(fabsf((LU.v[14])-(-1.666667f)) <=100*FLT_EPSILON /* yes this is bad */,"U:Entry B_a34 failed!"); + TASSERT(fabsf((LU.v[3])-(4.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"L:Entry A_a41 failed!"); + TASSERT(fabsf((LU.v[7])-(4.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"L:Entry A_a42 failed!"); + TASSERT(fabsf((LU.v[11])-(6.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"L:Entry A_a43 failed!"); + TASSERT(fabsf((LU.v[15])-(-4.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"L:Entry A_a44 failed!"); + return ZTEST_SUCCESS; +} +static const char* testSST_Math_Mat44fCreateLULocal(){ + SST_Mat44f X; /* 4 x 4 matrix */ + X.v[0] = 2.000000f; + X.v[1] = 1.000000f; + X.v[2] = 0.000000f; + X.v[3] = 4.000000f; + X.v[4] = -1.000000f; + X.v[5] = 0.000000f; + X.v[6] = 2.000000f; + X.v[7] = 2.000000f; + X.v[8] = -1.000000f; + X.v[9] = -1.000000f; + X.v[10] = 1.000000f; + X.v[11] = 0.000000f; + X.v[12] = 1.000000f; + X.v[13] = 2.000000f; + X.v[14] = 1.000000f; + X.v[15] = 0.000000f; + SST_Math_Mat44fCreateLULocal(&X); + TASSERT(fabsf((X.v[0])-(2.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"L:Entry A_a11 failed!"); + TASSERT(fabsf((X.v[4])-(-0.500000f)) <=100*FLT_EPSILON /* yes this is bad */,"U:Entry B_a12 failed!"); + TASSERT(fabsf((X.v[8])-(-0.500000f)) <=100*FLT_EPSILON /* yes this is bad */,"U:Entry B_a13 failed!"); + TASSERT(fabsf((X.v[12])-(0.500000f)) <=100*FLT_EPSILON /* yes this is bad */,"U:Entry B_a14 failed!"); + TASSERT(fabsf((X.v[1])-(1.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"L:Entry A_a21 failed!"); + TASSERT(fabsf((X.v[5])-(0.500000f)) <=100*FLT_EPSILON /* yes this is bad */,"L:Entry A_a22 failed!"); + TASSERT(fabsf((X.v[9])-(-1.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"U:Entry B_a23 failed!"); + TASSERT(fabsf((X.v[13])-(3.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"U:Entry B_a24 failed!"); + TASSERT(fabsf((X.v[2])-(0.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"L:Entry A_a31 failed!"); + TASSERT(fabsf((X.v[6])-(2.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"L:Entry A_a32 failed!"); + TASSERT(fabsf((X.v[10])-(3.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"L:Entry A_a33 failed!"); + TASSERT(fabsf((X.v[14])-(-1.666667f)) <=100*FLT_EPSILON /* yes this is bad */,"U:Entry B_a34 failed!"); + TASSERT(fabsf((X.v[3])-(4.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"L:Entry A_a41 failed!"); + TASSERT(fabsf((X.v[7])-(4.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"L:Entry A_a42 failed!"); + TASSERT(fabsf((X.v[11])-(6.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"L:Entry A_a43 failed!"); + TASSERT(fabsf((X.v[15])-(-4.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"L:Entry A_a44 failed!"); + return ZTEST_SUCCESS; +} +static const char* testSST_Math_Mat44fApplyLUMat(){ + SST_Mat44f X; /* 4 x 4 matrix */ + SST_Mat44f LU; /* 4 x 4 matrix */ + SST_Mat44f I; /* 4 x 4 matrix */ + X.v[0] = 2.000000f; + X.v[1] = 1.000000f; + X.v[2] = 0.000000f; + X.v[3] = 4.000000f; + X.v[4] = -1.000000f; + X.v[5] = 0.000000f; + X.v[6] = 2.000000f; + X.v[7] = 2.000000f; + X.v[8] = -1.000000f; + X.v[9] = -1.000000f; + X.v[10] = 1.000000f; + X.v[11] = 0.000000f; + X.v[12] = 1.000000f; + X.v[13] = 2.000000f; + X.v[14] = 1.000000f; + X.v[15] = 0.000000f; + SST_Math_Mat44fCreateLU(&X,&LU); +/* +[[ 2 -1 -1 1] + [ 1 0 -1 2] + [ 0 2 1 1] + [ 4 2 0 0]] +*/ +/* +[[ 2. 0. 0. 0. ] + [ 1. 0.5 0. 0. ] + [ 0. 2. 3. 0. ] + [ 4. 4. 6. -4. ]] +*/ +/* +[[ 1. -0.5 -0.5 0.5 ] + [ 0. 1. -1. 3. ] + [ 0. 0. 1. -1.66666667] + [ 0. 0. 0. 1. ]] +*/ + TASSERT(fabsf((LU.v[0])-(2.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"L:Entry A_a11 failed!"); + TASSERT(fabsf((LU.v[4])-(-0.500000f)) <=100*FLT_EPSILON /* yes this is bad */,"U:Entry B_a12 failed!"); + TASSERT(fabsf((LU.v[8])-(-0.500000f)) <=100*FLT_EPSILON /* yes this is bad */,"U:Entry B_a13 failed!"); + TASSERT(fabsf((LU.v[12])-(0.500000f)) <=100*FLT_EPSILON /* yes this is bad */,"U:Entry B_a14 failed!"); + TASSERT(fabsf((LU.v[1])-(1.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"L:Entry A_a21 failed!"); + TASSERT(fabsf((LU.v[5])-(0.500000f)) <=100*FLT_EPSILON /* yes this is bad */,"L:Entry A_a22 failed!"); + TASSERT(fabsf((LU.v[9])-(-1.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"U:Entry B_a23 failed!"); + TASSERT(fabsf((LU.v[13])-(3.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"U:Entry B_a24 failed!"); + TASSERT(fabsf((LU.v[2])-(0.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"L:Entry A_a31 failed!"); + TASSERT(fabsf((LU.v[6])-(2.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"L:Entry A_a32 failed!"); + TASSERT(fabsf((LU.v[10])-(3.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"L:Entry A_a33 failed!"); + TASSERT(fabsf((LU.v[14])-(-1.666667f)) <=100*FLT_EPSILON /* yes this is bad */,"U:Entry B_a34 failed!"); + TASSERT(fabsf((LU.v[3])-(4.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"L:Entry A_a41 failed!"); + TASSERT(fabsf((LU.v[7])-(4.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"L:Entry A_a42 failed!"); + TASSERT(fabsf((LU.v[11])-(6.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"L:Entry A_a43 failed!"); + TASSERT(fabsf((LU.v[15])-(-4.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"L:Entry A_a44 failed!"); + SST_Math_Mat44fApplyLUMat(&LU,&X,&I); + TASSERT(fabsf((I.v[0])-(1.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"I:Entry I_a11 failed!"); + TASSERT(fabsf((I.v[1])-(0.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"I:Entry I_a21 failed!"); + TASSERT(fabsf((I.v[2])-(0.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"I:Entry I_a31 failed!"); + TASSERT(fabsf((I.v[3])-(0.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"I:Entry I_a41 failed!"); + TASSERT(fabsf((I.v[4])-(0.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"I:Entry I_a12 failed!"); + TASSERT(fabsf((I.v[5])-(1.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"I:Entry I_a22 failed!"); + TASSERT(fabsf((I.v[6])-(0.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"I:Entry I_a32 failed!"); + TASSERT(fabsf((I.v[7])-(0.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"I:Entry I_a42 failed!"); + TASSERT(fabsf((I.v[8])-(0.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"I:Entry I_a13 failed!"); + TASSERT(fabsf((I.v[9])-(0.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"I:Entry I_a23 failed!"); + TASSERT(fabsf((I.v[10])-(1.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"I:Entry I_a33 failed!"); + TASSERT(fabsf((I.v[11])-(0.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"I:Entry I_a43 failed!"); + TASSERT(fabsf((I.v[12])-(0.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"I:Entry I_a14 failed!"); + TASSERT(fabsf((I.v[13])-(0.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"I:Entry I_a24 failed!"); + TASSERT(fabsf((I.v[14])-(0.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"I:Entry I_a34 failed!"); + TASSERT(fabsf((I.v[15])-(1.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"I:Entry I_a44 failed!"); + return ZTEST_SUCCESS; +} +static const char* testSST_Math_Mat44fApplyLUMatLocal(){ + SST_Mat44f X; /* 4 x 4 matrix */ + SST_Mat44f Xinv; /* 4 x 4 matrix */ + X.v[0] = 2.000000f; + X.v[1] = 1.000000f; + X.v[2] = 0.000000f; + X.v[3] = 4.000000f; + X.v[4] = -1.000000f; + X.v[5] = 0.000000f; + X.v[6] = 2.000000f; + X.v[7] = 2.000000f; + X.v[8] = -1.000000f; + X.v[9] = -1.000000f; + X.v[10] = 1.000000f; + X.v[11] = 0.000000f; + X.v[12] = 1.000000f; + X.v[13] = 2.000000f; + X.v[14] = 1.000000f; + X.v[15] = 0.000000f; + Xinv.v[0] = 2.000000f; + Xinv.v[1] = 1.000000f; + Xinv.v[2] = 0.000000f; + Xinv.v[3] = 4.000000f; + Xinv.v[4] = -1.000000f; + Xinv.v[5] = 0.000000f; + Xinv.v[6] = 2.000000f; + Xinv.v[7] = 2.000000f; + Xinv.v[8] = -1.000000f; + Xinv.v[9] = -1.000000f; + Xinv.v[10] = 1.000000f; + Xinv.v[11] = 0.000000f; + Xinv.v[12] = 1.000000f; + Xinv.v[13] = 2.000000f; + Xinv.v[14] = 1.000000f; + Xinv.v[15] = 0.000000f; + SST_Math_Mat44fCreateLULocal(&X); + TASSERT(fabsf((X.v[0])-(2.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"L:Entry A_a11 failed!"); + TASSERT(fabsf((X.v[4])-(-0.500000f)) <=100*FLT_EPSILON /* yes this is bad */,"U:Entry B_a12 failed!"); + TASSERT(fabsf((X.v[8])-(-0.500000f)) <=100*FLT_EPSILON /* yes this is bad */,"U:Entry B_a13 failed!"); + TASSERT(fabsf((X.v[12])-(0.500000f)) <=100*FLT_EPSILON /* yes this is bad */,"U:Entry B_a14 failed!"); + TASSERT(fabsf((X.v[1])-(1.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"L:Entry A_a21 failed!"); + TASSERT(fabsf((X.v[5])-(0.500000f)) <=100*FLT_EPSILON /* yes this is bad */,"L:Entry A_a22 failed!"); + TASSERT(fabsf((X.v[9])-(-1.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"U:Entry B_a23 failed!"); + TASSERT(fabsf((X.v[13])-(3.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"U:Entry B_a24 failed!"); + TASSERT(fabsf((X.v[2])-(0.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"L:Entry A_a31 failed!"); + TASSERT(fabsf((X.v[6])-(2.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"L:Entry A_a32 failed!"); + TASSERT(fabsf((X.v[10])-(3.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"L:Entry A_a33 failed!"); + TASSERT(fabsf((X.v[14])-(-1.666667f)) <=100*FLT_EPSILON /* yes this is bad */,"U:Entry B_a34 failed!"); + TASSERT(fabsf((X.v[3])-(4.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"L:Entry A_a41 failed!"); + TASSERT(fabsf((X.v[7])-(4.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"L:Entry A_a42 failed!"); + TASSERT(fabsf((X.v[11])-(6.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"L:Entry A_a43 failed!"); + TASSERT(fabsf((X.v[15])-(-4.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"L:Entry A_a44 failed!"); + SST_Math_Mat44fApplyLUMatLocal(&X,&Xinv); + TASSERT(fabsf((Xinv.v[0])-(1.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Xinv:Entry Xinv_a11 failed!"); + TASSERT(fabsf((Xinv.v[1])-(0.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Xinv:Entry Xinv_a21 failed!"); + TASSERT(fabsf((Xinv.v[2])-(0.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Xinv:Entry Xinv_a31 failed!"); + TASSERT(fabsf((Xinv.v[3])-(0.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Xinv:Entry Xinv_a41 failed!"); + TASSERT(fabsf((Xinv.v[4])-(0.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Xinv:Entry Xinv_a12 failed!"); + TASSERT(fabsf((Xinv.v[5])-(1.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Xinv:Entry Xinv_a22 failed!"); + TASSERT(fabsf((Xinv.v[6])-(0.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Xinv:Entry Xinv_a32 failed!"); + TASSERT(fabsf((Xinv.v[7])-(0.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Xinv:Entry Xinv_a42 failed!"); + TASSERT(fabsf((Xinv.v[8])-(0.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Xinv:Entry Xinv_a13 failed!"); + TASSERT(fabsf((Xinv.v[9])-(0.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Xinv:Entry Xinv_a23 failed!"); + TASSERT(fabsf((Xinv.v[10])-(1.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Xinv:Entry Xinv_a33 failed!"); + TASSERT(fabsf((Xinv.v[11])-(0.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Xinv:Entry Xinv_a43 failed!"); + TASSERT(fabsf((Xinv.v[12])-(0.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Xinv:Entry Xinv_a14 failed!"); + TASSERT(fabsf((Xinv.v[13])-(0.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Xinv:Entry Xinv_a24 failed!"); + TASSERT(fabsf((Xinv.v[14])-(0.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Xinv:Entry Xinv_a34 failed!"); + TASSERT(fabsf((Xinv.v[15])-(1.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Xinv:Entry Xinv_a44 failed!"); + return ZTEST_SUCCESS; +} +static const char* testSST_Math_Mat44fApplyLUVec(){ + SST_Mat44f X; /* 4 x 4 matrix */ + SST_Mat44f LU; /* 4 x 4 matrix */ + SST_Vec4f b; /* 4 x 4 vector */ + SST_Vec4f x; /* 4 x 4 vector */ + X.v[0] = 2.000000f; + X.v[1] = 1.000000f; + X.v[2] = 0.000000f; + X.v[3] = 4.000000f; + X.v[4] = -1.000000f; + X.v[5] = 0.000000f; + X.v[6] = 2.000000f; + X.v[7] = 2.000000f; + X.v[8] = -1.000000f; + X.v[9] = -1.000000f; + X.v[10] = 1.000000f; + X.v[11] = 0.000000f; + X.v[12] = 1.000000f; + X.v[13] = 2.000000f; + X.v[14] = 1.000000f; + X.v[15] = 0.000000f; + b.v[0] = 2.000000f; + b.v[1] = -1.000000f; + b.v[2] = 1.000000f; + b.v[3] = 1.000000f; + SST_Math_Mat44fCreateLU(&X,&LU); + SST_Math_Mat44fApplyLUVec(&LU,&b,&x); + TASSERT(fabsf((x.v[0])-(1.583333f)) <=100*FLT_EPSILON /* yes this is bad */,"x:Entry x_a1 failed!"); + TASSERT(fabsf((x.v[1])-(-2.666667f)) <=100*FLT_EPSILON /* yes this is bad */,"x:Entry x_a2 failed!"); + TASSERT(fabsf((x.v[2])-(5.083333f)) <=100*FLT_EPSILON /* yes this is bad */,"x:Entry x_a3 failed!"); + TASSERT(fabsf((x.v[3])-(1.250000f)) <=100*FLT_EPSILON /* yes this is bad */,"x:Entry x_a4 failed!"); + return ZTEST_SUCCESS; +} +static const char* testSST_Math_Mat44fApplyLUVecLocal(){ + SST_Mat44f X; /* 4 x 4 matrix */ + SST_Mat44f LU; /* 4 x 4 matrix */ + SST_Vec4f b; /* 4 x 4 vector */ + X.v[0] = 2.000000f; + X.v[1] = 1.000000f; + X.v[2] = 0.000000f; + X.v[3] = 4.000000f; + X.v[4] = -1.000000f; + X.v[5] = 0.000000f; + X.v[6] = 2.000000f; + X.v[7] = 2.000000f; + X.v[8] = -1.000000f; + X.v[9] = -1.000000f; + X.v[10] = 1.000000f; + X.v[11] = 0.000000f; + X.v[12] = 1.000000f; + X.v[13] = 2.000000f; + X.v[14] = 1.000000f; + X.v[15] = 0.000000f; + b.v[0] = 2.000000f; + b.v[1] = -1.000000f; + b.v[2] = 1.000000f; + b.v[3] = 1.000000f; + SST_Math_Mat44fCreateLU(&X,&LU); + SST_Math_Mat44fApplyLUVecLocal(&LU,&b); + TASSERT(fabsf((b.v[0])-(1.583333f)) <=100*FLT_EPSILON /* yes this is bad */,"x:Entry x_a1 failed!"); + TASSERT(fabsf((b.v[1])-(-2.666667f)) <=100*FLT_EPSILON /* yes this is bad */,"x:Entry x_a2 failed!"); + TASSERT(fabsf((b.v[2])-(5.083333f)) <=100*FLT_EPSILON /* yes this is bad */,"x:Entry x_a3 failed!"); + TASSERT(fabsf((b.v[3])-(1.250000f)) <=100*FLT_EPSILON /* yes this is bad */,"x:Entry x_a4 failed!"); + return ZTEST_SUCCESS; +} diff --git a/ZTestSuite/Test-SST_Mat44i.cpp b/ZTestSuite/Test-SST_Mat44i.cpp new file mode 100644 index 0000000..fdf3af2 --- /dev/null +++ b/ZTestSuite/Test-SST_Mat44i.cpp @@ -0,0 +1,1026 @@ +/* + AUTOMATICALLY GENERATED FILE - DO NOT EDIT! + Please change MatrixNxN.py and re-run it +*/ +/* Generated with ./MatrixNxN.py n = 4, TYPE = int */ + +#include "ZUnitTest.hpp" +#include <float.h> +#include <math.h> +#include <stdlib.h> +#include <stdio.h> +#include <SST/SST_Mat44.h> +#include <SST/SST_Vec4.h> + + + + +static const char* testSST_Math_Mat44iAdd(); +static const char* testSST_Math_Mat44iAddLocal(); +static const char* testSST_Math_Mat44iSubtract(); +static const char* testSST_Math_Mat44iSubtractLocal(); +static const char* testSST_Math_Mat44iMultiplyElementwise(); +static const char* testSST_Math_Mat44iMultiplyElementwiseLocal(); +static const char* testSST_Math_Mat44iMultiplyScalar(); +static const char* testSST_Math_Mat44iMultiplyScalarLocal(); +static const char* testSST_Math_Mat44iMultiplyMatrix(); +static const char* testSST_Math_Mat44iMultiplyMatrixLocal(); +static const char* testSST_Math_Mat44iMultiplyVector(); +static const char* testSST_Math_Mat44iMultiplyVectorLocal(); +static const char* testSST_Math_Mat44iTranspose(); +static const char* testSST_Math_Mat44iTransposeLocal(); +static const char* testSST_Math_Mat44iDeterminant(); +static const char* testSST_Math_Mat44iCheckOrthonormal(); +// List of unit tests +ZUnitTest SST_Math_Mat44iUnitTests[] = +{ +{ "testSST_Math_Mat44iAdd " , testSST_Math_Mat44iAdd }, +{ "testSST_Math_Mat44iAddLocal " , testSST_Math_Mat44iAddLocal }, +{ "testSST_Math_Mat44iSubtract " , testSST_Math_Mat44iSubtract }, +{ "testSST_Math_Mat44iSubtractLocal " , testSST_Math_Mat44iSubtractLocal }, +{ "testSST_Math_Mat44iMultiplyElementwise " , testSST_Math_Mat44iMultiplyElementwise }, +{ "testSST_Math_Mat44iMultiplyElementwiseLocal " , testSST_Math_Mat44iMultiplyElementwiseLocal }, +{ "testSST_Math_Mat44iMultiplyScalar " , testSST_Math_Mat44iMultiplyScalar }, +{ "testSST_Math_Mat44iMultiplyScalarLocal " , testSST_Math_Mat44iMultiplyScalarLocal }, +{ "testSST_Math_Mat44iMultiplyMatrix " , testSST_Math_Mat44iMultiplyMatrix }, +{ "testSST_Math_Mat44iMultiplyMatrixLocal " , testSST_Math_Mat44iMultiplyMatrixLocal }, +{ "testSST_Math_Mat44iMultiplyVector " , testSST_Math_Mat44iMultiplyVector }, +{ "testSST_Math_Mat44iMultiplyVectorLocal " , testSST_Math_Mat44iMultiplyVectorLocal }, +{ "testSST_Math_Mat44iDeterminant " , testSST_Math_Mat44iDeterminant }, +{ "testSST_Math_Mat44iCheckOrthonormal " , testSST_Math_Mat44iCheckOrthonormal }, +{ "testSST_Math_Mat44iTranspose " , testSST_Math_Mat44iTranspose }, +{ "testSST_Math_Mat44iTransposeLocal " , testSST_Math_Mat44iTransposeLocal } +}; +DECLARE_ZTESTBLOCK(SST_Math_Mat44i) + +/******************************************************************************/ + +static const char* testSST_Math_Mat44iAdd(){ + SST_Mat44i X; /* 4 x 4 matrix */ + SST_Mat44i Y; /* 4 x 4 matrix */ + SST_Mat44i A; /* 4 x 4 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = -18; + X.v[1] = -6; + X.v[2] = -4; + X.v[3] = 2; + X.v[4] = -1; + X.v[5] = 18; + X.v[6] = 1; + X.v[7] = -19; + X.v[8] = -5; + X.v[9] = 7; + X.v[10] = -15; + X.v[11] = -20; + X.v[12] = -20; + X.v[13] = 19; + X.v[14] = 15; + X.v[15] = 2; + Y.v[0] = -5; + Y.v[1] = 5; + Y.v[2] = 19; + Y.v[3] = -11; + Y.v[4] = 1; + Y.v[5] = -16; + Y.v[6] = 9; + Y.v[7] = 15; + Y.v[8] = -20; + Y.v[9] = -20; + Y.v[10] = -15; + Y.v[11] = -14; + Y.v[12] = -10; + Y.v[13] = -3; + Y.v[14] = 16; + Y.v[15] = 13; +/* +[[-18 -1 -5 -20] + [ -6 18 7 19] + [ -4 1 -15 15] + [ 2 -19 -20 2]] +[[ -5 1 -20 -10] + [ 5 -16 -20 -3] + [ 19 9 -15 16] + [-11 15 -14 13]] +[[-23 0 -25 -30] + [ -1 2 -13 16] + [ 15 10 -30 31] + [ -9 -4 -34 15]] +*/ + SST_Math_Mat44iAdd(&X,&Y,&A); + TASSERT((A.v[0])==(-23),"Entry _a11 failed!"); + TASSERT((A.v[4])==(0),"Entry _a12 failed!"); + TASSERT((A.v[8])==(-25),"Entry _a13 failed!"); + TASSERT((A.v[12])==(-30),"Entry _a14 failed!"); + TASSERT((A.v[1])==(-1),"Entry _a21 failed!"); + TASSERT((A.v[5])==(2),"Entry _a22 failed!"); + TASSERT((A.v[9])==(-13),"Entry _a23 failed!"); + TASSERT((A.v[13])==(16),"Entry _a24 failed!"); + TASSERT((A.v[2])==(15),"Entry _a31 failed!"); + TASSERT((A.v[6])==(10),"Entry _a32 failed!"); + TASSERT((A.v[10])==(-30),"Entry _a33 failed!"); + TASSERT((A.v[14])==(31),"Entry _a34 failed!"); + TASSERT((A.v[3])==(-9),"Entry _a41 failed!"); + TASSERT((A.v[7])==(-4),"Entry _a42 failed!"); + TASSERT((A.v[11])==(-34),"Entry _a43 failed!"); + TASSERT((A.v[15])==(15),"Entry _a44 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat44iAddLocal(){ + SST_Mat44i X; /* 4 x 4 matrix */ + SST_Mat44i Y; /* 4 x 4 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = -3; + X.v[1] = 8; + X.v[2] = -15; + X.v[3] = 2; + X.v[4] = 7; + X.v[5] = 17; + X.v[6] = 7; + X.v[7] = -4; + X.v[8] = 0; + X.v[9] = 8; + X.v[10] = 13; + X.v[11] = -6; + X.v[12] = 6; + X.v[13] = -1; + X.v[14] = -6; + X.v[15] = -11; + Y.v[0] = 16; + Y.v[1] = -4; + Y.v[2] = 17; + Y.v[3] = 2; + Y.v[4] = -5; + Y.v[5] = 3; + Y.v[6] = -5; + Y.v[7] = -4; + Y.v[8] = -12; + Y.v[9] = -8; + Y.v[10] = 7; + Y.v[11] = -6; + Y.v[12] = 8; + Y.v[13] = 15; + Y.v[14] = 12; + Y.v[15] = 10; +/* +[[ -3 7 0 6] + [ 8 17 8 -1] + [-15 7 13 -6] + [ 2 -4 -6 -11]] +[[ 16 -5 -12 8] + [ -4 3 -8 15] + [ 17 -5 7 12] + [ 2 -4 -6 10]] +[[ 13 2 -12 14] + [ 4 20 0 14] + [ 2 2 20 6] + [ 4 -8 -12 -1]] +*/ + SST_Math_Mat44iAddLocal(&X,&Y); /* for accuracy */ + TASSERT((X.v[0])==(13),"Entry _a11 failed!"); + TASSERT((X.v[4])==(2),"Entry _a12 failed!"); + TASSERT((X.v[8])==(-12),"Entry _a13 failed!"); + TASSERT((X.v[12])==(14),"Entry _a14 failed!"); + TASSERT((X.v[1])==(4),"Entry _a21 failed!"); + TASSERT((X.v[5])==(20),"Entry _a22 failed!"); + TASSERT((X.v[9])==(0),"Entry _a23 failed!"); + TASSERT((X.v[13])==(14),"Entry _a24 failed!"); + TASSERT((X.v[2])==(2),"Entry _a31 failed!"); + TASSERT((X.v[6])==(2),"Entry _a32 failed!"); + TASSERT((X.v[10])==(20),"Entry _a33 failed!"); + TASSERT((X.v[14])==(6),"Entry _a34 failed!"); + TASSERT((X.v[3])==(4),"Entry _a41 failed!"); + TASSERT((X.v[7])==(-8),"Entry _a42 failed!"); + TASSERT((X.v[11])==(-12),"Entry _a43 failed!"); + TASSERT((X.v[15])==(-1),"Entry _a44 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat44iSubtract(){ + SST_Mat44i X; /* 4 x 4 matrix */ + SST_Mat44i Y; /* 4 x 4 matrix */ + SST_Mat44i A; /* 4 x 4 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = -3; + X.v[1] = -5; + X.v[2] = -8; + X.v[3] = -4; + X.v[4] = -1; + X.v[5] = 17; + X.v[6] = 16; + X.v[7] = 8; + X.v[8] = 14; + X.v[9] = -5; + X.v[10] = 18; + X.v[11] = 12; + X.v[12] = -20; + X.v[13] = -13; + X.v[14] = -4; + X.v[15] = 10; + Y.v[0] = -13; + Y.v[1] = -11; + Y.v[2] = -2; + Y.v[3] = 15; + Y.v[4] = -4; + Y.v[5] = -6; + Y.v[6] = 12; + Y.v[7] = 11; + Y.v[8] = -13; + Y.v[9] = -4; + Y.v[10] = 17; + Y.v[11] = -9; + Y.v[12] = -17; + Y.v[13] = 12; + Y.v[14] = 14; + Y.v[15] = 6; +/* +[[ -3 -1 14 -20] + [ -5 17 -5 -13] + [ -8 16 18 -4] + [ -4 8 12 10]] +[[-13 -4 -13 -17] + [-11 -6 -4 12] + [ -2 12 17 14] + [ 15 11 -9 6]] +[[ 10 3 27 -3] + [ 6 23 -1 -25] + [ -6 4 1 -18] + [-19 -3 21 4]] +*/ + SST_Math_Mat44iSubtract(&X,&Y,&A); + TASSERT((A.v[0])==(10),"Entry _a11 failed!"); + TASSERT((A.v[4])==(3),"Entry _a12 failed!"); + TASSERT((A.v[8])==(27),"Entry _a13 failed!"); + TASSERT((A.v[12])==(-3),"Entry _a14 failed!"); + TASSERT((A.v[1])==(6),"Entry _a21 failed!"); + TASSERT((A.v[5])==(23),"Entry _a22 failed!"); + TASSERT((A.v[9])==(-1),"Entry _a23 failed!"); + TASSERT((A.v[13])==(-25),"Entry _a24 failed!"); + TASSERT((A.v[2])==(-6),"Entry _a31 failed!"); + TASSERT((A.v[6])==(4),"Entry _a32 failed!"); + TASSERT((A.v[10])==(1),"Entry _a33 failed!"); + TASSERT((A.v[14])==(-18),"Entry _a34 failed!"); + TASSERT((A.v[3])==(-19),"Entry _a41 failed!"); + TASSERT((A.v[7])==(-3),"Entry _a42 failed!"); + TASSERT((A.v[11])==(21),"Entry _a43 failed!"); + TASSERT((A.v[15])==(4),"Entry _a44 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat44iSubtractLocal(){ + SST_Mat44i X; /* 4 x 4 matrix */ + SST_Mat44i Y; /* 4 x 4 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = -11; + X.v[1] = -11; + X.v[2] = 15; + X.v[3] = 2; + X.v[4] = 11; + X.v[5] = 17; + X.v[6] = -17; + X.v[7] = 1; + X.v[8] = -13; + X.v[9] = -18; + X.v[10] = -3; + X.v[11] = 6; + X.v[12] = 17; + X.v[13] = -10; + X.v[14] = 16; + X.v[15] = 4; + Y.v[0] = -7; + Y.v[1] = 15; + Y.v[2] = -13; + Y.v[3] = -10; + Y.v[4] = -5; + Y.v[5] = 10; + Y.v[6] = 10; + Y.v[7] = -3; + Y.v[8] = 0; + Y.v[9] = -16; + Y.v[10] = -6; + Y.v[11] = -13; + Y.v[12] = -1; + Y.v[13] = -16; + Y.v[14] = 7; + Y.v[15] = 5; +/* +[[-11 11 -13 17] + [-11 17 -18 -10] + [ 15 -17 -3 16] + [ 2 1 6 4]] +[[ -7 -5 0 -1] + [ 15 10 -16 -16] + [-13 10 -6 7] + [-10 -3 -13 5]] +[[ -4 16 -13 18] + [-26 7 -2 6] + [ 28 -27 3 9] + [ 12 4 19 -1]] +*/ + SST_Math_Mat44iSubtractLocal(&X,&Y); /* for accuracy */ + TASSERT((X.v[0])==(-4),"Entry _a11 failed!"); + TASSERT((X.v[4])==(16),"Entry _a12 failed!"); + TASSERT((X.v[8])==(-13),"Entry _a13 failed!"); + TASSERT((X.v[12])==(18),"Entry _a14 failed!"); + TASSERT((X.v[1])==(-26),"Entry _a21 failed!"); + TASSERT((X.v[5])==(7),"Entry _a22 failed!"); + TASSERT((X.v[9])==(-2),"Entry _a23 failed!"); + TASSERT((X.v[13])==(6),"Entry _a24 failed!"); + TASSERT((X.v[2])==(28),"Entry _a31 failed!"); + TASSERT((X.v[6])==(-27),"Entry _a32 failed!"); + TASSERT((X.v[10])==(3),"Entry _a33 failed!"); + TASSERT((X.v[14])==(9),"Entry _a34 failed!"); + TASSERT((X.v[3])==(12),"Entry _a41 failed!"); + TASSERT((X.v[7])==(4),"Entry _a42 failed!"); + TASSERT((X.v[11])==(19),"Entry _a43 failed!"); + TASSERT((X.v[15])==(-1),"Entry _a44 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat44iMultiplyElementwise(){ + SST_Mat44i X; /* 4 x 4 matrix */ + SST_Mat44i Y; /* 4 x 4 matrix */ + SST_Mat44i A; /* 4 x 4 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = -2; + X.v[1] = 16; + X.v[2] = -15; + X.v[3] = 2; + X.v[4] = -16; + X.v[5] = -3; + X.v[6] = -9; + X.v[7] = 18; + X.v[8] = -7; + X.v[9] = 12; + X.v[10] = -14; + X.v[11] = -7; + X.v[12] = 6; + X.v[13] = -7; + X.v[14] = 15; + X.v[15] = 3; + Y.v[0] = 14; + Y.v[1] = 18; + Y.v[2] = -15; + Y.v[3] = 18; + Y.v[4] = -6; + Y.v[5] = 7; + Y.v[6] = 5; + Y.v[7] = -15; + Y.v[8] = -4; + Y.v[9] = -16; + Y.v[10] = -8; + Y.v[11] = 15; + Y.v[12] = 4; + Y.v[13] = -3; + Y.v[14] = 18; + Y.v[15] = -17; +/* +[[ -2 -16 -7 6] + [ 16 -3 12 -7] + [-15 -9 -14 15] + [ 2 18 -7 3]] +[[ 14 -6 -4 4] + [ 18 7 -16 -3] + [-15 5 -8 18] + [ 18 -15 15 -17]] +[[ -28 96 28 24] + [ 288 -21 -192 21] + [ 225 -45 112 270] + [ 36 -270 -105 -51]] +*/ + SST_Math_Mat44iMultiplyElementwise(&X, &Y, &A); + TASSERT((A.v[0])==(-28),"Entry _a11 failed!"); + TASSERT((A.v[4])==(96),"Entry _a12 failed!"); + TASSERT((A.v[8])==(28),"Entry _a13 failed!"); + TASSERT((A.v[12])==(24),"Entry _a14 failed!"); + TASSERT((A.v[1])==(288),"Entry _a21 failed!"); + TASSERT((A.v[5])==(-21),"Entry _a22 failed!"); + TASSERT((A.v[9])==(-192),"Entry _a23 failed!"); + TASSERT((A.v[13])==(21),"Entry _a24 failed!"); + TASSERT((A.v[2])==(225),"Entry _a31 failed!"); + TASSERT((A.v[6])==(-45),"Entry _a32 failed!"); + TASSERT((A.v[10])==(112),"Entry _a33 failed!"); + TASSERT((A.v[14])==(270),"Entry _a34 failed!"); + TASSERT((A.v[3])==(36),"Entry _a41 failed!"); + TASSERT((A.v[7])==(-270),"Entry _a42 failed!"); + TASSERT((A.v[11])==(-105),"Entry _a43 failed!"); + TASSERT((A.v[15])==(-51),"Entry _a44 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat44iMultiplyElementwiseLocal(){ + SST_Mat44i X; /* 4 x 4 matrix */ + SST_Mat44i Y; /* 4 x 4 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = -11; + X.v[1] = 5; + X.v[2] = 6; + X.v[3] = -1; + X.v[4] = 18; + X.v[5] = -6; + X.v[6] = -6; + X.v[7] = -10; + X.v[8] = -10; + X.v[9] = -5; + X.v[10] = 11; + X.v[11] = -19; + X.v[12] = 15; + X.v[13] = -2; + X.v[14] = -13; + X.v[15] = 16; + Y.v[0] = 4; + Y.v[1] = -2; + Y.v[2] = -8; + Y.v[3] = -4; + Y.v[4] = 6; + Y.v[5] = -7; + Y.v[6] = 11; + Y.v[7] = 19; + Y.v[8] = -1; + Y.v[9] = 17; + Y.v[10] = 15; + Y.v[11] = -17; + Y.v[12] = 17; + Y.v[13] = -5; + Y.v[14] = -2; + Y.v[15] = -17; +/* +[[-11 18 -10 15] + [ 5 -6 -5 -2] + [ 6 -6 11 -13] + [ -1 -10 -19 16]] +[[ 4 6 -1 17] + [ -2 -7 17 -5] + [ -8 11 15 -2] + [ -4 19 -17 -17]] +[[ -44 108 10 255] + [ -10 42 -85 10] + [ -48 -66 165 26] + [ 4 -190 323 -272]] +*/ + SST_Math_Mat44iMultiplyElementwiseLocal(&X,&Y); + TASSERT((X.v[0])==(-44),"Entry _a11 failed!"); + TASSERT((X.v[4])==(108),"Entry _a12 failed!"); + TASSERT((X.v[8])==(10),"Entry _a13 failed!"); + TASSERT((X.v[12])==(255),"Entry _a14 failed!"); + TASSERT((X.v[1])==(-10),"Entry _a21 failed!"); + TASSERT((X.v[5])==(42),"Entry _a22 failed!"); + TASSERT((X.v[9])==(-85),"Entry _a23 failed!"); + TASSERT((X.v[13])==(10),"Entry _a24 failed!"); + TASSERT((X.v[2])==(-48),"Entry _a31 failed!"); + TASSERT((X.v[6])==(-66),"Entry _a32 failed!"); + TASSERT((X.v[10])==(165),"Entry _a33 failed!"); + TASSERT((X.v[14])==(26),"Entry _a34 failed!"); + TASSERT((X.v[3])==(4),"Entry _a41 failed!"); + TASSERT((X.v[7])==(-190),"Entry _a42 failed!"); + TASSERT((X.v[11])==(323),"Entry _a43 failed!"); + TASSERT((X.v[15])==(-272),"Entry _a44 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat44iMultiplyScalar(){ + SST_Mat44i X; /* 4 x 4 matrix */ + SST_Mat44i A; /* 4 x 4 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = 5; + X.v[1] = -18; + X.v[2] = -4; + X.v[3] = 6; + X.v[4] = -18; + X.v[5] = -11; + X.v[6] = -5; + X.v[7] = 19; + X.v[8] = -8; + X.v[9] = -18; + X.v[10] = 0; + X.v[11] = 10; + X.v[12] = 6; + X.v[13] = 8; + X.v[14] = -5; + X.v[15] = -2; +/* +[[ 5 -18 -8 6] + [-18 -11 -18 8] + [ -4 -5 0 -5] + [ 6 19 10 -2]] +[[ 10 -36 -16 12] + [-36 -22 -36 16] + [ -8 -10 0 -10] + [ 12 38 20 -4]] +*/ + SST_Math_Mat44iMultiplyScalar(&X,2,&A); + TASSERT((A.v[0])==(10),"Entry _a11 failed!"); + TASSERT((A.v[4])==(-36),"Entry _a12 failed!"); + TASSERT((A.v[8])==(-16),"Entry _a13 failed!"); + TASSERT((A.v[12])==(12),"Entry _a14 failed!"); + TASSERT((A.v[1])==(-36),"Entry _a21 failed!"); + TASSERT((A.v[5])==(-22),"Entry _a22 failed!"); + TASSERT((A.v[9])==(-36),"Entry _a23 failed!"); + TASSERT((A.v[13])==(16),"Entry _a24 failed!"); + TASSERT((A.v[2])==(-8),"Entry _a31 failed!"); + TASSERT((A.v[6])==(-10),"Entry _a32 failed!"); + TASSERT((A.v[10])==(0),"Entry _a33 failed!"); + TASSERT((A.v[14])==(-10),"Entry _a34 failed!"); + TASSERT((A.v[3])==(12),"Entry _a41 failed!"); + TASSERT((A.v[7])==(38),"Entry _a42 failed!"); + TASSERT((A.v[11])==(20),"Entry _a43 failed!"); + TASSERT((A.v[15])==(-4),"Entry _a44 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat44iMultiplyScalarLocal(){ + SST_Mat44i X; /* 4 x 4 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = -13; + X.v[1] = -8; + X.v[2] = 9; + X.v[3] = 3; + X.v[4] = -18; + X.v[5] = -2; + X.v[6] = -2; + X.v[7] = 3; + X.v[8] = 3; + X.v[9] = 12; + X.v[10] = 5; + X.v[11] = 5; + X.v[12] = 19; + X.v[13] = -14; + X.v[14] = 12; + X.v[15] = 13; +/* +[[-13 -18 3 19] + [ -8 -2 12 -14] + [ 9 -2 5 12] + [ 3 3 5 13]] +[[-26 -36 6 38] + [-16 -4 24 -28] + [ 18 -4 10 24] + [ 6 6 10 26]] +*/ + SST_Math_Mat44iMultiplyScalarLocal(&X,2); + TASSERT((X.v[0])==(-26),"Entry _a11 failed!"); + TASSERT((X.v[4])==(-36),"Entry _a12 failed!"); + TASSERT((X.v[8])==(6),"Entry _a13 failed!"); + TASSERT((X.v[12])==(38),"Entry _a14 failed!"); + TASSERT((X.v[1])==(-16),"Entry _a21 failed!"); + TASSERT((X.v[5])==(-4),"Entry _a22 failed!"); + TASSERT((X.v[9])==(24),"Entry _a23 failed!"); + TASSERT((X.v[13])==(-28),"Entry _a24 failed!"); + TASSERT((X.v[2])==(18),"Entry _a31 failed!"); + TASSERT((X.v[6])==(-4),"Entry _a32 failed!"); + TASSERT((X.v[10])==(10),"Entry _a33 failed!"); + TASSERT((X.v[14])==(24),"Entry _a34 failed!"); + TASSERT((X.v[3])==(6),"Entry _a41 failed!"); + TASSERT((X.v[7])==(6),"Entry _a42 failed!"); + TASSERT((X.v[11])==(10),"Entry _a43 failed!"); + TASSERT((X.v[15])==(26),"Entry _a44 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat44iMultiplyMatrix(){ + SST_Mat44i X; /* 4 x 4 matrix */ + SST_Mat44i Y; /* 4 x 4 matrix */ + SST_Mat44i A; /* 4 x 4 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = -9; + X.v[1] = -18; + X.v[2] = 16; + X.v[3] = 10; + X.v[4] = -18; + X.v[5] = 9; + X.v[6] = -17; + X.v[7] = 19; + X.v[8] = 10; + X.v[9] = 6; + X.v[10] = -4; + X.v[11] = -12; + X.v[12] = 14; + X.v[13] = -2; + X.v[14] = -9; + X.v[15] = -15; + Y.v[0] = -15; + Y.v[1] = -3; + Y.v[2] = 2; + Y.v[3] = 7; + Y.v[4] = -18; + Y.v[5] = -20; + Y.v[6] = -12; + Y.v[7] = -13; + Y.v[8] = 5; + Y.v[9] = -7; + Y.v[10] = -4; + Y.v[11] = 3; + Y.v[12] = 7; + Y.v[13] = -4; + Y.v[14] = 8; + Y.v[15] = 9; +/* +X +[[ -9 -18 10 14] + [-18 9 6 -2] + [ 16 -17 -4 -9] + [ 10 19 -12 -15]] +Y +[[-15 -18 5 7] + [ -3 -20 -7 -4] + [ 2 -12 -4 8] + [ 7 -13 3 9]] +[[ 307 220 83 215] + [ 241 98 -183 -132] + [-260 217 188 67] + [-336 -221 -80 -237]] +*/ + SST_Math_Mat44iMultiplyMatrix(&X,&Y,&A); + TASSERT((A.v[0])==(307),"Entry _a11 failed!"); + TASSERT((A.v[4])==(220),"Entry _a12 failed!"); + TASSERT((A.v[8])==(83),"Entry _a13 failed!"); + TASSERT((A.v[12])==(215),"Entry _a14 failed!"); + TASSERT((A.v[1])==(241),"Entry _a21 failed!"); + TASSERT((A.v[5])==(98),"Entry _a22 failed!"); + TASSERT((A.v[9])==(-183),"Entry _a23 failed!"); + TASSERT((A.v[13])==(-132),"Entry _a24 failed!"); + TASSERT((A.v[2])==(-260),"Entry _a31 failed!"); + TASSERT((A.v[6])==(217),"Entry _a32 failed!"); + TASSERT((A.v[10])==(188),"Entry _a33 failed!"); + TASSERT((A.v[14])==(67),"Entry _a34 failed!"); + TASSERT((A.v[3])==(-336),"Entry _a41 failed!"); + TASSERT((A.v[7])==(-221),"Entry _a42 failed!"); + TASSERT((A.v[11])==(-80),"Entry _a43 failed!"); + TASSERT((A.v[15])==(-237),"Entry _a44 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat44iMultiplyMatrixLocal(){ + SST_Mat44i X; /* 4 x 4 matrix */ + SST_Mat44i Y; /* 4 x 4 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = -3; + X.v[1] = -19; + X.v[2] = 4; + X.v[3] = -1; + X.v[4] = 11; + X.v[5] = 15; + X.v[6] = 11; + X.v[7] = 4; + X.v[8] = -2; + X.v[9] = 2; + X.v[10] = -4; + X.v[11] = -13; + X.v[12] = -17; + X.v[13] = -10; + X.v[14] = -15; + X.v[15] = 1; + Y.v[0] = 16; + Y.v[1] = -9; + Y.v[2] = 2; + Y.v[3] = -2; + Y.v[4] = -19; + Y.v[5] = -20; + Y.v[6] = 15; + Y.v[7] = 6; + Y.v[8] = 7; + Y.v[9] = -16; + Y.v[10] = 11; + Y.v[11] = 7; + Y.v[12] = -11; + Y.v[13] = -3; + Y.v[14] = -18; + Y.v[15] = 12; +/* +X +[[ -3 11 -2 -17] + [-19 15 2 -10] + [ 4 11 -4 -15] + [ -1 4 -13 1]] +Y +[[ 16 -19 7 -11] + [ -9 -20 -16 -3] + [ 2 15 11 -18] + [ -2 6 7 12]] +X +[[-117 -295 -338 -168] + [-415 31 -421 8] + [ -13 -446 -297 -185] + [ -80 -250 -207 245]] +*/ + SST_Math_Mat44iMultiplyMatrixLocal(&X,&Y); + TASSERT((X.v[0])==(-117),"Entry _a11 failed!"); + TASSERT((X.v[4])==(-295),"Entry _a12 failed!"); + TASSERT((X.v[8])==(-338),"Entry _a13 failed!"); + TASSERT((X.v[12])==(-168),"Entry _a14 failed!"); + TASSERT((X.v[1])==(-415),"Entry _a21 failed!"); + TASSERT((X.v[5])==(31),"Entry _a22 failed!"); + TASSERT((X.v[9])==(-421),"Entry _a23 failed!"); + TASSERT((X.v[13])==(8),"Entry _a24 failed!"); + TASSERT((X.v[2])==(-13),"Entry _a31 failed!"); + TASSERT((X.v[6])==(-446),"Entry _a32 failed!"); + TASSERT((X.v[10])==(-297),"Entry _a33 failed!"); + TASSERT((X.v[14])==(-185),"Entry _a34 failed!"); + TASSERT((X.v[3])==(-80),"Entry _a41 failed!"); + TASSERT((X.v[7])==(-250),"Entry _a42 failed!"); + TASSERT((X.v[11])==(-207),"Entry _a43 failed!"); + TASSERT((X.v[15])==(245),"Entry _a44 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat44iMultiplyVector(){ + SST_Mat44i X; /* 4 x 4 matrix */ + SST_Vec4i v; /* 4 vector */ + SST_Vec4i w; /* 4 vector */ +/* Resetting test vectors / mats */ + v.v[0] = -15; + v.v[1] = -17; + v.v[2] = 14; + v.v[3] = -16; + X.v[0] = -13; + X.v[1] = 8; + X.v[2] = 17; + X.v[3] = 13; + X.v[4] = 6; + X.v[5] = -11; + X.v[6] = -7; + X.v[7] = 14; + X.v[8] = 11; + X.v[9] = -2; + X.v[10] = -19; + X.v[11] = 18; + X.v[12] = -7; + X.v[13] = -2; + X.v[14] = 5; + X.v[15] = -11; +/* +X +[[-13 6 11 -7] + [ 8 -11 -2 -2] + [ 17 -7 -19 5] + [ 13 14 18 -11]] +v +[-15 -17 14 -16] +w +[ 359 71 -482 -5] +*/ + SST_Math_Mat44iMultiplyVector(&X,&v,&w); + TASSERT((w.v[0])==(359),"Entry .v[0] failed!"); + TASSERT((w.v[1])==(71),"Entry .v[1] failed!"); + TASSERT((w.v[2])==(-482),"Entry .v[2] failed!"); + TASSERT((w.v[3])==(-5),"Entry .v[3] failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat44iMultiplyVectorLocal(){ + SST_Mat44i X; /* 4 x 4 matrix */ + SST_Vec4i v; /* 4 vector */ +/* Resetting test vectors / mats */ + v.v[0] = 7; + v.v[1] = -1; + v.v[2] = 11; + v.v[3] = -12; + X.v[0] = 0; + X.v[1] = 9; + X.v[2] = -19; + X.v[3] = -17; + X.v[4] = 11; + X.v[5] = -18; + X.v[6] = -11; + X.v[7] = -13; + X.v[8] = -1; + X.v[9] = 13; + X.v[10] = -11; + X.v[11] = 2; + X.v[12] = 11; + X.v[13] = -14; + X.v[14] = -15; + X.v[15] = 4; +/* +X +[[ 0 11 -1 11] + [ 9 -18 13 -14] + [-19 -11 -11 -15] + [-17 -13 2 4]] +v +[ 7 -1 11 -12] +v +[-154 392 -63 -132] +*/ + SST_Math_Mat44iMultiplyVectorLocal(&X,&v); + TASSERT((v.v[0])==(-154),"Entry .v[0] failed!"); + TASSERT((v.v[1])==(392),"Entry .v[1] failed!"); + TASSERT((v.v[2])==(-63),"Entry .v[2] failed!"); + TASSERT((v.v[3])==(-132),"Entry .v[3] failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat44iTranspose(){ + SST_Mat44i X; /* 4 x 4 matrix */ + SST_Mat44i A; /* 4 x 4 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = 5; + X.v[1] = 3; + X.v[2] = 8; + X.v[3] = 0; + X.v[4] = -14; + X.v[5] = -19; + X.v[6] = -5; + X.v[7] = 6; + X.v[8] = 4; + X.v[9] = -12; + X.v[10] = -10; + X.v[11] = -1; + X.v[12] = -14; + X.v[13] = 15; + X.v[14] = -2; + X.v[15] = -15; + SST_Math_Mat44iTranspose(&X,&A); + TASSERT((A.v[0])==(5),"Entry _a11 failed!"); + TASSERT((A.v[4])==(3),"Entry _a12 failed!"); + TASSERT((A.v[8])==(8),"Entry _a13 failed!"); + TASSERT((A.v[12])==(0),"Entry _a14 failed!"); + TASSERT((A.v[1])==(-14),"Entry _a21 failed!"); + TASSERT((A.v[5])==(-19),"Entry _a22 failed!"); + TASSERT((A.v[9])==(-5),"Entry _a23 failed!"); + TASSERT((A.v[13])==(6),"Entry _a24 failed!"); + TASSERT((A.v[2])==(4),"Entry _a31 failed!"); + TASSERT((A.v[6])==(-12),"Entry _a32 failed!"); + TASSERT((A.v[10])==(-10),"Entry _a33 failed!"); + TASSERT((A.v[14])==(-1),"Entry _a34 failed!"); + TASSERT((A.v[3])==(-14),"Entry _a41 failed!"); + TASSERT((A.v[7])==(15),"Entry _a42 failed!"); + TASSERT((A.v[11])==(-2),"Entry _a43 failed!"); + TASSERT((A.v[15])==(-15),"Entry _a44 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat44iTransposeLocal(){ + SST_Mat44i X; /* 4 x 4 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = 1; + X.v[1] = -15; + X.v[2] = 18; + X.v[3] = 2; + X.v[4] = 8; + X.v[5] = -18; + X.v[6] = 17; + X.v[7] = -5; + X.v[8] = 1; + X.v[9] = 13; + X.v[10] = -1; + X.v[11] = 4; + X.v[12] = -1; + X.v[13] = -17; + X.v[14] = 19; + X.v[15] = -13; + SST_Math_Mat44iTransposeLocal(&X); + TASSERT((X.v[0])==(1),"Entry _a11 failed!"); + TASSERT((X.v[4])==(-15),"Entry _a12 failed!"); + TASSERT((X.v[8])==(18),"Entry _a13 failed!"); + TASSERT((X.v[12])==(2),"Entry _a14 failed!"); + TASSERT((X.v[1])==(8),"Entry _a21 failed!"); + TASSERT((X.v[5])==(-18),"Entry _a22 failed!"); + TASSERT((X.v[9])==(17),"Entry _a23 failed!"); + TASSERT((X.v[13])==(-5),"Entry _a24 failed!"); + TASSERT((X.v[2])==(1),"Entry _a31 failed!"); + TASSERT((X.v[6])==(13),"Entry _a32 failed!"); + TASSERT((X.v[10])==(-1),"Entry _a33 failed!"); + TASSERT((X.v[14])==(4),"Entry _a34 failed!"); + TASSERT((X.v[3])==(-1),"Entry _a41 failed!"); + TASSERT((X.v[7])==(-17),"Entry _a42 failed!"); + TASSERT((X.v[11])==(19),"Entry _a43 failed!"); + TASSERT((X.v[15])==(-13),"Entry _a44 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat44iCheckOrthonormal(){ + SST_Mat44i X; /* 4 x 4 matrix */ + SST_Mat44i Y; /* 4 x 4 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = -17; + X.v[1] = 12; + X.v[2] = -20; + X.v[3] = -11; + X.v[4] = 4; + X.v[5] = 12; + X.v[6] = 0; + X.v[7] = 17; + X.v[8] = 6; + X.v[9] = -14; + X.v[10] = -7; + X.v[11] = 1; + X.v[12] = -19; + X.v[13] = 18; + X.v[14] = 13; + X.v[15] = -11; + Y.v[0] = 7; + Y.v[1] = 0; + Y.v[2] = 7; + Y.v[3] = -14; + Y.v[4] = 0; + Y.v[5] = 7; + Y.v[6] = -13; + Y.v[7] = -14; + Y.v[8] = -16; + Y.v[9] = -13; + Y.v[10] = 16; + Y.v[11] = 9; + Y.v[12] = 2; + Y.v[13] = 5; + Y.v[14] = 6; + Y.v[15] = -7; +X.v[0] = (int)1; +X.v[1] = (int)0; +X.v[2] = (int)0; +X.v[3] = (int)0; +X.v[4] = (int)0; +X.v[5] = (int)1; +X.v[6] = (int)0; +X.v[7] = (int)0; +X.v[8] = (int)0; +X.v[9] = (int)0; +X.v[10] = (int)1; +X.v[11] = (int)0; +X.v[12] = (int)0; +X.v[13] = (int)0; +X.v[14] = (int)0; +X.v[15] = (int)1; +Y.v[0] = (int)1; +Y.v[1] = (int)0; +Y.v[2] = (int)0; +Y.v[3] = (int)0; +Y.v[4] = (int)0; +Y.v[5] = (int)1; +Y.v[6] = (int)0; +Y.v[7] = (int)0; +Y.v[8] = (int)0; +Y.v[9] = (int)0; +Y.v[10] = (int)1; +Y.v[11] = (int)0; +Y.v[12] = (int)0; +Y.v[13] = (int)0; +Y.v[14] = (int)0; +Y.v[15] = (int)1; +Y.v[3] = (int)1; /* Will cause Y to be fail */ +/* Check Positive Test */ + TASSERT(SST_Math_Mat44iCheckOrthonormal(&X),"CheckOrthonormal failed when it should have passed"); +/* Check Negative Test */ + TASSERT(!SST_Math_Mat44iCheckOrthonormal(&Y),"CheckOrthonormal succeeded when it should have failed"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat44iDeterminant(){ + SST_Mat44i X; /* 4 x 4 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = 13; + X.v[1] = -8; + X.v[2] = -17; + X.v[3] = -8; + X.v[4] = 15; + X.v[5] = -12; + X.v[6] = 4; + X.v[7] = -14; + X.v[8] = 16; + X.v[9] = -4; + X.v[10] = 4; + X.v[11] = 18; + X.v[12] = 4; + X.v[13] = 5; + X.v[14] = 17; + X.v[15] = -15; +/* det(X) = +123298.0 + */ + int result = SST_Math_Mat44iDeterminant(&X); + TASSERT(abs( (result)/(123297) - 1 ) <= 100*0,"Determinant failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + diff --git a/ZTestSuite/Test-SST_Mat44u.cpp b/ZTestSuite/Test-SST_Mat44u.cpp new file mode 100644 index 0000000..4ce4a32 --- /dev/null +++ b/ZTestSuite/Test-SST_Mat44u.cpp @@ -0,0 +1,915 @@ +/* + AUTOMATICALLY GENERATED FILE - DO NOT EDIT! + Please change MatrixNxN.py and re-run it +*/ +/* Generated with ./MatrixNxN.py n = 4, TYPE = unsigned int */ + +#include "ZUnitTest.hpp" +#include <float.h> +#include <math.h> +#include <stdlib.h> +#include <stdio.h> +#include <SST/SST_Mat44.h> +#include <SST/SST_Vec4.h> + + + + +static const char* testSST_Math_Mat44uAdd(); +static const char* testSST_Math_Mat44uAddLocal(); +static const char* testSST_Math_Mat44uSubtract(); +static const char* testSST_Math_Mat44uSubtractLocal(); +static const char* testSST_Math_Mat44uMultiplyElementwise(); +static const char* testSST_Math_Mat44uMultiplyElementwiseLocal(); +static const char* testSST_Math_Mat44uMultiplyScalar(); +static const char* testSST_Math_Mat44uMultiplyScalarLocal(); +static const char* testSST_Math_Mat44uMultiplyMatrix(); +static const char* testSST_Math_Mat44uMultiplyMatrixLocal(); +static const char* testSST_Math_Mat44uMultiplyVector(); +static const char* testSST_Math_Mat44uMultiplyVectorLocal(); +static const char* testSST_Math_Mat44uTranspose(); +static const char* testSST_Math_Mat44uTransposeLocal(); +// List of unit tests +ZUnitTest SST_Math_Mat44uUnitTests[] = +{ +{ "testSST_Math_Mat44uAdd " , testSST_Math_Mat44uAdd }, +{ "testSST_Math_Mat44uAddLocal " , testSST_Math_Mat44uAddLocal }, +{ "testSST_Math_Mat44uSubtract " , testSST_Math_Mat44uSubtract }, +{ "testSST_Math_Mat44uSubtractLocal " , testSST_Math_Mat44uSubtractLocal }, +{ "testSST_Math_Mat44uMultiplyElementwise " , testSST_Math_Mat44uMultiplyElementwise }, +{ "testSST_Math_Mat44uMultiplyElementwiseLocal " , testSST_Math_Mat44uMultiplyElementwiseLocal }, +{ "testSST_Math_Mat44uMultiplyScalar " , testSST_Math_Mat44uMultiplyScalar }, +{ "testSST_Math_Mat44uMultiplyScalarLocal " , testSST_Math_Mat44uMultiplyScalarLocal }, +{ "testSST_Math_Mat44uMultiplyMatrix " , testSST_Math_Mat44uMultiplyMatrix }, +{ "testSST_Math_Mat44uMultiplyMatrixLocal " , testSST_Math_Mat44uMultiplyMatrixLocal }, +{ "testSST_Math_Mat44uMultiplyVector " , testSST_Math_Mat44uMultiplyVector }, +{ "testSST_Math_Mat44uMultiplyVectorLocal " , testSST_Math_Mat44uMultiplyVectorLocal }, +{ "testSST_Math_Mat44uTranspose " , testSST_Math_Mat44uTranspose }, +{ "testSST_Math_Mat44uTransposeLocal " , testSST_Math_Mat44uTransposeLocal } +}; +DECLARE_ZTESTBLOCK(SST_Math_Mat44u) + +/******************************************************************************/ + +static const char* testSST_Math_Mat44uAdd(){ + SST_Mat44u X; /* 4 x 4 matrix */ + SST_Mat44u Y; /* 4 x 4 matrix */ + SST_Mat44u A; /* 4 x 4 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = 32; + X.v[1] = 39; + X.v[2] = 38; + X.v[3] = 32; + X.v[4] = 2; + X.v[5] = 38; + X.v[6] = 5; + X.v[7] = 1; + X.v[8] = 31; + X.v[9] = 30; + X.v[10] = 20; + X.v[11] = 26; + X.v[12] = 0; + X.v[13] = 2; + X.v[14] = 9; + X.v[15] = 13; + Y.v[0] = 25; + Y.v[1] = 38; + Y.v[2] = 28; + Y.v[3] = 18; + Y.v[4] = 7; + Y.v[5] = 3; + Y.v[6] = 13; + Y.v[7] = 2; + Y.v[8] = 27; + Y.v[9] = 30; + Y.v[10] = 18; + Y.v[11] = 14; + Y.v[12] = 25; + Y.v[13] = 6; + Y.v[14] = 16; + Y.v[15] = 22; +/* +[[32 2 31 0] + [39 38 30 2] + [38 5 20 9] + [32 1 26 13]] +[[25 7 27 25] + [38 3 30 6] + [28 13 18 16] + [18 2 14 22]] +[[57 9 58 25] + [77 41 60 8] + [66 18 38 25] + [50 3 40 35]] +*/ + SST_Math_Mat44uAdd(&X,&Y,&A); + TASSERT((A.v[0])==(57),"Entry _a11 failed!"); + TASSERT((A.v[4])==(9),"Entry _a12 failed!"); + TASSERT((A.v[8])==(58),"Entry _a13 failed!"); + TASSERT((A.v[12])==(25),"Entry _a14 failed!"); + TASSERT((A.v[1])==(77),"Entry _a21 failed!"); + TASSERT((A.v[5])==(41),"Entry _a22 failed!"); + TASSERT((A.v[9])==(60),"Entry _a23 failed!"); + TASSERT((A.v[13])==(8),"Entry _a24 failed!"); + TASSERT((A.v[2])==(66),"Entry _a31 failed!"); + TASSERT((A.v[6])==(18),"Entry _a32 failed!"); + TASSERT((A.v[10])==(38),"Entry _a33 failed!"); + TASSERT((A.v[14])==(25),"Entry _a34 failed!"); + TASSERT((A.v[3])==(50),"Entry _a41 failed!"); + TASSERT((A.v[7])==(3),"Entry _a42 failed!"); + TASSERT((A.v[11])==(40),"Entry _a43 failed!"); + TASSERT((A.v[15])==(35),"Entry _a44 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat44uAddLocal(){ + SST_Mat44u X; /* 4 x 4 matrix */ + SST_Mat44u Y; /* 4 x 4 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = 10; + X.v[1] = 26; + X.v[2] = 21; + X.v[3] = 18; + X.v[4] = 20; + X.v[5] = 0; + X.v[6] = 18; + X.v[7] = 37; + X.v[8] = 35; + X.v[9] = 37; + X.v[10] = 21; + X.v[11] = 28; + X.v[12] = 12; + X.v[13] = 17; + X.v[14] = 22; + X.v[15] = 20; + Y.v[0] = 39; + Y.v[1] = 20; + Y.v[2] = 11; + Y.v[3] = 8; + Y.v[4] = 8; + Y.v[5] = 32; + Y.v[6] = 19; + Y.v[7] = 18; + Y.v[8] = 3; + Y.v[9] = 34; + Y.v[10] = 7; + Y.v[11] = 16; + Y.v[12] = 18; + Y.v[13] = 23; + Y.v[14] = 1; + Y.v[15] = 1; +/* +[[10 20 35 12] + [26 0 37 17] + [21 18 21 22] + [18 37 28 20]] +[[39 8 3 18] + [20 32 34 23] + [11 19 7 1] + [ 8 18 16 1]] +[[49 28 38 30] + [46 32 71 40] + [32 37 28 23] + [26 55 44 21]] +*/ + SST_Math_Mat44uAddLocal(&X,&Y); /* for accuracy */ + TASSERT((X.v[0])==(49),"Entry _a11 failed!"); + TASSERT((X.v[4])==(28),"Entry _a12 failed!"); + TASSERT((X.v[8])==(38),"Entry _a13 failed!"); + TASSERT((X.v[12])==(30),"Entry _a14 failed!"); + TASSERT((X.v[1])==(46),"Entry _a21 failed!"); + TASSERT((X.v[5])==(32),"Entry _a22 failed!"); + TASSERT((X.v[9])==(71),"Entry _a23 failed!"); + TASSERT((X.v[13])==(40),"Entry _a24 failed!"); + TASSERT((X.v[2])==(32),"Entry _a31 failed!"); + TASSERT((X.v[6])==(37),"Entry _a32 failed!"); + TASSERT((X.v[10])==(28),"Entry _a33 failed!"); + TASSERT((X.v[14])==(23),"Entry _a34 failed!"); + TASSERT((X.v[3])==(26),"Entry _a41 failed!"); + TASSERT((X.v[7])==(55),"Entry _a42 failed!"); + TASSERT((X.v[11])==(44),"Entry _a43 failed!"); + TASSERT((X.v[15])==(21),"Entry _a44 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat44uSubtract(){ + SST_Mat44u X; /* 4 x 4 matrix */ + SST_Mat44u Y; /* 4 x 4 matrix */ + SST_Mat44u A; /* 4 x 4 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = 34; + X.v[1] = 21; + X.v[2] = 8; + X.v[3] = 38; + X.v[4] = 13; + X.v[5] = 11; + X.v[6] = 12; + X.v[7] = 34; + X.v[8] = 11; + X.v[9] = 6; + X.v[10] = 4; + X.v[11] = 25; + X.v[12] = 25; + X.v[13] = 1; + X.v[14] = 26; + X.v[15] = 35; + Y.v[0] = 21; + Y.v[1] = 26; + Y.v[2] = 4; + Y.v[3] = 5; + Y.v[4] = 0; + Y.v[5] = 13; + Y.v[6] = 32; + Y.v[7] = 37; + Y.v[8] = 16; + Y.v[9] = 39; + Y.v[10] = 10; + Y.v[11] = 12; + Y.v[12] = 28; + Y.v[13] = 4; + Y.v[14] = 3; + Y.v[15] = 23; +/* +[[34 13 11 25] + [21 11 6 1] + [ 8 12 4 26] + [38 34 25 35]] +[[21 0 16 28] + [26 13 39 4] + [ 4 32 10 3] + [ 5 37 12 23]] +[[ 13 13 4294967291 4294967293] + [4294967291 4294967294 4294967263 4294967293] + [ 4 4294967276 4294967290 23] + [ 33 4294967293 13 12]] +*/ + SST_Math_Mat44uSubtract(&X,&Y,&A); + TASSERT((A.v[0])==(13),"Entry _a11 failed!"); + TASSERT((A.v[4])==(13),"Entry _a12 failed!"); + TASSERT((A.v[8])==(4294967291),"Entry _a13 failed!"); + TASSERT((A.v[12])==(4294967293),"Entry _a14 failed!"); + TASSERT((A.v[1])==(4294967291),"Entry _a21 failed!"); + TASSERT((A.v[5])==(4294967294),"Entry _a22 failed!"); + TASSERT((A.v[9])==(4294967263),"Entry _a23 failed!"); + TASSERT((A.v[13])==(4294967293),"Entry _a24 failed!"); + TASSERT((A.v[2])==(4),"Entry _a31 failed!"); + TASSERT((A.v[6])==(4294967276),"Entry _a32 failed!"); + TASSERT((A.v[10])==(4294967290),"Entry _a33 failed!"); + TASSERT((A.v[14])==(23),"Entry _a34 failed!"); + TASSERT((A.v[3])==(33),"Entry _a41 failed!"); + TASSERT((A.v[7])==(4294967293),"Entry _a42 failed!"); + TASSERT((A.v[11])==(13),"Entry _a43 failed!"); + TASSERT((A.v[15])==(12),"Entry _a44 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat44uSubtractLocal(){ + SST_Mat44u X; /* 4 x 4 matrix */ + SST_Mat44u Y; /* 4 x 4 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = 4; + X.v[1] = 7; + X.v[2] = 8; + X.v[3] = 17; + X.v[4] = 10; + X.v[5] = 19; + X.v[6] = 14; + X.v[7] = 16; + X.v[8] = 33; + X.v[9] = 17; + X.v[10] = 1; + X.v[11] = 13; + X.v[12] = 36; + X.v[13] = 17; + X.v[14] = 23; + X.v[15] = 0; + Y.v[0] = 9; + Y.v[1] = 21; + Y.v[2] = 35; + Y.v[3] = 24; + Y.v[4] = 2; + Y.v[5] = 9; + Y.v[6] = 31; + Y.v[7] = 23; + Y.v[8] = 37; + Y.v[9] = 31; + Y.v[10] = 33; + Y.v[11] = 24; + Y.v[12] = 16; + Y.v[13] = 21; + Y.v[14] = 25; + Y.v[15] = 35; +/* +[[ 4 10 33 36] + [ 7 19 17 17] + [ 8 14 1 23] + [17 16 13 0]] +[[ 9 2 37 16] + [21 9 31 21] + [35 31 33 25] + [24 23 24 35]] +[[4294967291 8 4294967292 20] + [4294967282 10 4294967282 4294967292] + [4294967269 4294967279 4294967264 4294967294] + [4294967289 4294967289 4294967285 4294967261]] +*/ + SST_Math_Mat44uSubtractLocal(&X,&Y); /* for accuracy */ + TASSERT((X.v[0])==(4294967291),"Entry _a11 failed!"); + TASSERT((X.v[4])==(8),"Entry _a12 failed!"); + TASSERT((X.v[8])==(4294967292),"Entry _a13 failed!"); + TASSERT((X.v[12])==(20),"Entry _a14 failed!"); + TASSERT((X.v[1])==(4294967282),"Entry _a21 failed!"); + TASSERT((X.v[5])==(10),"Entry _a22 failed!"); + TASSERT((X.v[9])==(4294967282),"Entry _a23 failed!"); + TASSERT((X.v[13])==(4294967292),"Entry _a24 failed!"); + TASSERT((X.v[2])==(4294967269),"Entry _a31 failed!"); + TASSERT((X.v[6])==(4294967279),"Entry _a32 failed!"); + TASSERT((X.v[10])==(4294967264),"Entry _a33 failed!"); + TASSERT((X.v[14])==(4294967294),"Entry _a34 failed!"); + TASSERT((X.v[3])==(4294967289),"Entry _a41 failed!"); + TASSERT((X.v[7])==(4294967289),"Entry _a42 failed!"); + TASSERT((X.v[11])==(4294967285),"Entry _a43 failed!"); + TASSERT((X.v[15])==(4294967261),"Entry _a44 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat44uMultiplyElementwise(){ + SST_Mat44u X; /* 4 x 4 matrix */ + SST_Mat44u Y; /* 4 x 4 matrix */ + SST_Mat44u A; /* 4 x 4 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = 5; + X.v[1] = 38; + X.v[2] = 32; + X.v[3] = 15; + X.v[4] = 33; + X.v[5] = 21; + X.v[6] = 36; + X.v[7] = 8; + X.v[8] = 6; + X.v[9] = 13; + X.v[10] = 8; + X.v[11] = 4; + X.v[12] = 6; + X.v[13] = 13; + X.v[14] = 17; + X.v[15] = 6; + Y.v[0] = 35; + Y.v[1] = 27; + Y.v[2] = 20; + Y.v[3] = 1; + Y.v[4] = 20; + Y.v[5] = 23; + Y.v[6] = 39; + Y.v[7] = 38; + Y.v[8] = 31; + Y.v[9] = 27; + Y.v[10] = 33; + Y.v[11] = 32; + Y.v[12] = 33; + Y.v[13] = 9; + Y.v[14] = 37; + Y.v[15] = 31; +/* +[[ 5 33 6 6] + [38 21 13 13] + [32 36 8 17] + [15 8 4 6]] +[[35 20 31 33] + [27 23 27 9] + [20 39 33 37] + [ 1 38 32 31]] +[[ 175 660 186 198] + [1026 483 351 117] + [ 640 1404 264 629] + [ 15 304 128 186]] +*/ + SST_Math_Mat44uMultiplyElementwise(&X, &Y, &A); + TASSERT((A.v[0])==(175),"Entry _a11 failed!"); + TASSERT((A.v[4])==(660),"Entry _a12 failed!"); + TASSERT((A.v[8])==(186),"Entry _a13 failed!"); + TASSERT((A.v[12])==(198),"Entry _a14 failed!"); + TASSERT((A.v[1])==(1026),"Entry _a21 failed!"); + TASSERT((A.v[5])==(483),"Entry _a22 failed!"); + TASSERT((A.v[9])==(351),"Entry _a23 failed!"); + TASSERT((A.v[13])==(117),"Entry _a24 failed!"); + TASSERT((A.v[2])==(640),"Entry _a31 failed!"); + TASSERT((A.v[6])==(1404),"Entry _a32 failed!"); + TASSERT((A.v[10])==(264),"Entry _a33 failed!"); + TASSERT((A.v[14])==(629),"Entry _a34 failed!"); + TASSERT((A.v[3])==(15),"Entry _a41 failed!"); + TASSERT((A.v[7])==(304),"Entry _a42 failed!"); + TASSERT((A.v[11])==(128),"Entry _a43 failed!"); + TASSERT((A.v[15])==(186),"Entry _a44 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat44uMultiplyElementwiseLocal(){ + SST_Mat44u X; /* 4 x 4 matrix */ + SST_Mat44u Y; /* 4 x 4 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = 22; + X.v[1] = 11; + X.v[2] = 20; + X.v[3] = 39; + X.v[4] = 30; + X.v[5] = 37; + X.v[6] = 8; + X.v[7] = 20; + X.v[8] = 34; + X.v[9] = 12; + X.v[10] = 21; + X.v[11] = 6; + X.v[12] = 36; + X.v[13] = 26; + X.v[14] = 0; + X.v[15] = 33; + Y.v[0] = 38; + Y.v[1] = 15; + Y.v[2] = 9; + Y.v[3] = 3; + Y.v[4] = 2; + Y.v[5] = 13; + Y.v[6] = 26; + Y.v[7] = 18; + Y.v[8] = 21; + Y.v[9] = 34; + Y.v[10] = 39; + Y.v[11] = 14; + Y.v[12] = 39; + Y.v[13] = 19; + Y.v[14] = 22; + Y.v[15] = 35; +/* +[[22 30 34 36] + [11 37 12 26] + [20 8 21 0] + [39 20 6 33]] +[[38 2 21 39] + [15 13 34 19] + [ 9 26 39 22] + [ 3 18 14 35]] +[[ 836 60 714 1404] + [ 165 481 408 494] + [ 180 208 819 0] + [ 117 360 84 1155]] +*/ + SST_Math_Mat44uMultiplyElementwiseLocal(&X,&Y); + TASSERT((X.v[0])==(836),"Entry _a11 failed!"); + TASSERT((X.v[4])==(60),"Entry _a12 failed!"); + TASSERT((X.v[8])==(714),"Entry _a13 failed!"); + TASSERT((X.v[12])==(1404),"Entry _a14 failed!"); + TASSERT((X.v[1])==(165),"Entry _a21 failed!"); + TASSERT((X.v[5])==(481),"Entry _a22 failed!"); + TASSERT((X.v[9])==(408),"Entry _a23 failed!"); + TASSERT((X.v[13])==(494),"Entry _a24 failed!"); + TASSERT((X.v[2])==(180),"Entry _a31 failed!"); + TASSERT((X.v[6])==(208),"Entry _a32 failed!"); + TASSERT((X.v[10])==(819),"Entry _a33 failed!"); + TASSERT((X.v[14])==(0),"Entry _a34 failed!"); + TASSERT((X.v[3])==(117),"Entry _a41 failed!"); + TASSERT((X.v[7])==(360),"Entry _a42 failed!"); + TASSERT((X.v[11])==(84),"Entry _a43 failed!"); + TASSERT((X.v[15])==(1155),"Entry _a44 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat44uMultiplyScalar(){ + SST_Mat44u X; /* 4 x 4 matrix */ + SST_Mat44u A; /* 4 x 4 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = 26; + X.v[1] = 25; + X.v[2] = 4; + X.v[3] = 18; + X.v[4] = 33; + X.v[5] = 28; + X.v[6] = 15; + X.v[7] = 21; + X.v[8] = 30; + X.v[9] = 19; + X.v[10] = 33; + X.v[11] = 25; + X.v[12] = 23; + X.v[13] = 19; + X.v[14] = 37; + X.v[15] = 38; +/* +[[26 33 30 23] + [25 28 19 19] + [ 4 15 33 37] + [18 21 25 38]] +[[52 66 60 46] + [50 56 38 38] + [ 8 30 66 74] + [36 42 50 76]] +*/ + SST_Math_Mat44uMultiplyScalar(&X,2,&A); + TASSERT((A.v[0])==(52),"Entry _a11 failed!"); + TASSERT((A.v[4])==(66),"Entry _a12 failed!"); + TASSERT((A.v[8])==(60),"Entry _a13 failed!"); + TASSERT((A.v[12])==(46),"Entry _a14 failed!"); + TASSERT((A.v[1])==(50),"Entry _a21 failed!"); + TASSERT((A.v[5])==(56),"Entry _a22 failed!"); + TASSERT((A.v[9])==(38),"Entry _a23 failed!"); + TASSERT((A.v[13])==(38),"Entry _a24 failed!"); + TASSERT((A.v[2])==(8),"Entry _a31 failed!"); + TASSERT((A.v[6])==(30),"Entry _a32 failed!"); + TASSERT((A.v[10])==(66),"Entry _a33 failed!"); + TASSERT((A.v[14])==(74),"Entry _a34 failed!"); + TASSERT((A.v[3])==(36),"Entry _a41 failed!"); + TASSERT((A.v[7])==(42),"Entry _a42 failed!"); + TASSERT((A.v[11])==(50),"Entry _a43 failed!"); + TASSERT((A.v[15])==(76),"Entry _a44 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat44uMultiplyScalarLocal(){ + SST_Mat44u X; /* 4 x 4 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = 28; + X.v[1] = 2; + X.v[2] = 32; + X.v[3] = 36; + X.v[4] = 14; + X.v[5] = 31; + X.v[6] = 18; + X.v[7] = 34; + X.v[8] = 14; + X.v[9] = 7; + X.v[10] = 33; + X.v[11] = 0; + X.v[12] = 28; + X.v[13] = 22; + X.v[14] = 14; + X.v[15] = 21; +/* +[[28 14 14 28] + [ 2 31 7 22] + [32 18 33 14] + [36 34 0 21]] +[[56 28 28 56] + [ 4 62 14 44] + [64 36 66 28] + [72 68 0 42]] +*/ + SST_Math_Mat44uMultiplyScalarLocal(&X,2); + TASSERT((X.v[0])==(56),"Entry _a11 failed!"); + TASSERT((X.v[4])==(28),"Entry _a12 failed!"); + TASSERT((X.v[8])==(28),"Entry _a13 failed!"); + TASSERT((X.v[12])==(56),"Entry _a14 failed!"); + TASSERT((X.v[1])==(4),"Entry _a21 failed!"); + TASSERT((X.v[5])==(62),"Entry _a22 failed!"); + TASSERT((X.v[9])==(14),"Entry _a23 failed!"); + TASSERT((X.v[13])==(44),"Entry _a24 failed!"); + TASSERT((X.v[2])==(64),"Entry _a31 failed!"); + TASSERT((X.v[6])==(36),"Entry _a32 failed!"); + TASSERT((X.v[10])==(66),"Entry _a33 failed!"); + TASSERT((X.v[14])==(28),"Entry _a34 failed!"); + TASSERT((X.v[3])==(72),"Entry _a41 failed!"); + TASSERT((X.v[7])==(68),"Entry _a42 failed!"); + TASSERT((X.v[11])==(0),"Entry _a43 failed!"); + TASSERT((X.v[15])==(42),"Entry _a44 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat44uMultiplyMatrix(){ + SST_Mat44u X; /* 4 x 4 matrix */ + SST_Mat44u Y; /* 4 x 4 matrix */ + SST_Mat44u A; /* 4 x 4 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = 33; + X.v[1] = 22; + X.v[2] = 19; + X.v[3] = 4; + X.v[4] = 2; + X.v[5] = 31; + X.v[6] = 36; + X.v[7] = 10; + X.v[8] = 7; + X.v[9] = 19; + X.v[10] = 15; + X.v[11] = 7; + X.v[12] = 3; + X.v[13] = 38; + X.v[14] = 2; + X.v[15] = 23; + Y.v[0] = 28; + Y.v[1] = 32; + Y.v[2] = 26; + Y.v[3] = 8; + Y.v[4] = 18; + Y.v[5] = 38; + Y.v[6] = 19; + Y.v[7] = 11; + Y.v[8] = 20; + Y.v[9] = 33; + Y.v[10] = 12; + Y.v[11] = 9; + Y.v[12] = 21; + Y.v[13] = 15; + Y.v[14] = 31; + Y.v[15] = 10; +/* +X +[[33 2 7 3] + [22 31 19 38] + [19 36 15 2] + [ 4 10 7 23]] +Y +[[28 18 20 21] + [32 38 33 15] + [26 19 12 31] + [ 8 11 9 10]] +[[1194 836 837 970] + [2406 2353 2033 1896] + [2090 2017 1766 1424] + [ 798 838 701 681]] +*/ + SST_Math_Mat44uMultiplyMatrix(&X,&Y,&A); + TASSERT((A.v[0])==(1194),"Entry _a11 failed!"); + TASSERT((A.v[4])==(836),"Entry _a12 failed!"); + TASSERT((A.v[8])==(837),"Entry _a13 failed!"); + TASSERT((A.v[12])==(970),"Entry _a14 failed!"); + TASSERT((A.v[1])==(2406),"Entry _a21 failed!"); + TASSERT((A.v[5])==(2353),"Entry _a22 failed!"); + TASSERT((A.v[9])==(2033),"Entry _a23 failed!"); + TASSERT((A.v[13])==(1896),"Entry _a24 failed!"); + TASSERT((A.v[2])==(2090),"Entry _a31 failed!"); + TASSERT((A.v[6])==(2017),"Entry _a32 failed!"); + TASSERT((A.v[10])==(1766),"Entry _a33 failed!"); + TASSERT((A.v[14])==(1424),"Entry _a34 failed!"); + TASSERT((A.v[3])==(798),"Entry _a41 failed!"); + TASSERT((A.v[7])==(838),"Entry _a42 failed!"); + TASSERT((A.v[11])==(701),"Entry _a43 failed!"); + TASSERT((A.v[15])==(681),"Entry _a44 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat44uMultiplyMatrixLocal(){ + SST_Mat44u X; /* 4 x 4 matrix */ + SST_Mat44u Y; /* 4 x 4 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = 29; + X.v[1] = 16; + X.v[2] = 1; + X.v[3] = 34; + X.v[4] = 22; + X.v[5] = 28; + X.v[6] = 15; + X.v[7] = 35; + X.v[8] = 4; + X.v[9] = 4; + X.v[10] = 18; + X.v[11] = 11; + X.v[12] = 30; + X.v[13] = 1; + X.v[14] = 34; + X.v[15] = 17; + Y.v[0] = 35; + Y.v[1] = 5; + Y.v[2] = 10; + Y.v[3] = 16; + Y.v[4] = 31; + Y.v[5] = 11; + Y.v[6] = 15; + Y.v[7] = 26; + Y.v[8] = 24; + Y.v[9] = 9; + Y.v[10] = 12; + Y.v[11] = 25; + Y.v[12] = 26; + Y.v[13] = 19; + Y.v[14] = 14; + Y.v[15] = 38; +/* +X +[[29 22 4 30] + [16 28 4 1] + [ 1 15 18 34] + [34 35 11 17]] +Y +[[35 31 24 26] + [ 5 11 9 19] + [10 15 12 14] + [16 26 25 38]] +X +[[1645 1981 1692 2368] + [ 756 890 709 1042] + [ 834 1350 1225 1855] + [1747 2046 1688 2349]] +*/ + SST_Math_Mat44uMultiplyMatrixLocal(&X,&Y); + TASSERT((X.v[0])==(1645),"Entry _a11 failed!"); + TASSERT((X.v[4])==(1981),"Entry _a12 failed!"); + TASSERT((X.v[8])==(1692),"Entry _a13 failed!"); + TASSERT((X.v[12])==(2368),"Entry _a14 failed!"); + TASSERT((X.v[1])==(756),"Entry _a21 failed!"); + TASSERT((X.v[5])==(890),"Entry _a22 failed!"); + TASSERT((X.v[9])==(709),"Entry _a23 failed!"); + TASSERT((X.v[13])==(1042),"Entry _a24 failed!"); + TASSERT((X.v[2])==(834),"Entry _a31 failed!"); + TASSERT((X.v[6])==(1350),"Entry _a32 failed!"); + TASSERT((X.v[10])==(1225),"Entry _a33 failed!"); + TASSERT((X.v[14])==(1855),"Entry _a34 failed!"); + TASSERT((X.v[3])==(1747),"Entry _a41 failed!"); + TASSERT((X.v[7])==(2046),"Entry _a42 failed!"); + TASSERT((X.v[11])==(1688),"Entry _a43 failed!"); + TASSERT((X.v[15])==(2349),"Entry _a44 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat44uMultiplyVector(){ + SST_Mat44u X; /* 4 x 4 matrix */ + SST_Vec4u v; /* 4 vector */ + SST_Vec4u w; /* 4 vector */ +/* Resetting test vectors / mats */ + v.v[0] = 34; + v.v[1] = 14; + v.v[2] = 1; + v.v[3] = 10; + X.v[0] = 26; + X.v[1] = 24; + X.v[2] = 24; + X.v[3] = 37; + X.v[4] = 9; + X.v[5] = 35; + X.v[6] = 10; + X.v[7] = 37; + X.v[8] = 6; + X.v[9] = 9; + X.v[10] = 35; + X.v[11] = 34; + X.v[12] = 0; + X.v[13] = 22; + X.v[14] = 31; + X.v[15] = 17; +/* +X +[[26 9 6 0] + [24 35 9 22] + [24 10 35 31] + [37 37 34 17]] +v +[34 14 1 10] +w +[1016 1535 1301 1980] +*/ + SST_Math_Mat44uMultiplyVector(&X,&v,&w); + TASSERT((w.v[0])==(1016),"Entry .v[0] failed!"); + TASSERT((w.v[1])==(1535),"Entry .v[1] failed!"); + TASSERT((w.v[2])==(1301),"Entry .v[2] failed!"); + TASSERT((w.v[3])==(1980),"Entry .v[3] failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat44uMultiplyVectorLocal(){ + SST_Mat44u X; /* 4 x 4 matrix */ + SST_Vec4u v; /* 4 vector */ +/* Resetting test vectors / mats */ + v.v[0] = 33; + v.v[1] = 29; + v.v[2] = 13; + v.v[3] = 20; + X.v[0] = 37; + X.v[1] = 11; + X.v[2] = 37; + X.v[3] = 19; + X.v[4] = 20; + X.v[5] = 32; + X.v[6] = 19; + X.v[7] = 17; + X.v[8] = 4; + X.v[9] = 12; + X.v[10] = 24; + X.v[11] = 8; + X.v[12] = 33; + X.v[13] = 27; + X.v[14] = 21; + X.v[15] = 32; +/* +X +[[37 20 4 33] + [11 32 12 27] + [37 19 24 21] + [19 17 8 32]] +v +[33 29 13 20] +v +[2513 1987 2504 1864] +*/ + SST_Math_Mat44uMultiplyVectorLocal(&X,&v); + TASSERT((v.v[0])==(2513),"Entry .v[0] failed!"); + TASSERT((v.v[1])==(1987),"Entry .v[1] failed!"); + TASSERT((v.v[2])==(2504),"Entry .v[2] failed!"); + TASSERT((v.v[3])==(1864),"Entry .v[3] failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat44uTranspose(){ + SST_Mat44u X; /* 4 x 4 matrix */ + SST_Mat44u A; /* 4 x 4 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = 7; + X.v[1] = 19; + X.v[2] = 31; + X.v[3] = 31; + X.v[4] = 21; + X.v[5] = 10; + X.v[6] = 1; + X.v[7] = 0; + X.v[8] = 5; + X.v[9] = 3; + X.v[10] = 3; + X.v[11] = 24; + X.v[12] = 0; + X.v[13] = 0; + X.v[14] = 4; + X.v[15] = 0; + SST_Math_Mat44uTranspose(&X,&A); + TASSERT((A.v[0])==(7),"Entry _a11 failed!"); + TASSERT((A.v[4])==(19),"Entry _a12 failed!"); + TASSERT((A.v[8])==(31),"Entry _a13 failed!"); + TASSERT((A.v[12])==(31),"Entry _a14 failed!"); + TASSERT((A.v[1])==(21),"Entry _a21 failed!"); + TASSERT((A.v[5])==(10),"Entry _a22 failed!"); + TASSERT((A.v[9])==(1),"Entry _a23 failed!"); + TASSERT((A.v[13])==(0),"Entry _a24 failed!"); + TASSERT((A.v[2])==(5),"Entry _a31 failed!"); + TASSERT((A.v[6])==(3),"Entry _a32 failed!"); + TASSERT((A.v[10])==(3),"Entry _a33 failed!"); + TASSERT((A.v[14])==(24),"Entry _a34 failed!"); + TASSERT((A.v[3])==(0),"Entry _a41 failed!"); + TASSERT((A.v[7])==(0),"Entry _a42 failed!"); + TASSERT((A.v[11])==(4),"Entry _a43 failed!"); + TASSERT((A.v[15])==(0),"Entry _a44 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Mat44uTransposeLocal(){ + SST_Mat44u X; /* 4 x 4 matrix */ +/* Resetting test vectors / mats */ + X.v[0] = 30; + X.v[1] = 32; + X.v[2] = 4; + X.v[3] = 10; + X.v[4] = 31; + X.v[5] = 33; + X.v[6] = 36; + X.v[7] = 2; + X.v[8] = 27; + X.v[9] = 12; + X.v[10] = 7; + X.v[11] = 11; + X.v[12] = 38; + X.v[13] = 23; + X.v[14] = 24; + X.v[15] = 22; + SST_Math_Mat44uTransposeLocal(&X); + TASSERT((X.v[0])==(30),"Entry _a11 failed!"); + TASSERT((X.v[4])==(32),"Entry _a12 failed!"); + TASSERT((X.v[8])==(4),"Entry _a13 failed!"); + TASSERT((X.v[12])==(10),"Entry _a14 failed!"); + TASSERT((X.v[1])==(31),"Entry _a21 failed!"); + TASSERT((X.v[5])==(33),"Entry _a22 failed!"); + TASSERT((X.v[9])==(36),"Entry _a23 failed!"); + TASSERT((X.v[13])==(2),"Entry _a24 failed!"); + TASSERT((X.v[2])==(27),"Entry _a31 failed!"); + TASSERT((X.v[6])==(12),"Entry _a32 failed!"); + TASSERT((X.v[10])==(7),"Entry _a33 failed!"); + TASSERT((X.v[14])==(11),"Entry _a34 failed!"); + TASSERT((X.v[3])==(38),"Entry _a41 failed!"); + TASSERT((X.v[7])==(23),"Entry _a42 failed!"); + TASSERT((X.v[11])==(24),"Entry _a43 failed!"); + TASSERT((X.v[15])==(22),"Entry _a44 failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + diff --git a/ZTestSuite/Test-SST_Math.cpp b/ZTestSuite/Test-SST_Math.cpp new file mode 100644 index 0000000..594a966 --- /dev/null +++ b/ZTestSuite/Test-SST_Math.cpp @@ -0,0 +1,571 @@ +/* + Test-ZTransform.cpp +Author: Charles Lena <cmlena@762studios.com> +Created: 3/29/2012 + +Purpose: + +Tests to ensure that the math transform routines function accurately. +*/ + +#include "ZUnitTest.hpp" +#include <stdio.h> +#include <stdlib.h> +#include <climits> +#include <cfloat> +#include <math.h> +#include <SST/SST_Transform.h> +#include <SST/SST_Vec3.h> +#include <SST/SST_Vec4.h> + + +const double dPI = 3.1415926535897932384626433832795028841971693993751058209; +const float fPI = 3.1415926535897932384626433832795028841971693993751058209f; + +inline bool fpcomp(float typed_1, float typed_2, float tol = FLT_EPSILON) +{ + return (abs(typed_1 - typed_2) <= tol); +} +inline bool dpcomp(double typed_1, double typed_2, double tol = DBL_EPSILON) +{ + return (abs(typed_1 - typed_2) <= tol); +} + +static const char* testSST_Mat33f_IdentityCreate(); +static const char* testSST_Mat33f_Add(); +static const char* testSST_Mat33f_Sub(); +static const char* testSST_Mat33f_ElementMult(); + +//List of unit tests +ZUnitTest SST_TransformUnitTests[] = +{ +{ "testSST_Mat33f_IdentityCreate" , testSST_Mat33f_IdentityCreate }, +{ "testSST_Mat44f_IdentityCreate" , testSST_Mat44f_IdentityCreate }, +{ "testSST_Mat33d_IdentityCreate" , testSST_Mat33d_IdentityCreate }, +{ "testSST_Mat44d_IdentityCreate" , testSST_Mat44d_IdentityCreate }, +{ "testSST_Mat33f_TranslationCreate" , testSST_Mat33f_TranslationCreate }, +{ "testSST_Mat44f_TranslationCreate" , testSST_Mat44f_TranslationCreate }, +{ "testSST_Mat44f_EulerXCreate" , testSST_Mat44f_EulerXCreate }, +{ "testSST_Mat44f_EulerYCreate" , testSST_Mat44f_EulerYCreate }, +{ "testSST_Mat44f_EulerZCreate" , testSST_Mat44f_EulerZCreate }, +{ "testSST_Mat44f_EulerXCreateC" , testSST_Mat44f_EulerXCreateC }, +{ "testSST_Mat44f_EulerYCreateC" , testSST_Mat44f_EulerYCreateC }, +{ "testSST_Mat44f_EulerZCreateC" , testSST_Mat44f_EulerZCreateC }, +{ "testSST_Mat44f_ShearCreate" , testSST_Mat44f_ShearCreate }, +{ "testSST_Mat44f_FreeTransformCreate" , testSST_Mat44f_FreeTransformCreate }, +{ "testSST_Mat44f_QuaternionCreate" , testSST_Mat44f_QuaternionCreate }, +{ "testSST_Mat44f_ScaleCreate" , testSST_Mat44f_ScaleCreate }, +{ "testSST_Mat44_LookAt" , testSST_Mat44_LookAt }, +{ "testSST_Mat33_ExtractFromMat44" , testSST_Mat33_ExtractFromMat44 }, +{ "testSST_Mat44_PerspectiveProjectionCreate" , testSST_Mat44_PerspectiveProjectionCreate }, +{ "testSST_Mat44_OrthogonalProjectionCreate" , testSST_Mat44_OrthogonalProjectionCreate } +}; + +DECLARE_ZTESTBLOCK(SST_Transform); + +// ======================================= +#define A9f(i,j) A9f[i*3+j] +#define A16f(i,j) A16f[i*4+j] +#define A9d(i,j) A9d[i*3+j] +#define A16d(i,j) A16d[i*4+j] +static const char* testSST_Mat33f_IdentityCreate() +{ + float A9f[9]; + SST_Mat33f_IdentityCreate(A9f); + for(int i=0; i<3; i++) + TASSERT((A9f(i,i) != 1.f),"SST_Mat33f_IdentityCreate failed!"); + + return ZTEST_SUCCESS; +} +static const char* testSST_Mat33d_IdentityCreate() +{ + double A9d[9]; + SST_Mat33d_IdentityCreate(A9d); + for(int i=0; i<3; i++) + TASSERT((A9d(i,i) != 1.0),"SST_Mat33d_IdentityCreate failed!"); + + return ZTEST_SUCCESS; +} +static const char* testSST_Mat44f_IdentityCreate() +{ + float A16f[16]; + SST_Mat44f_IdentityCreate(A16f); + for(int i=0; i<4; i++) + TASSERT((A16f(i,i) != 1.f),"SST_Mat44f_IdentityCreate failed!"); + + return ZTEST_SUCCESS; +} +static const char* testSST_Mat44d_IdentityCreate() +{ + double A16d[16]; + SST_Mat44d_IdentityCreate(A16d); + for(int i=0; i<4; i++) + TASSERT((A16d(i,i) != 1.0),"SST_Mat44d_IdentityCreate failed!"); + + return ZTEST_SUCCESS; +} +static const char* testSST_Mat33f_TranslationCreate() +{ + float A9f[9]; + float txy[] = {1.0,2.0}; + + SST_Mat33f_TranslationCreate(txy,A9f); + for(int i = 0; i<2; i++) + TASSERT(A9f(i,i) == 1.f,"TranslationCreate: Diagonals incorrect"); + for(int i = 0; i<2; i++) + TASSERT(A9f(i,2) == txy[i],"TranslationCreate: Translation Column not correctly set!"); + return ZTEST_SUCCESS; +} +static const char* testSST_Mat44f_TranslationCreate(){ + float A16f[16]; + float txyz[] = {1.0,2.0,3.0}; + + SST_Mat44f_TranslationCreate(txyz,A16f); + for(int i = 0; i<3; i++) + TASSERT(A16f(i,i) == 1.f,"TranslationCreate: Diagonals incorrect"); + for(int i = 0; i<3; i++) + TASSERT(A16f(i,3) == txyz[i],"TranslationCreate: Translation Column not correctly set!"); + return ZTEST_SUCCESS; +} +static const char* testSST_Mat44f_EulerXCreate(){ + + float angle = fPI / 2.f; // 90 degrees + float* A16f = new float[16]; + float temp[16] = {0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f}; + float temp2[16] = {0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f}; + + // Make sure its actually setting entries to zero + for(int i=0; i < 16; i++) A16f[i] = 1.0*rand(); + + // Call + SST_Mat44f_EulerXCreate(angle,A16f); + // Check Actual Mat + TASSERT(A16f[0] == 1.f,"Entry 1 incorrect in EulerX Mat"); + TASSERT(A16f[1] == 0.f,"Entry 2 incorrect in EulerX Mat"); + TASSERT(A16f[2] == 0.f,"Entry 3 incorrect in EulerX Mat"); + TASSERT(A16f[3] == 0.f,"Entry 4 incorrect in EulerX Mat"); + TASSERT(A16f[4] == 0.f,"Entry 5 incorrect in EulerX Mat"); + TASSERT(A16f[5] == cosf(angle),"Entry 6 incorrect in EulerX Mat"); + TASSERT(A16f[6] == -sinf(angle),"Entry 7 incorrect in EulerX Mat"); + TASSERT(A16f[7] == 0.f,"Entry 8 incorrect in EulerX Mat"); + TASSERT(A16f[8] == 0.f,"Entry 9 incorrect in EulerX Mat"); + TASSERT(A16f[9] == sinf(angle),"Entry 10 incorrect in EulerX Mat"); + TASSERT(A16f[10] == cosf(angle),"Entry 11 incorrect in EulerX Mat"); + TASSERT(A16f[11] == 0.f,"Entry 12 incorrect in EulerX Mat"); + TASSERT(A16f[12] == 0.f,"Entry 13 incorrect in EulerX Mat"); + TASSERT(A16f[13] == 0.f,"Entry 14 incorrect in EulerX Mat"); + TASSERT(A16f[14] == 0.f,"Entry 15 incorrect in EulerX Mat"); + TASSERT(A16f[15] == 1.f,"Entry 16 incorrect in EulerX Mat"); + // Check Function of Mat Applied to a [0 1 1 .5] vector + float vectold[] = {2.f,1.f,1.f,.5f}; + float vectnew[] = {0.f,0.f,0.f,0.f}; + //C_ij = A_ik * B_kj + for(int i = 0; i < 4; i++) + for(int k = 0; k < 4; k++) + vectnew[i] += A16f[4*i+k]*vectold[k]; + + TASSERT((vectnew[0] == 2.f), "Resulting vectnew[0] is incorrect"); + TASSERT(fpcomp(vectnew[1],1.f), "Resulting vectnew[1] is incorrect"); + TASSERT(fpcomp(vectnew[2],-1.f),"Resulting vectnew[2] is incorrect"); + TASSERT((vectnew[3] == .5f), "Resulting vectnew[3] is incorrect"); + + memset(vectnew,0.f,4*sizeof(float)); + + //C_ij = A_ik * A_kj + for(int i = 0; i < 4; i++) + for(int j = 0; j < 4; j++) + for(int k = 0; k < 4; k++) + temp[4*i+j] += A16f[4*i+k]*A16f[4*k+j]; + + // Check Function of Mat Applied twice to [0 1 1 .5] vector + for(int i = 0; i < 4; i++) + for(int k = 0; k < 4; k++) + vectnew[i] += temp[4*i+k]*vectold[k]; + + TASSERT((vectnew[0] == 2.f), "Resulting vectnew[0] is incorrect"); + TASSERT(fpcomp(vectnew[1],-1.f),"Resulting vectnew[1] is incorrect"); + TASSERT(fpcomp(vectnew[2],-1.f),"Resulting vectnew[2] is incorrect"); + TASSERT((vectnew[3] == .5f), "Resulting vectnew[3] is incorrect"); + + // Check Function of Mat Applied 3 times to [0 1 1 .5] vector + memset(vectnew,0.f,4*sizeof(float)); + + for(int i = 0; i < 4; i++) + for(int j = 0; j < 4; j++) + for(int k = 0; k < 4; k++) + temp2[4*i+j] += A16f[4*i+k]*temp[4*k+j]; + + for(int i = 0; i < 4; i++) + for(int k = 0; k < 4; k++) + vectnew[i] += temp2[4*i+k]*vectold[k]; + + TASSERT((vectnew[0] == 2.f), "Resulting vectnew[0] is incorrect"); + TASSERT(fpcomp(vectnew[1],-1.f),"Resulting vectnew[1] is incorrect"); + TASSERT(fpcomp(vectnew[2], 1.f),"Resulting vectnew[2] is incorrect"); + TASSERT((vectnew[3] == .5f), "Resulting vectnew[3] is incorrect"); + + memset(vectnew,0.f,4*sizeof(float)); + + for(int i = 0; i < 4; i++) + for(int j = 0; j < 4; j++) + for(int k = 0; k < 4; k++) + temp[4*i+j] += A16f[4*i+k]*temp2[4*k+j]; + + for(int i = 0; i < 4; i++) + for(int k = 0; k < 4; k++) + vectnew[i] += temp[4*i+k]*vectold[k]; + + TASSERT((vectnew[0] == 2.f), "Resulting vectnew[0] is incorrect"); + TASSERT(fpcomp(vectnew[1],1.f),"Resulting vectnew[1] is incorrect"); + TASSERT(fpcomp(vectnew[2],1.f),"Resulting vectnew[2] is incorrect"); + TASSERT((vectnew[3] == .5f), "Resulting vectnew[3] is incorrect"); + + return ZTEST_SUCCESS; +} +static const char* testSST_Mat44f_EulerYCreate(){ + float angle = fPI / 2.f; // 90 degrees + float* A16f = new float[16]; + float temp[16] = {0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f}; + float temp2[16] = {0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f}; + + // Make sure its actually setting entries to zero + for(int i=0; i < 16; i++) A16f[i] = 1.0*rand(); + + TASSERT(A16f[0] == cosf(angle),"EulerY entry 1 is incorrect"); + TASSERT(A16f[1] == 0.f, "EulerY entry 2 is incorrect"); + TASSERT(A16f[2] == sinf(angle),"EulerY entry 3 is incorrect"); + TASSERT(A16f[3] == 0.f, "EulerY entry 4 is incorrect"); + TASSERT(A16f[4] == 0.f, "EulerY entry 5 is incorrect"); + TASSERT(A16f[5] == 1.f, "EulerY entry 6 is incorrect"); + TASSERT(A16f[6] == 0.f, "EulerY entry 7 is incorrect"); + TASSERT(A16f[7] == 0.f, "EulerY entry 8 is incorrect"); + TASSERT(A16f[8] ==-sinf(angle),"EulerY entry 9 is incorrect"); + TASSERT(A16f[9] == 0.f, "EulerY entry 10 is incorrect"); + TASSERT(A16f[10] == cosf(angle),"EulerY entry 11 is incorrect"); + TASSERT(A16f[11] == 0.f, "EulerY entry 12 is incorrect"); + TASSERT(A16f[12] == 0.f, "EulerY entry 13 is incorrect"); + TASSERT(A16f[13] == 0.f, "EulerY entry 14 is incorrect"); + TASSERT(A16f[14] == 0.f, "EulerY entry 15 is incorrect"); + TASSERT(A16f[15] == 1.f, "EulerY entry 16 is incorrect"); + // Check Function of Mat Applied to a [0 1 1 .5] vector + float vectold[] = {1.f,2.f,1.f,.5f}; + float vectnew[] = {0.f,0.f,0.f,0.f}; + //C_ij = A_ik * B_kj + for(int i = 0; i < 4; i++) + for(int k = 0; k < 4; k++) + vectnew[i] += A16f[4*i+k]*vectold[k]; + + TASSERT( (vectnew[0] ==-1.f),"Resulting vectnew[0] is incorrect"); + TASSERT(fpcomp(vectnew[1], 2.f),"Resulting vectnew[1] is incorrect"); + TASSERT(fpcomp(vectnew[2], 1.f),"Resulting vectnew[2] is incorrect"); + TASSERT( (vectnew[3] == .5f),"Resulting vectnew[3] is incorrect"); + + memset(vectnew,0.f,4*sizeof(float)); + + //C_ij = A_ik * A_kj + for(int i = 0; i < 4; i++) + for(int j = 0; j < 4; j++) + for(int k = 0; k < 4; k++) + temp[4*i+j] += A16f[4*i+k]*A16f[4*k+j]; + + // Check Function of Mat Applied twice to [0 1 1 .5] vector + for(int i = 0; i < 4; i++) + for(int k = 0; k < 4; k++) + vectnew[i] += temp[4*i+k]*vectold[k]; + + TASSERT( (vectnew[0] == -1.f),"Resulting vectnew[0] is incorrect"); + TASSERT(fpcomp(vectnew[1], 2.f),"Resulting vectnew[1] is incorrect"); + TASSERT(fpcomp(vectnew[2],-1.f),"Resulting vectnew[2] is incorrect"); + TASSERT( (vectnew[3] == .5f),"Resulting vectnew[3] is incorrect"); + + // Check Function of Mat Applied 3 times to [0 1 1 .5] vector + memset(vectnew,0.f,4*sizeof(float)); + + for(int i = 0; i < 4; i++) + for(int j = 0; j < 4; j++) + for(int k = 0; k < 4; k++) + temp2[4*i+j] += A16f[4*i+k]*temp[4*k+j]; + + for(int i = 0; i < 4; i++) + for(int k = 0; k < 4; k++) + vectnew[i] += temp2[4*i+k]*vectold[k]; + + TASSERT(fpcomp(vectnew[0],-1.f),"Resulting vectnew[0] is incorrect"); + TASSERT(fpcomp(vectnew[1], 2.f,0.f),"Resulting vectnew[1] is incorrect"); + TASSERT(fpcomp(vectnew[2], 1.f),"Resulting vectnew[2] is incorrect"); + TASSERT(fpcomp(vectnew[3], .5f,0.f),"Resulting vectnew[3] is incorrect"); + + memset(vectnew,0.f,4*sizeof(float)); + + for(int i = 0; i < 4; i++) + for(int j = 0; j < 4; j++) + for(int k = 0; k < 4; k++) + temp[4*i+j] += A16f[4*i+k]*temp2[4*k+j]; + + for(int i = 0; i < 4; i++) + for(int k = 0; k < 4; k++) + vectnew[i] += temp[4*i+k]*vectold[k]; + + TASSERT(fpcomp(vectnew[0],1.f),"Resulting vectnew[0] is incorrect"); + TASSERT(fpcomp(vectnew[1],2.f,0.f),"Resulting vectnew[1] is incorrect"); + TASSERT(fpcomp(vectnew[2],1.f),"Resulting vectnew[2] is incorrect"); + TASSERT(fpcomp(vectnew[3],.5f,0.f),"Resulting vectnew[3] is incorrect"); + + return ZTEST_SUCCESS; +} +static const char* testSST_Mat44f_EulerZCreate(){ + float angle = fPI / 2.f; // 90 degrees + float* A16f = new float[16]; + float temp[16] = {0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f}; + float temp2[16] = {0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f}; + + // Make sure its actually setting entries to zero + for(int i=0; i < 16; i++) A16f[i] = 1.0*rand(); + + const float cosa = cosf(angle); + const float sina = sinf(angle); + TASSERT(A16f[0] == cosa,"EulerY entry 10 is incorrect"); + TASSERT(A16f[1] == -sina,"EulerY entry 10 is incorrect"); + TASSERT(A16f[2] == 0.f,"EulerY entry 10 is incorrect"); + TASSERT(A16f[3] == 0.f,"EulerY entry 10 is incorrect"); + + TASSERT(A16f[4] == sina,"EulerY entry 10 is incorrect"); + TASSERT(A16f[5] == cosa,"EulerY entry 10 is incorrect"); + TASSERT(A16f[6] == 0.f,"EulerY entry 10 is incorrect"); + TASSERT(A16f[7] == 0.f,"EulerY entry 10 is incorrect"); + + TASSERT(A16f[8] == 0.f,"EulerY entry 10 is incorrect"); + TASSERT(A16f[9] == 0.f,"EulerY entry 10 is incorrect"); + TASSERT(A16f[10] == 1.f,"EulerY entry 10 is incorrect"); + TASSERT(A16f[11] == 0.f,"EulerY entry 10 is incorrect"); + + TASSERT(A16f[12] == 0.f,"EulerY entry 10 is incorrect"); + TASSERT(A16f[13] == 0.f,"EulerY entry 10 is incorrect"); + TASSERT(A16f[14] == 0.f,"EulerY entry 10 is incorrect"); + TASSERT(A16f[15] == 1.f,"EulerY entry 10 is incorrect"); + + // Check Function of Mat Applied to a [0 1 1 .5] vector + float vectold[] = {1.f,1.f,2.f,.5f}; + float vectnew[] = {0.f,0.f,0.f,0.f}; + //C_ij = A_ik * B_kj + for(int i = 0; i < 4; i++) + for(int k = 0; k < 4; k++) + vectnew[i] += A16f[4*i+k]*vectold[k]; + + TASSERT(fpcomp(vectnew[0],-1.f),"Resulting vectnew[0] is incorrect"); + TASSERT(fpcomp(vectnew[1], 1.f),"Resulting vectnew[1] is incorrect"); + TASSERT(fpcomp(vectnew[2], 2.f,0.f),"Resulting vectnew[2] is incorrect"); + TASSERT(fpcomp(vectnew[3], .5f,0.f),"Resulting vectnew[3] is incorrect"); + + memset(vectnew,0.f,4*sizeof(float)); + + //C_ij = A_ik * A_kj + for(int i = 0; i < 4; i++) + for(int j = 0; j < 4; j++) + for(int k = 0; k < 4; k++) + temp[4*i+j] += A16f[4*i+k]*A16f[4*k+j]; + + // Check Function of Mat Applied twice to [0 1 1 .5] vector + for(int i = 0; i < 4; i++) + for(int k = 0; k < 4; k++) + vectnew[i] += temp[4*i+k]*vectold[k]; + + TASSERT(fpcomp(vectnew[0],-1.f),"Resulting vectnew[0] is incorrect"); + TASSERT(fpcomp(vectnew[1],-1.f),"Resulting vectnew[1] is incorrect"); + TASSERT(fpcomp(vectnew[2], 2.f,0.f),"Resulting vectnew[2] is incorrect"); + TASSERT(fpcomp(vectnew[3], .5f,0.f),"Resulting vectnew[3] is incorrect"); + + // Check Function of Mat Applied 3 times to [0 1 1 .5] vector + memset(vectnew,0.f,4*sizeof(float)); + + for(int i = 0; i < 4; i++) + for(int j = 0; j < 4; j++) + for(int k = 0; k < 4; k++) + temp2[4*i+j] += A16f[4*i+k]*temp[4*k+j]; + + for(int i = 0; i < 4; i++) + for(int k = 0; k < 4; k++) + vectnew[i] += temp2[4*i+k]*vectold[k]; + + TASSERT(fpcomp(vectnew[0], 1.f),"Resulting vectnew[0] is incorrect"); + TASSERT(fpcomp(vectnew[1],-1.f),"Resulting vectnew[1] is incorrect"); + TASSERT(fpcomp(vectnew[2], 2.f,0.f),"Resulting vectnew[2] is incorrect"); + TASSERT(fpcomp(vectnew[3], .5f,0.f),"Resulting vectnew[3] is incorrect"); + + memset(vectnew,0.f,4*sizeof(float)); + + for(int i = 0; i < 4; i++) + for(int j = 0; j < 4; j++) + for(int k = 0; k < 4; k++) + temp[4*i+j] += A16f[4*i+k]*temp2[4*k+j]; + + for(int i = 0; i < 4; i++) + for(int k = 0; k < 4; k++) + vectnew[i] += temp[4*i+k]*vectold[k]; + + TASSERT(fpcomp(vectnew[0],1.f),"Resulting vectnew[0] is incorrect"); + TASSERT(fpcomp(vectnew[1],1.f),"Resulting vectnew[1] is incorrect"); + TASSERT(fpcomp(vectnew[2],2.f,0.f),"Resulting vectnew[2] is incorrect"); + TASSERT(fpcomp(vectnew[3],.5f,0.f),"Resulting vectnew[3] is incorrect"); + return ZTEST_SUCCESS; +} +static const char* testSST_Mat44f_EulerXCreateC(){ + float angle = fPI / 2.f; // 90 degrees + float A16f[16]; + float temp[16] = {0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f}; + float temp2[16] = {0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f}; + SST_Mat44f_IdentityCreate(A16f); + SST_Mat44f_EulerXCreateC(angle,A16f); + SST_Mat44f_EulerXCreate(angle,temp); + int i = 0; + TASSERT(fpcomp(A16f[i],temp[i]),"Entry 1 in EulerXCreateC acting on Identity disagrees with EulerXCreate"); i++; + TASSERT(fpcomp(A16f[i],temp[i]),"Entry 2 in EulerXCreateC acting on Identity disagrees with EulerXCreate"); i++; + TASSERT(fpcomp(A16f[i],temp[i]),"Entry 3 in EulerXCreateC acting on Identity disagrees with EulerXCreate"); i++; + TASSERT(fpcomp(A16f[i],temp[i]),"Entry 4 in EulerXCreateC acting on Identity disagrees with EulerXCreate"); i++; + TASSERT(fpcomp(A16f[i],temp[i]),"Entry 5 in EulerXCreateC acting on Identity disagrees with EulerXCreate"); i++; + TASSERT(fpcomp(A16f[i],temp[i]),"Entry 6 in EulerXCreateC acting on Identity disagrees with EulerXCreate"); i++; + TASSERT(fpcomp(A16f[i],temp[i]),"Entry 7 in EulerXCreateC acting on Identity disagrees with EulerXCreate"); i++; + TASSERT(fpcomp(A16f[i],temp[i]),"Entry 8 in EulerXCreateC acting on Identity disagrees with EulerXCreate"); i++; + TASSERT(fpcomp(A16f[i],temp[i]),"Entry 9 in EulerXCreateC acting on Identity disagrees with EulerXCreate"); i++; + TASSERT(fpcomp(A16f[i],temp[i]),"Entry 10 in EulerXCreateC acting on Identity disagrees with EulerXCreate"); i++; + TASSERT(fpcomp(A16f[i],temp[i]),"Entry 11 in EulerXCreateC acting on Identity disagrees with EulerXCreate"); i++; + TASSERT(fpcomp(A16f[i],temp[i]),"Entry 12 in EulerXCreateC acting on Identity disagrees with EulerXCreate"); i++; + TASSERT(fpcomp(A16f[i],temp[i]),"Entry 13 in EulerXCreateC acting on Identity disagrees with EulerXCreate"); i++; + TASSERT(fpcomp(A16f[i],temp[i]),"Entry 14 in EulerXCreateC acting on Identity disagrees with EulerXCreate"); i++; + TASSERT(fpcomp(A16f[i],temp[i]),"Entry 15 in EulerXCreateC acting on Identity disagrees with EulerXCreate"); i++; + TASSERT(fpcomp(A16f[i],temp[i]),"Entry 16 in EulerXCreateC acting on Identity disagrees with EulerXCreate"); i++; + return ZTEST_SUCCESS; +} +static const char* testSST_Mat44f_EulerYCreateC(){ + float angle = fPI / 2.f; // 90 degrees + float A16f[16]; + float temp[16] = {0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f}; + float temp2[16] = {0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f}; + SST_Mat44f_IdentityCreate(A16f); + SST_Mat44f_EulerYCreateC(angle,A16f); + SST_Mat44f_EulerYCreate(angle,temp); + int i = 0; + TASSERT(fpcomp(A16f[i],temp[i]),"Entry 1 in EulerYCreateC acting on Identity disagrees with EulerYCreate"); i++; + TASSERT(fpcomp(A16f[i],temp[i]),"Entry 2 in EulerYCreateC acting on Identity disagrees with EulerYCreate"); i++; + TASSERT(fpcomp(A16f[i],temp[i]),"Entry 3 in EulerYCreateC acting on Identity disagrees with EulerYCreate"); i++; + TASSERT(fpcomp(A16f[i],temp[i]),"Entry 4 in EulerYCreateC acting on Identity disagrees with EulerYCreate"); i++; + TASSERT(fpcomp(A16f[i],temp[i]),"Entry 5 in EulerYCreateC acting on Identity disagrees with EulerYCreate"); i++; + TASSERT(fpcomp(A16f[i],temp[i]),"Entry 6 in EulerYCreateC acting on Identity disagrees with EulerYCreate"); i++; + TASSERT(fpcomp(A16f[i],temp[i]),"Entry 7 in EulerYCreateC acting on Identity disagrees with EulerYCreate"); i++; + TASSERT(fpcomp(A16f[i],temp[i]),"Entry 8 in EulerYCreateC acting on Identity disagrees with EulerYCreate"); i++; + TASSERT(fpcomp(A16f[i],temp[i]),"Entry 9 in EulerYCreateC acting on Identity disagrees with EulerYCreate"); i++; + TASSERT(fpcomp(A16f[i],temp[i]),"Entry 10 in EulerYCreateC acting on Identity disagrees with EulerYCreate"); i++; + TASSERT(fpcomp(A16f[i],temp[i]),"Entry 11 in EulerYCreateC acting on Identity disagrees with EulerYCreate"); i++; + TASSERT(fpcomp(A16f[i],temp[i]),"Entry 12 in EulerYCreateC acting on Identity disagrees with EulerYCreate"); i++; + TASSERT(fpcomp(A16f[i],temp[i]),"Entry 13 in EulerYCreateC acting on Identity disagrees with EulerYCreate"); i++; + TASSERT(fpcomp(A16f[i],temp[i]),"Entry 14 in EulerYCreateC acting on Identity disagrees with EulerYCreate"); i++; + TASSERT(fpcomp(A16f[i],temp[i]),"Entry 15 in EulerYCreateC acting on Identity disagrees with EulerYCreate"); i++; + TASSERT(fpcomp(A16f[i],temp[i]),"Entry 16 in EulerYCreateC acting on Identity disagrees with EulerYCreate"); i++; + return ZTEST_SUCCESS; +} +static const char* testSST_Mat44f_EulerZCreateC(){ + float angle = fPI / 2.f; // 90 degrees + float A16f[16]; + float temp[16] = {0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f}; + float temp2[16] = {0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f}; + SST_Mat44f_IdentityCreate(A16f); + SST_Mat44f_EulerZCreateC(angle,A16f); + SST_Mat44f_EulerZCreate(angle,temp); + int i = 0; + TASSERT(fpcomp(A16f[i],temp[i]),"Entry 1 in EulerZCreateC acting on Identity disagrees with EulerZCreate"); i++; + TASSERT(fpcomp(A16f[i],temp[i]),"Entry 2 in EulerZCreateC acting on Identity disagrees with EulerZCreate"); i++; + TASSERT(fpcomp(A16f[i],temp[i]),"Entry 3 in EulerZCreateC acting on Identity disagrees with EulerZCreate"); i++; + TASSERT(fpcomp(A16f[i],temp[i]),"Entry 4 in EulerZCreateC acting on Identity disagrees with EulerZCreate"); i++; + TASSERT(fpcomp(A16f[i],temp[i]),"Entry 5 in EulerZCreateC acting on Identity disagrees with EulerZCreate"); i++; + TASSERT(fpcomp(A16f[i],temp[i]),"Entry 6 in EulerZCreateC acting on Identity disagrees with EulerZCreate"); i++; + TASSERT(fpcomp(A16f[i],temp[i]),"Entry 7 in EulerZCreateC acting on Identity disagrees with EulerZCreate"); i++; + TASSERT(fpcomp(A16f[i],temp[i]),"Entry 8 in EulerZCreateC acting on Identity disagrees with EulerZCreate"); i++; + TASSERT(fpcomp(A16f[i],temp[i]),"Entry 9 in EulerZCreateC acting on Identity disagrees with EulerZCreate"); i++; + TASSERT(fpcomp(A16f[i],temp[i]),"Entry 10 in EulerZCreateC acting on Identity disagrees with EulerZCreate"); i++; + TASSERT(fpcomp(A16f[i],temp[i]),"Entry 11 in EulerZCreateC acting on Identity disagrees with EulerZCreate"); i++; + TASSERT(fpcomp(A16f[i],temp[i]),"Entry 12 in EulerZCreateC acting on Identity disagrees with EulerZCreate"); i++; + TASSERT(fpcomp(A16f[i],temp[i]),"Entry 13 in EulerZCreateC acting on Identity disagrees with EulerZCreate"); i++; + TASSERT(fpcomp(A16f[i],temp[i]),"Entry 14 in EulerZCreateC acting on Identity disagrees with EulerZCreate"); i++; + TASSERT(fpcomp(A16f[i],temp[i]),"Entry 15 in EulerZCreateC acting on Identity disagrees with EulerZCreate"); i++; + TASSERT(fpcomp(A16f[i],temp[i]),"Entry 16 in EulerZCreateC acting on Identity disagrees with EulerZCreate"); i++; + return ZTEST_SUCCESS; +} +static const char* testSST_Mat44f_ShearCreate(){ + + float A16f[16]; + float shearing[6] = {0.5f,0.25f,0.5f,0.25f,.5f,.25f}; + float temp[16] = {0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f}; + float temp2[16] = {0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f}; + + SST_Mat44f_ShearCreate(shearing,A16f); + + TASSERT(A16f[0] == 1.f,"EulerY entry 1 is incorrect"); + TASSERT(A16f[1] == shearing[0],"EulerY entry 2 is incorrect"); + TASSERT(A16f[2] == shearing[1],"EulerY entry 3 is incorrect"); + TASSERT(A16f[3] == 0.f,"EulerY entry 4 is incorrect"); + + TASSERT(A16f[4] == shearing[2],"EulerY entry 5 is incorrect"); + TASSERT(A16f[5] == 1.f,"EulerY entry 6 is incorrect"); + TASSERT(A16f[6] == shearing[3],"EulerY entry 7 is incorrect"); + TASSERT(A16f[7] == 0.f,"EulerY entry 8 is incorrect"); + + TASSERT(A16f[8] == shearing[4],"EulerY entry 9 is incorrect"); + TASSERT(A16f[9] == shearing[5],"EulerY entry 10 is incorrect"); + TASSERT(A16f[10] == 1.f,"EulerY entry 11 is incorrect"); + TASSERT(A16f[11] == 0.f,"EulerY entry 12 is incorrect"); + + TASSERT(A16f[12] == 0.f,"EulerY entry 13 is incorrect"); + TASSERT(A16f[13] == 0.f,"EulerY entry 14 is incorrect"); + TASSERT(A16f[14] == 0.f,"EulerY entry 15 is incorrect"); + TASSERT(A16f[15] == 1.f,"EulerY entry 16 is incorrect"); + + return ZTEST_SUCCESS; +} +static const char* testSST_Mat44f_FreeTransformCreate(){ + float A16f[16]; + float scale[3] = {0.5f,0.25f,0.5f}; + float shearing[6] = {0.5f,0.25f,0.5f,0.25f,.5f,.25f}; + + float temp[16] = {0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f}; + float temp2[16] = {0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f,0.f}; + + TASSERT(A16f[0] == scale[0],"EulerY entry 1 is incorrect"); + TASSERT(A16f[1] == shearing[0],"EulerY entry 2 is incorrect"); + TASSERT(A16f[2] == shearing[1],"EulerY entry 3 is incorrect"); + TASSERT(A16f[3] == 0.f,"EulerY entry 4 is incorrect"); + + TASSERT(A16f[4] == shearing[2],"EulerY entry 5 is incorrect"); + TASSERT(A16f[5] == scale[1],"EulerY entry 6 is incorrect"); + TASSERT(A16f[6] == shearing[3],"EulerY entry 7 is incorrect"); + TASSERT(A16f[7] == 0.f,"EulerY entry 8 is incorrect"); + + TASSERT(A16f[8] == shearing[4],"EulerY entry 9 is incorrect"); + TASSERT(A16f[9] == shearing[5],"EulerY entry 10 is incorrect"); + TASSERT(A16f[10] == scale[2],"EulerY entry 11 is incorrect"); + TASSERT(A16f[11] == 0.f,"EulerY entry 12 is incorrect"); + + TASSERT(A16f[12] == 0.f,"EulerY entry 13 is incorrect"); + TASSERT(A16f[13] == 0.f,"EulerY entry 14 is incorrect"); + TASSERT(A16f[14] == 0.f,"EulerY entry 15 is incorrect"); + TASSERT(A16f[15] == 1.f,"EulerY entry 16 is incorrect"); + + return ZTEST_SUCCESS; +} +static const char* testSST_Mat44f_QuaternionCreate(){ + return ZTEST_SUCCESS; +} +static const char* testSST_Mat44f_ScaleCreate(){ + return ZTEST_SUCCESS; +} +static const char* testSST_Mat44_LookAt(){ + return ZTEST_SUCCESS; +} +static const char* testSST_Mat33_ExtractFromMat44(){ + return ZTEST_SUCCESS; +} +static const char* testSST_Mat44_PerspectiveProjectionCreate(){ + return ZTEST_SUCCESS; +} +static const char* testSST_Mat44_OrthogonalProjectionCreate(){ + return ZTEST_SUCCESS; +} diff --git a/ZTestSuite/Test-SST_SafeArithmetic.cpp b/ZTestSuite/Test-SST_SafeArithmetic.cpp new file mode 100644 index 0000000..f5cc229 --- /dev/null +++ b/ZTestSuite/Test-SST_SafeArithmetic.cpp @@ -0,0 +1,387 @@ +/* + Test-SST_SafeArithmetic.cpp + Author: Chris Ertel <crertel@762studios.com> + Created: 2/5/2012 + + Purpose: + + Tests to ensure that the safe arithmetic package for libsst is, in fact, safe. +*/ +#include "ZUnitTest.hpp" +#include <stdio.h> +#include <stdlib.h> +#include <climits> +#include <SST/SST_SafeArithmetic.h> + +static const char* testSafeAddI8(); +static const char* testSafeAddI16(); +static const char* testSafeAddI32(); +static const char* testSafeAddI64(); + +static const char* testSafeAddU8(); +static const char* testSafeAddU16(); +static const char* testSafeAddU32(); +static const char* testSafeAddU64(); + +static const char* testSafeMultiplyU8(); +static const char* testSafeMultiplyU16(); +static const char* testSafeMultiplyU32(); +static const char* testSafeMultiplyU64(); + +static const char* testSafeAddI8ToSizeT(); +static const char* testSafeAddI16ToSizeT(); +static const char* testSafeAddI32ToSizeT(); +static const char* testSafeAddI64ToSizeT(); + +static const char* testSafeAddU8ToSizeT(); +static const char* testSafeAddU16ToSizeT(); +static const char* testSafeAddU32ToSizeT(); +static const char* testSafeAddU64ToSizeT(); + +static const char* testSafeAddSizeTToSizeT(); + +//List of unit tests +ZUnitTest SST_SafeArithmeticUnitTests[] = +{ + { + "Safe add signed 8-bit", + testSafeAddI8 + }, + { + "Safe add signed 16-bit", + testSafeAddI16 + }, + { + "Safe add signed 32-bit", + testSafeAddI32 + }, + { + "Safe add signed 64-bit", + testSafeAddI64 + }, + { + "Safe add unsigned 8-bit", + testSafeAddU8 + }, + { + "Safe add unsigned 16-bit", + testSafeAddU16 + }, + { + "Safe add unsigned 32-bit", + testSafeAddU32 + }, + { + "Safe add unsigned 64-bit", + testSafeAddU64 + }, + + { + "Safe multiply unsigned 8-bit", + testSafeMultiplyU8 + }, + { + "Safe multiply unsigned 16-bit", + testSafeMultiplyU16 + }, + { + "Safe multiply unsigned 32-bit", + testSafeMultiplyU32 + }, + { + "Safe multiply unsigned 64-bit", + testSafeMultiplyU64 + }, + + { + "Safe add signed 8-bit to size_t", + testSafeAddI8ToSizeT + }, + { + "Safe add signed 16-bit to size_t", + testSafeAddI16ToSizeT + }, + { + "Safe add signed 32-bit to size_t", + testSafeAddI32ToSizeT + }, + { + "Safe add signed 64-bit to size_t", + testSafeAddI64ToSizeT + }, + { + "Safe add unsigned 8-bit to size_t", + testSafeAddU8ToSizeT + }, + { + "Safe add unsigned 16-bit to size_t", + testSafeAddU16ToSizeT + }, + { + "Safe add unsigned 32-bit to size_t", + testSafeAddU32ToSizeT + }, + { + "Safe add unsigned 64-bit to size_t", + testSafeAddU64ToSizeT + }, + { + "Safe add size_t to size_t", + testSafeAddSizeTToSizeT + } +}; + +DECLARE_ZTESTBLOCK(SST_SafeArithmetic); + +/*************************************************************************/ + +static const char* testSafeAddI8() +{ + int8_t out; + TASSERT( (SST_OS_SafeAddI8(INT8_MAX-1, 1, &out) == 1), "SafeAddI8 returned false when no overflow!\n"); + TASSERT( (out == INT8_MAX), "SafeAddI8 can't add without overflow!\n"); + TASSERT( (SST_OS_SafeAddI8(INT8_MAX-1, 2, &out) == 0), "SafeAddI8 returned true when overflow!\n"); + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* testSafeAddI16() +{ + int16_t out; + TASSERT( (SST_OS_SafeAddI16(INT16_MAX-1, 1, &out) == 1), "SafeAddI16 returned false when no overflow!\n"); + TASSERT( (out == INT16_MAX), "SafeAddI16 can't add without overflow!\n"); + TASSERT( (SST_OS_SafeAddI16(INT16_MAX-1, 2, &out) == 0), "SafeAddI16 returned true when overflow!\n"); + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* testSafeAddI32() +{ + int32_t out; + TASSERT( (SST_OS_SafeAddI32(INT32_MAX-1, 1, &out) == 1), "SafeAddI32 returned false when no overflow!\n"); + TASSERT( (out == INT32_MAX), "SafeAddI32 can't add without overflow!\n"); + TASSERT( (SST_OS_SafeAddI32(INT32_MAX-1, 2, &out) == 0), "SafeAddI32 returned true when overflow!\n"); + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* testSafeAddI64() +{ + int64_t out; + TASSERT( (SST_OS_SafeAddI64(INT64_MAX-1, 1, &out) == 1), "SafeAddI64 returned false when no overflow!\n"); + TASSERT( (out == INT64_MAX), "SafeAddI64 can't add without overflow!\n"); + TASSERT( (SST_OS_SafeAddI64(INT64_MAX-1, 2, &out) == 0), "SafeAddI64 returned true when overflow!\n"); + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* testSafeAddU8() +{ + uint8_t out; + TASSERT( (SST_OS_SafeAddU8(UINT8_MAX-1, 1, &out) == 1), "SafeAddU8 returned false when no overflow!\n"); + TASSERT( (out == UINT8_MAX), "SafeAddU8 can't add without overflow!\n"); + TASSERT( (SST_OS_SafeAddU8(UINT8_MAX-1, 2, &out) == 0), "SafeAddU8 returned true when overflow!\n"); + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* testSafeAddU16() +{ + uint16_t out; + TASSERT( (SST_OS_SafeAddU16(UINT16_MAX-1, 1, &out) == 1), "SafeAddU16 returned false when no overflow!\n"); + TASSERT( (out == UINT16_MAX), "SafeAddU16 can't add without overflow!\n"); + TASSERT( (SST_OS_SafeAddU16(UINT16_MAX-1, 2, &out) == 0), "SafeAddU16 returned true when overflow!\n"); + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* testSafeAddU32() +{ + uint32_t out; + TASSERT( (SST_OS_SafeAddU32(UINT32_MAX-1, 1, &out) == 1), "SafeAddU32 returned false when no overflow!\n"); + TASSERT( (out == UINT32_MAX), "SafeAddU32 can't add without overflow!\n"); + TASSERT( (SST_OS_SafeAddU32(UINT32_MAX, 2, &out) == 0), "SafeAddU32 returned true when overflow!\n"); + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* testSafeAddU64() +{ + uint64_t out; + TASSERT( (SST_OS_SafeAddU64(UINT64_MAX-1, 1, &out) == 1), "SafeAddU64 returned false when no overflow!\n"); + TASSERT( (out == UINT64_MAX), "SafeAddU64 can't add without overflow!\n"); + TASSERT( (SST_OS_SafeAddU64(UINT64_MAX-1, 2, &out) == 0), "SafeAddU64 returned true when overflow!\n"); + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* testSafeMultiplyU8() +{ + uint8_t a = UINT8_MAX - 1; + uint8_t b = 1; + uint8_t out; + TASSERT( (SST_OS_SafeMultiplyU8(a,b,&out) == 1), "SafeMultiplyU8 returned false when no overflow!\n"); + TASSERT( (out == UINT8_MAX - 1), "SafeMultiplyU8 can't multiply without overflow!\n"); + TASSERT( (SST_OS_SafeMultiplyU8(a,a,&out) == 0), "SafeMultiplyU8 returned true when overflow!\n"); + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* testSafeMultiplyU16() +{ + uint16_t a = UINT16_MAX - 1; + uint16_t b = 1; + uint16_t out; + TASSERT( (SST_OS_SafeMultiplyU16(a,b,&out) == 1), "SafeMultiplyU16 returned false when no overflow!\n"); + TASSERT( (out == UINT16_MAX - 1), "SafeMultiplyU16 can't multiply without overflow!\n"); + TASSERT( (SST_OS_SafeMultiplyU16(a,a,&out) == 0), "SafeMultiplyU16 returned true when overflow!\n"); + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* testSafeMultiplyU32() +{ + uint32_t a = UINT32_MAX - 1; + uint32_t b = 1; + uint32_t out; + TASSERT( (SST_OS_SafeMultiplyU32(a,b,&out) == 1), "SafeMultiplyU32 returned false when no overflow!\n"); + TASSERT( (out == UINT32_MAX - 1), "SafeMultiplyU32 can't multiply without overflow!\n"); + TASSERT( (SST_OS_SafeMultiplyU32(a,a,&out) == 0), "SafeMultiplyU32 returned true when overflow!\n"); + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* testSafeMultiplyU64() +{ + uint64_t a = UINT64_MAX; + uint64_t b = 1; + uint64_t out; + TASSERT( (SST_OS_SafeMultiplyU64(a,b,&out) == 1), "SafeMultiplyU64 returned false when no overflow!\n"); + TASSERT( (out == UINT64_MAX), "SafeMultiplyU64 can't multiply without overflow!\n"); + TASSERT( (SST_OS_SafeMultiplyU64(a,2,&out) == 0), "SafeMultiplyU64 returned true when overflow!\n"); + TASSERT( (SST_OS_SafeMultiplyU64(a,a,&out) == 0), "SafeMultiplyU64 returned true when overflow!\n"); + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* testSafeAddI8ToSizeT() +{ + size_t out; + + TASSERT( (SST_OS_SafeAddI8ToSizeT(1, SIZE_MAX-1, &out) == 1), "SafeAddI8ToSizeT returned false when no overflow!\n"); + TASSERT( (out == SIZE_MAX), "SafeAddI8ToSizeT can't add without overflow!\n"); + TASSERT( (SST_OS_SafeAddI8ToSizeT(2, SIZE_MAX-1, &out) == 0), "SafeAddI8ToSizeT returned true when overflow!\n"); + TASSERT( (SST_OS_SafeAddI8ToSizeT(-1, 0, &out) == 0), "SafeAddI8ToSizeT returned true when underflow!\n"); + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* testSafeAddI16ToSizeT() +{ + size_t out; + + TASSERT( (SST_OS_SafeAddI16ToSizeT(1, SIZE_MAX-1, &out) == 1), "SafeAddI16ToSizeT returned false when no overflow!\n"); + TASSERT( (out == SIZE_MAX), "SafeAddI16ToSizeT can't add without overflow!\n"); + TASSERT( (SST_OS_SafeAddI16ToSizeT(2, SIZE_MAX-1, &out) == 0), "SafeAddI16ToSizeT returned true when overflow!\n"); + TASSERT( (SST_OS_SafeAddI16ToSizeT(-1, 0, &out) == 0), "SafeAddI16ToSizeT returned true when underflow!\n"); + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* testSafeAddI32ToSizeT() +{ + size_t out; + + TASSERT( (SST_OS_SafeAddI32ToSizeT(1, SIZE_MAX-1, &out) == 1), "SafeAddI32ToSizeT returned false when no overflow!\n"); + TASSERT( (out == SIZE_MAX), "SafeAddI32ToSizeT can't add without overflow!\n"); + TASSERT( (SST_OS_SafeAddI32ToSizeT(2, SIZE_MAX-1, &out) == 0), "SafeAddI32ToSizeT returned true when overflow!\n"); + TASSERT( (SST_OS_SafeAddI32ToSizeT(-1, 0, &out) == 0), "SafeAddI32ToSizeT returned true when underflow!\n"); + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* testSafeAddI64ToSizeT() +{ + size_t out; + + TASSERT( (SST_OS_SafeAddI64ToSizeT(1, SIZE_MAX-1, &out) == 1), "SafeAddI64ToSizeT returned false when no overflow!\n"); + TASSERT( (out == SIZE_MAX), "SafeAddI64ToSizeT can't add without overflow!\n"); + TASSERT( (SST_OS_SafeAddI64ToSizeT(2, SIZE_MAX-1, &out) == 0), "SafeAddI64ToSizeT returned true when overflow!\n"); + TASSERT( (SST_OS_SafeAddI64ToSizeT(-1, 0, &out) == 0), "SafeAddI64ToSizeT returned true when underflow!\n"); + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* testSafeAddU8ToSizeT() +{ + size_t out; + + TASSERT( (SST_OS_SafeAddU8ToSizeT(1, SIZE_MAX-1, &out) == 1), "SafeAddU8ToSizeT returned false when no overflow!\n"); + TASSERT( (out == SIZE_MAX), "SafeAddU8ToSizeT can't add without overflow!\n"); + TASSERT( (SST_OS_SafeAddU8ToSizeT(2, SIZE_MAX-1, &out) == 0), "SafeAddU8ToSizeT returned true when overflow!\n"); + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* testSafeAddU16ToSizeT() +{ + size_t out; + + TASSERT( (SST_OS_SafeAddU16ToSizeT(1, SIZE_MAX-1, &out) == 1), "SafeAddU16ToSizeT returned false when no overflow!\n"); + TASSERT( (out == SIZE_MAX), "SafeAddU16ToSizeT can't add without overflow!\n"); + TASSERT( (SST_OS_SafeAddU16ToSizeT(2, SIZE_MAX-1, &out) == 0), "SafeAddU16ToSizeT returned true when overflow!\n"); + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* testSafeAddU32ToSizeT() +{ + size_t out; + + TASSERT( (SST_OS_SafeAddU32ToSizeT(1, SIZE_MAX-1, &out) == 1), "SafeAddU32ToSizeT returned false when no overflow!\n"); + TASSERT( (out == SIZE_MAX), "SafeAddU32ToSizeT can't add without overflow!\n"); + TASSERT( (SST_OS_SafeAddU32ToSizeT(2, SIZE_MAX-1, &out) == 0), "SafeAddU32ToSizeT returned true when overflow!\n"); + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* testSafeAddU64ToSizeT() +{ + size_t out; + + TASSERT( (SST_OS_SafeAddU64ToSizeT(1, SIZE_MAX-1, &out) == 1), "SafeAddU64ToSizeT returned false when no overflow!\n"); + TASSERT( (out == SIZE_MAX), "SafeAddU64ToSizeT can't add without overflow!\n"); + TASSERT( (SST_OS_SafeAddU64ToSizeT(2, SIZE_MAX-1, &out) == 0), "SafeAddU64ToSizeT returned true when overflow!\n"); + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* testSafeAddSizeTToSizeT() +{ + size_t out; + + TASSERT( (SST_OS_SafeAddSizeTToSizeT(1, SIZE_MAX-1, &out) == 1), "SafeAddSizeTToSizeT returned false when no overflow!\n"); + TASSERT( (out == SIZE_MAX), "SafeAddSizeTToSizeT can't add without overflow!\n"); + TASSERT( (SST_OS_SafeAddSizeTToSizeT(2, SIZE_MAX-1, &out) == 0), "SafeAddSizeTToSizeT returned true when overflow!\n"); + return ZTEST_SUCCESS; +} \ No newline at end of file diff --git a/ZTestSuite/Test-SST_Transform.cpp b/ZTestSuite/Test-SST_Transform.cpp new file mode 100644 index 0000000..5a14468 --- /dev/null +++ b/ZTestSuite/Test-SST_Transform.cpp @@ -0,0 +1,615 @@ +/* + Test-ZTransform.cpp +Author: Charles Lena <cmlena@762studios.com> +Created: 3/29/2012 + +Purpose: + +Tests to ensure that the math transform routines function accurately. +*/ + +#include "ZUnitTest.hpp" +#include <stdio.h> +#include <stdlib.h> +#include <climits> +#include <cfloat> +#include <math.h> +#include <cmath> +#include <SST/SST_Math.h> + +inline bool fpcomp(float typed_1, float typed_2, float tol = FLT_EPSILON) +{ + return (std::abs(typed_1 - typed_2) <= tol); +} +inline bool dpcomp(double typed_1, double typed_2, double tol = DBL_EPSILON) +{ + return (std::abs(typed_1 - typed_2) <= tol); +} +static const SST_Vec4f X_AXIS_3D = {{1.f,0.f,0.f,1.f}}; +static const SST_Vec4f Y_AXIS_3D = {{0.f,1.f,0.f,1.f}}; +static const SST_Vec4f Z_AXIS_3D = {{0.f,0.f,1.f,1.f}}; +static const SST_Vec4f UNIT_SQUARE[4] = { + {{0.f,0.f,1.f}}, + {{1.f,0.f,1.f}}, + {{1.f,1.f,1.f}}, + {{0.f,1.f,1.f}}, +}; +static const SST_Vec4f UNIT_CUBE[8] = { + {{0.f,0.f,0.f,1.f}}, + {{1.f,0.f,0.f,1.f}}, + {{1.f,1.f,0.f,1.f}}, + {{0.f,1.f,0.f,1.f}}, + {{0.f,0.f,1.f,1.f}}, + {{1.f,0.f,1.f,1.f}}, + {{1.f,1.f,1.f,1.f}}, + {{0.f,1.f,1.f,1.f}}, +}; +char msg[4096]; + +static const char* testSST_Math_Mat33fCreateIdentity(); +static const char* testSST_Math_Mat44fCreateIdentity(); +static const char* testSST_Math_Mat33fCreateTranslation(); +static const char* testSST_Math_Mat44fCreateTranslation(); +static const char* testSST_Math_Mat44fCreateEulerX(); +static const char* testSST_Math_Mat44fCreateEulerY(); +static const char* testSST_Math_Mat44fCreateEulerZ(); +static const char* testSST_Math_Mat44fCreateEulerXC(); +static const char* testSST_Math_Mat44fCreateEulerYC(); +static const char* testSST_Math_Mat44fCreateEulerZC(); +static const char* testSST_Math_Mat44fCreateShear(); +static const char* testSST_Math_Mat44fCreateFreeTransform(); +static const char* testSST_Math_Mat44fConvertQuaternion(); +static const char* testSST_Math_Mat44fCreateRotationFromQuaternion(); +static const char* testSST_Math_Mat44fCreateScale(); +static const char* testSST_Math_Mat44fCreateLookAt(); +static const char* testSST_Math_Mat44fCreateLookDir(); +static const char* testSST_Math_Mat33fCreateFromMat44f(); +static const char* testSST_Math_Mat44fCreatePerspective(); +static const char* testSST_Math_Mat44fCreateOrtho(); + +static const char* testSST_Math_Mat44dFromVec4d(); +static const char* testSST_Math_Mat44fFromVec4f(); +static const char* testSST_Math_Mat33dFromVec3d(); +static const char* testSST_Math_Mat33fFromVec3f(); + +//List of unit tests +ZUnitTest SST_Math_TransformUnitTests[] = +{ +{"testSST_Math_Mat33fCreateIdentity",testSST_Math_Mat33fCreateIdentity}, +{"testSST_Math_Mat44fCreateIdentity",testSST_Math_Mat44fCreateIdentity}, +{"testSST_Math_Mat33fCreateTranslation",testSST_Math_Mat33fCreateTranslation}, +{"testSST_Math_Mat44fCreateTranslation",testSST_Math_Mat44fCreateTranslation}, +{"testSST_Math_Mat44fCreateEulerX",testSST_Math_Mat44fCreateEulerX}, +{"testSST_Math_Mat44fCreateEulerY",testSST_Math_Mat44fCreateEulerY}, +{"testSST_Math_Mat44fCreateEulerZ",testSST_Math_Mat44fCreateEulerZ}, +{"testSST_Math_Mat44fCreateEulerXC",testSST_Math_Mat44fCreateEulerXC}, +{"testSST_Math_Mat44fCreateEulerYC",testSST_Math_Mat44fCreateEulerYC}, +{"testSST_Math_Mat44fCreateEulerZC",testSST_Math_Mat44fCreateEulerZC}, +{"testSST_Math_Mat44fCreateScale",testSST_Math_Mat44fCreateScale}, +{"testSST_Math_Mat44fCreateShear",testSST_Math_Mat44fCreateShear}, +{"testSST_Math_Mat44fCreateFreeTransform",testSST_Math_Mat44fCreateFreeTransform}, +{"testSST_Math_Mat44fConvertQuaternion",testSST_Math_Mat44fConvertQuaternion}, +{"testSST_Math_Mat44fCreateRotationFromQuaternion",testSST_Math_Mat44fCreateRotationFromQuaternion}, +{"testSST_Math_Mat44fCreateLookAt",testSST_Math_Mat44fCreateLookAt}, +{"testSST_Math_Mat44fCreateLookDir",testSST_Math_Mat44fCreateLookDir}, +{"testSST_Math_Mat33fCreateFromMat44f",testSST_Math_Mat33fCreateFromMat44f}, +{"testSST_Math_Mat44fCreatePerspective",testSST_Math_Mat44fCreatePerspective}, +{"testSST_Math_Mat44fCreateOrtho",testSST_Math_Mat44fCreateOrtho}, +{"testSST_Math_Mat44dFromVec4d", testSST_Math_Mat44dFromVec4d}, +{"testSST_Math_Mat44fFromVec4f", testSST_Math_Mat44fFromVec4f}, +{"testSST_Math_Mat33dFromVec3d", testSST_Math_Mat33dFromVec3d}, +{"testSST_Math_Mat33fFromVec3f", testSST_Math_Mat33fFromVec3f}, +}; + +DECLARE_ZTESTBLOCK(SST_Math_Transform); + +// ======================================= +/* +void SST_Math_Mat33fCreateIdentity(SST_Mat33f* Mat); +void SST_Math_Mat44fCreateIdentity(SST_Mat44f* Mat); +void SST_Math_Mat33fCreateTranslation(SST_Mat33f* Mat, const float x, const float y); +void SST_Math_Mat44fCreateTranslation(SST_Mat44f* Mat, const float x, const float y, const float z); +void SST_Math_Mat44fCreateEulerX(SST_Mat44f* Mat, const float angle); +void SST_Math_Mat44fCreateEulerY(SST_Mat44f* Mat, const float angle); +void SST_Math_Mat44fCreateEulerZ(SST_Mat44f* Mat, const float angle); +void SST_Math_Mat44fCreateEulerXC(SST_Mat44f* Mat, const float angle); +void SST_Math_Mat44fCreateEulerYC(SST_Mat44f* Mat, const float angle); +void SST_Math_Mat44fCreateEulerZC(SST_Mat44f* Mat, const float angle); +void SST_Math_Mat44fCreateShear(SST_Mat44f* Mat, const float x_in_y, const float x_in_z, const float y_in_x, const float y_in_z, const float z_in_x, const float z_in_y); +void SST_Math_Mat44fCreateFreeTransform(SST_Mat44f* Mat,const float scale_x, const float scale_y, const float scale_z, const float x_in_y, const float x_in_z, const float y_in_x, const float y_in_z, const float z_in_x, const float z_in_y); +void SST_Math_Mat44fConvertQuaternion(SST_Mat44f* Mat,const SST_Vec4f* q); +void SST_Math_Mat44fCreateRotationFromQuaternion(SST_Mat44f* Mat,const SST_Vec4f* q); +void SST_Math_Mat44fCreateScale(SST_Mat44f* Mat, const float scale_x, const float scale_y, const float scale_z); +void SST_Math_Mat44fCreateLookAt(SST_Mat44f* Mat, const SST_Vec3f* eye,const SST_Vec3f* at, const SST_Vec3f* up); +void SST_Math_Mat44fCreateLookDir(SST_Mat44f* Mat, const SST_Vec3f* eye,const SST_Vec3f* dir, const SST_Vec3f* up); +void SST_Math_Mat33fCreateFromMat44f(const SST_Mat44f* Mat44, SST_Mat33f* Mat33); +void SST_Math_Mat44fCreatePerspective(SST_Mat44f* Mat, const float FOV_in_y, const float aspect_in_x, const float zNear, const float zFar); +void SST_Math_Mat44fCreateOrtho(SST_Mat44f* Mat, const float left, const float right, const float bottom, const float top, const float nearVal, const float farVal); +*/ +static const char* testSST_Math_Mat33fCreateIdentity(){ + SST_Mat33f A; + SST_Math_Mat33fCreateIdentity(&A); + const int N = 3; + for(int i = 0; i < N; i++) + for(int j = 0; j < N; j++) + { + if(i==j) { TASSERT(A.v[i+N*j] == 1.f, "Diagonal was not 1!"); } + else { TASSERT(A.v[i+N*j] == 0.f, "Off-diagonal was not 0!"); } + } + + return ZTEST_SUCCESS; +} +static const char* testSST_Math_Mat44fCreateIdentity(){ + SST_Mat44f A; + SST_Math_Mat44fCreateIdentity(&A); + const int N = 4; + for(int i = 0; i < N; i++) + for(int j = 0; j < N; j++) + { + if(i==j) { TASSERT(A.v[i+N*j] == 1.f, "Diagonal was not 1!"); } + else { TASSERT(A.v[i+N*j] == 0.f, "Off-diagonal was not 0!"); } + } + return ZTEST_SUCCESS; +} +static const char* testSST_Math_Mat33fCreateTranslation(){ + SST_Mat33f A; + SST_Vec3f r,p; + const float x = (float)rand(); + const float y = (float)rand(); + r.x = 0; + r.y = 0; + r.z = 1.f; + + SST_Math_Mat33fCreateTranslation(&A,x,y); + SST_Math_Mat33fMultiplyVector(&A,&r,&p); + TASSERT(fpcomp(p.x,x,1.e-7F),"x component of p incorrect!"); + TASSERT(fpcomp(p.y,y,1.e-7F),"y component of p incorrect!"); + TASSERT(fpcomp(p.z,1.f,1.e-7F),"z(inactive) component of p incorrect!"); + + SST_Math_Mat33fCreateTranslation(&A,-x,-y); + SST_Math_Mat33fMultiplyVector(&A,&p,&r); + TASSERT(fpcomp(r.x,0.f,1.0e-7F),"x component of r incorrect!"); + TASSERT(fpcomp(r.y,0.f,1.0e-7F),"y component of r incorrect!"); + TASSERT(fpcomp(r.z,1.f,1.0e-7F),"z(inactive) component of r incorrect!"); + + return ZTEST_SUCCESS; +} +static const char* testSST_Math_Mat44fCreateTranslation(){ + SST_Mat44f A; + SST_Vec4f r,p; + const float x = (float)rand(); + const float y = (float)rand(); + const float z = (float)rand(); + const float w = (float)rand(); + r.x = 0.f; + r.y = 0.f; + r.z = 0.f; + r.w = 1.f; + + p.w = w; + + SST_Math_Mat44fCreateTranslation(&A,x,y,z); + SST_Math_Mat44fMultiplyVector(&A,&r,&p); + TASSERT(fpcomp(p.x,x,1.0e-7F),"x component of p incorrect!"); + TASSERT(fpcomp(p.y,y,1.0e-7F),"y component of p incorrect!"); + TASSERT(fpcomp(p.z,z,1.0e-7F),"z component of p incorrect!"); + TASSERT(fpcomp(p.w,1.f,1.0e-7F),"w(inactive) component of p incorrect!"); + + SST_Math_Mat44fCreateTranslation(&A,-x,-y,-z); + SST_Math_Mat44fMultiplyVector(&A,&p,&r); + TASSERT(fpcomp(r.x,0.f,1.0e-7F),"x component of r incorrect!"); + TASSERT(fpcomp(r.y,0.f,1.0e-7F),"y component of r incorrect!"); + TASSERT(fpcomp(r.z,0.f,1.0e-7F),"z(inactive) component of r incorrect!"); + TASSERT(fpcomp(r.w,1.f,1.0e-7F),"w(inactive) component of r incorrect!"); + + return ZTEST_SUCCESS; +} +static const char* testSST_Math_Mat44fCreateEulerX(){ + SST_Mat44f R; + SST_Vec4f out; + SST_Math_Mat44fCreateEulerX(&R,(float)M_PI_2); + // Rotate X-axis around X-axis 90 degrees + SST_Math_Mat44fMultiplyVector(&R,&X_AXIS_3D,&out); + TASSERT(fpcomp(out.v[0],X_AXIS_3D.x,1.0e-7F),"x-axis - x component of out incorrect!"); + TASSERT(fpcomp(out.v[1],X_AXIS_3D.y,1.0e-7F),"x-axis - y component of out incorrect!"); + TASSERT(fpcomp(out.v[2],X_AXIS_3D.z,1.0e-7F),"x-axis - z component of out incorrect!"); + TASSERT(fpcomp(out.v[3],X_AXIS_3D.w,1.0e-7F),"x-axis - w component of out incorrect!"); + + // Rotate Y-axis around X-axis 90 degrees + SST_Math_Mat44fMultiplyVector(&R,&Y_AXIS_3D,&out); + TASSERT(fpcomp(out.v[0],0.f,1.0e-7F),"y-axis - x component of out incorrect!"); + TASSERT(fpcomp(out.v[1],0.f,1.0e-7F),"y-axis - y component of out incorrect!"); + TASSERT(fpcomp(out.v[2],1.f,1.0e-7F),"y-axis - z component of out incorrect!"); + TASSERT(fpcomp(out.v[3],1.f,1.0e-7F),"y-axis - w component of out incorrect!"); + + // Rotate Z-axis around X-axis 90 degrees gives + SST_Math_Mat44fMultiplyVector(&R,&Z_AXIS_3D,&out); + TASSERT(fpcomp(out.v[0], 0.f,1.0e-7F),"y-axis - x component of out incorrect!"); + TASSERT(fpcomp(out.v[1],-1.f,1.0e-7F),"y-axis - y component of out incorrect!"); + TASSERT(fpcomp(out.v[2], 0.f,1.0e-7F),"y-axis - z component of out incorrect!"); + TASSERT(fpcomp(out.v[3], 1.f,1.0e-7F),"y-axis - w component of out incorrect!"); + + return ZTEST_SUCCESS; +} +static const char* testSST_Math_Mat44fCreateEulerY(){ + SST_Mat44f R; + SST_Vec4f out; + SST_Math_Mat44fCreateEulerY(&R,(float)M_PI_2); + // Rotate Y-axis around Y-axis 90 degrees + SST_Math_Mat44fMultiplyVector(&R,&Y_AXIS_3D,&out); + TASSERT(fpcomp(out.v[0],Y_AXIS_3D.x,1.0e-7F),"y-axis - x component of out incorrect!"); + TASSERT(fpcomp(out.v[1],Y_AXIS_3D.y,1.0e-7F),"y-axis - y component of out incorrect!"); + TASSERT(fpcomp(out.v[2],Y_AXIS_3D.z,1.0e-7F),"y-axis - z component of out incorrect!"); + TASSERT(fpcomp(out.v[3],Y_AXIS_3D.w,1.0e-7F),"y-axis - w component of out incorrect!"); + + // Rotate X-axis around Y-axis 90 degrees + SST_Math_Mat44fMultiplyVector(&R,&X_AXIS_3D,&out); + TASSERT(fpcomp(out.v[0],0.f,1.0e-7F),"x-axis - x component of out incorrect!"); + TASSERT(fpcomp(out.v[1],0.f,1.0e-7F),"x-axis - y component of out incorrect!"); + TASSERT(fpcomp(out.v[2],-1.f,1.0e-7F),"x-axis - z component of out incorrect!"); + TASSERT(fpcomp(out.v[3],1.f,1.0e-7F),"x-axis - w component of out incorrect!"); + + // Rotate Z-axis around Y-axis 90 degrees gives + SST_Math_Mat44fMultiplyVector(&R,&Z_AXIS_3D,&out); + TASSERT(fpcomp(out.v[0], 1.f,1.0e-7F),"z-axis - x component of out incorrect!"); + TASSERT(fpcomp(out.v[1], 0.f,1.0e-7F),"z-axis - y component of out incorrect!"); + TASSERT(fpcomp(out.v[2], 0.f,1.0e-7F),"z-axis - z component of out incorrect!"); + TASSERT(fpcomp(out.v[3], 1.f,1.0e-7F),"z-axis - w component of out incorrect!"); + return ZTEST_SUCCESS; +} +static const char* testSST_Math_Mat44fCreateEulerZ(){ + SST_Mat44f R; + SST_Vec4f out; + SST_Math_Mat44fCreateEulerZ(&R,(float)M_PI_2); + // Rotate Z-axis around Z-axis 90 degrees + SST_Math_Mat44fMultiplyVector(&R,&Z_AXIS_3D,&out); + TASSERT(fpcomp(out.v[0],Z_AXIS_3D.x,1.0e-7F),"z-axis - x component of out incorrect!"); + TASSERT(fpcomp(out.v[1],Z_AXIS_3D.y,1.0e-7F),"z-axis - y component of out incorrect!"); + TASSERT(fpcomp(out.v[2],Z_AXIS_3D.z,1.0e-7F),"z-axis - z component of out incorrect!"); + TASSERT(fpcomp(out.v[3],Z_AXIS_3D.w,1.0e-7F),"z-axis - w component of out incorrect!"); + + // Rotate Y-axis around Z-axis 90 degrees + SST_Math_Mat44fMultiplyVector(&R,&Y_AXIS_3D,&out); + TASSERT(fpcomp(out.v[0],-1.f,1.0e-7F),"y-axis - x component of out incorrect!"); + TASSERT(fpcomp(out.v[1],0.f,1.0e-7F),"y-axis - y component of out incorrect!"); + TASSERT(fpcomp(out.v[2],0.f,1.0e-7F),"y-axis - z component of out incorrect!"); + TASSERT(fpcomp(out.v[3],1.f,1.0e-7F),"y-axis - w component of out incorrect!"); + + // Rotate X-axis around Z-axis 90 degrees gives + SST_Math_Mat44fMultiplyVector(&R,&X_AXIS_3D,&out); + TASSERT(fpcomp(out.v[0], 0.f,1.0e-7F),"x-axis - x component of out incorrect!"); + TASSERT(fpcomp(out.v[1], 1.f,1.0e-7F),"x-axis - y component of out incorrect!"); + TASSERT(fpcomp(out.v[2], 0.f,1.0e-7F),"x-axis - z component of out incorrect!"); + TASSERT(fpcomp(out.v[3], 1.f,1.0e-7F),"x-axis - w component of out incorrect!"); + return ZTEST_SUCCESS; +} +static const char* testSST_Math_Mat44fCreateScale(){ + SST_Mat44f A; + SST_Math_Mat44fCreateScale(&A,.3333333333f,1.f,2.f); + SST_Vec4f x,r; + x.x = 3.f; + x.y = 1.f; + x.z = .5f; + x.w = 1.f; + + SST_Math_Mat44fMultiplyVector(&A,&x,&r); + + TASSERT(fpcomp(r.v[0],1.f,1.0e-7F),"x Component incorrect! (should be 1)"); + TASSERT(fpcomp(r.v[1],1.f,1.0e-7F),"y Component incorrect! (should be 1)"); + TASSERT(fpcomp(r.v[2],1.f,1.0e-7F),"z Component incorrect! (should be 1)"); + TASSERT(fpcomp(r.v[3],1.f,1.0e-7F),"w Component incorrect! (should be 1)"); + + return ZTEST_SUCCESS; +} +static const char* testSST_Math_Mat44fCreateEulerXC(){ + SST_Mat44f R; + SST_Vec4f out; + SST_Math_Mat44fCreateIdentity(&R); + SST_Math_Mat44fCreateEulerXC(&R,(float)M_PI_2); + // Rotate X-axis around X-axis 90 degrees + SST_Math_Mat44fMultiplyVector(&R,&X_AXIS_3D,&out); + TASSERT(fpcomp(out.v[0],X_AXIS_3D.x,1.0e-7F),"x-axis - x component of out incorrect!"); + TASSERT(fpcomp(out.v[1],X_AXIS_3D.y,1.0e-7F),"x-axis - y component of out incorrect!"); + TASSERT(fpcomp(out.v[2],X_AXIS_3D.z,1.0e-7F),"x-axis - z component of out incorrect!"); + TASSERT(fpcomp(out.v[3],X_AXIS_3D.w,1.0e-7F),"x-axis - w component of out incorrect!"); + + // Rotate Y-axis around X-axis 90 degrees + SST_Math_Mat44fMultiplyVector(&R,&Y_AXIS_3D,&out); + TASSERT(fpcomp(out.v[0],0.f,1.0e-7F),"y-axis - x component of out incorrect!"); + TASSERT(fpcomp(out.v[1],0.f,1.0e-7F),"y-axis - y component of out incorrect!"); + TASSERT(fpcomp(out.v[2],1.f,1.0e-7F),"y-axis - z component of out incorrect!"); + TASSERT(fpcomp(out.v[3],1.f,1.0e-7F),"y-axis - w component of out incorrect!"); + + // Rotate Z-axis around X-axis 90 degrees gives + SST_Math_Mat44fMultiplyVector(&R,&Z_AXIS_3D,&out); + TASSERT(fpcomp(out.v[0], 0.f,1.0e-7F),"Z-axis - x component of out incorrect!"); + TASSERT(fpcomp(out.v[1],-1.f,1.0e-7F),"z-axis - y component of out incorrect!"); + TASSERT(fpcomp(out.v[2], 0.f,1.0e-7F),"z-axis - z component of out incorrect!"); + TASSERT(fpcomp(out.v[3], 1.f,1.0e-7F),"z-axis - w component of out incorrect!"); + + return ZTEST_SUCCESS; +} +static const char* testSST_Math_Mat44fCreateEulerYC(){ + SST_Mat44f R; + SST_Vec4f out; + SST_Math_Mat44fCreateIdentity(&R); + SST_Math_Mat44fCreateEulerYC(&R,(float)M_PI_2); + // Rotate Y-axis around Y-axis 90 degrees + SST_Math_Mat44fMultiplyVector(&R,&Y_AXIS_3D,&out); + TASSERT(fpcomp(out.v[0],Y_AXIS_3D.x,1.0e-7F),"y-axis - x component of out incorrect!"); + TASSERT(fpcomp(out.v[1],Y_AXIS_3D.y,1.0e-7F),"y-axis - y component of out incorrect!"); + TASSERT(fpcomp(out.v[2],Y_AXIS_3D.z,1.0e-7F),"y-axis - z component of out incorrect!"); + TASSERT(fpcomp(out.v[3],Y_AXIS_3D.w,1.0e-7F),"y-axis - w component of out incorrect!"); + + // Rotate X-axis around Y-axis 90 degrees + SST_Math_Mat44fMultiplyVector(&R,&X_AXIS_3D,&out); + TASSERT(fpcomp(out.v[0],0.f,1.0e-7F),"x-axis - x component of out incorrect!"); + TASSERT(fpcomp(out.v[1],0.f,1.0e-7F),"x-axis - y component of out incorrect!"); + TASSERT(fpcomp(out.v[2],-1.f,1.0e-7F),"x-axis - z component of out incorrect!"); + TASSERT(fpcomp(out.v[3],1.f,1.0e-7F),"x-axis - w component of out incorrect!"); + + // Rotate Z-axis around Y-axis 90 degrees gives + SST_Math_Mat44fMultiplyVector(&R,&Z_AXIS_3D,&out); + TASSERT(fpcomp(out.v[0], 1.f,1.0e-7F),"z-axis - x component of out incorrect!"); + TASSERT(fpcomp(out.v[1], 0.f,1.0e-7F),"z-axis - y component of out incorrect!"); + TASSERT(fpcomp(out.v[2], 0.f,1.0e-7F),"z-axis - z component of out incorrect!"); + TASSERT(fpcomp(out.v[3], 1.f,1.0e-7F),"z-axis - w component of out incorrect!"); + return ZTEST_SUCCESS; +} +static const char* testSST_Math_Mat44fCreateEulerZC(){ + SST_Mat44f R; + SST_Vec4f out; + SST_Math_Mat44fCreateIdentity(&R); + SST_Math_Mat44fCreateEulerZC(&R,(float)M_PI_2); + // Rotate Z-axis around Z-axis 90 degrees + SST_Math_Mat44fMultiplyVector(&R,&Z_AXIS_3D,&out); + TASSERT(fpcomp(out.v[0],Z_AXIS_3D.x,1.0e-7F),"z-axis - x component of out incorrect!"); + TASSERT(fpcomp(out.v[1],Z_AXIS_3D.y,1.0e-7F),"z-axis - y component of out incorrect!"); + TASSERT(fpcomp(out.v[2],Z_AXIS_3D.z,1.0e-7F),"z-axis - z component of out incorrect!"); + TASSERT(fpcomp(out.v[3],Z_AXIS_3D.w,1.0e-7F),"z-axis - w component of out incorrect!"); + + // Rotate Y-axis around Z-axis 90 degrees + SST_Math_Mat44fMultiplyVector(&R,&Y_AXIS_3D,&out); + TASSERT(fpcomp(out.v[0],-1.f,1.0e-7F),"y-axis - x component of out incorrect!"); + TASSERT(fpcomp(out.v[1],0.f,1.0e-7F),"y-axis - y component of out incorrect!"); + TASSERT(fpcomp(out.v[2],0.f,1.0e-7F),"y-axis - z component of out incorrect!"); + TASSERT(fpcomp(out.v[3],1.f,1.0e-7F),"y-axis - w component of out incorrect!"); + + // Rotate X-axis around Z-axis 90 degrees gives + SST_Math_Mat44fMultiplyVector(&R,&X_AXIS_3D,&out); + TASSERT(fpcomp(out.v[0], 0.f,1.0e-7F),"x-axis - x component of out incorrect!"); + TASSERT(fpcomp(out.v[1], 1.f,1.0e-7F),"x-axis - y component of out incorrect!"); + TASSERT(fpcomp(out.v[2], 0.f,1.0e-7F),"x-axis - z component of out incorrect!"); + TASSERT(fpcomp(out.v[3], 1.f,1.0e-7F),"x-axis - w component of out incorrect!"); + return ZTEST_SUCCESS; +} +static const char* testSST_Math_Mat44fCreateShear(){ + SST_Mat44f R; + SST_Vec4f out[8]; + SST_Math_Mat44fCreateShear(&R,2.f,0.f,0.f,0.f,0.f,0.f); + + for(int i = 0; i < 8; i++) + { + SST_Math_Mat44fMultiplyVector(&R,&UNIT_CUBE[i],&out[i]); + sprintf(msg,"(%5.3f,%5.3f,%5.3f,%5.3f) was not sheared by x+=2y (i=%d)",UNIT_CUBE[i].x,UNIT_CUBE[i].y,UNIT_CUBE[i].z,UNIT_CUBE[i].w,i); + TASSERT(fpcomp(out[i].x,UNIT_CUBE[i].x+UNIT_CUBE[i].y*2.f,1e-7F),msg); + TASSERT(fpcomp(out[i].y,UNIT_CUBE[i].y+UNIT_CUBE[i].y*0.f,1e-7F),msg); + TASSERT(fpcomp(out[i].z,UNIT_CUBE[i].z+UNIT_CUBE[i].y*0.f,1e-7F),msg); + TASSERT(fpcomp(out[i].w,UNIT_CUBE[i].w+UNIT_CUBE[i].y*0.f,1e-7F),msg); + } + /* if != 0, then we're shearing */ + float x_in_y = 2.f; + float x_in_z = 2.f; + float y_in_x = 2.f; + float y_in_z = 0.f; + float z_in_x = 1.f; + float z_in_y = 0.f; + + /* these will be used in the free transform */ + float scale_x = .333333333f; + float scale_y = 1.f; + float scale_z = 2.f; + + SST_Math_Mat44fCreateFreeTransform(&R,scale_x,scale_y,scale_z,x_in_y,x_in_z,y_in_x,y_in_z,z_in_x,z_in_y); + for(int i = 0; i < 8; i++) + { + SST_Math_Mat44fMultiplyVector(&R,&UNIT_CUBE[i],&out[i]); + sprintf(msg,"(%5.3f,%5.3f,%5.3f,%5.3f) was not sheared by x = %5.3fx+%5.3fy+%5.3fz (i=%d)",UNIT_CUBE[i].x,UNIT_CUBE[i].y,UNIT_CUBE[i].z,UNIT_CUBE[i].w,scale_x,x_in_y,x_in_z,i); + TASSERT(fpcomp(out[i].x,UNIT_CUBE[i].x*scale_x+UNIT_CUBE[i].y*x_in_y + UNIT_CUBE[i].z*x_in_z ,1e-7F),msg); + sprintf(msg,"(%5.3f,%5.3f,%5.3f,%5.3f) was not sheared by x = %5.3fx+%5.3fy+%5.3fz (i=%d)",UNIT_CUBE[i].x,UNIT_CUBE[i].y,UNIT_CUBE[i].z,UNIT_CUBE[i].w,y_in_x,scale_y,y_in_z,i); + TASSERT(fpcomp(out[i].y,UNIT_CUBE[i].x*y_in_x +UNIT_CUBE[i].y*scale_y + UNIT_CUBE[i].z*y_in_z ,1e-7F),msg); + sprintf(msg,"(%5.3f,%5.3f,%5.3f,%5.3f) was not sheared by x = %5.3fx+%5.3fy+%5.3fz (i=%d)",UNIT_CUBE[i].x,UNIT_CUBE[i].y,UNIT_CUBE[i].z,UNIT_CUBE[i].w,z_in_x,z_in_y,scale_z,i); + TASSERT(fpcomp(out[i].z,UNIT_CUBE[i].x*z_in_x +UNIT_CUBE[i].y*z_in_y + UNIT_CUBE[i].z*scale_z,1e-7F),msg); + sprintf(msg,"(%5.3f,%5.3f,%5.3f,%5.3f) was not sheared by w = w (i=%d)",UNIT_CUBE[i].x,UNIT_CUBE[i].y,UNIT_CUBE[i].z,UNIT_CUBE[i].w,i); + TASSERT(fpcomp(out[i].w,UNIT_CUBE[i].w,1e-7F),msg); + } + return ZTEST_SUCCESS; +} +static const char* testSST_Math_Mat44fCreateFreeTransform(){ + SST_Mat44f R; + SST_Vec4f out[8]; + /* if != 0, then we're shearing */ + float x_in_y = 2.f; + float x_in_z = 2.f; + float y_in_x = 2.f; + float y_in_z = 0.f; + float z_in_x = 1.f; + float z_in_y = 0.f; + + /* these will be used in the free transform */ + float scale_x = 1.f; + float scale_y = 1.f; + float scale_z = 1.f; + + SST_Math_Mat44fCreateFreeTransform(&R,scale_x,scale_y,scale_z,x_in_y,x_in_z,y_in_x,y_in_z,z_in_x,z_in_y); + for(int i = 0; i < 8; i++) + { + SST_Math_Mat44fMultiplyVector(&R,&UNIT_CUBE[i],&out[i]); + sprintf(msg,"(%5.3f,%5.3f,%5.3f,%5.3f) was not sheared by x = %5.3fx+%5.3fy+%5.3fz (i=%d)",UNIT_CUBE[i].x,UNIT_CUBE[i].y,UNIT_CUBE[i].z,UNIT_CUBE[i].w,scale_x,x_in_y,x_in_z,i); + TASSERT(fpcomp(out[i].x,UNIT_CUBE[i].x*scale_x+UNIT_CUBE[i].y*x_in_y + UNIT_CUBE[i].z*x_in_z ,1e-7F),msg); + sprintf(msg,"(%5.3f,%5.3f,%5.3f,%5.3f) was not sheared by x = %5.3fx+%5.3fy+%5.3fz (i=%d)",UNIT_CUBE[i].x,UNIT_CUBE[i].y,UNIT_CUBE[i].z,UNIT_CUBE[i].w,y_in_x,scale_y,y_in_z,i); + TASSERT(fpcomp(out[i].y,UNIT_CUBE[i].x*y_in_x +UNIT_CUBE[i].y*scale_y + UNIT_CUBE[i].z*y_in_z ,1e-7F),msg); + sprintf(msg,"(%5.3f,%5.3f,%5.3f,%5.3f) was not sheared by x = %5.3fx+%5.3fy+%5.3fz (i=%d)",UNIT_CUBE[i].x,UNIT_CUBE[i].y,UNIT_CUBE[i].z,UNIT_CUBE[i].w,z_in_x,z_in_y,scale_z,i); + TASSERT(fpcomp(out[i].z,UNIT_CUBE[i].x*z_in_x +UNIT_CUBE[i].y*z_in_y + UNIT_CUBE[i].z*scale_z,1e-7F),msg); + sprintf(msg,"(%5.3f,%5.3f,%5.3f,%5.3f) was not sheared by w = w (i=%d)",UNIT_CUBE[i].x,UNIT_CUBE[i].y,UNIT_CUBE[i].z,UNIT_CUBE[i].w,i); + TASSERT(fpcomp(out[i].w,UNIT_CUBE[i].w,1e-7F),msg); + } + return ZTEST_SUCCESS; +} +static const char* testSST_Math_Mat44dFromVec4d(){ + SST_Mat44d A; + SST_Vec4d tits; + SST_Vec4d leet; + + /* TITS! */ + tits.v[0] = 7.0; + tits.v[1] = 1.0; + tits.v[2] = 7.0; + tits.v[3] = 5.0; + + /* LEET! */ + leet.v[0] = 1.0; + leet.v[1] = 3.0; + leet.v[2] = 3.0; + leet.v[3] = 7.0; + + for(int col=0; col < 4; col++){ + /* leet */ + A.v[0+col*4] = leet.x; + A.v[1+col*4] = leet.y; + A.v[2+col*4] = leet.z; + A.v[3+col*4] = leet.w; + SST_Math_Mat44dFromVec4d(&A,&tits,col); + TASSERT(A.v[0+col*4] == tits.x, "x component failed in one of the iterations"); + TASSERT(A.v[1+col*4] == tits.y, "y component failed in one of the iterations"); + TASSERT(A.v[2+col*4] == tits.z, "z component failed in one of the iterations"); + TASSERT(A.v[3+col*4] == tits.w, "w component failed in one of the iterations"); + } + + return ZTEST_SUCCESS; +} +static const char* testSST_Math_Mat44fFromVec4f(){ + SST_Mat44f A; + SST_Vec4f tits; + SST_Vec4f leet; + + /* TITS! */ + tits.v[0] = 7.0f; + tits.v[1] = 1.0f; + tits.v[2] = 7.0f; + tits.v[3] = 5.0f; + + /* LEET! */ + leet.v[0] = 1.0f; + leet.v[1] = 3.0f; + leet.v[2] = 3.0f; + leet.v[3] = 7.0f; + + for(int col=0; col < 4; col++){ + /* leet */ + A.v[0+col*4] = leet.x; + A.v[1+col*4] = leet.y; + A.v[2+col*4] = leet.z; + A.v[3+col*4] = leet.w; + SST_Math_Mat44fFromVec4f(&A,&tits,col); + TASSERT(A.v[0+col*4] == tits.x, "x component failed in one of the iterations"); + TASSERT(A.v[1+col*4] == tits.y, "y component failed in one of the iterations"); + TASSERT(A.v[2+col*4] == tits.z, "z component failed in one of the iterations"); + TASSERT(A.v[3+col*4] == tits.w, "w component failed in one of the iterations"); + } + + return ZTEST_SUCCESS; +} +static const char* testSST_Math_Mat33dFromVec3d(){ + SST_Mat33d A; + SST_Vec3d tits; + SST_Vec3d leet; + + /* TITS! */ + tits.v[0] = 7.0; + tits.v[1] = 1.0; + tits.v[2] = 7.0; + + /* LEET! */ + leet.v[0] = 1.0; + leet.v[1] = 3.0; + leet.v[2] = 3.0; + + for(int col=0; col < 3; col++){ + /* leet */ + A.v[0+col*3] = leet.x; + A.v[1+col*3] = leet.y; + A.v[2+col*3] = leet.z; + SST_Math_Mat33dFromVec3d(&A,&tits,col); + TASSERT(A.v[0+col*3] == tits.x, "x component failed in one of the iterations"); + TASSERT(A.v[1+col*3] == tits.y, "y component failed in one of the iterations"); + TASSERT(A.v[2+col*3] == tits.z, "z component failed in one of the iterations"); + } + + + return ZTEST_SUCCESS; +} +static const char* testSST_Math_Mat33fFromVec3f(){ + SST_Mat33f A; + SST_Vec3f tits; + SST_Vec3f leet; + + /* TITS! */ + tits.v[0] = 7.0f; + tits.v[1] = 1.0f; + tits.v[2] = 7.0f; + + /* LEET! */ + leet.v[0] = 1.0f; + leet.v[1] = 3.0f; + leet.v[2] = 3.0f; + + for(int col=0; col < 3; col++){ + /* leet */ + A.v[0+col*3] = leet.x; + A.v[1+col*3] = leet.y; + A.v[2+col*3] = leet.z; + SST_Math_Mat33fFromVec3f(&A,&tits,col); + TASSERT(A.v[0+col*3] == tits.x, "x component failed in one of the iterations"); + TASSERT(A.v[1+col*3] == tits.y, "y component failed in one of the iterations"); + TASSERT(A.v[2+col*3] == tits.z, "z component failed in one of the iterations"); + } + + return ZTEST_SUCCESS; +} +#if SST_COMPILER == SST_COMPILER_MSVC +#pragma warning(push) +#pragma warning(disable:4127) +#endif +static const char* testSST_Math_Mat44fConvertQuaternion(){ + TASSERT(false,"Test Not Implemented Yet!"); + return ZTEST_SUCCESS; +} +static const char* testSST_Math_Mat44fCreateRotationFromQuaternion(){ + TASSERT(false,"Test Not Implemented Yet!"); + return ZTEST_SUCCESS; +} + +static const char* testSST_Math_Mat44fCreateLookAt(){ + TASSERT(false,"Test Not Implemented Yet!"); + return ZTEST_SUCCESS; +} +static const char* testSST_Math_Mat44fCreateLookDir(){ + TASSERT(false,"Test Not Implemented Yet!"); + return ZTEST_SUCCESS; +} +static const char* testSST_Math_Mat33fCreateFromMat44f(){ + TASSERT(false,"Test Not Implemented Yet!"); + return ZTEST_SUCCESS; +} +static const char* testSST_Math_Mat44fCreatePerspective(){ + TASSERT(false,"Test Not Implemented Yet!"); + return ZTEST_SUCCESS; +} +static const char* testSST_Math_Mat44fCreateOrtho(){ + TASSERT(false,"Test Not Implemented Yet!"); + return ZTEST_SUCCESS; +} +#if SST_COMPILER == SST_COMPILER_MSVC +#pragma warning(pop) +#endif diff --git a/ZTestSuite/Test-SST_Vec2d.cpp b/ZTestSuite/Test-SST_Vec2d.cpp new file mode 100644 index 0000000..7e6d48c --- /dev/null +++ b/ZTestSuite/Test-SST_Vec2d.cpp @@ -0,0 +1,749 @@ +/* + AUTOMATICALLY GENERATED FILE - DO NOT EDIT! + Please change MatrixNxN.py and re-run it +*/ +/* Generated with ./VectorN.py n = 2, TYPE = double */ + +#include "ZUnitTest.hpp" +#include <float.h> +#include <math.h> +#include <stdlib.h> +#include <stdio.h> +#include <SST/SST_Vec2.h> + + + + +static const char* testSST_Math_Vec2dAdd(); +static const char* testSST_Math_Vec2dAddLocal(); +static const char* testSST_Math_Vec2dSubtract(); +static const char* testSST_Math_Vec2dSubtractLocal(); +static const char* testSST_Math_Vec2dMultiply(); +static const char* testSST_Math_Vec2dMultiplyLocal(); +static const char* testSST_Math_Vec2dScale(); +static const char* testSST_Math_Vec2dScaleLocal(); +static const char* testSST_Math_Vec2dDivide(); +static const char* testSST_Math_Vec2dDivideLocal(); +static const char* testSST_Math_Vec2dAbs(); +static const char* testSST_Math_Vec2dAbsLocal(); +static const char* testSST_Math_Vec2dNegate(); +static const char* testSST_Math_Vec2dNegateLocal(); +static const char* testSST_Math_Vec2dBias(); +static const char* testSST_Math_Vec2dBiasLocal(); +static const char* testSST_Math_Vec2dRecip(); +static const char* testSST_Math_Vec2dRecipLocal(); +static const char* testSST_Math_Vec2dRecipSqrt(); +static const char* testSST_Math_Vec2dRecipSqrtLocal(); +static const char* testSST_Math_Vec2dSqrt(); +static const char* testSST_Math_Vec2dSqrtLocal(); +static const char* testSST_Math_Vec2dSqrt(); +static const char* testSST_Math_Vec2dSqrtLocal(); +static const char* testSST_Math_Vec2dCross(); +static const char* testSST_Math_Vec2dCrossLocal(); +static const char* testSST_Math_Vec2dProject(); +static const char* testSST_Math_Vec2dProjectLocal(); +static const char* testSST_Math_Vec2dMagnitude(); +static const char* testSST_Math_Vec2dNormalize(); +static const char* testSST_Math_Vec2dNormalizeLocal(); +static const char* testSST_Math_Vec2dMagnitudeSquared(); +static const char* testSST_Math_Vec2dDot(); +// List of unit tests +ZUnitTest SST_Math_Vec2dUnitTests[] = +{ +{ "testSST_Math_Vec2dAdd " , testSST_Math_Vec2dAdd }, +{ "testSST_Math_Vec2dAddLocal " , testSST_Math_Vec2dAddLocal }, +{ "testSST_Math_Vec2dSubtract " , testSST_Math_Vec2dSubtract }, +{ "testSST_Math_Vec2dSubtractLocal " , testSST_Math_Vec2dSubtractLocal }, +{ "testSST_Math_Vec2dMultiply " , testSST_Math_Vec2dMultiply }, +{ "testSST_Math_Vec2dMultiplyLocal " , testSST_Math_Vec2dMultiplyLocal }, +{ "testSST_Math_Vec2dScale " , testSST_Math_Vec2dScale }, +{ "testSST_Math_Vec2dScaleLocal " , testSST_Math_Vec2dScaleLocal }, +{ "testSST_Math_Vec2dDivide " , testSST_Math_Vec2dDivide }, +{ "testSST_Math_Vec2dDivideLocal " , testSST_Math_Vec2dDivideLocal }, +{ "testSST_Math_Vec2dAbs " , testSST_Math_Vec2dAbs }, +{ "testSST_Math_Vec2dAbsLocal " , testSST_Math_Vec2dAbsLocal }, +{ "testSST_Math_Vec2dNegate " , testSST_Math_Vec2dNegate }, +{ "testSST_Math_Vec2dNegateLocal " , testSST_Math_Vec2dNegateLocal }, +{ "testSST_Math_Vec2dBias " , testSST_Math_Vec2dBias }, +{ "testSST_Math_Vec2dBiasLocal " , testSST_Math_Vec2dBiasLocal }, +{ "testSST_Math_Vec2dRecip " , testSST_Math_Vec2dRecip }, +{ "testSST_Math_Vec2dRecipLocal " , testSST_Math_Vec2dRecipLocal }, +{ "testSST_Math_Vec2dRecipSqrt " , testSST_Math_Vec2dRecipSqrt }, +{ "testSST_Math_Vec2dRecipSqrtLocal " , testSST_Math_Vec2dRecipSqrtLocal }, +{ "testSST_Math_Vec2dSqrt " , testSST_Math_Vec2dSqrt }, +{ "testSST_Math_Vec2dSqrtLocal " , testSST_Math_Vec2dSqrtLocal }, +{ "testSST_Math_Vec2dSqrt " , testSST_Math_Vec2dSqrt }, +{ "testSST_Math_Vec2dSqrtLocal " , testSST_Math_Vec2dSqrtLocal }, +{ "testSST_Math_Vec2dMagnitude " , testSST_Math_Vec2dMagnitude }, +{ "testSST_Math_Vec2dNormalize " , testSST_Math_Vec2dNormalize }, +{ "testSST_Math_Vec2dNormalizeLocal " , testSST_Math_Vec2dNormalizeLocal }, +{ "testSST_Math_Vec2dCross " , testSST_Math_Vec2dCross }, +{ "testSST_Math_Vec2dCrossLocal " , testSST_Math_Vec2dCrossLocal }, +{ "testSST_Math_Vec2dProject " , testSST_Math_Vec2dProject }, +{ "testSST_Math_Vec2dProjectLocal " , testSST_Math_Vec2dProjectLocal }, +{ "testSST_Math_Vec2dMagnitudeSquared " , testSST_Math_Vec2dMagnitudeSquared }, +{ "testSST_Math_Vec2dDot " , testSST_Math_Vec2dDot } +}; +DECLARE_ZTESTBLOCK(SST_Math_Vec2d) + +/******************************************************************************/ + +static const char* testSST_Math_Vec2dAdd() +{ + SST_Vec2d x; /* 2 vector */ + SST_Vec2d y; /* 2 vector */ + SST_Vec2d w; /* 2 vector */ +/* Resetting test vectors */ + x.v[0] = 14.0000000000000000; + x.v[1] = -14.0000000000000000; + y.v[0] = -2.0000000000000000; + y.v[1] = -20.0000000000000000; + w.v[0] = 0.0000000000000000; + w.v[1] = 0.0000000000000000; +/* +[ 14. -14.] +[ -2. -20.] +[ 12. -34.] +*/ + SST_Math_Vec2dAdd(&x,&y,&w); + TASSERT(fabs((w.v[0])-( 12.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabs((w.v[1])-( -34.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _y failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec2dAddLocal() +{ + SST_Vec2d x; /* 2 vector */ + SST_Vec2d y; /* 2 vector */ +/* Resetting test vectors */ + x.v[0] = 10.0000000000000000; + x.v[1] = 2.0000000000000000; + y.v[0] = 3.0000000000000000; + y.v[1] = -11.0000000000000000; +/* +[ 10. 2.] +[ 3. -11.] +[ 13. -9.] +*/ + SST_Math_Vec2dAddLocal(&x,&y); /* for accuracy */ + TASSERT(fabs((x.v[0])-( 13.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabs((x.v[1])-( -9.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _y failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec2dSubtract() +{ + SST_Vec2d x; /* 2 vector */ + SST_Vec2d y; /* 2 vector */ + SST_Vec2d w; /* 2 vector */ +/* Resetting test vectors */ + x.v[0] = 13.0000000000000000; + x.v[1] = 11.0000000000000000; + y.v[0] = 15.0000000000000000; + y.v[1] = -11.0000000000000000; + w.v[0] = 0.0000000000000000; + w.v[1] = 0.0000000000000000; +/* +[ 13. 11.] +[ 15. -11.] +[ -2. 22.] +*/ + SST_Math_Vec2dSubtract(&x,&y,&w); + TASSERT(fabs((w.v[0])-( -2.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabs((w.v[1])-( 22.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _y failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec2dSubtractLocal() +{ + SST_Vec2d x; /* 2 vector */ + SST_Vec2d y; /* 2 vector */ +/* Resetting test vectors */ + x.v[0] = -4.0000000000000000; + x.v[1] = 19.0000000000000000; + y.v[0] = -19.0000000000000000; + y.v[1] = -12.0000000000000000; +/* +[ -4. 19.] +[-19. -12.] +[ 15. 31.] +*/ + SST_Math_Vec2dSubtractLocal(&x,&y); /* for accuracy */ + TASSERT(fabs((x.v[0])-( 15.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabs((x.v[1])-( 31.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _y failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec2dMultiply() +{ + SST_Vec2d x; /* 2 vector */ + SST_Vec2d y; /* 2 vector */ + SST_Vec2d w; /* 2 vector */ +/* Resetting test vectors */ + x.v[0] = 12.0000000000000000; + x.v[1] = 18.0000000000000000; + y.v[0] = -1.0000000000000000; + y.v[1] = 7.0000000000000000; + w.v[0] = 0.0000000000000000; + w.v[1] = 0.0000000000000000; +/* +[ 12. 18.] +[-1. 7.] +[ -12. 126.] +*/ + SST_Math_Vec2dMultiply(&x,&y,&w); + TASSERT(fabs((w.v[0])-( -12.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabs((w.v[1])-( 126.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _y failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec2dMultiplyLocal() +{ + SST_Vec2d x; /* 2 vector */ + SST_Vec2d y; /* 2 vector */ +/* Resetting test vectors */ + x.v[0] = -16.0000000000000000; + x.v[1] = 2.0000000000000000; + y.v[0] = -10.0000000000000000; + y.v[1] = 9.0000000000000000; +/* +[-16. 2.] +[-10. 9.] +[ 160. 18.] +*/ + SST_Math_Vec2dMultiplyLocal(&x,&y); /* for accuracy */ + TASSERT(fabs((x.v[0])-( 160.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabs((x.v[1])-( 18.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _y failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec2dDivide() +{ + SST_Vec2d x; /* 2 vector */ + SST_Vec2d y; /* 2 vector */ + SST_Vec2d w; /* 2 vector */ +/* Resetting test vectors */ + x.v[0] = 6.0000000000000000; + x.v[1] = 6.0000000000000000; + y.v[0] = 33.0000000000000000; + y.v[1] = 26.0000000000000000; + w.v[0] = 0.0000000000000000; + w.v[1] = 0.0000000000000000; +/* +[ 6. 6.] +[ 33. 26.] +[ 0.18181818 0.23076923] +*/ + SST_Math_Vec2dDivide(&x,&y,&w); + TASSERT(fabs((w.v[0])-( 0.1818181818181818)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabs((w.v[1])-( 0.2307692307692308)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _y failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec2dDivideLocal() +{ + SST_Vec2d x; /* 2 vector */ + SST_Vec2d y; /* 2 vector */ +/* Resetting test vectors */ + x.v[0] = 8.0000000000000000; + x.v[1] = 24.0000000000000000; + y.v[0] = 32.0000000000000000; + y.v[1] = 24.0000000000000000; +/* +[ 8. 24.] +[ 32. 24.] +[ 0.25 1. ] +*/ + SST_Math_Vec2dDivideLocal(&x,&y); /* for accuracy */ + TASSERT(fabs((x.v[0])-( 0.2500000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabs((x.v[1])-( 1.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _y failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec2dScale() +{ + SST_Vec2d x; /* 2 vector */ + SST_Vec2d w; /* 2 vector */ + double a; /* scalar */ +/* Resetting test vectors */ + x.v[0] = 16.0000000000000000; + x.v[1] = -15.0000000000000000; + w.v[0] = 0.0000000000000000; + w.v[1] = 0.0000000000000000; + a = 2.0000000000000000; +/* +[ 16. -15.] +[ 32. -30.] +*/ + SST_Math_Vec2dScale(&x,a,&w); + TASSERT(fabs((w.v[0])-( 32.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabs((w.v[1])-( -30.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _y failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec2dScaleLocal() +{ + SST_Vec2d x; /* 2 vector */ + double a; /* scalar */ +/* Resetting test vectors */ + x.v[0] = 3.0000000000000000; + x.v[1] = -7.0000000000000000; + a = 2.0000000000000000; +/* +[ 3. -7.] +[ 6. -14.] +*/ + SST_Math_Vec2dScaleLocal(&x,a); /* for accuracy */ + TASSERT(fabs((x.v[0])-( 6.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabs((x.v[1])-( -14.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _y failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec2dAbs() +{ + SST_Vec2d x; /* 2 vector */ + SST_Vec2d w; /* 2 vector */ +/* Resetting test vectors */ + x.v[0] = -19.0000000000000000; + x.v[1] = -1.0000000000000000; + w.v[0] = 0.0000000000000000; + w.v[1] = 0.0000000000000000; +/* +[-19. -1.] +[ 19. 1.] +*/ + SST_Math_Vec2dAbs(&x,&w); + TASSERT(fabs((w.v[0])-( 19.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabs((w.v[1])-( 1.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _y failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec2dAbsLocal() +{ + SST_Vec2d x; /* 2 vector */ +/* Resetting test vectors */ + x.v[0] = -17.0000000000000000; + x.v[1] = 16.0000000000000000; +/* +[-17. 16.] +[ 17. 16.] +*/ + SST_Math_Vec2dAbsLocal(&x); /* for accuracy */ + TASSERT(fabs((x.v[0])-( 17.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabs((x.v[1])-( 16.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _y failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec2dBias() +{ + SST_Vec2d x; /* 2 vector */ + SST_Vec2d w; /* 2 vector */ + double a; /* scalar */ +/* Resetting test vectors */ + x.v[0] = -11.0000000000000000; + x.v[1] = 0.0000000000000000; + w.v[0] = 0.0000000000000000; + w.v[1] = 0.0000000000000000; + a = -19.0000000000000000; +/* +[-11. 0.] +[-22. 0.] +*/ + SST_Math_Vec2dBias(&x,a,&w); + TASSERT(fabs((w.v[0])-( -30.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabs((w.v[1])-( -19.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _y failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec2dBiasLocal() +{ + SST_Vec2d x; /* 2 vector */ + double a; /* scalar */ +/* Resetting test vectors */ + x.v[0] = -18.0000000000000000; + x.v[1] = -3.0000000000000000; + a = -4.0000000000000000; +/* +[-18. -3.] +[-36. -6.] +*/ + SST_Math_Vec2dBiasLocal(&x,a); /* for accuracy */ + TASSERT(fabs((x.v[0])-( -22.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabs((x.v[1])-( -7.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _y failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec2dNegate() +{ + SST_Vec2d x; /* 2 vector */ + SST_Vec2d w; /* 2 vector */ +/* Resetting test vectors */ + x.v[0] = -4.0000000000000000; + x.v[1] = -19.0000000000000000; + w.v[0] = 0.0000000000000000; + w.v[1] = 0.0000000000000000; +/* +[ -4. -19.] +[ 4. 19.] +*/ + SST_Math_Vec2dNegate(&x,&w); + TASSERT(fabs((w.v[0])-( 4.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabs((w.v[1])-( 19.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _y failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec2dNegateLocal() +{ + SST_Vec2d x; /* 2 vector */ +/* Resetting test vectors */ + x.v[0] = -7.0000000000000000; + x.v[1] = -2.0000000000000000; +/* +[-7. -2.] +[ 7. 2.] +*/ + SST_Math_Vec2dNegateLocal(&x); /* for accuracy */ + TASSERT(fabs((x.v[0])-( 7.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabs((x.v[1])-( 2.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _y failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec2dSqrt() +{ + SST_Vec2d x; /* 2 vector */ + SST_Vec2d w; /* 2 vector */ +/* Resetting test vectors */ + x.v[0] = 14.0000000000000000; + x.v[1] = 32.0000000000000000; + w.v[0] = 0.0000000000000000; + w.v[1] = 0.0000000000000000; +/* +[ 14. 32.] +[ 3.74165739 5.65685425] +*/ + SST_Math_Vec2dSqrt(&x,&w); + TASSERT(fabs((w.v[0])-( 3.7416573867739413)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabs((w.v[1])-( 5.6568542494923806)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _y failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec2dSqrtLocal() +{ + SST_Vec2d x; /* 2 vector */ +/* Resetting test vectors */ + x.v[0] = 34.0000000000000000; + x.v[1] = 15.0000000000000000; +/* +[ 34. 15.] +[ 5.83095189 3.87298335] +*/ + SST_Math_Vec2dSqrtLocal(&x); /* for accuracy */ + TASSERT(fabs((x.v[0])-( 5.8309518948453007)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabs((x.v[1])-( 3.8729833462074170)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _y failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec2dRecipSqrt() +{ + SST_Vec2d x; /* 2 vector */ + SST_Vec2d w; /* 2 vector */ +/* Resetting test vectors */ + x.v[0] = 11.0000000000000000; + x.v[1] = 33.0000000000000000; + w.v[0] = 0.0000000000000000; + w.v[1] = 0.0000000000000000; +/* +[ 11. 33.] +[ 0.30151134 0.17407766] +*/ + SST_Math_Vec2dRecipSqrt(&x,&w); + TASSERT(fabs((w.v[0])-( 0.3015113445777636)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabs((w.v[1])-( 0.1740776559556979)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _y failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec2dRecipSqrtLocal() +{ + SST_Vec2d x; /* 2 vector */ +/* Resetting test vectors */ + x.v[0] = 2.0000000000000000; + x.v[1] = 15.0000000000000000; +/* +[ 2. 15.] +[ 0.70710678 0.25819889] +*/ + SST_Math_Vec2dRecipSqrtLocal(&x); /* for accuracy */ + TASSERT(fabs((x.v[0])-( 0.7071067811865475)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabs((x.v[1])-( 0.2581988897471611)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _y failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec2dRecip() +{ + SST_Vec2d x; /* 2 vector */ + SST_Vec2d w; /* 2 vector */ +/* Resetting test vectors */ + x.v[0] = 35.0000000000000000; + x.v[1] = 2.0000000000000000; + w.v[0] = 0.0000000000000000; + w.v[1] = 0.0000000000000000; +/* +[ 35. 2.] +[ 0.02857143 0.5 ] +*/ + SST_Math_Vec2dRecip(&x,&w); + TASSERT(fabs((w.v[0])-( 0.0285714285714286)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabs((w.v[1])-( 0.5000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _y failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec2dRecipLocal() +{ + SST_Vec2d x; /* 2 vector */ +/* Resetting test vectors */ + x.v[0] = 8.0000000000000000; + x.v[1] = 19.0000000000000000; +/* +[ 8. 19.] +[ 0.35355339 0.22941573] +*/ + SST_Math_Vec2dRecipLocal(&x); /* for accuracy */ + TASSERT(fabs((x.v[0])-( 0.1250000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabs((x.v[1])-( 0.0526315789473684)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _y failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec2dNormalize() +{ + SST_Vec2d x; /* 2 vector */ + SST_Vec2d w; /* 2 vector */ +/* Resetting test vectors */ + x.v[0] = -16.0000000000000000; + x.v[1] = -6.0000000000000000; + w.v[0] = 0.0000000000000000; + w.v[1] = 0.0000000000000000; +/* +[-16. -6.] +[-0.93632918 -0.35112344] +*/ + SST_Math_Vec2dNormalize(&x,&w); + TASSERT(fabs((w.v[0])-( -0.9363291775690445)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabs((w.v[1])-( -0.3511234415883917)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _y failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec2dNormalizeLocal() +{ + SST_Vec2d x; /* 2 vector */ +/* Resetting test vectors */ + x.v[0] = -8.0000000000000000; + x.v[1] = -18.0000000000000000; +/* +[ -8. -18.] +[-0.40613847 -0.91381155] +*/ + SST_Math_Vec2dNormalizeLocal(&x); /* for accuracy */ + TASSERT(fabs((x.v[0])-( -0.4061384660534477)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabs((x.v[1])-( -0.9138115486202573)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _y failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec2dProject() +{ + SST_Vec2d x; /* 2 vector */ + SST_Vec2d y; /* 2 vector */ + SST_Vec2d w; /* 2 vector */ +/* Resetting test vectors */ + x.v[0] = 9.0000000000000000; + x.v[1] = 0.0000000000000000; + y.v[0] = -14.0000000000000000; + y.v[1] = 4.0000000000000000; + w.v[0] = 0.0000000000000000; + w.v[1] = 0.0000000000000000; +/* +[ 9. 0.] +[-14. 4.] +[ 8.32075472 -2.37735849] +*/ + SST_Math_Vec2dProject(&x,&y,&w); + TASSERT(fabs((w.v[0])-( 8.3207547169811313)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabs((w.v[1])-( -2.3773584905660377)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _y failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec2dProjectLocal() +{ + SST_Vec2d x; /* 2 vector */ + SST_Vec2d y; /* 2 vector */ +/* Resetting test vectors */ + x.v[0] = -20.0000000000000000; + x.v[1] = -6.0000000000000000; + y.v[0] = -9.0000000000000000; + y.v[1] = -8.0000000000000000; +/* +[-20. -6.] +[-9. -8.] +[-14.15172414 -12.57931034] +*/ + SST_Math_Vec2dProjectLocal(&x,&y); /* for accuracy */ + TASSERT(fabs((x.v[0])-( -14.1517241379310352)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabs((x.v[1])-( -12.5793103448275865)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _y failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec2dCross() +{ + SST_Vec2d x; /* 2 vector */ + SST_Vec2d y; /* 2 vector */ + SST_Vec2d w; /* 2 vector */ +/* Resetting test vectors */ + x.v[0] = -4.0000000000000000; + x.v[1] = 5.0000000000000000; + y.v[0] = 5.0000000000000000; + y.v[1] = 16.0000000000000000; + w.v[0] = 0.0000000000000000; + w.v[1] = 0.0000000000000000; +/* +[-4. 5.] +[ 5. 16.] +-89.0 +*/ + SST_Math_Vec2dCross(&x,&y,&w); + TASSERT(fabs((w.v[0])-( -89.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabs((w.v[1])-( -89.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _y failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec2dCrossLocal() +{ + SST_Vec2d x; /* 2 vector */ + SST_Vec2d y; /* 2 vector */ +/* Resetting test vectors */ + x.v[0] = -13.0000000000000000; + x.v[1] = 0.0000000000000000; + y.v[0] = -8.0000000000000000; + y.v[1] = -5.0000000000000000; +/* +[-13. 0.] +[-8. -5.] +65.0 +*/ + SST_Math_Vec2dCrossLocal(&x,&y); /* for accuracy */ + TASSERT(fabs((x.v[0])-( 65.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabs((x.v[1])-( 65.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _y failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec2dMagnitude() +{ + SST_Vec2d x; /* 2 vector */ + double a; /* scalar */ +/* Resetting test vectors */ + x.v[0] = 1.0000000000000000; + x.v[1] = 19.0000000000000000; +/* +[ 1. 19.] +19.0262975904 +*/ + a = SST_Math_Vec2dMagnitude(&x); + TASSERT(fabs((a)-( 19.0262975904404463)) <=100*DBL_EPSILON /* yes this is bad */,"Magnitude failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec2dMagnitudeSquared() +{ + SST_Vec2d x; /* 2 vector */ + double a; /* scalar */ +/* Resetting test vectors */ + x.v[0] = 2.0000000000000000; + x.v[1] = 9.0000000000000000; +/* +[ 2. 9.] +85.0 +*/ + a = SST_Math_Vec2dMagnitudeSquared(&x); + TASSERT(fabs((a)-( 85.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"MagnitudeSquared failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec2dDot() +{ + SST_Vec2d x; /* 2 vector */ + SST_Vec2d y; /* 2 vector */ + double a; /* scalar */ +/* Resetting test vectors */ + x.v[0] = 16.0000000000000000; + x.v[1] = 14.0000000000000000; + y.v[0] = -17.0000000000000000; + y.v[1] = -16.0000000000000000; +/* +[ 16. 14.] +-496.0 +*/ + a = SST_Math_Vec2dDot(&x,&y); + TASSERT(fabs((a)-( -496.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Dot failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + diff --git a/ZTestSuite/Test-SST_Vec2f.cpp b/ZTestSuite/Test-SST_Vec2f.cpp new file mode 100644 index 0000000..5b2cd21 --- /dev/null +++ b/ZTestSuite/Test-SST_Vec2f.cpp @@ -0,0 +1,749 @@ +/* + AUTOMATICALLY GENERATED FILE - DO NOT EDIT! + Please change MatrixNxN.py and re-run it +*/ +/* Generated with ./VectorN.py n = 2, TYPE = float */ + +#include "ZUnitTest.hpp" +#include <float.h> +#include <math.h> +#include <stdlib.h> +#include <stdio.h> +#include <SST/SST_Vec2.h> + + + + +static const char* testSST_Math_Vec2fAdd(); +static const char* testSST_Math_Vec2fAddLocal(); +static const char* testSST_Math_Vec2fSubtract(); +static const char* testSST_Math_Vec2fSubtractLocal(); +static const char* testSST_Math_Vec2fMultiply(); +static const char* testSST_Math_Vec2fMultiplyLocal(); +static const char* testSST_Math_Vec2fScale(); +static const char* testSST_Math_Vec2fScaleLocal(); +static const char* testSST_Math_Vec2fDivide(); +static const char* testSST_Math_Vec2fDivideLocal(); +static const char* testSST_Math_Vec2fAbs(); +static const char* testSST_Math_Vec2fAbsLocal(); +static const char* testSST_Math_Vec2fNegate(); +static const char* testSST_Math_Vec2fNegateLocal(); +static const char* testSST_Math_Vec2fBias(); +static const char* testSST_Math_Vec2fBiasLocal(); +static const char* testSST_Math_Vec2fRecip(); +static const char* testSST_Math_Vec2fRecipLocal(); +static const char* testSST_Math_Vec2fRecipSqrt(); +static const char* testSST_Math_Vec2fRecipSqrtLocal(); +static const char* testSST_Math_Vec2fSqrt(); +static const char* testSST_Math_Vec2fSqrtLocal(); +static const char* testSST_Math_Vec2fSqrt(); +static const char* testSST_Math_Vec2fSqrtLocal(); +static const char* testSST_Math_Vec2fCross(); +static const char* testSST_Math_Vec2fCrossLocal(); +static const char* testSST_Math_Vec2fProject(); +static const char* testSST_Math_Vec2fProjectLocal(); +static const char* testSST_Math_Vec2fMagnitude(); +static const char* testSST_Math_Vec2fNormalize(); +static const char* testSST_Math_Vec2fNormalizeLocal(); +static const char* testSST_Math_Vec2fMagnitudeSquared(); +static const char* testSST_Math_Vec2fDot(); +// List of unit tests +ZUnitTest SST_Math_Vec2fUnitTests[] = +{ +{ "testSST_Math_Vec2fAdd " , testSST_Math_Vec2fAdd }, +{ "testSST_Math_Vec2fAddLocal " , testSST_Math_Vec2fAddLocal }, +{ "testSST_Math_Vec2fSubtract " , testSST_Math_Vec2fSubtract }, +{ "testSST_Math_Vec2fSubtractLocal " , testSST_Math_Vec2fSubtractLocal }, +{ "testSST_Math_Vec2fMultiply " , testSST_Math_Vec2fMultiply }, +{ "testSST_Math_Vec2fMultiplyLocal " , testSST_Math_Vec2fMultiplyLocal }, +{ "testSST_Math_Vec2fScale " , testSST_Math_Vec2fScale }, +{ "testSST_Math_Vec2fScaleLocal " , testSST_Math_Vec2fScaleLocal }, +{ "testSST_Math_Vec2fDivide " , testSST_Math_Vec2fDivide }, +{ "testSST_Math_Vec2fDivideLocal " , testSST_Math_Vec2fDivideLocal }, +{ "testSST_Math_Vec2fAbs " , testSST_Math_Vec2fAbs }, +{ "testSST_Math_Vec2fAbsLocal " , testSST_Math_Vec2fAbsLocal }, +{ "testSST_Math_Vec2fNegate " , testSST_Math_Vec2fNegate }, +{ "testSST_Math_Vec2fNegateLocal " , testSST_Math_Vec2fNegateLocal }, +{ "testSST_Math_Vec2fBias " , testSST_Math_Vec2fBias }, +{ "testSST_Math_Vec2fBiasLocal " , testSST_Math_Vec2fBiasLocal }, +{ "testSST_Math_Vec2fRecip " , testSST_Math_Vec2fRecip }, +{ "testSST_Math_Vec2fRecipLocal " , testSST_Math_Vec2fRecipLocal }, +{ "testSST_Math_Vec2fRecipSqrt " , testSST_Math_Vec2fRecipSqrt }, +{ "testSST_Math_Vec2fRecipSqrtLocal " , testSST_Math_Vec2fRecipSqrtLocal }, +{ "testSST_Math_Vec2fSqrt " , testSST_Math_Vec2fSqrt }, +{ "testSST_Math_Vec2fSqrtLocal " , testSST_Math_Vec2fSqrtLocal }, +{ "testSST_Math_Vec2fSqrt " , testSST_Math_Vec2fSqrt }, +{ "testSST_Math_Vec2fSqrtLocal " , testSST_Math_Vec2fSqrtLocal }, +{ "testSST_Math_Vec2fMagnitude " , testSST_Math_Vec2fMagnitude }, +{ "testSST_Math_Vec2fNormalize " , testSST_Math_Vec2fNormalize }, +{ "testSST_Math_Vec2fNormalizeLocal " , testSST_Math_Vec2fNormalizeLocal }, +{ "testSST_Math_Vec2fCross " , testSST_Math_Vec2fCross }, +{ "testSST_Math_Vec2fCrossLocal " , testSST_Math_Vec2fCrossLocal }, +{ "testSST_Math_Vec2fProject " , testSST_Math_Vec2fProject }, +{ "testSST_Math_Vec2fProjectLocal " , testSST_Math_Vec2fProjectLocal }, +{ "testSST_Math_Vec2fMagnitudeSquared " , testSST_Math_Vec2fMagnitudeSquared }, +{ "testSST_Math_Vec2fDot " , testSST_Math_Vec2fDot } +}; +DECLARE_ZTESTBLOCK(SST_Math_Vec2f) + +/******************************************************************************/ + +static const char* testSST_Math_Vec2fAdd() +{ + SST_Vec2f x; /* 2 vector */ + SST_Vec2f y; /* 2 vector */ + SST_Vec2f w; /* 2 vector */ +/* Resetting test vectors */ + x.v[0] = 0.000000f; + x.v[1] = 4.000000f; + y.v[0] = -12.000000f; + y.v[1] = -14.000000f; + w.v[0] = 0.000000f; + w.v[1] = 0.000000f; +/* +[ 0. 4.] +[-12. -14.] +[-12. -10.] +*/ + SST_Math_Vec2fAdd(&x,&y,&w); + TASSERT(fabsf((w.v[0])-(-12.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabsf((w.v[1])-(-10.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _y failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec2fAddLocal() +{ + SST_Vec2f x; /* 2 vector */ + SST_Vec2f y; /* 2 vector */ +/* Resetting test vectors */ + x.v[0] = 2.000000f; + x.v[1] = 2.000000f; + y.v[0] = 14.000000f; + y.v[1] = -6.000000f; +/* +[ 2. 2.] +[ 14. -6.] +[ 16. -4.] +*/ + SST_Math_Vec2fAddLocal(&x,&y); /* for accuracy */ + TASSERT(fabsf((x.v[0])-(16.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabsf((x.v[1])-(-4.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _y failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec2fSubtract() +{ + SST_Vec2f x; /* 2 vector */ + SST_Vec2f y; /* 2 vector */ + SST_Vec2f w; /* 2 vector */ +/* Resetting test vectors */ + x.v[0] = -3.000000f; + x.v[1] = 8.000000f; + y.v[0] = -5.000000f; + y.v[1] = -17.000000f; + w.v[0] = 0.000000f; + w.v[1] = 0.000000f; +/* +[-3. 8.] +[ -5. -17.] +[ 2. 25.] +*/ + SST_Math_Vec2fSubtract(&x,&y,&w); + TASSERT(fabsf((w.v[0])-(2.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabsf((w.v[1])-(25.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _y failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec2fSubtractLocal() +{ + SST_Vec2f x; /* 2 vector */ + SST_Vec2f y; /* 2 vector */ +/* Resetting test vectors */ + x.v[0] = 8.000000f; + x.v[1] = 13.000000f; + y.v[0] = -17.000000f; + y.v[1] = 10.000000f; +/* +[ 8. 13.] +[-17. 10.] +[ 25. 3.] +*/ + SST_Math_Vec2fSubtractLocal(&x,&y); /* for accuracy */ + TASSERT(fabsf((x.v[0])-(25.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabsf((x.v[1])-(3.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _y failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec2fMultiply() +{ + SST_Vec2f x; /* 2 vector */ + SST_Vec2f y; /* 2 vector */ + SST_Vec2f w; /* 2 vector */ +/* Resetting test vectors */ + x.v[0] = 16.000000f; + x.v[1] = 7.000000f; + y.v[0] = 6.000000f; + y.v[1] = -12.000000f; + w.v[0] = 0.000000f; + w.v[1] = 0.000000f; +/* +[ 16. 7.] +[ 6. -12.] +[ 96. -84.] +*/ + SST_Math_Vec2fMultiply(&x,&y,&w); + TASSERT(fabsf((w.v[0])-(96.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabsf((w.v[1])-(-84.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _y failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec2fMultiplyLocal() +{ + SST_Vec2f x; /* 2 vector */ + SST_Vec2f y; /* 2 vector */ +/* Resetting test vectors */ + x.v[0] = 3.000000f; + x.v[1] = 7.000000f; + y.v[0] = 5.000000f; + y.v[1] = 14.000000f; +/* +[ 3. 7.] +[ 5. 14.] +[ 15. 98.] +*/ + SST_Math_Vec2fMultiplyLocal(&x,&y); /* for accuracy */ + TASSERT(fabsf((x.v[0])-(15.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabsf((x.v[1])-(98.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _y failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec2fDivide() +{ + SST_Vec2f x; /* 2 vector */ + SST_Vec2f y; /* 2 vector */ + SST_Vec2f w; /* 2 vector */ +/* Resetting test vectors */ + x.v[0] = 14.000000f; + x.v[1] = 18.000000f; + y.v[0] = 39.000000f; + y.v[1] = 26.000000f; + w.v[0] = 0.000000f; + w.v[1] = 0.000000f; +/* +[ 14. 18.] +[ 39. 26.] +[ 0.35897437 0.69230771] +*/ + SST_Math_Vec2fDivide(&x,&y,&w); + TASSERT(fabsf((w.v[0])-(0.358974f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabsf((w.v[1])-(0.692308f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _y failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec2fDivideLocal() +{ + SST_Vec2f x; /* 2 vector */ + SST_Vec2f y; /* 2 vector */ +/* Resetting test vectors */ + x.v[0] = 4.000000f; + x.v[1] = 31.000000f; + y.v[0] = 31.000000f; + y.v[1] = 18.000000f; +/* +[ 4. 31.] +[ 31. 18.] +[ 0.12903225 1.72222221] +*/ + SST_Math_Vec2fDivideLocal(&x,&y); /* for accuracy */ + TASSERT(fabsf((x.v[0])-(0.129032f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabsf((x.v[1])-(1.722222f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _y failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec2fScale() +{ + SST_Vec2f x; /* 2 vector */ + SST_Vec2f w; /* 2 vector */ + float a; /* scalar */ +/* Resetting test vectors */ + x.v[0] = -18.000000f; + x.v[1] = 18.000000f; + w.v[0] = 0.000000f; + w.v[1] = 0.000000f; + a = 2.000000f; +/* +[-18. 18.] +[-36. 36.] +*/ + SST_Math_Vec2fScale(&x,a,&w); + TASSERT(fabsf((w.v[0])-(-36.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabsf((w.v[1])-(36.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _y failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec2fScaleLocal() +{ + SST_Vec2f x; /* 2 vector */ + float a; /* scalar */ +/* Resetting test vectors */ + x.v[0] = 2.000000f; + x.v[1] = -3.000000f; + a = 2.000000f; +/* +[ 2. -3.] +[ 4. -6.] +*/ + SST_Math_Vec2fScaleLocal(&x,a); /* for accuracy */ + TASSERT(fabsf((x.v[0])-(4.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabsf((x.v[1])-(-6.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _y failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec2fAbs() +{ + SST_Vec2f x; /* 2 vector */ + SST_Vec2f w; /* 2 vector */ +/* Resetting test vectors */ + x.v[0] = 13.000000f; + x.v[1] = 14.000000f; + w.v[0] = 0.000000f; + w.v[1] = 0.000000f; +/* +[ 13. 14.] +[ 13. 14.] +*/ + SST_Math_Vec2fAbs(&x,&w); + TASSERT(fabsf((w.v[0])-(13.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabsf((w.v[1])-(14.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _y failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec2fAbsLocal() +{ + SST_Vec2f x; /* 2 vector */ +/* Resetting test vectors */ + x.v[0] = 12.000000f; + x.v[1] = -4.000000f; +/* +[ 12. -4.] +[ 12. 4.] +*/ + SST_Math_Vec2fAbsLocal(&x); /* for accuracy */ + TASSERT(fabsf((x.v[0])-(12.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabsf((x.v[1])-(4.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _y failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec2fBias() +{ + SST_Vec2f x; /* 2 vector */ + SST_Vec2f w; /* 2 vector */ + float a; /* scalar */ +/* Resetting test vectors */ + x.v[0] = -2.000000f; + x.v[1] = -20.000000f; + w.v[0] = 0.000000f; + w.v[1] = 0.000000f; + a = 9.000000f; +/* +[ -2. -20.] +[ -4. -40.] +*/ + SST_Math_Vec2fBias(&x,a,&w); + TASSERT(fabsf((w.v[0])-(7.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabsf((w.v[1])-(-11.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _y failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec2fBiasLocal() +{ + SST_Vec2f x; /* 2 vector */ + float a; /* scalar */ +/* Resetting test vectors */ + x.v[0] = -9.000000f; + x.v[1] = -2.000000f; + a = 5.000000f; +/* +[-9. -2.] +[-18. -4.] +*/ + SST_Math_Vec2fBiasLocal(&x,a); /* for accuracy */ + TASSERT(fabsf((x.v[0])-(-4.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabsf((x.v[1])-(3.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _y failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec2fNegate() +{ + SST_Vec2f x; /* 2 vector */ + SST_Vec2f w; /* 2 vector */ +/* Resetting test vectors */ + x.v[0] = 11.000000f; + x.v[1] = 9.000000f; + w.v[0] = 0.000000f; + w.v[1] = 0.000000f; +/* +[ 11. 9.] +[-11. -9.] +*/ + SST_Math_Vec2fNegate(&x,&w); + TASSERT(fabsf((w.v[0])-(-11.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabsf((w.v[1])-(-9.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _y failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec2fNegateLocal() +{ + SST_Vec2f x; /* 2 vector */ +/* Resetting test vectors */ + x.v[0] = -15.000000f; + x.v[1] = 11.000000f; +/* +[-15. 11.] +[ 15. -11.] +*/ + SST_Math_Vec2fNegateLocal(&x); /* for accuracy */ + TASSERT(fabsf((x.v[0])-(15.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabsf((x.v[1])-(-11.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _y failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec2fSqrt() +{ + SST_Vec2f x; /* 2 vector */ + SST_Vec2f w; /* 2 vector */ +/* Resetting test vectors */ + x.v[0] = 27.000000f; + x.v[1] = 9.000000f; + w.v[0] = 0.000000f; + w.v[1] = 0.000000f; +/* +[ 27. 9.] +[ 5.19615221 3. ] +*/ + SST_Math_Vec2fSqrt(&x,&w); + TASSERT(fabsf((w.v[0])-(5.196152f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabsf((w.v[1])-(3.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _y failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec2fSqrtLocal() +{ + SST_Vec2f x; /* 2 vector */ +/* Resetting test vectors */ + x.v[0] = 30.000000f; + x.v[1] = 36.000000f; +/* +[ 30. 36.] +[ 5.47722578 6. ] +*/ + SST_Math_Vec2fSqrtLocal(&x); /* for accuracy */ + TASSERT(fabsf((x.v[0])-(5.477226f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabsf((x.v[1])-(6.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _y failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec2fRecipSqrt() +{ + SST_Vec2f x; /* 2 vector */ + SST_Vec2f w; /* 2 vector */ +/* Resetting test vectors */ + x.v[0] = 6.000000f; + x.v[1] = 38.000000f; + w.v[0] = 0.000000f; + w.v[1] = 0.000000f; +/* +[ 6. 38.] +[ 0.40824828 0.16222142] +*/ + SST_Math_Vec2fRecipSqrt(&x,&w); + TASSERT(fabsf((w.v[0])-(0.408248f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabsf((w.v[1])-(0.162221f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _y failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec2fRecipSqrtLocal() +{ + SST_Vec2f x; /* 2 vector */ +/* Resetting test vectors */ + x.v[0] = 28.000000f; + x.v[1] = 31.000000f; +/* +[ 28. 31.] +[ 0.18898225 0.17960531] +*/ + SST_Math_Vec2fRecipSqrtLocal(&x); /* for accuracy */ + TASSERT(fabsf((x.v[0])-(0.188982f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabsf((x.v[1])-(0.179605f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _y failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec2fRecip() +{ + SST_Vec2f x; /* 2 vector */ + SST_Vec2f w; /* 2 vector */ +/* Resetting test vectors */ + x.v[0] = 1.000000f; + x.v[1] = 22.000000f; + w.v[0] = 0.000000f; + w.v[1] = 0.000000f; +/* +[ 1. 22.] +[ 1. 0.04545455] +*/ + SST_Math_Vec2fRecip(&x,&w); + TASSERT(fabsf((w.v[0])-(1.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabsf((w.v[1])-(0.045455f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _y failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec2fRecipLocal() +{ + SST_Vec2f x; /* 2 vector */ +/* Resetting test vectors */ + x.v[0] = 12.000000f; + x.v[1] = 1.000000f; +/* +[ 12. 1.] +[ 0.28867513 1. ] +*/ + SST_Math_Vec2fRecipLocal(&x); /* for accuracy */ + TASSERT(fabsf((x.v[0])-(0.083333f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabsf((x.v[1])-(1.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _y failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec2fNormalize() +{ + SST_Vec2f x; /* 2 vector */ + SST_Vec2f w; /* 2 vector */ +/* Resetting test vectors */ + x.v[0] = 11.000000f; + x.v[1] = -11.000000f; + w.v[0] = 0.000000f; + w.v[1] = 0.000000f; +/* +[ 11. -11.] +[ 0.70710677 -0.70710677] +*/ + SST_Math_Vec2fNormalize(&x,&w); + TASSERT(fabsf((w.v[0])-(0.707107f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabsf((w.v[1])-(-0.707107f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _y failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec2fNormalizeLocal() +{ + SST_Vec2f x; /* 2 vector */ +/* Resetting test vectors */ + x.v[0] = 11.000000f; + x.v[1] = 16.000000f; +/* +[ 11. 16.] +[ 0.5665288 0.8240419] +*/ + SST_Math_Vec2fNormalizeLocal(&x); /* for accuracy */ + TASSERT(fabsf((x.v[0])-(0.566529f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabsf((x.v[1])-(0.824042f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _y failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec2fProject() +{ + SST_Vec2f x; /* 2 vector */ + SST_Vec2f y; /* 2 vector */ + SST_Vec2f w; /* 2 vector */ +/* Resetting test vectors */ + x.v[0] = -4.000000f; + x.v[1] = -13.000000f; + y.v[0] = 5.000000f; + y.v[1] = -4.000000f; + w.v[0] = 0.000000f; + w.v[1] = 0.000000f; +/* +[ -4. -13.] +[ 5. -4.] +[ 3.90243888 -3.1219511 ] +*/ + SST_Math_Vec2fProject(&x,&y,&w); + TASSERT(fabsf((w.v[0])-(3.902439f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabsf((w.v[1])-(-3.121951f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _y failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec2fProjectLocal() +{ + SST_Vec2f x; /* 2 vector */ + SST_Vec2f y; /* 2 vector */ +/* Resetting test vectors */ + x.v[0] = -7.000000f; + x.v[1] = 3.000000f; + y.v[0] = 4.000000f; + y.v[1] = 18.000000f; +/* +[-7. 3.] +[ 4. 18.] +[ 0.30588236 1.37647069] +*/ + SST_Math_Vec2fProjectLocal(&x,&y); /* for accuracy */ + TASSERT(fabsf((x.v[0])-(0.305882f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabsf((x.v[1])-(1.376471f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _y failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec2fCross() +{ + SST_Vec2f x; /* 2 vector */ + SST_Vec2f y; /* 2 vector */ + SST_Vec2f w; /* 2 vector */ +/* Resetting test vectors */ + x.v[0] = -3.000000f; + x.v[1] = 2.000000f; + y.v[0] = -4.000000f; + y.v[1] = -20.000000f; + w.v[0] = 0.000000f; + w.v[1] = 0.000000f; +/* +[-3. 2.] +[ -4. -20.] +68.0 +*/ + SST_Math_Vec2fCross(&x,&y,&w); + TASSERT(fabsf((w.v[0])-(68.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabsf((w.v[1])-(68.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _y failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec2fCrossLocal() +{ + SST_Vec2f x; /* 2 vector */ + SST_Vec2f y; /* 2 vector */ +/* Resetting test vectors */ + x.v[0] = 3.000000f; + x.v[1] = -4.000000f; + y.v[0] = 17.000000f; + y.v[1] = 19.000000f; +/* +[ 3. -4.] +[ 17. 19.] +125.0 +*/ + SST_Math_Vec2fCrossLocal(&x,&y); /* for accuracy */ + TASSERT(fabsf((x.v[0])-(125.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabsf((x.v[1])-(125.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _y failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec2fMagnitude() +{ + SST_Vec2f x; /* 2 vector */ + float a; /* scalar */ +/* Resetting test vectors */ + x.v[0] = -4.000000f; + x.v[1] = -3.000000f; +/* +[-4. -3.] +5.0 +*/ + a = SST_Math_Vec2fMagnitude(&x); + TASSERT(fabsf((a)-(5.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Magnitude failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec2fMagnitudeSquared() +{ + SST_Vec2f x; /* 2 vector */ + float a; /* scalar */ +/* Resetting test vectors */ + x.v[0] = -2.000000f; + x.v[1] = 7.000000f; +/* +[-2. 7.] +53.0 +*/ + a = SST_Math_Vec2fMagnitudeSquared(&x); + TASSERT(fabsf((a)-(53.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"MagnitudeSquared failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec2fDot() +{ + SST_Vec2f x; /* 2 vector */ + SST_Vec2f y; /* 2 vector */ + float a; /* scalar */ +/* Resetting test vectors */ + x.v[0] = -7.000000f; + x.v[1] = -1.000000f; + y.v[0] = 13.000000f; + y.v[1] = -16.000000f; +/* +[-7. -1.] +-75.0 +*/ + a = SST_Math_Vec2fDot(&x,&y); + TASSERT(fabsf((a)-(-75.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Dot failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + diff --git a/ZTestSuite/Test-SST_Vec2i.cpp b/ZTestSuite/Test-SST_Vec2i.cpp new file mode 100644 index 0000000..a96a940 --- /dev/null +++ b/ZTestSuite/Test-SST_Vec2i.cpp @@ -0,0 +1,451 @@ +/* + AUTOMATICALLY GENERATED FILE - DO NOT EDIT! + Please change MatrixNxN.py and re-run it +*/ +/* Generated with ./VectorN.py n = 2, TYPE = int */ + +#include "ZUnitTest.hpp" +#include <float.h> +#include <math.h> +#include <stdlib.h> +#include <stdio.h> +#include <SST/SST_Vec2.h> + + + + +static const char* testSST_Math_Vec2iAdd(); +static const char* testSST_Math_Vec2iAddLocal(); +static const char* testSST_Math_Vec2iSubtract(); +static const char* testSST_Math_Vec2iSubtractLocal(); +static const char* testSST_Math_Vec2iMultiply(); +static const char* testSST_Math_Vec2iMultiplyLocal(); +static const char* testSST_Math_Vec2iScale(); +static const char* testSST_Math_Vec2iScaleLocal(); +static const char* testSST_Math_Vec2iDivide(); +static const char* testSST_Math_Vec2iDivideLocal(); +static const char* testSST_Math_Vec2iAbs(); +static const char* testSST_Math_Vec2iAbsLocal(); +static const char* testSST_Math_Vec2iNegate(); +static const char* testSST_Math_Vec2iNegateLocal(); +static const char* testSST_Math_Vec2iBias(); +static const char* testSST_Math_Vec2iBiasLocal(); +static const char* testSST_Math_Vec2iMagnitudeSquared(); +static const char* testSST_Math_Vec2iDot(); +// List of unit tests +ZUnitTest SST_Math_Vec2iUnitTests[] = +{ +{ "testSST_Math_Vec2iAdd " , testSST_Math_Vec2iAdd }, +{ "testSST_Math_Vec2iAddLocal " , testSST_Math_Vec2iAddLocal }, +{ "testSST_Math_Vec2iSubtract " , testSST_Math_Vec2iSubtract }, +{ "testSST_Math_Vec2iSubtractLocal " , testSST_Math_Vec2iSubtractLocal }, +{ "testSST_Math_Vec2iMultiply " , testSST_Math_Vec2iMultiply }, +{ "testSST_Math_Vec2iMultiplyLocal " , testSST_Math_Vec2iMultiplyLocal }, +{ "testSST_Math_Vec2iScale " , testSST_Math_Vec2iScale }, +{ "testSST_Math_Vec2iScaleLocal " , testSST_Math_Vec2iScaleLocal }, +{ "testSST_Math_Vec2iDivide " , testSST_Math_Vec2iDivide }, +{ "testSST_Math_Vec2iDivideLocal " , testSST_Math_Vec2iDivideLocal }, +{ "testSST_Math_Vec2iAbs " , testSST_Math_Vec2iAbs }, +{ "testSST_Math_Vec2iAbsLocal " , testSST_Math_Vec2iAbsLocal }, +{ "testSST_Math_Vec2iNegate " , testSST_Math_Vec2iNegate }, +{ "testSST_Math_Vec2iNegateLocal " , testSST_Math_Vec2iNegateLocal }, +{ "testSST_Math_Vec2iBias " , testSST_Math_Vec2iBias }, +{ "testSST_Math_Vec2iBiasLocal " , testSST_Math_Vec2iBiasLocal }, +{ "testSST_Math_Vec2iMagnitudeSquared " , testSST_Math_Vec2iMagnitudeSquared }, +{ "testSST_Math_Vec2iDot " , testSST_Math_Vec2iDot } +}; +DECLARE_ZTESTBLOCK(SST_Math_Vec2i) + +/******************************************************************************/ + +static const char* testSST_Math_Vec2iAdd() +{ + SST_Vec2i x; /* 2 vector */ + SST_Vec2i y; /* 2 vector */ + SST_Vec2i w; /* 2 vector */ +/* Resetting test vectors */ + x.v[0] = 14; + x.v[1] = -13; + y.v[0] = 6; + y.v[1] = -12; + w.v[0] = 0; + w.v[1] = 0; +/* +[ 14 -13] +[ 6 -12] +[ 20 -25] +*/ + SST_Math_Vec2iAdd(&x,&y,&w); + TASSERT((w.v[0])==(20),"Entry _x failed!"); + TASSERT((w.v[1])==(-25),"Entry _y failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec2iAddLocal() +{ + SST_Vec2i x; /* 2 vector */ + SST_Vec2i y; /* 2 vector */ +/* Resetting test vectors */ + x.v[0] = -10; + x.v[1] = -20; + y.v[0] = -6; + y.v[1] = 17; +/* +[-10 -20] +[-6 17] +[-16 -3] +*/ + SST_Math_Vec2iAddLocal(&x,&y); /* for accuracy */ + TASSERT((x.v[0])==(-16),"Entry _x failed!"); + TASSERT((x.v[1])==(-3),"Entry _y failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec2iSubtract() +{ + SST_Vec2i x; /* 2 vector */ + SST_Vec2i y; /* 2 vector */ + SST_Vec2i w; /* 2 vector */ +/* Resetting test vectors */ + x.v[0] = -3; + x.v[1] = -9; + y.v[0] = 9; + y.v[1] = -20; + w.v[0] = 0; + w.v[1] = 0; +/* +[-3 -9] +[ 9 -20] +[-12 11] +*/ + SST_Math_Vec2iSubtract(&x,&y,&w); + TASSERT((w.v[0])==(-12),"Entry _x failed!"); + TASSERT((w.v[1])==(11),"Entry _y failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec2iSubtractLocal() +{ + SST_Vec2i x; /* 2 vector */ + SST_Vec2i y; /* 2 vector */ +/* Resetting test vectors */ + x.v[0] = -8; + x.v[1] = 0; + y.v[0] = 14; + y.v[1] = 4; +/* +[-8 0] +[14 4] +[-22 -4] +*/ + SST_Math_Vec2iSubtractLocal(&x,&y); /* for accuracy */ + TASSERT((x.v[0])==(-22),"Entry _x failed!"); + TASSERT((x.v[1])==(-4),"Entry _y failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec2iMultiply() +{ + SST_Vec2i x; /* 2 vector */ + SST_Vec2i y; /* 2 vector */ + SST_Vec2i w; /* 2 vector */ +/* Resetting test vectors */ + x.v[0] = 15; + x.v[1] = 14; + y.v[0] = 16; + y.v[1] = 7; + w.v[0] = 0; + w.v[1] = 0; +/* +[15 14] +[16 7] +[240 98] +*/ + SST_Math_Vec2iMultiply(&x,&y,&w); + TASSERT((w.v[0])==(240),"Entry _x failed!"); + TASSERT((w.v[1])==(98),"Entry _y failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec2iMultiplyLocal() +{ + SST_Vec2i x; /* 2 vector */ + SST_Vec2i y; /* 2 vector */ +/* Resetting test vectors */ + x.v[0] = 2; + x.v[1] = -8; + y.v[0] = 13; + y.v[1] = -14; +/* +[ 2 -8] +[ 13 -14] +[ 26 112] +*/ + SST_Math_Vec2iMultiplyLocal(&x,&y); /* for accuracy */ + TASSERT((x.v[0])==(26),"Entry _x failed!"); + TASSERT((x.v[1])==(112),"Entry _y failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec2iDivide() +{ + SST_Vec2i x; /* 2 vector */ + SST_Vec2i y; /* 2 vector */ + SST_Vec2i w; /* 2 vector */ +/* Resetting test vectors */ + x.v[0] = 37; + x.v[1] = 28; + y.v[0] = 16; + y.v[1] = 7; + w.v[0] = 0; + w.v[1] = 0; +/* +[37 28] +[16 7] +[2 4] +*/ + SST_Math_Vec2iDivide(&x,&y,&w); + TASSERT((w.v[0])==(2),"Entry _x failed!"); + TASSERT((w.v[1])==(4),"Entry _y failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec2iDivideLocal() +{ + SST_Vec2i x; /* 2 vector */ + SST_Vec2i y; /* 2 vector */ +/* Resetting test vectors */ + x.v[0] = 15; + x.v[1] = 25; + y.v[0] = 19; + y.v[1] = 1; +/* +[15 25] +[19 1] +[ 0 25] +*/ + SST_Math_Vec2iDivideLocal(&x,&y); /* for accuracy */ + TASSERT((x.v[0])==(0),"Entry _x failed!"); + TASSERT((x.v[1])==(25),"Entry _y failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec2iScale() +{ + SST_Vec2i x; /* 2 vector */ + SST_Vec2i w; /* 2 vector */ + int a; /* scalar */ +/* Resetting test vectors */ + x.v[0] = -14; + x.v[1] = 0; + w.v[0] = 0; + w.v[1] = 0; + a = 2; +/* +[-14 0] +[-28 0] +*/ + SST_Math_Vec2iScale(&x,a,&w); + TASSERT((w.v[0])==(-28),"Entry _x failed!"); + TASSERT((w.v[1])==(0),"Entry _y failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec2iScaleLocal() +{ + SST_Vec2i x; /* 2 vector */ + int a; /* scalar */ +/* Resetting test vectors */ + x.v[0] = -20; + x.v[1] = -1; + a = 2; +/* +[-20 -1] +[-40 -2] +*/ + SST_Math_Vec2iScaleLocal(&x,a); /* for accuracy */ + TASSERT((x.v[0])==(-40),"Entry _x failed!"); + TASSERT((x.v[1])==(-2),"Entry _y failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec2iAbs() +{ + SST_Vec2i x; /* 2 vector */ + SST_Vec2i w; /* 2 vector */ +/* Resetting test vectors */ + x.v[0] = -13; + x.v[1] = 6; + w.v[0] = 0; + w.v[1] = 0; +/* +[-13 6] +[13 6] +*/ + SST_Math_Vec2iAbs(&x,&w); + TASSERT((w.v[0])==(13),"Entry _x failed!"); + TASSERT((w.v[1])==(6),"Entry _y failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec2iAbsLocal() +{ + SST_Vec2i x; /* 2 vector */ +/* Resetting test vectors */ + x.v[0] = 12; + x.v[1] = 16; +/* +[12 16] +[12 16] +*/ + SST_Math_Vec2iAbsLocal(&x); /* for accuracy */ + TASSERT((x.v[0])==(12),"Entry _x failed!"); + TASSERT((x.v[1])==(16),"Entry _y failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec2iBias() +{ + SST_Vec2i x; /* 2 vector */ + SST_Vec2i w; /* 2 vector */ + int a; /* scalar */ +/* Resetting test vectors */ + x.v[0] = -10; + x.v[1] = 5; + w.v[0] = 0; + w.v[1] = 0; + a = -8; +/* +[-10 5] +[-20 10] +*/ + SST_Math_Vec2iBias(&x,a,&w); + TASSERT((w.v[0])==(-18),"Entry _x failed!"); + TASSERT((w.v[1])==(-3),"Entry _y failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec2iBiasLocal() +{ + SST_Vec2i x; /* 2 vector */ + int a; /* scalar */ +/* Resetting test vectors */ + x.v[0] = 7; + x.v[1] = -9; + a = -6; +/* +[ 7 -9] +[ 14 -18] +*/ + SST_Math_Vec2iBiasLocal(&x,a); /* for accuracy */ + TASSERT((x.v[0])==(1),"Entry _x failed!"); + TASSERT((x.v[1])==(-15),"Entry _y failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec2iNegate() +{ + SST_Vec2i x; /* 2 vector */ + SST_Vec2i w; /* 2 vector */ +/* Resetting test vectors */ + x.v[0] = -4; + x.v[1] = 9; + w.v[0] = 0; + w.v[1] = 0; +/* +[-4 9] +[ 4 -9] +*/ + SST_Math_Vec2iNegate(&x,&w); + TASSERT((w.v[0])==(4),"Entry _x failed!"); + TASSERT((w.v[1])==(-9),"Entry _y failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec2iNegateLocal() +{ + SST_Vec2i x; /* 2 vector */ +/* Resetting test vectors */ + x.v[0] = -8; + x.v[1] = 2; +/* +[-8 2] +[ 8 -2] +*/ + SST_Math_Vec2iNegateLocal(&x); /* for accuracy */ + TASSERT((x.v[0])==(8),"Entry _x failed!"); + TASSERT((x.v[1])==(-2),"Entry _y failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec2iMagnitudeSquared() +{ + SST_Vec2i x; /* 2 vector */ + int a; /* scalar */ +/* Resetting test vectors */ + x.v[0] = -20; + x.v[1] = -4; +/* +[-20 -4] +416 +*/ + a = SST_Math_Vec2iMagnitudeSquared(&x); + TASSERT((a)==(416),"MagnitudeSquared failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec2iDot() +{ + SST_Vec2i x; /* 2 vector */ + SST_Vec2i y; /* 2 vector */ + int a; /* scalar */ +/* Resetting test vectors */ + x.v[0] = 16; + x.v[1] = 11; + y.v[0] = 0; + y.v[1] = 8; +/* +[16 11] +88 +*/ + a = SST_Math_Vec2iDot(&x,&y); + TASSERT((a)==(88),"Dot failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + diff --git a/ZTestSuite/Test-SST_Vec2u.cpp b/ZTestSuite/Test-SST_Vec2u.cpp new file mode 100644 index 0000000..628a876 --- /dev/null +++ b/ZTestSuite/Test-SST_Vec2u.cpp @@ -0,0 +1,318 @@ +/* + AUTOMATICALLY GENERATED FILE - DO NOT EDIT! + Please change MatrixNxN.py and re-run it +*/ +/* Generated with ./VectorN.py n = 2, TYPE = unsigned int */ + +#include "ZUnitTest.hpp" +#include <float.h> +#include <math.h> +#include <stdlib.h> +#include <stdio.h> +#include <SST/SST_Vec2.h> + + + + +static const char* testSST_Math_Vec2uAdd(); +static const char* testSST_Math_Vec2uAddLocal(); +static const char* testSST_Math_Vec2uSubtract(); +static const char* testSST_Math_Vec2uSubtractLocal(); +static const char* testSST_Math_Vec2uMultiply(); +static const char* testSST_Math_Vec2uMultiplyLocal(); +static const char* testSST_Math_Vec2uScale(); +static const char* testSST_Math_Vec2uScaleLocal(); +static const char* testSST_Math_Vec2uDivide(); +static const char* testSST_Math_Vec2uDivideLocal(); +static const char* testSST_Math_Vec2uMagnitudeSquared(); +static const char* testSST_Math_Vec2uDot(); +// List of unit tests +ZUnitTest SST_Math_Vec2uUnitTests[] = +{ +{ "testSST_Math_Vec2uAdd " , testSST_Math_Vec2uAdd }, +{ "testSST_Math_Vec2uAddLocal " , testSST_Math_Vec2uAddLocal }, +{ "testSST_Math_Vec2uSubtract " , testSST_Math_Vec2uSubtract }, +{ "testSST_Math_Vec2uSubtractLocal " , testSST_Math_Vec2uSubtractLocal }, +{ "testSST_Math_Vec2uMultiply " , testSST_Math_Vec2uMultiply }, +{ "testSST_Math_Vec2uMultiplyLocal " , testSST_Math_Vec2uMultiplyLocal }, +{ "testSST_Math_Vec2uScale " , testSST_Math_Vec2uScale }, +{ "testSST_Math_Vec2uScaleLocal " , testSST_Math_Vec2uScaleLocal }, +{ "testSST_Math_Vec2uDivide " , testSST_Math_Vec2uDivide }, +{ "testSST_Math_Vec2uDivideLocal " , testSST_Math_Vec2uDivideLocal }, +{ "testSST_Math_Vec2uMagnitudeSquared " , testSST_Math_Vec2uMagnitudeSquared }, +{ "testSST_Math_Vec2uDot " , testSST_Math_Vec2uDot } +}; +DECLARE_ZTESTBLOCK(SST_Math_Vec2u) + +/******************************************************************************/ + +static const char* testSST_Math_Vec2uAdd() +{ + SST_Vec2u x; /* 2 vector */ + SST_Vec2u y; /* 2 vector */ + SST_Vec2u w; /* 2 vector */ +/* Resetting test vectors */ + x.v[0] = 35; + x.v[1] = 32; + y.v[0] = 4; + y.v[1] = 17; + w.v[0] = 0; + w.v[1] = 0; +/* +[35 32] +[ 4 17] +[39 49] +*/ + SST_Math_Vec2uAdd(&x,&y,&w); + TASSERT((w.v[0])==(39),"Entry _x failed!"); + TASSERT((w.v[1])==(49),"Entry _y failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec2uAddLocal() +{ + SST_Vec2u x; /* 2 vector */ + SST_Vec2u y; /* 2 vector */ +/* Resetting test vectors */ + x.v[0] = 10; + x.v[1] = 35; + y.v[0] = 6; + y.v[1] = 39; +/* +[10 35] +[ 6 39] +[16 74] +*/ + SST_Math_Vec2uAddLocal(&x,&y); /* for accuracy */ + TASSERT((x.v[0])==(16),"Entry _x failed!"); + TASSERT((x.v[1])==(74),"Entry _y failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec2uSubtract() +{ + SST_Vec2u x; /* 2 vector */ + SST_Vec2u y; /* 2 vector */ + SST_Vec2u w; /* 2 vector */ +/* Resetting test vectors */ + x.v[0] = 36; + x.v[1] = 37; + y.v[0] = 39; + y.v[1] = 33; + w.v[0] = 0; + w.v[1] = 0; +/* +[36 37] +[39 33] +[4294967293 4] +*/ + SST_Math_Vec2uSubtract(&x,&y,&w); + TASSERT((w.v[0])==(4294967293),"Entry _x failed!"); + TASSERT((w.v[1])==(4),"Entry _y failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec2uSubtractLocal() +{ + SST_Vec2u x; /* 2 vector */ + SST_Vec2u y; /* 2 vector */ +/* Resetting test vectors */ + x.v[0] = 16; + x.v[1] = 26; + y.v[0] = 29; + y.v[1] = 29; +/* +[16 26] +[29 29] +[4294967283 4294967293] +*/ + SST_Math_Vec2uSubtractLocal(&x,&y); /* for accuracy */ + TASSERT((x.v[0])==(4294967283),"Entry _x failed!"); + TASSERT((x.v[1])==(4294967293),"Entry _y failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec2uMultiply() +{ + SST_Vec2u x; /* 2 vector */ + SST_Vec2u y; /* 2 vector */ + SST_Vec2u w; /* 2 vector */ +/* Resetting test vectors */ + x.v[0] = 25; + x.v[1] = 37; + y.v[0] = 26; + y.v[1] = 17; + w.v[0] = 0; + w.v[1] = 0; +/* +[25 37] +[26 17] +[650 629] +*/ + SST_Math_Vec2uMultiply(&x,&y,&w); + TASSERT((w.v[0])==(650),"Entry _x failed!"); + TASSERT((w.v[1])==(629),"Entry _y failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec2uMultiplyLocal() +{ + SST_Vec2u x; /* 2 vector */ + SST_Vec2u y; /* 2 vector */ +/* Resetting test vectors */ + x.v[0] = 38; + x.v[1] = 39; + y.v[0] = 10; + y.v[1] = 10; +/* +[38 39] +[10 10] +[380 390] +*/ + SST_Math_Vec2uMultiplyLocal(&x,&y); /* for accuracy */ + TASSERT((x.v[0])==(380),"Entry _x failed!"); + TASSERT((x.v[1])==(390),"Entry _y failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec2uDivide() +{ + SST_Vec2u x; /* 2 vector */ + SST_Vec2u y; /* 2 vector */ + SST_Vec2u w; /* 2 vector */ +/* Resetting test vectors */ + x.v[0] = 13; + x.v[1] = 12; + y.v[0] = 34; + y.v[1] = 8; + w.v[0] = 0; + w.v[1] = 0; +/* +[13 12] +[34 8] +[0 1] +*/ + SST_Math_Vec2uDivide(&x,&y,&w); + TASSERT((w.v[0])==(0),"Entry _x failed!"); + TASSERT((w.v[1])==(1),"Entry _y failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec2uDivideLocal() +{ + SST_Vec2u x; /* 2 vector */ + SST_Vec2u y; /* 2 vector */ +/* Resetting test vectors */ + x.v[0] = 12; + x.v[1] = 11; + y.v[0] = 24; + y.v[1] = 22; +/* +[12 11] +[24 22] +[0 0] +*/ + SST_Math_Vec2uDivideLocal(&x,&y); /* for accuracy */ + TASSERT((x.v[0])==(0),"Entry _x failed!"); + TASSERT((x.v[1])==(0),"Entry _y failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec2uScale() +{ + SST_Vec2u x; /* 2 vector */ + SST_Vec2u w; /* 2 vector */ + unsigned int a; /* scalar */ +/* Resetting test vectors */ + x.v[0] = 7; + x.v[1] = 31; + w.v[0] = 0; + w.v[1] = 0; + a = 2; +/* +[ 7 31] +[14 62] +*/ + SST_Math_Vec2uScale(&x,a,&w); + TASSERT((w.v[0])==(14),"Entry _x failed!"); + TASSERT((w.v[1])==(62),"Entry _y failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec2uScaleLocal() +{ + SST_Vec2u x; /* 2 vector */ + unsigned int a; /* scalar */ +/* Resetting test vectors */ + x.v[0] = 15; + x.v[1] = 39; + a = 2; +/* +[15 39] +[30 78] +*/ + SST_Math_Vec2uScaleLocal(&x,a); /* for accuracy */ + TASSERT((x.v[0])==(30),"Entry _x failed!"); + TASSERT((x.v[1])==(78),"Entry _y failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec2uMagnitudeSquared() +{ + SST_Vec2u x; /* 2 vector */ + unsigned int a; /* scalar */ +/* Resetting test vectors */ + x.v[0] = 37; + x.v[1] = 27; +/* +[37 27] +2098 +*/ + a = SST_Math_Vec2uMagnitudeSquared(&x); + TASSERT((a)==(2098),"MagnitudeSquared failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec2uDot() +{ + SST_Vec2u x; /* 2 vector */ + SST_Vec2u y; /* 2 vector */ + unsigned int a; /* scalar */ +/* Resetting test vectors */ + x.v[0] = 10; + x.v[1] = 5; + y.v[0] = 2; + y.v[1] = 11; +/* +[10 5] +75 +*/ + a = SST_Math_Vec2uDot(&x,&y); + TASSERT((a)==(75),"Dot failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + diff --git a/ZTestSuite/Test-SST_Vec3d.cpp b/ZTestSuite/Test-SST_Vec3d.cpp new file mode 100644 index 0000000..4d28a32 --- /dev/null +++ b/ZTestSuite/Test-SST_Vec3d.cpp @@ -0,0 +1,888 @@ +/* + AUTOMATICALLY GENERATED FILE - DO NOT EDIT! + Please change MatrixNxN.py and re-run it +*/ +/* Generated with ./VectorN.py n = 3, TYPE = double */ + +#include "ZUnitTest.hpp" +#include <float.h> +#include <math.h> +#include <stdlib.h> +#include <stdio.h> +#include <SST/SST_Vec3.h> + + + + +static const char* testSST_Math_Vec3dAdd(); +static const char* testSST_Math_Vec3dAddLocal(); +static const char* testSST_Math_Vec3dSubtract(); +static const char* testSST_Math_Vec3dSubtractLocal(); +static const char* testSST_Math_Vec3dMultiply(); +static const char* testSST_Math_Vec3dMultiplyLocal(); +static const char* testSST_Math_Vec3dScale(); +static const char* testSST_Math_Vec3dScaleLocal(); +static const char* testSST_Math_Vec3dDivide(); +static const char* testSST_Math_Vec3dDivideLocal(); +static const char* testSST_Math_Vec3dAbs(); +static const char* testSST_Math_Vec3dAbsLocal(); +static const char* testSST_Math_Vec3dNegate(); +static const char* testSST_Math_Vec3dNegateLocal(); +static const char* testSST_Math_Vec3dBias(); +static const char* testSST_Math_Vec3dBiasLocal(); +static const char* testSST_Math_Vec3dRecip(); +static const char* testSST_Math_Vec3dRecipLocal(); +static const char* testSST_Math_Vec3dRecipSqrt(); +static const char* testSST_Math_Vec3dRecipSqrtLocal(); +static const char* testSST_Math_Vec3dSqrt(); +static const char* testSST_Math_Vec3dSqrtLocal(); +static const char* testSST_Math_Vec3dSqrt(); +static const char* testSST_Math_Vec3dSqrtLocal(); +static const char* testSST_Math_Vec3dCross(); +static const char* testSST_Math_Vec3dCrossLocal(); +static const char* testSST_Math_Vec3dRotateAbout(); +static const char* testSST_Math_Vec3dRotateAboutLocal(); +static const char* testSST_Math_Vec3dProject(); +static const char* testSST_Math_Vec3dProjectLocal(); +static const char* testSST_Math_Vec3dMagnitude(); +static const char* testSST_Math_Vec3dNormalize(); +static const char* testSST_Math_Vec3dNormalizeLocal(); +static const char* testSST_Math_Vec3dMagnitudeSquared(); +static const char* testSST_Math_Vec3dDot(); +// List of unit tests +ZUnitTest SST_Math_Vec3dUnitTests[] = +{ +{ "testSST_Math_Vec3dAdd " , testSST_Math_Vec3dAdd }, +{ "testSST_Math_Vec3dAddLocal " , testSST_Math_Vec3dAddLocal }, +{ "testSST_Math_Vec3dSubtract " , testSST_Math_Vec3dSubtract }, +{ "testSST_Math_Vec3dSubtractLocal " , testSST_Math_Vec3dSubtractLocal }, +{ "testSST_Math_Vec3dMultiply " , testSST_Math_Vec3dMultiply }, +{ "testSST_Math_Vec3dMultiplyLocal " , testSST_Math_Vec3dMultiplyLocal }, +{ "testSST_Math_Vec3dScale " , testSST_Math_Vec3dScale }, +{ "testSST_Math_Vec3dScaleLocal " , testSST_Math_Vec3dScaleLocal }, +{ "testSST_Math_Vec3dDivide " , testSST_Math_Vec3dDivide }, +{ "testSST_Math_Vec3dDivideLocal " , testSST_Math_Vec3dDivideLocal }, +{ "testSST_Math_Vec3dAbs " , testSST_Math_Vec3dAbs }, +{ "testSST_Math_Vec3dAbsLocal " , testSST_Math_Vec3dAbsLocal }, +{ "testSST_Math_Vec3dNegate " , testSST_Math_Vec3dNegate }, +{ "testSST_Math_Vec3dNegateLocal " , testSST_Math_Vec3dNegateLocal }, +{ "testSST_Math_Vec3dBias " , testSST_Math_Vec3dBias }, +{ "testSST_Math_Vec3dBiasLocal " , testSST_Math_Vec3dBiasLocal }, +{ "testSST_Math_Vec3dRecip " , testSST_Math_Vec3dRecip }, +{ "testSST_Math_Vec3dRecipLocal " , testSST_Math_Vec3dRecipLocal }, +{ "testSST_Math_Vec3dRecipSqrt " , testSST_Math_Vec3dRecipSqrt }, +{ "testSST_Math_Vec3dRecipSqrtLocal " , testSST_Math_Vec3dRecipSqrtLocal }, +{ "testSST_Math_Vec3dSqrt " , testSST_Math_Vec3dSqrt }, +{ "testSST_Math_Vec3dSqrtLocal " , testSST_Math_Vec3dSqrtLocal }, +{ "testSST_Math_Vec3dSqrt " , testSST_Math_Vec3dSqrt }, +{ "testSST_Math_Vec3dSqrtLocal " , testSST_Math_Vec3dSqrtLocal }, +{ "testSST_Math_Vec3dMagnitude " , testSST_Math_Vec3dMagnitude }, +{ "testSST_Math_Vec3dNormalize " , testSST_Math_Vec3dNormalize }, +{ "testSST_Math_Vec3dNormalizeLocal " , testSST_Math_Vec3dNormalizeLocal }, +{ "testSST_Math_Vec3dCross " , testSST_Math_Vec3dCross }, +{ "testSST_Math_Vec3dCrossLocal " , testSST_Math_Vec3dCrossLocal }, +{ "testSST_Math_Vec3dRotateAbout " , testSST_Math_Vec3dRotateAbout }, +{ "testSST_Math_Vec3dRotateAboutLocal " , testSST_Math_Vec3dRotateAboutLocal }, +{ "testSST_Math_Vec3dProject " , testSST_Math_Vec3dProject }, +{ "testSST_Math_Vec3dProjectLocal " , testSST_Math_Vec3dProjectLocal }, +{ "testSST_Math_Vec3dMagnitudeSquared " , testSST_Math_Vec3dMagnitudeSquared }, +{ "testSST_Math_Vec3dDot " , testSST_Math_Vec3dDot } +}; +DECLARE_ZTESTBLOCK(SST_Math_Vec3d) + +/******************************************************************************/ + +static const char* testSST_Math_Vec3dAdd() +{ + SST_Vec3d x; /* 3 vector */ + SST_Vec3d y; /* 3 vector */ + SST_Vec3d w; /* 3 vector */ +/* Resetting test vectors */ + x.v[0] = -1.0000000000000000; + x.v[1] = -8.0000000000000000; + x.v[2] = -5.0000000000000000; + y.v[0] = 9.0000000000000000; + y.v[1] = -4.0000000000000000; + y.v[2] = -18.0000000000000000; + w.v[0] = 0.0000000000000000; + w.v[1] = 0.0000000000000000; + w.v[2] = 0.0000000000000000; +/* +[-1. -8. -5.] +[ 9. -4. -18.] +[ 8. -12. -23.] +*/ + SST_Math_Vec3dAdd(&x,&y,&w); + TASSERT(fabs((w.v[0])-( 8.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabs((w.v[1])-( -12.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _y failed!"); + TASSERT(fabs((w.v[2])-( -23.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _z failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec3dAddLocal() +{ + SST_Vec3d x; /* 3 vector */ + SST_Vec3d y; /* 3 vector */ +/* Resetting test vectors */ + x.v[0] = -13.0000000000000000; + x.v[1] = -4.0000000000000000; + x.v[2] = 8.0000000000000000; + y.v[0] = -6.0000000000000000; + y.v[1] = 9.0000000000000000; + y.v[2] = -17.0000000000000000; +/* +[-13. -4. 8.] +[ -6. 9. -17.] +[-19. 5. -9.] +*/ + SST_Math_Vec3dAddLocal(&x,&y); /* for accuracy */ + TASSERT(fabs((x.v[0])-( -19.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabs((x.v[1])-( 5.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _y failed!"); + TASSERT(fabs((x.v[2])-( -9.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _z failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec3dSubtract() +{ + SST_Vec3d x; /* 3 vector */ + SST_Vec3d y; /* 3 vector */ + SST_Vec3d w; /* 3 vector */ +/* Resetting test vectors */ + x.v[0] = 12.0000000000000000; + x.v[1] = 14.0000000000000000; + x.v[2] = 2.0000000000000000; + y.v[0] = 4.0000000000000000; + y.v[1] = -8.0000000000000000; + y.v[2] = 3.0000000000000000; + w.v[0] = 0.0000000000000000; + w.v[1] = 0.0000000000000000; + w.v[2] = 0.0000000000000000; +/* +[ 12. 14. 2.] +[ 4. -8. 3.] +[ 8. 22. -1.] +*/ + SST_Math_Vec3dSubtract(&x,&y,&w); + TASSERT(fabs((w.v[0])-( 8.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabs((w.v[1])-( 22.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _y failed!"); + TASSERT(fabs((w.v[2])-( -1.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _z failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec3dSubtractLocal() +{ + SST_Vec3d x; /* 3 vector */ + SST_Vec3d y; /* 3 vector */ +/* Resetting test vectors */ + x.v[0] = -13.0000000000000000; + x.v[1] = -3.0000000000000000; + x.v[2] = -7.0000000000000000; + y.v[0] = 13.0000000000000000; + y.v[1] = 13.0000000000000000; + y.v[2] = -12.0000000000000000; +/* +[-13. -3. -7.] +[ 13. 13. -12.] +[-26. -16. 5.] +*/ + SST_Math_Vec3dSubtractLocal(&x,&y); /* for accuracy */ + TASSERT(fabs((x.v[0])-( -26.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabs((x.v[1])-( -16.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _y failed!"); + TASSERT(fabs((x.v[2])-( 5.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _z failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec3dMultiply() +{ + SST_Vec3d x; /* 3 vector */ + SST_Vec3d y; /* 3 vector */ + SST_Vec3d w; /* 3 vector */ +/* Resetting test vectors */ + x.v[0] = -17.0000000000000000; + x.v[1] = -13.0000000000000000; + x.v[2] = 19.0000000000000000; + y.v[0] = 10.0000000000000000; + y.v[1] = 2.0000000000000000; + y.v[2] = -2.0000000000000000; + w.v[0] = 0.0000000000000000; + w.v[1] = 0.0000000000000000; + w.v[2] = 0.0000000000000000; +/* +[-17. -13. 19.] +[ 10. 2. -2.] +[-170. -26. -38.] +*/ + SST_Math_Vec3dMultiply(&x,&y,&w); + TASSERT(fabs((w.v[0])-( -170.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabs((w.v[1])-( -26.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _y failed!"); + TASSERT(fabs((w.v[2])-( -38.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _z failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec3dMultiplyLocal() +{ + SST_Vec3d x; /* 3 vector */ + SST_Vec3d y; /* 3 vector */ +/* Resetting test vectors */ + x.v[0] = -2.0000000000000000; + x.v[1] = -17.0000000000000000; + x.v[2] = 7.0000000000000000; + y.v[0] = -11.0000000000000000; + y.v[1] = -17.0000000000000000; + y.v[2] = 5.0000000000000000; +/* +[ -2. -17. 7.] +[-11. -17. 5.] +[ 22. 289. 35.] +*/ + SST_Math_Vec3dMultiplyLocal(&x,&y); /* for accuracy */ + TASSERT(fabs((x.v[0])-( 22.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabs((x.v[1])-( 289.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _y failed!"); + TASSERT(fabs((x.v[2])-( 35.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _z failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec3dDivide() +{ + SST_Vec3d x; /* 3 vector */ + SST_Vec3d y; /* 3 vector */ + SST_Vec3d w; /* 3 vector */ +/* Resetting test vectors */ + x.v[0] = 7.0000000000000000; + x.v[1] = 25.0000000000000000; + x.v[2] = 8.0000000000000000; + y.v[0] = 22.0000000000000000; + y.v[1] = 33.0000000000000000; + y.v[2] = 3.0000000000000000; + w.v[0] = 0.0000000000000000; + w.v[1] = 0.0000000000000000; + w.v[2] = 0.0000000000000000; +/* +[ 7. 25. 8.] +[ 22. 33. 3.] +[ 0.31818182 0.75757576 2.66666667] +*/ + SST_Math_Vec3dDivide(&x,&y,&w); + TASSERT(fabs((w.v[0])-( 0.3181818181818182)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabs((w.v[1])-( 0.7575757575757576)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _y failed!"); + TASSERT(fabs((w.v[2])-( 2.6666666666666665)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _z failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec3dDivideLocal() +{ + SST_Vec3d x; /* 3 vector */ + SST_Vec3d y; /* 3 vector */ +/* Resetting test vectors */ + x.v[0] = 10.0000000000000000; + x.v[1] = 24.0000000000000000; + x.v[2] = 14.0000000000000000; + y.v[0] = 17.0000000000000000; + y.v[1] = 39.0000000000000000; + y.v[2] = 28.0000000000000000; +/* +[ 10. 24. 14.] +[ 17. 39. 28.] +[ 0.58823529 0.61538462 0.5 ] +*/ + SST_Math_Vec3dDivideLocal(&x,&y); /* for accuracy */ + TASSERT(fabs((x.v[0])-( 0.5882352941176471)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabs((x.v[1])-( 0.6153846153846154)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _y failed!"); + TASSERT(fabs((x.v[2])-( 0.5000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _z failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec3dScale() +{ + SST_Vec3d x; /* 3 vector */ + SST_Vec3d w; /* 3 vector */ + double a; /* scalar */ +/* Resetting test vectors */ + x.v[0] = -4.0000000000000000; + x.v[1] = -8.0000000000000000; + x.v[2] = 1.0000000000000000; + w.v[0] = 0.0000000000000000; + w.v[1] = 0.0000000000000000; + w.v[2] = 0.0000000000000000; + a = 2.0000000000000000; +/* +[-4. -8. 1.] +[ -8. -16. 2.] +*/ + SST_Math_Vec3dScale(&x,a,&w); + TASSERT(fabs((w.v[0])-( -8.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabs((w.v[1])-( -16.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _y failed!"); + TASSERT(fabs((w.v[2])-( 2.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _z failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec3dScaleLocal() +{ + SST_Vec3d x; /* 3 vector */ + double a; /* scalar */ +/* Resetting test vectors */ + x.v[0] = -2.0000000000000000; + x.v[1] = -4.0000000000000000; + x.v[2] = 17.0000000000000000; + a = 2.0000000000000000; +/* +[ -2. -4. 17.] +[ -4. -8. 34.] +*/ + SST_Math_Vec3dScaleLocal(&x,a); /* for accuracy */ + TASSERT(fabs((x.v[0])-( -4.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabs((x.v[1])-( -8.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _y failed!"); + TASSERT(fabs((x.v[2])-( 34.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _z failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec3dAbs() +{ + SST_Vec3d x; /* 3 vector */ + SST_Vec3d w; /* 3 vector */ +/* Resetting test vectors */ + x.v[0] = -2.0000000000000000; + x.v[1] = -11.0000000000000000; + x.v[2] = -19.0000000000000000; + w.v[0] = 0.0000000000000000; + w.v[1] = 0.0000000000000000; + w.v[2] = 0.0000000000000000; +/* +[ -2. -11. -19.] +[ 2. 11. 19.] +*/ + SST_Math_Vec3dAbs(&x,&w); + TASSERT(fabs((w.v[0])-( 2.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabs((w.v[1])-( 11.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _y failed!"); + TASSERT(fabs((w.v[2])-( 19.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _z failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec3dAbsLocal() +{ + SST_Vec3d x; /* 3 vector */ +/* Resetting test vectors */ + x.v[0] = -18.0000000000000000; + x.v[1] = -3.0000000000000000; + x.v[2] = -12.0000000000000000; +/* +[-18. -3. -12.] +[ 18. 3. 12.] +*/ + SST_Math_Vec3dAbsLocal(&x); /* for accuracy */ + TASSERT(fabs((x.v[0])-( 18.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabs((x.v[1])-( 3.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _y failed!"); + TASSERT(fabs((x.v[2])-( 12.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _z failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec3dBias() +{ + SST_Vec3d x; /* 3 vector */ + SST_Vec3d w; /* 3 vector */ + double a; /* scalar */ +/* Resetting test vectors */ + x.v[0] = -20.0000000000000000; + x.v[1] = -9.0000000000000000; + x.v[2] = 13.0000000000000000; + w.v[0] = 0.0000000000000000; + w.v[1] = 0.0000000000000000; + w.v[2] = 0.0000000000000000; + a = 15.0000000000000000; +/* +[-20. -9. 13.] +[-40. -18. 26.] +*/ + SST_Math_Vec3dBias(&x,a,&w); + TASSERT(fabs((w.v[0])-( -5.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabs((w.v[1])-( 6.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _y failed!"); + TASSERT(fabs((w.v[2])-( 28.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _z failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec3dBiasLocal() +{ + SST_Vec3d x; /* 3 vector */ + double a; /* scalar */ +/* Resetting test vectors */ + x.v[0] = -4.0000000000000000; + x.v[1] = -6.0000000000000000; + x.v[2] = -7.0000000000000000; + a = -20.0000000000000000; +/* +[-4. -6. -7.] +[ -8. -12. -14.] +*/ + SST_Math_Vec3dBiasLocal(&x,a); /* for accuracy */ + TASSERT(fabs((x.v[0])-( -24.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabs((x.v[1])-( -26.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _y failed!"); + TASSERT(fabs((x.v[2])-( -27.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _z failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec3dNegate() +{ + SST_Vec3d x; /* 3 vector */ + SST_Vec3d w; /* 3 vector */ +/* Resetting test vectors */ + x.v[0] = 5.0000000000000000; + x.v[1] = -2.0000000000000000; + x.v[2] = -17.0000000000000000; + w.v[0] = 0.0000000000000000; + w.v[1] = 0.0000000000000000; + w.v[2] = 0.0000000000000000; +/* +[ 5. -2. -17.] +[ -5. 2. 17.] +*/ + SST_Math_Vec3dNegate(&x,&w); + TASSERT(fabs((w.v[0])-( -5.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabs((w.v[1])-( 2.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _y failed!"); + TASSERT(fabs((w.v[2])-( 17.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _z failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec3dNegateLocal() +{ + SST_Vec3d x; /* 3 vector */ +/* Resetting test vectors */ + x.v[0] = -5.0000000000000000; + x.v[1] = -20.0000000000000000; + x.v[2] = 2.0000000000000000; +/* +[ -5. -20. 2.] +[ 5. 20. -2.] +*/ + SST_Math_Vec3dNegateLocal(&x); /* for accuracy */ + TASSERT(fabs((x.v[0])-( 5.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabs((x.v[1])-( 20.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _y failed!"); + TASSERT(fabs((x.v[2])-( -2.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _z failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec3dSqrt() +{ + SST_Vec3d x; /* 3 vector */ + SST_Vec3d w; /* 3 vector */ +/* Resetting test vectors */ + x.v[0] = 20.0000000000000000; + x.v[1] = 25.0000000000000000; + x.v[2] = 27.0000000000000000; + w.v[0] = 0.0000000000000000; + w.v[1] = 0.0000000000000000; + w.v[2] = 0.0000000000000000; +/* +[ 20. 25. 27.] +[ 4.47213595 5. 5.19615242] +*/ + SST_Math_Vec3dSqrt(&x,&w); + TASSERT(fabs((w.v[0])-( 4.4721359549995796)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabs((w.v[1])-( 5.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _y failed!"); + TASSERT(fabs((w.v[2])-( 5.1961524227066320)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _z failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec3dSqrtLocal() +{ + SST_Vec3d x; /* 3 vector */ +/* Resetting test vectors */ + x.v[0] = 8.0000000000000000; + x.v[1] = 13.0000000000000000; + x.v[2] = 4.0000000000000000; +/* +[ 8. 13. 4.] +[ 2.82842712 3.60555128 2. ] +*/ + SST_Math_Vec3dSqrtLocal(&x); /* for accuracy */ + TASSERT(fabs((x.v[0])-( 2.8284271247461903)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabs((x.v[1])-( 3.6055512754639891)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _y failed!"); + TASSERT(fabs((x.v[2])-( 2.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _z failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec3dRecipSqrt() +{ + SST_Vec3d x; /* 3 vector */ + SST_Vec3d w; /* 3 vector */ +/* Resetting test vectors */ + x.v[0] = 19.0000000000000000; + x.v[1] = 28.0000000000000000; + x.v[2] = 10.0000000000000000; + w.v[0] = 0.0000000000000000; + w.v[1] = 0.0000000000000000; + w.v[2] = 0.0000000000000000; +/* +[ 19. 28. 10.] +[ 0.22941573 0.18898224 0.31622777] +*/ + SST_Math_Vec3dRecipSqrt(&x,&w); + TASSERT(fabs((w.v[0])-( 0.2294157338705617)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabs((w.v[1])-( 0.1889822365046136)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _y failed!"); + TASSERT(fabs((w.v[2])-( 0.3162277660168379)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _z failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec3dRecipSqrtLocal() +{ + SST_Vec3d x; /* 3 vector */ +/* Resetting test vectors */ + x.v[0] = 26.0000000000000000; + x.v[1] = 12.0000000000000000; + x.v[2] = 37.0000000000000000; +/* +[ 26. 12. 37.] +[ 0.19611614 0.28867513 0.16439899] +*/ + SST_Math_Vec3dRecipSqrtLocal(&x); /* for accuracy */ + TASSERT(fabs((x.v[0])-( 0.1961161351381840)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabs((x.v[1])-( 0.2886751345948129)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _y failed!"); + TASSERT(fabs((x.v[2])-( 0.1643989873053573)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _z failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec3dRecip() +{ + SST_Vec3d x; /* 3 vector */ + SST_Vec3d w; /* 3 vector */ +/* Resetting test vectors */ + x.v[0] = 5.0000000000000000; + x.v[1] = 3.0000000000000000; + x.v[2] = 14.0000000000000000; + w.v[0] = 0.0000000000000000; + w.v[1] = 0.0000000000000000; + w.v[2] = 0.0000000000000000; +/* +[ 5. 3. 14.] +[ 0.2 0.33333333 0.07142857] +*/ + SST_Math_Vec3dRecip(&x,&w); + TASSERT(fabs((w.v[0])-( 0.2000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabs((w.v[1])-( 0.3333333333333333)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _y failed!"); + TASSERT(fabs((w.v[2])-( 0.0714285714285714)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _z failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec3dRecipLocal() +{ + SST_Vec3d x; /* 3 vector */ +/* Resetting test vectors */ + x.v[0] = 23.0000000000000000; + x.v[1] = 16.0000000000000000; + x.v[2] = 6.0000000000000000; +/* +[ 23. 16. 6.] +[ 0.20851441 0.25 0.40824829] +*/ + SST_Math_Vec3dRecipLocal(&x); /* for accuracy */ + TASSERT(fabs((x.v[0])-( 0.0434782608695652)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabs((x.v[1])-( 0.0625000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _y failed!"); + TASSERT(fabs((x.v[2])-( 0.1666666666666667)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _z failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec3dNormalize() +{ + SST_Vec3d x; /* 3 vector */ + SST_Vec3d w; /* 3 vector */ +/* Resetting test vectors */ + x.v[0] = 18.0000000000000000; + x.v[1] = 13.0000000000000000; + x.v[2] = -7.0000000000000000; + w.v[0] = 0.0000000000000000; + w.v[1] = 0.0000000000000000; + w.v[2] = 0.0000000000000000; +/* +[ 18. 13. -7.] +[ 0.7731662 0.55839781 -0.30067575] +*/ + SST_Math_Vec3dNormalize(&x,&w); + TASSERT(fabs((w.v[0])-( 0.7731662032576040)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabs((w.v[1])-( 0.5583978134638251)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _y failed!"); + TASSERT(fabs((w.v[2])-( -0.3006757457112904)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _z failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec3dNormalizeLocal() +{ + SST_Vec3d x; /* 3 vector */ +/* Resetting test vectors */ + x.v[0] = -15.0000000000000000; + x.v[1] = -20.0000000000000000; + x.v[2] = -12.0000000000000000; +/* +[-15. -20. -12.] +[-0.54091383 -0.72121845 -0.43273107] +*/ + SST_Math_Vec3dNormalizeLocal(&x); /* for accuracy */ + TASSERT(fabs((x.v[0])-( -0.5409138344809642)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabs((x.v[1])-( -0.7212184459746188)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _y failed!"); + TASSERT(fabs((x.v[2])-( -0.4327310675847713)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _z failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec3dProject() +{ + SST_Vec3d x; /* 3 vector */ + SST_Vec3d y; /* 3 vector */ + SST_Vec3d w; /* 3 vector */ +/* Resetting test vectors */ + x.v[0] = -2.0000000000000000; + x.v[1] = 7.0000000000000000; + x.v[2] = -12.0000000000000000; + y.v[0] = -14.0000000000000000; + y.v[1] = 6.0000000000000000; + y.v[2] = 15.0000000000000000; + w.v[0] = 0.0000000000000000; + w.v[1] = 0.0000000000000000; + w.v[2] = 0.0000000000000000; +/* +[ -2. 7. -12.] +[-14. 6. 15.] +[ 3.36980306 -1.44420131 -3.61050328] +*/ + SST_Math_Vec3dProject(&x,&y,&w); + TASSERT(fabs((w.v[0])-( 3.3698030634573306)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabs((w.v[1])-( -1.4442013129102844)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _y failed!"); + TASSERT(fabs((w.v[2])-( -3.6105032822757113)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _z failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec3dProjectLocal() +{ + SST_Vec3d x; /* 3 vector */ + SST_Vec3d y; /* 3 vector */ +/* Resetting test vectors */ + x.v[0] = -9.0000000000000000; + x.v[1] = 4.0000000000000000; + x.v[2] = 10.0000000000000000; + y.v[0] = 17.0000000000000000; + y.v[1] = 0.0000000000000000; + y.v[2] = -12.0000000000000000; +/* +[ -9. 4. 10.] +[ 17. 0. -12.] +[-10.7182448 -0. 7.56581986] +*/ + SST_Math_Vec3dProjectLocal(&x,&y); /* for accuracy */ + TASSERT(fabs((x.v[0])-( -10.7182448036951499)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabs((x.v[1])-( -0.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _y failed!"); + TASSERT(fabs((x.v[2])-( 7.5658198614318710)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _z failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec3dCross() +{ + SST_Vec3d x; /* 3 vector */ + SST_Vec3d y; /* 3 vector */ + SST_Vec3d w; /* 3 vector */ +/* Resetting test vectors */ + x.v[0] = -14.0000000000000000; + x.v[1] = -5.0000000000000000; + x.v[2] = 14.0000000000000000; + y.v[0] = 0.0000000000000000; + y.v[1] = -15.0000000000000000; + y.v[2] = 8.0000000000000000; + w.v[0] = 0.0000000000000000; + w.v[1] = 0.0000000000000000; + w.v[2] = 0.0000000000000000; +/* +[-14. -5. 14.] +[ 0. -15. 8.] +[ 170. 112. 210.] +*/ + SST_Math_Vec3dCross(&x,&y,&w); + TASSERT(fabs((w.v[0])-( 170.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabs((w.v[1])-( 112.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _y failed!"); + TASSERT(fabs((w.v[2])-( 210.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _z failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec3dCrossLocal() +{ + SST_Vec3d x; /* 3 vector */ + SST_Vec3d y; /* 3 vector */ +/* Resetting test vectors */ + x.v[0] = 17.0000000000000000; + x.v[1] = 7.0000000000000000; + x.v[2] = 8.0000000000000000; + y.v[0] = -5.0000000000000000; + y.v[1] = 11.0000000000000000; + y.v[2] = 2.0000000000000000; +/* +[ 17. 7. 8.] +[ -5. 11. 2.] +[ -74. -74. 222.] +*/ + SST_Math_Vec3dCrossLocal(&x,&y); /* for accuracy */ + TASSERT(fabs((x.v[0])-( -74.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabs((x.v[1])-( -74.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _y failed!"); + TASSERT(fabs((x.v[2])-( 222.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _z failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec3dRotateAbout() +{ + SST_Vec3d x; /* 3 vector */ + SST_Vec3d y; /* 3 vector */ + SST_Vec3d w; /* 3 vector */ + x.v[0] = 1.0000000000000000; + x.v[1] = 0.0000000000000000; + x.v[2] = 0.0000000000000000; + y.v[0] = 0.0000000000000000; + y.v[1] = 0.0000000000000000; + y.v[2] = 1.0000000000000000; +/* +[ 1. 0. 0.] +[ 0. 0. 1.] +[ 0. 1. 0.] +*/ + SST_Math_Vec3dRotateAbout(&x,&y, 1.5707963267948966,&w); + TASSERT(fabs((w.v[0])-( 0.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabs((w.v[1])-( 1.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _y failed!"); + TASSERT(fabs((w.v[2])-( 0.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _z failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec3dRotateAboutLocal() +{ + SST_Vec3d x; /* 3 vector */ + SST_Vec3d y; /* 3 vector */ + x.v[0] = 1.0000000000000000; + x.v[1] = 0.0000000000000000; + x.v[2] = 0.0000000000000000; + y.v[0] = 0.0000000000000000; + y.v[1] = 0.0000000000000000; + y.v[2] = 1.0000000000000000; +/* +[ 1. 0. 0.] +[ 0. 0. 1.] +[ 0. 1. 0.] +*/ + SST_Math_Vec3dRotateAboutLocal(&x,&y, 1.5707963267948966); + TASSERT(fabs((x.v[0])-( 0.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabs((x.v[1])-( 1.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _y failed!"); + TASSERT(fabs((x.v[2])-( 0.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _z failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec3dMagnitude() +{ + SST_Vec3d x; /* 3 vector */ + double a; /* scalar */ +/* Resetting test vectors */ + x.v[0] = -10.0000000000000000; + x.v[1] = 14.0000000000000000; + x.v[2] = -1.0000000000000000; +/* +[-10. 14. -1.] +17.2336879396 +*/ + a = SST_Math_Vec3dMagnitude(&x); + TASSERT(fabs((a)-( 17.2336879396140858)) <=100*DBL_EPSILON /* yes this is bad */,"Magnitude failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec3dMagnitudeSquared() +{ + SST_Vec3d x; /* 3 vector */ + double a; /* scalar */ +/* Resetting test vectors */ + x.v[0] = 0.0000000000000000; + x.v[1] = -11.0000000000000000; + x.v[2] = -20.0000000000000000; +/* +[ 0. -11. -20.] +521.0 +*/ + a = SST_Math_Vec3dMagnitudeSquared(&x); + TASSERT(fabs((a)-( 521.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"MagnitudeSquared failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec3dDot() +{ + SST_Vec3d x; /* 3 vector */ + SST_Vec3d y; /* 3 vector */ + double a; /* scalar */ +/* Resetting test vectors */ + x.v[0] = 10.0000000000000000; + x.v[1] = 4.0000000000000000; + x.v[2] = -17.0000000000000000; + y.v[0] = -6.0000000000000000; + y.v[1] = -16.0000000000000000; + y.v[2] = -6.0000000000000000; +/* +[ 10. 4. -17.] +-22.0 +*/ + a = SST_Math_Vec3dDot(&x,&y); + TASSERT(fabs((a)-( -22.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Dot failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + diff --git a/ZTestSuite/Test-SST_Vec3f.cpp b/ZTestSuite/Test-SST_Vec3f.cpp new file mode 100644 index 0000000..fa0c6df --- /dev/null +++ b/ZTestSuite/Test-SST_Vec3f.cpp @@ -0,0 +1,888 @@ +/* + AUTOMATICALLY GENERATED FILE - DO NOT EDIT! + Please change MatrixNxN.py and re-run it +*/ +/* Generated with ./VectorN.py n = 3, TYPE = float */ + +#include "ZUnitTest.hpp" +#include <float.h> +#include <math.h> +#include <stdlib.h> +#include <stdio.h> +#include <SST/SST_Vec3.h> + + + + +static const char* testSST_Math_Vec3fAdd(); +static const char* testSST_Math_Vec3fAddLocal(); +static const char* testSST_Math_Vec3fSubtract(); +static const char* testSST_Math_Vec3fSubtractLocal(); +static const char* testSST_Math_Vec3fMultiply(); +static const char* testSST_Math_Vec3fMultiplyLocal(); +static const char* testSST_Math_Vec3fScale(); +static const char* testSST_Math_Vec3fScaleLocal(); +static const char* testSST_Math_Vec3fDivide(); +static const char* testSST_Math_Vec3fDivideLocal(); +static const char* testSST_Math_Vec3fAbs(); +static const char* testSST_Math_Vec3fAbsLocal(); +static const char* testSST_Math_Vec3fNegate(); +static const char* testSST_Math_Vec3fNegateLocal(); +static const char* testSST_Math_Vec3fBias(); +static const char* testSST_Math_Vec3fBiasLocal(); +static const char* testSST_Math_Vec3fRecip(); +static const char* testSST_Math_Vec3fRecipLocal(); +static const char* testSST_Math_Vec3fRecipSqrt(); +static const char* testSST_Math_Vec3fRecipSqrtLocal(); +static const char* testSST_Math_Vec3fSqrt(); +static const char* testSST_Math_Vec3fSqrtLocal(); +static const char* testSST_Math_Vec3fSqrt(); +static const char* testSST_Math_Vec3fSqrtLocal(); +static const char* testSST_Math_Vec3fCross(); +static const char* testSST_Math_Vec3fCrossLocal(); +static const char* testSST_Math_Vec3fRotateAbout(); +static const char* testSST_Math_Vec3fRotateAboutLocal(); +static const char* testSST_Math_Vec3fProject(); +static const char* testSST_Math_Vec3fProjectLocal(); +static const char* testSST_Math_Vec3fMagnitude(); +static const char* testSST_Math_Vec3fNormalize(); +static const char* testSST_Math_Vec3fNormalizeLocal(); +static const char* testSST_Math_Vec3fMagnitudeSquared(); +static const char* testSST_Math_Vec3fDot(); +// List of unit tests +ZUnitTest SST_Math_Vec3fUnitTests[] = +{ +{ "testSST_Math_Vec3fAdd " , testSST_Math_Vec3fAdd }, +{ "testSST_Math_Vec3fAddLocal " , testSST_Math_Vec3fAddLocal }, +{ "testSST_Math_Vec3fSubtract " , testSST_Math_Vec3fSubtract }, +{ "testSST_Math_Vec3fSubtractLocal " , testSST_Math_Vec3fSubtractLocal }, +{ "testSST_Math_Vec3fMultiply " , testSST_Math_Vec3fMultiply }, +{ "testSST_Math_Vec3fMultiplyLocal " , testSST_Math_Vec3fMultiplyLocal }, +{ "testSST_Math_Vec3fScale " , testSST_Math_Vec3fScale }, +{ "testSST_Math_Vec3fScaleLocal " , testSST_Math_Vec3fScaleLocal }, +{ "testSST_Math_Vec3fDivide " , testSST_Math_Vec3fDivide }, +{ "testSST_Math_Vec3fDivideLocal " , testSST_Math_Vec3fDivideLocal }, +{ "testSST_Math_Vec3fAbs " , testSST_Math_Vec3fAbs }, +{ "testSST_Math_Vec3fAbsLocal " , testSST_Math_Vec3fAbsLocal }, +{ "testSST_Math_Vec3fNegate " , testSST_Math_Vec3fNegate }, +{ "testSST_Math_Vec3fNegateLocal " , testSST_Math_Vec3fNegateLocal }, +{ "testSST_Math_Vec3fBias " , testSST_Math_Vec3fBias }, +{ "testSST_Math_Vec3fBiasLocal " , testSST_Math_Vec3fBiasLocal }, +{ "testSST_Math_Vec3fRecip " , testSST_Math_Vec3fRecip }, +{ "testSST_Math_Vec3fRecipLocal " , testSST_Math_Vec3fRecipLocal }, +{ "testSST_Math_Vec3fRecipSqrt " , testSST_Math_Vec3fRecipSqrt }, +{ "testSST_Math_Vec3fRecipSqrtLocal " , testSST_Math_Vec3fRecipSqrtLocal }, +{ "testSST_Math_Vec3fSqrt " , testSST_Math_Vec3fSqrt }, +{ "testSST_Math_Vec3fSqrtLocal " , testSST_Math_Vec3fSqrtLocal }, +{ "testSST_Math_Vec3fSqrt " , testSST_Math_Vec3fSqrt }, +{ "testSST_Math_Vec3fSqrtLocal " , testSST_Math_Vec3fSqrtLocal }, +{ "testSST_Math_Vec3fMagnitude " , testSST_Math_Vec3fMagnitude }, +{ "testSST_Math_Vec3fNormalize " , testSST_Math_Vec3fNormalize }, +{ "testSST_Math_Vec3fNormalizeLocal " , testSST_Math_Vec3fNormalizeLocal }, +{ "testSST_Math_Vec3fCross " , testSST_Math_Vec3fCross }, +{ "testSST_Math_Vec3fCrossLocal " , testSST_Math_Vec3fCrossLocal }, +{ "testSST_Math_Vec3fRotateAbout " , testSST_Math_Vec3fRotateAbout }, +{ "testSST_Math_Vec3fRotateAboutLocal " , testSST_Math_Vec3fRotateAboutLocal }, +{ "testSST_Math_Vec3fProject " , testSST_Math_Vec3fProject }, +{ "testSST_Math_Vec3fProjectLocal " , testSST_Math_Vec3fProjectLocal }, +{ "testSST_Math_Vec3fMagnitudeSquared " , testSST_Math_Vec3fMagnitudeSquared }, +{ "testSST_Math_Vec3fDot " , testSST_Math_Vec3fDot } +}; +DECLARE_ZTESTBLOCK(SST_Math_Vec3f) + +/******************************************************************************/ + +static const char* testSST_Math_Vec3fAdd() +{ + SST_Vec3f x; /* 3 vector */ + SST_Vec3f y; /* 3 vector */ + SST_Vec3f w; /* 3 vector */ +/* Resetting test vectors */ + x.v[0] = -17.000000f; + x.v[1] = -13.000000f; + x.v[2] = -8.000000f; + y.v[0] = 13.000000f; + y.v[1] = 8.000000f; + y.v[2] = 14.000000f; + w.v[0] = 0.000000f; + w.v[1] = 0.000000f; + w.v[2] = 0.000000f; +/* +[-17. -13. -8.] +[ 13. 8. 14.] +[-4. -5. 6.] +*/ + SST_Math_Vec3fAdd(&x,&y,&w); + TASSERT(fabsf((w.v[0])-(-4.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabsf((w.v[1])-(-5.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _y failed!"); + TASSERT(fabsf((w.v[2])-(6.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _z failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec3fAddLocal() +{ + SST_Vec3f x; /* 3 vector */ + SST_Vec3f y; /* 3 vector */ +/* Resetting test vectors */ + x.v[0] = 7.000000f; + x.v[1] = 16.000000f; + x.v[2] = -8.000000f; + y.v[0] = -20.000000f; + y.v[1] = -16.000000f; + y.v[2] = 14.000000f; +/* +[ 7. 16. -8.] +[-20. -16. 14.] +[-13. 0. 6.] +*/ + SST_Math_Vec3fAddLocal(&x,&y); /* for accuracy */ + TASSERT(fabsf((x.v[0])-(-13.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabsf((x.v[1])-(0.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _y failed!"); + TASSERT(fabsf((x.v[2])-(6.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _z failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec3fSubtract() +{ + SST_Vec3f x; /* 3 vector */ + SST_Vec3f y; /* 3 vector */ + SST_Vec3f w; /* 3 vector */ +/* Resetting test vectors */ + x.v[0] = 4.000000f; + x.v[1] = -2.000000f; + x.v[2] = -12.000000f; + y.v[0] = -5.000000f; + y.v[1] = 19.000000f; + y.v[2] = 13.000000f; + w.v[0] = 0.000000f; + w.v[1] = 0.000000f; + w.v[2] = 0.000000f; +/* +[ 4. -2. -12.] +[ -5. 19. 13.] +[ 9. -21. -25.] +*/ + SST_Math_Vec3fSubtract(&x,&y,&w); + TASSERT(fabsf((w.v[0])-(9.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabsf((w.v[1])-(-21.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _y failed!"); + TASSERT(fabsf((w.v[2])-(-25.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _z failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec3fSubtractLocal() +{ + SST_Vec3f x; /* 3 vector */ + SST_Vec3f y; /* 3 vector */ +/* Resetting test vectors */ + x.v[0] = -6.000000f; + x.v[1] = -2.000000f; + x.v[2] = -17.000000f; + y.v[0] = -15.000000f; + y.v[1] = 3.000000f; + y.v[2] = -1.000000f; +/* +[ -6. -2. -17.] +[-15. 3. -1.] +[ 9. -5. -16.] +*/ + SST_Math_Vec3fSubtractLocal(&x,&y); /* for accuracy */ + TASSERT(fabsf((x.v[0])-(9.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabsf((x.v[1])-(-5.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _y failed!"); + TASSERT(fabsf((x.v[2])-(-16.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _z failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec3fMultiply() +{ + SST_Vec3f x; /* 3 vector */ + SST_Vec3f y; /* 3 vector */ + SST_Vec3f w; /* 3 vector */ +/* Resetting test vectors */ + x.v[0] = -19.000000f; + x.v[1] = -16.000000f; + x.v[2] = 15.000000f; + y.v[0] = -13.000000f; + y.v[1] = 6.000000f; + y.v[2] = 12.000000f; + w.v[0] = 0.000000f; + w.v[1] = 0.000000f; + w.v[2] = 0.000000f; +/* +[-19. -16. 15.] +[-13. 6. 12.] +[ 247. -96. 180.] +*/ + SST_Math_Vec3fMultiply(&x,&y,&w); + TASSERT(fabsf((w.v[0])-(247.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabsf((w.v[1])-(-96.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _y failed!"); + TASSERT(fabsf((w.v[2])-(180.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _z failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec3fMultiplyLocal() +{ + SST_Vec3f x; /* 3 vector */ + SST_Vec3f y; /* 3 vector */ +/* Resetting test vectors */ + x.v[0] = -1.000000f; + x.v[1] = -14.000000f; + x.v[2] = 1.000000f; + y.v[0] = 9.000000f; + y.v[1] = -16.000000f; + y.v[2] = -20.000000f; +/* +[ -1. -14. 1.] +[ 9. -16. -20.] +[ -9. 224. -20.] +*/ + SST_Math_Vec3fMultiplyLocal(&x,&y); /* for accuracy */ + TASSERT(fabsf((x.v[0])-(-9.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabsf((x.v[1])-(224.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _y failed!"); + TASSERT(fabsf((x.v[2])-(-20.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _z failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec3fDivide() +{ + SST_Vec3f x; /* 3 vector */ + SST_Vec3f y; /* 3 vector */ + SST_Vec3f w; /* 3 vector */ +/* Resetting test vectors */ + x.v[0] = 15.000000f; + x.v[1] = 11.000000f; + x.v[2] = 31.000000f; + y.v[0] = 16.000000f; + y.v[1] = 16.000000f; + y.v[2] = 17.000000f; + w.v[0] = 0.000000f; + w.v[1] = 0.000000f; + w.v[2] = 0.000000f; +/* +[ 15. 11. 31.] +[ 16. 16. 17.] +[ 0.9375 0.6875 1.82352936] +*/ + SST_Math_Vec3fDivide(&x,&y,&w); + TASSERT(fabsf((w.v[0])-(0.937500f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabsf((w.v[1])-(0.687500f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _y failed!"); + TASSERT(fabsf((w.v[2])-(1.823529f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _z failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec3fDivideLocal() +{ + SST_Vec3f x; /* 3 vector */ + SST_Vec3f y; /* 3 vector */ +/* Resetting test vectors */ + x.v[0] = 1.000000f; + x.v[1] = 2.000000f; + x.v[2] = 3.000000f; + y.v[0] = 15.000000f; + y.v[1] = 14.000000f; + y.v[2] = 1.000000f; +/* +[ 1. 2. 3.] +[ 15. 14. 1.] +[ 0.06666667 0.14285715 3. ] +*/ + SST_Math_Vec3fDivideLocal(&x,&y); /* for accuracy */ + TASSERT(fabsf((x.v[0])-(0.066667f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabsf((x.v[1])-(0.142857f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _y failed!"); + TASSERT(fabsf((x.v[2])-(3.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _z failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec3fScale() +{ + SST_Vec3f x; /* 3 vector */ + SST_Vec3f w; /* 3 vector */ + float a; /* scalar */ +/* Resetting test vectors */ + x.v[0] = -17.000000f; + x.v[1] = 10.000000f; + x.v[2] = -11.000000f; + w.v[0] = 0.000000f; + w.v[1] = 0.000000f; + w.v[2] = 0.000000f; + a = 2.000000f; +/* +[-17. 10. -11.] +[-34. 20. -22.] +*/ + SST_Math_Vec3fScale(&x,a,&w); + TASSERT(fabsf((w.v[0])-(-34.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabsf((w.v[1])-(20.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _y failed!"); + TASSERT(fabsf((w.v[2])-(-22.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _z failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec3fScaleLocal() +{ + SST_Vec3f x; /* 3 vector */ + float a; /* scalar */ +/* Resetting test vectors */ + x.v[0] = -19.000000f; + x.v[1] = -14.000000f; + x.v[2] = 18.000000f; + a = 2.000000f; +/* +[-19. -14. 18.] +[-38. -28. 36.] +*/ + SST_Math_Vec3fScaleLocal(&x,a); /* for accuracy */ + TASSERT(fabsf((x.v[0])-(-38.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabsf((x.v[1])-(-28.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _y failed!"); + TASSERT(fabsf((x.v[2])-(36.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _z failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec3fAbs() +{ + SST_Vec3f x; /* 3 vector */ + SST_Vec3f w; /* 3 vector */ +/* Resetting test vectors */ + x.v[0] = 16.000000f; + x.v[1] = 6.000000f; + x.v[2] = -2.000000f; + w.v[0] = 0.000000f; + w.v[1] = 0.000000f; + w.v[2] = 0.000000f; +/* +[ 16. 6. -2.] +[ 16. 6. 2.] +*/ + SST_Math_Vec3fAbs(&x,&w); + TASSERT(fabsf((w.v[0])-(16.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabsf((w.v[1])-(6.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _y failed!"); + TASSERT(fabsf((w.v[2])-(2.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _z failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec3fAbsLocal() +{ + SST_Vec3f x; /* 3 vector */ +/* Resetting test vectors */ + x.v[0] = 11.000000f; + x.v[1] = 18.000000f; + x.v[2] = -7.000000f; +/* +[ 11. 18. -7.] +[ 11. 18. 7.] +*/ + SST_Math_Vec3fAbsLocal(&x); /* for accuracy */ + TASSERT(fabsf((x.v[0])-(11.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabsf((x.v[1])-(18.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _y failed!"); + TASSERT(fabsf((x.v[2])-(7.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _z failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec3fBias() +{ + SST_Vec3f x; /* 3 vector */ + SST_Vec3f w; /* 3 vector */ + float a; /* scalar */ +/* Resetting test vectors */ + x.v[0] = 18.000000f; + x.v[1] = 12.000000f; + x.v[2] = -1.000000f; + w.v[0] = 0.000000f; + w.v[1] = 0.000000f; + w.v[2] = 0.000000f; + a = 15.000000f; +/* +[ 18. 12. -1.] +[ 36. 24. -2.] +*/ + SST_Math_Vec3fBias(&x,a,&w); + TASSERT(fabsf((w.v[0])-(33.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabsf((w.v[1])-(27.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _y failed!"); + TASSERT(fabsf((w.v[2])-(14.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _z failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec3fBiasLocal() +{ + SST_Vec3f x; /* 3 vector */ + float a; /* scalar */ +/* Resetting test vectors */ + x.v[0] = -18.000000f; + x.v[1] = 18.000000f; + x.v[2] = -1.000000f; + a = -10.000000f; +/* +[-18. 18. -1.] +[-36. 36. -2.] +*/ + SST_Math_Vec3fBiasLocal(&x,a); /* for accuracy */ + TASSERT(fabsf((x.v[0])-(-28.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabsf((x.v[1])-(8.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _y failed!"); + TASSERT(fabsf((x.v[2])-(-11.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _z failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec3fNegate() +{ + SST_Vec3f x; /* 3 vector */ + SST_Vec3f w; /* 3 vector */ +/* Resetting test vectors */ + x.v[0] = -4.000000f; + x.v[1] = 2.000000f; + x.v[2] = -5.000000f; + w.v[0] = 0.000000f; + w.v[1] = 0.000000f; + w.v[2] = 0.000000f; +/* +[-4. 2. -5.] +[ 4. -2. 5.] +*/ + SST_Math_Vec3fNegate(&x,&w); + TASSERT(fabsf((w.v[0])-(4.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabsf((w.v[1])-(-2.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _y failed!"); + TASSERT(fabsf((w.v[2])-(5.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _z failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec3fNegateLocal() +{ + SST_Vec3f x; /* 3 vector */ +/* Resetting test vectors */ + x.v[0] = 9.000000f; + x.v[1] = 7.000000f; + x.v[2] = -6.000000f; +/* +[ 9. 7. -6.] +[-9. -7. 6.] +*/ + SST_Math_Vec3fNegateLocal(&x); /* for accuracy */ + TASSERT(fabsf((x.v[0])-(-9.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabsf((x.v[1])-(-7.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _y failed!"); + TASSERT(fabsf((x.v[2])-(6.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _z failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec3fSqrt() +{ + SST_Vec3f x; /* 3 vector */ + SST_Vec3f w; /* 3 vector */ +/* Resetting test vectors */ + x.v[0] = 33.000000f; + x.v[1] = 37.000000f; + x.v[2] = 27.000000f; + w.v[0] = 0.000000f; + w.v[1] = 0.000000f; + w.v[2] = 0.000000f; +/* +[ 33. 37. 27.] +[ 5.74456263 6.08276272 5.19615221] +*/ + SST_Math_Vec3fSqrt(&x,&w); + TASSERT(fabsf((w.v[0])-(5.744563f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabsf((w.v[1])-(6.082763f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _y failed!"); + TASSERT(fabsf((w.v[2])-(5.196152f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _z failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec3fSqrtLocal() +{ + SST_Vec3f x; /* 3 vector */ +/* Resetting test vectors */ + x.v[0] = 2.000000f; + x.v[1] = 36.000000f; + x.v[2] = 13.000000f; +/* +[ 2. 36. 13.] +[ 1.41421354 6. 3.60555124] +*/ + SST_Math_Vec3fSqrtLocal(&x); /* for accuracy */ + TASSERT(fabsf((x.v[0])-(1.414214f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabsf((x.v[1])-(6.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _y failed!"); + TASSERT(fabsf((x.v[2])-(3.605551f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _z failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec3fRecipSqrt() +{ + SST_Vec3f x; /* 3 vector */ + SST_Vec3f w; /* 3 vector */ +/* Resetting test vectors */ + x.v[0] = 17.000000f; + x.v[1] = 2.000000f; + x.v[2] = 27.000000f; + w.v[0] = 0.000000f; + w.v[1] = 0.000000f; + w.v[2] = 0.000000f; +/* +[ 17. 2. 27.] +[ 0.24253564 0.70710677 0.19245009] +*/ + SST_Math_Vec3fRecipSqrt(&x,&w); + TASSERT(fabsf((w.v[0])-(0.242536f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabsf((w.v[1])-(0.707107f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _y failed!"); + TASSERT(fabsf((w.v[2])-(0.192450f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _z failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec3fRecipSqrtLocal() +{ + SST_Vec3f x; /* 3 vector */ +/* Resetting test vectors */ + x.v[0] = 30.000000f; + x.v[1] = 6.000000f; + x.v[2] = 33.000000f; +/* +[ 30. 6. 33.] +[ 0.18257418 0.40824828 0.17407766] +*/ + SST_Math_Vec3fRecipSqrtLocal(&x); /* for accuracy */ + TASSERT(fabsf((x.v[0])-(0.182574f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabsf((x.v[1])-(0.408248f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _y failed!"); + TASSERT(fabsf((x.v[2])-(0.174078f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _z failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec3fRecip() +{ + SST_Vec3f x; /* 3 vector */ + SST_Vec3f w; /* 3 vector */ +/* Resetting test vectors */ + x.v[0] = 35.000000f; + x.v[1] = 9.000000f; + x.v[2] = 8.000000f; + w.v[0] = 0.000000f; + w.v[1] = 0.000000f; + w.v[2] = 0.000000f; +/* +[ 35. 9. 8.] +[ 0.02857143 0.11111111 0.125 ] +*/ + SST_Math_Vec3fRecip(&x,&w); + TASSERT(fabsf((w.v[0])-(0.028571f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabsf((w.v[1])-(0.111111f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _y failed!"); + TASSERT(fabsf((w.v[2])-(0.125000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _z failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec3fRecipLocal() +{ + SST_Vec3f x; /* 3 vector */ +/* Resetting test vectors */ + x.v[0] = 14.000000f; + x.v[1] = 36.000000f; + x.v[2] = 24.000000f; +/* +[ 14. 36. 24.] +[ 0.26726124 0.16666667 0.20412414] +*/ + SST_Math_Vec3fRecipLocal(&x); /* for accuracy */ + TASSERT(fabsf((x.v[0])-(0.071429f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabsf((x.v[1])-(0.027778f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _y failed!"); + TASSERT(fabsf((x.v[2])-(0.041667f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _z failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec3fNormalize() +{ + SST_Vec3f x; /* 3 vector */ + SST_Vec3f w; /* 3 vector */ +/* Resetting test vectors */ + x.v[0] = -13.000000f; + x.v[1] = -17.000000f; + x.v[2] = 10.000000f; + w.v[0] = 0.000000f; + w.v[1] = 0.000000f; + w.v[2] = 0.000000f; +/* +[-13. -17. 10.] +[-0.55033386 -0.71966738 0.42333373] +*/ + SST_Math_Vec3fNormalize(&x,&w); + TASSERT(fabsf((w.v[0])-(-0.550334f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabsf((w.v[1])-(-0.719667f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _y failed!"); + TASSERT(fabsf((w.v[2])-(0.423334f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _z failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec3fNormalizeLocal() +{ + SST_Vec3f x; /* 3 vector */ +/* Resetting test vectors */ + x.v[0] = -14.000000f; + x.v[1] = -19.000000f; + x.v[2] = 12.000000f; +/* +[-14. -19. 12.] +[-0.52877271 -0.71762013 0.45323375] +*/ + SST_Math_Vec3fNormalizeLocal(&x); /* for accuracy */ + TASSERT(fabsf((x.v[0])-(-0.528773f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabsf((x.v[1])-(-0.717620f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _y failed!"); + TASSERT(fabsf((x.v[2])-(0.453234f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _z failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec3fProject() +{ + SST_Vec3f x; /* 3 vector */ + SST_Vec3f y; /* 3 vector */ + SST_Vec3f w; /* 3 vector */ +/* Resetting test vectors */ + x.v[0] = -5.000000f; + x.v[1] = 19.000000f; + x.v[2] = -6.000000f; + y.v[0] = 2.000000f; + y.v[1] = 14.000000f; + y.v[2] = -10.000000f; + w.v[0] = 0.000000f; + w.v[1] = 0.000000f; + w.v[2] = 0.000000f; +/* +[ -5. 19. -6.] +[ 2. 14. -10.] +[ 2.10666656 14.74666595 -10.53333282] +*/ + SST_Math_Vec3fProject(&x,&y,&w); + TASSERT(fabsf((w.v[0])-(2.106667f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabsf((w.v[1])-(14.746666f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _y failed!"); + TASSERT(fabsf((w.v[2])-(-10.533333f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _z failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec3fProjectLocal() +{ + SST_Vec3f x; /* 3 vector */ + SST_Vec3f y; /* 3 vector */ +/* Resetting test vectors */ + x.v[0] = 7.000000f; + x.v[1] = 17.000000f; + x.v[2] = 13.000000f; + y.v[0] = -2.000000f; + y.v[1] = 12.000000f; + y.v[2] = 12.000000f; +/* +[ 7. 17. 13.] +[ -2. 12. 12.] +[ -2.36986303 14.2191782 14.2191782 ] +*/ + SST_Math_Vec3fProjectLocal(&x,&y); /* for accuracy */ + TASSERT(fabsf((x.v[0])-(-2.369863f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabsf((x.v[1])-(14.219178f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _y failed!"); + TASSERT(fabsf((x.v[2])-(14.219178f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _z failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec3fCross() +{ + SST_Vec3f x; /* 3 vector */ + SST_Vec3f y; /* 3 vector */ + SST_Vec3f w; /* 3 vector */ +/* Resetting test vectors */ + x.v[0] = 12.000000f; + x.v[1] = -16.000000f; + x.v[2] = 12.000000f; + y.v[0] = 9.000000f; + y.v[1] = 6.000000f; + y.v[2] = 16.000000f; + w.v[0] = 0.000000f; + w.v[1] = 0.000000f; + w.v[2] = 0.000000f; +/* +[ 12. -16. 12.] +[ 9. 6. 16.] +[-328. -84. 216.] +*/ + SST_Math_Vec3fCross(&x,&y,&w); + TASSERT(fabsf((w.v[0])-(-328.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabsf((w.v[1])-(-84.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _y failed!"); + TASSERT(fabsf((w.v[2])-(216.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _z failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec3fCrossLocal() +{ + SST_Vec3f x; /* 3 vector */ + SST_Vec3f y; /* 3 vector */ +/* Resetting test vectors */ + x.v[0] = 6.000000f; + x.v[1] = 10.000000f; + x.v[2] = 13.000000f; + y.v[0] = 17.000000f; + y.v[1] = 19.000000f; + y.v[2] = -15.000000f; +/* +[ 6. 10. 13.] +[ 17. 19. -15.] +[-397. 311. -56.] +*/ + SST_Math_Vec3fCrossLocal(&x,&y); /* for accuracy */ + TASSERT(fabsf((x.v[0])-(-397.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabsf((x.v[1])-(311.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _y failed!"); + TASSERT(fabsf((x.v[2])-(-56.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _z failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec3fRotateAbout() +{ + SST_Vec3f x; /* 3 vector */ + SST_Vec3f y; /* 3 vector */ + SST_Vec3f w; /* 3 vector */ + x.v[0] = 1.000000f; + x.v[1] = 0.000000f; + x.v[2] = 0.000000f; + y.v[0] = 0.000000f; + y.v[1] = 0.000000f; + y.v[2] = 1.000000f; +/* +[ 1. 0. 0.] +[ 0. 0. 1.] +[ 0. 1. 0.] +*/ + SST_Math_Vec3fRotateAbout(&x,&y,1.570796f,&w); + TASSERT(fabsf((w.v[0])-(0.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabsf((w.v[1])-(1.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _y failed!"); + TASSERT(fabsf((w.v[2])-(0.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _z failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec3fRotateAboutLocal() +{ + SST_Vec3f x; /* 3 vector */ + SST_Vec3f y; /* 3 vector */ + x.v[0] = 1.000000f; + x.v[1] = 0.000000f; + x.v[2] = 0.000000f; + y.v[0] = 0.000000f; + y.v[1] = 0.000000f; + y.v[2] = 1.000000f; +/* +[ 1. 0. 0.] +[ 0. 0. 1.] +[ 0. 1. 0.] +*/ + SST_Math_Vec3fRotateAboutLocal(&x,&y,1.570796f); + TASSERT(fabsf((x.v[0])-(0.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabsf((x.v[1])-(1.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _y failed!"); + TASSERT(fabsf((x.v[2])-(0.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _z failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec3fMagnitude() +{ + SST_Vec3f x; /* 3 vector */ + float a; /* scalar */ +/* Resetting test vectors */ + x.v[0] = -19.000000f; + x.v[1] = 13.000000f; + x.v[2] = -17.000000f; +/* +[-19. 13. -17.] +28.6182 +*/ + a = SST_Math_Vec3fMagnitude(&x); + TASSERT(fabsf((a)-(28.618176f)) <=100*FLT_EPSILON /* yes this is bad */,"Magnitude failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec3fMagnitudeSquared() +{ + SST_Vec3f x; /* 3 vector */ + float a; /* scalar */ +/* Resetting test vectors */ + x.v[0] = -10.000000f; + x.v[1] = -20.000000f; + x.v[2] = 19.000000f; +/* +[-10. -20. 19.] +861.0 +*/ + a = SST_Math_Vec3fMagnitudeSquared(&x); + TASSERT(fabsf((a)-(861.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"MagnitudeSquared failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec3fDot() +{ + SST_Vec3f x; /* 3 vector */ + SST_Vec3f y; /* 3 vector */ + float a; /* scalar */ +/* Resetting test vectors */ + x.v[0] = -14.000000f; + x.v[1] = 4.000000f; + x.v[2] = 10.000000f; + y.v[0] = 19.000000f; + y.v[1] = -15.000000f; + y.v[2] = 0.000000f; +/* +[-14. 4. 10.] +-326.0 +*/ + a = SST_Math_Vec3fDot(&x,&y); + TASSERT(fabsf((a)-(-326.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Dot failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + diff --git a/ZTestSuite/Test-SST_Vec3i.cpp b/ZTestSuite/Test-SST_Vec3i.cpp new file mode 100644 index 0000000..c2788f2 --- /dev/null +++ b/ZTestSuite/Test-SST_Vec3i.cpp @@ -0,0 +1,502 @@ +/* + AUTOMATICALLY GENERATED FILE - DO NOT EDIT! + Please change MatrixNxN.py and re-run it +*/ +/* Generated with ./VectorN.py n = 3, TYPE = int */ + +#include "ZUnitTest.hpp" +#include <float.h> +#include <math.h> +#include <stdlib.h> +#include <stdio.h> +#include <SST/SST_Vec3.h> + + + + +static const char* testSST_Math_Vec3iAdd(); +static const char* testSST_Math_Vec3iAddLocal(); +static const char* testSST_Math_Vec3iSubtract(); +static const char* testSST_Math_Vec3iSubtractLocal(); +static const char* testSST_Math_Vec3iMultiply(); +static const char* testSST_Math_Vec3iMultiplyLocal(); +static const char* testSST_Math_Vec3iScale(); +static const char* testSST_Math_Vec3iScaleLocal(); +static const char* testSST_Math_Vec3iDivide(); +static const char* testSST_Math_Vec3iDivideLocal(); +static const char* testSST_Math_Vec3iAbs(); +static const char* testSST_Math_Vec3iAbsLocal(); +static const char* testSST_Math_Vec3iNegate(); +static const char* testSST_Math_Vec3iNegateLocal(); +static const char* testSST_Math_Vec3iBias(); +static const char* testSST_Math_Vec3iBiasLocal(); +static const char* testSST_Math_Vec3iMagnitudeSquared(); +static const char* testSST_Math_Vec3iDot(); +// List of unit tests +ZUnitTest SST_Math_Vec3iUnitTests[] = +{ +{ "testSST_Math_Vec3iAdd " , testSST_Math_Vec3iAdd }, +{ "testSST_Math_Vec3iAddLocal " , testSST_Math_Vec3iAddLocal }, +{ "testSST_Math_Vec3iSubtract " , testSST_Math_Vec3iSubtract }, +{ "testSST_Math_Vec3iSubtractLocal " , testSST_Math_Vec3iSubtractLocal }, +{ "testSST_Math_Vec3iMultiply " , testSST_Math_Vec3iMultiply }, +{ "testSST_Math_Vec3iMultiplyLocal " , testSST_Math_Vec3iMultiplyLocal }, +{ "testSST_Math_Vec3iScale " , testSST_Math_Vec3iScale }, +{ "testSST_Math_Vec3iScaleLocal " , testSST_Math_Vec3iScaleLocal }, +{ "testSST_Math_Vec3iDivide " , testSST_Math_Vec3iDivide }, +{ "testSST_Math_Vec3iDivideLocal " , testSST_Math_Vec3iDivideLocal }, +{ "testSST_Math_Vec3iAbs " , testSST_Math_Vec3iAbs }, +{ "testSST_Math_Vec3iAbsLocal " , testSST_Math_Vec3iAbsLocal }, +{ "testSST_Math_Vec3iNegate " , testSST_Math_Vec3iNegate }, +{ "testSST_Math_Vec3iNegateLocal " , testSST_Math_Vec3iNegateLocal }, +{ "testSST_Math_Vec3iBias " , testSST_Math_Vec3iBias }, +{ "testSST_Math_Vec3iBiasLocal " , testSST_Math_Vec3iBiasLocal }, +{ "testSST_Math_Vec3iMagnitudeSquared " , testSST_Math_Vec3iMagnitudeSquared }, +{ "testSST_Math_Vec3iDot " , testSST_Math_Vec3iDot } +}; +DECLARE_ZTESTBLOCK(SST_Math_Vec3i) + +/******************************************************************************/ + +static const char* testSST_Math_Vec3iAdd() +{ + SST_Vec3i x; /* 3 vector */ + SST_Vec3i y; /* 3 vector */ + SST_Vec3i w; /* 3 vector */ +/* Resetting test vectors */ + x.v[0] = 11; + x.v[1] = -1; + x.v[2] = 18; + y.v[0] = -9; + y.v[1] = -16; + y.v[2] = 15; + w.v[0] = 0; + w.v[1] = 0; + w.v[2] = 0; +/* +[11 -1 18] +[ -9 -16 15] +[ 2 -17 33] +*/ + SST_Math_Vec3iAdd(&x,&y,&w); + TASSERT((w.v[0])==(2),"Entry _x failed!"); + TASSERT((w.v[1])==(-17),"Entry _y failed!"); + TASSERT((w.v[2])==(33),"Entry _z failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec3iAddLocal() +{ + SST_Vec3i x; /* 3 vector */ + SST_Vec3i y; /* 3 vector */ +/* Resetting test vectors */ + x.v[0] = 5; + x.v[1] = -7; + x.v[2] = 5; + y.v[0] = 15; + y.v[1] = 0; + y.v[2] = 5; +/* +[ 5 -7 5] +[15 0 5] +[20 -7 10] +*/ + SST_Math_Vec3iAddLocal(&x,&y); /* for accuracy */ + TASSERT((x.v[0])==(20),"Entry _x failed!"); + TASSERT((x.v[1])==(-7),"Entry _y failed!"); + TASSERT((x.v[2])==(10),"Entry _z failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec3iSubtract() +{ + SST_Vec3i x; /* 3 vector */ + SST_Vec3i y; /* 3 vector */ + SST_Vec3i w; /* 3 vector */ +/* Resetting test vectors */ + x.v[0] = 6; + x.v[1] = 11; + x.v[2] = -12; + y.v[0] = 8; + y.v[1] = 0; + y.v[2] = 9; + w.v[0] = 0; + w.v[1] = 0; + w.v[2] = 0; +/* +[ 6 11 -12] +[8 0 9] +[ -2 11 -21] +*/ + SST_Math_Vec3iSubtract(&x,&y,&w); + TASSERT((w.v[0])==(-2),"Entry _x failed!"); + TASSERT((w.v[1])==(11),"Entry _y failed!"); + TASSERT((w.v[2])==(-21),"Entry _z failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec3iSubtractLocal() +{ + SST_Vec3i x; /* 3 vector */ + SST_Vec3i y; /* 3 vector */ +/* Resetting test vectors */ + x.v[0] = -19; + x.v[1] = -17; + x.v[2] = 18; + y.v[0] = 9; + y.v[1] = 4; + y.v[2] = -12; +/* +[-19 -17 18] +[ 9 4 -12] +[-28 -21 30] +*/ + SST_Math_Vec3iSubtractLocal(&x,&y); /* for accuracy */ + TASSERT((x.v[0])==(-28),"Entry _x failed!"); + TASSERT((x.v[1])==(-21),"Entry _y failed!"); + TASSERT((x.v[2])==(30),"Entry _z failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec3iMultiply() +{ + SST_Vec3i x; /* 3 vector */ + SST_Vec3i y; /* 3 vector */ + SST_Vec3i w; /* 3 vector */ +/* Resetting test vectors */ + x.v[0] = 10; + x.v[1] = -15; + x.v[2] = -15; + y.v[0] = -18; + y.v[1] = -7; + y.v[2] = 17; + w.v[0] = 0; + w.v[1] = 0; + w.v[2] = 0; +/* +[ 10 -15 -15] +[-18 -7 17] +[-180 105 -255] +*/ + SST_Math_Vec3iMultiply(&x,&y,&w); + TASSERT((w.v[0])==(-180),"Entry _x failed!"); + TASSERT((w.v[1])==(105),"Entry _y failed!"); + TASSERT((w.v[2])==(-255),"Entry _z failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec3iMultiplyLocal() +{ + SST_Vec3i x; /* 3 vector */ + SST_Vec3i y; /* 3 vector */ +/* Resetting test vectors */ + x.v[0] = -14; + x.v[1] = 15; + x.v[2] = -2; + y.v[0] = 19; + y.v[1] = -4; + y.v[2] = -4; +/* +[-14 15 -2] +[19 -4 -4] +[-266 -60 8] +*/ + SST_Math_Vec3iMultiplyLocal(&x,&y); /* for accuracy */ + TASSERT((x.v[0])==(-266),"Entry _x failed!"); + TASSERT((x.v[1])==(-60),"Entry _y failed!"); + TASSERT((x.v[2])==(8),"Entry _z failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec3iDivide() +{ + SST_Vec3i x; /* 3 vector */ + SST_Vec3i y; /* 3 vector */ + SST_Vec3i w; /* 3 vector */ +/* Resetting test vectors */ + x.v[0] = 28; + x.v[1] = 23; + x.v[2] = 8; + y.v[0] = 2; + y.v[1] = 2; + y.v[2] = 29; + w.v[0] = 0; + w.v[1] = 0; + w.v[2] = 0; +/* +[28 23 8] +[ 2 2 29] +[14 11 0] +*/ + SST_Math_Vec3iDivide(&x,&y,&w); + TASSERT((w.v[0])==(14),"Entry _x failed!"); + TASSERT((w.v[1])==(11),"Entry _y failed!"); + TASSERT((w.v[2])==(0),"Entry _z failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec3iDivideLocal() +{ + SST_Vec3i x; /* 3 vector */ + SST_Vec3i y; /* 3 vector */ +/* Resetting test vectors */ + x.v[0] = 31; + x.v[1] = 36; + x.v[2] = 33; + y.v[0] = 1; + y.v[1] = 9; + y.v[2] = 16; +/* +[31 36 33] +[ 1 9 16] +[31 4 2] +*/ + SST_Math_Vec3iDivideLocal(&x,&y); /* for accuracy */ + TASSERT((x.v[0])==(31),"Entry _x failed!"); + TASSERT((x.v[1])==(4),"Entry _y failed!"); + TASSERT((x.v[2])==(2),"Entry _z failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec3iScale() +{ + SST_Vec3i x; /* 3 vector */ + SST_Vec3i w; /* 3 vector */ + int a; /* scalar */ +/* Resetting test vectors */ + x.v[0] = -11; + x.v[1] = -6; + x.v[2] = 12; + w.v[0] = 0; + w.v[1] = 0; + w.v[2] = 0; + a = 2; +/* +[-11 -6 12] +[-22 -12 24] +*/ + SST_Math_Vec3iScale(&x,a,&w); + TASSERT((w.v[0])==(-22),"Entry _x failed!"); + TASSERT((w.v[1])==(-12),"Entry _y failed!"); + TASSERT((w.v[2])==(24),"Entry _z failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec3iScaleLocal() +{ + SST_Vec3i x; /* 3 vector */ + int a; /* scalar */ +/* Resetting test vectors */ + x.v[0] = 1; + x.v[1] = 19; + x.v[2] = -8; + a = 2; +/* +[ 1 19 -8] +[ 2 38 -16] +*/ + SST_Math_Vec3iScaleLocal(&x,a); /* for accuracy */ + TASSERT((x.v[0])==(2),"Entry _x failed!"); + TASSERT((x.v[1])==(38),"Entry _y failed!"); + TASSERT((x.v[2])==(-16),"Entry _z failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec3iAbs() +{ + SST_Vec3i x; /* 3 vector */ + SST_Vec3i w; /* 3 vector */ +/* Resetting test vectors */ + x.v[0] = 16; + x.v[1] = 15; + x.v[2] = -14; + w.v[0] = 0; + w.v[1] = 0; + w.v[2] = 0; +/* +[ 16 15 -14] +[16 15 14] +*/ + SST_Math_Vec3iAbs(&x,&w); + TASSERT((w.v[0])==(16),"Entry _x failed!"); + TASSERT((w.v[1])==(15),"Entry _y failed!"); + TASSERT((w.v[2])==(14),"Entry _z failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec3iAbsLocal() +{ + SST_Vec3i x; /* 3 vector */ +/* Resetting test vectors */ + x.v[0] = -1; + x.v[1] = -12; + x.v[2] = -18; +/* +[ -1 -12 -18] +[ 1 12 18] +*/ + SST_Math_Vec3iAbsLocal(&x); /* for accuracy */ + TASSERT((x.v[0])==(1),"Entry _x failed!"); + TASSERT((x.v[1])==(12),"Entry _y failed!"); + TASSERT((x.v[2])==(18),"Entry _z failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec3iBias() +{ + SST_Vec3i x; /* 3 vector */ + SST_Vec3i w; /* 3 vector */ + int a; /* scalar */ +/* Resetting test vectors */ + x.v[0] = -12; + x.v[1] = -9; + x.v[2] = -2; + w.v[0] = 0; + w.v[1] = 0; + w.v[2] = 0; + a = -20; +/* +[-12 -9 -2] +[-24 -18 -4] +*/ + SST_Math_Vec3iBias(&x,a,&w); + TASSERT((w.v[0])==(-32),"Entry _x failed!"); + TASSERT((w.v[1])==(-29),"Entry _y failed!"); + TASSERT((w.v[2])==(-22),"Entry _z failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec3iBiasLocal() +{ + SST_Vec3i x; /* 3 vector */ + int a; /* scalar */ +/* Resetting test vectors */ + x.v[0] = 0; + x.v[1] = 19; + x.v[2] = -15; + a = 16; +/* +[ 0 19 -15] +[ 0 38 -30] +*/ + SST_Math_Vec3iBiasLocal(&x,a); /* for accuracy */ + TASSERT((x.v[0])==(16),"Entry _x failed!"); + TASSERT((x.v[1])==(35),"Entry _y failed!"); + TASSERT((x.v[2])==(1),"Entry _z failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec3iNegate() +{ + SST_Vec3i x; /* 3 vector */ + SST_Vec3i w; /* 3 vector */ +/* Resetting test vectors */ + x.v[0] = 14; + x.v[1] = -14; + x.v[2] = -9; + w.v[0] = 0; + w.v[1] = 0; + w.v[2] = 0; +/* +[ 14 -14 -9] +[-14 14 9] +*/ + SST_Math_Vec3iNegate(&x,&w); + TASSERT((w.v[0])==(-14),"Entry _x failed!"); + TASSERT((w.v[1])==(14),"Entry _y failed!"); + TASSERT((w.v[2])==(9),"Entry _z failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec3iNegateLocal() +{ + SST_Vec3i x; /* 3 vector */ +/* Resetting test vectors */ + x.v[0] = 15; + x.v[1] = 16; + x.v[2] = 1; +/* +[15 16 1] +[-15 -16 -1] +*/ + SST_Math_Vec3iNegateLocal(&x); /* for accuracy */ + TASSERT((x.v[0])==(-15),"Entry _x failed!"); + TASSERT((x.v[1])==(-16),"Entry _y failed!"); + TASSERT((x.v[2])==(-1),"Entry _z failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec3iMagnitudeSquared() +{ + SST_Vec3i x; /* 3 vector */ + int a; /* scalar */ +/* Resetting test vectors */ + x.v[0] = -15; + x.v[1] = 13; + x.v[2] = 14; +/* +[-15 13 14] +590 +*/ + a = SST_Math_Vec3iMagnitudeSquared(&x); + TASSERT((a)==(590),"MagnitudeSquared failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec3iDot() +{ + SST_Vec3i x; /* 3 vector */ + SST_Vec3i y; /* 3 vector */ + int a; /* scalar */ +/* Resetting test vectors */ + x.v[0] = -20; + x.v[1] = -1; + x.v[2] = -4; + y.v[0] = 12; + y.v[1] = -20; + y.v[2] = -12; +/* +[-20 -1 -4] +-172 +*/ + a = SST_Math_Vec3iDot(&x,&y); + TASSERT((a)==(-172),"Dot failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + diff --git a/ZTestSuite/Test-SST_Vec3u.cpp b/ZTestSuite/Test-SST_Vec3u.cpp new file mode 100644 index 0000000..b824a86 --- /dev/null +++ b/ZTestSuite/Test-SST_Vec3u.cpp @@ -0,0 +1,354 @@ +/* + AUTOMATICALLY GENERATED FILE - DO NOT EDIT! + Please change MatrixNxN.py and re-run it +*/ +/* Generated with ./VectorN.py n = 3, TYPE = unsigned int */ + +#include "ZUnitTest.hpp" +#include <float.h> +#include <math.h> +#include <stdlib.h> +#include <stdio.h> +#include <SST/SST_Vec3.h> + + + + +static const char* testSST_Math_Vec3uAdd(); +static const char* testSST_Math_Vec3uAddLocal(); +static const char* testSST_Math_Vec3uSubtract(); +static const char* testSST_Math_Vec3uSubtractLocal(); +static const char* testSST_Math_Vec3uMultiply(); +static const char* testSST_Math_Vec3uMultiplyLocal(); +static const char* testSST_Math_Vec3uScale(); +static const char* testSST_Math_Vec3uScaleLocal(); +static const char* testSST_Math_Vec3uDivide(); +static const char* testSST_Math_Vec3uDivideLocal(); +static const char* testSST_Math_Vec3uMagnitudeSquared(); +static const char* testSST_Math_Vec3uDot(); +// List of unit tests +ZUnitTest SST_Math_Vec3uUnitTests[] = +{ +{ "testSST_Math_Vec3uAdd " , testSST_Math_Vec3uAdd }, +{ "testSST_Math_Vec3uAddLocal " , testSST_Math_Vec3uAddLocal }, +{ "testSST_Math_Vec3uSubtract " , testSST_Math_Vec3uSubtract }, +{ "testSST_Math_Vec3uSubtractLocal " , testSST_Math_Vec3uSubtractLocal }, +{ "testSST_Math_Vec3uMultiply " , testSST_Math_Vec3uMultiply }, +{ "testSST_Math_Vec3uMultiplyLocal " , testSST_Math_Vec3uMultiplyLocal }, +{ "testSST_Math_Vec3uScale " , testSST_Math_Vec3uScale }, +{ "testSST_Math_Vec3uScaleLocal " , testSST_Math_Vec3uScaleLocal }, +{ "testSST_Math_Vec3uDivide " , testSST_Math_Vec3uDivide }, +{ "testSST_Math_Vec3uDivideLocal " , testSST_Math_Vec3uDivideLocal }, +{ "testSST_Math_Vec3uMagnitudeSquared " , testSST_Math_Vec3uMagnitudeSquared }, +{ "testSST_Math_Vec3uDot " , testSST_Math_Vec3uDot } +}; +DECLARE_ZTESTBLOCK(SST_Math_Vec3u) + +/******************************************************************************/ + +static const char* testSST_Math_Vec3uAdd() +{ + SST_Vec3u x; /* 3 vector */ + SST_Vec3u y; /* 3 vector */ + SST_Vec3u w; /* 3 vector */ +/* Resetting test vectors */ + x.v[0] = 24; + x.v[1] = 38; + x.v[2] = 8; + y.v[0] = 37; + y.v[1] = 3; + y.v[2] = 25; + w.v[0] = 0; + w.v[1] = 0; + w.v[2] = 0; +/* +[24 38 8] +[37 3 25] +[61 41 33] +*/ + SST_Math_Vec3uAdd(&x,&y,&w); + TASSERT((w.v[0])==(61),"Entry _x failed!"); + TASSERT((w.v[1])==(41),"Entry _y failed!"); + TASSERT((w.v[2])==(33),"Entry _z failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec3uAddLocal() +{ + SST_Vec3u x; /* 3 vector */ + SST_Vec3u y; /* 3 vector */ +/* Resetting test vectors */ + x.v[0] = 24; + x.v[1] = 8; + x.v[2] = 24; + y.v[0] = 33; + y.v[1] = 28; + y.v[2] = 25; +/* +[24 8 24] +[33 28 25] +[57 36 49] +*/ + SST_Math_Vec3uAddLocal(&x,&y); /* for accuracy */ + TASSERT((x.v[0])==(57),"Entry _x failed!"); + TASSERT((x.v[1])==(36),"Entry _y failed!"); + TASSERT((x.v[2])==(49),"Entry _z failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec3uSubtract() +{ + SST_Vec3u x; /* 3 vector */ + SST_Vec3u y; /* 3 vector */ + SST_Vec3u w; /* 3 vector */ +/* Resetting test vectors */ + x.v[0] = 18; + x.v[1] = 29; + x.v[2] = 32; + y.v[0] = 38; + y.v[1] = 30; + y.v[2] = 6; + w.v[0] = 0; + w.v[1] = 0; + w.v[2] = 0; +/* +[18 29 32] +[38 30 6] +[4294967276 4294967295 26] +*/ + SST_Math_Vec3uSubtract(&x,&y,&w); + TASSERT((w.v[0])==(4294967276),"Entry _x failed!"); + TASSERT((w.v[1])==(4294967295),"Entry _y failed!"); + TASSERT((w.v[2])==(26),"Entry _z failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec3uSubtractLocal() +{ + SST_Vec3u x; /* 3 vector */ + SST_Vec3u y; /* 3 vector */ +/* Resetting test vectors */ + x.v[0] = 5; + x.v[1] = 15; + x.v[2] = 11; + y.v[0] = 13; + y.v[1] = 7; + y.v[2] = 24; +/* +[ 5 15 11] +[13 7 24] +[4294967288 8 4294967283] +*/ + SST_Math_Vec3uSubtractLocal(&x,&y); /* for accuracy */ + TASSERT((x.v[0])==(4294967288),"Entry _x failed!"); + TASSERT((x.v[1])==(8),"Entry _y failed!"); + TASSERT((x.v[2])==(4294967283),"Entry _z failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec3uMultiply() +{ + SST_Vec3u x; /* 3 vector */ + SST_Vec3u y; /* 3 vector */ + SST_Vec3u w; /* 3 vector */ +/* Resetting test vectors */ + x.v[0] = 22; + x.v[1] = 9; + x.v[2] = 9; + y.v[0] = 29; + y.v[1] = 16; + y.v[2] = 24; + w.v[0] = 0; + w.v[1] = 0; + w.v[2] = 0; +/* +[22 9 9] +[29 16 24] +[638 144 216] +*/ + SST_Math_Vec3uMultiply(&x,&y,&w); + TASSERT((w.v[0])==(638),"Entry _x failed!"); + TASSERT((w.v[1])==(144),"Entry _y failed!"); + TASSERT((w.v[2])==(216),"Entry _z failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec3uMultiplyLocal() +{ + SST_Vec3u x; /* 3 vector */ + SST_Vec3u y; /* 3 vector */ +/* Resetting test vectors */ + x.v[0] = 32; + x.v[1] = 27; + x.v[2] = 34; + y.v[0] = 33; + y.v[1] = 16; + y.v[2] = 36; +/* +[32 27 34] +[33 16 36] +[1056 432 1224] +*/ + SST_Math_Vec3uMultiplyLocal(&x,&y); /* for accuracy */ + TASSERT((x.v[0])==(1056),"Entry _x failed!"); + TASSERT((x.v[1])==(432),"Entry _y failed!"); + TASSERT((x.v[2])==(1224),"Entry _z failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec3uDivide() +{ + SST_Vec3u x; /* 3 vector */ + SST_Vec3u y; /* 3 vector */ + SST_Vec3u w; /* 3 vector */ +/* Resetting test vectors */ + x.v[0] = 36; + x.v[1] = 14; + x.v[2] = 10; + y.v[0] = 30; + y.v[1] = 35; + y.v[2] = 27; + w.v[0] = 0; + w.v[1] = 0; + w.v[2] = 0; +/* +[36 14 10] +[30 35 27] +[1 0 0] +*/ + SST_Math_Vec3uDivide(&x,&y,&w); + TASSERT((w.v[0])==(1),"Entry _x failed!"); + TASSERT((w.v[1])==(0),"Entry _y failed!"); + TASSERT((w.v[2])==(0),"Entry _z failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec3uDivideLocal() +{ + SST_Vec3u x; /* 3 vector */ + SST_Vec3u y; /* 3 vector */ +/* Resetting test vectors */ + x.v[0] = 21; + x.v[1] = 5; + x.v[2] = 36; + y.v[0] = 14; + y.v[1] = 13; + y.v[2] = 6; +/* +[21 5 36] +[14 13 6] +[1 0 6] +*/ + SST_Math_Vec3uDivideLocal(&x,&y); /* for accuracy */ + TASSERT((x.v[0])==(1),"Entry _x failed!"); + TASSERT((x.v[1])==(0),"Entry _y failed!"); + TASSERT((x.v[2])==(6),"Entry _z failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec3uScale() +{ + SST_Vec3u x; /* 3 vector */ + SST_Vec3u w; /* 3 vector */ + unsigned int a; /* scalar */ +/* Resetting test vectors */ + x.v[0] = 30; + x.v[1] = 18; + x.v[2] = 37; + w.v[0] = 0; + w.v[1] = 0; + w.v[2] = 0; + a = 2; +/* +[30 18 37] +[60 36 74] +*/ + SST_Math_Vec3uScale(&x,a,&w); + TASSERT((w.v[0])==(60),"Entry _x failed!"); + TASSERT((w.v[1])==(36),"Entry _y failed!"); + TASSERT((w.v[2])==(74),"Entry _z failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec3uScaleLocal() +{ + SST_Vec3u x; /* 3 vector */ + unsigned int a; /* scalar */ +/* Resetting test vectors */ + x.v[0] = 26; + x.v[1] = 26; + x.v[2] = 28; + a = 2; +/* +[26 26 28] +[52 52 56] +*/ + SST_Math_Vec3uScaleLocal(&x,a); /* for accuracy */ + TASSERT((x.v[0])==(52),"Entry _x failed!"); + TASSERT((x.v[1])==(52),"Entry _y failed!"); + TASSERT((x.v[2])==(56),"Entry _z failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec3uMagnitudeSquared() +{ + SST_Vec3u x; /* 3 vector */ + unsigned int a; /* scalar */ +/* Resetting test vectors */ + x.v[0] = 28; + x.v[1] = 36; + x.v[2] = 39; +/* +[28 36 39] +3601 +*/ + a = SST_Math_Vec3uMagnitudeSquared(&x); + TASSERT((a)==(3601),"MagnitudeSquared failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec3uDot() +{ + SST_Vec3u x; /* 3 vector */ + SST_Vec3u y; /* 3 vector */ + unsigned int a; /* scalar */ +/* Resetting test vectors */ + x.v[0] = 0; + x.v[1] = 26; + x.v[2] = 4; + y.v[0] = 16; + y.v[1] = 24; + y.v[2] = 31; +/* +[ 0 26 4] +748 +*/ + a = SST_Math_Vec3uDot(&x,&y); + TASSERT((a)==(748),"Dot failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + diff --git a/ZTestSuite/Test-SST_Vec4d.cpp b/ZTestSuite/Test-SST_Vec4d.cpp new file mode 100644 index 0000000..19cf59f --- /dev/null +++ b/ZTestSuite/Test-SST_Vec4d.cpp @@ -0,0 +1,859 @@ +/* + AUTOMATICALLY GENERATED FILE - DO NOT EDIT! + Please change MatrixNxN.py and re-run it +*/ +/* Generated with ./VectorN.py n = 4, TYPE = double */ + +#include "ZUnitTest.hpp" +#include <float.h> +#include <math.h> +#include <stdlib.h> +#include <stdio.h> +#include <SST/SST_Vec4.h> + + + + +static const char* testSST_Math_Vec4dAdd(); +static const char* testSST_Math_Vec4dAddLocal(); +static const char* testSST_Math_Vec4dSubtract(); +static const char* testSST_Math_Vec4dSubtractLocal(); +static const char* testSST_Math_Vec4dMultiply(); +static const char* testSST_Math_Vec4dMultiplyLocal(); +static const char* testSST_Math_Vec4dScale(); +static const char* testSST_Math_Vec4dScaleLocal(); +static const char* testSST_Math_Vec4dDivide(); +static const char* testSST_Math_Vec4dDivideLocal(); +static const char* testSST_Math_Vec4dAbs(); +static const char* testSST_Math_Vec4dAbsLocal(); +static const char* testSST_Math_Vec4dNegate(); +static const char* testSST_Math_Vec4dNegateLocal(); +static const char* testSST_Math_Vec4dBias(); +static const char* testSST_Math_Vec4dBiasLocal(); +static const char* testSST_Math_Vec4dRecip(); +static const char* testSST_Math_Vec4dRecipLocal(); +static const char* testSST_Math_Vec4dRecipSqrt(); +static const char* testSST_Math_Vec4dRecipSqrtLocal(); +static const char* testSST_Math_Vec4dSqrt(); +static const char* testSST_Math_Vec4dSqrtLocal(); +static const char* testSST_Math_Vec4dSqrt(); +static const char* testSST_Math_Vec4dSqrtLocal(); +static const char* testSST_Math_Vec4dProject(); +static const char* testSST_Math_Vec4dProjectLocal(); +static const char* testSST_Math_Vec4dMagnitude(); +static const char* testSST_Math_Vec4dNormalize(); +static const char* testSST_Math_Vec4dNormalizeLocal(); +static const char* testSST_Math_Vec4dMagnitudeSquared(); +static const char* testSST_Math_Vec4dDot(); +// List of unit tests +ZUnitTest SST_Math_Vec4dUnitTests[] = +{ +{ "testSST_Math_Vec4dAdd " , testSST_Math_Vec4dAdd }, +{ "testSST_Math_Vec4dAddLocal " , testSST_Math_Vec4dAddLocal }, +{ "testSST_Math_Vec4dSubtract " , testSST_Math_Vec4dSubtract }, +{ "testSST_Math_Vec4dSubtractLocal " , testSST_Math_Vec4dSubtractLocal }, +{ "testSST_Math_Vec4dMultiply " , testSST_Math_Vec4dMultiply }, +{ "testSST_Math_Vec4dMultiplyLocal " , testSST_Math_Vec4dMultiplyLocal }, +{ "testSST_Math_Vec4dScale " , testSST_Math_Vec4dScale }, +{ "testSST_Math_Vec4dScaleLocal " , testSST_Math_Vec4dScaleLocal }, +{ "testSST_Math_Vec4dDivide " , testSST_Math_Vec4dDivide }, +{ "testSST_Math_Vec4dDivideLocal " , testSST_Math_Vec4dDivideLocal }, +{ "testSST_Math_Vec4dAbs " , testSST_Math_Vec4dAbs }, +{ "testSST_Math_Vec4dAbsLocal " , testSST_Math_Vec4dAbsLocal }, +{ "testSST_Math_Vec4dNegate " , testSST_Math_Vec4dNegate }, +{ "testSST_Math_Vec4dNegateLocal " , testSST_Math_Vec4dNegateLocal }, +{ "testSST_Math_Vec4dBias " , testSST_Math_Vec4dBias }, +{ "testSST_Math_Vec4dBiasLocal " , testSST_Math_Vec4dBiasLocal }, +{ "testSST_Math_Vec4dRecip " , testSST_Math_Vec4dRecip }, +{ "testSST_Math_Vec4dRecipLocal " , testSST_Math_Vec4dRecipLocal }, +{ "testSST_Math_Vec4dRecipSqrt " , testSST_Math_Vec4dRecipSqrt }, +{ "testSST_Math_Vec4dRecipSqrtLocal " , testSST_Math_Vec4dRecipSqrtLocal }, +{ "testSST_Math_Vec4dSqrt " , testSST_Math_Vec4dSqrt }, +{ "testSST_Math_Vec4dSqrtLocal " , testSST_Math_Vec4dSqrtLocal }, +{ "testSST_Math_Vec4dSqrt " , testSST_Math_Vec4dSqrt }, +{ "testSST_Math_Vec4dSqrtLocal " , testSST_Math_Vec4dSqrtLocal }, +{ "testSST_Math_Vec4dMagnitude " , testSST_Math_Vec4dMagnitude }, +{ "testSST_Math_Vec4dNormalize " , testSST_Math_Vec4dNormalize }, +{ "testSST_Math_Vec4dNormalizeLocal " , testSST_Math_Vec4dNormalizeLocal }, +{ "testSST_Math_Vec4dProject " , testSST_Math_Vec4dProject }, +{ "testSST_Math_Vec4dProjectLocal " , testSST_Math_Vec4dProjectLocal }, +{ "testSST_Math_Vec4dMagnitudeSquared " , testSST_Math_Vec4dMagnitudeSquared }, +{ "testSST_Math_Vec4dDot " , testSST_Math_Vec4dDot } +}; +DECLARE_ZTESTBLOCK(SST_Math_Vec4d) + +/******************************************************************************/ + +static const char* testSST_Math_Vec4dAdd() +{ + SST_Vec4d x; /* 4 vector */ + SST_Vec4d y; /* 4 vector */ + SST_Vec4d w; /* 4 vector */ +/* Resetting test vectors */ + x.v[0] = -16.0000000000000000; + x.v[1] = 8.0000000000000000; + x.v[2] = -12.0000000000000000; + x.v[3] = 3.0000000000000000; + y.v[0] = -1.0000000000000000; + y.v[1] = 9.0000000000000000; + y.v[2] = 11.0000000000000000; + y.v[3] = 10.0000000000000000; + w.v[0] = 0.0000000000000000; + w.v[1] = 0.0000000000000000; + w.v[2] = 0.0000000000000000; + w.v[3] = 0.0000000000000000; +/* +[-16. 8. -12. 3.] +[ -1. 9. 11. 10.] +[-17. 17. -1. 13.] +*/ + SST_Math_Vec4dAdd(&x,&y,&w); + TASSERT(fabs((w.v[0])-( -17.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabs((w.v[1])-( 17.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _y failed!"); + TASSERT(fabs((w.v[2])-( -1.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _z failed!"); + TASSERT(fabs((w.v[3])-( 13.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _w failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec4dAddLocal() +{ + SST_Vec4d x; /* 4 vector */ + SST_Vec4d y; /* 4 vector */ +/* Resetting test vectors */ + x.v[0] = -7.0000000000000000; + x.v[1] = -6.0000000000000000; + x.v[2] = -15.0000000000000000; + x.v[3] = -1.0000000000000000; + y.v[0] = -1.0000000000000000; + y.v[1] = 14.0000000000000000; + y.v[2] = 7.0000000000000000; + y.v[3] = 10.0000000000000000; +/* +[ -7. -6. -15. -1.] +[ -1. 14. 7. 10.] +[-8. 8. -8. 9.] +*/ + SST_Math_Vec4dAddLocal(&x,&y); /* for accuracy */ + TASSERT(fabs((x.v[0])-( -8.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabs((x.v[1])-( 8.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _y failed!"); + TASSERT(fabs((x.v[2])-( -8.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _z failed!"); + TASSERT(fabs((x.v[3])-( 9.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _w failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec4dSubtract() +{ + SST_Vec4d x; /* 4 vector */ + SST_Vec4d y; /* 4 vector */ + SST_Vec4d w; /* 4 vector */ +/* Resetting test vectors */ + x.v[0] = -16.0000000000000000; + x.v[1] = 1.0000000000000000; + x.v[2] = -19.0000000000000000; + x.v[3] = 8.0000000000000000; + y.v[0] = 11.0000000000000000; + y.v[1] = 15.0000000000000000; + y.v[2] = 3.0000000000000000; + y.v[3] = -19.0000000000000000; + w.v[0] = 0.0000000000000000; + w.v[1] = 0.0000000000000000; + w.v[2] = 0.0000000000000000; + w.v[3] = 0.0000000000000000; +/* +[-16. 1. -19. 8.] +[ 11. 15. 3. -19.] +[-27. -14. -22. 27.] +*/ + SST_Math_Vec4dSubtract(&x,&y,&w); + TASSERT(fabs((w.v[0])-( -27.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabs((w.v[1])-( -14.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _y failed!"); + TASSERT(fabs((w.v[2])-( -22.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _z failed!"); + TASSERT(fabs((w.v[3])-( 27.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _w failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec4dSubtractLocal() +{ + SST_Vec4d x; /* 4 vector */ + SST_Vec4d y; /* 4 vector */ +/* Resetting test vectors */ + x.v[0] = -10.0000000000000000; + x.v[1] = 17.0000000000000000; + x.v[2] = 16.0000000000000000; + x.v[3] = 16.0000000000000000; + y.v[0] = -15.0000000000000000; + y.v[1] = 0.0000000000000000; + y.v[2] = 15.0000000000000000; + y.v[3] = 3.0000000000000000; +/* +[-10. 17. 16. 16.] +[-15. 0. 15. 3.] +[ 5. 17. 1. 13.] +*/ + SST_Math_Vec4dSubtractLocal(&x,&y); /* for accuracy */ + TASSERT(fabs((x.v[0])-( 5.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabs((x.v[1])-( 17.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _y failed!"); + TASSERT(fabs((x.v[2])-( 1.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _z failed!"); + TASSERT(fabs((x.v[3])-( 13.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _w failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec4dMultiply() +{ + SST_Vec4d x; /* 4 vector */ + SST_Vec4d y; /* 4 vector */ + SST_Vec4d w; /* 4 vector */ +/* Resetting test vectors */ + x.v[0] = -11.0000000000000000; + x.v[1] = -13.0000000000000000; + x.v[2] = 3.0000000000000000; + x.v[3] = -15.0000000000000000; + y.v[0] = -6.0000000000000000; + y.v[1] = -4.0000000000000000; + y.v[2] = -16.0000000000000000; + y.v[3] = 10.0000000000000000; + w.v[0] = 0.0000000000000000; + w.v[1] = 0.0000000000000000; + w.v[2] = 0.0000000000000000; + w.v[3] = 0.0000000000000000; +/* +[-11. -13. 3. -15.] +[ -6. -4. -16. 10.] +[ 66. 52. -48. -150.] +*/ + SST_Math_Vec4dMultiply(&x,&y,&w); + TASSERT(fabs((w.v[0])-( 66.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabs((w.v[1])-( 52.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _y failed!"); + TASSERT(fabs((w.v[2])-( -48.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _z failed!"); + TASSERT(fabs((w.v[3])-( -150.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _w failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec4dMultiplyLocal() +{ + SST_Vec4d x; /* 4 vector */ + SST_Vec4d y; /* 4 vector */ +/* Resetting test vectors */ + x.v[0] = -3.0000000000000000; + x.v[1] = 14.0000000000000000; + x.v[2] = 2.0000000000000000; + x.v[3] = 13.0000000000000000; + y.v[0] = -18.0000000000000000; + y.v[1] = -11.0000000000000000; + y.v[2] = 4.0000000000000000; + y.v[3] = -2.0000000000000000; +/* +[ -3. 14. 2. 13.] +[-18. -11. 4. -2.] +[ 54. -154. 8. -26.] +*/ + SST_Math_Vec4dMultiplyLocal(&x,&y); /* for accuracy */ + TASSERT(fabs((x.v[0])-( 54.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabs((x.v[1])-( -154.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _y failed!"); + TASSERT(fabs((x.v[2])-( 8.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _z failed!"); + TASSERT(fabs((x.v[3])-( -26.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _w failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec4dDivide() +{ + SST_Vec4d x; /* 4 vector */ + SST_Vec4d y; /* 4 vector */ + SST_Vec4d w; /* 4 vector */ +/* Resetting test vectors */ + x.v[0] = 4.0000000000000000; + x.v[1] = 34.0000000000000000; + x.v[2] = 17.0000000000000000; + x.v[3] = 9.0000000000000000; + y.v[0] = 26.0000000000000000; + y.v[1] = 16.0000000000000000; + y.v[2] = 8.0000000000000000; + y.v[3] = 20.0000000000000000; + w.v[0] = 0.0000000000000000; + w.v[1] = 0.0000000000000000; + w.v[2] = 0.0000000000000000; + w.v[3] = 0.0000000000000000; +/* +[ 4. 34. 17. 9.] +[ 26. 16. 8. 20.] +[ 0.15384615 2.125 2.125 0.45 ] +*/ + SST_Math_Vec4dDivide(&x,&y,&w); + TASSERT(fabs((w.v[0])-( 0.1538461538461539)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabs((w.v[1])-( 2.1250000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _y failed!"); + TASSERT(fabs((w.v[2])-( 2.1250000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _z failed!"); + TASSERT(fabs((w.v[3])-( 0.4500000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _w failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec4dDivideLocal() +{ + SST_Vec4d x; /* 4 vector */ + SST_Vec4d y; /* 4 vector */ +/* Resetting test vectors */ + x.v[0] = 7.0000000000000000; + x.v[1] = 35.0000000000000000; + x.v[2] = 16.0000000000000000; + x.v[3] = 4.0000000000000000; + y.v[0] = 28.0000000000000000; + y.v[1] = 22.0000000000000000; + y.v[2] = 3.0000000000000000; + y.v[3] = 39.0000000000000000; +/* +[ 7. 35. 16. 4.] +[ 28. 22. 3. 39.] +[ 0.25 1.59090909 5.33333333 0.1025641 ] +*/ + SST_Math_Vec4dDivideLocal(&x,&y); /* for accuracy */ + TASSERT(fabs((x.v[0])-( 0.2500000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabs((x.v[1])-( 1.5909090909090908)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _y failed!"); + TASSERT(fabs((x.v[2])-( 5.3333333333333330)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _z failed!"); + TASSERT(fabs((x.v[3])-( 0.1025641025641026)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _w failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec4dScale() +{ + SST_Vec4d x; /* 4 vector */ + SST_Vec4d w; /* 4 vector */ + double a; /* scalar */ +/* Resetting test vectors */ + x.v[0] = -7.0000000000000000; + x.v[1] = 1.0000000000000000; + x.v[2] = 5.0000000000000000; + x.v[3] = 0.0000000000000000; + w.v[0] = 0.0000000000000000; + w.v[1] = 0.0000000000000000; + w.v[2] = 0.0000000000000000; + w.v[3] = 0.0000000000000000; + a = 2.0000000000000000; +/* +[-7. 1. 5. 0.] +[-14. 2. 10. 0.] +*/ + SST_Math_Vec4dScale(&x,a,&w); + TASSERT(fabs((w.v[0])-( -14.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabs((w.v[1])-( 2.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _y failed!"); + TASSERT(fabs((w.v[2])-( 10.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _z failed!"); + TASSERT(fabs((w.v[3])-( 0.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _w failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec4dScaleLocal() +{ + SST_Vec4d x; /* 4 vector */ + double a; /* scalar */ +/* Resetting test vectors */ + x.v[0] = 4.0000000000000000; + x.v[1] = 7.0000000000000000; + x.v[2] = -8.0000000000000000; + x.v[3] = 11.0000000000000000; + a = 2.0000000000000000; +/* +[ 4. 7. -8. 11.] +[ 8. 14. -16. 22.] +*/ + SST_Math_Vec4dScaleLocal(&x,a); /* for accuracy */ + TASSERT(fabs((x.v[0])-( 8.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabs((x.v[1])-( 14.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _y failed!"); + TASSERT(fabs((x.v[2])-( -16.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _z failed!"); + TASSERT(fabs((x.v[3])-( 22.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _w failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec4dAbs() +{ + SST_Vec4d x; /* 4 vector */ + SST_Vec4d w; /* 4 vector */ +/* Resetting test vectors */ + x.v[0] = 10.0000000000000000; + x.v[1] = -8.0000000000000000; + x.v[2] = -17.0000000000000000; + x.v[3] = -13.0000000000000000; + w.v[0] = 0.0000000000000000; + w.v[1] = 0.0000000000000000; + w.v[2] = 0.0000000000000000; + w.v[3] = 0.0000000000000000; +/* +[ 10. -8. -17. -13.] +[ 10. 8. 17. 13.] +*/ + SST_Math_Vec4dAbs(&x,&w); + TASSERT(fabs((w.v[0])-( 10.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabs((w.v[1])-( 8.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _y failed!"); + TASSERT(fabs((w.v[2])-( 17.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _z failed!"); + TASSERT(fabs((w.v[3])-( 13.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _w failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec4dAbsLocal() +{ + SST_Vec4d x; /* 4 vector */ +/* Resetting test vectors */ + x.v[0] = 3.0000000000000000; + x.v[1] = -11.0000000000000000; + x.v[2] = 9.0000000000000000; + x.v[3] = 9.0000000000000000; +/* +[ 3. -11. 9. 9.] +[ 3. 11. 9. 9.] +*/ + SST_Math_Vec4dAbsLocal(&x); /* for accuracy */ + TASSERT(fabs((x.v[0])-( 3.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabs((x.v[1])-( 11.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _y failed!"); + TASSERT(fabs((x.v[2])-( 9.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _z failed!"); + TASSERT(fabs((x.v[3])-( 9.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _w failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec4dBias() +{ + SST_Vec4d x; /* 4 vector */ + SST_Vec4d w; /* 4 vector */ + double a; /* scalar */ +/* Resetting test vectors */ + x.v[0] = 6.0000000000000000; + x.v[1] = 10.0000000000000000; + x.v[2] = -16.0000000000000000; + x.v[3] = -12.0000000000000000; + w.v[0] = 0.0000000000000000; + w.v[1] = 0.0000000000000000; + w.v[2] = 0.0000000000000000; + w.v[3] = 0.0000000000000000; + a = -5.0000000000000000; +/* +[ 6. 10. -16. -12.] +[ 12. 20. -32. -24.] +*/ + SST_Math_Vec4dBias(&x,a,&w); + TASSERT(fabs((w.v[0])-( 1.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabs((w.v[1])-( 5.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _y failed!"); + TASSERT(fabs((w.v[2])-( -21.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _z failed!"); + TASSERT(fabs((w.v[3])-( -17.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _w failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec4dBiasLocal() +{ + SST_Vec4d x; /* 4 vector */ + double a; /* scalar */ +/* Resetting test vectors */ + x.v[0] = 1.0000000000000000; + x.v[1] = 4.0000000000000000; + x.v[2] = -13.0000000000000000; + x.v[3] = -2.0000000000000000; + a = -12.0000000000000000; +/* +[ 1. 4. -13. -2.] +[ 2. 8. -26. -4.] +*/ + SST_Math_Vec4dBiasLocal(&x,a); /* for accuracy */ + TASSERT(fabs((x.v[0])-( -11.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabs((x.v[1])-( -8.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _y failed!"); + TASSERT(fabs((x.v[2])-( -25.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _z failed!"); + TASSERT(fabs((x.v[3])-( -14.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _w failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec4dNegate() +{ + SST_Vec4d x; /* 4 vector */ + SST_Vec4d w; /* 4 vector */ +/* Resetting test vectors */ + x.v[0] = 8.0000000000000000; + x.v[1] = -8.0000000000000000; + x.v[2] = 12.0000000000000000; + x.v[3] = -12.0000000000000000; + w.v[0] = 0.0000000000000000; + w.v[1] = 0.0000000000000000; + w.v[2] = 0.0000000000000000; + w.v[3] = 0.0000000000000000; +/* +[ 8. -8. 12. -12.] +[ -8. 8. -12. 12.] +*/ + SST_Math_Vec4dNegate(&x,&w); + TASSERT(fabs((w.v[0])-( -8.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabs((w.v[1])-( 8.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _y failed!"); + TASSERT(fabs((w.v[2])-( -12.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _z failed!"); + TASSERT(fabs((w.v[3])-( 12.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _w failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec4dNegateLocal() +{ + SST_Vec4d x; /* 4 vector */ +/* Resetting test vectors */ + x.v[0] = -8.0000000000000000; + x.v[1] = -12.0000000000000000; + x.v[2] = 12.0000000000000000; + x.v[3] = -5.0000000000000000; +/* +[ -8. -12. 12. -5.] +[ 8. 12. -12. 5.] +*/ + SST_Math_Vec4dNegateLocal(&x); /* for accuracy */ + TASSERT(fabs((x.v[0])-( 8.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabs((x.v[1])-( 12.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _y failed!"); + TASSERT(fabs((x.v[2])-( -12.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _z failed!"); + TASSERT(fabs((x.v[3])-( 5.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _w failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec4dSqrt() +{ + SST_Vec4d x; /* 4 vector */ + SST_Vec4d w; /* 4 vector */ +/* Resetting test vectors */ + x.v[0] = 12.0000000000000000; + x.v[1] = 19.0000000000000000; + x.v[2] = 35.0000000000000000; + x.v[3] = 3.0000000000000000; + w.v[0] = 0.0000000000000000; + w.v[1] = 0.0000000000000000; + w.v[2] = 0.0000000000000000; + w.v[3] = 0.0000000000000000; +/* +[ 12. 19. 35. 3.] +[ 3.46410162 4.35889894 5.91607978 1.73205081] +*/ + SST_Math_Vec4dSqrt(&x,&w); + TASSERT(fabs((w.v[0])-( 3.4641016151377544)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabs((w.v[1])-( 4.3588989435406740)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _y failed!"); + TASSERT(fabs((w.v[2])-( 5.9160797830996161)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _z failed!"); + TASSERT(fabs((w.v[3])-( 1.7320508075688772)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _w failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec4dSqrtLocal() +{ + SST_Vec4d x; /* 4 vector */ +/* Resetting test vectors */ + x.v[0] = 23.0000000000000000; + x.v[1] = 16.0000000000000000; + x.v[2] = 29.0000000000000000; + x.v[3] = 31.0000000000000000; +/* +[ 23. 16. 29. 31.] +[ 4.79583152 4. 5.38516481 5.56776436] +*/ + SST_Math_Vec4dSqrtLocal(&x); /* for accuracy */ + TASSERT(fabs((x.v[0])-( 4.7958315233127191)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabs((x.v[1])-( 4.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _y failed!"); + TASSERT(fabs((x.v[2])-( 5.3851648071345037)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _z failed!"); + TASSERT(fabs((x.v[3])-( 5.5677643628300215)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _w failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec4dRecipSqrt() +{ + SST_Vec4d x; /* 4 vector */ + SST_Vec4d w; /* 4 vector */ +/* Resetting test vectors */ + x.v[0] = 27.0000000000000000; + x.v[1] = 26.0000000000000000; + x.v[2] = 32.0000000000000000; + x.v[3] = 16.0000000000000000; + w.v[0] = 0.0000000000000000; + w.v[1] = 0.0000000000000000; + w.v[2] = 0.0000000000000000; + w.v[3] = 0.0000000000000000; +/* +[ 27. 26. 32. 16.] +[ 0.19245009 0.19611614 0.1767767 0.25 ] +*/ + SST_Math_Vec4dRecipSqrt(&x,&w); + TASSERT(fabs((w.v[0])-( 0.1924500897298753)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabs((w.v[1])-( 0.1961161351381840)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _y failed!"); + TASSERT(fabs((w.v[2])-( 0.1767766952966369)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _z failed!"); + TASSERT(fabs((w.v[3])-( 0.2500000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _w failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec4dRecipSqrtLocal() +{ + SST_Vec4d x; /* 4 vector */ +/* Resetting test vectors */ + x.v[0] = 10.0000000000000000; + x.v[1] = 3.0000000000000000; + x.v[2] = 39.0000000000000000; + x.v[3] = 4.0000000000000000; +/* +[ 10. 3. 39. 4.] +[ 0.31622777 0.57735027 0.16012815 0.5 ] +*/ + SST_Math_Vec4dRecipSqrtLocal(&x); /* for accuracy */ + TASSERT(fabs((x.v[0])-( 0.3162277660168379)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabs((x.v[1])-( 0.5773502691896258)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _y failed!"); + TASSERT(fabs((x.v[2])-( 0.1601281538050871)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _z failed!"); + TASSERT(fabs((x.v[3])-( 0.5000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _w failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec4dRecip() +{ + SST_Vec4d x; /* 4 vector */ + SST_Vec4d w; /* 4 vector */ +/* Resetting test vectors */ + x.v[0] = 14.0000000000000000; + x.v[1] = 11.0000000000000000; + x.v[2] = 3.0000000000000000; + x.v[3] = 11.0000000000000000; + w.v[0] = 0.0000000000000000; + w.v[1] = 0.0000000000000000; + w.v[2] = 0.0000000000000000; + w.v[3] = 0.0000000000000000; +/* +[ 14. 11. 3. 11.] +[ 0.07142857 0.09090909 0.33333333 0.09090909] +*/ + SST_Math_Vec4dRecip(&x,&w); + TASSERT(fabs((w.v[0])-( 0.0714285714285714)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabs((w.v[1])-( 0.0909090909090909)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _y failed!"); + TASSERT(fabs((w.v[2])-( 0.3333333333333333)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _z failed!"); + TASSERT(fabs((w.v[3])-( 0.0909090909090909)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _w failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec4dRecipLocal() +{ + SST_Vec4d x; /* 4 vector */ +/* Resetting test vectors */ + x.v[0] = 8.0000000000000000; + x.v[1] = 6.0000000000000000; + x.v[2] = 33.0000000000000000; + x.v[3] = 31.0000000000000000; +/* +[ 8. 6. 33. 31.] +[ 0.35355339 0.40824829 0.17407766 0.1796053 ] +*/ + SST_Math_Vec4dRecipLocal(&x); /* for accuracy */ + TASSERT(fabs((x.v[0])-( 0.1250000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabs((x.v[1])-( 0.1666666666666667)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _y failed!"); + TASSERT(fabs((x.v[2])-( 0.0303030303030303)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _z failed!"); + TASSERT(fabs((x.v[3])-( 0.0322580645161290)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _w failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec4dNormalize() +{ + SST_Vec4d x; /* 4 vector */ + SST_Vec4d w; /* 4 vector */ +/* Resetting test vectors */ + x.v[0] = -1.0000000000000000; + x.v[1] = 2.0000000000000000; + x.v[2] = -17.0000000000000000; + x.v[3] = 10.0000000000000000; + w.v[0] = 0.0000000000000000; + w.v[1] = 0.0000000000000000; + w.v[2] = 0.0000000000000000; + w.v[3] = 0.0000000000000000; +/* +[ -1. 2. -17. 10.] +[-0.05037927 0.10075854 -0.85644763 0.50379272] +*/ + SST_Math_Vec4dNormalize(&x,&w); + TASSERT(fabs((w.v[0])-( -0.0503792721859878)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabs((w.v[1])-( 0.1007585443719757)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _y failed!"); + TASSERT(fabs((w.v[2])-( -0.8564476271617932)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _z failed!"); + TASSERT(fabs((w.v[3])-( 0.5037927218598783)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _w failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec4dNormalizeLocal() +{ + SST_Vec4d x; /* 4 vector */ +/* Resetting test vectors */ + x.v[0] = 0.0000000000000000; + x.v[1] = 7.0000000000000000; + x.v[2] = -5.0000000000000000; + x.v[3] = -12.0000000000000000; +/* +[ 0. 7. -5. -12.] +[ 0. 0.47409982 -0.33864273 -0.81274255] +*/ + SST_Math_Vec4dNormalizeLocal(&x); /* for accuracy */ + TASSERT(fabs((x.v[0])-( 0.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabs((x.v[1])-( 0.4740998230350175)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _y failed!"); + TASSERT(fabs((x.v[2])-( -0.3386427307392982)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _z failed!"); + TASSERT(fabs((x.v[3])-( -0.8127425537743156)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _w failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec4dProject() +{ + SST_Vec4d x; /* 4 vector */ + SST_Vec4d y; /* 4 vector */ + SST_Vec4d w; /* 4 vector */ +/* Resetting test vectors */ + x.v[0] = 11.0000000000000000; + x.v[1] = -10.0000000000000000; + x.v[2] = 7.0000000000000000; + x.v[3] = 10.0000000000000000; + y.v[0] = 16.0000000000000000; + y.v[1] = -1.0000000000000000; + y.v[2] = -9.0000000000000000; + y.v[3] = -19.0000000000000000; + w.v[0] = 0.0000000000000000; + w.v[1] = 0.0000000000000000; + w.v[2] = 0.0000000000000000; + w.v[3] = 0.0000000000000000; +/* +[ 11. -10. 7. 10.] +[ 16. -1. -9. -19.] +[-1.53361946 0.09585122 0.86266094 1.8211731 ] +*/ + SST_Math_Vec4dProject(&x,&y,&w); + TASSERT(fabs((w.v[0])-( -1.5336194563662375)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabs((w.v[1])-( 0.0958512160228898)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _y failed!"); + TASSERT(fabs((w.v[2])-( 0.8626609442060086)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _z failed!"); + TASSERT(fabs((w.v[3])-( 1.8211731044349071)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _w failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec4dProjectLocal() +{ + SST_Vec4d x; /* 4 vector */ + SST_Vec4d y; /* 4 vector */ +/* Resetting test vectors */ + x.v[0] = 15.0000000000000000; + x.v[1] = -7.0000000000000000; + x.v[2] = -10.0000000000000000; + x.v[3] = -19.0000000000000000; + y.v[0] = 12.0000000000000000; + y.v[1] = -5.0000000000000000; + y.v[2] = 3.0000000000000000; + y.v[3] = -20.0000000000000000; +/* +[ 15. -7. -10. -19.] +[ 12. -5. 3. -20.] +[ 11.73010381 -4.88754325 2.93252595 -19.55017301] +*/ + SST_Math_Vec4dProjectLocal(&x,&y); /* for accuracy */ + TASSERT(fabs((x.v[0])-( 11.7301038062283745)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabs((x.v[1])-( -4.8875432525951554)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _y failed!"); + TASSERT(fabs((x.v[2])-( 2.9325259515570936)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _z failed!"); + TASSERT(fabs((x.v[3])-( -19.5501730103806217)) <=100*DBL_EPSILON /* yes this is bad */,"Entry _w failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + + +/******************************************************************************/ + +static const char* testSST_Math_Vec4dMagnitude() +{ + SST_Vec4d x; /* 4 vector */ + double a; /* scalar */ +/* Resetting test vectors */ + x.v[0] = 9.0000000000000000; + x.v[1] = -19.0000000000000000; + x.v[2] = 12.0000000000000000; + x.v[3] = 12.0000000000000000; +/* +[ 9. -19. 12. 12.] +27.0185121722 +*/ + a = SST_Math_Vec4dMagnitude(&x); + TASSERT(fabs((a)-( 27.0185121722125920)) <=100*DBL_EPSILON /* yes this is bad */,"Magnitude failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec4dMagnitudeSquared() +{ + SST_Vec4d x; /* 4 vector */ + double a; /* scalar */ +/* Resetting test vectors */ + x.v[0] = 13.0000000000000000; + x.v[1] = 5.0000000000000000; + x.v[2] = 18.0000000000000000; + x.v[3] = 5.0000000000000000; +/* +[ 13. 5. 18. 5.] +543.0 +*/ + a = SST_Math_Vec4dMagnitudeSquared(&x); + TASSERT(fabs((a)-( 543.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"MagnitudeSquared failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec4dDot() +{ + SST_Vec4d x; /* 4 vector */ + SST_Vec4d y; /* 4 vector */ + double a; /* scalar */ +/* Resetting test vectors */ + x.v[0] = 12.0000000000000000; + x.v[1] = -12.0000000000000000; + x.v[2] = -3.0000000000000000; + x.v[3] = -9.0000000000000000; + y.v[0] = -9.0000000000000000; + y.v[1] = 7.0000000000000000; + y.v[2] = -11.0000000000000000; + y.v[3] = -7.0000000000000000; +/* +[ 12. -12. -3. -9.] +-96.0 +*/ + a = SST_Math_Vec4dDot(&x,&y); + TASSERT(fabs((a)-( -96.0000000000000000)) <=100*DBL_EPSILON /* yes this is bad */,"Dot failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + diff --git a/ZTestSuite/Test-SST_Vec4f.cpp b/ZTestSuite/Test-SST_Vec4f.cpp new file mode 100644 index 0000000..99e2606 --- /dev/null +++ b/ZTestSuite/Test-SST_Vec4f.cpp @@ -0,0 +1,859 @@ +/* + AUTOMATICALLY GENERATED FILE - DO NOT EDIT! + Please change MatrixNxN.py and re-run it +*/ +/* Generated with ./VectorN.py n = 4, TYPE = float */ + +#include "ZUnitTest.hpp" +#include <float.h> +#include <math.h> +#include <stdlib.h> +#include <stdio.h> +#include <SST/SST_Vec4.h> + + + + +static const char* testSST_Math_Vec4fAdd(); +static const char* testSST_Math_Vec4fAddLocal(); +static const char* testSST_Math_Vec4fSubtract(); +static const char* testSST_Math_Vec4fSubtractLocal(); +static const char* testSST_Math_Vec4fMultiply(); +static const char* testSST_Math_Vec4fMultiplyLocal(); +static const char* testSST_Math_Vec4fScale(); +static const char* testSST_Math_Vec4fScaleLocal(); +static const char* testSST_Math_Vec4fDivide(); +static const char* testSST_Math_Vec4fDivideLocal(); +static const char* testSST_Math_Vec4fAbs(); +static const char* testSST_Math_Vec4fAbsLocal(); +static const char* testSST_Math_Vec4fNegate(); +static const char* testSST_Math_Vec4fNegateLocal(); +static const char* testSST_Math_Vec4fBias(); +static const char* testSST_Math_Vec4fBiasLocal(); +static const char* testSST_Math_Vec4fRecip(); +static const char* testSST_Math_Vec4fRecipLocal(); +static const char* testSST_Math_Vec4fRecipSqrt(); +static const char* testSST_Math_Vec4fRecipSqrtLocal(); +static const char* testSST_Math_Vec4fSqrt(); +static const char* testSST_Math_Vec4fSqrtLocal(); +static const char* testSST_Math_Vec4fSqrt(); +static const char* testSST_Math_Vec4fSqrtLocal(); +static const char* testSST_Math_Vec4fProject(); +static const char* testSST_Math_Vec4fProjectLocal(); +static const char* testSST_Math_Vec4fMagnitude(); +static const char* testSST_Math_Vec4fNormalize(); +static const char* testSST_Math_Vec4fNormalizeLocal(); +static const char* testSST_Math_Vec4fMagnitudeSquared(); +static const char* testSST_Math_Vec4fDot(); +// List of unit tests +ZUnitTest SST_Math_Vec4fUnitTests[] = +{ +{ "testSST_Math_Vec4fAdd " , testSST_Math_Vec4fAdd }, +{ "testSST_Math_Vec4fAddLocal " , testSST_Math_Vec4fAddLocal }, +{ "testSST_Math_Vec4fSubtract " , testSST_Math_Vec4fSubtract }, +{ "testSST_Math_Vec4fSubtractLocal " , testSST_Math_Vec4fSubtractLocal }, +{ "testSST_Math_Vec4fMultiply " , testSST_Math_Vec4fMultiply }, +{ "testSST_Math_Vec4fMultiplyLocal " , testSST_Math_Vec4fMultiplyLocal }, +{ "testSST_Math_Vec4fScale " , testSST_Math_Vec4fScale }, +{ "testSST_Math_Vec4fScaleLocal " , testSST_Math_Vec4fScaleLocal }, +{ "testSST_Math_Vec4fDivide " , testSST_Math_Vec4fDivide }, +{ "testSST_Math_Vec4fDivideLocal " , testSST_Math_Vec4fDivideLocal }, +{ "testSST_Math_Vec4fAbs " , testSST_Math_Vec4fAbs }, +{ "testSST_Math_Vec4fAbsLocal " , testSST_Math_Vec4fAbsLocal }, +{ "testSST_Math_Vec4fNegate " , testSST_Math_Vec4fNegate }, +{ "testSST_Math_Vec4fNegateLocal " , testSST_Math_Vec4fNegateLocal }, +{ "testSST_Math_Vec4fBias " , testSST_Math_Vec4fBias }, +{ "testSST_Math_Vec4fBiasLocal " , testSST_Math_Vec4fBiasLocal }, +{ "testSST_Math_Vec4fRecip " , testSST_Math_Vec4fRecip }, +{ "testSST_Math_Vec4fRecipLocal " , testSST_Math_Vec4fRecipLocal }, +{ "testSST_Math_Vec4fRecipSqrt " , testSST_Math_Vec4fRecipSqrt }, +{ "testSST_Math_Vec4fRecipSqrtLocal " , testSST_Math_Vec4fRecipSqrtLocal }, +{ "testSST_Math_Vec4fSqrt " , testSST_Math_Vec4fSqrt }, +{ "testSST_Math_Vec4fSqrtLocal " , testSST_Math_Vec4fSqrtLocal }, +{ "testSST_Math_Vec4fSqrt " , testSST_Math_Vec4fSqrt }, +{ "testSST_Math_Vec4fSqrtLocal " , testSST_Math_Vec4fSqrtLocal }, +{ "testSST_Math_Vec4fMagnitude " , testSST_Math_Vec4fMagnitude }, +{ "testSST_Math_Vec4fNormalize " , testSST_Math_Vec4fNormalize }, +{ "testSST_Math_Vec4fNormalizeLocal " , testSST_Math_Vec4fNormalizeLocal }, +{ "testSST_Math_Vec4fProject " , testSST_Math_Vec4fProject }, +{ "testSST_Math_Vec4fProjectLocal " , testSST_Math_Vec4fProjectLocal }, +{ "testSST_Math_Vec4fMagnitudeSquared " , testSST_Math_Vec4fMagnitudeSquared }, +{ "testSST_Math_Vec4fDot " , testSST_Math_Vec4fDot } +}; +DECLARE_ZTESTBLOCK(SST_Math_Vec4f) + +/******************************************************************************/ + +static const char* testSST_Math_Vec4fAdd() +{ + SST_Vec4f x; /* 4 vector */ + SST_Vec4f y; /* 4 vector */ + SST_Vec4f w; /* 4 vector */ +/* Resetting test vectors */ + x.v[0] = 19.000000f; + x.v[1] = -3.000000f; + x.v[2] = 1.000000f; + x.v[3] = -7.000000f; + y.v[0] = 3.000000f; + y.v[1] = -10.000000f; + y.v[2] = 0.000000f; + y.v[3] = 8.000000f; + w.v[0] = 0.000000f; + w.v[1] = 0.000000f; + w.v[2] = 0.000000f; + w.v[3] = 0.000000f; +/* +[ 19. -3. 1. -7.] +[ 3. -10. 0. 8.] +[ 22. -13. 1. 1.] +*/ + SST_Math_Vec4fAdd(&x,&y,&w); + TASSERT(fabsf((w.v[0])-(22.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabsf((w.v[1])-(-13.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _y failed!"); + TASSERT(fabsf((w.v[2])-(1.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _z failed!"); + TASSERT(fabsf((w.v[3])-(1.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _w failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec4fAddLocal() +{ + SST_Vec4f x; /* 4 vector */ + SST_Vec4f y; /* 4 vector */ +/* Resetting test vectors */ + x.v[0] = 4.000000f; + x.v[1] = 10.000000f; + x.v[2] = -4.000000f; + x.v[3] = -18.000000f; + y.v[0] = 7.000000f; + y.v[1] = -15.000000f; + y.v[2] = 0.000000f; + y.v[3] = -16.000000f; +/* +[ 4. 10. -4. -18.] +[ 7. -15. 0. -16.] +[ 11. -5. -4. -34.] +*/ + SST_Math_Vec4fAddLocal(&x,&y); /* for accuracy */ + TASSERT(fabsf((x.v[0])-(11.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabsf((x.v[1])-(-5.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _y failed!"); + TASSERT(fabsf((x.v[2])-(-4.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _z failed!"); + TASSERT(fabsf((x.v[3])-(-34.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _w failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec4fSubtract() +{ + SST_Vec4f x; /* 4 vector */ + SST_Vec4f y; /* 4 vector */ + SST_Vec4f w; /* 4 vector */ +/* Resetting test vectors */ + x.v[0] = 3.000000f; + x.v[1] = 1.000000f; + x.v[2] = -19.000000f; + x.v[3] = -13.000000f; + y.v[0] = 5.000000f; + y.v[1] = -3.000000f; + y.v[2] = -2.000000f; + y.v[3] = -15.000000f; + w.v[0] = 0.000000f; + w.v[1] = 0.000000f; + w.v[2] = 0.000000f; + w.v[3] = 0.000000f; +/* +[ 3. 1. -19. -13.] +[ 5. -3. -2. -15.] +[ -2. 4. -17. 2.] +*/ + SST_Math_Vec4fSubtract(&x,&y,&w); + TASSERT(fabsf((w.v[0])-(-2.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabsf((w.v[1])-(4.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _y failed!"); + TASSERT(fabsf((w.v[2])-(-17.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _z failed!"); + TASSERT(fabsf((w.v[3])-(2.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _w failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec4fSubtractLocal() +{ + SST_Vec4f x; /* 4 vector */ + SST_Vec4f y; /* 4 vector */ +/* Resetting test vectors */ + x.v[0] = -9.000000f; + x.v[1] = 0.000000f; + x.v[2] = 8.000000f; + x.v[3] = 13.000000f; + y.v[0] = 10.000000f; + y.v[1] = -19.000000f; + y.v[2] = -9.000000f; + y.v[3] = -19.000000f; +/* +[ -9. 0. 8. 13.] +[ 10. -19. -9. -19.] +[-19. 19. 17. 32.] +*/ + SST_Math_Vec4fSubtractLocal(&x,&y); /* for accuracy */ + TASSERT(fabsf((x.v[0])-(-19.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabsf((x.v[1])-(19.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _y failed!"); + TASSERT(fabsf((x.v[2])-(17.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _z failed!"); + TASSERT(fabsf((x.v[3])-(32.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _w failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec4fMultiply() +{ + SST_Vec4f x; /* 4 vector */ + SST_Vec4f y; /* 4 vector */ + SST_Vec4f w; /* 4 vector */ +/* Resetting test vectors */ + x.v[0] = 9.000000f; + x.v[1] = -3.000000f; + x.v[2] = -18.000000f; + x.v[3] = 1.000000f; + y.v[0] = -15.000000f; + y.v[1] = -4.000000f; + y.v[2] = -17.000000f; + y.v[3] = -13.000000f; + w.v[0] = 0.000000f; + w.v[1] = 0.000000f; + w.v[2] = 0.000000f; + w.v[3] = 0.000000f; +/* +[ 9. -3. -18. 1.] +[-15. -4. -17. -13.] +[-135. 12. 306. -13.] +*/ + SST_Math_Vec4fMultiply(&x,&y,&w); + TASSERT(fabsf((w.v[0])-(-135.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabsf((w.v[1])-(12.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _y failed!"); + TASSERT(fabsf((w.v[2])-(306.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _z failed!"); + TASSERT(fabsf((w.v[3])-(-13.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _w failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec4fMultiplyLocal() +{ + SST_Vec4f x; /* 4 vector */ + SST_Vec4f y; /* 4 vector */ +/* Resetting test vectors */ + x.v[0] = 2.000000f; + x.v[1] = 0.000000f; + x.v[2] = -19.000000f; + x.v[3] = -20.000000f; + y.v[0] = -16.000000f; + y.v[1] = 5.000000f; + y.v[2] = -3.000000f; + y.v[3] = 13.000000f; +/* +[ 2. 0. -19. -20.] +[-16. 5. -3. 13.] +[ -32. 0. 57. -260.] +*/ + SST_Math_Vec4fMultiplyLocal(&x,&y); /* for accuracy */ + TASSERT(fabsf((x.v[0])-(-32.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabsf((x.v[1])-(0.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _y failed!"); + TASSERT(fabsf((x.v[2])-(57.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _z failed!"); + TASSERT(fabsf((x.v[3])-(-260.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _w failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec4fDivide() +{ + SST_Vec4f x; /* 4 vector */ + SST_Vec4f y; /* 4 vector */ + SST_Vec4f w; /* 4 vector */ +/* Resetting test vectors */ + x.v[0] = 1.000000f; + x.v[1] = 24.000000f; + x.v[2] = 26.000000f; + x.v[3] = 7.000000f; + y.v[0] = 29.000000f; + y.v[1] = 38.000000f; + y.v[2] = 14.000000f; + y.v[3] = 30.000000f; + w.v[0] = 0.000000f; + w.v[1] = 0.000000f; + w.v[2] = 0.000000f; + w.v[3] = 0.000000f; +/* +[ 1. 24. 26. 7.] +[ 29. 38. 14. 30.] +[ 0.03448276 0.63157892 1.85714281 0.23333333] +*/ + SST_Math_Vec4fDivide(&x,&y,&w); + TASSERT(fabsf((w.v[0])-(0.034483f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabsf((w.v[1])-(0.631579f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _y failed!"); + TASSERT(fabsf((w.v[2])-(1.857143f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _z failed!"); + TASSERT(fabsf((w.v[3])-(0.233333f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _w failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec4fDivideLocal() +{ + SST_Vec4f x; /* 4 vector */ + SST_Vec4f y; /* 4 vector */ +/* Resetting test vectors */ + x.v[0] = 26.000000f; + x.v[1] = 9.000000f; + x.v[2] = 12.000000f; + x.v[3] = 10.000000f; + y.v[0] = 24.000000f; + y.v[1] = 3.000000f; + y.v[2] = 25.000000f; + y.v[3] = 4.000000f; +/* +[ 26. 9. 12. 10.] +[ 24. 3. 25. 4.] +[ 1.08333337 3. 0.47999999 2.5 ] +*/ + SST_Math_Vec4fDivideLocal(&x,&y); /* for accuracy */ + TASSERT(fabsf((x.v[0])-(1.083333f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabsf((x.v[1])-(3.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _y failed!"); + TASSERT(fabsf((x.v[2])-(0.480000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _z failed!"); + TASSERT(fabsf((x.v[3])-(2.500000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _w failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec4fScale() +{ + SST_Vec4f x; /* 4 vector */ + SST_Vec4f w; /* 4 vector */ + float a; /* scalar */ +/* Resetting test vectors */ + x.v[0] = 8.000000f; + x.v[1] = -9.000000f; + x.v[2] = 10.000000f; + x.v[3] = -20.000000f; + w.v[0] = 0.000000f; + w.v[1] = 0.000000f; + w.v[2] = 0.000000f; + w.v[3] = 0.000000f; + a = 2.000000f; +/* +[ 8. -9. 10. -20.] +[ 16. -18. 20. -40.] +*/ + SST_Math_Vec4fScale(&x,a,&w); + TASSERT(fabsf((w.v[0])-(16.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabsf((w.v[1])-(-18.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _y failed!"); + TASSERT(fabsf((w.v[2])-(20.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _z failed!"); + TASSERT(fabsf((w.v[3])-(-40.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _w failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec4fScaleLocal() +{ + SST_Vec4f x; /* 4 vector */ + float a; /* scalar */ +/* Resetting test vectors */ + x.v[0] = -9.000000f; + x.v[1] = -9.000000f; + x.v[2] = 12.000000f; + x.v[3] = -20.000000f; + a = 2.000000f; +/* +[ -9. -9. 12. -20.] +[-18. -18. 24. -40.] +*/ + SST_Math_Vec4fScaleLocal(&x,a); /* for accuracy */ + TASSERT(fabsf((x.v[0])-(-18.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabsf((x.v[1])-(-18.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _y failed!"); + TASSERT(fabsf((x.v[2])-(24.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _z failed!"); + TASSERT(fabsf((x.v[3])-(-40.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _w failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec4fAbs() +{ + SST_Vec4f x; /* 4 vector */ + SST_Vec4f w; /* 4 vector */ +/* Resetting test vectors */ + x.v[0] = 17.000000f; + x.v[1] = -13.000000f; + x.v[2] = -16.000000f; + x.v[3] = -14.000000f; + w.v[0] = 0.000000f; + w.v[1] = 0.000000f; + w.v[2] = 0.000000f; + w.v[3] = 0.000000f; +/* +[ 17. -13. -16. -14.] +[ 17. 13. 16. 14.] +*/ + SST_Math_Vec4fAbs(&x,&w); + TASSERT(fabsf((w.v[0])-(17.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabsf((w.v[1])-(13.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _y failed!"); + TASSERT(fabsf((w.v[2])-(16.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _z failed!"); + TASSERT(fabsf((w.v[3])-(14.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _w failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec4fAbsLocal() +{ + SST_Vec4f x; /* 4 vector */ +/* Resetting test vectors */ + x.v[0] = -14.000000f; + x.v[1] = -9.000000f; + x.v[2] = -20.000000f; + x.v[3] = 10.000000f; +/* +[-14. -9. -20. 10.] +[ 14. 9. 20. 10.] +*/ + SST_Math_Vec4fAbsLocal(&x); /* for accuracy */ + TASSERT(fabsf((x.v[0])-(14.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabsf((x.v[1])-(9.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _y failed!"); + TASSERT(fabsf((x.v[2])-(20.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _z failed!"); + TASSERT(fabsf((x.v[3])-(10.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _w failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec4fBias() +{ + SST_Vec4f x; /* 4 vector */ + SST_Vec4f w; /* 4 vector */ + float a; /* scalar */ +/* Resetting test vectors */ + x.v[0] = 5.000000f; + x.v[1] = 12.000000f; + x.v[2] = -7.000000f; + x.v[3] = 17.000000f; + w.v[0] = 0.000000f; + w.v[1] = 0.000000f; + w.v[2] = 0.000000f; + w.v[3] = 0.000000f; + a = -13.000000f; +/* +[ 5. 12. -7. 17.] +[ 10. 24. -14. 34.] +*/ + SST_Math_Vec4fBias(&x,a,&w); + TASSERT(fabsf((w.v[0])-(-8.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabsf((w.v[1])-(-1.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _y failed!"); + TASSERT(fabsf((w.v[2])-(-20.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _z failed!"); + TASSERT(fabsf((w.v[3])-(4.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _w failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec4fBiasLocal() +{ + SST_Vec4f x; /* 4 vector */ + float a; /* scalar */ +/* Resetting test vectors */ + x.v[0] = 10.000000f; + x.v[1] = 10.000000f; + x.v[2] = -5.000000f; + x.v[3] = 14.000000f; + a = 7.000000f; +/* +[ 10. 10. -5. 14.] +[ 20. 20. -10. 28.] +*/ + SST_Math_Vec4fBiasLocal(&x,a); /* for accuracy */ + TASSERT(fabsf((x.v[0])-(17.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabsf((x.v[1])-(17.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _y failed!"); + TASSERT(fabsf((x.v[2])-(2.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _z failed!"); + TASSERT(fabsf((x.v[3])-(21.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _w failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec4fNegate() +{ + SST_Vec4f x; /* 4 vector */ + SST_Vec4f w; /* 4 vector */ +/* Resetting test vectors */ + x.v[0] = -17.000000f; + x.v[1] = -8.000000f; + x.v[2] = -15.000000f; + x.v[3] = 8.000000f; + w.v[0] = 0.000000f; + w.v[1] = 0.000000f; + w.v[2] = 0.000000f; + w.v[3] = 0.000000f; +/* +[-17. -8. -15. 8.] +[ 17. 8. 15. -8.] +*/ + SST_Math_Vec4fNegate(&x,&w); + TASSERT(fabsf((w.v[0])-(17.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabsf((w.v[1])-(8.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _y failed!"); + TASSERT(fabsf((w.v[2])-(15.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _z failed!"); + TASSERT(fabsf((w.v[3])-(-8.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _w failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec4fNegateLocal() +{ + SST_Vec4f x; /* 4 vector */ +/* Resetting test vectors */ + x.v[0] = 14.000000f; + x.v[1] = -4.000000f; + x.v[2] = 4.000000f; + x.v[3] = 5.000000f; +/* +[ 14. -4. 4. 5.] +[-14. 4. -4. -5.] +*/ + SST_Math_Vec4fNegateLocal(&x); /* for accuracy */ + TASSERT(fabsf((x.v[0])-(-14.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabsf((x.v[1])-(4.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _y failed!"); + TASSERT(fabsf((x.v[2])-(-4.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _z failed!"); + TASSERT(fabsf((x.v[3])-(-5.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _w failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec4fSqrt() +{ + SST_Vec4f x; /* 4 vector */ + SST_Vec4f w; /* 4 vector */ +/* Resetting test vectors */ + x.v[0] = 6.000000f; + x.v[1] = 6.000000f; + x.v[2] = 38.000000f; + x.v[3] = 22.000000f; + w.v[0] = 0.000000f; + w.v[1] = 0.000000f; + w.v[2] = 0.000000f; + w.v[3] = 0.000000f; +/* +[ 6. 6. 38. 22.] +[ 2.44948983 2.44948983 6.16441393 4.69041586] +*/ + SST_Math_Vec4fSqrt(&x,&w); + TASSERT(fabsf((w.v[0])-(2.449490f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabsf((w.v[1])-(2.449490f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _y failed!"); + TASSERT(fabsf((w.v[2])-(6.164414f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _z failed!"); + TASSERT(fabsf((w.v[3])-(4.690416f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _w failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec4fSqrtLocal() +{ + SST_Vec4f x; /* 4 vector */ +/* Resetting test vectors */ + x.v[0] = 17.000000f; + x.v[1] = 39.000000f; + x.v[2] = 17.000000f; + x.v[3] = 8.000000f; +/* +[ 17. 39. 17. 8.] +[ 4.12310553 6.24499798 4.12310553 2.82842708] +*/ + SST_Math_Vec4fSqrtLocal(&x); /* for accuracy */ + TASSERT(fabsf((x.v[0])-(4.123106f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabsf((x.v[1])-(6.244998f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _y failed!"); + TASSERT(fabsf((x.v[2])-(4.123106f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _z failed!"); + TASSERT(fabsf((x.v[3])-(2.828427f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _w failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec4fRecipSqrt() +{ + SST_Vec4f x; /* 4 vector */ + SST_Vec4f w; /* 4 vector */ +/* Resetting test vectors */ + x.v[0] = 16.000000f; + x.v[1] = 31.000000f; + x.v[2] = 37.000000f; + x.v[3] = 23.000000f; + w.v[0] = 0.000000f; + w.v[1] = 0.000000f; + w.v[2] = 0.000000f; + w.v[3] = 0.000000f; +/* +[ 16. 31. 37. 23.] +[ 0.25 0.17960531 0.16439898 0.20851441] +*/ + SST_Math_Vec4fRecipSqrt(&x,&w); + TASSERT(fabsf((w.v[0])-(0.250000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabsf((w.v[1])-(0.179605f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _y failed!"); + TASSERT(fabsf((w.v[2])-(0.164399f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _z failed!"); + TASSERT(fabsf((w.v[3])-(0.208514f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _w failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec4fRecipSqrtLocal() +{ + SST_Vec4f x; /* 4 vector */ +/* Resetting test vectors */ + x.v[0] = 28.000000f; + x.v[1] = 38.000000f; + x.v[2] = 14.000000f; + x.v[3] = 9.000000f; +/* +[ 28. 38. 14. 9.] +[ 0.18898225 0.16222142 0.26726124 0.33333334] +*/ + SST_Math_Vec4fRecipSqrtLocal(&x); /* for accuracy */ + TASSERT(fabsf((x.v[0])-(0.188982f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabsf((x.v[1])-(0.162221f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _y failed!"); + TASSERT(fabsf((x.v[2])-(0.267261f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _z failed!"); + TASSERT(fabsf((x.v[3])-(0.333333f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _w failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec4fRecip() +{ + SST_Vec4f x; /* 4 vector */ + SST_Vec4f w; /* 4 vector */ +/* Resetting test vectors */ + x.v[0] = 36.000000f; + x.v[1] = 15.000000f; + x.v[2] = 31.000000f; + x.v[3] = 3.000000f; + w.v[0] = 0.000000f; + w.v[1] = 0.000000f; + w.v[2] = 0.000000f; + w.v[3] = 0.000000f; +/* +[ 36. 15. 31. 3.] +[ 0.02777778 0.06666667 0.03225806 0.33333334] +*/ + SST_Math_Vec4fRecip(&x,&w); + TASSERT(fabsf((w.v[0])-(0.027778f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabsf((w.v[1])-(0.066667f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _y failed!"); + TASSERT(fabsf((w.v[2])-(0.032258f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _z failed!"); + TASSERT(fabsf((w.v[3])-(0.333333f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _w failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec4fRecipLocal() +{ + SST_Vec4f x; /* 4 vector */ +/* Resetting test vectors */ + x.v[0] = 4.000000f; + x.v[1] = 11.000000f; + x.v[2] = 3.000000f; + x.v[3] = 39.000000f; +/* +[ 4. 11. 3. 39.] +[ 0.5 0.30151135 0.57735026 0.16012816] +*/ + SST_Math_Vec4fRecipLocal(&x); /* for accuracy */ + TASSERT(fabsf((x.v[0])-(0.250000f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabsf((x.v[1])-(0.090909f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _y failed!"); + TASSERT(fabsf((x.v[2])-(0.333333f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _z failed!"); + TASSERT(fabsf((x.v[3])-(0.025641f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _w failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec4fNormalize() +{ + SST_Vec4f x; /* 4 vector */ + SST_Vec4f w; /* 4 vector */ +/* Resetting test vectors */ + x.v[0] = 1.000000f; + x.v[1] = 11.000000f; + x.v[2] = 11.000000f; + x.v[3] = -12.000000f; + w.v[0] = 0.000000f; + w.v[1] = 0.000000f; + w.v[2] = 0.000000f; + w.v[3] = 0.000000f; +/* +[ 1. 11. 11. -12.] +[ 0.05083286 0.55916142 0.55916142 -0.60999429] +*/ + SST_Math_Vec4fNormalize(&x,&w); + TASSERT(fabsf((w.v[0])-(0.050833f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabsf((w.v[1])-(0.559161f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _y failed!"); + TASSERT(fabsf((w.v[2])-(0.559161f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _z failed!"); + TASSERT(fabsf((w.v[3])-(-0.609994f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _w failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec4fNormalizeLocal() +{ + SST_Vec4f x; /* 4 vector */ +/* Resetting test vectors */ + x.v[0] = -4.000000f; + x.v[1] = -14.000000f; + x.v[2] = -6.000000f; + x.v[3] = 2.000000f; +/* +[ -4. -14. -6. 2.] +[-0.25197631 -0.88191712 -0.37796447 0.12598816] +*/ + SST_Math_Vec4fNormalizeLocal(&x); /* for accuracy */ + TASSERT(fabsf((x.v[0])-(-0.251976f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabsf((x.v[1])-(-0.881917f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _y failed!"); + TASSERT(fabsf((x.v[2])-(-0.377964f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _z failed!"); + TASSERT(fabsf((x.v[3])-(0.125988f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _w failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec4fProject() +{ + SST_Vec4f x; /* 4 vector */ + SST_Vec4f y; /* 4 vector */ + SST_Vec4f w; /* 4 vector */ +/* Resetting test vectors */ + x.v[0] = -2.000000f; + x.v[1] = 8.000000f; + x.v[2] = -8.000000f; + x.v[3] = 5.000000f; + y.v[0] = 3.000000f; + y.v[1] = -4.000000f; + y.v[2] = 17.000000f; + y.v[3] = 2.000000f; + w.v[0] = 0.000000f; + w.v[1] = 0.000000f; + w.v[2] = 0.000000f; + w.v[3] = 0.000000f; +/* +[-2. 8. -8. 5.] +[ 3. -4. 17. 2.] +[-1.54716992 2.06289315 -8.76729584 -1.03144658] +*/ + SST_Math_Vec4fProject(&x,&y,&w); + TASSERT(fabsf((w.v[0])-(-1.547170f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabsf((w.v[1])-(2.062893f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _y failed!"); + TASSERT(fabsf((w.v[2])-(-8.767296f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _z failed!"); + TASSERT(fabsf((w.v[3])-(-1.031447f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _w failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec4fProjectLocal() +{ + SST_Vec4f x; /* 4 vector */ + SST_Vec4f y; /* 4 vector */ +/* Resetting test vectors */ + x.v[0] = -11.000000f; + x.v[1] = 4.000000f; + x.v[2] = -7.000000f; + x.v[3] = -1.000000f; + y.v[0] = -20.000000f; + y.v[1] = -5.000000f; + y.v[2] = 14.000000f; + y.v[3] = -18.000000f; +/* +[-11. 4. -7. -1.] +[-20. -5. 14. -18.] +[-2.53968263 -0.63492066 1.77777791 -2.28571439] +*/ + SST_Math_Vec4fProjectLocal(&x,&y); /* for accuracy */ + TASSERT(fabsf((x.v[0])-(-2.539683f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _x failed!"); + TASSERT(fabsf((x.v[1])-(-0.634921f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _y failed!"); + TASSERT(fabsf((x.v[2])-(1.777778f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _z failed!"); + TASSERT(fabsf((x.v[3])-(-2.285714f)) <=100*FLT_EPSILON /* yes this is bad */,"Entry _w failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + + +/******************************************************************************/ + +static const char* testSST_Math_Vec4fMagnitude() +{ + SST_Vec4f x; /* 4 vector */ + float a; /* scalar */ +/* Resetting test vectors */ + x.v[0] = 17.000000f; + x.v[1] = -10.000000f; + x.v[2] = 8.000000f; + x.v[3] = 0.000000f; +/* +[ 17. -10. 8. 0.] +21.2838 +*/ + a = SST_Math_Vec4fMagnitude(&x); + TASSERT(fabsf((a)-(21.283796f)) <=100*FLT_EPSILON /* yes this is bad */,"Magnitude failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec4fMagnitudeSquared() +{ + SST_Vec4f x; /* 4 vector */ + float a; /* scalar */ +/* Resetting test vectors */ + x.v[0] = 5.000000f; + x.v[1] = 1.000000f; + x.v[2] = 8.000000f; + x.v[3] = 13.000000f; +/* +[ 5. 1. 8. 13.] +259.0 +*/ + a = SST_Math_Vec4fMagnitudeSquared(&x); + TASSERT(fabsf((a)-(259.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"MagnitudeSquared failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec4fDot() +{ + SST_Vec4f x; /* 4 vector */ + SST_Vec4f y; /* 4 vector */ + float a; /* scalar */ +/* Resetting test vectors */ + x.v[0] = 9.000000f; + x.v[1] = -9.000000f; + x.v[2] = -3.000000f; + x.v[3] = -12.000000f; + y.v[0] = 9.000000f; + y.v[1] = 5.000000f; + y.v[2] = -3.000000f; + y.v[3] = -19.000000f; +/* +[ 9. -9. -3. -12.] +273.0 +*/ + a = SST_Math_Vec4fDot(&x,&y); + TASSERT(fabsf((a)-(273.000000f)) <=100*FLT_EPSILON /* yes this is bad */,"Dot failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + diff --git a/ZTestSuite/Test-SST_Vec4i.cpp b/ZTestSuite/Test-SST_Vec4i.cpp new file mode 100644 index 0000000..963cce2 --- /dev/null +++ b/ZTestSuite/Test-SST_Vec4i.cpp @@ -0,0 +1,553 @@ +/* + AUTOMATICALLY GENERATED FILE - DO NOT EDIT! + Please change MatrixNxN.py and re-run it +*/ +/* Generated with ./VectorN.py n = 4, TYPE = int */ + +#include "ZUnitTest.hpp" +#include <float.h> +#include <math.h> +#include <stdlib.h> +#include <stdio.h> +#include <SST/SST_Vec4.h> + + + + +static const char* testSST_Math_Vec4iAdd(); +static const char* testSST_Math_Vec4iAddLocal(); +static const char* testSST_Math_Vec4iSubtract(); +static const char* testSST_Math_Vec4iSubtractLocal(); +static const char* testSST_Math_Vec4iMultiply(); +static const char* testSST_Math_Vec4iMultiplyLocal(); +static const char* testSST_Math_Vec4iScale(); +static const char* testSST_Math_Vec4iScaleLocal(); +static const char* testSST_Math_Vec4iDivide(); +static const char* testSST_Math_Vec4iDivideLocal(); +static const char* testSST_Math_Vec4iAbs(); +static const char* testSST_Math_Vec4iAbsLocal(); +static const char* testSST_Math_Vec4iNegate(); +static const char* testSST_Math_Vec4iNegateLocal(); +static const char* testSST_Math_Vec4iBias(); +static const char* testSST_Math_Vec4iBiasLocal(); +static const char* testSST_Math_Vec4iMagnitudeSquared(); +static const char* testSST_Math_Vec4iDot(); +// List of unit tests +ZUnitTest SST_Math_Vec4iUnitTests[] = +{ +{ "testSST_Math_Vec4iAdd " , testSST_Math_Vec4iAdd }, +{ "testSST_Math_Vec4iAddLocal " , testSST_Math_Vec4iAddLocal }, +{ "testSST_Math_Vec4iSubtract " , testSST_Math_Vec4iSubtract }, +{ "testSST_Math_Vec4iSubtractLocal " , testSST_Math_Vec4iSubtractLocal }, +{ "testSST_Math_Vec4iMultiply " , testSST_Math_Vec4iMultiply }, +{ "testSST_Math_Vec4iMultiplyLocal " , testSST_Math_Vec4iMultiplyLocal }, +{ "testSST_Math_Vec4iScale " , testSST_Math_Vec4iScale }, +{ "testSST_Math_Vec4iScaleLocal " , testSST_Math_Vec4iScaleLocal }, +{ "testSST_Math_Vec4iDivide " , testSST_Math_Vec4iDivide }, +{ "testSST_Math_Vec4iDivideLocal " , testSST_Math_Vec4iDivideLocal }, +{ "testSST_Math_Vec4iAbs " , testSST_Math_Vec4iAbs }, +{ "testSST_Math_Vec4iAbsLocal " , testSST_Math_Vec4iAbsLocal }, +{ "testSST_Math_Vec4iNegate " , testSST_Math_Vec4iNegate }, +{ "testSST_Math_Vec4iNegateLocal " , testSST_Math_Vec4iNegateLocal }, +{ "testSST_Math_Vec4iBias " , testSST_Math_Vec4iBias }, +{ "testSST_Math_Vec4iBiasLocal " , testSST_Math_Vec4iBiasLocal }, +{ "testSST_Math_Vec4iMagnitudeSquared " , testSST_Math_Vec4iMagnitudeSquared }, +{ "testSST_Math_Vec4iDot " , testSST_Math_Vec4iDot } +}; +DECLARE_ZTESTBLOCK(SST_Math_Vec4i) + +/******************************************************************************/ + +static const char* testSST_Math_Vec4iAdd() +{ + SST_Vec4i x; /* 4 vector */ + SST_Vec4i y; /* 4 vector */ + SST_Vec4i w; /* 4 vector */ +/* Resetting test vectors */ + x.v[0] = -18; + x.v[1] = -17; + x.v[2] = 14; + x.v[3] = -11; + y.v[0] = 11; + y.v[1] = -16; + y.v[2] = -12; + y.v[3] = 12; + w.v[0] = 0; + w.v[1] = 0; + w.v[2] = 0; + w.v[3] = 0; +/* +[-18 -17 14 -11] +[ 11 -16 -12 12] +[ -7 -33 2 1] +*/ + SST_Math_Vec4iAdd(&x,&y,&w); + TASSERT((w.v[0])==(-7),"Entry _x failed!"); + TASSERT((w.v[1])==(-33),"Entry _y failed!"); + TASSERT((w.v[2])==(2),"Entry _z failed!"); + TASSERT((w.v[3])==(1),"Entry _w failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec4iAddLocal() +{ + SST_Vec4i x; /* 4 vector */ + SST_Vec4i y; /* 4 vector */ +/* Resetting test vectors */ + x.v[0] = 19; + x.v[1] = -9; + x.v[2] = -4; + x.v[3] = -20; + y.v[0] = -5; + y.v[1] = 19; + y.v[2] = -8; + y.v[3] = 12; +/* +[ 19 -9 -4 -20] +[-5 19 -8 12] +[ 14 10 -12 -8] +*/ + SST_Math_Vec4iAddLocal(&x,&y); /* for accuracy */ + TASSERT((x.v[0])==(14),"Entry _x failed!"); + TASSERT((x.v[1])==(10),"Entry _y failed!"); + TASSERT((x.v[2])==(-12),"Entry _z failed!"); + TASSERT((x.v[3])==(-8),"Entry _w failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec4iSubtract() +{ + SST_Vec4i x; /* 4 vector */ + SST_Vec4i y; /* 4 vector */ + SST_Vec4i w; /* 4 vector */ +/* Resetting test vectors */ + x.v[0] = -15; + x.v[1] = -11; + x.v[2] = 0; + x.v[3] = -10; + y.v[0] = -19; + y.v[1] = -9; + y.v[2] = -11; + y.v[3] = 7; + w.v[0] = 0; + w.v[1] = 0; + w.v[2] = 0; + w.v[3] = 0; +/* +[-15 -11 0 -10] +[-19 -9 -11 7] +[ 4 -2 11 -17] +*/ + SST_Math_Vec4iSubtract(&x,&y,&w); + TASSERT((w.v[0])==(4),"Entry _x failed!"); + TASSERT((w.v[1])==(-2),"Entry _y failed!"); + TASSERT((w.v[2])==(11),"Entry _z failed!"); + TASSERT((w.v[3])==(-17),"Entry _w failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec4iSubtractLocal() +{ + SST_Vec4i x; /* 4 vector */ + SST_Vec4i y; /* 4 vector */ +/* Resetting test vectors */ + x.v[0] = 3; + x.v[1] = 8; + x.v[2] = 17; + x.v[3] = 1; + y.v[0] = 11; + y.v[1] = 6; + y.v[2] = -2; + y.v[3] = 19; +/* +[ 3 8 17 1] +[11 6 -2 19] +[ -8 2 19 -18] +*/ + SST_Math_Vec4iSubtractLocal(&x,&y); /* for accuracy */ + TASSERT((x.v[0])==(-8),"Entry _x failed!"); + TASSERT((x.v[1])==(2),"Entry _y failed!"); + TASSERT((x.v[2])==(19),"Entry _z failed!"); + TASSERT((x.v[3])==(-18),"Entry _w failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec4iMultiply() +{ + SST_Vec4i x; /* 4 vector */ + SST_Vec4i y; /* 4 vector */ + SST_Vec4i w; /* 4 vector */ +/* Resetting test vectors */ + x.v[0] = 0; + x.v[1] = 9; + x.v[2] = -18; + x.v[3] = 9; + y.v[0] = -17; + y.v[1] = 0; + y.v[2] = 8; + y.v[3] = -12; + w.v[0] = 0; + w.v[1] = 0; + w.v[2] = 0; + w.v[3] = 0; +/* +[ 0 9 -18 9] +[-17 0 8 -12] +[ 0 0 -144 -108] +*/ + SST_Math_Vec4iMultiply(&x,&y,&w); + TASSERT((w.v[0])==(0),"Entry _x failed!"); + TASSERT((w.v[1])==(0),"Entry _y failed!"); + TASSERT((w.v[2])==(-144),"Entry _z failed!"); + TASSERT((w.v[3])==(-108),"Entry _w failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec4iMultiplyLocal() +{ + SST_Vec4i x; /* 4 vector */ + SST_Vec4i y; /* 4 vector */ +/* Resetting test vectors */ + x.v[0] = -9; + x.v[1] = 10; + x.v[2] = -6; + x.v[3] = -2; + y.v[0] = 10; + y.v[1] = 11; + y.v[2] = -19; + y.v[3] = 12; +/* +[-9 10 -6 -2] +[ 10 11 -19 12] +[-90 110 114 -24] +*/ + SST_Math_Vec4iMultiplyLocal(&x,&y); /* for accuracy */ + TASSERT((x.v[0])==(-90),"Entry _x failed!"); + TASSERT((x.v[1])==(110),"Entry _y failed!"); + TASSERT((x.v[2])==(114),"Entry _z failed!"); + TASSERT((x.v[3])==(-24),"Entry _w failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec4iDivide() +{ + SST_Vec4i x; /* 4 vector */ + SST_Vec4i y; /* 4 vector */ + SST_Vec4i w; /* 4 vector */ +/* Resetting test vectors */ + x.v[0] = 28; + x.v[1] = 34; + x.v[2] = 37; + x.v[3] = 21; + y.v[0] = 39; + y.v[1] = 16; + y.v[2] = 22; + y.v[3] = 26; + w.v[0] = 0; + w.v[1] = 0; + w.v[2] = 0; + w.v[3] = 0; +/* +[28 34 37 21] +[39 16 22 26] +[0 2 1 0] +*/ + SST_Math_Vec4iDivide(&x,&y,&w); + TASSERT((w.v[0])==(0),"Entry _x failed!"); + TASSERT((w.v[1])==(2),"Entry _y failed!"); + TASSERT((w.v[2])==(1),"Entry _z failed!"); + TASSERT((w.v[3])==(0),"Entry _w failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec4iDivideLocal() +{ + SST_Vec4i x; /* 4 vector */ + SST_Vec4i y; /* 4 vector */ +/* Resetting test vectors */ + x.v[0] = 12; + x.v[1] = 36; + x.v[2] = 30; + x.v[3] = 7; + y.v[0] = 38; + y.v[1] = 16; + y.v[2] = 28; + y.v[3] = 3; +/* +[12 36 30 7] +[38 16 28 3] +[0 2 1 2] +*/ + SST_Math_Vec4iDivideLocal(&x,&y); /* for accuracy */ + TASSERT((x.v[0])==(0),"Entry _x failed!"); + TASSERT((x.v[1])==(2),"Entry _y failed!"); + TASSERT((x.v[2])==(1),"Entry _z failed!"); + TASSERT((x.v[3])==(2),"Entry _w failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec4iScale() +{ + SST_Vec4i x; /* 4 vector */ + SST_Vec4i w; /* 4 vector */ + int a; /* scalar */ +/* Resetting test vectors */ + x.v[0] = -2; + x.v[1] = -16; + x.v[2] = 6; + x.v[3] = 19; + w.v[0] = 0; + w.v[1] = 0; + w.v[2] = 0; + w.v[3] = 0; + a = 2; +/* +[ -2 -16 6 19] +[ -4 -32 12 38] +*/ + SST_Math_Vec4iScale(&x,a,&w); + TASSERT((w.v[0])==(-4),"Entry _x failed!"); + TASSERT((w.v[1])==(-32),"Entry _y failed!"); + TASSERT((w.v[2])==(12),"Entry _z failed!"); + TASSERT((w.v[3])==(38),"Entry _w failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec4iScaleLocal() +{ + SST_Vec4i x; /* 4 vector */ + int a; /* scalar */ +/* Resetting test vectors */ + x.v[0] = -1; + x.v[1] = 16; + x.v[2] = -20; + x.v[3] = -6; + a = 2; +/* +[ -1 16 -20 -6] +[ -2 32 -40 -12] +*/ + SST_Math_Vec4iScaleLocal(&x,a); /* for accuracy */ + TASSERT((x.v[0])==(-2),"Entry _x failed!"); + TASSERT((x.v[1])==(32),"Entry _y failed!"); + TASSERT((x.v[2])==(-40),"Entry _z failed!"); + TASSERT((x.v[3])==(-12),"Entry _w failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec4iAbs() +{ + SST_Vec4i x; /* 4 vector */ + SST_Vec4i w; /* 4 vector */ +/* Resetting test vectors */ + x.v[0] = -5; + x.v[1] = 7; + x.v[2] = -2; + x.v[3] = -6; + w.v[0] = 0; + w.v[1] = 0; + w.v[2] = 0; + w.v[3] = 0; +/* +[-5 7 -2 -6] +[5 7 2 6] +*/ + SST_Math_Vec4iAbs(&x,&w); + TASSERT((w.v[0])==(5),"Entry _x failed!"); + TASSERT((w.v[1])==(7),"Entry _y failed!"); + TASSERT((w.v[2])==(2),"Entry _z failed!"); + TASSERT((w.v[3])==(6),"Entry _w failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec4iAbsLocal() +{ + SST_Vec4i x; /* 4 vector */ +/* Resetting test vectors */ + x.v[0] = 6; + x.v[1] = 2; + x.v[2] = -20; + x.v[3] = -8; +/* +[ 6 2 -20 -8] +[ 6 2 20 8] +*/ + SST_Math_Vec4iAbsLocal(&x); /* for accuracy */ + TASSERT((x.v[0])==(6),"Entry _x failed!"); + TASSERT((x.v[1])==(2),"Entry _y failed!"); + TASSERT((x.v[2])==(20),"Entry _z failed!"); + TASSERT((x.v[3])==(8),"Entry _w failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec4iBias() +{ + SST_Vec4i x; /* 4 vector */ + SST_Vec4i w; /* 4 vector */ + int a; /* scalar */ +/* Resetting test vectors */ + x.v[0] = -15; + x.v[1] = 10; + x.v[2] = 0; + x.v[3] = 5; + w.v[0] = 0; + w.v[1] = 0; + w.v[2] = 0; + w.v[3] = 0; + a = -12; +/* +[-15 10 0 5] +[-30 20 0 10] +*/ + SST_Math_Vec4iBias(&x,a,&w); + TASSERT((w.v[0])==(-27),"Entry _x failed!"); + TASSERT((w.v[1])==(-2),"Entry _y failed!"); + TASSERT((w.v[2])==(-12),"Entry _z failed!"); + TASSERT((w.v[3])==(-7),"Entry _w failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec4iBiasLocal() +{ + SST_Vec4i x; /* 4 vector */ + int a; /* scalar */ +/* Resetting test vectors */ + x.v[0] = 14; + x.v[1] = 17; + x.v[2] = -5; + x.v[3] = -2; + a = 17; +/* +[14 17 -5 -2] +[ 28 34 -10 -4] +*/ + SST_Math_Vec4iBiasLocal(&x,a); /* for accuracy */ + TASSERT((x.v[0])==(31),"Entry _x failed!"); + TASSERT((x.v[1])==(34),"Entry _y failed!"); + TASSERT((x.v[2])==(12),"Entry _z failed!"); + TASSERT((x.v[3])==(15),"Entry _w failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec4iNegate() +{ + SST_Vec4i x; /* 4 vector */ + SST_Vec4i w; /* 4 vector */ +/* Resetting test vectors */ + x.v[0] = -7; + x.v[1] = 5; + x.v[2] = 12; + x.v[3] = -15; + w.v[0] = 0; + w.v[1] = 0; + w.v[2] = 0; + w.v[3] = 0; +/* +[ -7 5 12 -15] +[ 7 -5 -12 15] +*/ + SST_Math_Vec4iNegate(&x,&w); + TASSERT((w.v[0])==(7),"Entry _x failed!"); + TASSERT((w.v[1])==(-5),"Entry _y failed!"); + TASSERT((w.v[2])==(-12),"Entry _z failed!"); + TASSERT((w.v[3])==(15),"Entry _w failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec4iNegateLocal() +{ + SST_Vec4i x; /* 4 vector */ +/* Resetting test vectors */ + x.v[0] = 3; + x.v[1] = -8; + x.v[2] = -7; + x.v[3] = 14; +/* +[ 3 -8 -7 14] +[ -3 8 7 -14] +*/ + SST_Math_Vec4iNegateLocal(&x); /* for accuracy */ + TASSERT((x.v[0])==(-3),"Entry _x failed!"); + TASSERT((x.v[1])==(8),"Entry _y failed!"); + TASSERT((x.v[2])==(7),"Entry _z failed!"); + TASSERT((x.v[3])==(-14),"Entry _w failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec4iMagnitudeSquared() +{ + SST_Vec4i x; /* 4 vector */ + int a; /* scalar */ +/* Resetting test vectors */ + x.v[0] = 12; + x.v[1] = 12; + x.v[2] = -15; + x.v[3] = 11; +/* +[ 12 12 -15 11] +634 +*/ + a = SST_Math_Vec4iMagnitudeSquared(&x); + TASSERT((a)==(634),"MagnitudeSquared failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec4iDot() +{ + SST_Vec4i x; /* 4 vector */ + SST_Vec4i y; /* 4 vector */ + int a; /* scalar */ +/* Resetting test vectors */ + x.v[0] = 1; + x.v[1] = 1; + x.v[2] = 1; + x.v[3] = 8; + y.v[0] = 7; + y.v[1] = 12; + y.v[2] = -18; + y.v[3] = -11; +/* +[1 1 1 8] +-87 +*/ + a = SST_Math_Vec4iDot(&x,&y); + TASSERT((a)==(-87),"Dot failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + diff --git a/ZTestSuite/Test-SST_Vec4u.cpp b/ZTestSuite/Test-SST_Vec4u.cpp new file mode 100644 index 0000000..cc7cbe9 --- /dev/null +++ b/ZTestSuite/Test-SST_Vec4u.cpp @@ -0,0 +1,390 @@ +/* + AUTOMATICALLY GENERATED FILE - DO NOT EDIT! + Please change MatrixNxN.py and re-run it +*/ +/* Generated with ./VectorN.py n = 4, TYPE = unsigned int */ + +#include "ZUnitTest.hpp" +#include <float.h> +#include <math.h> +#include <stdlib.h> +#include <stdio.h> +#include <SST/SST_Vec4.h> + + + + +static const char* testSST_Math_Vec4uAdd(); +static const char* testSST_Math_Vec4uAddLocal(); +static const char* testSST_Math_Vec4uSubtract(); +static const char* testSST_Math_Vec4uSubtractLocal(); +static const char* testSST_Math_Vec4uMultiply(); +static const char* testSST_Math_Vec4uMultiplyLocal(); +static const char* testSST_Math_Vec4uScale(); +static const char* testSST_Math_Vec4uScaleLocal(); +static const char* testSST_Math_Vec4uDivide(); +static const char* testSST_Math_Vec4uDivideLocal(); +static const char* testSST_Math_Vec4uMagnitudeSquared(); +static const char* testSST_Math_Vec4uDot(); +// List of unit tests +ZUnitTest SST_Math_Vec4uUnitTests[] = +{ +{ "testSST_Math_Vec4uAdd " , testSST_Math_Vec4uAdd }, +{ "testSST_Math_Vec4uAddLocal " , testSST_Math_Vec4uAddLocal }, +{ "testSST_Math_Vec4uSubtract " , testSST_Math_Vec4uSubtract }, +{ "testSST_Math_Vec4uSubtractLocal " , testSST_Math_Vec4uSubtractLocal }, +{ "testSST_Math_Vec4uMultiply " , testSST_Math_Vec4uMultiply }, +{ "testSST_Math_Vec4uMultiplyLocal " , testSST_Math_Vec4uMultiplyLocal }, +{ "testSST_Math_Vec4uScale " , testSST_Math_Vec4uScale }, +{ "testSST_Math_Vec4uScaleLocal " , testSST_Math_Vec4uScaleLocal }, +{ "testSST_Math_Vec4uDivide " , testSST_Math_Vec4uDivide }, +{ "testSST_Math_Vec4uDivideLocal " , testSST_Math_Vec4uDivideLocal }, +{ "testSST_Math_Vec4uMagnitudeSquared " , testSST_Math_Vec4uMagnitudeSquared }, +{ "testSST_Math_Vec4uDot " , testSST_Math_Vec4uDot } +}; +DECLARE_ZTESTBLOCK(SST_Math_Vec4u) + +/******************************************************************************/ + +static const char* testSST_Math_Vec4uAdd() +{ + SST_Vec4u x; /* 4 vector */ + SST_Vec4u y; /* 4 vector */ + SST_Vec4u w; /* 4 vector */ +/* Resetting test vectors */ + x.v[0] = 15; + x.v[1] = 34; + x.v[2] = 18; + x.v[3] = 33; + y.v[0] = 31; + y.v[1] = 5; + y.v[2] = 22; + y.v[3] = 22; + w.v[0] = 0; + w.v[1] = 0; + w.v[2] = 0; + w.v[3] = 0; +/* +[15 34 18 33] +[31 5 22 22] +[46 39 40 55] +*/ + SST_Math_Vec4uAdd(&x,&y,&w); + TASSERT((w.v[0])==(46),"Entry _x failed!"); + TASSERT((w.v[1])==(39),"Entry _y failed!"); + TASSERT((w.v[2])==(40),"Entry _z failed!"); + TASSERT((w.v[3])==(55),"Entry _w failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec4uAddLocal() +{ + SST_Vec4u x; /* 4 vector */ + SST_Vec4u y; /* 4 vector */ +/* Resetting test vectors */ + x.v[0] = 23; + x.v[1] = 7; + x.v[2] = 20; + x.v[3] = 39; + y.v[0] = 29; + y.v[1] = 24; + y.v[2] = 33; + y.v[3] = 20; +/* +[23 7 20 39] +[29 24 33 20] +[52 31 53 59] +*/ + SST_Math_Vec4uAddLocal(&x,&y); /* for accuracy */ + TASSERT((x.v[0])==(52),"Entry _x failed!"); + TASSERT((x.v[1])==(31),"Entry _y failed!"); + TASSERT((x.v[2])==(53),"Entry _z failed!"); + TASSERT((x.v[3])==(59),"Entry _w failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec4uSubtract() +{ + SST_Vec4u x; /* 4 vector */ + SST_Vec4u y; /* 4 vector */ + SST_Vec4u w; /* 4 vector */ +/* Resetting test vectors */ + x.v[0] = 28; + x.v[1] = 35; + x.v[2] = 2; + x.v[3] = 0; + y.v[0] = 25; + y.v[1] = 4; + y.v[2] = 2; + y.v[3] = 30; + w.v[0] = 0; + w.v[1] = 0; + w.v[2] = 0; + w.v[3] = 0; +/* +[28 35 2 0] +[25 4 2 30] +[ 3 31 0 4294967266] +*/ + SST_Math_Vec4uSubtract(&x,&y,&w); + TASSERT((w.v[0])==(3),"Entry _x failed!"); + TASSERT((w.v[1])==(31),"Entry _y failed!"); + TASSERT((w.v[2])==(0),"Entry _z failed!"); + TASSERT((w.v[3])==(4294967266),"Entry _w failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec4uSubtractLocal() +{ + SST_Vec4u x; /* 4 vector */ + SST_Vec4u y; /* 4 vector */ +/* Resetting test vectors */ + x.v[0] = 10; + x.v[1] = 6; + x.v[2] = 29; + x.v[3] = 10; + y.v[0] = 27; + y.v[1] = 37; + y.v[2] = 26; + y.v[3] = 27; +/* +[10 6 29 10] +[27 37 26 27] +[4294967279 4294967265 3 4294967279] +*/ + SST_Math_Vec4uSubtractLocal(&x,&y); /* for accuracy */ + TASSERT((x.v[0])==(4294967279),"Entry _x failed!"); + TASSERT((x.v[1])==(4294967265),"Entry _y failed!"); + TASSERT((x.v[2])==(3),"Entry _z failed!"); + TASSERT((x.v[3])==(4294967279),"Entry _w failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec4uMultiply() +{ + SST_Vec4u x; /* 4 vector */ + SST_Vec4u y; /* 4 vector */ + SST_Vec4u w; /* 4 vector */ +/* Resetting test vectors */ + x.v[0] = 23; + x.v[1] = 8; + x.v[2] = 8; + x.v[3] = 1; + y.v[0] = 13; + y.v[1] = 29; + y.v[2] = 2; + y.v[3] = 12; + w.v[0] = 0; + w.v[1] = 0; + w.v[2] = 0; + w.v[3] = 0; +/* +[23 8 8 1] +[13 29 2 12] +[299 232 16 12] +*/ + SST_Math_Vec4uMultiply(&x,&y,&w); + TASSERT((w.v[0])==(299),"Entry _x failed!"); + TASSERT((w.v[1])==(232),"Entry _y failed!"); + TASSERT((w.v[2])==(16),"Entry _z failed!"); + TASSERT((w.v[3])==(12),"Entry _w failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec4uMultiplyLocal() +{ + SST_Vec4u x; /* 4 vector */ + SST_Vec4u y; /* 4 vector */ +/* Resetting test vectors */ + x.v[0] = 6; + x.v[1] = 37; + x.v[2] = 35; + x.v[3] = 22; + y.v[0] = 13; + y.v[1] = 11; + y.v[2] = 12; + y.v[3] = 20; +/* +[ 6 37 35 22] +[13 11 12 20] +[ 78 407 420 440] +*/ + SST_Math_Vec4uMultiplyLocal(&x,&y); /* for accuracy */ + TASSERT((x.v[0])==(78),"Entry _x failed!"); + TASSERT((x.v[1])==(407),"Entry _y failed!"); + TASSERT((x.v[2])==(420),"Entry _z failed!"); + TASSERT((x.v[3])==(440),"Entry _w failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec4uDivide() +{ + SST_Vec4u x; /* 4 vector */ + SST_Vec4u y; /* 4 vector */ + SST_Vec4u w; /* 4 vector */ +/* Resetting test vectors */ + x.v[0] = 10; + x.v[1] = 3; + x.v[2] = 32; + x.v[3] = 2; + y.v[0] = 13; + y.v[1] = 15; + y.v[2] = 14; + y.v[3] = 10; + w.v[0] = 0; + w.v[1] = 0; + w.v[2] = 0; + w.v[3] = 0; +/* +[10 3 32 2] +[13 15 14 10] +[0 0 2 0] +*/ + SST_Math_Vec4uDivide(&x,&y,&w); + TASSERT((w.v[0])==(0),"Entry _x failed!"); + TASSERT((w.v[1])==(0),"Entry _y failed!"); + TASSERT((w.v[2])==(2),"Entry _z failed!"); + TASSERT((w.v[3])==(0),"Entry _w failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec4uDivideLocal() +{ + SST_Vec4u x; /* 4 vector */ + SST_Vec4u y; /* 4 vector */ +/* Resetting test vectors */ + x.v[0] = 7; + x.v[1] = 6; + x.v[2] = 8; + x.v[3] = 5; + y.v[0] = 10; + y.v[1] = 32; + y.v[2] = 32; + y.v[3] = 36; +/* +[7 6 8 5] +[10 32 32 36] +[0 0 0 0] +*/ + SST_Math_Vec4uDivideLocal(&x,&y); /* for accuracy */ + TASSERT((x.v[0])==(0),"Entry _x failed!"); + TASSERT((x.v[1])==(0),"Entry _y failed!"); + TASSERT((x.v[2])==(0),"Entry _z failed!"); + TASSERT((x.v[3])==(0),"Entry _w failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec4uScale() +{ + SST_Vec4u x; /* 4 vector */ + SST_Vec4u w; /* 4 vector */ + unsigned int a; /* scalar */ +/* Resetting test vectors */ + x.v[0] = 23; + x.v[1] = 36; + x.v[2] = 14; + x.v[3] = 6; + w.v[0] = 0; + w.v[1] = 0; + w.v[2] = 0; + w.v[3] = 0; + a = 2; +/* +[23 36 14 6] +[46 72 28 12] +*/ + SST_Math_Vec4uScale(&x,a,&w); + TASSERT((w.v[0])==(46),"Entry _x failed!"); + TASSERT((w.v[1])==(72),"Entry _y failed!"); + TASSERT((w.v[2])==(28),"Entry _z failed!"); + TASSERT((w.v[3])==(12),"Entry _w failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec4uScaleLocal() +{ + SST_Vec4u x; /* 4 vector */ + unsigned int a; /* scalar */ +/* Resetting test vectors */ + x.v[0] = 29; + x.v[1] = 5; + x.v[2] = 28; + x.v[3] = 38; + a = 2; +/* +[29 5 28 38] +[58 10 56 76] +*/ + SST_Math_Vec4uScaleLocal(&x,a); /* for accuracy */ + TASSERT((x.v[0])==(58),"Entry _x failed!"); + TASSERT((x.v[1])==(10),"Entry _y failed!"); + TASSERT((x.v[2])==(56),"Entry _z failed!"); + TASSERT((x.v[3])==(76),"Entry _w failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec4uMagnitudeSquared() +{ + SST_Vec4u x; /* 4 vector */ + unsigned int a; /* scalar */ +/* Resetting test vectors */ + x.v[0] = 38; + x.v[1] = 24; + x.v[2] = 18; + x.v[3] = 38; +/* +[38 24 18 38] +3788 +*/ + a = SST_Math_Vec4uMagnitudeSquared(&x); + TASSERT((a)==(3788),"MagnitudeSquared failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + +static const char* testSST_Math_Vec4uDot() +{ + SST_Vec4u x; /* 4 vector */ + SST_Vec4u y; /* 4 vector */ + unsigned int a; /* scalar */ +/* Resetting test vectors */ + x.v[0] = 29; + x.v[1] = 21; + x.v[2] = 23; + x.v[3] = 13; + y.v[0] = 11; + y.v[1] = 38; + y.v[2] = 30; + y.v[3] = 26; +/* +[29 21 23 13] +2145 +*/ + a = SST_Math_Vec4uDot(&x,&y); + TASSERT((a)==(2145),"Dot failed!"); + return ZTEST_SUCCESS; +} + +/******************************************************************************/ + diff --git a/ZTestSuite/Test-ZAlloc.cpp b/ZTestSuite/Test-ZAlloc.cpp new file mode 100644 index 0000000..87179b5 --- /dev/null +++ b/ZTestSuite/Test-ZAlloc.cpp @@ -0,0 +1,100 @@ +/* + Test-ZAlloc.cpp + Author: James Russell <jcrussell@762studios.com> + + Purpose: Unit Test the TestZAlloc class. + + Changelog: + 12/18/2011 - Removed dependency on ZString (crertel) + 2011/09/18 - creation (jcrussell) +*/ + +#include "ZUnitTest.hpp" + +#include <ZUtil/ZAlloc.hpp> + +static const char* testNew(); +static const char* testAlloc(); + +//List of unit tests +ZUnitTest ZAllocUnitTests[] = +{ + { "Test New", testNew }, + { "Test Alloc", testAlloc } +}; + +//Now declare the ZUnitTestBlock associated with this. +DECLARE_ZTESTBLOCK(ZAlloc); + +/*************************************************************************/ + +struct AllocTestObject +{ + //Constructor + AllocTestObject() { AllocTestObject::Instances++; } + + //Parameterized constructor + AllocTestObject(int _val) { AllocTestObject::Instances++; Value = _val; } + + //Destructor + ~AllocTestObject() { AllocTestObject::Instances--; } + + //Value field + int Value; + + //Static Instance Count + static int Instances; + + //Virtual Function + virtual bool Foo() const { return true; } +}; + +struct AllocTestObjectSubclass : public AllocTestObject +{ + //Constructor + AllocTestObjectSubclass() : AllocTestObject() {} + + //Subclass Override + bool Foo() const { return false; } + + //Subclass Method + bool Bar() const { return true; } +}; + +//Defaults to zero +int AllocTestObject::Instances = 0; + +static const char* testNew() +{ + AllocTestObject *testObj1 = znew AllocTestObject(); + + TASSERT(AllocTestObject::Instances == 1, "Failed to call constructor with ZNew!"); + + AllocTestObject *testObj2 = znew AllocTestObject(5); + + TASSERT(AllocTestObject::Instances == 2, "Failed to call constructor with ZNew!"); + TASSERT(testObj2->Value == 5, "Failed to call correct constructor with ZNew!"); + + zdelete testObj1; + + TASSERT(AllocTestObject::Instances == 1, "Failed to deallocate with ZDel!"); + + zdelete testObj2; + + TASSERT(AllocTestObject::Instances == 0, "Failed to deallocate with ZDel!"); + + return ZTEST_SUCCESS; +} + +static const char* testAlloc() +{ + AllocTestObject *testArray = zalloc(AllocTestObject, 12); + + TASSERT(AllocTestObject::Instances == 12, "Failed to call all constructors with ZAlloc!"); + + zfree(testArray); + + TASSERT(AllocTestObject::Instances == 0, "Failed to call all destructors with ZFree!"); + + return ZTEST_SUCCESS; +} diff --git a/ZTestSuite/Test-ZAllocWindow.cpp b/ZTestSuite/Test-ZAllocWindow.cpp new file mode 100644 index 0000000..5ac6e97 --- /dev/null +++ b/ZTestSuite/Test-ZAllocWindow.cpp @@ -0,0 +1,120 @@ +/* + Test-ZAllocWindow.cpp + Author: James Russell <jcrussell@762studios.com> + + Purpose: Unit Test the ZAllocWindow class. +*/ + +#include "ZUnitTest.hpp" + +#include <ZUtil/ZAllocWindow.hpp> + +static const char* test_ConstructResizeSetBuffer(); +static const char* test_AllocDealloc(); + +//List of unit tests +ZUnitTest ZAllocWindowUnitTests[] = +{ + { "ZAllocWindow: Construction, Resize, SetBuffer", test_ConstructResizeSetBuffer }, + { "ZAllocWindow: Allocate, Deallocate", test_AllocDealloc }, +}; + +//Now declare the ZUnitTestBlock associated with this. +DECLARE_ZTESTBLOCK(ZAllocWindow); + +/*************************************************************************/ + +namespace ZAllocWindowTestObjects +{ + struct IntStruct { + int data; + + IntStruct() : data(0xFFFFFFFF) { } + ~IntStruct() { data = 0xFEEEFEEE; } + }; +} + +using namespace ZAllocWindowTestObjects; + +/*************************************************************************/ + +static const char* test_ConstructResizeSetBuffer() +{ + ZAllocWindow buf1; + ZAllocWindow buf2(1024); + + TASSERT(buf1.Size() == 0, "Buffer 1 does not return a size of 0!"); + TASSERT(buf2.Size() == 1024, "Buffer 2 does not return a size of 1024!"); + + buf1.Resize(100); + + TASSERT(buf1.Size() == 100, "Buffer 1 does not return a size of 100 after resize!"); + + buf1.Resize<int>(50); + + TASSERT(buf1.Size() >= ((sizeof(int) + 8) * 50), "Template Resize does not size correctly!"); + + char local_buffer[500]; + + buf2.SetBuffer(local_buffer, 500); + + TASSERT(buf2.Size() == 500, "Buffer 2 does not return a size of 500 after resize!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_AllocDealloc() +{ + ZAllocWindow buf1; + ZAllocWindow buf2(1024); + + buf1.Resize<IntStruct>(5); + + IntStruct* alloc1 = buf1.Allocate<IntStruct>(); + IntStruct* alloc2 = buf1.Allocate<IntStruct>(); + IntStruct* alloc3 = buf1.Allocate<IntStruct>(); + IntStruct* alloc4 = buf1.Allocate<IntStruct>(); + IntStruct* alloc5 = buf1.Allocate<IntStruct>(); + IntStruct* alloc6 = buf1.Allocate<IntStruct>(); + + TASSERT(alloc1 != NULL, "Allocation 1 returned NULL!"); + TASSERT(alloc2 != NULL, "Allocation 2 returned NULL!"); + TASSERT(alloc3 != NULL, "Allocation 3 returned NULL!"); + TASSERT(alloc4 != NULL, "Allocation 4 returned NULL!"); + TASSERT(alloc5 != NULL, "Allocation 5 returned NULL!"); + TASSERT(alloc6 == NULL, "Allocation 6 returned valid pointer - should be NULL!"); + + alloc1->data = 0xA; + alloc2->data = 0xB; + alloc3->data = 0xC; + alloc4->data = 0xD; + alloc5->data = 0xE; + + buf1.Deallocate(alloc2); + + alloc6 = buf1.Allocate<IntStruct>(); + + TASSERT(alloc6 == NULL, "Allocation window frees space before earliest dealloc!"); + + buf1.Deallocate(alloc1); + + IntStruct* alloc7; + + alloc6 = buf1.Allocate<IntStruct>(); + alloc7 = buf1.Allocate<IntStruct>(); + + TASSERT(alloc6 != NULL, "Allocation window fails to free space after dealloc!"); + TASSERT(alloc7 != NULL, "Allocation window fails to roll up multiple deallocs!"); + + buf1.Deallocate(alloc3); + buf1.Deallocate(alloc4); + buf1.Deallocate(alloc5); + buf1.Deallocate(alloc6); + buf1.Deallocate(alloc7); + + //TODO - test buf2 + + return ZTEST_SUCCESS; +} diff --git a/ZTestSuite/Test-ZArray.cpp b/ZTestSuite/Test-ZArray.cpp new file mode 100644 index 0000000..189c571 --- /dev/null +++ b/ZTestSuite/Test-ZArray.cpp @@ -0,0 +1,548 @@ +#include "ZUnitTest.hpp" + +#include <ZSTL/ZArray.hpp> + +#include <string.h> //for memcmp + +static const char* test_Constructors_Size_Capacity(); +static const char* test_SliceConstructor(); +static const char* test_At_Data(); +static const char* test_Copy_Equals_Swap(); +static const char* test_Allocator(); +static const char* test_Reserve_Resize_Clear_Empty(); +static const char* test_Push_Pop(); +static const char* test_Insert_Erase(); +static const char* test_Begin_End(); +static const char* test_Find_Iterator(); + +//List of unit tests +ZUnitTest ZArrayUnitTests[] = +{ + { "ZArray: Constructors, Size, Capacity", test_Constructors_Size_Capacity }, + { "ZArray: Slice Constructor", test_SliceConstructor }, + { "ZArray: At, Data", test_At_Data }, + { "ZArray: Copy, Equals, Swap", test_Copy_Equals_Swap }, + { "ZArray: Allocator", test_Allocator }, + { "ZArray: Reserve, Resize, Clear, Empty", test_Reserve_Resize_Clear_Empty }, + { "ZArray: Push, Pop", test_Push_Pop }, + { "ZArray: Insert, Erase", test_Insert_Erase }, + { "ZArray: Begin, End", test_Begin_End }, + { "ZArray: Iterator", test_Find_Iterator } +}; + +DECLARE_ZTESTBLOCK(ZArray); + +/*************************************************************************/ +namespace ZArrayTestObjects +{ + struct TestObject + { + //Constructor + TestObject() { TestObject::Instances++; } + + //Destructor + ~TestObject() { TestObject::Instances--; } + + //Static Instance Count + static size_t Instances; + }; + + //Defaults to zero + size_t TestObject::Instances = 0; + + //We use this allocator to ensure that allocator-agnostic functions work correctly + class IntArrayAllocator + { + public: + int* Allocate(size_t _size) + { + return new (std::nothrow) int[_size]; + } + + void Deallocate(int* _ptr, size_t _size) + { + (void)_size; + delete[] _ptr; + } + }; +} + +static const char* test_Constructors_Size_Capacity() +{ + int testData[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + //First we test our basic constructors with default allocator + ZArray<int> arr1; + ZArray<int> arr2(5); + ZArray<int> arr3(testData, 6, 10); + + TASSERT(arr1.Capacity() == ZARRAY_DEFAULT_CAPACITY, "Capacity() returns wrong value after default constructor!"); + TASSERT(arr1.Size() == 0, "Size() returns wrong value after default constructor!"); + + TASSERT(arr2.Capacity() == 5, "Capacity() returns wrong value after constructing with explicit capacity"); + TASSERT(arr2.Size() == 0, "Size() returns wrong value after constructing with explicit capacity!"); + + TASSERT(arr3.Capacity() == 10, "Capacity() returns wrong value after data constructor!"); + TASSERT(arr3.Size() == 6, "Size() returns wrong value after data constructor!"); + + //Test our copy constructor with typename A == typename B + ZArray<int> arr4(arr3); + + TASSERT(arr3.Capacity() == 10, "arr3 modified after copy constructor! (Capacity)"); + TASSERT(arr3.Size() == 6, "arr3 modified after copy constructor! (Size)"); + + TASSERT(arr4.Capacity() == 10, "Capacity() returns wrong value after copy constructor!"); + TASSERT(arr4.Size() == 6, "Size() returns wrong value after copy constructor!"); + + //Test our basic constructors with provided allocator + ZArray<int, ZArrayTestObjects::IntArrayAllocator> arr5; + ZArray<int, ZArrayTestObjects::IntArrayAllocator> arr6(5); + ZArray<int, ZArrayTestObjects::IntArrayAllocator> arr7(testData, 6, 10); + + TASSERT(arr5.Capacity() == ZARRAY_DEFAULT_CAPACITY, "Capacity() returns wrong value after default constructor! (IntArrayAllocator)"); + TASSERT(arr5.Size() == 0, "Size() returns wrong value after default constructor! (IntArrayAllocator)"); + + TASSERT(arr6.Capacity() == 5, "Capacity() returns wrong value after constructing with explicit capacity! (IntArrayAllocator)"); + TASSERT(arr6.Size() == 0, "Size() returns wrong value after constructing with explicit capacity! (IntArrayAllocator)"); + + TASSERT(arr7.Capacity() == 10, "Capacity() returns wrong value after data constructor! (IntArrayAllocator)"); + TASSERT(arr7.Size() == 6, "Size() returns wrong value after data constructor! (IntArrayAllocator)"); + + //Test our copy constructor with typename A != typename B + ZArray<int> arr8(arr7); + + TASSERT(arr7.Capacity() == 10, "arr7 modified after copy constructor! (Capacity)"); + TASSERT(arr7.Size() == 6, "arr7 modified after copy constructor! (Size)"); + + TASSERT(arr8.Capacity() == 10, "Capacity() returns wrong value after copy constructor! (IntArrayAllocator)"); + TASSERT(arr8.Size() == 6, "Size() returns wrong value after copy constructor! (IntArrayAllocator)"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_SliceConstructor() +{ + ZArray<int> list; + + list.PushBack(1); + list.PushBack(2); + list.PushBack(3); + list.PushBack(4); + list.PushBack(5); + list.PushBack(6); + + ZArray<int> slice(list, 2, 5); + + TASSERT(slice.Size() == 3, "Slice() created slice of incorrect size!"); + TASSERT(slice.PopFront() == 3, "Slice() created incorrect slice!"); + TASSERT(slice.PopFront() == 4, "Slice() created incorrect slice!"); + TASSERT(slice.PopFront() == 5, "Slice() created incorrect slice!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_At_Data() +{ + int testData[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + ZArray<int> arr1; + ZArray<int> arr2(5); + ZArray<int> arr3(testData, 6, 10); + + //Ensure that 'At' returns proper data + TASSERT(arr3.At(0) == testData[0], "arr3[0] != testData[0]"); + TASSERT(arr3.At(1) == testData[1], "arr3[1] != testData[1]"); + TASSERT(arr3.At(2) == testData[2], "arr3[2] != testData[2]"); + TASSERT(arr3.At(3) == testData[3], "arr3[3] != testData[3]"); + TASSERT(arr3.At(4) == testData[4], "arr3[4] != testData[4]"); + TASSERT(arr3.At(5) == testData[5], "arr3[5] != testData[5]"); + + //Ensure that Data() != testData (this would be bad) + TASSERT(arr3.Data() != testData, "Data constructor failed to copy data, instead took ownership of array!"); + + //Ensure that 'At(i)' returns the same as 'Data()[i]' + TASSERT(arr3.At(0) == arr3.Data()[0], "arr3[0] != arr3.Data()[0]"); + TASSERT(arr3.At(1) == arr3.Data()[1], "arr3[1] != arr3.Data()[1]"); + TASSERT(arr3.At(2) == arr3.Data()[2], "arr3[2] != arr3.Data()[2]"); + TASSERT(arr3.At(3) == arr3.Data()[3], "arr3[3] != arr3.Data()[3]"); + TASSERT(arr3.At(4) == arr3.Data()[4], "arr3[4] != arr3.Data()[4]"); + TASSERT(arr3.At(5) == arr3.Data()[5], "arr3[5] != arr3.Data()[5]"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Copy_Equals_Swap() +{ + int testData[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + ZArray<int> arr1; + ZArray<int> arr2(5); + ZArray<int> arr3(testData, 6, 10); + + arr2.Copy(arr3); + + TASSERT(arr3.At(0) == arr2.At(0), "arr3.At(0) != arr2.At(0) after Copy()!"); + TASSERT(arr3.At(1) == arr2.At(1), "arr3.At(1) != arr2.At(1) after Copy()!"); + TASSERT(arr3.At(2) == arr2.At(2), "arr3.At(2) != arr2.At(2) after Copy()!"); + TASSERT(arr3.At(3) == arr2.At(3), "arr3.At(3) != arr2.At(3) after Copy()!"); + TASSERT(arr3.At(4) == arr2.At(4), "arr3.At(4) != arr2.At(4) after Copy()!"); + TASSERT(arr3.At(5) == arr2.At(5), "arr3.At(5) != arr2.At(5) after Copy()!"); + + TASSERT(arr2.Equals(arr3), "arr2.Equals(arr3) returns false after Copy()!") + TASSERT(arr3.Equals(arr2), "arr3.Equals(arr2) returns false after Copy()!") + + arr1.Swap(arr3); + + TASSERT(arr2.Equals(arr1), "arr2.Equals(arr2) returns false after Swap()!"); + TASSERT(!arr3.Equals(arr1), "arr3.Equals(arr1) returns true after Swap()!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +class PooledIntArrayAllocator +{ +public: + static size_t GlobalArray[256]; + static size_t GlobalTracker; + + size_t CurrentSize; + + size_t* Allocate(size_t _size) + { + GlobalTracker = GlobalTracker + _size; + CurrentSize = _size; + return &GlobalArray[GlobalTracker - _size]; + } + + void Deallocate(size_t* _ptr, size_t _size) + { + (void)_ptr; + (void)_size; + } +}; + +size_t PooledIntArrayAllocator::GlobalTracker = 0; +size_t PooledIntArrayAllocator::GlobalArray[256]; + +static const char* test_Allocator() +{ + size_t testData[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + ZArray<size_t> arr1; + ZArray<size_t> arr2(5); + ZArray<size_t> arr3(testData, 6, 10); + + ZArray<size_t, PooledIntArrayAllocator> arr4(testData, 10, 10); + ZArray<size_t, PooledIntArrayAllocator> arr5(testData, 5, 5); + + TASSERT(arr4.Allocator().CurrentSize != arr5.Allocator().CurrentSize, + "Allocator returns invalid allocator instances!"); + + for (int i = 0; i < 10; i++) + { + TASSERT(memcmp(arr4.Allocator().GlobalArray, arr5.Allocator().GlobalArray, 256 * sizeof(size_t)) == 0, + "arr4 and arr5 do not share static global data with pooled allocator!"); + } + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +using namespace ZArrayTestObjects; + +static const char* test_Reserve_Resize_Clear_Empty() +{ + int testData[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + ZArray<int> arr1; + ZArray<int> arr2(5); + ZArray<int> arr3(testData, 6, 10); + + arr3.Reserve(arr3.Size()); + + TASSERT(arr3.Capacity() != arr3.Size(), "Reserve(Size()) improperly reduced capacity!"); + + arr3.Reserve(arr3.Size(), true); + + TASSERT(arr3.Capacity() == arr3.Size(), "Reserve(Size(), true) did not reduce capacity to proper value!"); + + arr3.Reserve(10); + + TASSERT(arr3.Capacity() == 10, "Reserve(10) did not reserve enough capacity!"); + TASSERT(arr3.Size() == 6, "Reserve(10) modified the size!"); + + for (size_t i = 0; i < arr3.Size(); i++) + { + TASSERT(arr3[i] == (int)i, "Reserve(10) modified elements!"); + } + + arr3.Resize(arr3.Capacity()); + + TASSERT(arr3.Capacity() == 10, "Resize(Capacity()) improperly modified capacity!"); + TASSERT(arr3.Size() == 10, "Resize(Capacity() did not grow arr3 to the correct size!"); + + for (int i = 0; i < 6; i++) + { + TASSERT(arr3[i] == i, "Resize(Capacity() improperly modifed existing elements!"); + } + + arr3.Resize(6); + + TASSERT(arr3.Capacity() == 10, "Resize(6) with _size < Capacity() improperly modified capacity!"); + TASSERT(arr3.Size() == 6, "Resize(6) did not shrink arr3 to the correct size!"); + + for (size_t i = 0; i < arr3.Size(); i++) + { + TASSERT(arr3[i] == (int)i, "Resize(6) improperly modified existing elements!"); + } + + arr3.Resize(arr3.Capacity(), -1); + + TASSERT(arr3.Capacity() == 10, "Resize(Capacity(), -1) improperly modified capacity!"); + TASSERT(arr3.Size() == 10, "Resize(Capacity(), -1) did not grow arr3 to the correct size!"); + + for (int i = 0; i < 6; i++) + { + TASSERT(arr3[i] == i, "Resize(Capacity(), -1) improperly modified existing elements!"); + } + + for (size_t i = 6; i < arr3.Size(); i++) + { + TASSERT(arr3[i] == -1, "Resize(Capacity(), -1) improperly set new values!"); + } + + arr3.Resize(32, -1); + + TASSERT(arr3.Capacity() == 32, "Resize(32, -1) did not grow capacity!"); + TASSERT(arr3.Size() == 32, "Resize(32, -1) did not grow arr3 to the correct size!"); + TASSERT(!arr3.Empty(), "Empty() did not return false when Size() == 32!"); + + arr3.Clear(); + + TASSERT(arr3.Capacity() == 32, "Clear() improperly reduced capacity!"); + TASSERT(arr3.Size() == 0, "Clear() did not correctly reduce size!"); + TASSERT(arr3.Empty(), "Empty() did not return true when Size() == 0!"); + + arr3.Clear(arr3.Capacity()); + + TASSERT(arr3.Capacity() == 32, "Clear(Capacity()) improperly reduced capacity!"); + TASSERT(arr3.Empty(), "Empty() did not return true when Size() == 0!"); + + arr3.Clear(256); + + TASSERT(arr3.Capacity() == 256, "Clear(256) did not correctly grow capacity!"); + TASSERT(arr3.Empty(), "Empty() did not return true when Size() == 0!"); + + /* Testing memory allocator guarantees */ + { + ZArray<TestObject> arr4; + + TASSERT(TestObject::Instances == ZARRAY_DEFAULT_ALLOCATOR_STORAGE, "TestObject array constructed invalid number of instances with default constructor!"); + } + + TASSERT(TestObject::Instances == 0, "TestObject array failed to deallocate instances when out of scope!"); + + ZArray<TestObject, ZArrayAllocator<ZArrayTestObjects::TestObject, 0> > arr5(0); + + TASSERT(TestObject::Instances == 0, "TestObject array constructed instances with zero capacity constructor!"); + + arr5.Reserve(5); + + TASSERT(TestObject::Instances == 5, "TestObject array constructed invalid number of instances after Reserve(5)!"); + + arr5.Reserve(2); + + TASSERT(TestObject::Instances == 5, "TestObject array destructed instances when _reallocate was false!"); + + arr5.Reserve(2, true); + + TASSERT(TestObject::Instances == 2, "TestObject array failed to deallocate instances when _reallocate was true!"); + + arr5.Reserve(0); + + TASSERT(TestObject::Instances == 0, "TestObject array failed to deallocate all instances when Reserve(0) was called!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Push_Pop() +{ + int testData[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + ZArray<int> arr1; + ZArray<int> arr2(5); + ZArray<int> arr3(testData, 6, 10); + + int val; + + val = arr3.PopBack(); + + TASSERT(val == 5, "Pop() did not return correct value!"); + TASSERT(arr3.Size() == 5, "Pop() did not correctly reduce size!"); + TASSERT(arr3.Capacity() == 10, "Pop() incorrectly modified capacity!"); + + arr3.PushBack(10); + + TASSERT(arr3[arr3.Size() - 1] == 10, "PushBack(10) did not push correct value!"); + TASSERT(arr3[arr3.Size() - 2] == 4, "PushBack(10) incorrectly modified earlier elements!"); + TASSERT(arr3.Size() == 6, "PushBack(10) did not correctly increase size!"); + TASSERT(arr3.Capacity() == 10, "Pop() incorrectly modified capacity!"); + + arr3.PushBack(10); + arr3.PushBack(10); + arr3.PushBack(10); + arr3.PushBack(10); + + arr3.PushBack(15); //This one should trigger a capacity increase + + TASSERT(arr3.Size() == 11, "PushBack(...) did not correctly increase size!"); + TASSERT(arr3.Capacity() > 11, "PushBack(...) with Size() == Capacity() did not increase capacity!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Insert_Erase() +{ + int testData[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + ZArray<int> arr1; + ZArray<int> arr2(5); + ZArray<int> arr3(testData, 6, 10); + + //a1 = [1,2,3,4] + arr1.PushBack(1); + arr1.PushBack(2); + arr1.PushBack(3); + arr1.PushBack(4); + + //a1 = [0xFF, 1, 2, 3, 4] + arr1.Insert(0, 0xFF); + + TASSERT(arr1[0] == 0xFF, "Insert(0, 0xFF) did not set element [0] to 0xFF"); + TASSERT(arr1.Size() == 5, "Insert(0, 0xFF) did not set the size correctly"); + + for(size_t i = 1; i < arr1.Size(); i++) + { + //Elements [1] .. [Size()-1] should be unmodified. + TASSERT(arr1[i] == (int)i, "Insert(0, 0xFF) did not preserve remaining elements' values!"); + } + + int test = arr1.Erase(0); + + TASSERT(test == 0xFF, "Erase(0) returned the wrong value!"); + TASSERT(arr1.Size() == 4, "Erase(0) did not correctly set the size!"); + + for(size_t i = 0; i < arr1.Size(); i++) + { + //Now elements [0..3] should be the values {1, 2, 3, 4} again. + TASSERT(arr1[i] == (int)(i+1), "Erase(0) did not preserve remaining elements' values"); + } + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Begin_End() +{ + int testData[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + ZArray<int> arr1; + ZArray<int> arr2(5); + ZArray<int> arr3(testData, 6, 10); + + ZArray<int>::Iterator itr1_1 = arr1.Begin(); + ZArray<int>::Iterator itr1_2 = arr1.End(); + + TASSERT(itr1_1 == itr1_2, "Empty array does not return Begin() == End()!"); + + ZArray<int>::Iterator itr3_1 = arr3.Begin(); + ZArray<int>::Iterator itr3_2 = arr3.End(); + + TASSERT(itr3_1 != itr3_2, "Non-empty array returns Begin() == End()!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Find_Iterator() +{ + int testData[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + ZArray<int> arr1; + ZArray<int> arr2(5); + ZArray<int> arr3(testData, 6, 10); + + ZArray<int>::Iterator itr1_1 = arr1.Begin(); + + ZArray<int>::Iterator itr3_1 = arr3.Begin(); + ZArray<int>::Iterator itr3_2 = arr3.End(); + + TASSERT(itr1_1.HasNext() == false, "Iterator HasNext() returns true on empty array iterator!"); + TASSERT(itr1_1.HasPrev() == false, "Iterator HasPrev() returns true on empty array iterator!"); + TASSERT(itr1_1.HasCurrent() == false, "Iterator HasCurrent() returns false on empty array iterator!"); + + TASSERT(itr3_1.HasNext() == true, "Iterator HasNext() returns false when elements remain!"); + TASSERT(itr3_1.HasPrev() == false, "Iterator HasPrev() returns true on Begin() Iterator!"); + TASSERT(itr3_1.HasCurrent() == true, "Iterator HasCurrent() returns false on Begin() Iterator!"); + + TASSERT(itr1_1 >= arr1.Begin(), "Iterator >= did not return true when equal to Begin()!"); + TASSERT(itr1_1 <= arr1.Begin(), "Iterator <= did not return true when equal to Begin()!"); + TASSERT(itr3_1 <= arr3.End(), "Iterator <= did not return true when less than End()!"); + + size_t i = 0; + + TASSERT(itr3_1.HasCurrent() == true, "Iterator HasCurrent() does not return true when elements exist!"); + TASSERT(itr3_1.Get() == arr3[i], "Iterator Get() does not return value at beginning of array with Begin() Iterator!"); + TASSERT(*itr3_1 == arr3[i], "Iterator operator * does not return value at beginning of array with Begin() Iterator!"); + TASSERT(itr3_1 + 1 == (size_t)arr3[i + 1], "Iterator + operator does not return correct iterator!"); + + itr3_1 += 1; + + TASSERT(*itr3_1 == arr3[i + 1], "Iterator += operator did not correctly update iterator!"); + TASSERT((size_t)*itr3_1 > arr3.Begin(), "Iterator > operator did not return true when compared to Begin()!"); + + for (i = 1; itr3_1 != itr3_2 && i < arr3.Size(); ++i, ++itr3_1) + { + TASSERT(itr3_1 != itr3_2, "Iterator != returns true when iterators not equal!"); + TASSERT(itr3_1 == (size_t)i, "Iterator does not cast correctly to size_t!"); + TASSERT(itr3_1.HasCurrent() == true, "Iterator HasCurrent() does not return true when elements exist!"); + TASSERT(itr3_1.HasPrev() == true, "Iterator HasPrev() returns false when previous elements exist!"); + TASSERT(itr3_1.Get() == arr3[i], "Iterator Get() does not return correct value!"); + TASSERT(*itr3_1 == arr3[i], "Iterator operator * does not return correct value!"); + TASSERT(itr3_1 - 1 == (size_t)arr3[i - 1], "Iterator - operator does not return correct iterator!"); + } + + TASSERT(itr3_1 == itr3_2, "Iterator did not iterate to end!"); + + itr3_1 -= 1; + + TASSERT(itr3_1 != itr3_2, "Iterator operator -= did not correctly update iterator!"); + + for (i = itr3_1; itr3_1 != arr3.Begin() && i < arr3.Size(); --i, --itr3_1) + { + TASSERT(itr3_1 != itr3_2, "Iterator != returns true when iterators not equal!"); + } + + TASSERT(itr3_1 == arr3.Begin(), "Iterator did not iterate to beginning!"); + + itr3_1 = itr3_2; + + TASSERT(itr3_1 == itr3_2, "Iterator operator = did not correctly assign iterator!"); + + return ZTEST_SUCCESS; +} diff --git a/ZTestSuite/Test-ZArrayAlgo.cpp b/ZTestSuite/Test-ZArrayAlgo.cpp new file mode 100644 index 0000000..57c4e20 --- /dev/null +++ b/ZTestSuite/Test-ZArrayAlgo.cpp @@ -0,0 +1,3163 @@ +#include "ZUnitTest.hpp" + +#include <ZSTL/ZArrayAlgo.hpp> + +static const char* test_Append(); +static const char* test_Append_Region(); +static const char* test_Apply(); +static const char* test_Apply_Region(); +static const char* test_Concatenate(); +static const char* test_Concatenate_Region(); +static const char* test_Contains(); +static const char* test_Contains_Region(); +static const char* test_ContainsSub(); +static const char* test_ContainsSub_Region(); +static const char* test_Copy(); +static const char* test_Copy_Region(); +static const char* test_Count(); +static const char* test_Count_Region(); +static const char* test_Equal(); +static const char* test_Equal_In_Region(); +static const char* test_Fill(); +static const char* test_Fill_Region(); +static const char* test_Find(); +static const char* test_Find_Region(); +static const char* test_FindAll(); +static const char* test_FindAll_Region(); +static const char* test_FindAllOf(); +static const char* test_FindAllOf_Region(); +static const char* test_FindIf(); +static const char* test_FindIf_In_Region(); +static const char* test_FindFirst(); +static const char* test_FindFirst_In_Region(); +static const char* test_FindFirstOf(); +static const char* test_FindFirstOf_In_Region(); +static const char* test_FindFirstNot(); +static const char* test_FindFirstNot_In_Region(); +static const char* test_FindFirstNotOf(); +static const char* test_FindFirstNotOf_In_Region(); +static const char* test_FindLast(); +static const char* test_FindLast_In_Region(); +static const char* test_FindLastOf(); +static const char* test_FindLastOf_In_Region(); +static const char* test_FindLastNot(); +static const char* test_FindLastNot_In_Region(); +static const char* test_FindLastNotOf(); +static const char* test_FindLastNotOf_In_Region(); +static const char* test_FindSub(); +static const char* test_FindSub_In_Region(); +static const char* test_FoldLeft(); +static const char* test_FoldLeft_Region(); +static const char* test_FoldRight(); +static const char* test_FoldRight_Region(); +static const char* test_Generate(); +static const char* test_Generate_In_Region(); +static const char* test_Max(); +static const char* test_Max_In_Region(); +static const char* test_Max_Comparator(); +static const char* test_Max_Comparator_In_Region(); +static const char* test_Min(); +static const char* test_Min_In_Region(); +static const char* test_Min_Comparator(); +static const char* test_Min_Comparator_In_Region(); +static const char* test_Remove(); +static const char* test_Remove_In_Region(); +static const char* test_RemoveAll(); +static const char* test_RemoveAll_In_Region(); +static const char* test_RemoveIf(); +static const char* test_RemoveIf_In_Region(); +static const char* test_RemoveUpTo(); +static const char* test_RemoveUpTo_In_Region(); +static const char* test_Replace(); +static const char* test_Replace_In_Region(); +static const char* test_ReplaceIf(); +static const char* test_ReplaceIf_In_Region(); +static const char* test_Reverse(); +static const char* test_Reverse_Region(); +static const char* test_Rotate(); +static const char* test_Rotate_Region(); +static const char* test_SetIntersection(); +static const char* test_SetIntersection_In_Region(); +static const char* test_SetUnion(); +static const char* test_SetUnion_In_Region(); +static const char* test_Slice(); +static const char* test_Sort(); +static const char* test_Sort_Region(); +static const char* test_Sort_Comparator(); +static const char* test_Sort_Comparator_Algorithm(); +static const char* test_Sort_Comparator_Algorithm_Region(); +static const char* test_Split(); +static const char* test_Split_Count(); +static const char* test_Split_Count_Region(); +static const char* test_Sum(); +static const char* test_Sum_Region(); +static const char* test_SwapElements(); +static const char* test_Map(); +static const char* test_Map_Region(); +static const char* test_Unique(); +static const char* test_Unique_In_Region(); + +//List of unit tests +ZUnitTest ZArrayAlgoUnitTests[] = +{ + { "ZArrayAlgo: Append", test_Append }, + { "ZArrayAlgo: Append region", test_Append_Region }, + { "ZArrayAlgo: Apply", test_Apply} , + { "ZArrayAlgo: Apply to region", test_Apply_Region} , + { "ZArrayAlgo: Concatenate", test_Concatenate }, + { "ZArrayAlgo: Concatenate region", test_Concatenate_Region }, + { "ZArrayAlgo: Contains", test_Contains }, + { "ZArrayAlgo: Contains region", test_Contains_Region }, + { "ZArrayAlgo: ContainsSub", test_ContainsSub }, + { "ZArrayAlgo: ContainsSub region", test_ContainsSub_Region }, + { "ZArrayAlgo: Copy", test_Copy }, + { "ZArrayAlgo: Copy region", test_Copy_Region }, + { "ZArrayAlgo: Count", test_Count }, + { "ZArrayAlgo: Count region", test_Count_Region }, + { "ZArrayAlgo: Equal", test_Equal }, + { "ZArrayAlgo: Equal in region", test_Equal_In_Region }, + { "ZArrayAlgo: Fill", test_Fill }, + { "ZArrayAlgo: Fill region", test_Fill_Region }, + { "ZArrayAlgo: Find ", test_Find }, + { "ZArrayAlgo: Find in region", test_Find_Region }, + { "ZArrayAlgo: FindAll ", test_FindAll }, + { "ZArrayAlgo: FindAll region ", test_FindAll_Region }, + { "ZArrayAlgo: FindAllOf ", test_FindAllOf }, + { "ZArrayAlgo: FindAllOf region ", test_FindAllOf_Region }, + { "ZArrayAlgo: FindIf", test_FindIf }, + { "ZArrayAlgo: FindIf in region", test_FindIf_In_Region }, + { "ZArrayAlgo: FindFirst", test_FindFirst }, + { "ZArrayAlgo: FindFirst in region", test_FindFirst_In_Region }, + { "ZArrayAlgo: FindFirstOf", test_FindFirstOf }, + { "ZArrayAlgo: FindFirstOf in region", test_FindFirstOf_In_Region }, + { "ZArrayAlgo: FindFirstNot", test_FindFirstNot }, + { "ZArrayAlgo: FindFirstNot in region", test_FindFirstNot_In_Region }, + { "ZArrayAlgo: FindFirstNotOf", test_FindFirstNotOf }, + { "ZArrayAlgo: FindFirstNotOf in region", test_FindFirstNotOf_In_Region }, + { "ZArrayAlgo: FindLast", test_FindLast}, + { "ZArrayAlgo: FindLast in region", test_FindLast_In_Region}, + { "ZArrayAlgo: FindLastOf", test_FindLastOf} , + { "ZArrayAlgo: FindLastOf in region", test_FindLastOf_In_Region} , + { "ZArrayAlgo: FindLastNot", test_FindLastNot}, + { "ZArrayAlgo: FindLastNot in region", test_FindLastNot_In_Region} , + { "ZArrayAlgo: FindLastNotOf", test_FindLastNotOf}, + { "ZArrayAlgo: FindLastNotOf in region", test_FindLastNotOf_In_Region} , + { "ZArrayAlgo: FindSub", test_FindSub }, + { "ZArrayAlgo: FindSub in region", test_FindSub_In_Region }, + { "ZArrayAlgo: FoldLeft", test_FoldLeft }, + { "ZArrayAlgo: FoldLeft region", test_FoldLeft_Region }, + { "ZArrayAlgo: FoldRight", test_FoldRight }, + { "ZArrayAlgo: FoldRight region", test_FoldRight_Region }, + { "ZArrayAlgo: Generate", test_Generate}, + { "ZArrayAlgo: Generate in region", test_Generate_In_Region} , + { "ZArrayAlgo: Map", test_Map} , + { "ZArrayAlgo: Map region", test_Map_Region} , + { "ZArrayAlgo: Max", test_Max} , + { "ZArrayAlgo: Max in region", test_Max_In_Region} , + { "ZArrayAlgo: Max with comparator", test_Max_Comparator} , + { "ZArrayAlgo: Max with comparator in region", test_Max_Comparator_In_Region} , + { "ZArrayAlgo: Min", test_Min} , + { "ZArrayAlgo: Min in region", test_Min_In_Region} , + { "ZArrayAlgo: Min comparator", test_Min_Comparator} , + { "ZArrayAlgo: Min comparator in region", test_Min_Comparator_In_Region} , + { "ZArrayAlgo: Remove", test_Remove} , + { "ZArrayAlgo: Remove in region", test_Remove_In_Region} , + { "ZArrayAlgo: RemoveAll", test_RemoveAll} , + { "ZArrayAlgo: RemoveAll in region", test_RemoveAll_In_Region} , + { "ZArrayAlgo: RemoveIf", test_RemoveIf} , + { "ZArrayAlgo: RemoveIf in region", test_RemoveIf_In_Region} , + { "ZArrayAlgo: RemoveUpTo", test_RemoveUpTo} , + { "ZArrayAlgo: RemoveUpTo in region", test_RemoveUpTo_In_Region} , + { "ZArrayAlgo: Replace", test_Replace} , + { "ZArrayAlgo: Replace in region", test_Replace_In_Region} , + { "ZArrayAlgo: ReplaceIf", test_ReplaceIf} , + { "ZArrayAlgo: ReplaceIf in region", test_ReplaceIf_In_Region} , + { "ZArrayAlgo: Reverse", test_Reverse} , + { "ZArrayAlgo: Reverse region", test_Reverse_Region} , + { "ZArrayAlgo: Rotate", test_Rotate} , + { "ZArrayAlgo: Rotate region", test_Rotate_Region} , + { "ZArrayAlgo: SetIntersection", test_SetIntersection} , + { "ZArrayAlgo: SetIntersection in region", test_SetIntersection_In_Region} , + { "ZArrayAlgo: SetUnion", test_SetUnion} , + { "ZArrayAlgo: SetUnion in region", test_SetUnion_In_Region} , + { "ZArrayAlgo: Slice", test_Slice }, + { "ZArrayAlgo: Sort", test_Sort} , + { "ZArrayAlgo: Sort region", test_Sort_Region} , + { "ZArrayAlgo: Sort given comparator", test_Sort_Comparator} , + { "ZArrayAlgo: Sort given comparator and algorithm", test_Sort_Comparator_Algorithm} , + { "ZArrayAlgo: Sort given comparator and algorithm in region", test_Sort_Comparator_Algorithm_Region}, + { "ZArrayAlgo: Split", test_Split }, + { "ZArrayAlgo: Split with count", test_Split_Count }, + { "ZArrayAlgo: Split with count in region", test_Split_Count_Region }, + { "ZArrayAlgo: Sum", test_Sum }, + { "ZArrayAlgo: Sum region", test_Sum_Region }, + { "ZArrayAlgo: SwapElements", test_SwapElements} , + { "ZArrayAlgo: Unique", test_Unique} , + { "ZArrayAlgo: Unique given comparator in region", test_Unique_In_Region} +}; + +//Now declare the ZUnitTestBlock associated with this. +DECLARE_ZTESTBLOCK(ZArrayAlgo); + +/*************************************************************************/ + +class ArrayValueTestClass +{ +public: + int val; + + ArrayValueTestClass() : val( 0 ) {} + ArrayValueTestClass(int v) : val(v) {} + + ArrayValueTestClass operator + (const ArrayValueTestClass& _other) + { + return ArrayValueTestClass(val + _other.val); + } +}; + +struct IfTestFunctor { + bool operator () (const int& val) { return val > 3; } +}; + +/*************************************************************************/ + +static const char* test_Append() +{ + ZArray<int> list; + ZArray<int> list2; + ZArray<int> out; + + list.PushBack(1); + list.PushBack(2); + list.PushBack(3); + list2.PushBack(4); + list2.PushBack(5); + list2.PushBack(6); + + ZArrayAlgo::Append(list,list2); + + TASSERT(list.Size() == 6, "Append() created list!\n"); + TASSERT(list.PopFront() == 1, "Append() corrupted list!\n"); + TASSERT(list.PopFront() == 2, "Append() corrupted list!\n"); + TASSERT(list.PopFront() == 3, "Append() corrupted list!\n"); + TASSERT(list.PopFront() == 4, "Append() corrupted list!\n"); + TASSERT(list.PopFront() == 5, "Append() corrupted list!\n"); + TASSERT(list.PopFront() == 6, "Append() corrupted list!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Append_Region() +{ + ZArray<int> list; + ZArray<int> list2; + ZArray<int> out; + + list.PushBack(1); + list.PushBack(2); + list2.PushBack(3); + list2.PushBack(4); + list2.PushBack(5); + list2.PushBack(6); + + ZArrayAlgo::Append(list,list2,1,3); + + TASSERT(list.Size() == 4, "Append() corrupted list!\n"); + TASSERT(list.PopFront() == 1, "Append() corrupted list!\n"); + TASSERT(list.PopFront() == 2, "Append() corrupted list!\n"); + TASSERT(list.PopFront() == 4, "Append() corrupted list!\n"); + TASSERT(list.PopFront() == 5, "Append() corrupted list!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +struct ApplyTestFunctor{ void operator()(int& _val) const { _val *= -1 ;} }; + +static const char* test_Apply() +{ + ZArray<int> list; + + list.PushBack(1); + list.PushBack(2); + list.PushBack(3); + list.PushBack(4); + list.PushBack(5); + + ZArrayAlgo::Apply(list, ApplyTestFunctor()); + TASSERT(list.Size() == 5, "Apply() changed list length!\n"); + TASSERT(list.PopFront() == -1, "Apply() did not apply functor!\n"); + TASSERT(list.PopFront() == -2, "Apply() did not apply functor!\n"); + TASSERT(list.PopFront() == -3, "Apply() did not apply functor!\n"); + TASSERT(list.PopFront() == -4, "Apply() did not apply functor!\n"); + TASSERT(list.PopFront() == -5, "Apply() did not apply functor!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Apply_Region() +{ + ZArray<int> list; + + list.PushBack(1); + list.PushBack(2); + list.PushBack(3); + list.PushBack(4); + list.PushBack(5); + + ZArrayAlgo::Apply(list, ApplyTestFunctor(), 1, 4); + TASSERT(list.Size() == 5, "Apply() changed list length!\n"); + TASSERT(list.PopFront() == 1, "Apply() did not apply functor!\n"); + TASSERT(list.PopFront() == -2, "Apply() did not apply functor!\n"); + TASSERT(list.PopFront() == -3, "Apply() did not apply functor!\n"); + TASSERT(list.PopFront() == -4, "Apply() did not apply functor!\n"); + TASSERT(list.PopFront() == 5, "Apply() did not apply functor!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Concatenate() +{ + ZArray<int> list; + ZArray<int> list2; + ZArray<int> out; + + list.PushBack(1); + list.PushBack(2); + list.PushBack(3); + list2.PushBack(4); + list2.PushBack(5); + list2.PushBack(6); + + out = ZArrayAlgo::Concatenate(list,list2); + + TASSERT(out.Size() == 6, "Append() created list of incorrect size!\n"); + TASSERT(out.PopFront() == 1, "Append() corrupted list!\n"); + TASSERT(out.PopFront() == 2, "Append() corrupted list!\n"); + TASSERT(out.PopFront() == 3, "Append() corrupted list!\n"); + TASSERT(out.PopFront() == 4, "Append() corrupted list!\n"); + TASSERT(out.PopFront() == 5, "Append() corrupted list!\n"); + TASSERT(out.PopFront() == 6, "Append() corrupted list!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Concatenate_Region() +{ + ZArray<int> list; + ZArray<int> list2; + ZArray<int> out; + + list.PushBack(1); + list.PushBack(2); + list.PushBack(3); + list.PushBack(4); + list2.PushBack(5); + list2.PushBack(6); + list2.PushBack(7); + list2.PushBack(8); + + out = ZArrayAlgo::Concatenate(list,1,3,list2,1,3); + + TASSERT(out.Size() == 4, "Append() created list of incorrect size!\n"); + TASSERT(out.PopFront() == 2, "Append() corrupted list!\n"); + TASSERT(out.PopFront() == 3, "Append() corrupted list!\n"); + TASSERT(out.PopFront() == 6, "Append() corrupted list!\n"); + TASSERT(out.PopFront() == 7, "Append() corrupted list!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Contains() +{ + ZArray<int> list; + + list.PushBack(1); + list.PushBack(2); + list.PushBack(3); + list.PushBack(4); + + TASSERT( ZArrayAlgo::Contains(list, 2) == true, "Contains() missed an existing element!\n"); + TASSERT( ZArrayAlgo::Contains(list, 5) == false, "Contains() found an nonexisting element!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Contains_Region() +{ + ZArray<int> list; + + list.PushBack(1); + list.PushBack(2); + list.PushBack(3); + list.PushBack(4); + list.PushBack(5); + list.PushBack(6); + + TASSERT( ZArrayAlgo::Contains(list, 2, 1, 5) == true, "Contains() missed an existing element inside of range!\n"); + TASSERT( ZArrayAlgo::Contains(list, 6, 1, 5) == false, "Contains() found an existing element outside of range!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_ContainsSub() +{ + ZArray<int> list; + + list.PushBack(1); + list.PushBack(2); + list.PushBack(3); + list.PushBack(4); + list.PushBack(5); + list.PushBack(6); + + ZArray<int> list2; + + list2.PushBack(3); + list2.PushBack(4); + list2.PushBack(5); + + ZArray<int> list3; + + list3.PushBack(3); + list3.PushBack(5); + + TASSERT(ZArrayAlgo::ContainsSub(list, list2), "ContainsSub() failed to return true when sub list is contained!"); + TASSERT(!ZArrayAlgo::ContainsSub(list, list3), "ContainsSub() failed to return false when sub list is not contained!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_ContainsSub_Region() +{ + ZArray<int> list; + + list.PushBack(1); + list.PushBack(2); + list.PushBack(3); + list.PushBack(4); + list.PushBack(5); + list.PushBack(6); + + ZArray<int> list2; + + list2.PushBack(3); + list2.PushBack(4); + list2.PushBack(5); + + TASSERT(ZArrayAlgo::ContainsSub(list, 2, 5, list2, 0, list2.Size()), "ContainsSub() failed to return true when sub list is contained in region 1!"); + TASSERT(!ZArrayAlgo::ContainsSub(list, 3, 5, list2, 0, list2.Size()), "ContainsSub() failed to return false when sub list is not contained in region!"); + TASSERT(ZArrayAlgo::ContainsSub(list, 3, 5, list2, 1, 3), "ContainsSub() failed to return true when sub list is contained in region 2!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Copy() +{ + ZArray<int> list; + ZArray<int> list2; + + list.PushBack(1); + list.PushBack(2); + list.PushBack(3); + list2.PushBack(5); + list2.PushBack(6); + list2.PushBack(7); + list2.PushBack(8); + + ZArrayAlgo::Copy(list2, list); + + TASSERT( list2.PopFront() == 1, "Copy() failed to copy correct element!\n"); + TASSERT( list2.PopFront() == 2, "Copy() failed to copy correct element!\n"); + TASSERT( list2.PopFront() == 3, "Copy() failed to copy correct element!\n"); + TASSERT( list2.PopFront() == 8, "Copy() overrode out-of-range element!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Copy_Region() +{ + ZArray<int> list; + ZArray<int> list2; + + list.PushBack(1); + list.PushBack(2); + list.PushBack(3); + list.PushBack(4); + + list2.PushBack(5); + list2.PushBack(6); + list2.PushBack(7); + list2.PushBack(8); + + ZArrayAlgo::Copy(list2, 1, 3, list, 2, 4); + + TASSERT( list2.PopFront() == 5, "Copy() failed to copy correct element!\n"); + TASSERT( list2.PopFront() == 3, "Copy() failed to copy correct element!\n"); + TASSERT( list2.PopFront() == 4, "Copy() failed to copy correct element!\n"); + TASSERT( list2.PopFront() == 8, "Copy() failed to copy correct element!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Count() +{ + ZArray<int> list; + + list.PushBack(1); + list.PushBack(2); + list.PushBack(2); + list.PushBack(2); + list.PushBack(2); + list.PushBack(3); + list.PushBack(4); + + TASSERT( ZArrayAlgo::Count(list, 2) == 4, "Count() failed to get accurate count of existing element!\n"); + TASSERT( ZArrayAlgo::Count(list, 5) == 0, "Count() failed to get accurate count of nonexisting element!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Count_Region() +{ + ZArray<int> list; + + list.PushBack(1); + list.PushBack(2); + list.PushBack(2); + list.PushBack(2); + list.PushBack(2); + list.PushBack(3); + list.PushBack(4); + + TASSERT( ZArrayAlgo::Count(list, 2, 2, 6) == 3, "Count() failed to get accurate count of existing element!\n"); + TASSERT( ZArrayAlgo::Count(list, 1, 2, 6) == 0, "Count() failed to get accurate count of existing element outside of range!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Equal() +{ + ZArray<int> list; + ZArray<int> list2a; + ZArray<int> list2b; + ZArray<int> list3; + + list.PushBack(1); + list.PushBack(2); + list.PushBack(3); + list.PushBack(4); + + list2a.PushBack(1); + list2a.PushBack(2); + list2a.PushBack(3); + list2a.PushBack(4); + + list3.PushBack(5); + list3.PushBack(6); + list3.PushBack(7); + list3.PushBack(8); + + TASSERT( ZArrayAlgo::Equal(list, list2a) == true, "Equal() reported nonequailty on identical lists!\n"); + TASSERT( ZArrayAlgo::Equal(list, list3) == false, "Equal() reported equality on different lists!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Equal_In_Region() +{ + ZArray<int> list; + ZArray<int> list2a; + ZArray<int> list2b; + ZArray<int> list3; + + list.PushBack(1); + list.PushBack(2); + list.PushBack(3); + list.PushBack(4); + + list2a.PushBack(1); + list2a.PushBack(2); + list2a.PushBack(3); + list2a.PushBack(4); + + list2b.PushBack(0); + list2b.PushBack(1); + list2b.PushBack(2); + list2b.PushBack(3); + + list3.PushBack(5); + list3.PushBack(6); + list3.PushBack(7); + list3.PushBack(8); + + TASSERT( ZArrayAlgo::Equal(list, 1, 4, list2a, 1, 4) == true, "Equal() reported nonequailty on identical sublists!\n"); + TASSERT( ZArrayAlgo::Equal(list, 0, 3, list2b, 1, 4) == true, "Equal() reported nonequailty on identical sublists!\n"); + TASSERT( ZArrayAlgo::Equal(list, 1, 4, list3, 1, 4) == false, "Equal() reported equality on different lists!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Fill() +{ + ZArray<int> list; + list.PushBack(1); + list.PushBack(2); + list.PushBack(3); + + ZArrayAlgo::Fill(list, 4); + + TASSERT( list.Size() == 3, "Fill() changed size of array!\n"); + TASSERT( list.PopFront() == 4, "Fill() didn't fill array correctly!\n"); + TASSERT( list.PopFront() == 4, "Fill() didn't fill array correctly!\n"); + TASSERT( list.PopFront() == 4, "Fill() didn't fill array correctly!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Fill_Region() +{ + ZArray<int> list; + list.PushBack(1); + list.PushBack(2); + list.PushBack(3); + list.PushBack(4); + list.PushBack(5); + + ZArrayAlgo::Fill(list, 6, 1, 4); + + TASSERT( list.Size() == 5, "Fill() changed size of array!\n"); + TASSERT( list.PopFront() == 1, "Fill() didn't fill array correctly!\n"); + TASSERT( list.PopFront() == 6, "Fill() didn't fill array correctly!\n"); + TASSERT( list.PopFront() == 6, "Fill() didn't fill array correctly!\n"); + TASSERT( list.PopFront() == 6, "Fill() didn't fill array correctly!\n"); + TASSERT( list.PopFront() == 5, "Fill() didn't fill array correctly!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Find() +{ + ZArray<int> list; + + list.PushBack(0); // 0 + list.PushBack(1); // 1 + list.PushBack(0); // 2 + list.PushBack(3); // 3 + list.PushBack(3); // 4 + list.PushBack(0); // 5 + list.PushBack(6); // 6 + list.PushBack(3); // 7 + list.PushBack(0); // 8 + list.PushBack(3); // 9 + list.PushBack(3); // 10 + list.PushBack(0); // 11 + + TASSERT( ZArrayAlgo::Find(list,42,0) == ZSTL::InvalidPos, "Find() found missing element!\n"); + TASSERT( ZArrayAlgo::Find(list,0,0) == 0, "Find() missed element at front!\n"); + TASSERT( ZArrayAlgo::Find(list,0,4) == 11, "Find() miscounted elements!\n"); + TASSERT( ZArrayAlgo::Find(list,0,23) == ZSTL::InvalidPos, "Find() found excess (nonexistent) element!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Find_Region() +{ + ZArray<int> list; + + list.PushBack(0); // 0 + list.PushBack(1); // 1 + list.PushBack(0); // 2 + list.PushBack(3); // 3 + list.PushBack(3); // 4 + list.PushBack(0); // 5 + list.PushBack(6); // 6 + list.PushBack(3); // 7 + list.PushBack(0); // 8 + list.PushBack(3); // 9 + list.PushBack(3); // 10 + list.PushBack(0); // 11 + + TASSERT( ZArrayAlgo::Find(list,42,0,2,10) == ZSTL::InvalidPos, "Find() found missing element!\n"); + TASSERT( ZArrayAlgo::Find(list,0,0,2,10) == 2, "Find() missed element at front!\n"); + TASSERT( ZArrayAlgo::Find(list,0,2,2,10) == 8, "Find() miscounted elements!\n"); + TASSERT( ZArrayAlgo::Find(list,0,23,2,10) == ZSTL::InvalidPos, "Find() found excess (nonexistent) element!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_FindAll() +{ + ZArray<int> list; + + list.PushBack(0); // 0 + list.PushBack(1); // 1 + list.PushBack(0); // 2 + list.PushBack(3); // 3 + list.PushBack(3); // 4 + list.PushBack(0); // 5 + list.PushBack(6); // 6 + list.PushBack(3); // 7 + list.PushBack(0); // 8 + list.PushBack(3); // 9 + list.PushBack(3); // 10 + list.PushBack(0); // 11 + + ZArray<size_t> inds; + + // search for nonexistent value + inds = ZArrayAlgo::FindAll(list, 10); + TASSERT(inds.Empty(), "FindAll() found nonexistent elements!\n"); + + // search for multiple elements + inds = ZArrayAlgo::FindAll(list, 3); + TASSERT(inds.Size() == 5, "FindAll() did not find all elements!\n"); + TASSERT(inds.PopFront() == 3,"FindAll() found element in incorrect position!\n"); + TASSERT(inds.PopFront() == 4,"FindAll() found element in incorrect position!\n"); + TASSERT(inds.PopFront() == 7,"FindAll() found element in incorrect position!\n"); + TASSERT(inds.PopFront() == 9,"FindAll() found element in incorrect position!\n"); + TASSERT(inds.PopFront() == 10,"FindAll() found element in incorrect position!\n"); + + // search for existing elements in middle and ends + inds = ZArrayAlgo::FindAll(list, 0); + TASSERT(inds.Size() == 5, "FindAll() did not find all elements!\n"); + TASSERT(inds.PopFront() == 0,"FindAll() found element in incorrect position!\n"); + TASSERT(inds.PopFront() == 2,"FindAll() found element in incorrect position!\n"); + TASSERT(inds.PopFront() == 5,"FindAll() found element in incorrect position!\n"); + TASSERT(inds.PopFront() == 8,"FindAll() found element in incorrect position!\n"); + TASSERT(inds.PopFront() == 11,"FindAll() found element in incorrect position!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_FindAll_Region() +{ + ZArray<int> list; + + list.PushBack(0); // 0 + list.PushBack(1); // 1 + list.PushBack(0); // 2 + list.PushBack(3); // 3 + list.PushBack(3); // 4 + list.PushBack(0); // 5 + list.PushBack(6); // 6 + list.PushBack(3); // 7 + list.PushBack(0); // 8 + list.PushBack(3); // 9 + list.PushBack(3); // 10 + list.PushBack(0); // 11 + + ZArray<size_t> inds; + + // search for nonexistent value + inds = ZArrayAlgo::FindAll(list, 10, 3, 9); + TASSERT(inds.Empty(), "FindAll() found nonexistent elements!\n"); + + // search for multiple elements + inds = ZArrayAlgo::FindAll(list, 3, 3, 9); + TASSERT(inds.Size() == 3, "FindAll() did not find all elements!\n"); + TASSERT(inds.PopFront() == 3,"FindAll() found element in incorrect position!\n"); + TASSERT(inds.PopFront() == 4,"FindAll() found element in incorrect position!\n"); + TASSERT(inds.PopFront() == 7,"FindAll() found element in incorrect position!\n"); + + // search for existing elements in middle and ends + inds = ZArrayAlgo::FindAll(list, 0, 3, 12); + TASSERT(inds.Size() == 3, "FindAll() did not find all elements!\n"); + TASSERT(inds.PopFront() == 5,"FindAll() found element in incorrect position!\n"); + TASSERT(inds.PopFront() == 8,"FindAll() found element in incorrect position!\n"); + TASSERT(inds.PopFront() == 11,"FindAll() found element in incorrect position!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_FindAllOf() +{ + ZArray<int> list; + + list.PushBack(0); // 0 + list.PushBack(1); // 1 + list.PushBack(0); // 2 + list.PushBack(3); // 3 + list.PushBack(3); // 4 + list.PushBack(0); // 5 + list.PushBack(6); // 6 + list.PushBack(3); // 7 + list.PushBack(0); // 8 + list.PushBack(3); // 9 + list.PushBack(3); // 10 + list.PushBack(0); // 11 + + ZArray<size_t> inds; + + // search for nonexistent value + const int badvalues[] = {7,9,-3}; + inds = ZArrayAlgo::FindAllOf(list, ZArray<int>(badvalues)); + TASSERT(inds.Empty(), "FindAll() found nonexistent elements!\n"); + + // search for existent values + const int goodvalues[] = {1,6}; + inds = ZArrayAlgo::FindAllOf(list, ZArray<int>(goodvalues)); + TASSERT(inds.Size() == 2, "FindAll() found wrong number of elements!\n"); + TASSERT(inds.PopFront() == 1, "FindAll() found element in wrong position!\n"); + TASSERT(inds.PopFront() == 6, "FindAll() found element in wrong position!\n"); + + // search for existent values, including those on ends + const int goodvalues2[] = {1,3}; + inds = ZArrayAlgo::FindAllOf(list, ZArray<int>(goodvalues2)); + TASSERT(inds.Size() == 6, "FindAll() found wrong number of elements!\n"); + TASSERT(inds.PopFront() == 1, "FindAll() found element in wrong position!\n"); + TASSERT(inds.PopFront() == 3, "FindAll() found element in wrong position!\n"); + TASSERT(inds.PopFront() == 4, "FindAll() found element in wrong position!\n"); + TASSERT(inds.PopFront() == 7, "FindAll() found element in wrong position!\n"); + TASSERT(inds.PopFront() == 9, "FindAll() found element in wrong position!\n"); + TASSERT(inds.PopFront() == 10, "FindAll() found element in wrong position!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_FindAllOf_Region() +{ + ZArray<int> list; + + list.PushBack(0); // 0 + list.PushBack(1); // 1 + list.PushBack(0); // 2 + list.PushBack(3); // 3 + list.PushBack(3); // 4 + list.PushBack(5); // 5 + list.PushBack(6); // 6 + list.PushBack(3); // 7 + list.PushBack(0); // 8 + list.PushBack(3); // 9 + list.PushBack(3); // 10 + list.PushBack(0); // 11 + + ZArray<size_t> inds; + + // search for nonexistent value + const int badvals[] = {13,43,14,42}; + inds = ZArrayAlgo::FindAllOf(list, 2, 9, ZArray<int>(badvals), 0, 4); + TASSERT(inds.Empty(), "FindAll() found nonexistent elements!\n"); + + // search for value in empty region + const int goodvals[] = {1,3,5,6}; + inds = ZArrayAlgo::FindAllOf(list, 0, 1, ZArray<int>(goodvals), 0, 4); + TASSERT(inds.Empty(), "FindAll() found nonexistent elements in empty region!\n"); + + // search for existent values in subregion of target list + inds = ZArrayAlgo::FindAllOf(list, 2, 9, ZArray<int>(goodvals), 1, 3); + TASSERT(inds.Size() == 4, "FindAll() found wrong number of elements!\n"); + TASSERT(inds.PopFront() == 3, "FindAll() found element in wrong position!\n"); + TASSERT(inds.PopFront() == 4, "FindAll() found element in wrong position!\n"); + TASSERT(inds.PopFront() == 5, "FindAll() found element in wrong position!\n"); + TASSERT(inds.PopFront() == 7, "FindAll() found element in wrong position!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_FindIf() +{ + ZArray<int> list; + list.PushBack(1); + list.PushBack(2); + list.PushBack(3); + list.PushBack(4); + list.PushBack(5); + + ZArray<int> list2; + list2.PushBack(1); + list2.PushBack(2); + list2.PushBack(3); + list2.PushBack(2); + list2.PushBack(1); + + TASSERT( ZArrayAlgo::FindIf(list, IfTestFunctor()) == 3, "FindIf() failed to find first element matching functor!\n"); + TASSERT( ZArrayAlgo::FindIf(list2, IfTestFunctor()) == ZSTL::InvalidPos, "FindIf() failed to not find first element matching functor!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_FindIf_In_Region() +{ + ZArray<int> list; + list.PushBack(1); + list.PushBack(2); + list.PushBack(3); + list.PushBack(4); + list.PushBack(5); + + TASSERT( ZArrayAlgo::FindIf(list, IfTestFunctor(), 1, 4) == 3, "FindIf() failed to find first element matching functor in subregion!\n"); + TASSERT( ZArrayAlgo::FindIf(list, IfTestFunctor(), 1, 3) == ZSTL::InvalidPos, "FindIf() found nonconforming element in range!\n"); + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_FindFirst() +{ + ZArray<int> list; + list.PushBack(1); + list.PushBack(2); + list.PushBack(3); + list.PushBack(4); + list.PushBack(5); + + TASSERT( ZArrayAlgo::FindFirst(list, 3) == 2, "FindFirst() failed to find first element in correct position!\n"); + TASSERT( ZArrayAlgo::FindFirst(list, 7) == ZSTL::InvalidPos, "FindFirst() found element not in list!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_FindFirst_In_Region() +{ + ZArray<int> list; + list.PushBack(1); + list.PushBack(2); + list.PushBack(3); + list.PushBack(4); + list.PushBack(5); + list.PushBack(6); + list.PushBack(7); + + TASSERT( ZArrayAlgo::FindFirst(list, 4, 2, 5) == 3, "FindFirst() failed to find first element in correct position in region!\n"); + TASSERT( ZArrayAlgo::FindFirst(list, 4, 4, 7) == ZSTL::InvalidPos, "FindFirst() found element not in region!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_FindFirstOf() +{ + ZArray<int> list; + + list.PushBack(1); + list.PushBack(2); + list.PushBack(3); + list.PushBack(4); + list.PushBack(5); + + ZArray<int> values1; + ZArray<int> values2; + + values1.PushBack(3); + values1.PushBack(5); + + values2.PushBack(6); + values2.PushBack(7); + + TASSERT( ZArrayAlgo::FindFirstOf(list, values1) == 2, "FindFirstOf() failed to find first element in correct position!\n"); + TASSERT( ZArrayAlgo::FindFirstOf(list, values2) == ZSTL::InvalidPos, "FindFirstOf() found element not in list!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_FindFirstOf_In_Region() +{ + ZArray<int> list; + + list.PushBack(1); + list.PushBack(2); + list.PushBack(3); + list.PushBack(4); + list.PushBack(5); + + ZArray<int> values1; + ZArray<int> values2; + + values1.PushBack(3); + values1.PushBack(5); + + values2.PushBack(6); + values2.PushBack(7); + + TASSERT( ZArrayAlgo::FindFirstOf(list, 3, 5, values1, 0, values1.Size()) == 4, "FindFirstOf() failed to find first element in correct position in region!\n"); + TASSERT( ZArrayAlgo::FindFirstOf(list, 2, 4, values2, 0, values2.Size()) ==ZSTL::InvalidPos, "FindFirstOf() found element not in region!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_FindFirstNot() +{ + ZArray<int> list; + ZArray<int> list2; + + list.PushBack(3); + list.PushBack(3); + list.PushBack(3); + list.PushBack(4); + list.PushBack(5); + + TASSERT( ZArrayAlgo::FindFirstNot(list, 3) == 3, "FindFirstNotOf() failed to find first element not of given type in correct position!\n"); + + list2.PushBack(3); + list2.PushBack(3); + list2.PushBack(3); + list2.PushBack(3); + list2.PushBack(3); + + TASSERT( ZArrayAlgo::FindFirstNot(list2, 3) == ZSTL::InvalidPos, "FindFirstNotOf() failed to find nonexistent nonelement nonoccurence\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_FindFirstNot_In_Region() +{ + ZArray<int> list; + ZArray<int> list2; + + list.PushBack(3); + list.PushBack(3); + list.PushBack(3); + list.PushBack(4); + list.PushBack(5); + + TASSERT( ZArrayAlgo::FindFirstNot(list, 3, 1, 4) == 3, "FindFirstNotOf() failed to find first element not of given type in correct position!\n"); + + list2.PushBack(3); + list2.PushBack(3); + list2.PushBack(3); + list2.PushBack(3); + list2.PushBack(3); + + TASSERT( ZArrayAlgo::FindFirstNot(list2, 3, 1, 4) == ZSTL::InvalidPos, "FindFirstNotOf() failed to find nonexistent nonelement nonoccurence\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_FindFirstNotOf() +{ + ZArray<int> list; + ZArray<int> list2; + + list.PushBack(3); + list.PushBack(3); + list.PushBack(3); + list.PushBack(4); + list.PushBack(5); + + ZArray<int> values1; + + values1.PushBack(3); + values1.PushBack(4); + + TASSERT( ZArrayAlgo::FindFirstNotOf(list, values1) == 4, "FindFirstNotOf() failed to find first element not of given type in correct position!\n"); + + list2.PushBack(3); + list2.PushBack(3); + list2.PushBack(3); + list2.PushBack(3); + list2.PushBack(3); + + TASSERT( ZArrayAlgo::FindFirstNotOf(list2, values1) == ZSTL::InvalidPos, "FindFirstNotOf() failed to find nonexistent nonelement nonoccurence\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_FindFirstNotOf_In_Region() +{ + ZArray<int> list; + ZArray<int> list2; + + list.PushBack(1); + list.PushBack(3); + list.PushBack(3); + list.PushBack(5); + list.PushBack(4); + + ZArray<int> values1; + + values1.PushBack(3); + values1.PushBack(4); + + TASSERT(ZArrayAlgo::FindFirstNotOf(list, 0, 4, values1, 0, values1.Size()) == 0, "FindFirstNotOf() failed to find first element not of given type in correct position in start region!"); + TASSERT(ZArrayAlgo::FindFirstNotOf(list, 1, 4, values1, 0, values1.Size()) == 3, "FindFirstNotOf() failed to find first element not of given type in correct position in end region!"); + + list2.PushBack(3); + list2.PushBack(2); + list2.PushBack(3); + list2.PushBack(3); + list2.PushBack(3); + + TASSERT(ZArrayAlgo::FindFirstNotOf(list2, 2, 4, values1, 0, values1.Size()) == ZSTL::InvalidPos, "FindFirstNotOf() failed to find nonexistent nonelement nonoccurence in region!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_FindLast() +{ + ZArray<int> list; + + list.PushBack(3); + list.PushBack(3); + list.PushBack(3); + list.PushBack(4); + list.PushBack(5); + + TASSERT( ZArrayAlgo::FindLast(list, 3) == 2, "FindLastOf() failed to find last element not of given type in correct position!\n"); + TASSERT( ZArrayAlgo::FindLast(list, 2) == ZSTL::InvalidPos, "FindLastOf() failed to find nonexistent nonelement nonoccurence\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_FindLast_In_Region() +{ + ZArray<int> list; + + list.PushBack(3); + list.PushBack(3); + list.PushBack(3); + list.PushBack(4); + list.PushBack(5); + list.PushBack(6); + + TASSERT( ZArrayAlgo::FindLast(list, 3, 1, 4) == 2, "FindLastOf() failed to find last element not of given type in correct position!\n"); + TASSERT( ZArrayAlgo::FindLast(list, 3, 3, 6) == ZSTL::InvalidPos, "FindLastOf() failed to find nonexistent nonelement nonoccurence\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_FindLastOf() +{ + ZArray<int> list; + + list.PushBack(3); + list.PushBack(3); + list.PushBack(3); + list.PushBack(4); + list.PushBack(5); + + ZArray<int> values1; + ZArray<int> values2; + + values1.PushBack(4); + values1.PushBack(3); + + values2.PushBack(1); + values2.PushBack(2); + + TASSERT( ZArrayAlgo::FindLastOf(list, values1) == 3, "FindLastOf() failed to find last element not of given type in correct position!\n"); + TASSERT( ZArrayAlgo::FindLastOf(list, values2) == ZSTL::InvalidPos, "FindLastOf() failed to find nonexistent nonelement nonoccurence\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_FindLastOf_In_Region() +{ + ZArray<int> list; + + list.PushBack(3); + list.PushBack(3); + list.PushBack(3); + list.PushBack(4); + list.PushBack(5); + + ZArray<int> values1; + ZArray<int> values2; + + values1.PushBack(4); + values1.PushBack(3); + + values2.PushBack(1); + values2.PushBack(2); + + TASSERT( ZArrayAlgo::FindLastOf(list, 1, 3, values1, 0, values1.Size()) == 2, "FindLastOf() failed to find last element not of given type in correct position in region!"); + TASSERT( ZArrayAlgo::FindLastOf(list, 2, 4, values2, 0, values2.Size()) == ZSTL::InvalidPos, "FindLastOf() failed to find nonexistent nonelement nonoccurence in region!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_FindLastNot() +{ + ZArray<int> list; + + list.PushBack(3); + list.PushBack(3); + list.PushBack(3); + list.PushBack(4); + list.PushBack(5); + list.PushBack(6); + list.PushBack(3); + list.PushBack(3); + list.PushBack(7); + list.PushBack(8); + list.PushBack(3); + + TASSERT( ZArrayAlgo::FindLastNot(list, 3) == 9, "FindLastNotOf() returned incorrect position!\n"); + TASSERT( ZArrayAlgo::FindLastNot(list, 11) == 10, "FindLastNotOf() returned incorrect position!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_FindLastNot_In_Region() +{ + ZArray<int> list; + + list.PushBack(3); + list.PushBack(3); + list.PushBack(3); + list.PushBack(4); + list.PushBack(5); + list.PushBack(6); + list.PushBack(3); + list.PushBack(3); + list.PushBack(7); + list.PushBack(8); + list.PushBack(3); + + TASSERT( ZArrayAlgo::FindLastNot(list, 3, 1, 7) == 5, "FindLastNotOf() returned incorrect position!\n"); + TASSERT( ZArrayAlgo::FindLastNot(list, 11, 1, 7) == 6, "FindLastNotOf() returned incorrect position!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_FindLastNotOf() +{ + ZArray<int> list; + + list.PushBack(3); + list.PushBack(3); + list.PushBack(3); + list.PushBack(4); + list.PushBack(5); + list.PushBack(6); + list.PushBack(3); + list.PushBack(3); + list.PushBack(7); + list.PushBack(8); + list.PushBack(3); + + ZArray<int> values1; + ZArray<int> values2; + + values1.PushBack(4); + values1.PushBack(3); + + values2.PushBack(1); + values2.PushBack(2); + + TASSERT( ZArrayAlgo::FindLastNotOf(list, values1) == 9, "FindLastNotOf() returned incorrect position!\n"); + TASSERT( ZArrayAlgo::FindLastNotOf(list, values2) == 10, "FindLastNotOf() returned incorrect position!\n"); + TASSERT( ZArrayAlgo::FindLastNotOf(list, list) == ZSTL::InvalidPos, "FindLastNotOf() returned incorrect position!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_FindLastNotOf_In_Region() +{ + ZArray<int> list; + + list.PushBack(3); + list.PushBack(3); + list.PushBack(3); + list.PushBack(4); + list.PushBack(5); + list.PushBack(6); + list.PushBack(3); + list.PushBack(3); + list.PushBack(7); + list.PushBack(8); + list.PushBack(3); + + ZArray<int> values1; + ZArray<int> values2; + + values1.PushBack(4); + values1.PushBack(3); + + values2.PushBack(1); + values2.PushBack(2); + + TASSERT( ZArrayAlgo::FindLastNotOf(list, 1, 7, values1, 0, values1.Size()) == 5, "FindLastNotOf() returned incorrect position!\n"); + TASSERT( ZArrayAlgo::FindLastNotOf(list, 1, 7, values2, 0, values2.Size()) == 6, "FindLastNotOf() returned incorrect position!\n"); + TASSERT( ZArrayAlgo::FindLastNotOf(list, 1, 7, list, 0, list.Size()) == ZSTL::InvalidPos, "FindLastNotOf() returned incorrect position!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_FindSub() +{ + ZArray<int> list; + + list.PushBack(3); + list.PushBack(3); + list.PushBack(3); + list.PushBack(4); + list.PushBack(5); + list.PushBack(6); + list.PushBack(3); + list.PushBack(3); + list.PushBack(7); + list.PushBack(8); + list.PushBack(3); + + ZArray<int> values1; + ZArray<int> values2; + + values1.PushBack(4); + values1.PushBack(5); + values1.PushBack(6); + + values2.PushBack(3); + values2.PushBack(3); + values2.PushBack(8); + + TASSERT( ZArrayAlgo::FindSub(list, values1) == 3, "FindSub() returned incorrect position!"); + TASSERT( ZArrayAlgo::FindSub(list, values2) == ZSTL::InvalidPos, "FindSub() failed to return invalid position with invalid sub array!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_FindSub_In_Region() +{ + ZArray<int> list; + + list.PushBack(3); + list.PushBack(3); + list.PushBack(3); + list.PushBack(4); + list.PushBack(5); + list.PushBack(6); + list.PushBack(3); + list.PushBack(3); + list.PushBack(7); + list.PushBack(8); + list.PushBack(3); + + ZArray<int> values1; + ZArray<int> values2; + + values1.PushBack(4); + values1.PushBack(5); + values1.PushBack(6); + + values2.PushBack(3); + values2.PushBack(3); + values2.PushBack(8); + + TASSERT( ZArrayAlgo::FindSub(list, 2, 6, values1, 0, values1.Size()) == 3, "FindSub() returned incorrect position in region!"); + TASSERT( ZArrayAlgo::FindSub(list, 2, 4, values1, 0, values1.Size()) == ZSTL::InvalidPos, "FindSub() returned valid position in region with invalid sub-array region!"); + TASSERT( ZArrayAlgo::FindSub(list, 2, 8, values1, 1, values1.Size()) == 4, "FindSub() returned incorrect position in region!"); + TASSERT( ZArrayAlgo::FindSub(list, 2, list.Size(), values2, 1, values2.Size()) == ZSTL::InvalidPos, "FindSub() failed to return invalid position with invalid sub array!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +class FoldLeftTestFunctor +{ +public: + FoldLeftTestFunctor() {} + ~FoldLeftTestFunctor() {} + + int operator () (const ArrayValueTestClass& _lhs, const ArrayValueTestClass& _rhs) const + { + if (_rhs.val > 3) + return _lhs.val + _rhs.val; + else + return _lhs.val; + } +}; + +static const char* test_FoldLeft() +{ + ZArray<int> list; + int ans; + + ZArray<ArrayValueTestClass> list2; + ArrayValueTestClass ans2; + + list.PushBack(1); + list.PushBack(2); + list.PushBack(3); + list.PushBack(4); + list.PushBack(5); + + ans = ZArrayAlgo::FoldLeft(list, FoldLeftTestFunctor(), 10); //only add values greater than 3 + TASSERT (ans == 19, "FoldLeft() failed to accumulate correctly!\n"); + + list2.PushBack(1); + list2.PushBack(2); + list2.PushBack(3); + list2.PushBack(4); + list2.PushBack(5); + + ans2 = ZArrayAlgo::FoldLeft(list2, FoldLeftTestFunctor(), ArrayValueTestClass(10)); //only add values greater than 3 + TASSERT (ans2.val == 19, "FoldLeft() failed to accumulate correctly!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_FoldLeft_Region() +{ + ZArray<int> list; + int ans; + + ZArray<ArrayValueTestClass> list2; + ArrayValueTestClass ans2; + + list.PushBack(1); + list.PushBack(2); + list.PushBack(3); + list.PushBack(4); + list.PushBack(5); + + ans = ZArrayAlgo::FoldLeft(list, FoldLeftTestFunctor(), 10, 1, 4); //only add values greater than 3 + TASSERT (ans == 14, "FoldLeft() failed to accumulate correctly in region!\n"); + + list2.PushBack(1); + list2.PushBack(2); + list2.PushBack(3); + list2.PushBack(4); + list2.PushBack(5); + + ans2 = ZArrayAlgo::FoldLeft(list2, FoldLeftTestFunctor(), ArrayValueTestClass(10), 1, 4); //only add values greater than 3 + TASSERT (ans2.val == 14, "FoldLeft() failed to accumulate correctly!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +class FoldRightTestFunctor +{ +public: + FoldRightTestFunctor() {} + ~FoldRightTestFunctor() {} + + int operator () (const int& _lhs, const int& _rhs) const + { + return _lhs - _rhs; + } +}; + +static const char* test_FoldRight() +{ + ZArray<int> list; + int ans; + + list.PushBack(1); + list.PushBack(2); + list.PushBack(3); + list.PushBack(4); + list.PushBack(5); + + ans = ZArrayAlgo::FoldLeft(list, FoldRightTestFunctor(), 10); + TASSERT(ans == -5, "FoldLeft() with subtraction operator returned incorrect value!"); + + ans = ZArrayAlgo::FoldRight(list, FoldRightTestFunctor(), 10); + TASSERT (ans == -7, "FoldRight() with subtraction operator returned incorrect value!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_FoldRight_Region() +{ + ZArray<int> list; + int ans; + + list.PushBack(1); + list.PushBack(2); + list.PushBack(3); + list.PushBack(4); + list.PushBack(5); + + ans = ZArrayAlgo::FoldLeft(list, FoldRightTestFunctor(), 10, 0, 4); + TASSERT(ans == 0, "FoldLeft() with subtraction operator returned incorrect value in region!"); + + ans = ZArrayAlgo::FoldRight(list, FoldRightTestFunctor(), 10, 1, 5); + TASSERT (ans == 8, "FoldRight() with subtraction operator returned incorrect value in region!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +struct GenerateTestFunctor +{ + int operator () ( size_t _index, size_t _count ) + { + return ((int)_count) - ((int)_index); + } +}; + +static const char* test_Generate() +{ + ZArray<int> list; + list.Resize(5); + ZArrayAlgo::Generate(list, GenerateTestFunctor()); + + TASSERT( list.Size() == 5, "Generate() changed size of list!\n"); + TASSERT( list.PopFront() == 5, "Generate() producted incorrect list!\n"); + TASSERT( list.PopFront() == 4, "Generate() producted incorrect list!\n"); + TASSERT( list.PopFront() == 3, "Generate() producted incorrect list!\n"); + TASSERT( list.PopFront() == 2, "Generate() producted incorrect list!\n"); + TASSERT( list.PopFront() == 1, "Generate() producted incorrect list!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Generate_In_Region() +{ + ZArray<int> list; + list.PushBack(9); + list.PushBack(9); + list.PushBack(9); + list.PushBack(9); + list.PushBack(9); + ZArrayAlgo::Generate(list, GenerateTestFunctor(), 1, 4); + + TASSERT( list.Size() == 5, "Generate() changed size of list!\n"); + TASSERT( list.PopFront() == 9, "Generate() producted incorrect list!\n"); + TASSERT( list.PopFront() == 3, "Generate() producted incorrect list!\n"); + TASSERT( list.PopFront() == 2, "Generate() producted incorrect list!\n"); + TASSERT( list.PopFront() == 1, "Generate() producted incorrect list!\n"); + TASSERT( list.PopFront() == 9, "Generate() producted incorrect list!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +struct MapTestFunctor { void operator() (int& _val) const { _val *= -1; } }; + +static const char* test_Map() +{ + ZArray<int> list; + ZArray<int> out; + list.PushBack(1); + list.PushBack(2); + list.PushBack(3); + list.PushBack(4); + list.PushBack(5); + + out = ZArrayAlgo::Map(list, MapTestFunctor()); + + TASSERT( list.Size() == 5, "Map() changed input array size!\n"); + TASSERT( list.PopFront() == 1, "Map() changed input array!\n"); + TASSERT( list.PopFront() == 2, "Map() changed input array!\n"); + TASSERT( list.PopFront() == 3, "Map() changed input array!\n"); + TASSERT( list.PopFront() == 4, "Map() changed input array!\n"); + TASSERT( list.PopFront() == 5, "Map() changed input array!\n"); + + TASSERT( out.Size() == 5, "Map() returned range of incorrect size!\n"); + TASSERT( out.PopFront() == -1, "Map() returned incorrect range!\n"); + TASSERT( out.PopFront() == -2, "Map() returned incorrect range!\n"); + TASSERT( out.PopFront() == -3, "Map() returned incorrect range!\n"); + TASSERT( out.PopFront() == -4, "Map() returned incorrect range!\n"); + TASSERT( out.PopFront() == -5, "Map() returned incorrect range!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Map_Region() +{ + ZArray<int> list; + ZArray<int> out; + list.PushBack(1); + list.PushBack(2); + list.PushBack(3); + list.PushBack(4); + list.PushBack(5); + + out = ZArrayAlgo::Map(list, MapTestFunctor(), 1, 4); + + TASSERT( list.Size() == 5, "Map() changed input array size!\n"); + TASSERT( list.PopFront() == 1, "Map() changed input array!\n"); + TASSERT( list.PopFront() == 2, "Map() changed input array!\n"); + TASSERT( list.PopFront() == 3, "Map() changed input array!\n"); + TASSERT( list.PopFront() == 4, "Map() changed input array!\n"); + TASSERT( list.PopFront() == 5, "Map() changed input array!\n"); + + TASSERT( out.Size() == 3, "Map() returned range of incorrect size!\n"); + TASSERT( out.PopFront() == -2, "Map() returned incorrect range!\n"); + TASSERT( out.PopFront() == -3, "Map() returned incorrect range!\n"); + TASSERT( out.PopFront() == -4, "Map() returned incorrect range!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Max() +{ + ZArray<int> list; + list.PushBack(1); + list.PushBack(2); + list.PushBack(5); + list.PushBack(4); + list.PushBack(2); + list.PushBack(7); + list.PushBack(3); + list.PushBack(0); + list.PushBack(5); + + ZArray<int> list2; + list2.PushBack(1); + list2.PushBack(2); + list2.PushBack(5); + list2.PushBack(5); + list2.PushBack(5); + list2.PushBack(4); + list2.PushBack(2); + + TASSERT( ZArrayAlgo::Max(list) == 5, "Max() failed to find max at expected place!\n"); + TASSERT( ZArrayAlgo::Max(list2) == 2, "Max() failed to find max at expected place for multiple max values!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Max_In_Region() +{ + ZArray<int> list; + list.PushBack(1); + list.PushBack(2); + list.PushBack(5); + list.PushBack(4); + list.PushBack(2); + list.PushBack(7); + list.PushBack(3); + list.PushBack(0); + list.PushBack(5); + + ZArray<int> list2; + list2.PushBack(1); + list2.PushBack(2); + list2.PushBack(5); + list2.PushBack(5); + list2.PushBack(5); + list2.PushBack(4); + list2.PushBack(2); + + TASSERT( ZArrayAlgo::Max(list, 3, 8 ) == 5, "Max() failed to find max at expected place!\n"); + TASSERT( ZArrayAlgo::Max(list2, 1, 6) == 2, "Max() failed to find max at expected place for multiple max values!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ +struct TestComparatorFunctor +{ + //operator overload which returns 1 if a < b, 0 if a == b, and -1 if a > b + //this basically means that this comparator returns the reverse of usual + int operator () (const int& _a, const int& _b) const + { + if (_a < _b) + { + return 1; + } + else if (_b < _a) + { + return -1; + } + else + { + return 0; + } + } +}; +static const char* test_Max_Comparator() +{ + ZArray<int> list; + list.PushBack(1); + list.PushBack(2); + list.PushBack(5); + list.PushBack(4); + list.PushBack(2); + list.PushBack(7); + list.PushBack(3); + list.PushBack(0); + list.PushBack(5); + + ZArray<int> list2; + list2.PushBack(4); + list2.PushBack(1); + list2.PushBack(2); + list2.PushBack(1); + list2.PushBack(1); + list2.PushBack(1); + list2.PushBack(4); + list2.PushBack(2); + + TASSERT( ZArrayAlgo::Max(list, TestComparatorFunctor()) == 7, "Max() failed to find max at expected place!\n"); + TASSERT( ZArrayAlgo::Max(list2, TestComparatorFunctor()) == 1, "Max() failed to find max at expected place for multiple max values!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Max_Comparator_In_Region() +{ + ZArray<int> list; + list.PushBack(1); + list.PushBack(2); + list.PushBack(5); + list.PushBack(4); + list.PushBack(2); + list.PushBack(7); + list.PushBack(3); + list.PushBack(0); + list.PushBack(5); + + ZArray<int> list2; + list2.PushBack(4); + list2.PushBack(1); + list2.PushBack(2); + list2.PushBack(1); + list2.PushBack(1); + list2.PushBack(1); + list2.PushBack(4); + list2.PushBack(2); + + TASSERT( ZArrayAlgo::Max(list, TestComparatorFunctor(), 0, 4) == 0, "Max() failed to find max at expected place in region!"); + TASSERT( ZArrayAlgo::Max(list2, TestComparatorFunctor(), 4, 6) == 4, "Max() failed to find max at expected place for multiple max values in region!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Min() +{ + ZArray<int> list; + list.PushBack(2); + list.PushBack(7); + list.PushBack(5); + list.PushBack(1); + list.PushBack(4); + list.PushBack(2); + list.PushBack(3); + list.PushBack(0); + list.PushBack(5); + + ZArray<int> list2; + list2.PushBack(3); + list2.PushBack(2); + list2.PushBack(3); + list2.PushBack(2); + list2.PushBack(1); + list2.PushBack(1); + list2.PushBack(1); + list2.PushBack(4); + list2.PushBack(2); + + TASSERT( ZArrayAlgo::Min(list) == 7, "Min() failed to find min at expected place!\n"); + TASSERT( ZArrayAlgo::Min(list2) == 4, "Min() failed to find min at expected place for multiple max values!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Min_In_Region() +{ + ZArray<int> list; + list.PushBack(2); + list.PushBack(7); + list.PushBack(5); + list.PushBack(1); + list.PushBack(4); + list.PushBack(2); + list.PushBack(3); + list.PushBack(0); + list.PushBack(5); + + ZArray<int> list2; + list2.PushBack(3); + list2.PushBack(2); + list2.PushBack(3); + list2.PushBack(2); + list2.PushBack(1); + list2.PushBack(1); + list2.PushBack(1); + list2.PushBack(4); + list2.PushBack(2); + + TASSERT( ZArrayAlgo::Min(list, 1, 6) == 3, "Min() failed to find min at expected place!\n"); + TASSERT( ZArrayAlgo::Min(list2, 3, 7) == 4, "Min() failed to find min at expected place for multiple max values!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Min_Comparator() +{ + ZArray<int> list; + list.PushBack(2); + list.PushBack(7); + list.PushBack(5); + list.PushBack(1); + list.PushBack(4); + list.PushBack(2); + list.PushBack(3); + list.PushBack(0); + list.PushBack(5); + + ZArray<int> list2; + list2.PushBack(3); + list2.PushBack(2); + list2.PushBack(3); + list2.PushBack(2); + list2.PushBack(1); + list2.PushBack(1); + list2.PushBack(1); + list2.PushBack(4); + list2.PushBack(2); + + TASSERT( ZArrayAlgo::Min(list, TestComparatorFunctor()) == 1, "Min() failed to find min at expected place!\n"); + TASSERT( ZArrayAlgo::Min(list2, TestComparatorFunctor()) == 7, "Min() failed to find min at expected place for multiple max values!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Min_Comparator_In_Region() +{ + ZArray<int> list; + list.PushBack(2); + list.PushBack(7); + list.PushBack(5); + list.PushBack(1); + list.PushBack(4); + list.PushBack(2); + list.PushBack(3); + list.PushBack(0); + list.PushBack(5); + + ZArray<int> list2; + list2.PushBack(3); + list2.PushBack(2); + list2.PushBack(3); + list2.PushBack(2); + list2.PushBack(4); + list2.PushBack(4); + list2.PushBack(4); + list2.PushBack(4); + list2.PushBack(2); + + TASSERT( ZArrayAlgo::Min(list, TestComparatorFunctor(), 2, 6) == 2, "Min() failed to find min at expected place in region!"); + TASSERT( ZArrayAlgo::Min(list2, TestComparatorFunctor(), 0, 4) == 0, "Min() failed to find min at expected place for multiple max values in region!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Remove() +{ + ZArray<int> list; + + list.PushBack(1); + list.PushBack(2); + list.PushBack(2); + list.PushBack(2); + list.PushBack(3); + list.PushBack(4); + list.PushBack(5); + + TASSERT(ZArrayAlgo::Remove(list, 8) == ZSTL::InvalidPos, "Remove() did not take out element at correct position!\n"); + TASSERT(list.Size() == 7, "Remove() did not change list size correctly!\n"); + TASSERT(ZArrayAlgo::Remove(list, 2) == 1, "Remove() did not take out element at correct position!\n"); + TASSERT(list.Size() == 6, "Remove() did not change list size correctly!\n"); + TASSERT(ZArrayAlgo::Remove(list, 5) == 5, "Remove() did not take out element at correct position!\n"); + TASSERT(list.Size() == 5, "Remove() did not change list size correctly!\n"); + TASSERT(ZArrayAlgo::Remove(list, 1) == 0, "Remove() did not take out element at correct position!\n"); + TASSERT(list.Size() == 4, "Remove() did not change list size correctly!\n"); + + TASSERT( list.PopFront() == 2, "Remove() created incorrect list!\n"); + TASSERT( list.PopFront() == 2, "Remove() created incorrect list!\n"); + TASSERT( list.PopFront() == 3, "Remove() created incorrect list!\n"); + TASSERT( list.PopFront() == 4, "Remove() created incorrect list!\n"); + TASSERT( list.Empty(), "Remove() created incorrectly sized list!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Remove_In_Region() +{ + ZArray<int> list; + + list.PushBack(1); + list.PushBack(2); + list.PushBack(2); + list.PushBack(2); + list.PushBack(3); + list.PushBack(4); + list.PushBack(5); + + TASSERT(ZArrayAlgo::Remove(list, 8, 1, 6 ) == ZSTL::InvalidPos, "Remove() did not take out element at correct position!\n"); + TASSERT(list.Size() == 7, "Remove() did not change list size correctly!\n"); + TASSERT(ZArrayAlgo::Remove(list, 2, 1, 6 ) == 1, "Remove() did not take out element at correct position!\n"); + TASSERT(list.Size() == 6, "Remove() did not change list size correctly!\n"); + TASSERT(ZArrayAlgo::Remove(list, 5, 1, 6 ) == 5, "Remove() did not take out element at correct position!\n"); + TASSERT(list.Size() == 5, "Remove() did not change list size correctly!\n"); + TASSERT(ZArrayAlgo::Remove(list, 1, 1, 5 ) == ZSTL::InvalidPos, "Remove() took out an element at the wrong place!\n"); + TASSERT(list.Size() == 5, "Remove() changed list size correctly!\n"); + + TASSERT( list.PopFront() == 1, "Remove() created incorrect list!\n"); + TASSERT( list.PopFront() == 2, "Remove() created incorrect list!\n"); + TASSERT( list.PopFront() == 2, "Remove() created incorrect list!\n"); + TASSERT( list.PopFront() == 3, "Remove() created incorrect list!\n"); + TASSERT( list.PopFront() == 4, "Remove() created incorrect list!\n"); + TASSERT( list.Empty(), "Remove() created incorrectly sized list!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_RemoveAll() +{ + ZArray<int> list; + + list.PushBack(1); + list.PushBack(2); + list.PushBack(2); + list.PushBack(2); + list.PushBack(3); + list.PushBack(4); + list.PushBack(5); + + TASSERT( ZArrayAlgo::RemoveAll(list, 2) == 3, "RemoveAll() claims wrong number of removals!\n"); + TASSERT( list.Size() == 4, "RemoveAll() failed to remove all elements of supplied value!\n"); + TASSERT( list.PopFront() == 1, "RemoveAll() corrupted list!\n"); + TASSERT( list.PopFront() == 3, "RemoveAll() corrupted list!\n"); + TASSERT( list.PopFront() == 4, "RemoveAll() corrupted list!\n"); + TASSERT( list.PopFront() == 5, "RemoveAll() corrupted list!\n"); + TASSERT( list.Empty(), "RemoveAll() corrupted list!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_RemoveAll_In_Region() +{ + ZArray<int> list; + + list.PushBack(1); + list.PushBack(2); + list.PushBack(2); + list.PushBack(2); + list.PushBack(3); + list.PushBack(4); + list.PushBack(5); + + TASSERT( ZArrayAlgo::RemoveAll(list, 2, 2,7 ) == 2, "RemoveAll() claims wrong number of removals!\n"); + TASSERT( list.Size() == 5, "RemoveAll() failed to remove all elements of supplied value!\n"); + TASSERT( list.PopFront() == 1, "RemoveAll() corrupted list!\n"); + TASSERT( list.PopFront() == 2, "RemoveAll() corrupted list!\n"); + TASSERT( list.PopFront() == 3, "RemoveAll() corrupted list!\n"); + TASSERT( list.PopFront() == 4, "RemoveAll() corrupted list!\n"); + TASSERT( list.PopFront() == 5, "RemoveAll() corrupted list!\n"); + TASSERT( list.Empty(), "RemoveAll() corrupted list!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ +// returns true if given odd number +struct RemoveIfTestFunctor{ bool operator()(int _val) { return (_val%2) == 1;}}; + +static const char* test_RemoveIf() +{ + ZArray<int> list; + + list.PushBack(1); + list.PushBack(2); + list.PushBack(2); + list.PushBack(2); + list.PushBack(3); + list.PushBack(4); + list.PushBack(5); + + TASSERT( ZArrayAlgo::RemoveIf(list,RemoveIfTestFunctor()) == 3, "RemoveIf() claims wrong number of removals!\n"); + TASSERT( list.Size() == 4, "RemoveIf() failed to remove all elements of supplied value!\n"); + TASSERT( list.PopFront() == 2, "RemoveIf() corrupted list!\n"); + TASSERT( list.PopFront() == 2, "RemoveIf() corrupted list!\n"); + TASSERT( list.PopFront() == 2, "RemoveIf() corrupted list!\n"); + TASSERT( list.PopFront() == 4, "RemoveIf() corrupted list!\n"); + TASSERT( list.Empty(), "RemoveIf() corrupted list!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_RemoveIf_In_Region() +{ + ZArray<int> list; + + list.PushBack(1); + list.PushBack(2); + list.PushBack(2); + list.PushBack(2); + list.PushBack(3); + list.PushBack(4); + list.PushBack(5); + + TASSERT( ZArrayAlgo::RemoveIf(list,RemoveIfTestFunctor(), 1, 5) == 1, "RemoveIf() claims wrong number of removals!\n"); + TASSERT( list.Size() == 6, "RemoveIf() failed to remove all elements of supplied value!\n"); + TASSERT( list.PopFront() == 1, "RemoveIf() corrupted list!\n"); + TASSERT( list.PopFront() == 2, "RemoveIf() corrupted list!\n"); + TASSERT( list.PopFront() == 2, "RemoveIf() corrupted list!\n"); + TASSERT( list.PopFront() == 2, "RemoveIf() corrupted list!\n"); + TASSERT( list.PopFront() == 4, "RemoveIf() corrupted list!\n"); + TASSERT( list.PopFront() == 5, "RemoveIf() corrupted list!\n"); + TASSERT( list.Empty(), "RemoveIf() corrupted list!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_RemoveUpTo() +{ + ZArray<int> list; + + list.PushBack(1); + list.PushBack(2); + list.PushBack(2); + list.PushBack(2); + list.PushBack(3); + list.PushBack(4); + list.PushBack(5); + + TASSERT( ZArrayAlgo::RemoveUpTo(list, 2, 2) == 2, "RemoveUpTo() claims incorrect number of removals!\n"); + TASSERT( list.Size() == 5, "RemoveUpTo() resized list to incorrect size!\n"); + TASSERT( list.At(0) == 1, "RemoveUpTo() corrupted list!\n"); + TASSERT( list.At(1) == 2, "RemoveUpTo() corrupted list!\n"); + TASSERT( list.At(2) == 3, "RemoveUpTo() corrupted list!\n"); + TASSERT( list.At(3) == 4, "RemoveUpTo() corrupted list!\n"); + TASSERT( list.At(4) == 5, "RemoveUpTo() corrupted list!\n"); + + TASSERT( ZArrayAlgo::RemoveUpTo(list, 3, 12) == 1, "RemoveUpTo() claims incorrect number of removals!\n"); + TASSERT( list.Size() == 4, "RemoveUpTo() resized list to incorrect size!\n"); + TASSERT( list.At(0) == 1, "RemoveUpTo() corrupted list!\n"); + TASSERT( list.At(1) == 2, "RemoveUpTo() corrupted list!\n"); + TASSERT( list.At(2) == 4, "RemoveUpTo() corrupted list!\n"); + TASSERT( list.At(3) == 5, "RemoveUpTo() corrupted list!\n"); + + TASSERT( ZArrayAlgo::RemoveUpTo(list, 1337, 12) == 0, "RemoveUpTo() claims incorrect number of removals!\n"); + TASSERT( list.Size() == 4, "RemoveUpTo() resized list to incorrect size!\n"); + TASSERT( list.At(0) == 1, "RemoveUpTo() corrupted list!\n"); + TASSERT( list.At(1) == 2, "RemoveUpTo() corrupted list!\n"); + TASSERT( list.At(2) == 4, "RemoveUpTo() corrupted list!\n"); + TASSERT( list.At(3) == 5, "RemoveUpTo() corrupted list!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_RemoveUpTo_In_Region() +{ + ZArray<int> list; + + list.PushBack(2); + list.PushBack(2); + list.PushBack(1); + list.PushBack(2); + list.PushBack(2); + list.PushBack(2); + list.PushBack(3); + list.PushBack(4); + list.PushBack(5); + + TASSERT( ZArrayAlgo::RemoveUpTo(list, 2, 2, 2, 9) == 2, "RemoveUpTo() claims incorrect number of removals!\n"); + TASSERT( list.Size() == 7, "RemoveUpTo() resized list to incorrect size!\n"); + TASSERT( list.At(0) == 2, "RemoveUpTo() corrupted list!\n"); + TASSERT( list.At(1) == 2, "RemoveUpTo() corrupted list!\n"); + TASSERT( list.At(2) == 1, "RemoveUpTo() corrupted list!\n"); + TASSERT( list.At(3) == 2, "RemoveUpTo() corrupted list!\n"); + TASSERT( list.At(4) == 3, "RemoveUpTo() corrupted list!\n"); + TASSERT( list.At(5) == 4, "RemoveUpTo() corrupted list!\n"); + TASSERT( list.At(6) == 5, "RemoveUpTo() corrupted list!\n"); + + TASSERT( ZArrayAlgo::RemoveUpTo(list, 3, 12, 2, 7) == 1, "RemoveUpTo() claims incorrect number of removals!\n"); + TASSERT( list.Size() == 6, "RemoveUpTo() resized list to incorrect size!\n"); + TASSERT( list.At(0) == 2, "RemoveUpTo() corrupted list!\n"); + TASSERT( list.At(1) == 2, "RemoveUpTo() corrupted list!\n"); + TASSERT( list.At(2) == 1, "RemoveUpTo() corrupted list!\n"); + TASSERT( list.At(3) == 2, "RemoveUpTo() corrupted list!\n"); + TASSERT( list.At(4) == 4, "RemoveUpTo() corrupted list!\n"); + TASSERT( list.At(5) == 5, "RemoveUpTo() corrupted list!\n"); + + TASSERT( ZArrayAlgo::RemoveUpTo(list, 1337, 12, 2, 6) == 0, "RemoveUpTo() claims incorrect number of removals!\n"); + TASSERT( list.Size() == 6, "RemoveUpTo() resized list to incorrect size!\n"); + TASSERT( list.At(0) == 2, "RemoveUpTo() corrupted list!\n"); + TASSERT( list.At(1) == 2, "RemoveUpTo() corrupted list!\n"); + TASSERT( list.At(2) == 1, "RemoveUpTo() corrupted list!\n"); + TASSERT( list.At(3) == 2, "RemoveUpTo() corrupted list!\n"); + TASSERT( list.At(4) == 4, "RemoveUpTo() corrupted list!\n"); + TASSERT( list.At(5) == 5, "RemoveUpTo() corrupted list!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Replace() +{ + ZArray<int> list; + + list.PushBack(2); + list.PushBack(2); + list.PushBack(1); + list.PushBack(2); + list.PushBack(2); + list.PushBack(2); + list.PushBack(3); + list.PushBack(4); + list.PushBack(5); + + TASSERT( ZArrayAlgo::Replace(list, 2, 42) == 5, "Replace() claims wrong number of replacements!\n"); + TASSERT( list.Size() == 9, "Replace() changed size of list!\n"); + TASSERT( list.PopFront() == 42, "Replace() did not replace element correctly!\n"); + TASSERT( list.PopFront() == 42, "Replace() did not replace element correctly!\n"); + TASSERT( list.PopFront() == 1, "Replace() did not replace element correctly!\n"); + TASSERT( list.PopFront() == 42, "Replace() did not replace element correctly!\n"); + TASSERT( list.PopFront() == 42, "Replace() did not replace element correctly!\n"); + TASSERT( list.PopFront() == 42, "Replace() did not replace element correctly!\n"); + TASSERT( list.PopFront() == 3, "Replace() did not replace element correctly!\n"); + TASSERT( list.PopFront() == 4, "Replace() did not replace element correctly!\n"); + TASSERT( list.PopFront() == 5, "Replace() did not replace element correctly!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Replace_In_Region() +{ + ZArray<int> list; + + list.PushBack(2); + list.PushBack(2); + list.PushBack(1); + list.PushBack(2); + list.PushBack(2); + list.PushBack(2); + list.PushBack(3); + list.PushBack(4); + list.PushBack(5); + + TASSERT( ZArrayAlgo::Replace(list, 2, 42, 2, 9) == 3, "Replace() claims wrong number of replacements!\n"); + TASSERT( list.Size() == 9, "Replace() changed size of list!\n"); + TASSERT( list.PopFront() == 2, "Replace() did not replace element correctly!\n"); + TASSERT( list.PopFront() == 2, "Replace() did not replace element correctly!\n"); + TASSERT( list.PopFront() == 1, "Replace() did not replace element correctly!\n"); + TASSERT( list.PopFront() == 42, "Replace() did not replace element correctly!\n"); + TASSERT( list.PopFront() == 42, "Replace() did not replace element correctly!\n"); + TASSERT( list.PopFront() == 42, "Replace() did not replace element correctly!\n"); + TASSERT( list.PopFront() == 3, "Replace() did not replace element correctly!\n"); + TASSERT( list.PopFront() == 4, "Replace() did not replace element correctly!\n"); + TASSERT( list.PopFront() == 5, "Replace() did not replace element correctly!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +// returns true if given odd number +struct ReplaceIfTestFunctor{ bool operator ()(int _val){ return (_val%2) == 1;} }; + +static const char* test_ReplaceIf() +{ + ZArray<int> list; + + list.PushBack(1); + list.PushBack(2); + list.PushBack(3); + list.PushBack(4); + list.PushBack(5); + list.PushBack(6); + + TASSERT( ZArrayAlgo::ReplaceIf(list, ReplaceIfTestFunctor(), 42) == 3, "ReplaceIf() claims wrong number of replacements!\n"); + TASSERT( list.Size() == 6, "ReplaceIf() changed size of list!\n"); + TASSERT( list.PopFront() == 42, "ReplaceIf() corrupted list!\n"); + TASSERT( list.PopFront() == 2, "ReplaceIf() corrupted list!\n"); + TASSERT( list.PopFront() == 42, "ReplaceIf() corrupted list!\n"); + TASSERT( list.PopFront() == 4, "ReplaceIf() corrupted list!\n"); + TASSERT( list.PopFront() == 42, "ReplaceIf() corrupted list!\n"); + TASSERT( list.PopFront() == 6, "ReplaceIf() corrupted list!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_ReplaceIf_In_Region() +{ + ZArray<int> list; + + list.PushBack(1); + list.PushBack(2); + list.PushBack(3); + list.PushBack(4); + list.PushBack(5); + list.PushBack(6); + + TASSERT( ZArrayAlgo::ReplaceIf(list, ReplaceIfTestFunctor(), 42, 1, 3) == 1, "ReplaceIf() claims wrong number of replacements!\n"); + TASSERT( list.Size() == 6, "ReplaceIf() changed size of list!\n"); + TASSERT( list.PopFront() == 1, "ReplaceIf() corrupted list!\n"); + TASSERT( list.PopFront() == 2, "ReplaceIf() corrupted list!\n"); + TASSERT( list.PopFront() == 42, "ReplaceIf() corrupted list!\n"); + TASSERT( list.PopFront() == 4, "ReplaceIf() corrupted list!\n"); + TASSERT( list.PopFront() == 5, "ReplaceIf() corrupted list!\n"); + TASSERT( list.PopFront() == 6, "ReplaceIf() corrupted list!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Reverse() +{ + ZArray<int> list; + + list.PushBack(1); + list.PushBack(2); + list.PushBack(3); + list.PushBack(4); + list.PushBack(5); + list.PushBack(6); + + ZArrayAlgo::Reverse(list); + TASSERT( list.Size() == 6, "Reverse() changed size of list!\n"); + TASSERT( list.PopFront() == 6, "Reverse() corrupted list!\n"); + TASSERT( list.PopFront() == 5, "Reverse() corrupted list!\n"); + TASSERT( list.PopFront() == 4, "Reverse() corrupted list!\n"); + TASSERT( list.PopFront() == 3, "Reverse() corrupted list!\n"); + TASSERT( list.PopFront() == 2, "Reverse() corrupted list!\n"); + TASSERT( list.PopFront() == 1, "Reverse() corrupted list!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Reverse_Region() +{ + ZArray<int> list; + + list.PushBack(1); + list.PushBack(2); + list.PushBack(3); + list.PushBack(4); + list.PushBack(5); + list.PushBack(6); + + // test reverse on same element + ZArrayAlgo::Reverse(list,0,0); + ZArrayAlgo::Reverse(list,3,3); + TASSERT( list.Size() == 6, "Reverse() changed size of list!\n"); + TASSERT( list.At(0) == 1, "Reverse() corrupted list!\n"); + TASSERT( list.At(1) == 2, "Reverse() corrupted list!\n"); + TASSERT( list.At(2) == 3, "Reverse() corrupted list!\n"); + TASSERT( list.At(3) == 4, "Reverse() corrupted list!\n"); + TASSERT( list.At(4) == 5, "Reverse() corrupted list!\n"); + TASSERT( list.At(5) == 6, "Reverse() corrupted list!\n"); + + // okay, real test + ZArrayAlgo::Reverse(list,2,5); + TASSERT( list.Size() == 6, "Reverse() changed size of list!\n"); + TASSERT( list.PopFront() == 1, "Reverse() corrupted list!\n"); + TASSERT( list.PopFront() == 2, "Reverse() corrupted list!\n"); + TASSERT( list.PopFront() == 5, "Reverse() corrupted list!\n"); + TASSERT( list.PopFront() == 4, "Reverse() corrupted list!\n"); + TASSERT( list.PopFront() == 3, "Reverse() corrupted list!\n"); + TASSERT( list.PopFront() == 6, "Reverse() corrupted list!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Rotate() +{ + ZArray<int> list; + list.PushBack(1); + list.PushBack(2); + list.PushBack(3); + list.PushBack(4); + list.PushBack(5); + list.PushBack(6); + + // test rotate at front + ZArrayAlgo::Rotate(list, 0); + TASSERT( list.Size() == 6, "Rotate() changed length of array!\n"); + TASSERT( list.PopFront() == 1, "Rotate() misordered list!\n"); + TASSERT( list.PopFront() == 2, "Rotate() misordered list!\n"); + TASSERT( list.PopFront() == 3, "Rotate() misordered list!\n"); + TASSERT( list.PopFront() == 4, "Rotate() misordered list!\n"); + TASSERT( list.PopFront() == 5, "Rotate() misordered list!\n"); + TASSERT( list.PopFront() == 6, "Rotate() misordered list!\n"); + + // test rotate at middle + list.PushBack(1); + list.PushBack(2); + list.PushBack(3); + list.PushBack(4); + list.PushBack(5); + list.PushBack(6); + ZArrayAlgo::Rotate(list, 3); + TASSERT( list.Size() == 6, "Rotate() changed length of array!\n"); + TASSERT( list.PopFront() == 4, "Rotate() misordered list!\n"); + TASSERT( list.PopFront() == 5, "Rotate() misordered list!\n"); + TASSERT( list.PopFront() == 6, "Rotate() misordered list!\n"); + TASSERT( list.PopFront() == 1, "Rotate() misordered list!\n"); + TASSERT( list.PopFront() == 2, "Rotate() misordered list!\n"); + TASSERT( list.PopFront() == 3, "Rotate() misordered list!\n"); + + // test pivot back + list.PushBack(1); + list.PushBack(2); + list.PushBack(3); + list.PushBack(4); + list.PushBack(5); + list.PushBack(6); + ZArrayAlgo::Rotate(list, 5); + TASSERT( list.Size() == 6, "Rotate() changed length of array!\n"); + TASSERT( list.PopFront() == 6, "Rotate() misordered list!\n"); + TASSERT( list.PopFront() == 1, "Rotate() misordered list!\n"); + TASSERT( list.PopFront() == 2, "Rotate() misordered list!\n"); + TASSERT( list.PopFront() == 3, "Rotate() misordered list!\n"); + TASSERT( list.PopFront() == 4, "Rotate() misordered list!\n"); + TASSERT( list.PopFront() == 5, "Rotate() misordered list!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Rotate_Region() +{ + ZArray<int> list; + list.PushBack(1); + list.PushBack(2); + list.PushBack(3); + list.PushBack(4); + list.PushBack(5); + list.PushBack(6); + + // test rotate at front + ZArrayAlgo::Rotate(list, 1, 0, 3); + TASSERT( list.Size() == 6, "Rotate() changed length of array!\n"); + TASSERT( list.PopFront() == 2, "Rotate() misordered list!\n"); + TASSERT( list.PopFront() == 3, "Rotate() misordered list!\n"); + TASSERT( list.PopFront() == 1, "Rotate() misordered list!\n"); + TASSERT( list.PopFront() == 4, "Rotate() misordered list!\n"); + TASSERT( list.PopFront() == 5, "Rotate() misordered list!\n"); + TASSERT( list.PopFront() == 6, "Rotate() misordered list!\n"); + + // test rotate at middle + list.PushBack(1); //0 + list.PushBack(2); //1 + list.PushBack(3); //2 = + list.PushBack(4); //3 | < + list.PushBack(5); //4 = + list.PushBack(6); //5 + ZArrayAlgo::Rotate(list, 3, 2, 5); + TASSERT( list.Size() == 6, "Rotate() changed length of array!\n"); + TASSERT( list.PopFront() == 1, "Rotate() misordered list!\n"); + TASSERT( list.PopFront() == 2, "Rotate() misordered list!\n"); + TASSERT( list.PopFront() == 4, "Rotate() misordered list!\n"); + TASSERT( list.PopFront() == 5, "Rotate() misordered list!\n"); + TASSERT( list.PopFront() == 3, "Rotate() misordered list!\n"); + TASSERT( list.PopFront() == 6, "Rotate() misordered list!\n"); + + // test pivot back + list.PushBack(1); //0 + list.PushBack(2); //1 + list.PushBack(3); //2 + list.PushBack(4); //3 = + list.PushBack(5); //4 | + list.PushBack(6); //5 = < + ZArrayAlgo::Rotate(list, 5, 3, 6); + TASSERT( list.Size() == 6, "Rotate() changed length of array!\n"); + TASSERT( list.PopFront() == 1, "Rotate() misordered list!\n"); + TASSERT( list.PopFront() == 2, "Rotate() misordered list!\n"); + TASSERT( list.PopFront() == 3, "Rotate() misordered list!\n"); + TASSERT( list.PopFront() == 6, "Rotate() misordered list!\n"); + TASSERT( list.PopFront() == 4, "Rotate() misordered list!\n"); + TASSERT( list.PopFront() == 5, "Rotate() misordered list!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_SetIntersection() +{ + ZArray<int> list; + list.PushBack(1); + list.PushBack(2); + list.PushBack(3); + list.PushBack(4); + + ZArray<int> list2; + list2.PushBack(2); + list2.PushBack(3); + list2.PushBack(4); + list2.PushBack(5); + + ZArray<int> intersection = ZArrayAlgo::SetIntersection(list, list2); + TASSERT( intersection.Size() == 3, "SetIntersection() created wrong size intersection set\n"); + TASSERT( intersection.PopFront() == 2, "SetIntersection() produced wrong value!\n"); + TASSERT( intersection.PopFront() == 3, "SetIntersection() produced wrong value!\n"); + TASSERT( intersection.PopFront() == 4, "SetIntersection() produced wrong value!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_SetIntersection_In_Region() +{ + ZArray<int> list; + list.PushBack(1); // 0 + list.PushBack(2); // 1 = + list.PushBack(3); // 2 | + list.PushBack(4); // 3 | + list.PushBack(5); // 4 | + list.PushBack(6); // 5 = + list.PushBack(7); // 6 + + ZArray<int> list2; + list2.PushBack(1); // 0 + list2.PushBack(2); // 1 + list2.PushBack(3); // 2 + list2.PushBack(4); // 3 = + list2.PushBack(5); // 4 | + list2.PushBack(6); // 5 | + list2.PushBack(7); // 6 = + + ZArray<int> intersection = ZArrayAlgo::SetIntersection(list, 1, 6, list2, 3, 7); + TASSERT( intersection.Size() == 3, "SetIntersection() created wrong size intersection set\n"); + TASSERT( intersection.PopFront() == 4, "SetIntersection() produced wrong value!\n"); + TASSERT( intersection.PopFront() == 5, "SetIntersection() produced wrong value!\n"); + TASSERT( intersection.PopFront() == 6, "SetIntersection() produced wrong value!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_SetUnion() +{ + ZArray<int> list; + list.PushBack(1); // 0 + list.PushBack(2); // 1 = + list.PushBack(3); // 2 | + list.PushBack(4); // 3 | + list.PushBack(5); // 4 | + + ZArray<int> list2; + list2.PushBack(1); // 0 + list2.PushBack(2); // 1 + list2.PushBack(3); // 2 + + ZArray<int> list3; + list3.PushBack(3); // 0 + list3.PushBack(4); // 1 + list3.PushBack(5); // 2 + + ZArray<int> same = ZArrayAlgo::SetUnion(list,list2); + TASSERT(same.Size() == 5, "SetUnion() created wrong sized list!\n"); + TASSERT(same.PopFront() == 1, "SetUnion() created wrong list!\n"); + TASSERT(same.PopFront() == 2, "SetUnion() created wrong list!\n"); + TASSERT(same.PopFront() == 3, "SetUnion() created wrong list!\n"); + TASSERT(same.PopFront() == 4, "SetUnion() created wrong list!\n"); + TASSERT(same.PopFront() == 5, "SetUnion() created wrong list!\n"); + + ZArray<int> diff = ZArrayAlgo::SetUnion(list2,list3); + TASSERT(diff.Size() == 5, "SetUnion() created wrong sized list!\n"); + TASSERT(diff.PopFront() == 1, "SetUnion() created wrong list!\n"); + TASSERT(diff.PopFront() == 2, "SetUnion() created wrong list!\n"); + TASSERT(diff.PopFront() == 3, "SetUnion() created wrong list!\n"); + TASSERT(diff.PopFront() == 4, "SetUnion() created wrong list!\n"); + TASSERT(diff.PopFront() == 5, "SetUnion() created wrong list!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_SetUnion_In_Region() +{ + ZArray<int> list; + list.PushBack(1); // 0 + list.PushBack(2); // 1 = + list.PushBack(3); // 2 | + list.PushBack(4); // 3 | + list.PushBack(5); // 4 = + list.PushBack(6); // 5 + list.PushBack(7); // 6 + + ZArray<int> list2; + list2.PushBack(1); // 0 + list2.PushBack(2); // 1 + list2.PushBack(3); // 2 + list2.PushBack(4); // 3 = + list2.PushBack(5); // 4 | + list2.PushBack(6); // 5 | + list2.PushBack(7); // 6 = + + ZArray<int> diff = ZArrayAlgo::SetUnion(list,1,4,list2,3,6); + TASSERT(diff.Size() == 5, "SetUnion() created wrong sized list!\n"); + TASSERT(diff.PopFront() == 2, "SetUnion() created wrong list!\n"); + TASSERT(diff.PopFront() == 3, "SetUnion() created wrong list!\n"); + TASSERT(diff.PopFront() == 4, "SetUnion() created wrong list!\n"); + TASSERT(diff.PopFront() == 5, "SetUnion() created wrong list!\n"); + TASSERT(diff.PopFront() == 6, "SetUnion() created wrong list!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Slice() +{ + ZArray<int> list; + ZArray<int> list2; + + list.PushBack(1); + list.PushBack(2); + list.PushBack(3); + list.PushBack(4); + list.PushBack(5); + + list2 = ZArrayAlgo::Slice(list,1,3); + + TASSERT( list.Size() == 3, "Slice() removed the wrong number of elements!\n"); + TASSERT( list.PopFront() == 1, "Slice() produced incorrect mutated list!\n"); + TASSERT( list.PopFront() == 4, "Slice() produced incorrect mutated list!\n"); + TASSERT( list.PopFront() == 5, "Slice() produced incorrect mutated list!\n"); + + TASSERT( list2.PopFront() == 2, "Slice() produced incorrect excise list!\n"); + TASSERT( list2.PopFront() == 3, "Slice() produced incorrect excise list!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Sort() +{ + ZArray<int> list; + + list.PushBack(4); + list.PushBack(1); + list.PushBack(3); + list.PushBack(6); + list.PushBack(7); + list.PushBack(2); + list.PushBack(5); + + ZArrayAlgo::Sort(list); + TASSERT(list.Size() == 7, "Sort() changed array size!\n"); + TASSERT(list.PopFront() == 1, "Sort() didn't sort list properly!\n"); + TASSERT(list.PopFront() == 2, "Sort() didn't sort list properly!\n"); + TASSERT(list.PopFront() == 3, "Sort() didn't sort list properly!\n"); + TASSERT(list.PopFront() == 4, "Sort() didn't sort list properly!\n"); + TASSERT(list.PopFront() == 5, "Sort() didn't sort list properly!\n"); + TASSERT(list.PopFront() == 6, "Sort() didn't sort list properly!\n"); + TASSERT(list.PopFront() == 7, "Sort() didn't sort list properly!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Sort_Region() +{ + ZArray<int> list; + + list.PushBack(4); + list.PushBack(1); + list.PushBack(3); + list.PushBack(6); + list.PushBack(7); + list.PushBack(2); + list.PushBack(5); + + ZArrayAlgo::Sort(list,2,6); + TASSERT(list.Size() == 7, "Sort() changed array size!\n"); + TASSERT(list.PopFront() == 4, "Sort() didn't sort list properly!\n"); + TASSERT(list.PopFront() == 1, "Sort() didn't sort list properly!\n"); + TASSERT(list.PopFront() == 2, "Sort() didn't sort list properly!\n"); + TASSERT(list.PopFront() == 3, "Sort() didn't sort list properly!\n"); + TASSERT(list.PopFront() == 6, "Sort() didn't sort list properly!\n"); + TASSERT(list.PopFront() == 7, "Sort() didn't sort list properly!\n"); + TASSERT(list.PopFront() == 5, "Sort() didn't sort list properly!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +// reverse from normal +struct SortComparatorTestFunctor +{ + int operator () (const int& _a, const int& _b) const + { + if (_a < _b) + { + return 1; + } + else if (_b < _a) + { + return -1; + } + else + { + return 0; + } + } +}; + +static const char* test_Sort_Comparator() +{ + ZArray<int> list; + + list.PushBack(4); + list.PushBack(1); + list.PushBack(3); + list.PushBack(6); + list.PushBack(7); + list.PushBack(2); + list.PushBack(5); + + ZArrayAlgo::Sort(list,SortComparatorTestFunctor()); + TASSERT(list.Size() == 7, "Sort() changed array size!\n"); + TASSERT(list.PopFront() == 7, "Sort() didn't sort list properly!\n"); + TASSERT(list.PopFront() == 6, "Sort() didn't sort list properly!\n"); + TASSERT(list.PopFront() == 5, "Sort() didn't sort list properly!\n"); + TASSERT(list.PopFront() == 4, "Sort() didn't sort list properly!\n"); + TASSERT(list.PopFront() == 3, "Sort() didn't sort list properly!\n"); + TASSERT(list.PopFront() == 2, "Sort() didn't sort list properly!\n"); + TASSERT(list.PopFront() == 1, "Sort() didn't sort list properly!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +// ye olde bubble sorte +struct SortAlgorithmTestFunctor +{ + //Functor operator () override + template <typename CF> + void operator () (CF& _comparator, int* _array, size_t _size) + { + if (_size == 0) + return; + + bool keepGoing; + size_t i; + int temp; + + do + { + keepGoing = false; + for (i = 1; i < _size; i++) + { + if ( _comparator(_array[i-1], _array[i]) > 0) + { + temp = _array[i]; + _array[i] = _array[i-1]; + _array[i-1] = temp; + keepGoing = true; + } + } + } while (keepGoing); + } +}; + +static const char* test_Sort_Comparator_Algorithm() +{ + ZArray<int> list; + + list.PushBack(4); + list.PushBack(1); + list.PushBack(3); + list.PushBack(6); + list.PushBack(7); + list.PushBack(2); + list.PushBack(5); + + ZArrayAlgo::Sort(list, SortComparatorTestFunctor(), SortAlgorithmTestFunctor(), 0, list.Size()); + TASSERT(list.Size() == 7, "Sort() changed array size!\n"); + TASSERT(list.PopFront() == 7, "Sort() didn't sort list properly!\n"); + TASSERT(list.PopFront() == 6, "Sort() didn't sort list properly!\n"); + TASSERT(list.PopFront() == 5, "Sort() didn't sort list properly!\n"); + TASSERT(list.PopFront() == 4, "Sort() didn't sort list properly!\n"); + TASSERT(list.PopFront() == 3, "Sort() didn't sort list properly!\n"); + TASSERT(list.PopFront() == 2, "Sort() didn't sort list properly!\n"); + TASSERT(list.PopFront() == 1, "Sort() didn't sort list properly!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Sort_Comparator_Algorithm_Region() +{ + ZArray<int> list; + + list.PushBack(4); + list.PushBack(1); + list.PushBack(3); + list.PushBack(6); + list.PushBack(7); + list.PushBack(2); + list.PushBack(5); + + ZArrayAlgo::Sort(list,SortComparatorTestFunctor(), SortAlgorithmTestFunctor(),2,5); + TASSERT(list.Size() == 7, "Sort() changed array size!\n"); + TASSERT(list.PopFront() == 4, "Sort() didn't sort list properly!\n"); + TASSERT(list.PopFront() == 1, "Sort() didn't sort list properly!\n"); + TASSERT(list.PopFront() == 7, "Sort() didn't sort list properly!\n"); + TASSERT(list.PopFront() == 6, "Sort() didn't sort list properly!\n"); + TASSERT(list.PopFront() == 3, "Sort() didn't sort list properly!\n"); + TASSERT(list.PopFront() == 2, "Sort() didn't sort list properly!\n"); + TASSERT(list.PopFront() == 5, "Sort() didn't sort list properly!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Split() +{ + ZArray<int> list; + + list.PushBack(4); + list.PushBack(1); + list.PushBack(3); + list.PushBack(6); + list.PushBack(7); + list.PushBack(2); + list.PushBack(5); + + ZArray<int> values; + + values.PushBack(4); + + ZArray< ZArray<int> > out = ZArrayAlgo::Split(list, values); + + TASSERT( out.Size() == 1, "Split() 1 did not create an array with the correct number of sections!"); + TASSERT( out[0].Size() == 6, "Split() 1 did not create correct size section!"); + TASSERT( out[0].Front() == 1, "Split() 1 did not create correct front element!"); + TASSERT( out[0].Back() == 5, "Split() 1 did not create correct back element!"); + + values.PushBack(6); + + out = ZArrayAlgo::Split(list, values); + + TASSERT( out.Size() == 2, "Split() 2 did not create an array with the correct number of sections!"); + TASSERT( out[0].Size() == 2, "Split() 2 did not create correct size section 1!"); + TASSERT( out[0].Front() == 1, "Split() 2 did not create correct front element on section 1!"); + TASSERT( out[0].Back() == 3, "Split() 2 did not create correct back element on section 1!"); + TASSERT( out[1].Size() == 3, "Split() 2 did not create correct size section 2!"); + TASSERT( out[1].Front() == 7, "Split() 2 did not create correct front element on section 2!"); + TASSERT( out[1].Back() == 5, "Split() 2 did not create correct back element on section 2!"); + + values.PushBack(5); + + out = ZArrayAlgo::Split(list, values); + + TASSERT( out.Size() == 2, "Split() 3 did not create an array with the correct number of sections!"); + TASSERT( out[0].Size() == 2, "Split() 3 did not create correct size section 1!"); + TASSERT( out[0].Front() == 1, "Split() 3 did not create correct front element on section 1!"); + TASSERT( out[0].Back() == 3, "Split() 3 did not create correct back element on section 1!"); + TASSERT( out[1].Size() == 2, "Split() 3 did not create correct size section 2!"); + TASSERT( out[1].Front() == 7, "Split() 3 did not create correct front element on section 2!"); + TASSERT( out[1].Back() == 2, "Split() 3 did not create correct back element on section 2!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Split_Count() +{ + ZArray<int> list; + + list.PushBack(4); + list.PushBack(1); + list.PushBack(3); + list.PushBack(6); + list.PushBack(7); + list.PushBack(2); + list.PushBack(5); + list.PushBack(1); + list.PushBack(7); + + ZArray<int> values; + + values.PushBack(1); + + ZArray< ZArray<int> > out = ZArrayAlgo::Split(list, values, 1); + + //Should create [ [4], [3, 6, 7, 2, 5, 1, 7] ] + + TASSERT( out.Size() == 2, "Split() 1 did not create an array with the correct number of sections!"); + TASSERT( out[0].Size() == 1, "Split() 1 did not create correct size section 1!"); + TASSERT( out[0].Front() == 4, "Split() 1 did not create correct front element for section 1!"); + TASSERT( out[0].Back() == 4, "Split() 1 did not create correct back element for section 1!"); + TASSERT( out[1].Size() == 7, "Split() 1 did not create correct size section 2!"); + TASSERT( out[1].Front() == 3, "Split() 1 did not create correct front element for section 2!"); + TASSERT( out[1].Back() == 7, "Split() 1 did not create correct back element for section 2!"); + + values.PushBack(6); + + out = ZArrayAlgo::Split(list, values, 2); + + //Should create [ [4], [3], [7, 2, 5, 1, 7] ] + + TASSERT( out.Size() == 3, "Split() 2 did not create an array with the correct number of sections!"); + TASSERT( out[0].Size() == 1, "Split() 2 did not create correct size section 1!"); + TASSERT( out[0].Front() == 4, "Split() 2 did not create correct front element for section 1!"); + TASSERT( out[0].Back() == 4, "Split() 2 did not create correct back element for section 1!"); + TASSERT( out[1].Size() == 1, "Split() 2 did not create correct size section 2!"); + TASSERT( out[1].Front() == 3, "Split() 2 did not create correct front element for section 2!"); + TASSERT( out[1].Back() == 3, "Split() 2 did not create correct back element for section 2!"); + TASSERT( out[2].Size() == 5, "Split() 2 did not create correct size section 3!"); + TASSERT( out[2].Front() == 7, "Split() 2 did not create correct front element for section 3!"); + TASSERT( out[2].Back() == 7, "Split() 2 did not create correct back element for section 3!"); + + values.PushBack(5); + + out = ZArrayAlgo::Split(list, values, 15); + + //Should create [ [4], [3], [7, 2], [7] ] + + TASSERT( out.Size() == 4, "Split() 3 did not create an array with the correct number of sections!"); + TASSERT( out[0].Size() == 1, "Split() 3 did not create correct size section 1!"); + TASSERT( out[0].Front() == 4, "Split() 3 did not create correct front element for section 1!"); + TASSERT( out[0].Back() == 4, "Split() 3 did not create correct back element for section 1!"); + TASSERT( out[1].Size() == 1, "Split() 3 did not create correct size section 2!"); + TASSERT( out[1].Front() == 3, "Split() 3 did not create correct front element for section 2!"); + TASSERT( out[1].Back() == 3, "Split() 3 did not create correct back element for section 2!"); + TASSERT( out[2].Size() == 2, "Split() 3 did not create correct size section 3!"); + TASSERT( out[2].Front() == 7, "Split() 3 did not create correct front element for section 3!"); + TASSERT( out[2].Back() == 2, "Split() 3 did not create correct back element for section 3!"); + TASSERT( out[3].Size() == 1, "Split() 3 did not create correct size section 4!"); + TASSERT( out[3].Front() == 7, "Split() 3 did not create correct front element for section 4!"); + TASSERT( out[3].Back() == 7, "Split() 3 did not create correct back element for section 4!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Split_Count_Region() +{ + ZArray<int> list; + + list.PushBack(4); + list.PushBack(1); + list.PushBack(3); + list.PushBack(6); + list.PushBack(7); + list.PushBack(2); + list.PushBack(5); + list.PushBack(1); + list.PushBack(7); + + ZArray<int> values; + + values.PushBack(1); + + ZArray< ZArray<int> > out = ZArrayAlgo::Split(list, values, 1, 4, list.Size()); + + //Should create [ [7, 2, 5], [7] ] + + TASSERT( out.Size() == 2, "Split() 1 did not create an array with the correct number of sections!"); + TASSERT( out[0].Size() == 3, "Split() 1 did not create correct size section 1!"); + TASSERT( out[0].Front() == 7, "Split() 1 did not create correct front element for section 1!"); + TASSERT( out[0].Back() == 5, "Split() 1 did not create correct back element for section 1!"); + TASSERT( out[1].Size() == 1, "Split() 1 did not create correct size section 2!"); + TASSERT( out[1].Front() == 7, "Split() 1 did not create correct front element for section 2!"); + TASSERT( out[1].Back() == 7, "Split() 1 did not create correct back element for section 2!"); + + values.PushBack(6); + + out = ZArrayAlgo::Split(list, values, 2, 4, list.Size()); + + //Should create [ [7, 2, 5], [7] ] + + TASSERT( out.Size() == 2, "Split() 2 did not create an array with the correct number of sections!"); + TASSERT( out[0].Size() == 3, "Split() 2 did not create correct size section 1!"); + TASSERT( out[0].Front() == 7, "Split() 2 did not create correct front element for section 1!"); + TASSERT( out[0].Back() == 5, "Split() 2 did not create correct back element for section 1!"); + TASSERT( out[1].Size() == 1, "Split() 2 did not create correct size section 2!"); + TASSERT( out[1].Front() == 7, "Split() 2 did not create correct front element for section 2!"); + TASSERT( out[1].Back() == 7, "Split() 2 did not create correct back element for section 2!"); + + values.PushBack(5); + + out = ZArrayAlgo::Split(list, values, 15, 1, list.Size()); + + //Should create [ [3], [7, 2], [7] ] + + TASSERT( out.Size() == 3, "Split() 3 did not create an array with the correct number of sections!"); + TASSERT( out[0].Size() == 1, "Split() 3 did not create correct size section 1!"); + TASSERT( out[0].Front() == 3, "Split() 3 did not create correct front element for section 1!"); + TASSERT( out[0].Back() == 3, "Split() 3 did not create correct back element for section 1!"); + TASSERT( out[1].Size() == 2, "Split() 3 did not create correct size section 2!"); + TASSERT( out[1].Front() == 7, "Split() 3 did not create correct front element for section 2!"); + TASSERT( out[1].Back() == 2, "Split() 3 did not create correct back element for section 2!"); + TASSERT( out[2].Size() == 1, "Split() 3 did not create correct size section 3!"); + TASSERT( out[2].Front() == 7, "Split() 3 did not create correct front element for section 3!"); + TASSERT( out[2].Back() == 7, "Split() 3 did not create correct back element for section 3!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Sum() +{ + ZArray<int> list; + ZArray<ArrayValueTestClass> list2; + int ans; + ArrayValueTestClass ans2; + + list.PushBack(1); + list.PushBack(2); + list.PushBack(3); + list.PushBack(4); + list.PushBack(5); + + ans = ZArrayAlgo::Sum(list, 10); + TASSERT (ans == 25, "Accumulate() failed to accumulate correctly on primitive list!\n"); + + list2.PushBack(1); + list2.PushBack(2); + list2.PushBack(3); + list2.PushBack(4); + list2.PushBack(5); + + ans2 = ZArrayAlgo::Sum(list2, ArrayValueTestClass(10)); + TASSERT (ans2.val == 25, "Accumulate() failed to accumulate correctly on overridden list!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Sum_Region() +{ + ZArray<int> list; + ZArray<ArrayValueTestClass> list2; + int ans; + ArrayValueTestClass ans2; + + list.PushBack(1); + list.PushBack(2); + list.PushBack(3); + list.PushBack(4); + list.PushBack(5); + + ans = ZArrayAlgo::Sum(list, 10, 1, 4); + TASSERT (ans == 19, "Accumulate() failed to accumulate correctly on primitive list!\n"); + + list2.PushBack(1); + list2.PushBack(2); + list2.PushBack(3); + list2.PushBack(4); + list2.PushBack(5); + + ans2 = ZArrayAlgo::Sum(list2, ArrayValueTestClass(10), 1, 4); + TASSERT (ans2.val == 19, "Accumulate() failed to accumulate correctly on overridden list!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_SwapElements() +{ + ZArray<int> list; + list.PushBack(1); + list.PushBack(2); + list.PushBack(3); + + ZArrayAlgo::SwapElements(list, 1,2); + TASSERT( list.Size() == 3, "SwapElements changed list size!\n"); + TASSERT( list.PopFront() == 1, "SwapElements corrupted list!\n"); + TASSERT( list.PopFront() == 3, "SwapElements failed to swap elements in list!\n"); + TASSERT( list.PopFront() == 2, "SwapElements failed to swap elements in list!\n"); + + list.PushBack(1); + list.PushBack(2); + list.PushBack(3); + ZArrayAlgo::SwapElements(list, 1,1); + TASSERT( list.Size() == 3, "SwapElements changed list size!\n"); + TASSERT( list.PopFront() == 1, "SwapElements corrupted list!\n"); + TASSERT( list.PopFront() == 2, "SwapElements failed to swap elements in list!\n"); + TASSERT( list.PopFront() == 3, "SwapElements failed to swap elements in list!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Unique() +{ + ZArray<int> list; + list.PushBack(1); + list.PushBack(2); + list.PushBack(3); + + TASSERT( ZArrayAlgo::Unique(list) == 0, "Unique() claims removals on unique list!\n"); + TASSERT( list.Size() == 3, "Unique() changed length of list!\n"); + + list.PushBack(2); + list.PushBack(3); + list.PushBack(2); + list.PushBack(3); + list.PushBack(4); + list.PushBack(5); + + TASSERT( ZArrayAlgo::Unique(list) == 4, "Unique() claims wrong number of removals on nonunique list!\n"); + TASSERT( list.Size() == 5, "Unique() changed length of list to wrong value!\n"); + TASSERT( list.PopFront() == 1, "Unique() put wrong value into list!\n"); + TASSERT( list.PopFront() == 2, "Unique() put wrong value into list!\n"); + TASSERT( list.PopFront() == 3, "Unique() put wrong value into list!\n"); + TASSERT( list.PopFront() == 4, "Unique() put wrong value into list!\n"); + TASSERT( list.PopFront() == 5, "Unique() put wrong value into list!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Unique_In_Region() +{ + ZArray<int> list; + list.PushBack(1); + list.PushBack(2); + list.PushBack(3); + list.PushBack(2); + list.PushBack(3); + list.PushBack(2); + list.PushBack(3); + list.PushBack(4); + list.PushBack(5); + + TASSERT( ZArrayAlgo::Unique(list, 1, 4) == 1, "Unique() claims wrong number of removals on nonunique list!\n"); + TASSERT( list.Size() == 8, "Unique() changed length of list to wrong value!\n"); + TASSERT( list.PopFront() == 1, "Unique() put wrong value into list!\n"); + TASSERT( list.PopFront() == 2, "Unique() put wrong value into list!\n"); + TASSERT( list.PopFront() == 3, "Unique() put wrong value into list!\n"); + TASSERT( list.PopFront() == 3, "Unique() put wrong value into list!\n"); + TASSERT( list.PopFront() == 2, "Unique() put wrong value into list!\n"); + TASSERT( list.PopFront() == 3, "Unique() put wrong value into list!\n"); + TASSERT( list.PopFront() == 4, "Unique() put wrong value into list!\n"); + TASSERT( list.PopFront() == 5, "Unique() put wrong value into list!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ diff --git a/ZTestSuite/Test-ZAssert.cpp b/ZTestSuite/Test-ZAssert.cpp new file mode 100644 index 0000000..2fe64f4 --- /dev/null +++ b/ZTestSuite/Test-ZAssert.cpp @@ -0,0 +1,60 @@ +/* + Test-ZArray.cpp + Author: Chris Ertel (crertel@762studios.com) + + Purpose : Unit tests for ZAssert. + + Changelog : + 1/8/2012 - Created (crertel) +*/ + +#include "ZUnitTest.hpp" + +#include <ZUtil/ZAssert.hpp> + +static const char* testRuntimeAssert(); + +//List of unit tests +ZUnitTest ZAssertUnitTests[] = +{ + { + "Runtime assert", + testRuntimeAssert + } +}; + +DECLARE_ZTESTBLOCK(ZAssert); + +/*************************************************************************/ + +static int handleAssert(const char* _msg, void* _arg) +{ + *((int*)_arg) = 1337; + printf("Assert thrown: %s\n", _msg); + return 1; +} + +static int manhandleAssert(const char* _msg, void* _arg) +{ + *((int*)_arg) = 357; + printf("Assert failed: %s\n",_msg); + return 1; +} + +/*************************************************************************/ + +static const char* testRuntimeAssert() +{ + int var = 762; + SST_OS_SetRuntimeAssertHandler(handleAssert, &var); + + ZASSERT_RUNTIME(false,"Assert test.\n"); + TASSERT(var == 1337, "var was not reset by assertion handler\n"); + SST_OS_SetRuntimeAssertHandler(manhandleAssert, &var); + ZASSERT_RUNTIME_FAIL("Assert fail test.\n"); + TASSERT(var == 357, "var was not reset by assertion failure\n"); + + SST_OS_SetRuntimeAssertHandler(NULL,NULL); + + return ZTEST_SUCCESS; +} diff --git a/ZTestSuite/Test-ZBasicString.cpp b/ZTestSuite/Test-ZBasicString.cpp new file mode 100644 index 0000000..1950714 --- /dev/null +++ b/ZTestSuite/Test-ZBasicString.cpp @@ -0,0 +1,660 @@ +#include "ZUnitTest.hpp" + +//Hijack the assert +#define ZSTL_ASSERT(condition, message) SST_OS_RuntimeAssert(condition, message) + +#include <ZSTL/ZBasicString.hpp> +#include <SST/SST_Hash.h> + +static const char* test_Constructors(); +static const char* test_AbsoluteIndex(); +static const char* test_Allocator(); +static const char* test_Array(); +static const char* test_At(); +static const char* test_Back(); +static const char* test_Capacity(); +static const char* test_Clear(); +static const char* test_Clear_With_Capacity(); +static const char* test_Compare_To_Array(); +static const char* test_Compare_To_ZString(); +static const char* test_Copy(); +static const char* test_Data(); +static const char* test_Empty(); +static const char* test_Equals_To_Array(); +static const char* test_Equals_To_ZString(); +static const char* test_Erase(); +static const char* test_Erase_Substring(); +static const char* test_Front(); +static const char* test_Hash(); +static const char* test_Insert(); +static const char* test_Length(); +static const char* test_OperatorPlus(); +static const char* test_PopBack(); +static const char* test_PopFront(); +static const char* test_PushBack(); +static const char* test_PushFront(); +static const char* test_Reserve(); +static const char* test_Resize(); +static const char* test_Resize_With_Fill(); +static const char* test_Swap(); + +ZUnitTest ZBasicStringUnitTests[] = +{ + { "ZBasicString: Constructors", test_Constructors }, + { "ZBasicString: AbsoluteIndex", test_AbsoluteIndex }, + { "ZBasicString: Allocator", test_Allocator }, + { "ZBasicString: Array", test_Array }, + { "ZBasicString: At", test_At }, + { "ZBasicString: Back", test_Back }, + { "ZBasicString: Capacity", test_Capacity }, + { "ZBasicString: Clear", test_Clear }, + { "ZBasicString: Clear with capacity", test_Clear_With_Capacity }, + { "ZBasicString: Compare to array", test_Compare_To_Array }, + { "ZBasicString: Compare to zstring", test_Compare_To_ZString }, + { "ZBasicString: Copy", test_Copy }, + { "ZBasicString: Data", test_Data }, + { "ZBasicString: Empty", test_Empty }, + { "ZBasicString: Equals to array", test_Equals_To_Array }, + { "ZBasicString: Equals to zstring", test_Equals_To_ZString }, + { "ZBasicString: Erase", test_Erase }, + { "ZBasicString: Erase substring", test_Erase_Substring }, + { "ZBasicString: Front", test_Front }, + { "ZBasicString: Hash", test_Hash }, + { "ZBasicString: Insert", test_Insert }, + { "ZBasicString: Length", test_Length }, + { "ZBasicString: OperatorPlus", test_OperatorPlus }, + { "ZBasicString: PopBack", test_PopBack }, + { "ZBasicString: PopFront", test_PopFront }, + { "ZBasicString: PushBack", test_PushBack }, + { "ZBasicString: PushFront", test_PushFront }, + { "ZBasicString: Reserve", test_Reserve }, + { "ZBasicString: Resize", test_Resize }, + { "ZBasicString: Resize with fill", test_Resize_With_Fill }, + { "ZBasicString: Swap", test_Swap } +}; + +DECLARE_ZTESTBLOCK(ZBasicString); + +/*************************************************************************/ + +//We use this allocator to ensure that allocator-agnostic functions work correctly +class CharArrayAllocator +{ +public: + char* Allocate(size_t _size) + { + return new (std::nothrow) char[_size]; + } + + void Deallocate(char* _ptr, size_t _size) + { + (void)_size; + delete[] _ptr; + } +}; + +/*************************************************************************/ + +static const char* test_Constructors() +{ + const char* testData1 = "SuperAwesomeString"; + const char* testData2 = "Super. Awesome. String."; + + ZBasicString<> string1; + ZBasicString<> string2(testData1); + ZBasicString<> string3(&testData1[5], 7); + ZBasicString<> string4(string2); + + ZBasicString<CharArrayAllocator> string5(testData2); + ZBasicString<> string6(string5); + + TASSERT( strcmp(string1.Data(), "") == 0 && + string1.Empty() == true && + string1.Length() == 0, + "Default string initialized with incorrect string!\n"); + + TASSERT( strcmp(string2.Data(), testData1) == 0 && + string2.Empty() == false && + string2.Length() == 18, + "String initialized with incorrect string!\n"); + + TASSERT( strcmp(string3.Data(), "Awesome") == 0 && + string3.Empty() == false && + string3.Length() == 7, + "Copy substring constructor initialized with incorrect string!\n"); + + TASSERT( strcmp(string4.Data(), testData1) == 0 && + string4.Empty() == false && + string4.Length() == 18, + "Copy string constructor initialized with incorrect string!\n"); + + TASSERT( strcmp(string5.Data(), testData2) == 0 && + string5.Empty() == false && + string5.Length() == 23, + "String constructor with custom allocator initialized with incorrect string!\n"); + + TASSERT( strcmp(string6.Data(), testData2) == 0 && + string6.Empty() == false && + string6.Length() == 23, + "Copy string constructor with custom allocator initialized with incorrect string!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_AbsoluteIndex() +{ + ZBasicString<> string("1235"); + + TASSERT( string.BoundsCheck(0, string.Length()) == 0, "AbsoluteIndex() mismaps 0!\n"); + TASSERT( string.BoundsCheck(1, string.Length()) == 1, "AbsoluteIndex() mismaps 1!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Allocator() +{ + // This is a pass-through for ZArray::Allocator(), so we don't need to do anything + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Array() +{ + ZBasicString<> string("12345"); + + TASSERT( string.Array().Empty() == false, "Array() gave back empty backing array!\n"); + TASSERT( string.Array().Back() == ZBASICSTRING_NULL_TERMINATOR, "Array() is not null terminated!\n"); + TASSERT( string.Array().Size() == 6, "Array() gave back missized array!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_At() +{ + ZBasicString<> string("12345"); + + TASSERT( string.At(0) == '1', "At() returned incorrect character!\n"); + TASSERT( string.At(1) == '2', "At() returned incorrect character!\n"); + TASSERT( string.At(2) == '3', "At() returned incorrect character!\n"); + TASSERT( string.At(3) == '4', "At() returned incorrect character!\n"); + TASSERT( string.At(4) == '5', "At() returned incorrect character!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Back() +{ + ZBasicString<> string = ZBasicString<>("abcde"); + ZBasicString<> string2 = ZBasicString<>("1"); + ZBasicString<> string3 = ZBasicString<>(); + + TASSERT(string.Back() == 'e', "Back() returned wrong front character for string length > 2"); + string.Back() = '!'; + TASSERT(string.Back() == '!', "Back() returned the correct reference"); + + TASSERT(string2.Back() == '1', "Back() returned the wrong character for a string of length 1."); + +// Uncomment to test if Back() raises an assert on an empty string. +// TASSERT(string3.Back() == '\0', "This should have asserted."); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ +static const char* test_Capacity() +{ + ZBasicString<ZArrayAllocator<char, 32> > string("12435"); + + //NOTE: We can do this because (at the moment) constructing from a const char array + // and that will init the capacity to just enough to hold it. + TASSERT( string.Capacity() == 5, "Capacity() returned incorrect capacity!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Clear() +{ + ZBasicString<> string("12435"); + + TASSERT( string.Length() == 5, "String initialized with incorrect size!\n"); + string.Clear(); + TASSERT( string.Length() == 0, "Clear() did not set string length to 0!\n"); + TASSERT( string.Equals("") == true, "Clear() did not set string to empty string!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Clear_With_Capacity() +{ + ZBasicString<> string("12435"); + + TASSERT( string.Length() == 5, "String initialized with incorrect size!\n"); + string.Clear(16); + TASSERT( string.Length() == 0, "Clear() did not set string length to 0!\n"); + TASSERT( string.Capacity() == 16, "Clear() did not properly set new capacity of string!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Compare_To_Array() +{ + const char* str1 = "Hallo!"; + const char* str2 = "Hello!"; + const char* str3 = "Hullo!"; + const char* str4 = "Goodbye!"; + ZBasicString<> string("Hello!"); + + TASSERT( string.Compare(str3) < 0, "Compare() misclassified lexigraphically larger string!\n"); + TASSERT( string.Compare(str2) == 0, "Compare() misclassified lexigraphically equal string!\n"); + TASSERT( string.Compare(str1) > 0, "Compare() misclassified lexigraphically smaller string!\n"); + TASSERT( string.Compare(str4) != 0, "Compare() misclassified different length different string!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Compare_To_ZString() +{ + ZBasicString<> str1("Hallo!"); + ZBasicString<> str2("Hello!"); + ZBasicString<> str3("Hullo!"); + ZBasicString<> str4("Goodbye!"); + ZBasicString<> str5("HELLO!"); + ZBasicString<> string("Hello!"); + + TASSERT( string.Compare(str3) < 0, "Compare() misclassified lexigraphically larger string!"); + TASSERT( string.Compare(str2) == 0, "Compare() misclassified lexigraphically equal string!"); + TASSERT( string.Compare(str1) > 0, "Compare() misclassified lexigraphically smaller string!"); + TASSERT( string.Compare(str4) != 0, "Compare() misclassified different length different string!"); + TASSERT( string.Compare(str5) != 0, "Compare() is case-insensitive!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Data() +{ + ZBasicString<> string("Hello!"); + + TASSERT ( string.Data() != NULL, "Data() returned null pointer for valid string!\n"); + TASSERT ( strcmp(string.Data(),"Hello!") == 0, "Data() returned null pointer for valid string!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Equals_To_Array() +{ + ZBasicString<> string("yes"); + const char* yes = "yes"; + const char* no = "no"; + + TASSERT( string.Equals(no) == false, "Equals() misclassified different char array string!\n"); + TASSERT( string.Equals(yes) == true, "Equals() misclassified identical char array string!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Equals_To_ZString() +{ + ZBasicString<> str1("Hallo!"); + ZBasicString<> str2("Hello!"); + ZBasicString<> str3("Hello!"); + + TASSERT( str3.Equals(str1) == false, "Equals() miscompared two different ZBasicStrings!\n"); + TASSERT( str3.Equals(str2) == true, "Equals() miscompared two equivalent ZBasicStrings!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Copy() +{ + ZBasicString<> emptyString(""); + ZBasicString<> notEmptyString("notEmpty"); + + emptyString.Copy(notEmptyString); + + TASSERT( emptyString.Equals(notEmptyString), "Copy() failed to move data!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Empty() +{ + ZBasicString<> emptyString; + ZBasicString<> emptyString2(""); + ZBasicString<> notEmptyString("notEmpty"); + + TASSERT( emptyString.Empty() == true, "Empty() returned false on empty string from default constructor!\n"); + TASSERT( emptyString2.Empty() == true, "Empty() returned false on empty string from empty constructor!\n"); + TASSERT( notEmptyString.Empty() == false, "Empty() returned true on nonempty string!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Erase() +{ + ZBasicString<> string("abc"); + ZBasicString<> string2("abc"); + ZBasicString<> string3("abc"); + ZBasicString<> string4("abc"); + + string.Erase(0); + TASSERT(string.Equals("bc"), "Erase() failed to remove first character!\n"); + + string2.Erase(2); + TASSERT(string2.Equals("ab"), "Erase() failed to remove last character!\n"); + + string3.Erase(1); + TASSERT(string3.Equals("ac"), "Erase() failed to remove middle character!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Erase_Substring() +{ + ZBasicString<> string("abcde"); + ZBasicString<> string2("abcde"); + ZBasicString<> string3("abcde"); + ZBasicString<> string4("abcde"); + + string.Erase(0,3); + TASSERT(string.Equals("de") == true, "Erase() failed to remove first 3 characters!\n"); + + string2.Erase(2,5); + TASSERT(string2.Equals("ab") == true, "Erase() failed to remove last 3 characters!\n"); + + string3.Erase(1,4); + TASSERT(string3.Equals("ae") == true, "Erase() failed to remove middle 3 characters!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Front() +{ + ZBasicString<> string = ZBasicString<>("abcde"); + ZBasicString<> string2 = ZBasicString<>("1"); + ZBasicString<> string3 = ZBasicString<>(); + + TASSERT(string.Front() == 'a', "Front() returned wrong front character for string length > 2"); + string.Front() = '!'; + TASSERT(string.Front() == '!', "Front() returned the correct reference)"); + + TASSERT(string2.Front() == '1', "Front() returned the wrong character for a string of length 1."); + //Uncomment to see if Front() asserts as advertised. + //TASSERT(string3.Front() == '\0', "This should have asserted."); + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Hash() +{ + ZBasicString<> string("hashMe"); + ZBasicString<> string2("hashMeToo"); + + TASSERT( string.Hash() == SST_Crypto_HashJ6("hashMe",6), "Hash() returned wrong hash on string!\n"); + TASSERT( string.Hash() != string2.Hash(), "Hash() returned same hash on different strings!\n") + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Insert() +{ + ZBasicString<> string1("hi"); + ZBasicString<> string2("hi"); + ZBasicString<> string3("hi"); + ZBasicString<> string4("hi"); + ZBasicString<> add("there"); + + string1.Insert(0,add); + TASSERT( string1.Equals("therehi"), "Insert() returned wrong string on insert front\n"); + + string2.Insert(2,add); + TASSERT( string2.Equals("hithere"), "Insert() returned wrong string on insert back\n"); + + string4.Insert(1,add); + TASSERT( string4.Equals("htherei"), "Insert() returned wrong string on insert middle\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Length() +{ + ZBasicString<> emptyString1(""); + ZBasicString<> emptyString2; + ZBasicString<> mystring("12345"); + + TASSERT( emptyString1.Length() == 0, "Length() reports nonempty on empty string!\n"); + TASSERT( emptyString2.Length() == 0, "Length() reports nonempty on default string!\n"); + TASSERT( mystring.Length() == 5, "Length() reports wrong length on string!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_OperatorPlus() +{ + /* + ZBasicString<A> operator + (const char *_lhs, const ZBasicString<A>& _rhs) + ZBasicString<A> operator + (const ZBasicString<A>& _lhs, const char *_rhs) + */ + ZBasicString<> string = ZBasicString<>("abcde"); + ZBasicString<> emptyString = ZBasicString<>(); + const char cString[5] = "1234"; + const char emptyCString[1] = ""; + + TASSERT(string + cString == "abcde1234", "Right add of a c-string failed."); + TASSERT(cString + string == "1234abcde", "Left add of a c-string failed"); + TASSERT(cString + emptyString == "1234", "Right add of empty ZBasicString failed"); + TASSERT(emptyString + cString == "1234", "Left add of empty ZBasicString failed"); + TASSERT(string + emptyCString == "abcde", "Right add of empty c-string failed."); + TASSERT(emptyCString + string == "abcde", "Left add of empty c-string failed."); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_PopBack() +{ + ZBasicString<> string("apple"); + char back; + + back = string.PopBack(); + TASSERT ( (back == 'e') && string.Equals("appl"), "PopBack() returned incorrect character!\n"); + + back = string.PopBack(); + TASSERT ( (back == 'l') && string.Equals("app"), "PopBack() returned incorrect character!\n"); + + back = string.PopBack(); + TASSERT ( (back == 'p') && string.Equals("ap"), "PopBack() returned incorrect character!\n"); + + back = string.PopBack(); + TASSERT ( (back == 'p') && string.Equals("a"), "PopBack() returned incorrect character!\n"); + + back = string.PopBack(); + TASSERT ( (back == 'a') && string.Empty(), "PopBack() returned incorrect character!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_PopFront() +{ + ZBasicString<> string("apple"); + char front; + + front = string.PopFront(); + TASSERT ( (front == 'a') && string.Equals("pple"), "PopFront() returned incorrect character!\n"); + + front = string.PopFront(); + TASSERT ( (front == 'p') && string.Equals("ple"), "PopFront() returned incorrect character!\n"); + + front = string.PopFront(); + TASSERT ( (front == 'p') && string.Equals("le"), "PopFront() returned incorrect character!\n"); + + front = string.PopFront(); + TASSERT ( (front == 'l') && string.Equals("e"), "PopFront() returned incorrect character!\n"); + + front = string.PopFront(); + TASSERT ( (front == 'e') && string.Empty(), "PopFront() returned incorrect character!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_PushBack() +{ + ZBasicString<> string(""); + + string.PushBack('a'); + TASSERT ( string.Equals("a"), "PushBack() returned broken string!\n"); + + string.PushBack('p'); + TASSERT ( string.Equals("ap"), "PushBack() returned broken string!\n"); + + string.PushBack('p'); + TASSERT ( string.Equals("app"), "PushBack() returned broken string!\n"); + + string.PushBack('l'); + TASSERT ( string.Equals("appl"), "PushBack() returned broken string!\n"); + + string.PushBack('e'); + TASSERT ( string.Equals("apple"), "PushBack() returned broken string!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_PushFront() +{ + ZBasicString<> string(""); + + string.PushFront('e'); + TASSERT ( string.Equals("e"), "PushFront() returned broken string!\n"); + + string.PushFront('l'); + TASSERT ( string.Equals("le"), "PushFront() returned broken string!\n"); + + string.PushFront('p'); + TASSERT ( string.Equals("ple"), "PushFront() returned broken string!\n"); + + string.PushFront('p'); + TASSERT ( string.Equals("pple"), "PushFront() returned broken string!\n"); + + string.PushFront('a'); + TASSERT ( string.Equals("apple"), "PushFront() returned broken string!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Reserve() +{ + ZBasicString<> str("wat"); + + str.Reserve(34); + TASSERT( str.Capacity() == 34, "Reserve() failed to set capacity to correct value!\n"); + + str.Reserve(43); + TASSERT( str.Capacity() == 43, "Reserve() failed to set capacity to correct value!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Resize() +{ + ZBasicString<> str("wat"); + + TASSERT( str.Length() == 3, "Size() of string returned wrong size!\n"); + + str.Resize(2); + + TASSERT( str.Length() == 2, "Size(2) of string returned wrong size!\n"); + + str.Resize(4); + + TASSERT( str.Length() == 4, "Size(4) of string returned wrong size!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Resize_With_Fill() +{ + ZBasicString<> str(""); + + str.Resize(4,'a'); + + TASSERT( str.Equals("aaaa"), "Resize() did not fill new string correctly!\n"); + + str.Resize(2,'b'); + TASSERT( str.Equals("aa"), "Resize() did resize the string correctly!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Swap() +{ + ZBasicString<> str("hi"); + ZBasicString<> str2("there"); + + str.Swap(str2); + + TASSERT( str.Equals("there") == true, "Swap did not replace first string!\n"); + TASSERT( str2.Equals("hi") == true, "Swap did not replace second string!\n"); + + str.Swap(str2); + + TASSERT( str.Equals("hi") == true, "Swap did not put back first string!\n"); + TASSERT( str2.Equals("there") == true, "Swap did not put back second string!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ diff --git a/ZTestSuite/Test-ZBasicStringAlgo.cpp b/ZTestSuite/Test-ZBasicStringAlgo.cpp new file mode 100644 index 0000000..3510f7d --- /dev/null +++ b/ZTestSuite/Test-ZBasicStringAlgo.cpp @@ -0,0 +1,1903 @@ +#include "ZUnitTest.hpp" +#include <ZSTL/ZString.hpp> +#include <ZSTL/ZBasicStringAlgo.hpp> +#include <stdexcept> + +static const char* test_Append(); +static const char* test_Append_Region(); +static const char* test_BuildNumeric_Double(); +static const char* test_BuildNumeric_Int(); +static const char* test_BuildPrintf(); +static const char* test_BuildRepeat(); +static const char* test_Contains(); +static const char* test_Contains_Region(); +static const char* test_ContainsSub(); +static const char* test_ContainsSub_Region(); +static const char* test_Copy(); +static const char* test_Copy_Region(); +static const char* test_EndsWith(); +static const char* test_EndsWith_Region(); +static const char* test_Equal(); +static const char* test_Equal_Region(); +static const char* test_EqualIgnoreCase(); +static const char* test_EqualIgnoreCase_Region(); +static const char* test_Fill(); +static const char* test_Fill_Region(); +static const char* test_Find(); +static const char* test_Find_Region(); +static const char* test_FindAll(); +static const char* test_FindAll_Region(); +static const char* test_FindAllOf(); +static const char* test_FindAllOf_Region(); +static const char* test_FindFirst(); +static const char* test_FindFirst_Region(); +static const char* test_FindFirstOf(); +static const char* test_FindFirstOf_Region(); +static const char* test_FindFirstNot(); +static const char* test_FindFirstNot_Region(); +static const char* test_FindFirstNotOf(); +static const char* test_FindFirstNotOf_Region(); +static const char* test_FindLast(); +static const char* test_FindLast_In_Region(); +static const char* test_FindLastOf(); +static const char* test_FindLastOf_In_Region(); +static const char* test_FindLastNot(); +static const char* test_FindLastNot_In_Region(); +static const char* test_FindLastNotOf(); +static const char* test_FindLastNotOf_In_Region(); +static const char* test_FindSub(); +static const char* test_FindSub_Region(); +static const char* test_IsNumeric(); +static const char* test_IsNumeric_Region(); +static const char* test_Remove(); +static const char* test_Remove_In_Region(); +static const char* test_RemoveAll(); +static const char* test_RemoveAll_In_Region(); +static const char* test_RemoveUpTo(); +static const char* test_RemoveUpTo_In_Region(); +static const char* test_Replace(); +#if 0 +static const char* test_ReplaceSub(); +#endif +static const char* test_Replace_In_Region(); +static const char* test_Reverse(); +static const char* test_Reverse_Region(); +static const char* test_Slice(); +static const char* test_Split(); +static const char* test_Split_Count(); +static const char* test_Split_Count_Region(); +static const char* test_StartsWith(); +static const char* test_StartsWith_Region(); +static const char* test_Strip(); +static const char* test_Strip_Region(); +static const char* test_Tokenize(); +static const char* test_ToLower(); +static const char* test_ToLower_Region(); +static const char* test_ToUpper(); +static const char* test_ToUpper_Region(); +static const char* test_TrimLeft(); +static const char* test_TrimLeft_Region(); +static const char* test_TrimRight(); +static const char* test_TrimRight_Region(); +static const char* test_Trim(); +static const char* test_Trim_Region(); + +ZUnitTest ZBasicStringAlgoUnitTests[] = +{ + { "ZBasicStringAlgo: Append", test_Append }, + { "ZBasicStringAlgo: Append in region", test_Append_Region }, + { "ZBasicStringAlgo: BuildNumeric_Double", test_BuildNumeric_Double }, + { "ZBasicStringAlgo: BuildNumeric_Int", test_BuildNumeric_Int }, + { "ZBasicStringAlgo: BuildPrintf", test_BuildPrintf }, + { "ZBasicStringAlgo: BuildRepeat", test_BuildRepeat }, + { "ZBasicStringAlgo: Contains", test_Contains }, + { "ZBasicStringAlgo: Contains region", test_Contains_Region }, + { "ZBasicStringAlgo: ContainsSub", test_ContainsSub }, + { "ZBasicStringAlgo: ContainsSub region", test_ContainsSub_Region }, + { "ZBasicStringAlgo: Copy", test_Copy }, + { "ZBasicStringAlgo: Copy region", test_Copy_Region }, + { "ZBasicStringAlgo: EndsWith", test_EndsWith }, + { "ZBasicStringAlgo: EndsWith region", test_EndsWith_Region }, + { "ZBasicStringAlgo: Equal", test_Equal }, + { "ZBasicStringAlgo: Equal region", test_Equal_Region }, + { "ZBasicStringAlgo: EqualIgnoreCase", test_EqualIgnoreCase }, + { "ZBasicStringAlgo: EqualIgnoreCase in region",test_EqualIgnoreCase_Region }, + { "ZBasicStringAlgo: Fill", test_Fill }, + { "ZBasicStringAlgo: Fill region", test_Fill_Region }, + { "ZBasicStringAlgo: Find", test_Find }, + { "ZBasicStringAlgo: Find in region", test_Find_Region }, + { "ZBasicStringAlgo: FindAll", test_FindAll }, + { "ZBasicStringAlgo: FindAll in region", test_FindAll_Region }, + { "ZBasicStringAlgo: FindAllOf", test_FindAllOf }, + { "ZBasicStringAlgo: FindAllOf region", test_FindAllOf_Region }, + { "ZBasicStringAlgo: FindFirst", test_FindFirst }, + { "ZBasicStringAlgo: FindFirst in region", test_FindFirst_Region }, + { "ZBasicStringAlgo: FindFirstOf", test_FindFirstOf }, + { "ZBasicStringAlgo: FindFirstOf in region", test_FindFirstOf_Region }, + { "ZBasicStringAlgo: FindFirstNot", test_FindFirstNot }, + { "ZBasicStringAlgo: FindFirstNot region", test_FindFirstNot_Region }, + { "ZBasicStringAlgo: FindFirstNotof", test_FindFirstNotOf }, + { "ZBasicStringAlgo: FindFirstNotOf region", test_FindFirstNotOf_Region }, + { "ZBasicStringAlgo: FindLast", test_FindLast }, + { "ZBasicStringAlgo: FindLast in region", test_FindLast_In_Region }, + { "ZBasicStringAlgo: FindLastOf", test_FindLastOf }, + { "ZBasicStringAlgo: FindLastOf in region", test_FindLastOf_In_Region }, + { "ZBasicStringAlgo: FindLastNot", test_FindLastNot }, + { "ZBasicStringAlgo: FindLastNot in region", test_FindLastNot_In_Region }, + { "ZBasicStringAlgo: FindLastNotOf", test_FindLastNotOf }, + { "ZBasicStringAlgo: FindLastNotOf in region", test_FindLastNotOf_In_Region }, + { "ZBasicStringAlgo: FindSub", test_FindSub }, + { "ZBasicStringAlgo: FindSub region", test_FindSub_Region }, + { "ZBasicStringAlgo: IsNumeric", test_IsNumeric }, + { "ZBasicStringAlgo: IsNumeric region", test_IsNumeric_Region }, + { "ZBasicStringAlgo: Remove", test_Remove }, + { "ZBasicStringAlgo: Remove in region", test_Remove_In_Region }, + { "ZBasicStringAlgo: RemoveAll", test_RemoveAll }, + { "ZBasicStringAlgo: RemoveAll in region", test_RemoveAll_In_Region }, + { "ZBasicStringAlgo: RemoveUpTo", test_RemoveUpTo }, + { "ZBasicStringAlgo: RemoveUpTo in region", test_RemoveUpTo_In_Region }, + { "ZBasicStringAlgo: Replace", test_Replace }, +#if 0 + { "ZBasicStringAlgo: ReplaceSub", test_ReplaceSub }, +#endif + { "ZBasicStringAlgo: Replace in region", test_Replace_In_Region }, + { "ZBasicStringAlgo: Reverse", test_Reverse }, + { "ZBasicStringAlgo: Reverse region", test_Reverse_Region }, + { "ZBasicStringAlgo: Slice", test_Slice }, + { "ZBasicStringAlgo: Split", test_Split }, + { "ZBasicStringAlgo: Split Count", test_Split_Count }, + { "ZBasicStringAlgo: Split Count region", test_Split_Count_Region }, + { "ZBasicStringAlgo: StartsWith", test_StartsWith }, + { "ZBasicStringAlgo: StartsWith region", test_StartsWith_Region }, + { "ZBasicStringAlgo: Strip", test_Strip }, + { "ZBasicStringAlgo: Strip region", test_Strip_Region }, + { "ZBasicStringAlgo: Tokenize", test_Tokenize }, + { "ZBasicStringAlgo: ToLower", test_ToLower }, + { "ZBasicStringAlgo: ToLower region", test_ToLower_Region }, + { "ZBasicStringAlgo: ToUpper", test_ToUpper }, + { "ZBasicStringAlgo: ToUpper region", test_ToUpper_Region }, + { "ZBasicStringAlgo: Trim left", test_TrimLeft }, + { "ZBasicStringAlgo: Trim left region", test_TrimLeft_Region }, + { "ZBasicStringAlgo: Trim right", test_TrimRight }, + { "ZBasicStringAlgo: Trim right region", test_TrimRight_Region }, + { "ZBasicStringAlgo: Trim", test_Trim }, + { "ZBasicStringAlgo: Trim region", test_Trim_Region }, +}; + +DECLARE_ZTESTBLOCK(ZBasicStringAlgo); + +/*************************************************************************/ + +static const char* test_Append() +{ + ZBasicString<> str; + + ZBasicStringAlgo::Append(str, "ABC"); + + TASSERT(str == "ABC", "Append() did not correctly append first string!"); + + ZBasicStringAlgo::Append(str, "DEF"); + + TASSERT(str == "ABCDEF", "Append() did not correctly append first string!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Append_Region() +{ + ZBasicString<> str; + + ZBasicStringAlgo::Append(str, "ABC", 0, 1); + + TASSERT(str == "A", "Append() did not correctly append first string!"); + + ZBasicStringAlgo::Append(str, "DEF", 1, 3); + + TASSERT(str == "AEF", "Append() did not correctly append first string!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_BuildNumeric_Double() +{ + ZBasicString<> str; + + ZBasicStringAlgo::BuildNumeric(str, 0.0); + + TASSERT(str == "0.000000", "BuildNumeric() failed to build correct string!"); + + ZBasicStringAlgo::BuildNumeric(str, "%.2f", 0.0); + + TASSERT(str == "0.00", "BuildNumeric(double) failed to build correct formatted string!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_BuildNumeric_Int() +{ + ZBasicString<> str; + + ZBasicStringAlgo::BuildNumeric(str, 12345); + + TASSERT(str == "12345", "BuildNumeric() failed to build correct string!"); + + ZBasicStringAlgo::BuildNumeric(str, "%+i", 12345); + + TASSERT(str == "+12345", "BuildNumeric(int) failed to build correct formatted string!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_BuildPrintf() +{ + ZBasicString<> str; + + ZBasicStringAlgo::BuildPrintf(str, " %3ist ", 1); + TASSERT(str == " 1st ", "BuildPrintf() failed to produce correct formatted string!"); + + ZBasicStringAlgo::BuildPrintf(str, " %3i %3.1f %3i %3.1f %3i %3.1f %3i %3.1f %3i %3.1f %3i %3.1f %3i %3.1f %3i %3.1f %3i %3.1f %3i %3.1f %3i %3.1f %3i %3.1f %3i %3.1f %3i %3.1f %3i %3.1f %3i %3.1f %3i %3.1f %3i %3.1f %3i %3.1f %3i %3.1f %3i %3.1f %3i %3.1f %3i %3.1f %3i %3.1f %3i %3.1f ", 1, 2.0f, 1, 2.0f, 1, 2.0f, 1, 2.0f, 1, 2.0f, 1, 2.0f, 1, 2.0f, 1, 2.0f, 1, 2.0f, 1, 2.0f, 1, 2.0f, 1, 2.0f, 1, 2.0f, 1, 2.0f, 1, 2.0f, 1, 2.0f, 1, 2.0f, 1, 2.0f, 1, 2.0f, 1, 2.0f, 1, 2.0f, 1, 2.0f, 1, 2.0f, 1, 2.0f, 1, 2.0f); + TASSERT(str == " 1 2.0 1 2.0 1 2.0 1 2.0 1 2.0 1 2.0 1 2.0 1 2.0 1 2.0 1 2.0 1 2.0 1 2.0 1 2.0 1 2.0 1 2.0 1 2.0 1 2.0 1 2.0 1 2.0 1 2.0 1 2.0 1 2.0 1 2.0 1 2.0 1 2.0 ", "BuildPrintf() failed to produce correct formatted string 2!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_BuildRepeat() +{ + ZBasicString<> str; + + ZBasicStringAlgo::BuildRepeat(str, "abc", 5); + + TASSERT(str == "abcabcabcabcabc", "BuildRepeat() failed to build abc * 5!"); + + ZBasicStringAlgo::BuildRepeat(str, "", 20); + + TASSERT(str.Empty(), "BuildRepeat() failed to build empty string with '' * 20!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Contains() +{ + ZBasicString<> str("abcdef"); + + TASSERT(ZBasicStringAlgo::Contains(str, 'a'), "Contains('a') on 'abcdef' returns false!"); + TASSERT(ZBasicStringAlgo::Contains(str, 'b'), "Contains('b') on 'abcdef' returns false!"); + TASSERT(ZBasicStringAlgo::Contains(str, 'c'), "Contains('c') on 'abcdef' returns false!"); + TASSERT(ZBasicStringAlgo::Contains(str, 'd'), "Contains('d') on 'abcdef' returns false!"); + TASSERT(ZBasicStringAlgo::Contains(str, 'e'), "Contains('e') on 'abcdef' returns false!"); + TASSERT(ZBasicStringAlgo::Contains(str, 'f'), "Contains('f') on 'abcdef' returns false!"); + + TASSERT(!ZBasicStringAlgo::Contains(str, 'g'), "Contains('g') on 'abcdef' returns true!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Contains_Region() +{ + ZBasicString<> str("abcdef"); + + TASSERT(ZBasicStringAlgo::Contains(str, 'a', 0, 1), "Contains('a', 0, 1) on 'abcdef' returns false!"); + TASSERT(!ZBasicStringAlgo::Contains(str, 'b', 0, 1), "Contains('b', 0, 1) on 'abcdef' returns true!"); + TASSERT(ZBasicStringAlgo::Contains(str, 'c', 1, 3), "Contains('c, 1, 3') on 'abcdef' returns false!"); + TASSERT(!ZBasicStringAlgo::Contains(str, 'd', 0, 2), "Contains('d', 0, 2) on 'abcdef' returns true!"); + TASSERT(ZBasicStringAlgo::Contains(str, 'e', 4, 5), "Contains('e', 4, 5) on 'abcdef' returns false!"); + TASSERT(!ZBasicStringAlgo::Contains(str, 'f', 4, 5), "Contains('f', 4, 5) on 'abcdef' returns true!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_ContainsSub() +{ + ZBasicString<> str("abcdef"); + + TASSERT(ZBasicStringAlgo::ContainsSub(str, "a"), "ContainsSub('a') on 'abcdef' returns false!"); + TASSERT(ZBasicStringAlgo::ContainsSub(str, "ab"), "ContainsSub('ab') on 'abcdef' returns false!"); + TASSERT(ZBasicStringAlgo::ContainsSub(str, "abc"), "ContainsSub('abc') on 'abcdef' returns false!"); + TASSERT(ZBasicStringAlgo::ContainsSub(str, "abcd"), "ContainsSub('abcd') on 'abcdef' returns false!"); + TASSERT(ZBasicStringAlgo::ContainsSub(str, "abcde"), "ContainsSub('abcde') on 'abcdef' returns false!"); + TASSERT(ZBasicStringAlgo::ContainsSub(str, "abcdef"), "ContainsSub('abcdef') on 'abcdef' returns false!"); + + TASSERT(ZBasicStringAlgo::ContainsSub(str, "f"), "ContainsSub('f') on 'abcdef' returns false!"); + TASSERT(!ZBasicStringAlgo::ContainsSub(str, "ac"), "ContainsSub('ac') on 'abcdef' returns true!"); + TASSERT(ZBasicStringAlgo::ContainsSub(str, "bc"), "ContainsSub('abc') on 'abcdef' returns false!"); + TASSERT(!ZBasicStringAlgo::ContainsSub(str, "bde"), "ContainsSub('bde') on 'abcdef' returns true!"); + TASSERT(ZBasicStringAlgo::ContainsSub(str, "cdef"), "ContainsSub('cdef') on 'abcdef' returns false!"); + TASSERT(!ZBasicStringAlgo::ContainsSub(str, "cfed"), "ContainsSub('cfed') on 'abcdef' returns true!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_ContainsSub_Region() +{ + ZBasicString<> str("abcdef"); + + TASSERT(!ZBasicStringAlgo::ContainsSub(str, 1, 3, "a", 0, 1), "ContainsSub(1, 3, 'a', 0, 1) on 'abcdef' returns true!"); + TASSERT(ZBasicStringAlgo::ContainsSub(str, 0, 2, "ab", 0, 2), "ContainsSub(0, 2, 'ab', 0, 2) on 'abcdef' returns false!"); + TASSERT(ZBasicStringAlgo::ContainsSub(str, 1, 3, "abc", 1, 3), "ContainsSub(1, 3, 'abc', 1, 3) on 'abcdef' returns false!"); + TASSERT(!ZBasicStringAlgo::ContainsSub(str, 2, 6, "abcd", 0, 4), "ContainsSub(2, 6, 'abcd', 0, 4) on 'abcdef' returns true!"); + TASSERT(ZBasicStringAlgo::ContainsSub(str, 4, 6, "abcde", 4, 5), "ContainsSub(4, 6, 'abcde', 4, 5) on 'abcdef' returns false!"); + TASSERT(!ZBasicStringAlgo::ContainsSub(str, 0, 3, "abcdef", 0, 6), "ContainsSub(0, 3, 'abcdef', 0, 6) on 'abcdef' returns true!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Copy() +{ + ZBasicString<> str; + + ZBasicStringAlgo::Copy(str, "abcdef"); + + TASSERT(str.Empty(), "Copy('abcdef') failed to keep string!"); + + str.Copy("abcdef"); + + ZBasicStringAlgo::Copy(str, ""); + + TASSERT(str == "abcdef", "Copy('') failed to keep 'abcdef'!"); + + ZBasicStringAlgo::Copy(str, "cba"); + + TASSERT(str == "cbadef", "Copy('cba') did not copy correctly!"); + + ZBasicStringAlgo::Copy(str, "abcdefghijklmnopqrstuvwxyz"); + + TASSERT(str == "abcdef", "Copy('abcdefghijklmnopqrstuvwxyz') failed to copy just 'abcdef'!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Copy_Region() +{ + ZBasicString<> str("abcdef"); + + ZBasicStringAlgo::Copy(str, 2, 4, "dc", 0, 2); + + TASSERT(str == "abdcef", "Copy(2, 4, 'dc', 0, 2) region on string 'abcdef' failed to copy correct string!"); + + ZBasicStringAlgo::Copy(str, 1, 5, "wxyz", 1, 4); + + TASSERT(str == "axyzef", "Copy(1, 5, 'wxyz', 1, 4) region on string 'abdcef' failed to copy correct string!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_EndsWith() +{ + ZBasicString<> str("abcdef"); + + TASSERT(ZBasicStringAlgo::EndsWith(str, "f"), "EndsWith('f') with string 'abcdef' returns false!"); + TASSERT(ZBasicStringAlgo::EndsWith(str, "ef"), "EndsWith('ef') with string 'abcdef' returns false!"); + TASSERT(ZBasicStringAlgo::EndsWith(str, "def"), "EndsWith('def') with string 'abcdef' returns false!"); + TASSERT(ZBasicStringAlgo::EndsWith(str, "cdef"), "EndsWith('cdef') with string 'abcdef' returns false!"); + TASSERT(ZBasicStringAlgo::EndsWith(str, "bcdef"), "EndsWith('bcdef') with string 'abcdef' returns false!"); + TASSERT(ZBasicStringAlgo::EndsWith(str, "abcdef"), "EndsWith('abcdef') with string 'abcdef' returns false!"); + + TASSERT(!ZBasicStringAlgo::EndsWith(str, "e"), "EndsWith('e') with string 'abcdef' returns true!"); + TASSERT(!ZBasicStringAlgo::EndsWith(str, "df"), "EndsWith('e') with string 'abcdef' returns true!"); + TASSERT(!ZBasicStringAlgo::EndsWith(str, "1bcdef"), "EndsWith('1bcdef') with string 'abcdef' returns true!"); + TASSERT(!ZBasicStringAlgo::EndsWith(str, "123abcdef"), "EndsWith('123abcdef') with string 'abcdef' returns true!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_EndsWith_Region() +{ + ZBasicString<> str("abcdef"); + + TASSERT(ZBasicStringAlgo::EndsWith(str, 2, 4, "cd", 0, 2), "EndsWith(2, 4, 'cd', 0, 2) with string 'abcdef' returns false!"); + + TASSERT(!ZBasicStringAlgo::EndsWith(str, 2, 4, "cd", 0, 1), "EndsWith(2, 4, 'cd', 0, 1) with string 'abcdef' returns true!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Equal() +{ + ZBasicString<> str1("abc"); + ZBasicString<> str2("abcd"); + ZBasicString<> str3("ab"); + ZBasicString<> str4("ace"); + + TASSERT(ZBasicStringAlgo::Equal(str1, str1), "Equal('abc', 'abc') did not return true!"); + TASSERT(ZBasicStringAlgo::Equal(str1, str2), "Equal('abc', 'abcd') did not return true!"); + TASSERT(ZBasicStringAlgo::Equal(str1, str3), "Equal('abc', 'ab') did not return true!"); + TASSERT(!ZBasicStringAlgo::Equal(str1, str4), "Equal('abc', 'ace') did not return false!"); + + TASSERT(ZBasicStringAlgo::Equal(str2, str1), "Equal('abcd', 'abc') did not return true!"); + TASSERT(ZBasicStringAlgo::Equal(str2, str2), "Equal('abcd', 'abcd') did not return true!"); + TASSERT(ZBasicStringAlgo::Equal(str2, str3), "Equal('abcd', 'ab') did not return true!"); + TASSERT(!ZBasicStringAlgo::Equal(str2, str4), "Equal('abcd', 'ace') did not return false!"); + + TASSERT(ZBasicStringAlgo::Equal(str3, str1), "Equal('ab', 'abc') did not return true!"); + TASSERT(ZBasicStringAlgo::Equal(str3, str2), "Equal('ab', 'abcd') did not return true!"); + TASSERT(ZBasicStringAlgo::Equal(str3, str3), "Equal('ab', 'ab') did not return true!"); + TASSERT(!ZBasicStringAlgo::Equal(str3, str4), "Equal('ab', 'ace') did not return false!"); + + TASSERT(!ZBasicStringAlgo::Equal(str4, str1), "Equal('ace', 'abc') did not return false!"); + TASSERT(!ZBasicStringAlgo::Equal(str4, str2), "Equal('ace', 'abcd') did not return false!"); + TASSERT(!ZBasicStringAlgo::Equal(str4, str3), "Equal('ace', 'ab') did not return false!"); + TASSERT(ZBasicStringAlgo::Equal(str4, str4), "Equal('ace', 'ace') did not return true!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Equal_Region() +{ + ZBasicString<> str1("abc"); + ZBasicString<> str2("abcd"); + ZBasicString<> str3("ab"); + ZBasicString<> str4("ace"); + + TASSERT(ZBasicStringAlgo::Equal(str1, 1, 2, str2, 1, 2), "Equal('abc', 1, 2, 'abcd', 1, 2) did not return true!"); + + TASSERT(ZBasicStringAlgo::Equal(str1, 0, 2, str3, 0, 1), "Equal('abc', 0, 2, 'ab', 0, 1) did not return true!"); + + TASSERT(!ZBasicStringAlgo::Equal(str2, 1, 4, str1, 0, 3), "Equal('abcd', 1, 4, 'abc', 0, 3) returned true!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_EqualIgnoreCase() +{ + ZBasicString<> str1("abC"); + ZBasicString<> str2("ABcd"); + ZBasicString<> str3("aB"); + ZBasicString<> str4("aCE"); + + TASSERT(ZBasicStringAlgo::EqualIgnoreCase(str1, str1), "EqualIgnoreCase('abC', 'abc') did not return true!"); + TASSERT(ZBasicStringAlgo::EqualIgnoreCase(str1, str2), "EqualIgnoreCase('abC', 'ABcd') did not return true!"); + TASSERT(ZBasicStringAlgo::EqualIgnoreCase(str1, str3), "EqualIgnoreCase('abC', 'aB') did not return true!"); + TASSERT(!ZBasicStringAlgo::EqualIgnoreCase(str1, str4), "EqualIgnoreCase('abC', 'aCE') did not return false!"); + + TASSERT(ZBasicStringAlgo::EqualIgnoreCase(str2, str1), "EqualIgnoreCase('ABcd', 'abC') did not return true!"); + TASSERT(ZBasicStringAlgo::EqualIgnoreCase(str2, str2), "EqualIgnoreCase('ABcd', 'ABcd') did not return true!"); + TASSERT(ZBasicStringAlgo::EqualIgnoreCase(str2, str3), "EqualIgnoreCase('ABcd', 'aB') did not return true!"); + TASSERT(!ZBasicStringAlgo::EqualIgnoreCase(str2, str4), "EqualIgnoreCase('ABcd', 'aCE') did not return false!"); + + TASSERT(ZBasicStringAlgo::EqualIgnoreCase(str3, str1), "EqualIgnoreCase('aB', 'abC') did not return true!"); + TASSERT(ZBasicStringAlgo::EqualIgnoreCase(str3, str2), "EqualIgnoreCase('aB', 'ABcd') did not return true!"); + TASSERT(ZBasicStringAlgo::EqualIgnoreCase(str3, str3), "EqualIgnoreCase('aB', 'aB') did not return true!"); + TASSERT(!ZBasicStringAlgo::EqualIgnoreCase(str3, str4), "EqualIgnoreCase('aB', 'aCE') did not return false!"); + + TASSERT(!ZBasicStringAlgo::EqualIgnoreCase(str4, str1), "EqualIgnoreCase('aCE', 'abC') did not return false!"); + TASSERT(!ZBasicStringAlgo::EqualIgnoreCase(str4, str2), "EqualIgnoreCase('aCE', 'ABcd') did not return false!"); + TASSERT(!ZBasicStringAlgo::EqualIgnoreCase(str4, str3), "EqualIgnoreCase('aCE', 'aB') did not return false!"); + TASSERT(ZBasicStringAlgo::EqualIgnoreCase(str4, str4), "EqualIgnoreCase('aCE', 'aCE') did not return true!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_EqualIgnoreCase_Region() +{ + ZBasicString<> str1("abC"); + ZBasicString<> str2("ABcd"); + ZBasicString<> str3("aB"); + ZBasicString<> str4("aCE"); + + TASSERT(ZBasicStringAlgo::EqualIgnoreCase(str1, 1, 2, str2, 1, 2), "Equal('abc', 1, 2, 'abcd', 1, 2) did not return true!"); + + TASSERT(ZBasicStringAlgo::EqualIgnoreCase(str1, 0, 2, str3, 0, 1), "Equal('abc', 0, 2, 'ab', 0, 1) did not return true!"); + + TASSERT(!ZBasicStringAlgo::EqualIgnoreCase(str2, 1, 4, str1, 0, 3), "Equal('abcd', 1, 4, 'abc', 0, 3) returned true!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Fill() +{ + ZBasicString<> str1; + ZBasicString<> str2("abcdef"); + + ZBasicStringAlgo::Fill(str1, ' '); + ZBasicStringAlgo::Fill(str2, 'a'); + + TASSERT(str1.Empty(), "Fill(' ') on empty string did not leave empty string!"); + TASSERT(str2 == "aaaaaa", "Fill('a') on 'abcdef' did not create correct string!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Fill_Region() +{ + ZBasicString<> str("abcdef"); + + ZBasicStringAlgo::Fill(str, 'a', 2, 5); + + TASSERT(str == "abaaaf", "Fill('a', 2, 5) on string 'abcdef' did not produce correct string!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Find() +{ + ZBasicString<> str1; + ZBasicString<> str2("abcdef"); + ZBasicString<> str3("abcdefabcdef"); + + TASSERT(ZBasicStringAlgo::Find(str1, 'a', 0) == ZSTL::InvalidPos, "Find('a', 0) with empty string did not return InvalidPos!"); + TASSERT(ZBasicStringAlgo::Find(str1, 'a', 1) == ZSTL::InvalidPos, "Find('a', 1) with empty string did not return InvalidPos!"); + + TASSERT(ZBasicStringAlgo::Find(str2, 'a', 0) == 0, "Find('a', 0) with 'abcdef' did not return index 0!"); + TASSERT(ZBasicStringAlgo::Find(str2, 'a', 1) == ZSTL::InvalidPos, "Find('a', 1) with 'abcdef' did not return InvalidPos!"); + TASSERT(ZBasicStringAlgo::Find(str2, 'c', 0) == 2, "Find('c', 0) with 'abcdef' did not return index 2!"); + TASSERT(ZBasicStringAlgo::Find(str2, 'c', 1) == ZSTL::InvalidPos, "Find('a', 1) with 'abcdef' did not return InvalidPos!"); + TASSERT(ZBasicStringAlgo::Find(str2, 'f', 0) == 5, "Find('f', 0) with 'abcdef' did not return index 5!"); + TASSERT(ZBasicStringAlgo::Find(str2, 'f', 1) == ZSTL::InvalidPos, "Find('a', 1) with 'abcdef' did not return InvalidPos!"); + + TASSERT(ZBasicStringAlgo::Find(str3, 'a', 0) == 0, "Find('a', 0) with 'abcdef' did not return index 0!"); + TASSERT(ZBasicStringAlgo::Find(str3, 'a', 1) == 6, "Find('a', 1) with 'abcdef' did not return index 6!"); + TASSERT(ZBasicStringAlgo::Find(str3, 'c', 0) == 2, "Find('c', 0) with 'abcdef' did not return index 2!"); + TASSERT(ZBasicStringAlgo::Find(str3, 'c', 1) == 8, "Find('a', 1) with 'abcdef' did not return index 8!"); + TASSERT(ZBasicStringAlgo::Find(str3, 'f', 0) == 5, "Find('f', 0) with 'abcdef' did not return index 5!"); + TASSERT(ZBasicStringAlgo::Find(str3, 'f', 1) == 11, "Find('a', 1) with 'abcdef' did not return index 11!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Find_Region() +{ + ZBasicString<> str1; + ZBasicString<> str2("abcdef"); + ZBasicString<> str3("abcdefabcdef"); + + TASSERT(ZBasicStringAlgo::Find(str2, 'a', 0, 2, 4) == ZSTL::InvalidPos, "Find('a', 0, 2, 4) with 'abcdef' did not return InvalidPos!"); + TASSERT(ZBasicStringAlgo::Find(str2, 'a', 0, 0, 1) == 0, "Find('a', 0, 0, 1) with 'abcdef' did not return index 0!"); + + TASSERT(ZBasicStringAlgo::Find(str3, 'a', 1, 3, 7) == ZSTL::InvalidPos, "Find('a', 1, 3, 7) with string 'abcdefabcdef' did not return InvalidPos!"); + TASSERT(ZBasicStringAlgo::Find(str3, 'f', 1, 5, 12) == 11, "Find('f', 1, 5, 12) with string 'abcdefabcdef' did not return index 11!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_FindAll() +{ + ZBasicString<> str1; + ZBasicString<> str2("abcdef"); + ZBasicString<> str3("abcdefabcdef"); + + ZArray<size_t> results; + + results = ZBasicStringAlgo::FindAll(str1, 'a'); + TASSERT(results.Empty(), "FindAll('a') on empty string returned values!"); + + + results = ZBasicStringAlgo::FindAll(str2, 'a'); + TASSERT(results.Size() == 1, "FindAll('a') on string 'abcdef' returned incorrect number of results!"); + TASSERT(results[0] == 0, "FindAll('a') on string 'abcdef' returned incorrect result!"); + + results = ZBasicStringAlgo::FindAll(str2, 'b'); + TASSERT(results.Size() == 1, "FindAll('b') on string 'abcdef' returned incorrect number of results!"); + TASSERT(results[0] == 1, "FindAll('b') on string 'abcdef' returned incorrect result!"); + + results = ZBasicStringAlgo::FindAll(str2, 'c'); + TASSERT(results.Size() == 1, "FindAll('c') on string 'abcdef' returned incorrect number of results!"); + TASSERT(results[0] == 2, "FindAll('c') on string 'abcdef' returned incorrect result!"); + + results = ZBasicStringAlgo::FindAll(str2, 'd'); + TASSERT(results.Size() == 1, "FindAll('d') on string 'abcdef' returned incorrect number of results!"); + TASSERT(results[0] == 3, "FindAll('d') on string 'abcdef' returned incorrect result!"); + + results = ZBasicStringAlgo::FindAll(str2, 'e'); + TASSERT(results.Size() == 1, "FindAll('e') on string 'abcdef' returned incorrect number of results!"); + TASSERT(results[0] == 4, "FindAll('e') on string 'abcdef' returned incorrect result!"); + + results = ZBasicStringAlgo::FindAll(str2, 'f'); + TASSERT(results.Size() == 1, "FindAll('f') on string 'abcdef' returned incorrect number of results!"); + TASSERT(results[0] == 5, "FindAll('f') on string 'abcdef' returned incorrect result!"); + + results = ZBasicStringAlgo::FindAll(str2, 'g'); + TASSERT(results.Empty(), "FindAll('g') on string 'abcdef' returned values!"); + + + results = ZBasicStringAlgo::FindAll(str3, 'a'); + TASSERT(results.Size() == 2, "FindAll('a') on string 'abcdefabcdef' returned incorrect number of results!"); + TASSERT(results[0] == 0, "FindAll('a') on string 'abcdefabcdef' returned incorrect result!"); + TASSERT(results[1] == 6, "FindAll('a') on string 'abcdefabcdef' returned incorrect result!"); + + results = ZBasicStringAlgo::FindAll(str3, 'b'); + TASSERT(results.Size() == 2, "FindAll('b') on string 'abcdefabcdef' returned incorrect number of results!"); + TASSERT(results[0] == 1, "FindAll('b') on string 'abcdefabcdef' returned incorrect result!"); + TASSERT(results[1] == 7, "FindAll('b') on string 'abcdefabcdef' returned incorrect result!"); + + results = ZBasicStringAlgo::FindAll(str3, 'c'); + TASSERT(results.Size() == 2, "FindAll('c') on string 'abcdefabcdef' returned incorrect number of results!"); + TASSERT(results[0] == 2, "FindAll('c') on string 'abcdefabcdef' returned incorrect result!"); + TASSERT(results[1] == 8, "FindAll('c') on string 'abcdefabcdef' returned incorrect result!"); + + results = ZBasicStringAlgo::FindAll(str3, 'd'); + TASSERT(results.Size() == 2, "FindAll('d') on string 'abcdefabcdef' returned incorrect number of results!"); + TASSERT(results[0] == 3, "FindAll('d') on string 'abcdefabcdef' returned incorrect result!"); + TASSERT(results[1] == 9, "FindAll('d') on string 'abcdefabcdef' returned incorrect result!"); + + results = ZBasicStringAlgo::FindAll(str3, 'e'); + TASSERT(results.Size() == 2, "FindAll('e') on string 'abcdefabcdef' returned incorrect number of results!"); + TASSERT(results[0] == 4, "FindAll('e') on string 'abcdefabcdef' returned incorrect result!"); + TASSERT(results[1] == 10, "FindAll('e') on string 'abcdefabcdef' returned incorrect result!"); + + results = ZBasicStringAlgo::FindAll(str3, 'f'); + TASSERT(results.Size() == 2, "FindAll('f') on string 'abcdefabcdef' incorrect number of results!"); + TASSERT(results[0] == 5, "FindAll('f') on string 'abcdefabcdef' returned incorrect result!"); + TASSERT(results[1] == 11, "FindAll('f') on string 'abcdefabcdef' returned incorrect result!"); + + results = ZBasicStringAlgo::FindAll(str3, 'g'); + TASSERT(results.Empty(), "FindAll('g') on string 'abcdefabcdef' returned values!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_FindAll_Region() +{ + ZBasicString<> str1; + ZBasicString<> str2("abcdef"); + ZBasicString<> str3("abcdefabcdef"); + + ZArray<size_t> results; + + results = ZBasicStringAlgo::FindAll(str2, 'a', 2, 4); + TASSERT(results.Size() == 0, "FindAll('abcdef', 'a', 2, 4) returned too many results!"); + + results = ZBasicStringAlgo::FindAll(str2, 'c', 2, 4); + TASSERT(results.Size() == 1, "FindAll('abcdef', 'c', 2, 4) returned incorrect number of results!"); + TASSERT(results[0] == 2, "FindAll('abcdef', 'c', 2, 4) returned incorrect index!"); + + results = ZBasicStringAlgo::FindAll(str3, 'd', 2, 9); + TASSERT(results.Size() == 1, "FindAll('abcdef', 'd', 2, 9) returned incorrect number of results!"); + TASSERT(results[0] == 3, "FindAll('abcdef', 'd', 2, 9) returned incorrect index!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_FindAllOf() +{ + ZBasicString<> str1; + ZBasicString<> str2("abcdef"); + ZBasicString<> str3("abcdefabcdef"); + + ZArray<size_t> results; + + results = ZBasicStringAlgo::FindAllOf(str1, "acg"); + TASSERT(results.Empty(), "FindAllOf('acg') on empty string returned values!"); + + + results = ZBasicStringAlgo::FindAllOf(str2, "b"); + TASSERT(results.Size() == 1, "FindAllOf('b') on string 'abcdef' returned wrong number of results!"); + TASSERT(results[0] == 1, "FindAllOf('b') on string 'abcdef' returned incorrect results!"); + + results = ZBasicStringAlgo::FindAllOf(str2, "acg"); + TASSERT(results.Size() == 2, "FindAllOf('acg') on string 'abcdef' returned wrong number of results!"); + TASSERT(results[0] == 0, "FindAllOf('acg') on string 'abcdef' returned incorrect result!"); + TASSERT(results[1] == 2, "FindAllOf('acg') on string 'abcdef' returned incorrect result!"); + + results = ZBasicStringAlgo::FindAllOf(str2, "acgab"); + TASSERT(results.Size() == 3, "FindAllOf('acgab') on string 'abcdef' returned wrong number of results!"); + TASSERT(results[0] == 0, "FindAllOf('acgab') on string 'abcdef' returned incorrect result!"); + TASSERT(results[1] == 1, "FindAllOf('acgab') on string 'abcdef' returned incorrect result!"); + TASSERT(results[2] == 2, "FindAllOf('acgab') on string 'abcdef' returned incorrect result!"); + + results = ZBasicStringAlgo::FindAllOf(str2, "sr g"); + TASSERT(results.Empty(), "FindAllOf('sr g') on string 'abcdef' returned values!"); + + + results = ZBasicStringAlgo::FindAllOf(str3, "e"); + TASSERT(results.Size() == 2, "FindAllOf('e') on string 'abcdef' returned wrong number of results!"); + TASSERT(results[0] == 4, "FindAllOf('e') on string 'abcdef' returned incorrect results!"); + TASSERT(results[1] == 10, "FindAllOf('e') on string 'abcdef' returned incorrect results!"); + + results = ZBasicStringAlgo::FindAllOf(str3, "afk"); + TASSERT(results.Size() == 4, "FindAllOf('afk') on string 'abcdefabcdef' returned wrong number of results!"); + TASSERT(results[0] == 0, "FindAllOf('afk') on string 'abcdefabcdef' returned incorrect result!"); + TASSERT(results[1] == 5, "FindAllOf('afk') on string 'abcdefabcdef' returned incorrect result!"); + TASSERT(results[2] == 6, "FindAllOf('afk') on string 'abcdefabcdef' returned incorrect result!"); + TASSERT(results[3] == 11, "FindAllOf('afk') on string 'abcdefabcdef' returned incorrect result!"); + + results = ZBasicStringAlgo::FindAllOf(str3, "qrg "); + TASSERT(results.Empty(), "FindAllOf('qrg ') on string 'abcdefabcdef' returned values!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_FindAllOf_Region() +{ + ZBasicString<> str1; + ZBasicString<> str2("abcdef"); + ZBasicString<> str3("abcdefabcdef"); + + ZArray<size_t> results; + + results = ZBasicStringAlgo::FindAllOf(str2, 2, 4, "ab", 0, 2); + TASSERT(results.Size() == 0, "FindAll('abcdef', 2, 4, 'ab', 0, 2) returned too many results!"); + + results = ZBasicStringAlgo::FindAllOf(str2, 2, 4, "cde", 1, 3); + TASSERT(results.Size() == 1, "FindAll('abcdef', 2, 4, 'cde', 1, 3) returned incorrect number of results!"); + TASSERT(results[0] == 3, "FindAll('abcdef', 2, 4, 'cde', 1, 3) returned incorrect second index!"); + + results = ZBasicStringAlgo::FindAllOf(str3, 2, 9, "ade", 0, 2); + TASSERT(results.Size() == 2, "FindAll('abcdefabcdef', 2, 9, 'ade', 0, 2) returned incorrect number of results!"); + TASSERT(results[0] == 3, "FindAll('abcdefabcdef', 2, 9, 'ade', 0, 2) returned incorrect first index!"); + TASSERT(results[1] == 6, "FindAll('abcdefabcdef', 2, 9, 'ade', 0, 2) return incorrect second index!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_FindFirst() +{ + ZBasicString<> str1; + ZBasicString<> str2("abcdef"); + ZBasicString<> str3("abcdefabcdef"); + + TASSERT(ZBasicStringAlgo::FindFirst(str1, 'a') == ZSTL::InvalidPos, "FindFirst('a') on empty string did not return InvalidPos!"); + + TASSERT(ZBasicStringAlgo::FindFirst(str2, 'a') == 0, "FindFirst('a') on string 'abcdef' did not return index 0!"); + TASSERT(ZBasicStringAlgo::FindFirst(str2, 'b') == 1, "FindFirst('b') on string 'abcdef' did not return index 1!"); + TASSERT(ZBasicStringAlgo::FindFirst(str2, 'c') == 2, "FindFirst('c') on string 'abcdef' did not return index 2!"); + TASSERT(ZBasicStringAlgo::FindFirst(str2, 'd') == 3, "FindFirst('d') on string 'abcdef' did not return index 3!"); + TASSERT(ZBasicStringAlgo::FindFirst(str2, 'e') == 4, "FindFirst('e') on string 'abcdef' did not return index 4!"); + TASSERT(ZBasicStringAlgo::FindFirst(str2, 'f') == 5, "FindFirst('f') on string 'abcdef' did not return index 5!"); + + TASSERT(ZBasicStringAlgo::FindFirst(str2, 'g') == ZSTL::InvalidPos, "FindFirst('g') on string 'abcdef' did not return InvalidPos!"); + + TASSERT(ZBasicStringAlgo::FindFirst(str3, 'a') == 0, "FindFirst('a') on string 'abcdefabcdef' did not return index 0!"); + TASSERT(ZBasicStringAlgo::FindFirst(str3, 'b') == 1, "FindFirst('b') on string 'abcdefabcdef' did not return index 1!"); + TASSERT(ZBasicStringAlgo::FindFirst(str3, 'c') == 2, "FindFirst('c') on string 'abcdefabcdef' did not return index 2!"); + TASSERT(ZBasicStringAlgo::FindFirst(str3, 'd') == 3, "FindFirst('d') on string 'abcdefabcdef' did not return index 3!"); + TASSERT(ZBasicStringAlgo::FindFirst(str3, 'e') == 4, "FindFirst('e') on string 'abcdefabcdef' did not return index 4!"); + TASSERT(ZBasicStringAlgo::FindFirst(str3, 'f') == 5, "FindFirst('f') on string 'abcdefabcdef' did not return index 5!"); + + TASSERT(ZBasicStringAlgo::FindFirst(str3, 'g') == ZSTL::InvalidPos, "FindFirst('g') on string 'abcdefabcdef' did not return InvalidPos!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_FindFirst_Region() +{ + ZBasicString<> str1; + ZBasicString<> str2("abcdef"); + ZBasicString<> str3("abcdefabcdef"); + + TASSERT(ZBasicStringAlgo::FindFirst(str2, 'a', 2, 5) == ZSTL::InvalidPos, "FindFirst('abcdef', 'a', 2, 5) did not return InvalidPos!"); + TASSERT(ZBasicStringAlgo::FindFirst(str2, 'd', 2, 5) == 3, "FindFirst('abcdef', 'd', 2, 5) did not return index 3!"); + TASSERT(ZBasicStringAlgo::FindFirst(str3, 'c', 1, 11) == 2, "FindFirst('abcdefabcdef', 'c', 1, 11) did not return index 2!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_FindFirstOf() +{ + ZBasicString<> str1; + ZBasicString<> str2("abcdef"); + + TASSERT(ZBasicStringAlgo::FindFirstOf(str1, "abc") == ZSTL::InvalidPos, "FindFirstOf('abc') on empty string did not return InvalidPos!"); + + TASSERT(ZBasicStringAlgo::FindFirstOf(str2, "ace") == 0, "FindFirstOf('ace') on string 'abcdef' did not return index 0!"); + TASSERT(ZBasicStringAlgo::FindFirstOf(str2, "ce") == 2, "FindFirstOf('ce') on string 'abcdef' did not return index 2!"); + TASSERT(ZBasicStringAlgo::FindFirstOf(str2, "e") == 4, "FindFirstOf('e') on string 'abcdef' did not return index 4!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_FindFirstOf_Region() +{ + ZBasicString<> str1; + ZBasicString<> str2("abcdef"); + + TASSERT(ZBasicStringAlgo::FindFirstOf(str2, 2, 4, "ace", 0, 3) == 2, "FindFirstOf('abcdef', 2, 4, 'ace', 0, 3) did not return index 2!"); + TASSERT(ZBasicStringAlgo::FindFirstOf(str2, 0, 2, "ce", 0, 2) == ZSTL::InvalidPos, "FindFirstOf('abcdef', 0, 2, 'ce', 0, 2) did not return index InvalidPos!"); + TASSERT(ZBasicStringAlgo::FindFirstOf(str2, 1, 6, "e", 0, 1) == 4, "FindFirstOf('abcdef, 1, 6, 'e', 0, 1) did not return index 4!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_FindFirstNot() +{ + ZBasicString<> str1; + ZBasicString<> str2("abcdef"); + ZBasicString<> str3("aacdef"); + ZBasicString<> str4("aaadef"); + ZBasicString<> str5("aaaaef"); + ZBasicString<> str6("aaaaaf"); + ZBasicString<> str7("aaaaaa"); + + TASSERT(ZBasicStringAlgo::FindFirstNot(str1, 'a') == ZSTL::InvalidPos, "FindFirstNot('a') on empty string did not return InvalidPos!"); + TASSERT(ZBasicStringAlgo::FindFirstNot(str2, 'a') == 1, "FindFirstNot('a') on string 'abcdef' did not return index 1!"); + TASSERT(ZBasicStringAlgo::FindFirstNot(str3, 'a') == 2, "FindFirstNot('a') on string 'aacdef' did not return index 2!"); + TASSERT(ZBasicStringAlgo::FindFirstNot(str4, 'a') == 3, "FindFirstNot('a') on string 'aaadef' did not return index 3!"); + TASSERT(ZBasicStringAlgo::FindFirstNot(str5, 'a') == 4, "FindFirstNot('a') on string 'aaaaef' did not return index 4!"); + TASSERT(ZBasicStringAlgo::FindFirstNot(str6, 'a') == 5, "FindFirstNot('a') on string 'aaaaaf' did not return index 5!"); + TASSERT(ZBasicStringAlgo::FindFirstNot(str7, 'a') == ZSTL::InvalidPos, "FindFirstNot('a') on string 'aaaaaa' did not return InvalidPos!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_FindFirstNot_Region() +{ + ZBasicString<> str1; + ZBasicString<> str2("abcdef"); + ZBasicString<> str3("aacdef"); + ZBasicString<> str4("aaadef"); + + TASSERT(ZBasicStringAlgo::FindFirstNot(str2, 'a', 0, 1) == ZSTL::InvalidPos, "FindFirstNot('abcdef', 'a', 0, 1) did not return index InvalidPos!"); + TASSERT(ZBasicStringAlgo::FindFirstNot(str3, 'a', 1, 4) == 2, "FindFirstNot('abcdef', 'a', 1, 4) did not return index 2!"); + TASSERT(ZBasicStringAlgo::FindFirstNot(str4, 'a', 0, 4) == 3, "FindFirstNot('a') on string 'aaadef' did not return index 3!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_FindFirstNotOf() +{ + ZBasicString<> str1; + ZBasicString<> str2("abcdef"); + + TASSERT(ZBasicStringAlgo::FindFirstNotOf(str1, "abc") == ZSTL::InvalidPos, "FindFirstNotOf('abc') on empty string did not return InvalidPos!"); + + TASSERT(ZBasicStringAlgo::FindFirstNotOf(str2, " ") == 0, "FindFirstNotOf(' ') on string 'abcdef' did not return index 0!"); + TASSERT(ZBasicStringAlgo::FindFirstNotOf(str2, "a") == 1, "FindFirstNotOf('a') on string 'abcdef' did not return index 1!"); + TASSERT(ZBasicStringAlgo::FindFirstNotOf(str2, "ab") == 2, "FindFirstNotOf('ab') on string 'abcdef' did not return index 2!"); + TASSERT(ZBasicStringAlgo::FindFirstNotOf(str2, "abc") == 3, "FindFirstNotOf('abc') on string 'abcdef' did not return index 3!"); + TASSERT(ZBasicStringAlgo::FindFirstNotOf(str2, "abcd") == 4, "FindFirstNotOf('abcd') on string 'abcdef' did not return index 4!"); + TASSERT(ZBasicStringAlgo::FindFirstNotOf(str2, "abcde") == 5, "FindFirstNotOf('abcde') on string 'abcdef' did not return index 5!"); + TASSERT(ZBasicStringAlgo::FindFirstNotOf(str2, "abcdef") == ZSTL::InvalidPos, "FindFirstNotOf('abcdef') on string 'abcdef' did not return InvalidPos!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_FindFirstNotOf_Region() +{ + ZBasicString<> str1; + ZBasicString<> str2("abcdef"); + + TASSERT(ZBasicStringAlgo::FindFirstNotOf(str2, 2, 4, " ", 0, 1) == 2, "FindFirstNotOf('abcdef', 2, 4, ' ', 0 , 1) did not return index 2!"); + TASSERT(ZBasicStringAlgo::FindFirstNotOf(str2, 2, 4, "a", 0, 1) == 2, "FindFirstNotOf('abcdef', 2, 4, 'a', 0, 1) did not return index 2!"); + TASSERT(ZBasicStringAlgo::FindFirstNotOf(str2, 1, 6, "abcd", 1, 3) == 3, "FindFirstNotOf('abcdef', 1, 6, 'abcd', 1, 3) did not return index 3!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_FindLast() +{ + ZBasicString<> str1; + ZBasicString<> str2("abcdef"); + ZBasicString<> str3("abcdefabcdef"); + + TASSERT(ZBasicStringAlgo::FindLast(str1, 'a') == ZSTL::InvalidPos, "FindLast('a') on empty string did not return InvalidPos!"); + + TASSERT(ZBasicStringAlgo::FindLast(str2, 'a') == 0, "FindLast('a') on string 'abcdef' did not return index 0!"); + TASSERT(ZBasicStringAlgo::FindLast(str2, 'b') == 1, "FindLast('b') on string 'abcdef' did not return index 1!"); + TASSERT(ZBasicStringAlgo::FindLast(str2, 'c') == 2, "FindLast('c') on string 'abcdef' did not return index 2!"); + TASSERT(ZBasicStringAlgo::FindLast(str2, 'd') == 3, "FindLast('d') on string 'abcdef' did not return index 3!"); + TASSERT(ZBasicStringAlgo::FindLast(str2, 'e') == 4, "FindLast('e') on string 'abcdef' did not return index 4!"); + TASSERT(ZBasicStringAlgo::FindLast(str2, 'f') == 5, "FindLast('f') on string 'abcdef' did not return index 5!"); + + TASSERT(ZBasicStringAlgo::FindLast(str2, 'g') == ZSTL::InvalidPos, "FindLast('g') on string 'abcdef' did not return InvalidPos!"); + + TASSERT(ZBasicStringAlgo::FindLast(str3, 'a') == 6, "FindLast('a') on string 'abcdefabcdef' did not return index 6!"); + TASSERT(ZBasicStringAlgo::FindLast(str3, 'b') == 7, "FindLast('b') on string 'abcdefabcdef' did not return index 7!"); + TASSERT(ZBasicStringAlgo::FindLast(str3, 'c') == 8, "FindLast('c') on string 'abcdefabcdef' did not return index 8!"); + TASSERT(ZBasicStringAlgo::FindLast(str3, 'd') == 9, "FindLast('d') on string 'abcdefabcdef' did not return index 9!"); + TASSERT(ZBasicStringAlgo::FindLast(str3, 'e') == 10, "FindLast('e') on string 'abcdefabcdef' did not return index 10!"); + TASSERT(ZBasicStringAlgo::FindLast(str3, 'f') == 11, "FindLast('f') on string 'abcdefabcdef' did not return index 11!"); + + TASSERT(ZBasicStringAlgo::FindLast(str3, 'g') == ZSTL::InvalidPos, "FindLast('g') on string 'abcdefabcdef' did not return InvalidPos!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_FindLast_In_Region() +{ + ZBasicString<> str1; + ZBasicString<> str2("abcdef"); + ZBasicString<> str3("abcdefabcdef"); + + TASSERT(ZBasicStringAlgo::FindLast(str2, 'a', 2, 5) == ZSTL::InvalidPos, "FindLast('abcdef', 'a', 2, 5) did not return index InvalidPos!"); + TASSERT(ZBasicStringAlgo::FindLast(str2, 'b', 1, 3) == 1, "FindLast('abcdef', 'b', 1, 3) did not return index 1!"); + + TASSERT(ZBasicStringAlgo::FindLast(str3, 'a', 2, 9) == 6, "FindLast('abcdefabcdef', 'a', 2, 9) did not return index 6!"); + TASSERT(ZBasicStringAlgo::FindLast(str3, 'b', 1, 6) == 1, "FindLast('abcdefabcdef', 'b', 1, 6) did not return index 1!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_FindLastOf() +{ + ZBasicString<> str1; + ZBasicString<> str2("abcdef"); + ZBasicString<> str3("abcdefabcdef"); + + TASSERT(ZBasicStringAlgo::FindLastOf(str1, "abc") == ZSTL::InvalidPos, "FindLastOf('abc') on empty string did not return InvalidPos!"); + + TASSERT(ZBasicStringAlgo::FindLastOf(str2, "ace") == 4, "FindLastOf('ace') on string 'abcdef' did not return index 4!"); + TASSERT(ZBasicStringAlgo::FindLastOf(str2, "ac") == 2, "FindLastOf('ac') on string 'abcdef' did not return index 2!"); + TASSERT(ZBasicStringAlgo::FindLastOf(str2, "a") == 0, "FindLastOf('a') on string 'abcdef' did not return index 0!"); + + TASSERT(ZBasicStringAlgo::FindLastOf(str2, "ghijklmnop") == ZSTL::InvalidPos, "FindLastOf('ghijklmnop') on string 'abcdef' did not return InvalidPos!"); + + TASSERT(ZBasicStringAlgo::FindLastOf(str3, "ace") == 10, "FindLastOf('ace') on string 'abcdef' did not return index 10!"); + TASSERT(ZBasicStringAlgo::FindLastOf(str3, "ac") == 8, "FindLastOf('ac') on string 'abcdef' did not return index 8!"); + TASSERT(ZBasicStringAlgo::FindLastOf(str3, "a") == 6, "FindLastOf('a') on string 'abcdef' did not return index 6!"); + + TASSERT(ZBasicStringAlgo::FindLastOf(str3, "ghijklmnop") == ZSTL::InvalidPos, "FindLastOf('ghijklmnop') on string 'abcdefabcdef' did not return InvalidPos!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_FindLastOf_In_Region() +{ + ZBasicString<> str1; + ZBasicString<> str2("abcdef"); + ZBasicString<> str3("abcdefabcdef"); + + TASSERT(ZBasicStringAlgo::FindLastOf(str2, 2, 6, "ace", 0, 2) == 2, "FindLastOf('abcdef', 2, 6, 'ace', 0, 2) did not return index 2!"); + TASSERT(ZBasicStringAlgo::FindLastOf(str2, 0, 2, "ac", 0, 2) == 0, "FindLastOf('abcdef', 0, 2, 'ac', 0, 2) did not return index 0!"); + + TASSERT(ZBasicStringAlgo::FindLastOf(str3, 0, 6, "ace", 1, 3) == 4, "FindLastOf('abcdef', 0, 6, 'ace', 1, 3) did not return index 4!"); + TASSERT(ZBasicStringAlgo::FindLastOf(str3, 2, 11, "ac", 0, 2) == 8, "FindLastOf('abcdef', 2, 11, 'ac', 0, 2) did not return index 8!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_FindLastNot() +{ + ZBasicString<> str1; + ZBasicString<> str2("abcdef"); + ZBasicString<> str3("abcdff"); + ZBasicString<> str4("abcfff"); + ZBasicString<> str5("abffff"); + ZBasicString<> str6("afffff"); + ZBasicString<> str7("ffffff"); + + TASSERT(ZBasicStringAlgo::FindLastNot(str1, 'f') == ZSTL::InvalidPos, "FindLastNot('f') on empty string did not return InvalidPos!"); + TASSERT(ZBasicStringAlgo::FindLastNot(str2, 'f') == 4, "FindLastNot('f') on string 'abcdef' did not return index 4!"); + TASSERT(ZBasicStringAlgo::FindLastNot(str3, 'f') == 3, "FindLastNot('f') on string 'abcdff' did not return index 3!"); + TASSERT(ZBasicStringAlgo::FindLastNot(str4, 'f') == 2, "FindLastNot('f') on string 'abcfff' did not return index 2!"); + TASSERT(ZBasicStringAlgo::FindLastNot(str5, 'f') == 1, "FindLastNot('f') on string 'abffff' did not return index 1!"); + TASSERT(ZBasicStringAlgo::FindLastNot(str6, 'f') == 0, "FindLastNot('f') on string 'afffff' did not return index 0!"); + TASSERT(ZBasicStringAlgo::FindLastNot(str7, 'f') == ZSTL::InvalidPos, "FindLastNot('f') on string 'ffffff' did not return InvalidPos!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_FindLastNot_In_Region() +{ + ZBasicString<> str1; + ZBasicString<> str2("abcdef"); + ZBasicString<> str3("abcdff"); + + TASSERT(ZBasicStringAlgo::FindLastNot(str2, 'f', 2, 4) == 3, "FindLastNot('abcdef', 'f', 2, 4) did not return index 3!"); + TASSERT(ZBasicStringAlgo::FindLastNot(str3, 'f', 2, 5) == 3, "FindLastNot('abcdef', 'f', 2, 5) did not return index 3!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_FindLastNotOf() +{ + ZBasicString<> str1; + ZBasicString<> str2("abcdef"); + + TASSERT(ZBasicStringAlgo::FindLastNotOf(str1, "abc") == ZSTL::InvalidPos, "FindLastNotOf('abc') on empty string did not return InvalidPos!"); + + TASSERT(ZBasicStringAlgo::FindLastNotOf(str2, " ") == 5, "FindLastNotOf(' ') on string 'abcdef' did not return index 5!"); + TASSERT(ZBasicStringAlgo::FindLastNotOf(str2, "f") == 4, "FindLastNotOf('f') on string 'abcdef' did not return index 4!"); + TASSERT(ZBasicStringAlgo::FindLastNotOf(str2, "ef") == 3, "FindLastNotOf('ef') on string 'abcdef' did not return index 3!"); + TASSERT(ZBasicStringAlgo::FindLastNotOf(str2, "def") == 2, "FindLastNotOf('def') on string 'abcdef' did not return index 2!"); + TASSERT(ZBasicStringAlgo::FindLastNotOf(str2, "cdef") == 1, "FindLastNotOf('cdef') on string 'abcdef' did not return index 1!"); + TASSERT(ZBasicStringAlgo::FindLastNotOf(str2, "bcdef") == 0, "FindLastNotOf('bcdef') on string 'abcdef' did not return index 0!"); + TASSERT(ZBasicStringAlgo::FindLastNotOf(str2, "abcdef") == ZSTL::InvalidPos, "FindLastNotOf('abcdef') on string 'abcdef' did not return InvalidPos!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_FindLastNotOf_In_Region() +{ + ZBasicString<> str1; + ZBasicString<> str2("abcdef"); + + TASSERT(ZBasicStringAlgo::FindLastNotOf(str2, 2, 4, " ", 0, 1) == 3, "FindLastNotOf('abcdef', 2, 4, ' ', 0, 1) did not return index 3!"); + TASSERT(ZBasicStringAlgo::FindLastNotOf(str2, 2, 6, "f", 0, 1) == 4, "FindLastNotOf('abcdef', 2, 6, 'f', 0, 1) did not return index 4!"); + TASSERT(ZBasicStringAlgo::FindLastNotOf(str2, 3, 5, "ef", 0, 2) == 3, "FindLastNotOf('abcdef', 3, 5, 'ef', 0, 2) did not return index 3!"); + TASSERT(ZBasicStringAlgo::FindLastNotOf(str2, 1, 5, "def", 1, 2) == 3, "FindLastNotOf('abcdef', 1, 5, 'def', 1, 2) did not return index 3!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_FindSub() +{ + ZBasicString<> str1; + ZBasicString<> str2("abcdef"); + + TASSERT(ZBasicStringAlgo::FindSub(str1, "a") == ZSTL::InvalidPos, "FindSub('a') on empty string does not return InvalidPos!"); + + TASSERT(ZBasicStringAlgo::FindSub(str2, "a") == 0, "FindSub('a') on 'abcdef' does not return index 0!"); + TASSERT(ZBasicStringAlgo::FindSub(str2, "abc") == 0, "FindSub('abc') on 'abcdef' does not return index 0!"); + TASSERT(ZBasicStringAlgo::FindSub(str2, "abcdef") == 0, "FindSub('abcdef') on 'abcdef' does not return index 0!"); + TASSERT(ZBasicStringAlgo::FindSub(str2, "abcdefg") == ZSTL::InvalidPos, "FindSub('abcdefg') on 'abcdef' does not return InvalidPos!"); + + TASSERT(ZBasicStringAlgo::FindSub(str2, "bc") == 1, "FindSub('bc') on 'abcdef' does not return index 1!"); + TASSERT(ZBasicStringAlgo::FindSub(str2, "def") == 3, "FindSub('def') on 'abcdef' does not return index 3!"); + TASSERT(ZBasicStringAlgo::FindSub(str2, "efg") == ZSTL::InvalidPos, "FindSub('efg') on 'abcdef' does not return InvalidPos!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_FindSub_Region() +{ + ZBasicString<> str1; + ZBasicString<> str2("abcdef"); + + TASSERT(ZBasicStringAlgo::FindSub(str2, 0, 2, "abc", 1, 3) == ZSTL::InvalidPos, "FindSub(\"abcdef\", 0, 2, 'abc, 1, 3) does not return InvalidPos!"); + TASSERT(ZBasicStringAlgo::FindSub(str2, 0, 2, "abc", 0, 2) == 0, "FindSub('abcdef', 0, 2, 'abc', 0, 2) does not return index 0!"); + + TASSERT(ZBasicStringAlgo::FindSub(str2, 0, 4, "bc", 1, 2) == 2, "FindSub('abcdef, 0, 4, 'bc', 1, 2) does not return index 2!"); + TASSERT(ZBasicStringAlgo::FindSub(str2, 4, 6, "def", 1, 3) == 4, "FindSub('abcdef', 4, 6, 'def', 1, 3) does not return index 3!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_IsNumeric() +{ + ZBasicString<> str1; + ZBasicString<> str2("0"); + ZBasicString<> str3("12345"); + ZBasicString<> str4("0.0"); + ZBasicString<> str5("10.01"); + ZBasicString<> str6("-1.5"); + + ZBasicString<> str7("123.456.789"); + ZBasicString<> str8("NotANumber"); + ZBasicString<> str9("-1.45 "); + ZBasicString<> str10("50a00"); + + TASSERT(!ZBasicStringAlgo::IsNumeric(str1), "IsNumeric() returns true on empty string!"); + + TASSERT(ZBasicStringAlgo::IsNumeric(str2), "IsNumeric() returns false on '0'!"); + TASSERT(ZBasicStringAlgo::IsNumeric(str3), "IsNumeric() returns false on '12345'!"); + TASSERT(ZBasicStringAlgo::IsNumeric(str4), "IsNumeric() returns false on '0.0'!"); + TASSERT(ZBasicStringAlgo::IsNumeric(str5), "IsNumeric() returns false on '10.01'!"); + TASSERT(ZBasicStringAlgo::IsNumeric(str6), "IsNumeric() returns false on '-1.5'!"); + + TASSERT(!ZBasicStringAlgo::IsNumeric(str7), "IsNumeric() returns true on '123.456.789'!"); + TASSERT(!ZBasicStringAlgo::IsNumeric(str8), "IsNumeric() returns true on 'NotANumber'!"); + TASSERT(!ZBasicStringAlgo::IsNumeric(str9), "IsNumeric() returns true on '-1.45'!"); + TASSERT(!ZBasicStringAlgo::IsNumeric(str10), "IsNumeric() returns true on '50a00'!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_IsNumeric_Region() +{ + ZBasicString<> str7("123.456.789"); + ZBasicString<> str10("50a00"); + + TASSERT(ZBasicStringAlgo::IsNumeric(str7, 0, 3), "IsNumeric('123.456.789', 0, 3) does not return true!"); + TASSERT(ZBasicStringAlgo::IsNumeric(str7, 0, 6), "IsNumeric('123.456.789', 0, 6) does not return true!"); + TASSERT(!ZBasicStringAlgo::IsNumeric(str7, 2, 8), "IsNumeric(123.456.789, 2, 8) does not return false!"); + + TASSERT(ZBasicStringAlgo::IsNumeric(str10, 0, 2), "IsNumeric('50a00', 3, 4) does not return true!"); + TASSERT(ZBasicStringAlgo::IsNumeric(str10, 3, 4), "IsNumeric('50a00', 3, 4) does not return true!"); + TASSERT(!ZBasicStringAlgo::IsNumeric(str10, 2, 4), "IsNumeric('50a00', 2, 4) does not return false!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Remove() +{ + ZString teststr("abcde"); + + // remove nonexistant character + TASSERT( ZBasicStringAlgo::Remove(teststr, 'z') == ZSTL::InvalidPos, "Remove() claimed removal on nonpresent character!\n"); + TASSERT(teststr.Length() == 5, "Remove() created wrong size string!\n"); + + // remove from front + TASSERT( ZBasicStringAlgo::Remove(teststr, 'c') == 2, "Remove() claimed bad removal on existing character!\n"); + TASSERT(teststr.Length() == 4, "Remove() created wrong size string!\n"); + + // remove from front + TASSERT( ZBasicStringAlgo::Remove(teststr, 'a') == 0, "Remove() claimed bad removal on existing character\n"); + TASSERT(teststr.Length() == 3, "Remove() created wrong size string!\n"); + + // remove from back + TASSERT( ZBasicStringAlgo::Remove(teststr, 'e') == 2, "Remove() claimed bad removal on existing character\n"); + TASSERT(teststr.Length() == 2, "Remove() created wrong size string!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Remove_In_Region() +{ + ZString teststr("abccddde"); + + // remove nonexistant character + TASSERT( ZBasicStringAlgo::Remove(teststr, 'z',1,4) == ZSTL::InvalidPos, "Remove() claimed removal on nonpresent character!\n"); + TASSERT(teststr.Length() == 8, "Remove() created wrong size string!\n"); + + // remove from back out of range + TASSERT( ZBasicStringAlgo::Remove(teststr, 'd',1,4) == ZSTL::InvalidPos, "Remove() claimed removal on character not in region!\n"); + TASSERT(teststr.Length() == 8, "Remove() created wrong size string!\n"); + + // remove from back + TASSERT( ZBasicStringAlgo::Remove(teststr, 'c',1,4) == 2, "Remove() claimed bad removal on existing character!\n"); + TASSERT(teststr.Length() == 7, "Remove() created wrong size string!\n"); + + // remove from front out of range + TASSERT( ZBasicStringAlgo::Remove(teststr, 'a',1,4) == ZSTL::InvalidPos, "Remove() claimed removal on character not in region\n"); + TASSERT(teststr.Length() == 7, "Remove() created wrong size string!\n"); + + // remove from front + TASSERT( ZBasicStringAlgo::Remove(teststr, 'b', 1,4) == 1, "Remove() claimed bad removal on existing character\n"); + TASSERT(teststr.Length() == 6, "Remove() created wrong size string!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_RemoveAll() +{ + ZString teststr("aaabcccdeeee"); + + // remove nonexistant character + TASSERT( ZBasicStringAlgo::RemoveAll(teststr, 'z') == 0, "RemoveAll() claimed removal of nonpresent character!\n"); + TASSERT(teststr.Length() == 12, "Remove() created wrong size string!\n"); + + // remove from front + TASSERT( ZBasicStringAlgo::RemoveAll(teststr, 'c') == 3, "RemoveAll() claimed bad removal on existing character!\n"); + TASSERT(teststr.Length() == 9, "Remove() created wrong size string!\n"); + + // remove from front + TASSERT( ZBasicStringAlgo::RemoveAll(teststr, 'a') == 3, "RemoveAll() claimed bad removal on existing character\n"); + TASSERT(teststr.Length() == 6, "Remove() created wrong size string!\n"); + + // remove from back + TASSERT( ZBasicStringAlgo::RemoveAll(teststr, 'e') == 4, "RemoveAll() claimed bad removal on existing character\n"); + TASSERT(teststr.Length() == 2, "Remove() created wrong size string!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_RemoveAll_In_Region() +{ + ZString teststr("aaabcccdeeee"); + + // remove nonexistant character + TASSERT( ZBasicStringAlgo::RemoveAll(teststr, 'z', 1, 8) == 0, "RemoveAll() claimed removal of nonpresent character!\n"); + TASSERT( teststr.Equals("aaabcccdeeee"), "RemoveAll() produced incorrect string!\n"); + + // remove from middle + TASSERT( ZBasicStringAlgo::RemoveAll(teststr, 'c', 1, 8) == 3, "RemoveAll() claimed bad removal on existing character!\n"); + TASSERT( teststr.Equals("aaabdeeee"), "RemoveAll() produced incorrect string!\n"); + + // remove from front + TASSERT( ZBasicStringAlgo::RemoveAll(teststr, 'a', 1, 8) == 2, "RemoveAll() claimed bad removal on existing character\n"); + TASSERT( teststr.Equals("abdeeee"), "RemoveAll() produced incorrect string!\n"); + + // remove from back + TASSERT( ZBasicStringAlgo::RemoveAll(teststr, 'e', 1, 6) == 3, "RemoveAll() claimed bad removal on existing character\n"); + TASSERT( teststr.Equals("abde"), "RemoveAll() produced incorrect string!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_RemoveUpTo() +{ + ZString teststr("aaabcccdeeee"); + + // remove nonexistent character + TASSERT(ZBasicStringAlgo::RemoveUpTo(teststr, 'z', 1) == 0,"RemoveUpTo() removed nonexistent character!\n"); + TASSERT( teststr.Equals("aaabcccdeeee"), "RemoveUpTo() produced incorrect string!\n"); + + // remove from middle + TASSERT(ZBasicStringAlgo::RemoveUpTo(teststr, 'c', 2) == 2,"RemoveUpTo() removed incorrect amounts of character!\n"); + TASSERT( teststr.Equals("aaabcdeeee"), "RemoveUpTo() produced incorrect string!\n"); + + // remove from front + TASSERT(ZBasicStringAlgo::RemoveUpTo(teststr, 'a', 2) == 2,"RemoveUpTo() removed incorrect amounts of character!\n"); + TASSERT( teststr.Equals("abcdeeee"), "RemoveUpTo() produced incorrect string!\n"); + + // remove from back + TASSERT(ZBasicStringAlgo::RemoveUpTo(teststr, 'e', 4) == 4,"RemoveUpTo() removed incorrect amounts of character!\n"); + TASSERT( teststr.Equals("abcd"), "RemoveUpTo() produced incorrect string!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_RemoveUpTo_In_Region() +{ + ZString teststr("aaabcccdeeee"); + + // remove nonexistent character + TASSERT(ZBasicStringAlgo::RemoveUpTo(teststr, 'z', 1, 1, 8) == 0,"RemoveUpTo() removed nonexistent character!\n"); + TASSERT( teststr.Equals("aaabcccdeeee"), "RemoveUpTo() produced incorrect string!\n"); + + // remove from outside region + TASSERT(ZBasicStringAlgo::RemoveUpTo(teststr, 'e', 1, 1, 8) == 0,"RemoveUpTo() removed character from outside region!\n"); + TASSERT( teststr.Equals("aaabcccdeeee"), "RemoveUpTo() produced incorrect string!\n"); + + // remove from middle + TASSERT(ZBasicStringAlgo::RemoveUpTo(teststr, 'c', 2, 1, 8) == 2,"RemoveUpTo() removed incorrect amounts of character!\n"); + TASSERT( teststr.Equals("aaabcdeeee"), "RemoveUpTo() produced incorrect string!\n"); + + // remove from front + TASSERT(ZBasicStringAlgo::RemoveUpTo(teststr, 'a', 2, 1,8) == 2,"RemoveUpTo() removed incorrect amounts of character!\n"); + TASSERT( teststr.Equals("abcdeeee"), "RemoveUpTo() produced incorrect string!\n"); + + // remove from back + TASSERT(ZBasicStringAlgo::RemoveUpTo(teststr, 'e', 4,1,6) == 2,"RemoveUpTo() removed incorrect amounts of character!\n"); + TASSERT( teststr.Equals("abcdee"), "RemoveUpTo() produced incorrect string!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Replace() +{ + ZString teststr("aabbcc"); + + // replace nothing + ZBasicStringAlgo::Replace(teststr,'d','e'); + TASSERT(teststr.Equals("aabbcc"), "Replace() failed to leave string with no replacements alone!\n"); + + // replace in middle + ZBasicStringAlgo::Replace(teststr,'b','2'); + TASSERT(teststr.Equals("aa22cc"),"Replace() failed to correctly replace chars in middle of string!\n"); + + // replace in back + ZBasicStringAlgo::Replace(teststr,'a','1'); + TASSERT(teststr.Equals("1122cc"),"Replace() failed to correctly replace chars in front of string!\n"); + + // replace in front + ZBasicStringAlgo::Replace(teststr,'c','3'); + TASSERT(teststr.Equals("112233"),"Replace() failed to correctly replace chars in middle of string!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +#if 0 +static const char* test_ReplaceSub() +{ + // This function may need to be renamed. What it does is replace a substring of the hoststring with the substring of substr + // marked by start and end size_t + ZString hoststr("aabbcc"); + ZString substr("abc"); + + // replace in front + ZBasicStringAlgo::ReplaceSub(hoststr,0,3,substr,0,3); + TASSERT(hoststr.Equals("abcbcc"), "Replace() failed to correctly replace chars in front of string!\n"); + + // replace in middle + ZBasicStringAlgo::ReplaceSub(hoststr,1,4,substr,0,3); + TASSERT(hoststr.Equals("aabccc"), "Replace() failed to correctly replace chars in middle of string!\n"); + + // replace in back + ZBasicStringAlgo::ReplaceSub(hoststr,3,6,substr,0,3); + TASSERT(hoststr.Equals("aababc"), "Replace() failed to correctly replace chars in end of string!\n"); + + // replace entire string + ZString dullstring("zzzzzz"); + ZBasicStringAlgo::ReplaceSub(hoststr,0,6,dullstring,0,6); + TASSERT(hoststr.Equals("zzzzzz"), "Replace() failed to replace entire string with same length string!\n"); + + // replace entire string with shorter string + hoststr = "abcabc"; + ZBasicStringAlgo::ReplaceSub(hoststr,0,6,dullstring,0,3); + TASSERT(hoststr.Equals("zzz"), "Replace() failed to replace entire string with shorter string!\n"); + + // replace entire string with longer string + ZBasicStringAlgo::ReplaceSub(hoststr,0,3,dullstring,0,6); + TASSERT(hoststr.Equals("zzzzzz"), "Replace() failed to replace entire string with longer string!\n"); + + return ZTEST_SUCCESS; +} +#endif + +/*************************************************************************/ + +static const char* test_Replace_In_Region() +{ + ZString teststr("aabbcc"); + + // replace nothing + ZBasicStringAlgo::Replace(teststr,'d','e',1,5); + TASSERT(teststr.Equals("aabbcc"), "Replace() failed to leave string with no replacements alone!\n"); + + // replace in middle + ZBasicStringAlgo::Replace(teststr,'b','2',1,5); + TASSERT(teststr.Equals("aa22cc"),"Replace() failed to correctly replace chars in middle of string!\n"); + + // replace in back + ZBasicStringAlgo::Replace(teststr,'a','1',1,5); + TASSERT(teststr.Equals("a122cc"),"Replace() failed to correctly replace chars in front of string!\n"); + + // replace in front + ZBasicStringAlgo::Replace(teststr,'c','3',1,5); + TASSERT(teststr.Equals("a1223c"),"Replace() failed to correctly replace chars in middle of string!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Reverse() +{ + ZString testempty; + ZString teststr("aabbcc"); + + // test reverse empty string + ZBasicStringAlgo::Reverse(testempty); + TASSERT(testempty.Equals(""), "Reverse() on empty string resulted in broken string!\n"); + + // test on normal string + ZBasicStringAlgo::Reverse(teststr); + TASSERT(teststr.Equals("ccbbaa"), "Reverse() created incorrect string!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Reverse_Region() +{ + ZString testempty; + ZString teststr("aabbcc"); + + // test on normal string + ZBasicStringAlgo::Reverse(teststr,1,5); + TASSERT(teststr.Equals("acbbac"), "Reverse() created incorrect string!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Slice() +{ + ZString emptystr; + ZString teststr("aaabbbccc"); + ZString slice; + + // slice an empty string + slice = ZBasicStringAlgo::Slice(emptystr,0,0); + TASSERT(slice.Empty(), "Slice() on empty string returned nonempty slice!\n"); + TASSERT(emptystr.Empty(), "Slice() on empy string returned nonempty remainder!\n"); + + // make an empty slice + slice = ZBasicStringAlgo::Slice(teststr,0,0); + TASSERT(slice.Empty(), "Zero-length Slice() on string returned wrong slice!\n"); + TASSERT(teststr.Equals("aaabbbccc"), "Slice() on string returned wrong remainder!\n"); + + // make a whole-length slice + slice = ZBasicStringAlgo::Slice(teststr,0,teststr.Length()); + TASSERT(slice.Equals("aaabbbccc"), "Full-length Slice() on string returned wrong slice!\n"); + TASSERT(teststr.Empty(), "Slice() on string returned wrong remainder!\n"); + + // slice off the back + teststr = ZString("aaabbbccc"); + slice = ZBasicStringAlgo::Slice(teststr,3,teststr.Length()); + TASSERT(slice.Equals("bbbccc"), "Slice() on string returned wrong slice!\n"); + TASSERT(teststr.Equals("aaa"), "Slice() on string returned wrong remainder!\n"); + + // slice off the front + teststr = ZString("aaabbbccc"); + slice = ZBasicStringAlgo::Slice(teststr, 0, 3); + TASSERT(slice.Equals("aaa"), "Slice() on string returned wrong slice!\n"); + TASSERT(teststr.Equals("bbbccc"), "Slice() on string returned wrong remainder!\n"); + + // slice off the middle + teststr = ZString("aaabbbccc"); + slice = ZBasicStringAlgo::Slice(teststr, 3, 6); + TASSERT(slice.Equals("bbb"), "Slice() on string returned wrong slice!\n"); + TASSERT(teststr.Equals("aaaccc"), "Slice() on string returned wrong remainder!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Split() +{ + ZString emptystr; + ZString teststr; + ZArray< ZString > ret; + + // test on empty string + ret = ZBasicStringAlgo::Split(emptystr, ",;"); + TASSERT(ret.Empty(), "Split() created nonempty array for empty string!\n"); + + // test on legit string with no delimiters on ends + teststr = ZString("aaa,bbb;ccc;ddd,eee"); + ret = ZBasicStringAlgo::Split(teststr, ",;"); + TASSERT(teststr.Equals("aaa,bbb;ccc;ddd,eee"), "Split() harmed underlying string!\n"); + TASSERT(ret.Size() == 5, "Split() created array of wrong size for string!\n"); + TASSERT(ret.At(0).Equals("aaa"), "Split() created wrong string for section!\n"); + TASSERT(ret.At(1).Equals("bbb"), "Split() created wrong string for section!\n"); + TASSERT(ret.At(2).Equals("ccc"), "Split() created wrong string for section!\n"); + TASSERT(ret.At(3).Equals("ddd"), "Split() created wrong string for section!\n"); + TASSERT(ret.At(4).Equals("eee"), "Split() created wrong string for section!\n"); + + // test on legit string with extra delimiters + teststr = ZString(",aaa,bbb;ccc;"); + ret = ZBasicStringAlgo::Split(teststr, ",;"); + TASSERT(teststr.Equals(",aaa,bbb;ccc;"), "Split() harmed underlying string!\n"); + TASSERT(ret.Size() == 3, "Split() created array of wrong size for string!\n"); + TASSERT(ret.At(0).Equals("aaa"), "Split() created wrong string for section!\n"); + TASSERT(ret.At(1).Equals("bbb"), "Split() created wrong string for section!\n"); + TASSERT(ret.At(2).Equals("ccc"), "Split() created wrong string for section!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Split_Count() +{ + ZString emptystr; + ZString teststr; + ZArray< ZString > ret; + + // test on legit string with no delimiters on ends + teststr = ZString("aaa,bbb;ccc;ddd,eee"); + ret = ZBasicStringAlgo::Split(teststr, ",;", 2); + TASSERT(teststr.Equals("aaa,bbb;ccc;ddd,eee"), "Split() harmed underlying string!\n"); + TASSERT(ret.Size() == 3, "Split() created array of wrong size for string!\n"); + TASSERT(ret.At(0).Equals("aaa"), "Split() created wrong string for section!\n"); + TASSERT(ret.At(1).Equals("bbb"), "Split() created wrong string for section!\n"); + TASSERT(ret.At(2).Equals("ccc;ddd,eee"), "Split() created wrong string for section!\n"); + + // test on legit string with extra delimiters + teststr = ZString(",aaa,bbb;;;ccc;"); + ret = ZBasicStringAlgo::Split(teststr, ",;", 2); + TASSERT(teststr.Equals(",aaa,bbb;;;ccc;"), "Split() harmed underlying string!\n"); + TASSERT(ret.Size() == 3, "Split() created array of wrong size for string given count!\n"); + TASSERT(ret.At(0).Equals("aaa"), "Split() created wrong string for section!\n"); + TASSERT(ret.At(1).Equals("bbb"), "Split() created wrong string for section!\n"); + // note that the below is expected because we had finished our two splits and stopped looking for delimiters + TASSERT(ret.At(2).Equals(";;ccc;"), "Split() created wrong string for section!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Split_Count_Region() +{ + ZString emptystr; + ZString teststr; + ZArray< ZString > ret; + + // test on legit string with no delimiters on ends + teststr = ZString("aaa,bbb;ccc;ddd,eee"); + ret = ZBasicStringAlgo::Split(teststr, ",;", 2, 5, teststr.Length() - 1); + TASSERT(teststr.Equals("aaa,bbb;ccc;ddd,eee"), "Split() harmed underlying string!\n"); + TASSERT(ret.Size() == 3, "Split() created array of wrong size for string!\n"); + TASSERT(ret.At(0).Equals("bb"), "Split() created wrong string for section!\n"); + TASSERT(ret.At(1).Equals("ccc"), "Split() created wrong string for section!\n"); + TASSERT(ret.At(2).Equals("ddd,ee"), "Split() created wrong string for section!\n"); + + // test on legit string with extra delimiters + teststr = ZString(",aaa,bbb;ccc;"); + ret = ZBasicStringAlgo::Split(teststr, ",;", 2, 3, teststr.Length()-2); + TASSERT(teststr.Equals(",aaa,bbb;ccc;"), "Split() harmed underlying string!\n"); + TASSERT(ret.Size() == 3, "Split() created array of wrong size for string given count!\n"); + TASSERT(ret.At(0).Equals("a"), "Split() created wrong string for section!\n"); + TASSERT(ret.At(1).Equals("bbb"), "Split() created wrong string for section!\n"); + TASSERT(ret.At(2).Equals("cc"), "Split() created wrong string for section!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_StartsWith() +{ + ZString testempty; + ZString teststr("aaabbbccc"); + + // empty string with empty startstring + TASSERT( ZBasicStringAlgo::StartsWith(testempty, "") == false, "StartsWith() claimed empty string started with empty string!"); + + // empty string with empty startstring + TASSERT( ZBasicStringAlgo::StartsWith(testempty, "aaa") == false, "StartsWith() claimed empty string started with nonempty string!"); + + // string with empty startstring + TASSERT( ZBasicStringAlgo::StartsWith(teststr, "") == false, "StartsWith() claimed string started with empty string!\n"); + + // string with wrong startstring + TASSERT( ZBasicStringAlgo::StartsWith(teststr, "bbbb") == false, "StartsWith() claimed string started with empty string!\n"); + + // string with truncated startstring + TASSERT( ZBasicStringAlgo::StartsWith(teststr, "aa") == true, "StartsWith() claimed string not started with truncated string!\n"); + + // string with overlong startstring + TASSERT( ZBasicStringAlgo::StartsWith(teststr, "aaaa") == false, "StartsWith() claimed string started with overlong string!\n"); + + // string with correct startstring + TASSERT( ZBasicStringAlgo::StartsWith(teststr,"aaa") == true, "StartsWith() failed to match start string correctly!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_StartsWith_Region() +{ + ZString testempty; + ZString teststr("aaabbbccc"); + + // empty string with empty startstring + TASSERT( ZBasicStringAlgo::StartsWith(testempty, 0, testempty.Length(), "", 0, 0) == false, "StartsWith() claimed empty string started with empty string!"); + + // empty string with empty startstring + TASSERT( ZBasicStringAlgo::StartsWith(testempty, 0, testempty.Length(), "aaaa", 1, 3) == false, "StartsWith() claimed empty string started with nonempty string!"); + + // string with empty startstring + TASSERT( ZBasicStringAlgo::StartsWith(teststr, 1, teststr.Length(), "", 0, 0) == false, "StartsWith() claimed string started with empty string!\n"); + + // string with wrong startstring + TASSERT( ZBasicStringAlgo::StartsWith(teststr, 1, teststr.Length(), "bbbb", 1, 3) == false, "StartsWith() claimed string started with empty string!\n"); + + // string with truncated startstring + TASSERT( ZBasicStringAlgo::StartsWith(teststr, 1, teststr.Length(), "aaaa", 1, 2) == true, "StartsWith() claimed string not started with truncated string!\n"); + + // string with overlong startstring + TASSERT( ZBasicStringAlgo::StartsWith(teststr, 1, teststr.Length(), "aaaa", 1, 4) == false, "StartsWith() claimed string started with overlong string!\n"); + + // string with correct startstring + TASSERT( ZBasicStringAlgo::StartsWith(teststr, 1, teststr.Length(), "aaaa", 1, 3) == true, "StartsWith() failed to match start string correctly!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Strip() +{ + ZString testempty; + ZString teststr(" ab\t\t c d "); + + TASSERT(ZBasicStringAlgo::Strip(testempty) == 0, "Strip() attempted to remove characters from empty string!\n"); + TASSERT(testempty.Equals(""), "Strip() broke empty string!\n"); + + TASSERT(ZBasicStringAlgo::Strip(teststr) == 7, "Strip() removed wrong number of characters!\n"); + TASSERT(teststr.Equals("abcd"), "Strip() created wrong string!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Strip_Region() +{ + ZString testempty; + ZString teststr(" ab\t\t c d "); + + TASSERT(ZBasicStringAlgo::Strip(testempty ,0 ,0) == 0, "Strip() attempted to remove characters from empty string!\n"); + TASSERT(testempty.Equals(""), "Strip() broke empty string!\n"); + + TASSERT(ZBasicStringAlgo::Strip(teststr, 1, 10) == 5, "Strip() removed wrong number of characters!\n"); + TASSERT(teststr.Equals(" abcd "), "Strip() created wrong string!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Tokenize() +{ + ZString testempty; + ZString testcsv(",a,b,c,d,"); + ZString tok; + + // check empty string + tok = ZBasicStringAlgo::Tokenize(testempty,","); + TASSERT(tok.Empty(),"Tokenize() on empty string returned nonempty string!\n"); + + // check empty delimiter string + tok = ZBasicStringAlgo::Tokenize(testcsv, ""); + TASSERT( tok.Equals(",a,b,c,d,"), "Tokenize() with empty delimiters returned wrong string!\n"); + TASSERT( testcsv.Empty(), "Tokenize() with empty delimiters did not consume whole string!\n"); + + // check delimited string + testcsv = ZString(",a,b,c,d,"); + tok = ZBasicStringAlgo::Tokenize(testcsv,","); + TASSERT(tok.Equals(""),"Tokenize() produced wrong token!\n"); + TASSERT(testcsv.Equals("a,b,c,d,"),"Tokenize() produced wrong remainder!\n"); + + tok = ZBasicStringAlgo::Tokenize(testcsv,","); + TASSERT(tok.Equals("a"),"Tokenize() produced wrong token!\n"); + TASSERT(testcsv.Equals("b,c,d,"),"Tokenize() produced wrong remainder!\n"); + + tok = ZBasicStringAlgo::Tokenize(testcsv,","); + TASSERT(tok.Equals("b"),"Tokenize() produced wrong token!\n"); + TASSERT(testcsv.Equals("c,d,"),"Tokenize() produced wrong remainder!\n"); + + tok = ZBasicStringAlgo::Tokenize(testcsv,","); + TASSERT(tok.Equals("c"),"Tokenize() produced wrong token!\n"); + TASSERT(testcsv.Equals("d,"),"Tokenize() produced wrong remainder!\n"); + + tok = ZBasicStringAlgo::Tokenize(testcsv,","); + TASSERT(tok.Equals("d"),"Tokenize() produced wrong token!\n"); + TASSERT(testcsv.Equals(""),"Tokenize() produced wrong remainder!\n"); + + // check delimited empty strings + testcsv = ZString(",,;;"); + tok = ZBasicStringAlgo::Tokenize(testcsv,",;"); + TASSERT(tok.Equals(""),"Tokenize() produced wrong token!\n"); + TASSERT(testcsv.Equals(",;;"),"Tokenize() produced wrong remainder!\n"); + + tok = ZBasicStringAlgo::Tokenize(testcsv,",;"); + TASSERT(tok.Equals(""),"Tokenize() produced wrong token!\n"); + TASSERT(testcsv.Equals(";;"),"Tokenize() produced wrong remainder!\n"); + + tok = ZBasicStringAlgo::Tokenize(testcsv,",;"); + TASSERT(tok.Equals(""),"Tokenize() produced wrong token!\n"); + TASSERT(testcsv.Equals(";"),"Tokenize() produced wrong remainder!\n"); + + tok = ZBasicStringAlgo::Tokenize(testcsv,",;"); + TASSERT(tok.Equals(""),"Tokenize() produced wrong token!\n"); + TASSERT(testcsv.Equals(""),"Tokenize() produced wrong remainder!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_ToLower() +{ + ZString testempty; + ZString teststr("AaBbCc"); + + ZBasicStringAlgo::ToLower(testempty); + TASSERT(testempty.Equals(""), "ToLower() produced bad result on empty string!\n"); + + ZBasicStringAlgo::ToLower(teststr); + TASSERT(teststr.Equals("aabbcc"), "ToLower() produced bad result on mixed string!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_ToLower_Region() +{ + ZString testempty; + ZString teststr("AaBbCcDdEe"); + + ZBasicStringAlgo::ToLower(testempty,0,0); + TASSERT(testempty.Equals(""), "ToLower() produced bad result on empty string!\n"); + + ZBasicStringAlgo::ToLower(teststr,2,8); + TASSERT(teststr.Equals("AabbccddEe"), "ToLower() produced bad result on mixed string!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_ToUpper() +{ + ZString testempty; + ZString teststr("AaBbCc"); + + ZBasicStringAlgo::ToUpper(testempty); + TASSERT(testempty.Equals(""), "ToUpper() produced bad result on empty string!\n"); + + ZBasicStringAlgo::ToUpper(teststr); + TASSERT(teststr.Equals("AABBCC"), "ToUpper() produced bad result on mixed string!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_ToUpper_Region() +{ + ZString testempty; + ZString teststr("AaBbCcDdEe"); + + ZBasicStringAlgo::ToUpper(testempty,0,0); + TASSERT(testempty.Equals(""), "ToUpper() produced bad result on empty string!\n"); + + ZBasicStringAlgo::ToUpper(teststr,2,8); + TASSERT(teststr.Equals("AaBBCCDDEe"), "ToUpper() produced bad result on mixed string!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_TrimLeft() +{ + ZString testempty; + ZString teststr(" test "); + + TASSERT(ZBasicStringAlgo::TrimLeft(testempty) == 0, "TrimLeft() removed nonzero characters from empty string!"); + TASSERT(testempty.Empty(), "TrimLeft() broke empty string!\n"); + + TASSERT(ZBasicStringAlgo::TrimLeft(teststr) == 2, "TrimLeft() removed wrong number of characters!\n"); + TASSERT(teststr.Equals("test "), "TrimLeft() produced incorrect string!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_TrimLeft_Region() +{ + ZString testempty; + ZString teststr(" test "); + + TASSERT(ZBasicStringAlgo::TrimLeft(testempty,0,0) == 0, "TrimLeft() removed nonzero characters from empty string!"); + TASSERT(testempty.Empty(), "TrimLeft() broke empty string!\n"); + + TASSERT(ZBasicStringAlgo::TrimLeft(teststr,1,7) == 1, "TrimLeft() removed wrong number of characters!\n"); + TASSERT(teststr.Equals(" test "), "TrimLeft() produced incorrect string!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_TrimRight() +{ + ZString testempty; + ZString teststr(" test "); + + TASSERT(ZBasicStringAlgo::TrimRight(testempty) == 0, "TrimRight() removed nonzero characters from empty string!"); + TASSERT(testempty.Empty(), "TrimRight() broke empty string!\n"); + + TASSERT(ZBasicStringAlgo::TrimRight(teststr) == 2, "TrimRight() removed wrong number of characters!\n"); + TASSERT(teststr.Equals(" test"), "TrimRight() produced incorrect string!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_TrimRight_Region() +{ + ZString testempty; + ZString teststr(" test "); + + TASSERT(ZBasicStringAlgo::TrimRight(testempty,0,0) == 0, "TrimRight() removed nonzero characters from empty string!"); + TASSERT(testempty.Empty(), "TrimRight() broke empty string!\n"); + + TASSERT(ZBasicStringAlgo::TrimRight(teststr,1,7) == 1, "TrimRight() removed wrong number of characters!\n"); + TASSERT(teststr.Equals(" test "), "TrimRight() produced incorrect string!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Trim() +{ + ZString testempty; + ZString teststr(" test "); + + TASSERT(ZBasicStringAlgo::Trim(testempty) == 0, "Trim() removed nonzero characters from empty string!"); + TASSERT(testempty.Empty(), "Trim() broke empty string!\n"); + + TASSERT(ZBasicStringAlgo::Trim(teststr) == 4, "Trim() removed wrong number of characters!\n"); + TASSERT(teststr.Equals("test"), "Trim() produced incorrect string!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Trim_Region() +{ + ZString testempty; + ZString teststr(" test "); + + TASSERT(ZBasicStringAlgo::Trim(testempty,0,0) == 0, "Trim() removed nonzero characters from empty string!"); + TASSERT(testempty.Empty(), "Trim() broke empty string!\n"); + + TASSERT(ZBasicStringAlgo::Trim(teststr,1,7) == 2, "Trim() removed wrong number of characters!\n"); + TASSERT(teststr.Equals(" test "), "Trim() produced incorrect string!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + diff --git a/ZTestSuite/Test-ZBinaryDataWriter.cpp b/ZTestSuite/Test-ZBinaryDataWriter.cpp new file mode 100644 index 0000000..41b750a --- /dev/null +++ b/ZTestSuite/Test-ZBinaryDataWriter.cpp @@ -0,0 +1,244 @@ +/* + Test-ZTransform.cpp +Author: Charles Lena <cmlena@762studios.com> +Created: 3/29/2012 + +Purpose: + +Tests to ensure that the math transform routines function accurately. +*/ + +#include "ZUnitTest.hpp" +#include <stdio.h> +#include <stdlib.h> +#include <climits> +#include <cfloat> +#include <math.h> +#include <SST/SST_File.h> +#include <ZUtil/ZBinaryDataWriter.hpp> + +inline bool fpcomp(float typed_1, float typed_2, float tol = FLT_EPSILON) { + return (abs(typed_1 - typed_2) <= tol); +} +inline bool dpcomp(double typed_1, double typed_2, double tol = DBL_EPSILON) { + return (abs(typed_1 - typed_2) <= tol); +} +/* class ZBinaryDataWriter +{ +protected: + SST_File file; + bool swapEndian; + +public: + ZBinaryDataWriter( SST_File _file, bool _swapEndian = false) + : file(_file), swapEndian(_swapEndian) + { + } + + ~ZBinaryDataWriter() {} + + bool GetWillSwap(); + void SetWillSwap( bool _swap ); + + void WriteChar( const char _out); + inline void WriteInt8( const int8_t _out) { WriteChar( _out); } + void WriteInt16( const int16_t _out); + void WriteInt32( const int32_t _out); + void WriteInt64( const int64_t _out); + void WriteUInt16( const uint16_t _out); + void WriteUInt32( const uint32_t _out); + void WriteUInt64( const uint64_t _out); + void WriteFloat( const float _out); + void WriteDouble( const double _out); + + void WriteCharArray( const char* _out, size_t _count); + void WriteInt16Array( const int16_t* _out, size_t _count); + void WriteInt32Array( const int32_t* _out, size_t _count); + void WriteInt64Array( const int64_t* _out, size_t _count); + void WriteUInt16Array( const uint16_t* _out, size_t _count); + void WriteUInt32Array( const uint32_t* _out, size_t _count); + void WriteUInt64Array( const uint64_t* _out, size_t _count); + void WriteFloatArray( const float* _out, size_t _count); + void WriteDoubleArray( const double* _out, size_t _count); +}; */ +static const char* testGetWillSwap(); +static const char* testSetWillSwap(); +static const char* testWriteChar(); +static const char* testWriteChar(); +static const char* testWriteInt16(); +static const char* testWriteInt32(); +static const char* testWriteInt64(); +static const char* testWriteUInt16(); +static const char* testWriteUInt32(); +static const char* testWriteUInt64(); +static const char* testWriteFloat(); +static const char* testWriteDouble(); +static const char* testWriteCharArray(); +static const char* testWriteInt16Array(); +static const char* testWriteInt32Array(); +static const char* testWriteInt64Array(); +static const char* testWriteUInt16Array(); +static const char* testWriteUInt32Array(); +static const char* testWriteUInt64Array(); +static const char* testWriteFloatArray(); +static const char* testWriteDoubleArray(); + +//List of unit tests +ZUnitTest ZBinaryDataWriterUnitTests[] = +{ +{"testGetWillSwap",testGetWillSwap}, +{"testSetWillSwap",testSetWillSwap}, +{"testWriteChar",testWriteChar}, +{"testWriteChar",testWriteChar}, +{"testWriteInt16",testWriteInt16}, +{"testWriteInt32",testWriteInt32}, +{"testWriteInt64",testWriteInt64}, +{"testWriteUInt16",testWriteUInt16}, +{"testWriteUInt32",testWriteUInt32}, +{"testWriteUInt64",testWriteUInt64}, +{"testWriteFloat",testWriteFloat}, +{"testWriteDouble",testWriteDouble}, +{"testWriteCharArray",testWriteCharArray}, +{"testWriteInt16Array",testWriteInt16Array}, +{"testWriteInt32Array",testWriteInt32Array}, +{"testWriteInt64Array",testWriteInt64Array}, +{"testWriteUInt16Array",testWriteUInt16Array}, +{"testWriteUInt32Array",testWriteUInt32Array}, +{"testWriteUInt64Array",testWriteUInt64Array}, +{"testWriteFloatArray",testWriteFloatArray}, +{"testWriteDoubleArray",testWriteDoubleArray}, +}; + +DECLARE_ZTESTBLOCK(ZBinaryDataWriter); + +// ======================================= +#include <stdio.h> +#if SST_COMPILER == SST_COMPILER_MSVC +#pragma warning(push) +#pragma warning(disable:4127) +#endif +static const char* testGetWillSwap(){ + SST_File File; + bool result; + File = SST_OS_OpenFile("test.dat",SST_OPEN_WRITE); + ZBinaryDataWriter Z( File , false); + result = Z.GetWillSwap(); + SST_OS_CloseFile(File); + + + TASSERT(result == false,"GetWillSwap() failed to detect false!"); + return ZTEST_SUCCESS; +} +static const char* testSetWillSwap(){ + SST_File File; + bool result; + File = SST_OS_OpenFile("test.dat",SST_OPEN_WRITE); + ZBinaryDataWriter Z( File , false); + Z.SetWillSwap(true); + result = Z.GetWillSwap(); + SST_OS_CloseFile(File); + + + TASSERT(result == true,"SetWillSwap() failed to detect true!"); + return ZTEST_SUCCESS; +} +static const char* testWriteChar(){ + SST_File File; + bool result; + File = SST_OS_OpenFile("char.dat",SST_OPEN_WRITE); + ZBinaryDataWriter Z( File , false); + Z.WriteChar('C'); + SST_OS_CloseFile(File); + + + TASSERT(result == false,"WriteChar() failed to detect false!"); + return ZTEST_SUCCESS; +} +static const char* testWriteInt16(){ + bool result; + + TASSERT(result == false,"WriteInt16() failed to produce desired results!"); + return ZTEST_SUCCESS; +} +static const char* testWriteInt32(){ + TASSERT(false,"WriteInt32() failed to produce the desired results!"); + return ZTEST_SUCCESS; +} +static const char* testWriteInt64(){ + + TASSERT(false,"Test Not Implemented Yet!"); + return ZTEST_SUCCESS; +} +static const char* testWriteUInt16(){ + + TASSERT(false,"Test Not Implemented Yet!"); + return ZTEST_SUCCESS; +} +static const char* testWriteUInt32(){ + + TASSERT(false,"Test Not Implemented Yet!"); + return ZTEST_SUCCESS; +} +static const char* testWriteUInt64(){ + + TASSERT(false,"Test Not Implemented Yet!"); + return ZTEST_SUCCESS; +} +static const char* testWriteFloat(){ + + TASSERT(false,"Test Not Implemented Yet!"); + return ZTEST_SUCCESS; +} +static const char* testWriteDouble(){ + + TASSERT(false,"Test Not Implemented Yet!"); + return ZTEST_SUCCESS; +} +static const char* testWriteCharArray(){ + + TASSERT(false,"Test Not Implemented Yet!"); + return ZTEST_SUCCESS; +} +static const char* testWriteInt16Array(){ + + TASSERT(false,"Test Not Implemented Yet!"); + return ZTEST_SUCCESS; +} +static const char* testWriteInt32Array(){ + + TASSERT(false,"Test Not Implemented Yet!"); + return ZTEST_SUCCESS; +} +static const char* testWriteInt64Array(){ + + TASSERT(false,"Test Not Implemented Yet!"); + return ZTEST_SUCCESS; +} +static const char* testWriteUInt16Array(){ + + TASSERT(false,"Test Not Implemented Yet!"); + return ZTEST_SUCCESS; +} +static const char* testWriteUInt32Array(){ + + TASSERT(false,"Test Not Implemented Yet!"); + return ZTEST_SUCCESS; +} +static const char* testWriteUInt64Array(){ + + TASSERT(false,"Test Not Implemented Yet!"); + return ZTEST_SUCCESS; +} +static const char* testWriteFloatArray(){ + + TASSERT(false,"Test Not Implemented Yet!"); + return ZTEST_SUCCESS; +} +static const char* testWriteDoubleArray(){ + + TASSERT(false,"Test Not Implemented Yet!"); + return ZTEST_SUCCESS; +} +#if SST_COMPILER == SST_COMPILER_MSVC +#pragma warning(pop) +#endif diff --git a/ZTestSuite/Test-ZConcurrency.cpp b/ZTestSuite/Test-ZConcurrency.cpp new file mode 100644 index 0000000..ab3a6a6 --- /dev/null +++ b/ZTestSuite/Test-ZConcurrency.cpp @@ -0,0 +1,241 @@ +/* + Test-ZConcurrency.cpp + Author: Patrick Baggett + + Purpose : Unit tests for ZConcurrency implementation to ensure correct behavior + + Changelog : + 12/18/2011 - Removed dependency on ZString (crertel) + 5/15/2011 - Created (ptbaggett) +*/ + +#include "ZUnitTest.hpp" +#include <stdio.h> +#include <stdlib.h> +#include <ZUtil/ZConcurrency.hpp> + +static const char* testCreateThread(); +static const char* testSleepGetTicks(); +static const char* testUncontLockUnlockMutex(); +static const char* testContLockUnlockMutex(); +static const char* testUncontSema(); +static const char* testContSema(); + +#define NRTHR 16 +#define NRITER 10000 + +//List of unit tests +ZUnitTest ZConcurrencyUnitTests[] = +{ + { "CreateThread()/WaitThread()", testCreateThread }, + { "Sleep()/GetTicks()", testSleepGetTicks }, + { "Uncontested LockMutex()/UnlockMutex()", testUncontLockUnlockMutex }, + { "Heavily contested LockMutex/UnlockMutex()", testContLockUnlockMutex }, + { "Uncontested Semaphore", testUncontSema }, + { "Heavily contested Semaphore", testContSema } + +}; + +DECLARE_ZTESTBLOCK(ZConcurrency); + +/*************************************************************************/ + +static const char* testThread1Data; +static int testThread1(void* arg) +{ + unsigned int* val = (unsigned int*)arg; + + if(*val == 0xAABBCCDD) + testThread1Data = ZTEST_SUCCESS; + else + testThread1Data = "Error with CreateThread()'s argument passing"; + + return 0x11223344; +} + +static const char* testCreateThread() +{ + ZThreadContext ctx; + int arg = 0xAABBCCDD; + + ctx = ZConcurrency::CreateThread(testThread1, &arg); + + TASSERT(ctx.IsValid(), "CreateThread() returned invalid thread context"); + + ZConcurrency::WaitThread(ctx); + + int thrRetVal = ctx.ThreadExitStatus; + + TASSERT(thrRetVal == 0x11223344, "WaitThread() returned wrong value"); + + ZConcurrency::DestroyThread(ctx); + + TASSERT(!ctx.IsValid(), "ZThreadContext is valid after DestroyThread()"); + + return testThread1Data; +} + +/*************************************************************************/ + +static const char* testSleepGetTicks() +{ + uint64_t timeStart, timeEnd; + + timeStart = ZConcurrency::GetTicks(); + ZConcurrency::SleepThread(1000); + timeEnd = ZConcurrency::GetTicks(); + + TASSERT(timeStart < timeEnd, "GetTicks() not monotonically increasing"); + + //We can't require precisely 1,000ms, but we do require it as a lower bound + TASSERT(timeEnd - timeStart >= 1000, "GetTicks() reports < 1000ms elapsed, but SleepThread(1000) called."); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* testUncontLockUnlockMutex() +{ + //Basically, if this crashes, then FAIL + ZMutex lock; + + //TASSERT(lock != NULL, "CreateMutex() returned null pointer"); + + //Lock/unlock a bunch. This should be fast since it is uncontested. + //Mainly, we're checking here to see if lock/unlock repeatedly triggers a crash + for(int i=0; i<1000; i++) + { + lock.Acquire(); + lock.Release(); + } + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static ZMutex testContLock; + +static int testContFunc(void* arg) +{ + int* inc = (int*) arg; + + for(int i=0; i<NRITER; i++) + { + testContLock.Acquire(); + *inc += 1; + testContLock.Release(); + } + + return 0; +} + +static const char* testContLockUnlockMutex() +{ + ZThreadContext threads[NRTHR]; + int arg = 0; + + for(int i=0; i<NRTHR; i++) + threads[i] = ZConcurrency::CreateThread(testContFunc, &arg); + + for(int i=0; i<NRTHR; i++) + { + ZConcurrency::WaitThread(threads[i]); + ZConcurrency::DestroyThread(threads[i]); + } + + TASSERT(arg == NRTHR * NRITER, "Invalid counter value, mutex not functioning") + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* testUncontSema() +{ + ZSemaphore sem(3); + bool ok = true; + + //TASSERT(sem != NULL, "CreateSemaphore() failed"); + + //Decrement count back down to 0 from 3 + ok = ok && sem.Wait(ZWAIT_INFINITE); + TASSERT(ok, "First WaitSemaphore() failed"); + ok = ok && sem.Wait(ZWAIT_INFINITE); + TASSERT(ok, "Second WaitSemaphore() failed"); + ok = ok && sem.Wait(ZWAIT_INFINITE); + TASSERT(ok, "Third WaitSemaphore() failed"); + + //This should immediately return with a failure message + ok = sem.Wait(0); + TASSERT(!ok, "sem.Wait() with count of 0 succeeded, but should have failed."); + + //Post to the semaphore, the decrement it again + sem.Post(2); + ok = sem.Wait(ZWAIT_INFINITE); + TASSERT(ok, "First sem.Wait() after PostSemaphore() failed"); + ok = ok && sem.Wait(ZWAIT_INFINITE); + TASSERT(ok, "Second sem.Wait() after PostSemaphore() failed"); + + //This should immediately return with a failure message + ok = sem.Wait(0); + TASSERT(!ok, "sem.Wait() (second round) with count of 0 succeeded, but should have failed."); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ +static volatile int testContSemaCounter; +static ZMutex testContSemaLock; + +#include <ZUtil/ZConcurrency.hpp> +static int testContSemaFunc(void* arg) +{ + ZSemaphore* sem = (ZSemaphore*)arg; + bool ok; + do + { + ok = sem->Wait(0); + if (ok) + { + testContSemaLock.Acquire(); + testContSemaCounter++; + testContSemaLock.Release(); + } + } while(ok); + + return 0; +} + +static const char* testContSema() +{ + ZThreadContext thread[NRTHR]; + + + + //sem = ZConcurrency::CreateSemaphore(NRITER); + //testContSemaLock = ZConcurrency::CreateMutex(); + + //Run 50 batches of this test just in case there might be a race condition + for(int j = 0; j < 50; j++) + { + ZSemaphore sem(NRITER); + testContSemaCounter = 0; + + //Create a bunch of threads. + for(int i=0; i<NRTHR; i++) + thread[i] = ZConcurrency::CreateThread(testContSemaFunc, &sem); + + //Wait and close their contexts + for(int i = 0; i < NRTHR; i++) + { + ZConcurrency::WaitThread(thread[i]); + ZConcurrency::DestroyThread(thread[i]); + } + TASSERT(testContSemaCounter == NRITER, "Counter after semaphore is incorrect"); + TASSERT(sem.Wait(0) == false, "Semaphore still had non-zero count!"); + } + + return ZTEST_SUCCESS; +} \ No newline at end of file diff --git a/ZTestSuite/Test-ZHashMap.cpp b/ZTestSuite/Test-ZHashMap.cpp new file mode 100644 index 0000000..6c4b118 --- /dev/null +++ b/ZTestSuite/Test-ZHashMap.cpp @@ -0,0 +1,388 @@ +/* + Test-ZHashMap.cpp + Author: James Russell <jcrussell@762studios.com> + + Purpose: Unit Test the ZHashMap class. + + Changelog: + 12/18/2011 - Removed dependency on ZString (crertel) + 03/13/2011 - creation (jcrussell) +*/ + +#include "ZUnitTest.hpp" + +#include <ZSTL/ZHashMap.hpp> +#include <ZSTL/ZString.hpp> + +static const char* testPutGetSize(); +static const char* testBeginEnd(); +static const char* testFind(); +static const char* testClearEmpty(); +static const char* testContainsKey(); +static const char* testContainsValue(); +static const char* testKeys(); +static const char* testValues(); +static const char* testMappings(); +static const char* testErase(); +static const char* testResize(); + +//List of unit tests +ZUnitTest ZHashMapUnitTests[] = +{ + { "ZHashMap: Put, Get, Size", testPutGetSize }, + { "ZHashMap: Begin, End", testBeginEnd }, + { "ZHashMap: Find", testFind }, + { "ZHashMap: Clear, Empty", testClearEmpty }, + { "ZHashMap: ContainsKey", testContainsKey }, + { "ZHashMap: ContainsValue", testContainsValue }, + { "ZHashMap: Keys", testKeys }, + { "ZHashMap: Values", testValues }, + { "ZHashMap: Mappings", testMappings }, + { "ZHashMap: Erase", testErase }, + { "ZHashMap: Resize", testResize } +}; + +//Now declare the ZUnitTestBlock associated with this. +DECLARE_ZTESTBLOCK(ZHashMap); + +typedef ZHashMap<ZString, int> StringIntMap; + +/*************************************************************************/ + +static const char* testPutGetSize() +{ + StringIntMap map; + + TASSERT(map.Size() == 0, "Size() returns non-zero value after initialization!"); + + map.Put("wakka", 24); + map.Put("ooga", 42); + + TASSERT(map.Size() == 2, "Size() returned incorrect value after 2 calls to Put()!"); + TASSERT(map.Get("wakka") == 24, "Get('wakka') retrieved wrong value after 2 calls to Put()!"); + TASSERT(map.Get("ooga") == 42, "Get('ooga') retrieved wrong value after 2 calls to Put()!"); + + map.Put("booga", 2442); + map.Put("wooga", 4224); + + TASSERT(map.Size() == 4, "Size() returned incorrect value after 4 calls to Put()!"); + TASSERT(map.Get("wakka") == 24, "Get('wakka') retrieved wrong value after 4 calls to Put()!"); + TASSERT(map.Get("ooga") == 42, "Get('ooga') retrieved wrong value after 4 calls to Put()!"); + TASSERT(map.Get("booga") == 2442, "Get('booga') retrieved wrong value after 4 calls to Put()!"); + TASSERT(map.Get("wooga") == 4224, "Get('wooga') retrieved wrong value after 4 calls to Put()!!"); + + //TODO - a bit more rigor + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* testBeginEnd() +{ + StringIntMap map; + bool found[4] = { false, false, false, false }; + + map.Put("wakka", 24); + map.Put("ooga", 42); + + StringIntMap::Iterator itr_begin = map.Begin(); + StringIntMap::Iterator itr_end = map.End(); + + for (; itr_begin != itr_end; itr_begin++) + { + if ((*itr_begin).Key == "wakka") + { + TASSERT((*itr_begin).Value == 24, "'wakka' iterator returned wrong value!"); + TASSERT(found[0] == false, "Already found value 'wakka'!"); + found[0] = true; + continue; + } + + if ((*itr_begin).Key == "ooga") + { + TASSERT((*itr_begin).Value == 42, "'ooga' iterator returned wrong value!"); + TASSERT(found[1] == false, "Already found value 'ooga'!"); + found[1] = true; + continue; + } + + TASSERT_FAIL("Iterator returned invalid value after two calls to Put()!"); + } + + TASSERT(found[0] && found[1], "Iterator did not find both values!"); + + found[0] = false; + found[1] = false; + + map.Put("booga", 2442); + map.Put("wooga", 4224); + + itr_begin = map.Begin(); + + while (itr_begin.HasCurrent()) + { + if ((*itr_begin).Key == "wakka") + { + TASSERT((*itr_begin).Value == 24, "'wakka' iterator returned wrong value!"); + TASSERT(found[0] == false, "Already found value 'wakka'!"); + found[0] = true; + itr_begin.Next(); + continue; + } + + if ((*itr_begin).Key == "ooga") + { + TASSERT((*itr_begin).Value == 42, "'ooga' iterator returned wrong value!"); + TASSERT(found[1] == false, "Already found value 'ooga'!"); + found[1] = true; + itr_begin.Next(); + continue; + } + + if ((*itr_begin).Key == "booga") + { + TASSERT((*itr_begin).Value == 2442, "'booga' iterator returned wrong value!"); + TASSERT(found[2] == false, "Already found value 'wooga'!"); + found[2] = true; + itr_begin.Next(); + continue; + } + + if ((*itr_begin).Key == "wooga") + { + TASSERT((*itr_begin).Value == 4224, "'wooga' iterator returned wrong value!"); + TASSERT(found[3] == false, "Already found value 'wooga'!"); + found[3] = true; + itr_begin.Next(); + continue; + } + + TASSERT_FAIL("Iterator returned invalid value after four calls to Put()!"); + } + + TASSERT(found[0] && found[1] && found[2] && found[3], "Iterator did not find all four values!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* testFind() +{ + StringIntMap map; + + map.Put("wakka", 24); + map.Put("ooga", 42); + + StringIntMap::Iterator itr = map.Find("wakka"); + + TASSERT(itr != map.End(), "Find('wakka') returned End()!"); + TASSERT((*itr).Key == "wakka", "Find('wakka') returned incorrect iterator key!"); + TASSERT((*itr).Value == 24, "Find('wakka') returned incorrect iterator value!"); + + itr = map.Find("ooga"); + + TASSERT(itr != map.End(), "Find('ooga') returned End()!"); + TASSERT((*itr).Key == "ooga", "Find('ooga') returned incorrect iterator key!"); + TASSERT((*itr).Value == 42, "Find('ooga') returned incorrect iterator value!"); + + itr = map.Find("woogawakka"); + + TASSERT(itr == map.End(), "Find('oogawakka') returned a valid iterator!"); + + //TODO - a bit more rigor + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* testClearEmpty() +{ + StringIntMap map; + + map.Put("wakka", 24); + map.Put("ooga", 42); + map.Put("booga", 2442); + map.Put("wooga", 4224); + + TASSERT(map.Size() == 4, "Size() returned incorrect value after 4 calls to Put()!"); + TASSERT(!map.Empty(), "Empty() returns true after 4 calls to Put()!"); + + map.Clear(); + + TASSERT(map.Size() == 0, "Size() returned non-zero value after call to Clear()!"); + TASSERT(map.Empty(), "Empty() returns false after Clear()!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* testContainsKey() +{ + StringIntMap map; + + TASSERT(map.ContainsKey("wakka") == false, "ContainsKey() returned true when given empty set"); + + map.Put("oonga",2); + TASSERT(map.ContainsKey("wakka") == false, "ContainsKey() returned true when given set missing key"); + + map.Put("wakka",1); + TASSERT(map.ContainsKey("wakka"), "ContainsKey() returned false when given set containing key"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* testContainsValue() +{ + StringIntMap map; + + map.Put("wakka", 1); + map.Put("wakkawakka", 2); + + TASSERT(map.ContainsValue(3) == false, "ContainsValue() claims to contain a value it doesn't have"); + TASSERT(map.ContainsValue(2) == true, "ContainsValue() claims to contain a value it does have"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* testKeys() +{ + StringIntMap map; + + const char* test[3] = {"wakka", "wakkawakka", "wakkawakkawakka"}; + + map.Put(test[0], 11); + map.Put(test[1], 22); + map.Put(test[2], 33); + + ZList<ZString> keys; + + map.Keys(keys); + + TASSERT(keys.Size() == 3, "Keys() did not return accurate sized list of keys in hashmap."); + + int found = 0; + for (ZList<ZString>::Iterator itr = keys.Begin(); itr != keys.End(); ++itr) + { + ZString tofind = *itr; + for (int i = 0; i < 3; i++) + { + if (strcmp(tofind.Data(), test[i]) == 0) + found++; + } + } + + TASSERT(found == 3, "Keys() did not return accurate list of keys for values in hashmap."); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* testValues() +{ + StringIntMap map; + + int test[3] = {11, 22, 33}; + + map.Put("wakka", test[0]); + map.Put("wakkawakka", test[1]); + map.Put("wakkawakkawakka", test[2]); + + ZList<int> values; + + map.Values(values); + + TASSERT(values.Size() == 3, "Values() did not return accurate sized list of values in hashmap."); + + int found = 0; + for (ZList<int>::Iterator itr = values.Begin(); itr != values.End(); ++itr) + { + int tofind = *itr; + for (int i = 0; i < 3; i++) + { + if (tofind == test[i]) + found++; + } + } + + TASSERT(found == 3, "Values() did not return accurate list of values for values in hashmap."); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* testMappings() +{ + StringIntMap map; + + map.Put("wakka", 11); + + ZList< ZPair<ZString, int> > mappings; + + map.Mappings(mappings); + + TASSERT(mappings.Size() == 1, "Mappings() returned list of incorrect size for key/value pairs.n"); + TASSERT( strcmp(mappings.Front().First.Data(), "wakka") == 0 && mappings.Front().Second == 11, "Mappings() returned incorrect key/value pair."); + + //TODO - more rigor + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* testErase() +{ + StringIntMap map; + + map.Put("wakka", 1); + TASSERT(map.ContainsValue(1) && map.ContainsKey("wakka"), "Map has somehow lost our value."); + + map.Erase("wakka"); + TASSERT(map.ContainsValue(1) == false && map.ContainsKey("wakka") == false, "Map claims key despite removal."); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* testResize() +{ + StringIntMap map(5); + + map.Put("wakka", 1); + map.Put("oonga", 2); + + size_t wakkaBucket = (*map.Find("wakka")).HashMod; + size_t oongaBucket = (*map.Find("oonga")).HashMod; + + StringIntMap::Iterator itr1 = map.Find("wakka"); + StringIntMap::Iterator itr2 = map.Find("oonga"); + + TASSERT(itr1 != map.End(), "Could not find 'wakka' before resize!"); + TASSERT(itr2 != map.End(), "Could not find 'oonga' before resize!"); + + map.Resize(11); + + itr1 = map.Find("wakka"); + itr2 = map.Find("oonga"); + + TASSERT(itr1 != map.End(), "Could not find 'wakka' after resize!"); + TASSERT(itr2 != map.End(), "Could not find 'oonga' after resize!"); + + TASSERT((*itr1).HashMod != wakkaBucket, "ZHashMap did not move 'wakka' to another bucket!"); + TASSERT((*itr2).HashMod != oongaBucket, "ZHashMap did not move 'oonga' to another bucket!"); + + //TODO - a bit more rigor + + return ZTEST_SUCCESS; +} diff --git a/ZTestSuite/Test-ZIniReader.cpp b/ZTestSuite/Test-ZIniReader.cpp new file mode 100644 index 0000000..cee9930 --- /dev/null +++ b/ZTestSuite/Test-ZIniReader.cpp @@ -0,0 +1,183 @@ +/* + Test-ZIniReader.cpp + Author: James Russell + + Purpose : Unit tests for ZIniReader + + Changelog : + 12/18/2011 - Removed dependency on ZString (crertel) + 2/15/2011 - Created (jcrussell) +*/ + +#include "ZUnitTest.hpp" + +#include <ZUtil/ZSmartPointer.hpp> +#include <ZUtil/ZIniReader.hpp> + +static const char* test_LoadSuccess(); +static const char* test_LoadFailure(); +static const char* test_SectionNames(); +static const char* test_SectionValues(); +static const char* test_AsZRegistry(); + +//List of unit tests +ZUnitTest ZIniReaderUnitTests[] = +{ + { "Successfully load good data", test_LoadSuccess }, + { "Fail load on invalid data", test_LoadFailure }, + { "Section names", test_SectionNames }, + { "Section values", test_SectionValues }, + { "CreateZRegistry()", test_AsZRegistry } +}; + +DECLARE_ZTESTBLOCK(ZIniReader); + +/*************************************************************************/ + +namespace ZIniReaderTestData +{ + const char testDataValid1[] = "[Header1]" LINE_TERMINATOR + "Variable1=Value1" LINE_TERMINATOR + "Variable2=Value2" LINE_TERMINATOR + "" LINE_TERMINATOR + "#Comment" LINE_TERMINATOR + "" LINE_TERMINATOR + "[Header2]" LINE_TERMINATOR + "Variable1=Value3" LINE_TERMINATOR + LINE_TERMINATOR; + + const char testDataValid2[] = "[Header1]" LINE_TERMINATOR + ";Comment here" LINE_TERMINATOR + "Variable1= Value1" LINE_TERMINATOR + "Variable2 =Value2" LINE_TERMINATOR + "Variable3 = Value3" LINE_TERMINATOR + "" LINE_TERMINATOR + LINE_TERMINATOR; + + const char testDataInvalid1[] = "[Hea[der1]" LINE_TERMINATOR + "Variable1=Value1" LINE_TERMINATOR + "Variable2=Value2" LINE_TERMINATOR + "" LINE_TERMINATOR + "# Comment" LINE_TERMINATOR + "" LINE_TERMINATOR + "[Header2]" LINE_TERMINATOR + "Variable1=Value3" LINE_TERMINATOR + LINE_TERMINATOR; + + const char testDataInvalid2[] = "[Header1]" LINE_TERMINATOR + "Variable1=Value1" LINE_TERMINATOR + "Variable2" LINE_TERMINATOR + "" LINE_TERMINATOR + "# Comment" LINE_TERMINATOR + "" LINE_TERMINATOR + "[Header2]" LINE_TERMINATOR + "Variable1=Value3" LINE_TERMINATOR + LINE_TERMINATOR; + + const char testDataInvalid3[] = "" LINE_TERMINATOR; + const char testDataInvalid4[] = "[Header1]" LINE_TERMINATOR + "Val ue = failure" LINE_TERMINATOR; + const char testDataInvalid5[] = "[Header1]" LINE_TERMINATOR + "Val!ue = failure" LINE_TERMINATOR; +} + +using namespace ZIniReaderTestData; + +/*************************************************************************/ + +static const char* test_LoadSuccess() +{ + ZIniReader reader; + + TASSERT(reader.Read(testDataValid1, sizeof(testDataValid1)-1), "Failed to read valid data set #1"); + TASSERT(reader.GetErrorString().Empty(), "Error is not empty after reading #1 successful?"); + TASSERT(reader.Read(testDataValid2, sizeof(testDataValid2)-1), "Failed to read valid data set #2"); + TASSERT(reader.GetErrorString().Empty(), "Error is not empty after reading #2 successful?"); + return ZTEST_SUCCESS; +} + +static const char* test_SectionNames() +{ + ZIniReader reader; + + TASSERT(reader.Read(testDataValid1, sizeof(testDataValid1)-1), "Failed to read valid data set #1"); + TASSERT(reader.GetSectionCount() == 2, "Incorrect number of sections"); + + for(size_t i=0; i<reader.GetSectionCount(); i++) + { + ZString header("Header"); + + header += '1' + (char)i; + + TASSERT(reader.GetSectionName(i) == header, "Header name does not match"); + TASSERT(reader.GetSection(i) != NULL, "Unable to get header by ordinal"); + TASSERT(reader.GetSection(header) != NULL, "Unable to get header by name"); + + } + + return ZTEST_SUCCESS; +} + +static const char* test_SectionValues() +{ + ZIniReader reader; + + TASSERT(reader.Read(testDataValid1, sizeof(testDataValid1)-1), "Failed to read valid data set #1"); + + TASSERT(reader.GetSection("Header1")->Get("Variable1") == "Value1", "[Header1]:Variable1 does not match!"); + TASSERT(reader.GetSection("Header1")->Get("Variable2") == "Value2", "[Header1]:Variable2 does not match!"); + TASSERT(reader.GetSection("Header2")->Get("Variable1") == "Value3", "[Header2]:Variable1 does not match!"); + + //======= + + TASSERT(reader.Read(testDataValid2, sizeof(testDataValid2)-1), "Failed to read valid data set #2"); + + TASSERT(reader.GetSection("Header1")->Get("Variable1") == "Value1", "[Header1]:Variable1 does not match!"); + TASSERT(reader.GetSection("Header1")->Get("Variable2") == "Value2", "[Header1]:Variable2 does not match!"); + TASSERT(reader.GetSection("Header1")->Get("Variable3") == "Value3", "[Header2]:Variable1 does not match!"); + + return ZTEST_SUCCESS; +} + +static const char* test_LoadFailure() +{ + ZIniReader reader; + + TASSERT(!reader.Read(testDataInvalid1, sizeof(testDataInvalid1)-1), "ZIniReader loaded invalid data set #1!"); + TASSERT(!reader.Read(testDataInvalid2, sizeof(testDataInvalid2)-1), "ZIniReader loaded invalid data set #2!"); + TASSERT(!reader.Read(testDataInvalid3, sizeof(testDataInvalid3)-1), "ZIniReader loaded invalid data set #3!"); + TASSERT(!reader.Read(testDataInvalid4, sizeof(testDataInvalid4)-1), "ZIniReader loaded invalid data set #4!"); + TASSERT(!reader.Read(testDataInvalid5, sizeof(testDataInvalid5)-1), "ZIniReader loaded invalid data set #5!"); + + TASSERT(reader.GetSectionCount() == 0, "Shouldn't have any valid sections after this"); + TASSERT(reader.GetSection("Header1") == NULL, "Shouldn't have any valid name -> section mappings"); + + return ZTEST_SUCCESS; +} + + +static const char* test_AsZRegistry() +{ + ZKVTree tree1; + ZKVTree tree2; + ZIniReader reader; + + reader.Read(testDataValid1, sizeof(testDataValid1)-1); + + reader.GetKVTree(tree1); + + TASSERT(tree1.Get("Header1.Variable1") == "Value1", "ZIniReader failed to store [Header1]:Variable1 correctly!"); + TASSERT(tree1.Get("Header1.Variable2") == "Value2", "ZIniReader failed to store [Header1]:Variable2 correctly!"); + TASSERT(tree1.Get("Header2.Variable1") == "Value3", "ZIniReader failed to store [Header2]:Variable1 correctly!"); + + //============ + reader.Read(testDataValid2, sizeof(testDataValid2)-1); + + reader.GetKVTree(tree2); + + TASSERT(tree2.Get("Header1.Variable1") == "Value1", "ZIniReader failed to store [Header1]:Variable1 correctly!"); + TASSERT(tree2.Get("Header1.Variable2") == "Value2", "ZIniReader failed to store [Header1]:Variable2 correctly!"); + TASSERT(tree2.Get("Header1.Variable3") == "Value3", "ZIniReader failed to store [Header1]:Variable3 correctly!"); + + return ZTEST_SUCCESS; +} \ No newline at end of file diff --git a/ZTestSuite/Test-ZIniWriter.cpp b/ZTestSuite/Test-ZIniWriter.cpp new file mode 100644 index 0000000..60731be --- /dev/null +++ b/ZTestSuite/Test-ZIniWriter.cpp @@ -0,0 +1,104 @@ +/* + Test-ZIniWriter.cpp + Author: James Russell <jcrussell@762studios.com> + + Purpose: Unit Test the ZIniWriter class. +*/ + +#include "ZUnitTest.hpp" + +#include <ZUtil/ZIniWriter.hpp> + +static const char* test_WriteSuccess(); +static const char* test_WriteFailure(); + +//List of unit tests +ZUnitTest ZIniWriterUnitTests[] = +{ + { "ZIniWriter: WriteSuccess", test_WriteSuccess }, + { "ZIniWriter: WriteFailure", test_WriteFailure } +}; + +//Now declare the ZUnitTestBlock associated with this. +DECLARE_ZTESTBLOCK(ZIniWriter); + +/*************************************************************************/ + +namespace ZIniWriterTestData +{ + const char* test1Output = "[Header1]" LINE_TERMINATOR + "Variable1=Value1" LINE_TERMINATOR + "Variable2=Value2" LINE_TERMINATOR + "" LINE_TERMINATOR + "[Header2]" LINE_TERMINATOR + "Variable1=Value3" LINE_TERMINATOR + LINE_TERMINATOR; + + const char* test2Output = "[Header1]" LINE_TERMINATOR + "Variable1=Value11" LINE_TERMINATOR + "Variable1=Value12" LINE_TERMINATOR + "Variable1=Value13" LINE_TERMINATOR + "Variable2=Value21" LINE_TERMINATOR + "Variable2=Value22" LINE_TERMINATOR + "" LINE_TERMINATOR + "[Header2]" LINE_TERMINATOR + "Variable1=Value31" LINE_TERMINATOR + "Variable1=Value32" LINE_TERMINATOR + LINE_TERMINATOR; +} + +using namespace ZIniWriterTestData; + +/*************************************************************************/ + +static const char* test_WriteSuccess() +{ + ZKVTree tree1; + + tree1.Put("Header1.Variable1", "Value1"); + tree1.Put("Header1.Variable2", "Value2"); + + tree1.Put("Header2.Variable1", "Value3"); + + ZIniWriter writer; + ZString output; + + TASSERT(writer.Write(tree1, output), "ZIniWriter failed to write valid data set 1!"); + + TASSERT(output == test1Output, "ZIniWriter has written invalid output for data set 1!"); + + ZKVTree tree2; + + tree2.Add("Header1", "Variable1", "Value11"); + tree2.Add("Header1", "Variable1", "Value12"); + tree2.Add("Header1", "Variable1", "Value13"); + tree2.Add("Header1", "Variable2", "Value21"); + tree2.Add("Header1", "Variable2", "Value22"); + + tree2.Add("Header2", "Variable1", "Value31"); + tree2.Add("Header2", "Variable1", "Value32"); + + output.Clear(); + + TASSERT(writer.Write(tree2, output), "ZIniWriter failed to write valid data set 2!"); + + TASSERT(output == test2Output, "ZIniWriter has written invalid output for data set 2!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_WriteFailure() +{ + //Currently, only one way to fail + // Empty Registry (no sections) + + ZKVTree tree; + ZIniWriter writer; + ZString output; + + TASSERT(!writer.Write(tree, output), "ZIniWriter wrote data with empty kvtree!"); + + return ZTEST_SUCCESS; +} \ No newline at end of file diff --git a/ZTestSuite/Test-ZJSONReader.cpp b/ZTestSuite/Test-ZJSONReader.cpp new file mode 100644 index 0000000..03200c9 --- /dev/null +++ b/ZTestSuite/Test-ZJSONReader.cpp @@ -0,0 +1,25 @@ +#include "ZUnitTest.hpp" + +#include <ZUtil/ZJSONReader.hpp> + +static const char* test_LoadSuccess(); +static const char* test_LoadFailed(); + +ZUnitTest ZJSONReaderUnitTests[] = +{ + { "ZJSONReader: Successful Load", test_LoadSuccess }, + { "ZJSONReader: Failed Load", test_LoadFailed } +}; + +//Now declare the ZUnitTestBlock associated with this. +DECLARE_ZTESTBLOCK(ZJSONReader); + +static const char* test_LoadSuccess() +{ + return "TODO"; +} + +static const char* test_LoadFailed() +{ + return "TODO"; +} \ No newline at end of file diff --git a/ZTestSuite/Test-ZJSONWriter.cpp b/ZTestSuite/Test-ZJSONWriter.cpp new file mode 100644 index 0000000..fbf895b --- /dev/null +++ b/ZTestSuite/Test-ZJSONWriter.cpp @@ -0,0 +1,25 @@ +#include "ZUnitTest.hpp" + +#include <ZUtil/ZJSONWriter.hpp> + +static const char* test_LoadSuccess(); +static const char* test_LoadFailed(); + +ZUnitTest ZJSONWriterUnitTests[] = +{ + { "ZJSONWriter: Successful Load", test_LoadSuccess }, + { "ZJSONWriter: Failed Load", test_LoadFailed } +}; + +//Now declare the ZUnitTestBlock associated with this. +DECLARE_ZTESTBLOCK(ZJSONWriter); + +static const char* test_LoadSuccess() +{ + return "TODO"; +} + +static const char* test_LoadFailed() +{ + return "TODO"; +} \ No newline at end of file diff --git a/ZTestSuite/Test-ZKVTree.cpp b/ZTestSuite/Test-ZKVTree.cpp new file mode 100644 index 0000000..101efea --- /dev/null +++ b/ZTestSuite/Test-ZKVTree.cpp @@ -0,0 +1,402 @@ +/* + Test-ZKVTree.cpp + Author: James Russell + + Purpose : Unit tests for ZKVTree + + Changelog : + 12/18/2011 - Removed dependency on ZString (crertel) + 2/20/2011 - Created (jcrussell) +*/ + + +#include "ZUnitTest.hpp" + +#include <ZUtil/ZSmartPointer.hpp> +#include <ZUtil/ZKVTree.hpp> + +#include <iostream> + +static const char* test_Put_Add_Begin_End(); +static const char* test_Find_Iterator(); +static const char* test_Get(); +static const char* test_Erase_Clear(); +static const char* test_Find(); +static const char* test_Merge(); +static const char* test_EmptyKey(); +static const char* test_NestedSubscript(); +static const char* test_Operators(); + +//List of unit tests +ZUnitTest ZKVTreeUnitTests[] = +{ + { "ZKVTree: Put, Add, Begin, End", test_Put_Add_Begin_End }, + { "ZKVTree: Find, Iterator", test_Find_Iterator }, + { "ZKVTree: Get", test_Get }, + { "ZKVTree: Erase, Clear", test_Erase_Clear }, + { "ZKVTree: Merge", test_Merge }, + { "ZKVTree: Empty Key", test_EmptyKey }, + { "ZKVTree: Nested Subscript", test_NestedSubscript }, + { "ZKVTree: Operators", test_Operators }, +}; + +DECLARE_ZTESTBLOCK(ZKVTree); + +/*************************************************************************/ + +static const char* test_Put_Add_Begin_End() +{ + ZKVTree tree1; + ZKVTree tree2; + + // adding out of order to test the insert order + tree1.Put("a", "1"); + tree1.Put("b", "4"); + tree1.Put("a[1]", "2"); + tree1.Put("a[2]", "3"); + tree1.Put("A", "5"); + tree1.Put("A.b", "6"); + tree1.Put("A.c", "8"); + tree1.Put("A.d", "9"); + tree1.Put("A.b[1]", "7"); + tree1.Put("A.B", "10"); + tree1.Put("A.B.c[0]", "11"); + tree1.Put("A.B.c[1]", "12"); + tree1.Put("A.B[1]", "13"); + tree1.Put("A.B[1].c", "14"); + tree1.Put("A.B[1].d", "15"); + tree1.Put("B", "16"); + tree1.Put("B.c", "17"); + tree1.Put("B.d", "18"); + + size_t count = 1; + + for (ZKVTree::Iterator itr = tree1.Begin(); itr != tree1.End(); ++itr) + { + //This is just to inspect the order of values iterated + ZString name = itr.GetName(); + ZString val = itr.GetValue(); + + TASSERT(ZStringAlgo::NumericInt(val) == (int)count, "ZRegistry::Iterator visited nodes in incorrect order!"); + + count++; + } + + //This will build the registry as described at the top of ZRegistry.hpp + tree2.Put("A", "0"); + tree2.Add("A", "B", "8"); + tree2.Add("A.B", "c", "16"); + tree2.Add("A.B", "c", "32"); + tree2.Add("A.B", "", "100"); + tree2.Add("A.B", "", "200"); + tree2.Add("A", "B", "8"); + tree2.Add("A.B[1]", "c", "64"); + tree2.Add("A.B[1]", "d", "128"); + tree2.Add("A.B[1]", "", "10"); + tree2.Add("A.B[1]", "", "20"); + tree2.Add("A", "b", "5"); + tree2.Add("A", "b", "10"); + tree2.Add("A", "c", "15"); + tree2.Add("A", "d", "20"); + tree2.Put("B", "8"); + tree2.Add("B", "c", "50"); + tree2.Add("B", "d", "100"); + tree2.Add("a", "1"); + tree2.Add("a", "2"); + tree2.Add("a", "3"); + tree2.Put("b", "4"); + + //Test using get on each of those + TASSERT(tree2.Get("a") == "1", "GetValue() failed to return correct value for path 'a'!"); + TASSERT(tree2.Get("a[1]") == "2", "GetValue() failed to return correct value for path 'a[1]'!"); + TASSERT(tree2.Get("a[2]") == "3", "GetValue() failed to return correct value for path 'a[2]'!"); + TASSERT(tree2.Get("b") == "4", "GetValue() failed to return correct value for path 'b'!"); + TASSERT(tree2.Get("A.b") == "5", "GetValue() failed to return correct value for path 'A.b'!"); + TASSERT(tree2.Get("A.b[1]") == "10", "GetValue() failed to return correct value for path 'A.b[1]'!"); + TASSERT(tree2.Get("A.c") == "15", "GetValue() failed to return correct value for path 'A.c'!"); + TASSERT(tree2.Get("A.d") == "20", "GetValue() failed to return correct value for path 'A.d'!"); + TASSERT(tree2.Get("B.c") == "50", "GetValue() faield to return correct value for path 'B.c'!"); + TASSERT(tree2.Get("B.d") == "100", "GetValue() failed to return correct value for path 'B.d'!"); + TASSERT(tree2.Get("A.B.c") == "16", "GetValue() failed to return correct value for path 'A.B.c'!"); + TASSERT(tree2.Get("A.B.c[1]") == "32", "GetValue() failed to return correct value for path 'A.B.c[1]'!"); + TASSERT(tree2.Get("A.B[1].c") == "64", "GetValue() failed to return corrrect value for path 'A.B[1].c'!"); + TASSERT(tree2.Get("A.B[1].d") == "128", "GetValue() failed to return correct value for path 'A.B[1].d'!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Find_Iterator() +{ + ZKVTree tree; + + tree.Put("a", "1"); + tree.Put("b", "4"); + tree.Put("a[1]", "2"); + tree.Put("a[2]", "3"); + tree.Put("A", "5"); + tree.Put("A.b", "6"); + tree.Put("A.c", "8"); + tree.Put("A.d", "9"); + tree.Put("A.b[1]", "7"); + tree.Put("A.B", "10"); + tree.Put("A.B.c[0]", "11"); + tree.Put("A.B.c[1]", "12"); + tree.Put("A.B[1]", "13"); + tree.Put("A.B[1].c", "14"); + tree.Put("A.B[1].d", "15"); + tree.Put("B", "16"); + tree.Put("B.c", "17"); + tree.Put("B.d", "18"); + + ZKVTree::Iterator itr = tree.Find("A.B"); + + TASSERT(itr.GetName() == "B", "GetName() failed after ZKVTree::Find('A.B')!"); + TASSERT(itr.GetValue() == "10", "GetValue() failed after ZKVTree::Find('A.B')!"); + + itr.NextSibling(); + + TASSERT(itr.GetName() == "B", "GetName() failed after Iterator::NextSibling()!"); + TASSERT(itr.GetValue() == "13", "GetName() failed after Iterator::NextSibling()!"); + + itr.Child(1); + + TASSERT(itr.GetName() == "d", "GetName() failed after Iterator::Child()!"); + TASSERT(itr.GetValue() == "15", "GetValue() failed after Iterator::Child()!"); + + itr.PrevSibling(); + + TASSERT(itr.GetName() == "c", "GetName() failed after Iterator::PrevSibling()!"); + TASSERT(itr.GetValue() == "14", "GetValue() failed after Iterator::PrevSibling()!"); + + itr.Parent(); + + TASSERT(itr.GetName() == "B", "GetName() failed after Iterator::NextSibling()!"); + TASSERT(itr.GetValue() == "13", "GetName() failed after Iterator::NextSibling()!"); + TASSERT(itr.GetSiblingCount() == 6, "GetSiblingCount() failed on node 'A.B[1]'!"); + TASSERT(itr.GetChildCount() == 2, "GetChildCount() failed on node 'A.B[1]'"); + + ZKVTree::Iterator child_itr = itr.ChildItr(0); + ZKVTree::Iterator sibling_itr = itr.SiblingItr(1); + + TASSERT(child_itr.GetName() == "c", "GetName() failed after Iterator::GetChild(0)!"); + TASSERT(child_itr.GetValue() == "14", "GetValue() failed after Iterator::GetChild(1)!"); + TASSERT(sibling_itr.GetName() == "b", "GetName() failed after GetSibling(1)!"); + TASSERT(sibling_itr.GetValue() == "7", "GetValue() failed after GetSibling(1)!"); + + child_itr = tree.Find(itr, "d"); + + TASSERT(child_itr.GetName() == "d", "GetName() failed after Find(itr, 'd')!"); + TASSERT(child_itr.GetValue() == "15", "GetValue() failed after Find(itr, 'd')!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Get() +{ + ZKVTree tree; + + TASSERT(tree.Put("a", "1") != tree.End(), "PutValue() failed on a valid path 'a'!"); + TASSERT(tree.Put("a[1]", "2") != tree.End(), "PutValue() failed on a valid path 'a[1]'!"); + + TASSERT(tree.Put("A.b", "5") != tree.End(), "PutValue failed on a valid path 'A.b'!"); + TASSERT(tree.Put("A.b[1]", "10") != tree.End(), "PutValue failed on a valid path 'A.b[1]'!"); + + ZString val; + + val = tree.Get("a"); + + TASSERT(val == "1", "GetValue() on the path 'a' returned an incorrect value!"); + + val = tree.Get("a[1]"); + + TASSERT(val == "2", "GetValue() on the path 'a[1]' returned an incorrect value!"); + + val = tree.Get("A.b"); + + TASSERT(val == "5", "GetValue() on the path 'A.b' returned an incorrect value!"); + + val = tree.Get("A.b[1]"); + + TASSERT(val == "10", "GetValue() on the path 'A.b[1]' returned an incorrect value!"); + + tree.Put("a", "3"); + + val = tree.Get("a"); + + TASSERT(val == "3", "GetValue() on the path 'a' returned an incorrect value after overwrite!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Erase_Clear() +{ + ZKVTree tree; + + tree.Put("a", "1"); + tree.Put("b", "4"); + tree.Put("a[1]", "2"); + tree.Put("a[2]", "3"); + tree.Put("A", "5"); + tree.Put("A.b", "6"); + tree.Put("A.c", "8"); + tree.Put("A.d", "9"); + tree.Put("A.b[1]", "7"); + tree.Put("A.B", "10"); + tree.Put("A.B.c[0]", "11"); + tree.Put("A.B.c[1]", "12"); + tree.Put("A.B[1]", "13"); + tree.Put("A.B[1].c", "14"); + tree.Put("A.B[1].d", "15"); + tree.Put("B", "16"); + tree.Put("B.c", "17"); + tree.Put("B.d", "18"); + + tree.Erase("A.B[1]"); + + TASSERT(tree.Find("A.B") != tree.End(), "Find('A.B') returns invalid iterator after Erase('A.B[1]')!"); + + TASSERT(tree.Find("A.B[1]") == tree.End(), "Find('A.B[1]') returns valid iterator after Erase('A.B[1]')!"); + TASSERT(tree.Find("A.B[1].c") == tree.End(), "Find('A.B[1].c') returns valid iterator after Erase('A.B[1]')!"); + + tree.Put("A.B[1]", "derp"); + + TASSERT(tree.Find("A.B[1]").GetValue() == "derp", "Find('A.B[1]') returns invalid iterator after Erase / Put!"); + + tree.Clear(); + + ZKVTree::Iterator itr = tree.Begin(); + + TASSERT(itr == tree.End(), "Clear failed to erase values from the tree!"); + TASSERT(tree.Find("B") == tree.End(), "Find('B') returns valid iterator after Clear()!"); + TASSERT(tree.Find("B.c") == tree.End(), "Find('B.c') returns valid iterator after Clear()!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Merge() +{ + ZKVTree tree1; + ZKVTree tree2; + ZKVTree tree3; + + tree1.Add("a", "10"); + tree1.Add("b", "40"); + tree1.Add("a", "20"); + tree1.Add("a", "30"); + + tree2.Add("a", "10"); + tree2.Add("b", "40"); + tree2.Add("a", "20"); + tree2.Add("a", "30"); + + tree3.Put("a", "1"); + tree3.Put("b", "4"); + tree3.Put("a[1]", "2"); + tree3.Put("a[2]", "3"); + tree3.Put("A", "5"); + tree3.Put("A.b", "6"); + tree3.Put("A.c", "8"); + tree3.Put("A.d", "9"); + tree3.Put("A.b[1]", "7"); + tree3.Put("A.B", "10"); + tree3.Put("A.B.c[0]", "11"); + tree3.Put("A.B.c[1]", "12"); + tree3.Put("A.B[1]", "13"); + tree3.Put("A.B[1].c", "14"); + tree3.Put("A.B[1].d", "15"); + tree3.Put("B", "16"); + tree3.Put("B.c", "17"); + tree3.Put("B.d", "18"); + + tree1.Merge(tree3, false); + tree2.Merge(tree3, true); + + TASSERT(tree1.Get("a") == "10", "Get('a') returned invalid value after Merge(false)!"); + TASSERT(tree1.Get("b") == "40", "Get('b') returned invalid value after Merge(false)!"); + TASSERT(tree1.Get("a[1]") == "20", "Get('a[1]') returned invalid value after Merge(false)!"); + TASSERT(tree1.Get("a[2]") == "30", "Get('a[2]') returned invalid value after Merge(false)!"); + + TASSERT(tree2.Get("a") == "1", "Get('a') returned invalid value after Merge(true)!"); + TASSERT(tree2.Get("b") == "4", "Get('b') returned invalid value after Merge(true)!"); + TASSERT(tree2.Get("a[1]") == "2", "Get('a[1]') returned invalid value after Merge(true)!"); + TASSERT(tree2.Get("a[2]") == "3", "Get('a[2]') returned invalid value after Merge(true)!"); + + TASSERT(tree1.Get("A.b") == "6", "Get('A.b') returned invalid value after Merge(false)!"); + TASSERT(tree2.Get("A.b") == "6", "Get('A.b') returned invalid value after Merge(true)!"); + + TASSERT(tree1.Get("A.B[1].c") == "14", "Get('A.B[1].c') returned invalid value after Merge(false)!"); + TASSERT(tree2.Get("A.B[1].c") == "14", "Get('A.B[1].c') returned invalid value after Merge(true)!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_EmptyKey() +{ + ZKVTree tree; + + tree.Add("", "1"); + tree.Add("", "2"); + tree.Add("", "3"); + tree.Add("", "4"); + + TASSERT(tree.Get("") == "1", "First unnamed key has invalid value!"); + TASSERT(tree.Get("[1]") == "2", "Second unnamed key has invalid value!"); + TASSERT(tree.Get("[2]") == "3", "Third unnamed key has invalid value!"); + TASSERT(tree.Get("[3]") == "4", "Fourth unnamed key has invalid value!"); + + tree.Add("", "", "11"); + + TASSERT(tree.Get("[0].[0]") == "11", "First child of first unnamed key has invalid value!"); + TASSERT(tree.Get(".") == "11", "Invalid path conversion on first child of first unnamed key!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_NestedSubscript() +{ + ZKVTree tree; + + tree.Put("A", "A1"); + tree.Put("A[0][0]", "A11"); + tree.Add("A", "", "A12"); + + TASSERT(tree.Get("A[0]") == "A1", "Key A[0] has invalid value!"); + TASSERT(tree.Get("A[0][0]") == "A11", "Key A[0][0] has invalid value!"); + TASSERT(tree.Get("A[0][1]") == "A12", "Key A[0][1] has invalid value!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Operators() +{ + ZKVTree tree1; + ZKVTree tree2; + + tree1.Put("A", "A1"); + tree1.Put("A[0][0]", "A11"); + tree1.Add("A", "", "A12"); + + tree2 = tree1; + + TASSERT(tree2.Get("A[0]") == "A1", "Key A[0] has invalid value!"); + TASSERT(tree2.Get("A[0][0]") == "A11", "Key A[0][0] has invalid value!"); + TASSERT(tree2.Get("A[0][1]") == "A12", "Key A[0][1] has invalid value!"); + + return ZTEST_SUCCESS; + +} + diff --git a/ZTestSuite/Test-ZList.cpp b/ZTestSuite/Test-ZList.cpp new file mode 100644 index 0000000..7ba4726 --- /dev/null +++ b/ZTestSuite/Test-ZList.cpp @@ -0,0 +1,416 @@ +#include "ZUnitTest.hpp" + +#include <ZSTL/ZList.hpp> +#include <ZSTL/ZListAlgo.hpp> + +static const char* test_Constructors_PushBack_Size_Empty(); +static const char* test_Begin_End_At_Iterator(); +static const char* test_Allocator_Front_Back_Clear(); +static const char* test_Copy_Equals(); +static const char* test_PushFront_PopBack_PopFront(); +static const char* test_Insert_Erase(); +static const char* test_Swap_Splice_SwapNodes(); + +//List of unit tests +ZUnitTest ZListUnitTests[] = +{ + { "ZList: Constructors, PushBack, Size, Empty", test_Constructors_PushBack_Size_Empty }, + { "ZList: Begin, End, At, Iterator", test_Begin_End_At_Iterator }, + { "ZList: Allocator, Front, Back, Clear", test_Allocator_Front_Back_Clear }, + { "ZList: Copy, Equals", test_Copy_Equals }, + { "ZList: PushFront, PopBack, PopFront", test_PushFront_PopBack_PopFront }, + { "ZList: Insert, Erase", test_Insert_Erase }, + { "ZList: Swap, Splice, SwapNodes", test_Swap_Splice_SwapNodes } +}; + +//Now declare the ZUnitTestBlock associated with this. +DECLARE_ZTESTBLOCK(ZList); + +/*************************************************************************/ + +static const char* test_Constructors_PushBack_Size_Empty() +{ + //Test our default list constructor with default allocator + ZList<int> list1; + + //Should start empty + TASSERT(list1.Size() == 0, "Size() returns non-zero value but should be empty!"); + TASSERT(list1.Empty() == true, "Empty() returns false on newly created list!"); + + //Fill in with 5 elements + for(int i = 0; i < 5; i++) + { + list1.PushBack(i); + + TASSERT(list1.Size() == (size_t)(i + 1), "Size() returns incorrect value after PushBack()!"); + TASSERT(list1.Empty() == false, "Empty() returns true on list with elements!"); + } + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Begin_End_At_Iterator() +{ + int i; + + ZList<int> list1; + ZList<int>::Iterator itr1; + ZListIterator<int> itr2; + + itr1 = list1.Begin(); + + TASSERT(itr1.HasNext() == false, "Iterator HasNext() returns true on empty list iterator!"); + TASSERT(itr1.HasPrev() == false, "Iterator HasPrev() returns true on empty list iterator!"); + TASSERT(itr1.HasCurrent() == false, "Iterator HasCurrent() returns false on empty list iterator!"); + + for(int i = 0; i < 5; i++) + list1.PushBack(i); //These calls will invalidate the iterator, or, rather, have it point to 'End' + + itr1 = list1.Begin(); + + TASSERT(itr1.HasNext() == true, "Iterator HasNext() returns false when elements remain!"); + TASSERT(itr1.HasPrev() == false, "Iterator HasPrevious() returns true at list Begin()!"); + + //Check going forwards + for (itr1 = list1.Begin(), i = 0; i < 5; itr1++, i++) + { + TASSERT(itr1.HasCurrent() == true, "Iterator HasCurrent() returns false when elements should exist!"); + TASSERT(itr1.Get() == i, "Iterator Get() does not return correct value when iterating list!"); + TASSERT((*itr1) == i, "Iterator operator * does not return correct value when iterating list!"); + + TASSERT(itr1 == list1.At(i), "At() returns incorrect iterator when forward iterating!"); + } + + //Should be at end + TASSERT(list1.End() == itr1, "Iterator should be at end after forward iteration but == End() returns false!"); + TASSERT(itr1.HasNext() == false, "Iterator HasNext() should return false at End() but returns true!"); + TASSERT(itr1.HasPrev() == true, "Iterator HasPrev() should return true at End() but returns false!"); + TASSERT(itr1.HasCurrent() == false, "Iterator HasCurrent() should return false at End() but returns true!"); + + for (i = 4; i >= 0; i--) + { + itr1--; + + TASSERT(itr1.Get() == i, "Iterator Get() does not return correct value when reverse iterating list!"); + TASSERT((*itr1) == i, "Iterator operator * does not return correct value when reverse iterating list!"); + + TASSERT(itr1 == list1.At(i), "At() returns incorrect iterator when reverse iterating!"); + } + + //Should be at the beginning now + TASSERT(itr1 == list1.Begin(), "Iterator should be at start after reverse iteration but == Begin() returns false!"); + + for (i = 0; i < 5; i++) + { + itr1 = list1.At(i); + + TASSERT((*itr1) == i, "Iterator operator * returns incorrect value after iterator assignment!"); + } + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +//Allocator that counts current number of node allocations +template <typename T> +class ZListTestAllocator : public ZListAllocator<T> +{ +public: + //Current number of allocated nodes + int Count; + + ZListTestAllocator() : Count(0) { } + + ZListNode<T>* Allocate() + { + Count++; + + return new (std::nothrow) ZListNode<T>(); + } + + void Deallocate( ZListNode<T>* _node ) + { + Count--; + + delete _node; + } +}; + +static const char* test_Allocator_Front_Back_Clear() +{ + ZList<int, ZListTestAllocator<int> > list1; + ZList<int>::Iterator itr; + + for (int i = 0; i < 5; i++) + { + list1.PushBack(i); + + TASSERT(list1.Allocator().Count == i + 1, "Allocator() returns incorrect count for number of allocated nodes!"); + } + + TASSERT(list1.Front() == 0, "Front() returns incorrect value!"); + TASSERT(list1.Back() == 4, "Back() returns incorrect value!"); + + list1.Clear(); + + TASSERT(list1.Empty(), "Empty() returns false after call to Clear()!"); + TASSERT(list1.Allocator().Count == 0, "Clear() failed to deallocate nodes!");; + + for (int i = 0; i < 5; i++) + list1.PushBack(i); + + itr = list1.At(2); + + list1.Clear(itr); + + TASSERT(list1.Size() == 2, "Size() returns incorrect value after call to Clear()!"); + + itr = list1.End(); + + list1.Clear(itr); + + TASSERT(list1.Size() == 2, "Size() returns incorrect value after call to Clear(End())!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Copy_Equals() +{ + ZList<int, ZListTestAllocator<int> > list1; + ZList<int, ZListTestAllocator<int> > list2; + + ZList<int>::Iterator itr; + + TASSERT(list1.Equals(list2) == true, "Equals() returns false when empty list is compared to empty list!"); + + for (int i = 0; i < 5; i++) + list1.PushBack(i); + + TASSERT(list1.Equals(list2) == false, "Equals() returns true when empty list is compared to non-empty list!"); + + list2.Copy(list1); + + TASSERT(list1.Size() == list2.Size(), "Size() of list1 does not equal Size() of list2 after Copy!"); + TASSERT(list1.Equals(list2) == true, "Equals(list1, list2) returns false after Copy!"); + TASSERT(list2.Equals(list1) == true, "Equals(list2, list1) returns false after Copy!"); + + itr = list2.At(3); + + list2.Clear(itr); + + TASSERT(list1.Equals(list2) == false, "Equals(list1, list2) returns true after Clear()!"); + TASSERT(list2.Equals(list1) == false, "Equals(list2, list1) returns true after Clear()!"); + + ZList<int, ZListTestAllocator<int> > list3(list2.Begin(), list2.End()); + ZList<int, ZListTestAllocator<int> > list4(list2.Begin(), --itr); + + TASSERT(list3.Back() == 2, "Back() returns incorrect value on list3 after sub-list constructor!"); + TASSERT(list4.Back() == 1, "Back() returns incorrect value on list4 after sub-list constructor!"); + TASSERT(list3.Equals(list4) == false, "Equals(list3, list4) returns true after sub-list constructor!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_PushFront_PopBack_PopFront() +{ + int i; + + ZList<int, ZListTestAllocator<int> > list1; + + for (i = 0; i < 5; i++) + { + list1.PushBack(i); + + TASSERT(list1.Allocator().Count == i + 1, "Allocator() returns incorrect count for number of allocated nodes after PushBack()!"); + TASSERT(list1.Back() == i, "Back() returns incorrect value after PushBack()!"); + } + + TASSERT(list1.Size() == 5, "Size() returns incorrect value after after PushBack()!"); + + for (i = 5; i > 0; i--) + { + int j = list1.PopBack(); + + TASSERT(j == i - 1, "PopBack() returns incorrect value!"); + + TASSERT(list1.Allocator().Count == i - 1, "Allocator() returns incorrect count for number of allocated nodes after PopBack()!"); + TASSERT(list1.Size() == (size_t)(i - 1), "Size() returns incorrect value after PopBack()!"); + } + + list1.Clear(); + + for (i = 0; i < 5; i++) + { + list1.PushFront(i); + + TASSERT(list1.Allocator().Count == i + 1, "Allocator() returns incorrect count for number of allocated nodes!"); + TASSERT(list1.Front() == i, "Front() returns wrong value after calls to PushFront()!"); + } + + TASSERT(list1.Size() == 5, "Size() returns incorrect value after after PushFront()!"); + + for (i = 5; i > 0; i--) + { + int j = list1.PopFront(); + + TASSERT(j == i - 1, "PopFront() returns incorrect value!"); + + TASSERT(list1.Allocator().Count == i - 1, "Allocator() returns incorrect count for number of allocated nodes!"); + TASSERT(list1.Size() == (size_t)(i - 1), "Size() returns incorrect value after PopFront()!"); + } + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Insert_Erase() +{ + ZList<int, ZListTestAllocator<int> > list1; + ZList<int, ZListTestAllocator<int> > list2; + + ZList<int>::Iterator itr1; + ZList<int>::Iterator itr2; + + for (int i = 0; i < 5; i++) + list1.PushBack(i); + + itr1 = list1.Begin(); + + list1.Insert(itr1, 10); + + TASSERT((*itr1) == 0, "Iterator operator * returns incorrect value after Insert()!"); + TASSERT(list1.Begin().Get() == 10, "Iterator Get() returns incorrect value after Insert()!"); + TASSERT(list1.Size() == 6, "Size() returns incorrect value after Insert()!") + + itr2 = list1.End(); + + list1.Insert(itr2, 20); + + TASSERT(list1.Back() == 20, "Back() returns incorrect value after Insert()!"); + TASSERT(itr2 == list1.End(), "Iterator does not equal End after Insert()!"); + TASSERT(list1.Size() == 7, "Size() returns incorrect value after Insert(End())!"); + + itr1 = list1.Begin(); + + int j = list1.Erase(itr1); + + TASSERT(j == 10, "Erase(itr1) returns incorrect value!"); + TASSERT(list1.Front() == 0, "Front() returns incorrect value after Erase()!"); + TASSERT(list1.Size() == 6, "Size() returns incorrect value after Erase(Begin())!"); + + itr2 = list1.End() - 1; + + j = list1.Erase(itr2); + + TASSERT(j == 20, "Erase(itr2) returns incorrect value!"); + TASSERT(list1.Back() == 4, "Back() returns incorrect value after Erase()!"); + TASSERT(list1.Size() == 5, "Size() returns incorrect value after Erase(End() - 1))!"); + + itr1 = list1.Begin(); + itr2 = list1.At(2); //0, 1, 2 + + list2.Insert(list2.Begin(), itr1, itr2); + + TASSERT(list2.Front() == 0 && list2.Back() == 1, "Front() and Back() do not return correct values after Insert(Begin(), itr1, itr2)!"); + + itr1 = list2.Begin(); + itr2 = list2.End(); + + list1.Insert(list1.At(2), itr1, itr2); + + TASSERT(list1.Size() == 7, "Size() returns incorrect value after Insert(At(2), itr1, itr2)!"); + + TASSERT(list1.Front() == 0, "Front() returns incorrect value after Insert(At(2), itr1, itr2)!"); + TASSERT(list1.Back() == 4, "Back() returns incorrect value after Insert(At(2), itr1, itr2)"); + + TASSERT(*list1.At(2) == 0, "At(2) dereference contains invalid value after Insert(At(2), itr1, itr2)!"); + TASSERT(*list1.At(3) == 1, "At(3) dereference contains invalid value after Insert(At(2), itr1, itr2)!"); + + itr1 = list1.At(2); + itr2 = list1.At(4); + + list1.Erase(itr1, itr2); + + TASSERT(list1.Size() == 5, "Size() returns incorrect value after Erase(itr1, itr2)!"); + + itr1 = list1.Begin(); + + for (int i = 0; itr1 != list1.End(); itr1++, i++) + { + TASSERT((*itr1) == i, "Iterator operator * returns incorrect value after Erase(itr1, itr2)!"); + } + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Swap_Splice_SwapNodes() +{ + int i; + + ZList<int> list1; + ZList<int> list2; + + ZList<int>::Iterator itr1; + ZList<int>::Iterator itr2; + + for (int i = 0; i < 5; i++) + list1.PushBack(i); + + for (int i = 5; i < 10; i++) + list2.PushBack(i); + + list1.Swap(list2); + + for (i = 5, itr1 = list1.Begin(); itr1 != list1.End(); i++, itr1++) + { + TASSERT((*itr1) == i, "Iterator operator * returns incorrect value on list1 after Swap()!"); + } + + for (i = 0, itr2 = list2.Begin(); itr2 != list2.End(); i++, itr2++) + { + TASSERT((*itr2) == i, "Iterator operator * returns incorrect value on list2 after Swap()!"); + } + + itr1 = list1.Begin(); + itr2 = list1.End(); + + list2.Splice(list2.End(), list1, itr1, itr2); + + TASSERT(list2.Size() == 10, "Size() returns incorrect value after Splice()!"); + TASSERT(list1.Empty(), "Empty() returns false after Splice()!"); + + for (i = 0, itr2 = list2.Begin(); itr2 != list2.End(); i++, itr2++) + { + TASSERT((*itr2) == i, "Iterator operator * returns incorrect value on list2 after Splice()!"); + } + + itr1 = list2.At(3); + itr2 = list2.At(6); + + list1.Splice(list1.Begin(), list2, itr1, itr2); + + TASSERT(list2.Size() == 7, "Size() returns incorrect value for list2 after Splice(At(3), At(6))!"); + TASSERT(list1.Size() == 3, "Size() returns incorrect value for list1 after Splice(At(3), At(6))!"); + + for (i = 3, itr1 = list1.Begin(); itr1 != list1.End(); i++, itr1++) + { + TASSERT((*itr1) == i, "Iterator operator * returns incorrect value on list1 after Splice()!"); + } + + list1.SwapNodes(list1.Begin(), list1.End() - 1); + + TASSERT(list1.Front() == 5, "Front() returns invalid value after call to SwapNodes()!"); + TASSERT(list1.Back() == 3, "Back() returns invalid value after call to SwapNodes()!"); + + return ZTEST_SUCCESS; +} diff --git a/ZTestSuite/Test-ZListAlgo.cpp b/ZTestSuite/Test-ZListAlgo.cpp new file mode 100644 index 0000000..db6c407 --- /dev/null +++ b/ZTestSuite/Test-ZListAlgo.cpp @@ -0,0 +1,1143 @@ +#include "ZUnitTest.hpp" + +#include <ZSTL/ZListAlgo.hpp> + +static const char* test_Append(); +static const char* test_Append_Region(); +static const char* test_Concatenate(); +static const char* test_Concatenate_In_Region(); +static const char* test_Contains(); +static const char* test_Contains_In_Region(); +static const char* test_Count(); +static const char* test_Count_In_Region(); +static const char* test_Excise(); +static const char* test_FindFirst(); +static const char* test_FirstOf_In_Region(); +static const char* test_FirstNotOf(); +static const char* test_FirstNotOf_In_Region(); +static const char* test_Prepend(); +static const char* test_Prepend_Region(); +static const char* test_Remove(); +static const char* test_Remove_In_Region(); +static const char* test_RemoveAll(); +static const char* test_RemoveAll_In_Region(); +static const char* test_Reverse(); +static const char* test_Reverse_In_Region(); +static const char* test_ReverseNodes(); +static const char* test_ReverseNodes_In_Region(); +static const char* test_Slice(); +static const char* test_Sort(); +static const char* test_Sort_Region(); +static const char* test_Sort_Comparator(); +static const char* test_Sort_Comparator_Algorithm(); +static const char* test_Sort_Comparator_Algorithm_Range(); +static const char* test_Split(); +static const char* test_SwapElements(); + +//List of unit tests +ZUnitTest ZListAlgoUnitTests[] = +{ + { "Append", test_Append }, + { "Append region", test_Append_Region}, + { "Concatenate", test_Concatenate }, + { "Concatenate in region", test_Concatenate_In_Region }, + { "Contains", test_Contains }, + { "Contains in region", test_Contains_In_Region }, + { "Count", test_Count }, + { "Count in region", test_Count_In_Region }, + { "Excise", test_Excise }, + { "FindFirstOf", test_FindFirst }, + { "FindFirstOf in region", test_FirstOf_In_Region }, + { "FirstNotOf", test_FirstNotOf }, + { "FirstNotOf in region", test_FirstNotOf_In_Region }, + { "Prepend", test_Prepend }, + { "Prepend region", test_Prepend_Region }, + { "Remove", test_Remove }, + { "Remove in region", test_Remove_In_Region }, + { "RemoveAll", test_RemoveAll }, + { "RemoveAll in region", test_RemoveAll_In_Region }, + { "Reverse", test_Reverse }, + { "Reverse in region", test_Reverse_In_Region }, + { "ReverseNodes", test_ReverseNodes }, + { "ReverseNodes in region", test_ReverseNodes_In_Region }, + { "Slice", test_Slice }, + { "Sort", test_Sort }, + { "Sort region", test_Sort_Region }, + { "Sort comparator", test_Sort_Comparator }, + { "Sort comparator algorithm", test_Sort_Comparator_Algorithm }, + { "Sort comparator algorithm region", test_Sort_Comparator_Algorithm_Range }, + { "Split", test_Split }, + { "SwapElements", test_SwapElements } +}; + +//Now declare the ZUnitTestBlock associated with this. +DECLARE_ZTESTBLOCK(ZListAlgo); + +/*************************************************************************/ + +static const char* test_Append() +{ + ZList<int> list; + ZList<int> list2; + int temp = -1; + + list.PushBack(1); + list.PushBack(2); + list.PushBack(3); + + list2.PushBack(4); + list2.PushBack(5); + + ZListAlgo::Append(list,list2); + TASSERT( list.Size() == 5, "Append() failed to create list of proper size!\n"); + + temp = list.PopFront(); + TASSERT( temp == 1, "Append() corrupted list!\n"); + temp = list.PopFront(); + TASSERT( temp == 2, "Append() corrupted list!\n"); + temp = list.PopFront(); + TASSERT( temp == 3, "Append() corrupted list!\n"); + temp = list.PopFront(); + TASSERT( temp == 4, "Append() corrupted list!\n"); + temp = list.PopFront(); + TASSERT( temp == 5, "Append() corrupted list!\n"); + + TASSERT( list.Size() == 0, "Append() somehow made excessively long list!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Append_Region() +{ + ZList<int> list; + ZList<int> list2; + int temp = -1; + + list.PushBack(1); + list.PushBack(2); + list.PushBack(3); + + list2.PushBack(4); + list2.PushBack(5); + list2.PushBack(6); + list2.PushBack(7); + list2.PushBack(8); + + ZListAlgo::Append(list,list2, list2.At(2), list2.End()); + TASSERT( list.Size() == 6, "Append() failed to create list of proper size!\n"); + + temp = list.PopFront(); + TASSERT( temp == 1, "Append() corrupted list!\n"); + temp = list.PopFront(); + TASSERT( temp == 2, "Append() corrupted list!\n"); + temp = list.PopFront(); + TASSERT( temp == 3, "Append() corrupted list!\n"); + temp = list.PopFront(); + TASSERT( temp == 6, "Append() corrupted list!\n"); + temp = list.PopFront(); + TASSERT( temp == 7, "Append() corrupted list!\n"); + temp = list.PopFront(); + TASSERT( temp == 8, "Append() corrupted list!\n"); + + TASSERT( list.Size() == 0, "Append() somehow made excessively long list!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Concatenate() +{ + ZList<int> list1; + ZList<int> list2; + + list1.PushBack(1); + list1.PushBack(2); + list1.PushBack(3); + list1.PushBack(4); + + list2.PushBack(5); + list2.PushBack(6); + list2.PushBack(7); + list2.PushBack(8); + + ZList<int> test = ZListAlgo::Concatenate(list1, list2); + + TASSERT( test.Size() == 8, "Concatenate() output list shorter than sum of input lists!\n"); + + TASSERT( test.PopFront() == 1, "Concatenate() created wrong list!\n"); + TASSERT( test.PopFront() == 2, "Concatenate() created wrong list!\n"); + TASSERT( test.PopFront() == 3, "Concatenate() created wrong list!\n"); + TASSERT( test.PopFront() == 4, "Concatenate() created wrong list!\n"); + TASSERT( test.PopFront() == 5, "Concatenate() created wrong list!\n"); + TASSERT( test.PopFront() == 6, "Concatenate() created wrong list!\n"); + TASSERT( test.PopFront() == 7, "Concatenate() created wrong list!\n"); + TASSERT( test.PopFront() == 8, "Concatenate() created wrong list!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Concatenate_In_Region() +{ + ZList<int> list1; + ZList<int> list2; + + list1.PushBack(1); + list1.PushBack(2); + list1.PushBack(3); + list1.PushBack(4); + + list2.PushBack(5); + list2.PushBack(6); + list2.PushBack(7); + list2.PushBack(8); + + ZList<int> test = ZListAlgo::Concatenate(list1, list1.At(1), list1.At(3), + list2, list2.At(1), list2.At(3)); + + TASSERT( test.Size() == 4, "Concatenate() output list shorter than sum of input lists!\n"); + + TASSERT( test.PopFront() == 2, "Concatenate() created wrong list!\n"); + TASSERT( test.PopFront() == 3, "Concatenate() created wrong list!\n"); + TASSERT( test.PopFront() == 6, "Concatenate() created wrong list!\n"); + TASSERT( test.PopFront() == 7, "Concatenate() created wrong list!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Contains() +{ + ZList<int> list; + + list.PushBack(1); + list.PushBack(2); + list.PushBack(3); + + TASSERT( ZListAlgo::Contains(list, 1) == true, "Contains() failed to find present value!\n"); + TASSERT( ZListAlgo::Contains(list, 2) == true, "Contains() failed to find present value!\n"); + TASSERT( ZListAlgo::Contains(list, 3) == true, "Contains() failed to find present value!\n"); + + TASSERT( ZListAlgo::Contains(list, 4) == false, "Contains() successfully found missing value!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Contains_In_Region() +{ + ZList<int> list; + ZListIterator<int> goodStartItr; + ZListIterator<int> goodEndItr; + + ZListIterator<int> badStartItr; + ZListIterator<int> badEndItr; + + list.PushBack(1); + list.PushBack(2); + list.PushBack(3); + list.PushBack(4); + list.PushBack(5); + list.PushBack(6); + + goodStartItr = list.At(2); // will point at 3 + goodEndItr = list.At(4); // will point at 5 + + TASSERT( ZListAlgo::Contains(list, 1, goodStartItr, goodEndItr) == false, "Contains() sucessfully found missing value!\n"); + TASSERT( ZListAlgo::Contains(list, 2, goodStartItr, goodEndItr) == false, "Contains() sucessfully found missing value!\n"); + TASSERT( ZListAlgo::Contains(list, 3, goodStartItr, goodEndItr) == true, "Contains() failed to find value at inclusive endpoint!\n"); + TASSERT( ZListAlgo::Contains(list, 4, goodStartItr, goodEndItr) == true, "Contains() failed to find value!\n"); + TASSERT( ZListAlgo::Contains(list, 5, goodStartItr, goodEndItr) == false, "Contains() accidentally included exclusive endpoint!\n"); + TASSERT( ZListAlgo::Contains(list, 6, goodStartItr, goodEndItr) == false, "Contains()sucessfully found missing value!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Count() +{ + ZList<int> list; + + //Fill list with 5 items and check for + for(int i=0; i<5; i++) + list.PushBack(1); + list.PushBack(2); //These add a bit of extra stuff to compare against + list.PushBack(3); + TASSERT(ZListAlgo::Count(list, 1) == 5, "Count() gave wrong number of items, should be 5"); + + //Remove 1 item from the front of the list + list.PopFront(); + TASSERT( ZListAlgo::Count(list, 1) == 4, "Count() gave wrong number of items, should be 4"); + + //Empty the list + list.Clear(); + TASSERT( ZListAlgo::Count(list, 1) == 0, "Count() gave wrong number of items, should be 0"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Count_In_Region() +{ + ZList<int> list; + list.PushBack(3); //0 + list.PushBack(2); //1 + list.PushBack(3); //2 + list.PushBack(3); //3 + list.PushBack(1); //4 + list.PushBack(6); //5 + list.PushBack(3); //6 + list.PushBack(8); //7 + list.PushBack(1); //8 + + ZListIterator<int> start = list.At(3); + ZListIterator<int> end = list.At(7); + + TASSERT( ZListAlgo::Count(list, 3, start, end) == 2, "Count() miscounted occurences in region!\n"); + TASSERT( ZListAlgo::Count(list, 8, start, end) == 0, "Count() found element out of range!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Excise() +{ + ZList<int> list; + ZList<int> excise; + + list.PushBack(1); + list.PushBack(2); + list.PushBack(3); + list.PushBack(4); + list.PushBack(5); + list.PushBack(6); + + ZListIterator<int> start = list.At(1); // points at 2 + ZListIterator<int> end = list.At(4); // points at 5 + excise = ZListAlgo::Excise(list,start,end); + + TASSERT( list.Size() == 3, "Slice() mutated target list to incorrect size!\n"); + TASSERT( excise.Size() == 3, "Slice() produced list of incorrect size!\n"); + + // check remainder + TASSERT( list.PopFront() == 1, "Slice() produced bad list!\n"); + TASSERT( list.PopFront() == 5, "Slice() produced bad list!\n"); + TASSERT( list.PopFront() == 6, "Slice() produced bad list!\n"); + + // check excised bit + TASSERT( excise.PopFront() == 2, "Slice() produced bad list!\n"); + TASSERT( excise.PopFront() == 3, "Slice() produced bad list!\n"); + TASSERT( excise.PopFront() == 4, "Slice() produced bad list!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_FindFirst() +{ + ZList<int> list; + ZList<int>::Iterator it; + int i; + + //Add 0-9 + for(i=0; i<10; i++) + list.PushBack(i); + + list.PushBack(1000); + + //Find the element with the value '5' + it = ZListAlgo::FindFirst(list, 5); + if(it == list.End()) + return "Find(5) could not find element known to exist"; + if(*it != 5) + return "Find(5) found the wrong element"; + + //Find an element that does not exist + it = ZListAlgo::FindFirst(list, (int)0xdeadc0de); + if(it != list.End()) + return "Find() erroneously found element known NOT to exist"; + + //Find an element 1000, then remove it + it = ZListAlgo::FindFirst(list, 1000); + if(it == list.End()) + return "Find(1000) could not find element known to exist"; + if(*it != 1000) + return "Find(1000) found the wrong element"; + list.Erase(it); + + //Now try to find it + it = ZListAlgo::FindFirst(list, 1000); + if(it != list.End()) + return "Find(1000) erroneously found element known NOT to exist"; + + list.Clear(); + + ZListIterator<int> good; + ZListIterator<int> temp; + + list.PushBack(1); + list.PushBack(2); + list.PushBack(2); + list.PushBack(3); + list.PushBack(4); + list.PushBack(7); + list.PushBack(8); + + good = list.At(1); // points at the first 2 + + // test whole-list ones + temp = ZListAlgo::FindFirst(list, 2); + + TASSERT( temp == good, "FirstOf() misplaced element in list!\n"); + + temp = ZListAlgo::FindFirst(list, 5); + + TASSERT( temp == list.End(), "FirstOf() returned good position to missing element!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_FirstOf_In_Region() +{ + ZList<int> list; + ZListIterator<int> firstItr; + ZListIterator<int> badItr; + ZListIterator<int> start; + ZListIterator<int> end; + ZListIterator<int> good; + + list.PushBack(1); + list.PushBack(2); + list.PushBack(2); + list.PushBack(3); + list.PushBack(4); + list.PushBack(7); + list.PushBack(8); + + firstItr = list.At(1); + badItr = list.End(); + start = list.At(2); // points at second 2 + end = list.At(5); // points at 7 + good = list.At(4); // points at 4 + + // test whole-list ones + TASSERT( ZListAlgo::FindFirst(list, 2, list.Begin(), list.End()) == firstItr, "FirstOf() misplaced element in list!\n"); + TASSERT( ZListAlgo::FindFirst(list, 5, list.Begin(), list.End()) == badItr, "FirstOf() returned good position to missing element!\n"); + + TASSERT( ZListAlgo::FindFirst(list, 4, start, end) == good, "FirstOf() misplaced element in list!\n"); + TASSERT( ZListAlgo::FindFirst(list, 7, start, end) == list.End(), "FirstOf() returned good position to out-of-bounds element!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_FirstNotOf() +{ + ZList<int> list; + ZListIterator<int> good; + ZListIterator<int> temp; + + list.PushBack(2); + list.PushBack(2); + list.PushBack(2); + list.PushBack(3); + list.PushBack(4); + + good = list.At(3); // points at the 3 + temp = ZListAlgo::FirstNotOf(list, 2); + TASSERT( temp == good, "FirstNotOf() misplaced element in list!\n"); + + good = list.Begin(); // points at first element in list (a 2, which is not a 3) + temp = ZListAlgo::FirstNotOf(list, 3); + TASSERT( temp == good, "FirstNotOf() misplaced element in list!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_FirstNotOf_In_Region() +{ + ZList<int> list; + ZListIterator<int> good; + ZListIterator<int> temp; + ZListIterator<int> start; + ZListIterator<int> end; + + list.PushBack(2); + list.PushBack(2); + list.PushBack(2); + list.PushBack(3); + list.PushBack(4); + list.PushBack(5); + list.PushBack(6); + + good = list.At(3); // points at the 3 + start = list.At(1); // points at the second 2 + end = list.At(4); // points at the 4 + temp = ZListAlgo::FirstNotOf(list, 2, start, end); + TASSERT( temp == good, "FirstNotOf() misplaced element in list!\n"); + + good = list.At(1); // points at the second 2 + temp = ZListAlgo::FirstNotOf(list, 3, start, end); + TASSERT( temp == good, "FirstNotOf() misplaced element in list!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Prepend() +{ + ZList<int> list; + ZList<int> list2; + int temp = -1; + + list.PushBack(1); + list.PushBack(2); + list.PushBack(3); + + list2.PushBack(4); + list2.PushBack(5); + + ZListAlgo::Prepend(list,list2); + TASSERT( list.Size() == 5, "Append() failed to create list of proper size!\n"); + + temp = list.PopFront(); + TASSERT( temp == 4, "Append() corrupted list!\n"); + temp = list.PopFront(); + TASSERT( temp == 5, "Append() corrupted list!\n"); + temp = list.PopFront(); + TASSERT( temp == 1, "Append() corrupted list!\n"); + temp = list.PopFront(); + TASSERT( temp == 2, "Append() corrupted list!\n"); + temp = list.PopFront(); + TASSERT( temp == 3, "Append() corrupted list!\n"); + + TASSERT( list.Size() == 0, "Append() somehow made excessively long list!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Prepend_Region() +{ + ZList<int> list; + ZList<int> list2; + int temp = -1; + + list.PushBack(1); + list.PushBack(2); + list.PushBack(3); + + list2.PushBack(4); + list2.PushBack(5); + list2.PushBack(6); + list2.PushBack(7); + list2.PushBack(8); + + ZListAlgo::Prepend(list,list2, list2.At(2), list2.End()); + TASSERT( list.Size() == 6, "Append() failed to create list of proper size!\n"); + + temp = list.PopFront(); + TASSERT( temp == 6, "Append() corrupted list!\n"); + temp = list.PopFront(); + TASSERT( temp == 7, "Append() corrupted list!\n"); + temp = list.PopFront(); + TASSERT( temp == 8, "Append() corrupted list!\n"); + temp = list.PopFront(); + TASSERT( temp == 1, "Append() corrupted list!\n"); + temp = list.PopFront(); + TASSERT( temp == 2, "Append() corrupted list!\n"); + temp = list.PopFront(); + TASSERT( temp == 3, "Append() corrupted list!\n"); + + TASSERT( list.Size() == 0, "Append() somehow made excessively long list!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Remove() +{ + ZList<int> list; + + list.PushBack(1); + list.PushBack(2); + list.PushBack(3); + list.PushBack(3); + list.PushBack(4); + list.PushBack(5); + + ZListIterator<int> a = list.At(3); + ZListIterator<int> b = list.At(4); + + ZListIterator<int> ap = ZListAlgo::Remove(list, 3); + TASSERT( list.Size() == 5, "Remove() failed to produce list of correct size!\n"); + TASSERT( ap == a, "Remove() returned incorrect iterator!\n"); + ZListIterator<int> bp = ZListAlgo::Remove(list, 3); + TASSERT( list.Size() == 4, "Remove() failed to produce list of correct size!\n"); + TASSERT( bp == b, "Remove() returned incorrect iterator!\n"); + TASSERT( list.PopFront() == 1, "Remove() produced incorrect list!\n"); + TASSERT( list.PopFront() == 2, "Remove() produced incorrect list!\n"); + TASSERT( list.PopFront() == 4, "Remove() produced incorrect list!\n"); + TASSERT( list.PopFront() == 5, "Remove() produced incorrect list!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Remove_In_Region() +{ + ZList<int> list; + + list.PushBack(1); // 0 + list.PushBack(2); // 1 + list.PushBack(3); // 2 + list.PushBack(3); // 3 + list.PushBack(4); // 4 + list.PushBack(5); // 5 + + ZListIterator<int> start = list.At(3); + ZListIterator<int> end = list.At(list.Size()); + + ZListAlgo::Remove(list, 3, start, end); + TASSERT( list.Size() == 5, "Remove() failed to produce list of correct size!\n"); + + start = list.At(3); + end = list.At(list.Size()); + ZListAlgo::Remove(list, 3, start, end); + TASSERT( list.Size() == 5, "Remove() removed element outstide of valid range!\n"); + + start = list.At(3); + end = list.At(list.Size()); + ZListAlgo::Remove(list, 1, start, end); + TASSERT( list.Size() == 5, "Remove() removed element outside of valid range!\n"); + TASSERT( list.PopFront() == 1, "Remove() produced incorrect list!\n"); + TASSERT( list.PopFront() == 2, "Remove() produced incorrect list!\n"); + TASSERT( list.PopFront() == 3, "Remove() produced incorrect list!\n"); + TASSERT( list.PopFront() == 4, "Remove() produced incorrect list!\n"); + TASSERT( list.PopFront() == 5, "Remove() produced incorrect list!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_RemoveAll() +{ + ZList<int> list; + + list.PushBack(1); + list.PushBack(2); + list.PushBack(1); + list.PushBack(3); + list.PushBack(2); + list.PushBack(2); + list.PushBack(1); + + ZListAlgo::RemoveAll(list, 2); + + TASSERT( list.Size() == 4, "RemoveAll() produced list of incorrect size!\n"); + + TASSERT( list.PopFront() == 1, "RemoveAll() produced bad list!\n"); + TASSERT( list.PopFront() == 1, "RemoveAll() produced bad list!\n"); + TASSERT( list.PopFront() == 3, "RemoveAll() produced bad list!\n"); + TASSERT( list.PopFront() == 1, "RemoveAll() produced bad list!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_RemoveAll_In_Region() +{ + ZList<int> list; + + list.PushBack(1); + list.PushBack(2); + list.PushBack(1); + list.PushBack(3); + list.PushBack(2); + list.PushBack(2); + list.PushBack(1); + + ZListIterator<int> start = list.At(2); + ZListIterator<int> end = list.At(5); + + ZListAlgo::RemoveAll(list, 2, start, end); + + TASSERT( list.Size() == 6, "RemoveAll() produced list of incorrect size!\n"); + + TASSERT( list.PopFront() == 1, "RemoveAll() produced bad list!\n"); + TASSERT( list.PopFront() == 2, "RemoveAll() produced bad list!\n"); + TASSERT( list.PopFront() == 1, "RemoveAll() produced bad list!\n"); + TASSERT( list.PopFront() == 3, "RemoveAll() produced bad list!\n"); + TASSERT( list.PopFront() == 2, "RemoveAll() produced bad list!\n"); + TASSERT( list.PopFront() == 1, "RemoveAll() produced bad list!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Reverse() +{ + ZList<int> list; + + // test list with odd number of elements + list.PushBack(1); + list.PushBack(2); + list.PushBack(3); + list.PushBack(4); + list.PushBack(5); + ZListAlgo::Reverse(list); + TASSERT( list.Size() == 5, "Reverse() produced list of incorrect size!\n"); + TASSERT( list.PopFront() == 5, "Reverse() produced bad list!\n"); + TASSERT( list.PopFront() == 4, "Reverse() produced bad list!\n"); + TASSERT( list.PopFront() == 3, "Reverse() produced bad list!\n"); + TASSERT( list.PopFront() == 2, "Reverse() produced bad list!\n"); + TASSERT( list.PopFront() == 1, "Reverse() produced bad list!\n"); + + // test list with even number of elements + list.PushBack(1); + list.PushBack(2); + list.PushBack(3); + list.PushBack(4); + ZListAlgo::Reverse(list); + TASSERT( list.Size() == 4, "Reverse() produced list of incorrect size!\n"); + TASSERT( list.PopFront() == 4, "Reverse() produced bad list!\n"); + TASSERT( list.PopFront() == 3, "Reverse() produced bad list!\n"); + TASSERT( list.PopFront() == 2, "Reverse() produced bad list!\n"); + TASSERT( list.PopFront() == 1, "Reverse() produced bad list!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Reverse_In_Region() +{ + ZList<int> list; + ZList<int> list2; + + list.PushBack(1); + list.PushBack(2); + list.PushBack(3); + list.PushBack(4); + list.PushBack(5); + list.PushBack(6); + + ZListIterator<int> start = list.At(1); + ZListIterator<int> end = list.At(4); + + ZListAlgo::Reverse(list, start, end); + + TASSERT( list.Size() == 6, "Reverse() produced list of incorrect size!\n"); + + // store a copy for later testing + list2 = list; + + TASSERT( list.PopFront() == 1, "Reverse() produced bad list!\n"); + TASSERT( list.PopFront() == 4, "Reverse() produced bad list!\n"); + TASSERT( list.PopFront() == 3, "Reverse() produced bad list!\n"); + TASSERT( list.PopFront() == 2, "Reverse() produced bad list!\n"); + TASSERT( list.PopFront() == 5, "Reverse() produced bad list!\n"); + TASSERT( list.PopFront() == 6, "Reverse() produced bad list!\n"); + + // second batch is to make sure the list can be reverse iterated too + TASSERT( list2.PopBack() == 6, "Reverse() produced bad list!\n"); + TASSERT( list2.PopBack() == 5, "Reverse() produced bad list!\n"); + TASSERT( list2.PopBack() == 2, "Reverse() produced bad list!\n"); + TASSERT( list2.PopBack() == 3, "Reverse() produced bad list!\n"); + TASSERT( list2.PopBack() == 4, "Reverse() produced bad list!\n"); + TASSERT( list2.PopBack() == 1, "Reverse() produced bad list!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_ReverseNodes() +{ + ZList<int> list; + + list.PushBack(1); + list.PushBack(2); + list.PushBack(3); + list.PushBack(4); + + ZListAlgo::ReverseNodes(list); + + TASSERT( list.Size() == 4, "ReverseNodes() produced list of incorrect size!\n"); + + TASSERT( list.PopFront() == 4, "ReverseNodes() produced bad list!\n"); + TASSERT( list.PopFront() == 3, "ReverseNodes() produced bad list!\n"); + TASSERT( list.PopFront() == 2, "ReverseNodes() produced bad list!\n"); + TASSERT( list.PopFront() == 1, "ReverseNodes() produced bad list!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_ReverseNodes_In_Region() +{ + ZList<int> list; + ZList<int> list2; + + list.PushBack(1); + list.PushBack(2); + list.PushBack(3); + list.PushBack(4); + list.PushBack(5); + list.PushBack(6); + + ZListIterator<int> start = list.At(1); + ZListIterator<int> end = list.At(4); + + ZListAlgo::ReverseNodes(list, start, end); + + TASSERT( list.Size() == 6, "ReverseNodes() produced list of incorrect size!\n"); + + // store a copy for later testing + list2 = list; + + TASSERT( list.PopFront() == 1, "ReverseNodes() produced bad list!\n"); + TASSERT( list.PopFront() == 4, "ReverseNodes() produced bad list!\n"); + TASSERT( list.PopFront() == 3, "ReverseNodes() produced bad list!\n"); + TASSERT( list.PopFront() == 2, "ReverseNodes() produced bad list!\n"); + TASSERT( list.PopFront() == 5, "ReverseNodes() produced bad list!\n"); + TASSERT( list.PopFront() == 6, "ReverseNodes() produced bad list!\n"); + + // second batch is to make sure the list can be reverse iterated too + TASSERT( list2.PopBack() == 6, "ReverseNodes() produced bad list!\n"); + TASSERT( list2.PopBack() == 5, "ReverseNodes() produced bad list!\n"); + TASSERT( list2.PopBack() == 2, "ReverseNodes() produced bad list!\n"); + TASSERT( list2.PopBack() == 3, "ReverseNodes() produced bad list!\n"); + TASSERT( list2.PopBack() == 4, "ReverseNodes() produced bad list!\n"); + TASSERT( list2.PopBack() == 1, "ReverseNodes() produced bad list!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Slice() +{ + ZList<int> list; + ZList<int> slice; + + list.PushBack(1); + list.PushBack(2); + list.PushBack(3); + list.PushBack(4); + list.PushBack(5); + list.PushBack(6); + + ZListIterator<int> start = list.At(1); // points at 2 + ZListIterator<int> end = list.At(4); // points at 5 + slice = ZListAlgo::Slice(list,start,end); + + TASSERT( list.Size() == 6, "Slice() mutated target list to incorrect size!\n"); + TASSERT( slice.Size() == 3, "Slice() produced list of incorrect size!\n"); + + TASSERT( slice.PopFront() == 2, "Slice() produced bad list!\n"); + TASSERT( slice.PopFront() == 3, "Slice() produced bad list!\n"); + TASSERT( slice.PopFront() == 4, "Slice() produced bad list!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Sort() +{ + ZList<int> list; + ZList<int>::Iterator it; + int i; + int min; + + srand(0xdeadc0de); + + //Add 100 random integers + for(i=0; i<100; i++) + list.PushBack( rand() % 128 ); + + //Sort + ZListAlgo::Sort(list); + + if(list.Size() != 100) + return "Sort() lost elements"; + + //Make sure it is monotonically increasing + for(it=list.Begin(), min = *it; it != list.End(); it++) + { + if(min > (*it)) + return "Found element out of place after Sort()"; + + min = *it; + } + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Sort_Region() +{ + ZList<int> list; + ZList<int>::Iterator it; + ZListIterator<int> start; + ZListIterator<int> end; + int i, min; + + srand(0xdeadc0de); + + //Add 100 random integers + list.PushBack(998); + list.PushBack(999); + for(i=0; i<100; i++) + { + list.PushBack( rand() % 128 ); + } + list.PushBack(1); + start = list.At(2); + end = list.At(list.Size()-1); + + //Sort + ZListAlgo::Sort(list,start,end); + + if(list.Size() != 103) + return "Sort() lost elements"; + + //Make sure the front wasn't moved + TASSERT(list.PopFront() == 998, "Sort() in region touched outside given bounds!\n"); + TASSERT(list.PopFront() == 999, "Sort() in region touched outside given bounds!\n"); + + //Make sure it is monotonically increasing + min = -1; + int temp; + for(i=0; i<100; i++) + { + temp = list.PopFront(); + TASSERT(temp >= min, "Found element out of place after Sort()!\n"); + min = temp; + } + + //Make sure the back wasn't moved + TASSERT(list.PopFront() == 1, "Sort() in region touched outside given bounds!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Sort_Comparator() +{ + ZList<int> list; + ZList<int>::Iterator it; + int i, min; + + srand(0xdeadc0de); + + //Add 100 random integers + for(i=0; i<100; i++) + list.PushBack( rand() % 128 ); + + //Sort + ZListAlgo::Sort(list, ZComparator<int>()); + + if(list.Size() != 100) + return "Sort() lost elements"; + + //Make sure it is monotonically increasing + for(it=list.Begin(), min = *it; it != list.End(); it++) + { + if(min > (*it)) + return "Found element out of place after Sort()"; + + min = *it; + } + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Sort_Comparator_Algorithm() +{ + ZList<int> list; + ZList<int>::Iterator it; + int i, min; + + srand(0xdeadc0de); + + //Add 100 random integers + for(i=0; i<100; i++) + list.PushBack( rand() % 128 ); + + //Sort + ZListAlgo::Sort(list, ZComparator<int>(), ZListMergeSort<int>()); + + if(list.Size() != 100) + return "Sort() lost elements"; + + //Make sure it is monotonically increasing + for(it=list.Begin(), min = *it; it != list.End(); it++) + { + if(min > (*it)) + return "Found element out of place after Sort()"; + + min = *it; + } + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Sort_Comparator_Algorithm_Range() +{ + ZList<int> list; + ZList<int>::Iterator it; + ZListIterator<int> start; + ZListIterator<int> end; + int i, min; + + srand(0xdeadc0de); + + //Add 100 random integers + list.PushBack(998); + list.PushBack(999); + for(i=0; i<100; i++) + { + list.PushBack( rand() % 128 ); + } + list.PushBack(1); + start = list.At(2); + end = list.At(list.Size()-1); + + //Sort + ZListAlgo::Sort(list, ZComparator<int>(), ZListMergeSort<int>(), start,end); + + if(list.Size() != 103) + return "Sort() lost elements"; + + //Make sure the front wasn't moved + TASSERT(list.PopFront() == 998, "Sort() in region touched outside given bounds!\n"); + TASSERT(list.PopFront() == 999, "Sort() in region touched outside given bounds!\n"); + + //Make sure it is monotonically increasing + min = -1; + int temp; + for(i=0; i<100; i++) + { + temp = list.PopFront(); + TASSERT(temp >= min, "Found element out of place after Sort()!\n"); + min = temp; + } + + //Make sure the back wasn't moved + TASSERT(list.PopFront() == 1, "Sort() in region touched outside given bounds!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Split() +{ + ZList<int> list1, list2; + ZList<int>::Iterator it; + int i; + + //list1 = 1, 2, 3, 4, 5 + list1.Clear(); + + for(i = 0; i < 5; i++) + list1.PushBack(i + 1); + + //Test inclusion into secondary list + it = ZListAlgo::FindFirst(list1, 3); + + list2 = ZListAlgo::Split(list1, it); + + if(list1.Size() != 2) + return "List 1 after split is wrong size"; + if(list2.Size() != 3) + return "List 2 after split is wrong size"; + if(list1.Front() != 1) + return "List 1 has wrong front value after split"; + if(list1.Back() != 2) + return "List 1 has wrong back value after split"; + if(list2.Front() != 3) + return "List 2 has wrong front value after split"; + if(list2.Back() != 5) + return "List 2 has wrong back value after split"; + + return ZTEST_SUCCESS; + +} + +/*************************************************************************/ + +static const char* test_SwapElements() +{ + ZList<int> list; + ZList<int>::Iterator e1, e2, it; + int i; + + //Create list: 1,2,5,4,3 + //We'll swap 3 & 5 to create: 1,2,3,4,5 + list.PushBack(1); + list.PushBack(2); + list.PushBack(5); + list.PushBack(4); + list.PushBack(3); + + //Find elements 3 and 5 + e1 = ZListAlgo::FindFirst(list, 5); + e2 = ZListAlgo::FindFirst(list, 3); + + //Swap them + ZListAlgo::SwapElements(list, e1, e2); + + //Verify swap worked, since now they will be sorted + for(i=1, it=list.Begin(); it != list.End(); it++, i++) + { + if((*it) != i) + return "SwapElements() did not correctly the elements"; + } + + //Try making a list of two elements and swapping them (i.e. swapping front and back) + list.Clear(); + list.PushBack(100); + list.PushBack(200); + e1 = ZListAlgo::FindFirst(list, 100); + e2 = ZListAlgo::FindFirst(list, 200); + ZListAlgo::SwapElements(list, e1, e2); + + if(list.Front() != 200) + return "SwapElements() did not correctly swap front and back elements"; + if(list.Back() != 100) + return "SwapElements() did not correctly swap front and back elements"; + + return ZTEST_SUCCESS; +} diff --git a/ZTestSuite/Test-ZName.cpp b/ZTestSuite/Test-ZName.cpp new file mode 100644 index 0000000..f88585c --- /dev/null +++ b/ZTestSuite/Test-ZName.cpp @@ -0,0 +1,96 @@ +/* + Test-ZName.cpp + Author: James Russell <jcrussell@762studios.com> + + Purpose: Unit Test the ZName class. + + Changelog: + 12/18/2011 - Removed dependency on ZString (crertel) + 2011/04/07 - creation (jcrussell) +*/ + +#include "ZUnitTest.hpp" + +#include <ZUtil/ZName.hpp> + +static const char* test_Constructors(); +static const char* test_Operators(); +static const char* test_ToString(); + +//List of unit tests +ZUnitTest ZNameUnitTests[] = +{ + { "ZName: Constructors", test_Constructors }, + { "ZName: Operators", test_Operators }, + { "ZName: String Conversion", test_ToString } +}; + +//Now declare the ZUnitTestBlock associated with this. +DECLARE_ZTESTBLOCK(ZName); + +/*************************************************************************/ + +static bool testFunction(ZName _name, ZString _string) +{ + return _name.ToString() == _string; +} + +static const char* test_Constructors() +{ + ZName name1("TestName1"); + ZName name2("TestName2"); + + TASSERT(testFunction(name1, "TestName1"), "ZName: Failed to copy construct and compare correctly!"); + TASSERT(!testFunction(name2, "WRONG!"), "ZName: Failed to copy construct and compare incorrectly!") + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Operators() +{ + ZName testName1 = "Name1"; + ZName testName2("Name2"); + ZName testName3; + + ZName testName4 = "TestName4"; + ZName testName5("TestName5"); + ZName testName6; + + testName3 = "Name3"; + + TASSERT(testName1 == "Name1", "ZName : Setting testName1 Failed!"); + TASSERT(testName2 == "Name2", "ZName : Setting testName2 Failed!"); + TASSERT(testName3 == "Name3", "ZName : Setting testName3 Failed!"); + + TASSERT(testName1 != testName2, "ZName : Comparison of testName1 and testName2 Failed!"); + TASSERT(testName1 != testName3, "ZName : Comparison of testName1 and testName3 Failed!"); + TASSERT(testName2 != testName3, "ZName : Comparison of testName1 and testName2 Failed!"); + + testName6 = "TestName6"; + + TASSERT(testName4 == "TestName4", "ZName : Setting testName4 Failed!"); + TASSERT(testName5 == "TestName5", "ZName : Setting testName5 Failed!"); + TASSERT(testName6 == "TestName6", "ZName : Setting testName6 Failed!"); + + TASSERT(testName4 != testName5, "ZName : Comparison of testName4 and testName5 Failed!"); + TASSERT(testName4 != testName6, "ZName : Comparison of testName4 and testName6 Failed!"); + TASSERT(testName5 != testName6, "ZName : Comparison of testName5 and testName6 Failed!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ +static const char* test_ToString() +{ + ZName testName1 = "Name1"; + + ZString testString1 = testName1.ToString(); + + TASSERT(testString1 == "Name1", "ZName : Unable to convert to ZString!"); + + TASSERT(testString1.PopBack() == '1', "ZName : Unable to manipulate converted ZString!"); + + return ZTEST_SUCCESS; +} diff --git a/ZTestSuite/Test-ZRandomGenerator.cpp b/ZTestSuite/Test-ZRandomGenerator.cpp new file mode 100644 index 0000000..0763e70 --- /dev/null +++ b/ZTestSuite/Test-ZRandomGenerator.cpp @@ -0,0 +1,371 @@ +/* + Test-ZRandomGenerator.cpp + Author: James Russell <jcrussell@762studios.com> + + Purpose: Unit Test the ZRandomGenerator class. + + Changelog: + 2011/12/18 - Removed dependency on ZString (crertel) + 2011/11/27 - creation (jcrussell) +*/ + +#include "ZUnitTest.hpp" + +#include <ZUtil/ZAlloc.hpp> +#include <ZUtil/ZRandomGenerator.hpp> + +//#include <ZUtil/ZMath.hpp> + +static const char* testMersenne(); +static const char* testCMWC(); +static const char* testSmallPRNG(); + +#define FPEQUALS(a,b) (a == b) + +#define ZRG_TEST_SEED_1 (1000) +#define ZRG_TEST_SEED_2 (1024) + +#define ZRG_TEST_FLOAT_RANGE_MIN (-64000.0f) +#define ZRG_TEST_FLOAT_RANGE_MAX (64000.0f) + +#define ZRG_TEST_INT_RANGE_MIN (-10000) +#define ZRG_TEST_INT_RANGE_MAX (10000) + +//List of unit tests +ZUnitTest ZRandomGeneratorUnitTests[] = +{ + { + "Test SST_Mersenne Generator", + testMersenne + }, + { + "Test SST_CMWC Generator", + testCMWC + }, + { + "Test SST_SmallPRNG Generator", + testSmallPRNG + } +}; + +//Now declare the ZUnitTestBlock associated with this. +DECLARE_ZTESTBLOCK(ZRandomGenerator); + +/*************************************************************************/ + +static const char* testGenerator(ZRandomGenerator *generator) +{ + uint32_t seed; + uint64_t sequence, correctSequence; + + seed = generator->GetSeed(); + + //First, we test grabbing floats + float f1, f2, f3, f4; + + f1 = generator->GetFloat(); + f2 = generator->GetFloat(); + f3 = generator->GetFloat(); + f4 = generator->GetFloat(); + + correctSequence = 4; + + sequence = generator->GetSequence(); + + TASSERT(sequence == correctSequence, + "Generator has incorrect sequence number after GetFloat!"); + + TASSERT(f1 >= 0.0f && f1 < 1.0f, "f1 is out of range [0, 1.0)!"); + TASSERT(f2 >= 0.0f && f2 < 1.0f, "f2 is out of range [0, 1.0)!"); + TASSERT(f3 >= 0.0f && f3 < 1.0f, "f3 is out of range [0, 1.0)!"); + TASSERT(f4 >= 0.0f && f4 < 1.0f, "f4 is out of range [0, 1.0)!"); + + //Swap seed, make sure we don't get the same four floats + float f5, f6, f7, f8; + + generator->SetSeed(ZRG_TEST_SEED_2); + + seed = generator->GetSeed(); + + TASSERT(seed == ZRG_TEST_SEED_2, "After reseeding, generator returns incorrect seed!"); + + sequence = generator->GetSequence(); + + TASSERT(sequence == 0, "After reseeding, generator does not have sequence zero!"); + + f5 = generator->GetFloat(); + f6 = generator->GetFloat(); + f7 = generator->GetFloat(); + f8 = generator->GetFloat(); + + sequence = generator->GetSequence(); + + TASSERT(sequence == correctSequence, + "Generator has incorrect sequence number after SetSeed and four gets!"); + + bool equal; + + equal = FPEQUALS(f1, f5) && FPEQUALS(f2, f6) && FPEQUALS(f3, f7) && FPEQUALS(f4, f8); + + TASSERT(!equal, "After reseeding, generator generates same four numbers!"); + + //Now we test grabbing an array of floats + float f1a[10], f2a[1000], f3a[100000]; + + generator->GetFloatArray(f1a, sizeof(f1a) / sizeof(float)); + generator->GetFloatArray(f2a, sizeof(f2a) / sizeof(float)); + generator->GetFloatArray(f3a, sizeof(f3a) / sizeof(float)); + + correctSequence = correctSequence + (sizeof(f1a) / sizeof(float)) + (sizeof(f2a) / sizeof(float)) + (sizeof(f3a) / sizeof(float)); + + sequence = generator->GetSequence(); + + TASSERT(sequence == correctSequence, + "Generator has incorrect sequence number after GetFloatArray!"); + + for (size_t i = 0; i < sizeof(f1a) / sizeof(float); i++) + { + TASSERT(f1a[i] >= 0.0f && f1a[i] < 1.0f, "f1a has members out of range!"); + } + + for (size_t i = 0; i < sizeof(f2a) / sizeof(float); i++) + { + TASSERT(f2a[i] >= 0.0f && f2a[i] < 1.0f, "f2a has members out of range!"); + } + + for (size_t i = 0; i < sizeof(f3a) / sizeof(float); i++) + { + TASSERT(f3a[i] >= 0.0f && f3a[i] < 1.0f, "f3a has members out of range!"); + } + + //Now we test grabbing floats in a range + f1 = generator->GetFloatInRange(ZRG_TEST_FLOAT_RANGE_MIN, ZRG_TEST_FLOAT_RANGE_MAX); + f2 = generator->GetFloatInRange(ZRG_TEST_FLOAT_RANGE_MIN, ZRG_TEST_FLOAT_RANGE_MAX); + f3 = generator->GetFloatInRange(ZRG_TEST_FLOAT_RANGE_MIN, ZRG_TEST_FLOAT_RANGE_MAX); + f4 = generator->GetFloatInRange(ZRG_TEST_FLOAT_RANGE_MIN, ZRG_TEST_FLOAT_RANGE_MAX); + + correctSequence += 4; + + sequence = generator->GetSequence(); + + TASSERT(sequence == correctSequence, + "Generator has incorrect sequence number after GetFloatInRange!"); + + TASSERT(f1 >= ZRG_TEST_FLOAT_RANGE_MIN && f1 < ZRG_TEST_FLOAT_RANGE_MAX, "f1 is out of range [ZRG_TEST_FLOAT_RANGE_MIN, ZRG_TEST_FLOAT_RANGE_MAX)!"); + TASSERT(f2 >= ZRG_TEST_FLOAT_RANGE_MIN && f2 < ZRG_TEST_FLOAT_RANGE_MAX, "f2 is out of range [ZRG_TEST_FLOAT_RANGE_MIN, ZRG_TEST_FLOAT_RANGE_MAX)!"); + TASSERT(f3 >= ZRG_TEST_FLOAT_RANGE_MIN && f3 < ZRG_TEST_FLOAT_RANGE_MAX, "f3 is out of range [ZRG_TEST_FLOAT_RANGE_MIN, ZRG_TEST_FLOAT_RANGE_MAX)!"); + TASSERT(f4 >= ZRG_TEST_FLOAT_RANGE_MIN && f4 < ZRG_TEST_FLOAT_RANGE_MAX, "f4 is out of range [ZRG_TEST_FLOAT_RANGE_MIN, ZRG_TEST_FLOAT_RANGE_MAX)!"); + + //Now we test grabbing arrays of floats in a range + generator->GetFloatArrayInRange(f1a, sizeof(f1a) / sizeof(float), ZRG_TEST_FLOAT_RANGE_MIN, ZRG_TEST_FLOAT_RANGE_MAX); + generator->GetFloatArrayInRange(f2a, sizeof(f2a) / sizeof(float), ZRG_TEST_FLOAT_RANGE_MIN, ZRG_TEST_FLOAT_RANGE_MAX); + generator->GetFloatArrayInRange(f3a, sizeof(f3a) / sizeof(float), ZRG_TEST_FLOAT_RANGE_MIN, ZRG_TEST_FLOAT_RANGE_MAX); + + correctSequence = correctSequence + (sizeof(f1a) / sizeof(float)) + (sizeof(f2a) / sizeof(float)) + (sizeof(f3a) / sizeof(float)); + + sequence = generator->GetSequence(); + + TASSERT(sequence == correctSequence, + "Generator has incorrect sequence number after GetFloatArrayInRange!"); + + for (size_t i = 0; i < sizeof(f1a) / sizeof(float); i++) + { + TASSERT(f1a[i] >= ZRG_TEST_FLOAT_RANGE_MIN && f1a[i] < ZRG_TEST_FLOAT_RANGE_MAX, "f1a has members out of range!"); + } + + for (size_t i = 0; i < sizeof(f2a) / sizeof(float); i++) + { + TASSERT(f2a[i] >= ZRG_TEST_FLOAT_RANGE_MIN && f2a[i] < ZRG_TEST_FLOAT_RANGE_MAX, "f2a has members out of range!"); + } + + for (size_t i = 0; i < sizeof(f3a) / sizeof(float); i++) + { + TASSERT(f3a[i] >= ZRG_TEST_FLOAT_RANGE_MIN && f3a[i] < ZRG_TEST_FLOAT_RANGE_MAX, "f3a has members out of range!"); + } + + //Now we grab an int in a range + int i1, i2, i3, i4; + + i1 = generator->GetIntInRange(ZRG_TEST_INT_RANGE_MIN, ZRG_TEST_INT_RANGE_MAX); + i2 = generator->GetIntInRange(ZRG_TEST_INT_RANGE_MIN, ZRG_TEST_INT_RANGE_MAX); + i3 = generator->GetIntInRange(ZRG_TEST_INT_RANGE_MIN, ZRG_TEST_INT_RANGE_MAX); + i4 = generator->GetIntInRange(ZRG_TEST_INT_RANGE_MIN, ZRG_TEST_INT_RANGE_MAX); + + correctSequence += 4; + + sequence = generator->GetSequence(); + + TASSERT(sequence == correctSequence, + "Generator has incorrect sequence number after GetIntInRange!"); + + TASSERT(i1 >= ZRG_TEST_INT_RANGE_MIN && i1 < ZRG_TEST_INT_RANGE_MAX, "i1 is out of range [ZRG_TEST_INT_RANGE_MIN, ZRG_TEST_INT_RANGE_MAX)!"); + TASSERT(i2 >= ZRG_TEST_INT_RANGE_MIN && i2 < ZRG_TEST_INT_RANGE_MAX, "i2 is out of range [ZRG_TEST_INT_RANGE_MIN, ZRG_TEST_INT_RANGE_MAX)!"); + TASSERT(i3 >= ZRG_TEST_INT_RANGE_MIN && i3 < ZRG_TEST_INT_RANGE_MAX, "i3 is out of range [ZRG_TEST_INT_RANGE_MIN, ZRG_TEST_INT_RANGE_MAX)!"); + TASSERT(i4 >= ZRG_TEST_INT_RANGE_MIN && i4 < ZRG_TEST_INT_RANGE_MAX, "i4 is out of range [ZRG_TEST_INT_RANGE_MIN, ZRG_TEST_INT_RANGE_MAX)!"); + + //Now we grab an int array in range + int i1a[10], i2a[1000], i3a[100000]; + + generator->GetIntArrayInRange(i1a, sizeof(i1a) / sizeof(int), ZRG_TEST_INT_RANGE_MIN, ZRG_TEST_INT_RANGE_MAX); + generator->GetIntArrayInRange(i2a, sizeof(i2a) / sizeof(int), ZRG_TEST_INT_RANGE_MIN, ZRG_TEST_INT_RANGE_MAX); + generator->GetIntArrayInRange(i3a, sizeof(i3a) / sizeof(int), ZRG_TEST_INT_RANGE_MIN, ZRG_TEST_INT_RANGE_MAX); + + correctSequence = correctSequence + (sizeof(i1a) / sizeof(int)) + (sizeof(i2a) / sizeof(int)) + (sizeof(i3a) / sizeof(int)); + + sequence = generator->GetSequence(); + + TASSERT(sequence == correctSequence, + "Generator has incorrect sequence number after GetIntArrayInRange!"); + + for (size_t i = 0; i < sizeof(i1a) / sizeof(int); i++) + { + TASSERT(i1a[i] >= ZRG_TEST_INT_RANGE_MIN && i1a[i] < ZRG_TEST_INT_RANGE_MAX, "i1a has members out of range!"); + } + + for (size_t i = 0; i < sizeof(i2a) / sizeof(int); i++) + { + TASSERT(i2a[i] >= ZRG_TEST_INT_RANGE_MIN && i2a[i] < ZRG_TEST_INT_RANGE_MAX, "i2a has members out of range!"); + } + + for (size_t i = 0; i < sizeof(i3a) / sizeof(int); i++) + { + TASSERT(i3a[i] >= ZRG_TEST_INT_RANGE_MIN && i3a[i] < ZRG_TEST_INT_RANGE_MAX, "i3a has member out of range!"); + } + + //Now we grab some gaussian distributed floats + f1 = generator->GetGaussianFloat(ZRG_TEST_FLOAT_RANGE_MIN, ZRG_TEST_FLOAT_RANGE_MAX); + f2 = generator->GetGaussianFloat(ZRG_TEST_FLOAT_RANGE_MIN, ZRG_TEST_FLOAT_RANGE_MAX); + f3 = generator->GetGaussianFloat(ZRG_TEST_FLOAT_RANGE_MIN, ZRG_TEST_FLOAT_RANGE_MAX); + f4 = generator->GetGaussianFloat(ZRG_TEST_FLOAT_RANGE_MIN, ZRG_TEST_FLOAT_RANGE_MAX); + + correctSequence += 8; //Two per call + + sequence = generator->GetSequence(); + + TASSERT(sequence == correctSequence, + "Generator has incorrect sequence number after GetGaussianFloat!"); + + TASSERT(f1 >= ZRG_TEST_FLOAT_RANGE_MIN && f1 < ZRG_TEST_FLOAT_RANGE_MAX, "f1 is out of range [ZRG_TEST_FLOAT_RANGE_MIN, ZRG_TEST_FLOAT_RANGE_MAX) for gaussian test!"); + TASSERT(f2 >= ZRG_TEST_FLOAT_RANGE_MIN && f2 < ZRG_TEST_FLOAT_RANGE_MAX, "f2 is out of range [ZRG_TEST_FLOAT_RANGE_MIN, ZRG_TEST_FLOAT_RANGE_MAX) for gaussian test!"); + TASSERT(f3 >= ZRG_TEST_FLOAT_RANGE_MIN && f3 < ZRG_TEST_FLOAT_RANGE_MAX, "f3 is out of range [ZRG_TEST_FLOAT_RANGE_MIN, ZRG_TEST_FLOAT_RANGE_MAX) for gaussian test!"); + TASSERT(f4 >= ZRG_TEST_FLOAT_RANGE_MIN && f4 < ZRG_TEST_FLOAT_RANGE_MAX, "f4 is out of range [ZRG_TEST_FLOAT_RANGE_MIN, ZRG_TEST_FLOAT_RANGE_MAX) for gaussian test!"); + + //Now we grab some gaussian distributed floats in an array + generator->GetGaussianFloatArray(f1a, sizeof(f1a) / sizeof(float), ZRG_TEST_FLOAT_RANGE_MIN, ZRG_TEST_FLOAT_RANGE_MAX); + generator->GetGaussianFloatArray(f2a, sizeof(f2a) / sizeof(float), ZRG_TEST_FLOAT_RANGE_MIN, ZRG_TEST_FLOAT_RANGE_MAX); + generator->GetGaussianFloatArray(f3a, sizeof(f3a) / sizeof(float), ZRG_TEST_FLOAT_RANGE_MIN, ZRG_TEST_FLOAT_RANGE_MAX); + + correctSequence = correctSequence + 2*(sizeof(f1a) / sizeof(float)) + 2*(sizeof(f2a) / sizeof(float)) + 2*(sizeof(f3a) / sizeof(float)); //Two per call + + sequence = generator->GetSequence(); + + TASSERT(sequence == correctSequence, + "Generator has incorrect sequence number after GetGaussianFloatArray!"); + + for (size_t i = 0; i < sizeof(f1a) / sizeof(float); i++) + { + TASSERT(f1a[i] >= ZRG_TEST_FLOAT_RANGE_MIN && f1a[i] < ZRG_TEST_FLOAT_RANGE_MAX, "f1a has members out of range for gaussian test!"); + } + + for (size_t i = 0; i < sizeof(f2a) / sizeof(float); i++) + { + TASSERT(f2a[i] >= ZRG_TEST_FLOAT_RANGE_MIN && f2a[i] < ZRG_TEST_FLOAT_RANGE_MAX, "f2a has members out of range for gaussian test!"); + } + + for (size_t i = 0; i < sizeof(f3a) / sizeof(float); i++) + { + TASSERT(f3a[i] >= ZRG_TEST_FLOAT_RANGE_MIN && f3a[i] < ZRG_TEST_FLOAT_RANGE_MAX, "f3a has member out of range for gaussian test!\n"); + } + + //Now we grab some gaussian distributed ints + i1 = generator->GetGaussianInt(ZRG_TEST_INT_RANGE_MIN, ZRG_TEST_INT_RANGE_MAX); + i2 = generator->GetGaussianInt(ZRG_TEST_INT_RANGE_MIN, ZRG_TEST_INT_RANGE_MAX); + i3 = generator->GetGaussianInt(ZRG_TEST_INT_RANGE_MIN, ZRG_TEST_INT_RANGE_MAX); + i4 = generator->GetGaussianInt(ZRG_TEST_INT_RANGE_MIN, ZRG_TEST_INT_RANGE_MAX); + + correctSequence += 8; //Two per call + + sequence = generator->GetSequence(); + + TASSERT(sequence == correctSequence, + "Generator has incorrect sequence number after GetGaussianInt!"); + + TASSERT(i1 >= ZRG_TEST_INT_RANGE_MIN && i1 < ZRG_TEST_INT_RANGE_MAX, "i1 is out of range [ZRG_TEST_INT_RANGE_MIN, ZRG_TEST_INT_RANGE_MAX) for gaussian test!"); + TASSERT(i2 >= ZRG_TEST_INT_RANGE_MIN && i2 < ZRG_TEST_INT_RANGE_MAX, "i2 is out of range [ZRG_TEST_INT_RANGE_MIN, ZRG_TEST_INT_RANGE_MAX) for gaussian test!"); + TASSERT(i3 >= ZRG_TEST_INT_RANGE_MIN && i3 < ZRG_TEST_INT_RANGE_MAX, "i3 is out of range [ZRG_TEST_INT_RANGE_MIN, ZRG_TEST_INT_RANGE_MAX) for gaussian test!"); + TASSERT(i4 >= ZRG_TEST_INT_RANGE_MIN && i4 < ZRG_TEST_INT_RANGE_MAX, "i4 is out of range [ZRG_TEST_INT_RANGE_MIN, ZRG_TEST_INT_RANGE_MAX) for gaussian test!"); + + //Now we grab some gaussian distributed ints in an array + generator->GetGaussianIntArray(i1a, sizeof(i1a) / sizeof(int), ZRG_TEST_INT_RANGE_MIN, ZRG_TEST_INT_RANGE_MAX); + generator->GetGaussianIntArray(i2a, sizeof(i2a) / sizeof(int), ZRG_TEST_INT_RANGE_MIN, ZRG_TEST_INT_RANGE_MAX); + generator->GetGaussianIntArray(i3a, sizeof(i3a) / sizeof(int), ZRG_TEST_INT_RANGE_MIN, ZRG_TEST_INT_RANGE_MAX); + + correctSequence = correctSequence + 2*(sizeof(i1a) / sizeof(int)) + 2*(sizeof(i2a) / sizeof(int)) + 2*(sizeof(i3a) / sizeof(int)); + + sequence = generator->GetSequence(); + + TASSERT(sequence == correctSequence, + "Generator has incorrect sequence number after GetGaussianIntArray!"); + + for (size_t i = 0; i < sizeof(i1a) / sizeof(int); i++) + { + TASSERT(i1a[i] >= ZRG_TEST_INT_RANGE_MIN && i1a[i] < ZRG_TEST_INT_RANGE_MAX, "i1a has members out of range for guassian test!"); + } + + for (size_t i = 0; i < sizeof(i2a) / sizeof(int); i++) + { + TASSERT(i2a[i] >= ZRG_TEST_INT_RANGE_MIN && i2a[i] < ZRG_TEST_INT_RANGE_MAX, "i2a has members out of range for guassian test!"); + } + + for (size_t i = 0; i < sizeof(i3a) / sizeof(int); i++) + { + TASSERT(i3a[i] >= ZRG_TEST_INT_RANGE_MIN && i3a[i] < ZRG_TEST_INT_RANGE_MAX, "i3a has member %i (%i) out of range for gaussian test!\n"); + } + + return ZTEST_SUCCESS; +} + +static const char* testMersenne() +{ + ZRandomGenerator *generator; + + generator = znew ZRandomGenerator(SST_PRNG_MERSENNE, ZRG_TEST_SEED_1); + + TASSERT(generator->GetSeed() == ZRG_TEST_SEED_1, "Mersenne Generator has incorrect seed !"); + + const char* result = testGenerator(generator); + + zdelete generator; + + return result; +} + +static const char* testCMWC() +{ + ZRandomGenerator *generator; + + generator = znew ZRandomGenerator(SST_PRNG_CMWC, ZRG_TEST_SEED_1); + + TASSERT(generator->GetSeed() == ZRG_TEST_SEED_1, "CMWC Generator has incorrect seed!"); + + const char* result = testGenerator(generator); + + zdelete generator; + + return result; +} + +static const char* testSmallPRNG() +{ + ZRandomGenerator *generator; + + generator = znew ZRandomGenerator(SST_PRNG_SMALLPRNG, ZRG_TEST_SEED_1); + + TASSERT(generator->GetSeed() == ZRG_TEST_SEED_1, "Small PRNG Generator has incorrect seed!"); + + const char* result = testGenerator(generator); + + zdelete generator; + + return result; +} diff --git a/ZTestSuite/Test-ZReferenceCounter.cpp b/ZTestSuite/Test-ZReferenceCounter.cpp new file mode 100644 index 0000000..0531f99 --- /dev/null +++ b/ZTestSuite/Test-ZReferenceCounter.cpp @@ -0,0 +1,106 @@ +/* + Test-ZReferenceCounter.cpp + Author: James Russell <jcrussell@762studios.com> + + Purpose: Unit Test the ZReferenceCounter class. +*/ + +#include "ZUnitTest.hpp" + +#include <ZUtil/ZConcurrency.hpp> +#include <ZUtil/ZReferenceCounter.hpp> +#include <SST/SST_Thread.h> // SST_Concurrency_YieldThread() + +static const char* test_GainLoseReferences(); +static const char* test_Signal(); + +//List of unit tests +ZUnitTest ZReferenceCounterUnitTests[] = +{ + { "ZReferenceCounter: Gain / Lose References", test_GainLoseReferences }, + { "ZReferenceCounter: Signal", test_Signal } +}; + +//Now declare the ZUnitTestBlock associated with this. +DECLARE_ZTESTBLOCK(ZReferenceCounter); + + +/*************************************************************************/ + +static const char* test_GainLoseReferences() +{ + ZReferenceCounter counter; + + //Ensure both start at zero + TASSERT(counter.GetStrongRefCount() == 0, "Strong count set to non-zero value on default construct!"); + TASSERT(counter.GetWeakRefCount() == 0, "Weak count set to non-zero value on default construct!"); + + //Test GainStrongRef() + counter.GainStrongRef(); + TASSERT(counter.GetStrongRefCount() == 1, "Strong count not equal to 1 after strong reference gained!"); + + //Test GainWeakRef() + counter.GainWeakRef(); + counter.GainWeakRef(); + TASSERT(counter.GetWeakRefCount() == 2, "Weak count not equal to 2 after double increment!"); + + //Test validity of both counters after weak ref decrement + uint32_t combinedCount = counter.LoseWeakRef(); + TASSERT(ZREFCOUNTER_EXTRACT_STRONG_REF(combinedCount) == 1, "After losing weak reference, strong count does not equal one!"); + TASSERT(ZREFCOUNTER_EXTRACT_WEAK_REF(combinedCount) == 1, "After losing weak reference, weak count does not equal one!"); + + //Test validity of both counters after strong ref decrement + combinedCount = counter.LoseStrongRef(); + TASSERT(ZREFCOUNTER_EXTRACT_STRONG_REF(combinedCount) == 0, "After losing strong reference, strong count does not equal zero!"); + TASSERT(ZREFCOUNTER_EXTRACT_WEAK_REF(combinedCount) == 1, "After losing strong reference, weak count does not equal one!"); + + //Test validity of both counters when all references are lost + combinedCount = counter.LoseWeakRef(); + TASSERT(ZREFCOUNTER_EXTRACT_STRONG_REF(combinedCount) == 0, "After losing second weak reference, strong count does not equal zero!"); + TASSERT(ZREFCOUNTER_EXTRACT_WEAK_REF(combinedCount) == 0, "After losing second weak reference, weak count does not equal one!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static int signalDeallocate(void* _refCounter) +{ + //This should block + reinterpret_cast<ZReferenceCounter*>(_refCounter)->SignalDeallocateObject(); + + return 0; +} + +static const char* test_Signal() +{ + ZReferenceCounter counter; + + counter.GainStrongRef(); + counter.GainWeakRef(); + + TASSERT(counter.GetStrongRefCount() == 1, "Strong count incorrect after GainStrongRef!"); + TASSERT(counter.GetWeakRefCount() == 1, "Weak count incorrect after GainWeakRef!"); + + TASSERT(counter.SignalInUse(), "SignalInUse returned false when it should be valid to use!"); + + TASSERT(counter.State > 0, "State not increased after SignalInUse!"); + + ZThreadContext ctxt = ZConcurrency::CreateThread(signalDeallocate, &counter); + + //At this point, the other thread should be waiting on this one, but + //should signal us by setting state to NULL with an atomic XOR + while (counter.State > 0) + SST_Concurrency_YieldThread(); + + TASSERT(counter.SignalInUse() == false, "SignalInUse returned true when it should be invalid to use!"); + + counter.SignalUnused(); //This should allow the thread to return from the SignalDeallocate method + + ZConcurrency::WaitThread(ctxt); + ZConcurrency::DestroyThread(ctxt); + + TASSERT(counter.State == (-1 & ZREFCOUNTER_DEALLOC_BIT), "State variable invalid after SignalDeallocate and SignalUnused!"); + + return ZTEST_SUCCESS; +} diff --git a/ZTestSuite/Test-ZRegistry.cpp b/ZTestSuite/Test-ZRegistry.cpp new file mode 100644 index 0000000..f0c243c --- /dev/null +++ b/ZTestSuite/Test-ZRegistry.cpp @@ -0,0 +1,89 @@ + + +#include "ZUnitTest.hpp" + +#include <ZUtil/ZSmartPointer.hpp> +#include <ZUtil/ZRegistry.hpp> + +#include <iostream> + +static const char* test_PutProducesValidNodes(); +static const char* test_GetAfterPut(); +static const char* test_Erase(); +static const char* test_EraseHierarchy(); + +//List of unit tests +ZUnitTest ZRegistryUnitTests[] = +{ + { "ZRegistry: Put() produces valid nodes.", test_PutProducesValidNodes }, + { "ZRegistry: Get() after Put() finds the value.", test_GetAfterPut }, + { "ZRegistry: Erase", test_Erase }, + { "ZRegistry: Erase hierarchy", test_EraseHierarchy }, +}; + +DECLARE_ZTESTBLOCK(ZRegistry); + +/*************************************************************************/ + +static const char* test_PutProducesValidNodes() +{ + ZRegistry reg; + + reg.Put("A.B.C", "100"); + + TASSERT(reg.Get("A").Valid(), "Registry failed to create first key node!"); + TASSERT(reg.Get("A.B").Valid(), "Registry failed to create first key node!"); + TASSERT(reg.Get("A.B.C").Valid(), "Registry failed to create first key node!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_GetAfterPut() +{ + ZRegistry reg; + + reg.Put("A", "10"); + reg.Put("A.B", "20"); + + TASSERT(reg.Get("A").GetString() == "10", "Registry does not contain correct string value!"); + TASSERT(reg.Get("A").GetInt() == 10, "Registry did not convert correct integer value!"); + TASSERT(reg.Get("A").GetDouble() == 10.0, "ZRegistry did not convert correct double value!"); + + TASSERT(reg.Get("A.B").GetString() == "20", "Registry does not contain correct string value!"); + TASSERT(reg.Get("A.B").GetInt() == 20, "Registry did not convert correct integer value!"); + TASSERT(reg.Get("A.B").GetDouble() == 20.0, "ZRegistry did not convert correct double value!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Erase() +{ + ZRegistry reg; + + reg.Put("A", "Test"); + reg.Erase("A"); + + TASSERT(!reg.Get("A").Valid(), "Erased value still queryable"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_EraseHierarchy() +{ + ZRegistry reg; + + reg.Put("A.B", "Test2"); + + reg.Erase("A"); + + TASSERT(!reg.Get("A.B").Valid(), "Child node should have been erased but was not"); + + return ZTEST_SUCCESS; + +} \ No newline at end of file diff --git a/ZTestSuite/Test-ZRingBuffer.cpp b/ZTestSuite/Test-ZRingBuffer.cpp new file mode 100644 index 0000000..6016091 --- /dev/null +++ b/ZTestSuite/Test-ZRingBuffer.cpp @@ -0,0 +1,1307 @@ +#include "ZUnitTest.hpp" + +//Hijack the assert +#define ZSTL_ASSERT(condition, message) SST_OS_RuntimeAssert(condition, message) + +#include <ZSTL/ZRingBuffer.hpp> + +/* construction, size, capacity, empty and full */ +static const char* test_Constructors_Array_Data_Length_Capacity(); +static const char* test_Empty(); +static const char* test_Full(); + +/* primary accessors */ +static const char* test_Front(); +static const char* test_Back(); + +/* primary removal operations */ +static const char* test_PopFront(); +static const char* test_PopBack(); + +/* primary add operations */ +static const char* test_PushFront_OverflowUnsafe(); +static const char* test_PushFront_OverflowAssert(); +static const char* test_PushFront_OverflowIgnore(); +static const char* test_PushFront_OverflowDropFront(); +static const char* test_PushFront_OverflowDropBack(); +static const char* test_PushFront_OverflowOverwrite(); +static const char* test_PushFront_OverflowEvict(); +static const char* test_PushFront_OverflowGrow(); + +static const char* test_PushBack_OverflowUnsafe(); +static const char* test_PushBack_OverflowAssert(); +static const char* test_PushBack_OverflowIgnore(); +static const char* test_PushBack_OverflowDropFront(); +static const char* test_PushBack_OverflowDropBack(); +static const char* test_PushBack_OverflowOverwrite(); +static const char* test_PushBack_OverflowEvict(); +static const char* test_PushBack_OverflowGrow(); + +/* secondary accessors */ +static const char* test_AbsoluteIndex(); +static const char* test_At(); + +/* secondary removal operations */ +static const char* test_Clear(); +static const char* test_Erase(); + +/* secondary add operations */ +static const char* test_Insert(); +static const char* test_TryPushBack(); +static const char* test_TryPushFront(); + +/* equivalence and assignment */ +static const char* test_Equals(); +static const char* test_Copy(); + +/* usage tests */ +static const char* test_Stack(); +static const char* test_Queue(); +static const char* test_Alternating(); + +ZUnitTest ZRingBufferUnitTests[] = +{ + { "ZRingBuffer: Constructors, Array, Size, Capacity", test_Constructors_Array_Data_Length_Capacity }, + { "ZRingBuffer: Empty", test_Empty }, + { "ZRingBuffer: Full", test_Full }, + { "ZRingBuffer: Front", test_Front }, + { "ZRingBuffer: Back", test_Back }, + { "ZRingBuffer: PopFront", test_PopFront }, + { "ZRingBuffer: PopBack", test_PopBack }, + { "ZRingBuffer: PushFront (OverflowUnsafe)", test_PushFront_OverflowUnsafe }, + { "ZRingBuffer: PushFront (OverflowAssert)", test_PushFront_OverflowAssert }, + { "ZRingBuffer: PushFront (OverflowIgnore)", test_PushFront_OverflowIgnore }, + { "ZRingBuffer: PushFront (OverflowDropFront)", test_PushFront_OverflowDropFront }, + { "ZRingBuffer: PushFront (OverflowDropBack)", test_PushFront_OverflowDropBack }, + { "ZRingBuffer: PushFront (OverflowOverwrite)", test_PushFront_OverflowOverwrite }, + { "ZRingBuffer: PushFront (OverflowEvict)", test_PushFront_OverflowEvict }, + { "ZRingBuffer: PushFront (OverflowGrow)", test_PushFront_OverflowGrow }, + { "ZRingBuffer: PushBack (OverflowUnsafe)", test_PushBack_OverflowUnsafe }, + { "ZRingBuffer: PushBack (OverflowAssert)", test_PushBack_OverflowAssert }, + { "ZRingBuffer: PushBack (OverflowIgnore)", test_PushBack_OverflowIgnore }, + { "ZRingBuffer: PushBack (OverflowDropFront)", test_PushBack_OverflowDropFront }, + { "ZRingBuffer: PushBack (OverflowDropBack)", test_PushBack_OverflowDropBack }, + { "ZRingBuffer: PushBack (OverflowOverwrite)", test_PushBack_OverflowOverwrite }, + { "ZRingBuffer: PushBack (OverflowEvict)", test_PushBack_OverflowEvict }, + { "ZRingBuffer: PushBack (OverflowGrow)", test_PushBack_OverflowGrow }, + { "ZRingBuffer: AbsoluteIndex", test_AbsoluteIndex }, + { "ZRingBuffer: At", test_At }, + { "ZRingBuffer: Clear", test_Clear }, + { "ZRingBuffer: Erase", test_Erase }, + { "ZRingBuffer: Insert", test_Insert }, + { "ZRingBuffer: TryPushBack", test_TryPushBack }, + { "ZRingBuffer: TryPushFront", test_TryPushFront }, + { "ZRingBuffer: Equals", test_Equals }, + { "ZRingBuffer: Copy", test_Copy }, + + { "ZRingBuffer: Usage (Stack)", test_Stack }, + { "ZRingBuffer: Usage (Queue)", test_Queue }, + { "ZRingBuffer: Usage (Alternating)", test_Alternating } +}; + +DECLARE_ZTESTBLOCK(ZRingBuffer); + +/*************************************************************************/ + +static const char* test_Constructors_Array_Data_Length_Capacity() +{ + int testData[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + ZArray<int> data1(testData, 10, 10); + ZArray<int> data2(testData, 6, 20); + + ZRingBuffer<int> buf1; + ZRingBuffer<int> buf2(10); + ZRingBuffer<int> buf3(data1); + ZRingBuffer<int> buf4(data2); + + TASSERT(buf1.Array().Size() == ZRINGBUFFER_DEFAULT_CAPACITY, "Default constructor fails to properly initialize storage array!"); + TASSERT(buf2.Array().Size() == 10, "Capacity constructor failed to properly initialize storage array!"); + TASSERT(buf3.Array().Size() == 10, "Storage constructor failed to properly initialize storage array!"); + + for (int i = 0; i < (int)data1.Size(); i++) + { + TASSERT(buf3.Array()[i] == i, "Storage constructor failed to properly copy storage data!"); + } + + for (int i = 0; i < (int)data2.Size(); i++) + { + TASSERT(buf4.Array()[i] == i, "Storage constructor (2) failed to properly copy storage data!"); + } + + TASSERT(buf1.Size() == 0, "Default constructor initializes with incorrect size!"); + TASSERT(buf1.Capacity() == ZRINGBUFFER_DEFAULT_CAPACITY, "Default constructor initializes with incorrect capacity!"); + + TASSERT(buf2.Size() == 0, "Capacity constructor initializes with incorrect size!"); + TASSERT(buf2.Capacity() == 10, "Capacity constructor initializes with incorrect capacity!"); + + TASSERT(buf3.Size() == 10, "Storage constructor initializes with incorrect size!"); + TASSERT(buf3.Capacity() == 10, "Storage constructor initializes with incorrect capacity!"); + + TASSERT(buf4.Size() == 6, "Storage constructor (2) initializes with incorrect size!"); + TASSERT(buf4.Capacity() == 20, "Storage constructor (2) initializes with incorrect capacity!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Empty() +{ + int testData[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + ZArray<int> data1(testData, 10, 10); + ZArray<int> data2(testData, 6, 20); + + ZRingBuffer<int> buf1; + ZRingBuffer<int> buf2(10); + ZRingBuffer<int> buf3(data1); + ZRingBuffer<int> buf4(data2); + + TASSERT(buf1.Empty(), "Empty() returns false on empty buffer!"); + TASSERT(buf2.Empty(), "Empty() returns false on empty buffer with low capacity!"); + TASSERT(!buf3.Empty(), "Empty() returns true on non-empty buffer with Size() = Capacity()!"); + TASSERT(!buf4.Empty(), "Empty() returns true on non-empty buffer with Size() != Capacity()!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Full() +{ + int testData[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + ZArray<int> data1(testData, 10, 10); + ZArray<int> data2(testData, 6, 20); + + ZRingBuffer<int> buf1; + ZRingBuffer<int> buf2(10); + ZRingBuffer<int> buf3(data1); + ZRingBuffer<int> buf4(data2); + + TASSERT(!buf1.Full(), "Full() returns true on empty buffer!"); + TASSERT(!buf2.Full(), "Full() returns true on empty buffer with low capacity!"); + TASSERT(buf3.Full(), "Full() returns false on non-empty buffer with Size() = Capacity()!"); + TASSERT(!buf4.Full(), "Full() returns true on non-empty buffer with Size() != Capacity()!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Front() +{ + int testData[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + ZArray<int> data1(testData, 10, 10); + ZArray<int> data2(testData, 6, 20); + + ZRingBuffer<int> buf1; + ZRingBuffer<int> buf2(10); + ZRingBuffer<int> buf3(data1); + ZRingBuffer<int> buf4(data2); + + ZTEST_BeginHandleAssert(); + + buf1.Front(); //This will ruin buf1, so don't use it anymore + + ZTEST_EndHandleAssert(); + + TASSERT(ZTEST_CheckAssert(), "Front() on empty buffer failed to trigger assert!"); + + TASSERT(buf3.Front() == 0, "Front() returns incorrect value on non-empty buffer!"); + TASSERT(buf4.Front() == 0, "Front() returns incorrect value on second non-empty buffer!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Back() +{ + int testData[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + ZArray<int> data1(testData, 10, 10); + ZArray<int> data2(testData, 6, 20); + + ZRingBuffer<int> buf1; + ZRingBuffer<int> buf2(10); + ZRingBuffer<int> buf3(data1); + ZRingBuffer<int> buf4(data2); + + ZTEST_BeginHandleAssert(); + + buf1.Back(); //This will ruin buf1, so don't use it anymore + + ZTEST_EndHandleAssert(); + + TASSERT(ZTEST_CheckAssert(), "Back() on empty buffer failed to trigger assert!"); + + TASSERT(buf3.Back() == 9, "Back() returns incorrect value on non-empty buffer!"); + TASSERT(buf4.Back() == 5, "Back() returns incorrect value on second non-empty buffer!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_PopFront() +{ + int testData[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + ZArray<int> data1(testData, 10, 10); + ZArray<int> data2(testData, 6, 20); + + ZRingBuffer<int> buf1; + ZRingBuffer<int> buf2(10); + ZRingBuffer<int> buf3(data1); + ZRingBuffer<int> buf4(data2); + + int i; + + ZTEST_BeginHandleAssert(); + + buf1.PopFront(); //This will ruin buf1, so don't use it anymore + + ZTEST_EndHandleAssert(); + + TASSERT(ZTEST_CheckAssert(), "PopFront() on empty buffer failed to trigger assert!"); + + i = buf3.PopFront(); + + TASSERT(i == 0, "PopFront() returned incorrect value for first element!"); + TASSERT(buf3.Size() == 9, "PopFront() failed to reduce buffer size!"); + TASSERT(buf3.Capacity() == 10, "PopFront improperly reduced capacity!"); + + for (i = 1; i < 9; i++) + { + TASSERT(buf3.PopFront() == i, "PopFront() returned incorrect value when looping through buf3!"); + } + + TASSERT(buf3.Size() == 1, "PopFront() x 8 failed to reduce buffer to one element!"); + + i = buf3.PopFront(); + + TASSERT(i == 9, "PopFront() returned incorrect value on last element!"); + TASSERT(buf3.Size() == 0, "PopFront() on last element did not reduce buffer size to zero!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_PopBack() +{ + int testData[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + ZArray<int> data1(testData, 10, 10); + ZArray<int> data2(testData, 6, 20); + + ZRingBuffer<int> buf1; + ZRingBuffer<int> buf2(10); + ZRingBuffer<int> buf3(data1); + ZRingBuffer<int> buf4(data2); + + int i; + + ZTEST_BeginHandleAssert(); + + buf1.PopBack(); //This will ruin buf1, so don't use it anymore + + ZTEST_EndHandleAssert(); + + TASSERT(ZTEST_CheckAssert(), "PopBack() on empty buffer failed to trigger assert!"); + + i = buf3.PopBack(); + + TASSERT(i == 9, "PopBack() returned incorrect value for last element!"); + TASSERT(buf3.Size() == 9, "PopBack() failed to reduce buffer size!"); + TASSERT(buf3.Capacity() == 10, "PopBack improperly reduced capacity!"); + + for (i = 8; i > 5; i--) + { + TASSERT(buf3.PopBack() == i, "PopBack() returned incorrect value when looping through buf3!"); + } + + for (i = 0; i < 5; i++) + buf3.PopFront(); + + TASSERT(buf3.Size() == 1, "PopBack() / PopFront() combo failed to reduce buffer to correct size!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +const char* test_PushFront_ErrorMsg = NULL; + +#define PF_TASSERT(condition, msg) if (!(condition)) { test_PushFront_ErrorMsg = msg; return false; } + +/* +This little helper method will test an empty ring buffer push front function and return a full buffer +that has been wrap-around tested so you can test the specifics of overflow +looks like the following when done: [ (Back)0, (Front) 9, 8, 7, 6, 5, 4, 3, 2, 1 ] +*/ +template <typename T, typename P, typename A> +inline bool test_PushFront(ZRingBuffer<T, P, A>& buffer) +{ + int i; + + buffer.PushFront(0); + + PF_TASSERT(buffer.Size() == 1, "PushFront() does not properly increment size!"); + PF_TASSERT(buffer.Front() == 0, "PushFront() does not properly set value for Front()!"); + PF_TASSERT(buffer.Back() == 0, "PushFront() does not properly set value for Back()!"); + + for (i = 1; i < 10; i++) + buffer.PushFront(i); + + PF_TASSERT(buffer.Size() == 10, "PushFront() does not properly handle wrap-around!"); + PF_TASSERT(buffer.Front() == 9, "PushFront() does not correctly set Front() value after wrap-around!"); + PF_TASSERT(buffer.Back() == 0, "PushFront() improperly modifies Back() value after wrap-around!"); + + return true; +} + +static const char* test_PushFront_OverflowUnsafe() +{ + int testData[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + ZArray<int> data1(testData, 10, 10); + ZArray<int> data2(testData, 6, 20); + + ZRingBuffer<int, ZRingBuffer_OverflowUnsafe> buf1; + ZRingBuffer<int, ZRingBuffer_OverflowUnsafe> buf2(10); + ZRingBuffer<int, ZRingBuffer_OverflowUnsafe> buf3(data1); + ZRingBuffer<int, ZRingBuffer_OverflowUnsafe> buf4(data2); + + if (!test_PushFront(buf2)) + return test_PushFront_ErrorMsg; + + //Test the unsafe behavior (this will actually invalidate the buffer, so BEWARE) + buf2.PushFront(15); + + TASSERT(buf2.Front() == buf2.Back(), "PushFront() does not properly overwrite the back value when overflow occurs!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_PushFront_OverflowAssert() +{ + int testData[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + ZArray<int> data1(testData, 10, 10); + ZArray<int> data2(testData, 6, 20); + + ZRingBuffer<int, ZRingBuffer_OverflowAssert> buf1; + ZRingBuffer<int, ZRingBuffer_OverflowAssert> buf2(10); + ZRingBuffer<int, ZRingBuffer_OverflowAssert> buf3(data1); + ZRingBuffer<int, ZRingBuffer_OverflowAssert> buf4(data2); + + if (!test_PushFront(buf2)) + return test_PushFront_ErrorMsg; + + ZTEST_BeginHandleAssert(); + + buf2.PushFront(15); //This will ruin buf2, so don't use it anymore + + ZTEST_EndHandleAssert(); + + TASSERT(ZTEST_CheckAssert(), "PushFront() on full buffer failed to assert!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_PushFront_OverflowIgnore() +{ + int testData[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + ZArray<int> data1(testData, 10, 10); + ZArray<int> data2(testData, 6, 20); + + ZRingBuffer<int, ZRingBuffer_OverflowIgnore> buf1; + ZRingBuffer<int, ZRingBuffer_OverflowIgnore> buf2(10); + ZRingBuffer<int, ZRingBuffer_OverflowIgnore> buf3(data1); + ZRingBuffer<int, ZRingBuffer_OverflowIgnore> buf4(data2); + + if (!test_PushFront(buf2)) + return test_PushFront_ErrorMsg; + + buf2.PushFront(15); + + TASSERT(buf2.Front() == 9, "PushFront() added element on full buffer with ZRingBuffer_OverflowIgnore policy (Front)!"); + TASSERT(buf2.Back() == 0, "PushFront() added element on full buffer with ZRingBuffer_OverflowIgnore policy (Back)!"); + TASSERT(buf2.Size() == 10, "PushFront() added element on full buffer with ZRingBuffer_OverflowIgnore policy (Size)!"); + TASSERT(buf2.Full(), "PushFront() added element on full buffer with ZRingBuffer_OverflowIgnore policy (Full)!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_PushFront_OverflowDropFront() +{ + int testData[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + ZArray<int> data1(testData, 10, 10); + ZArray<int> data2(testData, 6, 20); + + ZRingBuffer<int, ZRingBuffer_OverflowDropFront> buf1; + ZRingBuffer<int, ZRingBuffer_OverflowDropFront> buf2(10); + ZRingBuffer<int, ZRingBuffer_OverflowDropFront> buf3(data1); + ZRingBuffer<int, ZRingBuffer_OverflowDropFront> buf4(data2); + + if (!test_PushFront(buf2)) + return test_PushFront_ErrorMsg; + + buf2.PushFront(15); + + TASSERT(buf2.Front() == 15, "PushFront() failed to drop front element with ZRingBuffer_OverflowDropFront policy!"); + TASSERT(buf2.Back() == 0, "PushFront() improperly modified back element with ZRingBuffer_OverflowDropFront policy!"); + TASSERT(buf2.Size() == 10, "PushFront() failed to keep size with ZRingBuffer_OverflowDropFront policy!"); + TASSERT(buf2.Full(), "PushFront() failed to keep buffer full with ZRingBuffer_OverflowDropFront policy!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_PushFront_OverflowDropBack() +{ + int testData[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + ZArray<int> data1(testData, 10, 10); + ZArray<int> data2(testData, 6, 20); + + ZRingBuffer<int, ZRingBuffer_OverflowDropBack> buf1; + ZRingBuffer<int, ZRingBuffer_OverflowDropBack> buf2(10); + ZRingBuffer<int, ZRingBuffer_OverflowDropBack> buf3(data1); + ZRingBuffer<int, ZRingBuffer_OverflowDropBack> buf4(data2); + + if (!test_PushFront(buf2)) + return test_PushFront_ErrorMsg; + + buf2.PushFront(15); + + TASSERT(buf2.Front() == 15, "PushFront() failed to change front element with ZRingBuffer_OverflowDropBack policy!"); + TASSERT(buf2.Back() == 1, "PushFront() failed to drop back element with ZRingBuffer_OverflowDropBack policy!"); + TASSERT(buf2.Size() == 10, "PushFront() failed to keep size with ZRingBuffer_OverflowDropBack policy!"); + TASSERT(buf2.Full(), "PushFront() failed to keep buffer full with ZRingBuffer_OverflowDropBack policy!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_PushFront_OverflowOverwrite() +{ + int testData[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + ZArray<int> data1(testData, 10, 10); + ZArray<int> data2(testData, 6, 20); + + ZRingBuffer<int, ZRingBuffer_OverflowOverwrite> buf1; + ZRingBuffer<int, ZRingBuffer_OverflowOverwrite> buf2(10); + ZRingBuffer<int, ZRingBuffer_OverflowOverwrite> buf3(data1); + ZRingBuffer<int, ZRingBuffer_OverflowOverwrite> buf4(data2); + + if (!test_PushFront(buf2)) + return test_PushFront_ErrorMsg; + + buf2.PushFront(15); + + TASSERT(buf2.Front() == 15, "PushFront() failed to overwrite front element with ZRingBuffer_OverflowOverwrite policy!"); + TASSERT(buf2.Back() == 0, "PushFront() improperly modified back element with ZRingBuffer_OverflowOverwrite policy!"); + TASSERT(buf2.Size() == 10, "PushFront() failed to keep size with ZRingBuffer_OverflowOverwrite policy!"); + TASSERT(buf2.Full(), "PushFront() failed to keep buffer full with ZRingBuffer_OverflowOverwrite policy!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_PushFront_OverflowEvict() +{ + int testData[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + ZArray<int> data1(testData, 10, 10); + ZArray<int> data2(testData, 6, 20); + + ZRingBuffer<int, ZRingBuffer_OverflowEvict> buf1; + ZRingBuffer<int, ZRingBuffer_OverflowEvict> buf2(10); + ZRingBuffer<int, ZRingBuffer_OverflowEvict> buf3(data1); + ZRingBuffer<int, ZRingBuffer_OverflowEvict> buf4(data2); + + if (!test_PushFront(buf2)) + return test_PushFront_ErrorMsg; + + buf2.PushFront(15); + + TASSERT(buf2.Front() == 15, "PushFront() failed to change front element with ZRingBuffer_OverflowEvict policy!"); + TASSERT(buf2.Back() == 1, "PushFront() failed to evict back element with ZRingBuffer_OverflowEvict policy!"); + TASSERT(buf2.Size() == 10, "PushFront() failed to keep size with ZRingBuffer_OverflowEvict policy!"); + TASSERT(buf2.Full(), "PushFront() failed to keep buffer full with ZRingBuffer_OverflowEvict policy!"); + + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_PushFront_OverflowGrow() +{ + int testData[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + ZArray<int> data1(testData, 10, 10); + ZArray<int> data2(testData, 6, 20); + + ZRingBuffer<int, ZRingBuffer_OverflowGrow> buf1; + ZRingBuffer<int, ZRingBuffer_OverflowGrow> buf2(10); + ZRingBuffer<int, ZRingBuffer_OverflowGrow> buf3(data1); + ZRingBuffer<int, ZRingBuffer_OverflowGrow> buf4(data2); + + if (!test_PushFront(buf2)) + return test_PushFront_ErrorMsg; + + buf2.PushFront(15); + + TASSERT(buf2.Front() == 15, "PushFront() failed to add front element with ZRingBuffer_OverflowGrow policy!"); + TASSERT(buf2.Back() == 0, "PushFront() improperly modified back element with ZRingBuffer_OverflowGrow policy!"); + TASSERT(buf2.Size() == 11, "PushFront() did not properly increment size with ZRingBuffer_OverflowGrow policy!"); + TASSERT(buf2.Capacity() > 10, "PushFront() did not properly grow the buffer with ZRingBuffer_OverflowGrow policy!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +const char* test_PushBack_ErrorMsg = NULL; + +#define PB_TASSERT(condition, msg) if (!(condition)) { test_PushBack_ErrorMsg = msg; return false; } + +/* +This little helper method will test an empty ring buffer push front function and return a full buffer +that has been wrap-around tested so you can test the specifics of overflow +looks like the following when done: [ 6, 7, 8, 9, (Front) 0, (Back) 1, 2, 3, 4, 5 ] +*/ +template <typename T, typename P, typename A> +inline bool test_PushBack(ZRingBuffer<T, P, A>& buffer) +{ + int i; + + buffer.PushBack(0); + + PB_TASSERT(buffer.Size() == 1, "PushBack() does not properly increment size!"); + PB_TASSERT(buffer.Front() == 0, "PushBack() does not properly set value for Front()!"); + PB_TASSERT(buffer.Back() == 0, "PushBack() does not properly set value for Back()!"); + + for (i = 1; i < 5; i++) + buffer.PushBack(i); + + for (i = 5; i < 10; i++) + buffer.PushFront(i); + + //Current layout: [ 0, 1, 2, 3, (Back) 4, (Front) 9, 8, 7, 6, 5 ] + + for (i = 0; i < 5; i++) + { + PB_TASSERT(buffer.Array()[i] == i, "PushBack() does not correctly set values!"); + PB_TASSERT(buffer.Array()[9 - i] == 5 + i, "PushFront() does not correctly set values!"); + } + + for (i = 0; i < 10; i++) + { + buffer.PopFront(); + buffer.PushBack(i); + } + + //New layout: [ 5, 6, 7, 8, (Back) 9, (Front) 0, 1, 2, 3, 4 ] + + for (i = 0; i < 5; i++) + { + PB_TASSERT(buffer.Array()[i] == i + 5, "PopFront()/PushBack() does not correctly set values!"); + PB_TASSERT(buffer.Array()[i + 5] == i, "PopFront()/PushBack() does not correctly set values!"); + } + + PB_TASSERT(buffer.Size() == 10, "PushFront() does not properly handle wrap-around!"); + PB_TASSERT(buffer.Front() == 0, "Buffer does not correctly set Front() value after wrap-around!"); + PB_TASSERT(buffer.Back() == 9, "Buffer improperly modifies Back() value after wrap-around!"); + + return true; +} + +static const char* test_PushBack_OverflowUnsafe() +{ + int testData[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + ZArray<int> data1(testData, 10, 10); + ZArray<int> data2(testData, 6, 20); + + ZRingBuffer<int, ZRingBuffer_OverflowUnsafe> buf1; + ZRingBuffer<int, ZRingBuffer_OverflowUnsafe> buf2(10); + ZRingBuffer<int, ZRingBuffer_OverflowUnsafe> buf3(data1); + ZRingBuffer<int, ZRingBuffer_OverflowUnsafe> buf4(data2); + + if (!test_PushBack(buf2)) + return test_PushBack_ErrorMsg; + + //Test the unsafe behavior (this will actually invalidate the buffer, so BEWARE) + buf2.PushBack(15); + + TASSERT(buf2.Front() == buf2.Back(), "PushBack() does not properly overwrite the back value when overflow occurs!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_PushBack_OverflowAssert() +{ + int testData[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + ZArray<int> data1(testData, 10, 10); + ZArray<int> data2(testData, 6, 20); + + ZRingBuffer<int, ZRingBuffer_OverflowAssert> buf1; + ZRingBuffer<int, ZRingBuffer_OverflowAssert> buf2(10); + ZRingBuffer<int, ZRingBuffer_OverflowAssert> buf3(data1); + ZRingBuffer<int, ZRingBuffer_OverflowAssert> buf4(data2); + + if (!test_PushBack(buf2)) + return test_PushBack_ErrorMsg; + + ZTEST_BeginHandleAssert(); + + buf2.PushBack(15); //This will ruin buf2, so don't use it anymore + + ZTEST_EndHandleAssert(); + + TASSERT(ZTEST_CheckAssert(), "PushBack() on full buffer failed to assert!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_PushBack_OverflowIgnore() +{ + int testData[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + ZArray<int> data1(testData, 10, 10); + ZArray<int> data2(testData, 6, 20); + + ZRingBuffer<int, ZRingBuffer_OverflowIgnore> buf1; + ZRingBuffer<int, ZRingBuffer_OverflowIgnore> buf2(10); + ZRingBuffer<int, ZRingBuffer_OverflowIgnore> buf3(data1); + ZRingBuffer<int, ZRingBuffer_OverflowIgnore> buf4(data2); + + if (!test_PushBack(buf2)) + return test_PushBack_ErrorMsg; + + buf2.PushBack(15); + + TASSERT(buf2.Back() == 9, "PushBack() added element on full buffer with ZRingBuffer_OverflowIgnore policy (Back)!"); + TASSERT(buf2.Front() == 0, "PushBack() added element on full buffer with ZRingBuffer_OverflowIgnore policy (Front)!"); + TASSERT(buf2.Size() == 10, "PushBack() added element on full buffer with ZRingBuffer_OverflowIgnore policy (Size)!"); + TASSERT(buf2.Full(), "PushBack() added element on full buffer with ZRingBuffer_OverflowIgnore policy (Full)!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_PushBack_OverflowDropFront() +{ + int testData[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + ZArray<int> data1(testData, 10, 10); + ZArray<int> data2(testData, 6, 20); + + ZRingBuffer<int, ZRingBuffer_OverflowDropFront> buf1; + ZRingBuffer<int, ZRingBuffer_OverflowDropFront> buf2(10); + ZRingBuffer<int, ZRingBuffer_OverflowDropFront> buf3(data1); + ZRingBuffer<int, ZRingBuffer_OverflowDropFront> buf4(data2); + + if (!test_PushBack(buf2)) + return test_PushBack_ErrorMsg; + + buf2.PushBack(15); + + TASSERT(buf2.Back() == 15, "PushBack() failed to correctly set back element with ZRingBuffer_OverflowDropFront policy!"); + TASSERT(buf2.Front() == 1, "PushBack() failed to drop front element with ZRingBuffer_OverflowDropFront policy!"); + TASSERT(buf2.Size() == 10, "PushBack() failed to keep size with ZRingBuffer_OverflowDropFront policy!"); + TASSERT(buf2.Full(), "PushBack() failed to keep buffer full with ZRingBuffer_OverflowDropFront policy!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_PushBack_OverflowDropBack() +{ + int testData[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + ZArray<int> data1(testData, 10, 10); + ZArray<int> data2(testData, 6, 20); + + ZRingBuffer<int, ZRingBuffer_OverflowDropBack> buf1; + ZRingBuffer<int, ZRingBuffer_OverflowDropBack> buf2(10); + ZRingBuffer<int, ZRingBuffer_OverflowDropBack> buf3(data1); + ZRingBuffer<int, ZRingBuffer_OverflowDropBack> buf4(data2); + + if (!test_PushBack(buf2)) + return test_PushBack_ErrorMsg; + + buf2.PushBack(15); + + TASSERT(buf2.Back() == 15, "PushBack() failed to correctly set back element with ZRingBuffer_OverflowDropBack policy!"); + TASSERT(buf2.Front() == 0, "PushBack() improperly modified front element with ZRingBuffer_OverflowDropBack policy!"); + TASSERT(buf2.Size() == 10, "PushBack() failed to keep size with ZRingBuffer_OverflowDropBack policy!"); + TASSERT(buf2.Full(), "PushBack() failed to keep buffer full with ZRingBuffer_OverflowDropBack policy!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_PushBack_OverflowOverwrite() +{ + int testData[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + ZArray<int> data1(testData, 10, 10); + ZArray<int> data2(testData, 6, 20); + + ZRingBuffer<int, ZRingBuffer_OverflowOverwrite> buf1; + ZRingBuffer<int, ZRingBuffer_OverflowOverwrite> buf2(10); + ZRingBuffer<int, ZRingBuffer_OverflowOverwrite> buf3(data1); + ZRingBuffer<int, ZRingBuffer_OverflowOverwrite> buf4(data2); + + if (!test_PushBack(buf2)) + return test_PushBack_ErrorMsg; + + buf2.PushBack(15); + + TASSERT(buf2.Back() == 15, "PushBack() failed to correctly overwrite back element with ZRingBuffer_OverflowOverwrite policy!"); + TASSERT(buf2.Front() == 0, "PushBack() improperly modified front element with ZRingBuffer_OverflowOverwrite policy!"); + TASSERT(buf2.Size() == 10, "PushBack() failed to keep size with ZRingBuffer_OverflowOverwrite policy!"); + TASSERT(buf2.Full(), "PushBack() failed to keep buffer full with ZRingBuffer_OverflowOverwrite policy!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_PushBack_OverflowEvict() +{ + int testData[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + ZArray<int> data1(testData, 10, 10); + ZArray<int> data2(testData, 6, 20); + + ZRingBuffer<int, ZRingBuffer_OverflowEvict> buf1; + ZRingBuffer<int, ZRingBuffer_OverflowEvict> buf2(10); + ZRingBuffer<int, ZRingBuffer_OverflowEvict> buf3(data1); + ZRingBuffer<int, ZRingBuffer_OverflowEvict> buf4(data2); + + if (!test_PushBack(buf2)) + return test_PushBack_ErrorMsg; + + buf2.PushBack(15); + + TASSERT(buf2.Back() == 15, "PushBack() failed to correctly set back element with ZRingBuffer_OverflowEvict policy!"); + TASSERT(buf2.Front() == 1, "PushBack() failed to evict front element with ZRingBuffer_OverflowEvict policy!"); + TASSERT(buf2.Size() == 10, "PushBack() failed to keep size with ZRingBuffer_OverflowEvict policy!"); + TASSERT(buf2.Full(), "PushBack() failed to keep buffer full with ZRingBuffer_OverflowEvict policy!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_PushBack_OverflowGrow() +{ + int testData[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + ZArray<int> data1(testData, 10, 10); + ZArray<int> data2(testData, 6, 20); + + ZRingBuffer<int, ZRingBuffer_OverflowGrow> buf1; + ZRingBuffer<int, ZRingBuffer_OverflowGrow> buf2(10); + ZRingBuffer<int, ZRingBuffer_OverflowGrow> buf3(data1); + ZRingBuffer<int, ZRingBuffer_OverflowGrow> buf4(data2); + + if (!test_PushBack(buf2)) + return test_PushBack_ErrorMsg; + + buf2.PushBack(15); + + TASSERT(buf2.Back() == 15, "PushBack() failed to add back element with ZRingBuffer_OverflowGrow policy!"); + TASSERT(buf2.Front() == 0, "PushBack() improperly modified front element with ZRingBuffer_OverflowGrow policy!"); + TASSERT(buf2.Size() == 11, "PushBack() did not properly increment size with ZRingBuffer_OverflowGrow policy!"); + TASSERT(buf2.Capacity() > 10, "PushBack() did not properly grow the buffer with ZRingBuffer_OverflowGrow policy!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_AbsoluteIndex() +{ + int testData[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + ZArray<int> data1(testData, 10, 10); + ZArray<int> data2(testData, 6, 20); + + ZRingBuffer<int> buf1; + ZRingBuffer<int> buf2(10); + ZRingBuffer<int> buf3(data1); + ZRingBuffer<int> buf4(data2); + + size_t i; + + for (i = 0; i < buf3.Size(); i++) + { + TASSERT(buf3.ActualIndex(i) == i, "AbsoluteIndex() does not return correct value on aligned buffer!"); + } + + buf3.PopBack(); + + TASSERT(buf3.ActualIndex(0) == 0, "AbsoluteIndex(0) returns non-zero after PopBack()!"); + + buf3.PopFront(); + + TASSERT(buf3.ActualIndex(0) == 1, "AbsoluteIndex(0) returns incorrect value after PopFront()!"); + + buf3.PushBack(9); + buf3.PushBack(10); + + //New layout: [(Back) 10, (Front) 1, 2, 3, 4, 5, 6, 7, 8, 9 ] + + TASSERT(buf3.ActualIndex(9) == 0, "AbsoluteIndex(9) returns incorrect value with Back < Front!"); + + buf3.PopFront(); + + ZTEST_BeginHandleAssert(); + + buf3.ActualIndex(9); + + ZTEST_EndHandleAssert(); + + TASSERT(ZTEST_CheckAssert(), "AbsoluteIndex(9) with 9 out-of-bounds did not trigger assert!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_At() +{ + int testData[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + ZArray<int> data1(testData, 10, 10); + ZArray<int> data2(testData, 6, 20); + + ZRingBuffer<int> buf1; + ZRingBuffer<int> buf2(10); + ZRingBuffer<int> buf3(data1); + ZRingBuffer<int> buf4(data2); + + int i; + + for (i = 0; i < (int)buf3.Size(); i++) + { + TASSERT(buf3.At(i) == i, "At() does not return correct value on aligned buffer!"); + } + + buf3.PopBack(); + + TASSERT(buf3.At(0) == 0, "At(0) returns non-zero after PopBack()!"); + + buf3.PopFront(); + + TASSERT(buf3.At(0) == 1, "At(0) returns incorrect value after PopFront()!"); + + buf3.PushBack(9); + buf3.PushBack(10); + + //New layout: [(Back) 10, (Front) 1, 2, 3, 4, 5, 6, 7, 8, 9 ] + + TASSERT(buf3.At(9) == 10, "At(9) returns incorrect value with Back < Front!"); + + buf3.PopFront(); + + ZTEST_BeginHandleAssert(); + + buf3.At(9); + + ZTEST_EndHandleAssert(); + + TASSERT(ZTEST_CheckAssert(), "At(9) with 9 out-of-bounds did not trigger assert!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Clear() +{ + int testData[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + ZArray<int> data1(testData, 10, 10); + ZArray<int> data2(testData, 6, 20); + + ZRingBuffer<int> buf1; + ZRingBuffer<int> buf2(10); + ZRingBuffer<int> buf3(data1); + ZRingBuffer<int> buf4(data2); + + buf3.Clear(); + + TASSERT(buf3.Size() == 0, "Clear() failed to reduce buffer size to zero!"); + TASSERT(buf3.Capacity() == 10, "Clear() improperly reduced capacity!"); + + buf4.Clear(64); + + TASSERT(buf4.Size() == 0, "Clear(64) failed to reduce buffer size to zero!"); + TASSERT(buf4.Capacity() == 64, "Clear(64) failed to set proper capacity!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Erase() +{ + int testData[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + ZArray<int> data1(testData, 10, 10); + ZArray<int> data2(testData, 6, 20); + + ZRingBuffer<int> buf1; + ZRingBuffer<int> buf2(10); + ZRingBuffer<int> buf3(data1); + ZRingBuffer<int> buf4(data2); + + buf3.PopFront(); + buf3.PushBack(10); + + //New layout: [(Back) 10, (Front) 1, 2, 3, 4, 5, 6, 7, 8, 9 ] + + buf3.Erase(0); + + TASSERT(buf3.Size() == 9, "Erase() did not correctly reduce size!"); + TASSERT(buf3.At(0) == 2, "Erase() did not erase correct element!"); + + buf3.Erase(4, 6); + + TASSERT(buf3.Size() == 7, "Erase(i, j) did not correctly reduce size!"); + TASSERT(buf3.At(4) == 8, "Erase(i, j) did not erase correct elements!"); + TASSERT(buf3.At(5) == 9, "Erase(i, j) did not erase correct elements!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Insert() +{ + int testData[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + ZArray<int> data1(testData, 10, 10); + ZArray<int> data2(testData, 6, 20); + + ZRingBuffer<int> buf1; + ZRingBuffer<int> buf2(10); + ZRingBuffer<int> buf3(data1); + ZRingBuffer<int> buf4(data2); + + buf3.PopFront(); + buf3.PushBack(10); + + buf3.PopFront(); + buf3.PopFront(); + + //New layout: [(Back) 10, x, x, (Front) 3, 4, 5, 6, 7, 8, 9 ] + + buf3.Insert(2, 15, 1); //Insert at index 2 the value 15, 1 time + + //New layout: [(Front) 3, 4, 15, 5, 6, 7, 8, 9, (Back) 10, x ] + + TASSERT(buf3.Size() == 9, "Insert(i, j, k) did not correctly increase buffer size!"); + TASSERT(buf3.Front() == 3, "Insert(i, j, k) improperly modified Front() value!"); + TASSERT(buf3.Back() == 10, "Insert(i, j, k) improperly modified Back() value!"); + TASSERT(buf3.At(2) == 15, "Insert(i, j, k) did not insert correct value at location 2!"); + + buf3.PopFront(); + buf3.PopFront(); + + //New layout: [ x, x, (Front) 15, 5, 6, 7, 8, 9, (Back) 10, x ] + + buf3.Insert(1, 15, 2); //Insert at index 1 the value 15, 2 times + + //New layout: [ (Front) 15, 15, 15, 5, 6, 7, 8, 9, (Back) 10, x ] + + TASSERT(buf3.Size() == 9, "Insert(i, j, 2k) did not correctly increase buffer size!"); + TASSERT(buf3.Front() == 15, "Insert(i, j, 2k) improperly modified Front() value!"); + TASSERT(buf3.Back() == 10, "Insert(i, j, 2k) improperly modified Back() value!"); + TASSERT(buf3.At(1) == 15, "Insert(i, j, 2k) did not insert correct value at location 1!"); + TASSERT(buf3.At(2) == 15, "Insert(i, j, 2k) did not insert correct value at location 2!"); + + buf3.PopFront(); + buf3.PopFront(); + buf3.PopFront(); + + //New layout: [ x, x, x, (Front) 5, 6, 7, 8, 9, (Back) 10, x ] + + ZArray<int> data3(testData, 4, 10); //Array [0, 1, 2, 3] with capacity 10 + + buf3.Insert(6, data3); + + //New layout: [ (Front) 5, 6, 7, 8, 9, 10, 0, 1, 2, (Back) 3 ] + + TASSERT(buf3.Size() == 10, "Insert(i, array) did not correctly increase buffer size!"); + TASSERT(buf3.Front() == 5, "Insert(i, array) improperly modified Front() value!"); + TASSERT(buf3.Back() == 3, "Insert(i, array) did not correctly set Back() value!"); + TASSERT(buf3.At(5) == 10, "Insert(i, array) improperly set At(5) value!"); + TASSERT(buf3.At(6) == 0, "Insert(i, array) did not correctly set At(6) value!"); + + ZRingBuffer<int> buf5(data1); + + buf5.Insert(0, buf3, 6, 4); //Insert at index 0 the values contained in buf3 starting at index 6 (4 values) + + //New layout: [ (Front) 0, 1, 2, 3, 0, 1, 2, 3, 4, 5, 6, 7, 8, (Back) 9 ] + + TASSERT(buf5.Size() == 14, "Insert(i, buffer) did not correctly increase buffer size!"); + TASSERT(buf5.Front() == 0, "Insert(i, buffer) did not correctly set Front() value!"); + TASSERT(buf5.Back() == 9, "Insert(i, buffer) improperly modified Back() value!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_TryPushBack() +{ + int testData[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + ZArray<int> data1(testData, 10, 10); + ZArray<int> data2(testData, 6, 20); + + ZRingBuffer<int> buf1; + ZRingBuffer<int> buf2(10); + ZRingBuffer<int> buf3(data1); + ZRingBuffer<int> buf4(data2); + + bool val; + + val = buf1.TryPushBack(0); + + TASSERT(val == true, "TryPushBack() fails with empty buffer!"); + + val = buf3.TryPushBack(0); + + TASSERT(val == false, "TryPushBack() succeeds with full buffer!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_TryPushFront() +{ + int testData[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + ZArray<int> data1(testData, 10, 10); + ZArray<int> data2(testData, 6, 20); + + ZRingBuffer<int> buf1; + ZRingBuffer<int> buf2(10); + ZRingBuffer<int> buf3(data1); + ZRingBuffer<int> buf4(data2); + + bool val; + + val = buf1.TryPushFront(0); + + TASSERT(val == true, "TryPushFront() fails with empty buffer!"); + + val = buf3.TryPushFront(0); + + TASSERT(val == false, "TryPushFront() succeeds with full buffer!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Equals() +{ + int testData[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + ZArray<int> data1(testData, 10, 10); + ZArray<int> data2(testData, 6, 20); + + ZRingBuffer<int> buf1; + ZRingBuffer<int> buf2(10); + ZRingBuffer<int> buf3(data1); + ZRingBuffer<int> buf4(data2); + ZRingBuffer<int> buf5(data2); + + TASSERT(buf1.Equals(buf1), "Equals returns false on same buffer!"); + TASSERT(buf1.Equals(buf2), "Equals returns false on buffers with different capacity!"); + TASSERT(!buf1.Equals(buf3), "Equals returns true on empty buffer and 10-element buffer!"); + TASSERT(!buf1.Equals(buf4), "Equals returns true on empty buffer and 6-element buffer!"); + + TASSERT(buf3.Equals(buf3), "Equals returns false on same (non-empty) buffer!"); + TASSERT(!buf3.Equals(buf4), "Equals returns true on non-equivalent buffers!"); + + TASSERT(buf4.Equals(buf5), "Equals returns false on equivalent buffers!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Copy() +{ + int testData[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + ZArray<int> data1(testData, 10, 10); + ZArray<int> data2(testData, 6, 20); + + ZRingBuffer<int> buf1; + ZRingBuffer<int> buf2(10); + ZRingBuffer<int> buf3(data1); + ZRingBuffer<int> buf4(data2); + + buf1.Copy(buf2); + + TASSERT(buf1.Empty(), "Copy() fails on empty buffer source and target!"); + + buf1.Copy(buf3); + + TASSERT(buf1.Equals(buf3), "Equals() returns false after Copy() with empty target!"); + + buf4.Copy(buf3); + + TASSERT(buf4.Equals(buf3), "Equals() returns false after Copy() with non-empty target!"); + + buf4.Copy(buf2); + + TASSERT(buf4.Empty(), "Copy() fails with empty buffer source and non-empty target!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Stack() +{ + int testData[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + //Test using front loading + ZRingBuffer<int> buf1(10); + + for (int i = 0; i < 5; i++) + buf1.PushFront(testData[i]); + + TASSERT (buf1.Size() == 5, "After 5 front pushes, Size() returned something other than 5!"); + + for (int i = 0; i < 5; i++) + { + int temp = buf1.PopFront(); + + TASSERT(temp == testData[4 - i], "Ring buffer corrupted while front loading as stack!"); + } + + //Test using back loading + ZRingBuffer<int> buf2(10); + + for (int i = 0; i < 5; i++) + buf2.PushBack(testData[i]); + + TASSERT(buf2.Size() == 5, "After 5 back pushes, Size() returned something other than 5!"); + + for (int i = 0; i < 5; i++) + { + int temp = buf2.PopBack(); + + TASSERT(temp == testData[4 - i], "Ring buffer corrupted while back loading as stack!"); + } + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Queue() +{ + int testData[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + //Test front loading + ZRingBuffer<int> buf1(10); + + for (int i = 0; i < 5; i++) + buf1.PushFront(testData[i]); + + TASSERT(buf1.Size() == 5, "After 5 front pushes, Size() returned something other than 5!"); + + for (int i = 0; i < 5; i++) + { + int temp = buf1.PopBack(); + + TASSERT(temp == testData[i], "Ring buffer corrupted while front loading as queue!"); + } + + //Test back loading + ZRingBuffer<int> buf2(10); + + for (int i = 0; i < 5; i++) + buf2.PushBack(testData[i]); + + TASSERT(buf2.Size() == 5, "After 5 back pushes, GetSize() returned something other than 5!"); + + for (int i = 0; i < 5; i++) + { + int temp = buf2.PopFront(); + + TASSERT(temp == testData[i], "Ring buffer corrupted while back loading as queue!"); + } + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Alternating() +{ + ZRingBuffer<int> buffer(10); + + int testArray[] = {0, 1, 2, 3, 4, 5, 6, 7}; + int correctResults[] = {7, 5, 3, 1, 0, 2, 4, 6}; + + buffer.PushFront(testArray[0]); + buffer.PushBack(testArray[1]); + buffer.PushFront(testArray[2]); + buffer.PushBack(testArray[3]); + buffer.PushFront(testArray[4]); + buffer.PushBack(testArray[5]); + buffer.PushFront(testArray[6]); + buffer.PushBack(testArray[7]); + + TASSERT(buffer.Size() == 8, "After 8 pushes, ring buffer returned something other than 8!"); + + for (int i = 0; i < 8; i++) + { + int temp = buffer.PopBack(); + + TASSERT(temp == correctResults[i], "Ring buffer corrupted while alternate loading!"); + } + + return ZTEST_SUCCESS; +} diff --git a/ZTestSuite/Test-ZSimplexNoise.cpp b/ZTestSuite/Test-ZSimplexNoise.cpp new file mode 100644 index 0000000..554fd91 --- /dev/null +++ b/ZTestSuite/Test-ZSimplexNoise.cpp @@ -0,0 +1,124 @@ +/* + Test-ZSimplexNoise.cpp + Author: Chris Ertel + + Purpose : Unit tests for ZSimplexNoise + + Changelog : + 05/11/2012 - Removed dependency on FreeImage + 12/08/2011 - Removed dependency on ZString (crertel) + 15/02/2011 - Created (crertel) +*/ + +#include "ZUnitTest.hpp" +#include <ZUtil/ZSimplexNoise.hpp> + +#include <iostream> + +static const char* test2DSimplexNoise(); + +//List of unit tests +ZUnitTest ZSimplexNoiseUnitTests[] = +{ + { + "test2DSimplexNoise", + test2DSimplexNoise + }, +}; + +DECLARE_ZTESTBLOCK(ZSimplexNoise); + +static void SaveTGA(const char* filename, const char* bitmap) +{ + FILE* fp = fopen(filename, "wb"); + + if(fp == NULL) + return; + + fputc(0, fp); //Image ID length + fputc(0, fp); //Color map type + fputc(2, fp); //Image type. 2 = uncompressed true color + + char zero[5] = { 0, 0, 0, 0, 0 }; + fwrite(zero, 5, sizeof(char), fp); //5 bytes of zero for colormap + + fputc(0, fp); fputc(0, fp); //X image origin: 0x0000 + fputc(0, fp); fputc(0, fp); //Y image origin: 0x0000 + fputc(0x00, fp); fputc(0x01, fp); //X image width: 0x0100 + fputc(0x00, fp); fputc(0x01, fp); //Y image width: 0x0100 + fputc(0x20, fp); //Image bits per pixel (32) + fputc((8<<0) | (2<<4), fp); //bits 0-3: alpha channel depth, bits 4-5: image origin, 2 = top-left + + + fwrite(bitmap, 256*256, 4, fp); + + fclose(fp); +} + +/*************************************************************************/ + +static const char* test2DSimplexNoise() +{ + char* bitmap = NULL; + ZSimplexNoise noisegen; + int i; + int j; + + bitmap = new char[256*256*4]; + + noisegen.reseed(0); + for (i = 0; i <256; i++) + { + for (j = 0; j <256; j++) + { + + double noiseval = noisegen.noise2( ((float) 2*i)/256.0f,((float) 2*j)/256.0f); + + bitmap[ (i*4*256) + (4*j)+ 0] = (char)( 128.0f + (128.0f * (noiseval))); + bitmap[ (i*4*256) + (4*j)+ 1] = (char)( 128.0f + (128.0f * (noiseval))); + bitmap[ (i*4*256) + (4*j)+ 2] = (char)( 128.0f + (128.0f * (noiseval))); + bitmap[ (i*4*256) + (4*j)+ 3] = -1; + } + } + SaveTGA("testnoise1.tga", bitmap); + + + noisegen.reseed(1); + for (i = 0; i <256; i++) + { + for (j = 0; j <256; j++) + { + + double noiseval = noisegen.noise2( ((float) 2*i)/256.0f,((float) 2*j)/256.0f); + + bitmap[ (i*4*256) + (4*j)+ 0] = (char)( 128.0f + (128.0f * (noiseval))); + bitmap[ (i*4*256) + (4*j)+ 1] = (char)( 128.0f + (128.0f * (noiseval))); + bitmap[ (i*4*256) + (4*j)+ 2] = (char)( 128.0f + (128.0f * (noiseval))); + bitmap[ (i*4*256) + (4*j)+ 3] = -1; + } + } + SaveTGA("testnoise2.tga", bitmap); + + noisegen.reseed(2); + for (i = 0; i <256; i++) + { + for (j = 0; j <256; j++) + { + + double noiseval = noisegen.noise2( ((float) 2*i)/256.0f,((float) 2*j)/256.0f); + + bitmap[ (i*4*256) + (4*j)+ 0] = (char)( 128.0f + (128.0f * (noiseval))); + bitmap[ (i*4*256) + (4*j)+ 1] = (char)( 128.0f + (128.0f * (noiseval))); + bitmap[ (i*4*256) + (4*j)+ 2] = (char)( 128.0f + (128.0f * (noiseval))); + bitmap[ (i*4*256) + (4*j)+ 3] = -1; + } + } + SaveTGA("testnoise3.tga", bitmap); + + + delete[] bitmap; + + return ZTEST_SUCCESS; +} + + diff --git a/ZTestSuite/Test-ZSlabAllocator.cpp b/ZTestSuite/Test-ZSlabAllocator.cpp new file mode 100644 index 0000000..de64206 --- /dev/null +++ b/ZTestSuite/Test-ZSlabAllocator.cpp @@ -0,0 +1,125 @@ +/* + Test-ZSlabAllocator.cpp + Author: James Russell <jcrussell@762studios.com> + + Purpose: Unit Test the ZSlabAllocator class. + + Changelog: + 12/18/2011 - Removed dependency on ZString (crertel) + 07/17/2011 - creation (jcrussell) +*/ + +#include "ZUnitTest.hpp" + +#include <ZUtil/ZSlabAllocator.hpp> + +static const char* testCapacity(); +static const char* testCount(); +static const char* testExcessCount(); +static const char* testCheckInCheckOut(); + +//List of unit tests +ZUnitTest ZSlabAllocatorUnitTests[] = +{ + { "ZObjectPool: Capacity", testCapacity }, + { "ZObjectPool: CheckOut", testCount }, + { "ZObjectPool: CheckIn, CheckOut", testCheckInCheckOut } +}; + +//Now declare the ZUnitTestBlock associated with this. +DECLARE_ZTESTBLOCK(ZSlabAllocator); + +/*************************************************************************/ + +struct PoolTestObject +{ + //Just some data + int Data; + + //Static Counter + static int StaticCount; + + PoolTestObject() : Data(StaticCount++) { } +}; + +int PoolTestObject::StaticCount = 0; + + +static const char* testCapacity() +{ + ZSlabAllocator<PoolTestObject, 4> testPool; + ZSlabAllocator<PoolTestObject, 14> testPool2; + + TASSERT(testPool.Capacity() == 4, "ZSlabAllocator: Capacity reports not 4 despite being inited to 4!"); + TASSERT(testPool2.Capacity() == 14, "ZSlabAllocator: Capacity reports not 14 despite being inited to 14!"); + + return ZTEST_SUCCESS; +} + +static const char* testCount() +{ + ZSlabAllocator<PoolTestObject, 4> testPool; + PoolTestObject* objs[4]; + + TASSERT(testPool.Available() == 4, "ZSlabAllocator: AvailableCount reports not 4 despite being unused!"); + + for (size_t i = 0; i < 4; i++) + { + objs[i] = testPool.Allocate(); + TASSERT(testPool.Available() == 3 - i, "ZSlabAllocator: AvailableCount reports incorrect available count during checkouts!"); + } + + for (size_t i = 0; i < 4; i++) + { + testPool.Deallocate(objs[i]); + TASSERT(testPool.Available() == i + 1, "ZSlabAllocator: AvailableCount reports incorrect available count during checkins!"); + } + + TASSERT(testPool.Available() == 4, "ZSlabAllocator: AvailableCount reports not 4 despite all objects checked in!"); + + return ZTEST_SUCCESS; +} + +static const char* testCheckInCheckOut() +{ + ZSlabAllocator<PoolTestObject, 4> testPool; + + TASSERT(testPool.Available() == 4, "ZSlabAllocator: Contains wrong number of objects!"); + TASSERT(testPool.Capacity() == 4, "ZSlabAllocator: Capacity is incorrect!"); + + //Allocated: 0 -> 2 + PoolTestObject *testObj1 = testPool.Allocate(); + PoolTestObject *testObj2 = testPool.Allocate(); + + TASSERT(testPool.Available() == testPool.Capacity()-2, "ZSlabAllocator: Contains wrong number of objects after CheckOut!"); + + //Allocated: 2 -> 4 + PoolTestObject *testObj3 = testPool.Allocate(); + PoolTestObject *testObj4 = testPool.Allocate(); + + TASSERT(testPool.Available() == testPool.Capacity()-4, "ZSlabAllocator: Contains objects when none should remain!"); + + //Allocated: 4 -> 6 + PoolTestObject *testObj5 = testPool.Allocate(); + PoolTestObject *testObj6 = testPool.Allocate(); + + + //Allocated: 6 -> 4 + testPool.Deallocate(testObj1); + testPool.Deallocate(testObj4); + + TASSERT(testPool.Available() == testPool.Capacity()-4, "ZSlabAllocator: Failed to return objects correctly!"); + + //Allocated: 4 -> 2 + testPool.Deallocate(testObj6); + testPool.Deallocate(testObj5); + + + //Allocated: 4 -> 2 == 0 + testPool.Deallocate(testObj3); + testPool.Deallocate(testObj2); + + TASSERT(testPool.Available() == testPool.Capacity(), "ZSlabAllocator: Failed to return objects to full count!"); + + return ZTEST_SUCCESS; +} \ No newline at end of file diff --git a/ZTestSuite/Test-ZSmartPointer.cpp b/ZTestSuite/Test-ZSmartPointer.cpp new file mode 100644 index 0000000..f4c4fde --- /dev/null +++ b/ZTestSuite/Test-ZSmartPointer.cpp @@ -0,0 +1,490 @@ +/* +Unit tests for ZSmartPointer to ensure correct behavior. +*/ + +#define ZSTL_DISABLE_RUNTIME_CHECKS 1 +#include "ZUnitTest.hpp" + +#include <ZUtil/ZSmartPointer.hpp> +#include <ZUtil/ZConcurrency.hpp> +#include <SST/SST_MemBarrier.h> + +static const char* test_Constructors(); +static const char* test_Operators(); +static const char* test_Cast(); +static const char* test_Detach(); +static const char* test_ArrayContainment(); +static const char* test_ListContainment(); +static const char* test_RingBufferContainment(); +static const char* test_MultithreadAccess(); + +//List of unit tests +ZUnitTest ZSmartPointerUnitTests[] = +{ + { "ZSmartPointer: Constructors", test_Constructors }, + { "ZSmartPointer: Operators", test_Operators }, + { "ZSmartPointer: Cast", test_Cast }, + { "ZSmartPointer: Detach", test_Detach }, + { "ZSmartPointer: Containment in ZArray", test_ArrayContainment }, + { "ZSmartPointer: Containment in ZList", test_ListContainment }, + { "ZSmartPointer: Containment in ZRingBuffer", test_RingBufferContainment }, + { "ZSmartPointer: Multithreaded Access", test_MultithreadAccess } +}; + +DECLARE_ZTESTBLOCK(ZSmartPointer); + +/*************************************************************************/ + +namespace ZSmartPointerTestObjects +{ + struct TestObject + { + //Constructor + TestObject() { TestObject::Instances++; } + + //Destructor + ~TestObject() { TestObject::Instances--; } + + //Value field + size_t Value; + + //Static Instance Count + static size_t Instances; + + //Virtual Function + virtual bool Foo() const { return true; } + }; + + struct TestObjectSubclass : public TestObject + { + //Constructor + TestObjectSubclass() : TestObject() {} + + //Subclass Override + bool Foo() const { return false; } + + //Subclass Method + bool Bar() const { return true; } + }; + + //Defaults to zero + size_t TestObject::Instances = 0; + + //Factory Method + ZSmartPointer<TestObject> getAllocatedTestObject() + { + return ZSmartPointer<TestObject>(new TestObject()); + } + + //This function is used to test the auto up-casting of contained types + bool autoCast(ZSmartPointer<TestObject> testObj) + { + return true; + } +} + +using namespace ZSmartPointerTestObjects; + +/*************************************************************************/ + +static const char* test_Constructors() +{ + ZSmartPointer<TestObject> nullPtr; + TASSERT(nullPtr.Pointer() == NULL, "ZSmartPointer() constructed default pointer not set to null!\n"); + TASSERT(nullPtr.Counter() == NULL, "ZSmartPointer() constructed default pointer with counter!\n"); + + TestObject* testObj = new TestObject(); + ZSmartPointer<TestObject> fromPtr(testObj); + TASSERT(fromPtr.Pointer() != NULL, "ZSmartPointer() constructed pointer from valid pointer as null!\n"); + TASSERT(fromPtr.Pointer() == testObj, "ZSmartPointer() constructed pointer from valid pointer and changed pointer!\n"); + TASSERT(fromPtr.Counter() != NULL, "ZSmartPointer() constructed pointer without counter!\n"); + TASSERT(ZREFCOUNTER_EXTRACT_STRONG_REF(fromPtr.Counter()->CombinedCount) == 1, "ZSmartPointer() constructed default pointer with bad strong count!\n"); + TASSERT(ZREFCOUNTER_EXTRACT_WEAK_REF(fromPtr.Counter()->CombinedCount) == 0, "ZSmartPointer() constructed default pointer with bad weak count!\n"); + + ZSmartPointer<TestObject> fromOtherPtr(fromPtr); + TASSERT(fromOtherPtr.Pointer() != NULL, "ZSmartPointer() constructed pointer from valid pointer as null!\n"); + TASSERT(fromOtherPtr.Pointer() == testObj, "ZSmartPointer() constructed pointer from valid pointer and changed pointer!\n"); + TASSERT(fromOtherPtr.Counter() != NULL, "ZSmartPointer() constructed pointer without counter!\n"); + TASSERT(ZREFCOUNTER_EXTRACT_STRONG_REF(fromOtherPtr.Counter()->CombinedCount) == 2, "ZSmartPointer() constructed default pointer with bad strong count!\n"); + TASSERT(ZREFCOUNTER_EXTRACT_WEAK_REF(fromOtherPtr.Counter()->CombinedCount) == 0, "ZSmartPointer() constructed default pointer with bad weak count!\n"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Operators() +{ + //Scope in to ensure all destructors get called + { + TestObject *temp; + + //Equivalent to + // TestObject* testObj1 = NULL; + ZSmartPointer<TestObject> testObj1; + + TASSERT(TestObject::Instances == 0, "Default constructor allocated object!"); + + //Equivalent to + // TestObject* testObj2 = new TestObject(); + ZSmartPointer<TestObject> testObj2(new TestObject()); + + TASSERT(TestObject::Instances == 1, "TestObject failed to construct!"); + TASSERT(testObj1 != testObj2, "ZSmartPointer != operator failed!"); + + //Equivalent to + // testObj1 = new TestObject(); + temp = new TestObject(); + + TASSERT(TestObject::Instances == 2, "TestObject failed to construct!"); + + testObj1 = temp; + + //Equivalent syntax + testObj1->Value = 5; + testObj2->Value = 10; + + TASSERT(testObj1->Value == 5 && testObj2->Value == 10, "ZSmartPointer = operator failed!"); + TASSERT(testObj1 != testObj2, "ZSmartPointer != operator failed!"); + + //Equivalent to + // delete testObj2; + // testObj2 = testObj1; + testObj2 = testObj1; + + TASSERT(TestObject::Instances == 1, "ZSmartPointer failed to deallocate!"); + TASSERT(testObj2->Value == 5, "ZSmartPointer = operator failed!"); + TASSERT(testObj2 == testObj1, "ZSmartPointer == operator failed!"); + + //Hard to equate to new/delete, as it allocates a new object and returns a smart pointer to it + testObj1 = getAllocatedTestObject(); + + TASSERT(TestObject::Instances == 2, "ZSmartPointer copy constructor and assignment operator failed!"); + + //Equivalent syntax + testObj1->Value = 10; + + TASSERT(testObj2->Value == 5, "ZSmartPointer referencing incorrect object!"); + TASSERT(testObj1->Value == 10, "ZSmartPointer referencing incorrect object!"); + + //Equivalent to + // delete testObj1; + // testObj1 = testObj2; + testObj1 = testObj2; + + TASSERT(TestObject::Instances == 1, "ZSmartPointer failed to deallocate!"); + + testObj2 = NULL; + + TASSERT(TestObject::Instances == 1, "ZSmartPointer deallocated incorrectly!"); + + testObj1 = NULL; + + TASSERT(TestObject::Instances == 0, "ZSmartPointer failed to deallocate!"); + } + + TASSERT(TestObject::Instances == 0, "ZSmartPointer failed to call destructors!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Cast() +{ + ZSmartPointer<TestObject> testObj1(new TestObject()); + TASSERT(TestObject::Instances == 1, "Superclass failed to allocate!"); + + ZSmartPointer<TestObject> testObj2(new TestObjectSubclass()); + TASSERT(TestObject::Instances == 2, "Subclass failed to allocate!"); + + TASSERT(testObj1->Foo(), "TestObject virtual method call failed!"); + TASSERT(!testObj2->Foo(), "TestObjectSubclass virtual method call failed!"); + TASSERT(testObj2.Cast<TestObjectSubclass>()->Bar(), "ZSmartPointer failed to cast!"); + + ZSmartPointer<TestObjectSubclass> testObjSub = testObj2.Cast<TestObjectSubclass>(); + + TASSERT(TestObject::Instances == 2, "ZSmartPointer cast function created new object!"); + + TASSERT(autoCast(testObjSub), "ZSmartPointer failed to auto up-cast!"); + + testObj2 = NULL; + + TASSERT(TestObject::Instances == 2, "ZSmartPointer casted to subclass failed to maintain reference!"); + + testObjSub = NULL; + + TASSERT(TestObject::Instances == 1, "ZSmartPointer subclass nullify failed to call destructor!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Detach() +{ + TestObject* object = new TestObject(); + + ZSmartPointer<TestObject> sPtr(object); + ZSmartPointer<TestObject> sPtr2(sPtr); + + TASSERT(sPtr.Detach() == NULL, "Detach() succeeded when two references are held!"); + + sPtr2 = NULL; + + TASSERT(sPtr.Detach() == object, "Detach() failed when one reference was held!"); + + delete object; + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_ArrayContainment() +{ + ZArray< ZPtr< TestObject > > testArray(10); + + TASSERT(TestObject::Instances == 0, "ZArray of smart pointers allocated instances!"); + + for (size_t i = 0; i < 10; i++) + { + testArray.PushBack(ZSmartPointer<TestObject>(new TestObject())); + testArray[i]->Value = i; + } + + TASSERT(TestObject::Instances == 10, "ZArray of smart pointers failing to maintain instances!"); + + //After PopBack, we should still have 10 objects (we held onto the popped element) + ZPtr<TestObject> testObj1 = testArray.PopBack(); + + TASSERT(TestObject::Instances == 10, "ZArray failed to deallocate contained smart pointer!"); + TASSERT(testObj1->Value == 9, "ZArray failed to return correct smart pointer from PopBack!"); + + //Now we should have lost the popped element from earlier + testObj1 = testArray.PopFront(); + + TASSERT(TestObject::Instances == 9, "ZArray failed to deallocate smart pointer after PopFront!"); + TASSERT(testObj1->Value == 0, "ZArray failed to return correct smart pointer from PopFront!"); + + //This assignment will cause us to lose a test object, but also gain one + testObj1 = ZPtr<TestObject>(new TestObject()); + testObj1->Value = 11; + + //This should keep the same amount of smart pointers (two references to the last one) + testArray.PushBack(testObj1); + + TASSERT(TestObject::Instances == 9, "ZArray failed to accept smart pointer with PushBack!"); + TASSERT(testArray[testArray.Size() - 1]->Value == 11, "ZArray failed to push correct smart pointer with PushBack!"); + + //This will cause us to lose one + testArray.Erase(5); + + TASSERT(TestObject::Instances == 8, "ZArray failed to deallocate smart pointer after Erase(5)!"); + + //This will cause us to lose two more + testArray.Erase(2, 4); + + TASSERT(TestObject::Instances == 6, "ZArray failed to deallocate smart pointers after Erase(2, 4)!"); + + //This should cause us to lose them all, but testObj1 still has a single reference + testArray.Clear(); + + TASSERT(TestObject::Instances == 1, "ZArray failed to deallocate all smart pointers after Clear()!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_ListContainment() +{ + unsigned int i; + + ZList< ZPtr<TestObject> > testList; + + TASSERT(TestObject::Instances == 0, "ZList of smart pointers allocated instances!"); + + for (i = 0; i < 10; i++) + { + testList.PushBack(ZPtr<TestObject>(new TestObject())); + testList.Back()->Value = i; + } + + TASSERT(TestObject::Instances == 10, "ZList of smart pointers failing to maintain instances!"); + + ZPtr<TestObject> testObj1 = testList.PopBack(); + + TASSERT(TestObject::Instances == 10, "ZList failed to deallocate smart pointer!"); + TASSERT(testObj1->Value == 9, "ZList failed to return correct smart pointer!"); + + testObj1 = testList.PopFront(); + + TASSERT(TestObject::Instances == 9, "ZSmartPointer failed to deallocate!"); + TASSERT(testObj1->Value == 0, "ZList failed to return correct smart pointer!"); + + testList.PushBack(testObj1); + + TASSERT(TestObject::Instances == 9, "ZList failed to accept SmartPointer!"); + TASSERT(testList.Back()->Value == 0, "ZList failed to push correct smart pointer!"); + + ZList< ZSmartPointer< TestObject > >::Iterator itr3 = testList[5]; + + testList.Erase(itr3); + + TASSERT(TestObject::Instances == 8, "ZList failed to deallocate smart pointer!"); + + ZList< ZSmartPointer< TestObject > >::Iterator itr1 = testList[2]; + ZList< ZSmartPointer< TestObject > >::Iterator itr2 = testList[4]; + + testList.Erase(itr1, itr2); + + TASSERT(TestObject::Instances == 6, "ZList failed to deallocate smart pointers!"); + + testList.Clear(); + + TASSERT(TestObject::Instances == 1, "ZList failed to deallocate all smart pointers!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_RingBufferContainment() +{ + return "TODO"; +} + +/*************************************************************************/ + +#define TEST_NUM_POINTERS (1024) +#define TEST_NUM_THREADS 4 + +static ZArray< ZSmartPointer<TestObject> > g_threadPointers[TEST_NUM_THREADS]; +static SST_TLS tls; +static SST_Event readyGo; + +static void testFunction(ZSmartPointer<TestObject> _sPtr) +{ + ZSmartPointer<TestObject>* sPtr = (ZSmartPointer<TestObject>*)SST_Concurrency_GetTLSValue(tls); //This is just here to hold the reference for a while + + *sPtr = _sPtr; +} + +static int threadTest(void* tid) +{ + size_t index = (size_t)tid; + ZArray< ZSmartPointer<TestObject> >* thrPtrs = &g_threadPointers[index]; + ZSmartPointer<TestObject>* ptr; + size_t numnullified = 0; + + //Allocate a smart pointer object, store in TLS slot + ptr = new ZSmartPointer<TestObject>(); + SST_Concurrency_SetTLSValue(tls, (void*)ptr); + + //For for ready + SST_Concurrency_WaitEvent(readyGo, SST_WAIT_INFINITE); + + //Iterate over and nullify if value is above the loop count + while (WHILE_TRUE) + { + for (size_t i = 0; i < TEST_NUM_POINTERS; i++) + { + if (i == 0) { + i = 0; + } + + if ((*thrPtrs)[i] != NULL && (*thrPtrs)[i]->Value > i) + { + (*thrPtrs)[i] = NULL; + numnullified++; + } + else + { + testFunction((*thrPtrs)[i]); + } + + } + + if (numnullified == TEST_NUM_POINTERS) + break; + + //ZConcurrency::SleepThread(10); + } + + testFunction(ZSmartPointer<TestObject>()); //Nullify + + delete ptr; + + return 0; +} + +/* +This is a bit of a strange test. The only way to really ensure that it is safe to lose and gain references +across threads is to have two threads operating on smart pointers that reference the same object. If the method +terminates, than it was safe. Otherwise... we loop because of bad reference count state. +*/ +static const char* test_MultithreadAccess() +{ + ZArray< ZSmartPointer<TestObject> > pointers; + ZThreadContext ctx[TEST_NUM_THREADS]; + + pointers.Resize(TEST_NUM_POINTERS); + + //Resize all thread smart pointer arrays + for(size_t j=0; j<TEST_NUM_THREADS; j++) + g_threadPointers[j].Resize(TEST_NUM_POINTERS); + + for (size_t i = 0; i < TEST_NUM_POINTERS; i++) + { + pointers[i] = znew TestObject(); + + //Copy smart pointers to other threads + for(size_t j=0; j< TEST_NUM_THREADS; j++) + g_threadPointers[j][i] = pointers[i]; + } + + //Create TLS and event + tls = SST_Concurrency_CreateTLS(); + readyGo = SST_Concurrency_CreateEvent(); + + for(size_t i=0; i<TEST_NUM_THREADS; i++) + ctx[i] = ZConcurrency::CreateThread(threadTest, (void*)i); + + size_t numdeleted = 0; + size_t itrval = 0; + + SST_Concurrency_SignalEvent(readyGo); + while (numdeleted < TEST_NUM_POINTERS) + { + TestObject *object; + + for (size_t i = 0; i < TEST_NUM_POINTERS; i++) + { + object = pointers[i].Detach(); //This will only work if this thread holds the only reference + + if (object != NULL) + { + zdelete object; + numdeleted++; + } + else if (pointers[i] != NULL) + pointers[i]->Value = itrval; + } + + if(itrval < TEST_NUM_POINTERS) + itrval++; + } + + //Await thread exit + for(size_t i=0; i<TEST_NUM_THREADS; i++) + { + ZConcurrency::WaitThread(ctx[i]); + ZConcurrency::DestroyThread(ctx[i]); + } + + SST_Concurrency_DestroyEvent(readyGo); + SST_Concurrency_DestroyTLS(tls); + + return ZTEST_SUCCESS; +} diff --git a/ZTestSuite/Test-ZTaskStream.cpp b/ZTestSuite/Test-ZTaskStream.cpp new file mode 100644 index 0000000..ba3b4ec --- /dev/null +++ b/ZTestSuite/Test-ZTaskStream.cpp @@ -0,0 +1,207 @@ +/* + Test-ZTaskStream.cpp + Author: James Russell <jcrussell@762studios.com> + + Purpose: Unit Test the ZTaskStream class. + + Changelog: + 12/18/2011 - Removed dependency on ZString (crertel) + 2011/04/13 - creation (jcrussell) +*/ + +#include "ZUnitTest.hpp" + +#include <ZUtil/ZTaskStream.hpp> +#include <SST/SST_Atomic.h> + +static const char* testSingleTask(); +static const char* testTaskStream(); +static const char* testFuture(); + + +//List of unit tests +ZUnitTest ZTaskStreamUnitTests[] = +{ + { + "Single task and wait", + testSingleTask + }, + { + "Test TaskStream", + testTaskStream + }, + { + "Test Future", + testFuture + } +}; + +//Now declare the ZUnitTestBlock associated with this. +DECLARE_ZTESTBLOCK(ZTaskStream); + +/*************************************************************************/ + +static volatile int Task1Val = 0; +static volatile int Task2Val = 0; + +//Wrapper Class +class ZTestTask : public ZTask +{ + virtual ZTaskReturnStatus Execute( void *_arg ) + { + URFP(_arg); + return ZTRS_FAILURE; + } + + virtual void OnTaskFailed( void *_taskArgument ) + { + URFP(_taskArgument); + SST_Atomic_Inc(&Task2Val); + } +}; + +//Should be pointer to int as arg +static ZTaskReturnStatus TaskMethod1(ZTaskStream *_stream, ZTask *_task, void* _arg) +{ + URFP(_stream); + URFP(_task); + + //Arg is pointer to int + int lim = *(int*)_arg; + + for (int i = 0; i < lim; i++) + SST_Atomic_Inc(&Task1Val); + + return ZTRS_SUCCESS; +} + +//Should be pointer to bool as arg +static ZTaskReturnStatus TaskMethod2(ZTaskStream *_stream, ZTask *_task, void* _arg) +{ + URFP(_stream); + URFP(_task); + + //Arg is pointer to bool + bool val = *(bool*)_arg; + + if (val) + SST_Atomic_Inc(&Task1Val); + else + SST_Atomic_Inc(&Task2Val); + + return ZTRS_SUCCESS; +} + +//Takes integer argument, returns string with parsed int +static const char* FutureMethod(int _arg) +{ + char* buffer = new char[65]; + + + sprintf(buffer, "String%d", _arg); + + buffer[64] = ZBASICSTRING_NULL_TERMINATOR; + return buffer; +} + +//Takes an integer amount, sleeps that long, returns string with parsed int +static const char* FutureMethod2(int _arg) +{ + ZConcurrency::SleepThread(_arg); + + return FutureMethod(_arg); +} + +static ZTaskReturnStatus SingleTaskMethod(ZTaskStream *_stream, ZTask *_task, void* _arg) +{ + URFP(_stream); + URFP(_task); + + int* arg = (int*)_arg; + + *arg = 0xaabbccdd; + return ZTRS_SUCCESS; +} + +////////////////////////////// +/////// ACTUAL TESTS ///////// +////////////////////////////// +static const char* testSingleTask() +{ + ZTaskStream stream; + unsigned int k = 0; + + stream.PushTask(ZPtr<ZTask>(new ZTask(SingleTaskMethod, &k))); + + stream.ExecuteTasks(500); + + TASSERT(k == 0xAABBCCDD, "Task did not set variable to correct value."); + + return ZTEST_SUCCESS; +} + +static const char* testTaskStream() +{ + //To Test Shutdown, We Scope + { + ZTaskStream TaskStream; + + TaskStream.SetTaskThreadCount(2); + + Task1Val = 0; + Task2Val = 0; + + int i = 1000; + int j = 10000; + + bool trueVal = true; + bool falseVal = false; + + TaskStream.PushTask(ZPtr<ZTask>(new ZTask(TaskMethod1, &i))); + TaskStream.PushTask(ZPtr<ZTask>(new ZTask(TaskMethod1, &j))); + TaskStream.PushTask(ZPtr<ZTask>(new ZTask(TaskMethod2, &trueVal))); + TaskStream.PushTask(ZPtr<ZTask>(new ZTask(TaskMethod2, &falseVal))); + TaskStream.PushTask(ZPtr<ZTask>(new ZTestTask())); + + TaskStream.ExecuteTasks(10000); + + TASSERT(Task1Val == 11001, "TaskVal1 Not Set Correctly!"); + TASSERT(Task2Val == 2, "TaskVal2 Not Set Correctly!"); + } + + return ZTEST_SUCCESS; +} + +static const char* testFuture() +{ + ZTaskStream TaskStream; + + TaskStream.SetTaskThreadCount(2); + + ZPtr< ZFuture<const char*, int> > testFuture1; + ZPtr< ZFuture<const char*, int> > testFuture2; + ZPtr< ZFuture<const char*, int> > testFuture3; + ZPtr< ZFuture<const char*, int> > testFuture4; + + testFuture1 = new ZFuture<const char*, int>(FutureMethod, 1); + testFuture2 = new ZFuture<const char*, int>(FutureMethod, 2); + testFuture3 = new ZFuture<const char*, int>(FutureMethod2, 1000); + testFuture4 = new ZFuture<const char*, int>(FutureMethod2, 2000); + + TaskStream.PushFuture(testFuture3); + TaskStream.PushFuture(testFuture4); + TaskStream.PushFuture(testFuture1); + TaskStream.PushFuture(testFuture2); + + TASSERT(testFuture1->IsComplete() == false, "Test Future 1 completed waaaaaaay too soon!"); + TASSERT( strcmp(testFuture2->GetValue(),"String2") == 0, "Test Future 2 returned invalid value"); + TASSERT( strcmp(testFuture3->GetValue(), "String1000") == 0, "Test Future 3 returned invalid value"); + TASSERT( strcmp(testFuture4->GetValueRef(), "String2000") == 0, "TestFuture3 returned invalid value reference"); + + TASSERT(testFuture1->IsComplete(), "Test Future 1 not registering as complete!"); + TASSERT(testFuture2->IsComplete(), "Test Future 2 not registering as complete!"); + TASSERT(testFuture3->IsComplete(), "Test Future 3 not registering as complete!"); + TASSERT(testFuture4->IsComplete(), "Test Future 4 not registering as complete!"); + + return ZTEST_SUCCESS; +} diff --git a/ZTestSuite/Test-ZWeakPointer.cpp b/ZTestSuite/Test-ZWeakPointer.cpp new file mode 100644 index 0000000..2e2d399 --- /dev/null +++ b/ZTestSuite/Test-ZWeakPointer.cpp @@ -0,0 +1,383 @@ + +#include "ZUnitTest.hpp" + +#include <ZUtil/ZConcurrency.hpp> +#include <ZUtil/ZWeakPointer.hpp> + +static const char* test_Constructors_Nullify(); +static const char* test_Operators(); +static const char* test_Cast(); +static const char* test_ArrayContainment(); +static const char* test_ListContainment(); +static const char* test_RingBufferContainment(); +static const char* test_DeallocLock(); +static const char* test_MultithreadAccess(); + +//List of unit tests +ZUnitTest ZWeakPointerUnitTests[] = +{ + { "ZWeakPointer: Constructors, Nullify", test_Constructors_Nullify }, + { "ZWeakPointer: Operators", test_Operators }, + { "ZWeakPointer: Cast", test_Cast }, + { "ZWeakPointer: Containment in ZArray", test_ArrayContainment }, + { "ZWeakPointer: Containment in ZList", test_ListContainment }, + { "ZWeakPointer: Containment in ZRingBuffer", test_RingBufferContainment }, + { "ZWeakPointer: Deallocation Lock", test_DeallocLock }, + { "ZWeakPointer: Multithreaded Access, Deallocation Lock", test_MultithreadAccess } +}; + +DECLARE_ZTESTBLOCK(ZWeakPointer); + +/*************************************************************************/ + +namespace ZWeakPointerTestObjects +{ + struct TestObject + { + //Constructor + TestObject() { TestObject::Instances++; } + + //Destructor + ~TestObject() { TestObject::Instances--; } + + //Value field + size_t Value; + + //Static Instance Count + static size_t Instances; + + //Virtual Function + virtual bool Foo() const { return true; } + }; + + struct TestObjectSubclass : public TestObject + { + //Constructor + TestObjectSubclass() : TestObject() {} + + //Subclass Override + bool Foo() const { return false; } + + //Subclass Method + bool Bar() const { return true; } + }; + + //Defaults to zero + size_t TestObject::Instances = 0; + + //This function is used to test the auto up-casting of contained types + bool autoCast(ZWeakPointer<TestObject> _testObj) + { + return true; + } + + //Method used to nullify a smart pointer in another thread + int nullifySmartPointer(void* _sPtr) + { + ZSmartPointer<TestObject>& sPtr = *reinterpret_cast<ZSmartPointer<TestObject>*>(_sPtr); + + sPtr = NULL; + + return 0; + } +} + +using namespace ZWeakPointerTestObjects; + +/*************************************************************************/ + +static const char* test_Constructors_Nullify() +{ + ZSmartPointer<TestObject> sNullPtr; + ZSmartPointer<TestObject> sPtr(new TestObject()); + + ZReferenceCounter* sPtrRefCounter = sPtr.Counter(); + + ZWeakPointer<TestObject> wNullPtr; + TASSERT(wNullPtr.Pointer() == NULL, "ZWeakPointer() constructed default pointer not set to null!\n"); + TASSERT(wNullPtr.Counter() == NULL, "ZWeakPointer() constructed default pointer with counter!\n"); + + ZWeakPointer<TestObject> wNullPtrFromPtr(sNullPtr); + TASSERT(wNullPtr.Pointer() == NULL, "ZWeakPointer() constructed from null smart pointer not set to null!\n"); + TASSERT(wNullPtr.Counter() == NULL, "ZWeakPointer() constructed from null smart pointer with counter!\n"); + + ZWeakPointer<TestObject> wPtrFromSPtr = sPtr; + TASSERT(TestObject::Instances == 1, "ZWeakPointer() constructed additional test object from smart pointer!"); + TASSERT(sPtr.Counter() == wPtrFromSPtr.Counter(), "ZWeakPointer() constructed from smart pointer does not share counter!"); + TASSERT(wPtrFromSPtr.Counter()->GetStrongRefCount() == 1, "ZWeakPointer() constructed from smart pointer added strong reference!"); + TASSERT(wPtrFromSPtr.Counter()->GetWeakRefCount() == 1, "ZWeakPointer() constructed from smart pointer did not add weak reference!"); + + ZWeakPointer<TestObject> wPtrFromWPtr = wPtrFromSPtr; + TASSERT(TestObject::Instances == 1, "ZWeakPointer() constructed additional test object from weak pointer!"); + TASSERT(wPtrFromSPtr.Counter() == wPtrFromWPtr.Counter(), "ZWeakPointer() constructed from weak pointer does not share counter!"); + TASSERT(wPtrFromWPtr.Counter()->GetStrongRefCount() == 1, "ZWeakPointer() constructed from weak pointer added strong reference!"); + TASSERT(wPtrFromWPtr.Counter()->GetWeakRefCount() == 2, "ZWeakPointer() constructed from weak pointer did not add weak reference!"); + + //Equality Tests + TASSERT(wPtrFromSPtr == sPtr, "Equality test failed on weak pointer from smart pointer and smart pointer!"); + TASSERT(wPtrFromWPtr == sPtr, "Equality test failed on weak pointer from weak pointer and smart pointer!"); + TASSERT(wPtrFromWPtr == wPtrFromSPtr, "Equality test failed on weak pointer from smart pointer and weak pointer from weak pointer!"); + + //Lose the object + sPtr = NULL; + + TASSERT(TestObject::Instances == 0, "Weak references prevented ZSmartPointer from deallocating object!"); + TASSERT(sPtr.Counter() == NULL, "ZSmartPointer failed to nullify pointer to reference counter!"); + + TASSERT(sPtrRefCounter->GetStrongRefCount() == 0, "Nullification of smart pointer failed to lose strong reference!"); + + TASSERT(sPtrRefCounter->GetWeakRefCount() == 2, "Nullification of smart pointer reduced weak reference count!"); + TASSERT(wPtrFromSPtr == NULL, "Nullification of weak pointer from smart pointer failed!"); + + TASSERT(sPtrRefCounter->GetWeakRefCount() == 1, "Auto-nullification of weak pointer failed to lose weak reference!"); + TASSERT(wPtrFromWPtr == NULL, "Nullification of weak pointer from weak pointer failed!"); + + TASSERT(wPtrFromSPtr.Counter() == NULL, "Nullification of weak pointer from smart pointer failed to lose reference counter!"); + TASSERT(wPtrFromWPtr.Counter() == NULL, "Nullification of weak pointer from weak pointer failed to lose reference counter!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Operators() +{ + TestObject* object1 = new TestObject(); + TestObject* object2 = new TestObject(); + + ZSmartPointer<TestObject> sPtr1(object1); + ZSmartPointer<TestObject> sPtr2(object2); + + ZWeakPointer<TestObject> wPtr1 = sPtr1; + ZWeakPointer<TestObject> wPtr2 = sPtr2; + + TASSERT(wPtr1 == object1, "Equality operator failed between weak pointer and object pointer!"); + TASSERT(wPtr1 == sPtr1, "Equality operator failed between weak pointer and smart pointer!"); + TASSERT(wPtr1 != sPtr2, "Equality operator succeeded between weak pointer and different smart pointer!"); + TASSERT(wPtr1 != wPtr2, "Equality operator succeeded between weak pointer and different weak pointer!"); + TASSERT(wPtr1->Foo(), "Access operator, call to Foo() failed to return true!"); + TASSERT((*wPtr1).Foo(), "Dereference operator, call to Foo() failed to return true!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_Cast() +{ + ZSmartPointer<TestObject> sPtr(new TestObjectSubclass()); + ZWeakPointer<TestObject> wPtr1(sPtr); + ZWeakPointer<TestObjectSubclass> wPtr2(sPtr); + + TASSERT(TestObject::Instances == 1, "Subclass weak pointer created additional test object!"); + TASSERT(sPtr.Counter()->GetWeakRefCount() == 2, "Subclassed weak pointer failed to share reference counter!"); + + TASSERT(!wPtr1->Foo(), "TestObject virtual method call failed!"); + TASSERT(!wPtr2->Foo(), "TestObjectSubclass virtual method call failed!"); + TASSERT(wPtr1.Cast<TestObjectSubclass>()->Bar(), "ZWeakPointer failed to cast!"); + + TASSERT(autoCast(wPtr2), "ZWeakPointer failed to auto up-cast!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_ArrayContainment() +{ + ZArray< ZSmartPointer< TestObject > > sPtrArray(10); + ZArray< ZWeakPointer< TestObject > > wPtrArray(10); + + TASSERT(TestObject::Instances == 0, "ZArray of smart pointers allocated instances!"); + + for (size_t i = 0; i < 10; i++) + { + //Add a smart pointer to the set + sPtrArray.PushBack(ZSmartPointer<TestObject>(znew TestObject())); + sPtrArray[i]->Value = i; + + //Add a weak pointer created from that smart pointer + wPtrArray.PushBack(sPtrArray[i]); + } + + for (size_t i = 0; i < 10; i++) + { + TASSERT(sPtrArray[i].Counter()->GetStrongRefCount() == 1, "Starting Strong Count is incorrect!"); + TASSERT(sPtrArray[i].Counter()->GetWeakRefCount() == 1, "Starting Weak Count is incorrect!"); + } + + wPtrArray.PopBack(); + + TASSERT(sPtrArray[sPtrArray.Size() - 1].Counter()->GetWeakRefCount() == 0, "PopBack() with weak pointer array failed to remove weak reference!"); + + wPtrArray.PopFront(); + + TASSERT(sPtrArray[0].Counter()->GetWeakRefCount() == 0, "PopFront() with weak pointer array failed to remove weak reference!"); + + wPtrArray.Erase(0, 2); + + for (size_t i = 1; i < 3; i++) + { + TASSERT(sPtrArray[i].Counter()->GetWeakRefCount() == 0, "Erase() with weak pointer array failed to remove weak reference!"); + } + + //At this point, we have six elements in the weak pointer array + wPtrArray.Resize(4); + + //That call should have ditched weak references from the last two + for (size_t i = 7; i < 9; i++) + { + TASSERT(sPtrArray[i].Counter()->GetWeakRefCount() == 0, "Resize() with lower count failed to remove weak references!"); + } + + wPtrArray.Clear(); + + for (size_t i = 0; i < 10; i++) + { + TASSERT(sPtrArray[i].Counter()->GetWeakRefCount() == 0, "Clear() failed to remove all weak references!"); + } + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_ListContainment() +{ + return "TODO"; +} + +/*************************************************************************/ + +static const char* test_RingBufferContainment() +{ + return "TODO"; +} + +/*************************************************************************/ + +static int useWeakPointer(void* _wPtr) +{ + ZWeakPointer<TestObject>& wPtr = *reinterpret_cast<ZWeakPointer<TestObject>*>(_wPtr); + + DeallocLock(wPtr) { + return 0; + } else { + return 1; + } +} + +static const char* test_DeallocLock() +{ + TestObject* object = znew TestObject(); + + ZSmartPointer<TestObject> sPtr(object); + + ZWeakPointer<TestObject> wPtr = sPtr; + + DeallocLock(wPtr) { + TASSERT(wPtr.Counter()->State > 0, "ZWeakPointer DeallocLock did not increase State variable!"); + } + + TASSERT(wPtr.Counter()->State == 0, "ZWeakPointer DeallocLock did not decrement State variable!"); + + ZThreadContext ctxt; + ZThreadContext ctxt2; + + DeallocLock(wPtr) { + ctxt = ZConcurrency::CreateThread(nullifySmartPointer, &sPtr); + + //At this point, the other thread should be waiting on this one, but + //should signal us by setting state to NULL with an atomic XOR + while (wPtr.Counter()->State > 0) + continue; + + ZWeakPointer<TestObject> wPtr2 = wPtr; + + ctxt2 = ZConcurrency::CreateThread(useWeakPointer, &wPtr2); + + ZConcurrency::WaitThread(ctxt2); + + //At the time we have gotten here, State has been signaled and we should fail to be able to signal 'InUse' + TASSERT(ctxt2.ThreadExitStatus == 1, "ZWeakPointer was locked and used after being signaled for deallocation!"); + + ZConcurrency::DestroyThread(ctxt2); + } + + //Now that we have signaled that we are no longer in use, we can wait + ZConcurrency::WaitThread(ctxt); + ZConcurrency::DestroyThread(ctxt); + + TASSERT(TestObject::Instances == 0, "Failed to completely deallocate all TestObject instances!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +#define TEST_NUM_POINTERS (1024) + +static ZArray< ZWeakPointer<TestObject> > g_threadPointers; + +static int threadTest(void *arg) +{ + URFP(arg); + + while (WHILE_TRUE) + { + size_t numupdated = 0; + + for (size_t i = 0; i < TEST_NUM_POINTERS; i++) + { + if (g_threadPointers[i] == NULL) + continue; + + //Effectively DeallocLock, but with the ability to inspect testLock + if (ZWeakPointerDeallocLock testLock = g_threadPointers[i]()) { + g_threadPointers[i]->Value++; + numupdated++; + } + } + + if (numupdated == 0) + break; + } + + return 0; +} + +static const char* test_MultithreadAccess() +{ + ZArray< ZSmartPointer<TestObject> > pointers; + + pointers.Resize(TEST_NUM_POINTERS); + g_threadPointers.Resize(TEST_NUM_POINTERS); + + for (size_t i = 0; i < TEST_NUM_POINTERS; i++) + { + pointers[i] = znew TestObject(); + g_threadPointers[i] = pointers[i]; + + pointers[i]->Value = 0; + } + + ZThreadContext ctxt = ZConcurrency::CreateThread(threadTest, NULL); + + //Each object now has a smart pointer in this thread and a weak pointer that will be used + //by the other thread, so it should be safe to use the weak pointer as long as the DeallocLock + //macro is used to prevent deallocation + + for (size_t i = 0; i < TEST_NUM_POINTERS; i++) + { + pointers[i] = NULL; + + ZConcurrency::SleepThread(10); + } + + ZConcurrency::WaitThread(ctxt); + ZConcurrency::DestroyThread(ctxt); + + TASSERT(TestObject::Instances == 0, "Failed to completely deallocate all TestObject instances!"); + + return ZTEST_SUCCESS; +} \ No newline at end of file diff --git a/ZTestSuite/Test-ZXMLReader.cpp b/ZTestSuite/Test-ZXMLReader.cpp new file mode 100644 index 0000000..7b378f7 --- /dev/null +++ b/ZTestSuite/Test-ZXMLReader.cpp @@ -0,0 +1,142 @@ +#include "ZUnitTest.hpp" + +#include <ZUtil/ZXMLReader.hpp> + +static const char* test_LoadSuccess(); +static const char* test_LoadFailed(); + +ZUnitTest ZXMLReaderUnitTests[] = +{ + { "ZXMLReader: Successful Load", test_LoadSuccess }, + { "ZXMLReader: Failed Load", test_LoadFailed } +}; + +//Now declare the ZUnitTestBlock associated with this. +DECLARE_ZTESTBLOCK(ZXMLReader); + +/*************************************************************************/ + +namespace ZXMLReaderTestData +{ + const char* testDataValid1 = "<?xml version=\"1.0\"?>" LINE_TERMINATOR + "<lvl1node>" LINE_TERMINATOR + " <lvl2node>" LINE_TERMINATOR + " <lvl3node x=\"0\" y=\"1\" z=\"2\" />" LINE_TERMINATOR + " Level 2 Node Has Some of the Datas." LINE_TERMINATOR + " </lvl2node>" LINE_TERMINATOR + " Level 1 Node Has All the Datas." LINE_TERMINATOR + "</lvl1node>" LINE_TERMINATOR + LINE_TERMINATOR; + + const char* testDataValid2 = "<?xml version=\"1.0\"?>" LINE_TERMINATOR + "<lvl1node>" LINE_TERMINATOR + " <lvl2node>" LINE_TERMINATOR + " <lvl3node x=\"0\" y=\"1\" z=\"2\" />" LINE_TERMINATOR + " <lvl3node x=\"2\" y=\"1\" z=\"0\" />" LINE_TERMINATOR + " Level 2 Node Has Some of the Datas." LINE_TERMINATOR + " </lvl2node>" LINE_TERMINATOR + " <tinylvl2node size=\"tiny\" />" LINE_TERMINATOR + " <largelvl2node size=\"large\" />" LINE_TERMINATOR + " Level 1 Node Has All the Datas." LINE_TERMINATOR + "</lvl1node>" LINE_TERMINATOR + "<secondrootnode>" LINE_TERMINATOR + " This is a second root node. Use it wisely." LINE_TERMINATOR + "</secondrootnode>" LINE_TERMINATOR + LINE_TERMINATOR; + + // the 'invalid' tests are mostly designed to test custom error handling in the reader, not + // stability of rapidxml + const char* testDataInvalid1 = "<lvl1node>" LINE_TERMINATOR + " <lvl2node>" LINE_TERMINATOR + " </lvl1node>" LINE_TERMINATOR + "</lvl2node>" LINE_TERMINATOR + "</lvl3node>" LINE_TERMINATOR + LINE_TERMINATOR; + + const char* testDataInvalid2 = "<lvl1node>><>" LINE_TERMINATOR + "</lvl1node>" LINE_TERMINATOR + LINE_TERMINATOR; + + const char* testDataInvalid3 = "<!-- This is a bad comment. ->" LINE_TERMINATOR + "<lvl1node>" LINE_TERMINATOR + " Bad Comment. Bad." LINE_TERMINATOR + "</lvl1node>" LINE_TERMINATOR + LINE_TERMINATOR; +} + +using namespace ZXMLReaderTestData; + +/*************************************************************************/ + +static const char* test_LoadSuccess() +{ + ZString val; + ZKVTree tree; + + ZXMLReader reader1; + + TASSERT(reader1.Read(testDataValid1, strlen(testDataValid1)), "ZXMLReader::Read returned 'false' on valid data set #1!"); + TASSERT(reader1.GetErrorString().Empty(), "ZXMLReader failed to load valid data set #1!"); + + reader1.GetKVTree(tree); + + TASSERT(tree.Get("lvl1node") == "Level 1 Node Has All the Datas.", "ZXMLReader failed to store lvl1node correctly!"); + + TASSERT(tree.Get("lvl1node.lvl2node") == "Level 2 Node Has Some of the Datas.", "ZXMLReader failed to store lvl2node correctly!"); + + TASSERT(tree.Get("lvl1node.lvl2node.lvl3node") == "", "ZXMLReader failed to store lvl3node correctly!"); + TASSERT(tree.Get("lvl1node.lvl2node.lvl3node.x") == "0", "ZXMLReader failed to store lvl3node.x correctly!"); + TASSERT(tree.Get("lvl1node.lvl2node.lvl3node.y") == "1", "ZXMLReader failed to store lvl3node.y correctly!"); + TASSERT(tree.Get("lvl1node.lvl2node.lvl3node.z") == "2", "ZXMLReader failed to store lvl3node.z correctly!"); + + ZXMLReader reader2; + + TASSERT(reader2.Read(testDataValid2, strlen(testDataValid2)), "ZXMLReader::Read returned 'false' on valid data set #2!"); + TASSERT(reader2.GetErrorString().Empty(), "ZXMLReader failed to load valid data set #2!"); + + tree.Clear(); + reader2.GetKVTree(tree); + + TASSERT(tree.Get("lvl1node") == "Level 1 Node Has All the Datas.", "ZXMLReader failed to store lvl1node correctly!"); + + TASSERT(tree.Get("lvl1node.lvl2node") == "Level 2 Node Has Some of the Datas.", "ZXMLReader failed to store lvl2node correctly!"); + + TASSERT(tree.Get("lvl1node.lvl2node.lvl3node") == "", "ZXMLReader failed to store lvl3node correctly!"); + TASSERT(tree.Get("lvl1node.lvl2node.lvl3node.x") == "0", "ZXMLReader failed to store lvl3node.x correctly!"); + TASSERT(tree.Get("lvl1node.lvl2node.lvl3node.y") == "1", "ZXMLReader failed to store lvl3node.y correctly!"); + TASSERT(tree.Get("lvl1node.lvl2node.lvl3node.z") == "2", "ZXMLReader failed to store lvl3node.z correctly!"); + + TASSERT(tree.Get("lvl1node.lvl2node.lvl3node[1]") == "", "ZXMLReader failed to store lvl3node[1] correctly!"); + TASSERT(tree.Get("lvl1node.lvl2node.lvl3node[1].x") == "2", "ZXMLReader failed to store lvl3node[1].x correctly!"); + TASSERT(tree.Get("lvl1node.lvl2node.lvl3node[1].y") == "1", "ZXMLReader failed to store lvl3node[1].y correctly!"); + TASSERT(tree.Get("lvl1node.lvl2node.lvl3node[1].z") == "0", "ZXMLReader failed to store lvl3node[1].z correctly!"); + + TASSERT(tree.Get("lvl1node.tinylvl2node") == "", "ZXMLReader failed to store tinylvl2node correctly!"); + TASSERT(tree.Get("lvl1node.tinylvl2node.size") == "tiny", "ZXMLReader failed to store tinylvl2node.size correctly!"); + + TASSERT(tree.Get("lvl1node.largelvl2node") == "", "ZXMLReader failed to store largelvl2node correctly!"); + TASSERT(tree.Get("lvl1node.largelvl2node.size") == "large", "ZXMLReader failed to store largelvl2node.size correctly!"); + + TASSERT(tree.Get("secondrootnode") == "This is a second root node. Use it wisely.", "ZXMLReader failed to store secondrootnode correctly!"); + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_LoadFailed() +{ + ZXMLReader reader1; + ZXMLReader reader2; + ZXMLReader reader3; + + TASSERT(!reader1.Read(testDataValid1, strlen(testDataInvalid1)), "ZXMLReader returned 'true' on invalid data set #1!"); + TASSERT(!reader2.Read(testDataInvalid2, strlen(testDataInvalid2)), "ZXMLReader returned 'true' on invalid data set #2!"); + TASSERT(!reader3.Read(testDataInvalid3, strlen(testDataInvalid3)), "ZXMLReader returned 'true' on invalid data set #2!"); + + TASSERT(!reader1.GetErrorString().Empty(), "ZXMLReader did not report error message for invalid data set #1!"); + TASSERT(!reader2.GetErrorString().Empty(), "ZXMLReader did not report error message for invalid data set #2!"); + TASSERT(!reader3.GetErrorString().Empty(), "ZXMLReader did not report error message for invalid data set #3!"); + + return ZTEST_SUCCESS; +} \ No newline at end of file diff --git a/ZTestSuite/Test-ZXMLWriter.cpp b/ZTestSuite/Test-ZXMLWriter.cpp new file mode 100644 index 0000000..008cb1a --- /dev/null +++ b/ZTestSuite/Test-ZXMLWriter.cpp @@ -0,0 +1,73 @@ +#include "ZUnitTest.hpp" + +#include <ZUtil/ZXMLWriter.hpp> + +static const char* test_WriteSuccess(); +static const char* test_WriteFailure(); + +ZUnitTest ZXMLWriterUnitTests[] = +{ + { "ZXMLWriter: WriteSuccess", test_WriteSuccess }, + { "ZXMLWriter: WriteFailure", test_WriteFailure } +}; + +//Now declare the ZUnitTestBlock associated with this. +DECLARE_ZTESTBLOCK(ZXMLWriter); + +/*************************************************************************/ + +namespace ZXMLWriterTestData +{ + const char* test1Output = "<node1>" LINE_TERMINATOR + "<node2>" LINE_TERMINATOR + "<node3 attr1=\"value1\" attr2=\"value2\"/>" LINE_TERMINATOR + "</node2>" LINE_TERMINATOR + "Node1Body" LINE_TERMINATOR + "</node1>" LINE_TERMINATOR; + + const char* test2Output = "<node1><node2><node3 attr1=\"value1\" attr2=\"value2\"/></node2>Node1Body</node1>"; + + const char* test3Output = "" LINE_TERMINATOR + LINE_TERMINATOR; + +} + +using namespace ZXMLWriterTestData; + +/*************************************************************************/ + +static const char* test_WriteSuccess() +{ + ZString output; + ZKVTree tree; + + tree.Put("node1", "Node1Body"); + + tree.Put("node1.node2", ""); + + tree.Put("node1.node2.node3", ""); + tree.Put("node1.node2.node3.attr1", "value1"); + tree.Put("node1.node2.node3.attr2", "value2"); + + ZXMLWriter writer1; + ZXMLWriter writer2; + + TASSERT(writer1.Write(tree, output, true), "ZXMLWriter failed to write valid data set #1!"); + TASSERT(output == test1Output, "ZXMLWriter wrote incorrect value for data set #1!"); + + output.Clear(); + + TASSERT(writer2.Write(tree, output, false), "ZXMLWriter failed to write valid data set #1 with no newlines!"); + TASSERT(output == test2Output, "ZXMLWriter wrote incorrect value for data set #1 with no newlines!"); + + //TODO - one more output case, preferably something a bit more complicated? + + return ZTEST_SUCCESS; +} + +/*************************************************************************/ + +static const char* test_WriteFailure() +{ + return "TODO"; +} \ No newline at end of file diff --git a/ZTestSuite/ZTestSuite.vcxproj b/ZTestSuite/ZTestSuite.vcxproj new file mode 100644 index 0000000..d775c20 --- /dev/null +++ b/ZTestSuite/ZTestSuite.vcxproj @@ -0,0 +1,300 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup Label="ProjectConfigurations"> + <ProjectConfiguration Include="Debug|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectGuid>{2ECCF1D0-468D-4D45-B23F-857F2DD3A4CF}</ProjectGuid> + <RootNamespace>ZTestSuite</RootNamespace> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <PlatformToolset>v110</PlatformToolset> + <CharacterSet>MultiByte</CharacterSet> + <WholeProgramOptimization>true</WholeProgramOptimization> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <PlatformToolset>v110</PlatformToolset> + <CharacterSet>MultiByte</CharacterSet> + <WholeProgramOptimization>true</WholeProgramOptimization> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <PlatformToolset>v110</PlatformToolset> + <CharacterSet>MultiByte</CharacterSet> + <WholeProgramOptimization>true</WholeProgramOptimization> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <PlatformToolset>v110</PlatformToolset> + <CharacterSet>MultiByte</CharacterSet> + <WholeProgramOptimization>true</WholeProgramOptimization> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <ImportGroup Label="ExtensionSettings"> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <PropertyGroup Label="UserMacros" /> + <PropertyGroup> + <_ProjectFileVersion>11.0.50727.1</_ProjectFileVersion> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <OutDir>$(SolutionDir)Bin\x86\</OutDir> + <IntDir>$(SolutionDir)Intermediate\$(Configuration)\$(Platform)\$(ProjectName)\</IntDir> + <TargetName>$(ProjectName)-debug</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <OutDir>$(SolutionDir)Bin\x64\</OutDir> + <IntDir>$(SolutionDir)Intermediate\$(Configuration)\$(Platform)\$(ProjectName)\</IntDir> + <TargetName>$(ProjectName)-debug</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <OutDir>$(SolutionDir)Bin\x86\</OutDir> + <IntDir>$(SolutionDir)Intermediate\$(Configuration)\$(Platform)\$(ProjectName)\</IntDir> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <OutDir>$(SolutionDir)Bin\x64\</OutDir> + <IntDir>$(SolutionDir)Intermediate\$(Configuration)\$(Platform)\$(ProjectName)\</IntDir> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <Optimization>Disabled</Optimization> + <AdditionalIncludeDirectories>$(SolutionDir)Include;$(SolutionDir)Lib/Include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>_DEBUG;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <MinimalRebuild>false</MinimalRebuild> + <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> + <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> + <DisableLanguageExtensions>false</DisableLanguageExtensions> + <WarningLevel>Level4</WarningLevel> + <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> + <DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings> + <MultiProcessorCompilation>true</MultiProcessorCompilation> + <StringPooling>true</StringPooling> + <BufferSecurityCheck>false</BufferSecurityCheck> + </ClCompile> + <Link> + <AdditionalLibraryDirectories>$(SolutionDir)\Lib\x86;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> + <GenerateDebugInformation>true</GenerateDebugInformation> + <TargetMachine>MachineX86</TargetMachine> + <IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Midl> + <TargetEnvironment>X64</TargetEnvironment> + </Midl> + <ClCompile> + <Optimization>Disabled</Optimization> + <AdditionalIncludeDirectories>$(SolutionDir)Lib/Include;$(SolutionDir)Include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>_DEBUG;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <MinimalRebuild>false</MinimalRebuild> + <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> + <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> + <DisableLanguageExtensions>false</DisableLanguageExtensions> + <WarningLevel>Level4</WarningLevel> + <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> + <MultiProcessorCompilation>true</MultiProcessorCompilation> + <StringPooling>true</StringPooling> + <BufferSecurityCheck>false</BufferSecurityCheck> + </ClCompile> + <Link> + <AdditionalLibraryDirectories>$(SolutionDir)\Lib\x64;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> + <GenerateDebugInformation>true</GenerateDebugInformation> + <TargetMachine>MachineX64</TargetMachine> + <IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <Optimization>MaxSpeed</Optimization> + <IntrinsicFunctions>true</IntrinsicFunctions> + <WholeProgramOptimization>false</WholeProgramOptimization> + <AdditionalIncludeDirectories>$(SolutionDir)Include;$(SolutionDir)Lib/Include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> + <FunctionLevelLinking>true</FunctionLevelLinking> + <WarningLevel>Level4</WarningLevel> + <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> + <DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings> + <MultiProcessorCompilation>true</MultiProcessorCompilation> + <StringPooling>true</StringPooling> + <BufferSecurityCheck>false</BufferSecurityCheck> + </ClCompile> + <Link> + <AdditionalLibraryDirectories>$(SolutionDir)\Lib\x86;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> + <GenerateDebugInformation>true</GenerateDebugInformation> + <OptimizeReferences>true</OptimizeReferences> + <EnableCOMDATFolding>true</EnableCOMDATFolding> + <TargetMachine>MachineX86</TargetMachine> + <IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Midl> + <TargetEnvironment>X64</TargetEnvironment> + </Midl> + <ClCompile> + <Optimization>MaxSpeed</Optimization> + <IntrinsicFunctions>true</IntrinsicFunctions> + <WholeProgramOptimization>false</WholeProgramOptimization> + <AdditionalIncludeDirectories>$(SolutionDir)Lib/Include;$(SolutionDir)Include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> + <FunctionLevelLinking>true</FunctionLevelLinking> + <WarningLevel>Level4</WarningLevel> + <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> + <MultiProcessorCompilation>true</MultiProcessorCompilation> + <StringPooling>true</StringPooling> + <BufferSecurityCheck>false</BufferSecurityCheck> + </ClCompile> + <Link> + <AdditionalLibraryDirectories>$(SolutionDir)\Lib\x64;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> + <GenerateDebugInformation>true</GenerateDebugInformation> + <OptimizeReferences>true</OptimizeReferences> + <EnableCOMDATFolding>true</EnableCOMDATFolding> + <TargetMachine>MachineX64</TargetMachine> + <IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries> + </Link> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="Test-SST_Geo.cpp" /> + <ClCompile Include="Test-ZAllocWindow.cpp" /> + <ClCompile Include="Test-ZJSONReader.cpp" /> + <ClCompile Include="Test-ZJSONWriter.cpp" /> + <ClCompile Include="Test-ZRegistry.cpp" /> + <ClCompile Include="ZTestSuiteMain.cpp" /> + <ClCompile Include="Test-ZArray.cpp" /> + <ClCompile Include="Test-ZArrayAlgo.cpp" /> + <ClCompile Include="Test-ZBasicString.cpp" /> + <ClCompile Include="Test-ZBasicStringAlgo.cpp" /> + <ClCompile Include="Test-ZHashMap.cpp" /> + <ClCompile Include="Test-ZList.cpp" /> + <ClCompile Include="Test-ZListAlgo.cpp" /> + <ClCompile Include="Test-ZRingBuffer.cpp" /> + <ClCompile Include="Test-ZAlloc.cpp" /> + <ClCompile Include="Test-ZAssert.cpp" /> + <ClCompile Include="Test-ZConcurrency.cpp" /> + <ClCompile Include="Test-ZIniReader.cpp" /> + <ClCompile Include="Test-ZIniWriter.cpp" /> + <ClCompile Include="Test-ZName.cpp" /> + <ClCompile Include="Test-ZRandomGenerator.cpp" /> + <ClCompile Include="Test-ZReferenceCounter.cpp" /> + <ClCompile Include="Test-ZKVTree.cpp" /> + <ClCompile Include="Test-ZSimplexNoise.cpp" /> + <ClCompile Include="Test-ZSlabAllocator.cpp" /> + <ClCompile Include="Test-ZSmartPointer.cpp" /> + <ClCompile Include="Test-ZTaskStream.cpp" /> + <ClCompile Include="Test-ZWeakPointer.cpp" /> + <ClCompile Include="Test-ZXMLReader.cpp" /> + <ClCompile Include="Test-ZXMLWriter.cpp" /> + <ClCompile Include="Test-SST_Atomic.cpp" /> + <ClCompile Include="Test-SST_Endian.cpp" /> + <ClCompile Include="Test-SST_FileSys.cpp" /> + <ClCompile Include="Test-SST_SafeArithmetic.cpp" /> + <ClCompile Include="Test-SST_Mat22d.cpp" /> + <ClCompile Include="Test-SST_Mat22f.cpp" /> + <ClCompile Include="Test-SST_Mat22i.cpp" /> + <ClCompile Include="Test-SST_Mat22u.cpp" /> + <ClCompile Include="Test-SST_Mat33d.cpp" /> + <ClCompile Include="Test-SST_Mat33f.cpp" /> + <ClCompile Include="Test-SST_Mat33i.cpp" /> + <ClCompile Include="Test-SST_Mat33u.cpp" /> + <ClCompile Include="Test-SST_Mat44d.cpp" /> + <ClCompile Include="Test-SST_Mat44f.cpp" /> + <ClCompile Include="Test-SST_Mat44i.cpp" /> + <ClCompile Include="Test-SST_Mat44u.cpp" /> + <ClCompile Include="Test-SST_Transform.cpp" /> + <ClCompile Include="Test-SST_Vec2d.cpp" /> + <ClCompile Include="Test-SST_Vec2f.cpp" /> + <ClCompile Include="Test-SST_Vec2i.cpp" /> + <ClCompile Include="Test-SST_Vec2u.cpp" /> + <ClCompile Include="Test-SST_Vec3d.cpp" /> + <ClCompile Include="Test-SST_Vec3f.cpp" /> + <ClCompile Include="Test-SST_Vec3i.cpp" /> + <ClCompile Include="Test-SST_Vec3u.cpp" /> + <ClCompile Include="Test-SST_Vec4d.cpp" /> + <ClCompile Include="Test-SST_Vec4f.cpp" /> + <ClCompile Include="Test-SST_Vec4i.cpp" /> + <ClCompile Include="Test-SST_Vec4u.cpp" /> + <ClCompile Include="ZUnitTest.cpp" /> + </ItemGroup> + <ItemGroup> + <ClInclude Include="ZUnitTest.hpp" /> + </ItemGroup> + <ItemGroup> + <Xml Include="test1.xml" /> + <Xml Include="testAttributes.xml" /> + </ItemGroup> + <ItemGroup> + <Text Include="FileSystemTestDir\ZFileSystemTest-001.txt" /> + </ItemGroup> + <ItemGroup> + <None Include="FileSystemTestDir\ZFileSystemTest-002" /> + <None Include="FileSystemTestDir\ZFileSystemTest-7z.zep" /> + <None Include="FileSystemTestDir\ZFileSystemTest-ZIP.zep" /> + <None Include="FileSystemTestDir\ZRegistryTest1.ini" /> + <None Include="FileSystemTestDir\ZRegistryTest2.ini" /> + <None Include="FileSystemTestDir\initest\Test.ini" /> + <None Include="FileSystemTestDir\initest\TestFail1.ini" /> + <None Include="FileSystemTestDir\initest\TestFail2.ini" /> + <None Include="FileSystemTestDir\initest\TestFail3.ini" /> + <None Include="FileSystemTestDir\initest\TestFail4.ini" /> + </ItemGroup> + <ItemGroup> + <ProjectReference Include="..\libsst-atomic\libsst-atomic.vcxproj"> + <Project>{43ed481f-c4a3-40ed-81a3-46c43dc4eb1e}</Project> + </ProjectReference> + <ProjectReference Include="..\libsst-concurrency\libsst-concurrency.vcxproj"> + <Project>{7af55ff8-2f78-42ec-8a05-7fa1ae514814}</Project> + </ProjectReference> + <ProjectReference Include="..\libsst-crypto\libsst-crypto.vcxproj"> + <Project>{e5172b73-ab9a-4702-998f-84c841b30c02}</Project> + </ProjectReference> + <ProjectReference Include="..\libsst-math\libsst-math.vcxproj"> + <Project>{27b995c6-2b30-4852-b796-12e2b5883c35}</Project> + </ProjectReference> + <ProjectReference Include="..\libsst-net\libsst-net.vcxproj"> + <Project>{e6679a2f-6c8e-4555-9228-6929c734cef4}</Project> + </ProjectReference> + <ProjectReference Include="..\libsst-os\libsst-os.vcxproj"> + <Project>{4bac6d63-c2e8-43f7-87ea-ef953cbfddd3}</Project> + </ProjectReference> + <ProjectReference Include="..\libsst-random\libsst-random.vcxproj"> + <Project>{8aa34f81-4045-4613-88b7-6ff58d7e0a7a}</Project> + </ProjectReference> + <ProjectReference Include="..\ZUtil\ZUtil.vcxproj"> + <Project>{49e96a5c-ac79-412b-bbba-4653795d5edc}</Project> + </ProjectReference> + </ItemGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> + <ImportGroup Label="ExtensionTargets"> + </ImportGroup> +</Project> \ No newline at end of file diff --git a/ZTestSuite/ZTestSuite.vcxproj.filters b/ZTestSuite/ZTestSuite.vcxproj.filters new file mode 100644 index 0000000..49e2c1b --- /dev/null +++ b/ZTestSuite/ZTestSuite.vcxproj.filters @@ -0,0 +1,278 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup> + <Filter Include="Source Files"> + <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier> + <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions> + </Filter> + <Filter Include="Source Files\Tests"> + <UniqueIdentifier>{62e04273-c57a-404b-93fd-1db8a1604576}</UniqueIdentifier> + </Filter> + <Filter Include="Source Files\Tests\ZSTL Tests"> + <UniqueIdentifier>{bd5f3ccc-c160-42b0-ad39-f2165c097ed3}</UniqueIdentifier> + </Filter> + <Filter Include="Source Files\Tests\ZUtil Tests"> + <UniqueIdentifier>{63d59d62-c394-4fef-9648-e2d35a0f027b}</UniqueIdentifier> + </Filter> + <Filter Include="Source Files\Tests\SST Tests"> + <UniqueIdentifier>{8c6ffb10-acae-4d8d-b2e3-8ddfc4f94090}</UniqueIdentifier> + </Filter> + <Filter Include="Source Files\Tests\SST Math Tests"> + <UniqueIdentifier>{3fd58ac1-0756-4246-9c81-7504f74dde5b}</UniqueIdentifier> + </Filter> + <Filter Include="Source Files\Framework"> + <UniqueIdentifier>{1f6f98d2-0dfd-4e5b-9611-e2a46701e36f}</UniqueIdentifier> + </Filter> + <Filter Include="Header Files"> + <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier> + <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> + </Filter> + <Filter Include="Header Files\Framework"> + <UniqueIdentifier>{614820ad-b8f8-4f48-8757-2e29cbe12994}</UniqueIdentifier> + </Filter> + <Filter Include="Resource Files"> + <UniqueIdentifier>{0d1a9d45-7fe3-498a-a527-728deb8ce20c}</UniqueIdentifier> + </Filter> + <Filter Include="Resource Files\File System"> + <UniqueIdentifier>{6804028b-ba8e-4dbb-82cf-96465c190053}</UniqueIdentifier> + </Filter> + <Filter Include="Resource Files\Registry"> + <UniqueIdentifier>{1ce2fb63-9c03-43a6-94e8-a99471a02e48}</UniqueIdentifier> + </Filter> + <Filter Include="Resource Files\Ini Reader"> + <UniqueIdentifier>{4dc92dec-d5a5-4146-9a46-06ac4839bdcb}</UniqueIdentifier> + </Filter> + </ItemGroup> + <ItemGroup> + <ClCompile Include="ZTestSuiteMain.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="Test-ZArray.cpp"> + <Filter>Source Files\Tests\ZSTL Tests</Filter> + </ClCompile> + <ClCompile Include="Test-ZArrayAlgo.cpp"> + <Filter>Source Files\Tests\ZSTL Tests</Filter> + </ClCompile> + <ClCompile Include="Test-ZBasicString.cpp"> + <Filter>Source Files\Tests\ZSTL Tests</Filter> + </ClCompile> + <ClCompile Include="Test-ZBasicStringAlgo.cpp"> + <Filter>Source Files\Tests\ZSTL Tests</Filter> + </ClCompile> + <ClCompile Include="Test-ZHashMap.cpp"> + <Filter>Source Files\Tests\ZSTL Tests</Filter> + </ClCompile> + <ClCompile Include="Test-ZList.cpp"> + <Filter>Source Files\Tests\ZSTL Tests</Filter> + </ClCompile> + <ClCompile Include="Test-ZListAlgo.cpp"> + <Filter>Source Files\Tests\ZSTL Tests</Filter> + </ClCompile> + <ClCompile Include="Test-ZRingBuffer.cpp"> + <Filter>Source Files\Tests\ZSTL Tests</Filter> + </ClCompile> + <ClCompile Include="Test-ZAlloc.cpp"> + <Filter>Source Files\Tests\ZUtil Tests</Filter> + </ClCompile> + <ClCompile Include="Test-ZAssert.cpp"> + <Filter>Source Files\Tests\ZUtil Tests</Filter> + </ClCompile> + <ClCompile Include="Test-ZConcurrency.cpp"> + <Filter>Source Files\Tests\ZUtil Tests</Filter> + </ClCompile> + <ClCompile Include="Test-ZIniReader.cpp"> + <Filter>Source Files\Tests\ZUtil Tests</Filter> + </ClCompile> + <ClCompile Include="Test-ZIniWriter.cpp"> + <Filter>Source Files\Tests\ZUtil Tests</Filter> + </ClCompile> + <ClCompile Include="Test-ZName.cpp"> + <Filter>Source Files\Tests\ZUtil Tests</Filter> + </ClCompile> + <ClCompile Include="Test-ZRandomGenerator.cpp"> + <Filter>Source Files\Tests\ZUtil Tests</Filter> + </ClCompile> + <ClCompile Include="Test-ZReferenceCounter.cpp"> + <Filter>Source Files\Tests\ZUtil Tests</Filter> + </ClCompile> + <ClCompile Include="Test-ZSimplexNoise.cpp"> + <Filter>Source Files\Tests\ZUtil Tests</Filter> + </ClCompile> + <ClCompile Include="Test-ZSlabAllocator.cpp"> + <Filter>Source Files\Tests\ZUtil Tests</Filter> + </ClCompile> + <ClCompile Include="Test-ZSmartPointer.cpp"> + <Filter>Source Files\Tests\ZUtil Tests</Filter> + </ClCompile> + <ClCompile Include="Test-ZTaskStream.cpp"> + <Filter>Source Files\Tests\ZUtil Tests</Filter> + </ClCompile> + <ClCompile Include="Test-ZWeakPointer.cpp"> + <Filter>Source Files\Tests\ZUtil Tests</Filter> + </ClCompile> + <ClCompile Include="Test-ZXMLReader.cpp"> + <Filter>Source Files\Tests\ZUtil Tests</Filter> + </ClCompile> + <ClCompile Include="Test-ZXMLWriter.cpp"> + <Filter>Source Files\Tests\ZUtil Tests</Filter> + </ClCompile> + <ClCompile Include="Test-SST_Atomic.cpp"> + <Filter>Source Files\Tests\SST Tests</Filter> + </ClCompile> + <ClCompile Include="Test-SST_Endian.cpp"> + <Filter>Source Files\Tests\SST Tests</Filter> + </ClCompile> + <ClCompile Include="Test-SST_FileSys.cpp"> + <Filter>Source Files\Tests\SST Tests</Filter> + </ClCompile> + <ClCompile Include="Test-SST_SafeArithmetic.cpp"> + <Filter>Source Files\Tests\SST Tests</Filter> + </ClCompile> + <ClCompile Include="Test-SST_Mat22d.cpp"> + <Filter>Source Files\Tests\SST Math Tests</Filter> + </ClCompile> + <ClCompile Include="Test-SST_Mat22f.cpp"> + <Filter>Source Files\Tests\SST Math Tests</Filter> + </ClCompile> + <ClCompile Include="Test-SST_Mat22i.cpp"> + <Filter>Source Files\Tests\SST Math Tests</Filter> + </ClCompile> + <ClCompile Include="Test-SST_Mat22u.cpp"> + <Filter>Source Files\Tests\SST Math Tests</Filter> + </ClCompile> + <ClCompile Include="Test-SST_Mat33d.cpp"> + <Filter>Source Files\Tests\SST Math Tests</Filter> + </ClCompile> + <ClCompile Include="Test-SST_Mat33f.cpp"> + <Filter>Source Files\Tests\SST Math Tests</Filter> + </ClCompile> + <ClCompile Include="Test-SST_Mat33i.cpp"> + <Filter>Source Files\Tests\SST Math Tests</Filter> + </ClCompile> + <ClCompile Include="Test-SST_Mat33u.cpp"> + <Filter>Source Files\Tests\SST Math Tests</Filter> + </ClCompile> + <ClCompile Include="Test-SST_Mat44d.cpp"> + <Filter>Source Files\Tests\SST Math Tests</Filter> + </ClCompile> + <ClCompile Include="Test-SST_Mat44f.cpp"> + <Filter>Source Files\Tests\SST Math Tests</Filter> + </ClCompile> + <ClCompile Include="Test-SST_Mat44i.cpp"> + <Filter>Source Files\Tests\SST Math Tests</Filter> + </ClCompile> + <ClCompile Include="Test-SST_Mat44u.cpp"> + <Filter>Source Files\Tests\SST Math Tests</Filter> + </ClCompile> + <ClCompile Include="Test-SST_Transform.cpp"> + <Filter>Source Files\Tests\SST Math Tests</Filter> + </ClCompile> + <ClCompile Include="Test-SST_Vec2d.cpp"> + <Filter>Source Files\Tests\SST Math Tests</Filter> + </ClCompile> + <ClCompile Include="Test-SST_Vec2f.cpp"> + <Filter>Source Files\Tests\SST Math Tests</Filter> + </ClCompile> + <ClCompile Include="Test-SST_Vec2i.cpp"> + <Filter>Source Files\Tests\SST Math Tests</Filter> + </ClCompile> + <ClCompile Include="Test-SST_Vec2u.cpp"> + <Filter>Source Files\Tests\SST Math Tests</Filter> + </ClCompile> + <ClCompile Include="Test-SST_Vec3d.cpp"> + <Filter>Source Files\Tests\SST Math Tests</Filter> + </ClCompile> + <ClCompile Include="Test-SST_Vec3f.cpp"> + <Filter>Source Files\Tests\SST Math Tests</Filter> + </ClCompile> + <ClCompile Include="Test-SST_Vec3i.cpp"> + <Filter>Source Files\Tests\SST Math Tests</Filter> + </ClCompile> + <ClCompile Include="Test-SST_Vec3u.cpp"> + <Filter>Source Files\Tests\SST Math Tests</Filter> + </ClCompile> + <ClCompile Include="Test-SST_Vec4d.cpp"> + <Filter>Source Files\Tests\SST Math Tests</Filter> + </ClCompile> + <ClCompile Include="Test-SST_Vec4f.cpp"> + <Filter>Source Files\Tests\SST Math Tests</Filter> + </ClCompile> + <ClCompile Include="Test-SST_Vec4i.cpp"> + <Filter>Source Files\Tests\SST Math Tests</Filter> + </ClCompile> + <ClCompile Include="Test-SST_Vec4u.cpp"> + <Filter>Source Files\Tests\SST Math Tests</Filter> + </ClCompile> + <ClCompile Include="ZUnitTest.cpp"> + <Filter>Source Files\Framework</Filter> + </ClCompile> + <ClCompile Include="Test-ZKVTree.cpp"> + <Filter>Source Files\Tests\ZUtil Tests</Filter> + </ClCompile> + <ClCompile Include="Test-ZRegistry.cpp"> + <Filter>Source Files\Tests\ZUtil Tests</Filter> + </ClCompile> + <ClCompile Include="Test-SST_Geo.cpp"> + <Filter>Source Files\Tests\SST Math Tests</Filter> + </ClCompile> + <ClCompile Include="Test-ZAllocWindow.cpp"> + <Filter>Source Files\Tests\ZUtil Tests</Filter> + </ClCompile> + <ClCompile Include="Test-ZJSONReader.cpp"> + <Filter>Source Files\Tests\ZUtil Tests</Filter> + </ClCompile> + <ClCompile Include="Test-ZJSONWriter.cpp"> + <Filter>Source Files\Tests\ZUtil Tests</Filter> + </ClCompile> + </ItemGroup> + <ItemGroup> + <ClInclude Include="ZUnitTest.hpp"> + <Filter>Header Files\Framework</Filter> + </ClInclude> + </ItemGroup> + <ItemGroup> + <Xml Include="test1.xml"> + <Filter>Resource Files</Filter> + </Xml> + <Xml Include="testAttributes.xml"> + <Filter>Resource Files</Filter> + </Xml> + </ItemGroup> + <ItemGroup> + <Text Include="FileSystemTestDir\ZFileSystemTest-001.txt"> + <Filter>Resource Files\File System</Filter> + </Text> + </ItemGroup> + <ItemGroup> + <None Include="FileSystemTestDir\ZFileSystemTest-002"> + <Filter>Resource Files\File System</Filter> + </None> + <None Include="FileSystemTestDir\ZFileSystemTest-7z.zep"> + <Filter>Resource Files\File System</Filter> + </None> + <None Include="FileSystemTestDir\ZFileSystemTest-ZIP.zep"> + <Filter>Resource Files\File System</Filter> + </None> + <None Include="FileSystemTestDir\ZRegistryTest1.ini"> + <Filter>Resource Files\Registry</Filter> + </None> + <None Include="FileSystemTestDir\ZRegistryTest2.ini"> + <Filter>Resource Files\Registry</Filter> + </None> + <None Include="FileSystemTestDir\initest\Test.ini"> + <Filter>Resource Files\Ini Reader</Filter> + </None> + <None Include="FileSystemTestDir\initest\TestFail1.ini"> + <Filter>Resource Files\Ini Reader</Filter> + </None> + <None Include="FileSystemTestDir\initest\TestFail2.ini"> + <Filter>Resource Files\Ini Reader</Filter> + </None> + <None Include="FileSystemTestDir\initest\TestFail3.ini"> + <Filter>Resource Files\Ini Reader</Filter> + </None> + <None Include="FileSystemTestDir\initest\TestFail4.ini"> + <Filter>Resource Files\Ini Reader</Filter> + </None> + </ItemGroup> +</Project> \ No newline at end of file diff --git a/ZTestSuite/ZTestSuiteMain.cpp b/ZTestSuite/ZTestSuiteMain.cpp new file mode 100644 index 0000000..52f7c3a --- /dev/null +++ b/ZTestSuite/ZTestSuiteMain.cpp @@ -0,0 +1,320 @@ +#include "ZUnitTest.hpp" + +#include <stdlib.h> //for NULL +#include <string.h> //strcmp +#include <stdio.h> //for printf + +#include <ZUtil/ZAlloc.hpp> //for ZENGINE_MEM_DUMP_LEAKS +#include <SST/SST_OS.h> +extern ZUnitTestBlock SST_SafeArithmeticTests; +extern ZUnitTestBlock SST_AtomicTests; +extern ZUnitTestBlock SST_EndianTests; +extern ZUnitTestBlock SST_FileSysTests; + +extern ZUnitTestBlock ZArrayTests; +extern ZUnitTestBlock ZArrayAlgoTests; +extern ZUnitTestBlock ZListTests; +extern ZUnitTestBlock ZListAlgoTests; +extern ZUnitTestBlock ZRingBufferTests; +extern ZUnitTestBlock ZBasicStringTests; +extern ZUnitTestBlock ZBasicStringAlgoTests; +extern ZUnitTestBlock ZHashMapTests; + +extern ZUnitTestBlock ZAssertTests; +extern ZUnitTestBlock ZAllocTests; +extern ZUnitTestBlock ZConcurrencyTests; + +extern ZUnitTestBlock ZNameTests; +extern ZUnitTestBlock ZReferenceCounterTests; +extern ZUnitTestBlock ZSmartPointerTests; +extern ZUnitTestBlock ZWeakPointerTests; +extern ZUnitTestBlock ZSlabAllocatorTests; + +extern ZUnitTestBlock ZRandomGeneratorTests; +extern ZUnitTestBlock ZSimplexNoiseTests; +extern ZUnitTestBlock ZTaskStreamTests; + +extern ZUnitTestBlock ZKVTreeTests; +extern ZUnitTestBlock ZIniReaderTests; +extern ZUnitTestBlock ZIniWriterTests; +extern ZUnitTestBlock ZJSONReaderTests; +extern ZUnitTestBlock ZJSONWriterTests; +extern ZUnitTestBlock ZXMLReaderTests; +extern ZUnitTestBlock ZXMLWriterTests; +extern ZUnitTestBlock ZRegistryTests; +extern ZUnitTestBlock ZAllocWindowTests; + +extern ZUnitTestBlock SST_Math_Mat22fTests; +extern ZUnitTestBlock SST_Math_Mat22dTests; +extern ZUnitTestBlock SST_Math_Mat22iTests; +extern ZUnitTestBlock SST_Math_Mat22uTests; +extern ZUnitTestBlock SST_Math_Mat33fTests; +extern ZUnitTestBlock SST_Math_Mat33dTests; +extern ZUnitTestBlock SST_Math_Mat33iTests; +extern ZUnitTestBlock SST_Math_Mat33uTests; +extern ZUnitTestBlock SST_Math_Mat44fTests; +extern ZUnitTestBlock SST_Math_Mat44dTests; +extern ZUnitTestBlock SST_Math_Mat44iTests; +extern ZUnitTestBlock SST_Math_Mat44uTests; + +extern ZUnitTestBlock SST_Math_Vec2fTests; +extern ZUnitTestBlock SST_Math_Vec2dTests; +extern ZUnitTestBlock SST_Math_Vec2iTests; +extern ZUnitTestBlock SST_Math_Vec2uTests; +extern ZUnitTestBlock SST_Math_Vec3fTests; +extern ZUnitTestBlock SST_Math_Vec3dTests; +extern ZUnitTestBlock SST_Math_Vec3iTests; +extern ZUnitTestBlock SST_Math_Vec3uTests; +extern ZUnitTestBlock SST_Math_Vec4fTests; +extern ZUnitTestBlock SST_Math_Vec4dTests; +extern ZUnitTestBlock SST_Math_Vec4iTests; +extern ZUnitTestBlock SST_Math_Vec4uTests; +extern ZUnitTestBlock SST_Math_TransformTests; +extern ZUnitTestBlock SST_Math_GeoTests; + +static ZUnitTestBlock* g_tests [] = +{ + &SST_SafeArithmeticTests, + &SST_AtomicTests, + &SST_EndianTests, + &SST_FileSysTests, + + &SST_Math_Mat22fTests, + &SST_Math_Mat22dTests, + &SST_Math_Mat22iTests, + &SST_Math_Mat22uTests, + &SST_Math_Mat33fTests, + &SST_Math_Mat33dTests, + &SST_Math_Mat33iTests, + &SST_Math_Mat33uTests, + &SST_Math_Mat44fTests, + &SST_Math_Mat44dTests, + &SST_Math_Mat44iTests, + &SST_Math_Mat44uTests, + + &SST_Math_Vec2fTests, + &SST_Math_Vec2dTests, + &SST_Math_Vec2iTests, + &SST_Math_Vec2uTests, + &SST_Math_Vec3fTests, + &SST_Math_Vec3dTests, + &SST_Math_Vec3iTests, + &SST_Math_Vec3uTests, + &SST_Math_Vec4fTests, + &SST_Math_Vec4dTests, + &SST_Math_Vec4iTests, + &SST_Math_Vec4uTests, + &SST_Math_TransformTests, + &SST_Math_GeoTests, + + &ZArrayTests, + &ZArrayAlgoTests, + &ZListTests, + &ZListAlgoTests, + &ZRingBufferTests, + &ZBasicStringTests, + &ZBasicStringAlgoTests, + &ZHashMapTests, + + &ZAssertTests, + &ZAllocTests, + &ZConcurrencyTests, + + &ZNameTests, + &ZReferenceCounterTests, + &ZSmartPointerTests, + &ZWeakPointerTests, + &ZSlabAllocatorTests, + + &ZRandomGeneratorTests, + &ZSimplexNoiseTests, + &ZTaskStreamTests, + + &ZKVTreeTests, + &ZIniReaderTests, + &ZIniWriterTests, + &ZJSONReaderTests, + &ZJSONWriterTests, + &ZXMLReaderTests, + &ZXMLWriterTests, + &ZRegistryTests, + &ZAllocWindowTests, + +}; + +static size_t g_numtests = sizeof(g_tests)/sizeof(g_tests[0]); + +/*************************************************************************/ + +const char* g_assert_message = NULL; +bool g_assert_triggered = false; + +int ZTEST_HandleAssert(const char* _msg, void* _arg) +{ + (void)_arg; + + g_assert_triggered = true; + g_assert_message = _msg; + + return 1; +} + +void ZTEST_BeginHandleAssert() +{ + SST_OS_SetRuntimeAssertHandler(ZTEST_HandleAssert, NULL); +} + +bool ZTEST_CheckAssert() +{ + bool result = g_assert_triggered; + + g_assert_triggered = false; + + return result; +} + +void ZTEST_EndHandleAssert() +{ + SST_OS_SetRuntimeAssertHandler(NULL, NULL); +} + +/*************************************************************************/ + +static bool doFullTestRun() +{ + bool success = true; + for (size_t i = 0; i < g_numtests; i++) + success &= RunUnitTests(g_tests[i]); + return success; +} + +/*************************************************************************/ + +int main(int argc, char **argv) +{ + //Make sure we set these values + ZUnitTestGlobals::ARGC = argc; + ZUnitTestGlobals::ARGV = argv; + + if(SST_OS_Init() == 0) + { + printf("Failed to initialize OS library, exiting.\n"); + exit(0xff); + } + + //Check our input arguments for test conditions + for(size_t i=1; i<(size_t)argc; i++) + { + if(!strcmp(argv[i], "-n")) + ZUnitTestGlobals::NonInteractive = 1; + else if(!strcmp(argv[i], "-c")) + { + printf("%lu\n", g_numtests); + exit(0); + } + else if(!strcmp(argv[i], "-r")) //Run a specific test + { + if(i == (size_t)argc-1) + { + printf("Invalid usage of -r"); + exit(1); + } + + ZUnitTestGlobals::TestNumber = atoi(argv[i+1]); + + if(ZUnitTestGlobals::TestNumber >= (int)g_numtests) + { + printf("Invalid test number \"%s\"\n", + argv[i+1]); + exit(1); + } + ZUnitTestGlobals::NonInteractive = 1; + + // Skip already parsed arg. + i++; + } + else if(!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) + { + printf( + "-h : help (this screen)\n" + "-n : non-interactive (don't wait for keys)\n" + "-r <N> : run test number <N>" + "-c : print number of tests available\n"); + exit(0); + } + else + { + printf("ERROR: Option \"%s\" not recognized", argv[1]); + exit(1); + } + } + + if(ZUnitTestGlobals::TestNumber >= 0) + { + return (RunUnitTests(g_tests[ZUnitTestGlobals::TestNumber]) ? 0 : 1); + } + + bool success = true; + if (ZUnitTestGlobals::NonInteractive == 1) + success = doFullTestRun(); + else + { + char inputbuff[512]; + for(;;) + { + printf("===============\nAVAILABLE TESTS\n===============\n"); + for (size_t i = 0; i < g_numtests; i++) + printf("%lu. %s\n",i+1,g_tests[i]->blockName); + printf("(q to quit)\n"); + printf("(0 for all tests)\n"); + memset(inputbuff,0,512); + fgets(inputbuff,512,stdin); + inputbuff[511] = '\0'; + + if (inputbuff[0]=='q') + break; + + int selection = atoi(inputbuff); + if (selection < 0 || selection > (int)g_numtests) + continue; + else if (selection == 0) + { + success &= doFullTestRun(); + printf("\nPress ENTER to continue...\n"); + fgetc(stdin); + } + else + { + success &= RunUnitTests(g_tests[selection-1]); + printf("\nPress ENTER to continue...\n"); + fgetc(stdin); + } + } + } + + /***********************/ + /* End Unit Tests Here */ + /***********************/ + + if (success) + printf("**************\nALL TESTS SUCCESSFUL!\n**************\n\n"); + else + printf("**************\nWARNING! SOME TESTS FAILED!\n**************\n\n"); + + ZALLOC_MEM_DUMP_LEAKS(NULL); + + if (g_assert_triggered) + printf("WARNING: Unit tests completed with assert flag tripped!\n\nMESSAGE: %s\n\n", g_assert_message); + + if(!ZUnitTestGlobals::NonInteractive) + { + printf("\nPress ENTER to continue...\n"); + fflush(stdout); + fgetc(stdin); + } + + if (success) + exit(0); + else + exit(1); +} diff --git a/ZTestSuite/ZUnitTest.cpp b/ZTestSuite/ZUnitTest.cpp new file mode 100644 index 0000000..17025d6 --- /dev/null +++ b/ZTestSuite/ZUnitTest.cpp @@ -0,0 +1,57 @@ +/* + ZUnitTest.cpp + Author: Patrick Baggett + + Purpose : Code for automated ZUnitTest running + + Changelog : + 12/18/2011 - Removed dependency on ZString (crertel) + 02/19/2011 - Added 'wait' after failed test (jcrussell) + 12/15/2010 - Created (ptbaggett) +*/ + +#include "ZUnitTest.hpp" + +#include <stdio.h> +#include <string.h> + +//Set our namespace globals +int ZUnitTestGlobals::ARGC = 0; +char** ZUnitTestGlobals::ARGV = NULL; +int ZUnitTestGlobals::NonInteractive = 0; +int ZUnitTestGlobals::TestNumber = -1; + +//This function runs a block of unit tests, returning true if they succeed +bool RunUnitTests(ZUnitTestBlock* block) +{ + bool passedAllTests = true; + + printf("*** BEGINNING TEST BLOCK FOR \"%s\" ***\n\n", block->blockName); + for(int i=0; i<block->nrTests; i++) + { + const char* result; + printf("Test %2d/%2d - %s: ", i+1, block->nrTests, block->tests[i].testName); + fflush(stdout); + result = block->tests[i].testFunc(); + if( strcmp(result, ZTEST_SUCCESS) != 0) + { + printf("FAIL.\n -> Error message: %s\n", result); + passedAllTests = false; + } + else + printf("PASS.\n"); + } + printf("\n*** OVERALL RESULT FOR \"%s\": %s ***\n\n", block->blockName, passedAllTests ? "PASS" : "FAIL"); + + if (!passedAllTests) + { + if(!ZUnitTestGlobals::NonInteractive) + { + printf("Press ENTER to keep running tests...\n"); + fflush(stdout); + fgetc(stdin); + } + } + + return passedAllTests; +} diff --git a/ZTestSuite/ZUnitTest.hpp b/ZTestSuite/ZUnitTest.hpp new file mode 100644 index 0000000..86f6ae9 --- /dev/null +++ b/ZTestSuite/ZUnitTest.hpp @@ -0,0 +1,76 @@ +/* + ZUnitTest.hpp + Author: Patrick Baggett + + Purpose : Header for ZUnitTest type and associated functions + Ignore the ugly C preprocessor hacks. They only make repetitive things + less repetitive. + + Changelog : + 12/18/2011 - Removed dependency on ZString (crertel) + 12/15/2010 - Created (ptbaggett) +*/ + +#pragma once + +#ifndef _ZUNITTEST_H +#define _ZUNITTEST_H + +#include <stdio.h> //for printf (among other things) + +#include <SST/SST_Assert.h> //for SST_OS_SetRuntimeAssertHandler + +//Global flags used during the unit tests +namespace ZUnitTestGlobals +{ + extern int ARGC; //The argument count provided to main() + extern char **ARGV; //The argument values provided to main() + extern int NonInteractive; //Flag indicating this is a non-interactive run + extern int TestNumber; //Test number to run +}; + +//Our unit test structure, which details a single unit test +typedef struct ZUnitTest +{ + const char* testName; //Name of the test + const char* (*testFunc)(); //Function that should be called +} ZUnitTest; + +//Unit test block structure, which details a set of ZUnitTests +typedef struct ZUnitTestBlock +{ + ZUnitTest* tests; //Array of tests + const char* blockName; //The name of this test block + int nrTests; //Number of tests +} ZUnitTestBlock; + +//Declares a ZUnitTestBlock given a data type name. Ensures ZUnitTestBlocks have consistent names for use in TestMain.cpp +#define DECLARE_ZTESTBLOCK(Type) ZUnitTestBlock Type##Tests = { Type##UnitTests, #Type, sizeof(Type##UnitTests) / sizeof(ZUnitTest) }; + +//This value is returned by a single ZUnitTest function to indicate success (anything else indicates failure) +#define ZTEST_SUCCESS "" + +//Tests a condition, and returns a string if the test condition is false +#define TASSERT(condition, msg) if (!(condition)) { return msg; } + +//Test assertion failure +#define TASSERT_FAIL(msg) { return msg; } + +//Runs a unit test block, returns true if and only if all tests are successful +bool RunUnitTests(ZUnitTestBlock* block); + +/*************************************************************************/ + +extern const char* g_assert_message; +extern bool g_assert_triggered; + +extern int ZTEST_HandleAssert(const char* _msg, void* _arg); + +//The following methods can be used by test methods to cause an assert to trip the g_assert_triggered flag, check the flag, and then reset +extern void ZTEST_BeginHandleAssert(); +extern bool ZTEST_CheckAssert(); +extern void ZTEST_EndHandleAssert(); + +/*************************************************************************/ + +#endif diff --git a/ZTestSuite/obj/x86-64/release/Test-SST_Atomic.o b/ZTestSuite/obj/x86-64/release/Test-SST_Atomic.o new file mode 100644 index 0000000000000000000000000000000000000000..e3fb932ce4c938a12b7aaef95e86cf6d54b58bb1 GIT binary patch literal 14432 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%0A_V0np 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 S9;CAZq?mz$As$T<-F^V+>PmP3 literal 0 HcmV?d00001 diff --git a/ZTestSuite/obj/x86-64/release/Test-SST_Endian.o b/ZTestSuite/obj/x86-64/release/Test-SST_Endian.o new file mode 100644 index 0000000000000000000000000000000000000000..926f9bd55e048b91e298e6eff7e1470573337c2d GIT binary patch literal 5512 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 F002wm(t!W~ literal 0 HcmV?d00001 diff --git a/ZTestSuite/obj/x86-64/release/Test-SST_FileSys.o b/ZTestSuite/obj/x86-64/release/Test-SST_FileSys.o new file mode 100644 index 0000000000000000000000000000000000000000..70e497585639a72025b26ab47db87d1c6aa18e23 GIT binary patch literal 7168 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 literal 0 HcmV?d00001 diff --git a/ZTestSuite/obj/x86-64/release/Test-SST_SafeArithmetic.o b/ZTestSuite/obj/x86-64/release/Test-SST_SafeArithmetic.o new file mode 100644 index 0000000000000000000000000000000000000000..aec7fa8dbb97210c9e5603c8e2011843b22a3740 GIT binary patch literal 17184 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 literal 0 HcmV?d00001 diff --git a/ZTestSuite/obj/x86-64/release/Test-ZAlloc.o b/ZTestSuite/obj/x86-64/release/Test-ZAlloc.o new file mode 100644 index 0000000000000000000000000000000000000000..d3fc84aaedabdbaded5b2eb77eb5cbacbcb3bdfc GIT binary patch literal 7840 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 literal 0 HcmV?d00001 diff --git a/ZTestSuite/obj/x86-64/release/Test-ZAllocWindow.o b/ZTestSuite/obj/x86-64/release/Test-ZAllocWindow.o new file mode 100644 index 0000000000000000000000000000000000000000..5490ec88c54bd816d687d9d97513caccb6ca0e6b GIT binary patch literal 9904 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 literal 0 HcmV?d00001 diff --git a/ZTestSuite/obj/x86-64/release/Test-ZArray.o b/ZTestSuite/obj/x86-64/release/Test-ZArray.o new file mode 100644 index 0000000000000000000000000000000000000000..c566ef8dde2a83e32e8744f74f042f51df880206 GIT binary patch literal 114736 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 msGK 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 DLSzJC literal 0 HcmV?d00001 diff --git a/ZTestSuite/obj/x86-64/release/Test-ZArrayAlgo.o b/ZTestSuite/obj/x86-64/release/Test-ZArrayAlgo.o new file mode 100644 index 0000000000000000000000000000000000000000..599adc3f240808b2a96cc78ec26b00ebb96d6bcf GIT binary patch literal 394272 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 Bz-Ise literal 0 HcmV?d00001 diff --git a/ZTestSuite/obj/x86-64/release/Test-ZAssert.o b/ZTestSuite/obj/x86-64/release/Test-ZAssert.o new file mode 100644 index 0000000000000000000000000000000000000000..a31b5979fdd5e5a7306a06b9ff1921e8abed60a3 GIT binary patch literal 3304 zcmb<-^>JfjWMqH=Mg}_u1P><4z>vX-U^{@B4h(z@+zg=}oliZQ-w1eg*8cG5EdAio z?fT(3gC#2igGaaP50B1c`$39#fQT0$Vh70ZlZUZuOJyWdTZ%_Fi>d|#1A|AW>kq>N z$6detVq#$M=ym-9vk`2W<4$7+1_np4?K?rX?*b9~Km^!XU`5@oUu;3{Enx?%dmW9% z7&GFG0l6P$j0l=FV8cDSLw}@r7>j`2Ucw5t|Kwqidx*uL;6qj$RGL?knVYJRSX`W1 zRKgJD2%#aALP<tZetDjif@(1r15_w2F*7GM1tJuZT3n(F)uNYNPyka?l3HA%$HkDA zm{XhzwX7_$NTEEjSRpUJM4>3PIJHC}sS;{wW`3SRMq*w{PHGW~EecR$z$OsT4{}v$ zQ7RW$Ei#dupI2O>kercNqy;t)>R*UwG&C6)+?}1R6f{DUO7lue6-@O^^bB;(O2ItC zIzux(0~0+nO^CRHk%6I^fti6N$b1nH!N9=4SQW&;SRueD&BM+yfsuhhh5>>>(&iw- zkx!tF$(fg}h=-j6DrW-{XJBB!B_9KozXqaV`k5|53;>B?!Jv3$VfgqTixdMh)*Q*e zz|6pmO*sQI11k=3HVkng1_lNu21bTFs0`T63=9lfP;sa*#IK-S02K%O9To-*3=Gkr zuw-CkcmUO)0Hr|`GXp5(KrB?u%z#v=AW1PZup{vx%q|8720<kM3P6MzW<$kcd<m%d z3I+xSm>5(DOs&Tueh!EDa~$Ff7<nf?%E!<gl;ly8Xc+@Y+z66CAgMOMJ2?O%Y?_;x zhfM~%Nv?*L@$msct|1|j@ou4h&LN)ue(~|JEFYSeSpsrXF-!o$DJaU!D@kJr4i1U; z4~`E`EkSXe2PE6Vq*3HNa|?19;^T`;5|gvzlQXj8L3xxx2^@+H44|9}N@e0uz7CXT zVqjq4XJBCX^B)2tq2e(0pmYTiN(K?&w1ldD3RE1V9%L4j%P<ql0EvO(6=wcYs5nSH z$UU(1w+c<%7Rm?3KZpra?+4;AFfeR^(lBvY9tM}<P<IL<`Rgp2`V1)lHk1aL19B@Y zpTOJ&5<_<X8zl9}?*E7;4s-uEH1P>g{%<G^vKM5|Vkn;#RIp%izX((urXG}EKw4Cx z;^^+wf{Me`!_2pXii6aH$`V+-fXo76kTl3WAT|iYN&=8LNDr*s0fh-j9wg2SVn8u0 zKZC?U=77=`ND5ZIfXo14kQfL<+9sef4T53ep8%4Ch66}F%w7h);>z5T#3Tm2;*uf= zodIJNrRF5+m84dbFzA7qDTyVC40=h$#SD5y`4CQWer|4RUI~L<UVcfcp1WVDE;zqH zHKb<5rxhjU!s<|{6Ud@K{sn~rdI=8muM0>L$z(JxgERvJ0}BHK157<ksR7hL4N#yk zFfj0d%W(#Hi46;XZKybUjRUGPL1uv(V;~xaVetv$tKqOe0-7LT@dL6SWCv830cO7; z1H?@rIhdIs8r+@)G0-r&|3NJ{kQmgPaMcGuf*>A@2C*3!7(n3-Wr8U?sQ(SXJOpt7 zYM?1X2+V>R2czAg`oWS?(Bq1;prVq?vU|;~1M<6kD<v*YT6)=TR8Ww&~E<-qu z@ZSMd=mAv-3V%?o3>AilKd9_O4|}i{kYWY~hBPn-L4e$f;4y$(Fi@u=3o{fz4Lt$X f0LuFyjBY>38mLkf{T84?fq{YH2Z|`fK4c*P{LHdQ literal 0 HcmV?d00001 diff --git a/ZTestSuite/obj/x86-64/release/Test-ZBasicString.o b/ZTestSuite/obj/x86-64/release/Test-ZBasicString.o new file mode 100644 index 0000000000000000000000000000000000000000..8c95fb4409c247828099618369f2ca7e3133bb9c GIT binary patch literal 133416 zcmb<-^>JfjWMqH=Mg}_u1P><4!0=)|Lev2)?7*;;aS>SO6b1&co@r2eCX}8HrRPHF z`A~WxlwJ&_mqO{~P<kblUJa$!Lh1ETdLxwH45hb1>FrQ@2bA6grT0MTeNg%Uls*Kd zk3i{TQ2GRvJ_V)EK<RT(`T~@`1f{P)>1$B>29&-9rSCxLdr<lTlzs%IpFrtnQ2GUw zeg&o9K<Rf-`U8~y1f{<~>2FZ_2bBH=rT;+be^B~Alm<l}C{~#nA@RowrP-l0CzR%f z(!5ZbA4&^CX<;ZW0;NTvv^bQOgwoPbS_VqXL1}p?tq7%+p|mQLR)^A>P+A*G>p*Ee zC~W|xji9s%ls1FX7Esy>O4~qbJ1Fe{rJbO(3zT+)(jHLS3rc%KX<sPq52XX3bP$vd zhSH%>It)rjK<P**9Sx;ppmZ#hj)&3-P&x@pCqwB}D4hnSGoW-9l+J<Dc~H6lN*6)t z5-42;r7NIx6_l=l(sfX}0ZKPP=@uy62BkZobQhHFfzo|Yx*tkUgwm6s^b{yP4NA{| z(z6&D7(zWdp9Xt0zKLLFU`X-kW>M8(U|{g*bbVoXz~gx9f<OO3iJHOVc<Txnv$yra zpa1_oI*)_06N5+hRFEQ%-qwP@Akk|G39xRDUJq7}-d2Hs|Nrk|2OE73uA+A;SWj>3 zhJR>Ur-E$r=xyBqwh3Wo?^LizZ)?DRR2`^};@`&5a-dYp168#717pj9QV}#!kJbYv z>^nf&^))M~fMaMmP{OqvR1&}BWMW`|dkpH`&O;vE5RY{p^XR+|4ujSMr5b4JS`L(o zq6v94{}94u6Q~k^h7v4vK!qv;j03d+6pAn*s13+M9?d`4aoJ$Y2=)skqzU^4Ssm0S zWFdThxeSVBSkxig1ddaTPy<IOG%>+!0>?U3Yx56r3_r1h<L7mb2P`2#)q*1jyETvm z15pRH23g1hk2S1d+tBSo^C2t|Lu^2cOZ1e0nl3#$Z+LY3zDV&f<^ktE{+4bA28Nf7 zpm6LwjArj^W)H9!a<IY0z}X1m0+<+b`hbana~(9uVPYtGy7LAsm4VZ@N8=Gt@emz* z7*<-WV8ARbAaQ|`Y|-5A(Rm0ef~u<Z0RPkjEeA@V(P|4-1akwDHc&Q&3pf8@MA3&m zp3nlfMCG+CBm_~SAJfMmFG76`E*2>FJS1We{*1uzCqxCf^g{8O9uAcr%|F;s6ygqo zP*D030jDo=f&f%SfI<YliohM|C{fJ6jlsqc;!<eY3TmrDeYFocRzWI_AS$8Bp$evq z37jF|VPs>BqAVDuj2TUt35qfum@*bLWu_>~Xc~|&7_sFZP)<b&G*JEb@Be>vF_d%* zsaauJ0u*?uDE^2>D~XOVD58mg^eCd}QHNTLY$`PJpizQ7bnq8}pnQm&2z_3=V&+3w zX@p$Yz{Eh|19K9n$b=SPuo4OssL=cx?9u$j10$unZa@o3*9~yvnt!mO1Od#0NJ`M% zulQOD?0!@wD2{4A;sJM2;~Ubl4^F3rK@%`s0VE5;xoCwcC^A7Q2F35-mJqDCh4~fQ zrh?=zPylx$M;95zCh27c+!N^W5e4=1J^`d$3l)QFLi4#Ax_t8w0j!Zs6OV)Xy68#p zc&ovGczfCc!E`_{Jzz{otfIu4NB2~aO1QV+&EoGD4!)2_G+P@$VbnbpWC5mHv_J~? z=$;C46jp`vkSb+8kM5};$6-}C1xX?9<b>43A-W0z1tU@(I)SB^(%WkA2eXs}wP#R6 z57I+H7Xy_l=whJK2VD#!4|%|QFCZz8PF%6E1{52;Q$g;*8g}58542JQ$6W7JkbkhM zMUIegkKU;u$75B993grhy;DIxBB&61%;7K9A%P0df@lp}NYub(K}9H1A|S4vOQkj~ ztQG->Ewq#d6>?A}tQG+!Fr@TGW|`f3fFC&q4B<f!DO^#~7FveH9toh3qe5v6YRIA& zO4tgT<E@~A2Gj@kINl1%^<XBh0szsX)xlXr5n1CPr4FKt2#}|cq72jy!1N<1r=SEo zw2gx<2FlB5VmNXcvafMvFd}@7KYM}V9XU*B+GuKg0~(0K3_DQaffgp<Dicj?Dk$ur z!HQHIdi3IuAU$x<L&M^=A-D+!b`7kQfn{`%t6^eTGCIhsM5P+I8IYJl^EB9MbTLq3 zgK0zYr42lIAO!)6q&!+Ffk<H3%LIsfVD_N3>Onq6X}{4p<#aG%>(YP*8n6Wpx)>;~ z(8WNh30(}Ec^G0Sfm#R+mwm{cN0=D6RD)IkD7vhn@r2Sdg^A(RMNTxK)t{ggj$F<s zypAL;g~L)ka?*o|fkFtLOfUyJKv9R36F^+dG5}--dTfB~LKh<?CU=2)>gWbwScDQW z)zGNh#md0IKw6wSK;v&0sN+8%5sO@q4?x6HUNOQG5$32vB1+F{gpN8;Sb;*PK_FFw zN9W;vYzzzx`$5GGxOLijz{Bz|N-lQcYDz$3$;f)g%cc^IW7N>mYrUI<aKn$^JC ze*^W62$loToR6-K$N~q}2Ek?(h8RkbQ;%rCfXgPdiUceMiX&K%qiA+QXa+kJd888> zc_<!2(M(iip=L$WCK^ggUguJ`dVy6rpdf_>2&gFntz^OJ*rV|XC>bDCIi!_LaC5Qs zT+o68t#joD4Rg2=X!2NwjIfUjf}4GCQwCK_OoA0#OYFff%psD7-=H~ENO5!A^?{+0 zvB@#lCk)42?}KJN6+n}4y`c|0dV4{dJvx!*ZCgQ-=m{5G_<$r};nH#&Hjz3HGWmD_ zY~)n1alO6|P>lphVl@&ZfoUXYjetjQYXWG}xpykqD;P$CB(WL^lE5?)w7kQkx0L}j z;sEhD*jN;ggCwyU36j7x60`!xqqlVd#K`+t!xAKk)ku&8l9AA{_fU^saPQos7Z#BB zQ3Ddxb;oKRNCMM5cqs$%EF?L2^tOUy37T&~Sr~PO60}6<C1^bnr2IgR_SfkUG30oA z9Sjje4*1vh5HaMCd#w!-L-zV>afleQ^I_!-vYTOI=njYa0ao^a@&{7c0~$TRZ0>^U zP?Ru4>zj47`v3p`zhN(kOf8j$%A)9i7UkGi7Jyd1KsCW)1lh<OGK~BT9%n=;n2?Pu zAj8N7R5TKrdIRwII<Zs?O%{6?LXCnaTu@}eLJ^!&k$X_Y&Rc-e0acSlA{hZrAX$(T zhxAVtBqd>fX>sY5SW90L~*i5|UEK?MXnQNyPQpdwhx3+O}uXyqTokOJ}z0WGVf z*pN;J1_p>BIb^s58olli6H>`H0e5Cc?p4z^vy<-$j94WnETM)_IabL@U#PK4PBMp@ zK+{+yZSH2D5~#9+wiTfH6JDt_|4>5dcw0dg?9;}pNgG8IZqJfaUx9pwR9}I(q&H(c zntw2(xG^8*F|=MTN)_Aug9$|wJTyQfYw$3G^v>Yi<{vC5nrIptpvs(x(12uUwDh|V zi!ZPg)X)^{2{9uHwPZsdnFIwNZZmKP1r^FR&^!lbP=E&`kVh?G@s2768#MtbN14(A z4^?6D5wwhI0c8tF0>GjO8g!sA0|gAcPmWwYf^5XCmE1)wXdQLXKo@clQ)!^fqxp?M zXYHTP(jU#We;7;E8*6`nR(+JpA;$7RJ17{y{zHgOI0;@}xeugvKWL!n#rpsM|HmE% zMad{04FS{;kVoZW@}is)i!+mhONuh{(ybJn^Ye;Jib|79@{5WYP^BD`it}?yOHw`a zQc^3><#KZJlM_qwi_pc3iV`c)#Y)fwoD!3>(S)263lftvOVG7C=cFbULA-$KHn4<3 zd1gt5LNZJ%R(1Kg1&Kwe3MKgpiD0Lp+l!E|Dh3A$hJpfgN4X@HB%-Nu%`L!iyK7-- zVoouV&Dh+BP=wuj*P_JYRCLQgVhY8jNmw21R+OKI9^f8{#TjUZc;*$S7NM*2NzF?y zL09QtkXi(a>42P4^b``1Uw|bp1M&;7IU=C6I0KvN(&7wk%7apiQ;W*b{T`HBoLQ9$ z3Q5%T01<~Ih_uX{95mksmnRmW2r&eg7NizAmZuiy=cYpP0z^np0V=4c01?&$S;oM? z;F6k_SejF!010%3%)HE!%*33`s?-#St(ker`9(#k$uJd)To8>AQ;1RzwHcz%IlrJ1 z5y=Y4h<r+vSqu>U;3Q4DW(EcZsJoHvg=DwV;*$Jag+y2ZK%8qBaJq*ALk*3LO&L&1 zDGg19+|1(K#DZc414S;Ja)ydr44_eMQw9bGM^Le#p{bCbSeB}gl$e~YkP6DoU}k1s zI;7YDnFUpsS*(zkU!ss#nv<hYl3J9TnU`3SngWY$Z06-=7K0LP3fw4g1Ur^!Xetz? zmXsFdrKTt#QcrS5Vo_ppNotWI7eiuFa!M+LAy_>q>mchWFUrqLS4acpb_KW|g|z%4 zSPIPnXJ!RE1tYBbOEOXwU@5jJH7&I$H7^;IvC!=Sse{;sYD*%_p8PZgs8xn~42DJ~ z#-LDTV1SkA$ZkgRCA82+gc~%y;mcQ<RjCN|;2J<fQz0cY1soy8sj!>}b52P<I1zw- z&%l63eMvqv&LMdlVh6hVf};F_)S{e91&~E~spar`M<G8A8Wf6L3?86-p~&Eonv;{S z$ly^5rrh)MQ<5rE6~QiXhSWHal$xBASX`W$mYJHOkds=GnO>Awkdc|3n3Gefkds)H zo(hXhMJ@(n^`(NU9fX63)>oXHn3IESA=tH`d<(8YG2EMynFdZYC9vQ|2*88U!_~*f zAL4DI-GS<F-1eh~7mB|bh}VbaZ=CK#cn_M|5du*ELIMmCPnpFE$%)0Ox|w;!sd>ej zC7ETQBminXAm<5iK~j*PnOBlp1kS!?i8+}mhzP7qEoR8eXJCM|6!1g?D0@PR7=&g9 zocc0TQu9hcNex_h5Yh)pvndKC<@pK-e<N4H#gJTsW*@S?)WXutvc#O!yb=X;jd}Sc zkQNlE($dgWNK4GjNlgJYopSTbQWa7XOA=wmGk_H$2Vh!aPI0P2ejZ951{I9C3MtS! z8>tc_%N$6JfNBbcJ4%X5!OqCb&x5FkCJS&e&XAN0NgfQ~79ENoi&DY9Ov@}PE&;~| zqWA~JAE>p5O?^%xx^l1;IL*(^Oi9T}MX?|ym4T3Zj1d|jQH;}kuzS#yC#K>yAL<@7 z9Sq>MAaeXdDj%XNIt=}w3Jjy7)5Np~qz+;iC?|pA0GuDOS9BSP#TmY-3=k?LKc4~A z#>R9uNFJ0n;b{RwU2$S=ssc<IB5y%7fPy?Dlc6LdwI~%rW@JLs5u^c+X(L1<$WBnX zQ&a-V33(-43>ldaQ;60FY722OWPo*LGB6OW4-&7?)-MACq)!2MXF+~Z38?i1%^zr4 z7Me5hs)uE0h$q21Fw{fh5L!s*=OGG1aBB+G>;s2jP-c2Yi9%vZ3aI{0R7lo^m<cU= zKrI<#6R-{jpVTzm3c>A2kbx-XK?(rmVh(C9C_E6R;Zeqb#XJl*g6u_h9mG5gWr+m^ zIjIaFl7WE%+Ghht2>!-rK><Tz0Yf4KST{%?M%F@V&mpy1L6+sDGJqPBAp4-*K4c4% zit@8lkzxkq4^a0I!vb`L<%uOAwIB@bAEK0upr#pYH~>_8z_NW=VooWn=@^_@m8zi$ zigaj%!`tAHgac}-gAx{4oe^P$V09*h)g>k-CPLi}aRIF13hJ&ZfEtug_dp$;Qwiz- zBr-sHw$O%d5xD!S04l1ms0JC&0P5<(8^uMb1v!bysS1#~1)>GyIZ*$uJh1>nU2$r1 zejZZe16^G~X$iPvgvCG<d*SLZ4b;!b&rQ|OO3Y0y)-TU5$}TQQOitC$$xJFPF46bN zOw#wvOU@}xN!5=E4)M`P&O&+_1qBQ!y?84H=fpfvZ!8s5NkaPJ@u_(!3N{My#U+VF zC5jASO2NifAvG@r96rb<S}8ztg950{otgqFH6eKj8dMC5&}yE6fkbzMyOm%UM}e7E z3jU=fpj4NXUz(RvtdN+ToLXG0$Pk|i8eIc97%Y)kR0(z^0|QJO)Q9P*(2!5fNzDbd zq0)--bD>Qh@W_@TLws>+PMRLrHc+Beuv0K#fSKb6@2(@-R`4DTsLzs|Sdt291u80N zz_Wy3sE-dMSV7qWWTGb2c?^mgV4D<dZ586<!HrloHHCPDGMM|5F=7ZBC7>8lgt-qM zlLh$&pc*R|;ueVAdHD)ZUl%K)hf5J;m<Z7u%SkORRw&6x%!8T$a*-lKJiJ)2vsFL~ zD435RbXk68iUP#(HX%9+j&@d7(7;R80GSnEqNxxK9<&Hiumv}ctQ8y;Y@u49O7n|s zK#d3;1w$i?(i}T$1&B@sTZJ4@ue~&{I5Qp6?JtRiSPLhMOA<>mlNFGh5f3fuJaY?j zU`}#Q%*oL}cBPsQ)D9hmr2PCG+PM+QVKB!)J&iwnoHG)Oz$pf*I=_gNP=N;zC_~dM ze5m0@XiOu=jg^%XIMX|4q$X!W6A>)BG$Dg?G)+>7z++&5g<psoG{we)27EA*7Pzki zRRM`+HPVw5deR2FgWU832~c?Af#xq`BNDS0%>PKvpmqKt&5aO;A<fa)fQleUuM3j4 z5J?A84pFo8fu|3MGr$=(9&9;A5`jbrG;zS(1fxk$EX0-upmG&u00A66(0W`0W-p;I z!J0I|=@X~<u*NBIfsWGxX!#xj&0O)Y*%JKW3-cH8bq+2EV6h)-34jv46kGqm8FWGr zXad}$v-XEaXXyuzZr2asiEh|RkdueOXO4L^zfpjz=?s10(Omn1p@avd9Hw%@$;1Eu zGx}SzGBAX&HgPbNvA$zx=x1cT#m=yTk@Xlm!$C&YP3#O87`L;`V`tdR2I3rI14&$D z11WmI2Ga1J4W#!U8!H3DEDlx%hX4N=g|%227%YR2F*2-WWMyEu2O?m?j)7+w88(AN zo`8t|{~1L<s_m9A&Shd~VPa)q*a{;4|7X+$i?i-vV(?{M!o(00J%NegCL@UXf)OP8 z9i;yPRI#86D+7Z8YYsy&D+5C#NCsx1Wz<PVh7BN*hadtWe3p@63rOTChyb}GjFo{Q zznO6r6T?K1sfR$s|No4>5O*A5VF+T~z`~HmI){a!inW7<p^uUE3p2xV#`TO3m>Iq@ zfjBM9Ac@J$AT^7aLCQBWvmRk#IKa%xz;K5JIe1hTGct66tlkYGV9tuv+`-5&A0%=C zL?D7;0uw_J>mNpjY|R&p3>z6i%ma+96POszgVe2nx>XM1)^m&u;c~ke8748Zo?~QK z2vYG3M1YJ_1;q{P6i}!(Ffqi~zhPw9%E;Ql#BhWWBzhU7ZVl8pQ;2c%m>GgtyO<f$ zSidnbRJAfbVq%!X1Y)md0txS8Vx7m#a1x|v8_1vk|1&~0t_5kF3DVfg%uwIY_>qZW zH4|$qGs7+>)|p@}Ynd5tfHWS3Y9uMrp}zgX$l&Y!fRSMbBkLDNhT|X)^nlF#|DVwj z;(=EncU%Lx;}A1L73(@?hN+B`8D}vw9AyG=t}wA4VrF>E#CnaH;S&?<D`tj9kaL=# z@db91CF?>^ko7V##JK)sWH`jg+RMankr5>N0A%A%sEw&08!cIz*%(q;-?K7QvVLb_ z=w&o`&&qIyk+qwZ;Q^REpNVxoE5l|ckoYGi*3GO8ZOkC{QD)ZTtPD4qb>FixOl4uc z&C0Nn1!T+#7LbY8K@OS?%4wkF3byDC(`#miOCZ-agCq%wd#z$x#mq1fr2Y_yfT_nK z4$j1Oo(CC0g#iO7=ON|o{6~xoCqdr+1tMUH*C+NqBf~L}2sm&4|Ia87a-<#WX(op7 z*^Jwn82Xt&?0KNDdJH1||7YaUU}a#iXH8-#hvW`EOI8L3*QDKy46q!)2P&b0bmoB5 zJ=hUg)L`h6bYW#+h-KZx$dIErkC9<IBZzql<hcL;8HGTSDXbG18H!mMARhexpOMFi zm4U%dI+~#XwEY!S(t=Jp((vf4y@9^OtK0R)KJaNG&=rlxT%R*|bi3a0=nZ|2ypjtf z1XVJ@quUj9NEqY@$P(!JMo0=kYwMwEA)6_hk7z)bAi_)hZr2~M;@bm>Jpo$kgWN0O z(OLV#qqFpZM|151h7uu<Zr2BJJ-q>puUU72RzHDUgX+>3a8;ml{#;++lsyd53*E}n zc@Sd5Ef3JygXbYm?*?gyDL_@vc;grYD6HVtK@NIC(E&dn&!hQ>1T+jlezO3@g-2)U z1&_|q6PR&w!lT!N5gZNOp(i}LLCPR*AR>C;p6?BS7=bu(25cfUX2^*}3#bp^u?VfV z;Z}mf`v+=x!{d1*#4S8zkkT}^^bJ=>RtUm%BiRC36o^d*a!lZq1GrUqG{0cPEsI-* zM3Yh5aUi#MhraOW_WgjgFAbXi!7aXS*B_9>6tVdVx2p)rfbt)rY(dGcs2LoTntdNY z$_T`!M#dXRdD$@pWSRiDq{3~IXXg=!DUeL;(d+Ra#P{iZgyeG%u)zY+jxn*2mM_R; zggb{<8Hg=L@#YgyYJrwqD5({crd}Wypg#-`fWj75Bpq}84k@F1L%$=HOQ6#4M~a6r zv<_nh7xu8U*Zc+)q0nAQD5z(GT%>`|Y=WmTu>GJ)3eyb_JRl`7a{WV^b3ipW){w%? zuaI&CUe<z+LhW|_0Ita(XAeVMjGCs9E7VT3w0{p4f=H<y?iR3Z1VRQW3_%WoC4F$E zgdCp8JvoT8k!7KaouR!zNOJ%sqaE_-#>}Igu0O!32^;~wAodHSoQ5#d0Gx3_O^nXa z8{pdC+Vuv1%OcRSbYg4)r44xX4~cGHkU7Y<c|aWV!Nc112miDK{M!yV?(}D3U~mL& zK491h8e~AM@`fdGkmcQ>KhO$C<b?g25wku8>4KSn9-oImno&B~kOBv}RRV4ydK`BJ z=LV1CuAp=BLAeLfim`Tmz&{;yh@Tb6IFEx5SUt2sEhJFlL8t;1oURW%7%%W|WANbL zcK~Elr|S!kX4eOduh)ZhLYjo&9zG~dqO^yQn<>yhy#NtIl)@n6x?NAe6DiocNL-M2 zZ+LW<zVPh40S;rhN~DJB1drw;ur>|o5K7P?f*zfFK?j+6bZ&+0BL*Ljh@81W2cCCB z4p{64pLvE<ta#u$P0<6U6q*e>55f+7fJq>{2H6h*b1&|rt6(}|Mk2x=DucWey983i zc{CmYc@k?o4kJIqij2lLAU&i649p9Nof<GFfrHbdw->yj17*iNL<H&?m~!M@7sPJb z135MtT8F|*ETsCQ`2!<36K)}#2@&OKZ@@oriGpZMqt_N#Y&c4S4UoV_F6WRF-4DY9 zII0eCZh~cch%1pR97u`!fPWi92NRA;52cm?m+YX@GxP&ex<-_ksHHl%d<FI7;1P{b ziK}Kj=K5X115_JhmfJWS2rea{Ap@zELF0f(;SH`rAU&oZ9-uZQQo=%31}>M7YZpid z4j#*}5*40mz@dSWFCYm4l2Q@=MGl!C9>+oDI;iXfIp~8&=Y$SOo$|xuc*6v+9JufJ z!=oD^gGgKWY(Vx9h>c`GHwQ!`yez@$It>57RCU(=n1CnWz*8uaPjQ+BYeRut2u+=E z{iwBWr!S~*e}M?G7arZA7Z4!^;@<G+oB#?naAJph7$uz_cLg2G0SR$y*BiyE5VZo} z5MhM15`K6vo&e_sk7m~&jIS?(6+zvH6#MYB3zmn+C1UsioRVH39EnASfP0ba>f^4U z8)ZOlM=}SL30+@!bc2(Nhqdd6G9)j3@Bn)W)Ux@2<fRXcuTQ~Z6BYyDH0+9*A_E{n zbKF4!lpMjq)D0EGnGj()5t0Is;ub|awq%G?Cp=X^%mllZj8ui3c0n@=$bHA*6q`t4 z4i7ny|B%Z?P*d{-|0GCLGmDvEQ}YAVBxtz7k{r0BgRMM(CQ0y_NZ^`Oo0Xs)KRmi2 z=?$v6`30i~;{{k9ifS{uo!~TqEd^_UlihI#(7F~-?)l--9RLv{I|W0u4@3%v<yWK_ zM(XJzr*AAOk;*Po@)0;>@#HqNlm#8F0lN@O9Rn)Y5$Ukg_kmBR>kW_YTF|W}55V<u zH+Y`!hi4~pl?!TrVDtfy8$aL{cPOZqxPjCrf%FI<wXg?h>=raq>UsmIp9dR{MKp{N zhgyPlV{0HIdISVo0kE`-B{rb>2_}O*l+pELSB14S_XYJke}H?9NZ!Rr1K@aq1Q6Us zq{S%7Y0346M{fYA6@onU0BM8%@aTk=01O_j2TIw&6S<`*H!6V(lN&7f3lms~pymiP ze}UZL!2wBgpwWk89-WW@eVA^PxB*qQu=d3dkM0I=Tg~!NQ60E^f%01qRB)&9zd!KV zgJ0{wYe|r&F1~7h!05qw2qt{!Gk?T^&-_sbKJiB!NaNQ7&Au=cvw!m7*E#T7?i0TN zFQ}^h#2<4IEaU->K?Vkf1`opvkd7`&TN+}!0fd4y1Hg^k&>tS1UEt<LuLv8c?F(+v zz<h=%OF`biRhB|MW$pT*SlFW*qX>Z53F-qN!UfSx0_9lP2(3pq11>v;MoNH(mxBP> zXfrrRg3^YA0I2;%AfN&yz=1|Elo0kw;IMC~g_{Nre{?%&5EE{Y1WqvAU^y0BsRk*h zKr(2(D>PGKX24<=SvB@T6-%6g>MF=c8EF0vX*daV{9L!|1=z?9=oD7a>HeiP9>}8L zt^-O%1{-igR%Pw_0y5BM2&t(+Mdu5TUKu7#vtB?3+B%p$nq6NozTN@W0QLB5M$i}+ z((J1P^28(9ENj;j{4JmxC&Bu<q4^!$DMPMIJvv=MwayJ#>k!=a_dNmDgw)-}GT6D6 zaO>~`=psRIP-}xqYtZ1`3vdqy)P8`Je3plb&A^s{+mQ%aP-XMO1FY>BxVOfL+#!0w z_<99I7t~*_A3U^Of56O!_bTB{1n{sbsC)y(a)d``?Fo<0(gPlyp*uV}eK+`Yx`K>5 zff@*)35OF%6|o1n+2gtco)92mwZWqsBnEFdd33shCYP`&Tj9Y7nvC9oY$#~76BawJ zD?Au4K*J2=7*I*?VeR??TtvO_04YUo0f(;e=mw8Vqqy?8E9f3oP`mkphqdd9VtcT@ zZU%_j&<h@nr#yOPKnV}wL~uI`<mw9`2SEDLpmcYE@%46y_E1o-7+g7lT>)u+fD&N@ z(wH2mrFa88{SC@KFkfLybD$pX4Org+JfPg+`W~E8AnEY~wBCfLOUpyWI*=F#xg63@ z2Bjj9w?23@A7n)BF7JV;g`~0G0MNV~(qIETS@3UjeGhL#Axax)X9m#|Qeea1cmcT_ zWe^_G3Iw%a5c3=GFaZTNmg$5Sh%iBO7r1PLROmZF>m$&t1Ep<`<~N`i0Nd7ip~LkK zIO9M)0~+FoPE$A&@(pNGveW^h8#a#h!UNoULUA)_ume7d^1|adxP=933%vwg*~`Dp z^-eSB&dm~0h*4l^50FEeL01by1VNXLf(Fx|0RkU!gvnaF{wNiMa6%tIM`m7Ec_7AC z$QVn37zgzk#yk>47H%1sizs&yF^ea?2onlnP@M)Y@j&fTaJGU>9{=#@>;QAY3LwcB zoIT*F0UpC1khv|8_o3y)18_NkJs=@QL5lGopg1U&1A7eW2+**T>kV*&6EcJbneOTa zhXT|=@EI{!j|5bff@XLiWhtm!fF*C&1F)jh@(_P(J7|m)G3^8@*}z7EQbOAz&?T!N zd%9f@Aaw&lPI0~Ofhhs5jYC16Jb|X18LApt+@tdl|2EhA9ZZl(szyj*2CFoXUD?J2 zI;0rn2xx`@O+_Ib{Qz7JXF;u?y-R!0U5Z@rgQn)dl?-xFmgztphvt8eZj^w91jJ!z z9|~FR%fFy_0!Je(wY)%@EgXmtIN$+KQOGU@r(8%i3y(r;*9Y(rK#m?zhYsW?r0@gJ zSHeO7MJ-q%q;7)*8-xvMZh@v0QO7$$Win{paw$7_()YEZM`P^=(6YNSVNm}KrHFpb z0;(hsr3a{9K#Zz@Oev8EsQ@*tOT@sv=n{UADX``SxCw)4KWLpzw=3aM19Z2_fvix# z<4|agLN9kB`cDS%eh1ucP;K^xe_QAq@XR@=Y(%t8VWkn;oIj{s1eY?}pyh?2VMh39 zJZK>GN3kzB6@kmY7arZPQul@j;|XxH6Fia$X|X~pK4`fBYLkK`;WG{&7+<eMnqh&v z+5<G7)d^b00K%YAHpn;`EJoojN9n&n>UgBG4UuNxWj`o9ptZY$1gJEJtw12IYKP47 zL#73Ysn;Dq*Df-=1XcBjN*%Ot^Myw@xD)+=zZrZOIH*C;O-zl>2MK&o^%5ZPx)8NG z2YZRgd6BaagFrJJcq(#`v@5*+Ldi*3!_<KMFa?b?6BVYQi`H?4DX4=@QJ89Agek~N zB!;PmM>oDOh4>U(%LuhM+UX1GNx@t4kX{pX*cZ9i1nq|+DrazC2-;JCwH<$e+c*$G zq$0gL^Z>MIK<V5fy5KK7tX&U)XAf_9fcrupz%?M_DM+6Yo|j)hW)E*5DxL!n71+8D zpbQLZ?t-wpv$K_gMrcxLUP-Bfsh)|Rfv#C8m}gjLXr^aiqGzTF5mzuWFf=nTGq40{ z69Ewn3=E7_K@5x)0*ul;>>Lvq85m?3AQ&XA3?dx)1lpLKdD-H4*g2qbHXv~Z1_mt< z4U<nr$b*C#s{(w$CbNTXTVh~_nXkgYzyQJ^HF_)z44_j_8DM63G&3_RvVaW&sqq0R zVqjqS#DJ-e=_yzl*u7_<>bOBP%q%yEJjk3WAaMo;h9B6>d5uuF2dd7K5z{_q8%D4~ zka<s_>Qb<&3rDEq0ri&{7#Jp@+w0oQ%+vuk4jdLHP<3C?)p;~CGrd5li-D^9iA~)b zgt``}x-e|+^F+9B4OCqL6Bhp_Gl2~R`S%J`-Fa;G9s(-^`{NH(9VmRz<CW<;LY)fe zlwSr01{-Yd(?__^2deHDHhbS9%qxMabHHYvF~Yn#P<5xUsoRTCcLb{LCN_0v5bEAQ z)e%YuBH%2*z@UK5JYj@+Hc)k9*y4i|5g#c~b-vilb3mBa168Nbj3s`Rn85)Eir+0z zb>i6U<wDqdhe&lS;K*lSxQ5MrClT(`AyQokRNY%_>EHp_8{qU;169X|&0a=?y-T3# zxUr~X`iC&@3{+h?7In;72=l%`)q%RhU?!{#0_F2Mh<TuLwFEqY!@!^pDnDRqk|6S+ zc(8%W-$C~$$ec?EbtzDFhp?&J0Z|9C?+H|$EwX(T5P6V&YoPM@>;svj1G*550lT|F z@;*>`Z1#ZUbD;84$nFS*xC12L1C<9Ig$}O^ViEFdpz?Ca`XdqYXQ1-9%zp!w$7Mbb zJIG)L23+RrK;?Bo%3$%9fw12PD$j>3?}?Dlfy(1@Uk?HKHF)F|7#JANK;^;pCCq)G zG~)zu14zvWsG4YGH@f#QH?uJLgH(ai!yc#_Lg~Q<)DXav9%7*KxWcmrDj$mM7N!7@ zGr;xv9H>05_Qf8kJov;Fn17k#;rj1D<#E~n2PzL<=K<574b~2}UxpLpFa`!Y5CxNW zZDuavVdns)R~x82F89Si<pYrQGkJq80O_xR%7>uHgQEd#{~V}1sNVz64@{7X7Nma< zRNf6)ziTsd4G%j9D6a27<-upYAi19@AM6AMkQxT)30iGvW-x&afws}kK+XArUe18p zCC?#df!yN*HA@xQtOSTWC|!v_<w5N$l=2Z|&U%PCkU3MJ>c9sX!Q9Oh16BZ%-vX8Q zL$-$rlF>l&SD^A0DDuT{{a>K+YRK}5U}<o;i+~%DxZAZRQ29V){Y*Y!13>nNK;^Sh z<kR5tB~W?riK#IE<$|Tb_D_MzC!y$v6oer2w?O5=?QfX=a)kaXP<dSb`vR2*Q!xF| zb~4C(5gw4m3=Fu+DHEtXF7rd6^0@SuK;;*Ltby6jGzaVfko{Aj^2bo*55ncQK;<J* z<U`={SD^CX4i3zGP^N|UTfRW$ak)<fyq<!A0hj+wpz^r%hd||Vg>MN|9#=gv1uBoz z|4?~c_FsX@d!dAnD?EI@K;@;8<-@?z;PfW~b{GQ#_-qGQ_%TI*6@cQ$1S&6ztRGTr zgY}0%<#EMN2~-|e{7iw$<MQ7Ys64LtxdN5PrT+_59#_2}!VmHo0|T!3Gl9zE3cnDj zJTCW@5Rjh&l?R^*4h#QGaPWh}cMDV=rCzFp$b-t+8mK&|zl&1Ng4zOI5Ott<`~y{o zt-J=w%YcX7aF+u%P<dSXW1#Z5!l4E#54yz$UcW(#Nw7cXK;?18;~uCyu5h{omB(fO zAE-R8dO}7Je>$*%%Ht}>W1#Z4K*qr0k?ATp0zlzg1C_^>kLEz-gHZJQ!u9Wg%7ZDG z`H*S|9DaAe5)2Hu{Pzbck1L(a2!SkSV8G=+8>l>(g4qvo9@zdEuml4GN_&*a9q#@b zs65yiF#SmGp97T#Q!sfX^Y?%yaQp8LR34ZA{y^n%`A<d|;(xF*EcV+#<#G8h1}cxs ze>G5fT<LobR32CRat~A<rTxd`2o7IR+wKlj9=sk9=6+BaumP+D97hb$0YDwlm<>z~ zvpTp_3o=6iDj$g~@7m1F><?A~Hp2y~20Y&cGlOX-*b-1WPl3wgYUj5=<()vm4bxu> z)($p*2~=JOSw0;he*`L@jqFC|G_V6f_CJBjmm%wCDg+w<l4k*DKn8|h6nV(N94HJ_ zpz_~A<2*3;fx_S|WK0BPh6hxQBeEILHZ({+11gWJZ`=Wu$5j@tfXZVl^FijHfXd@C z{{>VYm-!rGAcr$B;7aQnP<efjGFTX7frAhnM;=i5R%Cgm2CxE<`!b;N#>nz{U}>=a z4yZh?x?}}ZJ{TpA{orwYf`I%Bs61#48D7^gK?V;&?&A;#ISj3@2dz^<X+Q%i4-Q6{ z|DkOjh)(Pz$hj;GAOB;MWoGEZCd|Oh0Gc?&lwt;tAY&7sj3EeeE+Yd%9OMp=B2Zn) zh-3~-9F%UDklX_rlLx5><ynw8j1LY!1_p*a1_lO@xB_(S2wcW8FfcSj#X);FK>9&r z?I0S|76GYOhK|92#@0dNpgsUd95yxr8bbw%Z-AO}0oq3gjh%zUk3hwfpnX!%SUE`i zDpWii+P4FZjf2ENeO8e90Z<2m#==430*ny%FN5|4Kx5w^aXqLwD>x%CFo4FKLE^Sh zaWQC{2{Z-{68C|M|A(pvjXi_JW1-?tq3S_n;UMt}sQ5`}+XFQA4HBOU6}N|$RiLqH zkoYpFI43myg2tjj;s>GPk3bR4z`y_tw@XlQH%X8x$XGLo^$;qa2Ci%v7(ipoAo0&o z@fuJjU|?VXjU|J`S(zZ=b5a(>V_*P{9fMf1Q1Kt2Ou@jw02(U>i5o!0`N5M#2yqvv zxEeTPL&kzZ>LZ}yf5441gm^Ag{1SM2l7Rs<)(cYK02SX4JsB1>whI!U1QkCEt|S>4 zKx4Te@pVw~8{h(ufdMpj3laxmW(H7d1hG&tGs84g0Vt1|VFr|iN-;CcL=}MYm>Fh6 zS*R2<!(3DWD36(8K9q$@F*AU22dWr|$IP%8L}6fN2GD)q7{Uz949hVE85kIt89<Zf zm{QCPt1$(^>eu2BUynn4BMx!U_1&0K%nVyG1;O@i#~}`0_JSeD%m8ljU=at6JYfhk zFhj1w!;oNRIDjDr5@2QkjktqYsF;}nR63!Gfq2Xe;GR5)iGrCKKzqtjguonThEre~ zonU5w&2Xa1Ff)KIWknSO@t7IFD{(<g6wJ(U355^iFf&|%F;Qq{2GDX!6d^E&nc)VQ zMkkmVz&#!m;k`@@450dG0km8yK$2x<xP!z)Fqs+dAvj1ZW(M#H5=bHtCNsk$2m_5| zW`LExs1nQ!&rk)RJZ1*)Nfl5YgyLp~xc>mO{PchbgGpwFS6~{Mh=QtD01px{FnA(K zGBdnE;vtyK4DS#eBo;FRcpop42!zQDo)L$zkx6C-P_2h70%0>Ve1kC1NM`ViIGP|h z-@$4>R5@mbKd1sw9y7x~C<~QhX29C~VPIxpgf%}<G%zzT;}B=XAr9JSfMNug!_2^m zLp`jP04swN%nZCZ)bryI7sMeBx<4CkES$m2Ac8}^C=PLP9O9A~;;W$PEdkmd0Jp=T zHZwCwW2gs7F*C?ui2s6`!vNmC&A^ZgQV7M&400IiK~l^N@;Jm5afmD95Ld+^u8u=o z6Nk7q4smcV7vy9V%*+64^`QuXIm`?OILtA^Ar4!?0oD#Dm>JA)sJFl&ZiPb})>?!c z4Q4Pi*x^tQYmI`H!3kytCmiZsaEQC%5C`4v3pW<bh+u(~lM3LD5(5MDT1~JVGlLfn zbG&hg!&;+Y?Qnvb!5@eE036~$IK;udNw~Qn#v-Wu9iZ*)43HocGc$zZFbCGFfGUJi z%nT7Y)PqM;psElQGea~E^{^E`2(=&<GXtoX0b(KWGpPF;p!v5DA;rMV5Rb$B1RUZ? zIK-22h^OKZPs1UefkQkChj<PS@jMK1eO72Xgx1%{Eqi8$0u1$_U}9z{!XaLQA>I!) zzX4jmXMqfWVrGUi4D}!>W(H9255z*n%nVf+>OVluUjWTVsP3=9P#?qw@h^BVg@J(q zc7GGdCT4~@4D}H41{~r|IK*Kq%0Rjin3<sshx!g2;$1kzdvJ*N;Sle~AwCg@_#_<S zQ*ek+!w}yD4d(;U@}UP23=GT+GceTiu|wkp+U}i-qJ9>J`h0dszuO<Y$OJkb#lXNY zA1dAp6^AAZuxZQ;b1=*SNiZ|a$05D|L;MJM%?EU07f3S{e*=qyXOW;H5K03)E(0C> zfe3*~$eIu6AP-msLQDj!2O9<vfRe|-;$Q+Q0-?Twg`k5x5Fs$B2o{14@_<DkL;+YF zTIfN9z~o}EI5hCVA`s#VSR6bW2@!yiV53c7JUFcb7Po@)VT>5CxHXImr+dKS;2C<j z7>Kb6EDjoN1Mv{}23Xt~Apm75fyb?odk+u^U$8iMh8H4$L^3nX!-!vyG&2KMVFqRf z(7-lG1uAA{z)TMy70i&;x*#SBW@f-l4<H5144CNwB956JAmZT22Qg7FGXpr%P{cqS zX4oPY5C;h}LuPQ1L?BFN2I!z4gbOE`8K4v6a1jWDnE^Us4B^5_W(IyZ8=1k(03F;z z76kXFz%xN;qM&gY=-?rm3^Ri;nh1o;44brpaN#5~19GVV7iM5)fEHE=Aux-X0oqvr z^AH3xtnrT!0<)MIF!K>ef*G<>1jIza%nZ=V5k(Z_U+7>XhB$Pv5knk2Q;#MJG6(xD z^vsZzO<2@JFNsByVP*iY2t*SFnGYSzM3Z3#uQEjw1jjFQkP}Uc8M2ZDO%!B4cm*gH zap>SDnhY}obnp{H96I=kAr2k<#1IG1q@js|+ykv#&}5hyK(hvDf?)rGXM->#m>Iw; z>ad7I?wCfGV1~>vqYE=IGhiv7!S-U7&mhgr43ImaL2P8q%wUGhg|nF%%;9Wg1~Y>N zG8fKfW&p2Pf%9PuW(Lf90VK!FfLSj<#4+myh&X1w01*ez`hl1zn3=&Ig%9H}GdRGQ zC^Rzzcy<y+48&n(0MERFm?)T;0kb{=DPU%B0Z|y3nZXr93?#tJ0G^=+F;OrxgF6Zz z#$jea9$kZpg3>2uJqVIzX24YsdV{1fFf(LD0v2&!3^9-ZGXr>~A&7~BnHl_1_%IGL z19-(Jj0>lk8Ne$B;d~f_nE|}Q1IC5Z%nZSBHZp^m0lZ=qSqRK#W&q9Bfte@-GeZ~( zAI4#32!}CIXl8~86h4f@%m7}|1>?eLW`-y@8=1k(0A6K`ECgmVGsJ*tbb=YO;tXAw zfteu=LkuLq%n%QvFfcPi0)`k!fSCcjq7=kL!ORTcm6j-CAPzGF_^M+N69qFffL9!& zh=DlFu**n693;%lkcPxVFqs+B5ga5IGXwId144osrB{b6j@<i176-3DMF>Dy%nUhD z7AnPzGTMibV+POmBKR;CGebU%i9$0oAdl`Nq?j3yM<bBMkw=M;#fuRfBo;FR{CZX- zQBe6%io%C+m>Iw;KVV!q&CE~^XCpJ1AuFbkg}`iP2JlL1FdLa*W~f5u!r9CW)o?a4 zgPEZQnG0t#Gt|P_$P8wNI%F=K&CE~_XCpJ189;l$kwqYEW`;%x1C3;6XhIW#aGAlg z`4BcT$;{A#%!RX=8IVVv;ld2e4B*w}2mvUInE`Y%1C)bAF*AU6&>#swnam8GP!=l1 z%+Q4@0Oc_=bVFIF6f*;IuN@)B3|Rq$5MW?nSjW!5Ac(Xc;{&t{RlyArhw))O&n|8T z1|_8VWmpSxEjI(!UcoLL;^)BTAVz&)Exd0y)c?gHF2n<J4`QAg7P2m2am0KyYzD3Z zERL9uhRt-Y1&br*qhT$T$6#^9d^F4)L0*u(h<Rt2`UJ2zV%`}#JjXB%ERL9WhPBAg zg2fT@&aj>UD<Ago<lzI^i<pmwnQsFYN6bgV%+CdjBj%%F=FbO<Bj)j8E%l3Fal|}3 zO#Ck{_wZwPrz}6norw8vSj#&GERLA(hV?urgT)c^-7tS00gEH%yJ6yAz~YGcZkV`= z0LWhON<DBo2d`aZU|@&<izDW{VKsLjSR9rL7~nIt2f^Zqd2Lv@{Q`?4=D}g%qb&%s z7ct)rYpEoH#S!z}uyj5fERLA(hSj(i!QzPdZkWB?LLl=I^WCr>h#OcOG2abqN%w%o z5%b+JdoO~;5%b-!mYlFK$b7_nH>?Hb2^L4pcZ2upfX-e7i^FmQ1H1*i9W0KR*M`+7 zZ-ud^lmB4#i1}_<Nop+uat~s@8#d!x02W8gcf)$5OTprZ`EFRscmNhh%y+|DND`tT z^AYpfuoiG2SR65b4PIN!z`)Q07DvoqLzne1fYv1{A<bXI!WlFqp@cMl4Qm;ji-GKg z`G$c3)`BSnizDW*!E1II7#KEz#WBmbCtz{d>N5s-3r|2CWIkg48s<({usCA=nj4%u z7#Lc?;)r>0SkG-ESRAu_cnlWDELX)Pu*a{Q1js#z`Egi24FZcJ=Eq^~YzB)X=Eq^` zH{&pWH&{JpdHw+`j+jq}mFx<VAosv{3=FVxI}9w2m}iIO{5G&SX8FGbERL9ehxHt8 zfyEK?>@fFpNP+A{%(KJ%YYY}g%(KJP$AZNX^X#zrnhq96%<sc`?0doDnC13MusCKt zWg!i64`RL^Rt{%^#S!!MuyEK67Dvq2!`yinERLA3hxJs&WI*O4=H+1{WpQ9}#JoIs z4-NwZ!&0y~V*VXA()R`|j#)m-%Yw{D%*(^V-wP~`n16@4vlc9ln16?b|5~s(VxApV z-aY|~Bj)8{<_ODy>_yDK!{Q|fERI+Y0E?GeusCLYu?{Sbn6HP0&pog>V!j^cPCj{% zy@>gGn7Fq*_I#HDR*#s+hmCMe1&br*@nQAFb+9;M9v`-XP*MS8FJc}aR^EDo#S!!P zu<)q?izDXoVd__b#S!!PF!w(IizDXoVIz7%iXeLt^Y}3HUBKdqd3>0^D!}51d3>1p zTfpL&<>UjfIAVSuR?Z76f$T-h<HO?D4=j#ZPF8`%5%c@-avLm;nBRxhp#Q<*i1~e3 zI`>ir*^8LphmDv_28$!+_hBRKx4`0<<r|j@$Q;aa%nB@ySzaZ8#S!ZSVBydU7DucH zfQ7>$usCM<^8zf6SSJ7r2PsvMdl2gcU^4;nU~$Ac0a!b25m+3tP5|cL$6#^Ha!FSW zWIkg30L=V6usCM<FcU0}SXTh^?`g0&V*LQjzpUyY^D*<a0azTdt^nrWbg(#LT>;EJ z8^Pj;bp<g0{sfC7))m0~Yp(&a7qPAYmj3g=;)rzxu=d7QusC8}0c=F_FIXJ0t^n4O z4%P&jk62d#D~aZS#S!ZVU@`O^ERI+|0Bd2}Yk|x`tRH~2dpp76h;;(65!mx!al|?S z*hsysHpm>rIsx!r7X}7~46rz2JpgQ^V<T7`G4BuF+rq%W@E0tOnD+<oX<=Ys2+{$W zkC^v|jTBdd#S!!Vu=c=8usCAgA67111&br*{bA+jU$8i0-XCU;mM+L%#JoSuoM^B( zV%{H?P8Nd25%d1A8Hg)jam2hoY$SqR4`e=K-XAujU;`FM%=^R2;Y_eNV%{H?^VfmJ z5%c>n@gHDu#5_K1e}t<(_If84B#vdeH47vTZF3@1O*q6ELQ;!MbfcUSi!+mhONuh{ z()E%H3K-&}{7j;PLwtM;4LtM85_2+B0`iMp8RDaYOMEQi<1_O!^D;{q;-h>F%}Y{? zOX8jL^NLG~N|Q_Si;By@;uc_W$E4!?oYIn1&%Bh>3W$UWL?S0AKRK}^zX&2|01+%I zN~{D6KumQk0dp+Dl1_=q*<h}rF_`b1Sdf^USprdS2r<ApCp8gbq7lRzut0oxW=Tdo zih3hMh#C301&Kwe@ge!~j&Qq;pyngwq97pywjJUa=llYQ#SpGbVo4%c7U~Yy+ybb> zj35qkEi6sUDMqu$2<!%g6tXoigNhQ1Q^6*~3<3$n2bU%lgCh$p1y$=-l%IzjU>=FZ z84!7hXFc<ZQ;Q%93?U*usd?!oP&JSc_b*5-0>w%|PAN1VA&v~lFF+6ffcyf4jnFs= zC@s!FsDnfSNDN6K#Jr%?;?$xth|i#o2}&)_tb&L@V+SGvi9NT>oE)%cAORj+o>&0l zM)?^UAtzo>L(?d5Ogh5SmuIq1uAz~ItE;Q2D=6$-b8}q{E#u<@f?PvFBIDgc{hUKQ z{r%$O8RDZzG0hwrB(7ytG0p-OoOsRiHiP)iGZ~LR4Go?0OY>5SoikFCvk7<?8d~w7 zNb}4s$iZu{iF0C3j%yIY5y6J>u6TS;jAJdJ5tZtSFIo^LSvY4T7NN$lE2(BcJq@)v zzX+5>jE!7fi8RO%>Y8|PdLlN|pqf0BL4k%p4O&7XIUbfI$g%=Yyck+QEr8}ivdqs- zBE|-2CLzlPV$4VN0k*^eO|*#MH;8v7&h4mX<4iOd78v5Sz{D^<zPKc@Br`c4REK6J z=44hSmSpDV#V6*a#HXY}s!<T%ATyI8-rdLF$<Zf1zPL0g-ZLJ#s0+=@ECE&C#h}WX z_)^f>)D={4l2C5CkgUVm)HT36nPhhbcqiwQtSQJl*a%d1V|WN#V!-V%Y^urexThgD zlU#$mgX29z;z2Da42R-OS-4$`Qwz+=@Z^rCo^UpG1qU}VYDqK~6q7`o?Q9AP9!Ml2 z+=49_F<p#J6=`n87h%cJ7(=)UXTW1R4X0AD`;c=oA{S%v4pQX?Zho8R<(Fg><(D(W zN985v26+dUSVBeOK@D<0Z0XO?z$G;i(jZE84FG4dl*E8ChWPmOii-Gx)S}}2yu_T$ zlFIlp0}?Z!A*rQ_vmqH}16U6@L6K0<86uJux-Kl?>`I=)@FgE;>hVUm9b3wPG*L}J z9SKN?lAy~J+}$8qn;E3}?^?!CTvC*r3-0t`*orNr@VOG3dc5w#rUBuycv70=E;te+ zHY*@%L-Wcr^HSo2Qj1G-QyIV&b8>ckaz=K1T4H7nC@WwD2=2&3Z+DZZ-4xuag~lTO z5(ko4P=b{h4JM#gJ_#0>1ZP&ILe&$WhK(FcAoU6fL5JirVk`nT))D!YD2u>)EMS8G z5ML2(7bLZik`_(DBM%U3h;kn!PR$^r0i+j^Q2W4TBnkGR1qcZ`&7C3RBQU3uq16-A z6>`l)ZX1zc3N)x7h9n^yLQJ$mg4+Z%jsr2Fj64%yg9@O`PQ1M^U8F{rDR>}-<Wyw> z8VYhPV+aloiFYolEGWs32Z?x@k>+YM$Ow`vsMP^!u8|O31vzA-l+;3~rh*)NBRgmT z9}*AJ733Xkg0*9Sy97s!>5vvMNP{<|YJ?7$xdxHiU$TUctC6nP9NM*ol+$RTho{G2 z1{skfTN}xqGy#qC!SW|*Jt#;9cQ%4#7GkPLXG4g`h*4_+3Vm>OO0u5}O~3<lo_Qsy z=|!0(mBc%c^jgRT>V4v)*x3k_cR($|oYXu}Vn&Si;Yk>1)d(>mh?16wvIN%b%uUVB z%`Zy@IgV6+fy-NBTnA}f<bu_cWC?sYf=FB7>d|e%)@X%BPJEOf!gQ?apeY$CSg|R? z8Ee=S<BBhAYGE;jrS*<YIiVbZO%JZTfK@FSxqzI09X7j>TlI)Y!(9bA8{)GWHXuPD zVv!r}#8`^0=YkmJ2F+y=JAjLD7^rOr&Z1DiQZU7UVhpHHLV;_Dm@NYL6tHDAs82BG z4PZ3~!uMFqO0dB=GaXLTQF9)8Ie}Xnyn7!X<wuOm@Z?&YmJrIiI5pzRzqmC(Gchsg z8QK{Fk8_it9$eZJqaLH%0M3`7*0q0dd{Aj#NoH=UV=-v96_ipz$(I;YQ91?0Xn?lI zq3t73t32Kl<Pu1=MN-=wVn(o0JaR9H7&pKiO{^!;n#u&yC8QAtA5kF2L744gVsxRl zh>6kxo!TP4`3BF&&?X}>wxBnFLD5TWP&*ru(4K`BYN-${L`4fZc^?v?ux2SSA%JD< z+RqR^LkjIafwCDfQ`c|{LA4V!8sLV(#)gPB3=v2m(?GFeXpWdz&8$i#)*uvDfeRs6 z^$`ym4<^<aO!vSIhM5PAWyq8_BrYHo9i+%0Qa!xQicpWO>4Ta6u&F|w-$1UYu&E}L z=CJ9(Ol{ay;Z0{~NdudH=rk}=Bp5)a`>-YoJVwAnH5fEi4Nh0kS`j%p;4uKx4R9mz zCIn(yo-hOAk=kKYbPBkMgqd)l{zpl^V5PWI4^AzFk`PXfnCS?oQc@BVPD3zLlp($p zMaUd@8UU46B$YDYkjCj6L~4Vj4a{gl>X5+u72pAKV#_uZ$Ahy3R3x5!V^G5YJQ7UQ z3MfchsVoTU0?3LU@Mt5r^@ZX(N|p$L4T2ROkfB%Nf(xqyLCr%G<n|#vA}DYp*opAU z7`h;kI7hmoh9B4@V`%m1SVF8Bh{Oj^)kX$TQ$Ry>;PG-|4MU4i$O0DXtd#<L4`vj! z<w%yZzy`q*1!OpuEOT;UtsiKy5f2_|r6BzWLlYO+flxzH3IcF*1FgKqT4I0|Vk<%6 z@q=xRgDYwi9;?Zqf{Yj!fYjl405%VTbm4FXa&3uIE6x%Y;csku!NG-OZxSd5h|&_A zk(pK!THs22;}6>71kC_}SCJq$*KoTnvjWnqz_IQSPxArp4RBKk>@ysOV6z<@A<$4o zm;_#)2MQy2Yn_y`6|L9;Wg~Ds5?o@DnO_{Alvtc<;+dCO;tXDk5T8<<AD@w!my!b> zu0~e`83c(>u1JheEJ>}%ECKB?fUMdF?TZ1Of(E(nn1KPduNx*V1wB&D2BI8%@>(Gy z1H+&H5CGdB0@@+~+D!rzhn-Xb5-&zl54$M>Bo5kT0#gs$VGj~7MN$vjDF_k=?LL92 zzlh`>&{_E~@#je5pj|02@xMsol}P5pc0huTvjc^L1=PQ=9f2Twk<EwgYy*jdcDKOH zhwZNbi6h$!+wlVuN4B>SdM*RZ-U6t-pnDZSP6eq)wimWz1Ezj9RQ)2TIUx1O?%9eY zj_jTjNaD!uc?=bYnZE*R{&%Q2$b4k?@PGuscUUlhPXmR8gFKQrvb{z~;>h;;Ld9YB zzJS`B2o(oW)kyJG1`@zxZzqyCXm=6JJ+QlzLDIEI=4=NEFff2m;seFI2K30t6Hsvw zh3wzEAOS4)en1jO_AfKkA0TOD|H?tdVg9Xv+N+8tehMmX0u=|D1KJ%0^OrM{cs-K8 zf{?_K)hFT*how7o^XqY_UxP#Z0FpSed#)gfBfAF{&*=94!J%FN8XoBCrIExzyToAO zqktq1%4;z3K&Ut@{7*yqkx&|BK5{vhfh3L`kM&66pj~J%^ZTIUF!L`!`SYPP$b4jT zwjqfln{x~*4m0Nslz$dV!^C0f<PKCEWIl2@Gl3E}G~FVL^CF2Ohno<RIC8kDLdDVT z^+OZqfbzqjG{`;3;hBmg-i(xPbCJYByZ2z>Sq2q{*((6$w?k==`N-yg&N+sapRGvd zFMz6tnPUOvZ-mn5=Ilfg2kjb!x#uKQ9A-`elz#zA!^C0navv%VG9NkoS)oUaqKgY4 zi6h60D3UmGytqNdVfMnp-w!GdG9NkolaR#Qk;11KDh@NJ1L|(r9oHapkk!w{p?)(| z99{hps5rX$x1i$a>R&^}(bY3Tk6=YtF9a1wS1*Ys4vQBJs5r<R<aqJJAs&e&jvOy> zNaD!x(hn7fxd(P<`E;l_$X?`lSqv42sow+*|J6`&boINC#F5)$Cy~TKyINuC_7+qe zX8sPS`LChkAoG#c|HUEB2R-T*X3h_&Ir30(baM=#;xP3J(0DaR6Nkl%8&n)*4syJN z;t)^4A>M^Ud>#(*O*q8&B8el%`ynK8<amDz6^HpZ4(eaX`Ou)VvKbgUk@6iQ^oU@P ze?hyAVeush6^EIV0X0VgO&k_(Do}BdIo(L+yW<cKLJ~*zS2&V5vcFoP;xPBX{M8E; z2ic39o?&-^gT#^RyERbtFmq-={k0b=4pI-=T@4Ed*j?Trab$CDL)F8~IRQ22C7L)a zd_F?OLFV)#h0kB8ILw?MP;*#70!Zycm^s2wagaI4>C+O2xC@dvayWY;i6e(|6;vEV zfwC4XoSQ%b(0Uv>oF^iQBZtpIs5poMnF9;w?H~cDIiTI@uy8(xB#vy(Rj4?K0+|B~ z=Vu@Rs5zkB?J#q`LB&B7NIk5a{R<Mn5}rJujwaL`<nT1YA#RH#jvSs&NaD!hSp*da zQ6Trg%IjK?00ZRCWRQ3&w7ly;6NlaNHyKU57^;3gR2<|zWOJ57#X;!=Ilc}ciBCXE zhoJNGK<yToISo+r-{4UH3n~s%zXPgX6na!R$X;agm7(G=^&g<>?V#f5>V2T%F!iu< zJQz(JmM@Z^;vjR7<FNyW_+%t;<anHcB#s=9C!yjn_rT)uB2*k?FLF5Fg^I(}!{YZT zR2*IXN2oYVJuKdTLdDV5vqFzvhpC692VST+x_U{dI81#Gw4P9eileL7g^I(}!`yEQ z6-QU^ha?U<RRWeDW1!+Nb1I<rRzbx<<{+!@fQrM^Z-A;_1{FtFzXd7|Q~v_0{ybD1 zUHx6CI840)wEX=66-QUk20h3Mral3xo)=9VmJVg0;vjR7)1fvFaVs3+o;buKaEPbl z5Qp6jkM5ooIMnaKA$|de_!AuBKX8aML$3e;xd%DlaUh8!=Q~TNI4t~O>Ch1>4l)Nh z-vuCvBaffNL&ag{G(h9A04feL2U&e7R2-%rW^XN29Hbt3ysH~34pR>^e-fHFES)Tb zii6BSPAA84h+jeyM-I2^NaD!h#sR%j0p^|!Q2z=*#X<HWhnqB198|1>>JgZFH8k-p zP;=~|;vjR7+cO?eahSb3pz4#M;^^x0q2e(0AE4^X(8OWk)(RB|nS&f|t8s{LLlQ?0 zx7|qM$l>+|Dh_iGtepP>6$jai9BvHI1D0UwVd;beDvqvR1S*cMUIr?TuHF<$9CRuV ztX#E&io?v&05KRC7$TwKAajt_r$WU+%0Tg(0AesOFyx?#!@{{5Dh@ISIh?z2h|k0! zz8{D9WgOzqafp9H5=V~5??~dv@u&ek014zxkbhzRGJuMM{DmBkHc)Yx`Y9j=0|SE# zR2*G>ERy(Sq;^ypk~nhsH$lZg#)8~47sOy-VCX~>hq-eGR2*b4a`-RDA$}Hz_(L4x zZ;-^1!}BAOIC6NZLa$Z<xd*wwZwM6!c?aY#nENfE;vn_N;p_?(hpC5!voBN}U40Ca zIP&;*22>no&H)gEfq|hCDh@ISS$!*19Hb27P7Y8($H2fa4JwYVem+zjrrrapei@oL z%)eWq;vjR7<Ld|x@yj^Gf8r45h2C?GZoVQ8aUCRa<oGp25=V~TB&aydzr|4hW<kY4 z_9Dk)8B`oyeH~OBU40i+99{h+s5rX%c~Eh5^~<2*=<0VNiGxllgO!uVpyDud%Ax)` z2NegIgIs^zf{Me`H$c^YfQp0EBb)yRDh^Y>8mgWJdJrQ>J+k=%P;r?04N&!JP;roY zWb=)n;xP5Mpz5ul;vn_N=DR_~Vd@`1)%&7}!_sXGR2*aua=OjNAzp<;yc37`dK}`1 zafn~XA^sYN_%|eR<aGWUNgO$y>p-t|f`t!kT+{?A4hje4bPl`M5?#Fq4)q~Wadh=D zP;qqgGoa$=>I<Oa=;}L>#6feluyj5ZDh@M;2ik9(3l#^MgPcxQLd9X~1)%DWK*d4o zk<GsV6^E&ZrSlt5agcgs^FilHBabIIK+XS;q#oIPZs^roF!OVv>V=`==;q5q#bN3T zpz77o#9`^&6e<of2RWU);1CbSA)bUoyaR{$930{saEKqlA$}f7966m|K@vw!=d92R z7GU86OXs{$aZorQr*lcDI7~fk{9h3&j;`JSNgTO7V2>mYIu#O@J_DfQF!L8c<0}y= z4l*BEeK8L47N|JPoCi>Irb5Nh%~=K&hpFd)_Vd@GiNn i6T9OQIz8i)8T9OAI6 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 literal 0 HcmV?d00001 diff --git a/ZTestSuite/obj/x86-64/release/Test-ZBasicStringAlgo.o b/ZTestSuite/obj/x86-64/release/Test-ZBasicStringAlgo.o new file mode 100644 index 0000000000000000000000000000000000000000..c18f0249a251706aab0a4b20661a73f230ebbcba GIT binary patch literal 385352 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 literal 0 HcmV?d00001 diff --git a/ZTestSuite/obj/x86-64/release/Test-ZConcurrency.o b/ZTestSuite/obj/x86-64/release/Test-ZConcurrency.o new file mode 100644 index 0000000000000000000000000000000000000000..bfcea94b9a10365abc95e839cc4e4acfd1ef5a51 GIT binary patch literal 11352 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 literal 0 HcmV?d00001 diff --git a/ZTestSuite/obj/x86-64/release/Test-ZHashMap.o b/ZTestSuite/obj/x86-64/release/Test-ZHashMap.o new file mode 100644 index 0000000000000000000000000000000000000000..58df8d7b47d90ae394049ff35d046a2a536dd3f5 GIT binary patch literal 170808 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 z%0D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 E0GH39S^xk5 literal 0 HcmV?d00001 diff --git a/ZTestSuite/obj/x86-64/release/Test-ZIniReader.o b/ZTestSuite/obj/x86-64/release/Test-ZIniReader.o new file mode 100644 index 0000000000000000000000000000000000000000..92f6713ff57b818d0e5ca649aa98807e19727616 GIT binary patch literal 98160 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 J*#~2TXaJWymAC)^ literal 0 HcmV?d00001 diff --git a/ZTestSuite/obj/x86-64/release/Test-ZIniWriter.o b/ZTestSuite/obj/x86-64/release/Test-ZIniWriter.o new file mode 100644 index 0000000000000000000000000000000000000000..d60f4829c9a2b6417ec0db7e7ffc2b452f1bc30c GIT binary patch literal 31840 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 literal 0 HcmV?d00001 diff --git a/ZTestSuite/obj/x86-64/release/Test-ZJSONReader.o b/ZTestSuite/obj/x86-64/release/Test-ZJSONReader.o new file mode 100644 index 0000000000000000000000000000000000000000..0446c293f133837a3c79a6d7839a79fb8dc5b2fe GIT binary patch literal 2944 zcmb<-^>JfjWMqH=Mg}_u1P><4z|g>sU^{@B4h#YeybPfpolkdw__2r4m>$h<1UhT~ zbe8^TuKmMUs@_=p<NtpKhEloxAmuMW#4ZrA4@4luCY%Htv=5|qKgcC7*8l(iKlU(4 z6%{ZO%#0|nV1K`$)Wnq3A}fX9(&XgS;^MT@90i~J#1sY;Nw>tzoYWKy35F1V7k`*( z3=Hnh&Q=N<p-H8AC8Y|cdM0`Xx@M(do?)G#nVx}(o|z^@T*1h|(9FQhz!Icc1Vk_} zFfdjHF)&sLFiP{Vb4*}lV31*eV30I7h;ZZ+Xk&8bWpm?U=YY!DfW#RX7;wqQK;`W~ zG)#XbLVpcNoPmKs6hy=110eDsA#4~FBP<Lb|6`M5#+q^%7?>HDu_<R@W?;o3&W0f_ z1_~nvggD3@AVs=hafCTAaZuPWA-M+}MhpxL!3+!xAaNKUMrT6BLH2;m1&0{}1H(+H zcnC-k7FJL;GXqklfQo@AW(F=0g@KtNF@;5(6GLnT0|SE~Qn)EVRqTa|!}t<V@pB9e z3<6L#GW8534o~z5na?0`1Q*WYX2fm|Lr7|Ii7ryU&`T~TV2F?MGl>cg@$oS<@XRYq z%*jj%$S-zfh>r>`@v(@H&&<!v%Pe7tkMc1zD@iRbi3epaXkIG=3!B1)A-N1BYGN24 zUtE${l9?P2(w>=^lUbEml9`_upO}{tpORW!QdF7@<{M;YGQ_+4_&YiJ#K#wxCdGTk zBe^g%FS7*X>SE;V3=xQr@(V7p$jmQ}Pf9FKHSx^LEO9n;En|p}Pbtoi&q&Nm$w>uy z4qcH8L{V}@VtisrYDH!VJOzVd9Fz*3p&<#23v_W4s60rV1<D3d;KBf$))*Ls7#JA- z{D%NoIs~Z~1}TJMm^~nIWOF>A@*r_o*#Z*s1rbp5LHQkKK2#W-Q$X&A<sVQP1Cj&r zk&_S1Um$UidO46H1_lOLIs}P>)Wh->ES-YHVR}JYG(ZG6?=pbH&>YH#Q6Tjob71)n zW)4UUgkkC+brC2}Lom$V1gHX#S`dci>jpG&nE4EP#g(}wiAfB4#U(`$Is?WkO3g{s zD@m;=VbB9JQxZ!O8T68hiy8Ea@*y0sI4HHoCl(bYRx;=%=jZ08=9Mt$<>i;8>bd)c z>K2zICTBxUNX>{(D@x2wg*t`;3KTA&utJoK5W`^M0xH)aA`lX!7Q%v%(hLj?p!5S% z4-sWxZ~#Rv0|UbWr~n@{u3+f`7T?-Xar6=%rq2SZA4Y-P3uA+5H5~TCiuws4MGOoK zAp1dfpxbZAz`y_!1Ia;^f~g;1k^!8qp-eD^?te3=`$1_0tN=>D^uzKKR2aiNP(FmY z4W<S}J3uW0xedgJVRSwye`5>(3D5|Ig)_(wP;CR#4-*HqKtNU*z$}2$9w0#m1_o0o zA4Wli;r@t#`X43_qibObVFFMZT{su2A3gjUpbBR|^}#5Z`(gYH9Pz&b>VH^12KgV9 zw_*BW{ug8bwJ%_%A!rUzU@<T-lp}<|EU2@<Y!CtBqq`j>E&&x3fYSWX`V!rKP|b~= W_CWeIK#>Y67eN+)1fUp=%K!iYP8PfX literal 0 HcmV?d00001 diff --git a/ZTestSuite/obj/x86-64/release/Test-ZJSONWriter.o b/ZTestSuite/obj/x86-64/release/Test-ZJSONWriter.o new file mode 100644 index 0000000000000000000000000000000000000000..786adce6b255c9080147a91ce506c3a0c0689d7b GIT binary patch literal 2944 zcmb<-^>JfjWMqH=Mg}_u1P><4z|g>sU^{@B4h#YeybPfpolkdw__2r4m>$h<1UhT~ zbe8^TuKmMUs@_=p<NtpKhEloxAmuMW#4ZrA4@4luCY%Htv=5|qKgcC7*8l(iKlU(4 z6%{ZO%#0|nV1K{xqRf)iA}fX9(&XgS;^MT@90i~J#1sY;Nw>tzoYWKy35F1V7k`*( z3=Hnh&Q=N<p-H8AC8Y|cdM0`Xx@M(do?)G#nVx}(o|z^@T*1h|(9FQhz!Icc1Vk_} zFfdjHF)&sLFiP{Vb4*}lV31*eV30I7h;ZZ+Xk&8bWpm?U=YY!DfW#RX7;wqQK;`W~ zG)#XbLVpcNoPmKs6hy=110eDsA#4~FBP<Lb|6`M5#+q^%7?>HDu_<R@W?;o3&W0f_ z1_~nvggD3@AVs=hafCTAaZuPWA-M+}MhpxL!3+!xAaNKUMrT6BLH2;m1&0{}1H(+H zcnC-k7FJL;GXqklfQo@AW(F=0g@KtNF@;5(6GLnT0|SE~Qn)EVRqTa|!}t<V@pB9e z3<6L#GW8534o~z5na?0`1Q*WYX2fm|Lr7|Ii7ryU&`T~TV2F?MGl>cg@$oS<@XRYq z%*jj%$S-zfh>r>`@v(@H&&<!v%Pe7tkMc1zD@iRbi3epaXkIG=3!B1)A-N1BYGN24 zUtE${l9?P2(w>=^lUbEml9`_upO}{tpORW!QdF7@<{M;YGQ_+4_&YiJ#K#wxCdGTk zBe^g%FS7*X>SE;V3=xQr@(V7p$jmQ}Pf9FKHSx^LEO9n;En|p}Pbtoi&q&Nm$w>uy z4qcH8L{V}@VtisrYDH!VJOzVd9Fz*3p&<#23v_W4s60rV1<D3d;KBf$))*Ls7#JA- z{D%NoIs~Z~1}TJMm^~nIWOF>A@*r_o*#Z*s1rbp5LHQkKK2#W-Q$X&A<sVQP1Cj&r zk&_S1Um$UidO46H1_lOLIs}P>)Wh->ES-YHVR}JYG(ZG6?=pbH&>YH#Q6Tjob71)n zW)4UUgkkC+brC2}Lom$V1gHX#S`dci>jpG&nE4EP#g(}wiAfB4#U(`$Is?WkO3g{s zD@m;=VbB9JQxZ!O8T68hiy8Ea@*y0sI4HHoCl(bYRx;=%=jZ08=9Mt$<>i;8>bd)c z>K2zICTBxUNX>{(D@x2wg*t`;3KTA&utJoK5W`^M0xH)aA`lX!7Q%v%(hLj?p!5S% z4-sWxZ~#Rv0|UbWr~n@{u3+f`7T?-Xar6=%rq2SZA4Y-P3uA+5H5~TCiuws4MGOoK zAp1dfpxbZAz`y_!1Ia;^f~g;1k^!8qp-eD^?te3=`$1_0tN=>D^uzKKR2aiNP(FmY z4W<S}J3uW0xedgJVRSwye`5>(3D5|Ig)_(wP;CR#4-*HqKtNU*z$}2$9w0#m1_o0o zA4Wli;r@t#`X43_qibObVFFMZT{su2A3gjUpbBR|^}#5Z`(gYH9Pz&b>VH^12KgV9 zw_*BW{ug8bwJ%_%A!rUzU@<T-lp}<|EU2@<Y!CtBqq`j>E&&x3fYSWX`V!rKP|b~= W_CWeIK#>Y67eN+)1fUp=%K!j<q8GRT literal 0 HcmV?d00001 diff --git a/ZTestSuite/obj/x86-64/release/Test-ZKVTree.o b/ZTestSuite/obj/x86-64/release/Test-ZKVTree.o new file mode 100644 index 0000000000000000000000000000000000000000..b956c2d98e3dec770742c7eef691f9e72135d916 GIT binary patch literal 130736 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 literal 0 HcmV?d00001 diff --git a/ZTestSuite/obj/x86-64/release/Test-ZList.o b/ZTestSuite/obj/x86-64/release/Test-ZList.o new file mode 100644 index 0000000000000000000000000000000000000000..0a7ebc7b8e412b010c9cdb928ea61454ce11ace6 GIT binary patch literal 88224 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 literal 0 HcmV?d00001 diff --git a/ZTestSuite/obj/x86-64/release/Test-ZListAlgo.o b/ZTestSuite/obj/x86-64/release/Test-ZListAlgo.o new file mode 100644 index 0000000000000000000000000000000000000000..e40844ce365168efbaee31ef2639fc04b8952c4b GIT binary patch literal 120792 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 CerSOJ literal 0 HcmV?d00001 diff --git a/ZTestSuite/sst_fs/file1.txt b/ZTestSuite/sst_fs/file1.txt new file mode 100644 index 0000000..c928413 --- /dev/null +++ b/ZTestSuite/sst_fs/file1.txt @@ -0,0 +1 @@ +01234567890123456789012345678901 \ No newline at end of file diff --git a/ZTestSuite/sst_fs/file2.txt b/ZTestSuite/sst_fs/file2.txt new file mode 100644 index 0000000..e69de29 diff --git a/ZTestSuite/test1.xml b/ZTestSuite/test1.xml new file mode 100644 index 0000000..1bbcc75 --- /dev/null +++ b/ZTestSuite/test1.xml @@ -0,0 +1,40 @@ +<?xml version="1.0"?> +<building> + <assetInfo> + <version specRev="1" /> + <authoring name="Chris Ertel" email="crertel@www.762studios.com" copyright="Copyright 2010" license="CCSA"/> + <title string="ZomCo office"/> + <validationFlags unique="false" maxSeen="12" /> + </assetInfo> + + <assetDependencies> + <dependency package="textures\houseWalls"/> + <dependency package="textures\houseFloors"/> + <dependency package="objects\houseAppliances"/> + </assetDependencies> + + <construction> + <walls> + <wallSegment wallType="Stucco3" fromSpot="3,3" toSpot="3,6" baseAltitude="0" wallHeight="2"/> + </walls> + + <floors> + <floorSegment floorType="Stucco3" NWCorner="3,3" SECorner="6,6" baseAltitude="0" /> + </floors> + + <ceilings> + <ceilingSegment ceilingType="Stucco3" NWCorner="3,3" SECorner="6,6" baseAltitude="0" /> + </ceilings> + </construction> + + <layout> + <space spaceType="Living roomId" NWCorner="3,3" SECorner="6,6" baseAltitude="0" Height="3"/> + <space spaceType="Kitchen" NWCorner="3,3" SECorner="6,6" baseAltitude="0" Height="3"/> + <space spaceType="Bed roomId" NWCorner="3,3" SECorner="6,6" baseAltitude="0" Height="3"/> + </layout> + + <furnishings> + <object name="smallLamp" pos="24.42,43.32,239.15" rot=".4324 .24232 .12342 .23432" /> + <object name="book" pos="24.42,43.32,239.15" rot=".4234 .4323 .12364 .8654" /> + </furnishings> +</building> \ No newline at end of file diff --git a/ZTestSuite/testAttributes.xml b/ZTestSuite/testAttributes.xml new file mode 100644 index 0000000..5ab083f --- /dev/null +++ b/ZTestSuite/testAttributes.xml @@ -0,0 +1,18 @@ +<?xml version="1.0" ?> +<!-- +This is a sample XML file for testing attributes. + +It has multiple elements, testing string, real, integer, body text, and boolean attributes. +--> +<collection> + <speech> + "For score and seven years ago, our forefathers in order to form a more perfect union brought + forth on this Earth a great nation." + </speech> + <speech author="Nixon, D." published="1860" approvalRating=".5" veracity="false"> + "I am not a crook." + </speech> + <speech author="Chaplin, Charlie" published="1860" approvalRating="3" veracity="bogus"/> + <speech author="" published="bogus" approvalRating="bogus" veracity="bogus"> + </speech> +</collection> \ No newline at end of file diff --git a/ZUtil/Makefile b/ZUtil/Makefile new file mode 100644 index 0000000..fa60ddc --- /dev/null +++ b/ZUtil/Makefile @@ -0,0 +1,54 @@ +# ZUtil//Makefile +# Makefile for ZUtil, requires GNU "make" + +BINNAME := $(DIST)/libZUtil.a +ifeq ($(TARGET),debug) + BINNAME := $(subst .a,_d.a, $(BINNAME)) +endif + +SRC := \ + ZAlloc.cpp \ + ZAllocWindow.cpp \ + ZBinaryFileReader.cpp \ + ZBinaryFileWriter.cpp \ + ZBinaryBufferReader.cpp \ + ZBinaryBufferWriter.cpp \ + ZConcurrency.cpp \ + ZEvent.cpp \ + ZIniReader.cpp \ + ZIniWriter.cpp \ + ZJSONReader.cpp \ + ZJSONWriter.cpp \ + ZKVTree.cpp \ + ZLog.cpp \ + ZMutex.cpp \ + ZName.cpp \ + ZRandomGenerator.cpp \ + ZReadWriteLock.cpp \ + ZRegistry.cpp \ + ZSemaphore.cpp \ + ZSimplexNoise.cpp \ + ZSimplexNoiseMap.cpp \ + ZTaskStream.cpp \ + ZThread.cpp \ + ZXMLReader.cpp \ + ZXMLWriter.cpp + + +OBJ := $(addprefix obj/$(ARCH)/$(TARGET)/,$(subst .cpp,.o,$(SRC)) ) + +$(shell mkdir -p obj/$(ARCH)/$(TARGET)) + +$(BINNAME): $(OBJ) + $(AR) cru $@ $+ + $(RANLIB) $@ + +# CLEAN +clean: + @-rm -r -f obj $(DIST)/libZUtil*.a + + +# *.cpp files to *.o files +obj/$(ARCH)/$(TARGET)/%.o: %.cpp + @echo CXX $@ + @$(CXX) $(CXXFLAGS) -c $*.cpp -o obj/$(ARCH)/$(TARGET)/$*.o diff --git a/ZUtil/ZAlloc.cpp b/ZUtil/ZAlloc.cpp new file mode 100644 index 0000000..64663a2 --- /dev/null +++ b/ZUtil/ZAlloc.cpp @@ -0,0 +1,288 @@ +#include <stdlib.h> +#include <string.h> /* memmove() */ +#include <iostream> + +#include <SST/SST_Concurrency.h> + +#include <ZUtil/ZAlloc.hpp> + +SST_Mutex AllocLock = SST_Concurrency_CreateMutex(); + +#if ZALLOC_CHECK_ALLOC + +static ZAllocInfo* AllocList = NULL; + +int ZAllocInfo::CurrentAllocCount = 0; +int ZAllocInfo::CurrentCheckpoint = 0; + +void ZAllocAddTrack(uintptr_t _address, size_t _size, const char *_file, int _line, int _checkpoint) +{ + ZAllocInfo *info = (ZAllocInfo*)malloc(sizeof(ZAllocInfo)); + size_t len = strlen(_file); + + info->Address = _address; + info->Size = _size; + + if(len > sizeof(info->File)-1) + len = sizeof(info->File)-1; + + memcpy(info->File, _file, len); + info->File[len] = '\0'; + + info->Line = _line; + info->Checkpoint = _checkpoint; + + info->Next = NULL; + + //Mutex may be NULL if doing pre-main() init + if (AllocLock) + SST_Concurrency_LockMutex(AllocLock); + + info->Next = AllocList; + AllocList = info; + + #if ZALLOC_EXTRA_SPAMMY + std::cerr << "Inc Alloc Count " << ZAllocInfo::CurrentAllocCount << " -> " << (ZAllocInfo::CurrentAllocCount+1) << std::endl; + #endif + + ZAllocInfo::CurrentAllocCount++; + + //Mutex may be NULL if doing pre-main() init + if (AllocLock) + SST_Concurrency_UnlockMutex(AllocLock); +} + +void ZAllocRemoveTrack(uintptr_t _address) +{ + //Mutex may be NULL if doing pre-main() init + if (AllocLock) + SST_Concurrency_LockMutex(AllocLock); + + ZAllocInfo *prev = NULL; + ZAllocInfo *cur = AllocList; + + while (cur != NULL) + { + if (cur->Address == _address) + { + if (prev == NULL) //i.e. removing head + AllocList = cur->Next; + else + prev->Next = cur->Next; //Remove "this" from the chain. link parent's next pointer to this one's next pointer so nobody has a reference to "this". + + free(cur); + + #if ZALLOC_EXTRA_SPAMMY + std::cerr << "Dec Alloc Count " << ZAllocInfo::CurrentAllocCount << " -> " << (ZAllocInfo::CurrentAllocCount-1) << std::endl; + #endif + + ZAllocInfo::CurrentAllocCount--; + + break; + } + + prev = cur; + cur = cur->Next; + } + + //Mutex may be NULL if doing pre-main() init + if (AllocLock) + SST_Concurrency_UnlockMutex(AllocLock); +} + +void ZAllocDumpUnfreed(ZMemState *_state) +{ + SST_Concurrency_LockMutex(AllocLock); + + size_t totalSize = 0; + int checkpoint = _state == NULL ? 0 : _state->Checkpoint; + + std::cerr << "--- ZAlloc Unfreed Memory Dump ---" << std::endl << std::endl; + std::cerr << ZAllocInfo::CurrentAllocCount << " Current Unfreed Allocations:" << std::endl; + + ZAllocInfo *cur = AllocList; + + while (cur != NULL) + { + if (cur->Checkpoint >= checkpoint) + { + std::cerr << cur->File << "\n\tLINE: " << cur->Line << "\n\tADDRESS " << (void*)cur->Address << " (" << cur->Size << " bytes) unfreed!" << std::endl; + totalSize += cur->Size; + } + + cur = cur->Next; + } + + std::cerr << "-----------------------------------------------------------\n"; + std::cerr << "Total Unfreed: " << totalSize << " bytes" << std::endl << std::endl; + + std::cerr << "--- End Unfreed Memory Dump ---" << std::endl; + + SST_Concurrency_UnlockMutex(AllocLock); +} + +//Debug Operator New +void * operator new(size_t _size, const char *_file, int _line, int _checkpoint) +throw() +{ + void *ptr = (void*)malloc(_size); + + ZAllocAddTrack((uintptr_t)ptr, _size, _file, _line, _checkpoint); + + return ptr; +} + +void * operator new[](size_t _size, const char* _file, int _line, int _checkpoint) +throw() +{ + void *ptr = (void*)malloc(_size); + + ZAllocAddTrack((uintptr_t)ptr, _size, _file, _line, _checkpoint); + + return ptr; +} + +//Debug Delete +void operator delete(void *_ptr, const char* _file, int _line, int _checkpoint) +{ + (void)_file; + (void)_line; + (void)_checkpoint; + + ZAllocRemoveTrack((uintptr_t)_ptr); + + free(_ptr); +} + +void operator delete[](void *_ptr, const char* _file, int _line, int _checkpoint) +{ + (void)_file; + (void)_line; + (void)_checkpoint; + + ZAllocRemoveTrack((uintptr_t)_ptr); + + free(_ptr); +} +#ifndef __sun /* TODO: some error with Solaris Studio C++ compiler. */ +void operator delete(void *_ptr) +{ + ZAllocRemoveTrack((uintptr_t)_ptr); + + free(_ptr); +} + +void operator delete[](void *_ptr) +{ + ZAllocRemoveTrack((uintptr_t)_ptr); + + free(_ptr); +} +#endif + +#endif + +///////////////////////////////////// +/* Static New Functions and Fields */ +///////////////////////////////////// + +//This contains all our statically allocated pointers +void **StaticAllocArray = NULL; + +//This is how many we can hold +int StaticAllocCapacity = 0; + +//This is how many we've got +int StaticAllocSize = 0; + +//This iterates and deletes +void ZAllocDeleteStatic(void) +{ + int i; + + //Mutex may be NULL if doing pre-main() init + if (AllocLock) + SST_Concurrency_LockMutex(AllocLock); + + //Iterate, delete, then delete our static alloc array + for (i = 0; i < StaticAllocSize; i++) + free(StaticAllocArray[i]); + + free(StaticAllocArray); + + StaticAllocArray = NULL; + StaticAllocCapacity = 0; + StaticAllocSize = 0; + + //Mutex may be NULL if doing pre-main() init + if (AllocLock) + SST_Concurrency_UnlockMutex(AllocLock); +} + +void ZAllocAddStaticPtr(void *_ptr) +{ + //Mutex may be NULL if doing pre-main() init + if (AllocLock) + SST_Concurrency_LockMutex(AllocLock); + + //If we need to, register with atexit to call ZAllocDeleteStatic + if (StaticAllocArray == NULL) + atexit(ZAllocDeleteStatic); + + //Check to see if StaticAllocArray is full + if (StaticAllocSize >= StaticAllocCapacity ) + { + //Allocate new one + size_t newCapacity = StaticAllocCapacity == 0 ? 128 : StaticAllocCapacity * 2; + void *temp = malloc(newCapacity * sizeof(void*)); + + //Make sure we don't need to crash hard here + if (temp == NULL) + { + std::cerr << "ZAlloc failed to allocate static tracking array!" << std::endl; + exit(-1); + } + + //Copy the old data in + memmove(temp, StaticAllocArray, StaticAllocSize * sizeof(void*)); + + //Free the old pointer + free(StaticAllocArray); + + //Reset our pointer + StaticAllocArray = (void**)temp; + } + + //Add new void* + StaticAllocArray[StaticAllocSize] = _ptr; + + //Increment size + StaticAllocSize++; + + //Mutex may be NULL if doing pre-main() init + if (AllocLock) + SST_Concurrency_UnlockMutex(AllocLock); +} + +//Static operator new +void * operator new(size_t _size, znew_static_t _staticAlloc) +{ + URFP(_staticAlloc); + + void *ptr = (void*)malloc(_size); + + ZAllocAddStaticPtr(ptr); + + return ptr; +} + +void * operator new[](size_t _size, znew_static_t _staticAlloc) +{ + URFP(_staticAlloc); + + void *ptr = (void*)malloc(_size); + + ZAllocAddStaticPtr(ptr); + + return ptr; +} diff --git a/ZUtil/ZAllocWindow.cpp b/ZUtil/ZAllocWindow.cpp new file mode 100644 index 0000000..8ce8b46 --- /dev/null +++ b/ZUtil/ZAllocWindow.cpp @@ -0,0 +1,230 @@ +#include <ZUtil/ZAllocWindow.hpp> +#include <ZUtil/ZAssert.hpp> + +#include <SST/SST_OS.h> + +#define ALLOC_BITS (0xF00D) // Used to flag a section of memory as 'allocated' +#define DEALLOC_BITS (0xDEAD) // Used to flag a section of memory as 'deallocated' +#define LOOP_BITS (0xCAB0) // Used to flag that the next allocated section is back at the beginning of the buffer + +/*************************************************************************/ + +ZAllocWindow::ZAllocWindow() +: Buffer(NULL), Begin(NULL), End(NULL), + BufferSize(0), bOwnsBuffer(true), + NumAllocs(0) +{ + +} + +/*************************************************************************/ + +ZAllocWindow::ZAllocWindow( size_t _buffersize ) +: Buffer(NULL), Begin(NULL), End(NULL), + BufferSize(_buffersize), bOwnsBuffer(true), + NumAllocs(0) +{ + Resize(_buffersize); +} + +/*************************************************************************/ + +ZAllocWindow::~ZAllocWindow() +{ + if (bOwnsBuffer) + free(Buffer); +} + +/*************************************************************************/ + +void* ZAllocWindow::Allocate( size_t _size ) +{ + // boundary is the location in memory that we cannot write past + uintptr_t boundary; + + // determine where our boundary is + uintptr_t pool_begin = (uintptr_t)Buffer; + uintptr_t pool_end = pool_begin + BufferSize; + uintptr_t ptr_begin = (uintptr_t)Begin; + uintptr_t ptr_end = (uintptr_t)End; + + boundary = (ptr_begin > ptr_end ? ptr_begin : + ptr_begin < ptr_end ? pool_end : + ( NumAllocs > 0 ? ptr_end : + pool_end ) ); + + // align segment to word boundary + uintptr_t seg_begin = (uintptr_t)End; + uintptr_t seg_end = (uintptr_t)SST_OS_AlignPtr((void*)(seg_begin + 2*sizeof(uint32_t) + _size), sizeof(void*)); + + // check segment against boundary + if (seg_end > boundary) { + + // if the segment has not just run up against the pool end, we are done + if (boundary != pool_end) { + return NULL; + } + + // signal a loop (if less than 'end') and check again + if (seg_begin < pool_end) { + uint32_t* ptr_32 = (uint32_t*)seg_begin; + ptr_32[0] = (uint32_t)LOOP_BITS; + } + + boundary = ptr_begin; + + seg_begin = pool_begin; + seg_end = (uintptr_t)SST_OS_AlignPtr((void*)(seg_begin + 2 * sizeof(uint32_t) + _size), sizeof(void*)); + } + + // check segment against boundary again + if (seg_end <= boundary) { + NumAllocs++; + + // set size as first element in block + uint32_t* ptr_32 = (uint32_t*)seg_begin; + ptr_32[0] = (uint32_t)ALLOC_BITS; + ptr_32[1] = (uint32_t)(seg_end - seg_begin); + + // set new End pointer to ptr_end + End = (void*)seg_end; + + // if End == BufferEnd, End == 0 + if (End == (void*)((uintptr_t)Buffer + (uintptr_t)BufferSize)) + End = Buffer; + + // return the address of the first non-reserved element of the segment + return &ptr_32[2]; + } + + return NULL; +} + +/*************************************************************************/ + +void ZAllocWindow::Deallocate( void* _data ) +{ + // check size before data + uint32_t* ptr_32 = (uint32_t*)((uintptr_t)_data - (2*sizeof(uint32_t))); + uint32_t flag = ptr_32[0]; + uint32_t size = ptr_32[1]; + + // quick sanity check + ZASSERT(flag == ALLOC_BITS, "ZAllocWindow passed invalid pointer to deallocate!"); + ZASSERT(size < BufferSize, "ZAllocWindow passed corrupted pointer to deallocate!"); + + // mark size slot as 'freed' + ptr_32[0] = (uint32_t)DEALLOC_BITS; + NumAllocs--; + + // see if this was the oldest allocated block, and start rolling up + if (ptr_32 == Begin) { + while (WHILE_TRUE) { + ptr_32 = (uint32_t*)Begin; + + // if begin is at or past end, loop to the beginning + if ((uintptr_t)ptr_32 >= ((uintptr_t)Begin + BufferSize)) { + Begin = Buffer; + continue; + } + + // determine flag (size if needed) + flag = ptr_32[0]; + + // if this is a loop flag, start again at the beginning + if (flag == LOOP_BITS) { + Begin = Buffer; + continue; + } + + // if this is a dealloc flag, dealloc the segment, increment Begin + if (flag == DEALLOC_BITS) { + size = ptr_32[1]; + + uintptr_t seg_start = (uintptr_t)ptr_32; + uintptr_t seg_end = seg_start + size; + + Begin = (void*)seg_end; + + #ifdef _DEBUG + ptr_32[1] = DEALLOC_BITS; + #endif + + continue; + } + + break; + } + } +} + +/*************************************************************************/ + +void ZAllocWindow::Reset() +{ + NumAllocs = 0; + Begin = Buffer; + End = Buffer; +} + +/*************************************************************************/ + +bool ZAllocWindow::Resize( size_t _newsize ) +{ + // don't resize if we have allocations or don't own the buffer + if (NumAllocs > 0 || !bOwnsBuffer) { + return false; + } + + // check newsize is zero to free everything + if (_newsize == 0) { + if (Buffer != NULL) { + free(Buffer); + Buffer = NULL; + } + return true; + } + + // free current buffer if not NULL + if (Buffer != NULL) { + free(Buffer); + } + + // allocate new buffer and return success / failure + Buffer = malloc(_newsize); + Begin = Buffer; + End = Buffer; + BufferSize = _newsize; + + return Buffer != NULL; +} + +/*************************************************************************/ + +bool ZAllocWindow::SetBuffer( void* _buffer, size_t _buffersize ) +{ + // don't accept buffer if we have allocations + if (NumAllocs > 0) { + return 0; + } + + // if the new buffer is null, just reallocate to buffersize + if (_buffer == NULL) { + bOwnsBuffer = true; + return Resize(_buffersize); + } + + // Get rid of the current buffer if we need to + if (Buffer != NULL) { + free(Buffer); + } + + // lose ownership and set parameters, return success + bOwnsBuffer = false; + Buffer = _buffer; + Begin = Buffer; + End = Buffer; + BufferSize = _buffersize; + + return true; +} diff --git a/ZUtil/ZBinaryBufferReader.cpp b/ZUtil/ZBinaryBufferReader.cpp new file mode 100644 index 0000000..5454459 --- /dev/null +++ b/ZUtil/ZBinaryBufferReader.cpp @@ -0,0 +1,148 @@ +/* + ZBinaryBufferReader.cpp + Author: Chris Ertel <crertel@762studios.com>, Patrick Baggett <ptbaggett@762studios.com> + Created: 3/6/2013 + + Purpose: + + Reads a binary stream from memory. + + License: + + TODO + +*/ + +#include <ZUtil/ZBinaryBufferReader.hpp> + +/*************************************************************************/ + +uint8_t ZBinaryBufferReader::ReadU8() +{ + uint8_t retval = (uint8_t)Data[Offset]; + + ++Offset; + + return retval; +} + +/*************************************************************************/ + +uint16_t ZBinaryBufferReader::ReadU16() +{ + uint16_t value; + memcpy(&value, GetPosition(), sizeof(uint16_t)); + + if(GetStreamByteOrder() != SST_BYTEORDER_HOST) + value = SST_OS_ByteSwap16(value); + + Offset += sizeof(uint16_t); + return value; +} + +/*************************************************************************/ + +uint32_t ZBinaryBufferReader::ReadU32() +{ + uint32_t value; + memcpy(&value, GetPosition(), sizeof(uint32_t)); + + if(GetStreamByteOrder() != SST_BYTEORDER_HOST) + value = SST_OS_ByteSwap32(value); + + Offset += sizeof(uint32_t); + return value; +} + +/*************************************************************************/ + +uint64_t ZBinaryBufferReader::ReadU64() +{ + uint64_t value; + memcpy(&value, GetPosition(), sizeof(uint64_t)); + + if(GetStreamByteOrder() != SST_BYTEORDER_HOST) + value = SST_OS_ByteSwap64(value); + + Offset += sizeof(uint64_t); + return value; +} + +/*************************************************************************/ + +void ZBinaryBufferReader::ReadU8Array(uint8_t* ptr, size_t count) +{ + memcpy(ptr, GetPosition(), count); + Offset += count; +} + +/*************************************************************************/ + +void ZBinaryBufferReader::ReadU16Array(uint16_t* ptr, size_t count) +{ + if(GetStreamByteOrder() == SST_BYTEORDER_HOST) + { + memcpy(ptr, GetPosition(), sizeof(uint16_t) * count); + Offset += sizeof(uint16_t) * count; + } + else + { + for(size_t i=0; i<count; i++) + ptr[i] = ReadU16(); + } +} + +/*************************************************************************/ + +void ZBinaryBufferReader::ReadU32Array(uint32_t* ptr, size_t count) +{ + if(GetStreamByteOrder() == SST_BYTEORDER_HOST) + { + memcpy(ptr, GetPosition(), sizeof(uint32_t) * count); + Offset += sizeof(uint32_t) * count; + } + else + { + for(size_t i=0; i<count; i++) + ptr[i] = ReadU32(); + } +} + +/*************************************************************************/ + +void ZBinaryBufferReader::ReadU64Array(uint64_t* ptr, size_t count) +{ + if(GetStreamByteOrder() == SST_BYTEORDER_HOST) + { + memcpy(ptr, GetPosition(), sizeof(uint64_t) * count); + Offset += sizeof(uint64_t) * count; + } + else + { + for(size_t i=0; i<count; i++) + ptr[i] = ReadU64(); + } +} + +/*************************************************************************/ + +void* ZBinaryBufferReader::ReadPointer() +{ + uintptr_t value; + memcpy(&value, GetPosition(), sizeof(uintptr_t)); + + if(GetStreamByteOrder() != SST_BYTEORDER_HOST) + { + switch(sizeof(uintptr_t)) + { + case sizeof(uint16_t): value = (uintptr_t)SST_OS_ByteSwap16((uint16_t)value); break; + case sizeof(uint32_t): value = (uintptr_t)SST_OS_ByteSwap32((uint32_t)value); break; + case sizeof(uint64_t): value = (uintptr_t)SST_OS_ByteSwap64((uint64_t)value); break; + } + } + + Offset += sizeof(uintptr_t); + return (void*)value; +} + +/*************************************************************************/ diff --git a/ZUtil/ZBinaryBufferWriter.cpp b/ZUtil/ZBinaryBufferWriter.cpp new file mode 100644 index 0000000..e86e873 --- /dev/null +++ b/ZUtil/ZBinaryBufferWriter.cpp @@ -0,0 +1,148 @@ +/* + ZBinaryBufferWriter.cpp + Author: Patrick Baggett <ptbaggett@762studios.com> + Created: 6/05/2013 + + Purpose: + + Writes a binary stream to memory + + License: + + TODO + +*/ + +#include <ZUtil/ZBinaryBufferWriter.hpp> + +/*************************************************************************/ + +void ZBinaryBufferWriter::WriteU8(uint8_t v) +{ + Data[Offset] = v; + ++Offset; +} + +/*************************************************************************/ + +void ZBinaryBufferWriter::WriteU16(uint16_t v) +{ + if(GetStreamByteOrder() != SST_BYTEORDER_HOST) + v = SST_OS_ByteSwap16(v); + + memcpy(Data+Offset, &v, sizeof(uint16_t)); + + Offset += sizeof(uint16_t); +} + +/*************************************************************************/ + +void ZBinaryBufferWriter::WriteU32(uint32_t v) +{ + if(GetStreamByteOrder() != SST_BYTEORDER_HOST) + v = SST_OS_ByteSwap32(v); + + memcpy(Data+Offset, &v, sizeof(uint32_t)); + + Offset += sizeof(uint32_t); + +} + +/*************************************************************************/ + +void ZBinaryBufferWriter::WriteU64(uint64_t v) +{ + if(GetStreamByteOrder() != SST_BYTEORDER_HOST) + v = SST_OS_ByteSwap64(v); + + memcpy(Data+Offset, &v, sizeof(uint64_t)); + + Offset += sizeof(uint64_t); +} + +/*************************************************************************/ + +void ZBinaryBufferWriter::WriteU8Array(const uint8_t* v, size_t count) +{ + memcpy(Data+Offset, v, count); + + Offset += sizeof(uint8_t) * count; +} + +/*************************************************************************/ + +void ZBinaryBufferWriter::WriteU16Array(const uint16_t* v, size_t count) +{ + if(GetStreamByteOrder() == SST_BYTEORDER_HOST) + memcpy(Data+Offset, v, count*sizeof(uint16_t)); + else + { + for(size_t i=0; i<count; i++) + { + uint16_t value = SST_OS_ByteSwap16(v[i]); + memcpy(Data+Offset+i*sizeof(uint16_t), &value, sizeof(uint16_t)); + } + } + + Offset += sizeof(uint16_t) * count; +} + +/*************************************************************************/ + +void ZBinaryBufferWriter::WriteU32Array(const uint32_t* v, size_t count) +{ + if(GetStreamByteOrder() == SST_BYTEORDER_HOST) + memcpy(Data+Offset, v, count*sizeof(uint32_t)); + else + { + for(size_t i=0; i<count; i++) + { + uint32_t value = SST_OS_ByteSwap32(v[i]); + memcpy(Data+Offset+i*sizeof(uint32_t), &value, sizeof(uint32_t)); + } + } + + Offset += sizeof(uint32_t) * count; +} + +/*************************************************************************/ + +void ZBinaryBufferWriter::WriteU64Array(const uint64_t* v, size_t count) +{ + if(GetStreamByteOrder() == SST_BYTEORDER_HOST) + memcpy(Data+Offset, v, count*sizeof(uint16_t)); + else + { + for(size_t i=0; i<count; i++) + { + uint64_t value = SST_OS_ByteSwap64(v[i]); + memcpy(Data+Offset+i*sizeof(uint64_t), &value, sizeof(uint64_t)); + } + } + + Offset += sizeof(uint64_t) * count; +} + + +/*************************************************************************/ + +void ZBinaryBufferWriter::WritePointer(void* pointer) +{ + uintptr_t ptrValue = (uintptr_t)pointer; + + if(GetStreamByteOrder() == SST_BYTEORDER_HOST) + memcpy(Data+Offset, &ptrValue, sizeof(uintptr_t)); + else + { + switch(sizeof(uintptr_t)) + { + case sizeof(uint16_t): WriteU16((uint16_t)ptrValue); break; + case sizeof(uint32_t): WriteU32((uint32_t)ptrValue); break; + case sizeof(uint64_t): WriteU64((uint64_t)ptrValue); break; + } + } + + Offset += sizeof(uintptr_t); +} + +/*************************************************************************/ diff --git a/ZUtil/ZBinaryFileReader.cpp b/ZUtil/ZBinaryFileReader.cpp new file mode 100644 index 0000000..f804f5c --- /dev/null +++ b/ZUtil/ZBinaryFileReader.cpp @@ -0,0 +1,155 @@ +/* + ZBinaryFileReader.cpp + Author: Patrick Baggett <ptbaggett@762studios.com> + Created: 3/6/2013 + + Purpose: + + Reads a binary stream from a SST_File handle. NOTE: On 32-bit platforms, only files up to 4GB are supported. + + License: + + TODO + +*/ + +#include <ZUtil/ZBinaryFileReader.hpp> + +/*************************************************************************/ + +ZBinaryFileReader::ZBinaryFileReader(SST_File handle, SST_ByteOrder bo) +: ZBinaryReader(bo), fp(handle) +{ + uint64_t size64; + uint64_t offset64; + + SST_OS_GetFilePointer(fp, &offset64); + size64 = SST_OS_GetFileSize(fp); + + //Downcast (potentially) to size_t + Size = (size_t)size64; + Offset = (size_t)offset64; +} + +/*************************************************************************/ + +uint8_t ZBinaryFileReader::ReadU8() +{ + uint8_t retval; + + SST_OS_ReadFile(fp, &retval, sizeof(uint8_t)); + + ++Offset; + + return retval; +} + +/*************************************************************************/ + +uint16_t ZBinaryFileReader::ReadU16() +{ + uint16_t value; + + SST_OS_ReadFile(fp, &value, sizeof(uint16_t)); + + if(GetStreamByteOrder() != SST_BYTEORDER_HOST) + value = SST_OS_ByteSwap16(value); + + Offset += sizeof(uint16_t); + return value; +} + +/*************************************************************************/ + +uint32_t ZBinaryFileReader::ReadU32() +{ + uint32_t value; + SST_OS_ReadFile(fp, &value, sizeof(uint32_t)); + + + if(GetStreamByteOrder() != SST_BYTEORDER_HOST) + value = SST_OS_ByteSwap32(value); + + Offset += sizeof(uint32_t); + return value; +} + +/*************************************************************************/ + +uint64_t ZBinaryFileReader::ReadU64() +{ + uint64_t value; + SST_OS_ReadFile(fp, &value, sizeof(uint64_t)); + + + if(GetStreamByteOrder() != SST_BYTEORDER_HOST) + value = SST_OS_ByteSwap64(value); + + Offset += sizeof(uint64_t); + return value; +} + +/*************************************************************************/ + +void ZBinaryFileReader::ReadU8Array(uint8_t* ptr, size_t count) +{ + SST_OS_ReadFile(fp, ptr, count); + + Offset += count; +} + +/*************************************************************************/ + +void ZBinaryFileReader::ReadU16Array(uint16_t* ptr, size_t count) +{ + if(GetStreamByteOrder() == SST_BYTEORDER_HOST) + { + SST_OS_ReadFile(fp, ptr, sizeof(uint16_t) * count); + Offset += sizeof(uint16_t) * count; + } + else + { + for(size_t i=0; i<count; i++) + ptr[i] = ReadU16(); + } +} + +/*************************************************************************/ + +void ZBinaryFileReader::ReadU32Array(uint32_t* ptr, size_t count) +{ + if(GetStreamByteOrder() == SST_BYTEORDER_HOST) + { + SST_OS_ReadFile(fp, ptr, sizeof(uint32_t) * count); + Offset += sizeof(uint32_t) * count; + } + else + { + for(size_t i=0; i<count; i++) + ptr[i] = ReadU32(); + } +} + +/*************************************************************************/ + +void ZBinaryFileReader::ReadU64Array(uint64_t* ptr, size_t count) +{ + if(GetStreamByteOrder() == SST_BYTEORDER_HOST) + { + SST_OS_ReadFile(fp, ptr, sizeof(uint64_t) * count); + Offset += sizeof(uint64_t) * count; + } + else + { + for(size_t i=0; i<count; i++) + ptr[i] = ReadU64(); + } +} + +/*************************************************************************/ + +void ZBinaryFileReader::SeekTo(size_t offset) +{ + SST_OS_SeekFile(fp, (int64_t)offset, SST_SEEK_START); + Offset = offset; +} \ No newline at end of file diff --git a/ZUtil/ZBinaryFileWriter.cpp b/ZUtil/ZBinaryFileWriter.cpp new file mode 100644 index 0000000..184a356 --- /dev/null +++ b/ZUtil/ZBinaryFileWriter.cpp @@ -0,0 +1,160 @@ +/* + ZBinaryFileWriter.cpp + Author: Chris Ertel <crertel@762studios.com>, Patrick Baggett <ptbaggett@762studios.com> + Created: 3/11/2013 + + Purpose: + + Writes a binary stream from a SST_File handle. NOTE: On 32-bit platforms, only files up to 4GB are supported. + + License: + + TODO + +*/ + +#include <ZUtil/ZBinaryFileWriter.hpp> + +/* + TODO: This implementation makes use of SST_File, which is a thin wrapper over system calls. Because of this, + small writes can reduce performance. A 4KB buffer (or better, one that is a multiple of inode size) would + help reduce the overhead. +*/ + +/*************************************************************************/ + +ZBinaryFileWriter::ZBinaryFileWriter(SST_File handle, SST_ByteOrder bo) : +ZBinaryWriter(bo), fp(handle) +{ + uint64_t offset64; + + SST_OS_GetFilePointer(fp, &offset64); + + Offset = (size_t)offset64; + +} + +/*************************************************************************/ + +void ZBinaryFileWriter::WriteU8(uint8_t v) +{ + SST_OS_WriteFile(fp, &v, sizeof(uint8_t)); + + ++Offset; +} + +/*************************************************************************/ + +void ZBinaryFileWriter::WriteU16(uint16_t v) +{ + if(GetStreamByteOrder() != SST_BYTEORDER_HOST) + v = SST_OS_ByteSwap16(v); + + SST_OS_WriteFile(fp, &v, sizeof(uint16_t)); + + Offset += sizeof(uint16_t); +} + +/*************************************************************************/ + +void ZBinaryFileWriter::WriteU32(uint32_t v) +{ + if(GetStreamByteOrder() != SST_BYTEORDER_HOST) + v = SST_OS_ByteSwap32(v); + + SST_OS_WriteFile(fp, &v, sizeof(uint32_t)); + + Offset += sizeof(uint32_t); + +} + +/*************************************************************************/ + +void ZBinaryFileWriter::WriteU64(uint64_t v) +{ + if(GetStreamByteOrder() != SST_BYTEORDER_HOST) + v = SST_OS_ByteSwap64(v); + + SST_OS_WriteFile(fp, &v, sizeof(uint64_t)); + + Offset += sizeof(uint64_t); +} + +/*************************************************************************/ + +void ZBinaryFileWriter::WriteU8Array(const uint8_t* v, size_t count) +{ + SST_OS_WriteFile(fp, v, count); + + Offset += sizeof(uint8_t) * count; +} + +/*************************************************************************/ + +void ZBinaryFileWriter::WriteU16Array(const uint16_t* v, size_t count) +{ + if(GetStreamByteOrder() == SST_BYTEORDER_HOST) + SST_OS_WriteFile(fp, v, count * sizeof(uint16_t)); + else + { + for(size_t i=0; i<count; i++) + { + uint16_t value = SST_OS_ByteSwap16(v[i]); + SST_OS_WriteFile(fp, &value, sizeof(uint16_t)); + } + } + + Offset += sizeof(uint16_t) * count; + +} + +/*************************************************************************/ + +void ZBinaryFileWriter::WriteU32Array(const uint32_t* v, size_t count) +{ + if(GetStreamByteOrder() == SST_BYTEORDER_HOST) + SST_OS_WriteFile(fp, v, count * sizeof(uint32_t)); + else + { + for(size_t i=0; i<count; i++) + { + uint32_t value = SST_OS_ByteSwap32(v[i]); + SST_OS_WriteFile(fp, &value, sizeof(uint32_t)); + } + } + + Offset += sizeof(uint32_t) * count; + +} + +/*************************************************************************/ + +void ZBinaryFileWriter::WriteU64Array(const uint64_t* v, size_t count) +{ + if(GetStreamByteOrder() == SST_BYTEORDER_HOST) + SST_OS_WriteFile(fp, v, count * sizeof(uint64_t)); + else + { + for(size_t i=0; i<count; i++) + { + uint64_t value = SST_OS_ByteSwap64(v[i]); + SST_OS_WriteFile(fp, &value, sizeof(uint64_t)); + } + } + + Offset += sizeof(uint64_t) * count; + +} + + +/*************************************************************************/ + +void ZBinaryFileWriter::SeekTo(size_t offset) +{ + uint64_t offset64 = (uint64_t)offset; //Because size_t can be 32 bits, casting to int64_t can sign extend (bad), cast to uint64_t first so it is zero-extended. + SST_OS_SeekFile(fp, (int64_t)offset64, SST_SEEK_START); + + Offset = offset; +} + +/*************************************************************************/ diff --git a/ZUtil/ZConcurrency.cpp b/ZUtil/ZConcurrency.cpp new file mode 100644 index 0000000..5141432 --- /dev/null +++ b/ZUtil/ZConcurrency.cpp @@ -0,0 +1,50 @@ +#include <ZUtil/ZConcurrency.hpp> +#include <SST/SST_Concurrency.h> + +ZThreadContext ZConcurrency::CreateThread(int(*_func)(void*), void *_arg) +{ + ZThreadContext context; + + context.Thread = SST_Concurrency_CreateThread(_func, _arg); + + //TODO - this doesn't install the running thread id, just this current thread id + //bleargh + //context.ThreadId = SST_Concurrency_GetThreadId(); + + return context; +} + +void ZConcurrency::DestroyThread(ZThreadContext& _context) +{ + SST_Concurrency_DestroyThread(_context.Thread); + + _context.Thread = NULL; + _context.ThreadId = 0; + _context.ThreadExitStatus = 0; +} + +void ZConcurrency::SleepThread(uint32_t _ms) +{ + SST_Concurrency_SleepThread(_ms); +} + +uint32_t ZConcurrency::GetThreadId() +{ + return SST_Concurrency_GetThreadId(); +} + +uint64_t ZConcurrency::GetTicks() +{ + return SST_Concurrency_GetTicks(); +} + +bool ZConcurrency::WaitThread(ZThreadContext& _context) +{ + return SST_Concurrency_WaitThread(_context.Thread, &_context.ThreadExitStatus) != 0; +} + +void ZConcurrency::YieldThread() +{ + SST_Concurrency_YieldThread(); +} + diff --git a/ZUtil/ZEvent.cpp b/ZUtil/ZEvent.cpp new file mode 100644 index 0000000..50ec7b6 --- /dev/null +++ b/ZUtil/ZEvent.cpp @@ -0,0 +1,34 @@ +#include <ZUtil/ZEvent.hpp> +#include <ZUtil/ZAssert.hpp> +#include <SST/SST_Concurrency.h> //Need this for SST_WAIT_INFINITE + +ZEvent::ZEvent() +: Event(SST_Concurrency_CreateEvent()) +{ + ZASSERT_RUNTIME(Event != NULL, "ZEvent failed to allocate event from libsst-concurrency!"); +} + +ZEvent::~ZEvent() +{ + SST_Concurrency_DestroyEvent(Event); +} + +void ZEvent::Notify() +{ + SST_Concurrency_SignalEvent(Event); +} + +void ZEvent::Reset() +{ + SST_Concurrency_ResetEvent(Event); +} + +bool ZEvent::Wait() +{ + return SST_Concurrency_WaitEvent(Event, SST_WAIT_INFINITE) != 0; +} + +bool ZEvent::Wait( uint32_t _ms ) +{ + return SST_Concurrency_WaitEvent(Event, _ms) != 0; +} diff --git a/ZUtil/ZIniReader.cpp b/ZUtil/ZIniReader.cpp new file mode 100644 index 0000000..525facd --- /dev/null +++ b/ZUtil/ZIniReader.cpp @@ -0,0 +1,256 @@ +#include <ZUtil/ZIniReader.hpp> + +#include <ZSTL/ZBasicStringAlgo.hpp> + +bool ZIniReader::Read(const char* data, size_t length) +{ + /* + Algorithm: + 1) Read a line, ignore blank lines and comment lines + 2) If line is KVP + 2.1) No section? -> Error + 2.2) Section exists? -> Parse KVP + 2.2.1) Takes form of K = V? -> Add KVP + 2.2.2) Doesn't? -> Error + 3) Else if section + 3.1) If already seen section -> Error + 3.2) Create section hashtable, insert it + 4) Next line + */ + + ClearData(); + ErrorMessage.Clear(); + + ZHashMap<ZString, ZString>* currentSection = NULL; + + size_t i = 0; //Current index into file data + size_t lineStart = 0; //Start of line + size_t lineLength; + uint32_t lineNumber = 1; + + //Parse loop + while(i < length) + { + char c = data[i]; + i++; + + //Treat final character as EOL too + if(i < length) + { + //Split on \n or \r + if(c != 0x0A && c != 0x0D) + continue; + else //Found EOL character + { + //Line length does NOT include EOL character + lineLength = i - 1 - lineStart; + } + } + else //Final line, don't remove extra character + lineLength = i - lineStart; + + //Line must be non-blank + if(lineLength > 0 && data[lineStart] != '\n') + { + //Get pointer to start of line + const char* line = &data[lineStart]; + + //Ignore comments + if(line[0] != ';' && line [0] != '#') + { + //Section name + if(line[0] == '[') + { + size_t j=1; //Start after '[' + //Read until closing '] or EOL + while(j<lineLength && line[j] != ']') + { + if(!isalnum(line[j]) && line[j] != '_' && line[j] != ' ') + { + SetError("Header must contain alphanumeric, space, or _ only", lineNumber); + return false; + } + j++; + } + + //Reached end of line but no terminator + if(j == lineLength) + { + SetError("Missing closing \']\'", lineNumber); + return false; + } + + //Copy section name to ZString + ZString sectionName(line+1, j-1); + + //Check for existence + if(StringSectionMap.ContainsKey(sectionName)) + { + SetError("Section already exists", lineNumber); + return false; + } + + //Construct new table + ZHashMap<ZString, ZString>* table = new(std::nothrow) ZHashMap<ZString, ZString>(); + if(table != NULL) + { + //Add mapping + StringSectionMap.Put(sectionName, table); + Sections.PushBack(table); + SectionNames.PushBack(sectionName); + + //Save this as the current section + currentSection = table; + } + else + { + SetError("Out of memory", lineNumber); + return false; + } + } + else if(!isspace(line[0])) //Not a space, not comment, not section -> KVP + { + //Did we find a section first? + if(currentSection != NULL) + { + size_t j=0; //length of key + + //Scan until space, equals sign, or EOL + while(j<lineLength && line[j] != '=' && !isspace(line[j])) + { + if(!isalnum(line[j]) && line[j] != '_') + { + SetError("Key must contain alphanumeric or '_' only", lineNumber); + return false; + } + j++; + } + + //Didn't find either a space or '=' + if(j == lineLength) + { + SetError("Missing '=' after key name", lineNumber); + return false; + } + + //Copy key to ZString + ZString key(line, j); + + if(line[j] != '=') + { + //Skip remaining whitespace + while(j<lineLength && isspace(line[j])) + j++; + + if(j == lineLength || line[j] != '=') + { + SetError("Missing '=' after key name", lineNumber); + return false; + } + } + + //Now we definitely point to a '=' character. Ensure there is data after it + if(j+1 == lineLength) + { + SetError("Expected value after '='", lineNumber); + return false; + } + j++; + + //Skip any whitespace after '=' + while(j<lineLength && isspace(line[j])) + j++; + + //Special case: if we hit EOL, then we have an empty value + if(j == lineLength) + { + currentSection->Put(key, ""); + } + else + { + ZString val(&line[j], lineLength-j); + currentSection->Put(key, val); + } + } + else + { + SetError("Values must be in a section", lineNumber); + return false; + } + + } + else + { + SetError("Invalid line. Must be a section, comment, or value", lineNumber); + return false; + } + } + } //if(non-blank line) + + //Check for \r \n pattern + if(c == '\r') //we expect a \n, but verify + { + if(i < length && data[i] == '\n') + i++; + } + + //Start on next line + lineStart = i; + lineNumber++; + } + + return !Sections.Empty(); +} + +/*************************************************************************/ + +const ZHashMap<ZString, ZString>* ZIniReader::GetSection(const ZString& sectionName) +{ + ZHashMap<ZString, ZHashMap<ZString, ZString>* >::Iterator it = StringSectionMap.Find(sectionName); + + if(it.HasCurrent()) + return it.GetValue(); + + return NULL; +} + +/*************************************************************************/ + +void ZIniReader::SetError(const char* message, uint32_t line) +{ + ZStringAlgo::BuildPrintf(ErrorMessage, "Line %u: %s", line, message); + + //Clear all data + ClearData(); +} + +/*************************************************************************/ + +void ZIniReader::ClearData() +{ + for(size_t i = 0; i < Sections.Size(); i++) + delete Sections[i]; + + Sections.Clear(); + SectionNames.Clear(); + StringSectionMap.Clear(); +} + +/*************************************************************************/ + +void ZIniReader::GetKVTree(ZKVTree& _kvtree) +{ + for(size_t i = 0; i < Sections.Size(); i++) + { + ZHashMap<ZString, ZString>* hmap = Sections[i]; + ZHashMap<ZString, ZString>::Iterator it = hmap->Begin(); + + for(; it != hmap->End(); ++it) + { + ZString key = SectionNames[i]+"."+it.GetKey(); + ZString& value = it.GetValue(); + + _kvtree.Put(key, value); + } + } +} diff --git a/ZUtil/ZIniWriter.cpp b/ZUtil/ZIniWriter.cpp new file mode 100644 index 0000000..fb00e4c --- /dev/null +++ b/ZUtil/ZIniWriter.cpp @@ -0,0 +1,68 @@ +#include <ZUtil/ZIniWriter.hpp> + +#include <ZSTL/ZString.hpp> + +/*************************************************************************/ + +const ZString& ZIniWriter::GetErrorString() +{ + return ErrorMessage; +} + +/*************************************************************************/ + +bool ZIniWriter::Write( const ZKVTree& _kvtree, ZString& _output ) +{ + ErrorMessage.Clear(); + + ZKVTree::Iterator itr = _kvtree.Begin(); + + if (itr == _kvtree.End()) + { + ErrorMessage = "ZIniWriter: KV Tree has no data!"; + return false; + } + + //Each node name at this level is a section + for (size_t i = 0; i < itr.GetSiblingCount(); i++) + { + //Append the name in [Section] form + _output.PushBack('['); + + ZStringAlgo::Append(_output, itr.GetName()); + + _output.PushBack(']'); + + ZStringAlgo::Append(_output, LINE_TERMINATOR); + + //Iterate the kids (the kids!) + if (itr.CheckChild()) + { + itr.Child(); + + //Each node at this level is a key/value pair + for (size_t j = 0; j < itr.GetSiblingCount(); j++) + { + //Append the kid in key=value form + ZStringAlgo::Append(_output, itr.GetName()); + + _output.PushBack('='); + + ZStringAlgo::Append(_output, itr.GetValue()); + ZStringAlgo::Append(_output, LINE_TERMINATOR); + + if (itr.CheckNextSibling()) + itr.NextSibling(); + } + + itr.Parent(); + } + + ZStringAlgo::Append(_output, LINE_TERMINATOR); + + if (itr.CheckNextSibling()) + itr.NextSibling(); + } + + return true; +} diff --git a/ZUtil/ZJSONReader.cpp b/ZUtil/ZJSONReader.cpp new file mode 100644 index 0000000..98ae549 --- /dev/null +++ b/ZUtil/ZJSONReader.cpp @@ -0,0 +1,81 @@ +#include <ZUtil/ZJSONReader.hpp> + +#include <ZSTL/ZString.hpp> +#include <ZSTL/ZBasicStringAlgo.hpp> +#include <jansson.h> + +/* iterate over the values, adding to the KVTree as needed */ +static void recurse_and_populate ( json_t* _object, void* _itr, ZKVTree& _storage, ZString _currPath ) +{ + /* for each key-value pair in the object...*/ + while (_itr != NULL) + { + json_t* val = json_object_iter_value(_itr); + + if ( json_is_array ( val ) ) + { + + /* + TODO: + What happens if we have an array of arrays? An array of objects? + */ + size_t arraySize = json_array_size(val); + for (size_t i = 0; i < arraySize; i++) + { + ZBasicStringAlgo::BuildPrintf(_currPath,"%s.%s[%d]", _currPath.Data(), json_object_iter_key(_itr), i ); + json_t* data = json_array_get(val, i); + _storage.Put( _currPath, json_string_value(data) ); + } + } + else if ( json_is_object( val ) == false) + { + /* store the pair if it just a value...*/ + ZBasicStringAlgo::BuildPrintf(_currPath,"%s.%s", _currPath.Data(), json_object_iter_key(_itr) ); + json_t* data= json_object_iter_value( _itr ); + _storage.Put( _currPath, json_string_value(data) ); + } + else + { + /*...or parse it if it isn't */ + _currPath = ZString( json_object_iter_key(_itr)) + "."; + recurse_and_populate( _object, _itr, _storage, _currPath ); + } + + _itr = json_object_iter_next( _object, _itr ); + } +} + +ZJSONReader::ZJSONReader(const ZString& _jsonData) +: ErrorMessage(), JSONData(_jsonData), Registry(new (std::nothrow) ZKVTree()) +{ + json_t* rootNode; + + if (Registry == NULL) + { + ErrorMessage = "ZJSONReader: unable to create registry!"; + return; + } + + /* have Jansson parse the string out and make an object */ + json_error_t error; + rootNode = json_loads( _jsonData.Data(), 0, &error); + if (rootNode == NULL) + { + ZBasicStringAlgo::BuildPrintf(ErrorMessage, "ZJSONReader: %s on line %d", error.text, error.line); + return; + } + + /* now, we parse it out */ + void* itr = json_object_iter(rootNode); + recurse_and_populate( rootNode, itr, *Registry, ""); +} + +const ZString& ZJSONReader::GetErrorString() +{ + return this->ErrorMessage; +} + +ZPtr<ZKVTree> ZJSONReader::GetKVTree() +{ + return this->Registry; +} \ No newline at end of file diff --git a/ZUtil/ZJSONWriter.cpp b/ZUtil/ZJSONWriter.cpp new file mode 100644 index 0000000..d8ec092 --- /dev/null +++ b/ZUtil/ZJSONWriter.cpp @@ -0,0 +1,19 @@ +#include <ZUtil/ZJSONWriter.hpp> + +#include <ZSTL/ZString.hpp> +#include <jansson.h> + +ZJSONWriter::ZJSONWriter(ZPtr<ZKVTree> _registry) + : ErrorMessage("No error."), Registry(_registry), NoError("No error.") +{ +} + +const ZString& ZJSONWriter::GetErrorString() +{ + return this->ErrorMessage; +} + +bool ZJSONWriter::Write(ZString& _output) +{ + return false; +} diff --git a/ZUtil/ZKVTree.cpp b/ZUtil/ZKVTree.cpp new file mode 100644 index 0000000..2b1037a --- /dev/null +++ b/ZUtil/ZKVTree.cpp @@ -0,0 +1,547 @@ +#include <ZUtil/ZKVTree.hpp> +#include <ZUtil/ZLog.hpp> + +#include <ZSTL/ZBasicStringAlgo.hpp> +#include <ZSTL/ZArrayAlgo.hpp> + +/*************************************************************************/ + +void ZKVTree::NodeCheckIn(Node* _node) +{ + for (size_t i = 0; i < _node->Children.Size(); i++) + NodeCheckIn(_node->Children[i]); + + _node->Children.Clear(); + + NodeAllocator.Deallocate(_node); +} + +/*************************************************************************/ + +ZKVTree::ZKVTree() + : RootNode() +{ + RootNode.ParentNode = NULL; + RootNode.Index = 0; +} + +/*************************************************************************/ + +ZKVTree::ZKVTree( const ZKVTree& _other ) + : RootNode() +{ + RootNode.ParentNode = NULL; + RootNode.Index = 0; + + for (ZKVTree::Iterator itr = _other.Begin(); itr != _other.End(); ++itr) { + Put(itr, itr.GetValue()); + } +} + +/*************************************************************************/ + +ZKVTree::~ZKVTree() +{ + for (size_t i = 0; i < RootNode.Children.Size(); i++) + NodeCheckIn(RootNode.Children[i]); +} + +/*************************************************************************/ + +ZKVTree& ZKVTree::operator = ( const ZKVTree& _other ) +{ + Clear(); + + for (ZKVTree::Iterator itr = _other.Begin(); itr != _other.End(); ++itr) { + Put(itr.GetPath(), itr.GetValue()); + } + + return *this; +} + +/*************************************************************************/ + +// This will convert to a full path, with subscripts everywhere and path separators. EXAMPLES: +// +// A.B[2].C.d -> A[0].B[2].C[0].d[0] +// A.B[0][1] -> A[0].B[0].[1] +// +static bool ConvertPath(const ZString& _path, ZString& _out) +{ + const ZString zeroSubscript("[0]"); + + size_t i = 0; + size_t j = 0; + size_t k = 0; + + //We are going to loop, looking for path separator and making sure we have subscripts and proper path separators + while (i != ZSTL::InvalidPos) { + // find the next path separator or the first occurrence of a nested array access + j = ZStringAlgo::FindFirst(_path, ZKVTREE_PATH_SEPARATOR, i, _path.Length()); + k = ZStringAlgo::FindSub(_path, i, _path.Length(), "][", 0, 2); + + // if a nested array access occurs + if (k < j) { + // append the first part of it, a path separators, and then process from there + ZStringAlgo::Append(_out, _path, i, k + 1); + + _out.PushBack(ZKVTREE_PATH_SEPARATOR); + + i = k + 1; + } else if (i == j) { + // this means we are dealing with a node without a name (potentially first node) + if (_out.Empty() || _out.Back() != ']') + ZStringAlgo::Append(_out, zeroSubscript); + + _out.PushBack(ZKVTREE_PATH_SEPARATOR); + + i = j + 1; + } else if (j != ZSTL::InvalidPos) { + // found a substring between two path separators + ZStringAlgo::Append(_out, _path, i, j); + + if (_out.Back() != ']') + ZStringAlgo::Append(_out, zeroSubscript); + + _out.PushBack(ZKVTREE_PATH_SEPARATOR); + + i = j + 1; + } else { + // we have reached the end + ZStringAlgo::Append(_out, _path, i, _path.Length()); + + if (_out.Empty() || _out.Back() != ']') + ZStringAlgo::Append(_out, zeroSubscript); + + i = ZSTL::InvalidPos; + } + } + + // this method may be expanded later for path verification via regex or some such + return true; +} + +//This will insert a child node at the given index and increment the indices on the other child values +static void InsertNode( ZKVTree::Node* _parent, ZKVTree::Node* _child, size_t _index ) +{ + _parent->Children.Insert(_index, _child); + + for (size_t i = _index + 1; i < _parent->Children.Size(); i++) + _parent->Children.Data()[i]->Index++; +} + +//This will erase a child node at the given index and decrement the indices on the other child values +static ZKVTree::Node* EraseChildNode( ZKVTree::Node* _parent, size_t _index ) +{ + for (size_t i = _index + 1; i < _parent->Children.Size(); i++) + _parent->Children.Data()[i]->Index--; + + return _parent->Children.Erase(_index); +} + +/*************************************************************************/ + +// gets the value from a completed path (returned from ConvertFullPath) +ZKVTree::Node* ZKVTree::GetFromPath(const ZString& _path) const +{ + size_t i, j, k; + size_t subscript; + + const Node* node = &RootNode; + + // path[i...j] is our path window (current value we are looking for) + // path[subscript].nextpath + // ^ ^ ^ + // i j k + // or + // path.nextpath + // ^ ^ + // i j,k + i = 0; + j = 0; + k = 0; + + //While we still have a node to look in + while (node != NULL) + { + //See if we have reached the end + if (i >= _path.Length()) + break; + + subscript = 0; + + j = ZStringAlgo::FindFirst(_path, ZKVTREE_PATH_SEPARATOR, i, _path.Length()); + + //If we can't find a path separator, go to the end + if (j == ZSTL::InvalidPos) + j = _path.Length(); + + //See if we have found the node + if (i >= j) + break; + + k = j; + + //Determine if it has a subscript + if (_path[j - 1] == ']') + { + j = ZStringAlgo::FindLast(_path, '[', i, j); + + //Make sure this is bounded correct + if (j == ZSTL::InvalidPos || j < i) + { + node = NULL; + break; + } + + subscript = (size_t)ZStringAlgo::NumericInt(_path, j + 1, k - 1); + } + + node = node->GetChildByName(_path, i, j, subscript); + + //Move up our path 'window' + i = k + 1; + } + + return const_cast<ZKVTree::Node*>(node); +} + +/*************************************************************************/ + +ZKVTree::Node* ZKVTree::CreatePath(const ZString& _path) +{ + size_t i, j, k; + size_t subscript; + + Node* node = &RootNode; + + // path[i...j] is our path window (current value we are looking for) + // path[subscript].nextpath + // ^ ^ ^ + // i j k + // or + // path.nextpath + // ^ ^ + // i j,k + i = 0; + j = 0; + k = 0; + + // while we still have a node to look in + while (node != NULL) { + // see if we have reached the end + if (i >= _path.Length()) { + break; + } + + subscript = 0; + + j = ZStringAlgo::FindFirst(_path, ZKVTREE_PATH_SEPARATOR, i, _path.Length()); + + //If we can't find a path separator, go to the end + if (j == ZSTL::InvalidPos) { + j = _path.Length(); + } + + //See if we are done creating + if (i == j) { + break; + } + + k = j; + + // determine if it has a subscript + if (_path[j - 1] == ']') { + j = ZStringAlgo::FindLast(_path, '[', i, j); + + // make sure this is bounded correct (if not, bail out) + if (j == ZSTL::InvalidPos || j < i) { + node = NULL; + break; + } + + subscript = (size_t)ZStringAlgo::NumericInt(_path, j + 1, k - 1); + } + + Node* childNode = node->GetChildByName(_path, i, j, subscript); + + // create this node if it doesn't exist + if (childNode == NULL) { + // get the child count by name at the parent node + size_t count = node->GetChildCountByName(_path, i, j); + + // see if the subscript at the end is the 'next' value (if not, bail out) + if (count != subscript) { + node = NULL; + break; + } + + // get a new node, set the parent node, name, index (leave out the value) + childNode = NodeAllocator.Allocate(); + + childNode->ParentNode = node; + childNode->Name.Resize(j - i); + ZStringAlgo::Copy(childNode->Name, 0, childNode->Name.Length(), _path, i, j); + + if (count > 0) { + childNode->Index = node->GetLastIndexByName(_path, i, j) + 1; + + // increment the index on the rest of the nodes + for (size_t i = childNode->Index; i < node->Children.Size(); i++) + node->Children[i]->Index++; + + node->Children.Insert(childNode->Index, childNode); + } else { + childNode->Index = node->Children.Size(); + node->Children.PushBack(childNode); + } + } + + // set our new node + node = childNode; + + // move up our 'path window' + i = k + 1; + } + + return node; +} + +/*************************************************************************/ + +ZKVTree::Iterator ZKVTree::Add( const ZString& _name, const ZString& _value ) +{ + return Add(End(), _name, _value); +} + +/*************************************************************************/ + +ZKVTree::Iterator ZKVTree::Add( const ZString& _parent, const ZString& _name, const ZString& _value ) +{ + ZString path; + + if (!ConvertPath(_parent, path)) + return End(); + + Node* node = CreatePath(path); + + return Add(Iterator(node, this), _name, _value); +} + +/*************************************************************************/ + +ZKVTree::Iterator ZKVTree::Add( const Iterator& _itr, const ZString& _name, const ZString& _value ) +{ + ZKVTree::Node* parentNode = NULL; + ZKVTree::Node* childNode = NULL; + + if (_itr.CurrentNode == NULL) { + return End(); + } + + if (_itr.KVTree == this) { + parentNode = _itr.CurrentNode; + + // allocate a child node and set values + childNode = NodeAllocator.Allocate(); + childNode->ParentNode = parentNode; + childNode->Name = _name; + childNode->Value = _value; + + // determine if any other children of the same name exist (grouped on insert) + size_t count = parentNode->GetChildCountByName(_name, 0, _name.Length()); + + if (count > 0) { + childNode->Index = parentNode->GetLastIndexByName(_name, 0, _name.Length()) + 1; + } else { + childNode->Index = parentNode->Children.Size(); + } + + InsertNode(parentNode, childNode, childNode->Index); + + return Iterator(childNode, this); + } else { + // if this is from another tree, just add at the path + return Add(_itr.GetPath(), _name, _value); + } +} + + +/*************************************************************************/ + +void ZKVTree::Clear() +{ + for (size_t i = 0; i < RootNode.Children.Size(); i++) { + NodeCheckIn(RootNode.Children.Data()[i]); + } + + RootNode.Children.Clear(); +} + +/*************************************************************************/ + +void ZKVTree::Erase( const ZString& _path ) +{ + Erase(Find(_path)); +} + +/*************************************************************************/ + +void ZKVTree::Erase( const Iterator& _itr ) +{ + ZASSERT_RUNTIME(_itr.CurrentNode != NULL, "ZKVTree: Unable to erase value from provided iterator!"); + ZASSERT_RUNTIME(_itr.CurrentNode != &RootNode, "ZKVTree: Unable to erase root node!"); + + if (_itr.KVTree == this) { + NodeCheckIn(EraseChildNode(_itr.CurrentNode->ParentNode, _itr.CurrentNode->Index)); + } else { + Erase(_itr.GetPath()); + } +} + +/*************************************************************************/ + +ZKVTree::Iterator ZKVTree::Find( const ZString& _path ) const +{ + ZString path; + + if (!ConvertPath(_path, path)) { + return End(); + } + + Node* node = GetFromPath(path); + + if (node == NULL) { + return End(); + } + + return ZKVTree::Iterator(node, const_cast<ZKVTree*>(this)); +} + +/*************************************************************************/ + +ZKVTree::Iterator ZKVTree::Find( const Iterator& _itr, const ZString& _path ) const +{ + ZString path; + + if (!ConvertPath(_path, path)) { + return End(); + } + + Node* node = GetFromPath(_itr.GetPath() + ZKVTREE_PATH_SEPARATOR + path); + + if (node == NULL) { + return End(); + } + + return ZKVTree::Iterator(node, const_cast<ZKVTree*>(this)); + +} +/*************************************************************************/ + +const ZString& ZKVTree::Get( const ZString& _path ) const +{ + ZKVTree::Iterator itr = Find(_path); + + ZASSERT_RUNTIME(itr != End(), "ZKVTree: No value mapped to path!"); + + return itr.GetValue(); +} + +/*************************************************************************/ + +const ZString& ZKVTree::Get( const Iterator& _itr, const ZString& _path ) +{ + ZKVTree::Iterator itr = Find(_itr, _path); + + ZASSERT_RUNTIME(itr != End(), "ZKVTree: No value mapped to path!"); + + return itr.GetValue(); +} +/*************************************************************************/ + +void ZKVTree::Merge( const ZKVTree& _other, bool _overwrite ) +{ + for (ZKVTree::Iterator itr = _other.Begin(); itr != _other.End(); ++itr) { + if (_overwrite) { + Put(itr.GetPath(), itr.GetValue()); + } else { + ZKVTree::Iterator found = Find(itr.GetPath()); + if (found == End()) { + Put(itr.GetPath(), itr.GetValue()); + } + } + } +} + +/*************************************************************************/ + +ZKVTree::Iterator ZKVTree::Put( const ZString& _path, const ZString& _value ) +{ + ZString path; + + if (!ConvertPath(_path, path)) + return End(); + + // create the node at the path given (will return the existing node if there) + Node* node = CreatePath(path); + + // if we were able to successfully create the node, set its value + if (node != NULL) { + node->Value = _value; + return Iterator(node, this); + } else return End(); +} + +/*************************************************************************/ + +ZKVTree::Iterator ZKVTree::Put(const Iterator& _itr, const ZString& _value) +{ + // ensure this iterator belongs to us + if (_itr.KVTree == this) { + // it does, just set the value + _itr.CurrentNode->Value = _value; + return _itr; + } else { + // it does not, just create a new value using the path variant + return Put(_itr.GetPath(), _value); + } +} + +/*************************************************************************/ + +ZKVTree::Iterator ZKVTree::Begin() const +{ + if (RootNode.Children.Empty()) { + return End(); + } else return ZKVTree::Iterator(const_cast<Node*>(RootNode.Children.Front()), const_cast<ZKVTree*>(this)); +} + +/*************************************************************************/ + +const ZKVTree::Iterator ZKVTree::End() const +{ + return ZKVTree::Iterator(const_cast<Node*>(&RootNode), const_cast<ZKVTree*>(this)); +} + +/*************************************************************************/ + +static bool isInvalidKeyNameChar(const char _char) +{ + return ( isspace(_char) != 0) || + ( iscntrl(_char) != 0) || + ( _char == ZKVTREE_PATH_SEPARATOR ) || + ( _char == '[' ) || + ( _char == ']' ); +} + +bool ZKVTree::IsValidKeyName( const ZString& _name ) const +{ + for (size_t i = 0; i < _name.Length(); i++) { + if (isInvalidKeyNameChar( _name.Data()[i])) { + return false; + } + } + + return true; +} diff --git a/ZUtil/ZLog.cpp b/ZUtil/ZLog.cpp new file mode 100644 index 0000000..daa9e70 --- /dev/null +++ b/ZUtil/ZLog.cpp @@ -0,0 +1,306 @@ +#include <ZUtil/ZLog.hpp> +#include <ZUtil/ZAlloc.hpp> + +#include <iostream> +#include <fstream> +#include <stdarg.h> +#include <algorithm> + +//////////////////////////////////// +/* Static Variable Initialization */ +//////////////////////////////////// + +ZMutex ZLog::LogLock; + +bool ZLog::bIsInitialized = false; + +ZArray< ZPair<std::ofstream*, bool> > ZLog::LogFiles; + +ZArray< ZPtr<ZLogDelegate> > ZLog::Delegates; + +ZString ZLog::LogFileRoot; + +uint64_t* ZLog::UserTick = NULL; +uint64_t* ZLog::UserUpdate = NULL; + +uint64_t ZLog::TickEstimate = 0; +uint64_t ZLog::UpdateFrameEstimate = 0; + +/////////////////////////// +/* Local Helper Function */ +/////////////////////////// + +void writeHeader(std::ofstream& logfile, const char* filename) +{ + + logfile << filename << " : ZUtil version " << ZUTIL_VERSION_STRING << " default log file\n\n"; + + #if ZLOG_LEVEL >= ZLOG_LEVEL_INFO + logfile << "+------------+------------+\n"; + logfile << "| Time (sec) | Update No. |\n"; + logfile << "+------------+------------+\n"; + #endif +} + +void writeFooter(std::ofstream& logfile) +{ + #if ZLOG_LEVEL >= ZLOG_LEVEL_INFO + logfile << "+------------+------------+\n"; + #endif +} + +int logAssertHandler(const char* _msg, void *_arg) +{ + URFP(_arg); + + //Log it! + SystemLogError("Assertion Failed: \n"); + SystemLogError(_msg); + + //Let the error propagate + return 0; +} + +///////////////////////////////// +/* Static Function Declaration */ +///////////////////////////////// + +void ZLog::Init(const ZString& _logFileRoot, const ZString& _defaultLogFile, uint64_t* _ticks /*= NULL*/, uint64_t* _update /*= NULL*/) +{ + std::ofstream *logfile; + + //Save our root path + ZLog::LogFileRoot = _logFileRoot; + + //Create a default log file + ZString logFilePath = ZLog::LogFileRoot + _defaultLogFile; + + logfile = znew_notrack std::ofstream(); + logfile->open(logFilePath.Data(), std::ios::out); + + while (logfile->fail()) { + logFilePath += "_"; + logfile->open(logFilePath.Data(), std::ios::out); + } + + //Write the header + writeHeader(*logfile, _defaultLogFile.Data()); + + //Add the default log file to the set + ZLog::LogFiles.Reserve(16); + ZLog::LogFiles.Clear(); + ZLog::LogFiles.PushBack(ZPair<std::ofstream*, bool>(logfile, true)); + + //Set our SST_Assert handlers + SST_OS_SetDebugAssertHandler(logAssertHandler, NULL); + SST_OS_SetRuntimeAssertHandler(logAssertHandler, NULL); + + ZLog::UserTick = _ticks; + ZLog::UserUpdate = _update; + + //We're ready to rock and roll + ZLog::bIsInitialized = true; +} + +void ZLog::Shutdown() +{ + ZArray< ZPair<std::ofstream*, bool> >::Iterator itr; + + //Iterate and close out + for (itr = ZLog::LogFiles.Begin(); itr != ZLog::LogFiles.End(); itr++) + { + writeFooter(*((*itr).First)); + + (*itr).First->close(); + (*itr).Second = false; + + zdelete (*itr).First; + } + + //Flush standard outputs + std::cout.flush(); + std::cerr.flush(); + + //Clear our set of log files + ZLog::LogFiles.Clear(); +} + +void ZLog::AddLoggingDelegate(ZPtr<ZLogDelegate> _delegate) +{ + ZLog::LogLock.Acquire(); + + ZLog::Delegates.PushBack(_delegate); + + ZLog::LogLock.Release(); +} + +ZLogFile ZLog::CreateLogFile(const ZString& _fileName) +{ + ZLogFile handle; + std::ofstream *file; + + //See if we can early out + if (!ZLog::bIsInitialized) + { + std::cerr << "Attempted to create log file (Before call to Init) : " << _fileName.Data() << std::endl; + return (ZLogFile)0; + } + + ZString logFilePath = ZLog::LogFileRoot + _fileName; + + //Synchronized Section + { + //Scoped lock + ZLock scopedLock(ZLog::LogLock); + + file = znew_notrack std::ofstream(); + + if (file == NULL) + { + fprintf(stderr, "Failed to create log file %s!\n", _fileName.Data()); + return (ZLogFile)0; + } + + file->open(logFilePath.Data(), std::ios::out); + + if (!file->is_open()) + { + //Nope nope nope + fprintf(stderr, "Failed to open log file %s!\n", _fileName.Data()); + zdelete file; + return (ZLogFile)0; + } + else + { + //Write the header + writeHeader(*file, _fileName.Data()); + + //This will give us the index where it will be going + handle = ZLog::LogFiles.Size(); + + //Add to the set of streams already activated + ZLog::LogFiles.PushBack(ZPair<std::ofstream*, bool>(file, true)); + } + } + + return handle; +} + +void ZLog::Resume( ZLogFile _logFile ) +{ + //Scoped Lock + ZLock scopedLock(ZLog::LogLock); + + ZASSERT_RUNTIME((size_t)_logFile < LogFiles.Size(), "Cannot resume logging to file: file does not exist!"); + + ZLog::LogFiles[_logFile].Second = true; +} + +void ZLog::Suspend( ZLogFile _logFile ) +{ + //Scoped Lock + ZLock scopedLock(ZLog::LogLock); + + ZASSERT_RUNTIME((size_t)_logFile < LogFiles.Size(), "Cannot resume logging to file: file does not exist!"); + + ZLog::LogFiles[_logFile].Second = false; +} + +void ZLog::Printf(ZLogType _type, ZLogFile _file, uint64_t _ticks, uint32_t _updateFrame, const char *_function, const char *_str, ...) +{ + URFP(_function); + + va_list args; + + //Check for easy out + if (!ZLog::bIsInitialized) + return; + + //Make sure we're null terminated + char string[32768]; + MemSetChar(string, 0, 32768); + + va_start(args, _str); + + #ifdef _MSC_VER + vsnprintf_s(string, sizeof(string)-1, sizeof(string)-1, _str, args); + #else + vsnprintf(string, sizeof(string)-1, _str, args); + #endif + + //Write using our existing write function + ZLog::WriteLine(_type, _file, _ticks, _updateFrame, string); + + va_end(args); +} + +void ZLog::WriteLine(ZLogType _type, ZLogFile _file, uint64_t _ticks, uint32_t _updateFrame, const char *_str) +{ + #if ZLOG_LEVEL >= ZLOG_LEVEL_INFO + char time[32]; + char update[32]; + #endif + + //See if we can early out (should warn) + if (!ZLog::bIsInitialized) + { + std::cerr << "Logging Output (Before call to Init): " << _str << std::endl; + return; + } + + //Synchronized Section + { + //Scoped Lock + ZLock scopedLock(ZLog::LogLock); + + ZASSERT_RUNTIME((size_t)_file < LogFiles.Size(), "Cannot log to file: file not created!"); + + //Get the file and find out if activated + std::ofstream *logfile = ZLog::LogFiles[_file].First; + bool enabled = ZLog::LogFiles[_file].Second; + + //If we are not currently enabled, we are no longer needed + if (!enabled) + return; + + //Get our best guesses + if (ZLog::UserTick != NULL) { + ZLog::TickEstimate = *ZLog::UserTick; + } else if (_ticks > ZLog::TickEstimate) { + ZLog::TickEstimate = _ticks; + } + + if (ZLog::UserUpdate != NULL) { + ZLog::UpdateFrameEstimate = *ZLog::UserUpdate; + } else if (_updateFrame > ZLog::UpdateFrameEstimate) { + ZLog::UpdateFrameEstimate = _updateFrame; + } + + ZASSERT_UTIL(logfile != NULL, "ZLog Error: logfile is NULL!"); + + #if ZLOG_LEVEL >= ZLOG_LEVEL_INFO + + //If we are at detailed (or higher) log level, then log the extra details, then the string + if (_ticks == 0 && _updateFrame == 0 && ZLog::UserTick == NULL && ZLog::UserUpdate == NULL) { + sprintf(time, "?%11.3f", ((float)ZLog::TickEstimate) / 1000.0f); + sprintf(update, "?%11lu", ZLog::UpdateFrameEstimate); + } else { + sprintf(time, "%12.3f", ((float)ZLog::TickEstimate) / 1000.0f); + sprintf(update, "%12lu", ZLog::UpdateFrameEstimate); + } + + std::cout << _str << std::endl; + *logfile << "|" << time << "|" << update << "| " << /*ZConcurrency::GetThreadName() << ": " << */_str << std::endl; + + #else + + std::cout << _str << std::endl; + *logfile << _str << std::endl; + + #endif //ZLOG_LEVEL >= ZLOG_LEVEL_DETAILED + + //Let the delegates know what happened + for (ZArray< ZPtr<ZLogDelegate> >::Iterator i = ZLog::Delegates.Begin(); i != ZLog::Delegates.End(); i++) + (*i)->Execute(_type, _file, _str); + } +} \ No newline at end of file diff --git a/ZUtil/ZMutex.cpp b/ZUtil/ZMutex.cpp new file mode 100644 index 0000000..95c4c71 --- /dev/null +++ b/ZUtil/ZMutex.cpp @@ -0,0 +1,42 @@ +#include <ZUtil/ZMutex.hpp> +#include <ZUtil/ZAssert.hpp> + +////////////////////////// +/* ZLock Implementation */ +////////////////////////// + +ZMutex::ZMutex() +: Mutex(SST_Concurrency_CreateMutex()) +{ + ZASSERT_RUNTIME(Mutex != NULL, "ZMutex failed to allocate mutex from libsst-concurrency!"); +} + +ZMutex::~ZMutex() +{ + SST_Concurrency_DestroyMutex(Mutex); +} + +void ZMutex::Acquire() +{ + SST_Concurrency_LockMutex(Mutex); +} + +void ZMutex::Release() +{ + SST_Concurrency_UnlockMutex(Mutex); +} + +//////////////////////////////// +/* ZScopedLock Implementation */ +//////////////////////////////// + +ZLock::ZLock( ZMutex& _mutex ) + : Mutex(_mutex) +{ + Mutex.Acquire(); +} + +ZLock::~ZLock() +{ + Mutex.Release(); +} diff --git a/ZUtil/ZName.cpp b/ZUtil/ZName.cpp new file mode 100644 index 0000000..d676185 --- /dev/null +++ b/ZUtil/ZName.cpp @@ -0,0 +1,207 @@ +#include <ZUtil/ZName.hpp> +#include <ZUtil/ZAssert.hpp> +#include <ZUtil/ZAlloc.hpp> + +#include <SST/SST_Hash.h> + +ZName::ZName() +: Length(0), Hash(0) +{ + +} + +/*************************************************************************/ + +ZName::ZName( const char *_string ) +: Length(0), Hash(0) +{ + Length = _string != NULL ? strlen(_string) : 0; + + if (Length > ZNAME_MAX_LENGTH) + { + ZASSERT_RUNTIME_FAIL("ZName: Constructed from string with > ZNAME_MAX_LEN characters!"); + Length = ZNAME_MAX_LENGTH; + } + + MemCopyChar(String, _string, Length); + MemSetChar(&String[Length], '\0', ZNAME_MAX_LENGTH - Length + 1); + + Hash = SST_Crypto_HashJCR2(String, Length); +} + +/*************************************************************************/ + +ZName::ZName( const ZString& _string ) +{ + Length = _string.Length(); + + if (Length > ZNAME_MAX_LENGTH) + { + ZASSERT_RUNTIME_FAIL("ZName: Constructed from string with > ZNAME_MAX_LEN characters!"); + Length = ZNAME_MAX_LENGTH; + } + + MemCopyChar(String, _string.Data(), Length); + MemSetChar(&String[Length], '\0', ZNAME_MAX_LENGTH - Length + 1); + + Hash = SST_Crypto_HashJCR2(String, Length); +} + +/*************************************************************************/ + +ZName::ZName( const ZName& _other ) +: Length(0), Hash(0) +{ + MemCopyChar(String, _other.String, ZNAME_MAX_LENGTH); + + Length = _other.Length; + Hash = _other.Hash; +} + +/*************************************************************************/ + +ZName::ZName( uint64_t _hash ) +: Length(0), Hash(_hash) +{ + const char* precompStr = "<precomputed>"; + + MemCopyChar(String, precompStr, sizeof(precompStr)); + + Length = sizeof(precompStr) - 1; +} + +/*************************************************************************/ + +ZName::~ZName() +{ + +} + +/*************************************************************************/ + +ZName& ZName::operator = ( const ZName& _other ) +{ + MemCopyChar(String, _other.String, ZNAME_MAX_LENGTH); + + Length = _other.Length; + Hash = _other.Hash; + + return *this; +} + +/*************************************************************************/ + +ZName& ZName::operator = ( const ZString& _string ) +{ + Length = _string.Length(); + + if (Length > ZNAME_MAX_LENGTH) + { + ZASSERT_RUNTIME_FAIL("ZName: Assigned from string with > ZNAME_MAX_LEN characters!"); + Length = ZNAME_MAX_LENGTH; + } + + MemCopyChar(String, _string.Data(), Length); + MemSetChar(&String[Length], '\0', ZNAME_MAX_LENGTH - Length + 1); + + Hash = SST_Crypto_HashJCR2(String, Length); + + return *this; +} + +/*************************************************************************/ + +ZName& ZName::operator = (const char* _string ) +{ + Length = _string != NULL ? strlen(_string) : 0; + + if (Length > ZNAME_MAX_LENGTH) + { + ZASSERT_RUNTIME_FAIL("ZName: Assigned from string with > ZNAME_MAX_LEN characters!"); + Length = ZNAME_MAX_LENGTH; + } + + MemCopyChar(String, _string, Length); + MemSetChar(&String[Length], '\0', ZNAME_MAX_LENGTH - Length + 1); + + Hash = SST_Crypto_HashJCR2(String, Length); + + return *this; +} + +/*************************************************************************/ + +bool ZName::operator == ( const ZName& _other ) const +{ + #if ZSTL_CHECK_NAME + + bool ret = (Hash == _other.Hash); + + if (ret == true) + { + int strcmpRet = strcmp(String, _other.String); + + ZASSERT_RUNTIME(strcmpRet == 0, "ZName: Hash reported same, but failed strcmp!\n"); + + return (strcmpRet == 0); + } + + return ret; + + #else + + return Hash == _other.Hash; + + #endif +} + +/*************************************************************************/ + +bool ZName::operator == ( const ZHashValue hash ) const +{ + return Hash == hash; +} + +/*************************************************************************/ + +bool ZName::operator==( const ZString& _other ) const +{ + return Hash == ZName(_other); +} + +/*************************************************************************/ + +bool ZName::operator != ( const ZName& _other ) const +{ + return !((*this) == _other); +} + +/*************************************************************************/ + +ZName::operator ZHashValue() const +{ + return (ZHashValue)Hash; +} + +/*************************************************************************/ + +ZName::operator ZString() const +{ + return ToString(); +} + +/*************************************************************************/ + +ZString ZName::ToString() const +{ + return ZString(String); +} + +/*************************************************************************/ + +const char* ZName::Data() const +{ + return String; +} + +/*************************************************************************/ diff --git a/ZUtil/ZRandomGenerator.cpp b/ZUtil/ZRandomGenerator.cpp new file mode 100644 index 0000000..dd24233 --- /dev/null +++ b/ZUtil/ZRandomGenerator.cpp @@ -0,0 +1,213 @@ +#include <ZUtil/ZRandomGenerator.hpp> + +#include <ZUtil/ZAssert.hpp> + +#include <math.h> /* sine and other functions */ +#include <time.h> /* time function */ + +//Helper Function that returns a float distributed normally between a float min and max using random numbers r1, r2 +float getGaussianHelper(float _min, float _max, float _r1, float _r2) +{ + float deltamid, delta; + + deltamid = (float)(((_max - _min) / 2) * sin(_r1 * 3.14159f)); /* absolute delta from middle value */ + delta = _max - _min - (2 * deltamid); /* calculate the actual delta */ + + return (_min + deltamid + (_r2 * delta)); +} + +/*************************************************************************/ + +ZRandomGenerator::ZRandomGenerator() +: Type(SST_PRNG_SMALLPRNG), Seed((uint32_t)time(0)), Sequence(0), RNG(NULL) +{ + RNG = SST_Random_CreatePRNGFromSeed(Type, Seed); + + ZASSERT_RUNTIME(RNG != NULL, "ZRandomGenerator: Failure to initialize SST_PRNG instance!"); +} + +/*************************************************************************/ + +ZRandomGenerator::ZRandomGenerator(SST_PRNG_TYPE _type, uint32_t _seed, uint64_t _sequence ) +: Type(_type), Seed(_seed), Sequence(_sequence), RNG(SST_Random_CreatePRNGFromSeed(_type, _seed)) +{ + ZASSERT_RUNTIME(RNG != NULL, "ZRandomGenerator: Failure to initialize SST_PRNG instance!"); + + //Generate and discard a number of times equal to Sequence + for (uint64_t i = 0; i < Sequence; i++) + SST_Random_GetPRNGInt(RNG, 0, 1); +} + +/*************************************************************************/ + +ZRandomGenerator::~ZRandomGenerator() +{ + if (RNG != NULL) + SST_Random_DestroyPRNG(RNG); +} + +/*************************************************************************/ + +float ZRandomGenerator::GetFloat() +{ + ++Sequence; + + return SST_Random_GetPRNGFloat(RNG, 0, 1); +} + +/*************************************************************************/ + +void ZRandomGenerator::GetFloatArray( float *_array, size_t _count ) +{ + Sequence += _count; + + return SST_Random_GetPRNGFloatArray(RNG, _array, _count, 0, 1); +} + +/*************************************************************************/ + +float ZRandomGenerator::GetFloatInRange( float _min, float _max ) +{ + ++Sequence; + + return SST_Random_GetPRNGFloat(RNG, _min, _max); +} + +/*************************************************************************/ + +void ZRandomGenerator::GetFloatArrayInRange( float *_array, size_t _count, float _min, float _max ) +{ + Sequence += _count; + + return SST_Random_GetPRNGFloatArray(RNG, _array, _count, _min, _max); +} + +/*************************************************************************/ + +float ZRandomGenerator::GetGaussianFloat( float _min, float _max ) +{ + float r1, r2; + + r1 = GetFloat(); + r2 = GetFloat(); + + return getGaussianHelper(_min, _max, r1, r2); +} + +/*************************************************************************/ + +void ZRandomGenerator::GetGaussianFloatArray( float *_array, size_t _count, float _min, float _max ) +{ + size_t i; + float r1, r2; + + for (i = 0; i < _count; ++i) + { + r1 = GetFloat(); + r2 = GetFloat(); + + _array[i] = getGaussianHelper(_min, _max, r1, r2); + } +} + +/*************************************************************************/ + +int ZRandomGenerator::GetGaussianInt( int _min, int _max ) +{ + return (int)GetGaussianFloat((float)_min + 0.5f, (float)_max + 0.5f); +} + +/*************************************************************************/ + +void ZRandomGenerator::GetGaussianIntArray( int *_array, size_t _count, int _min, int _max ) +{ + size_t i; + float r1, r2; + + for (i = 0; i < _count; ++i) + { + r1 = GetFloat(); + r2 = GetFloat(); + + _array[i] = (int)getGaussianHelper((float)_min + 0.5f, (float)_max + 0.5f, r1, r2); + } +} + +/*************************************************************************/ + +int ZRandomGenerator::GetInt() +{ + ++Sequence; + + return SST_Random_GetPRNGInt(RNG, STDINT_MIN, STDINT_MAX); +} + +/*************************************************************************/ + +void ZRandomGenerator::GetIntArray( int *_array, size_t _count ) +{ + Sequence += _count; + + return SST_Random_GetPRNGIntArray(RNG, _array, _count, STDINT_MIN, STDINT_MAX); +} + +/*************************************************************************/ + +int ZRandomGenerator::GetIntInRange( int _min, int _max ) +{ + ++Sequence; + + return SST_Random_GetPRNGInt(RNG, _min, _max); +} + +/*************************************************************************/ + +void ZRandomGenerator::GetIntArrayInRange( int *_array, size_t _count, int _min, int _max ) +{ + Sequence += _count; + + return SST_Random_GetPRNGIntArray(RNG, _array, _count, _min, _max); +} + +/*************************************************************************/ + +uint32_t ZRandomGenerator::GetSeed() +{ + return Seed; +} + +/*************************************************************************/ + +uint64_t ZRandomGenerator::GetSequence() +{ + return Sequence; +} + +/*************************************************************************/ + +void ZRandomGenerator::SetSequence( uint64_t _seq ) +{ + //If less than, new instance + if (_seq < Sequence) + SetSeed(Seed); + + while (Sequence < _seq) + { + SST_Random_GetPRNGInt(RNG, 0, 1); + ++Sequence; + } +} + +/*************************************************************************/ + +void ZRandomGenerator::SetSeed( uint32_t _seed ) +{ + if (RNG != NULL) SST_Random_DestroyPRNG(RNG); + + Seed = _seed; + Sequence = 0; + + RNG = SST_Random_CreatePRNGFromSeed(Type, Seed); + + ZASSERT_RUNTIME(RNG != NULL, "ZRandomGenerator: Failure to initialize SST_PRNG_Instance!"); +} diff --git a/ZUtil/ZReadWriteLock.cpp b/ZUtil/ZReadWriteLock.cpp new file mode 100644 index 0000000..026712c --- /dev/null +++ b/ZUtil/ZReadWriteLock.cpp @@ -0,0 +1,33 @@ +#include <ZUtil/ZReadWriteLock.hpp> +#include <ZUtil/ZAssert.hpp> + +ZReadWriteLock::ZReadWriteLock() +: Lock(SST_Concurrency_CreateReadWriteLock()) +{ + ZASSERT_RUNTIME(Lock != NULL, "ZReadWriteLock failed to allocate lock from libsst-concurrency!"); +} + +ZReadWriteLock::~ZReadWriteLock() +{ + SST_Concurrency_DestroyReadWriteLock(Lock); +} + +bool ZReadWriteLock::LockForReading( uint32_t ticks ) const +{ + return SST_Concurrency_LockForReading(Lock, ticks) != 0; +} + +bool ZReadWriteLock::LockForWriting( uint32_t ticks ) +{ + return SST_Concurrency_LockForWriting(Lock, ticks) != 0; +} + +void ZReadWriteLock::EndReading( ) const +{ + SST_Concurrency_EndReading(Lock); +} + +void ZReadWriteLock::EndWriting( ) +{ + SST_Concurrency_EndWriting(Lock); +} diff --git a/ZUtil/ZRegistry.cpp b/ZUtil/ZRegistry.cpp new file mode 100644 index 0000000..85c320e --- /dev/null +++ b/ZUtil/ZRegistry.cpp @@ -0,0 +1,104 @@ +#include <ZUtil/ZRegistry.hpp> + +/*************************************************************************/ + +ZRegistry::ZRegistry() + : Lock(), Tree() +{ + +} + +/*************************************************************************/ + +ZRegistry::ZRegistry( const ZKVTree& _tree ) + : Lock(), Tree(_tree) +{ + +} + +/*************************************************************************/ + +ZRegistry::~ZRegistry() +{ + +} + +/*************************************************************************/ + +void ZRegistry::Erase( const ZString& _key ) +{ + Lock.LockForWriting(SST_WAIT_INFINITE); + + ZKVTree::Iterator itr = Tree.Find(_key); + + if (itr != Tree.End()) { + Tree.Erase(itr); + } + + Lock.EndWriting(); +} + +/*************************************************************************/ + +const ZRegistry::Value ZRegistry::Get( const ZString& _key ) const +{ + Lock.LockForReading(SST_WAIT_INFINITE); + + ZKVTree::Iterator itr = Tree.Find(_key); + + if (itr != Tree.End()) { + ZRegistry::Value val(itr.GetValue(), true); + Lock.EndReading(); + return val; + } + + Lock.EndReading(); + return ZRegistry::Value("", false); +} + +/*************************************************************************/ + +bool ZRegistry::Put( const ZString& _key, const ZString& _value ) +{ + size_t i = _key.Length(); + + //ZRegistry does not support sibling nodes with the same name + if (ZStringAlgo::FindFirstOf(_key, "[]") != ZSTL::InvalidPos) + return false; + + Lock.LockForWriting(SST_WAIT_INFINITE); + + /* + NOTE: This algorithm is not currently needed with the way ZKVTree works, but + that may change - placing value-less nodes in KV tree may be incorrect. If that + changes, this should work. + + Algorithm: + + attempt to place full key + if it succeeds, return true + else + while (valid path) + attempt key - child (i.e., A.B.C.d -> A.B.C, A.B.C -> A.B, A.B -> A, A -> '') + if success, attempt full key + else repeat + */ + while (i > 0) { + Tree.Put(ZString(_key, 0, i), _value); + + if (i == _key.Length()) { + break; + } else { + i = _key.Length(); + } + + i = ZStringAlgo::FindLast(_key, ZKVTREE_PATH_SEPARATOR, 0, i); + + if (i == ZSTL::InvalidPos) + break; + } + + Lock.EndWriting(); + + return i > 0; +} diff --git a/ZUtil/ZSemaphore.cpp b/ZUtil/ZSemaphore.cpp new file mode 100644 index 0000000..111273a --- /dev/null +++ b/ZUtil/ZSemaphore.cpp @@ -0,0 +1,35 @@ +#include <ZUtil/ZSemaphore.hpp> +#include <ZUtil/ZAssert.hpp> +#include <SST/SST_Concurrency.h> //For SST_WAIT_INFINITE + +ZSemaphore::ZSemaphore(int _initialCount) +: Semaphore(SST_Concurrency_CreateSemaphore(_initialCount)) +{ + ZASSERT_RUNTIME(Semaphore != NULL, "ZSemaphore failed to allocate semaphore from libsst-concurrency!"); +} + +ZSemaphore::~ZSemaphore() +{ + +} + +void ZSemaphore::Post() +{ + SST_Concurrency_PostSemaphore(Semaphore, 1); +} + +void ZSemaphore::Post( uint32_t _count ) +{ + SST_Concurrency_PostSemaphore(Semaphore, _count); +} + +bool ZSemaphore::Wait() +{ + return SST_Concurrency_WaitSemaphore(Semaphore, SST_WAIT_INFINITE) != 0; +} + +bool ZSemaphore::Wait( uint32_t _ms ) +{ + return SST_Concurrency_WaitSemaphore(Semaphore, _ms) != 0; +} + diff --git a/ZUtil/ZSimplexNoise.cpp b/ZUtil/ZSimplexNoise.cpp new file mode 100644 index 0000000..754e40d --- /dev/null +++ b/ZUtil/ZSimplexNoise.cpp @@ -0,0 +1,38 @@ +#include <ZUtil/ZUtil.hpp> +#include <ZUtil/ZSimplexNoise.hpp> +#include <SST/SST_SimplexNoise.h> + +ZSimplexNoise::ZSimplexNoise() +{ + this->simplexGenerator = SST_Random_CreateSimplexNoise(); +} + +void ZSimplexNoise::reseed(const int _seed) +{ + SST_Random_ReseedSimplexNoise(this->simplexGenerator, _seed); +} + +float ZSimplexNoise::noise1(const float _x) +{ + return SST_Random_MapSimplexNoise1D(this->simplexGenerator, _x); +} + +// 2D simplex noise +float ZSimplexNoise::noise2(const float _x, const float _y) +{ + return SST_Random_MapSimplexNoise2D(this->simplexGenerator, _x, _y); +} + +// 3D simplex noise +float ZSimplexNoise::noise3(const float _x, const float _y, const float _z) +{ + return SST_Random_MapSimplexNoise3D(this->simplexGenerator, _x, _y, _z); +} + +// 4D simplex noise +float ZSimplexNoise::noise4(const float _x, const float _y, const float _z, const float _w) +{ + return SST_Random_MapSimplexNoise4D(this->simplexGenerator, _x, _y, _z, _w); +} + + diff --git a/ZUtil/ZSimplexNoiseMap.cpp b/ZUtil/ZSimplexNoiseMap.cpp new file mode 100644 index 0000000..40e6451 --- /dev/null +++ b/ZUtil/ZSimplexNoiseMap.cpp @@ -0,0 +1,218 @@ +/* + ZSimplexNoiseMap.cpp + Author : Chris Ertel + + Purpose : Implementation of 2D, 3D, and 4D simplex noise maps. + + Changelog + 2/20/11 - Creation (crertel) +*/ + +#include <ZUtil/ZSimplexNoise.hpp> +#include <ZUtil/ZSimplexNoiseMap.hpp> +#include <string.h> +#include <math.h> + +bool ZSimplexNoiseMap2D::Generate(int _seed) +{ + int buffsize; + int currOctave; + float b_coeff; + float a_coeff; + float u,v; + int xstride; + + noiseGen.reseed(_seed); + + /* allocate buffer */ + if (this->values != NULL) + { + delete [] this->values; + this->values = NULL; + } + + buffsize = this->numberSamplesInX * this->numberSamplesInY; + this->values = znew float[buffsize]; + if (this->values == NULL) + return false; + + memset(this->values, 0, buffsize * sizeof(float)); + + /* fill in the noise */ + /* for good reference, consult http://local.wasp.uwa.edu.au/~pbourke/texture_colour/perlin/ */ + for (currOctave = 0; currOctave < this->numberofoctaves; currOctave++) + { + b_coeff = pow(this->lacunarity, currOctave); + a_coeff = pow(this->persistence, currOctave); + + for (int i = 0; i < this->numberSamplesInX; i++) + { + u = ((float) i)/((float) this->numberSamplesInX); + xstride = i * this->numberSamplesInY; + for (int j = 0; j < this->numberSamplesInY; j++) + { + v = ((float) j)/((float) this->numberSamplesInY); + this->values[ xstride + j ] += ((float) this->noiseGen.noise2(b_coeff * u, b_coeff * v))/a_coeff; + } + } + } + + return true; +} + +void ZSimplexNoiseMap2D::Cleanup() +{ + delete [] this->values; + this->values = NULL; +} + +float ZSimplexNoiseMap2D::getValue(int _x, int _y) +{ + float ret; + int xstride = _x * this->numberSamplesInY; + ret = this->values[ xstride + _y]; + return ret; +} + +bool ZSimplexNoiseMap3D::Generate(int _seed) +{ + int buffsize; + int currOctave; + float b_coeff; + float a_coeff; + float u,v,w; + int xstride, ystride; + + noiseGen.reseed(_seed); + + /* allocate buffer */ + if (this->values != NULL) + { + delete [] this->values; + this->values = NULL; + } + + buffsize = this->numberSamplesInX * this->numberSamplesInY * this->numberSamplesInZ; + this->values = znew float[buffsize]; + if (this->values == NULL) + return false; + + memset(this->values, 0, buffsize * sizeof(float)); + + /* fill in the noise */ + for (currOctave = 0; currOctave < this->numberofoctaves; currOctave++) + { + b_coeff = pow(this->lacunarity, currOctave); + a_coeff = pow(this->persistence, currOctave); + + for (int i = 0; i < this->numberSamplesInX; i++) + { + u = ((float) i)/((float) this->numberSamplesInX); + xstride = i * this->numberSamplesInY * this->numberSamplesInZ; + + for (int j = 0; j < this->numberSamplesInY; j++) + { + v = ((float) j)/((float) this->numberSamplesInY); + + ystride = j * this->numberSamplesInZ ; + for (int k = 0; k < this->numberSamplesInZ; k++) + { + w = ((float) k)/((float) this->numberSamplesInZ); + this->values[xstride+ystride+k] += ((float) this->noiseGen.noise3(b_coeff * u, b_coeff * v, b_coeff * w))/a_coeff; + } + } + } + } + + return true; +} + +void ZSimplexNoiseMap3D::Cleanup() +{ + delete [] this->values; + this->values = NULL; +} + +float ZSimplexNoiseMap3D::getValue(int _x, int _y, int _z) +{ + float ret; + int xstride = _x * this->numberSamplesInY * this->numberSamplesInZ; + int ystride = _y * this->numberSamplesInZ; + ret = this->values[ xstride + ystride + _z]; + return ret; +} + +bool ZSimplexNoiseMap4D::Generate(int _seed) +{ + int buffsize; + int currOctave; + float b_coeff; + float a_coeff; + float u,v,w,r; + int xstride, ystride, zstride; + + noiseGen.reseed(_seed); + + /* allocate buffer */ + if (this->values != NULL) + { + delete [] this->values; + this->values = NULL; + } + + buffsize = this->numberSamplesInX * this->numberSamplesInY * this->numberSamplesInZ * this->numberSamplesInW; + this->values = znew float[buffsize]; + if (this->values == NULL) + return false; + + /* fill in the noise */ + for (currOctave = 0; currOctave < this->numberofoctaves; currOctave++) + { + b_coeff = pow(this->lacunarity, currOctave); + a_coeff = pow(this->persistence, currOctave); + + for (int i = 0; i < this->numberSamplesInX; i++) + { + u = ((float) i)/((float) this->numberSamplesInX); + xstride = i * this->numberSamplesInY * this->numberSamplesInZ * this->numberSamplesInW; + + for (int j = 0; j < this->numberSamplesInY; j++) + { + v = ((float) j)/((float) this->numberSamplesInY); + ystride = j * this->numberSamplesInZ * this->numberSamplesInW; + + for (int k = 0; k < this->numberSamplesInZ; k++) + { + w = ((float) k)/((float) this->numberSamplesInZ); + zstride = k * this->numberSamplesInW; + + for (int l = 0; l < this->numberSamplesInW; l++) + { + r = ((float) l)/((float) this->numberSamplesInW); + this->values[xstride+ystride+zstride+l] += ((float) this->noiseGen.noise4(b_coeff * u, b_coeff * v, b_coeff * w, b_coeff*r))/a_coeff; + } + } + } + } + } + + return true; +} + +void ZSimplexNoiseMap4D::Cleanup() +{ + delete [] this->values; + this->values = NULL; +} + +float ZSimplexNoiseMap4D::getValue(int _x, int _y, int _z, int _w) +{ + float ret; + int xstride = _x * this->numberSamplesInY * this->numberSamplesInZ * this->numberSamplesInW; + int ystride = _y * this->numberSamplesInZ * this->numberSamplesInW; + int zstride = _z * this->numberSamplesInW; + ret = this->values[ xstride + ystride + zstride + _w]; + return ret; +} + + diff --git a/ZUtil/ZTaskStream.cpp b/ZUtil/ZTaskStream.cpp new file mode 100644 index 0000000..33fecb1 --- /dev/null +++ b/ZUtil/ZTaskStream.cpp @@ -0,0 +1,360 @@ +#include <ZUtil/ZTaskStream.hpp> + +#include <ZUtil/ZAlloc.hpp> + +///////////////// +/* ZTaskThread */ +///////////////// + +ZThreadReturn ZTaskThread::run( uint64_t _dt ) +{ + URFP(_dt); + + ZPtr<ZTask> task; + + //Check if a task is available. If it isn't set our status as waiting, then do an full wait + if(!TaskSema.Wait(0)) { + this->ThrStatus = ZTTS_WAITING; + TaskSema.Wait(); + } + + //At this point, we've decremented the semaphore. There should be a task waiting + TaskLock.Acquire(); + + //No tasks -> a) Logic error b) time to exit. Gracefully handle this + if(Tasks.Size() == 0) { + TaskLock.Release(); + return ZTR_TERMINATE; + } + + //Ok, we're executing tasks + ThrStatus = ZTTS_EXECUTING; + + task = Tasks.PopBack(); + + //Save the priority of the task that is executing + CurrentTaskPriority = task->Priority; + + TaskLock.Release(); + + //If the task has not been canceled + if (!task->bCancelTask) { + //Execute it and check task return status + if (task->Execute(task->TaskArgument) == ZTRS_FAILURE) + task->OnTaskFailed(task->TaskArgument); + } else { + //Reset the cancel flag + task->bCancelTask = false; + } + + return ZTR_LOOP; +} + +/******************************************************************************/ + +ZTaskThread::ZTaskThread( ZTaskStream *_stream, ZTaskThreadId _id ) +: TaskLock(), TaskSema(0), Stream(_stream), Id(_id), ThrStatus(ZTTS_UNINITIALIZED) +{ + +} + +/******************************************************************************/ + +ZTaskThread::~ZTaskThread() +{ + +} + +/******************************************************************************/ + +void ZTaskThread::PushTask( ZPtr<ZTask> _task ) +{ + //Add a task while the mutex is locked + TaskLock.Acquire(); + + Tasks.PushBack(_task); + + TaskLock.Release(); + + //1 new task available. + TaskSema.Post(); +} + +/******************************************************************************/ + +///////////////// +/* ZTaskStream */ +///////////////// + +ZTaskStream::ZTaskStream() +: TaskStreamLock(), TaskStreamSema(0), + FrameCompletedEvent(), PausedEvent(), + Tasks(ZTS_DEFAULT_BUFFER_SIZE), bPaused(false), bShouldHalt(false) +{ + //Initially unpaused + PausedEvent.Notify(); + + SetTaskThreadCount(1); +} + +/******************************************************************************/ + +ZTaskStream::~ZTaskStream() +{ + SetTaskThreadCount(0); +} + +/******************************************************************************/ + +void ZTaskStream::PushTask( ZPtr<ZTask> _task ) +{ + TaskStreamLock.Acquire(); + + Tasks.PushBack(_task); + + TaskStreamLock.Release(); + + TaskStreamSema.Post(); // 1 new task to schedule +} + +/******************************************************************************/ + +void ZTaskStream::PushTask( ZTask* _task ) +{ + +} + +/******************************************************************************/ + +void ZTaskStream::PushTasks( ZArray< ZPtr<ZTask> >& _tasks ) +{ + size_t count = _tasks.Size(); + + TaskStreamLock.Acquire(); + + ZArrayAlgo::Append(Tasks, _tasks); + + for (size_t i = 0; i < count; i++) { + Tasks.PushBack( _tasks[i]); + TaskStreamSema.Post(); // 1 new task to schedule + } + + TaskStreamLock.Release(); +} + +void ZTaskStream::PushTasks( ZTask* _tasks, size_t _count ) +{ + // TODO +} + +/******************************************************************************/ + +void ZTaskStream::ExecuteTasks(int _frameTime) +{ + ZPtr<ZTask> curTask; + ZArray< ZPtr<ZTask> > tmp; + ZArray< ZPtr<ZTask> > delayed; + + //Wait for the paused event to be signaled. + //When it isn't, this code blocks. + PausedEvent.Wait(); + + uint64_t timeStart = ZConcurrency::GetTicks(); + uint64_t timeEnd = timeStart + _frameTime; + uint64_t timeNow = timeStart; + + //Schedule tasks until timer elapsed + for (;;) { + //If we need to halt, do so + if (bShouldHalt) { + bShouldHalt = false; + return; + } + + //Check if we've run out of time + timeNow = ZConcurrency::GetTicks(); + + if (timeEnd < timeNow) { + break; + } + + //Empty task queue into a temporary array so we minimize time held with lock + TaskStreamLock.Acquire(); + + while(TaskStreamSema.Wait(0)) { + tmp.PushBack(Tasks.PopBack()); + } + + TaskStreamLock.Release(); + + //Check each task + while (tmp.Size() > 0) { + //Start assigning tasks to threads + curTask = tmp.PopBack(); + + //If our task can be delayed + if (curTask->Priority > 0) { + size_t newPriority; + uint64_t tickDelta = ZConcurrency::GetTicks() - timeStart; + if (tickDelta > curTask->Priority) { + newPriority = 0; + } else { + newPriority = curTask->Priority - (size_t)tickDelta; + } + + curTask->Priority = newPriority; + + delayed.PushBack(curTask); //delay the current task until after priority zero tasks are executed + } else { + //Assign to be executed immediately + TaskThreads[AssignTask(curTask.Pointer())]->PushTask(curTask); + } + } + + //Check what priority tasks are executing + bool execP0 = false; //Priority 0 tasks are executing + bool execPN = false; //Priority N > 0 tasks are executing + + for (ZArray<ZTaskThread*>::Iterator itr = TaskThreads.Begin(); itr != TaskThreads.End(); itr++) { + ZTaskThread* thr = *itr; + + if(thr->ThrStatus != ZTTS_WAITING) { + if(thr->CurrentTaskPriority == 0) { + execP0 = true; + } else { + execPN = true; + } + } + } + + //No priority 0 tasks executing -> schedule lower priority stuff now + if (!execP0) { + //At least one delayed task to assign? + if(delayed.Size() != 0) { + //Schedule a delayed task now + ZPtr<ZTask> task = delayed.PopBack(); + TaskThreads[AssignTask(task.Pointer())]->PushTask(task); + execPN = true; + } + } + + //No priority N tasks executing -> wait for something to do + if(!execPN) { + //Check if we've run out of time + timeNow = ZConcurrency::GetTicks(); + + if (timeEnd < timeNow) { + break; + } + + //Compute remaining time, and wait for up to that amount or + //the scheduler wait period, whichever is less. + uint64_t timeLeft = timeEnd - timeNow; + + bool newTasks = TaskStreamSema.Wait((uint32_t)timeLeft); + + if (newTasks) { + //Calling WaitSemaphore() actually decreased the count but since we won't + //duplicate code here, we'll just re-increment it because next loop + //iteration will do another WaitSemaphore() that won't block. + TaskStreamSema.Post(); + } else { + //Timeout -> Time to exit + break; + } + } + } //main scheduling loop + + // return delayed tasks to the task stream + PushTasks(delayed); +} + +/******************************************************************************/ + +size_t ZTaskStream::GetTaskThreadCount() +{ + return TaskThreads.Size(); +} + +/******************************************************************************/ + +void ZTaskStream::HaltFrame() +{ + bShouldHalt = true; +} + +/******************************************************************************/ + +void ZTaskStream::PauseFrame( bool _pause ) +{ + if (_pause) + { + this->bPaused = true; + PausedEvent.Reset(); + } + else + { + this->bPaused = false; + PausedEvent.Notify(); + } +} + +/******************************************************************************/ + +void ZTaskStream::SetTaskThreadCount( size_t _count ) +{ + size_t i, j; + + TaskStreamLock.Acquire(); + + //If there are n task threads and the user wants n + k threads, there is no point in killing all n + //threads just to create n + k more all over again. Similarly, if the user has n threads but wants + //n - k (> 0), then only k threads need to be shut down. + if (_count > TaskThreads.Size()) + { + //In with the new + for (i = TaskThreads.Size(); i < _count; ++i) + { + ZTaskThread* thr = znew ZTaskThread(this, i); + TaskThreads.PushBack(thr); + thr->StartThread(); + while(!thr->ThreadInitialized()) + thr->WaitInitialized(); + } + + } + else if (_count < TaskThreads.Size()) + { + //KILLAMANJARO! + size_t killCount = TaskThreads.Size() - _count; + + //Out with the old + for (i = TaskThreads.Size() - 1, j = 0; j < killCount; --i, ++j) + KillTaskThread(i); + } + + TaskStreamLock.Release(); +} + +/******************************************************************************/ + +ZTaskThreadId ZTaskStream::AssignTask( ZTask *_task ) +{ + URFP(_task); + + static int next = 0; + + int taskThread = next++ % TaskThreads.Size(); + + return TaskThreads[taskThread]->Id; +} + +/******************************************************************************/ + +void ZTaskStream::KillTaskThread( size_t _idx ) +{ + //Post a task that does not exist, task thread will shut down + TaskThreads[_idx]->TaskSema.Post(); + TaskThreads[_idx]->ShutdownThread(); + zdelete TaskThreads[_idx]; +} diff --git a/ZUtil/ZThread.cpp b/ZUtil/ZThread.cpp new file mode 100644 index 0000000..f4928be --- /dev/null +++ b/ZUtil/ZThread.cpp @@ -0,0 +1,322 @@ +#include <ZUtil/ZThread.hpp> +#include <ZUtil/ZLog.hpp> +#include <ZSTL/ZString.hpp> + +#ifdef _MSC_VER //begin Microsoft Visual C++ specific code +#include <windows.h> +#undef CreateMutex +#undef CreateEvent +const DWORD MS_VC_EXCEPTION=0x406D1388; + +#pragma pack(push,8) +typedef struct tagTHREADNAME_INFO +{ + DWORD dwType; // Must be 0x1000. + LPCSTR szName; // Pointer to name (in user addr space). + DWORD dwThreadID; // Thread ID (-1=caller thread). + DWORD dwFlags; // Reserved for future use, must be zero. +} THREADNAME_INFO; +#pragma pack(pop) + +//This disgusting little hack sets the thread's name in the MSVC debugger +void NativeSetThreadName(const char* threadName) +{ + THREADNAME_INFO info; + info.dwType = 0x1000; + info.szName = threadName; + info.dwThreadID = (DWORD)~0; + info.dwFlags = 0; + + __try + { + RaiseException( MS_VC_EXCEPTION, 0, sizeof(info)/sizeof(ULONG_PTR), (ULONG_PTR*)&info ); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + } +} + +#else +#define NativeSetThreadName(name) +#endif //end Microsoft Visual C++ specific code + +/*************************************************************************/ + +ZThread::ZThread(ZString _threadName) +: + ThreadName(_threadName), + bShouldShutdown(false), bShouldPause(false), + ThreadContext(), + ThreadLock(), + InitEvent(), + PreviousTickCount(0), CurrentTickCount(0), + bIsRunning(false), bIsInitialized(false) +{ + +} + +/*************************************************************************/ + +ZThread::~ZThread() +{ + ShutdownThread(); +} + +/*************************************************************************/ + +int ZThread::InitThread(void *_runnable) +{ + ZThread *thr = ((ZThread*)_runnable); + + NativeSetThreadName(thr->GetThreadName().Data()); + + //TODO - hack for now, need to fix CreateThread + thr->ThreadContext.ThreadId = ZConcurrency::GetThreadId(); + + thr->initThread(); + + thr->bIsInitialized = true; + + thr->InitEvent.Notify(); + + thr->Run(); + + return 0; +} + +/*************************************************************************/ + +void ZThread::Run() +{ + uint64_t dt; + + bIsRunning = true; + + while (!bShouldShutdown) + { + while (bShouldPause) + ZConcurrency::YieldThread(); + + ExecuteThreadRequests(); + + PreviousTickCount = CurrentTickCount; + CurrentTickCount = ZConcurrency::GetTicks(); + dt = CurrentTickCount - PreviousTickCount; + + switch (run(dt)) + { + case ZTR_LOOP: continue; + case ZTR_PAUSE: bShouldPause = true; break; + case ZTR_TERMINATE: bShouldShutdown = true; break; + default: bShouldShutdown = true; break; + } + } + + ExecuteThreadRequests(); + + shutdownThread(); + + bIsInitialized = false; + bIsRunning = false; +} + +/*************************************************************************/ + +void ZThread::AddThreadRequest(ZPtr<ZThreadRequest> _request, bool _wait) +{ + + //If this is thread adding a request to itself, don't deadlock + if(IsCallerTheThread()) { + _request->Execute(this); + return; + } + + ThreadLock.Acquire(); + { + ZTRCallbacks.PushBack(_request); + } + ThreadLock.Release(); + + if (_wait) + _request->Wait(); +} + +/*************************************************************************/ + +void ZThread::AddCallbackRequest(ZThreadCallbackFunc function, void* arg, bool async) +{ + ZThreadCallbackRequest req; + + //If this is the thread adding a callback to itself, don't deadlock + if(IsCallerTheThread()) { + function(this, arg); + return; + } + + req.arg = arg; + req.callback = function; + req.doneEvent = (async ? NULL : SST_Concurrency_CreateEvent()); + + ThreadLock.Acquire(); + { + Callbacks.PushBack(req); + } + ThreadLock.Release(); + + //Non-async -> wait for done + if(!async) { + SST_Concurrency_WaitEvent(req.doneEvent, SST_WAIT_INFINITE); + SST_Concurrency_DestroyEvent(req.doneEvent); + } +} + +/*************************************************************************/ + +void ZThread::ExecuteThreadRequests() +{ + ZList< ZPtr<ZThreadRequest> > persistentRequests; + + ThreadLock.Acquire(); + + while (!ZTRCallbacks.Empty()) + { + //Don't execute if we are told to stop + if (ZTRCallbacks.Front()->Stop) + { + ZTRCallbacks.Front()->Persist = false; + } + else + { + ZTRCallbacks.Front()->CompletedEvent.Reset(); + + ZTRCallbacks.Front()->Execute(this); + + ZTRCallbacks.Front()->CompletedEvent.Notify(); + } + + //If we are to persist, do so + if (ZTRCallbacks.Front()->Persist) + persistentRequests.PushBack(ZTRCallbacks.PopFront()); + else + ZTRCallbacks.PopFront(); + } + + while(!Callbacks.Empty()) { + ZThreadCallbackRequest& req = Callbacks.Front(); + + req.callback(this, req.arg); + if(req.doneEvent) { + SST_Concurrency_SignalEvent(req.doneEvent); + } + + Callbacks.PopFront(); + } + + + //Swap back in persistent requests + ZTRCallbacks.Swap(persistentRequests); + + ThreadLock.Release(); +} + +/*************************************************************************/ + +bool ZThread::StartThread() +{ + bShouldShutdown = false; + bShouldPause = false; + + ThreadContext = ZConcurrency::CreateThread(ZThread::InitThread, this); + + if (!ThreadContext.IsValid()) + return false; + + return true; +} + +/*************************************************************************/ + +void ZThread::ShutdownThread() +{ + bShouldShutdown = true; + + if (ThreadContext.IsValid()) + { + ZConcurrency::WaitThread(ThreadContext); + ZConcurrency::DestroyThread(ThreadContext); + ThreadContext.Invalidate(); + } +} + +/*************************************************************************/ + +void ZThread::PauseThread() +{ + bShouldPause = true; +} + +/*************************************************************************/ + +void ZThread::RestartThread() +{ + bShouldPause = false; +} + +/*************************************************************************/ + +bool ZThread::ThreadRunning() +{ + return bIsRunning; +} + +/*************************************************************************/ + +bool ZThread::ThreadInitialized() +{ + return bIsInitialized; +} + +/*************************************************************************/ + +uint32_t ZThread::GetThreadId() +{ + return ThreadContext.ThreadId; +} + +/*************************************************************************/ + +ZString ZThread::GetThreadName() +{ + ZString name; + + ThreadLock.Acquire(); + + name = ThreadName; + + ThreadLock.Release(); + + return name; +} + +/*************************************************************************/ + +void ZThread::WaitInitialized() +{ + InitEvent.Wait(); +} + +/*************************************************************************/ + +void ZThread::WaitShutdown() +{ + if (ThreadContext.IsValid()) + ZConcurrency::WaitThread(ThreadContext); +} + +/*************************************************************************/ +bool ZThread::IsCallerTheThread() +{ + uint32_t callerThreadID = SST_Concurrency_GetThreadId(); + + return (callerThreadID == this->GetThreadId()); +} \ No newline at end of file diff --git a/ZUtil/ZUtil.vcxproj b/ZUtil/ZUtil.vcxproj new file mode 100644 index 0000000..042cc8c --- /dev/null +++ b/ZUtil/ZUtil.vcxproj @@ -0,0 +1,252 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup Label="ProjectConfigurations"> + <ProjectConfiguration Include="Debug|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectGuid>{49E96A5C-AC79-412B-BBBA-4653795D5EDC}</ProjectGuid> + <RootNamespace>Util</RootNamespace> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> + <ConfigurationType>StaticLibrary</ConfigurationType> + <PlatformToolset>v110</PlatformToolset> + <CharacterSet>MultiByte</CharacterSet> + <WholeProgramOptimization>true</WholeProgramOptimization> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> + <ConfigurationType>StaticLibrary</ConfigurationType> + <PlatformToolset>v110</PlatformToolset> + <CharacterSet>MultiByte</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> + <ConfigurationType>StaticLibrary</ConfigurationType> + <PlatformToolset>v110</PlatformToolset> + <CharacterSet>MultiByte</CharacterSet> + <WholeProgramOptimization>true</WholeProgramOptimization> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> + <ConfigurationType>StaticLibrary</ConfigurationType> + <PlatformToolset>v110</PlatformToolset> + <CharacterSet>MultiByte</CharacterSet> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <ImportGroup Label="ExtensionSettings"> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <PropertyGroup Label="UserMacros" /> + <PropertyGroup> + <_ProjectFileVersion>11.0.50727.1</_ProjectFileVersion> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <OutDir>$(SolutionDir)Bin\x86\</OutDir> + <IntDir>$(SolutionDir)Intermediate\$(Configuration)\$(Platform)\$(ProjectName)\</IntDir> + <TargetName>$(ProjectName)-debug</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <OutDir>$(SolutionDir)Bin\x64\</OutDir> + <IntDir>$(SolutionDir)Intermediate\$(Configuration)\$(Platform)\$(ProjectName)\</IntDir> + <TargetName>$(ProjectName)-debug</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <OutDir>$(SolutionDir)Bin\x86\</OutDir> + <IntDir>$(SolutionDir)Intermediate\$(Configuration)\$(Platform)\$(ProjectName)\</IntDir> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <OutDir>$(SolutionDir)Bin\x64\</OutDir> + <IntDir>$(SolutionDir)Intermediate\$(Configuration)\$(Platform)\$(ProjectName)\</IntDir> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <Optimization>Disabled</Optimization> + <AdditionalIncludeDirectories>$(SolutionDir)Include;$(SolutionDir)Lib/Include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>_DEBUG ZASSERT_ENABLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <MinimalRebuild>false</MinimalRebuild> + <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> + <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> + <DisableLanguageExtensions>false</DisableLanguageExtensions> + <WarningLevel>Level4</WarningLevel> + <TreatWarningAsError>false</TreatWarningAsError> + <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> + <DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings> + <MultiProcessorCompilation>true</MultiProcessorCompilation> + <WholeProgramOptimization>true</WholeProgramOptimization> + </ClCompile> + <Lib /> + <Lib> + <LinkTimeCodeGeneration>true</LinkTimeCodeGeneration> + </Lib> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Midl> + <TargetEnvironment>X64</TargetEnvironment> + </Midl> + <ClCompile> + <Optimization>Disabled</Optimization> + <AdditionalIncludeDirectories>$(SolutionDir)Include;$(SolutionDir)Lib/Include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>_DEBUG ZASSERT_ENABLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <MinimalRebuild>false</MinimalRebuild> + <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> + <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> + <DisableLanguageExtensions>false</DisableLanguageExtensions> + <WarningLevel>Level4</WarningLevel> + <TreatWarningAsError>false</TreatWarningAsError> + <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> + <MultiProcessorCompilation>true</MultiProcessorCompilation> + <WholeProgramOptimization>true</WholeProgramOptimization> + </ClCompile> + <Lib /> + <Lib> + <LinkTimeCodeGeneration>true</LinkTimeCodeGeneration> + </Lib> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <Optimization>MaxSpeed</Optimization> + <InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion> + <IntrinsicFunctions>true</IntrinsicFunctions> + <AdditionalIncludeDirectories>$(SolutionDir)Include;$(SolutionDir)Lib/Include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>_RELEASE; _CRT_SECURE_NO_WARNINGS=1; SST_ASSERT_NODEBUG=1; ZSTL_DISABLE_RUNTIME_CHECKS=1;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> + <FunctionLevelLinking>true</FunctionLevelLinking> + <WarningLevel>Level4</WarningLevel> + <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> + <DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings> + <MultiProcessorCompilation>true</MultiProcessorCompilation> + </ClCompile> + <Lib> + <OutputFile>$(OutDir)$(ProjectName).lib</OutputFile> + </Lib> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Midl> + <TargetEnvironment>X64</TargetEnvironment> + </Midl> + <ClCompile> + <Optimization>MaxSpeed</Optimization> + <InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion> + <IntrinsicFunctions>true</IntrinsicFunctions> + <AdditionalIncludeDirectories>$(SolutionDir)Include;$(SolutionDir)Lib/Include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>_RELEASE; _CRT_SECURE_NO_WARNINGS=1; SST_ASSERT_NODEBUG=1; ZSTL_DISABLE_RUNTIME_CHECKS=1;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> + <FunctionLevelLinking>true</FunctionLevelLinking> + <WarningLevel>Level4</WarningLevel> + <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> + <MultiProcessorCompilation>true</MultiProcessorCompilation> + </ClCompile> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="ZAllocWindow.cpp" /> + <ClCompile Include="ZBinaryBufferReader.cpp" /> + <ClCompile Include="ZBinaryBufferWriter.cpp" /> + <ClCompile Include="ZBinaryFileReader.cpp" /> + <ClCompile Include="ZBinaryFileWriter.cpp" /> + <ClCompile Include="ZJSONReader.cpp" /> + <ClCompile Include="ZJSONWriter.cpp" /> + <ClCompile Include="ZRegistry.cpp" /> + <ClCompile Include="ZLog.cpp" /> + <ClCompile Include="ZXMLReader.cpp" /> + <ClCompile Include="ZXMLWriter.cpp" /> + <ClCompile Include="ZConcurrency.cpp" /> + <ClCompile Include="ZEvent.cpp" /> + <ClCompile Include="ZMutex.cpp" /> + <ClCompile Include="ZReadWriteLock.cpp" /> + <ClCompile Include="ZSemaphore.cpp" /> + <ClCompile Include="ZTaskStream.cpp" /> + <ClCompile Include="ZThread.cpp" /> + <ClCompile Include="ZKVTree.cpp" /> + <ClCompile Include="ZAlloc.cpp" /> + <ClCompile Include="ZName.cpp" /> + <ClCompile Include="ZIniReader.cpp" /> + <ClCompile Include="ZIniWriter.cpp" /> + <ClCompile Include="ZRandomGenerator.cpp" /> + <ClCompile Include="ZSimplexNoise.cpp" /> + <ClCompile Include="ZSimplexNoiseMap.cpp" /> + </ItemGroup> + <ItemGroup> + <ClInclude Include="..\Include\ZUtil\ZAssert.hpp" /> + <ClInclude Include="..\Include\ZUtil\ZAllocWindow.hpp" /> + <ClInclude Include="..\Include\ZUtil\ZBinaryBufferReader.hpp" /> + <ClInclude Include="..\Include\ZUtil\ZBinaryBufferWriter.hpp" /> + <ClInclude Include="..\Include\ZUtil\ZBinaryFileReader.hpp" /> + <ClInclude Include="..\Include\ZUtil\ZBinaryFileWriter.hpp" /> + <ClInclude Include="..\Include\ZUtil\ZBinaryReader.hpp" /> + <ClInclude Include="..\Include\ZUtil\ZBinaryWriter.hpp" /> + <ClInclude Include="..\Include\ZUtil\ZJSONReader.hpp" /> + <ClInclude Include="..\Include\ZUtil\ZJSONWriter.hpp" /> + <ClInclude Include="..\Include\ZUtil\ZRegistry.hpp" /> + <ClInclude Include="..\Include\ZUtil\ZUtil.hpp" /> + <ClInclude Include="..\Include\ZUtil\ZUtilBuild.hpp" /> + <ClInclude Include="..\Include\ZUtil\ZLog.hpp" /> + <ClInclude Include="..\Include\ZUtil\ZXMLReader.hpp" /> + <ClInclude Include="..\Include\ZUtil\ZXMLWriter.hpp" /> + <ClInclude Include="..\Include\ZUtil\ZConcurrency.hpp" /> + <ClInclude Include="..\Include\ZUtil\ZEvent.hpp" /> + <ClInclude Include="..\Include\ZUtil\ZMutex.hpp" /> + <ClInclude Include="..\Include\ZUtil\ZReadWriteLock.hpp" /> + <ClInclude Include="..\Include\ZUtil\ZSemaphore.hpp" /> + <ClInclude Include="..\Include\ZUtil\ZTaskStream.hpp" /> + <ClInclude Include="..\Include\ZUtil\ZThread.hpp" /> + <ClInclude Include="..\Include\ZUtil\ZKVTree.hpp" /> + <ClInclude Include="..\Include\ZUtil\ZAlloc.hpp" /> + <ClInclude Include="..\Include\ZUtil\ZReferenceCounter.hpp" /> + <ClInclude Include="..\Include\ZUtil\ZSlabAllocator.hpp" /> + <ClInclude Include="..\Include\ZUtil\ZSmartPointer.hpp" /> + <ClInclude Include="..\Include\ZUtil\ZWeakPointer.hpp" /> + <ClInclude Include="..\Include\ZUtil\ZBitmap.hpp" /> + <ClInclude Include="..\Include\ZUtil\ZIniReader.hpp" /> + <ClInclude Include="..\Include\ZUtil\ZIniWriter.hpp" /> + <ClInclude Include="..\Include\ZUtil\ZNoise.hpp" /> + <ClInclude Include="..\Include\ZUtil\ZNoiseMap.hpp" /> + <ClInclude Include="..\Include\ZUtil\ZRandomGenerator.hpp" /> + <ClInclude Include="..\Include\ZUtil\ZSimplexNoise.hpp" /> + <ClInclude Include="..\Include\ZUtil\ZSimplexNoiseMap.hpp" /> + <ClInclude Include="..\Include\ZUtil\ZName.hpp" /> + </ItemGroup> + <ItemGroup> + <ProjectReference Include="..\libsst-atomic\libsst-atomic.vcxproj"> + <Project>{43ed481f-c4a3-40ed-81a3-46c43dc4eb1e}</Project> + </ProjectReference> + <ProjectReference Include="..\libsst-concurrency\libsst-concurrency.vcxproj"> + <Project>{7af55ff8-2f78-42ec-8a05-7fa1ae514814}</Project> + </ProjectReference> + <ProjectReference Include="..\libsst-crypto\libsst-crypto.vcxproj"> + <Project>{e5172b73-ab9a-4702-998f-84c841b30c02}</Project> + </ProjectReference> + <ProjectReference Include="..\libsst-os\libsst-os.vcxproj"> + <Project>{4bac6d63-c2e8-43f7-87ea-ef953cbfddd3}</Project> + </ProjectReference> + <ProjectReference Include="..\libsst-random\libsst-random.vcxproj"> + <Project>{8aa34f81-4045-4613-88b7-6ff58d7e0a7a}</Project> + </ProjectReference> + </ItemGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> + <ImportGroup Label="ExtensionTargets"> + </ImportGroup> +</Project> \ No newline at end of file diff --git a/ZUtil/ZUtil.vcxproj.filters b/ZUtil/ZUtil.vcxproj.filters new file mode 100644 index 0000000..8899824 --- /dev/null +++ b/ZUtil/ZUtil.vcxproj.filters @@ -0,0 +1,278 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup> + <Filter Include="Source Files"> + <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier> + <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions> + </Filter> + <Filter Include="Source Files\IO"> + <UniqueIdentifier>{0c1f31dc-02e7-4854-b43b-f34122d54aef}</UniqueIdentifier> + </Filter> + <Filter Include="Source Files\Concurrency"> + <UniqueIdentifier>{fad6c8b5-e651-439c-bb10-da7549c3489a}</UniqueIdentifier> + </Filter> + <Filter Include="Source Files\Memory"> + <UniqueIdentifier>{fdf92c2b-f4b3-4897-b3cb-fce4bfa6ab2c}</UniqueIdentifier> + </Filter> + <Filter Include="Source Files\Parsing"> + <UniqueIdentifier>{46ffdb11-088a-42e1-b6e4-d48521f8bbe8}</UniqueIdentifier> + </Filter> + <Filter Include="Source Files\Name"> + <UniqueIdentifier>{56d072e1-ad9b-4f1e-ba27-69ac3e6aa033}</UniqueIdentifier> + </Filter> + <Filter Include="Source Files\Random"> + <UniqueIdentifier>{1310d55f-38d1-4da8-a565-2d7f9d40a4f1}</UniqueIdentifier> + </Filter> + <Filter Include="Header Files"> + <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier> + <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> + </Filter> + <Filter Include="Header Files\IO"> + <UniqueIdentifier>{c778d68f-0696-43bd-834c-a83f3e4e7926}</UniqueIdentifier> + </Filter> + <Filter Include="Header Files\Concurrency"> + <UniqueIdentifier>{99043719-ca05-4069-b7b4-c3a572f562bf}</UniqueIdentifier> + </Filter> + <Filter Include="Header Files\Memory"> + <UniqueIdentifier>{4b31f2cf-ae99-47a6-a73f-70917c38affb}</UniqueIdentifier> + </Filter> + <Filter Include="Header Files\Images"> + <UniqueIdentifier>{5792b217-d26d-4330-89f3-03afdec0dbf9}</UniqueIdentifier> + </Filter> + <Filter Include="Header Files\Parsing"> + <UniqueIdentifier>{c17952c6-c398-4dd0-8cf6-b101e689d7ab}</UniqueIdentifier> + </Filter> + <Filter Include="Header Files\Random"> + <UniqueIdentifier>{15ff240d-bda5-4b0e-890d-5c0c3504f1e3}</UniqueIdentifier> + </Filter> + <Filter Include="Header Files\Name"> + <UniqueIdentifier>{dd5284dc-acb7-43c6-985f-978b37eaa30d}</UniqueIdentifier> + </Filter> + <Filter Include="Header Files\Data Structures"> + <UniqueIdentifier>{5ba7ebcc-9121-466d-a20b-48433acc9793}</UniqueIdentifier> + </Filter> + <Filter Include="Source Files\Data Structures"> + <UniqueIdentifier>{ea8e988f-3565-46fb-bff7-a2a1b71be4be}</UniqueIdentifier> + </Filter> + <Filter Include="Header Files\Parsing\Binary"> + <UniqueIdentifier>{dc488f2c-c725-4010-a94a-3b2f16316e18}</UniqueIdentifier> + </Filter> + <Filter Include="Header Files\Parsing\Ini"> + <UniqueIdentifier>{8dddf8b2-5d9e-44d7-ae81-80e24681e795}</UniqueIdentifier> + </Filter> + <Filter Include="Header Files\Parsing\XML"> + <UniqueIdentifier>{45c76189-9994-4ae5-a18f-2f741f9f5054}</UniqueIdentifier> + </Filter> + <Filter Include="Source Files\Parsing\Binary"> + <UniqueIdentifier>{bc955f80-4159-4f9d-9baa-b30619e94f40}</UniqueIdentifier> + </Filter> + <Filter Include="Source Files\Parsing\Ini"> + <UniqueIdentifier>{e7c88882-2e0b-49a8-beb5-7bcf6ba6f9d1}</UniqueIdentifier> + </Filter> + <Filter Include="Source Files\Parsing\XML"> + <UniqueIdentifier>{e27c228e-1536-49ce-b79b-a2b25e224594}</UniqueIdentifier> + </Filter> + <Filter Include="Header Files\Parsing\JSON"> + <UniqueIdentifier>{8e4d71c0-00fb-4508-9498-d73ec0762ea7}</UniqueIdentifier> + </Filter> + <Filter Include="Source Files\Parsing\JSON"> + <UniqueIdentifier>{ace79183-f13f-4f5f-905f-2d5c7b80391d}</UniqueIdentifier> + </Filter> + </ItemGroup> + <ItemGroup> + <ClCompile Include="ZLog.cpp"> + <Filter>Source Files\IO</Filter> + </ClCompile> + <ClCompile Include="ZXMLReader.cpp"> + <Filter>Source Files\Parsing\XML</Filter> + </ClCompile> + <ClCompile Include="ZXMLWriter.cpp"> + <Filter>Source Files\Parsing\XML</Filter> + </ClCompile> + <ClCompile Include="ZConcurrency.cpp"> + <Filter>Source Files\Concurrency</Filter> + </ClCompile> + <ClCompile Include="ZEvent.cpp"> + <Filter>Source Files\Concurrency</Filter> + </ClCompile> + <ClCompile Include="ZMutex.cpp"> + <Filter>Source Files\Concurrency</Filter> + </ClCompile> + <ClCompile Include="ZReadWriteLock.cpp"> + <Filter>Source Files\Concurrency</Filter> + </ClCompile> + <ClCompile Include="ZSemaphore.cpp"> + <Filter>Source Files\Concurrency</Filter> + </ClCompile> + <ClCompile Include="ZTaskStream.cpp"> + <Filter>Source Files\Concurrency</Filter> + </ClCompile> + <ClCompile Include="ZThread.cpp"> + <Filter>Source Files\Concurrency</Filter> + </ClCompile> + <ClCompile Include="ZAlloc.cpp"> + <Filter>Source Files\Memory</Filter> + </ClCompile> + <ClCompile Include="ZName.cpp"> + <Filter>Source Files\Name</Filter> + </ClCompile> + <ClCompile Include="ZIniReader.cpp"> + <Filter>Source Files\Parsing\Ini</Filter> + </ClCompile> + <ClCompile Include="ZIniWriter.cpp"> + <Filter>Source Files\Parsing\Ini</Filter> + </ClCompile> + <ClCompile Include="ZRandomGenerator.cpp"> + <Filter>Source Files\Random</Filter> + </ClCompile> + <ClCompile Include="ZSimplexNoise.cpp"> + <Filter>Source Files\Random</Filter> + </ClCompile> + <ClCompile Include="ZSimplexNoiseMap.cpp"> + <Filter>Source Files\Random</Filter> + </ClCompile> + <ClCompile Include="ZKVTree.cpp"> + <Filter>Source Files\Data Structures</Filter> + </ClCompile> + <ClCompile Include="ZRegistry.cpp"> + <Filter>Source Files\Data Structures</Filter> + </ClCompile> + <ClCompile Include="ZBinaryBufferReader.cpp"> + <Filter>Source Files\Parsing\Binary</Filter> + </ClCompile> + <ClCompile Include="ZBinaryFileReader.cpp"> + <Filter>Source Files\Parsing\Binary</Filter> + </ClCompile> + <ClCompile Include="ZAllocWindow.cpp"> + <Filter>Source Files\Memory</Filter> + </ClCompile> + <ClCompile Include="ZBinaryFileWriter.cpp"> + <Filter>Source Files\Parsing\Binary</Filter> + </ClCompile> + <ClCompile Include="ZJSONWriter.cpp"> + <Filter>Source Files\Parsing\JSON</Filter> + </ClCompile> + <ClCompile Include="ZJSONReader.cpp"> + <Filter>Source Files\Parsing\JSON</Filter> + </ClCompile> + <ClCompile Include="ZBinaryBufferWriter.cpp"> + <Filter>Source Files\Parsing\Binary</Filter> + </ClCompile> + </ItemGroup> + <ItemGroup> + <ClInclude Include="..\Include\ZUtil\ZAssert.hpp"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\Include\ZUtil\ZUtil.hpp"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\Include\ZUtil\ZUtilBuild.hpp"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\Include\ZUtil\ZLog.hpp"> + <Filter>Header Files\IO</Filter> + </ClInclude> + <ClInclude Include="..\Include\ZUtil\ZXMLReader.hpp"> + <Filter>Header Files\Parsing\XML</Filter> + </ClInclude> + <ClInclude Include="..\Include\ZUtil\ZXMLWriter.hpp"> + <Filter>Header Files\Parsing\XML</Filter> + </ClInclude> + <ClInclude Include="..\Include\ZUtil\ZConcurrency.hpp"> + <Filter>Header Files\Concurrency</Filter> + </ClInclude> + <ClInclude Include="..\Include\ZUtil\ZEvent.hpp"> + <Filter>Header Files\Concurrency</Filter> + </ClInclude> + <ClInclude Include="..\Include\ZUtil\ZMutex.hpp"> + <Filter>Header Files\Concurrency</Filter> + </ClInclude> + <ClInclude Include="..\Include\ZUtil\ZReadWriteLock.hpp"> + <Filter>Header Files\Concurrency</Filter> + </ClInclude> + <ClInclude Include="..\Include\ZUtil\ZSemaphore.hpp"> + <Filter>Header Files\Concurrency</Filter> + </ClInclude> + <ClInclude Include="..\Include\ZUtil\ZTaskStream.hpp"> + <Filter>Header Files\Concurrency</Filter> + </ClInclude> + <ClInclude Include="..\Include\ZUtil\ZThread.hpp"> + <Filter>Header Files\Concurrency</Filter> + </ClInclude> + <ClInclude Include="..\Include\ZUtil\ZAlloc.hpp"> + <Filter>Header Files\Memory</Filter> + </ClInclude> + <ClInclude Include="..\Include\ZUtil\ZReferenceCounter.hpp"> + <Filter>Header Files\Memory</Filter> + </ClInclude> + <ClInclude Include="..\Include\ZUtil\ZSlabAllocator.hpp"> + <Filter>Header Files\Memory</Filter> + </ClInclude> + <ClInclude Include="..\Include\ZUtil\ZSmartPointer.hpp"> + <Filter>Header Files\Memory</Filter> + </ClInclude> + <ClInclude Include="..\Include\ZUtil\ZWeakPointer.hpp"> + <Filter>Header Files\Memory</Filter> + </ClInclude> + <ClInclude Include="..\Include\ZUtil\ZBitmap.hpp"> + <Filter>Header Files\Images</Filter> + </ClInclude> + <ClInclude Include="..\Include\ZUtil\ZIniReader.hpp"> + <Filter>Header Files\Parsing\Ini</Filter> + </ClInclude> + <ClInclude Include="..\Include\ZUtil\ZIniWriter.hpp"> + <Filter>Header Files\Parsing\Ini</Filter> + </ClInclude> + <ClInclude Include="..\Include\ZUtil\ZNoise.hpp"> + <Filter>Header Files\Random</Filter> + </ClInclude> + <ClInclude Include="..\Include\ZUtil\ZNoiseMap.hpp"> + <Filter>Header Files\Random</Filter> + </ClInclude> + <ClInclude Include="..\Include\ZUtil\ZRandomGenerator.hpp"> + <Filter>Header Files\Random</Filter> + </ClInclude> + <ClInclude Include="..\Include\ZUtil\ZSimplexNoise.hpp"> + <Filter>Header Files\Random</Filter> + </ClInclude> + <ClInclude Include="..\Include\ZUtil\ZSimplexNoiseMap.hpp"> + <Filter>Header Files\Random</Filter> + </ClInclude> + <ClInclude Include="..\Include\ZUtil\ZName.hpp"> + <Filter>Header Files\Name</Filter> + </ClInclude> + <ClInclude Include="..\Include\ZUtil\ZKVTree.hpp"> + <Filter>Header Files\Data Structures</Filter> + </ClInclude> + <ClInclude Include="..\Include\ZUtil\ZRegistry.hpp"> + <Filter>Header Files\Data Structures</Filter> + </ClInclude> + <ClInclude Include="..\Include\ZUtil\ZBinaryBufferReader.hpp"> + <Filter>Header Files\Parsing\Binary</Filter> + </ClInclude> + <ClInclude Include="..\Include\ZUtil\ZBinaryFileReader.hpp"> + <Filter>Header Files\Parsing\Binary</Filter> + </ClInclude> + <ClInclude Include="..\Include\ZUtil\ZBinaryReader.hpp"> + <Filter>Header Files\Parsing\Binary</Filter> + </ClInclude> + <ClInclude Include="..\Include\ZUtil\ZAllocWindow.hpp"> + <Filter>Header Files\Memory</Filter> + </ClInclude> + <ClInclude Include="..\Include\ZUtil\ZBinaryWriter.hpp"> + <Filter>Header Files\Parsing\Binary</Filter> + </ClInclude> + <ClInclude Include="..\Include\ZUtil\ZBinaryFileWriter.hpp"> + <Filter>Header Files\Parsing\Binary</Filter> + </ClInclude> + <ClInclude Include="..\Include\ZUtil\ZJSONReader.hpp"> + <Filter>Header Files\Parsing\JSON</Filter> + </ClInclude> + <ClInclude Include="..\Include\ZUtil\ZJSONWriter.hpp"> + <Filter>Header Files\Parsing\JSON</Filter> + </ClInclude> + <ClInclude Include="..\Include\ZUtil\ZBinaryBufferWriter.hpp"> + <Filter>Header Files\Parsing\Binary</Filter> + </ClInclude> + </ItemGroup> +</Project> \ No newline at end of file diff --git a/ZUtil/ZXMLReader.cpp b/ZUtil/ZXMLReader.cpp new file mode 100644 index 0000000..994834a --- /dev/null +++ b/ZUtil/ZXMLReader.cpp @@ -0,0 +1,109 @@ +#include <ZUtil/ZXMLReader.hpp> + +//We don't want rapidxml throwing exceptions at us, let the parse handler do it +#ifndef RAPIDXML_NO_EXCEPTIONS +#define RAPIDXML_NO_EXCEPTIONS +#endif + +#include <rapidxml/rapidxml.hpp> + +namespace rapidxml +{ + void parse_error_handler(const char *what, void *where, void *arg) + { + URFP(where); //For now + + ZString& errorMsg = *((ZString*)arg); + + errorMsg = "ZXMLReader (rapidxml): "; + ZStringAlgo::Append(errorMsg, what); + } +} + +/*************************************************************************/ + +bool ZXMLReader::Read(const char* data, size_t length) +{ + Tree.Clear(); + + ZString name; // current node name + ZString value; // current node value + + // make a copy of xml data so we can use rapidxml in destructive mode + ZString xmlData(data, length); + rapidxml::xml_document<> doc(&ErrorMessage); // character type is 'char' + + // 0 is default flags (error message will be set by handler) + if (!doc.parse<rapidxml::parse_no_data_nodes>(xmlData.Data())) { + return false; + } + + // iterate the nodes and set data in the tree + rapidxml::xml_node<> *node = doc.first_node(); + ZKVTree::Iterator itr = Tree.Begin(); + + while (node != NULL) { + name = node->name(); + value = node->value(); + + // xml often contains a lot of control characters within the 'body' + ZStringAlgo::Trim(value); + + // add this node under the root node + ZKVTree::Iterator node_itr = Tree.Add(itr, name, value); + + // iterate the attributes and set data in the kvtree + for (rapidxml::xml_attribute<> *attr = node->first_attribute(); attr != NULL; attr = attr->next_attribute()) { + ZString attr_name = attr->name(); + ZString attr_value = attr->value(); + + // add this node under the newly created node + Tree.Add(node_itr, attr_name, attr_value); + } + + // iterate to next node (check child first, then sibling, then go up to parent) + if (node->first_node() != NULL) { + node = node->first_node(); + itr = node_itr; + } else if (node->next_sibling() != NULL) { + node = node->next_sibling(); + } else { + + // go to next element (up and out) + while (node->parent() != NULL) { + node = node->parent(); + + if (node->type() != rapidxml::node_document) { + itr = itr.Parent(); + } else break; + + if (node->next_sibling() != NULL) { + node = node->next_sibling(); + break; + } + + } + + // if we end up NULL or back at the 'document' node by going to parent, then we are done. + if (node == NULL || node->parent() == NULL || node->type() == rapidxml::node_document) { + return true; + } + } + } + + return true; +} + +/*************************************************************************/ + +const ZString& ZXMLReader::GetErrorString() +{ + return ErrorMessage; +} + +/*************************************************************************/ + +void ZXMLReader::GetKVTree(ZKVTree& _kvtree) +{ + _kvtree = Tree; +} diff --git a/ZUtil/ZXMLWriter.cpp b/ZUtil/ZXMLWriter.cpp new file mode 100644 index 0000000..5edf265 --- /dev/null +++ b/ZUtil/ZXMLWriter.cpp @@ -0,0 +1,96 @@ +#include <ZUtil/ZXMLWriter.hpp> + +#define APPEND_NEWLINE \ + if (_useNewlines) { \ + ZStringAlgo::Append(_output, LINE_TERMINATOR); \ + } \ + +const ZString& ZXMLWriter::GetErrorString() +{ + return ErrorMessage; +} + +bool ZXMLWriter::writeAttributes(ZString& _output, const ZKVTree::Iterator& _itr) +{ + bool found_sub = false; // indicates we have sub-elements + + for (size_t i = 0; i < _itr.GetChildCount(); i++) { + + const ZKVTree::Iterator itr = _itr.ChildItr(i); + + if (itr.GetChildCount() > 0) { // attributes have no children + found_sub = true; + continue; + } + + const ZString& name = itr.GetName(); // attrib name + const ZString& val = itr.GetValue(); // attrib value + + _output.PushBack(' '); // start with a space + ZStringAlgo::Append(_output, name); // append attribute name + _output.PushBack('='); // equals + _output.PushBack('\"'); // escaped quote + ZStringAlgo::Append(_output, val); // attribute value + _output.PushBack('\"'); // escaped quote + } + + return found_sub; +} + +bool ZXMLWriter::writeElements(ZString& _output, bool _useNewlines, const ZKVTree::Iterator& _itr) +{ + if (_itr.GetChildCount() == 0) { // indicates an attribute + return true; + } + + const ZString& name = _itr.GetName(); // element name + const ZString& val = _itr.GetValue(); // element value + + _output.PushBack('<'); // open tag + ZStringAlgo::Append(_output, name); // element name + + bool found_sub = writeAttributes(_output, _itr); // write all attributes + + if (val.Empty() && !found_sub) { // close the tag, no body, no sub-elements + _output.PushBack('/'); + _output.PushBack('>'); + + APPEND_NEWLINE; + + } else { // keep tag open for sub-elements and body + _output.PushBack('>'); + + APPEND_NEWLINE; + + // write all sub-elements (this does nothing on an attribute) + for (size_t i = 0; i < _itr.GetChildCount(); i++) { + writeElements(_output, _useNewlines, _itr.ChildItr(i)); + } + + if (!val.Empty()) { + ZStringAlgo::Append(_output, val); // write element body + APPEND_NEWLINE; + } + + _output.PushBack('<'); // closing tag begin + _output.PushBack('/'); + ZStringAlgo::Append(_output, name); + _output.PushBack('>'); // closing tag end + + APPEND_NEWLINE; + } + + return true; +} + +bool ZXMLWriter::Write( const ZKVTree& _input, ZString& _output, bool _useNewlines ) +{ + ZKVTree::Iterator itr = _input.Begin(); + + if (itr == _input.End()) { + ErrorMessage = "ZXMLWriter: key value tree has no data!"; + return false; + } + + return writeElements(_output, _useNewlines, itr); +} diff --git a/ZUtil/obj/x86-64/release/ZAlloc.o b/ZUtil/obj/x86-64/release/ZAlloc.o new file mode 100644 index 0000000000000000000000000000000000000000..3f819904fbc2fd1b5769126a6d6d426246a75e80 GIT binary patch literal 5120 zcmb<-^>JfjWMqH=Mg}_u1P><4z~CT�E1R82A}@7(zWdpL#UE5%B0{1&MmJ9w_05 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 FNC1<UyKMjf literal 0 HcmV?d00001 diff --git a/ZUtil/obj/x86-64/release/ZAllocWindow.o b/ZUtil/obj/x86-64/release/ZAllocWindow.o new file mode 100644 index 0000000000000000000000000000000000000000..37c9a731a870893006e74c6c75e5d20259467bd2 GIT binary patch literal 3888 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 SmbeGWe}F1<MY9l%%K!lIGgqwu literal 0 HcmV?d00001 diff --git a/ZUtil/obj/x86-64/release/ZBinaryBufferReader.o b/ZUtil/obj/x86-64/release/ZBinaryBufferReader.o new file mode 100644 index 0000000000000000000000000000000000000000..74ad83e82797ca5d3d8f7dc34e5d1934bba90849 GIT binary patch literal 8496 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 WiMj)- z0hE40y?K~_VD&qw4G6Ly+AM)-XGlP<jNqb>dKrn!0IH)wW|FHPRM&#+XM?&EW;V=z zs5fB3;C3{e!@$6h2(8P}^%p_i56W}M>d~xW0EII)`zJv4!^TNqW}xc_jkRLazlccv zp!p$e`nN#!gW?xvH;6{JUz8CNCroG(7ohrK`4FTRgh6oyqG4Eo5t1j-)6Wd(kPxhX z2c;j-s3A;0Ed7A$dyxCl?YDp?XqY;feK7qnzBvy2cYrJdO}9c7g6s#4lEC!C%#Fk0 z{{X1{AU#kcz!a?A2Iep@Ftp;(p8?g6t{!GTOh0Ix8e9Hj5QV4!m02Jb$o-(v8JK>U z`xoM{zX6B+=<eAI)eo}=WETiefa(X8IUqg^gW?LrhSA5M`axpI_$X9AvKWXB(+6UM z@NKAmwB*Nd0;>N7ng*EvL3%+LG#-a7{0yMs7XZ}{3O`W&2h$G=KT!FAUiN^@ZGcAn z8>oJe7zm?r!OdE9w}aGefLbH~%}1a<5UBo#3d2XlL2YVm_8)*w1$d)LqT3Gu=zEeH literal 0 HcmV?d00001 diff --git a/ZUtil/obj/x86-64/release/ZBinaryBufferWriter.o b/ZUtil/obj/x86-64/release/ZBinaryBufferWriter.o new file mode 100644 index 0000000000000000000000000000000000000000..4f016641037b4a28af5711e35763e0497d6aa8d6 GIT binary patch literal 7696 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 literal 0 HcmV?d00001 diff --git a/ZUtil/obj/x86-64/release/ZBinaryFileReader.o b/ZUtil/obj/x86-64/release/ZBinaryFileReader.o new file mode 100644 index 0000000000000000000000000000000000000000..1cbae93aa621c5a93cf9e4777398e23647c69ae2 GIT binary patch literal 9440 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 G3<CgF^wU@X literal 0 HcmV?d00001 diff --git a/ZUtil/obj/x86-64/release/ZBinaryFileWriter.o b/ZUtil/obj/x86-64/release/ZBinaryFileWriter.o new file mode 100644 index 0000000000000000000000000000000000000000..a8bebd9a76d3b0f3cd47d0625d84f5d765164044 GIT binary patch literal 9048 zcmb<-^>JfjWMqH=Mg}_u1P><4z%WA!!FB*M9T=1u6u@fv7#P5`0F)Ml(n3&L1WJoR zX$dGT38keO7#Ko5I-hzpzcKLWtbO6pS^A(e^iGOLH;bwU0|SFcr|S>H10LP3FS<kT zbYAo5JpKaYf?Xg2B<j&A0H(S_A9!>IK-mrg9=)L-JP^t~x<fyJm30P4Oz`M-{gL8f z3^Bii6>Q$g!xNyc5b)@%{n7cM!}SYDokuswEZ;A?K;h!ic@AbjR8GR9H-Hh$1{r+v zFsd18olrxdj&41`KlMP%ff6D9?XF+=w;zBC!<E78Vgmacn_Wz}>?(!07HT5QBHnJ- zFHj+vQ($(m;IxAUhaDcBrJykU0Sf|{C7>|>02B1+bcHB_*z;i*2Tpr9FzrzQg+17w z&d?WNX^=79Ahz!ZjL;8|07og~A+SnF1i)g^!K1VGhDT@V1&_|q6PStV2F$&!2l%Ie zqD0Z7+x3J;uLy%jx9bgXq<8yXK(g_5sK;^F570#S!Nc11M6t6+x9bO}mJ1$?7x=d` zpv37rxKX{n?{=ZbX|wAG#@CynN+dkGLr-`xUh)9@<%S2yFCb6hPNk&!PZjFFR;U-S z`Y{B<k4{iO!nA?>+06h?Qg5K{7x3uyeX|QaNrAn%1*!z%#e<KSXz$0P`1}}-;YU}f zA7R=+e)Q;OfTa+RPFGM;galZx?+c6+4ff_nG;cB!_9nEf0Ht|wsprw{`T$hgd35{! z04MBj2LVVihf?gk@PHI`5))1yhLoJ3@~ZR;L}|C{4@imlqdW9VX8^~9SV)=FSqn1r zN4En<EJ7D3iFtH8NW>lnh1l@NhUQUDnR$stm2R0iso_PLC8<StJ#A<VRS#3^?(A%( zpb?r>npaY)V5(=LXP|3V3g#Ks8Jg)CnCO{lLc|q}3=GW-%nU3+7J%wN5Y1Q>#K2e~ zz$neb&M|?JfkB1=f<baBAi|MPppD6ymo1)$9aL_D<ZVFW3=9mQdX)ht?}Lz!fy#sG zTe!S0LcRtn56;0b{Y(vD1t9b1K;>OPG)%r8EDd(w9*{T#149mohRHLfgB5`E-vNm; zFfgQmXt+GY10eZ7AaMo;h71r5mrsW4mjP9*3=9mODDp0Fc^jzweH8gyaQPUh{9_dP zdvN(0sQfb&`G;`%IZ%0LWcfO<G)M$125Dho`1l{2Br^jSHem*41|A&Zyg0-`Eh|hZ zW(H783!6ANg<wc9Gk{YD7I9drM3rJ@0JYRm#Xvk}22jfl#6rc)44{@Asu+mJ%m8ZH zfmo=RnL!p+0Lo)#kb|-ilsK3P3T-e0g<uA!P81<9hZ)=&1v60yW(H6Vj3NZ)Ff%ZN zX>@{_0aTr#i!v}UGq7R`GJwR{aEP<x5C`ROOetmtP7Fak1_lNt21I%QmlX^Q46Y0e z42lehcuaumjKrb704$D3Kd=-t3oH)fF~C#IJ_ZmQk)FY22m=GdZLqzFbOp2bGXn$G z)XB++U0jM0yZPo&@iwS`z-1Ey149H3b26doPeIj#%PIy2hHf0{=R(z+L6a7^>|$VG z*pEZ~MX35&Q1#%ljDdmSGY<8vOb~xDL6aP~Y-3<x(1(iqK*hmj8Uq7E6jWRXniRoh z83O}DD^y$nniRoh7y|>t2B`Qqs5rRnVqjpnz=S=VA25N^i5N6=7~nbi2Ur}De_<(u zhZ(y$@;Jmjm_g<v$_H4AOu(VO4XhqfKEUi{fL6DN>RB(jpnxGh$`7q3b~bg*#3pP6 z77htRQ;tokAy}!OH=0sI3-{EL;F6-$#9XJ!l2reql++^EGLQk@SXvL3?x`jIX=%l& zB@i`OlsFr?29$vu8xn>^mLWJeB;G$b-aWMh<mrI?%sfz|BtE{lBr!QVJ~<;hJ}ogb z2V_4M-Oh$kv;DA0nu8lHp%$(gFiXG!AZu_KX8~3aYG~$K0@DHtgW&SS0z)(WdW?-+ zv(WVz8{yYuX5yNQuE)#-haN*Ch~q3Ai;5B}T?4!`a&f6NhNv_&gDEW`q}135rZkI? zQZo~n(p+3h&4N=?vqSO`o&)ir!5-p?C8ikSqe48<(jh~9d~!u%d_ieZYJ6E{QAuec zC=rB&`5793WGWJqGRq8&4C3R9GvkwU5{rxDODYRe<1_Qp@?AmZ1>>*>)c`~DcpSRX zTfX43Lmx~sfNN4v?)~#00!*OdpqfGvsSb#Pii3(fB?bltnEHAoab+a&^+@7sNa9bB z#6hhDm^r_Z#6e?4FmY*UISsNG*&JUaab$B6ki@l+?5#%<M>b~@k~p$C$C1Q!kj#0G zB#vy3F35olknltnFGmtbHh(^nII{ZlNaD!h@E%DVS-mQ>o&iZChkrPdII_LXNaD!m zY(^4C4!284;>hYbq4gEIz1B$L$o8fqi6fgc6G<F7oOdFLBdh;_B#!J~HE2@~<Q^lW z_=2_6LFpOPhk?~kuofFAI*p-e4@AM_LE@?)0Vsymh#+xws2GS+01?pfPfaKrM1kTC zM1$08gBVb30Hs0Vx==QVvH%fKb3koGD3<{;Mhh92h2>e0oCk=2s)v~g5()qjP;q%E z8$?Bb2&lLrlntVg!vU7}LE^~aU<wj|V&rf@7Do;TWO3whKo*C&859o4;>h8EERGxw z$l}Q1fGmz24#?uj;ead-^&Ys#VTM%hA%~ASOc9bi$o<IS22%nO2l)jSj>zVK2NIwP zVc`Z!x6mXEmVx;fB#zu0fwj*;;>f*`2Cyzj`2&)Jav2st86YtbhPA^FpozoU+Yivh zVeM*gz(C74kU6mSvjWJYNaC<|vICkpteuQpK7-7GwUZmr)Wh1z3(&-2?PLbM;>z5T z#3Tm2;*uf=odIJNrRF5+m84dbFzBTumLxLhB^4Jl=)pzxurxwJtxd2NkR*`}NhI}{ zgHb5WNr>G=`5@Qm#YbUpK4L0DtGLk>U~PZsA#B0gZoo7I!xp$RgV7r@ddc~@xv6<2 z40?I_C8>JuexbVH#w|2(Q#0bziV|~E8T8VN@=HNIRA^$NfCBaJ5WQK1L9qM*%U7_r z3bcBF_xN$?hm{-1`a$&-vHD@<3$lJtc}uK*SUH5OALIvO^~1^mWc{G}jadD#elN0q zP(4Vjepu`x>j#yO#OkkrMkTU-P&rDhepq>jtRGaaqU#5hub?6XxeNta-2oyP7#J*( z3tebA29*L+ptdo{OjvpY3o<Y;7(j<iUVsWQ@E8gMc(f4a9#}mIYP*2!hc=^N+8GX_ z*$a~ZsfDpYG^kAkGLu~Wpt=lXCL7e9ATvSu5Y&Fy_!CGBgwd2SfZ7V!{4XI2QjHjY z0Hs~fs20erAQ_ndgQ0B>bo-w{?MKhs==L|`(EkIf9~uoHE5R6D|0bw@SiJ;R1ggKG z2?CanVB#?M!}x0%7{Fx-M*Ktl&jAWtX#9iR0@Dxk|8*Sp7Z7RxB^>r!K!<>k?FWt3 zpxgfghy53z_QTu>^Dj(4j1L+I#1{V!kO5r=SUC!ce~^=4`eEiuFhbg{=;8kXYCp)$ zFuOoBti1$cgRm_Q{T$H754w7o{UE&{Y{7^<{yL!UhqXgN?gx#Y!Suu2ABn?$1swLH zyQdVYA7&58O(1Ll)sNl=g(fFhbBm!4svo2W8K*+^Ba4C9F#RAl2v3IUN6!}-Q2jg5 zG{F21(hI_UIKpoSH2gr}3sMIPKT!P%(+>+jQ2s_QyFltcKou-OvmcEM4hM9%gY+vv iht><A<p5|*0#sI`+YeHP&Hf3X!is@`VHTPsy8Qs1Pr_FK literal 0 HcmV?d00001 diff --git a/ZUtil/obj/x86-64/release/ZConcurrency.o b/ZUtil/obj/x86-64/release/ZConcurrency.o new file mode 100644 index 0000000000000000000000000000000000000000..2b8887e55fb8af111e3e3cb2238ed8f3d4d12c97 GIT binary patch literal 3856 zcmb<-^>JfjWMqH=Mg}_u1P><4z;J;J!FB*M9T)@|_`qt}85qDcCj$dRs7L2hkLEW9 z9-Xx}JUUA+q<D0*sA@1UFnDyj{xCe?(d+uaqx1L+kO>~$p%*;5U2k}FUV{sDx<2se z2I0^b9^Jk_Qap@#z`9FV!CFophMF(n(OLV$qucd|M>hjpGl+W}WHJLt=C}g~hz()# zfS3~y+B<9ibi4k6Is_^Xwjma50}|7t`3=Id-T)qud0<Q7j&41`KlK2_Xt2Hs5HnCT zB5Z<$5X|*>of~_Y!QI)}N<kwusWh*oRKZlwM9)CitQ5>MtTQyzGceIJ(}ajC7#SFv z8JHPZf_%!rAOfKn7^{L97%K!ArFqynCNMHE$S^=KNLm_1IPwX!F*)<Hh4HY1!V4sC z0}^LoV9){4F!^+Zd<;mOfq@|bM8o8nqQMG4`fEVq3=9nRAQ~oL1(pWeKL;evz`!5@ zqG9sE2>CrAaRvqkZV(NVcSFeE0g2<0{{xlR1<^4583_F{&;$-n6fk*rh&)IOHVo3j z!tn7wHaTVnW^BR?%nYnJ#My9&gK`q46f*-TXJHcuhY*GYGXvOXDB?n39>^D91`5H< zfRwqBWSGIZ8c6`kWM*K3vJjLO0|SE+1H%2_w8g-{-~<*&xF4LR7#J8*z~Y$dL1{+_ zDLlbxjDdk+83O}@0Kz&r>o5-SD+~+_Aah{)!D*3!fq|V7yE&?i5cTt+CWF%^0|SE_ z4)sY;_1mH9VKLE+L;ZZH`a@{y_ux=}6{`L$R6RH?GcYi)GGTYW0u#jjzo6=2DZmkj zdWI<H{JiASqN3Ei<VwBdf&zy4C_h7!sE~}J)Wj6${JfIXiV|m2*D|c)M%cv-4LtM8 z5_2+B5=&CCt8g}iiW?!@Z)oIPl$uzQ3bEWZz%4VN%r)2`o*_6mBp%6~@yN;;;^T`; z5|gvzlQXj8(-Jdtz%E5K*VrYsxTGk*5^8V|x(6{VKv9pyK*Qji)YJl~aakDJkz}!H zc26yVX!T5SEyK`^B#Wup0wkN6oL!7VBS;EUm!Uy;VkXp1SHiwWD8^!xVPs}%P71{R zSR8>Q3rd3OAcBDbTvG5eFfjc24*^z4;(|!xQApyTvI?fY97!Bhr@_QGAc>11nFFgk zKqV9?55v?$Dq4tpq>$9VM=}Rgcfr)d3VM(^a!BeyZUAWkiSr?eD}V%{{zWeJA#Ejy zy~w3LtXu+_1Hw@43=L2QNDPEw>K34h!^)`xXyUN)=mDBItlWVW=^(Q~7*@V0K&u9j z7zo445eB{D%G{E~BnG|Wk|GG50b>=V<|OKY$_WO&l*E!m2EC->Vg^09s2;Ww1ypi? z^<a}lD?jv-^K)}k^GX=>^72bk_1yhJb-_6vYDa2Dd|FXrZYqObdQpC90o213QcD;Z z7(nR~-56Lrg4#$RIZ&Dg)oLst4g&)NjK-zk1F8;LKPdgc^ucIQIs!!na#{gt4FC}g z3=C`_Nhljcp>Y{N^)ARPn0rBLKsW+w@eL4%fq?<!eo(6gDhz3hF)%QwLEG{mIjB-F z6^3pRSQOIkhcdwwsD1~TNv?h~sQql9L<lw!Lcr_?`41ujA<>jE7((L$-Twxl$bz*w zq5cQ8K0s~-nFJ~;Ky(NW`-`Cd2l)@A4u;X~2en^7N)2ENp!7VDAOiz~DU=VRpu(_h z$<PY5A0`i@FT)hV1fVp!@GPi)ba&l=Dzt#oQ0)vb|HJrGafF`-H2jd$52%d+(+>+j zP~Jh0dyv@*&?e?;5C;jPIR_jL=xzro7l0c20xAh=3-U5Bz}*kCALLA^Qjj({{sAqN MW1;$C66p2=0Fz8bF8}}l literal 0 HcmV?d00001 diff --git a/ZUtil/obj/x86-64/release/ZEvent.o b/ZUtil/obj/x86-64/release/ZEvent.o new file mode 100644 index 0000000000000000000000000000000000000000..587dbe03d7e0e18b2a5e5cfd5c14222a7b7c4793 GIT binary patch literal 2976 zcmb<-^>JfjWMqH=Mg}_u1P><4z>vU!U^{@B4h*~uTnwQeoliZQ-w1eg*8X?_68Gpl z<k9W=!=qCGOm#DOv>xD}dVqi10mq#nGaPq-RP6*2yFkP~5Yc%Ytarl6!^q~r44|3p zzW@LK|M!3z4|e9s!xNBQ&{_Hg>WJ>pFP+!Wl!9Cy<yw}SSE83(PypgFFhKYUX^ELR zsVNF2`3i|SIr+(nC8-LjAcYEPMftf3Ihjet#U;AQ`FY8uMMbH3$(4!>U~?1{Z586< z^Gb7aAg000v$BGitD(uj;O^{frJxa-RGL>(s$i;TqGzCMRtn}B))|`V8JOsqX+p#m zj0_CT49pBH85kHupawEl1u-yI2rx?XuyagcWMGhCfMAex0Elqp6KG>{=4E5@=3(c6 z$k~9z85kJkKr~D~5-bhY9|ID{BVR*6ehyS#9Yn*-PePc#2PDqGz@P=9Ve+XEd5{n` z3`)Z+3?KhvlVir3!WkHt8JMvtXJBSv!6D9yA<o0Vz`)4B%8&q+5ronpikX2OL}6fN z22jSp5N2RzV8akJVqjnpLUKPi&KMXN92poG1Ta)HFvQ{zFT-I@D^wh2E;!B^7#ODD zFlQqU^#`Ehc~CdO%(;TYoDWd-J!tBg8L|6Iju8?LtDx$^X@`M<!2pMPFR1!UQ1#%n z1Y$!n7B~aPM@9LWLHN!lu4S%<mhtfcL9QVok@0S!e$FAD{(kZC4Dkp>My_QH!NDQ% z&WMa0?_89cSdt3P&0snI;P{}@ypqh^RLA1t)S?p4+=3irGYnnJkhm_`jC4sYE-A{d zgqVr2-UU^wnO}ZMW?Cf{Ck1Dw=OyN#Yc~x_Elw@Lq8uuonpcA4Fq81aOl*oF!r0Vi zfkKyo7fdoRFflMNa5FG4`~elY|Ns9thKh4BFff2}5iGx0pov4d47N}POg${EJE4ht zLisQnWG^UB!t70l%7euDk=z4H_aG^dxDb-~VvryM#QmT$6lTsbBylk$^&fGFD<Fx3 z?0|9^AayCke2_RS-@(EIBnHB;eAEEd2oeKfSbkZ6CJxINpnM3D0;vUISo&wsE3V8f zNlaqUD=sO5&>1jRQEE=2UP)?234>lrVo4%{UQ%%}gI-ZSgp-_~n+u9>y}bOAR6TdU zP~GB^#N=!SJ+QXajQF&o#N1Snoz%dfa08X)=p`X6-2R|h0`eoWkTe4Wxb%jphsh;C z4dehB4o#aNCaffufGSi2m*=3m0V)8cY(R>kY-9>uScicDT)LyzEX3+JgxZhpF9)ba zg~*m;DO*8xKS-$on!1f3K?Vi}Q#5g?FuaBV<u8~RveIYR1fgz4Ru>KxLwElRsQw$s zilJeJEEI$z{xYCd=>(`^P}u^CI}ip5!Qu~8|DuOINd5;@e<Fy3grUxYi-7p(ZU;#o mfC@T5X;2vhDx1*l=VZW4J0ShwLXUxgAqHdtSO7wxaTx$bRI8c* literal 0 HcmV?d00001 diff --git a/ZUtil/obj/x86-64/release/ZIniReader.o b/ZUtil/obj/x86-64/release/ZIniReader.o new file mode 100644 index 0000000000000000000000000000000000000000..5fa40569936c94e7df1f08a32281b2b62457c894 GIT binary patch literal 157144 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 literal 0 HcmV?d00001 diff --git a/ZUtil/obj/x86-64/release/ZIniWriter.o b/ZUtil/obj/x86-64/release/ZIniWriter.o new file mode 100644 index 0000000000000000000000000000000000000000..a8776a600042f9524bfe67858694be187ff75e95 GIT binary patch literal 43288 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 GVHg18)MwTJ literal 0 HcmV?d00001 diff --git a/ZUtil/obj/x86-64/release/ZJSONReader.o b/ZUtil/obj/x86-64/release/ZJSONReader.o new file mode 100644 index 0000000000000000000000000000000000000000..475212454646e615ace0fa82f66e9008bd726131 GIT binary patch literal 54320 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 LK^SBoh=ySR*+U|Z literal 0 HcmV?d00001 diff --git a/ZUtil/obj/x86-64/release/ZJSONWriter.o b/ZUtil/obj/x86-64/release/ZJSONWriter.o new file mode 100644 index 0000000000000000000000000000000000000000..30b23f7939e294e8b4d71946540a98329ae62df2 GIT binary patch literal 25848 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 C3^mRG literal 0 HcmV?d00001 diff --git a/ZUtil/obj/x86-64/release/ZKVTree.o b/ZUtil/obj/x86-64/release/ZKVTree.o new file mode 100644 index 0000000000000000000000000000000000000000..bb025ecb8e9f749cd648df0cf788239e8053ee1c GIT binary patch literal 128768 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 D&Y|@- literal 0 HcmV?d00001 diff --git a/ZUtil/obj/x86-64/release/ZLog.o b/ZUtil/obj/x86-64/release/ZLog.o new file mode 100644 index 0000000000000000000000000000000000000000..faa53a298483c7c92530c2e0607559df08917a95 GIT binary patch literal 98768 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 VG(gE6&`a5!p!E<`7#{vGJ^*^H=a2vZ literal 0 HcmV?d00001 diff --git a/ZUtil/obj/x86-64/release/ZMutex.o b/ZUtil/obj/x86-64/release/ZMutex.o new file mode 100644 index 0000000000000000000000000000000000000000..cfa44c66aa5e59d457cab6d45b63671512bb829e GIT binary patch literal 3008 zcmb<-^>JfjWMqH=Mg}_u1P><4z|g>fU^{@B4h*~uTnwQeoliZQ-w1eg*8X?_68Gpl z<k9W=!=qCGOm#DOv>xD}dVqi10mq%(3=9m8J3y*-f{0xpVjqa;JPy`7;pAat^I!(h zK(@2=1H|;u4@fRWSTq5@J3wxR;3(hHlGF;l<bncZzCv1JW=?8~LP@?tVopwea$-rU zLM}+5LRwLNu0l>`QgLyKZgPHJa%oXfYF=`sA_LeQ1w~th`1riioE(U03=9zSt*jul zh9(1pyR);Ef<|akX<kXGf~lT~o`J4eDVS$iXK1EpV4`QH2@zK?GB7kVFf*`ZU|<k| z8pv1`#K2e~z$neb&M|?JfkB1=f<e*&Ai|MPppD6ymyOArhn)i=X9E&vU|^5~(J=W) zuryeI3`iW0d<_BlIZ%0B5Dhaw17ZFikT?$Wp;8zWC=IhPeEg3g!N9=4j5URW#F?=v zXJBSv!6D9yA<o0Vz`)4B%8&q+5ronpikX2OL}6fN2Bge|B+JaehQxy~jTjghgpk}1 zjx$iUVqjnpfG9yBV{wR=;V`EaDh@Lj9On!S3{!BJvk`~-15oiisB2*6T*YC|d#L&z zH1#Zu*!`uz2nmN(Q1#%n!@$5`ibLEBDt-g19_F419OBT72hP~>QBi(okPPT-;#%fv zXc-?L5ab#X5*hCn>gOEd>F*aG&k&DLWaL`L5F8v5?~KUc@y<o5i6yDvTn?7=4~`Ei z%`3^wO?50TPAw|&%q_@4Hp9@h42kQ4%}AHj;*z5LN{E>V>s?T_nmZ;JmSz^EVsVpC zesVUtZu6kjoYcf(Y|2CPa*#EcMuGG@8@UES0|(?@sGuPhL9id<qx>LBz^-Iq;DyEq z69WSSsCxMG9|DY_;#>?244_;F%TE?);!rMwEtCOM56cTqXyTqwK8yz03(B)Fd()xv zAaQ;M1_qcoC|`i2K;lA3;)_9o3=9k)aZnixQ-1+T98?Ct#6jsCBn470jAV`iNDyic zNDj(nfYh}R^FiXUd<hE=kQfNV@>v5^BS;K{VfkqRnm8=qfbuCw3Zxc<VflkWuedU| zBr%CWuehWLLTA8OMX5Q7dL^k9B@B8gi6w~)dP&8_40=WR5KeM_Zf<H`34>l<eo3mH zyI-hoaY<rwHiI5mTWUspT2W$dD#%W1U{JV$%6jyY5*BXX&@2J@5m`u@fdO2)!_>p% z8lVPpfDDJGO%M}SQcFM;s)5UUP~8C)fKp~4#ZWdfg)XeazyL1&(Q6)J^&3L%NB5Tl z)S^OU%dwQbptb=>sR5e0jUYi#d5R_u6^7S9p!@|BLst3>n;_J!$m+tOV(9LF0o4yr zk5Emp@P~34f^fuN2ehi4096PoTR?h27$gLXKTzI84|}jYRAC~BgM^{Zf{TFo=xzr| r9)Jo)Kxt4J11g)K#xlU{=LEM$Ksr#d1gOwsU|>iCS%4&k#$^BiF2$(4 literal 0 HcmV?d00001 diff --git a/ZUtil/obj/x86-64/release/ZName.o b/ZUtil/obj/x86-64/release/ZName.o new file mode 100644 index 0000000000000000000000000000000000000000..4138ae19005193ea9b594a08a9ec188d6a77f564 GIT binary patch literal 21592 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 literal 0 HcmV?d00001 diff --git a/ZUtil/obj/x86-64/release/ZRandomGenerator.o b/ZUtil/obj/x86-64/release/ZRandomGenerator.o new file mode 100644 index 0000000000000000000000000000000000000000..9fda82fe2be1043c34a27428487c826b46431838 GIT binary patch literal 9016 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 literal 0 HcmV?d00001 diff --git a/ZUtil/obj/x86-64/release/ZReadWriteLock.o b/ZUtil/obj/x86-64/release/ZReadWriteLock.o new file mode 100644 index 0000000000000000000000000000000000000000..885fad1945c49811c1a0b91cebe6c6b0e6f57782 GIT binary patch literal 3224 zcmb<-^>JfjWMqH=Mg}_u1P><4z!1TSU^{@B4h*~uTnwQeoliZQ-w1eg*8X?_68Gpl z<k9W=!=qCGOm#DOv>xD}dVqi10mq%}3=9m8J3y*-f{0xpVjqa;JPy`7;pAat^I!&G zm+dV50#(o*`la)l2UHc<HdJ$nR|z!`W)?yBFfc>~r6#6?7iE^D`s62P>m?Tyfc%3l zu8@|PnUk8LP?E2Zn3I#AoLG{okdvRBt&mofpR16QnN(a{qMMwbmt0y@l$w`ZsmK5_ zO+nFCAwE8@G$#jQCN>h)ek&_fzJ?|PgS)e{m4ZfSQfXdEse-AViJpP3St*!jSZ8Ra zXJDddrU?;OFfuSSGcYr-WME(rfm+5`6~w?;A;2ij!_F~*k%2*m0fIr&0U*MWPoRy- znU{^pn}?kPB4+~<XJBBE1JN+~NU$_me+)>Rfq_8_M8o7$5%M)4aXj*Kpz^rP--AaU zDuqFT(mV^p$Nv}-3=9m+SaSqOoEe*P24)5p9OA4P;-GM5WME}zfXXOBX%NNC0Lm~R z7Aj_D;6N3C@|YRepezLC%)r1Pgyep3oG~ykL^Cij2q2WfS@k%?XW%er15_MlE;vpY z7#L3AFy}1}^{k8#cjiG|0!|wY3=BGq*xl(3RS$9(NDEATArAGRv<nJ{Lm<Vlw8_B0 zuo;K?b5QdipsD|WLp`>FAU-O}&(H)lM>?Chmbn^Q#>WQ)xrT&9#=C|3Ifr=q`^CpI z#A8uy<XXlM92^qwj3^u8or_WvOHxtF9k3ez;P{}@ypqh^RLA1t)S?p4+=3jeh8nt- zVH0=3W|>QBaY<2rC8}*$T<QWf)EnKyh9;n*%q_nNWJG3Ox@#8LvB(}mRe;TDa6>>P zEnY*Q3P6TnI>o>>F9qfd%y30Wf^=i}1Ed*hI+jRr%>&m0nR)4u1j7rV7?>Cs7`Pc2 z82<c+0Ar{)7Xt$Ws5F4(dkZviD3`$&%7CetfbyN7G)z1K%J+oQAbWX`?1efD>>hq3 z@m?hLLP+A<k;Fk|6wLiMk;KK2)PF}32e}cZUI9rQ<R&PW0n&zG0J{ey4l6$rpb9`@ zAPg%HVBrK317TRcUx20_mcI|6iNo?SgI;lEZb@PigI;k-5rocwv5Hc267@<_D@qvj zQW8rN8T68hiy8Ea@*$k${M_8syb=bzy!?_>J$JuQ-QtqO<ZK2#u(s5U__U(L+*GKw z6jPvZ1Jz0BB|0qJ{-N0b3KL`@X$A&xEd)~!lZ${>DI6ffp=lGugw-gZxC5zGV_*Q+ z8t65g9Y`@q0UAaZ)?r`(*HYx_H-y@c?k@+ZMGMjF2Za~15U33UQfh!K$iTqx5G2UJ zz+j3d4iyIb86*YDUobHcABM%y9R!s?R~wGQ{Sr|9H=z1p6fFE<{2(0hmjG2b0jdyG zwt$2{7$gLXKS6N21tfxsKR^{Gq6)+P4HE|W2kKOq5Sab|6^ww=pfUzj20@KwfY}e~ bE}+Lf$N&#ep$AHLQ2ih=5C+)?qG1>S9h&%k literal 0 HcmV?d00001 diff --git a/ZUtil/obj/x86-64/release/ZRegistry.o b/ZUtil/obj/x86-64/release/ZRegistry.o new file mode 100644 index 0000000000000000000000000000000000000000..42007090b3ab50c84040d258b27715339401f0aa GIT binary patch literal 41336 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 Cs`I}9 literal 0 HcmV?d00001 diff --git a/ZUtil/obj/x86-64/release/ZSemaphore.o b/ZUtil/obj/x86-64/release/ZSemaphore.o new file mode 100644 index 0000000000000000000000000000000000000000..845890bcf5fb9e84fbb1ded1a321037bc635568f GIT binary patch literal 2936 zcmb<-^>JfjWMqH=Mg}_u1P><4z+l0FU^{@B4h*~uTnwQeoliZQ-w1eg*8b=${nG9F zrStd;ki19dA&+j?A0C|oV5*zJqxAs))C2t64mj=vndP_xq-rOK*aaf?fe5JH2`3MO z&F!rHF(LNw1TY(F2h^~AAUAp-l%uHWEd2si)*bq#^BR&eY$pBx|NlQs3D}7zQEkLw z8dPaiaB6O1K}LR2s$OzI0RsbquaK6QnUk8LP?E2Zn3I#AoLG{oPz+P7kXDqRtB{kK zR9sx5o1CAQTv}9=nwMOu$N)D_LD5zrK0dEBCkGTVFpMzY$_l~O$jmFzWMFW2cD7Q` z2u&)@D=Ael)icpE&^0Rs^9<_@&GZaR^vpCN;tECvhGqt429_{$MW77Esvri&3IRrG z9(Ilij0_Ai3=j;GjsOvkd;)Du&b(|)!94675IGx=I0FL%H;9JGyMd*_`eQ)i3=9m) zAQ~nghmfxUi8C-TsDWshd?G@A4oIAVfk7Qa!{n0?@_Rty3=9lfAQ~p03Xum1VZ)&G z!@}_KKQ=jLtT}*zfti6Bn{ozb1{NIRtQg_~3=9m646F<VP#IA8LYWNA4D2u_3eC&_ z$}lKGU=A|_8<<8WtQi;>gpk}1jxz=Z27d+y29VvzYC-IL9O4}~%mKv($b6W&;5cVs zVAudvk1l=$DxLze43-8M7#MEju=giaJ;;8L7I2yXsbz%tYaK`smKH!XBX)neLe*b` zst2bH5F3$cz!^3^D$38$03qmX;+pAdXc-?L5ab#X5*hCn>gOEd>F*aG&k&EM(#SQF zAvicB-Wid7<DH9A6H8Lzc^EA39~>W4npcvUo9b9xoLW@knOl&9VVI$7Cc2o5k!u-- zm?5T^NkD#aiEA0yE@ZcWgb^-5b3H^;7P|Q+;fa~p%mNAHHVY){ngt4722n7{z`z78 z5B`9P*Z=?jgVH5Pii?4P0hB9X=^s*;FfhQxL25wQ6+|!~#9?XI3r#!_%7@V)dwCcb z7-04`K;=Q=f=J@aafqKn5(kxuFmt}*5LZAF2iXDTGQj)=5(8mazDR&70EvMxEMFkI z6C@5x{|nI6!_xl&G;vruXV5FI%q>YwV$drtDT2@$Fji4&PNH5(YDEcyUP@v~B7<I1 zaWR8lQ9gu|oS&PUnpeW0mzQ6Xs^{((s#{!=n4Ha^2iBIF5ua9+n41c<mSPGNZlE$4 zy##}W8&VMlwhI&{U<Q<sW?%r9x^VSS@c^iSAE10t`2?~DR)R`E#X;o?NF2RHcK``O z)gV*o!a58L;8K}f{f6Lr0FqCT?Sa|fgDeOt|IqlLiW}r612pk7AVCHO22(U~s4zTO zouKxkDPv$n4``?Yn0_diAsnh7T{#C-;08<~l!k>rl*<r=BmNwqRp11uLQwpH^nx%* z2o`^!yo?_9Ao&YW{fQtB5=M7Fh!1rtk}3v<2T(x)C=Du0KxGrU{hSP-_5g}jFy{lb PDG&p)04xF_(6|f$60)$I literal 0 HcmV?d00001 diff --git a/ZUtil/obj/x86-64/release/ZSimplexNoise.o b/ZUtil/obj/x86-64/release/ZSimplexNoise.o new file mode 100644 index 0000000000000000000000000000000000000000..a7468a6473cbe21d102aa79c52604f7146f660f5 GIT binary patch literal 9192 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 literal 0 HcmV?d00001 diff --git a/ZUtil/obj/x86-64/release/ZSimplexNoiseMap.o b/ZUtil/obj/x86-64/release/ZSimplexNoiseMap.o new file mode 100644 index 0000000000000000000000000000000000000000..2f2a1f28a49b78eca38035ac35bcadf0a392ca04 GIT binary patch literal 36208 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 literal 0 HcmV?d00001 diff --git a/ZUtil/obj/x86-64/release/ZTaskStream.o b/ZUtil/obj/x86-64/release/ZTaskStream.o new file mode 100644 index 0000000000000000000000000000000000000000..310e640c629c703ea4246ca275dfb8d80837a32b GIT binary patch literal 86960 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 literal 0 HcmV?d00001 diff --git a/ZUtil/obj/x86-64/release/ZThread.o b/ZUtil/obj/x86-64/release/ZThread.o new file mode 100644 index 0000000000000000000000000000000000000000..8bf03e79d04518f243833d93f42fccd7b0299f0b GIT binary patch literal 83912 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 literal 0 HcmV?d00001 diff --git a/ZUtil/obj/x86-64/release/ZXMLReader.o b/ZUtil/obj/x86-64/release/ZXMLReader.o new file mode 100644 index 0000000000000000000000000000000000000000..5f9694b80f4fcbfd02157d2fd8e1146ccdf383ba GIT binary patch literal 102776 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 J?1QmEGyqOE`%VA= literal 0 HcmV?d00001 diff --git a/ZUtil/obj/x86-64/release/ZXMLWriter.o b/ZUtil/obj/x86-64/release/ZXMLWriter.o new file mode 100644 index 0000000000000000000000000000000000000000..c09e69820b59941dd86b7591c415749713619346 GIT binary patch literal 39904 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 literal 0 HcmV?d00001 diff --git a/libsst-atomic/Makefile b/libsst-atomic/Makefile new file mode 100644 index 0000000..aa86d59 --- /dev/null +++ b/libsst-atomic/Makefile @@ -0,0 +1,48 @@ +# libsst-atomic/Makefile +# Author: Patrick Baggett <ptbaggett@762studios.com> +# Created: 12/23/2011 +# +# Purpose: +# +# Makefile for libsst-atomic, requires GNU "make" +# +# License: +# +# This program is free software. It comes without any warranty, to +# the extent permitted by applicable law. You can redistribute it +# and/or modify it under the terms of the Do What The Fuck You Want +# To Public License, Version 2, as published by Sam Hocevar. See +# http://sam.zoy.org/wtfpl/COPYING for more details. + +# Should be invoked with: +# TARGET := { release, debug } +# ARCH := { x86, x86-64, sparc, sparc64, powerpc, powerpc64 } +# ASM := assembler tool + + +BINNAME := $(DIST)/libsst-atomic.a +ifeq ($(TARGET),debug) + BINNAME := $(subst libsst-atomic,libsst-atomic_d, $(BINNAME)) +endif + +# Architecture -> source file conversion +ASM_SRC := SST_Atomic_$(ARCH).asm + + +OBJ := $(addprefix obj/$(ARCH)/$(TARGET)/,$(subst .asm,.o,$(ASM_SRC)) ) + +$(shell mkdir -p obj/$(ARCH)/$(TARGET)) + +$(BINNAME): $(OBJ) + $(AR) cru $@ $+ + $(RANLIB) $@ + +# CLEAN +clean: + @-rm -r -f obj $(DIST)/libsst-atomic*.a + + +# *.asm files to *.o files +obj/$(ARCH)/$(TARGET)/%.o: %.asm + @echo ASM $@ + @$(ASM) -o obj/$(ARCH)/$(TARGET)/$*.o $*.asm diff --git a/libsst-atomic/SST_Atomic_arm.asm b/libsst-atomic/SST_Atomic_arm.asm new file mode 100644 index 0000000..f720cdd --- /dev/null +++ b/libsst-atomic/SST_Atomic_arm.asm @@ -0,0 +1,233 @@ +@ SST_Atomic_arm.asm +@ Author: Patrick Baggett <ptbaggett@762studios.com> +@ Created: 6/21/2012 +@ +@ Purpose: +@ +@ 32-bit assembly for atomic operations for ARMv6+ CPUs +@ Assembles with GNU as +@ +@ License: +@ +@ This program is free software. It comes without any warranty, to +@ the extent permitted by applicable law. You can redistribute it +@ and/or modify it under the terms of the Do What The Fuck You Want +@ To Public License, Version 2, as published by Sam Hocevar. See +@ http://sam.zoy.org/wtfpl/COPYING for more details. + +.text + +@Don't use thumb mode, use full ARM mode +.arm + +@ ELF symbol names +.global SST_Atomic_Add +.global SST_Atomic_AddPtr +.global SST_Atomic_And +.global SST_Atomic_Or +.global SST_Atomic_Xor +.global SST_Atomic_Not +.global SST_Atomic_AddReturn +.global SST_Atomic_AddPtrReturn +.global SST_Atomic_AndReturn +.global SST_Atomic_OrReturn +.global SST_Atomic_XorReturn +.global SST_Atomic_NotReturn +.global SST_Atomic_ExchangeAdd +.global SST_Atomic_ExchangeAddPtr +.global SST_Atomic_Exchange +.global SST_Atomic_ExchangePtr +.global SST_Atomic_CAS +.global SST_Atomic_CASPtr +.global SST_Atomic_LoadAcquire +.global SST_Atomic_LoadAcquirePtr +.global SST_Atomic_StoreRelease +.global SST_Atomic_StoreReleasePtr + + +.type SST_Atomic_Add, %function +.type SST_Atomic_AddPtr, %function +.type SST_Atomic_And, %function +.type SST_Atomic_Or, %function +.type SST_Atomic_Xor, %function +.type SST_Atomic_Not, %function +.type SST_Atomic_AddReturn, %function +.type SST_Atomic_AddPtrReturn, %function +.type SST_Atomic_AndReturn, %function +.type SST_Atomic_OrReturn, %function +.type SST_Atomic_XorReturn, %function +.type SST_Atomic_NotReturn, %function +.type SST_Atomic_ExchangeAdd, %function +.type SST_Atomic_ExchangeAddPtr, %function +.type SST_Atomic_Exchange, %function +.type SST_Atomic_ExchangePtr, %function +.type SST_Atomic_CAS, %function +.type SST_Atomic_CASPtr, %function +.type SST_Atomic_LoadAcquire, %function +.type SST_Atomic_LoadAcquirePtr, %function +.type SST_Atomic_StoreRelease, %function +.type SST_Atomic_StoreReleasePtr, %function + +@======================================================================= +@ Since pointers and integers are the same size on GCC, many of the +@ integer/pointer code paths are the same. This of course only holds true +@ for 32-bit compiles on ARM, which is exactly this file. +@======================================================================= + +@ I've merged the Atomic_XXX and Atomic_XXXReturn functions. The difference +@ is 1 mov instruction -- not really worth making separate functions. + +@ void SST_Atomic_Add(volatile int* x, int value) +@ void SST_Atomic_AddPtr(volatile void* x, uintptr_t value) +SST_Atomic_Add: +SST_Atomic_AddPtr: +SST_Atomic_AddReturn: +SST_Atomic_AddPtrReturn: + mcr p15, 0, r0, c7, c10, 5 @ memory barrier + + _again8: + ldrex r2, [r0] @ r2 <- *x + add r2, r2, r1 @ r2 += value + strex r3, r2, [r0] @ try { *x <- r2 } + teq r3, #0 @ success? + bne _again8 @ No, reload and retry + + mcr p15, 0, r0, c7, c10, 5 @ memory barrier + mov r0, r2 @ Setup return value + bx lr @ Return + +@ void SST_Atomic_And(volatile int* x, int value) +SST_Atomic_And: +SST_Atomic_AndReturn: + mcr p15, 0, r0, c7, c10, 5 @ memory barrier + + _again7: + ldrex r2, [r0] @ r2 <- *x + and r2, r2, r1 @ r2 &= value + strex r3, r2, [r0] @ try { *x <- r2 } + teq r3, #0 @ success? + bne _again7 @ No, reload and retry + + mcr p15, 0, r0, c7, c10, 5 @ memory barrier + mov r0, r2 @ Setup return value + bx lr @ Return + +@ void SST_Atomic_Or(volatile int* x, int value) +SST_Atomic_Or: +SST_Atomic_OrReturn: + mcr p15, 0, r0, c7, c10, 5 @ memory barrier + + _again6: + ldrex r2, [r0] @ r2 <- *x + orr r2, r2, r1 @ r2 |= value + strex r3, r2, [r0] @ try { *x <- r2 } + teq r3, #0 @ success? + bne _again6 @ No, reload and retry + + mcr p15, 0, r0, c7, c10, 5 @ memory barrier + mov r0, r2 @ Setup return value + bx lr @ Return + +@ void SST_Atomic_Xor(volatile int* x, int value) +SST_Atomic_Xor: +SST_Atomic_XorReturn: + mcr p15, 0, r0, c7, c10, 5 @ memory barrier + + _again5: + ldrex r2, [r0] @ r2 <- *x + eor r2, r2, r1 @ r2 ^= value + strex r3, r2, [r0] @ try { *x <- r2 } + teq r3, #0 @ success? + bne _again5 @ No, reload and retry + + mcr p15, 0, r0, c7, c10, 5 @ memory barrier + mov r0, r2 @ Setup return value + bx lr @ Return + +@ void SST_Atomic_Not(volatile int* x) +SST_Atomic_Not: +SST_Atomic_NotReturn: + mcr p15, 0, r0, c7, c10, 5 @ memory barrier + + _again4: + ldrex r2, [r0] @ r2 <- *x + mvn r2, r2 @ r2 = ~value + strex r3, r2, [r0] @ try { *x <- r2 } + teq r3, #0 @ success? + bne _again4 @ No, reload and retry + + mcr p15, 0, r0, c7, c10, 5 @ memory barrier + mov r0, r2 @ Setup return value + bx lr @ Return + + +@ int SST_Atomic_Exchange(volatile int* x, int value) +@ void* SST_Atomic_ExchangePtr(volatile void** x, void* value) +SST_Atomic_Exchange: +SST_Atomic_ExchangePtr: + mcr p15, 0, r0, c7, c10, 5 @ memory barrier + + _again3: + ldrex r2, [r0] @ r2 <- *x + strex r3, r1, [r0] @ try { *x <- r1 } + teq r3, #0 @ success? + bne _again3 @ No, reload and retry + + mcr p15, 0, r0, c7, c10, 5 @ memory barrier + mov r0, r2 @ Setup return value + bx lr @ Return + +@ int SST_Atomic_ExchangeAdd(volatile int* x, int value); +@ void* SST_Atomic_ExchangeAddPtr(volatile void** x, int value); +SST_Atomic_ExchangeAdd: +SST_Atomic_ExchangeAddPtr: + mcr p15, 0, r0, c7, c10, 5 @ memory barrier + push {r4} + + _again2: + ldrex r2, [r0] @ r2 <- *x + mov r4, r2 @ r4 <- *x + add r2, r2, r1 @ r2 += value + strex r3, r2, [r0] @ try { *x <- r2 } + teq r3, #0 @ success? + bne _again2 @ No, reload and retry + + mcr p15, 0, r0, c7, c10, 5 @ memory barrier + mov r0, r4 @ Setup return value as the old value of *x + pop {r4} + bx lr @ Return + + +@ int SST_Atomic_CAS(int* dest, int compare, int newValue); +@ void* SST_Atomic_CASPtr(void** dest, void* compare, void* newValue); +SST_Atomic_CAS: +SST_Atomic_CASPtr: + mcr p15, 0, r0, c7, c10, 5 @ memory barrier + push {r4} + mov r4, #0 + + _again1: + ldrex r3, [r0] @ r3 <- *dest + teq r3, r1 @ if(r3 == compare) { + strexeq r4, r2, [r0] @ try { *dest <- newValue } } + teq r4, #0 @ success? + bne _again1 @ No, reload and retry + + mcr p15, 0, r0, c7, c10, 5 @ memory barrier + mov r0, r3 @ Setup return value as the value of *dest + pop {r4} + bx lr @ Return + + + +SST_Atomic_LoadAcquire: +SST_Atomic_LoadAcquirePtr: + ldr r0, [r0] + mcr p15, 0, r0, c7, c10, 5 @ memory barrier + bx lr + +SST_Atomic_StoreRelease: +SST_Atomic_StoreReleasePtr: + mcr p15, 0, r0, c7, c10, 5 @ memory barrier + str r1, [r0] + bx lr diff --git a/libsst-atomic/SST_Atomic_ia64.asm b/libsst-atomic/SST_Atomic_ia64.asm new file mode 100644 index 0000000..ef5206f --- /dev/null +++ b/libsst-atomic/SST_Atomic_ia64.asm @@ -0,0 +1,265 @@ +// SST_Atomic_ia64.asm +// Author: Patrick Baggett +// Created: 4/16/2012 +// +// Purpose: +// +// Assembly for Itanium processors (aka ia64) +// Assembles with Intel ias assembler or GNU as. +// +// License: +// +// This program is free software. It comes without any warranty, to +// the extent permitted by applicable law. You can redistribute it +// and/or modify it under the terms of the Do What The Fuck You Want +// To Public License, Version 2, as published by Sam Hocevar. See +// http://sam.zoy.org/wtfpl/COPYING for more details. + + +.global SST_Atomic_Add# +.global SST_Atomic_AddReturn# +.global SST_Atomic_AddPtr# +.global SST_Atomic_AddPtrReturn# +.global SST_Atomic_And# +.global SST_Atomic_AndReturn# +.global SST_Atomic_Or# +.global SST_Atomic_OrReturn# +.global SST_Atomic_Xor# +.global SST_Atomic_XorReturn# +.global SST_Atomic_Not# +.global SST_Atomic_NotReturn# +.global SST_Atomic_Exchange# +.global SST_Atomic_ExchangePtr# +.global SST_Atomic_ExchangeAdd# +.global SST_Atomic_ExchangeAddPtr# +.global SST_Atomic_CAS# +.global SST_Atomic_CASPtr# +.global SST_Atomic_LoadAcquire# +.global SST_Atomic_LoadAcquirePtr# +.global SST_Atomic_StoreRelease# +.global SST_Atomic_StoreReleasePtr# +.section .text + +.align 32 + +// SST_Atomic_Add(volatile int* x, int value); +// x = r32, value = r33 +SST_Atomic_Add: +SST_Atomic_AddReturn: + mf + ld4.bias r31 = [r32];; //ensure all memory operations happen first, then load *x into r31 + + mov ar.ccv = r31 //Set CCV to be *x + add r8 = r31, r33;; //generated summed r8 = (*x + value) + +try_again1: + cmpxchg4.acq r30 = [r32], r8, ar.ccv;; //compare [r32] to CCV, exchange with r8 is successful. r30 <- *x + + mov ar.ccv = r30 //CCV <- r30 + cmp4.ne.unc p15, p0 = r30, r31 //compare old value in *x with new value in *x + add r8 = r33, r30 //set up return value r8 = value + *x (new) + mov r31 = r30 //set up old *x to be the new value if we need to loop again + (p15) br.cond.dptk.few try_again1;; //branch if old *x != new *x + + br.ret.sptk.many b0;; + + +// SST_Atomic_AddPtr(volatile void** x, int value); +// x = r32, value = r33 +SST_Atomic_AddPtr: +SST_Atomic_AddPtrReturn: + sxt4 r29 = r33;; //sign extend value to 64-bit quantity + mf + ld8.bias r31 = [r32];; //ensure all memory operations happen first, then load *x into r31 + + mov ar.ccv = r31 //Set CCV to be *x + add r8 = r31, r29;; //generated summed r8 = (*x + value) + +try_again2: + cmpxchg8.acq r30 = [r32], r8, ar.ccv;; //compare [r32] to CCV, exchange with r8 is successful. r30 <- *x + + mov ar.ccv = r30 //CCV <- r30 + cmp.ne.unc p15, p0 = r30, r31 //compare old value in *x with new value in *x + add r8 = r29, r30 //set up return value r8 = value + *x (new) + mov r31 = r30 //set up old *x to be the new value if we need to loop again + (p15) br.cond.dptk.few try_again2;; //branch if old *x != new *x + + br.ret.sptk.many b0;; + + + +// SST_Atomic_And(volatile int* x, int value); +// x = r32, value = r33 +SST_Atomic_And: +SST_Atomic_AndReturn: + mf + ld4.bias r31 = [r32];; //ensure all memory operations happen first, then load *x into r31 + + mov ar.ccv = r31 //Set CCV to be *x + and r8 = r31, r33;; //generated r8 = (*x & value) + +try_again3: + cmpxchg4.acq r30 = [r32], r8, ar.ccv;; //compare [r32] to CCV, exchange with r8 is successful. r30 <- *x + + mov ar.ccv = r30 //CCV <- r30 + cmp4.ne.unc p15, p0 = r30, r31 //compare old value in *x with new value in *x + and r8 = r33, r30 //set up return value r8 = value & *x (new) + mov r31 = r30 //set up old *x to be the new value if we need to loop again + (p15) br.cond.dptk.few try_again3;; //branch if old *x != new *x + + br.ret.sptk.many b0;; + + +// SST_Atomic_Or(volatile int* x, int value); +// x = r32, value = r33 +SST_Atomic_Or: +SST_Atomic_OrReturn: + mf + ld4.bias r31 = [r32];; //ensure all memory operations happen first, then load *x into r31 + + mov ar.ccv = r31 //Set CCV to be *x + or r8 = r31, r33;; //generated r8 = (*x | value) + +try_again4: + cmpxchg4.acq r30 = [r32], r8, ar.ccv;; //compare [r32] to CCV, exchange with r8 is successful. r30 <- *x + + mov ar.ccv = r30 //CCV <- r30 + cmp4.ne.unc p15, p0 = r30, r31 //compare old value in *x with new value in *x + or r8 = r33, r30 //set up return value r8 = value | *x (new) + mov r31 = r30 //set up old *x to be the new value if we need to loop again + (p15) br.cond.dptk.few try_again4;; //branch if old *x != new *x + + br.ret.sptk.many b0;; + + +// SST_Atomic_Xor(volatile int* x, int value); +// x = r32, value = r33 +SST_Atomic_Xor: +SST_Atomic_XorReturn: + mf + ld4.bias r31 = [r32];; //ensure all memory operations happen first, then load *x into r31 + + mov ar.ccv = r31 //Set CCV to be *x + xor r8 = r31, r33;; //generated r8 = (*x | value) + +try_again5: + cmpxchg4.acq r30 = [r32], r8, ar.ccv;; //compare [r32] to CCV, exchange with r8 is successful. r30 <- *x + + mov ar.ccv = r30 //CCV <- r30 + cmp4.ne.unc p15, p0 = r30, r31 //compare old value in *x with new value in *x + xor r8 = r33, r30 //set up return value r8 = value & *x (new) + mov r31 = r30 //set up old *x to be the new value if we need to loop again + (p15) br.cond.dptk.few try_again5;; //branch if old *x != new *x + + br.ret.sptk.many b0;; + + +// SST_Atomic_Not(volatile int* x); +// x = r32 +SST_Atomic_Not: +SST_Atomic_NotReturn: + mf + ld4.bias r31 = [r32];; //ensure all memory operations happen first, then load *x into r31 + + mov ar.ccv = r31 //Set CCV to be *x + andcm r8 = -1, r31;; //generated r8 = ~(*x) + +try_again6: + cmpxchg4.acq r30 = [r32], r8, ar.ccv;; //compare [r32] to CCV, exchange with r8 is successful. r30 <- *x + + mov ar.ccv = r30 //CCV <- r30 (in case compare failed) + cmp4.ne.unc p15, p0 = r30, r31 //compare old value in *x with new value in *x + andcm r8 = -1, r30 //set up return value r8 = ~*x (new) + (p15) br.cond.dptk.few try_again6;; //branch if old *x != new *x + + br.ret.sptk.many b0;; + + +// SST_Atomic_Exchange(volatile int* x, int value); +// x = r32, value = r33 +SST_Atomic_Exchange: + mf + xchg4 r8 = [r32], r33 + br.ret.sptk.many b0;; + + +// SST_Atomic_ExchangePtr(volatile int* x, int value); +// x = r32, value = r33 +SST_Atomic_ExchangePtr: + mf + xchg8 r8 = [r32], r33 + br.ret.sptk.many b0;; + +// int SST_Atomic_ExchangeAdd(volatile int* x, int value) +SST_Atomic_ExchangeAdd: + mf + ld4.bias r31 = [r32];; //ensure all memory operations happen first, then load *x into r31 + + mov ar.ccv = r31 //Set CCV to be *x + add r30 = r31, r33;; //r30 = *x + value + +try_again9: + cmpxchg4.acq r8 = [r32], r30, ar.ccv;; //compare [r32] to CCV, exchange with r30 if successful. r8 <- *x + mov ar.ccv = r8 + cmp4.ne.unc p15, p0 = r8, r31 + mov r31 = r8 + add r30 = r33, r8 + (p15) br.cond.dptk.few try_again9;; + + br.ret.sptk.many b0;; + +// int SST_Atomic_ExchangeAddPtr(volatile void** x, int value) +SST_Atomic_ExchangeAddPtr: + sxt4 r29 = r33;; //sign extend value to 64 bits + mf + ld8.bias r31 = [r32];; //ensure all memory operations happen first, then load *x into r31 + + mov ar.ccv = r31 //Set CCV to be *x + add r30 = r31, r29;; //r30 = *x + value + +try_again10: + cmpxchg8.acq r8 = [r32], r30, ar.ccv;; //compare [r32] to CCV, exchange with r30 if successful. r8 <- *x + mov ar.ccv = r8 + cmp.ne.unc p15, p0 = r8, r31 + mov r31 = r8 + add r30 = r8, r29 + (p15) br.cond.dptk.few try_again10;; + + br.ret.sptk.many b0;; + +// x = r32, compare = r33, newValue = r34 +SST_Atomic_CAS: + mf + ld4.bias r31 = [r32];; //ensure all memory operations happen first, then load *x into r31 + mov ar.ccv = r33;; //Set CCV to be *x + cmpxchg4.acq r8 = [r32], r34, ar.ccv;; //compare [r32] to CCV, exchange with r34 is successful. r8 <- *x + br.ret.sptk.many b0;; + +// x = r32, compare = r33, newValue = r34 +SST_Atomic_CASPtr: + mf + ld8.bias r31 = [r32];; //ensure all memory operations happen first, then load *x into r31 + mov ar.ccv = r33;; //Set CCV to be *x + cmpxchg8.acq r8 = [r32], r34, ar.ccv;; //compare [r32] to CCV, exchange with r34 is successful. r8 <- *x + br.ret.sptk.many b0;; + +// int SST_Atomic_LoadAcquire(const volatile int* src); +SST_Atomic_LoadAcquire: + ld4.acq r8 = [r32];; //Load-with-acquire into return value register r8 + br.ret.sptk.many b0;; + +// void* SST_Atomic_LoadAcquirePtr(const volatile void** src); +SST_Atomic_LoadAcquirePtr: + ld8.acq r8 = [r32];; //Load-with-acquire into return value register r8 + br.ret.sptk.many b0;; + +// void SST_Atomic_StoreRelease(volatile int* dest, int value); +SST_Atomic_StoreRelease: + st4.rel [r32] = r33;; //Store with release + br.ret.sptk.many b0;; + + +// void SST_Atomic_StoreReleasePtr(volatile void** dest, void* value); +SST_Atomic_StoreReleasePtr: + st8.rel [r32] = r33;; //Store with release + br.ret.sptk.many b0;; \ No newline at end of file diff --git a/libsst-atomic/SST_Atomic_mips.asm b/libsst-atomic/SST_Atomic_mips.asm new file mode 100644 index 0000000..8668695 --- /dev/null +++ b/libsst-atomic/SST_Atomic_mips.asm @@ -0,0 +1,219 @@ +# SST_Atomic_mips.asm +# Author: Patrick Baggett <ptbaggett@762studios.com> +# Created: 1/15/2013 +# +# Purpose: +# +# 32-bit assembly for atomic operations for MIPS CPUs. Targets MIPS32R2 ISA, but should run on +# older MIPS machines (e.g. MIPS-III / Loongson). +# Assembles with GNU as (doubtfully IRIX) +# +# License: +# +# This program is free software. It comes without any warranty, to +# the extent permitted by applicable law. You can redistribute it +# and/or modify it under the terms of the Do What The Fuck You Want +# To Public License, Version 2, as published by Sam Hocevar. See +# http://sam.zoy.org/wtfpl/COPYING for more details. + +.text + +#Don't reorder instructions +.set noreorder + +# ELF symbol names +.global SST_Atomic_Add +.global SST_Atomic_AddPtr +.global SST_Atomic_And +.global SST_Atomic_Or +.global SST_Atomic_Xor +.global SST_Atomic_Not +.global SST_Atomic_AddReturn +.global SST_Atomic_AddPtrReturn +.global SST_Atomic_AndReturn +.global SST_Atomic_OrReturn +.global SST_Atomic_XorReturn +.global SST_Atomic_NotReturn +.global SST_Atomic_ExchangeAdd +.global SST_Atomic_ExchangeAddPtr +.global SST_Atomic_Exchange +.global SST_Atomic_ExchangePtr +.global SST_Atomic_CAS +.global SST_Atomic_CASPtr +.global SST_Atomic_LoadAcquire +.global SST_Atomic_LoadAcquirePtr +.global SST_Atomic_StoreRelease +.global SST_Atomic_StoreReleasePtr + +#=================================================================================== +# Since pointers and integers are the same size on 32-bit code (GCC), many of the +# integer/pointer code paths are the same. This of course only holds true +# for 32-bit compiles on MIPS, which is exactly this file. +#=================================================================================== + +# MIPS has a "sync" instruction with a bitfield describing "what" to sync, sort of like SPARC's "membar" instruction. +# By default, "sync" means "sync 0" -- a full memory barrier including I/O devices/instructions. This is a very heavy-weight operation and used for things like ordering MMIO accesses +# MIPS32R2 defines "sync 0x10" as a full memory barrier that doesn't synchronize I/O, and "sync 0x04" as a "write/write" memory barrier. However, +# we can't use MIPS32R2 code only. But as it would turn out, it is OK because "sync <k>" is treated like "sync 0" in older MIPS CPUs, meaning full barrier, +# but it will automatically be faster on MIPS32R2 CPUs. Neat. + + +# TODO: not sure if this is a CPU hazard on any remotely recent MIPS CPU (i.e. not MIPS-I or MIPS-II) +# : beq $rs, $rt, someLabel //compare rs to rt +# : addiu $rs, $rs, 1 //increment rs +# I can't find any literature that says this is not allowed on anything other than MIPS-I, which has no interlocks. + +# void SST_Atomic_Add(volatile int* x, int value) +# void SST_Atomic_AddPtr(volatile void** x, int value) +# int SST_Atomic_AddReturn(volatile int* x, int value) +# void* SST_Atomic_AddPtrReturn(volatile void** x, int value) +SST_Atomic_Add: +SST_Atomic_AddPtr: +SST_Atomic_AddReturn: +SST_Atomic_AddPtrReturn: + sync 0x10 # sync_mb + +1: + ll $t4, 0($a0) # t4 <- *x + addu $t5, $t4, $a1 # t5 <- t4 + value + sc $t5, 0($a0) # try { *x <- t5 }, set t5 = 1/0 depending + beqz $t5,1b # if failure, retry + addu $v0, $t4, $a1 # (delay slot) $v0 <- *x + value (return value) + + jr $ra # return + sync 0x04 # (delay slot) sync_wmb + +# void SST_Atomic_And(volatile int* x, int value) +# int SST_Atomic_AndReturn(volatile int* x, int value) +SST_Atomic_And: +SST_Atomic_AndReturn: + sync 0x10 # sync_mb + +1: + ll $t4, 0($a0) # t4 <- *x + and $t5, $t4, $a1 # t5 <- t4 & value + sc $t5, 0($a0) # try { *x <- t5 }, set t5 = 1/0 depending + beqz $t5,1b # if failure, retry + and $v0, $t4, $a1 # (delay slot) compute return value + + jr $ra # return + sync 0x04 # (delay slot) sync_wmb + +# void SST_Atomic_Or(volatile int* x, int value) +# int SST_Atomic_OrReturn(volatile int* x, int value) +SST_Atomic_Or: +SST_Atomic_OrReturn: + sync 0x10 # sync_mb + +1: + ll $t4, 0($a0) # t4 <- *x + or $t5, $t4, $a1 # t5 <- t4 | value + sc $t5, 0($a0) # try { *x <- t5 }, set t5 = 1/0 depending + beqz $t5,1b # if failure, retry + or $v0, $t4, $a1 # (delay slot) compute return value + + jr $ra # return + sync 0x04 # (delay slot) sync_wmb + +# void SST_Atomic_Xor(volatile int* x, int value) +# int SST_Atomic_XorReturn(volatile int* x, int value) +SST_Atomic_XorReturn: +SST_Atomic_Xor: + sync 0x10 # sync_mb + +1: + ll $t4, 0($a0) # t4 <- *x + xor $t5, $t4, $a1 # t5 <- t4 ^ value + sc $t5, 0($a0) # try { *x <- t5 }, set t5 = 1/0 depending + beqz $t5,1b # if failure, retry + xor $v0, $t4, $a1 # (delay slot) Nothing to do + + jr $ra # return + sync 0x04 # (delay slot) sync_wmb + +# void SST_Atomic_Not(volatile int* x) +SST_Atomic_Not: +SST_Atomic_NotReturn: + sync 0x10 # sync_mb + +1: + ll $t4, 0($a0) # t4 <- *x + nor $t5, $t4, $0 # t5 <- ~t4 + sc $t5, 0($a0) # try { *x <- t5 }, set t5 = 1/0 depending + beqz $t5,1b # if failure, retry + nor $v0, $t4, $0 # (delay slot) compute return value + + jr $ra # return + sync 0x04 # (delay slot) sync_wmb + + +# int SST_Atomic_Exchange(volatile int* x, int value) +# void* SST_Atomic_ExchangePtr(volatile void** x, void* value) +SST_Atomic_Exchange: +SST_Atomic_ExchangePtr: + sync 0x10 # sync_mb + + move $t4, $a1 # t4 <- value + +1: + ll $v0, 0($a0) # v0 <- *x + sc $t4, 0($a0) # try { *x <- t4 }, set t4 = 1/0 depending + beqz $t4,1b # if failure, retry + move $t4, $a1 # (delay slot) reload t4 <- value for retry + + jr $ra # return + sync 0x04 # (delay slot) sync_wmb + + +# int SST_Atomic_ExchangeAdd(volatile int* x, int value); +# void* SST_Atomic_ExchangeAddPtr(volatile void** x, int value); +SST_Atomic_ExchangeAdd: +SST_Atomic_ExchangeAddPtr: + sync 0x10 # sync_mb + +1: + ll $v0, 0($a0) # v0 <- *x + addu $t4, $v0, $a1 # t4 <- v0 + value + sc $t4, 0($a0) # try { *x <- t4 }, set t4 = 1/0 depending + beqz $t4,1b # if failure, retry + nop # (delay slot) do nothing + + jr $ra # return + sync 0x04 # (delay slot) sync_wmb + + +# int SST_Atomic_CAS(int* dest, int compare, int newValue); +# void* SST_Atomic_CASPtr(void** dest, void* compare, void* newValue); +# a0 = dest, a1 = compare, a2 = newValue +SST_Atomic_CAS: +SST_Atomic_CASPtr: + sync 0x10 # sync_mb +1: + move $t4, $a2 # t4 <- newValue + ll $v0, 0($a0) # v0 <- *dest (captures "old" value of *dest, also is the return value) + bne $v0, $a1, 3f # compare v0 with a1 ("compare"), and if not equal, exit loop + nop # (delay slot) do nothing + sc $t4, 0($a0) # try { *x <- t4 }, set t4 = 1/0 depending + beqz $t4,1b # if failure, retry + nop # (delay slot) do nothing + + sync 0x04 # sync_wmb + +# Return +3: + jr $ra # return + nop # (delay slot) do nothing + +SST_Atomic_LoadAcquire: +SST_Atomic_LoadAcquirePtr: + lw $v0, 0($a0) + sync 0x11 # sync_acquire: LoadLoad | LoadStore + jr $ra + nop + +SST_Atomic_StoreRelease: +SST_Atomic_StoreReleasePtr: + sync 0x12 # sync_release: LoadStore | StoreStore + jr $ra + sw $a1, 0($a0) + diff --git a/libsst-atomic/SST_Atomic_mips64.asm b/libsst-atomic/SST_Atomic_mips64.asm new file mode 100644 index 0000000..465ad5d --- /dev/null +++ b/libsst-atomic/SST_Atomic_mips64.asm @@ -0,0 +1,277 @@ +# SST_Atomic_mips64.asm +# Author: Patrick Baggett <ptbaggett@762studios.com> +# Created: 7/1/2013 +# +# Purpose: +# +# 64-bit assembly for atomic operations for MIPS CPUs. Targets MIPS64R2 ISA, but should run on +# older MIPS machines (e.g. MIPS-III / Loongson). +# Assembles with GNU as (doubtfully IRIX) +# +# License: +# +# This program is free software. It comes without any warranty, to +# the extent permitted by applicable law. You can redistribute it +# and/or modify it under the terms of the Do What The Fuck You Want +# To Public License, Version 2, as published by Sam Hocevar. See +# http://sam.zoy.org/wtfpl/COPYING for more details. + +.text + +#Don't reorder instructions +.set noreorder + +# ELF symbol names +.global SST_Atomic_Add +.global SST_Atomic_AddPtr +.global SST_Atomic_And +.global SST_Atomic_Or +.global SST_Atomic_Xor +.global SST_Atomic_Not +.global SST_Atomic_AddReturn +.global SST_Atomic_AddPtrReturn +.global SST_Atomic_AndReturn +.global SST_Atomic_OrReturn +.global SST_Atomic_XorReturn +.global SST_Atomic_NotReturn +.global SST_Atomic_ExchangeAdd +.global SST_Atomic_ExchangeAddPtr +.global SST_Atomic_Exchange +.global SST_Atomic_ExchangePtr +.global SST_Atomic_CAS +.global SST_Atomic_CASPtr +.global SST_Atomic_LoadAcquire +.global SST_Atomic_LoadAcquirePtr +.global SST_Atomic_StoreRelease +.global SST_Atomic_StoreReleasePtr + +# Unbelievable. binutils-2.22 doesn't support register names in n64 (-mabi=64) mode, but it does in o32 (-mabi=32) +# Here are the symbolic names for registers used +# $v0-$v1 = $2-$3 +# $a0-$a4 = $4-$7 +# $t4-$t5 = $8-$9 +# $ra = $31 + + +# MIPS has a "sync" instruction with a bitfield describing "what" to sync, sort of like SPARC's "membar" instruction. +# By default, "sync" means "sync 0" -- a full memory barrier including I/O devices/instructions. This is a very heavy-weight operation and used for things like ordering MMIO accesses +# MIPS64R2 defines "sync 0x10" as a full memory barrier that doesn't synchronize I/O, and "sync 0x04" as a "write/write" memory barrier. However, +# we can't use MIPS64R2 code only. But as it would turn out, it is OK because "sync <k>" is treated like "sync 0" in older MIPS CPUs, meaning full barrier, +# but it will automatically be faster on MIPS32R2 CPUs. Neat. + +# void SST_Atomic_Add(volatile int* x, int value) +# int SST_Atomic_AddReturn(volatile int* x, int value) +SST_Atomic_Add: +SST_Atomic_AddReturn: + sync 0x10 # sync_mb + +1: + ll $12, 0($4) # t4 <- *x + addu $13, $12, $5 # t5 <- t4 + value + sc $13, 0($4) # try { *x <- t5 }, set t5 = 1/0 depending + beqz $13,1b # if failure, retry + addu $2, $12, $5 # (delay slot) $2 <- *x + value (return value) + + jr $31 # return + sync 0x04 # (delay slot) sync_wmb + +# void SST_Atomic_AddPtr(volatile void** x, int value) +# void* SST_Atomic_AddPtrReturn(volatile void** x, int value) +SST_Atomic_AddPtr: +SST_Atomic_AddPtrReturn: + sync 0x10 # sync_mb +1: + lld $12, 0($4) # t4 <- *x + daddu $13, $12, $5 # t5 <- t4 + value + scd $13, 0($4) # try { *x <- t5 }, set t5 = 1/0 depending + beqz $13,1b # if failure, retry + daddu $2, $12, $5 # (delay slot) $2 <- *x + value (return value) + + jr $31 # return + sync 0x04 # (delay slot) sync_wmb + + + +# void SST_Atomic_And(volatile int* x, int value) +# int SST_Atomic_AndReturn(volatile int* x, int value) +SST_Atomic_And: +SST_Atomic_AndReturn: + sync 0x10 # sync_mb + +1: + ll $12, 0($4) # t4 <- *x + and $13, $12, $5 # t5 <- t4 & value + sc $13, 0($4) # try { *x <- t5 }, set t5 = 1/0 depending + beqz $13,1b # if failure, retry + and $2, $12, $5 # (delay slot) compute return value + + jr $31 # return + sync 0x04 # (delay slot) sync_wmb + +# void SST_Atomic_Or(volatile int* x, int value) +# int SST_Atomic_OrReturn(volatile int* x, int value) +SST_Atomic_Or: +SST_Atomic_OrReturn: + sync 0x10 # sync_mb + +1: + ll $12, 0($4) # t4 <- *x + or $13, $12, $5 # t5 <- t4 | value + sc $13, 0($4) # try { *x <- t5 }, set t5 = 1/0 depending + beqz $13,1b # if failure, retry + or $2, $12, $5 # (delay slot) compute return value + + jr $31 # return + sync 0x04 # (delay slot) sync_wmb + +# void SST_Atomic_Xor(volatile int* x, int value) +# int SST_Atomic_XorReturn(volatile int* x, int value) +SST_Atomic_XorReturn: +SST_Atomic_Xor: + sync 0x10 # sync_mb + +1: + ll $12, 0($4) # t4 <- *x + xor $13, $12, $5 # t5 <- t4 ^ value + sc $13, 0($4) # try { *x <- t5 }, set t5 = 1/0 depending + beqz $13,1b # if failure, retry + xor $2, $12, $5 # (delay slot) Nothing to do + + jr $31 # return + sync 0x04 # (delay slot) sync_wmb + +# void SST_Atomic_Not(volatile int* x) +SST_Atomic_Not: +SST_Atomic_NotReturn: + sync 0x10 # sync_mb + +1: + ll $12, 0($4) # t4 <- *x + nor $13, $12, $0 # t5 <- ~t4 + sc $13, 0($4) # try { *x <- t5 }, set t5 = 1/0 depending + beqz $13,1b # if failure, retry + nor $2, $12, $0 # (delay slot) compute return value + + jr $31 # return + sync 0x04 # (delay slot) sync_wmb + + +# int SST_Atomic_Exchange(volatile int* x, int value) +SST_Atomic_Exchange: + sync 0x10 # sync_mb + + move $12, $5 # t4 <- value + +1: + ll $2, 0($4) # v0 <- *x + sc $12, 0($4) # try { *x <- t4 }, set t4 = 1/0 depending + beqz $12,1b # if failure, retry + move $12, $5 # (delay slot) reload t4 <- value for retry + + jr $31 # return + sync 0x04 # (delay slot) sync_wmb + +# void* SST_Atomic_ExchangePtr(volatile void** x, void* value) +SST_Atomic_ExchangePtr: + sync 0x10 # sync_mb + move $12, $5 # value for exchange +1: + lld $2, 0($4) # v0 <- *x + scd $12, 0($4) # try { *x <- t4 }, set t4 = 1/0 depending + beqz $12,1b # if failure, retry + move $12, $5 # (delay slot) t4 <- value for retry + + jr $31 # return + sync 0x04 # (delay slot) sync_wmb + +# int SST_Atomic_ExchangeAdd(volatile int* x, int value); +SST_Atomic_ExchangeAdd: + sync 0x10 # sync_mb + +1: + ll $2, 0($4) # v0 <- *x + addu $12, $2, $5 # t4 <- v0 + value + sc $12, 0($4) # try { *x <- t4 }, set t4 = 1/0 depending + beqz $12,1b # if failure, retry + nop # (delay slot) do nothing + + jr $31 # return + sync 0x04 # (delay slot) sync_wmb + +# void* SST_Atomic_ExchangeAddPtr(volatile void** x, int value); +SST_Atomic_ExchangeAddPtr: + sync 0x10 # sync_mb +1: + lld $2, 0($4) # v0 <- *x + daddu $12, $2, $5 # t4 <- v0 + value + scd $12, 0($4) # try { *x <- t4 }, set t4 = 1/0 depending + beqz $12,1b # if failure, retry + nop # (delay slot) do nothing + + jr $31 # return + sync 0x04 # (delay slot) sync_wmb + + + +# int SST_Atomic_CAS(int* dest, int compare, int newValue); +# a0 = dest, a1 = compare, a2 = newValue +SST_Atomic_CAS: + sync 0x10 # sync_mb +1: + move $12, $6 # t4 <- newValue + ll $2, 0($4) # v0 <- *dest (captures "old" value of *dest, also is the return value) + bne $2, $5, 3f # compare v0 with a1 ("compare"), and if not equal, exit loop + nop # (delay slot) do nothing + sc $12, 0($4) # try { *x <- t4 }, set t4 = 1/0 depending + beqz $12,1b # if failure, retry + nop # (delay slot) do nothing + + sync 0x04 # sync_wmb + +# Return +3: + jr $31 # return + nop # (delay slot) do nothing + +# void* SST_Atomic_CASPtr(void** dest, void* compare, void* newValue); +# a0 = dest, a1 = compare, a2 = newValue +SST_Atomic_CASPtr: + sync 0x10 # sync_mb +1: + move $12, $6 # t4 <- newValue + lld $2, 0($4) # v0 <- *dest (captures "old" value of *dest, also is the return value) + bne $2, $5, 3f # compare v0 with a1 ("compare"), and if not equal, exit loop + nop # (delay slot) do nothing + scd $12, 0($4) # try { *x <- t4 }, set t4 = 1/0 depending + beqz $12,1b # if failure, retry + nop # (delay slot) do nothing + + sync 0x04 # sync_wmb + +# Return +3: + jr $31 # return + nop # (delay slot) do nothing + +SST_Atomic_LoadAcquire: + lw $2, 0($4) + sync 0x11 # sync_acquire: LoadLoad | LoadStore + jr $31 + nop + +SST_Atomic_StoreRelease: + sync 0x12 # sync_release: LoadStore | StoreStore + jr $31 + sw $5, 0($4) + +SST_Atomic_LoadAcquirePtr: + ld $2, 0($4) + sync 0x11 # sync_acquire: LoadLoad | LoadStore + jr $31 + nop + +SST_Atomic_StoreReleasePtr: + sync 0x12 # sync_release: LoadStore | StoreStore + jr $31 + sd $5, 0($4) + diff --git a/libsst-atomic/SST_Atomic_ppc.asm b/libsst-atomic/SST_Atomic_ppc.asm new file mode 100644 index 0000000..35c149b --- /dev/null +++ b/libsst-atomic/SST_Atomic_ppc.asm @@ -0,0 +1,201 @@ +/* + SST_Atomic_ppc.asm + Author: Patrick Baggett + Created: 7/20/2012 + + Purpose: + + 32-bit assembly for Power Architecture processors. + Assembles with GNU as. + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. +*/ + +.global SST_Atomic_Add +.global SST_Atomic_AddPtr +.global SST_Atomic_And +.global SST_Atomic_Or +.global SST_Atomic_Xor +.global SST_Atomic_Not +.global SST_Atomic_AddReturn +.global SST_Atomic_AddPtrReturn +.global SST_Atomic_AndReturn +.global SST_Atomic_OrReturn +.global SST_Atomic_XorReturn +.global SST_Atomic_NotReturn +.global SST_Atomic_ExchangeAdd +.global SST_Atomic_ExchangeAddPtr +.global SST_Atomic_Exchange +.global SST_Atomic_ExchangePtr +.global SST_Atomic_CAS +.global SST_Atomic_CASPtr +.global SST_Atomic_LoadAcquire +.global SST_Atomic_LoadAcquirePtr +.global SST_Atomic_StoreRelease +.global SST_Atomic_StoreReleasePtr + +/* + This is for 32-bit Power arch, so the pointer versions are the same as + the non-pointer versions. + These are all leaf functions, so r3-r11 are legal to use. +*/ + +/* void SST_Atomic_Add(volatile int* x, int value) */ +/* void SST_Atomic_AddPtr(volatile void* x, int value) */ +/* void* SST_Atomic_AddPtrReturn(volatile void* x, int value) */ +/* int SST_Atomic_AddReturn(volatile int* x, int value) */ +SST_Atomic_Add: +SST_Atomic_AddPtr: +SST_Atomic_AddReturn: +SST_Atomic_AddPtrReturn: + mr r5, r3 /* r5 = x */ + sync /* mem barrier */ + +1: + lwarx r6, 0, r5 /* r6 = *x */ + add r3, r6, r4 /* return_value = r6 + value */ + add r6, r6, r4 /* r6 += value */ + stwcx. r6, 0, r5 /* try { *x = sum } */ + bne- 1b /* retry? */ + + isync /* order future L/S instructions */ + blr + + +/* void SST_Atomic_And(volatile int* x, int value) */ +/* int SST_Atomic_AndReturn(volatile int* x, int value) */ +SST_Atomic_And: +SST_Atomic_AndReturn: + mr r5, r3 /* r5 = x */ + sync /* mem barrier */ + +1: + lwarx r6, 0, r5 /* r6 = *x */ + and r3, r6, r4 /* return_value = r6 & value */ + and r6, r6, r4 /* r6 &= value */ + stwcx. r6, 0, r5 /* try { *x = result } */ + bne- 1b /* retry? */ + + isync /* order future L/S instructions */ + blr + + + +/* void SST_Atomic_Or(volatile int* x, int value) */ +/* int SST_Atomic_OrReturn(volatile int* x, int value) */ +SST_Atomic_Or: +SST_Atomic_OrReturn: + mr r5, r3 /* r5 = x */ + sync /* mem barrier */ + +1: + lwarx r6, 0, r5 /* r6 = *x */ + or r3, r6, r4 /* return_value = r6 | value */ + or r6, r6, r4 /* r6 |= value */ + stwcx. r6, 0, r5 /* try { *x = result } */ + bne- 1b /* retry? */ + + isync /* order future L/S instructions */ + blr + +/* void SST_Atomic_Xor(volatile int* x, int value) */ +/* int SST_Atomic_XorReturn(volatile int* x, int value) */ +SST_Atomic_Xor: +SST_Atomic_XorReturn: + mr r5, r3 /* r5 = x */ + sync /* mem barrier */ + +1: + lwarx r6, 0, r5 /* r6 = *x */ + xor r3, r6, r4 /* return_value = r6 ^ value */ + xor r6, r6, r4 /* r6 ^= value */ + stwcx. r6, 0, r5 /* try { *x = result } */ + bne- 1b /* retry? */ + + isync /* order future L/S instructions */ + blr + +/* void SST_Atomic_Not(volatile int* x) */ +/* int SST_Atomic_NotReturn(volatile int* x) */ +SST_Atomic_Not: +SST_Atomic_NotReturn: + mr r4, r3 /* r4 = x */ + sync /* mem barrier */ + +1: + lwarx r3, 0, r4 /* r3 = *x */ + nor r3, r3, r3 /* r5 = ~r5 */ + stwcx. r3, 0, r4 /* try { *x = sum } */ + bne- 1b /* retry? */ + + isync /* order future L/S instructions */ + blr + +/* int SST_Atomic_Exchange(volatile int* x, int value) */ +/* int SST_Atomic_ExchangePtr(volatile void** x, void* value) */ +SST_Atomic_Exchange: +SST_Atomic_ExchangePtr: + mr r5, r3 /* r5 = x */ + sync /* mem barrier */ + +1: + lwarx r3, 0, r5 /* try { return_value = *x */ + stwcx. r4, 0, r5 /* *x = value } */ + bne- 1b /* retry? */ + + isync /* order future L/S instructions */ + blr + +/* int SST_Atomic_CAS(volatile int* dest, int compare, int newValue) */ +SST_Atomic_CAS: +SST_Atomic_CASPtr: + mr r6, r3 /* r6 = dest */ + sync /* mem barrier */ + +1: + lwarx r3, 0, r6 /* return_value = *dest */ + cmpw r4, r3 /* if(return_value != compare) */ + bne- 2f /* return return_value; */ + stwcx. r5, 0, r6 /* else { *dest = newValue } */ + bne- 1b /* retry? */ + isync /* order future L/S instructions */ +2: + blr + +/* void* SST_Atomic_ExchangeAdd(volatile void* x, int value) */ +/* int SST_Atomic_(volatile int* x, int value) */ +SST_Atomic_ExchangeAdd: +SST_Atomic_ExchangeAddPtr: + mr r5, r3 /* r5 = x */ + sync /* mem barrier */ + +1: + lwarx r3, 0, r5 /* r3 = *x */ + add r6, r3, r4 /* r6 = *x + value */ + stwcx. r6, 0, r5 /* try { *x = sum } */ + bne- 1b /* retry? */ + + isync /* order future L/S instructions */ + blr + +/* int SST_Atomic_LoadAcquire(const volatile int* src); */ +/* void* SST_Atomic_LoadAcquirePtr(const volatile void** src); */ +SST_Atomic_LoadAcquire: +SST_Atomic_LoadAcquirePtr: + lw r3, 0, r3 + isync /* order future L/S instructions */ + blr + +/* void SST_Atomic_StoreRelease(volatile int* dest, int value); */ +/* void SST_Atomic_StoreReleasePtr(volatile void** dest, void* value); */ +SST_Atomic_StoreRelease: +SST_Atomic_StoreReleasePtr: + lwsync + stw r4, 0, r3 + blr diff --git a/libsst-atomic/SST_Atomic_sparc.asm b/libsst-atomic/SST_Atomic_sparc.asm new file mode 100644 index 0000000..8e7b176 --- /dev/null +++ b/libsst-atomic/SST_Atomic_sparc.asm @@ -0,0 +1,214 @@ +/* + SST_Atomic_sparc.asm + Author: Patrick Baggett + Created: 12/28/2011 + + Purpose: + + 32-bit assembly for SPARCv9 processors (aka v8+) + Older SPARC CPUs (e.g. sun4m) are not supported. + Assembles with Solaris assembler or GNU as. + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. +*/ + +.global SST_Atomic_Add +.global SST_Atomic_AddPtr +.global SST_Atomic_And +.global SST_Atomic_Or +.global SST_Atomic_Xor +.global SST_Atomic_Not +.global SST_Atomic_AddReturn +.global SST_Atomic_AddPtrReturn +.global SST_Atomic_AndReturn +.global SST_Atomic_OrReturn +.global SST_Atomic_XorReturn +.global SST_Atomic_NotReturn +.global SST_Atomic_ExchangeAdd +.global SST_Atomic_ExchangeAddPtr +.global SST_Atomic_Exchange +.global SST_Atomic_ExchangePtr +.global SST_Atomic_CAS +.global SST_Atomic_CASPtr +.global SST_Atomic_LoadAcquire +.global SST_Atomic_LoadAcquirePtr +.global SST_Atomic_StoreRelease +.global SST_Atomic_StoreReleasePtr + +/* + This is for 32-bit SPARC code, so the pointer versions are the same as + the non-pointer versions. + These are all leaf functions, so %o0-%o5 and %g1 are legal to use. +*/ + +/* void SST_Atomic_Add(volatile int* x, int value) */ +/* void SST_Atomic_AddPtr(volatile void* x, int value) */ +/* void* SST_Atomic_AddPtrReturn(volatile void* x, int value) */ +/* int SST_Atomic_AddReturn(volatile int* x, int value) */ +SST_Atomic_Add: +SST_Atomic_AddPtr: +SST_Atomic_AddReturn: +SST_Atomic_AddPtrReturn: + ld [%o0], %o4 /* o4 = *x */ + 1: + add %o1, %o4, %o5 /* o5 = *x + value */ + cas [%o0], %o4, %o5 /* compare and swap */ + + cmp %o4, %o5 /* compare what was in mem with our value */ + bne,a,pn %icc, 1b /* not the same -> try again. */ + mov %o5, %o4 /* restore o4, it should contain *x */ + + /* membar #StoreStore | #StoreLoad Force stores to complete before loads */ + + retl /* Success */ + add %o1, %o5, %o0 /* could do nop, but delay slot is free. + then we can make the "Return" versions + use the same code path */ + + + +/* void SST_Atomic_And(volatile int* x, int value) */ +/* int SST_Atomic_AndReturn(volatile int* x, int value) */ +SST_Atomic_And: +SST_Atomic_AndReturn: + ld [%o0], %o4 /* o4 = *x */ + 1: + and %o1, %o4, %o5 /* o5 = *x & value */ + cas [%o0], %o4, %o5 /* compare and swap */ + + cmp %o4, %o5 /* compare what was in mem with our value */ + bne,a,pn %icc, 1b /* not the same -> try again. */ + mov %o5, %o4 /* restore o4, it should contain *x */ + + /* membar #StoreStore | #StoreLoad Force stores to complete before loads */ + + retl /* Success */ + and %o1, %o5, %o0 /* could do nop, but delay slot is free. + then we can make the "Return" versions + use the same code path */ + + + +/* void SST_Atomic_Or(volatile int* x, int value) */ +/* int SST_Atomic_OrReturn(volatile int* x, int value) */ +SST_Atomic_Or: +SST_Atomic_OrReturn: + ld [%o0], %o4 /* o4 = *x */ + 1: + or %o1, %o4, %o5 /* o5 = *x | value */ + cas [%o0], %o4, %o5 /* compare and swap */ + + cmp %o4, %o5 /* compare what was in mem with our value */ + bne,a,pn %icc, 1b /* not the same -> try again. */ + mov %o5, %o4 /* restore o4, it should contain *x */ + + /* membar #StoreStore | #StoreLoad Force stores to complete before loads */ + + retl /* Success */ + or %o1, %o5, %o0 /* could do nop, but delay slot is free. + then we can make the "Return" versions + use the same code path */ + + +/* void SST_Atomic_Xor(volatile int* x, int value) */ +/* int SST_Atomic_XorReturn(volatile int* x, int value) */ +SST_Atomic_Xor: +SST_Atomic_XorReturn: + ld [%o0], %o4 /* o4 = *x */ + 1: + xor %o1, %o4, %o5 /* o5 = *x | value */ + cas [%o0], %o4, %o5 /* compare and swap */ + + cmp %o4, %o5 /* compare what was in mem with our value */ + bne,a,pn %icc, 1b /* not the same -> try again. */ + mov %o5, %o4 /* restore o4, it should contain *x */ + + /* membar #StoreStore | #StoreLoad Force stores to complete before loads */ + + retl /* Success */ + xor %o1, %o5, %o0 /* could do nop, but delay slot is free. + then we can make the "Return" versions + use the same code path */ + +/* void SST_Atomic_Not(volatile int* x) */ +/* int SST_Atomic_NotReturn(volatile int* x) */ +SST_Atomic_Not: +SST_Atomic_NotReturn: + ld [%o0], %o4 /* o4 = *x */ + 1: + not %o4, %o5 /* o5 = ~*x */ + cas [%o0], %o4, %o5 /* compare and swap */ + + cmp %o4, %o5 /* compare what was in mem with our value */ + bne,a,pn %icc, 1b /* not the same -> try again. */ + mov %o5, %o4 /* restore o4, it should contain *x */ + + /* membar #StoreStore | #StoreLoad Force stores to complete before loads */ + + retl /* Success */ + not %o4, %o0 /* could do nop, but delay slot is free. + then we can make the "Return" versions + use the same code path */ + +/* int SST_Atomic_Exchange(volatile int* x, int value) */ +/* int SST_Atomic_ExchangePtr(volatile void** x, void* value) */ +SST_Atomic_Exchange: +SST_Atomic_ExchangePtr: + swap [%o0], %o1 /* swap(*x, value) */ + retl + mov %o1, %o0 /* move return value to %o0 */ +/* NOTE: SPARCv9 manual calls the "swap" instruction deprecated. I don't + understand why. "cas" could fail, when really, we don't care if the + value changed, we care about ensuring that only 1 thread gets that value, + i.e. if 3 threads execute "swap" at the same time using 3 different values, + it is undefined which value is the final value, but each thread gets a + different value (thus, it is atomic). +*/ + +/* int SST_Atomic_CAS(volatile int* dest, int compare, int newValue) */ +SST_Atomic_CAS: +SST_Atomic_CASPtr: + cas [%o0], %o1, %o2 + retl + mov %o2, %o0 + +/* void* SST_Atomic_ExchangeAdd(volatile void* x, int value) */ +/* int SST_Atomic_(volatile int* x, int value) */ +SST_Atomic_ExchangeAdd: +SST_Atomic_ExchangeAddPtr: + ld [%o0], %o4 /* o4 = *x */ + 1: + add %o1, %o4, %o5 /* o5 = *x + value */ + cas [%o0], %o4, %o5 /* compare and swap */ + + cmp %o4, %o5 /* compare what was in mem with our value */ + bne,a,pn %icc, 1b /* not the same -> try again. */ + mov %o5, %o4 /* restore o4, it should contain *x */ + + /* membar #StoreStore | #StoreLoad Force stores to complete before loads */ + + retl /* Success */ + mov %o4, %o0 /* %o4 = value before add */ + +/* int SST_Atomic_LoadAcquire(const volatile int* src); */ +/* void* SST_Atomic_LoadAcquirePtr(const volatile void** src); */ +SST_Atomic_LoadAcquire: +SST_Atomic_LoadAcquirePtr: + ld [%o0], %o0 + membar #LoadStore | #LoadLoad + retl + nop + +/* void SST_Atomic_StoreRelease(volatile int* dest, int value); */ +/* void SST_Atomic_StoreReleasePtr(volatile void** dest, void* value); */ +SST_Atomic_StoreRelease: +SST_Atomic_StoreReleasePtr: + membar #LoadStore | #StoreStore + retl + st %o1, [%o0] diff --git a/libsst-atomic/SST_Atomic_sparc64.asm b/libsst-atomic/SST_Atomic_sparc64.asm new file mode 100644 index 0000000..32b0164 --- /dev/null +++ b/libsst-atomic/SST_Atomic_sparc64.asm @@ -0,0 +1,254 @@ +/* + SST_Atomic_sparc64.asm + Author: Patrick Baggett + Created: 4/3/2012 + + Purpose: + + 64-bit assembly for SPARCv9 processors + Assembles with Solaris assembler or GNU as. + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. +*/ + +.global SST_Atomic_Add +.global SST_Atomic_AddPtr +.global SST_Atomic_And +.global SST_Atomic_Or +.global SST_Atomic_Xor +.global SST_Atomic_Not +.global SST_Atomic_AddReturn +.global SST_Atomic_AddPtrReturn +.global SST_Atomic_AndReturn +.global SST_Atomic_OrReturn +.global SST_Atomic_XorReturn +.global SST_Atomic_NotReturn +.global SST_Atomic_ExchangeAdd +.global SST_Atomic_ExchangeAddPtr +.global SST_Atomic_Exchange +.global SST_Atomic_ExchangePtr +.global SST_Atomic_CAS +.global SST_Atomic_CASPtr +.global SST_Atomic_LoadAcquire +.global SST_Atomic_LoadAcquirePtr +.global SST_Atomic_StoreRelease +.global SST_Atomic_StoreReleasePtr + +/* + This is for 64-bit SPARC code, so the pointer versions are different + from the non-pointer versions. + These are all leaf functions, so %o0-%o5 and %g1 are legal to use. + + On TSO model, only "membar #StoreLoad" is a true barrier, the + rest are no-ops. This code assumes RMO. +*/ + +/* void SST_Atomic_Add(volatile int* x, int value) */ +/* int SST_Atomic_AddReturn(volatile int* x, int value) */ +SST_Atomic_Add: +SST_Atomic_AddReturn: + ld [%o0], %o4 /* o4 = *x */ + 1: + add %o1, %o4, %o5 /* o5 = *x + value */ + cas [%o0], %o4, %o5 /* compare and swap */ + + cmp %o4, %o5 /* compare what was in mem with our value */ + bne,a,pn %icc, 1b /* not the same -> try again. */ + mov %o5, %o4 /* restore o4, it should contain *x */ + + retl /* Success */ + add %o1, %o5, %o0 /* return sum */ + +/******************************************************************************/ + +/* void SST_Atomic_AddPtr(volatile void* x, int value) */ +/* void* SST_Atomic_AddPtrReturn(volatile void* x, int value) */ +SST_Atomic_AddPtr: +SST_Atomic_AddPtrReturn: + ldx [%o0], %o4 /* o4 = *x */ + 1: + add %o1, %o4, %o5 /* o5 = *x + value */ + casx [%o0], %o4, %o5 /* compare and swap */ + + cmp %o4, %o5 /* compare what was in mem with our value */ + bne,a,pn %xcc, 1b /* not the same -> try again. */ + mov %o5, %o4 /* restore o4, it should contain *x */ + + retl /* Success */ + add %o1, %o5, %o0 /* return sum */ + +/* void SST_Atomic_And(volatile int* x, int value) */ +/* int SST_Atomic_AndReturn(volatile int* x, int value) */ +SST_Atomic_And: +SST_Atomic_AndReturn: + ld [%o0], %o4 /* o4 = *x */ + 1: + and %o1, %o4, %o5 /* o5 = *x & value */ + cas [%o0], %o4, %o5 /* compare and swap */ + + cmp %o4, %o5 /* compare what was in mem with our value */ + bne,a,pn %icc, 1b /* not the same -> try again. */ + mov %o5, %o4 /* restore o4, it should contain *x */ + + retl /* Success */ + and %o1, %o5, %o0 /* could do nop, but delay slot is free. + then we can make the "Return" versions + use the same code path */ + +/* void SST_Atomic_Or(volatile int* x, int value) */ +/* int SST_Atomic_OrReturn(volatile int* x, int value) */ +SST_Atomic_Or: +SST_Atomic_OrReturn: + ld [%o0], %o4 /* o4 = *x */ + 1: + or %o1, %o4, %o5 /* o5 = *x | value */ + cas [%o0], %o4, %o5 /* compare and swap */ + + cmp %o4, %o5 /* compare what was in mem with our value */ + bne,a,pn %icc, 1b /* not the same -> try again. */ + mov %o5, %o4 /* restore o4, it should contain *x */ + + retl /* Success */ + or %o1, %o5, %o0 /* could do nop, but delay slot is free. + then we can make the "Return" versions + use the same code path */ + + +/* void SST_Atomic_Xor(volatile int* x, int value) */ +/* int SST_Atomic_XorReturn(volatile int* x, int value) */ +SST_Atomic_Xor: +SST_Atomic_XorReturn: + ld [%o0], %o4 /* o4 = *x */ + 1: + xor %o1, %o4, %o5 /* o5 = *x | value */ + cas [%o0], %o4, %o5 /* compare and swap */ + + cmp %o4, %o5 /* compare what was in mem with our value */ + bne,a,pn %icc, 1b /* not the same -> try again. */ + mov %o5, %o4 /* restore o4, it should contain *x */ + + retl /* Success */ + xor %o1, %o5, %o0 /* could do nop, but delay slot is free. + then we can make the "Return" versions + use the same code path */ + +/* void SST_Atomic_Not(volatile int* x) */ +/* int SST_Atomic_NotReturn(volatile int* x) */ +SST_Atomic_Not: +SST_Atomic_NotReturn: + ld [%o0], %o4 /* o4 = *x */ + 1: + not %o4, %o5 /* o5 = ~*x */ + cas [%o0], %o4, %o5 /* compare and swap */ + + cmp %o4, %o5 /* compare what was in mem with our value */ + bne,a,pn %icc, 1b /* not the same -> try again. */ + mov %o5, %o4 /* restore o4, it should contain *x */ + + retl /* Success */ + not %o4, %o0 /* could do nop, but delay slot is free. + then we can make the "Return" versions + use the same code path */ + +/* int SST_Atomic_Exchange(volatile int* x, int value) */ +SST_Atomic_Exchange: + ld [%o0], %o4 /* o4 = *x */ + 1: + mov %o1, %o5 /* o5 = value */ + cas [%o0], %o4, %o5 /* compare and swap */ + + cmp %o4, %o5 /* compare what was in mem with our value */ + bne,a,pn %icc, 1b /* not the same -> try again. */ + mov %o5, %o4 /* restore o4, it should contain *x */ + + membar #StoreStore | #LoadStore /* Ensure ordering */ + + retl /* Success */ + mov %o4, %o0 + +/* int SST_Atomic_ExchangePtr(volatile void** x, void* value) */ +SST_Atomic_ExchangePtr: + ldx [%o0], %o4 /* o4 = *x */ + 1: + mov %o1, %o5 /* o5 = value */ + casx [%o0], %o4, %o5 /* compare and swap */ + + cmp %o4, %o5 /* compare what was in mem with our value */ + bne,a,pn %xcc, 1b /* not the same -> try again. */ + mov %o5, %o4 /* restore o4, it should contain *x */ + + membar #StoreStore | #LoadStore /* Ensure ordering */ + + retl /* Success */ + mov %o4, %o0 + +/* int SST_Atomic_CAS(volatile int* dest, int compare, int newValue) */ +SST_Atomic_CAS: + cas [%o0], %o1, %o2 + retl + mov %o2, %o0 + +SST_Atomic_CASPtr: + casx [%o0], %o1, %o2 + retl + mov %o2, %o0 + +/* void* SST_Atomic_ExchangeAdd(volatile int* x, int value) */ +SST_Atomic_ExchangeAdd: + ld [%o0], %o4 /* o4 = *x */ + 1: + add %o1, %o4, %o5 /* o5 = *x + value */ + cas [%o0], %o4, %o5 /* compare and swap */ + + cmp %o4, %o5 /* compare what was in mem with our value */ + bne,a,pn %icc, 1b /* not the same -> try again. */ + mov %o5, %o4 /* restore o4, it should contain *x */ + + retl /* Success */ + mov %o4, %o0 /* %o4 = value before add */ + + +SST_Atomic_ExchangeAddPtr: + ldx [%o0], %o4 /* o4 = *x */ + 1: + add %o1, %o4, %o5 /* o5 = *x + value */ + casx [%o0], %o4, %o5 /* compare and swap */ + + cmp %o4, %o5 /* compare what was in mem with our value */ + bne,a,pn %xcc, 1b /* not the same -> try again. */ + mov %o5, %o4 /* restore o4, it should contain *x */ + + retl /* Success */ + mov %o4, %o0 /* %o4 = value before add */ + +/* int SST_Atomic_LoadAcquire(const volatile int* src); */ +SST_Atomic_LoadAcquire: + ld [%o0], %o0 + membar #LoadStore | #LoadLoad + retl + nop + +/* void* SST_Atomic_LoadAcquirePtr(const volatile void** src); */ +SST_Atomic_LoadAcquirePtr: + ldx [%o0], %o0 + membar #LoadStore | #LoadLoad + retl + nop + +/* void SST_Atomic_StoreRelease(volatile int* dest, int value); */ +SST_Atomic_StoreRelease: + membar #LoadStore | #StoreStore + retl + st %o1, [%o0] + +/* void SST_Atomic_StoreReleasePtr(volatile void** dest, void* value); */ +SST_Atomic_StoreReleasePtr: + membar #LoadStore | #StoreStore + retl + stx %o1, [%o0] diff --git a/libsst-atomic/SST_Atomic_x86-64-win64.asm b/libsst-atomic/SST_Atomic_x86-64-win64.asm new file mode 100644 index 0000000..8b1e3cc --- /dev/null +++ b/libsst-atomic/SST_Atomic_x86-64-win64.asm @@ -0,0 +1,237 @@ +; SST_Atomic_x86-64-win64.asm +; Author: Patrick Baggett <ptbaggett@762studios.com> +; Created: 12/27/2011 +; +; Purpose: +; +; 64-bit assembly for atomic operations using the Microsoft x64 ABI +; Assembles with YASM 1.1/NASM 2.0+ +; +; License: +; +; This program is free software. It comes without any warranty, to +; the extent permitted by applicable law. You can redistribute it +; and/or modify it under the terms of the Do What The Fuck You Want +; To Public License, Version 2, as published by Sam Hocevar. See +; http://sam.zoy.org/wtfpl/COPYING for more details. + + +; Win64 and UNIX calling conventions differ for x64-64. I know, it's absurd. +; Because of this, there are separate implementation for Win64 and x64-64 UNIX (Linux, *BSD, Solaris, MacOS X, etc.) +; Here is the break down: +; +; REGISTER | Win64 | UNIX +;-----------+-----------+---------- +;rax | Retval | Retval +;rdi | Not used | 1st arg +;rsi | Not used | 2nd arg +;rcx | 1st arg | 3rd arg +;rdx | 2nd arg | 4th arg +;r8 | 3rd arg | 5th arg +;r9 | 4th arg | 6th arg + +[bits 64] +[segment .text] + +; Win32 symbol names +[global SST_Atomic_Add] +[global SST_Atomic_AddPtr] +[global SST_Atomic_And] +[global SST_Atomic_Or] +[global SST_Atomic_Xor] +[global SST_Atomic_Not] +[global SST_Atomic_AddReturn] +[global SST_Atomic_AddPtrReturn] +[global SST_Atomic_AndReturn] +[global SST_Atomic_OrReturn] +[global SST_Atomic_XorReturn] +[global SST_Atomic_NotReturn] +[global SST_Atomic_ExchangeAdd] +[global SST_Atomic_ExchangeAddPtr] +[global SST_Atomic_Exchange] +[global SST_Atomic_ExchangePtr] +[global SST_Atomic_CAS] +[global SST_Atomic_CASPtr] +[global SST_Atomic_LoadAcquire] +[global SST_Atomic_LoadAcquirePtr] +[global SST_Atomic_StoreRelease] +[global SST_Atomic_StoreReleasePtr] + +;======================================================================= +; Pointers and integers are different sized (64 bits vs 32 bits) so +; each SST_Atomic_XxxxPtr() function uses the full 64-bit registers. +;======================================================================= + + +;==================================================== +; MICROSOFT WIN64 ABI +;==================================================== + +;void SST_Atomic_Add(volatile int* x, int value) +SST_Atomic_Add: + lock add [rcx], edx + ret + +;void SST_Atomic_AddPtr(volatile void** x, int value) +SST_Atomic_AddPtr: + lock add [rcx], rdx + ret + +; void SST_Atomic_And(volatile int* x, int value) +SST_Atomic_And: + lock and [rcx], edx + ret + +; void SST_Atomic_Or(volatile int* x, int value) +SST_Atomic_Or: + lock or [rcx], edx + ret + +; void SST_Atomic_Xor(volatile int* x, int value) +SST_Atomic_Xor: + lock xor [rcx], edx + ret + +; void SST_Atomic_Not(volatile int* x) +SST_Atomic_Not: + lock not DWORD [rcx] + ret + +; int SST_Atomic_AddReturn(volatile int* x, int value) +SST_Atomic_AddReturn: + mov eax, edx + lock xadd [rcx], eax ; eax contains orig value before xadd + add eax, edx ; now add 'value' (in edx) to get the sum that was stored in *x + ret + +; int SST_Atomic_AddReturn(volatile void** x, int value) +SST_Atomic_AddPtrReturn: + mov rax, rdx + lock xadd [rcx], rax ; rax contains orig value before xadd + add rax, rdx ; now add 'value' (in rdx) to get the sum that was stored in *x + ret + +; int SST_Atomic_AndReturn(volatile int* x, int value) +SST_Atomic_AndReturn: + mov eax, [rcx] ;eax = *x + mov r8d, eax ;r8d = *x +try_again_5: + and r8d, edx ;r8d <- *x & value + + lock cmpxchg [rcx], r8d ;if(eax == *x) *x = r8d, else eax = *x + jz done_5 ;success -> *x was successfully updated. Its new value is in r8d. + mov r8d, eax ;failure -> *x was changed previous, new value is in eax. Copy that new value to r8d, let's try again + jmp try_again_5 +done_5: + mov eax,r8d ;r8d has the value (*x & value), so mov to eax for return value + ret + +SST_Atomic_OrReturn: + mov eax, [rcx] ;eax = *x + mov r8d, eax ;r8d = *x +try_again_6: + or r8d, edx ;r8d <- *x | value + + lock cmpxchg [rcx], r8d ;if(eax == *x) *x = r8d, else eax = *x + jz done_6 ;success -> *x was successfully updated. Its new value is in r8d. + mov r8d, eax ;failure -> *x was changed previous, new value is in eax. Copy that new value to r8d, let's try again + jmp try_again_6 +done_6: + mov eax,r8d ;r8d has the value (*x & value), so mov to eax for return value + ret + +SST_Atomic_XorReturn: + mov eax, [rcx] ;eax = *x + mov r8d, eax ;r8d = *x +try_again_7: + xor r8d, edx ;r8d <- *x ^ value + + lock cmpxchg [rcx], r8d ;if(eax == *x) *x = r8d, else eax = *x + jz done_7 ;success -> *x was successfully updated. Its new value is in r8d. + mov r8d, eax ;failure -> *x was changed previous, new value is in eax. Copy that new value to r8d, let's try again + jmp try_again_7 +done_7: + mov eax,r8d ;r8d has the value (*x & value), so mov to eax for return value + ret + +; int SST_Atomic_NotReturn(volatile int* x) +SST_Atomic_NotReturn: + mov eax, [rcx] ;eax = *x + mov r8d, eax ;r8d = *x +try_again_8: + not r8d ;r8d <- ~*x + + lock cmpxchg [rcx], r8d ;if(eax == *x) *x = r8d, else eax = *x + jz done_8 ;success -> *x was successfully updated. Its new value is in r8d. + mov r8d, eax ;failure -> *x was changed previous, new value is in eax. Copy that new value to r8d, let's try again + jmp try_again_8 +done_8: + mov eax,r8d ;r8d has the value (*x & value), so mov to eax for return value + ret + +;int SST_Atomic_Exchange(volatile int* x, int value) +SST_Atomic_Exchange: + lock xchg [rcx], edx + mov eax, edx + ret + +;void* SST_Atomic_ExchangePtr(volatile void** x, void* value) +SST_Atomic_ExchangePtr: + lock xchg [rcx], rdx + mov rax, rdx + ret + +;int SST_Atomic_ExchangeAdd(volatile int* x, int value); +SST_Atomic_ExchangeAdd: + lock xadd [rcx], edx + mov eax, edx + ret + +;void* SST_Atomic_ExchangeAddPtr(volatile void** x, int value); +SST_Atomic_ExchangeAddPtr: + lock xadd [rcx], rdx + mov rax, rdx + ret + +;int SST_Atomic_CAS(int* dest, int compare, int newValue); +SST_Atomic_CAS: + ;rcx <- dest + ;edx <- compare + ;r8d <- newValue + mov eax, edx + lock cmpxchg [rcx], r8d ;compare [rcx] with eax | swap with r8d if equal, else store [rcx] into eax + ret + +;void* SST_Atomic_CASPtr(void** dest, void* compare, void* newValue); +SST_Atomic_CASPtr: + ;rcx <- dest + ;rdx <- compare + ;r8 <- newValue + mov rax, rdx + lock cmpxchg [rcx], r8 ;compare [rcx] with rax | swap with r8 if equal, else store [rcx] into eax + ret + +; int SST_Atomic_LoadAcquire(const volatile int* src); +; NOTE: x86 has strong memory ordering, thus no barrier is necessary, except for compiler barrier to reordering instructions +SST_Atomic_LoadAcquire: + mov eax, [rcx] + ret + +; void* SST_Atomic_LoadAcquirePtr(const volatile void** src); +; NOTE: x86 has strong memory ordering, thus no barrier is necessary, except for compiler barrier to reordering instructions +SST_Atomic_LoadAcquirePtr: + mov rax, [rcx] + ret + +; void SST_Atomic_StoreRelease(volatile int* dest, int value); +; NOTE: x86 has strong memory ordering, thus no barrier is necessary, except for compiler barrier to reordering instructions +SST_Atomic_StoreRelease: + mov [rcx], edx + ret + +; void SST_Atomic_StoreReleasePtr(volatile void** dest, void* value); +; NOTE: x86 has strong memory ordering, thus no barrier is necessary, except for compiler barrier to reordering instructions +SST_Atomic_StoreReleasePtr: + mov [rcx], rdx + ret + diff --git a/libsst-atomic/SST_Atomic_x86-64.asm b/libsst-atomic/SST_Atomic_x86-64.asm new file mode 100644 index 0000000..688d4d5 --- /dev/null +++ b/libsst-atomic/SST_Atomic_x86-64.asm @@ -0,0 +1,285 @@ +; SST_Atomic_x86-64.asm +; Author: Patrick Baggett <ptb1@762studios.com> +; Created: 12/20/2011 +; +; Purpose: +; +; 64-bit assembly for atomic operations using the SysV x86-64 ABI +; Assembles with YASM 1.1/NASM 2.0+ +; +; License: +; +; This program is free software. It comes without any warranty, to +; the extent permitted by applicable law. You can redistribute it +; and/or modify it under the terms of the Do What The Fuck You Want +; To Public License, Version 2, as published by Sam Hocevar. See +; http://sam.zoy.org/wtfpl/COPYING for more details. + +; Win64 and UNIX calling conventions differ for x64-64. I know, it's absurd. +; Because of this, there are separate implementation for Win64 and x64-64 UNIX (Linux, *BSD, Solaris, MacOS X, etc.) +; Here is the break down: +; +; REGISTER | Win64 | UNIX +;-----------+-----------+---------- +;rax | Retval | Retval +;rdi | Not used | 1st arg +;rsi | Not used | 2nd arg +;rcx | 1st arg | 3rd arg +;rdx | 2nd arg | 4th arg +;r8 | 3rd arg | 5th arg +;r9 | 4th arg | 6th arg + +[bits 64] +[segment .text] + +; ELF symbol names (UNIX) +[global SST_Atomic_Add] +[global SST_Atomic_AddPtr] +[global SST_Atomic_And] +[global SST_Atomic_Or] +[global SST_Atomic_Xor] +[global SST_Atomic_Not] +[global SST_Atomic_AddReturn] +[global SST_Atomic_AddPtrReturn] +[global SST_Atomic_AndReturn] +[global SST_Atomic_OrReturn] +[global SST_Atomic_XorReturn] +[global SST_Atomic_NotReturn] +[global SST_Atomic_ExchangeAdd] +[global SST_Atomic_ExchangeAddPtr] +[global SST_Atomic_Exchange] +[global SST_Atomic_ExchangePtr] +[global SST_Atomic_CAS] +[global SST_Atomic_CASPtr] +[global SST_Atomic_LoadAcquire] +[global SST_Atomic_LoadAcquirePtr] +[global SST_Atomic_StoreRelease] +[global SST_Atomic_StoreReleasePtr] + + +; Mach-O symbol names (MacOS X) +[global _SST_Atomic_Add] +[global _SST_Atomic_AddPtr] +[global _SST_Atomic_And] +[global _SST_Atomic_Or] +[global _SST_Atomic_Xor] +[global _SST_Atomic_Not] +[global _SST_Atomic_AddReturn] +[global _SST_Atomic_AddPtrReturn] +[global _SST_Atomic_AndReturn] +[global _SST_Atomic_OrReturn] +[global _SST_Atomic_XorReturn] +[global _SST_Atomic_NotReturn] +[global _SST_Atomic_ExchangeAdd] +[global _SST_Atomic_ExchangeAddPtr] +[global _SST_Atomic_Exchange] +[global _SST_Atomic_ExchangePtr] +[global _SST_Atomic_CAS] +[global _SST_Atomic_CASPtr] +[global _SST_Atomic_LoadAcquire] +[global _SST_Atomic_LoadAcquirePtr] +[global _SST_Atomic_StoreRelease] +[global _SST_Atomic_StoreReleasePtr] + + +;======================================================================= +; Pointers and integers are different sized (64 bits vs 32 bits) so +; each SST_Atomic_XxxxPtr() function uses the full 64-bit registers. +;======================================================================= + +;==================================================== +; UNIX/ELF ABI +;==================================================== + +;void SST_Atomic_Add(volatile int* x, int value) + SST_Atomic_Add: +_SST_Atomic_Add: + lock add [rdi], esi + ret + +;void SST_Atomic_AddPtr(volatile void** x, int value) + SST_Atomic_AddPtr: +_SST_Atomic_AddPtr: + lock add [rdi], rsi + ret + +; void SST_Atomic_And(volatile int* x, int value) + SST_Atomic_And: +_SST_Atomic_And: + lock and [rdi], esi + ret + +; void SST_Atomic_Or(volatile int* x, int value) + SST_Atomic_Or: +_SST_Atomic_Or: + lock or [rdi], esi + ret + +; void SST_Atomic_Xor(volatile int* x, int value) + SST_Atomic_Xor: +_SST_Atomic_Xor: + lock xor [rdi], esi + ret + +; void SST_Atomic_Not(volatile int* x) + SST_Atomic_Not: +_SST_Atomic_Not: + lock not DWORD [rdi] + ret + +; int SST_Atomic_AddReturn(volatile int* x, int value) + SST_Atomic_AddReturn: +_SST_Atomic_AddReturn: + mov eax, esi + lock xadd [rdi], eax ; eax contains orig value before xadd + add eax, esi ; now add 'value' (in esi) to get the sum that was stored in *x + ret + +; int SST_Atomic_AddReturn(volatile void** x, int value) + SST_Atomic_AddPtrReturn: +_SST_Atomic_AddPtrReturn: + mov rax, rsi + lock xadd [rdi], rax ; rax contains orig value before xadd + add rax, rsi ; now add 'value' (in rsi) to get the sum that was stored in *x + ret + +; int SST_Atomic_AndReturn(volatile int* x, int value) + SST_Atomic_AndReturn: +_SST_Atomic_AndReturn: + mov eax, [rdi] ;eax = *x + mov edx, eax ;edx = *x +try_again_1: + and edx, esi ;edx <- *x & value + + lock cmpxchg [rdi], edx ;if(eax == *x) *x = edx, else eax = *x + jz done_1 ;success -> *x was successfully updated. It's new value is in edx + mov edx, eax ;failure -> *x was changed previous, new value is in eax. Copy that new value to edx, lets try again + jmp try_again_1 +done_1: + mov eax,edx ;edx has the value (*x & value), so mov to eax for return value + ret + + SST_Atomic_OrReturn: +_SST_Atomic_OrReturn: + mov eax, [rdi] ;eax = *x + mov edx, eax ;edx = *x +try_again_2: + or edx, esi ;edx <- *x | value + + lock cmpxchg [rdi], edx ;if(eax == *x) *x = edx, else eax = *x + jz done_2 ;success -> *x was successfully updated. It's new value is in edx + mov edx, eax ;failure -> *x was changed previous, new value is in eax. Copy that new value to edx, lets try again + jmp try_again_2 +done_2: + mov eax,edx ;edx has the value (*x | value), so mov to eax for return value + ret + + SST_Atomic_XorReturn: +_SST_Atomic_XorReturn: + mov eax, [rdi] ;eax = *x + mov edx, eax ;edx = *x +try_again_3: + xor edx, esi ;edx <- *x ^ value + + lock cmpxchg [rdi], edx ;if(eax == *x) *x = edx, else eax = *x + jz done_3 ;success -> *x was successfully updated. It's new value is in edx + mov edx, eax ;failure -> *x was changed previous, new value is in eax. Copy that new value to edx, lets try again + jmp try_again_3 +done_3: + mov eax,edx ;edx has the value (*x ^ value), so mov to eax for return value + ret + + +; int SST_Atomic_NotReturn(volatile int* x) + SST_Atomic_NotReturn: +_SST_Atomic_NotReturn: + mov eax, [rdi] ;eax = *x + mov edx, eax ;edx = *x +try_again_4: + not edx + + lock cmpxchg [rdi], edx ;if(eax == *x) *x = edx, else eax = *x + jz done_4 ;success -> *x was successfully updated. It's new value is in edx + mov edx, eax ;failure -> *x was changed previous, new value is in eax. Copy that new value to edx, lets try again + jmp try_again_4 +done_4: + mov eax,edx ;edx has the value (~*x), so mov to eax for return value + ret + +;int SST_Atomic_Exchange(volatile int* x, int value) + SST_Atomic_Exchange: +_SST_Atomic_Exchange: + lock xchg [rdi], esi + mov eax, esi + ret + +;void* SST_Atomic_ExchangePtr(volatile void** x, void* value) + SST_Atomic_ExchangePtr: +_SST_Atomic_ExchangePtr: + lock xchg [rdi], rsi + mov rax, rsi + ret + +;int SST_Atomic_ExchangeAdd(volatile int* x, int value); + SST_Atomic_ExchangeAdd: +_SST_Atomic_ExchangeAdd: + lock xadd [rdi],esi + mov eax, esi + ret + +;void* SST_Atomic_ExchangeAddPtr(volatile void** x, int value); + SST_Atomic_ExchangeAddPtr: +_SST_Atomic_ExchangeAddPtr: + lock xadd [rdi],rsi + mov rax, rsi + ret + +;int SST_Atomic_CAS(int* dest, int compare, int newValue); + SST_Atomic_CAS: +_SST_Atomic_CAS: + ;rdi <- dest + ;rsi <- compare + ;rdx <- newValue + mov eax, esi + lock cmpxchg [rdi], edx ;compare [rdi] with eax | swap with edx if equal, else store [rdi] into eax + ret + +;void* SST_Atomic_CASPtr(void** dest, void* compare, void* newValue); + SST_Atomic_CASPtr: +_SST_Atomic_CASPtr: + ;rdi <- dest + ;rsi <- compare + ;rdx <- newValue + mov rax, rsi + lock cmpxchg [rdi], rdx ;compare [rdi] with rax | swap with rdx if equal, else store [rdi] into rax + ret + + + +; int SST_Atomic_LoadAcquire(const volatile int* src); +; NOTE: x86 has strong memory ordering, thus no barrier is necessary, except for compiler barrier to reordering instructions + SST_Atomic_LoadAcquire: +_SST_Atomic_LoadAcquire: + mov eax, [rdi] + ret + +; void* SST_Atomic_LoadAcquirePtr(const volatile void** src); +; NOTE: x86 has strong memory ordering, thus no barrier is necessary, except for compiler barrier to reordering instructions + SST_Atomic_LoadAcquirePtr: +_SST_Atomic_LoadAcquirePtr: + mov rax, [rdi] + ret + +; void SST_Atomic_StoreRelease(volatile int* dest, int value); +; NOTE: x86 has strong memory ordering, thus no barrier is necessary, except for compiler barrier to reordering instructions + SST_Atomic_StoreRelease: +_SST_Atomic_StoreRelease: + mov [rdi], esi + ret + +; void SST_Atomic_StoreReleasePtr(volatile void** dest, void* value); +; NOTE: x86 has strong memory ordering, thus no barrier is necessary, except for compiler barrier to reordering instructions + SST_Atomic_StoreReleasePtr: +_SST_Atomic_StoreReleasePtr: + mov [rdi], rsi + ret diff --git a/libsst-atomic/SST_Atomic_x86.asm b/libsst-atomic/SST_Atomic_x86.asm new file mode 100644 index 0000000..38842ec --- /dev/null +++ b/libsst-atomic/SST_Atomic_x86.asm @@ -0,0 +1,271 @@ +; SST_Atomic_x86.asm +; Author: Patrick Baggett <ptbaggett@762studios.com> +; Created: 11/15/2011 +; +; Purpose: +; +; 32-bit assembly for atomic operations for x86 CPUs +; Assembles with YASM 1.1/NASM 2.0+ +; +; License: +; +; This program is free software. It comes without any warranty, to +; the extent permitted by applicable law. You can redistribute it +; and/or modify it under the terms of the Do What The Fuck You Want +; To Public License, Version 2, as published by Sam Hocevar. See +; http://sam.zoy.org/wtfpl/COPYING for more details. + +[bits 32] +[segment .text] + +; Win32 symbol names +[global _SST_Atomic_Add] +[global _SST_Atomic_AddPtr] +[global _SST_Atomic_And] +[global _SST_Atomic_Or] +[global _SST_Atomic_Xor] +[global _SST_Atomic_Not] +[global _SST_Atomic_AddReturn] +[global _SST_Atomic_AddPtrReturn] +[global _SST_Atomic_AndReturn] +[global _SST_Atomic_OrReturn] +[global _SST_Atomic_XorReturn] +[global _SST_Atomic_NotReturn] +[global _SST_Atomic_ExchangeAdd] +[global _SST_Atomic_ExchangeAddPtr] +[global _SST_Atomic_Exchange] +[global _SST_Atomic_ExchangePtr] +[global _SST_Atomic_CAS] +[global _SST_Atomic_CASPtr] +[global _SST_Atomic_LoadAcquire] +[global _SST_Atomic_LoadAcquirePtr] +[global _SST_Atomic_StoreRelease] +[global _SST_Atomic_StoreReleasePtr] + +; ELF symbol names +[global SST_Atomic_Add] +[global SST_Atomic_AddPtr] +[global SST_Atomic_And] +[global SST_Atomic_Or] +[global SST_Atomic_Xor] +[global SST_Atomic_Not] +[global SST_Atomic_AddReturn] +[global SST_Atomic_AddPtrReturn] +[global SST_Atomic_AndReturn] +[global SST_Atomic_OrReturn] +[global SST_Atomic_XorReturn] +[global SST_Atomic_NotReturn] +[global SST_Atomic_ExchangeAdd] +[global SST_Atomic_ExchangeAddPtr] +[global SST_Atomic_Exchange] +[global SST_Atomic_ExchangePtr] +[global SST_Atomic_CAS] +[global SST_Atomic_CASPtr] +[global SST_Atomic_LoadAcquire] +[global SST_Atomic_LoadAcquirePtr] +[global SST_Atomic_StoreRelease] +[global SST_Atomic_StoreReleasePtr] + +;======================================================================= +; Since pointers and integers are the same on GCC/MSVC, many of the +; integer/pointer code paths are the same. This of course only holds true +; for 32-bit compiles on x86, which is exactly this file. +;======================================================================= + + +;void SST_Atomic_Add(volatile int* x, int value) +;void SST_Atomic_AddPtr(volatile void* x, uintptr_t value) +_SST_Atomic_AddPtr: +_SST_Atomic_Add: + SST_Atomic_AddPtr: + SST_Atomic_Add: + mov edx, [esp+4] + mov eax, [esp+8] + lock add [edx], eax + ret + + +; void SST_Atomic_And(volatile int* x, int value) +_SST_Atomic_And: + SST_Atomic_And: + mov edx, [esp+4] + mov eax, [esp+8] + lock and [edx], eax + ret + +; void SST_Atomic_Or(volatile int* x, int value) +_SST_Atomic_Or: + SST_Atomic_Or: + mov edx, [esp+4] + mov eax, [esp+8] + lock or [edx], eax + ret + +; void SST_Atomic_Xor(volatile int* x, int value) +_SST_Atomic_Xor: + SST_Atomic_Xor: + mov edx, [esp+4] + mov eax, [esp+8] + lock xor [edx], eax + ret + +; void SST_Atomic_Not(volatile int* x) +_SST_Atomic_Not: + SST_Atomic_Not: + mov edx, [esp+4] + lock not DWORD [edx] + ret + +; int SST_Atomic_AddReturn(volatile int* x, int value) +_SST_Atomic_AddReturn: +_SST_Atomic_AddPtrReturn: + SST_Atomic_AddReturn: + SST_Atomic_AddPtrReturn: + mov edx, [esp+4] + mov eax, [esp+8] + lock xadd [edx], eax + add eax, [esp+8] + ret + +; int SST_Atomic_AndReturn(volatile int* x, int value) +_SST_Atomic_AndReturn: + SST_Atomic_AndReturn: + push ebx ;save ebx + + mov ecx, [esp+8] ;ecx = x + mov ebx, [esp+12] ;ebx = value + + mov edx, [ecx] ;edx = *x + mov eax, edx ;eax = edx = *x +try_again_1: + and edx, ebx ;edx = *x & value + + lock cmpxchg [ecx], edx ;if(eax == *x) *x = edx, else eax = *x + jz done_1 ;*x was modified. It's new value is in edx + mov edx, eax ;copy that new value to edx, lets try again + jmp try_again_1 +done_1: + xchg edx, eax ;edx has the value (*x & value), so swap edx and eax + pop ebx ;restore ebx + ret + +_SST_Atomic_OrReturn: + SST_Atomic_OrReturn: + push ebx ;save ebx + + mov ecx, [esp+8] ;ecx = x + mov ebx, [esp+12] ;ebx = value + + mov edx, [ecx] ;edx = *x + mov eax, edx ;eax = edx = *x +try_again_2: + or edx, ebx ;edx = *x | value + + lock cmpxchg [ecx], edx ;if(eax == *x) *x = edx, else eax = *x + jz done_2 ;*x was modified. It's new value is in edx + mov edx, eax ;copy that new value to edx, lets try again + jmp try_again_2 +done_2: + xchg edx, eax ;edx has the value (*x | value), so swap edx and eax + pop ebx ;restore ebx + ret + +_SST_Atomic_XorReturn: + SST_Atomic_XorReturn: + push ebx ;save ebx + + mov ecx, [esp+8] ;ecx = x + mov ebx, [esp+12] ;ebx = value + + mov edx, [ecx] ;edx = *x + mov eax, edx ;eax = edx = *x +try_again_3: + xor edx, ebx ;edx = *x ^ value + + lock cmpxchg [ecx], edx ;if(eax == *x) *x = edx, else eax = *x + jz done_3 ;*x was modified. It's new value is in edx + mov edx, eax ;copy that new value to edx, lets try again + jmp try_again_3 +done_3: + xchg edx, eax ;edx has the value (*x ^ value), so swap edx and eax + pop ebx ;restore ebx + ret + +; int SST_Atomic_NotReturn(volatile int* x) +; ============================================= +_SST_Atomic_NotReturn: + SST_Atomic_NotReturn: + mov ecx, [esp+4] ;ecx = x + + mov edx, [ecx] ;edx = *x + mov eax, edx ;eax = edx = *x +try_again_4: + not edx ;edx = ~(*x) + + lock cmpxchg [ecx], edx ;if(eax == *x) *x = edx, else eax = *x + jz done_4 ;*x was modified. It's new value is in edx + mov edx, eax ;copy that new value to edx, lets try again + jmp try_again_4 +done_4: + xchg edx, eax ;edx has the value (~*x), so swap edx and eax + ret + +;int SST_Atomic_Exchange(volatile int* x, int value) +;void* SST_Atomic_ExchangePtr(volatile void** x, void* value) +_SST_Atomic_Exchange: + SST_Atomic_Exchange: +_SST_Atomic_ExchangePtr: + SST_Atomic_ExchangePtr: + mov edx, [esp+4] + mov eax, [esp+8] + + lock xchg [edx], eax + ret + +;int SST_Atomic_ExchangeAdd(volatile int* x, int value); +;void* SST_Atomic_ExchangeAddPtr(volatile void** x, int value); +_SST_Atomic_ExchangeAdd: + SST_Atomic_ExchangeAdd: +_SST_Atomic_ExchangeAddPtr: + SST_Atomic_ExchangeAddPtr: + mov edx, [esp+4] + mov eax, [esp+8] + + lock xadd [edx],eax ;Save [edx] to temp, store [edx]+eax into [edx], save + ret + +;int SST_Atomic_CAS(int* dest, int compare, int newValue); +;void* SST_Atomic_CASPtr(void** dest, void* compare, void* newValue); +_SST_Atomic_CAS: + SST_Atomic_CAS: +_SST_Atomic_CASPtr: + SST_Atomic_CASPtr: + mov edx, [esp+4] ;edx <- dest + mov eax, [esp+8] ;eax <- compare + mov ecx, [esp+12] ;ecx <- newValue + + lock cmpxchg [edx], ecx ;compare [edx] with eax | swap with ecx if equal, else store [edx] into eax + ret + +; int SST_Atomic_LoadAcquire(const volatile int* src); +; void* SST_Atomic_LoadAcquirePtr(const volatile void** src); +; NOTE: x86 has strong memory ordering, thus no barrier is necessary, except for compiler barrier to reordering instructions +_SST_Atomic_LoadAcquire: + SST_Atomic_LoadAcquire: +_SST_Atomic_LoadAcquirePtr: + SST_Atomic_LoadAcquirePtr: + mov eax, [esp+4] ;eax = ptr + mov eax, [eax] ;eax = *ptr + ret + +; void SST_Atomic_StoreRelease(volatile int* dest, int value); +; void SST_Atomic_StoreReleasePtr(volatile void** dest, void* value); +; NOTE: x86 has strong memory ordering, thus no barrier is necessary, except for compiler barrier to reordering instructions +_SST_Atomic_StoreRelease: + SST_Atomic_StoreRelease: +_SST_Atomic_StoreReleasePtr: + SST_Atomic_StoreReleasePtr: + mov edx, [esp+4] ;edx = dest + mov eax, [esp+8] ;eax = value + mov [edx], eax + ret diff --git a/libsst-atomic/libsst-atomic.vcxproj b/libsst-atomic/libsst-atomic.vcxproj new file mode 100644 index 0000000..b1027dc --- /dev/null +++ b/libsst-atomic/libsst-atomic.vcxproj @@ -0,0 +1,151 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup Label="ProjectConfigurations"> + <ProjectConfiguration Include="Debug|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectGuid>{43ED481F-C4A3-40ED-81A3-46C43DC4EB1E}</ProjectGuid> + <RootNamespace>libsstatomic</RootNamespace> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> + <ConfigurationType>StaticLibrary</ConfigurationType> + <PlatformToolset>v110</PlatformToolset> + <CharacterSet>MultiByte</CharacterSet> + <WholeProgramOptimization>true</WholeProgramOptimization> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> + <ConfigurationType>StaticLibrary</ConfigurationType> + <PlatformToolset>v110</PlatformToolset> + <CharacterSet>MultiByte</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> + <ConfigurationType>StaticLibrary</ConfigurationType> + <PlatformToolset>v110</PlatformToolset> + <CharacterSet>MultiByte</CharacterSet> + <WholeProgramOptimization>false</WholeProgramOptimization> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> + <ConfigurationType>StaticLibrary</ConfigurationType> + <PlatformToolset>v110</PlatformToolset> + <CharacterSet>MultiByte</CharacterSet> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <ImportGroup Label="ExtensionSettings"> + <Import Project="$(VCTargetsPath)\BuildCustomizations\vsyasm.props" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <PropertyGroup Label="UserMacros" /> + <PropertyGroup> + <_ProjectFileVersion>11.0.50727.1</_ProjectFileVersion> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <OutDir>$(SolutionDir)\Lib\x86\</OutDir> + <IntDir>$(SolutionDir)Intermediate\$(Configuration)\$(Platform)\$(ProjectName)\</IntDir> + <TargetName>$(ProjectName)-debug</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <OutDir>$(SolutionDir)\Lib\x64\</OutDir> + <IntDir>$(SolutionDir)Intermediate\$(Configuration)\$(Platform)\$(ProjectName)\</IntDir> + <TargetName>$(ProjectName)-debug</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <OutDir>$(SolutionDir)\Lib\x86\</OutDir> + <IntDir>$(SolutionDir)Intermediate\$(Configuration)\$(Platform)\$(ProjectName)\</IntDir> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <OutDir>$(SolutionDir)\Lib\x64\</OutDir> + <IntDir>$(SolutionDir)Intermediate\$(Configuration)\$(Platform)\$(ProjectName)\</IntDir> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <Optimization>Disabled</Optimization> + <MinimalRebuild>true</MinimalRebuild> + <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> + <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> + <WarningLevel>Level3</WarningLevel> + <DebugInformationFormat>EditAndContinue</DebugInformationFormat> + </ClCompile> + <Lib /> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Midl> + <TargetEnvironment>X64</TargetEnvironment> + </Midl> + <ClCompile> + <Optimization>Disabled</Optimization> + <MinimalRebuild>true</MinimalRebuild> + <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> + <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> + <WarningLevel>Level3</WarningLevel> + <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> + </ClCompile> + <Lib /> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <Optimization>MaxSpeed</Optimization> + <IntrinsicFunctions>true</IntrinsicFunctions> + <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> + <FunctionLevelLinking>true</FunctionLevelLinking> + <WarningLevel>Level3</WarningLevel> + <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> + </ClCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Midl> + <TargetEnvironment>X64</TargetEnvironment> + </Midl> + <ClCompile> + <Optimization>MaxSpeed</Optimization> + <IntrinsicFunctions>true</IntrinsicFunctions> + <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> + <FunctionLevelLinking>true</FunctionLevelLinking> + <WarningLevel>Level3</WarningLevel> + <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> + </ClCompile> + </ItemDefinitionGroup> + <ItemGroup> + <YASM Include="SST_Atomic_x86-64-win64.asm"> + <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> + <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> + </YASM> + <YASM Include="SST_Atomic_x86.asm"> + <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild> + <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild> + </YASM> + </ItemGroup> + <ItemGroup> + <ClInclude Include="..\Lib\Include\SST\SST_Atomic.h" /> + </ItemGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> + <ImportGroup Label="ExtensionTargets"> + <Import Project="$(VCTargetsPath)\BuildCustomizations\vsyasm.targets" /> + </ImportGroup> +</Project> \ No newline at end of file diff --git a/libsst-atomic/libsst-atomic.vcxproj.filters b/libsst-atomic/libsst-atomic.vcxproj.filters new file mode 100644 index 0000000..9b13243 --- /dev/null +++ b/libsst-atomic/libsst-atomic.vcxproj.filters @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup> + <Filter Include="Source Files"> + <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier> + <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions> + </Filter> + <Filter Include="Header Files"> + <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier> + <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> + </Filter> + </ItemGroup> + <ItemGroup> + <YASM Include="SST_Atomic_x86-64-win64.asm"> + <Filter>Source Files</Filter> + </YASM> + <YASM Include="SST_Atomic_x86.asm"> + <Filter>Source Files</Filter> + </YASM> + </ItemGroup> + <ItemGroup> + <ClInclude Include="..\Lib\Include\SST\SST_Atomic.h"> + <Filter>Header Files</Filter> + </ClInclude> + </ItemGroup> +</Project> \ No newline at end of file diff --git a/libsst-atomic/obj/x86-64/release/SST_Atomic_x86-64.o b/libsst-atomic/obj/x86-64/release/SST_Atomic_x86-64.o new file mode 100644 index 0000000000000000000000000000000000000000..1a2c1cac670bb1b8c3bddef11f16dd8dc64b870f GIT binary patch literal 2864 zcmb<-^>JfjWMqH=Mg}_u1P><4!0>?+!FB*M9T->{7#Th=njik)0U{L54}ah^Km5Va z{P2hG;)gpweBeLG&iLW5N9TtR9{dN{Js3Y6?q=^ir1<Fr|3>i=md-=3zjR&z3vpr! z8Da{3zl5UkL%VtBhr=H{+RZ&cH2*;em;WG`53+uvIMniu;)lE04|{a8AMP|i?9pj{ zn1O*ouOzjigh8*kq^Kk@i9xTpG8aN;Kt(`)3=R&7cPz=z%}kE3urSj#Gto;d&SgLn zbxcV?;|7!zp@`(6DDX#-jL1jf`sJ6PXiZ58N-ZfZ%0m+jC@I1so`*%TKNf`%`B((~ z@=Gv{bgf9vNX$!5Me`$)Fq&UsGRW?QiJ>WVb__;V<?I-YrobmZF~u>tur#wM6<HyY zFq($olKi67pwyhy#9|a3$l@R^@o2G!#>Y^Sm%@Oo#J>oI3yMKxX;2g*^Bv)Fh$f1N zL=*{lEFz1-qY+sU5s%2Ch=@cMg+&4=CUJ<P`x~YO#kVj)bj6_9L^c;1oybB+5r<+V zk~q4l$T5ea2U!B736xW@Vo*88!tn7wR!IgHhH|VDEDYH=#8YsHN8k_-#3AmAL);FB zxDgg{W(F1vQE>(a1_3PMYEW@>9Tre=q@o>craM%e7tBKtp-^!_gb<ho3Kx*QqF^3^ zD2A$+L<oUd9Z+#4Fb_d2fQsuOgutw=P;o~v4?&!SiiaSCz^r>v@pLc`L41aagX~9$ zGB9v4Lc*;dS&)H&K?N#ag(hwR6>mTj_lJtlKogIHiqA(AFMx`#Kof6=imyf!UkDXn zk0!noD!vI#{0dYYO_<>cR2)4$e20porw4W>Ncf<q2QjEPdU{ZUile6oGpIOvdhmgY zqo;>ds5p9hsD_H8r-unparE@C3@VPE9`-=R(bK~fs5p9hcn=jvPY*22knllI4>C}3 z^z@(u6-Q4G_E2&3^bigeM^6t$P;vD1&<zzwPY>wnfE+%kjA6#2@ds2)5lZ8t*cliY zu<4fp71j(449l@eA{oZdz`($S#D_7DKoheDD?|jOhMR$bfdj&2kbu%4Ye1L{%7;;q RHZ23gHkbgE7J$+)3IO~|@F@TQ literal 0 HcmV?d00001 diff --git a/libsst-concurrency/Makefile b/libsst-concurrency/Makefile new file mode 100644 index 0000000..7e637c9 --- /dev/null +++ b/libsst-concurrency/Makefile @@ -0,0 +1,42 @@ +# libsst-concurrency/Source/Makefile +# Author: Patrick Baggett <ptbaggett@762studios.com> +# Created: 12/23/2011 +# +# Purpose: +# +# Makefile for libsst-concurrency +# +# License: +# +# This program is free software. It comes without any warranty, to +# the extent permitted by applicable law. You can redistribute it +# and/or modify it under the terms of the Do What The Fuck You Want +# To Public License, Version 2, as published by Sam Hocevar. See +# http://sam.zoy.org/wtfpl/COPYING for more details. + +BINNAME := $(DIST)/libsst-concurrency.a +ifeq ($(TARGET),debug) + BINNAME := $(subst .a,_d.a, $(BINNAME)) +endif + +include sources-$(SUBSYSTEM).mk +include sources-common.mk + +OBJ := $(addprefix obj/$(ARCH)/$(TARGET)/,$(subst .c,.o,$(SRC)) ) + +$(shell mkdir -p obj/$(ARCH)/$(TARGET)) + +$(BINNAME): $(OBJ) + $(AR) cru $@ $+ + $(RANLIB) $@ + +# CLEAN +clean: + @-rm -r -f obj $(DIST)/libsst-concurrency*.a + +# *.c files to *.o files +obj/$(ARCH)/$(TARGET)/%.o: %.c + @echo CC $@ + @$(CC) $(CFLAGS) -c $*.c -o obj/$(ARCH)/$(TARGET)/$*.o + + diff --git a/libsst-concurrency/SST_Event_POSIX.c b/libsst-concurrency/SST_Event_POSIX.c new file mode 100644 index 0000000..9885842 --- /dev/null +++ b/libsst-concurrency/SST_Event_POSIX.c @@ -0,0 +1,138 @@ +/* + SST_Event_POSIX.c + Author: Patrick Baggett <ptbaggett@762studios.com> + Created: 12/20/2011 + + Purpose: + + libsst-concurrency event functions for POSIX platforms + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ +#include <SST/SST_Event.h> /* Functions being implemented */ +#include <SST/SST_Concurrency.h> /* SST_WAIT_INFINITE constant */ +#include <pthread.h> /* POSIX concurrency */ +#include <time.h> /* clock_gettime() */ +#include <stdlib.h> /* malloc()/free() */ +#include "timespecadd.h" /* inline function to add timespec*/ + +#ifdef __APPLE__ +#include <sys/time.h> +#endif +/******************************************************************************/ + +typedef struct UnixEvent +{ + pthread_mutex_t lock; + pthread_cond_t cond; + volatile int signaled; +} UnixEvent; + +/******************************************************************************/ + +SST_Event SST_Concurrency_CreateEvent(void) +{ + UnixEvent* ev = (UnixEvent*)malloc(sizeof(UnixEvent)); + + pthread_mutex_init(&ev->lock, NULL); + pthread_cond_init(&ev->cond, NULL); + ev->signaled = 0; + + return (SST_Event)ev; +} + +/******************************************************************************/ + +void SST_Concurrency_DestroyEvent(SST_Event _event) +{ + UnixEvent* ev = (UnixEvent*)_event; + + pthread_mutex_destroy(&ev->lock); + pthread_cond_destroy(&ev->cond); + free(ev); +} + +/******************************************************************************/ + +void SST_Concurrency_SignalEvent(SST_Event _event) +{ + UnixEvent* ev = (UnixEvent*)_event; + + pthread_mutex_lock(&ev->lock); + + ev->signaled = 1; + + pthread_cond_broadcast(&ev->cond); + pthread_mutex_unlock(&ev->lock); +} + +/******************************************************************************/ + +void SST_Concurrency_ResetEvent(SST_Event _event) +{ + UnixEvent* ev = (UnixEvent*)_event; + + /* TODO: Optimization opportunity here: These locks aren't needed except to serialize set/reset calls. However, + if we can leave the behavior 'undefined' for concurrent set/reset, then all that is needed is a set + membar. */ + pthread_mutex_lock(&ev->lock); + ev->signaled = 0; + pthread_mutex_unlock(&ev->lock); +} + +/******************************************************************************/ + +int SST_Concurrency_WaitEvent(SST_Event _event, uint32_t _ticks) +{ + int result = 0; + UnixEvent* ev = (UnixEvent*)_event; + + pthread_mutex_lock(&ev->lock); + + /* Infinite wait */ + if(_ticks == SST_WAIT_INFINITE) + { + while(ev->signaled == 0) + pthread_cond_wait(&ev->cond, &ev->lock); + + result = 1; + } + else /* Maximum wait measured in milliseconds */ + { + struct timespec ts, tswait; + int retval = 0; + +#ifdef __APPLE__ + /* Less precise, but getting nanosecond precision out of mach was proving exceedingly painful.*/ + struct timeval tv; + struct timezone tz; + tz.tz_minuteswest = 0; tz.tz_dsttime = 0; + gettimeofday(&tv, &tz); + ts.tv_sec = tv.tv_sec; + ts.tv_nsec = tv.tv_usec * 1000; +#else + clock_gettime(CLOCK_REALTIME, &ts); +#endif + tswait.tv_sec = (_ticks / 1000); /* add whole seconds */ + tswait.tv_nsec = (_ticks % 1000) * 1000 * 1000; /* add remaining milliseconds (converted to nanosecs by factor of 10^6) */ + + _sst_add_timespec(&ts, &tswait); + + /* timedwait() returns 0 on success, and non-zero on failure. Spurious wakeups return 0 (success) + while timeouts don't. A spurious wakeup won't have ev->signaled though, so it will go back to waiting */ + while(retval == 0 && ev->signaled == 0) + retval = pthread_cond_timedwait(&ev->cond, &ev->lock, &ts); + + /* If this returned success, then the condition is met AND the timeout did not expire -> success */ + result = (retval == 0); + } + + pthread_mutex_unlock(&ev->lock); + return result; +} diff --git a/libsst-concurrency/SST_Event_Solaris.c b/libsst-concurrency/SST_Event_Solaris.c new file mode 100644 index 0000000..f566f75 --- /dev/null +++ b/libsst-concurrency/SST_Event_Solaris.c @@ -0,0 +1,125 @@ +/* + SST_Event_Solaris.c + Author: Patrick Baggett <ptbaggett@762studios.com> + Created: 4/11/2012 + + Purpose: + + libsst-concurrency event functions using native Solaris primitives + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ +#include <SST/SST_Event.h> /* Functions being implemented */ +#include <SST/SST_Concurrency.h> /* SST_WAIT_INFINITE constant */ +#include <thread.h> /* POSIX concurrency */ +#include <time.h> /* clock_gettime() */ +#include <stdlib.h> /* malloc()/free() */ +#include "timespecadd.h" /* inline function to add timespec*/ +#include <atomic.h> /* membar_producer() */ + +/******************************************************************************/ + +typedef struct SolarisEvent +{ + mutex_t lock; + cond_t cond; + volatile int signaled; +} SolarisEvent; + +/******************************************************************************/ + +SST_Event SST_Concurrency_CreateEvent(void) +{ + SolarisEvent* ev = (SolarisEvent*)malloc(sizeof(SolarisEvent)); + + mutex_init(&ev->lock, USYNC_THREAD, NULL); + cond_init(&ev->cond, USYNC_THREAD, NULL); + ev->signaled = 0; + + return (SST_Event)ev; +} + +/******************************************************************************/ + +void SST_Concurrency_DestroyEvent(SST_Event _event) +{ + SolarisEvent* ev = (SolarisEvent*)_event; + + mutex_destroy(&ev->lock); + cond_destroy(&ev->cond); + free(ev); +} + +/******************************************************************************/ + +void SST_Concurrency_SignalEvent(SST_Event _event) +{ + SolarisEvent* ev = (SolarisEvent*)_event; + + mutex_lock(&ev->lock); + + ev->signaled = 1; + + cond_broadcast(&ev->cond); + mutex_unlock(&ev->lock); +} + +/******************************************************************************/ + +void SST_Concurrency_ResetEvent(SST_Event _event) +{ + SolarisEvent* ev = (SolarisEvent*)_event; + + + ev->signaled = 0; + membar_producer(); /* all stores reach global visibility before new stores */ +} + +/******************************************************************************/ + +int SST_Concurrency_WaitEvent(SST_Event _event, uint32_t _ticks) +{ + int result = 0; + SolarisEvent* ev = (SolarisEvent*)_event; + + mutex_lock(&ev->lock); + + /* Infinite wait */ + if(_ticks == SST_WAIT_INFINITE) + { + while(ev->signaled == 0) + cond_wait(&ev->cond, &ev->lock); + + result = 1; + } + else /* Maximum wait measured in milliseconds */ + { + struct timespec ts, tswait; + int retval = 0; + + clock_gettime(CLOCK_REALTIME, &ts); + + tswait.tv_sec = (_ticks / 1000); /* add whole seconds */ + tswait.tv_nsec = (_ticks % 1000) * 1000 * 1000; /* add remaining milliseconds (converted to nanosecs by factor of 10^6) */ + + _sst_add_timespec(&ts, &tswait); + + /* timedwait() returns 0 on success, and non-zero on failure. Spurious wakeups return 0 (success) + while timeouts don't. A spurious wakeup won't have ev->signaled though, so it will go back to waiting */ + while(retval == 0 && ev->signaled == 0) + retval = cond_timedwait(&ev->cond, &ev->lock, &ts); + + /* If this returned success, then the condition is met AND the timeout did not expire -> success */ + result = (retval == 0); + } + + mutex_unlock(&ev->lock); + return result; +} diff --git a/libsst-concurrency/SST_Event_Win32.c b/libsst-concurrency/SST_Event_Win32.c new file mode 100644 index 0000000..6829829 --- /dev/null +++ b/libsst-concurrency/SST_Event_Win32.c @@ -0,0 +1,74 @@ +/* + SST_Event_Win32.c + Author: Patrick Baggett <ptbaggett@762studios.com> + Created: 12/20/2011 + + Purpose: + + libsst-concurrency event functions for Win32 platforms (Windows 7 or later) + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ + +#include <SST/SST_Concurrency.h> /* SST_WAIT_INFINITE */ + +#define _WIN32_WINNT 0x0601 /* Windows 7 or later */ +#include <windows.h> + +/*************************************************************************/ + +SST_Event SST_Concurrency_CreateEvent(void) +{ + HANDLE hEvent = CreateEventA(NULL, TRUE, FALSE, NULL); + + return (SST_Event)hEvent; +} + +/*************************************************************************/ + +void SST_Concurrency_DestroyEvent(SST_Event _event) +{ + HANDLE hEvent = (HANDLE)_event; + + CloseHandle(hEvent); +} + +/*************************************************************************/ + +void SST_Concurrency_SignalEvent(SST_Event _event) +{ + HANDLE hEvent = (HANDLE)_event; + + SetEvent(hEvent); +} + +/*************************************************************************/ + +void SST_Concurrency_ResetEvent(SST_Event _event) +{ + HANDLE hEvent = (HANDLE)_event; + + ResetEvent(hEvent); +} + +/*************************************************************************/ + +int SST_Concurrency_WaitEvent(SST_Event _event, uint32_t _ticks) +{ + HANDLE hEvent = (HANDLE)_event; + DWORD dwTime; + + if(_ticks == SST_WAIT_INFINITE) + dwTime = INFINITE; + else + dwTime = (DWORD)_ticks; + + return (WaitForSingleObject(hEvent, dwTime) == WAIT_OBJECT_0); +} diff --git a/libsst-concurrency/SST_Mutex_POSIX.c b/libsst-concurrency/SST_Mutex_POSIX.c new file mode 100644 index 0000000..3fe3194 --- /dev/null +++ b/libsst-concurrency/SST_Mutex_POSIX.c @@ -0,0 +1,70 @@ +/* + SST_Mutex_POSIX.c + Author: Patrick Baggett <ptbaggett@762studios.com> + Created: 12/20/2011 + + Purpose: + + libsst-concurrency mutex functions for POSIX platforms + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ + +#include <SST/SST_Mutex.h> +#include <pthread.h> +#include <stdlib.h> + +/******************************************************************************/ + +SST_Mutex SST_Concurrency_CreateMutex(void) +{ + pthread_mutex_t* mutex = (pthread_mutex_t*)malloc(sizeof(pthread_mutex_t)); + + pthread_mutex_init(mutex, NULL); + return (SST_Mutex)mutex; +} + +/******************************************************************************/ + +void SST_Concurrency_DestroyMutex(SST_Mutex _mutex) +{ + pthread_mutex_t* mutex = (pthread_mutex_t*)_mutex; + + pthread_mutex_destroy(mutex); + free(mutex); +} + +/******************************************************************************/ + +void SST_Concurrency_LockMutex(SST_Mutex _mutex) +{ + pthread_mutex_t* mutex = (pthread_mutex_t*)_mutex; + pthread_mutex_lock(mutex); +} + +/******************************************************************************/ + +int SST_Concurrency_TryLockMutex(SST_Mutex _mutex) +{ + pthread_mutex_t* mutex = (pthread_mutex_t*)_mutex; + return (pthread_mutex_trylock(mutex) == 0); +} + +/******************************************************************************/ + +void SST_Concurrency_UnlockMutex(SST_Mutex _mutex) +{ + pthread_mutex_t* mutex = (pthread_mutex_t*)_mutex; + pthread_mutex_unlock(mutex); +} + + + + diff --git a/libsst-concurrency/SST_Mutex_Solaris.c b/libsst-concurrency/SST_Mutex_Solaris.c new file mode 100644 index 0000000..c9a1d38 --- /dev/null +++ b/libsst-concurrency/SST_Mutex_Solaris.c @@ -0,0 +1,68 @@ +/* + SST_Mutex_Solaris.c + Author: Patrick Baggett <ptbaggett@762studios.com> + Created: 4/11/2012 + + Purpose: + + libsst-concurrency mutex functions using native Solaris mutexes + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ + +#include <SST/SST_Mutex.h> +#include <synch.h> +#include <stdlib.h> + +/******************************************************************************/ + +SST_Mutex SST_Concurrency_CreateMutex(void) +{ + mutex_t* mutex = (mutex_t*)malloc(sizeof(mutex_t)); + + mutex_init(mutex, USYNC_THREAD, NULL); + return (SST_Mutex)mutex; +} + +/******************************************************************************/ + +void SST_Concurrency_DestroyMutex(SST_Mutex _mutex) +{ + mutex_t* mutex = (mutex_t*)_mutex; + + mutex_destroy(mutex); + free(mutex); +} + +/******************************************************************************/ + +void SST_Concurrency_LockMutex(SST_Mutex _mutex) +{ + mutex_t* mutex = (mutex_t*)_mutex; + mutex_lock(mutex); +} + +/******************************************************************************/ + +int SST_Concurrency_TryLockMutex(SST_Mutex _mutex) +{ + mutex_t* mutex = (mutex_t*)_mutex; + return (mutex_trylock(mutex) == 0); +} + +/******************************************************************************/ + +void SST_Concurrency_UnlockMutex(SST_Mutex _mutex) +{ + mutex_t* mutex = (mutex_t*)_mutex; + mutex_unlock(mutex); +} + + diff --git a/libsst-concurrency/SST_Mutex_Win32.c b/libsst-concurrency/SST_Mutex_Win32.c new file mode 100644 index 0000000..ab36d54 --- /dev/null +++ b/libsst-concurrency/SST_Mutex_Win32.c @@ -0,0 +1,77 @@ +/* + SST_Mutex_Win32.c + Author: Patrick Baggett <ptbaggett@762studios.com> + Created: 12/20/2011 + + Purpose: + + libsst-concurrency mutex functions for Win32 platforms (Windows 7 or later) + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ + +#include <SST/SST_Mutex.h> + +#define _WIN32_WINNT 0x0601 /* Windows 7 or later */ +#include <windows.h> + +#define SST_DEFAULT_SPINCOUNT 5500 + +/*************************************************************************/ + +SST_Mutex SST_Concurrency_CreateMutex(void) +{ + CRITICAL_SECTION* cs = HeapAlloc(GetProcessHeap(), 0, sizeof(CRITICAL_SECTION)); + + /* No memory? */ + if(!cs) + return NULL; + + InitializeCriticalSectionAndSpinCount(cs, SST_DEFAULT_SPINCOUNT); + + return (SST_Mutex)cs; +} + +/*************************************************************************/ + +void SST_Concurrency_DestroyMutex(SST_Mutex _mutex) +{ + CRITICAL_SECTION* cs = (CRITICAL_SECTION*)_mutex; + + DeleteCriticalSection(cs); + HeapFree(GetProcessHeap(), 0, cs); +} + +/*************************************************************************/ + +void SST_Concurrency_LockMutex(SST_Mutex _mutex) +{ + CRITICAL_SECTION* cs = (CRITICAL_SECTION*)_mutex; + + EnterCriticalSection(cs); +} + +/*************************************************************************/ + +int SST_Concurrency_TryLockMutex(SST_Mutex _mutex) +{ + CRITICAL_SECTION* cs = (CRITICAL_SECTION*)_mutex; + + return (int)TryEnterCriticalSection(cs); +} + +/*************************************************************************/ + +void SST_Concurrency_UnlockMutex(SST_Mutex _mutex) +{ + CRITICAL_SECTION* cs = (CRITICAL_SECTION*)_mutex; + LeaveCriticalSection(cs); +} + diff --git a/libsst-concurrency/SST_Once.c b/libsst-concurrency/SST_Once.c new file mode 100644 index 0000000..42a0eb8 --- /dev/null +++ b/libsst-concurrency/SST_Once.c @@ -0,0 +1,89 @@ +/* + SST_Once.c + Author: Patrick Baggett <ptbaggett@762studios.com> + Created: 12/20/2011 + + Purpose: + + libsst-concurrency "once" functions. This requires libsst-atomic. + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ + +#include <SST/SST_Once.h> +#include <SST/SST_Atomic.h> +#include <SST/SST_Concurrency.h> +#include <SST/SST_MemBarrier.h> + +#define SST_ONCE_INPROGRESS_BIT 0x80000000 /* Highest bit */ +#define SST_ONCE_DONE_BIT 0x00000001 /* Lowest bit */ + +#define SST_ONCE_DONE 0xd1d d0 +#ifdef _DEBUG +#include <stdlib.h> +#endif + +static void wait_done(volatile int* vonce) +{ + /* Spin carefully */ + while((*vonce & SST_ONCE_DONE_BIT) == 0) + { + SST_Concurrency_YieldThread(); + SST_Concurrency_Spin(); + } +} + +void SST_Concurrency_ExecOnce(SST_Once* once, SST_OnceFunc once_func, void* arg) +{ + int state; + volatile int* vonce = (volatile int*)once; + + /* Take a snapshot of the current state */ + state = *vonce; + + + /* Already done? */ + if((state & SST_ONCE_DONE_BIT) != 0) + return; + + /* In progress? */ + if((state & SST_ONCE_INPROGRESS_BIT) != 0) + { + wait_done(vonce); + return; + } + + /* Not done, not yet started -> attempt to set SST_ONCE_INPROGRESS bit. */ + if(SST_Atomic_CAS(vonce, SST_ONCE_INIT, SST_ONCE_INIT | SST_ONCE_INPROGRESS_BIT) == SST_ONCE_INIT) + { + /* Success: call user's once function */ + once_func(arg); + + /* Done, so set that we are done */ + SST_Atomic_Or(vonce, SST_ONCE_DONE_BIT); + } + else /* Already started or done, so just chill */ + wait_done(vonce); + +} + +/*************************************************************************/ + +void SST_Concurrency_InitOnceHandle(SST_Once* once) +{ + *once = SST_ONCE_INIT; + + /* This is the only tricky part -- a memory barrier. An atomic + operation could be used, but honestly, that's overkill for just + ensuring an atomic write. */ + SST_Concurrency_MemoryBarrier(); +} + + diff --git a/libsst-concurrency/SST_ReadWriteLock.c b/libsst-concurrency/SST_ReadWriteLock.c new file mode 100644 index 0000000..d9943c4 --- /dev/null +++ b/libsst-concurrency/SST_ReadWriteLock.c @@ -0,0 +1,162 @@ +/* + SST_ReadWriteLock.c + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. +*/ +#ifndef __APPLE_CC__ +#include <malloc.h> +#else +#include <stdlib.h> +#endif + +#include <SST/SST_Build.h> +#include <SST/SST_Concurrency.h> + +/* Leading (negative) bit is used to signal write lock */ +#define SST_RWL_WRITE_BIT (0x80000000u) + +/* ReadWriteLock implementation structure */ +typedef struct SST_ReadWriteLockImpl { + volatile uint32_t state; /* state flag in the form 0xWRRRRRRR, i.e., write flag and then number of readers */ +} SST_ReadWriteLockImpl; + +/*************************************************************************/ + +extern SST_ReadWriteLock SST_Concurrency_CreateReadWriteLock( void ) +{ + SST_ReadWriteLockImpl *lock_impl = (SST_ReadWriteLockImpl*)malloc(sizeof(SST_ReadWriteLockImpl)); + + /* Check for allocation failure */ + if (lock_impl == NULL) + return NULL; + + /* Initialize the impl */ + lock_impl->state = 0; + + /* Make sure that goes out to memory */ + SST_Concurrency_MemoryBarrier(); + + return lock_impl; +} + +/*************************************************************************/ + +extern void SST_Concurrency_DestroyReadWriteLock( SST_ReadWriteLock lock ) +{ + SST_ReadWriteLockImpl* lock_impl; + + if (lock == NULL) + return; + + lock_impl = (SST_ReadWriteLockImpl*)lock; + + free(lock_impl); +} + +/*************************************************************************/ + +extern int SST_Concurrency_LockForReading( SST_ReadWriteLock lock, uint32_t ticks ) +{ + uint64_t startTicks, currentTicks; + SST_ReadWriteLockImpl* lock_impl; + + if (lock == NULL) + return 0; + + startTicks = (uint32_t)SST_Concurrency_GetTicks(); + + lock_impl = (SST_ReadWriteLockImpl*)lock; + + /* Spin (and yield) until we are not writing */ + while (lock_impl->state & SST_RWL_WRITE_BIT) + { + if (ticks != SST_WAIT_INFINITE) + { + currentTicks = SST_Concurrency_GetTicks(); + + if ((uint32_t)(currentTicks - startTicks) > ticks) + return 0; + } + + SST_Concurrency_YieldThread(); + } + + /* Increment the reader count by incrementing the state variable */ + SST_Atomic_Inc(&lock_impl->state); + + return 1; +} + +/*************************************************************************/ + +extern int SST_Concurrency_LockForWriting( SST_ReadWriteLock lock, uint32_t ticks ) +{ + uint64_t startTicks, currentTicks; + SST_ReadWriteLockImpl* lock_impl; + + if (lock == NULL) + return 0; + + startTicks = SST_Concurrency_GetTicks(); + + lock_impl = (SST_ReadWriteLockImpl*)lock; + + /* If we are already locked for writing, return */ + if (lock_impl->state & SST_RWL_WRITE_BIT) + return 0; + + /* Set the write flag */ + SST_Atomic_Or((volatile int*)&lock_impl->state, SST_RWL_WRITE_BIT); + + /* Spin (and yield) until we have no more readers */ + while (lock_impl->state & ~SST_RWL_WRITE_BIT) + { + if (ticks != SST_WAIT_INFINITE) + { + currentTicks = SST_Concurrency_GetTicks(); + + if ((uint32_t)(currentTicks - startTicks) > ticks) + return 0; + } + + SST_Concurrency_YieldThread(); + } + + return 1; +} + +/*************************************************************************/ + +extern void SST_Concurrency_EndReading( SST_ReadWriteLock lock ) +{ + SST_ReadWriteLockImpl* lock_impl; + + if (lock == NULL) + return; + + lock_impl = (SST_ReadWriteLockImpl*)lock; + + /* Decrement the readers counter */ + SST_Atomic_Dec(&lock_impl->state); +} + +/*************************************************************************/ + +extern void SST_Concurrency_EndWriting( SST_ReadWriteLock lock ) +{ + SST_ReadWriteLockImpl* lock_impl; + + if (lock == NULL) + return; + + lock_impl = (SST_ReadWriteLockImpl*)lock; + + /* Signal that we are free to read */ + SST_Atomic_And((volatile int*)&lock_impl->state, ~SST_RWL_WRITE_BIT); +} diff --git a/libsst-concurrency/SST_Semaphore_MacOSX.c b/libsst-concurrency/SST_Semaphore_MacOSX.c new file mode 100644 index 0000000..340357b --- /dev/null +++ b/libsst-concurrency/SST_Semaphore_MacOSX.c @@ -0,0 +1,164 @@ +/* + SST_Semaphore_MacOSX.c + Author: Patrick Baggett <ptbaggett@762studios.com> + Created: 11/27/2012 + + Purpose: + + libsst-concurrency semaphore functions for MacOS X platform + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ + +/* + MacOS X doesn't implement named POSIX semaphores, nor does it have + a timed wait, making it utterly useless for any practical purposes. + This implementation uses pthread condition variables/mutexes to implement + a semaphore. It may end up replacing the POSIX semaphores implementation + on other platforms if their implementation is crap, too. +*/ + +#include <SST/SST_Concurrency.h> +#include <pthread.h> /* POSIX threads stuff */ +#include <sys/time.h> /* gettimeofday() */ +#include <stdlib.h> /* malloc()/free() */ +#include <errno.h> /* ETIMEDOUT */ +#include "timespecadd.h" + +/* Semaphore implementation */ +typedef struct SST_Semaphore_MacOSX +{ + pthread_mutex_t mutex; + pthread_cond_t cond; + volatile uint32_t semaCount; /* Semaphore's value */ + volatile uint32_t waiters; /* Number of waiters */ +} SST_Semaphore_MacOSX; + + +/******************************************************************************/ + +SST_Semaphore SST_Concurrency_CreateSemaphore(uint32_t _initialCount) +{ + SST_Semaphore_MacOSX* sema = malloc(sizeof(SST_Semaphore_MacOSX)); + + if(sema != NULL) + { + pthread_mutex_init(&sema->mutex, NULL); + pthread_cond_init(&sema->cond, NULL); + sema->semaCount = _initialCount; + sema->waiters = 0; + } + + return (SST_Semaphore)sema; +} + +/******************************************************************************/ + +void SST_Concurrency_DestroySemaphore(SST_Semaphore _sema) +{ + SST_Semaphore_MacOSX* sema = (SST_Semaphore_MacOSX*)_sema; + + pthread_mutex_destroy(&sema->mutex); + pthread_cond_destroy(&sema->cond); + free(sema); +} + +/******************************************************************************/ + +void SST_Concurrency_PostSemaphore(SST_Semaphore _sema, uint32_t _count) +{ + SST_Semaphore_MacOSX* sema = (SST_Semaphore_MacOSX*)_sema; + + pthread_mutex_lock(&sema->mutex); + + if(sema->waiters > 0) + { + if(_count <= 1) /* Typically wake one */ + pthread_cond_signal(&sema->cond); + else /* But if > 1, use broadcast */ + pthread_cond_broadcast(&sema->cond); + } + + /* Post the count to the semaphore */ + sema->semaCount += _count; + + + /* After this unlock, threads are scheduled again */ + pthread_mutex_unlock(&sema->mutex); +} + +/******************************************************************************/ + +int SST_Concurrency_WaitSemaphore(SST_Semaphore _sema, uint32_t _ticks) +{ + int result = 0; + SST_Semaphore_MacOSX* sema = (SST_Semaphore_MacOSX*)_sema; + + /* Infinite wait */ + if(_ticks == SST_WAIT_INFINITE) + { + pthread_mutex_lock(&sema->mutex); + sema->waiters++; + + while(sema->semaCount == 0) + { + pthread_cond_wait(&sema->cond, &sema->mutex); + } + + /* Drop count by 1 (we still hold lock) */ + sema->semaCount--; + sema->waiters--; + result = 1; + } + else /* Maximum wait measured in milliseconds */ + { + struct timespec ts, tswait; + struct timeval tv; + int timeout = 0; + + /* Get absolute time in the future */ + gettimeofday(&tv, NULL); + ts.tv_sec = tv.tv_sec; + ts.tv_nsec = tv.tv_usec * 1000; + tswait.tv_sec = (_ticks / 1000); + tswait.tv_nsec = (_ticks % 1000) * 1000 * 1000; + + _sst_add_timespec(&ts, &tswait); + + /* We do the locking now just in case locking takes a significant + amount of time */ + pthread_mutex_lock(&sema->mutex); + + /* Wait for the condition to be signaled or a timeout */ + while(sema->semaCount == 0) + { + /* This is one the few POSIX functions that doesn't use errno */ + int err = pthread_cond_timedwait(&sema->cond, &sema->mutex, &ts); + + if(err == ETIMEDOUT) + { + timeout = 1; + break; + } + } + + /* Only decrease count if we didn't time out on the wait */ + if(!timeout) + { + sema->semaCount--; + sema->waiters--; + result = 1; + } + + } + + pthread_mutex_unlock(&sema->mutex); + return result; +} diff --git a/libsst-concurrency/SST_Semaphore_POSIX.c b/libsst-concurrency/SST_Semaphore_POSIX.c new file mode 100644 index 0000000..def389b --- /dev/null +++ b/libsst-concurrency/SST_Semaphore_POSIX.c @@ -0,0 +1,126 @@ +/* + SST_Semaphore_POSIX.c + Author: Patrick Baggett <ptbaggett@762studios.com> + Created: 12/20/2011 + + Purpose: + + libsst-concurrency semaphore functions for POSIX platforms + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ + +#include <SST/SST_Concurrency.h> +#include <SST/SST_Semaphore.h> +#include <semaphore.h> /* POSIX semaphores */ +#include <time.h> +#include <stdlib.h> /* malloc()/free() */ +#include <errno.h> /* errno */ +#include "timespecadd.h" + +/******************************************************************************/ + +SST_Semaphore SST_Concurrency_CreateSemaphore(uint32_t _initialCount) +{ + sem_t* sema; + + sema = (sem_t*)malloc(sizeof(sem_t)); + if(sema) + { + sem_init(sema, 0, (unsigned int)_initialCount); + } + + return (SST_Semaphore)sema; +} + +/******************************************************************************/ + +void SST_Concurrency_DestroySemaphore(SST_Semaphore _sema) +{ + sem_t* sema = (sem_t*)_sema; + sem_destroy(sema); + free(sema); +} + +/******************************************************************************/ + +void SST_Concurrency_PostSemaphore(SST_Semaphore _sema, uint32_t _count) +{ + sem_t* sema = (sem_t*)_sema; + while(_count) + { + /* The Open Group doesn't define a sem_post() that allows + larger than incrementing by 1, so loop. */ + sem_post(sema); + _count--; + } +} + +/******************************************************************************/ + +int SST_Concurrency_WaitSemaphore(SST_Semaphore _sema, uint32_t _ticks) +{ + int result = 0; + sem_t* sema = (sem_t*)_sema; + int ok; + + /* Infinite wait */ + if(_ticks == SST_WAIT_INFINITE) + { + /* Wait in a loop until we get a value OTHER than EINTR, + or the function succeeds. + Basically, EINTR means a signal interrupted this function, + so we can retry the wait */ + do + { + ok = sem_wait(sema); + if(ok == 0) + break; + + } while(errno == EINTR); + + /* sem_wait() returns 0 on success, so see if successful */ + result = (ok == 0); + } + else /* Maximum wait measured in milliseconds */ + { + struct timespec ts, tswait; + + clock_gettime(CLOCK_REALTIME, &ts); + tswait.tv_sec = (_ticks / 1000); + tswait.tv_nsec = (_ticks % 1000) * 1000 * 1000; + + _sst_add_timespec(&ts, &tswait); + + /* EINTER = signal interrupted the function. Loop until we get + something other than a signal interruption */ + do + { + ok = sem_timedwait(sema, &ts); + if(ok == 0) + break; + } while(errno == EINTR); + + /* Either success or timeout, trap legitimate errors (which + are due to invalid conditions -> bug) */ + if(ok < 0 && errno != ETIMEDOUT) + { + result = 0; + } + else + { + /* If this returned success, then save that result + as TRUE */ + result = (ok == 0); + } + } + + return result; +} diff --git a/libsst-concurrency/SST_Semaphore_Solaris.c b/libsst-concurrency/SST_Semaphore_Solaris.c new file mode 100644 index 0000000..2a2b22c --- /dev/null +++ b/libsst-concurrency/SST_Semaphore_Solaris.c @@ -0,0 +1,127 @@ +/* + SST_Semaphore_Solaris.c + Author: Patrick Baggett <ptbaggett@762studios.com> + Created: 4/11/2012 + + Purpose: + + libsst-concurrency semaphore functions using native Solaris semaphores + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ + +#include <SST/SST_Concurrency.h> +#include <SST/SST_Semaphore.h> +#include <synch.h> /* native Solaris semaphores */ +#include <time.h> +#include <stdlib.h> /* malloc()/free() */ +#include <errno.h> /* errno */ +#include "timespecadd.h" /* add struct timespec */ + +/******************************************************************************/ + +SST_Semaphore SST_Concurrency_CreateSemaphore(uint32_t _initialCount) +{ + + sema_t* sema = (sema_t*)malloc(sizeof(sema_t)); + + if(sema) + { + if(sema_init(sema, (unsigned int)_initialCount, USYNC_THREAD, NULL) == 0) + return (SST_Semaphore)sema; + } + + return NULL; +} + +/******************************************************************************/ + +void SST_Concurrency_DestroySemaphore(SST_Semaphore _sema) +{ + sema_t* sema = (sema_t*)_sema; + sema_destroy(sema); + free(sema); +} + +/******************************************************************************/ + +void SST_Concurrency_PostSemaphore(SST_Semaphore _sema, uint32_t _count) +{ + sema_t* sema = (sema_t*)_sema; + while(_count) + { + /* sema_post() only allows 1 increment, so loop */ + sema_post(sema); + _count--; + } +} + +/******************************************************************************/ + +int SST_Concurrency_WaitSemaphore(SST_Semaphore _sema, uint32_t _ticks) +{ + int result = 0; + sema_t* sema = (sema_t*)_sema; + int ok; + + if(_ticks == SST_WAIT_INFINITE) + { + /* Wait in a loop until we get a value OTHER than EINTR, + or the function succeeds. + Basically, EINTR means a signal interrupted this function, + so we can retry the wait */ + do + { + ok = sema_wait(sema); + if(ok == 0) + break; + + } while(errno == EINTR); + + /* sema_wait() returns 0 on success, so see if successful */ + result = (ok == 0); + } + else /* Maximum wait measured in milliseconds */ + { + struct timespec ts, tswait; + + /* get absolute time in the future */ + clock_gettime(CLOCK_REALTIME, &ts); + tswait.tv_sec = (_ticks / 1000); + tswait.tv_nsec = (_ticks % 1000) * 1000 * 1000; + + _sst_add_timespec(&ts, &tswait); + /* EINTR = signal interrupted the function. Loop until we get + something other than a signal interruption */ + do + { + ok = sema_timedwait(sema, &ts); + if(ok == 0) + break; + } while(errno == EINTR); + + /* Either success or timeout, trap legitimate errors (which + are due to invalid conditions -> bug) */ + if(ok < 0 && errno != ETIMEDOUT) + { + result = 0; + } + else + { + /* If this returned success, then save that result + as TRUE */ + result = (ok == 0); + } + } + + return result; +} + + diff --git a/libsst-concurrency/SST_Semaphore_Win32.c b/libsst-concurrency/SST_Semaphore_Win32.c new file mode 100644 index 0000000..a9dd633 --- /dev/null +++ b/libsst-concurrency/SST_Semaphore_Win32.c @@ -0,0 +1,66 @@ +/* + SST_Semaphore_Win32.c + Author: Patrick Baggett <ptbaggett@762studios.com> + Created: 12/20/2011 + + Purpose: + + libsst-concurrency semaphore functions for Win32 platforms (Windows 7 or later) + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ + +#include <SST/SST_Concurrency.h> /* SST_WAIT_INFINITE */ + +#define _WIN32_WINNT 0x0601 /* Windows 7 or later */ +#include <windows.h> + +/*************************************************************************/ + +SST_Semaphore SST_Concurrency_CreateSemaphore(uint32_t _initialCount) +{ + /* Windows wants a maximum count, so 2^31-1 */ + HANDLE hSema = CreateSemaphoreA(NULL, _initialCount, (LONG)INT32_MAX, NULL); + + return (SST_Semaphore)hSema; +} + +/*************************************************************************/ + +void SST_Concurrency_DestroySemaphore(SST_Semaphore _sema) +{ + HANDLE hSema = (HANDLE)_sema; + + CloseHandle(hSema); +} + +/*************************************************************************/ + +void SST_Concurrency_PostSemaphore(SST_Semaphore _sema, uint32_t _count) +{ + HANDLE hSema = (HANDLE)_sema; + + ReleaseSemaphore(hSema, _count, NULL); +} + +/*************************************************************************/ + +int SST_Concurrency_WaitSemaphore(SST_Semaphore _sema, uint32_t _ticks) +{ + HANDLE hSema = (HANDLE)_sema; + DWORD dwTime; + + if(_ticks == SST_WAIT_INFINITE) + dwTime = INFINITE; + else + dwTime = (DWORD)_ticks; + + return (WaitForSingleObject(hSema, dwTime) == WAIT_OBJECT_0); +} diff --git a/libsst-concurrency/SST_TLS_POSIX.c b/libsst-concurrency/SST_TLS_POSIX.c new file mode 100644 index 0000000..5284b89 --- /dev/null +++ b/libsst-concurrency/SST_TLS_POSIX.c @@ -0,0 +1,70 @@ +/* + SST_TLS_POSIX.c + Author: Patrick Baggett <ptbaggett@762studios.com> + Created: 12/20/2011 + + Purpose: + + libsst-concurrency thread local storage functions for POSIX platforms + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ + +#include <SST/SST_TLS.h> +#include <pthread.h> +#include <stdlib.h> + +/******************************************************************************/ + +SST_TLS SST_Concurrency_CreateTLS(void) +{ + pthread_key_t* key = (pthread_key_t*)malloc(sizeof(pthread_key_t)); + + if(key == NULL) + return NULL; + + if(pthread_key_create(key, NULL) != 0) + { + free(key); + return NULL; + } + + return (SST_TLS)key; +} + +/******************************************************************************/ + +void SST_Concurrency_DestroyTLS(SST_TLS tls) +{ + pthread_key_t* key = (pthread_key_t*)tls; + + pthread_key_delete(*key); + free(key); +} + +/******************************************************************************/ + +void* SST_Concurrency_GetTLSValue(SST_TLS tls) +{ + pthread_key_t* key = (pthread_key_t*)tls; + + return pthread_getspecific(*key); +} + +/******************************************************************************/ + +void SST_Concurrency_SetTLSValue(SST_TLS tls, void* value) +{ + pthread_key_t* key = (pthread_key_t*)tls; + + pthread_setspecific(*key, value); +} + + diff --git a/libsst-concurrency/SST_TLS_Solaris.c b/libsst-concurrency/SST_TLS_Solaris.c new file mode 100644 index 0000000..3e1103e --- /dev/null +++ b/libsst-concurrency/SST_TLS_Solaris.c @@ -0,0 +1,66 @@ +/* + SST_TLS_POSIX.c + Author: Patrick Baggett <ptbaggett@762studios.com> + Created: 4/11/2012 + + Purpose: + + libsst-concurrency thread local storage functions using native Solaris TLS + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ + +#include <SST/SST_TLS.h> +#include <thread.h> + +/******************************************************************************/ + +SST_TLS SST_Concurrency_CreateTLS(void) +{ + thread_key_t key; + + if(thr_keycreate(&key, NULL) != 0) + return NULL; + + return (SST_TLS)key; +} + +/******************************************************************************/ + +void SST_Concurrency_DestroyTLS(SST_TLS tls) +{ + /* As noted in Solaris's source code, there is no function to destroy keys. + This is done for performance. Even the good old pthread_key_destroy() + interface does nothing on Solaris. Well. Hmm. */ + (void)tls; +} + +/******************************************************************************/ + +void* SST_Concurrency_GetTLSValue(SST_TLS tls) +{ + thread_key_t key = (thread_key_t)tls; + void* value = NULL; + + thr_getspecific(key, &value); + + return value; +} + +/******************************************************************************/ + +void SST_Concurrency_SetTLSValue(SST_TLS tls, void* value) +{ + thread_key_t key = (thread_key_t)tls; + + thr_setspecific(key, value); +} + + diff --git a/libsst-concurrency/SST_TLS_Win32.c b/libsst-concurrency/SST_TLS_Win32.c new file mode 100644 index 0000000..1d4b621 --- /dev/null +++ b/libsst-concurrency/SST_TLS_Win32.c @@ -0,0 +1,59 @@ +/* + SST_TLS_Win32.c + Author: Patrick Baggett <ptbaggett@762studios.com> + Created: 12/20/2011 + + Purpose: + + libsst-concurrency thread local storage functions for Win32 platforms (Windows 7 or later) + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ + +#include <SST/SST_TLS.h> + +#define _WIN32_WINNT 0x0601 /* Windows 7 or later */ +#include <windows.h> + +/*************************************************************************/ + +SST_TLS SST_Concurrency_CreateTLS(void) +{ + DWORD slot = TlsAlloc(); + + return (SST_TLS)slot; +} + +/*************************************************************************/ + +void SST_Concurrency_DestroyTLS(SST_TLS tls) +{ + DWORD slot = (DWORD)tls; + + TlsFree(slot); +} + +/*************************************************************************/ + +void* SST_Concurrency_GetTLSValue(SST_TLS tls) +{ + DWORD slot = (DWORD)tls; + + return TlsGetValue(slot); +} + +/*************************************************************************/ + +void SST_Concurrency_SetTLSValue(SST_TLS tls, void* value) +{ + DWORD slot = (DWORD)tls; + + TlsSetValue(slot, value); +} diff --git a/libsst-concurrency/SST_ThreadBarrier.c b/libsst-concurrency/SST_ThreadBarrier.c new file mode 100644 index 0000000..681b278 --- /dev/null +++ b/libsst-concurrency/SST_ThreadBarrier.c @@ -0,0 +1,150 @@ +/* + SST_ThreadBarrier.c + Author: Patrick Baggett <ptbaggett@762studios.com> + Created: 12/20/2011 + + Purpose: + + libsst-concurrency thread barrier functions + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ + +#include <SST/SST_Concurrency.h> /* SST_WAIT_INFINITE */ +#include <SST/SST_ThreadBarrier.h> /* Functions being implemented */ +#include <SST/SST_Atomic.h> /* Needed for atomic operations */ +#include <stdlib.h> + +#define WAKEUP_UNSIGNALED (-1) +#define WAKEUP_CANCELED 0 +#define WAKEUP_SUCCESS 1 + +typedef struct SST_ThreadBarrierImpl +{ + SST_Event event; + uint32_t count; + volatile int wakeup_reason; + uint32_t threshold; +} SST_ThreadBarrierImpl; + +/*************************************************************************/ + +SST_ThreadBarrier SST_Concurrency_CreateThreadBarrier(uint32_t threshold) +{ + SST_ThreadBarrierImpl* barrier; + + /* Allocate barrier */ + barrier = (SST_ThreadBarrierImpl*)malloc(sizeof(SST_ThreadBarrierImpl)); + if(barrier == NULL) + return NULL; + + barrier->event = SST_Concurrency_CreateEvent(); + if(barrier->event == NULL) /* Out of memory */ + { + free(barrier); + return NULL; + } + + barrier->count = 0; + barrier->wakeup_reason = WAKEUP_UNSIGNALED; /* == error condition */ + barrier->threshold = threshold; + + /* Ensure all memory operations are visible by the time this returns */ + SST_Concurrency_MemoryBarrier(); + + return (SST_ThreadBarrier)barrier; +} + +/*************************************************************************/ + +int SST_Concurrency_WaitThreadBarrier(SST_ThreadBarrier _barrier) +{ + SST_ThreadBarrierImpl* barrier = (SST_ThreadBarrierImpl*)_barrier; + uint32_t newValue; + const int reason = barrier->wakeup_reason; + int retval; + + /* Already canceled? */ + if(reason == WAKEUP_CANCELED) + return 0; + + /* Already successful? */ + if(reason == WAKEUP_SUCCESS) + return (int)barrier->threshold; + + /* At this point, we believe the barrier has not yet been canceled/finished. Due to + multithreading, it could have been though. */ + + /* Increment barrier count, see if we've exceeded the threshold */ + newValue = (uint32_t)SST_Atomic_AddReturn((volatile int*)&barrier->count, 1); + if(newValue == barrier->threshold) + { + /* Yes -- but is it already canceled/finished? */ + const int state = SST_Atomic_CAS(&barrier->wakeup_reason, WAKEUP_UNSIGNALED, WAKEUP_SUCCESS); + + /* + 'state' can only be WAKEUP_SUCCESS or WAKEUP_CANCELED at this point. Don't + (redundantly) signal the event if it was canceled. + */ + + if(state == WAKEUP_SUCCESS) + SST_Concurrency_SignalEvent(barrier->event); + + retval = SST_BARRIER_SINGLE; + } + else /* either newValue < threshold newValue > threshold or */ + { + /* No not yet. Wait. */ + SST_Concurrency_WaitEvent(barrier->event, SST_WAIT_INFINITE); + retval = 1; + } + + /* Threads could have been woken up due to a cancel or due to the count being exceeded. */ + if(barrier->wakeup_reason == WAKEUP_UNSIGNALED) /* error? */ + return -1; + if(barrier->wakeup_reason == WAKEUP_CANCELED) /* canceled */ + return 0; + + return retval; +} + +/*************************************************************************/ + +void SST_Concurrency_ResetThreadBarrier(SST_ThreadBarrier _barrier, uint32_t newThreshold) +{ + SST_ThreadBarrierImpl* barrier = (SST_ThreadBarrierImpl*)_barrier; + barrier->count = 0; + barrier->threshold = newThreshold; + barrier->wakeup_reason = WAKEUP_UNSIGNALED; /* == error condition */ + + SST_Concurrency_ResetEvent(barrier->event); +} + +/*************************************************************************/ + +void SST_Concurrency_CancelThreadBarrier(SST_ThreadBarrier _barrier) +{ + SST_ThreadBarrierImpl* barrier = (SST_ThreadBarrierImpl*)_barrier; + barrier->wakeup_reason = WAKEUP_CANCELED; /* == barrier canceled */ + SST_Concurrency_SignalEvent(barrier->event); + + /* NOTE: SignalEvent() provides a memory barrier so that barrier->wakeup_reason is globally + visible before the event is signaled. */ +} + +/*************************************************************************/ + +void SST_Concurrency_DestroyThreadBarrier(SST_ThreadBarrier _barrier) +{ + SST_ThreadBarrierImpl* barrier = (SST_ThreadBarrierImpl*)_barrier; + SST_Concurrency_DestroyEvent(barrier->event); + free(barrier); +} + diff --git a/libsst-concurrency/SST_Thread_POSIX.c b/libsst-concurrency/SST_Thread_POSIX.c new file mode 100644 index 0000000..076d830 --- /dev/null +++ b/libsst-concurrency/SST_Thread_POSIX.c @@ -0,0 +1,158 @@ +/* + SST_Thread_POSIX.c + Author: Patrick Baggett <ptbaggett@762studios.com> + Created: 12/20/2011 + + Purpose: + + libsst-concurrency thread functions for POSIX platforms + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ +#include <pthread.h> /* POSIX threads API */ +#include <unistd.h> /* usleep() */ +#include <stdlib.h> /* malloc()/free() */ +#include <sched.h> /* sched_yield() */ +#include <errno.h> /* system error codes */ +#include <time.h> /* nanosleep() */ + +#include <pstdint.h> +#include <SST/SST_Thread.h> + +/* Less-than-POSIX madness. Used for getting the thread ID, which POSIX decided to leave out... /rage */ +#if defined(__linux__) && !defined(__ANDROID__) + #include <sys/syscall.h> +#endif + +#ifdef __FreeBSD__ + #include <sys/thr.h> +#endif + +#ifdef __APPLE__ + #include <sys/time.h> + #include <mach/mach_init.h> +#endif + +SST_Thread SST_Concurrency_CreateThread(int(*_func)(void*), void *_arg) +{ + pthread_t* thr; + + #ifdef _DEBUG + if(_func == (int(*)(void*))NULL) + return NULL; + #endif + + thr =(pthread_t*)malloc(sizeof(pthread_t)); + + /* Create the thread */ + if(pthread_create(thr, NULL, (void*(*)(void*))_func, _arg) != 0) + { + free(thr); + return NULL; + } + + return (SST_Thread)thr; +} + +void SST_Concurrency_DestroyThread(SST_Thread _thr) +{ + pthread_t* thr = (pthread_t*)_thr; + + pthread_detach(*thr); + + free(thr); +} + +void SST_Concurrency_SleepThread(uint32_t _ms) +{ + struct timespec req, rem; + long msecs = _ms % 1000; /* milliseconds that are less than 1 sec (0-999) */ + rem.tv_sec = _ms / 1000; /* msec -> sec by mult 1e-3 */ + rem.tv_nsec = msecs * (1000 * 1000); /* msec -> nsec by mult 1e6 */ + + + /* Sleep, continuing if woken up by EINTR (POSIX signal) */ + do + { + /* On EINTR, 'rem' contains the remaining time that has not yet + been slept. */ + req = rem; + if(nanosleep(&req, &rem) == 0) /* 0 == success */ + break; + } while(errno == EINTR); + +} + +uint32_t SST_Concurrency_GetThreadId() +{ +#if defined(__APPLE__) + return (uint32_t)mach_thread_self(); +#elif defined(__FreeBSD__) + long lwpid; + + thr_self(&lwpid); + return (uint32_t)lwpid; +#elif defined(__ANDROID__) + return (uint32_t)pthread_self(); /* Android uses integer as pthread_t */ +#elif defined(__linux__) + return (uint32_t)syscall(SYS_gettid); /* kinda hacky but works */ +#else + #error Need Thread ID implementation for your OS +#endif + +} + +uint64_t SST_Concurrency_GetTicks(void) +{ +#if defined(__APPLE__) + struct timeval tv; + struct timezone tz; tz.tz_minuteswest = 0; tz.tz_dsttime = 0; + gettimeofday(&tv, &tz); + + return ((uint64_t) tv.tv_sec * 1000) + ((uint64_t)tv.tv_usec / 1000); + +#else + + struct timespec tv; + + clock_gettime(CLOCK_REALTIME, &tv); + + return ((uint64_t)tv.tv_sec * 1000) + ((uint64_t)tv.tv_nsec / 1000000); +#endif +} + +int SST_Concurrency_WaitThread(SST_Thread _thr, int* _retval) +{ + pthread_t* thr = (pthread_t*)_thr; + void* thrRetval; + int join_retval; + + /* Join, capturing the return value */ + if(_retval) + { + uintptr_t masked; + join_retval = pthread_join(*thr, &thrRetval); + + + masked = (uintptr_t)thrRetval; + *_retval = (int)masked; + } + else + join_retval = pthread_join(*thr, NULL); + + + return (join_retval == 0); +} + +void SST_Concurrency_YieldThread(void) +{ + sched_yield(); +} + diff --git a/libsst-concurrency/SST_Thread_Solaris.c b/libsst-concurrency/SST_Thread_Solaris.c new file mode 100644 index 0000000..cd5311c --- /dev/null +++ b/libsst-concurrency/SST_Thread_Solaris.c @@ -0,0 +1,127 @@ +/* + SST_Thread_Solaris.c + Author: Patrick Baggett <ptbaggett@762studios.com> + Created: 4/11/2012 + + Purpose: + + libsst-concurrency thread functions using Solaris native threads + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ +#include <thread.h> /* Solaris native threads */ +#include <unistd.h> /* usleep() */ +#include <errno.h> /* system error codes */ +#include <time.h> /* nanosleep() */ +#include <sys/syscall.h> + +#include <pstdint.h> +#include <SST/SST_Thread.h> + +/******************************************************************************/ + +SST_Thread SST_Concurrency_CreateThread(int(*_func)(void*), void *_arg) +{ + thread_t thr; + + #ifdef _DEBUG + if(_func == (int(*)(void*))NULL) + return NULL; + #endif + + /* Create the thread */ + if(thr_create(NULL, 0, (void*(*)(void*))_func, _arg, THR_BOUND, &thr) != 0) + return NULL; + + return (SST_Thread)thr; +} + +/******************************************************************************/ + +void SST_Concurrency_DestroyThread(SST_Thread _thr) +{ + /* Detach the thread. This uses the direct system call + since there is no thr_detach() function. This has + been tested to work on Solaris 10. */ + syscall(SYS_lwp_detach, (thread_t)_thr); +} + +/******************************************************************************/ + +void SST_Concurrency_SleepThread(uint32_t _ms) +{ + struct timespec req, rem; + long msecs = _ms % 1000; /* milliseconds that are less than 1 sec (0-999) */ + rem.tv_sec = _ms / 1000; /* msec -> sec by mult 1e-3 */ + rem.tv_nsec = msecs * (1000 * 1000); /* msec -> nsec by mult 1e6 */ + + /* Sleep, continuing if woken up by EINTR (POSIX signal) */ + do + { + /* On EINTR, 'rem' contains the remaining time that has not yet + been slept. */ + req = rem; + if(nanosleep(&req, &rem) == 0) /* 0 == success */ + break; + } while(errno == EINTR); + +} + +/******************************************************************************/ + +uint32_t SST_Concurrency_GetThreadId() +{ + return (uint32_t)thr_self(); +} + +/******************************************************************************/ + +uint64_t SST_Concurrency_GetTicks(void) +{ + struct timespec tv; + + clock_gettime(CLOCK_MONOTONIC, &tv); + + return ((uint64_t)tv.tv_sec * 1000) + ((uint64_t)tv.tv_nsec / 1000000); +} + +/******************************************************************************/ + +int SST_Concurrency_WaitThread(SST_Thread _thr, int* _retval) +{ + thread_t thr = (thread_t)_thr; + thread_t departed = 0; + void* thrRetval; + int join_retval; + + /* Join, capturing the return value */ + if(_retval) + { + uintptr_t masked; + join_retval = thr_join(thr, &departed, &thrRetval); + + + masked = (uintptr_t)thrRetval; + *_retval = (int)masked; + } + else + join_retval = thr_join(thr, &departed, NULL); + + + return (join_retval == 0 && thr == departed); +} + +/******************************************************************************/ + +void SST_Concurrency_YieldThread(void) +{ + thr_yield(); +} + diff --git a/libsst-concurrency/SST_Thread_Win32.c b/libsst-concurrency/SST_Thread_Win32.c new file mode 100644 index 0000000..14ebecd --- /dev/null +++ b/libsst-concurrency/SST_Thread_Win32.c @@ -0,0 +1,166 @@ +/* + SST_Thread_Win32.c + Author: Patrick Baggett <ptbaggett@762studios.com> + Created: 12/20/2011 + + Purpose: + + libsst-concurrency thread functions for Win32 platforms (Windows 7 or later) + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ + +#include <SST/SST_Thread.h> + +#define _WIN32_WINNT 0x0601 /* Windows 7 or later */ +#include <windows.h> +#include <process.h> /* _beginthreadex() */ + +struct WrapStdcallData +{ + int (*func)(void*); /* Function to call */ + void* arg; /* Arg for said function */ +}; + +/*************************************************************************/ + +/* OS really need "unsigned int" data type here, don't change! */ +static unsigned int __stdcall wrapStdcall(void* arg) +{ + struct WrapStdcallData* info = (struct WrapStdcallData*)arg; + struct WrapStdcallData thrData; + int retval; + + /* Copy data to local variable */ + thrData.arg = info->arg; + thrData.func = info->func; + + /* Free the allocated copy */ + HeapFree(GetProcessHeap(), 0, arg); + + /* Call user supplied function */ + retval = thrData.func(thrData.arg); + + /* This actually kills the thread */ + return (unsigned int)retval; +} + +/*************************************************************************/ + +SST_Thread SST_Concurrency_CreateThread(SST_ThreadFunc _func, void *_arg) +{ + HANDLE hNewThread; + struct WrapStdcallData* info; + + /* Allocate heap structure to pass between threads */ + info = HeapAlloc(GetProcessHeap(), 0, sizeof(struct WrapStdcallData)); + if(!info) + return NULL; + info->arg = _arg; + info->func = _func; + + /* Create the thread, and return the handle immediately on success */ + hNewThread = (HANDLE)_beginthreadex(NULL, 0, wrapStdcall, info, 0, NULL); + if(hNewThread != NULL) + return (SST_Thread)hNewThread; + + /* Not successful -- don't leak memory */ + free(info); + return (SST_Thread)NULL; +} + +/*************************************************************************/ + +void SST_Concurrency_DestroyThread(SST_Thread _thr) +{ + HANDLE hThread = (HANDLE)_thr; + + CloseHandle(hThread); +} + +/*************************************************************************/ + +void SST_Concurrency_SleepThread(uint32_t _ms) +{ + ULONGLONG now; + ULONGLONG done; + + /* Get the time now, and the time in the future for when it should be done */ + now = SST_Concurrency_GetTicks(); + done = now + (ULONGLONG)_ms; + + /* Do a cursory sleep. This can sleep less than the required time, per MSDN.*/ + Sleep((DWORD)_ms); + + /* Now, if didn't sleep enough, then do small sleeps until we did. */ + while(SST_Concurrency_GetTicks() < done) + Sleep(1); +} + +/*************************************************************************/ + +uint32_t SST_Concurrency_GetThreadId() +{ + return (uint32_t)GetCurrentThreadId(); +} + +/*************************************************************************/ + +uint64_t SST_Concurrency_GetTicks(void) +{ +#if defined(__GNUC__) + static ULONGLONG (WINAPI* pf_GetTickCount64)(void) = NULL; + + if(pf_GetTickCount64 == NULL) + { + pf_GetTickCount64 = (ULONGLONG (WINAPI*)(void))GetProcAddress(GetModuleHandleA("kernel32.dll"), "GetTickCount64"); + } + return (uint64_t)pf_GetTickCount64(); +#else + return (uint64_t)GetTickCount64(); +#endif +} + +/*************************************************************************/ + +int SST_Concurrency_WaitThread(SST_Thread _thr, int* _retval) +{ + HANDLE hThread = (HANDLE)_thr; + DWORD exitCode; + int waitOk = 0; + + /* Wait for the thread to exit */ + if(WaitForSingleObject(hThread, INFINITE) == WAIT_OBJECT_0) + { + /* Is a return value wanted? */ + if(_retval) + { + /* OK, try and get it */ + if(GetExitCodeThread(hThread, &exitCode)) + { + *_retval = (int)exitCode; + waitOk = 1; + } + } + else /* No return code wanted, so we're good */ + waitOk = 1; + } + + return waitOk; +} + +/*************************************************************************/ + +void SST_Concurrency_YieldThread(void) +{ + /* Attempt to schedule a different thread. False -> nothing to do */ + if(SwitchToThread() == FALSE) + Sleep(1); /* Nothing to do -> sleeeeeep */ +} diff --git a/libsst-concurrency/libsst-concurrency.vcxproj b/libsst-concurrency/libsst-concurrency.vcxproj new file mode 100644 index 0000000..217b569 --- /dev/null +++ b/libsst-concurrency/libsst-concurrency.vcxproj @@ -0,0 +1,183 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup Label="ProjectConfigurations"> + <ProjectConfiguration Include="Debug|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectGuid>{7AF55FF8-2F78-42EC-8A05-7FA1AE514814}</ProjectGuid> + <RootNamespace>libsstconcurrency</RootNamespace> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> + <ConfigurationType>StaticLibrary</ConfigurationType> + <PlatformToolset>v110</PlatformToolset> + <CharacterSet>MultiByte</CharacterSet> + <WholeProgramOptimization>true</WholeProgramOptimization> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> + <ConfigurationType>StaticLibrary</ConfigurationType> + <PlatformToolset>v110</PlatformToolset> + <CharacterSet>MultiByte</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> + <ConfigurationType>StaticLibrary</ConfigurationType> + <PlatformToolset>v110</PlatformToolset> + <CharacterSet>MultiByte</CharacterSet> + <WholeProgramOptimization>true</WholeProgramOptimization> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> + <ConfigurationType>StaticLibrary</ConfigurationType> + <PlatformToolset>v110</PlatformToolset> + <CharacterSet>MultiByte</CharacterSet> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <ImportGroup Label="ExtensionSettings"> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <PropertyGroup Label="UserMacros" /> + <PropertyGroup> + <_ProjectFileVersion>11.0.50727.1</_ProjectFileVersion> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <OutDir>$(SolutionDir)\Lib\x86\</OutDir> + <IntDir>$(SolutionDir)Intermediate\$(Configuration)\$(Platform)\$(ProjectName)\</IntDir> + <TargetName>$(ProjectName)-debug</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <OutDir>$(SolutionDir)\Lib\x86\</OutDir> + <IntDir>$(SolutionDir)Intermediate\$(Configuration)\$(Platform)\$(ProjectName)\</IntDir> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <OutDir>$(SolutionDir)\Lib\x64\</OutDir> + <IntDir>$(SolutionDir)Intermediate\$(Configuration)\$(Platform)\$(ProjectName)\</IntDir> + <TargetName>$(ProjectName)-debug</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <OutDir>$(SolutionDir)\Lib\x64\</OutDir> + <IntDir>$(SolutionDir)Intermediate\$(Configuration)\$(Platform)\$(ProjectName)\</IntDir> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <Optimization>Disabled</Optimization> + <AdditionalIncludeDirectories>$(SolutionDir)Lib\Include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <MinimalRebuild>false</MinimalRebuild> + <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> + <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> + <WarningLevel>Level4</WarningLevel> + <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> + <DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings> + <MultiProcessorCompilation>true</MultiProcessorCompilation> + <WholeProgramOptimization>true</WholeProgramOptimization> + </ClCompile> + <Lib /> + <Lib> + <LinkTimeCodeGeneration>true</LinkTimeCodeGeneration> + </Lib> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <Optimization>MaxSpeed</Optimization> + <IntrinsicFunctions>true</IntrinsicFunctions> + <AdditionalIncludeDirectories>$(SolutionDir)Lib\Include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> + <FunctionLevelLinking>true</FunctionLevelLinking> + <WarningLevel>Level4</WarningLevel> + <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> + <DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings> + <MultiProcessorCompilation>true</MultiProcessorCompilation> + </ClCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Midl> + <TargetEnvironment>X64</TargetEnvironment> + </Midl> + <ClCompile> + <Optimization>Disabled</Optimization> + <AdditionalIncludeDirectories>$(SolutionDir)Lib\Include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <MinimalRebuild>false</MinimalRebuild> + <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> + <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> + <WarningLevel>Level4</WarningLevel> + <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> + <MultiProcessorCompilation>true</MultiProcessorCompilation> + <WholeProgramOptimization>true</WholeProgramOptimization> + </ClCompile> + <Lib /> + <Lib> + <LinkTimeCodeGeneration>true</LinkTimeCodeGeneration> + </Lib> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Midl> + <TargetEnvironment>X64</TargetEnvironment> + </Midl> + <ClCompile> + <Optimization>MaxSpeed</Optimization> + <IntrinsicFunctions>true</IntrinsicFunctions> + <AdditionalIncludeDirectories>$(SolutionDir)Lib\Include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> + <FunctionLevelLinking>true</FunctionLevelLinking> + <WarningLevel>Level4</WarningLevel> + <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> + <MultiProcessorCompilation>true</MultiProcessorCompilation> + </ClCompile> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="SST_Event_Win32.c" /> + <ClCompile Include="SST_Mutex_Win32.c" /> + <ClCompile Include="SST_Once.c" /> + <ClCompile Include="SST_ReadWriteLock.c" /> + <ClCompile Include="SST_Semaphore_Win32.c" /> + <ClCompile Include="SST_Thread_Win32.c" /> + <ClCompile Include="SST_ThreadBarrier.c" /> + <ClCompile Include="SST_TLS_Win32.c" /> + </ItemGroup> + <ItemGroup> + <ClInclude Include="..\Lib\Include\SST\SST_Concurrency.h" /> + <ClInclude Include="..\Lib\Include\SST\SST_Event.h" /> + <ClInclude Include="..\Lib\Include\SST\SST_MemBarrier.h" /> + <ClInclude Include="..\Lib\Include\SST\SST_Mutex.h" /> + <ClInclude Include="..\Lib\Include\SST\SST_Once.h" /> + <ClInclude Include="..\Lib\Include\SST\SST_ReadWriteLock.h" /> + <ClInclude Include="..\Lib\Include\SST\SST_Semaphore.h" /> + <ClInclude Include="..\Lib\Include\SST\SST_Thread.h" /> + <ClInclude Include="..\Lib\Include\SST\SST_ThreadBarrier.h" /> + <ClInclude Include="..\Lib\Include\SST\SST_TLS.h" /> + </ItemGroup> + <ItemGroup> + <ProjectReference Include="..\libsst-atomic\libsst-atomic.vcxproj"> + <Project>{43ed481f-c4a3-40ed-81a3-46c43dc4eb1e}</Project> + </ProjectReference> + </ItemGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> + <ImportGroup Label="ExtensionTargets"> + </ImportGroup> +</Project> \ No newline at end of file diff --git a/libsst-concurrency/libsst-concurrency.vcxproj.filters b/libsst-concurrency/libsst-concurrency.vcxproj.filters new file mode 100644 index 0000000..b7d17ad --- /dev/null +++ b/libsst-concurrency/libsst-concurrency.vcxproj.filters @@ -0,0 +1,71 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup> + <Filter Include="Source Files"> + <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier> + <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions> + </Filter> + <Filter Include="Header Files"> + <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier> + <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> + </Filter> + </ItemGroup> + <ItemGroup> + <ClCompile Include="SST_Event_Win32.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="SST_Mutex_Win32.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="SST_Once.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="SST_ReadWriteLock.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="SST_Semaphore_Win32.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="SST_Thread_Win32.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="SST_ThreadBarrier.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="SST_TLS_Win32.c"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> + <ItemGroup> + <ClInclude Include="..\Lib\Include\SST\SST_Concurrency.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\Lib\Include\SST\SST_Event.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\Lib\Include\SST\SST_MemBarrier.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\Lib\Include\SST\SST_Mutex.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\Lib\Include\SST\SST_Once.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\Lib\Include\SST\SST_ReadWriteLock.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\Lib\Include\SST\SST_Semaphore.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\Lib\Include\SST\SST_Thread.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\Lib\Include\SST\SST_ThreadBarrier.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\Lib\Include\SST\SST_TLS.h"> + <Filter>Header Files</Filter> + </ClInclude> + </ItemGroup> +</Project> \ No newline at end of file diff --git a/libsst-concurrency/obj/x86-64/release/SST_Event_POSIX.o b/libsst-concurrency/obj/x86-64/release/SST_Event_POSIX.o new file mode 100644 index 0000000000000000000000000000000000000000..011251cf41f3a5e66a218aa506a89b33f91829a4 GIT binary patch literal 3520 zcmb<-^>JfjWMqH=Mg}_u1P><4z;J*I!FB*M9T<2RI2l4cI-h!U*8cG5EdAio?fS!` zTfn2+^@B$@g9qawus|nB;D<+d00%_EfdeiB7W(1Q?ZDw-%W!Izb)6<y2Z-N0fx#^G z2$<UmQ^w%Y8^8z=5||Ks7;JU(8-e`^3=9k}KyLEr1UbO<$36(>I7ATSs^$Y47=p(g zBEagpU4NW}8K&UTS^L7H+w}#^D34B5Q&9L&xe3H+Kkg6#3R$oRnh$7DW)jThFjEk2 z2=M5v-O*XPCB>tgMOA}=fdS+d!vn`%4?y+o@aS|s;nD4S0;adQcFX@#gV*9<vF^|l z9?gd|JUWkgbY6!A;E8UBh}Huo_l~<B0D0l%QU(Tw<E}@*2KKsM@aR0YAH)VL?{?j? z>#}c>!1qU;7Y@E)>pbAm>H47C7b4hs0xFz&-~}@SgXY1`6PX7bocI~Q%3gT%hCc8B z8+Z-mxcPto|9>q9cUG^LhDUEG$TpA8^I*F=U5_-^9$_fu2C0F#@ghiof64*=Z3jAC z4}io$CV^bn4dRymNbxW>0f$QoE7**ahZ)?Rovjo!LX%4KN=g+>^-S~(bj?b^Ji|Ie zGd%+nJu^*+xPp;^p_zf1fhEX55EcOu3=9m6RY44l6#|UXJnS437#SF37$6uVT@4}} z`2^aSoO#)p%6Qm0AaXV!aRvqkUl0wK_khdCfW#RX80<kbOuh;%4K}|9B+kIV;02;# z@=UH^1t9z9fW#RX7_2}vOuiH>4c5O0B+kIVU<ry-m^`xyBSZyM5{&{WWnuXEA59p{ zWyV@^FfcGPFoWgM31$WsbRh;|1_lNuBy+%F2UW$)zy@WZQp^nOr~*(PGXpD>g`iX! z7#M^Y7#U#Zg2SGHfx(f1fk6PF49@bvAs&rGJQr&I38)F+xMN^o=)$3X0S@u4IK+2B z&1VNi1T5|u7#ObMQ2!E#I4Fp*`B#(?5<Y=Y^TBC{fq}sQD&7qh2d5d3{fyYdEe3~p z77p=79O4YY!6EUkWvO{3@d5t9o)LP<4DrRqCGm+VDe)zlxv9kksmWk9&iQ%CrA0-l zdC8UW&PAz-C8=Ot47rIpIr+&91tl3psfj7^xuqqk74eyQnI&+c<ovu8hzQ6oWOH0n zi%W{~D<KA<nvepKLNx>?m{ydUis7i>%=Em(9BgLg<R@pN8kAI&pO})ISd4Ha#NDNN zV72J(3`#9dErFPfE)|}b36+7lAMD-o#LN<gWRPL;>8T~4fJAiwNF)WUC_cWpBr!QV zJ~<;hJ}ogb2b!)sp)?Z%0|TgO@aI1S%tI3AW?*1|iEl;{=Rp#Gf+Ws|B>n|SoF7RX zlx{&%AbUaS7iPXPG+lzkg^<+SA&G;^7MOZ3Byms~4inEs5=S<t1xXxPJ-9vumsy~E zgYfTtB=zD*?%@MD5UO4RNxTY4ToOrqIg&WCz59^FrI6GsfC2|<K2!-<1kz>$m8}pA zEB`=kCy)Y=S`dbnTMZyVBy(Wp4XC^VNrBXYFsz&aH!hIW!^#N;z2eH;lEfqiz2cH0 z2%Q0A6{Y4R>XoEclrZR}B$gyH=p_{wGw3Df=jNv7l`!b#<(H)Dx%-9cf)gNv9$0y5 zMtoXPVs0wP4b;G(@B&2@dd&h0uOlE&B3T4di^OG+W?%r<VleeEISUR5YX(#UD35@c zP+<m8+=Eo8f!YoXpgI!7Ltqx{RVFO?!xic<Fff43L|0C%enY7J25=K0448gX2p3L* z`~c#>Xi)tCV}rzD*b?1APziLk{!shTf|<bqs{aO5AB+O|6~+e9ptcXF6@ec97dSz( z3=9(>6u686wGv?ZVc{=`CG0_35<n5gz`zg*;vivk_k;N8ZU-rs06B_*fuRE`2`URg cPC~aIBnI^=NE;k4fF{UEAPeB43>fhb0Ga->AOHXW literal 0 HcmV?d00001 diff --git a/libsst-concurrency/obj/x86-64/release/SST_Mutex_POSIX.o b/libsst-concurrency/obj/x86-64/release/SST_Mutex_POSIX.o new file mode 100644 index 0000000000000000000000000000000000000000..3695155e2e12436fdb09d700b35f318ea6338b6c GIT binary patch literal 2424 zcmb<-^>JfjWMqH=Mg}_u1P><4z)-=4U^{@B4h%dDoD88JoliZQ-w5p2U|?W)0g~|O zbp7Gc?fPRMgmWAs*zNk`<YA~{1&_|!7arZNFJMYNIuWX1><NUG6QQK_0RNN&{M!x? zWf+6Iv$K_gMrcxLUP-Bfsh)|Rfv#C8m}gjLXr^aiqGzTF5mzuWFf=nTGq41C5`;xS z1Oo#DV^t6XV}$^tG!Hw+1V#o183qUjN$Y|LM?QfzCTCu@3?6n4sGJQ*oPmKsA4J3C zvk>wzAaMo;24xTplaE8l*MP(s7#OrbG)z7fAwLHsjzd3G3WEZr0Tzaj|1l&O7#Ntb zrVx-gGdAT6%nU3z#E}vek_u)9b|fBx$;`lt;6Pcz3=9lHNbUiLF*Ga%plXmQGX@3* zY~r3!bCC6e^rhiY4+?W^<}^ahL5VX428P)<%vlFjUk|bj7KaQB45x9Ze+X5-5~?1Y zCKwnP{^C&25F8v5?^{}uS`i=MAM6>Smkbth&d*COEh<XQORkJ}E=o--Nd>E6$W6@2 z$xmh|D9I>FO-zZ;1#8UA%Phgr<&s)lQj}i_(T1u%1tP_eR+O5Gq0c8jIUAd%oc!c$ z48<WumAKTG6jfr?5}F4R#%4n)SOywyd{CN+fq{XOfq~)Ae+YnuCrF$NNgR|uKw3cJ zJV@f9AVCHO29P)}l6VD@I6sm&C>?;LK<WjN#E*gmq2_?nG|W8;Na7$pP%Z<c42IYX z5{ISR1gHX#7zo4CVFQ{tEWIs26NjZM2EF3S+>*p32EF2vA_$!UV-=<5B<hu<R+KR4 zr6iUlGUz207c=N3=jZ08=9Mt$<>i;8>bd)c>K2zICTBC~ft9Cb#HSS{=B7feqnHAP z3#g1jFF|18at6%?kXmFRX$A&xsRUCGlluWJs#ZV+KxqJ^7gSb*gd{)&0|SE^sH_K< zg-`(~#RF0dWg}DQ!a58L3?MVnOH5+*8$#_jK(>T|fdQu96ipmvKa945>PJ(?;0RNI zCV?*O57iG!W5`N9pbB>&3qt*hEaZhF{1-rrcv$`cg+Hh^0EHDuKP>z~c?Ui0!1B-p z5eecTVW_j<A|O7x+rg4h!3Q7(3=9n1P`9Jo4=OXT+5Z44C<N6HHWM0FFgAz=0Cc}q AB>(^b literal 0 HcmV?d00001 diff --git a/libsst-concurrency/obj/x86-64/release/SST_Once.o b/libsst-concurrency/obj/x86-64/release/SST_Once.o new file mode 100644 index 0000000000000000000000000000000000000000..4d1d77e8ae152453d4dfdcfb9c59c55a3190abb4 GIT binary patch literal 1928 zcmb<-^>JfjWMqH=Mg}_u1P><4z|g^hU^{@B4h%dDoD88JoliZQ-w1eg*8X_S{sJWP zd4fl`>yK`R<_C<e2TI;dIC&VV$iSns_Jv1h=>w0>&>J4zt}i?~U4KB-cDjD)cKrg@ zQ5xS|`-P#B4<zBydHlt!|NsBL_5tyBG5r7Eu#e&Ye+G~^$SPY9r&PhC8*JVKkIw7= zFMw3;19<_a=run`2*mRT8N~>5P-iXJ^5YC3L-^Nym=JrI!QI)}N<kwusWh*oRKZlw zM9)CitQ5>MtTQyzGceIJ(}ajC7#SFv8JHPZg51HtAOfKn7^{L97%K!ArFqynCNMHE z$S^=KNLm#{IPwX!F*)<HCGfCwK;>*e;tUK76G1dgo~Z|{0Hi+#B+kIVAOWIb^1)zf zkO)=`3IG;{kN>erGGmQl1_ovZW^BqCm>G~FAF6_ffq{Vu$sDlXpmNL%Y)}>|#mvBt zDgfm%Gq6Hg2uh5Bfk6Plg|mzp7#M^Y7#U#pfy0b}fx#Px`Y0UY8BlY!K}`mSEr=Z) z91`!Jmz=7X%ut?~SrVU;pO?x25_HbbOD-)cO3h2IjE~Gr%}EK#C`wIC!H{#UNKFPA z0G4np$<NJ9j(2tpM&|k#fqBR#dgf)8fOL5z=B4DMGBEIi+yV|`1_n+B28KWXA)pFL zoEu4eK9V>nZeZ#aki?mwY!C&>!=N~XU|4u2fFz;zg4Dyphe5BnGPfi#i9xTpqzFQ1 zz*t48If;5DsTCy*dMSw|i41y4#l;MI$@#gtsd*&~dU^RJse0~yp}NH-iOJavdSK<L z8S!aFiMgpz>nNr`{sg6Y^ppql=Q%VRKx&bNq!}2%sT`&rCN~3`B|M-4Tnr50R1eC# zAR$<~QG<#@m4l?fm=E0|uqea~C=*QSFfcHH%p_O8A=G{YuxSVaX1^&y2+V>x3r1T( z^@Amm2xpiABry;ZUDzM0ACzW5@-XZHRagNNfYKnpLYZL73rF}rfCdP1_=8Fjn0{FJ z3o?MpFR)Q4ga)+eibN5`41bU_(cKQxasVX3z`zgyr9pWPlpoRU2Z=$Q3epD00#Lzr PxCn#+H4egIU|;|MuRi(7 literal 0 HcmV?d00001 diff --git a/libsst-concurrency/obj/x86-64/release/SST_ReadWriteLock.o b/libsst-concurrency/obj/x86-64/release/SST_ReadWriteLock.o new file mode 100644 index 0000000000000000000000000000000000000000..0db0460a664979177f5df974b3ce92d170475a46 GIT binary patch literal 2936 zcmb<-^>JfjWMqH=Mg}_u1P><4z)-<~U^{@B4h%dDoD88JoliZQ-w5nyVPIf*0g~|O zbp7GcT>FEelzj(?|60(a+x5qB5R-v_-3Jio<YA~b1&_|!7aq;EFBnS1Ji1+9fc18} z{_yBL4mRsG;{>=`1CP$y8=a+BJeq57z|BqpD{Fr6-=ov@g-5sR4UbOO53lu_Yp?t- zQ3lJwjO;uFvOx1t=LKumD`ilpsX~-=yME|qXgyGI!lT>u!#<GrVGh^<;^22eIm8Sk z`$49F%&Uaj5(*O7$H2hQ05g_&7fM1*2fI-9|NsB>tp`dEqq+(y5T!wWg!y>i|NsC0 z!)-(gNqidWQ8X~PJ3Ct`XoMz}=9QExnChA68R(jof_a8@hGu#OCVFO?5OD<~14A<d zGXqO-L^Fs$C<ex=AO^+?0Y+&ac8&>*3=A?15Dbzw2N8~Z0&Psrylh20?4TqDlD7eg zGcYjdfM}R}Izm1MB+kIV&<vts@=SGL1t9%3AaMo;hG`%gE<X`2KL;evz`$S#qG9qm zU}>=X_JG83$U~(tC{Q|KVfgqTLxO>Uff;L#0*NzYQ_jH50Lo05Qp^l&n1W#Q*>Q-o zVu*_}Ffa%qxd$8v3=9mQXcNFt&A<T4>mc<ob>KK*U|>jPU|_(eJ_~AoGSn<^95FC3 zbmCCI2!}W*yI?c_EY$pGQ1iiY%)r3#28TJnpz3Qt5d@1<1_lOEMo2iUMH4q*#O^PK z;NXz>pwz^a@S@C;RG<9hY`tW#m~(z!a%oXfYF=_>ymL`%Vo55BDu&#|oSb}2r7o$( zB}Ms_sA|)SQd2Pu1=;16Uj$N_nU{_s?Vef^l9`-cj3E)3nVORll2MeJm;#n_EXmK! zOpbR<fpC%C4YdN~HJBAp)&50by~v7P^HOlR#WfEcJZNS(=A|$&@Im8?iGhKElYxQZ z52$eZ|Nnm!k~lY#cq5WHFOv9N9O4I%#6fn!%)gB!&W~gc3pCzA?m;%+2uWNJNxeOi zII{XABynVWmmrBF+j|vB98^Za+^K-%PLP|RTyXvau|Z-W49kZJAVCHO29OvC!}41L znm8<<EI<>7<p<<&1DONM4-9(6mANH}Nep_$B}EWA1I8*!%}LZNNv$Yh&`U`yNo3GV zDlTTwOU}>DP0cG|(96p&N!4@r3)L+yNleaW&;u(^&4^DcO3Vcn8&H=}MuEZ$6qM*C zBB;CqnS2i<31UDo8ka$ufdO2~!qh{RF=RjuRDf#WVqgH5mY})`q(%ZnFfcHvLB-Ka za5+#QLe(HsP~+f2pmG#sCb{}Sbr;A?1GtG02F!j_2p3L*)PguL+6wA^kQg!!Cer=> zQ2pr2BcK8|kPT&EU;z0QS;z}V_;*07vI$VdpzsF?!SutzACx!I!w#fH0;(_)#6iL^ zf5U`8e5g}lLSWheYUmG;0tN;KP?-cW5`;ktVD^K`FsM?HFdS<@t6W%l0h53l2jemT E0P7hB{Qv*} literal 0 HcmV?d00001 diff --git a/libsst-concurrency/obj/x86-64/release/SST_Semaphore_POSIX.o b/libsst-concurrency/obj/x86-64/release/SST_Semaphore_POSIX.o new file mode 100644 index 0000000000000000000000000000000000000000..5e2c341963e0e528e95728f5e2d912749045fa98 GIT binary patch literal 2992 zcmb<-^>JfjWMqH=Mg}_u1P><4z_5V>!FB*M9T<2RI2l4cI-h!U*8cG5EdAio?fS!` zTfn2+^@B$@g9qawus|nB;D<+d00%_EfdeiB7W(1Q?ZDw-%W!Izb)6<y2Z-N0fx#^G z2$<UmQ^w%Y8^8z=5||Ks7;JU(8->o=H~SSB7#LoFoaNE!`op8S_6I|WNO$NPkm7w1 z;o}hLZr2|t;W|A!YhQSDyS@Nx0y(}Dp~?fwo`9;nv-Al}$7_hkpz4})pD;GpK4B<* zh0qb;(OJ8rvvf;}M>mVA1_J{F$Rfi7$6XJA-PG;6!=uynM04$y|D|Rg-L5BKc6PcR zX|6rOP{Idxb2mft50;YquNfzR1o@{N;NNzj)Ahj1%^(ANT`zca9@`Hx52Dz0%dX45 zNdn&=bzV65g01s_N2lw9ZeNIC=Lx8A=7AT?3=EnFJ5OXDaB$*h04sap(Hr`}18m?m zkV_Q*{r~UL8+rlaGO!TH8f=cc0d-uZD8vyA%|G%=IHCT0&5PphZr1}I-K9TLJd91i zVN${h)^qYOgS)e{m4ZfSQfXdEse-AViJpP3St*!jSZ8RaXJDddrU?;OFfuSSGcYr- zWDo&4iGhKEu_}mxu|j}RnuncZ0wV*13<Cs%q^m)MBcDJUlQS<HQyC9C2Sm;WB+kIV zU<IOK@}*#Du>Kg3I0FNNK8S|NXCdTkK;jGx3`QUtCZCItp92zSU|=u>Whj_DvjHPS z1ymA^0x4x-`1l`97|dnHnll*~m>HPC^5_IJ0}HwkgE#{N0~3-t;IM(JVrF22vQQ~z z26j{dD36(e70N<TnhXpKLJW)yFmu6S%fP_k$-uxMfKUc!1>g{mgqpJzsuCOr3=9la zIMlb{5buVX^8{)RIIb8N7*^s?zX_^d3=|QtxMN^oxPU|bO&sE{aESlFA<o8#J$x8~ zgG1tjQ*#pwGV+U3;{*JIJtOpz8RCnJOX3q#QsPT8b5n~8Qj@{zob&UNON)w9^O7s$ zor_WvOH$!F8FCYIa`KZIic@prGxIV_Fx0!G7MB#|S0XfkRHi@#8PbYUQ!#V|<QJEq zDlf<{#xyuQF%wN$d17V>LwtN{QBhugd`^CHVo7Fx9z$|YesXqvdTI&COJH|`7%5Q2 z#U+W!+40F4+3{(KnK=v$J<#}MVqjq4VqjqS^B)3MBZ+e(iC;t#=S32~izLp6B+d$r ze~|g0bPF>-5J_AJNqsz$xG<7<50W^jtb&>I4oO@TN&O!rab$A@K@I`uT?PhZaaSa9 zF(h+96(Y!MAZZW=u|XJ8cZ13R2!`d;1dt@ue2{urzH2}ehvlOMXyUN^!k|}NnOl;W z#GqGPQUswhV639loJ75n)QS=Yy_Cd~L<YU2;$jB9<ow*+)VvY~y}bOAR6TdUP+f3b zGw6Ypr)I>b6(#1TLan2i0)-1Gh|x<rSh#qDJdb1xNG%eVL7IU9T&lv<!{l~A4OD<? z0HsL~6V_~!fGSi2)m03jG8-xYrMl7Vg$g5;)DRIJ1_lO@ndl`xvHA_6_8UNqgOf1* zrf?Am1LOw~3r2&=a~K;W4#NkCbiY5;estw9{X1X=LTQj+p-eF4g(LiLK&z+<uqsHI z01|@fhlRf&maqqD34kgD)jJ?Q45RxM#7B2KNNoi)LNuU~pt6S(8do5BnEfCzs8WzH S94~-YrQ#q9;Gzr|@ecqo7bY73 literal 0 HcmV?d00001 diff --git a/libsst-concurrency/obj/x86-64/release/SST_TLS_POSIX.o b/libsst-concurrency/obj/x86-64/release/SST_TLS_POSIX.o new file mode 100644 index 0000000000000000000000000000000000000000..a64c1106860d2305f1735c913fe942f471cb3986 GIT binary patch literal 2264 zcmb<-^>JfjWMqH=Mg}_u1P><4z;J^V!FB*M9T<2RI2l4cI-hzpzY*Ba!oa}r0wm$l z>H5Q?x%LM`Df<o(|Fw=sx9g96Af`v>aj=rs10}*BK^PyRjs+xi@-Wmy1&_|!7arZN zFTmz?yZ-2Afa(S*gXx?=gnBe3ouv;@jrHgbec;h~4Ql#?lZP4Hot>=|G(wX~^GZq; zO!Z9k40O#(!92q{Lo+=C6FoCch`550fuWg!nSmw9dmt<VA{ZDL7^{L97%K!ArFqyn zCNMHE$S^=KNID2aIPwX!F*)<HG5PYab3o*5K;jGx3<e+?CZ7$K2J4Rji8C-TD1&I2 zd>lf)1|-hFz@QJJVe(lJd5{n`42o+OhL8WT$uVP12@DL(49wV+GcYrN5&@<ZGXoo@ zAOpx8b{yhJi4Cekkb!|g2+2L*Fl1n0&}Lv@5P+&dri^fiyW$Y{f|?IA7aRu+3=F9_ z)K@^&H$g20#|Z-i!xS9qS3uP-g{lX~5d#Cm5gh6nf`dciLwthc1N?(MBlMENeCPbU z<kF&|)V$=%c;}+j#FEqypJ0aE#GIV`WQKy0jH1-Ul=$q_%J^ikBtu$JYAS|Cm(=2t zqWnsbPGl`9sX3`7n5x}VOG12t!xD2!Q{gtGr<N2Kq$X#kWnwxj7>oL1B=vky|1&W# zFmN(3F#P!s0ftE8Tu9=MNaEZ`;`vD8yh!5JNaD!q=Oc;pBdI@&Bo0brF!v}RiG$n< z<uX9ZJ_ZJm7zo4CO9E5@NDPEw>7oHm92Wl!dc~EwC5cH4dc`G05IO_KDoV{s)GJA? zC}Ge`Ni0cZ&`T;VX3$H{&&^HED`C*f%P&dQbN36?EiOq+&Sua9D^JacPb*5y1tnLg zjg(O!|AWc~^qdRx{}nXjL28kOq!}2%r2$MmOs)W0M1b-GNDLI$AiW$Q4g&*&1e8_- zm7(A=0xAHdL_mt6Y-9>uScidu0c0k6Nky!FP<jNJ2`dL+cER+U!UUi+NG*s7qphIs z2Z<qLPnZH^K`d(hp<<x4gse0Gs(%KuAk?qOLZI>t6x8V9F99uDVd)hV{-9DA6jmVp zu<!@v1@y23$yY%2M}jy=80svz2#AmFc97%?kOTt*!v-h~%A+8=K^P<tvmaD8V6%S) PRPY8!F%pIv2NwYV1Cuon literal 0 HcmV?d00001 diff --git a/libsst-concurrency/obj/x86-64/release/SST_ThreadBarrier.o b/libsst-concurrency/obj/x86-64/release/SST_ThreadBarrier.o new file mode 100644 index 0000000000000000000000000000000000000000..49991067113d41b96c55496af7c2263c43dafbdf GIT binary patch literal 3000 zcmb<-^>JfjWMqH=Mg}_u1P><4z_5b@!FB*M9T<2RI2l4cI-hzpzftI{eY0PJfq~%# zNY10v^@m4u?GJ`h_8lPp>rklhA&+j?A0C|oV5*zJqxC?kFqqwW9IOJOS{)>G+yQJO zgvs;&|Ns9WW_ReD&Hw@abss>SlZT<U8+dfq-tg#ly#cnk+x17c15c;xo95a#45eIP zGhc3DU|?vjeZyGF1Jc>;An<Y#0|Nty?a_RIV;{)N9#BVgx`Ivbb`Y?3{ZMKRRl~Cj zq-G!3A#jCXnrpu>mhyv@bThyVIPUs_p@4zmwKP;5MbmND7a)T`Qr!+b%|HH^vhM&H z`dSn!)Or9GYRuiPFW`Pu@aU|4(OLS$quccb%$rDI)E)YyGXNZ}#~t9I<$-Y11XP1i zP2mAW63BYuG$5%0Yk~&Hgp-FE+?}1R6f{DUO7lue6-@O^^bB;(O2ItCIzux(0~0+n zO^CRHk%6I^fti6N$ZiG(5eUV=SQW&;SRueD&BM+yfsuhhh5>>>(sdxhkx!tF$(fgp zsgj4C10rVw5@%pwcmkr~^7rBLF(7dU1_n<M4VQO;%h!O!85kH0K{QN02P_S?e-22T zfq}sYM8o8BA@U$0Y#0>BEDRt2W0PaXn!^|vm>HO{DQ942V8J2IhC`ekhd3*SxF`by zgAkH?z+ue5zyOLC0Swg)44}M^O&k=)*u)c|=EKYd#}OzmGB7Y;Q$GWT_;MWLhjEDC zh1#10iU?TTgZ#sY-Ck)%NI0y9st2b91_lOusQ4YII5-V3FfgRxFoz*HI3zwKqbM~o z#VN6<C^NN4FBvT6oS&CmT2z#pms}a|T$Gwvl8T~=AvZB6Cm)wm*Rs^S5{9&*)Km<! z!V@z~P)!24z_BDhH#0fjF(oA^wWPEt53CI;=<FB_<|4Z&I5RyjF$ZD|NI$Y1$Oh~( zL8-;5SS&}@3|4|&w{v1%a%v8y+mW@qq!yPH<yR7=2x1E;ju{vj1fet&0|Nsm0|Ub! zP#OFG|9=f6aV{irFC=kpB=Pe|;=D-WKaj-vki-R`=>%jiKa#jEk~k>c!`!n3Nn8j? z{Z%A!WOIHaiG%Vk%p7)*g$xV~APU+23P|n*$w9f`d<<fP#6TF9KNCQLP;)@yu>8}2 zCJxId3(&-2`Gi5QxH7jSF^NI1xTFX|XTVrRsX2*yC8-r940<VvC5a4rNyWtsddc~@ zxu8_8mzQ6Xs^{((s#{!=n4Ha^2Ueb%5ua9+n41c<j$#TFE})=9FF`@&8^~}zkmo@R zC<dv8GQpHI0|U5JhN%Y&GB7aQfEvgF)c{IkASSpm!@$4*Y9oQvsxdHtOI`F5-w(}R zkXjH1nE|3<Scidu0c0k*`a$Iz$V>y6flwM|zbTXtqd;mwY#40?bw5Z988;K@et)Qb zbmbjT0dT7g$zYIQk+=+?{0gcS(Zl}%wCbyXDh7o=NC>7M7XF~}0X^(MS|XqdBS9P_ z4D&Zk2*igv6($6x9iWB^KqWzW5o9C?gA~B*2bD=sr66HA4uDqCjUWr)qL8$L#AN^g DIIby` literal 0 HcmV?d00001 diff --git a/libsst-concurrency/obj/x86-64/release/SST_Thread_POSIX.o b/libsst-concurrency/obj/x86-64/release/SST_Thread_POSIX.o new file mode 100644 index 0000000000000000000000000000000000000000..15f6e8b310ffa202e2631d48a955e97b4bac0138 GIT binary patch literal 3320 zcmb<-^>JfjWMqH=Mg}_u1P><4!0>|;!FB*M9T<2RI2l4cI-hzpzfth$tbO6pS^8i< z2Ll7c3y=bjPS+nE-M$Yzx<g-hbi4l82N66DmTWyxA`BAr=!EchfFxhDfP_vSMlrM7 z^##NvkZBAs^&o{X_5`?&fX>=IDIVP{su~Oo3?N;G2fBUt?7HlmB+z-{`=iba2Vbyd z9(cjbz@T}s^F-$Xk51PU-L4P?P-(E>1CMUk6CRld9Gv(;#(<m;@kXcX1&_|q8y>x( z4?KE7>}xPbv>qto1N*F-q4@_($=TP86DEKhnc`s#aZU*<SQ_Hi{ks?#7{Go83&z5| zjOKceUe^a6oyYcrLI<qUqucd?N9GBT7d${Av+K6Ww(Cvzq@6v!Kl13j;BoMUkO$)l zkM7bRDIUfq;BY{(*rWN4gGXoW36IXw1L$^v{M_mK!lSwN07HpB*!XS+uva_b-t2U} z19n2E>j#f+*AJbCJi1*EbPBu{hbl*j<WAQ+&9!$J_@^A;-*&*G+ZW^}9!xiZJvJfs zFoV0Zvz3BIXi{ljNvVRVo{64;u30IVXIN)wre|QHXQl}eS1>X#G&3+Wuw)Pc1q}lO z17lSX17n2%qcjgY#{@<O1{nqj21$p22uD7FHYR6YHYR@_b`FS~4M?1Ufx!qw!{l?p z(qR2DAaMo;hBY7>CeO4StN>(w4M?1Ufk6~R!{h_N(qR2_K;jGx3@IQQCeIWPRshn! z2PDqGz%T_w!{z(o@^?Vu3=9lBAQ~p`4weRqV8x)k%fj&SKQ>8btT~&3fti6Bn{ozb z1{NIRY&gW(afq{Gh=bxy2+2L*IAUO6Fl1n05WrB)z+izx+#QFw4+8@O$b6W&;5cSr zV93Iuz7ndw4Qe+y&KVdOrs7aPABXq`9O4I|<{N<`2$p6T7#Qy2Q2!LF-W{qQoQ4<} z82;f<&%+4u?`o)eaGGLZU{Gho9-byp_4Z5<4};Sf0|P?<4)qMd!6ES>8AYjyDe(dR z!JZL%$zUPp{JiASqN3Ei<jQ#GqSVBaREQ#m+{B!m{A7lL5{RB;upC2LQEDoNK9|(u zlA`=ds79EMl+=>M<O~eO!8xg^1yH4ViFx_OAU;EUd}>iqUVeN|esW?-W_}(+e0*_9 zVsdtTaz=K1T4H7nhB@x3B@k0QQy7XXi<1*`u&c>T&Msz1&dE>Cj!#c5Dap*mbboka zCe$prceC;{^DwN8%uLNmfmq5=oSc!G5?=`t0Y`usm}Fo8MF*&={qr9JjFH5-7#J8} z;?79o+(_cZNaDOm;`K=4$m&_3=>=pjKazT0BymuFgxRZuBrb@g-VsS$7)d-ENgPy8 z!pvEUB#vy(Yb0@TBy%J{4rG9Y53;x=k~p$CE=b~%NaiRYg#%OxSOn6hftU{xhm{)% zU|EDXtbAxd6NlyN1!&^1{CfaR9F|WXpozosBZFRXWo}7g5`$iGNfCt3fU$~Fa}xDR zQY%Ur^imQ_5*hT8ii;WalJj$OQ}ap~^z!mcQuW;ZLUqA8fI$zeJT)Uettc@!6>1&D z6et`)QH5R;z{1fR6o^Q+fYc&!8KfB)z_klZJxs0xT7_glHGtAQhzV*|g49TW2nGfQ zHBg<;0IIv70#K?O&0eT5QcVL9(P3a<0GWwi^AW2bR8N82WdJb_PQvt?!bKnqkXjH6 zMq5GM4-!Mh2Z(gPKU6=ua+v-f$c94wiY(-XBm6&r0)>HrVFgq%DEvWD0u^R}g+C~- zp@$tv%M4KA#lXN23F07On7?5{AU?X=L2^5wh8932L1h)lZV(2^!|VrH162wVhGPwA Of{X!K02gJzh<^a1%T*Tu literal 0 HcmV?d00001 diff --git a/libsst-concurrency/sources-POSIX.mk b/libsst-concurrency/sources-POSIX.mk new file mode 100644 index 0000000..3be9c70 --- /dev/null +++ b/libsst-concurrency/sources-POSIX.mk @@ -0,0 +1,30 @@ +# libsst-concurrency/sources-POSIX.mk +# Author: Patrick Baggett <ptbaggett@762studios.com> +# Created: 12/23/2011 +# +# Purpose: +# +# List of source files for POSIX-compliant systems. This reduces the amount +# of copy/pasting for different UNIX configurations +# +# License: +# +# This program is free software. It comes without any warranty, to +# the extent permitted by applicable law. You can redistribute it +# and/or modify it under the terms of the Do What The Fuck You Want +# To Public License, Version 2, as published by Sam Hocevar. See +# http://sam.zoy.org/wtfpl/COPYING for more details. + +SRC := \ + SST_Mutex_POSIX.c \ + SST_Event_POSIX.c \ + SST_Thread_POSIX.c \ + SST_ReadWriteLock.c \ + SST_TLS_POSIX.c \ + SST_Semaphore_POSIX.c + +# MacOS X doesn't have decent semaphore implementation, use home-rolled solution +ifeq ($(OS),Darwin) + SRC := $(subst SST_Semaphore_POSIX.c,SST_Semaphore_MacOSX.c, $(SRC)) +endif + diff --git a/libsst-concurrency/sources-Solaris.mk b/libsst-concurrency/sources-Solaris.mk new file mode 100644 index 0000000..4808a8c --- /dev/null +++ b/libsst-concurrency/sources-Solaris.mk @@ -0,0 +1,23 @@ +# libsst-concurrency/sources-Solaris.mk +# Author: Patrick Baggett <ptbaggett@762studios.com> +# Created: 6/21/2012 +# +# Purpose: +# +# List of source files for Solaris +# +# License: +# +# This program is free software. It comes without any warranty, to +# the extent permitted by applicable law. You can redistribute it +# and/or modify it under the terms of the Do What The Fuck You Want +# To Public License, Version 2, as published by Sam Hocevar. See +# http://sam.zoy.org/wtfpl/COPYING for more details. + +SRC := \ + SST_Mutex_Solaris.c \ + SST_Event_Solaris.c \ + SST_Thread_Solaris.c \ + SST_TLS_Solaris.c \ + SST_Semaphore_Solaris.c + diff --git a/libsst-concurrency/sources-Win32.mk b/libsst-concurrency/sources-Win32.mk new file mode 100644 index 0000000..8613f54 --- /dev/null +++ b/libsst-concurrency/sources-Win32.mk @@ -0,0 +1,23 @@ +# libsst-concurrency/sources-Win32.mk +# Author: Patrick Baggett <ptbaggett@762studios.com> +# Created: 11/09/2012 +# +# Purpose: +# +# List of source files for Win32 systems +# +# License: +# +# This program is free software. It comes without any warranty, to +# the extent permitted by applicable law. You can redistribute it +# and/or modify it under the terms of the Do What The Fuck You Want +# To Public License, Version 2, as published by Sam Hocevar. See +# http://sam.zoy.org/wtfpl/COPYING for more details. + +SRC := \ + SST_Mutex_Win32.c \ + SST_Event_Win32.c \ + SST_Thread_Win32.c \ + SST_TLS_Win32.c \ + SST_Semaphore_Win32.c + diff --git a/libsst-concurrency/sources-common.mk b/libsst-concurrency/sources-common.mk new file mode 100644 index 0000000..b793b78 --- /dev/null +++ b/libsst-concurrency/sources-common.mk @@ -0,0 +1,21 @@ +# libsst-concurrency/sources-common.mk +# Author: Patrick Baggett <ptbaggett@762studios.com> +# Created: 12/23/2011 +# +# Purpose: +# +# List of source files for common to all systems. This reduces the amount +# of copy/pasting for different OS configurations. +# +# License: +# +# This program is free software. It comes without any warranty, to +# the extent permitted by applicable law. You can redistribute it +# and/or modify it under the terms of the Do What The Fuck You Want +# To Public License, Version 2, as published by Sam Hocevar. See +# http://sam.zoy.org/wtfpl/COPYING for more details. + +SRC += \ + SST_Once.c \ + SST_ReadWriteLock.c \ + SST_ThreadBarrier.c diff --git a/libsst-concurrency/timespecadd.h b/libsst-concurrency/timespecadd.h new file mode 100644 index 0000000..21c854c --- /dev/null +++ b/libsst-concurrency/timespecadd.h @@ -0,0 +1,45 @@ +/* + timespecadd.h + Author: Patrick Baggett <ptbaggett@762studios.com> + Created: 4/11/2012 + + Purpose: + + Inline code for adding struct timespec, common in UNIX APIs. + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ + +#pragma once + +#ifndef _SST_CONCURRENCY_TIMESPECADD_H +#define _SST_CONCURRENCY_TIMESPECADD_H +#include <SST/SST_Build.h> /* INLINE definition */ + +/* + Compute t1 += t2 in a way that UNIX doesn't bitch. Adding the + tv_nsec fields is bad when they exceed 1B nsec (i.e. 1 sec), so + one must add and then check for overflow. Assumed that t1, t2 + have tv_nsec fields that are each < 1e9 +*/ +static INLINE void _sst_add_timespec(struct timespec* t1, const struct timespec* t2) +{ + t1->tv_sec += t2->tv_sec; + t1->tv_nsec += t2->tv_nsec; + + if(t1->tv_nsec > 1000000000) + { + t1->tv_nsec -= 1000000000; + t1->tv_sec += 1; + } +} + + +#endif diff --git a/libsst-crypto/Makefile b/libsst-crypto/Makefile new file mode 100644 index 0000000..342ab89 --- /dev/null +++ b/libsst-crypto/Makefile @@ -0,0 +1,39 @@ +# libsst-crypto/Makefile +# Author: Patrick Baggett <ptbaggett@762studios.com> +# Created: 12/23/2011 +# +# Purpose: +# +# Makefile for libsst-crypto +# +# License: +# +# This program is free software. It comes without any warranty, to +# the extent permitted by applicable law. You can redistribute it +# and/or modify it under the terms of the Do What The Fuck You Want +# To Public License, Version 2, as published by Sam Hocevar. See +# http://sam.zoy.org/wtfpl/COPYING for more details. + +BINNAME := $(DIST)/libsst-crypto.a +ifeq ($(TARGET),debug) + BINNAME := $(subst .a,_d.a, $(BINNAME)) +endif + +SRC := SST_Hash.c + +OBJ := $(addprefix obj/$(ARCH)/$(TARGET)/,$(subst .c,.o,$(SRC)) ) + +$(shell mkdir -p obj/$(ARCH)/$(TARGET)) + +$(BINNAME): $(OBJ) + $(AR) cru $@ $+ + $(RANLIB) $@ + +# CLEAN +clean: + @-rm -r -f obj $(DIST)/libsst-crypto*.a + +# *.c files to *.o files +obj/$(ARCH)/$(TARGET)/%.o: %.c + @echo CC $@ + @$(CC) $(CFLAGS) -c $*.c -o obj/$(ARCH)/$(TARGET)/$*.o diff --git a/libsst-crypto/SST_Hash.c b/libsst-crypto/SST_Hash.c new file mode 100644 index 0000000..3510ae1 --- /dev/null +++ b/libsst-crypto/SST_Hash.c @@ -0,0 +1,181 @@ +/* + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. +*/ + +#include <SST/SST_Hash.h> + +#include <string.h> + +SST_HashValue64 SST_Crypto_HashDJB2( const char* _string, size_t _len ) +{ + size_t i; + SST_HashValue64 hash = 5381; + + for (i = 0; i < _len; i++) + hash = ((hash << 5) + hash) + _string[i]; + + return hash; +} + +SST_HashValue32 SST_Crypto_HashJ6( const char * _string, size_t _len ) +{ + size_t i; + SST_HashValue32 hash; + + for (hash = 0, i = 0; i < _len; i++) + hash = (hash << 5) - hash + _string[i]; + + return hash; +} + +typedef struct jcr2HashValue +{ + unsigned int HashLower:28; + unsigned int HashMid:28; + unsigned int HashUpper:8; +} jcr2HashValue; + +SST_HashValue64 SST_Crypto_HashJCR2( const char* _string, size_t _len ) +{ + size_t i; + jcr2HashValue hash; + uint64_t val; + + hash.HashUpper = 256 - (unsigned int)_len; + hash.HashMid = 0; + hash.HashLower = 5381; + + for (i = 0; i < _len; i++) + { + hash.HashMid = ((hash.HashMid << 5) - hash.HashMid) + _string[i]; + hash.HashLower = ((hash.HashLower << 5) + hash.HashLower) + _string[i]; + } + + val = hash.HashUpper; + + val = val << 28; + val = val | hash.HashMid; + + val = val << 28; + val = val | hash.HashLower; + + return val; +} + +SST_HashValue64 SST_Crypto_HashSDBM( const char* _string, size_t _len ) +{ + size_t i; + SST_HashValue64 hash = 0; + + for (i = 0; i < _len; i++) + hash = _string[i] + (hash << 6) + (hash << 16) - hash; + + return hash; +} + +/*- + * COPYRIGHT (C) 1986 Gary S. Brown. You may use this program, or + * code or tables extracted from it, as desired without restriction. + * + * First, the polynomial itself and its table of feedback terms. The + * polynomial is + * 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+X^0 + * + * Note that we take it "backwards" and put the highest-order term in + * the lowest-order bit. The X^32 term is "implied"; the LSB is the + * X^31 term, etc. The X^0 term (usually shown as "+1") results in + * the MSB being 1 + * + * Note that the usual hardware shift register implementation, which + * is what we're using (we're merely optimizing it by doing eight-bit + * chunks at a time) shifts bits into the lowest-order term. In our + * implementation, that means shifting towards the right. Why do we + * do it this way? Because the calculated CRC must be transmitted in + * order from highest-order term to lowest-order term. UARTs transmit + * characters in order from LSB to MSB. By storing the CRC this way + * we hand it to the UART in the order low-byte to high-byte; the UART + * sends each low-bit to hight-bit; and the result is transmission bit + * by bit from highest- to lowest-order term without requiring any bit + * shuffling on our part. Reception works similarly + * + * The feedback terms table consists of 256, 32-bit entries. Notes + * + * The table can be generated at runtime if desired; code to do so + * is shown later. It might not be obvious, but the feedback + * terms simply represent the results of eight shift/xor opera + * tions for all combinations of data and CRC register values + * + * The values must be right-shifted by eight bits by the "updcrc + * logic; the shift must be unsigned (bring in zeroes). On some + * hardware you could probably optimize the shift in assembler by + * using byte-swap instructions + * polynomial $edb88320 + * + * + * CRC32 code derived from work by Gary S. Brown. + */ + +static uint32_t crc32_tab[] = +{ + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, + 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, + 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, + 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, + 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, + 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, + 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, + 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, + 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, + 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, + 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, + 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, + 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, + 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, + 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, + 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, + 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, + 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, + 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, + 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, + 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, + 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, + 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, + 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, + 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, + 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, + 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, + 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, + 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, + 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, + 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, + 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, + 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, + 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, + 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, + 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, + 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, + 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, + 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d +}; + +SST_HashValue32 SST_Crypto_HashCRC32(const char* _string, size_t _len) +{ + const uint8_t *p = (uint8_t*) _string; + + /* magic num to implement CRC-32C (so we can later test this v. intelacceleration stuff) */ + uint32_t crc = 0x1EDC6F41 ^ ~0U; + + while (_len--) + crc = crc32_tab[(crc ^ *p++) & 0xFF] ^ (crc >> 8); + + return crc ^ ~0U; +} + diff --git a/libsst-crypto/libsst-crypto.vcxproj b/libsst-crypto/libsst-crypto.vcxproj new file mode 100644 index 0000000..af50f65 --- /dev/null +++ b/libsst-crypto/libsst-crypto.vcxproj @@ -0,0 +1,173 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup Label="ProjectConfigurations"> + <ProjectConfiguration Include="Debug|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectGuid>{E5172B73-AB9A-4702-998F-84C841B30C02}</ProjectGuid> + <RootNamespace>libsstcrypto</RootNamespace> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> + <ConfigurationType>StaticLibrary</ConfigurationType> + <PlatformToolset>v110</PlatformToolset> + <CharacterSet>MultiByte</CharacterSet> + <WholeProgramOptimization>true</WholeProgramOptimization> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> + <ConfigurationType>StaticLibrary</ConfigurationType> + <PlatformToolset>v110</PlatformToolset> + <CharacterSet>MultiByte</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> + <ConfigurationType>StaticLibrary</ConfigurationType> + <PlatformToolset>v110</PlatformToolset> + <CharacterSet>MultiByte</CharacterSet> + <WholeProgramOptimization>true</WholeProgramOptimization> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> + <ConfigurationType>StaticLibrary</ConfigurationType> + <PlatformToolset>v110</PlatformToolset> + <CharacterSet>MultiByte</CharacterSet> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <ImportGroup Label="ExtensionSettings"> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <PropertyGroup Label="UserMacros" /> + <PropertyGroup> + <_ProjectFileVersion>11.0.50727.1</_ProjectFileVersion> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <OutDir>$(SolutionDir)\Lib\x86\</OutDir> + <IntDir>$(SolutionDir)Intermediate\$(Configuration)\$(Platform)\$(ProjectName)\</IntDir> + <TargetName>$(ProjectName)-debug</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <OutDir>$(SolutionDir)\Lib\x86\</OutDir> + <IntDir>$(SolutionDir)Intermediate\$(Configuration)\$(Platform)\$(ProjectName)\</IntDir> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <OutDir>$(SolutionDir)\Lib\x64\</OutDir> + <IntDir>$(SolutionDir)Intermediate\$(Configuration)\$(Platform)\$(ProjectName)\</IntDir> + <TargetName>$(ProjectName)-debug</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <OutDir>$(SolutionDir)\Lib\x64\</OutDir> + <IntDir>$(SolutionDir)Intermediate\$(Configuration)\$(Platform)\$(ProjectName)\</IntDir> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <Optimization>Disabled</Optimization> + <AdditionalIncludeDirectories>..\Lib\Include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <MinimalRebuild>false</MinimalRebuild> + <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> + <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> + <WarningLevel>Level4</WarningLevel> + <TreatWarningAsError>true</TreatWarningAsError> + <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> + <CompileAs>CompileAsC</CompileAs> + <DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings> + <MultiProcessorCompilation>true</MultiProcessorCompilation> + <WholeProgramOptimization>true</WholeProgramOptimization> + </ClCompile> + <Lib /> + <Lib> + <LinkTimeCodeGeneration>true</LinkTimeCodeGeneration> + </Lib> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <Optimization>MaxSpeed</Optimization> + <IntrinsicFunctions>true</IntrinsicFunctions> + <AdditionalIncludeDirectories>..\Lib\Include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> + <FunctionLevelLinking>true</FunctionLevelLinking> + <WarningLevel>Level4</WarningLevel> + <TreatWarningAsError>true</TreatWarningAsError> + <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> + <CompileAs>CompileAsC</CompileAs> + <DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings> + <MultiProcessorCompilation>true</MultiProcessorCompilation> + </ClCompile> + <Lib /> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Midl> + <TargetEnvironment>X64</TargetEnvironment> + </Midl> + <ClCompile> + <Optimization>Disabled</Optimization> + <AdditionalIncludeDirectories>..\Lib\Include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <MinimalRebuild>false</MinimalRebuild> + <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> + <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> + <WarningLevel>Level4</WarningLevel> + <TreatWarningAsError>true</TreatWarningAsError> + <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> + <CompileAs>CompileAsC</CompileAs> + <MultiProcessorCompilation>true</MultiProcessorCompilation> + <WholeProgramOptimization>true</WholeProgramOptimization> + </ClCompile> + <Lib /> + <Lib> + <LinkTimeCodeGeneration>true</LinkTimeCodeGeneration> + </Lib> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Midl> + <TargetEnvironment>X64</TargetEnvironment> + </Midl> + <ClCompile> + <Optimization>MaxSpeed</Optimization> + <IntrinsicFunctions>true</IntrinsicFunctions> + <AdditionalIncludeDirectories>..\Lib\Include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> + <FunctionLevelLinking>true</FunctionLevelLinking> + <WarningLevel>Level4</WarningLevel> + <TreatWarningAsError>true</TreatWarningAsError> + <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> + <CompileAs>CompileAsC</CompileAs> + <MultiProcessorCompilation>true</MultiProcessorCompilation> + </ClCompile> + <Lib /> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="SST_Hash.c" /> + </ItemGroup> + <ItemGroup> + <ClInclude Include="..\Lib\Include\SST\SST_Crypto.h" /> + <ClInclude Include="..\Lib\Include\SST\SST_Hash.h" /> + </ItemGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> + <ImportGroup Label="ExtensionTargets"> + </ImportGroup> +</Project> \ No newline at end of file diff --git a/libsst-crypto/libsst-crypto.vcxproj.filters b/libsst-crypto/libsst-crypto.vcxproj.filters new file mode 100644 index 0000000..281d41b --- /dev/null +++ b/libsst-crypto/libsst-crypto.vcxproj.filters @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup> + <Filter Include="Source Files"> + <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier> + <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions> + </Filter> + <Filter Include="Header Files"> + <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier> + <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> + </Filter> + </ItemGroup> + <ItemGroup> + <ClCompile Include="SST_Hash.c"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> + <ItemGroup> + <ClInclude Include="..\Lib\Include\SST\SST_Crypto.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\Lib\Include\SST\SST_Hash.h"> + <Filter>Header Files</Filter> + </ClInclude> + </ItemGroup> +</Project> \ No newline at end of file diff --git a/libsst-crypto/obj/x86-64/release/SST_Hash.o b/libsst-crypto/obj/x86-64/release/SST_Hash.o new file mode 100644 index 0000000000000000000000000000000000000000..e58ddee233312ddb60bfe941f87c581c73b66cd5 GIT binary patch literal 3472 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 literal 0 HcmV?d00001 diff --git a/libsst-glapi/GLAPIPrivate.h b/libsst-glapi/GLAPIPrivate.h new file mode 100644 index 0000000..95365ff --- /dev/null +++ b/libsst-glapi/GLAPIPrivate.h @@ -0,0 +1,59 @@ +/* + GLAPIPrivate.h + Author: Patrick Baggett <ptbaggett@762studios.com> + Created: 1/18/2013 + + Purpose: + + Private header for libsst-glapi. + Not to be distributed as part of public SDK + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ +#pragma once + +#ifndef _GLAPIPRIVATE_H +#define _GLAPIPRIVATE_H + +#include <pstdint.h> /* uintptr_t */ + +struct SST_GLAPI; + +typedef struct GLAPIResolver +{ + void* privateFields[2]; /* Platform dependent fields */ +} GLAPIResolver; + +/* THESE ARE PLATFORM SPECIFIC { */ + +/* Load libGL by name */ +void* openLibGL(const char* path); + +/* Close libGL by name */ +void closeLibGL(void* libGL); + +/* Get a resolver struct */ +int getResolver(void* oglLib, GLAPIResolver* resolver); + +/* Return default OpenGL library name for platform */ +const char* defaultLibGLName(); + +/* Resolve a GL symbol */ +void* resolveGLSymbol(const GLAPIResolver* resolver, const char* name); + +/* } END PLATFORM-SPECIFIC */ + +/* Resolve ALL GL symbols */ +void resolveGLAPI(const GLAPIResolver* resolver, struct SST_GLAPI* api); + + + +#endif + diff --git a/libsst-glapi/Makefile b/libsst-glapi/Makefile new file mode 100644 index 0000000..41eefe2 --- /dev/null +++ b/libsst-glapi/Makefile @@ -0,0 +1,53 @@ +# libsst-glapi/Makefile +# Author: Patrick Baggett <ptbaggett@762studios.com> +# Created: 12/12/2012 +# +# Purpose: +# +# Makefile for libsst-glapi +# +# License: +# +# This program is free software. It comes without any warranty, to +# the extent permitted by applicable law. You can redistribute it +# and/or modify it under the terms of the Do What The Fuck You Want +# To Public License, Version 2, as published by Sam Hocevar. See +# http://sam.zoy.org/wtfpl/COPYING for more details. + +BINNAME := $(DIST)/libsst-glapi.a +ifeq ($(TARGET),debug) + BINNAME := $(subst .a,_d.a, $(BINNAME)) +endif + +SRC := SST_GLAPIStruct.c \ + SST_GLAPIContext.c + +# Add platform specific code + +ifeq ($(OS),Darwin) + LIBGL_PLATFORM := MacOSX +else ifeq ($(SUBSYSTEM),Solaris) + LIBGL_PLATFORM := POSIX +else + LIBGL_PLATFORM := $(SUBSYSTEM) +endif + +include sources-$(LIBGL_PLATFORM).mk + +OBJ := $(addprefix obj/$(ARCH)/$(TARGET)/,$(subst .c,.o,$(SRC))) + +$(shell mkdir -p obj/$(ARCH)/$(TARGET)) + +$(BINNAME): $(OBJ) + $(AR) cru $@ $+ + $(RANLIB) $@ + + +# *.c files to *.o files +obj/$(ARCH)/$(TARGET)/%.o: %.c + @echo CC $@ + @$(CC) $(CFLAGS) -c $*.c -o obj/$(ARCH)/$(TARGET)/$*.o + +# CLEAN +clean: + @-rm -r -f obj $(DIST)/libsst-glapi*.a diff --git a/libsst-glapi/SST_GLAPIContext.c b/libsst-glapi/SST_GLAPIContext.c new file mode 100644 index 0000000..c0b3206 --- /dev/null +++ b/libsst-glapi/SST_GLAPIContext.c @@ -0,0 +1,228 @@ +/* + SST_GLAPIContext.c + Author: Patrick Baggett <ptbaggett@762studios.com> + Created: 12/12/2012 + + Purpose: + + GL API context init/shutdown + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ + +#include <SST/SST_GLAPI.h> +#include <stdlib.h> +#include <string.h> + +#include "GLAPIPrivate.h" + +/*************************************************************************/ + +/* Thread-local variable with GLAPI context */ +#ifdef _WIN32 + __declspec(thread) SST_GLAPI* __sstglctx = NULL; +#else + __thread SST_GLAPI* __sstglctx = NULL; +#endif + +/*************************************************************************/ + +/* strdup() implementation */ +static char* dupstr(const char* s); + +/* Unload libGL / libGL name, erase pointers */ +static void freeGLAPI(SST_GLAPI* api); + +/*************************************************************************/ + +int SST_GLAPI_InitForThread(const char* libGLName) +{ + SST_GLAPI* api = __sstglctx; + void* libGL; + char* libName; + GLAPIResolver resolver; + + /* + Generally, we need to: + 1) Open the libGL implementation + 2) Verify that this is in fact, an OpenGL implementation + 3) Resolve the OpenGL symbols + + We have to take care to unload the old libGL first, and + make sure to re-use the same SST_GLAPI value in the TLS + area. If no SST_GLAPI TLS value exists, create and store it. + */ + + /* Free any previous API in use */ + if(api != NULL) + freeGLAPI(api); + + /* No libGL name provided? */ + if(libGLName == NULL) + libGLName = defaultLibGLName(); /* Use default */ + + /* Duplicate the name of the library for future reference */ + libName = dupstr(libGLName); + if(libName == NULL) + return 0; + + /* Attempt to open libGL by name */ + libGL = openLibGL(libName); + if(libGL == NULL) + { + closeLibGL(libGL); + free(libName); + return 0; + } + + /* Get pointer to symbol resolving function. If this isn't a valid libGL + implementation, this will fail (e.g. specifying "libc.so.6" would fail here) */ + if(getResolver(libGL, &resolver) == 0) + { + closeLibGL(libGL); + free(libName); + return 0; + } + + /* No SST_GLAPI for this thread -- allocate it now */ + if(api == NULL) + { + api = (SST_GLAPI*)calloc(1, sizeof(SST_GLAPI)); + if(api == NULL) + { + closeLibGL(libGL); + free(libName); + return 0; + } + + /* Save API pointer */ + __sstglctx = api; + } + + /* Resolve all symbols and save libGL handle */ + resolveGLAPI(&resolver, api); + api->libGL = libGL; + api->libGLName = libName; + + return 1; +} + +/*************************************************************************/ + +void SST_GLAPI_ShutdownForThread() +{ + SST_GLAPI* api = __sstglctx; + + if(api != NULL) + { + freeGLAPI(api); + free(api); + __sstglctx = NULL; + } +} + +/*************************************************************************/ + +SST_GLAPI* SST_GLAPI_GetThreadGLAPI() +{ + return __sstglctx; +} + +/*************************************************************************/ + +int SST_GLAPI_CopyForThread(const SST_GLAPI* newapi) +{ + SST_GLAPI* api = __sstglctx; + void* libGL; + char* libGLName; + + if(newapi->libGL != NULL && newapi->libGLName != NULL) + { + /* Re-open libGL (to increment reference count) */ + libGL = openLibGL(newapi->libGLName); + if(libGL == NULL) + return 0; + + /* Duplicate libGL name */ + libGLName = dupstr(newapi->libGLName); + if(libGLName == NULL) + { + closeLibGL(libGL); + return 0; + } + } + else /* Not using a libGL implementation (e.g. user functions) */ + { + libGL = NULL; + libGLName = NULL; + } + + /* No previous API pointer? */ + if(api == NULL) + { + /* Allocate a new one */ + api = (SST_GLAPI*)calloc(1, sizeof(SST_GLAPI)); + if(api == NULL) + { + if(libGL != NULL) + closeLibGL(libGL); + if(libGLName != NULL) + free(libGLName); + return 0; + } + + /* Save API pointer */ + __sstglctx = api; + + } + + /* Copy API, but save the new libGL name and libGL handle */ + memcpy(api, newapi, sizeof(SST_GLAPI)); + api->libGL = libGL; + api->libGLName = libGLName; + + return 1; +} + +/*************************************************************************/ + +/* strdup() implementation */ +static char* dupstr(const char* s) +{ + size_t len; + char* copy; + + len = strlen(s); + copy = malloc(len+1); + if(copy == NULL) + return NULL; + + /* Copy whole string (including null terminator) */ + memcpy(copy, s, len+1); + + return copy; +} + +/*************************************************************************/ + +static void freeGLAPI(SST_GLAPI* api) +{ + /* Free name of library in use */ + if(api->libGLName) + free(api->libGLName); + + /* Close the library itself */ + if(api->libGL) + closeLibGL(api->libGL); + + /* In case we downgrade in GL version, erase previous pointers */ + memset(api, 0, sizeof(SST_GLAPI)); +} + diff --git a/libsst-glapi/SST_GLAPIResolve_MacOSX.c b/libsst-glapi/SST_GLAPIResolve_MacOSX.c new file mode 100644 index 0000000..af23d20 --- /dev/null +++ b/libsst-glapi/SST_GLAPIResolve_MacOSX.c @@ -0,0 +1,65 @@ +/* + SST_GLAPIResolve_MacOSX.c + Author: Patrick Baggett <ptbaggett@762studios.com> + Created: 4/16/2013 + + Purpose: + + Runtime OpenGL symbol resolution (MacOSX) + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ + +#include <dlfcn.h> +#include <string.h> +#include "GLAPIPrivate.h" + +/* Path to libGL by default */ +#define LIBGL_PATH "/System/Library/Frameworks/OpenGL.framework/libGL.dylib" + +/******************************************************************************/ + +void* openLibGL(const char* path) +{ + return dlopen(path, RTLD_GLOBAL | RTLD_NOW); +} + +/******************************************************************************/ + +void closeLibGL(void* libGL) +{ + dlclose(libGL); +} + +/******************************************************************************/ + +int getResolver(void* oglLib, GLAPIResolver* res) +{ + res->privateFields[0] = oglLib; + + return 1; +} + +/******************************************************************************/ + +const char* defaultLibGLName() +{ + return LIBGL_PATH; +} + +/******************************************************************************/ + +void* resolveGLSymbol(const GLAPIResolver* res, const char* name) +{ + return dlsym(res->privateFields[0], name); +} + +/******************************************************************************/ + diff --git a/libsst-glapi/SST_GLAPIResolve_POSIX.c b/libsst-glapi/SST_GLAPIResolve_POSIX.c new file mode 100644 index 0000000..5704318 --- /dev/null +++ b/libsst-glapi/SST_GLAPIResolve_POSIX.c @@ -0,0 +1,77 @@ +/* + SST_GLAPIResolve_Xlib.c + Author: Patrick Baggett <ptbaggett@762studios.com> + Created: 12/12/2012 + + Purpose: + + Runtime OpenGL symbol resolution (Xlib) + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ + +#include <dlfcn.h> +#include <string.h> +#include "GLAPIPrivate.h" + +typedef void* (*pf_glXGetProcAddressARB)(const char* symbol); + +typedef struct GLAPIResolver_Xlib +{ + pf_glXGetProcAddressARB pglXGetProcAddressARB; +} GLAPIResolver_Xlib; + +/******************************************************************************/ + +void* openLibGL(const char* path) +{ + return dlopen(path, RTLD_GLOBAL | RTLD_NOW); +} + +/******************************************************************************/ + +void closeLibGL(void* libGL) +{ + dlclose(libGL); +} + +/******************************************************************************/ + +int getResolver(void* oglLib, GLAPIResolver* res) +{ + GLAPIResolver_Xlib* resolver = (GLAPIResolver_Xlib*)res; + + resolver->pglXGetProcAddressARB = (pf_glXGetProcAddressARB)dlsym(oglLib, "glXGetProcAddressARB"); + + /* The -ARB variant doesn't exist? Try without */ + if(resolver->pglXGetProcAddressARB == NULL) + resolver->pglXGetProcAddressARB = (pf_glXGetProcAddressARB)dlsym(oglLib, "glXGetProcAddress"); + + return (resolver->pglXGetProcAddressARB != NULL); +} + +/******************************************************************************/ + +const char* defaultLibGLName() +{ + return "libGL.so.1"; +} + +/******************************************************************************/ + +void* resolveGLSymbol(const GLAPIResolver* res, const char* name) +{ + const GLAPIResolver_Xlib* resolver = (const GLAPIResolver_Xlib*)res; + + return resolver->pglXGetProcAddressARB(name); +} + +/******************************************************************************/ + diff --git a/libsst-glapi/SST_GLAPIResolve_Win32.c b/libsst-glapi/SST_GLAPIResolve_Win32.c new file mode 100644 index 0000000..3e87305 --- /dev/null +++ b/libsst-glapi/SST_GLAPIResolve_Win32.c @@ -0,0 +1,83 @@ +/* + SST_GLAPIResolve_Win32.c + Author: Patrick Baggett <ptbaggett@762studios.com> + Created: 12/12/2012 + + Purpose: + + Runtime OpenGL symbol resolution (Win32) + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ + +#include <windows.h> +#include "GLAPIPrivate.h" + +typedef void* (WINAPI*pf_wglGetProcAddress)(const char* symbol); + +typedef struct GLAPIResolver_Win32 +{ + pf_wglGetProcAddress pwglGetProcAddress; + HMODULE hDLL; +} GLAPIResolver_Win32; + +/*************************************************************************/ + +void* openLibGL(const char* path) +{ + return (void*)LoadLibraryA(path); +} + +/*************************************************************************/ + +void closeLibGL(void* libGL) +{ + FreeLibrary((HMODULE)libGL); +} + +/*************************************************************************/ + +int getResolver(void* oglLib, GLAPIResolver* res) +{ + HMODULE hDLL = (HMODULE)oglLib; + GLAPIResolver_Win32* resolver = (GLAPIResolver_Win32*)res; + + resolver->pwglGetProcAddress = (pf_wglGetProcAddress)GetProcAddress(hDLL, "wglGetProcAddress"); + resolver->hDLL = hDLL; + + return (resolver->pwglGetProcAddress != NULL); +} + +/*************************************************************************/ + +/* Return default OpenGL library name for platform */ +const char* defaultLibGLName() +{ + return "opengl32.dll"; +} + +/*************************************************************************/ + +void* resolveGLSymbol(const GLAPIResolver* res, const char* name) +{ + void* sym; + const GLAPIResolver_Win32* resolver = (const GLAPIResolver_Win32*)res; + + /* Try core (GL 1.1) symbol resolution first */ + sym = (void*)GetProcAddress(resolver->hDLL, name); + + /* If that fails, try wglGetProcAddress() for extension GL stuff */ + if(sym == NULL) + sym = resolver->pwglGetProcAddress(name); + + return sym; +} + +/*************************************************************************/ diff --git a/libsst-glapi/SST_GLAPIStruct.c b/libsst-glapi/SST_GLAPIStruct.c new file mode 100644 index 0000000..d5e2f85 --- /dev/null +++ b/libsst-glapi/SST_GLAPIStruct.c @@ -0,0 +1,335 @@ +/* AUTOGENERATED BY parsegl.c -- DO NOT MODIFY */ +#include <SST/SST_GLAPIStruct.h> +#include "GLAPIPrivate.h" + +void resolveGLAPI(const GLAPIResolver* resolver, struct SST_GLAPI* api) +{ + api->ActiveTexture = resolveGLSymbol(resolver, "glActiveTexture"); + api->AttachShader = resolveGLSymbol(resolver, "glAttachShader"); + api->BeginConditionalRender = resolveGLSymbol(resolver, "glBeginConditionalRender"); + api->BeginQuery = resolveGLSymbol(resolver, "glBeginQuery"); + api->BeginTransformFeedback = resolveGLSymbol(resolver, "glBeginTransformFeedback"); + api->BindAttribLocation = resolveGLSymbol(resolver, "glBindAttribLocation"); + api->BindBuffer = resolveGLSymbol(resolver, "glBindBuffer"); + api->BindBufferBase = resolveGLSymbol(resolver, "glBindBufferBase"); + api->BindBufferRange = resolveGLSymbol(resolver, "glBindBufferRange"); + api->BindFragDataLocation = resolveGLSymbol(resolver, "glBindFragDataLocation"); + api->BindFragDataLocationIndexed = resolveGLSymbol(resolver, "glBindFragDataLocationIndexed"); + api->BindFramebuffer = resolveGLSymbol(resolver, "glBindFramebuffer"); + api->BindRenderbuffer = resolveGLSymbol(resolver, "glBindRenderbuffer"); + api->BindSampler = resolveGLSymbol(resolver, "glBindSampler"); + api->BindTexture = resolveGLSymbol(resolver, "glBindTexture"); + api->BindVertexArray = resolveGLSymbol(resolver, "glBindVertexArray"); + api->BlendColor = resolveGLSymbol(resolver, "glBlendColor"); + api->BlendEquation = resolveGLSymbol(resolver, "glBlendEquation"); + api->BlendEquationSeparate = resolveGLSymbol(resolver, "glBlendEquationSeparate"); + api->BlendFunc = resolveGLSymbol(resolver, "glBlendFunc"); + api->BlendFuncSeparate = resolveGLSymbol(resolver, "glBlendFuncSeparate"); + api->BlitFramebuffer = resolveGLSymbol(resolver, "glBlitFramebuffer"); + api->BufferData = resolveGLSymbol(resolver, "glBufferData"); + api->BufferSubData = resolveGLSymbol(resolver, "glBufferSubData"); + api->CheckFramebufferStatus = resolveGLSymbol(resolver, "glCheckFramebufferStatus"); + api->ClampColor = resolveGLSymbol(resolver, "glClampColor"); + api->Clear = resolveGLSymbol(resolver, "glClear"); + api->ClearBufferiv = resolveGLSymbol(resolver, "glClearBufferiv"); + api->ClearBufferuiv = resolveGLSymbol(resolver, "glClearBufferuiv"); + api->ClearBufferfv = resolveGLSymbol(resolver, "glClearBufferfv"); + api->ClearBufferfi = resolveGLSymbol(resolver, "glClearBufferfi"); + api->ClearColor = resolveGLSymbol(resolver, "glClearColor"); + api->ClearDepth = resolveGLSymbol(resolver, "glClearDepth"); + api->ClearStencil = resolveGLSymbol(resolver, "glClearStencil"); + api->ClientWaitSync = resolveGLSymbol(resolver, "glClientWaitSync"); + api->ColorMask = resolveGLSymbol(resolver, "glColorMask"); + api->ColorMaski = resolveGLSymbol(resolver, "glColorMaski"); + api->CompileShader = resolveGLSymbol(resolver, "glCompileShader"); + api->CompressedTexImage1D = resolveGLSymbol(resolver, "glCompressedTexImage1D"); + api->CompressedTexImage2D = resolveGLSymbol(resolver, "glCompressedTexImage2D"); + api->CompressedTexImage3D = resolveGLSymbol(resolver, "glCompressedTexImage3D"); + api->CompressedTexSubImage1D = resolveGLSymbol(resolver, "glCompressedTexSubImage1D"); + api->CompressedTexSubImage2D = resolveGLSymbol(resolver, "glCompressedTexSubImage2D"); + api->CompressedTexSubImage3D = resolveGLSymbol(resolver, "glCompressedTexSubImage3D"); + api->CopyBufferSubData = resolveGLSymbol(resolver, "glCopyBufferSubData"); + api->CopyTexImage1D = resolveGLSymbol(resolver, "glCopyTexImage1D"); + api->CopyTexImage2D = resolveGLSymbol(resolver, "glCopyTexImage2D"); + api->CopyTexSubImage1D = resolveGLSymbol(resolver, "glCopyTexSubImage1D"); + api->CopyTexSubImage2D = resolveGLSymbol(resolver, "glCopyTexSubImage2D"); + api->CopyTexSubImage3D = resolveGLSymbol(resolver, "glCopyTexSubImage3D"); + api->CreateProgram = resolveGLSymbol(resolver, "glCreateProgram"); + api->CreateShader = resolveGLSymbol(resolver, "glCreateShader"); + api->CullFace = resolveGLSymbol(resolver, "glCullFace"); + api->DeleteBuffers = resolveGLSymbol(resolver, "glDeleteBuffers"); + api->DeleteFramebuffers = resolveGLSymbol(resolver, "glDeleteFramebuffers"); + api->DeleteProgram = resolveGLSymbol(resolver, "glDeleteProgram"); + api->DeleteQueries = resolveGLSymbol(resolver, "glDeleteQueries"); + api->DeleteRenderbuffers = resolveGLSymbol(resolver, "glDeleteRenderbuffers"); + api->DeleteSamplers = resolveGLSymbol(resolver, "glDeleteSamplers"); + api->DeleteShader = resolveGLSymbol(resolver, "glDeleteShader"); + api->DeleteSync = resolveGLSymbol(resolver, "glDeleteSync"); + api->DeleteTextures = resolveGLSymbol(resolver, "glDeleteTextures"); + api->DeleteVertexArrays = resolveGLSymbol(resolver, "glDeleteVertexArrays"); + api->DepthFunc = resolveGLSymbol(resolver, "glDepthFunc"); + api->DepthMask = resolveGLSymbol(resolver, "glDepthMask"); + api->DepthRange = resolveGLSymbol(resolver, "glDepthRange"); + api->DetachShader = resolveGLSymbol(resolver, "glDetachShader"); + api->Disable = resolveGLSymbol(resolver, "glDisable"); + api->DisableVertexAttribArray = resolveGLSymbol(resolver, "glDisableVertexAttribArray"); + api->Disablei = resolveGLSymbol(resolver, "glDisablei"); + api->DrawArrays = resolveGLSymbol(resolver, "glDrawArrays"); + api->DrawArraysInstanced = resolveGLSymbol(resolver, "glDrawArraysInstanced"); + api->DrawBuffer = resolveGLSymbol(resolver, "glDrawBuffer"); + api->DrawBuffers = resolveGLSymbol(resolver, "glDrawBuffers"); + api->DrawElements = resolveGLSymbol(resolver, "glDrawElements"); + api->DrawElementsBaseVertex = resolveGLSymbol(resolver, "glDrawElementsBaseVertex"); + api->DrawElementsInstanced = resolveGLSymbol(resolver, "glDrawElementsInstanced"); + api->DrawElementsInstancedBaseVertex = resolveGLSymbol(resolver, "glDrawElementsInstancedBaseVertex"); + api->DrawRangeElements = resolveGLSymbol(resolver, "glDrawRangeElements"); + api->DrawRangeElementsBaseVertex = resolveGLSymbol(resolver, "glDrawRangeElementsBaseVertex"); + api->Enable = resolveGLSymbol(resolver, "glEnable"); + api->EnableVertexAttribArray = resolveGLSymbol(resolver, "glEnableVertexAttribArray"); + api->Enablei = resolveGLSymbol(resolver, "glEnablei"); + api->EndQuery = resolveGLSymbol(resolver, "glEndQuery"); + api->EndTransformFeedback = resolveGLSymbol(resolver, "glEndTransformFeedback"); + api->FenceSync = resolveGLSymbol(resolver, "glFenceSync"); + api->Finish = resolveGLSymbol(resolver, "glFinish"); + api->Flush = resolveGLSymbol(resolver, "glFlush"); + api->FlushMappedBufferRange = resolveGLSymbol(resolver, "glFlushMappedBufferRange"); + api->FramebufferRenderbuffer = resolveGLSymbol(resolver, "glFramebufferRenderbuffer"); + api->FramebufferTexture = resolveGLSymbol(resolver, "glFramebufferTexture"); + api->FramebufferTexture1D = resolveGLSymbol(resolver, "glFramebufferTexture1D"); + api->FramebufferTexture2D = resolveGLSymbol(resolver, "glFramebufferTexture2D"); + api->FramebufferTexture3D = resolveGLSymbol(resolver, "glFramebufferTexture3D"); + api->FramebufferTextureLayer = resolveGLSymbol(resolver, "glFramebufferTextureLayer"); + api->FrontFace = resolveGLSymbol(resolver, "glFrontFace"); + api->GenBuffers = resolveGLSymbol(resolver, "glGenBuffers"); + api->GenFramebuffers = resolveGLSymbol(resolver, "glGenFramebuffers"); + api->GenQueries = resolveGLSymbol(resolver, "glGenQueries"); + api->GenRenderbuffers = resolveGLSymbol(resolver, "glGenRenderbuffers"); + api->GenSamplers = resolveGLSymbol(resolver, "glGenSamplers"); + api->GenTextures = resolveGLSymbol(resolver, "glGenTextures"); + api->GenVertexArrays = resolveGLSymbol(resolver, "glGenVertexArrays"); + api->GenerateMipmap = resolveGLSymbol(resolver, "glGenerateMipmap"); + api->GetBooleanv = resolveGLSymbol(resolver, "glGetBooleanv"); + api->GetDoublev = resolveGLSymbol(resolver, "glGetDoublev"); + api->GetFloatv = resolveGLSymbol(resolver, "glGetFloatv"); + api->GetIntegerv = resolveGLSymbol(resolver, "glGetIntegerv"); + api->GetInteger64v = resolveGLSymbol(resolver, "glGetInteger64v"); + api->GetActiveAttrib = resolveGLSymbol(resolver, "glGetActiveAttrib"); + api->GetActiveUniform = resolveGLSymbol(resolver, "glGetActiveUniform"); + api->GetActiveUniformBlockiv = resolveGLSymbol(resolver, "glGetActiveUniformBlockiv"); + api->GetActiveUniformBlockName = resolveGLSymbol(resolver, "glGetActiveUniformBlockName"); + api->GetActiveUniformName = resolveGLSymbol(resolver, "glGetActiveUniformName"); + api->GetActiveUniformsiv = resolveGLSymbol(resolver, "glGetActiveUniformsiv"); + api->GetAttachedShaders = resolveGLSymbol(resolver, "glGetAttachedShaders"); + api->GetAttribLocation = resolveGLSymbol(resolver, "glGetAttribLocation"); + api->GetBufferParameteriv = resolveGLSymbol(resolver, "glGetBufferParameteriv"); + api->GetBufferPointerv = resolveGLSymbol(resolver, "glGetBufferPointerv"); + api->GetBufferSubData = resolveGLSymbol(resolver, "glGetBufferSubData"); + api->GetCompressedTexImage = resolveGLSymbol(resolver, "glGetCompressedTexImage"); + api->GetError = resolveGLSymbol(resolver, "glGetError"); + api->GetFragDataIndex = resolveGLSymbol(resolver, "glGetFragDataIndex"); + api->GetFragDataLocation = resolveGLSymbol(resolver, "glGetFragDataLocation"); + api->GetFramebufferAttachmentParameteriv = resolveGLSymbol(resolver, "glGetFramebufferAttachmentParameteriv"); + api->GetMultisamplefv = resolveGLSymbol(resolver, "glGetMultisamplefv"); + api->GetProgramiv = resolveGLSymbol(resolver, "glGetProgramiv"); + api->GetProgramInfoLog = resolveGLSymbol(resolver, "glGetProgramInfoLog"); + api->GetQueryObjectiv = resolveGLSymbol(resolver, "glGetQueryObjectiv"); + api->GetQueryObjectuiv = resolveGLSymbol(resolver, "glGetQueryObjectuiv"); + api->GetQueryObjecti64v = resolveGLSymbol(resolver, "glGetQueryObjecti64v"); + api->GetQueryObjectui64v = resolveGLSymbol(resolver, "glGetQueryObjectui64v"); + api->GetQueryiv = resolveGLSymbol(resolver, "glGetQueryiv"); + api->GetRenderbufferParameteriv = resolveGLSymbol(resolver, "glGetRenderbufferParameteriv"); + api->GetSamplerParameterfv = resolveGLSymbol(resolver, "glGetSamplerParameterfv"); + api->GetSamplerParameteriv = resolveGLSymbol(resolver, "glGetSamplerParameteriv"); + api->GetShaderiv = resolveGLSymbol(resolver, "glGetShaderiv"); + api->GetShaderInfoLog = resolveGLSymbol(resolver, "glGetShaderInfoLog"); + api->GetShaderSource = resolveGLSymbol(resolver, "glGetShaderSource"); + api->GetString = resolveGLSymbol(resolver, "glGetString"); + api->GetStringi = resolveGLSymbol(resolver, "glGetStringi"); + api->GetSynciv = resolveGLSymbol(resolver, "glGetSynciv"); + api->GetTexImage = resolveGLSymbol(resolver, "glGetTexImage"); + api->GetTexLevelParameterfv = resolveGLSymbol(resolver, "glGetTexLevelParameterfv"); + api->GetTexLevelParameteriv = resolveGLSymbol(resolver, "glGetTexLevelParameteriv"); + api->GetTexParameterfv = resolveGLSymbol(resolver, "glGetTexParameterfv"); + api->GetTexParameteriv = resolveGLSymbol(resolver, "glGetTexParameteriv"); + api->GetTransformFeedbackVarying = resolveGLSymbol(resolver, "glGetTransformFeedbackVarying"); + api->GetUniformfv = resolveGLSymbol(resolver, "glGetUniformfv"); + api->GetUniformiv = resolveGLSymbol(resolver, "glGetUniformiv"); + api->GetUniformIndices = resolveGLSymbol(resolver, "glGetUniformIndices"); + api->GetUniformLocation = resolveGLSymbol(resolver, "glGetUniformLocation"); + api->GetVertexAttribdv = resolveGLSymbol(resolver, "glGetVertexAttribdv"); + api->GetVertexAttribfv = resolveGLSymbol(resolver, "glGetVertexAttribfv"); + api->GetVertexAttribiv = resolveGLSymbol(resolver, "glGetVertexAttribiv"); + api->GetVertexAttribIiv = resolveGLSymbol(resolver, "glGetVertexAttribIiv"); + api->GetVertexAttribIuiv = resolveGLSymbol(resolver, "glGetVertexAttribIuiv"); + api->GetVertexAttribPointerv = resolveGLSymbol(resolver, "glGetVertexAttribPointerv"); + api->Hint = resolveGLSymbol(resolver, "glHint"); + api->IsBuffer = resolveGLSymbol(resolver, "glIsBuffer"); + api->IsEnabled = resolveGLSymbol(resolver, "glIsEnabled"); + api->IsEnabledi = resolveGLSymbol(resolver, "glIsEnabledi"); + api->IsFramebuffer = resolveGLSymbol(resolver, "glIsFramebuffer"); + api->IsProgram = resolveGLSymbol(resolver, "glIsProgram"); + api->IsQuery = resolveGLSymbol(resolver, "glIsQuery"); + api->IsRenderbuffer = resolveGLSymbol(resolver, "glIsRenderbuffer"); + api->IsSampler = resolveGLSymbol(resolver, "glIsSampler"); + api->IsShader = resolveGLSymbol(resolver, "glIsShader"); + api->IsSync = resolveGLSymbol(resolver, "glIsSync"); + api->IsTexture = resolveGLSymbol(resolver, "glIsTexture"); + api->IsVertexArray = resolveGLSymbol(resolver, "glIsVertexArray"); + api->LineWidth = resolveGLSymbol(resolver, "glLineWidth"); + api->LinkProgram = resolveGLSymbol(resolver, "glLinkProgram"); + api->LogicOp = resolveGLSymbol(resolver, "glLogicOp"); + api->MapBuffer = resolveGLSymbol(resolver, "glMapBuffer"); + api->MapBufferRange = resolveGLSymbol(resolver, "glMapBufferRange"); + api->MultiDrawArrays = resolveGLSymbol(resolver, "glMultiDrawArrays"); + api->MultiDrawElements = resolveGLSymbol(resolver, "glMultiDrawElements"); + api->MultiDrawElementsBaseVertex = resolveGLSymbol(resolver, "glMultiDrawElementsBaseVertex"); + api->PixelStoref = resolveGLSymbol(resolver, "glPixelStoref"); + api->PixelStorei = resolveGLSymbol(resolver, "glPixelStorei"); + api->PointParameterf = resolveGLSymbol(resolver, "glPointParameterf"); + api->PointParameteri = resolveGLSymbol(resolver, "glPointParameteri"); + api->PointSize = resolveGLSymbol(resolver, "glPointSize"); + api->PolygonMode = resolveGLSymbol(resolver, "glPolygonMode"); + api->PolygonOffset = resolveGLSymbol(resolver, "glPolygonOffset"); + api->PrimitiveRestartIndex = resolveGLSymbol(resolver, "glPrimitiveRestartIndex"); + api->ProvokingVertex = resolveGLSymbol(resolver, "glProvokingVertex"); + api->QueryCounter = resolveGLSymbol(resolver, "glQueryCounter"); + api->ReadBuffer = resolveGLSymbol(resolver, "glReadBuffer"); + api->ReadPixels = resolveGLSymbol(resolver, "glReadPixels"); + api->RenderbufferStorage = resolveGLSymbol(resolver, "glRenderbufferStorage"); + api->RenderbufferStorageMultisample = resolveGLSymbol(resolver, "glRenderbufferStorageMultisample"); + api->SampleCoverage = resolveGLSymbol(resolver, "glSampleCoverage"); + api->SampleMaski = resolveGLSymbol(resolver, "glSampleMaski"); + api->SamplerParameterf = resolveGLSymbol(resolver, "glSamplerParameterf"); + api->SamplerParameteri = resolveGLSymbol(resolver, "glSamplerParameteri"); + api->SamplerParameterfv = resolveGLSymbol(resolver, "glSamplerParameterfv"); + api->SamplerParameteriv = resolveGLSymbol(resolver, "glSamplerParameteriv"); + api->SamplerParameterIiv = resolveGLSymbol(resolver, "glSamplerParameterIiv"); + api->SamplerParameterIuiv = resolveGLSymbol(resolver, "glSamplerParameterIuiv"); + api->Scissor = resolveGLSymbol(resolver, "glScissor"); + api->ShaderSource = resolveGLSymbol(resolver, "glShaderSource"); + api->StencilFunc = resolveGLSymbol(resolver, "glStencilFunc"); + api->StencilFuncSeparate = resolveGLSymbol(resolver, "glStencilFuncSeparate"); + api->StencilMask = resolveGLSymbol(resolver, "glStencilMask"); + api->StencilMaskSeparate = resolveGLSymbol(resolver, "glStencilMaskSeparate"); + api->StencilOp = resolveGLSymbol(resolver, "glStencilOp"); + api->StencilOpSeparate = resolveGLSymbol(resolver, "glStencilOpSeparate"); + api->TexBuffer = resolveGLSymbol(resolver, "glTexBuffer"); + api->TexImage1D = resolveGLSymbol(resolver, "glTexImage1D"); + api->TexImage2D = resolveGLSymbol(resolver, "glTexImage2D"); + api->TexImage2DMultisample = resolveGLSymbol(resolver, "glTexImage2DMultisample"); + api->TexImage3D = resolveGLSymbol(resolver, "glTexImage3D"); + api->TexImage3DMultisample = resolveGLSymbol(resolver, "glTexImage3DMultisample"); + api->TexParameterf = resolveGLSymbol(resolver, "glTexParameterf"); + api->TexParameteri = resolveGLSymbol(resolver, "glTexParameteri"); + api->TexParameterfv = resolveGLSymbol(resolver, "glTexParameterfv"); + api->TexParameteriv = resolveGLSymbol(resolver, "glTexParameteriv"); + api->TexParameterIiv = resolveGLSymbol(resolver, "glTexParameterIiv"); + api->TexParameterIuiv = resolveGLSymbol(resolver, "glTexParameterIuiv"); + api->TexSubImage1D = resolveGLSymbol(resolver, "glTexSubImage1D"); + api->TexSubImage2D = resolveGLSymbol(resolver, "glTexSubImage2D"); + api->TexSubImage3D = resolveGLSymbol(resolver, "glTexSubImage3D"); + api->TransformFeedbackVaryings = resolveGLSymbol(resolver, "glTransformFeedbackVaryings"); + api->Uniform1f = resolveGLSymbol(resolver, "glUniform1f"); + api->Uniform2f = resolveGLSymbol(resolver, "glUniform2f"); + api->Uniform3f = resolveGLSymbol(resolver, "glUniform3f"); + api->Uniform4f = resolveGLSymbol(resolver, "glUniform4f"); + api->Uniform1i = resolveGLSymbol(resolver, "glUniform1i"); + api->Uniform2i = resolveGLSymbol(resolver, "glUniform2i"); + api->Uniform3i = resolveGLSymbol(resolver, "glUniform3i"); + api->Uniform4i = resolveGLSymbol(resolver, "glUniform4i"); + api->Uniform1ui = resolveGLSymbol(resolver, "glUniform1ui"); + api->Uniform2ui = resolveGLSymbol(resolver, "glUniform2ui"); + api->Uniform3ui = resolveGLSymbol(resolver, "glUniform3ui"); + api->Uniform4ui = resolveGLSymbol(resolver, "glUniform4ui"); + api->Uniform1fv = resolveGLSymbol(resolver, "glUniform1fv"); + api->Uniform2fv = resolveGLSymbol(resolver, "glUniform2fv"); + api->Uniform3fv = resolveGLSymbol(resolver, "glUniform3fv"); + api->Uniform4fv = resolveGLSymbol(resolver, "glUniform4fv"); + api->Uniform1iv = resolveGLSymbol(resolver, "glUniform1iv"); + api->Uniform2iv = resolveGLSymbol(resolver, "glUniform2iv"); + api->Uniform3iv = resolveGLSymbol(resolver, "glUniform3iv"); + api->Uniform4iv = resolveGLSymbol(resolver, "glUniform4iv"); + api->Uniform1uiv = resolveGLSymbol(resolver, "glUniform1uiv"); + api->Uniform2uiv = resolveGLSymbol(resolver, "glUniform2uiv"); + api->Uniform3uiv = resolveGLSymbol(resolver, "glUniform3uiv"); + api->Uniform4uiv = resolveGLSymbol(resolver, "glUniform4uiv"); + api->UniformMatrix2fv = resolveGLSymbol(resolver, "glUniformMatrix2fv"); + api->UniformMatrix3fv = resolveGLSymbol(resolver, "glUniformMatrix3fv"); + api->UniformMatrix4fv = resolveGLSymbol(resolver, "glUniformMatrix4fv"); + api->UniformMatrix2x3fv = resolveGLSymbol(resolver, "glUniformMatrix2x3fv"); + api->UniformMatrix3x2fv = resolveGLSymbol(resolver, "glUniformMatrix3x2fv"); + api->UniformMatrix2x4fv = resolveGLSymbol(resolver, "glUniformMatrix2x4fv"); + api->UniformMatrix4x2fv = resolveGLSymbol(resolver, "glUniformMatrix4x2fv"); + api->UniformMatrix3x4fv = resolveGLSymbol(resolver, "glUniformMatrix3x4fv"); + api->UniformMatrix4x3fv = resolveGLSymbol(resolver, "glUniformMatrix4x3fv"); + api->UniformBlockBinding = resolveGLSymbol(resolver, "glUniformBlockBinding"); + api->UnmapBuffer = resolveGLSymbol(resolver, "glUnmapBuffer"); + api->UseProgram = resolveGLSymbol(resolver, "glUseProgram"); + api->ValidateProgram = resolveGLSymbol(resolver, "glValidateProgram"); + api->VertexAttrib1f = resolveGLSymbol(resolver, "glVertexAttrib1f"); + api->VertexAttrib1s = resolveGLSymbol(resolver, "glVertexAttrib1s"); + api->VertexAttrib1d = resolveGLSymbol(resolver, "glVertexAttrib1d"); + api->VertexAttribI1i = resolveGLSymbol(resolver, "glVertexAttribI1i"); + api->VertexAttribI1ui = resolveGLSymbol(resolver, "glVertexAttribI1ui"); + api->VertexAttrib2f = resolveGLSymbol(resolver, "glVertexAttrib2f"); + api->VertexAttrib2s = resolveGLSymbol(resolver, "glVertexAttrib2s"); + api->VertexAttrib2d = resolveGLSymbol(resolver, "glVertexAttrib2d"); + api->VertexAttribI2i = resolveGLSymbol(resolver, "glVertexAttribI2i"); + api->VertexAttribI2ui = resolveGLSymbol(resolver, "glVertexAttribI2ui"); + api->VertexAttrib3f = resolveGLSymbol(resolver, "glVertexAttrib3f"); + api->VertexAttrib3s = resolveGLSymbol(resolver, "glVertexAttrib3s"); + api->VertexAttrib3d = resolveGLSymbol(resolver, "glVertexAttrib3d"); + api->VertexAttribI3i = resolveGLSymbol(resolver, "glVertexAttribI3i"); + api->VertexAttribI3ui = resolveGLSymbol(resolver, "glVertexAttribI3ui"); + api->VertexAttrib4f = resolveGLSymbol(resolver, "glVertexAttrib4f"); + api->VertexAttrib4s = resolveGLSymbol(resolver, "glVertexAttrib4s"); + api->VertexAttrib4d = resolveGLSymbol(resolver, "glVertexAttrib4d"); + api->VertexAttrib4Nub = resolveGLSymbol(resolver, "glVertexAttrib4Nub"); + api->VertexAttribI4i = resolveGLSymbol(resolver, "glVertexAttribI4i"); + api->VertexAttribI4ui = resolveGLSymbol(resolver, "glVertexAttribI4ui"); + api->VertexAttrib1fv = resolveGLSymbol(resolver, "glVertexAttrib1fv"); + api->VertexAttrib1sv = resolveGLSymbol(resolver, "glVertexAttrib1sv"); + api->VertexAttrib1dv = resolveGLSymbol(resolver, "glVertexAttrib1dv"); + api->VertexAttribI1iv = resolveGLSymbol(resolver, "glVertexAttribI1iv"); + api->VertexAttribI1uiv = resolveGLSymbol(resolver, "glVertexAttribI1uiv"); + api->VertexAttrib2fv = resolveGLSymbol(resolver, "glVertexAttrib2fv"); + api->VertexAttrib2sv = resolveGLSymbol(resolver, "glVertexAttrib2sv"); + api->VertexAttrib2dv = resolveGLSymbol(resolver, "glVertexAttrib2dv"); + api->VertexAttribI2iv = resolveGLSymbol(resolver, "glVertexAttribI2iv"); + api->VertexAttribI2uiv = resolveGLSymbol(resolver, "glVertexAttribI2uiv"); + api->VertexAttrib3fv = resolveGLSymbol(resolver, "glVertexAttrib3fv"); + api->VertexAttrib3sv = resolveGLSymbol(resolver, "glVertexAttrib3sv"); + api->VertexAttrib3dv = resolveGLSymbol(resolver, "glVertexAttrib3dv"); + api->VertexAttribI3iv = resolveGLSymbol(resolver, "glVertexAttribI3iv"); + api->VertexAttribI3uiv = resolveGLSymbol(resolver, "glVertexAttribI3uiv"); + api->VertexAttrib4fv = resolveGLSymbol(resolver, "glVertexAttrib4fv"); + api->VertexAttrib4sv = resolveGLSymbol(resolver, "glVertexAttrib4sv"); + api->VertexAttrib4dv = resolveGLSymbol(resolver, "glVertexAttrib4dv"); + api->VertexAttrib4iv = resolveGLSymbol(resolver, "glVertexAttrib4iv"); + api->VertexAttrib4bv = resolveGLSymbol(resolver, "glVertexAttrib4bv"); + api->VertexAttrib4ubv = resolveGLSymbol(resolver, "glVertexAttrib4ubv"); + api->VertexAttrib4usv = resolveGLSymbol(resolver, "glVertexAttrib4usv"); + api->VertexAttrib4uiv = resolveGLSymbol(resolver, "glVertexAttrib4uiv"); + api->VertexAttrib4Nbv = resolveGLSymbol(resolver, "glVertexAttrib4Nbv"); + api->VertexAttrib4Nsv = resolveGLSymbol(resolver, "glVertexAttrib4Nsv"); + api->VertexAttrib4Niv = resolveGLSymbol(resolver, "glVertexAttrib4Niv"); + api->VertexAttrib4Nubv = resolveGLSymbol(resolver, "glVertexAttrib4Nubv"); + api->VertexAttrib4Nusv = resolveGLSymbol(resolver, "glVertexAttrib4Nusv"); + api->VertexAttrib4Nuiv = resolveGLSymbol(resolver, "glVertexAttrib4Nuiv"); + api->VertexAttribI4bv = resolveGLSymbol(resolver, "glVertexAttribI4bv"); + api->VertexAttribI4ubv = resolveGLSymbol(resolver, "glVertexAttribI4ubv"); + api->VertexAttribI4sv = resolveGLSymbol(resolver, "glVertexAttribI4sv"); + api->VertexAttribI4usv = resolveGLSymbol(resolver, "glVertexAttribI4usv"); + api->VertexAttribI4iv = resolveGLSymbol(resolver, "glVertexAttribI4iv"); + api->VertexAttribI4uiv = resolveGLSymbol(resolver, "glVertexAttribI4uiv"); + api->VertexAttribP1ui = resolveGLSymbol(resolver, "glVertexAttribP1ui"); + api->VertexAttribP2ui = resolveGLSymbol(resolver, "glVertexAttribP2ui"); + api->VertexAttribP3ui = resolveGLSymbol(resolver, "glVertexAttribP3ui"); + api->VertexAttribP4ui = resolveGLSymbol(resolver, "glVertexAttribP4ui"); + api->VertexAttribDivisor = resolveGLSymbol(resolver, "glVertexAttribDivisor"); + api->VertexAttribPointer = resolveGLSymbol(resolver, "glVertexAttribPointer"); + api->VertexAttribIPointer = resolveGLSymbol(resolver, "glVertexAttribIPointer"); + api->Viewport = resolveGLSymbol(resolver, "glViewport"); + api->WaitSync = resolveGLSymbol(resolver, "glWaitSync"); + +} diff --git a/libsst-glapi/gl33.txt b/libsst-glapi/gl33.txt new file mode 100644 index 0000000..d39daf2 --- /dev/null +++ b/libsst-glapi/gl33.txt @@ -0,0 +1,388 @@ +// gl33.txt +// Author: Patrick Baggett <ptbaggett@762studios.com> +// Created: 12/12/2012 +// +// Purpose: +// +// OpenGL 3.3 function definitions +// +// License: +// +// This program is free software. It comes without any warranty, to +// the extent permitted by applicable law. You can redistribute it +// and/or modify it under the terms of the Do What The Fuck You Want +// To Public License, Version 2, as published by Sam Hocevar. See +// http://sam.zoy.org/wtfpl/COPYING for more details. + +// --A-- +void ActiveTexture GLenum +void AttachShader GLuint GLuint + +// --B-- +void BeginConditionalRender GLuint GLenum +void BeginQuery GLenum GLuint +void BeginTransformFeedback GLenum +void BindAttribLocation GLuint GLuint const_GLchar* +void BindBuffer GLenum GLuint +void BindBufferBase GLenum GLuint GLuint +void BindBufferRange GLenum GLuint GLuint GLintptr GLsizeiptr +void BindFragDataLocation GLuint GLuint const_GLchar* +void BindFragDataLocationIndexed GLuint GLuint GLuint const_GLchar* +void BindFramebuffer GLenum GLuint +void BindRenderbuffer GLenum GLuint +void BindSampler GLuint GLuint +void BindTexture GLenum GLuint +void BindVertexArray GLuint +void BlendColor GLclampf GLclampf GLclampf GLclampf +void BlendEquation GLenum +void BlendEquationSeparate GLenum GLenum +void BlendFunc GLenum GLenum +void BlendFuncSeparate GLenum GLenum GLenum GLenum +void BlitFramebuffer GLint GLint GLint GLint GLint GLint GLint GLint GLbitfield GLenum +void BufferData GLenum GLsizeiptr const_GLvoid* GLenum +void BufferSubData GLenum GLintptr GLsizeiptr const_GLvoid* + +// --C-- +GLenum CheckFramebufferStatus GLenum +void ClampColor GLenum GLenum +void Clear GLbitfield +void ClearBufferiv GLenum GLint const_GLint* +void ClearBufferuiv GLenum GLint const_GLuint* +void ClearBufferfv GLenum GLint const_GLfloat* +void ClearBufferfi GLenum GLint GLfloat GLint +void ClearColor GLclampf GLclampf GLclampf GLclampf +void ClearDepth GLclampd +void ClearStencil GLint +GLenum ClientWaitSync GLsync GLbitfield GLuint64 +void ColorMask GLboolean GLboolean GLboolean GLboolean +void ColorMaski GLuint GLboolean GLboolean GLboolean GLboolean +void CompileShader GLuint +void CompressedTexImage1D GLenum GLint GLenum GLsizei GLint GLsizei const_GLvoid* +void CompressedTexImage2D GLenum GLint GLenum GLsizei GLsizei GLint GLsizei const_GLvoid* +void CompressedTexImage3D GLenum GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const_GLvoid* +void CompressedTexSubImage1D GLenum GLint GLint GLsizei GLenum GLsizei const_GLvoid* +void CompressedTexSubImage2D GLenum GLint GLint GLint GLsizei GLsizei GLenum GLsizei const_GLvoid* +void CompressedTexSubImage3D GLenum GLint GLint GLint GLint GLsizei GLsizei GLsizei GLenum GLsizei const_GLvoid* +void CopyBufferSubData GLenum GLenum GLintptr GLintptr GLsizeiptr +void CopyTexImage1D GLenum GLint GLenum GLint GLint GLsizei GLint +void CopyTexImage2D GLenum GLint GLenum GLint GLint GLsizei GLsizei GLint +void CopyTexSubImage1D GLenum GLint GLint GLint GLint GLsizei +void CopyTexSubImage2D GLenum GLint GLint GLint GLint GLint GLsizei GLsizei +void CopyTexSubImage3D GLenum GLint GLint GLint GLint GLint GLint GLsizei GLsizei +GLuint CreateProgram +GLuint CreateShader GLenum +void CullFace GLenum + +// --D-- +void DeleteBuffers GLsizei const_GLuint* +void DeleteFramebuffers GLsizei GLuint* +void DeleteProgram GLuint +void DeleteQueries GLsizei const_GLuint* +void DeleteRenderbuffers GLsizei GLuint* +void DeleteSamplers GLsizei const_GLuint* +void DeleteShader GLuint +void DeleteSync GLsync +void DeleteTextures GLsizei const_GLuint* +void DeleteVertexArrays GLsizei const_GLuint* +void DepthFunc GLenum +void DepthMask GLboolean +void DepthRange GLclampd GLclampd +void DetachShader GLuint GLuint +void Disable GLenum +void DisableVertexAttribArray GLuint +void Disablei GLenum GLuint +void DrawArrays GLenum GLint GLsizei +void DrawArraysInstanced GLenum GLint GLsizei GLsizei +void DrawBuffer GLenum +void DrawBuffers GLsizei const_GLenum* +void DrawElements GLenum GLsizei GLenum const_GLvoid* +void DrawElementsBaseVertex GLenum GLsizei GLenum const_GLvoid* GLint +void DrawElementsInstanced GLenum GLsizei GLenum const_GLvoid* GLsizei +void DrawElementsInstancedBaseVertex GLenum GLsizei GLenum GLvoid* GLsizei GLint +void DrawRangeElements GLenum GLuint GLuint GLsizei GLenum const_GLvoid* +void DrawRangeElementsBaseVertex GLenum GLuint GLuint GLsizei GLenum GLvoid* GLint + +// --E-- +void Enable GLenum +void EnableVertexAttribArray GLuint +void Enablei GLenum GLuint +void EndQuery GLenum +void EndTransformFeedback + +// --F-- +GLsync FenceSync GLenum GLbitfield +void Finish +void Flush +void FlushMappedBufferRange GLenum GLintptr GLsizeiptr +void FramebufferRenderbuffer GLenum GLenum GLenum GLuint +void FramebufferTexture GLenum GLenum GLuint GLint +void FramebufferTexture1D GLenum GLenum GLenum GLuint GLint +void FramebufferTexture2D GLenum GLenum GLenum GLuint GLint +void FramebufferTexture3D GLenum GLenum GLenum GLuint GLint GLint +void FramebufferTextureLayer GLenum GLenum GLuint GLint GLint +void FrontFace GLenum + +// --G-- +void GenBuffers GLsizei GLuint* +void GenFramebuffers GLsizei GLuint* +void GenQueries GLsizei GLuint* +void GenRenderbuffers GLsizei GLuint* +void GenSamplers GLsizei GLuint* +void GenTextures GLsizei GLuint* +void GenVertexArrays GLsizei GLuint* +void GenerateMipmap GLenum +void GetBooleanv GLenum GLboolean* +void GetDoublev GLenum GLdouble* +void GetFloatv GLenum GLfloat* +void GetIntegerv GLenum GLint* +void GetInteger64v GLenum GLint64* +void GetActiveAttrib GLuint GLuint GLsizei GLsizei* GLint* GLenum* GLchar* +void GetActiveUniform GLuint GLuint GLsizei GLsizei* GLint* GLenum* GLchar* +void GetActiveUniformBlockiv GLuint GLuint GLenum GLint* +void GetActiveUniformBlockName GLuint GLuint GLsizei GLsizei* GLchar* +void GetActiveUniformName GLuint GLuint GLsizei GLsizei* GLchar* +void GetActiveUniformsiv GLuint GLsizei const_GLuint* GLenum GLint* +void GetAttachedShaders GLuint GLsizei GLsizei* GLuint* +GLint GetAttribLocation GLuint const_GLchar* +void GetBufferParameteriv GLenum GLenum GLint* +void GetBufferPointerv GLenum GLenum GLvoid** +void GetBufferSubData GLenum GLintptr GLsizeiptr GLvoid* +void GetCompressedTexImage GLenum GLint GLvoid* +GLenum GetError +GLint GetFragDataIndex GLuint const_char* +GLint GetFragDataLocation GLuint const_char* +void GetFramebufferAttachmentParameteriv GLenum GLenum GLenum GLint* +void GetMultisamplefv GLenum GLuint GLfloat* +void GetProgramiv GLuint GLenum GLint* +void GetProgramInfoLog GLuint GLsizei GLsizei* GLchar* +void GetQueryObjectiv GLuint GLenum GLint* +void GetQueryObjectuiv GLuint GLenum GLuint* +void GetQueryObjecti64v GLuint GLenum GLint64* +void GetQueryObjectui64v GLuint GLenum GLuint64* +void GetQueryiv GLenum GLenum GLint* +void GetRenderbufferParameteriv GLenum GLenum GLint* +void GetSamplerParameterfv GLuint GLenum GLfloat* +void GetSamplerParameteriv GLuint GLenum GLint* +void GetShaderiv GLuint GLenum GLint* +void GetShaderInfoLog GLuint GLsizei GLsizei* GLchar* +void GetShaderSource GLuint GLsizei GLsizei* GLchar* +const_GLubyte* GetString GLenum +const_GLubyte* GetStringi GLenum GLuint +void GetSynciv GLsync GLenum GLsizei GLsizei* GLint* +void GetTexImage GLenum GLint GLenum GLenum GLvoid* +void GetTexLevelParameterfv GLenum GLint GLenum GLfloat* +void GetTexLevelParameteriv GLenum GLint GLenum GLint* +void GetTexParameterfv GLenum GLenum GLfloat* +void GetTexParameteriv GLenum GLenum GLint* +void GetTransformFeedbackVarying GLuint GLuint GLsizei GLsizei* GLsizei GLenum* GLchar* +void GetUniformfv GLuint GLint GLfloat* +void GetUniformiv GLuint GLint GLint* +GLuint GetUniformIndices GLuint GLsizei const_GLchar** GLuint* +GLint GetUniformLocation GLuint const_GLchar* +void GetVertexAttribdv GLuint GLenum GLdouble* +void GetVertexAttribfv GLuint GLenum GLfloat* +void GetVertexAttribiv GLuint GLenum GLint* +void GetVertexAttribIiv GLuint GLenum GLint* +void GetVertexAttribIuiv GLuint GLenum GLuint* +void GetVertexAttribPointerv GLuint GLenum GLvoid** + +// --H-- +void Hint GLenum GLenum + +// --I-- +GLboolean IsBuffer GLuint +GLboolean IsEnabled GLenum +GLboolean IsEnabledi GLenum GLuint +GLboolean IsFramebuffer GLuint +GLboolean IsProgram GLuint +GLboolean IsQuery GLuint +GLboolean IsRenderbuffer GLuint +GLboolean IsSampler GLuint +GLboolean IsShader GLuint +GLboolean IsSync GLsync +GLboolean IsTexture GLuint +GLboolean IsVertexArray GLuint + +// --J-- + + +// --L-- +void LineWidth GLfloat +void LinkProgram GLuint +void LogicOp GLenum + +// --M-- +void* MapBuffer GLenum GLenum +void* MapBufferRange GLenum GLintptr GLsizeiptr GLbitfield +void MultiDrawArrays GLenum const_GLint* const_GLsizei* GLsizei +void MultiDrawElements GLenum const_GLsizei* GLenum const_GLvoid** GLsizei +void MultiDrawElementsBaseVertex GLenum const_GLsizei* GLenum const_GLvoid** GLsizei GLint* + +// --N-- + +// --O-- + +// --P-- +void PixelStoref GLenum GLfloat +void PixelStorei GLenum GLint +void PointParameterf GLenum GLfloat +void PointParameteri GLenum GLint +void PointSize GLfloat +void PolygonMode GLenum GLenum +void PolygonOffset GLfloat GLfloat +void PrimitiveRestartIndex GLuint +void ProvokingVertex GLenum + +// --Q-- +void QueryCounter GLuint GLenum + +// --R-- +void ReadBuffer GLenum +void ReadPixels GLint GLint GLsizei GLsizei GLenum GLenum GLvoid* +void RenderbufferStorage GLenum GLenum GLsizei GLsizei +void RenderbufferStorageMultisample GLenum GLsizei GLenum GLsizei GLsizei + +// --S-- +void SampleCoverage GLclampf GLboolean +void SampleMaski GLuint GLbitfield +void SamplerParameterf GLuint GLenum GLfloat +void SamplerParameteri GLuint GLenum GLint +void SamplerParameterfv GLuint GLenum const_GLfloat* +void SamplerParameteriv GLuint GLenum const_GLint* +void SamplerParameterIiv GLuint GLenum const_GLint* +void SamplerParameterIuiv GLuint GLenum const_GLuint* +void Scissor GLint GLint GLsizei GLsizei +void ShaderSource GLuint GLsizei const_GLchar** const_GLint* +void StencilFunc GLenum GLint GLuint +void StencilFuncSeparate GLenum GLenum GLint GLuint +void StencilMask GLuint +void StencilMaskSeparate GLenum GLuint +void StencilOp GLenum GLenum GLenum +void StencilOpSeparate GLenum GLenum GLenum GLenum + +// --T-- +void TexBuffer GLenum GLenum GLuint +void TexImage1D GLenum GLint GLint GLsizei GLint GLenum GLenum const_GLvoid* +void TexImage2D GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const_GLvoid* +void TexImage2DMultisample GLenum GLsizei GLint GLsizei GLsizei GLboolean +void TexImage3D GLenum GLint GLint GLsizei GLsizei GLsizei GLint GLenum GLenum const_GLvoid* +void TexImage3DMultisample GLenum GLsizei GLint GLsizei GLsizei GLsizei GLboolean +void TexParameterf GLenum GLenum GLfloat +void TexParameteri GLenum GLenum GLint +void TexParameterfv GLenum GLenum const_GLfloat* +void TexParameteriv GLenum GLenum const_GLint* +void TexParameterIiv GLenum GLenum const_GLint* +void TexParameterIuiv GLenum GLenum const_GLuint* +void TexSubImage1D GLenum GLint GLint GLsizei GLenum GLenum const_GLvoid* +void TexSubImage2D GLenum GLint GLint GLint GLsizei GLsizei GLenum GLenum const_GLvoid* +void TexSubImage3D GLenum GLint GLint GLint GLint GLsizei GLsizei GLsizei GLenum GLenum const_GLvoid* +void TransformFeedbackVaryings GLuint GLsizei const_GLchar** GLenum + +// --U-- +void Uniform1f GLint GLfloat +void Uniform2f GLint GLfloat GLfloat +void Uniform3f GLint GLfloat GLfloat GLfloat +void Uniform4f GLint GLfloat GLfloat GLfloat GLfloat +void Uniform1i GLint GLint +void Uniform2i GLint GLint GLint +void Uniform3i GLint GLint GLint GLint +void Uniform4i GLint GLint GLint GLint GLint +void Uniform1ui GLint GLuint +void Uniform2ui GLint GLuint GLuint +void Uniform3ui GLint GLuint GLuint GLuint +void Uniform4ui GLint GLuint GLuint GLuint GLuint +void Uniform1fv GLint GLsizei const_GLfloat* +void Uniform2fv GLint GLsizei const_GLfloat* +void Uniform3fv GLint GLsizei const_GLfloat* +void Uniform4fv GLint GLsizei const_GLfloat* +void Uniform1iv GLint GLsizei const_GLint* +void Uniform2iv GLint GLsizei const_GLint* +void Uniform3iv GLint GLsizei const_GLint* +void Uniform4iv GLint GLsizei const_GLint* +void Uniform1uiv GLint GLsizei const_GLuint* +void Uniform2uiv GLint GLsizei const_GLuint* +void Uniform3uiv GLint GLsizei const_GLuint* +void Uniform4uiv GLint GLsizei const_GLuint* +void UniformMatrix2fv GLint GLsizei GLboolean const_GLfloat* +void UniformMatrix3fv GLint GLsizei GLboolean const_GLfloat* +void UniformMatrix4fv GLint GLsizei GLboolean const_GLfloat* +void UniformMatrix2x3fv GLint GLsizei GLboolean const_GLfloat* +void UniformMatrix3x2fv GLint GLsizei GLboolean const_GLfloat* +void UniformMatrix2x4fv GLint GLsizei GLboolean const_GLfloat* +void UniformMatrix4x2fv GLint GLsizei GLboolean const_GLfloat* +void UniformMatrix3x4fv GLint GLsizei GLboolean const_GLfloat* +void UniformMatrix4x3fv GLint GLsizei GLboolean const_GLfloat* +void UniformBlockBinding GLuint GLuint GLuint +GLboolean UnmapBuffer GLenum +void UseProgram GLuint + + +void ValidateProgram GLuint +void VertexAttrib1f GLuint GLfloat +void VertexAttrib1s GLuint GLshort +void VertexAttrib1d GLuint GLdouble +void VertexAttribI1i GLuint GLint +void VertexAttribI1ui GLuint GLuint +void VertexAttrib2f GLuint GLfloat GLfloat +void VertexAttrib2s GLuint GLshort GLshort +void VertexAttrib2d GLuint GLdouble GLdouble +void VertexAttribI2i GLuint GLint GLint +void VertexAttribI2ui GLuint GLuint GLuint +void VertexAttrib3f GLuint GLfloat GLfloat GLfloat +void VertexAttrib3s GLuint GLshort GLshort GLshort +void VertexAttrib3d GLuint GLdouble GLdouble GLdouble +void VertexAttribI3i GLuint GLint GLint GLint +void VertexAttribI3ui GLuint GLuint GLuint GLuint +void VertexAttrib4f GLuint GLfloat GLfloat GLfloat GLfloat +void VertexAttrib4s GLuint GLshort GLshort GLshort GLshort +void VertexAttrib4d GLuint GLdouble GLdouble GLdouble GLdouble +void VertexAttrib4Nub GLuint GLubyte GLubyte GLubyte GLubyte +void VertexAttribI4i GLuint GLint GLint GLint GLint +void VertexAttribI4ui GLuint GLuint GLuint GLuint GLuint +void VertexAttrib1fv GLuint const_GLfloat* +void VertexAttrib1sv GLuint const_GLshort* +void VertexAttrib1dv GLuint const_GLdouble* +void VertexAttribI1iv GLuint const_GLint* +void VertexAttribI1uiv GLuint const_GLuint* +void VertexAttrib2fv GLuint const_GLfloat* +void VertexAttrib2sv GLuint const_GLshort* +void VertexAttrib2dv GLuint const_GLdouble* +void VertexAttribI2iv GLuint const_GLint* +void VertexAttribI2uiv GLuint const_GLuint* +void VertexAttrib3fv GLuint const_GLfloat* +void VertexAttrib3sv GLuint const_GLshort* +void VertexAttrib3dv GLuint const_GLdouble* +void VertexAttribI3iv GLuint const_GLint* +void VertexAttribI3uiv GLuint const_GLuint* +void VertexAttrib4fv GLuint const_GLfloat* +void VertexAttrib4sv GLuint const_GLshort* +void VertexAttrib4dv GLuint const_GLdouble* +void VertexAttrib4iv GLuint const_GLint* +void VertexAttrib4bv GLuint const_GLbyte* +void VertexAttrib4ubv GLuint const_GLubyte* +void VertexAttrib4usv GLuint const_GLushort* +void VertexAttrib4uiv GLuint const_GLuint* +void VertexAttrib4Nbv GLuint const_GLbyte* +void VertexAttrib4Nsv GLuint const_GLshort* +void VertexAttrib4Niv GLuint const_GLint* +void VertexAttrib4Nubv GLuint const_GLubyte* +void VertexAttrib4Nusv GLuint const_GLushort* +void VertexAttrib4Nuiv GLuint const_GLuint* +void VertexAttribI4bv GLuint const_GLbyte* +void VertexAttribI4ubv GLuint const_GLubyte* +void VertexAttribI4sv GLuint const_GLshort* +void VertexAttribI4usv GLuint const_GLushort* +void VertexAttribI4iv GLuint const_GLint* +void VertexAttribI4uiv GLuint const_GLuint* +void VertexAttribP1ui GLuint GLenum GLboolean GLuint +void VertexAttribP2ui GLuint GLenum GLboolean GLuint +void VertexAttribP3ui GLuint GLenum GLboolean GLuint +void VertexAttribP4ui GLuint GLenum GLboolean GLuint +void VertexAttribDivisor GLuint GLuint +void VertexAttribPointer GLuint GLint GLenum GLboolean GLsizei const_GLvoid* +void VertexAttribIPointer GLuint GLint GLenum GLsizei const_GLvoid* +void Viewport GLint GLint GLsizei GLsizei + +// --W-- +void WaitSync GLsync GLbitfield GLuint64 + diff --git a/libsst-glapi/libsst-glapi.vcxproj b/libsst-glapi/libsst-glapi.vcxproj new file mode 100644 index 0000000..3c2e79e --- /dev/null +++ b/libsst-glapi/libsst-glapi.vcxproj @@ -0,0 +1,180 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup Label="ProjectConfigurations"> + <ProjectConfiguration Include="Debug|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectGuid>{29F643C8-7935-43E9-B1AB-66FFBCDE9E38}</ProjectGuid> + <RootNamespace>libsstglapi</RootNamespace> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> + <ConfigurationType>StaticLibrary</ConfigurationType> + <UseDebugLibraries>true</UseDebugLibraries> + <PlatformToolset>v110</PlatformToolset> + <CharacterSet>MultiByte</CharacterSet> + <WholeProgramOptimization>true</WholeProgramOptimization> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> + <ConfigurationType>StaticLibrary</ConfigurationType> + <UseDebugLibraries>true</UseDebugLibraries> + <PlatformToolset>v110</PlatformToolset> + <CharacterSet>MultiByte</CharacterSet> + <WholeProgramOptimization>true</WholeProgramOptimization> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> + <ConfigurationType>StaticLibrary</ConfigurationType> + <UseDebugLibraries>false</UseDebugLibraries> + <PlatformToolset>v110</PlatformToolset> + <WholeProgramOptimization>true</WholeProgramOptimization> + <CharacterSet>MultiByte</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> + <ConfigurationType>StaticLibrary</ConfigurationType> + <UseDebugLibraries>false</UseDebugLibraries> + <PlatformToolset>v110</PlatformToolset> + <WholeProgramOptimization>true</WholeProgramOptimization> + <CharacterSet>MultiByte</CharacterSet> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <ImportGroup Label="ExtensionSettings"> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <PropertyGroup Label="UserMacros" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <OutDir>$(SolutionDir)\Lib\x64\</OutDir> + <IntDir>$(SolutionDir)Intermediate\$(Configuration)\$(Platform)\$(ProjectName)\</IntDir> + <TargetName>$(ProjectName)-debug</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <OutDir>$(SolutionDir)\Lib\x64\</OutDir> + <IntDir>$(SolutionDir)Intermediate\$(Configuration)\$(Platform)\$(ProjectName)\</IntDir> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <OutDir>$(SolutionDir)\Lib\x86\</OutDir> + <IntDir>$(SolutionDir)Intermediate\$(Configuration)\$(Platform)\$(ProjectName)\</IntDir> + <TargetName>$(ProjectName)-debug</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <OutDir>$(SolutionDir)\Lib\x86\</OutDir> + <IntDir>$(SolutionDir)Intermediate\$(Configuration)\$(Platform)\$(ProjectName)\</IntDir> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <WarningLevel>Level3</WarningLevel> + <Optimization>Disabled</Optimization> + <AdditionalIncludeDirectories>$(SolutionDir)Lib\Include</AdditionalIncludeDirectories> + <StringPooling>true</StringPooling> + <MinimalRebuild>false</MinimalRebuild> + <ExceptionHandling>false</ExceptionHandling> + <CreateHotpatchableImage>false</CreateHotpatchableImage> + <FunctionLevelLinking>true</FunctionLevelLinking> + <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> + <SDLCheck>false</SDLCheck> + <MultiProcessorCompilation>true</MultiProcessorCompilation> + </ClCompile> + <Link> + <GenerateDebugInformation>true</GenerateDebugInformation> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ClCompile> + <WarningLevel>Level3</WarningLevel> + <Optimization>Disabled</Optimization> + <AdditionalIncludeDirectories>$(SolutionDir)Lib\Include</AdditionalIncludeDirectories> + <StringPooling>true</StringPooling> + <MinimalRebuild>false</MinimalRebuild> + <ExceptionHandling>false</ExceptionHandling> + <CreateHotpatchableImage>false</CreateHotpatchableImage> + <FunctionLevelLinking>true</FunctionLevelLinking> + <SDLCheck>false</SDLCheck> + <MultiProcessorCompilation>true</MultiProcessorCompilation> + </ClCompile> + <Link> + <GenerateDebugInformation>true</GenerateDebugInformation> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <WarningLevel>Level3</WarningLevel> + <Optimization>MaxSpeed</Optimization> + <FunctionLevelLinking>true</FunctionLevelLinking> + <IntrinsicFunctions>true</IntrinsicFunctions> + <AdditionalIncludeDirectories>$(SolutionDir)Lib\Include</AdditionalIncludeDirectories> + <StringPooling>true</StringPooling> + <ExceptionHandling>false</ExceptionHandling> + <CreateHotpatchableImage>false</CreateHotpatchableImage> + <SDLCheck>false</SDLCheck> + <MultiProcessorCompilation>true</MultiProcessorCompilation> + </ClCompile> + <Link> + <GenerateDebugInformation>true</GenerateDebugInformation> + <EnableCOMDATFolding>true</EnableCOMDATFolding> + <OptimizeReferences>true</OptimizeReferences> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ClCompile> + <WarningLevel>Level3</WarningLevel> + <Optimization>MaxSpeed</Optimization> + <FunctionLevelLinking>true</FunctionLevelLinking> + <IntrinsicFunctions>true</IntrinsicFunctions> + <AdditionalIncludeDirectories>$(SolutionDir)Lib\Include</AdditionalIncludeDirectories> + <StringPooling>true</StringPooling> + <ExceptionHandling>false</ExceptionHandling> + <CreateHotpatchableImage>false</CreateHotpatchableImage> + <SDLCheck>false</SDLCheck> + <MultiProcessorCompilation>true</MultiProcessorCompilation> + </ClCompile> + <Link> + <GenerateDebugInformation>true</GenerateDebugInformation> + <EnableCOMDATFolding>true</EnableCOMDATFolding> + <OptimizeReferences>true</OptimizeReferences> + </Link> + </ItemDefinitionGroup> + <ItemGroup> + <Text Include="gl33.txt" /> + </ItemGroup> + <ItemGroup> + <ClCompile Include="SST_GLAPIContext.c" /> + <ClCompile Include="SST_GLAPIResolve_Win32.c" /> + <ClCompile Include="SST_GLAPIStruct.c" /> + </ItemGroup> + <ItemGroup> + <ClInclude Include="..\Lib\Include\SST\SST_GLAPI.h" /> + <ClInclude Include="..\Lib\Include\SST\SST_GLAPIContext.h" /> + <ClInclude Include="..\Lib\Include\SST\SST_GLAPIDefs.h" /> + <ClInclude Include="..\Lib\Include\SST\SST_GLAPIMacros.h" /> + <ClInclude Include="..\Lib\Include\SST\SST_GLAPIStruct.h" /> + <ClInclude Include="GLAPIPrivate.h" /> + </ItemGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> + <ImportGroup Label="ExtensionTargets"> + </ImportGroup> +</Project> \ No newline at end of file diff --git a/libsst-glapi/libsst-glapi.vcxproj.filters b/libsst-glapi/libsst-glapi.vcxproj.filters new file mode 100644 index 0000000..813e80d --- /dev/null +++ b/libsst-glapi/libsst-glapi.vcxproj.filters @@ -0,0 +1,53 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup> + <Filter Include="Source Files"> + <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier> + <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions> + </Filter> + <Filter Include="Header Files"> + <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier> + <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> + </Filter> + <Filter Include="Resource Files"> + <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier> + <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions> + </Filter> + </ItemGroup> + <ItemGroup> + <ClCompile Include="SST_GLAPIContext.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="SST_GLAPIResolve_Win32.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="SST_GLAPIStruct.c"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> + <ItemGroup> + <ClInclude Include="..\Lib\Include\SST\SST_GLAPI.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\Lib\Include\SST\SST_GLAPIContext.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\Lib\Include\SST\SST_GLAPIDefs.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\Lib\Include\SST\SST_GLAPIMacros.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\Lib\Include\SST\SST_GLAPIStruct.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="GLAPIPrivate.h"> + <Filter>Source Files</Filter> + </ClInclude> + </ItemGroup> + <ItemGroup> + <Text Include="gl33.txt"> + <Filter>Resource Files</Filter> + </Text> + </ItemGroup> +</Project> \ No newline at end of file diff --git a/libsst-glapi/libsst-glapi.vcxproj.user b/libsst-glapi/libsst-glapi.vcxproj.user new file mode 100644 index 0000000..a375ae3 --- /dev/null +++ b/libsst-glapi/libsst-glapi.vcxproj.user @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <PropertyGroup /> +</Project> \ No newline at end of file diff --git a/libsst-glapi/obj/x86-64/release/SST_GLAPIContext.o b/libsst-glapi/obj/x86-64/release/SST_GLAPIContext.o new file mode 100644 index 0000000000000000000000000000000000000000..a80358cecfa353639c40b8143ba2b2fa9a2c0baa GIT binary patch literal 4152 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 HXj}#W>$CfQ literal 0 HcmV?d00001 diff --git a/libsst-glapi/obj/x86-64/release/SST_GLAPIResolve_POSIX.o b/libsst-glapi/obj/x86-64/release/SST_GLAPIResolve_POSIX.o new file mode 100644 index 0000000000000000000000000000000000000000..d091d7ffb678ad32c9178b557ca5e87fceec17f1 GIT binary patch literal 2328 zcmb<-^>JfjWMqH=Mg}_u1P><4z;J^V!FB*M9T<2SxEMk`I-hzpzY*~0to`B9?fPRM z6C(qIN9XYuAT=isqf5hNCcvc>JUVM%cyyLN@aT4Z;L+&{GUdfSkZzb-kIq9NlRY{G zz*IMbN9%!7X^(DK!piuk9^l`00Akk;keRVC7a?2w0&49Kk8TE!?$8Gwo!9?gIC(fd zC&E3oB%mli*)b)hD7CoQG02GlLy#dSGs)dYuQ*@Nkb%M7+1W}#BQ&WrucTDLRL?}u zK-a7k%rmSrG}ALM(KFM8h$|Qw7@8TF8CZf`#lXNI0;L(Nf*2Sp1Q?}x*f}OJGBC(6 zKrl#J9z;0u3A8ae^Rh+puya7=Y(U}+3=GmB8YUlxkdFb0GcYjZfM}RJQ#x1y$ov|R zI0FL%H;9JGyMd*__Rj%{GcYh{foPa~DnuS6gbjnz5DUY{|JdZ1v8FHv24)6kY|0s! z8CY<LBPB{C70e9mNIV3SnE@1H2tJI(%)ka?!f7c61_mJ{cY?#7fq_AVfq_8)t_s1> zhN_3D1IGme1A`e3^>$G8R!}3ral^pC;Dtkd095@lsCsZ*F)%PBLd7>i#ldj|Vh0C@ z#Jl@A26zUg7U$=brN#&N2YW{7B{Sp~q~`g6(kw$t4v5W=oReRi3KIcy7}8TqpxTNU zQgVtba~V=n(-KQ_O2Eqe5_3}-iXg_i`vh0!CgsDN&mal1n}LCWiGhKEi-CdR&wmIo zMiS>i5)X%pgVZ9&W;|3JWDXya`Z}mMOuZ<S-v*`8)vtz%!_=!o`3g`Pq#lH!Tn0$l z25~<~92TDmPz4|{5QfED1DZH2eiopK!{UcQuedU|Br%CWuehWLLTA8OMX5Q7dL^k9 zB@B8gi6w~)dP&8_40=WR5KeM_Zf<H`34>l<eo3mHyI-hoaY<rwHiI5mTWUspS`jE- zp!QNqfx-urhtYEeEPQUGSpZUtECfpbpj-=650eW32{JG+tbhuD(lJOcEN4nU#nl)X zz_|~-M34q4hN?lP(1mpv7{IxmT>XYn`$2JyY!A$SBV<9ST4W(mxejuZ0kR+i1A{L} zkb!~06ipl|4E8ff$_a~^An_)cLJ$WDqYH!b6-W%-{T(1d1_lOjZHS~F7XC1yAO;3- zsf!+eKcMkf0aXZ!KagG!1_{C9Pmlpro`XbCaRD@wgUT&r8K|@1LLff6+d+~JP{A1> k1q=)fpt6J$8rL9snEfCz^tcDf-+&4hf;dPRY8+ey09@7+VE_OC literal 0 HcmV?d00001 diff --git a/libsst-glapi/obj/x86-64/release/SST_GLAPIStruct.o b/libsst-glapi/obj/x86-64/release/SST_GLAPIStruct.o new file mode 100644 index 0000000000000000000000000000000000000000..35a300d6e0f0cc07da1a86224780ef0f7b22d588 GIT binary patch literal 33032 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 NLys4beIWB-7yy#_2PFUi literal 0 HcmV?d00001 diff --git a/libsst-glapi/parsegl.c b/libsst-glapi/parsegl.c new file mode 100644 index 0000000..bb55935 --- /dev/null +++ b/libsst-glapi/parsegl.c @@ -0,0 +1,356 @@ +/* + parsegl.c + Author: Patrick Baggett <ptbaggett@762studios.com> + Created: 12/12/2012 + + Purpose: + + Parse GL function definitions and generate libsst-glapi code/headers + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> + +#define DEFS "gl33.txt" + +typedef struct GLFunc +{ + char name[64]; /* Name of OpenGL function, sans "gl" prefix */ + char returnType[64]; /* C return value type */ + char argTypes[16][64]; /* C argument type */ + + unsigned int constBitmask; /* If bit 'n' is set, then parameter 'n' is a const parameter. highest bit is return type */ + unsigned int nrArgs; /* Number of arguments in the function */ + + struct GLFunc* next; /* Next function in the list */ +} GLFunc; + +/* These test if parameter is marked as "const" */ +#define ISCONST(func, n) (func->constBitmask & (1u << n)) +#define ISCONSTRETURN(func) ISCONST(func, 31u) + +/* Linked list of functions parsed */ +GLFunc* first = NULL; +GLFunc* last = NULL; +unsigned int totalParsed = 0; + +/******************************************************************************/ + +static void parseLine(const char* line); +static void genStruct(FILE* fp); +static void genLinkCode(FILE* fp); +static void genMacros(FILE* fp); +static void autogenHeader(FILE* fp) { fprintf(fp, "/* AUTOGENERATED BY parsegl.c -- DO NOT MODIFY */\n"); } + +/******************************************************************************/ + +int main() +{ + char line[1024]; + FILE* fp = fopen(DEFS, "r"); + int c; + int eolFound = 0; + int k = 0; + + /* Can't open GL function definitions? */ + if(fp == NULL) + { + printf("Could not open file \"%s\" for reading\n", DEFS); + exit(1); + } + + /* Read each line of text until EOF */ + do + { + c = fgetc(fp); + + switch(c) + { + /* These end a line */ + case 0x0A: + case 0x0D: + eolFound = 1; + line[k] = '\0'; + k=0; + break; + + case EOF: + break; + + /* Otherwise, copy the line */ + default: + line[k] = (char)c; + k++; + break; + } + + /* Time to parse a line? */ + if(eolFound) + { + parseLine(line); + eolFound = 0; + } + + } while(c != EOF); + + fclose(fp); + + printf("%u GL functions parsed\n", totalParsed); + + /* Write API structure */ + fp = fopen("SST_GLAPIStruct.h", "w"); + if(fp != NULL) + { + autogenHeader(fp); + genStruct(fp); + fclose(fp); + } + + /* Write runtime API resolution */ + fp = fopen("SST_GLAPIStruct.c", "w"); + if(fp != NULL) + { + autogenHeader(fp); + genLinkCode(fp); + + fclose(fp); + } + + /* Write canonical glDoThing() macros */ + fp = fopen("SST_GLAPIMacros.h", "w"); + if(fp != NULL) + { + autogenHeader(fp); + genMacros(fp); + fclose(fp); + } + + /* Done */ + return 0; +} + +/******************************************************************************/ + +/* Read the line and parse out any GL function definitions */ +static void parseLine(const char* line) +{ + int exitTime; + int k = 0; + int nrFound = 0; + char word[64]; + char* s = word; + GLFunc* func; + + /* Ignore leading whitespace */ + while(isspace(*line)) + line++; + + /* Nothing to parse? */ + if(strlen(line) == 0) + return; + + /* Ignore comment lines */ + if(line[0] == '/' && line[1] == '/') + return; + + memset(word, 0, sizeof(word)); + func = (GLFunc*)calloc(1, sizeof(*func)); + + /* Pull words out of the line */ + exitTime = 0; + do + { + if(line[k] == '\0') + { + exitTime = 1; + *s = '\0'; + } + if(isspace(line[k])) + *s = '\0'; + else + *s = line[k]; + k++; + + /* Parse word time? */ + if(*s == '\0') + { + s = word; + + /* Skip all blank spaces */ + while(isspace(*s)) + s++; + + /* Non-zero lengths only, please */ + if(strlen(s) >= 0) + { + + /* First word is the return value type */ + if(nrFound == 0) + { + if(strstr(s, "const_")) + { + func->constBitmask |= (1u << 31); + s += strlen("const_"); + } + + strcpy(func->returnType, s); + } + else if (nrFound == 1) /* Second word is the function name */ + strcpy(func->name, s); + else /* Remaining words are arguments */ + { + int arg = nrFound - 2; + + /* Is it a const arg? */ + if(strstr(s, "const_")) + { + func->constBitmask |= (1u << arg); + s += strlen("const_"); + } + + strcpy(func->argTypes[arg], s); + func->nrArgs++; + } + + nrFound++; + + } /* non-zero length string */ + + s = word; + } /* Done parsing word */ + else + s++; + + } while(!exitTime); + + /* Store */ + if(first == NULL) + first = func; + + if(last != NULL) + last->next = func; + last = func; + totalParsed++; + +} + +/******************************************************************************/ + +static void genStruct(FILE* fp) +{ + const GLFunc* func = first; + + fprintf(fp, + "#ifndef _SST_GLAPISTRUCT_H\n" + "#define _SST_GLAPISTRUCT_H\n\n"); + fprintf(fp, "#include <SST/SST_GLAPIDefs.h>\n\n"); + fprintf(fp, "typedef struct SST_GLAPI\n{\n"); + while(func) + { + unsigned int i; + + /* Return value and name of function */ + fprintf(fp, "\t%s%s (OGLCALL* %s)(", + ISCONSTRETURN(func) ? "const " : "", + func->returnType, + func->name); + + /* Run through each valid argument */ + for(i=0; i<func->nrArgs; i++) + { + if(ISCONST(func, i)) + fprintf(fp, "const "); + + fprintf(fp, "%s", func->argTypes[i]); + + if(i != func->nrArgs-1) + fprintf(fp, ", "); + } + fprintf(fp, ");\n"); + + func = func->next; + } + fprintf(fp, "\t/*======================================*/\n"); + fprintf(fp, "\tvoid* libGL; /* OpenGL library handle */\n"); + fprintf(fp, "\tchar* libGLName; /* OpenGL library name */\n"); + + + fprintf(fp, "} SST_GLAPI;\n#endif\n\n"); +} + +static void genLinkCode(FILE* fp) +{ + const GLFunc* func = first; + fprintf(fp, "#include <SST/SST_GLAPIStruct.h>\n"); + fprintf(fp, "#include \"GLAPIPrivate.h\"\n\n"); + fprintf(fp, "void resolveGLAPI(const GLAPIResolver* resolver, struct SST_GLAPI* api)\n{\n"); + + while(func) + { + unsigned int i; + + /* Resolve it */ + fprintf(fp, "\tapi->%s = resolveGLSymbol(resolver, \"gl%s\");\n", + func->name, func->name); + + func = func->next; + } + + fprintf(fp, "\n}\n"); +} + +static void genMacros(FILE* fp) +{ + const GLFunc* func = first; + + fprintf(fp, + "#ifndef _SST_GLAPIMACROS_H\n" + "#define _SST_GLAPIMACROS_H\n\n"); + + while(func) + { + unsigned int i; + + /* #define a macro for it */ + fprintf(fp, "#define gl%s(",func->name); + + /* Label macro arguments as 'a', 'b', 'c', ... */ + for(i=0; i<func->nrArgs; i++) + { + fprintf(fp, "%c%s", + 'a'+i, + i < func->nrArgs-1?",":""); + } + + fprintf(fp, ") __sstglctx->%s(", func->name); + + /* Label macro arguments as 'a', 'b', 'c', ... */ + for(i=0; i<func->nrArgs; i++) + { + fprintf(fp, "(%c)%s", + 'a'+i, + i < func->nrArgs-1?",":""); + } + fprintf(fp, ")\n"); + + + func = func->next; + } + + + + fprintf(fp, " \n#endif\n\n"); + +} + diff --git a/libsst-glapi/sources-MacOSX.mk b/libsst-glapi/sources-MacOSX.mk new file mode 100644 index 0000000..c13d09b --- /dev/null +++ b/libsst-glapi/sources-MacOSX.mk @@ -0,0 +1,18 @@ +# libsst-glapi/sources-MacOSX.mk +# Author: Patrick Baggett <ptbaggett@762studios.com> +# Created: 4/16/2013 +# +# Purpose: +# +# List of source files for OSX-based systems. +# +# License: +# +# This program is free software. It comes without any warranty, to +# the extent permitted by applicable law. You can redistribute it +# and/or modify it under the terms of the Do What The Fuck You Want +# To Public License, Version 2, as published by Sam Hocevar. See +# http://sam.zoy.org/wtfpl/COPYING for more details. + +SRC += SST_GLAPIResolve_MacOSX.c + diff --git a/libsst-glapi/sources-POSIX.mk b/libsst-glapi/sources-POSIX.mk new file mode 100644 index 0000000..c07eda1 --- /dev/null +++ b/libsst-glapi/sources-POSIX.mk @@ -0,0 +1,19 @@ +# libsst-glapi/sources-POSIX.mk +# Author: Patrick Baggett <ptbaggett@762studios.com> +# Created: 12/12/2012 +# +# Purpose: +# +# List of source files for systems using libGL.so. This reduces the amount +# of copy/pasting for different UNIX configurations. +# +# License: +# +# This program is free software. It comes without any warranty, to +# the extent permitted by applicable law. You can redistribute it +# and/or modify it under the terms of the Do What The Fuck You Want +# To Public License, Version 2, as published by Sam Hocevar. See +# http://sam.zoy.org/wtfpl/COPYING for more details. + +SRC += SST_GLAPIResolve_POSIX.c + diff --git a/libsst-glapi/sources-Win32.mk b/libsst-glapi/sources-Win32.mk new file mode 100644 index 0000000..3830d4d --- /dev/null +++ b/libsst-glapi/sources-Win32.mk @@ -0,0 +1,18 @@ +# libsst-glapi/sources-Win32.mk +# Author: Patrick Baggett <ptbaggett@762studios.com> +# Created: 12/12/2012 +# +# Purpose: +# +# List of source files for Win32 systems +# +# License: +# +# This program is free software. It comes without any warranty, to +# the extent permitted by applicable law. You can redistribute it +# and/or modify it under the terms of the Do What The Fuck You Want +# To Public License, Version 2, as published by Sam Hocevar. See +# http://sam.zoy.org/wtfpl/COPYING for more details. + +SRC += SST_GLAPIResolve_Win32.c + diff --git a/libsst-math/Makefile b/libsst-math/Makefile new file mode 100644 index 0000000..f8c0b87 --- /dev/null +++ b/libsst-math/Makefile @@ -0,0 +1,370 @@ +# libsst-math/Makefile +# Author: Charles Lena <cmlena@762studios.com> +# Created: 5/17/2012 +# +# Purpose: +# +# Makefile for libsst-math +# +# License: +# +# This program is free software. It comes without any warranty, to +# the extent permitted by applicable law. You can redistribute it +# and/or modify it under the terms of the Do What The Fuck You Want +# To Public License, Version 2, as published by Sam Hocevar. See +# http://sam.zoy.org/wtfpl/COPYING for more details. + +#ifeq ($(IS_GCC),1) +#CFLAGS += -mssse3 -ftree-vectorize -ftree-vectorizer-verbose=5 -Wall -std=c99 +#CODFLAG=-Wa,-a,-ad +#endif +#ifeq ($(IS_ICC), 1) +#CFLAGS=-vec-report2 -restrict -xSSSE3 -Wall -std=c99 +#CODFLAG=-S -fcode-asm +#endif + +BINNAME := $(DIST)/libsst-math.a +ifeq ($(TARGET),debug) + BINNAME := $(subst .a,_d.a, $(BINNAME)) +endif + +#Required libraries +REQ_LIBS := libsst-math.a + +# Generate the lib names with the full dist name. +# This is only used for dependency checking +REQ_LIBS_DIST := $(foreach lib,$(REQ_LIBS), $(DIST)/$(lib)) + +#Generate LDFLAGS for $REQ_LIBS: "libfoo.a" becomes "-lfoo" +REQ_LIBS_LDFLAGS := $(foreach lib,$(REQ_LIBS), $(subst lib,-l,$(lib))) +REQ_LIBS_LDFLAGS := -L$(DIST) $(foreach lib,$(REQ_LIBS_LDFLAGS), $(subst .a,,$(lib))) + +DYNSRC_MAT= \ +SST_Mat22f.c SST_Mat22d.c \ +SST_Mat22i.c SST_Mat22u.c \ +SST_Mat33f.c SST_Mat33d.c \ +SST_Mat33i.c SST_Mat33u.c \ +SST_Mat44f.c SST_Mat44d.c \ +SST_Mat44i.c SST_Mat44u.c + +DYNSRC_VEC= \ +SST_Vec2f.c SST_Vec2d.c \ +SST_Vec2i.c SST_Vec2u.c \ +SST_Vec3f.c SST_Vec3u.c \ +SST_Vec3d.c SST_Vec3i.c \ +SST_Vec4f.c SST_Vec4d.c \ +SST_Vec4i.c SST_Vec4u.c +DYNUNITTEST = $(addprefix ../ZTestSuite/Test-,$(DYNSRC_MAT:.c=.cpp)) $(addprefix ../ZTestSuite/Test-,$(DYNSRC_VEC:.c=.cpp)) +DYNTEST : $(DYNTEST:.c=benchmark.c) +SRC=SST_Transform.c SST_Geo.c SST_VectorN.c +OBJ=$(addprefix obj/$(ARCH)/$(TARGET)/,$(subst .c,.o,$(SRC:.c=.o) $(DYNSRC_MAT:.c=.o) $(DYNSRC_VEC:.c=.o)) ) +FULLOBJ=$(addprefix obj/$(ARCH)/$(TARGET)/,$(DYNTEST:.c=.o) ) +CODs=$(SRC:.c=.cod) +PYFILE_MAT=./MatrixNxN.py +PYFILE_VEC=./VectorN.py +RANLIB?=ranlib + +.PHONY: all clean cleanall assemblers + +$(shell mkdir -p obj/$(ARCH)/$(TARGET)) + +$(BINNAME): $(OBJ) + $(AR) cru $@ $+ + $(RANLIB) $@ + +code: + @rm -f $(DYNSRC_MAT) $(DYNSRC_VEC) $(DYNTEST) $(DYNUNITTEST) + @$(MAKE) -C .. math + +test.bin: $(FULLOBJ) $(REQ_LIBS_DIST) + @echo LD $@ + $(CC) $+ $(LDFLAGS) -o $@ + +############################### +# THIS IS THE MATRIX AREA # +############################### +SST_Mat22f.c: + @echo GEN $@ + @$(PYFILE_MAT) 2 float > SST_Mat22f.c + +SST_Mat22d.c: + @echo GEN $@ + @$(PYFILE_MAT) 2 double > SST_Mat22d.c + +SST_Mat22i.c: + @echo GEN $@ + @$(PYFILE_MAT) 2 int > SST_Mat22i.c + +SST_Mat22u.c: + @echo GEN $@ + @$(PYFILE_MAT) 2 "unsigned int" > SST_Mat22u.c + +SST_Mat33f.c: + @echo GEN $@ + @$(PYFILE_MAT) 3 float > SST_Mat33f.c + +SST_Mat33d.c: + @echo GEN $@ + @$(PYFILE_MAT) 3 double > SST_Mat33d.c + +SST_Mat33i.c: + @echo GEN $@ + @$(PYFILE_MAT) 3 int > SST_Mat33i.c + +SST_Mat33u.c: + @echo GEN $@ + @$(PYFILE_MAT) 3 "unsigned int" > SST_Mat33u.c + +SST_Mat44f.c: + @echo GEN $@ + @$(PYFILE_MAT) 4 float > SST_Mat44f.c + +SST_Mat44d.c: + @echo GEN $@ + @$(PYFILE_MAT) 4 double > SST_Mat44d.c + +SST_Mat44i.c: + @echo GEN $@ + @$(PYFILE_MAT) 4 int > SST_Mat44i.c + +SST_Mat44u.c: + @echo GEN $@ + @$(PYFILE_MAT) 4 "unsigned int" > SST_Mat44u.c + +############################### +# THIS IS THE VECTOR AREA # +############################### +SST_Vec2f.c: + @echo GEN $@ + echo "$(PYFILE_VEC) 2 float > SST_Vec2f.c" + @$(PYFILE_VEC) 2 float > SST_Vec2f.c + +SST_Vec2d.c: + @echo GEN $@ + @$(PYFILE_VEC) 2 double > SST_Vec2d.c + +SST_Vec2i.c: + @echo GEN $@ + @$(PYFILE_VEC) 2 int > SST_Vec2i.c + +SST_Vec2u.c: + @echo GEN $@ + @$(PYFILE_VEC) 2 "unsigned int" > SST_Vec2u.c + +SST_Vec3f.c: + @echo GEN $@ + @$(PYFILE_VEC) 3 float > SST_Vec3f.c + +SST_Vec3d.c: + @echo GEN $@ + @$(PYFILE_VEC) 3 double > SST_Vec3d.c + +SST_Vec3i.c: + @echo GEN $@ + @$(PYFILE_VEC) 3 int > SST_Vec3i.c + +SST_Vec3u.c: + @echo GEN $@ + @$(PYFILE_VEC) 3 "unsigned int" > SST_Vec3u.c + +SST_Vec4f.c: + @echo GEN $@ + @$(PYFILE_VEC) 4 float > SST_Vec4f.c + +SST_Vec4d.c: + @echo GEN $@ + @$(PYFILE_VEC) 4 double > SST_Vec4d.c + +SST_Vec4i.c: + @echo GEN $@ + @$(PYFILE_VEC) 4 int > SST_Vec4i.c + +SST_Vec4u.c: + @echo GEN $@ + @$(PYFILE_VEC) 4 "unsigned int" > SST_Vec4u.c + +################################## +# THIS IS THE VECTEST SUITE AREA # +################################## +../ZTestSuite/Test-SST_Vec2f.cpp: + @echo GEN $@ + @$(PYFILE_VEC) 2 float unittest > $@ + +../ZTestSuite/Test-SST_Vec2d.cpp: + @echo GEN $@ + @$(PYFILE_VEC) 2 double unittest > $@ + +../ZTestSuite/Test-SST_Vec2i.cpp: + @echo GEN $@ + @$(PYFILE_VEC) 2 int unittest > $@ + +../ZTestSuite/Test-SST_Vec2u.cpp: + @echo GEN $@ + @$(PYFILE_VEC) 2 "unsigned int" unittest > $@ + +../ZTestSuite/Test-SST_Vec3f.cpp: + @echo GEN $@ + @$(PYFILE_VEC) 3 float unittest > $@ + +../ZTestSuite/Test-SST_Vec3d.cpp: + @echo GEN $@ + @$(PYFILE_VEC) 3 double unittest > $@ + +../ZTestSuite/Test-SST_Vec3i.cpp: + @echo GEN $@ + @$(PYFILE_VEC) 3 int unittest > $@ + +../ZTestSuite/Test-SST_Vec3u.cpp: + @echo GEN $@ + @$(PYFILE_VEC) 3 "unsigned int" unittest > $@ + +../ZTestSuite/Test-SST_Vec4f.cpp: + @echo GEN $@ + @$(PYFILE_VEC) 4 float unittest > $@ + +../ZTestSuite/Test-SST_Vec4d.cpp: + @echo GEN $@ + @$(PYFILE_VEC) 4 double unittest > $@ + +../ZTestSuite/Test-SST_Vec4i.cpp: + @echo GEN $@ + @$(PYFILE_VEC) 4 int unittest > $@ + +../ZTestSuite/Test-SST_Vec4u.cpp: + @echo GEN $@ + @$(PYFILE_VEC) 4 "unsigned int" unittest > $@ + +############################### +# THIS IS THE TEST SUITE AREA # +############################### +../ZTestSuite/Test-SST_Mat22f.cpp: + @echo GEN $@ + @$(PYFILE_MAT) 2 float unittest > $@ + +../ZTestSuite/Test-SST_Mat22d.cpp: + @echo GEN $@ + @$(PYFILE_MAT) 2 double unittest > $@ + +../ZTestSuite/Test-SST_Mat22i.cpp: + @echo GEN $@ + @$(PYFILE_MAT) 2 int unittest > $@ + +../ZTestSuite/Test-SST_Mat22u.cpp: + @echo GEN $@ + @$(PYFILE_MAT) 2 "unsigned int" unittest > $@ + +../ZTestSuite/Test-SST_Mat33f.cpp: + @echo GEN $@ + @$(PYFILE_MAT) 3 float unittest > $@ + +../ZTestSuite/Test-SST_Mat33d.cpp: + @echo GEN $@ + @$(PYFILE_MAT) 3 double unittest > $@ + +../ZTestSuite/Test-SST_Mat33i.cpp: + @echo GEN $@ + @$(PYFILE_MAT) 3 int unittest > $@ + +../ZTestSuite/Test-SST_Mat33u.cpp: + @echo GEN $@ + @$(PYFILE_MAT) 3 "unsigned int" unittest > $@ + +../ZTestSuite/Test-SST_Mat44f.cpp: + @echo GEN $@ + @$(PYFILE_MAT) 4 float unittest > $@ + +../ZTestSuite/Test-SST_Mat44d.cpp: + @echo GEN $@ + @$(PYFILE_MAT) 4 double unittest > $@ + +../ZTestSuite/Test-SST_Mat44i.cpp: + @echo GEN $@ + @$(PYFILE_MAT) 4 int unittest > $@ + +../ZTestSuite/Test-SST_Mat44u.cpp: + @echo GEN $@ + @$(PYFILE_MAT) 4 "unsigned int" unittest > $@ + +############################### +# THIS IS THE BENCHMARK AREA # +############################### +SST_Mat22f_benchmark.c : + @echo GEN $@ + @$(PYFILE_MAT) 2 float benchmark > $@ + +SST_Mat22d_benchmark.c : + @echo GEN $@ + @$(PYFILE_MAT) 2 double benchmark > $@ + +SST_Mat22i_benchmark.c : + @echo GEN $@ + @$(PYFILE_MAT) 2 int benchmark > $@ + +SST_Mat22u_benchmark.c : + @echo GEN $@ + @$(PYFILE_MAT) 2 "unsigned int" benchmark > $@ + +SST_Mat33f_benchmark.c : + @echo GEN $@ + @$(PYFILE_MAT) 3 float benchmark > $@ + +SST_Mat33d_benchmark.c : + @echo GEN $@ + @$(PYFILE_MAT) 3 double benchmark > $@ + +SST_Mat33i_benchmark.c : + @echo GEN $@ + @$(PYFILE_MAT) 3 int benchmark > $@ + +SST_Mat33u_benchmark.c : + @echo GEN $@ + @$(PYFILE_MAT) 3 "unsigned int" benchmark > $@ + +SST_Mat44f_benchmark.c : + @echo GEN $@ + @$(PYFILE_MAT) 4 float benchmark > $@ + +SST_Mat44d_benchmark.c : + @echo GEN $@ + @$(PYFILE_MAT) 4 double benchmark > $@ + +SST_Mat44i_benchmark.c : + @echo GEN $@ + @$(PYFILE_MAT) 4 int benchmark > $@ + +SST_Mat44u_benchmark.c : + @echo GEN $@ + @$(PYFILE_MAT) 4 "unsigned int" benchmark > $@ + + +# *.c files to *.o files +obj/$(ARCH)/$(TARGET)/%.o: %.c + @echo CC $@ + @$(CC) $(CFLAGS) -c $*.c -o obj/$(ARCH)/$(TARGET)/$*.o + +# *.cpp files to *.o files - specifically used for unit test code check +# This should be removed eventually and handled through the ... ZTestSuite? +obj/$(ARCH)/$(TARGET)/%.o: %.cpp + @echo CXX $@ + @$(CXX) $(CXXFLAGS) -I../Include -I../Lib/Include -c $< -o $@ + +$(CODs) : $(SRC) + $(CC) $(CODFLAG) $(CFLAGS) -c $< > $@ + +assemblers: $(CODs) + +# CLEAN +clean: + @-rm -r -f obj $(DIST)/libsst-math*.a test.bin + +# CLEAN - Gets rid of dynamically generated code as well +cleanall: clean + $(RM) $(OBJ) + $(RM) $(DYNSRC_MAT) + $(RM) $(DYNSRC_VEC) + $(RM) $(DYNTEST) + $(RM) $(DYNUNITTEST) + +all: $(DYNSRC) $(OBJ) $(BINNAME) $(DYNUNITTEST) + +release: $(OBJ) $(BINNAME) diff --git a/libsst-math/MatrixNxN.py b/libsst-math/MatrixNxN.py new file mode 100644 index 0000000..bb7245f --- /dev/null +++ b/libsst-math/MatrixNxN.py @@ -0,0 +1,1702 @@ +#!/usr/bin/env python +from scipy import * +from numpy import * +import re +import sys + +if len(sys.argv) < 3: + sys.exit("Please provide both the number of elements (2-4) and the type of element (float, int, double) at the command line") + +if len(sys.argv) == 3: + DEBUG_PRINT = False + CODE_TYPE = '' + +else: + DEBUG_PRINT = True + CODE_TYPE = sys.argv[3] + +N = int(sys.argv[1]) +N2 = N * N +TYPE = sys.argv[2] + + +tab = 4*' ' +COMMBREAK = '/******************************************************************************/' + + + +#C function table +fabs = {'double' : 'fabs', 'float' : 'fabsf', 'int' : 'abs', 'unsigned int' : ''} +cstyle = {'double' : '%24.15lf', 'float' : '%ff', 'int' : '%d', 'unsigned int' : '%u' } +fp_epsilon = {'double' : 'DBL_EPSILON' , 'float' : 'FLT_EPSILON' , 'int' : '0' , 'unsigned int' : '0'} +size_t = {'double' : 64, 'float' : 32, 'int' : 32, 'unsigned int' : 32} +DTYPE = {'double' : float64 , 'float' : float32 , 'int' : int32 , 'unsigned int' : uint32} + +def levi_civita(i,j,k): + indict = { (1,2,3): 1, + (3,1,2): 1, + (2,3,1): 1, + (1,3,2):-1, + (2,1,3):-1, + (3,2,1):-1} + return indict.get((i,j,k),0) + +def kronecker(i,j): + if(i==j): + return 1 + else: + return 0 + +def cprintf(name,N,M,explode_flag): + if(DEBUG_PRINT): + if(explode_flag): + print('fprintf(stdout,"'+name+'\");') + for i in r_[0:N]: + for j in r_[0:M]: + print('fprintf(stdout,"' + name + '[%d][%d]' % (i,j) + '='+cstyle[TYPE]+'",' + name + '.v[%d]' % (i+N*j) + ');') + print('fprintf(stdout,"\");') + else: + print('fprintf(stdout,"'+name+'\");') + for j in r_[0:M]: + for i in r_[0:N]: + print('fprintf(stdout,"'+cstyle[TYPE]+' ",' + name + '.v[%d]' % (i+N*j) + ');') + print('fprintf(stdout,"\");') + else: + '''N+1 #it gets angry if this isn't here ''' + +def A_op_B(op): + for i in range(N2): + print('\t _A->v[%d] %s _B->v[%d];' % (i, op, i)) + +def A_op_K(op): + for i in range(N2): + print('\t _A->v[%d] %s k;' % (i, op)) + +def A_op_B_eq_Out(op): + for i in range(N2): + print('\t _out->v[%d] = _A->v[%d] %s _B->v[%d];' % (i, i, op, i)) + +def A_op_K_eq_Out(op): + for i in range(N2): + print('\t _out->v[%d] = _A->v[%d] %s k;' % (i, i, op)) + +def commbreak(): + print('\n' + COMMBREAK + '\n'); + +# Generates: out = A op B +def ThreeMatrixFunc(Name, op): + # Function header + print(function_preamble+function_suffix+Name+'(const %s* RESTRICT _A, const %s* RESTRICT _B, %s* RESTRICT _out)\n{' % (MTXTYPE, MTXTYPE, MTXTYPE)) + + #Alignment assumptions + print('\tSST_ASSUME_ALIGNED(_A,16);\n\tSST_ASSUME_ALIGNED(_B,16);\n\tSST_ASSUME_ALIGNED(_out,16);\n') + + #Generate operation + A_op_B_eq_Out(op) + + print("}"); + commbreak(); + +# Generates: A op= B +def TwoMatrixFunc(Name, op): + # Function header + print(function_preamble+function_suffix+Name+'(%s* RESTRICT _A, const %s* RESTRICT _B)\n{' % (MTXTYPE, MTXTYPE)) + + #Alignment assumptions + print('\tSST_ASSUME_ALIGNED(_A,16);\n\tSST_ASSUME_ALIGNED(_B,16);\n') + + #Generate operation + A_op_B(op) + + print("}"); + commbreak(); + +# Generates: A op= K +def MatrixScalarFunc(Name, op): + # Function header + print(function_preamble+function_suffix+Name +'(%s* RESTRICT _A, const %s k)\n{' % (MTXTYPE, TYPE)) + + #Alignment assumptions + print('\tSST_ASSUME_ALIGNED(_A,16);\n') + + #Generate operation + A_op_K(op) + + print("}"); + commbreak(); + +# Generates: out = A op K +def TwoMatrixScalarFunc(Name, op): + # Function header + print(function_preamble+function_suffix+Name+'(const %s* RESTRICT _A, const %s k, %s* RESTRICT _out)\n{' % (MTXTYPE, TYPE, MTXTYPE)) + + #Alignment assumptions + print('\tSST_ASSUME_ALIGNED(_A,16);\n\tSST_ASSUME_ALIGNED(_out,16);\n') + + #Generate operation + A_op_K_eq_Out(op) + + print("}"); + commbreak(); + +rows = r_[0:N] +columns = r_[0:N] + +# FLAGS for use in this generator +PIVOTING_FLAG = True +SINGULAR_FLAG = False +TIMING_CHECK = False +# End of FLAGS + +function_preamble = 'void SST_Math_' +function_suffix = 'Mat%d%d%s' % (N,N,TYPE[0]) +function_call = 'SST_Math_Mat%d%d%s' % (N,N,TYPE[0]) +MTXTYPE = 'SST_Mat%d%d%s' % (N,N,TYPE[0]) +VTXTYPE = 'SST_Vec%d%s' % (N,TYPE[0]) + +if(DEBUG_PRINT != True): + # HEADER + print('/*') + print('\tAUTOMATICALLY GENERATED FILE - DO NOT EDIT!') + print('\tPlease change MatrixNxN.py and re-run it') + print('*/') + print('/* Generated with %s n = %d, TYPE = %s */\n' % (__file__,N,TYPE)) + + print('#include <float.h>') + print('#include <pstdbool.h>') + print('#include <stdio.h>') + print('#include <math.h> /* for sqrt functions */') + print('#include <stdlib.h> /* for the abs/labs functions */') + print('#include <SST/SST_Build.h>\n') + print('#include <SST/%s.h>' % MTXTYPE[0:-1]) + print('#include <SST/%s.h>' % VTXTYPE[0:-1]) + + #Add() + ThreeMatrixFunc("Add", "+") + + #AddLocal() + TwoMatrixFunc("AddLocal", "+=") + + #Sub() + ThreeMatrixFunc("Subtract", "-") + + #SubLocal() + TwoMatrixFunc("SubtractLocal", "-=") + + #MultElem() + ThreeMatrixFunc("MultiplyElementwise", "*") + + #MultElemLocal() + TwoMatrixFunc("MultiplyElementwiseLocal", "*=") + + #MultScalar() + TwoMatrixScalarFunc("MultiplyScalar", "*") + + #MultScalarLocal() + MatrixScalarFunc("MultiplyScalarLocal", "*=") + + function_preamble = function_preamble+function_suffix + print('\n'+function_preamble+'MultiplyMatrix(const %s* _A, const %s* RESTRICT _B, %s* RESTRICT _out)\n{' % (MTXTYPE,MTXTYPE,MTXTYPE) ) + print('SST_ASSUME_ALIGNED(_A,16);\nSST_ASSUME_ALIGNED(_B,16);\nSST_ASSUME_ALIGNED(_out,16);') + for i in rows: + for j in columns: + for k in r_[0:N]: + if(k==0): + outstr ='_out->v[%2d] = _A->v[%2d]*_B->v[%2d]' % (i+N*j,i+N*k,k+N*j) + else: + outstr +='+_A->v[%2d]*_B->v[%2d]' % (i+N*k,k+N*j) + print(outstr+';') + + print('}\n'+function_preamble+'MultiplyMatrixLocal(%s* RESTRICT _A, const %s* RESTRICT _B)\n{' % (MTXTYPE,MTXTYPE) ) + print('\t%s tmp[%d];' % (TYPE,N*N)) + print('\tSST_ASSUME_ALIGNED(_A,16);\nSST_ASSUME_ALIGNED(_B,16);') + for i in rows: + for j in columns: + for k in r_[0:N]: + if(k==0): + outstr ='tmp[%2d] = _A->v[%2d]*_B->v[%2d]' % (i+N*j,i+N*k,k+N*j) + else: + outstr +='+_A->v[%2d]*_B->v[%2d]' % (i+N*k,k+N*j) + print(outstr+';') + for j in columns: + print('_A->v[%d] = tmp[%d];' % (i+N*j,i+N*j)) + print('\n') + + print('}\n'+function_preamble+'MultiplyVector(const %s* RESTRICT _A, const %s* RESTRICT _v, %s* RESTRICT _out)\n{' % (MTXTYPE,VTXTYPE,VTXTYPE) ) + print('SST_ASSUME_ALIGNED(_A,16);\nSST_ASSUME_ALIGNED(_v,16);\nSST_ASSUME_ALIGNED(_out,16);') + for i in r_[0:N]: + outstr='_out->v[%2d] = _A->v[%2d]*_v->v[0]' % (i,i) + for j in r_[1:N]: + outstr+='+_A->v[%2d]*_v->v[%d]' % (i+N*j,j) + outstr+=';' + print(outstr) + + print('}\n'+function_preamble+'MultiplyVectorLocal(const %s* RESTRICT _A, %s* RESTRICT _v)\n{' % (MTXTYPE,VTXTYPE) ) + print('%s tmp[%d];' % (TYPE,N)) + print('SST_ASSUME_ALIGNED(_A,16);\nSST_ASSUME_ALIGNED(_v,16);') + for i in r_[0:N]: + outstr='tmp[%2d] = _A->v[%2d]*_v->v[0]' % (i,i) + for j in r_[1:N]: + outstr+='+_A->v[%2d]*_v->v[%d]' % (i+N*j,j) + outstr+=';' + print(outstr) + for i in r_[0:N]: + print('_v->v[%d] = tmp[%d];' % (i,i)); + print('}\n'+function_preamble+'Transpose(const %s* RESTRICT _A, %s* RESTRICT _out)\n{' % (MTXTYPE,MTXTYPE) ) + print('SST_ASSUME_ALIGNED(_A,16);\nSST_ASSUME_ALIGNED(_out,16);') + for i in r_[0:N]: + for j in r_[0:N]: + print('_out->v[%2d] = _A->v[%2d];' % (j+N*i,i+N*j)) + + print('}\n'+function_preamble+'TransposeLocal(%s* RESTRICT _A)\n{' % (MTXTYPE) ) + print('%s tmp[%d];' % (TYPE,N)) + print('SST_ASSUME_ALIGNED(_A,16);') + for i in r_[0:N]: + for j in r_[i:N]: + if(i!=j): + print('tmp[%d] = _A->v[%2d];' % (j,i+N*j)) + print('_A->v[%2d] = _A->v[%2d];' % (i+N*j,j+N*i)) + print('_A->v[%2d] = tmp[%d];' % (j+N*i,j)) + + if((TYPE != 'unsigned int')): + print('}\n'+re.sub(r"void",'bool',function_preamble)+'CheckOrthonormal(const %s* _A)\n{' % (MTXTYPE) ) + '''trans(M)*M = I if its Orthonormal''' + outstr ='((%s(' % fabs[TYPE]+ ('%s' % cstyle[TYPE]) % (N) + outstr2 ='((%s(' % fabs[TYPE] + outstr3 ='const %s diag =' % TYPE + outstr4 ='const %s odiag =' % TYPE + for i in rows: + for j in columns: + for k in r_[0:N]: + if(i==j): + outstr3 +=' -_A->v[%d]*_A->v[%d]' % (k+N*i,k+N*j) + else: + outstr4 +='+ _A->v[%d]*_A->v[%d]' % (k+N*i,k+N*j) + + outstr3+=';' + outstr4=re.sub("=\+",'=',outstr4)+';' + outstr+='+diag)) <= 100*%s) &' % fp_epsilon[TYPE] + outstr2+='odiag)) <= 100*%s);' % fp_epsilon[TYPE] + print(outstr3) + print(outstr4) + #print('fprintf(stdout,"diag = '+('%s' % cstyle[TYPE])+'\\n",%d+diag);' % (N)) + #print('fprintf(stdout,"odiag = '+('%s' % cstyle[TYPE])+'\\n",odiag);') + print('SST_ASSUME_ALIGNED(_A,16);') + print('return ') + print(outstr) + print(outstr2) + print('\n') + + print('}\n'+re.sub(r"void",TYPE,function_preamble)+'Determinant(const %s* _A)\n{' % (MTXTYPE) ) + # we're just going to use the first row... though I have an idea for an algo + # that might actually make the determinant feasibly useful for later calcs. + # A couple properties to remember: + # det(A) = det(LU) = det(L)det(U) = det(U) | det(L) ~ O(n) operations + # (L or U will have 1s on the diagonal) + # + if(N==2): + print('\tconst %s result = _A->v[0]*_A->v[3]-_A->v[1]*_A->v[2];' % (TYPE)) + print('\tSST_ASSUME_ALIGNED(_A,16);') + print('\treturn result;') + if(N==3): + print('\tconst %s result = _A->v[0]*(_A->v[4]*_A->v[8]-_A->v[5]*_A->v[7])-_A->v[1]*(_A->v[3]*_A->v[8]-_A->v[6]*_A->v[5])+_A->v[2]*(_A->v[3]*_A->v[7]-_A->v[6]*_A->v[4]);' % (TYPE)) + print('\tSST_ASSUME_ALIGNED(_A,16);') + print('\treturn result;') + # [[0 1 2 3] + # [4 5 6 7] + # [8 9 10 11] + # [12 13 14 15]] + # + # [[0 4 8 12] + # [1 5 9 13] + # [2 6 10 14] + # [3 7 11 15]] + # + if(N==4): + print('\tconst %s a10151411 = _A->v[10]*_A->v[15]-_A->v[11]*_A->v[14];' % TYPE) + print('\tconst %s a9151311 = _A->v[6]*_A->v[15]-_A->v[7]*_A->v[14];' % TYPE) + print('\tconst %s a9141310 = _A->v[6]*_A->v[11]-_A->v[7]*_A->v[10];' % TYPE) + print('\tconst %s a8151112 = _A->v[2]*_A->v[15]-_A->v[14]*_A->v[3];' % TYPE) + print('\tconst %s a8141210 = _A->v[2]*_A->v[11]-_A->v[3]*_A->v[10];' % TYPE) + print('\tconst %s a813129 = _A->v[2]*_A->v[7]-_A->v[3]*_A->v[6];' % TYPE) + print('\tconst %s result = _A->v[0]*(_A->v[5]*a10151411-_A->v[9]*a9151311+_A->v[13]*a9141310)' % (TYPE) + +'-_A->v[4]*(_A->v[1]*a10151411-_A->v[9]*a8151112+_A->v[13]*a8141210)' + +'+_A->v[8]*(_A->v[1]*a9151311 -_A->v[5]*a8151112+_A->v[13]*a813129)' + +'-_A->v[12]*(_A->v[1]*a9141310 -_A->v[5]*a8141210+_A->v[9]*a813129);' ) + print('\tSST_ASSUME_ALIGNED(_A,16);') + print('\treturn result;') + + + if((TYPE != 'int') & (TYPE != 'unsigned int')): + print('}\n'+function_preamble+'Invert(const %s* RESTRICT _A, %s* RESTRICT _out)\n{' % (MTXTYPE,MTXTYPE) ) + if(N==2): + print('/* Analytical Invert for 2x2 */') + print('const %s aij = (%s) / (_A->v[0]*_A->v[3]-_A->v[1]*_A->v[2]);' % (TYPE,cstyle[TYPE] % (1))) + print('SST_ASSUME_ALIGNED(_A,16);') + print('_out->v[0] = aij*_A->v[3];\n_out->v[1] = -aij*_A->v[1];\n_out->v[2] = -aij*_A->v[2];\n_out->v[3] = aij*_A->v[0];\n') + else: + # Gauss elimination + print('/* Gaussian Elimination */') + print('#define _A(i,j) _A->v[i+%d*j]' % (N)) + print('#define _out(i,j) _out->v[i+%d*j]' % (N)) + print('#define Pinv(i,j) Pinv.v[i+%d*j]' % (N)) + print('%s aij;' % TYPE) + print('%s norm_aij;' % (TYPE)) + print('%s Pinv;' % (MTXTYPE)) + print('SST_ASSUME_ALIGNED(_A,16);') + print('/* Set _out to the identity */') + + for j in r_[0:N]: + for i in r_[0:N]: + print('_out(%d,%d) = ' % (i,j) + (cstyle[TYPE] % (kronecker(i,j))) + ';') + + print("/* Set _Pinv to _A so we don't overwrite it */") + for i in r_[0:N*N]: + print('Pinv.v[%d] = _A->v[%d];' % (i,i)) + + cprintf('_out',N,N,False) + cprintf('Pinv',N,N,False) + + print('/* Put in Reduced Row Echelon form */') + print('/* Note that we can set the entry to 0, or just calculate it. \n The latter will be helpful when recognizing that these are all simple vector moves */') + for i in r_[0:N]: + for k in r_[i+1:N]: + print('/* Sort if need be */') + print('aij = -Pinv(%d,%d) / Pinv(%d,%d) ;' % (k,i,i,i)) + for j in r_[0:N]: + print('Pinv(%d,%d) += aij*Pinv(%d,%d) ;' % (k,j,i,j)) + cprintf('Pinv',N,N,False) + for j in r_[0:N]: + print('_out(%d,%d) += aij*_out(%d,%d) ;' % (k,j,i,j)) + cprintf('_out',N,N,False) + + print('/* Backsubstitution */') + for k in r_[(N-1):-1:-1]: + print('norm_aij = %s / Pinv(%d,%d) ;' % ((cstyle[TYPE] % (1)),k,k)) + print('Pinv(%d,%d) = %s;' % (k,k,(cstyle[TYPE] % (1)))) + for l in r_[0:N]: + print('_out(%d,%d) *= norm_aij;' % (k,l)) + for i in r_[0:k]: + print('aij = -Pinv(%d,%d);' % (i,k)) + for j in r_[0:N]: + print('Pinv(%d,%d) += aij*Pinv(%d,%d);' % (i,j,k,j)) + cprintf('Pinv',N,N,False) + for j in r_[0:N]: + print('_out(%d,%d) += aij*_out(%d,%d);' % (i,j,k,j)) + cprintf('_out',N,N,False) + print('#undef _A') + print('#undef _out') + print('#undef Pinv') + + + print('}\n'+function_preamble+'InvertLocal(%s* RESTRICT _A)\n{' % (MTXTYPE) ) + if(N==2): + print('/* Analytical Invert for 2x2 */') + print('const %s aij = (%s) / (_A->v[0]*_A->v[3]-_A->v[1]*_A->v[2]);' % (TYPE,cstyle[TYPE] % (1))) + print('const %s tmp = _A->v[0];' % (TYPE)) + print('SST_ASSUME_ALIGNED(_A,16);') + print('_A->v[0] = aij*_A->v[3];\n_A->v[1] *= -aij;\n_A->v[2] *= -aij;\n_A->v[3] = aij*tmp;\n') + else: + # Gauss elimination + print('/* Gaussian Elimination */') + print('#define _A(i,j) _A->v[i+%d*j]' % (N)) + print('#define out(i,j) out->v[i+%d*j]' % (N)) + print('#define Pinv(i,j) Pinv.v[i+%d*j]' % (N)) + print('%s aij;' % TYPE) + print('%s norm_aij;' % (TYPE)) + print('%s Pinv;' % (MTXTYPE)) + print('SST_ASSUME_ALIGNED(_A,16);') + print('/* Set _out to the identity */') + + print("/* Set _Pinv to _A so we don't overwrite it */") + for i in r_[0:N*N]: + print('Pinv.v[%d] = _A->v[%d];' % (i,i)) + + for j in r_[0:N]: + for i in r_[0:N]: + print('_A(%d,%d) = ' % (i,j) + (cstyle[TYPE] % (kronecker(i,j))) + ';') + + + cprintf('_A',N,N,False) + cprintf('Pinv',N,N,False) + + print('/* Put in Reduced Row Echelon form */') + print('/* Note that we can set the entry to 0, or just calculate it. \n The latter will be helpful when recognizing that these are all simple vector moves */') + for i in r_[0:N]: + for k in r_[i+1:N]: + print('/* Sort if need be */') + print('aij = -Pinv(%d,%d) / Pinv(%d,%d) ;' % (k,i,i,i)) + for j in r_[0:N]: + print('Pinv(%d,%d) += aij*Pinv(%d,%d) ;' % (k,j,i,j)) + cprintf('Pinv',N,N,False) + for j in r_[0:N]: + print('_A(%d,%d) += aij*_A(%d,%d) ;' % (k,j,i,j)) + cprintf('_A',N,N,False) + + print('/* Backsubstitution */') + for k in r_[(N-1):-1:-1]: + print('norm_aij = %s / Pinv(%d,%d) ;' % ((cstyle[TYPE] % (1)),k,k)) + print('Pinv(%d,%d) = %s;' % (k,k,(cstyle[TYPE] % (1)))) + for l in r_[0:N]: + print('_A(%d,%d) *= norm_aij;' % (k,l)) + for i in r_[0:k]: + print('aij = -Pinv.v[%d];' % (i+N*k)) + for j in r_[0:N]: + print('Pinv.v[%d] += aij*Pinv.v[%d];' % (i+N*j,k+N*j)) + cprintf('Pinv',N,N,False) + for j in r_[0:N]: + print('_A->v[%d] += aij*_A->v[%d];' % (i+N*j,k+N*j)) + cprintf('_A',N,N,False) + + + + print('}\n'+function_preamble+'CreateLU(const %s* RESTRICT _A, %s* RESTRICT _LU)\n{' % (MTXTYPE,MTXTYPE) ) + print('#define _A(i,j) _A->v[i+%d*j]' % (N)) + print('#define _LU(i,j) _LU->v[i+%d*j]' % (N)) + print(tab+'int i,j,k;') + print(tab+TYPE+' sum;') + print('SST_ASSUME_ALIGNED(_A,16);') + print('SST_ASSUME_ALIGNED(_LU,16);') + for i in rows: + print(tab+'_LU(%d,0) = _A(%d,0);' % (i,i)) + for j in r_[i+1:N]: + print(tab+'_LU(%d,%d) = 0;' % (i,j)) + + for i in rows: + print(tab+'/* _U(%d,%d) = ' % (i,i) + (('%s; */' % cstyle[TYPE]) % (1)) ) + + for i in r_[1:N]: + print(tab+'_LU(0,%d) = _A(0,%d) / _LU(0,0);' % (i,i)) + + print((tab+'for(i=1; i < %d; i++) {\n') %(N)) + print(2*tab+'for(j=1; j <= i; j++) {') + print(3*tab+'sum = '+('%s;' % cstyle[TYPE]) % (0)) + print(3*tab+'for(k=0; k < j; k++)') + print(4*tab+'sum += -_LU(i,k)*_LU(k,j);') + print(3*tab+'_LU(i,j) = _A(i,j) + sum;\n%s}' % (2*tab)) + print(2*tab+'for(j=i+1; j < %d; j++) {' % (N)) + print(3*tab+'sum = '+('%s;' % cstyle[TYPE]) % (0)) + print(3*tab+'for(k=0; k < i; k++)') + print(4*tab+'sum += -_LU(i,k)*_LU(k,j);') + print(3*tab+'_LU(i,j) = (_A(i,j) + sum) / _LU(i,i);\n%s}' % (2*tab)) + print(tab+'}') + print('#undef _A') + print('#undef _LU') + + print('}\n'+function_preamble+'ApplyLUMat(const %s* _LU, const %s* _A, %s* _out)\n{\n ' % (MTXTYPE,MTXTYPE,MTXTYPE) ) + print('#define _LU(i,j) _LU->v[i+%d*j]' % (N)) + print('#define _A(i,j) _A->v[i+%d*j]' % (N)) + print('#define _out(i,j) _out->v[i+%d*j]' % (N)) + + print(tab+'int i, j, col;') + print(tab+'%s sum;' % TYPE); + print('SST_ASSUME_ALIGNED(_A,16);') + print('SST_ASSUME_ALIGNED(_LU,16);') + print('SST_ASSUME_ALIGNED(_out,16);') + print(tab+'for(col = 0; col < %d; col++) {' % (N)) + for k in r_[0:N]: + print(tab+tab+'_out(%d,col) = _A(%d,col);' % (k,k) ) + print(tab+tab+'/* Forward Substitution for Ly = v */') + print(tab+tab+'for(i = 0; i < %d; i++) {' % (N)) + print(2*tab+tab+'sum = %s;' % (cstyle[TYPE] % (0)) ) + print(2*tab+tab+'for(j = 0; j < i; j++)' ) + print(3*tab+tab+'sum += _LU(i,j) * _out(j,col);') + print(2*tab+tab+'_out(i,col) = (_out(i,col) - sum) / _LU(i,i) ;') + print(tab+tab + '}' ) + print('/* Backwards Substitution for Uw = y */') + print(tab+tab+'for(i = %d; i >=0; i--) {' % (N-1)) + print(2*tab+tab+'sum = %s;' % (cstyle[TYPE] % (0)) ) + print(2*tab+tab+'for(j = i+1; j < %d; j++)' %(N) ) + print(3*tab+tab+'sum += _LU(i,j) * _out(j,col);') + print(2*tab+tab+'_out(i,col) = (_out(i,col) - sum) ; /* divide by U(i,i)=1 */') + print(tab+tab + '}' ) + print(tab + '}' ) + + print('#undef _LU /* (i,j) _LU->v[i+%d*j] */' % (N)) + print('#undef _A /* (i,j) _A->v[i+%d*j] */' % (N)) + print('#undef _out /* (i,j) _out->v[i+%d*j] */' % (N)) + + print('}\n'+function_preamble+'ApplyLUMatLocal(const %s* _LU,%s* _A)\n{\n ' % (MTXTYPE,MTXTYPE) ) + print('#define _LU(i,j) _LU->v[i+%d*j]' % (N)) + print('#define _A(i,j) _A->v[i+%d*j]' % (N)) + print(tab+'int i, j, col;') + print(tab+'%s sum;' % TYPE); + print(tab+'for(col = 0; col < %d; col++) {' % (N)) + print(tab+tab+'/* Forward Substitution for Ly = v */') + print(tab+tab+'for(i = 0; i < %d; i++) {' % (N)) + print(2*tab+tab+'sum = %s;' % (cstyle[TYPE] % (0)) ) + print(2*tab+tab+'for(j = 0; j < i; j++)' ) + print(3*tab+tab+'sum += _LU(i,j) * _A(j,col);') + print(2*tab+tab+'_A(i,col) = (_A(i,col) - sum) / _LU(i,i) ;') + print(tab+tab + '}' ) + print('/* Backwards Substitution for Uw = y */') + print(tab+tab+'for(i = %d; i >=0; i--) {' % (N-1)) + print(2*tab+tab+'sum = %s;' % (cstyle[TYPE] % (0)) ) + print(2*tab+tab+'for(j = i+1; j < %d; j++)' %(N) ) + print(3*tab+tab+'sum += _LU(i,j) * _A(j,col);') + print(2*tab+tab+'_A(i,col) = (_A(i,col) - sum) ; /* U is 1s along the diagonal */') + print(tab+tab + '}' ) + print(tab + '}' ) + + print('}\n'+function_preamble+'ApplyLUVec(const %s* _LU, const %s* _v,%s* _w)\n{\n ' % (MTXTYPE,VTXTYPE,VTXTYPE) ) + print('#define _LU(i,j) _LU->v[i+%d*j]' % (N)) + print(tab+'int i, j;') + print(tab+'%s sum;' % TYPE); + for k in r_[0:N]: + print(tab+'_w->v[%d] = _v->v[%d];' % (k,k) ) + print(tab+'/* Forward Substitution for Ly = v */') + print(tab+'for(i = 0; i < %d; i++) {' % (N)) + print(2*tab+'sum = %s;' % (cstyle[TYPE] % (0)) ) + print(2*tab+'for(j = 0; j < i; j++)' ) + print(3*tab+'sum += _LU(i,j) * _w->v[j];') + print(2*tab+'_w->v[i] = (_w->v[i] - sum) / _LU(i,i) ;') + print(tab + '}' ) + print('/* Backwards Substitution for Uw = y */') + print(tab+'for(i = %d; i >= 0; i--) {' % (N-1)) + print(2*tab+'sum = %s;' % (cstyle[TYPE] % (0)) ) + print(2*tab+'for(j = i+1; j < %d; j++)' %(N) ) + print(3*tab+'sum += _LU(i,j) * _w->v[j];') + print(2*tab+'/*_w->v[i] = (_w->v[i] - sum) ;*/') + print(2*tab+'_w->v[i] = (_w->v[i] - sum) ;') + print(tab + '}' ) + print('#undef _LU /* (i,j) _LU->v[i+%d*j] */' % (N)) + + print('}\n'+function_preamble+'ApplyLUVecLocal(const %s* _LU,%s* _w)\n{\n ' % (MTXTYPE,VTXTYPE) ) + print('#define _LU(i,j) _LU->v[i+%d*j]' % (N)) + print(tab+'int i, j;') + print(tab+'%s sum;' % TYPE); + print(tab+'/* Forward Substitution for Ly = v */') + print(tab+'for(i = 0; i < %d; i++) {' % (N)) + print(2*tab+'sum = %s;' % (cstyle[TYPE] % (0)) ) + print(2*tab+'for(j = 0; j < i; j++)' ) + print(3*tab+'sum += _LU(i,j) * _w->v[j];') + print(2*tab+'_w->v[i] = (_w->v[i] - sum) / _LU(i,i) ;') + print(tab + '}' ) + print('/* Backwards Substitution for Uw = y */') + print(tab+'for(i = %d; i >= 0; i--) {' % (N-1)) + print(2*tab+'sum = %s;' % (cstyle[TYPE] % (0)) ) + print(2*tab+'for(j = i+1; j < %d; j++)' %(N) ) + print(3*tab+'sum += _LU(i,j) * _w->v[j];') + print(2*tab+'/*_w->v[i] = (_w->v[i] - sum) ;*/') + print(2*tab+'_w->v[i] = (_w->v[i] - sum) ;') + print(tab + '}' ) + print('#undef _LU /* (i,j) _LU->v[i+%d*j] */' % (N)) + + print('}\n'+function_preamble+'CreateLULocal(%s* RESTRICT _A)\n{\n /* Note this code stores both L and U inside of A */' % (MTXTYPE) ) + print(' /* For A in R[n x m] we say that for n = m there is an LU = A decomposition [In our decomp, diag[L] = I. Furthermore there is an LU=PA decomposition, where P is a permutation matrix\n Step 1: U(i,i:m) = A(i,i:m) \n Step 2: L(i+1:n,i) = -A(i+1:n,i) \n Step 3: ??? \n Step 4: Profit */ ') + print('#define _A(i,j) _A->v[i+%d*j]' % (N)) + print(tab+'int i,j,k;') + print(tab+TYPE+' sum;') + + print('/* These entries are the same as before in the algorithm. This is left in for purposes of clarity and completeness ') + for i in rows: + print('_L(%d,0) = _A(%d,0);' % (i,i)) + print('These entries are understood to be 1 in this storage format. This is left in for purposes of clarity and completeness ') + for i in rows: + print('_U(%d,%d) = ' % (i,i) + (('%s;' % cstyle[TYPE]) % (1)) ) + print('*/') + + for i in r_[1:N]: + print('_A(0,%d) = _A(0,%d) / _A(0,0);' % (i,i)) + + + print((tab+'for(i=1; i < %d; i++) {\n') %(N)) + print(2*tab+'for(j=0; j <= i; j++) {') + print(3*tab+'sum = '+('%s;' % cstyle[TYPE]) % (0)) + print(3*tab+'for(k=0; k < j; k++) sum += -_A(i,k)*_A(k,j);') + print(3*tab+'_A(i,j) = _A(i,j) + sum;\n%s}' % (2*tab)) + print(2*tab+'for(j=i+1; j < %d; j++) {' % (N)) + print(3*tab+'sum = '+('%s;' % cstyle[TYPE]) % (0)) + print(3*tab+'for(k=0; k < i; k++) sum += -_A(i,k)*_A(k,j);') + print(3*tab+'_A(i,j) = (_A(i,j) + sum) / _A(i,i);\n%s}' % (2*tab)) + print(tab+'}') + print('#undef _A') + + print('}') +def resetMats(choices = ['v','X','Y']): + if(TYPE=='unsigned int'): + low = 0 + high = 40 + else: + low = -20 + high = 20 + + print('/* Resetting test vectors / mats */') + v = array(random.randint(low,high,N),dtype=DTYPE[TYPE]) + X = asfortranarray(random.randint(low,high,(N,N)),dtype=DTYPE[TYPE]) + Y = asfortranarray(random.randint(low,high,(N,N)),dtype=DTYPE[TYPE]) + if 'v' in choices: + '''print('/* v') + print(v) + print('*/')''' + for i in rows: + print(tab+'v.v[%d] = ' % i + ('%s' % cstyle[TYPE]) % (v[i])+';') + + if 'X' in choices: + '''print('/* X') + print(X) + print('*/')''' + for j in columns: + for i in rows: + print(tab+'X.v[%d] = ' %(i+N*j) + (('%s' % cstyle[TYPE]) % (X[i,j]))+';') + + if 'Y' in choices: + '''print('/* Y') + print(Y) + print('*/')''' + for j in columns: + for i in rows: + print(tab+'Y.v[%d] = ' %(i+N*j) + (('%s' % cstyle[TYPE]) % (Y[i,j]))+';') + + return v,X,Y + +def Equals(str1,str2): + if((TYPE=='int') | (TYPE=='unsigned int')): + return '('+str1+')==('+str2+')' + else: + return '%s((' % fabs[TYPE] + str1+')-('+str2+')) <=100*%s /* yes this is bad */' % (fp_epsilon[TYPE]) + +def ZUnitTestPair( testname , additional_endchars = ','): + print('{ "%-45s" , %-45s }' %(testname,testname)+additional_endchars) + +# Variable Setup +def VariableSetup(vars=['X','Y','A']): + for mat in ['X','Y','A','B']: + if mat in vars: print(tab+'%s %1s; /* %d x %d matrix */' % (MTXTYPE,mat,N,N)) + + for vec in ['v','w']: + if vec in vars: print(tab+'SST_Vec%s %1s; /* %d vector */' % (MTXTYPE[-2::],vec,N)) + +def EndTest(): + print(tab+'return ZTEST_SUCCESS;\n}') + +#Generate Unit Test code +if(CODE_TYPE == 'unittest'): + print('/*') + print('\tAUTOMATICALLY GENERATED FILE - DO NOT EDIT!') + print('\tPlease change MatrixNxN.py and re-run it') + print('*/') + print('/* Generated with %s n = %d, TYPE = %s */\n' % (__file__,N,TYPE)) + + print('#include "ZUnitTest.hpp"') + print('#include <float.h>') + print('#include <math.h>') + print('#include <stdlib.h>') + print('#include <stdio.h>') + print('#include <SST/%s.h>' % MTXTYPE[0:-1]) + print('#include <SST/%s.h>' % VTXTYPE[0:-1]) + print('\n\n\n') + + unittest_preamble = 'static const char* test' + print(unittest_preamble+function_call+'Add();') + print(unittest_preamble+function_call+'AddLocal();') + print(unittest_preamble+function_call+'Subtract();') + print(unittest_preamble+function_call+'SubtractLocal();') + print(unittest_preamble+function_call+'MultiplyElementwise();') + print(unittest_preamble+function_call+'MultiplyElementwiseLocal();') + print(unittest_preamble+function_call+'MultiplyScalar();') + print(unittest_preamble+function_call+'MultiplyScalarLocal();') + print(unittest_preamble+function_call+'MultiplyMatrix();') + print(unittest_preamble+function_call+'MultiplyMatrixLocal();') + print(unittest_preamble+function_call+'MultiplyVector();') + print(unittest_preamble+function_call+'MultiplyVectorLocal();') + print(unittest_preamble+function_call+'Transpose();') + print(unittest_preamble+function_call+'TransposeLocal();') + if((TYPE!='unsigned int')): + print(unittest_preamble+function_call+'Determinant();') + print(unittest_preamble+function_call+'CheckOrthonormal();') + if((TYPE!='int') & (TYPE!='unsigned int')): + print(unittest_preamble+function_call+'Invert();') + print(unittest_preamble+function_call+'InvertLocal();') + print(unittest_preamble+function_call+'CreateLU();') + print(unittest_preamble+function_call+'CreateLULocal();') + print(unittest_preamble+function_call+'ApplyLUMat();') + print(unittest_preamble+function_call+'ApplyLUMatLocal();') + print(unittest_preamble+function_call+'ApplyLUVec();') + print(unittest_preamble+function_call+'ApplyLUVecLocal();') + + print('// List of unit tests ') + print('ZUnitTest '+function_call+'UnitTests[] = \n{') + ZUnitTestPair('test'+function_call+'Add') + ZUnitTestPair('test'+function_call+'AddLocal') + ZUnitTestPair('test'+function_call+'Subtract') + ZUnitTestPair('test'+function_call+'SubtractLocal') + ZUnitTestPair('test'+function_call+'MultiplyElementwise') + ZUnitTestPair('test'+function_call+'MultiplyElementwiseLocal') + ZUnitTestPair('test'+function_call+'MultiplyScalar') + ZUnitTestPair('test'+function_call+'MultiplyScalarLocal') + ZUnitTestPair('test'+function_call+'MultiplyMatrix') + ZUnitTestPair('test'+function_call+'MultiplyMatrixLocal') + ZUnitTestPair('test'+function_call+'MultiplyVector') + ZUnitTestPair('test'+function_call+'MultiplyVectorLocal') + if((TYPE!='unsigned int')): + ZUnitTestPair('test'+function_call+'Determinant') + ZUnitTestPair('test'+function_call+'CheckOrthonormal') + if((TYPE!='int') & (TYPE!='unsigned int')): + ZUnitTestPair('test'+function_call+'Invert') + ZUnitTestPair('test'+function_call+'InvertLocal') + ZUnitTestPair('test'+function_call+'CreateLU') + ZUnitTestPair('test'+function_call+'CreateLULocal') + ZUnitTestPair('test'+function_call+'ApplyLUMat') + ZUnitTestPair('test'+function_call+'ApplyLUMatLocal') + ZUnitTestPair('test'+function_call+'ApplyLUVec') + ZUnitTestPair('test'+function_call+'ApplyLUVecLocal') + ZUnitTestPair('test'+function_call+'Transpose') + ZUnitTestPair('test'+function_call+'TransposeLocal','\n};') + + print('DECLARE_ZTESTBLOCK('+function_call+')') + + commbreak() + + print(unittest_preamble+function_call+'Add(){') + VariableSetup(vars=['X','Y','A']) + v,X,Y = resetMats(['X','Y']) + print('/*') + print(X) + print(Y) + print(X+Y) + print('*/') + print(tab+function_call+'Add(&X,&Y,&A);') + for i in rows: + for j in columns: + print(tab+'TASSERT('+Equals('A.v[%d]' % (i+N*j), ('%s' % cstyle[TYPE]) % (X[i,j]+Y[i,j]))+',"Entry _a%d%d failed!"' % (i+1,j+1) + ');') + EndTest() + + commbreak() + + print(unittest_preamble+function_call+'AddLocal(){') + VariableSetup(vars = ['X','Y']) + v,X,Y = resetMats(['X','Y']) + print('/*') + print(X) + print(Y) + print(X+Y) + print('*/') + print(tab+function_call+'AddLocal(&X,&Y); /* for accuracy */') + for i in rows: + for j in columns: + print(tab+'TASSERT('+Equals('X.v[%d]' % (i+N*j), ('%s' % cstyle[TYPE]) % (X[i,j]+Y[i,j]))+',"Entry _a%d%d failed!"' % (i+1,j+1)+');') + EndTest() + + commbreak() + + print(unittest_preamble+function_call+'Subtract(){') + VariableSetup(vars=['X','Y','A']) + v,X,Y = resetMats(['X','Y']) + print('/*') + print(X) + print(Y) + print(X-Y) + print('*/') + print(tab+function_call+'Subtract(&X,&Y,&A);') + for i in rows: + for j in columns: + print(tab+'TASSERT('+Equals('A.v[%d]' % (i+N*j), ('%s' % cstyle[TYPE]) % (X[i,j]-Y[i,j]))+',"Entry _a%d%d failed!"' % (i+1,j+1)+');') + EndTest() + + commbreak() + + print(unittest_preamble+function_call+'SubtractLocal(){') + VariableSetup(vars=['X','Y']) + v,X,Y = resetMats(['X','Y']) + print('/*') + print(X) + print(Y) + print(X-Y) + print('*/') + print(tab+function_call+'SubtractLocal(&X,&Y); /* for accuracy */') + for i in rows: + for j in columns: + print(tab+'TASSERT('+Equals('X.v[%d]' % (i+N*j), ('%s' % cstyle[TYPE]) % (X[i,j]-Y[i,j]))+',"Entry _a%d%d failed!"' % (i+1,j+1)+');') + EndTest() + + commbreak() + + print(unittest_preamble+function_call+'MultiplyElementwise(){') + VariableSetup(vars=['X','Y','A']) + v,X,Y = resetMats(['X','Y']) + print('/*') + print(X) + print(Y) + print(X*Y) + print('*/') + print(tab+function_call+'MultiplyElementwise(&X, &Y, &A);') + for i in rows: + for j in columns: + print(tab+'TASSERT('+Equals('A.v[%d]' % (i+N*j), ('%s' % cstyle[TYPE]) % (Y[i,j]*X[i,j]))+',"Entry _a%d%d failed!"' % (i+1,j+1) + ');') + EndTest() + + commbreak() + + print(unittest_preamble+function_call+'MultiplyElementwiseLocal(){') + VariableSetup(vars=['X','Y']) + v,X,Y = resetMats(['X','Y']) + print('/*') + print(X) + print(Y) + print(X*Y) + print('*/') + print(tab+function_call+'MultiplyElementwiseLocal(&X,&Y);') + for i in rows: + for j in columns: + print(tab+'TASSERT('+Equals('X.v[%d]' % (i+N*j), ('%s' % cstyle[TYPE]) % (Y[i,j]*X[i,j]))+',"Entry _a%d%d failed!"' % (i+1,j+1) + ');') + EndTest() + + commbreak() + + print(unittest_preamble+function_call+'MultiplyScalar(){') + VariableSetup(vars=['X','A']) + v,X,Y = resetMats(['X']) + print('/*') + print(X) + print(2*X) + print('*/') + print(tab+function_call+'MultiplyScalar(&X,'+('%s'%cstyle[TYPE])%(2)+',&A);') + for i in rows: + for j in columns: + print(tab+'TASSERT('+Equals('A.v[%d]' % (i+N*j), ('%s' % cstyle[TYPE]) % (2*X[i,j]))+',"Entry _a%d%d failed!"' % (i+1,j+1) + ');') + EndTest() + + commbreak() + + print(unittest_preamble+function_call+'MultiplyScalarLocal(){') + VariableSetup(vars=['X']) + v,X,Y = resetMats(['X']) + print('/*') + print(X) + print(2*X) + print('*/') + print(tab+function_call+'MultiplyScalarLocal(&X,'+('%s'%cstyle[TYPE]%2)+');') + for i in rows: + for j in columns: + print(tab+'TASSERT('+Equals('X.v[%d]' % (i+N*j), ('%s' % cstyle[TYPE]) % (2*X[i,j]))+',"Entry _a%d%d failed!"' % (i+1,j+1) + ');') + EndTest() + + commbreak() + + print(unittest_preamble+function_call+'MultiplyMatrix(){') + VariableSetup(vars=['X','Y','A']) + v,X,Y = resetMats(['X','Y']) + + A = dot(reshape(X,(N,N)),reshape(Y,(N,N))) + print('/*') + print('X') + print(reshape(X,(N,N))) + print('Y') + print(reshape(Y,(N,N))) + print(A) + print('*/') + print(tab+function_call+'MultiplyMatrix(&X,&Y,&A);') + for i in rows: + for j in columns: + print(tab+'TASSERT('+Equals('A.v[%d]' % (i+N*j), ('%s' % cstyle[TYPE]) % (A[i][j]))+',"Entry _a%d%d failed!"' % (i+1,j+1) + ');') + EndTest() + + commbreak() + + print(unittest_preamble+function_call+'MultiplyMatrixLocal(){') + VariableSetup(vars=['X','Y']) + v,X,Y = resetMats(['X','Y']) + + A = dot(reshape(X,(N,N)),reshape(Y,(N,N))) + print('/*') + print('X') + print(reshape(X,(N,N))) + print('Y') + print(reshape(Y,(N,N))) + print('X') + print(A) + print('*/') + print(tab+function_call+'MultiplyMatrixLocal(&X,&Y);') + for i in rows: + for j in columns: + print(tab+'TASSERT('+Equals('X.v[%d]' % (i+N*j), ('%s' % cstyle[TYPE]) % (A[i][j]))+',"Entry _a%d%d failed!"' % (i+1,j+1) + ');') + EndTest() + + commbreak() + + print(unittest_preamble+function_call+'MultiplyVector(){') + VariableSetup(vars=['v','X','w']) + v,X,Y = resetMats(['v','X']) + w = dot(reshape(X,(N,N)),v) + print('/*') + print('X') + print(X) + print('v') + print(v) + print('w') + print(w) + print('*/') + print(tab+function_call+'MultiplyVector(&X,&v,&w);') + for i in rows: + print(tab+'TASSERT('+Equals('w.v[%d]' % (i), ('%s' % cstyle[TYPE]) % (w[i]))+',"Entry .v[%d] failed!"' % (i) + ');') + EndTest() + + commbreak() + + print(unittest_preamble+function_call+'MultiplyVectorLocal(){') + VariableSetup(vars=['v','X']) + v,X,Y = resetMats(['v','X']) + print('/*') + print('X') + print(X) + print('v') + print(v) + v = dot(reshape(X,(N,N)),v) + print('v') + print(v) + print('*/') + print(tab+function_call+'MultiplyVectorLocal(&X,&v);') + for i in rows: + print(tab+'TASSERT('+Equals('v.v[%d]' % (i), ('%s' % cstyle[TYPE]) % (v[i]))+',"Entry .v[%d] failed!"' % (i) + ');') + EndTest() + + commbreak() + + print(unittest_preamble+function_call+'Transpose(){') + VariableSetup(vars=['X','A']) + v,X,Y = resetMats(['X']) + + print(tab+function_call+'Transpose(&X,&A);') + for i in rows: + for j in columns: + print(tab+'TASSERT('+Equals('A.v[%d]' % (i+N*j), ('%s' % cstyle[TYPE]) % (X[j,i]))+',"Entry _a%d%d failed!"' % (i+1,j+1) + ');') + EndTest() + + commbreak() + + print(unittest_preamble+function_call+'TransposeLocal(){') + VariableSetup(vars=['X']) + v,X,Y = resetMats(['X']) + print(tab+function_call+'TransposeLocal(&X);') + for i in rows: + for j in columns: + print(tab+'TASSERT('+Equals('X.v[%d]' % (i+N*j), ('%s' % cstyle[TYPE]) % (X[j,i]))+',"Entry _a%d%d failed!"' % (i+1,j+1) + ');') + EndTest() + + commbreak() + + + if((TYPE!='unsigned int')): + print(unittest_preamble+function_call+'CheckOrthonormal(){') + VariableSetup(['X','Y']) + v,X,Y = resetMats(['X','Y']) + # QR Decomposition - the first n independent columns of matrix X will result in the first n columns of Q being orthonormal basis + Q,R = linalg.qr(reshape(X,(N,N))) + QTQ = dot(Q.T,Q) + if((TYPE=='int') | (TYPE=='unsigned int')): + for j in columns: + for i in rows: + print('X.v[%d] = ' % (i+N*j) +('(%s)' % TYPE) + ('%s' % cstyle[TYPE]) % (kronecker(i,j))+';') + for j in columns: + for i in rows: + print('Y.v[%d] = ' % (i+N*j) +('(%s)' % TYPE) + ('%s' % cstyle[TYPE]) % (kronecker(i,j))+';') + print('Y.v[%d] = ' % (N-1) +('(%s)' % TYPE) + ('%s' % cstyle[TYPE]) % (1)+'; /* Will cause Y to be fail */') + else: + print('/*') + print(Q) + print(QTQ) + print('*/') + print('/* Set X to orthogonal matrix Q */') + for j in columns: + for i in rows: + print(tab+'X.v[%d] = ' % (i+N*j) +('(%s)' % TYPE) + ('%s' % cstyle[TYPE]) % (Q[i][j])+';') + + print('/* Check Positive Test */') + print(tab+'TASSERT('+function_call+'CheckOrthonormal(&X),"CheckOrthonormal failed when it should have passed");') + print('/* Check Negative Test */') + print(tab+'TASSERT(!'+function_call+'CheckOrthonormal(&Y),"CheckOrthonormal succeeded when it should have failed");') + + EndTest() + + commbreak() + + print(unittest_preamble+function_call+'Determinant(){') + VariableSetup(['X']) + v,X,Y = resetMats(['X']) + + print('/* det(X) = ') + print(linalg.det(X)) + print(' */') + print(tab+TYPE+' result = '+function_call+'Determinant(&X);') + print(tab+'TASSERT(%s( (result)/(%s) - %s ) <= 100*%s' % (fabs[TYPE],cstyle[TYPE] % (linalg.det(X)),cstyle[TYPE] % (1), fp_epsilon[TYPE] )+',"Determinant failed!");') + #print(tab+'TASSERT('+Equals('result ',('%s' % cstyle[TYPE]) % (linalg.det(X)))+',"Determinant failed!");') + EndTest() + + commbreak() + + if((TYPE != 'int') & (TYPE != 'unsigned int')): + print(unittest_preamble+function_call+'Invert(){') + VariableSetup(['X','B']) + v,X,Y = resetMats(['X']) + + B = linalg.inv(reshape(X,(N,N))) + print('/*') + print(B) + print('*/') + print(tab+function_call+'Invert(&X,&B);') + for j in columns: + for i in rows: + '''print('fprintf(stdout,"B[%d][%d] = '+('%s' % cstyle[TYPE])+'\\n",%d,%d,B.v[%d]);' % (i,j,i+N*j))''' + + for j in columns: + for i in rows: + print(tab+'TASSERT('+Equals('B.v[%d]' % (i+N*j), ('%s' % cstyle[TYPE]) % (B[i][j]))+',"Entry _a%d%d failed!"' % (i+1,j+1) + ');') + EndTest() + + commbreak() + + print(unittest_preamble+function_call+'InvertLocal(){') + VariableSetup(['X']) + v,X,Y = resetMats(['X']) + + B = linalg.inv(reshape(X,(N,N))) + print('/*') + print() + print(B) + print('*/') + print(tab+function_call+'InvertLocal(&X);') + for j in columns: + for i in rows: + print(tab+'TASSERT('+Equals('X.v[%d]' % (i+N*j), ('%s' % cstyle[TYPE]) % (B[i][j]))+',"Entry _a%d%d failed!"' % (i+1,j+1) + ');') + + EndTest() + + commbreak() + + print(unittest_preamble+function_call+'CreateLU(){') + print(tab+'%s X; /* %d x %d matrix */' % (MTXTYPE,N,N)) + print(tab+'%s LU; /* %d x %d matrix */' % (MTXTYPE,N,N)) + if(N==2): + X = array([[2,-1],[-3,1]],order='F') + if(N==3): + X = array([[2,-1,-1],[1,0,-1],[0,2,1]],order='F') + if(N==4): + X = array([[2,-1,-1,1],[1,0,-1,2],[0,2,1,1],[4,2,0,0]],order='F') + + for j in columns: + for i in rows: + print(tab+('X.v[%d] = %s;' % (i+N*j,cstyle[TYPE])) % (X[i,j])) + + print(tab+function_call+'CreateLU(&X,&LU);') + + if(N==2): + L = array([[2,0],[-3,-.5]],order='F') + U = array([[1,-.5],[0,1]], order='F') + + if(N==3): + L = array([[2,0,0],[1,.5,0],[0,2,3]],order='F') + U = array([[1,-.5,-.5],[0,1,-1],[0,0,1]],order='F') + + if(N==4): + L = array([[2,0,0,0],[1,.5,0,0],[0,2,3,0],[4,4,6,-4]],order='F') + U = array([[1,-.5,-.5,.5],[0,1,-1,3],[0,0,1,-1.66666666666667],[0,0,0,1]],order='F') + print('/*') + print(X) + print('*/') + print('/*') + print(L) + print('*/') + print('/*') + print(U) + print('*/') + for i in rows: + for j in r_[0:i+1]: + print(tab+'TASSERT('+Equals('LU.v[%d]' % (i+N*j), ('%s' % cstyle[TYPE]) % (L[i,j]))+',"L:Entry A_a%d%d failed!"' % (i+1,j+1) + ');') + for j in r_[i+1:N]: + print(tab+'TASSERT('+Equals('LU.v[%d]' % (i+N*j), ('%s' % cstyle[TYPE]) % (U[i,j]))+',"U:Entry B_a%d%d failed!"' % (i+1,j+1) + ');') + + EndTest() + print(unittest_preamble+function_call+'CreateLULocal(){') + print(tab+'%s X; /* %d x %d matrix */' % (MTXTYPE,N,N)) + if(N==2): + X = array([[2,-1],[-3,1]],order='F') + if(N==3): + X = array([[2,-1,-1],[1,0,-1],[0,2,1]],order='F') + if(N==4): + X = array([[2,-1,-1,1],[1,0,-1,2],[0,2,1,1],[4,2,0,0]],order='F') + + for j in columns: + for i in rows: + print(tab+('X.v[%d] = %s;' % (i+N*j,cstyle[TYPE])) % (X[i,j])) + + print(tab+function_call+'CreateLULocal(&X);') + + if(N==2): + A = array([[2,0],[-3,-.5]],order='F') + B = array([[1,-.5],[0,1]], order='F') + + if(N==3): + A = array([[2,0,0],[1,.5,0],[0,2,3]],order='F') + B = array([[1,-.5,-.5],[0,1,-1],[0,0,1]],order='F') + + if(N==4): + A = array([[2,0,0,0],[1,.5,0,0],[0,2,3,0],[4,4,6,-4]],order='F') + B = array([[1,-.5,-.5,.5],[0,1,-1,3],[0,0,1,-1.66666666666667],[0,0,0,1]],order='F') + + for i in rows: + for j in r_[0:i+1]: + print(tab+'TASSERT('+Equals('X.v[%d]' % (i+N*j), ('%s' % cstyle[TYPE]) % (A[i,j]))+',"L:Entry A_a%d%d failed!"' % (i+1,j+1) + ');') + for j in r_[i+1:N]: + print(tab+'TASSERT('+Equals('X.v[%d]' % (i+N*j), ('%s' % cstyle[TYPE]) % (B[i,j]))+',"U:Entry B_a%d%d failed!"' % (i+1,j+1) + ');') + + EndTest() + + print(unittest_preamble+function_call+'ApplyLUMat(){') + print(tab+'%s X; /* %d x %d matrix */' % (MTXTYPE,N,N)) + print(tab+'%s LU; /* %d x %d matrix */' % (MTXTYPE,N,N)) + print(tab+'%s I; /* %d x %d matrix */' % (MTXTYPE,N,N)) + if(N==2): + X = array([[2,-1],[-3,1]],order='F') + if(N==3): + X = array([[2,-1,-1],[1,0,-1],[0,2,1]],order='F') + if(N==4): + X = array([[2,-1,-1,1],[1,0,-1,2],[0,2,1,1],[4,2,0,0]],order='F') + + for j in columns: + for i in rows: + print(tab+('X.v[%d] = %s;' % (i+N*j,cstyle[TYPE])) % (X[i,j])) + + print(tab+function_call+'CreateLU(&X,&LU);') + + if(N==2): + L = array([[2,0],[-3,-.5]],order='F') + U = array([[1,-.5],[0,1]], order='F') + + if(N==3): + L = array([[2,0,0],[1,.5,0],[0,2,3]],order='F') + U = array([[1,-.5,-.5],[0,1,-1],[0,0,1]],order='F') + + if(N==4): + L = array([[2,0,0,0],[1,.5,0,0],[0,2,3,0],[4,4,6,-4]],order='F') + U = array([[1,-.5,-.5,.5],[0,1,-1,3],[0,0,1,-1.66666666666667],[0,0,0,1]],order='F') + print('/*') + print(X) + print('*/') + print('/*') + print(L) + print('*/') + print('/*') + print(U) + print('*/') + + for i in rows: + for j in r_[0:i+1]: + print(tab+'TASSERT('+Equals('LU.v[%d]' % (i+N*j), ('%s' % cstyle[TYPE]) % (L[i,j]))+',"L:Entry A_a%d%d failed!"' % (i+1,j+1) + ');') + for j in r_[i+1:N]: + print(tab+'TASSERT('+Equals('LU.v[%d]' % (i+N*j), ('%s' % cstyle[TYPE]) % (U[i,j]))+',"U:Entry B_a%d%d failed!"' % (i+1,j+1) + ');') + + print(tab+function_call+'ApplyLUMat(&LU,&X,&I);') + for j in columns: + for i in rows: + print(tab+'TASSERT('+Equals('I.v[%d]' % (i+N*j), ('%s' % cstyle[TYPE]) % (kronecker(i,j)))+',"I:Entry I_a%d%d failed!"' % (i+1,j+1) + ');') + EndTest() + + print(unittest_preamble+function_call+'ApplyLUMatLocal(){') + print(tab+'%s X; /* %d x %d matrix */' % (MTXTYPE,N,N)) + print(tab+'%s Xinv; /* %d x %d matrix */' % (MTXTYPE,N,N)) + if(N==2): + X = array([[2,-1],[-3,1]],order='F') + if(N==3): + X = array([[2,-1,-1],[1,0,-1],[0,2,1]],order='F') + if(N==4): + X = array([[2,-1,-1,1],[1,0,-1,2],[0,2,1,1],[4,2,0,0]],order='F') + + for j in columns: + for i in rows: + print(tab+('X.v[%d] = %s;' % (i+N*j,cstyle[TYPE])) % (X[i,j])) + + for j in columns: + for i in rows: + print(tab+('Xinv.v[%d] = %s;' % (i+N*j,cstyle[TYPE])) % (X[i,j])) + + print(tab+function_call+'CreateLULocal(&X);') + + if(N==2): + A = array([[2,0],[-3,-.5]],order='F') + B = array([[1,-.5],[0,1]], order='F') + + if(N==3): + A = array([[2,0,0],[1,.5,0],[0,2,3]],order='F') + B = array([[1,-.5,-.5],[0,1,-1],[0,0,1]],order='F') + + if(N==4): + A = array([[2,0,0,0],[1,.5,0,0],[0,2,3,0],[4,4,6,-4]],order='F') + B = array([[1,-.5,-.5,.5],[0,1,-1,3],[0,0,1,-1.66666666666667],[0,0,0,1]],order='F') + + for i in rows: + for j in r_[0:i+1]: + print(tab+'TASSERT('+Equals('X.v[%d]' % (i+N*j), ('%s' % cstyle[TYPE]) % (A[i,j]))+',"L:Entry A_a%d%d failed!"' % (i+1,j+1) + ');') + for j in r_[i+1:N]: + print(tab+'TASSERT('+Equals('X.v[%d]' % (i+N*j), ('%s' % cstyle[TYPE]) % (B[i,j]))+',"U:Entry B_a%d%d failed!"' % (i+1,j+1) + ');') + + print(tab+function_call+'ApplyLUMatLocal(&X,&Xinv);') + for j in columns: + for i in rows: + print(tab+'TASSERT('+Equals('Xinv.v[%d]' % (i+N*j), ('%s' % cstyle[TYPE]) % (kronecker(i,j)))+',"Xinv:Entry Xinv_a%d%d failed!"' % (i+1,j+1) + ');') + + EndTest() + + print(unittest_preamble+function_call+'ApplyLUVec(){') + print(tab+'%s X; /* %d x %d matrix */' % (MTXTYPE,N,N)) + print(tab+'%s LU; /* %d x %d matrix */' % (MTXTYPE,N,N)) + print(tab+'%s b; /* %d x %d vector */' % (VTXTYPE,N,N)) + print(tab+'%s x; /* %d x %d vector */' % (VTXTYPE,N,N)) + if(N==2): + X = array([[2,-1],[-3,1]],order='F') + b = array([2,-1]) + if(N==3): + X = array([[2,-1,-1],[1,0,-1],[0,2,1]],order='F') + b = array([2,-1,1]) + if(N==4): + X = array([[2,-1,-1,1],[1,0,-1,2],[0,2,1,1],[4,2,0,0]],order='F') + b = array([2,-1,1,1]) + + x = dot(linalg.inv(reshape(X,(N,N))),b) + + for j in columns: + for i in rows: + print(tab+('X.v[%d] = %s;' % (i+N*j,cstyle[TYPE])) % (X[i,j])) + + for j in columns: + print(tab+('b.v[%d] = %s;' % (j,cstyle[TYPE])) % (b[j])) + + print(tab+function_call+'CreateLU(&X,&LU);') + + if(N==2): + L = array([[2,0],[-3,-.5]],order='F') + U = array([[1,-.5],[0,1]], order='F') + + if(N==3): + L = array([[2,0,0],[1,.5,0],[0,2,3]],order='F') + U = array([[1,-.5,-.5],[0,1,-1],[0,0,1]],order='F') + + if(N==4): + L = array([[2,0,0,0],[1,.5,0,0],[0,2,3,0],[4,4,6,-4]],order='F') + U = array([[1,-.5,-.5,.5],[0,1,-1,3],[0,0,1,-1.66666666666667],[0,0,0,1]],order='F') + + print(tab+function_call+'ApplyLUVec(&LU,&b,&x);') + for j in columns: + print(tab+'TASSERT('+Equals('x.v[%d]' % (j), ('%s' % cstyle[TYPE]) % (x[j]))+',"x:Entry x_a%d failed!"' % (j+1) + ');') + + EndTest() + + print(unittest_preamble+function_call+'ApplyLUVecLocal(){') + print(tab+'%s X; /* %d x %d matrix */' % (MTXTYPE,N,N)) + print(tab+'%s LU; /* %d x %d matrix */' % (MTXTYPE,N,N)) + print(tab+'%s b; /* %d x %d vector */' % (VTXTYPE,N,N)) + if(N==2): + X = array([[2,-1],[-3,1]],order='F') + b = array([2,-1]) + if(N==3): + X = array([[2,-1,-1],[1,0,-1],[0,2,1]],order='F') + b = array([2,-1,1]) + if(N==4): + X = array([[2,-1,-1,1],[1,0,-1,2],[0,2,1,1],[4,2,0,0]],order='F') + b = array([2,-1,1,1]) + + x = dot(linalg.inv(reshape(X,(N,N))),b) + + for j in columns: + for i in rows: + print(tab+('X.v[%d] = %s;' % (i+N*j,cstyle[TYPE])) % (X[i,j])) + + for j in columns: + print(tab+('b.v[%d] = %s;' % (j,cstyle[TYPE])) % (b[j])) + + print(tab+function_call+'CreateLU(&X,&LU);') + + if(N==2): + L = array([[2,0],[-3,-.5]],order='F') + U = array([[1,-.5],[0,1]], order='F') + + if(N==3): + L = array([[2,0,0],[1,.5,0],[0,2,3]],order='F') + U = array([[1,-.5,-.5],[0,1,-1],[0,0,1]],order='F') + + if(N==4): + L = array([[2,0,0,0],[1,.5,0,0],[0,2,3,0],[4,4,6,-4]],order='F') + U = array([[1,-.5,-.5,.5],[0,1,-1,3],[0,0,1,-1.66666666666667],[0,0,0,1]],order='F') + + print(tab+function_call+'ApplyLUVecLocal(&LU,&b);') + for j in columns: + print(tab+'TASSERT('+Equals('b.v[%d]' % (j), ('%s' % cstyle[TYPE]) % (x[j]))+',"x:Entry x_a%d failed!"' % (j+1) + ');') + + EndTest() + + +# Generates the test code +if(CODE_TYPE == 'benchmark'): + print('/*') + print('\tAUTOMATICALLY GENERATED FILE - DO NOT EDIT!') + print('\tPlease change MatrixNxN.py and re-run it') + print('*/') + print('/* Generated with %s n = %d, TYPE = %s */\n' % (__file__,N,TYPE)) + + print('#include <float.h>') + print('#include <math.h>') + print('#include <stdlib.h>') + print('#include <stdio.h>') + print('#include <assert.h>') + print('#include <xmmintrin.h>') + print('#include <SST/SST_Timer_x86.h>') + print('#include <SST/%s.h>' % MTXTYPE[0:-1]) + print('#include <SST/%s.h>' % VTXTYPE[0:-1]) + print('\n\n\n') + print('int '+function_call+'_test_fxns()\n{') +# Variable Setup + print('const int NTESTS = 10;') + print('int i;') + print('uint64_t t0,t1;') + print('%s X; /* %d x %d matrix */' % (MTXTYPE,N,N)) + print('%s Y; /* %d x %d matrix */' % (MTXTYPE,N,N)) + print('%s A; /* %d x %d matrix */' % (MTXTYPE,N,N)) + print('%s B; /* %d x %d matrix */' % (MTXTYPE,N,N)) + print('SST_Vec%s v; /* %d vector */' % (MTXTYPE[-2::],N)) + print('SST_Vec%s w; /* %d vector */' % (MTXTYPE[-2::],N)) + print('for(i = 0; i < NTESTS; i++) { ') + print('t0 = rdtsc();') + print('t1 = rdtsc();') + print('fprintf(stdout," timing:%llu\\n",(long long unsigned int)(t1-t0));') + print('}') + print('fprintf(stdout," timing:%llu\\n",(long long unsigned int)(t1-t0));') +# Initial array / matrix values + v,X,Y = resetMats() +# Function Tests + print(function_call+'Add(&X,&Y,&A); /* clear out the initial finding of object */') + print('/* Clear out the rdtsc register */') + print('fprintf(stdout,"'+function_call+'Add(X,Y,A)\");') + print('for(i = 0; i < NTESTS; i++) { ') + print('t0 = rdtsc();') + print(function_call+'Add(&X,&Y,&A);') + print('t1 = rdtsc();') + print('fprintf(stdout," timing:%llu\\n",(long long unsigned int)(t1-t0));') + print('}') + print('/*') + print(X) + print(Y) + print(X+Y) + print('*/') + for i in rows: + for j in columns: + print('assert('+Equals('A.v[%d]' % (i+N*j), ('%s' % cstyle[TYPE]) % (X[i,j]+Y[i,j]))+');') + +# Unit test for Add equals + print('/*') + print(X) + print(Y) + print(X+Y) + print('*/') + print('fprintf(stdout,"'+function_call+'AddLocal(A,Y)\");') + print('for(i = 0; i < NTESTS; i++) { ') + print('t0 = rdtsc();') + print(function_call+'AddLocal(&A,&Y);') + print('t1 = rdtsc();') + print('fprintf(stdout," timing:%llu\\n",(long long unsigned int)(t1-t0));') + print('}') + print('fprintf(stdout," timing:%llu\\n",(long long unsigned int)(t1-t0));') + # have to check for accuracy as well as for timing + print(function_call+'AddLocal(&X,&Y); /* for accuracy */') + for i in rows: + for j in columns: + print('assert('+Equals('X.v[%d]' % (i+N*j), ('%s' % cstyle[TYPE]) % (X[i,j]+Y[i,j]))+');') + + v,X,Y = resetMats() + print('/*') + print(X) + print(2*X) + print('*/') + print('fprintf(stdout,"'+function_call+'MultiplyScalar(X,t,Y)\");') + print('for(i = 0; i < NTESTS; i++) { ') + print('t0 = rdtsc();') + print(function_call+'MultiplyScalar(&X,'+('%s'%cstyle[TYPE])%(2)+',&A);') + print('t1 = rdtsc();') + print('fprintf(stdout," timing:%llu\\n",(long long unsigned int)(t1-t0));') + print('}') + print('fprintf(stdout," timing:%llu\\n",(long long unsigned int)(t1-t0));') + for i in rows: + for j in columns: + print('assert('+Equals('A.v[%d]' % (i+N*j), ('%s' % cstyle[TYPE]) % (2*X[i,j]))+');') + + print('/*') + print(X) + print(2*X) + print('*/') + print('fprintf(stdout,"'+function_call+'MultiplyScalarLocal(A,t)\");') + print('for(i = 0; i < NTESTS; i++) { ') + print('t0 = rdtsc();') + print(function_call+'MultiplyScalarLocal(&A,'+('%s'%cstyle[TYPE]%2)+');') + print('t1 = rdtsc();') + print('fprintf(stdout," timing:%llu\\n",(long long unsigned int)(t1-t0));') + print('}') + print('fprintf(stdout," timing:%llu\\n",(long long unsigned int)(t1-t0));') + print(function_call+'MultiplyScalarLocal(&X,'+('%s'%cstyle[TYPE]%2)+');') + for i in rows: + for j in columns: + print('assert('+Equals('X.v[%d]' % (i+N*j), ('%s' % cstyle[TYPE]) % (2*X[i,j]))+');') + + v,X,Y = resetMats() + print('/*') + print(X) + print(Y) + print(X*Y) + print('*/') + print('fprintf(stdout,"'+function_call+'MultiplyElementwise(X,Y,A)\");') + print('for(i = 0; i < NTESTS; i++) { ') + print('t0 = rdtsc();') + print(function_call+'MultiplyElementwise(&X, &Y, &A);') + print('t1 = rdtsc();') + print('fprintf(stdout," timing:%llu\\n",(long long unsigned int)(t1-t0));') + print('}') + print('fprintf(stdout," timing:%llu\\n",(long long unsigned int)(t1-t0));') + for i in rows: + for j in columns: + print('assert('+Equals('A.v[%d]' % (i+N*j), ('%s' % cstyle[TYPE]) % (Y[i,j]*X[i,j]))+');') + + print('/*') + print(X) + print(Y) + print(X*Y) + print('*/') + print('fprintf(stdout,"'+function_call+'MultiplyElementwiseLocal(X,Y)\");') + print('for(i = 0; i < NTESTS; i++) { ') + print('t0 = rdtsc();') + print(function_call+'MultiplyElementwiseLocal(&A,&Y);') + print('t1 = rdtsc();') + print('fprintf(stdout," timing:%llu\\n",(long long unsigned int)(t1-t0));') + print('}') + print('fprintf(stdout," timing:%llu\\n",(long long unsigned int)(t1-t0));') + print(function_call+'MultiplyElementwiseLocal(&X,&Y);') + for i in rows: + for j in columns: + print('assert('+Equals('X.v[%d]' % (i+N*j), ('%s' % cstyle[TYPE]) % (Y[i,j]*X[i,j]))+');') + + v,X,Y = resetMats() + A = dot(reshape(X,(N,N)),reshape(Y,(N,N))) + print('/*') + print('X') + print(reshape(X,(N,N))) + print('Y') + print(reshape(Y,(N,N))) + print(A) + print('*/') + print('fprintf(stdout,"'+function_call+'MultiplyMatrix(X,Y,A)\");') + print('for(i = 0; i < NTESTS; i++) { ') + print('t0 = rdtsc();') + print(function_call+'MultiplyMatrix(&X,&Y,&A);') + print('t1 = rdtsc();') + print('}') + print('fprintf(stdout," timing:%llu\\n",(long long unsigned int)(t1-t0));') + for i in rows: + for j in columns: + print('assert('+Equals('A.v[%d]' % (i+N*j), ('%s' % cstyle[TYPE]) % (A[i][j]))+');') + + print('/*') + print('X') + print(reshape(X,(N,N))) + print('Y') + print(reshape(Y,(N,N))) + print('X') + print(A) + print('*/') + print('fprintf(stdout,"'+function_call+'MultiplyMatrixLocal(X,Y)\");') + print('for(i = 0; i < NTESTS; i++) { ') + print('t0 = rdtsc();') + print(function_call+'MultiplyMatrixLocal(&A,&Y);') + print('t1 = rdtsc();') + print('}') + print('fprintf(stdout," timing:%llu\\n",(long long unsigned int)(t1-t0));') + print(function_call+'MultiplyMatrixLocal(&X,&Y);') + for i in rows: + for j in columns: + print('assert('+Equals('X.v[%d]' % (i+N*j), ('%s' % cstyle[TYPE]) % (A[i][j]))+');') + + v,X,Y = resetMats() + w = dot(reshape(X,(N,N)),v) + print('/*') + print('X') + print(X) + print('v') + print(v) + print('w') + print(w) + print('*/') + print('i=0;') + print('fprintf(stdout,"'+function_call+'MultiplyVector(X,v,w)\");') + print('for(i = 0; i < NTESTS; i++) { ') + print('t0 = rdtsc();') + print(function_call+'MultiplyVector(&X,&v,&w);') + print('t1 = rdtsc();') + print('fprintf(stdout," timing:%llu\\n",(long long unsigned int)(t1-t0));') + print('}') + print('fprintf(stdout," timing:%llu\\n",(long long unsigned int)(t1-t0));') + '''for i in rows: + for j in columns: + print('fprintf(stdout,"X[%d] = '+('%s' % cstyle[TYPE])+'\\n",%d,X[%d]);' % (N*i+j,N*i+j)) + for i in rows: + print('fprintf(stdout,"v[%d] = '+('%s' % cstyle[TYPE])+'\\n",%d,v[%d]);' % (i,i)) + for i in rows: + print('fprintf(stdout,"w[%d] = '+('%s' % cstyle[TYPE])+'\\n",%d,w[%d]);' % (i,i)) ''' + for i in rows: + print('assert('+Equals('w.v[%d]' % (i), ('%s' % cstyle[TYPE]) % (w[i]))+');') + + print('/*') + print('X') + print(X) + print('v') + print(v) + v = dot(reshape(X,(N,N)),v) + print('v') + print(v) + print('*/') + print('fprintf(stdout,"'+function_call+'MultiplyVectorLocal(X,v)\");') + print('for(i = 0; i < NTESTS; i++) { ') + print('t0 = rdtsc();') + print(function_call+'MultiplyVectorLocal(&X,&w);') + print('t1 = rdtsc();') + print('fprintf(stdout," timing:%llu\\n",(long long unsigned int)(t1-t0));') + print('}') + print('fprintf(stdout," timing:%llu\\n",(long long unsigned int)(t1-t0));') + print(function_call+'MultiplyVectorLocal(&X,&v);') + for i in rows: + print('assert('+Equals('v.v[%d]' % (i), ('%s' % cstyle[TYPE]) % (v[i]))+');') + + v,X,Y = resetMats() + print('fprintf(stdout,"'+function_call+'Transpose(X,A)\");') + print('t0 = rdtsc();') + print(function_call+'Transpose(&X,&A);') + print('t1 = rdtsc();') + print('fprintf(stdout," timing:%llu\\n",(long long unsigned int)(t1-t0));') + for i in rows: + for j in columns: + print('assert('+Equals('A.v[%d]' % (i+N*j), ('%s' % cstyle[TYPE]) % (X[j,i]))+');') + + print('fprintf(stdout,"'+function_call+'TransposeLocal(X)\");') + print('for(i = 0; i < NTESTS; i++) { ') + print('t0 = rdtsc();') + print(function_call+'TransposeLocal(&A);') + print('t1 = rdtsc();') + print('fprintf(stdout," timing:%llu\\n",(long long unsigned int)(t1-t0));') + print('}') + print('fprintf(stdout," timing:%llu\\n",(long long unsigned int)(t1-t0));') + print(function_call+'TransposeLocal(&X);') + for i in rows: + for j in columns: + print('assert('+Equals('X.v[%d]' % (i+N*j), ('%s' % cstyle[TYPE]) % (X[j,i]))+');') + +# QR Decomposition - the first n independent columns of matrix X will result in the first n columns of Q being orthonormal basis + Q,R = linalg.qr(reshape(X,(N,N))) + QTQ = dot(Q.T,Q) + print('/*') + print(Q) + print(QTQ) + print('*/') + for i in rows: + for j in columns: + print('X.v[%d] = ' % (i+N*j) +('(%s)' % TYPE) + ('%s' % cstyle[TYPE]) % (Q[i][j])+';') + + print('fprintf(stdout,"'+function_call+'Transpose(X,A)\");') + print('t0 = rdtsc();') + print(function_call+'Transpose(&X,&A);') + print('t1 = rdtsc();') + print('fprintf(stdout," timing:%llu\\n",(long long unsigned int)(t1-t0));') + print('fprintf(stdout,"'+function_call+'MultiplyMatrix(A,X,B)\");') + print('t0 = rdtsc();') + print(function_call+'MultiplyMatrix(&A,&X,&B);') + print('t1 = rdtsc();') + print('fprintf(stdout," timing:%llu\\n",(long long unsigned int)(t1-t0));') + for i in rows: + for j in columns: + #print('fprintf(stdout,"B[%d][%d] = '+('%s' % cstyle[TYPE])+'\\n",%d,%d,B[%d]);' % (i,j,N*i+j)) + ''' ''' + + if(TYPE != 'unsigned int'): + if(TYPE != 'int'): + print('/* Check Negative Test */') + print('assert(!'+function_call+'CheckOrthonormal(&X));') + for i in rows: + for j in columns: + print('X.v[%d] = ' % (i+N*j) +('(%s)' % TYPE) + ('%s' % cstyle[TYPE]) % (kronecker(i,j))+';') + print('/* Check Positive Test */') + print('assert('+function_call+'CheckOrthonormal(&X));') + else: + print('/* Check Positive Test */') + print('assert('+function_call+'CheckOrthonormal(&X));') + print('/* Check Negative Test */') + print('assert(!'+function_call+'CheckOrthonormal(&Y));') + + if((TYPE != 'int') & (TYPE != 'unsigned int')): + v,X,Y = resetMats() + B = linalg.inv(reshape(X,(N,N))) + print('/*') + print(B) + print('*/') + print('fprintf(stdout,"'+function_call+'Invert(X,B)\\n");') + print('t0 = rdtsc();') + print(function_call+'Invert(&X,&B);') + print('t1 = rdtsc();') + print('fprintf(stdout," timing:%llu\\n",(long long unsigned int)(t1-t0));') + for i in rows: + for j in columns: + print('fprintf(stdout,"B[%d][%d] = '+('%s' % cstyle[TYPE])+'\\n",%d,%d,B.v[%d]);' % (i,j,N*i+j)) + ''' ''' + for i in rows: + for j in columns: + print('assert('+Equals('B.v[%d]' % (i+N*j), ('%s' % cstyle[TYPE]) % (B[i][j]))+');') + + v,X,Y = resetMats() + B = linalg.inv(reshape(X,(N,N))) + print('/*') + print(B) + print('*/') + print('fprintf(stdout,"'+function_call+'Invert(X,B)\\n");') + for i in rows: + for j in columns: + #print('fprintf(stdout,"X[%d][%d] = '+('%s' % cstyle[TYPE])+'\\n",%d,%d,X[%d]);' % (i,j,N*i+j)) + ''' ''' + print('fflush(stdout);') + print('fprintf(stdout,"'+function_call+'InvertLocal(X,B)\\n");') + print('t0 = rdtsc();') + print(function_call+'InvertLocal(&X);') + print('t1 = rdtsc();') + print('fprintf(stdout," timing:%llu\\n",(long long unsigned int)(t1-t0));') + for i in rows: + for j in columns: + #print('fprintf(stdout,"X[%d][%d] = '+('%s' % cstyle[TYPE])+'\\n",%d,%d,X[%d]);' % (i,j,N*i+j)) + ''' ''' + print('fflush(stdout);') + for i in rows: + for j in columns: + print('assert('+Equals('X.v[%d]' % (i+N*j), ('%s' % cstyle[TYPE]) % (B[i][j]))+');') + + print('fprintf(stdout,"\\n==== '+function_call+'test_fxn COMPLETE ====\\n");') + print('return 0;\n}') + +if(TIMING_CHECK): + NUM_TESTS = 1000 + print('#include <assert.h>') + print('#include <stdlib.h>') + print('#include <stdio.h>') + print('#include <SST/SST_Timer_x86.h>') + print('int '+function_call+'timing_fxns()\n{') +# Variable Setup + print('%s *X,*Y,*A,*B,*v,*w;' % TYPE) + print('int i;') + print('const int NUM_TESTS = %d;' % (NUM_TESTS)) + print('X = (%s*) calloc(%d,sizeof(%s));' % (TYPE,N*N,TYPE)) + print('Y = (%s*) calloc(%d,sizeof(%s));' % (TYPE,N*N,TYPE)) + print('A = (%s*) calloc(%d,sizeof(%s));' % (TYPE,N*N,TYPE)) + print('B = (%s*) calloc(%d,sizeof(%s));' % (TYPE,N*N,TYPE)) + print('v = (%s*) calloc(%d,sizeof(%s));' % (TYPE,N,TYPE)) + print('w = (%s*) calloc(%d,sizeof(%s));' % (TYPE,N,TYPE)) + print('for(i=0;i<NUM_TESTS;i++){}') + + print('free(X);') + print('free(Y);') + print('free(A);') + print('free(B);') + print('free(v);') + print('free(w);') + print('fprintf(stdout,"==== '+function_call+'timing_fxn COMPLETE ====\");') + print('return 0;\n}') + diff --git a/libsst-math/SST_Geo.c b/libsst-math/SST_Geo.c new file mode 100644 index 0000000..46e5ad8 --- /dev/null +++ b/libsst-math/SST_Geo.c @@ -0,0 +1,411 @@ +#include <math.h> +#include <SST/SST_Vec2.h> +#include <SST/SST_Vec3.h> +#include <SST/SST_Math.h> +#include <SST/SST_Geo.h> + +/* + Helper function to find intersection(s) of two line segments. + This is adapted from "Geometric Tools For Computer Graphpics", p. 244. + + Note that the segments are being represented here by a start point and a distance offset vector, + P and D, assuming that the full segment can be represented by the equation: + + L(t) = P + tD, where t is on the range [0,1] +*/ + +#define sqrEpsilon (0.0001f) + +static SST_2DLineSegmentIntersectType doFindIntersection( float u0, float u1, float v0, float v1, float w[2]) +{ + if ( u1 < v0 || u0 > v1 ) + { + return SST2DLINESEGINTERSECT_NONE; + } + + if ( u1 > v0 ) + { + if (u0 < v1) + { + w[0] = (u0 < v0) ? (v0) : (u0); + w[1] = (u1 > v1) ? (v1) : (u1); + return SST2DLINESEGINTERSECT_OVERLAP; + } + else + { + w[0] = u0; + return SST2DLINESEGINTERSECT_POINT; + } + } + else + { + w[0] = u1; + return SST2DLINESEGINTERSECT_POINT; + } +} + +SST_2DLineSegmentIntersectType doSegmentSegmentIntersectionF( const SST_Vec2f* RESTRICT P0, + const SST_Vec2f* RESTRICT D0, + const SST_Vec2f* RESTRICT P1, + const SST_Vec2f* RESTRICT D1, + SST_Vec2f* RESTRICT overlaps) +{ + SST_Vec2f e; + float kross; + float kross2; + float sqrKross; + float sqrKross2; + float sqrLen0; + float sqrLen1; + float sqrLenE; + float s; + float t; + float s0; + float s1; + float w[2]; + float smin; + float smax; + SST_2DLineSegmentIntersectType itype; + + SST_Math_Vec2fSubtract(P1, P0, &e); + + /* + Note on the kross operator: + + Kross(a,b) = (ax*by) - (bx*ay) + */ + kross = ((D0->x)*(D1->y)) - ((D0->y)*(D1->x)); + sqrKross = kross * kross; + sqrLen0 = ((D0->x) * (D0->x)) + ((D0->y) * (D0->y)); + sqrLen1 = ((D1->x) * (D1->x)) + ((D1->y) * (D1->y)); + + if (sqrKross > sqrEpsilon * sqrLen0 * sqrLen1) + { + s = ((e.x * D1->y) - (e.y * D1->x)) / kross; + if (s < 0.0f || s > 1.0f) + { + return SST2DLINESEGINTERSECT_NONE; + } + + t = ((e.x * D0->y) - (e.y * D0->x)) / kross; + if (t < 0.0f || t > 1.0f) + { + return SST2DLINESEGINTERSECT_NONE; + } + + SST_Math_Vec2fWeightedSum(P0, 1.0f, D0, s, overlaps); + + return SST2DLINESEGINTERSECT_POINT; + } + + sqrLenE = (e.x * e.x) + (e.y * e.y); + + kross2 = ((e.x)*(D0->y)) - ((e.y)*(D0->x)); + sqrKross2 = kross2 * kross2; + + if (sqrKross2 > sqrEpsilon * sqrLen0 * sqrLenE ) + { + return SST2DLINESEGINTERSECT_NONE; + } + + s0 = SST_Math_Vec2fDot( D0, &e) / sqrLen0; + s1 = s0 + SST_Math_Vec2fDot( D0, D1) / sqrLen0; + smin = s0 < s1 ? s0 : s1; + smax = s0 > s1 ? s0 : s1; + + itype = doFindIntersection(0.0f, 1.0f, smin, smax, w); + + switch (itype) { + case SST2DLINESEGINTERSECT_NONE: break; + case SST2DLINESEGINTERSECT_POINT: + SST_Math_Vec2fWeightedSum(P0, 1.0f, D0, w[0], &(overlaps[0]) ); + + break; + case SST2DLINESEGINTERSECT_OVERLAP: + SST_Math_Vec2fWeightedSum(P0, 1.0f, D0, w[0], &(overlaps[0]) ); + SST_Math_Vec2fWeightedSum(P0, 1.0f, D0, w[1], &(overlaps[1]) ); + + break; + default: break; + } + + return itype; +} + +/* + Main driver function, mostly just handles moving from the way we think about line segments, + using start and end points, to the way the routine thinks about things, using origin and offset. + +*/ +SST_2DLineSegmentIntersectType SST_Geo_2DSegmentSegmentIntersectionF( const SST_Vec2f* RESTRICT Astart, + const SST_Vec2f* RESTRICT Aend, + const SST_Vec2f* RESTRICT Bstart, + const SST_Vec2f* RESTRICT Bend, + SST_Vec2f* RESTRICT overlaps) +{ + SST_Vec2f p0; // starting point of first line segment + SST_Vec2f d0; // the offset of the first line segment + SST_Vec2f p1; // starting point of the second line segment + SST_Vec2f d1; // the offset of the second line segment + + // store starting points of rays + memmove( &p0, Astart, sizeof(SST_Vec2f) ); + memmove( &p1, Bstart, sizeof(SST_Vec2f) ); + + // grab the offset of the segment from the origin + SST_Math_Vec2fSubtract(Aend, Astart, &d0); + SST_Math_Vec2fSubtract(Bend, Bstart, &d1); + + return doSegmentSegmentIntersectionF(&p0, &d0, &p1, &d1, overlaps); +} + +float PointToPoint2f(const SST_Vec2f* a,const SST_Vec2f* b) +{ + SST_Vec2f temp; + SST_Math_Vec2fSubtract(a,b,&temp); + return SST_Math_Vec2fMagnitude(&temp); +} +float PointToPointSquared2f(const SST_Vec2f* a,const SST_Vec2f* b) +{ + SST_Vec2f temp; + SST_Math_Vec2fSubtract(a,b,&temp); + return SST_Math_Vec2fMagnitudeSquared(&temp); +} +double PointToPoint2d(const SST_Vec2d* a,const SST_Vec2d* b) +{ + SST_Vec2d temp; + SST_Math_Vec2dSubtract(a,b,&temp); + return SST_Math_Vec2dMagnitude(&temp); +} +double PointToPointSquared2d(const SST_Vec2d* a,const SST_Vec2d* b) +{ + SST_Vec2d temp; + SST_Math_Vec2dSubtract(a,b,&temp); + return SST_Math_Vec2dMagnitudeSquared(&temp); +} +float PointToLineSegment2f(SST_Vec2f* close, const SST_Vec2f* a, const SST_Vec2f* b) +{ + /* Line segment b is defined with two points b[0:1] and b[2:3] */ + SST_Vec2f temp; + float t; + float distsqr; + + temp.v[0] = b[1].v[0]-b[0].v[0]; + temp.v[1] = b[1].v[1]-b[0].v[1]; + distsqr = SST_Math_Vec2fMagnitudeSquared(&temp); + t = ((a->v[0]-b[0].v[0]) * temp.v[0] + (a->v[1]-b[0].v[1]) * temp.v[1] ) / distsqr; + if(t>1.f) + t = 1.f; + if(t<0.f) + t = 0.f; + + /* close[i] = b[i]+ t * temp[i]; */ + SST_Math_Vec2fScale(&temp,t,close); + SST_Math_Vec2fAddLocal(close,b); + + /* temp[i] = close[i]-a[i]; */ + SST_Math_Vec2fSubtract(close,a,&temp); + + return SST_Math_Vec2fMagnitude(&temp); +} +double PointToLineSegment2d(SST_Vec2d* close, const SST_Vec2d* a, const SST_Vec2d* b) +{ + /* Line segment b is defined with two points b[0:1] and b[2:3] */ + SST_Vec2d temp; + double t; + double distsqr; + temp.v[0] = b[1].v[0]-b[0].v[0]; + temp.v[1] = b[1].v[1]-b[0].v[1]; + distsqr = SST_Math_Vec2dMagnitudeSquared(&temp); + t = ((a->v[0]-b[0].v[0])*temp.v[0] + (a->v[1]-b[0].v[1])*temp.v[1]) / distsqr; + if(t>1.0) + t = 1.0; + if(t<0.0) + t = 0.0; + + /* close[i] = b[i]+ t * temp[i]; */ + SST_Math_Vec2dScale(&temp,t,close); + SST_Math_Vec2dAddLocal(close,b); + + //temp[i] = close[i]-a[i]; + SST_Math_Vec2dSubtract(close,a,&temp); + + return SST_Math_Vec2dMagnitude(&temp); +} + +float PointToPoint3f(const SST_Vec3f* a,const SST_Vec3f* b) +{ + SST_Vec3f temp; + SST_Math_Vec3fSubtract(a,b,&temp); + return SST_Math_Vec3fMagnitude(&temp); +} +float PointToPointSquared3f(const SST_Vec3f* a,const SST_Vec3f* b) +{ + SST_Vec3f temp; + SST_Math_Vec3fSubtract(a,b,&temp); + return SST_Math_Vec3fMagnitudeSquared(&temp); +} +float PointToLineSegment3f(SST_Vec3f* close, const SST_Vec3f* a, const SST_Vec3f* b) +{ + /* Line segment b is defined with two points b[0:1] and b[2:3] */ + SST_Vec3f temp; + float t; + float distsqr; + temp.v[0] = b[1].v[0]-b[0].v[0]; + temp.v[1] = b[1].v[1]-b[1].v[1]; + temp.v[2] = b[1].v[2]-b[2].v[2]; + distsqr = SST_Math_Vec3fMagnitudeSquared(&temp); + t = ((a->v[0]-b[0].v[0])*temp.v[0] + (a->v[1]-b[0].v[1])*temp.v[1]+(a->v[2]-b[0].v[2])*temp.v[2]) / distsqr; + if(t>1.f) + t = 1.f; + if(t<0.f) + t = 0.f; + + /* close[i] = b[i]+ t * temp[i]; */ + SST_Math_Vec3fScale(&temp,t,close); + SST_Math_Vec3fAddLocal(close,b); + + /* temp[i] = close[i]-a[i]; */ + SST_Math_Vec3fSubtract(close,a,&temp); + + return SST_Math_Vec3fMagnitude(&temp); +} +double PointToPoint3d(const SST_Vec3d* a,const SST_Vec3d* b) +{ + SST_Vec3d temp; + SST_Math_Vec3dSubtract(a,b,&temp); + return SST_Math_Vec3dMagnitude(&temp); +} +double PointToPointSquared3d(const SST_Vec3d* a,const SST_Vec3d* b) +{ + SST_Vec3d temp; + SST_Math_Vec3dSubtract(a,b,&temp); + return SST_Math_Vec3dMagnitudeSquared(&temp); +} +double PointToLineSegment3d(SST_Vec3d* close, const SST_Vec3d* a, const SST_Vec3d* b) +{ + /* Line segment b is defined with two points b[0:1] and b[2:3] */ + SST_Vec3d temp; + double t; + double distsqr; + temp.v[0] = b[1].v[0]-b[0].v[0]; + temp.v[1] = b[1].v[1]-b[0].v[1]; + temp.v[2] = b[1].v[2]-b[0].v[2]; + distsqr = SST_Math_Vec3dMagnitudeSquared(&temp); + t = ((a->v[0]-b[0].v[0])*temp.v[0] + (a->v[1]-b[0].v[1])*temp.v[1]+(a->v[2]-b[0].v[2])*temp.v[2]) / distsqr; + if(t>1.0) + t = 1.0; + if(t<0.0) + t = 0.0; + + /* close[i] = b[i]+ t * temp[i]; */ + SST_Math_Vec3dScale(&temp,t,close); + SST_Math_Vec3dAddLocal(close,b); + + /* temp[i] = close[i]-a[i]; */ + SST_Math_Vec3dSubtract(close,a,&temp); + + return SST_Math_Vec3dMagnitude(&temp); +} + +double PointToPlane3(const SST_Vec3d* a, const SST_Vec3d plane[3]) +{ +#pragma message("PointToPlane3-NOT IMPLEMENTED YET") + return (double)(0.0); +} +#include <stdio.h> +bool SST_Geo_RayPlaneIntersectionD(const SST_Vec3d* RESTRICT ray, const SST_Vec3d* RESTRICT ray_point, const SST_Vec3d* RESTRICT p0, const SST_Vec3d* RESTRICT p1,const SST_Vec3d* RESTRICT p2, SST_Vec3d* RESTRICT Intersection) +{ + /* + * The x=inv(A)*b + [t; u; v] = [l_a-l_b, p1-p0, p2-p0]^-1 * [l_a-p0] + Source: Wiki + In this formulation (to save on computation, t is actually -t from the wiki) + */ + + SST_Vec3d s; + SST_Mat33d A; + double t; + bool inTriangle; + inTriangle = false; + + /* First column */ + SST_Math_Mat33dFromVec3d(&A,ray_point,0); + + /* Second column */ + SST_Math_Vec3dSubtract(p1,p0,&s); + SST_Math_Mat33dFromVec3d(&A,&s,1); + + /* Third column */ + SST_Math_Vec3dSubtract(p2,p0,&s); + SST_Math_Mat33dFromVec3d(&A,&s,2); + + /* form b */ + SST_Math_Vec3dSubtract(ray,p0,&s); + SST_Math_Mat33dCreateLULocal(&A); + SST_Math_Mat33dApplyLUVec(&A,&s,Intersection); + + /* if u,v in [0,1] and (u+v) <= 1: + * ==> then the intersection point is in the plane inside the triangle spanned by the three points p_{i} + */ +#define SST_Math_RangeContains(x,a,b) ( ( (x) >= a ) & ( (x) <= b ) ) + //printf("t %f, u %f, v %f\n",Intersection->x, Intersection->y, Intersection->z); + if(SST_Math_RangeContains(Intersection->v[1],0.0,1.0) & SST_Math_RangeContains(Intersection->v[2],0.0,1.0) & SST_Math_RangeContains(Intersection->v[1]+Intersection->v[2],0.0,1.0)) { + inTriangle = true; + } +#undef SST_Math_RangeContains + /* calculate intersection point */ + t = -Intersection->v[0]; + /* ray_point + Intersection->v[0] * ray */ + SST_Math_Vec3dScale(ray,t,Intersection); + SST_Math_Vec3dAddLocal(Intersection,ray_point); + + return inTriangle; +} +bool SST_Geo_RayPlaneIntersectionF(const SST_Vec3f* RESTRICT ray, const SST_Vec3f* RESTRICT ray_point, const SST_Vec3f* RESTRICT p0, const SST_Vec3f* RESTRICT p1,const SST_Vec3f* RESTRICT p2, SST_Vec3f* RESTRICT Intersection) +{ + /* + * The x=inv(A)*b + [t; u; v] = [l_a-l_b, p1-p0, p2-p0]^-1 * [l_a-p0] + Source: Wiki + */ + + SST_Vec3f s; + SST_Mat33f A; + float t; + bool inTriangle; + inTriangle = false; + + /* First column */ + SST_Math_Mat33fFromVec3f(&A,ray_point,0); + + /* Second column */ + SST_Math_Vec3fSubtract(p1,p0,&s); + SST_Math_Mat33fFromVec3f(&A,&s,1); + + /* Third column */ + SST_Math_Vec3fSubtract(p2,p0,&s); + SST_Math_Mat33fFromVec3f(&A,&s,2); + + /* form b */ + SST_Math_Vec3fSubtract(ray,p0,&s); + SST_Math_Mat33fCreateLULocal(&A); + SST_Math_Mat33fApplyLUVec(&A,&s,Intersection); + + /* if u,v in [0,1] and (u+v) <= 1: + * ==> then the intersection point is in the plane inside the triangle spanned by the three points p_{i} + */ +#define SST_Math_RangeContains(x,a,b) ( ( (x) >= a ) & ( (x) <= b ) ) + //printf("t %f, u %f, v %f\n",Intersection->x, Intersection->y, Intersection->z); + if(SST_Math_RangeContains(Intersection->v[1],0.0f,1.0f) & SST_Math_RangeContains(Intersection->v[2],0.0f,1.0f) & SST_Math_RangeContains(Intersection->v[1]+Intersection->v[2],0.0f,1.0f)) { + inTriangle = true; + } +#undef SST_Math_RangeContains + /* calculate intersection point */ + t = -Intersection->v[0]; + /* ray_point + Intersection->v[0] * ray */ + SST_Math_Vec3fScale(ray,t,Intersection); + SST_Math_Vec3fAddLocal(Intersection,ray_point); + + return inTriangle; +} diff --git a/libsst-math/SST_Mat22d.c b/libsst-math/SST_Mat22d.c new file mode 100644 index 0000000..e35c4c8 --- /dev/null +++ b/libsst-math/SST_Mat22d.c @@ -0,0 +1,396 @@ +/* + AUTOMATICALLY GENERATED FILE - DO NOT EDIT! + Please change MatrixNxN.py and re-run it +*/ +/* Generated with ./MatrixNxN.py n = 2, TYPE = double */ + +#include <float.h> +#include <pstdbool.h> +#include <stdio.h> +#include <math.h> /* for sqrt functions */ +#include <stdlib.h> /* for the abs/labs functions */ +#include <SST/SST_Build.h> + +#include <SST/SST_Mat22.h> +#include <SST/SST_Vec2.h> +void SST_Math_Mat22dAdd(const SST_Mat22d* RESTRICT _A, const SST_Mat22d* RESTRICT _B, SST_Mat22d* RESTRICT _out) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + SST_ASSUME_ALIGNED(_out,16); + + _out->v[0] = _A->v[0] + _B->v[0]; + _out->v[1] = _A->v[1] + _B->v[1]; + _out->v[2] = _A->v[2] + _B->v[2]; + _out->v[3] = _A->v[3] + _B->v[3]; +} + +/******************************************************************************/ + +void SST_Math_Mat22dAddLocal(SST_Mat22d* RESTRICT _A, const SST_Mat22d* RESTRICT _B) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + + _A->v[0] += _B->v[0]; + _A->v[1] += _B->v[1]; + _A->v[2] += _B->v[2]; + _A->v[3] += _B->v[3]; +} + +/******************************************************************************/ + +void SST_Math_Mat22dSubtract(const SST_Mat22d* RESTRICT _A, const SST_Mat22d* RESTRICT _B, SST_Mat22d* RESTRICT _out) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + SST_ASSUME_ALIGNED(_out,16); + + _out->v[0] = _A->v[0] - _B->v[0]; + _out->v[1] = _A->v[1] - _B->v[1]; + _out->v[2] = _A->v[2] - _B->v[2]; + _out->v[3] = _A->v[3] - _B->v[3]; +} + +/******************************************************************************/ + +void SST_Math_Mat22dSubtractLocal(SST_Mat22d* RESTRICT _A, const SST_Mat22d* RESTRICT _B) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + + _A->v[0] -= _B->v[0]; + _A->v[1] -= _B->v[1]; + _A->v[2] -= _B->v[2]; + _A->v[3] -= _B->v[3]; +} + +/******************************************************************************/ + +void SST_Math_Mat22dMultiplyElementwise(const SST_Mat22d* RESTRICT _A, const SST_Mat22d* RESTRICT _B, SST_Mat22d* RESTRICT _out) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + SST_ASSUME_ALIGNED(_out,16); + + _out->v[0] = _A->v[0] * _B->v[0]; + _out->v[1] = _A->v[1] * _B->v[1]; + _out->v[2] = _A->v[2] * _B->v[2]; + _out->v[3] = _A->v[3] * _B->v[3]; +} + +/******************************************************************************/ + +void SST_Math_Mat22dMultiplyElementwiseLocal(SST_Mat22d* RESTRICT _A, const SST_Mat22d* RESTRICT _B) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + + _A->v[0] *= _B->v[0]; + _A->v[1] *= _B->v[1]; + _A->v[2] *= _B->v[2]; + _A->v[3] *= _B->v[3]; +} + +/******************************************************************************/ + +void SST_Math_Mat22dMultiplyScalar(const SST_Mat22d* RESTRICT _A, const double k, SST_Mat22d* RESTRICT _out) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_out,16); + + _out->v[0] = _A->v[0] * k; + _out->v[1] = _A->v[1] * k; + _out->v[2] = _A->v[2] * k; + _out->v[3] = _A->v[3] * k; +} + +/******************************************************************************/ + +void SST_Math_Mat22dMultiplyScalarLocal(SST_Mat22d* RESTRICT _A, const double k) +{ + SST_ASSUME_ALIGNED(_A,16); + + _A->v[0] *= k; + _A->v[1] *= k; + _A->v[2] *= k; + _A->v[3] *= k; +} + +/******************************************************************************/ + + +void SST_Math_Mat22dMultiplyMatrix(const SST_Mat22d* _A, const SST_Mat22d* RESTRICT _B, SST_Mat22d* RESTRICT _out) +{ +SST_ASSUME_ALIGNED(_A,16); +SST_ASSUME_ALIGNED(_B,16); +SST_ASSUME_ALIGNED(_out,16); +_out->v[ 0] = _A->v[ 0]*_B->v[ 0]+_A->v[ 2]*_B->v[ 1]; +_out->v[ 2] = _A->v[ 0]*_B->v[ 2]+_A->v[ 2]*_B->v[ 3]; +_out->v[ 1] = _A->v[ 1]*_B->v[ 0]+_A->v[ 3]*_B->v[ 1]; +_out->v[ 3] = _A->v[ 1]*_B->v[ 2]+_A->v[ 3]*_B->v[ 3]; +} +void SST_Math_Mat22dMultiplyMatrixLocal(SST_Mat22d* RESTRICT _A, const SST_Mat22d* RESTRICT _B) +{ + double tmp[4]; + SST_ASSUME_ALIGNED(_A,16); +SST_ASSUME_ALIGNED(_B,16); +tmp[ 0] = _A->v[ 0]*_B->v[ 0]+_A->v[ 2]*_B->v[ 1]; +tmp[ 2] = _A->v[ 0]*_B->v[ 2]+_A->v[ 2]*_B->v[ 3]; +_A->v[0] = tmp[0]; +_A->v[2] = tmp[2]; + + +tmp[ 1] = _A->v[ 1]*_B->v[ 0]+_A->v[ 3]*_B->v[ 1]; +tmp[ 3] = _A->v[ 1]*_B->v[ 2]+_A->v[ 3]*_B->v[ 3]; +_A->v[1] = tmp[1]; +_A->v[3] = tmp[3]; + + +} +void SST_Math_Mat22dMultiplyVector(const SST_Mat22d* RESTRICT _A, const SST_Vec2d* RESTRICT _v, SST_Vec2d* RESTRICT _out) +{ +SST_ASSUME_ALIGNED(_A,16); +SST_ASSUME_ALIGNED(_v,16); +SST_ASSUME_ALIGNED(_out,16); +_out->v[ 0] = _A->v[ 0]*_v->v[0]+_A->v[ 2]*_v->v[1]; +_out->v[ 1] = _A->v[ 1]*_v->v[0]+_A->v[ 3]*_v->v[1]; +} +void SST_Math_Mat22dMultiplyVectorLocal(const SST_Mat22d* RESTRICT _A, SST_Vec2d* RESTRICT _v) +{ +double tmp[2]; +SST_ASSUME_ALIGNED(_A,16); +SST_ASSUME_ALIGNED(_v,16); +tmp[ 0] = _A->v[ 0]*_v->v[0]+_A->v[ 2]*_v->v[1]; +tmp[ 1] = _A->v[ 1]*_v->v[0]+_A->v[ 3]*_v->v[1]; +_v->v[0] = tmp[0]; +_v->v[1] = tmp[1]; +} +void SST_Math_Mat22dTranspose(const SST_Mat22d* RESTRICT _A, SST_Mat22d* RESTRICT _out) +{ +SST_ASSUME_ALIGNED(_A,16); +SST_ASSUME_ALIGNED(_out,16); +_out->v[ 0] = _A->v[ 0]; +_out->v[ 1] = _A->v[ 2]; +_out->v[ 2] = _A->v[ 1]; +_out->v[ 3] = _A->v[ 3]; +} +void SST_Math_Mat22dTransposeLocal(SST_Mat22d* RESTRICT _A) +{ +double tmp[2]; +SST_ASSUME_ALIGNED(_A,16); +tmp[1] = _A->v[ 2]; +_A->v[ 2] = _A->v[ 1]; +_A->v[ 1] = tmp[1]; +} +bool SST_Math_Mat22dCheckOrthonormal(const SST_Mat22d* _A) +{ +const double diag = -_A->v[0]*_A->v[0] -_A->v[1]*_A->v[1] -_A->v[2]*_A->v[2] -_A->v[3]*_A->v[3]; +const double odiag = _A->v[0]*_A->v[2]+ _A->v[1]*_A->v[3]+ _A->v[2]*_A->v[0]+ _A->v[3]*_A->v[1]; +SST_ASSUME_ALIGNED(_A,16); +return +((fabs( 2.000000000000000+diag)) <= 100*DBL_EPSILON) & +((fabs(odiag)) <= 100*DBL_EPSILON); + + +} +double SST_Math_Mat22dDeterminant(const SST_Mat22d* _A) +{ + const double result = _A->v[0]*_A->v[3]-_A->v[1]*_A->v[2]; + SST_ASSUME_ALIGNED(_A,16); + return result; +} +void SST_Math_Mat22dInvert(const SST_Mat22d* RESTRICT _A, SST_Mat22d* RESTRICT _out) +{ +/* Analytical Invert for 2x2 */ +const double aij = ( 1.000000000000000) / (_A->v[0]*_A->v[3]-_A->v[1]*_A->v[2]); +SST_ASSUME_ALIGNED(_A,16); +_out->v[0] = aij*_A->v[3]; +_out->v[1] = -aij*_A->v[1]; +_out->v[2] = -aij*_A->v[2]; +_out->v[3] = aij*_A->v[0]; + +} +void SST_Math_Mat22dInvertLocal(SST_Mat22d* RESTRICT _A) +{ +/* Analytical Invert for 2x2 */ +const double aij = ( 1.000000000000000) / (_A->v[0]*_A->v[3]-_A->v[1]*_A->v[2]); +const double tmp = _A->v[0]; +SST_ASSUME_ALIGNED(_A,16); +_A->v[0] = aij*_A->v[3]; +_A->v[1] *= -aij; +_A->v[2] *= -aij; +_A->v[3] = aij*tmp; + +} +void SST_Math_Mat22dCreateLU(const SST_Mat22d* RESTRICT _A, SST_Mat22d* RESTRICT _LU) +{ +#define _A(i,j) _A->v[i+2*j] +#define _LU(i,j) _LU->v[i+2*j] + int i,j,k; + double sum; +SST_ASSUME_ALIGNED(_A,16); +SST_ASSUME_ALIGNED(_LU,16); + _LU(0,0) = _A(0,0); + _LU(0,1) = 0; + _LU(1,0) = _A(1,0); + /* _U(0,0) = 1.000000000000000; */ + /* _U(1,1) = 1.000000000000000; */ + _LU(0,1) = _A(0,1) / _LU(0,0); + for(i=1; i < 2; i++) { + + for(j=1; j <= i; j++) { + sum = 0.000000000000000; + for(k=0; k < j; k++) + sum += -_LU(i,k)*_LU(k,j); + _LU(i,j) = _A(i,j) + sum; + } + for(j=i+1; j < 2; j++) { + sum = 0.000000000000000; + for(k=0; k < i; k++) + sum += -_LU(i,k)*_LU(k,j); + _LU(i,j) = (_A(i,j) + sum) / _LU(i,i); + } + } +#undef _A +#undef _LU +} +void SST_Math_Mat22dApplyLUMat(const SST_Mat22d* _LU, const SST_Mat22d* _A, SST_Mat22d* _out) +{ + +#define _LU(i,j) _LU->v[i+2*j] +#define _A(i,j) _A->v[i+2*j] +#define _out(i,j) _out->v[i+2*j] + int i, j, col; + double sum; +SST_ASSUME_ALIGNED(_A,16); +SST_ASSUME_ALIGNED(_LU,16); +SST_ASSUME_ALIGNED(_out,16); + for(col = 0; col < 2; col++) { + _out(0,col) = _A(0,col); + _out(1,col) = _A(1,col); + /* Forward Substitution for Ly = v */ + for(i = 0; i < 2; i++) { + sum = 0.000000000000000; + for(j = 0; j < i; j++) + sum += _LU(i,j) * _out(j,col); + _out(i,col) = (_out(i,col) - sum) / _LU(i,i) ; + } +/* Backwards Substitution for Uw = y */ + for(i = 1; i >=0; i--) { + sum = 0.000000000000000; + for(j = i+1; j < 2; j++) + sum += _LU(i,j) * _out(j,col); + _out(i,col) = (_out(i,col) - sum) ; /* divide by U(i,i)=1 */ + } + } +#undef _LU /* (i,j) _LU->v[i+2*j] */ +#undef _A /* (i,j) _A->v[i+2*j] */ +#undef _out /* (i,j) _out->v[i+2*j] */ +} +void SST_Math_Mat22dApplyLUMatLocal(const SST_Mat22d* _LU,SST_Mat22d* _A) +{ + +#define _LU(i,j) _LU->v[i+2*j] +#define _A(i,j) _A->v[i+2*j] + int i, j, col; + double sum; + for(col = 0; col < 2; col++) { + /* Forward Substitution for Ly = v */ + for(i = 0; i < 2; i++) { + sum = 0.000000000000000; + for(j = 0; j < i; j++) + sum += _LU(i,j) * _A(j,col); + _A(i,col) = (_A(i,col) - sum) / _LU(i,i) ; + } +/* Backwards Substitution for Uw = y */ + for(i = 1; i >=0; i--) { + sum = 0.000000000000000; + for(j = i+1; j < 2; j++) + sum += _LU(i,j) * _A(j,col); + _A(i,col) = (_A(i,col) - sum) ; /* U is 1s along the diagonal */ + } + } +} +void SST_Math_Mat22dApplyLUVec(const SST_Mat22d* _LU, const SST_Vec2d* _v,SST_Vec2d* _w) +{ + +#define _LU(i,j) _LU->v[i+2*j] + int i, j; + double sum; + _w->v[0] = _v->v[0]; + _w->v[1] = _v->v[1]; + /* Forward Substitution for Ly = v */ + for(i = 0; i < 2; i++) { + sum = 0.000000000000000; + for(j = 0; j < i; j++) + sum += _LU(i,j) * _w->v[j]; + _w->v[i] = (_w->v[i] - sum) / _LU(i,i) ; + } +/* Backwards Substitution for Uw = y */ + for(i = 1; i >= 0; i--) { + sum = 0.000000000000000; + for(j = i+1; j < 2; j++) + sum += _LU(i,j) * _w->v[j]; + /*_w->v[i] = (_w->v[i] - sum) ;*/ + _w->v[i] = (_w->v[i] - sum) ; + } +#undef _LU /* (i,j) _LU->v[i+2*j] */ +} +void SST_Math_Mat22dApplyLUVecLocal(const SST_Mat22d* _LU,SST_Vec2d* _w) +{ + +#define _LU(i,j) _LU->v[i+2*j] + int i, j; + double sum; + /* Forward Substitution for Ly = v */ + for(i = 0; i < 2; i++) { + sum = 0.000000000000000; + for(j = 0; j < i; j++) + sum += _LU(i,j) * _w->v[j]; + _w->v[i] = (_w->v[i] - sum) / _LU(i,i) ; + } +/* Backwards Substitution for Uw = y */ + for(i = 1; i >= 0; i--) { + sum = 0.000000000000000; + for(j = i+1; j < 2; j++) + sum += _LU(i,j) * _w->v[j]; + /*_w->v[i] = (_w->v[i] - sum) ;*/ + _w->v[i] = (_w->v[i] - sum) ; + } +#undef _LU /* (i,j) _LU->v[i+2*j] */ +} +void SST_Math_Mat22dCreateLULocal(SST_Mat22d* RESTRICT _A) +{ + /* Note this code stores both L and U inside of A */ + /* For A in R[n x m] we say that for n = m there is an LU = A decomposition [In our decomp, diag[L] = I. Furthermore there is an LU=PA decomposition, where P is a permutation matrix + Step 1: U(i,i:m) = A(i,i:m) + Step 2: L(i+1:n,i) = -A(i+1:n,i) + Step 3: ??? + Step 4: Profit */ +#define _A(i,j) _A->v[i+2*j] + int i,j,k; + double sum; +/* These entries are the same as before in the algorithm. This is left in for purposes of clarity and completeness +_L(0,0) = _A(0,0); +_L(1,0) = _A(1,0); +These entries are understood to be 1 in this storage format. This is left in for purposes of clarity and completeness +_U(0,0) = 1.000000000000000; +_U(1,1) = 1.000000000000000; +*/ +_A(0,1) = _A(0,1) / _A(0,0); + for(i=1; i < 2; i++) { + + for(j=0; j <= i; j++) { + sum = 0.000000000000000; + for(k=0; k < j; k++) sum += -_A(i,k)*_A(k,j); + _A(i,j) = _A(i,j) + sum; + } + for(j=i+1; j < 2; j++) { + sum = 0.000000000000000; + for(k=0; k < i; k++) sum += -_A(i,k)*_A(k,j); + _A(i,j) = (_A(i,j) + sum) / _A(i,i); + } + } +#undef _A +} diff --git a/libsst-math/SST_Mat22d_benchmark.c b/libsst-math/SST_Mat22d_benchmark.c new file mode 100644 index 0000000..e25e4ca --- /dev/null +++ b/libsst-math/SST_Mat22d_benchmark.c @@ -0,0 +1,408 @@ +#include <float.h> +#include <math.h> +#include <stdlib.h> +#include <stdio.h> +#include <assert.h> +#include <xmmintrin.h> +#include <SST/SST_Timer_x86.h> +#include <SST/SST_Mat22.h> +#include <SST/SST_Vec2.h> + + + + +int SST_Math_Mat22d_test_fxns() +{ +const int NTESTS = 10; +int i; +uint64_t t0,t1; +SST_Mat22d X; /* 2 x 2 matrix */ +SST_Mat22d Y; /* 2 x 2 matrix */ +SST_Mat22d A; /* 2 x 2 matrix */ +SST_Mat22d B; /* 2 x 2 matrix */ +SST_Vec2d v; /* 2 vector */ +SST_Vec2d w; /* 2 vector */ +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +/* Resetting test vectors / mats */ + v.v[0] = -10.000000000000000; + v.v[1] = -20.000000000000000; + X.v[0] = 13.000000000000000; + X.v[1] = -18.000000000000000; + X.v[2] = -9.000000000000000; + X.v[3] = -2.000000000000000; + Y.v[0] = -9.000000000000000; + Y.v[1] = 1.000000000000000; + Y.v[2] = 1.000000000000000; + Y.v[3] = 4.000000000000000; +SST_Math_Mat22dAdd(&X,&Y,&A); /* clear out the initial finding of object */ +/* Clear out the rdtsc register */ +fprintf(stdout,"SST_Math_Mat22dAdd(X,Y,A)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat22dAdd(&X,&Y,&A); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +/* +[[ 13. -9.] + [-18. -2.]] +[[-9. 1.] + [ 1. 4.]] +[[ 4. -8.] + [-17. 2.]] +*/ +assert(fabs((A.v[0])-( 4.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[2])-( -8.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[1])-( -17.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[3])-( 2.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +/* +[[ 13. -9.] + [-18. -2.]] +[[-9. 1.] + [ 1. 4.]] +[[ 4. -8.] + [-17. 2.]] +*/ +fprintf(stdout,"SST_Math_Mat22dAddLocal(A,Y)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat22dAddLocal(&A,&Y); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +SST_Math_Mat22dAddLocal(&X,&Y); /* for accuracy */ +assert(fabs((X.v[0])-( 4.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[2])-( -8.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[1])-( -17.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[3])-( 2.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +/* Resetting test vectors / mats */ + v.v[0] = -11.000000000000000; + v.v[1] = -4.000000000000000; + X.v[0] = -13.000000000000000; + X.v[1] = 5.000000000000000; + X.v[2] = 6.000000000000000; + X.v[3] = 10.000000000000000; + Y.v[0] = -18.000000000000000; + Y.v[1] = 9.000000000000000; + Y.v[2] = -1.000000000000000; + Y.v[3] = 17.000000000000000; +/* +[[-13. 6.] + [ 5. 10.]] +[[-26. 12.] + [ 10. 20.]] +*/ +fprintf(stdout,"SST_Math_Mat22dMultiplyScalar(X,t,Y)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat22dMultiplyScalar(&X, 2.000000000000000,&A); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +assert(fabs((A.v[0])-( -26.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[2])-( 12.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[1])-( 10.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[3])-( 20.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +/* +[[-13. 6.] + [ 5. 10.]] +[[-26. 12.] + [ 10. 20.]] +*/ +fprintf(stdout,"SST_Math_Mat22dMultiplyScalarLocal(A,t)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat22dMultiplyScalarLocal(&A, 2.000000000000000); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +SST_Math_Mat22dMultiplyScalarLocal(&X, 2.000000000000000); +assert(fabs((X.v[0])-( -26.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[2])-( 12.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[1])-( 10.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[3])-( 20.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +/* Resetting test vectors / mats */ + v.v[0] = 12.000000000000000; + v.v[1] = -7.000000000000000; + X.v[0] = -20.000000000000000; + X.v[1] = -2.000000000000000; + X.v[2] = -1.000000000000000; + X.v[3] = -20.000000000000000; + Y.v[0] = 12.000000000000000; + Y.v[1] = 0.000000000000000; + Y.v[2] = 5.000000000000000; + Y.v[3] = -17.000000000000000; +/* +[[-20. -1.] + [ -2. -20.]] +[[ 12. 5.] + [ 0. -17.]] +[[-240. -5.] + [ -0. 340.]] +*/ +fprintf(stdout,"SST_Math_Mat22dMultiplyElementwise(X,Y,A)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat22dMultiplyElementwise(&X, &Y, &A); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +assert(fabs((A.v[0])-( -240.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[2])-( -5.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[1])-( -0.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[3])-( 340.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +/* +[[-20. -1.] + [ -2. -20.]] +[[ 12. 5.] + [ 0. -17.]] +[[-240. -5.] + [ -0. 340.]] +*/ +fprintf(stdout,"SST_Math_Mat22dMultiplyElementwiseLocal(X,Y)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat22dMultiplyElementwiseLocal(&A,&Y); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +SST_Math_Mat22dMultiplyElementwiseLocal(&X,&Y); +assert(fabs((X.v[0])-( -240.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[2])-( -5.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[1])-( -0.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[3])-( 340.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +/* Resetting test vectors / mats */ + v.v[0] = -4.000000000000000; + v.v[1] = -5.000000000000000; + X.v[0] = 18.000000000000000; + X.v[1] = 18.000000000000000; + X.v[2] = 10.000000000000000; + X.v[3] = -4.000000000000000; + Y.v[0] = -4.000000000000000; + Y.v[1] = 5.000000000000000; + Y.v[2] = 16.000000000000000; + Y.v[3] = 16.000000000000000; +/* +X +[[ 18. 10.] + [ 18. -4.]] +Y +[[ -4. 16.] + [ 5. 16.]] +[[ -22. 448.] + [ -92. 224.]] +*/ +fprintf(stdout,"SST_Math_Mat22dMultiplyMatrix(X,Y,A)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat22dMultiplyMatrix(&X,&Y,&A); +t1 = rdtsc(); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +assert(fabs((A.v[0])-( -22.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[2])-( 448.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[1])-( -92.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[3])-( 224.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +/* +X +[[ 18. 10.] + [ 18. -4.]] +Y +[[ -4. 16.] + [ 5. 16.]] +X +[[ -22. 448.] + [ -92. 224.]] +*/ +fprintf(stdout,"SST_Math_Mat22dMultiplyMatrixLocal(X,Y)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat22dMultiplyMatrixLocal(&A,&Y); +t1 = rdtsc(); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +SST_Math_Mat22dMultiplyMatrixLocal(&X,&Y); +assert(fabs((X.v[0])-( -22.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[2])-( 448.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[1])-( -92.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[3])-( 224.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +/* Resetting test vectors / mats */ + v.v[0] = 6.000000000000000; + v.v[1] = -13.000000000000000; + X.v[0] = -4.000000000000000; + X.v[1] = 1.000000000000000; + X.v[2] = -20.000000000000000; + X.v[3] = -16.000000000000000; + Y.v[0] = 0.000000000000000; + Y.v[1] = 17.000000000000000; + Y.v[2] = -20.000000000000000; + Y.v[3] = 14.000000000000000; +/* +X +[[ -4. -20.] + [ 1. -16.]] +v +[ 6. -13.] +w +[ 236. 214.] +*/ +i=0; +fprintf(stdout,"SST_Math_Mat22dMultiplyVector(X,v,w)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat22dMultiplyVector(&X,&v,&w); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +assert(fabs((w.v[0])-( 236.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((w.v[1])-( 214.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +/* +X +[[ -4. -20.] + [ 1. -16.]] +v +[ 6. -13.] +v +[ 236. 214.] +*/ +fprintf(stdout,"SST_Math_Mat22dMultiplyVectorLocal(X,v)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat22dMultiplyVectorLocal(&X,&w); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +SST_Math_Mat22dMultiplyVectorLocal(&X,&v); +assert(fabs((v.v[0])-( 236.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((v.v[1])-( 214.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +/* Resetting test vectors / mats */ + v.v[0] = -2.000000000000000; + v.v[1] = -6.000000000000000; + X.v[0] = -19.000000000000000; + X.v[1] = 0.000000000000000; + X.v[2] = -15.000000000000000; + X.v[3] = -4.000000000000000; + Y.v[0] = -5.000000000000000; + Y.v[1] = 16.000000000000000; + Y.v[2] = 11.000000000000000; + Y.v[3] = -8.000000000000000; +fprintf(stdout,"SST_Math_Mat22dTranspose(X,A)"); +t0 = rdtsc(); +SST_Math_Mat22dTranspose(&X,&A); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +assert(fabs((A.v[0])-( -19.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[2])-( 0.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[1])-( -15.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[3])-( -4.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +fprintf(stdout,"SST_Math_Mat22dTransposeLocal(X)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat22dTransposeLocal(&A); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +SST_Math_Mat22dTransposeLocal(&X); +assert(fabs((X.v[0])-( -19.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[2])-( 0.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[1])-( -15.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[3])-( -4.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +/* +[[ 1. 0.] + [ 0. 1.]] +[[ 1. 0.] + [ 0. 1.]] +*/ +X.v[0] = (double) 1.000000000000000; +X.v[2] = (double) 0.000000000000000; +X.v[1] = (double) 0.000000000000000; +X.v[3] = (double) 1.000000000000000; +fprintf(stdout,"SST_Math_Mat22dTranspose(X,A)"); +t0 = rdtsc(); +SST_Math_Mat22dTranspose(&X,&A); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +fprintf(stdout,"SST_Math_Mat22dMultiplyMatrix(A,X,B)"); +t0 = rdtsc(); +SST_Math_Mat22dMultiplyMatrix(&A,&X,&B); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +/* Check Negative Test */ +assert(!SST_Math_Mat22dCheckOrthonormal(&X)); +X.v[0] = (double) 1.000000000000000; +X.v[2] = (double) 0.000000000000000; +X.v[1] = (double) 0.000000000000000; +X.v[3] = (double) 1.000000000000000; +/* Check Positive Test */ +assert(SST_Math_Mat22dCheckOrthonormal(&X)); +/* Resetting test vectors / mats */ + v.v[0] = 11.000000000000000; + v.v[1] = 18.000000000000000; + X.v[0] = -18.000000000000000; + X.v[1] = -13.000000000000000; + X.v[2] = -11.000000000000000; + X.v[3] = 0.000000000000000; + Y.v[0] = 6.000000000000000; + Y.v[1] = 3.000000000000000; + Y.v[2] = -19.000000000000000; + Y.v[3] = -15.000000000000000; +/* +[[ -6.16790569e-18 -7.69230769e-02] + [ -9.09090909e-02 1.25874126e-01]] +*/ +fprintf(stdout,"SST_Math_Mat22dInvert(X,B)\n"); +t0 = rdtsc(); +SST_Math_Mat22dInvert(&X,&B); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +fprintf(stdout,"B[%d][%d] = %24.15lf\n",0,0,B.v[0]); +fprintf(stdout,"B[%d][%d] = %24.15lf\n",0,1,B.v[1]); +fprintf(stdout,"B[%d][%d] = %24.15lf\n",1,0,B.v[2]); +fprintf(stdout,"B[%d][%d] = %24.15lf\n",1,1,B.v[3]); +assert(fabs((B.v[0])-( -0.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((B.v[2])-( -0.076923076923077)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((B.v[1])-( -0.090909090909091)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((B.v[3])-( 0.125874125874126)) <=100*DBL_EPSILON /* yes this is bad */); +/* Resetting test vectors / mats */ + v.v[0] = 16.000000000000000; + v.v[1] = 6.000000000000000; + X.v[0] = 17.000000000000000; + X.v[1] = 15.000000000000000; + X.v[2] = -1.000000000000000; + X.v[3] = 6.000000000000000; + Y.v[0] = -1.000000000000000; + Y.v[1] = 17.000000000000000; + Y.v[2] = -18.000000000000000; + Y.v[3] = -8.000000000000000; +/* +[[ 0.05128205 0.00854701] + [-0.12820513 0.14529915]] +*/ +fprintf(stdout,"SST_Math_Mat22dInvert(X,B)\n"); +fflush(stdout); +fprintf(stdout,"SST_Math_Mat22dInvertLocal(X,B)\n"); +t0 = rdtsc(); +SST_Math_Mat22dInvertLocal(&X); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +fflush(stdout); +assert(fabs((X.v[0])-( 0.051282051282051)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[2])-( 0.008547008547009)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[1])-( -0.128205128205128)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[3])-( 0.145299145299145)) <=100*DBL_EPSILON /* yes this is bad */); +fprintf(stdout,"\n==== SST_Math_Mat22dtest_fxn COMPLETE ====\n"); +return 0; +} diff --git a/libsst-math/SST_Mat22f.c b/libsst-math/SST_Mat22f.c new file mode 100644 index 0000000..a4da83c --- /dev/null +++ b/libsst-math/SST_Mat22f.c @@ -0,0 +1,396 @@ +/* + AUTOMATICALLY GENERATED FILE - DO NOT EDIT! + Please change MatrixNxN.py and re-run it +*/ +/* Generated with ./MatrixNxN.py n = 2, TYPE = float */ + +#include <float.h> +#include <pstdbool.h> +#include <stdio.h> +#include <math.h> /* for sqrt functions */ +#include <stdlib.h> /* for the abs/labs functions */ +#include <SST/SST_Build.h> + +#include <SST/SST_Mat22.h> +#include <SST/SST_Vec2.h> +void SST_Math_Mat22fAdd(const SST_Mat22f* RESTRICT _A, const SST_Mat22f* RESTRICT _B, SST_Mat22f* RESTRICT _out) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + SST_ASSUME_ALIGNED(_out,16); + + _out->v[0] = _A->v[0] + _B->v[0]; + _out->v[1] = _A->v[1] + _B->v[1]; + _out->v[2] = _A->v[2] + _B->v[2]; + _out->v[3] = _A->v[3] + _B->v[3]; +} + +/******************************************************************************/ + +void SST_Math_Mat22fAddLocal(SST_Mat22f* RESTRICT _A, const SST_Mat22f* RESTRICT _B) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + + _A->v[0] += _B->v[0]; + _A->v[1] += _B->v[1]; + _A->v[2] += _B->v[2]; + _A->v[3] += _B->v[3]; +} + +/******************************************************************************/ + +void SST_Math_Mat22fSubtract(const SST_Mat22f* RESTRICT _A, const SST_Mat22f* RESTRICT _B, SST_Mat22f* RESTRICT _out) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + SST_ASSUME_ALIGNED(_out,16); + + _out->v[0] = _A->v[0] - _B->v[0]; + _out->v[1] = _A->v[1] - _B->v[1]; + _out->v[2] = _A->v[2] - _B->v[2]; + _out->v[3] = _A->v[3] - _B->v[3]; +} + +/******************************************************************************/ + +void SST_Math_Mat22fSubtractLocal(SST_Mat22f* RESTRICT _A, const SST_Mat22f* RESTRICT _B) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + + _A->v[0] -= _B->v[0]; + _A->v[1] -= _B->v[1]; + _A->v[2] -= _B->v[2]; + _A->v[3] -= _B->v[3]; +} + +/******************************************************************************/ + +void SST_Math_Mat22fMultiplyElementwise(const SST_Mat22f* RESTRICT _A, const SST_Mat22f* RESTRICT _B, SST_Mat22f* RESTRICT _out) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + SST_ASSUME_ALIGNED(_out,16); + + _out->v[0] = _A->v[0] * _B->v[0]; + _out->v[1] = _A->v[1] * _B->v[1]; + _out->v[2] = _A->v[2] * _B->v[2]; + _out->v[3] = _A->v[3] * _B->v[3]; +} + +/******************************************************************************/ + +void SST_Math_Mat22fMultiplyElementwiseLocal(SST_Mat22f* RESTRICT _A, const SST_Mat22f* RESTRICT _B) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + + _A->v[0] *= _B->v[0]; + _A->v[1] *= _B->v[1]; + _A->v[2] *= _B->v[2]; + _A->v[3] *= _B->v[3]; +} + +/******************************************************************************/ + +void SST_Math_Mat22fMultiplyScalar(const SST_Mat22f* RESTRICT _A, const float k, SST_Mat22f* RESTRICT _out) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_out,16); + + _out->v[0] = _A->v[0] * k; + _out->v[1] = _A->v[1] * k; + _out->v[2] = _A->v[2] * k; + _out->v[3] = _A->v[3] * k; +} + +/******************************************************************************/ + +void SST_Math_Mat22fMultiplyScalarLocal(SST_Mat22f* RESTRICT _A, const float k) +{ + SST_ASSUME_ALIGNED(_A,16); + + _A->v[0] *= k; + _A->v[1] *= k; + _A->v[2] *= k; + _A->v[3] *= k; +} + +/******************************************************************************/ + + +void SST_Math_Mat22fMultiplyMatrix(const SST_Mat22f* _A, const SST_Mat22f* RESTRICT _B, SST_Mat22f* RESTRICT _out) +{ +SST_ASSUME_ALIGNED(_A,16); +SST_ASSUME_ALIGNED(_B,16); +SST_ASSUME_ALIGNED(_out,16); +_out->v[ 0] = _A->v[ 0]*_B->v[ 0]+_A->v[ 2]*_B->v[ 1]; +_out->v[ 2] = _A->v[ 0]*_B->v[ 2]+_A->v[ 2]*_B->v[ 3]; +_out->v[ 1] = _A->v[ 1]*_B->v[ 0]+_A->v[ 3]*_B->v[ 1]; +_out->v[ 3] = _A->v[ 1]*_B->v[ 2]+_A->v[ 3]*_B->v[ 3]; +} +void SST_Math_Mat22fMultiplyMatrixLocal(SST_Mat22f* RESTRICT _A, const SST_Mat22f* RESTRICT _B) +{ + float tmp[4]; + SST_ASSUME_ALIGNED(_A,16); +SST_ASSUME_ALIGNED(_B,16); +tmp[ 0] = _A->v[ 0]*_B->v[ 0]+_A->v[ 2]*_B->v[ 1]; +tmp[ 2] = _A->v[ 0]*_B->v[ 2]+_A->v[ 2]*_B->v[ 3]; +_A->v[0] = tmp[0]; +_A->v[2] = tmp[2]; + + +tmp[ 1] = _A->v[ 1]*_B->v[ 0]+_A->v[ 3]*_B->v[ 1]; +tmp[ 3] = _A->v[ 1]*_B->v[ 2]+_A->v[ 3]*_B->v[ 3]; +_A->v[1] = tmp[1]; +_A->v[3] = tmp[3]; + + +} +void SST_Math_Mat22fMultiplyVector(const SST_Mat22f* RESTRICT _A, const SST_Vec2f* RESTRICT _v, SST_Vec2f* RESTRICT _out) +{ +SST_ASSUME_ALIGNED(_A,16); +SST_ASSUME_ALIGNED(_v,16); +SST_ASSUME_ALIGNED(_out,16); +_out->v[ 0] = _A->v[ 0]*_v->v[0]+_A->v[ 2]*_v->v[1]; +_out->v[ 1] = _A->v[ 1]*_v->v[0]+_A->v[ 3]*_v->v[1]; +} +void SST_Math_Mat22fMultiplyVectorLocal(const SST_Mat22f* RESTRICT _A, SST_Vec2f* RESTRICT _v) +{ +float tmp[2]; +SST_ASSUME_ALIGNED(_A,16); +SST_ASSUME_ALIGNED(_v,16); +tmp[ 0] = _A->v[ 0]*_v->v[0]+_A->v[ 2]*_v->v[1]; +tmp[ 1] = _A->v[ 1]*_v->v[0]+_A->v[ 3]*_v->v[1]; +_v->v[0] = tmp[0]; +_v->v[1] = tmp[1]; +} +void SST_Math_Mat22fTranspose(const SST_Mat22f* RESTRICT _A, SST_Mat22f* RESTRICT _out) +{ +SST_ASSUME_ALIGNED(_A,16); +SST_ASSUME_ALIGNED(_out,16); +_out->v[ 0] = _A->v[ 0]; +_out->v[ 1] = _A->v[ 2]; +_out->v[ 2] = _A->v[ 1]; +_out->v[ 3] = _A->v[ 3]; +} +void SST_Math_Mat22fTransposeLocal(SST_Mat22f* RESTRICT _A) +{ +float tmp[2]; +SST_ASSUME_ALIGNED(_A,16); +tmp[1] = _A->v[ 2]; +_A->v[ 2] = _A->v[ 1]; +_A->v[ 1] = tmp[1]; +} +bool SST_Math_Mat22fCheckOrthonormal(const SST_Mat22f* _A) +{ +const float diag = -_A->v[0]*_A->v[0] -_A->v[1]*_A->v[1] -_A->v[2]*_A->v[2] -_A->v[3]*_A->v[3]; +const float odiag = _A->v[0]*_A->v[2]+ _A->v[1]*_A->v[3]+ _A->v[2]*_A->v[0]+ _A->v[3]*_A->v[1]; +SST_ASSUME_ALIGNED(_A,16); +return +((fabsf(2.000000f+diag)) <= 100*FLT_EPSILON) & +((fabsf(odiag)) <= 100*FLT_EPSILON); + + +} +float SST_Math_Mat22fDeterminant(const SST_Mat22f* _A) +{ + const float result = _A->v[0]*_A->v[3]-_A->v[1]*_A->v[2]; + SST_ASSUME_ALIGNED(_A,16); + return result; +} +void SST_Math_Mat22fInvert(const SST_Mat22f* RESTRICT _A, SST_Mat22f* RESTRICT _out) +{ +/* Analytical Invert for 2x2 */ +const float aij = (1.000000f) / (_A->v[0]*_A->v[3]-_A->v[1]*_A->v[2]); +SST_ASSUME_ALIGNED(_A,16); +_out->v[0] = aij*_A->v[3]; +_out->v[1] = -aij*_A->v[1]; +_out->v[2] = -aij*_A->v[2]; +_out->v[3] = aij*_A->v[0]; + +} +void SST_Math_Mat22fInvertLocal(SST_Mat22f* RESTRICT _A) +{ +/* Analytical Invert for 2x2 */ +const float aij = (1.000000f) / (_A->v[0]*_A->v[3]-_A->v[1]*_A->v[2]); +const float tmp = _A->v[0]; +SST_ASSUME_ALIGNED(_A,16); +_A->v[0] = aij*_A->v[3]; +_A->v[1] *= -aij; +_A->v[2] *= -aij; +_A->v[3] = aij*tmp; + +} +void SST_Math_Mat22fCreateLU(const SST_Mat22f* RESTRICT _A, SST_Mat22f* RESTRICT _LU) +{ +#define _A(i,j) _A->v[i+2*j] +#define _LU(i,j) _LU->v[i+2*j] + int i,j,k; + float sum; +SST_ASSUME_ALIGNED(_A,16); +SST_ASSUME_ALIGNED(_LU,16); + _LU(0,0) = _A(0,0); + _LU(0,1) = 0; + _LU(1,0) = _A(1,0); + /* _U(0,0) = 1.000000f; */ + /* _U(1,1) = 1.000000f; */ + _LU(0,1) = _A(0,1) / _LU(0,0); + for(i=1; i < 2; i++) { + + for(j=1; j <= i; j++) { + sum = 0.000000f; + for(k=0; k < j; k++) + sum += -_LU(i,k)*_LU(k,j); + _LU(i,j) = _A(i,j) + sum; + } + for(j=i+1; j < 2; j++) { + sum = 0.000000f; + for(k=0; k < i; k++) + sum += -_LU(i,k)*_LU(k,j); + _LU(i,j) = (_A(i,j) + sum) / _LU(i,i); + } + } +#undef _A +#undef _LU +} +void SST_Math_Mat22fApplyLUMat(const SST_Mat22f* _LU, const SST_Mat22f* _A, SST_Mat22f* _out) +{ + +#define _LU(i,j) _LU->v[i+2*j] +#define _A(i,j) _A->v[i+2*j] +#define _out(i,j) _out->v[i+2*j] + int i, j, col; + float sum; +SST_ASSUME_ALIGNED(_A,16); +SST_ASSUME_ALIGNED(_LU,16); +SST_ASSUME_ALIGNED(_out,16); + for(col = 0; col < 2; col++) { + _out(0,col) = _A(0,col); + _out(1,col) = _A(1,col); + /* Forward Substitution for Ly = v */ + for(i = 0; i < 2; i++) { + sum = 0.000000f; + for(j = 0; j < i; j++) + sum += _LU(i,j) * _out(j,col); + _out(i,col) = (_out(i,col) - sum) / _LU(i,i) ; + } +/* Backwards Substitution for Uw = y */ + for(i = 1; i >=0; i--) { + sum = 0.000000f; + for(j = i+1; j < 2; j++) + sum += _LU(i,j) * _out(j,col); + _out(i,col) = (_out(i,col) - sum) ; /* divide by U(i,i)=1 */ + } + } +#undef _LU /* (i,j) _LU->v[i+2*j] */ +#undef _A /* (i,j) _A->v[i+2*j] */ +#undef _out /* (i,j) _out->v[i+2*j] */ +} +void SST_Math_Mat22fApplyLUMatLocal(const SST_Mat22f* _LU,SST_Mat22f* _A) +{ + +#define _LU(i,j) _LU->v[i+2*j] +#define _A(i,j) _A->v[i+2*j] + int i, j, col; + float sum; + for(col = 0; col < 2; col++) { + /* Forward Substitution for Ly = v */ + for(i = 0; i < 2; i++) { + sum = 0.000000f; + for(j = 0; j < i; j++) + sum += _LU(i,j) * _A(j,col); + _A(i,col) = (_A(i,col) - sum) / _LU(i,i) ; + } +/* Backwards Substitution for Uw = y */ + for(i = 1; i >=0; i--) { + sum = 0.000000f; + for(j = i+1; j < 2; j++) + sum += _LU(i,j) * _A(j,col); + _A(i,col) = (_A(i,col) - sum) ; /* U is 1s along the diagonal */ + } + } +} +void SST_Math_Mat22fApplyLUVec(const SST_Mat22f* _LU, const SST_Vec2f* _v,SST_Vec2f* _w) +{ + +#define _LU(i,j) _LU->v[i+2*j] + int i, j; + float sum; + _w->v[0] = _v->v[0]; + _w->v[1] = _v->v[1]; + /* Forward Substitution for Ly = v */ + for(i = 0; i < 2; i++) { + sum = 0.000000f; + for(j = 0; j < i; j++) + sum += _LU(i,j) * _w->v[j]; + _w->v[i] = (_w->v[i] - sum) / _LU(i,i) ; + } +/* Backwards Substitution for Uw = y */ + for(i = 1; i >= 0; i--) { + sum = 0.000000f; + for(j = i+1; j < 2; j++) + sum += _LU(i,j) * _w->v[j]; + /*_w->v[i] = (_w->v[i] - sum) ;*/ + _w->v[i] = (_w->v[i] - sum) ; + } +#undef _LU /* (i,j) _LU->v[i+2*j] */ +} +void SST_Math_Mat22fApplyLUVecLocal(const SST_Mat22f* _LU,SST_Vec2f* _w) +{ + +#define _LU(i,j) _LU->v[i+2*j] + int i, j; + float sum; + /* Forward Substitution for Ly = v */ + for(i = 0; i < 2; i++) { + sum = 0.000000f; + for(j = 0; j < i; j++) + sum += _LU(i,j) * _w->v[j]; + _w->v[i] = (_w->v[i] - sum) / _LU(i,i) ; + } +/* Backwards Substitution for Uw = y */ + for(i = 1; i >= 0; i--) { + sum = 0.000000f; + for(j = i+1; j < 2; j++) + sum += _LU(i,j) * _w->v[j]; + /*_w->v[i] = (_w->v[i] - sum) ;*/ + _w->v[i] = (_w->v[i] - sum) ; + } +#undef _LU /* (i,j) _LU->v[i+2*j] */ +} +void SST_Math_Mat22fCreateLULocal(SST_Mat22f* RESTRICT _A) +{ + /* Note this code stores both L and U inside of A */ + /* For A in R[n x m] we say that for n = m there is an LU = A decomposition [In our decomp, diag[L] = I. Furthermore there is an LU=PA decomposition, where P is a permutation matrix + Step 1: U(i,i:m) = A(i,i:m) + Step 2: L(i+1:n,i) = -A(i+1:n,i) + Step 3: ??? + Step 4: Profit */ +#define _A(i,j) _A->v[i+2*j] + int i,j,k; + float sum; +/* These entries are the same as before in the algorithm. This is left in for purposes of clarity and completeness +_L(0,0) = _A(0,0); +_L(1,0) = _A(1,0); +These entries are understood to be 1 in this storage format. This is left in for purposes of clarity and completeness +_U(0,0) = 1.000000f; +_U(1,1) = 1.000000f; +*/ +_A(0,1) = _A(0,1) / _A(0,0); + for(i=1; i < 2; i++) { + + for(j=0; j <= i; j++) { + sum = 0.000000f; + for(k=0; k < j; k++) sum += -_A(i,k)*_A(k,j); + _A(i,j) = _A(i,j) + sum; + } + for(j=i+1; j < 2; j++) { + sum = 0.000000f; + for(k=0; k < i; k++) sum += -_A(i,k)*_A(k,j); + _A(i,j) = (_A(i,j) + sum) / _A(i,i); + } + } +#undef _A +} diff --git a/libsst-math/SST_Mat22f_benchmark.c b/libsst-math/SST_Mat22f_benchmark.c new file mode 100644 index 0000000..ac13b42 --- /dev/null +++ b/libsst-math/SST_Mat22f_benchmark.c @@ -0,0 +1,408 @@ +#include <float.h> +#include <math.h> +#include <stdlib.h> +#include <stdio.h> +#include <assert.h> +#include <xmmintrin.h> +#include <SST/SST_Timer_x86.h> +#include <SST/SST_Mat22.h> +#include <SST/SST_Vec2.h> + + + + +int SST_Math_Mat22f_test_fxns() +{ +const int NTESTS = 10; +int i; +uint64_t t0,t1; +SST_Mat22f X; /* 2 x 2 matrix */ +SST_Mat22f Y; /* 2 x 2 matrix */ +SST_Mat22f A; /* 2 x 2 matrix */ +SST_Mat22f B; /* 2 x 2 matrix */ +SST_Vec2f v; /* 2 vector */ +SST_Vec2f w; /* 2 vector */ +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +/* Resetting test vectors / mats */ + v.v[0] = -11.000000f; + v.v[1] = -4.000000f; + X.v[0] = -5.000000f; + X.v[1] = -2.000000f; + X.v[2] = -20.000000f; + X.v[3] = -13.000000f; + Y.v[0] = -13.000000f; + Y.v[1] = -18.000000f; + Y.v[2] = 13.000000f; + Y.v[3] = -4.000000f; +SST_Math_Mat22fAdd(&X,&Y,&A); /* clear out the initial finding of object */ +/* Clear out the rdtsc register */ +fprintf(stdout,"SST_Math_Mat22fAdd(X,Y,A)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat22fAdd(&X,&Y,&A); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +/* +[[ -5. -20.] + [ -2. -13.]] +[[-13. 13.] + [-18. -4.]] +[[-18. -7.] + [-20. -17.]] +*/ +assert(fabsf((A.v[0])-(-18.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[2])-(-7.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[1])-(-20.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[3])-(-17.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +/* +[[ -5. -20.] + [ -2. -13.]] +[[-13. 13.] + [-18. -4.]] +[[-18. -7.] + [-20. -17.]] +*/ +fprintf(stdout,"SST_Math_Mat22fAddLocal(A,Y)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat22fAddLocal(&A,&Y); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +SST_Math_Mat22fAddLocal(&X,&Y); /* for accuracy */ +assert(fabsf((X.v[0])-(-18.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[2])-(-7.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[1])-(-20.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[3])-(-17.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +/* Resetting test vectors / mats */ + v.v[0] = -12.000000f; + v.v[1] = 8.000000f; + X.v[0] = -2.000000f; + X.v[1] = 17.000000f; + X.v[2] = -18.000000f; + X.v[3] = -7.000000f; + Y.v[0] = -1.000000f; + Y.v[1] = 0.000000f; + Y.v[2] = -12.000000f; + Y.v[3] = 15.000000f; +/* +[[ -2. -18.] + [ 17. -7.]] +[[ -4. -36.] + [ 34. -14.]] +*/ +fprintf(stdout,"SST_Math_Mat22fMultiplyScalar(X,t,Y)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat22fMultiplyScalar(&X,2.000000f,&A); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +assert(fabsf((A.v[0])-(-4.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[2])-(-36.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[1])-(34.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[3])-(-14.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +/* +[[ -2. -18.] + [ 17. -7.]] +[[ -4. -36.] + [ 34. -14.]] +*/ +fprintf(stdout,"SST_Math_Mat22fMultiplyScalarLocal(A,t)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat22fMultiplyScalarLocal(&A,2.000000f); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +SST_Math_Mat22fMultiplyScalarLocal(&X,2.000000f); +assert(fabsf((X.v[0])-(-4.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[2])-(-36.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[1])-(34.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[3])-(-14.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +/* Resetting test vectors / mats */ + v.v[0] = -18.000000f; + v.v[1] = 2.000000f; + X.v[0] = -19.000000f; + X.v[1] = 1.000000f; + X.v[2] = 14.000000f; + X.v[3] = 16.000000f; + Y.v[0] = -13.000000f; + Y.v[1] = -1.000000f; + Y.v[2] = -13.000000f; + Y.v[3] = -14.000000f; +/* +[[-19. 14.] + [ 1. 16.]] +[[-13. -13.] + [ -1. -14.]] +[[ 247. -182.] + [ -1. -224.]] +*/ +fprintf(stdout,"SST_Math_Mat22fMultiplyElementwise(X,Y,A)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat22fMultiplyElementwise(&X, &Y, &A); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +assert(fabsf((A.v[0])-(247.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[2])-(-182.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[1])-(-1.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[3])-(-224.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +/* +[[-19. 14.] + [ 1. 16.]] +[[-13. -13.] + [ -1. -14.]] +[[ 247. -182.] + [ -1. -224.]] +*/ +fprintf(stdout,"SST_Math_Mat22fMultiplyElementwiseLocal(X,Y)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat22fMultiplyElementwiseLocal(&A,&Y); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +SST_Math_Mat22fMultiplyElementwiseLocal(&X,&Y); +assert(fabsf((X.v[0])-(247.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[2])-(-182.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[1])-(-1.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[3])-(-224.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +/* Resetting test vectors / mats */ + v.v[0] = -13.000000f; + v.v[1] = -18.000000f; + X.v[0] = -17.000000f; + X.v[1] = 16.000000f; + X.v[2] = -2.000000f; + X.v[3] = -18.000000f; + Y.v[0] = 7.000000f; + Y.v[1] = -6.000000f; + Y.v[2] = 10.000000f; + Y.v[3] = 11.000000f; +/* +X +[[-17. -2.] + [ 16. -18.]] +Y +[[ 7. 10.] + [ -6. 11.]] +[[-107. -192.] + [ 220. -38.]] +*/ +fprintf(stdout,"SST_Math_Mat22fMultiplyMatrix(X,Y,A)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat22fMultiplyMatrix(&X,&Y,&A); +t1 = rdtsc(); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +assert(fabsf((A.v[0])-(-107.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[2])-(-192.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[1])-(220.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[3])-(-38.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +/* +X +[[-17. -2.] + [ 16. -18.]] +Y +[[ 7. 10.] + [ -6. 11.]] +X +[[-107. -192.] + [ 220. -38.]] +*/ +fprintf(stdout,"SST_Math_Mat22fMultiplyMatrixLocal(X,Y)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat22fMultiplyMatrixLocal(&A,&Y); +t1 = rdtsc(); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +SST_Math_Mat22fMultiplyMatrixLocal(&X,&Y); +assert(fabsf((X.v[0])-(-107.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[2])-(-192.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[1])-(220.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[3])-(-38.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +/* Resetting test vectors / mats */ + v.v[0] = 19.000000f; + v.v[1] = -14.000000f; + X.v[0] = 17.000000f; + X.v[1] = -17.000000f; + X.v[2] = 11.000000f; + X.v[3] = -13.000000f; + Y.v[0] = -7.000000f; + Y.v[1] = 11.000000f; + Y.v[2] = 6.000000f; + Y.v[3] = 12.000000f; +/* +X +[[ 17. 11.] + [-17. -13.]] +v +[ 19. -14.] +w +[ 169. -141.] +*/ +i=0; +fprintf(stdout,"SST_Math_Mat22fMultiplyVector(X,v,w)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat22fMultiplyVector(&X,&v,&w); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +assert(fabsf((w.v[0])-(169.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((w.v[1])-(-141.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +/* +X +[[ 17. 11.] + [-17. -13.]] +v +[ 19. -14.] +v +[ 169. -141.] +*/ +fprintf(stdout,"SST_Math_Mat22fMultiplyVectorLocal(X,v)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat22fMultiplyVectorLocal(&X,&w); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +SST_Math_Mat22fMultiplyVectorLocal(&X,&v); +assert(fabsf((v.v[0])-(169.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((v.v[1])-(-141.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +/* Resetting test vectors / mats */ + v.v[0] = -15.000000f; + v.v[1] = -6.000000f; + X.v[0] = 6.000000f; + X.v[1] = -18.000000f; + X.v[2] = -16.000000f; + X.v[3] = -19.000000f; + Y.v[0] = 9.000000f; + Y.v[1] = -16.000000f; + Y.v[2] = 17.000000f; + Y.v[3] = -18.000000f; +fprintf(stdout,"SST_Math_Mat22fTranspose(X,A)"); +t0 = rdtsc(); +SST_Math_Mat22fTranspose(&X,&A); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +assert(fabsf((A.v[0])-(6.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[2])-(-18.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[1])-(-16.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[3])-(-19.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +fprintf(stdout,"SST_Math_Mat22fTransposeLocal(X)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat22fTransposeLocal(&A); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +SST_Math_Mat22fTransposeLocal(&X); +assert(fabsf((X.v[0])-(6.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[2])-(-18.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[1])-(-16.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[3])-(-19.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +/* +[[ 0.31622776 -0.94868332] + [-0.94868332 -0.31622776]] +[[ 1. 0.] + [ 0. 1.]] +*/ +X.v[0] = (float)0.316228f; +X.v[2] = (float)-0.948683f; +X.v[1] = (float)-0.948683f; +X.v[3] = (float)-0.316228f; +fprintf(stdout,"SST_Math_Mat22fTranspose(X,A)"); +t0 = rdtsc(); +SST_Math_Mat22fTranspose(&X,&A); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +fprintf(stdout,"SST_Math_Mat22fMultiplyMatrix(A,X,B)"); +t0 = rdtsc(); +SST_Math_Mat22fMultiplyMatrix(&A,&X,&B); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +/* Check Negative Test */ +assert(!SST_Math_Mat22fCheckOrthonormal(&X)); +X.v[0] = (float)1.000000f; +X.v[2] = (float)0.000000f; +X.v[1] = (float)0.000000f; +X.v[3] = (float)1.000000f; +/* Check Positive Test */ +assert(SST_Math_Mat22fCheckOrthonormal(&X)); +/* Resetting test vectors / mats */ + v.v[0] = 10.000000f; + v.v[1] = 15.000000f; + X.v[0] = 16.000000f; + X.v[1] = -18.000000f; + X.v[2] = -13.000000f; + X.v[3] = 14.000000f; + Y.v[0] = -9.000000f; + Y.v[1] = 6.000000f; + Y.v[2] = -11.000000f; + Y.v[3] = 1.000000f; +/* +[[-1.39999998 -1.29999995] + [-1.79999995 -1.60000002]] +*/ +fprintf(stdout,"SST_Math_Mat22fInvert(X,B)\n"); +t0 = rdtsc(); +SST_Math_Mat22fInvert(&X,&B); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +fprintf(stdout,"B[%d][%d] = %ff\n",0,0,B.v[0]); +fprintf(stdout,"B[%d][%d] = %ff\n",0,1,B.v[1]); +fprintf(stdout,"B[%d][%d] = %ff\n",1,0,B.v[2]); +fprintf(stdout,"B[%d][%d] = %ff\n",1,1,B.v[3]); +assert(fabsf((B.v[0])-(-1.400000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((B.v[2])-(-1.300000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((B.v[1])-(-1.800000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((B.v[3])-(-1.600000f)) <=100*FLT_EPSILON /* yes this is bad */); +/* Resetting test vectors / mats */ + v.v[0] = -3.000000f; + v.v[1] = 6.000000f; + X.v[0] = -17.000000f; + X.v[1] = 14.000000f; + X.v[2] = -9.000000f; + X.v[3] = -20.000000f; + Y.v[0] = 1.000000f; + Y.v[1] = 12.000000f; + Y.v[2] = -12.000000f; + Y.v[3] = 14.000000f; +/* +[[-0.04291845 0.01931331] + [-0.03004292 -0.03648069]] +*/ +fprintf(stdout,"SST_Math_Mat22fInvert(X,B)\n"); +fflush(stdout); +fprintf(stdout,"SST_Math_Mat22fInvertLocal(X,B)\n"); +t0 = rdtsc(); +SST_Math_Mat22fInvertLocal(&X); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +fflush(stdout); +assert(fabsf((X.v[0])-(-0.042918f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[2])-(0.019313f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[1])-(-0.030043f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[3])-(-0.036481f)) <=100*FLT_EPSILON /* yes this is bad */); +fprintf(stdout,"\n==== SST_Math_Mat22ftest_fxn COMPLETE ====\n"); +return 0; +} diff --git a/libsst-math/SST_Mat22i.c b/libsst-math/SST_Mat22i.c new file mode 100644 index 0000000..c682ab7 --- /dev/null +++ b/libsst-math/SST_Mat22i.c @@ -0,0 +1,202 @@ +/* + AUTOMATICALLY GENERATED FILE - DO NOT EDIT! + Please change MatrixNxN.py and re-run it +*/ +/* Generated with ./MatrixNxN.py n = 2, TYPE = int */ + +#include <float.h> +#include <pstdbool.h> +#include <stdio.h> +#include <math.h> /* for sqrt functions */ +#include <stdlib.h> /* for the abs/labs functions */ +#include <SST/SST_Build.h> + +#include <SST/SST_Mat22.h> +#include <SST/SST_Vec2.h> +void SST_Math_Mat22iAdd(const SST_Mat22i* RESTRICT _A, const SST_Mat22i* RESTRICT _B, SST_Mat22i* RESTRICT _out) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + SST_ASSUME_ALIGNED(_out,16); + + _out->v[0] = _A->v[0] + _B->v[0]; + _out->v[1] = _A->v[1] + _B->v[1]; + _out->v[2] = _A->v[2] + _B->v[2]; + _out->v[3] = _A->v[3] + _B->v[3]; +} + +/******************************************************************************/ + +void SST_Math_Mat22iAddLocal(SST_Mat22i* RESTRICT _A, const SST_Mat22i* RESTRICT _B) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + + _A->v[0] += _B->v[0]; + _A->v[1] += _B->v[1]; + _A->v[2] += _B->v[2]; + _A->v[3] += _B->v[3]; +} + +/******************************************************************************/ + +void SST_Math_Mat22iSubtract(const SST_Mat22i* RESTRICT _A, const SST_Mat22i* RESTRICT _B, SST_Mat22i* RESTRICT _out) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + SST_ASSUME_ALIGNED(_out,16); + + _out->v[0] = _A->v[0] - _B->v[0]; + _out->v[1] = _A->v[1] - _B->v[1]; + _out->v[2] = _A->v[2] - _B->v[2]; + _out->v[3] = _A->v[3] - _B->v[3]; +} + +/******************************************************************************/ + +void SST_Math_Mat22iSubtractLocal(SST_Mat22i* RESTRICT _A, const SST_Mat22i* RESTRICT _B) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + + _A->v[0] -= _B->v[0]; + _A->v[1] -= _B->v[1]; + _A->v[2] -= _B->v[2]; + _A->v[3] -= _B->v[3]; +} + +/******************************************************************************/ + +void SST_Math_Mat22iMultiplyElementwise(const SST_Mat22i* RESTRICT _A, const SST_Mat22i* RESTRICT _B, SST_Mat22i* RESTRICT _out) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + SST_ASSUME_ALIGNED(_out,16); + + _out->v[0] = _A->v[0] * _B->v[0]; + _out->v[1] = _A->v[1] * _B->v[1]; + _out->v[2] = _A->v[2] * _B->v[2]; + _out->v[3] = _A->v[3] * _B->v[3]; +} + +/******************************************************************************/ + +void SST_Math_Mat22iMultiplyElementwiseLocal(SST_Mat22i* RESTRICT _A, const SST_Mat22i* RESTRICT _B) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + + _A->v[0] *= _B->v[0]; + _A->v[1] *= _B->v[1]; + _A->v[2] *= _B->v[2]; + _A->v[3] *= _B->v[3]; +} + +/******************************************************************************/ + +void SST_Math_Mat22iMultiplyScalar(const SST_Mat22i* RESTRICT _A, const int k, SST_Mat22i* RESTRICT _out) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_out,16); + + _out->v[0] = _A->v[0] * k; + _out->v[1] = _A->v[1] * k; + _out->v[2] = _A->v[2] * k; + _out->v[3] = _A->v[3] * k; +} + +/******************************************************************************/ + +void SST_Math_Mat22iMultiplyScalarLocal(SST_Mat22i* RESTRICT _A, const int k) +{ + SST_ASSUME_ALIGNED(_A,16); + + _A->v[0] *= k; + _A->v[1] *= k; + _A->v[2] *= k; + _A->v[3] *= k; +} + +/******************************************************************************/ + + +void SST_Math_Mat22iMultiplyMatrix(const SST_Mat22i* _A, const SST_Mat22i* RESTRICT _B, SST_Mat22i* RESTRICT _out) +{ +SST_ASSUME_ALIGNED(_A,16); +SST_ASSUME_ALIGNED(_B,16); +SST_ASSUME_ALIGNED(_out,16); +_out->v[ 0] = _A->v[ 0]*_B->v[ 0]+_A->v[ 2]*_B->v[ 1]; +_out->v[ 2] = _A->v[ 0]*_B->v[ 2]+_A->v[ 2]*_B->v[ 3]; +_out->v[ 1] = _A->v[ 1]*_B->v[ 0]+_A->v[ 3]*_B->v[ 1]; +_out->v[ 3] = _A->v[ 1]*_B->v[ 2]+_A->v[ 3]*_B->v[ 3]; +} +void SST_Math_Mat22iMultiplyMatrixLocal(SST_Mat22i* RESTRICT _A, const SST_Mat22i* RESTRICT _B) +{ + int tmp[4]; + SST_ASSUME_ALIGNED(_A,16); +SST_ASSUME_ALIGNED(_B,16); +tmp[ 0] = _A->v[ 0]*_B->v[ 0]+_A->v[ 2]*_B->v[ 1]; +tmp[ 2] = _A->v[ 0]*_B->v[ 2]+_A->v[ 2]*_B->v[ 3]; +_A->v[0] = tmp[0]; +_A->v[2] = tmp[2]; + + +tmp[ 1] = _A->v[ 1]*_B->v[ 0]+_A->v[ 3]*_B->v[ 1]; +tmp[ 3] = _A->v[ 1]*_B->v[ 2]+_A->v[ 3]*_B->v[ 3]; +_A->v[1] = tmp[1]; +_A->v[3] = tmp[3]; + + +} +void SST_Math_Mat22iMultiplyVector(const SST_Mat22i* RESTRICT _A, const SST_Vec2i* RESTRICT _v, SST_Vec2i* RESTRICT _out) +{ +SST_ASSUME_ALIGNED(_A,16); +SST_ASSUME_ALIGNED(_v,16); +SST_ASSUME_ALIGNED(_out,16); +_out->v[ 0] = _A->v[ 0]*_v->v[0]+_A->v[ 2]*_v->v[1]; +_out->v[ 1] = _A->v[ 1]*_v->v[0]+_A->v[ 3]*_v->v[1]; +} +void SST_Math_Mat22iMultiplyVectorLocal(const SST_Mat22i* RESTRICT _A, SST_Vec2i* RESTRICT _v) +{ +int tmp[2]; +SST_ASSUME_ALIGNED(_A,16); +SST_ASSUME_ALIGNED(_v,16); +tmp[ 0] = _A->v[ 0]*_v->v[0]+_A->v[ 2]*_v->v[1]; +tmp[ 1] = _A->v[ 1]*_v->v[0]+_A->v[ 3]*_v->v[1]; +_v->v[0] = tmp[0]; +_v->v[1] = tmp[1]; +} +void SST_Math_Mat22iTranspose(const SST_Mat22i* RESTRICT _A, SST_Mat22i* RESTRICT _out) +{ +SST_ASSUME_ALIGNED(_A,16); +SST_ASSUME_ALIGNED(_out,16); +_out->v[ 0] = _A->v[ 0]; +_out->v[ 1] = _A->v[ 2]; +_out->v[ 2] = _A->v[ 1]; +_out->v[ 3] = _A->v[ 3]; +} +void SST_Math_Mat22iTransposeLocal(SST_Mat22i* RESTRICT _A) +{ +int tmp[2]; +SST_ASSUME_ALIGNED(_A,16); +tmp[1] = _A->v[ 2]; +_A->v[ 2] = _A->v[ 1]; +_A->v[ 1] = tmp[1]; +} +bool SST_Math_Mat22iCheckOrthonormal(const SST_Mat22i* _A) +{ +const int diag = -_A->v[0]*_A->v[0] -_A->v[1]*_A->v[1] -_A->v[2]*_A->v[2] -_A->v[3]*_A->v[3]; +const int odiag = _A->v[0]*_A->v[2]+ _A->v[1]*_A->v[3]+ _A->v[2]*_A->v[0]+ _A->v[3]*_A->v[1]; +SST_ASSUME_ALIGNED(_A,16); +return +((abs(2+diag)) <= 100*0) & +((abs(odiag)) <= 100*0); + + +} +int SST_Math_Mat22iDeterminant(const SST_Mat22i* _A) +{ + const int result = _A->v[0]*_A->v[3]-_A->v[1]*_A->v[2]; + SST_ASSUME_ALIGNED(_A,16); + return result; +} diff --git a/libsst-math/SST_Mat22i_benchmark.c b/libsst-math/SST_Mat22i_benchmark.c new file mode 100644 index 0000000..4ef0f39 --- /dev/null +++ b/libsst-math/SST_Mat22i_benchmark.c @@ -0,0 +1,349 @@ +#include <float.h> +#include <math.h> +#include <stdlib.h> +#include <stdio.h> +#include <assert.h> +#include <xmmintrin.h> +#include <SST/SST_Timer_x86.h> +#include <SST/SST_Mat22.h> +#include <SST/SST_Vec2.h> + + + + +int SST_Math_Mat22i_test_fxns() +{ +const int NTESTS = 10; +int i; +uint64_t t0,t1; +SST_Mat22i X; /* 2 x 2 matrix */ +SST_Mat22i Y; /* 2 x 2 matrix */ +SST_Mat22i A; /* 2 x 2 matrix */ +SST_Mat22i B; /* 2 x 2 matrix */ +SST_Vec2i v; /* 2 vector */ +SST_Vec2i w; /* 2 vector */ +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +/* Resetting test vectors / mats */ + v.v[0] = -13; + v.v[1] = -2; + X.v[0] = 18; + X.v[1] = 5; + X.v[2] = -10; + X.v[3] = -16; + Y.v[0] = -3; + Y.v[1] = 16; + Y.v[2] = 3; + Y.v[3] = 7; +SST_Math_Mat22iAdd(&X,&Y,&A); /* clear out the initial finding of object */ +/* Clear out the rdtsc register */ +fprintf(stdout,"SST_Math_Mat22iAdd(X,Y,A)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat22iAdd(&X,&Y,&A); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +/* +[[ 18 -10] + [ 5 -16]] +[[-3 3] + [16 7]] +[[15 -7] + [21 -9]] +*/ +assert((A.v[0])==(15)); +assert((A.v[2])==(-7)); +assert((A.v[1])==(21)); +assert((A.v[3])==(-9)); +/* +[[ 18 -10] + [ 5 -16]] +[[-3 3] + [16 7]] +[[15 -7] + [21 -9]] +*/ +fprintf(stdout,"SST_Math_Mat22iAddLocal(A,Y)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat22iAddLocal(&A,&Y); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +SST_Math_Mat22iAddLocal(&X,&Y); /* for accuracy */ +assert((X.v[0])==(15)); +assert((X.v[2])==(-7)); +assert((X.v[1])==(21)); +assert((X.v[3])==(-9)); +/* Resetting test vectors / mats */ + v.v[0] = 2; + v.v[1] = 8; + X.v[0] = 2; + X.v[1] = 16; + X.v[2] = -9; + X.v[3] = 4; + Y.v[0] = 17; + Y.v[1] = -20; + Y.v[2] = 15; + Y.v[3] = 17; +/* +[[ 2 -9] + [16 4]] +[[ 4 -18] + [ 32 8]] +*/ +fprintf(stdout,"SST_Math_Mat22iMultiplyScalar(X,t,Y)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat22iMultiplyScalar(&X,2,&A); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +assert((A.v[0])==(4)); +assert((A.v[2])==(-18)); +assert((A.v[1])==(32)); +assert((A.v[3])==(8)); +/* +[[ 2 -9] + [16 4]] +[[ 4 -18] + [ 32 8]] +*/ +fprintf(stdout,"SST_Math_Mat22iMultiplyScalarLocal(A,t)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat22iMultiplyScalarLocal(&A,2); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +SST_Math_Mat22iMultiplyScalarLocal(&X,2); +assert((X.v[0])==(4)); +assert((X.v[2])==(-18)); +assert((X.v[1])==(32)); +assert((X.v[3])==(8)); +/* Resetting test vectors / mats */ + v.v[0] = -16; + v.v[1] = -18; + X.v[0] = -19; + X.v[1] = -14; + X.v[2] = -11; + X.v[3] = 7; + Y.v[0] = -18; + Y.v[1] = 3; + Y.v[2] = -14; + Y.v[3] = -13; +/* +[[-19 -11] + [-14 7]] +[[-18 -14] + [ 3 -13]] +[[342 154] + [-42 -91]] +*/ +fprintf(stdout,"SST_Math_Mat22iMultiplyElementwise(X,Y,A)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat22iMultiplyElementwise(&X, &Y, &A); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +assert((A.v[0])==(342)); +assert((A.v[2])==(154)); +assert((A.v[1])==(-42)); +assert((A.v[3])==(-91)); +/* +[[-19 -11] + [-14 7]] +[[-18 -14] + [ 3 -13]] +[[342 154] + [-42 -91]] +*/ +fprintf(stdout,"SST_Math_Mat22iMultiplyElementwiseLocal(X,Y)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat22iMultiplyElementwiseLocal(&A,&Y); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +SST_Math_Mat22iMultiplyElementwiseLocal(&X,&Y); +assert((X.v[0])==(342)); +assert((X.v[2])==(154)); +assert((X.v[1])==(-42)); +assert((X.v[3])==(-91)); +/* Resetting test vectors / mats */ + v.v[0] = 11; + v.v[1] = 8; + X.v[0] = -4; + X.v[1] = -2; + X.v[2] = 2; + X.v[3] = -11; + Y.v[0] = 10; + Y.v[1] = -2; + Y.v[2] = -10; + Y.v[3] = 7; +/* +X +[[ -4 2] + [ -2 -11]] +Y +[[ 10 -10] + [ -2 7]] +[[-44 54] + [ 2 -57]] +*/ +fprintf(stdout,"SST_Math_Mat22iMultiplyMatrix(X,Y,A)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat22iMultiplyMatrix(&X,&Y,&A); +t1 = rdtsc(); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +assert((A.v[0])==(-44)); +assert((A.v[2])==(54)); +assert((A.v[1])==(2)); +assert((A.v[3])==(-57)); +/* +X +[[ -4 2] + [ -2 -11]] +Y +[[ 10 -10] + [ -2 7]] +X +[[-44 54] + [ 2 -57]] +*/ +fprintf(stdout,"SST_Math_Mat22iMultiplyMatrixLocal(X,Y)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat22iMultiplyMatrixLocal(&A,&Y); +t1 = rdtsc(); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +SST_Math_Mat22iMultiplyMatrixLocal(&X,&Y); +assert((X.v[0])==(-44)); +assert((X.v[2])==(54)); +assert((X.v[1])==(2)); +assert((X.v[3])==(-57)); +/* Resetting test vectors / mats */ + v.v[0] = 0; + v.v[1] = -7; + X.v[0] = 2; + X.v[1] = 14; + X.v[2] = 2; + X.v[3] = -17; + Y.v[0] = 15; + Y.v[1] = -7; + Y.v[2] = 4; + Y.v[3] = 11; +/* +X +[[ 2 2] + [ 14 -17]] +v +[ 0 -7] +w +[-14 119] +*/ +i=0; +fprintf(stdout,"SST_Math_Mat22iMultiplyVector(X,v,w)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat22iMultiplyVector(&X,&v,&w); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +assert((w.v[0])==(-14)); +assert((w.v[1])==(119)); +/* +X +[[ 2 2] + [ 14 -17]] +v +[ 0 -7] +v +[-14 119] +*/ +fprintf(stdout,"SST_Math_Mat22iMultiplyVectorLocal(X,v)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat22iMultiplyVectorLocal(&X,&w); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +SST_Math_Mat22iMultiplyVectorLocal(&X,&v); +assert((v.v[0])==(-14)); +assert((v.v[1])==(119)); +/* Resetting test vectors / mats */ + v.v[0] = 14; + v.v[1] = -18; + X.v[0] = 11; + X.v[1] = -8; + X.v[2] = -5; + X.v[3] = 8; + Y.v[0] = 4; + Y.v[1] = 6; + Y.v[2] = -6; + Y.v[3] = -9; +fprintf(stdout,"SST_Math_Mat22iTranspose(X,A)"); +t0 = rdtsc(); +SST_Math_Mat22iTranspose(&X,&A); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +assert((A.v[0])==(11)); +assert((A.v[2])==(-8)); +assert((A.v[1])==(-5)); +assert((A.v[3])==(8)); +fprintf(stdout,"SST_Math_Mat22iTransposeLocal(X)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat22iTransposeLocal(&A); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +SST_Math_Mat22iTransposeLocal(&X); +assert((X.v[0])==(11)); +assert((X.v[2])==(-8)); +assert((X.v[1])==(-5)); +assert((X.v[3])==(8)); +/* +[[-0.80873608 0.5881717 ] + [ 0.5881717 0.80873608]] +[[ 1. 0.] + [ 0. 1.]] +*/ +X.v[0] = (int)0; +X.v[2] = (int)0; +X.v[1] = (int)0; +X.v[3] = (int)0; +fprintf(stdout,"SST_Math_Mat22iTranspose(X,A)"); +t0 = rdtsc(); +SST_Math_Mat22iTranspose(&X,&A); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +fprintf(stdout,"SST_Math_Mat22iMultiplyMatrix(A,X,B)"); +t0 = rdtsc(); +SST_Math_Mat22iMultiplyMatrix(&A,&X,&B); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +/* Check Positive Test */ +assert(SST_Math_Mat22iCheckOrthonormal(&X)); +/* Check Negative Test */ +assert(!SST_Math_Mat22iCheckOrthonormal(&Y)); +fprintf(stdout,"\n==== SST_Math_Mat22itest_fxn COMPLETE ====\n"); +return 0; +} diff --git a/libsst-math/SST_Mat22u.c b/libsst-math/SST_Mat22u.c new file mode 100644 index 0000000..039a2ac --- /dev/null +++ b/libsst-math/SST_Mat22u.c @@ -0,0 +1,185 @@ +/* + AUTOMATICALLY GENERATED FILE - DO NOT EDIT! + Please change MatrixNxN.py and re-run it +*/ +/* Generated with ./MatrixNxN.py n = 2, TYPE = unsigned int */ + +#include <float.h> +#include <pstdbool.h> +#include <stdio.h> +#include <math.h> /* for sqrt functions */ +#include <stdlib.h> /* for the abs/labs functions */ +#include <SST/SST_Build.h> + +#include <SST/SST_Mat22.h> +#include <SST/SST_Vec2.h> +void SST_Math_Mat22uAdd(const SST_Mat22u* RESTRICT _A, const SST_Mat22u* RESTRICT _B, SST_Mat22u* RESTRICT _out) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + SST_ASSUME_ALIGNED(_out,16); + + _out->v[0] = _A->v[0] + _B->v[0]; + _out->v[1] = _A->v[1] + _B->v[1]; + _out->v[2] = _A->v[2] + _B->v[2]; + _out->v[3] = _A->v[3] + _B->v[3]; +} + +/******************************************************************************/ + +void SST_Math_Mat22uAddLocal(SST_Mat22u* RESTRICT _A, const SST_Mat22u* RESTRICT _B) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + + _A->v[0] += _B->v[0]; + _A->v[1] += _B->v[1]; + _A->v[2] += _B->v[2]; + _A->v[3] += _B->v[3]; +} + +/******************************************************************************/ + +void SST_Math_Mat22uSubtract(const SST_Mat22u* RESTRICT _A, const SST_Mat22u* RESTRICT _B, SST_Mat22u* RESTRICT _out) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + SST_ASSUME_ALIGNED(_out,16); + + _out->v[0] = _A->v[0] - _B->v[0]; + _out->v[1] = _A->v[1] - _B->v[1]; + _out->v[2] = _A->v[2] - _B->v[2]; + _out->v[3] = _A->v[3] - _B->v[3]; +} + +/******************************************************************************/ + +void SST_Math_Mat22uSubtractLocal(SST_Mat22u* RESTRICT _A, const SST_Mat22u* RESTRICT _B) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + + _A->v[0] -= _B->v[0]; + _A->v[1] -= _B->v[1]; + _A->v[2] -= _B->v[2]; + _A->v[3] -= _B->v[3]; +} + +/******************************************************************************/ + +void SST_Math_Mat22uMultiplyElementwise(const SST_Mat22u* RESTRICT _A, const SST_Mat22u* RESTRICT _B, SST_Mat22u* RESTRICT _out) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + SST_ASSUME_ALIGNED(_out,16); + + _out->v[0] = _A->v[0] * _B->v[0]; + _out->v[1] = _A->v[1] * _B->v[1]; + _out->v[2] = _A->v[2] * _B->v[2]; + _out->v[3] = _A->v[3] * _B->v[3]; +} + +/******************************************************************************/ + +void SST_Math_Mat22uMultiplyElementwiseLocal(SST_Mat22u* RESTRICT _A, const SST_Mat22u* RESTRICT _B) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + + _A->v[0] *= _B->v[0]; + _A->v[1] *= _B->v[1]; + _A->v[2] *= _B->v[2]; + _A->v[3] *= _B->v[3]; +} + +/******************************************************************************/ + +void SST_Math_Mat22uMultiplyScalar(const SST_Mat22u* RESTRICT _A, const unsigned int k, SST_Mat22u* RESTRICT _out) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_out,16); + + _out->v[0] = _A->v[0] * k; + _out->v[1] = _A->v[1] * k; + _out->v[2] = _A->v[2] * k; + _out->v[3] = _A->v[3] * k; +} + +/******************************************************************************/ + +void SST_Math_Mat22uMultiplyScalarLocal(SST_Mat22u* RESTRICT _A, const unsigned int k) +{ + SST_ASSUME_ALIGNED(_A,16); + + _A->v[0] *= k; + _A->v[1] *= k; + _A->v[2] *= k; + _A->v[3] *= k; +} + +/******************************************************************************/ + + +void SST_Math_Mat22uMultiplyMatrix(const SST_Mat22u* _A, const SST_Mat22u* RESTRICT _B, SST_Mat22u* RESTRICT _out) +{ +SST_ASSUME_ALIGNED(_A,16); +SST_ASSUME_ALIGNED(_B,16); +SST_ASSUME_ALIGNED(_out,16); +_out->v[ 0] = _A->v[ 0]*_B->v[ 0]+_A->v[ 2]*_B->v[ 1]; +_out->v[ 2] = _A->v[ 0]*_B->v[ 2]+_A->v[ 2]*_B->v[ 3]; +_out->v[ 1] = _A->v[ 1]*_B->v[ 0]+_A->v[ 3]*_B->v[ 1]; +_out->v[ 3] = _A->v[ 1]*_B->v[ 2]+_A->v[ 3]*_B->v[ 3]; +} +void SST_Math_Mat22uMultiplyMatrixLocal(SST_Mat22u* RESTRICT _A, const SST_Mat22u* RESTRICT _B) +{ + unsigned int tmp[4]; + SST_ASSUME_ALIGNED(_A,16); +SST_ASSUME_ALIGNED(_B,16); +tmp[ 0] = _A->v[ 0]*_B->v[ 0]+_A->v[ 2]*_B->v[ 1]; +tmp[ 2] = _A->v[ 0]*_B->v[ 2]+_A->v[ 2]*_B->v[ 3]; +_A->v[0] = tmp[0]; +_A->v[2] = tmp[2]; + + +tmp[ 1] = _A->v[ 1]*_B->v[ 0]+_A->v[ 3]*_B->v[ 1]; +tmp[ 3] = _A->v[ 1]*_B->v[ 2]+_A->v[ 3]*_B->v[ 3]; +_A->v[1] = tmp[1]; +_A->v[3] = tmp[3]; + + +} +void SST_Math_Mat22uMultiplyVector(const SST_Mat22u* RESTRICT _A, const SST_Vec2u* RESTRICT _v, SST_Vec2u* RESTRICT _out) +{ +SST_ASSUME_ALIGNED(_A,16); +SST_ASSUME_ALIGNED(_v,16); +SST_ASSUME_ALIGNED(_out,16); +_out->v[ 0] = _A->v[ 0]*_v->v[0]+_A->v[ 2]*_v->v[1]; +_out->v[ 1] = _A->v[ 1]*_v->v[0]+_A->v[ 3]*_v->v[1]; +} +void SST_Math_Mat22uMultiplyVectorLocal(const SST_Mat22u* RESTRICT _A, SST_Vec2u* RESTRICT _v) +{ +unsigned int tmp[2]; +SST_ASSUME_ALIGNED(_A,16); +SST_ASSUME_ALIGNED(_v,16); +tmp[ 0] = _A->v[ 0]*_v->v[0]+_A->v[ 2]*_v->v[1]; +tmp[ 1] = _A->v[ 1]*_v->v[0]+_A->v[ 3]*_v->v[1]; +_v->v[0] = tmp[0]; +_v->v[1] = tmp[1]; +} +void SST_Math_Mat22uTranspose(const SST_Mat22u* RESTRICT _A, SST_Mat22u* RESTRICT _out) +{ +SST_ASSUME_ALIGNED(_A,16); +SST_ASSUME_ALIGNED(_out,16); +_out->v[ 0] = _A->v[ 0]; +_out->v[ 1] = _A->v[ 2]; +_out->v[ 2] = _A->v[ 1]; +_out->v[ 3] = _A->v[ 3]; +} +void SST_Math_Mat22uTransposeLocal(SST_Mat22u* RESTRICT _A) +{ +unsigned int tmp[2]; +SST_ASSUME_ALIGNED(_A,16); +tmp[1] = _A->v[ 2]; +_A->v[ 2] = _A->v[ 1]; +_A->v[ 1] = tmp[1]; +} diff --git a/libsst-math/SST_Mat22u_benchmark.c b/libsst-math/SST_Mat22u_benchmark.c new file mode 100644 index 0000000..b06e798 --- /dev/null +++ b/libsst-math/SST_Mat22u_benchmark.c @@ -0,0 +1,345 @@ +#include <float.h> +#include <math.h> +#include <stdlib.h> +#include <stdio.h> +#include <assert.h> +#include <xmmintrin.h> +#include <SST/SST_Timer_x86.h> +#include <SST/SST_Mat22.h> +#include <SST/SST_Vec2.h> + + + + +int SST_Math_Mat22u_test_fxns() +{ +const int NTESTS = 10; +int i; +uint64_t t0,t1; +SST_Mat22u X; /* 2 x 2 matrix */ +SST_Mat22u Y; /* 2 x 2 matrix */ +SST_Mat22u A; /* 2 x 2 matrix */ +SST_Mat22u B; /* 2 x 2 matrix */ +SST_Vec2u v; /* 2 vector */ +SST_Vec2u w; /* 2 vector */ +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +/* Resetting test vectors / mats */ + v.v[0] = 7; + v.v[1] = 16; + X.v[0] = 2; + X.v[1] = 8; + X.v[2] = 15; + X.v[3] = 17; + Y.v[0] = 15; + Y.v[1] = 6; + Y.v[2] = 15; + Y.v[3] = 38; +SST_Math_Mat22uAdd(&X,&Y,&A); /* clear out the initial finding of object */ +/* Clear out the rdtsc register */ +fprintf(stdout,"SST_Math_Mat22uAdd(X,Y,A)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat22uAdd(&X,&Y,&A); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +/* +[[ 2 15] + [ 8 17]] +[[15 15] + [ 6 38]] +[[17 30] + [14 55]] +*/ +assert((A.v[0])==(17)); +assert((A.v[2])==(30)); +assert((A.v[1])==(14)); +assert((A.v[3])==(55)); +/* +[[ 2 15] + [ 8 17]] +[[15 15] + [ 6 38]] +[[17 30] + [14 55]] +*/ +fprintf(stdout,"SST_Math_Mat22uAddLocal(A,Y)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat22uAddLocal(&A,&Y); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +SST_Math_Mat22uAddLocal(&X,&Y); /* for accuracy */ +assert((X.v[0])==(17)); +assert((X.v[2])==(30)); +assert((X.v[1])==(14)); +assert((X.v[3])==(55)); +/* Resetting test vectors / mats */ + v.v[0] = 30; + v.v[1] = 15; + X.v[0] = 6; + X.v[1] = 13; + X.v[2] = 26; + X.v[3] = 33; + Y.v[0] = 13; + Y.v[1] = 32; + Y.v[2] = 15; + Y.v[3] = 33; +/* +[[ 6 26] + [13 33]] +[[12 52] + [26 66]] +*/ +fprintf(stdout,"SST_Math_Mat22uMultiplyScalar(X,t,Y)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat22uMultiplyScalar(&X,2,&A); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +assert((A.v[0])==(12)); +assert((A.v[2])==(52)); +assert((A.v[1])==(26)); +assert((A.v[3])==(66)); +/* +[[ 6 26] + [13 33]] +[[12 52] + [26 66]] +*/ +fprintf(stdout,"SST_Math_Mat22uMultiplyScalarLocal(A,t)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat22uMultiplyScalarLocal(&A,2); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +SST_Math_Mat22uMultiplyScalarLocal(&X,2); +assert((X.v[0])==(12)); +assert((X.v[2])==(52)); +assert((X.v[1])==(26)); +assert((X.v[3])==(66)); +/* Resetting test vectors / mats */ + v.v[0] = 10; + v.v[1] = 33; + X.v[0] = 37; + X.v[1] = 9; + X.v[2] = 15; + X.v[3] = 8; + Y.v[0] = 34; + Y.v[1] = 13; + Y.v[2] = 28; + Y.v[3] = 16; +/* +[[37 15] + [ 9 8]] +[[34 28] + [13 16]] +[[1258 420] + [ 117 128]] +*/ +fprintf(stdout,"SST_Math_Mat22uMultiplyElementwise(X,Y,A)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat22uMultiplyElementwise(&X, &Y, &A); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +assert((A.v[0])==(1258)); +assert((A.v[2])==(420)); +assert((A.v[1])==(117)); +assert((A.v[3])==(128)); +/* +[[37 15] + [ 9 8]] +[[34 28] + [13 16]] +[[1258 420] + [ 117 128]] +*/ +fprintf(stdout,"SST_Math_Mat22uMultiplyElementwiseLocal(X,Y)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat22uMultiplyElementwiseLocal(&A,&Y); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +SST_Math_Mat22uMultiplyElementwiseLocal(&X,&Y); +assert((X.v[0])==(1258)); +assert((X.v[2])==(420)); +assert((X.v[1])==(117)); +assert((X.v[3])==(128)); +/* Resetting test vectors / mats */ + v.v[0] = 1; + v.v[1] = 22; + X.v[0] = 10; + X.v[1] = 29; + X.v[2] = 13; + X.v[3] = 38; + Y.v[0] = 10; + Y.v[1] = 4; + Y.v[2] = 15; + Y.v[3] = 3; +/* +X +[[10 13] + [29 38]] +Y +[[10 15] + [ 4 3]] +[[152 189] + [442 549]] +*/ +fprintf(stdout,"SST_Math_Mat22uMultiplyMatrix(X,Y,A)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat22uMultiplyMatrix(&X,&Y,&A); +t1 = rdtsc(); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +assert((A.v[0])==(152)); +assert((A.v[2])==(189)); +assert((A.v[1])==(442)); +assert((A.v[3])==(549)); +/* +X +[[10 13] + [29 38]] +Y +[[10 15] + [ 4 3]] +X +[[152 189] + [442 549]] +*/ +fprintf(stdout,"SST_Math_Mat22uMultiplyMatrixLocal(X,Y)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat22uMultiplyMatrixLocal(&A,&Y); +t1 = rdtsc(); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +SST_Math_Mat22uMultiplyMatrixLocal(&X,&Y); +assert((X.v[0])==(152)); +assert((X.v[2])==(189)); +assert((X.v[1])==(442)); +assert((X.v[3])==(549)); +/* Resetting test vectors / mats */ + v.v[0] = 8; + v.v[1] = 3; + X.v[0] = 27; + X.v[1] = 36; + X.v[2] = 5; + X.v[3] = 20; + Y.v[0] = 32; + Y.v[1] = 31; + Y.v[2] = 26; + Y.v[3] = 1; +/* +X +[[27 5] + [36 20]] +v +[8 3] +w +[231 348] +*/ +i=0; +fprintf(stdout,"SST_Math_Mat22uMultiplyVector(X,v,w)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat22uMultiplyVector(&X,&v,&w); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +assert((w.v[0])==(231)); +assert((w.v[1])==(348)); +/* +X +[[27 5] + [36 20]] +v +[8 3] +v +[231 348] +*/ +fprintf(stdout,"SST_Math_Mat22uMultiplyVectorLocal(X,v)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat22uMultiplyVectorLocal(&X,&w); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +SST_Math_Mat22uMultiplyVectorLocal(&X,&v); +assert((v.v[0])==(231)); +assert((v.v[1])==(348)); +/* Resetting test vectors / mats */ + v.v[0] = 27; + v.v[1] = 37; + X.v[0] = 35; + X.v[1] = 17; + X.v[2] = 16; + X.v[3] = 1; + Y.v[0] = 32; + Y.v[1] = 8; + Y.v[2] = 0; + Y.v[3] = 33; +fprintf(stdout,"SST_Math_Mat22uTranspose(X,A)"); +t0 = rdtsc(); +SST_Math_Mat22uTranspose(&X,&A); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +assert((A.v[0])==(35)); +assert((A.v[2])==(17)); +assert((A.v[1])==(16)); +assert((A.v[3])==(1)); +fprintf(stdout,"SST_Math_Mat22uTransposeLocal(X)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat22uTransposeLocal(&A); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +SST_Math_Mat22uTransposeLocal(&X); +assert((X.v[0])==(35)); +assert((X.v[2])==(17)); +assert((X.v[1])==(16)); +assert((X.v[3])==(1)); +/* +[[-0.89950816 -0.43690396] + [-0.43690396 0.89950816]] +[[ 1. 0.] + [ 0. 1.]] +*/ +X.v[0] = (unsigned int)0; +X.v[2] = (unsigned int)0; +X.v[1] = (unsigned int)0; +X.v[3] = (unsigned int)0; +fprintf(stdout,"SST_Math_Mat22uTranspose(X,A)"); +t0 = rdtsc(); +SST_Math_Mat22uTranspose(&X,&A); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +fprintf(stdout,"SST_Math_Mat22uMultiplyMatrix(A,X,B)"); +t0 = rdtsc(); +SST_Math_Mat22uMultiplyMatrix(&A,&X,&B); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +fprintf(stdout,"\n==== SST_Math_Mat22utest_fxn COMPLETE ====\n"); +return 0; +} diff --git a/libsst-math/SST_Mat33d.c b/libsst-math/SST_Mat33d.c new file mode 100644 index 0000000..695919e --- /dev/null +++ b/libsst-math/SST_Mat33d.c @@ -0,0 +1,647 @@ +/* + AUTOMATICALLY GENERATED FILE - DO NOT EDIT! + Please change MatrixNxN.py and re-run it +*/ +/* Generated with ./MatrixNxN.py n = 3, TYPE = double */ + +#include <float.h> +#include <pstdbool.h> +#include <stdio.h> +#include <math.h> /* for sqrt functions */ +#include <stdlib.h> /* for the abs/labs functions */ +#include <SST/SST_Build.h> + +#include <SST/SST_Mat33.h> +#include <SST/SST_Vec3.h> +void SST_Math_Mat33dAdd(const SST_Mat33d* RESTRICT _A, const SST_Mat33d* RESTRICT _B, SST_Mat33d* RESTRICT _out) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + SST_ASSUME_ALIGNED(_out,16); + + _out->v[0] = _A->v[0] + _B->v[0]; + _out->v[1] = _A->v[1] + _B->v[1]; + _out->v[2] = _A->v[2] + _B->v[2]; + _out->v[3] = _A->v[3] + _B->v[3]; + _out->v[4] = _A->v[4] + _B->v[4]; + _out->v[5] = _A->v[5] + _B->v[5]; + _out->v[6] = _A->v[6] + _B->v[6]; + _out->v[7] = _A->v[7] + _B->v[7]; + _out->v[8] = _A->v[8] + _B->v[8]; +} + +/******************************************************************************/ + +void SST_Math_Mat33dAddLocal(SST_Mat33d* RESTRICT _A, const SST_Mat33d* RESTRICT _B) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + + _A->v[0] += _B->v[0]; + _A->v[1] += _B->v[1]; + _A->v[2] += _B->v[2]; + _A->v[3] += _B->v[3]; + _A->v[4] += _B->v[4]; + _A->v[5] += _B->v[5]; + _A->v[6] += _B->v[6]; + _A->v[7] += _B->v[7]; + _A->v[8] += _B->v[8]; +} + +/******************************************************************************/ + +void SST_Math_Mat33dSubtract(const SST_Mat33d* RESTRICT _A, const SST_Mat33d* RESTRICT _B, SST_Mat33d* RESTRICT _out) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + SST_ASSUME_ALIGNED(_out,16); + + _out->v[0] = _A->v[0] - _B->v[0]; + _out->v[1] = _A->v[1] - _B->v[1]; + _out->v[2] = _A->v[2] - _B->v[2]; + _out->v[3] = _A->v[3] - _B->v[3]; + _out->v[4] = _A->v[4] - _B->v[4]; + _out->v[5] = _A->v[5] - _B->v[5]; + _out->v[6] = _A->v[6] - _B->v[6]; + _out->v[7] = _A->v[7] - _B->v[7]; + _out->v[8] = _A->v[8] - _B->v[8]; +} + +/******************************************************************************/ + +void SST_Math_Mat33dSubtractLocal(SST_Mat33d* RESTRICT _A, const SST_Mat33d* RESTRICT _B) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + + _A->v[0] -= _B->v[0]; + _A->v[1] -= _B->v[1]; + _A->v[2] -= _B->v[2]; + _A->v[3] -= _B->v[3]; + _A->v[4] -= _B->v[4]; + _A->v[5] -= _B->v[5]; + _A->v[6] -= _B->v[6]; + _A->v[7] -= _B->v[7]; + _A->v[8] -= _B->v[8]; +} + +/******************************************************************************/ + +void SST_Math_Mat33dMultiplyElementwise(const SST_Mat33d* RESTRICT _A, const SST_Mat33d* RESTRICT _B, SST_Mat33d* RESTRICT _out) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + SST_ASSUME_ALIGNED(_out,16); + + _out->v[0] = _A->v[0] * _B->v[0]; + _out->v[1] = _A->v[1] * _B->v[1]; + _out->v[2] = _A->v[2] * _B->v[2]; + _out->v[3] = _A->v[3] * _B->v[3]; + _out->v[4] = _A->v[4] * _B->v[4]; + _out->v[5] = _A->v[5] * _B->v[5]; + _out->v[6] = _A->v[6] * _B->v[6]; + _out->v[7] = _A->v[7] * _B->v[7]; + _out->v[8] = _A->v[8] * _B->v[8]; +} + +/******************************************************************************/ + +void SST_Math_Mat33dMultiplyElementwiseLocal(SST_Mat33d* RESTRICT _A, const SST_Mat33d* RESTRICT _B) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + + _A->v[0] *= _B->v[0]; + _A->v[1] *= _B->v[1]; + _A->v[2] *= _B->v[2]; + _A->v[3] *= _B->v[3]; + _A->v[4] *= _B->v[4]; + _A->v[5] *= _B->v[5]; + _A->v[6] *= _B->v[6]; + _A->v[7] *= _B->v[7]; + _A->v[8] *= _B->v[8]; +} + +/******************************************************************************/ + +void SST_Math_Mat33dMultiplyScalar(const SST_Mat33d* RESTRICT _A, const double k, SST_Mat33d* RESTRICT _out) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_out,16); + + _out->v[0] = _A->v[0] * k; + _out->v[1] = _A->v[1] * k; + _out->v[2] = _A->v[2] * k; + _out->v[3] = _A->v[3] * k; + _out->v[4] = _A->v[4] * k; + _out->v[5] = _A->v[5] * k; + _out->v[6] = _A->v[6] * k; + _out->v[7] = _A->v[7] * k; + _out->v[8] = _A->v[8] * k; +} + +/******************************************************************************/ + +void SST_Math_Mat33dMultiplyScalarLocal(SST_Mat33d* RESTRICT _A, const double k) +{ + SST_ASSUME_ALIGNED(_A,16); + + _A->v[0] *= k; + _A->v[1] *= k; + _A->v[2] *= k; + _A->v[3] *= k; + _A->v[4] *= k; + _A->v[5] *= k; + _A->v[6] *= k; + _A->v[7] *= k; + _A->v[8] *= k; +} + +/******************************************************************************/ + + +void SST_Math_Mat33dMultiplyMatrix(const SST_Mat33d* _A, const SST_Mat33d* RESTRICT _B, SST_Mat33d* RESTRICT _out) +{ +SST_ASSUME_ALIGNED(_A,16); +SST_ASSUME_ALIGNED(_B,16); +SST_ASSUME_ALIGNED(_out,16); +_out->v[ 0] = _A->v[ 0]*_B->v[ 0]+_A->v[ 3]*_B->v[ 1]+_A->v[ 6]*_B->v[ 2]; +_out->v[ 3] = _A->v[ 0]*_B->v[ 3]+_A->v[ 3]*_B->v[ 4]+_A->v[ 6]*_B->v[ 5]; +_out->v[ 6] = _A->v[ 0]*_B->v[ 6]+_A->v[ 3]*_B->v[ 7]+_A->v[ 6]*_B->v[ 8]; +_out->v[ 1] = _A->v[ 1]*_B->v[ 0]+_A->v[ 4]*_B->v[ 1]+_A->v[ 7]*_B->v[ 2]; +_out->v[ 4] = _A->v[ 1]*_B->v[ 3]+_A->v[ 4]*_B->v[ 4]+_A->v[ 7]*_B->v[ 5]; +_out->v[ 7] = _A->v[ 1]*_B->v[ 6]+_A->v[ 4]*_B->v[ 7]+_A->v[ 7]*_B->v[ 8]; +_out->v[ 2] = _A->v[ 2]*_B->v[ 0]+_A->v[ 5]*_B->v[ 1]+_A->v[ 8]*_B->v[ 2]; +_out->v[ 5] = _A->v[ 2]*_B->v[ 3]+_A->v[ 5]*_B->v[ 4]+_A->v[ 8]*_B->v[ 5]; +_out->v[ 8] = _A->v[ 2]*_B->v[ 6]+_A->v[ 5]*_B->v[ 7]+_A->v[ 8]*_B->v[ 8]; +} +void SST_Math_Mat33dMultiplyMatrixLocal(SST_Mat33d* RESTRICT _A, const SST_Mat33d* RESTRICT _B) +{ + double tmp[9]; + SST_ASSUME_ALIGNED(_A,16); +SST_ASSUME_ALIGNED(_B,16); +tmp[ 0] = _A->v[ 0]*_B->v[ 0]+_A->v[ 3]*_B->v[ 1]+_A->v[ 6]*_B->v[ 2]; +tmp[ 3] = _A->v[ 0]*_B->v[ 3]+_A->v[ 3]*_B->v[ 4]+_A->v[ 6]*_B->v[ 5]; +tmp[ 6] = _A->v[ 0]*_B->v[ 6]+_A->v[ 3]*_B->v[ 7]+_A->v[ 6]*_B->v[ 8]; +_A->v[0] = tmp[0]; +_A->v[3] = tmp[3]; +_A->v[6] = tmp[6]; + + +tmp[ 1] = _A->v[ 1]*_B->v[ 0]+_A->v[ 4]*_B->v[ 1]+_A->v[ 7]*_B->v[ 2]; +tmp[ 4] = _A->v[ 1]*_B->v[ 3]+_A->v[ 4]*_B->v[ 4]+_A->v[ 7]*_B->v[ 5]; +tmp[ 7] = _A->v[ 1]*_B->v[ 6]+_A->v[ 4]*_B->v[ 7]+_A->v[ 7]*_B->v[ 8]; +_A->v[1] = tmp[1]; +_A->v[4] = tmp[4]; +_A->v[7] = tmp[7]; + + +tmp[ 2] = _A->v[ 2]*_B->v[ 0]+_A->v[ 5]*_B->v[ 1]+_A->v[ 8]*_B->v[ 2]; +tmp[ 5] = _A->v[ 2]*_B->v[ 3]+_A->v[ 5]*_B->v[ 4]+_A->v[ 8]*_B->v[ 5]; +tmp[ 8] = _A->v[ 2]*_B->v[ 6]+_A->v[ 5]*_B->v[ 7]+_A->v[ 8]*_B->v[ 8]; +_A->v[2] = tmp[2]; +_A->v[5] = tmp[5]; +_A->v[8] = tmp[8]; + + +} +void SST_Math_Mat33dMultiplyVector(const SST_Mat33d* RESTRICT _A, const SST_Vec3d* RESTRICT _v, SST_Vec3d* RESTRICT _out) +{ +SST_ASSUME_ALIGNED(_A,16); +SST_ASSUME_ALIGNED(_v,16); +SST_ASSUME_ALIGNED(_out,16); +_out->v[ 0] = _A->v[ 0]*_v->v[0]+_A->v[ 3]*_v->v[1]+_A->v[ 6]*_v->v[2]; +_out->v[ 1] = _A->v[ 1]*_v->v[0]+_A->v[ 4]*_v->v[1]+_A->v[ 7]*_v->v[2]; +_out->v[ 2] = _A->v[ 2]*_v->v[0]+_A->v[ 5]*_v->v[1]+_A->v[ 8]*_v->v[2]; +} +void SST_Math_Mat33dMultiplyVectorLocal(const SST_Mat33d* RESTRICT _A, SST_Vec3d* RESTRICT _v) +{ +double tmp[3]; +SST_ASSUME_ALIGNED(_A,16); +SST_ASSUME_ALIGNED(_v,16); +tmp[ 0] = _A->v[ 0]*_v->v[0]+_A->v[ 3]*_v->v[1]+_A->v[ 6]*_v->v[2]; +tmp[ 1] = _A->v[ 1]*_v->v[0]+_A->v[ 4]*_v->v[1]+_A->v[ 7]*_v->v[2]; +tmp[ 2] = _A->v[ 2]*_v->v[0]+_A->v[ 5]*_v->v[1]+_A->v[ 8]*_v->v[2]; +_v->v[0] = tmp[0]; +_v->v[1] = tmp[1]; +_v->v[2] = tmp[2]; +} +void SST_Math_Mat33dTranspose(const SST_Mat33d* RESTRICT _A, SST_Mat33d* RESTRICT _out) +{ +SST_ASSUME_ALIGNED(_A,16); +SST_ASSUME_ALIGNED(_out,16); +_out->v[ 0] = _A->v[ 0]; +_out->v[ 1] = _A->v[ 3]; +_out->v[ 2] = _A->v[ 6]; +_out->v[ 3] = _A->v[ 1]; +_out->v[ 4] = _A->v[ 4]; +_out->v[ 5] = _A->v[ 7]; +_out->v[ 6] = _A->v[ 2]; +_out->v[ 7] = _A->v[ 5]; +_out->v[ 8] = _A->v[ 8]; +} +void SST_Math_Mat33dTransposeLocal(SST_Mat33d* RESTRICT _A) +{ +double tmp[3]; +SST_ASSUME_ALIGNED(_A,16); +tmp[1] = _A->v[ 3]; +_A->v[ 3] = _A->v[ 1]; +_A->v[ 1] = tmp[1]; +tmp[2] = _A->v[ 6]; +_A->v[ 6] = _A->v[ 2]; +_A->v[ 2] = tmp[2]; +tmp[2] = _A->v[ 7]; +_A->v[ 7] = _A->v[ 5]; +_A->v[ 5] = tmp[2]; +} +bool SST_Math_Mat33dCheckOrthonormal(const SST_Mat33d* _A) +{ +const double diag = -_A->v[0]*_A->v[0] -_A->v[1]*_A->v[1] -_A->v[2]*_A->v[2] -_A->v[3]*_A->v[3] -_A->v[4]*_A->v[4] -_A->v[5]*_A->v[5] -_A->v[6]*_A->v[6] -_A->v[7]*_A->v[7] -_A->v[8]*_A->v[8]; +const double odiag = _A->v[0]*_A->v[3]+ _A->v[1]*_A->v[4]+ _A->v[2]*_A->v[5]+ _A->v[0]*_A->v[6]+ _A->v[1]*_A->v[7]+ _A->v[2]*_A->v[8]+ _A->v[3]*_A->v[0]+ _A->v[4]*_A->v[1]+ _A->v[5]*_A->v[2]+ _A->v[3]*_A->v[6]+ _A->v[4]*_A->v[7]+ _A->v[5]*_A->v[8]+ _A->v[6]*_A->v[0]+ _A->v[7]*_A->v[1]+ _A->v[8]*_A->v[2]+ _A->v[6]*_A->v[3]+ _A->v[7]*_A->v[4]+ _A->v[8]*_A->v[5]; +SST_ASSUME_ALIGNED(_A,16); +return +((fabs( 3.000000000000000+diag)) <= 100*DBL_EPSILON) & +((fabs(odiag)) <= 100*DBL_EPSILON); + + +} +double SST_Math_Mat33dDeterminant(const SST_Mat33d* _A) +{ + const double result = _A->v[0]*(_A->v[4]*_A->v[8]-_A->v[5]*_A->v[7])-_A->v[1]*(_A->v[3]*_A->v[8]-_A->v[6]*_A->v[5])+_A->v[2]*(_A->v[3]*_A->v[7]-_A->v[6]*_A->v[4]); + SST_ASSUME_ALIGNED(_A,16); + return result; +} +void SST_Math_Mat33dInvert(const SST_Mat33d* RESTRICT _A, SST_Mat33d* RESTRICT _out) +{ +/* Gaussian Elimination */ +#define _A(i,j) _A->v[i+3*j] +#define _out(i,j) _out->v[i+3*j] +#define Pinv(i,j) Pinv.v[i+3*j] +double aij; +double norm_aij; +SST_Mat33d Pinv; +SST_ASSUME_ALIGNED(_A,16); +/* Set _out to the identity */ +_out(0,0) = 1.000000000000000; +_out(1,0) = 0.000000000000000; +_out(2,0) = 0.000000000000000; +_out(0,1) = 0.000000000000000; +_out(1,1) = 1.000000000000000; +_out(2,1) = 0.000000000000000; +_out(0,2) = 0.000000000000000; +_out(1,2) = 0.000000000000000; +_out(2,2) = 1.000000000000000; +/* Set _Pinv to _A so we don't overwrite it */ +Pinv.v[0] = _A->v[0]; +Pinv.v[1] = _A->v[1]; +Pinv.v[2] = _A->v[2]; +Pinv.v[3] = _A->v[3]; +Pinv.v[4] = _A->v[4]; +Pinv.v[5] = _A->v[5]; +Pinv.v[6] = _A->v[6]; +Pinv.v[7] = _A->v[7]; +Pinv.v[8] = _A->v[8]; +/* Put in Reduced Row Echelon form */ +/* Note that we can set the entry to 0, or just calculate it. + The latter will be helpful when recognizing that these are all simple vector moves */ +/* Sort if need be */ +aij = -Pinv(1,0) / Pinv(0,0) ; +Pinv(1,0) += aij*Pinv(0,0) ; +Pinv(1,1) += aij*Pinv(0,1) ; +Pinv(1,2) += aij*Pinv(0,2) ; +_out(1,0) += aij*_out(0,0) ; +_out(1,1) += aij*_out(0,1) ; +_out(1,2) += aij*_out(0,2) ; +/* Sort if need be */ +aij = -Pinv(2,0) / Pinv(0,0) ; +Pinv(2,0) += aij*Pinv(0,0) ; +Pinv(2,1) += aij*Pinv(0,1) ; +Pinv(2,2) += aij*Pinv(0,2) ; +_out(2,0) += aij*_out(0,0) ; +_out(2,1) += aij*_out(0,1) ; +_out(2,2) += aij*_out(0,2) ; +/* Sort if need be */ +aij = -Pinv(2,1) / Pinv(1,1) ; +Pinv(2,0) += aij*Pinv(1,0) ; +Pinv(2,1) += aij*Pinv(1,1) ; +Pinv(2,2) += aij*Pinv(1,2) ; +_out(2,0) += aij*_out(1,0) ; +_out(2,1) += aij*_out(1,1) ; +_out(2,2) += aij*_out(1,2) ; +/* Backsubstitution */ +norm_aij = 1.000000000000000 / Pinv(2,2) ; +Pinv(2,2) = 1.000000000000000; +_out(2,0) *= norm_aij; +_out(2,1) *= norm_aij; +_out(2,2) *= norm_aij; +aij = -Pinv(0,2); +Pinv(0,0) += aij*Pinv(2,0); +Pinv(0,1) += aij*Pinv(2,1); +Pinv(0,2) += aij*Pinv(2,2); +_out(0,0) += aij*_out(2,0); +_out(0,1) += aij*_out(2,1); +_out(0,2) += aij*_out(2,2); +aij = -Pinv(1,2); +Pinv(1,0) += aij*Pinv(2,0); +Pinv(1,1) += aij*Pinv(2,1); +Pinv(1,2) += aij*Pinv(2,2); +_out(1,0) += aij*_out(2,0); +_out(1,1) += aij*_out(2,1); +_out(1,2) += aij*_out(2,2); +norm_aij = 1.000000000000000 / Pinv(1,1) ; +Pinv(1,1) = 1.000000000000000; +_out(1,0) *= norm_aij; +_out(1,1) *= norm_aij; +_out(1,2) *= norm_aij; +aij = -Pinv(0,1); +Pinv(0,0) += aij*Pinv(1,0); +Pinv(0,1) += aij*Pinv(1,1); +Pinv(0,2) += aij*Pinv(1,2); +_out(0,0) += aij*_out(1,0); +_out(0,1) += aij*_out(1,1); +_out(0,2) += aij*_out(1,2); +norm_aij = 1.000000000000000 / Pinv(0,0) ; +Pinv(0,0) = 1.000000000000000; +_out(0,0) *= norm_aij; +_out(0,1) *= norm_aij; +_out(0,2) *= norm_aij; +#undef _A +#undef _out +#undef Pinv +} +void SST_Math_Mat33dInvertLocal(SST_Mat33d* RESTRICT _A) +{ +/* Gaussian Elimination */ +#define _A(i,j) _A->v[i+3*j] +#define out(i,j) out->v[i+3*j] +#define Pinv(i,j) Pinv.v[i+3*j] +double aij; +double norm_aij; +SST_Mat33d Pinv; +SST_ASSUME_ALIGNED(_A,16); +/* Set _out to the identity */ +/* Set _Pinv to _A so we don't overwrite it */ +Pinv.v[0] = _A->v[0]; +Pinv.v[1] = _A->v[1]; +Pinv.v[2] = _A->v[2]; +Pinv.v[3] = _A->v[3]; +Pinv.v[4] = _A->v[4]; +Pinv.v[5] = _A->v[5]; +Pinv.v[6] = _A->v[6]; +Pinv.v[7] = _A->v[7]; +Pinv.v[8] = _A->v[8]; +_A(0,0) = 1.000000000000000; +_A(1,0) = 0.000000000000000; +_A(2,0) = 0.000000000000000; +_A(0,1) = 0.000000000000000; +_A(1,1) = 1.000000000000000; +_A(2,1) = 0.000000000000000; +_A(0,2) = 0.000000000000000; +_A(1,2) = 0.000000000000000; +_A(2,2) = 1.000000000000000; +/* Put in Reduced Row Echelon form */ +/* Note that we can set the entry to 0, or just calculate it. + The latter will be helpful when recognizing that these are all simple vector moves */ +/* Sort if need be */ +aij = -Pinv(1,0) / Pinv(0,0) ; +Pinv(1,0) += aij*Pinv(0,0) ; +Pinv(1,1) += aij*Pinv(0,1) ; +Pinv(1,2) += aij*Pinv(0,2) ; +_A(1,0) += aij*_A(0,0) ; +_A(1,1) += aij*_A(0,1) ; +_A(1,2) += aij*_A(0,2) ; +/* Sort if need be */ +aij = -Pinv(2,0) / Pinv(0,0) ; +Pinv(2,0) += aij*Pinv(0,0) ; +Pinv(2,1) += aij*Pinv(0,1) ; +Pinv(2,2) += aij*Pinv(0,2) ; +_A(2,0) += aij*_A(0,0) ; +_A(2,1) += aij*_A(0,1) ; +_A(2,2) += aij*_A(0,2) ; +/* Sort if need be */ +aij = -Pinv(2,1) / Pinv(1,1) ; +Pinv(2,0) += aij*Pinv(1,0) ; +Pinv(2,1) += aij*Pinv(1,1) ; +Pinv(2,2) += aij*Pinv(1,2) ; +_A(2,0) += aij*_A(1,0) ; +_A(2,1) += aij*_A(1,1) ; +_A(2,2) += aij*_A(1,2) ; +/* Backsubstitution */ +norm_aij = 1.000000000000000 / Pinv(2,2) ; +Pinv(2,2) = 1.000000000000000; +_A(2,0) *= norm_aij; +_A(2,1) *= norm_aij; +_A(2,2) *= norm_aij; +aij = -Pinv.v[6]; +Pinv.v[0] += aij*Pinv.v[2]; +Pinv.v[3] += aij*Pinv.v[5]; +Pinv.v[6] += aij*Pinv.v[8]; +_A->v[0] += aij*_A->v[2]; +_A->v[3] += aij*_A->v[5]; +_A->v[6] += aij*_A->v[8]; +aij = -Pinv.v[7]; +Pinv.v[1] += aij*Pinv.v[2]; +Pinv.v[4] += aij*Pinv.v[5]; +Pinv.v[7] += aij*Pinv.v[8]; +_A->v[1] += aij*_A->v[2]; +_A->v[4] += aij*_A->v[5]; +_A->v[7] += aij*_A->v[8]; +norm_aij = 1.000000000000000 / Pinv(1,1) ; +Pinv(1,1) = 1.000000000000000; +_A(1,0) *= norm_aij; +_A(1,1) *= norm_aij; +_A(1,2) *= norm_aij; +aij = -Pinv.v[3]; +Pinv.v[0] += aij*Pinv.v[1]; +Pinv.v[3] += aij*Pinv.v[4]; +Pinv.v[6] += aij*Pinv.v[7]; +_A->v[0] += aij*_A->v[1]; +_A->v[3] += aij*_A->v[4]; +_A->v[6] += aij*_A->v[7]; +norm_aij = 1.000000000000000 / Pinv(0,0) ; +Pinv(0,0) = 1.000000000000000; +_A(0,0) *= norm_aij; +_A(0,1) *= norm_aij; +_A(0,2) *= norm_aij; +} +void SST_Math_Mat33dCreateLU(const SST_Mat33d* RESTRICT _A, SST_Mat33d* RESTRICT _LU) +{ +#define _A(i,j) _A->v[i+3*j] +#define _LU(i,j) _LU->v[i+3*j] + int i,j,k; + double sum; +SST_ASSUME_ALIGNED(_A,16); +SST_ASSUME_ALIGNED(_LU,16); + _LU(0,0) = _A(0,0); + _LU(0,1) = 0; + _LU(0,2) = 0; + _LU(1,0) = _A(1,0); + _LU(1,2) = 0; + _LU(2,0) = _A(2,0); + /* _U(0,0) = 1.000000000000000; */ + /* _U(1,1) = 1.000000000000000; */ + /* _U(2,2) = 1.000000000000000; */ + _LU(0,1) = _A(0,1) / _LU(0,0); + _LU(0,2) = _A(0,2) / _LU(0,0); + for(i=1; i < 3; i++) { + + for(j=1; j <= i; j++) { + sum = 0.000000000000000; + for(k=0; k < j; k++) + sum += -_LU(i,k)*_LU(k,j); + _LU(i,j) = _A(i,j) + sum; + } + for(j=i+1; j < 3; j++) { + sum = 0.000000000000000; + for(k=0; k < i; k++) + sum += -_LU(i,k)*_LU(k,j); + _LU(i,j) = (_A(i,j) + sum) / _LU(i,i); + } + } +#undef _A +#undef _LU +} +void SST_Math_Mat33dApplyLUMat(const SST_Mat33d* _LU, const SST_Mat33d* _A, SST_Mat33d* _out) +{ + +#define _LU(i,j) _LU->v[i+3*j] +#define _A(i,j) _A->v[i+3*j] +#define _out(i,j) _out->v[i+3*j] + int i, j, col; + double sum; +SST_ASSUME_ALIGNED(_A,16); +SST_ASSUME_ALIGNED(_LU,16); +SST_ASSUME_ALIGNED(_out,16); + for(col = 0; col < 3; col++) { + _out(0,col) = _A(0,col); + _out(1,col) = _A(1,col); + _out(2,col) = _A(2,col); + /* Forward Substitution for Ly = v */ + for(i = 0; i < 3; i++) { + sum = 0.000000000000000; + for(j = 0; j < i; j++) + sum += _LU(i,j) * _out(j,col); + _out(i,col) = (_out(i,col) - sum) / _LU(i,i) ; + } +/* Backwards Substitution for Uw = y */ + for(i = 2; i >=0; i--) { + sum = 0.000000000000000; + for(j = i+1; j < 3; j++) + sum += _LU(i,j) * _out(j,col); + _out(i,col) = (_out(i,col) - sum) ; /* divide by U(i,i)=1 */ + } + } +#undef _LU /* (i,j) _LU->v[i+3*j] */ +#undef _A /* (i,j) _A->v[i+3*j] */ +#undef _out /* (i,j) _out->v[i+3*j] */ +} +void SST_Math_Mat33dApplyLUMatLocal(const SST_Mat33d* _LU,SST_Mat33d* _A) +{ + +#define _LU(i,j) _LU->v[i+3*j] +#define _A(i,j) _A->v[i+3*j] + int i, j, col; + double sum; + for(col = 0; col < 3; col++) { + /* Forward Substitution for Ly = v */ + for(i = 0; i < 3; i++) { + sum = 0.000000000000000; + for(j = 0; j < i; j++) + sum += _LU(i,j) * _A(j,col); + _A(i,col) = (_A(i,col) - sum) / _LU(i,i) ; + } +/* Backwards Substitution for Uw = y */ + for(i = 2; i >=0; i--) { + sum = 0.000000000000000; + for(j = i+1; j < 3; j++) + sum += _LU(i,j) * _A(j,col); + _A(i,col) = (_A(i,col) - sum) ; /* U is 1s along the diagonal */ + } + } +} +void SST_Math_Mat33dApplyLUVec(const SST_Mat33d* _LU, const SST_Vec3d* _v,SST_Vec3d* _w) +{ + +#define _LU(i,j) _LU->v[i+3*j] + int i, j; + double sum; + _w->v[0] = _v->v[0]; + _w->v[1] = _v->v[1]; + _w->v[2] = _v->v[2]; + /* Forward Substitution for Ly = v */ + for(i = 0; i < 3; i++) { + sum = 0.000000000000000; + for(j = 0; j < i; j++) + sum += _LU(i,j) * _w->v[j]; + _w->v[i] = (_w->v[i] - sum) / _LU(i,i) ; + } +/* Backwards Substitution for Uw = y */ + for(i = 2; i >= 0; i--) { + sum = 0.000000000000000; + for(j = i+1; j < 3; j++) + sum += _LU(i,j) * _w->v[j]; + /*_w->v[i] = (_w->v[i] - sum) ;*/ + _w->v[i] = (_w->v[i] - sum) ; + } +#undef _LU /* (i,j) _LU->v[i+3*j] */ +} +void SST_Math_Mat33dApplyLUVecLocal(const SST_Mat33d* _LU,SST_Vec3d* _w) +{ + +#define _LU(i,j) _LU->v[i+3*j] + int i, j; + double sum; + /* Forward Substitution for Ly = v */ + for(i = 0; i < 3; i++) { + sum = 0.000000000000000; + for(j = 0; j < i; j++) + sum += _LU(i,j) * _w->v[j]; + _w->v[i] = (_w->v[i] - sum) / _LU(i,i) ; + } +/* Backwards Substitution for Uw = y */ + for(i = 2; i >= 0; i--) { + sum = 0.000000000000000; + for(j = i+1; j < 3; j++) + sum += _LU(i,j) * _w->v[j]; + /*_w->v[i] = (_w->v[i] - sum) ;*/ + _w->v[i] = (_w->v[i] - sum) ; + } +#undef _LU /* (i,j) _LU->v[i+3*j] */ +} +void SST_Math_Mat33dCreateLULocal(SST_Mat33d* RESTRICT _A) +{ + /* Note this code stores both L and U inside of A */ + /* For A in R[n x m] we say that for n = m there is an LU = A decomposition [In our decomp, diag[L] = I. Furthermore there is an LU=PA decomposition, where P is a permutation matrix + Step 1: U(i,i:m) = A(i,i:m) + Step 2: L(i+1:n,i) = -A(i+1:n,i) + Step 3: ??? + Step 4: Profit */ +#define _A(i,j) _A->v[i+3*j] + int i,j,k; + double sum; +/* These entries are the same as before in the algorithm. This is left in for purposes of clarity and completeness +_L(0,0) = _A(0,0); +_L(1,0) = _A(1,0); +_L(2,0) = _A(2,0); +These entries are understood to be 1 in this storage format. This is left in for purposes of clarity and completeness +_U(0,0) = 1.000000000000000; +_U(1,1) = 1.000000000000000; +_U(2,2) = 1.000000000000000; +*/ +_A(0,1) = _A(0,1) / _A(0,0); +_A(0,2) = _A(0,2) / _A(0,0); + for(i=1; i < 3; i++) { + + for(j=0; j <= i; j++) { + sum = 0.000000000000000; + for(k=0; k < j; k++) sum += -_A(i,k)*_A(k,j); + _A(i,j) = _A(i,j) + sum; + } + for(j=i+1; j < 3; j++) { + sum = 0.000000000000000; + for(k=0; k < i; k++) sum += -_A(i,k)*_A(k,j); + _A(i,j) = (_A(i,j) + sum) / _A(i,i); + } + } +#undef _A +} diff --git a/libsst-math/SST_Mat33d_benchmark.c b/libsst-math/SST_Mat33d_benchmark.c new file mode 100644 index 0000000..1565d0a --- /dev/null +++ b/libsst-math/SST_Mat33d_benchmark.c @@ -0,0 +1,601 @@ +#include <float.h> +#include <math.h> +#include <stdlib.h> +#include <stdio.h> +#include <assert.h> +#include <xmmintrin.h> +#include <SST/SST_Timer_x86.h> +#include <SST/SST_Mat33.h> +#include <SST/SST_Vec3.h> + + + + +int SST_Math_Mat33d_test_fxns() +{ +const int NTESTS = 10; +int i; +uint64_t t0,t1; +SST_Mat33d X; /* 3 x 3 matrix */ +SST_Mat33d Y; /* 3 x 3 matrix */ +SST_Mat33d A; /* 3 x 3 matrix */ +SST_Mat33d B; /* 3 x 3 matrix */ +SST_Vec3d v; /* 3 vector */ +SST_Vec3d w; /* 3 vector */ +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +/* Resetting test vectors / mats */ + v.v[0] = 14.000000000000000; + v.v[1] = -16.000000000000000; + v.v[2] = 13.000000000000000; + X.v[0] = -4.000000000000000; + X.v[1] = -18.000000000000000; + X.v[2] = 12.000000000000000; + X.v[3] = 11.000000000000000; + X.v[4] = -14.000000000000000; + X.v[5] = 19.000000000000000; + X.v[6] = -6.000000000000000; + X.v[7] = 0.000000000000000; + X.v[8] = 11.000000000000000; + Y.v[0] = -17.000000000000000; + Y.v[1] = 9.000000000000000; + Y.v[2] = 17.000000000000000; + Y.v[3] = -7.000000000000000; + Y.v[4] = 8.000000000000000; + Y.v[5] = -11.000000000000000; + Y.v[6] = -14.000000000000000; + Y.v[7] = 8.000000000000000; + Y.v[8] = -8.000000000000000; +SST_Math_Mat33dAdd(&X,&Y,&A); /* clear out the initial finding of object */ +/* Clear out the rdtsc register */ +fprintf(stdout,"SST_Math_Mat33dAdd(X,Y,A)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat33dAdd(&X,&Y,&A); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +/* +[[ -4. 11. -6.] + [-18. -14. 0.] + [ 12. 19. 11.]] +[[-17. -7. -14.] + [ 9. 8. 8.] + [ 17. -11. -8.]] +[[-21. 4. -20.] + [ -9. -6. 8.] + [ 29. 8. 3.]] +*/ +assert(fabs((A.v[0])-( -21.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[3])-( 4.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[6])-( -20.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[1])-( -9.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[4])-( -6.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[7])-( 8.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[2])-( 29.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[5])-( 8.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[8])-( 3.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +/* +[[ -4. 11. -6.] + [-18. -14. 0.] + [ 12. 19. 11.]] +[[-17. -7. -14.] + [ 9. 8. 8.] + [ 17. -11. -8.]] +[[-21. 4. -20.] + [ -9. -6. 8.] + [ 29. 8. 3.]] +*/ +fprintf(stdout,"SST_Math_Mat33dAddLocal(A,Y)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat33dAddLocal(&A,&Y); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +SST_Math_Mat33dAddLocal(&X,&Y); /* for accuracy */ +assert(fabs((X.v[0])-( -21.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[3])-( 4.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[6])-( -20.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[1])-( -9.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[4])-( -6.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[7])-( 8.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[2])-( 29.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[5])-( 8.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[8])-( 3.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +/* Resetting test vectors / mats */ + v.v[0] = -17.000000000000000; + v.v[1] = -8.000000000000000; + v.v[2] = 16.000000000000000; + X.v[0] = -18.000000000000000; + X.v[1] = 19.000000000000000; + X.v[2] = 0.000000000000000; + X.v[3] = -4.000000000000000; + X.v[4] = -10.000000000000000; + X.v[5] = -4.000000000000000; + X.v[6] = 9.000000000000000; + X.v[7] = -8.000000000000000; + X.v[8] = 14.000000000000000; + Y.v[0] = 11.000000000000000; + Y.v[1] = -10.000000000000000; + Y.v[2] = -20.000000000000000; + Y.v[3] = 9.000000000000000; + Y.v[4] = -14.000000000000000; + Y.v[5] = -10.000000000000000; + Y.v[6] = 9.000000000000000; + Y.v[7] = 11.000000000000000; + Y.v[8] = -20.000000000000000; +/* +[[-18. -4. 9.] + [ 19. -10. -8.] + [ 0. -4. 14.]] +[[-36. -8. 18.] + [ 38. -20. -16.] + [ 0. -8. 28.]] +*/ +fprintf(stdout,"SST_Math_Mat33dMultiplyScalar(X,t,Y)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat33dMultiplyScalar(&X, 2.000000000000000,&A); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +assert(fabs((A.v[0])-( -36.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[3])-( -8.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[6])-( 18.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[1])-( 38.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[4])-( -20.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[7])-( -16.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[2])-( 0.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[5])-( -8.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[8])-( 28.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +/* +[[-18. -4. 9.] + [ 19. -10. -8.] + [ 0. -4. 14.]] +[[-36. -8. 18.] + [ 38. -20. -16.] + [ 0. -8. 28.]] +*/ +fprintf(stdout,"SST_Math_Mat33dMultiplyScalarLocal(A,t)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat33dMultiplyScalarLocal(&A, 2.000000000000000); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +SST_Math_Mat33dMultiplyScalarLocal(&X, 2.000000000000000); +assert(fabs((X.v[0])-( -36.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[3])-( -8.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[6])-( 18.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[1])-( 38.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[4])-( -20.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[7])-( -16.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[2])-( 0.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[5])-( -8.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[8])-( 28.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +/* Resetting test vectors / mats */ + v.v[0] = -17.000000000000000; + v.v[1] = -4.000000000000000; + v.v[2] = -18.000000000000000; + X.v[0] = -3.000000000000000; + X.v[1] = -18.000000000000000; + X.v[2] = -9.000000000000000; + X.v[3] = -6.000000000000000; + X.v[4] = 2.000000000000000; + X.v[5] = -13.000000000000000; + X.v[6] = 15.000000000000000; + X.v[7] = 10.000000000000000; + X.v[8] = 9.000000000000000; + Y.v[0] = -20.000000000000000; + Y.v[1] = 3.000000000000000; + Y.v[2] = -16.000000000000000; + Y.v[3] = -14.000000000000000; + Y.v[4] = 18.000000000000000; + Y.v[5] = -11.000000000000000; + Y.v[6] = -2.000000000000000; + Y.v[7] = 11.000000000000000; + Y.v[8] = 7.000000000000000; +/* +[[ -3. -6. 15.] + [-18. 2. 10.] + [ -9. -13. 9.]] +[[-20. -14. -2.] + [ 3. 18. 11.] + [-16. -11. 7.]] +[[ 60. 84. -30.] + [ -54. 36. 110.] + [ 144. 143. 63.]] +*/ +fprintf(stdout,"SST_Math_Mat33dMultiplyElementwise(X,Y,A)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat33dMultiplyElementwise(&X, &Y, &A); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +assert(fabs((A.v[0])-( 60.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[3])-( 84.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[6])-( -30.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[1])-( -54.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[4])-( 36.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[7])-( 110.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[2])-( 144.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[5])-( 143.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[8])-( 63.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +/* +[[ -3. -6. 15.] + [-18. 2. 10.] + [ -9. -13. 9.]] +[[-20. -14. -2.] + [ 3. 18. 11.] + [-16. -11. 7.]] +[[ 60. 84. -30.] + [ -54. 36. 110.] + [ 144. 143. 63.]] +*/ +fprintf(stdout,"SST_Math_Mat33dMultiplyElementwiseLocal(X,Y)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat33dMultiplyElementwiseLocal(&A,&Y); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +SST_Math_Mat33dMultiplyElementwiseLocal(&X,&Y); +assert(fabs((X.v[0])-( 60.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[3])-( 84.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[6])-( -30.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[1])-( -54.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[4])-( 36.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[7])-( 110.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[2])-( 144.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[5])-( 143.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[8])-( 63.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +/* Resetting test vectors / mats */ + v.v[0] = -12.000000000000000; + v.v[1] = 4.000000000000000; + v.v[2] = -13.000000000000000; + X.v[0] = -17.000000000000000; + X.v[1] = 17.000000000000000; + X.v[2] = -10.000000000000000; + X.v[3] = 0.000000000000000; + X.v[4] = 12.000000000000000; + X.v[5] = 16.000000000000000; + X.v[6] = -3.000000000000000; + X.v[7] = -7.000000000000000; + X.v[8] = 4.000000000000000; + Y.v[0] = 15.000000000000000; + Y.v[1] = 2.000000000000000; + Y.v[2] = -7.000000000000000; + Y.v[3] = 16.000000000000000; + Y.v[4] = -2.000000000000000; + Y.v[5] = 11.000000000000000; + Y.v[6] = 12.000000000000000; + Y.v[7] = 14.000000000000000; + Y.v[8] = -12.000000000000000; +/* +X +[[-17. 0. -3.] + [ 17. 12. -7.] + [-10. 16. 4.]] +Y +[[ 15. 16. 12.] + [ 2. -2. 14.] + [ -7. 11. -12.]] +[[-234. -305. -168.] + [ 328. 171. 456.] + [-146. -148. 56.]] +*/ +fprintf(stdout,"SST_Math_Mat33dMultiplyMatrix(X,Y,A)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat33dMultiplyMatrix(&X,&Y,&A); +t1 = rdtsc(); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +assert(fabs((A.v[0])-( -234.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[3])-( -305.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[6])-( -168.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[1])-( 328.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[4])-( 171.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[7])-( 456.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[2])-( -146.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[5])-( -148.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[8])-( 56.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +/* +X +[[-17. 0. -3.] + [ 17. 12. -7.] + [-10. 16. 4.]] +Y +[[ 15. 16. 12.] + [ 2. -2. 14.] + [ -7. 11. -12.]] +X +[[-234. -305. -168.] + [ 328. 171. 456.] + [-146. -148. 56.]] +*/ +fprintf(stdout,"SST_Math_Mat33dMultiplyMatrixLocal(X,Y)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat33dMultiplyMatrixLocal(&A,&Y); +t1 = rdtsc(); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +SST_Math_Mat33dMultiplyMatrixLocal(&X,&Y); +assert(fabs((X.v[0])-( -234.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[3])-( -305.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[6])-( -168.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[1])-( 328.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[4])-( 171.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[7])-( 456.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[2])-( -146.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[5])-( -148.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[8])-( 56.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +/* Resetting test vectors / mats */ + v.v[0] = -15.000000000000000; + v.v[1] = -14.000000000000000; + v.v[2] = 10.000000000000000; + X.v[0] = 19.000000000000000; + X.v[1] = 7.000000000000000; + X.v[2] = 17.000000000000000; + X.v[3] = 15.000000000000000; + X.v[4] = 0.000000000000000; + X.v[5] = 12.000000000000000; + X.v[6] = -5.000000000000000; + X.v[7] = 17.000000000000000; + X.v[8] = -19.000000000000000; + Y.v[0] = 6.000000000000000; + Y.v[1] = 16.000000000000000; + Y.v[2] = -19.000000000000000; + Y.v[3] = 0.000000000000000; + Y.v[4] = 15.000000000000000; + Y.v[5] = -7.000000000000000; + Y.v[6] = 0.000000000000000; + Y.v[7] = 17.000000000000000; + Y.v[8] = 7.000000000000000; +/* +X +[[ 19. 15. -5.] + [ 7. 0. 17.] + [ 17. 12. -19.]] +v +[-15. -14. 10.] +w +[-545. 65. -613.] +*/ +i=0; +fprintf(stdout,"SST_Math_Mat33dMultiplyVector(X,v,w)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat33dMultiplyVector(&X,&v,&w); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +assert(fabs((w.v[0])-( -545.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((w.v[1])-( 65.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((w.v[2])-( -613.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +/* +X +[[ 19. 15. -5.] + [ 7. 0. 17.] + [ 17. 12. -19.]] +v +[-15. -14. 10.] +v +[-545. 65. -613.] +*/ +fprintf(stdout,"SST_Math_Mat33dMultiplyVectorLocal(X,v)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat33dMultiplyVectorLocal(&X,&w); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +SST_Math_Mat33dMultiplyVectorLocal(&X,&v); +assert(fabs((v.v[0])-( -545.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((v.v[1])-( 65.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((v.v[2])-( -613.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +/* Resetting test vectors / mats */ + v.v[0] = 2.000000000000000; + v.v[1] = 9.000000000000000; + v.v[2] = 11.000000000000000; + X.v[0] = 15.000000000000000; + X.v[1] = -12.000000000000000; + X.v[2] = -14.000000000000000; + X.v[3] = -6.000000000000000; + X.v[4] = -7.000000000000000; + X.v[5] = -6.000000000000000; + X.v[6] = 6.000000000000000; + X.v[7] = -16.000000000000000; + X.v[8] = 7.000000000000000; + Y.v[0] = 12.000000000000000; + Y.v[1] = 18.000000000000000; + Y.v[2] = 2.000000000000000; + Y.v[3] = 10.000000000000000; + Y.v[4] = -12.000000000000000; + Y.v[5] = 18.000000000000000; + Y.v[6] = 11.000000000000000; + Y.v[7] = -3.000000000000000; + Y.v[8] = 13.000000000000000; +fprintf(stdout,"SST_Math_Mat33dTranspose(X,A)"); +t0 = rdtsc(); +SST_Math_Mat33dTranspose(&X,&A); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +assert(fabs((A.v[0])-( 15.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[3])-( -12.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[6])-( -14.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[1])-( -6.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[4])-( -7.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[7])-( -6.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[2])-( 6.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[5])-( -16.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[8])-( 7.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +fprintf(stdout,"SST_Math_Mat33dTransposeLocal(X)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat33dTransposeLocal(&A); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +SST_Math_Mat33dTransposeLocal(&X); +assert(fabs((X.v[0])-( 15.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[3])-( -12.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[6])-( -14.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[1])-( -6.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[4])-( -7.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[7])-( -6.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[2])-( 6.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[5])-( -16.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[8])-( 7.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +/* +[[-0.63105474 -0.76871053 0.10418269] + [ 0.50484379 -0.50893357 -0.69722261] + [ 0.58898443 -0.38738965 0.70924369]] +[[ 1.00000000e+00 -1.11022302e-16 -5.55111512e-17] + [ -1.11022302e-16 1.00000000e+00 -1.66533454e-16] + [ -5.55111512e-17 -1.66533454e-16 1.00000000e+00]] +*/ +X.v[0] = (double) -0.631054742867507; +X.v[3] = (double) -0.768710530027031; +X.v[6] = (double) 0.104182688245145; +X.v[1] = (double) 0.504843794294005; +X.v[4] = (double) -0.508933572401668; +X.v[7] = (double) -0.697222605948278; +X.v[2] = (double) 0.588984426676340; +X.v[5] = (double) -0.387389648684675; +X.v[8] = (double) 0.709243685361179; +fprintf(stdout,"SST_Math_Mat33dTranspose(X,A)"); +t0 = rdtsc(); +SST_Math_Mat33dTranspose(&X,&A); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +fprintf(stdout,"SST_Math_Mat33dMultiplyMatrix(A,X,B)"); +t0 = rdtsc(); +SST_Math_Mat33dMultiplyMatrix(&A,&X,&B); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +/* Check Negative Test */ +assert(!SST_Math_Mat33dCheckOrthonormal(&X)); +X.v[0] = (double) 1.000000000000000; +X.v[3] = (double) 0.000000000000000; +X.v[6] = (double) 0.000000000000000; +X.v[1] = (double) 0.000000000000000; +X.v[4] = (double) 1.000000000000000; +X.v[7] = (double) 0.000000000000000; +X.v[2] = (double) 0.000000000000000; +X.v[5] = (double) 0.000000000000000; +X.v[8] = (double) 1.000000000000000; +/* Check Positive Test */ +assert(SST_Math_Mat33dCheckOrthonormal(&X)); +/* Resetting test vectors / mats */ + v.v[0] = -12.000000000000000; + v.v[1] = 18.000000000000000; + v.v[2] = -14.000000000000000; + X.v[0] = 9.000000000000000; + X.v[1] = 14.000000000000000; + X.v[2] = 12.000000000000000; + X.v[3] = -7.000000000000000; + X.v[4] = 1.000000000000000; + X.v[5] = -15.000000000000000; + X.v[6] = 12.000000000000000; + X.v[7] = -10.000000000000000; + X.v[8] = -18.000000000000000; + Y.v[0] = -3.000000000000000; + Y.v[1] = -5.000000000000000; + Y.v[2] = -4.000000000000000; + Y.v[3] = -14.000000000000000; + Y.v[4] = 14.000000000000000; + Y.v[5] = -12.000000000000000; + Y.v[6] = 4.000000000000000; + Y.v[7] = 8.000000000000000; + Y.v[8] = 11.000000000000000; +/* +[[ 0.03294118 0.06 -0.01137255] + [-0.02588235 0.06 -0.05058824] + [ 0.04352941 -0.01 -0.02098039]] +*/ +fprintf(stdout,"SST_Math_Mat33dInvert(X,B)\n"); +t0 = rdtsc(); +SST_Math_Mat33dInvert(&X,&B); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +fprintf(stdout,"B[%d][%d] = %24.15lf\n",0,0,B.v[0]); +fprintf(stdout,"B[%d][%d] = %24.15lf\n",0,1,B.v[1]); +fprintf(stdout,"B[%d][%d] = %24.15lf\n",0,2,B.v[2]); +fprintf(stdout,"B[%d][%d] = %24.15lf\n",1,0,B.v[3]); +fprintf(stdout,"B[%d][%d] = %24.15lf\n",1,1,B.v[4]); +fprintf(stdout,"B[%d][%d] = %24.15lf\n",1,2,B.v[5]); +fprintf(stdout,"B[%d][%d] = %24.15lf\n",2,0,B.v[6]); +fprintf(stdout,"B[%d][%d] = %24.15lf\n",2,1,B.v[7]); +fprintf(stdout,"B[%d][%d] = %24.15lf\n",2,2,B.v[8]); +assert(fabs((B.v[0])-( 0.032941176470588)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((B.v[3])-( 0.060000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((B.v[6])-( -0.011372549019608)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((B.v[1])-( -0.025882352941176)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((B.v[4])-( 0.060000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((B.v[7])-( -0.050588235294118)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((B.v[2])-( 0.043529411764706)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((B.v[5])-( -0.010000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((B.v[8])-( -0.020980392156863)) <=100*DBL_EPSILON /* yes this is bad */); +/* Resetting test vectors / mats */ + v.v[0] = 8.000000000000000; + v.v[1] = -14.000000000000000; + v.v[2] = -3.000000000000000; + X.v[0] = 12.000000000000000; + X.v[1] = 3.000000000000000; + X.v[2] = 12.000000000000000; + X.v[3] = 9.000000000000000; + X.v[4] = 17.000000000000000; + X.v[5] = 10.000000000000000; + X.v[6] = -13.000000000000000; + X.v[7] = 0.000000000000000; + X.v[8] = 7.000000000000000; + Y.v[0] = 13.000000000000000; + Y.v[1] = -12.000000000000000; + Y.v[2] = 11.000000000000000; + Y.v[3] = 1.000000000000000; + Y.v[4] = -3.000000000000000; + Y.v[5] = -2.000000000000000; + Y.v[6] = -2.000000000000000; + Y.v[7] = -7.000000000000000; + Y.v[8] = 16.000000000000000; +/* +[[ 0.03399029 -0.05512711 0.06312482] + [-0.00599829 0.06855184 -0.01113967] + [-0.04970009 -0.00342759 0.05055698]] +*/ +fprintf(stdout,"SST_Math_Mat33dInvert(X,B)\n"); +fflush(stdout); +fprintf(stdout,"SST_Math_Mat33dInvertLocal(X,B)\n"); +t0 = rdtsc(); +SST_Math_Mat33dInvertLocal(&X); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +fflush(stdout); +assert(fabs((X.v[0])-( 0.033990288489003)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[3])-( -0.055127106540988)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[6])-( 0.063124821479577)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[1])-( -0.005998286203942)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[4])-( 0.068551842330763)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[7])-( -0.011139674378749)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[2])-( -0.049700085689803)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[5])-( -0.003427592116538)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[8])-( 0.050556983718937)) <=100*DBL_EPSILON /* yes this is bad */); +fprintf(stdout,"\n==== SST_Math_Mat33dtest_fxn COMPLETE ====\n"); +return 0; +} diff --git a/libsst-math/SST_Mat33f.c b/libsst-math/SST_Mat33f.c new file mode 100644 index 0000000..e0a58a6 --- /dev/null +++ b/libsst-math/SST_Mat33f.c @@ -0,0 +1,647 @@ +/* + AUTOMATICALLY GENERATED FILE - DO NOT EDIT! + Please change MatrixNxN.py and re-run it +*/ +/* Generated with ./MatrixNxN.py n = 3, TYPE = float */ + +#include <float.h> +#include <pstdbool.h> +#include <stdio.h> +#include <math.h> /* for sqrt functions */ +#include <stdlib.h> /* for the abs/labs functions */ +#include <SST/SST_Build.h> + +#include <SST/SST_Mat33.h> +#include <SST/SST_Vec3.h> +void SST_Math_Mat33fAdd(const SST_Mat33f* RESTRICT _A, const SST_Mat33f* RESTRICT _B, SST_Mat33f* RESTRICT _out) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + SST_ASSUME_ALIGNED(_out,16); + + _out->v[0] = _A->v[0] + _B->v[0]; + _out->v[1] = _A->v[1] + _B->v[1]; + _out->v[2] = _A->v[2] + _B->v[2]; + _out->v[3] = _A->v[3] + _B->v[3]; + _out->v[4] = _A->v[4] + _B->v[4]; + _out->v[5] = _A->v[5] + _B->v[5]; + _out->v[6] = _A->v[6] + _B->v[6]; + _out->v[7] = _A->v[7] + _B->v[7]; + _out->v[8] = _A->v[8] + _B->v[8]; +} + +/******************************************************************************/ + +void SST_Math_Mat33fAddLocal(SST_Mat33f* RESTRICT _A, const SST_Mat33f* RESTRICT _B) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + + _A->v[0] += _B->v[0]; + _A->v[1] += _B->v[1]; + _A->v[2] += _B->v[2]; + _A->v[3] += _B->v[3]; + _A->v[4] += _B->v[4]; + _A->v[5] += _B->v[5]; + _A->v[6] += _B->v[6]; + _A->v[7] += _B->v[7]; + _A->v[8] += _B->v[8]; +} + +/******************************************************************************/ + +void SST_Math_Mat33fSubtract(const SST_Mat33f* RESTRICT _A, const SST_Mat33f* RESTRICT _B, SST_Mat33f* RESTRICT _out) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + SST_ASSUME_ALIGNED(_out,16); + + _out->v[0] = _A->v[0] - _B->v[0]; + _out->v[1] = _A->v[1] - _B->v[1]; + _out->v[2] = _A->v[2] - _B->v[2]; + _out->v[3] = _A->v[3] - _B->v[3]; + _out->v[4] = _A->v[4] - _B->v[4]; + _out->v[5] = _A->v[5] - _B->v[5]; + _out->v[6] = _A->v[6] - _B->v[6]; + _out->v[7] = _A->v[7] - _B->v[7]; + _out->v[8] = _A->v[8] - _B->v[8]; +} + +/******************************************************************************/ + +void SST_Math_Mat33fSubtractLocal(SST_Mat33f* RESTRICT _A, const SST_Mat33f* RESTRICT _B) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + + _A->v[0] -= _B->v[0]; + _A->v[1] -= _B->v[1]; + _A->v[2] -= _B->v[2]; + _A->v[3] -= _B->v[3]; + _A->v[4] -= _B->v[4]; + _A->v[5] -= _B->v[5]; + _A->v[6] -= _B->v[6]; + _A->v[7] -= _B->v[7]; + _A->v[8] -= _B->v[8]; +} + +/******************************************************************************/ + +void SST_Math_Mat33fMultiplyElementwise(const SST_Mat33f* RESTRICT _A, const SST_Mat33f* RESTRICT _B, SST_Mat33f* RESTRICT _out) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + SST_ASSUME_ALIGNED(_out,16); + + _out->v[0] = _A->v[0] * _B->v[0]; + _out->v[1] = _A->v[1] * _B->v[1]; + _out->v[2] = _A->v[2] * _B->v[2]; + _out->v[3] = _A->v[3] * _B->v[3]; + _out->v[4] = _A->v[4] * _B->v[4]; + _out->v[5] = _A->v[5] * _B->v[5]; + _out->v[6] = _A->v[6] * _B->v[6]; + _out->v[7] = _A->v[7] * _B->v[7]; + _out->v[8] = _A->v[8] * _B->v[8]; +} + +/******************************************************************************/ + +void SST_Math_Mat33fMultiplyElementwiseLocal(SST_Mat33f* RESTRICT _A, const SST_Mat33f* RESTRICT _B) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + + _A->v[0] *= _B->v[0]; + _A->v[1] *= _B->v[1]; + _A->v[2] *= _B->v[2]; + _A->v[3] *= _B->v[3]; + _A->v[4] *= _B->v[4]; + _A->v[5] *= _B->v[5]; + _A->v[6] *= _B->v[6]; + _A->v[7] *= _B->v[7]; + _A->v[8] *= _B->v[8]; +} + +/******************************************************************************/ + +void SST_Math_Mat33fMultiplyScalar(const SST_Mat33f* RESTRICT _A, const float k, SST_Mat33f* RESTRICT _out) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_out,16); + + _out->v[0] = _A->v[0] * k; + _out->v[1] = _A->v[1] * k; + _out->v[2] = _A->v[2] * k; + _out->v[3] = _A->v[3] * k; + _out->v[4] = _A->v[4] * k; + _out->v[5] = _A->v[5] * k; + _out->v[6] = _A->v[6] * k; + _out->v[7] = _A->v[7] * k; + _out->v[8] = _A->v[8] * k; +} + +/******************************************************************************/ + +void SST_Math_Mat33fMultiplyScalarLocal(SST_Mat33f* RESTRICT _A, const float k) +{ + SST_ASSUME_ALIGNED(_A,16); + + _A->v[0] *= k; + _A->v[1] *= k; + _A->v[2] *= k; + _A->v[3] *= k; + _A->v[4] *= k; + _A->v[5] *= k; + _A->v[6] *= k; + _A->v[7] *= k; + _A->v[8] *= k; +} + +/******************************************************************************/ + + +void SST_Math_Mat33fMultiplyMatrix(const SST_Mat33f* _A, const SST_Mat33f* RESTRICT _B, SST_Mat33f* RESTRICT _out) +{ +SST_ASSUME_ALIGNED(_A,16); +SST_ASSUME_ALIGNED(_B,16); +SST_ASSUME_ALIGNED(_out,16); +_out->v[ 0] = _A->v[ 0]*_B->v[ 0]+_A->v[ 3]*_B->v[ 1]+_A->v[ 6]*_B->v[ 2]; +_out->v[ 3] = _A->v[ 0]*_B->v[ 3]+_A->v[ 3]*_B->v[ 4]+_A->v[ 6]*_B->v[ 5]; +_out->v[ 6] = _A->v[ 0]*_B->v[ 6]+_A->v[ 3]*_B->v[ 7]+_A->v[ 6]*_B->v[ 8]; +_out->v[ 1] = _A->v[ 1]*_B->v[ 0]+_A->v[ 4]*_B->v[ 1]+_A->v[ 7]*_B->v[ 2]; +_out->v[ 4] = _A->v[ 1]*_B->v[ 3]+_A->v[ 4]*_B->v[ 4]+_A->v[ 7]*_B->v[ 5]; +_out->v[ 7] = _A->v[ 1]*_B->v[ 6]+_A->v[ 4]*_B->v[ 7]+_A->v[ 7]*_B->v[ 8]; +_out->v[ 2] = _A->v[ 2]*_B->v[ 0]+_A->v[ 5]*_B->v[ 1]+_A->v[ 8]*_B->v[ 2]; +_out->v[ 5] = _A->v[ 2]*_B->v[ 3]+_A->v[ 5]*_B->v[ 4]+_A->v[ 8]*_B->v[ 5]; +_out->v[ 8] = _A->v[ 2]*_B->v[ 6]+_A->v[ 5]*_B->v[ 7]+_A->v[ 8]*_B->v[ 8]; +} +void SST_Math_Mat33fMultiplyMatrixLocal(SST_Mat33f* RESTRICT _A, const SST_Mat33f* RESTRICT _B) +{ + float tmp[9]; + SST_ASSUME_ALIGNED(_A,16); +SST_ASSUME_ALIGNED(_B,16); +tmp[ 0] = _A->v[ 0]*_B->v[ 0]+_A->v[ 3]*_B->v[ 1]+_A->v[ 6]*_B->v[ 2]; +tmp[ 3] = _A->v[ 0]*_B->v[ 3]+_A->v[ 3]*_B->v[ 4]+_A->v[ 6]*_B->v[ 5]; +tmp[ 6] = _A->v[ 0]*_B->v[ 6]+_A->v[ 3]*_B->v[ 7]+_A->v[ 6]*_B->v[ 8]; +_A->v[0] = tmp[0]; +_A->v[3] = tmp[3]; +_A->v[6] = tmp[6]; + + +tmp[ 1] = _A->v[ 1]*_B->v[ 0]+_A->v[ 4]*_B->v[ 1]+_A->v[ 7]*_B->v[ 2]; +tmp[ 4] = _A->v[ 1]*_B->v[ 3]+_A->v[ 4]*_B->v[ 4]+_A->v[ 7]*_B->v[ 5]; +tmp[ 7] = _A->v[ 1]*_B->v[ 6]+_A->v[ 4]*_B->v[ 7]+_A->v[ 7]*_B->v[ 8]; +_A->v[1] = tmp[1]; +_A->v[4] = tmp[4]; +_A->v[7] = tmp[7]; + + +tmp[ 2] = _A->v[ 2]*_B->v[ 0]+_A->v[ 5]*_B->v[ 1]+_A->v[ 8]*_B->v[ 2]; +tmp[ 5] = _A->v[ 2]*_B->v[ 3]+_A->v[ 5]*_B->v[ 4]+_A->v[ 8]*_B->v[ 5]; +tmp[ 8] = _A->v[ 2]*_B->v[ 6]+_A->v[ 5]*_B->v[ 7]+_A->v[ 8]*_B->v[ 8]; +_A->v[2] = tmp[2]; +_A->v[5] = tmp[5]; +_A->v[8] = tmp[8]; + + +} +void SST_Math_Mat33fMultiplyVector(const SST_Mat33f* RESTRICT _A, const SST_Vec3f* RESTRICT _v, SST_Vec3f* RESTRICT _out) +{ +SST_ASSUME_ALIGNED(_A,16); +SST_ASSUME_ALIGNED(_v,16); +SST_ASSUME_ALIGNED(_out,16); +_out->v[ 0] = _A->v[ 0]*_v->v[0]+_A->v[ 3]*_v->v[1]+_A->v[ 6]*_v->v[2]; +_out->v[ 1] = _A->v[ 1]*_v->v[0]+_A->v[ 4]*_v->v[1]+_A->v[ 7]*_v->v[2]; +_out->v[ 2] = _A->v[ 2]*_v->v[0]+_A->v[ 5]*_v->v[1]+_A->v[ 8]*_v->v[2]; +} +void SST_Math_Mat33fMultiplyVectorLocal(const SST_Mat33f* RESTRICT _A, SST_Vec3f* RESTRICT _v) +{ +float tmp[3]; +SST_ASSUME_ALIGNED(_A,16); +SST_ASSUME_ALIGNED(_v,16); +tmp[ 0] = _A->v[ 0]*_v->v[0]+_A->v[ 3]*_v->v[1]+_A->v[ 6]*_v->v[2]; +tmp[ 1] = _A->v[ 1]*_v->v[0]+_A->v[ 4]*_v->v[1]+_A->v[ 7]*_v->v[2]; +tmp[ 2] = _A->v[ 2]*_v->v[0]+_A->v[ 5]*_v->v[1]+_A->v[ 8]*_v->v[2]; +_v->v[0] = tmp[0]; +_v->v[1] = tmp[1]; +_v->v[2] = tmp[2]; +} +void SST_Math_Mat33fTranspose(const SST_Mat33f* RESTRICT _A, SST_Mat33f* RESTRICT _out) +{ +SST_ASSUME_ALIGNED(_A,16); +SST_ASSUME_ALIGNED(_out,16); +_out->v[ 0] = _A->v[ 0]; +_out->v[ 1] = _A->v[ 3]; +_out->v[ 2] = _A->v[ 6]; +_out->v[ 3] = _A->v[ 1]; +_out->v[ 4] = _A->v[ 4]; +_out->v[ 5] = _A->v[ 7]; +_out->v[ 6] = _A->v[ 2]; +_out->v[ 7] = _A->v[ 5]; +_out->v[ 8] = _A->v[ 8]; +} +void SST_Math_Mat33fTransposeLocal(SST_Mat33f* RESTRICT _A) +{ +float tmp[3]; +SST_ASSUME_ALIGNED(_A,16); +tmp[1] = _A->v[ 3]; +_A->v[ 3] = _A->v[ 1]; +_A->v[ 1] = tmp[1]; +tmp[2] = _A->v[ 6]; +_A->v[ 6] = _A->v[ 2]; +_A->v[ 2] = tmp[2]; +tmp[2] = _A->v[ 7]; +_A->v[ 7] = _A->v[ 5]; +_A->v[ 5] = tmp[2]; +} +bool SST_Math_Mat33fCheckOrthonormal(const SST_Mat33f* _A) +{ +const float diag = -_A->v[0]*_A->v[0] -_A->v[1]*_A->v[1] -_A->v[2]*_A->v[2] -_A->v[3]*_A->v[3] -_A->v[4]*_A->v[4] -_A->v[5]*_A->v[5] -_A->v[6]*_A->v[6] -_A->v[7]*_A->v[7] -_A->v[8]*_A->v[8]; +const float odiag = _A->v[0]*_A->v[3]+ _A->v[1]*_A->v[4]+ _A->v[2]*_A->v[5]+ _A->v[0]*_A->v[6]+ _A->v[1]*_A->v[7]+ _A->v[2]*_A->v[8]+ _A->v[3]*_A->v[0]+ _A->v[4]*_A->v[1]+ _A->v[5]*_A->v[2]+ _A->v[3]*_A->v[6]+ _A->v[4]*_A->v[7]+ _A->v[5]*_A->v[8]+ _A->v[6]*_A->v[0]+ _A->v[7]*_A->v[1]+ _A->v[8]*_A->v[2]+ _A->v[6]*_A->v[3]+ _A->v[7]*_A->v[4]+ _A->v[8]*_A->v[5]; +SST_ASSUME_ALIGNED(_A,16); +return +((fabsf(3.000000f+diag)) <= 100*FLT_EPSILON) & +((fabsf(odiag)) <= 100*FLT_EPSILON); + + +} +float SST_Math_Mat33fDeterminant(const SST_Mat33f* _A) +{ + const float result = _A->v[0]*(_A->v[4]*_A->v[8]-_A->v[5]*_A->v[7])-_A->v[1]*(_A->v[3]*_A->v[8]-_A->v[6]*_A->v[5])+_A->v[2]*(_A->v[3]*_A->v[7]-_A->v[6]*_A->v[4]); + SST_ASSUME_ALIGNED(_A,16); + return result; +} +void SST_Math_Mat33fInvert(const SST_Mat33f* RESTRICT _A, SST_Mat33f* RESTRICT _out) +{ +/* Gaussian Elimination */ +#define _A(i,j) _A->v[i+3*j] +#define _out(i,j) _out->v[i+3*j] +#define Pinv(i,j) Pinv.v[i+3*j] +float aij; +float norm_aij; +SST_Mat33f Pinv; +SST_ASSUME_ALIGNED(_A,16); +/* Set _out to the identity */ +_out(0,0) = 1.000000f; +_out(1,0) = 0.000000f; +_out(2,0) = 0.000000f; +_out(0,1) = 0.000000f; +_out(1,1) = 1.000000f; +_out(2,1) = 0.000000f; +_out(0,2) = 0.000000f; +_out(1,2) = 0.000000f; +_out(2,2) = 1.000000f; +/* Set _Pinv to _A so we don't overwrite it */ +Pinv.v[0] = _A->v[0]; +Pinv.v[1] = _A->v[1]; +Pinv.v[2] = _A->v[2]; +Pinv.v[3] = _A->v[3]; +Pinv.v[4] = _A->v[4]; +Pinv.v[5] = _A->v[5]; +Pinv.v[6] = _A->v[6]; +Pinv.v[7] = _A->v[7]; +Pinv.v[8] = _A->v[8]; +/* Put in Reduced Row Echelon form */ +/* Note that we can set the entry to 0, or just calculate it. + The latter will be helpful when recognizing that these are all simple vector moves */ +/* Sort if need be */ +aij = -Pinv(1,0) / Pinv(0,0) ; +Pinv(1,0) += aij*Pinv(0,0) ; +Pinv(1,1) += aij*Pinv(0,1) ; +Pinv(1,2) += aij*Pinv(0,2) ; +_out(1,0) += aij*_out(0,0) ; +_out(1,1) += aij*_out(0,1) ; +_out(1,2) += aij*_out(0,2) ; +/* Sort if need be */ +aij = -Pinv(2,0) / Pinv(0,0) ; +Pinv(2,0) += aij*Pinv(0,0) ; +Pinv(2,1) += aij*Pinv(0,1) ; +Pinv(2,2) += aij*Pinv(0,2) ; +_out(2,0) += aij*_out(0,0) ; +_out(2,1) += aij*_out(0,1) ; +_out(2,2) += aij*_out(0,2) ; +/* Sort if need be */ +aij = -Pinv(2,1) / Pinv(1,1) ; +Pinv(2,0) += aij*Pinv(1,0) ; +Pinv(2,1) += aij*Pinv(1,1) ; +Pinv(2,2) += aij*Pinv(1,2) ; +_out(2,0) += aij*_out(1,0) ; +_out(2,1) += aij*_out(1,1) ; +_out(2,2) += aij*_out(1,2) ; +/* Backsubstitution */ +norm_aij = 1.000000f / Pinv(2,2) ; +Pinv(2,2) = 1.000000f; +_out(2,0) *= norm_aij; +_out(2,1) *= norm_aij; +_out(2,2) *= norm_aij; +aij = -Pinv(0,2); +Pinv(0,0) += aij*Pinv(2,0); +Pinv(0,1) += aij*Pinv(2,1); +Pinv(0,2) += aij*Pinv(2,2); +_out(0,0) += aij*_out(2,0); +_out(0,1) += aij*_out(2,1); +_out(0,2) += aij*_out(2,2); +aij = -Pinv(1,2); +Pinv(1,0) += aij*Pinv(2,0); +Pinv(1,1) += aij*Pinv(2,1); +Pinv(1,2) += aij*Pinv(2,2); +_out(1,0) += aij*_out(2,0); +_out(1,1) += aij*_out(2,1); +_out(1,2) += aij*_out(2,2); +norm_aij = 1.000000f / Pinv(1,1) ; +Pinv(1,1) = 1.000000f; +_out(1,0) *= norm_aij; +_out(1,1) *= norm_aij; +_out(1,2) *= norm_aij; +aij = -Pinv(0,1); +Pinv(0,0) += aij*Pinv(1,0); +Pinv(0,1) += aij*Pinv(1,1); +Pinv(0,2) += aij*Pinv(1,2); +_out(0,0) += aij*_out(1,0); +_out(0,1) += aij*_out(1,1); +_out(0,2) += aij*_out(1,2); +norm_aij = 1.000000f / Pinv(0,0) ; +Pinv(0,0) = 1.000000f; +_out(0,0) *= norm_aij; +_out(0,1) *= norm_aij; +_out(0,2) *= norm_aij; +#undef _A +#undef _out +#undef Pinv +} +void SST_Math_Mat33fInvertLocal(SST_Mat33f* RESTRICT _A) +{ +/* Gaussian Elimination */ +#define _A(i,j) _A->v[i+3*j] +#define out(i,j) out->v[i+3*j] +#define Pinv(i,j) Pinv.v[i+3*j] +float aij; +float norm_aij; +SST_Mat33f Pinv; +SST_ASSUME_ALIGNED(_A,16); +/* Set _out to the identity */ +/* Set _Pinv to _A so we don't overwrite it */ +Pinv.v[0] = _A->v[0]; +Pinv.v[1] = _A->v[1]; +Pinv.v[2] = _A->v[2]; +Pinv.v[3] = _A->v[3]; +Pinv.v[4] = _A->v[4]; +Pinv.v[5] = _A->v[5]; +Pinv.v[6] = _A->v[6]; +Pinv.v[7] = _A->v[7]; +Pinv.v[8] = _A->v[8]; +_A(0,0) = 1.000000f; +_A(1,0) = 0.000000f; +_A(2,0) = 0.000000f; +_A(0,1) = 0.000000f; +_A(1,1) = 1.000000f; +_A(2,1) = 0.000000f; +_A(0,2) = 0.000000f; +_A(1,2) = 0.000000f; +_A(2,2) = 1.000000f; +/* Put in Reduced Row Echelon form */ +/* Note that we can set the entry to 0, or just calculate it. + The latter will be helpful when recognizing that these are all simple vector moves */ +/* Sort if need be */ +aij = -Pinv(1,0) / Pinv(0,0) ; +Pinv(1,0) += aij*Pinv(0,0) ; +Pinv(1,1) += aij*Pinv(0,1) ; +Pinv(1,2) += aij*Pinv(0,2) ; +_A(1,0) += aij*_A(0,0) ; +_A(1,1) += aij*_A(0,1) ; +_A(1,2) += aij*_A(0,2) ; +/* Sort if need be */ +aij = -Pinv(2,0) / Pinv(0,0) ; +Pinv(2,0) += aij*Pinv(0,0) ; +Pinv(2,1) += aij*Pinv(0,1) ; +Pinv(2,2) += aij*Pinv(0,2) ; +_A(2,0) += aij*_A(0,0) ; +_A(2,1) += aij*_A(0,1) ; +_A(2,2) += aij*_A(0,2) ; +/* Sort if need be */ +aij = -Pinv(2,1) / Pinv(1,1) ; +Pinv(2,0) += aij*Pinv(1,0) ; +Pinv(2,1) += aij*Pinv(1,1) ; +Pinv(2,2) += aij*Pinv(1,2) ; +_A(2,0) += aij*_A(1,0) ; +_A(2,1) += aij*_A(1,1) ; +_A(2,2) += aij*_A(1,2) ; +/* Backsubstitution */ +norm_aij = 1.000000f / Pinv(2,2) ; +Pinv(2,2) = 1.000000f; +_A(2,0) *= norm_aij; +_A(2,1) *= norm_aij; +_A(2,2) *= norm_aij; +aij = -Pinv.v[6]; +Pinv.v[0] += aij*Pinv.v[2]; +Pinv.v[3] += aij*Pinv.v[5]; +Pinv.v[6] += aij*Pinv.v[8]; +_A->v[0] += aij*_A->v[2]; +_A->v[3] += aij*_A->v[5]; +_A->v[6] += aij*_A->v[8]; +aij = -Pinv.v[7]; +Pinv.v[1] += aij*Pinv.v[2]; +Pinv.v[4] += aij*Pinv.v[5]; +Pinv.v[7] += aij*Pinv.v[8]; +_A->v[1] += aij*_A->v[2]; +_A->v[4] += aij*_A->v[5]; +_A->v[7] += aij*_A->v[8]; +norm_aij = 1.000000f / Pinv(1,1) ; +Pinv(1,1) = 1.000000f; +_A(1,0) *= norm_aij; +_A(1,1) *= norm_aij; +_A(1,2) *= norm_aij; +aij = -Pinv.v[3]; +Pinv.v[0] += aij*Pinv.v[1]; +Pinv.v[3] += aij*Pinv.v[4]; +Pinv.v[6] += aij*Pinv.v[7]; +_A->v[0] += aij*_A->v[1]; +_A->v[3] += aij*_A->v[4]; +_A->v[6] += aij*_A->v[7]; +norm_aij = 1.000000f / Pinv(0,0) ; +Pinv(0,0) = 1.000000f; +_A(0,0) *= norm_aij; +_A(0,1) *= norm_aij; +_A(0,2) *= norm_aij; +} +void SST_Math_Mat33fCreateLU(const SST_Mat33f* RESTRICT _A, SST_Mat33f* RESTRICT _LU) +{ +#define _A(i,j) _A->v[i+3*j] +#define _LU(i,j) _LU->v[i+3*j] + int i,j,k; + float sum; +SST_ASSUME_ALIGNED(_A,16); +SST_ASSUME_ALIGNED(_LU,16); + _LU(0,0) = _A(0,0); + _LU(0,1) = 0; + _LU(0,2) = 0; + _LU(1,0) = _A(1,0); + _LU(1,2) = 0; + _LU(2,0) = _A(2,0); + /* _U(0,0) = 1.000000f; */ + /* _U(1,1) = 1.000000f; */ + /* _U(2,2) = 1.000000f; */ + _LU(0,1) = _A(0,1) / _LU(0,0); + _LU(0,2) = _A(0,2) / _LU(0,0); + for(i=1; i < 3; i++) { + + for(j=1; j <= i; j++) { + sum = 0.000000f; + for(k=0; k < j; k++) + sum += -_LU(i,k)*_LU(k,j); + _LU(i,j) = _A(i,j) + sum; + } + for(j=i+1; j < 3; j++) { + sum = 0.000000f; + for(k=0; k < i; k++) + sum += -_LU(i,k)*_LU(k,j); + _LU(i,j) = (_A(i,j) + sum) / _LU(i,i); + } + } +#undef _A +#undef _LU +} +void SST_Math_Mat33fApplyLUMat(const SST_Mat33f* _LU, const SST_Mat33f* _A, SST_Mat33f* _out) +{ + +#define _LU(i,j) _LU->v[i+3*j] +#define _A(i,j) _A->v[i+3*j] +#define _out(i,j) _out->v[i+3*j] + int i, j, col; + float sum; +SST_ASSUME_ALIGNED(_A,16); +SST_ASSUME_ALIGNED(_LU,16); +SST_ASSUME_ALIGNED(_out,16); + for(col = 0; col < 3; col++) { + _out(0,col) = _A(0,col); + _out(1,col) = _A(1,col); + _out(2,col) = _A(2,col); + /* Forward Substitution for Ly = v */ + for(i = 0; i < 3; i++) { + sum = 0.000000f; + for(j = 0; j < i; j++) + sum += _LU(i,j) * _out(j,col); + _out(i,col) = (_out(i,col) - sum) / _LU(i,i) ; + } +/* Backwards Substitution for Uw = y */ + for(i = 2; i >=0; i--) { + sum = 0.000000f; + for(j = i+1; j < 3; j++) + sum += _LU(i,j) * _out(j,col); + _out(i,col) = (_out(i,col) - sum) ; /* divide by U(i,i)=1 */ + } + } +#undef _LU /* (i,j) _LU->v[i+3*j] */ +#undef _A /* (i,j) _A->v[i+3*j] */ +#undef _out /* (i,j) _out->v[i+3*j] */ +} +void SST_Math_Mat33fApplyLUMatLocal(const SST_Mat33f* _LU,SST_Mat33f* _A) +{ + +#define _LU(i,j) _LU->v[i+3*j] +#define _A(i,j) _A->v[i+3*j] + int i, j, col; + float sum; + for(col = 0; col < 3; col++) { + /* Forward Substitution for Ly = v */ + for(i = 0; i < 3; i++) { + sum = 0.000000f; + for(j = 0; j < i; j++) + sum += _LU(i,j) * _A(j,col); + _A(i,col) = (_A(i,col) - sum) / _LU(i,i) ; + } +/* Backwards Substitution for Uw = y */ + for(i = 2; i >=0; i--) { + sum = 0.000000f; + for(j = i+1; j < 3; j++) + sum += _LU(i,j) * _A(j,col); + _A(i,col) = (_A(i,col) - sum) ; /* U is 1s along the diagonal */ + } + } +} +void SST_Math_Mat33fApplyLUVec(const SST_Mat33f* _LU, const SST_Vec3f* _v,SST_Vec3f* _w) +{ + +#define _LU(i,j) _LU->v[i+3*j] + int i, j; + float sum; + _w->v[0] = _v->v[0]; + _w->v[1] = _v->v[1]; + _w->v[2] = _v->v[2]; + /* Forward Substitution for Ly = v */ + for(i = 0; i < 3; i++) { + sum = 0.000000f; + for(j = 0; j < i; j++) + sum += _LU(i,j) * _w->v[j]; + _w->v[i] = (_w->v[i] - sum) / _LU(i,i) ; + } +/* Backwards Substitution for Uw = y */ + for(i = 2; i >= 0; i--) { + sum = 0.000000f; + for(j = i+1; j < 3; j++) + sum += _LU(i,j) * _w->v[j]; + /*_w->v[i] = (_w->v[i] - sum) ;*/ + _w->v[i] = (_w->v[i] - sum) ; + } +#undef _LU /* (i,j) _LU->v[i+3*j] */ +} +void SST_Math_Mat33fApplyLUVecLocal(const SST_Mat33f* _LU,SST_Vec3f* _w) +{ + +#define _LU(i,j) _LU->v[i+3*j] + int i, j; + float sum; + /* Forward Substitution for Ly = v */ + for(i = 0; i < 3; i++) { + sum = 0.000000f; + for(j = 0; j < i; j++) + sum += _LU(i,j) * _w->v[j]; + _w->v[i] = (_w->v[i] - sum) / _LU(i,i) ; + } +/* Backwards Substitution for Uw = y */ + for(i = 2; i >= 0; i--) { + sum = 0.000000f; + for(j = i+1; j < 3; j++) + sum += _LU(i,j) * _w->v[j]; + /*_w->v[i] = (_w->v[i] - sum) ;*/ + _w->v[i] = (_w->v[i] - sum) ; + } +#undef _LU /* (i,j) _LU->v[i+3*j] */ +} +void SST_Math_Mat33fCreateLULocal(SST_Mat33f* RESTRICT _A) +{ + /* Note this code stores both L and U inside of A */ + /* For A in R[n x m] we say that for n = m there is an LU = A decomposition [In our decomp, diag[L] = I. Furthermore there is an LU=PA decomposition, where P is a permutation matrix + Step 1: U(i,i:m) = A(i,i:m) + Step 2: L(i+1:n,i) = -A(i+1:n,i) + Step 3: ??? + Step 4: Profit */ +#define _A(i,j) _A->v[i+3*j] + int i,j,k; + float sum; +/* These entries are the same as before in the algorithm. This is left in for purposes of clarity and completeness +_L(0,0) = _A(0,0); +_L(1,0) = _A(1,0); +_L(2,0) = _A(2,0); +These entries are understood to be 1 in this storage format. This is left in for purposes of clarity and completeness +_U(0,0) = 1.000000f; +_U(1,1) = 1.000000f; +_U(2,2) = 1.000000f; +*/ +_A(0,1) = _A(0,1) / _A(0,0); +_A(0,2) = _A(0,2) / _A(0,0); + for(i=1; i < 3; i++) { + + for(j=0; j <= i; j++) { + sum = 0.000000f; + for(k=0; k < j; k++) sum += -_A(i,k)*_A(k,j); + _A(i,j) = _A(i,j) + sum; + } + for(j=i+1; j < 3; j++) { + sum = 0.000000f; + for(k=0; k < i; k++) sum += -_A(i,k)*_A(k,j); + _A(i,j) = (_A(i,j) + sum) / _A(i,i); + } + } +#undef _A +} diff --git a/libsst-math/SST_Mat33f_benchmark.c b/libsst-math/SST_Mat33f_benchmark.c new file mode 100644 index 0000000..312b517 --- /dev/null +++ b/libsst-math/SST_Mat33f_benchmark.c @@ -0,0 +1,601 @@ +#include <float.h> +#include <math.h> +#include <stdlib.h> +#include <stdio.h> +#include <assert.h> +#include <xmmintrin.h> +#include <SST/SST_Timer_x86.h> +#include <SST/SST_Mat33.h> +#include <SST/SST_Vec3.h> + + + + +int SST_Math_Mat33f_test_fxns() +{ +const int NTESTS = 10; +int i; +uint64_t t0,t1; +SST_Mat33f X; /* 3 x 3 matrix */ +SST_Mat33f Y; /* 3 x 3 matrix */ +SST_Mat33f A; /* 3 x 3 matrix */ +SST_Mat33f B; /* 3 x 3 matrix */ +SST_Vec3f v; /* 3 vector */ +SST_Vec3f w; /* 3 vector */ +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +/* Resetting test vectors / mats */ + v.v[0] = -15.000000f; + v.v[1] = 15.000000f; + v.v[2] = -9.000000f; + X.v[0] = 8.000000f; + X.v[1] = -19.000000f; + X.v[2] = 0.000000f; + X.v[3] = 16.000000f; + X.v[4] = -17.000000f; + X.v[5] = -12.000000f; + X.v[6] = 6.000000f; + X.v[7] = 4.000000f; + X.v[8] = -18.000000f; + Y.v[0] = -6.000000f; + Y.v[1] = -16.000000f; + Y.v[2] = 1.000000f; + Y.v[3] = 7.000000f; + Y.v[4] = 1.000000f; + Y.v[5] = 9.000000f; + Y.v[6] = -12.000000f; + Y.v[7] = 10.000000f; + Y.v[8] = 19.000000f; +SST_Math_Mat33fAdd(&X,&Y,&A); /* clear out the initial finding of object */ +/* Clear out the rdtsc register */ +fprintf(stdout,"SST_Math_Mat33fAdd(X,Y,A)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat33fAdd(&X,&Y,&A); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +/* +[[ 8. 16. 6.] + [-19. -17. 4.] + [ 0. -12. -18.]] +[[ -6. 7. -12.] + [-16. 1. 10.] + [ 1. 9. 19.]] +[[ 2. 23. -6.] + [-35. -16. 14.] + [ 1. -3. 1.]] +*/ +assert(fabsf((A.v[0])-(2.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[3])-(23.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[6])-(-6.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[1])-(-35.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[4])-(-16.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[7])-(14.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[2])-(1.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[5])-(-3.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[8])-(1.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +/* +[[ 8. 16. 6.] + [-19. -17. 4.] + [ 0. -12. -18.]] +[[ -6. 7. -12.] + [-16. 1. 10.] + [ 1. 9. 19.]] +[[ 2. 23. -6.] + [-35. -16. 14.] + [ 1. -3. 1.]] +*/ +fprintf(stdout,"SST_Math_Mat33fAddLocal(A,Y)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat33fAddLocal(&A,&Y); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +SST_Math_Mat33fAddLocal(&X,&Y); /* for accuracy */ +assert(fabsf((X.v[0])-(2.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[3])-(23.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[6])-(-6.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[1])-(-35.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[4])-(-16.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[7])-(14.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[2])-(1.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[5])-(-3.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[8])-(1.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +/* Resetting test vectors / mats */ + v.v[0] = 9.000000f; + v.v[1] = 1.000000f; + v.v[2] = 19.000000f; + X.v[0] = 7.000000f; + X.v[1] = 13.000000f; + X.v[2] = -20.000000f; + X.v[3] = -19.000000f; + X.v[4] = 19.000000f; + X.v[5] = 8.000000f; + X.v[6] = 8.000000f; + X.v[7] = -16.000000f; + X.v[8] = -8.000000f; + Y.v[0] = -7.000000f; + Y.v[1] = -8.000000f; + Y.v[2] = 4.000000f; + Y.v[3] = -12.000000f; + Y.v[4] = 5.000000f; + Y.v[5] = -17.000000f; + Y.v[6] = 17.000000f; + Y.v[7] = 14.000000f; + Y.v[8] = -11.000000f; +/* +[[ 7. -19. 8.] + [ 13. 19. -16.] + [-20. 8. -8.]] +[[ 14. -38. 16.] + [ 26. 38. -32.] + [-40. 16. -16.]] +*/ +fprintf(stdout,"SST_Math_Mat33fMultiplyScalar(X,t,Y)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat33fMultiplyScalar(&X,2.000000f,&A); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +assert(fabsf((A.v[0])-(14.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[3])-(-38.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[6])-(16.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[1])-(26.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[4])-(38.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[7])-(-32.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[2])-(-40.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[5])-(16.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[8])-(-16.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +/* +[[ 7. -19. 8.] + [ 13. 19. -16.] + [-20. 8. -8.]] +[[ 14. -38. 16.] + [ 26. 38. -32.] + [-40. 16. -16.]] +*/ +fprintf(stdout,"SST_Math_Mat33fMultiplyScalarLocal(A,t)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat33fMultiplyScalarLocal(&A,2.000000f); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +SST_Math_Mat33fMultiplyScalarLocal(&X,2.000000f); +assert(fabsf((X.v[0])-(14.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[3])-(-38.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[6])-(16.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[1])-(26.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[4])-(38.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[7])-(-32.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[2])-(-40.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[5])-(16.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[8])-(-16.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +/* Resetting test vectors / mats */ + v.v[0] = -9.000000f; + v.v[1] = -2.000000f; + v.v[2] = -8.000000f; + X.v[0] = -5.000000f; + X.v[1] = -14.000000f; + X.v[2] = -6.000000f; + X.v[3] = 1.000000f; + X.v[4] = -9.000000f; + X.v[5] = 7.000000f; + X.v[6] = 18.000000f; + X.v[7] = 10.000000f; + X.v[8] = -19.000000f; + Y.v[0] = -8.000000f; + Y.v[1] = -6.000000f; + Y.v[2] = -2.000000f; + Y.v[3] = -12.000000f; + Y.v[4] = -6.000000f; + Y.v[5] = 8.000000f; + Y.v[6] = -5.000000f; + Y.v[7] = -16.000000f; + Y.v[8] = -16.000000f; +/* +[[ -5. 1. 18.] + [-14. -9. 10.] + [ -6. 7. -19.]] +[[ -8. -12. -5.] + [ -6. -6. -16.] + [ -2. 8. -16.]] +[[ 40. -12. -90.] + [ 84. 54. -160.] + [ 12. 56. 304.]] +*/ +fprintf(stdout,"SST_Math_Mat33fMultiplyElementwise(X,Y,A)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat33fMultiplyElementwise(&X, &Y, &A); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +assert(fabsf((A.v[0])-(40.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[3])-(-12.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[6])-(-90.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[1])-(84.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[4])-(54.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[7])-(-160.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[2])-(12.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[5])-(56.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[8])-(304.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +/* +[[ -5. 1. 18.] + [-14. -9. 10.] + [ -6. 7. -19.]] +[[ -8. -12. -5.] + [ -6. -6. -16.] + [ -2. 8. -16.]] +[[ 40. -12. -90.] + [ 84. 54. -160.] + [ 12. 56. 304.]] +*/ +fprintf(stdout,"SST_Math_Mat33fMultiplyElementwiseLocal(X,Y)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat33fMultiplyElementwiseLocal(&A,&Y); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +SST_Math_Mat33fMultiplyElementwiseLocal(&X,&Y); +assert(fabsf((X.v[0])-(40.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[3])-(-12.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[6])-(-90.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[1])-(84.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[4])-(54.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[7])-(-160.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[2])-(12.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[5])-(56.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[8])-(304.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +/* Resetting test vectors / mats */ + v.v[0] = -7.000000f; + v.v[1] = -15.000000f; + v.v[2] = -19.000000f; + X.v[0] = -16.000000f; + X.v[1] = -15.000000f; + X.v[2] = 10.000000f; + X.v[3] = 0.000000f; + X.v[4] = 0.000000f; + X.v[5] = 6.000000f; + X.v[6] = 1.000000f; + X.v[7] = 3.000000f; + X.v[8] = -18.000000f; + Y.v[0] = -5.000000f; + Y.v[1] = -12.000000f; + Y.v[2] = -15.000000f; + Y.v[3] = 6.000000f; + Y.v[4] = 7.000000f; + Y.v[5] = -7.000000f; + Y.v[6] = 14.000000f; + Y.v[7] = 6.000000f; + Y.v[8] = -18.000000f; +/* +X +[[-16. 0. 1.] + [-15. 0. 3.] + [ 10. 6. -18.]] +Y +[[ -5. 6. 14.] + [-12. 7. 6.] + [-15. -7. -18.]] +[[ 65. -103. -242.] + [ 30. -111. -264.] + [ 148. 228. 500.]] +*/ +fprintf(stdout,"SST_Math_Mat33fMultiplyMatrix(X,Y,A)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat33fMultiplyMatrix(&X,&Y,&A); +t1 = rdtsc(); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +assert(fabsf((A.v[0])-(65.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[3])-(-103.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[6])-(-242.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[1])-(30.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[4])-(-111.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[7])-(-264.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[2])-(148.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[5])-(228.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[8])-(500.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +/* +X +[[-16. 0. 1.] + [-15. 0. 3.] + [ 10. 6. -18.]] +Y +[[ -5. 6. 14.] + [-12. 7. 6.] + [-15. -7. -18.]] +X +[[ 65. -103. -242.] + [ 30. -111. -264.] + [ 148. 228. 500.]] +*/ +fprintf(stdout,"SST_Math_Mat33fMultiplyMatrixLocal(X,Y)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat33fMultiplyMatrixLocal(&A,&Y); +t1 = rdtsc(); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +SST_Math_Mat33fMultiplyMatrixLocal(&X,&Y); +assert(fabsf((X.v[0])-(65.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[3])-(-103.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[6])-(-242.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[1])-(30.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[4])-(-111.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[7])-(-264.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[2])-(148.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[5])-(228.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[8])-(500.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +/* Resetting test vectors / mats */ + v.v[0] = -13.000000f; + v.v[1] = -19.000000f; + v.v[2] = 5.000000f; + X.v[0] = 17.000000f; + X.v[1] = -19.000000f; + X.v[2] = -15.000000f; + X.v[3] = 16.000000f; + X.v[4] = -10.000000f; + X.v[5] = 15.000000f; + X.v[6] = -12.000000f; + X.v[7] = 7.000000f; + X.v[8] = -15.000000f; + Y.v[0] = -5.000000f; + Y.v[1] = -4.000000f; + Y.v[2] = 5.000000f; + Y.v[3] = 19.000000f; + Y.v[4] = 19.000000f; + Y.v[5] = 10.000000f; + Y.v[6] = 19.000000f; + Y.v[7] = 1.000000f; + Y.v[8] = 17.000000f; +/* +X +[[ 17. 16. -12.] + [-19. -10. 7.] + [-15. 15. -15.]] +v +[-13. -19. 5.] +w +[-585. 472. -165.] +*/ +i=0; +fprintf(stdout,"SST_Math_Mat33fMultiplyVector(X,v,w)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat33fMultiplyVector(&X,&v,&w); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +assert(fabsf((w.v[0])-(-585.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((w.v[1])-(472.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((w.v[2])-(-165.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +/* +X +[[ 17. 16. -12.] + [-19. -10. 7.] + [-15. 15. -15.]] +v +[-13. -19. 5.] +v +[-585. 472. -165.] +*/ +fprintf(stdout,"SST_Math_Mat33fMultiplyVectorLocal(X,v)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat33fMultiplyVectorLocal(&X,&w); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +SST_Math_Mat33fMultiplyVectorLocal(&X,&v); +assert(fabsf((v.v[0])-(-585.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((v.v[1])-(472.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((v.v[2])-(-165.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +/* Resetting test vectors / mats */ + v.v[0] = 10.000000f; + v.v[1] = 12.000000f; + v.v[2] = -16.000000f; + X.v[0] = 3.000000f; + X.v[1] = -2.000000f; + X.v[2] = 13.000000f; + X.v[3] = -5.000000f; + X.v[4] = 19.000000f; + X.v[5] = 18.000000f; + X.v[6] = -4.000000f; + X.v[7] = -20.000000f; + X.v[8] = -6.000000f; + Y.v[0] = -1.000000f; + Y.v[1] = -19.000000f; + Y.v[2] = -8.000000f; + Y.v[3] = 10.000000f; + Y.v[4] = 19.000000f; + Y.v[5] = -5.000000f; + Y.v[6] = 6.000000f; + Y.v[7] = 5.000000f; + Y.v[8] = 7.000000f; +fprintf(stdout,"SST_Math_Mat33fTranspose(X,A)"); +t0 = rdtsc(); +SST_Math_Mat33fTranspose(&X,&A); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +assert(fabsf((A.v[0])-(3.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[3])-(-2.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[6])-(13.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[1])-(-5.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[4])-(19.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[7])-(18.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[2])-(-4.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[5])-(-20.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[8])-(-6.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +fprintf(stdout,"SST_Math_Mat33fTransposeLocal(X)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat33fTransposeLocal(&A); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +SST_Math_Mat33fTransposeLocal(&X); +assert(fabsf((X.v[0])-(3.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[3])-(-2.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[6])-(13.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[1])-(-5.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[4])-(19.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[7])-(18.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[2])-(-4.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[5])-(-20.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[8])-(-6.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +/* +[[-0.2223748 0.34678361 -0.91120285] + [ 0.14824986 -0.91170913 -0.38315597] + [-0.96362412 -0.22028992 0.1513305 ]] +[[ 1.00000000e+00 -1.49011612e-08 1.49011612e-08] + [ -1.49011612e-08 1.00000000e+00 -3.72529030e-09] + [ 1.49011612e-08 -3.72529030e-09 1.00000000e+00]] +*/ +X.v[0] = (float)-0.222375f; +X.v[3] = (float)0.346784f; +X.v[6] = (float)-0.911203f; +X.v[1] = (float)0.148250f; +X.v[4] = (float)-0.911709f; +X.v[7] = (float)-0.383156f; +X.v[2] = (float)-0.963624f; +X.v[5] = (float)-0.220290f; +X.v[8] = (float)0.151331f; +fprintf(stdout,"SST_Math_Mat33fTranspose(X,A)"); +t0 = rdtsc(); +SST_Math_Mat33fTranspose(&X,&A); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +fprintf(stdout,"SST_Math_Mat33fMultiplyMatrix(A,X,B)"); +t0 = rdtsc(); +SST_Math_Mat33fMultiplyMatrix(&A,&X,&B); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +/* Check Negative Test */ +assert(!SST_Math_Mat33fCheckOrthonormal(&X)); +X.v[0] = (float)1.000000f; +X.v[3] = (float)0.000000f; +X.v[6] = (float)0.000000f; +X.v[1] = (float)0.000000f; +X.v[4] = (float)1.000000f; +X.v[7] = (float)0.000000f; +X.v[2] = (float)0.000000f; +X.v[5] = (float)0.000000f; +X.v[8] = (float)1.000000f; +/* Check Positive Test */ +assert(SST_Math_Mat33fCheckOrthonormal(&X)); +/* Resetting test vectors / mats */ + v.v[0] = 16.000000f; + v.v[1] = 12.000000f; + v.v[2] = 16.000000f; + X.v[0] = -2.000000f; + X.v[1] = -2.000000f; + X.v[2] = 10.000000f; + X.v[3] = 6.000000f; + X.v[4] = -14.000000f; + X.v[5] = -7.000000f; + X.v[6] = -8.000000f; + X.v[7] = -6.000000f; + X.v[8] = -9.000000f; + Y.v[0] = -9.000000f; + Y.v[1] = 12.000000f; + Y.v[2] = -10.000000f; + Y.v[3] = 1.000000f; + Y.v[4] = 3.000000f; + Y.v[5] = 13.000000f; + Y.v[6] = -8.000000f; + Y.v[7] = -16.000000f; + Y.v[8] = -11.000000f; +/* +[[-0.04496788 -0.05888651 0.07922912] + [ 0.04175589 -0.05246253 -0.00214133] + [-0.08244111 -0.02462527 -0.02141328]] +*/ +fprintf(stdout,"SST_Math_Mat33fInvert(X,B)\n"); +t0 = rdtsc(); +SST_Math_Mat33fInvert(&X,&B); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +fprintf(stdout,"B[%d][%d] = %ff\n",0,0,B.v[0]); +fprintf(stdout,"B[%d][%d] = %ff\n",0,1,B.v[1]); +fprintf(stdout,"B[%d][%d] = %ff\n",0,2,B.v[2]); +fprintf(stdout,"B[%d][%d] = %ff\n",1,0,B.v[3]); +fprintf(stdout,"B[%d][%d] = %ff\n",1,1,B.v[4]); +fprintf(stdout,"B[%d][%d] = %ff\n",1,2,B.v[5]); +fprintf(stdout,"B[%d][%d] = %ff\n",2,0,B.v[6]); +fprintf(stdout,"B[%d][%d] = %ff\n",2,1,B.v[7]); +fprintf(stdout,"B[%d][%d] = %ff\n",2,2,B.v[8]); +assert(fabsf((B.v[0])-(-0.044968f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((B.v[3])-(-0.058887f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((B.v[6])-(0.079229f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((B.v[1])-(0.041756f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((B.v[4])-(-0.052463f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((B.v[7])-(-0.002141f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((B.v[2])-(-0.082441f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((B.v[5])-(-0.024625f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((B.v[8])-(-0.021413f)) <=100*FLT_EPSILON /* yes this is bad */); +/* Resetting test vectors / mats */ + v.v[0] = 9.000000f; + v.v[1] = 0.000000f; + v.v[2] = -2.000000f; + X.v[0] = -11.000000f; + X.v[1] = -3.000000f; + X.v[2] = 19.000000f; + X.v[3] = 15.000000f; + X.v[4] = -19.000000f; + X.v[5] = 10.000000f; + X.v[6] = -3.000000f; + X.v[7] = 0.000000f; + X.v[8] = -20.000000f; + Y.v[0] = 12.000000f; + Y.v[1] = -17.000000f; + Y.v[2] = 4.000000f; + Y.v[3] = -7.000000f; + Y.v[4] = -20.000000f; + Y.v[5] = 10.000000f; + Y.v[6] = 18.000000f; + Y.v[7] = 4.000000f; + Y.v[8] = 5.000000f; +/* +[[-0.06257204 -0.04445908 0.00938581] + [ 0.0098798 -0.04561172 -0.00148197] + [-0.05450354 -0.06504199 -0.04182447]] +*/ +fprintf(stdout,"SST_Math_Mat33fInvert(X,B)\n"); +fflush(stdout); +fprintf(stdout,"SST_Math_Mat33fInvertLocal(X,B)\n"); +t0 = rdtsc(); +SST_Math_Mat33fInvertLocal(&X); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +fflush(stdout); +assert(fabsf((X.v[0])-(-0.062572f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[3])-(-0.044459f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[6])-(0.009386f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[1])-(0.009880f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[4])-(-0.045612f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[7])-(-0.001482f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[2])-(-0.054504f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[5])-(-0.065042f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[8])-(-0.041824f)) <=100*FLT_EPSILON /* yes this is bad */); +fprintf(stdout,"\n==== SST_Math_Mat33ftest_fxn COMPLETE ====\n"); +return 0; +} diff --git a/libsst-math/SST_Mat33i.c b/libsst-math/SST_Mat33i.c new file mode 100644 index 0000000..c869159 --- /dev/null +++ b/libsst-math/SST_Mat33i.c @@ -0,0 +1,273 @@ +/* + AUTOMATICALLY GENERATED FILE - DO NOT EDIT! + Please change MatrixNxN.py and re-run it +*/ +/* Generated with ./MatrixNxN.py n = 3, TYPE = int */ + +#include <float.h> +#include <pstdbool.h> +#include <stdio.h> +#include <math.h> /* for sqrt functions */ +#include <stdlib.h> /* for the abs/labs functions */ +#include <SST/SST_Build.h> + +#include <SST/SST_Mat33.h> +#include <SST/SST_Vec3.h> +void SST_Math_Mat33iAdd(const SST_Mat33i* RESTRICT _A, const SST_Mat33i* RESTRICT _B, SST_Mat33i* RESTRICT _out) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + SST_ASSUME_ALIGNED(_out,16); + + _out->v[0] = _A->v[0] + _B->v[0]; + _out->v[1] = _A->v[1] + _B->v[1]; + _out->v[2] = _A->v[2] + _B->v[2]; + _out->v[3] = _A->v[3] + _B->v[3]; + _out->v[4] = _A->v[4] + _B->v[4]; + _out->v[5] = _A->v[5] + _B->v[5]; + _out->v[6] = _A->v[6] + _B->v[6]; + _out->v[7] = _A->v[7] + _B->v[7]; + _out->v[8] = _A->v[8] + _B->v[8]; +} + +/******************************************************************************/ + +void SST_Math_Mat33iAddLocal(SST_Mat33i* RESTRICT _A, const SST_Mat33i* RESTRICT _B) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + + _A->v[0] += _B->v[0]; + _A->v[1] += _B->v[1]; + _A->v[2] += _B->v[2]; + _A->v[3] += _B->v[3]; + _A->v[4] += _B->v[4]; + _A->v[5] += _B->v[5]; + _A->v[6] += _B->v[6]; + _A->v[7] += _B->v[7]; + _A->v[8] += _B->v[8]; +} + +/******************************************************************************/ + +void SST_Math_Mat33iSubtract(const SST_Mat33i* RESTRICT _A, const SST_Mat33i* RESTRICT _B, SST_Mat33i* RESTRICT _out) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + SST_ASSUME_ALIGNED(_out,16); + + _out->v[0] = _A->v[0] - _B->v[0]; + _out->v[1] = _A->v[1] - _B->v[1]; + _out->v[2] = _A->v[2] - _B->v[2]; + _out->v[3] = _A->v[3] - _B->v[3]; + _out->v[4] = _A->v[4] - _B->v[4]; + _out->v[5] = _A->v[5] - _B->v[5]; + _out->v[6] = _A->v[6] - _B->v[6]; + _out->v[7] = _A->v[7] - _B->v[7]; + _out->v[8] = _A->v[8] - _B->v[8]; +} + +/******************************************************************************/ + +void SST_Math_Mat33iSubtractLocal(SST_Mat33i* RESTRICT _A, const SST_Mat33i* RESTRICT _B) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + + _A->v[0] -= _B->v[0]; + _A->v[1] -= _B->v[1]; + _A->v[2] -= _B->v[2]; + _A->v[3] -= _B->v[3]; + _A->v[4] -= _B->v[4]; + _A->v[5] -= _B->v[5]; + _A->v[6] -= _B->v[6]; + _A->v[7] -= _B->v[7]; + _A->v[8] -= _B->v[8]; +} + +/******************************************************************************/ + +void SST_Math_Mat33iMultiplyElementwise(const SST_Mat33i* RESTRICT _A, const SST_Mat33i* RESTRICT _B, SST_Mat33i* RESTRICT _out) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + SST_ASSUME_ALIGNED(_out,16); + + _out->v[0] = _A->v[0] * _B->v[0]; + _out->v[1] = _A->v[1] * _B->v[1]; + _out->v[2] = _A->v[2] * _B->v[2]; + _out->v[3] = _A->v[3] * _B->v[3]; + _out->v[4] = _A->v[4] * _B->v[4]; + _out->v[5] = _A->v[5] * _B->v[5]; + _out->v[6] = _A->v[6] * _B->v[6]; + _out->v[7] = _A->v[7] * _B->v[7]; + _out->v[8] = _A->v[8] * _B->v[8]; +} + +/******************************************************************************/ + +void SST_Math_Mat33iMultiplyElementwiseLocal(SST_Mat33i* RESTRICT _A, const SST_Mat33i* RESTRICT _B) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + + _A->v[0] *= _B->v[0]; + _A->v[1] *= _B->v[1]; + _A->v[2] *= _B->v[2]; + _A->v[3] *= _B->v[3]; + _A->v[4] *= _B->v[4]; + _A->v[5] *= _B->v[5]; + _A->v[6] *= _B->v[6]; + _A->v[7] *= _B->v[7]; + _A->v[8] *= _B->v[8]; +} + +/******************************************************************************/ + +void SST_Math_Mat33iMultiplyScalar(const SST_Mat33i* RESTRICT _A, const int k, SST_Mat33i* RESTRICT _out) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_out,16); + + _out->v[0] = _A->v[0] * k; + _out->v[1] = _A->v[1] * k; + _out->v[2] = _A->v[2] * k; + _out->v[3] = _A->v[3] * k; + _out->v[4] = _A->v[4] * k; + _out->v[5] = _A->v[5] * k; + _out->v[6] = _A->v[6] * k; + _out->v[7] = _A->v[7] * k; + _out->v[8] = _A->v[8] * k; +} + +/******************************************************************************/ + +void SST_Math_Mat33iMultiplyScalarLocal(SST_Mat33i* RESTRICT _A, const int k) +{ + SST_ASSUME_ALIGNED(_A,16); + + _A->v[0] *= k; + _A->v[1] *= k; + _A->v[2] *= k; + _A->v[3] *= k; + _A->v[4] *= k; + _A->v[5] *= k; + _A->v[6] *= k; + _A->v[7] *= k; + _A->v[8] *= k; +} + +/******************************************************************************/ + + +void SST_Math_Mat33iMultiplyMatrix(const SST_Mat33i* _A, const SST_Mat33i* RESTRICT _B, SST_Mat33i* RESTRICT _out) +{ +SST_ASSUME_ALIGNED(_A,16); +SST_ASSUME_ALIGNED(_B,16); +SST_ASSUME_ALIGNED(_out,16); +_out->v[ 0] = _A->v[ 0]*_B->v[ 0]+_A->v[ 3]*_B->v[ 1]+_A->v[ 6]*_B->v[ 2]; +_out->v[ 3] = _A->v[ 0]*_B->v[ 3]+_A->v[ 3]*_B->v[ 4]+_A->v[ 6]*_B->v[ 5]; +_out->v[ 6] = _A->v[ 0]*_B->v[ 6]+_A->v[ 3]*_B->v[ 7]+_A->v[ 6]*_B->v[ 8]; +_out->v[ 1] = _A->v[ 1]*_B->v[ 0]+_A->v[ 4]*_B->v[ 1]+_A->v[ 7]*_B->v[ 2]; +_out->v[ 4] = _A->v[ 1]*_B->v[ 3]+_A->v[ 4]*_B->v[ 4]+_A->v[ 7]*_B->v[ 5]; +_out->v[ 7] = _A->v[ 1]*_B->v[ 6]+_A->v[ 4]*_B->v[ 7]+_A->v[ 7]*_B->v[ 8]; +_out->v[ 2] = _A->v[ 2]*_B->v[ 0]+_A->v[ 5]*_B->v[ 1]+_A->v[ 8]*_B->v[ 2]; +_out->v[ 5] = _A->v[ 2]*_B->v[ 3]+_A->v[ 5]*_B->v[ 4]+_A->v[ 8]*_B->v[ 5]; +_out->v[ 8] = _A->v[ 2]*_B->v[ 6]+_A->v[ 5]*_B->v[ 7]+_A->v[ 8]*_B->v[ 8]; +} +void SST_Math_Mat33iMultiplyMatrixLocal(SST_Mat33i* RESTRICT _A, const SST_Mat33i* RESTRICT _B) +{ + int tmp[9]; + SST_ASSUME_ALIGNED(_A,16); +SST_ASSUME_ALIGNED(_B,16); +tmp[ 0] = _A->v[ 0]*_B->v[ 0]+_A->v[ 3]*_B->v[ 1]+_A->v[ 6]*_B->v[ 2]; +tmp[ 3] = _A->v[ 0]*_B->v[ 3]+_A->v[ 3]*_B->v[ 4]+_A->v[ 6]*_B->v[ 5]; +tmp[ 6] = _A->v[ 0]*_B->v[ 6]+_A->v[ 3]*_B->v[ 7]+_A->v[ 6]*_B->v[ 8]; +_A->v[0] = tmp[0]; +_A->v[3] = tmp[3]; +_A->v[6] = tmp[6]; + + +tmp[ 1] = _A->v[ 1]*_B->v[ 0]+_A->v[ 4]*_B->v[ 1]+_A->v[ 7]*_B->v[ 2]; +tmp[ 4] = _A->v[ 1]*_B->v[ 3]+_A->v[ 4]*_B->v[ 4]+_A->v[ 7]*_B->v[ 5]; +tmp[ 7] = _A->v[ 1]*_B->v[ 6]+_A->v[ 4]*_B->v[ 7]+_A->v[ 7]*_B->v[ 8]; +_A->v[1] = tmp[1]; +_A->v[4] = tmp[4]; +_A->v[7] = tmp[7]; + + +tmp[ 2] = _A->v[ 2]*_B->v[ 0]+_A->v[ 5]*_B->v[ 1]+_A->v[ 8]*_B->v[ 2]; +tmp[ 5] = _A->v[ 2]*_B->v[ 3]+_A->v[ 5]*_B->v[ 4]+_A->v[ 8]*_B->v[ 5]; +tmp[ 8] = _A->v[ 2]*_B->v[ 6]+_A->v[ 5]*_B->v[ 7]+_A->v[ 8]*_B->v[ 8]; +_A->v[2] = tmp[2]; +_A->v[5] = tmp[5]; +_A->v[8] = tmp[8]; + + +} +void SST_Math_Mat33iMultiplyVector(const SST_Mat33i* RESTRICT _A, const SST_Vec3i* RESTRICT _v, SST_Vec3i* RESTRICT _out) +{ +SST_ASSUME_ALIGNED(_A,16); +SST_ASSUME_ALIGNED(_v,16); +SST_ASSUME_ALIGNED(_out,16); +_out->v[ 0] = _A->v[ 0]*_v->v[0]+_A->v[ 3]*_v->v[1]+_A->v[ 6]*_v->v[2]; +_out->v[ 1] = _A->v[ 1]*_v->v[0]+_A->v[ 4]*_v->v[1]+_A->v[ 7]*_v->v[2]; +_out->v[ 2] = _A->v[ 2]*_v->v[0]+_A->v[ 5]*_v->v[1]+_A->v[ 8]*_v->v[2]; +} +void SST_Math_Mat33iMultiplyVectorLocal(const SST_Mat33i* RESTRICT _A, SST_Vec3i* RESTRICT _v) +{ +int tmp[3]; +SST_ASSUME_ALIGNED(_A,16); +SST_ASSUME_ALIGNED(_v,16); +tmp[ 0] = _A->v[ 0]*_v->v[0]+_A->v[ 3]*_v->v[1]+_A->v[ 6]*_v->v[2]; +tmp[ 1] = _A->v[ 1]*_v->v[0]+_A->v[ 4]*_v->v[1]+_A->v[ 7]*_v->v[2]; +tmp[ 2] = _A->v[ 2]*_v->v[0]+_A->v[ 5]*_v->v[1]+_A->v[ 8]*_v->v[2]; +_v->v[0] = tmp[0]; +_v->v[1] = tmp[1]; +_v->v[2] = tmp[2]; +} +void SST_Math_Mat33iTranspose(const SST_Mat33i* RESTRICT _A, SST_Mat33i* RESTRICT _out) +{ +SST_ASSUME_ALIGNED(_A,16); +SST_ASSUME_ALIGNED(_out,16); +_out->v[ 0] = _A->v[ 0]; +_out->v[ 1] = _A->v[ 3]; +_out->v[ 2] = _A->v[ 6]; +_out->v[ 3] = _A->v[ 1]; +_out->v[ 4] = _A->v[ 4]; +_out->v[ 5] = _A->v[ 7]; +_out->v[ 6] = _A->v[ 2]; +_out->v[ 7] = _A->v[ 5]; +_out->v[ 8] = _A->v[ 8]; +} +void SST_Math_Mat33iTransposeLocal(SST_Mat33i* RESTRICT _A) +{ +int tmp[3]; +SST_ASSUME_ALIGNED(_A,16); +tmp[1] = _A->v[ 3]; +_A->v[ 3] = _A->v[ 1]; +_A->v[ 1] = tmp[1]; +tmp[2] = _A->v[ 6]; +_A->v[ 6] = _A->v[ 2]; +_A->v[ 2] = tmp[2]; +tmp[2] = _A->v[ 7]; +_A->v[ 7] = _A->v[ 5]; +_A->v[ 5] = tmp[2]; +} +bool SST_Math_Mat33iCheckOrthonormal(const SST_Mat33i* _A) +{ +const int diag = -_A->v[0]*_A->v[0] -_A->v[1]*_A->v[1] -_A->v[2]*_A->v[2] -_A->v[3]*_A->v[3] -_A->v[4]*_A->v[4] -_A->v[5]*_A->v[5] -_A->v[6]*_A->v[6] -_A->v[7]*_A->v[7] -_A->v[8]*_A->v[8]; +const int odiag = _A->v[0]*_A->v[3]+ _A->v[1]*_A->v[4]+ _A->v[2]*_A->v[5]+ _A->v[0]*_A->v[6]+ _A->v[1]*_A->v[7]+ _A->v[2]*_A->v[8]+ _A->v[3]*_A->v[0]+ _A->v[4]*_A->v[1]+ _A->v[5]*_A->v[2]+ _A->v[3]*_A->v[6]+ _A->v[4]*_A->v[7]+ _A->v[5]*_A->v[8]+ _A->v[6]*_A->v[0]+ _A->v[7]*_A->v[1]+ _A->v[8]*_A->v[2]+ _A->v[6]*_A->v[3]+ _A->v[7]*_A->v[4]+ _A->v[8]*_A->v[5]; +SST_ASSUME_ALIGNED(_A,16); +return +((abs(3+diag)) <= 100*0) & +((abs(odiag)) <= 100*0); + + +} +int SST_Math_Mat33iDeterminant(const SST_Mat33i* _A) +{ + const int result = _A->v[0]*(_A->v[4]*_A->v[8]-_A->v[5]*_A->v[7])-_A->v[1]*(_A->v[3]*_A->v[8]-_A->v[6]*_A->v[5])+_A->v[2]*(_A->v[3]*_A->v[7]-_A->v[6]*_A->v[4]); + SST_ASSUME_ALIGNED(_A,16); + return result; +} diff --git a/libsst-math/SST_Mat33i_benchmark.c b/libsst-math/SST_Mat33i_benchmark.c new file mode 100644 index 0000000..ba5deed --- /dev/null +++ b/libsst-math/SST_Mat33i_benchmark.c @@ -0,0 +1,498 @@ +#include <float.h> +#include <math.h> +#include <stdlib.h> +#include <stdio.h> +#include <assert.h> +#include <xmmintrin.h> +#include <SST/SST_Timer_x86.h> +#include <SST/SST_Mat33.h> +#include <SST/SST_Vec3.h> + + + + +int SST_Math_Mat33i_test_fxns() +{ +const int NTESTS = 10; +int i; +uint64_t t0,t1; +SST_Mat33i X; /* 3 x 3 matrix */ +SST_Mat33i Y; /* 3 x 3 matrix */ +SST_Mat33i A; /* 3 x 3 matrix */ +SST_Mat33i B; /* 3 x 3 matrix */ +SST_Vec3i v; /* 3 vector */ +SST_Vec3i w; /* 3 vector */ +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +/* Resetting test vectors / mats */ + v.v[0] = -8; + v.v[1] = 0; + v.v[2] = -2; + X.v[0] = -3; + X.v[1] = -20; + X.v[2] = 10; + X.v[3] = -9; + X.v[4] = 4; + X.v[5] = 11; + X.v[6] = 2; + X.v[7] = 16; + X.v[8] = -11; + Y.v[0] = -7; + Y.v[1] = -13; + Y.v[2] = 15; + Y.v[3] = -2; + Y.v[4] = 0; + Y.v[5] = -2; + Y.v[6] = 2; + Y.v[7] = 5; + Y.v[8] = -16; +SST_Math_Mat33iAdd(&X,&Y,&A); /* clear out the initial finding of object */ +/* Clear out the rdtsc register */ +fprintf(stdout,"SST_Math_Mat33iAdd(X,Y,A)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat33iAdd(&X,&Y,&A); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +/* +[[ -3 -9 2] + [-20 4 16] + [ 10 11 -11]] +[[ -7 -2 2] + [-13 0 5] + [ 15 -2 -16]] +[[-10 -11 4] + [-33 4 21] + [ 25 9 -27]] +*/ +assert((A.v[0])==(-10)); +assert((A.v[3])==(-11)); +assert((A.v[6])==(4)); +assert((A.v[1])==(-33)); +assert((A.v[4])==(4)); +assert((A.v[7])==(21)); +assert((A.v[2])==(25)); +assert((A.v[5])==(9)); +assert((A.v[8])==(-27)); +/* +[[ -3 -9 2] + [-20 4 16] + [ 10 11 -11]] +[[ -7 -2 2] + [-13 0 5] + [ 15 -2 -16]] +[[-10 -11 4] + [-33 4 21] + [ 25 9 -27]] +*/ +fprintf(stdout,"SST_Math_Mat33iAddLocal(A,Y)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat33iAddLocal(&A,&Y); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +SST_Math_Mat33iAddLocal(&X,&Y); /* for accuracy */ +assert((X.v[0])==(-10)); +assert((X.v[3])==(-11)); +assert((X.v[6])==(4)); +assert((X.v[1])==(-33)); +assert((X.v[4])==(4)); +assert((X.v[7])==(21)); +assert((X.v[2])==(25)); +assert((X.v[5])==(9)); +assert((X.v[8])==(-27)); +/* Resetting test vectors / mats */ + v.v[0] = -17; + v.v[1] = 18; + v.v[2] = -14; + X.v[0] = -14; + X.v[1] = 12; + X.v[2] = -13; + X.v[3] = -2; + X.v[4] = -16; + X.v[5] = -20; + X.v[6] = 6; + X.v[7] = 15; + X.v[8] = 1; + Y.v[0] = 14; + Y.v[1] = 4; + Y.v[2] = 17; + Y.v[3] = -19; + Y.v[4] = -13; + Y.v[5] = -16; + Y.v[6] = -20; + Y.v[7] = 9; + Y.v[8] = -16; +/* +[[-14 -2 6] + [ 12 -16 15] + [-13 -20 1]] +[[-28 -4 12] + [ 24 -32 30] + [-26 -40 2]] +*/ +fprintf(stdout,"SST_Math_Mat33iMultiplyScalar(X,t,Y)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat33iMultiplyScalar(&X,2,&A); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +assert((A.v[0])==(-28)); +assert((A.v[3])==(-4)); +assert((A.v[6])==(12)); +assert((A.v[1])==(24)); +assert((A.v[4])==(-32)); +assert((A.v[7])==(30)); +assert((A.v[2])==(-26)); +assert((A.v[5])==(-40)); +assert((A.v[8])==(2)); +/* +[[-14 -2 6] + [ 12 -16 15] + [-13 -20 1]] +[[-28 -4 12] + [ 24 -32 30] + [-26 -40 2]] +*/ +fprintf(stdout,"SST_Math_Mat33iMultiplyScalarLocal(A,t)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat33iMultiplyScalarLocal(&A,2); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +SST_Math_Mat33iMultiplyScalarLocal(&X,2); +assert((X.v[0])==(-28)); +assert((X.v[3])==(-4)); +assert((X.v[6])==(12)); +assert((X.v[1])==(24)); +assert((X.v[4])==(-32)); +assert((X.v[7])==(30)); +assert((X.v[2])==(-26)); +assert((X.v[5])==(-40)); +assert((X.v[8])==(2)); +/* Resetting test vectors / mats */ + v.v[0] = -8; + v.v[1] = 1; + v.v[2] = 13; + X.v[0] = -7; + X.v[1] = 14; + X.v[2] = 9; + X.v[3] = 12; + X.v[4] = -5; + X.v[5] = -11; + X.v[6] = -1; + X.v[7] = -13; + X.v[8] = 0; + Y.v[0] = 12; + Y.v[1] = -3; + Y.v[2] = 15; + Y.v[3] = 16; + Y.v[4] = 7; + Y.v[5] = -9; + Y.v[6] = -11; + Y.v[7] = 16; + Y.v[8] = 7; +/* +[[ -7 12 -1] + [ 14 -5 -13] + [ 9 -11 0]] +[[ 12 16 -11] + [ -3 7 16] + [ 15 -9 7]] +[[ -84 192 11] + [ -42 -35 -208] + [ 135 99 0]] +*/ +fprintf(stdout,"SST_Math_Mat33iMultiplyElementwise(X,Y,A)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat33iMultiplyElementwise(&X, &Y, &A); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +assert((A.v[0])==(-84)); +assert((A.v[3])==(192)); +assert((A.v[6])==(11)); +assert((A.v[1])==(-42)); +assert((A.v[4])==(-35)); +assert((A.v[7])==(-208)); +assert((A.v[2])==(135)); +assert((A.v[5])==(99)); +assert((A.v[8])==(0)); +/* +[[ -7 12 -1] + [ 14 -5 -13] + [ 9 -11 0]] +[[ 12 16 -11] + [ -3 7 16] + [ 15 -9 7]] +[[ -84 192 11] + [ -42 -35 -208] + [ 135 99 0]] +*/ +fprintf(stdout,"SST_Math_Mat33iMultiplyElementwiseLocal(X,Y)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat33iMultiplyElementwiseLocal(&A,&Y); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +SST_Math_Mat33iMultiplyElementwiseLocal(&X,&Y); +assert((X.v[0])==(-84)); +assert((X.v[3])==(192)); +assert((X.v[6])==(11)); +assert((X.v[1])==(-42)); +assert((X.v[4])==(-35)); +assert((X.v[7])==(-208)); +assert((X.v[2])==(135)); +assert((X.v[5])==(99)); +assert((X.v[8])==(0)); +/* Resetting test vectors / mats */ + v.v[0] = -5; + v.v[1] = -6; + v.v[2] = -12; + X.v[0] = -14; + X.v[1] = 15; + X.v[2] = -10; + X.v[3] = -14; + X.v[4] = -20; + X.v[5] = -9; + X.v[6] = -11; + X.v[7] = -1; + X.v[8] = 18; + Y.v[0] = -18; + Y.v[1] = 19; + Y.v[2] = 3; + Y.v[3] = -8; + Y.v[4] = 16; + Y.v[5] = 12; + Y.v[6] = 19; + Y.v[7] = -10; + Y.v[8] = -3; +/* +X +[[-14 -14 -11] + [ 15 -20 -1] + [-10 -9 18]] +Y +[[-18 -8 19] + [ 19 16 -10] + [ 3 12 -3]] +[[ -47 -244 -93] + [-653 -452 488] + [ 63 152 -154]] +*/ +fprintf(stdout,"SST_Math_Mat33iMultiplyMatrix(X,Y,A)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat33iMultiplyMatrix(&X,&Y,&A); +t1 = rdtsc(); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +assert((A.v[0])==(-47)); +assert((A.v[3])==(-244)); +assert((A.v[6])==(-93)); +assert((A.v[1])==(-653)); +assert((A.v[4])==(-452)); +assert((A.v[7])==(488)); +assert((A.v[2])==(63)); +assert((A.v[5])==(152)); +assert((A.v[8])==(-154)); +/* +X +[[-14 -14 -11] + [ 15 -20 -1] + [-10 -9 18]] +Y +[[-18 -8 19] + [ 19 16 -10] + [ 3 12 -3]] +X +[[ -47 -244 -93] + [-653 -452 488] + [ 63 152 -154]] +*/ +fprintf(stdout,"SST_Math_Mat33iMultiplyMatrixLocal(X,Y)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat33iMultiplyMatrixLocal(&A,&Y); +t1 = rdtsc(); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +SST_Math_Mat33iMultiplyMatrixLocal(&X,&Y); +assert((X.v[0])==(-47)); +assert((X.v[3])==(-244)); +assert((X.v[6])==(-93)); +assert((X.v[1])==(-653)); +assert((X.v[4])==(-452)); +assert((X.v[7])==(488)); +assert((X.v[2])==(63)); +assert((X.v[5])==(152)); +assert((X.v[8])==(-154)); +/* Resetting test vectors / mats */ + v.v[0] = 9; + v.v[1] = 13; + v.v[2] = -11; + X.v[0] = 2; + X.v[1] = -4; + X.v[2] = 13; + X.v[3] = -1; + X.v[4] = 13; + X.v[5] = 1; + X.v[6] = -7; + X.v[7] = 3; + X.v[8] = 11; + Y.v[0] = -9; + Y.v[1] = -8; + Y.v[2] = 3; + Y.v[3] = -1; + Y.v[4] = -4; + Y.v[5] = 9; + Y.v[6] = 15; + Y.v[7] = 9; + Y.v[8] = -16; +/* +X +[[ 2 -1 -7] + [-4 13 3] + [13 1 11]] +v +[ 9 13 -11] +w +[ 82 100 9] +*/ +i=0; +fprintf(stdout,"SST_Math_Mat33iMultiplyVector(X,v,w)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat33iMultiplyVector(&X,&v,&w); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +assert((w.v[0])==(82)); +assert((w.v[1])==(100)); +assert((w.v[2])==(9)); +/* +X +[[ 2 -1 -7] + [-4 13 3] + [13 1 11]] +v +[ 9 13 -11] +v +[ 82 100 9] +*/ +fprintf(stdout,"SST_Math_Mat33iMultiplyVectorLocal(X,v)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat33iMultiplyVectorLocal(&X,&w); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +SST_Math_Mat33iMultiplyVectorLocal(&X,&v); +assert((v.v[0])==(82)); +assert((v.v[1])==(100)); +assert((v.v[2])==(9)); +/* Resetting test vectors / mats */ + v.v[0] = 17; + v.v[1] = 3; + v.v[2] = 4; + X.v[0] = -9; + X.v[1] = 17; + X.v[2] = 2; + X.v[3] = -14; + X.v[4] = -12; + X.v[5] = 16; + X.v[6] = -3; + X.v[7] = -2; + X.v[8] = -20; + Y.v[0] = 5; + Y.v[1] = 17; + Y.v[2] = 7; + Y.v[3] = -12; + Y.v[4] = -16; + Y.v[5] = 0; + Y.v[6] = 13; + Y.v[7] = 16; + Y.v[8] = -17; +fprintf(stdout,"SST_Math_Mat33iTranspose(X,A)"); +t0 = rdtsc(); +SST_Math_Mat33iTranspose(&X,&A); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +assert((A.v[0])==(-9)); +assert((A.v[3])==(17)); +assert((A.v[6])==(2)); +assert((A.v[1])==(-14)); +assert((A.v[4])==(-12)); +assert((A.v[7])==(16)); +assert((A.v[2])==(-3)); +assert((A.v[5])==(-2)); +assert((A.v[8])==(-20)); +fprintf(stdout,"SST_Math_Mat33iTransposeLocal(X)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat33iTransposeLocal(&A); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +SST_Math_Mat33iTransposeLocal(&X); +assert((X.v[0])==(-9)); +assert((X.v[3])==(17)); +assert((X.v[6])==(2)); +assert((X.v[1])==(-14)); +assert((X.v[4])==(-12)); +assert((X.v[7])==(16)); +assert((X.v[2])==(-3)); +assert((X.v[5])==(-2)); +assert((X.v[8])==(-20)); +/* +[[-0.46537892 -0.62176306 0.62994695] + [ 0.87904907 -0.40783255 0.2468711 ] + [ 0.10341754 0.66864289 0.73635691]] +[[ 1.00000000e+00 8.32667268e-17 -1.11022302e-16] + [ 8.32667268e-17 1.00000000e+00 -5.55111512e-17] + [ -1.11022302e-16 -5.55111512e-17 1.00000000e+00]] +*/ +X.v[0] = (int)0; +X.v[3] = (int)0; +X.v[6] = (int)0; +X.v[1] = (int)0; +X.v[4] = (int)0; +X.v[7] = (int)0; +X.v[2] = (int)0; +X.v[5] = (int)0; +X.v[8] = (int)0; +fprintf(stdout,"SST_Math_Mat33iTranspose(X,A)"); +t0 = rdtsc(); +SST_Math_Mat33iTranspose(&X,&A); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +fprintf(stdout,"SST_Math_Mat33iMultiplyMatrix(A,X,B)"); +t0 = rdtsc(); +SST_Math_Mat33iMultiplyMatrix(&A,&X,&B); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +/* Check Positive Test */ +assert(SST_Math_Mat33iCheckOrthonormal(&X)); +/* Check Negative Test */ +assert(!SST_Math_Mat33iCheckOrthonormal(&Y)); +fprintf(stdout,"\n==== SST_Math_Mat33itest_fxn COMPLETE ====\n"); +return 0; +} diff --git a/libsst-math/SST_Mat33u.c b/libsst-math/SST_Mat33u.c new file mode 100644 index 0000000..9a993f0 --- /dev/null +++ b/libsst-math/SST_Mat33u.c @@ -0,0 +1,256 @@ +/* + AUTOMATICALLY GENERATED FILE - DO NOT EDIT! + Please change MatrixNxN.py and re-run it +*/ +/* Generated with ./MatrixNxN.py n = 3, TYPE = unsigned int */ + +#include <float.h> +#include <pstdbool.h> +#include <stdio.h> +#include <math.h> /* for sqrt functions */ +#include <stdlib.h> /* for the abs/labs functions */ +#include <SST/SST_Build.h> + +#include <SST/SST_Mat33.h> +#include <SST/SST_Vec3.h> +void SST_Math_Mat33uAdd(const SST_Mat33u* RESTRICT _A, const SST_Mat33u* RESTRICT _B, SST_Mat33u* RESTRICT _out) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + SST_ASSUME_ALIGNED(_out,16); + + _out->v[0] = _A->v[0] + _B->v[0]; + _out->v[1] = _A->v[1] + _B->v[1]; + _out->v[2] = _A->v[2] + _B->v[2]; + _out->v[3] = _A->v[3] + _B->v[3]; + _out->v[4] = _A->v[4] + _B->v[4]; + _out->v[5] = _A->v[5] + _B->v[5]; + _out->v[6] = _A->v[6] + _B->v[6]; + _out->v[7] = _A->v[7] + _B->v[7]; + _out->v[8] = _A->v[8] + _B->v[8]; +} + +/******************************************************************************/ + +void SST_Math_Mat33uAddLocal(SST_Mat33u* RESTRICT _A, const SST_Mat33u* RESTRICT _B) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + + _A->v[0] += _B->v[0]; + _A->v[1] += _B->v[1]; + _A->v[2] += _B->v[2]; + _A->v[3] += _B->v[3]; + _A->v[4] += _B->v[4]; + _A->v[5] += _B->v[5]; + _A->v[6] += _B->v[6]; + _A->v[7] += _B->v[7]; + _A->v[8] += _B->v[8]; +} + +/******************************************************************************/ + +void SST_Math_Mat33uSubtract(const SST_Mat33u* RESTRICT _A, const SST_Mat33u* RESTRICT _B, SST_Mat33u* RESTRICT _out) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + SST_ASSUME_ALIGNED(_out,16); + + _out->v[0] = _A->v[0] - _B->v[0]; + _out->v[1] = _A->v[1] - _B->v[1]; + _out->v[2] = _A->v[2] - _B->v[2]; + _out->v[3] = _A->v[3] - _B->v[3]; + _out->v[4] = _A->v[4] - _B->v[4]; + _out->v[5] = _A->v[5] - _B->v[5]; + _out->v[6] = _A->v[6] - _B->v[6]; + _out->v[7] = _A->v[7] - _B->v[7]; + _out->v[8] = _A->v[8] - _B->v[8]; +} + +/******************************************************************************/ + +void SST_Math_Mat33uSubtractLocal(SST_Mat33u* RESTRICT _A, const SST_Mat33u* RESTRICT _B) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + + _A->v[0] -= _B->v[0]; + _A->v[1] -= _B->v[1]; + _A->v[2] -= _B->v[2]; + _A->v[3] -= _B->v[3]; + _A->v[4] -= _B->v[4]; + _A->v[5] -= _B->v[5]; + _A->v[6] -= _B->v[6]; + _A->v[7] -= _B->v[7]; + _A->v[8] -= _B->v[8]; +} + +/******************************************************************************/ + +void SST_Math_Mat33uMultiplyElementwise(const SST_Mat33u* RESTRICT _A, const SST_Mat33u* RESTRICT _B, SST_Mat33u* RESTRICT _out) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + SST_ASSUME_ALIGNED(_out,16); + + _out->v[0] = _A->v[0] * _B->v[0]; + _out->v[1] = _A->v[1] * _B->v[1]; + _out->v[2] = _A->v[2] * _B->v[2]; + _out->v[3] = _A->v[3] * _B->v[3]; + _out->v[4] = _A->v[4] * _B->v[4]; + _out->v[5] = _A->v[5] * _B->v[5]; + _out->v[6] = _A->v[6] * _B->v[6]; + _out->v[7] = _A->v[7] * _B->v[7]; + _out->v[8] = _A->v[8] * _B->v[8]; +} + +/******************************************************************************/ + +void SST_Math_Mat33uMultiplyElementwiseLocal(SST_Mat33u* RESTRICT _A, const SST_Mat33u* RESTRICT _B) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + + _A->v[0] *= _B->v[0]; + _A->v[1] *= _B->v[1]; + _A->v[2] *= _B->v[2]; + _A->v[3] *= _B->v[3]; + _A->v[4] *= _B->v[4]; + _A->v[5] *= _B->v[5]; + _A->v[6] *= _B->v[6]; + _A->v[7] *= _B->v[7]; + _A->v[8] *= _B->v[8]; +} + +/******************************************************************************/ + +void SST_Math_Mat33uMultiplyScalar(const SST_Mat33u* RESTRICT _A, const unsigned int k, SST_Mat33u* RESTRICT _out) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_out,16); + + _out->v[0] = _A->v[0] * k; + _out->v[1] = _A->v[1] * k; + _out->v[2] = _A->v[2] * k; + _out->v[3] = _A->v[3] * k; + _out->v[4] = _A->v[4] * k; + _out->v[5] = _A->v[5] * k; + _out->v[6] = _A->v[6] * k; + _out->v[7] = _A->v[7] * k; + _out->v[8] = _A->v[8] * k; +} + +/******************************************************************************/ + +void SST_Math_Mat33uMultiplyScalarLocal(SST_Mat33u* RESTRICT _A, const unsigned int k) +{ + SST_ASSUME_ALIGNED(_A,16); + + _A->v[0] *= k; + _A->v[1] *= k; + _A->v[2] *= k; + _A->v[3] *= k; + _A->v[4] *= k; + _A->v[5] *= k; + _A->v[6] *= k; + _A->v[7] *= k; + _A->v[8] *= k; +} + +/******************************************************************************/ + + +void SST_Math_Mat33uMultiplyMatrix(const SST_Mat33u* _A, const SST_Mat33u* RESTRICT _B, SST_Mat33u* RESTRICT _out) +{ +SST_ASSUME_ALIGNED(_A,16); +SST_ASSUME_ALIGNED(_B,16); +SST_ASSUME_ALIGNED(_out,16); +_out->v[ 0] = _A->v[ 0]*_B->v[ 0]+_A->v[ 3]*_B->v[ 1]+_A->v[ 6]*_B->v[ 2]; +_out->v[ 3] = _A->v[ 0]*_B->v[ 3]+_A->v[ 3]*_B->v[ 4]+_A->v[ 6]*_B->v[ 5]; +_out->v[ 6] = _A->v[ 0]*_B->v[ 6]+_A->v[ 3]*_B->v[ 7]+_A->v[ 6]*_B->v[ 8]; +_out->v[ 1] = _A->v[ 1]*_B->v[ 0]+_A->v[ 4]*_B->v[ 1]+_A->v[ 7]*_B->v[ 2]; +_out->v[ 4] = _A->v[ 1]*_B->v[ 3]+_A->v[ 4]*_B->v[ 4]+_A->v[ 7]*_B->v[ 5]; +_out->v[ 7] = _A->v[ 1]*_B->v[ 6]+_A->v[ 4]*_B->v[ 7]+_A->v[ 7]*_B->v[ 8]; +_out->v[ 2] = _A->v[ 2]*_B->v[ 0]+_A->v[ 5]*_B->v[ 1]+_A->v[ 8]*_B->v[ 2]; +_out->v[ 5] = _A->v[ 2]*_B->v[ 3]+_A->v[ 5]*_B->v[ 4]+_A->v[ 8]*_B->v[ 5]; +_out->v[ 8] = _A->v[ 2]*_B->v[ 6]+_A->v[ 5]*_B->v[ 7]+_A->v[ 8]*_B->v[ 8]; +} +void SST_Math_Mat33uMultiplyMatrixLocal(SST_Mat33u* RESTRICT _A, const SST_Mat33u* RESTRICT _B) +{ + unsigned int tmp[9]; + SST_ASSUME_ALIGNED(_A,16); +SST_ASSUME_ALIGNED(_B,16); +tmp[ 0] = _A->v[ 0]*_B->v[ 0]+_A->v[ 3]*_B->v[ 1]+_A->v[ 6]*_B->v[ 2]; +tmp[ 3] = _A->v[ 0]*_B->v[ 3]+_A->v[ 3]*_B->v[ 4]+_A->v[ 6]*_B->v[ 5]; +tmp[ 6] = _A->v[ 0]*_B->v[ 6]+_A->v[ 3]*_B->v[ 7]+_A->v[ 6]*_B->v[ 8]; +_A->v[0] = tmp[0]; +_A->v[3] = tmp[3]; +_A->v[6] = tmp[6]; + + +tmp[ 1] = _A->v[ 1]*_B->v[ 0]+_A->v[ 4]*_B->v[ 1]+_A->v[ 7]*_B->v[ 2]; +tmp[ 4] = _A->v[ 1]*_B->v[ 3]+_A->v[ 4]*_B->v[ 4]+_A->v[ 7]*_B->v[ 5]; +tmp[ 7] = _A->v[ 1]*_B->v[ 6]+_A->v[ 4]*_B->v[ 7]+_A->v[ 7]*_B->v[ 8]; +_A->v[1] = tmp[1]; +_A->v[4] = tmp[4]; +_A->v[7] = tmp[7]; + + +tmp[ 2] = _A->v[ 2]*_B->v[ 0]+_A->v[ 5]*_B->v[ 1]+_A->v[ 8]*_B->v[ 2]; +tmp[ 5] = _A->v[ 2]*_B->v[ 3]+_A->v[ 5]*_B->v[ 4]+_A->v[ 8]*_B->v[ 5]; +tmp[ 8] = _A->v[ 2]*_B->v[ 6]+_A->v[ 5]*_B->v[ 7]+_A->v[ 8]*_B->v[ 8]; +_A->v[2] = tmp[2]; +_A->v[5] = tmp[5]; +_A->v[8] = tmp[8]; + + +} +void SST_Math_Mat33uMultiplyVector(const SST_Mat33u* RESTRICT _A, const SST_Vec3u* RESTRICT _v, SST_Vec3u* RESTRICT _out) +{ +SST_ASSUME_ALIGNED(_A,16); +SST_ASSUME_ALIGNED(_v,16); +SST_ASSUME_ALIGNED(_out,16); +_out->v[ 0] = _A->v[ 0]*_v->v[0]+_A->v[ 3]*_v->v[1]+_A->v[ 6]*_v->v[2]; +_out->v[ 1] = _A->v[ 1]*_v->v[0]+_A->v[ 4]*_v->v[1]+_A->v[ 7]*_v->v[2]; +_out->v[ 2] = _A->v[ 2]*_v->v[0]+_A->v[ 5]*_v->v[1]+_A->v[ 8]*_v->v[2]; +} +void SST_Math_Mat33uMultiplyVectorLocal(const SST_Mat33u* RESTRICT _A, SST_Vec3u* RESTRICT _v) +{ +unsigned int tmp[3]; +SST_ASSUME_ALIGNED(_A,16); +SST_ASSUME_ALIGNED(_v,16); +tmp[ 0] = _A->v[ 0]*_v->v[0]+_A->v[ 3]*_v->v[1]+_A->v[ 6]*_v->v[2]; +tmp[ 1] = _A->v[ 1]*_v->v[0]+_A->v[ 4]*_v->v[1]+_A->v[ 7]*_v->v[2]; +tmp[ 2] = _A->v[ 2]*_v->v[0]+_A->v[ 5]*_v->v[1]+_A->v[ 8]*_v->v[2]; +_v->v[0] = tmp[0]; +_v->v[1] = tmp[1]; +_v->v[2] = tmp[2]; +} +void SST_Math_Mat33uTranspose(const SST_Mat33u* RESTRICT _A, SST_Mat33u* RESTRICT _out) +{ +SST_ASSUME_ALIGNED(_A,16); +SST_ASSUME_ALIGNED(_out,16); +_out->v[ 0] = _A->v[ 0]; +_out->v[ 1] = _A->v[ 3]; +_out->v[ 2] = _A->v[ 6]; +_out->v[ 3] = _A->v[ 1]; +_out->v[ 4] = _A->v[ 4]; +_out->v[ 5] = _A->v[ 7]; +_out->v[ 6] = _A->v[ 2]; +_out->v[ 7] = _A->v[ 5]; +_out->v[ 8] = _A->v[ 8]; +} +void SST_Math_Mat33uTransposeLocal(SST_Mat33u* RESTRICT _A) +{ +unsigned int tmp[3]; +SST_ASSUME_ALIGNED(_A,16); +tmp[1] = _A->v[ 3]; +_A->v[ 3] = _A->v[ 1]; +_A->v[ 1] = tmp[1]; +tmp[2] = _A->v[ 6]; +_A->v[ 6] = _A->v[ 2]; +_A->v[ 2] = tmp[2]; +tmp[2] = _A->v[ 7]; +_A->v[ 7] = _A->v[ 5]; +_A->v[ 5] = tmp[2]; +} diff --git a/libsst-math/SST_Mat33u_benchmark.c b/libsst-math/SST_Mat33u_benchmark.c new file mode 100644 index 0000000..cfbd016 --- /dev/null +++ b/libsst-math/SST_Mat33u_benchmark.c @@ -0,0 +1,494 @@ +#include <float.h> +#include <math.h> +#include <stdlib.h> +#include <stdio.h> +#include <assert.h> +#include <xmmintrin.h> +#include <SST/SST_Timer_x86.h> +#include <SST/SST_Mat33.h> +#include <SST/SST_Vec3.h> + + + + +int SST_Math_Mat33u_test_fxns() +{ +const int NTESTS = 10; +int i; +uint64_t t0,t1; +SST_Mat33u X; /* 3 x 3 matrix */ +SST_Mat33u Y; /* 3 x 3 matrix */ +SST_Mat33u A; /* 3 x 3 matrix */ +SST_Mat33u B; /* 3 x 3 matrix */ +SST_Vec3u v; /* 3 vector */ +SST_Vec3u w; /* 3 vector */ +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +/* Resetting test vectors / mats */ + v.v[0] = 28; + v.v[1] = 0; + v.v[2] = 25; + X.v[0] = 37; + X.v[1] = 35; + X.v[2] = 27; + X.v[3] = 16; + X.v[4] = 34; + X.v[5] = 18; + X.v[6] = 29; + X.v[7] = 15; + X.v[8] = 26; + Y.v[0] = 4; + Y.v[1] = 19; + Y.v[2] = 4; + Y.v[3] = 9; + Y.v[4] = 19; + Y.v[5] = 35; + Y.v[6] = 5; + Y.v[7] = 6; + Y.v[8] = 15; +SST_Math_Mat33uAdd(&X,&Y,&A); /* clear out the initial finding of object */ +/* Clear out the rdtsc register */ +fprintf(stdout,"SST_Math_Mat33uAdd(X,Y,A)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat33uAdd(&X,&Y,&A); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +/* +[[37 16 29] + [35 34 15] + [27 18 26]] +[[ 4 9 5] + [19 19 6] + [ 4 35 15]] +[[41 25 34] + [54 53 21] + [31 53 41]] +*/ +assert((A.v[0])==(41)); +assert((A.v[3])==(25)); +assert((A.v[6])==(34)); +assert((A.v[1])==(54)); +assert((A.v[4])==(53)); +assert((A.v[7])==(21)); +assert((A.v[2])==(31)); +assert((A.v[5])==(53)); +assert((A.v[8])==(41)); +/* +[[37 16 29] + [35 34 15] + [27 18 26]] +[[ 4 9 5] + [19 19 6] + [ 4 35 15]] +[[41 25 34] + [54 53 21] + [31 53 41]] +*/ +fprintf(stdout,"SST_Math_Mat33uAddLocal(A,Y)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat33uAddLocal(&A,&Y); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +SST_Math_Mat33uAddLocal(&X,&Y); /* for accuracy */ +assert((X.v[0])==(41)); +assert((X.v[3])==(25)); +assert((X.v[6])==(34)); +assert((X.v[1])==(54)); +assert((X.v[4])==(53)); +assert((X.v[7])==(21)); +assert((X.v[2])==(31)); +assert((X.v[5])==(53)); +assert((X.v[8])==(41)); +/* Resetting test vectors / mats */ + v.v[0] = 31; + v.v[1] = 21; + v.v[2] = 22; + X.v[0] = 0; + X.v[1] = 11; + X.v[2] = 3; + X.v[3] = 35; + X.v[4] = 25; + X.v[5] = 31; + X.v[6] = 15; + X.v[7] = 14; + X.v[8] = 33; + Y.v[0] = 32; + Y.v[1] = 23; + Y.v[2] = 23; + Y.v[3] = 35; + Y.v[4] = 2; + Y.v[5] = 31; + Y.v[6] = 31; + Y.v[7] = 2; + Y.v[8] = 8; +/* +[[ 0 35 15] + [11 25 14] + [ 3 31 33]] +[[ 0 70 30] + [22 50 28] + [ 6 62 66]] +*/ +fprintf(stdout,"SST_Math_Mat33uMultiplyScalar(X,t,Y)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat33uMultiplyScalar(&X,2,&A); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +assert((A.v[0])==(0)); +assert((A.v[3])==(70)); +assert((A.v[6])==(30)); +assert((A.v[1])==(22)); +assert((A.v[4])==(50)); +assert((A.v[7])==(28)); +assert((A.v[2])==(6)); +assert((A.v[5])==(62)); +assert((A.v[8])==(66)); +/* +[[ 0 35 15] + [11 25 14] + [ 3 31 33]] +[[ 0 70 30] + [22 50 28] + [ 6 62 66]] +*/ +fprintf(stdout,"SST_Math_Mat33uMultiplyScalarLocal(A,t)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat33uMultiplyScalarLocal(&A,2); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +SST_Math_Mat33uMultiplyScalarLocal(&X,2); +assert((X.v[0])==(0)); +assert((X.v[3])==(70)); +assert((X.v[6])==(30)); +assert((X.v[1])==(22)); +assert((X.v[4])==(50)); +assert((X.v[7])==(28)); +assert((X.v[2])==(6)); +assert((X.v[5])==(62)); +assert((X.v[8])==(66)); +/* Resetting test vectors / mats */ + v.v[0] = 1; + v.v[1] = 19; + v.v[2] = 20; + X.v[0] = 22; + X.v[1] = 25; + X.v[2] = 21; + X.v[3] = 28; + X.v[4] = 13; + X.v[5] = 7; + X.v[6] = 14; + X.v[7] = 5; + X.v[8] = 26; + Y.v[0] = 28; + Y.v[1] = 35; + Y.v[2] = 21; + Y.v[3] = 11; + Y.v[4] = 29; + Y.v[5] = 0; + Y.v[6] = 13; + Y.v[7] = 31; + Y.v[8] = 9; +/* +[[22 28 14] + [25 13 5] + [21 7 26]] +[[28 11 13] + [35 29 31] + [21 0 9]] +[[616 308 182] + [875 377 155] + [441 0 234]] +*/ +fprintf(stdout,"SST_Math_Mat33uMultiplyElementwise(X,Y,A)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat33uMultiplyElementwise(&X, &Y, &A); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +assert((A.v[0])==(616)); +assert((A.v[3])==(308)); +assert((A.v[6])==(182)); +assert((A.v[1])==(875)); +assert((A.v[4])==(377)); +assert((A.v[7])==(155)); +assert((A.v[2])==(441)); +assert((A.v[5])==(0)); +assert((A.v[8])==(234)); +/* +[[22 28 14] + [25 13 5] + [21 7 26]] +[[28 11 13] + [35 29 31] + [21 0 9]] +[[616 308 182] + [875 377 155] + [441 0 234]] +*/ +fprintf(stdout,"SST_Math_Mat33uMultiplyElementwiseLocal(X,Y)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat33uMultiplyElementwiseLocal(&A,&Y); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +SST_Math_Mat33uMultiplyElementwiseLocal(&X,&Y); +assert((X.v[0])==(616)); +assert((X.v[3])==(308)); +assert((X.v[6])==(182)); +assert((X.v[1])==(875)); +assert((X.v[4])==(377)); +assert((X.v[7])==(155)); +assert((X.v[2])==(441)); +assert((X.v[5])==(0)); +assert((X.v[8])==(234)); +/* Resetting test vectors / mats */ + v.v[0] = 15; + v.v[1] = 31; + v.v[2] = 26; + X.v[0] = 34; + X.v[1] = 10; + X.v[2] = 36; + X.v[3] = 34; + X.v[4] = 20; + X.v[5] = 13; + X.v[6] = 27; + X.v[7] = 36; + X.v[8] = 35; + Y.v[0] = 31; + Y.v[1] = 39; + Y.v[2] = 18; + Y.v[3] = 23; + Y.v[4] = 6; + Y.v[5] = 10; + Y.v[6] = 22; + Y.v[7] = 24; + Y.v[8] = 37; +/* +X +[[34 34 27] + [10 20 36] + [36 13 35]] +Y +[[31 23 22] + [39 6 24] + [18 10 37]] +[[2866 1256 2563] + [1738 710 2032] + [2253 1256 2399]] +*/ +fprintf(stdout,"SST_Math_Mat33uMultiplyMatrix(X,Y,A)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat33uMultiplyMatrix(&X,&Y,&A); +t1 = rdtsc(); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +assert((A.v[0])==(2866)); +assert((A.v[3])==(1256)); +assert((A.v[6])==(2563)); +assert((A.v[1])==(1738)); +assert((A.v[4])==(710)); +assert((A.v[7])==(2032)); +assert((A.v[2])==(2253)); +assert((A.v[5])==(1256)); +assert((A.v[8])==(2399)); +/* +X +[[34 34 27] + [10 20 36] + [36 13 35]] +Y +[[31 23 22] + [39 6 24] + [18 10 37]] +X +[[2866 1256 2563] + [1738 710 2032] + [2253 1256 2399]] +*/ +fprintf(stdout,"SST_Math_Mat33uMultiplyMatrixLocal(X,Y)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat33uMultiplyMatrixLocal(&A,&Y); +t1 = rdtsc(); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +SST_Math_Mat33uMultiplyMatrixLocal(&X,&Y); +assert((X.v[0])==(2866)); +assert((X.v[3])==(1256)); +assert((X.v[6])==(2563)); +assert((X.v[1])==(1738)); +assert((X.v[4])==(710)); +assert((X.v[7])==(2032)); +assert((X.v[2])==(2253)); +assert((X.v[5])==(1256)); +assert((X.v[8])==(2399)); +/* Resetting test vectors / mats */ + v.v[0] = 15; + v.v[1] = 30; + v.v[2] = 18; + X.v[0] = 15; + X.v[1] = 36; + X.v[2] = 12; + X.v[3] = 1; + X.v[4] = 3; + X.v[5] = 22; + X.v[6] = 13; + X.v[7] = 15; + X.v[8] = 13; + Y.v[0] = 33; + Y.v[1] = 38; + Y.v[2] = 32; + Y.v[3] = 13; + Y.v[4] = 28; + Y.v[5] = 7; + Y.v[6] = 39; + Y.v[7] = 8; + Y.v[8] = 32; +/* +X +[[15 1 13] + [36 3 15] + [12 22 13]] +v +[15 30 18] +w +[ 489 900 1074] +*/ +i=0; +fprintf(stdout,"SST_Math_Mat33uMultiplyVector(X,v,w)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat33uMultiplyVector(&X,&v,&w); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +assert((w.v[0])==(489)); +assert((w.v[1])==(900)); +assert((w.v[2])==(1074)); +/* +X +[[15 1 13] + [36 3 15] + [12 22 13]] +v +[15 30 18] +v +[ 489 900 1074] +*/ +fprintf(stdout,"SST_Math_Mat33uMultiplyVectorLocal(X,v)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat33uMultiplyVectorLocal(&X,&w); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +SST_Math_Mat33uMultiplyVectorLocal(&X,&v); +assert((v.v[0])==(489)); +assert((v.v[1])==(900)); +assert((v.v[2])==(1074)); +/* Resetting test vectors / mats */ + v.v[0] = 24; + v.v[1] = 36; + v.v[2] = 2; + X.v[0] = 34; + X.v[1] = 19; + X.v[2] = 4; + X.v[3] = 22; + X.v[4] = 9; + X.v[5] = 14; + X.v[6] = 29; + X.v[7] = 25; + X.v[8] = 32; + Y.v[0] = 5; + Y.v[1] = 6; + Y.v[2] = 26; + Y.v[3] = 22; + Y.v[4] = 22; + Y.v[5] = 32; + Y.v[6] = 36; + Y.v[7] = 9; + Y.v[8] = 16; +fprintf(stdout,"SST_Math_Mat33uTranspose(X,A)"); +t0 = rdtsc(); +SST_Math_Mat33uTranspose(&X,&A); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +assert((A.v[0])==(34)); +assert((A.v[3])==(19)); +assert((A.v[6])==(4)); +assert((A.v[1])==(22)); +assert((A.v[4])==(9)); +assert((A.v[7])==(14)); +assert((A.v[2])==(29)); +assert((A.v[5])==(25)); +assert((A.v[8])==(32)); +fprintf(stdout,"SST_Math_Mat33uTransposeLocal(X)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat33uTransposeLocal(&A); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +SST_Math_Mat33uTransposeLocal(&X); +assert((X.v[0])==(34)); +assert((X.v[3])==(19)); +assert((X.v[6])==(4)); +assert((X.v[1])==(22)); +assert((X.v[4])==(9)); +assert((X.v[7])==(14)); +assert((X.v[2])==(29)); +assert((X.v[5])==(25)); +assert((X.v[8])==(32)); +/* +[[-0.86837606 0.03165458 -0.49489495] + [-0.48526897 -0.25983137 0.83486627] + [-0.10216189 0.96513504 0.24099232]] +[[ 1.00000000e+00 0.00000000e+00 -7.63278329e-17] + [ 0.00000000e+00 1.00000000e+00 1.11022302e-16] + [ -7.63278329e-17 1.11022302e-16 1.00000000e+00]] +*/ +X.v[0] = (unsigned int)0; +X.v[3] = (unsigned int)0; +X.v[6] = (unsigned int)0; +X.v[1] = (unsigned int)0; +X.v[4] = (unsigned int)0; +X.v[7] = (unsigned int)0; +X.v[2] = (unsigned int)0; +X.v[5] = (unsigned int)0; +X.v[8] = (unsigned int)0; +fprintf(stdout,"SST_Math_Mat33uTranspose(X,A)"); +t0 = rdtsc(); +SST_Math_Mat33uTranspose(&X,&A); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +fprintf(stdout,"SST_Math_Mat33uMultiplyMatrix(A,X,B)"); +t0 = rdtsc(); +SST_Math_Mat33uMultiplyMatrix(&A,&X,&B); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +fprintf(stdout,"\n==== SST_Math_Mat33utest_fxn COMPLETE ====\n"); +return 0; +} diff --git a/libsst-math/SST_Mat44d.c b/libsst-math/SST_Mat44d.c new file mode 100644 index 0000000..45143c4 --- /dev/null +++ b/libsst-math/SST_Mat44d.c @@ -0,0 +1,946 @@ +/* + AUTOMATICALLY GENERATED FILE - DO NOT EDIT! + Please change MatrixNxN.py and re-run it +*/ +/* Generated with ./MatrixNxN.py n = 4, TYPE = double */ + +#include <float.h> +#include <pstdbool.h> +#include <stdio.h> +#include <math.h> /* for sqrt functions */ +#include <stdlib.h> /* for the abs/labs functions */ +#include <SST/SST_Build.h> + +#include <SST/SST_Mat44.h> +#include <SST/SST_Vec4.h> +void SST_Math_Mat44dAdd(const SST_Mat44d* RESTRICT _A, const SST_Mat44d* RESTRICT _B, SST_Mat44d* RESTRICT _out) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + SST_ASSUME_ALIGNED(_out,16); + + _out->v[0] = _A->v[0] + _B->v[0]; + _out->v[1] = _A->v[1] + _B->v[1]; + _out->v[2] = _A->v[2] + _B->v[2]; + _out->v[3] = _A->v[3] + _B->v[3]; + _out->v[4] = _A->v[4] + _B->v[4]; + _out->v[5] = _A->v[5] + _B->v[5]; + _out->v[6] = _A->v[6] + _B->v[6]; + _out->v[7] = _A->v[7] + _B->v[7]; + _out->v[8] = _A->v[8] + _B->v[8]; + _out->v[9] = _A->v[9] + _B->v[9]; + _out->v[10] = _A->v[10] + _B->v[10]; + _out->v[11] = _A->v[11] + _B->v[11]; + _out->v[12] = _A->v[12] + _B->v[12]; + _out->v[13] = _A->v[13] + _B->v[13]; + _out->v[14] = _A->v[14] + _B->v[14]; + _out->v[15] = _A->v[15] + _B->v[15]; +} + +/******************************************************************************/ + +void SST_Math_Mat44dAddLocal(SST_Mat44d* RESTRICT _A, const SST_Mat44d* RESTRICT _B) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + + _A->v[0] += _B->v[0]; + _A->v[1] += _B->v[1]; + _A->v[2] += _B->v[2]; + _A->v[3] += _B->v[3]; + _A->v[4] += _B->v[4]; + _A->v[5] += _B->v[5]; + _A->v[6] += _B->v[6]; + _A->v[7] += _B->v[7]; + _A->v[8] += _B->v[8]; + _A->v[9] += _B->v[9]; + _A->v[10] += _B->v[10]; + _A->v[11] += _B->v[11]; + _A->v[12] += _B->v[12]; + _A->v[13] += _B->v[13]; + _A->v[14] += _B->v[14]; + _A->v[15] += _B->v[15]; +} + +/******************************************************************************/ + +void SST_Math_Mat44dSubtract(const SST_Mat44d* RESTRICT _A, const SST_Mat44d* RESTRICT _B, SST_Mat44d* RESTRICT _out) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + SST_ASSUME_ALIGNED(_out,16); + + _out->v[0] = _A->v[0] - _B->v[0]; + _out->v[1] = _A->v[1] - _B->v[1]; + _out->v[2] = _A->v[2] - _B->v[2]; + _out->v[3] = _A->v[3] - _B->v[3]; + _out->v[4] = _A->v[4] - _B->v[4]; + _out->v[5] = _A->v[5] - _B->v[5]; + _out->v[6] = _A->v[6] - _B->v[6]; + _out->v[7] = _A->v[7] - _B->v[7]; + _out->v[8] = _A->v[8] - _B->v[8]; + _out->v[9] = _A->v[9] - _B->v[9]; + _out->v[10] = _A->v[10] - _B->v[10]; + _out->v[11] = _A->v[11] - _B->v[11]; + _out->v[12] = _A->v[12] - _B->v[12]; + _out->v[13] = _A->v[13] - _B->v[13]; + _out->v[14] = _A->v[14] - _B->v[14]; + _out->v[15] = _A->v[15] - _B->v[15]; +} + +/******************************************************************************/ + +void SST_Math_Mat44dSubtractLocal(SST_Mat44d* RESTRICT _A, const SST_Mat44d* RESTRICT _B) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + + _A->v[0] -= _B->v[0]; + _A->v[1] -= _B->v[1]; + _A->v[2] -= _B->v[2]; + _A->v[3] -= _B->v[3]; + _A->v[4] -= _B->v[4]; + _A->v[5] -= _B->v[5]; + _A->v[6] -= _B->v[6]; + _A->v[7] -= _B->v[7]; + _A->v[8] -= _B->v[8]; + _A->v[9] -= _B->v[9]; + _A->v[10] -= _B->v[10]; + _A->v[11] -= _B->v[11]; + _A->v[12] -= _B->v[12]; + _A->v[13] -= _B->v[13]; + _A->v[14] -= _B->v[14]; + _A->v[15] -= _B->v[15]; +} + +/******************************************************************************/ + +void SST_Math_Mat44dMultiplyElementwise(const SST_Mat44d* RESTRICT _A, const SST_Mat44d* RESTRICT _B, SST_Mat44d* RESTRICT _out) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + SST_ASSUME_ALIGNED(_out,16); + + _out->v[0] = _A->v[0] * _B->v[0]; + _out->v[1] = _A->v[1] * _B->v[1]; + _out->v[2] = _A->v[2] * _B->v[2]; + _out->v[3] = _A->v[3] * _B->v[3]; + _out->v[4] = _A->v[4] * _B->v[4]; + _out->v[5] = _A->v[5] * _B->v[5]; + _out->v[6] = _A->v[6] * _B->v[6]; + _out->v[7] = _A->v[7] * _B->v[7]; + _out->v[8] = _A->v[8] * _B->v[8]; + _out->v[9] = _A->v[9] * _B->v[9]; + _out->v[10] = _A->v[10] * _B->v[10]; + _out->v[11] = _A->v[11] * _B->v[11]; + _out->v[12] = _A->v[12] * _B->v[12]; + _out->v[13] = _A->v[13] * _B->v[13]; + _out->v[14] = _A->v[14] * _B->v[14]; + _out->v[15] = _A->v[15] * _B->v[15]; +} + +/******************************************************************************/ + +void SST_Math_Mat44dMultiplyElementwiseLocal(SST_Mat44d* RESTRICT _A, const SST_Mat44d* RESTRICT _B) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + + _A->v[0] *= _B->v[0]; + _A->v[1] *= _B->v[1]; + _A->v[2] *= _B->v[2]; + _A->v[3] *= _B->v[3]; + _A->v[4] *= _B->v[4]; + _A->v[5] *= _B->v[5]; + _A->v[6] *= _B->v[6]; + _A->v[7] *= _B->v[7]; + _A->v[8] *= _B->v[8]; + _A->v[9] *= _B->v[9]; + _A->v[10] *= _B->v[10]; + _A->v[11] *= _B->v[11]; + _A->v[12] *= _B->v[12]; + _A->v[13] *= _B->v[13]; + _A->v[14] *= _B->v[14]; + _A->v[15] *= _B->v[15]; +} + +/******************************************************************************/ + +void SST_Math_Mat44dMultiplyScalar(const SST_Mat44d* RESTRICT _A, const double k, SST_Mat44d* RESTRICT _out) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_out,16); + + _out->v[0] = _A->v[0] * k; + _out->v[1] = _A->v[1] * k; + _out->v[2] = _A->v[2] * k; + _out->v[3] = _A->v[3] * k; + _out->v[4] = _A->v[4] * k; + _out->v[5] = _A->v[5] * k; + _out->v[6] = _A->v[6] * k; + _out->v[7] = _A->v[7] * k; + _out->v[8] = _A->v[8] * k; + _out->v[9] = _A->v[9] * k; + _out->v[10] = _A->v[10] * k; + _out->v[11] = _A->v[11] * k; + _out->v[12] = _A->v[12] * k; + _out->v[13] = _A->v[13] * k; + _out->v[14] = _A->v[14] * k; + _out->v[15] = _A->v[15] * k; +} + +/******************************************************************************/ + +void SST_Math_Mat44dMultiplyScalarLocal(SST_Mat44d* RESTRICT _A, const double k) +{ + SST_ASSUME_ALIGNED(_A,16); + + _A->v[0] *= k; + _A->v[1] *= k; + _A->v[2] *= k; + _A->v[3] *= k; + _A->v[4] *= k; + _A->v[5] *= k; + _A->v[6] *= k; + _A->v[7] *= k; + _A->v[8] *= k; + _A->v[9] *= k; + _A->v[10] *= k; + _A->v[11] *= k; + _A->v[12] *= k; + _A->v[13] *= k; + _A->v[14] *= k; + _A->v[15] *= k; +} + +/******************************************************************************/ + + +void SST_Math_Mat44dMultiplyMatrix(const SST_Mat44d* _A, const SST_Mat44d* RESTRICT _B, SST_Mat44d* RESTRICT _out) +{ +SST_ASSUME_ALIGNED(_A,16); +SST_ASSUME_ALIGNED(_B,16); +SST_ASSUME_ALIGNED(_out,16); +_out->v[ 0] = _A->v[ 0]*_B->v[ 0]+_A->v[ 4]*_B->v[ 1]+_A->v[ 8]*_B->v[ 2]+_A->v[12]*_B->v[ 3]; +_out->v[ 4] = _A->v[ 0]*_B->v[ 4]+_A->v[ 4]*_B->v[ 5]+_A->v[ 8]*_B->v[ 6]+_A->v[12]*_B->v[ 7]; +_out->v[ 8] = _A->v[ 0]*_B->v[ 8]+_A->v[ 4]*_B->v[ 9]+_A->v[ 8]*_B->v[10]+_A->v[12]*_B->v[11]; +_out->v[12] = _A->v[ 0]*_B->v[12]+_A->v[ 4]*_B->v[13]+_A->v[ 8]*_B->v[14]+_A->v[12]*_B->v[15]; +_out->v[ 1] = _A->v[ 1]*_B->v[ 0]+_A->v[ 5]*_B->v[ 1]+_A->v[ 9]*_B->v[ 2]+_A->v[13]*_B->v[ 3]; +_out->v[ 5] = _A->v[ 1]*_B->v[ 4]+_A->v[ 5]*_B->v[ 5]+_A->v[ 9]*_B->v[ 6]+_A->v[13]*_B->v[ 7]; +_out->v[ 9] = _A->v[ 1]*_B->v[ 8]+_A->v[ 5]*_B->v[ 9]+_A->v[ 9]*_B->v[10]+_A->v[13]*_B->v[11]; +_out->v[13] = _A->v[ 1]*_B->v[12]+_A->v[ 5]*_B->v[13]+_A->v[ 9]*_B->v[14]+_A->v[13]*_B->v[15]; +_out->v[ 2] = _A->v[ 2]*_B->v[ 0]+_A->v[ 6]*_B->v[ 1]+_A->v[10]*_B->v[ 2]+_A->v[14]*_B->v[ 3]; +_out->v[ 6] = _A->v[ 2]*_B->v[ 4]+_A->v[ 6]*_B->v[ 5]+_A->v[10]*_B->v[ 6]+_A->v[14]*_B->v[ 7]; +_out->v[10] = _A->v[ 2]*_B->v[ 8]+_A->v[ 6]*_B->v[ 9]+_A->v[10]*_B->v[10]+_A->v[14]*_B->v[11]; +_out->v[14] = _A->v[ 2]*_B->v[12]+_A->v[ 6]*_B->v[13]+_A->v[10]*_B->v[14]+_A->v[14]*_B->v[15]; +_out->v[ 3] = _A->v[ 3]*_B->v[ 0]+_A->v[ 7]*_B->v[ 1]+_A->v[11]*_B->v[ 2]+_A->v[15]*_B->v[ 3]; +_out->v[ 7] = _A->v[ 3]*_B->v[ 4]+_A->v[ 7]*_B->v[ 5]+_A->v[11]*_B->v[ 6]+_A->v[15]*_B->v[ 7]; +_out->v[11] = _A->v[ 3]*_B->v[ 8]+_A->v[ 7]*_B->v[ 9]+_A->v[11]*_B->v[10]+_A->v[15]*_B->v[11]; +_out->v[15] = _A->v[ 3]*_B->v[12]+_A->v[ 7]*_B->v[13]+_A->v[11]*_B->v[14]+_A->v[15]*_B->v[15]; +} +void SST_Math_Mat44dMultiplyMatrixLocal(SST_Mat44d* RESTRICT _A, const SST_Mat44d* RESTRICT _B) +{ + double tmp[16]; + SST_ASSUME_ALIGNED(_A,16); +SST_ASSUME_ALIGNED(_B,16); +tmp[ 0] = _A->v[ 0]*_B->v[ 0]+_A->v[ 4]*_B->v[ 1]+_A->v[ 8]*_B->v[ 2]+_A->v[12]*_B->v[ 3]; +tmp[ 4] = _A->v[ 0]*_B->v[ 4]+_A->v[ 4]*_B->v[ 5]+_A->v[ 8]*_B->v[ 6]+_A->v[12]*_B->v[ 7]; +tmp[ 8] = _A->v[ 0]*_B->v[ 8]+_A->v[ 4]*_B->v[ 9]+_A->v[ 8]*_B->v[10]+_A->v[12]*_B->v[11]; +tmp[12] = _A->v[ 0]*_B->v[12]+_A->v[ 4]*_B->v[13]+_A->v[ 8]*_B->v[14]+_A->v[12]*_B->v[15]; +_A->v[0] = tmp[0]; +_A->v[4] = tmp[4]; +_A->v[8] = tmp[8]; +_A->v[12] = tmp[12]; + + +tmp[ 1] = _A->v[ 1]*_B->v[ 0]+_A->v[ 5]*_B->v[ 1]+_A->v[ 9]*_B->v[ 2]+_A->v[13]*_B->v[ 3]; +tmp[ 5] = _A->v[ 1]*_B->v[ 4]+_A->v[ 5]*_B->v[ 5]+_A->v[ 9]*_B->v[ 6]+_A->v[13]*_B->v[ 7]; +tmp[ 9] = _A->v[ 1]*_B->v[ 8]+_A->v[ 5]*_B->v[ 9]+_A->v[ 9]*_B->v[10]+_A->v[13]*_B->v[11]; +tmp[13] = _A->v[ 1]*_B->v[12]+_A->v[ 5]*_B->v[13]+_A->v[ 9]*_B->v[14]+_A->v[13]*_B->v[15]; +_A->v[1] = tmp[1]; +_A->v[5] = tmp[5]; +_A->v[9] = tmp[9]; +_A->v[13] = tmp[13]; + + +tmp[ 2] = _A->v[ 2]*_B->v[ 0]+_A->v[ 6]*_B->v[ 1]+_A->v[10]*_B->v[ 2]+_A->v[14]*_B->v[ 3]; +tmp[ 6] = _A->v[ 2]*_B->v[ 4]+_A->v[ 6]*_B->v[ 5]+_A->v[10]*_B->v[ 6]+_A->v[14]*_B->v[ 7]; +tmp[10] = _A->v[ 2]*_B->v[ 8]+_A->v[ 6]*_B->v[ 9]+_A->v[10]*_B->v[10]+_A->v[14]*_B->v[11]; +tmp[14] = _A->v[ 2]*_B->v[12]+_A->v[ 6]*_B->v[13]+_A->v[10]*_B->v[14]+_A->v[14]*_B->v[15]; +_A->v[2] = tmp[2]; +_A->v[6] = tmp[6]; +_A->v[10] = tmp[10]; +_A->v[14] = tmp[14]; + + +tmp[ 3] = _A->v[ 3]*_B->v[ 0]+_A->v[ 7]*_B->v[ 1]+_A->v[11]*_B->v[ 2]+_A->v[15]*_B->v[ 3]; +tmp[ 7] = _A->v[ 3]*_B->v[ 4]+_A->v[ 7]*_B->v[ 5]+_A->v[11]*_B->v[ 6]+_A->v[15]*_B->v[ 7]; +tmp[11] = _A->v[ 3]*_B->v[ 8]+_A->v[ 7]*_B->v[ 9]+_A->v[11]*_B->v[10]+_A->v[15]*_B->v[11]; +tmp[15] = _A->v[ 3]*_B->v[12]+_A->v[ 7]*_B->v[13]+_A->v[11]*_B->v[14]+_A->v[15]*_B->v[15]; +_A->v[3] = tmp[3]; +_A->v[7] = tmp[7]; +_A->v[11] = tmp[11]; +_A->v[15] = tmp[15]; + + +} +void SST_Math_Mat44dMultiplyVector(const SST_Mat44d* RESTRICT _A, const SST_Vec4d* RESTRICT _v, SST_Vec4d* RESTRICT _out) +{ +SST_ASSUME_ALIGNED(_A,16); +SST_ASSUME_ALIGNED(_v,16); +SST_ASSUME_ALIGNED(_out,16); +_out->v[ 0] = _A->v[ 0]*_v->v[0]+_A->v[ 4]*_v->v[1]+_A->v[ 8]*_v->v[2]+_A->v[12]*_v->v[3]; +_out->v[ 1] = _A->v[ 1]*_v->v[0]+_A->v[ 5]*_v->v[1]+_A->v[ 9]*_v->v[2]+_A->v[13]*_v->v[3]; +_out->v[ 2] = _A->v[ 2]*_v->v[0]+_A->v[ 6]*_v->v[1]+_A->v[10]*_v->v[2]+_A->v[14]*_v->v[3]; +_out->v[ 3] = _A->v[ 3]*_v->v[0]+_A->v[ 7]*_v->v[1]+_A->v[11]*_v->v[2]+_A->v[15]*_v->v[3]; +} +void SST_Math_Mat44dMultiplyVectorLocal(const SST_Mat44d* RESTRICT _A, SST_Vec4d* RESTRICT _v) +{ +double tmp[4]; +SST_ASSUME_ALIGNED(_A,16); +SST_ASSUME_ALIGNED(_v,16); +tmp[ 0] = _A->v[ 0]*_v->v[0]+_A->v[ 4]*_v->v[1]+_A->v[ 8]*_v->v[2]+_A->v[12]*_v->v[3]; +tmp[ 1] = _A->v[ 1]*_v->v[0]+_A->v[ 5]*_v->v[1]+_A->v[ 9]*_v->v[2]+_A->v[13]*_v->v[3]; +tmp[ 2] = _A->v[ 2]*_v->v[0]+_A->v[ 6]*_v->v[1]+_A->v[10]*_v->v[2]+_A->v[14]*_v->v[3]; +tmp[ 3] = _A->v[ 3]*_v->v[0]+_A->v[ 7]*_v->v[1]+_A->v[11]*_v->v[2]+_A->v[15]*_v->v[3]; +_v->v[0] = tmp[0]; +_v->v[1] = tmp[1]; +_v->v[2] = tmp[2]; +_v->v[3] = tmp[3]; +} +void SST_Math_Mat44dTranspose(const SST_Mat44d* RESTRICT _A, SST_Mat44d* RESTRICT _out) +{ +SST_ASSUME_ALIGNED(_A,16); +SST_ASSUME_ALIGNED(_out,16); +_out->v[ 0] = _A->v[ 0]; +_out->v[ 1] = _A->v[ 4]; +_out->v[ 2] = _A->v[ 8]; +_out->v[ 3] = _A->v[12]; +_out->v[ 4] = _A->v[ 1]; +_out->v[ 5] = _A->v[ 5]; +_out->v[ 6] = _A->v[ 9]; +_out->v[ 7] = _A->v[13]; +_out->v[ 8] = _A->v[ 2]; +_out->v[ 9] = _A->v[ 6]; +_out->v[10] = _A->v[10]; +_out->v[11] = _A->v[14]; +_out->v[12] = _A->v[ 3]; +_out->v[13] = _A->v[ 7]; +_out->v[14] = _A->v[11]; +_out->v[15] = _A->v[15]; +} +void SST_Math_Mat44dTransposeLocal(SST_Mat44d* RESTRICT _A) +{ +double tmp[4]; +SST_ASSUME_ALIGNED(_A,16); +tmp[1] = _A->v[ 4]; +_A->v[ 4] = _A->v[ 1]; +_A->v[ 1] = tmp[1]; +tmp[2] = _A->v[ 8]; +_A->v[ 8] = _A->v[ 2]; +_A->v[ 2] = tmp[2]; +tmp[3] = _A->v[12]; +_A->v[12] = _A->v[ 3]; +_A->v[ 3] = tmp[3]; +tmp[2] = _A->v[ 9]; +_A->v[ 9] = _A->v[ 6]; +_A->v[ 6] = tmp[2]; +tmp[3] = _A->v[13]; +_A->v[13] = _A->v[ 7]; +_A->v[ 7] = tmp[3]; +tmp[3] = _A->v[14]; +_A->v[14] = _A->v[11]; +_A->v[11] = tmp[3]; +} +bool SST_Math_Mat44dCheckOrthonormal(const SST_Mat44d* _A) +{ +const double diag = -_A->v[0]*_A->v[0] -_A->v[1]*_A->v[1] -_A->v[2]*_A->v[2] -_A->v[3]*_A->v[3] -_A->v[4]*_A->v[4] -_A->v[5]*_A->v[5] -_A->v[6]*_A->v[6] -_A->v[7]*_A->v[7] -_A->v[8]*_A->v[8] -_A->v[9]*_A->v[9] -_A->v[10]*_A->v[10] -_A->v[11]*_A->v[11] -_A->v[12]*_A->v[12] -_A->v[13]*_A->v[13] -_A->v[14]*_A->v[14] -_A->v[15]*_A->v[15]; +const double odiag = _A->v[0]*_A->v[4]+ _A->v[1]*_A->v[5]+ _A->v[2]*_A->v[6]+ _A->v[3]*_A->v[7]+ _A->v[0]*_A->v[8]+ _A->v[1]*_A->v[9]+ _A->v[2]*_A->v[10]+ _A->v[3]*_A->v[11]+ _A->v[0]*_A->v[12]+ _A->v[1]*_A->v[13]+ _A->v[2]*_A->v[14]+ _A->v[3]*_A->v[15]+ _A->v[4]*_A->v[0]+ _A->v[5]*_A->v[1]+ _A->v[6]*_A->v[2]+ _A->v[7]*_A->v[3]+ _A->v[4]*_A->v[8]+ _A->v[5]*_A->v[9]+ _A->v[6]*_A->v[10]+ _A->v[7]*_A->v[11]+ _A->v[4]*_A->v[12]+ _A->v[5]*_A->v[13]+ _A->v[6]*_A->v[14]+ _A->v[7]*_A->v[15]+ _A->v[8]*_A->v[0]+ _A->v[9]*_A->v[1]+ _A->v[10]*_A->v[2]+ _A->v[11]*_A->v[3]+ _A->v[8]*_A->v[4]+ _A->v[9]*_A->v[5]+ _A->v[10]*_A->v[6]+ _A->v[11]*_A->v[7]+ _A->v[8]*_A->v[12]+ _A->v[9]*_A->v[13]+ _A->v[10]*_A->v[14]+ _A->v[11]*_A->v[15]+ _A->v[12]*_A->v[0]+ _A->v[13]*_A->v[1]+ _A->v[14]*_A->v[2]+ _A->v[15]*_A->v[3]+ _A->v[12]*_A->v[4]+ _A->v[13]*_A->v[5]+ _A->v[14]*_A->v[6]+ _A->v[15]*_A->v[7]+ _A->v[12]*_A->v[8]+ _A->v[13]*_A->v[9]+ _A->v[14]*_A->v[10]+ _A->v[15]*_A->v[11]; +SST_ASSUME_ALIGNED(_A,16); +return +((fabs( 4.000000000000000+diag)) <= 100*DBL_EPSILON) & +((fabs(odiag)) <= 100*DBL_EPSILON); + + +} +double SST_Math_Mat44dDeterminant(const SST_Mat44d* _A) +{ + const double a10151411 = _A->v[10]*_A->v[15]-_A->v[11]*_A->v[14]; + const double a9151311 = _A->v[6]*_A->v[15]-_A->v[7]*_A->v[14]; + const double a9141310 = _A->v[6]*_A->v[11]-_A->v[7]*_A->v[10]; + const double a8151112 = _A->v[2]*_A->v[15]-_A->v[14]*_A->v[3]; + const double a8141210 = _A->v[2]*_A->v[11]-_A->v[3]*_A->v[10]; + const double a813129 = _A->v[2]*_A->v[7]-_A->v[3]*_A->v[6]; + const double result = _A->v[0]*(_A->v[5]*a10151411-_A->v[9]*a9151311+_A->v[13]*a9141310)-_A->v[4]*(_A->v[1]*a10151411-_A->v[9]*a8151112+_A->v[13]*a8141210)+_A->v[8]*(_A->v[1]*a9151311 -_A->v[5]*a8151112+_A->v[13]*a813129)-_A->v[12]*(_A->v[1]*a9141310 -_A->v[5]*a8141210+_A->v[9]*a813129); + SST_ASSUME_ALIGNED(_A,16); + return result; +} +void SST_Math_Mat44dInvert(const SST_Mat44d* RESTRICT _A, SST_Mat44d* RESTRICT _out) +{ +/* Gaussian Elimination */ +#define _A(i,j) _A->v[i+4*j] +#define _out(i,j) _out->v[i+4*j] +#define Pinv(i,j) Pinv.v[i+4*j] +double aij; +double norm_aij; +SST_Mat44d Pinv; +SST_ASSUME_ALIGNED(_A,16); +/* Set _out to the identity */ +_out(0,0) = 1.000000000000000; +_out(1,0) = 0.000000000000000; +_out(2,0) = 0.000000000000000; +_out(3,0) = 0.000000000000000; +_out(0,1) = 0.000000000000000; +_out(1,1) = 1.000000000000000; +_out(2,1) = 0.000000000000000; +_out(3,1) = 0.000000000000000; +_out(0,2) = 0.000000000000000; +_out(1,2) = 0.000000000000000; +_out(2,2) = 1.000000000000000; +_out(3,2) = 0.000000000000000; +_out(0,3) = 0.000000000000000; +_out(1,3) = 0.000000000000000; +_out(2,3) = 0.000000000000000; +_out(3,3) = 1.000000000000000; +/* Set _Pinv to _A so we don't overwrite it */ +Pinv.v[0] = _A->v[0]; +Pinv.v[1] = _A->v[1]; +Pinv.v[2] = _A->v[2]; +Pinv.v[3] = _A->v[3]; +Pinv.v[4] = _A->v[4]; +Pinv.v[5] = _A->v[5]; +Pinv.v[6] = _A->v[6]; +Pinv.v[7] = _A->v[7]; +Pinv.v[8] = _A->v[8]; +Pinv.v[9] = _A->v[9]; +Pinv.v[10] = _A->v[10]; +Pinv.v[11] = _A->v[11]; +Pinv.v[12] = _A->v[12]; +Pinv.v[13] = _A->v[13]; +Pinv.v[14] = _A->v[14]; +Pinv.v[15] = _A->v[15]; +/* Put in Reduced Row Echelon form */ +/* Note that we can set the entry to 0, or just calculate it. + The latter will be helpful when recognizing that these are all simple vector moves */ +/* Sort if need be */ +aij = -Pinv(1,0) / Pinv(0,0) ; +Pinv(1,0) += aij*Pinv(0,0) ; +Pinv(1,1) += aij*Pinv(0,1) ; +Pinv(1,2) += aij*Pinv(0,2) ; +Pinv(1,3) += aij*Pinv(0,3) ; +_out(1,0) += aij*_out(0,0) ; +_out(1,1) += aij*_out(0,1) ; +_out(1,2) += aij*_out(0,2) ; +_out(1,3) += aij*_out(0,3) ; +/* Sort if need be */ +aij = -Pinv(2,0) / Pinv(0,0) ; +Pinv(2,0) += aij*Pinv(0,0) ; +Pinv(2,1) += aij*Pinv(0,1) ; +Pinv(2,2) += aij*Pinv(0,2) ; +Pinv(2,3) += aij*Pinv(0,3) ; +_out(2,0) += aij*_out(0,0) ; +_out(2,1) += aij*_out(0,1) ; +_out(2,2) += aij*_out(0,2) ; +_out(2,3) += aij*_out(0,3) ; +/* Sort if need be */ +aij = -Pinv(3,0) / Pinv(0,0) ; +Pinv(3,0) += aij*Pinv(0,0) ; +Pinv(3,1) += aij*Pinv(0,1) ; +Pinv(3,2) += aij*Pinv(0,2) ; +Pinv(3,3) += aij*Pinv(0,3) ; +_out(3,0) += aij*_out(0,0) ; +_out(3,1) += aij*_out(0,1) ; +_out(3,2) += aij*_out(0,2) ; +_out(3,3) += aij*_out(0,3) ; +/* Sort if need be */ +aij = -Pinv(2,1) / Pinv(1,1) ; +Pinv(2,0) += aij*Pinv(1,0) ; +Pinv(2,1) += aij*Pinv(1,1) ; +Pinv(2,2) += aij*Pinv(1,2) ; +Pinv(2,3) += aij*Pinv(1,3) ; +_out(2,0) += aij*_out(1,0) ; +_out(2,1) += aij*_out(1,1) ; +_out(2,2) += aij*_out(1,2) ; +_out(2,3) += aij*_out(1,3) ; +/* Sort if need be */ +aij = -Pinv(3,1) / Pinv(1,1) ; +Pinv(3,0) += aij*Pinv(1,0) ; +Pinv(3,1) += aij*Pinv(1,1) ; +Pinv(3,2) += aij*Pinv(1,2) ; +Pinv(3,3) += aij*Pinv(1,3) ; +_out(3,0) += aij*_out(1,0) ; +_out(3,1) += aij*_out(1,1) ; +_out(3,2) += aij*_out(1,2) ; +_out(3,3) += aij*_out(1,3) ; +/* Sort if need be */ +aij = -Pinv(3,2) / Pinv(2,2) ; +Pinv(3,0) += aij*Pinv(2,0) ; +Pinv(3,1) += aij*Pinv(2,1) ; +Pinv(3,2) += aij*Pinv(2,2) ; +Pinv(3,3) += aij*Pinv(2,3) ; +_out(3,0) += aij*_out(2,0) ; +_out(3,1) += aij*_out(2,1) ; +_out(3,2) += aij*_out(2,2) ; +_out(3,3) += aij*_out(2,3) ; +/* Backsubstitution */ +norm_aij = 1.000000000000000 / Pinv(3,3) ; +Pinv(3,3) = 1.000000000000000; +_out(3,0) *= norm_aij; +_out(3,1) *= norm_aij; +_out(3,2) *= norm_aij; +_out(3,3) *= norm_aij; +aij = -Pinv(0,3); +Pinv(0,0) += aij*Pinv(3,0); +Pinv(0,1) += aij*Pinv(3,1); +Pinv(0,2) += aij*Pinv(3,2); +Pinv(0,3) += aij*Pinv(3,3); +_out(0,0) += aij*_out(3,0); +_out(0,1) += aij*_out(3,1); +_out(0,2) += aij*_out(3,2); +_out(0,3) += aij*_out(3,3); +aij = -Pinv(1,3); +Pinv(1,0) += aij*Pinv(3,0); +Pinv(1,1) += aij*Pinv(3,1); +Pinv(1,2) += aij*Pinv(3,2); +Pinv(1,3) += aij*Pinv(3,3); +_out(1,0) += aij*_out(3,0); +_out(1,1) += aij*_out(3,1); +_out(1,2) += aij*_out(3,2); +_out(1,3) += aij*_out(3,3); +aij = -Pinv(2,3); +Pinv(2,0) += aij*Pinv(3,0); +Pinv(2,1) += aij*Pinv(3,1); +Pinv(2,2) += aij*Pinv(3,2); +Pinv(2,3) += aij*Pinv(3,3); +_out(2,0) += aij*_out(3,0); +_out(2,1) += aij*_out(3,1); +_out(2,2) += aij*_out(3,2); +_out(2,3) += aij*_out(3,3); +norm_aij = 1.000000000000000 / Pinv(2,2) ; +Pinv(2,2) = 1.000000000000000; +_out(2,0) *= norm_aij; +_out(2,1) *= norm_aij; +_out(2,2) *= norm_aij; +_out(2,3) *= norm_aij; +aij = -Pinv(0,2); +Pinv(0,0) += aij*Pinv(2,0); +Pinv(0,1) += aij*Pinv(2,1); +Pinv(0,2) += aij*Pinv(2,2); +Pinv(0,3) += aij*Pinv(2,3); +_out(0,0) += aij*_out(2,0); +_out(0,1) += aij*_out(2,1); +_out(0,2) += aij*_out(2,2); +_out(0,3) += aij*_out(2,3); +aij = -Pinv(1,2); +Pinv(1,0) += aij*Pinv(2,0); +Pinv(1,1) += aij*Pinv(2,1); +Pinv(1,2) += aij*Pinv(2,2); +Pinv(1,3) += aij*Pinv(2,3); +_out(1,0) += aij*_out(2,0); +_out(1,1) += aij*_out(2,1); +_out(1,2) += aij*_out(2,2); +_out(1,3) += aij*_out(2,3); +norm_aij = 1.000000000000000 / Pinv(1,1) ; +Pinv(1,1) = 1.000000000000000; +_out(1,0) *= norm_aij; +_out(1,1) *= norm_aij; +_out(1,2) *= norm_aij; +_out(1,3) *= norm_aij; +aij = -Pinv(0,1); +Pinv(0,0) += aij*Pinv(1,0); +Pinv(0,1) += aij*Pinv(1,1); +Pinv(0,2) += aij*Pinv(1,2); +Pinv(0,3) += aij*Pinv(1,3); +_out(0,0) += aij*_out(1,0); +_out(0,1) += aij*_out(1,1); +_out(0,2) += aij*_out(1,2); +_out(0,3) += aij*_out(1,3); +norm_aij = 1.000000000000000 / Pinv(0,0) ; +Pinv(0,0) = 1.000000000000000; +_out(0,0) *= norm_aij; +_out(0,1) *= norm_aij; +_out(0,2) *= norm_aij; +_out(0,3) *= norm_aij; +#undef _A +#undef _out +#undef Pinv +} +void SST_Math_Mat44dInvertLocal(SST_Mat44d* RESTRICT _A) +{ +/* Gaussian Elimination */ +#define _A(i,j) _A->v[i+4*j] +#define out(i,j) out->v[i+4*j] +#define Pinv(i,j) Pinv.v[i+4*j] +double aij; +double norm_aij; +SST_Mat44d Pinv; +SST_ASSUME_ALIGNED(_A,16); +/* Set _out to the identity */ +/* Set _Pinv to _A so we don't overwrite it */ +Pinv.v[0] = _A->v[0]; +Pinv.v[1] = _A->v[1]; +Pinv.v[2] = _A->v[2]; +Pinv.v[3] = _A->v[3]; +Pinv.v[4] = _A->v[4]; +Pinv.v[5] = _A->v[5]; +Pinv.v[6] = _A->v[6]; +Pinv.v[7] = _A->v[7]; +Pinv.v[8] = _A->v[8]; +Pinv.v[9] = _A->v[9]; +Pinv.v[10] = _A->v[10]; +Pinv.v[11] = _A->v[11]; +Pinv.v[12] = _A->v[12]; +Pinv.v[13] = _A->v[13]; +Pinv.v[14] = _A->v[14]; +Pinv.v[15] = _A->v[15]; +_A(0,0) = 1.000000000000000; +_A(1,0) = 0.000000000000000; +_A(2,0) = 0.000000000000000; +_A(3,0) = 0.000000000000000; +_A(0,1) = 0.000000000000000; +_A(1,1) = 1.000000000000000; +_A(2,1) = 0.000000000000000; +_A(3,1) = 0.000000000000000; +_A(0,2) = 0.000000000000000; +_A(1,2) = 0.000000000000000; +_A(2,2) = 1.000000000000000; +_A(3,2) = 0.000000000000000; +_A(0,3) = 0.000000000000000; +_A(1,3) = 0.000000000000000; +_A(2,3) = 0.000000000000000; +_A(3,3) = 1.000000000000000; +/* Put in Reduced Row Echelon form */ +/* Note that we can set the entry to 0, or just calculate it. + The latter will be helpful when recognizing that these are all simple vector moves */ +/* Sort if need be */ +aij = -Pinv(1,0) / Pinv(0,0) ; +Pinv(1,0) += aij*Pinv(0,0) ; +Pinv(1,1) += aij*Pinv(0,1) ; +Pinv(1,2) += aij*Pinv(0,2) ; +Pinv(1,3) += aij*Pinv(0,3) ; +_A(1,0) += aij*_A(0,0) ; +_A(1,1) += aij*_A(0,1) ; +_A(1,2) += aij*_A(0,2) ; +_A(1,3) += aij*_A(0,3) ; +/* Sort if need be */ +aij = -Pinv(2,0) / Pinv(0,0) ; +Pinv(2,0) += aij*Pinv(0,0) ; +Pinv(2,1) += aij*Pinv(0,1) ; +Pinv(2,2) += aij*Pinv(0,2) ; +Pinv(2,3) += aij*Pinv(0,3) ; +_A(2,0) += aij*_A(0,0) ; +_A(2,1) += aij*_A(0,1) ; +_A(2,2) += aij*_A(0,2) ; +_A(2,3) += aij*_A(0,3) ; +/* Sort if need be */ +aij = -Pinv(3,0) / Pinv(0,0) ; +Pinv(3,0) += aij*Pinv(0,0) ; +Pinv(3,1) += aij*Pinv(0,1) ; +Pinv(3,2) += aij*Pinv(0,2) ; +Pinv(3,3) += aij*Pinv(0,3) ; +_A(3,0) += aij*_A(0,0) ; +_A(3,1) += aij*_A(0,1) ; +_A(3,2) += aij*_A(0,2) ; +_A(3,3) += aij*_A(0,3) ; +/* Sort if need be */ +aij = -Pinv(2,1) / Pinv(1,1) ; +Pinv(2,0) += aij*Pinv(1,0) ; +Pinv(2,1) += aij*Pinv(1,1) ; +Pinv(2,2) += aij*Pinv(1,2) ; +Pinv(2,3) += aij*Pinv(1,3) ; +_A(2,0) += aij*_A(1,0) ; +_A(2,1) += aij*_A(1,1) ; +_A(2,2) += aij*_A(1,2) ; +_A(2,3) += aij*_A(1,3) ; +/* Sort if need be */ +aij = -Pinv(3,1) / Pinv(1,1) ; +Pinv(3,0) += aij*Pinv(1,0) ; +Pinv(3,1) += aij*Pinv(1,1) ; +Pinv(3,2) += aij*Pinv(1,2) ; +Pinv(3,3) += aij*Pinv(1,3) ; +_A(3,0) += aij*_A(1,0) ; +_A(3,1) += aij*_A(1,1) ; +_A(3,2) += aij*_A(1,2) ; +_A(3,3) += aij*_A(1,3) ; +/* Sort if need be */ +aij = -Pinv(3,2) / Pinv(2,2) ; +Pinv(3,0) += aij*Pinv(2,0) ; +Pinv(3,1) += aij*Pinv(2,1) ; +Pinv(3,2) += aij*Pinv(2,2) ; +Pinv(3,3) += aij*Pinv(2,3) ; +_A(3,0) += aij*_A(2,0) ; +_A(3,1) += aij*_A(2,1) ; +_A(3,2) += aij*_A(2,2) ; +_A(3,3) += aij*_A(2,3) ; +/* Backsubstitution */ +norm_aij = 1.000000000000000 / Pinv(3,3) ; +Pinv(3,3) = 1.000000000000000; +_A(3,0) *= norm_aij; +_A(3,1) *= norm_aij; +_A(3,2) *= norm_aij; +_A(3,3) *= norm_aij; +aij = -Pinv.v[12]; +Pinv.v[0] += aij*Pinv.v[3]; +Pinv.v[4] += aij*Pinv.v[7]; +Pinv.v[8] += aij*Pinv.v[11]; +Pinv.v[12] += aij*Pinv.v[15]; +_A->v[0] += aij*_A->v[3]; +_A->v[4] += aij*_A->v[7]; +_A->v[8] += aij*_A->v[11]; +_A->v[12] += aij*_A->v[15]; +aij = -Pinv.v[13]; +Pinv.v[1] += aij*Pinv.v[3]; +Pinv.v[5] += aij*Pinv.v[7]; +Pinv.v[9] += aij*Pinv.v[11]; +Pinv.v[13] += aij*Pinv.v[15]; +_A->v[1] += aij*_A->v[3]; +_A->v[5] += aij*_A->v[7]; +_A->v[9] += aij*_A->v[11]; +_A->v[13] += aij*_A->v[15]; +aij = -Pinv.v[14]; +Pinv.v[2] += aij*Pinv.v[3]; +Pinv.v[6] += aij*Pinv.v[7]; +Pinv.v[10] += aij*Pinv.v[11]; +Pinv.v[14] += aij*Pinv.v[15]; +_A->v[2] += aij*_A->v[3]; +_A->v[6] += aij*_A->v[7]; +_A->v[10] += aij*_A->v[11]; +_A->v[14] += aij*_A->v[15]; +norm_aij = 1.000000000000000 / Pinv(2,2) ; +Pinv(2,2) = 1.000000000000000; +_A(2,0) *= norm_aij; +_A(2,1) *= norm_aij; +_A(2,2) *= norm_aij; +_A(2,3) *= norm_aij; +aij = -Pinv.v[8]; +Pinv.v[0] += aij*Pinv.v[2]; +Pinv.v[4] += aij*Pinv.v[6]; +Pinv.v[8] += aij*Pinv.v[10]; +Pinv.v[12] += aij*Pinv.v[14]; +_A->v[0] += aij*_A->v[2]; +_A->v[4] += aij*_A->v[6]; +_A->v[8] += aij*_A->v[10]; +_A->v[12] += aij*_A->v[14]; +aij = -Pinv.v[9]; +Pinv.v[1] += aij*Pinv.v[2]; +Pinv.v[5] += aij*Pinv.v[6]; +Pinv.v[9] += aij*Pinv.v[10]; +Pinv.v[13] += aij*Pinv.v[14]; +_A->v[1] += aij*_A->v[2]; +_A->v[5] += aij*_A->v[6]; +_A->v[9] += aij*_A->v[10]; +_A->v[13] += aij*_A->v[14]; +norm_aij = 1.000000000000000 / Pinv(1,1) ; +Pinv(1,1) = 1.000000000000000; +_A(1,0) *= norm_aij; +_A(1,1) *= norm_aij; +_A(1,2) *= norm_aij; +_A(1,3) *= norm_aij; +aij = -Pinv.v[4]; +Pinv.v[0] += aij*Pinv.v[1]; +Pinv.v[4] += aij*Pinv.v[5]; +Pinv.v[8] += aij*Pinv.v[9]; +Pinv.v[12] += aij*Pinv.v[13]; +_A->v[0] += aij*_A->v[1]; +_A->v[4] += aij*_A->v[5]; +_A->v[8] += aij*_A->v[9]; +_A->v[12] += aij*_A->v[13]; +norm_aij = 1.000000000000000 / Pinv(0,0) ; +Pinv(0,0) = 1.000000000000000; +_A(0,0) *= norm_aij; +_A(0,1) *= norm_aij; +_A(0,2) *= norm_aij; +_A(0,3) *= norm_aij; +} +void SST_Math_Mat44dCreateLU(const SST_Mat44d* RESTRICT _A, SST_Mat44d* RESTRICT _LU) +{ +#define _A(i,j) _A->v[i+4*j] +#define _LU(i,j) _LU->v[i+4*j] + int i,j,k; + double sum; +SST_ASSUME_ALIGNED(_A,16); +SST_ASSUME_ALIGNED(_LU,16); + _LU(0,0) = _A(0,0); + _LU(0,1) = 0; + _LU(0,2) = 0; + _LU(0,3) = 0; + _LU(1,0) = _A(1,0); + _LU(1,2) = 0; + _LU(1,3) = 0; + _LU(2,0) = _A(2,0); + _LU(2,3) = 0; + _LU(3,0) = _A(3,0); + /* _U(0,0) = 1.000000000000000; */ + /* _U(1,1) = 1.000000000000000; */ + /* _U(2,2) = 1.000000000000000; */ + /* _U(3,3) = 1.000000000000000; */ + _LU(0,1) = _A(0,1) / _LU(0,0); + _LU(0,2) = _A(0,2) / _LU(0,0); + _LU(0,3) = _A(0,3) / _LU(0,0); + for(i=1; i < 4; i++) { + + for(j=1; j <= i; j++) { + sum = 0.000000000000000; + for(k=0; k < j; k++) + sum += -_LU(i,k)*_LU(k,j); + _LU(i,j) = _A(i,j) + sum; + } + for(j=i+1; j < 4; j++) { + sum = 0.000000000000000; + for(k=0; k < i; k++) + sum += -_LU(i,k)*_LU(k,j); + _LU(i,j) = (_A(i,j) + sum) / _LU(i,i); + } + } +#undef _A +#undef _LU +} +void SST_Math_Mat44dApplyLUMat(const SST_Mat44d* _LU, const SST_Mat44d* _A, SST_Mat44d* _out) +{ + +#define _LU(i,j) _LU->v[i+4*j] +#define _A(i,j) _A->v[i+4*j] +#define _out(i,j) _out->v[i+4*j] + int i, j, col; + double sum; +SST_ASSUME_ALIGNED(_A,16); +SST_ASSUME_ALIGNED(_LU,16); +SST_ASSUME_ALIGNED(_out,16); + for(col = 0; col < 4; col++) { + _out(0,col) = _A(0,col); + _out(1,col) = _A(1,col); + _out(2,col) = _A(2,col); + _out(3,col) = _A(3,col); + /* Forward Substitution for Ly = v */ + for(i = 0; i < 4; i++) { + sum = 0.000000000000000; + for(j = 0; j < i; j++) + sum += _LU(i,j) * _out(j,col); + _out(i,col) = (_out(i,col) - sum) / _LU(i,i) ; + } +/* Backwards Substitution for Uw = y */ + for(i = 3; i >=0; i--) { + sum = 0.000000000000000; + for(j = i+1; j < 4; j++) + sum += _LU(i,j) * _out(j,col); + _out(i,col) = (_out(i,col) - sum) ; /* divide by U(i,i)=1 */ + } + } +#undef _LU /* (i,j) _LU->v[i+4*j] */ +#undef _A /* (i,j) _A->v[i+4*j] */ +#undef _out /* (i,j) _out->v[i+4*j] */ +} +void SST_Math_Mat44dApplyLUMatLocal(const SST_Mat44d* _LU,SST_Mat44d* _A) +{ + +#define _LU(i,j) _LU->v[i+4*j] +#define _A(i,j) _A->v[i+4*j] + int i, j, col; + double sum; + for(col = 0; col < 4; col++) { + /* Forward Substitution for Ly = v */ + for(i = 0; i < 4; i++) { + sum = 0.000000000000000; + for(j = 0; j < i; j++) + sum += _LU(i,j) * _A(j,col); + _A(i,col) = (_A(i,col) - sum) / _LU(i,i) ; + } +/* Backwards Substitution for Uw = y */ + for(i = 3; i >=0; i--) { + sum = 0.000000000000000; + for(j = i+1; j < 4; j++) + sum += _LU(i,j) * _A(j,col); + _A(i,col) = (_A(i,col) - sum) ; /* U is 1s along the diagonal */ + } + } +} +void SST_Math_Mat44dApplyLUVec(const SST_Mat44d* _LU, const SST_Vec4d* _v,SST_Vec4d* _w) +{ + +#define _LU(i,j) _LU->v[i+4*j] + int i, j; + double sum; + _w->v[0] = _v->v[0]; + _w->v[1] = _v->v[1]; + _w->v[2] = _v->v[2]; + _w->v[3] = _v->v[3]; + /* Forward Substitution for Ly = v */ + for(i = 0; i < 4; i++) { + sum = 0.000000000000000; + for(j = 0; j < i; j++) + sum += _LU(i,j) * _w->v[j]; + _w->v[i] = (_w->v[i] - sum) / _LU(i,i) ; + } +/* Backwards Substitution for Uw = y */ + for(i = 3; i >= 0; i--) { + sum = 0.000000000000000; + for(j = i+1; j < 4; j++) + sum += _LU(i,j) * _w->v[j]; + /*_w->v[i] = (_w->v[i] - sum) ;*/ + _w->v[i] = (_w->v[i] - sum) ; + } +#undef _LU /* (i,j) _LU->v[i+4*j] */ +} +void SST_Math_Mat44dApplyLUVecLocal(const SST_Mat44d* _LU,SST_Vec4d* _w) +{ + +#define _LU(i,j) _LU->v[i+4*j] + int i, j; + double sum; + /* Forward Substitution for Ly = v */ + for(i = 0; i < 4; i++) { + sum = 0.000000000000000; + for(j = 0; j < i; j++) + sum += _LU(i,j) * _w->v[j]; + _w->v[i] = (_w->v[i] - sum) / _LU(i,i) ; + } +/* Backwards Substitution for Uw = y */ + for(i = 3; i >= 0; i--) { + sum = 0.000000000000000; + for(j = i+1; j < 4; j++) + sum += _LU(i,j) * _w->v[j]; + /*_w->v[i] = (_w->v[i] - sum) ;*/ + _w->v[i] = (_w->v[i] - sum) ; + } +#undef _LU /* (i,j) _LU->v[i+4*j] */ +} +void SST_Math_Mat44dCreateLULocal(SST_Mat44d* RESTRICT _A) +{ + /* Note this code stores both L and U inside of A */ + /* For A in R[n x m] we say that for n = m there is an LU = A decomposition [In our decomp, diag[L] = I. Furthermore there is an LU=PA decomposition, where P is a permutation matrix + Step 1: U(i,i:m) = A(i,i:m) + Step 2: L(i+1:n,i) = -A(i+1:n,i) + Step 3: ??? + Step 4: Profit */ +#define _A(i,j) _A->v[i+4*j] + int i,j,k; + double sum; +/* These entries are the same as before in the algorithm. This is left in for purposes of clarity and completeness +_L(0,0) = _A(0,0); +_L(1,0) = _A(1,0); +_L(2,0) = _A(2,0); +_L(3,0) = _A(3,0); +These entries are understood to be 1 in this storage format. This is left in for purposes of clarity and completeness +_U(0,0) = 1.000000000000000; +_U(1,1) = 1.000000000000000; +_U(2,2) = 1.000000000000000; +_U(3,3) = 1.000000000000000; +*/ +_A(0,1) = _A(0,1) / _A(0,0); +_A(0,2) = _A(0,2) / _A(0,0); +_A(0,3) = _A(0,3) / _A(0,0); + for(i=1; i < 4; i++) { + + for(j=0; j <= i; j++) { + sum = 0.000000000000000; + for(k=0; k < j; k++) sum += -_A(i,k)*_A(k,j); + _A(i,j) = _A(i,j) + sum; + } + for(j=i+1; j < 4; j++) { + sum = 0.000000000000000; + for(k=0; k < i; k++) sum += -_A(i,k)*_A(k,j); + _A(i,j) = (_A(i,j) + sum) / _A(i,i); + } + } +#undef _A +} diff --git a/libsst-math/SST_Mat44d_benchmark.c b/libsst-math/SST_Mat44d_benchmark.c new file mode 100644 index 0000000..a23ff67 --- /dev/null +++ b/libsst-math/SST_Mat44d_benchmark.c @@ -0,0 +1,856 @@ +#include <float.h> +#include <math.h> +#include <stdlib.h> +#include <stdio.h> +#include <assert.h> +#include <xmmintrin.h> +#include <SST/SST_Timer_x86.h> +#include <SST/SST_Mat44.h> +#include <SST/SST_Vec4.h> + + + + +int SST_Math_Mat44d_test_fxns() +{ +const int NTESTS = 10; +int i; +uint64_t t0,t1; +SST_Mat44d X; /* 4 x 4 matrix */ +SST_Mat44d Y; /* 4 x 4 matrix */ +SST_Mat44d A; /* 4 x 4 matrix */ +SST_Mat44d B; /* 4 x 4 matrix */ +SST_Vec4d v; /* 4 vector */ +SST_Vec4d w; /* 4 vector */ +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +/* Resetting test vectors / mats */ + v.v[0] = 9.000000000000000; + v.v[1] = -6.000000000000000; + v.v[2] = -18.000000000000000; + v.v[3] = -13.000000000000000; + X.v[0] = -10.000000000000000; + X.v[1] = 17.000000000000000; + X.v[2] = 15.000000000000000; + X.v[3] = -1.000000000000000; + X.v[4] = -19.000000000000000; + X.v[5] = 4.000000000000000; + X.v[6] = -5.000000000000000; + X.v[7] = -4.000000000000000; + X.v[8] = -17.000000000000000; + X.v[9] = 16.000000000000000; + X.v[10] = 5.000000000000000; + X.v[11] = -4.000000000000000; + X.v[12] = -18.000000000000000; + X.v[13] = -4.000000000000000; + X.v[14] = 13.000000000000000; + X.v[15] = -16.000000000000000; + Y.v[0] = 9.000000000000000; + Y.v[1] = 8.000000000000000; + Y.v[2] = -10.000000000000000; + Y.v[3] = -16.000000000000000; + Y.v[4] = 0.000000000000000; + Y.v[5] = -19.000000000000000; + Y.v[6] = -11.000000000000000; + Y.v[7] = 18.000000000000000; + Y.v[8] = 16.000000000000000; + Y.v[9] = 13.000000000000000; + Y.v[10] = -12.000000000000000; + Y.v[11] = -14.000000000000000; + Y.v[12] = 9.000000000000000; + Y.v[13] = 5.000000000000000; + Y.v[14] = 13.000000000000000; + Y.v[15] = -10.000000000000000; +SST_Math_Mat44dAdd(&X,&Y,&A); /* clear out the initial finding of object */ +/* Clear out the rdtsc register */ +fprintf(stdout,"SST_Math_Mat44dAdd(X,Y,A)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat44dAdd(&X,&Y,&A); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +/* +[[-10. -19. -17. -18.] + [ 17. 4. 16. -4.] + [ 15. -5. 5. 13.] + [ -1. -4. -4. -16.]] +[[ 9. 0. 16. 9.] + [ 8. -19. 13. 5.] + [-10. -11. -12. 13.] + [-16. 18. -14. -10.]] +[[ -1. -19. -1. -9.] + [ 25. -15. 29. 1.] + [ 5. -16. -7. 26.] + [-17. 14. -18. -26.]] +*/ +assert(fabs((A.v[0])-( -1.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[4])-( -19.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[8])-( -1.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[12])-( -9.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[1])-( 25.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[5])-( -15.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[9])-( 29.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[13])-( 1.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[2])-( 5.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[6])-( -16.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[10])-( -7.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[14])-( 26.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[3])-( -17.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[7])-( 14.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[11])-( -18.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[15])-( -26.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +/* +[[-10. -19. -17. -18.] + [ 17. 4. 16. -4.] + [ 15. -5. 5. 13.] + [ -1. -4. -4. -16.]] +[[ 9. 0. 16. 9.] + [ 8. -19. 13. 5.] + [-10. -11. -12. 13.] + [-16. 18. -14. -10.]] +[[ -1. -19. -1. -9.] + [ 25. -15. 29. 1.] + [ 5. -16. -7. 26.] + [-17. 14. -18. -26.]] +*/ +fprintf(stdout,"SST_Math_Mat44dAddLocal(A,Y)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat44dAddLocal(&A,&Y); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +SST_Math_Mat44dAddLocal(&X,&Y); /* for accuracy */ +assert(fabs((X.v[0])-( -1.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[4])-( -19.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[8])-( -1.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[12])-( -9.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[1])-( 25.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[5])-( -15.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[9])-( 29.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[13])-( 1.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[2])-( 5.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[6])-( -16.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[10])-( -7.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[14])-( 26.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[3])-( -17.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[7])-( 14.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[11])-( -18.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[15])-( -26.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +/* Resetting test vectors / mats */ + v.v[0] = -8.000000000000000; + v.v[1] = -10.000000000000000; + v.v[2] = -7.000000000000000; + v.v[3] = 7.000000000000000; + X.v[0] = 3.000000000000000; + X.v[1] = 6.000000000000000; + X.v[2] = 0.000000000000000; + X.v[3] = 19.000000000000000; + X.v[4] = 14.000000000000000; + X.v[5] = -9.000000000000000; + X.v[6] = -17.000000000000000; + X.v[7] = -20.000000000000000; + X.v[8] = 18.000000000000000; + X.v[9] = -18.000000000000000; + X.v[10] = -4.000000000000000; + X.v[11] = 12.000000000000000; + X.v[12] = 8.000000000000000; + X.v[13] = -11.000000000000000; + X.v[14] = 12.000000000000000; + X.v[15] = -6.000000000000000; + Y.v[0] = -20.000000000000000; + Y.v[1] = -11.000000000000000; + Y.v[2] = -13.000000000000000; + Y.v[3] = 19.000000000000000; + Y.v[4] = 19.000000000000000; + Y.v[5] = 14.000000000000000; + Y.v[6] = 19.000000000000000; + Y.v[7] = -16.000000000000000; + Y.v[8] = -20.000000000000000; + Y.v[9] = 12.000000000000000; + Y.v[10] = -12.000000000000000; + Y.v[11] = 8.000000000000000; + Y.v[12] = 0.000000000000000; + Y.v[13] = 9.000000000000000; + Y.v[14] = 18.000000000000000; + Y.v[15] = 9.000000000000000; +/* +[[ 3. 14. 18. 8.] + [ 6. -9. -18. -11.] + [ 0. -17. -4. 12.] + [ 19. -20. 12. -6.]] +[[ 6. 28. 36. 16.] + [ 12. -18. -36. -22.] + [ 0. -34. -8. 24.] + [ 38. -40. 24. -12.]] +*/ +fprintf(stdout,"SST_Math_Mat44dMultiplyScalar(X,t,Y)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat44dMultiplyScalar(&X, 2.000000000000000,&A); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +assert(fabs((A.v[0])-( 6.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[4])-( 28.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[8])-( 36.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[12])-( 16.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[1])-( 12.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[5])-( -18.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[9])-( -36.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[13])-( -22.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[2])-( 0.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[6])-( -34.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[10])-( -8.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[14])-( 24.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[3])-( 38.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[7])-( -40.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[11])-( 24.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[15])-( -12.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +/* +[[ 3. 14. 18. 8.] + [ 6. -9. -18. -11.] + [ 0. -17. -4. 12.] + [ 19. -20. 12. -6.]] +[[ 6. 28. 36. 16.] + [ 12. -18. -36. -22.] + [ 0. -34. -8. 24.] + [ 38. -40. 24. -12.]] +*/ +fprintf(stdout,"SST_Math_Mat44dMultiplyScalarLocal(A,t)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat44dMultiplyScalarLocal(&A, 2.000000000000000); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +SST_Math_Mat44dMultiplyScalarLocal(&X, 2.000000000000000); +assert(fabs((X.v[0])-( 6.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[4])-( 28.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[8])-( 36.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[12])-( 16.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[1])-( 12.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[5])-( -18.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[9])-( -36.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[13])-( -22.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[2])-( 0.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[6])-( -34.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[10])-( -8.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[14])-( 24.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[3])-( 38.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[7])-( -40.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[11])-( 24.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[15])-( -12.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +/* Resetting test vectors / mats */ + v.v[0] = -1.000000000000000; + v.v[1] = -12.000000000000000; + v.v[2] = 11.000000000000000; + v.v[3] = -3.000000000000000; + X.v[0] = -5.000000000000000; + X.v[1] = -12.000000000000000; + X.v[2] = 16.000000000000000; + X.v[3] = 0.000000000000000; + X.v[4] = 10.000000000000000; + X.v[5] = -20.000000000000000; + X.v[6] = -15.000000000000000; + X.v[7] = 6.000000000000000; + X.v[8] = 0.000000000000000; + X.v[9] = 8.000000000000000; + X.v[10] = -14.000000000000000; + X.v[11] = -18.000000000000000; + X.v[12] = -1.000000000000000; + X.v[13] = 17.000000000000000; + X.v[14] = 15.000000000000000; + X.v[15] = 17.000000000000000; + Y.v[0] = 10.000000000000000; + Y.v[1] = 0.000000000000000; + Y.v[2] = 12.000000000000000; + Y.v[3] = -1.000000000000000; + Y.v[4] = 19.000000000000000; + Y.v[5] = -11.000000000000000; + Y.v[6] = -5.000000000000000; + Y.v[7] = -9.000000000000000; + Y.v[8] = 6.000000000000000; + Y.v[9] = -1.000000000000000; + Y.v[10] = 5.000000000000000; + Y.v[11] = -3.000000000000000; + Y.v[12] = -15.000000000000000; + Y.v[13] = -8.000000000000000; + Y.v[14] = 13.000000000000000; + Y.v[15] = -8.000000000000000; +/* +[[ -5. 10. 0. -1.] + [-12. -20. 8. 17.] + [ 16. -15. -14. 15.] + [ 0. 6. -18. 17.]] +[[ 10. 19. 6. -15.] + [ 0. -11. -1. -8.] + [ 12. -5. 5. 13.] + [ -1. -9. -3. -8.]] +[[ -50. 190. 0. 15.] + [ -0. 220. -8. -136.] + [ 192. 75. -70. 195.] + [ -0. -54. 54. -136.]] +*/ +fprintf(stdout,"SST_Math_Mat44dMultiplyElementwise(X,Y,A)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat44dMultiplyElementwise(&X, &Y, &A); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +assert(fabs((A.v[0])-( -50.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[4])-( 190.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[8])-( 0.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[12])-( 15.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[1])-( -0.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[5])-( 220.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[9])-( -8.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[13])-( -136.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[2])-( 192.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[6])-( 75.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[10])-( -70.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[14])-( 195.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[3])-( -0.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[7])-( -54.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[11])-( 54.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[15])-( -136.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +/* +[[ -5. 10. 0. -1.] + [-12. -20. 8. 17.] + [ 16. -15. -14. 15.] + [ 0. 6. -18. 17.]] +[[ 10. 19. 6. -15.] + [ 0. -11. -1. -8.] + [ 12. -5. 5. 13.] + [ -1. -9. -3. -8.]] +[[ -50. 190. 0. 15.] + [ -0. 220. -8. -136.] + [ 192. 75. -70. 195.] + [ -0. -54. 54. -136.]] +*/ +fprintf(stdout,"SST_Math_Mat44dMultiplyElementwiseLocal(X,Y)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat44dMultiplyElementwiseLocal(&A,&Y); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +SST_Math_Mat44dMultiplyElementwiseLocal(&X,&Y); +assert(fabs((X.v[0])-( -50.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[4])-( 190.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[8])-( 0.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[12])-( 15.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[1])-( -0.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[5])-( 220.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[9])-( -8.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[13])-( -136.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[2])-( 192.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[6])-( 75.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[10])-( -70.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[14])-( 195.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[3])-( -0.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[7])-( -54.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[11])-( 54.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[15])-( -136.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +/* Resetting test vectors / mats */ + v.v[0] = 14.000000000000000; + v.v[1] = 10.000000000000000; + v.v[2] = 0.000000000000000; + v.v[3] = -19.000000000000000; + X.v[0] = 9.000000000000000; + X.v[1] = -15.000000000000000; + X.v[2] = 1.000000000000000; + X.v[3] = -6.000000000000000; + X.v[4] = 0.000000000000000; + X.v[5] = -2.000000000000000; + X.v[6] = -14.000000000000000; + X.v[7] = -14.000000000000000; + X.v[8] = 4.000000000000000; + X.v[9] = -14.000000000000000; + X.v[10] = 14.000000000000000; + X.v[11] = -11.000000000000000; + X.v[12] = 16.000000000000000; + X.v[13] = 15.000000000000000; + X.v[14] = 8.000000000000000; + X.v[15] = -7.000000000000000; + Y.v[0] = -9.000000000000000; + Y.v[1] = -5.000000000000000; + Y.v[2] = 3.000000000000000; + Y.v[3] = 2.000000000000000; + Y.v[4] = -3.000000000000000; + Y.v[5] = -6.000000000000000; + Y.v[6] = 15.000000000000000; + Y.v[7] = -2.000000000000000; + Y.v[8] = 15.000000000000000; + Y.v[9] = -15.000000000000000; + Y.v[10] = -5.000000000000000; + Y.v[11] = -4.000000000000000; + Y.v[12] = 1.000000000000000; + Y.v[13] = -9.000000000000000; + Y.v[14] = -19.000000000000000; + Y.v[15] = 0.000000000000000; +/* +X +[[ 9. 0. 4. 16.] + [-15. -2. -14. 15.] + [ 1. -14. 14. 8.] + [ -6. -14. -11. -7.]] +Y +[[ -9. -3. 15. 1.] + [ -5. -6. -15. -9.] + [ 3. 15. -5. -19.] + [ 2. -2. -4. 0.]] +[[ -37. 1. 51. -67.] + [ 133. -183. -185. 269.] + [ 119. 275. 123. -139.] + [ 77. -49. 203. 329.]] +*/ +fprintf(stdout,"SST_Math_Mat44dMultiplyMatrix(X,Y,A)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat44dMultiplyMatrix(&X,&Y,&A); +t1 = rdtsc(); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +assert(fabs((A.v[0])-( -37.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[4])-( 1.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[8])-( 51.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[12])-( -67.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[1])-( 133.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[5])-( -183.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[9])-( -185.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[13])-( 269.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[2])-( 119.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[6])-( 275.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[10])-( 123.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[14])-( -139.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[3])-( 77.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[7])-( -49.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[11])-( 203.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[15])-( 329.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +/* +X +[[ 9. 0. 4. 16.] + [-15. -2. -14. 15.] + [ 1. -14. 14. 8.] + [ -6. -14. -11. -7.]] +Y +[[ -9. -3. 15. 1.] + [ -5. -6. -15. -9.] + [ 3. 15. -5. -19.] + [ 2. -2. -4. 0.]] +X +[[ -37. 1. 51. -67.] + [ 133. -183. -185. 269.] + [ 119. 275. 123. -139.] + [ 77. -49. 203. 329.]] +*/ +fprintf(stdout,"SST_Math_Mat44dMultiplyMatrixLocal(X,Y)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat44dMultiplyMatrixLocal(&A,&Y); +t1 = rdtsc(); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +SST_Math_Mat44dMultiplyMatrixLocal(&X,&Y); +assert(fabs((X.v[0])-( -37.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[4])-( 1.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[8])-( 51.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[12])-( -67.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[1])-( 133.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[5])-( -183.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[9])-( -185.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[13])-( 269.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[2])-( 119.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[6])-( 275.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[10])-( 123.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[14])-( -139.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[3])-( 77.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[7])-( -49.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[11])-( 203.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[15])-( 329.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +/* Resetting test vectors / mats */ + v.v[0] = 8.000000000000000; + v.v[1] = 8.000000000000000; + v.v[2] = -5.000000000000000; + v.v[3] = -18.000000000000000; + X.v[0] = 10.000000000000000; + X.v[1] = -7.000000000000000; + X.v[2] = 1.000000000000000; + X.v[3] = 1.000000000000000; + X.v[4] = -6.000000000000000; + X.v[5] = -15.000000000000000; + X.v[6] = -3.000000000000000; + X.v[7] = -5.000000000000000; + X.v[8] = -15.000000000000000; + X.v[9] = -2.000000000000000; + X.v[10] = -5.000000000000000; + X.v[11] = -6.000000000000000; + X.v[12] = -1.000000000000000; + X.v[13] = -9.000000000000000; + X.v[14] = -3.000000000000000; + X.v[15] = -5.000000000000000; + Y.v[0] = 6.000000000000000; + Y.v[1] = 17.000000000000000; + Y.v[2] = -16.000000000000000; + Y.v[3] = -8.000000000000000; + Y.v[4] = -1.000000000000000; + Y.v[5] = 14.000000000000000; + Y.v[6] = -7.000000000000000; + Y.v[7] = 8.000000000000000; + Y.v[8] = 9.000000000000000; + Y.v[9] = -1.000000000000000; + Y.v[10] = 11.000000000000000; + Y.v[11] = -17.000000000000000; + Y.v[12] = 6.000000000000000; + Y.v[13] = 5.000000000000000; + Y.v[14] = 11.000000000000000; + Y.v[15] = 8.000000000000000; +/* +X +[[ 10. -6. -15. -1.] + [ -7. -15. -2. -9.] + [ 1. -3. -5. -3.] + [ 1. -5. -6. -5.]] +v +[ 8. 8. -5. -18.] +w +[ 125. -4. 63. 88.] +*/ +i=0; +fprintf(stdout,"SST_Math_Mat44dMultiplyVector(X,v,w)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat44dMultiplyVector(&X,&v,&w); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +assert(fabs((w.v[0])-( 125.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((w.v[1])-( -4.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((w.v[2])-( 63.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((w.v[3])-( 88.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +/* +X +[[ 10. -6. -15. -1.] + [ -7. -15. -2. -9.] + [ 1. -3. -5. -3.] + [ 1. -5. -6. -5.]] +v +[ 8. 8. -5. -18.] +v +[ 125. -4. 63. 88.] +*/ +fprintf(stdout,"SST_Math_Mat44dMultiplyVectorLocal(X,v)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat44dMultiplyVectorLocal(&X,&w); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +SST_Math_Mat44dMultiplyVectorLocal(&X,&v); +assert(fabs((v.v[0])-( 125.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((v.v[1])-( -4.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((v.v[2])-( 63.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((v.v[3])-( 88.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +/* Resetting test vectors / mats */ + v.v[0] = 18.000000000000000; + v.v[1] = -8.000000000000000; + v.v[2] = -11.000000000000000; + v.v[3] = 10.000000000000000; + X.v[0] = -15.000000000000000; + X.v[1] = -6.000000000000000; + X.v[2] = -13.000000000000000; + X.v[3] = -17.000000000000000; + X.v[4] = 0.000000000000000; + X.v[5] = 8.000000000000000; + X.v[6] = -6.000000000000000; + X.v[7] = -18.000000000000000; + X.v[8] = -5.000000000000000; + X.v[9] = 8.000000000000000; + X.v[10] = -8.000000000000000; + X.v[11] = -12.000000000000000; + X.v[12] = -8.000000000000000; + X.v[13] = -17.000000000000000; + X.v[14] = 16.000000000000000; + X.v[15] = -1.000000000000000; + Y.v[0] = 16.000000000000000; + Y.v[1] = -8.000000000000000; + Y.v[2] = 13.000000000000000; + Y.v[3] = -2.000000000000000; + Y.v[4] = 8.000000000000000; + Y.v[5] = 9.000000000000000; + Y.v[6] = -1.000000000000000; + Y.v[7] = -20.000000000000000; + Y.v[8] = -14.000000000000000; + Y.v[9] = 11.000000000000000; + Y.v[10] = -12.000000000000000; + Y.v[11] = -4.000000000000000; + Y.v[12] = -3.000000000000000; + Y.v[13] = -12.000000000000000; + Y.v[14] = -10.000000000000000; + Y.v[15] = 18.000000000000000; +fprintf(stdout,"SST_Math_Mat44dTranspose(X,A)"); +t0 = rdtsc(); +SST_Math_Mat44dTranspose(&X,&A); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +assert(fabs((A.v[0])-( -15.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[4])-( -6.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[8])-( -13.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[12])-( -17.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[1])-( 0.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[5])-( 8.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[9])-( -6.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[13])-( -18.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[2])-( -5.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[6])-( 8.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[10])-( -8.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[14])-( -12.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[3])-( -8.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[7])-( -17.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[11])-( 16.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((A.v[15])-( -1.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +fprintf(stdout,"SST_Math_Mat44dTransposeLocal(X)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat44dTransposeLocal(&A); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +SST_Math_Mat44dTransposeLocal(&X); +assert(fabs((X.v[0])-( -15.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[4])-( -6.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[8])-( -13.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[12])-( -17.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[1])-( 0.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[5])-( 8.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[9])-( -6.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[13])-( -18.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[2])-( -5.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[6])-( 8.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[10])-( -8.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[14])-( -12.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[3])-( -8.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[7])-( -17.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[11])-( 16.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[15])-( -1.000000000000000)) <=100*DBL_EPSILON /* yes this is bad */); +/* +[[-0.55940561 -0.42900339 -0.45263254 -0.54602678] + [-0.22376224 -0.66120998 0.69491745 0.17268919] + [-0.48481819 -0.00459646 -0.35870509 0.79765961] + [-0.63399302 0.61541557 0.42842056 -0.18913578]] +[[ 1.00000000e+00 -5.55111512e-17 0.00000000e+00 2.77555756e-17] + [ -5.55111512e-17 1.00000000e+00 -1.66533454e-16 -6.93889390e-17] + [ 0.00000000e+00 -1.66533454e-16 1.00000000e+00 2.22044605e-16] + [ 2.77555756e-17 -6.93889390e-17 2.22044605e-16 1.00000000e+00]] +*/ +X.v[0] = (double) -0.559405605471151; +X.v[4] = (double) -0.429003386656450; +X.v[8] = (double) -0.452632538505463; +X.v[12] = (double) -0.546026783125930; +X.v[1] = (double) -0.223762242188460; +X.v[5] = (double) -0.661209981656212; +X.v[9] = (double) 0.694917449479891; +X.v[13] = (double) 0.172689193458502; +X.v[2] = (double) -0.484818191408331; +X.v[6] = (double) -0.004596464857033; +X.v[10] = (double) -0.358705093004686; +X.v[14] = (double) 0.797659607879747; +X.v[3] = (double) -0.633993019533971; +X.v[7] = (double) 0.615415572525027; +X.v[11] = (double) 0.428420564103736; +X.v[15] = (double) -0.189135783311693; +fprintf(stdout,"SST_Math_Mat44dTranspose(X,A)"); +t0 = rdtsc(); +SST_Math_Mat44dTranspose(&X,&A); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +fprintf(stdout,"SST_Math_Mat44dMultiplyMatrix(A,X,B)"); +t0 = rdtsc(); +SST_Math_Mat44dMultiplyMatrix(&A,&X,&B); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +/* Check Negative Test */ +assert(!SST_Math_Mat44dCheckOrthonormal(&X)); +X.v[0] = (double) 1.000000000000000; +X.v[4] = (double) 0.000000000000000; +X.v[8] = (double) 0.000000000000000; +X.v[12] = (double) 0.000000000000000; +X.v[1] = (double) 0.000000000000000; +X.v[5] = (double) 1.000000000000000; +X.v[9] = (double) 0.000000000000000; +X.v[13] = (double) 0.000000000000000; +X.v[2] = (double) 0.000000000000000; +X.v[6] = (double) 0.000000000000000; +X.v[10] = (double) 1.000000000000000; +X.v[14] = (double) 0.000000000000000; +X.v[3] = (double) 0.000000000000000; +X.v[7] = (double) 0.000000000000000; +X.v[11] = (double) 0.000000000000000; +X.v[15] = (double) 1.000000000000000; +/* Check Positive Test */ +assert(SST_Math_Mat44dCheckOrthonormal(&X)); +/* Resetting test vectors / mats */ + v.v[0] = -12.000000000000000; + v.v[1] = -12.000000000000000; + v.v[2] = 15.000000000000000; + v.v[3] = -12.000000000000000; + X.v[0] = 15.000000000000000; + X.v[1] = 8.000000000000000; + X.v[2] = 15.000000000000000; + X.v[3] = -17.000000000000000; + X.v[4] = 10.000000000000000; + X.v[5] = 10.000000000000000; + X.v[6] = -5.000000000000000; + X.v[7] = -10.000000000000000; + X.v[8] = 8.000000000000000; + X.v[9] = 3.000000000000000; + X.v[10] = 19.000000000000000; + X.v[11] = 19.000000000000000; + X.v[12] = 4.000000000000000; + X.v[13] = 9.000000000000000; + X.v[14] = 15.000000000000000; + X.v[15] = 11.000000000000000; + Y.v[0] = 1.000000000000000; + Y.v[1] = -17.000000000000000; + Y.v[2] = -3.000000000000000; + Y.v[3] = 2.000000000000000; + Y.v[4] = 15.000000000000000; + Y.v[5] = 8.000000000000000; + Y.v[6] = 3.000000000000000; + Y.v[7] = -6.000000000000000; + Y.v[8] = -7.000000000000000; + Y.v[9] = -6.000000000000000; + Y.v[10] = -15.000000000000000; + Y.v[11] = 1.000000000000000; + Y.v[12] = -18.000000000000000; + Y.v[13] = 6.000000000000000; + Y.v[14] = 11.000000000000000; + Y.v[15] = 18.000000000000000; +/* +[[ 0.00320783 -0.019247 0.03545501 -0.03376667] + [ 0.06084754 0.03491474 -0.05379031 0.02265744] + [ 0.09378693 -0.06272159 -0.01603917 0.03908492] + [-0.1017221 0.1103326 0.03359784 -0.00818842]] +*/ +fprintf(stdout,"SST_Math_Mat44dInvert(X,B)\n"); +t0 = rdtsc(); +SST_Math_Mat44dInvert(&X,&B); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +fprintf(stdout,"B[%d][%d] = %24.15lf\n",0,0,B.v[0]); +fprintf(stdout,"B[%d][%d] = %24.15lf\n",0,1,B.v[1]); +fprintf(stdout,"B[%d][%d] = %24.15lf\n",0,2,B.v[2]); +fprintf(stdout,"B[%d][%d] = %24.15lf\n",0,3,B.v[3]); +fprintf(stdout,"B[%d][%d] = %24.15lf\n",1,0,B.v[4]); +fprintf(stdout,"B[%d][%d] = %24.15lf\n",1,1,B.v[5]); +fprintf(stdout,"B[%d][%d] = %24.15lf\n",1,2,B.v[6]); +fprintf(stdout,"B[%d][%d] = %24.15lf\n",1,3,B.v[7]); +fprintf(stdout,"B[%d][%d] = %24.15lf\n",2,0,B.v[8]); +fprintf(stdout,"B[%d][%d] = %24.15lf\n",2,1,B.v[9]); +fprintf(stdout,"B[%d][%d] = %24.15lf\n",2,2,B.v[10]); +fprintf(stdout,"B[%d][%d] = %24.15lf\n",2,3,B.v[11]); +fprintf(stdout,"B[%d][%d] = %24.15lf\n",3,0,B.v[12]); +fprintf(stdout,"B[%d][%d] = %24.15lf\n",3,1,B.v[13]); +fprintf(stdout,"B[%d][%d] = %24.15lf\n",3,2,B.v[14]); +fprintf(stdout,"B[%d][%d] = %24.15lf\n",3,3,B.v[15]); +assert(fabs((B.v[0])-( 0.003207833867972)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((B.v[4])-( -0.019247003207834)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((B.v[8])-( 0.035455005909168)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((B.v[12])-( -0.033766672294445)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((B.v[1])-( 0.060847543474591)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((B.v[5])-( 0.034914739152457)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((B.v[9])-( -0.053790308965051)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((B.v[13])-( 0.022657437109573)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((B.v[2])-( 0.093786932297822)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((B.v[6])-( -0.062721593786932)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((B.v[10])-( -0.016039169339862)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((B.v[14])-( 0.039084923180821)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((B.v[3])-( -0.101722100287017)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((B.v[7])-( 0.110332601722100)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((B.v[11])-( 0.033597838932973)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((B.v[15])-( -0.008188418031403)) <=100*DBL_EPSILON /* yes this is bad */); +/* Resetting test vectors / mats */ + v.v[0] = 5.000000000000000; + v.v[1] = -17.000000000000000; + v.v[2] = -17.000000000000000; + v.v[3] = 10.000000000000000; + X.v[0] = 16.000000000000000; + X.v[1] = -11.000000000000000; + X.v[2] = -11.000000000000000; + X.v[3] = 14.000000000000000; + X.v[4] = 3.000000000000000; + X.v[5] = -10.000000000000000; + X.v[6] = 15.000000000000000; + X.v[7] = -3.000000000000000; + X.v[8] = 7.000000000000000; + X.v[9] = -14.000000000000000; + X.v[10] = 17.000000000000000; + X.v[11] = -4.000000000000000; + X.v[12] = 8.000000000000000; + X.v[13] = 1.000000000000000; + X.v[14] = -1.000000000000000; + X.v[15] = -10.000000000000000; + Y.v[0] = -1.000000000000000; + Y.v[1] = 19.000000000000000; + Y.v[2] = -19.000000000000000; + Y.v[3] = -12.000000000000000; + Y.v[4] = -5.000000000000000; + Y.v[5] = 16.000000000000000; + Y.v[6] = 11.000000000000000; + Y.v[7] = 1.000000000000000; + Y.v[8] = 2.000000000000000; + Y.v[9] = 13.000000000000000; + Y.v[10] = 5.000000000000000; + Y.v[11] = 17.000000000000000; + Y.v[12] = 11.000000000000000; + Y.v[13] = 14.000000000000000; + Y.v[14] = 3.000000000000000; + Y.v[15] = -17.000000000000000; +/* +[[ 0.14584812 0.16926899 0.10823279 0.12278211] + [ 1.2264017 1.84669979 1.26046842 1.0397445 ] + [-0.97444996 -1.50319375 -0.97374024 -0.83250532] + [ 0.22604684 0.28424414 0.16288148 0.09297374]] +*/ +fprintf(stdout,"SST_Math_Mat44dInvert(X,B)\n"); +fflush(stdout); +fprintf(stdout,"SST_Math_Mat44dInvertLocal(X,B)\n"); +t0 = rdtsc(); +SST_Math_Mat44dInvertLocal(&X); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +fflush(stdout); +assert(fabs((X.v[0])-( 0.145848119233499)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[4])-( 0.169268985095813)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[8])-( 0.108232789212207)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[12])-( 0.122782114975160)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[1])-( 1.226401703335700)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[5])-( 1.846699787083038)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[9])-( 1.260468417317247)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[13])-( 1.039744499645138)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[2])-( -0.974449964513840)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[6])-( -1.503193754435770)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[10])-( -0.973740241305891)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[14])-( -0.832505322924060)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[3])-( 0.226046841731725)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[7])-( 0.284244144783534)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[11])-( 0.162881476224273)) <=100*DBL_EPSILON /* yes this is bad */); +assert(fabs((X.v[15])-( 0.092973740241306)) <=100*DBL_EPSILON /* yes this is bad */); +fprintf(stdout,"\n==== SST_Math_Mat44dtest_fxn COMPLETE ====\n"); +return 0; +} diff --git a/libsst-math/SST_Mat44f.c b/libsst-math/SST_Mat44f.c new file mode 100644 index 0000000..aabcd54 --- /dev/null +++ b/libsst-math/SST_Mat44f.c @@ -0,0 +1,946 @@ +/* + AUTOMATICALLY GENERATED FILE - DO NOT EDIT! + Please change MatrixNxN.py and re-run it +*/ +/* Generated with ./MatrixNxN.py n = 4, TYPE = float */ + +#include <float.h> +#include <pstdbool.h> +#include <stdio.h> +#include <math.h> /* for sqrt functions */ +#include <stdlib.h> /* for the abs/labs functions */ +#include <SST/SST_Build.h> + +#include <SST/SST_Mat44.h> +#include <SST/SST_Vec4.h> +void SST_Math_Mat44fAdd(const SST_Mat44f* RESTRICT _A, const SST_Mat44f* RESTRICT _B, SST_Mat44f* RESTRICT _out) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + SST_ASSUME_ALIGNED(_out,16); + + _out->v[0] = _A->v[0] + _B->v[0]; + _out->v[1] = _A->v[1] + _B->v[1]; + _out->v[2] = _A->v[2] + _B->v[2]; + _out->v[3] = _A->v[3] + _B->v[3]; + _out->v[4] = _A->v[4] + _B->v[4]; + _out->v[5] = _A->v[5] + _B->v[5]; + _out->v[6] = _A->v[6] + _B->v[6]; + _out->v[7] = _A->v[7] + _B->v[7]; + _out->v[8] = _A->v[8] + _B->v[8]; + _out->v[9] = _A->v[9] + _B->v[9]; + _out->v[10] = _A->v[10] + _B->v[10]; + _out->v[11] = _A->v[11] + _B->v[11]; + _out->v[12] = _A->v[12] + _B->v[12]; + _out->v[13] = _A->v[13] + _B->v[13]; + _out->v[14] = _A->v[14] + _B->v[14]; + _out->v[15] = _A->v[15] + _B->v[15]; +} + +/******************************************************************************/ + +void SST_Math_Mat44fAddLocal(SST_Mat44f* RESTRICT _A, const SST_Mat44f* RESTRICT _B) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + + _A->v[0] += _B->v[0]; + _A->v[1] += _B->v[1]; + _A->v[2] += _B->v[2]; + _A->v[3] += _B->v[3]; + _A->v[4] += _B->v[4]; + _A->v[5] += _B->v[5]; + _A->v[6] += _B->v[6]; + _A->v[7] += _B->v[7]; + _A->v[8] += _B->v[8]; + _A->v[9] += _B->v[9]; + _A->v[10] += _B->v[10]; + _A->v[11] += _B->v[11]; + _A->v[12] += _B->v[12]; + _A->v[13] += _B->v[13]; + _A->v[14] += _B->v[14]; + _A->v[15] += _B->v[15]; +} + +/******************************************************************************/ + +void SST_Math_Mat44fSubtract(const SST_Mat44f* RESTRICT _A, const SST_Mat44f* RESTRICT _B, SST_Mat44f* RESTRICT _out) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + SST_ASSUME_ALIGNED(_out,16); + + _out->v[0] = _A->v[0] - _B->v[0]; + _out->v[1] = _A->v[1] - _B->v[1]; + _out->v[2] = _A->v[2] - _B->v[2]; + _out->v[3] = _A->v[3] - _B->v[3]; + _out->v[4] = _A->v[4] - _B->v[4]; + _out->v[5] = _A->v[5] - _B->v[5]; + _out->v[6] = _A->v[6] - _B->v[6]; + _out->v[7] = _A->v[7] - _B->v[7]; + _out->v[8] = _A->v[8] - _B->v[8]; + _out->v[9] = _A->v[9] - _B->v[9]; + _out->v[10] = _A->v[10] - _B->v[10]; + _out->v[11] = _A->v[11] - _B->v[11]; + _out->v[12] = _A->v[12] - _B->v[12]; + _out->v[13] = _A->v[13] - _B->v[13]; + _out->v[14] = _A->v[14] - _B->v[14]; + _out->v[15] = _A->v[15] - _B->v[15]; +} + +/******************************************************************************/ + +void SST_Math_Mat44fSubtractLocal(SST_Mat44f* RESTRICT _A, const SST_Mat44f* RESTRICT _B) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + + _A->v[0] -= _B->v[0]; + _A->v[1] -= _B->v[1]; + _A->v[2] -= _B->v[2]; + _A->v[3] -= _B->v[3]; + _A->v[4] -= _B->v[4]; + _A->v[5] -= _B->v[5]; + _A->v[6] -= _B->v[6]; + _A->v[7] -= _B->v[7]; + _A->v[8] -= _B->v[8]; + _A->v[9] -= _B->v[9]; + _A->v[10] -= _B->v[10]; + _A->v[11] -= _B->v[11]; + _A->v[12] -= _B->v[12]; + _A->v[13] -= _B->v[13]; + _A->v[14] -= _B->v[14]; + _A->v[15] -= _B->v[15]; +} + +/******************************************************************************/ + +void SST_Math_Mat44fMultiplyElementwise(const SST_Mat44f* RESTRICT _A, const SST_Mat44f* RESTRICT _B, SST_Mat44f* RESTRICT _out) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + SST_ASSUME_ALIGNED(_out,16); + + _out->v[0] = _A->v[0] * _B->v[0]; + _out->v[1] = _A->v[1] * _B->v[1]; + _out->v[2] = _A->v[2] * _B->v[2]; + _out->v[3] = _A->v[3] * _B->v[3]; + _out->v[4] = _A->v[4] * _B->v[4]; + _out->v[5] = _A->v[5] * _B->v[5]; + _out->v[6] = _A->v[6] * _B->v[6]; + _out->v[7] = _A->v[7] * _B->v[7]; + _out->v[8] = _A->v[8] * _B->v[8]; + _out->v[9] = _A->v[9] * _B->v[9]; + _out->v[10] = _A->v[10] * _B->v[10]; + _out->v[11] = _A->v[11] * _B->v[11]; + _out->v[12] = _A->v[12] * _B->v[12]; + _out->v[13] = _A->v[13] * _B->v[13]; + _out->v[14] = _A->v[14] * _B->v[14]; + _out->v[15] = _A->v[15] * _B->v[15]; +} + +/******************************************************************************/ + +void SST_Math_Mat44fMultiplyElementwiseLocal(SST_Mat44f* RESTRICT _A, const SST_Mat44f* RESTRICT _B) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + + _A->v[0] *= _B->v[0]; + _A->v[1] *= _B->v[1]; + _A->v[2] *= _B->v[2]; + _A->v[3] *= _B->v[3]; + _A->v[4] *= _B->v[4]; + _A->v[5] *= _B->v[5]; + _A->v[6] *= _B->v[6]; + _A->v[7] *= _B->v[7]; + _A->v[8] *= _B->v[8]; + _A->v[9] *= _B->v[9]; + _A->v[10] *= _B->v[10]; + _A->v[11] *= _B->v[11]; + _A->v[12] *= _B->v[12]; + _A->v[13] *= _B->v[13]; + _A->v[14] *= _B->v[14]; + _A->v[15] *= _B->v[15]; +} + +/******************************************************************************/ + +void SST_Math_Mat44fMultiplyScalar(const SST_Mat44f* RESTRICT _A, const float k, SST_Mat44f* RESTRICT _out) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_out,16); + + _out->v[0] = _A->v[0] * k; + _out->v[1] = _A->v[1] * k; + _out->v[2] = _A->v[2] * k; + _out->v[3] = _A->v[3] * k; + _out->v[4] = _A->v[4] * k; + _out->v[5] = _A->v[5] * k; + _out->v[6] = _A->v[6] * k; + _out->v[7] = _A->v[7] * k; + _out->v[8] = _A->v[8] * k; + _out->v[9] = _A->v[9] * k; + _out->v[10] = _A->v[10] * k; + _out->v[11] = _A->v[11] * k; + _out->v[12] = _A->v[12] * k; + _out->v[13] = _A->v[13] * k; + _out->v[14] = _A->v[14] * k; + _out->v[15] = _A->v[15] * k; +} + +/******************************************************************************/ + +void SST_Math_Mat44fMultiplyScalarLocal(SST_Mat44f* RESTRICT _A, const float k) +{ + SST_ASSUME_ALIGNED(_A,16); + + _A->v[0] *= k; + _A->v[1] *= k; + _A->v[2] *= k; + _A->v[3] *= k; + _A->v[4] *= k; + _A->v[5] *= k; + _A->v[6] *= k; + _A->v[7] *= k; + _A->v[8] *= k; + _A->v[9] *= k; + _A->v[10] *= k; + _A->v[11] *= k; + _A->v[12] *= k; + _A->v[13] *= k; + _A->v[14] *= k; + _A->v[15] *= k; +} + +/******************************************************************************/ + + +void SST_Math_Mat44fMultiplyMatrix(const SST_Mat44f* _A, const SST_Mat44f* RESTRICT _B, SST_Mat44f* RESTRICT _out) +{ +SST_ASSUME_ALIGNED(_A,16); +SST_ASSUME_ALIGNED(_B,16); +SST_ASSUME_ALIGNED(_out,16); +_out->v[ 0] = _A->v[ 0]*_B->v[ 0]+_A->v[ 4]*_B->v[ 1]+_A->v[ 8]*_B->v[ 2]+_A->v[12]*_B->v[ 3]; +_out->v[ 4] = _A->v[ 0]*_B->v[ 4]+_A->v[ 4]*_B->v[ 5]+_A->v[ 8]*_B->v[ 6]+_A->v[12]*_B->v[ 7]; +_out->v[ 8] = _A->v[ 0]*_B->v[ 8]+_A->v[ 4]*_B->v[ 9]+_A->v[ 8]*_B->v[10]+_A->v[12]*_B->v[11]; +_out->v[12] = _A->v[ 0]*_B->v[12]+_A->v[ 4]*_B->v[13]+_A->v[ 8]*_B->v[14]+_A->v[12]*_B->v[15]; +_out->v[ 1] = _A->v[ 1]*_B->v[ 0]+_A->v[ 5]*_B->v[ 1]+_A->v[ 9]*_B->v[ 2]+_A->v[13]*_B->v[ 3]; +_out->v[ 5] = _A->v[ 1]*_B->v[ 4]+_A->v[ 5]*_B->v[ 5]+_A->v[ 9]*_B->v[ 6]+_A->v[13]*_B->v[ 7]; +_out->v[ 9] = _A->v[ 1]*_B->v[ 8]+_A->v[ 5]*_B->v[ 9]+_A->v[ 9]*_B->v[10]+_A->v[13]*_B->v[11]; +_out->v[13] = _A->v[ 1]*_B->v[12]+_A->v[ 5]*_B->v[13]+_A->v[ 9]*_B->v[14]+_A->v[13]*_B->v[15]; +_out->v[ 2] = _A->v[ 2]*_B->v[ 0]+_A->v[ 6]*_B->v[ 1]+_A->v[10]*_B->v[ 2]+_A->v[14]*_B->v[ 3]; +_out->v[ 6] = _A->v[ 2]*_B->v[ 4]+_A->v[ 6]*_B->v[ 5]+_A->v[10]*_B->v[ 6]+_A->v[14]*_B->v[ 7]; +_out->v[10] = _A->v[ 2]*_B->v[ 8]+_A->v[ 6]*_B->v[ 9]+_A->v[10]*_B->v[10]+_A->v[14]*_B->v[11]; +_out->v[14] = _A->v[ 2]*_B->v[12]+_A->v[ 6]*_B->v[13]+_A->v[10]*_B->v[14]+_A->v[14]*_B->v[15]; +_out->v[ 3] = _A->v[ 3]*_B->v[ 0]+_A->v[ 7]*_B->v[ 1]+_A->v[11]*_B->v[ 2]+_A->v[15]*_B->v[ 3]; +_out->v[ 7] = _A->v[ 3]*_B->v[ 4]+_A->v[ 7]*_B->v[ 5]+_A->v[11]*_B->v[ 6]+_A->v[15]*_B->v[ 7]; +_out->v[11] = _A->v[ 3]*_B->v[ 8]+_A->v[ 7]*_B->v[ 9]+_A->v[11]*_B->v[10]+_A->v[15]*_B->v[11]; +_out->v[15] = _A->v[ 3]*_B->v[12]+_A->v[ 7]*_B->v[13]+_A->v[11]*_B->v[14]+_A->v[15]*_B->v[15]; +} +void SST_Math_Mat44fMultiplyMatrixLocal(SST_Mat44f* RESTRICT _A, const SST_Mat44f* RESTRICT _B) +{ + float tmp[16]; + SST_ASSUME_ALIGNED(_A,16); +SST_ASSUME_ALIGNED(_B,16); +tmp[ 0] = _A->v[ 0]*_B->v[ 0]+_A->v[ 4]*_B->v[ 1]+_A->v[ 8]*_B->v[ 2]+_A->v[12]*_B->v[ 3]; +tmp[ 4] = _A->v[ 0]*_B->v[ 4]+_A->v[ 4]*_B->v[ 5]+_A->v[ 8]*_B->v[ 6]+_A->v[12]*_B->v[ 7]; +tmp[ 8] = _A->v[ 0]*_B->v[ 8]+_A->v[ 4]*_B->v[ 9]+_A->v[ 8]*_B->v[10]+_A->v[12]*_B->v[11]; +tmp[12] = _A->v[ 0]*_B->v[12]+_A->v[ 4]*_B->v[13]+_A->v[ 8]*_B->v[14]+_A->v[12]*_B->v[15]; +_A->v[0] = tmp[0]; +_A->v[4] = tmp[4]; +_A->v[8] = tmp[8]; +_A->v[12] = tmp[12]; + + +tmp[ 1] = _A->v[ 1]*_B->v[ 0]+_A->v[ 5]*_B->v[ 1]+_A->v[ 9]*_B->v[ 2]+_A->v[13]*_B->v[ 3]; +tmp[ 5] = _A->v[ 1]*_B->v[ 4]+_A->v[ 5]*_B->v[ 5]+_A->v[ 9]*_B->v[ 6]+_A->v[13]*_B->v[ 7]; +tmp[ 9] = _A->v[ 1]*_B->v[ 8]+_A->v[ 5]*_B->v[ 9]+_A->v[ 9]*_B->v[10]+_A->v[13]*_B->v[11]; +tmp[13] = _A->v[ 1]*_B->v[12]+_A->v[ 5]*_B->v[13]+_A->v[ 9]*_B->v[14]+_A->v[13]*_B->v[15]; +_A->v[1] = tmp[1]; +_A->v[5] = tmp[5]; +_A->v[9] = tmp[9]; +_A->v[13] = tmp[13]; + + +tmp[ 2] = _A->v[ 2]*_B->v[ 0]+_A->v[ 6]*_B->v[ 1]+_A->v[10]*_B->v[ 2]+_A->v[14]*_B->v[ 3]; +tmp[ 6] = _A->v[ 2]*_B->v[ 4]+_A->v[ 6]*_B->v[ 5]+_A->v[10]*_B->v[ 6]+_A->v[14]*_B->v[ 7]; +tmp[10] = _A->v[ 2]*_B->v[ 8]+_A->v[ 6]*_B->v[ 9]+_A->v[10]*_B->v[10]+_A->v[14]*_B->v[11]; +tmp[14] = _A->v[ 2]*_B->v[12]+_A->v[ 6]*_B->v[13]+_A->v[10]*_B->v[14]+_A->v[14]*_B->v[15]; +_A->v[2] = tmp[2]; +_A->v[6] = tmp[6]; +_A->v[10] = tmp[10]; +_A->v[14] = tmp[14]; + + +tmp[ 3] = _A->v[ 3]*_B->v[ 0]+_A->v[ 7]*_B->v[ 1]+_A->v[11]*_B->v[ 2]+_A->v[15]*_B->v[ 3]; +tmp[ 7] = _A->v[ 3]*_B->v[ 4]+_A->v[ 7]*_B->v[ 5]+_A->v[11]*_B->v[ 6]+_A->v[15]*_B->v[ 7]; +tmp[11] = _A->v[ 3]*_B->v[ 8]+_A->v[ 7]*_B->v[ 9]+_A->v[11]*_B->v[10]+_A->v[15]*_B->v[11]; +tmp[15] = _A->v[ 3]*_B->v[12]+_A->v[ 7]*_B->v[13]+_A->v[11]*_B->v[14]+_A->v[15]*_B->v[15]; +_A->v[3] = tmp[3]; +_A->v[7] = tmp[7]; +_A->v[11] = tmp[11]; +_A->v[15] = tmp[15]; + + +} +void SST_Math_Mat44fMultiplyVector(const SST_Mat44f* RESTRICT _A, const SST_Vec4f* RESTRICT _v, SST_Vec4f* RESTRICT _out) +{ +SST_ASSUME_ALIGNED(_A,16); +SST_ASSUME_ALIGNED(_v,16); +SST_ASSUME_ALIGNED(_out,16); +_out->v[ 0] = _A->v[ 0]*_v->v[0]+_A->v[ 4]*_v->v[1]+_A->v[ 8]*_v->v[2]+_A->v[12]*_v->v[3]; +_out->v[ 1] = _A->v[ 1]*_v->v[0]+_A->v[ 5]*_v->v[1]+_A->v[ 9]*_v->v[2]+_A->v[13]*_v->v[3]; +_out->v[ 2] = _A->v[ 2]*_v->v[0]+_A->v[ 6]*_v->v[1]+_A->v[10]*_v->v[2]+_A->v[14]*_v->v[3]; +_out->v[ 3] = _A->v[ 3]*_v->v[0]+_A->v[ 7]*_v->v[1]+_A->v[11]*_v->v[2]+_A->v[15]*_v->v[3]; +} +void SST_Math_Mat44fMultiplyVectorLocal(const SST_Mat44f* RESTRICT _A, SST_Vec4f* RESTRICT _v) +{ +float tmp[4]; +SST_ASSUME_ALIGNED(_A,16); +SST_ASSUME_ALIGNED(_v,16); +tmp[ 0] = _A->v[ 0]*_v->v[0]+_A->v[ 4]*_v->v[1]+_A->v[ 8]*_v->v[2]+_A->v[12]*_v->v[3]; +tmp[ 1] = _A->v[ 1]*_v->v[0]+_A->v[ 5]*_v->v[1]+_A->v[ 9]*_v->v[2]+_A->v[13]*_v->v[3]; +tmp[ 2] = _A->v[ 2]*_v->v[0]+_A->v[ 6]*_v->v[1]+_A->v[10]*_v->v[2]+_A->v[14]*_v->v[3]; +tmp[ 3] = _A->v[ 3]*_v->v[0]+_A->v[ 7]*_v->v[1]+_A->v[11]*_v->v[2]+_A->v[15]*_v->v[3]; +_v->v[0] = tmp[0]; +_v->v[1] = tmp[1]; +_v->v[2] = tmp[2]; +_v->v[3] = tmp[3]; +} +void SST_Math_Mat44fTranspose(const SST_Mat44f* RESTRICT _A, SST_Mat44f* RESTRICT _out) +{ +SST_ASSUME_ALIGNED(_A,16); +SST_ASSUME_ALIGNED(_out,16); +_out->v[ 0] = _A->v[ 0]; +_out->v[ 1] = _A->v[ 4]; +_out->v[ 2] = _A->v[ 8]; +_out->v[ 3] = _A->v[12]; +_out->v[ 4] = _A->v[ 1]; +_out->v[ 5] = _A->v[ 5]; +_out->v[ 6] = _A->v[ 9]; +_out->v[ 7] = _A->v[13]; +_out->v[ 8] = _A->v[ 2]; +_out->v[ 9] = _A->v[ 6]; +_out->v[10] = _A->v[10]; +_out->v[11] = _A->v[14]; +_out->v[12] = _A->v[ 3]; +_out->v[13] = _A->v[ 7]; +_out->v[14] = _A->v[11]; +_out->v[15] = _A->v[15]; +} +void SST_Math_Mat44fTransposeLocal(SST_Mat44f* RESTRICT _A) +{ +float tmp[4]; +SST_ASSUME_ALIGNED(_A,16); +tmp[1] = _A->v[ 4]; +_A->v[ 4] = _A->v[ 1]; +_A->v[ 1] = tmp[1]; +tmp[2] = _A->v[ 8]; +_A->v[ 8] = _A->v[ 2]; +_A->v[ 2] = tmp[2]; +tmp[3] = _A->v[12]; +_A->v[12] = _A->v[ 3]; +_A->v[ 3] = tmp[3]; +tmp[2] = _A->v[ 9]; +_A->v[ 9] = _A->v[ 6]; +_A->v[ 6] = tmp[2]; +tmp[3] = _A->v[13]; +_A->v[13] = _A->v[ 7]; +_A->v[ 7] = tmp[3]; +tmp[3] = _A->v[14]; +_A->v[14] = _A->v[11]; +_A->v[11] = tmp[3]; +} +bool SST_Math_Mat44fCheckOrthonormal(const SST_Mat44f* _A) +{ +const float diag = -_A->v[0]*_A->v[0] -_A->v[1]*_A->v[1] -_A->v[2]*_A->v[2] -_A->v[3]*_A->v[3] -_A->v[4]*_A->v[4] -_A->v[5]*_A->v[5] -_A->v[6]*_A->v[6] -_A->v[7]*_A->v[7] -_A->v[8]*_A->v[8] -_A->v[9]*_A->v[9] -_A->v[10]*_A->v[10] -_A->v[11]*_A->v[11] -_A->v[12]*_A->v[12] -_A->v[13]*_A->v[13] -_A->v[14]*_A->v[14] -_A->v[15]*_A->v[15]; +const float odiag = _A->v[0]*_A->v[4]+ _A->v[1]*_A->v[5]+ _A->v[2]*_A->v[6]+ _A->v[3]*_A->v[7]+ _A->v[0]*_A->v[8]+ _A->v[1]*_A->v[9]+ _A->v[2]*_A->v[10]+ _A->v[3]*_A->v[11]+ _A->v[0]*_A->v[12]+ _A->v[1]*_A->v[13]+ _A->v[2]*_A->v[14]+ _A->v[3]*_A->v[15]+ _A->v[4]*_A->v[0]+ _A->v[5]*_A->v[1]+ _A->v[6]*_A->v[2]+ _A->v[7]*_A->v[3]+ _A->v[4]*_A->v[8]+ _A->v[5]*_A->v[9]+ _A->v[6]*_A->v[10]+ _A->v[7]*_A->v[11]+ _A->v[4]*_A->v[12]+ _A->v[5]*_A->v[13]+ _A->v[6]*_A->v[14]+ _A->v[7]*_A->v[15]+ _A->v[8]*_A->v[0]+ _A->v[9]*_A->v[1]+ _A->v[10]*_A->v[2]+ _A->v[11]*_A->v[3]+ _A->v[8]*_A->v[4]+ _A->v[9]*_A->v[5]+ _A->v[10]*_A->v[6]+ _A->v[11]*_A->v[7]+ _A->v[8]*_A->v[12]+ _A->v[9]*_A->v[13]+ _A->v[10]*_A->v[14]+ _A->v[11]*_A->v[15]+ _A->v[12]*_A->v[0]+ _A->v[13]*_A->v[1]+ _A->v[14]*_A->v[2]+ _A->v[15]*_A->v[3]+ _A->v[12]*_A->v[4]+ _A->v[13]*_A->v[5]+ _A->v[14]*_A->v[6]+ _A->v[15]*_A->v[7]+ _A->v[12]*_A->v[8]+ _A->v[13]*_A->v[9]+ _A->v[14]*_A->v[10]+ _A->v[15]*_A->v[11]; +SST_ASSUME_ALIGNED(_A,16); +return +((fabsf(4.000000f+diag)) <= 100*FLT_EPSILON) & +((fabsf(odiag)) <= 100*FLT_EPSILON); + + +} +float SST_Math_Mat44fDeterminant(const SST_Mat44f* _A) +{ + const float a10151411 = _A->v[10]*_A->v[15]-_A->v[11]*_A->v[14]; + const float a9151311 = _A->v[6]*_A->v[15]-_A->v[7]*_A->v[14]; + const float a9141310 = _A->v[6]*_A->v[11]-_A->v[7]*_A->v[10]; + const float a8151112 = _A->v[2]*_A->v[15]-_A->v[14]*_A->v[3]; + const float a8141210 = _A->v[2]*_A->v[11]-_A->v[3]*_A->v[10]; + const float a813129 = _A->v[2]*_A->v[7]-_A->v[3]*_A->v[6]; + const float result = _A->v[0]*(_A->v[5]*a10151411-_A->v[9]*a9151311+_A->v[13]*a9141310)-_A->v[4]*(_A->v[1]*a10151411-_A->v[9]*a8151112+_A->v[13]*a8141210)+_A->v[8]*(_A->v[1]*a9151311 -_A->v[5]*a8151112+_A->v[13]*a813129)-_A->v[12]*(_A->v[1]*a9141310 -_A->v[5]*a8141210+_A->v[9]*a813129); + SST_ASSUME_ALIGNED(_A,16); + return result; +} +void SST_Math_Mat44fInvert(const SST_Mat44f* RESTRICT _A, SST_Mat44f* RESTRICT _out) +{ +/* Gaussian Elimination */ +#define _A(i,j) _A->v[i+4*j] +#define _out(i,j) _out->v[i+4*j] +#define Pinv(i,j) Pinv.v[i+4*j] +float aij; +float norm_aij; +SST_Mat44f Pinv; +SST_ASSUME_ALIGNED(_A,16); +/* Set _out to the identity */ +_out(0,0) = 1.000000f; +_out(1,0) = 0.000000f; +_out(2,0) = 0.000000f; +_out(3,0) = 0.000000f; +_out(0,1) = 0.000000f; +_out(1,1) = 1.000000f; +_out(2,1) = 0.000000f; +_out(3,1) = 0.000000f; +_out(0,2) = 0.000000f; +_out(1,2) = 0.000000f; +_out(2,2) = 1.000000f; +_out(3,2) = 0.000000f; +_out(0,3) = 0.000000f; +_out(1,3) = 0.000000f; +_out(2,3) = 0.000000f; +_out(3,3) = 1.000000f; +/* Set _Pinv to _A so we don't overwrite it */ +Pinv.v[0] = _A->v[0]; +Pinv.v[1] = _A->v[1]; +Pinv.v[2] = _A->v[2]; +Pinv.v[3] = _A->v[3]; +Pinv.v[4] = _A->v[4]; +Pinv.v[5] = _A->v[5]; +Pinv.v[6] = _A->v[6]; +Pinv.v[7] = _A->v[7]; +Pinv.v[8] = _A->v[8]; +Pinv.v[9] = _A->v[9]; +Pinv.v[10] = _A->v[10]; +Pinv.v[11] = _A->v[11]; +Pinv.v[12] = _A->v[12]; +Pinv.v[13] = _A->v[13]; +Pinv.v[14] = _A->v[14]; +Pinv.v[15] = _A->v[15]; +/* Put in Reduced Row Echelon form */ +/* Note that we can set the entry to 0, or just calculate it. + The latter will be helpful when recognizing that these are all simple vector moves */ +/* Sort if need be */ +aij = -Pinv(1,0) / Pinv(0,0) ; +Pinv(1,0) += aij*Pinv(0,0) ; +Pinv(1,1) += aij*Pinv(0,1) ; +Pinv(1,2) += aij*Pinv(0,2) ; +Pinv(1,3) += aij*Pinv(0,3) ; +_out(1,0) += aij*_out(0,0) ; +_out(1,1) += aij*_out(0,1) ; +_out(1,2) += aij*_out(0,2) ; +_out(1,3) += aij*_out(0,3) ; +/* Sort if need be */ +aij = -Pinv(2,0) / Pinv(0,0) ; +Pinv(2,0) += aij*Pinv(0,0) ; +Pinv(2,1) += aij*Pinv(0,1) ; +Pinv(2,2) += aij*Pinv(0,2) ; +Pinv(2,3) += aij*Pinv(0,3) ; +_out(2,0) += aij*_out(0,0) ; +_out(2,1) += aij*_out(0,1) ; +_out(2,2) += aij*_out(0,2) ; +_out(2,3) += aij*_out(0,3) ; +/* Sort if need be */ +aij = -Pinv(3,0) / Pinv(0,0) ; +Pinv(3,0) += aij*Pinv(0,0) ; +Pinv(3,1) += aij*Pinv(0,1) ; +Pinv(3,2) += aij*Pinv(0,2) ; +Pinv(3,3) += aij*Pinv(0,3) ; +_out(3,0) += aij*_out(0,0) ; +_out(3,1) += aij*_out(0,1) ; +_out(3,2) += aij*_out(0,2) ; +_out(3,3) += aij*_out(0,3) ; +/* Sort if need be */ +aij = -Pinv(2,1) / Pinv(1,1) ; +Pinv(2,0) += aij*Pinv(1,0) ; +Pinv(2,1) += aij*Pinv(1,1) ; +Pinv(2,2) += aij*Pinv(1,2) ; +Pinv(2,3) += aij*Pinv(1,3) ; +_out(2,0) += aij*_out(1,0) ; +_out(2,1) += aij*_out(1,1) ; +_out(2,2) += aij*_out(1,2) ; +_out(2,3) += aij*_out(1,3) ; +/* Sort if need be */ +aij = -Pinv(3,1) / Pinv(1,1) ; +Pinv(3,0) += aij*Pinv(1,0) ; +Pinv(3,1) += aij*Pinv(1,1) ; +Pinv(3,2) += aij*Pinv(1,2) ; +Pinv(3,3) += aij*Pinv(1,3) ; +_out(3,0) += aij*_out(1,0) ; +_out(3,1) += aij*_out(1,1) ; +_out(3,2) += aij*_out(1,2) ; +_out(3,3) += aij*_out(1,3) ; +/* Sort if need be */ +aij = -Pinv(3,2) / Pinv(2,2) ; +Pinv(3,0) += aij*Pinv(2,0) ; +Pinv(3,1) += aij*Pinv(2,1) ; +Pinv(3,2) += aij*Pinv(2,2) ; +Pinv(3,3) += aij*Pinv(2,3) ; +_out(3,0) += aij*_out(2,0) ; +_out(3,1) += aij*_out(2,1) ; +_out(3,2) += aij*_out(2,2) ; +_out(3,3) += aij*_out(2,3) ; +/* Backsubstitution */ +norm_aij = 1.000000f / Pinv(3,3) ; +Pinv(3,3) = 1.000000f; +_out(3,0) *= norm_aij; +_out(3,1) *= norm_aij; +_out(3,2) *= norm_aij; +_out(3,3) *= norm_aij; +aij = -Pinv(0,3); +Pinv(0,0) += aij*Pinv(3,0); +Pinv(0,1) += aij*Pinv(3,1); +Pinv(0,2) += aij*Pinv(3,2); +Pinv(0,3) += aij*Pinv(3,3); +_out(0,0) += aij*_out(3,0); +_out(0,1) += aij*_out(3,1); +_out(0,2) += aij*_out(3,2); +_out(0,3) += aij*_out(3,3); +aij = -Pinv(1,3); +Pinv(1,0) += aij*Pinv(3,0); +Pinv(1,1) += aij*Pinv(3,1); +Pinv(1,2) += aij*Pinv(3,2); +Pinv(1,3) += aij*Pinv(3,3); +_out(1,0) += aij*_out(3,0); +_out(1,1) += aij*_out(3,1); +_out(1,2) += aij*_out(3,2); +_out(1,3) += aij*_out(3,3); +aij = -Pinv(2,3); +Pinv(2,0) += aij*Pinv(3,0); +Pinv(2,1) += aij*Pinv(3,1); +Pinv(2,2) += aij*Pinv(3,2); +Pinv(2,3) += aij*Pinv(3,3); +_out(2,0) += aij*_out(3,0); +_out(2,1) += aij*_out(3,1); +_out(2,2) += aij*_out(3,2); +_out(2,3) += aij*_out(3,3); +norm_aij = 1.000000f / Pinv(2,2) ; +Pinv(2,2) = 1.000000f; +_out(2,0) *= norm_aij; +_out(2,1) *= norm_aij; +_out(2,2) *= norm_aij; +_out(2,3) *= norm_aij; +aij = -Pinv(0,2); +Pinv(0,0) += aij*Pinv(2,0); +Pinv(0,1) += aij*Pinv(2,1); +Pinv(0,2) += aij*Pinv(2,2); +Pinv(0,3) += aij*Pinv(2,3); +_out(0,0) += aij*_out(2,0); +_out(0,1) += aij*_out(2,1); +_out(0,2) += aij*_out(2,2); +_out(0,3) += aij*_out(2,3); +aij = -Pinv(1,2); +Pinv(1,0) += aij*Pinv(2,0); +Pinv(1,1) += aij*Pinv(2,1); +Pinv(1,2) += aij*Pinv(2,2); +Pinv(1,3) += aij*Pinv(2,3); +_out(1,0) += aij*_out(2,0); +_out(1,1) += aij*_out(2,1); +_out(1,2) += aij*_out(2,2); +_out(1,3) += aij*_out(2,3); +norm_aij = 1.000000f / Pinv(1,1) ; +Pinv(1,1) = 1.000000f; +_out(1,0) *= norm_aij; +_out(1,1) *= norm_aij; +_out(1,2) *= norm_aij; +_out(1,3) *= norm_aij; +aij = -Pinv(0,1); +Pinv(0,0) += aij*Pinv(1,0); +Pinv(0,1) += aij*Pinv(1,1); +Pinv(0,2) += aij*Pinv(1,2); +Pinv(0,3) += aij*Pinv(1,3); +_out(0,0) += aij*_out(1,0); +_out(0,1) += aij*_out(1,1); +_out(0,2) += aij*_out(1,2); +_out(0,3) += aij*_out(1,3); +norm_aij = 1.000000f / Pinv(0,0) ; +Pinv(0,0) = 1.000000f; +_out(0,0) *= norm_aij; +_out(0,1) *= norm_aij; +_out(0,2) *= norm_aij; +_out(0,3) *= norm_aij; +#undef _A +#undef _out +#undef Pinv +} +void SST_Math_Mat44fInvertLocal(SST_Mat44f* RESTRICT _A) +{ +/* Gaussian Elimination */ +#define _A(i,j) _A->v[i+4*j] +#define out(i,j) out->v[i+4*j] +#define Pinv(i,j) Pinv.v[i+4*j] +float aij; +float norm_aij; +SST_Mat44f Pinv; +SST_ASSUME_ALIGNED(_A,16); +/* Set _out to the identity */ +/* Set _Pinv to _A so we don't overwrite it */ +Pinv.v[0] = _A->v[0]; +Pinv.v[1] = _A->v[1]; +Pinv.v[2] = _A->v[2]; +Pinv.v[3] = _A->v[3]; +Pinv.v[4] = _A->v[4]; +Pinv.v[5] = _A->v[5]; +Pinv.v[6] = _A->v[6]; +Pinv.v[7] = _A->v[7]; +Pinv.v[8] = _A->v[8]; +Pinv.v[9] = _A->v[9]; +Pinv.v[10] = _A->v[10]; +Pinv.v[11] = _A->v[11]; +Pinv.v[12] = _A->v[12]; +Pinv.v[13] = _A->v[13]; +Pinv.v[14] = _A->v[14]; +Pinv.v[15] = _A->v[15]; +_A(0,0) = 1.000000f; +_A(1,0) = 0.000000f; +_A(2,0) = 0.000000f; +_A(3,0) = 0.000000f; +_A(0,1) = 0.000000f; +_A(1,1) = 1.000000f; +_A(2,1) = 0.000000f; +_A(3,1) = 0.000000f; +_A(0,2) = 0.000000f; +_A(1,2) = 0.000000f; +_A(2,2) = 1.000000f; +_A(3,2) = 0.000000f; +_A(0,3) = 0.000000f; +_A(1,3) = 0.000000f; +_A(2,3) = 0.000000f; +_A(3,3) = 1.000000f; +/* Put in Reduced Row Echelon form */ +/* Note that we can set the entry to 0, or just calculate it. + The latter will be helpful when recognizing that these are all simple vector moves */ +/* Sort if need be */ +aij = -Pinv(1,0) / Pinv(0,0) ; +Pinv(1,0) += aij*Pinv(0,0) ; +Pinv(1,1) += aij*Pinv(0,1) ; +Pinv(1,2) += aij*Pinv(0,2) ; +Pinv(1,3) += aij*Pinv(0,3) ; +_A(1,0) += aij*_A(0,0) ; +_A(1,1) += aij*_A(0,1) ; +_A(1,2) += aij*_A(0,2) ; +_A(1,3) += aij*_A(0,3) ; +/* Sort if need be */ +aij = -Pinv(2,0) / Pinv(0,0) ; +Pinv(2,0) += aij*Pinv(0,0) ; +Pinv(2,1) += aij*Pinv(0,1) ; +Pinv(2,2) += aij*Pinv(0,2) ; +Pinv(2,3) += aij*Pinv(0,3) ; +_A(2,0) += aij*_A(0,0) ; +_A(2,1) += aij*_A(0,1) ; +_A(2,2) += aij*_A(0,2) ; +_A(2,3) += aij*_A(0,3) ; +/* Sort if need be */ +aij = -Pinv(3,0) / Pinv(0,0) ; +Pinv(3,0) += aij*Pinv(0,0) ; +Pinv(3,1) += aij*Pinv(0,1) ; +Pinv(3,2) += aij*Pinv(0,2) ; +Pinv(3,3) += aij*Pinv(0,3) ; +_A(3,0) += aij*_A(0,0) ; +_A(3,1) += aij*_A(0,1) ; +_A(3,2) += aij*_A(0,2) ; +_A(3,3) += aij*_A(0,3) ; +/* Sort if need be */ +aij = -Pinv(2,1) / Pinv(1,1) ; +Pinv(2,0) += aij*Pinv(1,0) ; +Pinv(2,1) += aij*Pinv(1,1) ; +Pinv(2,2) += aij*Pinv(1,2) ; +Pinv(2,3) += aij*Pinv(1,3) ; +_A(2,0) += aij*_A(1,0) ; +_A(2,1) += aij*_A(1,1) ; +_A(2,2) += aij*_A(1,2) ; +_A(2,3) += aij*_A(1,3) ; +/* Sort if need be */ +aij = -Pinv(3,1) / Pinv(1,1) ; +Pinv(3,0) += aij*Pinv(1,0) ; +Pinv(3,1) += aij*Pinv(1,1) ; +Pinv(3,2) += aij*Pinv(1,2) ; +Pinv(3,3) += aij*Pinv(1,3) ; +_A(3,0) += aij*_A(1,0) ; +_A(3,1) += aij*_A(1,1) ; +_A(3,2) += aij*_A(1,2) ; +_A(3,3) += aij*_A(1,3) ; +/* Sort if need be */ +aij = -Pinv(3,2) / Pinv(2,2) ; +Pinv(3,0) += aij*Pinv(2,0) ; +Pinv(3,1) += aij*Pinv(2,1) ; +Pinv(3,2) += aij*Pinv(2,2) ; +Pinv(3,3) += aij*Pinv(2,3) ; +_A(3,0) += aij*_A(2,0) ; +_A(3,1) += aij*_A(2,1) ; +_A(3,2) += aij*_A(2,2) ; +_A(3,3) += aij*_A(2,3) ; +/* Backsubstitution */ +norm_aij = 1.000000f / Pinv(3,3) ; +Pinv(3,3) = 1.000000f; +_A(3,0) *= norm_aij; +_A(3,1) *= norm_aij; +_A(3,2) *= norm_aij; +_A(3,3) *= norm_aij; +aij = -Pinv.v[12]; +Pinv.v[0] += aij*Pinv.v[3]; +Pinv.v[4] += aij*Pinv.v[7]; +Pinv.v[8] += aij*Pinv.v[11]; +Pinv.v[12] += aij*Pinv.v[15]; +_A->v[0] += aij*_A->v[3]; +_A->v[4] += aij*_A->v[7]; +_A->v[8] += aij*_A->v[11]; +_A->v[12] += aij*_A->v[15]; +aij = -Pinv.v[13]; +Pinv.v[1] += aij*Pinv.v[3]; +Pinv.v[5] += aij*Pinv.v[7]; +Pinv.v[9] += aij*Pinv.v[11]; +Pinv.v[13] += aij*Pinv.v[15]; +_A->v[1] += aij*_A->v[3]; +_A->v[5] += aij*_A->v[7]; +_A->v[9] += aij*_A->v[11]; +_A->v[13] += aij*_A->v[15]; +aij = -Pinv.v[14]; +Pinv.v[2] += aij*Pinv.v[3]; +Pinv.v[6] += aij*Pinv.v[7]; +Pinv.v[10] += aij*Pinv.v[11]; +Pinv.v[14] += aij*Pinv.v[15]; +_A->v[2] += aij*_A->v[3]; +_A->v[6] += aij*_A->v[7]; +_A->v[10] += aij*_A->v[11]; +_A->v[14] += aij*_A->v[15]; +norm_aij = 1.000000f / Pinv(2,2) ; +Pinv(2,2) = 1.000000f; +_A(2,0) *= norm_aij; +_A(2,1) *= norm_aij; +_A(2,2) *= norm_aij; +_A(2,3) *= norm_aij; +aij = -Pinv.v[8]; +Pinv.v[0] += aij*Pinv.v[2]; +Pinv.v[4] += aij*Pinv.v[6]; +Pinv.v[8] += aij*Pinv.v[10]; +Pinv.v[12] += aij*Pinv.v[14]; +_A->v[0] += aij*_A->v[2]; +_A->v[4] += aij*_A->v[6]; +_A->v[8] += aij*_A->v[10]; +_A->v[12] += aij*_A->v[14]; +aij = -Pinv.v[9]; +Pinv.v[1] += aij*Pinv.v[2]; +Pinv.v[5] += aij*Pinv.v[6]; +Pinv.v[9] += aij*Pinv.v[10]; +Pinv.v[13] += aij*Pinv.v[14]; +_A->v[1] += aij*_A->v[2]; +_A->v[5] += aij*_A->v[6]; +_A->v[9] += aij*_A->v[10]; +_A->v[13] += aij*_A->v[14]; +norm_aij = 1.000000f / Pinv(1,1) ; +Pinv(1,1) = 1.000000f; +_A(1,0) *= norm_aij; +_A(1,1) *= norm_aij; +_A(1,2) *= norm_aij; +_A(1,3) *= norm_aij; +aij = -Pinv.v[4]; +Pinv.v[0] += aij*Pinv.v[1]; +Pinv.v[4] += aij*Pinv.v[5]; +Pinv.v[8] += aij*Pinv.v[9]; +Pinv.v[12] += aij*Pinv.v[13]; +_A->v[0] += aij*_A->v[1]; +_A->v[4] += aij*_A->v[5]; +_A->v[8] += aij*_A->v[9]; +_A->v[12] += aij*_A->v[13]; +norm_aij = 1.000000f / Pinv(0,0) ; +Pinv(0,0) = 1.000000f; +_A(0,0) *= norm_aij; +_A(0,1) *= norm_aij; +_A(0,2) *= norm_aij; +_A(0,3) *= norm_aij; +} +void SST_Math_Mat44fCreateLU(const SST_Mat44f* RESTRICT _A, SST_Mat44f* RESTRICT _LU) +{ +#define _A(i,j) _A->v[i+4*j] +#define _LU(i,j) _LU->v[i+4*j] + int i,j,k; + float sum; +SST_ASSUME_ALIGNED(_A,16); +SST_ASSUME_ALIGNED(_LU,16); + _LU(0,0) = _A(0,0); + _LU(0,1) = 0; + _LU(0,2) = 0; + _LU(0,3) = 0; + _LU(1,0) = _A(1,0); + _LU(1,2) = 0; + _LU(1,3) = 0; + _LU(2,0) = _A(2,0); + _LU(2,3) = 0; + _LU(3,0) = _A(3,0); + /* _U(0,0) = 1.000000f; */ + /* _U(1,1) = 1.000000f; */ + /* _U(2,2) = 1.000000f; */ + /* _U(3,3) = 1.000000f; */ + _LU(0,1) = _A(0,1) / _LU(0,0); + _LU(0,2) = _A(0,2) / _LU(0,0); + _LU(0,3) = _A(0,3) / _LU(0,0); + for(i=1; i < 4; i++) { + + for(j=1; j <= i; j++) { + sum = 0.000000f; + for(k=0; k < j; k++) + sum += -_LU(i,k)*_LU(k,j); + _LU(i,j) = _A(i,j) + sum; + } + for(j=i+1; j < 4; j++) { + sum = 0.000000f; + for(k=0; k < i; k++) + sum += -_LU(i,k)*_LU(k,j); + _LU(i,j) = (_A(i,j) + sum) / _LU(i,i); + } + } +#undef _A +#undef _LU +} +void SST_Math_Mat44fApplyLUMat(const SST_Mat44f* _LU, const SST_Mat44f* _A, SST_Mat44f* _out) +{ + +#define _LU(i,j) _LU->v[i+4*j] +#define _A(i,j) _A->v[i+4*j] +#define _out(i,j) _out->v[i+4*j] + int i, j, col; + float sum; +SST_ASSUME_ALIGNED(_A,16); +SST_ASSUME_ALIGNED(_LU,16); +SST_ASSUME_ALIGNED(_out,16); + for(col = 0; col < 4; col++) { + _out(0,col) = _A(0,col); + _out(1,col) = _A(1,col); + _out(2,col) = _A(2,col); + _out(3,col) = _A(3,col); + /* Forward Substitution for Ly = v */ + for(i = 0; i < 4; i++) { + sum = 0.000000f; + for(j = 0; j < i; j++) + sum += _LU(i,j) * _out(j,col); + _out(i,col) = (_out(i,col) - sum) / _LU(i,i) ; + } +/* Backwards Substitution for Uw = y */ + for(i = 3; i >=0; i--) { + sum = 0.000000f; + for(j = i+1; j < 4; j++) + sum += _LU(i,j) * _out(j,col); + _out(i,col) = (_out(i,col) - sum) ; /* divide by U(i,i)=1 */ + } + } +#undef _LU /* (i,j) _LU->v[i+4*j] */ +#undef _A /* (i,j) _A->v[i+4*j] */ +#undef _out /* (i,j) _out->v[i+4*j] */ +} +void SST_Math_Mat44fApplyLUMatLocal(const SST_Mat44f* _LU,SST_Mat44f* _A) +{ + +#define _LU(i,j) _LU->v[i+4*j] +#define _A(i,j) _A->v[i+4*j] + int i, j, col; + float sum; + for(col = 0; col < 4; col++) { + /* Forward Substitution for Ly = v */ + for(i = 0; i < 4; i++) { + sum = 0.000000f; + for(j = 0; j < i; j++) + sum += _LU(i,j) * _A(j,col); + _A(i,col) = (_A(i,col) - sum) / _LU(i,i) ; + } +/* Backwards Substitution for Uw = y */ + for(i = 3; i >=0; i--) { + sum = 0.000000f; + for(j = i+1; j < 4; j++) + sum += _LU(i,j) * _A(j,col); + _A(i,col) = (_A(i,col) - sum) ; /* U is 1s along the diagonal */ + } + } +} +void SST_Math_Mat44fApplyLUVec(const SST_Mat44f* _LU, const SST_Vec4f* _v,SST_Vec4f* _w) +{ + +#define _LU(i,j) _LU->v[i+4*j] + int i, j; + float sum; + _w->v[0] = _v->v[0]; + _w->v[1] = _v->v[1]; + _w->v[2] = _v->v[2]; + _w->v[3] = _v->v[3]; + /* Forward Substitution for Ly = v */ + for(i = 0; i < 4; i++) { + sum = 0.000000f; + for(j = 0; j < i; j++) + sum += _LU(i,j) * _w->v[j]; + _w->v[i] = (_w->v[i] - sum) / _LU(i,i) ; + } +/* Backwards Substitution for Uw = y */ + for(i = 3; i >= 0; i--) { + sum = 0.000000f; + for(j = i+1; j < 4; j++) + sum += _LU(i,j) * _w->v[j]; + /*_w->v[i] = (_w->v[i] - sum) ;*/ + _w->v[i] = (_w->v[i] - sum) ; + } +#undef _LU /* (i,j) _LU->v[i+4*j] */ +} +void SST_Math_Mat44fApplyLUVecLocal(const SST_Mat44f* _LU,SST_Vec4f* _w) +{ + +#define _LU(i,j) _LU->v[i+4*j] + int i, j; + float sum; + /* Forward Substitution for Ly = v */ + for(i = 0; i < 4; i++) { + sum = 0.000000f; + for(j = 0; j < i; j++) + sum += _LU(i,j) * _w->v[j]; + _w->v[i] = (_w->v[i] - sum) / _LU(i,i) ; + } +/* Backwards Substitution for Uw = y */ + for(i = 3; i >= 0; i--) { + sum = 0.000000f; + for(j = i+1; j < 4; j++) + sum += _LU(i,j) * _w->v[j]; + /*_w->v[i] = (_w->v[i] - sum) ;*/ + _w->v[i] = (_w->v[i] - sum) ; + } +#undef _LU /* (i,j) _LU->v[i+4*j] */ +} +void SST_Math_Mat44fCreateLULocal(SST_Mat44f* RESTRICT _A) +{ + /* Note this code stores both L and U inside of A */ + /* For A in R[n x m] we say that for n = m there is an LU = A decomposition [In our decomp, diag[L] = I. Furthermore there is an LU=PA decomposition, where P is a permutation matrix + Step 1: U(i,i:m) = A(i,i:m) + Step 2: L(i+1:n,i) = -A(i+1:n,i) + Step 3: ??? + Step 4: Profit */ +#define _A(i,j) _A->v[i+4*j] + int i,j,k; + float sum; +/* These entries are the same as before in the algorithm. This is left in for purposes of clarity and completeness +_L(0,0) = _A(0,0); +_L(1,0) = _A(1,0); +_L(2,0) = _A(2,0); +_L(3,0) = _A(3,0); +These entries are understood to be 1 in this storage format. This is left in for purposes of clarity and completeness +_U(0,0) = 1.000000f; +_U(1,1) = 1.000000f; +_U(2,2) = 1.000000f; +_U(3,3) = 1.000000f; +*/ +_A(0,1) = _A(0,1) / _A(0,0); +_A(0,2) = _A(0,2) / _A(0,0); +_A(0,3) = _A(0,3) / _A(0,0); + for(i=1; i < 4; i++) { + + for(j=0; j <= i; j++) { + sum = 0.000000f; + for(k=0; k < j; k++) sum += -_A(i,k)*_A(k,j); + _A(i,j) = _A(i,j) + sum; + } + for(j=i+1; j < 4; j++) { + sum = 0.000000f; + for(k=0; k < i; k++) sum += -_A(i,k)*_A(k,j); + _A(i,j) = (_A(i,j) + sum) / _A(i,i); + } + } +#undef _A +} diff --git a/libsst-math/SST_Mat44f_benchmark.c b/libsst-math/SST_Mat44f_benchmark.c new file mode 100644 index 0000000..92aef66 --- /dev/null +++ b/libsst-math/SST_Mat44f_benchmark.c @@ -0,0 +1,856 @@ +#include <float.h> +#include <math.h> +#include <stdlib.h> +#include <stdio.h> +#include <assert.h> +#include <xmmintrin.h> +#include <SST/SST_Timer_x86.h> +#include <SST/SST_Mat44.h> +#include <SST/SST_Vec4.h> + + + + +int SST_Math_Mat44f_test_fxns() +{ +const int NTESTS = 10; +int i; +uint64_t t0,t1; +SST_Mat44f X; /* 4 x 4 matrix */ +SST_Mat44f Y; /* 4 x 4 matrix */ +SST_Mat44f A; /* 4 x 4 matrix */ +SST_Mat44f B; /* 4 x 4 matrix */ +SST_Vec4f v; /* 4 vector */ +SST_Vec4f w; /* 4 vector */ +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +/* Resetting test vectors / mats */ + v.v[0] = 8.000000f; + v.v[1] = -5.000000f; + v.v[2] = 18.000000f; + v.v[3] = -10.000000f; + X.v[0] = -12.000000f; + X.v[1] = -15.000000f; + X.v[2] = 4.000000f; + X.v[3] = -15.000000f; + X.v[4] = -8.000000f; + X.v[5] = -19.000000f; + X.v[6] = 18.000000f; + X.v[7] = 13.000000f; + X.v[8] = 0.000000f; + X.v[9] = -16.000000f; + X.v[10] = 5.000000f; + X.v[11] = 19.000000f; + X.v[12] = -18.000000f; + X.v[13] = -15.000000f; + X.v[14] = -11.000000f; + X.v[15] = 14.000000f; + Y.v[0] = 18.000000f; + Y.v[1] = -20.000000f; + Y.v[2] = 6.000000f; + Y.v[3] = 18.000000f; + Y.v[4] = -1.000000f; + Y.v[5] = 7.000000f; + Y.v[6] = 12.000000f; + Y.v[7] = -7.000000f; + Y.v[8] = -4.000000f; + Y.v[9] = -2.000000f; + Y.v[10] = 6.000000f; + Y.v[11] = -17.000000f; + Y.v[12] = 8.000000f; + Y.v[13] = -5.000000f; + Y.v[14] = -1.000000f; + Y.v[15] = 14.000000f; +SST_Math_Mat44fAdd(&X,&Y,&A); /* clear out the initial finding of object */ +/* Clear out the rdtsc register */ +fprintf(stdout,"SST_Math_Mat44fAdd(X,Y,A)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat44fAdd(&X,&Y,&A); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +/* +[[-12. -8. 0. -18.] + [-15. -19. -16. -15.] + [ 4. 18. 5. -11.] + [-15. 13. 19. 14.]] +[[ 18. -1. -4. 8.] + [-20. 7. -2. -5.] + [ 6. 12. 6. -1.] + [ 18. -7. -17. 14.]] +[[ 6. -9. -4. -10.] + [-35. -12. -18. -20.] + [ 10. 30. 11. -12.] + [ 3. 6. 2. 28.]] +*/ +assert(fabsf((A.v[0])-(6.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[4])-(-9.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[8])-(-4.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[12])-(-10.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[1])-(-35.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[5])-(-12.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[9])-(-18.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[13])-(-20.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[2])-(10.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[6])-(30.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[10])-(11.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[14])-(-12.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[3])-(3.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[7])-(6.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[11])-(2.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[15])-(28.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +/* +[[-12. -8. 0. -18.] + [-15. -19. -16. -15.] + [ 4. 18. 5. -11.] + [-15. 13. 19. 14.]] +[[ 18. -1. -4. 8.] + [-20. 7. -2. -5.] + [ 6. 12. 6. -1.] + [ 18. -7. -17. 14.]] +[[ 6. -9. -4. -10.] + [-35. -12. -18. -20.] + [ 10. 30. 11. -12.] + [ 3. 6. 2. 28.]] +*/ +fprintf(stdout,"SST_Math_Mat44fAddLocal(A,Y)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat44fAddLocal(&A,&Y); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +SST_Math_Mat44fAddLocal(&X,&Y); /* for accuracy */ +assert(fabsf((X.v[0])-(6.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[4])-(-9.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[8])-(-4.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[12])-(-10.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[1])-(-35.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[5])-(-12.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[9])-(-18.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[13])-(-20.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[2])-(10.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[6])-(30.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[10])-(11.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[14])-(-12.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[3])-(3.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[7])-(6.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[11])-(2.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[15])-(28.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +/* Resetting test vectors / mats */ + v.v[0] = 13.000000f; + v.v[1] = 0.000000f; + v.v[2] = -12.000000f; + v.v[3] = -6.000000f; + X.v[0] = 14.000000f; + X.v[1] = 4.000000f; + X.v[2] = 6.000000f; + X.v[3] = -13.000000f; + X.v[4] = 13.000000f; + X.v[5] = -3.000000f; + X.v[6] = 19.000000f; + X.v[7] = -3.000000f; + X.v[8] = 10.000000f; + X.v[9] = 17.000000f; + X.v[10] = -7.000000f; + X.v[11] = -8.000000f; + X.v[12] = -10.000000f; + X.v[13] = 13.000000f; + X.v[14] = 13.000000f; + X.v[15] = -9.000000f; + Y.v[0] = -16.000000f; + Y.v[1] = -5.000000f; + Y.v[2] = 11.000000f; + Y.v[3] = -8.000000f; + Y.v[4] = -3.000000f; + Y.v[5] = -8.000000f; + Y.v[6] = 4.000000f; + Y.v[7] = -10.000000f; + Y.v[8] = 14.000000f; + Y.v[9] = -19.000000f; + Y.v[10] = -4.000000f; + Y.v[11] = 11.000000f; + Y.v[12] = -9.000000f; + Y.v[13] = -8.000000f; + Y.v[14] = -12.000000f; + Y.v[15] = -11.000000f; +/* +[[ 14. 13. 10. -10.] + [ 4. -3. 17. 13.] + [ 6. 19. -7. 13.] + [-13. -3. -8. -9.]] +[[ 28. 26. 20. -20.] + [ 8. -6. 34. 26.] + [ 12. 38. -14. 26.] + [-26. -6. -16. -18.]] +*/ +fprintf(stdout,"SST_Math_Mat44fMultiplyScalar(X,t,Y)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat44fMultiplyScalar(&X,2.000000f,&A); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +assert(fabsf((A.v[0])-(28.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[4])-(26.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[8])-(20.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[12])-(-20.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[1])-(8.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[5])-(-6.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[9])-(34.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[13])-(26.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[2])-(12.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[6])-(38.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[10])-(-14.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[14])-(26.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[3])-(-26.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[7])-(-6.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[11])-(-16.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[15])-(-18.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +/* +[[ 14. 13. 10. -10.] + [ 4. -3. 17. 13.] + [ 6. 19. -7. 13.] + [-13. -3. -8. -9.]] +[[ 28. 26. 20. -20.] + [ 8. -6. 34. 26.] + [ 12. 38. -14. 26.] + [-26. -6. -16. -18.]] +*/ +fprintf(stdout,"SST_Math_Mat44fMultiplyScalarLocal(A,t)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat44fMultiplyScalarLocal(&A,2.000000f); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +SST_Math_Mat44fMultiplyScalarLocal(&X,2.000000f); +assert(fabsf((X.v[0])-(28.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[4])-(26.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[8])-(20.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[12])-(-20.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[1])-(8.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[5])-(-6.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[9])-(34.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[13])-(26.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[2])-(12.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[6])-(38.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[10])-(-14.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[14])-(26.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[3])-(-26.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[7])-(-6.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[11])-(-16.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[15])-(-18.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +/* Resetting test vectors / mats */ + v.v[0] = 0.000000f; + v.v[1] = -12.000000f; + v.v[2] = -11.000000f; + v.v[3] = 4.000000f; + X.v[0] = -20.000000f; + X.v[1] = 12.000000f; + X.v[2] = -12.000000f; + X.v[3] = 12.000000f; + X.v[4] = 7.000000f; + X.v[5] = -10.000000f; + X.v[6] = 17.000000f; + X.v[7] = -5.000000f; + X.v[8] = -6.000000f; + X.v[9] = 19.000000f; + X.v[10] = 19.000000f; + X.v[11] = -18.000000f; + X.v[12] = 7.000000f; + X.v[13] = -10.000000f; + X.v[14] = -18.000000f; + X.v[15] = -11.000000f; + Y.v[0] = 10.000000f; + Y.v[1] = 10.000000f; + Y.v[2] = 14.000000f; + Y.v[3] = 2.000000f; + Y.v[4] = -13.000000f; + Y.v[5] = 17.000000f; + Y.v[6] = -14.000000f; + Y.v[7] = 4.000000f; + Y.v[8] = 9.000000f; + Y.v[9] = 19.000000f; + Y.v[10] = 17.000000f; + Y.v[11] = 5.000000f; + Y.v[12] = -17.000000f; + Y.v[13] = -5.000000f; + Y.v[14] = 13.000000f; + Y.v[15] = 4.000000f; +/* +[[-20. 7. -6. 7.] + [ 12. -10. 19. -10.] + [-12. 17. 19. -18.] + [ 12. -5. -18. -11.]] +[[ 10. -13. 9. -17.] + [ 10. 17. 19. -5.] + [ 14. -14. 17. 13.] + [ 2. 4. 5. 4.]] +[[-200. -91. -54. -119.] + [ 120. -170. 361. 50.] + [-168. -238. 323. -234.] + [ 24. -20. -90. -44.]] +*/ +fprintf(stdout,"SST_Math_Mat44fMultiplyElementwise(X,Y,A)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat44fMultiplyElementwise(&X, &Y, &A); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +assert(fabsf((A.v[0])-(-200.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[4])-(-91.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[8])-(-54.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[12])-(-119.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[1])-(120.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[5])-(-170.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[9])-(361.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[13])-(50.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[2])-(-168.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[6])-(-238.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[10])-(323.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[14])-(-234.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[3])-(24.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[7])-(-20.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[11])-(-90.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[15])-(-44.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +/* +[[-20. 7. -6. 7.] + [ 12. -10. 19. -10.] + [-12. 17. 19. -18.] + [ 12. -5. -18. -11.]] +[[ 10. -13. 9. -17.] + [ 10. 17. 19. -5.] + [ 14. -14. 17. 13.] + [ 2. 4. 5. 4.]] +[[-200. -91. -54. -119.] + [ 120. -170. 361. 50.] + [-168. -238. 323. -234.] + [ 24. -20. -90. -44.]] +*/ +fprintf(stdout,"SST_Math_Mat44fMultiplyElementwiseLocal(X,Y)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat44fMultiplyElementwiseLocal(&A,&Y); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +SST_Math_Mat44fMultiplyElementwiseLocal(&X,&Y); +assert(fabsf((X.v[0])-(-200.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[4])-(-91.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[8])-(-54.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[12])-(-119.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[1])-(120.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[5])-(-170.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[9])-(361.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[13])-(50.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[2])-(-168.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[6])-(-238.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[10])-(323.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[14])-(-234.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[3])-(24.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[7])-(-20.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[11])-(-90.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[15])-(-44.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +/* Resetting test vectors / mats */ + v.v[0] = -13.000000f; + v.v[1] = -12.000000f; + v.v[2] = -20.000000f; + v.v[3] = 8.000000f; + X.v[0] = 2.000000f; + X.v[1] = 11.000000f; + X.v[2] = 4.000000f; + X.v[3] = -2.000000f; + X.v[4] = 10.000000f; + X.v[5] = 6.000000f; + X.v[6] = -6.000000f; + X.v[7] = -17.000000f; + X.v[8] = -1.000000f; + X.v[9] = 3.000000f; + X.v[10] = 9.000000f; + X.v[11] = 8.000000f; + X.v[12] = -4.000000f; + X.v[13] = -3.000000f; + X.v[14] = -10.000000f; + X.v[15] = 18.000000f; + Y.v[0] = 12.000000f; + Y.v[1] = -2.000000f; + Y.v[2] = 5.000000f; + Y.v[3] = -1.000000f; + Y.v[4] = -12.000000f; + Y.v[5] = 6.000000f; + Y.v[6] = 2.000000f; + Y.v[7] = -3.000000f; + Y.v[8] = -13.000000f; + Y.v[9] = 9.000000f; + Y.v[10] = 5.000000f; + Y.v[11] = 2.000000f; + Y.v[12] = 16.000000f; + Y.v[13] = -13.000000f; + Y.v[14] = 14.000000f; + Y.v[15] = -5.000000f; +/* +X +[[ 2. 10. -1. -4.] + [ 11. 6. 3. -3.] + [ 4. -6. 9. -10.] + [ -2. -17. 8. 18.]] +Y +[[ 12. -12. -13. 16.] + [ -2. 6. 9. -13.] + [ 5. 2. 5. 14.] + [ -1. -3. 2. -5.]] +[[ 3. 46. 51. -92.] + [ 138. -81. -80. 155.] + [ 115. -36. -81. 318.] + [ 32. -116. -51. 211.]] +*/ +fprintf(stdout,"SST_Math_Mat44fMultiplyMatrix(X,Y,A)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat44fMultiplyMatrix(&X,&Y,&A); +t1 = rdtsc(); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +assert(fabsf((A.v[0])-(3.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[4])-(46.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[8])-(51.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[12])-(-92.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[1])-(138.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[5])-(-81.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[9])-(-80.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[13])-(155.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[2])-(115.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[6])-(-36.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[10])-(-81.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[14])-(318.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[3])-(32.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[7])-(-116.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[11])-(-51.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[15])-(211.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +/* +X +[[ 2. 10. -1. -4.] + [ 11. 6. 3. -3.] + [ 4. -6. 9. -10.] + [ -2. -17. 8. 18.]] +Y +[[ 12. -12. -13. 16.] + [ -2. 6. 9. -13.] + [ 5. 2. 5. 14.] + [ -1. -3. 2. -5.]] +X +[[ 3. 46. 51. -92.] + [ 138. -81. -80. 155.] + [ 115. -36. -81. 318.] + [ 32. -116. -51. 211.]] +*/ +fprintf(stdout,"SST_Math_Mat44fMultiplyMatrixLocal(X,Y)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat44fMultiplyMatrixLocal(&A,&Y); +t1 = rdtsc(); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +SST_Math_Mat44fMultiplyMatrixLocal(&X,&Y); +assert(fabsf((X.v[0])-(3.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[4])-(46.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[8])-(51.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[12])-(-92.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[1])-(138.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[5])-(-81.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[9])-(-80.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[13])-(155.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[2])-(115.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[6])-(-36.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[10])-(-81.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[14])-(318.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[3])-(32.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[7])-(-116.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[11])-(-51.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[15])-(211.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +/* Resetting test vectors / mats */ + v.v[0] = -14.000000f; + v.v[1] = -16.000000f; + v.v[2] = 15.000000f; + v.v[3] = -20.000000f; + X.v[0] = -14.000000f; + X.v[1] = -20.000000f; + X.v[2] = 11.000000f; + X.v[3] = 18.000000f; + X.v[4] = -15.000000f; + X.v[5] = 18.000000f; + X.v[6] = -2.000000f; + X.v[7] = -11.000000f; + X.v[8] = -4.000000f; + X.v[9] = 4.000000f; + X.v[10] = -16.000000f; + X.v[11] = -12.000000f; + X.v[12] = 13.000000f; + X.v[13] = 9.000000f; + X.v[14] = -6.000000f; + X.v[15] = 0.000000f; + Y.v[0] = 3.000000f; + Y.v[1] = -8.000000f; + Y.v[2] = 16.000000f; + Y.v[3] = -4.000000f; + Y.v[4] = -15.000000f; + Y.v[5] = 2.000000f; + Y.v[6] = 13.000000f; + Y.v[7] = 18.000000f; + Y.v[8] = 7.000000f; + Y.v[9] = -13.000000f; + Y.v[10] = -6.000000f; + Y.v[11] = 6.000000f; + Y.v[12] = -19.000000f; + Y.v[13] = -1.000000f; + Y.v[14] = 1.000000f; + Y.v[15] = 10.000000f; +/* +X +[[-14. -15. -4. 13.] + [-20. 18. 4. 9.] + [ 11. -2. -16. -6.] + [ 18. -11. -12. 0.]] +v +[-14. -16. 15. -20.] +w +[ 116. -128. -242. -256.] +*/ +i=0; +fprintf(stdout,"SST_Math_Mat44fMultiplyVector(X,v,w)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat44fMultiplyVector(&X,&v,&w); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +assert(fabsf((w.v[0])-(116.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((w.v[1])-(-128.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((w.v[2])-(-242.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((w.v[3])-(-256.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +/* +X +[[-14. -15. -4. 13.] + [-20. 18. 4. 9.] + [ 11. -2. -16. -6.] + [ 18. -11. -12. 0.]] +v +[-14. -16. 15. -20.] +v +[ 116. -128. -242. -256.] +*/ +fprintf(stdout,"SST_Math_Mat44fMultiplyVectorLocal(X,v)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat44fMultiplyVectorLocal(&X,&w); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +SST_Math_Mat44fMultiplyVectorLocal(&X,&v); +assert(fabsf((v.v[0])-(116.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((v.v[1])-(-128.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((v.v[2])-(-242.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((v.v[3])-(-256.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +/* Resetting test vectors / mats */ + v.v[0] = -8.000000f; + v.v[1] = 10.000000f; + v.v[2] = 4.000000f; + v.v[3] = 5.000000f; + X.v[0] = -4.000000f; + X.v[1] = -6.000000f; + X.v[2] = -18.000000f; + X.v[3] = -15.000000f; + X.v[4] = 14.000000f; + X.v[5] = 13.000000f; + X.v[6] = -15.000000f; + X.v[7] = 11.000000f; + X.v[8] = 14.000000f; + X.v[9] = -2.000000f; + X.v[10] = 0.000000f; + X.v[11] = 10.000000f; + X.v[12] = -1.000000f; + X.v[13] = 4.000000f; + X.v[14] = 9.000000f; + X.v[15] = 6.000000f; + Y.v[0] = 0.000000f; + Y.v[1] = -8.000000f; + Y.v[2] = -9.000000f; + Y.v[3] = 2.000000f; + Y.v[4] = 18.000000f; + Y.v[5] = 16.000000f; + Y.v[6] = 18.000000f; + Y.v[7] = 9.000000f; + Y.v[8] = 13.000000f; + Y.v[9] = -6.000000f; + Y.v[10] = 1.000000f; + Y.v[11] = 15.000000f; + Y.v[12] = 1.000000f; + Y.v[13] = 4.000000f; + Y.v[14] = 5.000000f; + Y.v[15] = -14.000000f; +fprintf(stdout,"SST_Math_Mat44fTranspose(X,A)"); +t0 = rdtsc(); +SST_Math_Mat44fTranspose(&X,&A); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +assert(fabsf((A.v[0])-(-4.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[4])-(-6.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[8])-(-18.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[12])-(-15.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[1])-(14.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[5])-(13.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[9])-(-15.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[13])-(11.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[2])-(14.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[6])-(-2.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[10])-(0.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[14])-(10.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[3])-(-1.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[7])-(4.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[11])-(9.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((A.v[15])-(6.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +fprintf(stdout,"SST_Math_Mat44fTransposeLocal(X)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat44fTransposeLocal(&A); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +SST_Math_Mat44fTransposeLocal(&X); +assert(fabsf((X.v[0])-(-4.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[4])-(-6.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[8])-(-18.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[12])-(-15.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[1])-(14.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[5])-(13.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[9])-(-15.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[13])-(11.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[2])-(14.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[6])-(-2.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[10])-(0.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[14])-(10.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[3])-(-1.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[7])-(4.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[11])-(9.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[15])-(6.000000f)) <=100*FLT_EPSILON /* yes this is bad */); +/* +[[-0.16316341 -0.51831281 0.642591 -0.54019099] + [-0.24474511 -0.47715011 -0.75842094 -0.37043935] + [-0.73423529 0.59570372 0.02088371 -0.32496071] + [-0.61186278 -0.38576764 0.10695031 0.68217951]] +[[ 1.00000000e+00 0.00000000e+00 7.45058060e-09 0.00000000e+00] + [ 0.00000000e+00 1.00000000e+00 7.45058060e-09 -2.98023224e-08] + [ 7.45058060e-09 7.45058060e-09 1.00000000e+00 2.98023224e-08] + [ 0.00000000e+00 -2.98023224e-08 2.98023224e-08 1.00000000e+00]] +*/ +X.v[0] = (float)-0.163163f; +X.v[4] = (float)-0.518313f; +X.v[8] = (float)0.642591f; +X.v[12] = (float)-0.540191f; +X.v[1] = (float)-0.244745f; +X.v[5] = (float)-0.477150f; +X.v[9] = (float)-0.758421f; +X.v[13] = (float)-0.370439f; +X.v[2] = (float)-0.734235f; +X.v[6] = (float)0.595704f; +X.v[10] = (float)0.020884f; +X.v[14] = (float)-0.324961f; +X.v[3] = (float)-0.611863f; +X.v[7] = (float)-0.385768f; +X.v[11] = (float)0.106950f; +X.v[15] = (float)0.682180f; +fprintf(stdout,"SST_Math_Mat44fTranspose(X,A)"); +t0 = rdtsc(); +SST_Math_Mat44fTranspose(&X,&A); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +fprintf(stdout,"SST_Math_Mat44fMultiplyMatrix(A,X,B)"); +t0 = rdtsc(); +SST_Math_Mat44fMultiplyMatrix(&A,&X,&B); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +/* Check Negative Test */ +assert(!SST_Math_Mat44fCheckOrthonormal(&X)); +X.v[0] = (float)1.000000f; +X.v[4] = (float)0.000000f; +X.v[8] = (float)0.000000f; +X.v[12] = (float)0.000000f; +X.v[1] = (float)0.000000f; +X.v[5] = (float)1.000000f; +X.v[9] = (float)0.000000f; +X.v[13] = (float)0.000000f; +X.v[2] = (float)0.000000f; +X.v[6] = (float)0.000000f; +X.v[10] = (float)1.000000f; +X.v[14] = (float)0.000000f; +X.v[3] = (float)0.000000f; +X.v[7] = (float)0.000000f; +X.v[11] = (float)0.000000f; +X.v[15] = (float)1.000000f; +/* Check Positive Test */ +assert(SST_Math_Mat44fCheckOrthonormal(&X)); +/* Resetting test vectors / mats */ + v.v[0] = 12.000000f; + v.v[1] = 10.000000f; + v.v[2] = 8.000000f; + v.v[3] = -2.000000f; + X.v[0] = -7.000000f; + X.v[1] = -12.000000f; + X.v[2] = -6.000000f; + X.v[3] = -16.000000f; + X.v[4] = -18.000000f; + X.v[5] = 7.000000f; + X.v[6] = -2.000000f; + X.v[7] = 17.000000f; + X.v[8] = 9.000000f; + X.v[9] = 3.000000f; + X.v[10] = -10.000000f; + X.v[11] = -2.000000f; + X.v[12] = -16.000000f; + X.v[13] = -9.000000f; + X.v[14] = -2.000000f; + X.v[15] = 6.000000f; + Y.v[0] = -7.000000f; + Y.v[1] = 6.000000f; + Y.v[2] = -15.000000f; + Y.v[3] = 9.000000f; + Y.v[4] = -17.000000f; + Y.v[5] = -5.000000f; + Y.v[6] = 15.000000f; + Y.v[7] = -13.000000f; + Y.v[8] = 1.000000f; + Y.v[9] = -12.000000f; + Y.v[10] = -5.000000f; + Y.v[11] = -4.000000f; + Y.v[12] = -10.000000f; + Y.v[13] = -18.000000f; + Y.v[14] = 13.000000f; + Y.v[15] = -17.000000f; +/* +[[-0.04568416 0.04019328 -0.01570393 -0.06676916] + [-0.050604 0.07529102 -0.01739512 -0.02780584] + [ 0.0311443 -0.01682407 -0.08304415 0.03013398] + [ 0.03193499 -0.11175049 -0.02027235 0.07744344]] +*/ +fprintf(stdout,"SST_Math_Mat44fInvert(X,B)\n"); +t0 = rdtsc(); +SST_Math_Mat44fInvert(&X,&B); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +fprintf(stdout,"B[%d][%d] = %ff\n",0,0,B.v[0]); +fprintf(stdout,"B[%d][%d] = %ff\n",0,1,B.v[1]); +fprintf(stdout,"B[%d][%d] = %ff\n",0,2,B.v[2]); +fprintf(stdout,"B[%d][%d] = %ff\n",0,3,B.v[3]); +fprintf(stdout,"B[%d][%d] = %ff\n",1,0,B.v[4]); +fprintf(stdout,"B[%d][%d] = %ff\n",1,1,B.v[5]); +fprintf(stdout,"B[%d][%d] = %ff\n",1,2,B.v[6]); +fprintf(stdout,"B[%d][%d] = %ff\n",1,3,B.v[7]); +fprintf(stdout,"B[%d][%d] = %ff\n",2,0,B.v[8]); +fprintf(stdout,"B[%d][%d] = %ff\n",2,1,B.v[9]); +fprintf(stdout,"B[%d][%d] = %ff\n",2,2,B.v[10]); +fprintf(stdout,"B[%d][%d] = %ff\n",2,3,B.v[11]); +fprintf(stdout,"B[%d][%d] = %ff\n",3,0,B.v[12]); +fprintf(stdout,"B[%d][%d] = %ff\n",3,1,B.v[13]); +fprintf(stdout,"B[%d][%d] = %ff\n",3,2,B.v[14]); +fprintf(stdout,"B[%d][%d] = %ff\n",3,3,B.v[15]); +assert(fabsf((B.v[0])-(-0.045684f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((B.v[4])-(0.040193f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((B.v[8])-(-0.015704f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((B.v[12])-(-0.066769f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((B.v[1])-(-0.050604f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((B.v[5])-(0.075291f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((B.v[9])-(-0.017395f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((B.v[13])-(-0.027806f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((B.v[2])-(0.031144f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((B.v[6])-(-0.016824f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((B.v[10])-(-0.083044f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((B.v[14])-(0.030134f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((B.v[3])-(0.031935f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((B.v[7])-(-0.111750f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((B.v[11])-(-0.020272f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((B.v[15])-(0.077443f)) <=100*FLT_EPSILON /* yes this is bad */); +/* Resetting test vectors / mats */ + v.v[0] = -5.000000f; + v.v[1] = 4.000000f; + v.v[2] = -15.000000f; + v.v[3] = 8.000000f; + X.v[0] = -20.000000f; + X.v[1] = -1.000000f; + X.v[2] = -19.000000f; + X.v[3] = 10.000000f; + X.v[4] = 19.000000f; + X.v[5] = -17.000000f; + X.v[6] = 5.000000f; + X.v[7] = 3.000000f; + X.v[8] = -20.000000f; + X.v[9] = 17.000000f; + X.v[10] = -19.000000f; + X.v[11] = -8.000000f; + X.v[12] = -3.000000f; + X.v[13] = 4.000000f; + X.v[14] = 0.000000f; + X.v[15] = 9.000000f; + Y.v[0] = -3.000000f; + Y.v[1] = -20.000000f; + Y.v[2] = 8.000000f; + Y.v[3] = 1.000000f; + Y.v[4] = 3.000000f; + Y.v[5] = 6.000000f; + Y.v[6] = 9.000000f; + Y.v[7] = -15.000000f; + Y.v[8] = -19.000000f; + Y.v[9] = -18.000000f; + Y.v[10] = -16.000000f; + Y.v[11] = 12.000000f; + Y.v[12] = -14.000000f; + Y.v[13] = 14.000000f; + Y.v[14] = 2.000000f; + Y.v[15] = 0.000000f; +/* +[[-0.04497354 -0.04884005 0.000814 0.00671551] + [ 0.09047619 0.02087912 -0.08534799 0.02087912] + [ 0.06878307 0.05433455 -0.07590558 -0.001221 ] + [ 0.08095238 0.0956044 -0.03992674 0.0956044 ]] +*/ +fprintf(stdout,"SST_Math_Mat44fInvert(X,B)\n"); +fflush(stdout); +fprintf(stdout,"SST_Math_Mat44fInvertLocal(X,B)\n"); +t0 = rdtsc(); +SST_Math_Mat44fInvertLocal(&X); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +fflush(stdout); +assert(fabsf((X.v[0])-(-0.044974f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[4])-(-0.048840f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[8])-(0.000814f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[12])-(0.006716f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[1])-(0.090476f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[5])-(0.020879f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[9])-(-0.085348f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[13])-(0.020879f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[2])-(0.068783f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[6])-(0.054335f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[10])-(-0.075906f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[14])-(-0.001221f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[3])-(0.080952f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[7])-(0.095604f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[11])-(-0.039927f)) <=100*FLT_EPSILON /* yes this is bad */); +assert(fabsf((X.v[15])-(0.095604f)) <=100*FLT_EPSILON /* yes this is bad */); +fprintf(stdout,"\n==== SST_Math_Mat44ftest_fxn COMPLETE ====\n"); +return 0; +} diff --git a/libsst-math/SST_Mat44i.c b/libsst-math/SST_Mat44i.c new file mode 100644 index 0000000..04b9120 --- /dev/null +++ b/libsst-math/SST_Mat44i.c @@ -0,0 +1,377 @@ +/* + AUTOMATICALLY GENERATED FILE - DO NOT EDIT! + Please change MatrixNxN.py and re-run it +*/ +/* Generated with ./MatrixNxN.py n = 4, TYPE = int */ + +#include <float.h> +#include <pstdbool.h> +#include <stdio.h> +#include <math.h> /* for sqrt functions */ +#include <stdlib.h> /* for the abs/labs functions */ +#include <SST/SST_Build.h> + +#include <SST/SST_Mat44.h> +#include <SST/SST_Vec4.h> +void SST_Math_Mat44iAdd(const SST_Mat44i* RESTRICT _A, const SST_Mat44i* RESTRICT _B, SST_Mat44i* RESTRICT _out) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + SST_ASSUME_ALIGNED(_out,16); + + _out->v[0] = _A->v[0] + _B->v[0]; + _out->v[1] = _A->v[1] + _B->v[1]; + _out->v[2] = _A->v[2] + _B->v[2]; + _out->v[3] = _A->v[3] + _B->v[3]; + _out->v[4] = _A->v[4] + _B->v[4]; + _out->v[5] = _A->v[5] + _B->v[5]; + _out->v[6] = _A->v[6] + _B->v[6]; + _out->v[7] = _A->v[7] + _B->v[7]; + _out->v[8] = _A->v[8] + _B->v[8]; + _out->v[9] = _A->v[9] + _B->v[9]; + _out->v[10] = _A->v[10] + _B->v[10]; + _out->v[11] = _A->v[11] + _B->v[11]; + _out->v[12] = _A->v[12] + _B->v[12]; + _out->v[13] = _A->v[13] + _B->v[13]; + _out->v[14] = _A->v[14] + _B->v[14]; + _out->v[15] = _A->v[15] + _B->v[15]; +} + +/******************************************************************************/ + +void SST_Math_Mat44iAddLocal(SST_Mat44i* RESTRICT _A, const SST_Mat44i* RESTRICT _B) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + + _A->v[0] += _B->v[0]; + _A->v[1] += _B->v[1]; + _A->v[2] += _B->v[2]; + _A->v[3] += _B->v[3]; + _A->v[4] += _B->v[4]; + _A->v[5] += _B->v[5]; + _A->v[6] += _B->v[6]; + _A->v[7] += _B->v[7]; + _A->v[8] += _B->v[8]; + _A->v[9] += _B->v[9]; + _A->v[10] += _B->v[10]; + _A->v[11] += _B->v[11]; + _A->v[12] += _B->v[12]; + _A->v[13] += _B->v[13]; + _A->v[14] += _B->v[14]; + _A->v[15] += _B->v[15]; +} + +/******************************************************************************/ + +void SST_Math_Mat44iSubtract(const SST_Mat44i* RESTRICT _A, const SST_Mat44i* RESTRICT _B, SST_Mat44i* RESTRICT _out) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + SST_ASSUME_ALIGNED(_out,16); + + _out->v[0] = _A->v[0] - _B->v[0]; + _out->v[1] = _A->v[1] - _B->v[1]; + _out->v[2] = _A->v[2] - _B->v[2]; + _out->v[3] = _A->v[3] - _B->v[3]; + _out->v[4] = _A->v[4] - _B->v[4]; + _out->v[5] = _A->v[5] - _B->v[5]; + _out->v[6] = _A->v[6] - _B->v[6]; + _out->v[7] = _A->v[7] - _B->v[7]; + _out->v[8] = _A->v[8] - _B->v[8]; + _out->v[9] = _A->v[9] - _B->v[9]; + _out->v[10] = _A->v[10] - _B->v[10]; + _out->v[11] = _A->v[11] - _B->v[11]; + _out->v[12] = _A->v[12] - _B->v[12]; + _out->v[13] = _A->v[13] - _B->v[13]; + _out->v[14] = _A->v[14] - _B->v[14]; + _out->v[15] = _A->v[15] - _B->v[15]; +} + +/******************************************************************************/ + +void SST_Math_Mat44iSubtractLocal(SST_Mat44i* RESTRICT _A, const SST_Mat44i* RESTRICT _B) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + + _A->v[0] -= _B->v[0]; + _A->v[1] -= _B->v[1]; + _A->v[2] -= _B->v[2]; + _A->v[3] -= _B->v[3]; + _A->v[4] -= _B->v[4]; + _A->v[5] -= _B->v[5]; + _A->v[6] -= _B->v[6]; + _A->v[7] -= _B->v[7]; + _A->v[8] -= _B->v[8]; + _A->v[9] -= _B->v[9]; + _A->v[10] -= _B->v[10]; + _A->v[11] -= _B->v[11]; + _A->v[12] -= _B->v[12]; + _A->v[13] -= _B->v[13]; + _A->v[14] -= _B->v[14]; + _A->v[15] -= _B->v[15]; +} + +/******************************************************************************/ + +void SST_Math_Mat44iMultiplyElementwise(const SST_Mat44i* RESTRICT _A, const SST_Mat44i* RESTRICT _B, SST_Mat44i* RESTRICT _out) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + SST_ASSUME_ALIGNED(_out,16); + + _out->v[0] = _A->v[0] * _B->v[0]; + _out->v[1] = _A->v[1] * _B->v[1]; + _out->v[2] = _A->v[2] * _B->v[2]; + _out->v[3] = _A->v[3] * _B->v[3]; + _out->v[4] = _A->v[4] * _B->v[4]; + _out->v[5] = _A->v[5] * _B->v[5]; + _out->v[6] = _A->v[6] * _B->v[6]; + _out->v[7] = _A->v[7] * _B->v[7]; + _out->v[8] = _A->v[8] * _B->v[8]; + _out->v[9] = _A->v[9] * _B->v[9]; + _out->v[10] = _A->v[10] * _B->v[10]; + _out->v[11] = _A->v[11] * _B->v[11]; + _out->v[12] = _A->v[12] * _B->v[12]; + _out->v[13] = _A->v[13] * _B->v[13]; + _out->v[14] = _A->v[14] * _B->v[14]; + _out->v[15] = _A->v[15] * _B->v[15]; +} + +/******************************************************************************/ + +void SST_Math_Mat44iMultiplyElementwiseLocal(SST_Mat44i* RESTRICT _A, const SST_Mat44i* RESTRICT _B) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + + _A->v[0] *= _B->v[0]; + _A->v[1] *= _B->v[1]; + _A->v[2] *= _B->v[2]; + _A->v[3] *= _B->v[3]; + _A->v[4] *= _B->v[4]; + _A->v[5] *= _B->v[5]; + _A->v[6] *= _B->v[6]; + _A->v[7] *= _B->v[7]; + _A->v[8] *= _B->v[8]; + _A->v[9] *= _B->v[9]; + _A->v[10] *= _B->v[10]; + _A->v[11] *= _B->v[11]; + _A->v[12] *= _B->v[12]; + _A->v[13] *= _B->v[13]; + _A->v[14] *= _B->v[14]; + _A->v[15] *= _B->v[15]; +} + +/******************************************************************************/ + +void SST_Math_Mat44iMultiplyScalar(const SST_Mat44i* RESTRICT _A, const int k, SST_Mat44i* RESTRICT _out) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_out,16); + + _out->v[0] = _A->v[0] * k; + _out->v[1] = _A->v[1] * k; + _out->v[2] = _A->v[2] * k; + _out->v[3] = _A->v[3] * k; + _out->v[4] = _A->v[4] * k; + _out->v[5] = _A->v[5] * k; + _out->v[6] = _A->v[6] * k; + _out->v[7] = _A->v[7] * k; + _out->v[8] = _A->v[8] * k; + _out->v[9] = _A->v[9] * k; + _out->v[10] = _A->v[10] * k; + _out->v[11] = _A->v[11] * k; + _out->v[12] = _A->v[12] * k; + _out->v[13] = _A->v[13] * k; + _out->v[14] = _A->v[14] * k; + _out->v[15] = _A->v[15] * k; +} + +/******************************************************************************/ + +void SST_Math_Mat44iMultiplyScalarLocal(SST_Mat44i* RESTRICT _A, const int k) +{ + SST_ASSUME_ALIGNED(_A,16); + + _A->v[0] *= k; + _A->v[1] *= k; + _A->v[2] *= k; + _A->v[3] *= k; + _A->v[4] *= k; + _A->v[5] *= k; + _A->v[6] *= k; + _A->v[7] *= k; + _A->v[8] *= k; + _A->v[9] *= k; + _A->v[10] *= k; + _A->v[11] *= k; + _A->v[12] *= k; + _A->v[13] *= k; + _A->v[14] *= k; + _A->v[15] *= k; +} + +/******************************************************************************/ + + +void SST_Math_Mat44iMultiplyMatrix(const SST_Mat44i* _A, const SST_Mat44i* RESTRICT _B, SST_Mat44i* RESTRICT _out) +{ +SST_ASSUME_ALIGNED(_A,16); +SST_ASSUME_ALIGNED(_B,16); +SST_ASSUME_ALIGNED(_out,16); +_out->v[ 0] = _A->v[ 0]*_B->v[ 0]+_A->v[ 4]*_B->v[ 1]+_A->v[ 8]*_B->v[ 2]+_A->v[12]*_B->v[ 3]; +_out->v[ 4] = _A->v[ 0]*_B->v[ 4]+_A->v[ 4]*_B->v[ 5]+_A->v[ 8]*_B->v[ 6]+_A->v[12]*_B->v[ 7]; +_out->v[ 8] = _A->v[ 0]*_B->v[ 8]+_A->v[ 4]*_B->v[ 9]+_A->v[ 8]*_B->v[10]+_A->v[12]*_B->v[11]; +_out->v[12] = _A->v[ 0]*_B->v[12]+_A->v[ 4]*_B->v[13]+_A->v[ 8]*_B->v[14]+_A->v[12]*_B->v[15]; +_out->v[ 1] = _A->v[ 1]*_B->v[ 0]+_A->v[ 5]*_B->v[ 1]+_A->v[ 9]*_B->v[ 2]+_A->v[13]*_B->v[ 3]; +_out->v[ 5] = _A->v[ 1]*_B->v[ 4]+_A->v[ 5]*_B->v[ 5]+_A->v[ 9]*_B->v[ 6]+_A->v[13]*_B->v[ 7]; +_out->v[ 9] = _A->v[ 1]*_B->v[ 8]+_A->v[ 5]*_B->v[ 9]+_A->v[ 9]*_B->v[10]+_A->v[13]*_B->v[11]; +_out->v[13] = _A->v[ 1]*_B->v[12]+_A->v[ 5]*_B->v[13]+_A->v[ 9]*_B->v[14]+_A->v[13]*_B->v[15]; +_out->v[ 2] = _A->v[ 2]*_B->v[ 0]+_A->v[ 6]*_B->v[ 1]+_A->v[10]*_B->v[ 2]+_A->v[14]*_B->v[ 3]; +_out->v[ 6] = _A->v[ 2]*_B->v[ 4]+_A->v[ 6]*_B->v[ 5]+_A->v[10]*_B->v[ 6]+_A->v[14]*_B->v[ 7]; +_out->v[10] = _A->v[ 2]*_B->v[ 8]+_A->v[ 6]*_B->v[ 9]+_A->v[10]*_B->v[10]+_A->v[14]*_B->v[11]; +_out->v[14] = _A->v[ 2]*_B->v[12]+_A->v[ 6]*_B->v[13]+_A->v[10]*_B->v[14]+_A->v[14]*_B->v[15]; +_out->v[ 3] = _A->v[ 3]*_B->v[ 0]+_A->v[ 7]*_B->v[ 1]+_A->v[11]*_B->v[ 2]+_A->v[15]*_B->v[ 3]; +_out->v[ 7] = _A->v[ 3]*_B->v[ 4]+_A->v[ 7]*_B->v[ 5]+_A->v[11]*_B->v[ 6]+_A->v[15]*_B->v[ 7]; +_out->v[11] = _A->v[ 3]*_B->v[ 8]+_A->v[ 7]*_B->v[ 9]+_A->v[11]*_B->v[10]+_A->v[15]*_B->v[11]; +_out->v[15] = _A->v[ 3]*_B->v[12]+_A->v[ 7]*_B->v[13]+_A->v[11]*_B->v[14]+_A->v[15]*_B->v[15]; +} +void SST_Math_Mat44iMultiplyMatrixLocal(SST_Mat44i* RESTRICT _A, const SST_Mat44i* RESTRICT _B) +{ + int tmp[16]; + SST_ASSUME_ALIGNED(_A,16); +SST_ASSUME_ALIGNED(_B,16); +tmp[ 0] = _A->v[ 0]*_B->v[ 0]+_A->v[ 4]*_B->v[ 1]+_A->v[ 8]*_B->v[ 2]+_A->v[12]*_B->v[ 3]; +tmp[ 4] = _A->v[ 0]*_B->v[ 4]+_A->v[ 4]*_B->v[ 5]+_A->v[ 8]*_B->v[ 6]+_A->v[12]*_B->v[ 7]; +tmp[ 8] = _A->v[ 0]*_B->v[ 8]+_A->v[ 4]*_B->v[ 9]+_A->v[ 8]*_B->v[10]+_A->v[12]*_B->v[11]; +tmp[12] = _A->v[ 0]*_B->v[12]+_A->v[ 4]*_B->v[13]+_A->v[ 8]*_B->v[14]+_A->v[12]*_B->v[15]; +_A->v[0] = tmp[0]; +_A->v[4] = tmp[4]; +_A->v[8] = tmp[8]; +_A->v[12] = tmp[12]; + + +tmp[ 1] = _A->v[ 1]*_B->v[ 0]+_A->v[ 5]*_B->v[ 1]+_A->v[ 9]*_B->v[ 2]+_A->v[13]*_B->v[ 3]; +tmp[ 5] = _A->v[ 1]*_B->v[ 4]+_A->v[ 5]*_B->v[ 5]+_A->v[ 9]*_B->v[ 6]+_A->v[13]*_B->v[ 7]; +tmp[ 9] = _A->v[ 1]*_B->v[ 8]+_A->v[ 5]*_B->v[ 9]+_A->v[ 9]*_B->v[10]+_A->v[13]*_B->v[11]; +tmp[13] = _A->v[ 1]*_B->v[12]+_A->v[ 5]*_B->v[13]+_A->v[ 9]*_B->v[14]+_A->v[13]*_B->v[15]; +_A->v[1] = tmp[1]; +_A->v[5] = tmp[5]; +_A->v[9] = tmp[9]; +_A->v[13] = tmp[13]; + + +tmp[ 2] = _A->v[ 2]*_B->v[ 0]+_A->v[ 6]*_B->v[ 1]+_A->v[10]*_B->v[ 2]+_A->v[14]*_B->v[ 3]; +tmp[ 6] = _A->v[ 2]*_B->v[ 4]+_A->v[ 6]*_B->v[ 5]+_A->v[10]*_B->v[ 6]+_A->v[14]*_B->v[ 7]; +tmp[10] = _A->v[ 2]*_B->v[ 8]+_A->v[ 6]*_B->v[ 9]+_A->v[10]*_B->v[10]+_A->v[14]*_B->v[11]; +tmp[14] = _A->v[ 2]*_B->v[12]+_A->v[ 6]*_B->v[13]+_A->v[10]*_B->v[14]+_A->v[14]*_B->v[15]; +_A->v[2] = tmp[2]; +_A->v[6] = tmp[6]; +_A->v[10] = tmp[10]; +_A->v[14] = tmp[14]; + + +tmp[ 3] = _A->v[ 3]*_B->v[ 0]+_A->v[ 7]*_B->v[ 1]+_A->v[11]*_B->v[ 2]+_A->v[15]*_B->v[ 3]; +tmp[ 7] = _A->v[ 3]*_B->v[ 4]+_A->v[ 7]*_B->v[ 5]+_A->v[11]*_B->v[ 6]+_A->v[15]*_B->v[ 7]; +tmp[11] = _A->v[ 3]*_B->v[ 8]+_A->v[ 7]*_B->v[ 9]+_A->v[11]*_B->v[10]+_A->v[15]*_B->v[11]; +tmp[15] = _A->v[ 3]*_B->v[12]+_A->v[ 7]*_B->v[13]+_A->v[11]*_B->v[14]+_A->v[15]*_B->v[15]; +_A->v[3] = tmp[3]; +_A->v[7] = tmp[7]; +_A->v[11] = tmp[11]; +_A->v[15] = tmp[15]; + + +} +void SST_Math_Mat44iMultiplyVector(const SST_Mat44i* RESTRICT _A, const SST_Vec4i* RESTRICT _v, SST_Vec4i* RESTRICT _out) +{ +SST_ASSUME_ALIGNED(_A,16); +SST_ASSUME_ALIGNED(_v,16); +SST_ASSUME_ALIGNED(_out,16); +_out->v[ 0] = _A->v[ 0]*_v->v[0]+_A->v[ 4]*_v->v[1]+_A->v[ 8]*_v->v[2]+_A->v[12]*_v->v[3]; +_out->v[ 1] = _A->v[ 1]*_v->v[0]+_A->v[ 5]*_v->v[1]+_A->v[ 9]*_v->v[2]+_A->v[13]*_v->v[3]; +_out->v[ 2] = _A->v[ 2]*_v->v[0]+_A->v[ 6]*_v->v[1]+_A->v[10]*_v->v[2]+_A->v[14]*_v->v[3]; +_out->v[ 3] = _A->v[ 3]*_v->v[0]+_A->v[ 7]*_v->v[1]+_A->v[11]*_v->v[2]+_A->v[15]*_v->v[3]; +} +void SST_Math_Mat44iMultiplyVectorLocal(const SST_Mat44i* RESTRICT _A, SST_Vec4i* RESTRICT _v) +{ +int tmp[4]; +SST_ASSUME_ALIGNED(_A,16); +SST_ASSUME_ALIGNED(_v,16); +tmp[ 0] = _A->v[ 0]*_v->v[0]+_A->v[ 4]*_v->v[1]+_A->v[ 8]*_v->v[2]+_A->v[12]*_v->v[3]; +tmp[ 1] = _A->v[ 1]*_v->v[0]+_A->v[ 5]*_v->v[1]+_A->v[ 9]*_v->v[2]+_A->v[13]*_v->v[3]; +tmp[ 2] = _A->v[ 2]*_v->v[0]+_A->v[ 6]*_v->v[1]+_A->v[10]*_v->v[2]+_A->v[14]*_v->v[3]; +tmp[ 3] = _A->v[ 3]*_v->v[0]+_A->v[ 7]*_v->v[1]+_A->v[11]*_v->v[2]+_A->v[15]*_v->v[3]; +_v->v[0] = tmp[0]; +_v->v[1] = tmp[1]; +_v->v[2] = tmp[2]; +_v->v[3] = tmp[3]; +} +void SST_Math_Mat44iTranspose(const SST_Mat44i* RESTRICT _A, SST_Mat44i* RESTRICT _out) +{ +SST_ASSUME_ALIGNED(_A,16); +SST_ASSUME_ALIGNED(_out,16); +_out->v[ 0] = _A->v[ 0]; +_out->v[ 1] = _A->v[ 4]; +_out->v[ 2] = _A->v[ 8]; +_out->v[ 3] = _A->v[12]; +_out->v[ 4] = _A->v[ 1]; +_out->v[ 5] = _A->v[ 5]; +_out->v[ 6] = _A->v[ 9]; +_out->v[ 7] = _A->v[13]; +_out->v[ 8] = _A->v[ 2]; +_out->v[ 9] = _A->v[ 6]; +_out->v[10] = _A->v[10]; +_out->v[11] = _A->v[14]; +_out->v[12] = _A->v[ 3]; +_out->v[13] = _A->v[ 7]; +_out->v[14] = _A->v[11]; +_out->v[15] = _A->v[15]; +} +void SST_Math_Mat44iTransposeLocal(SST_Mat44i* RESTRICT _A) +{ +int tmp[4]; +SST_ASSUME_ALIGNED(_A,16); +tmp[1] = _A->v[ 4]; +_A->v[ 4] = _A->v[ 1]; +_A->v[ 1] = tmp[1]; +tmp[2] = _A->v[ 8]; +_A->v[ 8] = _A->v[ 2]; +_A->v[ 2] = tmp[2]; +tmp[3] = _A->v[12]; +_A->v[12] = _A->v[ 3]; +_A->v[ 3] = tmp[3]; +tmp[2] = _A->v[ 9]; +_A->v[ 9] = _A->v[ 6]; +_A->v[ 6] = tmp[2]; +tmp[3] = _A->v[13]; +_A->v[13] = _A->v[ 7]; +_A->v[ 7] = tmp[3]; +tmp[3] = _A->v[14]; +_A->v[14] = _A->v[11]; +_A->v[11] = tmp[3]; +} +bool SST_Math_Mat44iCheckOrthonormal(const SST_Mat44i* _A) +{ +const int diag = -_A->v[0]*_A->v[0] -_A->v[1]*_A->v[1] -_A->v[2]*_A->v[2] -_A->v[3]*_A->v[3] -_A->v[4]*_A->v[4] -_A->v[5]*_A->v[5] -_A->v[6]*_A->v[6] -_A->v[7]*_A->v[7] -_A->v[8]*_A->v[8] -_A->v[9]*_A->v[9] -_A->v[10]*_A->v[10] -_A->v[11]*_A->v[11] -_A->v[12]*_A->v[12] -_A->v[13]*_A->v[13] -_A->v[14]*_A->v[14] -_A->v[15]*_A->v[15]; +const int odiag = _A->v[0]*_A->v[4]+ _A->v[1]*_A->v[5]+ _A->v[2]*_A->v[6]+ _A->v[3]*_A->v[7]+ _A->v[0]*_A->v[8]+ _A->v[1]*_A->v[9]+ _A->v[2]*_A->v[10]+ _A->v[3]*_A->v[11]+ _A->v[0]*_A->v[12]+ _A->v[1]*_A->v[13]+ _A->v[2]*_A->v[14]+ _A->v[3]*_A->v[15]+ _A->v[4]*_A->v[0]+ _A->v[5]*_A->v[1]+ _A->v[6]*_A->v[2]+ _A->v[7]*_A->v[3]+ _A->v[4]*_A->v[8]+ _A->v[5]*_A->v[9]+ _A->v[6]*_A->v[10]+ _A->v[7]*_A->v[11]+ _A->v[4]*_A->v[12]+ _A->v[5]*_A->v[13]+ _A->v[6]*_A->v[14]+ _A->v[7]*_A->v[15]+ _A->v[8]*_A->v[0]+ _A->v[9]*_A->v[1]+ _A->v[10]*_A->v[2]+ _A->v[11]*_A->v[3]+ _A->v[8]*_A->v[4]+ _A->v[9]*_A->v[5]+ _A->v[10]*_A->v[6]+ _A->v[11]*_A->v[7]+ _A->v[8]*_A->v[12]+ _A->v[9]*_A->v[13]+ _A->v[10]*_A->v[14]+ _A->v[11]*_A->v[15]+ _A->v[12]*_A->v[0]+ _A->v[13]*_A->v[1]+ _A->v[14]*_A->v[2]+ _A->v[15]*_A->v[3]+ _A->v[12]*_A->v[4]+ _A->v[13]*_A->v[5]+ _A->v[14]*_A->v[6]+ _A->v[15]*_A->v[7]+ _A->v[12]*_A->v[8]+ _A->v[13]*_A->v[9]+ _A->v[14]*_A->v[10]+ _A->v[15]*_A->v[11]; +SST_ASSUME_ALIGNED(_A,16); +return +((abs(4+diag)) <= 100*0) & +((abs(odiag)) <= 100*0); + + +} +int SST_Math_Mat44iDeterminant(const SST_Mat44i* _A) +{ + const int a10151411 = _A->v[10]*_A->v[15]-_A->v[11]*_A->v[14]; + const int a9151311 = _A->v[6]*_A->v[15]-_A->v[7]*_A->v[14]; + const int a9141310 = _A->v[6]*_A->v[11]-_A->v[7]*_A->v[10]; + const int a8151112 = _A->v[2]*_A->v[15]-_A->v[14]*_A->v[3]; + const int a8141210 = _A->v[2]*_A->v[11]-_A->v[3]*_A->v[10]; + const int a813129 = _A->v[2]*_A->v[7]-_A->v[3]*_A->v[6]; + const int result = _A->v[0]*(_A->v[5]*a10151411-_A->v[9]*a9151311+_A->v[13]*a9141310)-_A->v[4]*(_A->v[1]*a10151411-_A->v[9]*a8151112+_A->v[13]*a8141210)+_A->v[8]*(_A->v[1]*a9151311 -_A->v[5]*a8151112+_A->v[13]*a813129)-_A->v[12]*(_A->v[1]*a9141310 -_A->v[5]*a8141210+_A->v[9]*a813129); + SST_ASSUME_ALIGNED(_A,16); + return result; +} diff --git a/libsst-math/SST_Mat44i_benchmark.c b/libsst-math/SST_Mat44i_benchmark.c new file mode 100644 index 0000000..865c9ad --- /dev/null +++ b/libsst-math/SST_Mat44i_benchmark.c @@ -0,0 +1,693 @@ +#include <float.h> +#include <math.h> +#include <stdlib.h> +#include <stdio.h> +#include <assert.h> +#include <xmmintrin.h> +#include <SST/SST_Timer_x86.h> +#include <SST/SST_Mat44.h> +#include <SST/SST_Vec4.h> + + + + +int SST_Math_Mat44i_test_fxns() +{ +const int NTESTS = 10; +int i; +uint64_t t0,t1; +SST_Mat44i X; /* 4 x 4 matrix */ +SST_Mat44i Y; /* 4 x 4 matrix */ +SST_Mat44i A; /* 4 x 4 matrix */ +SST_Mat44i B; /* 4 x 4 matrix */ +SST_Vec4i v; /* 4 vector */ +SST_Vec4i w; /* 4 vector */ +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +/* Resetting test vectors / mats */ + v.v[0] = 16; + v.v[1] = 7; + v.v[2] = 11; + v.v[3] = -12; + X.v[0] = -7; + X.v[1] = 6; + X.v[2] = 4; + X.v[3] = 19; + X.v[4] = -7; + X.v[5] = 14; + X.v[6] = -15; + X.v[7] = -17; + X.v[8] = -1; + X.v[9] = -4; + X.v[10] = 1; + X.v[11] = 5; + X.v[12] = 4; + X.v[13] = 3; + X.v[14] = -4; + X.v[15] = 5; + Y.v[0] = -13; + Y.v[1] = 7; + Y.v[2] = 10; + Y.v[3] = -2; + Y.v[4] = 13; + Y.v[5] = 5; + Y.v[6] = 15; + Y.v[7] = -15; + Y.v[8] = -5; + Y.v[9] = 5; + Y.v[10] = -17; + Y.v[11] = 7; + Y.v[12] = 19; + Y.v[13] = 17; + Y.v[14] = 15; + Y.v[15] = -9; +SST_Math_Mat44iAdd(&X,&Y,&A); /* clear out the initial finding of object */ +/* Clear out the rdtsc register */ +fprintf(stdout,"SST_Math_Mat44iAdd(X,Y,A)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat44iAdd(&X,&Y,&A); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +/* +[[ -7 -7 -1 4] + [ 6 14 -4 3] + [ 4 -15 1 -4] + [ 19 -17 5 5]] +[[-13 13 -5 19] + [ 7 5 5 17] + [ 10 15 -17 15] + [ -2 -15 7 -9]] +[[-20 6 -6 23] + [ 13 19 1 20] + [ 14 0 -16 11] + [ 17 -32 12 -4]] +*/ +assert((A.v[0])==(-20)); +assert((A.v[4])==(6)); +assert((A.v[8])==(-6)); +assert((A.v[12])==(23)); +assert((A.v[1])==(13)); +assert((A.v[5])==(19)); +assert((A.v[9])==(1)); +assert((A.v[13])==(20)); +assert((A.v[2])==(14)); +assert((A.v[6])==(0)); +assert((A.v[10])==(-16)); +assert((A.v[14])==(11)); +assert((A.v[3])==(17)); +assert((A.v[7])==(-32)); +assert((A.v[11])==(12)); +assert((A.v[15])==(-4)); +/* +[[ -7 -7 -1 4] + [ 6 14 -4 3] + [ 4 -15 1 -4] + [ 19 -17 5 5]] +[[-13 13 -5 19] + [ 7 5 5 17] + [ 10 15 -17 15] + [ -2 -15 7 -9]] +[[-20 6 -6 23] + [ 13 19 1 20] + [ 14 0 -16 11] + [ 17 -32 12 -4]] +*/ +fprintf(stdout,"SST_Math_Mat44iAddLocal(A,Y)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat44iAddLocal(&A,&Y); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +SST_Math_Mat44iAddLocal(&X,&Y); /* for accuracy */ +assert((X.v[0])==(-20)); +assert((X.v[4])==(6)); +assert((X.v[8])==(-6)); +assert((X.v[12])==(23)); +assert((X.v[1])==(13)); +assert((X.v[5])==(19)); +assert((X.v[9])==(1)); +assert((X.v[13])==(20)); +assert((X.v[2])==(14)); +assert((X.v[6])==(0)); +assert((X.v[10])==(-16)); +assert((X.v[14])==(11)); +assert((X.v[3])==(17)); +assert((X.v[7])==(-32)); +assert((X.v[11])==(12)); +assert((X.v[15])==(-4)); +/* Resetting test vectors / mats */ + v.v[0] = -15; + v.v[1] = -16; + v.v[2] = -2; + v.v[3] = -16; + X.v[0] = -16; + X.v[1] = -11; + X.v[2] = 15; + X.v[3] = -19; + X.v[4] = 1; + X.v[5] = -12; + X.v[6] = 10; + X.v[7] = -4; + X.v[8] = -18; + X.v[9] = 10; + X.v[10] = 3; + X.v[11] = -4; + X.v[12] = -11; + X.v[13] = 7; + X.v[14] = 17; + X.v[15] = 3; + Y.v[0] = 11; + Y.v[1] = -12; + Y.v[2] = 18; + Y.v[3] = -18; + Y.v[4] = -4; + Y.v[5] = -3; + Y.v[6] = -4; + Y.v[7] = -14; + Y.v[8] = -3; + Y.v[9] = 7; + Y.v[10] = -11; + Y.v[11] = -11; + Y.v[12] = -5; + Y.v[13] = -15; + Y.v[14] = 2; + Y.v[15] = 0; +/* +[[-16 1 -18 -11] + [-11 -12 10 7] + [ 15 10 3 17] + [-19 -4 -4 3]] +[[-32 2 -36 -22] + [-22 -24 20 14] + [ 30 20 6 34] + [-38 -8 -8 6]] +*/ +fprintf(stdout,"SST_Math_Mat44iMultiplyScalar(X,t,Y)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat44iMultiplyScalar(&X,2,&A); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +assert((A.v[0])==(-32)); +assert((A.v[4])==(2)); +assert((A.v[8])==(-36)); +assert((A.v[12])==(-22)); +assert((A.v[1])==(-22)); +assert((A.v[5])==(-24)); +assert((A.v[9])==(20)); +assert((A.v[13])==(14)); +assert((A.v[2])==(30)); +assert((A.v[6])==(20)); +assert((A.v[10])==(6)); +assert((A.v[14])==(34)); +assert((A.v[3])==(-38)); +assert((A.v[7])==(-8)); +assert((A.v[11])==(-8)); +assert((A.v[15])==(6)); +/* +[[-16 1 -18 -11] + [-11 -12 10 7] + [ 15 10 3 17] + [-19 -4 -4 3]] +[[-32 2 -36 -22] + [-22 -24 20 14] + [ 30 20 6 34] + [-38 -8 -8 6]] +*/ +fprintf(stdout,"SST_Math_Mat44iMultiplyScalarLocal(A,t)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat44iMultiplyScalarLocal(&A,2); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +SST_Math_Mat44iMultiplyScalarLocal(&X,2); +assert((X.v[0])==(-32)); +assert((X.v[4])==(2)); +assert((X.v[8])==(-36)); +assert((X.v[12])==(-22)); +assert((X.v[1])==(-22)); +assert((X.v[5])==(-24)); +assert((X.v[9])==(20)); +assert((X.v[13])==(14)); +assert((X.v[2])==(30)); +assert((X.v[6])==(20)); +assert((X.v[10])==(6)); +assert((X.v[14])==(34)); +assert((X.v[3])==(-38)); +assert((X.v[7])==(-8)); +assert((X.v[11])==(-8)); +assert((X.v[15])==(6)); +/* Resetting test vectors / mats */ + v.v[0] = 11; + v.v[1] = -13; + v.v[2] = -2; + v.v[3] = 11; + X.v[0] = 0; + X.v[1] = 4; + X.v[2] = 16; + X.v[3] = 8; + X.v[4] = -20; + X.v[5] = -15; + X.v[6] = 13; + X.v[7] = -9; + X.v[8] = -18; + X.v[9] = -12; + X.v[10] = 8; + X.v[11] = -18; + X.v[12] = -4; + X.v[13] = 11; + X.v[14] = -14; + X.v[15] = 15; + Y.v[0] = -15; + Y.v[1] = -5; + Y.v[2] = -7; + Y.v[3] = 19; + Y.v[4] = -1; + Y.v[5] = 16; + Y.v[6] = -4; + Y.v[7] = -12; + Y.v[8] = -17; + Y.v[9] = -7; + Y.v[10] = 0; + Y.v[11] = -3; + Y.v[12] = -9; + Y.v[13] = -17; + Y.v[14] = -14; + Y.v[15] = -14; +/* +[[ 0 -20 -18 -4] + [ 4 -15 -12 11] + [ 16 13 8 -14] + [ 8 -9 -18 15]] +[[-15 -1 -17 -9] + [ -5 16 -7 -17] + [ -7 -4 0 -14] + [ 19 -12 -3 -14]] +[[ 0 20 306 36] + [ -20 -240 84 -187] + [-112 -52 0 196] + [ 152 108 54 -210]] +*/ +fprintf(stdout,"SST_Math_Mat44iMultiplyElementwise(X,Y,A)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat44iMultiplyElementwise(&X, &Y, &A); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +assert((A.v[0])==(0)); +assert((A.v[4])==(20)); +assert((A.v[8])==(306)); +assert((A.v[12])==(36)); +assert((A.v[1])==(-20)); +assert((A.v[5])==(-240)); +assert((A.v[9])==(84)); +assert((A.v[13])==(-187)); +assert((A.v[2])==(-112)); +assert((A.v[6])==(-52)); +assert((A.v[10])==(0)); +assert((A.v[14])==(196)); +assert((A.v[3])==(152)); +assert((A.v[7])==(108)); +assert((A.v[11])==(54)); +assert((A.v[15])==(-210)); +/* +[[ 0 -20 -18 -4] + [ 4 -15 -12 11] + [ 16 13 8 -14] + [ 8 -9 -18 15]] +[[-15 -1 -17 -9] + [ -5 16 -7 -17] + [ -7 -4 0 -14] + [ 19 -12 -3 -14]] +[[ 0 20 306 36] + [ -20 -240 84 -187] + [-112 -52 0 196] + [ 152 108 54 -210]] +*/ +fprintf(stdout,"SST_Math_Mat44iMultiplyElementwiseLocal(X,Y)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat44iMultiplyElementwiseLocal(&A,&Y); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +SST_Math_Mat44iMultiplyElementwiseLocal(&X,&Y); +assert((X.v[0])==(0)); +assert((X.v[4])==(20)); +assert((X.v[8])==(306)); +assert((X.v[12])==(36)); +assert((X.v[1])==(-20)); +assert((X.v[5])==(-240)); +assert((X.v[9])==(84)); +assert((X.v[13])==(-187)); +assert((X.v[2])==(-112)); +assert((X.v[6])==(-52)); +assert((X.v[10])==(0)); +assert((X.v[14])==(196)); +assert((X.v[3])==(152)); +assert((X.v[7])==(108)); +assert((X.v[11])==(54)); +assert((X.v[15])==(-210)); +/* Resetting test vectors / mats */ + v.v[0] = -14; + v.v[1] = -14; + v.v[2] = 12; + v.v[3] = -12; + X.v[0] = -16; + X.v[1] = -19; + X.v[2] = 6; + X.v[3] = 19; + X.v[4] = 14; + X.v[5] = 10; + X.v[6] = 16; + X.v[7] = -17; + X.v[8] = -10; + X.v[9] = -5; + X.v[10] = -8; + X.v[11] = -20; + X.v[12] = 14; + X.v[13] = -12; + X.v[14] = 19; + X.v[15] = -2; + Y.v[0] = -10; + Y.v[1] = 6; + Y.v[2] = -6; + Y.v[3] = -17; + Y.v[4] = -8; + Y.v[5] = -6; + Y.v[6] = -19; + Y.v[7] = -5; + Y.v[8] = 14; + Y.v[9] = -6; + Y.v[10] = 0; + Y.v[11] = 12; + Y.v[12] = -17; + Y.v[13] = -12; + Y.v[14] = 8; + Y.v[15] = 14; +/* +X +[[-16 14 -10 14] + [-19 10 -5 -12] + [ 6 16 -8 19] + [ 19 -17 -20 -2]] +Y +[[-10 -8 14 -17] + [ 6 -6 -6 -12] + [ -6 -19 0 8] + [-17 -5 12 14]] +[[ 66 164 -140 220] + [ 484 247 -470 -5] + [-239 -87 216 -92] + [-138 340 344 -307]] +*/ +fprintf(stdout,"SST_Math_Mat44iMultiplyMatrix(X,Y,A)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat44iMultiplyMatrix(&X,&Y,&A); +t1 = rdtsc(); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +assert((A.v[0])==(66)); +assert((A.v[4])==(164)); +assert((A.v[8])==(-140)); +assert((A.v[12])==(220)); +assert((A.v[1])==(484)); +assert((A.v[5])==(247)); +assert((A.v[9])==(-470)); +assert((A.v[13])==(-5)); +assert((A.v[2])==(-239)); +assert((A.v[6])==(-87)); +assert((A.v[10])==(216)); +assert((A.v[14])==(-92)); +assert((A.v[3])==(-138)); +assert((A.v[7])==(340)); +assert((A.v[11])==(344)); +assert((A.v[15])==(-307)); +/* +X +[[-16 14 -10 14] + [-19 10 -5 -12] + [ 6 16 -8 19] + [ 19 -17 -20 -2]] +Y +[[-10 -8 14 -17] + [ 6 -6 -6 -12] + [ -6 -19 0 8] + [-17 -5 12 14]] +X +[[ 66 164 -140 220] + [ 484 247 -470 -5] + [-239 -87 216 -92] + [-138 340 344 -307]] +*/ +fprintf(stdout,"SST_Math_Mat44iMultiplyMatrixLocal(X,Y)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat44iMultiplyMatrixLocal(&A,&Y); +t1 = rdtsc(); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +SST_Math_Mat44iMultiplyMatrixLocal(&X,&Y); +assert((X.v[0])==(66)); +assert((X.v[4])==(164)); +assert((X.v[8])==(-140)); +assert((X.v[12])==(220)); +assert((X.v[1])==(484)); +assert((X.v[5])==(247)); +assert((X.v[9])==(-470)); +assert((X.v[13])==(-5)); +assert((X.v[2])==(-239)); +assert((X.v[6])==(-87)); +assert((X.v[10])==(216)); +assert((X.v[14])==(-92)); +assert((X.v[3])==(-138)); +assert((X.v[7])==(340)); +assert((X.v[11])==(344)); +assert((X.v[15])==(-307)); +/* Resetting test vectors / mats */ + v.v[0] = -13; + v.v[1] = -15; + v.v[2] = -5; + v.v[3] = 8; + X.v[0] = -1; + X.v[1] = 14; + X.v[2] = 17; + X.v[3] = 7; + X.v[4] = 14; + X.v[5] = -3; + X.v[6] = -15; + X.v[7] = 19; + X.v[8] = -20; + X.v[9] = -2; + X.v[10] = -2; + X.v[11] = 16; + X.v[12] = 5; + X.v[13] = 9; + X.v[14] = 14; + X.v[15] = 9; + Y.v[0] = -15; + Y.v[1] = -11; + Y.v[2] = 11; + Y.v[3] = -14; + Y.v[4] = 11; + Y.v[5] = -8; + Y.v[6] = -9; + Y.v[7] = -2; + Y.v[8] = 15; + Y.v[9] = -15; + Y.v[10] = -10; + Y.v[11] = -7; + Y.v[12] = 8; + Y.v[13] = 10; + Y.v[14] = 4; + Y.v[15] = -11; +/* +X +[[ -1 14 -20 5] + [ 14 -3 -2 9] + [ 17 -15 -2 14] + [ 7 19 16 9]] +v +[-13 -15 -5 8] +w +[ -57 -55 126 -384] +*/ +i=0; +fprintf(stdout,"SST_Math_Mat44iMultiplyVector(X,v,w)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat44iMultiplyVector(&X,&v,&w); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +assert((w.v[0])==(-57)); +assert((w.v[1])==(-55)); +assert((w.v[2])==(126)); +assert((w.v[3])==(-384)); +/* +X +[[ -1 14 -20 5] + [ 14 -3 -2 9] + [ 17 -15 -2 14] + [ 7 19 16 9]] +v +[-13 -15 -5 8] +v +[ -57 -55 126 -384] +*/ +fprintf(stdout,"SST_Math_Mat44iMultiplyVectorLocal(X,v)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat44iMultiplyVectorLocal(&X,&w); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +SST_Math_Mat44iMultiplyVectorLocal(&X,&v); +assert((v.v[0])==(-57)); +assert((v.v[1])==(-55)); +assert((v.v[2])==(126)); +assert((v.v[3])==(-384)); +/* Resetting test vectors / mats */ + v.v[0] = 6; + v.v[1] = 8; + v.v[2] = -16; + v.v[3] = -4; + X.v[0] = 2; + X.v[1] = 7; + X.v[2] = 7; + X.v[3] = 15; + X.v[4] = -3; + X.v[5] = -12; + X.v[6] = 3; + X.v[7] = -5; + X.v[8] = -4; + X.v[9] = 3; + X.v[10] = 17; + X.v[11] = 5; + X.v[12] = 11; + X.v[13] = 4; + X.v[14] = -19; + X.v[15] = -3; + Y.v[0] = 10; + Y.v[1] = -20; + Y.v[2] = 12; + Y.v[3] = -20; + Y.v[4] = 4; + Y.v[5] = 5; + Y.v[6] = 5; + Y.v[7] = -10; + Y.v[8] = -4; + Y.v[9] = -5; + Y.v[10] = 18; + Y.v[11] = -12; + Y.v[12] = 19; + Y.v[13] = -8; + Y.v[14] = -12; + Y.v[15] = 11; +fprintf(stdout,"SST_Math_Mat44iTranspose(X,A)"); +t0 = rdtsc(); +SST_Math_Mat44iTranspose(&X,&A); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +assert((A.v[0])==(2)); +assert((A.v[4])==(7)); +assert((A.v[8])==(7)); +assert((A.v[12])==(15)); +assert((A.v[1])==(-3)); +assert((A.v[5])==(-12)); +assert((A.v[9])==(3)); +assert((A.v[13])==(-5)); +assert((A.v[2])==(-4)); +assert((A.v[6])==(3)); +assert((A.v[10])==(17)); +assert((A.v[14])==(5)); +assert((A.v[3])==(11)); +assert((A.v[7])==(4)); +assert((A.v[11])==(-19)); +assert((A.v[15])==(-3)); +fprintf(stdout,"SST_Math_Mat44iTransposeLocal(X)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat44iTransposeLocal(&A); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +SST_Math_Mat44iTransposeLocal(&X); +assert((X.v[0])==(2)); +assert((X.v[4])==(7)); +assert((X.v[8])==(7)); +assert((X.v[12])==(15)); +assert((X.v[1])==(-3)); +assert((X.v[5])==(-12)); +assert((X.v[9])==(3)); +assert((X.v[13])==(-5)); +assert((X.v[2])==(-4)); +assert((X.v[6])==(3)); +assert((X.v[10])==(17)); +assert((X.v[14])==(5)); +assert((X.v[3])==(11)); +assert((X.v[7])==(4)); +assert((X.v[11])==(-19)); +assert((X.v[15])==(-3)); +/* +[[-0.11060025 -0.19063332 0.3125823 -0.92396906] + [-0.38710088 -0.8021454 -0.45077126 0.05933746] + [-0.38710088 0.54714239 -0.68026815 -0.29668731] + [-0.8295019 0.14441918 0.48614075 0.23395914]] +[[ 1.00000000e+00 -2.77555756e-17 1.66533454e-16 -3.05311332e-16] + [ -2.77555756e-17 1.00000000e+00 2.63677968e-16 -4.16333634e-17] + [ 1.66533454e-16 2.63677968e-16 1.00000000e+00 1.11022302e-16] + [ -3.05311332e-16 -4.16333634e-17 1.11022302e-16 1.00000000e+00]] +*/ +X.v[0] = (int)0; +X.v[4] = (int)0; +X.v[8] = (int)0; +X.v[12] = (int)0; +X.v[1] = (int)0; +X.v[5] = (int)0; +X.v[9] = (int)0; +X.v[13] = (int)0; +X.v[2] = (int)0; +X.v[6] = (int)0; +X.v[10] = (int)0; +X.v[14] = (int)0; +X.v[3] = (int)0; +X.v[7] = (int)0; +X.v[11] = (int)0; +X.v[15] = (int)0; +fprintf(stdout,"SST_Math_Mat44iTranspose(X,A)"); +t0 = rdtsc(); +SST_Math_Mat44iTranspose(&X,&A); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +fprintf(stdout,"SST_Math_Mat44iMultiplyMatrix(A,X,B)"); +t0 = rdtsc(); +SST_Math_Mat44iMultiplyMatrix(&A,&X,&B); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +/* Check Positive Test */ +assert(SST_Math_Mat44iCheckOrthonormal(&X)); +/* Check Negative Test */ +assert(!SST_Math_Mat44iCheckOrthonormal(&Y)); +fprintf(stdout,"\n==== SST_Math_Mat44itest_fxn COMPLETE ====\n"); +return 0; +} diff --git a/libsst-math/SST_Mat44u.c b/libsst-math/SST_Mat44u.c new file mode 100644 index 0000000..f45a5e7 --- /dev/null +++ b/libsst-math/SST_Mat44u.c @@ -0,0 +1,354 @@ +/* + AUTOMATICALLY GENERATED FILE - DO NOT EDIT! + Please change MatrixNxN.py and re-run it +*/ +/* Generated with ./MatrixNxN.py n = 4, TYPE = unsigned int */ + +#include <float.h> +#include <pstdbool.h> +#include <stdio.h> +#include <math.h> /* for sqrt functions */ +#include <stdlib.h> /* for the abs/labs functions */ +#include <SST/SST_Build.h> + +#include <SST/SST_Mat44.h> +#include <SST/SST_Vec4.h> +void SST_Math_Mat44uAdd(const SST_Mat44u* RESTRICT _A, const SST_Mat44u* RESTRICT _B, SST_Mat44u* RESTRICT _out) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + SST_ASSUME_ALIGNED(_out,16); + + _out->v[0] = _A->v[0] + _B->v[0]; + _out->v[1] = _A->v[1] + _B->v[1]; + _out->v[2] = _A->v[2] + _B->v[2]; + _out->v[3] = _A->v[3] + _B->v[3]; + _out->v[4] = _A->v[4] + _B->v[4]; + _out->v[5] = _A->v[5] + _B->v[5]; + _out->v[6] = _A->v[6] + _B->v[6]; + _out->v[7] = _A->v[7] + _B->v[7]; + _out->v[8] = _A->v[8] + _B->v[8]; + _out->v[9] = _A->v[9] + _B->v[9]; + _out->v[10] = _A->v[10] + _B->v[10]; + _out->v[11] = _A->v[11] + _B->v[11]; + _out->v[12] = _A->v[12] + _B->v[12]; + _out->v[13] = _A->v[13] + _B->v[13]; + _out->v[14] = _A->v[14] + _B->v[14]; + _out->v[15] = _A->v[15] + _B->v[15]; +} + +/******************************************************************************/ + +void SST_Math_Mat44uAddLocal(SST_Mat44u* RESTRICT _A, const SST_Mat44u* RESTRICT _B) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + + _A->v[0] += _B->v[0]; + _A->v[1] += _B->v[1]; + _A->v[2] += _B->v[2]; + _A->v[3] += _B->v[3]; + _A->v[4] += _B->v[4]; + _A->v[5] += _B->v[5]; + _A->v[6] += _B->v[6]; + _A->v[7] += _B->v[7]; + _A->v[8] += _B->v[8]; + _A->v[9] += _B->v[9]; + _A->v[10] += _B->v[10]; + _A->v[11] += _B->v[11]; + _A->v[12] += _B->v[12]; + _A->v[13] += _B->v[13]; + _A->v[14] += _B->v[14]; + _A->v[15] += _B->v[15]; +} + +/******************************************************************************/ + +void SST_Math_Mat44uSubtract(const SST_Mat44u* RESTRICT _A, const SST_Mat44u* RESTRICT _B, SST_Mat44u* RESTRICT _out) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + SST_ASSUME_ALIGNED(_out,16); + + _out->v[0] = _A->v[0] - _B->v[0]; + _out->v[1] = _A->v[1] - _B->v[1]; + _out->v[2] = _A->v[2] - _B->v[2]; + _out->v[3] = _A->v[3] - _B->v[3]; + _out->v[4] = _A->v[4] - _B->v[4]; + _out->v[5] = _A->v[5] - _B->v[5]; + _out->v[6] = _A->v[6] - _B->v[6]; + _out->v[7] = _A->v[7] - _B->v[7]; + _out->v[8] = _A->v[8] - _B->v[8]; + _out->v[9] = _A->v[9] - _B->v[9]; + _out->v[10] = _A->v[10] - _B->v[10]; + _out->v[11] = _A->v[11] - _B->v[11]; + _out->v[12] = _A->v[12] - _B->v[12]; + _out->v[13] = _A->v[13] - _B->v[13]; + _out->v[14] = _A->v[14] - _B->v[14]; + _out->v[15] = _A->v[15] - _B->v[15]; +} + +/******************************************************************************/ + +void SST_Math_Mat44uSubtractLocal(SST_Mat44u* RESTRICT _A, const SST_Mat44u* RESTRICT _B) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + + _A->v[0] -= _B->v[0]; + _A->v[1] -= _B->v[1]; + _A->v[2] -= _B->v[2]; + _A->v[3] -= _B->v[3]; + _A->v[4] -= _B->v[4]; + _A->v[5] -= _B->v[5]; + _A->v[6] -= _B->v[6]; + _A->v[7] -= _B->v[7]; + _A->v[8] -= _B->v[8]; + _A->v[9] -= _B->v[9]; + _A->v[10] -= _B->v[10]; + _A->v[11] -= _B->v[11]; + _A->v[12] -= _B->v[12]; + _A->v[13] -= _B->v[13]; + _A->v[14] -= _B->v[14]; + _A->v[15] -= _B->v[15]; +} + +/******************************************************************************/ + +void SST_Math_Mat44uMultiplyElementwise(const SST_Mat44u* RESTRICT _A, const SST_Mat44u* RESTRICT _B, SST_Mat44u* RESTRICT _out) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + SST_ASSUME_ALIGNED(_out,16); + + _out->v[0] = _A->v[0] * _B->v[0]; + _out->v[1] = _A->v[1] * _B->v[1]; + _out->v[2] = _A->v[2] * _B->v[2]; + _out->v[3] = _A->v[3] * _B->v[3]; + _out->v[4] = _A->v[4] * _B->v[4]; + _out->v[5] = _A->v[5] * _B->v[5]; + _out->v[6] = _A->v[6] * _B->v[6]; + _out->v[7] = _A->v[7] * _B->v[7]; + _out->v[8] = _A->v[8] * _B->v[8]; + _out->v[9] = _A->v[9] * _B->v[9]; + _out->v[10] = _A->v[10] * _B->v[10]; + _out->v[11] = _A->v[11] * _B->v[11]; + _out->v[12] = _A->v[12] * _B->v[12]; + _out->v[13] = _A->v[13] * _B->v[13]; + _out->v[14] = _A->v[14] * _B->v[14]; + _out->v[15] = _A->v[15] * _B->v[15]; +} + +/******************************************************************************/ + +void SST_Math_Mat44uMultiplyElementwiseLocal(SST_Mat44u* RESTRICT _A, const SST_Mat44u* RESTRICT _B) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + + _A->v[0] *= _B->v[0]; + _A->v[1] *= _B->v[1]; + _A->v[2] *= _B->v[2]; + _A->v[3] *= _B->v[3]; + _A->v[4] *= _B->v[4]; + _A->v[5] *= _B->v[5]; + _A->v[6] *= _B->v[6]; + _A->v[7] *= _B->v[7]; + _A->v[8] *= _B->v[8]; + _A->v[9] *= _B->v[9]; + _A->v[10] *= _B->v[10]; + _A->v[11] *= _B->v[11]; + _A->v[12] *= _B->v[12]; + _A->v[13] *= _B->v[13]; + _A->v[14] *= _B->v[14]; + _A->v[15] *= _B->v[15]; +} + +/******************************************************************************/ + +void SST_Math_Mat44uMultiplyScalar(const SST_Mat44u* RESTRICT _A, const unsigned int k, SST_Mat44u* RESTRICT _out) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_out,16); + + _out->v[0] = _A->v[0] * k; + _out->v[1] = _A->v[1] * k; + _out->v[2] = _A->v[2] * k; + _out->v[3] = _A->v[3] * k; + _out->v[4] = _A->v[4] * k; + _out->v[5] = _A->v[5] * k; + _out->v[6] = _A->v[6] * k; + _out->v[7] = _A->v[7] * k; + _out->v[8] = _A->v[8] * k; + _out->v[9] = _A->v[9] * k; + _out->v[10] = _A->v[10] * k; + _out->v[11] = _A->v[11] * k; + _out->v[12] = _A->v[12] * k; + _out->v[13] = _A->v[13] * k; + _out->v[14] = _A->v[14] * k; + _out->v[15] = _A->v[15] * k; +} + +/******************************************************************************/ + +void SST_Math_Mat44uMultiplyScalarLocal(SST_Mat44u* RESTRICT _A, const unsigned int k) +{ + SST_ASSUME_ALIGNED(_A,16); + + _A->v[0] *= k; + _A->v[1] *= k; + _A->v[2] *= k; + _A->v[3] *= k; + _A->v[4] *= k; + _A->v[5] *= k; + _A->v[6] *= k; + _A->v[7] *= k; + _A->v[8] *= k; + _A->v[9] *= k; + _A->v[10] *= k; + _A->v[11] *= k; + _A->v[12] *= k; + _A->v[13] *= k; + _A->v[14] *= k; + _A->v[15] *= k; +} + +/******************************************************************************/ + + +void SST_Math_Mat44uMultiplyMatrix(const SST_Mat44u* _A, const SST_Mat44u* RESTRICT _B, SST_Mat44u* RESTRICT _out) +{ +SST_ASSUME_ALIGNED(_A,16); +SST_ASSUME_ALIGNED(_B,16); +SST_ASSUME_ALIGNED(_out,16); +_out->v[ 0] = _A->v[ 0]*_B->v[ 0]+_A->v[ 4]*_B->v[ 1]+_A->v[ 8]*_B->v[ 2]+_A->v[12]*_B->v[ 3]; +_out->v[ 4] = _A->v[ 0]*_B->v[ 4]+_A->v[ 4]*_B->v[ 5]+_A->v[ 8]*_B->v[ 6]+_A->v[12]*_B->v[ 7]; +_out->v[ 8] = _A->v[ 0]*_B->v[ 8]+_A->v[ 4]*_B->v[ 9]+_A->v[ 8]*_B->v[10]+_A->v[12]*_B->v[11]; +_out->v[12] = _A->v[ 0]*_B->v[12]+_A->v[ 4]*_B->v[13]+_A->v[ 8]*_B->v[14]+_A->v[12]*_B->v[15]; +_out->v[ 1] = _A->v[ 1]*_B->v[ 0]+_A->v[ 5]*_B->v[ 1]+_A->v[ 9]*_B->v[ 2]+_A->v[13]*_B->v[ 3]; +_out->v[ 5] = _A->v[ 1]*_B->v[ 4]+_A->v[ 5]*_B->v[ 5]+_A->v[ 9]*_B->v[ 6]+_A->v[13]*_B->v[ 7]; +_out->v[ 9] = _A->v[ 1]*_B->v[ 8]+_A->v[ 5]*_B->v[ 9]+_A->v[ 9]*_B->v[10]+_A->v[13]*_B->v[11]; +_out->v[13] = _A->v[ 1]*_B->v[12]+_A->v[ 5]*_B->v[13]+_A->v[ 9]*_B->v[14]+_A->v[13]*_B->v[15]; +_out->v[ 2] = _A->v[ 2]*_B->v[ 0]+_A->v[ 6]*_B->v[ 1]+_A->v[10]*_B->v[ 2]+_A->v[14]*_B->v[ 3]; +_out->v[ 6] = _A->v[ 2]*_B->v[ 4]+_A->v[ 6]*_B->v[ 5]+_A->v[10]*_B->v[ 6]+_A->v[14]*_B->v[ 7]; +_out->v[10] = _A->v[ 2]*_B->v[ 8]+_A->v[ 6]*_B->v[ 9]+_A->v[10]*_B->v[10]+_A->v[14]*_B->v[11]; +_out->v[14] = _A->v[ 2]*_B->v[12]+_A->v[ 6]*_B->v[13]+_A->v[10]*_B->v[14]+_A->v[14]*_B->v[15]; +_out->v[ 3] = _A->v[ 3]*_B->v[ 0]+_A->v[ 7]*_B->v[ 1]+_A->v[11]*_B->v[ 2]+_A->v[15]*_B->v[ 3]; +_out->v[ 7] = _A->v[ 3]*_B->v[ 4]+_A->v[ 7]*_B->v[ 5]+_A->v[11]*_B->v[ 6]+_A->v[15]*_B->v[ 7]; +_out->v[11] = _A->v[ 3]*_B->v[ 8]+_A->v[ 7]*_B->v[ 9]+_A->v[11]*_B->v[10]+_A->v[15]*_B->v[11]; +_out->v[15] = _A->v[ 3]*_B->v[12]+_A->v[ 7]*_B->v[13]+_A->v[11]*_B->v[14]+_A->v[15]*_B->v[15]; +} +void SST_Math_Mat44uMultiplyMatrixLocal(SST_Mat44u* RESTRICT _A, const SST_Mat44u* RESTRICT _B) +{ + unsigned int tmp[16]; + SST_ASSUME_ALIGNED(_A,16); +SST_ASSUME_ALIGNED(_B,16); +tmp[ 0] = _A->v[ 0]*_B->v[ 0]+_A->v[ 4]*_B->v[ 1]+_A->v[ 8]*_B->v[ 2]+_A->v[12]*_B->v[ 3]; +tmp[ 4] = _A->v[ 0]*_B->v[ 4]+_A->v[ 4]*_B->v[ 5]+_A->v[ 8]*_B->v[ 6]+_A->v[12]*_B->v[ 7]; +tmp[ 8] = _A->v[ 0]*_B->v[ 8]+_A->v[ 4]*_B->v[ 9]+_A->v[ 8]*_B->v[10]+_A->v[12]*_B->v[11]; +tmp[12] = _A->v[ 0]*_B->v[12]+_A->v[ 4]*_B->v[13]+_A->v[ 8]*_B->v[14]+_A->v[12]*_B->v[15]; +_A->v[0] = tmp[0]; +_A->v[4] = tmp[4]; +_A->v[8] = tmp[8]; +_A->v[12] = tmp[12]; + + +tmp[ 1] = _A->v[ 1]*_B->v[ 0]+_A->v[ 5]*_B->v[ 1]+_A->v[ 9]*_B->v[ 2]+_A->v[13]*_B->v[ 3]; +tmp[ 5] = _A->v[ 1]*_B->v[ 4]+_A->v[ 5]*_B->v[ 5]+_A->v[ 9]*_B->v[ 6]+_A->v[13]*_B->v[ 7]; +tmp[ 9] = _A->v[ 1]*_B->v[ 8]+_A->v[ 5]*_B->v[ 9]+_A->v[ 9]*_B->v[10]+_A->v[13]*_B->v[11]; +tmp[13] = _A->v[ 1]*_B->v[12]+_A->v[ 5]*_B->v[13]+_A->v[ 9]*_B->v[14]+_A->v[13]*_B->v[15]; +_A->v[1] = tmp[1]; +_A->v[5] = tmp[5]; +_A->v[9] = tmp[9]; +_A->v[13] = tmp[13]; + + +tmp[ 2] = _A->v[ 2]*_B->v[ 0]+_A->v[ 6]*_B->v[ 1]+_A->v[10]*_B->v[ 2]+_A->v[14]*_B->v[ 3]; +tmp[ 6] = _A->v[ 2]*_B->v[ 4]+_A->v[ 6]*_B->v[ 5]+_A->v[10]*_B->v[ 6]+_A->v[14]*_B->v[ 7]; +tmp[10] = _A->v[ 2]*_B->v[ 8]+_A->v[ 6]*_B->v[ 9]+_A->v[10]*_B->v[10]+_A->v[14]*_B->v[11]; +tmp[14] = _A->v[ 2]*_B->v[12]+_A->v[ 6]*_B->v[13]+_A->v[10]*_B->v[14]+_A->v[14]*_B->v[15]; +_A->v[2] = tmp[2]; +_A->v[6] = tmp[6]; +_A->v[10] = tmp[10]; +_A->v[14] = tmp[14]; + + +tmp[ 3] = _A->v[ 3]*_B->v[ 0]+_A->v[ 7]*_B->v[ 1]+_A->v[11]*_B->v[ 2]+_A->v[15]*_B->v[ 3]; +tmp[ 7] = _A->v[ 3]*_B->v[ 4]+_A->v[ 7]*_B->v[ 5]+_A->v[11]*_B->v[ 6]+_A->v[15]*_B->v[ 7]; +tmp[11] = _A->v[ 3]*_B->v[ 8]+_A->v[ 7]*_B->v[ 9]+_A->v[11]*_B->v[10]+_A->v[15]*_B->v[11]; +tmp[15] = _A->v[ 3]*_B->v[12]+_A->v[ 7]*_B->v[13]+_A->v[11]*_B->v[14]+_A->v[15]*_B->v[15]; +_A->v[3] = tmp[3]; +_A->v[7] = tmp[7]; +_A->v[11] = tmp[11]; +_A->v[15] = tmp[15]; + + +} +void SST_Math_Mat44uMultiplyVector(const SST_Mat44u* RESTRICT _A, const SST_Vec4u* RESTRICT _v, SST_Vec4u* RESTRICT _out) +{ +SST_ASSUME_ALIGNED(_A,16); +SST_ASSUME_ALIGNED(_v,16); +SST_ASSUME_ALIGNED(_out,16); +_out->v[ 0] = _A->v[ 0]*_v->v[0]+_A->v[ 4]*_v->v[1]+_A->v[ 8]*_v->v[2]+_A->v[12]*_v->v[3]; +_out->v[ 1] = _A->v[ 1]*_v->v[0]+_A->v[ 5]*_v->v[1]+_A->v[ 9]*_v->v[2]+_A->v[13]*_v->v[3]; +_out->v[ 2] = _A->v[ 2]*_v->v[0]+_A->v[ 6]*_v->v[1]+_A->v[10]*_v->v[2]+_A->v[14]*_v->v[3]; +_out->v[ 3] = _A->v[ 3]*_v->v[0]+_A->v[ 7]*_v->v[1]+_A->v[11]*_v->v[2]+_A->v[15]*_v->v[3]; +} +void SST_Math_Mat44uMultiplyVectorLocal(const SST_Mat44u* RESTRICT _A, SST_Vec4u* RESTRICT _v) +{ +unsigned int tmp[4]; +SST_ASSUME_ALIGNED(_A,16); +SST_ASSUME_ALIGNED(_v,16); +tmp[ 0] = _A->v[ 0]*_v->v[0]+_A->v[ 4]*_v->v[1]+_A->v[ 8]*_v->v[2]+_A->v[12]*_v->v[3]; +tmp[ 1] = _A->v[ 1]*_v->v[0]+_A->v[ 5]*_v->v[1]+_A->v[ 9]*_v->v[2]+_A->v[13]*_v->v[3]; +tmp[ 2] = _A->v[ 2]*_v->v[0]+_A->v[ 6]*_v->v[1]+_A->v[10]*_v->v[2]+_A->v[14]*_v->v[3]; +tmp[ 3] = _A->v[ 3]*_v->v[0]+_A->v[ 7]*_v->v[1]+_A->v[11]*_v->v[2]+_A->v[15]*_v->v[3]; +_v->v[0] = tmp[0]; +_v->v[1] = tmp[1]; +_v->v[2] = tmp[2]; +_v->v[3] = tmp[3]; +} +void SST_Math_Mat44uTranspose(const SST_Mat44u* RESTRICT _A, SST_Mat44u* RESTRICT _out) +{ +SST_ASSUME_ALIGNED(_A,16); +SST_ASSUME_ALIGNED(_out,16); +_out->v[ 0] = _A->v[ 0]; +_out->v[ 1] = _A->v[ 4]; +_out->v[ 2] = _A->v[ 8]; +_out->v[ 3] = _A->v[12]; +_out->v[ 4] = _A->v[ 1]; +_out->v[ 5] = _A->v[ 5]; +_out->v[ 6] = _A->v[ 9]; +_out->v[ 7] = _A->v[13]; +_out->v[ 8] = _A->v[ 2]; +_out->v[ 9] = _A->v[ 6]; +_out->v[10] = _A->v[10]; +_out->v[11] = _A->v[14]; +_out->v[12] = _A->v[ 3]; +_out->v[13] = _A->v[ 7]; +_out->v[14] = _A->v[11]; +_out->v[15] = _A->v[15]; +} +void SST_Math_Mat44uTransposeLocal(SST_Mat44u* RESTRICT _A) +{ +unsigned int tmp[4]; +SST_ASSUME_ALIGNED(_A,16); +tmp[1] = _A->v[ 4]; +_A->v[ 4] = _A->v[ 1]; +_A->v[ 1] = tmp[1]; +tmp[2] = _A->v[ 8]; +_A->v[ 8] = _A->v[ 2]; +_A->v[ 2] = tmp[2]; +tmp[3] = _A->v[12]; +_A->v[12] = _A->v[ 3]; +_A->v[ 3] = tmp[3]; +tmp[2] = _A->v[ 9]; +_A->v[ 9] = _A->v[ 6]; +_A->v[ 6] = tmp[2]; +tmp[3] = _A->v[13]; +_A->v[13] = _A->v[ 7]; +_A->v[ 7] = tmp[3]; +tmp[3] = _A->v[14]; +_A->v[14] = _A->v[11]; +_A->v[11] = tmp[3]; +} diff --git a/libsst-math/SST_Mat44u_benchmark.c b/libsst-math/SST_Mat44u_benchmark.c new file mode 100644 index 0000000..9e46a78 --- /dev/null +++ b/libsst-math/SST_Mat44u_benchmark.c @@ -0,0 +1,689 @@ +#include <float.h> +#include <math.h> +#include <stdlib.h> +#include <stdio.h> +#include <assert.h> +#include <xmmintrin.h> +#include <SST/SST_Timer_x86.h> +#include <SST/SST_Mat44.h> +#include <SST/SST_Vec4.h> + + + + +int SST_Math_Mat44u_test_fxns() +{ +const int NTESTS = 10; +int i; +uint64_t t0,t1; +SST_Mat44u X; /* 4 x 4 matrix */ +SST_Mat44u Y; /* 4 x 4 matrix */ +SST_Mat44u A; /* 4 x 4 matrix */ +SST_Mat44u B; /* 4 x 4 matrix */ +SST_Vec4u v; /* 4 vector */ +SST_Vec4u w; /* 4 vector */ +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +/* Resetting test vectors / mats */ + v.v[0] = 15; + v.v[1] = 7; + v.v[2] = 12; + v.v[3] = 29; + X.v[0] = 6; + X.v[1] = 36; + X.v[2] = 21; + X.v[3] = 26; + X.v[4] = 28; + X.v[5] = 22; + X.v[6] = 31; + X.v[7] = 11; + X.v[8] = 22; + X.v[9] = 11; + X.v[10] = 20; + X.v[11] = 9; + X.v[12] = 4; + X.v[13] = 25; + X.v[14] = 26; + X.v[15] = 32; + Y.v[0] = 9; + Y.v[1] = 22; + Y.v[2] = 6; + Y.v[3] = 0; + Y.v[4] = 34; + Y.v[5] = 12; + Y.v[6] = 36; + Y.v[7] = 16; + Y.v[8] = 33; + Y.v[9] = 29; + Y.v[10] = 10; + Y.v[11] = 38; + Y.v[12] = 8; + Y.v[13] = 3; + Y.v[14] = 5; + Y.v[15] = 31; +SST_Math_Mat44uAdd(&X,&Y,&A); /* clear out the initial finding of object */ +/* Clear out the rdtsc register */ +fprintf(stdout,"SST_Math_Mat44uAdd(X,Y,A)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat44uAdd(&X,&Y,&A); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +/* +[[ 6 28 22 4] + [36 22 11 25] + [21 31 20 26] + [26 11 9 32]] +[[ 9 34 33 8] + [22 12 29 3] + [ 6 36 10 5] + [ 0 16 38 31]] +[[15 62 55 12] + [58 34 40 28] + [27 67 30 31] + [26 27 47 63]] +*/ +assert((A.v[0])==(15)); +assert((A.v[4])==(62)); +assert((A.v[8])==(55)); +assert((A.v[12])==(12)); +assert((A.v[1])==(58)); +assert((A.v[5])==(34)); +assert((A.v[9])==(40)); +assert((A.v[13])==(28)); +assert((A.v[2])==(27)); +assert((A.v[6])==(67)); +assert((A.v[10])==(30)); +assert((A.v[14])==(31)); +assert((A.v[3])==(26)); +assert((A.v[7])==(27)); +assert((A.v[11])==(47)); +assert((A.v[15])==(63)); +/* +[[ 6 28 22 4] + [36 22 11 25] + [21 31 20 26] + [26 11 9 32]] +[[ 9 34 33 8] + [22 12 29 3] + [ 6 36 10 5] + [ 0 16 38 31]] +[[15 62 55 12] + [58 34 40 28] + [27 67 30 31] + [26 27 47 63]] +*/ +fprintf(stdout,"SST_Math_Mat44uAddLocal(A,Y)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat44uAddLocal(&A,&Y); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +SST_Math_Mat44uAddLocal(&X,&Y); /* for accuracy */ +assert((X.v[0])==(15)); +assert((X.v[4])==(62)); +assert((X.v[8])==(55)); +assert((X.v[12])==(12)); +assert((X.v[1])==(58)); +assert((X.v[5])==(34)); +assert((X.v[9])==(40)); +assert((X.v[13])==(28)); +assert((X.v[2])==(27)); +assert((X.v[6])==(67)); +assert((X.v[10])==(30)); +assert((X.v[14])==(31)); +assert((X.v[3])==(26)); +assert((X.v[7])==(27)); +assert((X.v[11])==(47)); +assert((X.v[15])==(63)); +/* Resetting test vectors / mats */ + v.v[0] = 7; + v.v[1] = 34; + v.v[2] = 14; + v.v[3] = 35; + X.v[0] = 30; + X.v[1] = 26; + X.v[2] = 28; + X.v[3] = 21; + X.v[4] = 24; + X.v[5] = 32; + X.v[6] = 35; + X.v[7] = 6; + X.v[8] = 17; + X.v[9] = 18; + X.v[10] = 10; + X.v[11] = 34; + X.v[12] = 14; + X.v[13] = 2; + X.v[14] = 25; + X.v[15] = 26; + Y.v[0] = 22; + Y.v[1] = 1; + Y.v[2] = 21; + Y.v[3] = 27; + Y.v[4] = 2; + Y.v[5] = 39; + Y.v[6] = 38; + Y.v[7] = 17; + Y.v[8] = 20; + Y.v[9] = 22; + Y.v[10] = 35; + Y.v[11] = 37; + Y.v[12] = 24; + Y.v[13] = 0; + Y.v[14] = 20; + Y.v[15] = 9; +/* +[[30 24 17 14] + [26 32 18 2] + [28 35 10 25] + [21 6 34 26]] +[[60 48 34 28] + [52 64 36 4] + [56 70 20 50] + [42 12 68 52]] +*/ +fprintf(stdout,"SST_Math_Mat44uMultiplyScalar(X,t,Y)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat44uMultiplyScalar(&X,2,&A); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +assert((A.v[0])==(60)); +assert((A.v[4])==(48)); +assert((A.v[8])==(34)); +assert((A.v[12])==(28)); +assert((A.v[1])==(52)); +assert((A.v[5])==(64)); +assert((A.v[9])==(36)); +assert((A.v[13])==(4)); +assert((A.v[2])==(56)); +assert((A.v[6])==(70)); +assert((A.v[10])==(20)); +assert((A.v[14])==(50)); +assert((A.v[3])==(42)); +assert((A.v[7])==(12)); +assert((A.v[11])==(68)); +assert((A.v[15])==(52)); +/* +[[30 24 17 14] + [26 32 18 2] + [28 35 10 25] + [21 6 34 26]] +[[60 48 34 28] + [52 64 36 4] + [56 70 20 50] + [42 12 68 52]] +*/ +fprintf(stdout,"SST_Math_Mat44uMultiplyScalarLocal(A,t)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat44uMultiplyScalarLocal(&A,2); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +SST_Math_Mat44uMultiplyScalarLocal(&X,2); +assert((X.v[0])==(60)); +assert((X.v[4])==(48)); +assert((X.v[8])==(34)); +assert((X.v[12])==(28)); +assert((X.v[1])==(52)); +assert((X.v[5])==(64)); +assert((X.v[9])==(36)); +assert((X.v[13])==(4)); +assert((X.v[2])==(56)); +assert((X.v[6])==(70)); +assert((X.v[10])==(20)); +assert((X.v[14])==(50)); +assert((X.v[3])==(42)); +assert((X.v[7])==(12)); +assert((X.v[11])==(68)); +assert((X.v[15])==(52)); +/* Resetting test vectors / mats */ + v.v[0] = 3; + v.v[1] = 26; + v.v[2] = 14; + v.v[3] = 12; + X.v[0] = 22; + X.v[1] = 9; + X.v[2] = 9; + X.v[3] = 11; + X.v[4] = 39; + X.v[5] = 37; + X.v[6] = 35; + X.v[7] = 1; + X.v[8] = 3; + X.v[9] = 33; + X.v[10] = 25; + X.v[11] = 13; + X.v[12] = 34; + X.v[13] = 9; + X.v[14] = 32; + X.v[15] = 16; + Y.v[0] = 30; + Y.v[1] = 17; + Y.v[2] = 29; + Y.v[3] = 11; + Y.v[4] = 22; + Y.v[5] = 25; + Y.v[6] = 10; + Y.v[7] = 13; + Y.v[8] = 14; + Y.v[9] = 10; + Y.v[10] = 13; + Y.v[11] = 32; + Y.v[12] = 35; + Y.v[13] = 19; + Y.v[14] = 21; + Y.v[15] = 31; +/* +[[22 39 3 34] + [ 9 37 33 9] + [ 9 35 25 32] + [11 1 13 16]] +[[30 22 14 35] + [17 25 10 19] + [29 10 13 21] + [11 13 32 31]] +[[ 660 858 42 1190] + [ 153 925 330 171] + [ 261 350 325 672] + [ 121 13 416 496]] +*/ +fprintf(stdout,"SST_Math_Mat44uMultiplyElementwise(X,Y,A)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat44uMultiplyElementwise(&X, &Y, &A); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +assert((A.v[0])==(660)); +assert((A.v[4])==(858)); +assert((A.v[8])==(42)); +assert((A.v[12])==(1190)); +assert((A.v[1])==(153)); +assert((A.v[5])==(925)); +assert((A.v[9])==(330)); +assert((A.v[13])==(171)); +assert((A.v[2])==(261)); +assert((A.v[6])==(350)); +assert((A.v[10])==(325)); +assert((A.v[14])==(672)); +assert((A.v[3])==(121)); +assert((A.v[7])==(13)); +assert((A.v[11])==(416)); +assert((A.v[15])==(496)); +/* +[[22 39 3 34] + [ 9 37 33 9] + [ 9 35 25 32] + [11 1 13 16]] +[[30 22 14 35] + [17 25 10 19] + [29 10 13 21] + [11 13 32 31]] +[[ 660 858 42 1190] + [ 153 925 330 171] + [ 261 350 325 672] + [ 121 13 416 496]] +*/ +fprintf(stdout,"SST_Math_Mat44uMultiplyElementwiseLocal(X,Y)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat44uMultiplyElementwiseLocal(&A,&Y); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +SST_Math_Mat44uMultiplyElementwiseLocal(&X,&Y); +assert((X.v[0])==(660)); +assert((X.v[4])==(858)); +assert((X.v[8])==(42)); +assert((X.v[12])==(1190)); +assert((X.v[1])==(153)); +assert((X.v[5])==(925)); +assert((X.v[9])==(330)); +assert((X.v[13])==(171)); +assert((X.v[2])==(261)); +assert((X.v[6])==(350)); +assert((X.v[10])==(325)); +assert((X.v[14])==(672)); +assert((X.v[3])==(121)); +assert((X.v[7])==(13)); +assert((X.v[11])==(416)); +assert((X.v[15])==(496)); +/* Resetting test vectors / mats */ + v.v[0] = 12; + v.v[1] = 32; + v.v[2] = 34; + v.v[3] = 7; + X.v[0] = 9; + X.v[1] = 38; + X.v[2] = 14; + X.v[3] = 19; + X.v[4] = 5; + X.v[5] = 6; + X.v[6] = 34; + X.v[7] = 34; + X.v[8] = 7; + X.v[9] = 26; + X.v[10] = 9; + X.v[11] = 37; + X.v[12] = 39; + X.v[13] = 3; + X.v[14] = 8; + X.v[15] = 4; + Y.v[0] = 2; + Y.v[1] = 25; + Y.v[2] = 12; + Y.v[3] = 4; + Y.v[4] = 25; + Y.v[5] = 29; + Y.v[6] = 16; + Y.v[7] = 6; + Y.v[8] = 20; + Y.v[9] = 37; + Y.v[10] = 36; + Y.v[11] = 34; + Y.v[12] = 18; + Y.v[13] = 5; + Y.v[14] = 2; + Y.v[15] = 4; +/* +X +[[ 9 5 7 39] + [38 6 26 3] + [14 34 9 8] + [19 34 37 4]] +Y +[[ 2 25 20 18] + [25 29 37 5] + [12 16 36 2] + [ 4 6 34 4]] +[[ 383 716 1943 357] + [ 550 1558 2020 778] + [1018 1528 2134 472] + [1348 2077 3106 602]] +*/ +fprintf(stdout,"SST_Math_Mat44uMultiplyMatrix(X,Y,A)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat44uMultiplyMatrix(&X,&Y,&A); +t1 = rdtsc(); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +assert((A.v[0])==(383)); +assert((A.v[4])==(716)); +assert((A.v[8])==(1943)); +assert((A.v[12])==(357)); +assert((A.v[1])==(550)); +assert((A.v[5])==(1558)); +assert((A.v[9])==(2020)); +assert((A.v[13])==(778)); +assert((A.v[2])==(1018)); +assert((A.v[6])==(1528)); +assert((A.v[10])==(2134)); +assert((A.v[14])==(472)); +assert((A.v[3])==(1348)); +assert((A.v[7])==(2077)); +assert((A.v[11])==(3106)); +assert((A.v[15])==(602)); +/* +X +[[ 9 5 7 39] + [38 6 26 3] + [14 34 9 8] + [19 34 37 4]] +Y +[[ 2 25 20 18] + [25 29 37 5] + [12 16 36 2] + [ 4 6 34 4]] +X +[[ 383 716 1943 357] + [ 550 1558 2020 778] + [1018 1528 2134 472] + [1348 2077 3106 602]] +*/ +fprintf(stdout,"SST_Math_Mat44uMultiplyMatrixLocal(X,Y)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat44uMultiplyMatrixLocal(&A,&Y); +t1 = rdtsc(); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +SST_Math_Mat44uMultiplyMatrixLocal(&X,&Y); +assert((X.v[0])==(383)); +assert((X.v[4])==(716)); +assert((X.v[8])==(1943)); +assert((X.v[12])==(357)); +assert((X.v[1])==(550)); +assert((X.v[5])==(1558)); +assert((X.v[9])==(2020)); +assert((X.v[13])==(778)); +assert((X.v[2])==(1018)); +assert((X.v[6])==(1528)); +assert((X.v[10])==(2134)); +assert((X.v[14])==(472)); +assert((X.v[3])==(1348)); +assert((X.v[7])==(2077)); +assert((X.v[11])==(3106)); +assert((X.v[15])==(602)); +/* Resetting test vectors / mats */ + v.v[0] = 8; + v.v[1] = 4; + v.v[2] = 7; + v.v[3] = 3; + X.v[0] = 20; + X.v[1] = 11; + X.v[2] = 0; + X.v[3] = 12; + X.v[4] = 11; + X.v[5] = 6; + X.v[6] = 34; + X.v[7] = 20; + X.v[8] = 3; + X.v[9] = 13; + X.v[10] = 17; + X.v[11] = 11; + X.v[12] = 9; + X.v[13] = 16; + X.v[14] = 34; + X.v[15] = 20; + Y.v[0] = 12; + Y.v[1] = 17; + Y.v[2] = 27; + Y.v[3] = 3; + Y.v[4] = 33; + Y.v[5] = 29; + Y.v[6] = 14; + Y.v[7] = 13; + Y.v[8] = 29; + Y.v[9] = 18; + Y.v[10] = 28; + Y.v[11] = 31; + Y.v[12] = 33; + Y.v[13] = 9; + Y.v[14] = 35; + Y.v[15] = 16; +/* +X +[[20 11 3 9] + [11 6 13 16] + [ 0 34 17 34] + [12 20 11 20]] +v +[8 4 7 3] +w +[252 251 357 313] +*/ +i=0; +fprintf(stdout,"SST_Math_Mat44uMultiplyVector(X,v,w)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat44uMultiplyVector(&X,&v,&w); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +assert((w.v[0])==(252)); +assert((w.v[1])==(251)); +assert((w.v[2])==(357)); +assert((w.v[3])==(313)); +/* +X +[[20 11 3 9] + [11 6 13 16] + [ 0 34 17 34] + [12 20 11 20]] +v +[8 4 7 3] +v +[252 251 357 313] +*/ +fprintf(stdout,"SST_Math_Mat44uMultiplyVectorLocal(X,v)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat44uMultiplyVectorLocal(&X,&w); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +SST_Math_Mat44uMultiplyVectorLocal(&X,&v); +assert((v.v[0])==(252)); +assert((v.v[1])==(251)); +assert((v.v[2])==(357)); +assert((v.v[3])==(313)); +/* Resetting test vectors / mats */ + v.v[0] = 20; + v.v[1] = 16; + v.v[2] = 38; + v.v[3] = 29; + X.v[0] = 35; + X.v[1] = 31; + X.v[2] = 23; + X.v[3] = 0; + X.v[4] = 10; + X.v[5] = 32; + X.v[6] = 37; + X.v[7] = 21; + X.v[8] = 26; + X.v[9] = 6; + X.v[10] = 18; + X.v[11] = 20; + X.v[12] = 22; + X.v[13] = 33; + X.v[14] = 2; + X.v[15] = 30; + Y.v[0] = 20; + Y.v[1] = 33; + Y.v[2] = 7; + Y.v[3] = 30; + Y.v[4] = 34; + Y.v[5] = 37; + Y.v[6] = 30; + Y.v[7] = 30; + Y.v[8] = 9; + Y.v[9] = 0; + Y.v[10] = 10; + Y.v[11] = 31; + Y.v[12] = 22; + Y.v[13] = 7; + Y.v[14] = 1; + Y.v[15] = 32; +fprintf(stdout,"SST_Math_Mat44uTranspose(X,A)"); +t0 = rdtsc(); +SST_Math_Mat44uTranspose(&X,&A); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +assert((A.v[0])==(35)); +assert((A.v[4])==(31)); +assert((A.v[8])==(23)); +assert((A.v[12])==(0)); +assert((A.v[1])==(10)); +assert((A.v[5])==(32)); +assert((A.v[9])==(37)); +assert((A.v[13])==(21)); +assert((A.v[2])==(26)); +assert((A.v[6])==(6)); +assert((A.v[10])==(18)); +assert((A.v[14])==(20)); +assert((A.v[3])==(22)); +assert((A.v[7])==(33)); +assert((A.v[11])==(2)); +assert((A.v[15])==(30)); +fprintf(stdout,"SST_Math_Mat44uTransposeLocal(X)"); +for(i = 0; i < NTESTS; i++) { +t0 = rdtsc(); +SST_Math_Mat44uTransposeLocal(&A); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +} +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +SST_Math_Mat44uTransposeLocal(&X); +assert((X.v[0])==(35)); +assert((X.v[4])==(31)); +assert((X.v[8])==(23)); +assert((X.v[12])==(0)); +assert((X.v[1])==(10)); +assert((X.v[5])==(32)); +assert((X.v[9])==(37)); +assert((X.v[13])==(21)); +assert((X.v[2])==(26)); +assert((X.v[6])==(6)); +assert((X.v[10])==(18)); +assert((X.v[14])==(20)); +assert((X.v[3])==(22)); +assert((X.v[7])==(33)); +assert((X.v[11])==(2)); +assert((X.v[15])==(30)); +/* +[[-0.67171203 0.53583792 -0.51132829 0.01496829] + [-0.59494494 -0.20412719 0.58270865 0.51460979] + [-0.44141076 -0.54027758 -0.00728165 -0.71638234] + [-0. -0.61588144 -0.63161776 0.47090239]] +[[ 1.00000000e+00 -8.32667268e-17 3.51281504e-17 5.55111512e-17] + [ -8.32667268e-17 1.00000000e+00 2.22044605e-16 2.22044605e-16] + [ 3.51281504e-17 2.22044605e-16 1.00000000e+00 5.55111512e-17] + [ 5.55111512e-17 2.22044605e-16 5.55111512e-17 1.00000000e+00]] +*/ +X.v[0] = (unsigned int)0; +X.v[4] = (unsigned int)0; +X.v[8] = (unsigned int)0; +X.v[12] = (unsigned int)0; +X.v[1] = (unsigned int)0; +X.v[5] = (unsigned int)0; +X.v[9] = (unsigned int)0; +X.v[13] = (unsigned int)0; +X.v[2] = (unsigned int)0; +X.v[6] = (unsigned int)0; +X.v[10] = (unsigned int)0; +X.v[14] = (unsigned int)0; +X.v[3] = (unsigned int)0; +X.v[7] = (unsigned int)0; +X.v[11] = (unsigned int)0; +X.v[15] = (unsigned int)0; +fprintf(stdout,"SST_Math_Mat44uTranspose(X,A)"); +t0 = rdtsc(); +SST_Math_Mat44uTranspose(&X,&A); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +fprintf(stdout,"SST_Math_Mat44uMultiplyMatrix(A,X,B)"); +t0 = rdtsc(); +SST_Math_Mat44uMultiplyMatrix(&A,&X,&B); +t1 = rdtsc(); +fprintf(stdout," timing:%llu\n",(long long unsigned int)(t1-t0)); +fprintf(stdout,"\n==== SST_Math_Mat44utest_fxn COMPLETE ====\n"); +return 0; +} diff --git a/libsst-math/SST_Transform.c b/libsst-math/SST_Transform.c new file mode 100644 index 0000000..87fb0a6 --- /dev/null +++ b/libsst-math/SST_Transform.c @@ -0,0 +1,544 @@ + +#include <math.h> /* tanf() */ +#include <string.h> /* memset() */ +#include <SST/SST_Math.h> + +/* Will form the 4x4 identity matrix. + * Remember that you can save operations by + * simply zeroing what you're not going to fill in yourself */ +void SST_Math_Mat33fCreateIdentity(SST_Mat33f* Mat) +{ + memset(Mat, 0, sizeof(SST_Mat33f)); + Mat->v[0] = 1.f; + Mat->v[4] = 1.f; + Mat->v[8] = 1.f; +} + +void SST_Math_Mat33fFromVec3f(SST_Mat33f* Mat, const SST_Vec3f* v, const int column) +{ + Mat->v[0+3*column] = v->v[0]; + Mat->v[1+3*column] = v->v[1]; + Mat->v[2+3*column] = v->v[2]; +} + +void SST_Math_Mat44fFromVec4f(SST_Mat44f* Mat, const SST_Vec4f* v, const int column) +{ + Mat->v[0+4*column] = v->v[0]; + Mat->v[1+4*column] = v->v[1]; + Mat->v[2+4*column] = v->v[2]; + Mat->v[3+4*column] = v->v[3]; +} +void SST_Math_Mat33dFromVec3d(SST_Mat33d* Mat, const SST_Vec3d* v, const int column) +{ + Mat->v[0+3*column] = v->v[0]; + Mat->v[1+3*column] = v->v[1]; + Mat->v[2+3*column] = v->v[2]; +} +void SST_Math_Mat44dFromVec4d(SST_Mat44d* Mat, const SST_Vec4d* v, const int column) +{ + Mat->v[0+4*column] = v->v[0]; + Mat->v[1+4*column] = v->v[1]; + Mat->v[2+4*column] = v->v[2]; + Mat->v[3+4*column] = v->v[3]; +} +/* Will form the 4x4 identity matrix. + * Remember that you can save operations by + * simply zeroing what you're not going to fill in yourself */ +void SST_Math_Mat44fCreateIdentity(SST_Mat44f* Mat) +{ + memset(Mat, 0, sizeof(SST_Mat44f)); + Mat->v[0] = 1.f; + Mat->v[5] = 1.f; + Mat->v[10] = 1.f; + Mat->v[15] = 1.f; +} +void SST_Math_Mat33fApplyTransforms(SST_Vec3f** Vecs, SST_Mat33f* Transforms, const int num_Vecs) +{ + int i; + for(i=0; i < num_Vecs; i++) + SST_Math_Mat33fMultiplyVectorLocal(Transforms, Vecs[i]); +} +void SST_Math_Mat33fCreateTranslation(SST_Mat33f* Mat, const float x, const float y) +{ + memset(Mat, 0, sizeof(SST_Mat33f)); + Mat->v[0] = 1.f; + Mat->v[4] = 1.f; + + Mat->v[6] = x; + Mat->v[7] = y; + Mat->v[8] = 1.f; +} +void SST_Math_Mat44fCreateTranslation(SST_Mat44f* Mat, const float x, const float y, const float z) +{ + memset(Mat, 0, sizeof(SST_Mat44f)); + Mat->v[0] = 1.f; + Mat->v[5] = 1.f; + Mat->v[10] = 1.f; + + Mat->v[12] = x; + Mat->v[13] = y; + Mat->v[14] = z; + Mat->v[15] = 1.f; +} +/* Forms the matrix to rotate around the X-axis some angle (RADIANS)*/ +void SST_Math_Mat44fCreateEulerX(SST_Mat44f* Mat, const float angle) +{ + Mat->v[0] = 1.f; + Mat->v[1] = 0.f; + Mat->v[2] = 0.f; + Mat->v[3] = 0.f; + + Mat->v[4] = 0.f; + Mat->v[5] = cosf(angle); + Mat->v[6] = sinf(angle); + Mat->v[7] = 0.f; + + Mat->v[8] = 0.f; + Mat->v[9] = -sinf(angle); + Mat->v[10] = cosf(angle); + Mat->v[11] = 0.f; + + Mat->v[12] = 0.f; + Mat->v[13] = 0.f; + Mat->v[14] = 0.f; + Mat->v[15] = 1.f; +} +/* Forms the matrix to rotate around the X-axis some angle(RADIANS) + * and applies it to the given Mat */ +void SST_Math_Mat44fCreateEulerY(SST_Mat44f* Mat, const float angle) +{ + Mat->v[0] = cosf(angle); + Mat->v[1] = 0.f; + Mat->v[2] = -sinf(angle); + Mat->v[3] = 0.f; + + Mat->v[4] = 0.f; + Mat->v[5] = 1.f; + Mat->v[6] = 0.f; + Mat->v[7] = 0.f; + + Mat->v[8] = sinf(angle); + Mat->v[9] = 0.f; + Mat->v[10] = cosf(angle); + Mat->v[11] = 0.f; + + Mat->v[12] = 0.f; + Mat->v[13] = 0.f; + Mat->v[14] = 0.f; + Mat->v[15] = 1.f; +} +void SST_Math_Mat33fRAT(SST_Mat33f* _mat,const SST_Vec2f* _about, const SST_Vec2f* _translation, const float angle) +{ + const float cosa = cosf(angle); + const float sina = sinf(angle); + + _mat->v[0] = cosa; + _mat->v[1] = sina; + _mat->v[2] = 0.f; + + _mat->v[3] = -sina; + _mat->v[4] = cosa; + _mat->v[5] = 0.f; + + _mat->v[6] = -cosa * _about->v[0] + sina * _about->v[1] + _about->v[0] + _translation->v[0]; + _mat->v[6] = -sina * _about->v[0] + -cosa * _about->v[1] + _about->v[1] + _translation->v[1]; + _mat->v[8] = 1.f; + +} +void SST_Math_Mat33fCreateEulerZ(SST_Mat33f* Mat, const float angle) +{ + const float cosa = cosf(angle); + const float sina = sinf(angle); + + Mat->v[0] = cosa; + Mat->v[1] = sina; + Mat->v[2] = 0.f; + + Mat->v[3] = -sina; + Mat->v[4] = cosa; + Mat->v[5] = 0.f; + + Mat->v[6] = 0.f; + Mat->v[7] = 0.f; + Mat->v[8] = 1.f; +} + +void SST_Math_Mat44fCreateEulerZ(SST_Mat44f* Mat, const float angle) +{ + const float cosa = cosf(angle); + const float sina = sinf(angle); + Mat->v[0] = cosa; + Mat->v[1] = sina; + Mat->v[2] = 0.f; + Mat->v[3] = 0.f; + + Mat->v[4] = -sina; + Mat->v[5] = cosa; + Mat->v[6] = 0.f; + Mat->v[7] = 0.f; + + Mat->v[8] = 0.f; + Mat->v[9] = 0.f; + Mat->v[10] = 1.f; + Mat->v[11] = 0.f; + + Mat->v[12] = 0.f; + Mat->v[13] = 0.f; + Mat->v[14] = 0.f; + Mat->v[15] = 1.f; +} +/* The chained forms are designed so that they can be chained if desired, e.g.: + float Original[16]; + Original = SST_Math_Mat33fCreateEulerZ(-30, SST_Math_Mat33fCreateEulerX(-45, SST_Math_Mat33fCreateEulerY(30, Original))); + --Charles + */ +/* Forms the matrix to rotate around the X-axis some angle (RADIANS)*/ +/* Much faster to do this than Create and then multiply */ +void SST_Math_Mat44fCreateEulerXC(SST_Mat44f* Mat, const float angle) +{ +#define Mat(i,j) Mat->v[i+4*j] + float cosv = cosf(angle); + float sinv = sinf(angle); + float nsinv = -sinv; + float t[8]; + int i; + t[0] = nsinv*Mat(2,0); + t[1] = nsinv*Mat(2,1); + t[2] = nsinv*Mat(2,2); + t[3] = nsinv*Mat(2,3); + + t[4] = sinv*Mat(1,0); + t[5] = sinv*Mat(1,1); + t[6] = sinv*Mat(1,2); + t[7] = sinv*Mat(1,3); + //If this fails, it's probably the next two lines,and the offset of t[]; + + for(i=0;i<4;i++) + Mat(1,i)= cosv*Mat(1,i)+t[i]; + for(i=0;i<4;i++) + Mat(2,i)= cosv*Mat(2,i)+t[i+4]; + +#undef Mat +} +/* Forms the matrix to rotate around the X-axis some angle(RADIANS) + * and applies it to the given Mat */ +void SST_Math_Mat44fCreateEulerYC(SST_Mat44f* Mat, const float angle) +{ +#define Mat(i,j) Mat->v[i+4*j] + float cosv = cosf(angle); + float sinv = sinf(angle); + float t[8]; + int i; + t[0] = sinv*Mat(2,0); + t[1] = sinv*Mat(2,1); + t[2] = sinv*Mat(2,2); + t[3] = sinv*Mat(2,3); + + t[4] = -sinv*Mat(0,0); + t[5] = -sinv*Mat(0,1); + t[6] = -sinv*Mat(0,2); + t[7] = -sinv*Mat(0,3); + + for(i=0;i<4;i++) + Mat(0,i) = cosv*Mat(0,i)+t[i]; + for(i=0;i<4;i++) + Mat(2,i) = cosv*Mat(2,i)+t[i+4]; +#undef Mat +} +void SST_Math_Mat44fCreateEulerZC(SST_Mat44f* Mat, const float angle) +{ +#define Mat(i,j) Mat->v[i+4*j] + float cosv = cosf(angle); + float sinv = sinf(angle); + float t[8]; + int i; + t[0] = -sinv*Mat(1,0); + t[1] = -sinv*Mat(1,1); + t[2] = -sinv*Mat(1,2); + t[3] = -sinv*Mat(1,3); + + t[4] = sinv*Mat(0,0); + t[5] = sinv*Mat(0,1); + t[6] = sinv*Mat(0,2); + t[7] = sinv*Mat(0,3); + + for(i=0;i<4;i++) + Mat(0,i) = cosv*Mat(0,i)+t[i]; + for(i=0;i<4;i++) + Mat(1,i) = cosv*Mat(1,i)+t[i+4]; +#undef Mat +} +/* Forms the Shear Mat described as: + * X' = M * X + * where M = I + ShearX + ShearY + ShearZ + * shearing[0:1] -- x in y, x in z + * shearing[2:3] -- y in x, y in z + * shearing[4:5] -- z in x, z in y + */ +void SST_Math_Mat44fCreateShear(SST_Mat44f* Mat, const float x_in_y, const float x_in_z, const float y_in_x, const float y_in_z, const float z_in_x, const float z_in_y) +{ +#define Mat(i,j) Mat->v[i+4*j] + Mat(0,0) = 1.0; + Mat(1,0) = y_in_x; + Mat(2,0) = z_in_x; + Mat(3,0) = 0.0; + + Mat(0,1) = x_in_y; + Mat(1,1) = 1.0; + Mat(2,1) = z_in_y; + Mat(3,1) = 0.0; + + Mat(0,2) = x_in_z; + Mat(1,2) = y_in_z; + Mat(2,2) = 1.0; + Mat(3,2) = 0.0; + + Mat(0,3) = 0.0; + Mat(1,3) = 0.0; + Mat(2,3) = 0.0; + Mat(3,3) = 1.0; +#undef Mat +} +/* Forms the Free Transform Mat described as: + * X' = M * X + * where M = ScaleM + Shear_forX + Shear_forY + Shear_forZ + * scale[0:2] -- scale x,y,z + * shearing[0:1] -- x in y, x in z + * shearing[2:3] -- y in x, y in z + * shearing[4:5] -- z in x, z in y + */ +void SST_Math_Mat44fCreateFreeTransform(SST_Mat44f* Mat,const float scale_x, const float scale_y, const float scale_z, const float x_in_y, const float x_in_z, const float y_in_x, const float y_in_z, const float z_in_x, const float z_in_y) +{ +#define Mat(i,j) Mat->v[i+4*j] + Mat(0,0) = scale_x; + Mat(1,0) = y_in_x; + Mat(2,0) = z_in_x; + Mat(3,0) = 0.0; + + Mat(0,1) = x_in_y; + Mat(1,1) = scale_y; + Mat(2,1) = z_in_y; + Mat(3,1) = 0.0; + + Mat(0,2) = x_in_z; + Mat(1,2) = y_in_z; + Mat(2,2) = scale_z; + Mat(3,2) = 0.0; + + Mat(0,3) = 0.0; + Mat(1,3) = 0.0; + Mat(2,3) = 0.0; + Mat(3,3) = 1.0; +#undef Mat +} + +void SST_Math_Mat44fConvertQuaternion(SST_Mat44f* Mat,const SST_Vec4f* q) +{ + /* From Wikipedia - 8/30/2012 */ +#define Mat(i,j) Mat->v[i+4*j] + Mat(0,0) = q->x; + Mat(1,0) = -q->y; + Mat(2,0) = -q->z; + Mat(3,0) = -q->w; + + Mat(0,1) = q->y; + Mat(1,1) = q->x; + Mat(2,1) = q->w; + Mat(3,1) = -q->z; + + Mat(0,2) = q->z; + Mat(1,2) = -q->w; + Mat(2,2) = q->x; + Mat(3,2) = q->y; + + Mat(0,3) = q->w; + Mat(1,3) = q->z; + Mat(2,3) = -q->y; + Mat(3,3) = q->x; +#undef Mat +} +void SST_Math_Mat44fCreateRotationFromQuaternion(SST_Mat44f* Mat,const SST_Vec4f* q) +{ + /* From Wikipedia - 8/30/2012 */ +#define Mat(i,j) Mat->v[i+4*j] + const float norm = sqrtf(q->x * q->x + q->y * q->y + q->z * q->z + q->w * q->w); + const float a = q->x / norm; + const float b = q->y / norm; + const float c = q->z / norm; + const float d = q->w / norm; + Mat(0,0) = a*a + b*b - c*c - d*d; + Mat(1,0) = 2.f * (b*c+a*d); + Mat(2,0) = 2.f * (b*d-a*c); + Mat(3,0) = 0.f; + + Mat(0,1) = 2.f * (b*c-a*d); + Mat(1,1) = a*a - b*b + c*c - d*d; + Mat(2,1) = 2.f * (c*d-a*b); + Mat(3,1) = 0.f; + + Mat(0,2) = 2.f * (b*d + a*c); + Mat(1,2) = 2.f * (c*d - a*b); + Mat(2,2) = a*a-b*b-c*c+d*d; + Mat(3,2) = 0.f; + + Mat(0,3) = 0.f; + Mat(1,3) = 0.f; + Mat(2,3) = 0.f; + Mat(3,3) = 1.f; +#undef Mat +} + +void SST_Math_Mat44fCreateScale(SST_Mat44f* Mat, const float scale_x, const float scale_y, const float scale_z) +{ + memset(Mat, 0, sizeof(SST_Mat44f)); + Mat->v[0] = scale_x; + Mat->v[5] = scale_y; + Mat->v[10] = scale_z; + Mat->v[15] = 1; +} + + +void SST_Math_Mat44fCreateLookAt(SST_Mat44f* Mat, const SST_Vec3f* eye,const SST_Vec3f* at, const SST_Vec3f* up) +{ +#define Mat(i,j) Mat->v[i+4*j] + int i; + SST_Vec3f F; + SST_Vec3f UP; + SST_Vec3f s; + SST_Vec3f u; + SST_Mat44f tmp; + + SST_Math_Vec3fNormalize(up,&UP); + SST_Math_Vec3fSubtract(at,eye,&F); + SST_Math_Vec3fNormalizeLocal(&F); + SST_Math_Vec3fCross(&F,&UP,&s); + SST_Math_Vec3fCross(&s,&F,&u); + + for(i=0;i<3;i++) + { + Mat(0,i) = s.v[i]; + Mat(1,i) = u.v[i]; + Mat(2,i) = -F.v[i]; + Mat(3,i) = 0.0f; + } + + + Mat(0,3) = 0; + Mat(1,3) = 0; + Mat(2,3) = 0; + Mat(3,3) = 1.f; + + /* Multiply by translation matrix */ + SST_Math_Mat44fCreateTranslation(&tmp, -eye->x, -eye->y, -eye->z); + SST_Math_Mat44fMultiplyMatrixLocal(Mat, &tmp); + + +#undef Mat +} + +void SST_Math_Mat44fCreateLookDir(SST_Mat44f* Mat, const SST_Vec3f* eye,const SST_Vec3f* dir, const SST_Vec3f* up) +{ +#define Mat(i,j) Mat->v[i+4*j] + int i; + SST_Vec3f F; + SST_Vec3f UP; + SST_Vec3f s; + SST_Vec3f u; + SST_Vec3f at; + SST_Mat44f tmp; + + SST_Math_Vec3fAdd(eye,dir,&at); + SST_Math_Vec3fNormalize(up,&UP); + SST_Math_Vec3fSubtract(&at,eye,&F); + SST_Math_Vec3fNormalizeLocal(&F); + SST_Math_Vec3fCross(&F,&UP,&s); + SST_Math_Vec3fCross(&s,&F,&u); + + for(i=0;i<3;i++) + { + Mat(0,i) = s.v[i]; + Mat(1,i) = u.v[i]; + Mat(2,i) = -F.v[i]; + Mat(3,i) = 0.0f; + } + Mat(0,3) = 0; + Mat(1,3) = 0; + Mat(2,3) = 0; + Mat(3,3) = 1.f; + + /* Multiply by translation matrix */ + SST_Math_Mat44fCreateTranslation(&tmp, -eye->x, -eye->y, -eye->z); + SST_Math_Mat44fMultiplyMatrixLocal(Mat, &tmp); + +#undef Mat +} + +/* Extracts the 3x3 matrix most used from Geo routines from a 4x4 matrix */ +void SST_Math_Mat33fCreateFromMat44f(const SST_Mat44f* Mat44, SST_Mat33f* Mat33) +{ +#define Mat33(i,j) Mat33->v[i+3*j] +#define Mat44(i,j) Mat44->v[i+4*j] + int i; + for(i=0;i<3;i++) + { + Mat33(i,0) = Mat44(i,0); + Mat33(i,1) = Mat44(i,1); + Mat33(i,2) = Mat44(i,2); + } +#undef Mat33 +#undef Mat44 +} +void SST_Math_Mat44fCreatePerspective(SST_Mat44f* Mat, const float FOV_in_y, const float aspect_in_x, const float zNear, const float zFar) +{ +#define Mat(i,j) Mat->v[i + 4*j] + const float f = tanf(((float)M_PI_2) - FOV_in_y * ((float)M_PI) / 360.f); + memset(Mat, 0, sizeof(SST_Mat44f)); + Mat(0,0) = f/aspect_in_x; + Mat(1,1) = f; + Mat(2,2) = (zFar+zNear)/(zNear-zFar); + Mat(3,2) = -1.f; + Mat(2,3) = (2.f * zFar * zNear)/(zNear-zFar); +#undef Mat +} +void SST_Math_Mat44fCreateOrtho(SST_Mat44f* Mat, const float left, const float right, const float bottom, const float top, const float nearVal, const float farVal) +{ +#define Mat(i,j) Mat->v[i + 4*j] + const float rl = right - left; + const float tb = top - bottom; + const float fn = farVal - nearVal; + memset(Mat, 0, sizeof(SST_Mat44f)); + Mat(0,0) = 2.f/rl; + Mat(1,1) = 2.f/tb; + Mat(2,2) = -2.f/fn; + + Mat(0,3) = -(right+left)/rl; + Mat(1,3) = -(top+bottom)/tb; + Mat(2,3) = -(farVal+nearVal)/fn; + Mat(3,3) = 1.f; +#undef Mat +} +void SST_Math_Mat33fHomogenousMultiplyAssumed(const SST_Mat33f* Mat,const SST_Vec2f* VecIn, SST_Vec2f* VecOut) +{ +#define Mat(i,j) Mat->v[i + 3*j] +#define VI(i) VecIn->v[i] + float recipz; + recipz = 1.f / (Mat(2,0)*VI(0) + Mat(2,1) * VI(1) + Mat(2,2)); + VecOut->v[0] = recipz*(Mat(0,0)*VI(0) + Mat(0,1) * VI(1) + Mat(0,2)); + VecOut->v[1] = recipz*(Mat(1,0)*VI(0) + Mat(1,1) * VI(1) + Mat(1,2)); +#undef Mat +#undef VI +} + +void SST_Math_Mat33fHomogenousMultiplyAssumedLocal(const SST_Mat33f* Mat, SST_Vec2f* Vec) +{ +#define Mat(i,j) Mat->v[i + 3*j] +#define VI(i) Vec->v[i] + float tmp,tmp2,recipz; + tmp = Mat(0,0)*VI(0) + Mat(0,1) * VI(1) + Mat(0,2); + tmp2 = Mat(1,0)*VI(0) + Mat(1,1) * VI(1) + Mat(1,2); + recipz = 1.f / (Mat(2,0)*VI(0) + Mat(2,1) * VI(1) + Mat(2,2)); + VI(0) = tmp * recipz; + VI(1) = tmp2 * recipz; +#undef Mat +#undef VI +} diff --git a/libsst-math/SST_Vec2d.c b/libsst-math/SST_Vec2d.c new file mode 100644 index 0000000..502979e --- /dev/null +++ b/libsst-math/SST_Vec2d.c @@ -0,0 +1,467 @@ +/* + AUTOMATICALLY GENERATED FILE - DO NOT EDIT! + Please change MatrixNxN.py and re-run it +*/ +/* Generated with ./VectorN.py n = 2, TYPE = double */ + +#include <float.h> +#include <math.h> +#include <pstdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <SST/SST_Build.h> +#include <SST/SST_Vec2.h> + +void SST_Math_Vec2dAdd(const SST_Vec2d* RESTRICT _A, const SST_Vec2d* RESTRICT _B, SST_Vec2d* RESTRICT _out) +{ + _out->v[0] = _A->v[0] + _B->v[0]; + _out->v[1] = _A->v[1] + _B->v[1]; +} + +/******************************************************************************/ + +void SST_Math_Vec2dAddLocal(SST_Vec2d* RESTRICT _A, const SST_Vec2d* RESTRICT _B) +{ + _A->v[0] += _B->v[0]; + _A->v[1] += _B->v[1]; +} + +/******************************************************************************/ + +void SST_Math_Vec2dSubtract(const SST_Vec2d* RESTRICT _A, const SST_Vec2d* RESTRICT _B, SST_Vec2d* RESTRICT _out) +{ + _out->v[0] = _A->v[0] - _B->v[0]; + _out->v[1] = _A->v[1] - _B->v[1]; +} + +/******************************************************************************/ + +void SST_Math_Vec2dSubtractLocal(SST_Vec2d* RESTRICT _A, const SST_Vec2d* RESTRICT _B) +{ + _A->v[0] -= _B->v[0]; + _A->v[1] -= _B->v[1]; +} + +/******************************************************************************/ + +void SST_Math_Vec2dMultiply(const SST_Vec2d* RESTRICT _A, const SST_Vec2d* RESTRICT _B, SST_Vec2d* RESTRICT _out) +{ + _out->v[0] = _A->v[0] * _B->v[0]; + _out->v[1] = _A->v[1] * _B->v[1]; +} + +/******************************************************************************/ + +void SST_Math_Vec2dMultiplyLocal(SST_Vec2d* RESTRICT _A, const SST_Vec2d* RESTRICT _B) +{ + _A->v[0] *= _B->v[0]; + _A->v[1] *= _B->v[1]; +} + +/******************************************************************************/ + +void SST_Math_Vec2dScale(const SST_Vec2d* RESTRICT _A, const double k, SST_Vec2d* RESTRICT _out) +{ + _out->v[0] = _A->v[0] * k; + _out->v[1] = _A->v[1] * k; +} + +/******************************************************************************/ + +void SST_Math_Vec2dScaleLocal(SST_Vec2d* RESTRICT _A, const double k) +{ + _A->v[0] *= k; + _A->v[1] *= k; +} + +/******************************************************************************/ + +void SST_Math_Vec2dDivide(const SST_Vec2d* RESTRICT _A, const SST_Vec2d* RESTRICT _B, SST_Vec2d* RESTRICT _out) +{ + _out->v[0] = _A->v[0] / _B->v[0]; + _out->v[1] = _A->v[1] / _B->v[1]; +} + +/******************************************************************************/ + +void SST_Math_Vec2dDivideLocal(SST_Vec2d* RESTRICT _A, const SST_Vec2d* RESTRICT _B) +{ + _A->v[0] /= _B->v[0]; + _A->v[1] /= _B->v[1]; +} + +/******************************************************************************/ + + +/******************************************************************************/ + + +void SST_Math_Vec2dAddMult(const SST_Vec2d* RESTRICT _X, const double _x, const SST_Vec2d* RESTRICT _Y, SST_Vec2d* RESTRICT _Z) +{ + SST_ASSUME_ALIGNED(_X,16); + SST_ASSUME_ALIGNED(_Y,16); + SST_ASSUME_ALIGNED(_Z,16); + /* _Z = _x * _X + _Y */ + _Z->v[0] = _x * _X->v[0] + _Y->v[0]; + _Z->v[1] = _x * _X->v[1] + _Y->v[1]; + +} + + +void SST_Math_Vec2dAddMultLocal(SST_Vec2d* RESTRICT _X, const double _x, const SST_Vec2d* RESTRICT _Y) +{ + SST_ASSUME_ALIGNED(_X,16); + SST_ASSUME_ALIGNED(_Y,16); + /* _X = _x * _X + _Y */ + _X->v[0] = _x * _X->v[0] + _Y->v[0]; + _X->v[1] = _x * _X->v[1] + _Y->v[1]; + +} + + +/******************************************************************************/ + + +void SST_Math_Vec2dLerp(const SST_Vec2d* RESTRICT _X, const SST_Vec2d* RESTRICT _Y, const double _y, SST_Vec2d* RESTRICT _Z) +{ + SST_ASSUME_ALIGNED(_X,16); + SST_ASSUME_ALIGNED(_Y,16); + SST_ASSUME_ALIGNED(_Z,16); + /* Z = x*X + y*Y */ + _Z->v[0] = _X->v[0] + (_Y->v[0] - _X->v[0]) * _y ; + _Z->v[1] = _X->v[1] + (_Y->v[1] - _X->v[1]) * _y ; + +} + +void SST_Math_Vec2dLerpLocal(SST_Vec2d* RESTRICT _X, const SST_Vec2d* RESTRICT _Y, const double _y) +{ + SST_ASSUME_ALIGNED(_X,16); + SST_ASSUME_ALIGNED(_Y,16); + /* Z = x*X + y*Y */ + _X->v[0] = _X->v[0] + (_Y->v[0] - _X->v[0]) * _y ; + _X->v[1] = _X->v[1] + (_Y->v[1] - _X->v[1]) * _y ; + +} + +/******************************************************************************/ + + +void SST_Math_Vec2dWeightedSum(const SST_Vec2d* RESTRICT _X, const double _x, const SST_Vec2d* RESTRICT _Y, const double _y, SST_Vec2d* RESTRICT _Z) +{ + SST_ASSUME_ALIGNED(_X,16); + SST_ASSUME_ALIGNED(_Y,16); + SST_ASSUME_ALIGNED(_Z,16); + /* Z = x*X + y*Y */ + _Z->v[0] = _x * _X->v[0] + _y * _Y->v[0]; + _Z->v[1] = _x * _X->v[1] + _y * _Y->v[1]; + +} + +void SST_Math_Vec2dWeightedSumLocal(SST_Vec2d* RESTRICT _X, const double _x, const SST_Vec2d* RESTRICT _Y, const double _y) +{ + SST_ASSUME_ALIGNED(_X,16); + SST_ASSUME_ALIGNED(_Y,16); + /* Z = x*X + y*Y */ + _X->v[0] = _x * _X->v[0] + _y * _Y->v[0]; + _X->v[1] = _x * _X->v[1] + _y * _Y->v[1]; + +} + +/******************************************************************************/ + +bool SST_Math_Vec2dEquals(const SST_Vec2d* RESTRICT _a, const SST_Vec2d* RESTRICT _b, const double _tolerance) +{ + SST_Vec2d tmp; + int i; + bool returncode; + SST_ASSUME_ALIGNED(_a,16); + SST_ASSUME_ALIGNED(_b,16); + returncode = 1; + + SST_Math_Vec2dSubtract(_a,_b,&tmp); + for(i=0;i<2;i++) + { + returncode = (fabs(tmp.v[i]) <= _tolerance) && returncode; + } + + return returncode; +} + + +/******************************************************************************/ + +double SST_Math_Vec2dMax(const SST_Vec2d* RESTRICT _a) +{ + double tmp = _a->v[0]; + if(tmp < _a->v[1]) tmp = _a->v[1]; + + return tmp; +} + +/******************************************************************************/ + +double SST_Math_Vec2dMin(const SST_Vec2d* RESTRICT _a) +{ + double tmp = _a->v[0]; + if(tmp > _a->v[1]) tmp = _a->v[1]; + + return tmp; +} + +/******************************************************************************/ + +void SST_Math_Vec2dCross(const SST_Vec2d* RESTRICT _a, const SST_Vec2d* RESTRICT _b, SST_Vec2d* RESTRICT _out) + { + + _out->v[0] = _a->v[0]*_b->v[1] - _a->v[1]*_b->v[0]; + _out->v[1] = _out->v[0]; +} + +/******************************************************************************/ + +void SST_Math_Vec2dCrossLocal(SST_Vec2d* RESTRICT _a, const SST_Vec2d* RESTRICT _b) +{ + SST_Vec2d out; + + out.v[0] = _a->v[0]*_b->v[1] - _a->v[1]*_b->v[0]; + _a->v[0] = out.v[0]; + _a->v[1] = out.v[0]; +} + +/******************************************************************************/ + +void SST_Math_Vec2dRotateAbout(const SST_Vec2d* RESTRICT _a, const SST_Vec2d* RESTRICT _about,double _theta, SST_Vec2d* RESTRICT _out) +{ + + + const double cosa = cos(_theta); + const double sina = sin(_theta); + _out->x = cosa * (_a->x-_about->x) + sina * (_a->y-_about->y) + _about->x; + _out->y = -sina * (_a->x-_about->x) + cosa * (_a->y-_about->y) + _about->y; + +} + +/******************************************************************************/ + +void SST_Math_Vec2dRotateAboutLocal(SST_Vec2d* RESTRICT _a, const SST_Vec2d* RESTRICT _about,double _theta) +{ + + + double tmp; + const double cosa = cos(_theta); + const double sina = sin(_theta); + + _a->x -= _about->x; + _a->y -= _about->y; + + tmp = cosa * (_a->x) + sina * (_a->y) + _about->x; + _a->y = -sina * (_a->x) + cosa * (_a->y) + _about->y; + _a->x = tmp; + +} + +/******************************************************************************/ + +void SST_Math_Vec2dRotate(const SST_Vec2d* RESTRICT _a,double _theta, SST_Vec2d* RESTRICT _out) +{ + + + const double cosa = cos(_theta); + const double sina = sin(_theta); + _out->x = cosa * (_a->x) + sina * (_a->y); + _out->y = -sina * (_a->x) + cosa * (_a->y); + +} + +/******************************************************************************/ + +void SST_Math_Vec2dRotateLocal(SST_Vec2d* RESTRICT _a, double _theta) +{ + + + const double cosa = cos(_theta); + const double sina = sin(_theta); + double tmp; + + tmp = cosa * (_a->x) + sina * (_a->y); + _a->y = -sina * (_a->x) + cosa * (_a->y); + _a->x = tmp; + +} +void SST_Math_Vec2dNormalize(const SST_Vec2d* RESTRICT _in, SST_Vec2d* RESTRICT _out) +{ + double scalar = 1.f/SST_Math_Vec2dMagnitude(_in); + SST_Math_Vec2dScale(_in,scalar,_out); +} + +/******************************************************************************/ + +void SST_Math_Vec2dNormalizeLocal(SST_Vec2d* _inout) +{ + double scalar = 1.f/SST_Math_Vec2dMagnitude(_inout); + SST_Math_Vec2dScaleLocal(_inout,scalar); +} + +/******************************************************************************/ + +void SST_Math_Vec2dRecipSqrt(const SST_Vec2d* RESTRICT _in, SST_Vec2d* RESTRICT _out) +{ + int i; + for(i = 0; i < 2; i++) + _out->v[i] = 1/sqrt(_in->v[i]); +} + +/******************************************************************************/ + +void SST_Math_Vec2dRecipSqrtLocal(SST_Vec2d* RESTRICT _a) +{ + int i; + for(i = 0; i < 2; i++) + _a->v[i] = 1/sqrt(_a->v[i]); +} + +/******************************************************************************/ + +void SST_Math_Vec2dSqrt(const SST_Vec2d* RESTRICT _in, SST_Vec2d* RESTRICT _out) +{ + int i; + for(i = 0; i < 2; i++) + _out->v[i] = sqrt(_in->v[i]); +} + +/******************************************************************************/ + +void SST_Math_Vec2dSqrtLocal(SST_Vec2d* RESTRICT _a) +{ + int i; + for(i = 0; i < 2; i++) + _a->v[i] = sqrt(_a->v[i]); +} + +/******************************************************************************/ + +double SST_Math_Vec2dMagnitude(const SST_Vec2d* RESTRICT _a) +{ + double sum = 0; + int i; + for(i = 0; i < 2; i++) + sum += _a->v[i] * _a->v[i]; + return sqrt(sum); +} + +/******************************************************************************/ + +void SST_Math_Vec2dAbs(const SST_Vec2d* RESTRICT _in, SST_Vec2d* RESTRICT _out) +{ + int i; + for(i = 0; i < 2; i++) + _out->v[i] = fabs(_in->v[i]); +} + +/******************************************************************************/ + +void SST_Math_Vec2dAbsLocal(SST_Vec2d* RESTRICT _a) +{ + int i; + for(i = 0; i < 2; i++) + _a->v[i] = fabs(_a->v[i]); +} + +/******************************************************************************/ + +void SST_Math_Vec2dNegate(const SST_Vec2d* RESTRICT _in, SST_Vec2d* RESTRICT _out) +{ + int i; + for(i = 0; i < 2; i++) + _out->v[i] = -(_in->v[i]); +} + +/******************************************************************************/ + +void SST_Math_Vec2dNegateLocal(SST_Vec2d* RESTRICT _a) +{ + int i; + for(i = 0; i < 2; i++) + _a->v[i] = -(_a->v[i]); +} + +/******************************************************************************/ + +void SST_Math_Vec2dRecip(const SST_Vec2d* RESTRICT _in, SST_Vec2d* RESTRICT _out) +{ + int i; + for(i = 0; i < 2; i++) + _out->v[i] = 1/(_in->v[i]); +} + +/******************************************************************************/ + +void SST_Math_Vec2dRecipLocal(SST_Vec2d* RESTRICT _a) +{ + int i; + for(i = 0; i < 2; i++) + _a->v[i] = 1/(_a->v[i]); +} + +/******************************************************************************/ + +double SST_Math_Vec2dDot(const SST_Vec2d* RESTRICT _a, const SST_Vec2d* RESTRICT _b) +{ + double sum = 0; + int i; + for(i = 0; i < 2; i++) + sum += _a->v[i] * _b->v[i]; + return sum; +} + +/******************************************************************************/ + +double SST_Math_Vec2dMagnitudeSquared(const SST_Vec2d* RESTRICT _a) +{ + double sum = 0; + int i; + for(i = 0; i < 2; i++) + sum += _a->v[i] * _a->v[i]; + return sum; +} + +/******************************************************************************/ + +void SST_Math_Vec2dProject(const SST_Vec2d* RESTRICT _a, const SST_Vec2d* RESTRICT _b, SST_Vec2d* RESTRICT _out) +{ + double scalar = SST_Math_Vec2dDot(_a,_b) / SST_Math_Vec2dDot(_b,_b); + SST_Math_Vec2dScale(_b, scalar, _out); +} + + +/******************************************************************************/ + +void SST_Math_Vec2dProjectLocal(SST_Vec2d* RESTRICT _a, const SST_Vec2d* RESTRICT _b) +{ + double scalar = SST_Math_Vec2dDot(_a,_b) / SST_Math_Vec2dDot(_b,_b); + SST_Math_Vec2dScale(_b, scalar, _a); +} + + +/******************************************************************************/ + +void SST_Math_Vec2dBias(const SST_Vec2d* RESTRICT _a, const double _bias, SST_Vec2d* RESTRICT _out) +{ + int i; + for(i = 0; i < 2; i++) + _out->v[i] = _a->v[i] + _bias; +} + + +/******************************************************************************/ + +void SST_Math_Vec2dBiasLocal(SST_Vec2d* RESTRICT _a, const double _bias) +{ + int i; + for(i = 0; i < 2; i++) + _a->v[i] += _bias; +} + + +/******************************************************************************/ + diff --git a/libsst-math/SST_Vec2f.c b/libsst-math/SST_Vec2f.c new file mode 100644 index 0000000..6383fd7 --- /dev/null +++ b/libsst-math/SST_Vec2f.c @@ -0,0 +1,467 @@ +/* + AUTOMATICALLY GENERATED FILE - DO NOT EDIT! + Please change MatrixNxN.py and re-run it +*/ +/* Generated with ./VectorN.py n = 2, TYPE = float */ + +#include <float.h> +#include <math.h> +#include <pstdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <SST/SST_Build.h> +#include <SST/SST_Vec2.h> + +void SST_Math_Vec2fAdd(const SST_Vec2f* RESTRICT _A, const SST_Vec2f* RESTRICT _B, SST_Vec2f* RESTRICT _out) +{ + _out->v[0] = _A->v[0] + _B->v[0]; + _out->v[1] = _A->v[1] + _B->v[1]; +} + +/******************************************************************************/ + +void SST_Math_Vec2fAddLocal(SST_Vec2f* RESTRICT _A, const SST_Vec2f* RESTRICT _B) +{ + _A->v[0] += _B->v[0]; + _A->v[1] += _B->v[1]; +} + +/******************************************************************************/ + +void SST_Math_Vec2fSubtract(const SST_Vec2f* RESTRICT _A, const SST_Vec2f* RESTRICT _B, SST_Vec2f* RESTRICT _out) +{ + _out->v[0] = _A->v[0] - _B->v[0]; + _out->v[1] = _A->v[1] - _B->v[1]; +} + +/******************************************************************************/ + +void SST_Math_Vec2fSubtractLocal(SST_Vec2f* RESTRICT _A, const SST_Vec2f* RESTRICT _B) +{ + _A->v[0] -= _B->v[0]; + _A->v[1] -= _B->v[1]; +} + +/******************************************************************************/ + +void SST_Math_Vec2fMultiply(const SST_Vec2f* RESTRICT _A, const SST_Vec2f* RESTRICT _B, SST_Vec2f* RESTRICT _out) +{ + _out->v[0] = _A->v[0] * _B->v[0]; + _out->v[1] = _A->v[1] * _B->v[1]; +} + +/******************************************************************************/ + +void SST_Math_Vec2fMultiplyLocal(SST_Vec2f* RESTRICT _A, const SST_Vec2f* RESTRICT _B) +{ + _A->v[0] *= _B->v[0]; + _A->v[1] *= _B->v[1]; +} + +/******************************************************************************/ + +void SST_Math_Vec2fScale(const SST_Vec2f* RESTRICT _A, const float k, SST_Vec2f* RESTRICT _out) +{ + _out->v[0] = _A->v[0] * k; + _out->v[1] = _A->v[1] * k; +} + +/******************************************************************************/ + +void SST_Math_Vec2fScaleLocal(SST_Vec2f* RESTRICT _A, const float k) +{ + _A->v[0] *= k; + _A->v[1] *= k; +} + +/******************************************************************************/ + +void SST_Math_Vec2fDivide(const SST_Vec2f* RESTRICT _A, const SST_Vec2f* RESTRICT _B, SST_Vec2f* RESTRICT _out) +{ + _out->v[0] = _A->v[0] / _B->v[0]; + _out->v[1] = _A->v[1] / _B->v[1]; +} + +/******************************************************************************/ + +void SST_Math_Vec2fDivideLocal(SST_Vec2f* RESTRICT _A, const SST_Vec2f* RESTRICT _B) +{ + _A->v[0] /= _B->v[0]; + _A->v[1] /= _B->v[1]; +} + +/******************************************************************************/ + + +/******************************************************************************/ + + +void SST_Math_Vec2fAddMult(const SST_Vec2f* RESTRICT _X, const float _x, const SST_Vec2f* RESTRICT _Y, SST_Vec2f* RESTRICT _Z) +{ + SST_ASSUME_ALIGNED(_X,16); + SST_ASSUME_ALIGNED(_Y,16); + SST_ASSUME_ALIGNED(_Z,16); + /* _Z = _x * _X + _Y */ + _Z->v[0] = _x * _X->v[0] + _Y->v[0]; + _Z->v[1] = _x * _X->v[1] + _Y->v[1]; + +} + + +void SST_Math_Vec2fAddMultLocal(SST_Vec2f* RESTRICT _X, const float _x, const SST_Vec2f* RESTRICT _Y) +{ + SST_ASSUME_ALIGNED(_X,16); + SST_ASSUME_ALIGNED(_Y,16); + /* _X = _x * _X + _Y */ + _X->v[0] = _x * _X->v[0] + _Y->v[0]; + _X->v[1] = _x * _X->v[1] + _Y->v[1]; + +} + + +/******************************************************************************/ + + +void SST_Math_Vec2fLerp(const SST_Vec2f* RESTRICT _X, const SST_Vec2f* RESTRICT _Y, const float _y, SST_Vec2f* RESTRICT _Z) +{ + SST_ASSUME_ALIGNED(_X,16); + SST_ASSUME_ALIGNED(_Y,16); + SST_ASSUME_ALIGNED(_Z,16); + /* Z = x*X + y*Y */ + _Z->v[0] = _X->v[0] + (_Y->v[0] - _X->v[0]) * _y ; + _Z->v[1] = _X->v[1] + (_Y->v[1] - _X->v[1]) * _y ; + +} + +void SST_Math_Vec2fLerpLocal(SST_Vec2f* RESTRICT _X, const SST_Vec2f* RESTRICT _Y, const float _y) +{ + SST_ASSUME_ALIGNED(_X,16); + SST_ASSUME_ALIGNED(_Y,16); + /* Z = x*X + y*Y */ + _X->v[0] = _X->v[0] + (_Y->v[0] - _X->v[0]) * _y ; + _X->v[1] = _X->v[1] + (_Y->v[1] - _X->v[1]) * _y ; + +} + +/******************************************************************************/ + + +void SST_Math_Vec2fWeightedSum(const SST_Vec2f* RESTRICT _X, const float _x, const SST_Vec2f* RESTRICT _Y, const float _y, SST_Vec2f* RESTRICT _Z) +{ + SST_ASSUME_ALIGNED(_X,16); + SST_ASSUME_ALIGNED(_Y,16); + SST_ASSUME_ALIGNED(_Z,16); + /* Z = x*X + y*Y */ + _Z->v[0] = _x * _X->v[0] + _y * _Y->v[0]; + _Z->v[1] = _x * _X->v[1] + _y * _Y->v[1]; + +} + +void SST_Math_Vec2fWeightedSumLocal(SST_Vec2f* RESTRICT _X, const float _x, const SST_Vec2f* RESTRICT _Y, const float _y) +{ + SST_ASSUME_ALIGNED(_X,16); + SST_ASSUME_ALIGNED(_Y,16); + /* Z = x*X + y*Y */ + _X->v[0] = _x * _X->v[0] + _y * _Y->v[0]; + _X->v[1] = _x * _X->v[1] + _y * _Y->v[1]; + +} + +/******************************************************************************/ + +bool SST_Math_Vec2fEquals(const SST_Vec2f* RESTRICT _a, const SST_Vec2f* RESTRICT _b, const float _tolerance) +{ + SST_Vec2f tmp; + int i; + bool returncode; + SST_ASSUME_ALIGNED(_a,16); + SST_ASSUME_ALIGNED(_b,16); + returncode = 1; + + SST_Math_Vec2fSubtract(_a,_b,&tmp); + for(i=0;i<2;i++) + { + returncode = (fabsf(tmp.v[i]) <= _tolerance) && returncode; + } + + return returncode; +} + + +/******************************************************************************/ + +float SST_Math_Vec2fMax(const SST_Vec2f* RESTRICT _a) +{ + float tmp = _a->v[0]; + if(tmp < _a->v[1]) tmp = _a->v[1]; + + return tmp; +} + +/******************************************************************************/ + +float SST_Math_Vec2fMin(const SST_Vec2f* RESTRICT _a) +{ + float tmp = _a->v[0]; + if(tmp > _a->v[1]) tmp = _a->v[1]; + + return tmp; +} + +/******************************************************************************/ + +void SST_Math_Vec2fCross(const SST_Vec2f* RESTRICT _a, const SST_Vec2f* RESTRICT _b, SST_Vec2f* RESTRICT _out) + { + + _out->v[0] = _a->v[0]*_b->v[1] - _a->v[1]*_b->v[0]; + _out->v[1] = _out->v[0]; +} + +/******************************************************************************/ + +void SST_Math_Vec2fCrossLocal(SST_Vec2f* RESTRICT _a, const SST_Vec2f* RESTRICT _b) +{ + SST_Vec2f out; + + out.v[0] = _a->v[0]*_b->v[1] - _a->v[1]*_b->v[0]; + _a->v[0] = out.v[0]; + _a->v[1] = out.v[0]; +} + +/******************************************************************************/ + +void SST_Math_Vec2fRotateAbout(const SST_Vec2f* RESTRICT _a, const SST_Vec2f* RESTRICT _about,float _theta, SST_Vec2f* RESTRICT _out) +{ + + + const float cosa = cosf(_theta); + const float sina = sinf(_theta); + _out->x = cosa * (_a->x-_about->x) + sina * (_a->y-_about->y) + _about->x; + _out->y = -sina * (_a->x-_about->x) + cosa * (_a->y-_about->y) + _about->y; + +} + +/******************************************************************************/ + +void SST_Math_Vec2fRotateAboutLocal(SST_Vec2f* RESTRICT _a, const SST_Vec2f* RESTRICT _about,float _theta) +{ + + + float tmp; + const float cosa = cosf(_theta); + const float sina = sinf(_theta); + + _a->x -= _about->x; + _a->y -= _about->y; + + tmp = cosa * (_a->x) + sina * (_a->y) + _about->x; + _a->y = -sina * (_a->x) + cosa * (_a->y) + _about->y; + _a->x = tmp; + +} + +/******************************************************************************/ + +void SST_Math_Vec2fRotate(const SST_Vec2f* RESTRICT _a,float _theta, SST_Vec2f* RESTRICT _out) +{ + + + const float cosa = cosf(_theta); + const float sina = sinf(_theta); + _out->x = cosa * (_a->x) + sina * (_a->y); + _out->y = -sina * (_a->x) + cosa * (_a->y); + +} + +/******************************************************************************/ + +void SST_Math_Vec2fRotateLocal(SST_Vec2f* RESTRICT _a, float _theta) +{ + + + const float cosa = cosf(_theta); + const float sina = sinf(_theta); + float tmp; + + tmp = cosa * (_a->x) + sina * (_a->y); + _a->y = -sina * (_a->x) + cosa * (_a->y); + _a->x = tmp; + +} +void SST_Math_Vec2fNormalize(const SST_Vec2f* RESTRICT _in, SST_Vec2f* RESTRICT _out) +{ + float scalar = 1.f/SST_Math_Vec2fMagnitude(_in); + SST_Math_Vec2fScale(_in,scalar,_out); +} + +/******************************************************************************/ + +void SST_Math_Vec2fNormalizeLocal(SST_Vec2f* _inout) +{ + float scalar = 1.f/SST_Math_Vec2fMagnitude(_inout); + SST_Math_Vec2fScaleLocal(_inout,scalar); +} + +/******************************************************************************/ + +void SST_Math_Vec2fRecipSqrt(const SST_Vec2f* RESTRICT _in, SST_Vec2f* RESTRICT _out) +{ + int i; + for(i = 0; i < 2; i++) + _out->v[i] = 1/sqrtf(_in->v[i]); +} + +/******************************************************************************/ + +void SST_Math_Vec2fRecipSqrtLocal(SST_Vec2f* RESTRICT _a) +{ + int i; + for(i = 0; i < 2; i++) + _a->v[i] = 1/sqrtf(_a->v[i]); +} + +/******************************************************************************/ + +void SST_Math_Vec2fSqrt(const SST_Vec2f* RESTRICT _in, SST_Vec2f* RESTRICT _out) +{ + int i; + for(i = 0; i < 2; i++) + _out->v[i] = sqrtf(_in->v[i]); +} + +/******************************************************************************/ + +void SST_Math_Vec2fSqrtLocal(SST_Vec2f* RESTRICT _a) +{ + int i; + for(i = 0; i < 2; i++) + _a->v[i] = sqrtf(_a->v[i]); +} + +/******************************************************************************/ + +float SST_Math_Vec2fMagnitude(const SST_Vec2f* RESTRICT _a) +{ + float sum = 0; + int i; + for(i = 0; i < 2; i++) + sum += _a->v[i] * _a->v[i]; + return sqrtf(sum); +} + +/******************************************************************************/ + +void SST_Math_Vec2fAbs(const SST_Vec2f* RESTRICT _in, SST_Vec2f* RESTRICT _out) +{ + int i; + for(i = 0; i < 2; i++) + _out->v[i] = fabsf(_in->v[i]); +} + +/******************************************************************************/ + +void SST_Math_Vec2fAbsLocal(SST_Vec2f* RESTRICT _a) +{ + int i; + for(i = 0; i < 2; i++) + _a->v[i] = fabsf(_a->v[i]); +} + +/******************************************************************************/ + +void SST_Math_Vec2fNegate(const SST_Vec2f* RESTRICT _in, SST_Vec2f* RESTRICT _out) +{ + int i; + for(i = 0; i < 2; i++) + _out->v[i] = -(_in->v[i]); +} + +/******************************************************************************/ + +void SST_Math_Vec2fNegateLocal(SST_Vec2f* RESTRICT _a) +{ + int i; + for(i = 0; i < 2; i++) + _a->v[i] = -(_a->v[i]); +} + +/******************************************************************************/ + +void SST_Math_Vec2fRecip(const SST_Vec2f* RESTRICT _in, SST_Vec2f* RESTRICT _out) +{ + int i; + for(i = 0; i < 2; i++) + _out->v[i] = 1/(_in->v[i]); +} + +/******************************************************************************/ + +void SST_Math_Vec2fRecipLocal(SST_Vec2f* RESTRICT _a) +{ + int i; + for(i = 0; i < 2; i++) + _a->v[i] = 1/(_a->v[i]); +} + +/******************************************************************************/ + +float SST_Math_Vec2fDot(const SST_Vec2f* RESTRICT _a, const SST_Vec2f* RESTRICT _b) +{ + float sum = 0; + int i; + for(i = 0; i < 2; i++) + sum += _a->v[i] * _b->v[i]; + return sum; +} + +/******************************************************************************/ + +float SST_Math_Vec2fMagnitudeSquared(const SST_Vec2f* RESTRICT _a) +{ + float sum = 0; + int i; + for(i = 0; i < 2; i++) + sum += _a->v[i] * _a->v[i]; + return sum; +} + +/******************************************************************************/ + +void SST_Math_Vec2fProject(const SST_Vec2f* RESTRICT _a, const SST_Vec2f* RESTRICT _b, SST_Vec2f* RESTRICT _out) +{ + float scalar = SST_Math_Vec2fDot(_a,_b) / SST_Math_Vec2fDot(_b,_b); + SST_Math_Vec2fScale(_b, scalar, _out); +} + + +/******************************************************************************/ + +void SST_Math_Vec2fProjectLocal(SST_Vec2f* RESTRICT _a, const SST_Vec2f* RESTRICT _b) +{ + float scalar = SST_Math_Vec2fDot(_a,_b) / SST_Math_Vec2fDot(_b,_b); + SST_Math_Vec2fScale(_b, scalar, _a); +} + + +/******************************************************************************/ + +void SST_Math_Vec2fBias(const SST_Vec2f* RESTRICT _a, const float _bias, SST_Vec2f* RESTRICT _out) +{ + int i; + for(i = 0; i < 2; i++) + _out->v[i] = _a->v[i] + _bias; +} + + +/******************************************************************************/ + +void SST_Math_Vec2fBiasLocal(SST_Vec2f* RESTRICT _a, const float _bias) +{ + int i; + for(i = 0; i < 2; i++) + _a->v[i] += _bias; +} + + +/******************************************************************************/ + diff --git a/libsst-math/SST_Vec2i.c b/libsst-math/SST_Vec2i.c new file mode 100644 index 0000000..e7d1cf5 --- /dev/null +++ b/libsst-math/SST_Vec2i.c @@ -0,0 +1,322 @@ +/* + AUTOMATICALLY GENERATED FILE - DO NOT EDIT! + Please change MatrixNxN.py and re-run it +*/ +/* Generated with ./VectorN.py n = 2, TYPE = int */ + +#include <float.h> +#include <math.h> +#include <pstdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <SST/SST_Build.h> +#include <SST/SST_Vec2.h> + +void SST_Math_Vec2iAdd(const SST_Vec2i* RESTRICT _A, const SST_Vec2i* RESTRICT _B, SST_Vec2i* RESTRICT _out) +{ + _out->v[0] = _A->v[0] + _B->v[0]; + _out->v[1] = _A->v[1] + _B->v[1]; +} + +/******************************************************************************/ + +void SST_Math_Vec2iAddLocal(SST_Vec2i* RESTRICT _A, const SST_Vec2i* RESTRICT _B) +{ + _A->v[0] += _B->v[0]; + _A->v[1] += _B->v[1]; +} + +/******************************************************************************/ + +void SST_Math_Vec2iSubtract(const SST_Vec2i* RESTRICT _A, const SST_Vec2i* RESTRICT _B, SST_Vec2i* RESTRICT _out) +{ + _out->v[0] = _A->v[0] - _B->v[0]; + _out->v[1] = _A->v[1] - _B->v[1]; +} + +/******************************************************************************/ + +void SST_Math_Vec2iSubtractLocal(SST_Vec2i* RESTRICT _A, const SST_Vec2i* RESTRICT _B) +{ + _A->v[0] -= _B->v[0]; + _A->v[1] -= _B->v[1]; +} + +/******************************************************************************/ + +void SST_Math_Vec2iMultiply(const SST_Vec2i* RESTRICT _A, const SST_Vec2i* RESTRICT _B, SST_Vec2i* RESTRICT _out) +{ + _out->v[0] = _A->v[0] * _B->v[0]; + _out->v[1] = _A->v[1] * _B->v[1]; +} + +/******************************************************************************/ + +void SST_Math_Vec2iMultiplyLocal(SST_Vec2i* RESTRICT _A, const SST_Vec2i* RESTRICT _B) +{ + _A->v[0] *= _B->v[0]; + _A->v[1] *= _B->v[1]; +} + +/******************************************************************************/ + +void SST_Math_Vec2iScale(const SST_Vec2i* RESTRICT _A, const int k, SST_Vec2i* RESTRICT _out) +{ + _out->v[0] = _A->v[0] * k; + _out->v[1] = _A->v[1] * k; +} + +/******************************************************************************/ + +void SST_Math_Vec2iScaleLocal(SST_Vec2i* RESTRICT _A, const int k) +{ + _A->v[0] *= k; + _A->v[1] *= k; +} + +/******************************************************************************/ + +void SST_Math_Vec2iDivide(const SST_Vec2i* RESTRICT _A, const SST_Vec2i* RESTRICT _B, SST_Vec2i* RESTRICT _out) +{ + _out->v[0] = _A->v[0] / _B->v[0]; + _out->v[1] = _A->v[1] / _B->v[1]; +} + +/******************************************************************************/ + +void SST_Math_Vec2iDivideLocal(SST_Vec2i* RESTRICT _A, const SST_Vec2i* RESTRICT _B) +{ + _A->v[0] /= _B->v[0]; + _A->v[1] /= _B->v[1]; +} + +/******************************************************************************/ + + +/******************************************************************************/ + + +void SST_Math_Vec2iAddMult(const SST_Vec2i* RESTRICT _X, const int _x, const SST_Vec2i* RESTRICT _Y, SST_Vec2i* RESTRICT _Z) +{ + SST_ASSUME_ALIGNED(_X,16); + SST_ASSUME_ALIGNED(_Y,16); + SST_ASSUME_ALIGNED(_Z,16); + /* _Z = _x * _X + _Y */ + _Z->v[0] = _x * _X->v[0] + _Y->v[0]; + _Z->v[1] = _x * _X->v[1] + _Y->v[1]; + +} + + +void SST_Math_Vec2iAddMultLocal(SST_Vec2i* RESTRICT _X, const int _x, const SST_Vec2i* RESTRICT _Y) +{ + SST_ASSUME_ALIGNED(_X,16); + SST_ASSUME_ALIGNED(_Y,16); + /* _X = _x * _X + _Y */ + _X->v[0] = _x * _X->v[0] + _Y->v[0]; + _X->v[1] = _x * _X->v[1] + _Y->v[1]; + +} + + +/******************************************************************************/ + + +void SST_Math_Vec2iLerp(const SST_Vec2i* RESTRICT _X, const SST_Vec2i* RESTRICT _Y, const int _y, SST_Vec2i* RESTRICT _Z) +{ + SST_ASSUME_ALIGNED(_X,16); + SST_ASSUME_ALIGNED(_Y,16); + SST_ASSUME_ALIGNED(_Z,16); + /* Z = x*X + y*Y */ + _Z->v[0] = _X->v[0] + (_Y->v[0] - _X->v[0]) * _y ; + _Z->v[1] = _X->v[1] + (_Y->v[1] - _X->v[1]) * _y ; + +} + +void SST_Math_Vec2iLerpLocal(SST_Vec2i* RESTRICT _X, const SST_Vec2i* RESTRICT _Y, const int _y) +{ + SST_ASSUME_ALIGNED(_X,16); + SST_ASSUME_ALIGNED(_Y,16); + /* Z = x*X + y*Y */ + _X->v[0] = _X->v[0] + (_Y->v[0] - _X->v[0]) * _y ; + _X->v[1] = _X->v[1] + (_Y->v[1] - _X->v[1]) * _y ; + +} + +/******************************************************************************/ + + +void SST_Math_Vec2iWeightedSum(const SST_Vec2i* RESTRICT _X, const int _x, const SST_Vec2i* RESTRICT _Y, const int _y, SST_Vec2i* RESTRICT _Z) +{ + SST_ASSUME_ALIGNED(_X,16); + SST_ASSUME_ALIGNED(_Y,16); + SST_ASSUME_ALIGNED(_Z,16); + /* Z = x*X + y*Y */ + _Z->v[0] = _x * _X->v[0] + _y * _Y->v[0]; + _Z->v[1] = _x * _X->v[1] + _y * _Y->v[1]; + +} + +void SST_Math_Vec2iWeightedSumLocal(SST_Vec2i* RESTRICT _X, const int _x, const SST_Vec2i* RESTRICT _Y, const int _y) +{ + SST_ASSUME_ALIGNED(_X,16); + SST_ASSUME_ALIGNED(_Y,16); + /* Z = x*X + y*Y */ + _X->v[0] = _x * _X->v[0] + _y * _Y->v[0]; + _X->v[1] = _x * _X->v[1] + _y * _Y->v[1]; + +} + +/******************************************************************************/ + +bool SST_Math_Vec2iEquals(const SST_Vec2i* RESTRICT _a, const SST_Vec2i* RESTRICT _b) +{ + int i; + bool returncode; + SST_ASSUME_ALIGNED(_a,16); + SST_ASSUME_ALIGNED(_b,16); + returncode = 1; + for(i=0;i<2;i++) + { + returncode = (_a->v[i]==_b->v[i]) && returncode; + } + return returncode; +} + + +/******************************************************************************/ + +int SST_Math_Vec2iMax(const SST_Vec2i* RESTRICT _a) +{ + int tmp = _a->v[0]; + if(tmp < _a->v[1]) tmp = _a->v[1]; + + return tmp; +} + +/******************************************************************************/ + +int SST_Math_Vec2iMin(const SST_Vec2i* RESTRICT _a) +{ + int tmp = _a->v[0]; + if(tmp > _a->v[1]) tmp = _a->v[1]; + + return tmp; +} + +/******************************************************************************/ + +void SST_Math_Vec2iAbs(const SST_Vec2i* RESTRICT _in, SST_Vec2i* RESTRICT _out) +{ + int i; + for(i = 0; i < 2; i++) + _out->v[i] = abs(_in->v[i]); +} + +/******************************************************************************/ + +void SST_Math_Vec2iAbsLocal(SST_Vec2i* RESTRICT _a) +{ + int i; + for(i = 0; i < 2; i++) + _a->v[i] = abs(_a->v[i]); +} + +/******************************************************************************/ + +void SST_Math_Vec2iNegate(const SST_Vec2i* RESTRICT _in, SST_Vec2i* RESTRICT _out) +{ + int i; + for(i = 0; i < 2; i++) + _out->v[i] = -(_in->v[i]); +} + +/******************************************************************************/ + +void SST_Math_Vec2iNegateLocal(SST_Vec2i* RESTRICT _a) +{ + int i; + for(i = 0; i < 2; i++) + _a->v[i] = -(_a->v[i]); +} + +/******************************************************************************/ + +void SST_Math_Vec2iRecip(const SST_Vec2i* RESTRICT _in, SST_Vec2i* RESTRICT _out) +{ + int i; + for(i = 0; i < 2; i++) + _out->v[i] = 1/(_in->v[i]); +} + +/******************************************************************************/ + +void SST_Math_Vec2iRecipLocal(SST_Vec2i* RESTRICT _a) +{ + int i; + for(i = 0; i < 2; i++) + _a->v[i] = 1/(_a->v[i]); +} + +/******************************************************************************/ + +int SST_Math_Vec2iDot(const SST_Vec2i* RESTRICT _a, const SST_Vec2i* RESTRICT _b) +{ + int sum = 0; + int i; + for(i = 0; i < 2; i++) + sum += _a->v[i] * _b->v[i]; + return sum; +} + +/******************************************************************************/ + +int SST_Math_Vec2iMagnitudeSquared(const SST_Vec2i* RESTRICT _a) +{ + int sum = 0; + int i; + for(i = 0; i < 2; i++) + sum += _a->v[i] * _a->v[i]; + return sum; +} + +/******************************************************************************/ + +void SST_Math_Vec2iProject(const SST_Vec2i* RESTRICT _a, const SST_Vec2i* RESTRICT _b, SST_Vec2i* RESTRICT _out) +{ + int scalar = SST_Math_Vec2iDot(_a,_b) / SST_Math_Vec2iDot(_b,_b); + SST_Math_Vec2iScale(_b, scalar, _out); +} + + +/******************************************************************************/ + +void SST_Math_Vec2iProjectLocal(SST_Vec2i* RESTRICT _a, const SST_Vec2i* RESTRICT _b) +{ + int scalar = SST_Math_Vec2iDot(_a,_b) / SST_Math_Vec2iDot(_b,_b); + SST_Math_Vec2iScale(_b, scalar, _a); +} + + +/******************************************************************************/ + +void SST_Math_Vec2iBias(const SST_Vec2i* RESTRICT _a, const int _bias, SST_Vec2i* RESTRICT _out) +{ + int i; + for(i = 0; i < 2; i++) + _out->v[i] = _a->v[i] + _bias; +} + + +/******************************************************************************/ + +void SST_Math_Vec2iBiasLocal(SST_Vec2i* RESTRICT _a, const int _bias) +{ + int i; + for(i = 0; i < 2; i++) + _a->v[i] += _bias; +} + + +/******************************************************************************/ + diff --git a/libsst-math/SST_Vec2u.c b/libsst-math/SST_Vec2u.c new file mode 100644 index 0000000..b6ddc86 --- /dev/null +++ b/libsst-math/SST_Vec2u.c @@ -0,0 +1,268 @@ +/* + AUTOMATICALLY GENERATED FILE - DO NOT EDIT! + Please change MatrixNxN.py and re-run it +*/ +/* Generated with ./VectorN.py n = 2, TYPE = unsigned int */ + +#include <float.h> +#include <math.h> +#include <pstdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <SST/SST_Build.h> +#include <SST/SST_Vec2.h> + +void SST_Math_Vec2uAdd(const SST_Vec2u* RESTRICT _A, const SST_Vec2u* RESTRICT _B, SST_Vec2u* RESTRICT _out) +{ + _out->v[0] = _A->v[0] + _B->v[0]; + _out->v[1] = _A->v[1] + _B->v[1]; +} + +/******************************************************************************/ + +void SST_Math_Vec2uAddLocal(SST_Vec2u* RESTRICT _A, const SST_Vec2u* RESTRICT _B) +{ + _A->v[0] += _B->v[0]; + _A->v[1] += _B->v[1]; +} + +/******************************************************************************/ + +void SST_Math_Vec2uSubtract(const SST_Vec2u* RESTRICT _A, const SST_Vec2u* RESTRICT _B, SST_Vec2u* RESTRICT _out) +{ + _out->v[0] = _A->v[0] - _B->v[0]; + _out->v[1] = _A->v[1] - _B->v[1]; +} + +/******************************************************************************/ + +void SST_Math_Vec2uSubtractLocal(SST_Vec2u* RESTRICT _A, const SST_Vec2u* RESTRICT _B) +{ + _A->v[0] -= _B->v[0]; + _A->v[1] -= _B->v[1]; +} + +/******************************************************************************/ + +void SST_Math_Vec2uMultiply(const SST_Vec2u* RESTRICT _A, const SST_Vec2u* RESTRICT _B, SST_Vec2u* RESTRICT _out) +{ + _out->v[0] = _A->v[0] * _B->v[0]; + _out->v[1] = _A->v[1] * _B->v[1]; +} + +/******************************************************************************/ + +void SST_Math_Vec2uMultiplyLocal(SST_Vec2u* RESTRICT _A, const SST_Vec2u* RESTRICT _B) +{ + _A->v[0] *= _B->v[0]; + _A->v[1] *= _B->v[1]; +} + +/******************************************************************************/ + +void SST_Math_Vec2uScale(const SST_Vec2u* RESTRICT _A, const unsigned int k, SST_Vec2u* RESTRICT _out) +{ + _out->v[0] = _A->v[0] * k; + _out->v[1] = _A->v[1] * k; +} + +/******************************************************************************/ + +void SST_Math_Vec2uScaleLocal(SST_Vec2u* RESTRICT _A, const unsigned int k) +{ + _A->v[0] *= k; + _A->v[1] *= k; +} + +/******************************************************************************/ + +void SST_Math_Vec2uDivide(const SST_Vec2u* RESTRICT _A, const SST_Vec2u* RESTRICT _B, SST_Vec2u* RESTRICT _out) +{ + _out->v[0] = _A->v[0] / _B->v[0]; + _out->v[1] = _A->v[1] / _B->v[1]; +} + +/******************************************************************************/ + +void SST_Math_Vec2uDivideLocal(SST_Vec2u* RESTRICT _A, const SST_Vec2u* RESTRICT _B) +{ + _A->v[0] /= _B->v[0]; + _A->v[1] /= _B->v[1]; +} + +/******************************************************************************/ + + +/******************************************************************************/ + + +void SST_Math_Vec2uAddMult(const SST_Vec2u* RESTRICT _X, const unsigned int _x, const SST_Vec2u* RESTRICT _Y, SST_Vec2u* RESTRICT _Z) +{ + SST_ASSUME_ALIGNED(_X,16); + SST_ASSUME_ALIGNED(_Y,16); + SST_ASSUME_ALIGNED(_Z,16); + /* _Z = _x * _X + _Y */ + _Z->v[0] = _x * _X->v[0] + _Y->v[0]; + _Z->v[1] = _x * _X->v[1] + _Y->v[1]; + +} + + +void SST_Math_Vec2uAddMultLocal(SST_Vec2u* RESTRICT _X, const unsigned int _x, const SST_Vec2u* RESTRICT _Y) +{ + SST_ASSUME_ALIGNED(_X,16); + SST_ASSUME_ALIGNED(_Y,16); + /* _X = _x * _X + _Y */ + _X->v[0] = _x * _X->v[0] + _Y->v[0]; + _X->v[1] = _x * _X->v[1] + _Y->v[1]; + +} + + +/******************************************************************************/ + + +void SST_Math_Vec2uLerp(const SST_Vec2u* RESTRICT _X, const SST_Vec2u* RESTRICT _Y, const unsigned int _y, SST_Vec2u* RESTRICT _Z) +{ + SST_ASSUME_ALIGNED(_X,16); + SST_ASSUME_ALIGNED(_Y,16); + SST_ASSUME_ALIGNED(_Z,16); + /* Z = x*X + y*Y */ + _Z->v[0] = _X->v[0] + (_Y->v[0] - _X->v[0]) * _y ; + _Z->v[1] = _X->v[1] + (_Y->v[1] - _X->v[1]) * _y ; + +} + +void SST_Math_Vec2uLerpLocal(SST_Vec2u* RESTRICT _X, const SST_Vec2u* RESTRICT _Y, const unsigned int _y) +{ + SST_ASSUME_ALIGNED(_X,16); + SST_ASSUME_ALIGNED(_Y,16); + /* Z = x*X + y*Y */ + _X->v[0] = _X->v[0] + (_Y->v[0] - _X->v[0]) * _y ; + _X->v[1] = _X->v[1] + (_Y->v[1] - _X->v[1]) * _y ; + +} + +/******************************************************************************/ + + +void SST_Math_Vec2uWeightedSum(const SST_Vec2u* RESTRICT _X, const unsigned int _x, const SST_Vec2u* RESTRICT _Y, const unsigned int _y, SST_Vec2u* RESTRICT _Z) +{ + SST_ASSUME_ALIGNED(_X,16); + SST_ASSUME_ALIGNED(_Y,16); + SST_ASSUME_ALIGNED(_Z,16); + /* Z = x*X + y*Y */ + _Z->v[0] = _x * _X->v[0] + _y * _Y->v[0]; + _Z->v[1] = _x * _X->v[1] + _y * _Y->v[1]; + +} + +void SST_Math_Vec2uWeightedSumLocal(SST_Vec2u* RESTRICT _X, const unsigned int _x, const SST_Vec2u* RESTRICT _Y, const unsigned int _y) +{ + SST_ASSUME_ALIGNED(_X,16); + SST_ASSUME_ALIGNED(_Y,16); + /* Z = x*X + y*Y */ + _X->v[0] = _x * _X->v[0] + _y * _Y->v[0]; + _X->v[1] = _x * _X->v[1] + _y * _Y->v[1]; + +} + +/******************************************************************************/ + +bool SST_Math_Vec2uEquals(const SST_Vec2u* RESTRICT _a, const SST_Vec2u* RESTRICT _b) +{ + int i; + bool returncode; + SST_ASSUME_ALIGNED(_a,16); + SST_ASSUME_ALIGNED(_b,16); + returncode = 1; + for(i=0;i<2;i++) + { + returncode = (_a->v[i]==_b->v[i]) && returncode; + } + return returncode; +} + + +/******************************************************************************/ + +unsigned int SST_Math_Vec2uMax(const SST_Vec2u* RESTRICT _a) +{ + unsigned int tmp = _a->v[0]; + if(tmp < _a->v[1]) tmp = _a->v[1]; + + return tmp; +} + +/******************************************************************************/ + +unsigned int SST_Math_Vec2uMin(const SST_Vec2u* RESTRICT _a) +{ + unsigned int tmp = _a->v[0]; + if(tmp > _a->v[1]) tmp = _a->v[1]; + + return tmp; +} + +/******************************************************************************/ + +unsigned int SST_Math_Vec2uDot(const SST_Vec2u* RESTRICT _a, const SST_Vec2u* RESTRICT _b) +{ + unsigned int sum = 0; + int i; + for(i = 0; i < 2; i++) + sum += _a->v[i] * _b->v[i]; + return sum; +} + +/******************************************************************************/ + +unsigned int SST_Math_Vec2uMagnitudeSquared(const SST_Vec2u* RESTRICT _a) +{ + unsigned int sum = 0; + int i; + for(i = 0; i < 2; i++) + sum += _a->v[i] * _a->v[i]; + return sum; +} + +/******************************************************************************/ + +void SST_Math_Vec2uProject(const SST_Vec2u* RESTRICT _a, const SST_Vec2u* RESTRICT _b, SST_Vec2u* RESTRICT _out) +{ + unsigned int scalar = SST_Math_Vec2uDot(_a,_b) / SST_Math_Vec2uDot(_b,_b); + SST_Math_Vec2uScale(_b, scalar, _out); +} + + +/******************************************************************************/ + +void SST_Math_Vec2uProjectLocal(SST_Vec2u* RESTRICT _a, const SST_Vec2u* RESTRICT _b) +{ + unsigned int scalar = SST_Math_Vec2uDot(_a,_b) / SST_Math_Vec2uDot(_b,_b); + SST_Math_Vec2uScale(_b, scalar, _a); +} + + +/******************************************************************************/ + +void SST_Math_Vec2uBias(const SST_Vec2u* RESTRICT _a, const unsigned int _bias, SST_Vec2u* RESTRICT _out) +{ + int i; + for(i = 0; i < 2; i++) + _out->v[i] = _a->v[i] + _bias; +} + + +/******************************************************************************/ + +void SST_Math_Vec2uBiasLocal(SST_Vec2u* RESTRICT _a, const unsigned int _bias) +{ + int i; + for(i = 0; i < 2; i++) + _a->v[i] += _bias; +} + + +/******************************************************************************/ + diff --git a/libsst-math/SST_Vec3d.c b/libsst-math/SST_Vec3d.c new file mode 100644 index 0000000..e7194c4 --- /dev/null +++ b/libsst-math/SST_Vec3d.c @@ -0,0 +1,553 @@ +/* + AUTOMATICALLY GENERATED FILE - DO NOT EDIT! + Please change MatrixNxN.py and re-run it +*/ +/* Generated with ./VectorN.py n = 3, TYPE = double */ + +#include <float.h> +#include <math.h> +#include <pstdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <SST/SST_Build.h> +#include <SST/SST_Vec3.h> + +void SST_Math_Vec3dAdd(const SST_Vec3d* RESTRICT _A, const SST_Vec3d* RESTRICT _B, SST_Vec3d* RESTRICT _out) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + SST_ASSUME_ALIGNED(_out,16); + + _out->v[0] = _A->v[0] + _B->v[0]; + _out->v[1] = _A->v[1] + _B->v[1]; + _out->v[2] = _A->v[2] + _B->v[2]; +} + +/******************************************************************************/ + +void SST_Math_Vec3dAddLocal(SST_Vec3d* RESTRICT _A, const SST_Vec3d* RESTRICT _B) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + + _A->v[0] += _B->v[0]; + _A->v[1] += _B->v[1]; + _A->v[2] += _B->v[2]; +} + +/******************************************************************************/ + +void SST_Math_Vec3dSubtract(const SST_Vec3d* RESTRICT _A, const SST_Vec3d* RESTRICT _B, SST_Vec3d* RESTRICT _out) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + SST_ASSUME_ALIGNED(_out,16); + + _out->v[0] = _A->v[0] - _B->v[0]; + _out->v[1] = _A->v[1] - _B->v[1]; + _out->v[2] = _A->v[2] - _B->v[2]; +} + +/******************************************************************************/ + +void SST_Math_Vec3dSubtractLocal(SST_Vec3d* RESTRICT _A, const SST_Vec3d* RESTRICT _B) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + + _A->v[0] -= _B->v[0]; + _A->v[1] -= _B->v[1]; + _A->v[2] -= _B->v[2]; +} + +/******************************************************************************/ + +void SST_Math_Vec3dMultiply(const SST_Vec3d* RESTRICT _A, const SST_Vec3d* RESTRICT _B, SST_Vec3d* RESTRICT _out) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + SST_ASSUME_ALIGNED(_out,16); + + _out->v[0] = _A->v[0] * _B->v[0]; + _out->v[1] = _A->v[1] * _B->v[1]; + _out->v[2] = _A->v[2] * _B->v[2]; +} + +/******************************************************************************/ + +void SST_Math_Vec3dMultiplyLocal(SST_Vec3d* RESTRICT _A, const SST_Vec3d* RESTRICT _B) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + + _A->v[0] *= _B->v[0]; + _A->v[1] *= _B->v[1]; + _A->v[2] *= _B->v[2]; +} + +/******************************************************************************/ + +void SST_Math_Vec3dScale(const SST_Vec3d* RESTRICT _A, const double k, SST_Vec3d* RESTRICT _out) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_out,16); + + _out->v[0] = _A->v[0] * k; + _out->v[1] = _A->v[1] * k; + _out->v[2] = _A->v[2] * k; +} + +/******************************************************************************/ + +void SST_Math_Vec3dScaleLocal(SST_Vec3d* RESTRICT _A, const double k) +{ + SST_ASSUME_ALIGNED(_A,16); + + _A->v[0] *= k; + _A->v[1] *= k; + _A->v[2] *= k; +} + +/******************************************************************************/ + +void SST_Math_Vec3dDivide(const SST_Vec3d* RESTRICT _A, const SST_Vec3d* RESTRICT _B, SST_Vec3d* RESTRICT _out) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + SST_ASSUME_ALIGNED(_out,16); + + _out->v[0] = _A->v[0] / _B->v[0]; + _out->v[1] = _A->v[1] / _B->v[1]; + _out->v[2] = _A->v[2] / _B->v[2]; +} + +/******************************************************************************/ + +void SST_Math_Vec3dDivideLocal(SST_Vec3d* RESTRICT _A, const SST_Vec3d* RESTRICT _B) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + + _A->v[0] /= _B->v[0]; + _A->v[1] /= _B->v[1]; + _A->v[2] /= _B->v[2]; +} + +/******************************************************************************/ + + +/******************************************************************************/ + + +void SST_Math_Vec3dAddMult(const SST_Vec3d* RESTRICT _X, const double _x, const SST_Vec3d* RESTRICT _Y, SST_Vec3d* RESTRICT _Z) +{ + SST_ASSUME_ALIGNED(_X,16); + SST_ASSUME_ALIGNED(_Y,16); + SST_ASSUME_ALIGNED(_Z,16); + /* _Z = _x * _X + _Y */ + _Z->v[0] = _x * _X->v[0] + _Y->v[0]; + _Z->v[1] = _x * _X->v[1] + _Y->v[1]; + _Z->v[2] = _x * _X->v[2] + _Y->v[2]; + +} + + +void SST_Math_Vec3dAddMultLocal(SST_Vec3d* RESTRICT _X, const double _x, const SST_Vec3d* RESTRICT _Y) +{ + SST_ASSUME_ALIGNED(_X,16); + SST_ASSUME_ALIGNED(_Y,16); + /* _X = _x * _X + _Y */ + _X->v[0] = _x * _X->v[0] + _Y->v[0]; + _X->v[1] = _x * _X->v[1] + _Y->v[1]; + _X->v[2] = _x * _X->v[2] + _Y->v[2]; + +} + + +/******************************************************************************/ + + +void SST_Math_Vec3dLerp(const SST_Vec3d* RESTRICT _X, const SST_Vec3d* RESTRICT _Y, const double _y, SST_Vec3d* RESTRICT _Z) +{ + SST_ASSUME_ALIGNED(_X,16); + SST_ASSUME_ALIGNED(_Y,16); + SST_ASSUME_ALIGNED(_Z,16); + /* Z = x*X + y*Y */ + _Z->v[0] = _X->v[0] + (_Y->v[0] - _X->v[0]) * _y ; + _Z->v[1] = _X->v[1] + (_Y->v[1] - _X->v[1]) * _y ; + _Z->v[2] = _X->v[2] + (_Y->v[2] - _X->v[2]) * _y ; + +} + +void SST_Math_Vec3dLerpLocal(SST_Vec3d* RESTRICT _X, const SST_Vec3d* RESTRICT _Y, const double _y) +{ + SST_ASSUME_ALIGNED(_X,16); + SST_ASSUME_ALIGNED(_Y,16); + /* Z = x*X + y*Y */ + _X->v[0] = _X->v[0] + (_Y->v[0] - _X->v[0]) * _y ; + _X->v[1] = _X->v[1] + (_Y->v[1] - _X->v[1]) * _y ; + _X->v[2] = _X->v[2] + (_Y->v[2] - _X->v[2]) * _y ; + +} + +/******************************************************************************/ + + +void SST_Math_Vec3dWeightedSum(const SST_Vec3d* RESTRICT _X, const double _x, const SST_Vec3d* RESTRICT _Y, const double _y, SST_Vec3d* RESTRICT _Z) +{ + SST_ASSUME_ALIGNED(_X,16); + SST_ASSUME_ALIGNED(_Y,16); + SST_ASSUME_ALIGNED(_Z,16); + /* Z = x*X + y*Y */ + _Z->v[0] = _x * _X->v[0] + _y * _Y->v[0]; + _Z->v[1] = _x * _X->v[1] + _y * _Y->v[1]; + _Z->v[2] = _x * _X->v[2] + _y * _Y->v[2]; + +} + +void SST_Math_Vec3dWeightedSumLocal(SST_Vec3d* RESTRICT _X, const double _x, const SST_Vec3d* RESTRICT _Y, const double _y) +{ + SST_ASSUME_ALIGNED(_X,16); + SST_ASSUME_ALIGNED(_Y,16); + /* Z = x*X + y*Y */ + _X->v[0] = _x * _X->v[0] + _y * _Y->v[0]; + _X->v[1] = _x * _X->v[1] + _y * _Y->v[1]; + _X->v[2] = _x * _X->v[2] + _y * _Y->v[2]; + +} + +/******************************************************************************/ + +bool SST_Math_Vec3dEquals(const SST_Vec3d* RESTRICT _a, const SST_Vec3d* RESTRICT _b, const double _tolerance) +{ + SST_Vec3d tmp; + int i; + bool returncode; + SST_ASSUME_ALIGNED(_a,16); + SST_ASSUME_ALIGNED(_b,16); + returncode = 1; + + SST_Math_Vec3dSubtract(_a,_b,&tmp); + for(i=0;i<3;i++) + { + returncode = (fabs(tmp.v[i]) <= _tolerance) && returncode; + } + + return returncode; +} + + +/******************************************************************************/ + +double SST_Math_Vec3dMax(const SST_Vec3d* RESTRICT _a) +{ + double tmp = _a->v[0]; + if(tmp < _a->v[1]) tmp = _a->v[1]; + if(tmp < _a->v[2]) tmp = _a->v[2]; + + return tmp; +} + +/******************************************************************************/ + +double SST_Math_Vec3dMin(const SST_Vec3d* RESTRICT _a) +{ + double tmp = _a->v[0]; + if(tmp > _a->v[1]) tmp = _a->v[1]; + if(tmp > _a->v[2]) tmp = _a->v[2]; + + return tmp; +} + +/******************************************************************************/ + +void SST_Math_Vec3dCross(const SST_Vec3d* RESTRICT _a, const SST_Vec3d* RESTRICT _b, SST_Vec3d* RESTRICT _out) + { + + _out->v[0] = _a->v[1]*_b->v[2] - _a->v[2]*_b->v[1]; + _out->v[1] =-(_a->v[0]*_b->v[2] - _a->v[2]*_b->v[0]); + _out->v[2] = _a->v[0]*_b->v[1] - _a->v[1]*_b->v[0]; +} + +/******************************************************************************/ + +void SST_Math_Vec3dCrossLocal(SST_Vec3d* RESTRICT _a, const SST_Vec3d* RESTRICT _b) +{ + SST_Vec3d out; + + out.v[0] = _a->v[1]*_b->v[2] - _a->v[2]*_b->v[1]; + out.v[1] =-(_a->v[0]*_b->v[2] - _a->v[2]*_b->v[0]); + out.v[2] = _a->v[0]*_b->v[1] - _a->v[1]*_b->v[0]; + _a->v[0] = out.v[0]; + _a->v[1] = out.v[1]; + _a->v[2] = out.v[2]; +} + +/******************************************************************************/ + +void SST_Math_Vec3dRotateAbout(const SST_Vec3d* RESTRICT _a, const SST_Vec3d* RESTRICT _about,double _theta, SST_Vec3d* RESTRICT _out) +{ + + + SST_Vec3d tmp; + double scalar = ( 1.0000000000000000-cos(_theta)) * SST_Math_Vec3dDot(_about,_a); + SST_Math_Vec3dScale(_about,scalar,_out); + SST_Math_Vec3dCross(_about,_a,&tmp); + SST_Math_Vec3dScaleLocal(&tmp,sin(_theta)); + SST_Math_Vec3dAddLocal(_out,&tmp); + SST_Math_Vec3dScale(_a,cos(_theta),&tmp); + SST_Math_Vec3dAddLocal(_out,&tmp); + +} + +/******************************************************************************/ + +void SST_Math_Vec3dRotateAboutLocal(SST_Vec3d* RESTRICT _a, const SST_Vec3d* RESTRICT _about,double _theta) +{ + + + int i; + SST_Vec3d tmp; + SST_Vec3d tmp2; + double scalar = ( 1.0000000000000000-cos(_theta)) * SST_Math_Vec3dDot(_about,_a); + + SST_Math_Vec3dScale(_about,scalar,&tmp2); + SST_Math_Vec3dCross(_about,_a,&tmp); + SST_Math_Vec3dScaleLocal(&tmp,sin(_theta)); + SST_Math_Vec3dAddLocal(&tmp2,&tmp); + SST_Math_Vec3dScale(_a,cos(_theta),&tmp); + SST_Math_Vec3dAddLocal(&tmp2,&tmp); + + for(i = 0; i < 3; i++) + _a->v[i] = tmp2.v[i]; + + +} + +/******************************************************************************/ + +void SST_Math_Vec3dRotate(const SST_Vec3d* RESTRICT _a,double _theta, SST_Vec3d* RESTRICT _out) +{ + + + SST_Vec3d tmp; + SST_Vec3d about; + double scalar; + about.x = 0.0; + about.y = 0.0; + about.z = 0.0; + scalar = ( 1.0000000000000000-cos(_theta)) * SST_Math_Vec3dDot(&about,_a); + SST_Math_Vec3dScale(&about,scalar,_out); + SST_Math_Vec3dCross(&about,_a,&tmp); + SST_Math_Vec3dScaleLocal(&tmp,sin(_theta)); + SST_Math_Vec3dAddLocal(_out,&tmp); + SST_Math_Vec3dScale(_a,cos(_theta),&tmp); + SST_Math_Vec3dAddLocal(_out,&tmp); + +} + +/******************************************************************************/ + +void SST_Math_Vec3dRotateLocal(SST_Vec3d* RESTRICT _a, double _theta) +{ + + + int i; + SST_Vec3d tmp; + SST_Vec3d tmp2; + SST_Vec3d about; + double scalar; + about.x = 0.0; + about.y = 0.0; + about.z = 0.0; + scalar = ( 1.0000000000000000-cos(_theta)) * SST_Math_Vec3dDot(&about,_a); + + SST_Math_Vec3dScale(&about,scalar,&tmp2); + SST_Math_Vec3dCross(&about,_a,&tmp); + SST_Math_Vec3dScaleLocal(&tmp,sin(_theta)); + SST_Math_Vec3dAddLocal(&tmp2,&tmp); + SST_Math_Vec3dScale(_a,cos(_theta),&tmp); + SST_Math_Vec3dAddLocal(&tmp2,&tmp); + + for(i = 0; i < 3; i++) + _a->v[i] = tmp2.v[i]; + + +} +void SST_Math_Vec3dNormalize(const SST_Vec3d* RESTRICT _in, SST_Vec3d* RESTRICT _out) +{ + double scalar = 1.f/SST_Math_Vec3dMagnitude(_in); + SST_Math_Vec3dScale(_in,scalar,_out); +} + +/******************************************************************************/ + +void SST_Math_Vec3dNormalizeLocal(SST_Vec3d* _inout) +{ + double scalar = 1.f/SST_Math_Vec3dMagnitude(_inout); + SST_Math_Vec3dScaleLocal(_inout,scalar); +} + +/******************************************************************************/ + +void SST_Math_Vec3dRecipSqrt(const SST_Vec3d* RESTRICT _in, SST_Vec3d* RESTRICT _out) +{ + int i; + for(i = 0; i < 3; i++) + _out->v[i] = 1/sqrt(_in->v[i]); +} + +/******************************************************************************/ + +void SST_Math_Vec3dRecipSqrtLocal(SST_Vec3d* RESTRICT _a) +{ + int i; + for(i = 0; i < 3; i++) + _a->v[i] = 1/sqrt(_a->v[i]); +} + +/******************************************************************************/ + +void SST_Math_Vec3dSqrt(const SST_Vec3d* RESTRICT _in, SST_Vec3d* RESTRICT _out) +{ + int i; + for(i = 0; i < 3; i++) + _out->v[i] = sqrt(_in->v[i]); +} + +/******************************************************************************/ + +void SST_Math_Vec3dSqrtLocal(SST_Vec3d* RESTRICT _a) +{ + int i; + for(i = 0; i < 3; i++) + _a->v[i] = sqrt(_a->v[i]); +} + +/******************************************************************************/ + +double SST_Math_Vec3dMagnitude(const SST_Vec3d* RESTRICT _a) +{ + double sum = 0; + int i; + for(i = 0; i < 3; i++) + sum += _a->v[i] * _a->v[i]; + return sqrt(sum); +} + +/******************************************************************************/ + +void SST_Math_Vec3dAbs(const SST_Vec3d* RESTRICT _in, SST_Vec3d* RESTRICT _out) +{ + int i; + for(i = 0; i < 3; i++) + _out->v[i] = fabs(_in->v[i]); +} + +/******************************************************************************/ + +void SST_Math_Vec3dAbsLocal(SST_Vec3d* RESTRICT _a) +{ + int i; + for(i = 0; i < 3; i++) + _a->v[i] = fabs(_a->v[i]); +} + +/******************************************************************************/ + +void SST_Math_Vec3dNegate(const SST_Vec3d* RESTRICT _in, SST_Vec3d* RESTRICT _out) +{ + int i; + for(i = 0; i < 3; i++) + _out->v[i] = -(_in->v[i]); +} + +/******************************************************************************/ + +void SST_Math_Vec3dNegateLocal(SST_Vec3d* RESTRICT _a) +{ + int i; + for(i = 0; i < 3; i++) + _a->v[i] = -(_a->v[i]); +} + +/******************************************************************************/ + +void SST_Math_Vec3dRecip(const SST_Vec3d* RESTRICT _in, SST_Vec3d* RESTRICT _out) +{ + int i; + for(i = 0; i < 3; i++) + _out->v[i] = 1/(_in->v[i]); +} + +/******************************************************************************/ + +void SST_Math_Vec3dRecipLocal(SST_Vec3d* RESTRICT _a) +{ + int i; + for(i = 0; i < 3; i++) + _a->v[i] = 1/(_a->v[i]); +} + +/******************************************************************************/ + +double SST_Math_Vec3dDot(const SST_Vec3d* RESTRICT _a, const SST_Vec3d* RESTRICT _b) +{ + double sum = 0; + int i; + for(i = 0; i < 3; i++) + sum += _a->v[i] * _b->v[i]; + return sum; +} + +/******************************************************************************/ + +double SST_Math_Vec3dMagnitudeSquared(const SST_Vec3d* RESTRICT _a) +{ + double sum = 0; + int i; + for(i = 0; i < 3; i++) + sum += _a->v[i] * _a->v[i]; + return sum; +} + +/******************************************************************************/ + +void SST_Math_Vec3dProject(const SST_Vec3d* RESTRICT _a, const SST_Vec3d* RESTRICT _b, SST_Vec3d* RESTRICT _out) +{ + double scalar = SST_Math_Vec3dDot(_a,_b) / SST_Math_Vec3dDot(_b,_b); + SST_Math_Vec3dScale(_b, scalar, _out); +} + + +/******************************************************************************/ + +void SST_Math_Vec3dProjectLocal(SST_Vec3d* RESTRICT _a, const SST_Vec3d* RESTRICT _b) +{ + double scalar = SST_Math_Vec3dDot(_a,_b) / SST_Math_Vec3dDot(_b,_b); + SST_Math_Vec3dScale(_b, scalar, _a); +} + + +/******************************************************************************/ + +void SST_Math_Vec3dBias(const SST_Vec3d* RESTRICT _a, const double _bias, SST_Vec3d* RESTRICT _out) +{ + int i; + for(i = 0; i < 3; i++) + _out->v[i] = _a->v[i] + _bias; +} + + +/******************************************************************************/ + +void SST_Math_Vec3dBiasLocal(SST_Vec3d* RESTRICT _a, const double _bias) +{ + int i; + for(i = 0; i < 3; i++) + _a->v[i] += _bias; +} + + +/******************************************************************************/ + diff --git a/libsst-math/SST_Vec3f.c b/libsst-math/SST_Vec3f.c new file mode 100644 index 0000000..b3cc1d2 --- /dev/null +++ b/libsst-math/SST_Vec3f.c @@ -0,0 +1,553 @@ +/* + AUTOMATICALLY GENERATED FILE - DO NOT EDIT! + Please change MatrixNxN.py and re-run it +*/ +/* Generated with ./VectorN.py n = 3, TYPE = float */ + +#include <float.h> +#include <math.h> +#include <pstdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <SST/SST_Build.h> +#include <SST/SST_Vec3.h> + +void SST_Math_Vec3fAdd(const SST_Vec3f* RESTRICT _A, const SST_Vec3f* RESTRICT _B, SST_Vec3f* RESTRICT _out) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + SST_ASSUME_ALIGNED(_out,16); + + _out->v[0] = _A->v[0] + _B->v[0]; + _out->v[1] = _A->v[1] + _B->v[1]; + _out->v[2] = _A->v[2] + _B->v[2]; +} + +/******************************************************************************/ + +void SST_Math_Vec3fAddLocal(SST_Vec3f* RESTRICT _A, const SST_Vec3f* RESTRICT _B) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + + _A->v[0] += _B->v[0]; + _A->v[1] += _B->v[1]; + _A->v[2] += _B->v[2]; +} + +/******************************************************************************/ + +void SST_Math_Vec3fSubtract(const SST_Vec3f* RESTRICT _A, const SST_Vec3f* RESTRICT _B, SST_Vec3f* RESTRICT _out) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + SST_ASSUME_ALIGNED(_out,16); + + _out->v[0] = _A->v[0] - _B->v[0]; + _out->v[1] = _A->v[1] - _B->v[1]; + _out->v[2] = _A->v[2] - _B->v[2]; +} + +/******************************************************************************/ + +void SST_Math_Vec3fSubtractLocal(SST_Vec3f* RESTRICT _A, const SST_Vec3f* RESTRICT _B) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + + _A->v[0] -= _B->v[0]; + _A->v[1] -= _B->v[1]; + _A->v[2] -= _B->v[2]; +} + +/******************************************************************************/ + +void SST_Math_Vec3fMultiply(const SST_Vec3f* RESTRICT _A, const SST_Vec3f* RESTRICT _B, SST_Vec3f* RESTRICT _out) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + SST_ASSUME_ALIGNED(_out,16); + + _out->v[0] = _A->v[0] * _B->v[0]; + _out->v[1] = _A->v[1] * _B->v[1]; + _out->v[2] = _A->v[2] * _B->v[2]; +} + +/******************************************************************************/ + +void SST_Math_Vec3fMultiplyLocal(SST_Vec3f* RESTRICT _A, const SST_Vec3f* RESTRICT _B) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + + _A->v[0] *= _B->v[0]; + _A->v[1] *= _B->v[1]; + _A->v[2] *= _B->v[2]; +} + +/******************************************************************************/ + +void SST_Math_Vec3fScale(const SST_Vec3f* RESTRICT _A, const float k, SST_Vec3f* RESTRICT _out) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_out,16); + + _out->v[0] = _A->v[0] * k; + _out->v[1] = _A->v[1] * k; + _out->v[2] = _A->v[2] * k; +} + +/******************************************************************************/ + +void SST_Math_Vec3fScaleLocal(SST_Vec3f* RESTRICT _A, const float k) +{ + SST_ASSUME_ALIGNED(_A,16); + + _A->v[0] *= k; + _A->v[1] *= k; + _A->v[2] *= k; +} + +/******************************************************************************/ + +void SST_Math_Vec3fDivide(const SST_Vec3f* RESTRICT _A, const SST_Vec3f* RESTRICT _B, SST_Vec3f* RESTRICT _out) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + SST_ASSUME_ALIGNED(_out,16); + + _out->v[0] = _A->v[0] / _B->v[0]; + _out->v[1] = _A->v[1] / _B->v[1]; + _out->v[2] = _A->v[2] / _B->v[2]; +} + +/******************************************************************************/ + +void SST_Math_Vec3fDivideLocal(SST_Vec3f* RESTRICT _A, const SST_Vec3f* RESTRICT _B) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + + _A->v[0] /= _B->v[0]; + _A->v[1] /= _B->v[1]; + _A->v[2] /= _B->v[2]; +} + +/******************************************************************************/ + + +/******************************************************************************/ + + +void SST_Math_Vec3fAddMult(const SST_Vec3f* RESTRICT _X, const float _x, const SST_Vec3f* RESTRICT _Y, SST_Vec3f* RESTRICT _Z) +{ + SST_ASSUME_ALIGNED(_X,16); + SST_ASSUME_ALIGNED(_Y,16); + SST_ASSUME_ALIGNED(_Z,16); + /* _Z = _x * _X + _Y */ + _Z->v[0] = _x * _X->v[0] + _Y->v[0]; + _Z->v[1] = _x * _X->v[1] + _Y->v[1]; + _Z->v[2] = _x * _X->v[2] + _Y->v[2]; + +} + + +void SST_Math_Vec3fAddMultLocal(SST_Vec3f* RESTRICT _X, const float _x, const SST_Vec3f* RESTRICT _Y) +{ + SST_ASSUME_ALIGNED(_X,16); + SST_ASSUME_ALIGNED(_Y,16); + /* _X = _x * _X + _Y */ + _X->v[0] = _x * _X->v[0] + _Y->v[0]; + _X->v[1] = _x * _X->v[1] + _Y->v[1]; + _X->v[2] = _x * _X->v[2] + _Y->v[2]; + +} + + +/******************************************************************************/ + + +void SST_Math_Vec3fLerp(const SST_Vec3f* RESTRICT _X, const SST_Vec3f* RESTRICT _Y, const float _y, SST_Vec3f* RESTRICT _Z) +{ + SST_ASSUME_ALIGNED(_X,16); + SST_ASSUME_ALIGNED(_Y,16); + SST_ASSUME_ALIGNED(_Z,16); + /* Z = x*X + y*Y */ + _Z->v[0] = _X->v[0] + (_Y->v[0] - _X->v[0]) * _y ; + _Z->v[1] = _X->v[1] + (_Y->v[1] - _X->v[1]) * _y ; + _Z->v[2] = _X->v[2] + (_Y->v[2] - _X->v[2]) * _y ; + +} + +void SST_Math_Vec3fLerpLocal(SST_Vec3f* RESTRICT _X, const SST_Vec3f* RESTRICT _Y, const float _y) +{ + SST_ASSUME_ALIGNED(_X,16); + SST_ASSUME_ALIGNED(_Y,16); + /* Z = x*X + y*Y */ + _X->v[0] = _X->v[0] + (_Y->v[0] - _X->v[0]) * _y ; + _X->v[1] = _X->v[1] + (_Y->v[1] - _X->v[1]) * _y ; + _X->v[2] = _X->v[2] + (_Y->v[2] - _X->v[2]) * _y ; + +} + +/******************************************************************************/ + + +void SST_Math_Vec3fWeightedSum(const SST_Vec3f* RESTRICT _X, const float _x, const SST_Vec3f* RESTRICT _Y, const float _y, SST_Vec3f* RESTRICT _Z) +{ + SST_ASSUME_ALIGNED(_X,16); + SST_ASSUME_ALIGNED(_Y,16); + SST_ASSUME_ALIGNED(_Z,16); + /* Z = x*X + y*Y */ + _Z->v[0] = _x * _X->v[0] + _y * _Y->v[0]; + _Z->v[1] = _x * _X->v[1] + _y * _Y->v[1]; + _Z->v[2] = _x * _X->v[2] + _y * _Y->v[2]; + +} + +void SST_Math_Vec3fWeightedSumLocal(SST_Vec3f* RESTRICT _X, const float _x, const SST_Vec3f* RESTRICT _Y, const float _y) +{ + SST_ASSUME_ALIGNED(_X,16); + SST_ASSUME_ALIGNED(_Y,16); + /* Z = x*X + y*Y */ + _X->v[0] = _x * _X->v[0] + _y * _Y->v[0]; + _X->v[1] = _x * _X->v[1] + _y * _Y->v[1]; + _X->v[2] = _x * _X->v[2] + _y * _Y->v[2]; + +} + +/******************************************************************************/ + +bool SST_Math_Vec3fEquals(const SST_Vec3f* RESTRICT _a, const SST_Vec3f* RESTRICT _b, const float _tolerance) +{ + SST_Vec3f tmp; + int i; + bool returncode; + SST_ASSUME_ALIGNED(_a,16); + SST_ASSUME_ALIGNED(_b,16); + returncode = 1; + + SST_Math_Vec3fSubtract(_a,_b,&tmp); + for(i=0;i<3;i++) + { + returncode = (fabsf(tmp.v[i]) <= _tolerance) && returncode; + } + + return returncode; +} + + +/******************************************************************************/ + +float SST_Math_Vec3fMax(const SST_Vec3f* RESTRICT _a) +{ + float tmp = _a->v[0]; + if(tmp < _a->v[1]) tmp = _a->v[1]; + if(tmp < _a->v[2]) tmp = _a->v[2]; + + return tmp; +} + +/******************************************************************************/ + +float SST_Math_Vec3fMin(const SST_Vec3f* RESTRICT _a) +{ + float tmp = _a->v[0]; + if(tmp > _a->v[1]) tmp = _a->v[1]; + if(tmp > _a->v[2]) tmp = _a->v[2]; + + return tmp; +} + +/******************************************************************************/ + +void SST_Math_Vec3fCross(const SST_Vec3f* RESTRICT _a, const SST_Vec3f* RESTRICT _b, SST_Vec3f* RESTRICT _out) + { + + _out->v[0] = _a->v[1]*_b->v[2] - _a->v[2]*_b->v[1]; + _out->v[1] =-(_a->v[0]*_b->v[2] - _a->v[2]*_b->v[0]); + _out->v[2] = _a->v[0]*_b->v[1] - _a->v[1]*_b->v[0]; +} + +/******************************************************************************/ + +void SST_Math_Vec3fCrossLocal(SST_Vec3f* RESTRICT _a, const SST_Vec3f* RESTRICT _b) +{ + SST_Vec3f out; + + out.v[0] = _a->v[1]*_b->v[2] - _a->v[2]*_b->v[1]; + out.v[1] =-(_a->v[0]*_b->v[2] - _a->v[2]*_b->v[0]); + out.v[2] = _a->v[0]*_b->v[1] - _a->v[1]*_b->v[0]; + _a->v[0] = out.v[0]; + _a->v[1] = out.v[1]; + _a->v[2] = out.v[2]; +} + +/******************************************************************************/ + +void SST_Math_Vec3fRotateAbout(const SST_Vec3f* RESTRICT _a, const SST_Vec3f* RESTRICT _about,float _theta, SST_Vec3f* RESTRICT _out) +{ + + + SST_Vec3f tmp; + float scalar = (1.000000f-cosf(_theta)) * SST_Math_Vec3fDot(_about,_a); + SST_Math_Vec3fScale(_about,scalar,_out); + SST_Math_Vec3fCross(_about,_a,&tmp); + SST_Math_Vec3fScaleLocal(&tmp,sinf(_theta)); + SST_Math_Vec3fAddLocal(_out,&tmp); + SST_Math_Vec3fScale(_a,cosf(_theta),&tmp); + SST_Math_Vec3fAddLocal(_out,&tmp); + +} + +/******************************************************************************/ + +void SST_Math_Vec3fRotateAboutLocal(SST_Vec3f* RESTRICT _a, const SST_Vec3f* RESTRICT _about,float _theta) +{ + + + int i; + SST_Vec3f tmp; + SST_Vec3f tmp2; + float scalar = (1.000000f-cosf(_theta)) * SST_Math_Vec3fDot(_about,_a); + + SST_Math_Vec3fScale(_about,scalar,&tmp2); + SST_Math_Vec3fCross(_about,_a,&tmp); + SST_Math_Vec3fScaleLocal(&tmp,sinf(_theta)); + SST_Math_Vec3fAddLocal(&tmp2,&tmp); + SST_Math_Vec3fScale(_a,cosf(_theta),&tmp); + SST_Math_Vec3fAddLocal(&tmp2,&tmp); + + for(i = 0; i < 3; i++) + _a->v[i] = tmp2.v[i]; + + +} + +/******************************************************************************/ + +void SST_Math_Vec3fRotate(const SST_Vec3f* RESTRICT _a,float _theta, SST_Vec3f* RESTRICT _out) +{ + + + SST_Vec3f tmp; + SST_Vec3f about; + float scalar; + about.x = 0.0; + about.y = 0.0; + about.z = 0.0; + scalar = (1.000000f-cosf(_theta)) * SST_Math_Vec3fDot(&about,_a); + SST_Math_Vec3fScale(&about,scalar,_out); + SST_Math_Vec3fCross(&about,_a,&tmp); + SST_Math_Vec3fScaleLocal(&tmp,sinf(_theta)); + SST_Math_Vec3fAddLocal(_out,&tmp); + SST_Math_Vec3fScale(_a,cosf(_theta),&tmp); + SST_Math_Vec3fAddLocal(_out,&tmp); + +} + +/******************************************************************************/ + +void SST_Math_Vec3fRotateLocal(SST_Vec3f* RESTRICT _a, float _theta) +{ + + + int i; + SST_Vec3f tmp; + SST_Vec3f tmp2; + SST_Vec3f about; + float scalar; + about.x = 0.0; + about.y = 0.0; + about.z = 0.0; + scalar = (1.000000f-cosf(_theta)) * SST_Math_Vec3fDot(&about,_a); + + SST_Math_Vec3fScale(&about,scalar,&tmp2); + SST_Math_Vec3fCross(&about,_a,&tmp); + SST_Math_Vec3fScaleLocal(&tmp,sinf(_theta)); + SST_Math_Vec3fAddLocal(&tmp2,&tmp); + SST_Math_Vec3fScale(_a,cosf(_theta),&tmp); + SST_Math_Vec3fAddLocal(&tmp2,&tmp); + + for(i = 0; i < 3; i++) + _a->v[i] = tmp2.v[i]; + + +} +void SST_Math_Vec3fNormalize(const SST_Vec3f* RESTRICT _in, SST_Vec3f* RESTRICT _out) +{ + float scalar = 1.f/SST_Math_Vec3fMagnitude(_in); + SST_Math_Vec3fScale(_in,scalar,_out); +} + +/******************************************************************************/ + +void SST_Math_Vec3fNormalizeLocal(SST_Vec3f* _inout) +{ + float scalar = 1.f/SST_Math_Vec3fMagnitude(_inout); + SST_Math_Vec3fScaleLocal(_inout,scalar); +} + +/******************************************************************************/ + +void SST_Math_Vec3fRecipSqrt(const SST_Vec3f* RESTRICT _in, SST_Vec3f* RESTRICT _out) +{ + int i; + for(i = 0; i < 3; i++) + _out->v[i] = 1/sqrtf(_in->v[i]); +} + +/******************************************************************************/ + +void SST_Math_Vec3fRecipSqrtLocal(SST_Vec3f* RESTRICT _a) +{ + int i; + for(i = 0; i < 3; i++) + _a->v[i] = 1/sqrtf(_a->v[i]); +} + +/******************************************************************************/ + +void SST_Math_Vec3fSqrt(const SST_Vec3f* RESTRICT _in, SST_Vec3f* RESTRICT _out) +{ + int i; + for(i = 0; i < 3; i++) + _out->v[i] = sqrtf(_in->v[i]); +} + +/******************************************************************************/ + +void SST_Math_Vec3fSqrtLocal(SST_Vec3f* RESTRICT _a) +{ + int i; + for(i = 0; i < 3; i++) + _a->v[i] = sqrtf(_a->v[i]); +} + +/******************************************************************************/ + +float SST_Math_Vec3fMagnitude(const SST_Vec3f* RESTRICT _a) +{ + float sum = 0; + int i; + for(i = 0; i < 3; i++) + sum += _a->v[i] * _a->v[i]; + return sqrtf(sum); +} + +/******************************************************************************/ + +void SST_Math_Vec3fAbs(const SST_Vec3f* RESTRICT _in, SST_Vec3f* RESTRICT _out) +{ + int i; + for(i = 0; i < 3; i++) + _out->v[i] = fabsf(_in->v[i]); +} + +/******************************************************************************/ + +void SST_Math_Vec3fAbsLocal(SST_Vec3f* RESTRICT _a) +{ + int i; + for(i = 0; i < 3; i++) + _a->v[i] = fabsf(_a->v[i]); +} + +/******************************************************************************/ + +void SST_Math_Vec3fNegate(const SST_Vec3f* RESTRICT _in, SST_Vec3f* RESTRICT _out) +{ + int i; + for(i = 0; i < 3; i++) + _out->v[i] = -(_in->v[i]); +} + +/******************************************************************************/ + +void SST_Math_Vec3fNegateLocal(SST_Vec3f* RESTRICT _a) +{ + int i; + for(i = 0; i < 3; i++) + _a->v[i] = -(_a->v[i]); +} + +/******************************************************************************/ + +void SST_Math_Vec3fRecip(const SST_Vec3f* RESTRICT _in, SST_Vec3f* RESTRICT _out) +{ + int i; + for(i = 0; i < 3; i++) + _out->v[i] = 1/(_in->v[i]); +} + +/******************************************************************************/ + +void SST_Math_Vec3fRecipLocal(SST_Vec3f* RESTRICT _a) +{ + int i; + for(i = 0; i < 3; i++) + _a->v[i] = 1/(_a->v[i]); +} + +/******************************************************************************/ + +float SST_Math_Vec3fDot(const SST_Vec3f* RESTRICT _a, const SST_Vec3f* RESTRICT _b) +{ + float sum = 0; + int i; + for(i = 0; i < 3; i++) + sum += _a->v[i] * _b->v[i]; + return sum; +} + +/******************************************************************************/ + +float SST_Math_Vec3fMagnitudeSquared(const SST_Vec3f* RESTRICT _a) +{ + float sum = 0; + int i; + for(i = 0; i < 3; i++) + sum += _a->v[i] * _a->v[i]; + return sum; +} + +/******************************************************************************/ + +void SST_Math_Vec3fProject(const SST_Vec3f* RESTRICT _a, const SST_Vec3f* RESTRICT _b, SST_Vec3f* RESTRICT _out) +{ + float scalar = SST_Math_Vec3fDot(_a,_b) / SST_Math_Vec3fDot(_b,_b); + SST_Math_Vec3fScale(_b, scalar, _out); +} + + +/******************************************************************************/ + +void SST_Math_Vec3fProjectLocal(SST_Vec3f* RESTRICT _a, const SST_Vec3f* RESTRICT _b) +{ + float scalar = SST_Math_Vec3fDot(_a,_b) / SST_Math_Vec3fDot(_b,_b); + SST_Math_Vec3fScale(_b, scalar, _a); +} + + +/******************************************************************************/ + +void SST_Math_Vec3fBias(const SST_Vec3f* RESTRICT _a, const float _bias, SST_Vec3f* RESTRICT _out) +{ + int i; + for(i = 0; i < 3; i++) + _out->v[i] = _a->v[i] + _bias; +} + + +/******************************************************************************/ + +void SST_Math_Vec3fBiasLocal(SST_Vec3f* RESTRICT _a, const float _bias) +{ + int i; + for(i = 0; i < 3; i++) + _a->v[i] += _bias; +} + + +/******************************************************************************/ + diff --git a/libsst-math/SST_Vec3i.c b/libsst-math/SST_Vec3i.c new file mode 100644 index 0000000..6d80810 --- /dev/null +++ b/libsst-math/SST_Vec3i.c @@ -0,0 +1,373 @@ +/* + AUTOMATICALLY GENERATED FILE - DO NOT EDIT! + Please change MatrixNxN.py and re-run it +*/ +/* Generated with ./VectorN.py n = 3, TYPE = int */ + +#include <float.h> +#include <math.h> +#include <pstdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <SST/SST_Build.h> +#include <SST/SST_Vec3.h> + +void SST_Math_Vec3iAdd(const SST_Vec3i* RESTRICT _A, const SST_Vec3i* RESTRICT _B, SST_Vec3i* RESTRICT _out) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + SST_ASSUME_ALIGNED(_out,16); + + _out->v[0] = _A->v[0] + _B->v[0]; + _out->v[1] = _A->v[1] + _B->v[1]; + _out->v[2] = _A->v[2] + _B->v[2]; +} + +/******************************************************************************/ + +void SST_Math_Vec3iAddLocal(SST_Vec3i* RESTRICT _A, const SST_Vec3i* RESTRICT _B) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + + _A->v[0] += _B->v[0]; + _A->v[1] += _B->v[1]; + _A->v[2] += _B->v[2]; +} + +/******************************************************************************/ + +void SST_Math_Vec3iSubtract(const SST_Vec3i* RESTRICT _A, const SST_Vec3i* RESTRICT _B, SST_Vec3i* RESTRICT _out) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + SST_ASSUME_ALIGNED(_out,16); + + _out->v[0] = _A->v[0] - _B->v[0]; + _out->v[1] = _A->v[1] - _B->v[1]; + _out->v[2] = _A->v[2] - _B->v[2]; +} + +/******************************************************************************/ + +void SST_Math_Vec3iSubtractLocal(SST_Vec3i* RESTRICT _A, const SST_Vec3i* RESTRICT _B) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + + _A->v[0] -= _B->v[0]; + _A->v[1] -= _B->v[1]; + _A->v[2] -= _B->v[2]; +} + +/******************************************************************************/ + +void SST_Math_Vec3iMultiply(const SST_Vec3i* RESTRICT _A, const SST_Vec3i* RESTRICT _B, SST_Vec3i* RESTRICT _out) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + SST_ASSUME_ALIGNED(_out,16); + + _out->v[0] = _A->v[0] * _B->v[0]; + _out->v[1] = _A->v[1] * _B->v[1]; + _out->v[2] = _A->v[2] * _B->v[2]; +} + +/******************************************************************************/ + +void SST_Math_Vec3iMultiplyLocal(SST_Vec3i* RESTRICT _A, const SST_Vec3i* RESTRICT _B) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + + _A->v[0] *= _B->v[0]; + _A->v[1] *= _B->v[1]; + _A->v[2] *= _B->v[2]; +} + +/******************************************************************************/ + +void SST_Math_Vec3iScale(const SST_Vec3i* RESTRICT _A, const int k, SST_Vec3i* RESTRICT _out) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_out,16); + + _out->v[0] = _A->v[0] * k; + _out->v[1] = _A->v[1] * k; + _out->v[2] = _A->v[2] * k; +} + +/******************************************************************************/ + +void SST_Math_Vec3iScaleLocal(SST_Vec3i* RESTRICT _A, const int k) +{ + SST_ASSUME_ALIGNED(_A,16); + + _A->v[0] *= k; + _A->v[1] *= k; + _A->v[2] *= k; +} + +/******************************************************************************/ + +void SST_Math_Vec3iDivide(const SST_Vec3i* RESTRICT _A, const SST_Vec3i* RESTRICT _B, SST_Vec3i* RESTRICT _out) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + SST_ASSUME_ALIGNED(_out,16); + + _out->v[0] = _A->v[0] / _B->v[0]; + _out->v[1] = _A->v[1] / _B->v[1]; + _out->v[2] = _A->v[2] / _B->v[2]; +} + +/******************************************************************************/ + +void SST_Math_Vec3iDivideLocal(SST_Vec3i* RESTRICT _A, const SST_Vec3i* RESTRICT _B) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + + _A->v[0] /= _B->v[0]; + _A->v[1] /= _B->v[1]; + _A->v[2] /= _B->v[2]; +} + +/******************************************************************************/ + + +/******************************************************************************/ + + +void SST_Math_Vec3iAddMult(const SST_Vec3i* RESTRICT _X, const int _x, const SST_Vec3i* RESTRICT _Y, SST_Vec3i* RESTRICT _Z) +{ + SST_ASSUME_ALIGNED(_X,16); + SST_ASSUME_ALIGNED(_Y,16); + SST_ASSUME_ALIGNED(_Z,16); + /* _Z = _x * _X + _Y */ + _Z->v[0] = _x * _X->v[0] + _Y->v[0]; + _Z->v[1] = _x * _X->v[1] + _Y->v[1]; + _Z->v[2] = _x * _X->v[2] + _Y->v[2]; + +} + + +void SST_Math_Vec3iAddMultLocal(SST_Vec3i* RESTRICT _X, const int _x, const SST_Vec3i* RESTRICT _Y) +{ + SST_ASSUME_ALIGNED(_X,16); + SST_ASSUME_ALIGNED(_Y,16); + /* _X = _x * _X + _Y */ + _X->v[0] = _x * _X->v[0] + _Y->v[0]; + _X->v[1] = _x * _X->v[1] + _Y->v[1]; + _X->v[2] = _x * _X->v[2] + _Y->v[2]; + +} + + +/******************************************************************************/ + + +void SST_Math_Vec3iLerp(const SST_Vec3i* RESTRICT _X, const SST_Vec3i* RESTRICT _Y, const int _y, SST_Vec3i* RESTRICT _Z) +{ + SST_ASSUME_ALIGNED(_X,16); + SST_ASSUME_ALIGNED(_Y,16); + SST_ASSUME_ALIGNED(_Z,16); + /* Z = x*X + y*Y */ + _Z->v[0] = _X->v[0] + (_Y->v[0] - _X->v[0]) * _y ; + _Z->v[1] = _X->v[1] + (_Y->v[1] - _X->v[1]) * _y ; + _Z->v[2] = _X->v[2] + (_Y->v[2] - _X->v[2]) * _y ; + +} + +void SST_Math_Vec3iLerpLocal(SST_Vec3i* RESTRICT _X, const SST_Vec3i* RESTRICT _Y, const int _y) +{ + SST_ASSUME_ALIGNED(_X,16); + SST_ASSUME_ALIGNED(_Y,16); + /* Z = x*X + y*Y */ + _X->v[0] = _X->v[0] + (_Y->v[0] - _X->v[0]) * _y ; + _X->v[1] = _X->v[1] + (_Y->v[1] - _X->v[1]) * _y ; + _X->v[2] = _X->v[2] + (_Y->v[2] - _X->v[2]) * _y ; + +} + +/******************************************************************************/ + + +void SST_Math_Vec3iWeightedSum(const SST_Vec3i* RESTRICT _X, const int _x, const SST_Vec3i* RESTRICT _Y, const int _y, SST_Vec3i* RESTRICT _Z) +{ + SST_ASSUME_ALIGNED(_X,16); + SST_ASSUME_ALIGNED(_Y,16); + SST_ASSUME_ALIGNED(_Z,16); + /* Z = x*X + y*Y */ + _Z->v[0] = _x * _X->v[0] + _y * _Y->v[0]; + _Z->v[1] = _x * _X->v[1] + _y * _Y->v[1]; + _Z->v[2] = _x * _X->v[2] + _y * _Y->v[2]; + +} + +void SST_Math_Vec3iWeightedSumLocal(SST_Vec3i* RESTRICT _X, const int _x, const SST_Vec3i* RESTRICT _Y, const int _y) +{ + SST_ASSUME_ALIGNED(_X,16); + SST_ASSUME_ALIGNED(_Y,16); + /* Z = x*X + y*Y */ + _X->v[0] = _x * _X->v[0] + _y * _Y->v[0]; + _X->v[1] = _x * _X->v[1] + _y * _Y->v[1]; + _X->v[2] = _x * _X->v[2] + _y * _Y->v[2]; + +} + +/******************************************************************************/ + +bool SST_Math_Vec3iEquals(const SST_Vec3i* RESTRICT _a, const SST_Vec3i* RESTRICT _b) +{ + int i; + bool returncode; + SST_ASSUME_ALIGNED(_a,16); + SST_ASSUME_ALIGNED(_b,16); + returncode = 1; + for(i=0;i<3;i++) + { + returncode = (_a->v[i]==_b->v[i]) && returncode; + } + return returncode; +} + + +/******************************************************************************/ + +int SST_Math_Vec3iMax(const SST_Vec3i* RESTRICT _a) +{ + int tmp = _a->v[0]; + if(tmp < _a->v[1]) tmp = _a->v[1]; + if(tmp < _a->v[2]) tmp = _a->v[2]; + + return tmp; +} + +/******************************************************************************/ + +int SST_Math_Vec3iMin(const SST_Vec3i* RESTRICT _a) +{ + int tmp = _a->v[0]; + if(tmp > _a->v[1]) tmp = _a->v[1]; + if(tmp > _a->v[2]) tmp = _a->v[2]; + + return tmp; +} + +/******************************************************************************/ + +void SST_Math_Vec3iAbs(const SST_Vec3i* RESTRICT _in, SST_Vec3i* RESTRICT _out) +{ + int i; + for(i = 0; i < 3; i++) + _out->v[i] = abs(_in->v[i]); +} + +/******************************************************************************/ + +void SST_Math_Vec3iAbsLocal(SST_Vec3i* RESTRICT _a) +{ + int i; + for(i = 0; i < 3; i++) + _a->v[i] = abs(_a->v[i]); +} + +/******************************************************************************/ + +void SST_Math_Vec3iNegate(const SST_Vec3i* RESTRICT _in, SST_Vec3i* RESTRICT _out) +{ + int i; + for(i = 0; i < 3; i++) + _out->v[i] = -(_in->v[i]); +} + +/******************************************************************************/ + +void SST_Math_Vec3iNegateLocal(SST_Vec3i* RESTRICT _a) +{ + int i; + for(i = 0; i < 3; i++) + _a->v[i] = -(_a->v[i]); +} + +/******************************************************************************/ + +void SST_Math_Vec3iRecip(const SST_Vec3i* RESTRICT _in, SST_Vec3i* RESTRICT _out) +{ + int i; + for(i = 0; i < 3; i++) + _out->v[i] = 1/(_in->v[i]); +} + +/******************************************************************************/ + +void SST_Math_Vec3iRecipLocal(SST_Vec3i* RESTRICT _a) +{ + int i; + for(i = 0; i < 3; i++) + _a->v[i] = 1/(_a->v[i]); +} + +/******************************************************************************/ + +int SST_Math_Vec3iDot(const SST_Vec3i* RESTRICT _a, const SST_Vec3i* RESTRICT _b) +{ + int sum = 0; + int i; + for(i = 0; i < 3; i++) + sum += _a->v[i] * _b->v[i]; + return sum; +} + +/******************************************************************************/ + +int SST_Math_Vec3iMagnitudeSquared(const SST_Vec3i* RESTRICT _a) +{ + int sum = 0; + int i; + for(i = 0; i < 3; i++) + sum += _a->v[i] * _a->v[i]; + return sum; +} + +/******************************************************************************/ + +void SST_Math_Vec3iProject(const SST_Vec3i* RESTRICT _a, const SST_Vec3i* RESTRICT _b, SST_Vec3i* RESTRICT _out) +{ + int scalar = SST_Math_Vec3iDot(_a,_b) / SST_Math_Vec3iDot(_b,_b); + SST_Math_Vec3iScale(_b, scalar, _out); +} + + +/******************************************************************************/ + +void SST_Math_Vec3iProjectLocal(SST_Vec3i* RESTRICT _a, const SST_Vec3i* RESTRICT _b) +{ + int scalar = SST_Math_Vec3iDot(_a,_b) / SST_Math_Vec3iDot(_b,_b); + SST_Math_Vec3iScale(_b, scalar, _a); +} + + +/******************************************************************************/ + +void SST_Math_Vec3iBias(const SST_Vec3i* RESTRICT _a, const int _bias, SST_Vec3i* RESTRICT _out) +{ + int i; + for(i = 0; i < 3; i++) + _out->v[i] = _a->v[i] + _bias; +} + + +/******************************************************************************/ + +void SST_Math_Vec3iBiasLocal(SST_Vec3i* RESTRICT _a, const int _bias) +{ + int i; + for(i = 0; i < 3; i++) + _a->v[i] += _bias; +} + + +/******************************************************************************/ + diff --git a/libsst-math/SST_Vec3u.c b/libsst-math/SST_Vec3u.c new file mode 100644 index 0000000..4b325e0 --- /dev/null +++ b/libsst-math/SST_Vec3u.c @@ -0,0 +1,319 @@ +/* + AUTOMATICALLY GENERATED FILE - DO NOT EDIT! + Please change MatrixNxN.py and re-run it +*/ +/* Generated with ./VectorN.py n = 3, TYPE = unsigned int */ + +#include <float.h> +#include <math.h> +#include <pstdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <SST/SST_Build.h> +#include <SST/SST_Vec3.h> + +void SST_Math_Vec3uAdd(const SST_Vec3u* RESTRICT _A, const SST_Vec3u* RESTRICT _B, SST_Vec3u* RESTRICT _out) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + SST_ASSUME_ALIGNED(_out,16); + + _out->v[0] = _A->v[0] + _B->v[0]; + _out->v[1] = _A->v[1] + _B->v[1]; + _out->v[2] = _A->v[2] + _B->v[2]; +} + +/******************************************************************************/ + +void SST_Math_Vec3uAddLocal(SST_Vec3u* RESTRICT _A, const SST_Vec3u* RESTRICT _B) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + + _A->v[0] += _B->v[0]; + _A->v[1] += _B->v[1]; + _A->v[2] += _B->v[2]; +} + +/******************************************************************************/ + +void SST_Math_Vec3uSubtract(const SST_Vec3u* RESTRICT _A, const SST_Vec3u* RESTRICT _B, SST_Vec3u* RESTRICT _out) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + SST_ASSUME_ALIGNED(_out,16); + + _out->v[0] = _A->v[0] - _B->v[0]; + _out->v[1] = _A->v[1] - _B->v[1]; + _out->v[2] = _A->v[2] - _B->v[2]; +} + +/******************************************************************************/ + +void SST_Math_Vec3uSubtractLocal(SST_Vec3u* RESTRICT _A, const SST_Vec3u* RESTRICT _B) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + + _A->v[0] -= _B->v[0]; + _A->v[1] -= _B->v[1]; + _A->v[2] -= _B->v[2]; +} + +/******************************************************************************/ + +void SST_Math_Vec3uMultiply(const SST_Vec3u* RESTRICT _A, const SST_Vec3u* RESTRICT _B, SST_Vec3u* RESTRICT _out) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + SST_ASSUME_ALIGNED(_out,16); + + _out->v[0] = _A->v[0] * _B->v[0]; + _out->v[1] = _A->v[1] * _B->v[1]; + _out->v[2] = _A->v[2] * _B->v[2]; +} + +/******************************************************************************/ + +void SST_Math_Vec3uMultiplyLocal(SST_Vec3u* RESTRICT _A, const SST_Vec3u* RESTRICT _B) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + + _A->v[0] *= _B->v[0]; + _A->v[1] *= _B->v[1]; + _A->v[2] *= _B->v[2]; +} + +/******************************************************************************/ + +void SST_Math_Vec3uScale(const SST_Vec3u* RESTRICT _A, const unsigned int k, SST_Vec3u* RESTRICT _out) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_out,16); + + _out->v[0] = _A->v[0] * k; + _out->v[1] = _A->v[1] * k; + _out->v[2] = _A->v[2] * k; +} + +/******************************************************************************/ + +void SST_Math_Vec3uScaleLocal(SST_Vec3u* RESTRICT _A, const unsigned int k) +{ + SST_ASSUME_ALIGNED(_A,16); + + _A->v[0] *= k; + _A->v[1] *= k; + _A->v[2] *= k; +} + +/******************************************************************************/ + +void SST_Math_Vec3uDivide(const SST_Vec3u* RESTRICT _A, const SST_Vec3u* RESTRICT _B, SST_Vec3u* RESTRICT _out) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + SST_ASSUME_ALIGNED(_out,16); + + _out->v[0] = _A->v[0] / _B->v[0]; + _out->v[1] = _A->v[1] / _B->v[1]; + _out->v[2] = _A->v[2] / _B->v[2]; +} + +/******************************************************************************/ + +void SST_Math_Vec3uDivideLocal(SST_Vec3u* RESTRICT _A, const SST_Vec3u* RESTRICT _B) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + + _A->v[0] /= _B->v[0]; + _A->v[1] /= _B->v[1]; + _A->v[2] /= _B->v[2]; +} + +/******************************************************************************/ + + +/******************************************************************************/ + + +void SST_Math_Vec3uAddMult(const SST_Vec3u* RESTRICT _X, const unsigned int _x, const SST_Vec3u* RESTRICT _Y, SST_Vec3u* RESTRICT _Z) +{ + SST_ASSUME_ALIGNED(_X,16); + SST_ASSUME_ALIGNED(_Y,16); + SST_ASSUME_ALIGNED(_Z,16); + /* _Z = _x * _X + _Y */ + _Z->v[0] = _x * _X->v[0] + _Y->v[0]; + _Z->v[1] = _x * _X->v[1] + _Y->v[1]; + _Z->v[2] = _x * _X->v[2] + _Y->v[2]; + +} + + +void SST_Math_Vec3uAddMultLocal(SST_Vec3u* RESTRICT _X, const unsigned int _x, const SST_Vec3u* RESTRICT _Y) +{ + SST_ASSUME_ALIGNED(_X,16); + SST_ASSUME_ALIGNED(_Y,16); + /* _X = _x * _X + _Y */ + _X->v[0] = _x * _X->v[0] + _Y->v[0]; + _X->v[1] = _x * _X->v[1] + _Y->v[1]; + _X->v[2] = _x * _X->v[2] + _Y->v[2]; + +} + + +/******************************************************************************/ + + +void SST_Math_Vec3uLerp(const SST_Vec3u* RESTRICT _X, const SST_Vec3u* RESTRICT _Y, const unsigned int _y, SST_Vec3u* RESTRICT _Z) +{ + SST_ASSUME_ALIGNED(_X,16); + SST_ASSUME_ALIGNED(_Y,16); + SST_ASSUME_ALIGNED(_Z,16); + /* Z = x*X + y*Y */ + _Z->v[0] = _X->v[0] + (_Y->v[0] - _X->v[0]) * _y ; + _Z->v[1] = _X->v[1] + (_Y->v[1] - _X->v[1]) * _y ; + _Z->v[2] = _X->v[2] + (_Y->v[2] - _X->v[2]) * _y ; + +} + +void SST_Math_Vec3uLerpLocal(SST_Vec3u* RESTRICT _X, const SST_Vec3u* RESTRICT _Y, const unsigned int _y) +{ + SST_ASSUME_ALIGNED(_X,16); + SST_ASSUME_ALIGNED(_Y,16); + /* Z = x*X + y*Y */ + _X->v[0] = _X->v[0] + (_Y->v[0] - _X->v[0]) * _y ; + _X->v[1] = _X->v[1] + (_Y->v[1] - _X->v[1]) * _y ; + _X->v[2] = _X->v[2] + (_Y->v[2] - _X->v[2]) * _y ; + +} + +/******************************************************************************/ + + +void SST_Math_Vec3uWeightedSum(const SST_Vec3u* RESTRICT _X, const unsigned int _x, const SST_Vec3u* RESTRICT _Y, const unsigned int _y, SST_Vec3u* RESTRICT _Z) +{ + SST_ASSUME_ALIGNED(_X,16); + SST_ASSUME_ALIGNED(_Y,16); + SST_ASSUME_ALIGNED(_Z,16); + /* Z = x*X + y*Y */ + _Z->v[0] = _x * _X->v[0] + _y * _Y->v[0]; + _Z->v[1] = _x * _X->v[1] + _y * _Y->v[1]; + _Z->v[2] = _x * _X->v[2] + _y * _Y->v[2]; + +} + +void SST_Math_Vec3uWeightedSumLocal(SST_Vec3u* RESTRICT _X, const unsigned int _x, const SST_Vec3u* RESTRICT _Y, const unsigned int _y) +{ + SST_ASSUME_ALIGNED(_X,16); + SST_ASSUME_ALIGNED(_Y,16); + /* Z = x*X + y*Y */ + _X->v[0] = _x * _X->v[0] + _y * _Y->v[0]; + _X->v[1] = _x * _X->v[1] + _y * _Y->v[1]; + _X->v[2] = _x * _X->v[2] + _y * _Y->v[2]; + +} + +/******************************************************************************/ + +bool SST_Math_Vec3uEquals(const SST_Vec3u* RESTRICT _a, const SST_Vec3u* RESTRICT _b) +{ + int i; + bool returncode; + SST_ASSUME_ALIGNED(_a,16); + SST_ASSUME_ALIGNED(_b,16); + returncode = 1; + for(i=0;i<3;i++) + { + returncode = (_a->v[i]==_b->v[i]) && returncode; + } + return returncode; +} + + +/******************************************************************************/ + +unsigned int SST_Math_Vec3uMax(const SST_Vec3u* RESTRICT _a) +{ + unsigned int tmp = _a->v[0]; + if(tmp < _a->v[1]) tmp = _a->v[1]; + if(tmp < _a->v[2]) tmp = _a->v[2]; + + return tmp; +} + +/******************************************************************************/ + +unsigned int SST_Math_Vec3uMin(const SST_Vec3u* RESTRICT _a) +{ + unsigned int tmp = _a->v[0]; + if(tmp > _a->v[1]) tmp = _a->v[1]; + if(tmp > _a->v[2]) tmp = _a->v[2]; + + return tmp; +} + +/******************************************************************************/ + +unsigned int SST_Math_Vec3uDot(const SST_Vec3u* RESTRICT _a, const SST_Vec3u* RESTRICT _b) +{ + unsigned int sum = 0; + int i; + for(i = 0; i < 3; i++) + sum += _a->v[i] * _b->v[i]; + return sum; +} + +/******************************************************************************/ + +unsigned int SST_Math_Vec3uMagnitudeSquared(const SST_Vec3u* RESTRICT _a) +{ + unsigned int sum = 0; + int i; + for(i = 0; i < 3; i++) + sum += _a->v[i] * _a->v[i]; + return sum; +} + +/******************************************************************************/ + +void SST_Math_Vec3uProject(const SST_Vec3u* RESTRICT _a, const SST_Vec3u* RESTRICT _b, SST_Vec3u* RESTRICT _out) +{ + unsigned int scalar = SST_Math_Vec3uDot(_a,_b) / SST_Math_Vec3uDot(_b,_b); + SST_Math_Vec3uScale(_b, scalar, _out); +} + + +/******************************************************************************/ + +void SST_Math_Vec3uProjectLocal(SST_Vec3u* RESTRICT _a, const SST_Vec3u* RESTRICT _b) +{ + unsigned int scalar = SST_Math_Vec3uDot(_a,_b) / SST_Math_Vec3uDot(_b,_b); + SST_Math_Vec3uScale(_b, scalar, _a); +} + + +/******************************************************************************/ + +void SST_Math_Vec3uBias(const SST_Vec3u* RESTRICT _a, const unsigned int _bias, SST_Vec3u* RESTRICT _out) +{ + int i; + for(i = 0; i < 3; i++) + _out->v[i] = _a->v[i] + _bias; +} + + +/******************************************************************************/ + +void SST_Math_Vec3uBiasLocal(SST_Vec3u* RESTRICT _a, const unsigned int _bias) +{ + int i; + for(i = 0; i < 3; i++) + _a->v[i] += _bias; +} + + +/******************************************************************************/ + diff --git a/libsst-math/SST_Vec4d.c b/libsst-math/SST_Vec4d.c new file mode 100644 index 0000000..4e20e0e --- /dev/null +++ b/libsst-math/SST_Vec4d.c @@ -0,0 +1,458 @@ +/* + AUTOMATICALLY GENERATED FILE - DO NOT EDIT! + Please change MatrixNxN.py and re-run it +*/ +/* Generated with ./VectorN.py n = 4, TYPE = double */ + +#include <float.h> +#include <math.h> +#include <pstdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <SST/SST_Build.h> +#include <SST/SST_Vec4.h> + +void SST_Math_Vec4dAdd(const SST_Vec4d* RESTRICT _A, const SST_Vec4d* RESTRICT _B, SST_Vec4d* RESTRICT _out) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + SST_ASSUME_ALIGNED(_out,16); + + _out->v[0] = _A->v[0] + _B->v[0]; + _out->v[1] = _A->v[1] + _B->v[1]; + _out->v[2] = _A->v[2] + _B->v[2]; + _out->v[3] = _A->v[3] + _B->v[3]; +} + +/******************************************************************************/ + +void SST_Math_Vec4dAddLocal(SST_Vec4d* RESTRICT _A, const SST_Vec4d* RESTRICT _B) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + + _A->v[0] += _B->v[0]; + _A->v[1] += _B->v[1]; + _A->v[2] += _B->v[2]; + _A->v[3] += _B->v[3]; +} + +/******************************************************************************/ + +void SST_Math_Vec4dSubtract(const SST_Vec4d* RESTRICT _A, const SST_Vec4d* RESTRICT _B, SST_Vec4d* RESTRICT _out) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + SST_ASSUME_ALIGNED(_out,16); + + _out->v[0] = _A->v[0] - _B->v[0]; + _out->v[1] = _A->v[1] - _B->v[1]; + _out->v[2] = _A->v[2] - _B->v[2]; + _out->v[3] = _A->v[3] - _B->v[3]; +} + +/******************************************************************************/ + +void SST_Math_Vec4dSubtractLocal(SST_Vec4d* RESTRICT _A, const SST_Vec4d* RESTRICT _B) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + + _A->v[0] -= _B->v[0]; + _A->v[1] -= _B->v[1]; + _A->v[2] -= _B->v[2]; + _A->v[3] -= _B->v[3]; +} + +/******************************************************************************/ + +void SST_Math_Vec4dMultiply(const SST_Vec4d* RESTRICT _A, const SST_Vec4d* RESTRICT _B, SST_Vec4d* RESTRICT _out) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + SST_ASSUME_ALIGNED(_out,16); + + _out->v[0] = _A->v[0] * _B->v[0]; + _out->v[1] = _A->v[1] * _B->v[1]; + _out->v[2] = _A->v[2] * _B->v[2]; + _out->v[3] = _A->v[3] * _B->v[3]; +} + +/******************************************************************************/ + +void SST_Math_Vec4dMultiplyLocal(SST_Vec4d* RESTRICT _A, const SST_Vec4d* RESTRICT _B) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + + _A->v[0] *= _B->v[0]; + _A->v[1] *= _B->v[1]; + _A->v[2] *= _B->v[2]; + _A->v[3] *= _B->v[3]; +} + +/******************************************************************************/ + +void SST_Math_Vec4dScale(const SST_Vec4d* RESTRICT _A, const double k, SST_Vec4d* RESTRICT _out) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_out,16); + + _out->v[0] = _A->v[0] * k; + _out->v[1] = _A->v[1] * k; + _out->v[2] = _A->v[2] * k; + _out->v[3] = _A->v[3] * k; +} + +/******************************************************************************/ + +void SST_Math_Vec4dScaleLocal(SST_Vec4d* RESTRICT _A, const double k) +{ + SST_ASSUME_ALIGNED(_A,16); + + _A->v[0] *= k; + _A->v[1] *= k; + _A->v[2] *= k; + _A->v[3] *= k; +} + +/******************************************************************************/ + +void SST_Math_Vec4dDivide(const SST_Vec4d* RESTRICT _A, const SST_Vec4d* RESTRICT _B, SST_Vec4d* RESTRICT _out) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + SST_ASSUME_ALIGNED(_out,16); + + _out->v[0] = _A->v[0] / _B->v[0]; + _out->v[1] = _A->v[1] / _B->v[1]; + _out->v[2] = _A->v[2] / _B->v[2]; + _out->v[3] = _A->v[3] / _B->v[3]; +} + +/******************************************************************************/ + +void SST_Math_Vec4dDivideLocal(SST_Vec4d* RESTRICT _A, const SST_Vec4d* RESTRICT _B) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + + _A->v[0] /= _B->v[0]; + _A->v[1] /= _B->v[1]; + _A->v[2] /= _B->v[2]; + _A->v[3] /= _B->v[3]; +} + +/******************************************************************************/ + + +/******************************************************************************/ + + +void SST_Math_Vec4dAddMult(const SST_Vec4d* RESTRICT _X, const double _x, const SST_Vec4d* RESTRICT _Y, SST_Vec4d* RESTRICT _Z) +{ + SST_ASSUME_ALIGNED(_X,16); + SST_ASSUME_ALIGNED(_Y,16); + SST_ASSUME_ALIGNED(_Z,16); + /* _Z = _x * _X + _Y */ + _Z->v[0] = _x * _X->v[0] + _Y->v[0]; + _Z->v[1] = _x * _X->v[1] + _Y->v[1]; + _Z->v[2] = _x * _X->v[2] + _Y->v[2]; + _Z->v[3] = _x * _X->v[3] + _Y->v[3]; + +} + + +void SST_Math_Vec4dAddMultLocal(SST_Vec4d* RESTRICT _X, const double _x, const SST_Vec4d* RESTRICT _Y) +{ + SST_ASSUME_ALIGNED(_X,16); + SST_ASSUME_ALIGNED(_Y,16); + /* _X = _x * _X + _Y */ + _X->v[0] = _x * _X->v[0] + _Y->v[0]; + _X->v[1] = _x * _X->v[1] + _Y->v[1]; + _X->v[2] = _x * _X->v[2] + _Y->v[2]; + _X->v[3] = _x * _X->v[3] + _Y->v[3]; + +} + + +/******************************************************************************/ + + +void SST_Math_Vec4dLerp(const SST_Vec4d* RESTRICT _X, const SST_Vec4d* RESTRICT _Y, const double _y, SST_Vec4d* RESTRICT _Z) +{ + SST_ASSUME_ALIGNED(_X,16); + SST_ASSUME_ALIGNED(_Y,16); + SST_ASSUME_ALIGNED(_Z,16); + /* Z = x*X + y*Y */ + _Z->v[0] = _X->v[0] + (_Y->v[0] - _X->v[0]) * _y ; + _Z->v[1] = _X->v[1] + (_Y->v[1] - _X->v[1]) * _y ; + _Z->v[2] = _X->v[2] + (_Y->v[2] - _X->v[2]) * _y ; + _Z->v[3] = _X->v[3] + (_Y->v[3] - _X->v[3]) * _y ; + +} + +void SST_Math_Vec4dLerpLocal(SST_Vec4d* RESTRICT _X, const SST_Vec4d* RESTRICT _Y, const double _y) +{ + SST_ASSUME_ALIGNED(_X,16); + SST_ASSUME_ALIGNED(_Y,16); + /* Z = x*X + y*Y */ + _X->v[0] = _X->v[0] + (_Y->v[0] - _X->v[0]) * _y ; + _X->v[1] = _X->v[1] + (_Y->v[1] - _X->v[1]) * _y ; + _X->v[2] = _X->v[2] + (_Y->v[2] - _X->v[2]) * _y ; + _X->v[3] = _X->v[3] + (_Y->v[3] - _X->v[3]) * _y ; + +} + +/******************************************************************************/ + + +void SST_Math_Vec4dWeightedSum(const SST_Vec4d* RESTRICT _X, const double _x, const SST_Vec4d* RESTRICT _Y, const double _y, SST_Vec4d* RESTRICT _Z) +{ + SST_ASSUME_ALIGNED(_X,16); + SST_ASSUME_ALIGNED(_Y,16); + SST_ASSUME_ALIGNED(_Z,16); + /* Z = x*X + y*Y */ + _Z->v[0] = _x * _X->v[0] + _y * _Y->v[0]; + _Z->v[1] = _x * _X->v[1] + _y * _Y->v[1]; + _Z->v[2] = _x * _X->v[2] + _y * _Y->v[2]; + _Z->v[3] = _x * _X->v[3] + _y * _Y->v[3]; + +} + +void SST_Math_Vec4dWeightedSumLocal(SST_Vec4d* RESTRICT _X, const double _x, const SST_Vec4d* RESTRICT _Y, const double _y) +{ + SST_ASSUME_ALIGNED(_X,16); + SST_ASSUME_ALIGNED(_Y,16); + /* Z = x*X + y*Y */ + _X->v[0] = _x * _X->v[0] + _y * _Y->v[0]; + _X->v[1] = _x * _X->v[1] + _y * _Y->v[1]; + _X->v[2] = _x * _X->v[2] + _y * _Y->v[2]; + _X->v[3] = _x * _X->v[3] + _y * _Y->v[3]; + +} + +/******************************************************************************/ + +bool SST_Math_Vec4dEquals(const SST_Vec4d* RESTRICT _a, const SST_Vec4d* RESTRICT _b, const double _tolerance) +{ + SST_Vec4d tmp; + int i; + bool returncode; + SST_ASSUME_ALIGNED(_a,16); + SST_ASSUME_ALIGNED(_b,16); + returncode = 1; + + SST_Math_Vec4dSubtract(_a,_b,&tmp); + for(i=0;i<4;i++) + { + returncode = (fabs(tmp.v[i]) <= _tolerance) && returncode; + } + + return returncode; +} + + +/******************************************************************************/ + +double SST_Math_Vec4dMax(const SST_Vec4d* RESTRICT _a) +{ + double tmp = _a->v[0]; + if(tmp < _a->v[1]) tmp = _a->v[1]; + if(tmp < _a->v[2]) tmp = _a->v[2]; + if(tmp < _a->v[3]) tmp = _a->v[3]; + + return tmp; +} + +/******************************************************************************/ + +double SST_Math_Vec4dMin(const SST_Vec4d* RESTRICT _a) +{ + double tmp = _a->v[0]; + if(tmp > _a->v[1]) tmp = _a->v[1]; + if(tmp > _a->v[2]) tmp = _a->v[2]; + if(tmp > _a->v[3]) tmp = _a->v[3]; + + return tmp; +} + +/******************************************************************************/ + +void SST_Math_Vec4dNormalize(const SST_Vec4d* RESTRICT _in, SST_Vec4d* RESTRICT _out) +{ + double scalar = 1.f/SST_Math_Vec4dMagnitude(_in); + SST_Math_Vec4dScale(_in,scalar,_out); +} + +/******************************************************************************/ + +void SST_Math_Vec4dNormalizeLocal(SST_Vec4d* _inout) +{ + double scalar = 1.f/SST_Math_Vec4dMagnitude(_inout); + SST_Math_Vec4dScaleLocal(_inout,scalar); +} + +/******************************************************************************/ + +void SST_Math_Vec4dRecipSqrt(const SST_Vec4d* RESTRICT _in, SST_Vec4d* RESTRICT _out) +{ + int i; + for(i = 0; i < 4; i++) + _out->v[i] = 1/sqrt(_in->v[i]); +} + +/******************************************************************************/ + +void SST_Math_Vec4dRecipSqrtLocal(SST_Vec4d* RESTRICT _a) +{ + int i; + for(i = 0; i < 4; i++) + _a->v[i] = 1/sqrt(_a->v[i]); +} + +/******************************************************************************/ + +void SST_Math_Vec4dSqrt(const SST_Vec4d* RESTRICT _in, SST_Vec4d* RESTRICT _out) +{ + int i; + for(i = 0; i < 4; i++) + _out->v[i] = sqrt(_in->v[i]); +} + +/******************************************************************************/ + +void SST_Math_Vec4dSqrtLocal(SST_Vec4d* RESTRICT _a) +{ + int i; + for(i = 0; i < 4; i++) + _a->v[i] = sqrt(_a->v[i]); +} + +/******************************************************************************/ + +double SST_Math_Vec4dMagnitude(const SST_Vec4d* RESTRICT _a) +{ + double sum = 0; + int i; + for(i = 0; i < 4; i++) + sum += _a->v[i] * _a->v[i]; + return sqrt(sum); +} + +/******************************************************************************/ + +void SST_Math_Vec4dAbs(const SST_Vec4d* RESTRICT _in, SST_Vec4d* RESTRICT _out) +{ + int i; + for(i = 0; i < 4; i++) + _out->v[i] = fabs(_in->v[i]); +} + +/******************************************************************************/ + +void SST_Math_Vec4dAbsLocal(SST_Vec4d* RESTRICT _a) +{ + int i; + for(i = 0; i < 4; i++) + _a->v[i] = fabs(_a->v[i]); +} + +/******************************************************************************/ + +void SST_Math_Vec4dNegate(const SST_Vec4d* RESTRICT _in, SST_Vec4d* RESTRICT _out) +{ + int i; + for(i = 0; i < 4; i++) + _out->v[i] = -(_in->v[i]); +} + +/******************************************************************************/ + +void SST_Math_Vec4dNegateLocal(SST_Vec4d* RESTRICT _a) +{ + int i; + for(i = 0; i < 4; i++) + _a->v[i] = -(_a->v[i]); +} + +/******************************************************************************/ + +void SST_Math_Vec4dRecip(const SST_Vec4d* RESTRICT _in, SST_Vec4d* RESTRICT _out) +{ + int i; + for(i = 0; i < 4; i++) + _out->v[i] = 1/(_in->v[i]); +} + +/******************************************************************************/ + +void SST_Math_Vec4dRecipLocal(SST_Vec4d* RESTRICT _a) +{ + int i; + for(i = 0; i < 4; i++) + _a->v[i] = 1/(_a->v[i]); +} + +/******************************************************************************/ + +double SST_Math_Vec4dDot(const SST_Vec4d* RESTRICT _a, const SST_Vec4d* RESTRICT _b) +{ + double sum = 0; + int i; + for(i = 0; i < 4; i++) + sum += _a->v[i] * _b->v[i]; + return sum; +} + +/******************************************************************************/ + +double SST_Math_Vec4dMagnitudeSquared(const SST_Vec4d* RESTRICT _a) +{ + double sum = 0; + int i; + for(i = 0; i < 4; i++) + sum += _a->v[i] * _a->v[i]; + return sum; +} + +/******************************************************************************/ + +void SST_Math_Vec4dProject(const SST_Vec4d* RESTRICT _a, const SST_Vec4d* RESTRICT _b, SST_Vec4d* RESTRICT _out) +{ + double scalar = SST_Math_Vec4dDot(_a,_b) / SST_Math_Vec4dDot(_b,_b); + SST_Math_Vec4dScale(_b, scalar, _out); +} + + +/******************************************************************************/ + +void SST_Math_Vec4dProjectLocal(SST_Vec4d* RESTRICT _a, const SST_Vec4d* RESTRICT _b) +{ + double scalar = SST_Math_Vec4dDot(_a,_b) / SST_Math_Vec4dDot(_b,_b); + SST_Math_Vec4dScale(_b, scalar, _a); +} + + +/******************************************************************************/ + +void SST_Math_Vec4dBias(const SST_Vec4d* RESTRICT _a, const double _bias, SST_Vec4d* RESTRICT _out) +{ + int i; + for(i = 0; i < 4; i++) + _out->v[i] = _a->v[i] + _bias; +} + + +/******************************************************************************/ + +void SST_Math_Vec4dBiasLocal(SST_Vec4d* RESTRICT _a, const double _bias) +{ + int i; + for(i = 0; i < 4; i++) + _a->v[i] += _bias; +} + + +/******************************************************************************/ + diff --git a/libsst-math/SST_Vec4f.c b/libsst-math/SST_Vec4f.c new file mode 100644 index 0000000..ce760dd --- /dev/null +++ b/libsst-math/SST_Vec4f.c @@ -0,0 +1,458 @@ +/* + AUTOMATICALLY GENERATED FILE - DO NOT EDIT! + Please change MatrixNxN.py and re-run it +*/ +/* Generated with ./VectorN.py n = 4, TYPE = float */ + +#include <float.h> +#include <math.h> +#include <pstdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <SST/SST_Build.h> +#include <SST/SST_Vec4.h> + +void SST_Math_Vec4fAdd(const SST_Vec4f* RESTRICT _A, const SST_Vec4f* RESTRICT _B, SST_Vec4f* RESTRICT _out) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + SST_ASSUME_ALIGNED(_out,16); + + _out->v[0] = _A->v[0] + _B->v[0]; + _out->v[1] = _A->v[1] + _B->v[1]; + _out->v[2] = _A->v[2] + _B->v[2]; + _out->v[3] = _A->v[3] + _B->v[3]; +} + +/******************************************************************************/ + +void SST_Math_Vec4fAddLocal(SST_Vec4f* RESTRICT _A, const SST_Vec4f* RESTRICT _B) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + + _A->v[0] += _B->v[0]; + _A->v[1] += _B->v[1]; + _A->v[2] += _B->v[2]; + _A->v[3] += _B->v[3]; +} + +/******************************************************************************/ + +void SST_Math_Vec4fSubtract(const SST_Vec4f* RESTRICT _A, const SST_Vec4f* RESTRICT _B, SST_Vec4f* RESTRICT _out) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + SST_ASSUME_ALIGNED(_out,16); + + _out->v[0] = _A->v[0] - _B->v[0]; + _out->v[1] = _A->v[1] - _B->v[1]; + _out->v[2] = _A->v[2] - _B->v[2]; + _out->v[3] = _A->v[3] - _B->v[3]; +} + +/******************************************************************************/ + +void SST_Math_Vec4fSubtractLocal(SST_Vec4f* RESTRICT _A, const SST_Vec4f* RESTRICT _B) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + + _A->v[0] -= _B->v[0]; + _A->v[1] -= _B->v[1]; + _A->v[2] -= _B->v[2]; + _A->v[3] -= _B->v[3]; +} + +/******************************************************************************/ + +void SST_Math_Vec4fMultiply(const SST_Vec4f* RESTRICT _A, const SST_Vec4f* RESTRICT _B, SST_Vec4f* RESTRICT _out) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + SST_ASSUME_ALIGNED(_out,16); + + _out->v[0] = _A->v[0] * _B->v[0]; + _out->v[1] = _A->v[1] * _B->v[1]; + _out->v[2] = _A->v[2] * _B->v[2]; + _out->v[3] = _A->v[3] * _B->v[3]; +} + +/******************************************************************************/ + +void SST_Math_Vec4fMultiplyLocal(SST_Vec4f* RESTRICT _A, const SST_Vec4f* RESTRICT _B) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + + _A->v[0] *= _B->v[0]; + _A->v[1] *= _B->v[1]; + _A->v[2] *= _B->v[2]; + _A->v[3] *= _B->v[3]; +} + +/******************************************************************************/ + +void SST_Math_Vec4fScale(const SST_Vec4f* RESTRICT _A, const float k, SST_Vec4f* RESTRICT _out) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_out,16); + + _out->v[0] = _A->v[0] * k; + _out->v[1] = _A->v[1] * k; + _out->v[2] = _A->v[2] * k; + _out->v[3] = _A->v[3] * k; +} + +/******************************************************************************/ + +void SST_Math_Vec4fScaleLocal(SST_Vec4f* RESTRICT _A, const float k) +{ + SST_ASSUME_ALIGNED(_A,16); + + _A->v[0] *= k; + _A->v[1] *= k; + _A->v[2] *= k; + _A->v[3] *= k; +} + +/******************************************************************************/ + +void SST_Math_Vec4fDivide(const SST_Vec4f* RESTRICT _A, const SST_Vec4f* RESTRICT _B, SST_Vec4f* RESTRICT _out) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + SST_ASSUME_ALIGNED(_out,16); + + _out->v[0] = _A->v[0] / _B->v[0]; + _out->v[1] = _A->v[1] / _B->v[1]; + _out->v[2] = _A->v[2] / _B->v[2]; + _out->v[3] = _A->v[3] / _B->v[3]; +} + +/******************************************************************************/ + +void SST_Math_Vec4fDivideLocal(SST_Vec4f* RESTRICT _A, const SST_Vec4f* RESTRICT _B) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + + _A->v[0] /= _B->v[0]; + _A->v[1] /= _B->v[1]; + _A->v[2] /= _B->v[2]; + _A->v[3] /= _B->v[3]; +} + +/******************************************************************************/ + + +/******************************************************************************/ + + +void SST_Math_Vec4fAddMult(const SST_Vec4f* RESTRICT _X, const float _x, const SST_Vec4f* RESTRICT _Y, SST_Vec4f* RESTRICT _Z) +{ + SST_ASSUME_ALIGNED(_X,16); + SST_ASSUME_ALIGNED(_Y,16); + SST_ASSUME_ALIGNED(_Z,16); + /* _Z = _x * _X + _Y */ + _Z->v[0] = _x * _X->v[0] + _Y->v[0]; + _Z->v[1] = _x * _X->v[1] + _Y->v[1]; + _Z->v[2] = _x * _X->v[2] + _Y->v[2]; + _Z->v[3] = _x * _X->v[3] + _Y->v[3]; + +} + + +void SST_Math_Vec4fAddMultLocal(SST_Vec4f* RESTRICT _X, const float _x, const SST_Vec4f* RESTRICT _Y) +{ + SST_ASSUME_ALIGNED(_X,16); + SST_ASSUME_ALIGNED(_Y,16); + /* _X = _x * _X + _Y */ + _X->v[0] = _x * _X->v[0] + _Y->v[0]; + _X->v[1] = _x * _X->v[1] + _Y->v[1]; + _X->v[2] = _x * _X->v[2] + _Y->v[2]; + _X->v[3] = _x * _X->v[3] + _Y->v[3]; + +} + + +/******************************************************************************/ + + +void SST_Math_Vec4fLerp(const SST_Vec4f* RESTRICT _X, const SST_Vec4f* RESTRICT _Y, const float _y, SST_Vec4f* RESTRICT _Z) +{ + SST_ASSUME_ALIGNED(_X,16); + SST_ASSUME_ALIGNED(_Y,16); + SST_ASSUME_ALIGNED(_Z,16); + /* Z = x*X + y*Y */ + _Z->v[0] = _X->v[0] + (_Y->v[0] - _X->v[0]) * _y ; + _Z->v[1] = _X->v[1] + (_Y->v[1] - _X->v[1]) * _y ; + _Z->v[2] = _X->v[2] + (_Y->v[2] - _X->v[2]) * _y ; + _Z->v[3] = _X->v[3] + (_Y->v[3] - _X->v[3]) * _y ; + +} + +void SST_Math_Vec4fLerpLocal(SST_Vec4f* RESTRICT _X, const SST_Vec4f* RESTRICT _Y, const float _y) +{ + SST_ASSUME_ALIGNED(_X,16); + SST_ASSUME_ALIGNED(_Y,16); + /* Z = x*X + y*Y */ + _X->v[0] = _X->v[0] + (_Y->v[0] - _X->v[0]) * _y ; + _X->v[1] = _X->v[1] + (_Y->v[1] - _X->v[1]) * _y ; + _X->v[2] = _X->v[2] + (_Y->v[2] - _X->v[2]) * _y ; + _X->v[3] = _X->v[3] + (_Y->v[3] - _X->v[3]) * _y ; + +} + +/******************************************************************************/ + + +void SST_Math_Vec4fWeightedSum(const SST_Vec4f* RESTRICT _X, const float _x, const SST_Vec4f* RESTRICT _Y, const float _y, SST_Vec4f* RESTRICT _Z) +{ + SST_ASSUME_ALIGNED(_X,16); + SST_ASSUME_ALIGNED(_Y,16); + SST_ASSUME_ALIGNED(_Z,16); + /* Z = x*X + y*Y */ + _Z->v[0] = _x * _X->v[0] + _y * _Y->v[0]; + _Z->v[1] = _x * _X->v[1] + _y * _Y->v[1]; + _Z->v[2] = _x * _X->v[2] + _y * _Y->v[2]; + _Z->v[3] = _x * _X->v[3] + _y * _Y->v[3]; + +} + +void SST_Math_Vec4fWeightedSumLocal(SST_Vec4f* RESTRICT _X, const float _x, const SST_Vec4f* RESTRICT _Y, const float _y) +{ + SST_ASSUME_ALIGNED(_X,16); + SST_ASSUME_ALIGNED(_Y,16); + /* Z = x*X + y*Y */ + _X->v[0] = _x * _X->v[0] + _y * _Y->v[0]; + _X->v[1] = _x * _X->v[1] + _y * _Y->v[1]; + _X->v[2] = _x * _X->v[2] + _y * _Y->v[2]; + _X->v[3] = _x * _X->v[3] + _y * _Y->v[3]; + +} + +/******************************************************************************/ + +bool SST_Math_Vec4fEquals(const SST_Vec4f* RESTRICT _a, const SST_Vec4f* RESTRICT _b, const float _tolerance) +{ + SST_Vec4f tmp; + int i; + bool returncode; + SST_ASSUME_ALIGNED(_a,16); + SST_ASSUME_ALIGNED(_b,16); + returncode = 1; + + SST_Math_Vec4fSubtract(_a,_b,&tmp); + for(i=0;i<4;i++) + { + returncode = (fabsf(tmp.v[i]) <= _tolerance) && returncode; + } + + return returncode; +} + + +/******************************************************************************/ + +float SST_Math_Vec4fMax(const SST_Vec4f* RESTRICT _a) +{ + float tmp = _a->v[0]; + if(tmp < _a->v[1]) tmp = _a->v[1]; + if(tmp < _a->v[2]) tmp = _a->v[2]; + if(tmp < _a->v[3]) tmp = _a->v[3]; + + return tmp; +} + +/******************************************************************************/ + +float SST_Math_Vec4fMin(const SST_Vec4f* RESTRICT _a) +{ + float tmp = _a->v[0]; + if(tmp > _a->v[1]) tmp = _a->v[1]; + if(tmp > _a->v[2]) tmp = _a->v[2]; + if(tmp > _a->v[3]) tmp = _a->v[3]; + + return tmp; +} + +/******************************************************************************/ + +void SST_Math_Vec4fNormalize(const SST_Vec4f* RESTRICT _in, SST_Vec4f* RESTRICT _out) +{ + float scalar = 1.f/SST_Math_Vec4fMagnitude(_in); + SST_Math_Vec4fScale(_in,scalar,_out); +} + +/******************************************************************************/ + +void SST_Math_Vec4fNormalizeLocal(SST_Vec4f* _inout) +{ + float scalar = 1.f/SST_Math_Vec4fMagnitude(_inout); + SST_Math_Vec4fScaleLocal(_inout,scalar); +} + +/******************************************************************************/ + +void SST_Math_Vec4fRecipSqrt(const SST_Vec4f* RESTRICT _in, SST_Vec4f* RESTRICT _out) +{ + int i; + for(i = 0; i < 4; i++) + _out->v[i] = 1/sqrtf(_in->v[i]); +} + +/******************************************************************************/ + +void SST_Math_Vec4fRecipSqrtLocal(SST_Vec4f* RESTRICT _a) +{ + int i; + for(i = 0; i < 4; i++) + _a->v[i] = 1/sqrtf(_a->v[i]); +} + +/******************************************************************************/ + +void SST_Math_Vec4fSqrt(const SST_Vec4f* RESTRICT _in, SST_Vec4f* RESTRICT _out) +{ + int i; + for(i = 0; i < 4; i++) + _out->v[i] = sqrtf(_in->v[i]); +} + +/******************************************************************************/ + +void SST_Math_Vec4fSqrtLocal(SST_Vec4f* RESTRICT _a) +{ + int i; + for(i = 0; i < 4; i++) + _a->v[i] = sqrtf(_a->v[i]); +} + +/******************************************************************************/ + +float SST_Math_Vec4fMagnitude(const SST_Vec4f* RESTRICT _a) +{ + float sum = 0; + int i; + for(i = 0; i < 4; i++) + sum += _a->v[i] * _a->v[i]; + return sqrtf(sum); +} + +/******************************************************************************/ + +void SST_Math_Vec4fAbs(const SST_Vec4f* RESTRICT _in, SST_Vec4f* RESTRICT _out) +{ + int i; + for(i = 0; i < 4; i++) + _out->v[i] = fabsf(_in->v[i]); +} + +/******************************************************************************/ + +void SST_Math_Vec4fAbsLocal(SST_Vec4f* RESTRICT _a) +{ + int i; + for(i = 0; i < 4; i++) + _a->v[i] = fabsf(_a->v[i]); +} + +/******************************************************************************/ + +void SST_Math_Vec4fNegate(const SST_Vec4f* RESTRICT _in, SST_Vec4f* RESTRICT _out) +{ + int i; + for(i = 0; i < 4; i++) + _out->v[i] = -(_in->v[i]); +} + +/******************************************************************************/ + +void SST_Math_Vec4fNegateLocal(SST_Vec4f* RESTRICT _a) +{ + int i; + for(i = 0; i < 4; i++) + _a->v[i] = -(_a->v[i]); +} + +/******************************************************************************/ + +void SST_Math_Vec4fRecip(const SST_Vec4f* RESTRICT _in, SST_Vec4f* RESTRICT _out) +{ + int i; + for(i = 0; i < 4; i++) + _out->v[i] = 1/(_in->v[i]); +} + +/******************************************************************************/ + +void SST_Math_Vec4fRecipLocal(SST_Vec4f* RESTRICT _a) +{ + int i; + for(i = 0; i < 4; i++) + _a->v[i] = 1/(_a->v[i]); +} + +/******************************************************************************/ + +float SST_Math_Vec4fDot(const SST_Vec4f* RESTRICT _a, const SST_Vec4f* RESTRICT _b) +{ + float sum = 0; + int i; + for(i = 0; i < 4; i++) + sum += _a->v[i] * _b->v[i]; + return sum; +} + +/******************************************************************************/ + +float SST_Math_Vec4fMagnitudeSquared(const SST_Vec4f* RESTRICT _a) +{ + float sum = 0; + int i; + for(i = 0; i < 4; i++) + sum += _a->v[i] * _a->v[i]; + return sum; +} + +/******************************************************************************/ + +void SST_Math_Vec4fProject(const SST_Vec4f* RESTRICT _a, const SST_Vec4f* RESTRICT _b, SST_Vec4f* RESTRICT _out) +{ + float scalar = SST_Math_Vec4fDot(_a,_b) / SST_Math_Vec4fDot(_b,_b); + SST_Math_Vec4fScale(_b, scalar, _out); +} + + +/******************************************************************************/ + +void SST_Math_Vec4fProjectLocal(SST_Vec4f* RESTRICT _a, const SST_Vec4f* RESTRICT _b) +{ + float scalar = SST_Math_Vec4fDot(_a,_b) / SST_Math_Vec4fDot(_b,_b); + SST_Math_Vec4fScale(_b, scalar, _a); +} + + +/******************************************************************************/ + +void SST_Math_Vec4fBias(const SST_Vec4f* RESTRICT _a, const float _bias, SST_Vec4f* RESTRICT _out) +{ + int i; + for(i = 0; i < 4; i++) + _out->v[i] = _a->v[i] + _bias; +} + + +/******************************************************************************/ + +void SST_Math_Vec4fBiasLocal(SST_Vec4f* RESTRICT _a, const float _bias) +{ + int i; + for(i = 0; i < 4; i++) + _a->v[i] += _bias; +} + + +/******************************************************************************/ + diff --git a/libsst-math/SST_Vec4i.c b/libsst-math/SST_Vec4i.c new file mode 100644 index 0000000..4e601a0 --- /dev/null +++ b/libsst-math/SST_Vec4i.c @@ -0,0 +1,391 @@ +/* + AUTOMATICALLY GENERATED FILE - DO NOT EDIT! + Please change MatrixNxN.py and re-run it +*/ +/* Generated with ./VectorN.py n = 4, TYPE = int */ + +#include <float.h> +#include <math.h> +#include <pstdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <SST/SST_Build.h> +#include <SST/SST_Vec4.h> + +void SST_Math_Vec4iAdd(const SST_Vec4i* RESTRICT _A, const SST_Vec4i* RESTRICT _B, SST_Vec4i* RESTRICT _out) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + SST_ASSUME_ALIGNED(_out,16); + + _out->v[0] = _A->v[0] + _B->v[0]; + _out->v[1] = _A->v[1] + _B->v[1]; + _out->v[2] = _A->v[2] + _B->v[2]; + _out->v[3] = _A->v[3] + _B->v[3]; +} + +/******************************************************************************/ + +void SST_Math_Vec4iAddLocal(SST_Vec4i* RESTRICT _A, const SST_Vec4i* RESTRICT _B) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + + _A->v[0] += _B->v[0]; + _A->v[1] += _B->v[1]; + _A->v[2] += _B->v[2]; + _A->v[3] += _B->v[3]; +} + +/******************************************************************************/ + +void SST_Math_Vec4iSubtract(const SST_Vec4i* RESTRICT _A, const SST_Vec4i* RESTRICT _B, SST_Vec4i* RESTRICT _out) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + SST_ASSUME_ALIGNED(_out,16); + + _out->v[0] = _A->v[0] - _B->v[0]; + _out->v[1] = _A->v[1] - _B->v[1]; + _out->v[2] = _A->v[2] - _B->v[2]; + _out->v[3] = _A->v[3] - _B->v[3]; +} + +/******************************************************************************/ + +void SST_Math_Vec4iSubtractLocal(SST_Vec4i* RESTRICT _A, const SST_Vec4i* RESTRICT _B) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + + _A->v[0] -= _B->v[0]; + _A->v[1] -= _B->v[1]; + _A->v[2] -= _B->v[2]; + _A->v[3] -= _B->v[3]; +} + +/******************************************************************************/ + +void SST_Math_Vec4iMultiply(const SST_Vec4i* RESTRICT _A, const SST_Vec4i* RESTRICT _B, SST_Vec4i* RESTRICT _out) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + SST_ASSUME_ALIGNED(_out,16); + + _out->v[0] = _A->v[0] * _B->v[0]; + _out->v[1] = _A->v[1] * _B->v[1]; + _out->v[2] = _A->v[2] * _B->v[2]; + _out->v[3] = _A->v[3] * _B->v[3]; +} + +/******************************************************************************/ + +void SST_Math_Vec4iMultiplyLocal(SST_Vec4i* RESTRICT _A, const SST_Vec4i* RESTRICT _B) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + + _A->v[0] *= _B->v[0]; + _A->v[1] *= _B->v[1]; + _A->v[2] *= _B->v[2]; + _A->v[3] *= _B->v[3]; +} + +/******************************************************************************/ + +void SST_Math_Vec4iScale(const SST_Vec4i* RESTRICT _A, const int k, SST_Vec4i* RESTRICT _out) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_out,16); + + _out->v[0] = _A->v[0] * k; + _out->v[1] = _A->v[1] * k; + _out->v[2] = _A->v[2] * k; + _out->v[3] = _A->v[3] * k; +} + +/******************************************************************************/ + +void SST_Math_Vec4iScaleLocal(SST_Vec4i* RESTRICT _A, const int k) +{ + SST_ASSUME_ALIGNED(_A,16); + + _A->v[0] *= k; + _A->v[1] *= k; + _A->v[2] *= k; + _A->v[3] *= k; +} + +/******************************************************************************/ + +void SST_Math_Vec4iDivide(const SST_Vec4i* RESTRICT _A, const SST_Vec4i* RESTRICT _B, SST_Vec4i* RESTRICT _out) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + SST_ASSUME_ALIGNED(_out,16); + + _out->v[0] = _A->v[0] / _B->v[0]; + _out->v[1] = _A->v[1] / _B->v[1]; + _out->v[2] = _A->v[2] / _B->v[2]; + _out->v[3] = _A->v[3] / _B->v[3]; +} + +/******************************************************************************/ + +void SST_Math_Vec4iDivideLocal(SST_Vec4i* RESTRICT _A, const SST_Vec4i* RESTRICT _B) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + + _A->v[0] /= _B->v[0]; + _A->v[1] /= _B->v[1]; + _A->v[2] /= _B->v[2]; + _A->v[3] /= _B->v[3]; +} + +/******************************************************************************/ + + +/******************************************************************************/ + + +void SST_Math_Vec4iAddMult(const SST_Vec4i* RESTRICT _X, const int _x, const SST_Vec4i* RESTRICT _Y, SST_Vec4i* RESTRICT _Z) +{ + SST_ASSUME_ALIGNED(_X,16); + SST_ASSUME_ALIGNED(_Y,16); + SST_ASSUME_ALIGNED(_Z,16); + /* _Z = _x * _X + _Y */ + _Z->v[0] = _x * _X->v[0] + _Y->v[0]; + _Z->v[1] = _x * _X->v[1] + _Y->v[1]; + _Z->v[2] = _x * _X->v[2] + _Y->v[2]; + _Z->v[3] = _x * _X->v[3] + _Y->v[3]; + +} + + +void SST_Math_Vec4iAddMultLocal(SST_Vec4i* RESTRICT _X, const int _x, const SST_Vec4i* RESTRICT _Y) +{ + SST_ASSUME_ALIGNED(_X,16); + SST_ASSUME_ALIGNED(_Y,16); + /* _X = _x * _X + _Y */ + _X->v[0] = _x * _X->v[0] + _Y->v[0]; + _X->v[1] = _x * _X->v[1] + _Y->v[1]; + _X->v[2] = _x * _X->v[2] + _Y->v[2]; + _X->v[3] = _x * _X->v[3] + _Y->v[3]; + +} + + +/******************************************************************************/ + + +void SST_Math_Vec4iLerp(const SST_Vec4i* RESTRICT _X, const SST_Vec4i* RESTRICT _Y, const int _y, SST_Vec4i* RESTRICT _Z) +{ + SST_ASSUME_ALIGNED(_X,16); + SST_ASSUME_ALIGNED(_Y,16); + SST_ASSUME_ALIGNED(_Z,16); + /* Z = x*X + y*Y */ + _Z->v[0] = _X->v[0] + (_Y->v[0] - _X->v[0]) * _y ; + _Z->v[1] = _X->v[1] + (_Y->v[1] - _X->v[1]) * _y ; + _Z->v[2] = _X->v[2] + (_Y->v[2] - _X->v[2]) * _y ; + _Z->v[3] = _X->v[3] + (_Y->v[3] - _X->v[3]) * _y ; + +} + +void SST_Math_Vec4iLerpLocal(SST_Vec4i* RESTRICT _X, const SST_Vec4i* RESTRICT _Y, const int _y) +{ + SST_ASSUME_ALIGNED(_X,16); + SST_ASSUME_ALIGNED(_Y,16); + /* Z = x*X + y*Y */ + _X->v[0] = _X->v[0] + (_Y->v[0] - _X->v[0]) * _y ; + _X->v[1] = _X->v[1] + (_Y->v[1] - _X->v[1]) * _y ; + _X->v[2] = _X->v[2] + (_Y->v[2] - _X->v[2]) * _y ; + _X->v[3] = _X->v[3] + (_Y->v[3] - _X->v[3]) * _y ; + +} + +/******************************************************************************/ + + +void SST_Math_Vec4iWeightedSum(const SST_Vec4i* RESTRICT _X, const int _x, const SST_Vec4i* RESTRICT _Y, const int _y, SST_Vec4i* RESTRICT _Z) +{ + SST_ASSUME_ALIGNED(_X,16); + SST_ASSUME_ALIGNED(_Y,16); + SST_ASSUME_ALIGNED(_Z,16); + /* Z = x*X + y*Y */ + _Z->v[0] = _x * _X->v[0] + _y * _Y->v[0]; + _Z->v[1] = _x * _X->v[1] + _y * _Y->v[1]; + _Z->v[2] = _x * _X->v[2] + _y * _Y->v[2]; + _Z->v[3] = _x * _X->v[3] + _y * _Y->v[3]; + +} + +void SST_Math_Vec4iWeightedSumLocal(SST_Vec4i* RESTRICT _X, const int _x, const SST_Vec4i* RESTRICT _Y, const int _y) +{ + SST_ASSUME_ALIGNED(_X,16); + SST_ASSUME_ALIGNED(_Y,16); + /* Z = x*X + y*Y */ + _X->v[0] = _x * _X->v[0] + _y * _Y->v[0]; + _X->v[1] = _x * _X->v[1] + _y * _Y->v[1]; + _X->v[2] = _x * _X->v[2] + _y * _Y->v[2]; + _X->v[3] = _x * _X->v[3] + _y * _Y->v[3]; + +} + +/******************************************************************************/ + +bool SST_Math_Vec4iEquals(const SST_Vec4i* RESTRICT _a, const SST_Vec4i* RESTRICT _b) +{ + int i; + bool returncode; + SST_ASSUME_ALIGNED(_a,16); + SST_ASSUME_ALIGNED(_b,16); + returncode = 1; + for(i=0;i<4;i++) + { + returncode = (_a->v[i]==_b->v[i]) && returncode; + } + return returncode; +} + + +/******************************************************************************/ + +int SST_Math_Vec4iMax(const SST_Vec4i* RESTRICT _a) +{ + int tmp = _a->v[0]; + if(tmp < _a->v[1]) tmp = _a->v[1]; + if(tmp < _a->v[2]) tmp = _a->v[2]; + if(tmp < _a->v[3]) tmp = _a->v[3]; + + return tmp; +} + +/******************************************************************************/ + +int SST_Math_Vec4iMin(const SST_Vec4i* RESTRICT _a) +{ + int tmp = _a->v[0]; + if(tmp > _a->v[1]) tmp = _a->v[1]; + if(tmp > _a->v[2]) tmp = _a->v[2]; + if(tmp > _a->v[3]) tmp = _a->v[3]; + + return tmp; +} + +/******************************************************************************/ + +void SST_Math_Vec4iAbs(const SST_Vec4i* RESTRICT _in, SST_Vec4i* RESTRICT _out) +{ + int i; + for(i = 0; i < 4; i++) + _out->v[i] = abs(_in->v[i]); +} + +/******************************************************************************/ + +void SST_Math_Vec4iAbsLocal(SST_Vec4i* RESTRICT _a) +{ + int i; + for(i = 0; i < 4; i++) + _a->v[i] = abs(_a->v[i]); +} + +/******************************************************************************/ + +void SST_Math_Vec4iNegate(const SST_Vec4i* RESTRICT _in, SST_Vec4i* RESTRICT _out) +{ + int i; + for(i = 0; i < 4; i++) + _out->v[i] = -(_in->v[i]); +} + +/******************************************************************************/ + +void SST_Math_Vec4iNegateLocal(SST_Vec4i* RESTRICT _a) +{ + int i; + for(i = 0; i < 4; i++) + _a->v[i] = -(_a->v[i]); +} + +/******************************************************************************/ + +void SST_Math_Vec4iRecip(const SST_Vec4i* RESTRICT _in, SST_Vec4i* RESTRICT _out) +{ + int i; + for(i = 0; i < 4; i++) + _out->v[i] = 1/(_in->v[i]); +} + +/******************************************************************************/ + +void SST_Math_Vec4iRecipLocal(SST_Vec4i* RESTRICT _a) +{ + int i; + for(i = 0; i < 4; i++) + _a->v[i] = 1/(_a->v[i]); +} + +/******************************************************************************/ + +int SST_Math_Vec4iDot(const SST_Vec4i* RESTRICT _a, const SST_Vec4i* RESTRICT _b) +{ + int sum = 0; + int i; + for(i = 0; i < 4; i++) + sum += _a->v[i] * _b->v[i]; + return sum; +} + +/******************************************************************************/ + +int SST_Math_Vec4iMagnitudeSquared(const SST_Vec4i* RESTRICT _a) +{ + int sum = 0; + int i; + for(i = 0; i < 4; i++) + sum += _a->v[i] * _a->v[i]; + return sum; +} + +/******************************************************************************/ + +void SST_Math_Vec4iProject(const SST_Vec4i* RESTRICT _a, const SST_Vec4i* RESTRICT _b, SST_Vec4i* RESTRICT _out) +{ + int scalar = SST_Math_Vec4iDot(_a,_b) / SST_Math_Vec4iDot(_b,_b); + SST_Math_Vec4iScale(_b, scalar, _out); +} + + +/******************************************************************************/ + +void SST_Math_Vec4iProjectLocal(SST_Vec4i* RESTRICT _a, const SST_Vec4i* RESTRICT _b) +{ + int scalar = SST_Math_Vec4iDot(_a,_b) / SST_Math_Vec4iDot(_b,_b); + SST_Math_Vec4iScale(_b, scalar, _a); +} + + +/******************************************************************************/ + +void SST_Math_Vec4iBias(const SST_Vec4i* RESTRICT _a, const int _bias, SST_Vec4i* RESTRICT _out) +{ + int i; + for(i = 0; i < 4; i++) + _out->v[i] = _a->v[i] + _bias; +} + + +/******************************************************************************/ + +void SST_Math_Vec4iBiasLocal(SST_Vec4i* RESTRICT _a, const int _bias) +{ + int i; + for(i = 0; i < 4; i++) + _a->v[i] += _bias; +} + + +/******************************************************************************/ + diff --git a/libsst-math/SST_Vec4u.c b/libsst-math/SST_Vec4u.c new file mode 100644 index 0000000..53101e9 --- /dev/null +++ b/libsst-math/SST_Vec4u.c @@ -0,0 +1,337 @@ +/* + AUTOMATICALLY GENERATED FILE - DO NOT EDIT! + Please change MatrixNxN.py and re-run it +*/ +/* Generated with ./VectorN.py n = 4, TYPE = unsigned int */ + +#include <float.h> +#include <math.h> +#include <pstdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <SST/SST_Build.h> +#include <SST/SST_Vec4.h> + +void SST_Math_Vec4uAdd(const SST_Vec4u* RESTRICT _A, const SST_Vec4u* RESTRICT _B, SST_Vec4u* RESTRICT _out) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + SST_ASSUME_ALIGNED(_out,16); + + _out->v[0] = _A->v[0] + _B->v[0]; + _out->v[1] = _A->v[1] + _B->v[1]; + _out->v[2] = _A->v[2] + _B->v[2]; + _out->v[3] = _A->v[3] + _B->v[3]; +} + +/******************************************************************************/ + +void SST_Math_Vec4uAddLocal(SST_Vec4u* RESTRICT _A, const SST_Vec4u* RESTRICT _B) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + + _A->v[0] += _B->v[0]; + _A->v[1] += _B->v[1]; + _A->v[2] += _B->v[2]; + _A->v[3] += _B->v[3]; +} + +/******************************************************************************/ + +void SST_Math_Vec4uSubtract(const SST_Vec4u* RESTRICT _A, const SST_Vec4u* RESTRICT _B, SST_Vec4u* RESTRICT _out) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + SST_ASSUME_ALIGNED(_out,16); + + _out->v[0] = _A->v[0] - _B->v[0]; + _out->v[1] = _A->v[1] - _B->v[1]; + _out->v[2] = _A->v[2] - _B->v[2]; + _out->v[3] = _A->v[3] - _B->v[3]; +} + +/******************************************************************************/ + +void SST_Math_Vec4uSubtractLocal(SST_Vec4u* RESTRICT _A, const SST_Vec4u* RESTRICT _B) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + + _A->v[0] -= _B->v[0]; + _A->v[1] -= _B->v[1]; + _A->v[2] -= _B->v[2]; + _A->v[3] -= _B->v[3]; +} + +/******************************************************************************/ + +void SST_Math_Vec4uMultiply(const SST_Vec4u* RESTRICT _A, const SST_Vec4u* RESTRICT _B, SST_Vec4u* RESTRICT _out) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + SST_ASSUME_ALIGNED(_out,16); + + _out->v[0] = _A->v[0] * _B->v[0]; + _out->v[1] = _A->v[1] * _B->v[1]; + _out->v[2] = _A->v[2] * _B->v[2]; + _out->v[3] = _A->v[3] * _B->v[3]; +} + +/******************************************************************************/ + +void SST_Math_Vec4uMultiplyLocal(SST_Vec4u* RESTRICT _A, const SST_Vec4u* RESTRICT _B) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + + _A->v[0] *= _B->v[0]; + _A->v[1] *= _B->v[1]; + _A->v[2] *= _B->v[2]; + _A->v[3] *= _B->v[3]; +} + +/******************************************************************************/ + +void SST_Math_Vec4uScale(const SST_Vec4u* RESTRICT _A, const unsigned int k, SST_Vec4u* RESTRICT _out) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_out,16); + + _out->v[0] = _A->v[0] * k; + _out->v[1] = _A->v[1] * k; + _out->v[2] = _A->v[2] * k; + _out->v[3] = _A->v[3] * k; +} + +/******************************************************************************/ + +void SST_Math_Vec4uScaleLocal(SST_Vec4u* RESTRICT _A, const unsigned int k) +{ + SST_ASSUME_ALIGNED(_A,16); + + _A->v[0] *= k; + _A->v[1] *= k; + _A->v[2] *= k; + _A->v[3] *= k; +} + +/******************************************************************************/ + +void SST_Math_Vec4uDivide(const SST_Vec4u* RESTRICT _A, const SST_Vec4u* RESTRICT _B, SST_Vec4u* RESTRICT _out) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + SST_ASSUME_ALIGNED(_out,16); + + _out->v[0] = _A->v[0] / _B->v[0]; + _out->v[1] = _A->v[1] / _B->v[1]; + _out->v[2] = _A->v[2] / _B->v[2]; + _out->v[3] = _A->v[3] / _B->v[3]; +} + +/******************************************************************************/ + +void SST_Math_Vec4uDivideLocal(SST_Vec4u* RESTRICT _A, const SST_Vec4u* RESTRICT _B) +{ + SST_ASSUME_ALIGNED(_A,16); + SST_ASSUME_ALIGNED(_B,16); + + _A->v[0] /= _B->v[0]; + _A->v[1] /= _B->v[1]; + _A->v[2] /= _B->v[2]; + _A->v[3] /= _B->v[3]; +} + +/******************************************************************************/ + + +/******************************************************************************/ + + +void SST_Math_Vec4uAddMult(const SST_Vec4u* RESTRICT _X, const unsigned int _x, const SST_Vec4u* RESTRICT _Y, SST_Vec4u* RESTRICT _Z) +{ + SST_ASSUME_ALIGNED(_X,16); + SST_ASSUME_ALIGNED(_Y,16); + SST_ASSUME_ALIGNED(_Z,16); + /* _Z = _x * _X + _Y */ + _Z->v[0] = _x * _X->v[0] + _Y->v[0]; + _Z->v[1] = _x * _X->v[1] + _Y->v[1]; + _Z->v[2] = _x * _X->v[2] + _Y->v[2]; + _Z->v[3] = _x * _X->v[3] + _Y->v[3]; + +} + + +void SST_Math_Vec4uAddMultLocal(SST_Vec4u* RESTRICT _X, const unsigned int _x, const SST_Vec4u* RESTRICT _Y) +{ + SST_ASSUME_ALIGNED(_X,16); + SST_ASSUME_ALIGNED(_Y,16); + /* _X = _x * _X + _Y */ + _X->v[0] = _x * _X->v[0] + _Y->v[0]; + _X->v[1] = _x * _X->v[1] + _Y->v[1]; + _X->v[2] = _x * _X->v[2] + _Y->v[2]; + _X->v[3] = _x * _X->v[3] + _Y->v[3]; + +} + + +/******************************************************************************/ + + +void SST_Math_Vec4uLerp(const SST_Vec4u* RESTRICT _X, const SST_Vec4u* RESTRICT _Y, const unsigned int _y, SST_Vec4u* RESTRICT _Z) +{ + SST_ASSUME_ALIGNED(_X,16); + SST_ASSUME_ALIGNED(_Y,16); + SST_ASSUME_ALIGNED(_Z,16); + /* Z = x*X + y*Y */ + _Z->v[0] = _X->v[0] + (_Y->v[0] - _X->v[0]) * _y ; + _Z->v[1] = _X->v[1] + (_Y->v[1] - _X->v[1]) * _y ; + _Z->v[2] = _X->v[2] + (_Y->v[2] - _X->v[2]) * _y ; + _Z->v[3] = _X->v[3] + (_Y->v[3] - _X->v[3]) * _y ; + +} + +void SST_Math_Vec4uLerpLocal(SST_Vec4u* RESTRICT _X, const SST_Vec4u* RESTRICT _Y, const unsigned int _y) +{ + SST_ASSUME_ALIGNED(_X,16); + SST_ASSUME_ALIGNED(_Y,16); + /* Z = x*X + y*Y */ + _X->v[0] = _X->v[0] + (_Y->v[0] - _X->v[0]) * _y ; + _X->v[1] = _X->v[1] + (_Y->v[1] - _X->v[1]) * _y ; + _X->v[2] = _X->v[2] + (_Y->v[2] - _X->v[2]) * _y ; + _X->v[3] = _X->v[3] + (_Y->v[3] - _X->v[3]) * _y ; + +} + +/******************************************************************************/ + + +void SST_Math_Vec4uWeightedSum(const SST_Vec4u* RESTRICT _X, const unsigned int _x, const SST_Vec4u* RESTRICT _Y, const unsigned int _y, SST_Vec4u* RESTRICT _Z) +{ + SST_ASSUME_ALIGNED(_X,16); + SST_ASSUME_ALIGNED(_Y,16); + SST_ASSUME_ALIGNED(_Z,16); + /* Z = x*X + y*Y */ + _Z->v[0] = _x * _X->v[0] + _y * _Y->v[0]; + _Z->v[1] = _x * _X->v[1] + _y * _Y->v[1]; + _Z->v[2] = _x * _X->v[2] + _y * _Y->v[2]; + _Z->v[3] = _x * _X->v[3] + _y * _Y->v[3]; + +} + +void SST_Math_Vec4uWeightedSumLocal(SST_Vec4u* RESTRICT _X, const unsigned int _x, const SST_Vec4u* RESTRICT _Y, const unsigned int _y) +{ + SST_ASSUME_ALIGNED(_X,16); + SST_ASSUME_ALIGNED(_Y,16); + /* Z = x*X + y*Y */ + _X->v[0] = _x * _X->v[0] + _y * _Y->v[0]; + _X->v[1] = _x * _X->v[1] + _y * _Y->v[1]; + _X->v[2] = _x * _X->v[2] + _y * _Y->v[2]; + _X->v[3] = _x * _X->v[3] + _y * _Y->v[3]; + +} + +/******************************************************************************/ + +bool SST_Math_Vec4uEquals(const SST_Vec4u* RESTRICT _a, const SST_Vec4u* RESTRICT _b) +{ + int i; + bool returncode; + SST_ASSUME_ALIGNED(_a,16); + SST_ASSUME_ALIGNED(_b,16); + returncode = 1; + for(i=0;i<4;i++) + { + returncode = (_a->v[i]==_b->v[i]) && returncode; + } + return returncode; +} + + +/******************************************************************************/ + +unsigned int SST_Math_Vec4uMax(const SST_Vec4u* RESTRICT _a) +{ + unsigned int tmp = _a->v[0]; + if(tmp < _a->v[1]) tmp = _a->v[1]; + if(tmp < _a->v[2]) tmp = _a->v[2]; + if(tmp < _a->v[3]) tmp = _a->v[3]; + + return tmp; +} + +/******************************************************************************/ + +unsigned int SST_Math_Vec4uMin(const SST_Vec4u* RESTRICT _a) +{ + unsigned int tmp = _a->v[0]; + if(tmp > _a->v[1]) tmp = _a->v[1]; + if(tmp > _a->v[2]) tmp = _a->v[2]; + if(tmp > _a->v[3]) tmp = _a->v[3]; + + return tmp; +} + +/******************************************************************************/ + +unsigned int SST_Math_Vec4uDot(const SST_Vec4u* RESTRICT _a, const SST_Vec4u* RESTRICT _b) +{ + unsigned int sum = 0; + int i; + for(i = 0; i < 4; i++) + sum += _a->v[i] * _b->v[i]; + return sum; +} + +/******************************************************************************/ + +unsigned int SST_Math_Vec4uMagnitudeSquared(const SST_Vec4u* RESTRICT _a) +{ + unsigned int sum = 0; + int i; + for(i = 0; i < 4; i++) + sum += _a->v[i] * _a->v[i]; + return sum; +} + +/******************************************************************************/ + +void SST_Math_Vec4uProject(const SST_Vec4u* RESTRICT _a, const SST_Vec4u* RESTRICT _b, SST_Vec4u* RESTRICT _out) +{ + unsigned int scalar = SST_Math_Vec4uDot(_a,_b) / SST_Math_Vec4uDot(_b,_b); + SST_Math_Vec4uScale(_b, scalar, _out); +} + + +/******************************************************************************/ + +void SST_Math_Vec4uProjectLocal(SST_Vec4u* RESTRICT _a, const SST_Vec4u* RESTRICT _b) +{ + unsigned int scalar = SST_Math_Vec4uDot(_a,_b) / SST_Math_Vec4uDot(_b,_b); + SST_Math_Vec4uScale(_b, scalar, _a); +} + + +/******************************************************************************/ + +void SST_Math_Vec4uBias(const SST_Vec4u* RESTRICT _a, const unsigned int _bias, SST_Vec4u* RESTRICT _out) +{ + int i; + for(i = 0; i < 4; i++) + _out->v[i] = _a->v[i] + _bias; +} + + +/******************************************************************************/ + +void SST_Math_Vec4uBiasLocal(SST_Vec4u* RESTRICT _a, const unsigned int _bias) +{ + int i; + for(i = 0; i < 4; i++) + _a->v[i] += _bias; +} + + +/******************************************************************************/ + diff --git a/libsst-math/SST_VectorN.c b/libsst-math/SST_VectorN.c new file mode 100644 index 0000000..812e5ea --- /dev/null +++ b/libsst-math/SST_VectorN.c @@ -0,0 +1,452 @@ +#include <SST/SST_VectorN.h> +#include <math.h> +#include <string.h> + +float SST_VectorNf_Magnitude(const int N, const float* _in) +{ + int i; + float sum = 0.f; + for(i = 0; i < N; i++) + sum += _in[i] * _in[i]; + return sqrt(sum); +} + +float SST_VectorNf_MagnitudeSquared(const int N, const float* _in) +{ + int i; + float sum = 0.f; + for(i = 0; i < N; i++) + sum += _in[i] * _in[i]; + return sum; +} + +float SST_VectorNf_L1Norm(const int N, const float* _in) +{ + int i; + float sum = 0.f; + for(i = 0; i < N; i++) + sum += _in[i]; + return sum; +} + +float SST_VectorNf_Dot(const int N, const float* _a, const float* _b) +{ + int i; + float sum = 0.f; + for(i = 0; i < N; i++) + sum += _a[i]*_b[i]; + return sum; +} + +float* SST_VectorNf_Normalize(const int N, const float* _in, float* _out) +{ + float scalar = 1.f/SST_VectorNf_Magnitude(N,_in); + return SST_VectorNf_Scale(N,_in,scalar,_out); +} + +float* SST_VectorNf_NormalizeLocal(const int N, float* _inout) +{ + float scalar = 1.f/SST_VectorNf_Magnitude(N,_inout); + return SST_VectorNf_ScaleLocal(N,_inout,scalar); +} + +float* SST_VectorNf_Add(const int N, const float* _a, const float* _b, float* _out) +{ + int i; + for(i = 0; i < N; i++) + _out[i] = _a[i]+_b[i]; + return _out; +} + +float* SST_VectorNf_Subtract(const int N, const float* _a, const float* _b, float* _out) +{ + int i; + for(i = 0; i < N; i++) + _out[i] = _a[i]-_b[i]; + return _out; +} + +float* SST_VectorNf_AddLocal(const int N, float* _a, const float* _b) +{ + int i; + for(i = 0; i < N; i++) + _a[i]+=_b[i]; + return _a; +} + +float* SST_VectorNf_Cross(const int N, const float* _a, const float* _b, float* _out) +{ + if(N==2) { + _out[0] = _a[0]*_b[1] - _a[1]*_b[0]; + } else if(N==3) { + _out[0] = _a[1]*_b[2] - _a[2]*_b[1]; + _out[1] =-(_a[0]*_b[2] - _a[2]*_b[0]); + _out[2] = _a[0]*_b[1] - _a[1]*_b[0]; + + } else { + /* do nothing */ + } + return _out; +} + +float* SST_VectorNf_CrossLocal(const int N, float* _a, const float* _b) +{ + if(N==2) { + _a[0] = _a[0]*_b[1] - _a[1]*_b[0]; + } else if(N==3) { + float tmp[3] = { + + _a[1]*_b[2] - _a[2]*_b[1], + -(_a[0]*_b[2] - _a[2]*_b[0]), + _a[0]*_b[1] - _a[1]*_b[0]}; + + _a[0]=tmp[0]; + _a[1]=tmp[1]; + _a[2]=tmp[2]; + + } else { + /* do nothing */ + } + return _a; +} + +float* SST_VectorNf_Scale(const int N, const float* _a, const float _scale, float* _out) +{ + int i; + for(i = 0; i < N; i++) + _out[i]= _scale * _a[i]; + return _out; +} + +float* SST_VectorNf_ScaleLocal(const int N, float* _a, const float _scale) +{ + int i; + for(i = 0; i < N; i++) + _a[i]*=_scale; + return _a; +} + +float* SST_VectorNf_RotateAbout(const int N, const float* _a, const float* _about,float _theta, float* _out) +{ + if(N==2) { + _out[0] = _a[0]; + _out[1] = _a[1]; + + } else if(N==3){ + float tmp[4] = {_about[0],_about[1],_about[2],0}; + float scalar = (1.0-cos(_theta)) * SST_VectorNf_Dot(3,_about,_a); + SST_VectorNf_Scale(3,tmp,scalar,_out); + SST_VectorNf_Cross(3,_about,_a,tmp); + SST_VectorNf_ScaleLocal(3,tmp,sin(_theta)); + SST_VectorNf_AddLocal(3,_out,tmp); + SST_VectorNf_Scale(3,_a,cos(_theta),tmp); + SST_VectorNf_AddLocal(3,_out,tmp); + } else { + int i; + for(i = 0; i < N; i++) + _out[i] = _a[i]; + } + return _out; +} + +float* SST_VectorNf_Project(const int N, const float* _a, const float* _b, float* _out) +{ + float scalar = SST_VectorNf_Dot(N,_a,_b) / SST_VectorNf_Dot(N,_b,_b); + SST_VectorNf_Scale(N, _b, scalar, _out); + return _out; +} + +float* SST_VectorNf_ProjectLocal(const int N, float* _a, const float* _b) +{ + float scalar = SST_VectorNf_Dot(N,_a,_b) / SST_VectorNf_Dot(N,_b,_b); + SST_VectorNf_Scale(N, _b, scalar, _a); + return _a; +} + +float* SST_VectorNf_Bias(const int N, const float* a, const float bias, float* out) +{ + int i; + for(i = 0; i < N; i++) + out[i] = a[i]+bias; + return out; +} + +float* SST_VectorNf_RotateAboutLocal(const int N, float* _a, const float* _about,float _theta) +{ + int i; + float tmp2[N]; + if(N==2) { + tmp2[0] = _a[0]; + tmp2[1] = _a[1]; + } else if(N==3){ + float tmp[4] = {_about[0],_about[1],_about[2],0}; + float scalar = (1.0-cos(_theta)) * SST_VectorNf_Dot(3,_about,_a); + SST_VectorNf_Scale(3,tmp,scalar,tmp2); + SST_VectorNf_Cross(3,_about,_a,tmp); + SST_VectorNf_ScaleLocal(3,tmp,sin(_theta)); + SST_VectorNf_AddLocal(3,tmp2,tmp); + SST_VectorNf_Scale(3,_a,cos(_theta),tmp); + SST_VectorNf_AddLocal(3,tmp2,tmp); + } else { + for(i = 0; i < N; i++) + tmp2[i] = _a[i]; + } + for(i = 0; i < N; i++) + _a[i] = tmp2[i]; + + return _a; +} + +double SST_VectorNd_Magnitude(const int N, const double* _in) +{ + int i; + double sum = 0.0; + for(i = 0; i < N; i++) + sum += _in[i] * _in[i]; + return sqrt(sum); +} + +double SST_VectorNd_MagnitudeSquared(const int N, const double* _in) +{ + int i; + double sum = 0.0; + for(i = 0; i < N; i++) + sum += _in[i] * _in[i]; + return sum; +} + +double SST_VectorNd_L1Norm(const int N, const double* _in) +{ + int i; + double sum = 0.0; + for(i = 0; i < N; i++) + sum += _in[i]; + return sum; +} + +double SST_VectorNd_Dot(const int N, const double* _a, const double* _b) +{ + int i; + double sum = 0.0; + for(i = 0; i < N; i++) + sum += _a[i]*_b[i]; + return sum; +} + +double* SST_VectorNd_Normalize(const int N, const double* _in, double* _out) +{ + double scalar = 1.0/SST_VectorNd_Magnitude(N,_in); + return SST_VectorNd_Scale(N,_in,scalar,_out); +} + +double* SST_VectorNd_NormalizeLocal(const int N, double* _inout) +{ + double scalar = 1.0/SST_VectorNd_Magnitude(N,_inout); + return SST_VectorNd_ScaleLocal(N,_inout,scalar); +} + +double* SST_VectorNd_Add(const int N, const double* _a, const double* _b, double* _out) +{ + int i; + for(i = 0; i < N; i++) + _out[i] = _a[i]+_b[i]; + return _out; +} + +double* SST_VectorNd_Subtract(const int N, const double* _a, const double* _b, double* _out) +{ + int i; + for(i = 0; i < N; i++) + _out[i] = _a[i]-_b[i]; + return _out; +} + +double* SST_VectorNd_AddLocal(const int N, double* _a, const double* _b) +{ + int i; + for(i = 0; i < N; i++) + _a[i]+=_b[i]; + return _a; +} + +double* SST_VectorNd_Cross(const int N, const double* _a, const double* _b, double* _out) +{ + if(N==2) { + _out[0] = _a[0]*_b[1] - _a[1]*_b[0]; + } else if(N==3) { + _out[0] = _a[1]*_b[2] - _a[2]*_b[1]; + _out[1] =-(_a[0]*_b[2] - _a[2]*_b[0]); + _out[2] = _a[0]*_b[1] - _a[1]*_b[0]; + } else { + /* do nothing */ + } + return _out; +} + +double* SST_VectorNd_CrossLocal(const int N, double* _a, const double* _b) +{ + if(N==2) { + _a[0] = _a[0]*_b[1] - _a[1]*_b[0]; + } else if(N==3) { + double tmp[3] = { + _a[1]*_b[2] - _a[2]*_b[1], + -(_a[0]*_b[2] - _a[2]*_b[0]), + _a[0]*_b[1] - _a[1]*_b[0]}; + _a[0]=tmp[0]; + _a[1]=tmp[1]; + _a[2]=tmp[2]; + } else { + /* do nothing */ + } + return _a; +} + +double* SST_VectorNd_Scale(const int N, const double* _a, const double _scale, double* _out) +{ + int i; + for(i = 0; i < N; i++) + _out[i]= _scale * _a[i]; + return _out; +} + +double* SST_VectorNd_ScaleLocal(const int N, double* _a, const double _scale) +{ + int i; + for(i = 0; i < N; i++) + _a[i]*=_scale; + return _a; +} + +double* SST_VectorNd_RotateAbout(const int N, const double* _a, const double* _about,double _theta, double* _out) +{ + if(N==3) { + double tmp[4] = {_about[0],_about[1],_about[2],0}; + double scalar = (1.0-cos(_theta)) * SST_VectorNd_Dot(3,_about,_a); + SST_VectorNd_Scale(3,tmp,scalar,_out); + SST_VectorNd_Cross(3,_about,_a,tmp); + SST_VectorNd_ScaleLocal(3,tmp,sin(_theta)); + SST_VectorNd_AddLocal(3,_out,tmp); + SST_VectorNd_Scale(3,_a,cos(_theta),tmp); + SST_VectorNd_AddLocal(3,_out,tmp); + } else { + memset(_out,0,N*sizeof(double)); + } + return _out; +} + +double* SST_VectorNd_RotateAboutLocal(const int N, double* _a, const double* _about,double _theta) +{ + int i; + double tmp2[N]; + if(N==2) { + tmp2[0] = _a[0]; + tmp2[1] = _a[1]; + } else if(N==3){ + double tmp[4] = {_about[0],_about[1],_about[2],0}; + double scalar = (1.0-cos(_theta)) * SST_VectorNd_Dot(3,_about,_a); + SST_VectorNd_Scale(3,tmp,scalar,tmp2); + SST_VectorNd_Cross(3,_about,_a,tmp); + SST_VectorNd_ScaleLocal(3,tmp,sin(_theta)); + SST_VectorNd_AddLocal(3,tmp2,tmp); + SST_VectorNd_Scale(3,_a,cos(_theta),tmp); + SST_VectorNd_AddLocal(3,tmp2,tmp); + } else { + for(i = 0; i < N; i++) + tmp2[i] = _a[i]; + } + for(i = 0; i < N; i++) + _a[i] = tmp2[i]; + + return _a; +} + +int SST_VectorNi_MagnitudeSquared(const int N, const int* _in) +{ + int i; + int sum = 0; + for(i = 0; i < N; i++) + sum=_in[i]*_in[i]; + return sum; +} + +int SST_VectorNi_Dot(const int N, const int* _a, const int* _b) +{ + int i; + int sum = 0; + for(i = 0; i < N; i++) + sum=_a[i]*_b[i]; + return sum; +} + +int* SST_VectorNi_Add(const int N, const int* _a, const int* _b, int* _out) +{ + int i; + for(i = 0; i < N; i++) + _out[i]=_a[i]+_b[i]; + return _out; +} + +int* SST_VectorNi_Subtract(const int N, const int* _a, const int* _b, int* _out) +{ + int i; + for(i = 0; i < N; i++) + _out[i]=_a[i]-_b[i]; + return _out; +} + +int* SST_VectorNi_AddLocal(const int N, int* _a, const int* _b) +{ + int i; + for(i = 0; i < N; i++) + _a[i]+=_b[i]; + return _a; +} + +int* SST_VectorNi_Cross(const int N, const int* _a, const int* _b, int* _out) +{ + if(N==2) { + _out[0] = _a[0]*_b[1] - _a[1]*_b[0]; + } else if(N==3) { + _out[0] = _a[1]*_b[2] - _a[2]*_b[1]; + _out[1] =-(_a[0]*_b[2] - _a[2]*_b[0]); + _out[2] = _a[0]*_b[1] - _a[1]*_b[0]; + + } else { + /* do nothing */ + } + return _out; +} + +int* SST_VectorNi_CrossLocal(const int N, int* _a, const int* _b) +{ + if(N==2) { + _a[0] = _a[0]*_b[1] - _a[1]*_b[0]; + } else if(N==3) { + int tmp[3] = { + _a[1]*_b[2] - _a[2]*_b[1], + -(_a[0]*_b[2] - _a[2]*_b[0]), + _a[0]*_b[1] - _a[1]*_b[0]}; + _a[0]=tmp[0]; + _a[1]=tmp[1]; + _a[2]=tmp[2]; + } else { + /* do nothing */ + } + return _a; +} + +int* SST_VectorNi_Scale(const int N, const int* _a, const int _scale, int* _out) +{ + int i; + for(i = 0; i < N; i++) + _out[i] = _scale * _a[i]; + return _out; +} + +int* SST_VectorNi_ScaleLocal(const int N, int* _a, const int _scale) +{ + int i; + for(i = 0; i < N; i++) + _a[i]*=_scale; + return _a; +} diff --git a/libsst-math/VectorN.py b/libsst-math/VectorN.py new file mode 100644 index 0000000..b29dfe4 --- /dev/null +++ b/libsst-math/VectorN.py @@ -0,0 +1,1589 @@ +#!/usr/bin/env python +from scipy import * +from numpy import * +import re +import sys + +if len(sys.argv) < 3: + sys.exit("Please provide both the number of elements (2-4) and the type of element (float, int, double) at the command line") + +if len(sys.argv) == 3: + DEBUG_PRINT = False + CODE_TYPE = '' + +else: + DEBUG_PRINT = True + CODE_TYPE = sys.argv[3] + +N = int(sys.argv[1]) +TYPE = sys.argv[2] + +COMMBREAK = '/******************************************************************************/' + +''' +/* Vec3f (3D float Vector) Routines */ + +/* f:R3 -> R3 */ +void SST_Math_Vec3fAbs(const SST_Vec3f* a, SST_Vec3f* out); +void SST_Math_Vec3fAbsLocal(SST_Vec3f* a); +void SST_Math_Vec3fNegate(const SST_Vec3f* a, SST_Vec3f* out); +void SST_Math_Vec3fNegateLocal(const SST_Vec3f* a); +void SST_Math_Vec3fNormalize(const SST_Vec3f* a, SST_Vec3f* out); +void SST_Math_Vec3fNormalizeLocal(SST_Vec3f* a); +void SST_Math_Vec3fRecip(const SST_Vec3f* a, SST_Vec3f* out); +void SST_Math_Vec3fRecipLocal(SST_Vec3f* a); +void SST_Math_Vec3fRecipEst(const SST_Vec3f* a, SST_Vec3f* out); +void SST_Math_Vec3fRecipEstLocal(SST_Vec3f* a); +void SST_Math_Vec3fRecipSqrt(const SST_Vec3f* a, SST_Vec3f* out); +void SST_Math_Vec3fRecipSqrtLocal(SST_Vec3f* a); +void SST_Math_Vec3fRecipSqrtEst(const SST_Vec3f* a, SST_Vec3f* out); +void SST_Math_Vec3fRecipSqrtEstLocal(const SST_Vec3f* a); +void SST_Math_Vec3fSqrt(const SST_Vec3f* a, SST_Vec3f* out); +void SST_Math_Vec3fSqrtLocal(SST_Vec3f* a); +void SST_Math_Vec3fSqrtEst(const SST_Vec3f* a, SST_Vec3f* out); +void SST_Math_Vec3fSqrtEstLocal(SST_Vec3f* a); + +/* f:R3 -> R */ +float SST_Math_Vec3fL1Norm(const SST_Vec3f* a); +float SST_Math_Vec3fMagnitude(const SST_Vec3f* a); +float SST_Math_Vec3fMagnitudeSquared(const SST_Vec3f* a); +float SST_Math_Vec3fRecipMagnitude(const SST_Vec3f* a); + +/* f:R3xR3 -> R */ +float SST_Vector3f_Dot(const SST_Vec3f* a, const SST_Vec3f* b); + +/* f:R3xR3 -> R3 */ +void SST_Math_Vec3fAdd(const SST_Vec3f* a, const SST_Vec3f* b, SST_Vec3f* out); +void SST_Math_Vec3fAddLocal(SST_Vec3f* a, const SST_Vec3f* b); +void SST_Math_Vec3fCross(const SST_Vec3f* a, const SST_Vec3f* b, SST_Vec3f* out); +void SST_Math_Vec3fCrossLocal(SST_Vec3f* a, const SST_Vec3f* b); +void SST_Math_Vec3fDivide(const SST_Vec3f* a, const SST_Vec3f* b, SST_Vec3f* out); +void SST_Math_Vec3fDivideLocal(SST_Vec3f* a, const SST_Vec3f* b); +void SST_Math_Vec3fMultiply(const SST_Vec3f* a, const SST_Vec3f* b, SST_Vec3f* out); +void SST_Math_Vec3fMultiplyLocal(SST_Vec3f* a, const SST_Vec3f* b); +void SST_Math_Vec3fProject(const SST_Vec3f* a, const SST_Vec3f* b, SST_Vec3f* out); +void SST_Math_Vec3fProjectLocal(SST_Vec3f* a, const SST_Vec3f* b); +void SST_Math_Vec3fSubtract(const SST_Vec3f* a, const SST_Vec3f* b, SST_Vec3f* out); +void SST_Math_Vec3fSubtractLocal(SST_Vec3f* a, const SST_Vec3f* b); + +/* f:R3xR -> R3 */ +void SST_Math_Vec3fBias(const SST_Vec3f* a, const float bias, SST_Vec3f* out); +void SST_Math_Vec3fBiasLocal(SST_Vec3f* a, const float bias); +void SST_Math_Vec3fScale(const SST_Vec3f* a, const float scale, SST_Vec3f* out); +void SST_Math_Vec3fScaleLocal(SST_Vec3f* a, const float scale); + +/* f:R3xR3xR -> R3 */ +void SST_Math_Vec3fRotate(const SST_Vec3f* a, const SST_Vec3f* axis, float theta, SST_Vec3f* out); +void SST_Math_Vec3fRotateLocal(SST_Vec3f* a, const SST_Vec3f* axis, float theta);''' + + +#C function table +fabs = {'double' : 'fabs', 'float' : 'fabsf', 'int' : 'abs', 'unsigned int' : 'abs'} +cstyle = {'double' : '%24.16f', 'float' : '%ff', 'int' : '%d' , 'unsigned int' : '%u' } +fp_epsilon = {'double' : 'DBL_EPSILON' , 'float' : 'FLT_EPSILON' , 'int' : '0', 'unsigned int' : '0'} +size_t = {'double' : 64, 'float' : 32, 'int' : 32, 'unsigned int' : 32} +DTYPE = {'double' : float64 , 'float' : float32 , 'int' : int32 , 'unsigned int' : uint32} +COS = {'double' : 'cos', 'float' : 'cosf', 'int' : '(int)cosf', 'unsigned int' : None} +SIN = {'double' : 'sin', 'float' : 'sinf', 'int' : '(int)sinf', 'unsigned int' : None} +SQRT = {'double' : 'sqrt', 'float' : 'sqrtf', 'int' : '(int)sqrtf', 'unsigned int' : None} + +def levi_civita(i,j,k): + indict = { (1,2,3): 1, + (3,1,2): 1, + (2,3,1): 1, + (1,3,2):-1, + (2,1,3):-1, + (3,2,1):-1} + return indict.get((i,j,k),0) + +def kronecker(i,j): + if(i==j): + return 1 + else: + return 0 + +def cprintf(name,N,M,explode_flag): + if(DEBUG_PRINT): + if(explode_flag): + print('fprintf(stdout,"'+name+'\");') + for i in r_[0:N]: + for j in r_[0:M]: + print('fprintf(stdout,"' + name + '[%d][%d]' % (i,j) + '='+cstyle[TYPE]+'",' + name + '[%d]' % (N*i+j) + ');') + print('fprintf(stdout,"\");') + else: + print('fprintf(stdout,"'+name+'\");') + for i in r_[0:N]: + for j in r_[0:M]: + print('fprintf(stdout,"'+cstyle[TYPE]+' ",' + name + '[%d]' % (N*i+j) + ');') + print('fprintf(stdout,"\");') + else: + '''N+1 #it gets angry if this isn't here ''' + +def A_op_B(op): + for i in range(N): + print('\t _A->v[%d] %s _B->v[%d];' % (i, op, i)) + +def A_op_K(op): + for i in range(N): + print('\t _A->v[%d] %s k;' % (i, op)) + +def A_op_B_eq_Out(op): + for i in range(N): + print('\t _out->v[%d] = _A->v[%d] %s _B->v[%d];' % (i, i, op, i)) + +def A_op_K_eq_Out(op): + for i in range(N): + print('\t _out->v[%d] = _A->v[%d] %s k;' % (i, i, op)) + +def commbreak(): + print('\n' + COMMBREAK + '\n'); + +# Generates: out = A op B +def ThreeVectorFunc(Name, op): + # Function header + print(function_preamble+function_suffix+Name +'(const %s* RESTRICT _A, const %s* RESTRICT _B, %s* RESTRICT _out)\n{' % (VECTYPE, VECTYPE, VECTYPE)) + + #Alignment assumptions + if(N == 3) or (N == 4): + print('\tSST_ASSUME_ALIGNED(_A,16);\n\tSST_ASSUME_ALIGNED(_B,16);\n\tSST_ASSUME_ALIGNED(_out,16);\n') + + #Generate operation + A_op_B_eq_Out(op) + + print("}"); + commbreak(); + + +# Generates: out = function(A, B) +def ThreeVectorWithFunctionFunc(Name, func): + # Function header + print(function_preamble+function_suffix+Name +'(const %s* RESTRICT _A, const %s* RESTRICT _B, %s* RESTRICT _out)\n{' % (VECTYPE, VECTYPE, VECTYPE)) + + #Alignment assumptions + if(N == 3) or (N == 4): + print('\tSST_ASSUME_ALIGNED(_A,16);\n\tSST_ASSUME_ALIGNED(_B,16);\n\tSST_ASSUME_ALIGNED(_out,16);\n') + + #Generate operation + A_op_B_eq_Out(op) + + print("}"); + commbreak(); + + +# Generates: A op= B +def TwoVectorFunc(Name, op): + # Function header + print(function_preamble+function_suffix+Name +'(%s* RESTRICT _A, const %s* RESTRICT _B)\n{' % (VECTYPE, VECTYPE)) + + #Alignment assumptions + if(N == 3) or (N == 4): + print('\tSST_ASSUME_ALIGNED(_A,16);\n\tSST_ASSUME_ALIGNED(_B,16);\n') + + #Generate operation + A_op_B(op) + + print("}"); + commbreak(); + +# Generates: A op= K +def VectorScalarFunc(Name, op): + # Function header + print(function_preamble+function_suffix+Name +'(%s* RESTRICT _A, const %s k)\n{' % (VECTYPE, TYPE)) + + #Alignment assumptions + if(N == 3) or (N == 4): + print('\tSST_ASSUME_ALIGNED(_A,16);\n') + + #Generate operation + A_op_K(op) + + print("}"); + commbreak(); + + +# Generates: out = A op K +def TwoVectorScalarFunc(Name, op): + # Function header + print(function_preamble+function_suffix+Name +'(const %s* RESTRICT _A, const %s k, %s* RESTRICT _out)\n{' % (VECTYPE, TYPE, VECTYPE )) + + #Alignment assumptions + if(N == 3) or (N == 4): + print('\tSST_ASSUME_ALIGNED(_A,16);\n\tSST_ASSUME_ALIGNED(_out,16);\n') + + #Generate operation + A_op_K_eq_Out(op) + + print("}"); + commbreak(); + + + + +rows = r_[0:N] +columns = r_[0:N] + +# FLAGS for use in this generator +DEBUG_PRINT=False +DEBUG_FLAG = False +PIVOTING_FLAG = True +SINGULAR_FLAG = False +TIMING_CHECK = False +# End of FLAGS + +function_preamble = 'void SST_Math_' +function_suffix = 'Vec%d%s' % (N,TYPE[0]) +function_call = 'SST_Math_Vec%d%s' % (N,TYPE[0]) +VECTYPE = 'SST_Vec%d%s' % (N,TYPE[0]) + +if(CODE_TYPE == ''): + # HEADER + print('/*') + print('\tAUTOMATICALLY GENERATED FILE - DO NOT EDIT!') + print('\tPlease change MatrixNxN.py and re-run it') + print('*/') + print('/* Generated with %s n = %d, TYPE = %s */\n' % (__file__,N,TYPE)) + + + print('#include <float.h>') + print('#include <math.h>') + print('#include <pstdbool.h>') + print('#include <stdio.h>') + print('#include <stdlib.h>') + print('#include <SST/SST_Build.h>') + print('#include <SST/%s.h>\n' % (VECTYPE[0:-1])) + + #Add() + ThreeVectorFunc("Add", "+") + + #AddLocal() + TwoVectorFunc("AddLocal", "+=") + + #Sub() + ThreeVectorFunc("Subtract", "-") + + #SubLocal() + TwoVectorFunc("SubtractLocal", "-=") + + #Mult() + ThreeVectorFunc("Multiply", "*") + + #MultLocal() + TwoVectorFunc("MultiplyLocal", "*=") + + #Scale() + TwoVectorScalarFunc("Scale", "*") + + #ScaleLocal() + VectorScalarFunc("ScaleLocal", "*=") + + #Divide() + ThreeVectorFunc("Divide","/") + + #DivideLocal() + TwoVectorFunc("DivideLocal","/=") + + commbreak() + + #AddMult() + listnums = list(range(0,N)*3); listnums.sort() + opstr = "\t_Z->v[%d] = _x * _X->v[%d] + _Y->v[%d];\n"*N % (tuple(listnums)); + print(''' +void SST_Math_%sAddMult(const %s* RESTRICT _X, const %s _x, const %s* RESTRICT _Y, %s* RESTRICT _Z) +{ + SST_ASSUME_ALIGNED(_X,16); + SST_ASSUME_ALIGNED(_Y,16); + SST_ASSUME_ALIGNED(_Z,16); + /* _Z = _x * _X + _Y */ +%s +} +''' % (function_suffix, VECTYPE, TYPE, VECTYPE, VECTYPE,opstr)) + + #AddMultLocal() + listnums = list(range(0,N)*3); listnums.sort() + opstr = "\t_X->v[%d] = _x * _X->v[%d] + _Y->v[%d];\n"*N % (tuple(listnums)); + print(''' +void SST_Math_%sAddMultLocal(%s* RESTRICT _X, const %s _x, const %s* RESTRICT _Y) +{ + SST_ASSUME_ALIGNED(_X,16); + SST_ASSUME_ALIGNED(_Y,16); + /* _X = _x * _X + _Y */ +%s +} +''' % (function_suffix, VECTYPE, TYPE, VECTYPE, opstr)) + + commbreak() + + #Lerpolate() + listnums = list(range(0,N)*4); listnums.sort() + opstr = "\t_Z->v[%d] = _X->v[%d] + (_Y->v[%d] - _X->v[%d]) * _y ;\n"*N % (tuple(listnums)); + print(''' +void SST_Math_%sLerp(const %s* RESTRICT _X, const %s* RESTRICT _Y, const %s _y, %s* RESTRICT _Z) +{ + SST_ASSUME_ALIGNED(_X,16); + SST_ASSUME_ALIGNED(_Y,16); + SST_ASSUME_ALIGNED(_Z,16); + /* Z = x*X + y*Y */ +%s +}''' % (function_suffix, VECTYPE, VECTYPE, TYPE, VECTYPE,opstr)) + + #LerpolateLocal() + listnums = list(range(0,N)*4); listnums.sort() + opstr = "\t_X->v[%d] = _X->v[%d] + (_Y->v[%d] - _X->v[%d]) * _y ;\n"*N % (tuple(listnums)); + print(''' +void SST_Math_%sLerpLocal(%s* RESTRICT _X, const %s* RESTRICT _Y, const %s _y) +{ + SST_ASSUME_ALIGNED(_X,16); + SST_ASSUME_ALIGNED(_Y,16); + /* Z = x*X + y*Y */ +%s +}''' % (function_suffix, VECTYPE, VECTYPE, TYPE, opstr)) + + del opstr + + commbreak() + #Lerpolate() + listnums = list(range(0,N)*3); listnums.sort() + opstr = "\t_Z->v[%d] = _x * _X->v[%d] + _y * _Y->v[%d];\n"*N % (tuple(listnums)); + print(''' +void SST_Math_%sWeightedSum(const %s* RESTRICT _X, const %s _x, const %s* RESTRICT _Y, const %s _y, %s* RESTRICT _Z) +{ + SST_ASSUME_ALIGNED(_X,16); + SST_ASSUME_ALIGNED(_Y,16); + SST_ASSUME_ALIGNED(_Z,16); + /* Z = x*X + y*Y */ +%s +}''' % (function_suffix, VECTYPE, TYPE, VECTYPE, TYPE, VECTYPE,opstr)) + + #LerpolateLocal() + listnums = list(range(0,N)*3); listnums.sort() + opstr = "\t_X->v[%d] = _x * _X->v[%d] + _y * _Y->v[%d];\n"*N % (tuple(listnums)); + print(''' +void SST_Math_%sWeightedSumLocal(%s* RESTRICT _X, const %s _x, const %s* RESTRICT _Y, const %s _y) +{ + SST_ASSUME_ALIGNED(_X,16); + SST_ASSUME_ALIGNED(_Y,16); + /* Z = x*X + y*Y */ +%s +}''' % (function_suffix, VECTYPE, TYPE, VECTYPE, TYPE, opstr)) + + del opstr + + commbreak() + + #Equals() + if((TYPE == 'int') or (TYPE == 'unsigned int')): + print('''bool SST_Math_%sEquals(const %s* RESTRICT _a, const %s* RESTRICT _b) +{ + int i; + bool returncode; + SST_ASSUME_ALIGNED(_a,16); + SST_ASSUME_ALIGNED(_b,16); + returncode = 1; + for(i=0;i<%d;i++) + { + returncode = (_a->v[i]==_b->v[i]) && returncode; + } + return returncode; +} + ''' % (function_suffix, VECTYPE, VECTYPE, N)) + else: + print('''bool SST_Math_%sEquals(const %s* RESTRICT _a, const %s* RESTRICT _b, const %s _tolerance) +{ + %s tmp; + int i; + bool returncode; + SST_ASSUME_ALIGNED(_a,16); + SST_ASSUME_ALIGNED(_b,16); + returncode = 1; + + SST_Math_%sSubtract(_a,_b,&tmp); + for(i=0;i<%d;i++) + { + returncode = (%s(tmp.v[i]) <= _tolerance) && returncode; + } + + return returncode; +} + ''' % (function_suffix, VECTYPE, VECTYPE, TYPE, VECTYPE, function_suffix, N, fabs[TYPE])) + + + + commbreak() + # Comparisons + indices = range(1,N)*2; indices.sort() + print('''%s SST_Math_%sMax(const %s* RESTRICT _a) +{ + %s tmp = _a->v[0]; +%s + return tmp; +}''' % (TYPE, function_suffix, VECTYPE, TYPE,'\tif(tmp < _a->v[%d]) tmp = _a->v[%d];\n'*(N-1) % (tuple(indices)))) + commbreak() + print('''%s SST_Math_%sMin(const %s* RESTRICT _a) +{ + %s tmp = _a->v[0]; +%s + return tmp; +}''' % (TYPE, function_suffix, VECTYPE, TYPE,'\tif(tmp > _a->v[%d]) tmp = _a->v[%d];\n'*(N-1) % (tuple(indices)))) + + commbreak() + + if((TYPE != 'int') & (TYPE != 'unsigned int')): + if(N != 4): + #Cross + print('''void SST_Math_%sCross(const %s* RESTRICT _a, const %s* RESTRICT _b, %s* RESTRICT _out) + {''' % (function_suffix,VECTYPE,VECTYPE,VECTYPE)) + if (N==2): + print(''' + _out->v[0] = _a->v[0]*_b->v[1] - _a->v[1]*_b->v[0]; + _out->v[1] = _out->v[0];''') + if (N==3): + print(''' + _out->v[0] = _a->v[1]*_b->v[2] - _a->v[2]*_b->v[1]; + _out->v[1] =-(_a->v[0]*_b->v[2] - _a->v[2]*_b->v[0]); + _out->v[2] = _a->v[0]*_b->v[1] - _a->v[1]*_b->v[0];''') + + print('}') + + commbreak() + #CrossLocal + print('''void SST_Math_%sCrossLocal(%s* RESTRICT _a, const %s* RESTRICT _b)\n{ + %s out;'''% (function_suffix,VECTYPE,VECTYPE,VECTYPE)) + if(N==2): + print(''' + out.v[0] = _a->v[0]*_b->v[1] - _a->v[1]*_b->v[0]; + _a->v[0] = out.v[0]; + _a->v[1] = out.v[0];''') + if(N==3): + print(''' + out.v[0] = _a->v[1]*_b->v[2] - _a->v[2]*_b->v[1]; + out.v[1] =-(_a->v[0]*_b->v[2] - _a->v[2]*_b->v[0]); + out.v[2] = _a->v[0]*_b->v[1] - _a->v[1]*_b->v[0]; + _a->v[0] = out.v[0]; + _a->v[1] = out.v[1]; + _a->v[2] = out.v[2]; ''') + + print('}') + + commbreak() + + + if( (N==3) or (N==2)): + ''' // This is a giant comment if you're not apython person. algorithm using other thigns. inlined it because the includes + // got something horrid + /* + /* [sx 0 0; 0 sy 0; 0 0 1] */ + /* [cos(a) sin(a) 0; -sin(a) cos(a) 0; 0 0 1] */ + /* T are translations */ + SST_Vec3%s X; + SST_Mat33%s T; + SST_Mat33%s S; + SST_Mat33%s R; + + X.x = _a->x; + X.y = _a->y; + X.z = 1.0f; + + SST_Math_Mat33%sCreateIdentity(&T); + SST_Math_Mat33%sCreateTranslation(&S,_about->x,_about->y); + SST_Math_Mat33%sCreateEulerZ(&R,_theta); + SST_Math_Mat33%sMultiplyMatrixLocal(&S,&T); + SST_Math_Mat33%sMultiplyMatrixLocal(&R,&T); + SST_Math_Mat33%sCreateTranslation(&S,-_about->x,-_about->y); + SST_Math_Mat33%sMultiplyMatrixLocal(&S,&T); + + /* X' = S^-1 * R * S * X */ + /* See ApplyTransformations in SST_Transform */ + SST_Math_Mat33%sApplyTransforms(&T,&(&X),1); */ + ''' + #RotateAbout + print('''void SST_Math_%sRotateAbout(const %s* RESTRICT _a, const %s* RESTRICT _about,%s _theta, %s* RESTRICT _out)\n{ + ''' % (function_suffix,VECTYPE,VECTYPE,TYPE,VECTYPE)) + if (N==2): + print(''' + const %s cosa = %s(_theta); + const %s sina = %s(_theta); + _out->x = cosa * (_a->x-_about->x) + sina * (_a->y-_about->y) + _about->x; + _out->y = -sina * (_a->x-_about->x) + cosa * (_a->y-_about->y) + _about->y; + ''' % (TYPE, COS[TYPE], TYPE, SIN[TYPE])) + if (N==3): + print(''' + %s tmp; + %s scalar = (%s-%s(_theta)) * SST_Math_%sDot(_about,_a); + SST_Math_%sScale(_about,scalar,_out); + SST_Math_%sCross(_about,_a,&tmp); + SST_Math_%sScaleLocal(&tmp,%s(_theta)); + SST_Math_%sAddLocal(_out,&tmp); + SST_Math_%sScale(_a,%s(_theta),&tmp); + SST_Math_%sAddLocal(_out,&tmp); + ''' % (VECTYPE,TYPE,cstyle[TYPE] % (1), COS[TYPE],function_suffix,function_suffix,function_suffix,function_suffix,SIN[TYPE],function_suffix,function_suffix,COS[TYPE],function_suffix)) + + print('''}''') + + commbreak() + + #RotateAboutLocal + print('''void SST_Math_%sRotateAboutLocal(%s* RESTRICT _a, const %s* RESTRICT _about,%s _theta)\n{ + ''' % (function_suffix,VECTYPE,VECTYPE,TYPE)) + if (N==2): + print(''' + %s tmp; + const %s cosa = %s(_theta); + const %s sina = %s(_theta); + + _a->x -= _about->x; + _a->y -= _about->y; + + tmp = cosa * (_a->x) + sina * (_a->y) + _about->x; + _a->y = -sina * (_a->x) + cosa * (_a->y) + _about->y; + _a->x = tmp; + ''' % (TYPE, TYPE, COS[TYPE], TYPE, SIN[TYPE])) + + if (N==3): + print(''' + int i; + %s tmp; + %s tmp2; + %s scalar = (%s-%s(_theta)) * SST_Math_%sDot(_about,_a);''' % (VECTYPE,VECTYPE,TYPE,cstyle[TYPE] % (1), COS[TYPE],function_suffix)) + print(''' + SST_Math_%sScale(_about,scalar,&tmp2); + SST_Math_%sCross(_about,_a,&tmp); + SST_Math_%sScaleLocal(&tmp,%s(_theta)); + SST_Math_%sAddLocal(&tmp2,&tmp); + SST_Math_%sScale(_a,%s(_theta),&tmp); + SST_Math_%sAddLocal(&tmp2,&tmp); + + for(i = 0; i < %s; i++) + _a->v[i] = tmp2.v[i]; + + ''' % (function_suffix,function_suffix,function_suffix,SIN[TYPE],function_suffix,function_suffix,COS[TYPE],function_suffix,N)) + print('''}''') + + commbreak() + #Rotate + print('''void SST_Math_%sRotate(const %s* RESTRICT _a,%s _theta, %s* RESTRICT _out)\n{ + ''' % (function_suffix,VECTYPE,TYPE,VECTYPE)) + if (N==2): + print(''' + const %s cosa = %s(_theta); + const %s sina = %s(_theta); + _out->x = cosa * (_a->x) + sina * (_a->y); + _out->y = -sina * (_a->x) + cosa * (_a->y); + ''' % (TYPE, COS[TYPE], TYPE, SIN[TYPE])) + if (N==3): + print(''' + %s tmp; + %s about; + %s scalar; + about.x = 0.0; + about.y = 0.0; + about.z = 0.0; + scalar = (%s-%s(_theta)) * SST_Math_%sDot(&about,_a); + SST_Math_%sScale(&about,scalar,_out); + SST_Math_%sCross(&about,_a,&tmp); + SST_Math_%sScaleLocal(&tmp,%s(_theta)); + SST_Math_%sAddLocal(_out,&tmp); + SST_Math_%sScale(_a,%s(_theta),&tmp); + SST_Math_%sAddLocal(_out,&tmp); + ''' % (VECTYPE,VECTYPE,TYPE,cstyle[TYPE] % (1), COS[TYPE],function_suffix,function_suffix,function_suffix,function_suffix,SIN[TYPE],function_suffix,function_suffix,COS[TYPE],function_suffix)) + print('''}''') + + commbreak() + + #RotateLocal + print('''void SST_Math_%sRotateLocal(%s* RESTRICT _a, %s _theta)\n{ + ''' % (function_suffix,VECTYPE,TYPE)) + if (N==2): + print(''' + const %s cosa = %s(_theta); + const %s sina = %s(_theta); + %s tmp; + + tmp = cosa * (_a->x) + sina * (_a->y); + _a->y = -sina * (_a->x) + cosa * (_a->y); + _a->x = tmp; + ''' % (TYPE, COS[TYPE], TYPE, SIN[TYPE], TYPE)) + + if (N==3): + print(''' + int i; + %s tmp; + %s tmp2; + %s about; + %s scalar; + about.x = 0.0; + about.y = 0.0; + about.z = 0.0; + scalar = (%s-%s(_theta)) * SST_Math_%sDot(&about,_a);''' % (VECTYPE, VECTYPE, VECTYPE, TYPE,cstyle[TYPE] % (1), COS[TYPE],function_suffix)) + print(''' + SST_Math_%sScale(&about,scalar,&tmp2); + SST_Math_%sCross(&about,_a,&tmp); + SST_Math_%sScaleLocal(&tmp,%s(_theta)); + SST_Math_%sAddLocal(&tmp2,&tmp); + SST_Math_%sScale(_a,%s(_theta),&tmp); + SST_Math_%sAddLocal(&tmp2,&tmp); + + for(i = 0; i < %s; i++) + _a->v[i] = tmp2.v[i]; + + ''' % (function_suffix,function_suffix,function_suffix,SIN[TYPE],function_suffix,function_suffix,COS[TYPE],function_suffix,N)) + print('''}''') + + #Normalize + print('''void SST_Math_%sNormalize(const %s* RESTRICT _in, %s* RESTRICT _out)\n{ + %s scalar = 1.f/SST_Math_%sMagnitude(_in); + SST_Math_%sScale(_in,scalar,_out); +}''' % (function_suffix,VECTYPE,VECTYPE,TYPE,function_suffix,function_suffix)) + + commbreak() + + #NormalizeLocal + print('''void SST_Math_%sNormalizeLocal(%s* _inout)\n{ + %s scalar = 1.f/SST_Math_%sMagnitude(_inout); + SST_Math_%sScaleLocal(_inout,scalar); +}''' % (function_suffix,VECTYPE,TYPE,function_suffix,function_suffix)) + + commbreak() + #RecipSqrt + print('''void SST_Math_%sRecipSqrt(const %s* RESTRICT _in, %s* RESTRICT _out)\n{ + int i; + for(i = 0; i < %d; i++) + _out->v[i] = 1/%s(_in->v[i]); +}''' % (function_suffix,VECTYPE,VECTYPE,N,SQRT[TYPE])) + + commbreak() + #RecipSqrtLocal + print('''void SST_Math_%sRecipSqrtLocal(%s* RESTRICT _a)\n{ + int i; + for(i = 0; i < %d; i++) + _a->v[i] = 1/%s(_a->v[i]); +}''' % (function_suffix,VECTYPE,N,SQRT[TYPE])) + + commbreak() + #Sqrt + print('''void SST_Math_%sSqrt(const %s* RESTRICT _in, %s* RESTRICT _out)\n{ + int i; + for(i = 0; i < %d; i++) + _out->v[i] = %s(_in->v[i]); +}''' % (function_suffix,VECTYPE,VECTYPE,N,SQRT[TYPE])) + + commbreak() + #SqrtLocal + print('''void SST_Math_%sSqrtLocal(%s* RESTRICT _a)\n{ + int i; + for(i = 0; i < %d; i++) + _a->v[i] = %s(_a->v[i]); +}''' % (function_suffix,VECTYPE,N,SQRT[TYPE])) + + commbreak() + #Magnitude + print('''%s SST_Math_%sMagnitude(const %s* RESTRICT _a)\n{ + %s sum = 0; + int i; + for(i = 0; i < %d; i++) + sum += _a->v[i] * _a->v[i]; + return %s(sum); +}''' % (TYPE,function_suffix,VECTYPE,TYPE,N,SQRT[TYPE])) + + commbreak() + if(TYPE != 'unsigned int'): + #Abs + print('''void SST_Math_%sAbs(const %s* RESTRICT _in, %s* RESTRICT _out)\n{ + int i; + for(i = 0; i < %d; i++) + _out->v[i] = %s(_in->v[i]); +}''' % (function_suffix,VECTYPE,VECTYPE,N,fabs[TYPE])) + + commbreak() + #AbsLocal + print('''void SST_Math_%sAbsLocal(%s* RESTRICT _a)\n{ + int i; + for(i = 0; i < %d; i++) + _a->v[i] = %s(_a->v[i]); +}''' % (function_suffix,VECTYPE,N,fabs[TYPE])) + + commbreak() + #Negate + print('''void SST_Math_%sNegate(const %s* RESTRICT _in, %s* RESTRICT _out)\n{ + int i; + for(i = 0; i < %d; i++) + _out->v[i] = -(_in->v[i]); +}''' % (function_suffix,VECTYPE,VECTYPE,N)) + + commbreak() + #NegateLocal + print('''void SST_Math_%sNegateLocal(%s* RESTRICT _a)\n{ + int i; + for(i = 0; i < %d; i++) + _a->v[i] = -(_a->v[i]); +}''' % (function_suffix,VECTYPE,N)) + + commbreak() + #Recip + print('''void SST_Math_%sRecip(const %s* RESTRICT _in, %s* RESTRICT _out)\n{ + int i; + for(i = 0; i < %d; i++) + _out->v[i] = 1/(_in->v[i]); +}''' % (function_suffix,VECTYPE,VECTYPE,N)) + + commbreak() + #RecipLocal + print('''void SST_Math_%sRecipLocal(%s* RESTRICT _a)\n{ + int i; + for(i = 0; i < %d; i++) + _a->v[i] = 1/(_a->v[i]); +}''' % (function_suffix,VECTYPE,N)) + + commbreak() + #Dot + print('''%s SST_Math_%sDot(const %s* RESTRICT _a, const %s* RESTRICT _b)\n{ + %s sum = 0; + int i; + for(i = 0; i < %d; i++) + sum += _a->v[i] * _b->v[i]; + return sum; +}''' % (TYPE,function_suffix,VECTYPE,VECTYPE,TYPE,N)) + + commbreak() + + + #MagnitudeSquared + print('''%s SST_Math_%sMagnitudeSquared(const %s* RESTRICT _a)\n{ + %s sum = 0; + int i; + for(i = 0; i < %d; i++) + sum += _a->v[i] * _a->v[i]; + return sum; +}''' % (TYPE,function_suffix,VECTYPE,TYPE,N)) + + commbreak() + + print('''void SST_Math_%sProject(const %s* RESTRICT _a, const %s* RESTRICT _b, %s* RESTRICT _out)\n{ + %s scalar = SST_Math_%sDot(_a,_b) / SST_Math_%sDot(_b,_b); + SST_Math_%sScale(_b, scalar, _out); +} + ''' % (function_suffix,VECTYPE,VECTYPE,VECTYPE,TYPE,function_suffix,function_suffix,function_suffix) ) + + commbreak() + + print('''void SST_Math_%sProjectLocal(%s* RESTRICT _a, const %s* RESTRICT _b)\n{ + %s scalar = SST_Math_%sDot(_a,_b) / SST_Math_%sDot(_b,_b); + SST_Math_%sScale(_b, scalar, _a); +} + ''' % (function_suffix,VECTYPE,VECTYPE,TYPE,function_suffix,function_suffix,function_suffix) ) + + commbreak() + + print('''void SST_Math_%sBias(const %s* RESTRICT _a, const %s _bias, %s* RESTRICT _out)\n{ + int i; + for(i = 0; i < %d; i++) + _out->v[i] = _a->v[i] + _bias; +} + ''' % (function_suffix,VECTYPE,TYPE,VECTYPE,N) ) + + commbreak() + + print('''void SST_Math_%sBiasLocal(%s* RESTRICT _a, const %s _bias)\n{ + int i; + for(i = 0; i < %d; i++) + _a->v[i] += _bias; +} + ''' % (function_suffix,VECTYPE,TYPE,N) ) + + commbreak() + ''' + /* Vec3f (3D float Vector) Routines */ + + /* f:R3 -> R3 */ + /* f:R3 -> R */ + float SST_Math_Vec3fL1Norm(const SST_Vec3f* a); + float SST_Math_Vec3fRecipMagnitude(const SST_Vec3f* a); + + ''' +# End of SST_VecNT.c section +tab = ' ' +def Equals(str1,str2): + if((TYPE=='int') | (TYPE=='unsigned int')): + return '('+str1+')==('+str2+')' + else: + return '%s((' % fabs[TYPE] + str1+')-('+str2+')) <=100*%s /* yes this is bad */' % (fp_epsilon[TYPE]) + +def ZUnitTestPair( testname , additional_endchars = ','): + print('{ "%-45s" , %-45s }' %(testname,testname)+additional_endchars) + +# Variable Setup +def VariableSetup(vars = ['x','y','w']): + if( 'x' in vars ): + print(tab+'%s x; /* %d vector */' % (VECTYPE,N)) + if( 'y' in vars ): + print(tab+'%s y; /* %d vector */' % (VECTYPE,N)) + if( 'w' in vars ): + print(tab+'%s w; /* %d vector */' % (VECTYPE,N)) + if( 'a' in vars ): + print(tab+'%s a; /* scalar */' % (TYPE)) + +def resetVecs(vars = ['x','y','w']): + low = -20 + high = 20 + if(TYPE=='unsigned int'): + low = 0 + high = 40 + print('/* Resetting test vectors */') + if( 'x' in vars ): + x = array(random.randint(low,high,N),dtype=DTYPE[TYPE]) + '''print('/* x') + print(x.dtype) + print(x) + print('*/')''' + for i in rows: + print(tab+'x.v[%d] = ' % i + ('%s' % cstyle[TYPE]) % (x[i])+';') + if( 'y' in vars ): + y = array(random.randint(low,high,N),dtype=DTYPE[TYPE]) + '''print('/* y') + print(y.dtype) + print(y) + print('*/')''' + for i in rows: + print(tab+'y.v[%d] = ' % i + ('%s' % cstyle[TYPE]) % (y[i])+';') + + if( 'w' in vars ): + w = zeros((N),dtype=DTYPE[TYPE]) + '''print('/* w') + print(w.dtype) + print(w) + print('*/')''' + for i in rows: + print(tab+'w.v[%d] = ' % i + ('%s' % cstyle[TYPE]) % (w[i])+';') + + if (('w' in vars) & ('x' in vars) & ('y' in vars)): + return x,y,w + + if (('x' in vars) & ('y' in vars)): + return x,y + + if (('x' in vars) & ('w' in vars)): + return x,w + + if ('x' in vars): + return x + +def resetVecsPositive(vars = ['x','y','w']): + low = 1 + high = 40 + if(TYPE=='unsigned int'): + low = 1 + high = 40 + print('/* Resetting test vectors */') + if( 'x' in vars ): + x = array(random.randint(low,high,N),dtype=DTYPE[TYPE]) + '''print('/* x') + print(x.dtype) + print(x) + print('*/')''' + for i in rows: + print(tab+'x.v[%d] = ' % i + ('%s' % cstyle[TYPE]) % (x[i])+';') + if( 'y' in vars ): + y = array(random.randint(low,high,N),dtype=DTYPE[TYPE]) + '''print('/* y') + print(y.dtype) + print(y) + print('*/')''' + for i in rows: + print(tab+'y.v[%d] = ' % i + ('%s' % cstyle[TYPE]) % (y[i])+';') + + if( 'w' in vars ): + w = zeros((N),dtype=DTYPE[TYPE]) + '''print('/* w') + print(w.dtype) + print(w) + print('*/')''' + for i in rows: + print(tab+'w.v[%d] = ' % i + ('%s' % cstyle[TYPE]) % (w[i])+';') + + if (('w' in vars) & ('x' in vars) & ('y' in vars)): + return x,y,w + + if (('x' in vars) & ('y' in vars)): + return x,y + + if (('x' in vars) & ('w' in vars)): + return x,w + + if ('x' in vars): + return x +def project(a,b): + return b*(dot(a,b)/dot(b,b)) +def EndTest(): + print(tab+'return ZTEST_SUCCESS;\n}') + +entry = { 0 : 'x' , 1 : 'y' , 2 : 'z' , 3 : 'w' } + +#Generate Unit Test code +if(CODE_TYPE == 'unittest'): + print('/*') + print('\tAUTOMATICALLY GENERATED FILE - DO NOT EDIT!') + print('\tPlease change MatrixNxN.py and re-run it') + print('*/') + print('/* Generated with %s n = %d, TYPE = %s */\n' % (__file__,N,TYPE)) + print('#include "ZUnitTest.hpp"') + print('#include <float.h>') + print('#include <math.h>') + print('#include <stdlib.h>') + print('#include <stdio.h>') + print('#include <SST/%s.h>' % VECTYPE[0:-1]) + print('\n\n\n') + + unittest_preamble = 'static const char* test' + print(unittest_preamble+function_call+'Add();') + print(unittest_preamble+function_call+'AddLocal();') + print(unittest_preamble+function_call+'Subtract();') + print(unittest_preamble+function_call+'SubtractLocal();') + print(unittest_preamble+function_call+'Multiply();') + print(unittest_preamble+function_call+'MultiplyLocal();') + print(unittest_preamble+function_call+'Scale();') + print(unittest_preamble+function_call+'ScaleLocal();') + print(unittest_preamble+function_call+'Divide();') + print(unittest_preamble+function_call+'DivideLocal();') + if((TYPE!='unsigned int')): + print(unittest_preamble+function_call+'Abs();') + print(unittest_preamble+function_call+'AbsLocal();') + print(unittest_preamble+function_call+'Negate();') + print(unittest_preamble+function_call+'NegateLocal();') + print(unittest_preamble+function_call+'Bias();') + print(unittest_preamble+function_call+'BiasLocal();') + if((TYPE!='int') & (TYPE!='unsigned int')): + print(unittest_preamble+function_call+'Recip();') + print(unittest_preamble+function_call+'RecipLocal();') + print(unittest_preamble+function_call+'RecipSqrt();') + print(unittest_preamble+function_call+'RecipSqrtLocal();') + print(unittest_preamble+function_call+'Sqrt();') + print(unittest_preamble+function_call+'SqrtLocal();') + print(unittest_preamble+function_call+'Sqrt();') + print(unittest_preamble+function_call+'SqrtLocal();') + if((N==2) | (N==3)): + print(unittest_preamble+function_call+'Cross();') + print(unittest_preamble+function_call+'CrossLocal();') + if(N==3): + print(unittest_preamble+function_call+'RotateAbout();') + print(unittest_preamble+function_call+'RotateAboutLocal();') + print(unittest_preamble+function_call+'Project();') + print(unittest_preamble+function_call+'ProjectLocal();') + print(unittest_preamble+function_call+'Magnitude();') + print(unittest_preamble+function_call+'Normalize();') + print(unittest_preamble+function_call+'NormalizeLocal();') + print(unittest_preamble+function_call+'MagnitudeSquared();') + print(unittest_preamble+function_call+'Dot();') + + print('// List of unit tests ') + print('ZUnitTest '+function_call+'UnitTests[] = \n{') + ZUnitTestPair('test'+function_call+'Add') + ZUnitTestPair('test'+function_call+'AddLocal') + ZUnitTestPair('test'+function_call+'Subtract') + ZUnitTestPair('test'+function_call+'SubtractLocal') + ZUnitTestPair('test'+function_call+'Multiply') + ZUnitTestPair('test'+function_call+'MultiplyLocal') + ZUnitTestPair('test'+function_call+'Scale') + ZUnitTestPair('test'+function_call+'ScaleLocal') + ZUnitTestPair('test'+function_call+'Divide') + ZUnitTestPair('test'+function_call+'DivideLocal') + if((TYPE!='unsigned int')): + ZUnitTestPair('test'+function_call+'Abs') + ZUnitTestPair('test'+function_call+'AbsLocal') + ZUnitTestPair('test'+function_call+'Negate') + ZUnitTestPair('test'+function_call+'NegateLocal') + ZUnitTestPair('test'+function_call+'Bias') + ZUnitTestPair('test'+function_call+'BiasLocal') + if((TYPE!='int') & (TYPE!='unsigned int')): + ZUnitTestPair('test'+function_call+'Recip') + ZUnitTestPair('test'+function_call+'RecipLocal') + ZUnitTestPair('test'+function_call+'RecipSqrt') + ZUnitTestPair('test'+function_call+'RecipSqrtLocal') + ZUnitTestPair('test'+function_call+'Sqrt') + ZUnitTestPair('test'+function_call+'SqrtLocal') + ZUnitTestPair('test'+function_call+'Sqrt') + ZUnitTestPair('test'+function_call+'SqrtLocal') + ZUnitTestPair('test'+function_call+'Magnitude') + ZUnitTestPair('test'+function_call+'Normalize') + ZUnitTestPair('test'+function_call+'NormalizeLocal') + if((N==2) | (N==3)): + ZUnitTestPair('test'+function_call+'Cross') + ZUnitTestPair('test'+function_call+'CrossLocal') + if(N==3): + ZUnitTestPair('test'+function_call+'RotateAbout') + ZUnitTestPair('test'+function_call+'RotateAboutLocal') + ZUnitTestPair('test'+function_call+'Project') + ZUnitTestPair('test'+function_call+'ProjectLocal') + ZUnitTestPair('test'+function_call+'MagnitudeSquared') + ZUnitTestPair('test'+function_call+'Dot','\n};') + print('DECLARE_ZTESTBLOCK('+function_call+')') + + commbreak() + + print(unittest_preamble+function_call+'Add()\n{') + VariableSetup() + x,y,w = resetVecs() + print('/*') + print(x) + print(y) + print(x+y) + print('*/') + print(tab+function_call+'Add(&x,&y,&w);') + for i in rows: + print(tab+'TASSERT('+Equals('w.v[%d]' % (i), ('%s' % cstyle[TYPE]) % (x[i]+y[i]))+',"Entry _%s failed!"' % (entry[i]) + ');') + + EndTest() + + commbreak() + + print(unittest_preamble+function_call+'AddLocal()\n{') + VariableSetup(['x','y']) + x,y = resetVecs(['x','y']) + print('/*') + print(x) + print(y) + print(x+y) + print('*/') + print(tab+function_call+'AddLocal(&x,&y); /* for accuracy */') + for i in rows: + print(tab+'TASSERT('+Equals('x.v[%d]' % (i), ('%s' % cstyle[TYPE]) % (x[i]+y[i]))+',"Entry _%s failed!"' % (entry[i]) + ');') + + EndTest() + + commbreak() + + print(unittest_preamble+function_call+'Subtract()\n{') + VariableSetup() + x,y,w = resetVecs() + print('/*') + print(x) + print(y) + print(x-y) + print('*/') + print(tab+function_call+'Subtract(&x,&y,&w);') + for i in rows: + print(tab+'TASSERT('+Equals('w.v[%d]' % (i), ('%s' % cstyle[TYPE]) % (x[i]-y[i]))+',"Entry _%s failed!"' % (entry[i]) + ');') + + EndTest() + + commbreak() + + print(unittest_preamble+function_call+'SubtractLocal()\n{') + VariableSetup(['x','y']) + x,y = resetVecs(['x','y']) + print('/*') + print(x) + print(y) + print(x-y) + print('*/') + print(tab+function_call+'SubtractLocal(&x,&y); /* for accuracy */') + for i in rows: + print(tab+'TASSERT('+Equals('x.v[%d]' % (i), ('%s' % cstyle[TYPE]) % (x[i]-y[i]))+',"Entry _%s failed!"' % (entry[i]) + ');') + + EndTest() + + commbreak() + + print(unittest_preamble+function_call+'Multiply()\n{') + VariableSetup() + x,y,w = resetVecs() + print('/*') + print(x) + print(y) + print(x*y) + print('*/') + print(tab+function_call+'Multiply(&x,&y,&w);') + for i in rows: + print(tab+'TASSERT('+Equals('w.v[%d]' % (i), ('%s' % cstyle[TYPE]) % (x[i]*y[i]))+',"Entry _%s failed!"' % (entry[i]) + ');') + + EndTest() + + commbreak() + + print(unittest_preamble+function_call+'MultiplyLocal()\n{') + VariableSetup(['x','y']) + x,y = resetVecs(['x','y']) + print('/*') + print(x) + print(y) + print(x*y) + print('*/') + print(tab+function_call+'MultiplyLocal(&x,&y); /* for accuracy */') + for i in rows: + print(tab+'TASSERT('+Equals('x.v[%d]' % (i), ('%s' % cstyle[TYPE]) % (x[i]*y[i]))+',"Entry _%s failed!"' % (entry[i]) + ');') + + EndTest() + + commbreak() + + print(unittest_preamble+function_call+'Divide()\n{') + VariableSetup() + x,y,w = resetVecsPositive() + print('/*') + print(x) + print(y) + print(x / y) + print('*/') + print(tab+function_call+'Divide(&x,&y,&w);') + for i in rows: + print(tab+'TASSERT('+Equals('w.v[%d]' % (i), ('%s' % cstyle[TYPE]) % (x[i] / y[i]))+',"Entry _%s failed!"' % (entry[i]) + ');') + + EndTest() + + commbreak() + + print(unittest_preamble+function_call+'DivideLocal()\n{') + VariableSetup(['x','y']) + x,y = resetVecsPositive(['x','y']) + print('/*') + print(x) + print(y) + print(x / y) + print('*/') + print(tab+function_call+'DivideLocal(&x,&y); /* for accuracy */') + for i in rows: + print(tab+'TASSERT('+Equals('x.v[%d]' % (i), ('%s' % cstyle[TYPE]) % (x[i] / y[i]))+',"Entry _%s failed!"' % (entry[i]) + ');') + + EndTest() + + commbreak() + + print(unittest_preamble+function_call+'Scale()\n{') + VariableSetup(['x','w','a']) + x,w = resetVecs(['x','w']) + print(tab+'a = %s;' % cstyle[TYPE]%(2)) + print('/*') + print(x) + print(x*2) + print('*/') + print(tab+function_call+'Scale(&x,a,&w);') + for i in rows: + print(tab+'TASSERT('+Equals('w.v[%d]' % (i), ('%s' % cstyle[TYPE]) % (2 * x[i]))+',"Entry _%s failed!"' % (entry[i]) + ');') + + EndTest() + + commbreak() + + print(unittest_preamble+function_call+'ScaleLocal()\n{') + VariableSetup(['x','a']) + x = resetVecs(['x']) + print(tab+'a = %s;' % cstyle[TYPE]%(2)) + print('/*') + print(x) + print(2*x) + print('*/') + print(tab+function_call+'ScaleLocal(&x,a); /* for accuracy */') + for i in rows: + print(tab+'TASSERT('+Equals('x.v[%d]' % (i), ('%s' % cstyle[TYPE]) % (2 * x[i]))+',"Entry _%s failed!"' % (entry[i]) + ');') + + EndTest() + + commbreak() + + + if((TYPE!='unsigned int')): + print(unittest_preamble+function_call+'Abs()\n{') + VariableSetup(['x','w']) + x,w = resetVecs(['x','w']) + print('/*') + print(x) + print(abs(x)) + print('*/') + print(tab+function_call+'Abs(&x,&w);') + for i in rows: + print(tab+'TASSERT('+Equals('w.v[%d]' % (i), ('%s' % cstyle[TYPE]) % (abs(x[i])))+',"Entry _%s failed!"' % (entry[i]) + ');') + + EndTest() + + commbreak() + + print(unittest_preamble+function_call+'AbsLocal()\n{') + VariableSetup(['x']) + x = resetVecs(['x']) + print('/*') + print(x) + print(abs(x)) + print('*/') + print(tab+function_call+'AbsLocal(&x); /* for accuracy */') + for i in rows: + print(tab+'TASSERT('+Equals('x.v[%d]' % (i), ('%s' % cstyle[TYPE]) % (abs(x[i])))+',"Entry _%s failed!"' % (entry[i]) + ');') + + EndTest() + + commbreak() + + print(unittest_preamble+function_call+'Bias()\n{') + VariableSetup(['x','w','a']) + x,w = resetVecs(['x','w']) + a = random.randint(-20,20,1) + print(tab+'a = %s;' % cstyle[TYPE]%(a)) + print('/*') + print(x) + print(x*2) + print('*/') + print(tab+function_call+'Bias(&x,a,&w);') + for i in rows: + print(tab+'TASSERT('+Equals('w.v[%d]' % (i), ('%s' % cstyle[TYPE]) % (a + x[i]))+',"Entry _%s failed!"' % (entry[i]) + ');') + + EndTest() + + commbreak() + + print(unittest_preamble+function_call+'BiasLocal()\n{') + VariableSetup(['x','a']) + x = resetVecs(['x']) + a = random.randint(-20,20,1) + print(tab+'a = %s;' % cstyle[TYPE]%(a)) + print('/*') + print(x) + print(2*x) + print('*/') + print(tab+function_call+'BiasLocal(&x,a); /* for accuracy */') + for i in rows: + print(tab+'TASSERT('+Equals('x.v[%d]' % (i), ('%s' % cstyle[TYPE]) % (a + x[i]))+',"Entry _%s failed!"' % (entry[i]) + ');') + + EndTest() + + commbreak() + + print(unittest_preamble+function_call+'Negate()\n{') + VariableSetup(['x','w']) + x,w = resetVecs(['x','w']) + print('/*') + print(x) + print(-x) + print('*/') + print(tab+function_call+'Negate(&x,&w);') + for i in rows: + print(tab+'TASSERT('+Equals('w.v[%d]' % (i), ('%s' % cstyle[TYPE]) % (-x[i]))+',"Entry _%s failed!"' % (entry[i]) + ');') + + EndTest() + + commbreak() + + print(unittest_preamble+function_call+'NegateLocal()\n{') + VariableSetup(['x']) + x = resetVecs(['x']) + print('/*') + print(x) + print(-x) + print('*/') + print(tab+function_call+'NegateLocal(&x); /* for accuracy */') + for i in rows: + print(tab+'TASSERT('+Equals('x.v[%d]' % (i), ('%s' % cstyle[TYPE]) % (-x[i]))+',"Entry _%s failed!"' % (entry[i]) + ');') + + EndTest() + + commbreak() + + if((TYPE!='int') & (TYPE!='unsigned int')): + print(unittest_preamble+function_call+'Sqrt()\n{') + VariableSetup(['x','w']) + x,w = resetVecsPositive(['x','w']) + print('/*') + print(x) + print(sqrt(x)) + print('*/') + print(tab+function_call+'Sqrt(&x,&w);') + for i in rows: + print(tab+'TASSERT('+Equals('w.v[%d]' % (i), ('%s' % cstyle[TYPE]) % (sqrt(x[i])))+',"Entry _%s failed!"' % (entry[i]) + ');') + + EndTest() + + commbreak() + + print(unittest_preamble+function_call+'SqrtLocal()\n{') + VariableSetup(['x']) + x = resetVecsPositive(['x']) + print('/*') + print(x) + print(sqrt(x)) + print('*/') + print(tab+function_call+'SqrtLocal(&x); /* for accuracy */') + for i in rows: + print(tab+'TASSERT('+Equals('x.v[%d]' % (i), ('%s' % cstyle[TYPE]) % (sqrt(x[i])))+',"Entry _%s failed!"' % (entry[i]) + ');') + + EndTest() + + commbreak() + + print(unittest_preamble+function_call+'RecipSqrt()\n{') + VariableSetup(['x','w']) + x,w = resetVecsPositive(['x','w']) + print('/*') + print(x) + print(1/sqrt(x)) + print('*/') + print(tab+function_call+'RecipSqrt(&x,&w);') + for i in rows: + print(tab+'TASSERT('+Equals('w.v[%d]' % (i), ('%s' % cstyle[TYPE]) % (1/sqrt(x[i])))+',"Entry _%s failed!"' % (entry[i]) + ');') + + EndTest() + + commbreak() + + print(unittest_preamble+function_call+'RecipSqrtLocal()\n{') + VariableSetup(['x']) + x = resetVecsPositive(['x']) + print('/*') + print(x) + print(1/sqrt(x)) + print('*/') + print(tab+function_call+'RecipSqrtLocal(&x); /* for accuracy */') + for i in rows: + print(tab+'TASSERT('+Equals('x.v[%d]' % (i), ('%s' % cstyle[TYPE]) % (1/sqrt(x[i])))+',"Entry _%s failed!"' % (entry[i]) + ');') + + EndTest() + + commbreak() + + print(unittest_preamble+function_call+'Recip()\n{') + VariableSetup(['x','w']) + x,w = resetVecsPositive(['x','w']) + print('/*') + print(x) + print(1/x) + print('*/') + print(tab+function_call+'Recip(&x,&w);') + for i in rows: + print(tab+'TASSERT('+Equals('w.v[%d]' % (i), ('%s' % cstyle[TYPE]) % (1/x[i]))+',"Entry _%s failed!"' % (entry[i]) + ');') + + EndTest() + + commbreak() + + print(unittest_preamble+function_call+'RecipLocal()\n{') + VariableSetup(['x']) + x = resetVecsPositive(['x']) + print('/*') + print(x) + print(1/sqrt(x)) + print('*/') + print(tab+function_call+'RecipLocal(&x); /* for accuracy */') + for i in rows: + print(tab+'TASSERT('+Equals('x.v[%d]' % (i), ('%s' % cstyle[TYPE]) % (1/x[i]))+',"Entry _%s failed!"' % (entry[i]) + ');') + + EndTest() + + commbreak() + + print(unittest_preamble+function_call+'Normalize()\n{') + VariableSetup(['x','w']) + x,w = resetVecs(['x','w']) + print('/*') + print(x) + print(x/sqrt(sum(x**2))) + print('*/') + print(tab+function_call+'Normalize(&x,&w);') + for i in rows: + print(tab+'TASSERT('+Equals('w.v[%d]' % (i), ('%s' % cstyle[TYPE]) % ((x/sqrt(sum(x**2)))[i]))+',"Entry _%s failed!"' % (entry[i]) + ');') + + EndTest() + + commbreak() + + print(unittest_preamble+function_call+'NormalizeLocal()\n{') + VariableSetup(['x']) + x = resetVecs(['x']) + print('/*') + print(x) + print(x/sqrt(sum(x**2))) + print('*/') + print(tab+function_call+'NormalizeLocal(&x); /* for accuracy */') + for i in rows: + print(tab+'TASSERT('+Equals('x.v[%d]' % (i), ('%s' % cstyle[TYPE]) % ((x/sqrt(sum(x**2)))[i]))+',"Entry _%s failed!"' % (entry[i]) + ');') + + EndTest() + + commbreak() + + print(unittest_preamble+function_call+'Project()\n{') + VariableSetup(['x','y','w']) + x,y,w = resetVecs(['x','y','w']) + w = project(x,y) + print('/*') + print(x) + print(y) + print( w ) + print('*/') + print(tab+function_call+'Project(&x,&y,&w);') + for i in rows: + print(tab+'TASSERT('+Equals('w.v[%d]' % (i), ('%s' % cstyle[TYPE]) % ((w)[i]))+',"Entry _%s failed!"' % (entry[i]) + ');') + + EndTest() + + commbreak() + + print(unittest_preamble+function_call+'ProjectLocal()\n{') + VariableSetup(['x','y']) + x,y = resetVecs(['x','y']) + w = project(x,y) + print('/*') + print(x) + print(y) + print(w) + print('*/') + print(tab+function_call+'ProjectLocal(&x,&y); /* for accuracy */') + for i in rows: + print(tab+'TASSERT('+Equals('x.v[%d]' % (i), ('%s' % cstyle[TYPE]) % ((w)[i]))+',"Entry _%s failed!"' % (entry[i]) + ');') + + EndTest() + + commbreak() + + if(N==2): + print(unittest_preamble+function_call+'Cross()\n{') + VariableSetup(['x','y','w']) + x,y,w = resetVecs(['x','y','w']) + w = cross(x,y) + print('/*') + print(x) + print(y) + print(w) + print('*/') + print(tab+function_call+'Cross(&x,&y,&w);') + for i in rows: + print(tab+'TASSERT('+Equals('w.v[%d]' % (i), ('%s' % cstyle[TYPE]) % ((w)))+',"Entry _%s failed!"' % (entry[i]) + ');') + + EndTest() + + commbreak() + + print(unittest_preamble+function_call+'CrossLocal()\n{') + VariableSetup(['x','y']) + x,y = resetVecs(['x','y']) + w = cross(x,y) + print('/*') + print(x) + print(y) + print(w) + print('*/') + print(tab+function_call+'CrossLocal(&x,&y); /* for accuracy */') + for i in rows: + print(tab+'TASSERT('+Equals('x.v[%d]' % (i), ('%s' % cstyle[TYPE]) % ((w)))+',"Entry _%s failed!"' % (entry[i]) + ');') + + EndTest() + + if(N==3): + print(unittest_preamble+function_call+'Cross()\n{') + VariableSetup(['x','y','w']) + x,y,w = resetVecs(['x','y','w']) + w = cross(x,y) + print('/*') + print(x) + print(y) + print(w) + print('*/') + print(tab+function_call+'Cross(&x,&y,&w);') + for i in rows: + print(tab+'TASSERT('+Equals('w.v[%d]' % (i), ('%s' % cstyle[TYPE]) % ((w)[i]))+',"Entry _%s failed!"' % (entry[i]) + ');') + + EndTest() + + commbreak() + + print(unittest_preamble+function_call+'CrossLocal()\n{') + VariableSetup(['x','y']) + x,y = resetVecs(['x','y']) + w = cross(x,y) + print('/*') + print(x) + print(y) + print(w) + print('*/') + print(tab+function_call+'CrossLocal(&x,&y); /* for accuracy */') + for i in rows: + print(tab+'TASSERT('+Equals('x.v[%d]' % (i), ('%s' % cstyle[TYPE]) % ((w)[i]))+',"Entry _%s failed!"' % (entry[i]) + ');') + + EndTest() + + commbreak() + + print(unittest_preamble+function_call+'RotateAbout()\n{') + VariableSetup(['x','y','w']) + x = array([1,0,0],dtype=DTYPE[TYPE]) + y = array([0,0,1],dtype=DTYPE[TYPE]) + w = array([0,1,0],dtype=DTYPE[TYPE]) + for i in rows: + print(tab+('x.v[%d] = %s;' % (i,cstyle[TYPE])) % (x[i])) + + for i in rows: + print(tab+('y.v[%d] = %s;' % (i,cstyle[TYPE])) % (y[i])) + + print('/*') + print(x) + print(y) + print(w) + print('*/') + print(tab+function_call+'RotateAbout(&x,&y,%s,&w);' % (cstyle[TYPE] % (pi/2)) ) + for i in rows: + print(tab+'TASSERT('+Equals('w.v[%d]' % (i), ('%s' % cstyle[TYPE]) % ((w)[i]))+',"Entry _%s failed!"' % (entry[i]) + ');') + + EndTest() + + commbreak() + + print(unittest_preamble+function_call+'RotateAboutLocal()\n{') + VariableSetup(['x','y']) + x = array([1,0,0],dtype=DTYPE[TYPE]) + y = array([0,0,1],dtype=DTYPE[TYPE]) + w = array([0,1,0],dtype=DTYPE[TYPE]) + for i in rows: + print(tab+('x.v[%d] = %s;' % (i,cstyle[TYPE])) % (x[i])) + + for i in rows: + print(tab+('y.v[%d] = %s;' % (i,cstyle[TYPE])) % (y[i])) + + print('/*') + print(x) + print(y) + print(w) + print('*/') + print(tab+function_call+'RotateAboutLocal(&x,&y,%s);' % (cstyle[TYPE] % (pi/2)) ) + for i in rows: + print(tab+'TASSERT('+Equals('x.v[%d]' % (i), ('%s' % cstyle[TYPE]) % ((w)[i]))+',"Entry _%s failed!"' % (entry[i]) + ');') + + EndTest() + + commbreak() + + print(unittest_preamble+function_call+'Magnitude()\n{') + VariableSetup(['x','a']) + x = resetVecs(['x']) + print('/*') + print(x) + print(sqrt(sum(x**2))) + print('*/') + print(tab+'a = '+function_call+'Magnitude(&x);') + print(tab+'TASSERT('+Equals('a' , ('%s' % cstyle[TYPE]) % ((sqrt(sum(x**2)))))+',"Magnitude failed!");') + + EndTest() + + commbreak() + + print(unittest_preamble+function_call+'MagnitudeSquared()\n{') + VariableSetup(['x','a']) + x = resetVecs(['x']) + print('/*') + print(x) + print(sum(x**2)) + print('*/') + print(tab+'a = '+function_call+'MagnitudeSquared(&x);') + print(tab+'TASSERT('+Equals('a' , ('%s' % cstyle[TYPE]) % (((sum(x**2)))))+',"MagnitudeSquared failed!");') + + EndTest() + + commbreak() + + print(unittest_preamble+function_call+'Dot()\n{') + VariableSetup(['x','y','a']) + x,y = resetVecs(['x','y']) + a = dot(x,y) + print('/*') + print(x) + print(dot(x,y)) + print('*/') + print(tab+'a = '+function_call+'Dot(&x,&y);') + print(tab+'TASSERT('+Equals('a' , ('%s' % cstyle[TYPE]) % (a))+',"Dot failed!");') + + EndTest() + + commbreak() diff --git a/libsst-math/dump_MatNN_headers.sh b/libsst-math/dump_MatNN_headers.sh new file mode 100644 index 0000000..fdd42ec --- /dev/null +++ b/libsst-math/dump_MatNN_headers.sh @@ -0,0 +1,216 @@ +#!/bin/sh +HEADERPATH=../Lib/Include/SST +echo "/* NEXT FILE */ +/* This is an AUTOGENERATED FILE generated from the bash script 'dumpheader.sh', last generated on `date` */ +#ifndef __SST_MAT22_H__ +#define __SST_MAT22_H__ +#include <SST/SST_Build.h> +#include <SST/SST_Vec2.h> +#include <pstdbool.h> +#if SST_COMPILER == SST_COMPILER_MSVC +#pragma warning(disable:4201) +#endif +#ifdef __cplusplus +extern \"C\" { +#endif + typedef SST_ALIGN_PREFIX(16) union SST_Mat22f + { + float v[4]; + struct { float a11, a21, a12, a22; }; + } SST_ALIGN_SUFFIX(16) SST_Mat22f; + + typedef SST_ALIGN_PREFIX(16) union SST_Mat22d + { + double v[4]; + struct { double a11, a21, a12, a22; }; + } SST_ALIGN_SUFFIX(16) SST_Mat22d; + + typedef SST_ALIGN_PREFIX(16) union SST_Mat22i + { + int v[4]; + struct { int a11, a21, a12, a22; }; + } SST_ALIGN_SUFFIX(16) SST_Mat22i; + + typedef SST_ALIGN_PREFIX(16) union SST_Mat22u + { + unsigned int v[4]; + struct { unsigned int a11, a21, a12, a22; }; + } SST_ALIGN_SUFFIX(16) SST_Mat22u;" > $HEADERPATH/SST_Mat22.h + echo " + /*########################################################## + ## float + ##########################################################*/" >> $HEADERPATH/SST_Mat22.h +grep -h "^[bvfdiu][Boln][iouts].* SST_Math_Mat" SST_Mat22f.c | sed -e "s/$/;/" -e "s/^/ /" >> $HEADERPATH/SST_Mat22.h + echo " + /*########################################################## + ## double + ##########################################################*/" >> $HEADERPATH/SST_Mat22.h +grep -h "^[bvfdiu][Boln][iouts].* SST_Math_Mat" SST_Mat22d.c | sed -e "s/$/;/" -e "s/^/ /" >> $HEADERPATH/SST_Mat22.h + echo " + /*########################################################## + ## int + ##########################################################*/" >> $HEADERPATH/SST_Mat22.h +grep -h "^[bvfdiu][Boln][iouts].* SST_Math_Mat" SST_Mat22i.c | sed -e "s/$/;/" -e "s/^/ /" >> $HEADERPATH/SST_Mat22.h + echo " + /*########################################################## + ## unsigned int + ##########################################################*/" >> $HEADERPATH/SST_Mat22.h +grep -h "^[bvfdiu][Boln][iouts].* SST_Math_Mat" SST_Mat22u.c | sed -e "s/$/;/" -e "s/^/ /" >> $HEADERPATH/SST_Mat22.h +echo "#ifdef __cplusplus +} +#endif +#if SST_COMPILER == SST_COMPILER_MSVC +#pragma warning(default:4201) +#endif +#endif" >> $HEADERPATH/SST_Mat22.h +echo "/* NEXT FILE */ +/* This is an AUTOGENERATED FILE generated from the bash script 'dumpheader.sh', last generated on `date` */ +#ifndef __SST_MAT33_H__ +#define __SST_MAT33_H__ +#include <SST/SST_Build.h> +#include <SST/SST_Vec3.h> +#include <pstdbool.h> + +#if SST_COMPILER == SST_COMPILER_MSVC +#pragma warning(disable:4201) +#endif +#ifdef __cplusplus +extern \"C\" { +#endif +#define PAD 3 /* spaces it out to 4 * T for better alignment */ + typedef SST_ALIGN_PREFIX(16) union SST_Mat33f + { + float v[9+PAD]; + struct { float a11, a21, a31, + a12, a22, a32, + a13, a23, a33; }; + } SST_ALIGN_SUFFIX(16) SST_Mat33f; + + typedef SST_ALIGN_PREFIX(16) union SST_Mat33d + { + double v[9+PAD]; + struct { double a11, a21, a31, + a12, a22, a32, + a13, a23, a33; }; + } SST_ALIGN_SUFFIX(16) SST_Mat33d; + + typedef SST_ALIGN_PREFIX(16) union SST_Mat33u + { + unsigned int v[9+PAD]; + struct { unsigned int a11, a21, a31, + a12, a22, a32, + a13, a23, a33; }; + } SST_ALIGN_SUFFIX(16) SST_Mat33u; + + typedef SST_ALIGN_PREFIX(16) union SST_Mat33i + { + int v[9+PAD]; + struct { int a11, a21, a31, + a12, a22, a32, + a13, a23, a33; }; + } SST_ALIGN_SUFFIX(16) SST_Mat33i; +#undef PAD" > $HEADERPATH/SST_Mat33.h + echo " + /*########################################################## + ## float + ##########################################################*/" >> $HEADERPATH/SST_Mat33.h +grep -h "^[bvfdiu][Boln][iouts].* SST_Math_Mat" SST_Mat33f.c | sed -e "s/$/;/" -e "s/^/ /" >> $HEADERPATH/SST_Mat33.h + echo " + /*########################################################## + ## double + ##########################################################*/" >> $HEADERPATH/SST_Mat33.h +grep -h "^[bvfdiu][Boln][iouts].* SST_Math_Mat" SST_Mat33d.c | sed -e "s/$/;/" -e "s/^/ /" >> $HEADERPATH/SST_Mat33.h + echo " + /*########################################################## + ## int + ##########################################################*/" >> $HEADERPATH/SST_Mat33.h +grep -h "^[bvfdiu][Boln][iouts].* SST_Math_Mat" SST_Mat33i.c | sed -e "s/$/;/" -e "s/^/ /" >> $HEADERPATH/SST_Mat33.h + echo " + /*########################################################## + ## unsigned int + ##########################################################*/" >> $HEADERPATH/SST_Mat33.h +grep -h "^[bvfdiu][Boln][iouts].* SST_Math_Mat" SST_Mat33u.c | sed -e "s/$/;/" -e "s/^/ /" >> $HEADERPATH/SST_Mat33.h +echo "#ifdef __cplusplus +} +#endif +#if SST_COMPILER == SST_COMPILER_MSVC +#pragma warning(default:4201) +#endif +#endif" >> $HEADERPATH/SST_Mat33.h +echo "/* NEXT FILE */ +/* This is an AUTOGENERATED FILE generated from the bash script 'dumpheader.sh', last generated on `date` */ +#ifndef __SST_MAT44_H__ +#define __SST_MAT44_H__ +#include <SST/SST_Build.h> +#include <SST/SST_Vec4.h> +#include <pstdbool.h> + +#if SST_COMPILER == SST_COMPILER_MSVC +#pragma warning(disable:4201) +#endif +#ifdef __cplusplus +extern \"C\" { +#endif + + typedef SST_ALIGN_PREFIX(16) union SST_Mat44f + { + float v[16]; + struct { float a11, a21, a31, a41, + a12, a22, a32, a42, + a13, a23, a33, a43, + a14, a24, a34, a44; }; + } SST_ALIGN_SUFFIX(16) SST_Mat44f; + + typedef SST_ALIGN_PREFIX(16) union SST_Mat44d + { + double v[16]; + struct { double a11, a21, a31, a41, + a12, a22, a32, a42, + a13, a23, a33, a43, + a14, a24, a34, a44; }; + } SST_ALIGN_SUFFIX(16) SST_Mat44d; + + typedef SST_ALIGN_PREFIX(16) union SST_Mat44i + { + int v[16]; + struct { int a11, a21, a31, a41, + a12, a22, a32, a42, + a13, a23, a33, a43, + a14, a24, a34, a44; }; + } SST_ALIGN_SUFFIX(16) SST_Mat44i; + + typedef SST_ALIGN_PREFIX(16) union SST_Mat44u + { + unsigned int v[16]; + struct { unsigned int a11, a21, a31, a41, + a12, a22, a32, a42, + a13, a23, a33, a43, + a14, a24, a34, a44; }; + } SST_ALIGN_SUFFIX(16) SST_Mat44u;" > $HEADERPATH/SST_Mat44.h + echo " + /*########################################################## + ## float + ##########################################################*/" >> $HEADERPATH/SST_Mat44.h +grep -h "^[bvfdiu][Boln][iouts].* SST_Math_Mat" SST_Mat44f.c | sed -e "s/$/;/" -e "s/^/ /" >> $HEADERPATH/SST_Mat44.h + echo " + /*########################################################## + ## double + ##########################################################*/" >> $HEADERPATH/SST_Mat44.h +grep -h "^[bvfdiu][Boln][iouts].* SST_Math_Mat" SST_Mat44d.c | sed -e "s/$/;/" -e "s/^/ /" >> $HEADERPATH/SST_Mat44.h + echo " + /*########################################################## + ## int + ##########################################################*/" >> $HEADERPATH/SST_Mat44.h +grep -h "^[bvfdiu][Boln][iouts].* SST_Math_Mat" SST_Mat44i.c | sed -e "s/$/;/" -e "s/^/ /" >> $HEADERPATH/SST_Mat44.h + echo " + /*########################################################## + ## unsigned int + ##########################################################*/" >> $HEADERPATH/SST_Mat44.h +grep -h "^[bvfdiu][Boln][iouts].* SST_Math_Mat" SST_Mat44u.c | sed -e "s/$/;/" -e "s/^/ /" >> $HEADERPATH/SST_Mat44.h +echo "#ifdef __cplusplus +} +#endif +#if SST_COMPILER == SST_COMPILER_MSVC +#pragma warning(default:4201) +#endif +#endif" >> $HEADERPATH/SST_Mat44.h diff --git a/libsst-math/dump_VecN_headers.sh b/libsst-math/dump_VecN_headers.sh new file mode 100644 index 0000000..af31d2d --- /dev/null +++ b/libsst-math/dump_VecN_headers.sh @@ -0,0 +1,197 @@ +#!/bin/sh +HEADERPATH=../Lib/Include/SST +echo "/* NEXT FILE */ +/* This is an AUTOGENERATED FILE generated from the bash script 'dump_VecN_headers.sh', last generated on `date` */ +#ifndef __SST_VEC2_H__ +#define __SST_VEC2_H__ +#include <SST/SST_Build.h> +#include <SST/SST_Vec2.h> +#include <pstdbool.h> + +#if SST_COMPILER == SST_COMPILER_MSVC +#pragma warning(disable:4201) +#endif +#ifdef __cplusplus +extern \"C\" { +#endif + typedef SST_ALIGN_PREFIX(16) union SST_Vec2f + { + float v[2]; + struct { float x, y; }; + } SST_ALIGN_SUFFIX(16) SST_Vec2f; + + typedef SST_ALIGN_PREFIX(16) union SST_Vec2d + { + double v[2]; + struct { double x, y; }; + } SST_ALIGN_SUFFIX(16) SST_Vec2d; + + typedef SST_ALIGN_PREFIX(16) union SST_Vec2i + { + int v[2]; + struct { int x, y; }; + } SST_ALIGN_SUFFIX(16) SST_Vec2i; + + typedef SST_ALIGN_PREFIX(16) union SST_Vec2u + { + unsigned int v[2]; + struct { unsigned int x, y; }; + } SST_ALIGN_SUFFIX(16) SST_Vec2u;" > $HEADERPATH/SST_Vec2.h + echo " + /*########################################################## + ## float + ##########################################################*/" >> $HEADERPATH/SST_Vec2.h +grep -h "^[bvfdiu][Boln][iouts].* SST_Math_Vec" SST_Vec2f.c | sed -e "s/$/;/" -e "s/^/ /" >> $HEADERPATH/SST_Vec2.h + echo " + /*########################################################## + ## double + ##########################################################*/" >> $HEADERPATH/SST_Vec2.h +grep -h "^[bvfdiu][Boln][iouts].* SST_Math_Vec" SST_Vec2d.c | sed -e "s/$/;/" -e "s/^/ /" >> $HEADERPATH/SST_Vec2.h + echo " + /*########################################################## + ## int + ##########################################################*/" >> $HEADERPATH/SST_Vec2.h +grep -h "^[bvfdiu][Boln][iouts].* SST_Math_Vec" SST_Vec2i.c | sed -e "s/$/;/" -e "s/^/ /" >> $HEADERPATH/SST_Vec2.h + echo " + /*########################################################## + ## unsigned int + ##########################################################*/" >> $HEADERPATH/SST_Vec2.h +grep -h "^[bvfdiu][Boln][iouts].* SST_Math_Vec" SST_Vec2u.c | sed -e "s/$/;/" -e "s/^/ /" >> $HEADERPATH/SST_Vec2.h +echo "#ifdef __cplusplus +} +#endif +#if SST_COMPILER == SST_COMPILER_MSVC +#pragma warning(default:4201) +#endif +#endif" >> $HEADERPATH/SST_Vec2.h +echo "/* NEXT FILE */ +/* This is an AUTOGENERATED FILE generated from the bash script 'dumpheader.sh', last generated on `date` */ +#ifndef __SST_VEC3_H__ +#define __SST_VEC3_H__ +#include <SST/SST_Build.h> +#include <SST/SST_Vec3.h> +#include <pstdbool.h> + +#if SST_COMPILER == SST_COMPILER_MSVC +#pragma warning(disable:4201) +#endif +#ifdef __cplusplus +extern \"C\" { +#endif +#define PAD 3 /* spaces it out to 4 * T for better alignment */ + typedef SST_ALIGN_PREFIX(16) union SST_Vec3f + { + float v[4]; + struct { float x, y, z, _pad; }; + } SST_ALIGN_SUFFIX(16) SST_Vec3f; + + typedef SST_ALIGN_PREFIX(16) union SST_Vec3d + { + double v[4]; + struct { double x, y, z, _pad; }; + } SST_ALIGN_SUFFIX(16) SST_Vec3d; + + typedef SST_ALIGN_PREFIX(16) union SST_Vec3i + { + int v[4]; + struct { int x, y, z, _pad; }; + } SST_ALIGN_SUFFIX(16) SST_Vec3i; + + typedef SST_ALIGN_PREFIX(16) union SST_Vec3u + { + unsigned int v[4]; + struct { unsigned int x, y, z, _pad; }; + } SST_ALIGN_SUFFIX(16) SST_Vec3u; +#undef PAD" > $HEADERPATH/SST_Vec3.h + echo " + /*########################################################## + ## float + ##########################################################*/" >> $HEADERPATH/SST_Vec3.h +grep -h "^[bvfdiu][Boln][iouts].* SST_Math_Vec" SST_Vec3f.c | sed -e "s/$/;/" -e "s/^/ /" >> $HEADERPATH/SST_Vec3.h + echo " + /*########################################################## + ## double + ##########################################################*/" >> $HEADERPATH/SST_Vec3.h +grep -h "^[bvfdiu][Boln][iouts].* SST_Math_Vec" SST_Vec3d.c | sed -e "s/$/;/" -e "s/^/ /" >> $HEADERPATH/SST_Vec3.h + echo " + /*########################################################## + ## int + ##########################################################*/" >> $HEADERPATH/SST_Vec3.h +grep -h "^[bvfdiu][Boln][iouts].* SST_Math_Vec" SST_Vec3i.c | sed -e "s/$/;/" -e "s/^/ /" >> $HEADERPATH/SST_Vec3.h + echo " + /*########################################################## + ## unsigned int + ##########################################################*/" >> $HEADERPATH/SST_Vec3.h +grep -h "^[bvfdiu][Boln][iouts].* SST_Math_Vec" SST_Vec3u.c | sed -e "s/$/;/" -e "s/^/ /" >> $HEADERPATH/SST_Vec3.h +echo "#ifdef __cplusplus +} +#endif +#if SST_COMPILER == SST_COMPILER_MSVC +#pragma warning(default:4201) +#endif +#endif" >> $HEADERPATH/SST_Vec3.h +echo "/* NEXT FILE */ +/* This is an AUTOGENERATED FILE generated from the bash script 'dumpheader.sh', last generated on `date` */ +#ifndef __SST_VEC4_H__ +#define __SST_VEC4_H__ +#include <SST/SST_Build.h> +#include <SST/SST_Vec4.h> +#include <pstdbool.h> + +#if SST_COMPILER == SST_COMPILER_MSVC +#pragma warning(disable:4201) +#endif +#ifdef __cplusplus +extern \"C\" { +#endif + + typedef SST_ALIGN_PREFIX(16) union SST_Vec4f + { + float v[4]; + struct { float x, y, z, w; }; + } SST_ALIGN_SUFFIX(16) SST_Vec4f; + + typedef SST_ALIGN_PREFIX(16) union SST_Vec4d + { + double v[4]; + struct { double x, y, z, w; }; + } SST_ALIGN_SUFFIX(16) SST_Vec4d; + + typedef SST_ALIGN_PREFIX(16) union SST_Vec4i + { + int v[4]; + struct { int x, y, z, w; }; + } SST_ALIGN_SUFFIX(16) SST_Vec4i; + + typedef SST_ALIGN_PREFIX(16) union SST_Vec4u + { + unsigned int v[4]; + struct { unsigned int x, y, z, w; }; + } SST_ALIGN_SUFFIX(16) SST_Vec4u;" > $HEADERPATH/SST_Vec4.h + echo " + /*########################################################## + ## float + ##########################################################*/" >> $HEADERPATH/SST_Vec4.h +grep -h "^[bvfdiu][Boln][iouts].* SST_Math_Vec" SST_Vec4f.c | sed -e "s/$/;/" -e "s/^/ /" >> $HEADERPATH/SST_Vec4.h + echo " + /*########################################################## + ## double + ##########################################################*/" >> $HEADERPATH/SST_Vec4.h +grep -h "^[bvfdiu][Boln][iouts].* SST_Math_Vec" SST_Vec4d.c | sed -e "s/$/;/" -e "s/^/ /" >> $HEADERPATH/SST_Vec4.h + echo " + /*########################################################## + ## int + ##########################################################*/" >> $HEADERPATH/SST_Vec4.h +grep -h "^[bvfdiu][Boln][iouts].* SST_Math_Vec" SST_Vec4i.c | sed -e "s/$/;/" -e "s/^/ /" >> $HEADERPATH/SST_Vec4.h + echo " + /*########################################################## + ## unsigned int + ##########################################################*/" >> $HEADERPATH/SST_Vec4.h +grep -h "^[bvfdiu][Boln][iouts].* SST_Math_Vec" SST_Vec4u.c | sed -e "s/$/;/" -e "s/^/ /" >> $HEADERPATH/SST_Vec4.h +echo "#ifdef __cplusplus +} +#endif +#if SST_COMPILER == SST_COMPILER_MSVC +#pragma warning(default:4201) +#endif +#endif" >> $HEADERPATH/SST_Vec4.h diff --git a/libsst-math/libsst-math.vcxproj b/libsst-math/libsst-math.vcxproj new file mode 100644 index 0000000..030df5b --- /dev/null +++ b/libsst-math/libsst-math.vcxproj @@ -0,0 +1,224 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup Label="ProjectConfigurations"> + <ProjectConfiguration Include="Debug|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectGuid>{27B995C6-2B30-4852-B796-12E2B5883C35}</ProjectGuid> + <RootNamespace>LiblibZ</RootNamespace> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> + <ConfigurationType>StaticLibrary</ConfigurationType> + <PlatformToolset>v110</PlatformToolset> + <CharacterSet>MultiByte</CharacterSet> + <WholeProgramOptimization>true</WholeProgramOptimization> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> + <ConfigurationType>StaticLibrary</ConfigurationType> + <PlatformToolset>v110</PlatformToolset> + <CharacterSet>MultiByte</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> + <ConfigurationType>StaticLibrary</ConfigurationType> + <PlatformToolset>v110</PlatformToolset> + <CharacterSet>MultiByte</CharacterSet> + <WholeProgramOptimization>true</WholeProgramOptimization> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> + <ConfigurationType>StaticLibrary</ConfigurationType> + <PlatformToolset>v110</PlatformToolset> + <CharacterSet>MultiByte</CharacterSet> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <ImportGroup Label="ExtensionSettings"> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <PropertyGroup Label="UserMacros" /> + <PropertyGroup> + <_ProjectFileVersion>11.0.50727.1</_ProjectFileVersion> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <OutDir>$(SolutionDir)\Lib\x86\</OutDir> + <IntDir>$(SolutionDir)Intermediate\$(Configuration)\$(Platform)\$(ProjectName)\</IntDir> + <TargetName>$(ProjectName)-debug</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <OutDir>$(SolutionDir)\Lib\x64\</OutDir> + <IntDir>$(SolutionDir)Intermediate\$(Configuration)\$(Platform)\$(ProjectName)\</IntDir> + <TargetName>$(ProjectName)-debug</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <OutDir>$(SolutionDir)\Lib\x86\</OutDir> + <IntDir>$(SolutionDir)Intermediate\$(Configuration)\$(Platform)\$(ProjectName)\</IntDir> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <OutDir>$(SolutionDir)\Lib\x64\</OutDir> + <IntDir>$(SolutionDir)Intermediate\$(Configuration)\$(Platform)\$(ProjectName)\</IntDir> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <Optimization>Disabled</Optimization> + <AdditionalIncludeDirectories>..\Lib\Include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <MinimalRebuild>false</MinimalRebuild> + <ExceptionHandling /> + <BasicRuntimeChecks>Default</BasicRuntimeChecks> + <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> + <BufferSecurityCheck>false</BufferSecurityCheck> + <FunctionLevelLinking>true</FunctionLevelLinking> + <EnableEnhancedInstructionSet>NotSet</EnableEnhancedInstructionSet> + <RuntimeTypeInfo>false</RuntimeTypeInfo> + <WarningLevel>Level4</WarningLevel> + <TreatWarningAsError>false</TreatWarningAsError> + <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> + <CompileAs>CompileAsC</CompileAs> + <DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings> + <MultiProcessorCompilation>true</MultiProcessorCompilation> + <WholeProgramOptimization>true</WholeProgramOptimization> + </ClCompile> + <Lib /> + <Lib> + <LinkTimeCodeGeneration>true</LinkTimeCodeGeneration> + </Lib> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Midl> + <TargetEnvironment>X64</TargetEnvironment> + </Midl> + <ClCompile> + <Optimization>Disabled</Optimization> + <AdditionalIncludeDirectories>..\Lib\Include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <MinimalRebuild>false</MinimalRebuild> + <ExceptionHandling /> + <BasicRuntimeChecks>Default</BasicRuntimeChecks> + <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> + <BufferSecurityCheck>false</BufferSecurityCheck> + <FunctionLevelLinking>true</FunctionLevelLinking> + <EnableEnhancedInstructionSet>NotSet</EnableEnhancedInstructionSet> + <RuntimeTypeInfo>false</RuntimeTypeInfo> + <WarningLevel>Level3</WarningLevel> + <TreatWarningAsError>false</TreatWarningAsError> + <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> + <CompileAs>CompileAsC</CompileAs> + <MultiProcessorCompilation>true</MultiProcessorCompilation> + <WholeProgramOptimization>true</WholeProgramOptimization> + </ClCompile> + <Lib /> + <Lib> + <LinkTimeCodeGeneration>true</LinkTimeCodeGeneration> + </Lib> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <Optimization>MaxSpeed</Optimization> + <IntrinsicFunctions>true</IntrinsicFunctions> + <AdditionalIncludeDirectories>..\Lib\Include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <MinimalRebuild>false</MinimalRebuild> + <ExceptionHandling /> + <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> + <BufferSecurityCheck>false</BufferSecurityCheck> + <FunctionLevelLinking>true</FunctionLevelLinking> + <EnableEnhancedInstructionSet>NotSet</EnableEnhancedInstructionSet> + <DisableLanguageExtensions>false</DisableLanguageExtensions> + <RuntimeTypeInfo>false</RuntimeTypeInfo> + <WarningLevel>Level3</WarningLevel> + <TreatWarningAsError>false</TreatWarningAsError> + <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> + <DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings> + <MultiProcessorCompilation>true</MultiProcessorCompilation> + </ClCompile> + <Lib /> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Midl> + <TargetEnvironment>X64</TargetEnvironment> + </Midl> + <ClCompile> + <Optimization>MaxSpeed</Optimization> + <IntrinsicFunctions>true</IntrinsicFunctions> + <AdditionalIncludeDirectories>..\Lib\Include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <MinimalRebuild>false</MinimalRebuild> + <ExceptionHandling /> + <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> + <BufferSecurityCheck>false</BufferSecurityCheck> + <FunctionLevelLinking>true</FunctionLevelLinking> + <EnableEnhancedInstructionSet>NotSet</EnableEnhancedInstructionSet> + <RuntimeTypeInfo>false</RuntimeTypeInfo> + <WarningLevel>Level3</WarningLevel> + <TreatWarningAsError>false</TreatWarningAsError> + <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> + <MultiProcessorCompilation>true</MultiProcessorCompilation> + </ClCompile> + <Lib /> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="SST_Geo.c" /> + <ClCompile Include="SST_Mat22d.c" /> + <ClCompile Include="SST_Mat22f.c" /> + <ClCompile Include="SST_Mat22i.c" /> + <ClCompile Include="SST_Mat22u.c" /> + <ClCompile Include="SST_Mat33d.c" /> + <ClCompile Include="SST_Mat33f.c" /> + <ClCompile Include="SST_Mat33i.c" /> + <ClCompile Include="SST_Mat33u.c" /> + <ClCompile Include="SST_Mat44d.c" /> + <ClCompile Include="SST_Mat44f.c" /> + <ClCompile Include="SST_Mat44i.c" /> + <ClCompile Include="SST_Mat44u.c" /> + <ClCompile Include="SST_Transform.c" /> + <ClCompile Include="SST_Vec2d.c" /> + <ClCompile Include="SST_Vec2f.c" /> + <ClCompile Include="SST_Vec2i.c" /> + <ClCompile Include="SST_Vec2u.c" /> + <ClCompile Include="SST_Vec3d.c" /> + <ClCompile Include="SST_Vec3f.c" /> + <ClCompile Include="SST_Vec3i.c" /> + <ClCompile Include="SST_Vec3u.c" /> + <ClCompile Include="SST_Vec4d.c" /> + <ClCompile Include="SST_Vec4f.c" /> + <ClCompile Include="SST_Vec4i.c" /> + <ClCompile Include="SST_Vec4u.c" /> + </ItemGroup> + <ItemGroup> + <ClInclude Include="..\Lib\Include\SST\SST_Geo.h" /> + <ClInclude Include="..\Lib\Include\SST\SST_Mat22.h" /> + <ClInclude Include="..\Lib\Include\SST\SST_Mat33.h" /> + <ClInclude Include="..\Lib\Include\SST\SST_Mat44.h" /> + <ClInclude Include="..\Lib\Include\SST\SST_Math.h" /> + <ClInclude Include="..\Lib\Include\SST\SST_Transform.h" /> + <ClInclude Include="..\Lib\Include\SST\SST_Vec2.h" /> + <ClInclude Include="..\Lib\Include\SST\SST_Vec3.h" /> + <ClInclude Include="..\Lib\Include\SST\SST_Vec4.h" /> + </ItemGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> + <ImportGroup Label="ExtensionTargets"> + </ImportGroup> +</Project> \ No newline at end of file diff --git a/libsst-math/libsst-math.vcxproj.filters b/libsst-math/libsst-math.vcxproj.filters new file mode 100644 index 0000000..4f5ae48 --- /dev/null +++ b/libsst-math/libsst-math.vcxproj.filters @@ -0,0 +1,122 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup> + <Filter Include="Source Files"> + <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier> + <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions> + </Filter> + <Filter Include="Header Files"> + <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier> + <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> + </Filter> + </ItemGroup> + <ItemGroup> + <ClCompile Include="SST_Geo.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="SST_Mat22d.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="SST_Mat22f.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="SST_Mat22i.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="SST_Mat22u.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="SST_Mat33d.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="SST_Mat33f.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="SST_Mat33i.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="SST_Mat33u.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="SST_Mat44d.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="SST_Mat44f.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="SST_Mat44i.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="SST_Mat44u.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="SST_Transform.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="SST_Vec2d.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="SST_Vec2f.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="SST_Vec2i.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="SST_Vec2u.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="SST_Vec3d.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="SST_Vec3f.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="SST_Vec3i.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="SST_Vec3u.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="SST_Vec4d.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="SST_Vec4f.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="SST_Vec4i.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="SST_Vec4u.c"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> + <ItemGroup> + <ClInclude Include="..\Lib\Include\SST\SST_Mat22.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\Lib\Include\SST\SST_Mat33.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\Lib\Include\SST\SST_Mat44.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\Lib\Include\SST\SST_Math.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\Lib\Include\SST\SST_Transform.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\Lib\Include\SST\SST_Vec2.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\Lib\Include\SST\SST_Vec3.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\Lib\Include\SST\SST_Vec4.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\Lib\Include\SST\SST_Geo.h"> + <Filter>Header Files</Filter> + </ClInclude> + </ItemGroup> +</Project> \ No newline at end of file diff --git a/libsst-math/obj/x86-64/release/SST_Geo.o b/libsst-math/obj/x86-64/release/SST_Geo.o new file mode 100644 index 0000000000000000000000000000000000000000..1d6be1813bf5729c5c64c59cae2cc3624a6a7472 GIT binary patch literal 12104 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 O2{sWzfb4^?AS3|C0~z`N literal 0 HcmV?d00001 diff --git a/libsst-math/obj/x86-64/release/SST_Mat22d.o b/libsst-math/obj/x86-64/release/SST_Mat22d.o new file mode 100644 index 0000000000000000000000000000000000000000..f098473ad7e4c019170f877ac310c2d56e2bc07e GIT binary patch literal 9960 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 GfGGg^m1!{m literal 0 HcmV?d00001 diff --git a/libsst-math/obj/x86-64/release/SST_Mat22f.o b/libsst-math/obj/x86-64/release/SST_Mat22f.o new file mode 100644 index 0000000000000000000000000000000000000000..b2c0ce34c7979ea33df446ab467fe88f668ce72c GIT binary patch literal 9936 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 Uq5(>JKr6KCXoiFAgDL@2097eiIRF3v literal 0 HcmV?d00001 diff --git a/libsst-math/obj/x86-64/release/SST_Mat22i.o b/libsst-math/obj/x86-64/release/SST_Mat22i.o new file mode 100644 index 0000000000000000000000000000000000000000..bda319a51920f458e121759224f01d99507a7261 GIT binary patch literal 5056 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 Wuzv;*$P@;K{~!w>OfZSYWdHzX56R#F literal 0 HcmV?d00001 diff --git a/libsst-math/obj/x86-64/release/SST_Mat22u.o b/libsst-math/obj/x86-64/release/SST_Mat22u.o new file mode 100644 index 0000000000000000000000000000000000000000..534ce384a5553a9f8a7a47bc55bffa33428e02f2 GIT binary patch literal 4536 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 MSpYH+iqW_X04h@?DgXcg literal 0 HcmV?d00001 diff --git a/libsst-math/obj/x86-64/release/SST_Mat33d.o b/libsst-math/obj/x86-64/release/SST_Mat33d.o new file mode 100644 index 0000000000000000000000000000000000000000..70af40dcdc9bb15e16dabc7872240a9d7fe29478 GIT binary patch literal 18072 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 MXoiFAgDL@205#{|UjP6A literal 0 HcmV?d00001 diff --git a/libsst-math/obj/x86-64/release/SST_Mat33f.o b/libsst-math/obj/x86-64/release/SST_Mat33f.o new file mode 100644 index 0000000000000000000000000000000000000000..ee969878495a86e2577beffb5bb67fd9674cd7b9 GIT binary patch literal 17488 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 b8D>9745|d80ZK-gLm1c53<uc<k%5o^f<3Q* literal 0 HcmV?d00001 diff --git a/libsst-math/obj/x86-64/release/SST_Mat33i.o b/libsst-math/obj/x86-64/release/SST_Mat33i.o new file mode 100644 index 0000000000000000000000000000000000000000..77c780cee00f7c201c90e8f8b085e5a213c3ba73 GIT binary patch literal 7600 zcmb<-^>JfjWMqH=Mg}_u1P><4z_39I!FB*M9T<2RI2l4cI-h!U*8cG5EdAio8T!Jb z+x17cfJe9Mhi(SOLmu6(FFHZIAKd{gU_l2Ks3@5KqdR~DBFq632JwG%2k=0Id0@gI z{*UeekXawP9Ry&)ApVc;01=345tuND|D!uV0wOE{69(~rbO*>lgk@mDApVc;00oG! z0!&z8LhNA_@1c9`2Uf5B=)~%^ADv*YqI>N}C)lg#Ui;Ar_A0v9esqGpite=^onWt` zd+kRj*sJJX`_UPI;Wf0F)5IEcP*HU6!GzIb4knBib1-4Fn1czU#T-l+E#_dtXfX#9 z#_%3e%z@Ql#2i!<tJg4N4yGEL*DzxarW%{qFk=p;8k^UMh&lfC7qDeIm@v8r;o@kK z2Ny^4B3v9T`rzVdo`j2|MIc-p&6{v>d{GEdgb{}@VeEdyj77M5tbW9dN4R>de#DGP zxO%L9M2pML(l7AhlYxJ|>z7XCEa<?3Bn0)J0|&AgB>o(Dki{VWau7fkgT$MI2(lQ& zKMoSeVvzW9kU<uM_`^W~SqwRzKz;z_G=%$MafIZ4c=3qjet6s<xgTCIBDo(PCrIvx z7l}yjhsOny`{9KllKau(09zdfjl^ybP+)%O26^OQFAo#AngbWQAG$#vIn*n{h?MU@ zq5Pp6<Qq_K`~lZ3z`q_tw+R1wxNc}&0M#ymZn+E=?Fz`+A+ZKdARoFJ;M$?)u^?*) zMJAft!TJz2H4nOe6xT!bqqrVq4?;h}`5^HR-Jr-o_#Ubs#rYsHc#{C(d{FvC4|-^2 z&4KKDNFD%JvnYWN)sNzQsD2dZgVe#T2PG$H<blM|oe$NI;(T~sXny11(OG-KqqFot zibpq#ss;lCgGZ<955of<-L5CV&7%Xb=s5vN90!n-)(J?{<p3mUF`npj1-S&K5tghF zIuSlY=mhx;r1K7vl`uacbRtp|LMO;iAe}F|L&4T|3Ur5pP3a8a=?1s(PC(ilCm@YF zWUqi?8r>_PSVi*66|jTAY3%?!i=628fNDkY3sfu2FAq?(Lem#QD~e~JT4A1f(;W)7 zxHEvII}~hAXMjL==o^rUkY>^eNLv)yH=u||_YElGk$iIlWB^PjQp`ZLqWA`?73P~K zC|VJ|foetZ4OA=4Hy^q~!4`K0aCC=)&FKsf=??t>G7;3e0~Jpx9>$QASHk)N)L=h} z+L%Ra@xk*tN#z_k7AYucKsgp!JIL!q<#brny!nlRM`!H~kIvEym^tkRIHz5J<+K}+ zoOS^@r`>?$v<rxw21*+@APE~;Cn$BI>jWh+B%PpmxB*ED$T~rOLe~k3P9&W#AW8B9 zD5rr;xd2Y3puW_F&H#=HM8qbj+66iB1FTB|jz)M-1XM44fOkN^Ju%dN2fVuh^3w-+ zF9RGukj(xA+RK7u7FeGGl-QuXBxqD%iv|atPFIk>py7H0T#$eTATGSo?I6+V3i2;B z{BCpxNI;638xU9D=ys5Ss{n=Qjm`iWxC#;cK?E}RMK{Cu8;~{?EIqvF_5g*%3rKqC zyr_8)RD(kz@C776z=S}d`2t*69fApgLi<HGsBr=p0=er&H>hm_7Xk(Ri*8W43l{=~ z@C$Hd2p0k+hZo(ThRGq#gPkWjU4MXG0<{8K4<nq5C{$j+T?;N$ARd5fli*)}h!G+J z&Zba1VM3s&h1v-dg7}gFNgvcG79=64CqWf2sy?tMVM0)iGME~{MHtjskkCQ45E?kh z7D59D*+PguP-zSIAylIPl7&!>;E*}d>H4SJ^+)po=GFrhf-qJ+`wq}p$7|LdpaQb_ z0b}a{{;7wWYyU7*@PbIJ@&^<z@NYZN{D2Xf?mKHC=?mgza5V-A*Aw7KEPw`>4FCFL zpvZ+3wD8C*fCM@y?m?yZi|z`j=S29|AJ;tA`GJ4^!OrWN$H8WSn>H^X#TX<yp>{y^ z2*B+)#P|d3<3F*78Qh(ntrRpulS=bSN)=4?O!N$N%}T*M!#YDVJp&UxGfjxNf{}rt znSq&sB?E&9C`1?-7#OR97#J%A7^QjGIVLbNFvu`KFi847h;ZZ+Xk&8bWn;R<!_EPb zvjK@SFfiN((Qx@|aQPUJI0FL%F8wu7d0hJEK;^;J8r=NHaP#*-<)46Pxcq&%{2h=u z0|Ubm5Dk~#510P~5@%pwH~^yI^1I>kGN44mz`)?c#K6D+lV^5k0x1B6j}26Q4vPGA zxO@y${v3+=Cqdf5;adZh2M@%-%xC%ym!AWb??%zz2AAIhm7jqkKN&862P&U{;=X9O z`~E=Xm!jxj0M-u@!iGUwSQtM3$0o-N_6Vj7GXpcGAOiyfGXo0_aW)*{>^Q_(F~s>8 z7#M_*+yhR73=9m4P;nR^oc0(P7%ZXUyFea<rCA0BhCrzJOi&oY(mDeJLmpJT1nM<# z8f9Q$m<Sb*fqD&`HW?Tgc0$D+piTv+Nd^Xn>rinPsF%TMk%58X7gYQRR2-ZJ85kHO z7$N==;DmS?oc0(P7_1o?7z7|fD5MWm{TgnFFgPtTFfe36#jAKA;;^9Vg^BY*#KCEg zfq`KeRGbwQunY_g;4}xyTTt=2P;qctV_;x-0u}!Ybrd*_fs70e4vF_oEHO6D)JtZ7 zax$PIjwvZvgnaUo6LZkTgG-Z2iV~AcaEW8p<Xf6kl39>b>6(+8o0?Zro>`oVt{;mM zyha5lC*~v;;W7mxi`M|(#FC=S3S0(2WFZE`#}}6*CTGVdXJp5xC1zp-3C!tXsmUez zIGqHMg_wvI{2@h&dBp|!n1KS9z^ctTBQ-hOzo;Z5KQF&17c;6{QcF^cax?Q1^GX;P zmO;}YC_4!;Ffjc24*@06^oA}z9h$Dt#T7tliGhIuBo4w*E(2uF0wE5|=Lt{+AhjS2 z%jXSf;;?+a08Jd0&tdr!WCjSs^7#Wa^{{*n%U2+^APmdr3ea)}BnHB;eC~iI4$J2W zXyUN^+<+zy%g+nY#i8MQ08Jd0pC6!!!}2pYfRVx(mY*5)iYs$V5|bG8ic5+hbOwx7 zl$w*MSCU#$!l0LuSdz$~msDKLpqHGV3(9m1dU^RJse0~yp}OGY%%BHWo|+M#R+N~V z3JpezDNy<Vc?nv4!p(!Fk41uTAut1^7R-PW(hLmX+6kr}D$LL!0bzMSC<ZQ2+lhgJ zfdk5iN;9ZI#i7*$RF;9^5t_X)33U5)pk|V*-w<lQ0n7p@4YS`A%7;-f`(d;dR6k4} zMvH?oEsTRi!}P&~{Gs|mX&WX6q9vgECD0^b;RjL!!d^JS{{l3CVd)+e{-9O?Og~hb z0Tj&WVFxld06M=J3F07OboYb!XifyHHh?ymBcPI?;tXUr2!j;B><3lP*zE5R1F2$Q O_z$uG!UU6OTm}HCgaugu literal 0 HcmV?d00001 diff --git a/libsst-math/obj/x86-64/release/SST_Mat33u.o b/libsst-math/obj/x86-64/release/SST_Mat33u.o new file mode 100644 index 0000000000000000000000000000000000000000..28cbcf6a88ef3745e6199d633c52d649a33ef513 GIT binary patch literal 6616 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 F005sIkrDs^ literal 0 HcmV?d00001 diff --git a/libsst-math/obj/x86-64/release/SST_Mat44d.o b/libsst-math/obj/x86-64/release/SST_Mat44d.o new file mode 100644 index 0000000000000000000000000000000000000000..52b2d8ed528ec2f517948fed6fd536befc8c1c48 GIT binary patch literal 31176 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 literal 0 HcmV?d00001 diff --git a/libsst-math/obj/x86-64/release/SST_Mat44f.o b/libsst-math/obj/x86-64/release/SST_Mat44f.o new file mode 100644 index 0000000000000000000000000000000000000000..4473aa25d5aa2ab0d656ba74e7d8e83fb2db65b0 GIT binary patch literal 28496 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 literal 0 HcmV?d00001 diff --git a/libsst-math/obj/x86-64/release/SST_Mat44i.o b/libsst-math/obj/x86-64/release/SST_Mat44i.o new file mode 100644 index 0000000000000000000000000000000000000000..2af2872cf17c1d84782b1b8593096fe3e729b895 GIT binary patch literal 11880 zcmb<-^>JfjWMqH=Mg}_u1P><4z>uMhU^{@B4h%dDoD88JoliYFYkzojmVWT)41M9z z?fRozz@yvsLpKBCA&+j?7o8y9kL~~#u%H7AR20nr(H+165$1pigZMwX19%|9JTPGp z|3`NK$gB_D4gxS?5dTMafCxmj2uv8n|Ir;F0TGsf34{1Qx&ve&!ZI*n5dTMafC5BV z0VWLM|L6`-fe5R>ghBit-2oa9VGWoti2tKIKnEhM0}}@Ee{=^JK!goo!XW;S?f?^r zun9~U#Q)J9U;z=ffC+>6Ke_{KAi_2<VVeoDhf%^GJ?wvA4f`LRSi}BDCpa$9!~RDn zI4;n`{zoS`F3`jNM<+Ng(8K;mCpa$9!~RDnI4;n`{zoS`F3`jNM<+Ng(8K;mCpa$9 z!~RDnI4;n`{zoS`F3`jNM<+Ng(8K;mCpa$9!~RES07lrOrF~7TX&)+z9{w<4w6qTs zMoarJVYIXl6Glt>Fk!T`4--a9`!Hd&v=0+TOZzZkw6qTsMoarJVYIXl6Glt>Fk!T` z4->`+f26bzR)dlDp`uvB9y9I3RAUQ!%(M?vjV<gk(>_c!wy?)c`!Lnm!X7j2!&GAn zd(5;CQ;jX`G1ERwHAdK@rG5VO7qAulFk$o<fQzFgf4DeW9KglVG5}m0Ef(P7XjuR* zjusDaakNYT7e|W;xHwuifQzHW1za30Bf!PcVgoLYmKEUQ81aFW7a)o-G6PH)dt6{< z2e^8yae<j3;Oeo)1!k6jtH&A_n3)2u9&21+W(&A_tZ{*vG2rU4#sy~9fU8H2i_X$7 z@Fo!h|9aOioye7f0}GN6G#(r{ki{VR!GQ-^3=;kh0?1;JeBdC0ECva82MJ^`Ncwk> zK^B9Aw}S$*7$n_0s340$!r4IsSqzfi9dwYzAmQs^fGh?{=ME;wVvulkus{}rq;Cfs zWHI#c1SM@mSi;gZQdq)UH%MU#PtQnU32)aRg(W;4BZVcrMS~QU@brrmmhiR=Qdq*% zEmBy*TQNvs2~V#`VF_=)AcZA7og#%Lyyb!vmhkk66qZD^S)hry+XIxKK6HZu^<Xa# z6SzqaZjpWH1_kON#)A+cP`rNV28HRNUJ*v5A|I+>0Np?l{`D9JO7O2oH&BLuJ={QO zD-&v>0=kJRSWMKwG*JiHL`d?6nrMJ-q6rogEig^AK{gQ-5bz!j1KdPV9z+jDP(DHn zMo?Bj3r1*h0H#3Q9dsj60upK@azH|jL<vZcYv7IqB~nl&{iE9hB>tfrltK}412qyk zB%wy4gd|8A!bn6=LXAWTN|4$Q-JnDYk8Y@uC_xDlgZBy%K?y3l(1Q|G{GbITs02X| zN=PXR?%SXQCDcfipoAKU9F$NaQGybr74Ar+pahAd2PM=<<e-Eai4v3`We6h?K?yYy zB`85^(Sj0cBuY?%#NfR-L{NfCeDt6MmD*@Q3GHn1Ag6Ok<pb^yq68(>NR*(28i^c~ zP$N--5~LOGNTi?yiK7Q4)JWu@gc^wwlptjYBN0IfH4-H#L2A*05^5w$P{M1W<~Io* zowX}GI!hO%cyzO<YA`S`cyzk{Fg)PV?YaUy@Ufs98rCZy1?d9hf^-FBm|+1@LAnAm zI<NpzkTRa=blret7N~XtWmJS=h)_lt1`lO~VW3b38HVgISok6gLzJHg!{FhIFbovF zAj2Ro0TrDKx<U04gb%JS7IcFuC1??XFbrOFA`AnCEXc42-JxKgb_#Tdf?e4eAkZBO zHnKB7p*!>eC>S8!^%aoeBjlh3l`-f+3o2vKf)-SsAO-CfkeM*Ukir&f8cNtgO+yY_ zsA;gUJ%VByv~pSjDN+|87pW^C!$=FdL6ttF{96GT{aMfrs`C$l!s7~xY0z|wFb$Dz z5vC!BF4S$X(0$S!3ifPg084i$*rA;PBHf{2OF9Eox<j9Utb+`Dtbh!|AqOw0+(8ds zP`QH^yr41$DR_5)%!C<+6ueN=P=Xg~8glSLO@jsR2^7;1!3#AFCGA2@Lr%L;(_m@$ z28wBj;Dwro61-5;kb@U$8Z3BUbccdH+Zn*o9SU}6XMjX^DA<zD0F7?&Naza4@X-p$ za3*r_g32QF;02XMXu%6Ai;#kM55x<gVt7F}Qt(1eLkV7}X~@9~H4PTLXHZN-1TWMy zl;DM$h8(<5(_q1S2gNi*@Ip;P30|ma$iWLW4Hmp_x<kR9?F``Q4h1{3GeD+06l_Un zfKGSl8<2INVK`7zG{wUhQWTf4z5tC)pF|xN#X3Ck15!Gp*My+PAzDocYTcnVDnKP5 zyx{{a?h#EX7UU)*s1!jn5R_BV3<S6I;PpSkL{Q>HcOocpqL~OvoaiP(+dZJf@&Q&Q z{pj`p#Rs~Hp!h&D5fmTjCi1|>o15Plcy!j@@aQbPfLROP0M~*SU{>CMg!2XDTJQ#> z7QBE|3*La#f)^0AAgK7i0V%4H4Fi?b=!Sv97|k$H7$X@5D(r4R3MOR3K*5V{7$|tr z3<Cu(l3}1pjvJ6XjcgbwWYG-+g)Ew3ppZo}><y%%y8x;ML9V<2F0esXTmY9XpoD&* zGk|9T5eXgCIR+)o53q562nUw9z-b#k$`4M~@WFlX><sFdK71%26uckcBlw_@{Qw`h z2c@zP@bP+3cz!?~riYKtg97mbd{7>oEFqOUY*qkL7s1ByAw?%_<Q<gLp_3iZ#D^{6 zIS6#Rg2E7*Y;J%X6kq|!l*f&32Zc^oP}oA#!VPdk11taummA#<2A!^;Fo#C)jm`iA zNNIBe5>_|59aP|Efc$#{T$@7801I?Gn83{dC5juJ0VZ%WzyjS47H}1yByyuOzyhv9 z2Y*z9Y<khn@cjm4Gzpf^UUYka;_w9|pLJf;1a;D1K$83mNJfJRfx`X;B%{HEKndjq zxJo$$69Q$l7u}$d5V#P?cQ3j@10irBkau2mgT_JNLZD>!q8rrKgbRUE&<k*b2rdN5 zW-lP^A()Mzkaz)U55a^$iSz}ysR`F;0vc!lH#XryprrKz(zk?Z1m&_9-JtQ0Lz)LW zPjtHe0Bb||6V%Q`gc+jhL<AYU>U;so>riikM?YSG3puDSp(5aH2K6OO2$VgbzJv)u zLmymkLgEPOC<E9i!wX2M_X6Tcm_Ddc@JbWmDsZI<F$z3f@&c45Ag#<7khxJvs(=eY z<B<c<EgKx_dASq0Ul3QUy&DDo8?5v*0a*7m)c?Xgs2sh3rMBStgifA$t+(E@Ur4 z(ia1gK4|h{K@x%{FJv!5lNYiVAx42(Qt+^Wnk9m17IJ!kngwo3K|>yD7P1$iW+8hK z>Mmq2Ld`<<A|%-(dl8!Ik-Z2_^~hd?rg~&ALX1N3BGfEoFG9^i_9E0QWG_O^LQWA- zvyf8+)GXu_0W}Mp=1+9G{^@r8(R_fV^+1Inj8)IR1GMbmHR}#g1Frc2W9tF_sfU_t z|1ebWf=I0L2NW;xZ#&TZfDu|XfZ8P8t~Vf)^Ebe`AC%2+bbElp_y)LyIH-B3^8&n@ z0Ht0Og`o6?q7YQv-heD6xB)Jkpe8~UYVfaznh32lK-m<<L{M<t0GGB<g&#b?ZiFh- zfsF0l==J~=3^%|fB2?iQ6ooSA3MJrHgUU8Yv+D-9z;=Do2}+cps)~QT>kDw1cmrIT zxV~XL0XGMf!Eb=;3)d%|$H10>h5=naXhJ#Q5qriD{Ob>PUW1B($AO`mUchVt%{+WS zw&e%NmP3pXW55&cP%UqewS0kT0nIc(v}hjd`~XfLe_{_axH~&rDQJWymFAU{Dwyh- z=o#pmm4bPOb%tho1}1uDnh<dXBLhP-12Y3l1`$y5VPIfjtO{aatPo(7=3(cUz{tQL z!vMh`=>||rbL10fV{+zYW3Fc8VdntL+khk)7#M0$<jdjmF;ID2`fH%_xb)9~%7fg) z0JpyzZvGyqd=HBK?Qr=!Q2789d2hJ<AE>+!io82qUIrx2z`$U|%D{lI-;@>Zf2jOg z6!{f!`535tB#4H)KLl<**xw8c47mI^2c(aIf#EI4oiP1OFF@9V!+#G{{vV3`Pq_RY zsJtwS`y}A*`vaA~45DG?GoJ&y4`d`Z3{uL%@bN!3IcBUYp%@sL8JMvtXJBSv!6D9u zL!2FlILL#jQhW>y3_?im0jEI*1_ni_IE)XA152p*A0~)7F!?~Jcn#F4F!gy*@gGpD z!EwmIz%UUi-T`$gIBha8Fzkeii*Q2B2d7B}28QcU@f0qII5;gbFfjarif`bCh=bE0 z0|SEuBg9{?1R&zzw8y}}V9m(D02P8rKuM5!pm3Nj1`z<KMFs|jET}mj#3AA^_xD1@ z8zdp(;IzlUz_1J|o+||r2d6m(28JV0@oZ^`I5@2_FfcrUigzeL#KCC{#0(A&iT6z` zF)_*1OJ;y_GN2-kDJfWleDaeMbI`?uOOr~95|c}CiDT8|TbfgnS&&odnv<HFnpaYu zS)7WlABz&aMg=D)<|G#3G6f=w*8tzdlA_ECTn0d7AqK?97ndX^XU8XJWXGo^W?}>h z%;{mN$tC$Xodl7En1~kqAw`LK#Rd78fdZGns?9kgH96bAs3aplFTW@kGpbxtOHzw+ zGxHMjN*EX>Len8An+Y*6F#P!s0aeiShAy58O;_mR&}78`5(i;W(gI<~T1y7FI4mD0 zfFv0Z;_!TqCJxKz3(&-2`TPKyI4qw(Kof`Mb661saw7=C^0@-2AVqQyET21|iNo@F z0-881Kg0Y7G8=?p`FR1FdRTrwfF=&h&kxYVVfh&xkVx)?<!1)H;>z5T#3Tm2;*uf= zodIJNrRF5+m84dbFzBTumLxLhB^4Jl=q2apf-)V0US57ls-C-Fs4h4;Gw6Ypr)I>b z6(#1TLW7ZF3Y0!TUP7-)VCf@T3DpXaT4WJWvI7<QF!eAw2Tcge141!?ifxcy4k%v& zN~?j|R1BcH4=MnqW~12)6^11f7?(kZfq?;JCVI_DtbRkN{RVIoAq<#)QwSGMg8TsD zz-TL|evlY4zCfh={h|6nX%d@$2{Z|iUy;>$F))Bz2k7D70S$jxx(9_nsH%nOhlRf& zmaqqz&jDSR9SPzfVVJ*RLLfex6Twn1RKOHN1XL1KJ%j89VUP^Weo!@!9(N#l2Xzq1 P!0;br0fY%A(YOo%Yausv literal 0 HcmV?d00001 diff --git a/libsst-math/obj/x86-64/release/SST_Mat44u.o b/libsst-math/obj/x86-64/release/SST_Mat44u.o new file mode 100644 index 0000000000000000000000000000000000000000..1eca4337022942cc07d0b39e8e6b2aa78f0220a6 GIT binary patch literal 9888 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 literal 0 HcmV?d00001 diff --git a/libsst-math/obj/x86-64/release/SST_Transform.o b/libsst-math/obj/x86-64/release/SST_Transform.o new file mode 100644 index 0000000000000000000000000000000000000000..bc41ee2e9f89448a3c1eac4043dfb98ee76e6edd GIT binary patch literal 16144 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 T#IV^v0a{@uL-oT9N4FmUg4lF5 literal 0 HcmV?d00001 diff --git a/libsst-math/obj/x86-64/release/SST_Vec2d.o b/libsst-math/obj/x86-64/release/SST_Vec2d.o new file mode 100644 index 0000000000000000000000000000000000000000..ce58f4edb74cccf7ce7c45b8aa8f76ab839570ea GIT binary patch literal 11432 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 Z4-&&>{{?7+!U9?@KulwRRfjMx0|08rDKG#4 literal 0 HcmV?d00001 diff --git a/libsst-math/obj/x86-64/release/SST_Vec2f.o b/libsst-math/obj/x86-64/release/SST_Vec2f.o new file mode 100644 index 0000000000000000000000000000000000000000..4c5d8a6b5949bc5b0c8f1009be14a416632dffd2 GIT binary patch literal 11344 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 literal 0 HcmV?d00001 diff --git a/libsst-math/obj/x86-64/release/SST_Vec2i.o b/libsst-math/obj/x86-64/release/SST_Vec2i.o new file mode 100644 index 0000000000000000000000000000000000000000..c14132e68b41c1a64a5545eb3750557ce3adcb2d GIT binary patch literal 6720 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 bh8r69==O8suz!L8ME?ym!$I~zWFRB}X*?5& literal 0 HcmV?d00001 diff --git a/libsst-math/obj/x86-64/release/SST_Vec2u.o b/libsst-math/obj/x86-64/release/SST_Vec2u.o new file mode 100644 index 0000000000000000000000000000000000000000..be41ae482732fcfd5381caf15d8139c68728016e GIT binary patch literal 5744 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 E0sGhkDF6Tf literal 0 HcmV?d00001 diff --git a/libsst-math/obj/x86-64/release/SST_Vec3d.o b/libsst-math/obj/x86-64/release/SST_Vec3d.o new file mode 100644 index 0000000000000000000000000000000000000000..72274b3586a2c31bcdf15558df5325a8f9b1a140 GIT binary patch literal 13656 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 UoBba^l{;uW5n3+5>_oR804C6QwEzGB literal 0 HcmV?d00001 diff --git a/libsst-math/obj/x86-64/release/SST_Vec3f.o b/libsst-math/obj/x86-64/release/SST_Vec3f.o new file mode 100644 index 0000000000000000000000000000000000000000..699feeefe64d59778f51cb667c225c1c4b0b3468 GIT binary patch literal 13520 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 literal 0 HcmV?d00001 diff --git a/libsst-math/obj/x86-64/release/SST_Vec3i.o b/libsst-math/obj/x86-64/release/SST_Vec3i.o new file mode 100644 index 0000000000000000000000000000000000000000..e05b0b1f10936fdb1e4b940797fffc1739779e0e GIT binary patch literal 7192 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 Xpi02{U_^!xgmnYWaFBfv83+jgb~EQA literal 0 HcmV?d00001 diff --git a/libsst-math/obj/x86-64/release/SST_Vec3u.o b/libsst-math/obj/x86-64/release/SST_Vec3u.o new file mode 100644 index 0000000000000000000000000000000000000000..9601ccdbf49a35c995f4d842d8efb841efd508da GIT binary patch literal 6232 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 Gfsg<XgxkUZ literal 0 HcmV?d00001 diff --git a/libsst-math/obj/x86-64/release/SST_Vec4d.o b/libsst-math/obj/x86-64/release/SST_Vec4d.o new file mode 100644 index 0000000000000000000000000000000000000000..30ef1fbfe8e971a18ec2f7d1e9b5eabb3bc3e8a9 GIT binary patch literal 10576 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 P0ZN#l{w10udiVhVt0%f% literal 0 HcmV?d00001 diff --git a/libsst-math/obj/x86-64/release/SST_Vec4f.o b/libsst-math/obj/x86-64/release/SST_Vec4f.o new file mode 100644 index 0000000000000000000000000000000000000000..4b6a55dffc564e5509c3edca910be781e91d4c4f GIT binary patch literal 10512 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 GhL8YJ8I{5S literal 0 HcmV?d00001 diff --git a/libsst-math/obj/x86-64/release/SST_Vec4i.o b/libsst-math/obj/x86-64/release/SST_Vec4i.o new file mode 100644 index 0000000000000000000000000000000000000000..5fb533f7726b5a46ff771503ed4d6564b00f21e9 GIT binary patch literal 7672 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 literal 0 HcmV?d00001 diff --git a/libsst-math/obj/x86-64/release/SST_Vec4u.o b/libsst-math/obj/x86-64/release/SST_Vec4u.o new file mode 100644 index 0000000000000000000000000000000000000000..cdaf705cc027a6b4e0a62a0a1192bf4414eec576 GIT binary patch literal 6712 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%0A<({>3)Bxeo$J1Y6VjcQ2nrc3>Jj?6~+e9UJMN2 zRwa7)H$Xdt5m19c(FkgqfWiu-4;KD{Si&A8e?tsJGB89!C^!l8H%tJ;hgty>0@Dqk v!j*x6K>`{vAn$<e24Ro_nEjw)9jXK*497D-4r5?o2u3p;WFK4+0|Ns9QxC8Z literal 0 HcmV?d00001 diff --git a/libsst-math/obj/x86-64/release/SST_VectorN.o b/libsst-math/obj/x86-64/release/SST_VectorN.o new file mode 100644 index 0000000000000000000000000000000000000000..9eee1188a12887d76f6dd68bc4d725707d2749f9 GIT binary patch literal 15304 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 KvJYZ1gaiQYf$=~9 literal 0 HcmV?d00001 diff --git a/libsst-math/test.c b/libsst-math/test.c new file mode 100644 index 0000000..a78abe1 --- /dev/null +++ b/libsst-math/test.c @@ -0,0 +1,41 @@ +#include <stdio.h> +#include <SST/SST_Math.h> + +int SST_Math_Mat22d_test_fxns(); +int SST_Math_Mat33d_test_fxns(); +int SST_Math_Mat44d_test_fxns(); + +int SST_Math_Mat22f_test_fxns(); +int SST_Math_Mat33f_test_fxns(); +int SST_Math_Mat44f_test_fxns(); + +int SST_Math_Mat22u_test_fxns(); +int SST_Math_Mat33u_test_fxns(); +int SST_Math_Mat44u_test_fxns(); + +int SST_Math_Mat22i_test_fxns(); +int SST_Math_Mat33i_test_fxns(); +int SST_Math_Mat44i_test_fxns(); + +int main() +{ + + SST_Math_Mat22d_test_fxns(); + SST_Math_Mat33d_test_fxns(); + SST_Math_Mat44d_test_fxns(); + + SST_Math_Mat22f_test_fxns(); + SST_Math_Mat33f_test_fxns(); + SST_Math_Mat44f_test_fxns(); + + SST_Math_Mat22u_test_fxns(); + SST_Math_Mat33u_test_fxns(); + SST_Math_Mat44u_test_fxns(); + + SST_Math_Mat22i_test_fxns(); + SST_Math_Mat33i_test_fxns(); + SST_Math_Mat44i_test_fxns(); + + + return 0; +} diff --git a/libsst-net/Makefile b/libsst-net/Makefile new file mode 100644 index 0000000..c12357b --- /dev/null +++ b/libsst-net/Makefile @@ -0,0 +1,47 @@ +# libsst-net/Makefile +# Author: Patrick Baggett <ptbaggett@762studios.com> +# Created: 12/03/2012 +# +# Purpose: +# +# Makefile for libsst-net +# +# License: +# +# This program is free software. It comes without any warranty, to +# the extent permitted by applicable law. You can redistribute it +# and/or modify it under the terms of the Do What The Fuck You Want +# To Public License, Version 2, as published by Sam Hocevar. See +# http://sam.zoy.org/wtfpl/COPYING for more details. + +BINNAME := $(DIST)/libsst-net.a +ifeq ($(TARGET),debug) + BINNAME := $(subst .a,_d.a, $(BINNAME)) +endif + +SRC := SST_NetAddress.c \ + SST_NetSocket.c \ + +ifeq ($(SUBSYSTEM),Solaris) + include sources-POSIX.mk +else + # Add platform specific code + include sources-$(SUBSYSTEM).mk +endif + +OBJ := $(addprefix obj/$(ARCH)/$(TARGET)/,$(subst .c,.o,$(SRC))) + +$(shell mkdir -p obj/$(ARCH)/$(TARGET)) + +$(BINNAME): $(OBJ) + $(AR) cru $@ $+ + $(RANLIB) $@ + +# CLEAN +clean: + @-rm -r -f obj $(DIST)/libsst-net*.a + +# *.c files to *.o files +obj/$(ARCH)/$(TARGET)/%.o: %.c + @echo CC $@ + @$(CC) $(CFLAGS) -c $*.c -o obj/$(ARCH)/$(TARGET)/$*.o diff --git a/libsst-net/POSIXPrivate.h b/libsst-net/POSIXPrivate.h new file mode 100644 index 0000000..1d95a69 --- /dev/null +++ b/libsst-net/POSIXPrivate.h @@ -0,0 +1,44 @@ +/* + POSIXPrivate.h + Author: Patrick Baggett <ptbaggett@762studios.com> + Created: 12/3/2012 + + Purpose: + + Private data structures for POSIX implementation of libsst-net. Not to be distributed + as part of public SDK headers. + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ + +#pragma once + +#ifndef _POSIXPRIVATE_H +#define _POSIXPRIVATE_H + +/* Solaris needs this for FIONBIO */ +#define BSD_COMP + +#include <sys/ioctl.h> +#include <sys/socket.h> +#include <unistd.h> + +#include <netinet/in.h> +#include <arpa/inet.h> + +typedef int NativeSocketType; +typedef socklen_t NativeSocketLen; +#define SST_NATIVE_INVALIDSOCKET (-1) +#define SST_NATIVE_NETERROR (-1) +#define NativeCloseSocket(s) close(s) +#define NativeIoctl(s, cmd, arg) ioctl(s, cmd, arg) + + +#endif diff --git a/libsst-net/PlatformPrivate.h b/libsst-net/PlatformPrivate.h new file mode 100644 index 0000000..d3cf229 --- /dev/null +++ b/libsst-net/PlatformPrivate.h @@ -0,0 +1,98 @@ +/* + PlatformPrivate.h + Author: Patrick Baggett <ptbaggett@762studios.com> + Created: 8/7/2012 + + Purpose: + + Crossplatform include that defers to platform-specific headers. Not to be + distributed as part of public SDK headers. + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ + +#pragma once + +#ifndef _SST_PLATFORMPRIVATE_H +#define _SST_PLATFORMPRIVATE_H + +#include <pstdint.h> +#include <limits.h> +#include <SST/SST_Build.h> +#ifdef _WIN32 + #include "Win32Private.h" +#else + #include "POSIXPrivate.h" +#endif + +#include <SST/SST_NetResult.h> +#include <SST/SST_NetTypes.h> + +SST_NetResult NativeDecodeError(void); + +/*************************************************************************/ + +static INLINE NativeSocketLen sockLenForNetAddr(const SST_NetAddress* addr) +{ + NativeSocketLen socklen = 0; + const struct sockaddr* saddr = (const struct sockaddr*)addr; + + switch(saddr->sa_family) + { + case AF_INET: socklen = sizeof(struct sockaddr_in); break; + case AF_INET6: socklen = sizeof(struct sockaddr_in6); break; + } + + return socklen; +} + +/*************************************************************************/ + +static INLINE int convertSockOpt(SST_NetSocketOption option) +{ + int ret; + + switch(option) + { + case SSTNETSOCKOPT_DEBUG: ret = SO_DEBUG; break; + case SSTNETSOCKOPT_ACCEPTCONN: ret = SO_ACCEPTCONN; break; + case SSTNETSOCKOPT_BROADCAST: ret = SO_BROADCAST; break; + case SSTNETSOCKOPT_REUSEADDR: ret = SO_REUSEADDR; break; + case SSTNETSOCKOPT_KEEPALIVE: ret = SO_KEEPALIVE; break; + case SSTNETSOCKOPT_LINGER: ret = SO_LINGER; break; + case SSTNETSOCKOPT_OOBINLINE: ret = SO_OOBINLINE; break; + case SSTNETSOCKOPT_SENDBUFFERSIZE: ret = SO_SNDBUF; break; + case SSTNETSOCKOPT_RECVBUFFERSIZE: ret = SO_RCVBUF; break; + case SSTNETSOCKOPT_ERRORSTATUS: ret = SO_ERROR; break; + case SSTNETSOCKOPT_SOCKETTYPE: ret = SO_TYPE; break; + case SSTNETSOCKOPT_DONTROUTE: ret = SO_DONTROUTE; break; + default: ret = -1; break; + } + + return ret; +} + +/*************************************************************************/ + +static INLINE int convertSockLevel(SST_NetProtocolLevel level) +{ + int ret; + + switch(level) + { + case SSTNETPROTOLEVEL_SOCKET: ret = SO_DEBUG; break; + default: ret = -1; break; + } + + return ret; +} + +#endif + diff --git a/libsst-net/SST_NetAddress.c b/libsst-net/SST_NetAddress.c new file mode 100644 index 0000000..fae6025 --- /dev/null +++ b/libsst-net/SST_NetAddress.c @@ -0,0 +1,292 @@ +/* + SST_NetAddress.h + Author: Patrick Baggett <ptbaggett@762studios.com> + Created: 8/7/2012 + + Purpose: + + Address storage manipulation + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ + +#include "PlatformPrivate.h" +#include <SST/SST_NetAddress.h> +#include <string.h> + +/*************************************************************************/ + +SST_NetResult SST_Net_InitAddress(SST_NetAddress* addr, SST_NetAddressFamily family, unsigned short port) +{ + unsigned short nboPort; /* Port in network byte order */ + size_t addrSize; + uint8_t* asBytes = (uint8_t*)addr; + + nboPort = htons(port); + + /* Avoid strict aliasing violations by setting up a temporary structure and memcpy()ing. */ + + switch(family) + { + case SSTNETADDRFAM_IPV4: + { + struct sockaddr_in addr4; + + addr4.sin_family = AF_INET; + addr4.sin_port = nboPort; + addr4.sin_addr.s_addr = INADDR_ANY; + memset(&addr4.sin_zero, 0, sizeof(addr4.sin_zero)); + + addrSize = sizeof(struct sockaddr_in); + memcpy(addr, &addr4, addrSize); + break; + } + + case SSTNETADDRFAM_IPV6: + { + struct sockaddr_in6 addr6; + + addr6.sin6_family = AF_INET; + addr6.sin6_port = nboPort; + addr6.sin6_flowinfo = 0; + addr6.sin6_addr = in6addr_any; + addr6.sin6_scope_id = 0; + + addrSize = sizeof(struct sockaddr_in6); + memcpy(addr, &addr6, addrSize); + break; + } + + /* Default: return error */ + default: + return SSTNETRESULT_ADDRFAMNOTSUPPORTED; + } + + /* memset() the rest of the address storage to all-bits-zero. */ + memset(asBytes + addrSize, 0, sizeof(SST_NetAddress) - addrSize); + + return SSTNETRESULT_SUCCESS; +} + +/*************************************************************************/ + +SST_NetAddressFamily SST_Net_GetAddressFamily(const SST_NetAddress* addr) +{ + switch(addr->ss_family) + { + case AF_INET: return SSTNETADDRFAM_IPV4; + case AF_INET6: return SSTNETADDRFAM_IPV6; + default: return SSTNETADDRFAM_UNKNOWN; + } +} + +/*************************************************************************/ + +unsigned short SST_Net_GetAddressPort(const SST_NetAddress* addr) +{ + + switch(addr->ss_family) + { + case AF_INET: + { + const struct sockaddr_in* addr4 = (const struct sockaddr_in*)addr; + + return ntohs(addr4->sin_port); + } + + case AF_INET6: + { + const struct sockaddr_in6* addr6 = (const struct sockaddr_in6*)addr; + + return ntohs(addr6->sin6_port); + } + + default: return UINT16_MAX; + } +} + +/*************************************************************************/ + +int SST_Net_AddressCompare(const SST_NetAddress* addr1, const SST_NetAddress* addr2) +{ + + if(addr1->ss_family != addr2->ss_family) + return (addr1->ss_family < addr2->ss_family ? -1 : 1); + + switch(addr1->ss_family) + { + case AF_INET: + { + const struct sockaddr_in* A = (const struct sockaddr_in*)addr1; + const struct sockaddr_in* B = (const struct sockaddr_in*)addr2; + + /* Are the addresses different? */ + if(A->sin_addr.s_addr != B->sin_addr.s_addr) + return (A->sin_addr.s_addr < B->sin_addr.s_addr ? -1 : 1); + + /* Are the ports different? */ + if(A->sin_port != B->sin_port) + return (A->sin_port < B->sin_port ? -1 : 1); + + /* Address/port are the same, so OK */ + return 0; + } + + case AF_INET6: + { + const struct sockaddr_in6* A = (const struct sockaddr_in6*)addr1; + const struct sockaddr_in6* B = (const struct sockaddr_in6*)addr2; + int result; + + result = memcmp(&A->sin6_addr, &B->sin6_addr, sizeof(struct in6_addr)); + + /* Are the addresses different? */ + if(result != 0) + return result; + + /* Are the ports different? */ + if(A->sin6_port != B->sin6_port) + return (A->sin6_port < B->sin6_port ? -1 : 1); + + /* Address/port are the same, so OK */ + return 0; + } + + } + + /* Undefined structure -> useless result */ + return -1; +} + +/*************************************************************************/ + +int SST_Net_AddressIsLocalhost(const SST_NetAddress* addr) +{ + int retval = 0; + + switch(addr->ss_family) + { + case AF_INET: + { + struct sockaddr_in* addr4 = (struct sockaddr_in*)addr; + + uint32_t localhost = (uint32_t)inet_addr("127.0.0.1"); + uint32_t myaddr = (uint32_t)addr4->sin_addr.s_addr; + + /* Compare address to loopback */ + retval = (myaddr == localhost); + } + + case AF_INET6: + { + struct sockaddr_in6* addr6 = (struct sockaddr_in6*)addr; + + /* Compare address to loopback */ + retval = (memcmp(&addr6->sin6_addr, &in6addr_loopback, sizeof(in6addr_loopback)) == 0); + } + + default: retval = -1; /* Error code*/ + } + + return retval; +} + +/*************************************************************************/ + +void SST_Net_AddressSetToLocalhost(SST_NetAddress* addr) +{ + switch(addr->ss_family) + { + case AF_INET: + { + struct sockaddr_in* addr4 = (struct sockaddr_in*)addr; + + addr4->sin_addr.s_addr = inet_addr("127.0.0.1"); + } + + case AF_INET6: + { + struct sockaddr_in6* addr6 = (struct sockaddr_in6*)addr; + + addr6->sin6_addr = in6addr_loopback; + } + } + +} + + +/*************************************************************************/ + +SST_NetResult SST_Net_SetAddressFromAddress(SST_NetAddress* dst, const SST_NetAddress* src) +{ + switch(src->ss_family) + { + case AF_INET: + { + struct sockaddr_in* dstAddr = (struct sockaddr_in*)dst; + const struct sockaddr_in* srcAddr = (const struct sockaddr_in*)src; + + memcpy(&dstAddr->sin_addr, &srcAddr->sin_addr, sizeof(struct in_addr)); + break; + } + + case AF_INET6: + { + struct sockaddr_in6* dstAddr = (struct sockaddr_in6*)dst; + const struct sockaddr_in6* srcAddr = (const struct sockaddr_in6*)src; + + memcpy(&dstAddr->sin6_addr, &srcAddr->sin6_addr, sizeof(struct in6_addr)); + break; + } + /* Default: return error */ + default: + return SSTNETRESULT_ADDRFAMNOTSUPPORTED; + } + + return SSTNETRESULT_SUCCESS; +} + +/*************************************************************************/ + +SST_NetResult SST_Net_SetAddressFromString(SST_NetAddress* addr, const char* addrString) +{ + int result; + char buf[sizeof(SST_NetAddress)]; + result = inet_pton(addr->ss_family, addrString, buf); + + if(result > 0) + { + switch(addr->ss_family) + { + case AF_INET: + { + struct sockaddr_in* dst = (struct sockaddr_in*)addr; + + memcpy(&dst->sin_addr, buf, sizeof(dst->sin_addr)); + + break; + } + + case AF_INET6: + { + struct sockaddr_in6* dst = (struct sockaddr_in6*)addr; + + memcpy(&dst->sin6_addr, buf, sizeof(dst->sin6_addr)); + break; + } + } + return SSTNETRESULT_SUCCESS; + } + else if(result == 0) + return SSTNETRESULT_BADADDRESSSTRING; + + //Other error + return NativeDecodeError(); +} \ No newline at end of file diff --git a/libsst-net/SST_NetInit_Generic.c b/libsst-net/SST_NetInit_Generic.c new file mode 100644 index 0000000..25caef1 --- /dev/null +++ b/libsst-net/SST_NetInit_Generic.c @@ -0,0 +1,29 @@ +/* + SST_NetInit_Generic.c + Author: Patrick Baggett <ptbaggett@762studios.com> + Created: 8/7/2012 + + Purpose: + + libsst-net initialization functions for platforms that do not need them. + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ + +int SST_Net_Init(void) +{ + return 1; +} + +void SST_Net_Shutdown(void) +{ + /* Intentionally blank */ +} + diff --git a/libsst-net/SST_NetInit_Win32.c b/libsst-net/SST_NetInit_Win32.c new file mode 100644 index 0000000..9888c73 --- /dev/null +++ b/libsst-net/SST_NetInit_Win32.c @@ -0,0 +1,36 @@ +/* + SST_NetInit_Win32.c + Author: Patrick Baggett <ptbaggett@762studios.com> + Created: 8/7/2012 + + Purpose: + + libsst-net initialization functions for Win32 + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ + +#include "PlatformPrivate.h" + +/*************************************************************************/ + +int SST_Net_Init(void) +{ + WSADATA wsainfo; + + return (WSAStartup(MAKEWORD(2,2), &wsainfo) == 0); +} + +/*************************************************************************/ + +void SST_Net_Shutdown(void) +{ + WSACleanup(); +} diff --git a/libsst-net/SST_NetResult_POSIX.c b/libsst-net/SST_NetResult_POSIX.c new file mode 100644 index 0000000..9d7d33c --- /dev/null +++ b/libsst-net/SST_NetResult_POSIX.c @@ -0,0 +1,64 @@ +/* + SST_NetResult_POSIX.c + Authors: Patrick Baggett <ptbaggett@762studios.com> + Created: 12/03/2012 + + Purpose: + + errno to libsst-net error codes + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ + +#include <SST/SST_NetResult.h> +#include "PlatformPrivate.h" +#include <errno.h> + +SST_NetResult NativeDecodeError(void) +{ + SST_NetResult e; + switch(errno) + { + case EAFNOSUPPORT: e = SSTNETRESULT_ADDRFAMNOTSUPPORTED; break; + case EINPROGRESS: e = SSTNETRESULT_INPROGRESS; break; + case EMFILE: e = SSTNETRESULT_NOFILESAVAILABLE; break; + case EINVAL: e = SSTNETRESULT_INVALIDARGS; break; + case ENOBUFS: return SSTNETRESULT_NOSPACE; break; + case EPROTONOSUPPORT: e = SSTNETRESULT_PROTOCOLNOTSUPPORTED; break; + case EPROTOTYPE: e = SSTNETRESULT_WRONGPROTOCOLFORSOCK; break; + case ESOCKTNOSUPPORT: e = SSTNETRESULT_SOCKETNOTSUPPORTED; break; + case EFAULT: return SSTNETRESULT_BADPOINTER; break; + case ENOTSOCK: return SSTNETRESULT_NOTASOCKET; break; + case EADDRINUSE: return SSTNETRESULT_ADDRINUSE; break; + case EISCONN: return SSTNETRESULT_ALREADYCONNECTED; break; + case EOPNOTSUPP: return SSTNETRESULT_OPNOTSUPPORTED; break; + case EINTR: return SSTNETRESULT_INTERRUPTED; break; + case EALREADY: return SSTNETRESULT_ALREADYCONNECTING; break; + case EADDRNOTAVAIL: return SSTNETRESULT_ADDRNOTAVAILABLE; break; + case ECONNREFUSED: return SSTNETRESULT_CONNECTIONREFUSED; break; + case ENETUNREACH: return SSTNETRESULT_NETUNREACHABLE; break; + case EHOSTUNREACH: return SSTNETRESULT_HOSTUNREACHABLE; break; + case ETIMEDOUT: return SSTNETRESULT_TIMEDOUT; break; + case EWOULDBLOCK: return SSTNETRESULT_WOULDBLOCK; break; + case EACCES: return SSTNETRESULT_ACCESSDENIED; break; + case ECONNRESET: return SSTNETRESULT_CONNECTIONRESET; break; + case ENOTCONN: return SSTNETRESULT_NOTCONNECTED; break; + case ENETRESET: return SSTNETRESULT_NETRESET; break; + case ESHUTDOWN: return SSTNETRESULT_SOCKETSHUTDOWN; break; + case EMSGSIZE: return SSTNETRESULT_MESSAGESIZE; break; + case ECONNABORTED: return SSTNETRESULT_CONNECTIONABORTED; break; + case EDESTADDRREQ: return SSTNETRESULT_NODESTADDRESSGIVEN; break; + + + default: e = SSTNETRESULT_UNKNOWN; break; + } + + return e; +} diff --git a/libsst-net/SST_NetResult_Win32.c b/libsst-net/SST_NetResult_Win32.c new file mode 100644 index 0000000..3671bcb --- /dev/null +++ b/libsst-net/SST_NetResult_Win32.c @@ -0,0 +1,67 @@ +/* + SST_NetResult_Win32.c + Authors: Chris Ertel <crertel@762studios.com, Patrick Baggett <ptbaggett@762studios.com> + Created: 8/7/2012 + + Purpose: + + Winsock2 to libsst-net error codes + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ +#include <SST/SST_NetResult.h> +#include "PlatformPrivate.h" + +SST_NetResult NativeDecodeError(void) +{ + SST_NetResult e; + switch(WSAGetLastError()) + { + case WSANOTINITIALISED: e = SSTNETRESULT_NETNOTINIT; break; + case WSAENETDOWN: e = SSTNETRESULT_NETDOWN; break; + case WSAEAFNOSUPPORT: e = SSTNETRESULT_ADDRFAMNOTSUPPORTED; break; + case WSAEINPROGRESS: e = SSTNETRESULT_INPROGRESS; break; + case WSAEMFILE: e = SSTNETRESULT_NOFILESAVAILABLE; break; + case WSAEINVAL: e = SSTNETRESULT_INVALIDARGS; break; + case WSAENOBUFS: return SSTNETRESULT_NOSPACE; break; + case WSAEPROTONOSUPPORT: e = SSTNETRESULT_PROTOCOLNOTSUPPORTED; break; + case WSAEPROTOTYPE: e = SSTNETRESULT_WRONGPROTOCOLFORSOCK; break; + case WSAEPROVIDERFAILEDINIT: e = SSTNETRESULT_NETNOTINIT; break; + case WSAESOCKTNOSUPPORT: e = SSTNETRESULT_SOCKETNOTSUPPORTED; break; + case WSAEINVALIDPROVIDER: e = SSTNETRESULT_NETNOTINIT; break; + case WSAEINVALIDPROCTABLE: e = SSTNETRESULT_NETNOTINIT; break; + case WSAEFAULT: return SSTNETRESULT_BADPOINTER; break; + case WSAENOTSOCK: return SSTNETRESULT_NOTASOCKET; break; + case WSAEADDRINUSE: return SSTNETRESULT_ADDRINUSE; break; + case WSAEISCONN: return SSTNETRESULT_ALREADYCONNECTED; break; + case WSAEOPNOTSUPP: return SSTNETRESULT_OPNOTSUPPORTED; break; + case WSAEINTR: return SSTNETRESULT_INTERRUPTED; break; + case WSAEALREADY: return SSTNETRESULT_ALREADYCONNECTING; break; + case WSAEADDRNOTAVAIL: return SSTNETRESULT_ADDRNOTAVAILABLE; break; + case WSAECONNREFUSED: return SSTNETRESULT_CONNECTIONREFUSED; break; + case WSAENETUNREACH: return SSTNETRESULT_NETUNREACHABLE; break; + case WSAEHOSTUNREACH: return SSTNETRESULT_HOSTUNREACHABLE; break; + case WSAETIMEDOUT: return SSTNETRESULT_TIMEDOUT; break; + case WSAEWOULDBLOCK: return SSTNETRESULT_WOULDBLOCK; break; + case WSAEACCES: return SSTNETRESULT_ACCESSDENIED; break; + case WSAECONNRESET: return SSTNETRESULT_CONNECTIONRESET; break; + case WSAENOTCONN: return SSTNETRESULT_NOTCONNECTED; break; + case WSAENETRESET: return SSTNETRESULT_NETRESET; break; + case WSAESHUTDOWN: return SSTNETRESULT_SOCKETSHUTDOWN; break; + case WSAEMSGSIZE: return SSTNETRESULT_MESSAGESIZE; break; + case WSAECONNABORTED: return SSTNETRESULT_CONNECTIONABORTED; break; + case WSAEDESTADDRREQ: return SSTNETRESULT_NODESTADDRESSGIVEN; break; + + + default: e = SSTNETRESULT_UNKNOWN; break; + } + + return e; +} \ No newline at end of file diff --git a/libsst-net/SST_NetSocket.c b/libsst-net/SST_NetSocket.c new file mode 100644 index 0000000..afbeef9 --- /dev/null +++ b/libsst-net/SST_NetSocket.c @@ -0,0 +1,309 @@ +/* + SST_NetSocket.c + Author: Patrick Baggett <ptbaggett@762studios.com> + Created: 8/7/2012 + + Purpose: + + Socket functions + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ +#include <SST/SST_NetSocket.h> +#include "PlatformPrivate.h" + +/*************************************************************************/ + +SST_NetResult SST_Net_Socket( SST_NetAddressFamily _addressFamily, SST_NetSocketType _socketType, SST_NetProtocol _protocol, SST_Socket* _createdSocket) +{ + NativeSocketType sock; + int af; + int socktype; + int proto; + + /* Configure socket options */ + switch (_addressFamily) + { + case SSTNETADDRFAM_IPV4: af = AF_INET; break; + case SSTNETADDRFAM_IPV6: af = AF_INET6; break; + default: return SSTNETRESULT_ADDRFAMNOTSUPPORTED; break; + } + + switch (_socketType) + { + case SSTNETSOCKTYPE_STREAM: socktype = SOCK_STREAM; break; + case SSTNETSOCKTYPE_DATAGRAM: socktype = SOCK_DGRAM; break; + default: return SSTNETRESULT_SOCKETNOTSUPPORTED; break; + } + + switch (_protocol) + { + case SSTNETPROTOCOL_TCP: proto = IPPROTO_TCP; break; + case SSTNETPROTOCOL_UDP: proto = IPPROTO_UDP; break; + default: return SSTNETRESULT_PROTOCOLNOTSUPPORTED; break; + } + + /* Create socket */ + sock = socket(af, socktype, proto); + if(sock == SST_NATIVE_INVALIDSOCKET) + return NativeDecodeError(); + + *_createdSocket = (SST_Socket)sock; + return SSTNETRESULT_SUCCESS; +} + +/*************************************************************************/ + +SST_NetResult SST_Net_Bind(SST_Socket sock, const SST_NetAddress* addr) +{ + NativeSocketLen socklen; + NativeSocketType s = (NativeSocketType)sock; + + socklen = sockLenForNetAddr(addr); + + if(bind(s, (struct sockaddr*) addr, socklen) == 0) + return SSTNETRESULT_SUCCESS; + + return NativeDecodeError(); +} + +/*************************************************************************/ + +SST_NetResult SST_Net_Listen( SST_Socket sock, int backlog) +{ + NativeSocketType s = (NativeSocketType)sock; + + if(listen(s, backlog) == 0) + return SSTNETRESULT_SUCCESS; + + return NativeDecodeError(); +} + +/*************************************************************************/ + +SST_NetResult SST_Net_Connect( SST_Socket sock, const SST_NetAddress* addr) +{ + int socklen; + NativeSocketType s = (NativeSocketType)sock; + + socklen = sockLenForNetAddr(addr); + + if(connect(s, (struct sockaddr*)addr, socklen) == 0) + return SSTNETRESULT_SUCCESS; + + return NativeDecodeError(); +} + +/*************************************************************************/ + +SST_NetResult SST_Net_Accept(SST_Socket sock, SST_NetAddress* addr, SST_Socket* newSockReturn) +{ + NativeSocketType s = (NativeSocketType)sock; + NativeSocketType newSock; + + NativeSocketLen addrlen = (int) sizeof(SST_NetAddress); + + newSock = accept(s, (struct sockaddr*)addr, &addrlen); + if(newSock != SST_NATIVE_INVALIDSOCKET) + { + *newSockReturn = newSock; + return SSTNETRESULT_SUCCESS; + } + + return NativeDecodeError(); +} + +/*************************************************************************/ + +SST_NetResult SST_Net_Send(SST_Socket sock, const void* data, size_t length, uint32_t sendFlags, size_t* bytesSentReturn) +{ + NativeSocketType s = (NativeSocketType)sock; + int bytesSent; + int flags = 0; + int sendAmount; + + flags |= (sendFlags & SSTNET_DONTROUTE ? MSG_DONTROUTE : 0); + flags |= (sendFlags & SSTNET_OOB ? MSG_OOB : 0); + + /* Ensure send() with huge values doesn't result in negative numbers when typecasted to an int */ + if(length > INT_MAX) + sendAmount = INT_MAX; + else + sendAmount = (int)length; + + bytesSent = send(s, data, sendAmount,flags); + if(bytesSent != SST_NATIVE_NETERROR) + { + *bytesSentReturn = (size_t)bytesSent; + return SSTNETRESULT_SUCCESS; + } + + return NativeDecodeError(); +} + +/*************************************************************************/ + +SST_NetResult SST_Net_Recv(SST_Socket sock, void* data, size_t length, uint32_t recvFlags, size_t* bytesRecvReturn) +{ + NativeSocketType s = (NativeSocketType)sock; + int bytesReceived; + int flags = 0; + int recvSize; + + flags |= (recvFlags & SSTNET_PEEK)? MSG_PEEK : 0; + flags |= (recvFlags & SSTNET_OOB)? MSG_OOB : 0; + flags |= (recvFlags & SSTNET_WAITALL)? MSG_WAITALL : 0; + + /* Ensure recv() with huge values doesn't result in negative numbers when typecasted to an int */ + if(length > INT_MAX) + recvSize = INT_MAX; + else + recvSize = (int)length; + + bytesReceived = recv(s, data, recvSize, flags); + if(bytesReceived != SST_NATIVE_NETERROR) + { + *bytesRecvReturn = (size_t)bytesReceived; + return SSTNETRESULT_SUCCESS; + } + + return NativeDecodeError(); +} + +/*************************************************************************/ + +SST_NetResult SST_Net_SendTo(SST_Socket sock, const void* data, size_t length, uint32_t sendFlags, const SST_NetAddress* dest, size_t* bytesSentReturn) +{ + NativeSocketType s = (NativeSocketType)sock; + int bytesSent; + int flags = 0; + int sendAmount; + NativeSocketLen addrLen = sockLenForNetAddr(dest); + + flags |= (sendFlags & SSTNET_DONTROUTE)? MSG_DONTROUTE : 0; + flags |= (sendFlags & SSTNET_OOB)? MSG_OOB : 0; + + /* Ensure send() with huge values doesn't result in negative numbers when typecasted to an int */ + if(length > INT_MAX) + sendAmount = INT_MAX; + else + sendAmount = (int)length; + + + bytesSent = sendto(s, data, sendAmount, flags, (struct sockaddr*)dest, addrLen); + if(bytesSent != SST_NATIVE_NETERROR) + { + *bytesSentReturn = (size_t)bytesSent; + return SSTNETRESULT_SUCCESS; + } + + return NativeDecodeError(); +} + +/*************************************************************************/ + +SST_NetResult SST_Net_RecvFrom(SST_Socket sock, void* data, size_t length, uint32_t recvFlags, SST_NetAddress* senderReturn, size_t* bytesRecvReturn) +{ + NativeSocketType s = (NativeSocketType)sock; + int bytesReceived; + int flags = 0; + NativeSocketLen addrsize = sizeof(SST_NetAddress); + int recvSize; + + flags |= (recvFlags & SSTNET_DONTROUTE)? MSG_DONTROUTE : 0; + flags |= (recvFlags & SSTNET_OOB)? MSG_OOB : 0; + + /* Ensure recv() with huge values doesn't result in negative numbers when typecasted to an int */ + if(length > INT_MAX) + recvSize = INT_MAX; + else + recvSize = (int)length; + + bytesReceived = recvfrom(s, data, recvSize, flags, (struct sockaddr*)senderReturn, &addrsize); + + if(bytesReceived != SST_NATIVE_NETERROR) + { + *bytesRecvReturn = (size_t)bytesReceived; + return SSTNETRESULT_SUCCESS; + } + + return NativeDecodeError(); +} + +/*************************************************************************/ + +void SST_Net_Close(SST_Socket sock) +{ + NativeSocketType s = (NativeSocketType)sock; + + NativeCloseSocket(s); +} + +/*************************************************************************/ + +SST_NetResult SST_Net_GetSockOpt(SST_Socket sock, SST_NetProtocolLevel level, SST_NetSocketOption option, void* optionStorage, size_t* optionStorageSize) +{ + NativeSocketType s = (NativeSocketType)sock; + int opt; + int lvl; + NativeSocketLen optlen; + + lvl = convertSockLevel(level); + if(lvl == -1) + return SSTNETRESULT_BADPROTOCOLLEVEL; + + opt = convertSockOpt(option); + if(opt == -1) + return SSTNETRESULT_BADSOCKETOP; + + optlen = (NativeSocketLen)*optionStorageSize; + if(getsockopt(s, lvl, opt, optionStorage, &optlen) == SST_NATIVE_NETERROR) + return NativeDecodeError(); + + *optionStorageSize = (size_t)optlen; + return SSTNETRESULT_SUCCESS; +} + +/*************************************************************************/ + +SST_NetResult SST_Net_SetSockOpt(SST_Socket sock, SST_NetProtocolLevel level, SST_NetSocketOption option, const void* optionData, size_t optionDataSize) +{ + NativeSocketType s = (NativeSocketType)sock; + int opt; + int lvl; + int optlen; + + lvl = convertSockLevel(level); + if(lvl == -1) + return SSTNETRESULT_BADPROTOCOLLEVEL; + + opt = convertSockOpt(option); + if(opt == -1) + return SSTNETRESULT_BADSOCKETOP; + + optlen = (int)optionDataSize; + if(setsockopt(s, lvl, opt, (const void*)optionData, optlen) == SST_NATIVE_NETERROR) + return NativeDecodeError(); + + return SSTNETRESULT_SUCCESS; +} + +/*************************************************************************/ + +SST_NetResult SST_Net_SetNonblock(SST_Socket sock, int nonblock) +{ + NativeSocketType s = (NativeSocketType)sock; + int nb = (nonblock != 0); + + if(NativeIoctl(s, FIONBIO, (void*)&nb) != SST_NATIVE_NETERROR) + return SSTNETRESULT_SUCCESS; + + return NativeDecodeError(); +} diff --git a/libsst-net/SST_Sockets_Win32.c b/libsst-net/SST_Sockets_Win32.c new file mode 100644 index 0000000..5195f84 --- /dev/null +++ b/libsst-net/SST_Sockets_Win32.c @@ -0,0 +1,772 @@ +/* + SST_Sockets_Win32.c + Author: Chris Ertel <crertel@762studios.com> + Created: 07/15/2012 + + Purpose: + + libsst-net BSD sockets wrapper, Win32 implementation. + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ + +#include <SST/SST_Sockets.h> +#include <SST/SST_NetTypes.h> +#include <SST/SST_NetResult.h> +#include "Win32Private.h" + +#include <stdlib.h> + +typedef struct SST_NetPollDescriptorSet_Win32 +{ + size_t Count; + WSAPOLLFD* Descriptors; +} SST_NetPollDescriptorSet_Win32; + + +typedef struct SST_NetAddrInfo_Win32 +{ + SST_NetAddrInfoFlags flags; + SST_NetAddressFamily family; + SST_NetSocketType socketType; + SST_NetProtocol protocol; + char* canonicalName; + SOCKADDR_STORAGE addr; + struct SST_NetAddrInfo_Win32* next; +} SST_NetAddrInfo_Win32; +SST_NetResult SST_Net_CreateSocketSet( SST_NetSocketSet* _out ) +{ + fd_set* ret; + + ret = (fd_set*) calloc( 1, sizeof(fd_set) ); + if (ret == NULL) + { + return SSTNETRESULT_NOSPACE; + } + else + { + *_out = (SST_NetSocketSet) ret; + return SSTNETRESULT_SUCCESS; + } +} + +void SST_Net_DestroySocketSet( SST_NetSocketSet _set ) +{ + free( (void*) _set ); +} + +void SST_Net_ClearSocketFromSocketSet( SST_NetSocketSet _set, SST_Socket _sock) +{ + FD_CLR( ( *(SOCKET*)_sock), (fd_set*) _set ); +} + +void SST_Net_AddSocketToSocketSet( SST_NetSocketSet _set, SST_Socket _sock) +{ + FD_SET( ( *(SOCKET*)_sock), (fd_set*) _set ); +} + +int SST_Net_IsSocketInSocketSet( SST_NetSocketSet _set, SST_Socket _sock) +{ + return FD_ISSET( ( *(SOCKET*)_sock), (fd_set*) _set ); +} + +void SST_Net_ZeroSocketSet( SST_NetSocketSet _set) +{ + FD_ZERO( (fd_set*) _set ); +} + +static SST_NetResult decodeerror_select(int _errcode) +{ + switch( _errcode ) + { + case WSANOTINITIALISED: return SSTNETRESULT_NETNOTINIT; break; + case WSAEFAULT: return SSTNETRESULT_BADPOINTER; break; + case WSAENETDOWN: return SSTNETRESULT_NETDOWN; break; + case WSAEINVAL: return SSTNETRESULT_INVALIDARGS; break; + case WSAEINTR: return SSTNETRESULT_INTERRUPTED; break; + case WSAEINPROGRESS: return SSTNETRESULT_INPROGRESS; break; + case WSAENOTSOCK: return SSTNETRESULT_NOTASOCKET; break; + + default: return SSTNETRESULT_UNKNOWN; break; + } +} + +SST_NetResult SST_Net_Select( size_t _numSockets, SST_NetSocketSet _readSockets, SST_NetSocketSet _writeSockets, SST_NetSocketSet _errorSockets, SST_NetTimeval* _timeout, size_t* _numEvented) +{ + int numEvented; + struct timeval timeVal; /* really, Winsock? You couldn't typedef this? */ + + if (_timeout != NULL) + { + timeVal.tv_sec = _timeout->seconds; + timeVal.tv_usec = _timeout->microseconds; + } + else + { + timeVal.tv_sec = 0; + timeVal.tv_usec = 0; + } + + numEvented = select((int) _numSockets, + (fd_set*) _readSockets, + (fd_set*) _writeSockets, + (fd_set*) _errorSockets, + (_timeout != NULL)? &timeVal : NULL ); + + if (numEvented == SOCKET_ERROR) + { + return decodeerror_select(WSAGetLastError()); + } + else + { + *_numEvented = numEvented; + return SSTNETRESULT_SUCCESS; + } +} + +static SST_NetResult decodeerror_poll(int _errcode) +{ + switch( _errcode ) + { + case WSAENETDOWN: return SSTNETRESULT_NETDOWN; break; + case WSAEFAULT: return SSTNETRESULT_BADPOINTER; break; + case WSAEINVAL: return SSTNETRESULT_INVALIDARGS; break; + case WSAENOBUFS: return SSTNETRESULT_NOSPACE; break; + + default: return SSTNETRESULT_UNKNOWN; break; + } +} + +SST_NetResult SST_Net_CreatePollDescriptorSet(size_t _numDescriptors, SST_NetPollDescriptorSet* _out) +{ + WSAPOLLFD* fds; + SST_NetPollDescriptorSet_Win32* ret; + + fds = (WSAPOLLFD*) calloc(_numDescriptors, sizeof(WSAPOLLFD)); + if (fds == NULL) + return SSTNETRESULT_NOSPACE; + + ret = (SST_NetPollDescriptorSet_Win32*) malloc( sizeof(SST_NetPollDescriptorSet_Win32) ); + if (ret == NULL) + { + free(fds); + return SSTNETRESULT_NOSPACE; + } + + ret->Count = _numDescriptors; + ret->Descriptors = fds; + *_out = ret; + + return SSTNETRESULT_SUCCESS; +} + +void SST_Net_DestroyPollDescriptorSet(SST_NetPollDescriptorSet _toDestroy) +{ + SST_NetPollDescriptorSet_Win32* desc = (SST_NetPollDescriptorSet_Win32*) _toDestroy; + + free(desc->Descriptors); + desc->Descriptors = NULL; + desc->Count = 0; +} + +void SST_Net_SetPollDescriptorSocket(SST_NetPollDescriptorSet _descriptors, size_t _which, SST_Socket _socket) +{ + SST_NetPollDescriptorSet_Win32* desc = (SST_NetPollDescriptorSet_Win32*) _descriptors; + desc->Descriptors[_which].fd = *((SOCKET*) _socket); +} + +SST_Socket SST_Net_GetPollDescriptorSocket(SST_NetPollDescriptorSet _descriptors, size_t _which ) +{ + SST_Socket ret; + SST_NetPollDescriptorSet_Win32* desc = (SST_NetPollDescriptorSet_Win32*) _descriptors; + + if (convertWinSocketToSSTSocket(&(desc->Descriptors[_which].fd), &ret) != SSTNETRESULT_SUCCESS) + { + return SSTNET_INVALIDSOCKET; + } + else + { + return ret; + } +} + +static short convertSSTPollFlagsToWinPollFlags(SST_NetPollFlag _flags) +{ + short ret = 0; + + ret |= (_flags & SSTNETPOLLFLAG_POLLPRI)? POLLPRI : 0; + ret |= (_flags & SSTNETPOLLFLAG_POLLRDBAND)? POLLRDBAND : 0; + ret |= (_flags & SSTNETPOLLFLAG_POLLRDNORM)? POLLRDNORM : 0; + ret |= (_flags & SSTNETPOLLFLAG_POLLWRNORM)? POLLWRNORM : 0; + ret |= (_flags & SSTNETPOLLFLAG_POLLERR)? POLLERR : 0; + ret |= (_flags & SSTNETPOLLFLAG_POLLHUP)? POLLHUP : 0; + ret |= (_flags & SSTNETPOLLFLAG_POLLNVAL)? POLLNVAL : 0; + + return ret; +} + +void SST_Net_SetPollDescriptorFlag(SST_NetPollDescriptorSet _descriptors, size_t _which, SST_NetPollFlag _flags) +{ + SST_NetPollDescriptorSet_Win32* desc = (SST_NetPollDescriptorSet_Win32*) _descriptors; + desc->Descriptors[_which].events = convertSSTPollFlagsToWinPollFlags(_flags); +} + +static short convertWinPollFlagsToSSTPollFlags(short _flags) +{ + SST_NetPollFlag ret = 0; + + ret |= (_flags & POLLPRI)? SSTNETPOLLFLAG_POLLPRI : 0; + ret |= (_flags & POLLRDBAND )? SSTNETPOLLFLAG_POLLRDBAND : 0; + ret |= (_flags & POLLRDNORM )? SSTNETPOLLFLAG_POLLRDNORM : 0; + ret |= (_flags & POLLWRNORM )? SSTNETPOLLFLAG_POLLWRNORM : 0; + ret |= (_flags & POLLERR )? SSTNETPOLLFLAG_POLLERR : 0; + ret |= (_flags & POLLHUP )? SSTNETPOLLFLAG_POLLHUP : 0; + ret |= (_flags & POLLNVAL )? SSTNETPOLLFLAG_POLLNVAL : 0; + + return ret; +} + +SST_NetPollFlag SST_Net_GetPollDescriptorFlags(SST_NetPollDescriptorSet _descriptors, size_t _which) +{ + SST_NetPollDescriptorSet_Win32* desc = (SST_NetPollDescriptorSet_Win32*) _descriptors; + return convertWinPollFlagsToSSTPollFlags(desc->Descriptors[_which].events); +} + +void SST_Net_ClearPollDescriptorFlags(SST_NetPollDescriptorSet _descriptors, size_t _which) +{ + SST_NetPollDescriptorSet_Win32* desc = (SST_NetPollDescriptorSet_Win32*) _descriptors; + desc->Descriptors[_which].events = 0; +} + +SST_NetPollFlag SST_Net_GetPollDescriptorEvents(SST_NetPollDescriptorSet _descriptors, size_t _which) +{ + SST_NetPollDescriptorSet_Win32* desc = (SST_NetPollDescriptorSet_Win32*) _descriptors; + return convertWinPollFlagsToSSTPollFlags(desc->Descriptors[_which].revents); +} + +SST_NetResult SST_Net_Poll( SST_NetPollDescriptorSet _toPoll, int _timeout, size_t* _numEvented) +{ + int polled = 0; + SST_NetPollDescriptorSet_Win32* set = (SST_NetPollDescriptorSet_Win32*) _toPoll; + + polled = WSAPoll( (WSAPOLLFD*)set->Descriptors, + (ULONG) set->Count, + _timeout); + + if (polled == SOCKET_ERROR) + { + return decodeerror_poll(WSAGetLastError()); + } + else + { + *_numEvented = polled; + return SSTNETRESULT_SUCCESS; + } +} + +static SST_NetResult decodeerror_getsockopt(int _errcode) +{ + switch( _errcode ) + { + case WSANOTINITIALISED: return SSTNETRESULT_NETNOTINIT; break; + case WSAENETDOWN: return SSTNETRESULT_NETDOWN; break; + case WSAEFAULT: return SSTNETRESULT_BADPOINTER; break; + case WSAEINPROGRESS: return SSTNETRESULT_INPROGRESS; break; + case WSAEINVAL: return SSTNETRESULT_INVALIDARGS; break; + case WSAENOPROTOOPT: return SSTNETRESULT_PROTOCOLOPNOTSUPPORED; break; + case WSAENOTSOCK: return SSTNETRESULT_NOTASOCKET; break; + + default: return SSTNETRESULT_UNKNOWN; break; + } +} + +static int convertSSTSockOptToWinSockOpt( SST_NetSocketOption _in, int* _out) +{ + int ret = 0; + switch(_in) + { + case SSTNETSOCKOPT_DEBUG: ret = SO_DEBUG; break; + case SSTNETSOCKOPT_ACCEPTCONN: ret = SO_ACCEPTCONN; break; + case SSTNETSOCKOPT_BROADCAST: ret = SO_BROADCAST; break; + case SSTNETSOCKOPT_REUSEADDR: ret = SO_REUSEADDR; break; + case SSTNETSOCKOPT_KEEPALIVE: ret = SO_KEEPALIVE; break; + case SSTNETSOCKOPT_LINGER: ret = SO_LINGER; break; + case SSTNETSOCKOPT_OOBINLINE: ret = SO_OOBINLINE; break; + case SSTNETSOCKOPT_SENDBUFFERSIZE: ret = SO_SNDBUF; break; + case SSTNETSOCKOPT_RECVBUFFERSIZE: ret = SO_RCVBUF; break; + case SSTNETSOCKOPT_ERRORSTATUS: ret = SO_ERROR; break; + case SSTNETSOCKOPT_SOCKETTYPE: ret = SO_TYPE; break; + case SSTNETSOCKOPT_DONTROUTE: ret = SO_DONTROUTE; break; + + default: return -1; break; + } + + *_out = ret; + return 0; +} + +static int convertSSTSockLevelToWinSockLevel( SST_NetProtocolLevel _in, int* _out) +{ + int ret = 0; + switch(_in) + { + case SSTNETPROTOLEVEL_SOCKET: ret = SO_DEBUG; break; + default: return -1; break; + } + + *_out = ret; + return 0; +} + +SST_NetResult SST_Net_GetSockOpt( SST_Socket _socket, SST_NetProtocolLevel _level, SST_NetSocketOption _option, void* _optionStorage, size_t* _optionStorageSize) +{ + int winsockopt; + int winsocklevel; + int errcode; + int optlen; + + if (convertSSTSockLevelToWinSockLevel(_level, &winsocklevel) != 0) + return SSTNETRESULT_BADPROTOCOLLEVEL; + + if (convertSSTSockOptToWinSockOpt(_option, &winsockopt) != 0) + return SSTNETRESULT_BADSOCKETOP; + + optlen = (int) _optionStorageSize; + errcode = getsockopt( *((SOCKET*)_socket), + winsocklevel, + winsockopt, + (char*) _optionStorage, + &optlen); + if (errcode == SOCKET_ERROR) + { + return decodeerror_getsockopt(WSAGetLastError()); + } + else + { + *_optionStorageSize = (size_t) optlen; + return SSTNETRESULT_SUCCESS; + } +} + +static SST_NetResult decodeerror_setsockopt(int _errcode) +{ + switch( _errcode ) + { + case WSANOTINITIALISED: return SSTNETRESULT_NETNOTINIT; break; + case WSAENETDOWN: return SSTNETRESULT_NETDOWN; break; + case WSAEFAULT: return SSTNETRESULT_BADPOINTER; break; + case WSAEINPROGRESS: return SSTNETRESULT_INPROGRESS; break; + case WSAEINVAL: return SSTNETRESULT_INVALIDARGS; break; + case WSAENETRESET: return SSTNETRESULT_NETRESET; break; + case WSAENOPROTOOPT: return SSTNETRESULT_PROTOCOLOPNOTSUPPORED; break; + case WSAENOTCONN: return SSTNETRESULT_NOTCONNECTED; break; + case WSAENOTSOCK: return SSTNETRESULT_NOTASOCKET; break; + + default: return SSTNETRESULT_UNKNOWN; break; + } +} +SST_NetResult SST_Net_SetSockOpt( SST_Socket _socket, SST_NetProtocolLevel _level, SST_NetSocketOption _option, const void* _optionData, size_t* _optionDataSize) +{ + int winsockopt; + int winsocklevel; + int errcode; + int optlen; + + if (convertSSTSockLevelToWinSockLevel(_level, &winsocklevel) != 0) + return SSTNETRESULT_BADPROTOCOLLEVEL; + + if (convertSSTSockOptToWinSockOpt(_option, &winsockopt) != 0) + return SSTNETRESULT_BADSOCKETOP; + + optlen = (int) *_optionDataSize; + errcode = getsockopt( *((SOCKET*)_socket), + winsocklevel, + winsockopt, + (char*) _optionData, + &optlen); + if (errcode == SOCKET_ERROR) + { + return decodeerror_setsockopt(WSAGetLastError()); + } + else + { + *_optionDataSize = (size_t) optlen; + return SSTNETRESULT_SUCCESS; + } +} + +static SST_NetResult decodeerror_pton(int _errcode) +{ + switch( _errcode ) + { + case WSAEAFNOSUPPORT: return SSTNETRESULT_ADDRFAMNOTSUPPORTED; break; + case WSAEFAULT: return SSTNETRESULT_BADPOINTER; break; + + default: return SSTNETRESULT_UNKNOWN; break; + } +} + +SST_NetResult SST_Net_PToN( SST_NetAddressFamily _family, const char* _addressText, SST_NetAddress _storage) +{ + int af = 0; + int errcode = 0; + void* addr = NULL; + + struct in_addr* v4addr = &( ((struct sockaddr_in*)_storage)->sin_addr ); + struct in6_addr* v6addr = &( ((struct sockaddr_in6*)_storage)->sin6_addr ); + + switch (_family) + { + case SSTNETADDRFAM_IPV4: af = AF_INET; + addr = (void*) v4addr; + ((struct sockaddr_in*)_storage)->sin_family = AF_INET; + break; + case SSTNETADDRFAM_IPV6: af = AF_INET6; + addr = (void*) v6addr; + ((struct sockaddr_in6*)_storage)->sin6_family = AF_INET6; + break; + default: return SSTNETRESULT_ADDRFAMNOTSUPPORTED; break; + } + + errcode = InetPton( af, + _addressText, + addr ); + if (errcode == 1) + { + return SSTNETRESULT_SUCCESS; + } + else + { + if (errcode == 0) + { + return SSTNETRESULT_BADADDRESSSTRING; + } + else + { + return decodeerror_pton(WSAGetLastError()); + } + } +} + +static SST_NetResult decodeerror_ntop(int _errcode) +{ + switch( _errcode ) + { + case WSAEAFNOSUPPORT: return SSTNETRESULT_ADDRFAMNOTSUPPORTED; break; + case ERROR_INVALID_PARAMETER: return SSTNETRESULT_INVALIDARGS; break; + + default: return SSTNETRESULT_UNKNOWN; break; + } +} + +SST_NetResult SST_Net_NToP( SST_NetAddressFamily _family, SST_NetAddress _data, char* _addressTextStorage, size_t _addressTextStorageLength) +{ + char* retval = NULL; + struct sockaddr_storage* ss = (struct sockaddr_storage*) _data; + + switch (_family) + { + case SSTNETADDRFAM_IPV4: retval = (char*) InetNtop(AF_INET, &(((struct sockaddr_in*)ss)->sin_addr), _addressTextStorage, _addressTextStorageLength); break; + case SSTNETADDRFAM_IPV6: retval = (char*) InetNtop(AF_INET6, &(((struct sockaddr_in6*)ss)->sin6_addr), _addressTextStorage, _addressTextStorageLength); break; + default: return SSTNETRESULT_ADDRFAMNOTSUPPORTED; break; + } + + if (retval == NULL) + { + return decodeerror_ntop(WSAGetLastError()); + } + else + { + return SSTNETRESULT_SUCCESS; + } +} + +static SST_NetResult decodeerror_getaddrinfo( int _errcode ) +{ + switch( _errcode ) + { + case WSATRY_AGAIN: return SSTNETRESULT_TRYAGAIN; break; + case WSAEINVAL: return SSTNETRESULT_INVALIDARGS; break; + case WSANO_RECOVERY: return SSTNETRESULT_HOSTUNREACHABLE; break; + case WSAEAFNOSUPPORT: return SSTNETRESULT_ADDRFAMNOTSUPPORTED; break; + case WSA_NOT_ENOUGH_MEMORY: return SSTNETRESULT_NOSPACE; break; + case WSAHOST_NOT_FOUND: return SSTNETRESULT_HOSTUNREACHABLE; break; + case WSATYPE_NOT_FOUND: return SSTNETRESULT_SERVICENOTSUPPORTED; break; + case WSAESOCKTNOSUPPORT: return SSTNETRESULT_SOCKETNOTSUPPORTED; break; + + default: return SSTNETRESULT_UNKNOWN; break; + } +} + +static SST_NetResult convertSSTAddrHintsToWinAddrHints( const SST_NetAddrHints* _hints, struct addrinfo* _winHints ) +{ + int tempflags = 0; + + /* handle address family */ + switch (_hints->addressFamily) + { + case SSTNETADDRFAM_IPV4: _winHints->ai_family = AF_INET; break; + case SSTNETADDRFAM_IPV6: _winHints->ai_family = AF_INET6; break; + default: return SSTNETRESULT_ADDRFAMNOTSUPPORTED; break; + } + + /* handle socket type */ + switch (_hints->socketType) + { + case SSTNETSOCKTYPE_STREAM: _winHints->ai_socktype = SOCK_STREAM; break; + case SSTNETSOCKTYPE_DATAGRAM: _winHints->ai_socktype = SOCK_DGRAM; break; + default: return SSTNETRESULT_SOCKETNOTSUPPORTED; break; + } + + /* handle protocol */ + switch (_hints->protocolType) + { + case SSTNETPROTOCOL_TCP: _winHints->ai_protocol = IPPROTO_TCP; break; + case SSTNETPROTOCOL_UDP: _winHints->ai_protocol = IPPROTO_UDP; break; + default: return SSTNETRESULT_PROTOCOLNOTSUPPORTED; break; + } + + /* handle flags */ + tempflags |= (_hints->flags & SSTNETAINFOFLAG_PASSIVE) ? AI_PASSIVE : 0; + tempflags |= (_hints->flags & SSTNETAINFOFLAG_CANONICALNAME) ? AI_CANONNAME : 0; + tempflags |= (_hints->flags & SSTNETAINFOFLAG_NUMERICHOST) ? AI_NUMERICHOST : 0; + tempflags |= (_hints->flags & SSTNETAINFOFLAG_ADDRESSCONFIG) ? AI_ADDRCONFIG : 0; + tempflags |= (_hints->flags & SSTNETAINFOFLAG_NONAUTHORATATIVE) ? AI_NON_AUTHORITATIVE : 0; + tempflags |= (_hints->flags & SSTNETAINFOFLAG_SECURE) ? AI_SECURE : 0; + tempflags |= (_hints->flags & SSTNETAINFOFLAG_RETURNPREFERREDNAME) ? AI_RETURN_PREFERRED_NAMES : 0; + tempflags |= (_hints->flags & SSTNETAINFOFLAG_FILESERVER) ? AI_FILESERVER : 0; + _winHints->ai_flags = tempflags; + + return SSTNETRESULT_SUCCESS; +} + +static SST_NetResult copySingleWinAddrInfoToSSTAddrInfo( const ADDRINFO* _winInfo, SST_NetAddrInfo_Win32* _sstInfo ) +{ + SST_NetAddrInfoFlags tempflags = 0; + int winFlags = 0; + + /* handle address family */ + switch (_winInfo->ai_family) + { + case AF_INET: _sstInfo->family = SSTNETADDRFAM_IPV4; break; + case AF_INET6: _sstInfo->family = SSTNETADDRFAM_IPV6; break; + default: _sstInfo->family = SSTNETADDRFAM_UNKNOWN; break; + } + + /* handle socket type */ + switch (_winInfo->ai_socktype) + { + case SOCK_STREAM: _sstInfo->socketType = SSTNETSOCKTYPE_STREAM; break; + case SOCK_DGRAM: _sstInfo->socketType = SSTNETSOCKTYPE_DATAGRAM; break; + default: _sstInfo->socketType = SSTNETSOCKTYPE_UNKNOWN; break; + } + + /* handle protocol */ + switch (_winInfo->ai_protocol) + { + case IPPROTO_TCP: _sstInfo->protocol = SSTNETPROTOCOL_TCP; break; + case IPPROTO_UDP: _sstInfo->protocol = SSTNETPROTOCOL_UDP; break; + default: _sstInfo->protocol = SSTNETPROTOCOL_UNKNOWN; break; + } + + /* handle flags */ + winFlags = _winInfo->ai_flags; + tempflags |= (winFlags & AI_PASSIVE) ? SSTNETAINFOFLAG_PASSIVE : 0; + tempflags |= (winFlags & AI_CANONNAME) ? SSTNETAINFOFLAG_CANONICALNAME : 0; + tempflags |= (winFlags & AI_NUMERICHOST) ? SSTNETAINFOFLAG_NUMERICHOST : 0; + tempflags |= (winFlags & AI_ADDRCONFIG) ? SSTNETAINFOFLAG_ADDRESSCONFIG : 0; + tempflags |= (winFlags & AI_NON_AUTHORITATIVE) ? SSTNETAINFOFLAG_NONAUTHORATATIVE : 0; + tempflags |= (winFlags & AI_SECURE) ? SSTNETAINFOFLAG_SECURE : 0; + tempflags |= (winFlags & AI_RETURN_PREFERRED_NAMES) ? SSTNETAINFOFLAG_RETURNPREFERREDNAME : 0; + tempflags |= (winFlags & AI_FILESERVER) ? SSTNETAINFOFLAG_FILESERVER : 0; + _sstInfo->flags = tempflags; + + /* handle canonical name */ + _sstInfo->canonicalName = _strdup(_winInfo->ai_canonname); + if (_sstInfo->canonicalName == NULL) + return SSTNETRESULT_NOSPACE; + + /* handle sockaddr info */ + memcpy( &(_sstInfo->addr), + &(_winInfo->ai_addr), + _winInfo->ai_addrlen); + + return SSTNETRESULT_SUCCESS; +} + +static SST_NetResult convertWinAddrInfoToSSTAddrInfo( ADDRINFO* _winai, SST_NetAddrInfo_Win32** _out ) +{ + SST_NetAddrInfo_Win32* root = NULL; + SST_NetAddrInfo_Win32* prev = NULL; + SST_NetAddrInfo_Win32* temp = NULL; + ADDRINFO* currWinInfo = _winai; + + while (currWinInfo != NULL) + { + /* allocate our temp node space */ + temp = calloc( 1, sizeof(SST_NetAddrInfo_Win32) ); + if (temp == NULL) + { + /* handle out of memory... */ + if (root != NULL) + { + SST_Net_FreeAddrInfo(root); + } + *_out = NULL; + return SSTNETRESULT_NOSPACE; + } + + /* if we haven't had a root node yet, set that */ + if (root == NULL) + { + root = temp; + } + + /* if we have a previous node, attach us as the next node */ + if (prev != NULL) + { + prev->next = temp; + } + + /* copy over attributes, bail if we can't */ + temp->next = NULL; + if ( copySingleWinAddrInfoToSSTAddrInfo(currWinInfo, temp) != SSTNETRESULT_SUCCESS ) + { + /* handle out of memory... */ + if (root != NULL) + { + SST_Net_FreeAddrInfo(root); + } + *_out = NULL; + return SSTNETRESULT_NOSPACE; + } + + /* set us to be the previous node */ + prev = temp; + + /* go to next record */ + currWinInfo = currWinInfo->ai_next; + } + + return SSTNETRESULT_SUCCESS; +}; + +SST_NetResult SST_Net_GetAddrInfo( const char* _node, const char* _service, const SST_NetAddrHints* _hints, SST_NetAddrInfo* _results) +{ + int errcode = 0; + ADDRINFO hints; + ADDRINFO* results; + ADDRINFO* currResult; + SST_NetAddrInfo_Win32* ret; + SST_NetResult convret; + size_t recordCount = 0; + + /* convert the hints */ + memset(&hints, 0, sizeof(struct addrinfo)); + convret = convertSSTAddrHintsToWinAddrHints(_hints, &hints); + if ( convret != SSTNETRESULT_SUCCESS ) + { + return convret; + } + + /* do the lookup */ + errcode = getaddrinfo(_node, _service, (struct addrinfo*) _hints, &results); + if ( errcode != 0 ) + { + return decodeerror_getaddrinfo(errcode); + } + + /* count the number of records */ + currResult = results; + while (currResult != NULL) + { + currResult = currResult->ai_next; + recordCount++; + } + + /* convert results */ + *_results = NULL; + convret = convertWinAddrInfoToSSTAddrInfo(results, &ret); + if (convret == SSTNETRESULT_SUCCESS) + { + *_results = ret; + } + + /* cleanup */ + freeaddrinfo(results); + + return convret; +} + +void SST_Net_FreeAddrInfo( SST_NetAddrInfo _toFree ) +{ + SST_NetAddrInfo_Win32* root = (SST_NetAddrInfo_Win32*) _toFree; + SST_NetAddrInfo_Win32* curr; + SST_NetAddrInfo_Win32* temp; + + + curr = root; + while (curr != NULL) + { + /* free strings */ + free(curr->canonicalName); + curr->canonicalName = NULL; + + /* save where we are and free it */ + temp = curr; + curr = curr->next; + free(temp); + } +} + +static SST_NetResult decodeerror_getnameinfo( int _errcode ) +{ + switch( _errcode ) + { + case WSATRY_AGAIN: return SSTNETRESULT_TRYAGAIN; break; + case WSAEINVAL: return SSTNETRESULT_INVALIDARGS; break; + case WSANO_RECOVERY: return SSTNETRESULT_HOSTUNREACHABLE; break; + case WSAEAFNOSUPPORT: return SSTNETRESULT_ADDRFAMNOTSUPPORTED; break; + case WSA_NOT_ENOUGH_MEMORY: return SSTNETRESULT_NOSPACE; break; + case WSAHOST_NOT_FOUND: return SSTNETRESULT_HOSTUNREACHABLE; break; + case WSAEFAULT: return SSTNETRESULT_BADPOINTER; break; + + default: return SSTNETRESULT_UNKNOWN; break; + } +} + +SST_NetResult SST_Net_GetNameInfo(SST_NetAddress _address, char* _hostName, size_t _hostNameLength, char* _serviceName, size_t _serviceNameLength, SST_NetNameInfoFlags _flags) +{ + int flags = 0; + int errcode = 0; + + flags |= ( _flags &SSTNETNINFOFLAGS_NOFQDN) ? NI_NOFQDN : 0; + flags |= ( _flags &SSTNETNINFOFLAGS_NUMBERICHOST) ? NI_NUMERICHOST : 0; + flags |= ( _flags &SSTNETNINFOFLAGS_NAMEREQD) ? NI_NAMEREQD : 0; + flags |= ( _flags &SSTNETNINFOFLAGS_NUMERICSERVICE) ? NI_NUMERICSERV : 0; + flags |= ( _flags &SSTNETNINFOFLAGS_DATAGRAM) ? NI_DGRAM : 0; + + errcode = getnameinfo( (const struct sockaddr*) _address, + sizeof(SOCKADDR_STORAGE), + _hostName, + (DWORD) _hostNameLength, + _serviceName, + (DWORD) _serviceNameLength, + flags ); + + if (errcode != 0) + { + return decodeerror_getnameinfo(WSAGetLastError()); + } + else + { + return SSTNETRESULT_SUCCESS; + } +} \ No newline at end of file diff --git a/libsst-net/Win32Private.h b/libsst-net/Win32Private.h new file mode 100644 index 0000000..bfd4948 --- /dev/null +++ b/libsst-net/Win32Private.h @@ -0,0 +1,40 @@ +/* + Win32Private.h + Author: Chris Ertel <crertel@762studios.com> + Created: 07/15/2012 + + Purpose: + + Private data structures for Win32 implementation of libsst-net. Not to be distributed + as part of public SDK headers. + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ + +#pragma once + +#ifndef _WIN32PRIVATE_H +#define _WIN32PRIVATE_H + +#define _WIN32_WINNT 0x0601 /* Windows 7 or later */ +#define WIN32_LEAN_AND_MEAN + +#include <windows.h> +#include <winsock2.h> +#include <ws2tcpip.h> +#include <ws2ipdef.h> + +typedef SOCKET NativeSocketType; +typedef int NativeSocketLen; +#define SST_NATIVE_INVALIDSOCKET INVALID_SOCKET +#define SST_NATIVE_NETERROR SOCKET_ERROR +#define NativeCloseSocket(s) closesocket(s) +#define NativeIoctl(s, cmd, arg) ioctlsocket(s, cmd, arg) +#endif diff --git a/libsst-net/libsst-net.vcxproj b/libsst-net/libsst-net.vcxproj new file mode 100644 index 0000000..0469eed --- /dev/null +++ b/libsst-net/libsst-net.vcxproj @@ -0,0 +1,163 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup Label="ProjectConfigurations"> + <ProjectConfiguration Include="Debug|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectGuid>{E6679A2F-6C8E-4555-9228-6929C734CEF4}</ProjectGuid> + <RootNamespace>libsstnet</RootNamespace> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> + <ConfigurationType>StaticLibrary</ConfigurationType> + <PlatformToolset>v110</PlatformToolset> + <CharacterSet>MultiByte</CharacterSet> + <WholeProgramOptimization>true</WholeProgramOptimization> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> + <ConfigurationType>StaticLibrary</ConfigurationType> + <PlatformToolset>v110</PlatformToolset> + <CharacterSet>MultiByte</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> + <ConfigurationType>StaticLibrary</ConfigurationType> + <PlatformToolset>v110</PlatformToolset> + <CharacterSet>MultiByte</CharacterSet> + <WholeProgramOptimization>true</WholeProgramOptimization> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> + <ConfigurationType>StaticLibrary</ConfigurationType> + <PlatformToolset>v110</PlatformToolset> + <CharacterSet>MultiByte</CharacterSet> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <ImportGroup Label="ExtensionSettings"> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <PropertyGroup Label="UserMacros" /> + <PropertyGroup> + <_ProjectFileVersion>11.0.50727.1</_ProjectFileVersion> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <OutDir>$(SolutionDir)\Lib\x86\</OutDir> + <IntDir>$(SolutionDir)Intermediate\$(Configuration)\$(Platform)\$(ProjectName)\</IntDir> + <TargetName>$(ProjectName)-debug</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <OutDir>$(SolutionDir)\Lib\x64\</OutDir> + <IntDir>$(SolutionDir)Intermediate\$(Configuration)\$(Platform)\$(ProjectName)\</IntDir> + <TargetName>$(ProjectName)-debug</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <OutDir>$(SolutionDir)\Lib\x86\</OutDir> + <IntDir>$(SolutionDir)Intermediate\$(Configuration)\$(Platform)\$(ProjectName)\</IntDir> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <OutDir>$(SolutionDir)\Lib\x64\</OutDir> + <IntDir>$(SolutionDir)Intermediate\$(Configuration)\$(Platform)\$(ProjectName)\</IntDir> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <Optimization>Disabled</Optimization> + <AdditionalIncludeDirectories>$(SolutionDir)Lib\Include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <MinimalRebuild>false</MinimalRebuild> + <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> + <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> + <WarningLevel>Level4</WarningLevel> + <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> + <MultiProcessorCompilation>true</MultiProcessorCompilation> + <StringPooling>true</StringPooling> + </ClCompile> + <Lib /> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Midl> + <TargetEnvironment>X64</TargetEnvironment> + </Midl> + <ClCompile> + <Optimization>Disabled</Optimization> + <AdditionalIncludeDirectories>$(SolutionDir)Lib\Include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <MinimalRebuild>false</MinimalRebuild> + <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> + <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> + <WarningLevel>Level4</WarningLevel> + <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> + <MultiProcessorCompilation>true</MultiProcessorCompilation> + <StringPooling>true</StringPooling> + </ClCompile> + <Lib /> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <Optimization>MaxSpeed</Optimization> + <IntrinsicFunctions>true</IntrinsicFunctions> + <AdditionalIncludeDirectories>$(SolutionDir)Lib\Include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> + <FunctionLevelLinking>true</FunctionLevelLinking> + <WarningLevel>Level4</WarningLevel> + <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> + <MultiProcessorCompilation>true</MultiProcessorCompilation> + <StringPooling>true</StringPooling> + </ClCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Midl> + <TargetEnvironment>X64</TargetEnvironment> + </Midl> + <ClCompile> + <Optimization>MaxSpeed</Optimization> + <IntrinsicFunctions>true</IntrinsicFunctions> + <AdditionalIncludeDirectories>$(SolutionDir)Lib\Include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> + <FunctionLevelLinking>true</FunctionLevelLinking> + <WarningLevel>Level4</WarningLevel> + <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> + <MultiProcessorCompilation>true</MultiProcessorCompilation> + <StringPooling>true</StringPooling> + </ClCompile> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="SST_NetAddress.c" /> + <ClCompile Include="SST_NetSocket.c" /> + <ClCompile Include="SST_NetInit_Win32.c" /> + <ClCompile Include="SST_NetResult_Win32.c" /> + </ItemGroup> + <ItemGroup> + <ClInclude Include="PlatformPrivate.h" /> + <ClInclude Include="Win32Private.h" /> + <ClInclude Include="..\Lib\Include\SST\SST_Net.h" /> + <ClInclude Include="..\Lib\Include\SST\SST_NetAddress.h" /> + <ClInclude Include="..\Lib\Include\SST\SST_NetResult.h" /> + <ClInclude Include="..\Lib\Include\SST\SST_NetSocket.h" /> + <ClInclude Include="..\Lib\Include\SST\SST_NetTypes.h" /> + </ItemGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> + <ImportGroup Label="ExtensionTargets"> + </ImportGroup> +</Project> \ No newline at end of file diff --git a/libsst-net/libsst-net.vcxproj.filters b/libsst-net/libsst-net.vcxproj.filters new file mode 100644 index 0000000..0a3f8f9 --- /dev/null +++ b/libsst-net/libsst-net.vcxproj.filters @@ -0,0 +1,63 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup> + <Filter Include="Source Files"> + <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier> + <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions> + </Filter> + <Filter Include="Source Files\Crossplatform"> + <UniqueIdentifier>{e3f3c5ec-e302-4820-ae8b-c035c895fd62}</UniqueIdentifier> + </Filter> + <Filter Include="Source Files\Private"> + <UniqueIdentifier>{d95db6dc-a57d-48c0-b644-d334e7e9e051}</UniqueIdentifier> + </Filter> + <Filter Include="Source Files\Win32"> + <UniqueIdentifier>{7009320b-8cf4-4dd4-9fc5-3cac9de62341}</UniqueIdentifier> + </Filter> + <Filter Include="Header Files"> + <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier> + <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> + </Filter> + <Filter Include="Resource Files"> + <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier> + <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav</Extensions> + </Filter> + </ItemGroup> + <ItemGroup> + <ClCompile Include="SST_NetAddress.c"> + <Filter>Source Files\Crossplatform</Filter> + </ClCompile> + <ClCompile Include="SST_NetSocket.c"> + <Filter>Source Files\Crossplatform</Filter> + </ClCompile> + <ClCompile Include="SST_NetInit_Win32.c"> + <Filter>Source Files\Win32</Filter> + </ClCompile> + <ClCompile Include="SST_NetResult_Win32.c"> + <Filter>Source Files\Win32</Filter> + </ClCompile> + </ItemGroup> + <ItemGroup> + <ClInclude Include="PlatformPrivate.h"> + <Filter>Source Files\Private</Filter> + </ClInclude> + <ClInclude Include="Win32Private.h"> + <Filter>Source Files\Private</Filter> + </ClInclude> + <ClInclude Include="..\Lib\Include\SST\SST_Net.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\Lib\Include\SST\SST_NetAddress.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\Lib\Include\SST\SST_NetResult.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\Lib\Include\SST\SST_NetSocket.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\Lib\Include\SST\SST_NetTypes.h"> + <Filter>Header Files</Filter> + </ClInclude> + </ItemGroup> +</Project> \ No newline at end of file diff --git a/libsst-net/obj/x86-64/release/SST_NetAddress.o b/libsst-net/obj/x86-64/release/SST_NetAddress.o new file mode 100644 index 0000000000000000000000000000000000000000..452c896a0b3f67f9f4c9176451d8e830861cdc53 GIT binary patch literal 4544 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 literal 0 HcmV?d00001 diff --git a/libsst-net/obj/x86-64/release/SST_NetInit_Generic.o b/libsst-net/obj/x86-64/release/SST_NetInit_Generic.o new file mode 100644 index 0000000000000000000000000000000000000000..97cfd701402a20f65e3477929477c8d5173fde51 GIT binary patch literal 1360 zcmb<-^>JfjWMqH=Mg}_u1P><4z%YRc!FB*M9T>P7I2b}bI-l+UX^1@xVor!X%;4_q zY^9(PnpB!sQmSC8XQF4IYgP*88P*w^=^2>lnQ21A6^slF%?!*8EEyO?z-BTqFjfUI zFjfdKO7pODOkiYSkYRvekTf@laO4wcV{+zYbK_y>fXdl`#2FYE*g-T*-U%WP62gW- zPG({F_#c}bGu9AbU|?oI3IrsL%nZy(JOq=Offd0)VlgwYA@LAQW(F1n2g(v>U|<kJ zat}BR7#J8-pyDt-*zX`c!NDQ%eyJs%d6^~g?x}gHMVZNZ$qZ1@c#trh6P!_6l9FGZ z2hyehA{ZFJK1B8<B(4$SF#8zviYs$V5|bG8ic5+hbOwx7l3G#1pqG+ZlE|Q!R9wuU zmz<xQo0?a`pqH0llB(zK7phxal9-&$pjVWdlc<-P5ua9+n41c90cDgl0|Pj;&_fvJ z4<R(;LFoWlND-<ZJw}6&6(O<F^{X>5Fo4n}x%zdW_8TDC0b;`JHwAH!FwA}!4U&hk zk(4pCBXf}0=xV*7_9LeOkn#=?!N9-}0i|IS$geOqh<0UQ0H<PDc!R`1m;-7c%wL=g z4B%V<(=P#1#K6EH$N<V`P!1Ah0o5OZBnD!lyC1}dDg{Zy@dGI91C-{1#uK{zAa|k1 Y9Z1UskiiTL4507@@nIM$4C68Y0PIOus{jB1 literal 0 HcmV?d00001 diff --git a/libsst-net/obj/x86-64/release/SST_NetResult_POSIX.o b/libsst-net/obj/x86-64/release/SST_NetResult_POSIX.o new file mode 100644 index 0000000000000000000000000000000000000000..f25d3998677cf322cb343c6578a83e382be2ae35 GIT binary patch literal 5472 zcmb<-^>JfjWMqH=Mg}_u1P><4!0<p2!FB*M9T@l+xEVq{I-hzpzY%x=66<DYe!<fG zBcH#WlaYa;^MFS;%TbW{{|Coi|FAGHFueT9z`$_a^^X9E{T9NO0I?rJ*dR+@US(il z*dYlLJqHn$1F`o**lHm5W(Zpm#9j_k%?@HM0I{S%tZ5(?6NuFVVzGi)O(2#m0|UeB z>K*(bs$>Tnh|1l;45HF@@PMfJ9bzCVVh10H3f!R#qP%vff+*)5pn!R8vx67JGu<Hr zqV#r%f++PJN+3#MhY*O8+`$c^gm#F7DDLB~f7BTm7$$VP{yBLV6dt2^Gz3ONU|>VQ z-PzenK_fJ&G_Ryo!Bo#g&p_9#6wEWMGc?mPFwry9gorB`85o)wm>F1t94rDN7#J8B ztAZF9D+Cy&dDuB7FfuTJ3Ih-ZNgIO72}eGGHYR6YHf9}09(E3pFjfpw%EIvRKQ>8b ztR*o612Y4t$imdY%m6B5v5A99Ky2dJ-NnqniK&<YWG|?kMU?`Ta6(A#1pA$VfkBgj zfdN#?qpD_LU<eKliT6t_2}&(4%_)fw@DKKk&`W0UODxGOOLa+2&QD2oEh@?{Vu+7V zEh@^(kI%_ZPAtjH&x0BSa~Y^~=VD-B`12nEKy?8~38>)3=37uWgY;|xDPmw?fcYFI zt^#5pxf#R-sfUS!YAKLbba4fcASgXBFfbsi*T5lefJ58@P5dd852<Szz#)umz6Vqu z=AJiDegKq)iMK-e5l|W?4)a$64)F{e;srRwD{zQ6;1KV?AwB_3+#AZD0j1I1532M* zQZR9Q5Ql+*VFi?iiNpN60f+bw9O4IXh@ZeAegTL04IJVRaEOE3Q&`f~2OR2u;1CBV z94zK=fC2`KxBw1u2^``IIK(w@h#TM#x4<FpfJ58^hj;)E@dzB^2{^<vaEKS+5U;=? z-he~A1BW=ME&)X)NE$i6&j1NviLV7X#8==D-+)6L+_uGH{sA27Pv8*0fJ6KS4)F&# z#9!bL|A0gM2M%#?p^U{}9H79(A})YKTmpx<0uFHv9O4Ez#4T`$JKzxaz#$%hLp%b9 zcmfXb3>@MGIK(S(h&SL6@4z8G0f+bu9O4Vm#QQ;+2UPx}iOWLM#|AWUeyI2kH1S-h zIS0_hVfDxfH1R~J`U_~{l~C~;XyR+3;t$ZoVdlR;69;u5L0UebiO&QHGB7awKodU% z6^AtyLEZ!@ftk+%Z9>AtVfB^(nmBA|Kmtu%45X2Pfk6RH{4>;E4K(p^sJH=|_+qHI z1)BITsJH`~IIQ0CKof`gD*#RW9@Lx&H1U&A@dPw+m^m3};@6?-3(&-OL&Yo5#Eqfi zu=XJ+>_HeR%)p>mT$x*vn8cu0Tv7y~GhnQu)SN`UlGKV42ECNTl0*i*q~c-*J+Np| zK13urKQ}iuuY^G_FTW&J&)qLnx40xRIUA}fH6uQ)C^0t`ZW;Luko!SV4H_#!HU-u$ zg|+u#av-%ZHi(vHU;y_@VCq3)AiM!;AgnzM8hrujg|*9J?QPI_4@evuydbS$TnG{b zvrq|iVI62&pIrTBNOc6VO|bgD0nK2T`(bJgarplM)c*~jP7DJB1IYiNehW-L%>Q;! z`(fb(GxrCyt7i%mfYLDk!)SM?eyB8@(gj%t=OGv{eK3(2sD6~R%fP^30M!rcx4_iH z+z;b}@;%6@=<%Nb8tP+UV1W4(<bP1#4yGR_4pN2|#9*T<KoSfL3~68<f<Sjah>z}e jkm?Mm`(fn?XiN{A{U9-H_7_0o&kAH15(e3a#AN^g(5Vjj literal 0 HcmV?d00001 diff --git a/libsst-net/obj/x86-64/release/SST_NetSocket.o b/libsst-net/obj/x86-64/release/SST_NetSocket.o new file mode 100644 index 0000000000000000000000000000000000000000..3e4bd3fd64e4f56c2c9288ab2f01509b176287ce GIT binary patch literal 6544 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 VkTy780jh*RQyw4-;G&rJ0{}oK$Z`Mx literal 0 HcmV?d00001 diff --git a/libsst-net/sources-POSIX.mk b/libsst-net/sources-POSIX.mk new file mode 100644 index 0000000..3f57570 --- /dev/null +++ b/libsst-net/sources-POSIX.mk @@ -0,0 +1,19 @@ +# libsst-net/sources-POSIX.mk +# Author: Patrick Baggett <ptbaggett@762studios.com> +# Created: 12/03/2012 +# +# Purpose: +# +# List of source files for POSIX-compliant systems. This reduces the amount +# of copy/pasting for different UNIX configurations. +# +# License: +# +# This program is free software. It comes without any warranty, to +# the extent permitted by applicable law. You can redistribute it +# and/or modify it under the terms of the Do What The Fuck You Want +# To Public License, Version 2, as published by Sam Hocevar. See +# http://sam.zoy.org/wtfpl/COPYING for more details. + +SRC += SST_NetInit_Generic.c \ + SST_NetResult_POSIX.c diff --git a/libsst-os/Makefile b/libsst-os/Makefile new file mode 100644 index 0000000..7862da5 --- /dev/null +++ b/libsst-os/Makefile @@ -0,0 +1,44 @@ +# libsst-os/Makefile +# Author: Patrick Baggett <ptbaggett@762studios.com> +# Created: 12/23/2011 +# +# Purpose: +# +# Makefile for libsst-os +# +# License: +# +# This program is free software. It comes without any warranty, to +# the extent permitted by applicable law. You can redistribute it +# and/or modify it under the terms of the Do What The Fuck You Want +# To Public License, Version 2, as published by Sam Hocevar. See +# http://sam.zoy.org/wtfpl/COPYING for more details. + +BINNAME := $(DIST)/libsst-os.a +ifeq ($(TARGET),debug) + BINNAME := $(subst .a,_d.a, $(BINNAME)) +endif + +include sources-$(SUBSYSTEM).mk + +OBJ := $(addprefix obj/$(ARCH)/$(TARGET)/,$(subst .c,.o,$(SRC))) obj/$(ARCH)/$(TARGET)/SST_CPUCache_$(ARCH).o + +$(shell mkdir -p obj/$(ARCH)/$(TARGET)) + +$(BINNAME): $(OBJ) + $(AR) cru $@ $+ + $(RANLIB) $@ + +# CLEAN +clean: + @-rm -r -f obj $(DIST)/libsst-os*.a + +# *.c files to *.o files +obj/$(ARCH)/$(TARGET)/%.o: %.c + @echo CC $@ + @$(CC) $(CFLAGS) -c $*.c -o obj/$(ARCH)/$(TARGET)/$*.o + +# *.asm files to *.o files +obj/$(ARCH)/$(TARGET)/%.o: %.asm + @echo ASM $@ + @$(ASM) $*.asm -o obj/$(ARCH)/$(TARGET)/$*.o diff --git a/libsst-os/POSIXPrivate.h b/libsst-os/POSIXPrivate.h new file mode 100644 index 0000000..fec1b68 --- /dev/null +++ b/libsst-os/POSIXPrivate.h @@ -0,0 +1,57 @@ +/* + POSIXPrivate.h + Author: Patrick Baggett <ptb1@762studios.com> + Created: 12/23/2011 + + Purpose: + + Private data structures for POSIX implementation of libsst-os. Not to be distributed + as part of public SDK headers. + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ + +#pragma once + +#ifndef _POSIXPRIVATE_H +#define _POSIXPRIVATE_H + +/* We *really* want 64-bit support */ +#define _LARGEFILE64_SOURCE +#define _FILE_OFFSET_BITS 64 +#include <pstdint.h> + +#include <stdlib.h> /* size_t, malloc(), free()*/ +#include <unistd.h> +#include <sys/mman.h> /* mmap(), mprotect(), munmap(), etc. */ + +/******************************************************************************/ +typedef struct SST_File_POSIX +{ + int fd; + int isAsync; /* Is this file in async mode */ + +#ifdef _DEBUG + int nrMmaps; /* Number of outstanding memory maps */ +#endif +} SST_File_POSIX; + +typedef struct SST_MemoryMap_POSIX +{ + uint64_t offset; /* Offset parameter as given to SST_OS_MmapCreate() */ + size_t len; /* Length parameter as given to SST_OS_MmapCreate() */ + void* base; /* Returned base address from SST_OS_MmapCreate() */ + +#ifdef _DEBUG + SST_File_POSIX* owner; /* File that created this memory map */ +#endif +} SST_MemoryMap_POSIX; + +#endif diff --git a/libsst-os/SST_Alloc.c b/libsst-os/SST_Alloc.c new file mode 100644 index 0000000..0a1129d --- /dev/null +++ b/libsst-os/SST_Alloc.c @@ -0,0 +1,118 @@ +/* + SST_Alloc.c + Author: Patrick Baggett <ptbaggett@762studios.com> + Created: 1/7/2012 + + Purpose: + + Provides portable implementations for various CRT-like memory functions + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ + +#include <SST/SST_Alloc.h> +#include <SST/SST_Assert.h> +#include <stdio.h> +#include <pstdint.h> +#include <limits.h> + +#define OVERFLOW_MESSAGE "Multiplication overflow in memory allocation" + +/*************************************************************************/ + +void* SST_OS_AlignPtr(void* ptr, size_t boundary) +{ + if ((((uintptr_t)ptr) % boundary) == 0) + return ptr; + + return (void*)((uintptr_t)ptr + (boundary) - ((uintptr_t)ptr % boundary)); +} + +/*************************************************************************/ + +void* SST_OS_AlignedMalloc(size_t bytes, size_t boundary) +{ + uintptr_t mask; + uintptr_t addr; + unsigned char delta; + void* base; + unsigned char* backptr; + + if(boundary == 0 || boundary > UCHAR_MAX) + return NULL; + + mask = (uintptr_t)(boundary - 1); + + /* Check if not a power 2 */ + if(boundary & mask) + return NULL; + + /* Allocate memory with some slack space */ + base = malloc(bytes + boundary); + if(base == NULL) + return NULL; + + /* Get aligned address. It'll be somewhere in the extra slackspace that we just malloc()'d */ + addr = ((uintptr_t)base + boundary - 1) & mask; + + /* Address was already aligned...but the free function expects a backtrack amount */ + if(addr == (uintptr_t)base) + addr += boundary; + + delta = (unsigned char)((addr - (uintptr_t)base) & 0xFF); + + backptr = (unsigned char*)(addr-1); + *backptr = delta-1; + + return (void*)addr; +} + +/*************************************************************************/ + +void SST_OS_AlignedFree(void* ptr) +{ + unsigned char* back = ((unsigned char*)ptr) - 1; + unsigned char delta; + + delta = *back; + + back = back - delta; + + free(back); +} + +/*************************************************************************/ + +void* SST_OS_SafeAlignedMalloc(size_t nelem, size_t elsize, size_t boundary) +{ + if(nelem > SIZE_MAX/elsize) + { + SST_OS_RuntimeError(OVERFLOW_MESSAGE); + + /* If app just swallows the error, then return NULL */ + return NULL; + } + return SST_OS_AlignedMalloc(nelem*elsize, boundary); +} + +/*************************************************************************/ + +void* SST_OS_SafeRealloc(void* ptr, size_t nelem, size_t elsize) +{ + if(nelem > SIZE_MAX/elsize) + { + SST_OS_RuntimeError(OVERFLOW_MESSAGE); + + /* If app just swallows the error, then return NULL */ + return NULL; + } + + return realloc(ptr, nelem * elsize); +} diff --git a/libsst-os/SST_Assert.c b/libsst-os/SST_Assert.c new file mode 100644 index 0000000..41fd925 --- /dev/null +++ b/libsst-os/SST_Assert.c @@ -0,0 +1,44 @@ +/* + SST_Assert.c + Author: Patrick Baggett <ptbaggett@762studios.com> + Created: 12/23/2011 + + Purpose: + + libsst-os common assert functions + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ + +#include <SST/SST_Assert.h> +#include <stdlib.h> /* NULL */ + +/*************************************************************************/ + +SST_AssertHandlerFunc sst_debug_assert_handler = NULL; /* Handler function for debug asserts */ +void* sst_debug_assert_handler_arg = NULL; /* Argument to the debug assert */ +SST_AssertHandlerFunc sst_runtime_assert_handler = NULL; /* Handler function for runtime asserts */ +void* sst_runtime_assert_handler_arg = NULL; /* Argument to the runtime assert */ + +/*************************************************************************/ + +void SST_OS_SetDebugAssertHandler(SST_AssertHandlerFunc _func, void *_arg) +{ + sst_debug_assert_handler = _func; + sst_debug_assert_handler_arg = _arg; +} + +/*************************************************************************/ + +void SST_OS_SetRuntimeAssertHandler(SST_AssertHandlerFunc _func, void *_arg) +{ + sst_runtime_assert_handler = _func; + sst_runtime_assert_handler_arg = _arg; +} diff --git a/libsst-os/SST_Assert_Generic.c b/libsst-os/SST_Assert_Generic.c new file mode 100644 index 0000000..06906f4 --- /dev/null +++ b/libsst-os/SST_Assert_Generic.c @@ -0,0 +1,74 @@ +/* + SST_Assert_Generic.c + Author: Patrick Baggett <ptb1@762studios.com> + Created: 12/23/2011 + + Purpose: + + libsst-os assert functions portable for any system with a C standard library + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ + +#include <SST/SST_Assert.h> + +#include <stdio.h> /* printf() */ +#include <stdlib.h> /* abort() */ + +/******************************************************************************/ + +void SST_OS_RuntimeAssertImpl(int condition, const char* condString, const char* msgString, const char* file, const char* func, int line) +{ + /* Assume likely success and exit early */ + if(condition) + return; + + /* Call the runtime handler if we have one */ + if (sst_runtime_assert_handler != 0) + if(sst_runtime_assert_handler(msgString, sst_runtime_assert_handler_arg)) + return; + + printf("The application has reached a runtime assertion failure! This means a serious problem has occurred and the program needs to close.\n\nProgrammer Info:\n\nFile \"%s\", line (%d) in function \"%s()\".\n\nFailed condition: \"%s\"\n\n" + , + file, + line, + func, + condString); + + #ifdef _DEBUG + PORTABLE_TRAP(); + #else + abort(); + #endif +} + +/******************************************************************************/ + +void SST_OS_RuntimeAssertImplNoInfo(int cond, const char* msgString) +{ + /* Assume likely success and exit early */ + if(cond) + return; + + /* Call the runtime handler if we have one */ + if (sst_runtime_assert_handler != 0) + if(sst_runtime_assert_handler(msgString, sst_runtime_assert_handler_arg)) + return; + + printf("The application has reached a runtime assertion failure! This means a serious problem has occurred, and the application needs to close.\n"); + + #ifdef _DEBUG + PORTABLE_TRAP(); + #else + abort(); + #endif +} + + diff --git a/libsst-os/SST_Assert_Win32.c b/libsst-os/SST_Assert_Win32.c new file mode 100644 index 0000000..b86a4ea --- /dev/null +++ b/libsst-os/SST_Assert_Win32.c @@ -0,0 +1,157 @@ +/* + SST_Assert_Win32.c + Author: Patrick Baggett <ptbaggett@762studios.com> + Created: 12/23/2011 + + Purpose: + + libsst-os assert functions for Win32 systems (Windows 7 or later) + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ + +#define _CRT_SECURE_NO_WARNINGS /* Shhh, compiler */ + +#include <SST/SST_Assert.h> + +#include "Win32Private.h" +#include <stdio.h> /* sprintf() */ + +/*************************************************************************/ +void SST_OS_RuntimeAssertImpl(int condition, const char* condString, const char* msgString, const char* file, const char* func, int line) +{ + UINT flags; + char buf[2048]; + int retcode; + + /* Assume likely success and exit early */ + if(condition) + return; + + /* Call the runtime handler if we have one */ + if (sst_runtime_assert_handler != 0) + retcode = sst_runtime_assert_handler(msgString, sst_runtime_assert_handler_arg); + else + retcode = 0; + + /* See if user handler returned non-zero (i.e. don't raise error) */ + if(retcode != 0) + return; + + sprintf(buf, "The application has reached a runtime assertion failure! Normally, this means a serious problem, and the program should close.\n\nProgrammer Info:\n\nFile \"%s\", line (%d) in function \"%s()\".\n\nFailed condition: \"%s\"\n\n" + + #ifdef _DEBUG + "Terminate application? (Click \"Cancel\" to debug)\n\n" + #endif + , + file, + line, + func, + condString); + + + #ifdef _DEBUG + flags = MB_YESNOCANCEL | MB_ICONERROR; + #else + flags = MB_OK | MB_ICONERROR; + #endif + retcode = MessageBoxA(NULL, buf, "libSST: Runtime assertion failure!", flags); + + + #ifdef _DEBUG + switch(retcode) + { + /* Yes -- terminate process */ + case IDYES: + ExitProcess((UINT)line); + /* No 'break' -- function never returns */ + + /* No -- just continue */ + case IDNO: + return; + + /* Cancel -- debug it */ + case IDCANCEL: + PORTABLE_TRAP(); + break; + } + + #else + /* Ignore return value in release mode, just exit using the line number as the exit code. Since this is non-zero, it should signal to the OS that there was a problem. */ + (void)retcode; + ExitProcess((UINT)line); + #endif +} + +/*************************************************************************/ + +void SST_OS_RuntimeAssertImplNoInfo(int cond, const char* msgString) +{ + UINT flags; + int retcode; + + /* Assume likely success and exit early */ + if(cond) + return; + + /* Call the runtime handler if we have one */ + if (sst_runtime_assert_handler != 0) + retcode = sst_runtime_assert_handler(msgString, sst_runtime_assert_handler_arg); + else + retcode = 0; + + /* See if user handler returned non-zero (i.e. don't raise error) */ + if(retcode != 0) + return; + + #ifdef _DEBUG + flags = MB_YESNOCANCEL | MB_ICONERROR; + #else + flags = MB_OK | MB_ICONERROR; + #endif + retcode = MessageBoxA(NULL, + /* Message */ + #ifdef _DEBUG + "The application has reached a runtime assertion failure! Normally, this means a serious problem has occurred, and the program should close.\n\n" + "Terminate application?" + #else /* Release doesn't have an option to not close */ + "The application has reached a runtime assertion failure! This means a serious problem has occurred, and the application needs to close." + #endif + , + + "libSST: Runtime assertion failure!", flags); + + #ifdef _DEBUG + switch(retcode) + { + /* No -- just continue */ + case IDNO: + return; + + /* Cancel -- debug it */ + case IDCANCEL: + PORTABLE_TRAP(); + break; + + /* Yes -- terminate process */ + case IDYES: + break; + } + + #else + /* Ignore return value in release mode, just exit. */ + (void)retcode; + #endif + + /* dead code :( */ + ExitProcess(0xdeadc0de); +} + + diff --git a/libsst-os/SST_CPUCache_arm.asm b/libsst-os/SST_CPUCache_arm.asm new file mode 100644 index 0000000..ad04ffd --- /dev/null +++ b/libsst-os/SST_CPUCache_arm.asm @@ -0,0 +1,41 @@ +@ SST_CPUCache_arm.asm +@ Author: Patrick Baggett <ptbaggett@762studios.com> +@ Created: 6/21/2012 +@ +@ Purpose: +@ +@ 32-bit assembly for ARMv6+ CPU cache functions. Assembles with GNU as +@ +@ License: +@ +@ This program is free software. It comes without any warranty, to +@ the extent permitted by applicable law. You can redistribute it +@ and/or modify it under the terms of the Do What The Fuck You Want +@ To Public License, Version 2, as published by Sam Hocevar. See +@ http://sam.zoy.org/wtfpl/COPYING for more details. + +.text + +@ ELF symbol names +.global SST_OS_GetCacheLineSize +.global SST_OS_FlushDCRange +.global SST_OS_InvalidateICRange +.global SST_OS_SyncCache + + +@ uint32_t SST_OS_GetCacheLineSize() +SST_OS_GetCacheLineSize: + bx lr + +@ void SST_OS_FlushDCRange(void* base, size_t range) +SST_OS_FlushDCRange: + bx lr + +@ void SST_OS_InvalidateICRange(void* base, size_t range) +SST_OS_InvalidateICRange: + bx lr + + +@ void SST_OS_SyncCache() +SST_OS_SyncCache: + bx lr diff --git a/libsst-os/SST_CPUCache_ia64.asm b/libsst-os/SST_CPUCache_ia64.asm new file mode 100644 index 0000000..c700989 --- /dev/null +++ b/libsst-os/SST_CPUCache_ia64.asm @@ -0,0 +1,38 @@ +/* + SST_CPUCache_ia64.asm + Author: Patrick Baggett <ptb1@762studios.com> + Created: 4/16/2012 + + Purpose: + + Itanium assembly for CPU cache functions + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ + +//Functions +.global SST_OS_GetCacheLineSize# +.global SST_OS_FlushDCRange# +.global SST_OS_InvalidateICRange# +.global SST_OS_SyncCache# + +.section .text + +/* uint32_t SST_OS_GetCacheLineSize() */ +.align 32 +SST_OS_GetCacheLineSize: + +/* SST_OS_InvalidateICRange(void* base, size_t range) */ +SST_OS_InvalidateICRange: +SST_OS_FlushDCRange: + +/* void SST_OS_SyncCache() */ +SST_OS_SyncCache: + br.ret.sptk.many b0;; diff --git a/libsst-os/SST_CPUCache_mips.asm b/libsst-os/SST_CPUCache_mips.asm new file mode 100644 index 0000000..61b4ed5 --- /dev/null +++ b/libsst-os/SST_CPUCache_mips.asm @@ -0,0 +1,46 @@ +/* + SST_CPUCache_mips.asm + Author: Patrick Baggett <ptb1@762studios.com> + Created: 7/20/2012 + + Purpose: + + 32-bit assembly for MIPS CPU cache functions + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ + +/* ELF symbol names */ +.global SST_OS_GetCacheLineSize +.global SST_OS_FlushDCRange +.global SST_OS_InvalidateICRange +.global SST_OS_SyncCache + + +/* uint32_t SST_OS_GetCacheLineSize() */ +SST_OS_GetCacheLineSize: + jr $ra + li $v0, 64 + +/* SST_OS_InvalidateICRange(void* base, size_t range) */ +SST_OS_InvalidateICRange: + jr $ra + nop + +SST_OS_FlushDCRange: + sync + jr $ra + nop + +/* void SST_OS_SyncCache() */ +SST_OS_SyncCache: + sync + jr $ra + nop diff --git a/libsst-os/SST_CPUCache_ppc.asm b/libsst-os/SST_CPUCache_ppc.asm new file mode 100644 index 0000000..55b198b --- /dev/null +++ b/libsst-os/SST_CPUCache_ppc.asm @@ -0,0 +1,41 @@ +/* + SST_CPUCache_ppc.asm + Author: Patrick Baggett <ptb1@762studios.com> + Created: 7/20/2012 + + Purpose: + + 32-bit assembly for Power Architecture CPU cache functions + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ + +/* ELF symbol names */ +.global SST_OS_GetCacheLineSize +.global SST_OS_FlushDCRange +.global SST_OS_InvalidateICRange +.global SST_OS_SyncCache + + +/* uint32_t SST_OS_GetCacheLineSize() */ +SST_OS_GetCacheLineSize: + li r3, 64 + blr + +/* SST_OS_InvalidateICRange(void* base, size_t range) */ +SST_OS_InvalidateICRange: +SST_OS_FlushDCRange: + blr + +/* void SST_OS_SyncCache() */ +SST_OS_SyncCache: + sync + isync + blr diff --git a/libsst-os/SST_CPUCache_sparc.asm b/libsst-os/SST_CPUCache_sparc.asm new file mode 100644 index 0000000..6e0b82c --- /dev/null +++ b/libsst-os/SST_CPUCache_sparc.asm @@ -0,0 +1,50 @@ +/* + SST_CPUCache_sparc.asm + Author: Patrick Baggett <ptb1@762studios.com> + Created: 12/23/2011 + + Purpose: + + 32-bit assembly for SPARCv9 CPU cache functions + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ + +/* ELF symbol names */ +.global SST_OS_GetCacheLineSize +.global SST_OS_FlushDCRange +.global SST_OS_InvalidateICRange +.global SST_OS_SyncCache + + +/* uint32_t SST_OS_GetCacheLineSize() */ +SST_OS_GetCacheLineSize: + retl + or %g0, 64, %o0 /* kludge: it's 64. */ + +/* SST_OS_InvalidateICRange(void* base, size_t range) */ +SST_OS_InvalidateICRange: +SST_OS_FlushDCRange: + add %o0, %o1, %o2 /* %o2 = end address */ + + 1: + flush %o0 + cmp %o0, %o2 + bcs %icc,1b /* branch on less than (unsigned) */ + add %o0, 8, %o0 /* FLUSH insn flushes a double word at a time */ + + retl + nop + +/* void SST_OS_SyncCache() */ +SST_OS_SyncCache: + membar #Sync + retl + nop diff --git a/libsst-os/SST_CPUCache_sparc64.asm b/libsst-os/SST_CPUCache_sparc64.asm new file mode 100644 index 0000000..85497e0 --- /dev/null +++ b/libsst-os/SST_CPUCache_sparc64.asm @@ -0,0 +1,49 @@ +/* + SST_CPUCache_sparc64.asm + Author: Patrick Baggett <ptb1@762studios.com> + Created: 12/23/2011 + + Purpose: + + 64-bit assembly for SPARCv9 CPU cache functions + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ + +.global SST_OS_GetCacheLineSize +.global SST_OS_FlushDCRange +.global SST_OS_InvalidateICRange +.global SST_OS_SyncCache + + +/* uint32_t SST_OS_GetCacheLineSize() */ +SST_OS_GetCacheLineSize: + retl + or %g0, 64, %o0 /* kludge: it's 64. */ + +/* SST_OS_InvalidateICRange(void* base, size_t range) */ +SST_OS_InvalidateICRange: +SST_OS_FlushDCRange: + add %o0, %o1, %o2 /* %o2 = end address */ + + 1: + flush %o0 + cmp %o0, %o2 + bcs %xcc,1b /* branch on less than (unsigned) */ + add %o0, 8, %o0 /* FLUSH insn flushes a double word at a time */ + + retl + nop + +/* void SST_OS_SyncCache() */ +SST_OS_SyncCache: + membar #Sync + retl + nop diff --git a/libsst-os/SST_CPUCache_x86-64-win64.asm b/libsst-os/SST_CPUCache_x86-64-win64.asm new file mode 100644 index 0000000..313c181 --- /dev/null +++ b/libsst-os/SST_CPUCache_x86-64-win64.asm @@ -0,0 +1,76 @@ +; SST_CPUCache_x86-64-win64.asm +; Author: Patrick Baggett <ptbaggett@762studios.com> +; Created: 12/23/2011 +; +; Purpose: +; +; 64-bit assembly for x86 CPU cache functions for the Microsoft x64 ABI. Assembles with YASM 1.1/NASM 2.0+ +; +; License: +; +; This program is free software. It comes without any warranty, to +; the extent permitted by applicable law. You can redistribute it +; and/or modify it under the terms of the Do What The Fuck You Want +; To Public License, Version 2, as published by Sam Hocevar. See +; http://sam.zoy.org/wtfpl/COPYING for more details. + +; Win64 and UNIX calling conventions differ for x64-64. I know, it's absurd. +; Because of this, there are separate implementation for Win64 and x64-64 UNIX (Linux, *BSD, Solaris, MacOS X, etc.) +; Here is the break down: +; +; REGISTER | Win64 | UNIX +;-----------+-----------+---------- +;rax | Retval | Retval +;rsi | Not used | 1st arg +;rdi | Not used | 2nd arg +;rcx | 1st arg | 3rd arg +;rdx | 2nd arg | 4th arg +;r8 | 3rd arg | 5th arg +;r9 | 4th arg | 6th arg + +[bits 64] +[segment .text] + +; Win64 symbol names +[global SST_OS_GetCacheLineSize] +[global SST_OS_FlushDCRange] +[global SST_OS_InvalidateICRange] +[global SST_OS_SyncCache] + + +;uint32_t SST_OS_GetCacheLineSize() +SST_OS_GetCacheLineSize: + push rbx + mov eax, 0x80000006 ;Cache info command + cpuid + movzx rax, cl ;ECX bits 0-7 = L2 cache line size (TODO: what about L1?) + pop rbx + ret + +;SST_OS_InvalidateICRange(void* base, size_t range) +SST_OS_InvalidateICRange: + + ;A jmp instruction is sufficient. x86 CPUs have self-snooping caches. + jmp do_serialize + do_serialize: + + ret + +; void SST_OS_SyncCache() +SST_OS_SyncCache: + mfence + ret + +;void SST_OS_FlushDCRange(void* base, size_t range) +SST_OS_FlushDCRange: + call SST_OS_GetCacheLineSize ;Get the cache line size + + dc_flush_more2: ;do { + clflush [rsi] + add rsi, rax ;base += cache_line_size + sub rdi, rax ;range -= cache_line_size + + cmp rcx, 0 + jg dc_flush_more2 ; } while(range > 0) + + ret diff --git a/libsst-os/SST_CPUCache_x86-64.asm b/libsst-os/SST_CPUCache_x86-64.asm new file mode 100644 index 0000000..10608ae --- /dev/null +++ b/libsst-os/SST_CPUCache_x86-64.asm @@ -0,0 +1,78 @@ +; SST_CPUCache_x86-64.asm +; Author: Patrick Baggett <ptbaggett@762studios.com> +; Created: 12/23/2011 +; +; Purpose: +; +; 64-bit assembly for x86 CPU cache functions for the SysV ABI. Assembles with YASM 1.1/NASM 2.0+ +; +; License: +; +; This program is free software. It comes without any warranty, to +; the extent permitted by applicable law. You can redistribute it +; and/or modify it under the terms of the Do What The Fuck You Want +; To Public License, Version 2, as published by Sam Hocevar. See +; http://sam.zoy.org/wtfpl/COPYING for more details. + +; Win64 and UNIX calling conventions differ for x64-64. I know, it's absurd. +; Because of this, there are separate implementation for Win64 and x64-64 UNIX (Linux, *BSD, Solaris, MacOS X, etc.) +; Here is the break down: +; +; REGISTER | Win64 | UNIX +;-----------+-----------+---------- +;rax | Retval | Retval +;rsi | Not used | 1st arg +;rdi | Not used | 2nd arg +;rcx | 1st arg | 3rd arg +;rdx | 2nd arg | 4th arg +;r8 | 3rd arg | 5th arg +;r9 | 4th arg | 6th arg + +[bits 64] +[segment .text] + +; ELF symbol names +[global SST_OS_GetCacheLineSize] +[global SST_OS_FlushDCRange] +[global SST_OS_InvalidateICRange] +[global SST_OS_SyncCache] + + +;uint32_t SST_OS_GetCacheLineSize() +;no args, so win64 and unix abis are the same + SST_OS_GetCacheLineSize: + push rbx + mov eax, 0x80000006 ;Cache info command + cpuid + movzx rax, cl ;ECX bits 0-7 = L2 cache line size (TODO: what about L1?) + pop rbx + ret + +;SST_OS_InvalidateICRange(void* base, size_t range) +SST_OS_InvalidateICRange: + + ;A jmp instruction is sufficient. x86 CPUs have self-snooping caches. + jmp do_serialize + do_serialize: + + ret + +; void SST_OS_SyncCache() +SST_OS_SyncCache: + mfence + ret + +;void SST_OS_FlushDCRange(void* base, size_t range) + SST_OS_FlushDCRange: + + call SST_OS_GetCacheLineSize ;Get the cache line size + + dc_flush_more1: ;do { + clflush [rcx] + add rcx, rax ;base += cache_line_size + sub rdx, rax ;range -= cache_line_size + + cmp rcx, 0 + jg dc_flush_more1 ; } while(range > 0) + + ret \ No newline at end of file diff --git a/libsst-os/SST_CPUCache_x86.asm b/libsst-os/SST_CPUCache_x86.asm new file mode 100644 index 0000000..05b26d1 --- /dev/null +++ b/libsst-os/SST_CPUCache_x86.asm @@ -0,0 +1,77 @@ +; SST_CPUCache_x86.asm +; Author: Patrick Baggett <ptbaggett@762studios.com> +; Created: 12/23/2011 +; +; Purpose: +; +; 32-bit assembly for x86 CPU cache functions. Assembles with YASM 1.1/NASM 2.0+ +; +; License: +; +; This program is free software. It comes without any warranty, to +; the extent permitted by applicable law. You can redistribute it +; and/or modify it under the terms of the Do What The Fuck You Want +; To Public License, Version 2, as published by Sam Hocevar. See +; http://sam.zoy.org/wtfpl/COPYING for more details. + +[bits 32] +[segment .text] + +; Win32 symbol names +[global _SST_OS_GetCacheLineSize] +[global _SST_OS_FlushDCRange] +[global _SST_OS_InvalidateICRange] +[global _SST_OS_SyncCache] + +; ELF symbol names +[global SST_OS_GetCacheLineSize] +[global SST_OS_FlushDCRange] +[global SST_OS_InvalidateICRange] +[global SST_OS_SyncCache] + + +;uint32_t SST_OS_GetCacheLineSize() +_SST_OS_GetCacheLineSize: + SST_OS_GetCacheLineSize: + push ebx + mov eax, 0x80000006 ;Cache info command + cpuid + movzx eax, cl ;ECX bits 0-7 = L2 cache line size (TODO: what about L1?) + pop ebx + ret + +;void SST_OS_FlushDCRange(void* base, size_t range) +_SST_OS_FlushDCRange: + SST_OS_FlushDCRange: + + call SST_OS_GetCacheLineSize ;Get the cache line size + + mov edx, [esp+4] ;edx = base + mov ecx, [esp+8] ;ecx = range (in bytes) + + dc_flush_more: ;do { + clflush [edx] + add edx, eax ;base += cache_line_size + sub ecx, eax ;range -= cache_line_size + + cmp ecx, 0 + jg dc_flush_more ; } while(range > 0) + + ret + +;SST_OS_InvalidateICRange(void* base, size_t range) +_SST_OS_InvalidateICRange: + SST_OS_InvalidateICRange: + + ;A jmp instruction is sufficient. x86 CPUs have self-snooping caches. + jmp do_serialize + do_serialize: + + ret + + +; void SST_OS_SyncCache() +_SST_OS_SyncCache: + SST_OS_SyncCache: + mfence + ret \ No newline at end of file diff --git a/libsst-os/SST_CPU_POSIX.c b/libsst-os/SST_CPU_POSIX.c new file mode 100644 index 0000000..a70240e --- /dev/null +++ b/libsst-os/SST_CPU_POSIX.c @@ -0,0 +1,94 @@ +/* + SST_CPU_POSIX.c + Author: Patrick Baggett <ptb1@762studios.com> + Created: 12/23/2011 + + Purpose: + + libsst-os CPU querying functions for POSIX systems + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ + +/* + The POSIX doesn't actually provide much in the terms of CPU + querying. Other source files provide specific operating systems + implementations (e.g: Linux, Solaris, ...) +*/ + + +#include "POSIXPrivate.h" +#include <SST/SST_CPU.h> +#include <SST/SST_Assert.h> + +/******************************************************************************/ + +int SST_OS_GetNumberCPUChips() +{ + /* 0 -> no information available */ + return 0; +} + +/******************************************************************************/ + +int SST_OS_GetNumberPhysicalCPUs(void) +{ + /* 0 -> no information available */ + return 0; +} + +/******************************************************************************/ + +int SST_OS_GetNumberLogicalCPUs(void) +{ + return (int)sysconf(_SC_NPROCESSORS_ONLN); +} + +/******************************************************************************/ + +int SST_OS_MapPhysicalToLogicalCPU(int physCpuId, int* logCpuIds) +{ + (void)physCpuId; + (void)logCpuIds; + /* 0 -> API not available */ + return 0; +} + +/******************************************************************************/ + +int SST_OS_GetCPUAffinity(unsigned char* cpuMaskReturn, unsigned int cpuMaskSize) +{ + SST_OS_DebugAssert(cpuMaskReturn != NULL, "CPU mask may not be NULL"); + + (void)cpuMaskReturn; + (void)cpuMaskSize; + return 0; /* NYI */ +} + +/******************************************************************************/ + +int SST_OS_SetCPUAffinity(const unsigned char* cpuMask, unsigned int cpuMaskSize) +{ + SST_OS_DebugAssert(cpuMask != NULL, "CPU mask may not be NULL"); + + (void)cpuMask; + (void)cpuMaskSize; + return 0; /* NYI */ +} + +/******************************************************************************/ + +void SST_OS_SetPreferredCPU(int logCpuId) +{ + (void)logCpuId; + + /* Hint ignored */ + return; +} diff --git a/libsst-os/SST_CPU_Win32.c b/libsst-os/SST_CPU_Win32.c new file mode 100644 index 0000000..f529ae8 --- /dev/null +++ b/libsst-os/SST_CPU_Win32.c @@ -0,0 +1,354 @@ +/* + SST_CPU_Win32.c + Author: Patrick Baggett <ptbaggett@762studios.com> + Created: 12/23/2011 + + Purpose: + + libsst-os CPU querying functions for Win32 systems (Windows 7 or later) + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ + +#include "Win32Private.h" +#include <malloc.h> /* _alloca() */ + +#include <SST/SST_CPU.h> +#include <SST/SST_Assert.h> + +/* + SUPPORT FOR > 64 CPUS + ---------------------- + This code does its best to be compatible with large numbers of logical CPUs. Processor groups are + a bit weird, see MSDN (http://msdn.microsoft.com/en-us/library/windows/desktop/dd405503(v=vs.85).aspx) +*/ + +/*************************************************************************/ + +static const uint8_t popbits[16] = { 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4 }; + +/*************************************************************************/ + +/* popcount of an 8-bit value */ +static uint8_t popcount8(uint8_t v) +{ + return popbits[v & 0x0Fu] + popbits[v>>4]; +} + +/*************************************************************************/ + +/* popcount on the Win32 KAFFINITY value (64-bit value) */ +static int popcount(KAFFINITY mask) +{ + int count = 0, i; + + for(i=0; i<sizeof(KAFFINITY); i++) + { + /* No more bits set? */ + if(!mask) + break; + + count += popcount8(mask & 0xFF); + + mask >>= 8; + } + + return count; +} + +/*************************************************************************/ + +int SST_OS_GetNumberCPUChips() +{ + DWORD length = 0; + SYSTEM_LOGICAL_PROCESSOR_INFORMATION* relat; + DWORD nr; + int nrChips = 0; + + /* Query data structure size */ + GetLogicalProcessorInformation(NULL, &length); + if(GetLastError() != ERROR_INSUFFICIENT_BUFFER) + return -1; + + /* Really get the info this time */ + relat = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION*)_alloca((size_t)length); + if(GetLogicalProcessorInformation(relat, &length) == FALSE) + return -2; + + /* Scan list */ + nr = length / sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION); + while(nr > 0) + { + if(relat->Relationship == RelationProcessorPackage) + nrChips++; + + relat++; + nr--; + } + + return nrChips; +} + +/*************************************************************************/ + +int SST_OS_GetNumberPhysicalCPUs(void) +{ + DWORD length = 0; + char* ptr, *end; + int nrCores = 0; + + /* Query data structure size */ + GetLogicalProcessorInformationEx(RelationProcessorCore, NULL, &length); + if(GetLastError() != ERROR_INSUFFICIENT_BUFFER) + return -1; + + /* Really get the info this time */ + ptr = (char*)_alloca((size_t)length); + end = ptr + length; + if(GetLogicalProcessorInformationEx( + RelationProcessorCore, + (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*)ptr, + &length) == FALSE) + return -2; + + while(ptr < end) + { + SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX* info = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*)ptr; + nrCores++; + + ptr += (size_t)info->Size; + } + + return nrCores; +} + +/*************************************************************************/ + +int SST_OS_GetNumberLogicalCPUs(void) +{ + DWORD length = 0; + char* ptr, *end; + int nrThreads = 0; + + /* Query data structure size */ + GetLogicalProcessorInformationEx(RelationProcessorPackage, NULL, &length); + if(GetLastError() != ERROR_INSUFFICIENT_BUFFER) + return -1; + + /* Really get the info this time */ + ptr = (char*)_alloca((size_t)length); + end = ptr + length; + if(GetLogicalProcessorInformationEx( + RelationProcessorPackage, + (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*)ptr, + &length) == FALSE) + return -2; + + while(ptr < end) + { + WORD i; + SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX* info = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*)ptr; + + for(i=0; i<info->Processor.GroupCount; i++) + nrThreads += popcount(info->Processor.GroupMask[i].Mask); + + + ptr += info->Size; + } + + return nrThreads; +} + +/*************************************************************************/ + +int SST_OS_MapPhysicalToLogicalCPU(int physCpuId, int* logCpuIds) +{ + DWORD length = 0; + char* ptr, *end; + WORD i; + int j; + SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX* info; + + SST_OS_DebugAssert(logCpuIds != NULL, "The return array for logical CPUs may not be NULL"); + + /* Query data structure size */ + GetLogicalProcessorInformationEx(RelationProcessorCore, NULL, &length); + if(GetLastError() != ERROR_INSUFFICIENT_BUFFER) + return -2; + + /* Really get the info this time */ + ptr = (char*)_alloca((size_t)length); + end = ptr + length; + if(GetLogicalProcessorInformationEx( + RelationProcessorCore, + (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*)ptr, + &length) == FALSE) + return -3; + + info = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*)ptr; + #ifdef _DEBUG + { + /* Figure out how many elements in this array */ + int nr = (int)(length / info->Size); + + /* Bounds checking */ + SST_OS_DebugAssert(!(physCpuId >= nr), "Array too small to contain logical CPUs. Use SST_OS_GetNumberLogicalCPUs() to determine correct size"); + } + #endif + + /* This union is large, so we can't just do info[index], we have to do + 'base_address + size * index'. Ugly, but necessary. */ + info = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*)(ptr + (size_t)(info->Size*physCpuId)); + + j = 0; /* j = number of logical CPUs mapped */ + for(i=0; i<info->Processor.GroupCount; i++) + { + /* Figure out base logical CPU ID for processor group. Usually 64 CPUs / group. */ + int groupbase = (int)(info->Processor.GroupMask[i].Group * 8 * sizeof(KAFFINITY)); + size_t k; + KAFFINITY mask = info->Processor.GroupMask[i].Mask; + + /* + Algorithm: Each GROUP_AFFINITY structure has a mask. Scan through it and + if bit 'k' is set, then add 'k+groupbase' to the array. + */ + + /* Scan through bits and add logical CPUs */ + for(k=0; k<(8 * sizeof(KAFFINITY)); k++) + { + /* No more bits set */ + if(!mask) + break; + + /* Is this bit set? */ + if(mask & 1) + { + /* Add the logical CPU to the array */ + logCpuIds[j] = (int)k + groupbase; + j++; + } + + /* Next bit... */ + mask >>= 1; + } + } + + /* Return the number of logical CPUs written to logCpuIds[] */ + return j; +} + +/*************************************************************************/ + +int SST_OS_GetCPUAffinity(unsigned char* cpuMaskReturn, unsigned int cpuMaskSize) +{ + WORD maxGroup; + GROUP_AFFINITY aff; + SST_OS_DebugAssert(cpuMaskReturn != NULL, "CPU mask may not be NULL"); + SST_OS_DebugAssert(cpuMaskSize > 0, "CPU mask may not be zero"); + + /* Calculate the maximum number of groups that can be stored using the space provided */ + maxGroup = (WORD)(cpuMaskSize / sizeof(KAFFINITY)); + if(cpuMaskSize % sizeof(KAFFINITY)) + maxGroup += 1; + + if(maxGroup == 0) + return -1; + + memset(cpuMaskReturn, 0, cpuMaskSize); + + GetThreadGroupAffinity(GetCurrentThread(), &aff); + + /* Ensure the real processor group doesn't exceed provided space */ + if(aff.Group < maxGroup) + { + uint32_t byteOffset = aff.Group * sizeof(KAFFINITY); /* i.e. where to begin in cpuMaskReturn[] */ + uint32_t bytesLeft = cpuMaskSize - byteOffset; /* i.e. how many bytes are left */ + uint32_t i; + KAFFINITY mask = aff.Mask; + unsigned char* maskReturn = cpuMaskReturn + byteOffset; + + for(i=0; i<bytesLeft; i++) + { + if(!mask) + break; + + maskReturn[i] = (uint8_t)(mask & 0xFF); + + mask >>= 8; + } + } + + return 1; +} + +/*************************************************************************/ + +int SST_OS_SetCPUAffinity(const unsigned char* cpuMask, unsigned int cpuMaskSize) +{ + uint8_t groupPopCount[4096/(sizeof(KAFFINITY) * 8)]; + KAFFINITY groupMask[4096/(sizeof(KAFFINITY) * 8)]; + uint8_t lowest = UINT8_MAX; + uint8_t lowestGroup = 0; + unsigned int i; + GROUP_AFFINITY aff; + + + SST_OS_DebugAssert(cpuMask != NULL, "CPU mask may not be NULL"); + + + /* Windows only allows a thread to be a member of a single processor group, which makes sense + when you consider that migrating threads across NUMA nodes is a bad idea. Here, we select the + processor group that has the fewest bits set (except for 0...) */ + if(cpuMaskSize > 4096) /* Disallow arbitrarily large masks. 4096 processors is fine, really */ + cpuMaskSize = 4096; + + memset(groupPopCount, 0, sizeof(groupPopCount)); + memset(groupMask, 0, sizeof(groupMask)); + + /* Operate on each byte */ + for(i=0; i<cpuMaskSize; i++) + { + uint8_t groupIndex = (uint8_t)(i / sizeof(KAFFINITY)); /* i is in bytes, sizeof() is in bytes */ + uint8_t groupByte = (uint8_t)(i % 8); + + /* Sum all popcount8() of the bytes that make up a processor group's mask */ + groupPopCount[groupIndex] += popcount8(cpuMask[i]); + + /* OR the 8-bit mask into KAFFINITY values (essentially merge them) */ + groupMask[groupIndex] |= (KAFFINITY)cpuMask[i] << (KAFFINITY)(groupByte * 8); + + /* Record the smallest group that is not 0 */ + if(groupPopCount[groupIndex] > 0 && groupPopCount[groupIndex] < lowest) + lowest = groupIndex; + } + + + aff.Group = (WORD)((uint16_t)lowestGroup); + aff.Mask = groupMask[lowestGroup]; + + SetThreadGroupAffinity(GetCurrentThread(), &aff, NULL); + + return 1; +} + +/*************************************************************************/ + +void SST_OS_SetPreferredCPU(int logCpuId) +{ + PROCESSOR_NUMBER ideal; + + SST_OS_DebugAssert(logCpuId < SST_OS_GetNumberLogicalCPUs(), "Logical CPU ID is out of range"); + + ideal.Group = (WORD)logCpuId / (WORD)(sizeof(KAFFINITY)*8); + ideal.Number = (WORD)logCpuId % (WORD)(sizeof(KAFFINITY)*8); + ideal.Reserved = 0; + + SetThreadIdealProcessorEx(GetCurrentThread(), &ideal, NULL); +} diff --git a/libsst-os/SST_DynLib_POSIX.c b/libsst-os/SST_DynLib_POSIX.c new file mode 100644 index 0000000..e38da63 --- /dev/null +++ b/libsst-os/SST_DynLib_POSIX.c @@ -0,0 +1,77 @@ +/* + SST_DynLib_POSIX.c + Author: Patrick Baggett <ptb1@762studios.com> + Created: 12/23/2011 + + Purpose: + + libsst-os dynamic linking functions for POSIX systems + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ + +#include <SST/SST_DynLib.h> +#include <SST/SST_Assert.h> + +#include <stdlib.h> +#include <dlfcn.h> +#include <string.h> + +/******************************************************************************/ + +SST_DynLib SST_OS_LoadDynLib(const char* path) +{ + SST_OS_DebugAssert(path != NULL, "Path may not be NULL"); + + + return (SST_DynLib)dlopen(path, RTLD_LAZY); +} + +/******************************************************************************/ + +SST_DynLibFunc SST_OS_GetLibSymbol(SST_DynLib lib, const char* symbol) +{ + uintptr_t tmp; + + SST_OS_DebugAssert(lib != NULL, "Library may not be NULL"); + SST_OS_DebugAssert(symbol != NULL, "Library may not be NULL"); + + tmp = (uintptr_t)dlsym((void*)lib, symbol); + + return (SST_DynLibFunc)tmp; +} + +/******************************************************************************/ + +void SST_OS_CloseDynLib(SST_DynLib lib) +{ + SST_OS_DebugAssert(lib != NULL, "Library may not be NULL"); + + dlclose((void*)lib); +} + +/******************************************************************************/ + +int SST_OS_DynLibName(char* libnameOut, const char* libnameIn) +{ + SST_OS_DebugAssert(libnameIn != NULL, "Library name may not be NULL"); + + if(libnameOut == NULL) + return 3+(int)strlen(libnameIn)+3; /* strlen("lib")+strlen(libnameIn)+strlen(".so") */ + + libnameOut[0] = 'l'; /* strcpy(libnameOut, "lib") */ + libnameOut[1] = 'i'; + libnameOut[2] = 'b'; + + strcpy(libnameOut+3, libnameIn); + strcat(libnameOut, ".so"); + + return 0; +} diff --git a/libsst-os/SST_DynLib_Win32.c b/libsst-os/SST_DynLib_Win32.c new file mode 100644 index 0000000..45f3130 --- /dev/null +++ b/libsst-os/SST_DynLib_Win32.c @@ -0,0 +1,66 @@ +/* + SST_DynLib_Win32.c + Author: Patrick Baggett <ptbaggett@762studios.com> + Created: 12/23/2011 + + Purpose: + + libsst-os dynamic linking functions for Win32 systems (Windows 7 or later) + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ + +#include "Win32Private.h" +#include <SST/SST_Assert.h> +#include <SST/SST_DynLib.h> +#include <string.h> + +/*************************************************************************/ + +SST_DynLib SST_OS_LoadDynLib(const char* path) +{ + SST_OS_DebugAssert(path != NULL, "Path may not be NULL"); + + return (SST_DynLib)LoadLibraryExA(path, NULL, 0); +} + +/*************************************************************************/ + +SST_DynLibFunc SST_OS_GetLibSymbol(SST_DynLib lib, const char* symbol) +{ + SST_OS_DebugAssert(lib != NULL, "Library may not be NULL"); + SST_OS_DebugAssert(symbol != NULL, "Library may not be NULL"); + + return (SST_DynLibFunc)GetProcAddress((HMODULE)lib, symbol); +} + +/*************************************************************************/ + +void SST_OS_CloseDynLib(SST_DynLib lib) +{ + SST_OS_DebugAssert(lib != NULL, "Library may not be NULL"); + + FreeLibrary((HMODULE)lib); +} + +/*************************************************************************/ + +int SST_OS_DynLibName(char* libnameOut, const char* libnameIn) +{ + SST_OS_DebugAssert(libnameIn != NULL, "Library name may not be NULL"); + + if(libnameOut == NULL) + return (int)strlen(libnameIn)+4; /* +strlen(".dll") */ + + strcpy(libnameOut, libnameIn); + strcat(libnameOut, ".dll"); + + return 0; +} diff --git a/libsst-os/SST_Endian.c b/libsst-os/SST_Endian.c new file mode 100644 index 0000000..0d1ae15 --- /dev/null +++ b/libsst-os/SST_Endian.c @@ -0,0 +1,70 @@ +/* + SST_Endian.c + Author: Chris Ertel <crertel@762studios.com> + Created: 1/16/2012 + + Purpose: + + libsst-os endian and byte reordering routines. + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ + +#include <SST/SST_Endian.h> +#include <pstdint.h> + +static SST_ByteOrder machineByteOrder; + +void __libsst_init_endian() +{ + const uint16_t testSeq = 0x55FE; + const uint8_t* c = (const uint8_t*)&testSeq; + + if(c[0] == 0x55) + machineByteOrder = SST_BIG_ENDIAN; + else + machineByteOrder = SST_LITTLE_ENDIAN; +} + +SST_ByteOrder SST_OS_GetHostEndianness( void ) +{ + return machineByteOrder; +} + +uint16_t SST_OS_ByteSwap16( uint16_t _toSwap) +{ + return (_toSwap >> 8) | (_toSwap << 8); +} + +uint32_t SST_OS_ByteSwap32( uint32_t _toSwap) +{ + uint32_t a = (_toSwap & 0x000000ff); + uint32_t b = (_toSwap & 0x0000ff00) >> 8; + uint32_t c = (_toSwap & 0x00ff0000) >> 16; + uint32_t d = (_toSwap & 0xff000000) >> 24; + + uint32_t ret = (a << 24) | (b << 16) | (c << 8) | (d); + return ret; +} + +uint64_t SST_OS_ByteSwap64( uint64_t _toSwap) +{ + uint64_t a = (_toSwap & 0x00000000000000ffull); + uint64_t b = (_toSwap & 0x000000000000ff00ull) >> 8; + uint64_t c = (_toSwap & 0x0000000000ff0000ull) >> 16; + uint64_t d = (_toSwap & 0x00000000ff000000ull) >> 24; + uint64_t e = (_toSwap & 0x000000ff00000000ull) >> 32; + uint64_t f = (_toSwap & 0x0000ff0000000000ull) >> 40; + uint64_t g = (_toSwap & 0x00ff000000000000ull) >> 48; + uint64_t h = (_toSwap & 0xff00000000000000ull) >> 56; + + uint64_t ret = (a << 56) | (b << 48) | (c << 40) | (d << 32) | (e << 24) | (f << 16) | (g << 8) | h; + return ret; +} \ No newline at end of file diff --git a/libsst-os/SST_FileSys_POSIX.c b/libsst-os/SST_FileSys_POSIX.c new file mode 100644 index 0000000..de767b3 --- /dev/null +++ b/libsst-os/SST_FileSys_POSIX.c @@ -0,0 +1,191 @@ +/* + SST_FileSys_POSIX.c + Author: Patrick Baggett <ptbaggett@762studios.com> + Created: 3/31/2012 + + Purpose: + + libsst-os file system querying for POSIX systems + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ + +#include <SST/SST_FileSys.h> + +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <limits.h> +#include <dirent.h> +#include <errno.h> +#include <string.h> +#include <stdlib.h> + +/* In order to get alloca() on Solaris, <alloca.h> is needed */ +#if defined(__SUNPRO_C) + #include <alloca.h> +#endif + +/* No PATH_MAX symbol */ +#if !defined(PATH_MAX) + + #if defined(_POSIX_PATH_MAX) && + #define PATH_MAX _POSIX_PATH_MAX + #else + #define PATH_MAX 256 /* This is what _POSIX_PATH_MAX must be according to POSIX */ + #endif +#endif + +typedef struct SST_Dir_POSIX +{ + char* canonPath; + size_t canonPathLen; + DIR* dirp; +} SST_Dir_POSIX; + +SST_Dir SST_OS_OpenDirectory(const char* path) +{ + size_t len; + char* canonPath; + SST_Dir_POSIX* dh; + DIR* dirp; + + /* Ensure no trailing slash */ + len = strlen(path); + if(len == 0 || path[len-1] == '/') + return NULL; + + /* Out of memory? */ + canonPath = (char*)malloc(PATH_MAX); + if(!canonPath) + return NULL; + + /* Allocate directory handle */ + dh = (SST_Dir_POSIX*)malloc(sizeof(SST_Dir_POSIX)); + if(!dh) + { + free(canonPath); + return NULL; + } + + /* Remove garbage "." and ".." from path, get canonical form */ + if(!realpath(path, canonPath)) + { + free(canonPath); + free(dh); + return NULL; + } + + /* Attempt to open directory */ + dirp = opendir(canonPath); + if(!dirp) + { + free(canonPath); + free(dh); + return NULL; + } + + dh->canonPathLen = strlen(canonPath); + dh->canonPath = canonPath; + dh->dirp = dirp; + + return (SST_Dir)dh; +} + +int SST_OS_ReadNextDirectoryEntry(SST_Dir dir, SST_FileInfo* fileInfoReturn) +{ + SST_Dir_POSIX* dh = (SST_Dir_POSIX*)dir; + struct dirent* ent; + size_t len; + char* tmp; + struct stat statbuf; + + /* Read next directory entry */ + ent = readdir(dh->dirp); + if(!ent) + return 0; + + /* Ignore "." and ".." */ + if(strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0) + return SST_OS_ReadNextDirectoryEntry(dir, fileInfoReturn); + + len = strlen(ent->d_name); + if(len >= SST_FILENAME_MAX) + len = SST_FILENAME_MAX-1; + + memcpy(fileInfoReturn->name, ent->d_name, len); + fileInfoReturn->name[len] = 0; + fileInfoReturn->nameLen = len; + + tmp = (char*)alloca(dh->canonPathLen + len + 2); /* +2 because of "/" character and NULL */ + + /* Construct `canonPath` + '/' + `ent->d_name` + '\0' */ + memcpy(tmp, dh->canonPath, dh->canonPathLen); + tmp[dh->canonPathLen] = '/'; + memcpy(&tmp[dh->canonPathLen+1], ent->d_name, len); + tmp[dh->canonPathLen+1+len] = '\0'; + + if(stat(tmp, &statbuf) == 0) + { + + /* Save result */ + fileInfoReturn->isDir = S_ISDIR(statbuf.st_mode); + fileInfoReturn->size = (fileInfoReturn->isDir ? 0 : (size_t)statbuf.st_size); + } + else /* can't stat() file, so not really much to say about it */ + { + fileInfoReturn->isDir = 0; + fileInfoReturn->size = 0; + } + + return (ent != NULL); +} + + +void SST_OS_CloseDirectory(SST_Dir dir) +{ + SST_Dir_POSIX* dh = (SST_Dir_POSIX*)dir; + closedir(dh->dirp); + free(dh->canonPath); + free(dh); +} + +int SST_OS_CreateDirectory(const char* dir) +{ + /* Make a directory for anyone to read/write. */ + if(mkdir(dir, 0777) == 0) + return 0; /* Success */ + + if(errno == EEXIST) + { + /* This could refer to a file by the same name, so check to + see if it is really a directory. */ + struct stat statbuf; + + if(stat(dir, &statbuf) == 0) + { + /* It really is a directory. Return positive to signal + that the directory already exists. */ + if(S_ISDIR(statbuf.st_mode)) + return 1; + } + } + + /* Other error -> failure */ + return -1; +} + +/******************************************************************************/ + +int SST_OS_RemoveDirectory(const char* dir) +{ + return (rmdir(dir) == 0); +} + diff --git a/libsst-os/SST_FileSys_Win32.c b/libsst-os/SST_FileSys_Win32.c new file mode 100644 index 0000000..52c77aa --- /dev/null +++ b/libsst-os/SST_FileSys_Win32.c @@ -0,0 +1,164 @@ +/* + SST_FileSys_Win32.c + Author: Patrick Baggett <ptbaggett@762studios.com> + Created: 3/29/2012 + + Purpose: + + libsst-os file system querying for Win32 + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ + +#include <SST/SST_FileSys.h> + +#include <windows.h> +#include <string.h> + +/*************************************************************************/ + +typedef struct SST_Dir_Win32 +{ + HANDLE hFind; + WIN32_FIND_DATAA data; + int once; +} SST_Dir_Win32; + +/*************************************************************************/ + +/* Copy data from WIN32_FILE_DATAA structure to SST_FileInfo structure */ +static void copyWin32FindData(SST_FileInfo* info, const WIN32_FIND_DATAA* data) +{ + size_t len = strlen(data->cFileName); + + if(len >= SST_FILENAME_MAX) + len = SST_FILENAME_MAX-1; + + memcpy(info->name, data->cFileName, len); + info->name[len] = '\0'; + info->size = (((uint64_t)data->nFileSizeHigh) << (8*sizeof(uint32_t))) | ((uint64_t)data->nFileSizeLow); + info->nameLen = len; + info->isDir = (data->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY); +} + +/*************************************************************************/ + +SST_Dir SST_OS_OpenDirectory(const char* path) +{ + char findPath[MAX_PATH]; + size_t len = strlen(path); + SST_Dir_Win32* win32dir; + + /* Don't allow paths to end with a trailing slash */ + if(path[len-1] == '/' || path[len-1] == '\\') + return NULL; + + if(len > MAX_PATH-3) + len = MAX_PATH-3; + + /* Append "/" and "*" to the end */ + memcpy(findPath, path, len); + findPath[len] = '/'; + findPath[len+1] = '*'; + findPath[len+2] = '\0'; + + /* Allocate structure to use */ + win32dir = (SST_Dir_Win32*)HeapAlloc(GetProcessHeap(), 0, sizeof(SST_Dir_Win32)); + if(win32dir == NULL) + return (SST_Dir)NULL; + + /* Attempt to find the first file */ + win32dir->hFind = FindFirstFileA(findPath, &win32dir->data); + win32dir->once = 1; + + /* Failed? */ + if(win32dir->hFind == INVALID_HANDLE_VALUE) + { + /* FindFirstFile() returns ERROR_FILE_NOT_FOUND when no files are found. + If we didn't get that, then return NULL */ + if(GetLastError() != ERROR_FILE_NOT_FOUND) + { + HeapFree(GetProcessHeap(), 0, (void*)win32dir); + return NULL; + } + } + + return (SST_Dir)win32dir; +} + +/*************************************************************************/ + +int SST_OS_ReadNextDirectoryEntry(SST_Dir dir, SST_FileInfo* fileInfoReturn) +{ + SST_Dir_Win32* win32dir = (SST_Dir_Win32*)dir; + int result = 0; + + /* Check if call to FindFirstFileA() returned 0 files found */ + if(win32dir->hFind != INVALID_HANDLE_VALUE) + { + /* FindFirstFileA() copies the first file data automatically, so use the first time */ + if(win32dir->once) + { + /* NOTE: data already copied to win32dir->data when FindFirstFileA() was called */ + win32dir->once = 0; + result = 1; + } + else + result = FindNextFileA(win32dir->hFind, &win32dir->data); + + /* If we have file data to copy, then do so now */ + if(result) + { + if(strcmp(win32dir->data.cFileName, ".") == 0 || strcmp(win32dir->data.cFileName, "..") == 0) + return SST_OS_ReadNextDirectoryEntry(dir, fileInfoReturn); + else + copyWin32FindData(fileInfoReturn, &win32dir->data); + } + } + + return result; +} + +/*************************************************************************/ + +void SST_OS_CloseDirectory(SST_Dir dir) +{ + SST_Dir_Win32* win32dir = (SST_Dir_Win32*)dir; + + /* Close the handle if not invalid */ + if(win32dir->hFind != INVALID_HANDLE_VALUE) + FindClose(win32dir->hFind); + + /* Return heap memory */ + HeapFree(GetProcessHeap(), 0, (void*)win32dir); +} + +/*************************************************************************/ + +int SST_OS_CreateDirectory(const char* dir) +{ + if(CreateDirectoryA(dir, NULL) == FALSE) + { + if(GetLastError() == ERROR_ALREADY_EXISTS) + return 1; /* positive == already exists */ + else + return -1; /* negative == error */ + } + + return 0; /* zero == success */ +} + +/*************************************************************************/ + +int SST_OS_RemoveDirectory(const char* dir) +{ + return (int)RemoveDirectory(dir); +} + diff --git a/libsst-os/SST_File_POSIX.c b/libsst-os/SST_File_POSIX.c new file mode 100644 index 0000000..64f8688 --- /dev/null +++ b/libsst-os/SST_File_POSIX.c @@ -0,0 +1,350 @@ +/* + SST_File_POSIX.c + Author: Patrick Baggett <ptb1@762studios.com> + Created: 12/23/2011 + + Purpose: + + libsst-os file I/O for POSIX platforms + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ + +#include "POSIXPrivate.h" +#include <SST/SST_File.h> +#include <SST/SST_Assert.h> + +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> + +/******************************************************************************/ + +SST_File SST_OS_OpenFile(const char* path, uint32_t mode) +{ + int flags; + int fd; + SST_File_POSIX* file; + mode_t openMode = 0; + + SST_OS_DebugAssert(path != NULL, "File path may not be NULL"); + + /* Async I/O is not yet suppported */ + if(mode & SST_OPEN_ASYNC) + return NULL; + + /* Only one of SST_OPEN_HINTRAND or SST_OPEN_HINTSEQ may be set. */ + if((mode & (SST_OPEN_HINTRAND|SST_OPEN_HINTSEQ)) == (SST_OPEN_HINTRAND|SST_OPEN_HINTSEQ)) + return NULL; + + switch(mode & 0xF) /* Lower byte has the open mode, remaining 24 bits are flags */ + { + /* In each of the three cases (r/w/a), we set the execute bit so that memory mapped + I/O can specify 'execute' a permission too -- apparently the mapped view must be a + subset of the permissions the file was originally opened with. */ + case SST_OPEN_READ: + flags = O_RDONLY; + break; + + case SST_OPEN_WRITE: + flags = O_WRONLY | O_CREAT | O_TRUNC; + openMode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH; /* User/Group: RW, Other: R */ + break; + + case SST_OPEN_APPEND: + flags = O_WRONLY | O_APPEND; + break; + + /* Invalid open mode */ + default: + return NULL; + } + + fd = open(path, flags, openMode); + if(fd < 0) + return NULL; + #if _XOPEN_SOURCE >= 600 || _POSIX_C_SOURCE >= 200112L + if(mode & SST_OPEN_HINTRAND) + posix_fadvise(fd, 0, 0, POSIX_FADV_RANDOM); + else if(mode & SST_OPEN_HINTSEQ) + posix_fadvise(fd, 0, 0, POSIX_FADV_SEQUENTIAL); + #endif + + file = (SST_File_POSIX*)malloc(sizeof(SST_File_POSIX)); + if(file == NULL) + { + close(fd); + return NULL; + } + + file->fd = fd; + file->isAsync = (int)(mode & SST_OPEN_ASYNC); /* Not yet used */ +#ifdef _DEBUG + file->nrMmaps = 0; +#endif + + return (SST_File)file; +} + +/******************************************************************************/ + +uint64_t SST_OS_WriteFile(SST_File file, const void* buf, uint64_t bytes) +{ + SST_File_POSIX* fp = (SST_File_POSIX*)file; + uint64_t bytesLeft = bytes; + uint64_t totalWritten; + const char* writePtr = (const char*)buf; + + SST_OS_DebugAssert(file != NULL, "File handle may not be NULL"); + SST_OS_DebugAssert(buf != NULL, "Buffer may not be NULL"); + SST_OS_DebugAssert(!fp->isAsync, "Files opened for asynchronous I/O may not use the synchronous file I/O functions"); +#ifdef _DEBUG + SST_OS_DebugAssert(fp->nrMmaps == 0, "Cannot use synchronous file I/O while memory maps exist!"); +#endif + /* Do nothing? */ + if(bytes == 0) + return 0; + + totalWritten = 0; + do + { + size_t nrBytesToWrite; + ssize_t nrWritten; + + /* Determine how many bytes to write */ + if(bytesLeft > SIZE_MAX) + nrBytesToWrite = SIZE_MAX; + else + nrBytesToWrite = (size_t)bytesLeft; + + /* Actually write data to the file */ + nrWritten = write(fp->fd, writePtr, nrBytesToWrite); + + if(nrWritten < 0) /* error */ + { + /* OK, but some of the data may have been written, so stop now but return how far we did get */ + break; + } + + /* Advance pointers and counters */ + writePtr += nrWritten; + totalWritten += (uint64_t)nrWritten; + bytesLeft -= (uint64_t)nrWritten; + } while(bytesLeft > 0); + + return totalWritten; +} + +/******************************************************************************/ + +uint64_t SST_OS_ReadFile(SST_File file, void* buf, uint64_t bytes) +{ + SST_File_POSIX* fp = (SST_File_POSIX*)file; + uint64_t bytesLeft = bytes; + uint64_t totalRead; + char* readPtr = (char*)buf; + + SST_OS_DebugAssert(file != NULL, "File handle may not be NULL"); + SST_OS_DebugAssert(buf != NULL, "Buffer may not be NULL"); + SST_OS_DebugAssert(!fp->isAsync, "Files opened for asynchronous I/O may not use the synchronous file I/O functions"); +#ifdef _DEBUG + SST_OS_DebugAssert(fp->nrMmaps == 0, "Cannot use synchronous file I/O while memory maps exist!"); +#endif + + /* Do nothing? */ + if(bytes == 0) + return 0; + + totalRead = 0; + do + { + size_t nrBytesToRead; + ssize_t nrRead; + + /* Determine how many bytes to read */ + if(bytesLeft > SIZE_MAX) + nrBytesToRead = SIZE_MAX; + else + nrBytesToRead = (size_t)bytesLeft; + + + nrRead = read(fp->fd, readPtr, nrBytesToRead); + if(nrRead <= 0) + { + /* Error or EOF, but some of the reads could have succeeded, so return how much + was read */ + break; + } + + /* Advance pointers and counters */ + readPtr += nrRead; + totalRead += (uint64_t)nrRead; + bytesLeft -= (uint64_t)nrRead; + + } while(bytesLeft > 0); + + return totalRead; +} + +/******************************************************************************/ +int SST_OS_GetFilePointer(SST_File file, uint64_t* fpReturn) +{ + SST_File_POSIX* fp = (SST_File_POSIX*)file; + off_t off; + + SST_OS_DebugAssert(file != NULL, "File handle may not be NULL"); + SST_OS_DebugAssert(fpReturn != NULL, "File pointer return may not be NULL"); +#ifdef _DEBUG + SST_OS_DebugAssert(fp->nrMmaps == 0, "Cannot use synchronous file I/O while memory maps exist!"); +#endif + + off = lseek(fp->fd, 0, SEEK_CUR); + + if(off == (off_t)-1) + return 0; + + *fpReturn = (uint64_t)off; + return 1; +} + +/******************************************************************************/ + +int SST_OS_SetFilePointer(SST_File file, uint64_t ptr) +{ + SST_File_POSIX* fp = (SST_File_POSIX*)file; + off_t off; + SST_OS_DebugAssert(file != NULL, "File handle may not be NULL"); +#ifdef _DEBUG + SST_OS_DebugAssert(fp->nrMmaps == 0, "Cannot use synchronous file I/O while memory maps exist!"); +#endif + + /* Trying to seek > 4GB but underlying OS doesn't support it -> error */ + if(sizeof(off_t) == sizeof(uint32_t) && ptr > UINT32_MAX) + return 0; + + off = (off_t)ptr; + + if(lseek(fp->fd, off, SEEK_SET) != (off_t)-1) + return 0; + + return 1; +} + +/******************************************************************************/ + +int SST_OS_FileEOF(SST_File file) +{ + SST_File_POSIX* fp = (SST_File_POSIX*)file; + off_t here, eof; + SST_OS_DebugAssert(file != NULL, "File handle may not be NULL"); +#ifdef _DEBUG + SST_OS_DebugAssert(fp->nrMmaps == 0, "Cannot use synchronous file I/O while memory maps exist!"); +#endif + + /* Step 1: Get current file position */ + here = lseek(fp->fd, 0, SEEK_CUR); + if(here == (off_t)-1) + return -1; + + /* Step 2: Seek to EOF */ + eof = lseek(fp->fd, 0, SEEK_END); + if(eof == (off_t)-1) + return -2; + + /* Step 3: Put it back! */ + lseek(fp->fd, here, SEEK_SET); + + /* Step 4: Compare and return */ + return (here == eof); +} + +/******************************************************************************/ + +void SST_OS_FlushFile(SST_File file) +{ + SST_File_POSIX* fp = (SST_File_POSIX*)file; + + SST_OS_DebugAssert(file != NULL, "File handle may not be NULL"); + + (void)fsync(fp->fd); +} + +/******************************************************************************/ + +void SST_OS_CloseFile(SST_File file) +{ + SST_File_POSIX* fp = (SST_File_POSIX*)file; + + SST_OS_DebugAssert(file != NULL, "File handle may not be NULL"); + + if(fp->fd > 0) + { + close(fp->fd); + #ifdef _DEBUG + fp->fd = 0; + #endif + } + + #ifdef _DEBUG + SST_OS_DebugAssert(fp->nrMmaps == 0, "Closing file with open memory maps means leaked OS resources"); + #endif + + free(fp); +} + +/******************************************************************************/ + +int SST_OS_SeekFile(SST_File file, int64_t offset, int fromWhere) +{ + SST_File_POSIX* fp = (SST_File_POSIX*)file; + int method; + off_t off; + + SST_OS_DebugAssert(file != NULL, "File handle may not be NULL"); +#ifdef _DEBUG + SST_OS_DebugAssert(fp->nrMmaps == 0, "Cannot use synchronous file I/O while memory maps exist!"); +#endif + + off = (off_t)offset; + + /* Map SST to POSIX constants (pretty sure they are isomorphic) */ + switch(fromWhere) + { + case SST_SEEK_START: method = SEEK_SET; break; + case SST_SEEK_CUR: method = SEEK_CUR; break; + case SST_SEEK_END: method = SEEK_END; break; + + /* Invalid parameter */ + default: return 0; + } + + if(lseek(fp->fd, off, method) == (off_t)-1) + return 0; + + return 1; + +} + +/******************************************************************************/ + +uint64_t SST_OS_GetFileSize(SST_File file) +{ + SST_File_POSIX* fp = (SST_File_POSIX*)file; + struct stat info; + + if(fstat(fp->fd, &info) == 0) /* i.e. success */ + return (uint64_t)info.st_size; + + /* Failure */ + return UINT64_MAX; +} + +/******************************************************************************/ + diff --git a/libsst-os/SST_File_Win32.c b/libsst-os/SST_File_Win32.c new file mode 100644 index 0000000..83a338a --- /dev/null +++ b/libsst-os/SST_File_Win32.c @@ -0,0 +1,370 @@ +/* + SST_File_Win32.c + Author: Patrick Baggett <ptbaggett@762studios.com> + Created: 12/23/2011 + + Purpose: + + libsst-os file I/O for Win32 platforms (Windows 7 or later) + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ + +#include "Win32Private.h" +#include <SST/SST_File.h> +#include <SST/SST_Assert.h> + +/*************************************************************************/ + +SST_File SST_OS_OpenFile(const char* path, uint32_t mode) +{ + DWORD accessFlags; + DWORD createFlags; + DWORD otherFlags; + DWORD shareFlags; + HANDLE hFile; + SST_File_Win32* file; + + SST_OS_DebugAssert(path != NULL, "File path may not be NULL"); + + /* Async I/O is not yet suppported */ + /* see win32 flag FILE_FLAG_OVERLAPPED */ + if(mode & SST_OPEN_ASYNC) + return NULL; + + /* Only one of SST_OPEN_HINTRAND or SST_OPEN_HINTSEQ may be set. */ + if((mode & (SST_OPEN_HINTRAND|SST_OPEN_HINTSEQ)) == (SST_OPEN_HINTRAND|SST_OPEN_HINTSEQ)) + return NULL; + + otherFlags = FILE_ATTRIBUTE_NORMAL; + switch(mode & 0xF) /* Lower byte has the open mode, remaining 24 bits are flags */ + { + /* In each of the three cases (r/w/a), we set the execute bit so that memory mapped + I/O can specify 'execute' a permission too -- apparently the mapped view must be a + subset of the permissions the file was originally opened with. */ + case SST_OPEN_READ: + createFlags = OPEN_EXISTING; + accessFlags = GENERIC_READ | GENERIC_EXECUTE; + shareFlags = FILE_SHARE_READ; + break; + + case SST_OPEN_WRITE: + createFlags = CREATE_ALWAYS; + accessFlags = GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE; + shareFlags = 0; + break; + + case SST_OPEN_APPEND: + createFlags = OPEN_ALWAYS; + accessFlags = FILE_APPEND_DATA; + shareFlags = 0; + break; + + /* Invalid open mode */ + default: + return NULL; + } + + if(mode & SST_OPEN_HINTRAND) + otherFlags |= FILE_FLAG_RANDOM_ACCESS; + else if(mode & SST_OPEN_HINTSEQ) + otherFlags |= FILE_FLAG_SEQUENTIAL_SCAN; + + + hFile = CreateFileA(path, accessFlags, shareFlags, NULL, createFlags, otherFlags, NULL); + if(hFile == INVALID_HANDLE_VALUE) + return NULL; + + /* Append mode: start at end of file */ + if((mode & 0xF) == SST_OPEN_APPEND) + SetFilePointer(hFile, 0, NULL, FILE_END); + + /* Can't use malloc(), so use the process heap */ + file = (SST_File_Win32*)HeapAlloc(GetProcessHeap(), 0, sizeof(SST_File_Win32)); + if(file == NULL) + { + CloseHandle(hFile); + return NULL; + } + + file->hFile = hFile; + file->hMap = NULL; + file->isAsync = (int)(mode & SST_OPEN_ASYNC); /* Not yet used */ + file->accessFlags = accessFlags; +#ifdef _DEBUG + file->nrMmaps = 0; +#endif + + return (SST_File)file; +} + +/*************************************************************************/ + +uint64_t SST_OS_WriteFile(SST_File file, const void* buf, uint64_t bytes) +{ + SST_File_Win32* fp = (SST_File_Win32*)file; + uint64_t bytesLeft = bytes; + uint64_t totalWritten; + const char* writePtr = (const char*)buf; + + SST_OS_DebugAssert(file != NULL, "File handle may not be NULL"); + SST_OS_DebugAssert(buf != NULL, "Buffer may not be NULL"); + SST_OS_DebugAssert(!fp->isAsync, "Files opened for asynchronous I/O may not use the synchronous file I/O functions"); +#ifdef _DEBUG + SST_OS_DebugAssert(fp->nrMmaps == 0, "Cannot use synchronous file I/O while memory maps exist!"); +#endif + /* Do nothing? */ + if(bytes == 0) + return 0; + + totalWritten = 0; + do + { + DWORD nrBytesToWrite, nrWritten; + + /* Determine how many bytes to write (at most 4GB per WriteFile() call) */ + if(bytesLeft > (uint64_t)0xFFFFFFFF) + nrBytesToWrite = 0xFFFFFFFF; + else + nrBytesToWrite = (DWORD)bytesLeft; + + /* Ensure invalid 'nrWritten' before calling WriteFile() */ + nrWritten = 0; + + /* Actually write data to the file */ + if(WriteFile(fp->hFile, writePtr, nrBytesToWrite, &nrWritten, NULL) == FALSE) + { + /* OK, but some of the data may have been written, so stop now but return how far we did get */ + break; + } + + /* Advance pointers and counters */ + writePtr += nrWritten; + totalWritten += (uint64_t)nrWritten; + bytesLeft -= (uint64_t)nrWritten; + } while(bytesLeft > 0); + + return totalWritten; +} + +/*************************************************************************/ + +uint64_t SST_OS_ReadFile(SST_File file, void* buf, uint64_t bytes) +{ + SST_File_Win32* fp = (SST_File_Win32*)file; + uint64_t bytesLeft = bytes; + uint64_t totalRead; + char* readPtr = (char*)buf; + + SST_OS_DebugAssert(file != NULL, "File handle may not be NULL"); + SST_OS_DebugAssert(buf != NULL, "Buffer may not be NULL"); + SST_OS_DebugAssert(!fp->isAsync, "Files opened for asynchronous I/O may not use the synchronous file I/O functions"); +#ifdef _DEBUG + SST_OS_DebugAssert(fp->nrMmaps == 0, "Cannot use synchronous file I/O while memory maps exist!"); +#endif + /* Do nothing? */ + if(bytes == 0) + return 0; + + totalRead = 0; + do + { + DWORD nrBytesToRead, nrRead; + + /* Determine how many bytes to read (at most 4GB per ReadFile() call) */ + if(bytesLeft > (uint64_t)0xFFFFFFFF) + nrBytesToRead = 0xFFFFFFFF; + else + nrBytesToRead = (DWORD)bytesLeft; + + /* Ensure invalid 'nrRead' before calling ReadFile() */ + nrRead = 0; + + if(ReadFile(fp->hFile, readPtr, nrBytesToRead, &nrRead, NULL) == FALSE) + { + /* Error, but some of the reads could have succeeded, so return how much + was read */ + break; + } + + /* When nrRead is 0 but ReadFile() returns true, then the EOF is hit */ + if(nrRead == 0) + break; + + /* Advance pointers and counters */ + readPtr += (size_t)nrRead; + totalRead += (uint64_t)nrRead; + bytesLeft -= (uint64_t)nrRead; + } while(bytesLeft > 0); + + return totalRead; +} + +/*************************************************************************/ + +int SST_OS_GetFilePointer(SST_File file, uint64_t* fpReturn) +{ + SST_File_Win32* fp = (SST_File_Win32*)file; + LARGE_INTEGER zeroPos, newPos; + + SST_OS_DebugAssert(file != NULL, "File handle may not be NULL"); + SST_OS_DebugAssert(fpReturn != NULL, "File pointer return may not be NULL"); +#ifdef _DEBUG + SST_OS_DebugAssert(fp->nrMmaps == 0, "Cannot use synchronous file I/O while memory maps exist!"); +#endif + + /* Zero bytes from 'current' = just get the position */ + zeroPos.QuadPart = 0; + + if(SetFilePointerEx(fp->hFile, zeroPos, &newPos, FILE_CURRENT) == FALSE) + return 0; + + *fpReturn = (uint64_t)newPos.QuadPart; + return 1; +} + +/*************************************************************************/ + +int SST_OS_SetFilePointer(SST_File file, uint64_t ptr) +{ + SST_File_Win32* fp = (SST_File_Win32*)file; + LARGE_INTEGER pos; + + SST_OS_DebugAssert(file != NULL, "File handle may not be NULL"); +#ifdef _DEBUG + SST_OS_DebugAssert(fp->nrMmaps == 0, "Cannot use synchronous file I/O while memory maps exist!"); +#endif + + /* Set it */ + pos.QuadPart = (LONGLONG)ptr; + if(SetFilePointerEx(fp->hFile, pos, NULL, FILE_BEGIN) == FALSE) + return 0; + + return 1; +} + +/*************************************************************************/ + +int SST_OS_FileEOF(SST_File file) +{ + SST_File_Win32* fp = (SST_File_Win32*)file; + LARGE_INTEGER ptr, end, zero; + + SST_OS_DebugAssert(file != NULL, "File handle may not be NULL"); +#ifdef _DEBUG + SST_OS_DebugAssert(fp->nrMmaps == 0, "Cannot use synchronous file I/O while memory maps exist!"); +#endif + + zero.QuadPart = 0; + + /* Step 1: Get current file position */ + if(SetFilePointerEx(fp->hFile, zero, &ptr, FILE_CURRENT) == FALSE) + return -2; + + /* Step 2: Get end of file position */ + if(GetFileSizeEx(fp->hFile, &end) == FALSE) + return -3; + + /* Step 3: Compare */ + return (ptr.QuadPart == end.QuadPart); +} + +/*************************************************************************/ + +void SST_OS_FlushFile(SST_File file) +{ + SST_File_Win32* fp = (SST_File_Win32*)file; + + SST_OS_DebugAssert(file != NULL, "File handle may not be NULL"); + + (void)FlushFileBuffers(fp->hFile); +} + +/*************************************************************************/ + +void SST_OS_CloseFile(SST_File file) +{ + SST_File_Win32* fp = (SST_File_Win32*)file; + + SST_OS_DebugAssert(file != NULL, "File handle may not be NULL"); + + if(fp->hFile != NULL) + { + CloseHandle(fp->hFile); + #ifdef _DEBUG + fp->hFile = NULL; + #endif + } + + if(fp->hMap != NULL) + { + CloseHandle(fp->hMap); + #ifdef _DEBUG + fp->hMap = NULL; + #endif + } + + #ifdef _DEBUG + SST_OS_DebugAssert(fp->nrMmaps == 0, "Closing file with open memory maps means leaked OS resources"); + #endif + + + HeapFree(GetProcessHeap(), 0, fp); +} + +/*************************************************************************/ + +int SST_OS_SeekFile(SST_File file, int64_t offset, int fromWhere) +{ + SST_File_Win32* fp = (SST_File_Win32*)file; + LARGE_INTEGER pos; + DWORD method; + + SST_OS_DebugAssert(file != NULL, "File handle may not be NULL"); +#ifdef _DEBUG + SST_OS_DebugAssert(fp->nrMmaps == 0, "Cannot use synchronous file I/O while memory maps exist!"); +#endif + + /* Map SST to Win32 constants (pretty sure they are isomorphic) */ + switch(fromWhere) + { + case SST_SEEK_START: method = FILE_BEGIN; break; + case SST_SEEK_CUR: method = FILE_CURRENT; break; + case SST_SEEK_END: method = FILE_END; break; + + /* Invalid parameter */ + default: return 0; + } + + /* Save the offset, then do it */ + pos.QuadPart = (LONGLONG)offset; + if(SetFilePointerEx(fp->hFile, pos, NULL, method) == FALSE) + return 0; + + return 1; + +} + +/*************************************************************************/ + +uint64_t SST_OS_GetFileSize(SST_File file) +{ + SST_File_Win32* fp = (SST_File_Win32*)file; + LARGE_INTEGER size; + + if(GetFileSizeEx(fp->hFile, &size)) + return (uint64_t)size.QuadPart; + + /* Failure */ + return UINT64_MAX; +} + +/*************************************************************************/ + diff --git a/libsst-os/SST_Mmap_POSIX.c b/libsst-os/SST_Mmap_POSIX.c new file mode 100644 index 0000000..afe3ea4 --- /dev/null +++ b/libsst-os/SST_Mmap_POSIX.c @@ -0,0 +1,170 @@ +/* + SST_Mmap_POSIX.c + Author: Patrick Baggett <ptb1@762studios.com> + Created: 12/23/2011 + + Purpose: + + libsst-os memory mapped file I/O functions for POSIX + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ + +#include "POSIXPrivate.h" +#include <sys/stat.h> +#include <SST/SST_Mmap.h> +#include <SST/SST_SysMem.h> /* SST_PROTECT_XXXXX constants, SST_OS_GetPageSize() */ +#include <SST/SST_Assert.h> + +void __libsst_init_mmapsize() { /* Not used on POSIX */ } + +/******************************************************************************/ + +uint32_t SST_OS_GetMmapGranularity(void) +{ + return SST_OS_GetPageSize(); +} + +/******************************************************************************/ + +SST_MemoryMap SST_OS_CreateMmap(SST_File file, uint64_t offset, size_t mapLength, int mode) +{ + SST_File_POSIX* fp = (SST_File_POSIX*)file; + SST_MemoryMap_POSIX* mm; + int access = 0; + void* ptr; + off_t off; + + SST_OS_DebugAssert(file != NULL, "File handle may not be NULL"); + SST_OS_DebugAssert((mode & (~(SST_PROTECT_READ|SST_PROTECT_WRITE|SST_PROTECT_EXEC))) == 0, "The mode bits may only contain SST_PROTECT_READ/WRITE/EXEC and nothing else"); + SST_OS_DebugAssert((offset & (SST_OS_GetMmapGranularity()-1)) == 0, "Offset must be aligned to system granularity. Use SST_OS_GetMmapGranuality() to determine this"); + SST_OS_DebugAssert( (offset == 0 && mapLength == 0) || mapLength > 0, "Map length must be non-zero OR offset and length must both be zero (map whole file)"); + + if(mode & SST_PROTECT_READ) + access |= PROT_READ;; + if(mode & SST_PROTECT_WRITE) + access |= PROT_WRITE; + if(mode & SST_PROTECT_EXEC) + access |= PROT_EXEC; + + off = (off_t)offset; + + /* Map whole file */ + if(mapLength == 0) + { + struct stat s; + if(fstat(fp->fd, &s) == 0) + mapLength = (size_t)s.st_size; + else /* fstat() failed, try lseek() */ + { + off_t here, end; + + here = lseek(fp->fd, 0, SEEK_CUR); + end = lseek(fp->fd, 0, SEEK_END); + + /* failed? */ + if(here == (off_t)-1 || end == (off_t)-1) + return NULL; + + mapLength = (size_t)end; + + /* Restore file position (not that it matters much if you mmap() the whole thing) */ + lseek(fp->fd, here, SEEK_SET); + } + + } + + ptr = mmap(NULL, mapLength, access, MAP_SHARED, fp->fd, off); + + if(ptr == MAP_FAILED) + return NULL; + + /* Allocate a memory map region */ + mm = (SST_MemoryMap_POSIX*)malloc(sizeof(SST_MemoryMap_POSIX)); + if(mm == NULL) + { + munmap(ptr, mapLength); + return NULL; + } + + mm->offset = offset; + mm->len = mapLength; + mm->base = ptr; + #ifdef _DEBUG + mm->owner = fp; + fp->nrMmaps++; + #endif + + return (SST_MemoryMap)mm; +} + +/******************************************************************************/ + +void SST_OS_DestroyMmap(SST_MemoryMap mappedRegion) +{ + SST_MemoryMap_POSIX* mm = (SST_MemoryMap_POSIX*)mappedRegion; + + SST_OS_DebugAssert(mappedRegion != NULL, "Memory map handle may not be NULL"); + + munmap(mm->base, mm->len); + + #ifdef _DEBUG + mm->base = NULL; + mm->owner->nrMmaps--; + #endif + + free(mm); +} + +/******************************************************************************/ + +void* SST_OS_GetMmapBase(SST_MemoryMap mappedRegion) +{ + SST_MemoryMap_POSIX* mm = (SST_MemoryMap_POSIX*)mappedRegion; + + SST_OS_DebugAssert(mappedRegion != NULL, "Memory map handle may not be NULL"); + + return mm->base; +} + +/******************************************************************************/ + +size_t SST_OS_GetMmapSize(SST_MemoryMap mappedRegion) +{ + SST_MemoryMap_POSIX* mm = (SST_MemoryMap_POSIX*)mappedRegion; + + SST_OS_DebugAssert(mappedRegion != NULL, "Memory map handle may not be NULL"); + + return mm->len; +} + +/******************************************************************************/ + +uint64_t SST_OS_GetMmapOffset(SST_MemoryMap mappedRegion) +{ + SST_MemoryMap_POSIX* mm = (SST_MemoryMap_POSIX*)mappedRegion; + + SST_OS_DebugAssert(mappedRegion != NULL, "Memory map handle may not be NULL"); + + return mm->offset; +} + +/******************************************************************************/ + +void SST_OS_SyncMmap(SST_MemoryMap mappedRegion) +{ + SST_MemoryMap_POSIX* mm = (SST_MemoryMap_POSIX*)mappedRegion; + + SST_OS_DebugAssert(mappedRegion != NULL, "Memory map handle may not be NULL"); + + /* Synchronize with the OS, but do so async */ + msync(mm->base, mm->len, MS_ASYNC); +} + diff --git a/libsst-os/SST_Mmap_Win32.c b/libsst-os/SST_Mmap_Win32.c new file mode 100644 index 0000000..96ffbae --- /dev/null +++ b/libsst-os/SST_Mmap_Win32.c @@ -0,0 +1,188 @@ +/* + SST_Mmap_Win32.c + Author: Patrick Baggett <ptbaggett@762studios.com> + Created: 12/23/2011 + + Purpose: + + libsst-os memory mapped file I/O functions for Win32 systems (Windows 7 or later) + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ + +#include "Win32Private.h" +#include <SST/SST_Mmap.h> +#include <SST/SST_SysMem.h> /* SST_PROTECT_XXXXX constants */ +#include <SST/SST_Assert.h> + +#if !defined(FILE_MAP_EXECUTE) /* Added in Windows XP SP2 */ + #define FILE_MAP_EXECUTE 0x20 +#endif + +static uint32_t allocGranularity; + +void __libsst_init_mmapsize() +{ + SYSTEM_INFO si; + + GetNativeSystemInfo(&si); + + allocGranularity = (uint32_t)si.dwAllocationGranularity; +} + + +/*************************************************************************/ + +uint32_t SST_OS_GetMmapGranularity(void) +{ + return allocGranularity; +} + +/*************************************************************************/ + +SST_MemoryMap SST_OS_CreateMmap(SST_File file, uint64_t offset, size_t mapLength, int mode) +{ + SST_File_Win32* fp = (SST_File_Win32*)file; + SST_MemoryMap_Win32* mm; + DWORD access, offsetLow, offsetHigh; + void* ptr; + + SST_OS_DebugAssert(file != NULL, "File handle may not be NULL"); + SST_OS_DebugAssert((mode & (~(SST_PROTECT_READ|SST_PROTECT_WRITE|SST_PROTECT_EXEC))) == 0, "The mode bits may only contain SST_PROTECT_READ/WRITE/EXEC and nothing else"); + SST_OS_DebugAssert((offset & (SST_OS_GetMmapGranularity()-1)) == 0, "Offset must be aligned to system granularity. Use SST_OS_GetMmapGranuality() to determine this"); + SST_OS_DebugAssert((offset == 0 && mapLength == 0) || mapLength > 0, "Map length must be non-zero OR offset and length must both be zero (map whole file)"); + + /* No file mapping yet? */ + if(fp->hMap == NULL) + { + DWORD pageProt; + + /* Decide on protection flags. See SST_File_Win32.c/SST_OS_OpenFile() for the 'case' values */ + switch(fp->accessFlags) + { + case GENERIC_READ | GENERIC_EXECUTE: pageProt = PAGE_EXECUTE_READ; break; + case GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE: pageProt = PAGE_EXECUTE_READWRITE; break; + default: return NULL; + } + + /* Actually create the file mapping */ + fp->hMap = CreateFileMappingA(fp->hFile, NULL, pageProt, 0, 0, NULL); + if(fp->hMap == NULL) + return NULL; + } + /* Windows is weird about its flags: it allows {R, W} + {X}, so only 4 combinations of + possible values. However, the 'W' bit implies 'R'. */ + if(mode & SST_PROTECT_READ) + access = FILE_MAP_READ; + if(mode & SST_PROTECT_WRITE) + access = FILE_MAP_WRITE; /* This is actually r/w, which is why we don't use "else if(...)" */ + if(mode & SST_PROTECT_EXEC) + access |= FILE_MAP_EXECUTE; + + offsetLow = (DWORD)(offset & 0xFFFFFFFF); + offsetHigh = (DWORD)(offset >> 32); + + /* Windows already treats a mapLength == 0 as "map to end of file". We just ensure (at the top) that + offset == 0 so it really means "map from beginning to end". */ + + ptr = MapViewOfFileEx(fp->hMap, access, offsetHigh, offsetLow, mapLength, NULL); + + if(ptr == NULL) + return NULL; + + /* Allocate a memory map region */ + mm = (SST_MemoryMap_Win32*)HeapAlloc(GetProcessHeap(), 0, sizeof(SST_MemoryMap_Win32)); + if(mm == NULL) + { + UnmapViewOfFile(ptr); + return NULL; + } + + if(mapLength == 0) + { + LARGE_INTEGER size; + GetFileSizeEx(fp->hFile, &size); + + mapLength = (size_t)size.QuadPart; + } + + mm->offset = offset; + mm->len = mapLength; + mm->base = ptr; + #ifdef _DEBUG + mm->owner = fp; + fp->nrMmaps++; + #endif + + return (SST_MemoryMap)mm; +} + +/*************************************************************************/ + +void SST_OS_DestroyMmap(SST_MemoryMap mappedRegion) +{ + SST_MemoryMap_Win32* mm = (SST_MemoryMap_Win32*)mappedRegion; + + SST_OS_DebugAssert(mappedRegion != NULL, "Memory map handle may not be NULL"); + + UnmapViewOfFile(mm->base); + + #ifdef _DEBUG + mm->base = NULL; + mm->owner->nrMmaps--; + #endif + + HeapFree(GetProcessHeap(), 0, mm); +} + +/*************************************************************************/ + +void* SST_OS_GetMmapBase(SST_MemoryMap mappedRegion) +{ + SST_MemoryMap_Win32* mm = (SST_MemoryMap_Win32*)mappedRegion; + + SST_OS_DebugAssert(mappedRegion != NULL, "Memory map handle may not be NULL"); + + return mm->base; +} + +/*************************************************************************/ + +size_t SST_OS_GetMmapSize(SST_MemoryMap mappedRegion) +{ + SST_MemoryMap_Win32* mm = (SST_MemoryMap_Win32*)mappedRegion; + + SST_OS_DebugAssert(mappedRegion != NULL, "Memory map handle may not be NULL"); + + return mm->len; +} + +/*************************************************************************/ + +uint64_t SST_OS_GetMmapOffset(SST_MemoryMap mappedRegion) +{ + SST_MemoryMap_Win32* mm = (SST_MemoryMap_Win32*)mappedRegion; + + SST_OS_DebugAssert(mappedRegion != NULL, "Memory map handle may not be NULL"); + + return mm->offset; +} + +/*************************************************************************/ + +void SST_OS_SyncMmap(SST_MemoryMap mappedRegion) +{ + SST_MemoryMap_Win32* mm = (SST_MemoryMap_Win32*)mappedRegion; + + SST_OS_DebugAssert(mappedRegion != NULL, "Memory map handle may not be NULL"); + + FlushViewOfFile(mm->base, mm->len); +} + diff --git a/libsst-os/SST_OSInit.c b/libsst-os/SST_OSInit.c new file mode 100644 index 0000000..dece43c --- /dev/null +++ b/libsst-os/SST_OSInit.c @@ -0,0 +1,33 @@ +/* + SST_OSInit.c + Author: Patrick Baggett <ptbaggett@762studios.com> + Created: 5/29/2013 + + Purpose: + + libsst-os initialization function + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ + +extern void __libsst_init_endian(); +extern void __libsst_init_pagesize(); +extern void __libsst_init_mmapsize(); +extern int __libsst_init_time(); +extern int __libsst_init_user(); + +int SST_OS_Init() +{ + __libsst_init_endian(); + __libsst_init_pagesize(); + __libsst_init_mmapsize(); + + return __libsst_init_time() && __libsst_init_user(); +} diff --git a/libsst-os/SST_SafeArithmetic.c b/libsst-os/SST_SafeArithmetic.c new file mode 100644 index 0000000..e93a70b --- /dev/null +++ b/libsst-os/SST_SafeArithmetic.c @@ -0,0 +1,407 @@ +/* + SST_SafeArithmetic.c + Author: Chris Ertel <crertel@762studios.com> + Created: 1/16/2012 + + Purpose: + + Functions to help perform integer arithmetic while catching overflow conditions. + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ + +#include <SST/SST_SafeArithmetic.h> +#include <limits.h> + +int SST_OS_SafeAddI8(int8_t _a, int8_t _b, int8_t* _out) +{ + int8_t ret = _a + _b; + + /* if they are opposite signs, they cannot overflow */ + if ( (_a >= 0 && _b <= 0) || + (_b >= 0 && _a <= 0) ) + { + *_out = ret; + return 1; + } + + /* if they are the same sign, check for overflow */ + if (_a < 0 || _b < 0) + { + if (ret > _a && ret > _b) + return 0; + } + else + { + if (ret < _a && ret < _b) + return 0; + } + + + *_out = ret; + return 1; +} + +int SST_OS_SafeAddI8ToSizeT(int8_t _a, size_t _size, size_t* _out) +{ + size_t ret = _size + _a; + + if (_a >= 0) + { + if (ret < _size) + return 0; + } + else + { + if (ret > _size) + return 0; + } + + *_out = ret; + return 1; +} + +int SST_OS_SafeAddU8(uint8_t _a, uint8_t _b, uint8_t* _out) +{ + uint8_t ret = _a + _b; + + if (ret < _a || ret < _b) + return 0; + + *_out = ret; + return 1; +} + +int SST_OS_SafeMultiplyU8(uint8_t _a, uint8_t _b, uint8_t* _out) +{ + uint16_t a = _a; + uint16_t b = _b; + uint16_t ret = a*b; + + if (ret > 0xff) + return 0; + + *_out = (uint8_t) ret; + return 1; +} + +int SST_OS_SafeAddU8ToSizeT(uint8_t _a, size_t _size, size_t* _out) +{ + size_t ret = _a + _size; + + if (ret < _size) + return 0; + + *_out = ret; + return 1; +} + +int SST_OS_SafeAddI16(int16_t _a, int16_t _b, int16_t* _out) +{ + int16_t ret = _a + _b; + + /* if they are opposite signs, they cannot overflow */ + if ( (_a >= 0 && _b <= 0) || + (_b >= 0 && _a <= 0) ) + { + *_out = ret; + return 1; + } + + /* if they are the same sign, check for overflow */ + if (_a < 0 || _b < 0) + { + if (ret > _a && ret > _b) + return 0; + } + else + { + if (ret < _a && ret < _b) + return 0; + } + + + *_out = ret; + return 1; +} + +int SST_OS_SafeAddI16ToSizeT(int16_t _a, size_t _size, size_t* _out) +{ + size_t ret = _size + _a; + + if (_a >= 0) + { + if (ret < _size) + return 0; + } + else + { + if (ret > _size) + return 0; + } + + *_out = ret; + return 1; +} + +int SST_OS_SafeAddU16(uint16_t _a, uint16_t _b, uint16_t* _out) +{ + uint16_t ret = _a + _b; + + if (ret < _a || ret < _b) + return 0; + + *_out = ret; + return 1; +} + +int SST_OS_SafeMultiplyU16(uint16_t _a, uint16_t _b, uint16_t* _out) +{ + uint32_t a = _a; + uint32_t b = _b; + uint32_t ret = a*b; + + if (ret > 0xffff) + return 0; + + *_out = (uint16_t) ret; + return 1; +} + +int SST_OS_SafeAddU16ToSizeT(uint16_t _a, size_t _size, size_t* _out) +{ + size_t ret = _a + _size; + + if (ret < _size) + return 0; + + *_out = ret; + return 1; +} + +int SST_OS_SafeAddI32(int32_t _a, int32_t _b, int32_t* _out) +{ + int32_t ret = _a + _b; + + /* if they are opposite signs, they cannot overflow */ + if ( (_a >= 0 && _b <= 0) || + (_b >= 0 && _a <= 0) ) + { + *_out = ret; + return 1; + } + + /* if they are the same sign, check for overflow */ + if (_a < 0 || _b < 0) + { + if (ret > _a && ret > _b) + return 0; + } + else + { + if (ret < _a && ret < _b) + return 0; + } + + *_out = ret; + return 1; +} + +int SST_OS_SafeAddI32ToSizeT(int32_t _a, size_t _size, size_t* _out) +{ + size_t ret = _size + _a; + + if (_a >= 0) + { + if (ret < _size) + return 0; + } + else + { + if (ret > _size) + return 0; + } + + *_out = ret; + return 1; +} + +int SST_OS_SafeAddU32(uint32_t _a, uint32_t _b, uint32_t* _out) +{ + uint32_t ret = _a + _b; + + if (ret < _b || ret < _a) + return 0; + + *_out = ret; + return 1; +} + +int SST_OS_SafeMultiplyU32(uint32_t _a, uint32_t _b, uint32_t* _out) +{ + uint64_t a = _a; + uint64_t b = _b; + uint64_t ret = a*b; + + if (ret > 0xffffffff) + return 0; + + *_out = (uint32_t) ret; + return 1; +} + +int SST_OS_SafeAddU32ToSizeT(uint32_t _a, size_t _size, size_t* _out) +{ + size_t ret = _a + _size; + + if (ret < _size) + return 0; + + *_out = ret; + return 1; +} + +int SST_OS_SafeAddI64(int64_t _a, int64_t _b, int64_t* _out) +{ + int64_t ret = _a + _b; + + /* if they are opposite signs, they cannot overflow */ + if ( (_a >= 0 && _b <= 0) || + (_b >= 0 && _a <= 0) ) + { + *_out = ret; + return 1; + } + + /* if they are the same sign, check for overflow */ + if (_a < 0 || _b < 0) + { + if (ret > _a && ret > _b) + return 0; + } + else + { + if (ret < _a && ret < _b) + return 0; + } + + *_out = ret; + return 1; +} + +int SST_OS_SafeAddI64ToSizeT(int64_t _a, size_t _size, size_t* _out) +{ + + /* Positive value being added */ + if(_a >= 0) + { + /* + Some weirdness with the casting: if you cast 32-bit size_t to + a signed int64_t, it can sign extend the value. This is bad. + We want to zero extend to 64 bits, *then* interpret that as + a 64-bit integer. In other words, size_t -> int64_t should + always be a positive integer, and the upper 32-bits are zero. + + On 64-bit machines where size_t is 64 bits, then the cast + will never do a sign extend. + */ + const int64_t diff64 = (int64_t)((uint64_t)(SIZE_MAX - _size)); + + /* Then it shouldn't matter */ + if(_a > diff64) + return 0; + } + else /* Negative value being added. */ + { + const int64_t size64 = (int64_t)((uint64_t)_size); + + /* Ensure that if _a was added, the results + would be > 0, otherwise it is negative we + would overflow */ + if(size64 + _a < 0) + { + return 0; + } + } + + *_out = (size_t)_a + _size; + return 1; +} + +int SST_OS_SafeAddU64(uint64_t _a, uint64_t _b, uint64_t* _out) +{ + uint64_t ret = _a + _b; + + if (ret < _a || ret < _b) + return 0; + + *_out = ret; + return 1; +} + +/* SLOWSLOW This is obviously correct, but not fast. Use LUTs or something. */ +static int countHighestSetBitU64(uint64_t _in) +{ + int ret = 0; + while (_in > 0) + { + _in >>= 1; + ret++; + } + return ret; +} + +/* NOTE: For explanation, see ( http://stackoverflow.com/a/199455 ). */ +int SST_OS_SafeMultiplyU64(uint64_t _a, uint64_t _b, uint64_t* _out) +{ + uint64_t ret; + int log2a; + int log2b; + + /* special-case for 1 -- probably not needed */ + if (_a == 1 || _b == 1) + { + *_out = _a*_b; + return 1; + } + + log2a = countHighestSetBitU64(_a); + log2b = countHighestSetBitU64(_b); + + if (log2a + log2b > 64) + return 0; + + ret = _a*_b; + *_out = ret; + return 1; +} + +int SST_OS_SafeAddU64ToSizeT(uint64_t _a, size_t _size, size_t* _out) +{ + const size_t diff = SIZE_MAX - _size; + const uint64_t diff64 = (uint64_t)diff; + + if(diff64 < _a) + return 0; + + *_out = (size_t)_a + _size; + + return 1; +} + +int SST_OS_SafeAddSizeTToSizeT( size_t _a, size_t _b, size_t* _out) +{ + size_t out = _a + _b; + if (out < _a && out < _b) + return 0; + + *_out = out; + return 1; +} diff --git a/libsst-os/SST_SysMem_POSIX.c b/libsst-os/SST_SysMem_POSIX.c new file mode 100644 index 0000000..00731e2 --- /dev/null +++ b/libsst-os/SST_SysMem_POSIX.c @@ -0,0 +1,147 @@ +/* + SST_SysMem_POSIX.c + Author: Patrick Baggett <ptb1@762studios.com> + Created: 12/23/2011 + + Purpose: + + libsst-os system memory allocation functions for POSIX platforms + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ + +#include "POSIXPrivate.h" +#include <SST/SST_SysMem.h> +#include <SST/SST_Assert.h> + +#ifdef __APPLE__ +#include<sys/sysctl.h> +#endif + +static uint32_t cached_pagesize; + +void __libsst_init_pagesize() +{ + uint32_t pgsz = (uint32_t)-1; + + #ifdef _SC_PAGESIZE + pgsz = (uint32_t)sysconf(_SC_PAGESIZE); + #elif defined(_SC_PAGE_SIZE) + if(pgsz == (uint32_t)-1) + pgsz = (uint32_t)sysconf(_SC_PAGE_SIZE); + #endif + + cached_pagesize = pgsz; +} + +/******************************************************************************/ + +uint64_t SST_OS_GetMemorySize() +{ +#ifdef __APPLE__ + int param[2] = { CTL_HW, HW_MEMSIZE }; + uint64_t mem; + size_t size = sizeof(mem); + sysctl(param, 2, &mem, &size, NULL, 0); + return mem; +#else + uint32_t pagesize = SST_OS_GetPageSize(); + uint32_t pages; + + pages = sysconf(_SC_PHYS_PAGES); + if(pages == (uint32_t)-1) + return 0; + + return (uint64_t)pages*(uint64_t)pagesize; +#endif +} + +/******************************************************************************/ + +uint32_t SST_OS_GetPageSize() +{ + return cached_pagesize; +} + +/******************************************************************************/ + +void* SST_OS_AllocPages(size_t allocBytes) +{ + void* addr; + #if defined(MAP_ANON) && !defined(MAP_ANONYMOUS) + int flags = MAP_SHARED | MAP_ANON; + #else + int flags = MAP_SHARED | MAP_ANONYMOUS; + #endif + + SST_OS_DebugAssert(allocBytes > 0, "Allocating 0 bytes is not allowed"); + + #ifdef MAP_UNINITIALIZED /* Linux only, 2.6.33+, don't zero pages */ + flags |= MAP_UNINITIALIZED; + #endif + + addr = mmap(NULL, allocBytes, PROT_READ | PROT_WRITE, flags, -1, 0); + + if(addr == MAP_FAILED) + return NULL; + + return addr; +} + +/******************************************************************************/ + +int SST_OS_FreePages(void* pageBase, size_t nrBytes) +{ + uintptr_t addr; + uint32_t pageSize; + + SST_OS_DebugAssert(pageBase != NULL, "Base address may not be NULL"); + SST_OS_DebugAssert(nrBytes > 0, "The number of bytes to free may not be zero"); + + addr = (uintptr_t)pageBase; + pageSize = SST_OS_GetPageSize(); + + /* Check if address is aligned to page boundary */ + if(addr & (pageSize-1)) + return -1; + + /* Free the pages */ + return (munmap(pageBase, nrBytes) == 0); +} + +/******************************************************************************/ + +int SST_OS_ProtectPages(void* pageBase, size_t nrBytes, int protectFlags) +{ + uintptr_t addr; + uint32_t pageSize; + int newFlags = 0; + + SST_OS_DebugAssert(pageBase != NULL, "Base address may not be NULL"); + SST_OS_DebugAssert(nrBytes > 0, "The number of bytes to free may not be zero"); + SST_OS_DebugAssert((protectFlags & (~(SST_PROTECT_READ|SST_PROTECT_WRITE|SST_PROTECT_EXEC))) == 0, "Protect flags contain invalid bits"); + + addr = (uintptr_t)pageBase; + pageSize = SST_OS_GetPageSize(); + + /* Check if address is aligned to page boundary */ + if(addr & (pageSize-1)) + return -1; + + if(protectFlags & SST_PROTECT_READ) + newFlags |= PROT_READ; + if(protectFlags & SST_PROTECT_WRITE) + newFlags |= PROT_WRITE; + if(protectFlags & SST_PROTECT_EXEC) + newFlags |= PROT_EXEC; + + return (mprotect(pageBase, nrBytes, newFlags) == 0); +} + diff --git a/libsst-os/SST_SysMem_Win32.c b/libsst-os/SST_SysMem_Win32.c new file mode 100644 index 0000000..7c9b2b1 --- /dev/null +++ b/libsst-os/SST_SysMem_Win32.c @@ -0,0 +1,155 @@ +/* + SST_SysMem_Win32.c + Author: Patrick Baggett <ptbaggett@762studios.com> + Created: 12/23/2011 + + Purpose: + + libsst-os system memory allocation functions for Win32 platforms (Windows 7 or later) + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ + +#include "Win32Private.h" +#include <SST/SST_SysMem.h> +#include <SST/SST_Assert.h> + +static uint32_t cached_pagesize; + +void __libsst_init_pagesize() +{ + SYSTEM_INFO info; + GetNativeSystemInfo(&info); + + cached_pagesize = (uint32_t)info.dwPageSize; +} + +/* Round an allocation of 'amount' bytes to be a multiple of 'pageSize' */ +static size_t roundToPage(uint32_t pageSize, size_t amount) +{ + size_t rounded; + + /* ASSUMPTION: pageSize is a power of two */ + + /* + Algorithm: Round up allocation to the nearest page. + + [1] x & (pageSize-1) = Bytes that are extra parts of a page + [2] x & (~(pageSize-1)) = Bytes that are whole pages. + + Start with [2] bytes. If [1] is non-zero, then add page size. + */ + rounded = amount & (~(pageSize-1)); + if(amount & (pageSize-1)) + rounded += pageSize; + + return rounded; +} + +/*************************************************************************/ + +uint64_t SST_OS_GetMemorySize() +{ + ULONGLONG mem = 0; + + if(GetPhysicallyInstalledSystemMemory(&mem)) + return (uint64_t)mem; + + return 0; +} + +/*************************************************************************/ + +uint32_t SST_OS_GetPageSize() +{ + return cached_pagesize; +} + +/*************************************************************************/ + +void* SST_OS_AllocPages(size_t allocBytes) +{ + SST_OS_DebugAssert(allocBytes > 0, "Allocating 0 bytes is not allowed"); + + return VirtualAllocEx(GetCurrentProcess(), NULL, roundToPage(SST_OS_GetPageSize(), allocBytes), MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); +} + +/*************************************************************************/ + +int SST_OS_FreePages(void* pageBase, size_t nrBytes) +{ + uintptr_t addr; + uint32_t pageSize; + + SST_OS_DebugAssert(pageBase != NULL, "Base address may not be NULL"); + SST_OS_DebugAssert(nrBytes > 0, "The number of bytes to free may not be zero"); + + addr = (uintptr_t)pageBase; + pageSize = SST_OS_GetPageSize(); + + /* Check if address is aligned to page boundary */ + if(addr & (pageSize-1)) + return -1; + + /* Free the pages */ + if(VirtualFreeEx(GetCurrentProcess(), pageBase, roundToPage(pageSize, nrBytes), MEM_DECOMMIT | MEM_RELEASE) != 0) + return 1; + + return 0; +} + +/*************************************************************************/ + +int SST_OS_ProtectPages(void* pageBase, size_t nrBytes, int protectFlags) +{ + uintptr_t addr; + uint32_t pageSize; + DWORD newFlags = PAGE_NOACCESS; + + SST_OS_DebugAssert(pageBase != NULL, "Base address may not be NULL"); + SST_OS_DebugAssert(nrBytes > 0, "The number of bytes to free may not be zero"); + + + addr = (uintptr_t)pageBase; + pageSize = SST_OS_GetPageSize(); + + /* Check if address is aligned to page boundary */ + if(addr & (pageSize-1)) + return -1; + + /* Microsoft doesn't believe in bitfields. This switch brought to you by a poor design decision */ + switch(protectFlags) + { + /* r/o */ + case SST_PROTECT_READ: newFlags = PAGE_READONLY; break; + + /* r/w, w/o */ + case SST_PROTECT_READ | SST_PROTECT_WRITE: + case SST_PROTECT_WRITE: newFlags = PAGE_READWRITE; break; /* Win32 doesn't have w/o */ + + /* x/o */ + case SST_PROTECT_EXEC: newFlags = PAGE_EXECUTE; break; + + /* w/x */ + case SST_PROTECT_WRITE | SST_PROTECT_EXEC: newFlags = PAGE_EXECUTE_READWRITE; break; + + /* r/x */ + case SST_PROTECT_READ | SST_PROTECT_EXEC: newFlags = PAGE_EXECUTE_READ; break; + + /* r/w/x */ + case SST_PROTECT_READ | SST_PROTECT_WRITE | SST_PROTECT_EXEC: newFlags = PAGE_EXECUTE_READWRITE; break; + } + + if(VirtualProtectEx(GetCurrentProcess(), (void*)addr, roundToPage(pageSize, nrBytes), newFlags, NULL) != 0) + return 1; + + return 0; +} + diff --git a/libsst-os/SST_Time_MacOSX.c b/libsst-os/SST_Time_MacOSX.c new file mode 100644 index 0000000..aeb0cac --- /dev/null +++ b/libsst-os/SST_Time_MacOSX.c @@ -0,0 +1,60 @@ +/* + SST_Time_MacOSX.c + Author: Patrick Baggett <ptbaggett@762studios.com> + Created: 5/30/2013 + + Purpose: + + libsst-os timing functions for MacOSX systems + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ + +#include <SST/SST_Time.h> +#include <mach/mach_time.h> + +/******************************************************************************/ + +static mach_timebase_info_data_t info; + +/******************************************************************************/ + +int __libsst_init_time() +{ + return (mach_timebase_info(&info) == KERN_SUCCESS); +} + +/******************************************************************************/ + +static uint64_t absToNsec(uint64_t abstime) +{ + return abstime * info.numer / info.denom; +} + +/******************************************************************************/ + +uint64_t SST_OS_GetMicroTime() +{ + return absToNsec(mach_absolute_time()) / 1000; +} + +/******************************************************************************/ + +uint64_t SST_OS_GetMilliTime() +{ + return absToNsec(mach_absolute_time()) / 1000000; +} + +/******************************************************************************/ + +double SST_OS_GetFloatingTime() +{ + return absToNsec(mach_absolute_time()) / 1000000000.0; +} \ No newline at end of file diff --git a/libsst-os/SST_Time_POSIX.c b/libsst-os/SST_Time_POSIX.c new file mode 100644 index 0000000..877f1b9 --- /dev/null +++ b/libsst-os/SST_Time_POSIX.c @@ -0,0 +1,85 @@ +/* + SST_Time_POSIX.c + Author: Patrick Baggett <ptbaggett@762studios.com> + Created: 5/29/2013 + + Purpose: + + libsst-os timing functions for POSIX systems + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ + +/* + Sadly, MacOS X does not implement clock_gettime(), so it has its own file +*/ + +#include <SST/SST_Time.h> +#include <time.h> + +struct timespec freq; + +static clockid_t timeSource = +#if defined(CLOCK_MONOTONIC_RAW) /* Linux >= 2.6.28 */ + CLOCK_MONOTONIC_RAW; +#else + CLOCK_MONOTONIC; +#endif + +int __libsst_init_time() +{ + struct timespec v; + int clkOk = (clock_gettime(timeSource, &v) > 0); + + if(!clkOk) + { + #if defined(CLOCK_MONOTONIC_RAW) + timeSource = CLOCK_MONOTONIC; + clkOk = (clock_gettime(timeSource, &v) > 0); + if(!clkOk) + #else + timeSource = CLOCK_REALTIME; + #endif + + + if(clock_gettime(timeSource, &v) < 0) + return 0; + } + return 1; +} + +uint64_t SST_OS_GetMicroTime() +{ + struct timespec v; + + clock_gettime(timeSource, &v); + + return (uint64_t)((v.tv_sec * 1000000) + (v.tv_nsec / 1000)); +} + +uint64_t SST_OS_GetMilliTime() /* Not be confused with Miller Time (TM) :D */ +{ + struct timespec v; + + clock_gettime(timeSource, &v); + + return (uint64_t)((v.tv_sec * 1000) + (v.tv_nsec / 1000000)); +} + +double SST_OS_GetFloatingTime() +{ + struct timespec v; + + clock_gettime(timeSource, &v); + + return (double)v.tv_sec + (v.tv_nsec / 1000000000.0); +} + + diff --git a/libsst-os/SST_Time_Win32.c b/libsst-os/SST_Time_Win32.c new file mode 100644 index 0000000..74c2c0f --- /dev/null +++ b/libsst-os/SST_Time_Win32.c @@ -0,0 +1,80 @@ +/* + SST_Time_Win32.c + Author: Patrick Baggett <ptbaggett@762studios.com> + Created: 5/29/2013 + + Purpose: + + libsst-os timing functions for Win32 + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ + +#include <SST/SST_Time.h> +#include <windows.h> + +static LARGE_INTEGER freq; /* Frequency, as 64-bit integer */ +static double dfreq; /* Frequency, as a double value */ + +/* + Quick note about frequencies: + + x86 PCs typically have various sources of timers, but these 3 are the most common: + * RDTSC -- x86 instruction to read a cycle counter, varies per CPU but can be in the low GHz range. + * ACPI -- Advanced Configuration and Power Interface timer, about 3.57 MHz (so, about 280 nanosecond accuracy) + * i8254 -- Intel chip on keyboard, about 1.193 MHz (so, about 838 nanosecond accuracy) +*/ + +int __libsst_init_time() +{ + BOOL ok = QueryPerformanceFrequency(&freq); + if(ok) + dfreq = (double)freq.QuadPart; + + return (int)ok; +} + +uint64_t SST_OS_GetRawTime() +{ + LARGE_INTEGER v; + QueryPerformanceCounter(&v); + + return (uint64_t)v.QuadPart; +} + +uint64_t SST_OS_GetRawFrequency() +{ + return (uint64_t)freq.QuadPart; +} + +uint64_t SST_OS_GetMicroTime() +{ + LARGE_INTEGER v; + QueryPerformanceCounter(&v); + + return (uint64_t)((v.QuadPart * 1000LL * 1000LL) / freq.QuadPart); +} + +uint64_t SST_OS_GetMilliTime() /* Not be confused with Miller Time (TM) :D */ +{ + LARGE_INTEGER v; + QueryPerformanceCounter(&v); + + return (uint64_t)((v.QuadPart * 1000LL) / freq.QuadPart); +} + +double SST_OS_GetFloatingTime() +{ + LARGE_INTEGER v; + QueryPerformanceCounter(&v); + + return (double)v.QuadPart / dfreq; + +} \ No newline at end of file diff --git a/libsst-os/SST_User_POSIX.c b/libsst-os/SST_User_POSIX.c new file mode 100644 index 0000000..db704e9 --- /dev/null +++ b/libsst-os/SST_User_POSIX.c @@ -0,0 +1,152 @@ +/* + SST_User_POSIX.c + Author: Patrick Baggett <ptb1@762studios.com> + Created: 12/23/2011 + + Purpose: + + libsst-os user account information functions for POSIX platforms + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ + +#include <unistd.h> +#include <sys/types.h> +#include <pwd.h> +#include <string.h> + +int __libsst_init_user() { return 1; } + +/******************************************************************************/ + +int SST_OS_GetUserName(char* usernameReturn, int bufferSize) +{ + uid_t euid; + struct passwd pwd; + struct passwd* ptrpwd = NULL; + char buf[1024]; + int len; + + /* Here we using the POSIX '95 extension for reentrant functions */ + euid = geteuid(); + if(getpwuid_r(euid, &pwd, buf, sizeof(buf), &ptrpwd) != 0) + return -1; + + /* getpwuid_r() will return 0 to indicate success, but it does not indicate that a matching + record was found, just that the arguments weren't incorrect. Check if *ptrpwd is still NULL, + which means the record wasn't found. */ + if(ptrpwd == NULL) + return 0; + + len = (int)strlen(pwd.pw_name); + + /* Is the user just querying the length? */ + if(usernameReturn == NULL) + return len; + + + /* Expected case: (more than) enough space -> just do strcpy() */ + if(bufferSize >= len+1) + { + strcpy(usernameReturn, pwd.pw_name); + return len; + } + + /* Exceptional case: less than enough space. Copy 'bufferSize'-1 characters, then add NULL terminator. */ + memcpy(usernameReturn, pwd.pw_name, bufferSize-1); + usernameReturn[bufferSize-1] = 0; + + return len; +} + +/******************************************************************************/ + +int SST_OS_GetUserRealName(char* realnameReturn, int bufferSize) +{ + uid_t euid; + struct passwd pwd; + struct passwd* ptrpwd = NULL; + char buf[1024]; + int len; + + /* Here we using the POSIX '95 extension for reentrant functions */ + euid = geteuid(); + if(getpwuid_r(euid, &pwd, buf, sizeof(buf), &ptrpwd) != 0) + return -1; + + /* getpwuid_r() will return 0 to indicate success, but it does not indicate that a matching + record was found, just that the arguments weren't incorrect. Check if *ptrpwd is still NULL, + which means the record wasn't found. */ + if(ptrpwd == NULL) + return 0; + + len = (int)strlen(pwd.pw_gecos); + + /* Is the user just querying the length? */ + if(realnameReturn == NULL) + return len; + + + /* Expected case: (more than) enough space -> just do strcpy() */ + if(bufferSize >= len+1) + { + strcpy(realnameReturn, pwd.pw_gecos); + return len; + } + + /* Exceptional case: less than enough space. Copy 'bufferSize'-1 characters, then add NULL terminator. */ + memcpy(realnameReturn, pwd.pw_gecos, bufferSize-1); + realnameReturn[bufferSize-1] = 0; + + return len; +} + +/******************************************************************************/ + +int SST_OS_GetUserHomeDirectory(char* homedirReturn, int bufferSize) +{ + uid_t euid; + struct passwd pwd; + struct passwd* ptrpwd = NULL; + char buf[1024]; + int len; + + /* Here we using the POSIX '95 extension for reentrant functions */ + euid = geteuid(); + if(getpwuid_r(euid, &pwd, buf, sizeof(buf), &ptrpwd) != 0) + return -1; + + /* getpwuid_r() will return 0 to indicate success, but it does not indicate that a matching + record was found, just that the arguments weren't incorrect. Check if *ptrpwd is still NULL, + which means the record wasn't found. */ + if(ptrpwd == NULL) + return 0; + + len = (int)strlen(pwd.pw_dir); + + /* Is the user just querying the length? */ + if(homedirReturn == NULL) + return len; + + + /* Expected case: (more than) enough space -> just do strcpy() */ + if(bufferSize >= len+1) + { + strcpy(homedirReturn, pwd.pw_dir); + return len; + } + + /* Exceptional case: less than enough space. Copy 'bufferSize'-1 characters, then add NULL terminator. */ + memcpy(homedirReturn, pwd.pw_dir, bufferSize-1); + homedirReturn[bufferSize-1] = 0; + + return len; +} + diff --git a/libsst-os/SST_User_Win32.c b/libsst-os/SST_User_Win32.c new file mode 100644 index 0000000..0e4e27c --- /dev/null +++ b/libsst-os/SST_User_Win32.c @@ -0,0 +1,197 @@ +/* + SST_User_Win32.c + Author: Patrick Baggett <ptbaggett@762studios.com> + Created: 12/23/2011 + + Purpose: + + libsst-os user information functions for Win32 systems (Windows 7 or later) + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ + +#define _CRT_SECURE_NO_WARNINGS /* strncpy() isn't deprecated, stupid programming is */ + +#include "Win32Private.h" +#include <userenv.h> +#include <SST/SST_User.h> +#include <malloc.h> //_alloca() on Win32 + +static HMODULE advapi32_dll = NULL; +static BOOL (WINAPI * pfOpenProcessToken)(_In_ HANDLE ProcessHandle, _In_ DWORD DesiredAccess, _Out_ PHANDLE TokenHandle) = NULL; +static BOOL (WINAPI * pfGetUserNameA)(_Out_ LPSTR lpBuffer, _Inout_ LPDWORD lpnSize) = NULL; + +static HMODULE userenv_dll = NULL; +static BOOL (WINAPI * pfGetUserProfileDirectoryA)(_In_ HANDLE hToken,_Out_opt_ LPSTR lpProfileDir, _Inout_ LPDWORD lpcchSize) = NULL; + +void libsst_free_user() +{ + pfOpenProcessToken = NULL; + pfGetUserNameA = NULL; + pfGetUserProfileDirectoryA = NULL; + + if(advapi32_dll) + { + FreeLibrary(advapi32_dll); + advapi32_dll = NULL; + } + + if(userenv_dll) + { + FreeLibrary(userenv_dll); + userenv_dll = NULL; + } +} + +int __libsst_init_user() +{ + advapi32_dll = LoadLibraryA("advapi32.dll"); + if(advapi32_dll == NULL) + return 0; + + userenv_dll = LoadLibraryA("userenv.dll"); + if(userenv_dll == NULL) + { + FreeLibrary(advapi32_dll); + return 0; + } + + /* Load all symbols */ + /* advapi32.dll */ + pfOpenProcessToken = (BOOL (WINAPI*)(HANDLE,DWORD,PHANDLE))GetProcAddress(advapi32_dll, "OpenProcessToken"); + pfGetUserNameA = (BOOL (WINAPI*)(LPSTR, LPDWORD))GetProcAddress(advapi32_dll, "GetUserNameA"); + + /* userenv.dll */ + pfGetUserProfileDirectoryA = (BOOL (WINAPI*)(HANDLE, LPSTR,LPDWORD))GetProcAddress(userenv_dll, "GetUserProfileDirectoryA"); + + /* Verify all loaded */ + if(pfOpenProcessToken == NULL || pfGetUserNameA == NULL || pfGetUserProfileDirectoryA == NULL) + { + libsst_free_user(); + return 0; + } + + return 1; +} + + + +int SST_OS_GetUserName(char* usernameReturn, int bufferSize) +{ + DWORD size; + + /* User is querying the username size */ + if(usernameReturn == NULL) + { + char dummy[1]; + + /* This *should* generate the insufficient buffer error. When it does, it returns + the correct size in 'size'. */ + size = sizeof(dummy); + pfGetUserNameA(dummy, &size); + + /* Make sure it really did. */ + if(GetLastError() == ERROR_INSUFFICIENT_BUFFER) + return (int)size-1; + + /* Some other error :( */ + return -1; + } + + size = (DWORD)bufferSize; + if(pfGetUserNameA(usernameReturn, &size) == FALSE) + { + /* GetUserName() returns false on insufficient space, but that is OK. + However, errors for any other reason isn't OK, so catch them here. */ + if(GetLastError() != ERROR_INSUFFICIENT_BUFFER) + return -2; + } + + return (int)(size-1); +} + +int SST_OS_GetUserRealName(char* realnameReturn, int bufferSize) +{ + /* TODO: better implementation here plz */ + return SST_OS_GetUserName(realnameReturn, bufferSize); +} + +int SST_OS_GetUserHomeDirectory(char* homedirReturn, int bufferSize) +{ + HANDLE hToken = NULL; + DWORD size; + int retcode; + + #ifdef _DEBUG + if(homedirReturn && bufferSize < 0) + return -1; + #endif + + if(pfOpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken) == FALSE) + return -2; + + /* User is querying the username size */ + if(homedirReturn == NULL) + { + char dummy[1]; /* See comment block */ + size = 0; + + /* + Bug in GetUserProfileDirectoryA() impl: NULL for 2nd param should be allowed but isn't. + + MSDN: "If the buffer specified by lpProfileDir is not large enough or lpProfileDir is NULL, the function fails + and this parameter receives the necessary buffer size, including the terminating null character." + + However, in practice, when I set the second param to NULL, `size` remains zero. + */ + + + pfGetUserProfileDirectoryA(hToken, dummy, &size); + + if(size == 0) + retcode = -3; + else + retcode = (int)(size-1); + } + else /* Actually getting the size */ + { + /* Set the size to the user provided size and query*/ + size = (DWORD)bufferSize; + if(pfGetUserProfileDirectoryA(hToken, homedirReturn, &size) == FALSE) + { + + /* This gets tricky: the function doesn't write partial paths, so we have to first detect + if the error was due to buffer size */ + if(GetLastError() == ERROR_INSUFFICIENT_BUFFER) + { + char* tmpbuf = (char*)_alloca(size); + + /* OK, now we've ensured we have a correctly-sized buffer, so call it again. */ + if(pfGetUserProfileDirectoryA(hToken, tmpbuf, &size) == FALSE) + { + /* Failed second time around, doh -- give up */ + retcode = -4; + } + else + { + /* Success -- copy n-1 characters, then null terminate */ + strncpy(homedirReturn, tmpbuf, bufferSize-1); + homedirReturn[bufferSize-1] = 0; + retcode = (int)size-1; + } + } + } + else /* Success */ + retcode = (int)(size-1); + } + + CloseHandle(hToken); + return retcode; +} \ No newline at end of file diff --git a/libsst-os/Win32Private.h b/libsst-os/Win32Private.h new file mode 100644 index 0000000..a85d610 --- /dev/null +++ b/libsst-os/Win32Private.h @@ -0,0 +1,168 @@ +/* + Win32Private.h + Author: Patrick Baggett <ptbaggett@762studios.com> + Created: 12/23/2011 + + Purpose: + + Private data structures for Win32 implementation of libsst-os. Not to be distributed + as part of public SDK headers. + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ + +#pragma once + +#ifndef _WIN32PRIVATE_H +#define _WIN32PRIVATE_H + +#define _WIN32_WINNT 0x0601 /* Windows 7 or later */ +#include <windows.h> +#include <pstdint.h> + +#if defined(__GNUC__) /* Missing Windows 7 API on various GCC targets, remove when is fixed. */ +typedef ULONG_PTR KAFFINITY; + +typedef enum _LOGICAL_PROCESSOR_RELATIONSHIP { + RelationProcessorCore, + RelationNumaNode, + RelationCache, + RelationProcessorPackage, + RelationGroup, + RelationAll = 0xffff +} LOGICAL_PROCESSOR_RELATIONSHIP; + +typedef enum _PROCESSOR_CACHE_TYPE { + CacheUnified, + CacheInstruction, + CacheData, + CacheTrace +} PROCESSOR_CACHE_TYPE; + +typedef struct _CACHE_DESCRIPTOR { + BYTE Level; + BYTE Associativity; + WORD LineSize; + DWORD Size; + PROCESSOR_CACHE_TYPE Type; +} CACHE_DESCRIPTOR, *PCACHE_DESCRIPTOR; + +typedef struct _GROUP_AFFINITY { + KAFFINITY Mask; + WORD Group; + WORD Reserved[3]; +} GROUP_AFFINITY, *PGROUP_AFFINITY; + +typedef struct _PROCESSOR_NUMBER { + WORD Group; + BYTE Number; + BYTE Reserved; +} PROCESSOR_NUMBER, *PPROCESSOR_NUMBER; + +typedef struct _PROCESSOR_GROUP_INFO { + BYTE MaximumProcessorCount; + BYTE ActiveProcessorCount; + BYTE Reserved[38]; + KAFFINITY ActiveProcessorMask; +} PROCESSOR_GROUP_INFO, *PPROCESSOR_GROUP_INFO; + +typedef struct _PROCESSOR_RELATIONSHIP { + BYTE Flags; + BYTE Reserved[21]; + WORD GroupCount; + GROUP_AFFINITY GroupMask[ANYSIZE_ARRAY]; +} PROCESSOR_RELATIONSHIP, *PPROCESSOR_RELATIONSHIP; + +typedef struct _NUMA_NODE_RELATIONSHIP { + DWORD NodeNumber; + BYTE Reserved[20]; + GROUP_AFFINITY GroupMask; +} NUMA_NODE_RELATIONSHIP, *PNUMA_NODE_RELATIONSHIP; + +typedef struct _CACHE_RELATIONSHIP { + BYTE Level; + BYTE Associativity; + WORD LineSize; + DWORD CacheSize; + PROCESSOR_CACHE_TYPE Type; + BYTE Reserved[20]; + GROUP_AFFINITY GroupMask; +} CACHE_RELATIONSHIP, *PCACHE_RELATIONSHIP; + +typedef struct _GROUP_RELATIONSHIP { + WORD MaximumGroupCount; + WORD ActiveGroupCount; + BYTE Reserved[20]; + PROCESSOR_GROUP_INFO GroupInfo[ANYSIZE_ARRAY]; +} GROUP_RELATIONSHIP, *PGROUP_RELATIONSHIP; + +typedef struct _SYSTEM_LOGICAL_PROCESSOR_INFORMATION { + ULONG_PTR ProcessorMask; + LOGICAL_PROCESSOR_RELATIONSHIP Relationship; + union { + struct { + BYTE Flags; + } ProcessorCore; + struct { + DWORD NodeNumber; + } NumaNode; + CACHE_DESCRIPTOR Cache; + ULONGLONG Reserved[2]; + }; +} SYSTEM_LOGICAL_PROCESSOR_INFORMATION, *PSYSTEM_LOGICAL_PROCESSOR_INFORMATION; + +typedef struct _SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX { + LOGICAL_PROCESSOR_RELATIONSHIP Relationship; + DWORD Size; + union { + PROCESSOR_RELATIONSHIP Processor; + NUMA_NODE_RELATIONSHIP NumaNode; + CACHE_RELATIONSHIP Cache; + GROUP_RELATIONSHIP Group; + }; +} SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX, *PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX; + +BOOL WINAPI GetLogicalProcessorInformationEx( + LOGICAL_PROCESSOR_RELATIONSHIP RelationshipType, + PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX Buffer, + PDWORD ReturnedLength); + +BOOL WINAPI GetLogicalProcessorInformation(PSYSTEM_LOGICAL_PROCESSOR_INFORMATION Buffer, PDWORD ReturnLength); + + +BOOL WINAPI SetThreadIdealProcessorEx(HANDLE hThread, PPROCESSOR_NUMBER lpIdealProcessor, PPROCESSOR_NUMBER lpPreviousIdealProcessor); + +#endif + +/*************************************************************************/ +typedef struct SST_File_Win32 +{ + HANDLE hFile; /* Handle from CreateFile() */ + HANDLE hMap; /* Handle from CreateFileMapping() */ + int isAsync; /* Is this file in async mode */ + DWORD accessFlags; /* Flags for access used in CreateFileA() */ + +#ifdef _DEBUG + int nrMmaps; /* Number of outstanding memory maps */ +#endif +} SST_File_Win32; + +typedef struct SST_MemoryMap_Win32 +{ + uint64_t offset; /* Offset parameter as given to SST_OS_MmapCreate() */ + size_t len; /* Length parameter as given to SST_OS_MmapCreate() */ + void* base; /* Returned base address from SST_OS_MmapCreate() */ + +#ifdef _DEBUG + SST_File_Win32* owner; /* File that created this memory map */ +#endif +} SST_MemoryMap_Win32; + +#endif diff --git a/libsst-os/libsst-os.vcxproj b/libsst-os/libsst-os.vcxproj new file mode 100644 index 0000000..a8d15e1 --- /dev/null +++ b/libsst-os/libsst-os.vcxproj @@ -0,0 +1,200 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup Label="ProjectConfigurations"> + <ProjectConfiguration Include="Debug|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectGuid>{4BAC6D63-C2E8-43F7-87EA-EF953CBFDDD3}</ProjectGuid> + <RootNamespace>libsstos</RootNamespace> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> + <ConfigurationType>StaticLibrary</ConfigurationType> + <PlatformToolset>v110</PlatformToolset> + <CharacterSet>MultiByte</CharacterSet> + <WholeProgramOptimization>true</WholeProgramOptimization> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> + <ConfigurationType>StaticLibrary</ConfigurationType> + <PlatformToolset>v110</PlatformToolset> + <CharacterSet>MultiByte</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> + <ConfigurationType>StaticLibrary</ConfigurationType> + <PlatformToolset>v110</PlatformToolset> + <CharacterSet>MultiByte</CharacterSet> + <WholeProgramOptimization>true</WholeProgramOptimization> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> + <ConfigurationType>StaticLibrary</ConfigurationType> + <PlatformToolset>v110</PlatformToolset> + <CharacterSet>MultiByte</CharacterSet> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <ImportGroup Label="ExtensionSettings"> + <Import Project="$(VCTargetsPath)\BuildCustomizations\vsyasm.props" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <PropertyGroup Label="UserMacros" /> + <PropertyGroup> + <_ProjectFileVersion>11.0.50727.1</_ProjectFileVersion> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <OutDir>$(SolutionDir)\Lib\x86\</OutDir> + <IntDir>$(SolutionDir)Intermediate\$(Configuration)\$(Platform)\$(ProjectName)\</IntDir> + <TargetName>$(ProjectName)-debug</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <OutDir>$(SolutionDir)\Lib\x86\</OutDir> + <IntDir>$(SolutionDir)Intermediate\$(Configuration)\$(Platform)\$(ProjectName)\</IntDir> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <OutDir>$(SolutionDir)\Lib\x64\</OutDir> + <IntDir>$(SolutionDir)Intermediate\$(Configuration)\$(Platform)\$(ProjectName)\</IntDir> + <TargetName>$(ProjectName)-debug</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <OutDir>$(SolutionDir)\Lib\x64\</OutDir> + <IntDir>$(SolutionDir)Intermediate\$(Configuration)\$(Platform)\$(ProjectName)\</IntDir> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <Optimization>Disabled</Optimization> + <AdditionalIncludeDirectories>$(SolutionDir)Lib\Include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <MinimalRebuild>false</MinimalRebuild> + <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> + <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> + <WarningLevel>Level4</WarningLevel> + <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> + <DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings> + <MultiProcessorCompilation>true</MultiProcessorCompilation> + </ClCompile> + <Lib /> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <Optimization>MaxSpeed</Optimization> + <IntrinsicFunctions>true</IntrinsicFunctions> + <AdditionalIncludeDirectories>$(SolutionDir)Lib\Include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> + <FunctionLevelLinking>true</FunctionLevelLinking> + <WarningLevel>Level4</WarningLevel> + <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> + <PreprocessorDefinitions>SST_ASSERT_NODEBUG=1;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <MultiProcessorCompilation>true</MultiProcessorCompilation> + </ClCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Midl> + <TargetEnvironment>X64</TargetEnvironment> + </Midl> + <ClCompile> + <Optimization>Disabled</Optimization> + <AdditionalIncludeDirectories>$(SolutionDir)Lib\Include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <MinimalRebuild>false</MinimalRebuild> + <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> + <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> + <WarningLevel>Level4</WarningLevel> + <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> + <MultiProcessorCompilation>true</MultiProcessorCompilation> + </ClCompile> + <Lib /> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Midl> + <TargetEnvironment>X64</TargetEnvironment> + </Midl> + <ClCompile> + <Optimization>MaxSpeed</Optimization> + <IntrinsicFunctions>true</IntrinsicFunctions> + <AdditionalIncludeDirectories>$(SolutionDir)Lib\Include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> + <FunctionLevelLinking>true</FunctionLevelLinking> + <WarningLevel>Level4</WarningLevel> + <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> + <PreprocessorDefinitions>SST_ASSERT_NODEBUG=1;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <MultiProcessorCompilation>true</MultiProcessorCompilation> + </ClCompile> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="SST_Alloc.c" /> + <ClCompile Include="SST_Assert.c" /> + <ClCompile Include="SST_Assert_Win32.c" /> + <ClCompile Include="SST_CPU_Win32.c" /> + <ClCompile Include="SST_DynLib_Win32.c" /> + <ClCompile Include="SST_Endian.c" /> + <ClCompile Include="SST_File_Win32.c" /> + <ClCompile Include="SST_FileSys_Win32.c" /> + <ClCompile Include="SST_Mmap_Win32.c" /> + <ClCompile Include="SST_OSInit.c" /> + <ClCompile Include="SST_SafeArithmetic.c" /> + <ClCompile Include="SST_SysMem_Win32.c" /> + <ClCompile Include="SST_Time_Win32.c" /> + <ClCompile Include="SST_User_Win32.c" /> + </ItemGroup> + <ItemGroup> + <YASM Include="SST_CPUCache_x86-64-win64.asm"> + <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> + <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> + </YASM> + <YASM Include="SST_CPUCache_x86.asm"> + <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild> + <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild> + </YASM> + </ItemGroup> + <ItemGroup> + <ClInclude Include="..\Lib\Include\SST\SST_Time.h" /> + <ClInclude Include="Win32Private.h" /> + <ClInclude Include="..\Lib\Include\SST\SST_Alloc.h" /> + <ClInclude Include="..\Lib\Include\SST\SST_Assert.h" /> + <ClInclude Include="..\Lib\Include\SST\SST_Build.h" /> + <ClInclude Include="..\Lib\Include\SST\SST_CPU.h" /> + <ClInclude Include="..\Lib\Include\SST\SST_CPUCache.h" /> + <ClInclude Include="..\Lib\Include\SST\SST_DynLib.h" /> + <ClInclude Include="..\Lib\Include\SST\SST_Endian.h" /> + <ClInclude Include="..\Lib\Include\SST\SST_File.h" /> + <ClInclude Include="..\Lib\Include\SST\SST_FileSys.h" /> + <ClInclude Include="..\Lib\Include\SST\SST_Mmap.h" /> + <ClInclude Include="..\Lib\Include\SST\SST_OS.h" /> + <ClInclude Include="..\Lib\Include\SST\SST_SafeArithmetic.h" /> + <ClInclude Include="..\Lib\Include\SST\SST_SysMem.h" /> + <ClInclude Include="..\Lib\Include\SST\SST_User.h" /> + </ItemGroup> + <ItemGroup> + <ProjectReference Include="..\libsst-atomic\libsst-atomic.vcxproj"> + <Project>{43ed481f-c4a3-40ed-81a3-46c43dc4eb1e}</Project> + </ProjectReference> + </ItemGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> + <ImportGroup Label="ExtensionTargets"> + <Import Project="$(VCTargetsPath)\BuildCustomizations\vsyasm.targets" /> + </ImportGroup> +</Project> \ No newline at end of file diff --git a/libsst-os/libsst-os.vcxproj.filters b/libsst-os/libsst-os.vcxproj.filters new file mode 100644 index 0000000..9d8b96f --- /dev/null +++ b/libsst-os/libsst-os.vcxproj.filters @@ -0,0 +1,115 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup> + <Filter Include="Source Files"> + <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier> + <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions> + </Filter> + <Filter Include="Header Files"> + <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier> + <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> + </Filter> + </ItemGroup> + <ItemGroup> + <ClCompile Include="SST_Alloc.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="SST_Assert.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="SST_Assert_Win32.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="SST_CPU_Win32.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="SST_DynLib_Win32.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="SST_Endian.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="SST_File_Win32.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="SST_FileSys_Win32.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="SST_Mmap_Win32.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="SST_SafeArithmetic.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="SST_SysMem_Win32.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="SST_User_Win32.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="SST_Time_Win32.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="SST_OSInit.c"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> + <ItemGroup> + <YASM Include="SST_CPUCache_x86-64-win64.asm"> + <Filter>Source Files</Filter> + </YASM> + <YASM Include="SST_CPUCache_x86.asm"> + <Filter>Source Files</Filter> + </YASM> + </ItemGroup> + <ItemGroup> + <ClInclude Include="Win32Private.h"> + <Filter>Source Files</Filter> + </ClInclude> + <ClInclude Include="..\Lib\Include\SST\SST_Alloc.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\Lib\Include\SST\SST_Assert.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\Lib\Include\SST\SST_Build.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\Lib\Include\SST\SST_CPU.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\Lib\Include\SST\SST_CPUCache.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\Lib\Include\SST\SST_DynLib.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\Lib\Include\SST\SST_Endian.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\Lib\Include\SST\SST_File.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\Lib\Include\SST\SST_FileSys.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\Lib\Include\SST\SST_Mmap.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\Lib\Include\SST\SST_OS.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\Lib\Include\SST\SST_SafeArithmetic.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\Lib\Include\SST\SST_SysMem.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\Lib\Include\SST\SST_User.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\Lib\Include\SST\SST_Time.h"> + <Filter>Header Files</Filter> + </ClInclude> + </ItemGroup> +</Project> \ No newline at end of file diff --git a/libsst-os/obj/x86-64/release/SST_Alloc.o b/libsst-os/obj/x86-64/release/SST_Alloc.o new file mode 100644 index 0000000000000000000000000000000000000000..44f6e53ee0b978600a6a05c17b5692f485172c66 GIT binary patch literal 3072 zcmb<-^>JfjWMqH=Mg}_u1P><4z;J*A!FB*M9T<2SxEMk`I-h!U*8cG5EdAio?fPRE zNY3MX=?9O_3m&ZpO4&eyua!KyLw|U5yMFNK<zWJepeWNk=+Sv1_AuC}<~I%=owX-C zI!h0DG}j(rDB<#GtUd6bfq|inYX`{emva~x7(BXN4|p`cVD#v8eF0`GyT0&fJy609 zR`R;WqdW8jSe)^KN9XYuAblR4t{*&_Yd<iQLKTI3bcceRe87Y80@y5&8J(^Vz|ORE zeNf5)F##;{pz{z&T=P)pg$~#I9^I}Fz*;(8fADW}z26(~ALOYH0g%K=m`4;mI%`3$ zdjV4lQp3NEp~Lk%|2Eg}9^Y?xFuH<5<p<1-6HxR*!n8B=g~#y&|NsC0j|eks*B`|? zjyn?>7#JMEKHdrPAy|GNh_xR?fPD>?eJug9*@J(*>j#hS&=($^*I*VBW#0=AYu67T z`|^pkPZ|_fAp2f;fWz$vij^S8!EtbKNW5cCPJXgpGFZ&FG^Zr9ASW|9u_QA;Pa(f7 zwJ0qozg!_RPa!uoH@~P-ArYh+EDO>A((fM}ADoz$>X?(6o|l^93swM<17Rfjpj4=g zyR);Ef<|akX<kXGf~lT~o`J4eDVS$iXK1EpV4`QH2@zK?GB7kVFf*`Z5CIv+z`(#* z6~w?;A;2ij!_F~*k%2*m0fIr&-XOw}PoRy-nU{^pjfb5BB4+~<XJBAB38LZhN8s`? zAaMo;2CzDqd^uPeY<>+?z5qnS<e9R;3PARQas)`K7(~G3^T6^TA#50w$5|LYf-)9{ zG&9x`fPsOTff++BNPwAv1w>(BW(HOaF<wv@GO#j0$`A$yNvH}nsCWXDFASwY6f*-m zh{C|k3`m6%k}NX=8xjw~v}a&o5JK`7IIb8N82q8)Fg`er7#J8*7#J7?AX-t#Y^Zt> zPyoW>jDdln4u|??sQLh?dT<;vFff4P44e5|q3RDn)q~@dfq~%!4)Ym62^^Mz;^PB? zTth-4<K062oI^bQ{o>>Gj19~U8E{CLgLV4{$Ahy@KuHk_AD)$RA^8Sm6HIMtid#`? zDnlBGfQn;gL8wGfX<kWYZmMH(acWVCXKq0b%odOiSf(t3X3nM1&}L#_U;w3+KcJHD z|NsA<(C`3>^D{6oz{H!N;#>?2;M4|7SM6xxP-7W-(8OVJFcD4M7OG)3R2*clAd<bi zki>bA#6LmBVeWyY=kI9ZP~#c?pozoW!w9mFfq?;L4$M8=P;n52>>gc^00RR9hyvvu zSokPFEdq&yFq8|=e;_dshNXX)dqH9#3`^$?P>mol5Qe4a1!&^1bjzSuT$x*vn8cu0 zTv7y~GhnQu)SN`UlGKV42ECNTl0*i*q~c-*y`p>wCpkYiH#M(>K`$@ABvsGdFI2a< zBr!RgK@Y4gH6uQ)C^0t`YAwYSD11OsfL>z2(vdO9vq-jp)FN>iq!}2%r5{W^Ol|_y zKv+0&gUdGtc!?zeRR}5fKxHdb07@03*$Wj$D#0KkIt&mq(Mx7x^&3Lng>GE~Q~*}~ zKy1S-6D^_o4PXkO^k=AkQz#!s!NLzlJ3;ls<YBZ1x`&_=Fnv%iLpW4F)H;|j157`- z0R$I?gcTB(AqYqOJ%Cm@6;Q>X_yg58APf?M#UCgSVsmN)R3WI122u~h=<Wyc(cKPG q`v7X_1CRm+1_n?W19JmN9%er$17_L*$sd4Ly%#_nBn&kUE&>2NC+v6t literal 0 HcmV?d00001 diff --git a/libsst-os/obj/x86-64/release/SST_Assert.o b/libsst-os/obj/x86-64/release/SST_Assert.o new file mode 100644 index 0000000000000000000000000000000000000000..dc52ce72f641d29fc39b82cb99dfc145d91db5b1 GIT binary patch literal 1824 zcmb<-^>JfjWMqH=Mg}_u1P><4z@Wf_U^{@B4h%dDoD88JoliYFYkzojmVWT)cKzYe z$qJJ7=yv@8Wlo4aOq3#!HU<U;cV}lS1&z?8(!7#V1yel}Jp)~{QZUc3&d^NHz(mhX z6C$o)WMF7!U}j(m(kTKW7#J8BtAZF9D+Cy&dDuB7FfuU6FhDR!S`|b%@(HvtIrFk5 z@UU}0<!nIW3=9m|<e^d+6ex^X7(V{TkYHe7V8$APAaQ1F${Cm$kOCJ;1v3L15)Z*- zW?)BfkXXzN;IKy$VPN26U|<kLG9Tn;kOFn6IE)XYU7+FuAVmxe3^4I{sJH~0cpU=+ zgAkH`!C}b2z%Uys4&%dUhT!0kc*o-6)S?o-WQOA6lK7O=q|)^GM6ghNMq*w{PHGWO ziTK2#bg*PmX<kWYZYnl?*rmWaL6-Xm#|NjDxPWYhxWfZ#Cqgm^VmPWa#N)ycih&6l zHh=y@fE<!ICj$cmOxyxVoC`_Z8A+TQNn8O*9ApQS%K*u93}Aaf;_&d)E3V8fNlaqU zD=sO5&>1jRQEE=2UP)?234>lrVo4%{UQ%%}gI;oeZf<H`34>l<eo3mHyI-hoaY<rw zHiI5md1^*{T2W$dD$HI=X^?+Fc?CTs!~ElgW&ubovXC?b132}<)WhTqpjjyaDgX*w zkX~4Ng{4z9P?-SElTd|FstZb^Qy?>t#dM(Y47Cm}H37;3`47qjQ!x9%90mpkL#X`* zFaanH({Bpp!zh^jFxm>LA0`i@kHQ#eG)x~%*dMANlxARJAo>J|U|?W~fYLAu-Tk2W z0hLbZ;XeTyATWP{!XH#B!SutzUl2>!gX}s0)gKAsAYpX(gZSuf2PszoNiZ-l1VCv} k9s=17!XSB={h+)EwF)E*#|2PBcfmy<45)Ds4g&)N07c))3;+NC literal 0 HcmV?d00001 diff --git a/libsst-os/obj/x86-64/release/SST_Assert_Generic.o b/libsst-os/obj/x86-64/release/SST_Assert_Generic.o new file mode 100644 index 0000000000000000000000000000000000000000..d77083b2be2adc22a8fb5ea1540f5da165f9c204 GIT binary patch literal 2600 zcmb<-^>JfjWMqH=Mg}_u1P><4!0>_%!FB*M9T<2SxEMk`I-hzpzcJ{n{o~PD`oW_! z^o2*K?*pGs*BdUKzCW64|1gvWdvvpcw0N{0D3OD)yLrJv-5~YnJUXxcztDQ1RL7&c z^n*vY?~U%zA0FMV4?H_Rcyu1y4^p`UM7)3#6J9e;IC&Uqy8zU7ux*ww8?f5;!J`vy zn-JJwbTdI#FffE<q$(s96y#(kCzfR9=P6_)7Aq8`CMIX3rYIyT6qV+cWag$SBo-H^ z7J=o{5;Jp3i&7O8LNYRo6>?J(^NJM`6^c`fGV@D|6$*;-lX6mX!KUOVCzlo#fsDyZ zQ7Fks1xcnCCFUyRrKYA7E0p9bB<JK8r|NNW1r+6jByv-W6g>0N@~ybI+%j`g6_iwq zm2?zxGV@XuG*nYG6*BV_(n|A^!Ol=pE!NOf(&OTCOU%qkO;JeB&r8V!$ykB4adAO> zM-Tt$C?rBXh#Zb+o@8KfcXqZ?&<IT`%_}KYFx4~BGtf0F1@jE+49)ZmO!Uk&A>s-~ z28Lz^W(JlZKZt+`1_lPksvri&3IRrG9(Ilij0_Ai3=j;Gt^*N{d;)Du&b(|)l|1Ym z5IGx=I0FMi2#AKu`-9~{Lf9}UPp~k2{EtnJ8EcMVU|?oo#-^NsnSlj|I5?YN$T2gp zV~BwSm>D=g6b5EyK+3F8Suq9%1|cMOg2RS^fkB^vfk6PO2AT50A)bjtya0!I8Pr~w zec&)>U|^VvLp?)qa7er(I9tWLr{<*=WhUz-g9ZJA<AWgC4kGQDTad$0TwD?l&5ZGo z%ov}Mn3s~1T7*X`KCvjBp`a);uOy8jF)6>O1gH6a`Jjx)P*7S@3=JF&D9yyczyQij zfBr*&2@Y{<BynyA1_qe=RH!(}4CGkPhl+#D=Rs0mf+P+qIbr5ZLlOs>1ruL{LwqHY zII?^8LB&C4fZX!{%0CRHLGIy4a?c4Qab))>Ac=$YK)DQ%I)i}$BnHB;^uVB3T$x*v zn8cu0Tv7y~GhnQu)SN`UlGKV42ECNTl0*i*q~c-*y`p>wCpkYiH#M(>K`$@ABvsGd zFI2a<Br!RgK@Y4gH6uQ)C@~in%rIw=O@sUeDg)4S7R+Cl&`buYMHZ4~U;yWOn0lC; z0VuE;7#I|w8bEOZV#0E^1XQ6KsH|fEl_^jGC?y0^3}quz=)yV-4B*lNy+k5bzai9q zP~0KgBLTH214_f>VD5+UL4`I*i2+OiN;g0aG==hE6i6+I4Wpf)_JhQb@m8pQWHAsM zrVqph;c%#abmcps0udlZNEqGyK{(<s0Gc3R{sP4xNG}M3jDy9WAeOiT$u~gtCxSRg z7~TCKKGdm5su&mqpb^>tQoz8#04g&$p>YjT2(up~22~0YhT{p)s%REm1j2wC2jMU< GFaQ8uf~PeA literal 0 HcmV?d00001 diff --git a/libsst-os/obj/x86-64/release/SST_CPUCache_x86-64.o b/libsst-os/obj/x86-64/release/SST_CPUCache_x86-64.o new file mode 100644 index 0000000000000000000000000000000000000000..cee7a08a7c27827b9c9a324e91f5109262de6394 GIT binary patch literal 800 zcmb<-^>JfjWMqH=Mg}_u1P><4!0-S`&;cy$z`)AD$Pm1Pje((oe~}0Owu8}!Uo#x$ zU-#kgi)a7;|L0$4>A`r=L-UYF^G}BQkB1o;81za~D@qvjic5-05|bG8iYs#=bOuxe zWNvV9NW61EsB>a+MrwS8g_*9IiC$uHE(1v1KRDh!wFE5XlbM$qoLQ9$6L-rgEzWRp z4ob{Rhl_dUl_ln6rX-f6dZJ1MSLP*yO#xYm9fQ2f!tn7wc3Bn%DXbDK3<6lhnHg9x zL?sy*7zD708$!iJ(R8>%#re?0<DlY#XyVl3iZd`UFk>++2P&orrEyX0IP_0|YRHGu zxF~)G1_mZ<lAs7;U|_fbl>@0^Wnf_7fbu1vG)Nf;vqAYV3X+By7_?vlP#Qh{000C} AZ2$lO literal 0 HcmV?d00001 diff --git a/libsst-os/obj/x86-64/release/SST_CPU_POSIX.o b/libsst-os/obj/x86-64/release/SST_CPU_POSIX.o new file mode 100644 index 0000000000000000000000000000000000000000..fd5d09452dcc7d98484e65e42f789d449bbb1ab1 GIT binary patch literal 2648 zcmb<-^>JfjWMqH=Mg}_u1P><4z#zenU^{@B4h*~uTnwQeolkdw__2r4nEOK*7#Ln4 zq&jQ=cyyM2KvL|{{6@f|v-U@4=@*aY+8+$1Iv(AuAPpX^2TJ5&>~2x8Q0KM%Ao~A> z)&r$1XI?X&0ULA@Y%A3a>a6`UA@;CyK&V1)VsW-YZepcEUVe!}QmTSqsE-c=gS)e{ zm4ZfSQfXdEse-AViJpP3St*!jSZ8RaXJDddrU?;OFfuSSGcYr-1UZ_4fk6aHGgbvL zFjfdKO7pODOkiYSkYRvekTf@laO4wcV{+zYbK_y>fXdl`#2FYEaLLC&<pn@AOusim ze+@{Sfq_8?M8o8L5%P0D;tUK7o*)_~&*TDD0CL|RkT@RsJ5YHp5DnAs3f2x1!HPj? zjD_Lje{7P>SW_Sa12Y3NHsuV=3@kXr!Kn#Dj+p@|F(b(`Gk`)INdU@ZW?+M|5R@P| zJVCyIh=JpVfq_8_Dh}hrXm_Z%7(_V(IIb8N7?K$n;B2TAn97E#R|E5)amT>G&;=E@ zfQp0TjDdk+0S<F^;t;<EHK!5HoHtPMQ&4emoPyZF!6EU^0ip2${=uFRddUnRzJGAM zduoYaX>L+#k#j((b4F%CF@{7yMrCnka$=5iKq#i9PkuUFuDG%|IX^EAW`J*E0ZeO1 zK0+N#+C8<zIUv+AEiE%Iv!s%txVR)fB{iuuJwCCxIJKxGJ|i(NB`38Ar$l^WQ98`5 zU{tf9UJFhw2`EZUOD!r&O>qtg1qA{Fg93zNU}9ik;9+23`12nE0+Gb|k;G$hh^HWl zgVF-boE)e)DBO`#?<}Y|$X;agm*Eg!izJS0{#K|sy7|cd0@(po#sDen8NmJpiNn%! z0#pG=41{6nx&cibmVQC$6C?#v3&ODUdjKTJfG{7H9v`5I!_p&zUU6k^Nn#R%UU5kg zgwBAmic)hD^-5AJN*MG~5=#;p^pc8;8T5+sA)Ms=+}zZ>5(d4z{E}2XcfU~G;*!MV zYz95Bw$zOHw4%h^RH(HSQ=sq!l@9172P{0VpxFRYi!3C~zyL1QVCrFV2GB%t11bQD z50GA1$t3|52ZcLG9KFO80SQ9YAXDhVIt&cp(vV#Jh71hgQXCZ5$o9bOmqZqXsznw8 z)tewU86XQXFfizX1Q{3@Owq)l!eBc=QchUR1c@iX6oNQN7+p9Vsvq6`8Bm2kko1C> zu<!@5K{yCU{Bb}N#0roiXq^ty3&J2FSp0$N7xb_P$!~z_PXuw0Fw|La5fC5U?I6hn ksNe~Z0%#e=35{!zJj{NO7&iMgpj9n1R6j@$2%~Ws069BO2><{9 literal 0 HcmV?d00001 diff --git a/libsst-os/obj/x86-64/release/SST_DynLib_POSIX.o b/libsst-os/obj/x86-64/release/SST_DynLib_POSIX.o new file mode 100644 index 0000000000000000000000000000000000000000..be5eab146c1151107a2c39ab31396e47a87af2f1 GIT binary patch literal 3144 zcmb<-^>JfjWMqH=Mg}_u1P><4z`((YU^{@B4h*~uTnwQeoliZQ-w1eg*8cEluKmGK zs^ihk3R2+FdZ0ue#_kpc3w2)G52F8HXgyHMa^^MT8INw)ANxS|d2}9s0g^g-7;2(| zM`!H|kIvEu9?i8cNHw*&_5rC{x<em$bi2Or=)4AVibtpG50LxdPNKw<FheJxnbukQ z!K1nM1F5bBhqRzax9bO(!OaKQUT1)udyF9mM0qqHU_8c<31u=JV@Lusdjpsux{i5t zUI&LbSorwC|NsC0_vk#d0~84!o!39D^XNR`@%@5FZ@_=B3dRe^8T5+t8Ndoo9u7z> z$xz5mtW?O$FHuNJRqzY-@nP`EOe#t&s>CUtmzbN1A<5wG>};i=5t>w*S5m5As%N5S zplenN<{8!*n&}ys=$UCk#1)JT49yJ83@jNKL_qFjU|?XZ3SwZa5MY$%Vdt2@$iN`O z0Kp*XAQ0imC(y>^%*)2)%frqAk+T7bGcYhr2GMZ&KDc}gNSuLz!4E{k<vro@H6U>Y z28N>`8ZLhTEDsXGhCykZh2i6WY;w$4a~uN$GXpa=<qXUWEI7o$84p8_nSmWc3?#tJ zzyYE#Ff#)ih8QTkg^=6{4qFBW1~mo-1_2D!3=H--#6e+;O?@&00|Ur>n7QD%VPIe= z$6-z_RQ*$^-Qc)lU|^VlL;Vb>dSg&Tz~YX9fngO6^&4@BGXw{R#Jg1H`D7-=2lxkj zM(8Djh5Uo#eex4iATkWa#U=46sY#{j@rlL7sYNC68Hsr*IjKcBCE^o{(iu{6@(WV) zV8*$pmiS~Q1y|-K<>xS@<P=xt!epFt@{3cUHl^ewgLp70h^Sv;ZYo1@Nl{K}9*9aV zsALd>h7%J50|OTW1H&Ise*gdfzY-2{O(bz{B=v?+agZ6vsm%u}4l<tyNqr8II7ko7 z-U=Mz^+@8#_O?UCL1uvL1=lAG3=H$3;vjoLaxn8(;}GA3B#vzUE~q%j3}o}KL&ZVn z^C9``H<CC=56oV6X!-)FM;7Np5=XXI3@Q#%i)^nBR2*auD8InW_eBy1>4Awy;t)?j z5=XW-11b(O17xo*)IY6Iage=2Nd5&^(hLj?AaP+NaRsP8kT?iKxeSmt0z^GX9G0&W zpb9`@APmdD4QS%9e9E9#T$x*vn8cu0Tv7y~GhnQu)SN`UlGKV42ECNTl0*i*q~c-* zy`p>wCpkYiH#M(>K`$@ABvsGdFI2a<Br!RgK@Y4gH6uQ)2$W5r_EJiL!T}U?=p`pC z9DaZ#kt{*uGDtHpfJ=3ldYIA|pvYlhV2A((76StVC=Nk-VI{W&R3WGw28pBB7#2`{ zP-Somq!!L$U|`T;U;x(!<mv~N3m`Mmt%KR`g=`t9-bUkFLd6Ww#G9Z7nxct=>;ehF zXeX$CkQg%F4%Lq=24chXf!H7%4%LsYd<RqjRDXcf!7wcRVSG^f2Gz>w@#g?l2ut^% z_yY-nFi0;f{sb97^*u-g6)%7)Ohgq%s)->IApby}3K4*k0niA208+rfzyK<nK}~t6 fu?#T#L1Iv)P@NFU0Gj^5%|3__n1mV!W`hU-?OGtG literal 0 HcmV?d00001 diff --git a/libsst-os/obj/x86-64/release/SST_Endian.o b/libsst-os/obj/x86-64/release/SST_Endian.o new file mode 100644 index 0000000000000000000000000000000000000000..f32bccd16716eb44130993214fda364f542b5454 GIT binary patch literal 2360 zcmb<-^>JfjWMqH=Mg}_u1P><4z+l0KU^{@B4h%dDoD88JoliZQ-zcPbbhD^xFfcH9 zbh`d9Jdk$W_1(Wvk6zbz9-XcqJi1*!@NZ+V2`%M0&I-~Dvf(usgbm_P@aT5^k>X(t zF`|U^1xWDZVUXe7U=6WgcIS_@PS-#D+g<;p9elyjc?iTh_<)1+0#v&8PPgkF{%r?3 zUEg%O-ce=v&%gju=lTK6WBAW-@P$C9>z8iVI|pA#bh`fNc71d3fkfw_Zr2Y79|&+B z>URACHjdl%N2lwbZr48$b3Hn1S9o;0uHfHxz@yW32Z#wa+vDI14v$XP0}ug*{|p`n zUkG?~x}JavF#Pv8_(H;?)AfSK4v>fbgMvrdb%n>l7YZJot~Vf}AXj=oL^V7*T^~S2 zLB>Hu4LmwsUx1ACIQYT>8k{>k4nDB(=se`n?RvoD-~$5>P7w2i$H5005atDsgAWuS z%o`pDA4ou$4?GS&5P&dWcpQAd;lX*qgWL53D9%7J5PO(`!QI)}N<kwusWh*oRKZlw zM9)CitQ5>MtTQyzGceIJ(}ajC7#SFv8JHPZg8U`|A{ZDL7^{L97%K!ArFqynCNMHE z$S^=KNIDioIPwX!F*)<HF-7pOb3o*5K;jGx3_KtjChrcG2J4Rji8C-T$b)E@d=x^y z1|-hFzz_kVVe(ADU<Dxi=YYf+7#QAzXt?|<uslcz8wRCN7KV?YD8rCu#+pMI7?>HD zG1P(tm>F0=6bj}8g%y%GvI=Gfq|An-i<yBPiHBe^Gl265LI4_8LP+iehdl!Wg9!rz zg8+(32*;IyfdQl*rVbnz3=9l$Q1MKNGDsXSFfbHA#XF$l;IL<4U}%DhKY)sZ!yLp8 z4i1TT%}dEl%+pI|$W2Vn$jnQ1sw_$MFG@)*Vu+8=$xJFPE{V^~%Pfgc1*>C-k1sAs zOwNu^&d82WOU%q+0GZ(*9Pgf5;*nom0x>NwwYV520WvSRJh8yg3|++72wlVs6cP*! zMj*E_FfcGNFo0v@$A1X0!yz7yB+kXa!0-p6{C_f%I4CY*;tELOAUmL321pqSu@@u` z3-<)50+1L8!@|7*O&k{P3(&-2;m)8}T$x*vn8cu0Tv7y~GhnQu)SN`UlGKV42ECNT zl0*i*q~c-*z2yAd+|;}h2EDxel2ko+zffIp=ribnm8WLJrxhjUrb4Zwm;!|hD3771 zbXd5Y2T3B?g2rW#hQ=36JzOa?E5O1L6h|Pv98d)kP+AR~|3G;bDgdSUL4gisBU2zV zkoh_c3=AMM(Q~{2R6i&UAgf2`8$#_jKvo3Gn^66xXyP#YVYC%gKbkTISEzn;ahN`s zxIa`sx^fSw0Jy?}DTewLiOb-HBm5Jf;a>q&3<`fxsRarvkPs~V1sO2I9wdJQsy`CM zLBi<n2l1g!MN)+@Gy|l7fq{XWfq{V&$^9_<L1O4}2QnxF8c|a~93%`i4lV)!L8@!Q literal 0 HcmV?d00001 diff --git a/libsst-os/obj/x86-64/release/SST_FileSys_POSIX.o b/libsst-os/obj/x86-64/release/SST_FileSys_POSIX.o new file mode 100644 index 0000000000000000000000000000000000000000..4501ca7eaa09c51533df300ac73f96d2552bdf76 GIT binary patch literal 4336 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 literal 0 HcmV?d00001 diff --git a/libsst-os/obj/x86-64/release/SST_File_POSIX.o b/libsst-os/obj/x86-64/release/SST_File_POSIX.o new file mode 100644 index 0000000000000000000000000000000000000000..dcc7a3f7b081f41b861f6bf9e95c08cdc992c82c GIT binary patch literal 6720 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 GmjM8p>nO|s literal 0 HcmV?d00001 diff --git a/libsst-os/obj/x86-64/release/SST_Mmap_POSIX.o b/libsst-os/obj/x86-64/release/SST_Mmap_POSIX.o new file mode 100644 index 0000000000000000000000000000000000000000..54170b1604c75622ec278c9da0f97cc84626a29f GIT binary patch literal 5336 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 E04R^#DgXcg literal 0 HcmV?d00001 diff --git a/libsst-os/obj/x86-64/release/SST_OSInit.o b/libsst-os/obj/x86-64/release/SST_OSInit.o new file mode 100644 index 0000000000000000000000000000000000000000..5e8eda2681d14f77bd8d367501cd55dad8d6ef21 GIT binary patch literal 1736 zcmb<-^>JfjWMqH=Mg}_u1P><4z;J>Y!FB*M9T<2RI2l4cI-l+U@n3)l{H)dkC87uw ztp`fjcYv&V%?cKbJ<Q<l>};i=5t>w*S5m5As%N5SplenN<{8!*n&}ys=$UCk#1)JT z49yJ83@kymg0KjPU|?WitO{aatPo(7=3(cUz{tQL!vMh`X&(^b$S2Uo<jl*)<j%v+ z0TRHDK@MYK`1l{2EHl;+VqjoqKnf%zjm!)zNIV3SnSl+#L1Hm8up{vhOlAgF1P99E zV_;wqLUIq-j|>b9QVa|X0#G%`ls*n|Hyq-zIK&HZh%*EShs65_d*)@9=p{or@gN>U ze0)x3QgLxfd}dx|NqlNvN@ijnnqWa<dTMcIRVtcrZf;@$7U7c2Ty&MC#i>OQ-*Q1H z1||ju22KVBhClxy0G3Wb;vh9JaXBRQ+(_y*ki>bA#LbYzd6C2wki<cDK)DPIdc~Ew zC5cH4dc`G05IO_KDoV{s)GJA?C}Ge`Ni0cZ&`T;VX3$H{&&^HED`C*f%P&dQbN36? zEiOq+&Sua9D^JacPb*5yO@*6JAp_)YP?|?ik&wL3zyM2EFl#_+VQdgB&A<Ro<uLUi zF%Z514TK61hk=0s6y_kku&gHm6;}i0T?SAdf(k&X9w?1Yfy_V_(_vs>0GWxN1Bumd z2({k;*-!=s2AF<RG;x^yFxm>LA59s<L39BqAEpn=W$=gUhXxl+nBfGJWdWsO6v(eI zHi-7Z5&i+t0D*-wDEvXC3rs&uTo6mxgUro<>W>6*kTAOYL40(#gO!6M7#J7=pfo6N jf$RohkUY$OP#%R^1rmni0H~qOa1jUtY8-^az`y_i5#6kg literal 0 HcmV?d00001 diff --git a/libsst-os/obj/x86-64/release/SST_SafeArithmetic.o b/libsst-os/obj/x86-64/release/SST_SafeArithmetic.o new file mode 100644 index 0000000000000000000000000000000000000000..4b55318a3884d667668c00b1c48c40718ee0546f GIT binary patch literal 5456 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 IOrmia07G=%zyJUM literal 0 HcmV?d00001 diff --git a/libsst-os/obj/x86-64/release/SST_SysMem_POSIX.o b/libsst-os/obj/x86-64/release/SST_SysMem_POSIX.o new file mode 100644 index 0000000000000000000000000000000000000000..bd01586ce77aa2790af30c4cb87bf6ab463bb2b0 GIT binary patch literal 3888 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 MJ*qG`tsx5m0J3laDF6Tf literal 0 HcmV?d00001 diff --git a/libsst-os/obj/x86-64/release/SST_Time_POSIX.o b/libsst-os/obj/x86-64/release/SST_Time_POSIX.o new file mode 100644 index 0000000000000000000000000000000000000000..ef7d2b217e4de86cf667d77f0e799e944509b9b4 GIT binary patch literal 2816 zcmb<-^>JfjWMqH=Mg}_u1P><4z;J*a!FB*M9T<2SxEMk`I-hzpzcEPh=w?yXU|?YI z=yd&Ic%YjVq{gE+^npj`wa()&K)lui{PPd+Z#&TGdZ)Se4nwKmaj+tgZNw;-$F8W7 zeFw<!*Q`5026=S*{z&mK<^emUgcWS>$-_`bDiGmFk8alo9+@8;ocI|$x_w`G>^lEF z`0>)&M-)6dPk4NP<#F&AJBW4ghrNg9A&<@r9*iG6x@$pp+E8le3uXqWowrT4U2nQ4 z?F_OBY^M;2MRhyV_}`!W<iW3X!lT>uMH>J610c?UPy7O+pb-7UA9v^zf5btLZdZ`^ zAh8P%QWlUBC{8_l){(*8+1W}#BQ&WrucTDLRL?}uK-a7k%rmSrG}ALM(KFM8h$|Qw z7@8TF8CZg}i+~6Q1_s8eAO^+?0Y+&ac8&>*3=A?15Db!D3L+f&1lpLKdD)m2@UU}0 z<ZM9V3=9k<AQ~>850{StiQ|#4fy!rtXt@3~uzrvbHVjH+EDRt2W0PaXnsXQ!m>HO{ zDQ942Kn_KS5+P7nAgM=I!OQ^8Fc5`EBr^k2=0p+aK;j{o%nWP@4wNO!z`!8L@aew* zln<ko7#J9Yko*OX3kC)TQw9bGm>Q@SFy)LxJOpYEOg}iz7#J8bpyHCCfQ7{s0|Nsn zZb0_-LdC&x1hOGGI3zwKGdDFpz(3eCLNA%2Br`WPIKQ+gIh7%;D7BCwK0YTiskpc# zJ~J<~BpxKokerjBoE@K@S_0<9#}}6*CTGVdXJp5xC1&O@fQ<AHj(1Nj@y$#w$_JT_ zB9@bri6-Wjlb=|UnU@Y02Dyqs5==5MFfoAQn}Olae+W=V66aw+h}$8FgHp#2i1Pm) zXyPz)!jQy~&B;X)2blv?UyUS=tbRU{I4_cW_92NQn{x(99N8RUXuN>@i)@Y&k~p$C z4oKq2=CmV;Bb&1fNgUanElA?X=3GM(2c>RUIDA49M>byp$zLEpK)DQ%x(yPKAaPiF zO@Jx@iGeUIy*8kU!_q5*UU6k^Nn#R%UU5kggwBAmic)hD^-5AJN*MG~5=#;p^pc8; z8T5+sA)Ms=+}zZ>5(d4z{E}2XcfU|waB^kP18Ymoh)*j@%uR(_OECos2T%}!!VK9k zSUCIuNg_$0aT%l;7{H|%Og&7g2ehc#0M)<^F4q_sU?q|SRG}JF92Cb;AuweD3S_9+ zU;!wBTpogibQmCJqU*PT>IbPo#!%<Lg$$wgqbqlS3c%b8(}2zgRbn7B4PXkOv<Fl_ zsGNiffhmw$5CcX#LG1^LA>&%8eq=Ea8>SD$2H|k1estvxP=OgBMMxOk{Xx($MvuQA z&;$WX_n`O#=>=hsaj^IkgqC+8F=QM8t&$Rv1)*+576SPP>QrQ51_@|{&HyQ3U|;~{ cbuMUJgA~H-=fq+E253T=3{s4Qp~k^Q033zmxc~qF literal 0 HcmV?d00001 diff --git a/libsst-os/obj/x86-64/release/SST_User_POSIX.o b/libsst-os/obj/x86-64/release/SST_User_POSIX.o new file mode 100644 index 0000000000000000000000000000000000000000..959fa901d8284eef75fa3c0ae943939b50e1be75 GIT binary patch literal 3232 zcmb<-^>JfjWMqH=Mg}_u1P><4z_5T5!FB*M9T<2RI2l4cI-l+UX^1@xVtO>bNnl}M z@aWvT;`jgmom-du{{KJ4qnkxlg8?M!`or*m$MM!3zyJRSnehTdbhd8z{r|s5Z!bvH zqj%~DFmLOD-~a!2gQYw>PwZr1VPNPy4p!fKpoDA3|NsC0zuXKmvm0!hN9%!7t{oub zUe1Mxg7kYpwRE;_0U6p1b`(P?M>m-Nx(q@$A7Hd@1v#`{(W84RSYLN5$oU?f*I*_< zRK9lU1}kiS!RV2E!K1quMe#X=VvuPbGdy|&{(C@;V!UvSfdOKQN4M{f6c1w_aF~>^ zf<1L|kcHk2P<W9MdSHD}FB1$s6ve|S^d68IdSHFTh8~Jy%0iF9-PzenK_fJ&G_Ryo z!Bo#g&p_9#6wEWMGc?mPFwry9gorB`85o)wm>F1t@)`pJg9wyntO{aatPo(7=3(cU zz{tQL!vMh`X>JhV$S2Uo<jl+F#>375m9qhfGcYjNfyxh<JhLSuNCilL3<3EXJn~Q} z3<_iw3&Tfn@q;eOjJ4!rU|?ooMpp{vGlNPcFbkDnW?(}Vfby6b*r6;`ikX2GRe*tk zK?saNu7yZ}!;pc2K@}<v<AcMFfq}t-fq_8)q7;P$mDSk9y>X}y!XX}sLp%Y8cp=oC zo=`8q+}QyYZ)buy6DH0O92^oKTAW%GAK)MC8KIZV5FekDnN(a{5}%ouSrT7boLU4{ z;~yOFo>~G@>6e(B%8;H~l3JRX0-_7bOEXjAix`SaigHr(KvZ%;B|~m%E{KYcFD^+; z&W=yc$c|4-%*;VED=0NF2W%e583-#p@^e#NGK*4^OY(~<!49?qlMD<X=W{VIF#G}4 zMF0Q)&qERi#SKh+A(A)`lKRI;;=D-W0?_aRna_tL?u;bPk0f4$B#!K!HAv#f?zxX7 zj_e*qkcA8oe<8ca4@n%^J&j1>$nM#NB#!K!S4iT>?vaINEs!*_d*YGAk=@gSB#!K! z{Yc`-?omJrXOJCGE(0iEfY=~05C*vk#0RBk5DgLoVOaWY00~0F2P6(lzYKcCmANH} zNep_$B}EWA1I8*!%}LZNNv$Yh&`U`yNo3GVDlTTwOU}>DP0cG|(96p&N!4@r3)Kau zOa?u$^3;s@v?5T#hT2Cd1@b>A%F#<CnE#JL!wqH+NG*&FqNN!az@;2aJxC0M4WLEY z2B-#5T!WaPvK=HZ0U{U}7}OXTz@;jhH4LmQPz7id$P8p59R>ylkeTG_H-y@6fNUrO z1KfU7G;x^yFxm>LA59s96_M`uhw2BV8DujYp!#PZ3qt*hEaZhF{2zb<g@J(qmR>>O z4~i0~Fas?71sOo~7qW>EwgV@G29@g&7KDWP8^VLc9lF~=ayOvvhs8fA|A6cUVURq` WevmcjaR-v`fF{T#APy2nw;uo?4KdyT literal 0 HcmV?d00001 diff --git a/libsst-os/sources-POSIX.mk b/libsst-os/sources-POSIX.mk new file mode 100644 index 0000000..2825cb1 --- /dev/null +++ b/libsst-os/sources-POSIX.mk @@ -0,0 +1,38 @@ +# libsst-os/Source/sources-POSIX.mk +# Author: Patrick Baggett <ptbaggett@762studios.com> +# Created: 12/23/2011 +# +# Purpose: +# +# List of source files for POSIX-compliant systems. This reduces the amount +# of copy/pasting for different UNIX configurations. +# +# License: +# +# This program is free software. It comes without any warranty, to +# the extent permitted by applicable law. You can redistribute it +# and/or modify it under the terms of the Do What The Fuck You Want +# To Public License, Version 2, as published by Sam Hocevar. See +# http://sam.zoy.org/wtfpl/COPYING for more details. + +SRC := \ + SST_DynLib_POSIX.c \ + SST_FileSys_POSIX.c \ + SST_File_POSIX.c \ + SST_SysMem_POSIX.c \ + SST_CPU_POSIX.c \ + SST_Mmap_POSIX.c \ + SST_User_POSIX.c \ + SST_Alloc.c \ + SST_Assert.c \ + SST_Assert_Generic.c \ + SST_Endian.c \ + SST_SafeArithmetic.c \ + SST_OSInit.c \ + +# MacOS X doesn't have POSIX realtime extension, so it needs a different implementation. Le sigh. +ifeq ($(OS),Darwin) + SRC += SST_Time_MacOSX.c +else + SRC += SST_Time_POSIX.c +endif diff --git a/libsst-os/sources-Solaris.mk b/libsst-os/sources-Solaris.mk new file mode 100644 index 0000000..dd56a8f --- /dev/null +++ b/libsst-os/sources-Solaris.mk @@ -0,0 +1,18 @@ +# libsst-os/sources-Solaris.mk +# Author: Patrick Baggett <ptbaggett@762studios.com> +# Created: 6/21/2012 +# +# Purpose: +# +# List of source files for Solaris +# +# License: +# +# This program is free software. It comes without any warranty, to +# the extent permitted by applicable law. You can redistribute it +# and/or modify it under the terms of the Do What The Fuck You Want +# To Public License, Version 2, as published by Sam Hocevar. See +# http://sam.zoy.org/wtfpl/COPYING for more details. + +include sources-POSIX.mk + diff --git a/libsst-os/sources-Win32.mk b/libsst-os/sources-Win32.mk new file mode 100644 index 0000000..c6592ae --- /dev/null +++ b/libsst-os/sources-Win32.mk @@ -0,0 +1,28 @@ +# libsst-os/sources-Win32.mk +# Author: Patrick Baggett <ptbaggett@762studios.com> +# Created: 11/09/2012 +# +# Purpose: +# +# List of source files for Win32 systems. +# +# License: +# +# This program is free software. It comes without any warranty, to +# the extent permitted by applicable law. You can redistribute it +# and/or modify it under the terms of the Do What The Fuck You Want +# To Public License, Version 2, as published by Sam Hocevar. See +# http://sam.zoy.org/wtfpl/COPYING for more details. + +SRC := \ + SST_DynLib_Win32.c \ + SST_FileSys_Win32.c \ + SST_File_Win32.c \ + SST_SysMem_Win32.c \ + SST_CPU_Win32.c \ + SST_Mmap_Win32.c \ + SST_Assert_Win32.c \ + SST_Alloc.c \ + SST_Assert.c \ + SST_Endian.c \ + SST_SafeArithmetic.c diff --git a/libsst-random/Makefile b/libsst-random/Makefile new file mode 100644 index 0000000..5ce7c6a --- /dev/null +++ b/libsst-random/Makefile @@ -0,0 +1,44 @@ +# libsst-random/Makefile +# Author: Patrick Baggett <ptbaggett@762studios.com> +# Created: 2/26/2012 +# +# Purpose: +# +# Makefile for libsst-random +# +# License: +# +# This program is free software. It comes without any warranty, to +# the extent permitted by applicable law. You can redistribute it +# and/or modify it under the terms of the Do What The Fuck You Want +# To Public License, Version 2, as published by Sam Hocevar. See +# http://sam.zoy.org/wtfpl/COPYING for more details. + +BINNAME := $(DIST)/libsst-random.a +ifeq ($(TARGET),debug) + BINNAME := $(subst .a,_d.a, $(BINNAME)) +endif + +SRC := SST_CMWC.c \ + SST_Mersenne.c \ + SST_SimplexNoise.c \ + SST_PRNG.c \ + SST_SimplexNoise.c \ + SST_SmallPRNG.c + +OBJ := $(addprefix obj/$(ARCH)/$(TARGET)/,$(subst .c,.o,$(SRC)) ) + +$(shell mkdir -p obj/$(ARCH)/$(TARGET)) + +$(BINNAME): $(OBJ) + $(AR) cru $@ $+ + $(RANLIB) $@ + +# CLEAN +clean: + @-rm -r -f obj $(DIST)/libsst-random*.a + +# *.c files to *.o files +obj/$(ARCH)/$(TARGET)/%.o: %.c + @echo CC $@ + @$(CC) $(CFLAGS) -c $*.c -o obj/$(ARCH)/$(TARGET)/$*.o diff --git a/libsst-random/RandomFuncTbl.h b/libsst-random/RandomFuncTbl.h new file mode 100644 index 0000000..6c1f9cd --- /dev/null +++ b/libsst-random/RandomFuncTbl.h @@ -0,0 +1,87 @@ +/* + RandomFuncTbl.h + Author: James Russell <jcrussell@762studios.com>, Patrick Baggett <@762studios.com> + Created: 5/1/2012 + + Purpose: + + Private header for libsst-random function table + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. +*/ + +#pragma once + +#ifndef _SST_RANDOMFUNCTBL_H +#define _SST_RANDOMFUNCTBL_H + +#include <SST/SST_PRNG.h> +#include <SST/SST_Build.h> +#include <stdlib.h> /* size_t */ + +/* +The following typedefs are used to set function pointer types. +*/ +typedef void (*SST_Random_InitFromSeedFunc)(void*, uint32_t); +typedef void (*SST_Random_GetFloatArrayFunc)(void*, float*, size_t, float, float); +typedef int (*SST_Random_GetIntFunc)(void*); +typedef void (*SST_Random_GetIntArrayFunc)(void*, int*, size_t, int, int); + +/* + Struct used to contain the necessary function pointers for a given PRNG. + See SST_PRNG.c for explanation of non-orthogonality. +*/ +typedef struct SST_PRNG_FuncTable +{ + SST_Random_InitFromSeedFunc initFromSeed; + SST_Random_GetFloatArrayFunc getFloatArray; + SST_Random_GetIntFunc getInt; + SST_Random_GetIntArrayFunc getIntArray; + size_t privateSize; +} SST_PRNG_FuncTable; + + +#define SST_RAND_FLOATBITS_MAX (0x00FFFFFF) + +/* Takes a value in the range of [0, SST_RAND_FLOATBITS_MAX] and converts to float in the range 0.0 to 1.0 */ +static INLINE float randIntToFloat(uint32_t value) +{ + return (float)value / (float)SST_RAND_FLOATBITS_MAX; +} + +/* Take any random integer in [INT_MIN,INT_MAX] and bound it to [min,max] */ +static INLINE int boundInt(int x, int min, int max) +{ + int diff; + + x &= 0x7FFFFFFF; /* Ensure this number is positive. Modulus with negative numbers can be "surprising", e.g. 340 % 60 == 40, but -340 % 60 == 20 */ + + /* Handle edge cases */ + if(min == max) + return min; + if(min > max) + { + int tmp = min; + min = max; + max = tmp; + } + + diff = max - min; + + return min + (x % diff); +} + + + +extern const SST_PRNG_FuncTable _SST_MersenneFuncTable; +extern const SST_PRNG_FuncTable _SST_CMWCFuncTable; +extern const SST_PRNG_FuncTable _SST_SmallPRNGFuncTable; + +#endif + diff --git a/libsst-random/SST_CMWC.c b/libsst-random/SST_CMWC.c new file mode 100644 index 0000000..0180ffe --- /dev/null +++ b/libsst-random/SST_CMWC.c @@ -0,0 +1,121 @@ +/* + SST_CMWC.c + Author: Chris Ertel <crertel@762studios.com> + Created: 2/26/2012 + + Purpose: + + Implementation of complimentary multiply with carry algorithm + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. +*/ + +#include "RandomFuncTbl.h" + +/* Do you believe in magic? */ +#define PHI 0x9e3779b9 +#define CMWC_SIZE 4096 + +/* CMWC Data Struct */ +typedef struct SST_CMWC_Private +{ + uint32_t cmwc_buffer[CMWC_SIZE]; + uint32_t cmwc_carry; + size_t cmwc_index; +} SST_CMWC_Private; + +/*************************************************************************/ + +static int cmwc_random(SST_CMWC_Private* cmwc) +{ + uint64_t t, a = (uint64_t)18782; + uint32_t x, r = 0xfffffffe; + + cmwc->cmwc_index = (cmwc->cmwc_index + 1) % CMWC_SIZE; + t = a * cmwc->cmwc_buffer[cmwc->cmwc_index] + cmwc->cmwc_carry; + cmwc->cmwc_carry = (uint32_t)(t >> 32); + x = (uint32_t)(t + cmwc->cmwc_carry); + + if (x < cmwc->cmwc_carry) + { + x++; + cmwc->cmwc_carry++; + } + + cmwc->cmwc_buffer[cmwc->cmwc_index] = r - x; + + return (int)cmwc->cmwc_buffer[cmwc->cmwc_index]; +} + +/*************************************************************************/ + +static void CMWC_InitFromSeed(void* priv, uint32_t seed) +{ + SST_CMWC_Private* cmwc = (SST_CMWC_Private*)priv; + size_t i; + + cmwc->cmwc_index = 4095; + cmwc->cmwc_carry = 362436; + cmwc->cmwc_buffer[0] = seed; + cmwc->cmwc_buffer[1] = seed + PHI; + cmwc->cmwc_buffer[2] = seed + PHI + PHI; + + for (i = 3; i < CMWC_SIZE; i++) + cmwc->cmwc_buffer[i] = cmwc->cmwc_buffer[i - 3] ^ cmwc->cmwc_buffer[i - 2] ^ PHI ^ (uint32_t)i; +} + +/*************************************************************************/ + +static void CMWC_GetFloatArray(void* priv, float* _out, size_t _numElements, float _min, float _max) +{ + SST_CMWC_Private* cmwc = (SST_CMWC_Private*)priv; + size_t i; + const float diff = _max - _min; + + /* compute and return a pseudorandom float in the range */ + for ( i = 0; i < _numElements; i++ ) + { + _out[i] = _min + randIntToFloat((uint32_t)boundInt(cmwc_random(cmwc), 0, SST_RAND_FLOATBITS_MAX)) * diff; /* x = [0,1]; value = min + x*(max - min) */ + } +} + +/*************************************************************************/ + +static int CMWC_GetInt(void* priv) +{ + SST_CMWC_Private* cmwc = (SST_CMWC_Private*)priv; + + return cmwc_random(cmwc); +} + +/*************************************************************************/ + +static void CMWC_GetIntArray(void* priv, int* _out, size_t _numElements, int _min, int _max) +{ + SST_CMWC_Private* cmwc = (SST_CMWC_Private*)priv; + size_t i; + + /* grab an number of pseudorandom ints in the specified range */ + for(i = 0; i < _numElements; i++) + { + _out[i] = boundInt(cmwc_random(cmwc), _min, _max); + } +} + +/*************************************************************************/ + +/* Function table for CMWC random number generation. */ +const SST_PRNG_FuncTable _SST_CMWCFuncTable = +{ + CMWC_InitFromSeed, + CMWC_GetFloatArray, + CMWC_GetInt, + CMWC_GetIntArray, + sizeof(SST_CMWC_Private) +}; diff --git a/libsst-random/SST_Mersenne.c b/libsst-random/SST_Mersenne.c new file mode 100644 index 0000000..ce9e2a4 --- /dev/null +++ b/libsst-random/SST_Mersenne.c @@ -0,0 +1,143 @@ +/* + SST_Mersenne.c + Author: Chris Ertel <crertel@762studios.com> + Created: 2/26/2012 + + Purpose: + + Implementation of Mersenne Twister + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. +*/ + +#include "RandomFuncTbl.h" + +/* +Note: This implementation of mersenne twister was originally written by Michael Brundage and has +been placed in the public domain. We modified it somewhat. +*/ + +/* Length of our mersenne twister buffer */ +#define MT_LEN 624 + +/* Bunch of useful macro functions and magic numbers */ +#define MT_IA 397 +#define MT_IB (MT_LEN - MT_IA) +#define UPPER_MASK 0x80000000 +#define LOWER_MASK 0x7FFFFFFF +#define MATRIX_A 0x9908B0DF +#define SEED_MAGIC 0x6C078965 +#define TWIST(b,i,j) ((b)[i] & UPPER_MASK) | ((b)[j] & LOWER_MASK) +#define MAGIC(s) (((s)&1)*MATRIX_A) + +/*************************************************************************/ + +/* Mersenne Twister Data Struct */ +typedef struct SST_Mersenne_Private +{ + uint32_t mt_buffer[MT_LEN]; /* Buffer for our seed data */ + size_t mt_index; +} SST_Mersenne_Private; + +/*************************************************************************/ + +/* get the next random value from the mersenne twister array */ +static int mt_random(SST_Mersenne_Private* mt) +{ + uint32_t* b = mt->mt_buffer; + size_t idx = mt->mt_index; + + uint32_t s; + int i; + + if(idx == MT_LEN) + { + idx = 0; + i = 0; + for (; i < MT_IB; i++) { + s = TWIST(b, i, i+1); + b[i] = b[i + MT_IA] ^ (s >> 1) ^ MAGIC(s); + } + for (; i < MT_LEN-1; i++) { + s = TWIST(b, i, i+1); + b[i] = b[i - MT_IB] ^ (s >> 1) ^ MAGIC(s); + } + + s = TWIST(b, MT_LEN-1, 0); + b[MT_LEN-1] = b[MT_IA-1] ^ (s >> 1) ^ MAGIC(s); + } + + mt->mt_index = idx + 1; + + return (int)b[idx]; +} + +/*************************************************************************/ + +static void Mersenne_InitFromSeed(void* priv, uint32_t seed) +{ + SST_Mersenne_Private* mt_data = (SST_Mersenne_Private*)priv; + size_t i; + + mt_data->mt_index = 0; + mt_data->mt_buffer[0] = seed; + + /* Initialize the generator */ + for(i = 1; i < MT_LEN; i++) + mt_data->mt_buffer[i] = (SEED_MAGIC * (mt_data->mt_buffer[i - 1] ^ (mt_data->mt_buffer[i - 1] >> 30)) + (uint32_t)i); + +} + +/*************************************************************************/ + +static void Mersenne_GetFloatArray(void* priv, float* _out, size_t _numElements, float _min, float _max) +{ + SST_Mersenne_Private* mt_data = (SST_Mersenne_Private*)priv; + size_t i; + const float diff = _max - _min; + + /* grab a number of pseudorandom floating point numbers in the specified range */ + for (i = 0; i < _numElements; i++) + { + _out[i] = _min + randIntToFloat((uint32_t)boundInt(mt_random(mt_data), 0, SST_RAND_FLOATBITS_MAX)) * diff; /* x = [0,1]; value = min + x*(max - min) */ + } +} + +/*************************************************************************/ + +static int Mersenne_GetInt(void* priv) +{ + SST_Mersenne_Private* mt_data = (SST_Mersenne_Private*)priv; + + return mt_random(mt_data); +} + +/*************************************************************************/ + +static void Mersenne_GetIntArray(void* priv, int* _out, size_t _numElements, int _min, int _max) +{ + SST_Mersenne_Private* mt_data = (SST_Mersenne_Private*)priv; + size_t i; + + /* grab an number of pseudorandom ints in the specified range */ + for (i = 0; i <_numElements; i++) + _out[i] = boundInt(mt_random(mt_data), _min, _max); +} + +/*************************************************************************/ + +/* Function table for mersenne random number generation. */ +const SST_PRNG_FuncTable _SST_MersenneFuncTable = +{ + Mersenne_InitFromSeed, + Mersenne_GetFloatArray, + Mersenne_GetInt, + Mersenne_GetIntArray, + sizeof(SST_Mersenne_Private) +}; diff --git a/libsst-random/SST_PRNG.c b/libsst-random/SST_PRNG.c new file mode 100644 index 0000000..1095140 --- /dev/null +++ b/libsst-random/SST_PRNG.c @@ -0,0 +1,157 @@ +/* + SST_PRNG.c + Author: Patrick Baggett <ptbaggett@762studios.h> + Created: 5/1/2012 + + Purpose: + + PRNG interface functions that call out to implementations as necessary + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. +*/ + +#include "RandomFuncTbl.h" +#include <time.h> /* clock() */ +#include <string.h> /* memcpy() */ + +/* + PRNG instances consist of a function table and associated private data that is implementation-specific. + In order to reduce the number of malloc() calls and points of failure, the private data is not stored as + a pointer but actually grafted onto the instance structure. Thus, the layout in memory is: + + [ handle data ][ private data ] + + In order to know the required size of the private data, the function table has a 'size_t' member called "privateSize" + that is used. The PRNG_GET_PRIVATE() macro is used to get the address of the private data section given the base handle. + This is what is passed to the implementation-specific functions. + + The function tables mimic the API somewhat, but with a few exceptions. First, they don't do any memory allocation, so they + can't fail. Second, they only expose the functions required to implement the API optimally. For example, GetInt() is required, but + it returns the full range, and these functions convert it to the necessary range. GetFloat() does not exist because it can be + done via int -> float conversions; however the GetFloatArray() /is/ because it would require dereferencing a function pointer + (indirect jump) over and over which reduces performance compared to looping in implementation code. Same goes for GetIntArray(). + The non-orthogonality may seem odd, but it is minimal and optimal. + +*/ + +/* Macro to get the start of the private data section given a PRNG handle */ +#define PRNG_GET_PRIVATE(prng) (void*)(((uintptr_t)prng) + sizeof(SST_PRNGImpl)) + +/* +This struct contains the data necessary for a created PRNG of any +of the implemented types. +*/ +typedef struct SST_PRNGImpl { + const SST_PRNG_FuncTable* vtbl; /* function table for the generator */ +} SST_PRNGImpl; + +/*************************************************************************/ + +SST_PRNG SST_Random_CreatePRNG(SST_PRNG_TYPE type) +{ + uint32_t seed = (uint32_t)clock(); + return (SST_PRNG)SST_Random_CreatePRNGFromSeed(type, seed); +} + +/*************************************************************************/ + +SST_PRNG SST_Random_CreatePRNGFromSeed(SST_PRNG_TYPE type, uint32_t seed) +{ + SST_PRNGImpl* instance; + const SST_PRNG_FuncTable* vtbl; + + switch(type) + { + case SST_PRNG_MERSENNE: vtbl = &_SST_MersenneFuncTable; break; + case SST_PRNG_CMWC: vtbl = &_SST_CMWCFuncTable; break; + case SST_PRNG_SMALLPRNG: vtbl = &_SST_SmallPRNGFuncTable; break; + + /* Unknown */ + default: return NULL; + } + + /* Allocate instance + private data */ + instance = (SST_PRNGImpl*)malloc(sizeof(SST_PRNGImpl) + vtbl->privateSize); + if(instance == NULL) + return NULL; + + /* Initialize the instance */ + instance->vtbl = vtbl; + + vtbl->initFromSeed(PRNG_GET_PRIVATE(instance), seed); + + return (SST_PRNG)instance; +} + +/*************************************************************************/ + +SST_PRNG SST_Random_ClonePRNG(SST_PRNG instance) +{ + SST_PRNGImpl* prng = (SST_PRNGImpl*)instance; + SST_PRNGImpl* newPrng; + + /* Allocate new prng data */ + newPrng = (SST_PRNGImpl*)malloc(sizeof(SST_PRNGImpl) + prng->vtbl->privateSize); + if(newPrng == NULL) + return NULL; + + /* Copy function table, then private data area */ + newPrng->vtbl = prng->vtbl; + memcpy(PRNG_GET_PRIVATE(newPrng), PRNG_GET_PRIVATE(prng), prng->vtbl->privateSize); + + return (SST_PRNG)newPrng; +} + +/*************************************************************************/ + +void SST_Random_DestroyPRNG(SST_PRNG instance) +{ + free(instance); +} + +/*************************************************************************/ + +float SST_Random_GetPRNGFloat(SST_PRNG instance, float min, float max) +{ + int x; + + /* Get integer value in the range [0, SST_RAND_FLOATBITS_MAX] */ + x = SST_Random_GetPRNGInt(instance, 0, SST_RAND_FLOATBITS_MAX); + + /* Convert to float in range [0, 1.0], then scale/bias to [min,max] range */ + return randIntToFloat(x) * (max - min) + min; /* This works even if min >= max */ +} + +/*************************************************************************/ + +void SST_Random_GetPRNGFloatArray(SST_PRNG instance, float* out, size_t num, float min, float max) +{ + SST_PRNGImpl* prng = (SST_PRNGImpl*)instance; + + prng->vtbl->getFloatArray(PRNG_GET_PRIVATE(prng), out, num, min, max); +} + +/*************************************************************************/ + +int SST_Random_GetPRNGInt(SST_PRNG instance, int min, int max) +{ + SST_PRNGImpl* prng = (SST_PRNGImpl*)instance; + + return boundInt(prng->vtbl->getInt(PRNG_GET_PRIVATE(prng)), min, max); +} + +/*************************************************************************/ + +void SST_Random_GetPRNGIntArray(SST_PRNG instance, int* out, size_t num, int min, int max) +{ + SST_PRNGImpl* prng = (SST_PRNGImpl*)instance; + + prng->vtbl->getIntArray(PRNG_GET_PRIVATE(prng), out, num, min, max); +} + diff --git a/libsst-random/SST_SimplexNoise.c b/libsst-random/SST_SimplexNoise.c new file mode 100644 index 0000000..59d824d --- /dev/null +++ b/libsst-random/SST_SimplexNoise.c @@ -0,0 +1,590 @@ +#include <SST/SST_SimplexNoise.h> + +#include <time.h> +#include <math.h> +#include <stdlib.h> + +#include <pstdint.h> +#include <string.h> /* memcpy() */ + +static const int grad3[][3] = +{ + {1,1,0}, {-1,1,0}, {1,-1,0}, {-1,-1,0}, + {1,0,1}, {-1,0,1}, {1,0,-1}, {-1,0,-1}, + {0,1,1}, {0,-1,1}, {0,1,-1}, {0,-1,-1} +}; + +static const int grad4[][4] = +{ + {0,1,1,1}, {0,1,1,-1}, {0,1,-1,1}, {0,1,-1,-1}, + {0,-1,1,1}, {0,-1,1,-1}, {0,-1,-1,1}, {0,-1,-1,-1}, + {1,0,1,1}, {1,0,1,-1}, {1,0,-1,1}, {1,0,-1,-1}, + {-1,0,1,1}, {-1,0,1,-1}, {-1,0,-1,1}, {-1,0,-1,-1}, + {1,1,0,1}, {1,1,0,-1}, {1,-1,0,1}, {1,-1,0,-1}, + {-1,1,0,1}, {-1,1,0,-1}, {-1,-1,0,1}, {-1,-1,0,-1}, + {1,1,1,0}, {1,1,-1,0}, {1,-1,1,0}, {1,-1,-1,0}, + {-1,1,1,0}, {-1,1,-1,0}, {-1,-1,1,0}, {-1,-1,-1,0} +}; + +static const int p[] = +{ + 151,160,137,91,90,15,131,13,201,95,96,53,194,233,7, + 225,140,36,103,30,69,142,8,99,37,240,21,10,23,190,6, + 148,247,120,234,75,0,26,197,62,94,252,219,203,117,35, + 11,32,57,177,33,88,237,149,56,87,174,20,125,136,171, + 168, 68,175,74,165,71,134,139,48,27,166,77,146,158, + 231,83,111,229,122,60,211,133,230,220,105,92,41,55, + 46,245,40,244,102,143,54,65,25,63,161,1,216,80,73, + 209,76,132,187,208, 89,18,169,200,196,135,130,116,188, + 159,86,164,100,109,198,173,186, 3,64,52,217,226,250,124, + 123,5,202,38,147,118,126,255,82,85,212,207,206,59,227, + 47,16,58,17,182,189,28,42,223,183,170,213,119,248,152, + 2,44,154,163, 70,221,153,101,155,167, 43,172,9,129,22, + 39,253, 19,98,108,110,79,113,224,232,178,185,112,104, + 218,246,97,228,251,34,242,193,238,210,144,12,191,179, + 162,241, 81,51,145,235,249,14,239,107,49,192,214,31, + 181,199,106,157,184,84,204,176,115,121,50,45,127,4,150, + 254, 138,236,205,93,222,114,67,29,24,72,243,141,128,195, + 78,66,215,61,156,180 +}; + +/* +A lookup table to traverse the simplex around a given point in 4D. +Details can be found where this table is used, in the 4D noise method. +*/ +static const int simplex[][4] = +{ + {0,1,2,3},{0,1,3,2},{0,0,0,0},{0,2,3,1},{0,0,0,0},{0,0,0,0},{0,0,0,0},{1,2,3,0}, + {0,2,1,3},{0,0,0,0},{0,3,1,2},{0,3,2,1},{0,0,0,0},{0,0,0,0},{0,0,0,0},{1,3,2,0}, + {0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}, + {1,2,0,3},{0,0,0,0},{1,3,0,2},{0,0,0,0},{0,0,0,0},{0,0,0,0},{2,3,0,1},{2,3,1,0}, + {1,0,2,3},{1,0,3,2},{0,0,0,0},{0,0,0,0},{0,0,0,0},{2,0,3,1},{0,0,0,0},{2,1,3,0}, + {0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}, + {2,0,1,3},{0,0,0,0},{0,0,0,0},{0,0,0,0},{3,0,1,2},{3,0,2,1},{0,0,0,0},{3,1,2,0}, + {2,1,0,3},{0,0,0,0},{0,0,0,0},{0,0,0,0},{3,1,0,2},{0,0,0,0},{3,2,0,1},{3,2,1,0} +}; + +typedef struct +{ + int perm[512]; +} SST_Simplex_Data_t; + +static int fastfloor(const double x) +{ + return (int) floor(x); +} +static double dot2(const int* g, const double x, const double y) +{ + return g[0]*x + g[1]*y; +} + +static double dot3(const int* g, const double x, const double y, const double z) +{ + return g[0]*x + g[1]*y + g[2]*z; +} +static double dot4(const int* g, const double x, const double y, const double z, const double w) +{ + return g[0]*x + g[1]*y + g[2]*z + g[3]*w; +} + +SST_SimplexNoise SST_Random_CreateSimplexNoise() +{ + return SST_Random_CreateSimplexNoiseFromSeed((uint32_t) time(NULL)); +} + +SST_SimplexNoise SST_Random_CreateSimplexNoiseFromSeed(uint32_t _seed) +{ + SST_Simplex_Data_t* ret = (SST_Simplex_Data_t *)calloc(sizeof(SST_Simplex_Data_t), 1); + size_t i; + + if (ret == NULL) + return NULL; + + for(i = 0; i < 512; i++) + ret->perm[i] = p[i & 255]; + + SST_Random_ReseedSimplexNoise(ret, _seed); + + return (SST_SimplexNoise) ret; +} + +void SST_Random_ReseedSimplexNoise(SST_SimplexNoise _source, uint32_t _seed) +{ + SST_Simplex_Data_t* temp = (SST_Simplex_Data_t *) _source; + int i; + + /* reseeding here currently means shifting around the values */ + for(i = 0; i < 512; i++) + temp->perm[i] = p[ ( (i + _seed) % 256) & 255]; +} + +SST_SimplexNoise SST_Random_CloneSimplexNoise(SST_SimplexNoise _source) +{ + SST_Simplex_Data_t* ret; + + if (_source == NULL) + return NULL; + + ret = (SST_Simplex_Data_t*)calloc(sizeof(SST_Simplex_Data_t), 1); + + memcpy(ret,(SST_Simplex_Data_t*)_source, sizeof(SST_Simplex_Data_t)); + + return (SST_SimplexNoise) ret; +} + +void SST_Random_DestroySimplexNoise(SST_SimplexNoise _instance) +{ + free(_instance); +} + +float SST_Random_MapSimplexNoise1D( SST_SimplexNoise _instance, float _x) +{ + /* HACKHACK */ + return SST_Random_MapSimplexNoise2D(_instance,_x,0); +} + +void SST_Random_MapSimplexNoise1DFromArray( SST_SimplexNoise _instance, float* _destination, float* _sourceX, size_t _numElements) +{ + size_t i; + + if (_destination == NULL || _sourceX == NULL) + return; + + for (i = 0; i < _numElements; i++) + _destination[i] = SST_Random_MapSimplexNoise1D(_instance, _sourceX[i]); +} + +float SST_Random_MapSimplexNoise2D( SST_SimplexNoise _instance, float _x, float _y) +{ + int* perm; + + int i, j; + int i1, j1; /* Offsets for second (middle) corner of simplex in (i,j) coords */ + double n0, n1, n2; /* Noise contributions from the three corners */ + double s, t,x0,X0,y0,Y0; + double x1,y1,x2,y2; + double t0,t1,t2; + int ii, jj, gi0, gi1, gi2; + + /* Skew the input space to determine which simplex cell we're in */ + const double F2 = 0.5*(sqrtf(3.0)-1.0); + const double G2 = (3.0-sqrtf(3.0))/6.0; + s = (_x+_y)*F2; // Hairy factor for 2D + i = fastfloor(_x+s); + j = fastfloor(_y+s); + + t = (i+j)*G2; + X0 = i-t; /* Unskew the cell origin back to (x,y) space */ + Y0 = j-t; + x0 = _x-X0; /* The x,y distances from the cell origin */ + y0 = _y-Y0; + + /* + For the 2D case, the simplex shape is an equilateral triangle. + Determine which simplex we are in. + */ + perm = ((SST_Simplex_Data_t*)_instance)->perm; + + if(x0>y0) + { + i1=1; + j1=0; + } /* lower triangle, XY order: (0,0)->(1,0)->(1,1) */ + else + { + i1=0; + j1=1; + } /* upper triangle, YX order: (0,0)->(0,1)->(1,1) */ + + /* + A step of (1,0) in (i,j) means a step of (1-c,-c) in (x,y), and + a step of (0,1) in (i,j) means a step of (-c,1-c) in (x,y), where + c = (3-sqrt(3))/6 + */ + x1 = x0 - i1 + G2; /* Offsets for middle corner in (x,y) unskewed coords */ + y1 = y0 - j1 + G2; + x2 = x0 - 1.0 + 2.0 * G2; /* Offsets for last corner in (x,y) unskewed coords */ + y2 = y0 - 1.0 + 2.0 * G2; + + /* Work out the hashed gradient indices of the three simplex corners */ + ii = i & 255; + jj = j & 255; + gi0 = perm[ii+perm[jj]] % 12; + gi1 = perm[ii+i1+perm[jj+j1]] % 12; + gi2 = perm[ii+1+perm[jj+1]] % 12; + + /* Calculate the contribution from the three corners */ + t0 = 0.5 - x0*x0-y0*y0; + if(t0<0) + n0 = 0.0; + else + { + t0 *= t0; + n0 = t0 * t0 * dot2(grad3[gi0], x0, y0); /* (x,y) of grad3 used for 2D gradient */ + } + t1 = 0.5 - x1*x1-y1*y1; + if(t1<0) + n1 = 0.0; + else + { + t1 *= t1; + n1 = t1 * t1 * dot2(grad3[gi1], x1, y1); + } + + t2 = 0.5 - x2*x2-y2*y2; + if (t2<0) + n2 = 0.0; + else + { + t2 *= t2; + n2 = t2 * t2 * dot2(grad3[gi2], x2, y2); + } + + /* + Add contributions from each corner to get the final noise value. + The result is scaled to return values in the interval [-1,1]. + TODO check accuracy of this + */ + return (float) (70.0 * (n0 + n1 + n2)); +} + +void SST_Random_MapSimplexNoise2DFromArray( SST_SimplexNoise _instance, float* _destination, float* _sourceX, float* _sourceY, size_t _numElements) +{ + size_t i; + + if (_destination == NULL || _sourceX == NULL || _sourceY == NULL) + return; + + for (i = 0; i < _numElements; i++) + _destination[i] = SST_Random_MapSimplexNoise2D(_instance, _sourceX[i], _sourceY[i]); +} + +float SST_Random_MapSimplexNoise3D( SST_SimplexNoise _instance, float _x, float _y, float _z) +{ + double n0, n1, n2, n3; /* Noise contributions from the four corners */ + + /* Skew the input space to determine which simplex cell we're in */ + const double F3 = 1.0/3.0; + const double G3 = 1.0/6.0; /* Very nice and simple unskew factor, too */ + double s = (_x+_y+_z)*F3; /* Very nice and simple skew factor for 3D */ + int i = (int)floor(_x+s); + int j = (int)floor(_y+s); + int k = (int)floor(_z+s); + + double t = (i+j+k)*G3; + double X0 = i-t; /* Unskew the cell origin back to (x,y,z) space */ + double Y0 = j-t; + double Z0 = k-t; + double x0 = _x-X0; /* The x,y,z distances from the cell origin */ + double y0 = _y-Y0; + double z0 = _z-Z0; + + double x1,y1,z1,x2,y2,z2,x3,y3,z3; + double t0,t1,t2,t3; + + /* + For the 3D case, the simplex shape is a slightly irregular tetrahedron. + Determine which simplex we are in. + */ + int i1, j1, k1; /* Offsets for second corner of simplex in (i,j,k) coords */ + int i2, j2, k2; /* Offsets for third corner of simplex in (i,j,k) coords */ + int ii,jj,kk,gi0,gi1,gi2,gi3; + + int* perm = ((SST_Simplex_Data_t*)_instance)->perm; + + if(x0>=y0) + { + if(y0>=z0) + { + i1=1; + j1=0; + k1=0; + i2=1; + j2=1; + k2=0; + } /* X Y Z order */ + else if(x0>=z0) + { + i1=1; + j1=0; + k1=0; + i2=1; + j2=0; + k2=1; + } /* X Z Y order */ + else + { + i1=0; + j1=0; + k1=1; + i2=1; + j2=0; + k2=1; + } /* Z X Y order */ + } + else + { /* x0<y0 */ + if(y0<z0) + { + i1=0; + j1=0; + k1=1; + i2=0; + j2=1; + k2=1; + } /* Z Y X order */ + else if(x0<z0) + { + i1=0; + j1=1; + k1=0; + i2=0; + j2=1; + k2=1; + } /* Y Z X order */ + else + { + i1=0; + j1=1; + k1=0; + i2=1; + j2=1; + k2=0; + } /* Y X Z order */ + } + /* + A step of (1,0,0) in (i,j,k) means a step of (1-c,-c,-c) in (x,y,z), + a step of (0,1,0) in (i,j,k) means a step of (-c,1-c,-c) in (x,y,z), and + a step of (0,0,1) in (i,j,k) means a step of (-c,-c,1-c) in (x,y,z), where + c = 1/6 + */ + x1 = x0 - i1 + G3; /* Offsets for second corner in (x,y,z) coords */ + y1 = y0 - j1 + G3; + z1 = z0 - k1 + G3; + x2 = x0 - i2 + 2.0*G3; /* Offsets for third corner in (x,y,z) coords */ + y2 = y0 - j2 + 2.0*G3; + z2 = z0 - k2 + 2.0*G3; + x3 = x0 - 1.0 + 3.0*G3; /* Offsets for last corner in (x,y,z) coords */ + y3 = y0 - 1.0 + 3.0*G3; + z3 = z0 - 1.0 + 3.0*G3; + + /* Work out the hashed gradient indices of the four simplex corners */ + ii = i & 255; + jj = j & 255; + kk = k & 255; + gi0 = perm[ii+perm[jj+perm[kk]]] % 12; + gi1 = perm[ii+i1+perm[jj+j1+perm[kk+k1]]] % 12; + gi2 = perm[ii+i2+perm[jj+j2+perm[kk+k2]]] % 12; + gi3 = perm[ii+1+perm[jj+1+perm[kk+1]]] % 12; + + /* Calculate the contribution from the four corners */ + t0 = 0.6 - x0*x0 - y0*y0 - z0*z0; + if(t0<0) + n0 = 0.0; + else + { + t0 *= t0; + n0 = t0 * t0 * dot3(grad3[gi0], x0, y0, z0); + } + t1 = 0.6 - x1*x1 - y1*y1 - z1*z1; + if(t1<0) n1 = 0.0; + else + { + t1 *= t1; + n1 = t1 * t1 * dot3(grad3[gi1], x1, y1, z1); + } + t2 = 0.6 - x2*x2 - y2*y2 - z2*z2; + if(t2<0) + n2 = 0.0; + else + { + t2 *= t2; + n2 = t2 * t2 * dot3(grad3[gi2], x2, y2, z2); + } + t3 = 0.6 - x3*x3 - y3*y3 - z3*z3; + if(t3<0) + n3 = 0.0; + else + { + t3 *= t3; + n3 = t3 * t3 * dot3(grad3[gi3], x3, y3, z3); + } + /* + Add contributions from each corner to get the final noise value. + The result is scaled to stay just inside [-1,1] + */ + return (float)(32.0*(n0 + n1 + n2 + n3)); +} + +void SST_Random_MapSimplexNoise3DFromArray( SST_SimplexNoise _instance, float* _destination, float* _sourceX, float* _sourceY, float* _sourceZ, size_t _numElements) +{ + size_t i; + + if (_destination == NULL || _sourceX == NULL || _sourceY == NULL || _sourceZ == NULL) + return; + + for (i = 0; i < _numElements; i++) + _destination[i] = SST_Random_MapSimplexNoise3D(_instance, _sourceX[i], _sourceY[i], _sourceZ[i]); +} + +float SST_Random_MapSimplexNoise4D( SST_SimplexNoise _instance, float _x, float _y, float _z, float _w) +{ + /* The skewing and unskewing factors are hairy again for the 4D case */ + const double F4 = (sqrtf(5.0)-1.0)/4.0; + const double G4 = (5.0-sqrtf(5.0))/20.0; + double n0, n1, n2, n3, n4; /* Noise contributions from the five corners */ + + /* Skew the (x,y,z,w) space to determine which cell of 24 simplices we're in */ + double s = (_x + _y + _z + _w) * F4; /* Factor for 4D skewing */ + int i = fastfloor(_x + s); + int j = fastfloor(_y + s); + int k = fastfloor(_z + s); + int l = fastfloor(_w + s); + double t = (i + j + k + l) * G4; /* Factor for 4D unskewing */ + double X0 = i - t; /* Unskew the cell origin back to (x,y,z,w) space */ + double Y0 = j - t; + double Z0 = k - t; + double W0 = l - t; + double x0,x1,x2,x3,x4,y0,y1,y2,y3,y4,z0,z1,z2,z3,z4,w0,w1,w2,w3,w4; + int c,c1,c2,c3,c4,c5,c6; + double t0,t1,t2,t3,t4; + int i1, j1, k1, l1; /* The integer offsets for the second simplex corner */ + int i2, j2, k2, l2; /* The integer offsets for the third simplex corner */ + int i3, j3, k3, l3; /* The integer offsets for the fourth simplex corner */ + int ii,jj,kk,ll,gi0,gi1,gi2,gi3,gi4; + int* perm = ((SST_Simplex_Data_t*)_instance)->perm; + + x0 = _x - X0; /* The x,y,z,w distances from the cell origin */ + y0 = _y - Y0; + z0 = _z - Z0; + w0 = _w - W0; + + /* + For the 4D case, the simplex is a 4D shape I won't even try to describe. + To find out which of the 24 possible simplices we're in, we need to + determine the magnitude ordering of x0, y0, z0 and w0. + The method below is a good way of finding the ordering of x,y,z,w and + then find the correct traversal order for the simplex weÆre in. + First, six pair-wise comparisons are performed between each possible pair + of the four coordinates, and the results are used to add up binary bits + for an integer index. + */ + c1 = (x0 > y0) ? 32 : 0; + c2 = (x0 > z0) ? 16 : 0; + c3 = (y0 > z0) ? 8 : 0; + c4 = (x0 > w0) ? 4 : 0; + c5 = (y0 > w0) ? 2 : 0; + c6 = (z0 > w0) ? 1 : 0; + c = c1 + c2 + c3 + c4 + c5 + c6; + + /* + simplex[c] is a 4-vector with the numbers 0, 1, 2 and 3 in some order. + Many values of c will never occur, since e.g. x>y>z>w makes x<z, y<w and x<w + impossible. Only the 24 indices which have non-zero entries make any sense. + We use a thresholding to set the coordinates in turn from the largest magnitude. + The number 3 in the "simplex" array is at the position of the largest coordinate. + */ + i1 = simplex[c][0]>=3 ? 1 : 0; + j1 = simplex[c][1]>=3 ? 1 : 0; + k1 = simplex[c][2]>=3 ? 1 : 0; + l1 = simplex[c][3]>=3 ? 1 : 0; + + /* The number 2 in the "simplex" array is at the second largest coordinate. */ + i2 = simplex[c][0]>=2 ? 1 : 0; + j2 = simplex[c][1]>=2 ? 1 : 0; + k2 = simplex[c][2]>=2 ? 1 : 0; + l2 = simplex[c][3]>=2 ? 1 : 0; + + /* The number 1 in the "simplex" array is at the second smallest coordinate. */ + i3 = simplex[c][0]>=1 ? 1 : 0; + j3 = simplex[c][1]>=1 ? 1 : 0; + k3 = simplex[c][2]>=1 ? 1 : 0; + l3 = simplex[c][3]>=1 ? 1 : 0; + + /* The fifth corner has all coordinate offsets = 1, so no need to look that up. */ + x1 = x0 - i1 + G4; /* Offsets for second corner in (x,y,z,w) coords */ + y1 = y0 - j1 + G4; + z1 = z0 - k1 + G4; + w1 = w0 - l1 + G4; + x2 = x0 - i2 + 2.0*G4; /* Offsets for third corner in (x,y,z,w) coords */ + y2 = y0 - j2 + 2.0*G4; + z2 = z0 - k2 + 2.0*G4; + w2 = w0 - l2 + 2.0*G4; + x3 = x0 - i3 + 3.0*G4; /* Offsets for fourth corner in (x,y,z,w) coords */ + y3 = y0 - j3 + 3.0*G4; + z3 = z0 - k3 + 3.0*G4; + w3 = w0 - l3 + 3.0*G4; + x4 = x0 - 1.0 + 4.0*G4; /* Offsets for last corner in (x,y,z,w) coords */ + y4 = y0 - 1.0 + 4.0*G4; + z4 = z0 - 1.0 + 4.0*G4; + w4 = w0 - 1.0 + 4.0*G4; + + /* Work out the hashed gradient indices of the five simplex corners */ + ii = i & 255; + jj = j & 255; + kk = k & 255; + ll = l & 255; + gi0 = perm[ii+perm[jj+perm[kk+perm[ll]]]] % 32; + gi1 = perm[ii+i1+perm[jj+j1+perm[kk+k1+perm[ll+l1]]]] % 32; + gi2 = perm[ii+i2+perm[jj+j2+perm[kk+k2+perm[ll+l2]]]] % 32; + gi3 = perm[ii+i3+perm[jj+j3+perm[kk+k3+perm[ll+l3]]]] % 32; + gi4 = perm[ii+1+perm[jj+1+perm[kk+1+perm[ll+1]]]] % 32; + + /* Calculate the contribution from the five corners */ + t0 = 0.6 - x0*x0 - y0*y0 - z0*z0 - w0*w0; + if(t0<0) + n0 = 0.0; + else + { + t0 *= t0; + n0 = t0 * t0 * dot4(grad4[gi0], x0, y0, z0, w0); + } + t1 = 0.6 - x1*x1 - y1*y1 - z1*z1 - w1*w1; + if(t1<0) + n1 = 0.0; + else + { + t1 *= t1; + n1 = t1 * t1 * dot4(grad4[gi1], x1, y1, z1, w1); + } + t2 = 0.6 - x2*x2 - y2*y2 - z2*z2 - w2*w2; + if(t2<0) + n2 = 0.0; + else + { + t2 *= t2; + n2 = t2 * t2 * dot4(grad4[gi2], x2, y2, z2, w2); + } + + t3 = 0.6 - x3*x3 - y3*y3 - z3*z3 - w3*w3; + + if(t3<0) + n3 = 0.0; + else + { + t3 *= t3; + n3 = t3 * t3 * dot4(grad4[gi3], x3, y3, z3, w3); + } + t4 = 0.6 - x4*x4 - y4*y4 - z4*z4 - w4*w4; + if(t4<0) + n4 = 0.0; + else + { + t4 *= t4; + n4 = t4 * t4 * dot4(grad4[gi4], x4, y4, z4, w4); + } + + /* Sum up and scale the result to cover the range [-1,1] */ + return (float)(27.0 * (n0 + n1 + n2 + n3 + n4)); +} + +void SST_Random_MapSimplexNoise4DFromArray( SST_SimplexNoise _instance, float* _destination, float* _sourceX, float* _sourceY, float* _sourceZ, float* _sourceW, size_t _numElements) +{ + size_t i; + + if (_destination == NULL || _sourceX == NULL || _sourceY == NULL || _sourceZ == NULL || _sourceW == NULL) + return; + + for (i = 0; i < _numElements; i++) + _destination[i] = SST_Random_MapSimplexNoise4D(_instance, _sourceX[i], _sourceY[i], _sourceZ[i], _sourceW[i]); +} diff --git a/libsst-random/SST_SmallPRNG.c b/libsst-random/SST_SmallPRNG.c new file mode 100644 index 0000000..ad1fa85 --- /dev/null +++ b/libsst-random/SST_SmallPRNG.c @@ -0,0 +1,100 @@ +/* + SST_SmallPRNG.c + Author: Chris Ertel <crertel@762studios.com> + Created: 2/26/2012 + + Purpose: + + Implementation of SmallPRNG + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. +*/ + +#include "RandomFuncTbl.h" + +#define BIT_ROTATE(x,k) (((x)<<(k))|((x)>>(32-(k)))) + +/*************************************************************************/ + +typedef struct SST_SmallPRNG_Private +{ + uint32_t a; + uint32_t b; + uint32_t c; + uint32_t d; +} SST_SmallPRNG_Private; + +static int sprng_random(SST_SmallPRNG_Private* x) +{ + uint32_t e = x->a - BIT_ROTATE(x->b, 27); + x->a = x->b ^ BIT_ROTATE(x->c, 17); + x->b = x->c + x->d; + x->c = x->d + e; + x->d = e + x->a; + return (int)x->d; +} + +/*************************************************************************/ + +static void SmallPRNG_InitFromSeed(void* priv, uint32_t seed) +{ + SST_SmallPRNG_Private* sprng = (SST_SmallPRNG_Private*)priv; + int i; + sprng->a = 0xf1ea5eed; + sprng->b = sprng->c = sprng->d = seed; + + for(i=0; i<20; ++i) + (void)sprng_random(sprng); +} + +/*************************************************************************/ + +static void SmallPRNG_GetFloatArray(void* priv, float* _out, size_t _numElements, float _min, float _max) +{ + SST_SmallPRNG_Private* sprng_data = (SST_SmallPRNG_Private*)priv; + size_t i; + const float diff = _max - _min; + + for (i = 0; i < _numElements; i++) + _out[i] = _min + randIntToFloat(boundInt(sprng_random(sprng_data), 0, SST_RAND_FLOATBITS_MAX)) * diff; +} + +/*************************************************************************/ + +static int SmallPRNG_GetInt(void* priv) +{ + SST_SmallPRNG_Private* sprng_data = (SST_SmallPRNG_Private*)priv; + + return sprng_random(sprng_data); +} + +/*************************************************************************/ + +static void SmallPRNG_GetIntArray(void* priv, int* _out, size_t _numElements, int _min, int _max) +{ + SST_SmallPRNG_Private* sprng_data = (SST_SmallPRNG_Private*)priv; + size_t i; + + for (i = 0; i < _numElements; i++) + { + _out[i] = boundInt(sprng_random(sprng_data), _min, _max); /* TODO: This does redundant operations. Compilers may not be able to optimize. */ + } +} + +/*************************************************************************/ + +/* Function table for SmallPRNG random number generator */ +const SST_PRNG_FuncTable _SST_SmallPRNGFuncTable = +{ + SmallPRNG_InitFromSeed, + SmallPRNG_GetFloatArray, + SmallPRNG_GetInt, + SmallPRNG_GetIntArray, + sizeof(SST_SmallPRNG_Private) +}; diff --git a/libsst-random/libsst-random.vcproj b/libsst-random/libsst-random.vcproj new file mode 100644 index 0000000..85f8034 --- /dev/null +++ b/libsst-random/libsst-random.vcproj @@ -0,0 +1,331 @@ +<?xml version="1.0" encoding="Windows-1252"?> +<VisualStudioProject + ProjectType="Visual C++" + Version="9.00" + Name="libsst-random" + ProjectGUID="{8AA34F81-4045-4613-88B7-6FF58D7E0A7A}" + RootNamespace="libsstrandom" + TargetFrameworkVersion="196613" + > + <Platforms> + <Platform + Name="Win32" + /> + <Platform + Name="x64" + /> + </Platforms> + <ToolFiles> + </ToolFiles> + <Configurations> + <Configuration + Name="Debug|Win32" + OutputDirectory="$(SolutionDir)\Lib\x86" + IntermediateDirectory="$(SolutionDir)Intermediate\$(ConfigurationName)\$(PlatformName)\$(ProjectName)" + ConfigurationType="4" + CharacterSet="2" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + AdditionalIncludeDirectories="..\Lib\Include" + MinimalRebuild="true" + BasicRuntimeChecks="3" + RuntimeLibrary="3" + WarningLevel="4" + WarnAsError="false" + DebugInformationFormat="4" + CompileAs="1" + DisableSpecificWarnings="4996" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLibrarianTool" + OutputFile="$(OutDir)\$(ProjectName)-debug.lib" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Debug|x64" + OutputDirectory="$(SolutionDir)\Lib\x64" + IntermediateDirectory="$(SolutionDir)Intermediate\$(ConfigurationName)\$(PlatformName)\$(ProjectName)" + ConfigurationType="4" + CharacterSet="2" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + TargetEnvironment="3" + /> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + AdditionalIncludeDirectories="..\Lib\Include" + MinimalRebuild="true" + BasicRuntimeChecks="3" + RuntimeLibrary="3" + WarningLevel="4" + WarnAsError="false" + DebugInformationFormat="3" + CompileAs="1" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLibrarianTool" + OutputFile="$(OutDir)\$(ProjectName)-debug.lib" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Release|Win32" + OutputDirectory="$(SolutionDir)\Lib\x86" + IntermediateDirectory="$(SolutionDir)Intermediate\$(ConfigurationName)\$(PlatformName)\$(ProjectName)" + ConfigurationType="4" + CharacterSet="2" + WholeProgramOptimization="1" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + EnableIntrinsicFunctions="true" + AdditionalIncludeDirectories="..\Lib\Include" + RuntimeLibrary="2" + EnableFunctionLevelLinking="true" + WarningLevel="4" + WarnAsError="false" + DebugInformationFormat="3" + CompileAs="1" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLibrarianTool" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Release|x64" + OutputDirectory="$(SolutionDir)\Lib\x64" + IntermediateDirectory="$(SolutionDir)Intermediate\$(ConfigurationName)\$(PlatformName)\$(ProjectName)" + ConfigurationType="4" + CharacterSet="2" + WholeProgramOptimization="1" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + TargetEnvironment="3" + /> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + EnableIntrinsicFunctions="true" + AdditionalIncludeDirectories="..\Lib\Include" + RuntimeLibrary="2" + EnableFunctionLevelLinking="true" + WarningLevel="4" + WarnAsError="false" + DebugInformationFormat="3" + CompileAs="1" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLibrarianTool" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + </Configurations> + <References> + </References> + <Files> + <Filter + Name="Source Files" + Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx" + UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}" + > + <File + RelativePath=".\RandomFuncTbl.h" + > + </File> + <File + RelativePath=".\SST_CMWC.c" + > + </File> + <File + RelativePath=".\SST_Mersenne.c" + > + </File> + <File + RelativePath=".\SST_PRNG.c" + > + </File> + <File + RelativePath=".\SST_SimplexNoise.c" + > + </File> + <File + RelativePath=".\SST_SmallPRNG.c" + > + </File> + </Filter> + <Filter + Name="Header Files" + Filter="h;hpp;hxx;hm;inl;inc;xsd" + UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" + > + <File + RelativePath="..\Lib\Include\SST\SST_PRNG.h" + > + </File> + <File + RelativePath="..\Lib\Include\SST\SST_Random.h" + > + </File> + <File + RelativePath="..\Lib\Include\SST\SST_SimplexNoise.h" + > + </File> + </Filter> + </Files> + <Globals> + </Globals> +</VisualStudioProject> diff --git a/libsst-random/libsst-random.vcxproj b/libsst-random/libsst-random.vcxproj new file mode 100644 index 0000000..d6aee7b --- /dev/null +++ b/libsst-random/libsst-random.vcxproj @@ -0,0 +1,196 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup Label="ProjectConfigurations"> + <ProjectConfiguration Include="Debug|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectGuid>{8AA34F81-4045-4613-88B7-6FF58D7E0A7A}</ProjectGuid> + <RootNamespace>libsstrandom</RootNamespace> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> + <ConfigurationType>StaticLibrary</ConfigurationType> + <PlatformToolset>v110</PlatformToolset> + <CharacterSet>MultiByte</CharacterSet> + <WholeProgramOptimization>true</WholeProgramOptimization> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> + <ConfigurationType>StaticLibrary</ConfigurationType> + <PlatformToolset>v110</PlatformToolset> + <CharacterSet>MultiByte</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> + <ConfigurationType>StaticLibrary</ConfigurationType> + <PlatformToolset>v110</PlatformToolset> + <CharacterSet>MultiByte</CharacterSet> + <WholeProgramOptimization>true</WholeProgramOptimization> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> + <ConfigurationType>StaticLibrary</ConfigurationType> + <PlatformToolset>v110</PlatformToolset> + <CharacterSet>MultiByte</CharacterSet> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <ImportGroup Label="ExtensionSettings"> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <PropertyGroup Label="UserMacros" /> + <PropertyGroup> + <_ProjectFileVersion>11.0.50727.1</_ProjectFileVersion> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <OutDir>$(SolutionDir)\Lib\x86\</OutDir> + <IntDir>$(SolutionDir)Intermediate\$(Configuration)\$(Platform)\$(ProjectName)\</IntDir> + <TargetName>$(ProjectName)-debug</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <OutDir>$(SolutionDir)\Lib\x64\</OutDir> + <IntDir>$(SolutionDir)Intermediate\$(Configuration)\$(Platform)\$(ProjectName)\</IntDir> + <TargetName>$(ProjectName)-debug</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <OutDir>$(SolutionDir)\Lib\x86\</OutDir> + <IntDir>$(SolutionDir)Intermediate\$(Configuration)\$(Platform)\$(ProjectName)\</IntDir> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <OutDir>$(SolutionDir)\Lib\x64\</OutDir> + <IntDir>$(SolutionDir)Intermediate\$(Configuration)\$(Platform)\$(ProjectName)\</IntDir> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <Optimization>Disabled</Optimization> + <AdditionalIncludeDirectories>..\Lib\Include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <MinimalRebuild>false</MinimalRebuild> + <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> + <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> + <WarningLevel>Level4</WarningLevel> + <TreatWarningAsError>false</TreatWarningAsError> + <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> + <CompileAs>CompileAsC</CompileAs> + <DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings> + <MultiProcessorCompilation>true</MultiProcessorCompilation> + <WholeProgramOptimization>true</WholeProgramOptimization> + <StringPooling>true</StringPooling> + <ExceptionHandling>false</ExceptionHandling> + <BufferSecurityCheck>false</BufferSecurityCheck> + <FunctionLevelLinking>true</FunctionLevelLinking> + <CreateHotpatchableImage>false</CreateHotpatchableImage> + <RuntimeTypeInfo>false</RuntimeTypeInfo> + </ClCompile> + <Lib /> + <Lib> + <LinkTimeCodeGeneration>true</LinkTimeCodeGeneration> + </Lib> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Midl> + <TargetEnvironment>X64</TargetEnvironment> + </Midl> + <ClCompile> + <Optimization>Disabled</Optimization> + <AdditionalIncludeDirectories>..\Lib\Include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <MinimalRebuild>false</MinimalRebuild> + <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> + <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> + <WarningLevel>Level4</WarningLevel> + <TreatWarningAsError>false</TreatWarningAsError> + <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> + <CompileAs>CompileAsC</CompileAs> + <MultiProcessorCompilation>true</MultiProcessorCompilation> + <WholeProgramOptimization>true</WholeProgramOptimization> + <StringPooling>true</StringPooling> + <ExceptionHandling>false</ExceptionHandling> + <BufferSecurityCheck>false</BufferSecurityCheck> + <FunctionLevelLinking>true</FunctionLevelLinking> + <CreateHotpatchableImage>false</CreateHotpatchableImage> + <RuntimeTypeInfo>false</RuntimeTypeInfo> + </ClCompile> + <Lib /> + <Lib> + <LinkTimeCodeGeneration>true</LinkTimeCodeGeneration> + </Lib> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <Optimization>MaxSpeed</Optimization> + <IntrinsicFunctions>true</IntrinsicFunctions> + <AdditionalIncludeDirectories>..\Lib\Include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> + <FunctionLevelLinking>true</FunctionLevelLinking> + <WarningLevel>Level4</WarningLevel> + <TreatWarningAsError>false</TreatWarningAsError> + <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> + <CompileAs>CompileAsC</CompileAs> + <MultiProcessorCompilation>true</MultiProcessorCompilation> + <StringPooling>true</StringPooling> + <ExceptionHandling>false</ExceptionHandling> + <BufferSecurityCheck>false</BufferSecurityCheck> + <CreateHotpatchableImage>false</CreateHotpatchableImage> + <RuntimeTypeInfo>false</RuntimeTypeInfo> + </ClCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Midl> + <TargetEnvironment>X64</TargetEnvironment> + </Midl> + <ClCompile> + <Optimization>MaxSpeed</Optimization> + <IntrinsicFunctions>true</IntrinsicFunctions> + <AdditionalIncludeDirectories>..\Lib\Include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> + <FunctionLevelLinking>true</FunctionLevelLinking> + <WarningLevel>Level4</WarningLevel> + <TreatWarningAsError>false</TreatWarningAsError> + <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> + <CompileAs>CompileAsC</CompileAs> + <MultiProcessorCompilation>true</MultiProcessorCompilation> + <StringPooling>true</StringPooling> + <ExceptionHandling>false</ExceptionHandling> + <BufferSecurityCheck>false</BufferSecurityCheck> + <CreateHotpatchableImage>false</CreateHotpatchableImage> + <RuntimeTypeInfo>false</RuntimeTypeInfo> + </ClCompile> + </ItemDefinitionGroup> + <ItemGroup> + <ClInclude Include="RandomFuncTbl.h" /> + <ClInclude Include="..\Lib\Include\SST\SST_PRNG.h" /> + <ClInclude Include="..\Lib\Include\SST\SST_Random.h" /> + <ClInclude Include="..\Lib\Include\SST\SST_SimplexNoise.h" /> + </ItemGroup> + <ItemGroup> + <ClCompile Include="SST_CMWC.c" /> + <ClCompile Include="SST_Mersenne.c" /> + <ClCompile Include="SST_PRNG.c" /> + <ClCompile Include="SST_SimplexNoise.c" /> + <ClCompile Include="SST_SmallPRNG.c" /> + </ItemGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> + <ImportGroup Label="ExtensionTargets"> + </ImportGroup> +</Project> \ No newline at end of file diff --git a/libsst-random/libsst-random.vcxproj.filters b/libsst-random/libsst-random.vcxproj.filters new file mode 100644 index 0000000..71c0ea9 --- /dev/null +++ b/libsst-random/libsst-random.vcxproj.filters @@ -0,0 +1,44 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup> + <Filter Include="Source Files"> + <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier> + <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions> + </Filter> + <Filter Include="Header Files"> + <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier> + <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> + </Filter> + </ItemGroup> + <ItemGroup> + <ClInclude Include="RandomFuncTbl.h"> + <Filter>Source Files</Filter> + </ClInclude> + <ClInclude Include="..\Lib\Include\SST\SST_PRNG.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\Lib\Include\SST\SST_Random.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\Lib\Include\SST\SST_SimplexNoise.h"> + <Filter>Header Files</Filter> + </ClInclude> + </ItemGroup> + <ItemGroup> + <ClCompile Include="SST_CMWC.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="SST_Mersenne.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="SST_PRNG.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="SST_SimplexNoise.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="SST_SmallPRNG.c"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> +</Project> \ No newline at end of file diff --git a/libsst-random/obj/x86-64/release/SST_CMWC.o b/libsst-random/obj/x86-64/release/SST_CMWC.o new file mode 100644 index 0000000000000000000000000000000000000000..3ec7996c564300a9b464bcc6170fa4e2110c13a8 GIT binary patch literal 3120 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 literal 0 HcmV?d00001 diff --git a/libsst-random/obj/x86-64/release/SST_Mersenne.o b/libsst-random/obj/x86-64/release/SST_Mersenne.o new file mode 100644 index 0000000000000000000000000000000000000000..926ccb94f40489d31c5ae43bce754ea1537588ed GIT binary patch literal 3368 zcmb<-^>JfjWMqH=Mg}_u1P><4z_5Z7!FB*M9T@l+xEVq{I-hpd{^@r8<I#Gcf;)}> z{ejOO{8|TIOL}x3^0@e_`2nK`=OLKzq0jsg2R`!)@PbVE%pZ3!_AtbNH=U&~Izyi{ zroQ?A|9^eA>kDhwC#9_2t}kBeLpXIp-L5Y>U4L}DKIwFQ(e3)9)AdQW>l1B|;Gb^S zH#5J39Pxtj0>ng*&e|Iu-L5x0I$eK&>F$ODoD2*eovt4|8f!lkFflOjx6WZ?VDLEZ z`T^va<E}42)XP2w28M3e7alV_dPQ16A|BnYKRg&ObTg<jFfcT99)d_VA7J$8<v~(# zqMJb#<aEvpovv>nYS0V_ec_RO$)oX5FUZzjo~aPSLw|TMp6V9r_I-2lrQyZy&^OJG z7&9;3-@q}`@KmQjv+E1S#@ZK;7#JA%`%?e^|NpX!#_l`#h{>b3tK`rB{~p~$xh)SA zlzo~1K^k0tc(Cr_WMF^?7AWwL0|vy0C;^+^c*uZ_fdQxQJ-S^#c=QG^f+MhV0yqM} zLTE7qkMb9trB6ISfe(rGA0EfSu?`7o*B{-XPdWua5e`b=uN|Pq{|7m$TVw)+>jB}i zbR2vkXLup=Kx!v@jz@Rshh825kU9{vlV^fQv+D;&P(sRQVqhrSHUZ*-V2|cE4j!Gg z7d$#kPk3~O9{9{J=(^`Kzo739k8alspv3o?U%++8XZ{$lu<H{KXtI0l4R$sn#hmcy zm0<$AsPp&>?Z5y3@B07$Kf^wdPdbmkIPvHI|IXtt8vgwM|CvA1^~q=c2(W?79-ssR zHp<%dK+)<69?eG_q9Km+XnrH%(OLTfEDH;t&f_o6{rUg@Bsdp>oNwUKS^L1Fv-E~X zXXu4a-!m?qt|vUYT_1ql4tJ~t*bIbYZy-Ci4&=6j-JvJCUC(qL>pcHL8YF<?vI|A~ zKrS<gjy(+W5MF!&TJHS+U+>M}?(A%(pb?r>npaY)V5(=LXP|3V3g#Ks8Jg)CnCO{l zLc|q}3=GW-%nU4HhKoQMj8#Dlj1>Zm(md=O6Brp7WEdbAB<%<$_ypRRoO#)5c-T3h zayB4w1_p*85bX$+XYvIr0O^kbi8C-Td<LZ}m^|}4MvwxKd<|5-2}Hx>nQB4O3<?Yk z40Ax@3=9l&K{QO>wV9b|GFS=NjR!z-3=9lPAR4A779tNa;{iyVfq|g{M8o7kX5>NC zfP}GOkds*$KK{oh$BeZmU|?WoV8*7Lfti5?LtKD?fq@Ch9B>#jFfhnN#bJDK*fKCM zXh6j$LrnsQDFXw85mda52_gXwO9lo852!c?)JfnlWME*3hl($Sii5+Afq@|(Dt;U) z4h}DfkqpcXtWXvz#moRo38-Qq9y0?pae_EVn3;hci3ee}FfcF(BAE~JCs-ypI3(UT zwWv5XFE3RunV~2#FU2#jBqZN0CqJ=-At}EU%xB0gi3dsL=Q6+)$9v{wmbew==LV;y zrXWP!Q%k^F9gB(*D^Y|!^GeY95JmCGZg4BjOAbj)%1H&gj=>y4F@S=dhk=1X1<Hp} zp!5ThgT)Ihq+sH(cmbsYkRF&gEM6o)f(#7c6aq2_7B8SQ4Uz(hfiQ>-!jQHHC`~~y zEd3;aB*AeD5r?Ip1~hS)I~Smd!`yiUO&sRVCurg@cQWV|SLT)^CNbz0mlQ$h3>d2@ zH78N8B(<W1K`$k-B#}WcskoRy4=h@g4-rYu&&^HED`C*f%P&dQbN36?EiOq+&W5T= z&4^DcO3Z~u1=I!PQK0Yyg*_XZc361Yqh(!?T4bft3=H7h4O0)3Q-DS|EFM8=1f&-# z%m5QtgT^s5+rhLm)T7x8lK`0kV}ocN1_p30Bv-!~)PCf&1Twb)YCp()5Fds?;RR!Z zXhR(Sw}5&Smi|Eg2bCgFVYvV8p!OSp3`4?ep!S<0iGi3f|HEi^sD6+fGJXivk1Pga z!}NjJAPlObKw{|re*x1Ek_0J)Vwn4(T!wHQ{+|I=xB{vW<bP192o;9=UyuP*Z$K3x zQ4S!*3=9luNMax+nseag14s@TzW@a`0|Ubhs0L8a0#w$Z+Yhn^J?((ZX@C~hvq2mr J3^fie0suCDm-zqy literal 0 HcmV?d00001 diff --git a/libsst-random/obj/x86-64/release/SST_PRNG.o b/libsst-random/obj/x86-64/release/SST_PRNG.o new file mode 100644 index 0000000000000000000000000000000000000000..3d8a652adbac3030d439f6cfad18b0885cd86102 GIT binary patch literal 3680 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 literal 0 HcmV?d00001 diff --git a/libsst-random/obj/x86-64/release/SST_SimplexNoise.o b/libsst-random/obj/x86-64/release/SST_SimplexNoise.o new file mode 100644 index 0000000000000000000000000000000000000000..59248125c627012ca18561e7dad0334388e4a5bf GIT binary patch literal 18056 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 literal 0 HcmV?d00001 diff --git a/libsst-random/obj/x86-64/release/SST_SmallPRNG.o b/libsst-random/obj/x86-64/release/SST_SmallPRNG.o new file mode 100644 index 0000000000000000000000000000000000000000..0ead9b319c79e76fa093bcd5c8fcb6ee111311bb GIT binary patch literal 2992 zcmb<-^>JfjWMqH=Mg}_u1P><4z+k|EU^{@B4h(z@+zg=}oliS!|8%?l@n}6z!JWqc z{=jDseyszqB|SP1d0c$e{D9Ge^AJq<&}aUL1E2W?ctIw7=8roVdl+KCo6gb~ouN+} zQ{Vjm|G&Q5^@X+TlTy}h*B7t#A)Gp)Zr2x`u0Oh6pLDvu=yv_l>H4JG^@%n}@K3kv zo0;E1j(EX%0b-&@XYC7*Zr2yx0$|dC<=_cc%|o3RI$i&O1p-*Wlmo}X6a0pUK<rM4 z$^Z@!r`v&t5h4mz7{Jr*`UfTiQ6hjO!UNR=wY>R_0>}ZKrB6WO9-Xc~Ji1+f9A|hN z_v#~v)gAhzGXSLLM>mA(1Y7%~8$xvkupD>&0t%wnAV>Z1=sf;H{r~^}&8}Y<n`^%a z*S(r>5*%*99?fqYJUVMHcyyMY@aPOZ@R?uGb<byhLEjx7-L4lrI$b|}<`;0?@tHpc zEbRKk<GAY!u)*G7m-ULYf_NU?t|vTtWtcp=T|a;<+x74N|6Tw8|7X|-lI=YHBK+U~ z|DDHQ@c;Y&|1*E2>yyv?5nuzEJ(^u#FoKP;c0EwEdV)vu5r=4aC`f=p0W1p*0+8Xc z|Nj3+IN!jdv-W{UXXy=(&d>{;zGqxIT~By)yFLK99qw2Quo(!)-avLNFUV~NyF*WO zyPoMh)_MNLs=xpLccQrLLeV~u%M7Ap4}&~J3KoDW{{O$;o59`L*-AkpG^sSNq*TFF z&qU8a*Q^xGGpsW-(=#y9Gt-2KD;OCVni-fGSVFZkh(H;PRY44l6#|UXJnS437#SF3 z7$6uV?Fc6L1lpLKdD&`s*g;tiByR%}XJB9m0@038c_v@50+4(RNSuLzp%z5L<tyOw zH6U>Y28K)!4VO;=%PTN2Fw6moGcYjB1<^2h*Jfs>$zUa5Hy!}VF)%PFfoPbTScp8x zj0Yfb1_p)-5Dk+DnUM!k0}{rDL1hgK!^i*F<e0IRL<|hf49wV+GcYr-V2BGcFfcG7 znF9`E1_lO@n?d3*J~(U{7#K96>L)`@0*5IB1A`e<Tma-?SXeSJF!(~nE1}}xFl1n0 zNQH`vF+mIhhZ_R}Lm5=u0xAv;FNhKbW(HO$3zcGK0Hp*}F%XZLffGbwU}gq(46z;t z1_nVS^EF^9f`dcigL4yeasq<<-1U+fiW2iuJo8FI^4)Us6H6G9@=L*dhT?*vy!3dG zY<?~STtmEPUS^3~QGRZ4YHA9SuzP9=SifUYQDP;kxMyAoh5$raJc?V~O7oIK5|eU3 zA<4jC4s|am*mxKi7*wEq7zGM`kQ^+2U?Bz*hs6&pKf}af@go5>2qq4TA5c00NrB7; zVGtXHA$1@qZ9y<B9VLJy!Ep=`hoz$iG;x?a7ods5+<62|9Olj^XyPz;GUydo=9VNT zG3XVS6hY_=7^^5XCsD5?wW5SUFD0=gkwGu1xR^l?ELxNg5lPO^%}vcKVbIIVFG<yN z_Y2i6E=f$zhN?=<h)*j@%!R}R)B$8tpzs8RF&mnGSa@zg4rB%fq?`-UAkDx4&gC%m z5K#t(6;K0V@d!#IAbVix04A;mH50uA`G96G%v_KeFgA$RVPF8~MsoFo$`O#67}h}z z1ep)A2Zll61!IF~Lmd7;0QEmC{ek=sDoxP+ZwK|i0mv{UtOK>*6iE!k1i2NNc8BT* zi6P@esD5NI5F4f+#0FtdT?G<D_kRXVKS&a!5Q<^$hjJOharj>WTI8*ODg^l-R64@+ z!{Q%QAHb}FDg{#~p!(CmJOqK}9B_I>cRNUR2DIv#0o4F%;eyH<bo)VW!e&1MH2#)= L3`4?D<KQ9yusZcg literal 0 HcmV?d00001 diff --git a/libsst-wm/API.c b/libsst-wm/API.c new file mode 100644 index 0000000..0a7feed --- /dev/null +++ b/libsst-wm/API.c @@ -0,0 +1,282 @@ +/* + API.c + Author: Patrick Baggett <ptbaggett@762studios.com> + Created: 1/8/2013 + + Purpose: + + The libsst-wm API. Mostly calls into the current driver. + + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ +#include "APIPrivate.h" +#include <stdlib.h> +#include <stdio.h> + +/******************************************************************************/ + +#if defined(HAVE_XLIB) +extern struct SST_WM_Driver XlibDriver; +#endif + +#if defined(_WIN32) +extern struct SST_WM_Driver Win32Driver; +#endif + +/******************************************************************************/ + +const static struct SST_WM_Driver* drivers[] = { + #if defined(HAVE_XLIB) + &XlibDriver, + #endif + #if defined(_WIN32) + &Win32Driver, + #endif + NULL +}; + +static const struct SST_WM_Driver* driver = NULL; + +/******************************************************************************/ + +int SST_WM_Init(void) { + size_t i; + /* Try to initialize a driver. If it fails, then try the next. First successful one wins */ + for(i=0; drivers[i] != NULL; i++) { + if(drivers[i]->init() != 0) { + driver = drivers[i]; + printf("libsst-wm: Using driver \"%s\"", driver->name); + return 1; + } + } + + /* No suitable driver found */ + return 0; +} + +/******************************************************************************/ + +void SST_WM_Shutdown(void) { + if(driver != NULL) { + driver->shutdown(); + driver = NULL; + } +} + +/******************************************************************************/ + +SST_DisplayTarget SST_WM_CreateDisplayTarget(size_t adapterIndex, size_t screenIndexOrMultihead) { + return driver->window->CreateDisplayTarget(adapterIndex, screenIndexOrMultihead); +} + +/******************************************************************************/ + +size_t SST_WM_GetDisplayTargetScreenCount(SST_DisplayTarget target) { + return driver->window->GetDisplayTargetScreenCount(target); +} + +/******************************************************************************/ + +SST_Window SST_WM_CreateWindowOnScreen(SST_DisplayTarget target, size_t screenIndex, uint32_t x, uint32_t y, uint32_t width, uint32_t height, const char* title) { + return driver->window->CreateWindowOnScreen(target, screenIndex, x, y, width, height, title); +} + +/******************************************************************************/ + +SST_DisplayTarget SST_WM_GetWindowDisplayTarget(SST_Window window) { + return driver->window->GetWindowDisplayTarget(window); +} + +/******************************************************************************/ + +void SST_WM_SetWindowText(SST_Window window, const char* titleBar) { + driver->window->SetWindowText(window, titleBar); +} + +/******************************************************************************/ + +void SST_WM_GetWindowRect(SST_Window window, SST_Rect* rectReturn) { + driver->window->GetWindowRect(window, rectReturn); +} + +/******************************************************************************/ + +void SST_WM_MoveWindowOnScreen(SST_Window window, size_t screenIndex, uint32_t x, uint32_t y) { + driver->window->MoveWindowOnScreen(window, screenIndex, x, y); +} + +/******************************************************************************/ + +void SST_WM_ResizeWindow(SST_Window window, uint32_t width, uint32_t height) { + driver->window->ResizeWindow(window, width, height); +} + +/******************************************************************************/ + +int SST_WM_ShowDialogBox(SST_DisplayTarget target, SST_Window parent, const char* caption, const char* message, const char** buttons, int nrButtons) { + return driver->window->ShowDialogBox(target, parent, caption, message, buttons, nrButtons); +} + +/******************************************************************************/ + +void SST_WM_SetWindowState(SST_Window window, SST_WMWindowState state, uint32_t param) { + driver->window->SetWindowState(window, state, param); +} + +/******************************************************************************/ + +void SST_WM_SetDisplayTargetState(SST_DisplayTarget target, SST_WMDisplayTargetState state, uint32_t param) { + driver->window->SetDisplayTargetState(target, state, param); +} + +/******************************************************************************/ + +void SST_WM_DestroyWindow(SST_Window window) { + driver->window->DestroyWindow(window); +} + +/******************************************************************************/ + +void SST_WM_DestroyDisplayTarget(SST_DisplayTarget target) { + driver->window->DestroyDisplayTarget(target); +} + +/******************************************************************************/ + +SST_GraphicsEnumerator SST_WM_CreateGraphicsEnumerator(void) { + return driver->enumf->CreateGraphicsEnumerator(); +} + +/******************************************************************************/ + +size_t SST_WM_GetEnumAdapterCount(SST_GraphicsEnumerator enumerator) { + return driver->enumf->GetEnumAdapterCount(enumerator); +} + +/******************************************************************************/ + +void SST_WM_GetEnumAdapterName(SST_GraphicsEnumerator enumerator, size_t adapterIndex, char* nameReturn, size_t* bufferSize) { + driver->enumf->GetEnumAdapterName(enumerator, adapterIndex, nameReturn, bufferSize); +} + +/******************************************************************************/ + +size_t SST_WM_GetEnumScreenCount(SST_GraphicsEnumerator enumerator, size_t adapterIndex) { + return driver->enumf->GetEnumScreenCount(enumerator, adapterIndex); +} + +/******************************************************************************/ + +void SST_WM_GetEnumVideoModes(SST_GraphicsEnumerator enumerator, size_t adapterIndex, size_t screenIndex, SST_VideoMode* modesReturn, size_t* modeCountReturn) { + driver->enumf->GetEnumVideoModes(enumerator, adapterIndex, screenIndex, modesReturn, modeCountReturn); +} + +/******************************************************************************/ + +void SST_WM_GetEnumCurrentVideoMode(SST_GraphicsEnumerator enumerator, size_t adapterIndex, size_t screenIndex, SST_VideoMode* mode) { + driver->enumf->GetEnumCurrentVideoMode(enumerator, adapterIndex, screenIndex, mode); +} + +/******************************************************************************/ + +void SST_WM_DestroyGraphicsEnumerator(SST_GraphicsEnumerator enumerator) { + driver->enumf->DestroyGraphicsEnumerator(enumerator); +} + +/******************************************************************************/ + +int SST_WM_GetEvent(SST_DisplayTarget target, SST_WMEvent* eventReturn) { + return driver->event->GetEvent(target, eventReturn); +} + +/******************************************************************************/ + +int SST_WM_SendUserEvent(SST_DisplayTarget target, const SST_WMEvent* event) +{ + EventQueue* eq; + SST_WMEvent* newEvent; + + eq = driver->event->getUserEventQueue(target); + + driver->event->lockUserEventQueue(target); + newEvent = AllocSlotInEQ(eq); + if(newEvent) + memcpy(newEvent, event, sizeof(SST_WMEvent)); + driver->event->unlockUserEventQueue(target); + + return (newEvent != NULL); +} + +/******************************************************************************/ + +SST_OpenGLContext SST_WM_CreateOpenGLContext(SST_DisplayTarget target, SST_WMOpenGLType apiType, const SST_OpenGLContextAttributes* attribs, SST_OpenGLContextAttributes* selectedAttribsReturn) { + return driver->opengl->CreateOpenGLContext(target, apiType, attribs, selectedAttribsReturn); +} + +/******************************************************************************/ + +SST_OpenGLContext SST_WM_CreateSlaveOpenGLContext(SST_OpenGLContext masterGLContext) { + return driver->opengl->CreateSlaveOpenGLContext(masterGLContext); +} + +/******************************************************************************/ + +void SST_WM_SwapOpenGLBuffers(SST_OpenGLContext ctx) { + driver->opengl->SwapOpenGLBuffers(ctx); +} + +/******************************************************************************/ + +int SST_WM_BindOpenGLContext(SST_OpenGLContext ctx, SST_Window window) { + return driver->opengl->BindOpenGLContext(ctx, window); +} + +/******************************************************************************/ + +void SST_WM_DestroyOpenGLContext(SST_OpenGLContext ctx) { + driver->opengl->DestroyOpenGLContext(ctx); +} + +/******************************************************************************/ + +int SST_WM_EnableSoftwareRendering(SST_Window window) { + return driver->render->EnableSoftwareRendering(window); +} + +/******************************************************************************/ + +void SST_WM_DisableSoftwareRendering(SST_Window window) { + driver->render->DisableSoftwareRendering(window); +} + +/******************************************************************************/ + +void* SST_WM_LockBackbuffer(SST_Window window, size_t* pitchReturn) { + return driver->render->LockBackbuffer(window, pitchReturn); +} + +/******************************************************************************/ + +void SST_WM_UnlockBackbuffer(SST_Window window) { + driver->render->UnlockBackbuffer(window); +} + +/******************************************************************************/ + +int SST_WM_SetVideoModeOnScreen(SST_DisplayTarget target, size_t screenIndex, const SST_VideoMode* vmode) { + return driver->video->SetVideoModeOnScreen(target,screenIndex,vmode); +} + +/******************************************************************************/ + +int SST_WM_GetVideoModeOnScreen(SST_DisplayTarget target, size_t screenIndex, SST_VideoMode* vmodeReturn) { + return driver->video->GetVideoModeOnScreen(target, screenIndex, vmodeReturn); +} diff --git a/libsst-wm/APIPrivate.h b/libsst-wm/APIPrivate.h new file mode 100644 index 0000000..a93b39c --- /dev/null +++ b/libsst-wm/APIPrivate.h @@ -0,0 +1,104 @@ +/* + APIPrivate.h + Author: Patrick Baggett <ptbaggett@762studios.com> + Created: 4/29/2014 + + Purpose: + + Private API used internally for different WM drivers + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ + +#pragma once + +#ifndef _APIPRIVATE_H +#define _APIPRIVATE_H + +#include <SST/SST_WM.h> +#include "EventQueue.h" + +struct SST_WM_WindowFuncs +{ + SST_DisplayTarget (*CreateDisplayTarget)(size_t adapterIndex, size_t screenIndexOrMultihead); + size_t (*GetDisplayTargetScreenCount)(SST_DisplayTarget target); + SST_Window (*CreateWindowOnScreen)(SST_DisplayTarget target, size_t screenIndex, uint32_t x, uint32_t y, uint32_t width, uint32_t height, const char* title); + SST_DisplayTarget (*GetWindowDisplayTarget)(SST_Window window); + void (*SetWindowText)(SST_Window window, const char* titleBar); + void (*GetWindowRect)(SST_Window window, SST_Rect* rectReturn); + void (*MoveWindowOnScreen)(SST_Window window, size_t screenIndex, uint32_t x, uint32_t y); + void (*ResizeWindow)(SST_Window window, uint32_t width, uint32_t height); + int (*ShowDialogBox)(SST_DisplayTarget target, SST_Window parent, const char* caption, const char* message, const char** buttons, int nrButtons); + void (*SetWindowState)(SST_Window window, SST_WMWindowState state, uint32_t param); + void (*SetDisplayTargetState)(SST_DisplayTarget target, SST_WMDisplayTargetState state, uint32_t param); + void (*DestroyWindow)(SST_Window window); + void (*DestroyDisplayTarget)(SST_DisplayTarget target); +}; + +struct SST_WM_EnumFuncs +{ + SST_GraphicsEnumerator (*CreateGraphicsEnumerator)(void); + size_t (*GetEnumAdapterCount)(SST_GraphicsEnumerator enumerator); + void (*GetEnumAdapterName)(SST_GraphicsEnumerator enumerator, size_t adapterIndex, char* nameReturn, size_t* bufferSize); + size_t (*GetEnumScreenCount)(SST_GraphicsEnumerator enumerator, size_t adapterIndex); + void (*GetEnumVideoModes)(SST_GraphicsEnumerator enumerator, size_t adapterIndex, size_t screenIndex, SST_VideoMode* modesReturn, size_t* modeCountReturn); + void (*GetEnumCurrentVideoMode)(SST_GraphicsEnumerator enumerator, size_t adapterIndex, size_t screenIndex, SST_VideoMode* mode); + void (*DestroyGraphicsEnumerator)(SST_GraphicsEnumerator enumerator); +}; + +struct SST_WM_EventFuncs +{ + int (*GetEvent)(SST_DisplayTarget target, SST_WMEvent* eventReturn); + + /* These aren't public API, but they are driver-specific */ + EventQueue* (*getUserEventQueue)(SST_DisplayTarget target); + void (*lockUserEventQueue)(SST_DisplayTarget target); + void (*unlockUserEventQueue)(SST_DisplayTarget target); +}; + +struct SST_WM_OpenGLFuncs +{ + SST_OpenGLContext (*CreateOpenGLContext)(SST_DisplayTarget target, SST_WMOpenGLType apiType, const SST_OpenGLContextAttributes* attribs, SST_OpenGLContextAttributes* selectedAttribsReturn); + SST_OpenGLContext(*CreateSlaveOpenGLContext)(SST_OpenGLContext masterGLContext); + void (*SwapOpenGLBuffers)(SST_OpenGLContext ctx); + int (*BindOpenGLContext)(SST_OpenGLContext ctx, SST_Window window); + void (*DestroyOpenGLContext)(SST_OpenGLContext ctx); +}; + +struct SST_WM_RenderFuncs +{ + int (*EnableSoftwareRendering)(SST_Window window); + void (*DisableSoftwareRendering)(SST_Window window); + void* (*LockBackbuffer)(SST_Window window, size_t* pitchReturn); + void (*UnlockBackbuffer)(SST_Window window); +}; + +struct SST_WM_VideoModeFuncs +{ + int (*SetVideoModeOnScreen)(SST_DisplayTarget target, size_t screenIndex, const SST_VideoMode* vmode); + int (*GetVideoModeOnScreen)(SST_DisplayTarget target, size_t screenIndex, SST_VideoMode* vmodeReturn); + +}; + +struct SST_WM_Driver +{ + const char* name; + int (*init)(); + void (*shutdown)(); + const struct SST_WM_WindowFuncs* window; /* SST_WMWindow.h */ + const struct SST_WM_EnumFuncs* enumf; /* SST_WMEnum.h */ + const struct SST_WM_EventFuncs* event; /* SST_WMEvent.h */ + const struct SST_WM_OpenGLFuncs* opengl; /* SST_WMOpenGL.h */ + const struct SST_WM_RenderFuncs* render; /* SST_WMREnder.h */ + const struct SST_WM_VideoModeFuncs* video; /* SST_WMVideoMode.h */ +}; + + +#endif diff --git a/libsst-wm/EventQueue.h b/libsst-wm/EventQueue.h new file mode 100644 index 0000000..1084adb --- /dev/null +++ b/libsst-wm/EventQueue.h @@ -0,0 +1,147 @@ +/* + EventQueue.h + Author: Patrick Baggett <ptbaggett@762studios.com> + Created: 6/18/2012 + + Purpose: + + Common event queue code for libsst-wm implementations + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ + +#pragma once + +#ifndef _EVENTQUEUE_H +#define _EVENTQUEUE_H + +#include <SST/SST_WMEvent.h> +#include <SST/SST_Build.h> +#include <stdlib.h> + +typedef struct EventQueue +{ + SST_WMEvent* events; + size_t head; /* Index of next item to add (i.e. unused slot) */ + size_t tail; /* Index of next item to remove (i.e. used slot) */ + size_t count; /* Number of items in the queue */ + size_t storageSize; /* Size of the backing storage */ +} EventQueue; + +#define EQ_DEFAULT_SIZE 32 /* Default capacity of the event queue. It may grow beyond this. */ + +/*************************************************************************/ + +/* Initialize an event queue structure, returning non-zero if successful */ +static INLINE int InitEQ(EventQueue* q) +{ + /* Allocate raw storage for event queue */ + q->events = (SST_WMEvent*)malloc(EQ_DEFAULT_SIZE * sizeof(SST_WMEvent)); + if(q->events == NULL) + return 0; + + /* Initialize storage */ + q->head = 0; + q->tail = 0; + q->count = 0; + q->storageSize = EQ_DEFAULT_SIZE; + + return 1; +} + +/*************************************************************************/ + +/* Allocate a slot from the queue (as if adding) and return pointer. This manually +eliminates copying a SST_WMEvent structure that most "enqueue" operation require. */ +static INLINE SST_WMEvent* AllocSlotInEQ(EventQueue* q) +{ + SST_WMEvent* slot; + + /* Need to increase capacity? */ + if(q->head == q->tail && q->count == q->storageSize) + { + const size_t newSize = q->storageSize * 2; + SST_WMEvent* events; + + /* Expand the queue */ + events = realloc(q->events, newSize * sizeof(SST_WMEvent)); + if(events == NULL) + return NULL; + + /* All 'count' items from [0,tail] need to be moved to [oldSize, oldSize+count] */ + if(q->tail != 0) + { + /* + 1) A full queue + v--h + [G][H][A][B][C][D][E][F] + ^--t + + 2) Resized + v--h + [G][H][A][B][C][D][E][F][ ][ ][ ][ ][ ][ ][ ][ ] + ^--t + + 3) Shift elements from 0 to tail to end, update head ptr + v--h + [ ][ ][A][B][C][D][E][F][G][H][ ][ ][ ][ ][ ][ ] + ^--t + + */ + + /* Shift elements */ + memmove(&events[q->storageSize], &events[0], q->tail * sizeof(SST_WMEvent)); + + } + + /* Adjust head pointer to point to next empty slot */ + q->head = q->tail + q->storageSize; + + /* Update storage fields */ + q->storageSize = newSize; + q->events = events; + } /* if(needed to increase capacity) */ + + /* Get the pointer to the slot where the event may be stored */ + slot = &q->events[q->head]; + + /* Advance the head pointer by 1 */ + q->head = (q->head + 1) % q->storageSize; + q->count += 1; + + /* Return the slot */ + return slot; +} + +static INLINE int RemoveFromEQ(EventQueue* q, SST_WMEvent* event) +{ + /* Completely empty? */ + if(q->head == q->tail && q->count != q->storageSize) + return 0; + + /* Copy the structure */ + *event = q->events[q->tail]; + + /* Advance the tail pointer by 1 */ + q->tail = (q->tail + 1) % q->storageSize; + q->count -= 1; + + /* OK */ + return 1; +} + +static INLINE void DestroyEQ(EventQueue* q) +{ + if(q->events != NULL) + free(q->events); +} + +#endif + diff --git a/libsst-wm/MacOSX/MacOSXPrivate.h b/libsst-wm/MacOSX/MacOSXPrivate.h new file mode 100644 index 0000000..a435e37 --- /dev/null +++ b/libsst-wm/MacOSX/MacOSXPrivate.h @@ -0,0 +1,32 @@ +/* + MacOSXPrivate.h + Author: Patrick Baggett <ptbaggett@762studios.com> + Created: 1/7/2012 + + Purpose: + + Private defintions and functions for MacOS X implementation of libsst-wm + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ + +#pragma once + +#ifndef _MACOSXPRIVATE_H +#define _MACOSXPRIVATE_H + +typedef struct SST_GraphicsEnumerator_MacOSX +{ + size_t nrAdapters; + size_t nrScreens; +} SST_GraphicsEnumerator_MacOSX; + +#endif + diff --git a/libsst-wm/MacOSX/SST_WMEnum_MacOSX.m b/libsst-wm/MacOSX/SST_WMEnum_MacOSX.m new file mode 100644 index 0000000..2f23f4f --- /dev/null +++ b/libsst-wm/MacOSX/SST_WMEnum_MacOSX.m @@ -0,0 +1,145 @@ +/* + SST_WMEnum_MacOSX.m + Author: Patrick Baggett <ptbaggett@762studios.com> + Created: 11/16/2012 + + Purpose: + + Enumerates graphics adapters and screens on MacOS X + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ + +#import <AppKit/AppKit.h> +#import <Foundation/Foundation.h> +#import <IOKit/IOKitLib.h> + +#include <SST/SST_WM.h> +#include "MacOSXPrivate.h" + +#include <string.h> +#include <stdlib.h> + +/******************************************************************************/ + +SST_GraphicsEnumerator SST_WM_CreateGraphicsEnumerator(void) +{ + SST_GraphicsEnumerator_MacOSX* enumerator; + uint32_t count = 0, i; + CGDirectDisplayID* ids; + + /* Get list of active displays */ + CGGetActiveDisplayList(UINT32_MAX, NULL, &count); + if(count == 0) + return NULL; + + /* Allocate array of displays, then fetch */ + ids = malloc(sizeof(CGDirectDisplayID) * count); + if(ids == NULL) + return NULL; + if(CGGetActiveDisplayList(count, ids, &count) != kCGErrorSuccess) + { + free(ids); + return NULL; + } + + /* Match GPU to display */ + for(i=0; i<count; i++) + { + io_service_t port = CGDisplayIOServicePort(ids[i]); /* Port is owned by CG, don't release */ + + /* TODO: derp how does one do this using I/O Kit? */ + + + } + + /* Allocate enumerator object */ + enumerator = malloc(sizeof(SST_GraphicsEnumerator_MacOSX)); + if(enumerator == NULL) + return NULL; + + + + + return (SST_GraphicsEnumerator)enumerator; +} + +/******************************************************************************/ + +size_t SST_WM_GetEnumAdapterCount(SST_GraphicsEnumerator enumerator) +{ + /* TODO: Implement */ + return 1; +} + +/******************************************************************************/ + +void SST_WM_GetEnumAdapterName(SST_GraphicsEnumerator enumerator, size_t adapterId,char* nameReturn, size_t* bufferSize) +{ + /* TODO: Implement fully */ + const char* s = "Default Adapter"; + + /* Query name length */ + if(nameReturn == NULL) + *bufferSize = strlen(s) + 1; + else + { + size_t copyAmount; + + /* Nothing to do? */ + if(*bufferSize == 0) + return; + + /* Use min(len, (*bufferSize)-1) */ + copyAmount = strlen(s); + if(copyAmount > (*bufferSize)-1) + copyAmount = (*bufferSize)-1; + + memcpy(nameReturn, s, copyAmount); + nameReturn[copyAmount] = '\0'; + } +} + +/******************************************************************************/ + +size_t SST_WM_GetEnumScreenCount(SST_GraphicsEnumerator enumerator, size_t adapterId) +{ + /* TODO: Implement */ + + return 1; +} + +/******************************************************************************/ + +void SST_WM_GetEnumVideoModes(SST_GraphicsEnumerator enumerator, size_t adapterId, size_t screenId, SST_VideoMode* modesReturn, size_t* modeCountReturn) +{ + /* TODO: Implement */ + +} + +/******************************************************************************/ + +void SST_WM_GetEnumCurrentVideoMode(SST_GraphicsEnumerator enumerator, size_t adapterId, size_t screenId, SST_VideoMode* mode) +{ + /* TODO: Implement */ +} + +/******************************************************************************/ + +void SST_WM_DestroyGraphicsEnumerator(SST_GraphicsEnumerator enumerator) +{ + /* TODO: Implement */ + SST_GraphicsEnumerator_MacOSX* enumMac = (SST_GraphicsEnumerator_MacOSX*)enumerator; + + free(enumMac); +} + +/******************************************************************************/ + diff --git a/libsst-wm/Makefile b/libsst-wm/Makefile new file mode 100644 index 0000000..a193b60 --- /dev/null +++ b/libsst-wm/Makefile @@ -0,0 +1,53 @@ +# libsst-wm/Makefile +# Author: Patrick Baggett <ptbaggett@762studios.com> +# Created: 11/16/2012 +# +# Purpose: +# +# Makefile for libsst-wm +# +# License: +# +# This program is free software. It comes without any warranty, to +# the extent permitted by applicable law. You can redistribute it +# and/or modify it under the terms of the Do What The Fuck You Want +# To Public License, Version 2, as published by Sam Hocevar. See +# http://sam.zoy.org/wtfpl/COPYING for more details. + +BINNAME := $(DIST)/libsst-wm.a +ifeq ($(TARGET),debug) + BINNAME := $(subst .a,_d.a, $(BINNAME)) +endif + +# Now, include the window system drivers (detection occurs inside) +#include Win32/sources.mk +#include RaspPi/sources.mk +include Xlib/sources.mk + +SRC += API.c + +OBJ := $(addprefix obj/$(ARCH)/$(TARGET)/,$(subst .m,.o,$(subst .c,.o,$(SRC)))) +$(shell mkdir -p obj/$(ARCH)/$(TARGET)) +$(shell mkdir -p obj/$(ARCH)/$(TARGET)/Xlib) +$(shell mkdir -p obj/$(ARCH)/$(TARGET)/RaspPi) +$(shell mkdir -p obj/$(ARCH)/$(TARGET)/Win32) +$(shell mkdir -p obj/$(ARCH)/$(TARGET)/MacOSX) + +$(BINNAME): $(OBJ) + $(AR) cru $@ $+ + $(RANLIB) $@ + +# CLEAN +clean: + @-rm -r -f obj $(DIST)/libsst-wm*.a + +# *.c files to *.o files +obj/$(ARCH)/$(TARGET)/%.o: %.c + @echo CC $@ + @$(CC) -I. $(CFLAGS) -c $*.c -o obj/$(ARCH)/$(TARGET)/$*.o + + +# *.m files to *.o files (Mac) +obj/$(ARCH)/$(TARGET)/%.o: %.m + @echo OBJCC $@ + @$(CC) $(CFLAGS) -c $*.m -o obj/$(ARCH)/$(TARGET)/$*.o diff --git a/libsst-wm/RaspPi/RaspPiPrivate.h b/libsst-wm/RaspPi/RaspPiPrivate.h new file mode 100644 index 0000000..fb2094a --- /dev/null +++ b/libsst-wm/RaspPi/RaspPiPrivate.h @@ -0,0 +1,80 @@ +/* + RaspPiPrivate.h + Author: Patrick Baggett <ptbaggett@762studios.com> + Created: 6/25/2013 + + Purpose: + + Private defintions and functions for Raspberry Pi implementation of + libsst-wm + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ + +#pragma once + +#ifndef _RASPPIPRIVATE_H +#define _RASPPIPRIVATE_H + +#include <bcm_host.h> +#include <pthread.h> + +#include <SST/SST_WMTypes.h> +#include "EventQueue.h" + +/******************************************************************************/ + +struct SST_Window_RaspPi; + +typedef struct SST_DisplayTarget_RaspPi +{ + EventQueue eventQueue; + EventQueue userEventQueue; + uint8_t keymapBitvector[32]; /* Bitmap similar to XQueryKeymap() */ + pthread_mutex_t eventLock; /* Lock protecting user events */ + struct SST_Window_RaspPi* firstWindow; /* Window */ + int relativeMouse; + DISPMANX_DISPLAY_HANDLE_T display; +} SST_DisplayTarget_RaspPi; + +/******************************************************************************/ + +typedef struct SST_Window_RaspPi +{ + SST_DisplayTarget_RaspPi* owner; + struct SST_Window_RaspPi* next; + int isFullscreen; + uint32_t x, y; + uint32_t w, h; + + DISPMANX_ELEMENT_HANDLE_T element; + + /* Software rendering support */ + void* softwareBackbuffer; + uint32_t softwarePitch; + DISPMANX_RESOURCE_HANDLE_T softwareImage; + VC_RECT_T softwareRect; +} SST_Window_RaspPi; + +/******************************************************************************/ + +typedef struct SST_OpenGLContext_RaspPi +{ + SST_DisplayTarget_RaspPi* displayTarget; + uint16_t ctxVersion[2]; /* context version major/minor */ + int debugEnabled; /* Did we use debug OpenGL context support? */ + + /* EGL fields */ + /* TODO */ +} SST_OpenGLContext_RaspPi; + +/******************************************************************************/ + +#endif diff --git a/libsst-wm/RaspPi/SST_WMDialogBox_RaspPi.c b/libsst-wm/RaspPi/SST_WMDialogBox_RaspPi.c new file mode 100644 index 0000000..a2a16cf --- /dev/null +++ b/libsst-wm/RaspPi/SST_WMDialogBox_RaspPi.c @@ -0,0 +1,49 @@ +/* + SST_WMDialogBox_RaspPi.c + Author: Patrick Baggett <ptbaggett@762studios.com> + Created: 6/25/2013 + + Purpose: + + Simple dialog box window + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ + +#include "RaspPiPrivate.h" + +#define BUTTON_HSPACE 16 /* Space on either side of a button */ +#define BUTTON_VSPACE 16 /* Space between top of button and dialog text */ +#define TEXT_HSPACE 16 +#define TEXT_VSPACE 16 + +typedef struct DialogBoxData +{ + const char* message; + int lenMessage; + int buttonId; + int exitTime; +} DialogBoxData; + +/******************************************************************************/ + +int SST_WM_ShowDialogBox(SST_DisplayTarget target, SST_Window parent, const char* caption, const char* message, const char** buttons, int nrButtons) +{ + /* TODO: helluvalota work */ + (void)target; + (void)parent; + (void)caption; + (void)message; + (void)buttons; + (void)nrButtons; + + return 0; +} + diff --git a/libsst-wm/RaspPi/SST_WMEnum_RaspPi.c b/libsst-wm/RaspPi/SST_WMEnum_RaspPi.c new file mode 100644 index 0000000..cbd1a9b --- /dev/null +++ b/libsst-wm/RaspPi/SST_WMEnum_RaspPi.c @@ -0,0 +1,144 @@ +/* + SST_WMEnum_RaspPi.c + Author: Patrick Baggett <ptbaggett@762studios.com> + Created: 5/31/2013 + + Purpose: + + Raspberry Pi native (no display server) port for Linux + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ + +#include <SST/SST_WM.h> + +#include <bcm_host.h> /* R-Pi header */ + +#include <string.h> /* strlen() etc. */ +#include <stdlib.h> + +/******************************************************************************/ + +SST_GraphicsEnumerator SST_WM_CreateGraphicsEnumerator(void) +{ + /* Call this just in case. Multiple calls do not affect anything */ + bcm_host_init(); + + return (void*)(uintptr_t)(0x40000000); /* No, it is meaningless */ +} + +/******************************************************************************/ + +size_t SST_WM_GetEnumAdapterCount(SST_GraphicsEnumerator enumerator) +{ + (void)enumerator; + + /* R-Pi only has the one on-chip device */ + return 1; +} + +/******************************************************************************/ + +void SST_WM_GetEnumAdapterName(SST_GraphicsEnumerator enumerator, size_t adapterId, char* nameReturn, size_t* bufferSize) +{ + size_t len; + const char* name = "VideoCore IV (R) GPU"; + + (void)enumerator; + (void)adapterId; + + len = strlen(name); + + /* Query name length */ + if(nameReturn == NULL) + { + *bufferSize = len+1; + } + else + { + size_t copyAmount; + + /* Nothing to do? */ + if(*bufferSize == 0) + return; + + /* Use min(len, (*bufferSize)-1) */ + copyAmount = len; + if(copyAmount > (*bufferSize)-1) + copyAmount = (*bufferSize)-1; + + memcpy(nameReturn, name, copyAmount); + nameReturn[copyAmount] = '\0'; + } + +} + +/******************************************************************************/ + +size_t SST_WM_GetEnumScreenCount(SST_GraphicsEnumerator enumerator, size_t adapterId) +{ + (void)enumerator; + (void)adapterId; + return 1; +} + +/******************************************************************************/ + +void SST_WM_GetEnumVideoModes(SST_GraphicsEnumerator enumerator, size_t adapterId, size_t screenId, SST_VideoMode* modesReturn, size_t* modeCountReturn) +{ + (void)enumerator; + + /* Only one adapter/screen supported */ + if(adapterId != 0 || screenId != 0) + return; + + if(modesReturn == NULL) + *modeCountReturn = 1; + else + { + /* TODO: there might be a way to do this, but it + is very manual. Just return current resolution. */ + uint32_t w, h; + + graphics_get_display_size(0, &w, &h); + + modesReturn[0].bpp = 16; /* TODO: not always 16 */ + modesReturn[0].width = w; + modesReturn[0].height = h; + modesReturn[0].refreshRate = 0; + } + +} + +/******************************************************************************/ + +void SST_WM_GetEnumCurrentVideoMode(SST_GraphicsEnumerator enumerator, size_t adapterId, size_t screenId, SST_VideoMode* mode) +{ + uint32_t w, h; + (void)enumerator; + + if(adapterId != 0 || screenId != 0) + return; + + /* TODO: does this reflect changes made with fbset? */ + graphics_get_display_size(0, &w, &h); + + mode->bpp = 16; + mode->width = w; + mode->height = h; + mode->refreshRate = 0; +} + +/******************************************************************************/ + +void SST_WM_DestroyGraphicsEnumerator(SST_GraphicsEnumerator enumerator) +{ + (void)enumerator; +} diff --git a/libsst-wm/RaspPi/SST_WMEvent_RaspPi.c b/libsst-wm/RaspPi/SST_WMEvent_RaspPi.c new file mode 100644 index 0000000..7e7c146 --- /dev/null +++ b/libsst-wm/RaspPi/SST_WMEvent_RaspPi.c @@ -0,0 +1,60 @@ +/* + SST_WMEvent_Win32.c + Author: Patrick Baggett <ptbaggett@762studios.com> + Created: 6/25/2013 + + Purpose: + + Raspberry Pi "window" event functions + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ + +#include <SST/SST_WMEvent.h> +#include "RaspPiPrivate.h" + +/******************************************************************************/ + +int SST_WM_GetEvent(SST_DisplayTarget target, SST_WMEvent* eventReturn) +{ + SST_DisplayTarget_RaspPi* displayTarget = (SST_DisplayTarget_RaspPi*)target; + + /* Check for user events */ + if(RemoveFromEQ(&displayTarget->userEventQueue, eventReturn)) + return 1; + + if(RemoveFromEQ(&displayTarget->eventQueue, eventReturn)) + return 1; + + + return 0; +} + +/******************************************************************************/ +/* These functions are used by SST_WMEvent_Common.c */ +EventQueue* getUserEventQueue(SST_DisplayTarget target) +{ + + SST_DisplayTarget_RaspPi* displayTarget = (SST_DisplayTarget_RaspPi*)target; + return &displayTarget->userEventQueue; +} + +void lockUserEventQueue(SST_DisplayTarget target) +{ + SST_DisplayTarget_RaspPi* displayTarget = (SST_DisplayTarget_RaspPi*)target; + pthread_mutex_lock(&displayTarget->eventLock); +} + +void unlockUserEventQueue(SST_DisplayTarget target) +{ + SST_DisplayTarget_RaspPi* displayTarget = (SST_DisplayTarget_RaspPi*)target; + pthread_mutex_unlock(&displayTarget->eventLock); +} + diff --git a/libsst-wm/RaspPi/SST_WMRender_RaspPi.c b/libsst-wm/RaspPi/SST_WMRender_RaspPi.c new file mode 100644 index 0000000..75d5b58 --- /dev/null +++ b/libsst-wm/RaspPi/SST_WMRender_RaspPi.c @@ -0,0 +1,113 @@ +/* + SST_WMRender_RaspPi.c + Author: Patrick Baggett <ptbaggett@762studios.com> + Created: 6/25/2013 + + Purpose: + + Software rendering support for Raspberry Pi + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ + +#include "RaspPiPrivate.h" +#include <SST/SST_WMWindow.h> + +#define ROUNDUP(val, power) ((val + (power)-1) & ~((power)-1)) + +/******************************************************************************/ + +int SST_WM_EnableSoftwareRendering(SST_Window window) +{ + SST_Window_RaspPi* win = (SST_Window_RaspPi*)window; + DISPMANX_UPDATE_HANDLE_T update; + + /* Each pixel is 4 bytes. */ + uint32_t pitch = win->w * sizeof(uint32_t); + uint32_t dummy; + + /* Pitch must be a multiple of 32 bytes, so round up */ + pitch = ROUNDUP(pitch, 32); + + /* TODO: what does vc_dispmanx_resource_create() return on error? */ + /* Last parameter "dummy" is always set to zero according to source code, must be from other videocore versions */ + win->softwareImage = vc_dispmanx_resource_create(VC_IMAGE_ARGB8888, win->w, win->h, &dummy); + win->softwareBackbuffer = calloc(win->h, pitch); + win->softwarePitch = pitch; + + /* TODO: wtf, why << 16 */ + vc_dispmanx_rect_set(&win->softwareRect, 0, 0, win->w << 16, win->h << 16 ); + + if(win->softwareBackbuffer == NULL) + return 0; + + /* Update dispmanx to bind the new image to the */ + update = vc_dispmanx_update_start(0); + vc_dispmanx_element_change_source(update, win->element, win->softwareImage); + vc_dispmanx_update_submit_sync(update); + + return 1; +} + +/******************************************************************************/ + +void SST_WM_DisableSoftwareRendering(SST_Window window) +{ + SST_Window_RaspPi* win = (SST_Window_RaspPi*)window; + DISPMANX_UPDATE_HANDLE_T update; + + /* Update dispmanx; remove the resource from the window element */ + update = vc_dispmanx_update_start(0); + + vc_dispmanx_element_change_source(update, win->element, 0); + + vc_dispmanx_update_submit_sync(update); + + /* Now we can delete the resource */ + if(win->softwareImage != 0) + { + vc_dispmanx_resource_delete(win->softwareImage); + win->softwareImage = 0; + } + + if(win->softwareBackbuffer) + { + free(win->softwareBackbuffer); + win->softwareBackbuffer = NULL; + } +} + +/******************************************************************************/ + +void* SST_WM_LockBackbuffer(SST_Window window, size_t* pitchReturn) +{ + SST_Window_RaspPi* win = (SST_Window_RaspPi*)window; + + *pitchReturn = win->softwarePitch; + + return win->softwareBackbuffer; +} + +/******************************************************************************/ + +void SST_WM_UnlockBackbuffer(SST_Window window) +{ + SST_Window_RaspPi* win = (SST_Window_RaspPi*)window; + VC_RECT_T blit; + + blit.x = blit.y = 0; + blit.width = win->w; + blit.height = win->h; + + /* Push the pixels to the resource */ + vc_dispmanx_resource_write_data(win->softwareImage, VC_IMAGE_ARGB8888, win->softwarePitch, win->softwareBackbuffer, &blit); + +} + diff --git a/libsst-wm/RaspPi/SST_WMVideoMode_RaspPi.c b/libsst-wm/RaspPi/SST_WMVideoMode_RaspPi.c new file mode 100644 index 0000000..e32433f --- /dev/null +++ b/libsst-wm/RaspPi/SST_WMVideoMode_RaspPi.c @@ -0,0 +1,56 @@ +/* + SST_WMVideoMode_RaspPi.c + Author: Patrick Baggett <ptbaggett@762studios.com> + Created: 6/25/2013 + + Purpose: + + Video mode setting functions for the Raspberry Pi + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ + +#include "RaspPiPrivate.h" + +/* + Right now, these are essentially no-ops. The vc_tv_xxx API can be used + to query and change the video mode +*/ + +/******************************************************************************/ + +int SST_WM_SetVideoModeOnScreen(SST_DisplayTarget target, size_t screenIndex, const SST_VideoMode* vmode) +{ + SST_DisplayTarget_RaspPi* displayTarget = (SST_DisplayTarget_RaspPi*)target; + + /* Must be screen 0 */ + if(screenIndex != 0) + return 0; + + return 1; +} + +/******************************************************************************/ + +int SST_WM_GetVideoModeOnScreen(SST_DisplayTarget target, size_t screenIndex, SST_VideoMode* vmodeReturn) +{ + SST_DisplayTarget_RaspPi* displayTarget = (SST_DisplayTarget_RaspPi*)target; + + /* Must be screen 0 */ + if(screenIndex != 0) + return 0; + + vmodeReturn->bpp = 16; /* ? The HWS runs at what depth? */ + vmodeReturn->width = 0; + vmodeReturn->height = 0; + vmodeReturn->refreshRate = 0; + + return 1; +} diff --git a/libsst-wm/RaspPi/SST_WMWindow_RaspPi.c b/libsst-wm/RaspPi/SST_WMWindow_RaspPi.c new file mode 100644 index 0000000..5cd9398 --- /dev/null +++ b/libsst-wm/RaspPi/SST_WMWindow_RaspPi.c @@ -0,0 +1,390 @@ +/* + SST_WMWindow_RaspPi.c + Author: Patrick Baggett <ptbaggett@762studios.com> + Created: 1/8/2013 + + Purpose: + + Window emulation for native Raspberry Pi port + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ + +#include <SST/SST_WMWindow.h> +#include "RaspPiPrivate.h" +#include "EventQueue.h" + +#define WINDOW_LAYER 2000 + +/******************************************************************************/ + +static void destroyWin(SST_Window_RaspPi* win) +{ + /* Only after an element is removed can the resource under it + be deleted. */ + if(win->element != 0) + { + DISPMANX_UPDATE_HANDLE_T update; + + update = vc_dispmanx_update_start(0); + vc_dispmanx_element_remove(update, win->element); + vc_dispmanx_update_submit_sync(update); + } + + if(win->softwareImage != 0) + vc_dispmanx_resource_delete(win->softwareImage); + + free(win); +} + +/******************************************************************************/ + +SST_DisplayTarget SST_WM_CreateDisplayTarget(size_t adapterIndex, size_t screenIndexOrMultihead) +{ + SST_DisplayTarget_RaspPi* displayTarget; + + /* > 1 adapters not supported, multihead not supported */ + if(screenIndexOrMultihead != 0 || adapterIndex != 0) + return NULL; + + displayTarget = (SST_DisplayTarget_RaspPi*)malloc(sizeof(SST_DisplayTarget_RaspPi)); + if(displayTarget == NULL) + return NULL; + + /* Initialize lock for user events */ + if(pthread_mutex_init(&displayTarget->eventLock, NULL) != 0) + { + free(displayTarget); + return NULL; + } + + if(InitEQ(&displayTarget->eventQueue) == 0) + { + pthread_mutex_destroy(&displayTarget->eventLock); + free(displayTarget); + return NULL; + } + + if(InitEQ(&displayTarget->userEventQueue) == 0) + { + DestroyEQ(&displayTarget->eventQueue); + pthread_mutex_destroy(&displayTarget->eventLock); + free(displayTarget); + return NULL; + } + + /* Save fields */ + displayTarget->firstWindow = NULL; + displayTarget->relativeMouse = 0; + displayTarget->display = vc_dispmanx_display_open(DISPMANX_ID_MAIN_LCD); + memset(displayTarget->keymapBitvector, 0, sizeof(displayTarget->keymapBitvector)); + + return (SST_DisplayTarget)displayTarget; +} + +/******************************************************************************/ + +size_t SST_WM_GetDisplayTargetScreenCount(SST_DisplayTarget target) +{ + (void)target; + return 1; +} + +/******************************************************************************/ + +SST_Window SST_WM_CreateWindowOnScreen(SST_DisplayTarget target, size_t screenIndex, uint32_t x, uint32_t y, uint32_t width, uint32_t height, const char* title) +{ + SST_Window_RaspPi* win; + SST_DisplayTarget_RaspPi* displayTarget = (SST_DisplayTarget_RaspPi*)target; + SST_WMEvent* event; + DISPMANX_UPDATE_HANDLE_T update; + VC_DISPMANX_ALPHA_T alpha; + VC_RECT_T srcRect, dstRect; + + /* Title is not used */ + (void)title; + + /* Must be on screen 0 */ + if(screenIndex != 0) + return NULL; + + /* Allocate SST window structure */ + win = (SST_Window_RaspPi*)calloc(1, sizeof(SST_Window_RaspPi)); + if(win == NULL) + return NULL; + + /* link the window */ + displayTarget->firstWindow = win; + win->next = displayTarget->firstWindow; + win->owner = displayTarget; + win->x = x; + win->y = y; + win->w = width; + win->h = height; + + srcRect.x = srcRect.y = 0; + srcRect.width = width << 16; srcRect.height = height << 16; + + dstRect.x = x; dstRect.y = y; + dstRect.width = width; dstRect.height = height; + + /* TODO: clip these so they make sense */ + + alpha.flags = DISPMANX_FLAGS_ALPHA_FIXED_ALL_PIXELS; + alpha.opacity = 0xFF; + alpha.mask = 0; + + update = vc_dispmanx_update_start(0); + win->element = vc_dispmanx_element_add(update, displayTarget->display, + WINDOW_LAYER, + &dstRect, + 0, &srcRect, /* no source data */ + DISPMANX_PROTECTION_NONE, /* no content protection */ + &alpha, NULL, /* Alpha/clamp/transform parameters */ + VC_IMAGE_ROT0); /* No rotation required */ + + + vc_dispmanx_update_submit_sync(update); + + /* Add a SSTWMEVENT_CREATED event */ + event = AllocSlotInEQ(&displayTarget->eventQueue); + if(event != NULL) + { + event->window = win; + event->type = SSTWMEVENT_CREATED; + memset(&event->details, 0, sizeof(event->details)); + } + + return (SST_Window)win; +} + +/******************************************************************************/ + +SST_DisplayTarget SST_WM_GetWindowDisplayTarget(SST_Window window) +{ + SST_Window_RaspPi* win = (SST_Window_RaspPi*)window; + + return win->owner; +} + +/******************************************************************************/ + +void SST_WM_SetWindowText(SST_Window window, const char* titleBar) +{ + /* There is no way to do this; Ignore. */ + (void)window; + (void)titleBar; +} +/******************************************************************************/ + +void SST_WM_GetWindowRect(SST_Window window, SST_Rect* rectReturn) +{ + SST_Window_RaspPi* win = (SST_Window_RaspPi*)window; + + rectReturn->x = win->x; + rectReturn->y = win->y; + rectReturn->width = win->w; + rectReturn->height = win->h; + return; +} + +/******************************************************************************/ + +void SST_WM_MoveWindowOnScreen(SST_Window window, size_t screenIndex, uint32_t x, uint32_t y) +{ + SST_Window_RaspPi* win = (SST_Window_RaspPi*)window; + + /* Only allow operations on screen 0 */ + if(screenIndex != SST_SAME_SCREEN && screenIndex != 0) + return; + + /* TODO: verify these coords make any sense */ + win->x = x; + win->y = y; + /* TODO: send message */ +} + +/******************************************************************************/ + +void SST_WM_ResizeWindow(SST_Window window, uint32_t width, uint32_t height) +{ + SST_Window_RaspPi* win = (SST_Window_RaspPi*)window; + /* TODO: verify these coords make any sense */ + win->w = width; + win->h = height; + /* TODO: send a message */ +} + +/******************************************************************************/ + +void SST_WM_SetWindowState(SST_Window window, SST_WMWindowState state, uint32_t param) +{ + SST_Window_RaspPi* win = (SST_Window_RaspPi*)window; + + switch(state) + { + case SSTWS_SHOWN: + { + /* Map or unmap the window respectively */ + if(param == 0) + { + /* TODO: hide window */ + } + else + { + /* TODO: show window */ + } + + break; + } + + /* Turn on/off resizeability */ + case SSTWS_RESIZEABLE: + { + /* No-op. */ + break; + } + + case SSTWS_FULLSCREEN: + { + + /* Enabling fullscreen? */ + if(param && !win->isFullscreen) + { + /* TODO: save old X/Y/W/H */ + win->isFullscreen = 1; + } + else if(win->isFullscreen) + { + /* TODO: restore old X/Y/W/H */ + win->isFullscreen = 0; + } + + break; + } + + case SSTWS_MINIMIZED: + { + if(param == 0) /* Maximize */ + { + /* TODO: maximize? */ + } + else /* Minimize */ + { + /* TODO: minimize? */ + } + break; + } + + default: break; + } +} + +/******************************************************************************/ + +void SST_WM_SetDisplayTargetState(SST_DisplayTarget target, SST_WMDisplayTargetState state, uint32_t param) +{ + SST_DisplayTarget_RaspPi* displayTarget = (SST_DisplayTarget_RaspPi*)target; + + switch(state) + { + case SSTDTS_RELMOUSE: + { + /* Disabling? */ + if(displayTarget->relativeMouse && param == 0) + { + /* TODO */ + } + else if(!displayTarget->relativeMouse && param != 0) /* Enabling? */ + { + /* TODO */ + } + + break; + } + } +} + +/******************************************************************************/ + +void SST_WM_DestroyWindow(SST_Window window) +{ + SST_DisplayTarget_RaspPi* displayTarget; + SST_Window_RaspPi* win = (SST_Window_RaspPi*)window; + SST_Window_RaspPi* nextWin; + + displayTarget = win->owner; + nextWin = displayTarget->firstWindow; + + /* Special case: root window */ + if(nextWin == win) + { + /* Set new root to be this->next */ + displayTarget->firstWindow = win->next; + } + else + { + int found = 0; + + /* Check list */ + while(nextWin) + { + /* Did we find the window? */ + if(nextWin->next == win) + { + /* Remove this window from the linked list */ + nextWin->next = win->next; + found = 1; + break; + } + else + nextWin = nextWin->next; + } + + /* Don't destroy another display target's window */ + if(!found) + return; + + } + + /* Actually destroy the window window */ + destroyWin(win); +} + +/******************************************************************************/ + +void SST_WM_DestroyDisplayTarget(SST_DisplayTarget target) +{ + SST_DisplayTarget_RaspPi* displayTarget = (SST_DisplayTarget_RaspPi*)target; + SST_Window_RaspPi* window = displayTarget->firstWindow; + + /* Destroy window */ + while(window) + { + SST_Window_RaspPi* next = window->next; + destroyWin(window); + window = next; + } + + /* Delete any events */ + DestroyEQ(&displayTarget->eventQueue); + DestroyEQ(&displayTarget->userEventQueue); + pthread_mutex_destroy(&displayTarget->eventLock); + + vc_dispmanx_display_close(displayTarget->display); + + /* Free structure */ + free(displayTarget); + +} + +/******************************************************************************/ + + diff --git a/libsst-wm/Win32/SST_WMDialogBox_Win32.c b/libsst-wm/Win32/SST_WMDialogBox_Win32.c new file mode 100644 index 0000000..8111259 --- /dev/null +++ b/libsst-wm/Win32/SST_WMDialogBox_Win32.c @@ -0,0 +1,319 @@ +/* + SST_WMDialogBox_Win32.c + Author: Patrick Baggett <ptbaggett@762studios.com> + Created: 1/5/2013 + + Purpose: + + Model + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ + +#include "Win32Private.h" + +#define BUTTON_HSPACE 16 /* Space on either side of a button */ +#define BUTTON_VSPACE 16 /* Space between top of button and dialog text */ +#define TEXT_HSPACE 16 +#define TEXT_VSPACE 16 + +typedef struct DialogBoxData +{ + const char* message; + int lenMessage; + int buttonId; + int exitTime; +} DialogBoxData; + +/*************************************************************************/ + +static LONG dlgRegCount = 0; + +/*************************************************************************/ + +static LRESULT WINAPI libsstDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); + +static HWND createButton(HWND owner, int id, const char* label, int x, int y, int w, int h); + +/*************************************************************************/ + +int Win32_ShowDialogBox(SST_DisplayTarget target, SST_Window parent, const char* caption, const char* message, const char** buttons, int nrButtons) +{ + SST_Window_Win32* win = (SST_Window_Win32*)parent; + SST_DisplayTarget_Win32* displayTarget = (SST_DisplayTarget_Win32*)target; + HWND hWnd; + HWND hParentWnd = NULL; + MSG msg; + HDC hDC; + HFONT hFont = (HFONT)GetStockObject(DEFAULT_GUI_FONT); + + /* Compute size of a button. This is absolutely arcane, but the 50x14 units and the /4 /8 are documented. Somewhere... */ + uint32_t units = (uint32_t)GetDialogBaseUnits(); + int horiz = (int)MulDiv((units & 0xFF), 50, 4); + int vert = (int)MulDiv((units >> 16), 14, 8); + int w, h; + int returnCode; + + /* Window rectangle computation */ + DWORD style = WS_CAPTION | WS_SYSMENU | WS_CLIPCHILDREN; + DWORD styleEx = 0; + RECT r; + RECT textRect; + RECT centerOn; + DialogBoxData* dlgData; + + /* Allocate dialog box data */ + dlgData = (DialogBoxData*)HeapAlloc(GetProcessHeap(), 0, sizeof(DialogBoxData)); + if(dlgData == NULL) + return -1; + + dlgData->message = message; + dlgData->lenMessage = (int)strlen(message); + dlgData->buttonId = -1; + dlgData->exitTime = 0; + /* + First, figure out a good area to center the dialog box on. It's highly unintuitive to have it + it mapped in the top-left corner. We center it on the parent window (if possible) or the monitor + otherwise. + */ + + /* Have a parent window? */ + if(win != NULL) + { + /* Then center on it */ + hParentWnd = win->hWnd; + GetWindowRect(hParentWnd, ¢erOn); + } + else /* Otherwise center on default display */ + { + FindMonitorInfo fmi; + + /* Attempt to find the monitor associated with a display device */ + findMonitor(&displayTarget->devs[0], &fmi); + + /* Didn't find it? */ + if(!fmi.foundIt) + return -1; + + /* Center on the monitor */ + centerOn.top = fmi.top; + centerOn.left = fmi.left; + centerOn.bottom = fmi.bottom; + centerOn.right = fmi.right; + } + + /* Start the window as if it was at (0,0) */ + r.top = 0; + r.left = 0; + r.bottom = 2*BUTTON_VSPACE+vert; /* Enough space for a button and vertical padding above and below it */ + r.right = (LONG)nrButtons*(horiz + BUTTON_HSPACE)+BUTTON_HSPACE; + + /* Now we need to compute the area requried to display the text. This will be summed with the area required for the buttons on the Y axis, but + the X axis will be the maximum of the two. */ + /* 1) Create a fake DC to compute the size of the text's rect */ + hDC = CreateDC("DISPLAY", NULL, NULL, NULL); + SelectObject(hDC, (HGDIOBJ)hFont); + + /* 2) Actually compute the rect using DrawTextEx() and DT_CALCRECT. */ + memset(&textRect, 0, sizeof(textRect)); + DrawTextExA(hDC, (LPSTR)dlgData->message, dlgData->lenMessage, &textRect, DT_CALCRECT | DT_TOP | DT_LEFT, NULL); + DeleteDC(hDC); + + /* 3) Add a border around the entire thing */ + textRect.bottom += 2*TEXT_VSPACE; + textRect.right += 2*TEXT_HSPACE; + + /* For the X-axis, we want the maximum of the amount of space it takes to display buttons and text */ + if(r.right < textRect.right) + r.right = textRect.right; + + /* For the Y-aaxis, just append space to the top of dialog box for the text rect */ + r.bottom += textRect.bottom; + + /* Move the window to the center of the screen: */ + /* 1) Compute width and height of window */ + w = r.right - r.left; + h = r.bottom - r.top; + + AdjustWindowRectEx(&r, style, FALSE, styleEx); + + /* After we adjusted the size of the window so that the client area is constant, we need + to move it back to (0,0). */ + if(r.top != 0) + { + LONG d = -r.top; + + r.top = 0; + r.bottom += d; + } + if(r.left != 0) + { + LONG d = -r.left; + + r.left = 0; + r.right += d; + } + + /* 2) Adjust so it fits on the screen by doing: `adjust = (center - size) /2` */ + r.left += ((centerOn.right - centerOn.left) - w) / 2; + r.right += ((centerOn.right - centerOn.left) - w) / 2; + r.top += ((centerOn.bottom - centerOn.top) - h) / 2; + r.bottom += ((centerOn.bottom - centerOn.top) - h) / 2; + + /* You can't create a window without registering the class, so let's do it now. Since + this function has "Concurrent" access, use an atomic operation to decide if it is necessary. */ + if(InterlockedIncrement(&dlgRegCount) == 1) + { + WNDCLASSEXA wc; + + memset(&wc, 0, sizeof(wc)); + wc.cbSize = sizeof(wc); + wc.lpszClassName = SST_DLGCLASS; + wc.hInstance = GetModuleHandleA(NULL); + wc.lpfnWndProc = libsstDlgProc; + wc.hCursor = LoadCursor(NULL, IDC_ARROW); + wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); + wc.style = CS_OWNDC; + wc.hbrBackground = (HBRUSH)(uintptr_t)(COLOR_WINDOW+1); + RegisterClassExA(&wc); + } /* TODO: I suppose it is possible that someone could turn this into a race condition. Priority = lowest */ + + /* FINALLY, create the dialog window */ + hWnd = CreateWindowExA(styleEx, + SST_DLGCLASS, + caption, + style, + r.left, r.top, /* XY position */ + r.right-r.left, r.bottom-r.top, /* Size */ + hParentWnd, + (NULL), + GetModuleHandleA(NULL), + NULL); + + /* Made the window successfully? */ + if(hWnd != NULL) + { + int i; + POINT bottomRight; + RECT clientRect; + SetWindowLongPtrA(hWnd, GWLP_USERDATA, (LONG_PTR)dlgData); + + ShowWindow(hWnd, SW_SHOW); + + /* Get the coordinates of the bottom right pixel */ + GetClientRect(hWnd, &clientRect); + bottomRight.x = clientRect.right; + bottomRight.y = clientRect.bottom; + + /* Create the dialog buttons in reverse order starting at the right end of the dialog and moving left */ + for(i=0; i<nrButtons; i++) + { + HWND hButton = createButton(hWnd, nrButtons-1-i, buttons[nrButtons-1-i], bottomRight.x-((i+1)*(BUTTON_HSPACE+horiz)), bottomRight.y-(BUTTON_VSPACE+vert), horiz, vert); + + /* Set the font on them too */ + SendMessage(hButton, WM_SETFONT, (WPARAM)hFont, MAKELPARAM(TRUE, 0)); + } + + do + { + while(PeekMessageA(&msg, hWnd, 0, 0, PM_REMOVE)) + { + TranslateMessage(&msg); + DispatchMessageA(&msg); + } + } while(!dlgData->exitTime); + } + + returnCode = dlgData->buttonId; + + HeapFree(GetProcessHeap(), 0,dlgData); + return returnCode; +} + +/*************************************************************************/ + +static LRESULT WINAPI libsstDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + DialogBoxData* dlgData = (DialogBoxData*)GetWindowLongPtrA(hWnd, GWLP_USERDATA); + + + switch(msg) + { + case WM_PAINT: + { + PAINTSTRUCT ps; + RECT r; + HDC hDC; + + + if(dlgData) + { + hDC = BeginPaint(hWnd, &ps); + + SelectObject(hDC, GetStockObject(DEFAULT_GUI_FONT)); + + GetClientRect(hWnd, &r); + + r.left += TEXT_HSPACE; + r.right -= TEXT_HSPACE; + r.top += TEXT_VSPACE; + r.bottom -= TEXT_VSPACE; + + DrawTextExA(hDC, (LPSTR)dlgData->message, dlgData->lenMessage, &r, DT_TOP | DT_LEFT, NULL); + EndPaint(hWnd, &ps); + } + return 0; + break; + } + + /* Aborting the dialog */ + case WM_CLOSE: + dlgData->buttonId = -1; + dlgData->exitTime = 1; + DestroyWindow(hWnd); + return 0; + break; + + case WM_COMMAND: + { + if(HIWORD(wParam) == BN_CLICKED) + { + dlgData->buttonId = (int)LOWORD(wParam); + dlgData->exitTime = 1; + + DestroyWindow(hWnd); + } + return 0; + break; + } + + } + + return DefWindowProc(hWnd, msg, wParam, lParam); +} + +/*************************************************************************/ + +static HWND createButton(HWND owner, int id, const char* label, int x, int y, int w, int h) +{ + HWND hWnd = CreateWindowExA(0, + "BUTTON", + label, + WS_TABSTOP|WS_VISIBLE| + WS_CHILD|BS_DEFPUSHBUTTON, + x, y, + w, h, + owner, + (HMENU)(uintptr_t)id, + GetModuleHandleA(NULL), + NULL); + return hWnd; +} + diff --git a/libsst-wm/Win32/SST_WMEnum_Win32.c b/libsst-wm/Win32/SST_WMEnum_Win32.c new file mode 100644 index 0000000..c219f6b --- /dev/null +++ b/libsst-wm/Win32/SST_WMEnum_Win32.c @@ -0,0 +1,268 @@ +/* + SST_WMEnum_Win32.c + Author: Patrick Baggett <ptbaggett@762studios.com> + Created: 1/7/2012 + + Purpose: + + Enumerates graphics adapters and screens. + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ + +#include <SST/SST_WM.h> + +#include "Win32Private.h" +#include "../APIPrivate.h" + +#include <string.h> /* strlen() etc. */ +#include <stdlib.h> + +/*************************************************************************/ + +static SST_GraphicsEnumerator Win32_CreateGraphicsEnumerator(void) +{ + DISPLAY_DEVICEA* devsFound = NULL; + char* adapterNames; + char* adapterGUIDs; + size_t* screenCount; + size_t adapterCount; + size_t devCount = 0; + size_t ASPairCount = 0; + size_t i; + SST_GraphicsEnumerator_Win32* enumerator; + ASMapEntry* ASMap; + HANDLE hProcessHeap; + + /* Get a list of Win32 display devices */ + devsFound = get_win32devs(&devCount); + if(devsFound == NULL) + return NULL; + + hProcessHeap = GetProcessHeap(); + + /* Get a list of the graphics adapters' names */ + adapterNames = get_adapters(devsFound, devCount, &adapterCount, &adapterGUIDs); + if(adapterNames == NULL) + { + HeapFree(hProcessHeap, 0, devsFound); + return NULL; + } + + /* Make a map of adapter->screen count */ + screenCount = HeapAlloc(hProcessHeap, 0, adapterCount*sizeof(size_t)); + if(screenCount == NULL) + { + HeapFree(hProcessHeap, 0, adapterGUIDs); + HeapFree(hProcessHeap, 0, adapterNames); + HeapFree(hProcessHeap, 0, devsFound); + return NULL; + } + for(i=0; i<adapterCount; i++) + screenCount[i] = 0; + + /* Attempt to build the adapter-screen map */ + ASMap = build_asmap(devsFound, adapterGUIDs, devCount, adapterCount, screenCount, &ASPairCount); + if(ASMap == NULL) + { + HeapFree(hProcessHeap, 0, adapterGUIDs); + HeapFree(hProcessHeap, 0, adapterNames); + HeapFree(hProcessHeap, 0, devsFound); + HeapFree(hProcessHeap, 0, screenCount); + return NULL; + } + + /* Done with GUIDs */ + HeapFree(hProcessHeap, 0, adapterGUIDs); + + /* Get the list of video modes for each adapter-screen pair */ + for(i=0; i<ASPairCount; i++) + { + size_t vmodeCount; + SST_VideoMode* vmodes; + + vmodes = get_vmodes(ASMap[i].dev, &vmodeCount, &ASMap[i].defaultVmode); + if(vmodes == NULL) + { + size_t j; + for(j=0; j<i; j++) + HeapFree(hProcessHeap, 0, ASMap[i].vmodes); + HeapFree(hProcessHeap, 0, adapterNames); + HeapFree(hProcessHeap, 0, devsFound); + HeapFree(hProcessHeap, 0, screenCount); + HeapFree(hProcessHeap, 0, ASMap); + return NULL; + } + /* Save the screens for this */ + ASMap[i].vmodeCount = vmodeCount; + ASMap[i].vmodes = vmodes; + } + + /* Prepare a structure to return... */ + enumerator = HeapAlloc(hProcessHeap, 0, sizeof(SST_GraphicsEnumerator_Win32)); + if(enumerator == NULL) + { + /* Doh! So close :\ */ + size_t j; + for(j=0; j<i; j++) + HeapFree(hProcessHeap, 0, ASMap[i].vmodes); + + HeapFree(hProcessHeap, 0, adapterNames); + HeapFree(hProcessHeap, 0, devsFound); + HeapFree(hProcessHeap, 0, screenCount); + HeapFree(hProcessHeap, 0, ASMap); + return NULL; + } + + /* Save fields */ + enumerator->adapterNames = adapterNames; + enumerator->adapterCount = adapterCount; + enumerator->devCount = devCount; + enumerator->devsFound = devsFound; + enumerator->screenCount = screenCount; + enumerator->ASMap = ASMap; + enumerator->ASPairCount = ASPairCount; + + return enumerator; +} + +/*************************************************************************/ + +static size_t Win32_GetEnumAdapterCount(SST_GraphicsEnumerator enumerator) +{ + SST_GraphicsEnumerator_Win32* enumWin32 = (SST_GraphicsEnumerator_Win32*)enumerator; + + return enumWin32->adapterCount; +} + +/*************************************************************************/ + +static void Win32_GetEnumAdapterName(SST_GraphicsEnumerator enumerator, size_t adapterId, char* nameReturn, size_t* bufferSize) +{ + SST_GraphicsEnumerator_Win32* enumWin32 = (SST_GraphicsEnumerator_Win32*)enumerator; + size_t len; + const char* name = &enumWin32->adapterNames[adapterId * ADAPTER_NAME_STRLEN]; + + len = strlen(name); + + /* Query name length */ + if(nameReturn == NULL) + { + *bufferSize = len+1; + } + else + { + size_t copyAmount; + + /* Nothing to do? */ + if(*bufferSize == 0) + return; + + /* Use min(len, (*bufferSize)-1) */ + copyAmount = len; + if(copyAmount > (*bufferSize)-1) + copyAmount = (*bufferSize)-1; + + memcpy(nameReturn, name, copyAmount); + nameReturn[copyAmount] = '\0'; + } + +} + +/*************************************************************************/ + +static size_t Win32_GetEnumScreenCount(SST_GraphicsEnumerator enumerator, size_t adapterId) +{ + SST_GraphicsEnumerator_Win32* enumWin32 = (SST_GraphicsEnumerator_Win32*)enumerator; + + return enumWin32->screenCount[adapterId]; +} + +/*************************************************************************/ + +static void Win32_GetEnumVideoModes(SST_GraphicsEnumerator enumerator, size_t adapterId, size_t screenId, SST_VideoMode* modesReturn, size_t* modeCountReturn) +{ + SST_GraphicsEnumerator_Win32* enumWin32 = (SST_GraphicsEnumerator_Win32*)enumerator; + size_t i; + ASMapEntry* entry = NULL; + + /* Determine which adapter-screen pair to use */ + for(i=0; i<enumWin32->ASPairCount; i++) + { + entry = &enumWin32->ASMap[i]; + if(entry->adapter == adapterId && entry->screen == screenId) + { + entry = &enumWin32->ASMap[i]; + break; + } + } + + /* When 'modesReturn' is null, user is getting mode count */ + if(modesReturn == NULL) + *modeCountReturn = entry->vmodeCount; + else /* else, copy '*modeCountReturn' number of modes */ + { + size_t nrCopy = *modeCountReturn; + if(nrCopy > entry->vmodeCount) + nrCopy = entry->vmodeCount; + + memcpy(modesReturn, entry->vmodes, sizeof(SST_VideoMode) * nrCopy); + } + +} + +/*************************************************************************/ + +static void Win32_GetEnumCurrentVideoMode(SST_GraphicsEnumerator enumerator, size_t adapterId, size_t screenId, SST_VideoMode* mode) +{ + SST_GraphicsEnumerator_Win32* enumWin32 = (SST_GraphicsEnumerator_Win32*)enumerator; + size_t i; + + for(i=0; i<enumWin32->ASPairCount; i++) + { + if(enumWin32->ASMap[i].adapter == adapterId && enumWin32->ASMap[i].screen == screenId) + { + *mode = enumWin32->ASMap[i].defaultVmode; + return; + } + } +} + +/*************************************************************************/ + +static void Win32_DestroyGraphicsEnumerator(SST_GraphicsEnumerator enumerator) +{ + SST_GraphicsEnumerator_Win32* enumWin32 = (SST_GraphicsEnumerator_Win32*)enumerator; + size_t i; + HANDLE hProcessHeap; + + hProcessHeap = GetProcessHeap(); + + HeapFree(hProcessHeap, 0, enumWin32->adapterNames); + HeapFree(hProcessHeap, 0, enumWin32->devsFound); + HeapFree(hProcessHeap, 0, enumWin32->screenCount); + + /* Free modes for each adapter-screen pair */ + for(i=0; i<enumWin32->ASPairCount; i++) + HeapFree(hProcessHeap, 0, enumWin32->ASMap[i].vmodes); + HeapFree(hProcessHeap, 0, enumWin32->ASMap); + + HeapFree(hProcessHeap, 0, enumWin32); +} + +struct SST_WM_EnumFuncs Win32_EnumFuncs = { + Win32_CreateGraphicsEnumerator, + Win32_GetEnumAdapterCount, + Win32_GetEnumAdapterName, + Win32_GetEnumScreenCount, + Win32_GetEnumVideoModes, + Win32_GetEnumCurrentVideoMode, + Win32_DestroyGraphicsEnumerator +}; diff --git a/libsst-wm/Win32/SST_WMEvent_Win32.c b/libsst-wm/Win32/SST_WMEvent_Win32.c new file mode 100644 index 0000000..90fdb94 --- /dev/null +++ b/libsst-wm/Win32/SST_WMEvent_Win32.c @@ -0,0 +1,90 @@ +/* + SST_WMEvent_Win32.c + Author: Patrick Baggett <ptbaggett@762studios.com> + Created: 6/5/2012 + + Purpose: + + Window event functions + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ + +#include <SST/SST_WMEvent.h> +#include "Win32Private.h" +#include "../APIPrivate.h" +static void copyAndRemoveUserEvent(SST_DisplayTarget_Win32* displayTarget, SST_WMEvent* eventReturn); + +/*************************************************************************/ + +static int Win32_GetEvent(SST_DisplayTarget target, SST_WMEvent* eventReturn) +{ + MSG msg; + SST_DisplayTarget_Win32* displayTarget = (SST_DisplayTarget_Win32*)target; + SST_Window_Win32* win; + int found = 0; + + /* First, get Win32 messages and dispatch to winproc. We + do this immediately, otherwise the OS thinks we've hung. */ + while(PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) + { + TranslateMessage(&msg); + DispatchMessageA(&msg); + } + + /* Check for user events */ + if(RemoveFromEQ(&displayTarget->userEventQueue, eventReturn)) + return 1; + + /* Now check each window's event queue */ + win = displayTarget->firstWindow; + while(win) + { + if(RemoveFromEQ(&win->eventQueue, eventReturn)) + { + found = 1; + break; + } + + win = win->next; + } + + return found; +} + +/*************************************************************************/ + +/* Platform-specific code dealing with user event queue */ + +static void Win32_lockUserEventQueue(SST_DisplayTarget target) +{ + SST_DisplayTarget_Win32* displayTarget = (SST_DisplayTarget_Win32*)target; + EnterCriticalSection(&displayTarget->userEventLock); +} + +static void Win32_unlockUserEventQueue(SST_DisplayTarget target) +{ + SST_DisplayTarget_Win32* displayTarget = (SST_DisplayTarget_Win32*)target; + LeaveCriticalSection(&displayTarget->userEventLock); +} + +static EventQueue* Win32_getUserEventQueue(SST_DisplayTarget target) +{ + + SST_DisplayTarget_Win32* displayTarget = (SST_DisplayTarget_Win32*)target; + return &displayTarget->userEventQueue; +} + +const struct SST_WM_EventFuncs Win32_EventFuncs = { + Win32_GetEvent, + Win32_getUserEventQueue, + Win32_lockUserEventQueue, + Win32_unlockUserEventQueue +}; diff --git a/libsst-wm/Win32/SST_WMNonPortable_Win32.c b/libsst-wm/Win32/SST_WMNonPortable_Win32.c new file mode 100644 index 0000000..e8cb9fc --- /dev/null +++ b/libsst-wm/Win32/SST_WMNonPortable_Win32.c @@ -0,0 +1,26 @@ +/* + SST_WMNonPortable_Win32.c + Author: Patrick Baggett <ptbaggett@762studios.com> + Created: 6/1/2012 + + Purpose: + + Non-portable API calls in libsst-wm for the Win32 platform + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ + +#include "Win32Private.h" + +HWND SST_WM_GetHWNDWin32(SST_Window window) +{ + return ((SST_Window_Win32*)window)->hWnd; +} + diff --git a/libsst-wm/Win32/SST_WMOpenGL_Win32.c b/libsst-wm/Win32/SST_WMOpenGL_Win32.c new file mode 100644 index 0000000..ac7aebc --- /dev/null +++ b/libsst-wm/Win32/SST_WMOpenGL_Win32.c @@ -0,0 +1,848 @@ +/* + SST_WMOpenGL_Win32.c + Author: Patrick Baggett <ptbaggett@762studios.com> + Created: 6/28/2012 + + Purpose: + + OpenGL context creation + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ +#include <SST/SST_WMOpenGL.h> +#include "Win32Private.h" +#include "../APIPrivate.h" +#include <GL/gl.h> + +/* + NOTE: Herein lines madness. Abandon faith all ye who would enter. + + Windows has been notoriously bad at keeping up with OpenGL progress. In particular, to get a modern context, + one must: + + 1) Create a fake window + 2) Select a fake pixel format + 4) Create a fake GL context + 5) Bind that context + 6) Resolve the wglGetExtensionStringARB() symbol + 7) Call wglGetExtensionStringARB() and check for various WGL extensions + 8) Resolve required extensions + 9) Select a real pixel format + 10) Create a real context + + This doesn't even consider the complexity of handling issues such as pushing/popping the current OpenGL context + so that calling SST_WM_CreateOpenGLContext() doesn't result in losing the currently active context, or providing + fallbacks in case the person wants GL <= 2.x and doesn't have the GL >= 3.x WGL extensions. So much madness. +*/ + +/* Create a temporary 1x1 window that is invisible */ +static HWND createTmpWindow(SST_DisplayTarget_Win32* copyFrom); + +/* Create OpenGL context that would probably work with Windows 95 */ +static SST_OpenGLContext legacyCreateOpenGLContext(SST_DisplayTarget_Win32* win, const SST_OpenGLContextAttributes* attribs, SST_OpenGLContextAttributes* selectedAttribsReturn, HMODULE opengl32, WGLFunctions* wgl); + +/* Use wglChoosePixelFormatARB() to find a useful pixel format */ +static int modernChoosePixelFormat(HDC hDC, WGLFunctions* wgl, const SST_OpenGLContextAttributes* attribs); + +/* Get selected pixel format return value information */ +static void modernGetPixelInfo(HDC hDC, int format, WGLFunctions* wgl, SST_OpenGLContextAttributes* selectedAttribsReturn); + +static int* addAttr(int* ptr, int x, int y) +{ + ptr[0] = x; + ptr[1] = y; + return ptr + 2; +} + +/*************************************************************************/ + +static SST_OpenGLContext Win32_CreateOpenGLContext(SST_DisplayTarget target, SST_WMOpenGLType apiType, const SST_OpenGLContextAttributes* attribs, SST_OpenGLContextAttributes* selectedAttribsReturn) +{ + HMODULE opengl32; + HWND hTmpWnd, hTmpWnd2; + HDC hTmpDC, hTmpDC2, oldDC = NULL; + HGLRC hTmpCtx, oldRC = NULL; + PIXELFORMATDESCRIPTOR pfd; + WGLFunctions wgl; + SST_DisplayTarget_Win32* displayTarget = (SST_DisplayTarget_Win32*)target; + SST_OpenGLContext_Win32* glctx; + int format; + int OK; + + /* Win32 doesn't have OpenGL ES AFAIK. */ + if(apiType == SSTGL_OPENGL_ES) + return NULL; + + /* Load opengl32.dll */ + opengl32 = LoadLibraryA("opengl32.dll"); + if(opengl32 == NULL) + return NULL; + + memset(&wgl, 0, sizeof(wgl)); + resolveWGLSymbols(opengl32, &wgl); + + /* + OK, this next code attempts to create an invisible window which can then be used + to bind a fake GL context to. This allows us to grab WGL extensions for advanced + OpenGL context creation (i.e. forward compatible contexts). If this isn't supported, + then old style context creation will be used as a fallback. + */ + hTmpWnd = createTmpWindow(displayTarget); + if(hTmpWnd == NULL) + { + FreeLibrary(opengl32); + return NULL; + } + + /* Grab the window's DC */ + hTmpDC = GetDC(hTmpWnd); + + /* Initialize pixel format descriptor to find 24-bit color / double-buffered / render to window */ + memset(&pfd, 0, sizeof(pfd)); + pfd.nSize = sizeof(pfd); + pfd.nVersion = 1; + pfd.dwFlags = PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER | PFD_DRAW_TO_WINDOW; + pfd.iPixelType = PFD_TYPE_RGBA; + pfd.cColorBits = 24; + pfd.cRedBits = 8; + pfd.cGreenBits = 8; + pfd.cBlueBits = 8; + pfd.cDepthBits = 24; + pfd.iLayerType = PFD_MAIN_PLANE; + + /* Attempt to find a matching pixel format */ + OK = 0; + hTmpCtx = NULL; + format = ChoosePixelFormat(hTmpDC, &pfd); + if(format > 0) + { + /* Attempt to set the pixel format */ + OK = (int)SetPixelFormat(hTmpDC, format, &pfd); + if(OK) + { + /* Create the context */ + hTmpCtx = wgl.CreateContext(hTmpDC); + OK = (hTmpCtx != NULL); + + /* Bind it */ + if(OK) + { + /* Save old context */ + oldDC = wgl.GetCurrentDC(); + oldRC = wgl.GetCurrentContext(); + + OK = (int)wgl.MakeCurrent(hTmpDC, hTmpCtx); + } + } + } + + /* Failed in any of these steps? */ + if(!OK) + { + if(hTmpCtx != NULL) + { + wgl.DeleteContext(hTmpCtx); + + /* Restore old context (since wglMakeCurrent() failed with new context) */ + wgl.MakeCurrent(oldDC, oldRC); + + } + ReleaseDC(hTmpWnd, hTmpDC); + DestroyWindow(hTmpWnd); + FreeLibrary(opengl32); + return NULL; + } + + /* Resolve context-specific strings */ + resolveWGLExtSymbols(hTmpDC, &wgl); + + /* Only "legacy" context functions allowed? */ + if(wgl.ChoosePixelFormatARB == NULL || wgl.CreateContextAttribsARB == NULL) + { + /* Remove temporary context / window, they aren't needed for legacy contexts */ + wgl.MakeCurrent(oldDC, oldRC); + wgl.DeleteContext(hTmpCtx); + ReleaseDC(hTmpWnd, hTmpDC); + DestroyWindow(hTmpWnd); + + /* Just make a legacy context */ + return legacyCreateOpenGLContext(displayTarget, attribs, selectedAttribsReturn, opengl32, &wgl); + } + else /* "Modern" context creation */ + { + #define MAX_CTX_ATTRS 16 + int contextAttrs[MAX_CTX_ATTRS]; + int* ptr; + HGLRC hGLRC; + size_t i; + int ctxFlags = 0; + + /* Create another set of temporary handles. Since we already called + SetPixelFormat() on hTmpDC, we can't set it to the new pixel format + that we picked with modernChoosePixelFormat(). Thus, if we do wglCreateContext() with + hTmpDC, we'll get an invalid context. Instead, create a new window/DC and use the new + pixel format. */ + hTmpWnd2 = createTmpWindow(displayTarget); + hTmpDC2 = GetDC(hTmpWnd2); + + /* Choose a pixel format */ + format = modernChoosePixelFormat(hTmpDC2, &wgl, attribs); + if(format == 0) + { + wgl.MakeCurrent(oldDC, oldRC); + wgl.DeleteContext(hTmpCtx); + ReleaseDC(hTmpWnd, hTmpDC); + DestroyWindow(hTmpWnd); + } + SetPixelFormat(hTmpDC2, format, NULL); + + i = 0; + + if(attribs->debugEnabled) + ctxFlags |= WGL_CONTEXT_DEBUG_BIT_ARB; + ptr = contextAttrs; + ptr = addAttr(ptr, WGL_CONTEXT_MAJOR_VERSION_ARB, attribs->contextVersionMajor); + ptr = addAttr(ptr, WGL_CONTEXT_MINOR_VERSION_ARB, attribs->contextVersionMinor); + ptr = addAttr(ptr, WGL_CONTEXT_LAYER_PLANE_ARB, 0); + + /* If WGL_ARB_create_context_profile is supported, add a profile mask */ + if(wgl.supportsProfiles) + ptr = addAttr(ptr, WGL_CONTEXT_PROFILE_MASK_ARB, (attribs->legacyEnabled ? WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB : WGL_CONTEXT_CORE_PROFILE_BIT_ARB)); + + /* Legacy-free? */ + if(!attribs->legacyEnabled) + ctxFlags |= WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB; + + /* Debug mode? */ + if(attribs->debugEnabled) + ctxFlags |= WGL_CONTEXT_DEBUG_BIT_ARB; + + ptr = addAttr(ptr, WGL_CONTEXT_FLAGS_ARB, ctxFlags); + *ptr = 0; + + + + /* Create the OpenGL context */ + hGLRC = wgl.CreateContextAttribsARB(hTmpDC2, NULL, contextAttrs); + glctx = (SST_OpenGLContext_Win32*)HeapAlloc(GetProcessHeap(), 0, sizeof(SST_OpenGLContext_Win32)); + if(hGLRC == NULL || glctx == NULL) + { + if(hGLRC != NULL) + wgl.DeleteContext(hGLRC); + if(glctx != NULL) + HeapFree(GetProcessHeap(), 0, glctx); + wgl.MakeCurrent(oldDC, oldRC); + wgl.DeleteContext(hTmpCtx); + ReleaseDC(hTmpWnd, hTmpDC); + DestroyWindow(hTmpWnd); + ReleaseDC(hTmpWnd2, hTmpDC2); + DestroyWindow(hTmpWnd2); + + return NULL; + } + glctx->displayTarget = displayTarget; + glctx->context = hGLRC; + glctx->hDCActive = NULL; + glctx->hSlaveWnd = NULL; + glctx->opengl32 = opengl32; + glctx->pixelFormat = format; + glctx->wgl = wgl; + glctx->isLegacy = FALSE; + glctx->ctxVersion[0] = (short)attribs->contextVersionMajor; + glctx->ctxVersion[1] = (short)attribs->contextVersionMinor; + glctx->legacyEnabled = attribs->legacyEnabled? TRUE : FALSE; + glctx->debugEnabled = attribs->debugEnabled? TRUE : FALSE; + + if(selectedAttribsReturn) + { + modernGetPixelInfo(hTmpDC2, format, &wgl, selectedAttribsReturn); + selectedAttribsReturn->contextVersionMajor = attribs->contextVersionMajor; + selectedAttribsReturn->contextVersionMinor = attribs->contextVersionMinor; + selectedAttribsReturn->legacyEnabled = (attribs->legacyEnabled ? 1 : 0); + selectedAttribsReturn->debugEnabled = (ctxFlags & WGL_CONTEXT_DEBUG_BIT_ARB ? 1 : 0); + } + + /* Delete temporary window */ + wgl.MakeCurrent(oldDC, oldRC); + wgl.DeleteContext(hTmpCtx); + ReleaseDC(hTmpWnd, hTmpDC); + DestroyWindow(hTmpWnd); + ReleaseDC(hTmpWnd2, hTmpDC2); + DestroyWindow(hTmpWnd2); + } + + return glctx; +} + +/*************************************************************************/ + +static SST_OpenGLContext Win32_CreateSlaveOpenGLContext(SST_OpenGLContext masterGLContext) +{ + SST_OpenGLContext_Win32* master = (SST_OpenGLContext_Win32*)masterGLContext; + SST_OpenGLContext_Win32* slave; + HWND hInvisWnd; + FindMonitorInfo fmi; + HDC hDC = NULL; + HGLRC hGLRC = NULL; + BOOL ok; + const WGLFunctions* wgl = &master->wgl; + + /* Since the slave context merely needs to be on *a* screen controlled by the display target, just use the first one */ + findMonitor(&master->displayTarget->devs[0], &fmi); + if(!fmi.foundIt) + return NULL; + + /* Make 1x1 hidden window that doesn't appear in the titlebar and has no borders */ + hInvisWnd = CreateWindowExA(WS_EX_TOOLWINDOW, SST_WINCLASS, "(temp)", WS_POPUP, fmi.left, fmi.top, 1, 1, NULL, NULL, GetModuleHandleA(NULL), NULL); + if(hInvisWnd == NULL) + return NULL; + ShowWindow(hInvisWnd, SW_HIDE); + + /* Allocate context structure */ + slave = HeapAlloc(GetProcessHeap(), 0, sizeof(SST_OpenGLContext_Win32)); + if(slave == NULL) + { + DestroyWindow(hInvisWnd); + return NULL; + } + + ok = FALSE; + hDC = GetDC(hInvisWnd); + + /* If master context was done using legacy functions... */ + if(master->isLegacy) + { + PIXELFORMATDESCRIPTOR pfd; + + /* Get the PFD for this pixel foramt */ + DescribePixelFormat(hDC, master->pixelFormat, sizeof(pfd), &pfd); + + /* Set it */ + if(SetPixelFormat(hDC, master->pixelFormat, &pfd)) + { + hGLRC = wgl->CreateContext(hDC); + if(hGLRC != NULL) + { + if(wgl->ShareLists(master->context, hGLRC)) + ok = TRUE; + } + } + + } + else /* Modern OpenGL functions */ + { + if(SetPixelFormat(hDC, master->pixelFormat, NULL)) + { + HGLRC oldRC; + HDC oldDC; + + oldDC = wgl->GetCurrentDC(); + oldRC = wgl->GetCurrentContext(); + + /* Bind master context so we can call wgl extension functions. Note that we're using + the invisible window's HDC. This should work because we just set the pixel format to be + identical to the master context, meaning they should be compatible */ + if(wgl->MakeCurrent(hDC, master->context)) + { + int attrs[16]; + int* ptr = attrs; + int ctxFlags; + + if(master->debugEnabled) + ctxFlags |= WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB; + + ptr = addAttr(ptr, WGL_CONTEXT_MAJOR_VERSION_ARB, master->ctxVersion[0]); + ptr = addAttr(ptr, WGL_CONTEXT_MINOR_VERSION_ARB, master->ctxVersion[1]); + ptr = addAttr(ptr, WGL_CONTEXT_LAYER_PLANE_ARB, 0); + + /* If WGL_ARB_create_context_profile is supported, add a profile mask */ + if(wgl->supportsProfiles) + ptr = addAttr(ptr, WGL_CONTEXT_PROFILE_MASK_ARB, (master->legacyEnabled ? WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB : WGL_CONTEXT_CORE_PROFILE_BIT_ARB)); + + /* Legacy-free? */ + if(!master->legacyEnabled) + ctxFlags |= WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB; + + /* Debug mode? */ + if(master->debugEnabled) + ctxFlags |= WGL_CONTEXT_DEBUG_BIT_ARB; + + ptr = addAttr(ptr, WGL_CONTEXT_FLAGS_ARB, ctxFlags); + *ptr = 0; + + /* Create the new context, sharing with the master context */ + hGLRC = wgl->CreateContextAttribsARB(hDC, master->context, attrs); + if(hGLRC != NULL) + ok = TRUE; + } + + /* Restore old context */ + wgl->MakeCurrent(oldDC, oldRC); + } + } + + /* Done with the DC */ + if(hDC) + ReleaseDC(hInvisWnd, hDC); + + /* Did we succeed in making the slave context? */ + if(ok) + { + /* Set up slave context info */ + slave->context = hGLRC; + slave->displayTarget = master->displayTarget; + slave->hDCActive = NULL; + slave->hSlaveWnd = hInvisWnd; + slave->isLegacy = master->isLegacy; + slave->opengl32 = LoadLibraryA("opengl32.dll"); /* Need to increase ref count for opengl32.dll */ + slave->pixelFormat = master->pixelFormat; + slave->wgl = master->wgl; /* TODO: should be safe, right? context dependent, but same device/GL impl... */ + slave->ctxVersion[0] = master->ctxVersion[0]; + slave->ctxVersion[1] = master->ctxVersion[1]; + slave->legacyEnabled = master->legacyEnabled; + slave->debugEnabled = master->debugEnabled; + } + else /* Failure, clean up */ + { + if(hGLRC) + master->wgl.DeleteContext(hGLRC); + + DestroyWindow(hInvisWnd); + + HeapFree(GetProcessHeap(), 0, slave); + slave = NULL; + } + + return slave; +} + +/*************************************************************************/ + +static void Win32_SwapOpenGLBuffers(SST_OpenGLContext ctx) +{ + SST_OpenGLContext_Win32* glctx = (SST_OpenGLContext_Win32*)ctx; + + SwapBuffers(glctx->hDCActive); +} + +/*************************************************************************/ + +static int Win32_BindOpenGLContext(SST_OpenGLContext ctx, SST_Window window) +{ + SST_OpenGLContext_Win32* glctx = (SST_OpenGLContext_Win32*)ctx; + SST_Window_Win32* win = (SST_Window_Win32*)window; + + /* Unbinding a context from a thread */ + if(ctx == NULL) + { + HMODULE opengl32; + + /* We actually need some WGL symbols. Oops. That's OK, we can just grab the symbol */ + pf_wglMakeCurrent sst_wglMakeCurrent; + pf_wglGetCurrentDC sst_wglGetCurrentDC; + + /* We use LoadLibrary() instead of GetModuleHandle() so that we don't unmap the DLL + in the middle of using it. */ + opengl32 = LoadLibraryA("opengl32.dll"); + if(opengl32) + { + HDC hDC; + HWND hWnd; + + sst_wglMakeCurrent = (pf_wglMakeCurrent)GetProcAddress(opengl32, "wglMakeCurrent"); + sst_wglGetCurrentDC = (pf_wglGetCurrentDC)GetProcAddress(opengl32, "wglGetCurrentDC"); + + /* Release the DC */ + hDC = sst_wglGetCurrentDC(); + hWnd = WindowFromDC(hDC); + if(hDC != NULL && hWnd != NULL) + ReleaseDC(hWnd, hDC); + + /* OK, unbind it */ + sst_wglMakeCurrent(NULL, NULL); + + FreeLibrary(opengl32); + } + + /* OK */ + return 1; + } + else /* Have a valid context */ + { + HDC hDC, oldDC; + HGLRC oldRC; + + if( (glctx->hSlaveWnd != NULL && win != NULL) || /* Slave context provided a SST_Window */ + (glctx->hSlaveWnd == NULL && win == NULL) /* Master context with no SST_Window */ + ) + { + /* Both are illegal according the the functions */ + return 0; + } + + /* Get old context info */ + oldDC = glctx->wgl.GetCurrentDC(); + oldRC = glctx->wgl.GetCurrentContext(); + + /* First, are we re-binding the same context? If so, then just return "success" */ + if( oldDC != NULL && oldRC != NULL && + oldDC == glctx->hDCActive && oldRC == glctx->context) + return 1; + + /* Binding master context to a window */ + if(win != NULL) + { + hDC = GetDC(win->hWnd); + + /* Haven't set the pixel format for this window yet? */ + if(!win->setPixelFormat) + { + PIXELFORMATDESCRIPTOR pfd; + DescribePixelFormat(hDC, glctx->pixelFormat, sizeof(pfd), &pfd); + + if(SetPixelFormat(hDC, glctx->pixelFormat, &pfd)) + { + /* OK, mark that we've set this window's pixel format once, and we won't do it again. */ + win->setPixelFormat = TRUE; + } + else + { + /* Failed to set this window's pixel format, so we can't do much */ + return 0; + } + } + } + else /* Bind slave context */ + { + hDC = GetDC(glctx->hSlaveWnd); + + } + + /* Make current */ + if(!glctx->wgl.MakeCurrent(hDC, glctx->context)) + { + /* Failed -- restore old context settings */ + glctx->wgl.MakeCurrent(oldDC, oldRC); + return 0; + } + + /* Since we were successful, release the old DC */ + if(oldDC) + { + HWND hWnd = WindowFromDC(oldDC); + if(hWnd) + ReleaseDC(hWnd, oldDC); + } + + /* Save window / DC */ + glctx->hDCActive = hDC; + } + + return 1; +} + +/*************************************************************************/ + +static void Win32_DestroyOpenGLContext(SST_OpenGLContext ctx) +{ + SST_OpenGLContext_Win32* glctx = (SST_OpenGLContext_Win32*)ctx; + + if(glctx->hSlaveWnd) + DestroyWindow(glctx->hSlaveWnd); + + glctx->wgl.DeleteContext(glctx->context); + FreeLibrary(glctx->opengl32); + + HeapFree(GetProcessHeap(), 0, glctx); +} + +/*************************************************************************/ + +static HWND createTmpWindow(SST_DisplayTarget_Win32* copyFrom) +{ + HWND hTmpWnd; + FindMonitorInfo fmi; + + /* Find the first monitor */ + findMonitor(©From->devs[0], &fmi); + if(!fmi.foundIt) + return NULL; + + /* Make 1x1 hidden window that doesn't appear in the titlebar and has no borders */ + hTmpWnd = CreateWindowExA(WS_EX_TOOLWINDOW, SST_WINCLASS, "(temp)", WS_POPUP, fmi.left, fmi.top, 1, 1, NULL, NULL, GetModuleHandleA(NULL), NULL); + if(hTmpWnd == NULL) + return NULL; + + ShowWindow(hTmpWnd, SW_HIDE); + + return hTmpWnd; +} + +/*************************************************************************/ + +static SST_OpenGLContext legacyCreateOpenGLContext(SST_DisplayTarget_Win32* displayTarget, const SST_OpenGLContextAttributes* attribs, SST_OpenGLContextAttributes* selectedAttribsReturn, HMODULE opengl32, WGLFunctions* wgl) +{ + PIXELFORMATDESCRIPTOR pfd; + HWND hWnd; + HDC hDC, oldDC = NULL; + HGLRC hGLRC, oldRC = NULL; + int format; + int major, minor; + const char* version; + const GLubyte* (APIENTRY *sst_glGetString)(GLenum); + SST_OpenGLContext_Win32* ctx; + BYTE rgb[3] = { 1, 1, 1 }; + + /* No multisample support, but 2x or greater MSAA requested -> fail */ + if(attribs->multisampleFactor > 1) + { + FreeLibrary(opengl32); + return NULL; + } + + /* Allocate a GL context */ + ctx = (SST_OpenGLContext_Win32*)HeapAlloc(GetProcessHeap(), 0, sizeof(SST_OpenGLContext_Win32)); + if(ctx == NULL) + { + FreeLibrary(opengl32); + return NULL; + } + + /* Get window DC */ + hWnd = createTmpWindow(displayTarget); + hDC = GetDC(hWnd); + + /* We can't do MSAA at all, though */ + if(attribs->multisampleFactor > 1) + { + FreeLibrary(opengl32); + return NULL; + } + + /* Figure out how to set up color bits. These are minimums. MSDN states that they + are "Not used", but be safe anyways. */ + if(attribs->colorBits == 24) + { + rgb[0] = rgb[1] = rgb[2] = 8; + } + else if(attribs->colorBits == 16 || attribs->colorBits == 15) + { + /* 555 or 565 color. Set all to 5 since "minimum" of 5 allows for 565 too */ + rgb[0] = rgb[1] = rgb[2] = 5; + } + + /* Initialize the PFD */ + memset(&pfd, 0, sizeof(pfd)); + pfd.nSize = sizeof(pfd); + pfd.nVersion = 1; + pfd.dwFlags = PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER | PFD_DRAW_TO_WINDOW | (attribs->stereoEnabled? PFD_STEREO : 0); + pfd.iPixelType = PFD_TYPE_RGBA; + pfd.cColorBits = attribs->colorBits; + pfd.cAlphaBits = attribs->alphaBits; + pfd.cRedBits = rgb[0]; + pfd.cGreenBits = rgb[1]; + pfd.cBlueBits = rgb[2]; + pfd.cDepthBits = attribs->depthBits; + pfd.cStencilBits = attribs->stencilBits; + pfd.iLayerType = PFD_MAIN_PLANE; + + /* Get a compatiable pixel format */ + format = ChoosePixelFormat(hDC, &pfd); + if(format == 0) + { + ReleaseDC(hWnd, hDC); + DestroyWindow(hWnd); + FreeLibrary(opengl32); + return NULL; + } + + /* Get info about the pixel format we're using */ + if(selectedAttribsReturn != NULL) + { + PIXELFORMATDESCRIPTOR spfd; + DescribePixelFormat(hDC, format, sizeof(spfd), &spfd); + + selectedAttribsReturn->alphaBits = pfd.cAlphaBits; + selectedAttribsReturn->colorBits = pfd.cColorBits; + selectedAttribsReturn->contextVersionMajor = 0; + selectedAttribsReturn->contextVersionMinor = 0; + selectedAttribsReturn->depthBits = pfd.cDepthBits; + selectedAttribsReturn->multisampleFactor = 1; + selectedAttribsReturn->stencilBits = pfd.cStencilBits; + selectedAttribsReturn->stereoEnabled = (pfd.dwFlags & PFD_STEREO); + + + } + + /* Set the pixel format for the device */ + if(!SetPixelFormat(hDC, format, &pfd)) + { + ReleaseDC(hWnd, hDC); + DestroyWindow(hWnd); + FreeLibrary(opengl32); + return NULL; + } + + /* Create the GL context */ + hGLRC = wgl->CreateContext(hDC); + if(hGLRC == NULL) + { + ReleaseDC(hWnd, hDC); + DestroyWindow(hWnd); + FreeLibrary(opengl32); + return NULL; + } + + /* Activate the context to see if correct version was set */ + oldDC = wgl->GetCurrentDC(); + oldRC = wgl->GetCurrentContext(); + if(!wgl->MakeCurrent(hDC, hGLRC)) + { + wgl->DeleteContext(hGLRC); + ReleaseDC(hWnd, hDC); + DestroyWindow(hWnd); + FreeLibrary(opengl32); + return NULL; + } + + /* Resolve glGetString() and call it to check version number matching */ + sst_glGetString = (const GLubyte* (APIENTRY*)(GLenum name))GetProcAddress(opengl32, "glGetString"); + version = (const char*)sst_glGetString(GL_VERSION); + major = (int)(version[0] - '0'); /* "X.Y" -> [0]:major, [2]:minor */ + minor = (int)(version[2] - '0'); + + /* Got version info. Detach our context, restore old one */ + wgl->MakeCurrent(oldDC, oldRC); + + /* Save context version information */ + if(selectedAttribsReturn != NULL) + { + selectedAttribsReturn->contextVersionMajor = (uint8_t)major; + selectedAttribsReturn->contextVersionMinor = (uint8_t)minor; + } + + /* If the major version is too low or the major version is OK, but the minor version is lacking, then fail */ + if(major < attribs->contextVersionMajor || + (major == attribs->contextVersionMajor && minor < attribs->contextVersionMinor)) + { + wgl->DeleteContext(hGLRC); + ReleaseDC(hWnd, hDC); + DestroyWindow(hWnd); + FreeLibrary(opengl32); + return NULL; + } + + ReleaseDC(hWnd, hDC); + DestroyWindow(hWnd); + + ctx->displayTarget = displayTarget; + ctx->hSlaveWnd = NULL; + ctx->hDCActive = NULL; + ctx->opengl32 = opengl32; + ctx->wgl = *wgl; + ctx->pixelFormat = format; + ctx->context = hGLRC; + ctx->isLegacy = TRUE; + ctx->ctxVersion[0] = (short)major; + ctx->ctxVersion[1] = (short)minor; + ctx->legacyEnabled = FALSE; /* These refer to profiles in GL >= 3.x contexts. Here they are meaningless, so set to false */ + ctx->debugEnabled = FALSE; + + return (SST_OpenGLContext)ctx; +} + +/*************************************************************************/ + +static int modernChoosePixelFormat(HDC hDC, WGLFunctions* wgl, const SST_OpenGLContextAttributes* attribs) +{ + int attrs[MAX_GL_ATTRS]; + int format; + int* ptr = attrs; + UINT nrFormats; + BOOL ok; + + + /* Set up basic attributes */ + ptr = addAttr(ptr, WGL_DRAW_TO_WINDOW_ARB, GL_TRUE); + ptr = addAttr(ptr, WGL_SUPPORT_OPENGL_ARB, GL_TRUE); + ptr = addAttr(ptr, WGL_DOUBLE_BUFFER_ARB, GL_TRUE); + ptr = addAttr(ptr, WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB); + ptr = addAttr(ptr, WGL_COLOR_BITS_ARB, attribs->colorBits); + ptr = addAttr(ptr, WGL_ALPHA_BITS_ARB, attribs->alphaBits); + ptr = addAttr(ptr, WGL_DEPTH_BITS_ARB, attribs->depthBits); + ptr = addAttr(ptr, WGL_STENCIL_BITS_ARB, attribs->stencilBits); + ptr = addAttr(ptr, WGL_STEREO_ARB, attribs->stereoEnabled ? GL_TRUE : GL_FALSE); /* Must be GL_TRUE || GL_FALSE, not just "non-zero" */ + + /* Multisampling requested? */ + if(attribs->multisampleFactor > 1) + { + /* Is it supported? */ + if(wgl->supportsMultisample) + { + ptr = addAttr(ptr, WGL_SAMPLE_BUFFERS_ARB, 1); + ptr = addAttr(ptr, WGL_SAMPLES_ARB, attribs->multisampleFactor); + } + else + return 0; + } + *ptr = 0; + + nrFormats = 0; + /* Attempt to get pixel formats that match ours */ + ok = wgl->ChoosePixelFormatARB(hDC, attrs, NULL, 1, &format, &nrFormats); + + /* This can return success with 0 formats, so check if it was actually "successful" in finding > 0 formats */ + if(!ok || nrFormats == 0) + return 0; + + return format; +} + +/*************************************************************************/ + +static void modernGetPixelInfo(HDC hDC, int format, WGLFunctions* wgl, SST_OpenGLContextAttributes* selectedAttribsReturn) +{ + int attrs[8]; + int values[8] = { 0 }; + int attrCount; + + attrs[0] = WGL_COLOR_BITS_ARB; + attrs[1] = WGL_ALPHA_BITS_ARB; + attrs[2] = WGL_DEPTH_BITS_ARB; + attrs[3] = WGL_STENCIL_BITS_ARB; + attrs[4] = WGL_STEREO_ARB; + attrs[5] = WGL_SAMPLE_BUFFERS_ARB; + + /* Check multisample */ + attrCount = (wgl->supportsMultisample ? 6 : 5); + + + wgl->GetPixelFormatAttribivARB(hDC, format, 0, attrCount, attrs, values); + + + selectedAttribsReturn->colorBits = (uint8_t)values[0]; + selectedAttribsReturn->alphaBits = (uint8_t)values[1]; + selectedAttribsReturn->depthBits = (uint8_t)values[2]; + selectedAttribsReturn->stencilBits = (uint8_t)values[3]; + selectedAttribsReturn->stereoEnabled = (uint8_t)values[4]; + if(wgl->supportsMultisample) + selectedAttribsReturn->multisampleFactor = (uint8_t)values[5]; + else + selectedAttribsReturn->multisampleFactor = 1; + +} + +const struct SST_WM_OpenGLFuncs Win32_OpenGLFuncs = { + Win32_CreateOpenGLContext, + Win32_CreateSlaveOpenGLContext, + Win32_SwapOpenGLBuffers, + Win32_BindOpenGLContext, + Win32_DestroyOpenGLContext +}; diff --git a/libsst-wm/Win32/SST_WMRender_Win32.c b/libsst-wm/Win32/SST_WMRender_Win32.c new file mode 100644 index 0000000..f619215 --- /dev/null +++ b/libsst-wm/Win32/SST_WMRender_Win32.c @@ -0,0 +1,97 @@ +/* + SST_WMRender_Win32.c + Author: Patrick Baggett <ptbaggett@762studios.com> + Created: 9/19/2012 + + Purpose: + + Software rendering support (Win32) + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ + +#include "Win32Private.h" +#include "../APIPrivate.h" +#include <SST/SST_WMWindow.h> + +/*************************************************************************/ + +static int Win32_EnableSoftwareRendering(SST_Window window) +{ + SST_Window_Win32* win = (SST_Window_Win32*)window; + HDC hDC; + HDC hDCTmp; + HBITMAP hBMP; + RECT r; + + hDCTmp = GetDC(win->hWnd); + hDC = CreateCompatibleDC(hDCTmp); + + if(GetDeviceCaps(hDCTmp, BITSPIXEL) != 32) + { + DeleteDC(hDC); + return 0; + } + + GetClientRect(win->hWnd, &r); + + hBMP = CreateCompatibleBitmap(hDCTmp, r.right, r.bottom); + SelectObject(hDC, hBMP); + + ReleaseDC(win->hWnd, hDCTmp); + + win->softwareDC = hDC; + win->softwareImage = hBMP; + win->softwareBackbuffer = HeapAlloc(GetProcessHeap(), 0, (SIZE_T)r.right * (SIZE_T)r.bottom * 4); + win->softwarePitch = r.right * 4; + + return 1; +} + +/*************************************************************************/ + +static void Win32_DisableSoftwareRendering(SST_Window window) +{ + SST_Window_Win32* win = (SST_Window_Win32*)window; + + if(win->softwareBackbuffer) + HeapFree(GetProcessHeap(), 0, win->softwareBackbuffer); + if(win->softwareDC) + DeleteDC(win->softwareDC); + if(win->softwareImage) + DeleteObject(win->softwareImage); +} + +/*************************************************************************/ + +static void* Win32_LockBackbuffer(SST_Window window, size_t* pitchReturn) +{ + SST_Window_Win32* win = (SST_Window_Win32*)window; + + *pitchReturn = win->softwarePitch; + + return win->softwareBackbuffer; +} + +/*************************************************************************/ + +static void Win32_UnlockBackbuffer(SST_Window window) +{ + SST_Window_Win32* win = (SST_Window_Win32*)window; + InvalidateRect(win->hWnd, NULL, FALSE); + UpdateWindow(win->hWnd); +} + +struct SST_WM_RenderFuncs Win32_RenderFuncs = { + Win32_EnableSoftwareRendering, + Win32_DisableSoftwareRendering, + Win32_LockBackbuffer, + Win32_UnlockBackbuffer +}; diff --git a/libsst-wm/Win32/SST_WMVideoMode_Win32.c b/libsst-wm/Win32/SST_WMVideoMode_Win32.c new file mode 100644 index 0000000..564e882 --- /dev/null +++ b/libsst-wm/Win32/SST_WMVideoMode_Win32.c @@ -0,0 +1,72 @@ +/* + SST_WMVideoMode_Win32.c + Author: Patrick Baggett <ptbaggett@762studios.com> + Created: 6/26/2012 + + Purpose: + + Video mode setting functions + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ + +#include "Win32Private.h" +#include "../APIPrivate.h" + +/*************************************************************************/ + +static int Win32_SetVideoModeOnScreen(SST_DisplayTarget target, size_t screenIndex, const SST_VideoMode* vmode) +{ + DEVMODEA devMode; + SST_DisplayTarget_Win32* displayTarget = (SST_DisplayTarget_Win32*)target; + const DISPLAY_DEVICEA* dev = &displayTarget->devs[screenIndex]; + + memset(&devMode, 0, sizeof(devMode)); + devMode.dmSize = sizeof(devMode); + devMode.dmBitsPerPel = vmode->bpp; + devMode.dmPelsWidth = vmode->width; + devMode.dmPelsHeight = vmode->height; + devMode.dmDisplayFrequency = vmode->refreshRate; + devMode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFREQUENCY; + + return (ChangeDisplaySettingsExA(dev->DeviceName, &devMode, NULL, CDS_FULLSCREEN, NULL) == DISP_CHANGE_SUCCESSFUL); +} + +/*************************************************************************/ + +static int Win32_GetVideoModeOnScreen(SST_DisplayTarget target, size_t screenIndex, SST_VideoMode* vmodeReturn) +{ + SST_DisplayTarget_Win32* displayTarget = (SST_DisplayTarget_Win32*)target; + const DISPLAY_DEVICEA* dev = &displayTarget->devs[screenIndex]; + DEVMODEA devMode; + int ok = 0; + + devMode.dmSize = sizeof(devMode); + + if(EnumDisplaySettingsA(dev->DeviceName, ENUM_CURRENT_SETTINGS, &devMode)) + { + vmodeReturn->bpp = devMode.dmBitsPerPel; + vmodeReturn->width = devMode.dmPelsWidth; + vmodeReturn->height = devMode.dmPelsHeight; + vmodeReturn->refreshRate = devMode.dmDisplayFrequency; + + if(vmodeReturn->refreshRate == 1) + vmodeReturn->refreshRate = SST_DEFAULT_REFRESHRATE; + + ok = 1; + } + + return ok; +} + +const struct SST_WM_VideoModeFuncs Win32_VideoModeFuncs = { + Win32_SetVideoModeOnScreen, + Win32_GetVideoModeOnScreen +}; diff --git a/libsst-wm/Win32/SST_WMWindow_Win32.c b/libsst-wm/Win32/SST_WMWindow_Win32.c new file mode 100644 index 0000000..28b6c40 --- /dev/null +++ b/libsst-wm/Win32/SST_WMWindow_Win32.c @@ -0,0 +1,667 @@ +/* + SST_WMWindow_Win32.c + Author: Patrick Baggett <ptbaggett@762studios.com> + Created: 6/1/2012 + + Purpose: + + Window creation (Win32) + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ + +#include <SST/SST_WMWindow.h> +#include "Win32Private.h" +#include "../EventQueue.h" +#include "../APIPrivate.h" + +static LONG regRefCount = 0; + + + +/*************************************************************************/ + +static SST_DisplayTarget Win32_CreateDisplayTarget(size_t adapterIndex, size_t screenIndexOrMultihead) +{ + DISPLAY_DEVICEA* devs; + size_t devCount; + SST_DisplayTarget_Win32* displayTarget; + + + /* Get Win32 devices */ + devs = get_win32devs(&devCount); + if(devs == NULL) + return NULL; + + /* Filter the list */ + devCount = filter_win32devs(devs, devCount, adapterIndex); + if(devCount == 0) + { + HeapFree(GetProcessHeap(), 0, devs); + return NULL; + } + + /* Not doing multihead? */ + if(screenIndexOrMultihead != SST_MULTIHEAD) + { + /* Does the screen index exceed the number of attached screens? */ + if(screenIndexOrMultihead >= devCount) + { + /* Failure */ + HeapFree(GetProcessHeap(), 0, devs); + return NULL; + } + + } + + /* Allocate a display target structure */ + displayTarget = (SST_DisplayTarget_Win32*)HeapAlloc(GetProcessHeap(), 0, sizeof(SST_DisplayTarget_Win32)); + if(displayTarget == NULL) + { + /* Failure */ + HeapFree(GetProcessHeap(), 0, devs); + return NULL; + } + + /* Initialize user event queue */ + if(!InitEQ(&displayTarget->userEventQueue)) + { + /* Failure */ + HeapFree(GetProcessHeap(), 0, displayTarget); + HeapFree(GetProcessHeap(), 0, devs); + return NULL; + } + + + InitializeCriticalSection(&displayTarget->userEventLock); + displayTarget->devs = devs; + displayTarget->screenCount = devCount; + displayTarget->screenIndex = screenIndexOrMultihead; + displayTarget->firstWindow = NULL; + displayTarget->relativeMouse = FALSE; + + /* Register class if the refcount == 1 */ + if(InterlockedIncrement(®RefCount) == 1) + { + WNDCLASSEXA wc; + + memset(&wc, 0, sizeof(wc)); + wc.cbSize = sizeof(wc); + wc.lpszClassName = SST_WINCLASS; + wc.hInstance = GetModuleHandleA(NULL); + wc.lpfnWndProc = libsstWndProc; + wc.hCursor = LoadCursor(NULL, IDC_ARROW); + wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); + wc.style = CS_OWNDC; + wc.hbrBackground = (HBRUSH)(uintptr_t)(COLOR_WINDOW+1); + RegisterClassExA(&wc); + } + + return (SST_DisplayTarget)displayTarget; +} + +/*************************************************************************/ + +static size_t Win32_GetDisplayTargetScreenCount(SST_DisplayTarget target) +{ + SST_DisplayTarget_Win32* displayTarget = (SST_DisplayTarget_Win32*)target; + + /* + Multihead -> real screen count + Otherwise -> 1 + */ + if(displayTarget->screenIndex == SST_MULTIHEAD) + return displayTarget->screenCount; + + return 1; +} + +/*************************************************************************/ + +static SST_Window Win32_CreateWindowOnScreen(SST_DisplayTarget target, size_t screenIndex, uint32_t x, uint32_t y, uint32_t width, uint32_t height, const char* title) +{ + RECT r; + DWORD style, styleEx; + HWND hWnd; + SST_Window_Win32* win; + SST_DisplayTarget_Win32* displayTarget = (SST_DisplayTarget_Win32*)target; + FindMonitorInfo fmi; + + /* Attempt to find the monitor associated with a display device */ + findMonitor(&displayTarget->devs[screenIndex], &fmi); + + /* Didn't find it? */ + if(!fmi.foundIt) + return NULL; + + /* Allocate SST window structure */ + win = (SST_Window_Win32*)HeapAlloc(GetProcessHeap(), 0, sizeof(SST_Window_Win32)); + if(win == NULL) + return NULL; + + win->owner = displayTarget; + win->next = displayTarget->firstWindow; + win->owner = displayTarget; + win->isFullscreen = FALSE; + win->setPixelFormat = FALSE; + win->softwareBackbuffer = NULL; + win->softwareDC = NULL; + win->softwareImage = NULL; + win->softwarePitch = 0; + + /* These styles may be useful later. + DWORD style = (Fullscreen ? WS_POPUP : WS_CAPTION | WS_SYSMENU); + DWORD styleEx = (Multihead2ndWindow? WS_EX_TOOLWINDOW : WS_EX_APPWINDOW); + */ + style = WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX; + styleEx = WS_EX_APPWINDOW; + + /* Start the window relative to those coordinates */ + r.top = 0; + r.left = 0; + r.bottom = (LONG)height; + r.right = (LONG)width; + AdjustWindowRectEx(&r, style, FALSE, styleEx); + + if(r.top != 0) + { + LONG d = -r.top; + + r.top = 0; + r.bottom += d; + } + if(r.left != 0) + { + LONG d = -r.left; + + r.left = 0; + r.right += d; + } + + r.top += fmi.top + (LONG)y; + r.left += fmi.left + (LONG)x; + r.bottom += r.top; + r.right += r.left; + + + hWnd = CreateWindowExA( + styleEx, + SST_WINCLASS, + title, + style, + r.left, r.top, /* XY position */ + r.right-r.left, r.bottom-r.top, /* Position */ + NULL, /* parent window */ + NULL, GetModuleHandleA(NULL), win); + + /* Failed to create window */ + if(hWnd == NULL) + { + HeapFree(GetProcessHeap(), 0, win); + return NULL; + } + + /* Save window info */ + win->hWnd = hWnd; + + ShowWindow(hWnd, SW_SHOW); + + /* Link window as new root */ + displayTarget->firstWindow = win; + + return (SST_Window)win; +} + +/*************************************************************************/ + +static SST_DisplayTarget Win32_GetWindowDisplayTarget(SST_Window window) +{ + SST_Window_Win32* win = (SST_Window_Win32*)window; + + return win->owner; +} + +/*************************************************************************/ + +static void Win32_SetWindowText(SST_Window window, const char* titleBar) +{ + SST_Window_Win32* win = (SST_Window_Win32*)window; + + SetWindowTextA(win->hWnd, titleBar); +} + +/*************************************************************************/ + +static void Win32_GetWindowRect(SST_Window window, SST_Rect* rectReturn) +{ + SST_Window_Win32* win = (SST_Window_Win32*)window; + MONITORINFO info; + RECT rectClient; + RECT rectWin; + + /* Get info about the monitor the window is on */ + info.cbSize = sizeof(info); + if(!GetMonitorInfoA(MonitorFromWindow(win->hWnd, MONITOR_DEFAULTTONEAREST), &info)) + return; + + /* This returns (0,0) - (w,h). I don't know why they bother using a RECT instead + of a POINT structure, since the top/left is always (0,0). */ + GetClientRect(win->hWnd, &rectClient); + + GetWindowRect(win->hWnd, &rectWin); + + rectReturn->x = (uint32_t)(rectWin.left - info.rcMonitor.left); + rectReturn->y = (uint32_t)(rectWin.top - info.rcMonitor.top); + rectReturn->width = (uint32_t)rectClient.right; + rectReturn->height = (uint32_t)rectClient.bottom; +} + +/*************************************************************************/ + +static void Win32_MoveWindowOnScreen(SST_Window window, size_t screenIndex, uint32_t x, uint32_t y) +{ + FindMonitorInfo fmi; + SST_Window_Win32* win = (SST_Window_Win32*)window; + SST_DisplayTarget_Win32* displayTarget = win->owner; + int px, py; + + if(screenIndex != SST_SAME_SCREEN) + { + /* Atttempt to find the monitor associated with a display device */ + findMonitor(&displayTarget->devs[screenIndex], &fmi); + + /* Didn't find it? (monitor unplugged?) */ + if(!fmi.foundIt) + return; + + /* New position = monitor base + offset */ + px = (int)x + (int)fmi.top; + py = (int)y + (int)fmi.left; + } + else /* Move relative to the same screen */ + { + MONITORINFO info; + + /* Get info about the monitor the window is on */ + info.cbSize = sizeof(info); + if(!GetMonitorInfoA(MonitorFromWindow(win->hWnd, MONITOR_DEFAULTTONEAREST), &info)) + return; + + px = (int)x + (int)info.rcMonitor.left; + py = (int)y + (int)info.rcMonitor.top; + } + + SetWindowPos(win->hWnd, NULL, + px, py, + 0, 0, + SWP_NOOWNERZORDER | SWP_NOSIZE); + +} + +/*************************************************************************/ + +static void Win32_ResizeWindow(SST_Window window, uint32_t width, uint32_t height) +{ + SST_Window_Win32* win = (SST_Window_Win32*)window; + RECT r; + BOOL hasMenu; + HWND hParent; + + /* Get the client & window rect */ + GetClientRect(win->hWnd, &r); + + r.right = r.left + (LONG)width; + r.bottom = r.top + (LONG)height; + + hParent = (HWND)GetWindowLongPtrA(win->hWnd, GWLP_HWNDPARENT); + if(hParent == NULL) + hasMenu = (GetMenu(win->hWnd) != NULL); + else + hasMenu = FALSE; + + + AdjustWindowRectEx(&r, GetWindowLongA(win->hWnd, GWL_STYLE), hasMenu, GetWindowLongA(win->hWnd, GWL_EXSTYLE)); + + SetWindowPos(win->hWnd, NULL, 0, 0, r.right - r.left, r.bottom - r.top, SWP_NOOWNERZORDER | SWP_NOMOVE); +} + +/*************************************************************************/ + +static void Win32_SetWindowState(SST_Window window, SST_WMWindowState state, uint32_t param) +{ + SST_Window_Win32* win = (SST_Window_Win32*)window; + + switch(state) + { + case SSTWS_SHOWN: + { + int cmd; + if(param == 0) + cmd = SW_HIDE; + else + cmd = SW_SHOW; + + ShowWindow(win->hWnd, cmd); + break; + } + + /* Turn on/off resizeability */ + case SSTWS_RESIZEABLE: + { + DWORD style; + RECT rect; + POINT tl, br; + + /* Get info about the window */ + style = GetWindowLongA(win->hWnd, GWL_STYLE); + GetClientRect(win->hWnd, &rect); + + tl.x = rect.left; + tl.y = rect.top; + + br.x = rect.right; + br.y = rect.bottom; + + ClientToScreen(win->hWnd, &tl); + ClientToScreen(win->hWnd, &br); + + rect.left = tl.x; + rect.top = tl.y; + rect.right = br.x; + rect.bottom = br.y; + + + if(param == 0) + style &= ~(WS_THICKFRAME | WS_MAXIMIZEBOX); + else + style |= (WS_THICKFRAME | WS_MAXIMIZEBOX); + + AdjustWindowRectEx(&rect, style, (GetMenu(win->hWnd) ? TRUE : FALSE), GetWindowLongA(win->hWnd, GWL_EXSTYLE)); + SetWindowLongA(win->hWnd, GWL_STYLE, (LONG)style); + + /* MSDN: "Certain window data is cached, so changes you make using SetWindowLong() will not take effect until you + call the SetWindowPos() function." So, let's update it... */ + SetWindowPos(win->hWnd, NULL, + rect.left, rect.top, + rect.right - rect.left, + rect.bottom - rect.top, + SWP_NOZORDER | SWP_FRAMECHANGED); + break; + } + + case SSTWS_FULLSCREEN: + { + DWORD style; + + /* Enabling fullscreen? */ + if(param && !win->isFullscreen) + { + MONITORINFO info; + RECT r; + POINT pt; + + /* Get current window style */ + style = GetWindowLongA(win->hWnd, GWL_STYLE); + + /* Save info about the window so when we exit fullscreen, we're good */ + win->wp.length = sizeof(win->wp); + GetWindowPlacement(win->hWnd, &win->wp); + GetWindowRect(win->hWnd, &r); + pt.x = r.top; + pt.y = r.left; + + + + /* Get info about the monitor the window is on */ + info.cbSize = sizeof(MONITORINFO); + GetMonitorInfo(MonitorFromPoint(pt, MONITOR_DEFAULTTONEAREST), &info); + + /* Remove title bar, caption, etc. */ + SetWindowLong(win->hWnd, GWL_STYLE, style & (~WS_OVERLAPPEDWINDOW)); + + /* Move & resize to cover entire screen */ + SetWindowPos(win->hWnd, HWND_TOP, + (int)info.rcMonitor.left, (int)info.rcMonitor.top, /* Position window in the top-left corner */ + (int)(info.rcMonitor.right - info.rcMonitor.left), /* Width = width of monitor */ + (int)(info.rcMonitor.bottom - info.rcMonitor.top), /* Height = height of monitor */ + SWP_NOOWNERZORDER | SWP_FRAMECHANGED); /* Don't change*/ + + + win->isFullscreen = TRUE; + } + else if(win->isFullscreen) /* Disabling fullscreen */ + { + style = GetWindowLongA(win->hWnd, GWL_STYLE); + SetWindowLong(win->hWnd, GWL_STYLE, style | WS_OVERLAPPEDWINDOW); + + /* Restore old window placement */ + SetWindowPlacement(win->hWnd, &win->wp); + SetWindowPos(win->hWnd, NULL, 0, 0, 0, 0, + SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_FRAMECHANGED); + + win->isFullscreen = FALSE; + } + + break; + } + + case SSTWS_MINIMIZED: + { + int cmd; + if(param == 0) + { + SST_WMEvent* event; + cmd = SW_RESTORE; + + /* Win32 doesn't send a restore message if pragmatically restored, so do it ourselves */ + event = AllocSlotInEQ(&win->eventQueue); + if(event) + { + event->window = win; + event->type = SSTWMEVENT_RESTORED; + memset(&event->details, 0, sizeof(event->details)); + } + } + else + cmd = SW_MINIMIZE; + + ShowWindow(win->hWnd, cmd); + break; + } + + default: break; + } +} + +/*************************************************************************/ + +static void Win32_SetDisplayTargetState(SST_DisplayTarget target, SST_WMDisplayTargetState state, uint32_t param) +{ + SST_DisplayTarget_Win32* displayTarget = (SST_DisplayTarget_Win32*)target; + + switch(state) + { + case SSTDTS_RELMOUSE: + { + RAWINPUTDEVICE rawMouse = { 0x01, 0x02, 0, NULL }; /* Mouse: UsagePage = 1, Usage = 2 */ + + /* Disabling? */ + if(displayTarget->relativeMouse && param == 0) + { + rawMouse.dwFlags |= RIDEV_REMOVE; + + /* Attempt to unregister raw mouse. If successful, set 'relativeMouse' to FALSE */ + if(RegisterRawInputDevices(&rawMouse, 1, sizeof(RAWINPUTDEVICE))) + { + displayTarget->relativeMouse = FALSE; + ClipCursor(NULL); + ShowCursor(TRUE); + } + } + else if(!displayTarget->relativeMouse && param != 0) /* Enabling? */ + { + if(RegisterRawInputDevices(&rawMouse, 1, sizeof(RAWINPUTDEVICE))) + { + HWND active; + SST_Window_Win32* win; + + displayTarget->relativeMouse = TRUE; + ShowCursor(FALSE); + + /* Decide if this window belows to any in this display target, if so, lock cursor into it */ + active = GetActiveWindow(); + win = displayTarget->firstWindow; + + while(win) + { + /* It does belong to this display target, so lock it into place */ + if(win->hWnd == active) + { + LONG cx, cy; + RECT rect; + + GetWindowRect(win->hWnd, &rect); + cx = (rect.left + rect.right) / 2; + cy = (rect.top + rect.bottom) / 2; + + /* Ensure cursor cannot leave the center of the window */ + rect.left = cx-1; + rect.right = cx+1; + rect.top = cy-1; + rect.bottom = cy+1; + ClipCursor(&rect); + break; + } + else + win = win->next; + } + } + } + + break; + } + } +} + +/*************************************************************************/ + +static void Win32_DestroyWindow(SST_Window window) +{ + SST_DisplayTarget_Win32* displayTarget; + SST_Window_Win32* win = (SST_Window_Win32*)window; + SST_Window_Win32* nextWin; + + displayTarget = win->owner; + nextWin = displayTarget->firstWindow; + + /* Special case: root window */ + if(nextWin == win) + { + /* Set new root to be this->next */ + displayTarget->firstWindow = win->next; + } + else + { + int found = 0; + + /* Check list */ + while(nextWin) + { + /* Did we find the window? */ + if(nextWin->next == win) + { + /* Remove this window from the linked list */ + nextWin->next = win->next; + found = 1; + break; + } + else + nextWin = nextWin->next; + } + + /* Don't destroy another display target's window */ + if(!found) + return; + + } + /* Actually destroy the Win32 window */ + DestroyWindow(win->hWnd); + + if(win->softwareBackbuffer) + HeapFree(GetProcessHeap(), 0, win->softwareBackbuffer); + if(win->softwareDC) + DeleteDC(win->softwareDC); + if(win->softwareImage) + DeleteObject(win->softwareImage); + + + /* TODO empty message queue? */ + + /* Free the window */ + HeapFree(GetProcessHeap(), 0, win); +} + +/*************************************************************************/ + +static void Win32_DestroyDisplayTarget(SST_DisplayTarget target) +{ + SST_DisplayTarget_Win32* displayTarget = (SST_DisplayTarget_Win32*)target; + SST_Window_Win32* window = displayTarget->firstWindow; + + /* Destroy all windows */ + while(window) + { + /* Save the next window */ + SST_Window_Win32* next = window->next; + + /* Actually destroy the Win32 window handle */ + DestroyWindow(window->hWnd); + HeapFree(GetProcessHeap(), 0, window); + + /* + TODO: should we empty the message queue of all messages owned by this window? Do + they automatically get removed? Aiiyeeee! + */ + + /* Move to next window */ + window = next; + } + + /* Delete user event queue lock */ + DeleteCriticalSection(&displayTarget->userEventLock); + + + /* Free structures */ + DestroyEQ(&displayTarget->userEventQueue); + HeapFree(GetProcessHeap(), 0, displayTarget->devs); + HeapFree(GetProcessHeap(), 0, displayTarget); + + /* Unregister */ + if(InterlockedDecrement(®RefCount) == 0) + UnregisterClassA(SST_WINCLASS, GetModuleHandleA(NULL)); +} + +extern int Win32_ShowDialogBox(SST_DisplayTarget target, SST_Window parent, const char* caption, const char* message, const char** buttons, int nrButtons); + +const struct SST_WM_WindowFuncs Win32_WindowFuncs = { + Win32_CreateDisplayTarget, + Win32_GetDisplayTargetScreenCount, + Win32_CreateWindowOnScreen, + Win32_GetWindowDisplayTarget, + Win32_SetWindowText, + Win32_GetWindowRect, + Win32_MoveWindowOnScreen, + Win32_ResizeWindow, + Win32_ShowDialogBox, + Win32_SetWindowState, + Win32_SetDisplayTargetState, + Win32_DestroyWindow, + Win32_DestroyDisplayTarget +}; diff --git a/libsst-wm/Win32/Win32Driver.c b/libsst-wm/Win32/Win32Driver.c new file mode 100644 index 0000000..120843c --- /dev/null +++ b/libsst-wm/Win32/Win32Driver.c @@ -0,0 +1,62 @@ +/* + Win32Driver.c + Author: Patrick Baggett <ptbaggett@762studios.com> + Created: 12/18/2014 + + Purpose: + + Windows (Win32 API) driver for libsst-wm + + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ +#include "../APIPrivate.h" +#include "Win32Private.h" + +extern const struct SST_WM_WindowFuncs Win32_WindowFuncs; +extern const struct SST_WM_EnumFuncs Win32_EnumFuncs; +extern const struct SST_WM_EventFuncs Win32_EventFuncs; +extern const struct SST_WM_OpenGLFuncs Win32_OpenGLFuncs; +extern const struct SST_WM_RenderFuncs Win32_RenderFuncs; +extern const struct SST_WM_VideoModeFuncs Win32_VideoModeFuncs; + + +/******************************************************************************/ + +int Win32_init() +{ + if(getenv("LIBSST_NO_WIN32")) + return 0; + + + return 1; +} + +/******************************************************************************/ + +void Win32_shutdown() +{ + /* Nothing to do (now) */ + return; +} + +/******************************************************************************/ + +const struct SST_WM_Driver Win32Driver = { + "Win32 Driver", + Win32_init, + Win32_shutdown, + &Win32_WindowFuncs, + &Win32_EnumFuncs, + &Win32_EventFuncs, + &Win32_OpenGLFuncs, + &Win32_RenderFuncs, + &Win32_VideoModeFuncs +}; diff --git a/libsst-wm/Win32/Win32Private.c b/libsst-wm/Win32/Win32Private.c new file mode 100644 index 0000000..c11a186 --- /dev/null +++ b/libsst-wm/Win32/Win32Private.c @@ -0,0 +1,1351 @@ +/* + Win32Private.c + Author: Patrick Baggett <ptbaggett@762studios.com> + Created: 6/1/2012 + + Purpose: + + Private defintions and functions for Win32 implementation of libsst-wm + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ + +#include "Win32Private.h" +#include <SST/SST_WMRender.h> + +static SST_WMKey Win32KeyToSSTKey(WPARAM vkey, LPARAM lParam); +static int extSupported(const char* extlist, const char* s); +static BOOL CALLBACK findMonitorCallback(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData); + +DISPLAY_DEVICEA* get_win32devs(size_t* devCountReturn) +{ + DWORD devID = 0; + BOOL cont; + DISPLAY_DEVICEA* devsFound = NULL; + size_t devCount = 0; + size_t i; + HANDLE hProcessHeap; + + hProcessHeap = GetProcessHeap(); + + do + { + /* Initialize device structure */ + DISPLAY_DEVICEA dev; + memset(&dev, 0, sizeof(dev)); + dev.cb = sizeof(dev); + + /* Try to enumerator the next device */ + cont = EnumDisplayDevicesA(NULL, devID, &dev, 0); + if(cont) + { + if( (dev.StateFlags & DISPLAY_DEVICE_ACTIVE) && /* Device must be active */ + ((dev.StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER) == 0)) /* Device must not be a mirror (i.e. fake) */ + { + void* ptr; + + /* Attempt Heap[Re]Alloc(). Don't leak memory if it does! */ + if(devsFound == NULL) + ptr = HeapAlloc(hProcessHeap, 0, (devCount+1) * sizeof(DISPLAY_DEVICEA)); + else + ptr = HeapReAlloc(hProcessHeap, 0, devsFound, (devCount+1)* sizeof(DISPLAY_DEVICEA)); + if(ptr == NULL) + { + /* The Heap[Re]Alloc() call failed, so if there is any memory that was allocated, HeapFree() it now */ + if(devsFound != NULL) + HeapFree(hProcessHeap, 0, devsFound); + + /* Failure -> out of memory */ + return NULL; + } + + devsFound = (DISPLAY_DEVICEA*)ptr; + + devsFound[devCount] = dev; + devCount++; + } + } + + /* Try the next Win32 device */ + devID++; + } while(cont); + + /* No graphics adapters found! */ + if(devsFound == NULL) + return NULL; + + /* Search for the Win32 "primary device" -- make sure it is always the first device in the list. The + "primary device" flag is only set on one of these structures, so once we find it, we can stop. */ + for(i=0; i<devCount; i++) + { + if((devsFound[i].StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE) && i != 0) + { + /* Swap with slot 0 */ + DISPLAY_DEVICEA tmp; + + memcpy(&tmp, &devsFound[0], sizeof(DISPLAY_DEVICEA)); + memcpy(&devsFound[0], &devsFound[i], sizeof(DISPLAY_DEVICEA)); + memcpy(&devsFound[i], &tmp, sizeof(DISPLAY_DEVICEA)); + break; + } + } + + *devCountReturn = devCount; + return devsFound; +} + +/*************************************************************************/ + +char* get_adapters(const DISPLAY_DEVICEA* devsFound, size_t devCount, size_t* adapterCountReturn, char** adapterGUIDReturn) +{ + char* adapterNames = NULL; + char* adapterGUIDs = NULL; + size_t adapterCount = 0; + size_t i; + HANDLE hProcessHeap; + + hProcessHeap = GetProcessHeap(); + + /* + We now have an array of DISPLAY_DEVICEs. These represent individual screens, not the actual number + of adapters. To find that out, we'll have to count the number of unique occurrences of the graphics + card's GUID in the DeviceKey field. + + The DeviceKey field of DISPLAY_DEVICE is this long registry key, specifically, in the format of: + + "\Registry\Machine\System\CurrentControlSet\Control\Video\{<long GUID>}\<screen id>" + + For example, the last part might be something like "{deadc0de-1122-3344}\0000" + The part in the {}s is unique per card, so we count how many unique strings there are to + figure out how many graphics adapters there are. + */ + + /* A quick note about 'adapterNames'. It is one "char*", but logically, it is an array of fixed-length + strings. Every 'STRLEN_GUID' bytes is a string, so string at index 'k' is '&adapterNames[k*STRLEN_GUID]' */ + + for(i=0; i<devCount; i++) + { + /* Copy the string between the {}s */ + char* start; + char* end; + char* rdp; + char tmpGuid[STRLEN_GUID]; + void* ptr; + + /* + RDP devices have "RDP" in the name and no '{'. There will + only be one, so we can break out early. + */ + rdp = strstr(devsFound[i].DeviceKey, "RDP"); + + /* Find pointers to the { and } characters. */ + start = strchr(devsFound[i].DeviceKey, '{'); + + /* Found RDP device? */ + if(rdp != NULL && start == NULL && devCount == 1) + { + char* guid; + char* name; + + guid = HeapAlloc(hProcessHeap, 0, STRLEN_GUID); + if(guid == NULL) + return NULL; + + name = HeapAlloc(hProcessHeap, 0, ADAPTER_NAME_STRLEN); + if(name == NULL) + { + HeapFree(hProcessHeap, 0, guid); + return NULL; + } + + /* This is the one and only RDP device. */ + strcpy(name, devsFound[i].DeviceString); + strcpy(guid, "fake guid"); + *adapterCountReturn = 1; + *adapterGUIDReturn = guid; + + return name; + } + + end = strchr(start, '}'); + + /* Copy the characters in between */ + memcpy(tmpGuid, start+1, (end - start - 1)); + tmpGuid[end-start-1] = 0; + + /* Check the array for matches */ + if(adapterGUIDs) + { + size_t j; + int found = 0; + + for(j=0; j<adapterCount; j++) + { + if(!strcmp(&adapterGUIDs[j*STRLEN_GUID], tmpGuid)) + { + found = 1; + break; + } + } + + /* Try next device */ + if(found) + continue; + + } + + /* -> No match -- add this adapter to the list of adapters */ + + /* Expand array of GUIDs */ + if(adapterGUIDs == NULL) + ptr = HeapAlloc(hProcessHeap, 0, (adapterCount+1) * STRLEN_GUID); + else + ptr = HeapReAlloc(hProcessHeap, 0, adapterGUIDs, (adapterCount+1) * STRLEN_GUID); + if(ptr == NULL) + { + /* Clean up */ + if(adapterGUIDs) + HeapFree(hProcessHeap, 0, adapterGUIDs); + if(adapterNames) + HeapFree(hProcessHeap, 0, adapterNames); + + /* Return out of memory */ + return NULL; + } /* <- all error handling */ + + + adapterGUIDs = (char*)ptr; + + /* Copy the new adapter name over */ + strcpy(&adapterGUIDs[adapterCount*STRLEN_GUID], tmpGuid); + + /* Expand array of adapter names */ + if(adapterNames == NULL) + ptr = HeapAlloc(hProcessHeap, 0, (adapterCount+1) * ADAPTER_NAME_STRLEN); + else + ptr = HeapReAlloc(hProcessHeap, 0, adapterNames, (adapterCount+1) * ADAPTER_NAME_STRLEN); + if(ptr == NULL) + { + HeapFree(hProcessHeap, 0, adapterGUIDs); /* This must be non-NULL or else we would have failed by now */ + if(adapterNames != NULL) + HeapFree(hProcessHeap, 0, adapterGUIDs); + + /* Return out of memory */ + return NULL; + } + adapterNames = (char*)ptr; + + /* Copy the new adapter name over */ + strcpy(&adapterNames[adapterCount*ADAPTER_NAME_STRLEN], devsFound[i].DeviceString); + + + adapterCount++; + } /* for each device -> look for unique graphics adapters */ + + + *adapterCountReturn = adapterCount; + *adapterGUIDReturn = adapterGUIDs; + return adapterNames; +} + +/*************************************************************************/ + +/* + Filter a list of Win32 devices in-place; modify list so that only relevant Win32 devices are returned. + For example, if there are 3 devices: { Gpu0Screen0, Gpu1Screen0, Gpu1Screen1}, and adapterIndex == 1, + then this returns { Gpu1Screen0, Gpu1Screen1 } in place. The number of devices in the filtered list are + returned (in the example, 2). +*/ +size_t filter_win32devs(DISPLAY_DEVICEA* devsFound, size_t devCount, size_t adapterIndex) +{ + char* adapterGUIDs = NULL; + char* GUID; + size_t i; + size_t adapterCount = 0; + size_t matched = 0; + size_t len = 0; + HANDLE hProcessHeap; + + hProcessHeap = GetProcessHeap(); + + /* + STEP 1: Get list of adapter GUIDs + */ + for(i=0; i<devCount; i++) + { + /* Copy the string between the {}s */ + char* start; + char* end; + char* rdp; + void* ptr; + char tmpGuid[STRLEN_GUID]; + + /* + RDP devices have "RDP" in the name and no '{'. There will + only be one, so we can return this immediately + */ + rdp = strstr(devsFound[i].DeviceKey, "RDP"); + + /* Find pointers to the { and } characters. */ + start = strchr(devsFound[i].DeviceKey, '{'); + + if(rdp != NULL && start == NULL && adapterIndex == 0 && devCount == 1) + { + /* This is the one and only RDP device. Just return that it's already all good. */ + return 1; + } + end = strchr(start, '}'); + + /* GUIDs are constant length, but we save the length here in case it ever changes */ + if(len == 0) + len = end - start - 1; + + /* Copy the characters in between */ + memcpy(tmpGuid, start+1, (end - start - 1)); + tmpGuid[end-start-1] = 0; + + + /* Check the array for matches */ + if(adapterGUIDs) + { + size_t j; + int found = 0; + + for(j=0; j<adapterCount; j++) + { + if(!strcmp(&adapterGUIDs[j*STRLEN_GUID], tmpGuid)) + { + found = 1; + break; + } + } + + /* Try next device */ + if(found) + continue; + + } + + /* -> No match -- add this adapter to the list of adapters */ + + /* Expand array of GUIDs */ + if(adapterGUIDs == NULL) + ptr = HeapAlloc(hProcessHeap, 0, (adapterCount+1) * STRLEN_GUID); + else + ptr = HeapReAlloc(hProcessHeap, 0, adapterGUIDs, (adapterCount+1) * STRLEN_GUID); + if(ptr == NULL) + { + /* Clean up */ + if(adapterGUIDs) + HeapFree(hProcessHeap, 0, adapterGUIDs); + + /* Return out of memory */ + return 0; + } /* <- all error handling */ + + + adapterGUIDs = (char*)ptr; + + /* Copy the new adapter name over */ + strcpy(&adapterGUIDs[adapterCount*STRLEN_GUID], tmpGuid); + + adapterCount++; + } /* for each device -> look for unique graphics adapters */ + + /* Invalid index? */ + if(adapterCount <= adapterIndex) + { + if(adapterGUIDs != NULL) + HeapFree(hProcessHeap, 0, adapterGUIDs); + return 0; + } + + /* + STEP 2: Filter list based on adapter GUIDs + */ + GUID = &adapterGUIDs[adapterIndex*STRLEN_GUID]; + for(i=0; i<devCount; i++) + { + char* start; + + /* Find pointer to start of GUID */ + start = strchr(devsFound[i].DeviceKey, '{') + 1; + + /* Does this display device match the GUID of the adapter we're interested in? */ + if(memcmp(start, GUID, len) == 0) + { + /* Is it not already in place? */ + if(matched < i) + { + /* Move from current location to correct location. Since 'matched' only increases + we examine a device and find it matching, it can never be larger than the current + device index we're examining (i.e. we can't have matched 5 devices but only examined + 3). Thus, 'matched' is always <= 'i', so we'll never overwrite an index we needed to + keep around. */ + memmove(&devsFound[matched], &devsFound[i], sizeof(DISPLAY_DEVICEA)); + } + + matched++; + } + + } + + /* Return number of adapters matched */ + HeapFree(hProcessHeap, 0, adapterGUIDs); + return matched; +} + +/*************************************************************************/ + +ASMapEntry* build_asmap(const DISPLAY_DEVICEA* devsFound, const char* adapterNames, size_t devCount, size_t adapterCount, size_t* screenCount, size_t* mapSizeReturn) +{ + size_t i; + size_t j; + size_t mapSize = 0; + ASMapEntry* ASMap = NULL; + HANDLE hProcessHeap; + + hProcessHeap = GetProcessHeap(); + + for(i=0; i<devCount; i++) + { + const char* start = strchr(devsFound[i].DeviceKey, '{'); + const char* end = strchr(start, '}'); + const size_t size = (size_t)(end - start - 1); + const DISPLAY_DEVICEA* thisDev = &devsFound[i]; + + for(j=0; j<adapterCount; j++) + { + /* Matches the adapter? */ + if(strncmp(start+1, &adapterNames[j*STRLEN_GUID], size) == 0) + { + void* ptr; + + /* Convert the ID to an integer */ + size_t screenId = screenCount[j]; + + /* This adapter has one more screen */ + screenCount[j] += 1; + + /* Increase map size */ + if(ASMap == NULL) + ptr = HeapAlloc(hProcessHeap, 0, (mapSize+1) * sizeof(ASMapEntry)); + else + ptr = HeapReAlloc(hProcessHeap, 0, ASMap, (mapSize+1) * sizeof(ASMapEntry)); + if(ptr == NULL) + { + if(ASMap) + HeapFree(hProcessHeap, 0, ASMap); + return NULL; + } + + /* Insert into the map */ + ASMap = (ASMapEntry*)ptr; + + ASMap[mapSize].adapter = j; + ASMap[mapSize].screen = screenId; + ASMap[mapSize].dev = thisDev; + mapSize += 1; + + } /* if device name matches adapter name */ + } /* try each adapter */ + } /* for each Win32 DISPLAY_DEVICE structure... */ + + + *mapSizeReturn = mapSize; + return ASMap; +} + +/*************************************************************************/ + +SST_VideoMode* get_vmodes(const DISPLAY_DEVICEA* dev, size_t* modeCountReturn, SST_VideoMode* defaultMode) +{ + SST_VideoMode* vmodes; + size_t modeCount = 0; + DEVMODEA devMode; + DWORD mode = 0; + + devMode.dmSize = sizeof(devMode); + vmodes = NULL; + + if(!EnumDisplaySettingsA(dev->DeviceName, ENUM_CURRENT_SETTINGS, &devMode)) + return NULL; + + defaultMode->bpp = (uint32_t)devMode.dmBitsPerPel; + defaultMode->width = (uint32_t)devMode.dmPelsWidth; + defaultMode->height = (uint32_t)devMode.dmPelsHeight; + defaultMode->refreshRate = (uint32_t)devMode.dmDisplayFrequency; + + if(defaultMode->refreshRate == 1) + defaultMode->refreshRate = 0; + + /* Enumerate all display mode settings */ + while(EnumDisplaySettingsA(dev->DeviceName, mode, &devMode)) + { + if(devMode.dmBitsPerPel >= MIN_BPP) /* Ignore low color modes */ + { + void* ptr; + + if(vmodes == NULL) + ptr = HeapAlloc(GetProcessHeap(), 0, (modeCount+1) * sizeof(SST_VideoMode)); + else + ptr = HeapReAlloc(GetProcessHeap(), 0, vmodes, (modeCount+1) * sizeof(SST_VideoMode)); + if(ptr == NULL) + { + if(vmodes) + HeapFree(GetProcessHeap(), 0, vmodes); + } + + vmodes = (SST_VideoMode*)ptr; + + vmodes[modeCount].bpp = (uint32_t)devMode.dmBitsPerPel; + vmodes[modeCount].width = (uint32_t)devMode.dmPelsWidth; + vmodes[modeCount].height = (uint32_t)devMode.dmPelsHeight; + vmodes[modeCount].refreshRate = (uint32_t)devMode.dmDisplayFrequency; + + /* Sometimes a value of 0 or 1 is returned to indicate "default". Normalize to just 0 */ + if(vmodes[modeCount].refreshRate == 1) + vmodes[modeCount].refreshRate = 0; + + modeCount += 1; + } + mode++; + } + + *modeCountReturn = modeCount; + return vmodes; +} + +/*************************************************************************/ + +LRESULT WINAPI libsstWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + HANDLE hProcessHeap; + SST_Window_Win32* win; + uint32_t updown = 0; + + hProcessHeap = GetProcessHeap(); + #define GETWINPTR() win = (SST_Window_Win32*)GetWindowLongPtr(hWnd, GWLP_USERDATA) + + switch(msg) + { + case WM_PAINT: + { + GETWINPTR(); + if(win && win->softwareImage != NULL) + { + PAINTSTRUCT ps; + RECT r; + + InvalidateRect(hWnd, NULL, FALSE); + GetClientRect(win->hWnd, &r); + + BeginPaint(hWnd, &ps); /* store into a bitmap */ + SetMapMode(ps.hdc, MM_TEXT); /* blit a bitmap */ + SetBitmapBits(win->softwareImage, r.right * r.bottom * 4, (void*)win->softwareBackbuffer); + BitBlt(ps.hdc, 0, 0, r.right, r.bottom, win->softwareDC, 0, 0, SRCCOPY); + EndPaint(hWnd, &ps); + + } + else /* Ignore WM_PAINT */ + return DefWindowProc(hWnd, msg, wParam, lParam); + + break; + } + + + case WM_CREATE: + { + CREATESTRUCTA* createStruct = (CREATESTRUCTA*)lParam; + SST_WMEvent* event; + + /* Get the pointer we passed to CreateWindow[Ex]() */ + win = (SST_Window_Win32*)createStruct->lpCreateParams; + + /* The window can be a temporary window, in which case lpCreateParams will be NULL. Don't + throw an exception here. */ + if(win) + { + /* Initialize the event queue */ + if(!InitEQ(&win->eventQueue)) + return -1; /* Tell Windows to have CreateWindow[Ex]() fail */ + + /* Get an event (it really shouldn't fail!) */ + event = AllocSlotInEQ(&win->eventQueue); + if(event == NULL) + { + DestroyEQ(&win->eventQueue); + return -1; + } + + /* Set up SSTWMEVENT_CREATED */ + event->window = win; + event->type = SSTWMEVENT_CREATED; + memset(&event->details, 0, sizeof(event->details)); + + /* Save window queue */ + SetWindowLongPtrA(hWnd, GWLP_USERDATA, (LONG_PTR)win); + } + break; + } + + /********/ + + case WM_DESTROY: + { + GETWINPTR(); + if(win != NULL) + { + /* Free all memory associated with it */ + DestroyEQ(&win->eventQueue); + } + + break; + } + + /********/ + + case WM_CLOSE: + { + GETWINPTR(); + if(win) + { + SST_WMEvent* event; + + event = AllocSlotInEQ(&win->eventQueue); + if(event) + { + event->window = win; + event->type = SSTWMEVENT_CLOSE; + memset(&event->details, 0, sizeof(event->details)); + } + } + break; + } + + case WM_ACTIVATE: + { + GETWINPTR(); + if(win) + { + if(win->owner->relativeMouse) + { + WORD active = LOWORD(wParam); + + if(active == WA_ACTIVE || active == WA_CLICKACTIVE) + { + LONG cx, cy; + RECT rect; + + GetWindowRect(win->hWnd, &rect); + + cx = (rect.left + rect.right) / 2; + cy = (rect.top + rect.bottom) / 2; + + /* Ensure cursor cannot leave the center */ + rect.left = cx-1; + rect.right = cx+1; + rect.top = cy-1; + rect.bottom = cy+1; + + ClipCursor(&rect); + } + } + } + break; + } + + /********/ + + case WM_SYSCOMMAND: + { + /* MSDN: In WM_SYSCOMMAND messages, the four low-order bits of the wParam parameter are used internally by the system. */ + const WPARAM command = wParam & 0xFFF0; + + /* Restored */ + if(command == SC_RESTORE) + { + GETWINPTR(); + if(win) + { + SST_WMEvent* event; + + event = AllocSlotInEQ(&win->eventQueue); + if(event) + { + event->window = win; + event->type = SSTWMEVENT_RESTORED; + memset(&event->details, 0, sizeof(event->details)); + } + } + } + + /* If you return 0, then the system assumes you performed the action (e.g. ShowWindow(hWnd, SW_MAXIMIZE). + To reduce code size, just use OS default behaviors. */ + return DefWindowProc(hWnd, msg, wParam, lParam); + } + + /********/ + + case WM_SETFOCUS: + { + GETWINPTR(); + if(win) + { + SST_WMEvent* event; + + event = AllocSlotInEQ(&win->eventQueue); + if(event) + { + event->window = win; + event->type = SSTWMEVENT_GAINFOCUS; + memset(&event->details, 0, sizeof(event->details)); + } + } + break; + } + + /********/ + + case WM_KILLFOCUS: + { + GETWINPTR(); + if(win) + { + SST_WMEvent* event; + + event = AllocSlotInEQ(&win->eventQueue); + if(event) + { + event->window = win; + event->type = SSTWMEVENT_LOSEFOCUS; + memset(&event->details, 0, sizeof(event->details)); + } + } + + break; + } + + /********/ + + case WM_SIZE: + { + SST_WMEvent* event; + switch(wParam) /* wParam has the type of resize */ + { + case SIZE_MAXIMIZED: + case SIZE_RESTORED: /* "Restored" here means (!maximized && !minimized). This is confusing since we have SC_RESTORED too. */ + { + uint32_t x = (uint32_t)LOWORD(lParam); + uint32_t y = (uint32_t)HIWORD(lParam); + + GETWINPTR(); + if(win && x > 0 && y > 0) + { + event = AllocSlotInEQ(&win->eventQueue); + if(event) + { + event->window = win; + event->type = SSTWMEVENT_RESIZED; + event->details.winEvent.x = (uint32_t)LOWORD(lParam); + event->details.winEvent.y = (uint32_t)HIWORD(lParam); + + if(win->softwareImage) + { + /* Recreate window resources */ + SST_WM_DisableSoftwareRendering(win); + SST_WM_EnableSoftwareRendering(win); + } + } + } + break; + } + + /* Minimize event */ + case SIZE_MINIMIZED: + { + GETWINPTR(); + if(win) + { + SST_WMEvent* event; + + event = AllocSlotInEQ(&win->eventQueue); + if(event) + { + event->window = win; + event->type = SSTWMEVENT_MINIMIZED; + memset(&event->details, 0, sizeof(event->details)); + } + } + break; + } + + /* Don't attempt to handle other messages */ + default: return DefWindowProc(hWnd, msg, wParam, lParam); + } + + break; + } + + /********/ + + case WM_MOVE: + { + /* + Note: On Windows 7 (maybe earlier) if the "System->Advanced->Performance Options->Show window contents while dragging" + is set, you get a ton of WM_MOVE messages. I guess this is so that you can redraw the window as it moves. It floods + the message queue pretty badly. There is no fix that I can tell of since it is intended behavior. + */ + GETWINPTR(); + if(win) + { + SST_WMEvent* event; + + event = AllocSlotInEQ(&win->eventQueue); + if(event) + { + HMONITOR hMonitor; + POINT pt; + MONITORINFO info; + + pt.x = (LONG)((SHORT)LOWORD(lParam)); /* u16->s16->s32 */ + pt.y = (LONG)((SHORT)HIWORD(lParam)); /* u16->s16->s32 */ + + info.cbSize = sizeof(info); + + /* Convert the coordinates to a position relative to the monitor they are on */ + hMonitor = MonitorFromPoint(pt, MONITOR_DEFAULTTONEAREST); + if(hMonitor != NULL) + { + if(GetMonitorInfo(hMonitor, &info)) + { + pt.x -= info.rcMonitor.left; + pt.y -= info.rcMonitor.top; + } + } + + if(pt.x < 0) + pt.x = 0; + if(pt.y < 0) + pt.y = 0; + + + + event->window = win; + event->type = SSTWMEVENT_MOVED; + event->details.winEvent.x = (uint32_t)pt.x; + event->details.winEvent.y = (uint32_t)pt.y; + } + } + break; + } + + /********/ + + case WM_MOUSEWHEEL: + case WM_MOUSEHWHEEL: + { + GETWINPTR(); + if(win) + { + SST_WMEvent* event; + + event = AllocSlotInEQ(&win->eventQueue); + if(event) + { + /* Compute scroll delta in terms of fractions of a whole line of text */ + float delta = ((float)GET_WHEEL_DELTA_WPARAM(wParam)) / (float)WHEEL_DELTA; + + event->type = SSTWMEVENT_MOUSEWHEEL; + event->window = win; + if(msg == WM_MOUSEWHEEL) + { + event->details.scrollEvent.vscroll = delta; + event->details.scrollEvent.hscroll = 0; + } + else /* i.e. HWHEEL*/ + { + event->details.scrollEvent.vscroll = 0; + event->details.scrollEvent.hscroll = delta; + } + } + } + + break; + } + + /********/ + + /* Left, middle, right mouse buttons */ + case WM_LBUTTONDOWN: + case WM_MBUTTONDOWN: + case WM_RBUTTONDOWN: + updown = 1; /* Intentional fall through */ + case WM_LBUTTONUP: + case WM_MBUTTONUP: + case WM_RBUTTONUP: + { + /* 'updown' is either 1 (button down) or 0 (button up) at this point */ + + GETWINPTR(); + if(win) + { + SST_WMEvent* event; + + event = AllocSlotInEQ(&win->eventQueue); + if(event) + { + /* These coordinates are relative to the top of the window, so they are [0,w),[0,h) range */ + uint32_t x = (uint32_t)GET_X_LPARAM(lParam); + uint32_t y = (uint32_t)GET_Y_LPARAM(lParam); + uint32_t button; + + if(msg == WM_LBUTTONDOWN || msg == WM_LBUTTONUP) + button = SST_MBLEFT; + else if(msg == WM_MBUTTONDOWN || msg == WM_MBUTTONUP) + button = SST_MBMIDDLE; + else + button = SST_MBRIGHT; + + + + event->window = win; + event->type = (updown ? SSTWMEVENT_MOUSEDOWN : SSTWMEVENT_MOUSEUP); + event->details.mouseEvent.x = x; + event->details.mouseEvent.y = y; + event->details.mouseEvent.button = button; + } + } + + break; + } + + /********/ + + /* Extra mouse buttons (#4 & #5)*/ + case WM_XBUTTONDOWN: + updown = 1; /* Intentional fall through */ + case WM_XBUTTONUP: + { + /* 'updown' is either 1 (button down) or 0 (button up) at this point */ + + GETWINPTR(); + if(win) + { + SST_WMEvent* event; + + event = AllocSlotInEQ(&win->eventQueue); + if(event) + { + /* These coordinates are relative to the top of the window, so they are [0,w),[0,h) range */ + uint32_t x = (uint32_t)GET_X_LPARAM(lParam); + uint32_t y = (uint32_t)GET_Y_LPARAM(lParam); + uint32_t button; + + if(HIWORD(wParam) == XBUTTON1) + button = SST_MB4; + else + button = SST_MB5; + + event->window = win; + event->type = (updown ? SSTWMEVENT_MOUSEDOWN : SSTWMEVENT_MOUSEUP); + event->details.mouseEvent.x = x; + event->details.mouseEvent.y = y; + event->details.mouseEvent.button = button; + } + } + /* MSDN: "An application should return TRUE from this message if it processes it. Doing so allows software + that simulates this message on Windows systems earlier than Windows 2000 to determine whether the window + procedure processed the message or called DefWindowProc to process it." + + Since we handle it, we return TRUE here. */ + return TRUE; + } + + /********/ + + case WM_INPUT: + { + GETWINPTR(); + if(win) + { + HRAWINPUT hRawInput = (HRAWINPUT)lParam; + RAWINPUT inp; + UINT size = sizeof(inp); + + /* Ignore WM_INPUT if not in relative mouse movement mode */ + if(!win->owner->relativeMouse) + break; + + GetRawInputData(hRawInput, RID_INPUT, &inp, &size, sizeof(RAWINPUTHEADER)); + + /* Mouse data */ + if(inp.header.dwType == RIM_TYPEMOUSE) + { + RAWMOUSE* mouse = &inp.data.mouse; + if((mouse->usFlags & 0x01) == MOUSE_MOVE_RELATIVE && (mouse->lLastX != 0 || mouse->lLastY != 0)) + { + SST_WMEvent* event = AllocSlotInEQ(&win->eventQueue); + if(event) + { + event->type = SSTWMEVENT_MOUSERELMOVED; + event->window = win; + event->details.relMouseEvent.relx = (int32_t)mouse->lLastX; + event->details.relMouseEvent.rely = (int32_t)mouse->lLastY; + + } + } + } + } + break; + } + + /********/ + + case WM_MOUSEMOVE: + { + /* These coordinates are relative to the top of the window, so they are [0,w),[0,h) range */ + uint32_t x = (uint32_t)GET_X_LPARAM(lParam); + uint32_t y = (uint32_t)GET_Y_LPARAM(lParam); + + GETWINPTR(); + if(win) + { + SST_WMEvent* event; + + /* Ignore WM_MOUSEMOVE in relative mouse movement mode */ + if(win->owner->relativeMouse) + break; + + + event = AllocSlotInEQ(&win->eventQueue); + if(event) + { + event->window = win; + event->type = SSTWMEVENT_MOUSEMOVED; + event->details.mouseEvent.x = x; + event->details.mouseEvent.y = y; + event->details.mouseEvent.button = 0; + } + } + break; + } + + case WM_SYSKEYDOWN: + case WM_KEYDOWN: + updown = 1; /* Intentional fall through */ + case WM_SYSKEYUP: + case WM_KEYUP: + { + BYTE kbstate[256]; + WCHAR buf[32]; + SST_WMKey key; + uint32_t modState = 0; + uint32_t utf32 = 0; + + + + /* Windows doesn't send right/left VKs. However, using the scancode (in lParam), you can + squeeze a right/left version out of it, e.g. VK_SHIFT -> { VK_LSHIFT || VK_RSHIFT }. + + The scan code is in bits 16-23 (i.e. 3rd byte if talking little-endian) */ + if(wParam == VK_CONTROL || wParam == VK_SHIFT || wParam == VK_MENU) + wParam = (WPARAM)MapVirtualKeyA((UINT)((lParam >> 16) & 0xFF), MAPVK_VSC_TO_VK_EX); + + /* Translate the key, stopping if we don't successfully do so */ + key = Win32KeyToSSTKey(wParam, lParam); + if(key == SSTWMKEY_NONE) + break; + + /* TODO: Strictly, this isn't UTF-32, but UTF-16, so you can get multiple characters here. + Ack. CJK languages are going to suffer strangeness. Need UTF-16 to UTF-32 (precombined). */ + GetKeyboardState(kbstate); + if(ToUnicode((UINT)wParam, (UINT)(((lParam >> 16) & 0xFF) | (LPARAM)(updown<<31)), kbstate,buf, sizeof(buf) / sizeof(WCHAR), 0) > 0) + utf32 = buf[0]; + + /* MSDN: "Bit 30: The value is 1 if the key is down before the message is sent, or it is zero if the key is up." + + Use this to check for repeated WM messages. Obviously, this only applies to key "down" messages. + */ + if(lParam & (1<<30) && (msg == WM_SYSKEYDOWN || msg == WM_KEYDOWN)) + modState |= SSTKEYMOD_REPEAT; + + /* MSDN: "If the high-order bit is 1, the key is down; otherwise, it is up." */ + if(kbstate[VK_SHIFT] & 0x80) + modState |= SSTKEYMOD_SHIFT; + if(kbstate[VK_CONTROL] & 0x80) + modState |= SSTKEYMOD_CONTROL; + if(kbstate[VK_MENU] & 0x80) + modState |= SSTKEYMOD_ALT; + + GETWINPTR(); + if(win) + { + SST_WMEvent* event; + + event = AllocSlotInEQ(&win->eventQueue); + if(event) + { + event->window = win; + event->type = (updown ? SSTWMEVENT_KEYDOWN : SSTWMEVENT_KEYUP); + event->details.keyEvent.key = key; + event->details.keyEvent.utf32 = utf32; + event->details.keyEvent.modifierState = modState; + + } + } + } + + default: + return DefWindowProc(hWnd, msg, wParam, lParam); + } + + return 0; +} + +/*************************************************************************/ + +void resolveWGLSymbols(HMODULE opengl32, WGLFunctions* wgl) +{ + /* These can be resolved without an active context */ + wgl->CreateContext = (pf_wglCreateContext)GetProcAddress(opengl32, "wglCreateContext"); + wgl->MakeCurrent = (pf_wglMakeCurrent)GetProcAddress(opengl32, "wglMakeCurrent"); + wgl->GetProcAddress = (pf_wglGetProcAddress)GetProcAddress(opengl32, "wglGetProcAddress"); /* <- This line of code is ironic */ + wgl->DeleteContext = (pf_wglDeleteContext)GetProcAddress(opengl32, "wglDeleteContext"); + wgl->ShareLists = (pf_wglShareLists)GetProcAddress(opengl32, "wglShareLists"); + wgl->GetCurrentContext = (pf_wglGetCurrentContext)GetProcAddress(opengl32, "wglGetCurrentContext"); + wgl->GetCurrentDC = (pf_wglGetCurrentDC)GetProcAddress(opengl32, "wglGetCurrentDC"); +} + +/*************************************************************************/ + +void resolveWGLExtSymbols(HDC hDC, WGLFunctions* wgl) +{ + const char* ext; + + /* Use wglGetProcAddress(), not GetProcAddress() for this one */ + wgl->GetExtensionsStringARB = (pf_wglGetExtensionsStringARB)wgl->GetProcAddress("wglGetExtensionsStringARB"); + + /* REALLY old WGL implementation, so stop. */ + if(wgl->GetExtensionsStringARB == NULL) + return; + + /* Get extension string */ + ext = wgl->GetExtensionsStringARB(hDC); + + /* WGL_ARB_pixel_format: choosing advanced pixel formats (e.g. MSAA) */ + if(extSupported(ext, "WGL_ARB_pixel_format")) + { + wgl->ChoosePixelFormatARB = (pf_wglChoosePixelFormatARB)wgl->GetProcAddress("wglChoosePixelFormatARB"); + wgl->GetPixelFormatAttribivARB = (pf_wglGetPixelFormatAttribivARB)wgl->GetProcAddress("wglGetPixelFormatAttribivARB"); + } + + /* WGL_ARB_create_context: creating versioned contexts */ + if(extSupported(ext, "WGL_ARB_create_context")) + wgl->CreateContextAttribsARB = (pf_wglCreateContextAttribsARB)wgl->GetProcAddress("wglCreateContextAttribsARB"); + + /* WGL_ARB_create_context_profile: creating core / compatability / debug contexts */ + if(extSupported(ext, "WGL_ARB_create_context_profile")) + wgl->supportsProfiles = TRUE; + + /* WGL_ARB_multisample: tokens for multisample contexts using WGL_ARB_pixel_format */ + if(extSupported(ext, "WGL_ARB_multisample")) + wgl->supportsMultisample = TRUE; +} +/*************************************************************************/ + +void findMonitor(const DISPLAY_DEVICEA* dev, FindMonitorInfo* fmi) +{ + fmi->dev = dev; + fmi->foundIt = FALSE; + + EnumDisplayMonitors(NULL, NULL, findMonitorCallback, (LPARAM)fmi); +} + +/*************************************************************************/ + +static int extSupported(const char* extlist, const char* s) +{ + const char* end; + const char* start = extlist; + size_t len = strlen(s); + do + { + /* Look for substring */ + end = strstr(start, s); + if(end != NULL) + { + const char* term; + + /* Check if end of string is null character or space */ + term = end + len; + if(*term == '\0' || *term == ' ') + return 1; + + /* Guess not... resume at end of string */ + while(*term != '\0' && *term != ' ') + term++; + + start = term; + } + + } while(end); + + return 0; +} + +/*************************************************************************/ + +static SST_WMKey Win32KeyToSSTKey(WPARAM vkey, LPARAM lParam) +{ + //Virtual key values are all less than 0x100, but now the compiler knows that. + unsigned char value = (unsigned char)(vkey & 0xFF); + + if(value >= '0' && value <= '9') + return (SST_WMKey)(SSTWMKEY_0 + (value - '0')); + + if(value >= 'A' && value <= 'Z') + return (SST_WMKey)(SSTWMKEY_A + (value - 'A')); + + /* MSDN: "Bit 24: The value is 1 if it is an extended key; otherwise, it is 0." + We use this to differentiate some keys */ + #define ISEXTENDED() (lParam & (1<<24)) + + /* + Any good compiler should be able to generate a table from this switch() + since 'value' is defined to be a 0-255 value that maps to only enum elements + with values <= 255. Asm output confirms MSVC/GCC do, no doubt ICC does as well. + */ + switch(value) + { + + case VK_BACK: return SSTWMKEY_BACKSPACE; + case VK_TAB: return SSTWMKEY_TAB; + case VK_RETURN: + if(ISEXTENDED()) + return SSTWMKEY_KEYPAD_ENTER; + else + return SSTWMKEY_RETURN; + case VK_ESCAPE: return SSTWMKEY_ESCAPE; + case VK_SPACE: return SSTWMKEY_SPACE; + case VK_CAPITAL: return SSTWMKEY_CAPSLOCK; + + case VK_OEM_COMMA : return SSTWMKEY_COMMA; + case VK_OEM_PERIOD: return SSTWMKEY_PERIOD; + case VK_OEM_2: return SSTWMKEY_FORWARDSLASH; /* '/?' key */ + case VK_OEM_1: return SSTWMKEY_SEMICOLON; /* ';:' key */ + case VK_OEM_7: return SSTWMKEY_QUOTES; /* single-quote/double quotes key */ + case VK_OEM_4: return SSTWMKEY_OPENBRACKET; /* '{{' key */ + case VK_OEM_6: return SSTWMKEY_CLOSEBRACKET; /* ']}' key */ + case VK_OEM_5: return SSTWMKEY_BACKSLASH; /* '\|' key */ + case VK_OEM_MINUS : return SSTWMKEY_UNDERBAR; + case VK_OEM_PLUS: return SSTWMKEY_EQUALS; + + //Keypad + case VK_NUMLOCK: return SSTWMKEY_NUMLOCK; + case VK_NUMPAD0: return SSTWMKEY_KEYPAD_0; + case VK_NUMPAD1: return SSTWMKEY_KEYPAD_1; + case VK_NUMPAD2: return SSTWMKEY_KEYPAD_2; + case VK_NUMPAD3: return SSTWMKEY_KEYPAD_3; + case VK_NUMPAD4: return SSTWMKEY_KEYPAD_4; + case VK_NUMPAD5: return SSTWMKEY_KEYPAD_5; + case VK_NUMPAD6: return SSTWMKEY_KEYPAD_6; + case VK_NUMPAD7: return SSTWMKEY_KEYPAD_7; + case VK_NUMPAD8: return SSTWMKEY_KEYPAD_8; + case VK_NUMPAD9: return SSTWMKEY_KEYPAD_9; + case VK_DECIMAL: return SSTWMKEY_KEYPAD_PERIOD; + case VK_DIVIDE: return SSTWMKEY_KEYPAD_DIVIDE; + case VK_MULTIPLY: return SSTWMKEY_KEYPAD_MULTIPLY; + case VK_SUBTRACT: return SSTWMKEY_KEYPAD_MINUS; + case VK_ADD: return SSTWMKEY_KEYPAD_PLUS; + + /* Arrow keys */ + case VK_UP: return SSTWMKEY_ARROW_UP; + case VK_DOWN: return SSTWMKEY_ARROW_DOWN; + case VK_LEFT: return SSTWMKEY_ARROW_LEFT; + case VK_RIGHT: return SSTWMKEY_ARROW_RIGHT; + + /* The page up/down block */ + case VK_INSERT: return SSTWMKEY_INSERT; + case VK_HOME: return SSTWMKEY_HOME; + case VK_END: return SSTWMKEY_END; + case VK_PRIOR: return SSTWMKEY_PAGEUP; + case VK_NEXT: return SSTWMKEY_PAGEDOWN; + case VK_DELETE: return SSTWMKEY_DELETE; + + /* Function Keys */ + case VK_F1: return SSTWMKEY_F1; + case VK_F2: return SSTWMKEY_F2; + case VK_F3: return SSTWMKEY_F3; + case VK_F4: return SSTWMKEY_F4; + case VK_F5: return SSTWMKEY_F5; + case VK_F6: return SSTWMKEY_F6; + case VK_F7: return SSTWMKEY_F7; + case VK_F8: return SSTWMKEY_F8; + case VK_F9: return SSTWMKEY_F9; + case VK_F10: return SSTWMKEY_F10; + case VK_F11: return SSTWMKEY_F11; + case VK_F12: return SSTWMKEY_F12; + case VK_F13: return SSTWMKEY_F13; + case VK_F14: return SSTWMKEY_F14; + case VK_F15: return SSTWMKEY_F15; + + case VK_LSHIFT: return SSTWMKEY_LEFTSHIFT; + case VK_RSHIFT: return SSTWMKEY_RIGHTSHIFT; + case VK_RCONTROL: return SSTWMKEY_RIGHTCONTROL; + case VK_LCONTROL: return SSTWMKEY_LEFTCONTROL; + case VK_LMENU: return SSTWMKEY_LEFTALT; + case VK_RMENU: return SSTWMKEY_RIGHTALT; + case VK_LWIN: return SSTWMKEY_LEFTSUPER; + case VK_RWIN: return SSTWMKEY_RIGHTSUPER; + + /* Misc */ + case VK_SNAPSHOT: return SSTWMKEY_PRINTSCREEN; + case VK_SCROLL: return SSTWMKEY_SCROLLLOCK; + case VK_PAUSE: return SSTWMKEY_PAUSE; + case VK_OEM_3: return SSTWMKEY_TILDE; /* `~ key */ + + default: break; + } + + return SSTWMKEY_NONE; +} + +/*************************************************************************/ + +static BOOL CALLBACK findMonitorCallback(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) +{ + FindMonitorInfo* fmi = (FindMonitorInfo*)dwData; + MONITORINFOEXA info; + + /* Unused */ + (void)hdcMonitor; + + info.cbSize = sizeof(info); + + /* Get info about this monitor */ + if(GetMonitorInfoA(hMonitor, (MONITORINFO*)&info)) + { + /* Check to see if device names match */ + if(strcmp(info.szDevice, fmi->dev->DeviceName) == 0) + { + /* Stop enumeration -- we found it! */ + fmi->top = lprcMonitor->top; + fmi->left = lprcMonitor->left; + fmi->bottom = lprcMonitor->bottom; + fmi->right = lprcMonitor->right; + fmi->foundIt = TRUE; + return FALSE; + } + } + + /* Continue enumeration */ + return TRUE; +} diff --git a/libsst-wm/Win32/Win32Private.h b/libsst-wm/Win32/Win32Private.h new file mode 100644 index 0000000..2376955 --- /dev/null +++ b/libsst-wm/Win32/Win32Private.h @@ -0,0 +1,267 @@ +/* + Win32Private.h + Author: Patrick Baggett <ptbaggett@762studios.com> + Created: 1/7/2012 + + Purpose: + + Private defintions and functions for Win32 implementation of libsst-wm + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ + +#pragma once + +#ifndef _WIN32PRIVATE_H +#define _WIN32PRIVATE_H + +#include <windows.h> +#include <windowsx.h> /* More Win32 macros */ +#include <GL/gl.h> +#include <SST/SST_WMTypes.h> +#include "../EventQueue.h" + +#define ADAPTER_NAME_STRLEN 128 +#define STRLEN_GUID ((size_t)64) /* Storage enough to hold a Win32 GUID if it was written as a string of hex characters with dashes (need only like 36-38) */ +#define MIN_BPP 24 /* Minimum BPP for a mode to be considered */ +#define SST_WINCLASS "libsstwm" +#define SST_DLGCLASS "libsstwmdlg" +#define MAX_GL_ATTRS 32 + +/*************************************************************************/ + +typedef HGLRC (WINAPI * pf_wglCreateContext)(HDC hdc); +typedef BOOL (WINAPI * pf_wglMakeCurrent)(HDC hdc, HGLRC hglrc); +typedef PROC (WINAPI * pf_wglGetProcAddress)(LPCSTR lpszProc); +typedef BOOL (WINAPI * pf_wglDeleteContext)(HGLRC hglrc); +typedef BOOL (WINAPI * pf_wglShareLists)(HGLRC hglrc1, HGLRC hglrc2); +typedef HGLRC (WINAPI * pf_wglGetCurrentContext)(void); +typedef HDC (WINAPI * pf_wglGetCurrentDC)(void); +typedef const char* (WINAPI * pf_wglGetExtensionsStringARB)(HDC hdc); +typedef BOOL (WINAPI * pf_wglChoosePixelFormatARB)(HDC hdc, const int* piAttribIList, const FLOAT* pfAttribFList, UINT nMaxFormats, int* piFormats, UINT* nNumFormats); +typedef HGLRC (WINAPI * pf_wglCreateContextAttribsARB)(HDC hDC, HGLRC hshareContext, const int *attribList); +typedef BOOL (WINAPI * pf_wglGetPixelFormatAttribivARB)(HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, const int *piAttributes, int *piValues); + +/*************************************************************************/ + +/* + Note about memory management -- these functions all use the Win32 API (HeapAlloc()/HeapFree()) instead of the CRT functions (malloc()/free()). + This is so that it has less of dependency on the CRT. +*/ + +/*************************************************************************/ + +/* Structure to maps an adapter-display pair to a DISPLAY_DEVICE */ +typedef struct ASMapEntry +{ + SST_VideoMode defaultVmode; + const DISPLAY_DEVICEA* dev; + SST_VideoMode* vmodes; + size_t adapter; + size_t screen; + size_t vmodeCount; +} ASMapEntry; + +/*************************************************************************/ + +typedef struct FindMonitorInfo +{ + const DISPLAY_DEVICEA* dev; /* Name of the device we are trying to find a matching HMONITOR for */ + BOOL foundIt; /* Did we find it? */ + LONG top, left; /* Monitor corner (top,left) */ + LONG bottom, right; +} FindMonitorInfo; + + +/*************************************************************************/ + +typedef struct SST_GraphicsEnumerator_Win32 +{ + char* adapterNames; + DISPLAY_DEVICEA* devsFound; + size_t* screenCount; + ASMapEntry* ASMap; + + + size_t adapterCount; + size_t devCount; + size_t ASPairCount; +} SST_GraphicsEnumerator_Win32; + +/*************************************************************************/ + +typedef struct SST_DisplayTarget_Win32 +{ + CRITICAL_SECTION userEventLock; /* Lock protection user events */ + EventQueue userEventQueue; + DISPLAY_DEVICEA* devs; /* Array of devices representing this display target */ + struct SST_Window_Win32* firstWindow; /* First window in a list of windows */ + size_t screenCount; + size_t screenIndex; + BOOL relativeMouse; +} SST_DisplayTarget_Win32; + +/*************************************************************************/ + +typedef struct SST_Window_Win32 +{ + WINDOWPLACEMENT wp; + EventQueue eventQueue; + struct SST_Window_Win32* next; + SST_DisplayTarget_Win32* owner; + HWND hWnd; + BOOL isFullscreen; + BOOL setPixelFormat; /* If TRUE, then SetPixelFormat() was called on this window */ + + + /* Software rendering support */ + HBITMAP softwareImage; + HDC softwareDC; + void* softwareBackbuffer; + size_t softwarePitch; + +} SST_Window_Win32; + +/*************************************************************************/ + +typedef struct WGLFunctions +{ + pf_wglCreateContext CreateContext; + pf_wglMakeCurrent MakeCurrent; + pf_wglGetProcAddress GetProcAddress; + pf_wglDeleteContext DeleteContext; + pf_wglShareLists ShareLists; + pf_wglGetCurrentContext GetCurrentContext; + pf_wglGetCurrentDC GetCurrentDC; + + /* WGL Extensions */ + pf_wglGetExtensionsStringARB GetExtensionsStringARB; + pf_wglChoosePixelFormatARB ChoosePixelFormatARB; + pf_wglCreateContextAttribsARB CreateContextAttribsARB; + pf_wglGetPixelFormatAttribivARB GetPixelFormatAttribivARB; + + BOOL supportsProfiles; + BOOL supportsMultisample; +} WGLFunctions; + +/*************************************************************************/ + +typedef struct SST_OpenGLContext_Win32 +{ + WGLFunctions wgl; + SST_DisplayTarget_Win32* displayTarget; + HMODULE opengl32; + HGLRC context; + HDC hDCActive; + HWND hSlaveWnd; /* Slave contexts use a dummy window. Regular (master) GL contexts have this as NULL */ + int pixelFormat; + short ctxVersion[2]; /* context version major/minor */ + BOOL isLegacy; /* Did we use legacy context creation functions? */ + BOOL legacyEnabled; /* Did we use legacy OpenGL (< 3.0) context support? */ + BOOL debugEnabled; /* Did we use debug OpenGL context support? */ +} SST_OpenGLContext_Win32; + +/*************************************************************************/ + +DISPLAY_DEVICEA* get_win32devs(size_t* devCountReturn); + +char* get_adapters(const DISPLAY_DEVICEA* devsFound, size_t devCount, size_t* adapterCountReturn, char** adapterGUIDReturn); + +/* + Filter a list of Win32 devices in-place; modify list so that only relevant Win32 devices are returned. + For example, if there are 3 devices: { Gpu0Screen0, Gpu1Screen0, Gpu1Screen1}, and adapterIndex == 1, + then this returns { Gpu1Screen0, Gpu1Screen1 } in place. The number of devices in the filtered list are + returned (in the example, 2). +*/ +size_t filter_win32devs(DISPLAY_DEVICEA* devsFound, size_t devCount, size_t adapterIndex); + +ASMapEntry* build_asmap(const DISPLAY_DEVICEA* devsFound, const char* adapterGUIDs, size_t devCount, size_t adapterCount, size_t* screenCount, size_t* mapSizeReturn); + +SST_VideoMode* get_vmodes(const DISPLAY_DEVICEA* dev, size_t* modeCountReturn, SST_VideoMode* defaultMode); + +LRESULT WINAPI libsstWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); + +void resolveWGLSymbols(HMODULE opengl32, WGLFunctions* wgl); +void resolveWGLExtSymbols(HDC hDC, WGLFunctions* wgl); + +void findMonitor(const DISPLAY_DEVICEA* dev, FindMonitorInfo* fmi); + +/* WGL_ARB_multisample */ +#define WGL_SAMPLE_BUFFERS_ARB 0x2041 +#define WGL_SAMPLES_ARB 0x2042 + +/* WGL_ARB_pixel_format */ +#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 + +/* WGL_ARB_create_context */ +#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 WGL_CONTEXT_PROFILE_MASK_ARB 0x9126 +#define WGL_CONTEXT_DEBUG_BIT_ARB 0x0001 +#define WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x0002 +#define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001 +#define WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002 +#define ERROR_INVALID_VERSION_ARB 0x2095 +#define ERROR_INVALID_PROFILE_ARB 0x2096 + +#endif diff --git a/libsst-wm/Xlib/GLXPrivate.c b/libsst-wm/Xlib/GLXPrivate.c new file mode 100644 index 0000000..356006a --- /dev/null +++ b/libsst-wm/Xlib/GLXPrivate.c @@ -0,0 +1,374 @@ +/* + GLXPrivate.c + Author: Patrick Baggett <ptbaggett@762studios.com> + Created: 1/11/2013 + + Purpose: + + OpenGL on X Windows (GLX) utility code + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ + +#include <SST/SST_WMOpenGL.h> +#include "XlibPrivate.h" +#include <dlfcn.h> +#include <string.h> +#include <stdio.h> + +/* GL constants */ +#define GL_VERSION 0x1F02 + +/* GLX constants */ +#define GLX_DOUBLEBUFFER 5 +#define GLX_STEREO 6 +#define GLX_AUX_BUFFERS 7 +#define GLX_RED_SIZE 8 +#define GLX_GREEN_SIZE 9 +#define GLX_BLUE_SIZE 10 +#define GLX_ALPHA_SIZE 11 +#define GLX_DEPTH_SIZE 12 +#define GLX_STENCIL_SIZE 13 +#define GLX_DRAWABLE_TYPE 0x8010 +#define GLX_RGBA_TYPE 0x8014 +#define GLX_WINDOW_BIT 0x00000001 +#define GLX_PIXMAP_BIT 0x00000002 +#define GLX_PBUFFER_BIT 0x00000004 + +/* GLX_ARB_multisample */ +#define GLX_SAMPLE_BUFFERS_ARB 100000 +#define GLX_SAMPLES_ARB 100001 + +#define GLX_PBUFFER_HEIGHT 0x8040 +#define GLX_PBUFFER_WIDTH 0x8041 + +/* GLX_ARB_create_context[_profile] */ +#define GLX_CONTEXT_MAJOR_VERSION_ARB 0x2091 +#define GLX_CONTEXT_MINOR_VERSION_ARB 0x2092 +#define GLX_CONTEXT_FLAGS_ARB 0x2094 +#define GLX_CONTEXT_PROFILE_MASK_ARB 0x9126 +#define GLX_CONTEXT_DEBUG_BIT_ARB 0x0001 +#define GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x0002 +#define GLX_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001 +#define GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002 + +GLXFunctions glX = { 0 }; + +static void setupAttribs(int* glxAttr, const SST_OpenGLContextAttributes* attribs, Bool supportsMultisample); +static int* addAttr(int* ptr, int attr, int value) +{ + ptr[0] = attr; + ptr[1] = value; + return ptr + 2; +} + +/******************************************************************************/ + +int loadGLX() +{ + const int flags = RTLD_LAZY | RTLD_GLOBAL; + void* libGL; + + /* Set all values to null/0/false */ + memset(&glX, 0, sizeof(GLXFunctions)); + + /* Load OpenGL library with proper DT_SONAME */ + libGL = dlopen("libGL.so.1", flags); + if(libGL == NULL) + { + /* Failed...try generic name for it */ + libGL = dlopen("libGL.so", flags); + if(libGL == NULL) + return 0; + } + + /* Resolve symbols */ + glX.QueryExtension = dlsym(libGL, "glXQueryExtension"); + glX.QueryVersion = dlsym(libGL, "glXQueryVersion"); + glX.QueryExtensionsString = dlsym(libGL, "glXQueryExtensionsString"); + glX.ChooseFBConfig = dlsym(libGL, "glXChooseFBConfig"); + glX.CreateNewContext = dlsym(libGL, "glXCreateNewContext"); + glX.DestroyContext = dlsym(libGL, "glXDestroyContext"); + glX.MakeContextCurrent = dlsym(libGL, "glXMakeContextCurrent"); + glX.GetCurrentContext = dlsym(libGL, "glXGetCurrentContext"); + glX.SwapBuffers = dlsym(libGL, "glXSwapBuffers"); + glX.CreatePbuffer = dlsym(libGL, "glXCreatePbuffer"); + glX.DestroyPbuffer = dlsym(libGL, "glXDestroyPbuffer"); + + /* On Linux, glXGetProcAddressARB() is statically exported from libGL.so as part of LSB. However, + on non-LSB compliant or other UNIX systems, the -ARB version may not exist. Try the unsuffixed + form if the -ARB variant does not exist. */ + glX.GetProcAddressARB = dlsym(libGL, "glXGetProcAddressARB"); + if(glX.GetProcAddressARB == NULL) + glX.GetProcAddressARB = dlsym(libGL, "glXGetProcAddress"); + + /* We dont resolve glXCreateContextAttribsARB yet; first check GLX extension strings. */ + glX.CreateContextAttribsARB = NULL; + + /* Save library handle */ + glX.libGL = libGL; + return 1; +} + +/******************************************************************************/ + +void unloadGLX() +{ + dlclose(glX.libGL); +} + +/******************************************************************************/ + +int isGLXLoaded() +{ + return (glX.libGL != NULL); +} + +/******************************************************************************/ + +int isGLXSupported(Display* display) +{ + int major = 0, minor = 0; + int combined; + const char* ext; + + /* Query if the X server supports GLX. If it doesn't, then nothing to do */ + if(glX.QueryExtension(display, NULL, NULL) == False) + { + fprintf(stderr, "%s:GLX extension not supported on this connection.\n", "libsst-wm"); + return 0; + } + + /* Query the version; we need 1.3 or later */ + if(glX.QueryVersion(display, &major, &minor) == False) + { + fprintf(stderr, "%s:Unable to query GLX version.\n", "libsst-wm"); + return 0; + } + + /* Fail on less than 1.3 */ + combined = (major << 8) | minor; + if(combined < 0x13) + { + fprintf(stderr, "%s:GLX version 1.3 required, found %d.%d\n", "libsst-wm", major, minor); + return 0; + } + + ext = glX.QueryExtensionsString(display, DefaultScreen(display)); + + /* "GLX_ARB_create_context" and "GLX_ARB_create_context_profile" might both match the first strstr(), + but "GLX_ARB_create_context_profile" requires the former, so it's all good. + TODO: write less stupid extension checker - one day may not be true */ + if(combined >= 0x14) /* GLX 1.4 required for GLX_ARB_create_context */ + { + glX.supportsCreateContextARB = (Bool)(strstr(ext, "GLX_ARB_create_context") != NULL); + glX.supportsProfiles = (Bool)(strstr(ext, "GLX_ARB_create_context_profile") != NULL); + + /* Supposedly GLX_ARB_create_context is supported. Try to resolve the symbol. If we can't, + then backout. */ + if(glX.supportsCreateContextARB) { + glX.CreateContextAttribsARB = glX.GetProcAddressARB("glXCreateContextAttribsARB"); + if(glX.CreateContextAttribsARB == NULL) { + glX.supportsCreateContextARB = False; + } + } + } + else /* Don't have GLX 1.4, so can't possibly have these */ + { + glX.supportsCreateContextARB = False; + glX.supportsProfiles = False; + } + + glX.supportsMultisample = (Bool)(strstr(ext, "GLX_ARB_multisample") != NULL); + + return 1; +} + +/******************************************************************************/ + +SST_OpenGLContext GLXCreateOpenGLContext(SST_DisplayTarget_Xlib* displayTarget, SST_WMOpenGLType apiType, const SST_OpenGLContextAttributes* attribs, SST_OpenGLContextAttributes* selectedAttribsReturn) +{ + int attr[MAX_GL_ATTRS]; + Display* display = displayTarget->display; + GLXFBConfig* configs; + GLXFBConfig fbconfig; + GLXContext ctx; + int nrConfigs = 0; + SST_OpenGLContext_Xlib* GLctx; + uint8_t major, minor; + GLXPbuffer pb; + const int pbattr[5] = { GLX_PBUFFER_WIDTH, 1, GLX_PBUFFER_HEIGHT, 1, None }; + + /* GLX cannot be used to do anything other than standard OpenGL */ + if(apiType != SSTGL_OPENGL) + return NULL; + + /* GLX doesn't support multisampling, but it was explicitly requested */ + if(!glX.supportsMultisample && attribs->multisampleFactor > 1) + return NULL; + + /* Copy SST attributes to GLX attributes */ + setupAttribs(attr, attribs, glX.supportsMultisample); + + /* Get a list of configs -- we're going to only use the first one though */ + configs = glX.ChooseFBConfig(display, DefaultScreen(display), attr, &nrConfigs); + if(configs == NULL) + return NULL; + + /* Copy first FBConfig entry, free array */ + fbconfig = *configs; + X.Free(configs); + + /* Use the new create context functions? */ + if(glX.supportsCreateContextARB) + { + int attr[32]; + int* ptr = &attr[0]; + int ctxFlags = 0; + + /* Set the major/minor version */ + ptr = addAttr(ptr, GLX_CONTEXT_MAJOR_VERSION_ARB, attribs->contextVersionMajor); + ptr = addAttr(ptr, GLX_CONTEXT_MINOR_VERSION_ARB, attribs->contextVersionMinor); + + /* If GLX_ARB_create_context_profile is supported, add a profile mask */ + if(glX.supportsProfiles) + ptr = addAttr(ptr, GLX_CONTEXT_PROFILE_MASK_ARB, (attribs->legacyEnabled ? GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB : GLX_CONTEXT_CORE_PROFILE_BIT_ARB)); + + /* Enable/disable forward compatibility */ + if(!attribs->legacyEnabled) + ctxFlags |= GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB; + + /* Debug mode? */ + if(attribs->debugEnabled) + ctxFlags |= GLX_CONTEXT_DEBUG_BIT_ARB; + + ptr = addAttr(ptr, GLX_CONTEXT_FLAGS_ARB, ctxFlags); + *ptr = None; + + + ctx = glX.CreateContextAttribsARB(display, fbconfig, NULL, True, attr); + if(ctx == NULL) + return NULL; + + } + else /* Use older GLX 1.3 glXCreateNewContext() function */ + { + /* Attempt to create an OpenGL context */ + ctx = glX.CreateNewContext(display, fbconfig, GLX_RGBA_TYPE, NULL, True); + if(ctx == NULL) + return NULL; + } + + /* In order to check the version number, we're going to need to create + a temporary context. I'm using a Pbuffer to do so. */ + pb = glX.CreatePbuffer(display, fbconfig, pbattr); + if(pb == None) + { + glX.DestroyContext(display, ctx); + return NULL; + } + + /* Activate it */ + if(glX.MakeContextCurrent(display, pb, pb, ctx)) + { + const char* (*pglGetString)(unsigned int); + const char* version; + + /* Check libGL for this */ + pglGetString = dlsym(glX.libGL, "glGetString"); + + version = pglGetString(GL_VERSION); + + major = (uint8_t)(version[0] - '0'); /* "X.Y" -> [0]:major, [2]:minor */ + minor = (uint8_t)(version[2] - '0'); + + /* Save context version information */ + if(selectedAttribsReturn != NULL) + { + selectedAttribsReturn->contextVersionMajor = (uint8_t)major; + selectedAttribsReturn->contextVersionMinor = (uint8_t)minor; + } + + /* OK, we have the information we need. Unbind the context and destroy the Pbuffer */ + glX.MakeContextCurrent(display, None, None, NULL); + glX.DestroyPbuffer(display, pb); + + /* If the major version is too low or the major version is OK, but the minor version is lacking, then fail */ + if(major < attribs->contextVersionMajor || (major == attribs->contextVersionMajor && minor < attribs->contextVersionMinor)) + { + glX.DestroyContext(display, ctx); + return NULL; + } + } + else /* Failed to make current */ + { + glX.DestroyContext(display, ctx); + glX.DestroyPbuffer(display, pb); + return NULL; + } + + + + GLctx = (SST_OpenGLContext_Xlib*)malloc(sizeof(SST_OpenGLContext_Xlib)); + if(GLctx == NULL) + { + glX.DestroyContext(display, ctx); + return NULL; + } + + GLctx->glxcontext = ctx; + GLctx->displayTarget = displayTarget; + GLctx->ctxVersion[0] = major; + GLctx->ctxVersion[1] = minor; + + return GLctx; +} + +/******************************************************************************/ + +static void setupAttribs(int* glxAttr, const SST_OpenGLContextAttributes* attribs, Bool supportsMultisample) +{ + int* ptr = glxAttr; + int r, b, g; + + + switch(attribs->colorBits) + { + /* Since these values are "at least", 5-5-5 and 5-6-5 configurations can use the same number */ + case 15: + case 16: + r = g = b = 5; + break; + + case 24: + r = g = b = 8; + + } + + ptr = addAttr(ptr, GLX_DOUBLEBUFFER, True); + ptr = addAttr(ptr, GLX_STEREO, (attribs-> stereoEnabled != 0)); + ptr = addAttr(ptr, GLX_RED_SIZE, r); + ptr = addAttr(ptr, GLX_GREEN_SIZE, r); + ptr = addAttr(ptr, GLX_BLUE_SIZE, b); + ptr = addAttr(ptr, GLX_ALPHA_SIZE, ((int)attribs->alphaBits) & 0xFF); + ptr = addAttr(ptr, GLX_DEPTH_SIZE, ((int)attribs->depthBits) & 0xFF); + ptr = addAttr(ptr, GLX_STENCIL_SIZE, ((int)attribs->stencilBits) & 0xFF); + + /* Add multisample attributes as appropriate */ + if(attribs->multisampleFactor > 1 && supportsMultisample) + { + ptr = addAttr(ptr, GLX_SAMPLE_BUFFERS_ARB, 1); + ptr = addAttr(ptr, GLX_SAMPLES_ARB, ((int)attribs->multisampleFactor) & 0xFF); + } + + /* End attribute list */ + *ptr = None; + +} diff --git a/libsst-wm/Xlib/GLXPrivate.h b/libsst-wm/Xlib/GLXPrivate.h new file mode 100644 index 0000000..d1d03e8 --- /dev/null +++ b/libsst-wm/Xlib/GLXPrivate.h @@ -0,0 +1,95 @@ +/* + GLXPrivate.h + Author: Patrick Baggett <ptbaggett@762studios.com> + Created: 1/11/2013 + + Purpose: + + OpenGL on X Windows (GLX) utility code + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ + +#pragma once + +#ifndef _GLXPRIVATE_H +#define _GLXPRIVATE_H + +#include <X11/Xlib.h> +#include <SST/SST_WMOpenGL.h> + +struct SST_DisplayTarget_Xlib; + +#define MAX_GL_ATTRS 32 + +/* glx.h types */ +typedef XID GLXDrawable; +typedef XID GLXWindow; +typedef XID GLXPbuffer; +typedef struct __fakeGLXContext* GLXContext; +typedef struct __fakeGLXFBConfig* GLXFBConfig; + +typedef Bool (*pf_glXQueryExtension)(Display* dpy, int* errorBase, int* eventBase); +typedef Bool (*pf_glXQueryVersion)(Display* dpy, int* major, int* minor); +typedef const char* (*pf_glXQueryExtensionsString)(Display* dpy, int screen); +typedef GLXFBConfig* (*pf_glXChooseFBConfig)(Display* dpy, int screen, const int* attrib_list, int* nelements); +typedef GLXContext (*pf_glXCreateNewContext)(Display* dpy, GLXFBConfig config, int render_type, GLXContext share_list, Bool direct); +typedef void (*pf_glXDestroyContext)(Display* dpy, GLXContext ctx); +typedef Bool (*pf_glXMakeContextCurrent)(Display* display, GLXDrawable draw, GLXDrawable read, GLXContext ctx); +typedef GLXContext (*pf_glXGetCurrentContext)(void); +typedef void (*pf_glXSwapBuffers)(Display * dpy, GLXDrawable drawable); +typedef GLXPbuffer (*pf_glXCreatePbuffer)(Display* dpy, GLXFBConfig config, const int* attrib_list); +typedef void (*pf_glXDestroyPbuffer)(Display* dpy, GLXPbuffer pbuf); +typedef GLXContext (*pf_glXCreateContextAttribsARB)(Display* dpy, GLXFBConfig config, GLXContext share_context, Bool direct, const int* attrib_list); + +typedef void* (*pf_glXGetProcAddressARB)(const char* procName); + +typedef struct GLXFunctions +{ + pf_glXQueryExtension QueryExtension; + pf_glXQueryVersion QueryVersion; + pf_glXQueryExtensionsString QueryExtensionsString; + pf_glXChooseFBConfig ChooseFBConfig; + pf_glXCreateNewContext CreateNewContext; + pf_glXDestroyContext DestroyContext; + pf_glXMakeContextCurrent MakeContextCurrent; + pf_glXGetCurrentContext GetCurrentContext; + pf_glXSwapBuffers SwapBuffers; + pf_glXCreatePbuffer CreatePbuffer; + pf_glXDestroyPbuffer DestroyPbuffer; + pf_glXCreateContextAttribsARB CreateContextAttribsARB; + pf_glXGetProcAddressARB GetProcAddressARB; + + Bool supportsCreateContextARB; + Bool supportsProfiles; + Bool supportsMultisample; + void* libGL; +} GLXFunctions; + +extern GLXFunctions glX; + +/* Load libGL and resolve GLX symbols */ +int loadGLX(); + +/* Unload libGL */ +void unloadGLX(); + +/* Check if libGL was loaded */ +int isGLXLoaded(); + +/* Check if GLX is supported by the X server, and a usable version */ +int isGLXSupported(Display* display); + +/* Create a GLX context */ +SST_OpenGLContext GLXCreateOpenGLContext(struct SST_DisplayTarget_Xlib* target, SST_WMOpenGLType apiType, const SST_OpenGLContextAttributes* attribs, SST_OpenGLContextAttributes* selectedAttribsReturn); + +#endif + + diff --git a/libsst-wm/Xlib/SST_WMDialogBox_Xlib.c b/libsst-wm/Xlib/SST_WMDialogBox_Xlib.c new file mode 100644 index 0000000..65c2911 --- /dev/null +++ b/libsst-wm/Xlib/SST_WMDialogBox_Xlib.c @@ -0,0 +1,49 @@ +/* + SST_WMDialogBox_Xlib.c + Author: Patrick Baggett <ptbaggett@762studios.com> + Created: 1/5/2013 + + Purpose: + + Simple dialog box window (Xlib) + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ + +#include "XlibPrivate.h" + +#define BUTTON_HSPACE 16 /* Space on either side of a button */ +#define BUTTON_VSPACE 16 /* Space between top of button and dialog text */ +#define TEXT_HSPACE 16 +#define TEXT_VSPACE 16 + +typedef struct DialogBoxData +{ + const char* message; + int lenMessage; + int buttonId; + int exitTime; +} DialogBoxData; + +/******************************************************************************/ + +int Xlib_ShowDialogBox(SST_DisplayTarget target, SST_Window parent, const char* caption, const char* message, const char** buttons, int nrButtons) +{ + /* TODO: helluvalota work */ + (void)target; + (void)parent; + (void)caption; + (void)message; + (void)buttons; + (void)nrButtons; + + return 0; +} + diff --git a/libsst-wm/Xlib/SST_WMEnum_Xlib.c b/libsst-wm/Xlib/SST_WMEnum_Xlib.c new file mode 100644 index 0000000..bb0092b --- /dev/null +++ b/libsst-wm/Xlib/SST_WMEnum_Xlib.c @@ -0,0 +1,166 @@ +/* + SST_WMEnum_Xlib.c + Author: Patrick Baggett <ptbaggett@762studios.com> + Created: 1/8/2013 + + Purpose: + + Enumerates graphics adapters and screens. + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ + +#include <SST/SST_WM.h> + +#include "XlibPrivate.h" +#include "APIPrivate.h" +#include <string.h> /* strlen() etc. */ +#include <stdlib.h> + +/******************************************************************************/ + +static SST_GraphicsEnumerator Xlib_CreateGraphicsEnumerator(void) +{ + Display* display; + SST_GraphicsEnumerator_Xlib* enumerator; + + enumerator = (SST_GraphicsEnumerator_Xlib*)malloc(sizeof(SST_GraphicsEnumerator_Xlib)); + + if(enumerator == NULL) + return NULL; + + /* Open the display */ + display = X.OpenDisplay(NULL); + if(display == NULL) + { + free(enumerator); + return NULL; + } + + /* Save and return */ + enumerator->bpp = (uint32_t)DefaultDepth(display, DefaultScreen(display)); + enumerator->width = (uint32_t)DisplayWidth(display, DefaultScreen(display)); + enumerator->height = (uint32_t)DisplayHeight(display, DefaultScreen(display)); + + /* Done with display */ + X.CloseDisplay(display); + + return enumerator; +} + +/******************************************************************************/ + +static size_t Xlib_GetEnumAdapterCount(SST_GraphicsEnumerator enumerator) +{ + (void)enumerator; + + /* Only support 1 adapter */ + return 1; +} + +/******************************************************************************/ + +static void Xlib_GetEnumAdapterName(SST_GraphicsEnumerator enumerator, size_t adapterId, char* nameReturn, size_t* bufferSize) +{ + size_t len; + const char* name = "X Display Device"; + + (void)enumerator; + (void)adapterId; + + len = strlen(name); + + /* Query name length */ + if(nameReturn == NULL) + { + *bufferSize = len+1; + } + else + { + size_t copyAmount; + + /* Nothing to do? */ + if(*bufferSize == 0) + return; + + /* Use min(len, (*bufferSize)-1) */ + copyAmount = len; + if(copyAmount > (*bufferSize)-1) + copyAmount = (*bufferSize)-1; + + memcpy(nameReturn, name, copyAmount); + nameReturn[copyAmount] = '\0'; + } + +} + +/******************************************************************************/ + +static size_t Xlib_GetEnumScreenCount(SST_GraphicsEnumerator enumerator, size_t adapterId) +{ + (void)enumerator; + (void)adapterId; + return 1; +} + +/******************************************************************************/ + +static void Xlib_GetEnumVideoModes(SST_GraphicsEnumerator enumerator, size_t adapterId, size_t screenId, SST_VideoMode* modesReturn, size_t* modeCountReturn) +{ + SST_GraphicsEnumerator_Xlib* enumXlib = (SST_GraphicsEnumerator_Xlib*)enumerator; + + /* Only one adapter/screen supported */ + if(adapterId != 0 || screenId != 0) + return; + + if(modesReturn == NULL) + *modeCountReturn = 1; + else + { + modesReturn[0].bpp = enumXlib->bpp; + modesReturn[0].width = enumXlib->width; + modesReturn[0].height = enumXlib->height; + modesReturn[0].refreshRate = 0; + } + +} + +/******************************************************************************/ + +void Xlib_GetEnumCurrentVideoMode(SST_GraphicsEnumerator enumerator, size_t adapterId, size_t screenId, SST_VideoMode* mode) +{ + SST_GraphicsEnumerator_Xlib* enumXlib = (SST_GraphicsEnumerator_Xlib*)enumerator; + if(adapterId != 0 || screenId != 0) + return; + + mode->bpp = enumXlib->bpp; + mode->width = enumXlib->width; + mode->height = enumXlib->height; + mode->refreshRate = 0; +} + +/******************************************************************************/ + +static void Xlib_DestroyGraphicsEnumerator(SST_GraphicsEnumerator enumerator) +{ + free(enumerator); +} + +/******************************************************************************/ +struct SST_WM_EnumFuncs Xlib_EnumFuncs = { + Xlib_CreateGraphicsEnumerator, + Xlib_GetEnumAdapterCount, + Xlib_GetEnumAdapterName, + Xlib_GetEnumScreenCount, + Xlib_GetEnumVideoModes, + Xlib_GetEnumCurrentVideoMode, + Xlib_DestroyGraphicsEnumerator +}; + diff --git a/libsst-wm/Xlib/SST_WMEvent_Xlib.c b/libsst-wm/Xlib/SST_WMEvent_Xlib.c new file mode 100644 index 0000000..dbbb5ab --- /dev/null +++ b/libsst-wm/Xlib/SST_WMEvent_Xlib.c @@ -0,0 +1,482 @@ +/* + SST_WMEvent_Xlib.c + Author: Patrick Baggett <ptbaggett@762studios.com> + Created: 1/8/2013 + + Purpose: + + Window event functions (Xlib) + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ + +#include <SST/SST_WMEvent.h> +#include "XlibPrivate.h" +#include "APIPrivate.h" + +static SST_WMKey XlibKeyToSSTKey(XEvent* e, uint32_t* utf32Return); + +#ifdef HAVE_XINPUT2 +static void handleXI2Event(SST_DisplayTarget_Xlib*, XGenericEventCookie* cookie); +#endif + +/******************************************************************************/ + +static int Xlib_GetEvent(SST_DisplayTarget target, SST_WMEvent* eventReturn) +{ + XEvent e; + SST_DisplayTarget_Xlib* displayTarget = (SST_DisplayTarget_Xlib*)target; + Display* display = displayTarget->display; + EventQueue* q = &displayTarget->eventQueue; + + /* Read all X events */ + while(X.Pending(display)) + { + SST_Window_Xlib* win = NULL; + SST_Window_Xlib* next; + SST_WMEvent* event; + #ifdef HAVE_XINPUT2 + XGenericEventCookie* cookie = &e.xcookie; + #endif + int up = 1; + + X.NextEvent(display, &e); + + /* Find the window for which this matches and save into 'win' */ + next = displayTarget->firstWindow; + while(next) + { + /* Window ID matches this event? */ + if(next->xwin == e.xany.window) + { + /* Found it, stop here */ + win = next; + break; + } + + next = next->next; + } + + #ifdef HAVE_XINPUT2 + /* Handle X extension events */ + if(cookie->type == GenericEvent && cookie->extension == displayTarget->xi2opcode) + { + X.GetEventData(display, cookie); + handleXI2Event(displayTarget, cookie); + X.FreeEventData(display, cookie); + continue; + } + #endif + + /* Event doesn't apply to any window we own, ignore it */ + if(win == NULL) + continue; + + switch(e.type) + { + /* Moved mouse */ + case MotionNotify: + { + //Ignore MotionNotify when using relative mouse movements + if(!displayTarget->relativeMouse) + { + event = AllocSlotInEQ(q); + if(event) + { + event->window = win; + event->type = SSTWMEVENT_MOUSEMOVED; + event->details.mouseEvent.x = (uint32_t)e.xmotion.x; + event->details.mouseEvent.y = (uint32_t)e.xmotion.y; + event->details.mouseEvent.button = 0; + } + } + break; + } + + case ButtonPress: up = 0; /* Intentional fall through */ + case ButtonRelease: + { + const uint32_t button = e.xbutton.button; + + event = AllocSlotInEQ(q); + if(event) + { + event->window = win; + + /* Button press (1 - 3) */ + if(button >= Button1 && button <= Button3) + { + event->type = (up ? SSTWMEVENT_MOUSEUP : SSTWMEVENT_MOUSEDOWN); + event->details.mouseEvent.x = (uint32_t)e.xbutton.x; + event->details.mouseEvent.y = (uint32_t)e.xbutton.y; + event->details.mouseEvent.button = SST_MB1 + (button - Button1); + } + else if(e.type == ButtonPress) /* Scroll wheel. Button4 = scroll up, Button5 = scroll down. */ + { /* X will send two events: press/release for a single scroll. Only send 1 event */ + event->type = SSTWMEVENT_MOUSEWHEEL; + event->details.scrollEvent.vscroll = (button == Button4 ? 1.0f : -1.0f); + event->details.scrollEvent.hscroll = 0.0f; /* TODO: how to get horizonal scroll wheel? */ + } + + } + + break; + } + + case KeyPress: up = 0; /* Intentional fall through */ + case KeyRelease: + { + uint32_t modState = 0; + uint8_t whichBit = e.xkey.keycode % 8; + uint32_t whichByte = e.xkey.keycode / 8; + + /* + X will autorepeat with a bunch of keyd release messages. We only want the key up, so it looks like: + PPPPPPPPPPPPPR + instead of: + PRPRPRPRPRPRPR + + To find this out, when receive a KeyRelease message, we check if there is another KeyPress message with the same + exact time. If so, we ignore this KeyRelease message. + */ + if(e.xany.type == KeyRelease) + { + if(X.Pending(display)) + { + XEvent nextEvent; + X.PeekEvent(display, &nextEvent); + + if( nextEvent.type == KeyPress && /* Opposite of KeyRelease */ + nextEvent.xkey.keycode == e.xkey.keycode && /* Same key code */ + nextEvent.xkey.time == e.xkey.time) /* Same time */ + { + /* Ignore it */ + continue; + } + } + + /* OK, really is a key release then -- unset this bit */ + displayTarget->keymapBitvector[whichByte] &= ~(1 << whichBit); + + } + else + { + + if(displayTarget->keymapBitvector[whichByte] >> whichBit) + modState |= SSTKEYMOD_REPEAT; + + /* TODO: how to set SSTKEYMOD_REPEAT flag? Maybe use XQueryKeymap()? */ + displayTarget->keymapBitvector[whichByte] |= (1 << whichBit); + + } + + + event = AllocSlotInEQ(q); + if(event) + { + SST_WMKey key; + uint32_t utf32; + + key = XlibKeyToSSTKey(&e, &utf32); + + event->window = win; + event->type = (up ? SSTWMEVENT_KEYUP : SSTWMEVENT_KEYDOWN); + event->details.keyEvent.key = key; + event->details.keyEvent.utf32 = utf32; + event->details.keyEvent.modifierState = modState; + + } + break; + } + + /* Window shown */ + case Expose: + { + /* TODO: software rendering should blit image */ + break; + } + + case ConfigureNotify: + { + /* Clients are told to ignore this message if override_redirect is true. */ + if(e.xconfigure.override_redirect == False) + { + const XConfigureEvent* xc = (const XConfigureEvent*)&e.xconfigure; + + /* Check if window moved */ + if(win->lastX != xc->x || win->lastY != xc->y) + { + event = AllocSlotInEQ(q); + if(event) + { + event->window = win; + event->type = SSTWMEVENT_MOVED; + event->details.winEvent.x = (uint32_t)(xc->x < 0 ? 0 : xc->x); + event->details.winEvent.y = (uint32_t)(xc->y < 0 ? 0 : xc->y); + } + } + + if(win->lastWidth != xc->width || win->lastHeight != xc->height) + { + event = AllocSlotInEQ(q); + if(event) + { + event->window = win; + event->type = SSTWMEVENT_RESIZED; + event->details.winEvent.x = (uint32_t)xc->width; + event->details.winEvent.y = (uint32_t)xc->height; + } + + win->lastWidth = xc->width; + win->lastHeight = xc->height; + } + + } + break; + } + + case ClientMessage: + { + /* Close window attempt? */ + if(e.xclient.message_type == displayTarget->atomWmProtocols && + (Atom)e.xclient.data.l[0] == displayTarget->atomWmDeleteWindow) + { + event = AllocSlotInEQ(q); + if(event) + { + event->window = win; + event->type = SSTWMEVENT_CLOSE; + memset(&event->details, 0, sizeof(event->details)); + } + } + break; + } + } + } + + /* Dequeue for user events first */ + if(RemoveFromEQ(&displayTarget->userEventQueue, eventReturn)) + return 1; + + /* Remove system events next */ + if(RemoveFromEQ(&displayTarget->eventQueue, eventReturn)) + return 1; + + return 0; +} + +/******************************************************************************/ + +static EventQueue* Xlib_getUserEventQueue(SST_DisplayTarget target) +{ + + SST_DisplayTarget_Xlib* displayTarget = (SST_DisplayTarget_Xlib*)target; + return &displayTarget->userEventQueue; +} + +/******************************************************************************/ +static void Xlib_lockUserEventQueue(SST_DisplayTarget target) +{ + SST_DisplayTarget_Xlib* displayTarget = (SST_DisplayTarget_Xlib*)target; + pthread_mutex_lock(&displayTarget->eventLock); +} + +/******************************************************************************/ + +static void Xlib_unlockUserEventQueue(SST_DisplayTarget target) +{ + SST_DisplayTarget_Xlib* displayTarget = (SST_DisplayTarget_Xlib*)target; + pthread_mutex_unlock(&displayTarget->eventLock); +} + +/******************************************************************************/ + +static SST_WMKey XlibKeyToSSTKey(XEvent* e, uint32_t* utf32Return) +{ + uint8_t chars[8]; + uint32_t utf32; + + KeySym keycode; + + X.LookupString(&e->xkey, (char*)chars, sizeof(chars), &keycode, NULL); + + /* TODO: figure out how to extract multicharacter values */ + utf32 = (uint32_t)chars[0]; + + /* X allows Ctrl+[a-z] to generate some weird characters */ + if(utf32 < 0x20u) + utf32 = 0; + + *utf32Return = utf32; + + /* 0 - 9 */ + if(keycode >= XK_0 && keycode <= XK_9) + return (SST_WMKey)(SSTWMKEY_0 + (keycode - XK_0)); + + /* Keypad 0 - 9 */ + if(keycode >= XK_KP_0 && keycode <= XK_KP_9) + return (SST_WMKey)(SSTWMKEY_KEYPAD_0 + (keycode - XK_KP_0)); + + /* Capital A-Z */ + if(keycode >= XK_A && keycode <= XK_Z) + return (SST_WMKey)(SSTWMKEY_A + (keycode - XK_A)); + + /* Lower case A-Z */ + if(keycode >= XK_a && keycode <= XK_z) + return (SST_WMKey)(SSTWMKEY_A + (keycode - XK_a)); + + /* Function keys (F1-F15) */ + if(keycode >= XK_F1 && keycode <= XK_F15) + return (SST_WMKey)(SSTWMKEY_F1 + (keycode - XK_F1)); + + switch(keycode) + { + + case XK_BackSpace: return SSTWMKEY_BACKSPACE; + case XK_Tab: return SSTWMKEY_TAB; + case XK_Return: return SSTWMKEY_RETURN; + + case XK_Escape: return SSTWMKEY_ESCAPE; + case XK_space: return SSTWMKEY_SPACE; + case XK_Caps_Lock: return SSTWMKEY_CAPSLOCK; +#if 0 + case VK_OEM_COMMA : return SSTWMKEY_COMMA; + case VK_OEM_PERIOD: return SSTWMKEY_PERIOD; + case VK_OEM_2: return SSTWMKEY_FORWARDSLASH; /* '/?' key */ + case VK_OEM_1: return SSTWMKEY_SEMICOLON; /* ';:' key */ + case VK_OEM_7: return SSTWMKEY_QUOTES; /* single-quote/double quotes key */ + case VK_OEM_4: return SSTWMKEY_OPENBRACKET; /* '{{' key */ + case VK_OEM_6: return SSTWMKEY_CLOSEBRACKET; /* ']}' key */ + case VK_OEM_5: return SSTWMKEY_BACKSLASH; /* '\|' key */ + case VK_OEM_MINUS : return SSTWMKEY_UNDERBAR; + case VK_OEM_PLUS: return SSTWMKEY_EQUALS; +#endif + + //Keypad + case XK_KP_Enter: return SSTWMKEY_KEYPAD_ENTER; + case XK_Num_Lock: return SSTWMKEY_NUMLOCK; + case XK_KP_Decimal: return SSTWMKEY_KEYPAD_PERIOD; + case XK_KP_Divide: return SSTWMKEY_KEYPAD_DIVIDE; + case XK_KP_Multiply: return SSTWMKEY_KEYPAD_MULTIPLY; + case XK_KP_Subtract: return SSTWMKEY_KEYPAD_MINUS; + case XK_KP_Add: return SSTWMKEY_KEYPAD_PLUS; + + /* Arrow keys */ + case XK_Up: return SSTWMKEY_ARROW_UP; + case XK_Down: return SSTWMKEY_ARROW_DOWN; + case XK_Left: return SSTWMKEY_ARROW_LEFT; + case XK_Right: return SSTWMKEY_ARROW_RIGHT; + + /* The page up/down block */ + case XK_Insert: return SSTWMKEY_INSERT; + case XK_Home: return SSTWMKEY_HOME; + case XK_End: return SSTWMKEY_END; + case XK_Page_Up: return SSTWMKEY_PAGEUP; + case XK_Page_Down: return SSTWMKEY_PAGEDOWN; + case XK_Delete: return SSTWMKEY_DELETE; + + case XK_Shift_L: return SSTWMKEY_LEFTSHIFT; + case XK_Shift_R: return SSTWMKEY_RIGHTSHIFT; + case XK_Control_L: return SSTWMKEY_LEFTCONTROL; + case XK_Control_R: return SSTWMKEY_RIGHTCONTROL; + case XK_Alt_L: return SSTWMKEY_LEFTALT; + case XK_Alt_R: return SSTWMKEY_RIGHTALT; + case XK_Super_L: return SSTWMKEY_LEFTSUPER; + case XK_Super_R: return SSTWMKEY_RIGHTSUPER; +#if 0 + /* Misc */ + case VK_SNAPSHOT: return SSTWMKEY_PRINTSCREEN; + case VK_SCROLL: return SSTWMKEY_SCROLLLOCK; + case VK_PAUSE: return SSTWMKEY_PAUSE; +#endif + case XK_asciitilde: return SSTWMKEY_TILDE; /* `~ key */ + + default: break; + } + + return SSTWMKEY_NONE; +} + +/******************************************************************************/ +#ifdef HAVE_XINPUT2 + +static size_t min2(size_t x, size_t y) { return (x < y ? x : y); } + +static void extractXI2values(const XIRawEvent* rawev, double* valuesReturn, size_t valueArraySize) { + size_t i; + const double* raw_values = rawev->raw_values; + const unsigned char* mask = rawev->valuators.mask; + const size_t elemsToCheck = min2(valueArraySize, rawev->valuators.mask_len * 8); + + /* From what I can understand, raw_values[] is a compressed array. XIMaskIsSet(mask,i) + is used to check whether element i of the output should be read from raw_values[]. So + for example, raw_values[] could be just { 3.0, 5.0}, but the mask could be 1001b, which + means that: + XIMaskIsSet(1001b,0) == true; -> output[0] = 3.0 (raw_values[0)] + XIMaskIsSet(1001b,1) == false; -> output[1] = 0.0 (default value) + XIMaskIsSet(1001b,2) == false; -> output[2] = 0.0 (default value) + XIMaskIsSet(1001b,3) == true; -> output[3] = 5.0 (raw_values[1]) + */ + for(i=0; i < elemsToCheck; i++) { + if(XIMaskIsSet(mask, i)) { + valuesReturn[i] = *raw_values; + raw_values++; + } else { + valuesReturn[i] = 0.0; + } + } + + /* Any uninitialized elements at the end set to zero */ + if(elemsToCheck < valueArraySize) { + memset(&valuesReturn[elemsToCheck], 0, (valueArraySize-elemsToCheck)*sizeof(*valuesReturn)); + } +} + +static void handleXI2Event(SST_DisplayTarget_Xlib* displayTarget, XGenericEventCookie* cookie) +{ + XIDeviceEvent* ev = (XIDeviceEvent*)cookie->data; + EventQueue* q = &displayTarget->eventQueue; + SST_WMEvent* event; + + switch(ev->evtype) + { + case XI_RawButtonPress: + case XI_RawButtonRelease: + break; + + case XI_RawMotion: + { + XIRawEvent* re = (XIRawEvent*)cookie->data; + + event = AllocSlotInEQ(q); + if(event) + { + double rel[2]; + + extractXI2values(re, rel, 2); + + event->window = NULL; /* TODO: ... ?*/ + event->type = SSTWMEVENT_MOUSERELMOVED; + event->details.relMouseEvent.relx = (int32_t)rel[0]; + event->details.relMouseEvent.rely = (int32_t)rel[1]; + } + break; + } + } +} +#endif + +const struct SST_WM_EventFuncs Xlib_EventFuncs = { + Xlib_GetEvent, + Xlib_getUserEventQueue, + Xlib_lockUserEventQueue, + Xlib_unlockUserEventQueue +}; + diff --git a/libsst-wm/Xlib/SST_WMNonPortable_Xlib.c b/libsst-wm/Xlib/SST_WMNonPortable_Xlib.c new file mode 100644 index 0000000..c3edff8 --- /dev/null +++ b/libsst-wm/Xlib/SST_WMNonPortable_Xlib.c @@ -0,0 +1,38 @@ +/* + SST_WMNonPortable_Xlib.c + Author: Patrick Baggett <ptbaggett@762studios.com> + Created: 1/8/2012 + + Purpose: + + Non-portable API calls in libsst-wm for the Xlib platform + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ + +#include "XlibPrivate.h" + +/******************************************************************************/ + +Display* SST_WM_GetDisplayX11(SST_Window window) +{ + SST_Window_Xlib* win = (SST_Window_Xlib*)window; + + return win->owner->display; +} + +/******************************************************************************/ + +Window SST_WM_GetWindowX11(SST_Window window) +{ + SST_Window_Xlib* win = (SST_Window_Xlib*)window; + + return win->xwin; +} diff --git a/libsst-wm/Xlib/SST_WMOpenGL_Xlib.c b/libsst-wm/Xlib/SST_WMOpenGL_Xlib.c new file mode 100644 index 0000000..73b3c1d --- /dev/null +++ b/libsst-wm/Xlib/SST_WMOpenGL_Xlib.c @@ -0,0 +1,315 @@ +/* + SST_WMOpenGL_Xlib.c + Author: Patrick Baggett <ptbaggett@762studios.com> + Created: 1/13/2013 + + Purpose: + + OpenGL context creation on X Windows + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ +#include <SST/SST_WMOpenGL.h> +#include "XlibPrivate.h" +#include "GLXPrivate.h" +#include "APIPrivate.h" + +/* + NOTE: We don't include <GL/gl.h> because it may not exist! Many embedded Linux + systems now ship with OpenGL|ES only, and because of that, they don't have + headers for full OpenGL. This API supports both, so we can't assume any OpenGL + headers (either regular or "ES") exist. +*/ + +/******************************************************************************/ + +static SST_OpenGLContext Xlib_CreateOpenGLContext(SST_DisplayTarget target, SST_WMOpenGLType apiType, const SST_OpenGLContextAttributes* attribs, SST_OpenGLContextAttributes* selectedAttribsReturn) +{ + SST_DisplayTarget_Xlib* displayTarget = (SST_DisplayTarget_Xlib*)target; + SST_OpenGLContext glctx; + Bool usingGLX = True; + Display* display = displayTarget->display; + + /* If using GL|ES, only EGL will do */ + if(apiType == SSTGL_OPENGL_ES) + usingGLX = False; + else /* We can use either GLX or EGL to create a full GL context */ + { + /* Not loaded -> fail */ + if(!isGLXLoaded()) + usingGLX = False; + + /* The client has GLX libraries, but does the server support it? */ + if(!isGLXSupported(display)) + usingGLX = False; + + /* GLX isn't supported */ + if(usingGLX == False) + { + /* TODO: try EGL */ + return NULL; + } + + } + + + if(usingGLX) + { + glctx = GLXCreateOpenGLContext(displayTarget, apiType, attribs, selectedAttribsReturn); + } + else + { + /* TODO: Add EGL path */ + return NULL; + } + + return glctx; +} + +/******************************************************************************/ + +static SST_OpenGLContext Xlib_CreateSlaveOpenGLContext(SST_OpenGLContext masterGLContext) +{ + SST_OpenGLContext_Xlib* master = (SST_OpenGLContext_Xlib*)masterGLContext; + SST_OpenGLContext_Xlib* slave; + + #if 0 + HWND hInvisWnd; + FindMonitorInfo fmi; + HDC hDC = NULL; + HGLRC hGLRC = NULL; + BOOL ok; + const WGLFunctions* wgl = &master->wgl; + + /* Since the slave context merely needs to be on *a* screen controlled by the display target, just use the first one */ + findMonitor(&master->displayTarget->devs[0], &fmi); + if(!fmi.foundIt) + return NULL; + + /* Make 1x1 hidden window that doesn't appear in the titlebar and has no borders */ + hInvisWnd = CreateWindowExA(WS_EX_TOOLWINDOW, SST_WINCLASS, "(temp)", WS_POPUP, fmi.left, fmi.top, 1, 1, NULL, NULL, GetModuleHandleA(NULL), NULL); + if(hInvisWnd == NULL) + return NULL; + ShowWindow(hInvisWnd, SW_HIDE); + + /* Allocate context structure */ + slave = HeapAlloc(GetProcessHeap(), 0, sizeof(SST_OpenGLContext_Win32)); + if(slave == NULL) + { + DestroyWindow(hInvisWnd); + return NULL; + } + + ok = FALSE; + hDC = GetDC(hInvisWnd); + + /* If master context was done using legacy functions... */ + if(master->isLegacy) + { + PIXELFORMATDESCRIPTOR pfd; + + /* Get the PFD for this pixel foramt */ + DescribePixelFormat(hDC, master->pixelFormat, sizeof(pfd), &pfd); + + /* Set it */ + if(SetPixelFormat(hDC, master->pixelFormat, &pfd)) + { + hGLRC = wgl->CreateContext(hDC); + if(hGLRC != NULL) + { + if(wgl->ShareLists(master->context, hGLRC)) + ok = TRUE; + } + } + + } + else /* Modern OpenGL functions */ + { + if(SetPixelFormat(hDC, master->pixelFormat, NULL)) + { + HGLRC oldRC; + HDC oldDC; + + oldDC = wgl->GetCurrentDC(); + oldRC = wgl->GetCurrentContext(); + + /* Bind master context so we can call wgl extension functions. Note that we're using + the invisible window's HDC. This should work because we just set the pixel format to be + identical to the master context, meaning they should be compatible */ + if(wgl->MakeCurrent(hDC, master->context)) + { + int attrs[16]; + int* ptr = attrs; + int ctxFlags; + + if(master->debugEnabled) + ctxFlags |= WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB; + + ptr = addAttr(ptr, WGL_CONTEXT_MAJOR_VERSION_ARB, master->ctxVersion[0]); + ptr = addAttr(ptr, WGL_CONTEXT_MINOR_VERSION_ARB, master->ctxVersion[1]); + ptr = addAttr(ptr, WGL_CONTEXT_LAYER_PLANE_ARB, 0); + + /* If WGL_ARB_create_context_profile is supported, add a profile mask */ + if(wgl->supportsProfiles) + ptr = addAttr(ptr, WGL_CONTEXT_PROFILE_MASK_ARB, (master->legacyEnabled ? WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB : WGL_CONTEXT_CORE_PROFILE_BIT_ARB)); + + /* Legacy-free? */ + if(!master->legacyEnabled) + ctxFlags |= WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB; + + /* Debug mode? */ + if(master->debugEnabled) + ctxFlags |= WGL_CONTEXT_DEBUG_BIT_ARB; + + ptr = addAttr(ptr, WGL_CONTEXT_FLAGS_ARB, ctxFlags); + *ptr = 0; + + /* Create the new context, sharing with the master context */ + hGLRC = wgl->CreateContextAttribsARB(hDC, master->context, attrs); + if(hGLRC != NULL) + ok = TRUE; + } + + /* Restore old context */ + wgl->MakeCurrent(oldDC, oldRC); + } + } + + /* Done with the DC */ + if(hDC) + ReleaseDC(hInvisWnd, hDC); + + /* Did we succeed in making the slave context? */ + if(ok) + { + /* Set up slave context info */ + slave->context = hGLRC; + slave->displayTarget = master->displayTarget; + slave->hDCActive = NULL; + slave->hSlaveWnd = hInvisWnd; + slave->isLegacy = master->isLegacy; + slave->opengl32 = LoadLibraryA("opengl32.dll"); /* Need to increase ref count for opengl32.dll */ + slave->pixelFormat = master->pixelFormat; + slave->wgl = master->wgl; /* TODO: should be safe, right? context dependent, but same device/GL impl... */ + slave->ctxVersion[0] = master->ctxVersion[0]; + slave->ctxVersion[1] = master->ctxVersion[1]; + slave->legacyEnabled = master->legacyEnabled; + slave->debugEnabled = master->debugEnabled; + } + else /* Failure, clean up */ + { + if(hGLRC) + master->wgl.DeleteContext(hGLRC); + + DestroyWindow(hInvisWnd); + + HeapFree(GetProcessHeap(), 0, slave); + slave = NULL; + } + #endif + return slave; +} + +/******************************************************************************/ + +static void Xlib_SwapOpenGLBuffers(SST_OpenGLContext ctx) +{ + SST_OpenGLContext_Xlib* glctx = (SST_OpenGLContext_Xlib*)ctx; + + if(glctx->glxcontext) + glX.SwapBuffers(glctx->displayTarget->display, glctx->win); + else + { + /* TODO: eglSwapBuffers() */ + } +} + +/******************************************************************************/ + +static int Xlib_BindOpenGLContext(SST_OpenGLContext ctx, SST_Window window) +{ + SST_OpenGLContext_Xlib* glctx = (SST_OpenGLContext_Xlib*)ctx; + SST_Window_Xlib* win = (SST_Window_Xlib*)window; + + /* Unbinding a context from a thread */ + if(ctx == NULL) + { + + /* GLX: Unbind context */ + if(glctx->glxcontext) + { + glX.MakeContextCurrent(glctx->displayTarget->display, None, None, NULL); + + glctx->win = None; + } + else + { + /* TODO: EGL implementation */ + } + + /* OK */ + return 1; + } + + /* GLX*/ + if(glctx->glxcontext) + { + + /* Binding master context to a window */ + if(win != NULL) + { + if(glX.MakeContextCurrent(glctx->displayTarget->display, win->xwin, win->xwin, glctx->glxcontext)) + { + glctx->win = win->xwin; + return 1; + } + + /* Failed to bind */ + return 0; + } + else /* Bind slave context */ + { + /* TODO: bind to a slave's pbuffer, I guess? */ + } + } + else /* Otherwise EGL */ + { + /* TODO: EGL */ + } + + return 0; +} + +/******************************************************************************/ + +static void Xlib_DestroyOpenGLContext(SST_OpenGLContext ctx) +{ + SST_OpenGLContext_Xlib* glctx = (SST_OpenGLContext_Xlib*)ctx; + +#if 0 + if(glctx->hSlaveWnd) + DestroyWindow(glctx->hSlaveWnd); +#endif + + /* Destroy the OpenGL context */ + glX.DestroyContext(glctx->displayTarget->display, glctx->glxcontext); + + /* Free memory used by our GL context */ + free(glctx); +} + +/******************************************************************************/ +const struct SST_WM_OpenGLFuncs Xlib_OpenGLFuncs = { + Xlib_CreateOpenGLContext, + Xlib_CreateSlaveOpenGLContext, + Xlib_SwapOpenGLBuffers, + Xlib_BindOpenGLContext, + Xlib_DestroyOpenGLContext +}; diff --git a/libsst-wm/Xlib/SST_WMRender_Xlib.c b/libsst-wm/Xlib/SST_WMRender_Xlib.c new file mode 100644 index 0000000..2a2170d --- /dev/null +++ b/libsst-wm/Xlib/SST_WMRender_Xlib.c @@ -0,0 +1,75 @@ +/* + SST_WMRender_Xlib.c + Author: Patrick Baggett <ptbaggett@762studios.com> + Created: 1/8/2013 + + Purpose: + + Software rendering support + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ + +#include "XlibPrivate.h" +#include <SST/SST_WMWindow.h> +#include "APIPrivate.h" + +/******************************************************************************/ + +int Xlib_EnableSoftwareRendering(SST_Window window) +{ + SST_Window_Xlib* win = (SST_Window_Xlib*)window; + + /* TODO: Use XPutImage or XShm extension */ + (void)win; + + return 0; +} + +/******************************************************************************/ + +void Xlib_DisableSoftwareRendering(SST_Window window) +{ + SST_Window_Xlib* win = (SST_Window_Xlib*)window; + + /* TODO */ + (void)win; +} + +/******************************************************************************/ + +void* Xlib_LockBackbuffer(SST_Window window, size_t* pitchReturn) +{ + SST_Window_Xlib* win = (SST_Window_Xlib*)window; + + *pitchReturn = win->softwarePitch; + + return win->softwareBackbuffer; +} + +/******************************************************************************/ + +void Xlib_UnlockBackbuffer(SST_Window window) +{ + SST_Window_Xlib* win = (SST_Window_Xlib*)window; + + /* TODO: invalidate window rect and repaint */ + (void)win; +} + +/******************************************************************************/ + +struct SST_WM_RenderFuncs Xlib_RenderFuncs = { + Xlib_EnableSoftwareRendering, + Xlib_DisableSoftwareRendering, + Xlib_LockBackbuffer, + Xlib_UnlockBackbuffer +}; + diff --git a/libsst-wm/Xlib/SST_WMVideoMode_Xlib.c b/libsst-wm/Xlib/SST_WMVideoMode_Xlib.c new file mode 100644 index 0000000..9d8551d --- /dev/null +++ b/libsst-wm/Xlib/SST_WMVideoMode_Xlib.c @@ -0,0 +1,86 @@ +/* + SST_WMVideoMode_Xlib.c + Author: Patrick Baggett <ptbaggett@762studios.com> + Created: 1/8/2013 + + Purpose: + + Video mode setting functions (Xlib) + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ + +#include "XlibPrivate.h" +#include "APIPrivate.h" +/* + Right now, these are essentially no-ops. Later, some real mechanism needs to be used: + + 1) [Preferred] XRandR extension + 2) XF86VideoMode extension + + That will get good and messy then. In particular, if a set of headers isn't available for the platform, + then it basically won't compile. Seems like I need to re-write a few definitions in-line, and of course, + link dynamically and do proper version queries (*.so doesn't mean server actually supports it). +*/ + +/******************************************************************************/ + +static int Xlib_SetVideoModeOnScreen(SST_DisplayTarget target, size_t screenIndex, const SST_VideoMode* vmode) +{ + SST_DisplayTarget_Xlib* displayTarget = (SST_DisplayTarget_Xlib*)target; + Display* display = displayTarget->display; + int xscreen; + + /* Must be screen 0 */ + if(screenIndex != 0) + return 0; + + xscreen = DefaultScreen(display); + + /* Since we aren't changing the display mode, just verify it matches */ + if(vmode->bpp != (uint32_t)DefaultDepth(display, xscreen) || + vmode->width != (uint32_t)DisplayWidth(display, xscreen) || + vmode->height != (uint32_t)DisplayHeight(display, xscreen) || + vmode->refreshRate != 0) + { + return 0; + } + + return 1; +} + +/******************************************************************************/ + +static int Xlib_GetVideoModeOnScreen(SST_DisplayTarget target, size_t screenIndex, SST_VideoMode* vmodeReturn) +{ + SST_DisplayTarget_Xlib* displayTarget = (SST_DisplayTarget_Xlib*)target; + Display* display = displayTarget->display; + int xscreen; + + /* Must be screen 0 */ + if(screenIndex != 0) + return 0; + + xscreen = DefaultScreen(display); + vmodeReturn->bpp = (uint32_t)DefaultDepth(display, xscreen); + vmodeReturn->width = (uint32_t)DisplayWidth(display, xscreen); + vmodeReturn->height = (uint32_t)DisplayHeight(display, xscreen); + vmodeReturn->refreshRate = 0; + + return 1; +} + +/******************************************************************************/ + +const struct SST_WM_VideoModeFuncs Xlib_VideoModeFuncs = { + Xlib_SetVideoModeOnScreen, + Xlib_GetVideoModeOnScreen +}; + diff --git a/libsst-wm/Xlib/SST_WMWindow_Xlib.c b/libsst-wm/Xlib/SST_WMWindow_Xlib.c new file mode 100644 index 0000000..ed06d6b --- /dev/null +++ b/libsst-wm/Xlib/SST_WMWindow_Xlib.c @@ -0,0 +1,537 @@ +/* + SST_WMWindow_Xlib.c + Author: Patrick Baggett <ptbaggett@762studios.com> + Created: 1/8/2013 + + Purpose: + + Window creation (Xlib) + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ + +#include <SST/SST_WMWindow.h> +#include "XlibPrivate.h" +#include "XI2Private.h" +#include "EventQueue.h" +#include "APIPrivate.h" +#include <stdio.h> + +static void destroyWin(SST_Window_Xlib* win); + +/* Extended Window Manager Hints (http://standards.freedesktop.org/wm-spec/wm-spec-latest.html) */ +static int ewmh_supported(SST_DisplayTarget_Xlib* displayTarget, SST_Window_Xlib* win); +static void ewmh_setFullscreen(SST_Window_Xlib* win, int fullscreen); + +/******************************************************************************/ + +static SST_DisplayTarget Xlib_CreateDisplayTarget(size_t adapterIndex, size_t screenIndexOrMultihead) +{ + SST_DisplayTarget_Xlib* displayTarget; + #ifdef HAVE_XINPUT2 + XI2Functions XI; + #endif + Display* display; + + /* > 1 adapters not supported, multihead not supported */ + if(screenIndexOrMultihead != 0 || adapterIndex != 0) + return NULL; + + /* Open the X display */ + display = X.OpenDisplay(NULL); + if(display == NULL) + return NULL; + + /* If we can open a display, then we're connected to the X server, + so that is good enough. */ + + /* Allocate a display target structure */ + displayTarget = (SST_DisplayTarget_Xlib*)malloc(sizeof(SST_DisplayTarget_Xlib)); + if(displayTarget == NULL) + { + X.CloseDisplay(display); + return NULL; + } + + /* Initialize lock for user events */ + if(pthread_mutex_init(&displayTarget->eventLock, NULL) != 0) + { + X.CloseDisplay(display); + free(displayTarget); + return NULL; + } + + if(InitEQ(&displayTarget->eventQueue) == 0) + { + pthread_mutex_destroy(&displayTarget->eventLock); + X.CloseDisplay(display); + free(displayTarget); + return NULL; + } + + if(InitEQ(&displayTarget->userEventQueue) == 0) + { + DestroyEQ(&displayTarget->eventQueue); + pthread_mutex_destroy(&displayTarget->eventLock); + X.CloseDisplay(display); + free(displayTarget); + return NULL; + } + + + /* Save fields */ + displayTarget->display = display; + displayTarget->firstWindow = NULL; + displayTarget->relativeMouse = 0; + displayTarget->ewmhSupport = -1; + displayTarget->atomWmProtocols = X.InternAtom(display, "WM_PROTOCOLS", True); + displayTarget->atomWmDeleteWindow = X.InternAtom(display, "WM_DELETE_WINDOW", False); + memset(displayTarget->keymapBitvector, 0, sizeof(displayTarget->keymapBitvector)); + + /* XInput2: Verify that server supports XI2 (sets */ + #ifdef HAVE_XINPUT2 + if(XI2_IsLoaded()) + XI2_IsSupportedOnConnection(displayTarget); + #endif + + return (SST_DisplayTarget)displayTarget; +} + +/******************************************************************************/ + +static size_t Xlib_GetDisplayTargetScreenCount(SST_DisplayTarget target) +{ + (void)target; + return 1; +} + +/******************************************************************************/ + +static SST_Window Xlib_CreateWindowOnScreen(SST_DisplayTarget target, size_t screenIndex, uint32_t x, uint32_t y, uint32_t width, uint32_t height, const char* title) +{ + SST_Window_Xlib* win; + SST_DisplayTarget_Xlib* displayTarget = (SST_DisplayTarget_Xlib*)target; + Window xwin; + Display* display = displayTarget->display; + int screen = DefaultScreen(display); + SST_WMEvent* event; + + /* Must be on screen 0 */ + if(screenIndex != 0) + return 0; + + xwin = X.CreateSimpleWindow(display, + RootWindow(display, screen), + (int)x, (int)y, + (int)width, (int)height, + 0, 0, /* border width/color */ + WhitePixel(display, screen)); /* background color */ + + /* Set window's WM_PROTOCOLS property */ + X.SetWMProtocols(display, xwin, &displayTarget->atomWmDeleteWindow, 1); + + /* Set title bar text */ + X.StoreName(display, xwin, title); + + /* Map the window to the screen */ + X.MapRaised(display, xwin); + + /* Force the move, because some window managers just put windows wherever. Argh. */ + X.MoveWindow(display, xwin, (int)x, (int)y); + + X.SelectInput(display, xwin, KeyPressMask| KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask | ExposureMask | StructureNotifyMask); + + /* Display it now */ + X.Flush(display); + + /* Allocate SST window structure */ + win = (SST_Window_Xlib*)malloc(sizeof(SST_Window_Xlib)); + if(win == NULL) + return NULL; + + win->owner = displayTarget; + win->next = displayTarget->firstWindow; + win->xwin = xwin; + win->lastX = (uint32_t)x; + win->lastY = (uint32_t)y; + win->lastWidth = (uint32_t)width; + win->lastHeight = (uint32_t)height; + win->isFullscreen = 0; + win->softwareBackbuffer = NULL; + win->softwareImage = NULL; + win->softwarePitch = 0; + + /* Link window as new root */ + displayTarget->firstWindow = win; + + /* Add a SSTWMEVENT_CREATED event */ + event = AllocSlotInEQ(&displayTarget->eventQueue); + if(event != NULL) + { + event->window = win; + event->type = SSTWMEVENT_CREATED; + memset(&event->details, 0, sizeof(event->details)); + } + + return (SST_Window)win; +} + +/******************************************************************************/ + +static SST_DisplayTarget Xlib_GetWindowDisplayTarget(SST_Window window) +{ + SST_Window_Xlib* win = (SST_Window_Xlib*)window; + + return win->owner; +} + +/******************************************************************************/ + +static void Xlib_SetWindowText(SST_Window window, const char* titleBar) +{ + SST_Window_Xlib* win = (SST_Window_Xlib*)window; + + X.StoreName(win->owner->display, win->xwin, titleBar); +} + +/******************************************************************************/ + +static void Xlib_GetWindowRect(SST_Window window, SST_Rect* rectReturn) +{ + SST_Window_Xlib* win = (SST_Window_Xlib*)window; + Window dummyRoot; + int x, y; + unsigned int w, h; + unsigned int dummy1, dummy2; + + X.GetGeometry(win->owner->display, win->xwin, &dummyRoot, &x, &y, &w, &h, &dummy1, &dummy2); + + rectReturn->x = (uint32_t)x; + rectReturn->y = (uint32_t)y; + rectReturn->width = (uint32_t)w; + rectReturn->height = (uint32_t)h; + return; +} + +/******************************************************************************/ + +static void Xlib_MoveWindowOnScreen(SST_Window window, size_t screenIndex, uint32_t x, uint32_t y) +{ + SST_Window_Xlib* win = (SST_Window_Xlib*)window; + + /* Only allow operations on screen 0 */ + if(screenIndex != SST_SAME_SCREEN && screenIndex != 0) + return; + + X.MoveWindow(win->owner->display, win->xwin, (int)x, (int)y); + X.Sync(win->owner->display, False); +} + +/******************************************************************************/ + +static void Xlib_ResizeWindow(SST_Window window, uint32_t width, uint32_t height) +{ + SST_Window_Xlib* win = (SST_Window_Xlib*)window; + + X.ResizeWindow(win->owner->display, win->xwin, width, height); + X.Sync(win->owner->display, False); +} + +/******************************************************************************/ + +static void Xlib_SetWindowState(SST_Window window, SST_WMWindowState state, uint32_t param) +{ + SST_Window_Xlib* win = (SST_Window_Xlib*)window; + Display* display = win->owner->display; + + switch(state) + { + case SSTWS_SHOWN: + { + /* Map or unmap the window respectively */ + if(param == 0) + X.UnmapWindow(display, win->xwin); + else + X.MapWindow(display, win->xwin); + + break; + } + + /* Turn on/off resizeability */ + case SSTWS_RESIZEABLE: + { + /* TODO */ + break; + } + + case SSTWS_FULLSCREEN: + { + /* If we haven't yet checked for EWMH support, do so now */ + if(win->owner->ewmhSupport == -1) + win->owner->ewmhSupport = ewmh_supported(win->owner, win); + + /* Enabling fullscreen? */ + if(param && !win->isFullscreen) + { + + /* Use EWMH */ + if(win->owner->ewmhSupport != 0) + ewmh_setFullscreen(win, 1); + + win->isFullscreen = True; + } + else if(win->isFullscreen) /* Disabling fullscreen */ + { + win->isFullscreen = False; + + if(win->owner->ewmhSupport != 0) + ewmh_setFullscreen(win, 0); + } + + break; + } + + case SSTWS_MINIMIZED: + { + if(param == 0) /* Maximize */ + X.MapRaised(display, win->xwin); + else /* Minimize */ + X.IconifyWindow(display, win->xwin, DefaultScreen(display)); + break; + } + + default: break; + } +} + +/******************************************************************************/ + +static void Xlib_SetDisplayTargetState(SST_DisplayTarget target, SST_WMDisplayTargetState state, uint32_t param) +{ + SST_DisplayTarget_Xlib* displayTarget = (SST_DisplayTarget_Xlib*)target; + switch(state) + { + case SSTDTS_RELMOUSE: + { + #ifdef HAVE_XINPUT2 + XIEventMask eventmask; + uint8_t maskBytes[3]; + + memset(maskBytes, 0, sizeof(maskBytes)); + + eventmask.deviceid = XIAllMasterDevices; + eventmask.mask_len = sizeof(maskBytes); + eventmask.mask = maskBytes; + + if(!displayTarget->xi2Support) + { + printf("libsst-wm: XInput2 not supported; cannot use relative mouse mode.\n"); + return; + } + + /* Disabling? */ + if(displayTarget->relativeMouse && param == 0) + { + displayTarget->relativeMouse = 0; + } + else if(!displayTarget->relativeMouse && param != 0) /* Enabling? */ + { + printf("libsst-wm: enabling XI2 raw motion\n"); + XISetMask(maskBytes, XI_RawMotion); /* Macro invocation */ + displayTarget->relativeMouse = 1; + } + + if(XI.SelectEvents(displayTarget->display, DefaultRootWindow(displayTarget->display), &eventmask, 1) == Success) + printf("libsst-wm: relative mouse is %s!\n", param?"ON":"OFF"); + else + printf("libsst-wm: failed to change relative mouse mode - XISelectEvents() returned failure\n"); + + #else + printf("libsst-wm: XI2 not compiled in, cannot use relative mouse mode."); + #endif + break; + } + } +} + +/******************************************************************************/ + +static void Xlib_DestroyWindow(SST_Window window) +{ + SST_DisplayTarget_Xlib* displayTarget; + SST_Window_Xlib* win = (SST_Window_Xlib*)window; + SST_Window_Xlib* nextWin; + + displayTarget = win->owner; + nextWin = displayTarget->firstWindow; + + /* Special case: root window */ + if(nextWin == win) + { + /* Set new root to be this->next */ + displayTarget->firstWindow = win->next; + } + else + { + int found = 0; + + /* Check list */ + while(nextWin) + { + /* Did we find the window? */ + if(nextWin->next == win) + { + /* Remove this window from the linked list */ + nextWin->next = win->next; + found = 1; + break; + } + else + nextWin = nextWin->next; + } + + /* Don't destroy another display target's window */ + if(!found) + return; + + } + + /* Actually destroy the window window */ + destroyWin(win); + +} + +/******************************************************************************/ + +static void Xlib_DestroyDisplayTarget(SST_DisplayTarget target) +{ + SST_DisplayTarget_Xlib* displayTarget = (SST_DisplayTarget_Xlib*)target; + SST_Window_Xlib* window = displayTarget->firstWindow; + + /* Destroy all windows */ + while(window) + { + /* Save the next window */ + SST_Window_Xlib* next = window->next; + + destroyWin(window); + + /* Move to next window */ + window = next; + } + + DestroyEQ(&displayTarget->userEventQueue); + DestroyEQ(&displayTarget->eventQueue); + pthread_mutex_destroy(&displayTarget->eventLock); + X.CloseDisplay(displayTarget->display); + + /* Free structures */ + free(displayTarget); + +} + +/******************************************************************************/ + +static void destroyWin(SST_Window_Xlib* win) +{ + /* TODO Destroy more */ + + X.DestroyWindow(win->owner->display, win->xwin); + free(win); +} + +/******************************************************************************/ + +/* Check if extended window manager hints are supported */ +static int ewmh_supported(SST_DisplayTarget_Xlib* displayTarget, SST_Window_Xlib* win) +{ + Atom actions; + Atom actionFullscreen; + Atom actualType; + int format; + unsigned long nrItems; + unsigned long bytesAfterReturn; + unsigned long i; + Atom* propReturn; + int foundit = 0; + Display* display = displayTarget->display; + + actions = X.InternAtom(display, "_NET_WM_ALLOWED_ACTIONS", False); + actionFullscreen = X.InternAtom(display, "_NET_WM_ACTION_FULLSCREEN", False); + + /* Get a list of atoms */ + if(X.GetWindowProperty(display, win->xwin, actions, 0, 1024, False, XA_ATOM, &actualType, + &format, + &nrItems, + &bytesAfterReturn, + (unsigned char**)&propReturn) != Success) + { + /* Nope */ + return 0; + } + + /* Search through the list for the atom that matches the fullscreen atom */ + for(i=0; i<nrItems; i++) + { + if(propReturn[i] == actionFullscreen) + { + foundit = 1; + break; + } + } + + /* Free atom list and return */ + X.Free(propReturn); + + return foundit; +} + +/******************************************************************************/ + +/* Use extended window manager hints to set the window in/out of fullscreen mode */ +static void ewmh_setFullscreen(SST_Window_Xlib* win, int fullscreen) +{ + XEvent event; + Display* display = win->owner->display; + + event.xclient.type = ClientMessage; + event.xclient.serial = 0; + event.xclient.send_event = True; + event.xclient.display = display; + event.xclient.window = win->xwin; + event.xclient.message_type = X.InternAtom(display, "_NET_WM_STATE", False); + event.xclient.format = 32; + event.xclient.data.l[0] = fullscreen; + event.xclient.data.l[1] = X.InternAtom(display, "_NET_WM_STATE_FULLSCREEN", False); + event.xclient.data.l[2] = 0; + event.xclient.data.l[3] = 0; + event.xclient.data.l[4] = 0; + + X.SendEvent(display, DefaultRootWindow(display), False, StructureNotifyMask | ResizeRedirectMask, &event); +} + +extern int Xlib_ShowDialogBox(SST_DisplayTarget target, SST_Window parent, const char* caption, const char* message, const char** buttons, int nrButtons); + +const struct SST_WM_WindowFuncs Xlib_WindowFuncs = { + Xlib_CreateDisplayTarget, + Xlib_GetDisplayTargetScreenCount, + Xlib_CreateWindowOnScreen, + Xlib_GetWindowDisplayTarget, + Xlib_SetWindowText, + Xlib_GetWindowRect, + Xlib_MoveWindowOnScreen, + Xlib_ResizeWindow, + Xlib_ShowDialogBox, + Xlib_SetWindowState, + Xlib_SetDisplayTargetState, + Xlib_DestroyWindow, + Xlib_DestroyDisplayTarget +}; + diff --git a/libsst-wm/Xlib/XI2Private.c b/libsst-wm/Xlib/XI2Private.c new file mode 100644 index 0000000..a3cf720 --- /dev/null +++ b/libsst-wm/Xlib/XI2Private.c @@ -0,0 +1,83 @@ + +#ifdef HAVE_XINPUT2 +#include <dlfcn.h> +#include "XlibPrivate.h" +#include "XI2Private.h" + +XI2Functions XI = { 0 }; + +void XI2_Load() +{ + const int flags = RTLD_LAZY | RTLD_GLOBAL; + void* XI2lib; + + /* Try opening the correct SONAME version of libXi */ + XI2lib = dlopen("libXi.so.6", flags); + + /* Didn't work? */ + if(XI2lib == NULL) + { + /* Try a super-generic version */ + XI2lib = dlopen("libXi.so", flags); + if(XI2lib == NULL) + return; + + } + + /* Resolve symbols */ + XI.SelectEvents = dlsym(XI2lib, "XISelectEvents"); + XI.QueryVersion = dlsym(XI2lib, "XIQueryVersion"); + + if(XI.SelectEvents == NULL || XI.QueryVersion == NULL) + { + dlclose(XI2lib); + return; + } + + + /* Save handle */ + XI.XI2lib = XI2lib; + return; +} + +/******************************************************************************/ + +void XI2_Unload() +{ + if(XI.XI2lib != NULL) + dlclose(XI.XI2lib); +} + +/******************************************************************************/ + +int XI2_IsLoaded() +{ + return (XI.XI2lib != NULL); +} + +/******************************************************************************/ + +void XI2_IsSupportedOnConnection(SST_DisplayTarget_Xlib* displayTarget) +{ + int major = 2, minor = 0; + int dummyEvent, dummyError; + + /* Default to NO */ + displayTarget->xi2Support = 0; + displayTarget->xi2opcode = ~0; + + /* Check if server has XI at all. */ + if(X.QueryExtension(displayTarget->display, "XInputExtension", &displayTarget->xi2opcode, &dummyEvent, &dummyError)) + { + /* OK, does it support XI2? */ + XI.QueryVersion(displayTarget->display, &major, &minor); + + /* If the version is at least 2.0, we're good */ + if(major * 100 + minor >= 200) { + displayTarget->xi2Support = 1; + } + + } +} + +#endif diff --git a/libsst-wm/Xlib/XI2Private.h b/libsst-wm/Xlib/XI2Private.h new file mode 100644 index 0000000..c42b8e9 --- /dev/null +++ b/libsst-wm/Xlib/XI2Private.h @@ -0,0 +1,60 @@ +/* + XI2Private.h + Author: Patrick Baggett <ptbaggett@762studios.com> + Created: 5/13/2013 + + Purpose: + + Private definitions and functions for XInput2 portion of Xlib driver. XI2 support + is optional, but most systems that run a recent version of X will have it. + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ +#ifndef _XI2PRIVATE_H +#define _XI2PRIVATE_H + +#ifdef HAVE_XINPUT2 + +#include <X11/X.h> +#include <X11/Xlib.h> +#include <X11/extensions/XInput2.h> + +/******************************************************************************/ + +typedef Status (*pf_XISelectEvents)(Display* display, Window win, XIEventMask* masks, int num_masks); +typedef Status (*pf_XIQueryVersion)(Display *display, int *major_version_inout, int *minor_version_inout); + +/** Structure describing XInput2 functions used */ +typedef struct XI2Functions { + pf_XISelectEvents SelectEvents; + pf_XIQueryVersion QueryVersion; + void* XI2lib; +} XI2Functions; + +extern XI2Functions XI; + +struct SST_DisplayTarget_Xlib; + +/* Attempt to load XInput2 library */ +void XI2_Load(); + +/* Check if XInput2 library was successfully loaded (X server may not support it though) */ +int XI2_IsLoaded(); + +/* Unload XInput2 library */ +void XI2_Unload(); + +/* Check if the connection to the X server supports XInput2. */ +void XI2_IsSupportedOnConnection(struct SST_DisplayTarget_Xlib* displayTarget); + +#endif + +#endif + diff --git a/libsst-wm/Xlib/XlibDriver.c b/libsst-wm/Xlib/XlibDriver.c new file mode 100644 index 0000000..c3d5f34 --- /dev/null +++ b/libsst-wm/Xlib/XlibDriver.c @@ -0,0 +1,76 @@ +/* + XlibDriver.c + Author: Patrick Baggett <ptbaggett@762studios.com> + Created: 5/14/2014 + + Purpose: + + Xlib driver for libsst-wm + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ + +#include "APIPrivate.h" +#include "XlibPrivate.h" +#include "XI2Private.h" +#include "GLXPrivate.h" + +extern const struct SST_WM_WindowFuncs Xlib_WindowFuncs; +extern const struct SST_WM_EnumFuncs Xlib_EnumFuncs; +extern const struct SST_WM_EventFuncs Xlib_EventFuncs; +extern const struct SST_WM_OpenGLFuncs Xlib_OpenGLFuncs; +extern const struct SST_WM_RenderFuncs Xlib_RenderFuncs; +extern const struct SST_WM_VideoModeFuncs Xlib_VideoModeFuncs; + +/******************************************************************************/ + +int Xlib_init() +{ + if(getenv("LIBSST_NO_XLIB")) + return 0; + + if(loadXlib() == 0) + return 0; + + #ifdef HAVE_XINPUT2 + XI2_Load(); /* may fail, but that's OK */ + #endif + + + loadGLX(); + return 1; +} + +/******************************************************************************/ + +void Xlib_shutdown() +{ + #ifdef HAVE_XINPUT2 + XI2_Unload(); + #endif + + unloadGLX(); + + unloadXlib(); +} + +/******************************************************************************/ + +const struct SST_WM_Driver XlibDriver = { + "Xlib Driver", + Xlib_init, + Xlib_shutdown, + &Xlib_WindowFuncs, + &Xlib_EnumFuncs, + &Xlib_EventFuncs, + &Xlib_OpenGLFuncs, + &Xlib_RenderFuncs, + &Xlib_VideoModeFuncs +}; diff --git a/libsst-wm/Xlib/XlibPrivate.c b/libsst-wm/Xlib/XlibPrivate.c new file mode 100644 index 0000000..336d71d --- /dev/null +++ b/libsst-wm/Xlib/XlibPrivate.c @@ -0,0 +1,91 @@ +/* + XlibPrivate.c + Author: Patrick Baggett <ptbaggett@762studios.com> + Created: 1/8/2013 + + Purpose: + + Private defintions and functions for Xlib implementation of libsst-wm + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ + +#include "XlibPrivate.h" +#include <dlfcn.h> + +XlibFunctions X; + +/******************************************************************************/ + +int loadXlib() +{ + const int flags = RTLD_LAZY | RTLD_GLOBAL; + void* xlib; + + X.xlib = NULL; + + /* Try opening the correct SONAME version of libX11 */ + xlib = dlopen("libX11.so.6", flags); + + /* Didn't work? */ + if(xlib == NULL) + { + /* Try a super-generic version */ + xlib = dlopen("libX11.so", flags); + if(xlib == NULL) + return 0; + + } + + /* Resolve symbols */ + X.OpenDisplay = dlsym(xlib, "XOpenDisplay"); + X.CloseDisplay = dlsym(xlib, "XCloseDisplay"); + X.MoveWindow = dlsym(xlib, "XMoveWindow"); + X.ResizeWindow = dlsym(xlib, "XResizeWindow"); + X.MapRaised = dlsym(xlib, "XMapRaised"); + X.MapWindow = dlsym(xlib, "XMapWindow"); + X.UnmapWindow = dlsym(xlib, "XUnmapWindow"); + X.StoreName = dlsym(xlib, "XStoreName"); + X.DestroyWindow = dlsym(xlib, "XDestroyWindow"); + X.CreateSimpleWindow = dlsym(xlib, "XCreateSimpleWindow"); + X.GetGeometry = dlsym(xlib, "XGetGeometry"); + X.GetWindowProperty = dlsym(xlib,"XGetWindowProperty"); + X.Pending = dlsym(xlib, "XPending"); + X.NextEvent = dlsym(xlib, "XNextEvent"); + X.PeekEvent = dlsym(xlib, "XPeekEvent"); + X.SendEvent = dlsym(xlib, "XSendEvent"); + X.Flush = dlsym(xlib, "XFlush"); + X.Sync = dlsym(xlib, "XSync"); + X.InternAtom = dlsym(xlib, "XInternAtom"); + X.SetWMProtocols = dlsym(xlib, "XSetWMProtocols"); + X.IconifyWindow = dlsym(xlib, "XIconifyWindow"); + X.Free = dlsym(xlib, "XFree"); + X.SelectInput = dlsym(xlib, "XSelectInput"); + X.LookupString = dlsym(xlib, "XLookupString"); + X.QueryKeymap = dlsym(xlib, "XQueryKeymap"); + X.QueryExtension = dlsym(xlib, "XQueryExtension"); + X.GetEventData = dlsym(xlib, "XGetEventData"); + X.FreeEventData = dlsym(xlib, "XFreeEventData"); + + + /* Save handle */ + X.xlib = xlib; + + return 1; +} + +/******************************************************************************/ + +void unloadXlib() +{ + if(X.xlib != NULL) + dlclose(X.xlib); +} + diff --git a/libsst-wm/Xlib/XlibPrivate.h b/libsst-wm/Xlib/XlibPrivate.h new file mode 100644 index 0000000..4a0df94 --- /dev/null +++ b/libsst-wm/Xlib/XlibPrivate.h @@ -0,0 +1,186 @@ +/* + XlibPrivate.h + Author: Patrick Baggett <ptbaggett@762studios.com> + Created: 1/8/2013 + + Purpose: + + + + License: + + This program is free software. It comes without any warranty, to + the extent permitted by applicable law. You can redistribute it + and/or modify it under the terms of the Do What The Fuck You Want + To Public License, Version 2, as published by Sam Hocevar. See + http://sam.zoy.org/wtfpl/COPYING for more details. + +*/ + +#pragma once + +#ifndef _XLIBPRIVATE_H +#define _XLIBPRIVATE_H + +#include <X11/X.h> +#include <X11/Xlib.h> +#include <X11/Xproto.h> +#include <X11/Xutil.h> +#include <X11/Xatom.h> +#include <X11/keysym.h> + +#include <pthread.h> + +#include <SST/SST_WMTypes.h> +#include "EventQueue.h" +#include "GLXPrivate.h" +#include "XI2Private.h" + +#define MIN_BPP 16 /* Minimum BPP for a mode to be considered. Some embedded systems use 16-bit color to save memory, so accept those too. */ + +/* XGenericEventCookie is required for XI2, but not present on Solaris 10, so fake it*/ +#if defined(__sun) && !defined(HAVE_XINPUT2) +typedef void XGenericEventCookie; +#endif + +/* Xlib C API */ +typedef Display* (*pf_XOpenDisplay)(const char* s); +typedef void (*pf_XCloseDisplay)(Display* dpy); +typedef int (*pf_XMoveWindow)(Display* dpy, Window w, int x, int y); +typedef int (*pf_XResizeWindow)(Display* dpy, Window w, unsigned int x, unsigned int y); +typedef int (*pf_XMapRaised)(Display* dpy, Window w); +typedef int (*pf_XMapWindow)(Display* dpy, Window w); +typedef int (*pf_XUnmapWindow)(Display* dpy, Window w); +typedef int (*pf_XStoreName)(Display* dpy, Window w, const char* windowName); +typedef int (*pf_XDestroyWindow)(Display* dpy, Window w); +typedef Window (*pf_XCreateSimpleWindow)(Display*, Window parent, int x, int y, unsigned int w, unsigned int h, unsigned int borderWidth, unsigned long border, unsigned long background); +typedef Status (*pf_XGetGeometry)(Display* display, Drawable d, Window* root_return, int* x_return, int* y_return, unsigned int* width_return, unsigned int* height_return, unsigned int* border_width_return, unsigned int* depth_return); +typedef int (*pf_XGetWindowProperty)(Display *display, Window w, Atom property, long long_offset, long long_length, Bool _delete, Atom req_type, Atom* actual_type_return, int* actual_format_return, unsigned long* nitems_return, unsigned long* bytes_after_return, unsigned char** prop_return); +typedef int (*pf_XPending)(Display* display); +typedef int (*pf_XNextEvent)(Display* display, XEvent* event_return); +typedef int (*pf_XPeekEvent)(Display* display, XEvent* event_return); +typedef Status (*pf_XSendEvent)(Display *display, Window w, Bool propagate, long event_mask, XEvent *event_send); +typedef int (*pf_XFlush)(Display* display); +typedef int (*pf_XSync)(Display* display, Bool discard); +typedef Atom (*pf_XInternAtom)(Display* display, const char* name, Bool create); +typedef Status (*pf_XSetWMProtocols)(Display* display, Window w, Atom* protocols, int count); +typedef Status (*pf_XIconifyWindow)(Display* display, Window w, int screen_number); +typedef void (*pf_XFree)(void*); +typedef int (*pf_XSelectInput)(Display* display, Window w, long event_mask); +typedef int (*pf_XLookupString)(XKeyEvent* event_struct, char* buffer_return, int bytes_buffer, KeySym* keysym_return, XComposeStatus* status_in_out); +typedef int (*pf_XQueryKeymap)(Display *display, char keys_return[32]); +typedef Bool (*pf_XQueryExtension)(Display* display, const char* name, int* major_opcode_return, int* first_event_return, int* first_error_return); +typedef Bool (*pf_XGetEventData)(Display *display, XGenericEventCookie *cookie); +typedef void (*pf_XFreeEventData)(Display *display, XGenericEventCookie *cookie); + +/******************************************************************************/ + +typedef struct XlibFunctions +{ + pf_XOpenDisplay OpenDisplay; + pf_XCloseDisplay CloseDisplay; + pf_XMoveWindow MoveWindow; + pf_XResizeWindow ResizeWindow; + pf_XMapRaised MapRaised; + pf_XMapWindow MapWindow; + pf_XUnmapWindow UnmapWindow; + pf_XStoreName StoreName; + pf_XDestroyWindow DestroyWindow; + pf_XCreateSimpleWindow CreateSimpleWindow; + pf_XGetGeometry GetGeometry; + pf_XGetWindowProperty GetWindowProperty; + pf_XPending Pending; + pf_XNextEvent NextEvent; + pf_XPeekEvent PeekEvent; + pf_XSendEvent SendEvent; + pf_XFlush Flush; + pf_XSync Sync; + pf_XInternAtom InternAtom; + pf_XSetWMProtocols SetWMProtocols; + pf_XIconifyWindow IconifyWindow; + pf_XFree Free; + pf_XSelectInput SelectInput; + pf_XLookupString LookupString; + pf_XQueryKeymap QueryKeymap; + pf_XQueryExtension QueryExtension; + pf_XGetEventData GetEventData; + pf_XFreeEventData FreeEventData; + + void* xlib; +} XlibFunctions; + +/******************************************************************************/ + +typedef struct SST_GraphicsEnumerator_Xlib +{ + uint32_t width; + uint32_t height; + uint32_t bpp; +} SST_GraphicsEnumerator_Xlib; + +/******************************************************************************/ + +struct SST_Window_Xlib; + +typedef struct SST_DisplayTarget_Xlib +{ + EventQueue eventQueue; + uint8_t keymapBitvector[32]; /* Bitmap similar to XQueryKeymap() */ + pthread_mutex_t eventLock; /* Lock protecting user events, since they may be freely added by other threads */ + EventQueue userEventQueue; + Display* display; + struct SST_Window_Xlib* firstWindow; + int relativeMouse; /* Is relative mouse move enabled? */ + int ewmhSupport; /* Extended WM Hints, -1: not checked, 0: not supported, else: supported */ + int xi2Support; /* XInput2 support, -1: not checked, 0: not supported, else: supported */ + int xi2opcode; /* XI2 opcode */ + Atom atomWmProtocols; + Atom atomWmDeleteWindow; +} SST_DisplayTarget_Xlib; + +/******************************************************************************/ + +typedef struct SST_Window_Xlib +{ + struct SST_Window_Xlib* next; + SST_DisplayTarget_Xlib* owner; + Window xwin; + int isFullscreen; + + /* Because configure requests cover a wide variety of events, + keep these "last" parameters to check if an event actually occured */ + int lastX, lastY; + int lastWidth, lastHeight; + + /* Software rendering support */ + XImage* softwareImage; + void* softwareBackbuffer; + uint32_t softwarePitch; +} SST_Window_Xlib; + +/******************************************************************************/ + +typedef struct SST_OpenGLContext_Xlib +{ + SST_DisplayTarget_Xlib* displayTarget; + uint16_t ctxVersion[2]; /* context version major/minor */ + + + /* GLX Fields */ + int legacyEnabled; /* Did we use legacy GLX (< 1.4) context support? */ + GLXContext glxcontext; + GLXFunctions glX; + Window win; /* Window context is bound to */ + + /* EGL fields */ + +} SST_OpenGLContext_Xlib; + +/******************************************************************************/ + +extern XlibFunctions X; + +int loadXlib(); +void unloadXlib(); + +#endif diff --git a/libsst-wm/Xlib/sources.mk b/libsst-wm/Xlib/sources.mk new file mode 100644 index 0000000..d57ccdc --- /dev/null +++ b/libsst-wm/Xlib/sources.mk @@ -0,0 +1,32 @@ +# libsst-wm/Xlib/sources.mk +# Author: Patrick Baggett <ptbaggett@762studios.com> +# Created: 1/8/2013 +# +# Purpose: +# +# List of source files for X Windows systems +# +# License: +# +# This program is free software. It comes without any warranty, to +# the extent permitted by applicable law. You can redistribute it +# and/or modify it under the terms of the Do What The Fuck You Want +# To Public License, Version 2, as published by Sam Hocevar. See +# http://sam.zoy.org/wtfpl/COPYING for more details. + +ifeq ($(findstring -DHAVE_XLIB,$(CFLAGS)),-DHAVE_XLIB) + SRC += \ + Xlib/SST_WMDialogBox_Xlib.c \ + Xlib/SST_WMEnum_Xlib.c \ + Xlib/SST_WMEvent_Xlib.c \ + Xlib/SST_WMOpenGL_Xlib.c \ + Xlib/SST_WMNonPortable_Xlib.c \ + Xlib/SST_WMVideoMode_Xlib.c \ + Xlib/SST_WMRender_Xlib.c \ + Xlib/SST_WMWindow_Xlib.c \ + Xlib/XlibPrivate.c \ + Xlib/GLXPrivate.c \ + Xlib/XI2Private.c \ + Xlib/XlibDriver.c + +endif diff --git a/libsst-wm/libsst-wm.vcxproj b/libsst-wm/libsst-wm.vcxproj new file mode 100644 index 0000000..65c19cd --- /dev/null +++ b/libsst-wm/libsst-wm.vcxproj @@ -0,0 +1,208 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup Label="ProjectConfigurations"> + <ProjectConfiguration Include="Debug|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectGuid>{D5B4F387-30FB-449A-B777-356D0398C701}</ProjectGuid> + <RootNamespace>libsstwm</RootNamespace> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> + <ConfigurationType>StaticLibrary</ConfigurationType> + <PlatformToolset>v110</PlatformToolset> + <CharacterSet>MultiByte</CharacterSet> + <WholeProgramOptimization>true</WholeProgramOptimization> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> + <ConfigurationType>StaticLibrary</ConfigurationType> + <PlatformToolset>v110</PlatformToolset> + <CharacterSet>MultiByte</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> + <ConfigurationType>StaticLibrary</ConfigurationType> + <PlatformToolset>v110</PlatformToolset> + <CharacterSet>MultiByte</CharacterSet> + <WholeProgramOptimization>true</WholeProgramOptimization> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> + <ConfigurationType>StaticLibrary</ConfigurationType> + <PlatformToolset>v110</PlatformToolset> + <CharacterSet>MultiByte</CharacterSet> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <ImportGroup Label="ExtensionSettings"> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <PropertyGroup Label="UserMacros" /> + <PropertyGroup> + <_ProjectFileVersion>11.0.50727.1</_ProjectFileVersion> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <OutDir>$(SolutionDir)\Lib\x86\</OutDir> + <IntDir>$(SolutionDir)Intermediate\$(Configuration)\$(Platform)\$(ProjectName)\</IntDir> + <TargetName>$(ProjectName)-debug</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <OutDir>$(SolutionDir)\Lib\x86\</OutDir> + <IntDir>$(SolutionDir)Intermediate\$(Configuration)\$(Platform)\$(ProjectName)\</IntDir> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <OutDir>$(SolutionDir)\Lib\x64\</OutDir> + <IntDir>$(SolutionDir)Intermediate\$(Configuration)\$(Platform)\$(ProjectName)\</IntDir> + <TargetName>$(ProjectName)-debug</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <OutDir>$(SolutionDir)\Lib\x64\</OutDir> + <IntDir>$(SolutionDir)Intermediate\$(Configuration)\$(Platform)\$(ProjectName)\</IntDir> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <Optimization>Disabled</Optimization> + <AdditionalIncludeDirectories>$(SolutionDir)Lib\Include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <MinimalRebuild>false</MinimalRebuild> + <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> + <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> + <WarningLevel>Level4</WarningLevel> + <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> + <DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings> + <MultiProcessorCompilation>true</MultiProcessorCompilation> + <BufferSecurityCheck>false</BufferSecurityCheck> + <FunctionLevelLinking>true</FunctionLevelLinking> + <CreateHotpatchableImage>false</CreateHotpatchableImage> + <StringPooling>true</StringPooling> + <ExceptionHandling>false</ExceptionHandling> + <RuntimeTypeInfo>false</RuntimeTypeInfo> + <WholeProgramOptimization>true</WholeProgramOptimization> + </ClCompile> + <Lib /> + <Lib> + <LinkTimeCodeGeneration>true</LinkTimeCodeGeneration> + </Lib> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <Optimization>MaxSpeed</Optimization> + <IntrinsicFunctions>true</IntrinsicFunctions> + <AdditionalIncludeDirectories>$(SolutionDir)Lib\Include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> + <FunctionLevelLinking>true</FunctionLevelLinking> + <WarningLevel>Level4</WarningLevel> + <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> + <DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings> + <MultiProcessorCompilation>true</MultiProcessorCompilation> + <BufferSecurityCheck>false</BufferSecurityCheck> + <CreateHotpatchableImage>false</CreateHotpatchableImage> + <StringPooling>true</StringPooling> + <ExceptionHandling>false</ExceptionHandling> + <RuntimeTypeInfo>false</RuntimeTypeInfo> + </ClCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Midl> + <TargetEnvironment>X64</TargetEnvironment> + </Midl> + <ClCompile> + <Optimization>Disabled</Optimization> + <AdditionalIncludeDirectories>$(SolutionDir)Lib\Include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <MinimalRebuild>false</MinimalRebuild> + <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> + <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> + <WarningLevel>Level4</WarningLevel> + <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> + <MultiProcessorCompilation>true</MultiProcessorCompilation> + <BufferSecurityCheck>false</BufferSecurityCheck> + <FunctionLevelLinking>true</FunctionLevelLinking> + <CreateHotpatchableImage>false</CreateHotpatchableImage> + <StringPooling>true</StringPooling> + <ExceptionHandling>false</ExceptionHandling> + <RuntimeTypeInfo>false</RuntimeTypeInfo> + <WholeProgramOptimization>true</WholeProgramOptimization> + </ClCompile> + <Lib /> + <Lib> + <LinkTimeCodeGeneration>true</LinkTimeCodeGeneration> + </Lib> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Midl> + <TargetEnvironment>X64</TargetEnvironment> + </Midl> + <ClCompile> + <Optimization>MaxSpeed</Optimization> + <IntrinsicFunctions>true</IntrinsicFunctions> + <AdditionalIncludeDirectories>$(SolutionDir)Lib\Include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> + <FunctionLevelLinking>true</FunctionLevelLinking> + <WarningLevel>Level4</WarningLevel> + <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> + <MultiProcessorCompilation>true</MultiProcessorCompilation> + <BufferSecurityCheck>false</BufferSecurityCheck> + <CreateHotpatchableImage>false</CreateHotpatchableImage> + <StringPooling>true</StringPooling> + <ExceptionHandling>false</ExceptionHandling> + <RuntimeTypeInfo>false</RuntimeTypeInfo> + </ClCompile> + </ItemDefinitionGroup> + <ItemGroup> + <ClInclude Include="..\Lib\Include\SST\SST_WM.h" /> + <ClInclude Include="..\Lib\Include\SST\SST_WMEnum.h" /> + <ClInclude Include="..\Lib\Include\SST\SST_WMEvent.h" /> + <ClInclude Include="..\Lib\Include\SST\SST_WMKeys.h" /> + <ClInclude Include="..\Lib\Include\SST\SST_WMNonPortable.h" /> + <ClInclude Include="..\Lib\Include\SST\SST_WMOpenGL.h" /> + <ClInclude Include="..\Lib\Include\SST\SST_WMRender.h" /> + <ClInclude Include="..\Lib\Include\SST\SST_WMTypes.h" /> + <ClInclude Include="..\Lib\Include\SST\SST_WMVideoMode.h" /> + <ClInclude Include="..\Lib\Include\SST\SST_WMWindow.h" /> + <ClInclude Include="APIPrivate.h" /> + <ClInclude Include="EventQueue.h" /> + <ClInclude Include="Win32\Win32Private.h" /> + </ItemGroup> + <ItemGroup> + <ClCompile Include="API.c" /> + <ClCompile Include="Win32\SST_WMDialogBox_Win32.c" /> + <ClCompile Include="Win32\SST_WMEnum_Win32.c" /> + <ClCompile Include="Win32\SST_WMEvent_Win32.c" /> + <ClCompile Include="Win32\SST_WMNonPortable_Win32.c" /> + <ClCompile Include="Win32\SST_WMOpenGL_Win32.c" /> + <ClCompile Include="Win32\SST_WMRender_Win32.c" /> + <ClCompile Include="Win32\SST_WMVideoMode_Win32.c" /> + <ClCompile Include="Win32\SST_WMWindow_Win32.c" /> + <ClCompile Include="Win32\Win32Driver.c" /> + <ClCompile Include="Win32\Win32Private.c" /> + </ItemGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> + <ImportGroup Label="ExtensionTargets"> + </ImportGroup> +</Project> \ No newline at end of file diff --git a/libsst-wm/libsst-wm.vcxproj.filters b/libsst-wm/libsst-wm.vcxproj.filters new file mode 100644 index 0000000..17b4d03 --- /dev/null +++ b/libsst-wm/libsst-wm.vcxproj.filters @@ -0,0 +1,92 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup> + <Filter Include="Source Files"> + <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier> + <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions> + </Filter> + <Filter Include="Header Files"> + <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier> + <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> + </Filter> + <Filter Include="Source Files\Win32"> + <UniqueIdentifier>{5e667c79-5dd8-45f6-a16c-800453e72a33}</UniqueIdentifier> + </Filter> + </ItemGroup> + <ItemGroup> + <ClInclude Include="..\Lib\Include\SST\SST_WM.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\Lib\Include\SST\SST_WMEnum.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\Lib\Include\SST\SST_WMEvent.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\Lib\Include\SST\SST_WMKeys.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\Lib\Include\SST\SST_WMNonPortable.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\Lib\Include\SST\SST_WMOpenGL.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\Lib\Include\SST\SST_WMRender.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\Lib\Include\SST\SST_WMTypes.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\Lib\Include\SST\SST_WMVideoMode.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\Lib\Include\SST\SST_WMWindow.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="APIPrivate.h"> + <Filter>Source Files</Filter> + </ClInclude> + <ClInclude Include="EventQueue.h"> + <Filter>Source Files</Filter> + </ClInclude> + <ClInclude Include="Win32\Win32Private.h"> + <Filter>Source Files\Win32</Filter> + </ClInclude> + </ItemGroup> + <ItemGroup> + <ClCompile Include="API.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="Win32\SST_WMDialogBox_Win32.c"> + <Filter>Source Files\Win32</Filter> + </ClCompile> + <ClCompile Include="Win32\SST_WMEnum_Win32.c"> + <Filter>Source Files\Win32</Filter> + </ClCompile> + <ClCompile Include="Win32\SST_WMEvent_Win32.c"> + <Filter>Source Files\Win32</Filter> + </ClCompile> + <ClCompile Include="Win32\SST_WMNonPortable_Win32.c"> + <Filter>Source Files\Win32</Filter> + </ClCompile> + <ClCompile Include="Win32\SST_WMOpenGL_Win32.c"> + <Filter>Source Files\Win32</Filter> + </ClCompile> + <ClCompile Include="Win32\SST_WMRender_Win32.c"> + <Filter>Source Files\Win32</Filter> + </ClCompile> + <ClCompile Include="Win32\SST_WMVideoMode_Win32.c"> + <Filter>Source Files\Win32</Filter> + </ClCompile> + <ClCompile Include="Win32\SST_WMWindow_Win32.c"> + <Filter>Source Files\Win32</Filter> + </ClCompile> + <ClCompile Include="Win32\Win32Private.c"> + <Filter>Source Files\Win32</Filter> + </ClCompile> + <ClCompile Include="Win32\Win32Driver.c"> + <Filter>Source Files\Win32</Filter> + </ClCompile> + </ItemGroup> +</Project> \ No newline at end of file diff --git a/libsst-wm/obj/x86-64/release/API.o b/libsst-wm/obj/x86-64/release/API.o new file mode 100644 index 0000000000000000000000000000000000000000..5cfebd85e1b967549669baf4f37380cd0dd4d6d3 GIT binary patch literal 8816 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 N7EKalA4CR10sx5Yn=k+X literal 0 HcmV?d00001 diff --git a/libsst-wm/obj/x86-64/release/Xlib/GLXPrivate.o b/libsst-wm/obj/x86-64/release/Xlib/GLXPrivate.o new file mode 100644 index 0000000000000000000000000000000000000000..959d3d7740ae6ce8caccbf8a405f0e1b507f075a GIT binary patch literal 8224 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 ZB`<9D8-N_fz`(E;q!<Z<>_g%*002yhe4GFP literal 0 HcmV?d00001 diff --git a/libsst-wm/obj/x86-64/release/Xlib/SST_WMDialogBox_Xlib.o b/libsst-wm/obj/x86-64/release/Xlib/SST_WMDialogBox_Xlib.o new file mode 100644 index 0000000000000000000000000000000000000000..e2bb0dff2701ea0e137e571640c53c41907c6fe3 GIT binary patch literal 1288 zcmb<-^>JfjWMqH=Mg}_u1P><4z~I4zU^{@B4h-B391NizoliYFYkzojmVWT)41M9z z>HEN^)Afc+r|*>=Aa${a8Qh(ntrRpulS=bSN)=4?O!N$N%}T*M!#YDVJp&UxGfjxN zf{}rtnSq&sC4&e^F9QPuV^t6XV}$^tG!Hw+1V#o183qUjNh^a0M?QfzCTCu@I39Km z5FZBy`H6+$<9}?@%vgQQz`)Fa<Y^?0%nZy(JOq=Offd0)VlgwYA@LAQW(F1n2g;IQ zU|<kJau3*#Ai3b+koa(4m(0YR{B)=Miuj0}%p|>J1`rh=oRMD+mjNkeU{HWiU>~6P zLa(?ow<Ix%L9e)^2tsGTSS6_yB@B8gi6w~)dP&8_40_4=xw)x%B@B9b`6a1(?tY=V z#U+W!*$jF`sX2*ysTuKUMTxnoP@5>Dq(O1bz<?1_khI3Y01pSKHK6!}GQpH0R6lym zB!gu!33UDH3=9mQ^h2(G9jN^VXjZ}OH$@YN*$<;Z@-Q~C(izAcBsRKQFR1+}am~QM z0Ml=Qq!+{l`4vRNuqy)tI5on;8zz1OY7r=1g2XtXaRk#36BlFv<rk0&RQv&|KLk}6 yDTPBMK+4eF4wAV5A{ZDLZa`@+Xgs0Y4{{fJ+<~;L02$1{z@QD{AYrI5Tm%4&cU!Ii literal 0 HcmV?d00001 diff --git a/libsst-wm/obj/x86-64/release/Xlib/SST_WMEnum_Xlib.o b/libsst-wm/obj/x86-64/release/Xlib/SST_WMEnum_Xlib.o new file mode 100644 index 0000000000000000000000000000000000000000..36b05c093b29c275369ba18e0a02ecdaf3889304 GIT binary patch literal 3448 zcmb<-^>JfjWMqH=Mg}_u1P><4!0>|;!FB*M9T@l+xEVq{I-hzpzY*Ba!@$7s0wm$l z>H5K=x%LA?Dc24V|K$M&1_qCARuFqXi1>fOqto?=M|15DhEg$)Zr2YUoyWmCA<8F$ zmAn4%=$-%)_2_o}(cSO>Bsjz4-~)CK#tYpJ7M+Jc8ao3xK+^bBN<dW#5K<@uRT#hm zb*o2r=ns$1>;Er+Y&v-u?9tBJA3H#y6AR%szj5&Bti9pUS$e^vGxUT<r|$ue<E|e- zo&;%v`3vgZ6AYz-U{~}8FnV;m9`NWCcpU>~bTfFg9w_k#OLn@xfQdD~VDzwdeNoJh zEC7}dec{pV`@y5z^@K;~Ik+|5p(i}LU0--GUO2|U@S1S~!qFa`r5}(T-dX#?qqFpZ zM`!2_k51nUKAo-*osf8Wz)%|C(Oi3jq14l(x%L7>DKFTj<KTqx+6?5(Zg9w7fJQ(! zD0DA$g2*4;pa68e&<UZAJAl#!$T83$L$ev|Ubw9`5L-<tvZ48nfJbNT50DwKkeP7u zFepx_i6azTGK&jx5-Sy4Qp+-vQyCcCot>=|G(wX~^GZq;O!Z9k40O#(!92q{Lo+=C z6FoCch`550fuWg!nSmt(1A_?EQH)hV42%^5jM6;p91|EB7-SeA7$p4?L^$#Zv@tpJ zvN1j3VdsFz*?`0u7#R3LG)&$LEDhEl0}^LoU|0sCVe(81!3sd;*MP(s7#M^>G)&$P zEDhE_2PDqGz)%IEVe(9+U<DxkdqCn03=Byi8ZI9Tm%jrNXJBBE2GKD2Ft9X81S<yR zE*6H5|FKCjgA*X83^M~WrXT|Y12Y4-&_R&{`IQOD9B|k&FfbT0Fff3`VSI3yLUl4T zut8Y}$_uLg2UG|g#?Y_;nKKXM5m?wl!w@9C5h@N2Qw9bGP-zDe?`47*1P&_*lYyCm z1Ij|Bm>G}?V<ahN26iMKgt>u%fk6PmL?O515Z{SId>;<+qd3IRFfcF(F)%V{L;VF# zBMb}-pzsw$iZ2V8tAc|=;=_Gi^Gb8$BXTm6^pY7sRJ?OhYGO&Mdr@LRMrLv`NIJDB zu_V6;BI}-70upjeNh~NyEppB;%`3qs;g^`3iXtAIT$Gxchp9d+GbJ_OH$Nq{7^2)I zwYa1xzY>e}xrsSB`N<3s3~5EFsSL#>MLDT?47sVf$pw`Vtx%^qmlhSJ=9Rz=hDd@O z?N*wXT+F}+^*<<>KxyvJe+bY*5(mW}Oxy!WT#$i*0VaM8NgSk}1<DtJrZ;W|29(sH z02K$>D}-cDJCZmkufWV-2vP`6^9&5g_Cl=z=P0NWun;Wef{X)+gW??|0dgCNhKa-S zj|51NfdOs~EdMB=iNo@b29h|e3<U`pfCwaWVEGDW4#+Ja3{}PeY0H4}J_N(unE+J) zQVYT`cQ&Aj!`!(5O&sP<P~!(A1u_GKVfg{npg|UgxsyS!xH7jSF^NI1xTFX|XTVrR zsX2*yC8-r940>Q@N@7VOgI-c`F@s)FK7^B;pPQSSSHhr|mtT^q=k6D(TU?TuoDJ2G znh~E?1j-8_n<>Mf@C3ynddUb2&lMogB3S`ai^K)j37|9zQxB7CfEHn}a04|TKzd>6 z36@T@p>d2+@<RpS<qFhbkb9v_Fr~)8z<|wu2dG6Wz^WJ+K=y--gbFjj><85sATf{} zR4JIUKo<auLee#q38u`T?netI2AF<O9s?_c5}+`EGQpG`R6i`eg9RBF7(Ai&o5BR3 zG)zB?c8BVRO2er-sD8KrlmXKR<uZWU79cTn_cuWG!}1GEJt(YTY!DreBm7@L6(WZ} zsJ4R&!^0mGK2WPb#=-FfkYWY~hBUYcgaL9Zgasi%d~~;iWGX<30#v6#C3&IkD|Guo U)?l;01DYYw{SUGaWIhZ70Kv{8wg3PC literal 0 HcmV?d00001 diff --git a/libsst-wm/obj/x86-64/release/Xlib/SST_WMEvent_Xlib.o b/libsst-wm/obj/x86-64/release/Xlib/SST_WMEvent_Xlib.o new file mode 100644 index 0000000000000000000000000000000000000000..fba300495f5840894e962dc20b6a5ff89a7b4c1b GIT binary patch literal 8528 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 literal 0 HcmV?d00001 diff --git a/libsst-wm/obj/x86-64/release/Xlib/SST_WMNonPortable_Xlib.o b/libsst-wm/obj/x86-64/release/Xlib/SST_WMNonPortable_Xlib.o new file mode 100644 index 0000000000000000000000000000000000000000..a62073a30ebe49134c532b91f62db42af38518ed GIT binary patch literal 1416 zcmb<-^>JfjWMqH=Mg}_u1P><4z;J>I!FB*M9T>P7I2b}bI-h!U*1quQc75T|>H5Q? z8-yJ=Jh~fZFfcI09>$?SAoehWyR);Ef<|akX<kXGf~lT~o`J4eDVS$iXK1EpV4`QH z2@zK?GB7kVFf*`Z5CPlGz`$4)#K2e~z$neb&M|?JfkB1=f<e-XAi|MPppD6ymo0{e zodYUo0}^LoV2}dQF!@l3JV*!|289I+!^i*F<e0IB6axb@15#iiX=G+#M&cou%nYmu z4ibx*fend=U@|kXAUIGK$WKB@?g57Z0|SFT0|Ns{9L5K!18WHm4v7!<^~=u-$S*2M zOv*`(kI2bP(o1H5NW{CRmbhdV7vv;XMi?3*35I9prR0}`#K6WVfJp|hkCA;1Nh1hx znEecT#g(}wiAfB4#U&tn8T5)XV62kViV_CBl*E!m2EC->Vg|kB{M_8syb=bzy!?_> zJ$JuQ-QtqO<ZK4LqSTy3z0{2Ow4%h^RHzFmqof%az@dj8;xK<$qZtoM7sx^&|AEBN zW4Ibw5fU4u7KzKC&cMI`N~h%N*MYj<0NGFm1_qe@rfA|Y`(ZRl9>zvix&fJk#70-^ z1+^bJ4S<xx^hba=NEqZ-Brbz10|Pi!!@?UT=KwVj<}XeL25_!`>6d^i6l4J9J17T< zDuC(_K@tNo(cKT?LzRN0;g|y?!N9=q0V=`;jVE;bLGD72JCK$iQ2ovz4ibh6!$knD CTX7En literal 0 HcmV?d00001 diff --git a/libsst-wm/obj/x86-64/release/Xlib/SST_WMOpenGL_Xlib.o b/libsst-wm/obj/x86-64/release/Xlib/SST_WMOpenGL_Xlib.o new file mode 100644 index 0000000000000000000000000000000000000000..3ce61e0d699611ec66602e51862e73efadcb2110 GIT binary patch literal 3056 zcmb<-^>JfjWMqH=Mg}_u1P><4z)-+}U^{@B4h(z@+zg=}oliZQ-#B=5*52qWz2eas zdcvdA_kc&Y>kW@i*B8fKpMXsB=yrYK(cLhEfq}uJ)Ad7h?G?sS&f~66KnA_G+ySCq zfQZ%urR-2)k8alw9-YV0g_~=iFqE=`b-dOAaY__Dx<U4Zp6D*U0=5UL$)nTthex;T zkJqeV)h7>wo!VLZ0;0(E14uF!BHH{$!2=-!*5=XeAmGt@phUx?n-%0VkM7VP9^GAF zFMyds9^I3`yv}nTo!9?gm;kk*8ERH%=>sI29)O+GT>FBd)D!GAsPU!<<3D(G3wd<! z0-3oJWaBOnu@6N2zW~;992|fkfgPYgeVq#yg&Gv?(Omn3p(F&wJTC!=vx5XYx=Vj} zbe9Qubk~0H=(hLh-Vd_p|Ap2AB~qY(@aPT@02|ji0VDyjfCn6Mr~wG`9w<h^A&e9{ zFze8R25bQ|S|*%44DtcV*xlLLN<kwusWh*oRKZlwM9)CitQ5>MtTQyzGceIJ(}ajC z7#SFv8JHPZg6t3h5ey6rj8#Dlj1>Zm(md=O6Brp7WEdbAB)u9$IPwX!F*)<HF)ia^ z=YYuBfW#RX7{ov{Og<1S4b~q65@%pw@Bz^<c_w$T0+9JNAaMo;hWj8IE`JLyKL;cZ z$`T+NF7FJM2MJ-rponK-`1l{295dFO%fP_Qz>G~f12Y2)hPWsL0|OJ1IpDBiU|`UL zio^KeFoF6Vr2Zh(Byd<TFfb%T)$@WJ3=0DW28JrA_#3FW2UH)3VrBrRB@hz@GczC+ zK1edm44g<j1e2M89l?RJrZ6xt2te7$)B+sh>v4!5!y$eOhxmC01_nVSe`&xh4-O8A z5BK#iNX>KiiI2$1Owvnc08#PIMX8A;sSpY0{JfIXiV|dr;GD!VY_h@Si3Jc%PNivS zsYS&QO-`A4DG*^4vs_Y(ON#O<QDriV-F+f_@)J{1Qy9SP;L?JE{GyW76b5&n2yE_3 z&xv42D@sj;*ab1otu!yWn86F`PbLNi20jJ`hClxyAQ4HNA4z-~k~k=yVCtVDi3>6? zFu?Mp3pD+J%m<0<K-EpbA<hg^2u^#T_+VgAfvVR<5*I>p4^$eQ6QD}KLa>wwvIZm$ z%MTzogA~BTVfjG<BnT>hpmxLZg94g3EI+`+L1u$6R2c)L&IRR72!`340961|3&Jpa z8_>jI_JYzoND8DDgkknF=oMGymLw)I=oOa~LFfz^t0*-mQ4gFB^->Z`5*hT8ii;Wa zz@kO@5Rv5k+}zZ>5(d4z{E}2XcfU~G;*!MVY^bW#jQF&o#N1Sn#S~&t_<+Kg4b2=_ z_?Un^g(L@3i^OG+W?%r9dNB1cxd^C%2cQBx&^Uv|H!L32pyKEyY6+UXP-DR92gU}` zpmYi{lU)5~Q2WuXYk&&C%NLMk3=9mQ@PabIlpzlPOF)av3a}~$29W<jr7_5@AR(Cl z?V$D>fCQ273aI_2NMax+Ec{`#J5)bN4jJEt>PHp>v0?f^Y!C+3xgarg<qx0&;1&x= zAr!;h59Kn1<M96kEdB@8E-?Kt|AWdJ^tc0=%>h-I2I3%LkXw<s;Pe1>DzY%c45*<G kpc;6g<tEfv2AKUIH$j!6=&t}p76Svr0~ApPuzkov0IHe07ytkO literal 0 HcmV?d00001 diff --git a/libsst-wm/obj/x86-64/release/Xlib/SST_WMRender_Xlib.o b/libsst-wm/obj/x86-64/release/Xlib/SST_WMRender_Xlib.o new file mode 100644 index 0000000000000000000000000000000000000000..619077a3807b82f27ba9aec2125685953665a657 GIT binary patch literal 1944 zcmb<-^>JfjWMqH=Mg}_u1P><4z%YXa!FB*M9T<2RI2l4cI-h!U*1quQc75T|>H1>_ zNG|p;y6^-fq0Z6=Fx4L2u0OgR96Aqqbh|$A=oA3)J-Qt%kW@p>oe+B%WHRa4-Pzen zK_fJ&G_Ryo!Bo#g&p_9#6wEWMGc?mPFwry9gorB`85o)wm>F1tED-?_3=9m6RY44l z6#|UXJnS437#SF37$6uVEe;|a`2^aSoO#)Tc-T3hayB4w1_lOU5Dk;}L&(Q~#2FYE z^guLBJ`*8d0}{ufA1Z}Gf#QsX;p2Y{2?hoRW~?y^5@*7uoPn7EDYB7NFf*_r@eoXA z26hAoiN(yoio}C3MHv_vgpk|=4nqb81|z6Aj1LYw1_p)zsJIqHJ0#2)7#LEZ;t^1B znEEOP1_nU}gufJ^@(jVjA@Sk9L8*BusYUS-Ihjd%$qXPW-Zd{VDJL~JKdq!Zu_zUy zATuu=BI%M@j7QcdKRMeeF*!S_G%YQ)2%;l2F9(Y##8|h|yyRk-gCI00-azRF!ed~7 zu|eXTFhK?e1_3A=B+dn8gD43Q0ZOL~3=G^*Hi&}x8x#^C3=#ujNZw@thY&~{7TyUU zNd|;CEW8`g#9`shpjTX(TauW>pjTW{1fervtdi7<5(d4Z)SN`Ul*E!m2EC->Vg|kB z{M_8syb=bzy!?_>J$JuQ-QtqO<ZP(I)QtGFqQu-(sC5)m($FwLPq8rnXQSBw3Rh$y zHK=}OWI+Z7h67MOEPSC{26Vn60|Pi0!R&*ntAH8^3vW<dg5m)d@38pPVSuCssB)Ng zh6ivKDg)j9hEVq#pelpwH$@YN>4(u)Q2l7i7(`(T&?L}>{h|6nenVC&0aZ8ySrF=1 zWFapc;dcWXAjshdDt*wyPY_)0A)5$cTR@ApNC+2BLY;-eM|V3&asyPM1(XKmIgs5T g43dY%A1LoaoeC0$;}=jvyWt`b2GlqRhk=0s0E-i}9smFU literal 0 HcmV?d00001 diff --git a/libsst-wm/obj/x86-64/release/Xlib/SST_WMVideoMode_Xlib.o b/libsst-wm/obj/x86-64/release/Xlib/SST_WMVideoMode_Xlib.o new file mode 100644 index 0000000000000000000000000000000000000000..0c1346d307142ecfd50a325dcbe2decefbbb8579 GIT binary patch literal 2056 zcmb<-^>JfjWMqH=Mg}_u1P><4z;J>E!FB*M9T<2SxEMk`I-h!U*52^wEWO~-8G6E_ z+x3P=r|SogZV+ym!N9=a(dqibqq+71LkZUokj|G=L4w_`Ke`(pFfcH5y1wz~c0JJ@ zz~RyD`op8U;ROQ&L$~i6kK~gc2OqL~FrMgku&_K-8U|J+fLoD-<)KnTu%ZAK+^S?O z50!F*RXOmq9w=c4JLxs+4v?o~50m4a4lLe*`y=#?NAe|)gOAuf7%y}?Saco&S>1{1 zS5!3;P&Ft%MO7jLRRZ?siQ^7DpkRgi0K~+H-JPAS6f{DUO7lue6-@O^^bB;(O2ItC zIzux(0~0+nO^CRHk%6I^fti6N$T$%Y!N9=4SQW&;SRueD&BM+yfsuhhh5>>>(&s^h zBcDJUlQS<H(<vTy4v3r$NSuLz;Sh+1%kKrtgM_eQP;{^`eEg41ju~qTWnf@tV8W)H zfti6BLtKJ^fq@Ch9I)FN7#NJ8;xIng%~0LU3`m&(Dh8sM8Q4J-24-g9zz_ooFf*`$ zC=~3&z`!7gWWE4QHaIvWKHN7fGbJ_OH$NpcJ|ZVGNiUfJM8yZEmcS+a^MaF$Qd9FF zGVVBK;2PXY^OB2UwtzzdIrLyI2gL(O92Oo5P#qvK5QcIYAY}q5Od%Mio<Xm;GPfi# zi9xTpqzFQ1z*r@z6(tOMDTyVC40=h$#SD5ysX2*yMfnhs<ow*+)VvY~y}bOAR6TdU zP~GB^#N=$Ks??15w4%h^RG9sg($b)`&A@;WGcbQm1O)_=C1_j*MW}xCly(taA=C_X zVRZ%uaB3k}zai9q<TwFY^#E!SJUxK~85kJQ`8o^?;M526FH{*skb!~004l%@RR>ES zpnL?90u>S<t6=ItVj%nhB*?(PU<%?OVW==T-GPLipza5;k+CYehoF)${ZKALI8;Bn zat)|J1WX~6hPfZgWe9@$3*G+)&@2!07s&r0y&w$I3-iAq1E~A~iJ;;HsQyG$VYt6x v!XW=ZoeC2I(+yBT1&{&;1_n@34|4-Z0nC0*9QH4OCa46EVk8VT4lV)!!qpO( literal 0 HcmV?d00001 diff --git a/libsst-wm/obj/x86-64/release/Xlib/SST_WMWindow_Xlib.o b/libsst-wm/obj/x86-64/release/Xlib/SST_WMWindow_Xlib.o new file mode 100644 index 0000000000000000000000000000000000000000..91e6eafabcba6c39163fd29f9e77e65d613c2ef5 GIT binary patch literal 10304 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 PHv2uG4zxfs9Nm5Z!DUB% literal 0 HcmV?d00001 diff --git a/libsst-wm/obj/x86-64/release/Xlib/XI2Private.o b/libsst-wm/obj/x86-64/release/Xlib/XI2Private.o new file mode 100644 index 0000000000000000000000000000000000000000..13a5bfb89e966809400a68c2a8aeaeabeb1d991f GIT binary patch literal 2920 zcmb<-^>JfjWMqH=Mg}_u1P><4z@Wi_U^{@B4h*~uTnwQeoliZQ-v}Ic{Q@$j+x1K5 zvHc+V7a+o;)Aff(bL|g?QYl<AB`F@=u0QrcR3C@xVg++?ibJGZ50vnDbi>%Cd?0f? zIw3~9=7;dWvJ+l2PB?iO>{7V$5`LIgsE!G-Xe#)p9^l`004m!2#=xVq_C|_FH;bwU z0|NudV}=KgyS`vzU|=}z`UdLW8^;?qfS4c^-L5x|H*8^GVEF(4|9_Ze-Jv%;dN+YY zJwVLvT{A#Rdwsun^oD-$>^$ModC{Zu6F4;fUuZp0Vvnq`y9=T^^o>Vv=?jm}^Zze& zyS~W2kkak?hVg>!aRvs4I#4J;T>*;537}v|@i2zCx`Y)Rz9$bu-N?Yekdv7dk*Qal zuV)5lGDLU=r{<(4m$;Ut=9LsPM0f_4rWRF(r4|)u=I1d)c;*$9mbg}wq~?M74DQa( zRtg%SNu_xur3$8cCVB?CW~E@BVV$9wo`H#;nI=SB!N|bS%)rdRl7T@4>IBBBAO^+? z0Y+&ac8&>*3=A?15Db!D1tJ{z1lpLKdD)nj^00G2<ZM9V3=9lPAQ~ng3zi1!j{%7@ zFffRLXqbE;LcRth&cMKM1w_N-na)ELfW)w1P++n!eEg3^ih&txj$vS6W?;sqoPn8v z1&25|xnjsMGq7WbfdrTtkTNAm0E(Fz*q|%~#mB(FAc$nI1XN0pfq_8?$^GCkXJBBE zVqjnpfT}^J6mf{F;}F+}nh!G<9A^v+3|3I_Gf>09amB#E;0_gk1QiFz5d#B5G7j@o zafmZScp3#1WtJtDr0OLzM0kSu@jm&9DGVt&`30$Y3@JIqmAMQlImtQs#i?M~(7YUw ze1xY_yk{{;X=(~s+_N~iw4flrs3bMTKhHToFE2H@1e_5V;^T`;5|gvzlQXj8(-Jdt z7#J8tq3-5lU|>LwO;C7(q(J2bHv<F1A5f|A|Nnnb_<+P=>OpcKz6pq6U|>L3?*SEu zsfXpG0H`=fJr9!k;Yi|~Na6`lahN&EP<{rKMmHxPNgQMjECrXLiNpNWgeDGCKN(4! z7s)*fki<degZuyz+6W?`;eaf@7l-&!BynW(FC&Q~o1+EF*iiF9dEp3DT^Ljx7CuH$ z@nontD11QX!2GoVNn8lYUkXrtAoU;&<uX9(P)PiO#9{dZ7B3(%5QgQC2B=1m7zo4i z2ZLU5Wo}7g5`$iGNfCt3fU$~Fa}xDRQY%Ur^imQ_5*hT8ii;Wait-_x<ow*+)VvY~ zy}bOAR6TdUP+f3hX3zs`OU;N+D@x1-WiP1Blu@8?00j|x$pj0BZ6HY`E6}(M(hLmX z(hH^@rZfPW$pk=w!oa`)%0D2zu#yp0&Z#jlfJ-^_68RfQG0ZR|8eLe2fdO3FqU#4| zPzDADm_0Bf(92FksQpl9!jwT000RSq6G8;cLbu-%s^0)Ciy)k!2AU#-z$}=47!5KX z#s({Z66H|+P%fN8R|_gfKw{|1E1&|PmI+)lG^~*MK{(<s0a~@e(mg2tKye4cApNj# z1?5eQuxDUkH~`h32vUrML2gCjg5w_QRAgZW0jQxTpc+8s4k%xv+Yb_hDn-$M16lyU N%0ZYU)HoQI0RSr}gC76@ literal 0 HcmV?d00001 diff --git a/libsst-wm/obj/x86-64/release/Xlib/XlibDriver.o b/libsst-wm/obj/x86-64/release/Xlib/XlibDriver.o new file mode 100644 index 0000000000000000000000000000000000000000..a20f70bc30e50f810da2ac7907853395f82e017d GIT binary patch literal 2696 zcmb<-^>JfjWMqH=Mg}_u1P><4z`((dU^{@B4h(z@+zg=}olp0J_%A?&N9%zS_8lPB zYdtUp7HvIH3Kf(@2qLjS_Qf6snS>+=G6bv}AvPiQFh~>y`*=D92ZzM_`Nv22cseme z<YXo(xD;iUr52$mqnzXJ>};i=5t>w*S5m5As%N5SplenN<{8!*n&}ys=$UCk#1)JT z49yJ83@kyGihu|P1_s8eAO^+?0Y+&ac8&>*3=A?15Db#`0uhdU0&PsrylhOaJnS40 zIUA5T0|SF9h=$20fTckqSTQIpSr|V4$0o^)HD(zYm>HO{DQ942V8J2IibI?Ohd3t= zail~ARl&!=z#xR=PH@;TFfd3kFfa%})gV*8IK<^~h&$sD*MQm!vkx5R3=9lrIMh4h z5ckF*9>&1HAjrVVpa6Be2b504p&pccvH7<Vhx&;)#24WZ-;6^XoP!`4NG}=8iO<Z- zEMZ7bElJHQV~FrHiucJ+Oo7N0XOxzt<d^4xg+udlKoX^3%H1b|0m1_1NU&;%p<rfw zcxGNoez{v|UUD%+z%{Ql7nxg@npc9v_b*7zbN4|K2ujUMNi9MW2+K@K&G*euNri|p zz)~m|0|T553UUx1L^ClkFo4*9{zCvPUO?j93=9k~aZ`|D1_lO@I1iGzJ(4&tl6VM` zI6snj9FjOFUSZ~EAc+eisfW1-l%GL<0ht9-3QDIS8YGUKs|-MbpmK(RfdQ0<pj-wE zC<CNk7|I4wkTRSBoYP=s6i6JFE<x%=K>|=50Hs0VVo)}SiU1K%d&Qw_5S0KTpyHss z3+2MoKPWsw7$y#L4@eAzVfm0juedU|Br%CWuehWLLTA8OMX5Q7dL^k9B@B8gi6w~) zdP&8_40>SEqI`%*a(-@ZYF-J0US57ls-C-FsBUpdVsbWARcc0jT2W$dD$EfS(4hDN zg$)~;88Cn4qltsmA`3|~Fn~*2n0lDp4QLU304e}VgCM=Ik`@-WYS6GoFUi+K^`TQB zGmyn}7#J8pW|FHPR8E4-1jQY)xiELb(m6~H6kaekh&IIG{~4gf&%nTN1Eh$7fdS-y zkPyhNAR(Cl?V$dL<pYo$2y1{G#lXM-%f}!w5QYka(?5vs4%H80BjZ?@LS#WKYGa^c z=>AWD>WAeMm@zQ-!}#Gi{9gb~P%wXi{13|aF#Rz9gUSx{xC5EJ0IEL?#6iMPXTe24 od~~;iBzJ%$7#J8Lppu}n4x9ZTF>Lk=K-2GWkYPv|YAjp?0DF-6F#rGn literal 0 HcmV?d00001 diff --git a/libsst-wm/obj/x86-64/release/Xlib/XlibPrivate.o b/libsst-wm/obj/x86-64/release/Xlib/XlibPrivate.o new file mode 100644 index 0000000000000000000000000000000000000000..425924ac3b4a7592833295add19dd851eb915835 GIT binary patch literal 5032 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 XJ?=sJA3zf{D1JeF7={`L<1zpMzIX_w literal 0 HcmV?d00001 diff --git a/libsst-wm/sources-MacOSX.mk b/libsst-wm/sources-MacOSX.mk new file mode 100644 index 0000000..4914dd7 --- /dev/null +++ b/libsst-wm/sources-MacOSX.mk @@ -0,0 +1,26 @@ +# libsst-wm/sources-Darwin.mk +# Author: Patrick Baggett <ptbaggett@762studios.com> +# Created: 11/27/2012 +# +# Purpose: +# +# List of source files for MacOS X systems +# +# License: +# +# This program is free software. It comes without any warranty, to +# the extent permitted by applicable law. You can redistribute it +# and/or modify it under the terms of the Do What The Fuck You Want +# To Public License, Version 2, as published by Sam Hocevar. See +# http://sam.zoy.org/wtfpl/COPYING for more details. + +SRC := \ + SST_WMEnum_MacOSX.m #\ + #SST_WMEvent_Win32.c \ + #SST_WMNonPortable_Win32.c \ + #SST_WMOpenGL_Win32.c \ + #SST_WMRender_Win32.c \ + #SST_WMVideoMode_Win32.c \ + #SST_WMWindow_Win32.c \ + #Win32Private.c + diff --git a/libsst-wm/sources-RaspPi.mk b/libsst-wm/sources-RaspPi.mk new file mode 100644 index 0000000..07b2f37 --- /dev/null +++ b/libsst-wm/sources-RaspPi.mk @@ -0,0 +1,24 @@ +# libsst-wm/sources-RaspPi.mk +# Author: Patrick Baggett <ptbaggett@762studios.com> +# Created: 6/12/2013 +# +# Purpose: +# +# List of source files for Raspberry Pi native port +# +# License: +# +# This program is free software. It comes without any warranty, to +# the extent permitted by applicable law. You can redistribute it +# and/or modify it under the terms of the Do What The Fuck You Want +# To Public License, Version 2, as published by Sam Hocevar. See +# http://sam.zoy.org/wtfpl/COPYING for more details. + +SRC := \ + SST_WMDialogBox_RaspPi.c \ + SST_WMEnum_RaspPi.c \ + SST_WMEvent_RaspPi.c \ + SST_WMRender_RaspPi.c \ + SST_WMWindow_RaspPi.c \ + SST_WMVideoMode_RaspPi.c + diff --git a/libsst-wm/sources-Win32.mk b/libsst-wm/sources-Win32.mk new file mode 100644 index 0000000..c58df05 --- /dev/null +++ b/libsst-wm/sources-Win32.mk @@ -0,0 +1,26 @@ +# libsst-wm/sources-Win32.mk +# Author: Patrick Baggett <ptbaggett@762studios.com> +# Created: 11/16/2012 +# +# Purpose: +# +# List of source files for Win32 systems +# +# License: +# +# This program is free software. It comes without any warranty, to +# the extent permitted by applicable law. You can redistribute it +# and/or modify it under the terms of the Do What The Fuck You Want +# To Public License, Version 2, as published by Sam Hocevar. See +# http://sam.zoy.org/wtfpl/COPYING for more details. + +SRC := \ + SST_WMEnum_Win32.c \ + SST_WMEvent_Win32.c \ + SST_WMNonPortable_Win32.c \ + SST_WMOpenGL_Win32.c \ + SST_WMRender_Win32.c \ + SST_WMVideoMode_Win32.c \ + SST_WMWindow_Win32.c \ + Win32Private.c +