From ef36f284fbb7aa86d6f8f51688b95698aecd0131 Mon Sep 17 00:00:00 2001 From: nieznanysprawiciel Date: Fri, 11 Oct 2019 12:04:09 +0200 Subject: [PATCH] Merge branch 'master' into Rendering (everything compiles but not work) --- .gitignore | 2 + Assets/MaterialAsset/MaterialAsset.cpp | 76 + Assets/MaterialAsset/MaterialAsset.h | 106 + .../MaterialAsset/MaterialAssetInitData.cpp | 58 + Assets/MaterialAsset/MaterialAssetInitData.h | 66 + Assets/MaterialAsset/MaterialCreator.cpp | 85 + Assets/MaterialAsset/MaterialCreator.h | 53 + Assets/MaterialAsset/MaterialInfo.h | 89 + Assets/MaterialAsset/PhongMaterialData.h | 64 + Assets/MaterialAsset/ShadingModelData.h | 102 + Assets/MaterialAsset/ShadingModels.cpp | 55 + Assets/MaterialAsset/stdafx.cpp | 9 + Assets/MaterialAsset/stdafx.h | 44 + Assets/MeshAsset/stdafx.cpp | 9 + Assets/MeshAsset/stdafx.h | 44 + DX11API/DX11Initializer/DX11APIObjects.cpp | 98 +- DX11API/DX11Initializer/DX11APIObjects.h | 36 +- .../DX11Initializer/DX11ConstantsMapper.cpp | 306 +- DX11API/DX11Initializer/DX11ConstantsMapper.h | 53 +- DX11API/DX11Initializer/DX11DebugLayer.cpp | 30 + DX11API/DX11Initializer/DX11DebugLayer.h | 38 + DX11API/DX11Initializer/DX11Initializer.cpp | 61 +- DX11API/DX11Initializer/DX11Initializer.h | 18 +- DX11API/DX11Initializer/DX11Utils.cpp | 28 +- DX11API/DX11Initializer/DX11Utils.h | 22 +- DX11API/DX11Initializer/DX11Utils.inl | 11 + DX11API/DX11Renderer/DX11Renderer.cpp | 69 +- DX11API/DX11Renderer/DX11Renderer.h | 56 +- DX11API/DX11Resources/DX11Buffer.cpp | 52 +- DX11API/DX11Resources/DX11Buffer.h | Bin 1812 -> 2078 bytes DX11API/DX11Resources/DX11Compiler.cpp | 127 +- DX11API/DX11Resources/DX11Compiler.h | 53 +- DX11API/DX11Resources/DX11ComputeShader.cpp | Bin 3522 -> 3438 bytes DX11API/DX11Resources/DX11ComputeShader.h | Bin 1896 -> 2342 bytes DX11API/DX11Resources/DX11InputLayout.cpp | 265 +- DX11API/DX11Resources/DX11InputLayout.h | 32 +- .../DX11InputLayoutDescriptor.cpp | 44 - .../DX11Resources/DX11InputLayoutDescriptor.h | 31 - DX11API/DX11Resources/DX11PipelineState.cpp | 83 +- DX11API/DX11Resources/DX11PipelineState.h | 74 +- DX11API/DX11Resources/DX11PixelShader.cpp | Bin 5092 -> 3898 bytes DX11API/DX11Resources/DX11PixelShader.h | Bin 2352 -> 2266 bytes DX11API/DX11Resources/DX11RenderTarget.cpp | Bin 23496 -> 24500 bytes DX11API/DX11Resources/DX11RenderTarget.h | Bin 3004 -> 3522 bytes DX11API/DX11Resources/DX11SwapChain.cpp | 25 +- DX11API/DX11Resources/DX11SwapChain.h | 22 +- DX11API/DX11Resources/DX11Texture.cpp | 157 +- DX11API/DX11Resources/DX11Texture.h | Bin 3230 -> 3964 bytes DX11API/DX11Resources/DX11VertexShader.cpp | Bin 10126 -> 3500 bytes DX11API/DX11Resources/DX11VertexShader.h | Bin 2934 -> 2260 bytes DX11API/DX11Resources/ResourcesFactory.cpp | 145 +- DX11API/stdafx.h | 1 - GraphicAPI.sln | 139 +- ImageGenerators/CheckerboardGenerator.cpp | 78 + ImageGenerators/CheckerboardGenerator.h | 49 + Loaders/SoilTextureLoader/SOIL/etc1_utils.cpp | 680 ++ Loaders/SoilTextureLoader/SOIL/etc1_utils.h | 106 + Loaders/SoilTextureLoader/SOIL/image_DXT.c | 632 ++ Loaders/SoilTextureLoader/SOIL/image_DXT.h | 123 + Loaders/SoilTextureLoader/SOIL/image_helper.c | 435 ++ Loaders/SoilTextureLoader/SOIL/image_helper.h | 115 + Loaders/SoilTextureLoader/SOIL/jo_jpeg.h | 338 + Loaders/SoilTextureLoader/SOIL/pkm_helper.h | 19 + Loaders/SoilTextureLoader/SOIL/pvr_helper.h | 264 + Loaders/SoilTextureLoader/SOIL/stb_image.h | 6582 +++++++++++++++++ .../SoilTextureLoader/SOIL/stb_image_write.h | 993 +++ Loaders/SoilTextureLoader/SOIL/stbi_DDS.h | 34 + Loaders/SoilTextureLoader/SOIL/stbi_DDS_c.h | 589 ++ Loaders/SoilTextureLoader/SOIL/stbi_ext.h | 28 + Loaders/SoilTextureLoader/SOIL/stbi_ext_c.h | 74 + Loaders/SoilTextureLoader/SOIL/stbi_pkm.h | 34 + Loaders/SoilTextureLoader/SOIL/stbi_pkm_c.h | 227 + Loaders/SoilTextureLoader/SOIL/stbi_pvr.h | 34 + Loaders/SoilTextureLoader/SOIL/stbi_pvr_c.h | 1001 +++ .../SoilTextureLoader/SoilTextureLoader.cpp | 176 + Loaders/SoilTextureLoader/SoilTextureLoader.h | 43 + Loaders/SoilTextureLoader/stdafx.cpp | 9 + Loaders/SoilTextureLoader/stdafx.h | 40 + Loaders/swMaterialLoader/stdafx.cpp | 9 + Loaders/swMaterialLoader/stdafx.h | 43 + Loaders/swMaterialLoader/swMaterialLoader.cpp | 548 ++ Loaders/swMaterialLoader/swMaterialLoader.h | 88 + MockAPI/MockInitializer/MockInitializer.cpp | 16 +- MockAPI/MockInitializer/MockInitializer.h | 8 +- MockAPI/MockRenderer/MockRenderer.cpp | 13 +- MockAPI/MockRenderer/MockRenderer.h | 14 +- MockAPI/MockResources/MockBuffer.cpp | 17 +- MockAPI/MockResources/MockBuffer.h | Bin 1466 -> 1646 bytes MockAPI/MockResources/MockComputeShader.cpp | Bin 2504 -> 2754 bytes MockAPI/MockResources/MockComputeShader.h | Bin 1458 -> 1730 bytes MockAPI/MockResources/MockInputLayout.cpp | 13 +- MockAPI/MockResources/MockInputLayout.h | 12 +- .../MockInputLayoutDescriptor.cpp | 48 - .../MockResources/MockInputLayoutDescriptor.h | 45 - MockAPI/MockResources/MockPipelineState.cpp | 55 +- MockAPI/MockResources/MockPipelineState.h | 30 +- MockAPI/MockResources/MockPixelShader.cpp | Bin 3078 -> 3022 bytes MockAPI/MockResources/MockPixelShader.h | Bin 1940 -> 1702 bytes MockAPI/MockResources/MockRenderTarget.cpp | Bin 6576 -> 7238 bytes MockAPI/MockResources/MockRenderTarget.h | Bin 2034 -> 2512 bytes MockAPI/MockResources/MockSwapChain.cpp | 13 +- MockAPI/MockResources/MockSwapChain.h | 6 +- MockAPI/MockResources/MockTexture.cpp | 32 +- MockAPI/MockResources/MockTexture.h | Bin 1604 -> 2228 bytes MockAPI/MockResources/MockVertexShader.cpp | Bin 6114 -> 2498 bytes MockAPI/MockResources/MockVertexShader.h | Bin 2558 -> 1764 bytes MockAPI/MockResources/ResourcesFactory.cpp | 140 +- MockAssets/GraphicAPI.h | 112 + MockAssets/MockAsset.cpp | 39 + MockAssets/MockAsset.h | 42 + MockAssets/MockAssetCreator.cpp | 105 + MockAssets/MockAssetCreator.h | 79 + MockAssets/MockAssetLoader.cpp | 67 + MockAssets/MockAssetLoader.h | 61 + MockAssets/MockCompositeAsset.cpp | 35 + MockAssets/MockCompositeAsset.h | 47 + MockAssets/MockCompositeAssetCreator.cpp | 95 + MockAssets/MockCompositeAssetCreator.h | 73 + MockAssets/MockCompositeAssetLoader.cpp | 143 + MockAssets/MockCompositeAssetLoader.h | 73 + MockAssets/Utils.h | 97 + MockAssets/stdafx.cpp | 9 + MockAssets/stdafx.h | 51 + .../Visual2015/LibraryTemplate.vcxproj | 153 + .../Visual2015/LibraryTemplateConfig.props | 21 + .../Templates/Visual2015/TestTemplate.vcxproj | 167 + .../TestAssets/material/invalid-version.swmat | 25 + .../TestAssets/material/invalid-xml.swmat | 26 + .../material/no-MaterialAsset.swmat | 2 + .../TestAssets/material/no-gs-entry.swmat | 24 + .../TestAssets/material/no-header.swmat | 2 + ProjectsDir/TestAssets/material/no-ps.swmat | 25 + .../material/no-textures-entry.swmat | 19 + ProjectsDir/TestAssets/material/no-vs.swmat | 25 + .../TestAssets/material/not-existing-ps.swmat | 25 + .../material/not-existing-texture.swmat | 22 + .../TestAssets/material/not-existing-vs.swmat | 25 + .../material/single-texture-entry.swmat | 22 + ProjectsDir/TestAssets/mock/example.mock | 1 + ProjectsDir/TestAssets/mock/example1.mock | 1 + ProjectsDir/TestAssets/mock/example2.mock | 1 + ProjectsDir/TestAssets/mock/example3.mock | 1 + .../TestAssets/shaders/hlsl/MinimalShader.csh | 19 + .../TestAssets/shaders/hlsl/MinimalShader.psh | 9 + .../TestAssets/shaders/hlsl/MinimalShader.vsh | 16 + .../TestAssets/shaders/hlsl/NotCompiing.psh | 8 + .../TestAssets/shaders/hlsl/NotCompiling.csh | 19 + .../TestAssets/shaders/hlsl/NotCompiling.vsh | 16 + .../TestAssets/texture/big-lightweight.png | Bin 0 -> 16786 bytes .../TestAssets/texture/random-pixels.bmp | Bin 0 -> 102 bytes .../TestAssets/texture/random-pixels.jpg | Bin 0 -> 788 bytes .../TestAssets/texture/random-pixels.png | Bin 0 -> 148 bytes .../Visual2015/DX11API/DX11API.vcxproj | 4 +- .../DX11API/DX11API.vcxproj.filters | 12 +- .../MaterialAsset/MaterialAsset.vcxproj | 166 + .../MaterialAsset.vcxproj.filters | 51 + .../MaterialAsset/MaterialAssetConfig.props | 21 + .../Visual2015/MeshAsset/MeshAsset.vcxproj | 156 + .../MeshAsset/MeshAsset.vcxproj.filters | 21 + .../MeshAsset/MeshAssetConfig.props | 21 + .../Visual2015/MockAPI/MockAPI.vcxproj | 2 - .../MockAPI/MockAPI.vcxproj.filters | 6 - .../Visual2015/MockAssets/MockAssets.vcxproj | 170 + .../MockAssets/MockAssets.vcxproj.filters | 66 + .../MockAssets/MockAssetsConfig.props | 21 + ProjectsDir/Visual2015/Paths.props | 2 +- .../ResourceManager/ResourceManager.vcxproj | 111 +- .../ResourceManager.vcxproj.filters | 352 +- .../SoilTextureLoader.vcxproj | 180 + .../SoilTextureLoader.vcxproj.filters | 87 + .../SoilTextureLoaderConfig.props | 21 + .../Tests/TestMaterial/TestMaterial.vcxproj | 195 + .../TestMaterial/TestMaterial.vcxproj.filters | 25 + .../TestMipMapGenerator.vcxproj | 175 + .../TestResourceManager.vcxproj | 220 + .../TestResourceManager.vcxproj.filters | 94 + .../TestResources/TestResources.DX11.vcxproj | 13 +- .../TestResources.DX11.vcxproj.filters | 50 + .../TestSoilTextureLoader.DX11.vcxproj | 179 + ...TestSoilTextureLoader.DX11.vcxproj.filters | 16 + .../TestSoilTextureLoader.vcxproj | 190 + .../TestSoilTextureLoader.vcxproj.filters | 14 + .../swMaterialLoader/swMaterialLoader.vcxproj | 161 + .../swMaterialLoader.vcxproj.filters | 27 + .../swMaterialLoaderConfig.props | 21 + Rendering/GraphicAPIConstants.h | 98 +- Rendering/IGraphicAPIInitializer.h | 54 +- Rendering/IRenderer.h | 40 +- Rendering/RenderCommands.h | 52 +- .../AssetCreators/AssetsFactory.cpp | 158 + ResourceManager/AssetCreators/AssetsFactory.h | 88 + .../AssetCreators/Buffers/BufferCreator.cpp | 145 + .../AssetCreators/Buffers/BufferCreator.h | 52 + .../AssetCreators/IAssetCreateInfo.h | 42 + ResourceManager/AssetCreators/IAssetCreator.h | 85 + .../PipelineStates/BlendingStateCreator.cpp | 81 + .../PipelineStates/BlendingStateCreator.h | 48 + .../DepthStencilStateCreator.cpp | 81 + .../PipelineStates/DepthStencilStateCreator.h | 48 + .../PipelineStates/RasterizerStateCreator.cpp | 81 + .../PipelineStates/RasterizerStateCreator.h | 48 + .../AssetCreators/Shaders/LayoutCreator.cpp | 79 + .../AssetCreators/Shaders/LayoutCreator.h | 45 + .../AssetCreators/Shaders/ShaderCreator.h | 62 + .../AssetCreators/Shaders/ShaderCreator.inl | 179 + .../Textures/MipMapGenerator.cpp | 296 + .../AssetCreators/Textures/MipMapGenerator.h | 43 + .../Textures/RenderTargetCreator.cpp | 87 + .../Textures/RenderTargetCreator.h | 69 + .../Textures/Resampler/resampler.cpp | 1220 +++ .../Textures/Resampler/resampler.h | 196 + .../AssetCreators/Textures/TextureCreator.cpp | 119 + .../AssetCreators/Textures/TextureCreator.h | 65 + ResourceManager/AsyncLoad/AssetLoadRequest.h | 67 + ResourceManager/AsyncLoad/AssetLoadResponse.h | 41 + ResourceManager/AsyncLoad/AssetsThread.cpp | 86 + ResourceManager/AsyncLoad/AssetsThread.h | 80 + ResourceManager/AsyncLoad/LoadBarrier.cpp | 213 + ResourceManager/AsyncLoad/LoadBarrier.h | 110 + ResourceManager/AsyncLoad/RMAsyncThread.cpp | 42 + ResourceManager/AsyncLoad/RMAsyncThread.h | 50 + ResourceManager/Cache/CacheManager.cpp | 46 + ResourceManager/Cache/CacheManager.h | 43 + ResourceManager/Cache/IAssetCache.h | 55 + ResourceManager/Cache/MemoryCache.cpp | 37 + ResourceManager/Cache/MemoryCache.h | 40 + .../Exceptions/LoaderException.cpp | 60 + ResourceManager/Exceptions/LoaderException.h | 57 + .../Exceptions/ResourceManagerException.cpp | 49 + .../Exceptions/ResourceManagerException.h | 42 + ResourceManager/Loaders/IAssetLoadInfo.h | 38 + ResourceManager/Loaders/IAssetLoader.h | 117 + ResourceManager/Loaders/LoadingResult.h | 98 + ResourceManager/Loaders/RMLoaderAPI.h | 73 + .../Loaders/RenderTargetLoadInfo.h | 63 + .../Loaders/RenderTargetLoader.cpp | 116 + ResourceManager/Loaders/RenderTargetLoader.h | 45 + ResourceManager/Loaders/ShaderLoader.cpp | 98 + ResourceManager/Loaders/ShaderLoader.h | 36 + ResourceManager/Loaders/TextureLoadInfo.h | 69 + ResourceManager/Loaders/Tools/CanLoad.h | 62 + .../Loaders/Tools/LoadingContext.h | 99 + ResourceManager/PathTranslators/AssetPath.cpp | 42 + ResourceManager/PathTranslators/AssetPath.h | 165 + ResourceManager/PathTranslators/LoadPath.h | 131 + .../PathTranslators/PathsManager.cpp | 114 + .../PathTranslators/PathsManager.h | 70 + ResourceManager/ResourceContainer.h | 360 +- ResourceManager/ResourceManager.cpp | 707 +- ResourceManager/ResourceManager.h | 291 +- ResourceManager/ResourceManagerAPI.cpp | 279 + ResourceManager/ResourceManagerAPI.h | 302 + ResourceManager/stdafx.h | 14 +- Resources/Buffers/Buffer.cpp | 59 + Resources/Buffers/Buffer.h | 47 + Resources/{ => Buffers}/BufferInitData.h | 79 +- Resources/{ => Buffers}/IBuffer.h | 36 +- Resources/DepthStencilState.h | 61 - Resources/IRenderTarget.h | 18 - Resources/IShader.h | 34 - Resources/IShaderInputLayout.h | 23 - Resources/MeshResources.cpp | 222 +- Resources/MeshResources.h | 445 +- .../{ => PipelineStates}/BlendingState.h | 59 +- Resources/PipelineStates/DepthStencilState.h | 75 + .../{ => PipelineStates}/RasterizerState.h | 53 +- Resources/Resource.cpp | 318 + Resources/ResourceObject.h | 166 +- Resources/ResourcePtr.h | 248 +- Resources/ResourcesFactory.h | 92 +- .../Shaders/Exceptions/CompilationException.h | 54 + Resources/Shaders/IShader.h | 37 + Resources/Shaders/IShaderInputLayout.h | 31 + Resources/Shaders/InputLayout.h | 38 + Resources/Shaders/LayoutInitData.h | 96 + Resources/Shaders/Layouts.cpp | 91 + Resources/Shaders/ShaderInitData.h | 76 + Resources/Shaders/Shaders.cpp | 82 + Resources/Shaders/Shaders.h | 169 + Resources/SwapChain.h | 63 +- Resources/Texture.cpp | 99 - Resources/Texture.h | 157 - Resources/Textures/IRenderTarget.h | 31 + Resources/Textures/RenderTarget.cpp | 56 + Resources/Textures/RenderTarget.h | 128 + Resources/Textures/Texture.cpp | 105 + Resources/Textures/Texture.h | 216 + Resources/Textures/TextureInitData.h | 80 + Tests/TestMaterial/TestCreation.cpp | 71 + Tests/TestMaterial/TestSWMaterialLoader.cpp | 190 + Tests/TestMaterial/TestSWMaterialSaver.cpp | 170 + Tests/TestMaterial/Utils.h | 89 + Tests/TestMaterial/main.cpp | 3 + Tests/TestMipMapGenerator/TestMipMaps.cpp | 64 + Tests/TestMipMapGenerator/main.cpp | 3 + Tests/TestResourceManager/LoadBarrierTest.cpp | 249 + Tests/TestResourceManager/TestAssetPath.cpp | 180 + .../TestResourceManager/TestAssetsFactory.cpp | 75 + .../TestCreators/TestBufferCreator.cpp | 47 + Tests/TestResourceManager/TestLoadPath.cpp | 68 + .../TestLoaders/TestRenderTargetLoader.cpp | 49 + .../TestLoaders/TestShaderLoader.cpp | 67 + .../TestResourceManager/TestLoadingResult.cpp | 140 + .../TestResourceManager/TestPathsManager.cpp | 97 + .../TestAssetsCreation.cpp | 125 + .../TestAssetsLoadingAsync.cpp | 107 + .../TestAssetsLoadingSync.cpp | 123 + .../TestResourceManager/TestAssetsRemoval.cpp | 118 + .../TestResourceManager/TestListAssets.cpp | 36 + .../TestResourceManager/TestLoaders.cpp | 41 + .../TestResourceManager/TestPathAliases.cpp | 87 + .../TestResourceManagerAPI.cpp | 97 + Tests/TestResourceManager/TestResourcePtr.cpp | 43 + .../Utils/Tests/TestMockCompositeAsset.cpp | 85 + Tests/TestResourceManager/main.cpp | 3 + Tests/TestResourceManager/stdafx.cpp | 7 + Tests/TestResourceManager/stdafx.h | 25 + Tests/TestResources.DX11/GraphicAPI.h | 54 - .../TestResources.DX11/TestBlendingState.cpp | 14 +- .../TestCreators/TestBlendingStateCreator.cpp | 35 + .../TestCreators/TestBufferCreator.cpp | 124 + .../TestDepthStencilStateCreator.cpp | 33 + .../TestCreators/TestLayoutCreator.cpp | 120 + .../TestRasterizerStateCreator.cpp | 32 + .../TestCreators/TestRenderTargetCreator.cpp | 72 + .../TestCreators/TestShaderCreator.cpp | 122 + .../TestCreators/TestTextureCreator.cpp | 81 + .../TestLoaders/TestRenderTargetLoader.cpp | 65 + .../TestLoaders/TestShaderLoader.cpp | 65 + Tests/TestResources.DX11/main.cpp | 4 + .../TestFilesLoading.cpp | 104 + .../TestMipMapGeneration.cpp | 45 + Tests/TestSoilTextureLoader.DX11/main.cpp | 7 + .../TestTextureLoading.cpp | 78 + Tests/TestSoilTextureLoader/main.cpp | 3 + 335 files changed, 33636 insertions(+), 3136 deletions(-) create mode 100644 Assets/MaterialAsset/MaterialAsset.cpp create mode 100644 Assets/MaterialAsset/MaterialAsset.h create mode 100644 Assets/MaterialAsset/MaterialAssetInitData.cpp create mode 100644 Assets/MaterialAsset/MaterialAssetInitData.h create mode 100644 Assets/MaterialAsset/MaterialCreator.cpp create mode 100644 Assets/MaterialAsset/MaterialCreator.h create mode 100644 Assets/MaterialAsset/MaterialInfo.h create mode 100644 Assets/MaterialAsset/PhongMaterialData.h create mode 100644 Assets/MaterialAsset/ShadingModelData.h create mode 100644 Assets/MaterialAsset/ShadingModels.cpp create mode 100644 Assets/MaterialAsset/stdafx.cpp create mode 100644 Assets/MaterialAsset/stdafx.h create mode 100644 Assets/MeshAsset/stdafx.cpp create mode 100644 Assets/MeshAsset/stdafx.h create mode 100644 DX11API/DX11Initializer/DX11DebugLayer.cpp create mode 100644 DX11API/DX11Initializer/DX11DebugLayer.h delete mode 100644 DX11API/DX11Resources/DX11InputLayoutDescriptor.cpp delete mode 100644 DX11API/DX11Resources/DX11InputLayoutDescriptor.h create mode 100644 ImageGenerators/CheckerboardGenerator.cpp create mode 100644 ImageGenerators/CheckerboardGenerator.h create mode 100644 Loaders/SoilTextureLoader/SOIL/etc1_utils.cpp create mode 100644 Loaders/SoilTextureLoader/SOIL/etc1_utils.h create mode 100644 Loaders/SoilTextureLoader/SOIL/image_DXT.c create mode 100644 Loaders/SoilTextureLoader/SOIL/image_DXT.h create mode 100644 Loaders/SoilTextureLoader/SOIL/image_helper.c create mode 100644 Loaders/SoilTextureLoader/SOIL/image_helper.h create mode 100644 Loaders/SoilTextureLoader/SOIL/jo_jpeg.h create mode 100644 Loaders/SoilTextureLoader/SOIL/pkm_helper.h create mode 100644 Loaders/SoilTextureLoader/SOIL/pvr_helper.h create mode 100644 Loaders/SoilTextureLoader/SOIL/stb_image.h create mode 100644 Loaders/SoilTextureLoader/SOIL/stb_image_write.h create mode 100644 Loaders/SoilTextureLoader/SOIL/stbi_DDS.h create mode 100644 Loaders/SoilTextureLoader/SOIL/stbi_DDS_c.h create mode 100644 Loaders/SoilTextureLoader/SOIL/stbi_ext.h create mode 100644 Loaders/SoilTextureLoader/SOIL/stbi_ext_c.h create mode 100644 Loaders/SoilTextureLoader/SOIL/stbi_pkm.h create mode 100644 Loaders/SoilTextureLoader/SOIL/stbi_pkm_c.h create mode 100644 Loaders/SoilTextureLoader/SOIL/stbi_pvr.h create mode 100644 Loaders/SoilTextureLoader/SOIL/stbi_pvr_c.h create mode 100644 Loaders/SoilTextureLoader/SoilTextureLoader.cpp create mode 100644 Loaders/SoilTextureLoader/SoilTextureLoader.h create mode 100644 Loaders/SoilTextureLoader/stdafx.cpp create mode 100644 Loaders/SoilTextureLoader/stdafx.h create mode 100644 Loaders/swMaterialLoader/stdafx.cpp create mode 100644 Loaders/swMaterialLoader/stdafx.h create mode 100644 Loaders/swMaterialLoader/swMaterialLoader.cpp create mode 100644 Loaders/swMaterialLoader/swMaterialLoader.h delete mode 100644 MockAPI/MockResources/MockInputLayoutDescriptor.cpp delete mode 100644 MockAPI/MockResources/MockInputLayoutDescriptor.h create mode 100644 MockAssets/GraphicAPI.h create mode 100644 MockAssets/MockAsset.cpp create mode 100644 MockAssets/MockAsset.h create mode 100644 MockAssets/MockAssetCreator.cpp create mode 100644 MockAssets/MockAssetCreator.h create mode 100644 MockAssets/MockAssetLoader.cpp create mode 100644 MockAssets/MockAssetLoader.h create mode 100644 MockAssets/MockCompositeAsset.cpp create mode 100644 MockAssets/MockCompositeAsset.h create mode 100644 MockAssets/MockCompositeAssetCreator.cpp create mode 100644 MockAssets/MockCompositeAssetCreator.h create mode 100644 MockAssets/MockCompositeAssetLoader.cpp create mode 100644 MockAssets/MockCompositeAssetLoader.h create mode 100644 MockAssets/Utils.h create mode 100644 MockAssets/stdafx.cpp create mode 100644 MockAssets/stdafx.h create mode 100644 ProjectsDir/Templates/Visual2015/LibraryTemplate.vcxproj create mode 100644 ProjectsDir/Templates/Visual2015/LibraryTemplateConfig.props create mode 100644 ProjectsDir/Templates/Visual2015/TestTemplate.vcxproj create mode 100644 ProjectsDir/TestAssets/material/invalid-version.swmat create mode 100644 ProjectsDir/TestAssets/material/invalid-xml.swmat create mode 100644 ProjectsDir/TestAssets/material/no-MaterialAsset.swmat create mode 100644 ProjectsDir/TestAssets/material/no-gs-entry.swmat create mode 100644 ProjectsDir/TestAssets/material/no-header.swmat create mode 100644 ProjectsDir/TestAssets/material/no-ps.swmat create mode 100644 ProjectsDir/TestAssets/material/no-textures-entry.swmat create mode 100644 ProjectsDir/TestAssets/material/no-vs.swmat create mode 100644 ProjectsDir/TestAssets/material/not-existing-ps.swmat create mode 100644 ProjectsDir/TestAssets/material/not-existing-texture.swmat create mode 100644 ProjectsDir/TestAssets/material/not-existing-vs.swmat create mode 100644 ProjectsDir/TestAssets/material/single-texture-entry.swmat create mode 100644 ProjectsDir/TestAssets/mock/example.mock create mode 100644 ProjectsDir/TestAssets/mock/example1.mock create mode 100644 ProjectsDir/TestAssets/mock/example2.mock create mode 100644 ProjectsDir/TestAssets/mock/example3.mock create mode 100644 ProjectsDir/TestAssets/shaders/hlsl/MinimalShader.csh create mode 100644 ProjectsDir/TestAssets/shaders/hlsl/MinimalShader.psh create mode 100644 ProjectsDir/TestAssets/shaders/hlsl/MinimalShader.vsh create mode 100644 ProjectsDir/TestAssets/shaders/hlsl/NotCompiing.psh create mode 100644 ProjectsDir/TestAssets/shaders/hlsl/NotCompiling.csh create mode 100644 ProjectsDir/TestAssets/shaders/hlsl/NotCompiling.vsh create mode 100644 ProjectsDir/TestAssets/texture/big-lightweight.png create mode 100644 ProjectsDir/TestAssets/texture/random-pixels.bmp create mode 100644 ProjectsDir/TestAssets/texture/random-pixels.jpg create mode 100644 ProjectsDir/TestAssets/texture/random-pixels.png create mode 100644 ProjectsDir/Visual2015/MaterialAsset/MaterialAsset.vcxproj create mode 100644 ProjectsDir/Visual2015/MaterialAsset/MaterialAsset.vcxproj.filters create mode 100644 ProjectsDir/Visual2015/MaterialAsset/MaterialAssetConfig.props create mode 100644 ProjectsDir/Visual2015/MeshAsset/MeshAsset.vcxproj create mode 100644 ProjectsDir/Visual2015/MeshAsset/MeshAsset.vcxproj.filters create mode 100644 ProjectsDir/Visual2015/MeshAsset/MeshAssetConfig.props create mode 100644 ProjectsDir/Visual2015/MockAssets/MockAssets.vcxproj create mode 100644 ProjectsDir/Visual2015/MockAssets/MockAssets.vcxproj.filters create mode 100644 ProjectsDir/Visual2015/MockAssets/MockAssetsConfig.props create mode 100644 ProjectsDir/Visual2015/SoilTextureLoader/SoilTextureLoader.vcxproj create mode 100644 ProjectsDir/Visual2015/SoilTextureLoader/SoilTextureLoader.vcxproj.filters create mode 100644 ProjectsDir/Visual2015/SoilTextureLoader/SoilTextureLoaderConfig.props create mode 100644 ProjectsDir/Visual2015/Tests/TestMaterial/TestMaterial.vcxproj create mode 100644 ProjectsDir/Visual2015/Tests/TestMaterial/TestMaterial.vcxproj.filters create mode 100644 ProjectsDir/Visual2015/Tests/TestMipMapsGenerator/TestMipMapGenerator.vcxproj create mode 100644 ProjectsDir/Visual2015/Tests/TestResourceManager/TestResourceManager.vcxproj create mode 100644 ProjectsDir/Visual2015/Tests/TestResourceManager/TestResourceManager.vcxproj.filters create mode 100644 ProjectsDir/Visual2015/Tests/TestResources/TestResources.DX11.vcxproj.filters create mode 100644 ProjectsDir/Visual2015/Tests/TestSoilTextureLoader/TestSoilTextureLoader.DX11.vcxproj create mode 100644 ProjectsDir/Visual2015/Tests/TestSoilTextureLoader/TestSoilTextureLoader.DX11.vcxproj.filters create mode 100644 ProjectsDir/Visual2015/Tests/TestSoilTextureLoader/TestSoilTextureLoader.vcxproj create mode 100644 ProjectsDir/Visual2015/Tests/TestSoilTextureLoader/TestSoilTextureLoader.vcxproj.filters create mode 100644 ProjectsDir/Visual2015/swMaterialLoader/swMaterialLoader.vcxproj create mode 100644 ProjectsDir/Visual2015/swMaterialLoader/swMaterialLoader.vcxproj.filters create mode 100644 ProjectsDir/Visual2015/swMaterialLoader/swMaterialLoaderConfig.props create mode 100644 ResourceManager/AssetCreators/AssetsFactory.cpp create mode 100644 ResourceManager/AssetCreators/AssetsFactory.h create mode 100644 ResourceManager/AssetCreators/Buffers/BufferCreator.cpp create mode 100644 ResourceManager/AssetCreators/Buffers/BufferCreator.h create mode 100644 ResourceManager/AssetCreators/IAssetCreateInfo.h create mode 100644 ResourceManager/AssetCreators/IAssetCreator.h create mode 100644 ResourceManager/AssetCreators/PipelineStates/BlendingStateCreator.cpp create mode 100644 ResourceManager/AssetCreators/PipelineStates/BlendingStateCreator.h create mode 100644 ResourceManager/AssetCreators/PipelineStates/DepthStencilStateCreator.cpp create mode 100644 ResourceManager/AssetCreators/PipelineStates/DepthStencilStateCreator.h create mode 100644 ResourceManager/AssetCreators/PipelineStates/RasterizerStateCreator.cpp create mode 100644 ResourceManager/AssetCreators/PipelineStates/RasterizerStateCreator.h create mode 100644 ResourceManager/AssetCreators/Shaders/LayoutCreator.cpp create mode 100644 ResourceManager/AssetCreators/Shaders/LayoutCreator.h create mode 100644 ResourceManager/AssetCreators/Shaders/ShaderCreator.h create mode 100644 ResourceManager/AssetCreators/Shaders/ShaderCreator.inl create mode 100644 ResourceManager/AssetCreators/Textures/MipMapGenerator.cpp create mode 100644 ResourceManager/AssetCreators/Textures/MipMapGenerator.h create mode 100644 ResourceManager/AssetCreators/Textures/RenderTargetCreator.cpp create mode 100644 ResourceManager/AssetCreators/Textures/RenderTargetCreator.h create mode 100644 ResourceManager/AssetCreators/Textures/Resampler/resampler.cpp create mode 100644 ResourceManager/AssetCreators/Textures/Resampler/resampler.h create mode 100644 ResourceManager/AssetCreators/Textures/TextureCreator.cpp create mode 100644 ResourceManager/AssetCreators/Textures/TextureCreator.h create mode 100644 ResourceManager/AsyncLoad/AssetLoadRequest.h create mode 100644 ResourceManager/AsyncLoad/AssetLoadResponse.h create mode 100644 ResourceManager/AsyncLoad/AssetsThread.cpp create mode 100644 ResourceManager/AsyncLoad/AssetsThread.h create mode 100644 ResourceManager/AsyncLoad/LoadBarrier.cpp create mode 100644 ResourceManager/AsyncLoad/LoadBarrier.h create mode 100644 ResourceManager/AsyncLoad/RMAsyncThread.cpp create mode 100644 ResourceManager/AsyncLoad/RMAsyncThread.h create mode 100644 ResourceManager/Cache/CacheManager.cpp create mode 100644 ResourceManager/Cache/CacheManager.h create mode 100644 ResourceManager/Cache/IAssetCache.h create mode 100644 ResourceManager/Cache/MemoryCache.cpp create mode 100644 ResourceManager/Cache/MemoryCache.h create mode 100644 ResourceManager/Exceptions/LoaderException.cpp create mode 100644 ResourceManager/Exceptions/LoaderException.h create mode 100644 ResourceManager/Exceptions/ResourceManagerException.cpp create mode 100644 ResourceManager/Exceptions/ResourceManagerException.h create mode 100644 ResourceManager/Loaders/IAssetLoadInfo.h create mode 100644 ResourceManager/Loaders/IAssetLoader.h create mode 100644 ResourceManager/Loaders/LoadingResult.h create mode 100644 ResourceManager/Loaders/RMLoaderAPI.h create mode 100644 ResourceManager/Loaders/RenderTargetLoadInfo.h create mode 100644 ResourceManager/Loaders/RenderTargetLoader.cpp create mode 100644 ResourceManager/Loaders/RenderTargetLoader.h create mode 100644 ResourceManager/Loaders/ShaderLoader.cpp create mode 100644 ResourceManager/Loaders/ShaderLoader.h create mode 100644 ResourceManager/Loaders/TextureLoadInfo.h create mode 100644 ResourceManager/Loaders/Tools/CanLoad.h create mode 100644 ResourceManager/Loaders/Tools/LoadingContext.h create mode 100644 ResourceManager/PathTranslators/AssetPath.cpp create mode 100644 ResourceManager/PathTranslators/AssetPath.h create mode 100644 ResourceManager/PathTranslators/LoadPath.h create mode 100644 ResourceManager/PathTranslators/PathsManager.cpp create mode 100644 ResourceManager/PathTranslators/PathsManager.h create mode 100644 ResourceManager/ResourceManagerAPI.cpp create mode 100644 ResourceManager/ResourceManagerAPI.h create mode 100644 Resources/Buffers/Buffer.cpp create mode 100644 Resources/Buffers/Buffer.h rename Resources/{ => Buffers}/BufferInitData.h (61%) rename Resources/{ => Buffers}/IBuffer.h (82%) delete mode 100644 Resources/DepthStencilState.h delete mode 100644 Resources/IRenderTarget.h delete mode 100644 Resources/IShader.h delete mode 100644 Resources/IShaderInputLayout.h rename Resources/{ => PipelineStates}/BlendingState.h (55%) create mode 100644 Resources/PipelineStates/DepthStencilState.h rename Resources/{ => PipelineStates}/RasterizerState.h (54%) create mode 100644 Resources/Resource.cpp create mode 100644 Resources/Shaders/Exceptions/CompilationException.h create mode 100644 Resources/Shaders/IShader.h create mode 100644 Resources/Shaders/IShaderInputLayout.h create mode 100644 Resources/Shaders/InputLayout.h create mode 100644 Resources/Shaders/LayoutInitData.h create mode 100644 Resources/Shaders/Layouts.cpp create mode 100644 Resources/Shaders/ShaderInitData.h create mode 100644 Resources/Shaders/Shaders.cpp create mode 100644 Resources/Shaders/Shaders.h delete mode 100644 Resources/Texture.cpp delete mode 100644 Resources/Texture.h create mode 100644 Resources/Textures/IRenderTarget.h create mode 100644 Resources/Textures/RenderTarget.cpp create mode 100644 Resources/Textures/RenderTarget.h create mode 100644 Resources/Textures/Texture.cpp create mode 100644 Resources/Textures/Texture.h create mode 100644 Resources/Textures/TextureInitData.h create mode 100644 Tests/TestMaterial/TestCreation.cpp create mode 100644 Tests/TestMaterial/TestSWMaterialLoader.cpp create mode 100644 Tests/TestMaterial/TestSWMaterialSaver.cpp create mode 100644 Tests/TestMaterial/Utils.h create mode 100644 Tests/TestMaterial/main.cpp create mode 100644 Tests/TestMipMapGenerator/TestMipMaps.cpp create mode 100644 Tests/TestMipMapGenerator/main.cpp create mode 100644 Tests/TestResourceManager/LoadBarrierTest.cpp create mode 100644 Tests/TestResourceManager/TestAssetPath.cpp create mode 100644 Tests/TestResourceManager/TestAssetsFactory.cpp create mode 100644 Tests/TestResourceManager/TestCreators/TestBufferCreator.cpp create mode 100644 Tests/TestResourceManager/TestLoadPath.cpp create mode 100644 Tests/TestResourceManager/TestLoaders/TestRenderTargetLoader.cpp create mode 100644 Tests/TestResourceManager/TestLoaders/TestShaderLoader.cpp create mode 100644 Tests/TestResourceManager/TestLoadingResult.cpp create mode 100644 Tests/TestResourceManager/TestPathsManager.cpp create mode 100644 Tests/TestResourceManager/TestResourceManager/TestAssetsCreation.cpp create mode 100644 Tests/TestResourceManager/TestResourceManager/TestAssetsLoadingAsync.cpp create mode 100644 Tests/TestResourceManager/TestResourceManager/TestAssetsLoadingSync.cpp create mode 100644 Tests/TestResourceManager/TestResourceManager/TestAssetsRemoval.cpp create mode 100644 Tests/TestResourceManager/TestResourceManager/TestListAssets.cpp create mode 100644 Tests/TestResourceManager/TestResourceManager/TestLoaders.cpp create mode 100644 Tests/TestResourceManager/TestResourceManager/TestPathAliases.cpp create mode 100644 Tests/TestResourceManager/TestResourceManager/TestResourceManagerAPI.cpp create mode 100644 Tests/TestResourceManager/TestResourcePtr.cpp create mode 100644 Tests/TestResourceManager/Utils/Tests/TestMockCompositeAsset.cpp create mode 100644 Tests/TestResourceManager/main.cpp create mode 100644 Tests/TestResourceManager/stdafx.cpp create mode 100644 Tests/TestResourceManager/stdafx.h delete mode 100644 Tests/TestResources.DX11/GraphicAPI.h create mode 100644 Tests/TestResources.DX11/TestCreators/TestBlendingStateCreator.cpp create mode 100644 Tests/TestResources.DX11/TestCreators/TestBufferCreator.cpp create mode 100644 Tests/TestResources.DX11/TestCreators/TestDepthStencilStateCreator.cpp create mode 100644 Tests/TestResources.DX11/TestCreators/TestLayoutCreator.cpp create mode 100644 Tests/TestResources.DX11/TestCreators/TestRasterizerStateCreator.cpp create mode 100644 Tests/TestResources.DX11/TestCreators/TestRenderTargetCreator.cpp create mode 100644 Tests/TestResources.DX11/TestCreators/TestShaderCreator.cpp create mode 100644 Tests/TestResources.DX11/TestCreators/TestTextureCreator.cpp create mode 100644 Tests/TestResources.DX11/TestLoaders/TestRenderTargetLoader.cpp create mode 100644 Tests/TestResources.DX11/TestLoaders/TestShaderLoader.cpp create mode 100644 Tests/TestSoilTextureLoader.DX11/TestFilesLoading.cpp create mode 100644 Tests/TestSoilTextureLoader.DX11/TestMipMapGeneration.cpp create mode 100644 Tests/TestSoilTextureLoader.DX11/main.cpp create mode 100644 Tests/TestSoilTextureLoader/TestTextureLoading.cpp create mode 100644 Tests/TestSoilTextureLoader/main.cpp diff --git a/.gitignore b/.gitignore index 68a0be2..dd9249f 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ *.suo *.user *.sln.docstates +.vs # Build results @@ -17,6 +18,7 @@ build/ BuildDir/ LibDir/ ProjectDir/Documentation/ +ProjectsDir/Output/ diff --git a/Assets/MaterialAsset/MaterialAsset.cpp b/Assets/MaterialAsset/MaterialAsset.cpp new file mode 100644 index 0000000..3c7f648 --- /dev/null +++ b/Assets/MaterialAsset/MaterialAsset.cpp @@ -0,0 +1,76 @@ +/** +@file MaterialAsset.cpp +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + +#include "swGraphicAPI/Assets/MaterialAsset/stdafx.h" + +#include "MaterialAsset.h" + + + +RTTR_REGISTRATION +{ + rttr::registration::class_< std::vector< sw::ParametricBufferInfo > >( "ParametricBuffers" ); + + rttr::registration::class_< sw::ParametricBufferInfo >( "ParametricBufferInfo" ) + .property( "ShaderType", &sw::ParametricBufferInfo::ShaderType ) + .property( "BufferSize", &sw::ParametricBufferInfo::BufferSize ) + .property( "BufferType", &sw::ParametricBufferInfo::GetBufferType, &sw::ParametricBufferInfo::SetBufferType ); + + rttr::registration::class_< sw::MaterialInfo >( "MaterialInfo" ) + .property( "ParametricBuffers", &sw::MaterialInfo::ParametricBuffers ) + .property( "ShadingData", &sw::MaterialInfo::ShadingData ); + + rttr::registration::class_< sw::MaterialAsset >( "MaterialAsset" ) + .property( "VertexShader", &sw::MaterialAsset::m_vertexShader ) + .property( "PixelShader", &sw::MaterialAsset::m_pixelShader ) + .property( "GeometryShader", &sw::MaterialAsset::m_geometryShader ) + .property( "TesselationControlShader", &sw::MaterialAsset::m_controlShader ) + .property( "TesselationEvaluationShader", &sw::MaterialAsset::m_evaluationShader ) + .property_readonly( "DiffuseTexture", &sw::MaterialAsset::GetTexture1 ) + .property_readonly( "SpecularTexture", &sw::MaterialAsset::GetTexture2 ) + .property_readonly( "AmbientTexture", &sw::MaterialAsset::GetTexture3 ) + .property_readonly( "NormalMap", &sw::MaterialAsset::GetTexture4 ) + .property_readonly( "DisplacementMap", &sw::MaterialAsset::GetTexture5 ) + .property_readonly( "Texture6", &sw::MaterialAsset::GetTexture6 ) + .property_readonly( "Texture7", &sw::MaterialAsset::GetTexture7 ) + .property_readonly( "Texture8", &sw::MaterialAsset::GetTexture8 ) + //.property( "Textures", &MaterialAsset::m_textures ) + .property( "Descriptor", &sw::MaterialAsset::m_descriptor ) BIND_AS_PTR; + +} + + +namespace sw +{ + + +// ================================ // +// +MaterialAsset::MaterialAsset ( AssetPath path, MaterialInitData&& initData ) + : Resource( std::move( path ) ) + , m_materialBuffer( std::move( initData.MaterialBuffer ) ) + , m_vertexShader( std::move( initData.VertexShader ) ) + , m_pixelShader( std::move( initData.PixelShader ) ) + , m_geometryShader( std::move( initData.GeometryShader ) ) + , m_evaluationShader( std::move( initData.TesselationEvaluationShader ) ) + , m_controlShader( std::move( initData.TesselationControlShader ) ) + , m_descriptor( std::move( initData.AdditionalBuffers ), std::move( initData.ShadingData ) ) +{ + for( int i = 0; i < MAX_MATERIAL_TEXTURES; ++i ) + { + m_textures[ i ] = std::move( initData.Textures[ i ] ); + } +} + +// ================================ // +// +MaterialAsset::~MaterialAsset () +{} + + + +} // sw + diff --git a/Assets/MaterialAsset/MaterialAsset.h b/Assets/MaterialAsset/MaterialAsset.h new file mode 100644 index 0000000..a62f063 --- /dev/null +++ b/Assets/MaterialAsset/MaterialAsset.h @@ -0,0 +1,106 @@ +#pragma once +/** +@file MaterialAsset.h +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + + + +#include "swGraphicAPI/Resources/Textures/Texture.h" +#include "swGraphicAPI/Resources/Buffers/Buffer.h" + +#include "ShadingModelData.h" +#include "MaterialAssetInitData.h" +#include "MaterialInfo.h" + +#include + + +namespace sw +{ + + +/**@defgroup Assets Assets + +@brief High level engine resources. +*/ + + +/**@defgroup Materials Materials + +@brief Classes describing materials. + +Class @ref MaterialAsset is main material class used by engine. + +@ingroup Assets +*/ + + + + +/**@brief Class describes Material. + +Material consists of shaders that will be used to render scene element. +Only VertexShader and PixelShader fileds are necessary. GeometryShader will be used +only if it is set. Tesselation will be tuned on if both ControlsShader and EvaluationShader +will be present. + +Material has it's own buffer with shading parameters. It will be initialized with ShadingData +from MaterialInfo structure. There's only single Buffer per material instance. We can parametrize +Material by binding to shaders additional buffers with different parameters per scene entity. +To do this we should fill @ref MaterialInfo::ParametricBuffers field. + +@ingroup Assets +@ingroup Materials +*/ +class MaterialAsset : public Resource +{ + RTTR_ENABLE( Resource ); + RTTR_REGISTRATION_FRIEND; +private: + + BufferPtr m_materialBuffer; ///< GPU buffer containing material data. + VertexShaderPtr m_vertexShader; ///< Vertex shader. + PixelShaderPtr m_pixelShader; ///< Pixel shader. + TexturePtr m_textures[ MAX_MATERIAL_TEXTURES ]; ///< Textures set. + + GeometryShaderPtr m_geometryShader; ///< [Optional] Geometry shader. + ControlShaderPtr m_controlShader; ///< [Optional] Shader invoked before tesselation. + EvaluationShaderPtr m_evaluationShader; ///< [Optional] Shader invoked after tesselation. + + + MaterialInfo m_descriptor; ///< Material descriptor. + +public: + explicit MaterialAsset ( AssetPath filePath, MaterialInitData&& initData ); + +public: + + const BufferPtr& GetMaterialBuffer () const { return m_materialBuffer; } + const VertexShaderPtr& GetVertexShader () const { return m_vertexShader; } + const PixelShaderPtr& GetPixelShader () const { return m_pixelShader; } + const GeometryShaderPtr& GetGeometryShader () const { return m_geometryShader; } + const ControlShaderPtr& GetTessControlShader () const { return m_controlShader; } + const EvaluationShaderPtr& GetTessEvaluationShader () const { return m_evaluationShader; } + + const TexturePtr& GetTexture ( int index ) const { return m_textures[ index ]; } + const MaterialInfo& GetDescriptor () const { return m_descriptor; } + +private: + ~MaterialAsset(); + + // Temporary textures getters for properties. + Texture* GetTexture1() const { return m_textures[ 0 ].Ptr(); } + Texture* GetTexture2() const { return m_textures[ 1 ].Ptr(); } + Texture* GetTexture3() const { return m_textures[ 2 ].Ptr(); } + Texture* GetTexture4() const { return m_textures[ 3 ].Ptr(); } + Texture* GetTexture5() const { return m_textures[ 4 ].Ptr(); } + Texture* GetTexture6() const { return m_textures[ 5 ].Ptr(); } + Texture* GetTexture7() const { return m_textures[ 6 ].Ptr(); } + Texture* GetTexture8() const { return m_textures[ 7 ].Ptr(); } +}; + +DEFINE_RESOURCE_PTR_TYPE( MaterialAsset ); + +} // sw diff --git a/Assets/MaterialAsset/MaterialAssetInitData.cpp b/Assets/MaterialAsset/MaterialAssetInitData.cpp new file mode 100644 index 0000000..a4ec1f3 --- /dev/null +++ b/Assets/MaterialAsset/MaterialAssetInitData.cpp @@ -0,0 +1,58 @@ +/** +@file MaterialAssetInitData.cpp +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ +#include "swGraphicAPI/Assets/MaterialAsset/stdafx.h" + + +#include "MaterialAssetInitData.h" +#include "swGraphicAPI/Assets/MaterialAsset/MaterialAsset.h" + +#include "swGraphicAPI/ResourceManager/ResourceManager.h" +#include "swGraphicAPI/ResourceManager/ResourceManagerAPI.h" + + + +namespace sw +{ + +// ================================ // +// +ReturnResult MaterialInitData::AutoCreateBuffer ( const AssetPath& materialName, RMLoaderAPI& rmAPI ) +{ + if( ShadingData.get() != nullptr ) + { + BufferRange bufferInfo( ShadingData->GetData(), ShadingData->GetSize() ); + + auto result = rmAPI.CreateConstantsBuffer( DefaultBufferName( materialName ), + bufferInfo, + (uint32)ShadingData->GetSize(), + ShadingData->GetShadingModelType() ); + + if( result.IsValid() ) + { + this->MaterialBuffer = result.Get(); + return Result::Success; + } + else + { + return result.GetError(); + } + } + else + { + return "MaterialInitData.ShadingData was nullptr. Set ShadingModel struct before creating buffer."; + } +} + +// ================================ // +// +AssetPath MaterialInitData::DefaultBufferName ( const AssetPath& materialName ) const +{ + return AssetPath( materialName.GetFile(), materialName.GetInternalPath() / "buffer" ); +} + + +} // sw + diff --git a/Assets/MaterialAsset/MaterialAssetInitData.h b/Assets/MaterialAsset/MaterialAssetInitData.h new file mode 100644 index 0000000..9b204b5 --- /dev/null +++ b/Assets/MaterialAsset/MaterialAssetInitData.h @@ -0,0 +1,66 @@ +#pragma once +/** +@file MaterialAssetInitData.h +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + + +#include "swCommonLib/Common/TypesDefinitions.h" + +#include "swGraphicAPI/Resources/MeshResources.h" +#include "swGraphicAPI/ResourceManager/AssetCreators/IAssetCreateInfo.h" + +#include "ShadingModelData.h" +#include "MaterialInfo.h" + +#include + + +namespace sw +{ + +class MaterialAsset; +class ResourceManager; + + +/**@brief Struct contains data needed to initialize material. +@ingroup Materials*/ +struct MaterialInitData : public IAssetCreateInfo +{ + RTTR_ENABLE( IAssetCreateInfo ); +public: + BufferPtr MaterialBuffer; + VertexShaderPtr VertexShader; + PixelShaderPtr PixelShader; + GeometryShaderPtr GeometryShader; + ControlShaderPtr TesselationControlShader; + EvaluationShaderPtr TesselationEvaluationShader; + TexturePtr Textures[ MAX_MATERIAL_TEXTURES ]; + + std::vector< ParametricBufferInfo > AdditionalBuffers; ///< Additional buffers which should be provided by scene entity. + UPtr< ShadingModelBase > ShadingData; ///< Initializes buffer with shading model data. @see ShadingModelData + +public: + + // ================================ // + // + MaterialInitData () {} + +public: + + /**@brief Creates buffer using ShadingData.*/ + ReturnResult AutoCreateBuffer ( const AssetPath& materialName, RMLoaderAPI& rm ); + AssetPath DefaultBufferName ( const AssetPath& materialName ) const; + +public: + // ================================ // + // + virtual TypeID GetAssetType () const override { return TypeID::get< MaterialAsset >(); } +}; + + + + +} // sw + diff --git a/Assets/MaterialAsset/MaterialCreator.cpp b/Assets/MaterialAsset/MaterialCreator.cpp new file mode 100644 index 0000000..422ca1e --- /dev/null +++ b/Assets/MaterialAsset/MaterialCreator.cpp @@ -0,0 +1,85 @@ +/** +@file MaterialCreator.cpp +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + +#include "swGraphicAPI/Assets/MaterialAsset/stdafx.h" + +#include "MaterialCreator.h" +#include "MaterialAssetInitData.h" + +#include "swGraphicAPI/Resources/MeshResources.h" + + + +namespace sw +{ + +// ================================ // +// +Nullable< Resource* > MaterialCreator::Create ( const AssetPath& assetName, IAssetCreateInfo&& createInfo ) +{ + TypeID type = createInfo.get_type(); + if( type == TypeID::get< MaterialInitData >() ) + { + return new MaterialAsset( assetName, std::move( static_cast< MaterialInitData&& >( createInfo ) ) ); + } + + return "[MaterialCreator] IAssetCreateInfo of type [" + TypeID::get( createInfo ).get_name().to_string() + "] not supported."; +} + +// ================================ // +// +Nullable< Resource* > MaterialCreator::LoadFromRaw ( const AssetPath& assetName, const BufferRaw& rawData ) +{ + assert( !"Buffer is not cacheable" ); + return nullptr; +} + +// ================================ // +// +BufferRaw MaterialCreator::SaveToRaw ( const IAssetCreateInfo& createInfo ) +{ + assert( !"Buffer is not cacheable" ); + return BufferTyped< uint8 >::CreateEmpty(); +} + +// ================================ // +// +BufferRaw MaterialCreator::SaveToRaw ( ResourcePtr< Resource > resource ) +{ + assert( !"Buffer is not cacheable" ); + return BufferTyped< uint8 >::CreateEmpty(); +} + +// ================================ // +// +bool MaterialCreator::IsCacheable () const +{ + return false; +} + +// ================================ // +// +bool MaterialCreator::SupportsResourceToRaw () const +{ + return false; +} + +// ================================ // +// +TypeID MaterialCreator::GetAssetType () const +{ + return TypeID::get< MaterialAsset >(); +} + +// ================================ // +// +MaterialCreatorPtr MaterialCreator::CreateCreator () +{ + return std::make_shared< MaterialCreator >(); +} + + +} // sw diff --git a/Assets/MaterialAsset/MaterialCreator.h b/Assets/MaterialAsset/MaterialCreator.h new file mode 100644 index 0000000..b36c0c6 --- /dev/null +++ b/Assets/MaterialAsset/MaterialCreator.h @@ -0,0 +1,53 @@ +#pragma once +/** +@file MaterialCreator.h +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + +#include "swGraphicAPI/ResourceManager/AssetCreators/IAssetCreator.h" + +#include "MaterialAsset.h" + + +namespace sw +{ + +class MaterialCreator; +DEFINE_PTR_TYPE( MaterialCreator ); + + + +/**@brief Creates @ref MaterialAsset. +@ingroup AssetsCreators*/ +class MaterialCreator : public IAssetCreator +{ +private: +protected: +public: + explicit MaterialCreator () = default; + virtual ~MaterialCreator () = default; + + +public: + + virtual Nullable< Resource* > Create ( const AssetPath& assetName, IAssetCreateInfo&& createInfo ) override; + + virtual Nullable< Resource* > LoadFromRaw ( const AssetPath& assetName, const BufferRaw& rawData ) override; + virtual BufferRaw SaveToRaw ( const IAssetCreateInfo& createInfo ) override; + virtual BufferRaw SaveToRaw ( ResourcePtr< Resource > resource ) override; + + virtual bool IsCacheable () const override; + virtual bool SupportsResourceToRaw () const override; + virtual TypeID GetAssetType () const override; + +public: + + static MaterialCreatorPtr CreateCreator (); +}; + + + + +} // sw + diff --git a/Assets/MaterialAsset/MaterialInfo.h b/Assets/MaterialAsset/MaterialInfo.h new file mode 100644 index 0000000..4ded12a --- /dev/null +++ b/Assets/MaterialAsset/MaterialInfo.h @@ -0,0 +1,89 @@ +#pragma once +/** +@file MaterialInfo.h +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + + +#include "swCommonLib/Common/TypesDefinitions.h" +#include "swCommonLib/Common/Macros/GenerateOperators.h" + + +namespace sw +{ + +/// Maximal number of textures in material. +#define MAX_MATERIAL_TEXTURES 5 + + +/**@brief Structure describes additional buffers that must be provided for Material. +@ingroup Materials*/ +struct ParametricBufferInfo +{ + ShaderType ShaderType; ///< Shader that should have this buffer bound. + TypeID BufferType; ///< Type of buffer, which must be bound to material by actor. + uint32 BufferSize; ///< Buffer size in bytes. + + // ================================ // + // + ParametricBufferInfo() + : BufferType( rttr::type::get_by_name( "" ) ) + {} + + std::string GetBufferType () const { return BufferType.get_name().to_string(); } + void SetBufferType ( std::string name ); +}; + +GENERATE_EQUALITY_OPERATORS( ParametricBufferInfo, ShaderType, BufferType, BufferSize ); + + +/**@brief Material description. + +This structure describes parameters buffers, that this material requires. + +@ingroup Materials*/ +struct MaterialInfo +{ + std::vector< ParametricBufferInfo > ParametricBuffers; ///< Description of additional buffers that must be provided for this M ShadingData; ///< Stores shading model parameters. @see ShadingModelData + + + // ================================ // + // + MaterialInfo ( std::vector< ParametricBufferInfo >&& addBuff, UPtr< ShadingModelBase >&& shadModel ); + ~MaterialInfo (); +}; + + + +//====================================================================================// +// Implementation +//====================================================================================// + +// ================================ // +// +inline MaterialInfo::MaterialInfo ( std::vector< ParametricBufferInfo >&& addBuff, UPtr< ShadingModelBase >&& shadModel ) +{ + ParametricBuffers = std::move( addBuff ); + ShadingData = std::move( shadModel ); +} + +// ================================ // +// +inline MaterialInfo::~MaterialInfo () +{} + +// ================================ // +// +inline void ParametricBufferInfo::SetBufferType( std::string name ) +{ + auto newType = rttr::type::get( name ); + if( newType.is_valid() ) + BufferType = newType; +} + + + +} // sw + diff --git a/Assets/MaterialAsset/PhongMaterialData.h b/Assets/MaterialAsset/PhongMaterialData.h new file mode 100644 index 0000000..e53ecbc --- /dev/null +++ b/Assets/MaterialAsset/PhongMaterialData.h @@ -0,0 +1,64 @@ +#pragma once +/** +@file PhongMaterial.h +@author nieznanysprawiciel +@copyright File is part of graphic engine SWEngine. +*/ + + + +#include + + + +namespace sw +{ + +/**@brief Phong material buffer layout in @ref MaterialAsset. + +@ingroup Materials*/ +struct PhongMaterial +{ + DirectX::XMFLOAT4 Diffuse; + DirectX::XMFLOAT4 Ambient; + DirectX::XMFLOAT4 Specular; + DirectX::XMFLOAT3 Emissive; + float Power; + + // ================================ // + // + explicit PhongMaterial() + { SetNullMaterial(); } + + inline void SetNullMaterial(); +}; + + +/**@brief Sets the most neutral material values.*/ +inline void PhongMaterial::SetNullMaterial() +{ + Diffuse.x = 1.0f; + Diffuse.y = 1.0f; + Diffuse.z = 1.0f; + Diffuse.w = 1.0f; + + Ambient.x = 1.0f; + Ambient.y = 1.0f; + Ambient.z = 1.0f; + Ambient.w = 1.0f; + + Specular.x = 1.0f; + Specular.y = 1.0f; + Specular.z = 1.0f; + Specular.w = 1.0f; + + Emissive.x = 0.0f; + Emissive.y = 0.0f; + Emissive.z = 0.0f; + + Power = 1.0f; +} + + +} // sw + diff --git a/Assets/MaterialAsset/ShadingModelData.h b/Assets/MaterialAsset/ShadingModelData.h new file mode 100644 index 0000000..58c75a4 --- /dev/null +++ b/Assets/MaterialAsset/ShadingModelData.h @@ -0,0 +1,102 @@ +#pragma once +/** +@file ShadingModelData.h +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + + +#include "swCommonLib/Serialization/PropertySerialization/EngineObject.h" +#include "swCommonLib/Common/TypesDefinitions.h" +#include "swCommonLib/Common/RTTR.h" + + + +namespace sw +{ + + +/**@brief Base class for classes storing shading model parameters. + +@ingroup Materials*/ +class ShadingModelBase : public EngineObject +{ + RTTR_ENABLE( EngineObject ) +private: +public: + ShadingModelBase(); + + virtual Size GetSize () = 0; + virtual uint8* GetData () = 0; + virtual TypeID GetShadingModelType () = 0; + virtual TypeID GetShadingModelPtrType () = 0; + + + std::string GetShadingModelTypeName (); +}; + + +/**@brief Class wrapping shading model parameters and exposing raw buffer access +to them. + +@ingroup Materials*/ +template< typename ShadingModelStruct > +class ShadingModelData : public ShadingModelBase +{ + RTTR_ENABLE( ShadingModelBase ) +private: +public: + ShadingModelStruct Data; + +public: + explicit ShadingModelData (); + explicit ShadingModelData ( ShadingModelStruct model ); + + void StaticValidate (); + + + virtual Size GetSize () override { return sizeof( ShadingModelStruct ); } + virtual uint8* GetData () override { return reinterpret_cast( &Data ); } + virtual TypeID GetShadingModelType () override { return rttr::type::get< ShadingModelStruct >(); } + virtual TypeID GetShadingModelPtrType () override { return rttr::type::get< ShadingModelStruct* >(); } + + ShadingModelStruct& GetStruct () { return Data; } +}; + + +//====================================================================================// +// Inline definitions +//====================================================================================// + +// ================================ // +// +template< typename ShadingModelStruct > +inline void ShadingModelData< ShadingModelStruct >::StaticValidate () +{ + static_assert( std::is_default_constructible< ShadingModelStruct >::value, "Material data must be default constructible." ); + + // Constructor must be registered in rttr with AsRawPtr policy. + assert( TypeID::get< ShadingModelData< ShadingModelStruct > >().get_constructor().is_valid() ); + assert( TypeID::get< ShadingModelData< ShadingModelStruct > >().get_constructor().get_instantiated_type().is_pointer() ); + assert( TypeID::get< ShadingModelData< ShadingModelStruct > >().get_property( "Data" ).is_valid() ); +} + +// ================================ // +// +template< typename ShadingModelStruct > +inline ShadingModelData< ShadingModelStruct >::ShadingModelData () +{ + StaticValidate(); +} + +// ================================ // +// +template< typename ShadingModelStruct > +inline ShadingModelData< ShadingModelStruct >::ShadingModelData ( ShadingModelStruct model ) + : Data( model ) +{ + StaticValidate(); +} + +} // sw + diff --git a/Assets/MaterialAsset/ShadingModels.cpp b/Assets/MaterialAsset/ShadingModels.cpp new file mode 100644 index 0000000..3b05713 --- /dev/null +++ b/Assets/MaterialAsset/ShadingModels.cpp @@ -0,0 +1,55 @@ +/** +@file ShadingModels.cpp +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + + +#include "swGraphicAPI/Assets/MaterialAsset/stdafx.h" + +#include "swCommonLib/Common/RTTR.h" + +#include "ShadingModelData.h" +#include "PhongMaterialData.h" + +#include "swCommonLib/Common/MemoryLeaks.h" + + +RTTR_REGISTRATION +{ + rttr::registration::class_< sw::ShadingModelBase >( "ShadingModelBase" ) + .property_readonly( "TypeName", &sw::ShadingModelBase::GetShadingModelTypeName ); + + rttr::registration::class_< sw::PhongMaterial >( "PhongMaterial" ) + .property( "Diffuse", &sw::PhongMaterial::Diffuse ) BIND_AS_PTR + .property( "Specular", &sw::PhongMaterial::Specular ) BIND_AS_PTR + .property( "Emissive", &sw::PhongMaterial::Emissive ) BIND_AS_PTR + .property( "Ambient", &sw::PhongMaterial::Ambient ) BIND_AS_PTR + .property( "Power", &sw::PhongMaterial::Power ); + + rttr::registration::class_< sw::ShadingModelData< sw::PhongMaterial > >( "ShadingModelData< PhongMaterial >" ) + .constructor<>()( rttr::policy::ctor::as_raw_ptr ) + .property( "Data", &sw::ShadingModelData< sw::PhongMaterial >::Data ) BIND_AS_PTR; +} + + + + +namespace sw +{ + +// Note: There should be at least one function (or constructor) in this file. Otherwise compiler +//doesn't want to compile RTTR type registrations. + +ShadingModelBase::ShadingModelBase() +{} + + +// ================================ // +// +std::string ShadingModelBase::GetShadingModelTypeName () +{ + return GetShadingModelType().get_name().to_string(); +} + +} // sw diff --git a/Assets/MaterialAsset/stdafx.cpp b/Assets/MaterialAsset/stdafx.cpp new file mode 100644 index 0000000..8699da8 --- /dev/null +++ b/Assets/MaterialAsset/stdafx.cpp @@ -0,0 +1,9 @@ +// stdafx.cpp : source file that includes just the standard includes +// stdafx.obj will contain the pre-compiled type information + +#include "swGraphicAPI/Assets/MaterialAsset/stdafx.h" + + + +// TODO: reference any additional headers you need in STDAFX.H +// and not in this file diff --git a/Assets/MaterialAsset/stdafx.h b/Assets/MaterialAsset/stdafx.h new file mode 100644 index 0000000..755a57b --- /dev/null +++ b/Assets/MaterialAsset/stdafx.h @@ -0,0 +1,44 @@ +#pragma once +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently +// + + +/// @note You can disable all headers in precompiled header with one macro. +/// All cpp files should be precompiled header independet and explicitly include needed headers. +#ifndef DISABLE_PRECOMPILED_HEADER + + +#include + +#include +#include +#include + +#include + +#include "swCommonLib/Common/RTTR.h" + +#include "swGraphicAPI/Resources/MeshResources.h" +#include "swGraphicAPI/Resources/PipelineStates/BlendingState.h" +#include "swGraphicAPI/Resources/PipelineStates/DepthStencilState.h" +#include "swGraphicAPI/Resources/PipelineStates/RasterizerState.h" +#include "swGraphicAPI/Rendering/GraphicAPIConstants.h" +#include "swGraphicAPI/ResourceManager/ResourceManager.h" +#include "swGraphicAPI/Resources/ResourcesFactory.h" +#include "swGraphicAPI/Resources/SwapChain.h" + +#include "swCommonLib/System/File.h" +#include "swCommonLib/Common/Buffers/BufferTyped.h" + + + +#undef min +#undef max +#undef RegisterClass + + +#endif // !DISABLE_PRECOMPILED_HEADER + + diff --git a/Assets/MeshAsset/stdafx.cpp b/Assets/MeshAsset/stdafx.cpp new file mode 100644 index 0000000..7918fd6 --- /dev/null +++ b/Assets/MeshAsset/stdafx.cpp @@ -0,0 +1,9 @@ +// stdafx.cpp : source file that includes just the standard includes +// stdafx.obj will contain the pre-compiled type information + +#include "swGraphicAPI/Assets/MeshAsset/stdafx.h" + + + +// TODO: reference any additional headers you need in STDAFX.H +// and not in this file diff --git a/Assets/MeshAsset/stdafx.h b/Assets/MeshAsset/stdafx.h new file mode 100644 index 0000000..755a57b --- /dev/null +++ b/Assets/MeshAsset/stdafx.h @@ -0,0 +1,44 @@ +#pragma once +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently +// + + +/// @note You can disable all headers in precompiled header with one macro. +/// All cpp files should be precompiled header independet and explicitly include needed headers. +#ifndef DISABLE_PRECOMPILED_HEADER + + +#include + +#include +#include +#include + +#include + +#include "swCommonLib/Common/RTTR.h" + +#include "swGraphicAPI/Resources/MeshResources.h" +#include "swGraphicAPI/Resources/PipelineStates/BlendingState.h" +#include "swGraphicAPI/Resources/PipelineStates/DepthStencilState.h" +#include "swGraphicAPI/Resources/PipelineStates/RasterizerState.h" +#include "swGraphicAPI/Rendering/GraphicAPIConstants.h" +#include "swGraphicAPI/ResourceManager/ResourceManager.h" +#include "swGraphicAPI/Resources/ResourcesFactory.h" +#include "swGraphicAPI/Resources/SwapChain.h" + +#include "swCommonLib/System/File.h" +#include "swCommonLib/Common/Buffers/BufferTyped.h" + + + +#undef min +#undef max +#undef RegisterClass + + +#endif // !DISABLE_PRECOMPILED_HEADER + + diff --git a/DX11API/DX11Initializer/DX11APIObjects.cpp b/DX11API/DX11Initializer/DX11APIObjects.cpp index ae25501..996f411 100644 --- a/DX11API/DX11Initializer/DX11APIObjects.cpp +++ b/DX11API/DX11Initializer/DX11APIObjects.cpp @@ -1,8 +1,9 @@ /** @file DX11APIObjects.cpp @author nieznanysprawiciel -@copyright File is part of graphic engine SWEngine. +@copyright File is part of Sleeping Wombat Libraries. */ + #include "swGraphicAPI/DX11API/stdafx.h" @@ -13,6 +14,11 @@ #include "swCommonLib/Common/MemoryLeaks.h" + +namespace sw +{ + + //----------------------------------------------------------------------------------------------// // Zmienne statyczne klasy // //----------------------------------------------------------------------------------------------// @@ -24,6 +30,7 @@ DX11APIObjects* DX11APIObjects::this_ptr = nullptr; bool DX11APIObjects::m_useDebugLayer = false; +DX11DebugLayer DX11APIObjects::m_debugLayer; //Zmienne globalne dla funkcji D3D11_VIEWPORT DX11APIObjects::_view_port_desc; //Domy�lny viewport. Je�eli uzytkownik poda w�asny to zostanie on nadpisany. @@ -107,15 +114,15 @@ ARRAYSIZE( vertex_normal_color ) }; DX11APIObjects::DX11APIObjects() { // Inicjalizujemy tylko wtedy, kiedy wcze�niej si� to nie sta�o. - if ( this_ptr == nullptr ) + if( this_ptr == nullptr ) { this_ptr = this; _window_width = 1024; _window_height = 768; - _vertex_layout_desc = layouts[0]; - _layout_elements_count = layouts_elements[0]; + _vertex_layout_desc = layouts[ 0 ]; + _layout_elements_count = layouts_elements[ 0 ]; // DXGI_SWAP_CHAIN_DESC ZeroMemory( &_swap_chain_desc, sizeof( _swap_chain_desc ) ); @@ -197,27 +204,27 @@ void DX11APIObjects::release_DirectX() // Bardzo wa�ne jest ustawienie zmiennych na nullptr w razie, gdyby jaka� inna klasa wywo�ywa�a destruktor //Zmienne pomocnicze - if ( default_sampler ) + if( default_sampler ) default_sampler->Release(), default_sampler = nullptr; - if ( swap_chain ) + if( swap_chain ) //DirectX nie potrafi si� zamkn�� w trybie pe�noekranowym, wi�c musimy go zmieni� swap_chain->SetFullscreenState( FALSE, NULL ); //Zmienne s�u��ce do wy�wietlania - if ( z_buffer_view ) + if( z_buffer_view ) z_buffer_view->Release(), z_buffer_view = nullptr; - if ( swap_chain ) + if( swap_chain ) swap_chain->Release(), swap_chain = nullptr; - if ( render_target ) + if( render_target ) render_target->Release(), render_target = nullptr; if( back_buffer ) back_buffer->Release(), back_buffer = nullptr; if( z_buffer ) z_buffer->Release(), z_buffer = nullptr; - if ( device_context ) + if( device_context ) device_context->Release(), device_context = nullptr; - if ( device ) + if( device ) device->Release(), device = nullptr; if( IsDebugLayerEnabled() ) @@ -257,8 +264,8 @@ void DX11APIObjects::set_viewport_desc( const D3D11_VIEWPORT& view_port_desc ) { _view_port_desc = view_port_desc; - _view_port_desc.Height = static_cast(_window_height); - _view_port_desc.Width = static_cast(_window_width); + _view_port_desc.Height = static_cast( _window_height ); + _view_port_desc.Width = static_cast( _window_width ); } /**@brief ustawia podan� w parametrze tablic� z levelami. @@ -293,8 +300,8 @@ void DX11APIObjects::set_window_resolution( unsigned int window_width, unsigned _swap_chain_desc.BufferDesc.Height = _window_height; // D3D11_VIEWPORT - _view_port_desc.Height = static_cast(_window_height); - _view_port_desc.Width = static_cast(_window_width); + _view_port_desc.Height = static_cast( _window_height ); + _view_port_desc.Width = static_cast( _window_width ); // D3D11_TEXTURE2D_DESC Z-Buffer _z_buffer_desc.Height = _window_height; @@ -314,8 +321,8 @@ void DX11APIObjects::set_depth_stencil_format( DXGI_FORMAT depth_stencil_format i by� zmiennymi globalnymi w przeciwnym razie moga byc wycieki pam�ci.*/ void DX11APIObjects::set_vertex_layout( DX11_DEFAULT_VERTEX_LAYOUT layout ) { - _vertex_layout_desc = layouts[static_cast(layout)]; - _layout_elements_count = layouts_elements[static_cast(layout)]; + _vertex_layout_desc = layouts[ static_cast( layout ) ]; + _layout_elements_count = layouts_elements[ static_cast( layout ) ]; } /**@brief Ustawia podany deskryptor layoutu. @@ -365,15 +372,15 @@ DX11_INIT_RESULT DX11APIObjects::init_DX11( int width, int height, HWND window, _swap_chain_desc.OutputWindow = window; result = InitDevicesAndSwapChain( window, fullscreen, singleThread ); // Funkcja sama sprz�ta po sobie - if ( result != DX11_INIT_OK ) + if( result != DX11_INIT_OK ) return result; result = init_z_buffer_and_render_target(); // Funkcja sama sprz�ta po sobie - if ( result != DX11_INIT_OK ) + if( result != DX11_INIT_OK ) return result; result = init_viewport(); // Funkcja nie sprz�ta, bo by� mo�e nie ma czego, je�eli si� nie uda�o. - if ( result != DX11_INIT_OK ) + if( result != DX11_INIT_OK ) { release_DirectX(); // Sprz�tamy na wszelki wypadek, ale w gruncie rzeczy najprawdopodobniej nie ma czego. return result; @@ -397,7 +404,7 @@ DX11_INIT_RESULT DX11APIObjects::init_DX11( int width, int height, HWND window, @return Zwraca jedn� z warto�ci DX11_INIT_RESULT.*/ DX11_INIT_RESULT DX11APIObjects::InitDevicesAndSwapChain( HWND window, bool fullscreen, bool single_thread ) { - if ( !this_ptr ) + if( !this_ptr ) return NO_CLASS_INHERTIS_THIS_INTERFACE; HRESULT result = S_OK; @@ -408,7 +415,7 @@ DX11_INIT_RESULT DX11APIObjects::InitDevicesAndSwapChain( HWND window, bool full createDeviceFlags |= D3D11_CREATE_DEVICE_DEBUG; } - if ( single_thread ) + if( single_thread ) // Domy�lnie obiekt ID3D11Device jest synchronizowany, ale mo�na to wy��czy� createDeviceFlags |= D3D11_CREATE_DEVICE_SINGLETHREADED; @@ -417,10 +424,10 @@ DX11_INIT_RESULT DX11APIObjects::InitDevicesAndSwapChain( HWND window, bool full createDeviceFlags, _feature_levels, _num_feature_levels, D3D11_SDK_VERSION, &_swap_chain_desc, &swap_chain, &device, &_current_feature_level, &device_context ); - if ( FAILED( result ) ) + if( FAILED( result ) ) return COULD_NOT_INIT_DEVICES_AND_SWAPCHAIN; - if ( fullscreen ) + if( fullscreen ) swap_chain->SetFullscreenState( TRUE, nullptr ); if( m_useDebugLayer ) @@ -436,7 +443,7 @@ DX11_INIT_RESULT DX11APIObjects::InitDevicesAndSwapChain( HWND window, bool full /**@brief Ustawia viewport zgodny z aktualnie ustawionym deskryptorem.*/ DX11_INIT_RESULT DX11APIObjects::init_viewport() { - if ( !device ) + if( !device ) return DX11_DEVICE_NOT_INITIALIZED; device_context->RSSetViewports( 1, &_view_port_desc ); //tworzymy tylko jeden viewport, ale noramlnie mo�na wiecej, tylko po co return DX11_INIT_OK; @@ -450,21 +457,21 @@ DX11_INIT_RESULT DX11APIObjects::init_viewport() DX11_INIT_RESULT DX11APIObjects::init_z_buffer_and_render_target() { HRESULT result = S_OK; - if ( !device ) + if( !device ) return DX11_DEVICE_NOT_INITIALIZED; // RenderTargetView // Tworzymy RenderTargetView. W tym celu pobieramy wska�nik na obiekt tylniego bufora // i tworzymy z niego widok. - result = swap_chain->GetBuffer( 0, __uuidof(ID3D11Texture2D), (LPVOID*)&back_buffer ); - if ( FAILED( result ) ) + result = swap_chain->GetBuffer( 0, __uuidof( ID3D11Texture2D ), (LPVOID*)&back_buffer ); + if( FAILED( result ) ) { release_DirectX(); return COULD_NOT_CREATE_BACKBUFFER; } result = device->CreateRenderTargetView( back_buffer, nullptr, &render_target ); - if ( FAILED( result ) ) + if( FAILED( result ) ) { release_DirectX(); return COULD_NOT_CREATE_RENDERTARGET; @@ -476,7 +483,7 @@ DX11_INIT_RESULT DX11APIObjects::init_z_buffer_and_render_target() result = device->CreateTexture2D( &_z_buffer_desc, nullptr, &z_buffer ); - if ( FAILED( result ) ) + if( FAILED( result ) ) { release_DirectX(); return COULD_NOT_CREATE_DEPTHSTENCIL; @@ -487,7 +494,7 @@ DX11_INIT_RESULT DX11APIObjects::init_z_buffer_and_render_target() z_buffer->Release(); z_buffer = nullptr; - if ( FAILED( result ) ) + if( FAILED( result ) ) { release_DirectX(); return COULD_NOT_CREATE_DEPTHSTENCIL_VIEW; @@ -505,7 +512,7 @@ DX11_INIT_RESULT DX11APIObjects::init_sampler() { HRESULT result = device->CreateSamplerState( &_sampler_desc, &default_sampler ); - if ( FAILED( result ) ) + if( FAILED( result ) ) return COULD_NOT_CREATE_SAMPLER; device_context->PSSetSamplers( 0, 1, &default_sampler ); @@ -525,7 +532,7 @@ DX11_INIT_RESULT DX11APIObjects::init_sampler() void DX11APIObjects::begin_scene() { //Bufor tylny - float ClearColor[4] = { 0.0f, 0.0f, 0.0f, 1.0f }; // red, green, blue, alpha + float ClearColor[ 4 ] = { 0.0f, 0.0f, 0.0f, 1.0f }; // red, green, blue, alpha device_context->ClearRenderTargetView( render_target, ClearColor ); //Z-bufor @@ -536,10 +543,7 @@ void DX11APIObjects::begin_scene() // void DX11APIObjects::SetDebugName ( ID3D11DeviceChild* child, const std::string& name ) { - if( child != nullptr ) - { - child->SetPrivateData( WKPDID_D3DDebugObjectName, (uint32)name.size(), name.c_str() ); - } + m_debugLayer.SetDebugName( child, name ); } // ================================ // @@ -568,16 +572,16 @@ void DX11AuxiliaryObjects::init_buffers( unsigned int size_per_frame, unsigned i // Bufory sta�ych musz� mie� rozmiar b�d�cy wielokrotno�ci� 16 // Dobrze �e DirectX wypluwa jakie� debugowe informacje, bo nie wiem, jakbym na to wpad� - if ( size_per_frame % 16 ) + if( size_per_frame % 16 ) { size_per_frame = size_per_frame >> 4; // Dzielimy na 16 (dzielenie ca�kowite) - size_per_frame = (size_per_frame + 1) << 4; // Najbli�sza wielokrotno�� 16 + size_per_frame = ( size_per_frame + 1 ) << 4; // Najbli�sza wielokrotno�� 16 } - if ( size_per_mesh % 16 ) + if( size_per_mesh % 16 ) { size_per_mesh = size_per_mesh >> 4; // Dzielimy na 16 (dzielenie ca�kowite) - size_per_mesh = (size_per_mesh + 1) << 4; // Najbli�sza wielokrotno�� 16 + size_per_mesh = ( size_per_mesh + 1 ) << 4; // Najbli�sza wielokrotno�� 16 } // Tworzymy bufor sta�ych w ka�dej ramce @@ -640,15 +644,19 @@ void DX11AuxiliaryObjects::init_depth_states() zwolni� wszystkie obiekty, kt�re istniej�.*/ void DX11AuxiliaryObjects::release_DirectX() { - if ( const_per_frame ) + if( const_per_frame ) const_per_frame->Release(), const_per_frame = nullptr; - if ( const_per_mesh ) + if( const_per_mesh ) const_per_mesh->Release(), const_per_mesh = nullptr; - if ( depth_enabled ) + if( depth_enabled ) depth_enabled->Release(); - if ( depth_disabled ) + if( depth_disabled ) depth_disabled->Release(); // Zwalniamy te� wszystkie obiekty, kt�re zwalnia�a klasa bazowa DX11APIObjects::release_DirectX(); } + +} // sw + + diff --git a/DX11API/DX11Initializer/DX11APIObjects.h b/DX11API/DX11Initializer/DX11APIObjects.h index c58507b..23be79d 100644 --- a/DX11API/DX11Initializer/DX11APIObjects.h +++ b/DX11API/DX11Initializer/DX11APIObjects.h @@ -1,13 +1,12 @@ #pragma once - -/**@file DX11APIObjects.h +/** +@file DX11APIObjects.h @author nieznanysprawiciel -@copyright Plik jest cz�ci� silnika graficznego SWEngine. - -@brief Zawiera deklaracj� klasy DX11APIObjects i DX11AuxiliaryObjects s�u��cych do -inicjowania i przechowywania obiekt�w DirectXa. +@copyright File is part of Sleeping Wombat Libraries. */ + + #include #pragma warning( disable : 4005 ) @@ -16,6 +15,13 @@ #pragma warning( default : 4005 ) +#include "DX11DebugLayer.h" + + +namespace sw +{ + + typedef ID3D11DeviceContext DeviceContext; typedef ID3D11Device Device; @@ -66,7 +72,12 @@ class DX11APIObjects protected: static DX11APIObjects* this_ptr; ///( i ); + return static_cast( i ); } return ResourceFormat::RESOURCE_FORMAT_UNKNOWN; @@ -356,157 +363,160 @@ size_t DX11ConstantsMapper::BitsPerPixel( DXGI_FORMAT fmt ) { switch( fmt ) { - case DXGI_FORMAT_R32G32B32A32_TYPELESS: - case DXGI_FORMAT_R32G32B32A32_FLOAT: - case DXGI_FORMAT_R32G32B32A32_UINT: - case DXGI_FORMAT_R32G32B32A32_SINT: - return 128; - - case DXGI_FORMAT_R32G32B32_TYPELESS: - case DXGI_FORMAT_R32G32B32_FLOAT: - case DXGI_FORMAT_R32G32B32_UINT: - case DXGI_FORMAT_R32G32B32_SINT: - return 96; - - case DXGI_FORMAT_R16G16B16A16_TYPELESS: - case DXGI_FORMAT_R16G16B16A16_FLOAT: - case DXGI_FORMAT_R16G16B16A16_UNORM: - case DXGI_FORMAT_R16G16B16A16_UINT: - case DXGI_FORMAT_R16G16B16A16_SNORM: - case DXGI_FORMAT_R16G16B16A16_SINT: - case DXGI_FORMAT_R32G32_TYPELESS: - case DXGI_FORMAT_R32G32_FLOAT: - case DXGI_FORMAT_R32G32_UINT: - case DXGI_FORMAT_R32G32_SINT: - case DXGI_FORMAT_R32G8X24_TYPELESS: - case DXGI_FORMAT_D32_FLOAT_S8X24_UINT: - case DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS: - case DXGI_FORMAT_X32_TYPELESS_G8X24_UINT: - //case DXGI_FORMAT_Y416: - //case DXGI_FORMAT_Y210: - //case DXGI_FORMAT_Y216: - return 64; - - case DXGI_FORMAT_R10G10B10A2_TYPELESS: - case DXGI_FORMAT_R10G10B10A2_UNORM: - case DXGI_FORMAT_R10G10B10A2_UINT: - case DXGI_FORMAT_R11G11B10_FLOAT: - case DXGI_FORMAT_R8G8B8A8_TYPELESS: - case DXGI_FORMAT_R8G8B8A8_UNORM: - case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: - case DXGI_FORMAT_R8G8B8A8_UINT: - case DXGI_FORMAT_R8G8B8A8_SNORM: - case DXGI_FORMAT_R8G8B8A8_SINT: - case DXGI_FORMAT_R16G16_TYPELESS: - case DXGI_FORMAT_R16G16_FLOAT: - case DXGI_FORMAT_R16G16_UNORM: - case DXGI_FORMAT_R16G16_UINT: - case DXGI_FORMAT_R16G16_SNORM: - case DXGI_FORMAT_R16G16_SINT: - case DXGI_FORMAT_R32_TYPELESS: - case DXGI_FORMAT_D32_FLOAT: - case DXGI_FORMAT_R32_FLOAT: - case DXGI_FORMAT_R32_UINT: - case DXGI_FORMAT_R32_SINT: - case DXGI_FORMAT_R24G8_TYPELESS: - case DXGI_FORMAT_D24_UNORM_S8_UINT: - case DXGI_FORMAT_R24_UNORM_X8_TYPELESS: - case DXGI_FORMAT_X24_TYPELESS_G8_UINT: - case DXGI_FORMAT_R9G9B9E5_SHAREDEXP: - case DXGI_FORMAT_R8G8_B8G8_UNORM: - case DXGI_FORMAT_G8R8_G8B8_UNORM: - case DXGI_FORMAT_B8G8R8A8_UNORM: - case DXGI_FORMAT_B8G8R8X8_UNORM: - case DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM: - case DXGI_FORMAT_B8G8R8A8_TYPELESS: - case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB: - case DXGI_FORMAT_B8G8R8X8_TYPELESS: - case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB: - //case DXGI_FORMAT_AYUV: - //case DXGI_FORMAT_Y410: - //case DXGI_FORMAT_YUY2: - return 32; - - //case DXGI_FORMAT_P010: - //case DXGI_FORMAT_P016: - //return 24; - - case DXGI_FORMAT_R8G8_TYPELESS: - case DXGI_FORMAT_R8G8_UNORM: - case DXGI_FORMAT_R8G8_UINT: - case DXGI_FORMAT_R8G8_SNORM: - case DXGI_FORMAT_R8G8_SINT: - case DXGI_FORMAT_R16_TYPELESS: - case DXGI_FORMAT_R16_FLOAT: - case DXGI_FORMAT_D16_UNORM: - case DXGI_FORMAT_R16_UNORM: - case DXGI_FORMAT_R16_UINT: - case DXGI_FORMAT_R16_SNORM: - case DXGI_FORMAT_R16_SINT: - case DXGI_FORMAT_B5G6R5_UNORM: - case DXGI_FORMAT_B5G5R5A1_UNORM: - //case DXGI_FORMAT_A8P8: - //case DXGI_FORMAT_B4G4R4A4_UNORM: - return 16; - - //case DXGI_FORMAT_NV12: - //case DXGI_FORMAT_420_OPAQUE: - //case DXGI_FORMAT_NV11: - return 12; - - case DXGI_FORMAT_R8_TYPELESS: - case DXGI_FORMAT_R8_UNORM: - case DXGI_FORMAT_R8_UINT: - case DXGI_FORMAT_R8_SNORM: - case DXGI_FORMAT_R8_SINT: - case DXGI_FORMAT_A8_UNORM: - //case DXGI_FORMAT_AI44: - //case DXGI_FORMAT_IA44: - //case DXGI_FORMAT_P8: - return 8; - - case DXGI_FORMAT_R1_UNORM: - return 1; - - case DXGI_FORMAT_BC1_TYPELESS: - case DXGI_FORMAT_BC1_UNORM: - case DXGI_FORMAT_BC1_UNORM_SRGB: - case DXGI_FORMAT_BC4_TYPELESS: - case DXGI_FORMAT_BC4_UNORM: - case DXGI_FORMAT_BC4_SNORM: - return 4; - - case DXGI_FORMAT_BC2_TYPELESS: - case DXGI_FORMAT_BC2_UNORM: - case DXGI_FORMAT_BC2_UNORM_SRGB: - case DXGI_FORMAT_BC3_TYPELESS: - case DXGI_FORMAT_BC3_UNORM: - case DXGI_FORMAT_BC3_UNORM_SRGB: - case DXGI_FORMAT_BC5_TYPELESS: - case DXGI_FORMAT_BC5_UNORM: - case DXGI_FORMAT_BC5_SNORM: - case DXGI_FORMAT_BC6H_TYPELESS: - case DXGI_FORMAT_BC6H_UF16: - case DXGI_FORMAT_BC6H_SF16: - case DXGI_FORMAT_BC7_TYPELESS: - case DXGI_FORMAT_BC7_UNORM: - case DXGI_FORMAT_BC7_UNORM_SRGB: - return 8; + case DXGI_FORMAT_R32G32B32A32_TYPELESS: + case DXGI_FORMAT_R32G32B32A32_FLOAT: + case DXGI_FORMAT_R32G32B32A32_UINT: + case DXGI_FORMAT_R32G32B32A32_SINT: + return 128; + + case DXGI_FORMAT_R32G32B32_TYPELESS: + case DXGI_FORMAT_R32G32B32_FLOAT: + case DXGI_FORMAT_R32G32B32_UINT: + case DXGI_FORMAT_R32G32B32_SINT: + return 96; + + case DXGI_FORMAT_R16G16B16A16_TYPELESS: + case DXGI_FORMAT_R16G16B16A16_FLOAT: + case DXGI_FORMAT_R16G16B16A16_UNORM: + case DXGI_FORMAT_R16G16B16A16_UINT: + case DXGI_FORMAT_R16G16B16A16_SNORM: + case DXGI_FORMAT_R16G16B16A16_SINT: + case DXGI_FORMAT_R32G32_TYPELESS: + case DXGI_FORMAT_R32G32_FLOAT: + case DXGI_FORMAT_R32G32_UINT: + case DXGI_FORMAT_R32G32_SINT: + case DXGI_FORMAT_R32G8X24_TYPELESS: + case DXGI_FORMAT_D32_FLOAT_S8X24_UINT: + case DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS: + case DXGI_FORMAT_X32_TYPELESS_G8X24_UINT: + //case DXGI_FORMAT_Y416: + //case DXGI_FORMAT_Y210: + //case DXGI_FORMAT_Y216: + return 64; + + case DXGI_FORMAT_R10G10B10A2_TYPELESS: + case DXGI_FORMAT_R10G10B10A2_UNORM: + case DXGI_FORMAT_R10G10B10A2_UINT: + case DXGI_FORMAT_R11G11B10_FLOAT: + case DXGI_FORMAT_R8G8B8A8_TYPELESS: + case DXGI_FORMAT_R8G8B8A8_UNORM: + case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: + case DXGI_FORMAT_R8G8B8A8_UINT: + case DXGI_FORMAT_R8G8B8A8_SNORM: + case DXGI_FORMAT_R8G8B8A8_SINT: + case DXGI_FORMAT_R16G16_TYPELESS: + case DXGI_FORMAT_R16G16_FLOAT: + case DXGI_FORMAT_R16G16_UNORM: + case DXGI_FORMAT_R16G16_UINT: + case DXGI_FORMAT_R16G16_SNORM: + case DXGI_FORMAT_R16G16_SINT: + case DXGI_FORMAT_R32_TYPELESS: + case DXGI_FORMAT_D32_FLOAT: + case DXGI_FORMAT_R32_FLOAT: + case DXGI_FORMAT_R32_UINT: + case DXGI_FORMAT_R32_SINT: + case DXGI_FORMAT_R24G8_TYPELESS: + case DXGI_FORMAT_D24_UNORM_S8_UINT: + case DXGI_FORMAT_R24_UNORM_X8_TYPELESS: + case DXGI_FORMAT_X24_TYPELESS_G8_UINT: + case DXGI_FORMAT_R9G9B9E5_SHAREDEXP: + case DXGI_FORMAT_R8G8_B8G8_UNORM: + case DXGI_FORMAT_G8R8_G8B8_UNORM: + case DXGI_FORMAT_B8G8R8A8_UNORM: + case DXGI_FORMAT_B8G8R8X8_UNORM: + case DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM: + case DXGI_FORMAT_B8G8R8A8_TYPELESS: + case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB: + case DXGI_FORMAT_B8G8R8X8_TYPELESS: + case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB: + //case DXGI_FORMAT_AYUV: + //case DXGI_FORMAT_Y410: + //case DXGI_FORMAT_YUY2: + return 32; + + //case DXGI_FORMAT_P010: + //case DXGI_FORMAT_P016: + //return 24; + + case DXGI_FORMAT_R8G8_TYPELESS: + case DXGI_FORMAT_R8G8_UNORM: + case DXGI_FORMAT_R8G8_UINT: + case DXGI_FORMAT_R8G8_SNORM: + case DXGI_FORMAT_R8G8_SINT: + case DXGI_FORMAT_R16_TYPELESS: + case DXGI_FORMAT_R16_FLOAT: + case DXGI_FORMAT_D16_UNORM: + case DXGI_FORMAT_R16_UNORM: + case DXGI_FORMAT_R16_UINT: + case DXGI_FORMAT_R16_SNORM: + case DXGI_FORMAT_R16_SINT: + case DXGI_FORMAT_B5G6R5_UNORM: + case DXGI_FORMAT_B5G5R5A1_UNORM: + //case DXGI_FORMAT_A8P8: + //case DXGI_FORMAT_B4G4R4A4_UNORM: + return 16; + + //case DXGI_FORMAT_NV12: + //case DXGI_FORMAT_420_OPAQUE: + //case DXGI_FORMAT_NV11: + return 12; + + case DXGI_FORMAT_R8_TYPELESS: + case DXGI_FORMAT_R8_UNORM: + case DXGI_FORMAT_R8_UINT: + case DXGI_FORMAT_R8_SNORM: + case DXGI_FORMAT_R8_SINT: + case DXGI_FORMAT_A8_UNORM: + //case DXGI_FORMAT_AI44: + //case DXGI_FORMAT_IA44: + //case DXGI_FORMAT_P8: + return 8; + + case DXGI_FORMAT_R1_UNORM: + return 1; + + case DXGI_FORMAT_BC1_TYPELESS: + case DXGI_FORMAT_BC1_UNORM: + case DXGI_FORMAT_BC1_UNORM_SRGB: + case DXGI_FORMAT_BC4_TYPELESS: + case DXGI_FORMAT_BC4_UNORM: + case DXGI_FORMAT_BC4_SNORM: + return 4; + + case DXGI_FORMAT_BC2_TYPELESS: + case DXGI_FORMAT_BC2_UNORM: + case DXGI_FORMAT_BC2_UNORM_SRGB: + case DXGI_FORMAT_BC3_TYPELESS: + case DXGI_FORMAT_BC3_UNORM: + case DXGI_FORMAT_BC3_UNORM_SRGB: + case DXGI_FORMAT_BC5_TYPELESS: + case DXGI_FORMAT_BC5_UNORM: + case DXGI_FORMAT_BC5_SNORM: + case DXGI_FORMAT_BC6H_TYPELESS: + case DXGI_FORMAT_BC6H_UF16: + case DXGI_FORMAT_BC6H_SF16: + case DXGI_FORMAT_BC7_TYPELESS: + case DXGI_FORMAT_BC7_UNORM: + case DXGI_FORMAT_BC7_UNORM_SRGB: + return 8; #if defined(_XBOX_ONE) && defined(_TITLE) - case DXGI_FORMAT_R10G10B10_7E3_A2_FLOAT: - case DXGI_FORMAT_R10G10B10_6E4_A2_FLOAT: - return 32; + case DXGI_FORMAT_R10G10B10_7E3_A2_FLOAT: + case DXGI_FORMAT_R10G10B10_6E4_A2_FLOAT: + return 32; - case DXGI_FORMAT_D16_UNORM_S8_UINT: - case DXGI_FORMAT_R16_UNORM_X8_TYPELESS: - case DXGI_FORMAT_X16_TYPELESS_G8_UINT: - return 24; + case DXGI_FORMAT_D16_UNORM_S8_UINT: + case DXGI_FORMAT_R16_UNORM_X8_TYPELESS: + case DXGI_FORMAT_X16_TYPELESS_G8_UINT: + return 24; #endif // _XBOX_ONE && _TITLE - default: - return 0; + default: + return 0; } } + +} // sw + diff --git a/DX11API/DX11Initializer/DX11ConstantsMapper.h b/DX11API/DX11Initializer/DX11ConstantsMapper.h index ccee28d..a4b1d0c 100644 --- a/DX11API/DX11Initializer/DX11ConstantsMapper.h +++ b/DX11API/DX11Initializer/DX11ConstantsMapper.h @@ -1,9 +1,21 @@ #pragma once +/** +@file DX11ConstantsMapper.h +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + + #include "swGraphicAPI/Rendering/GraphicAPIConstants.h" #include "DX11APIObjects.h" + +namespace sw +{ + + extern D3D11_USAGE DX11ResourceUsage[ 4 ]; extern DXGI_FORMAT DX11ResourceFormat[ 133 ]; extern D3D_PRIMITIVE_TOPOLOGY DX11PrimitiveTopology[ 9 ]; @@ -23,6 +35,10 @@ extern D3D11_CULL_MODE DX11CullMode[ 3 ]; extern D3D11_BLEND DX11BlendFactor[ 12 ]; extern D3D11_BLEND_OP DX11BlendOperation[ 5 ]; + + + + /**@brief Klasa s�u�y do mapowania sta�ych z warto�ci silnikowych do DirectX 11. @ingroup DX11API*/ class DX11ConstantsMapper @@ -33,26 +49,29 @@ class DX11ConstantsMapper ~DX11ConstantsMapper() = default; - static inline D3D11_USAGE Get( ResourceUsage usage ) { return DX11ResourceUsage[ (int)usage ]; } - static inline DXGI_FORMAT Get( ResourceFormat format ) { return DX11ResourceFormat[ (int)format ]; } - static inline D3D_PRIMITIVE_TOPOLOGY Get( PrimitiveTopology topology ) { return DX11PrimitiveTopology[ (int)topology ]; } - static inline D3D11_BIND_FLAG Get( ResourceBinding binding ) { return DX11ResourceBinding[ (int)binding ]; } - static inline D3D11_RTV_DIMENSION Get( TextureType texType ) { return DX11TextureType[ (int)texType ]; } - static inline DXGI_FORMAT Get( DepthStencilFormat format ) { return DX11DepthStencilFormat[ (int)format ]; } - static inline D3D11_FILL_MODE Get( FillMode mode ) { return DX11FillMode[ (int)mode ]; } - static inline D3D11_CULL_MODE Get( CullMode mode ) { return DX11CullMode[ (int)mode ]; } - static inline D3D11_BLEND Get( BlendFactor factor ) { return DX11BlendFactor[ (int)factor ]; } - static inline D3D11_BLEND_OP Get( BlendOperation op ) { return DX11BlendOperation[ (int)op ]; } + static inline D3D11_USAGE Get( ResourceUsage usage ) { return DX11ResourceUsage[ (int)usage ]; } + static inline DXGI_FORMAT Get( ResourceFormat format ) { return DX11ResourceFormat[ (int)format ]; } + static inline D3D_PRIMITIVE_TOPOLOGY Get( PrimitiveTopology topology ) { return DX11PrimitiveTopology[ (int)topology ]; } + static inline D3D11_BIND_FLAG Get( ResourceBinding binding ) { return DX11ResourceBinding[ (int)binding ]; } + static inline D3D11_RTV_DIMENSION Get( TextureType texType ) { return DX11TextureType[ (int)texType ]; } + static inline DXGI_FORMAT Get( DepthStencilFormat format ) { return DX11DepthStencilFormat[ (int)format ]; } + static inline D3D11_FILL_MODE Get( FillMode mode ) { return DX11FillMode[ (int)mode ]; } + static inline D3D11_CULL_MODE Get( CullMode mode ) { return DX11CullMode[ (int)mode ]; } + static inline D3D11_BLEND Get( BlendFactor factor ) { return DX11BlendFactor[ (int)factor ]; } + static inline D3D11_BLEND_OP Get( BlendOperation op ) { return DX11BlendOperation[ (int)op ]; } static ResourceFormat ConvertBack ( DXGI_FORMAT ); - - static inline D3D11_SRV_DIMENSION ConvertSRV ( TextureType texType ) { return DX11TextureTypeToSRV[ (int)texType ]; } - static inline D3D11_DSV_DIMENSION ConvertDSV ( TextureType texType ) { return DX11TextureTypeToDSV[ (int)texType ]; } - static inline DXGI_FORMAT ConvertTypeless ( DepthStencilFormat format ) { return DX11DepthStencilTypeless[ (int)format ]; } - static inline DXGI_FORMAT ConvertDepthOnly ( DepthStencilFormat format ) { return DX11DepthOnly[ (int)format ]; } - static inline DXGI_FORMAT ConvertStencilOnly ( DepthStencilFormat format ) { return DX11StencilOnly[ (int)format ]; } + + static inline D3D11_SRV_DIMENSION ConvertSRV ( TextureType texType ) { return DX11TextureTypeToSRV[ (int)texType ]; } + static inline D3D11_DSV_DIMENSION ConvertDSV ( TextureType texType ) { return DX11TextureTypeToDSV[ (int)texType ]; } + static inline DXGI_FORMAT ConvertTypeless ( DepthStencilFormat format ) { return DX11DepthStencilTypeless[ (int)format ]; } + static inline DXGI_FORMAT ConvertDepthOnly ( DepthStencilFormat format ) { return DX11DepthOnly[ (int)format ]; } + static inline DXGI_FORMAT ConvertStencilOnly ( DepthStencilFormat format ) { return DX11StencilOnly[ (int)format ]; } static size_t BitsPerPixel ( DXGI_FORMAT fmt ); - static inline size_t BytesPerPixel ( DXGI_FORMAT fmt ) { return BitsPerPixel( fmt ) / 8; } + static inline size_t BytesPerPixel ( DXGI_FORMAT fmt ) { return BitsPerPixel( fmt ) / 8; } }; + +} // sw + diff --git a/DX11API/DX11Initializer/DX11DebugLayer.cpp b/DX11API/DX11Initializer/DX11DebugLayer.cpp new file mode 100644 index 0000000..78d685a --- /dev/null +++ b/DX11API/DX11Initializer/DX11DebugLayer.cpp @@ -0,0 +1,30 @@ +/** +@file DX11DebugLayer.cpp +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + +#include "swGraphicAPI/DX11API/stdafx.h" + +#include "DX11DebugLayer.h" + + + +namespace sw +{ + + + + +// ================================ // +// +void DX11DebugLayer::SetDebugName ( ID3D11DeviceChild* child, const std::string& name ) +{ + if( child != nullptr ) + { + child->SetPrivateData( WKPDID_D3DDebugObjectName, (uint32)name.size(), name.c_str() ); + } +} + +} // sw + diff --git a/DX11API/DX11Initializer/DX11DebugLayer.h b/DX11API/DX11Initializer/DX11DebugLayer.h new file mode 100644 index 0000000..155f59c --- /dev/null +++ b/DX11API/DX11Initializer/DX11DebugLayer.h @@ -0,0 +1,38 @@ +#pragma once +/** +@file DX11DebugLayer.h +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + +#include + +#pragma warning( disable : 4005 ) +//#include "d3dx11.h" +#include +#pragma warning( default : 4005 ) + + +namespace sw +{ + + +/**@brief Debug functionalities.*/ +class DX11DebugLayer +{ +private: +protected: +public: + explicit DX11DebugLayer () = default; + ~DX11DebugLayer () = default; + +public: + + void SetDebugName ( ID3D11DeviceChild* child, const std::string& name ); +}; + + + +} // sw + + diff --git a/DX11API/DX11Initializer/DX11Initializer.cpp b/DX11API/DX11Initializer/DX11Initializer.cpp index 86e1b6c..2e1860b 100644 --- a/DX11API/DX11Initializer/DX11Initializer.cpp +++ b/DX11API/DX11Initializer/DX11Initializer.cpp @@ -1,8 +1,9 @@ /** -@file DX11Initializaer.cpp +@file DX11Initializer.cpp @author nieznanysprawiciel -@copyright File is part of graphic engine SWEngine. +@copyright File is part of Sleeping Wombat Libraries. */ + #include "swGraphicAPI/DX11API/stdafx.h" @@ -22,7 +23,11 @@ using namespace Microsoft::WRL; -#include "swCommonLib/Common/MemoryLeaks.h" + +namespace sw +{ + + // ================================ // // @@ -63,12 +68,12 @@ SwapChain* DX11Initializer::CreateSwapChain ( const SwapChainInitData& swapCh // Render target ComPtr< ID3D11Texture2D > backBuffer = nullptr; - result = swapChain->GetBuffer( 0, __uuidof(ID3D11Texture2D), (LPVOID*)backBuffer.GetAddressOf() ); - if ( FAILED( result ) ) return nullptr; + result = swapChain->GetBuffer( 0, __uuidof( ID3D11Texture2D ), (LPVOID*)backBuffer.GetAddressOf() ); + if( FAILED( result ) ) return nullptr; ComPtr< ID3D11RenderTargetView > renderTargetView; result = device->CreateRenderTargetView( backBuffer.Get(), nullptr, renderTargetView.GetAddressOf() ); - if ( FAILED( result ) ) return nullptr; + if( FAILED( result ) ) return nullptr; // Depth buffer _z_buffer_desc.Format = DX11ConstantsMapper::Get( swapChainData.DepthStencilFormat ); @@ -82,20 +87,21 @@ SwapChain* DX11Initializer::CreateSwapChain ( const SwapChainInitData& swapCh _z_buffer_desc.BindFlags = D3D11_BIND_DEPTH_STENCIL; _z_buffer_desc.CPUAccessFlags = 0; _z_buffer_desc.MiscFlags = 0; - + _z_buffer_view_desc.Format = _z_buffer_desc.Format; ComPtr< ID3D11Texture2D > backBufferDepth = nullptr; result = device->CreateTexture2D( &_z_buffer_desc, nullptr, backBufferDepth.GetAddressOf() ); - if ( FAILED( result ) ) return nullptr; + if( FAILED( result ) ) return nullptr; ComPtr< ID3D11DepthStencilView > zBufferView; result = device->CreateDepthStencilView( backBufferDepth.Get(), &_z_buffer_view_desc, zBufferView.GetAddressOf() ); - if ( FAILED( result ) ) return nullptr; - + if( FAILED( result ) ) return nullptr; - DX11RenderTarget* renderTargetObject = new DX11RenderTarget( renderTargetView, zBufferView, nullptr, nullptr, nullptr ); + ///@todo Set here proper RenderTarget path. This code can be used in different branch, we must check what happens + ///there after we merge this to master. + DX11RenderTarget* renderTargetObject = new DX11RenderTarget( AssetPath( "", "/RenderTarget" ), renderTargetView, zBufferView, nullptr, nullptr, nullptr ); renderTargetObject->SetHeight( static_cast( swapChainData.WindowHeight ) ); renderTargetObject->SetWidth( static_cast( swapChainData.WindowWidth ) ); @@ -121,7 +127,7 @@ SwapChain* DX11Initializer::CreateCompositionSwapChain ( const SwapChainInitDa @param[in] initData Dane u�ywane do inicjalizacji. @return Zwraca true, je�eli inicjalizacja si� uda.*/ -bool DX11Initializer::InitAPI ( const GraphicAPIInitData& initData ) +ReturnResult DX11Initializer::InitAPI ( const GraphicAPIInitData& initData ) { set_depth_stencil_format( DX11ConstantsMapper::Get( initData.SwapChain.DepthStencilFormat ) ); @@ -137,24 +143,24 @@ bool DX11Initializer::InitAPI ( const GraphicAPIInitData& initData ) initData.SingleThreaded ); if( result != DX11_INIT_RESULT::DX11_INIT_OK ) - return false; + return "Failed to init DirectX 11"; ///< @todo More descriptive error message. } else { auto result = InitDevices( initData ); - if( !result.IsValid ) - return false; + if( !result.IsValid() ) + return result; } result = init_sampler(); - if ( result != DX11_INIT_OK ) + if( result != DX11_INIT_OK ) { release_DirectX(); // Jak tu co� si� nie uda�o, to znaczy, �e deskryptor by� niepoprawny. - return false; + return "Failed to create sampler."; } if( FAILED( device->CreateRasterizerState( &get_rasterizer_desc(), &m_rasterizer ) ) ) - return false; + return "Failed to create RasterizerState."; device_context->RSSetState( m_rasterizer ); @@ -179,7 +185,7 @@ bool DX11Initializer::InitAPI ( const GraphicAPIInitData& initData ) //device_context->OMSetDepthStencilState( m_depthState, 0 ); - return true; + return Result::Success; } /**@brief Zwalnia stworzone obiekty DirectX 11.*/ @@ -204,13 +210,13 @@ void DX11Initializer::ReleaseAPI() @param[in] renderTarget RenderTarget, z kt�rego ma zosta� wzi�tu wska�nik. @return Zwraca wska�nik na widok na bufor koloru render targetu lub nullptr, jezeli podano niepoprawny render target.*/ -void* DX11Initializer::GetRenderTargetHandle( RenderTargetObject* renderTarget ) +void* DX11Initializer::GetRenderTargetHandle( RenderTarget* renderTarget ) { DX11RenderTarget* renderTargetDX11 = static_cast( renderTarget ); if( renderTargetDX11 ) { - auto colorBufferTex = static_cast< DX11Texture* >( renderTargetDX11->GetColorBuffer() ); + auto colorBufferTex = static_cast( renderTargetDX11->GetColorBuffer() ); if( colorBufferTex ) { ComPtr< ID3D11Resource > renderTargetTexture; @@ -224,7 +230,7 @@ void* DX11Initializer::GetRenderTargetHandle( RenderTargetObject* renderTarge } /**@brief Creates only device and device context.*/ -Nullable< bool > DX11Initializer::InitDevices ( const GraphicAPIInitData& initData ) +ReturnResult DX11Initializer::InitDevices ( const GraphicAPIInitData& initData ) { UINT createDeviceFlags = 0; @@ -232,23 +238,24 @@ Nullable< bool > DX11Initializer::InitDevices ( const GraphicAPIInitData& initDa if( initData.UseDebugLayer ) createDeviceFlags |= D3D11_CREATE_DEVICE_DEBUG; - if ( initData.SingleThreaded ) + if( initData.SingleThreaded ) // Domy�lnie obiekt ID3D11Device jest synchronizowany, ale mo�na to wy��czy� createDeviceFlags |= D3D11_CREATE_DEVICE_SINGLETHREADED; auto result = D3D11CreateDevice( nullptr, D3D_DRIVER_TYPE::D3D_DRIVER_TYPE_HARDWARE, nullptr, createDeviceFlags, _feature_levels, _num_feature_levels, D3D11_SDK_VERSION, &device, &_current_feature_level, &device_context ); - if ( FAILED( result ) ) - return "Creating device failed."; //@todo Use _com_error( result ).ErrorMessage(); + if( FAILED( result ) ) + return "Creating device failed. Error: " + DX11Utils::ErrorString( result ); if( initData.UseDebugLayer ) { result = device->QueryInterface( __uuidof( ID3D11Debug ), (void**)&debug_interface ); - if ( FAILED( result ) ) + if( FAILED( result ) ) return "Creating debug layer failed"; } - return true; + return Result::Success; } +} // sw diff --git a/DX11API/DX11Initializer/DX11Initializer.h b/DX11API/DX11Initializer/DX11Initializer.h index 3780ed6..ec8a733 100644 --- a/DX11API/DX11Initializer/DX11Initializer.h +++ b/DX11API/DX11Initializer/DX11Initializer.h @@ -2,16 +2,21 @@ /** @file DX11Initializer.h @author nieznanysprawiciel -@copyright Plik jest cz�ci� silnika graficznego SWEngine. +@copyright File is part of Sleeping Wombat Libraries. */ -#include "swCommonLib/Common/Nullable.h" +#include "swCommonLib/Common/Exceptions/Nullable.h" #include "swGraphicAPI/Rendering/IGraphicAPIInitializer.h" #include "DX11APIObjects.h" #include "swGraphicAPI/Resources/SwapChain.h" + +namespace sw +{ + + /**@defgroup DX11API @brief Implements renderer, initializer and resource objects in DirectX 11. @ingroup GraphicAPI @@ -36,15 +41,18 @@ class DX11Initializer : public IGraphicAPIInitializer, public DX11AuxiliaryObjec virtual IRenderer* CreateRenderer ( RendererUsage usage ) override; virtual SwapChain* CreateSwapChain ( const SwapChainInitData& swapChainData ) override; - virtual bool InitAPI ( const GraphicAPIInitData& initData ) override; + virtual ReturnResult InitAPI ( const GraphicAPIInitData& initData ) override; virtual void ReleaseAPI () override; - virtual void* GetRenderTargetHandle ( RenderTargetObject* renderTarget ) override; + virtual void* GetRenderTargetHandle ( RenderTarget* renderTarget ) override; private: - Nullable< bool > InitDevices ( const GraphicAPIInitData& initData ); + ReturnResult InitDevices ( const GraphicAPIInitData& initData ); SwapChain* CreateWindowSwapChain ( const SwapChainInitData& swapChainData ); SwapChain* CreateCompositionSwapChain ( const SwapChainInitData& swapChainData ); }; + +} // sw + diff --git a/DX11API/DX11Initializer/DX11Utils.cpp b/DX11API/DX11Initializer/DX11Utils.cpp index 957f7ff..bb862a9 100644 --- a/DX11API/DX11Initializer/DX11Utils.cpp +++ b/DX11API/DX11Initializer/DX11Utils.cpp @@ -11,6 +11,14 @@ #include "DX11ConstantsMapper.h" //#include +// _com_error +#include + + + + +namespace sw +{ // ================================ // @@ -46,10 +54,10 @@ DXGI_SWAP_CHAIN_DESC1 DX11Utils::CreateSwapChainDesc1 ( const SwapChainInitDa desc.SampleDesc.Quality = swapChainData.SamplesQuality; desc.Stereo = false; desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; - desc.Scaling = DXGI_SCALING_STRETCH; - desc.SwapEffect = DXGI_SWAP_EFFECT::DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; + desc.Scaling = DXGI_SCALING_STRETCH; + desc.SwapEffect = DXGI_SWAP_EFFECT::DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; desc.AlphaMode = DXGI_ALPHA_MODE_IGNORE; - desc.Flags = 0; + desc.Flags = 0; return desc; } @@ -62,13 +70,13 @@ ComPtr< IDXGIAdapter > DX11Utils::GetDXGIAdapter () ComPtr< IDXGIDevice > dxgiDevice = nullptr; result = device->QueryInterface( __uuidof( IDXGIDevice ), (void**)&dxgiDevice ); - + assert( SUCCEEDED( result ) ); if( FAILED( result ) ) return nullptr; ComPtr< IDXGIAdapter > dxgiAdapter = nullptr; result = dxgiDevice->GetParent( __uuidof( IDXGIAdapter ), (void **)&dxgiAdapter ); - + assert( SUCCEEDED( result ) ); if( FAILED( result ) ) return nullptr; @@ -111,6 +119,14 @@ ComPtr< IDXGISwapChain > DX11Utils::CreateCompositionSwapChain ( const SwapChai return swapChain; } +// ================================ // +// +std::string DX11Utils::ErrorString ( HRESULT result ) +{ + auto error = _com_error( result ); + return Convert::ToString( std::wstring( error.ErrorMessage() ) ); +} + // ================================ // // ComPtr< IDXGIFactory > DX11Utils::GetDXGIFactory () @@ -125,3 +141,5 @@ ComPtr< IDXGIFactory2 > DX11Utils::GetDXGIFactory2 () return GetFactory< IDXGIFactory2 >(); } + +} // sw \ No newline at end of file diff --git a/DX11API/DX11Initializer/DX11Utils.h b/DX11API/DX11Initializer/DX11Utils.h index 85f9ed3..1d88f81 100644 --- a/DX11API/DX11Initializer/DX11Utils.h +++ b/DX11API/DX11Initializer/DX11Utils.h @@ -1,4 +1,10 @@ #pragma once +/** +@file DX11Utils.h +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + #include "DX11APIObjects.h" #include "swGraphicAPI/Rendering/IGraphicAPIInitializer.h" @@ -6,6 +12,13 @@ #include +#include + + +namespace sw +{ + + /**@brief Helper functions for DirecX objects managment.*/ class DX11Utils : protected DX11APIObjects { @@ -18,8 +31,8 @@ class DX11Utils : protected DX11APIObjects public: - static DXGI_SWAP_CHAIN_DESC CreateSwapChainDesc ( const SwapChainInitData& swapChainData); - static DXGI_SWAP_CHAIN_DESC1 CreateSwapChainDesc1 ( const SwapChainInitData& swapChainData); + static DXGI_SWAP_CHAIN_DESC CreateSwapChainDesc ( const SwapChainInitData& swapChainData ); + static DXGI_SWAP_CHAIN_DESC1 CreateSwapChainDesc1 ( const SwapChainInitData& swapChainData ); public: @@ -34,7 +47,12 @@ class DX11Utils : protected DX11APIObjects template< typename FactoryType > static ComPtr< FactoryType > GetFactory (); + +public: + + static std::string ErrorString ( HRESULT result ); }; +} // sw diff --git a/DX11API/DX11Initializer/DX11Utils.inl b/DX11API/DX11Initializer/DX11Utils.inl index 72ab752..b0f1e2e 100644 --- a/DX11API/DX11Initializer/DX11Utils.inl +++ b/DX11API/DX11Initializer/DX11Utils.inl @@ -1,8 +1,18 @@ #pragma once +/** +@file DX11Utils.inl +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + + #include "DX11Utils.h" +namespace sw +{ + //====================================================================================// // Implementation //====================================================================================// @@ -29,3 +39,4 @@ inline ComPtr< FactoryType > DX11Utils::GetFactory () return nullptr; } +} // sw diff --git a/DX11API/DX11Renderer/DX11Renderer.cpp b/DX11API/DX11Renderer/DX11Renderer.cpp index a36bca4..5fd015e 100644 --- a/DX11API/DX11Renderer/DX11Renderer.cpp +++ b/DX11API/DX11Renderer/DX11Renderer.cpp @@ -1,8 +1,9 @@ /** @file DX11Renderer.cpp @author nieznanysprawiciel -@copyright File is part of graphic engine SWEngine. +@copyright File is part of Sleeping Wombat Libraries. */ + #include "swGraphicAPI/DX11API/stdafx.h" @@ -19,6 +20,10 @@ #include "swCommonLib/Common/MemoryLeaks.h" +namespace sw +{ + + #define ThrowIfNull( ptr, message ) \ if( !ptr ) \ @@ -38,12 +43,12 @@ RendererUsage::USE_AS_DEFERRED. DX11Renderer::DX11Renderer( RendererUsage usage ) { m_usageType = usage; - if ( usage == RendererUsage::USE_AS_IMMEDIATE ) + if( usage == RendererUsage::USE_AS_IMMEDIATE ) { m_localDeviceContext = device_context; m_valid = true; } - else if ( usage == RendererUsage::USE_AS_DEFERRED ) // Will not work, if the device was created with the D3D11_CREATE_DEVICE_SINGLETHREADED value. + else if( usage == RendererUsage::USE_AS_DEFERRED ) // Will not work, if the device was created with the D3D11_CREATE_DEVICE_SINGLETHREADED value. { device->CreateDeferredContext( 0, &m_localDeviceContext ); m_valid = true; @@ -59,8 +64,8 @@ DX11Renderer::DX11Renderer( RendererUsage usage ) // DX11Renderer::~DX11Renderer() { - if ( m_usageType == RendererUsage::USE_AS_DEFERRED ) /// Tylko w takim wypadku alokowali�my nowy kontekst. Inaczej zwalanianie nale�y do klasy DX11_interfaces_container. - if ( m_localDeviceContext ) + if( m_usageType == RendererUsage::USE_AS_DEFERRED ) /// Tylko w takim wypadku alokowali�my nowy kontekst. Inaczej zwalanianie nale�y do klasy DX11_interfaces_container. + if( m_localDeviceContext ) m_localDeviceContext->Release(); } @@ -84,7 +89,7 @@ void DX11Renderer::Draw ( const DrawCommand& command ) m_localDeviceContext->IASetInputLayout( nullptr ); m_localDeviceContext->IASetPrimitiveTopology( DX11ConstantsMapper::Get( command.Topology ) ); - + DX11Renderer::SetVertexBuffer( command.VertexBuffer, 0 ); SetIndexBuffer( command.IndexBufer, 0, command.ExtendedIndex ); @@ -242,7 +247,7 @@ void DX11Renderer::ClearRenderTarget ( const ClearRenderTargetCommand& command ) float clearColor[ 4 ] = { command.ClearColor.x, command.ClearColor.y, command.ClearColor.z, command.ClearColor.w }; device_context->ClearRenderTargetView( renderTarget->GetRenderTarget(), clearColor ); } - + uint32 clearFlags = 0; if( command.ClearDepth ) clearFlags = clearFlags | D3D11_CLEAR_DEPTH; @@ -389,16 +394,16 @@ void DX11Renderer::SetShaderState ( const SetShaderStateExCommand& command ) // void DX11Renderer::SetShaderState ( const SetRenderStateCommand& command ) { - DX11Renderer::SetShaderState( static_cast< const SetShaderStateCommand& >( command ) ); - DX11Renderer::SetDefaultBuffers( static_cast< const SetDefaultBuffersCommand& >( command ) ); + DX11Renderer::SetShaderState( static_cast( command ) ); + DX11Renderer::SetDefaultBuffers( static_cast( command ) ); } // ================================ // // void DX11Renderer::SetShaderState ( const SetRenderStateExCommand& command ) { - DX11Renderer::SetShaderState( static_cast< const SetShaderStateExCommand& >( command ) ); - DX11Renderer::SetDefaultBuffers( static_cast< const SetDefaultBuffersCommand& >( command ) ); + DX11Renderer::SetShaderState( static_cast( command ) ); + DX11Renderer::SetDefaultBuffers( static_cast( command ) ); } // ================================ // @@ -429,33 +434,33 @@ void DX11Renderer::FlushCommands () // ================================ // // -bool DX11Renderer::SetVertexBuffer ( BufferObject* buffer, unsigned int offset ) +bool DX11Renderer::SetVertexBuffer ( Buffer* buffer, unsigned int offset ) { - ID3D11Buffer* vertexBuffer = nullptr; - if( buffer ) - { - vertexBuffer = DX11( buffer )->Get(); - unsigned int stride = buffer->GetStride(); - m_localDeviceContext->IASetVertexBuffers( 0, 1, &vertexBuffer, &stride, &offset ); - - return false; - } - else - { - //throw new std::runtime_error( "Vertex buffer is nullptr" ); - //assert( !"Vertex buffer is nullptr" ); + ID3D11Buffer* vertexBuffer = nullptr; + if( buffer ) + { + vertexBuffer = DX11( buffer )->Get(); + unsigned int stride = buffer->GetStride(); + m_localDeviceContext->IASetVertexBuffers( 0, 1, &vertexBuffer, &stride, &offset ); + + return false; + } + else + { + //throw new std::runtime_error( "Vertex buffer is nullptr" ); + //assert( !"Vertex buffer is nullptr" ); unsigned int stride = 0; m_localDeviceContext->IASetVertexBuffers( 0, 1, &vertexBuffer, &stride, &offset ); - } - return true; + } + return true; } // ================================ // // Buffer can be nullptr. -void DX11Renderer::SetIndexBuffer ( BufferObject* buffer, unsigned int offset, bool extendedIndex ) +void DX11Renderer::SetIndexBuffer ( Buffer* buffer, unsigned int offset, bool extendedIndex ) { - if ( buffer ) + if( buffer ) { auto indexBuffer = DX11( buffer )->Get(); assert( indexBuffer ); @@ -469,7 +474,7 @@ void DX11Renderer::SetIndexBuffer ( BufferObject* buffer, unsigned int offset, b // ================================ // // -void DX11Renderer::SetRenderTarget ( RenderTargetObject* const targets[ MAX_BOUND_RENDER_TARGETS ], RenderTargetObject* depthStencil ) +void DX11Renderer::SetRenderTarget ( RenderTarget* const targets[ MAX_BOUND_RENDER_TARGETS ], RenderTarget* depthStencil ) { ID3D11RenderTargetView* DX11Targets[ MAX_BOUND_RENDER_TARGETS ]; for( int i = 0; i < MAX_BOUND_RENDER_TARGETS; ++i ) @@ -491,7 +496,7 @@ void DX11Renderer::SetRenderTarget ( RenderTargetObject* const targets[ MAX_BOUN // ================================ // // -void DX11Renderer::SetTextures ( TextureObject* const texturesArray[ MAX_BOUND_RENDER_TARGETS ], const uint8 shaderTypes[ MAX_BOUND_RENDER_TARGETS ] ) +void DX11Renderer::SetTextures ( Texture* const texturesArray[ MAX_BOUND_RENDER_TARGETS ], const uint8 shaderTypes[ MAX_BOUND_RENDER_TARGETS ] ) { ID3D11ShaderResourceView* texturesVert[ ENGINE_MAX_TEXTURES ]; ID3D11ShaderResourceView* texturesPix[ ENGINE_MAX_TEXTURES ]; @@ -527,3 +532,5 @@ void DX11Renderer::SetTextures ( TextureObject* const texturesArray[ MAX_BOUND_ device_context->DSSetShaderResources( 0, ENGINE_MAX_TEXTURES, texturesDomain ); } + +} // sw \ No newline at end of file diff --git a/DX11API/DX11Renderer/DX11Renderer.h b/DX11API/DX11Renderer/DX11Renderer.h index 0ad0944..2409709 100644 --- a/DX11API/DX11Renderer/DX11Renderer.h +++ b/DX11API/DX11Renderer/DX11Renderer.h @@ -2,33 +2,40 @@ /** @file DX11Renderer.h @author nieznanysprawiciel -@copyright File is part of graphic engine SWEngine. +@copyright File is part of Sleeping Wombat Libraries. */ + #include "DX11Initializer/DX11APIObjects.h" #include "swGraphicAPI/Resources/MeshResources.h" -#include "swGraphicAPI/Resources/BlendingState.h" -#include "swGraphicAPI/Resources/RasterizerState.h" -#include "swGraphicAPI/Resources/DepthStencilState.h" +#include "swGraphicAPI/Resources/PipelineStates/BlendingState.h" +#include "swGraphicAPI/Resources/PipelineStates/RasterizerState.h" +#include "swGraphicAPI/Resources/PipelineStates/DepthStencilState.h" #include "swGraphicAPI/Rendering/IRenderer.h" + + +namespace sw +{ + + class DX11Renderer; typedef DX11Renderer Renderer; -inline DX11Buffer* DX11 ( BufferObject* res ) { return static_cast< DX11Buffer* >( res ); } -inline DX11Texture* DX11 ( TextureObject* res ) { return static_cast< DX11Texture* >( res ); } -inline DX11ComputeShader* DX11 ( ComputeShader* res ) { return static_cast< DX11ComputeShader* >( res ); } -inline DX11PixelShader* DX11 ( PixelShader* res ) { return static_cast< DX11PixelShader* >( res ); } -inline DX11VertexShader* DX11 ( VertexShader* res ) { return static_cast< DX11VertexShader* >( res ); } -inline DX11RenderTarget* DX11 ( RenderTargetObject* res ) { return static_cast< DX11RenderTarget* >( res ); } +inline DX11Buffer* DX11 ( Buffer* res ) { return static_cast( res ); } +inline DX11Texture* DX11 ( sw::Texture* res ) { return static_cast( res ); } +inline DX11ComputeShader* DX11 ( ComputeShader* res ) { return static_cast( res ); } +inline DX11PixelShader* DX11 ( PixelShader* res ) { return static_cast( res ); } +inline DX11VertexShader* DX11 ( VertexShader* res ) { return static_cast( res ); } +inline DX11RenderTarget* DX11 ( RenderTarget* res ) { return static_cast( res ); } -inline DX11BlendingState* DX11 ( BlendingState* res ) { return static_cast< DX11BlendingState* >( res ); } -inline DX11RasterizerState* DX11 ( RasterizerState* res ) { return static_cast< DX11RasterizerState* >( res ); } -inline DX11DepthStencilState* DX11 ( DepthStencilState* res ) { return static_cast< DX11DepthStencilState* >( res ); } -inline DX11InputLayout* DX11 ( ShaderInputLayout* res ) { return static_cast< DX11InputLayout* >( res ); } +inline DX11BlendingState* DX11 ( BlendingState* res ) { return static_cast( res ); } +inline DX11RasterizerState* DX11 ( RasterizerState* res ) { return static_cast( res ); } +inline DX11DepthStencilState* DX11 ( DepthStencilState* res ) { return static_cast( res ); } +inline DX11InputLayout* DX11 ( ShaderInputLayout* res ) { return static_cast( res ); } //DX11GeometryShader* Typed ( GeometryShader* res ) { return static_cast< DX11GeometryShader* >( res ); } @@ -44,21 +51,21 @@ inline DX11InputLayout* DX11 ( ShaderInputLayout* res ) { return static_cast< /**@brief Renderer obs�uguj�cy DirectX 11. @ingroup DX11API*/ -class DX11Renderer : public IRenderer, protected DX11AuxiliaryObjects +class DX11Renderer : public IRenderer, protected DX11AuxiliaryObjects { private: /**Kontekst urz�dzenia s�u��cy do renderowania. W zale�no�ci czy stosujemy op�nione renderowanie (deferred rendering) czy nie, ta zmienna przechowuje kopi� wska�nika z DX11_interfaces_container lub op�niony kontekst (deferred context). W trakcie renderowania nie musimy wiedzie� z czym mamy do czynienia.*/ - ID3D11DeviceContext* m_localDeviceContext; + ID3D11DeviceContext* m_localDeviceContext; bool m_valid; ///< Je�eli klasa nie zosta�a zainicjowana poprawnie, to b�dzie tu warto�� false. RendererUsage m_usageType; ///< Informacja jak b�dzie u�ywany rederer. public: DX11Renderer( RendererUsage usage = USE_AS_IMMEDIATE ); ~DX11Renderer(); - bool SupportsDefferedContextRendering() override { return true; } ///< Informuje czy Renderer nadaje si� do renderowania w wielu w�tkach do op�nionego contextu. - bool IsValid() override { return m_valid; } + bool SupportsDefferedContextRendering() override { return true; } ///< Informuje czy Renderer nadaje si� do renderowania w wielu w�tkach do op�nionego contextu. + bool IsValid() override { return m_valid; } @@ -75,7 +82,7 @@ class DX11Renderer : public IRenderer, protected DX11AuxiliaryObjects virtual void UpdateAndBindBuffer ( const UpdateBindBuffer& command ) override; virtual void SetDefaultBuffers ( const SetDefaultBuffersCommand& command ) override; - + virtual void SetShaderState ( const SetShaderStateCommand& command ) override; virtual void SetShaderState ( const SetShaderStateExCommand& command ) override; virtual void SetShaderState ( const SetRenderStateCommand& command ) override; @@ -86,12 +93,13 @@ class DX11Renderer : public IRenderer, protected DX11AuxiliaryObjects virtual void FlushCommands () override; private: - - bool SetVertexBuffer ( BufferObject* buffer, unsigned int offset ); - void SetIndexBuffer ( BufferObject* buffer, unsigned int offset, bool extendedIndex ); - void SetRenderTarget ( RenderTargetObject* const targets[ MAX_BOUND_RENDER_TARGETS ], RenderTargetObject* depthStencil ); - void SetTextures ( TextureObject* const texturesArray[ MAX_BOUND_RENDER_TARGETS ], const uint8 shaderTypes[ MAX_BOUND_RENDER_TARGETS ] ); + + bool SetVertexBuffer ( Buffer* buffer, unsigned int offset ); + void SetIndexBuffer ( Buffer* buffer, unsigned int offset, bool extendedIndex ); + void SetRenderTarget ( RenderTarget* const targets[ MAX_BOUND_RENDER_TARGETS ], RenderTarget* depthStencil ); + void SetTextures ( Texture* const texturesArray[ MAX_BOUND_RENDER_TARGETS ], const uint8 shaderTypes[ MAX_BOUND_RENDER_TARGETS ] ); }; +} // sw diff --git a/DX11API/DX11Resources/DX11Buffer.cpp b/DX11API/DX11Resources/DX11Buffer.cpp index f6d9fb6..dec0345 100644 --- a/DX11API/DX11Resources/DX11Buffer.cpp +++ b/DX11API/DX11Resources/DX11Buffer.cpp @@ -9,53 +9,51 @@ #include "DX11Initializer/DX11ConstantsMapper.h" #include "swCommonLib/Common/Converters.h" +#include "swCommonLib/Common/Exceptions/Nullable.h" -#include "swCommonLib/Common/MemoryLeaks.h" RTTR_REGISTRATION { - rttr::registration::class_< DX11Buffer >( "DX11Buffer" ); + rttr::registration::class_< sw::DX11Buffer >( "sw::DX11Buffer" ); } - -DX11Buffer::DX11Buffer( const std::wstring& name, const BufferInfo& descriptor, ID3D11Buffer* buff ) - : BufferObject( descriptor.ElementSize, descriptor.NumElements ), m_buffer( buff ) - , m_descriptor( descriptor ) +namespace sw { - m_descriptor.Name = name; +// ================================ // +// +DX11Buffer::DX11Buffer ( const AssetPath& name, const BufferInfo& descriptor, ID3D11Buffer* buff ) + : Buffer( name, descriptor.ElementSize, descriptor.NumElements ), m_buffer( buff ) + , m_descriptor( descriptor ) +{ if( IsDebugLayerEnabled() ) - { - std::string nameStr = Convert::ToString< std::wstring >( name ); - SetDebugName( m_buffer, nameStr ); + { + std::string nameStr = name.String(); + SetDebugName( m_buffer.Get(), nameStr ); } } +// ================================ // +// DX11Buffer::~DX11Buffer() { - if( m_buffer ) - m_buffer->Release(); m_buffer = nullptr; } -/**@brief Tworzy bufor wierzcho�k�w, indeks�w lub sta�ych o podanych parametrach. - -@param[in] name Buffer name or file path. -@param[in] data Pointer to initialization data. Memory can be released after call. -@param[in] bufferInfo Buffer descriptor. -@return Wska�nik na DX11Buffer w przypadku powodzenia lub nullptr, je�eli co� p�jdzie nie tak.*/ -DX11Buffer* DX11Buffer::CreateFromMemory ( const std::wstring& name, const uint8* data, const BufferInfo& bufferInfo ) +// ================================ // +// +sw::Nullable< Buffer* > DX11Buffer::CreateFromMemory ( const AssetPath& name, const uint8* data, const BufferInfo& bufferInfo ) { ResourceBinding bindFlag; if( bufferInfo.BufferType == BufferType::VertexBuffer ) - bindFlag = ResourceBinding::BIND_RESOURCE_VERTEX_BUFFER; + bindFlag = ResourceBinding::RB_VertexBuffer; else if( bufferInfo.BufferType == BufferType::IndexBuffer ) - bindFlag = ResourceBinding::BIND_RESOURCE_INDEX_BUFFER; + bindFlag = ResourceBinding::RB_IndexBuffer; else if( bufferInfo.BufferType == BufferType::ConstantBuffer ) - bindFlag = ResourceBinding::BIND_RESOURCE_CONSTANT_BUFFER; + bindFlag = ResourceBinding::RB_ConstantsBuffer; // Wype�niamy deskryptor bufora D3D11_BUFFER_DESC bufferDesc; @@ -78,7 +76,7 @@ DX11Buffer* DX11Buffer::CreateFromMemory ( const std::wstring& name, const uint ID3D11Buffer* newBuffer; result = device->CreateBuffer( &bufferDesc, initDataPtr, &newBuffer ); if( FAILED( result ) ) - return nullptr; + return "[DX11Buffer] Buffer creation failed."; DX11Buffer* newBufferObject = new DX11Buffer( name, bufferInfo, newBuffer ); return newBufferObject; @@ -97,7 +95,7 @@ DX11Buffer* DX11Buffer::CreateFromMemory ( const std::wstring& name, const uint @attention Funkcja nie nadaje si� do wykonania wielow�tkowego. U�ywa DeviceContextu do kopiowania danych w zwi�zku z czym wymaga synchronizacji z innymi funkcjami renderuj�cymi. */ -MemoryChunk DX11Buffer::CopyData() +MemoryChunk DX11Buffer::CopyData() { // Trzeba stworzy� nowy bufor D3D11_BUFFER_DESC bufferDesc; @@ -114,7 +112,7 @@ MemoryChunk DX11Buffer::CopyData() return MemoryChunk(); // Kopiowanie zawarto�ci mi�dzy buforami - device_context->CopyResource( newBuffer, m_buffer ); + device_context->CopyResource( newBuffer, m_buffer.Get() ); D3D11_MAPPED_SUBRESOURCE data; result = device_context->Map( newBuffer, 0, D3D11_MAP::D3D11_MAP_READ, 0, &data ); @@ -129,3 +127,7 @@ MemoryChunk DX11Buffer::CopyData() return std::move( memoryChunk ); } + + +} // sw + diff --git a/DX11API/DX11Resources/DX11Buffer.h b/DX11API/DX11Resources/DX11Buffer.h index 90f4297e7499320c6c827b7925640d4a744c5741..ed501eda696840902985fa8b085dbe5bc64dfdd9 100644 GIT binary patch delta 522 zcmZut%}N4c6g}fOhEmZl^v@Ip>cT-5j>R$tD- zF0N340~bE)s?TH30WQ!W%49TH&7g)Q3?U(B+O#ZdZ;OoCTjp$s4409bVlr;2K3vPY z)-g=jFy%HfD^HQC%;*bQRf~rniqt&E23dR9!75*t*rIloa9A^umy&)Y&-&azz`T*H zF)1HXDmI|<}McTd;cGM30=|v delta 226 zcmbOyFokae598!A#tV~6m=>^dGFUNiPL^br=JsbuV#s1hWk_ZynQY9Qj>4bGEYHX} z`7E>K4|g91<_pCON- zn4tv729YU16;=%8V0IBuM;=4^ +#include "swCommonLib/Common/Converters.h" +#include "swCommonLib/System/File.h" +#include "swGraphicAPI/Resources/Shaders/Exceptions/CompilationException.h" +namespace sw +{ + //====================================================================================// // Template for choosing shader creation function. //====================================================================================// @@ -49,65 +60,143 @@ HRESULT CreateShader< ID3D11ComputeShader > ( ID3D11Device* device, ID3D // ================================ // // template< typename ShaderType, typename DXShaderType > -static Nullable< ShaderType* > CreateShader ( ID3D11Device* device, const std::wstring& fileName, const std::string& shaderName, const char* shaderModel, const CompilationConfig& config ) +static Nullable< ShaderType* > CreateShader ( ID3D11Device* device, const std::wstring& fileName, const std::string& shaderName, const CompilationConfig& config ) +{ + std::string code = filesystem::File::Load( fileName ); + return CreateShader< ShaderType, DXShaderType >( device, code, shaderName, config ); +} + +// ================================ // +// +template< typename ShaderType, typename DXShaderType > +static Nullable< ShaderType* > CreateShader ( ID3D11Device* device, const std::string& code, const std::string& entrypoint, const CompilationConfig& config ) { - auto result = DX11Compiler::CompileShader( fileName, shaderName, shaderModel, config ); + auto compilationResult = DX11Compiler::CompileShader( code, entrypoint, config ); - if( result.IsValid ) + if( compilationResult.IsValid() ) { - auto compiledShader = result.Value; - DXShaderType* vertexShader = nullptr; + auto compiledShader = compilationResult.Get(); + DXShaderType* shader = nullptr; - HRESULT result = CreateShader< DXShaderType >( device, compiledShader.Get(), &vertexShader ); + HRESULT result = CreateShader< DXShaderType >( device, compiledShader.Get(), &shader ); if( FAILED( result ) ) - return "Compiling shader [" + Convert::ToString( fileName ) + "], entry point [" + shaderName + "] failed."; + return "Creating shader failed."; - return new ShaderType( vertexShader ); + return new ShaderType( AssetPath( "", "" ), shader ); } else { - return Nullable< ShaderType* >( std::move( result.ErrorString ) ); + return Nullable< ShaderType* >( std::move( compilationResult.GetError() ) ); } } +// ================================ // +// +Nullable< DX11VertexShader* > DX11Compiler::CreateVertexShader ( const std::string& code, const std::string& entrypoint, const CompilationConfig& config ) +{ + return CreateShader< DX11VertexShader, ID3D11VertexShader >( device, code, entrypoint, config ); +} + +// ================================ // +// +Nullable< DX11PixelShader* > DX11Compiler::CreatePixelShader ( const std::string& code, const std::string& entrypoint, const CompilationConfig& config ) +{ + return CreateShader< DX11PixelShader, ID3D11PixelShader >( device, code, entrypoint, config ); +} + +// ================================ // +// +Nullable< DX11ComputeShader* > DX11Compiler::CreateComputeShader ( const std::string& code, const std::string& entrypoint, const CompilationConfig& config ) +{ + return CreateShader< DX11ComputeShader, ID3D11ComputeShader >( device, code, entrypoint, config ); +} // ================================ // // -Nullable< DX11VertexShader* > DX11Compiler::CreateVertexShader ( const std::wstring& fileName, const std::string& shaderName, const char* shaderModel, const CompilationConfig& config ) +Nullable< DX11VertexShader* > DX11Compiler::CreateVertexShader ( const std::wstring& fileName, const std::string& shaderName, const CompilationConfig& config ) { - return CreateShader< DX11VertexShader, ID3D11VertexShader >( device, fileName, shaderName, shaderModel, config ); + return CreateShader< DX11VertexShader, ID3D11VertexShader >( device, fileName, shaderName, config ); } // ================================ // // -Nullable< DX11PixelShader* > DX11Compiler::CreatePixelShader ( const std::wstring& fileName, const std::string& shaderName, const char* shaderModel, const CompilationConfig& config ) +Nullable< DX11PixelShader* > DX11Compiler::CreatePixelShader ( const std::wstring& fileName, const std::string& shaderName, const CompilationConfig& config ) { - return CreateShader< DX11PixelShader, ID3D11PixelShader >( device, fileName, shaderName, shaderModel, config ); + return CreateShader< DX11PixelShader, ID3D11PixelShader >( device, fileName, shaderName, config ); } // ================================ // // -Nullable< DX11ComputeShader* > DX11Compiler::CreateComputeShader ( const std::wstring& fileName, const std::string& shaderName, const char* shaderModel, const CompilationConfig & config ) +Nullable< DX11ComputeShader* > DX11Compiler::CreateComputeShader ( const std::wstring& fileName, const std::string& shaderName, const CompilationConfig & config ) { - return CreateShader< DX11ComputeShader, ID3D11ComputeShader >( device, fileName, shaderName, shaderModel, config ); + return CreateShader< DX11ComputeShader, ID3D11ComputeShader >( device, fileName, shaderName, config ); } // ================================ // // -Nullable< ComPtr< ID3D10Blob > > DX11Compiler::CompileShader ( const std::wstring& fileName, const std::string& shaderName, const char* shaderModel, const CompilationConfig& config ) +Nullable< ComPtr< ID3D10Blob > > DX11Compiler::CompileShader ( const std::wstring& fileName, const std::string& shaderName, const CompilationConfig& config ) +{ + std::string code = filesystem::File::Load( fileName ); + return CompileShader( code, shaderName, config ); +} + +// ================================ // +// +Nullable< ComPtr< ID3D10Blob > > DX11Compiler::CompileShader ( const std::string& code, const std::string& entrypoint, const CompilationConfig& config ) { ComPtr< ID3D10Blob > compiledShader = nullptr; ComPtr< ID3D10Blob > errorBlob = nullptr; - UINT flags = D3DCOMPILE_ENABLE_STRICTNESS; + UINT flags = D3DCOMPILE_ENABLE_STRICTNESS; if( config.Debug ) flags |= D3DCOMPILE_DEBUG; - HRESULT hr = D3DCompileFromFile( fileName.c_str(), nullptr, D3D_COMPILE_STANDARD_FILE_INCLUDE, shaderName.c_str(), shaderModel, flags, 0, &compiledShader, &errorBlob ); + std::string shaderModel = config.ShaderModel.ToString(); + + HRESULT hr = D3DCompile( code.c_str(), code.size(), nullptr, nullptr, D3D_COMPILE_STANDARD_FILE_INCLUDE, entrypoint.c_str(), shaderModel.c_str(), flags, 0, &compiledShader, &errorBlob ); if( FAILED( hr ) ) - return std::string( (char*)errorBlob->GetBufferPointer() ); + return CompilationException::Create( (char*)errorBlob->GetBufferPointer() ); return Nullable< ComPtr< ID3D10Blob > >( std::move( compiledShader ) ); } + + +namespace impl +{ + +// ================================ // +// +std::string ShaderTypeToString ( ShaderType type ) +{ + switch( type ) + { + case ShaderType::VertexShader: + return "vs"; + case ShaderType::PixelShader: + return "ps"; + case ShaderType::ComputeShader: + return "cs"; + case ShaderType::GeometryShader: + return "gs"; + case ShaderType::TesselationControlShader: + return "hs"; + case ShaderType::TesselationEvaluationShader: + return "ds"; + } + return ""; +} + +} // impl + + +// ================================ // +// +std::string ShaderModelDesc::ToString () const +{ + return impl::ShaderTypeToString( this->Type ) + "_" + Convert::ToString( this->Major ) + "_" + Convert::ToString( this->Minor ); +} + +} // sw + diff --git a/DX11API/DX11Resources/DX11Compiler.h b/DX11API/DX11Resources/DX11Compiler.h index 000a4fd..fcac19c 100644 --- a/DX11API/DX11Resources/DX11Compiler.h +++ b/DX11API/DX11Resources/DX11Compiler.h @@ -14,38 +14,75 @@ #include "DX11Resources/DX11ComputeShader.h" +namespace sw +{ + +// ================================ // +// +struct ShaderModelDesc +{ + ShaderType Type; + uint8 Major; + uint8 Minor; + +// ================================ // +// + ShaderModelDesc( ShaderType type ) + : Major( 5 ) + , Minor( 0 ) + , Type( type ) + {} + +// ================================ // +// + std::string ToString () const; +}; + + // ================================ // // struct CompilationConfig { - bool Debug; + ShaderModelDesc ShaderModel; + bool Debug; // ================================ // // - CompilationConfig() + CompilationConfig( ShaderType shaderType ) : Debug( false ) + , ShaderModel( shaderType ) {} }; -/**@brief Shader compiler.*/ +/**@brief Shader compiler. +@ingroup DX11API*/ class DX11Compiler : public DX11APIObjects { private: protected: public: explicit DX11Compiler () = default; - ~DX11Compiler () = default; + ~DX11Compiler () = default; - static Nullable< DX11VertexShader* > CreateVertexShader ( const std::wstring& fileName, const std::string& shaderName, const char* shaderModel, const CompilationConfig& config ); - static Nullable< DX11PixelShader* > CreatePixelShader ( const std::wstring& fileName, const std::string& shaderName, const char* shaderModel, const CompilationConfig& config ); - static Nullable< DX11ComputeShader* > CreateComputeShader ( const std::wstring& fileName, const std::string& shaderName, const char* shaderModel, const CompilationConfig& config ); + static Nullable< DX11VertexShader* > CreateVertexShader ( const std::string& code, const std::string& entrypoint, const CompilationConfig& config ); + static Nullable< DX11PixelShader* > CreatePixelShader ( const std::string& code, const std::string& entrypoint, const CompilationConfig& config ); + static Nullable< DX11ComputeShader* > CreateComputeShader ( const std::string& code, const std::string& entrypoint, const CompilationConfig& config ); + + + static Nullable< DX11VertexShader* > CreateVertexShader ( const std::wstring& fileName, const std::string& shaderName, const CompilationConfig& config ); + static Nullable< DX11PixelShader* > CreatePixelShader ( const std::wstring& fileName, const std::string& shaderName, const CompilationConfig& config ); + static Nullable< DX11ComputeShader* > CreateComputeShader ( const std::wstring& fileName, const std::string& shaderName, const CompilationConfig& config ); public: - static Nullable< ComPtr< ID3D10Blob > > CompileShader ( const std::wstring& fileName, const std::string& shaderName, const char* shaderModel, const CompilationConfig& config ); + static Nullable< ComPtr< ID3D10Blob > > CompileShader ( const std::wstring& fileName, const std::string& shaderName, const CompilationConfig& config ); + static Nullable< ComPtr< ID3D10Blob > > CompileShader ( const std::string& code, const std::string& entrypoint, const CompilationConfig& config ); }; + +} // sw + diff --git a/DX11API/DX11Resources/DX11ComputeShader.cpp b/DX11API/DX11Resources/DX11ComputeShader.cpp index b40f72c105100d1b2159fd678d18c7e5d041df35..74674c17d62ae1cc53e9f2245376efb87a24d729 100644 GIT binary patch delta 713 zcma)4&nrYx6h800naq7}gm@NSdZQ5|W2CIcuO`V(LbePuqA;3yk~C{OrL(ZJv`}iw zKY;A9u%l#W!QbFJ*TZ5gbQkyBd(U^i?>pz-cpn|LBh#wT9+#|Mu9@~v{A6}?HIhx+ zl&38!QiXO9ts+Vw-XnQC;5YMPOp&4#Zda*<>zBWC+w@Ht%J1eOpGJoH#p=E+M9)osjW%dg%iY&f ziV&a03T1FkxtxvJ8k+aSh`i3wE>N2gxT4Xcl;9;J$yZjy80UxB#K0uX6;StIX2CKM zm39>PShezOqs=?2xxa|^1XQMdw6X-9a{9J*5E={>@uM2@q^a|0U0ySnX+a~4qF6Vp z$4PU>UJgg*a?ObGnVs=9Gqk3G|AUiV$LB>S)s#Y8zxfr0Ip`$$$jSQCKm{}frDfRrBw0$x6k^f#akebpA`0UC!pVXFHq fd}q5#l<9ixH@G|#kMpb9)-E-xs5*%C`w>3@Vh@m| delta 642 zcmZ`$&r8B!7=E3b?uUZ{A#{{FA=Fgr)FIMC)GeVR4?>8Tnlx9;#Df&ksZ$^?bc^T| zbr7R_hyIHGi0DtK-fucwkc@5LzCF+T{P@1Y@7nN&!=R)~QOH38qM+l8H;$iN7(e(6 zyybMfRCo;XIlL0mN*j)#0*6oo3-5hRToy`d6Y4gz1!bsWU!KPT@AFGwfA?ddc!oyr z62+jq0&RLGAPH-rf(&CA(X`iRVZhr+ZR3>tDi> z67X*k<^)=}E^7bq9;N)g%P$m2yhY+^N?9eIX{)d`%Va@{_TBhx!my+U?I&%sy^&?y zkXLXZUsG>0IP{2ERI)pDa?1j`Rov62?N3xDzSyh=KFJw;Q__l~Eol1sQWtuNF+UHv_?x4BD+ zY07fVc6VN$nR#aR@1G|&w#qWQv>|_kjjXhu<@VSfS=ZKC+HKiaD{R1dusu7om#kf6 zhiFgjit|(JqkqA!vJLi8EA!hvk`kxZoZKpeT*0p{6?s*&It8lpqc8{<#U}bm~I%Q_53OFD+KBn*#-CUx_64pT!HON2xNpyv`V98mUVHY{<%L~)_HuBiN_1+($Ka{#4b~2c z{1xBw9uM}`I=+S=ny)~67DVszCIs`bw^3Y!PTf2O;lSe8{7 zFlKd|34g~9&{NFKQq}@}8OXWrG*e3cTVBhJ+EUDUu-g`k=Ia;eh!HDRvhgbx=bVnn z*98+@j2O-)dz6dVMsQWLNUYVX5_#0&w9S);`PuPIrguc%9_H&Bv_jL4NBdKv5!yEI z7x|j!QF>7){t{{$4C%|wIaVc^BRpvSi5Z%Di*ggWB96uh*+Wuqmu%jBht%iycYt`Q zF5jgJxm(R=HPcj7T~f{FV_V!KccW2X(e YCG~E5R@~N{Qr`645=)oWyj$t!AES$JssI20 delta 478 zcmZvYPfJ2U6vdDB{`driM9{Yhu?V#mDNsPug`dd4-00_%lNmO#Q1VpOlyd1AwrmH&W4_b_tJl9>?b4UxFh6qN z^adyr%6SW!KNNOINbzW}UgS#hWgAuGxfYlue*9WqC#6R@R@^*VDD{iB{ZBH=97g!E TZ%&VqJuvOaH^$xwr$YJ#Jhfz? diff --git a/DX11API/DX11Resources/DX11InputLayout.cpp b/DX11API/DX11Resources/DX11InputLayout.cpp index a2e4700..667747e 100644 --- a/DX11API/DX11Resources/DX11InputLayout.cpp +++ b/DX11API/DX11Resources/DX11InputLayout.cpp @@ -6,26 +6,275 @@ #include "swGraphicAPI/DX11API/stdafx.h" #include "DX11InputLayout.h" - -#include "swCommonLib/Common/MemoryLeaks.h" +#include "DX11Compiler.h" RTTR_REGISTRATION { - rttr::registration::class_< DX11InputLayout >( "DX11InputLayout" ); + rttr::registration::class_< sw::DX11InputLayout >( "sw::DX11InputLayout" ); } -DX11InputLayout::DX11InputLayout( ID3D11InputLayout* layout ) + +namespace sw { - m_vertexLayout = layout; -} +// ================================ // +// +DX11InputLayout::DX11InputLayout ( const AssetPath& fileName, ID3D11InputLayout* layout ) + : ShaderInputLayout( fileName ) + , m_vertexLayout( layout ) +{} + +// ================================ // +// DX11InputLayout::~DX11InputLayout() { - if( m_vertexLayout ) - m_vertexLayout->Release(); m_vertexLayout = nullptr; } + + + +//====================================================================================// +// Layout +//====================================================================================// + + +// ================================ // +// +class DX11LayoutTranslator +{ + typedef std::vector< D3D11_INPUT_ELEMENT_DESC > LayoutVec; +private: + + LayoutVec m_inputElement; + +public: + + explicit DX11LayoutTranslator ( const InputLayoutDescriptor& layoutDesc ); + + LayoutVec GetDX11LayoutDesc () const { return m_inputElement; } + std::string GenerateShader () const; + +public: + + LayoutVec Translate ( const InputLayoutDescriptor& layoutDesc ) const; + D3D11_INPUT_ELEMENT_DESC Translate ( const sw::LayoutEntry& entry ) const; + const char* Translate ( sw::AttributeSemantic semantic ) const; + +private: + D3D11_INPUT_ELEMENT_DESC CreateRow ( const char* semanticName, ResourceFormat format, unsigned int inputSlot, + unsigned int byteOffset, bool perInstance, unsigned int instanceDataStep ) const; + Size CountSemantic ( const char* semanticName ) const; + +private: + + std::string GenerateMain () const; + std::string GenerateInputStruct ( const LayoutVec& layout ) const; + std::string GenerateAttribute ( const D3D11_INPUT_ELEMENT_DESC& attribute ) const; + std::string InputStructName () const { return "InputVS"; } + std::string MapSemanticToType ( DXGI_FORMAT format ) const; +}; + + + +// ================================ // +// +DX11LayoutTranslator::DX11LayoutTranslator ( const InputLayoutDescriptor& layoutDesc ) + : m_inputElement( Translate( layoutDesc ) ) +{} + +// ================================ // +// +std::string DX11LayoutTranslator::GenerateShader () const +{ + std::string vertexLayout = GenerateInputStruct( m_inputElement ); + vertexLayout += GenerateMain(); + + return vertexLayout; +} + + +// ================================ // +// +DX11LayoutTranslator::LayoutVec DX11LayoutTranslator::Translate ( const InputLayoutDescriptor& layoutDesc ) const +{ + LayoutVec elements; + + for( auto& element : layoutDesc.GetEntries() ) + elements.push_back( Translate( element ) ); + + return elements; +} + +// ================================ // +// +D3D11_INPUT_ELEMENT_DESC DX11LayoutTranslator::Translate ( const sw::LayoutEntry& entry ) const +{ + return CreateRow( Translate( entry.SemanticName ), entry.AttribFormat, entry.InputSlot, entry.ByteOffset, entry.PerInstance, entry.InstanceDataStep ); +} + +// ================================ // +// +const char* DX11LayoutTranslator::Translate ( sw::AttributeSemantic semantic ) const +{ + + static std::pair< sw::AttributeSemantic, const char* > SemanticsMap[] = + { + std::make_pair( sw::AttributeSemantic::Position, "POSITION" ), + std::make_pair( sw::AttributeSemantic::Normal, "NORMAL" ), + std::make_pair( sw::AttributeSemantic::Tangent, "TANGENT" ), + std::make_pair( sw::AttributeSemantic::Binormal, "BINORMAL" ), + std::make_pair( sw::AttributeSemantic::BlendIndicies, "BLENDINDICES" ), + std::make_pair( sw::AttributeSemantic::BlendWeights, "BLENDWEIGHT" ), + std::make_pair( sw::AttributeSemantic::Color, "COLOR" ), + std::make_pair( sw::AttributeSemantic::Texcoord, "TEXCOORD" ), + std::make_pair( sw::AttributeSemantic::PositionTransformed, "POSITIONT" ), + std::make_pair( sw::AttributeSemantic::PointSize, "PSIZE" ) + }; + + for( auto& pair : SemanticsMap ) + if( pair.first == semantic ) + return pair.second; + + return ""; +} + +// ================================ // +// +D3D11_INPUT_ELEMENT_DESC DX11LayoutTranslator::CreateRow ( const char* semanticName, ResourceFormat format, unsigned int inputSlot, unsigned int byteOffset, bool perInstance, unsigned int instanceDataStep ) const +{ + D3D11_INPUT_ELEMENT_DESC inputElement; + inputElement.SemanticName = semanticName; + inputElement.Format = DX11ConstantsMapper::Get( format ); + inputElement.InputSlot = inputSlot; + inputElement.AlignedByteOffset = byteOffset; + inputElement.InstanceDataStepRate = instanceDataStep; + if( perInstance ) + inputElement.InputSlotClass = D3D11_INPUT_CLASSIFICATION::D3D11_INPUT_PER_INSTANCE_DATA; + else + inputElement.InputSlotClass = D3D11_INPUT_CLASSIFICATION::D3D11_INPUT_PER_VERTEX_DATA; + inputElement.SemanticIndex = (UINT)CountSemantic( semanticName ); + + return inputElement; +} + +// ================================ // +// +Size DX11LayoutTranslator::CountSemantic ( const char* semanticName ) const +{ + return std::count_if( m_inputElement.begin(), m_inputElement.end(), [ semanticName ]( const D3D11_INPUT_ELEMENT_DESC& element ) + { + return strcmp( element.SemanticName, semanticName ) == 0; + } ); +} + +// ================================ // +// +std::string DX11LayoutTranslator::GenerateMain () const +{ + std::string main; + main = "struct OutputVS {};\n"; + main += "OutputVS main()\n"; + main += "{\n"; + main += "return (OutputVS)0;\n"; + main += "}\n"; + + return main; +} + +// ================================ // +// +std::string DX11LayoutTranslator::GenerateInputStruct ( const LayoutVec& layout ) const +{ + std::string layoutStruct = "struct " + InputStructName(); + layoutStruct += "\n{\n"; + + for( auto& attrib : layout ) + { + layoutStruct += GenerateAttribute( attrib ); + layoutStruct += "\n"; + } + + layoutStruct += "\n};\n"; + + return layoutStruct; +} + +// ================================ // +// +std::string DX11LayoutTranslator::GenerateAttribute ( const D3D11_INPUT_ELEMENT_DESC& attribute ) const +{ + std::string fullSemanticStr = attribute.SemanticName + Convert::ToString( attribute.SemanticIndex ); + + std::string attributeEntry; + + attributeEntry = MapSemanticToType( attribute.Format ); + attributeEntry += " m" + fullSemanticStr + " : " + fullSemanticStr + ";"; + + return attributeEntry; +} + +// ================================ // +// +std::string DX11LayoutTranslator::MapSemanticToType ( DXGI_FORMAT format ) const +{ + switch( format ) + { + case DXGI_FORMAT::DXGI_FORMAT_R8G8B8A8_UINT: + return "uint4"; + case DXGI_FORMAT::DXGI_FORMAT_R8G8_UINT: + return "uint2"; + case DXGI_FORMAT::DXGI_FORMAT_R32G32B32A32_FLOAT: + return "float4"; + case DXGI_FORMAT::DXGI_FORMAT_R32G32B32_FLOAT: + return "float3"; + case DXGI_FORMAT::DXGI_FORMAT_R32G32_FLOAT: + return "float2"; + case DXGI_FORMAT::DXGI_FORMAT_R32_FLOAT: + return "float"; + } + return "float4"; +} + + +// ================================ // +// +sw::Nullable< DX11InputLayout* > DX11InputLayout::CreateLayout ( const AssetPath& fileName, const InputLayoutDescriptor& layoutDesc ) +{ + DX11LayoutTranslator layoutTranslator( layoutDesc ); + + std::string shaderCode = layoutTranslator.GenerateShader(); + sw::CompilationConfig config( ShaderType::VertexShader ); + +#ifdef _DEBUG + config.Debug = true; +#endif + + auto compiledBlob = sw::DX11Compiler::CompileShader( shaderCode, "main", config ); + + if( !compiledBlob.IsValid() ) + { +#ifdef _DEBUG + OutputDebugStringA( compiledBlob.GetErrorReason().c_str() ); +#endif + return compiledBlob.GetError(); + } + + auto& compiledShader = compiledBlob.Get(); + auto DX11layout = layoutTranslator.GetDX11LayoutDesc(); + + ID3D11InputLayout* DX11layoutInterface = nullptr; + + HRESULT result = device->CreateInputLayout( DX11layout.data(), (UINT)DX11layout.size(), compiledShader->GetBufferPointer(), compiledShader->GetBufferSize(), &DX11layoutInterface ); + + if( FAILED( result ) ) + return "[DX11InputLayout] Can't create layout."; + + return new DX11InputLayout( fileName, DX11layoutInterface ); +} + + +} // sw \ No newline at end of file diff --git a/DX11API/DX11Resources/DX11InputLayout.h b/DX11API/DX11Resources/DX11InputLayout.h index 8fbe60f..77ad338 100644 --- a/DX11API/DX11Resources/DX11InputLayout.h +++ b/DX11API/DX11Resources/DX11InputLayout.h @@ -2,24 +2,44 @@ /** @file DX11InputLayout.h @author nieznanysprawiciel -@copyright Plik jest cz�ci� silnika graficznego SWEngine. +@copyright File is part of Sleeping Wombat Libraries. */ + +#include "swCommonLib/Common/Exceptions/Nullable.h" + #include "swGraphicAPI/Resources/MeshResources.h" +#include "swGraphicAPI/Resources/Shaders/LayoutInitData.h" #include "DX11Initializer/DX11APIObjects.h" -/**@brief Implementacja layout w DirectX 11. + + +namespace sw +{ + + +/**@brief DirectX 11 implementation of input layout. @ingroup DX11API*/ class DX11InputLayout : public ShaderInputLayout, protected DX11APIObjects { RTTR_ENABLE( ShaderInputLayout ); private: - ID3D11InputLayout* m_vertexLayout; + + ComPtr< ID3D11InputLayout > m_vertexLayout; + protected: - ~DX11InputLayout(); + + virtual ~DX11InputLayout (); + +public: + + explicit DX11InputLayout ( const AssetPath& fileName, ID3D11InputLayout* layout ); + + static sw::Nullable< DX11InputLayout* > CreateLayout ( const AssetPath& fileName, const InputLayoutDescriptor& layoutDesc ); + public: - DX11InputLayout( ID3D11InputLayout* layout ); - inline ID3D11InputLayout* Get() { return m_vertexLayout; } + inline ID3D11InputLayout* Get () { return m_vertexLayout.Get(); } }; +} // sw diff --git a/DX11API/DX11Resources/DX11InputLayoutDescriptor.cpp b/DX11API/DX11Resources/DX11InputLayoutDescriptor.cpp deleted file mode 100644 index b3b7ddb..0000000 --- a/DX11API/DX11Resources/DX11InputLayoutDescriptor.cpp +++ /dev/null @@ -1,44 +0,0 @@ -/** -@file DX11InputLayoutDescriptor.cpp -@author nieznanysprawiciel -@copyright File is part of graphic engine SWEngine. -*/ -#include "swGraphicAPI/DX11API/stdafx.h" - - -#include "DX11InputLayoutDescriptor.h" -#include "DX11Initializer/DX11ConstantsMapper.h" - -#include - -#include "swCommonLib/Common/MemoryLeaks.h" - - - -void DX11InputLayoutDescriptor::AddRow( const char* semanticName, ResourceFormat format, unsigned int inputSlot, unsigned int byteOffset, bool perInstance, unsigned int instanceDataStep ) -{ - D3D11_INPUT_ELEMENT_DESC inputElement; - inputElement.SemanticName = semanticName; - inputElement.Format = DX11ConstantsMapper::Get( format ); - inputElement.InputSlot = inputSlot; - inputElement.AlignedByteOffset = byteOffset; - inputElement.InstanceDataStepRate = instanceDataStep; - if( perInstance ) - inputElement.InputSlotClass = D3D11_INPUT_CLASSIFICATION::D3D11_INPUT_PER_INSTANCE_DATA; - else - inputElement.InputSlotClass = D3D11_INPUT_CLASSIFICATION::D3D11_INPUT_PER_VERTEX_DATA; - inputElement.SemanticIndex = CountSemantic( semanticName ); - - m_inputElement.push_back( inputElement ); -} - -unsigned int DX11InputLayoutDescriptor::CountSemantic( const char* semanticName ) -{ - unsigned int numSemantic = 0; - - for( auto element : m_inputElement ) - if( strcmp( element.SemanticName, semanticName ) == 0 ) - ++numSemantic; - - return numSemantic; -} diff --git a/DX11API/DX11Resources/DX11InputLayoutDescriptor.h b/DX11API/DX11Resources/DX11InputLayoutDescriptor.h deleted file mode 100644 index 0b20a60..0000000 --- a/DX11API/DX11Resources/DX11InputLayoutDescriptor.h +++ /dev/null @@ -1,31 +0,0 @@ -#pragma once - -#include "DX11Initializer/DX11APIObjects.h" -#include "swGraphicAPI/Resources/MeshResources.h" - -#include - - -/**@brief Deskryptor layoutu dla DirectX 11. -@ingroup DX11API*/ -class DX11InputLayoutDescriptor : public InputLayoutDescriptor -{ -private: - std::vector m_inputElement; -public: - DX11InputLayoutDescriptor( const std::wstring& layoutName ) : InputLayoutDescriptor( layoutName ) {} - ~DX11InputLayoutDescriptor() = default; - - Size GetNumElements() { return m_inputElement.size(); } - D3D11_INPUT_ELEMENT_DESC* GetDescriptorPtr() { return m_inputElement.data(); } - - virtual void AddRow( const char* semanticName, - ResourceFormat format, - unsigned int inputSlot, - unsigned int byteOffset, - bool perInstance, - unsigned int instanceDataStep ); - - unsigned int CountSemantic( const char* semanticName ); -}; - diff --git a/DX11API/DX11Resources/DX11PipelineState.cpp b/DX11API/DX11Resources/DX11PipelineState.cpp index cbaf675..36bde27 100644 --- a/DX11API/DX11Resources/DX11PipelineState.cpp +++ b/DX11API/DX11Resources/DX11PipelineState.cpp @@ -11,39 +11,38 @@ RTTR_REGISTRATION { - rttr::registration::class_< DX11RasterizerState >( "DX11RasterizerState" ); - rttr::registration::class_< DX11DepthStencilState >( "DX11DepthStencilState" ); - rttr::registration::class_< DX11BlendingState >( "DX11BlendingState" ); + rttr::registration::class_< sw::DX11RasterizerState >( "sw::DX11RasterizerState" ); + rttr::registration::class_< sw::DX11DepthStencilState >( "sw::DX11DepthStencilState" ); + rttr::registration::class_< sw::DX11BlendingState >( "sw::DX11BlendingState" ); } +namespace sw +{ + + //====================================================================================// // RasterizerState //====================================================================================// -DX11RasterizerState::DX11RasterizerState( ComPtr< ID3D11RasterizerState > state, const RasterizerStateInfo& info ) - : m_state( state ) - , m_info( info ) -{ } +DX11RasterizerState::DX11RasterizerState ( const AssetPath& assetPath, ComPtr< ID3D11RasterizerState > state, const RasterizerStateInfo& info ) + : RasterizerState( assetPath ) + , m_state( state ) + , m_info( info ) +{} -// ================================ // -// -std::string DX11RasterizerState::GetResourceName() const -{ - return std::string(); -} // ================================ // // -const RasterizerStateInfo& DX11RasterizerState::GetDescriptor() +const RasterizerStateInfo& DX11RasterizerState::GetDescriptor () const { return m_info; } // ================================ // // -DX11RasterizerState* DX11RasterizerState::Create ( const RasterizerStateInfo& info ) +sw::Nullable< DX11RasterizerState* > DX11RasterizerState::Create ( const AssetPath& assetPath, const RasterizerStateInfo& info ) { D3D11_RASTERIZER_DESC desc; desc.CullMode = DX11ConstantsMapper::Get( info.CullMode ); @@ -60,9 +59,9 @@ DX11RasterizerState* DX11RasterizerState::Create ( const RasterizerStateInfo& ComPtr< ID3D11RasterizerState > state; auto result = device->CreateRasterizerState( &desc, state.GetAddressOf() ); if( FAILED( result ) ) - return nullptr; + return "[DX11RasterizerState] Creation failed."; - return new DX11RasterizerState( state, info ); + return new DX11RasterizerState( assetPath, state, info ); } @@ -71,28 +70,22 @@ DX11RasterizerState* DX11RasterizerState::Create ( const RasterizerStateInfo& // DepthStencilState //====================================================================================// -DX11DepthStencilState::DX11DepthStencilState( ComPtr< ID3D11DepthStencilState > state, const DepthStencilInfo& info ) - : m_state( state ) - , m_info( info ) -{ } - -// ================================ // -// -std::string DX11DepthStencilState::GetResourceName() const -{ - return std::string(); -} +DX11DepthStencilState::DX11DepthStencilState ( const AssetPath& assetPath, ComPtr< ID3D11DepthStencilState > state, const DepthStencilInfo& info ) + : DepthStencilState( assetPath ) + , m_state( state ) + , m_info( info ) +{} // ================================ // // -const DepthStencilInfo& DX11DepthStencilState::GetDescriptor() +const DepthStencilInfo& DX11DepthStencilState::GetDescriptor () const { return m_info; } // ================================ // // -DX11DepthStencilState* DX11DepthStencilState::Create ( const DepthStencilInfo& info ) +sw::Nullable< DX11DepthStencilState* > DX11DepthStencilState::Create ( const AssetPath& assetPath, const DepthStencilInfo& info ) { D3D11_DEPTH_STENCIL_DESC desc; desc.DepthEnable = info.EnableDepthTest; @@ -113,9 +106,9 @@ DX11DepthStencilState* DX11DepthStencilState::Create ( const DepthStencilInf ComPtr< ID3D11DepthStencilState > state; auto result = device->CreateDepthStencilState( &desc, state.GetAddressOf() ); if( FAILED( result ) ) - return nullptr; + return "[DX11DepthStencilState] Creation failed."; - return new DX11DepthStencilState( state, info ); + return new DX11DepthStencilState( assetPath, state, info ); } @@ -124,28 +117,22 @@ DX11DepthStencilState* DX11DepthStencilState::Create ( const DepthStencilInf // BlendingState //====================================================================================// -DX11BlendingState::DX11BlendingState( ComPtr< ID3D11BlendState > state, const BlendingInfo& info ) - : m_state( state ) - , m_info( info ) +DX11BlendingState::DX11BlendingState ( const AssetPath& assetPath, ComPtr< ID3D11BlendState > state, const BlendingInfo& info ) + : BlendingState( assetPath ) + , m_state( state ) + , m_info( info ) {} // ================================ // // -std::string DX11BlendingState::GetResourceName() const -{ - return std::string(); -} - -// ================================ // -// -const BlendingInfo& DX11BlendingState::GetDescriptor() +const BlendingInfo& DX11BlendingState::GetDescriptor () const { return m_info; } // ================================ // // -DX11BlendingState* DX11BlendingState::Create ( const BlendingInfo & info ) +sw::Nullable< DX11BlendingState* > DX11BlendingState::Create ( const AssetPath& assetPath, const BlendingInfo& info ) { D3D11_BLEND_DESC desc; desc.IndependentBlendEnable = false; @@ -164,7 +151,11 @@ DX11BlendingState* DX11BlendingState::Create ( const BlendingInfo & info ) ComPtr< ID3D11BlendState > state; auto result = device->CreateBlendState( &desc, state.GetAddressOf() ); if( FAILED( result ) ) - return nullptr; + return "[DX11BlendingState] Creation failed."; - return new DX11BlendingState( state, info ); + return new DX11BlendingState( assetPath, state, info ); } + +} // sw + + diff --git a/DX11API/DX11Resources/DX11PipelineState.h b/DX11API/DX11Resources/DX11PipelineState.h index 02d682e..e98d1a5 100644 --- a/DX11API/DX11Resources/DX11PipelineState.h +++ b/DX11API/DX11Resources/DX11PipelineState.h @@ -5,11 +5,13 @@ @copyright File is part of graphic engine SWEngine. */ +#include "swCommonLib/Common/Exceptions/Nullable.h" + #include "DX11Initializer/DX11APIObjects.h" -#include "swGraphicAPI/Resources/BlendingState.h" -#include "swGraphicAPI/Resources/DepthStencilState.h" -#include "swGraphicAPI/Resources/RasterizerState.h" +#include "swGraphicAPI/Resources/PipelineStates/BlendingState.h" +#include "swGraphicAPI/Resources/PipelineStates/DepthStencilState.h" +#include "swGraphicAPI/Resources/PipelineStates/RasterizerState.h" // ComPtr @@ -18,29 +20,44 @@ using namespace Microsoft::WRL; +namespace sw +{ + + +//====================================================================================// +// DX11RasterizerState +//====================================================================================// + + /**@brief RasterizerState DirectX11. @ingroup DX11API*/ class DX11RasterizerState : public RasterizerState, protected DX11APIObjects { RTTR_ENABLE( RasterizerState ); private: + ComPtr< ID3D11RasterizerState > m_state; RasterizerStateInfo m_info; protected: - ~DX11RasterizerState() = default; + + virtual ~DX11RasterizerState() = default; + public: - explicit DX11RasterizerState ( ComPtr< ID3D11RasterizerState > state, const RasterizerStateInfo& info ); - - ID3D11RasterizerState* Get () { return m_state.Get(); } + explicit DX11RasterizerState ( const AssetPath& assetPath, ComPtr< ID3D11RasterizerState > state, const RasterizerStateInfo& info ); + + ID3D11RasterizerState* Get () { return m_state.Get(); } // Inherited via RasterizerState - virtual std::string GetResourceName () const override; - virtual const RasterizerStateInfo& GetDescriptor () override; + virtual const RasterizerStateInfo& GetDescriptor () const override; - static DX11RasterizerState* Create ( const RasterizerStateInfo& info ); + static sw::Nullable< DX11RasterizerState* > Create ( const AssetPath& assetPath, const RasterizerStateInfo& info ); }; +//====================================================================================// +// DX11DepthStencilState +//====================================================================================// + /**@brief Depth stencil state DirectX11. @ingroup DX11API*/ @@ -54,38 +71,49 @@ class DX11DepthStencilState : public DepthStencilState, public DX11APIObjects protected: ~DX11DepthStencilState() = default; public: - explicit DX11DepthStencilState ( ComPtr< ID3D11DepthStencilState > state, const DepthStencilInfo& info ); - - ID3D11DepthStencilState* Get () { return m_state.Get(); } + explicit DX11DepthStencilState ( const AssetPath& assetPath, ComPtr< ID3D11DepthStencilState > state, const DepthStencilInfo& info ); + + ID3D11DepthStencilState* Get () { return m_state.Get(); } // Inherited via DepthStencilState - virtual std::string GetResourceName () const override; - virtual const DepthStencilInfo& GetDescriptor () override; + virtual const DepthStencilInfo& GetDescriptor () const override; - static DX11DepthStencilState* Create ( const DepthStencilInfo& info ); + static sw::Nullable< DX11DepthStencilState* > Create ( const AssetPath& assetPath, const DepthStencilInfo& info ); }; +//====================================================================================// +// DX11BlendingState +//====================================================================================// + + /**@brief Blending state DirectX11. @ingroup DX11API*/ class DX11BlendingState : public BlendingState, public DX11APIObjects { RTTR_ENABLE( BlendingState ); private: + ComPtr< ID3D11BlendState > m_state; BlendingInfo m_info; protected: - ~DX11BlendingState() = default; + + virtual ~DX11BlendingState () = default; + public: - explicit DX11BlendingState ( ComPtr< ID3D11BlendState > state, const BlendingInfo& info ); - - ID3D11BlendState* Get () { return m_state.Get(); } + explicit DX11BlendingState ( const AssetPath& assetPath, ComPtr< ID3D11BlendState > state, const BlendingInfo& info ); + + + ID3D11BlendState* Get () { return m_state.Get(); } // Inherited via BlendingState - virtual std::string GetResourceName () const override; - virtual const BlendingInfo& GetDescriptor () override; + virtual const BlendingInfo& GetDescriptor () const override; - static DX11BlendingState* Create ( const BlendingInfo& info ); + static sw::Nullable< DX11BlendingState* > Create ( const AssetPath& assetPath, const BlendingInfo& info ); }; + +} // sw + + diff --git a/DX11API/DX11Resources/DX11PixelShader.cpp b/DX11API/DX11Resources/DX11PixelShader.cpp index d00bc71b72b1f275d0767efe9078a238e5e4ca34..4eae84b3a61f89c1f6f43e7cc6278f2ffc2d149e 100644 GIT binary patch delta 741 zcma)4O-mb56g{Dnk0-4&lcHinoPbzk8b1o96eU6kCE%i1^$$dypx{SIrUa2JT)ML5 zt|~3~2MUFX3-J$h)m7KsblJZkcsIrp4%-@ozmksmoH*+dJon3cep zxKjr|>&|Ix>!3Ox1j&_^(lTLEEyQ&`DYEgL^KhxE^}>ie}qLM zBW&O~zt(!b7NwOa#SLW`DW`_yljmf6cjYi)dm0qwb26*DdA5Ht6dk&Nl?cowyc9at1P4+TJEZnSYIH;^y<)c6nKY^+`mPotBRA1Ga4^Y z`Mi8jm!>OpxK1{8`~c5nACPBm!DupyE6U&gVR_|xFG402p@BUnyGxDw)^%xtqgdRh$edX6;R v2vg{AYv)PK)0uYaIWuzP4a8O1oE)Tvr9b_+&|$viRc^i8>@dyi_IzFex%!PT literal 5092 zcmdUzNpBlR5QU2e9~dA%Ah(GO1c~5~2z+xENV4TXfH#QVkRT9-o5P445nN1*hV!R= zPx8I)X-^M59NQ6sfEbV*b$3<2dR1Ljt-t?j+dj|d_L&{n&_*`4fhBgwp4)dkj~IEy z$k;meyQS9WeP%7|*_6jirM9#Mvlq-HmLV~)HNPpJOPjN9#`}u#o|_xzay=xbte7$S z0{I2fcX{^+Mo1>ir_5{S0(1%Mq-)A*X-n8CV{F8?P!R_E_1^C7p-Ze1b$^ApAWCMW4Ng@X=!bJ*QI)ROt=U+xQFeb+Wgyd4jE;5wRYm zw(Tlwywn8Q%sCUFu=eut$b)s zrz3@_xt-Y$a91D4iTz|>vuf`H>-JdljeYO1ym8;MAoy$7*jKFi7^`Pzx8uv#g#+@3 z^7FuD-;hb`?N%JsuTadKu;wP8?Nw%Ysf7BEPKMyH2%wr>`8>zQ=fg-U)g)Pnxd?>iiZ? zZ{eFFugix;ZjaBG&mE81S3Sp?u0!2im;DEH9>P|iE!0z{tePU#ci4S5DV$ScWQ3L_ z{fiLj^URI=ozy?}-F(81M~yEUeR~U%gt4N#N~wE)peJ!N>JlzjVF6lw7f8jo`jZqr(&2fTgH!u0!KASTXvPk2 z=&t7_^zpudk5RtM0eh;0mS2BmkIa5UW9ah>f9q}S@W-6qVC|ZZyz~|=>Z4@Wns3FE zto688FeuOZF?l%7+}`49Eb+Q(JVThsz~Fr(OaYJB6GuM6#je&Z7@07mco8afeDd}R zd>YrU{?2mz(h{RcYq^V8-bah#V~mEwMrwB&JuvjBS>j0g&+};0O-CK5e0q&ln+&No z1YLoxaz6aUc}Je?@sSmZ0=(9c56&6Ue#KdO3ND@30rjy{s-n98blv*69{AYzF@5Qx zruy6zp1yR5w7d50VpktD)hEl_^l|;eex42Mvw||&Z5NaB?|@8Qt}x1|s=5C*2P)30 zWfg64_KYJUMDV7xVnXL|v!{t8D6WXj{LbcYf5n|eH@VE6U*#i@PpA1s-d!vI=}tLx zaj6^g8QJyNj_e6{1kE-}QY~hS{HCr+wk;X+Rrfk?8M>q~SMf8|7SU4NBKk@Q(=dqyPO}Yy1Qmn zk*hsf)=|df?JQy;uI_EHT=m|Txc@MS?{Iq$u~QuzSIY~V{n4)FhjMl(`>o3Ng}43z Dsj>|c diff --git a/DX11API/DX11Resources/DX11PixelShader.h b/DX11API/DX11Resources/DX11PixelShader.h index 3f2a0aa67e199157302648ca1d1984eb3388aabd..34acd98e9ed0470b6503d2824ab8f10b75ed53a0 100644 GIT binary patch delta 729 zcmZWnO-mb56g|mgj9L^@5e-H2QfaACGhpe)hE@?3iWb4ru16hBAYUXSYK!frTWQ1n z4aJopxb9ErLJ$gyb|tv+KX~rTfKqwPyqR;)z31NZ-qGW;)X(8Q4>_(LbYmJDD4~o% z_B*oQ@+d~Ak1d4!tDymdDmei@bNBh|qKP_jAKS#&Y^)sRtudocMuX@k^FwCO^P39% zDlyYA?lZ2D8r2O}Y&1Z9l7uSL3_dYb!77PLTO__}1+{FzB6%y9gV#!Dmu4-w!gn>I zdbp2yn8ObHqyo#8EUyUS?c%V%-zPp5y{N}ptP%!<{~RyEO3bK7cu(Rb_OPt3?+ z?6_Y&?26QuS-pV*jQH`9E`v9WaLI3H$RSS-;u*PidXpB#SNYMAaodcmcqSFF$2$9H zI~p=C=49nEIXE^$@g|!Hv1|<~;yD}gAE4t_`I)?PKK5(f1)I}WYwP@SUOvi4_zR56 zU+0x{CW?Fp<$L0ToF=9+(S2ZbJ?D@$DwyJmw56x>iA=k>v>KxL|1K7IlSUj)FZ*sf zspqiH+x0Iwka{qOoV#yby)o-@<4zO;o}W6nOCM_VLH`U!@!A@{7wzi!9;frT?vCXa Dhck=c literal 2352 zcmc(f?Q7Fe6vofj2>uVD1DQoOML%^2b2_Eq=2-o(Z=;Qwt8{Hh+D<3)Pgj4>y-Rab z(^1#1WHd)~0O#qHKgFK_I`p7C_?KeQ>MZzJAU*vqk7 z?t9-KY+zs5NjOQ`KEZ8;vvC`bjUdMmDLgR0-Sxv zUP{HVkMTallJ|GQzmRS@F1zfE(KB~CWbUkI;*qw&E>sD&``9jm6GscLy})N|9gBD} zbR9Si67DpgeZr0+I)RNxmx5e)LkxAbgyy@$6cMG5JjZrw`*uiN_v}5h&6WOQdu%)I zuDlLy4kvl;+}P{l`8h-SG$U?1ZV@p!4O9>LSN7|yN*_NK?3z7n1{f;^%iE4_Q}|;d6uXR@y6PJ9cbj6dUAqW)|8sojSeg+X zW%Pjjm@xBR{9CmJ%$m?~7qE6_#}oMNZLbLr+{s7ijs-WhW#afoGg3q@GnvPlcCxvZ%c z)E}$*YtFK=1|oZnuBp41u8hLnQL8&NGZxyAZ`kun&dawG*Q0X!YCZc8&_$V{Onb>_ zp;AG0zhFG&ud0s7>3lyb-EVxCxmLOHf0Qcg_|IHd-uF;@x~QQtUS&n7dpAdY-8@(C zQMU=RqU;Sm#>@4w!wuho)ERC=9oA?a`D)zj#K2c*6Y_nkTG{>$jLOfDRf(X&e|^*8 G6oKEf33EjN diff --git a/DX11API/DX11Resources/DX11RenderTarget.cpp b/DX11API/DX11Resources/DX11RenderTarget.cpp index 7853cef6d80dfbc5649d2c523d19eb11517f1fb8..6043cf775680805ef075abf0bf116307dc5bfa6e 100644 GIT binary patch delta 2241 zcmcImUrbw77(dq*DA3YUq@`f#ZRtv>>^8*-9WVsfF<78>g%$?ts8A*Z3evL8Ox)nX zY%_6Yzr^_DpO=NF&85p+qKQ8EVEi+Q@yVD)AAHemI^&ZM>UU0Wp%F}+$#Qb<`R+O2 z_nqJOo$vh4{q%k5+DFoRw;$4^*$Ldy?t)%Zwkfx2EJ$f}&J;_qd6r~pwn)+>NixYN zn1PkCQ~Zr{W_xx*b6vuiRd4U1$uuctScKFw?0M!P1JwzBD6(N7^a!S<8r)QLh!$O! zeDFtYP>Ma6DDI}OKuM$2j(ekZ<=z6z-O)N&N;QV_Ap!XASgKWeY=;p*d2{kUt*y3?)Kl(`=c{CuwAcEs!Lu z?iNT&Q)UxnGe-$qqHjLWGp#Tm^NYZErrW87$qUy@u;+w!Cxv@Y>n!q-RTmPmT@@%e!?2x zwDwZYwl<`cBI0GROg)c!r&SboQ0N>Woh8DuMA)0M7iyrfCD}>UILUg%bb`IeT3865 zJ74hs>ns}-iQ>sl6R>%)B}r7<|H5MJ9z0#&EBc@6!>DL0#x=R6G$u5Uu_P)3Gq~-D zT)E12j98MsI;!gJ!jv8)ij+ zqrrzYqgfz$$L&U^CzPFauSrq|R*h9EFjKbPlQQB`cP};`uYfLi2%c6i-fYkHXAd?b z(q_S*G?tV5@J3sW(Ep8kUGOD(;<($fNAweWgJc`Wvq2BecAY2rHDR|wW88kDBP#mt zpc{*wZdI0XtFuM*dkCq0+;5@J8od03N%fb?$pV)d;cgS|wg-iuNE`nSseVSOugI45 zd{#b~FOq&Lql`ExoK5C7`6X9&ek!qP+I4=E(o`wD^pmvz{P5(NhzQ ztJYJPIC9xg$V35Dj`vs#N4A(t%#|0+!8qQ7Crd0<|0K%)hS?dIrZ_TG>5GK1on#k1 zkJ2-&j`g#UsD5HL(&HC~4s-lDOoKiM2Y!MaF*@C{m1=4SfY!6$pn2!6Y@F>om*huWVYa Pke#2})^7**#hSt5xsH{ZSIp7Z;i zbI<+mIXAx&UwtTN5r^H&-e_vf>v-{f8}=YQi~l1f3=)#>^(%GrNTq z!jj;5)Y2}j`kLi86T0nf=&CT`QuR%S*buL+(XZ8PD+e_?OG}jH69uT3G=vYm^9Y@) z|9f45k*RC;tT1VTbItO)!ef=`uTlqVWO^H7k#$S>uJZ6niCJQu#+V$PXE{e1 z8WK6ytnp428eAGSO&Tgey*G(ElDSA#pwSh;H0HBwQ)>}q|uPgr7K#kTzDdZfPz2O6HwU z;hv_kw5v_?{GvB1{f1gP!vFd3|HBo0>_3bT+`i(G`4Z6CzRbs#(oVa-n9vPRJ>uSo zzTtjb2n}=2fZplN9>kTSm@^esJ}fhj8a+hZV$YG&3+R;8E~__Vfeov8pgF}r2kUi z@;ndy`S?5ocrR4D=dZAj6#2*XSU6v$XmkWWkGOC#(S|=$4frYEhRtLx8eN@OjyVw; zNf$9;Y1f0J=fobVG3hl(*)gxane>UWK6GKyh2`Tum`*fcJ$1Fr`e}*v{j_s?V!N~{ z>01**=%y1Lf_sevFAZAsnMsR~uPQV3u3YXtle5q6GsfN7uqVw``RINy#1$Ol5v6fdsZG{X+_+Y_ W?JOcW*HkZ?&slC;$Bc{%x&H-%vy{~U diff --git a/DX11API/DX11Resources/DX11RenderTarget.h b/DX11API/DX11Resources/DX11RenderTarget.h index c7194d524a8aa4745424773aae67f1ac8c1a9a30..0545308a35be9e4759474fbc9d132620ce2201fb 100644 GIT binary patch delta 831 zcmZ`%OKTHh6g`u4($0w8l_A!KFEtp=BGU*(h((mDD=oz?6c>eQNFR_)hnY$11Mvrl zV7Pz4y|~exR2S|Q`U8~uFI;-=m*AtNT)vt4?&F+u@129-%k1mQOo#^UEPUL+CU($6 z7e)??)fY`{kNpt_$a&jE3WJzgT|DJG;(3A$3H=fF>F?NBZ(P@5MZ%1f-YwSWtiHo< z%fWZXd&0`pMs~?>ux6uOBv+Uav&`TDVfxr$q5|Bdf5Q?gY?mNSOV>a+ELZO>+vGl< z@i;ZazrGN+@t8WvK)4;7mm$Ood+gC7f~!95etuX!tmX)H-C=k+*5bceOP7W8DUG xu8Zr}>vlHO`=45zn1QVMZ-e`GDg*8>hJI)EPsqhP^WmJ%P|tH}32A@V{u_-ap&bAK delta 377 zcmX>ky+?e4+~j+V5|bw|Zkb%fBqHg_kjqfOki(D)q*EF47)lrt8Il>Y7!oJ%W|EaG zWl&%!2Vxh7Ook$$d@@izg29l%aPoDgXjV=JD+bQV=FIAx{tQV#JwW-%(afbtytB-T zn?EsIF-}fm7Gkwx;AP;NoXDy_c?zo#Bj;p6W<^Gg$=qyjx#8LwN+y42vqj+>v!n9! z+2wgP8LUBOF>r!SROA$$yn$VdSA#(lC<29(-?OJmJu6qr diff --git a/DX11API/DX11Resources/DX11SwapChain.cpp b/DX11API/DX11Resources/DX11SwapChain.cpp index 14dfe98..3c3eb76 100644 --- a/DX11API/DX11Resources/DX11SwapChain.cpp +++ b/DX11API/DX11Resources/DX11SwapChain.cpp @@ -1,8 +1,9 @@ /** @file DX11SwapChain.cpp @author nieznanysprawiciel -@copyright File is part of graphic engine SWEngine. +@copyright File is part of Sleeping Wombat Libraries. */ + #include "swGraphicAPI/DX11API/stdafx.h" @@ -11,17 +12,24 @@ RTTR_REGISTRATION { - rttr::registration::class_< DX11SwapChain >( "DX11SwapChain" ); + rttr::registration::class_< sw::DX11SwapChain >( "sw::DX11SwapChain" ); } +namespace sw +{ + +// ================================ // +// DX11SwapChain::DX11SwapChain( IDXGISwapChain* chain, DX11RenderTarget* windowRT ) - : SwapChain( windowRT ) - , m_swapChain( chain ) -{ } + : SwapChain( windowRT ) + , m_swapChain( chain ) +{} +// ================================ // +// DX11SwapChain::~DX11SwapChain() { if( m_swapChain ) @@ -48,10 +56,13 @@ void DX11SwapChain::Resize( uint16 newWidth, uint16 newHeight ) @todo Wersja troszk� niew�a�ciwa. SwapChain jest ju� stworzony wcze�niej przy zwyk�ej inicjalizacji DX11APIObjects. Tutaj jest jedynie tworzony obiekt silnikowy, kt�ry potrafi to obs�u�y�. Trzeba to zmieni�, �eby ca�e tworzenie render targetu odbywa�o si� tutaj.*/ -DX11SwapChain* DX11SwapChain::CreateScreenSwapChain( RenderTargetObject* screenRT ) +DX11SwapChain* DX11SwapChain::CreateScreenSwapChain( RenderTarget* screenRT ) { - DX11SwapChain* swapChainObject = new DX11SwapChain( swap_chain, static_cast< DX11RenderTarget* >( screenRT ) ); + DX11SwapChain* swapChainObject = new DX11SwapChain( swap_chain, static_cast( screenRT ) ); swap_chain = nullptr; return swapChainObject; } + +} // sw + diff --git a/DX11API/DX11Resources/DX11SwapChain.h b/DX11API/DX11Resources/DX11SwapChain.h index 28f3b07..cb34f22 100644 --- a/DX11API/DX11Resources/DX11SwapChain.h +++ b/DX11API/DX11Resources/DX11SwapChain.h @@ -1,11 +1,27 @@ #pragma once +/** +@file DX11SwapChain.h +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + + + #include "swGraphicAPI/DX11API/DX11Initializer/DX11APIObjects.h" #include "swGraphicAPI/Resources/SwapChain.h" #include "DX11RenderTarget.h" -class DX11SwapChain : public SwapChain, protected DX11APIObjects + + +namespace sw +{ + + +// ================================ // +// +class DX11SwapChain : public SwapChain, protected DX11APIObjects { RTTR_ENABLE( SwapChain ) private: @@ -20,6 +36,8 @@ class DX11SwapChain : public SwapChain, protected DX11APIObjects virtual void Resize ( uint16 newWidth, uint16 newHeight ) override; public: - static DX11SwapChain* CreateScreenSwapChain ( RenderTargetObject* screenRT ); + static DX11SwapChain* CreateScreenSwapChain ( RenderTarget* screenRT ); }; + +} // sw \ No newline at end of file diff --git a/DX11API/DX11Resources/DX11Texture.cpp b/DX11API/DX11Resources/DX11Texture.cpp index 27a7833..6bf6aa1 100644 --- a/DX11API/DX11Resources/DX11Texture.cpp +++ b/DX11API/DX11Resources/DX11Texture.cpp @@ -1,13 +1,15 @@ /** @file DX11Texture.cpp @author nieznanysprawiciel -@copyright File is part of graphic engine SWEngine. +@copyright File is part of Sleeping Wombat Libraries. */ + #include "swGraphicAPI/DX11API/stdafx.h" #include "DX11Texture.h" #include "DX11Initializer/DX11ConstantsMapper.h" +#include "DX11Initializer/DX11Utils.h" #include "swCommonLib/Common/MemoryLeaks.h" @@ -16,9 +18,11 @@ RTTR_REGISTRATION { - rttr::registration::class_< DX11Texture >( "DX11Texture" ); + rttr::registration::class_< sw::DX11Texture >( "sw::DX11Texture" ); } +namespace sw +{ @@ -27,7 +31,7 @@ RTTR_REGISTRATION void DX11Texture::Construct() { if( IsDebugLayerEnabled() ) - { + { SetDebugName( m_texture.Get(), m_descriptor.FilePath.String() ); SetDebugName( m_textureView.Get(), m_descriptor.FilePath.String() ); } @@ -35,10 +39,11 @@ void DX11Texture::Construct() /**@brief Remember to release tex and texView (Call com interface Release method)*/ -DX11Texture::DX11Texture( TextureInfo&& texInfo, ID3D11Texture2D* tex, ID3D11ShaderResourceView* texView ) - : m_texture( tex ) - , m_textureView( texView ) - , m_descriptor( std::move( texInfo ) ) +DX11Texture::DX11Texture ( const AssetPath& name, TextureInfo&& texInfo, ID3D11Texture2D* tex, ID3D11ShaderResourceView* texView ) + : Texture( name ) + , m_texture( tex ) + , m_textureView( texView ) + , m_descriptor( std::move( texInfo ) ) { Construct(); } @@ -46,10 +51,11 @@ DX11Texture::DX11Texture( TextureInfo&& texInfo, ID3D11Texture2D* tex, ID3D11Sha // ================================ // // -DX11Texture::DX11Texture( TextureInfo&& texInfo, ComPtr< ID3D11Texture2D > tex, ComPtr< ID3D11ShaderResourceView > texView ) - : m_texture( tex ) - , m_textureView( texView ) - , m_descriptor( std::move( texInfo ) ) +DX11Texture::DX11Texture ( const AssetPath& name, TextureInfo&& texInfo, ComPtr< ID3D11Texture2D > tex, ComPtr< ID3D11ShaderResourceView > texView ) + : Texture( name ) + , m_texture( tex ) + , m_textureView( texView ) + , m_descriptor( std::move( texInfo ) ) { Construct(); } @@ -63,21 +69,76 @@ DX11Texture::~DX11Texture() } -/**@copydoc TextureObject::GetDescriptor.*/ -const TextureInfo& DX11Texture::GetDescriptor() const +/**@copydoc Texture::GetDescriptor.*/ +const TextureInfo& DX11Texture::GetDescriptor() const { return m_descriptor; } -/**@copydoc TextureObject::GetFilePath.*/ -const filesystem::Path& DX11Texture::GetFilePath() const + +// ================================ // +// +sw::Nullable< DX11Texture* > DX11Texture::CreateFromMemory ( const AssetPath& name, const BufferRaw& texData, TextureInfo&& texInfo ) { - return m_descriptor.FilePath; + if( texData.GetData() == nullptr ) + return "[DX11Texture] Can't create texture. Data field is nullptr."; + + /// @todo Trzeba zacz�� kiedy� ob��ugiwac inne typy tekstur. + assert( texInfo.TextureType == TextureType::Texture2D ); + if( texInfo.TextureType != TextureType::Texture2D ) + return "[DX11Texture] Can't create texture. Only Textures 2D are supported."; + + ComPtr< ID3D11Texture2D > texture = nullptr; + ComPtr< ID3D11ShaderResourceView > texView = nullptr; + D3D11_TEXTURE2D_DESC texDesc = FillDesc( texInfo ); + + std::unique_ptr< D3D11_SUBRESOURCE_DATA[] > initData( new D3D11_SUBRESOURCE_DATA[ texInfo.MipMapLevels /** texInfo.ArraySize*/ ] ); + uint16 mipWidth = texInfo.Width; + uint16 mipHeight = texInfo.Height; + PtrOffset offset = 0; + + for( int level = 0; level < texInfo.MipMapLevels; level++ ) + { + initData[ level ].pSysMem = texData.GetData() + offset; + initData[ level ].SysMemPitch = (uint32)mipWidth * BytesPerPixel( texInfo.Format ); + + offset += mipWidth * mipHeight * BytesPerPixel( texInfo.Format ); + + mipWidth /= 2; + mipHeight /= 2; + if( mipHeight == 0 ) mipHeight = 1; + if( mipWidth == 0 ) mipWidth = 1; + } + + HRESULT result = device->CreateTexture2D( &texDesc, initData.get(), &texture ); + if( result == S_OK ) + { + D3D11_SHADER_RESOURCE_VIEW_DESC viewDesc; + + if( texInfo.TextureType == TextureType::Texture2D ) + { + viewDesc.Format = texDesc.Format; + viewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; + viewDesc.Texture2D.MostDetailedMip = 0; + viewDesc.Texture2D.MipLevels = texInfo.MipMapLevels; + + result = device->CreateShaderResourceView( texture.Get(), &viewDesc, &texView ); + if( result == S_OK ) + return new DX11Texture( name, std::move( texInfo ), texture, texView ); + else + return "[DX11Texture] Can't create texture. Error: " + DX11Utils::ErrorString( result ); + } + + assert( !"Other texture types are not suported" ); + } + + return "[DX11Texture] Can't create texture. Error: " + DX11Utils::ErrorString( result ); } /**@brief Tworzy tekstur� z podanego wska�nika. +@deprecated Use functions taking BufferRaw as parameter. @return Zawraca stworzony wewn�trz obiekt DX11Texture z wczytan� tekstur� lub nullptr w przypadku niepowodzenia.*/ DX11Texture* DX11Texture::CreateFromMemory( const MemoryChunk& texData, TextureInfo&& texInfo ) { @@ -85,8 +146,8 @@ DX11Texture* DX11Texture::CreateFromMemory( const MemoryChunk& texData, TextureI return nullptr; /// @todo Trzeba zacz�� kiedy� ob��ugiwac inne typy tekstur. - assert( texInfo.TextureType == TextureType::TEXTURE_TYPE_TEXTURE2D ); - if( texInfo.TextureType != TextureType::TEXTURE_TYPE_TEXTURE2D ) + assert( texInfo.TextureType == TextureType::Texture2D ); + if( texInfo.TextureType != TextureType::Texture2D ) return nullptr; ComPtr< ID3D11Texture2D > texture = nullptr; @@ -94,8 +155,8 @@ DX11Texture* DX11Texture::CreateFromMemory( const MemoryChunk& texData, TextureI D3D11_TEXTURE2D_DESC texDesc = FillDesc( texInfo ); std::unique_ptr< D3D11_SUBRESOURCE_DATA[] > initData( new D3D11_SUBRESOURCE_DATA[ texInfo.MipMapLevels /** texInfo.ArraySize*/ ] ); - uint16 mipWidth = texInfo.TextureWidth; - uint16 mipHeight = texInfo.TextureHeight; + uint16 mipWidth = texInfo.Width; + uint16 mipHeight = texInfo.Height; PtrOffset offset = 0; for( int level = 0; level < texInfo.MipMapLevels; level++ ) @@ -116,7 +177,7 @@ DX11Texture* DX11Texture::CreateFromMemory( const MemoryChunk& texData, TextureI { D3D11_SHADER_RESOURCE_VIEW_DESC viewDesc; - if( texInfo.TextureType == TextureType::TEXTURE_TYPE_TEXTURE2D ) + if( texInfo.TextureType == TextureType::Texture2D ) { viewDesc.Format = texDesc.Format; viewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; @@ -125,11 +186,14 @@ DX11Texture* DX11Texture::CreateFromMemory( const MemoryChunk& texData, TextureI result = device->CreateShaderResourceView( texture.Get(), &viewDesc, &texView ); if( result == S_OK ) - return new DX11Texture( std::move( texInfo ), texture, texView ); - else + { + auto path = texInfo.FilePath; + return new DX11Texture( AssetPath( path, "" ), std::move( texInfo ), texture, texView ); + } + else return nullptr; } - + assert( !"Other texture types are not suported" ); } @@ -144,8 +208,8 @@ DX11Texture* DX11Texture::CreateFromMemory( const MemoryChunk& texData, TextureI MemoryChunk DX11Texture::CopyData() const { D3D11_TEXTURE2D_DESC texDesc = FillDesc( m_descriptor ); - texDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; - texDesc.Usage = D3D11_USAGE::D3D11_USAGE_STAGING; + texDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; + texDesc.Usage = D3D11_USAGE::D3D11_USAGE_STAGING; ID3D11Texture2D* newTex; @@ -174,7 +238,7 @@ MemoryChunk DX11Texture::CopyData() const device_context->Unmap( newTex, level ); } - + newTex->Release(); return std::move( memoryChunk ); @@ -186,25 +250,25 @@ D3D11_TEXTURE2D_DESC DX11Texture::FillDesc ( const TextureInfo& texInfo ) D3D11_TEXTURE2D_DESC texDesc; unsigned int ArraySize = 1; - if( texInfo.TextureType == TextureType::TEXTURE_TYPE_TEXTURE2D_ARRAY || texInfo.TextureType == TextureType::TEXTURE_TYPE_TEXTURE2D_MULTISAMPLE_ARRAY ) + if( texInfo.TextureType == TextureType::TextureArray2D || texInfo.TextureType == TextureType::TextureArray2DMultisample ) ArraySize = texInfo.ArraySize; - texDesc.Width = texInfo.TextureWidth; - texDesc.Height = texInfo.TextureHeight; - texDesc.MipLevels = texInfo.MipMapLevels; - texDesc.Usage = DX11ConstantsMapper::Get( texInfo.Usage ); - texDesc.ArraySize = ArraySize; - - - assert( texInfo.TextureType != TextureType::TEXTURE_TYPE_TEXTURE2D_MULTISAMPLE && texInfo.TextureType != TextureType::TEXTURE_TYPE_TEXTURE2D_MULTISAMPLE_ARRAY ); - texDesc.SampleDesc.Count = 1; - texDesc.SampleDesc.Quality = 0; - + texDesc.Width = texInfo.Width; + texDesc.Height = texInfo.Height; + texDesc.MipLevels = texInfo.MipMapLevels; + texDesc.Usage = DX11ConstantsMapper::Get( texInfo.Usage ); + texDesc.ArraySize = ArraySize; + + + assert( texInfo.TextureType != TextureType::Texture2DMultisample && texInfo.TextureType != TextureType::TextureArray2DMultisample ); + texDesc.SampleDesc.Count = 1; + texDesc.SampleDesc.Quality = 0; + texDesc.MiscFlags = 0; if( texInfo.IsCubeMap ) texDesc.MiscFlags |= D3D11_RESOURCE_MISC_TEXTURECUBE; if( texInfo.AllowShareResource ) - texDesc.MiscFlags |= D3D11_RESOURCE_MISC_SHARED ; + texDesc.MiscFlags |= D3D11_RESOURCE_MISC_SHARED; texDesc.CPUAccessFlags = 0; if( texInfo.CPURead ) @@ -225,8 +289,8 @@ D3D11_TEXTURE2D_DESC DX11Texture::FillDesc ( const TextureInfo& texInfo ) bool DX11Texture::UpdateData ( uint8* dataPtr, uint16 mipLevel, uint16 arrayIdx ) { // Texture must be updatable. - if( m_descriptor.Usage == ResourceUsage::RESOURCE_USAGE_STATIC || - m_descriptor.Usage == ResourceUsage::RESOURCE_USAGE_STAGING ) + if( m_descriptor.Usage == ResourceUsage::Static || + m_descriptor.Usage == ResourceUsage::Staging ) return false; if( mipLevel > m_descriptor.MipMapLevels || @@ -248,7 +312,7 @@ bool DX11Texture::UpdateData ( uint8* dataPtr, uint16 mipLevel, uint16 ar // mipLevel == 1 have index 0. uint16 subresourceIdx = ( mipLevel - 1 ) + m_descriptor.MipMapLevels * ( arrayIdx - 1 ); - if( m_descriptor.Usage == ResourceUsage::RESOURCE_USAGE_DYNAMIC ) + if( m_descriptor.Usage == ResourceUsage::Dynamic ) { D3D11_MAPPED_SUBRESOURCE updateData; HRESULT result = device_context->Map( m_texture.Get(), subresourceIdx, D3D11_MAP_WRITE_DISCARD, 0, &updateData ); @@ -262,7 +326,7 @@ bool DX11Texture::UpdateData ( uint8* dataPtr, uint16 mipLevel, uint16 ar } else { - // ResourceUsage::RESOURCE_USAGE_DEFAULT + // ResourceUsage::Default device_context->UpdateSubresource( m_texture.Get(), subresourceIdx, nullptr, dataPtr, MipRowSize( mipLevel ), 0 ); return true; } @@ -283,7 +347,7 @@ uint16 DX11Texture::MipWidth ( uint16 mipLevel ) const return 0; uint32 mipDivider = 0x1 << ( mipLevel - 1 ); // MipLevel = 1 means original texture level. - return m_descriptor.TextureWidth / mipDivider; + return m_descriptor.Width / mipDivider; } // ================================ // @@ -294,7 +358,7 @@ uint16 DX11Texture::MipHeight ( uint16 mipLevel ) const return 0; uint32 mipDivider = 0x1 << ( mipLevel - 1 ); // MipLevel = 1 means original texture level. - return m_descriptor.TextureWidth / mipDivider; + return m_descriptor.Width / mipDivider; } // ================================ // @@ -313,3 +377,4 @@ uint32 DX11Texture::MipLevelSize ( uint16 mipLevel ) const } +} // sw diff --git a/DX11API/DX11Resources/DX11Texture.h b/DX11API/DX11Resources/DX11Texture.h index 0a889505d4de59cc09b520ac34d97d5a8476fbc6..86831ea64d37643c570a41e939ffdcc9d407f36e 100644 GIT binary patch delta 871 zcmbVLO-mb56g`uSBpGZLDlH>KrY#Bvaipb-inLWxk(S0}L`*AE`VSng zYkxz*Z8t6c0e9W_7qTo}bkTEPCUn$Ap*-g6+;h)8_r5o0?(eaav0)!&t~+q>0^6ve zj!=#)_tP|X6Ewg9+WgwXK0HL^g!ss3!0Q8AXc7-_NW5xd^(3##j3ycTM0c3qX7)1Q zS%GggW_pYVjB8|%)jhm5(Gbl?Bt%T}u*pyZTO=y&74a=oP-R1kOq+6L__14xPwbUN z!*B2&C2SvQ%*PTsw8|n>tQlSlK3=oUI#)n_T8!U6TurC-3g47kVA3{MNJ}b`{$4jz z(K$Yd-OG{=tYI8$(^}tS%As+86kpw!8EfRR&ZR+PIwK`Vw5W~uZ1$(rW~4*(fK@|T zwBAg5n5A5kh?>`(=!wq~-?+y9X4SGDCgro^%6jG^rxwVPigQnTVfw0H` delta 334 zcmew(H&1ec+~g~aXC|Lw5^?op$Ym&C$YDqY(y0u23?&SS49N^xKvDt7PG!huCMEf6 zQyKh$GFcFvljk#M@+0wqYBeYO@=8utVL3AS1B=RJA=XVmT5Pfa+Z7PK*?^so2`mu9 z$uT*JGhp&7b^*_1hJ2utK@L=4NCR34@*c0B@c=2wwaVf)+d!5y79})r&swHcbMJATPT+^UlXJ^UUn4wReU0``U-^+BGc^ z%C0QRA`UV|T-B3(-7`FF>UnQl>he%p63Pyx1|^sBu2_uHodASIC@oX%Zu#c4Tkk zv;P8PY_?!s`+TFhA|eygolPlq#F;2Hc2e*t;Ns{8-| literal 10126 zcmeI2TW=Fb7>36esB)$L0PdC`AsW%7ReRNwk`SPgLO=vcRa8Ze?SP46B0EkRL;I(> zZ~H#;c`~!ht~V(mfP_|SduM09^Kr)i{}#vfwez zyG8$f)z51S{@C-8xjErDa(8ktm)(80rWHX3;dvzbI-+JrvRDxQIS&&FaF@Xj5UQn^ zLYW0&O+4*;DX)uyW61)EuZri9q=5YP^^E)@WoL&M*Vb`#Q@Hko({z<$ty+nkZPlLE z4&1udZcEDP*rK~Dj(9&5kL&u~a=YR%PZt;-xQDtPxGmkcq`x(3p66wKuDN?|!|UXw z|7;4{fv%zZUe{1iu@|(7RUYU!^zaVLXz9&JaDS9F)#)#DKfCLiH&;7zPP4vrKX`in z@}F?Qy{Id5KfUFZc{l+c-*vRZZ`~YtThpv>b{(m6Xh7Hif#X9*JH1Xh*UQ%t=iYRj;GJ+ z8YtP9_4Smm#>!Vv!Ts2e8!jrDj(?vC=St&pqvKwSmP}(Yo3KLxnZb+g;BK-g6{u_O7ERX6{aDzb6O>qL$A{>4xWvj5zTyOfn9G4H1|X}2JR0*3^gbCO{4spc=}VB-q75M zZuIn8P{`u&HPI(F1Gi`xxwSQVJRL*FX>LL*<&>ne%Bk6r90sDmGz3L~8f*dynGGXb z=218A=?&HbO;j7``bg9<&Nt74DfK`}sc3l{s;Bm@U|<`4tzT}m+-jpO3fjuZ$Oq`V zQ%j@XruIRfmo%#=9r9LyWwx>8WgVmJ@1hzVwspe+`j@^MNPkx&U^}~4QIT)^)oI2u zA28cK_SO^p$8?Qc@#T)Vqz~u`_ky|^tM==BdEUpex>-b`n_dQJud6s+%uQtbvqrFB zU)WIjS}ZAzeW_hktw!T`Sg{^U?IVqs&1v;*b$qOasmTZ4Gl?`tAAb6DT0`JNbQe3` z>gdY0l;dx?757NBIB%P|RSS9>BNz1^yp1(xnfj{NUdKaZwL!415+BFgvDv=XS!ENn z2Bm2qQq)#e=Y`ISkq2E=NjV*l(u~?O>BJhpUP8uWs1~o}cwA7`JyP#YJwwh7S+03f zQ8(4&x6yO~(cvadr^*)2#%LtSLQbSB;WmN23f>a55I**;%omDQBZB;%IrG7lq9 zlkpj?0m;0}3=a2XnAqQych@17)#duk5mmdE!Gm5*)gGOnn*wFuBTkEK$%(pEL zRC!lJ9!fxR!7fihlbtm?{t5yeeBG4Pak8CfCOSE z&`~ea*9bi&{l@HmAzhi;!9{clO+{PVF}|W0m{JmXIM05d8ppfu4Vu%_j!=gFnP>=rp~FK@7blyNE>zq#8GCDb5JCv@q?-^1Vvj-#(kKcXW=(smi)?cIXcx zk65kMyPQzbpRwb@NP04LHjH*!RV7pF#hbYkpK|y_kKj=$G-lIt3}w+|bavz5qpW8% zy~MMnE#ckJ$?GF^4_oR}*LC03z2TqPUD(uaMOBQvFT9*RgKd^vIZ?SIy2{T^4N7{( zvMJfq+vKfuLs@!H6j67vX9?GwRi7SvIfRJWr1OhE-Q1K+)+L3qeUOf@AA0-fI(SPx zt6X=)v{Yxo;*9s%x#qekK}!#{N07oO=VmsnqK~Cs7`3z_N$=>wrtT{`_D(DeS)DhA zpzV6t*G_H!;k+&%*>1aKNfH}hePfq~_!eW_%aa--m3XyZQFY{ZTgtpI-Lc7gd{qUA z=N)=I;NkgygUq5P-RlV+Qf;$U*h6iZX88YSF|*@;x#i{Uq8QKEt++NrHXnlp*cp3z zGPdWtul(uQKvA7NtMu%EUXz$hFKN3^>&&K!evG9L5REK94l^PtP7GEtd7=5bU<;L~Q$h_C3=MJ_Mu%sWtC qB|ke=i8WExysD1!d`^gCUs=_YQc0cv`AXV3navjUmY#1Fb@m_O3|=b$ diff --git a/DX11API/DX11Resources/DX11VertexShader.h b/DX11API/DX11Resources/DX11VertexShader.h index 270dd728652c5564ff466ac6d48bcd70762b2457..2ae8e5bdc4e9544391b13ceb2f2e3febd6a060bb 100644 GIT binary patch literal 2260 zcmbuATW`}q5QXQ}Nc@LYD8IhG-(SeKOOkatQ|Wj zZGw>H#NOSRGkeaN_3vM+HnhT0yRsg?!3Ng1wq^Fzo>r56 zO{TH$CD;n&%&}k>>5GQt*KNACyeV@ZbSW9xtyG^d zQ+ZH`O&1Dnll5{#fhJ?J)$WaZtJIg~De-bv#m+8ZQ{ZPeW(stWKdCuBSyIeQ&@#%T0Mb5!as!`&L|n%=B6ih9VS za#A16Wiv{PeXlX{66mu4tEx|DM4z|Ev|2BtBd5Xcr~ZgF&1w|z`hcraOXxb0x{T@E z-*dft(^FdWRb7M9FLI;45YZ(GqfHkqi?HQ9RbPXDN10Hu>WCHU_k1MLz(qR z^*tQc_=F*UV~jCEiVP3&z}#!-n~?#g_{i}XEfl!Iq1iRT z1?N+|z*}^&jT5dYXk*G*St&SnWS$o*=C-)IRg1EZQ#|3-C4L_z?*s$>ex<#fcHO+i zeuEGA%$bxc3wX=Uk8QMh?Q&I48yU{&NtZrPXfxw8BT7kxlvbp}B}a0OWcb3bf=mGnH~>US$| zns~FAHC`bp9hnSK97l{zQ;SmPkn2mvVq>mW#JI&K6H8NfBYxekV2m3R7grk*)mAQR zziKRIj*WQ@0t{95fMcqHS0=ZHeD*n(%~pw%`iG62vOxX9#_O&Kdq$xU=g&|s$wxd~ zW<}`H12GJ9Y86V%3R5pEsEQ(4(n^Qdm3fzUs_;jgJLkJpIHqOw5k ResourcesFactory::CreateVertexShader ( const AssetPath& fileName, const std::string& code, const std::string& entrypoint ) { - auto shader = VertexShaderObject::CreateFromFile( fileName, shaderName, shaderModel ); - if( shader ) - { - shader->SetFileName( fileName ); - shader->SetShaderName( shaderName ); - } - return shader; + return VertexShaderObject::CreateFromCode( fileName, code, entrypoint ); } -/**@brief Tworzy obiekt vertex shadera oraz layout wierzcho�ka. - -@param[in] fileName Nazwa pliku z kodem shadera. -@param[in] shaderName Nazwa funkcji, od kt�rej ma si� rozpocz�� wykonanie programu shadera. -@param[out] layout Zwraca obiekt layoutu. -@param[in] layoutDesc Deskryptor opisuj�cy layout. -@param[in] shaderModel Shader model. -@return Zwraca obiekt vertex shadera lub nullptr w przypadku niepowodzenia.*/ -VertexShader* ResourcesFactory::CreateVertexShaderFromFile ( const std::wstring& fileName, - const std::string& shaderName, - ShaderInputLayout** layout, - InputLayoutDescriptor* layoutDesc, - const char* shaderModel/* = "vs_4_0"*/ ) +// ================================ // +// +sw::Nullable< PixelShader* > ResourcesFactory::CreatePixelShader ( const AssetPath& fileName, const std::string& code, const std::string& entrypoint ) { - auto shader = VertexShaderObject::CreateFromFile( fileName, shaderName, layout, layoutDesc, shaderModel ); - if( shader ) - { - shader->SetFileName( fileName ); - shader->SetShaderName( shaderName ); - } - return shader; + return PixelShaderObject::CreateFromCode( fileName, code, entrypoint ); } -/**@brief Creates BlendingState.*/ -BlendingState* ResourcesFactory::CreateBlendingState ( const BlendingInfo& info ) +// ================================ // +// +sw::Nullable< ComputeShader* > ResourcesFactory::CreateComputeShader ( const AssetPath& fileName, const std::string& code, const std::string& entrypoint ) { - return BlendingStateObject::Create( info ); + return ComputeShaderObject::CreateFromCode( fileName, code, entrypoint ); } -/**@brief Creates RasterizerState*/ -RasterizerState* ResourcesFactory::CreateRasterizerState ( const RasterizerStateInfo& info ) +// ================================ // +// +sw::Nullable< ShaderInputLayout* > ResourcesFactory::CreateInputLayout ( const AssetPath& name, const InputLayoutDescriptor& layoutDesc ) { - return RasterizerStateObject::Create( info ); + return DX11InputLayout::CreateLayout( name, layoutDesc ); } -/**@brief Creates DepthStencilState.*/ -DepthStencilState* ResourcesFactory::CreateDepthStencilState ( const DepthStencilInfo& info ) +// ================================ // +// +sw::Nullable< Texture* > ResourcesFactory::CreateTextureFromMemory ( const AssetPath& fileName, const BufferRaw& texData, sw::TextureInfo&& texInfo ) { - return DepthStencilStateObject::Create( info ); + return TextureObject::CreateFromMemory( fileName, texData, std::move( texInfo ) ); } - -/**@brief Tworzy obekt pixel shadera. -@param[in] fileName Nazwa pliku z kodem shadera. -@param[in] shaderName Nazwa funkcji, od kt�rej ma si� rozpocz�� wykonanie programu shadera. -@param[in] shaderModel Shader model. -@return Zwraca obiekt vertex shadera lub nullptr w przypadku niepowodzenia.*/ -PixelShader* ResourcesFactory::CreatePixelShaderFromFile( const std::wstring& fileName, const std::string& shaderName, const char* shaderModel ) +/**@brief Creates BlendingState.*/ +sw::Nullable< BlendingState* > ResourcesFactory::CreateBlendingState ( const AssetPath& name, const BlendingInfo& info ) { - auto shader = PixelShaderObject::CreateFromFile( fileName, shaderName, shaderModel ); - if( shader ) - { - shader->SetFileName( fileName ); - shader->SetShaderName( shaderName ); - } - return shader; + return BlendingStateObject::Create( name, info ); } -/**@brief Tworzy obekt compute shadera. -@param[in] fileName Nazwa pliku z kodem shadera. -@param[in] shaderName Nazwa funkcji, od kt�rej ma si� rozpocz�� wykonanie programu shadera. -@param[in] shaderModel Shader model. -@return Zwraca obiekt vertex shadera lub nullptr w przypadku niepowodzenia.*/ -ComputeShader* ResourcesFactory::CreateComputeShaderFromFile ( const std::wstring& fileName, const std::string& shaderName, const char* shaderModel ) +/**@brief Creates RasterizerState*/ +sw::Nullable< RasterizerState* > ResourcesFactory::CreateRasterizerState ( const AssetPath& name, const RasterizerStateInfo& info ) { - return ComputeShaderObject::CreateFromFile( fileName, shaderName, shaderModel ); + return RasterizerStateObject::Create( name, info ); } +/**@brief Creates DepthStencilState.*/ +sw::Nullable< DepthStencilState* > ResourcesFactory::CreateDepthStencilState ( const AssetPath& name, const DepthStencilInfo& info ) +{ + return DepthStencilStateObject::Create( name, info ); +} -/**@brief Tworzy bufor na podstawie sanych w pami�ci. - -@param[in] name Buffer name or file path. -@param[in] data Pointer to initialization data. Memory can be released after call. -@param[in] bufferInfo Buffer descriptor. -@return Zwraca wska�nik na obiekt bufora lub nullptr w przypadku niepowodzenia.*/ -BufferObject* ResourcesFactory::CreateBufferFromMemory ( const std::wstring& name, const uint8* data, const BufferInfo& bufferInfo ) +// ================================ // +// +sw::Nullable< Buffer* > ResourcesFactory::CreateBufferFromMemory ( const AssetPath& name, const uint8* data, const BufferInfo& bufferInfo ) { - return Buffer::CreateFromMemory( name, data, bufferInfo ); + return BufferObject::CreateFromMemory( name, data, bufferInfo ); } -/**Tworzy object RenderTargetObject z bufora tylnego ekranu. +/**@brief Creates RenderTarget from screen buffer. -@return Zwraca object RenderTargetObject.*/ -RenderTargetObject* ResourcesFactory::CreateScreenRenderTarget() +@return Returns RenderTarget.*/ +RenderTarget* ResourcesFactory::CreateScreenRenderTarget() { return DX11RenderTarget::CreateScreenRenderTarget(); } // ================================ // // -SwapChain* ResourcesFactory::CreateScreenSwapChain( RenderTargetObject* screenRT ) +SwapChain* ResourcesFactory::CreateScreenSwapChain ( RenderTarget* screenRT ) { return DX11SwapChain::CreateScreenSwapChain( screenRT ); } // ================================ // // -IGraphicAPIInitializer* ResourcesFactory::CreateAPIInitializer() +IGraphicAPIInitializer* ResourcesFactory::CreateAPIInitializer () { return new DX11Initializer(); } -/**Tworzy obiekt deskryptora layoutu.*/ -InputLayoutDescriptor* ResourcesFactory::CreateInputLayoutDescriptor( const std::wstring& layoutName ) -{ - return new DX11InputLayoutDescriptor( layoutName ); -} - // ================================ // // -RenderTargetObject* ResourcesFactory::CreateRenderTarget( const std::wstring& name, const RenderTargetDescriptor& renderTargetDescriptor ) +sw::Nullable< RenderTarget* > ResourcesFactory::CreateRenderTarget ( const AssetPath& name, const RenderTargetDescriptor& renderTargetDescriptor ) { return DX11RenderTarget::CreateRenderTarget( name, renderTargetDescriptor ); } +} // sw diff --git a/DX11API/stdafx.h b/DX11API/stdafx.h index 50be106..c035b24 100644 --- a/DX11API/stdafx.h +++ b/DX11API/stdafx.h @@ -29,7 +29,6 @@ #include "DX11Resources/DX11Buffer.h" #include "DX11Resources/DX11ComputeShader.h" #include "DX11Resources/DX11InputLayout.h" -#include "DX11Resources/DX11InputLayoutDescriptor.h" #include "DX11Resources/DX11PixelShader.h" #include "DX11Resources/DX11RenderTarget.h" #include "DX11Resources/DX11SwapChain.h" diff --git a/GraphicAPI.sln b/GraphicAPI.sln index e1993d8..3f4acbf 100644 --- a/GraphicAPI.sln +++ b/GraphicAPI.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 14 -VisualStudioVersion = 14.0.25420.1 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.29209.62 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DX11API", "ProjectsDir\Visual2015\DX11API\DX11API.vcxproj", "{44643D7F-1C71-41C1-B452-B2DC5E088A58}" EndProject @@ -19,10 +19,40 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CommonBase", "..\swCommonLi EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MockAPI", "ProjectsDir\Visual2015\MockAPI\MockAPI.vcxproj", "{EEEFAB61-F404-4957-AC24-A3BF81C5E4ED}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{32AA682D-E5EE-4813-AFE8-E45D2EE62ED3}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{CCEBD2BA-27F7-4E13-AE56-841AE1C91B13}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TestResourceManager", "ProjectsDir\Visual2015\Tests\TestResourceManager\TestResourceManager.vcxproj", "{54F074CF-39C0-4FD6-BBEE-2DC880EB5C24}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TestResources.DX11", "ProjectsDir\Visual2015\Tests\TestResources\TestResources.DX11.vcxproj", "{22358F79-365C-477A-B485-1746C79EF6AA}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MockAssets", "ProjectsDir\Visual2015\MockAssets\MockAssets.vcxproj", "{FC28F28C-C54C-4F0C-BF70-43E7F4E7192E}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Assets", "Assets", "{AAC65EA8-DF18-44BB-811E-83B5E346B7C4}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Loaders", "Loaders", "{1F656768-1C78-4AFF-A865-C9A769D659F6}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "GraphicAPI", "GraphicAPI", "{66A269CE-8FB5-4D68-ABB4-CACA10A0700C}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "swMaterialLoader", "ProjectsDir\Visual2015\swMaterialLoader\swMaterialLoader.vcxproj", "{572003B3-3CC2-438E-9436-6B6EF9DC7BF5}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SoilTextureLoader", "ProjectsDir\Visual2015\SoilTextureLoader\SoilTextureLoader.vcxproj", "{7275758B-1ABC-4B28-BB42-CBDBCD2584D1}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MeshAsset", "ProjectsDir\Visual2015\MeshAsset\MeshAsset.vcxproj", "{406C51BB-C070-4B6A-8631-4C9A26CB1B2E}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MaterialAsset", "ProjectsDir\Visual2015\MaterialAsset\MaterialAsset.vcxproj", "{85BA6BD1-9CDC-451F-ADF8-A8CDE6443EAF}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "TestAssets", "TestAssets", "{F50E5C84-236D-4DF9-92EB-65E925769ADC}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "TestLoaders", "TestLoaders", "{DD05ED1D-D2B8-4273-8435-23C94A2FE6F5}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TestMipMapGenerator", "ProjectsDir\Visual2015\Tests\TestMipMapsGenerator\TestMipMapGenerator.vcxproj", "{CD54BACD-BC9B-40D8-8319-A3B4C6234073}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TestSoilTextureLoader.DX11", "ProjectsDir\Visual2015\Tests\TestSoilTextureLoader\TestSoilTextureLoader.DX11.vcxproj", "{20597CBF-CF6D-4D30-B0E3-2D289AF61143}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TestSoilTextureLoader", "ProjectsDir\Visual2015\Tests\TestSoilTextureLoader\TestSoilTextureLoader.vcxproj", "{A4A7B575-BCEE-43A6-A3F7-9831A2CCA253}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TestMaterial", "ProjectsDir\Visual2015\Tests\TestMaterial\TestMaterial.vcxproj", "{0FCBB0B0-0459-47F1-B93F-70E6BA6CA1A8}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 @@ -87,6 +117,14 @@ Global {EEEFAB61-F404-4957-AC24-A3BF81C5E4ED}.Release|x64.Build.0 = Release|x64 {EEEFAB61-F404-4957-AC24-A3BF81C5E4ED}.Release|x86.ActiveCfg = Release|Win32 {EEEFAB61-F404-4957-AC24-A3BF81C5E4ED}.Release|x86.Build.0 = Release|Win32 + {54F074CF-39C0-4FD6-BBEE-2DC880EB5C24}.Debug|x64.ActiveCfg = Debug|x64 + {54F074CF-39C0-4FD6-BBEE-2DC880EB5C24}.Debug|x64.Build.0 = Debug|x64 + {54F074CF-39C0-4FD6-BBEE-2DC880EB5C24}.Debug|x86.ActiveCfg = Debug|Win32 + {54F074CF-39C0-4FD6-BBEE-2DC880EB5C24}.Debug|x86.Build.0 = Debug|Win32 + {54F074CF-39C0-4FD6-BBEE-2DC880EB5C24}.Release|x64.ActiveCfg = Release|x64 + {54F074CF-39C0-4FD6-BBEE-2DC880EB5C24}.Release|x64.Build.0 = Release|x64 + {54F074CF-39C0-4FD6-BBEE-2DC880EB5C24}.Release|x86.ActiveCfg = Release|Win32 + {54F074CF-39C0-4FD6-BBEE-2DC880EB5C24}.Release|x86.Build.0 = Release|Win32 {22358F79-365C-477A-B485-1746C79EF6AA}.Debug|x64.ActiveCfg = Debug|x64 {22358F79-365C-477A-B485-1746C79EF6AA}.Debug|x64.Build.0 = Debug|x64 {22358F79-365C-477A-B485-1746C79EF6AA}.Debug|x86.ActiveCfg = Debug|Win32 @@ -95,15 +133,108 @@ Global {22358F79-365C-477A-B485-1746C79EF6AA}.Release|x64.Build.0 = Release|x64 {22358F79-365C-477A-B485-1746C79EF6AA}.Release|x86.ActiveCfg = Release|Win32 {22358F79-365C-477A-B485-1746C79EF6AA}.Release|x86.Build.0 = Release|Win32 + {FC28F28C-C54C-4F0C-BF70-43E7F4E7192E}.Debug|x64.ActiveCfg = Debug|x64 + {FC28F28C-C54C-4F0C-BF70-43E7F4E7192E}.Debug|x64.Build.0 = Debug|x64 + {FC28F28C-C54C-4F0C-BF70-43E7F4E7192E}.Debug|x86.ActiveCfg = Debug|Win32 + {FC28F28C-C54C-4F0C-BF70-43E7F4E7192E}.Debug|x86.Build.0 = Debug|Win32 + {FC28F28C-C54C-4F0C-BF70-43E7F4E7192E}.Release|x64.ActiveCfg = Release|x64 + {FC28F28C-C54C-4F0C-BF70-43E7F4E7192E}.Release|x64.Build.0 = Release|x64 + {FC28F28C-C54C-4F0C-BF70-43E7F4E7192E}.Release|x86.ActiveCfg = Release|Win32 + {FC28F28C-C54C-4F0C-BF70-43E7F4E7192E}.Release|x86.Build.0 = Release|Win32 + {572003B3-3CC2-438E-9436-6B6EF9DC7BF5}.Debug|x64.ActiveCfg = Debug|x64 + {572003B3-3CC2-438E-9436-6B6EF9DC7BF5}.Debug|x64.Build.0 = Debug|x64 + {572003B3-3CC2-438E-9436-6B6EF9DC7BF5}.Debug|x86.ActiveCfg = Debug|Win32 + {572003B3-3CC2-438E-9436-6B6EF9DC7BF5}.Debug|x86.Build.0 = Debug|Win32 + {572003B3-3CC2-438E-9436-6B6EF9DC7BF5}.Release|x64.ActiveCfg = Release|x64 + {572003B3-3CC2-438E-9436-6B6EF9DC7BF5}.Release|x64.Build.0 = Release|x64 + {572003B3-3CC2-438E-9436-6B6EF9DC7BF5}.Release|x86.ActiveCfg = Release|Win32 + {572003B3-3CC2-438E-9436-6B6EF9DC7BF5}.Release|x86.Build.0 = Release|Win32 + {7275758B-1ABC-4B28-BB42-CBDBCD2584D1}.Debug|x64.ActiveCfg = Debug|x64 + {7275758B-1ABC-4B28-BB42-CBDBCD2584D1}.Debug|x64.Build.0 = Debug|x64 + {7275758B-1ABC-4B28-BB42-CBDBCD2584D1}.Debug|x86.ActiveCfg = Debug|Win32 + {7275758B-1ABC-4B28-BB42-CBDBCD2584D1}.Debug|x86.Build.0 = Debug|Win32 + {7275758B-1ABC-4B28-BB42-CBDBCD2584D1}.Release|x64.ActiveCfg = Release|x64 + {7275758B-1ABC-4B28-BB42-CBDBCD2584D1}.Release|x64.Build.0 = Release|x64 + {7275758B-1ABC-4B28-BB42-CBDBCD2584D1}.Release|x86.ActiveCfg = Release|Win32 + {7275758B-1ABC-4B28-BB42-CBDBCD2584D1}.Release|x86.Build.0 = Release|Win32 + {406C51BB-C070-4B6A-8631-4C9A26CB1B2E}.Debug|x64.ActiveCfg = Debug|x64 + {406C51BB-C070-4B6A-8631-4C9A26CB1B2E}.Debug|x64.Build.0 = Debug|x64 + {406C51BB-C070-4B6A-8631-4C9A26CB1B2E}.Debug|x86.ActiveCfg = Debug|Win32 + {406C51BB-C070-4B6A-8631-4C9A26CB1B2E}.Debug|x86.Build.0 = Debug|Win32 + {406C51BB-C070-4B6A-8631-4C9A26CB1B2E}.Release|x64.ActiveCfg = Release|x64 + {406C51BB-C070-4B6A-8631-4C9A26CB1B2E}.Release|x64.Build.0 = Release|x64 + {406C51BB-C070-4B6A-8631-4C9A26CB1B2E}.Release|x86.ActiveCfg = Release|Win32 + {406C51BB-C070-4B6A-8631-4C9A26CB1B2E}.Release|x86.Build.0 = Release|Win32 + {85BA6BD1-9CDC-451F-ADF8-A8CDE6443EAF}.Debug|x64.ActiveCfg = Debug|x64 + {85BA6BD1-9CDC-451F-ADF8-A8CDE6443EAF}.Debug|x64.Build.0 = Debug|x64 + {85BA6BD1-9CDC-451F-ADF8-A8CDE6443EAF}.Debug|x86.ActiveCfg = Debug|Win32 + {85BA6BD1-9CDC-451F-ADF8-A8CDE6443EAF}.Debug|x86.Build.0 = Debug|Win32 + {85BA6BD1-9CDC-451F-ADF8-A8CDE6443EAF}.Release|x64.ActiveCfg = Release|x64 + {85BA6BD1-9CDC-451F-ADF8-A8CDE6443EAF}.Release|x64.Build.0 = Release|x64 + {85BA6BD1-9CDC-451F-ADF8-A8CDE6443EAF}.Release|x86.ActiveCfg = Release|Win32 + {85BA6BD1-9CDC-451F-ADF8-A8CDE6443EAF}.Release|x86.Build.0 = Release|Win32 + {CD54BACD-BC9B-40D8-8319-A3B4C6234073}.Debug|x64.ActiveCfg = Debug|x64 + {CD54BACD-BC9B-40D8-8319-A3B4C6234073}.Debug|x64.Build.0 = Debug|x64 + {CD54BACD-BC9B-40D8-8319-A3B4C6234073}.Debug|x86.ActiveCfg = Debug|Win32 + {CD54BACD-BC9B-40D8-8319-A3B4C6234073}.Debug|x86.Build.0 = Debug|Win32 + {CD54BACD-BC9B-40D8-8319-A3B4C6234073}.Release|x64.ActiveCfg = Release|x64 + {CD54BACD-BC9B-40D8-8319-A3B4C6234073}.Release|x64.Build.0 = Release|x64 + {CD54BACD-BC9B-40D8-8319-A3B4C6234073}.Release|x86.ActiveCfg = Release|Win32 + {CD54BACD-BC9B-40D8-8319-A3B4C6234073}.Release|x86.Build.0 = Release|Win32 + {20597CBF-CF6D-4D30-B0E3-2D289AF61143}.Debug|x64.ActiveCfg = Debug|x64 + {20597CBF-CF6D-4D30-B0E3-2D289AF61143}.Debug|x64.Build.0 = Debug|x64 + {20597CBF-CF6D-4D30-B0E3-2D289AF61143}.Debug|x86.ActiveCfg = Debug|Win32 + {20597CBF-CF6D-4D30-B0E3-2D289AF61143}.Debug|x86.Build.0 = Debug|Win32 + {20597CBF-CF6D-4D30-B0E3-2D289AF61143}.Release|x64.ActiveCfg = Release|x64 + {20597CBF-CF6D-4D30-B0E3-2D289AF61143}.Release|x64.Build.0 = Release|x64 + {20597CBF-CF6D-4D30-B0E3-2D289AF61143}.Release|x86.ActiveCfg = Release|Win32 + {20597CBF-CF6D-4D30-B0E3-2D289AF61143}.Release|x86.Build.0 = Release|Win32 + {A4A7B575-BCEE-43A6-A3F7-9831A2CCA253}.Debug|x64.ActiveCfg = Debug|x64 + {A4A7B575-BCEE-43A6-A3F7-9831A2CCA253}.Debug|x64.Build.0 = Debug|x64 + {A4A7B575-BCEE-43A6-A3F7-9831A2CCA253}.Debug|x86.ActiveCfg = Debug|Win32 + {A4A7B575-BCEE-43A6-A3F7-9831A2CCA253}.Debug|x86.Build.0 = Debug|Win32 + {A4A7B575-BCEE-43A6-A3F7-9831A2CCA253}.Release|x64.ActiveCfg = Release|x64 + {A4A7B575-BCEE-43A6-A3F7-9831A2CCA253}.Release|x64.Build.0 = Release|x64 + {A4A7B575-BCEE-43A6-A3F7-9831A2CCA253}.Release|x86.ActiveCfg = Release|Win32 + {A4A7B575-BCEE-43A6-A3F7-9831A2CCA253}.Release|x86.Build.0 = Release|Win32 + {0FCBB0B0-0459-47F1-B93F-70E6BA6CA1A8}.Debug|x64.ActiveCfg = Debug|x64 + {0FCBB0B0-0459-47F1-B93F-70E6BA6CA1A8}.Debug|x64.Build.0 = Debug|x64 + {0FCBB0B0-0459-47F1-B93F-70E6BA6CA1A8}.Debug|x86.ActiveCfg = Debug|Win32 + {0FCBB0B0-0459-47F1-B93F-70E6BA6CA1A8}.Debug|x86.Build.0 = Debug|Win32 + {0FCBB0B0-0459-47F1-B93F-70E6BA6CA1A8}.Release|x64.ActiveCfg = Release|x64 + {0FCBB0B0-0459-47F1-B93F-70E6BA6CA1A8}.Release|x64.Build.0 = Release|x64 + {0FCBB0B0-0459-47F1-B93F-70E6BA6CA1A8}.Release|x86.ActiveCfg = Release|Win32 + {0FCBB0B0-0459-47F1-B93F-70E6BA6CA1A8}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution + {44643D7F-1C71-41C1-B452-B2DC5E088A58} = {66A269CE-8FB5-4D68-ABB4-CACA10A0700C} + {9F71F0DA-1D72-4E96-93B7-5AC2C9CB6EDE} = {66A269CE-8FB5-4D68-ABB4-CACA10A0700C} {59FA8028-2346-4246-854F-14DCFAB6AB56} = {52A72E42-6F26-49E5-97D1-36CCA72C6139} {561754CB-295D-4D69-8DBC-BC069D1A636A} = {52A72E42-6F26-49E5-97D1-36CCA72C6139} {91CC6D16-F22C-434A-95E0-35EE857054C7} = {52A72E42-6F26-49E5-97D1-36CCA72C6139} {9ABCBAB4-05B4-47C5-B5D8-F201559FD096} = {52A72E42-6F26-49E5-97D1-36CCA72C6139} - {22358F79-365C-477A-B485-1746C79EF6AA} = {32AA682D-E5EE-4813-AFE8-E45D2EE62ED3} + {EEEFAB61-F404-4957-AC24-A3BF81C5E4ED} = {66A269CE-8FB5-4D68-ABB4-CACA10A0700C} + {CCEBD2BA-27F7-4E13-AE56-841AE1C91B13} = {66A269CE-8FB5-4D68-ABB4-CACA10A0700C} + {54F074CF-39C0-4FD6-BBEE-2DC880EB5C24} = {CCEBD2BA-27F7-4E13-AE56-841AE1C91B13} + {22358F79-365C-477A-B485-1746C79EF6AA} = {CCEBD2BA-27F7-4E13-AE56-841AE1C91B13} + {FC28F28C-C54C-4F0C-BF70-43E7F4E7192E} = {66A269CE-8FB5-4D68-ABB4-CACA10A0700C} + {AAC65EA8-DF18-44BB-811E-83B5E346B7C4} = {66A269CE-8FB5-4D68-ABB4-CACA10A0700C} + {1F656768-1C78-4AFF-A865-C9A769D659F6} = {66A269CE-8FB5-4D68-ABB4-CACA10A0700C} + {572003B3-3CC2-438E-9436-6B6EF9DC7BF5} = {1F656768-1C78-4AFF-A865-C9A769D659F6} + {7275758B-1ABC-4B28-BB42-CBDBCD2584D1} = {1F656768-1C78-4AFF-A865-C9A769D659F6} + {406C51BB-C070-4B6A-8631-4C9A26CB1B2E} = {AAC65EA8-DF18-44BB-811E-83B5E346B7C4} + {85BA6BD1-9CDC-451F-ADF8-A8CDE6443EAF} = {AAC65EA8-DF18-44BB-811E-83B5E346B7C4} + {F50E5C84-236D-4DF9-92EB-65E925769ADC} = {CCEBD2BA-27F7-4E13-AE56-841AE1C91B13} + {DD05ED1D-D2B8-4273-8435-23C94A2FE6F5} = {CCEBD2BA-27F7-4E13-AE56-841AE1C91B13} + {CD54BACD-BC9B-40D8-8319-A3B4C6234073} = {CCEBD2BA-27F7-4E13-AE56-841AE1C91B13} + {20597CBF-CF6D-4D30-B0E3-2D289AF61143} = {DD05ED1D-D2B8-4273-8435-23C94A2FE6F5} + {A4A7B575-BCEE-43A6-A3F7-9831A2CCA253} = {DD05ED1D-D2B8-4273-8435-23C94A2FE6F5} + {0FCBB0B0-0459-47F1-B93F-70E6BA6CA1A8} = {F50E5C84-236D-4DF9-92EB-65E925769ADC} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {49C2400F-1FAF-4195-AA48-C0C49F8247DF} EndGlobalSection EndGlobal diff --git a/ImageGenerators/CheckerboardGenerator.cpp b/ImageGenerators/CheckerboardGenerator.cpp new file mode 100644 index 0000000..b15d6ca --- /dev/null +++ b/ImageGenerators/CheckerboardGenerator.cpp @@ -0,0 +1,78 @@ +/** +@file CheckerboardGenerator.cpp +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + + +#include "swGraphicAPI/ResourceManager/stdafx.h" + +#include "CheckerboardGenerator.h" + +#include "swCommonLib/Common/Buffers/BufferTyped.h" + + + +namespace sw +{ + +// ================================ // +// +CheckerboardGenerator::CheckerboardGenerator () + : PixWidth( 8 ) + , PixHeight( 8 ) + , DarkColor( 0xFF000000 ) + , BrightColor( 0xFFFFFFFF ) + , CheckerSize( 1 ) +{} + + +// ================================ // +// +CheckerboardGenerator::CheckerboardGenerator ( uint16 width, uint16 height ) + : PixWidth( width ) + , PixHeight( height ) + , DarkColor( 0xFF000000 ) + , BrightColor( 0xFFFFFFFF ) + , CheckerSize( 1 ) +{} + +// ================================ // +// +CheckerboardGenerator::CheckerboardGenerator ( uint16 width, uint16 height, uint32 darkColor, uint32 brightColor ) + : PixWidth( width ) + , PixHeight( height ) + , DarkColor( darkColor ) + , BrightColor( brightColor ) + , CheckerSize( 1 ) +{} + +// ================================ // +// +BufferRaw CheckerboardGenerator::Generate () const +{ + auto numPixels = PixWidth * PixHeight; + + BufferTyped< uint32 > buffer( numPixels ); + + Size pixel = 0; + for( Size y = 0; y < PixHeight; ++y ) + { + for( Size x = 0; x < PixWidth; x++ ) + { + bool xParity = ( x / CheckerSize ) % 2 > 0; + bool yParity = ( y / CheckerSize ) % 2 > 0; + bool isDark = xParity ^ yParity; + + uint32 color = isDark ? DarkColor : BrightColor; + buffer[ pixel ] = color; + + pixel++; + } + } + + return buffer.MoveToRawBuffer(); +} + +} // sw + diff --git a/ImageGenerators/CheckerboardGenerator.h b/ImageGenerators/CheckerboardGenerator.h new file mode 100644 index 0000000..2b79e54 --- /dev/null +++ b/ImageGenerators/CheckerboardGenerator.h @@ -0,0 +1,49 @@ +#pragma once +/** +@file CheckerboardGenerator.h +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + +#include "swCommonLib/Common/TypesDefinitions.h" +#include "swCommonLib/Common/Buffers/BufferRaw.h" + + + +namespace sw +{ + + +/**@brief Generates 2D checkerboard image.*/ +class CheckerboardGenerator +{ +private: +public: + + uint16 PixWidth; + uint16 PixHeight; + + uint32 DarkColor; + uint32 BrightColor; + + uint16 CheckerSize; + +public: + + explicit CheckerboardGenerator (); + explicit CheckerboardGenerator ( uint16 width, uint16 height ); + explicit CheckerboardGenerator ( uint16 width, uint16 height, uint32 darkColor, uint32 brightColor ); + ~CheckerboardGenerator () = default; + + + BufferRaw Generate () const; +}; + + + + + +} // sw + + + diff --git a/Loaders/SoilTextureLoader/SOIL/etc1_utils.cpp b/Loaders/SoilTextureLoader/SOIL/etc1_utils.cpp new file mode 100644 index 0000000..1d10f0e --- /dev/null +++ b/Loaders/SoilTextureLoader/SOIL/etc1_utils.cpp @@ -0,0 +1,680 @@ +// Copyright 2009 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "etc1_utils.h" + +#include + +/* From http://www.khronos.org/registry/gles/extensions/OES/OES_compressed_ETC1_RGB8_texture.txt + + The number of bits that represent a 4x4 texel block is 64 bits if + is given by ETC1_RGB8_OES. + + The data for a block is a number of bytes, + + {q0, q1, q2, q3, q4, q5, q6, q7} + + where byte q0 is located at the lowest memory address and q7 at + the highest. The 64 bits specifying the block is then represented + by the following 64 bit integer: + + int64bit = 256*(256*(256*(256*(256*(256*(256*q0+q1)+q2)+q3)+q4)+q5)+q6)+q7; + + ETC1_RGB8_OES: + + a) bit layout in bits 63 through 32 if diffbit = 0 + + 63 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48 + ----------------------------------------------- + | base col1 | base col2 | base col1 | base col2 | + | R1 (4bits)| R2 (4bits)| G1 (4bits)| G2 (4bits)| + ----------------------------------------------- + + 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 + --------------------------------------------------- + | base col1 | base col2 | table | table |diff|flip| + | B1 (4bits)| B2 (4bits)| cw 1 | cw 2 |bit |bit | + --------------------------------------------------- + + + b) bit layout in bits 63 through 32 if diffbit = 1 + + 63 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48 + ----------------------------------------------- + | base col1 | dcol 2 | base col1 | dcol 2 | + | R1' (5 bits) | dR2 | G1' (5 bits) | dG2 | + ----------------------------------------------- + + 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 + --------------------------------------------------- + | base col 1 | dcol 2 | table | table |diff|flip| + | B1' (5 bits) | dB2 | cw 1 | cw 2 |bit |bit | + --------------------------------------------------- + + + c) bit layout in bits 31 through 0 (in both cases) + + 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 + ----------------------------------------------- + | most significant pixel index bits | + | p| o| n| m| l| k| j| i| h| g| f| e| d| c| b| a| + ----------------------------------------------- + + 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 + -------------------------------------------------- + | least significant pixel index bits | + | p| o| n| m| l| k| j| i| h| g| f| e| d| c | b | a | + -------------------------------------------------- + + + Add table 3.17.2: Intensity modifier sets for ETC1 compressed textures: + + table codeword modifier table + ------------------ ---------------------- + 0 -8 -2 2 8 + 1 -17 -5 5 17 + 2 -29 -9 9 29 + 3 -42 -13 13 42 + 4 -60 -18 18 60 + 5 -80 -24 24 80 + 6 -106 -33 33 106 + 7 -183 -47 47 183 + + + Add table 3.17.3 Mapping from pixel index values to modifier values for + ETC1 compressed textures: + + pixel index value + --------------- + msb lsb resulting modifier value + ----- ----- ------------------------- + 1 1 -b (large negative value) + 1 0 -a (small negative value) + 0 0 a (small positive value) + 0 1 b (large positive value) + + + */ + +static const int kModifierTable[] = { +/* 0 */2, 8, -2, -8, +/* 1 */5, 17, -5, -17, +/* 2 */9, 29, -9, -29, +/* 3 */13, 42, -13, -42, +/* 4 */18, 60, -18, -60, +/* 5 */24, 80, -24, -80, +/* 6 */33, 106, -33, -106, +/* 7 */47, 183, -47, -183 }; + +static const int kLookup[8] = { 0, 1, 2, 3, -4, -3, -2, -1 }; + +static inline etc1_byte clamp(int x) { + return (etc1_byte) (x >= 0 ? (x < 255 ? x : 255) : 0); +} + +static +inline int convert4To8(int b) { + int c = b & 0xf; + return (c << 4) | c; +} + +static +inline int convert5To8(int b) { + int c = b & 0x1f; + return (c << 3) | (c >> 2); +} + +static +inline int convert6To8(int b) { + int c = b & 0x3f; + return (c << 2) | (c >> 4); +} + +static +inline int divideBy255(int d) { + return (d + 128 + (d >> 8)) >> 8; +} + +static +inline int convert8To4(int b) { + //int c = b & 0xff; + return divideBy255(b * 15); +} + +static +inline int convert8To5(int b) { + //int c = b & 0xff; + return divideBy255(b * 31); +} + +static +inline int convertDiff(int base, int diff) { + return convert5To8((0x1f & base) + kLookup[0x7 & diff]); +} + +static +void decode_subblock(etc1_byte* pOut, int r, int g, int b, const int* table, + etc1_uint32 low, etc1_bool second, etc1_bool flipped) { + int baseX = 0; + int baseY = 0; + int i; + + if (second) { + if (flipped) { + baseY = 2; + } else { + baseX = 2; + } + } + for (i = 0; i < 8; i++) { + int x, y; + if (flipped) { + x = baseX + (i >> 1); + y = baseY + (i & 1); + } else { + x = baseX + (i >> 2); + y = baseY + (i & 3); + } + int k = y + (x * 4); + int offset = ((low >> k) & 1) | ((low >> (k + 15)) & 2); + int delta = table[offset]; + etc1_byte* q = pOut + 3 * (x + 4 * y); + *q++ = clamp(r + delta); + *q++ = clamp(g + delta); + *q++ = clamp(b + delta); + } +} + +// Input is an ETC1 compressed version of the data. +// Output is a 4 x 4 square of 3-byte pixels in form R, G, B + +void etc1_decode_block(const etc1_byte* pIn, etc1_byte* pOut) { + etc1_uint32 high = (pIn[0] << 24) | (pIn[1] << 16) | (pIn[2] << 8) | pIn[3]; + etc1_uint32 low = (pIn[4] << 24) | (pIn[5] << 16) | (pIn[6] << 8) | pIn[7]; + int r1, r2, g1, g2, b1, b2; + if (high & 2) { + // differential + int rBase = high >> 27; + int gBase = high >> 19; + int bBase = high >> 11; + r1 = convert5To8(rBase); + r2 = convertDiff(rBase, high >> 24); + g1 = convert5To8(gBase); + g2 = convertDiff(gBase, high >> 16); + b1 = convert5To8(bBase); + b2 = convertDiff(bBase, high >> 8); + } else { + // not differential + r1 = convert4To8(high >> 28); + r2 = convert4To8(high >> 24); + g1 = convert4To8(high >> 20); + g2 = convert4To8(high >> 16); + b1 = convert4To8(high >> 12); + b2 = convert4To8(high >> 8); + } + int tableIndexA = 7 & (high >> 5); + int tableIndexB = 7 & (high >> 2); + const int* tableA = kModifierTable + tableIndexA * 4; + const int* tableB = kModifierTable + tableIndexB * 4; + etc1_bool flipped = (high & 1) != 0; + decode_subblock(pOut, r1, g1, b1, tableA, low, 0, flipped); + decode_subblock(pOut, r2, g2, b2, tableB, low, 1, flipped); +} + +typedef struct { + etc1_uint32 high; + etc1_uint32 low; + etc1_uint32 score; // Lower is more accurate +} etc_compressed; + +static +inline void take_best(etc_compressed* a, const etc_compressed* b) { + if (a->score > b->score) { + *a = *b; + } +} + +static +void etc_average_colors_subblock(const etc1_byte* pIn, etc1_uint32 inMask, + etc1_byte* pColors, etc1_bool flipped, etc1_bool second) { + int r = 0; + int g = 0; + int b = 0; + int y, x; + + if (flipped) { + int by = 0; + if (second) { + by = 2; + } + for ( y = 0; y < 2; y++) { + int yy = by + y; + for ( x = 0; x < 4; x++) { + int i = x + 4 * yy; + if (inMask & (1 << i)) { + const etc1_byte* p = pIn + i * 3; + r += *(p++); + g += *(p++); + b += *(p++); + } + } + } + } else { + int bx = 0; + if (second) { + bx = 2; + } + for ( y = 0; y < 4; y++) { + for ( x = 0; x < 2; x++) { + int xx = bx + x; + int i = xx + 4 * y; + if (inMask & (1 << i)) { + const etc1_byte* p = pIn + i * 3; + r += *(p++); + g += *(p++); + b += *(p++); + } + } + } + } + pColors[0] = (etc1_byte)((r + 4) >> 3); + pColors[1] = (etc1_byte)((g + 4) >> 3); + pColors[2] = (etc1_byte)((b + 4) >> 3); +} + +static +inline int square(int x) { + return x * x; +} + +static etc1_uint32 chooseModifier(const etc1_byte* pBaseColors, + const etc1_byte* pIn, etc1_uint32 *pLow, int bitIndex, + const int* pModifierTable) { + etc1_uint32 bestScore = ~0; + int bestIndex = 0; + int pixelR = pIn[0]; + int pixelG = pIn[1]; + int pixelB = pIn[2]; + int r = pBaseColors[0]; + int g = pBaseColors[1]; + int b = pBaseColors[2]; + int i; + for ( i = 0; i < 4; i++) { + int modifier = pModifierTable[i]; + int decodedG = clamp(g + modifier); + etc1_uint32 score = (etc1_uint32) (6 * square(decodedG - pixelG)); + if (score >= bestScore) { + continue; + } + int decodedR = clamp(r + modifier); + score += (etc1_uint32) (3 * square(decodedR - pixelR)); + if (score >= bestScore) { + continue; + } + int decodedB = clamp(b + modifier); + score += (etc1_uint32) square(decodedB - pixelB); + if (score < bestScore) { + bestScore = score; + bestIndex = i; + } + } + etc1_uint32 lowMask = (((bestIndex >> 1) << 16) | (bestIndex & 1)) + << bitIndex; + *pLow |= lowMask; + return bestScore; +} + +static +void etc_encode_subblock_helper(const etc1_byte* pIn, etc1_uint32 inMask, + etc_compressed* pCompressed, etc1_bool flipped, etc1_bool second, + const etc1_byte* pBaseColors, const int* pModifierTable) { + int score = pCompressed->score; + int y, x; + if (flipped) { + int by = 0; + if (second) { + by = 2; + } + for ( y = 0; y < 2; y++) { + int yy = by + y; + for ( x = 0; x < 4; x++) { + int i = x + 4 * yy; + if (inMask & (1 << i)) { + score += chooseModifier(pBaseColors, pIn + i * 3, + &pCompressed->low, yy + x * 4, pModifierTable); + } + } + } + } else { + int bx = 0; + if (second) { + bx = 2; + } + for ( y = 0; y < 4; y++) { + for ( x = 0; x < 2; x++) { + int xx = bx + x; + int i = xx + 4 * y; + if (inMask & (1 << i)) { + score += chooseModifier(pBaseColors, pIn + i * 3, + &pCompressed->low, y + xx * 4, pModifierTable); + } + } + } + } + pCompressed->score = score; +} + +static etc1_bool inRange4bitSigned(int color) { + return color >= -4 && color <= 3; +} + +static void etc_encodeBaseColors(etc1_byte* pBaseColors, + const etc1_byte* pColors, etc_compressed* pCompressed) { + int r1, g1, b1, r2 = 0, g2 = 0, b2 = 0; // 8 bit base colors for sub-blocks + etc1_bool differential; + { + int r51 = convert8To5(pColors[0]); + int g51 = convert8To5(pColors[1]); + int b51 = convert8To5(pColors[2]); + int r52 = convert8To5(pColors[3]); + int g52 = convert8To5(pColors[4]); + int b52 = convert8To5(pColors[5]); + + r1 = convert5To8(r51); + g1 = convert5To8(g51); + b1 = convert5To8(b51); + + int dr = r52 - r51; + int dg = g52 - g51; + int db = b52 - b51; + + differential = inRange4bitSigned(dr) && inRange4bitSigned(dg) + && inRange4bitSigned(db); + if (differential) { + r2 = convert5To8(r51 + dr); + g2 = convert5To8(g51 + dg); + b2 = convert5To8(b51 + db); + pCompressed->high |= (r51 << 27) | ((7 & dr) << 24) | (g51 << 19) + | ((7 & dg) << 16) | (b51 << 11) | ((7 & db) << 8) | 2; + } + } + + if (!differential) { + int r41 = convert8To4(pColors[0]); + int g41 = convert8To4(pColors[1]); + int b41 = convert8To4(pColors[2]); + int r42 = convert8To4(pColors[3]); + int g42 = convert8To4(pColors[4]); + int b42 = convert8To4(pColors[5]); + r1 = convert4To8(r41); + g1 = convert4To8(g41); + b1 = convert4To8(b41); + r2 = convert4To8(r42); + g2 = convert4To8(g42); + b2 = convert4To8(b42); + pCompressed->high |= (r41 << 28) | (r42 << 24) | (g41 << 20) | (g42 + << 16) | (b41 << 12) | (b42 << 8); + } + pBaseColors[0] = r1; + pBaseColors[1] = g1; + pBaseColors[2] = b1; + pBaseColors[3] = r2; + pBaseColors[4] = g2; + pBaseColors[5] = b2; +} + +static +void etc_encode_block_helper(const etc1_byte* pIn, etc1_uint32 inMask, + const etc1_byte* pColors, etc_compressed* pCompressed, etc1_bool flipped) { + int i; + + pCompressed->score = ~0; + pCompressed->high = (flipped ? 1 : 0); + pCompressed->low = 0; + + etc1_byte pBaseColors[6]; + + etc_encodeBaseColors(pBaseColors, pColors, pCompressed); + + int originalHigh = pCompressed->high; + + const int* pModifierTable = kModifierTable; + for ( i = 0; i < 8; i++, pModifierTable += 4) { + etc_compressed temp; + temp.score = 0; + temp.high = originalHigh | (i << 5); + temp.low = 0; + etc_encode_subblock_helper(pIn, inMask, &temp, flipped, 0, + pBaseColors, pModifierTable); + take_best(pCompressed, &temp); + } + pModifierTable = kModifierTable; + etc_compressed firstHalf = *pCompressed; + for ( i = 0; i < 8; i++, pModifierTable += 4) { + etc_compressed temp; + temp.score = firstHalf.score; + temp.high = firstHalf.high | (i << 2); + temp.low = firstHalf.low; + etc_encode_subblock_helper(pIn, inMask, &temp, flipped, 1, + pBaseColors + 3, pModifierTable); + if (i == 0) { + *pCompressed = temp; + } else { + take_best(pCompressed, &temp); + } + } +} + +static void writeBigEndian(etc1_byte* pOut, etc1_uint32 d) { + pOut[0] = (etc1_byte)(d >> 24); + pOut[1] = (etc1_byte)(d >> 16); + pOut[2] = (etc1_byte)(d >> 8); + pOut[3] = (etc1_byte) d; +} + +// Input is a 4 x 4 square of 3-byte pixels in form R, G, B +// inmask is a 16-bit mask where bit (1 << (x + y * 4)) tells whether the corresponding (x,y) +// pixel is valid or not. Invalid pixel color values are ignored when compressing. +// Output is an ETC1 compressed version of the data. + +void etc1_encode_block(const etc1_byte* pIn, etc1_uint32 inMask, + etc1_byte* pOut) { + etc1_byte colors[6]; + etc1_byte flippedColors[6]; + etc_average_colors_subblock(pIn, inMask, colors, 0, 0); + etc_average_colors_subblock(pIn, inMask, colors + 3, 0, 1); + etc_average_colors_subblock(pIn, inMask, flippedColors, 1, 0); + etc_average_colors_subblock(pIn, inMask, flippedColors + 3, 1, 1); + + etc_compressed a, b; + etc_encode_block_helper(pIn, inMask, colors, &a, 0); + etc_encode_block_helper(pIn, inMask, flippedColors, &b, 1); + take_best(&a, &b); + writeBigEndian(pOut, a.high); + writeBigEndian(pOut + 4, a.low); +} + +// Return the size of the encoded image data (does not include size of PKM header). + +etc1_uint32 etc1_get_encoded_data_size(etc1_uint32 width, etc1_uint32 height) { + return (((width + 3) & ~3) * ((height + 3) & ~3)) >> 1; +} + +// Encode an entire image. +// pIn - pointer to the image data. Formatted such that the Red component of +// pixel (x,y) is at pIn + pixelSize * x + stride * y + redOffset; +// pOut - pointer to encoded data. Must be large enough to store entire encoded image. + +int etc1_encode_image(const etc1_byte* pIn, etc1_uint32 width, etc1_uint32 height, + etc1_uint32 pixelSize, etc1_uint32 stride, etc1_byte* pOut) { + if (pixelSize < 2 || pixelSize > 3) { + return -1; + } + static const unsigned short kYMask[] = { 0x0, 0xf, 0xff, 0xfff, 0xffff }; + static const unsigned short kXMask[] = { 0x0, 0x1111, 0x3333, 0x7777, + 0xffff }; + etc1_byte block[ETC1_DECODED_BLOCK_SIZE]; + etc1_byte encoded[ETC1_ENCODED_BLOCK_SIZE]; + etc1_uint32 y, x, cy, cx; + + etc1_uint32 encodedWidth = (width + 3) & ~3; + etc1_uint32 encodedHeight = (height + 3) & ~3; + + for ( y = 0; y < encodedHeight; y += 4) { + etc1_uint32 yEnd = height - y; + if (yEnd > 4) { + yEnd = 4; + } + int ymask = kYMask[yEnd]; + for ( x = 0; x < encodedWidth; x += 4) { + etc1_uint32 xEnd = width - x; + if (xEnd > 4) { + xEnd = 4; + } + int mask = ymask & kXMask[xEnd]; + for ( cy = 0; cy < yEnd; cy++) { + etc1_byte* q = block + (cy * 4) * 3; + const etc1_byte* p = pIn + pixelSize * x + stride * (y + cy); + if (pixelSize == 3) { + memcpy(q, p, xEnd * 3); + } else { + for ( cx = 0; cx < xEnd; cx++) { + int pixel = (p[1] << 8) | p[0]; + *q++ = convert5To8(pixel >> 11); + *q++ = convert6To8(pixel >> 5); + *q++ = convert5To8(pixel); + p += pixelSize; + } + } + } + etc1_encode_block(block, mask, encoded); + memcpy(pOut, encoded, sizeof(encoded)); + pOut += sizeof(encoded); + } + } + return 0; +} + +// Decode an entire image. +// pIn - pointer to encoded data. +// pOut - pointer to the image data. Will be written such that the Red component of +// pixel (x,y) is at pIn + pixelSize * x + stride * y + redOffset. Must be +// large enough to store entire image. + + +int etc1_decode_image(const etc1_byte* pIn, etc1_byte* pOut, + etc1_uint32 width, etc1_uint32 height, + etc1_uint32 pixelSize, etc1_uint32 stride) { + if (pixelSize < 2 || pixelSize > 3) { + return -1; + } + etc1_byte block[ETC1_DECODED_BLOCK_SIZE]; + + etc1_uint32 encodedWidth = (width + 3) & ~3; + etc1_uint32 encodedHeight = (height + 3) & ~3; + + etc1_uint32 y, x, cy, cx; + + for ( y = 0; y < encodedHeight; y += 4) { + etc1_uint32 yEnd = height - y; + if (yEnd > 4) { + yEnd = 4; + } + for ( x = 0; x < encodedWidth; x += 4) { + etc1_uint32 xEnd = width - x; + if (xEnd > 4) { + xEnd = 4; + } + etc1_decode_block(pIn, block); + pIn += ETC1_ENCODED_BLOCK_SIZE; + for ( cy = 0; cy < yEnd; cy++) { + const etc1_byte* q = block + (cy * 4) * 3; + etc1_byte* p = pOut + pixelSize * x + stride * (y + cy); + if (pixelSize == 3) { + memcpy(p, q, xEnd * 3); + } else { + for ( cx = 0; cx < xEnd; cx++) { + etc1_byte r = *q++; + etc1_byte g = *q++; + etc1_byte b = *q++; + etc1_uint32 pixel = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3); + *p++ = (etc1_byte) pixel; + *p++ = (etc1_byte) (pixel >> 8); + } + } + } + } + } + return 0; +} + +static const char kMagic[] = { 'P', 'K', 'M', ' ', '1', '0' }; + +static const etc1_uint32 ETC1_PKM_FORMAT_OFFSET = 6; +static const etc1_uint32 ETC1_PKM_ENCODED_WIDTH_OFFSET = 8; +static const etc1_uint32 ETC1_PKM_ENCODED_HEIGHT_OFFSET = 10; +static const etc1_uint32 ETC1_PKM_WIDTH_OFFSET = 12; +static const etc1_uint32 ETC1_PKM_HEIGHT_OFFSET = 14; + +static const etc1_uint32 ETC1_RGB_NO_MIPMAPS = 0; + +static void writeBEUint16(etc1_byte* pOut, etc1_uint32 data) { + pOut[0] = (etc1_byte) (data >> 8); + pOut[1] = (etc1_byte) data; +} + +static etc1_uint32 readBEUint16(const etc1_byte* pIn) { + return (pIn[0] << 8) | pIn[1]; +} + +// Format a PKM header + +void etc1_pkm_format_header(etc1_byte* pHeader, etc1_uint32 width, etc1_uint32 height) { + memcpy(pHeader, kMagic, sizeof(kMagic)); + etc1_uint32 encodedWidth = (width + 3) & ~3; + etc1_uint32 encodedHeight = (height + 3) & ~3; + writeBEUint16(pHeader + ETC1_PKM_FORMAT_OFFSET, ETC1_RGB_NO_MIPMAPS); + writeBEUint16(pHeader + ETC1_PKM_ENCODED_WIDTH_OFFSET, encodedWidth); + writeBEUint16(pHeader + ETC1_PKM_ENCODED_HEIGHT_OFFSET, encodedHeight); + writeBEUint16(pHeader + ETC1_PKM_WIDTH_OFFSET, width); + writeBEUint16(pHeader + ETC1_PKM_HEIGHT_OFFSET, height); +} + +// Check if a PKM header is correctly formatted. + +etc1_bool etc1_pkm_is_valid(const etc1_byte* pHeader) { + if (memcmp(pHeader, kMagic, sizeof(kMagic))) { + return 0; + } + etc1_uint32 format = readBEUint16(pHeader + ETC1_PKM_FORMAT_OFFSET); + etc1_uint32 encodedWidth = readBEUint16(pHeader + ETC1_PKM_ENCODED_WIDTH_OFFSET); + etc1_uint32 encodedHeight = readBEUint16(pHeader + ETC1_PKM_ENCODED_HEIGHT_OFFSET); + etc1_uint32 width = readBEUint16(pHeader + ETC1_PKM_WIDTH_OFFSET); + etc1_uint32 height = readBEUint16(pHeader + ETC1_PKM_HEIGHT_OFFSET); + return format == ETC1_RGB_NO_MIPMAPS && + encodedWidth >= width && encodedWidth - width < 4 && + encodedHeight >= height && encodedHeight - height < 4; +} + +// Read the image width from a PKM header + +etc1_uint32 etc1_pkm_get_width(const etc1_byte* pHeader) { + return readBEUint16(pHeader + ETC1_PKM_WIDTH_OFFSET); +} + +// Read the image height from a PKM header + +etc1_uint32 etc1_pkm_get_height(const etc1_byte* pHeader){ + return readBEUint16(pHeader + ETC1_PKM_HEIGHT_OFFSET); +} diff --git a/Loaders/SoilTextureLoader/SOIL/etc1_utils.h b/Loaders/SoilTextureLoader/SOIL/etc1_utils.h new file mode 100644 index 0000000..4bee00c --- /dev/null +++ b/Loaders/SoilTextureLoader/SOIL/etc1_utils.h @@ -0,0 +1,106 @@ +// Copyright 2009 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef __etc1_h__ +#define __etc1_h__ + +#define ETC1_ENCODED_BLOCK_SIZE 8 +#define ETC1_DECODED_BLOCK_SIZE 48 + +#ifndef ETC1_RGB8_OES +#define ETC1_RGB8_OES 0x8D64 +#endif + +typedef unsigned char etc1_byte; +typedef int etc1_bool; +typedef unsigned int etc1_uint32; + +#ifdef __cplusplus +extern "C" { +#endif + +// Encode a block of pixels. +// +// pIn is a pointer to a ETC_DECODED_BLOCK_SIZE array of bytes that represent a +// 4 x 4 square of 3-byte pixels in form R, G, B. Byte (3 * (x + 4 * y) is the R +// value of pixel (x, y). +// +// validPixelMask is a 16-bit mask where bit (1 << (x + y * 4)) indicates whether +// the corresponding (x,y) pixel is valid. Invalid pixel color values are ignored when compressing. +// +// pOut is an ETC1 compressed version of the data. + +void etc1_encode_block(const etc1_byte* pIn, etc1_uint32 validPixelMask, etc1_byte* pOut); + +// Decode a block of pixels. +// +// pIn is an ETC1 compressed version of the data. +// +// pOut is a pointer to a ETC_DECODED_BLOCK_SIZE array of bytes that represent a +// 4 x 4 square of 3-byte pixels in form R, G, B. Byte (3 * (x + 4 * y) is the R +// value of pixel (x, y). + +void etc1_decode_block(const etc1_byte* pIn, etc1_byte* pOut); + +// Return the size of the encoded image data (does not include size of PKM header). + +etc1_uint32 etc1_get_encoded_data_size(etc1_uint32 width, etc1_uint32 height); + +// Encode an entire image. +// pIn - pointer to the image data. Formatted such that +// pixel (x,y) is at pIn + pixelSize * x + stride * y; +// pOut - pointer to encoded data. Must be large enough to store entire encoded image. +// pixelSize can be 2 or 3. 2 is an GL_UNSIGNED_SHORT_5_6_5 image, 3 is a GL_BYTE RGB image. +// returns non-zero if there is an error. + +int etc1_encode_image(const etc1_byte* pIn, etc1_uint32 width, etc1_uint32 height, + etc1_uint32 pixelSize, etc1_uint32 stride, etc1_byte* pOut); + +// Decode an entire image. +// pIn - pointer to encoded data. +// pOut - pointer to the image data. Will be written such that +// pixel (x,y) is at pIn + pixelSize * x + stride * y. Must be +// large enough to store entire image. +// pixelSize can be 2 or 3. 2 is an GL_UNSIGNED_SHORT_5_6_5 image, 3 is a GL_BYTE RGB image. +// returns non-zero if there is an error. + +int etc1_decode_image(const etc1_byte* pIn, etc1_byte* pOut, + etc1_uint32 width, etc1_uint32 height, + etc1_uint32 pixelSize, etc1_uint32 stride); + +// Size of a PKM header, in bytes. + +#define ETC_PKM_HEADER_SIZE 16 + +// Format a PKM header + +void etc1_pkm_format_header(etc1_byte* pHeader, etc1_uint32 width, etc1_uint32 height); + +// Check if a PKM header is correctly formatted. + +etc1_bool etc1_pkm_is_valid(const etc1_byte* pHeader); + +// Read the image width from a PKM header + +etc1_uint32 etc1_pkm_get_width(const etc1_byte* pHeader); + +// Read the image height from a PKM header + +etc1_uint32 etc1_pkm_get_height(const etc1_byte* pHeader); + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/Loaders/SoilTextureLoader/SOIL/image_DXT.c b/Loaders/SoilTextureLoader/SOIL/image_DXT.c new file mode 100644 index 0000000..4206a1b --- /dev/null +++ b/Loaders/SoilTextureLoader/SOIL/image_DXT.c @@ -0,0 +1,632 @@ +/* + Jonathan Dummer + 2007-07-31-10.32 + + simple DXT compression / decompression code + + public domain +*/ + +#include "image_DXT.h" +#include +#include +#include +#include + +/* set this =1 if you want to use the covarince matrix method... + which is better than my method of using standard deviations + overall, except on the infintesimal chance that the power + method fails for finding the largest eigenvector */ +#define USE_COV_MAT 1 + +/********* Function Prototypes *********/ +/* + Takes a 4x4 block of pixels and compresses it into 8 bytes + in DXT1 format (color only, no alpha). Speed is valued + over prettyness, at least for now. +*/ +void compress_DDS_color_block( + int channels, + const unsigned char *const uncompressed, + unsigned char compressed[8] ); +/* + Takes a 4x4 block of pixels and compresses the alpha + component it into 8 bytes for use in DXT5 DDS files. + Speed is valued over prettyness, at least for now. +*/ +void compress_DDS_alpha_block( + const unsigned char *const uncompressed, + unsigned char compressed[8] ); + +/********* Actual Exposed Functions *********/ +int + save_image_as_DDS + ( + const char *filename, + int width, int height, int channels, + const unsigned char *const data + ) +{ + /* variables */ + FILE *fout; + unsigned char *DDS_data; + DDS_header header; + int DDS_size; + /* error check */ + if( (NULL == filename) || + (width < 1) || (height < 1) || + (channels < 1) || (channels > 4) || + (data == NULL ) ) + { + return 0; + } + /* Convert the image */ + if( (channels & 1) == 1 ) + { + /* no alpha, just use DXT1 */ + DDS_data = convert_image_to_DXT1( data, width, height, channels, &DDS_size ); + } else + { + /* has alpha, so use DXT5 */ + DDS_data = convert_image_to_DXT5( data, width, height, channels, &DDS_size ); + } + /* save it */ + memset( &header, 0, sizeof( DDS_header ) ); + header.dwMagic = ('D' << 0) | ('D' << 8) | ('S' << 16) | (' ' << 24); + header.dwSize = 124; + header.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT | DDSD_LINEARSIZE; + header.dwWidth = width; + header.dwHeight = height; + header.dwPitchOrLinearSize = DDS_size; + header.sPixelFormat.dwSize = 32; + header.sPixelFormat.dwFlags = DDPF_FOURCC; + if( (channels & 1) == 1 ) + { + header.sPixelFormat.dwFourCC = ('D' << 0) | ('X' << 8) | ('T' << 16) | ('1' << 24); + } else + { + header.sPixelFormat.dwFourCC = ('D' << 0) | ('X' << 8) | ('T' << 16) | ('5' << 24); + } + header.sCaps.dwCaps1 = DDSCAPS_TEXTURE; + /* write it out */ + fout = fopen( filename, "wb"); + fwrite( &header, sizeof( DDS_header ), 1, fout ); + fwrite( DDS_data, 1, DDS_size, fout ); + fclose( fout ); + /* done */ + free( DDS_data ); + return 1; +} + +unsigned char* convert_image_to_DXT1( + const unsigned char *const uncompressed, + int width, int height, int channels, + int *out_size ) +{ + unsigned char *compressed; + int i, j, x, y; + unsigned char ublock[16*3]; + unsigned char cblock[8]; + int index = 0, chan_step = 1; + int block_count = 0; + /* error check */ + *out_size = 0; + if( (width < 1) || (height < 1) || + (NULL == uncompressed) || + (channels < 1) || (channels > 4) ) + { + return NULL; + } + /* for channels == 1 or 2, I do not step forward for R,G,B values */ + if( channels < 3 ) + { + chan_step = 0; + } + /* get the RAM for the compressed image + (8 bytes per 4x4 pixel block) */ + *out_size = ((width+3) >> 2) * ((height+3) >> 2) * 8; + compressed = (unsigned char*)malloc( *out_size ); + /* go through each block */ + for( j = 0; j < height; j += 4 ) + { + for( i = 0; i < width; i += 4 ) + { + /* copy this block into a new one */ + int idx = 0; + int mx = 4, my = 4; + if( j+4 >= height ) + { + my = height - j; + } + if( i+4 >= width ) + { + mx = width - i; + } + for( y = 0; y < my; ++y ) + { + for( x = 0; x < mx; ++x ) + { + ublock[idx++] = uncompressed[(j+y)*width*channels+(i+x)*channels]; + ublock[idx++] = uncompressed[(j+y)*width*channels+(i+x)*channels+chan_step]; + ublock[idx++] = uncompressed[(j+y)*width*channels+(i+x)*channels+chan_step+chan_step]; + } + for( x = mx; x < 4; ++x ) + { + ublock[idx++] = ublock[0]; + ublock[idx++] = ublock[1]; + ublock[idx++] = ublock[2]; + } + } + for( y = my; y < 4; ++y ) + { + for( x = 0; x < 4; ++x ) + { + ublock[idx++] = ublock[0]; + ublock[idx++] = ublock[1]; + ublock[idx++] = ublock[2]; + } + } + /* compress the block */ + ++block_count; + compress_DDS_color_block( 3, ublock, cblock ); + /* copy the data from the block into the main block */ + for( x = 0; x < 8; ++x ) + { + compressed[index++] = cblock[x]; + } + } + } + return compressed; +} + +unsigned char* convert_image_to_DXT5( + const unsigned char *const uncompressed, + int width, int height, int channels, + int *out_size ) +{ + unsigned char *compressed; + int i, j, x, y; + unsigned char ublock[16*4]; + unsigned char cblock[8]; + int index = 0, chan_step = 1; + int block_count = 0, has_alpha; + /* error check */ + *out_size = 0; + if( (width < 1) || (height < 1) || + (NULL == uncompressed) || + (channels < 1) || ( channels > 4) ) + { + return NULL; + } + /* for channels == 1 or 2, I do not step forward for R,G,B vales */ + if( channels < 3 ) + { + chan_step = 0; + } + /* # channels = 1 or 3 have no alpha, 2 & 4 do have alpha */ + has_alpha = 1 - (channels & 1); + /* get the RAM for the compressed image + (16 bytes per 4x4 pixel block) */ + *out_size = ((width+3) >> 2) * ((height+3) >> 2) * 16; + compressed = (unsigned char*)malloc( *out_size ); + /* go through each block */ + for( j = 0; j < height; j += 4 ) + { + for( i = 0; i < width; i += 4 ) + { + /* local variables, and my block counter */ + int idx = 0; + int mx = 4, my = 4; + if( j+4 >= height ) + { + my = height - j; + } + if( i+4 >= width ) + { + mx = width - i; + } + for( y = 0; y < my; ++y ) + { + for( x = 0; x < mx; ++x ) + { + ublock[idx++] = uncompressed[(j+y)*width*channels+(i+x)*channels]; + ublock[idx++] = uncompressed[(j+y)*width*channels+(i+x)*channels+chan_step]; + ublock[idx++] = uncompressed[(j+y)*width*channels+(i+x)*channels+chan_step+chan_step]; + ublock[idx++] = + has_alpha * uncompressed[(j+y)*width*channels+(i+x)*channels+channels-1] + + (1-has_alpha)*255; + } + for( x = mx; x < 4; ++x ) + { + ublock[idx++] = ublock[0]; + ublock[idx++] = ublock[1]; + ublock[idx++] = ublock[2]; + ublock[idx++] = ublock[3]; + } + } + for( y = my; y < 4; ++y ) + { + for( x = 0; x < 4; ++x ) + { + ublock[idx++] = ublock[0]; + ublock[idx++] = ublock[1]; + ublock[idx++] = ublock[2]; + ublock[idx++] = ublock[3]; + } + } + /* now compress the alpha block */ + compress_DDS_alpha_block( ublock, cblock ); + /* copy the data from the compressed alpha block into the main buffer */ + for( x = 0; x < 8; ++x ) + { + compressed[index++] = cblock[x]; + } + /* then compress the color block */ + ++block_count; + compress_DDS_color_block( 4, ublock, cblock ); + /* copy the data from the compressed color block into the main buffer */ + for( x = 0; x < 8; ++x ) + { + compressed[index++] = cblock[x]; + } + } + } + return compressed; +} + +/********* Helper Functions *********/ +int convert_bit_range( int c, int from_bits, int to_bits ) +{ + int b = (1 << (from_bits - 1)) + c * ((1 << to_bits) - 1); + return (b + (b >> from_bits)) >> from_bits; +} + +int rgb_to_565( int r, int g, int b ) +{ + return + (convert_bit_range( r, 8, 5 ) << 11) | + (convert_bit_range( g, 8, 6 ) << 05) | + (convert_bit_range( b, 8, 5 ) << 00); +} + +void rgb_888_from_565( unsigned int c, int *r, int *g, int *b ) +{ + *r = convert_bit_range( (c >> 11) & 31, 5, 8 ); + *g = convert_bit_range( (c >> 05) & 63, 6, 8 ); + *b = convert_bit_range( (c >> 00) & 31, 5, 8 ); +} + +void compute_color_line_STDEV( + const unsigned char *const uncompressed, + int channels, + float point[3], float direction[3] ) +{ + const float inv_16 = 1.0f / 16.0f; + int i; + float sum_r = 0.0f, sum_g = 0.0f, sum_b = 0.0f; + float sum_rr = 0.0f, sum_gg = 0.0f, sum_bb = 0.0f; + float sum_rg = 0.0f, sum_rb = 0.0f, sum_gb = 0.0f; + /* calculate all data needed for the covariance matrix + ( to compare with _rygdxt code) */ + for( i = 0; i < 16*channels; i += channels ) + { + sum_r += uncompressed[i+0]; + sum_rr += uncompressed[i+0] * uncompressed[i+0]; + sum_g += uncompressed[i+1]; + sum_gg += uncompressed[i+1] * uncompressed[i+1]; + sum_b += uncompressed[i+2]; + sum_bb += uncompressed[i+2] * uncompressed[i+2]; + sum_rg += uncompressed[i+0] * uncompressed[i+1]; + sum_rb += uncompressed[i+0] * uncompressed[i+2]; + sum_gb += uncompressed[i+1] * uncompressed[i+2]; + } + /* convert the sums to averages */ + sum_r *= inv_16; + sum_g *= inv_16; + sum_b *= inv_16; + /* and convert the squares to the squares of the value - avg_value */ + sum_rr -= 16.0f * sum_r * sum_r; + sum_gg -= 16.0f * sum_g * sum_g; + sum_bb -= 16.0f * sum_b * sum_b; + sum_rg -= 16.0f * sum_r * sum_g; + sum_rb -= 16.0f * sum_r * sum_b; + sum_gb -= 16.0f * sum_g * sum_b; + /* the point on the color line is the average */ + point[0] = sum_r; + point[1] = sum_g; + point[2] = sum_b; + #if USE_COV_MAT + /* + The following idea was from ryg. + (https://mollyrocket.com/forums/viewtopic.php?t=392) + The method worked great (less RMSE than mine) most of + the time, but had some issues handling some simple + boundary cases, like full green next to full red, + which would generate a covariance matrix like this: + + | 1 -1 0 | + | -1 1 0 | + | 0 0 0 | + + For a given starting vector, the power method can + generate all zeros! So no starting with {1,1,1} + as I was doing! This kind of error is still a + slight posibillity, but will be very rare. + */ + /* use the covariance matrix directly + (1st iteration, don't use all 1.0 values!) */ + sum_r = 1.0f; + sum_g = 2.718281828f; + sum_b = 3.141592654f; + direction[0] = sum_r*sum_rr + sum_g*sum_rg + sum_b*sum_rb; + direction[1] = sum_r*sum_rg + sum_g*sum_gg + sum_b*sum_gb; + direction[2] = sum_r*sum_rb + sum_g*sum_gb + sum_b*sum_bb; + /* 2nd iteration, use results from the 1st guy */ + sum_r = direction[0]; + sum_g = direction[1]; + sum_b = direction[2]; + direction[0] = sum_r*sum_rr + sum_g*sum_rg + sum_b*sum_rb; + direction[1] = sum_r*sum_rg + sum_g*sum_gg + sum_b*sum_gb; + direction[2] = sum_r*sum_rb + sum_g*sum_gb + sum_b*sum_bb; + /* 3rd iteration, use results from the 2nd guy */ + sum_r = direction[0]; + sum_g = direction[1]; + sum_b = direction[2]; + direction[0] = sum_r*sum_rr + sum_g*sum_rg + sum_b*sum_rb; + direction[1] = sum_r*sum_rg + sum_g*sum_gg + sum_b*sum_gb; + direction[2] = sum_r*sum_rb + sum_g*sum_gb + sum_b*sum_bb; + #else + /* use my standard deviation method + (very robust, a tiny bit slower and less accurate) */ + direction[0] = sqrt( sum_rr ); + direction[1] = sqrt( sum_gg ); + direction[2] = sqrt( sum_bb ); + /* which has a greater component */ + if( sum_gg > sum_rr ) + { + /* green has greater component, so base the other signs off of green */ + if( sum_rg < 0.0f ) + { + direction[0] = -direction[0]; + } + if( sum_gb < 0.0f ) + { + direction[2] = -direction[2]; + } + } else + { + /* red has a greater component */ + if( sum_rg < 0.0f ) + { + direction[1] = -direction[1]; + } + if( sum_rb < 0.0f ) + { + direction[2] = -direction[2]; + } + } + #endif +} + +void LSE_master_colors_max_min( + int *cmax, int *cmin, + int channels, + const unsigned char *const uncompressed ) +{ + int i, j; + /* the master colors */ + int c0[3], c1[3]; + /* used for fitting the line */ + float sum_x[] = { 0.0f, 0.0f, 0.0f }; + float sum_x2[] = { 0.0f, 0.0f, 0.0f }; + float dot_max = 1.0f, dot_min = -1.0f; + float vec_len2 = 0.0f; + float dot; + /* error check */ + if( (channels < 3) || (channels > 4) ) + { + return; + } + compute_color_line_STDEV( uncompressed, channels, sum_x, sum_x2 ); + vec_len2 = 1.0f / ( 0.00001f + + sum_x2[0]*sum_x2[0] + sum_x2[1]*sum_x2[1] + sum_x2[2]*sum_x2[2] ); + /* finding the max and min vector values */ + dot_max = + ( + sum_x2[0] * uncompressed[0] + + sum_x2[1] * uncompressed[1] + + sum_x2[2] * uncompressed[2] + ); + dot_min = dot_max; + for( i = 1; i < 16; ++i ) + { + dot = + ( + sum_x2[0] * uncompressed[i*channels+0] + + sum_x2[1] * uncompressed[i*channels+1] + + sum_x2[2] * uncompressed[i*channels+2] + ); + if( dot < dot_min ) + { + dot_min = dot; + } else if( dot > dot_max ) + { + dot_max = dot; + } + } + /* and the offset (from the average location) */ + dot = sum_x2[0]*sum_x[0] + sum_x2[1]*sum_x[1] + sum_x2[2]*sum_x[2]; + dot_min -= dot; + dot_max -= dot; + /* post multiply by the scaling factor */ + dot_min *= vec_len2; + dot_max *= vec_len2; + /* OK, build the master colors */ + for( i = 0; i < 3; ++i ) + { + /* color 0 */ + c0[i] = (int)(0.5f + sum_x[i] + dot_max * sum_x2[i]); + if( c0[i] < 0 ) + { + c0[i] = 0; + } else if( c0[i] > 255 ) + { + c0[i] = 255; + } + /* color 1 */ + c1[i] = (int)(0.5f + sum_x[i] + dot_min * sum_x2[i]); + if( c1[i] < 0 ) + { + c1[i] = 0; + } else if( c1[i] > 255 ) + { + c1[i] = 255; + } + } + /* down_sample (with rounding?) */ + i = rgb_to_565( c0[0], c0[1], c0[2] ); + j = rgb_to_565( c1[0], c1[1], c1[2] ); + if( i > j ) + { + *cmax = i; + *cmin = j; + } else + { + *cmax = j; + *cmin = i; + } +} + +void + compress_DDS_color_block + ( + int channels, + const unsigned char *const uncompressed, + unsigned char compressed[8] + ) +{ + /* variables */ + int i; + int next_bit; + int enc_c0, enc_c1; + int c0[4], c1[4]; + float color_line[] = { 0.0f, 0.0f, 0.0f, 0.0f }; + float vec_len2 = 0.0f, dot_offset = 0.0f; + /* stupid order */ + int swizzle4[] = { 0, 2, 3, 1 }; + /* get the master colors */ + LSE_master_colors_max_min( &enc_c0, &enc_c1, channels, uncompressed ); + /* store the 565 color 0 and color 1 */ + compressed[0] = (enc_c0 >> 0) & 255; + compressed[1] = (enc_c0 >> 8) & 255; + compressed[2] = (enc_c1 >> 0) & 255; + compressed[3] = (enc_c1 >> 8) & 255; + /* zero out the compressed data */ + compressed[4] = 0; + compressed[5] = 0; + compressed[6] = 0; + compressed[7] = 0; + /* reconstitute the master color vectors */ + rgb_888_from_565( enc_c0, &c0[0], &c0[1], &c0[2] ); + rgb_888_from_565( enc_c1, &c1[0], &c1[1], &c1[2] ); + /* the new vector */ + vec_len2 = 0.0f; + for( i = 0; i < 3; ++i ) + { + color_line[i] = (float)(c1[i] - c0[i]); + vec_len2 += color_line[i] * color_line[i]; + } + if( vec_len2 > 0.0f ) + { + vec_len2 = 1.0f / vec_len2; + } + /* pre-proform the scaling */ + color_line[0] *= vec_len2; + color_line[1] *= vec_len2; + color_line[2] *= vec_len2; + /* compute the offset (constant) portion of the dot product */ + dot_offset = color_line[0]*c0[0] + color_line[1]*c0[1] + color_line[2]*c0[2]; + /* store the rest of the bits */ + next_bit = 8*4; + for( i = 0; i < 16; ++i ) + { + /* find the dot product of this color, to place it on the line + (should be [-1,1]) */ + int next_value = 0; + float dot_product = + color_line[0] * uncompressed[i*channels+0] + + color_line[1] * uncompressed[i*channels+1] + + color_line[2] * uncompressed[i*channels+2] - + dot_offset; + /* map to [0,3] */ + next_value = (int)( dot_product * 3.0f + 0.5f ); + if( next_value > 3 ) + { + next_value = 3; + } else if( next_value < 0 ) + { + next_value = 0; + } + /* OK, store this value */ + compressed[next_bit >> 3] |= swizzle4[ next_value ] << (next_bit & 7); + next_bit += 2; + } + /* done compressing to DXT1 */ +} + +void + compress_DDS_alpha_block + ( + const unsigned char *const uncompressed, + unsigned char compressed[8] + ) +{ + /* variables */ + int i; + int next_bit; + int a0, a1; + float scale_me; + /* stupid order */ + int swizzle8[] = { 1, 7, 6, 5, 4, 3, 2, 0 }; + /* get the alpha limits (a0 > a1) */ + a0 = a1 = uncompressed[3]; + for( i = 4+3; i < 16*4; i += 4 ) + { + if( uncompressed[i] > a0 ) + { + a0 = uncompressed[i]; + } else if( uncompressed[i] < a1 ) + { + a1 = uncompressed[i]; + } + } + /* store those limits, and zero the rest of the compressed dataset */ + compressed[0] = a0; + compressed[1] = a1; + /* zero out the compressed data */ + compressed[2] = 0; + compressed[3] = 0; + compressed[4] = 0; + compressed[5] = 0; + compressed[6] = 0; + compressed[7] = 0; + /* store the all of the alpha values */ + next_bit = 8*2; + scale_me = 7.9999f / (a0 - a1); + for( i = 3; i < 16*4; i += 4 ) + { + /* convert this alpha value to a 3 bit number */ + int svalue; + int value = (int)((uncompressed[i] - a1) * scale_me); + svalue = swizzle8[ value&7 ]; + /* OK, store this value, start with the 1st byte */ + compressed[next_bit >> 3] |= svalue << (next_bit & 7); + if( (next_bit & 7) > 5 ) + { + /* spans 2 bytes, fill in the start of the 2nd byte */ + compressed[1 + (next_bit >> 3)] |= svalue >> (8 - (next_bit & 7) ); + } + next_bit += 3; + } + /* done compressing to DXT1 */ +} diff --git a/Loaders/SoilTextureLoader/SOIL/image_DXT.h b/Loaders/SoilTextureLoader/SOIL/image_DXT.h new file mode 100644 index 0000000..75f604f --- /dev/null +++ b/Loaders/SoilTextureLoader/SOIL/image_DXT.h @@ -0,0 +1,123 @@ +/* + Jonathan Dummer + 2007-07-31-10.32 + + simple DXT compression / decompression code + + public domain +*/ + +#ifndef HEADER_IMAGE_DXT +#define HEADER_IMAGE_DXT + +/** + Converts an image from an array of unsigned chars (RGB or RGBA) to + DXT1 or DXT5, then saves the converted image to disk. + \return 0 if failed, otherwise returns 1 +**/ +int +save_image_as_DDS +( + const char *filename, + int width, int height, int channels, + const unsigned char *const data +); + +/** + take an image and convert it to DXT1 (no alpha) +**/ +unsigned char* +convert_image_to_DXT1 +( + const unsigned char *const uncompressed, + int width, int height, int channels, + int *out_size +); + +/** + take an image and convert it to DXT5 (with alpha) +**/ +unsigned char* +convert_image_to_DXT5 +( + const unsigned char *const uncompressed, + int width, int height, int channels, + int *out_size +); + +/** A bunch of DirectDraw Surface structures and flags **/ +typedef struct +{ + unsigned int dwMagic; + unsigned int dwSize; + unsigned int dwFlags; + unsigned int dwHeight; + unsigned int dwWidth; + unsigned int dwPitchOrLinearSize; + unsigned int dwDepth; + unsigned int dwMipMapCount; + unsigned int dwReserved1[ 11 ]; + + /* DDPIXELFORMAT */ + struct + { + unsigned int dwSize; + unsigned int dwFlags; + unsigned int dwFourCC; + unsigned int dwRGBBitCount; + unsigned int dwRBitMask; + unsigned int dwGBitMask; + unsigned int dwBBitMask; + unsigned int dwAlphaBitMask; + } + sPixelFormat; + + /* DDCAPS2 */ + struct + { + unsigned int dwCaps1; + unsigned int dwCaps2; + unsigned int dwDDSX; + unsigned int dwReserved; + } + sCaps; + unsigned int dwReserved2; +} +DDS_header ; + +/* the following constants were copied directly off the MSDN website */ + +/* The dwFlags member of the original DDSURFACEDESC2 structure + can be set to one or more of the following values. */ +#define DDSD_CAPS 0x00000001 +#define DDSD_HEIGHT 0x00000002 +#define DDSD_WIDTH 0x00000004 +#define DDSD_PITCH 0x00000008 +#define DDSD_PIXELFORMAT 0x00001000 +#define DDSD_MIPMAPCOUNT 0x00020000 +#define DDSD_LINEARSIZE 0x00080000 +#define DDSD_DEPTH 0x00800000 + +/* DirectDraw Pixel Format */ +#define DDPF_ALPHAPIXELS 0x00000001 +#define DDPF_FOURCC 0x00000004 +#define DDPF_RGB 0x00000040 + +/* The dwCaps1 member of the DDSCAPS2 structure can be + set to one or more of the following values. */ +#define DDSCAPS_COMPLEX 0x00000008 +#define DDSCAPS_TEXTURE 0x00001000 +#define DDSCAPS_MIPMAP 0x00400000 + +/* The dwCaps2 member of the DDSCAPS2 structure can be + set to one or more of the following values. */ +#define DDSCAPS2_CUBEMAP 0x00000200 +#define DDSCAPS2_CUBEMAP_POSITIVEX 0x00000400 +#define DDSCAPS2_CUBEMAP_NEGATIVEX 0x00000800 +#define DDSCAPS2_CUBEMAP_POSITIVEY 0x00001000 +#define DDSCAPS2_CUBEMAP_NEGATIVEY 0x00002000 +#define DDSCAPS2_CUBEMAP_POSITIVEZ 0x00004000 +#define DDSCAPS2_CUBEMAP_NEGATIVEZ 0x00008000 +#define DDSCAPS2_VOLUME 0x00200000 + +#endif /* HEADER_IMAGE_DXT */ diff --git a/Loaders/SoilTextureLoader/SOIL/image_helper.c b/Loaders/SoilTextureLoader/SOIL/image_helper.c new file mode 100644 index 0000000..12c701e --- /dev/null +++ b/Loaders/SoilTextureLoader/SOIL/image_helper.c @@ -0,0 +1,435 @@ +/* + Jonathan Dummer + + image helper functions + + MIT license +*/ + +#include "image_helper.h" +#include +#include + +/* Upscaling the image uses simple bilinear interpolation */ +int + up_scale_image + ( + const unsigned char* const orig, + int width, int height, int channels, + unsigned char* resampled, + int resampled_width, int resampled_height + ) +{ + float dx, dy; + int x, y, c; + + /* error(s) check */ + if ( (width < 1) || (height < 1) || + (resampled_width < 2) || (resampled_height < 2) || + (channels < 1) || + (NULL == orig) || (NULL == resampled) ) + { + /* signify badness */ + return 0; + } + /* + for each given pixel in the new map, find the exact location + from the original map which would contribute to this guy + */ + dx = (width - 1.0f) / (resampled_width - 1.0f); + dy = (height - 1.0f) / (resampled_height - 1.0f); + for ( y = 0; y < resampled_height; ++y ) + { + /* find the base y index and fractional offset from that */ + float sampley = y * dy; + int inty = (int)sampley; + /* if( inty < 0 ) { inty = 0; } else */ + if( inty > height - 2 ) { inty = height - 2; } + sampley -= inty; + for ( x = 0; x < resampled_width; ++x ) + { + float samplex = x * dx; + int intx = (int)samplex; + int base_index; + /* find the base x index and fractional offset from that */ + /* if( intx < 0 ) { intx = 0; } else */ + if( intx > width - 2 ) { intx = width - 2; } + samplex -= intx; + /* base index into the original image */ + base_index = (inty * width + intx) * channels; + for ( c = 0; c < channels; ++c ) + { + /* do the sampling */ + float value = 0.5f; + value += orig[base_index] + *(1.0f-samplex)*(1.0f-sampley); + value += orig[base_index+channels] + *(samplex)*(1.0f-sampley); + value += orig[base_index+width*channels] + *(1.0f-samplex)*(sampley); + value += orig[base_index+width*channels+channels] + *(samplex)*(sampley); + /* move to the next channel */ + ++base_index; + /* save the new value */ + resampled[y*resampled_width*channels+x*channels+c] = + (unsigned char)(value); + } + } + } + /* done */ + return 1; +} + +int + mipmap_image + ( + const unsigned char* const orig, + int width, int height, int channels, + unsigned char* resampled, + int block_size_x, int block_size_y + ) +{ + int mip_width, mip_height; + int i, j, c; + + /* error check */ + if( (width < 1) || (height < 1) || + (channels < 1) || (orig == NULL) || + (resampled == NULL) || + (block_size_x < 1) || (block_size_y < 1) ) + { + /* nothing to do */ + return 0; + } + mip_width = width / block_size_x; + mip_height = height / block_size_y; + if( mip_width < 1 ) + { + mip_width = 1; + } + if( mip_height < 1 ) + { + mip_height = 1; + } + for( j = 0; j < mip_height; ++j ) + { + for( i = 0; i < mip_width; ++i ) + { + for( c = 0; c < channels; ++c ) + { + const int index = (j*block_size_y)*width*channels + (i*block_size_x)*channels + c; + int sum_value; + int u,v; + int u_block = block_size_x; + int v_block = block_size_y; + int block_area; + /* do a bit of checking so we don't over-run the boundaries + (necessary for non-square textures!) */ + if( block_size_x * (i+1) > width ) + { + u_block = width - i*block_size_y; + } + if( block_size_y * (j+1) > height ) + { + v_block = height - j*block_size_y; + } + block_area = u_block*v_block; + /* for this pixel, see what the average + of all the values in the block are. + note: start the sum at the rounding value, not at 0 */ + sum_value = block_area >> 1; + for( v = 0; v < v_block; ++v ) + for( u = 0; u < u_block; ++u ) + { + sum_value += orig[index + v*width*channels + u*channels]; + } + resampled[j*mip_width*channels + i*channels + c] = sum_value / block_area; + } + } + } + return 1; +} + +int + scale_image_RGB_to_NTSC_safe + ( + unsigned char* orig, + int width, int height, int channels + ) +{ + const float scale_lo = 16.0f - 0.499f; + const float scale_hi = 235.0f + 0.499f; + int i, j; + int nc = channels; + unsigned char scale_LUT[256]; + /* error check */ + if( (width < 1) || (height < 1) || + (channels < 1) || (orig == NULL) ) + { + /* nothing to do */ + return 0; + } + /* set up the scaling Look Up Table */ + for( i = 0; i < 256; ++i ) + { + scale_LUT[i] = (unsigned char)((scale_hi - scale_lo) * i / 255.0f + scale_lo); + } + /* for channels = 2 or 4, ignore the alpha component */ + nc -= 1 - (channels & 1); + /* OK, go through the image and scale any non-alpha components */ + for( i = 0; i < width*height*channels; i += channels ) + { + for( j = 0; j < nc; ++j ) + { + orig[i+j] = scale_LUT[orig[i+j]]; + } + } + return 1; +} + +unsigned char clamp_byte( int x ) { return ( (x) < 0 ? (0) : ( (x) > 255 ? 255 : (x) ) ); } + +/* + This function takes the RGB components of the image + and converts them into YCoCg. 3 components will be + re-ordered to CoYCg (for optimum DXT1 compression), + while 4 components will be ordered CoCgAY (for DXT5 + compression). +*/ +int + convert_RGB_to_YCoCg + ( + unsigned char* orig, + int width, int height, int channels + ) +{ + int i; + /* error check */ + if( (width < 1) || (height < 1) || + (channels < 3) || (channels > 4) || + (orig == NULL) ) + { + /* nothing to do */ + return -1; + } + /* do the conversion */ + if( channels == 3 ) + { + for( i = 0; i < width*height*3; i += 3 ) + { + int r = orig[i+0]; + int g = (orig[i+1] + 1) >> 1; + int b = orig[i+2]; + int tmp = (2 + r + b) >> 2; + /* Co */ + orig[i+0] = clamp_byte( 128 + ((r - b + 1) >> 1) ); + /* Y */ + orig[i+1] = clamp_byte( g + tmp ); + /* Cg */ + orig[i+2] = clamp_byte( 128 + g - tmp ); + } + } else + { + for( i = 0; i < width*height*4; i += 4 ) + { + int r = orig[i+0]; + int g = (orig[i+1] + 1) >> 1; + int b = orig[i+2]; + unsigned char a = orig[i+3]; + int tmp = (2 + r + b) >> 2; + /* Co */ + orig[i+0] = clamp_byte( 128 + ((r - b + 1) >> 1) ); + /* Cg */ + orig[i+1] = clamp_byte( 128 + g - tmp ); + /* Alpha */ + orig[i+2] = a; + /* Y */ + orig[i+3] = clamp_byte( g + tmp ); + } + } + /* done */ + return 0; +} + +/* + This function takes the YCoCg components of the image + and converts them into RGB. See above. +*/ +int + convert_YCoCg_to_RGB + ( + unsigned char* orig, + int width, int height, int channels + ) +{ + int i; + /* error check */ + if( (width < 1) || (height < 1) || + (channels < 3) || (channels > 4) || + (orig == NULL) ) + { + /* nothing to do */ + return -1; + } + /* do the conversion */ + if( channels == 3 ) + { + for( i = 0; i < width*height*3; i += 3 ) + { + int co = orig[i+0] - 128; + int y = orig[i+1]; + int cg = orig[i+2] - 128; + /* R */ + orig[i+0] = clamp_byte( y + co - cg ); + /* G */ + orig[i+1] = clamp_byte( y + cg ); + /* B */ + orig[i+2] = clamp_byte( y - co - cg ); + } + } else + { + for( i = 0; i < width*height*4; i += 4 ) + { + int co = orig[i+0] - 128; + int cg = orig[i+1] - 128; + unsigned char a = orig[i+2]; + int y = orig[i+3]; + /* R */ + orig[i+0] = clamp_byte( y + co - cg ); + /* G */ + orig[i+1] = clamp_byte( y + cg ); + /* B */ + orig[i+2] = clamp_byte( y - co - cg ); + /* A */ + orig[i+3] = a; + } + } + /* done */ + return 0; +} + +float +find_max_RGBE +( + unsigned char *image, + int width, int height +) +{ + float max_val = 0.0f; + unsigned char *img = image; + int i, j; + for( i = width * height; i > 0; --i ) + { + /* float scale = powf( 2.0f, img[3] - 128.0f ) / 255.0f; */ + float scale = (float)ldexp( 1.0f / 255.0f, (int)(img[3]) - 128 ); + for( j = 0; j < 3; ++j ) + { + if( img[j] * scale > max_val ) + { + max_val = img[j] * scale; + } + } + /* next pixel */ + img += 4; + } + return max_val; +} + +int +RGBE_to_RGBdivA +( + unsigned char *image, + int width, int height, + int rescale_to_max +) +{ + /* local variables */ + int i, iv; + unsigned char *img = image; + float scale = 1.0f; + /* error check */ + if( (!image) || (width < 1) || (height < 1) ) + { + return 0; + } + /* convert (note: no negative numbers, but 0.0 is possible) */ + if( rescale_to_max ) + { + scale = 255.0f / find_max_RGBE( image, width, height ); + } + for( i = width * height; i > 0; --i ) + { + /* decode this pixel, and find the max */ + float r,g,b,e, m; + /* e = scale * powf( 2.0f, img[3] - 128.0f ) / 255.0f; */ + e = scale * (float)ldexp( 1.0f / 255.0f, (int)(img[3]) - 128 ); + r = e * img[0]; + g = e * img[1]; + b = e * img[2]; + m = (r > g) ? r : g; + m = (b > m) ? b : m; + /* and encode it into RGBdivA */ + iv = (m != 0.0f) ? (int)(255.0f / m) : 1; + iv = (iv < 1) ? 1 : iv; + img[3] = (iv > 255) ? 255 : iv; + iv = (int)(img[3] * r + 0.5f); + img[0] = (iv > 255) ? 255 : iv; + iv = (int)(img[3] * g + 0.5f); + img[1] = (iv > 255) ? 255 : iv; + iv = (int)(img[3] * b + 0.5f); + img[2] = (iv > 255) ? 255 : iv; + /* and on to the next pixel */ + img += 4; + } + return 1; +} + +int +RGBE_to_RGBdivA2 +( + unsigned char *image, + int width, int height, + int rescale_to_max +) +{ + /* local variables */ + int i, iv; + unsigned char *img = image; + float scale = 1.0f; + /* error check */ + if( (!image) || (width < 1) || (height < 1) ) + { + return 0; + } + /* convert (note: no negative numbers, but 0.0 is possible) */ + if( rescale_to_max ) + { + scale = 255.0f * 255.0f / find_max_RGBE( image, width, height ); + } + for( i = width * height; i > 0; --i ) + { + /* decode this pixel, and find the max */ + float r,g,b,e, m; + /* e = scale * powf( 2.0f, img[3] - 128.0f ) / 255.0f; */ + e = scale * (float)ldexp( 1.0f / 255.0f, (int)(img[3]) - 128 ); + r = e * img[0]; + g = e * img[1]; + b = e * img[2]; + m = (r > g) ? r : g; + m = (b > m) ? b : m; + /* and encode it into RGBdivA */ + iv = (m != 0.0f) ? (int)sqrtf( 255.0f * 255.0f / m ) : 1; + iv = (iv < 1) ? 1 : iv; + img[3] = (iv > 255) ? 255 : iv; + iv = (int)(img[3] * img[3] * r / 255.0f + 0.5f); + img[0] = (iv > 255) ? 255 : iv; + iv = (int)(img[3] * img[3] * g / 255.0f + 0.5f); + img[1] = (iv > 255) ? 255 : iv; + iv = (int)(img[3] * img[3] * b / 255.0f + 0.5f); + img[2] = (iv > 255) ? 255 : iv; + /* and on to the next pixel */ + img += 4; + } + return 1; +} diff --git a/Loaders/SoilTextureLoader/SOIL/image_helper.h b/Loaders/SoilTextureLoader/SOIL/image_helper.h new file mode 100644 index 0000000..3fa2662 --- /dev/null +++ b/Loaders/SoilTextureLoader/SOIL/image_helper.h @@ -0,0 +1,115 @@ +/* + Jonathan Dummer + + Image helper functions + + MIT license +*/ + +#ifndef HEADER_IMAGE_HELPER +#define HEADER_IMAGE_HELPER + +#ifdef __cplusplus +extern "C" { +#endif + +/** + This function upscales an image. + Not to be used to create MIPmaps, + but to make it square, + or to make it a power-of-two sized. +**/ +int + up_scale_image + ( + const unsigned char* const orig, + int width, int height, int channels, + unsigned char* resampled, + int resampled_width, int resampled_height + ); + +/** + This function downscales an image. + Used for creating MIPmaps, + the incoming image should be a + power-of-two sized. +**/ +int + mipmap_image + ( + const unsigned char* const orig, + int width, int height, int channels, + unsigned char* resampled, + int block_size_x, int block_size_y + ); + +/** + This function takes the RGB components of the image + and scales each channel from [0,255] to [16,235]. + This makes the colors "Safe" for display on NTSC + displays. Note that this is _NOT_ a good idea for + loading images like normal- or height-maps! +**/ +int + scale_image_RGB_to_NTSC_safe + ( + unsigned char* orig, + int width, int height, int channels + ); + +/** + This function takes the RGB components of the image + and converts them into YCoCg. 3 components will be + re-ordered to CoYCg (for optimum DXT1 compression), + while 4 components will be ordered CoCgAY (for DXT5 + compression). +**/ +int + convert_RGB_to_YCoCg + ( + unsigned char* orig, + int width, int height, int channels + ); + +/** + This function takes the YCoCg components of the image + and converts them into RGB. See above. +**/ +int + convert_YCoCg_to_RGB + ( + unsigned char* orig, + int width, int height, int channels + ); + +/** + Converts an HDR image from an array + of unsigned chars (RGBE) to RGBdivA + \return 0 if failed, otherwise returns 1 +**/ +int + RGBE_to_RGBdivA + ( + unsigned char *image, + int width, int height, + int rescale_to_max + ); + +/** + Converts an HDR image from an array + of unsigned chars (RGBE) to RGBdivA2 + \return 0 if failed, otherwise returns 1 +**/ +int + RGBE_to_RGBdivA2 + ( + unsigned char *image, + int width, int height, + int rescale_to_max + ); + +#ifdef __cplusplus +} +#endif + +#endif /* HEADER_IMAGE_HELPER */ diff --git a/Loaders/SoilTextureLoader/SOIL/jo_jpeg.h b/Loaders/SoilTextureLoader/SOIL/jo_jpeg.h new file mode 100644 index 0000000..e951a5a --- /dev/null +++ b/Loaders/SoilTextureLoader/SOIL/jo_jpeg.h @@ -0,0 +1,338 @@ +/* public domain Simple, Minimalistic JPEG writer - http://jonolick.com + * + * Quick Notes: + * Based on a javascript jpeg writer + * JPEG baseline (no JPEG progressive) + * Supports 1, 3 or 4 component input. (luminance, RGB or RGBX) + * + * Latest revisions: + * 1.53 (2016-07-08) Added support to compile as plain C code. + * 1.52 (2012-22-11) Added support for specifying Luminance, RGB, or RGBA via comp(onents) argument (1, 3 and 4 respectively). + * 1.51 (2012-19-11) Fixed some warnings + * 1.50 (2012-18-11) MT safe. Simplified. Optimized. Reduced memory requirements. Zero allocations. No namespace polution. Approx 340 lines code. + * 1.10 (2012-16-11) compile fixes, added docs, + * changed from .h to .cpp (simpler to bootstrap), etc + * 1.00 (2012-02-02) initial release + * + * Basic usage: + * char *foo = new char[128*128*4]; // 4 component. RGBX format, where X is unused + * jo_write_jpg("foo.jpg", foo, 128, 128, 4, 90); // comp can be 1, 3, or 4. Lum, RGB, or RGBX respectively. + * + * */ + +#ifndef JO_INCLUDE_JPEG_H +#define JO_INCLUDE_JPEG_H + +// To get a header file for this, either cut and paste the header, +// or create jo_jpeg.h, #define JO_JPEG_HEADER_FILE_ONLY, and +// then include jo_jpeg.c from it. + +// Returns false on failure +extern int jo_write_jpg(const char *filename, const void *data, int width, int height, int comp, int quality); + +#endif // JO_INCLUDE_JPEG_H + +#ifndef JO_JPEG_HEADER_FILE_ONLY + +#if defined(_MSC_VER) && _MSC_VER >= 0x1400 +#define _CRT_SECURE_NO_WARNINGS // suppress warnings about fopen() +#endif + +#include +#include +#include + +static const unsigned char s_jo_ZigZag[] = { 0,1,5,6,14,15,27,28,2,4,7,13,16,26,29,42,3,8,12,17,25,30,41,43,9,11,18,24,31,40,44,53,10,19,23,32,39,45,52,54,20,22,33,38,46,51,55,60,21,34,37,47,50,56,59,61,35,36,48,49,57,58,62,63 }; + +static void jo_writeBits(FILE *fp, int *bitBuf, int *bitCnt, const unsigned short *bs) { + *bitCnt += bs[1]; + *bitBuf |= bs[0] << (24 - *bitCnt); + while(*bitCnt >= 8) { + unsigned char c = (*bitBuf >> 16) & 255; + putc(c, fp); + if(c == 255) { + putc(0, fp); + } + *bitBuf <<= 8; + *bitCnt -= 8; + } +} + +static void jo_DCT(float *d0, float *d1, float *d2, float *d3, float *d4, float *d5, float *d6, float *d7) { + float tmp0 = *d0 + *d7; + float tmp7 = *d0 - *d7; + float tmp1 = *d1 + *d6; + float tmp6 = *d1 - *d6; + float tmp2 = *d2 + *d5; + float tmp5 = *d2 - *d5; + float tmp3 = *d3 + *d4; + float tmp4 = *d3 - *d4; + + // Even part + float tmp10 = tmp0 + tmp3; // phase 2 + float tmp13 = tmp0 - tmp3; + float tmp11 = tmp1 + tmp2; + float tmp12 = tmp1 - tmp2; + + *d0 = tmp10 + tmp11; // phase 3 + *d4 = tmp10 - tmp11; + + float z1 = (tmp12 + tmp13) * 0.707106781f; // c4 + *d2 = tmp13 + z1; // phase 5 + *d6 = tmp13 - z1; + + // Odd part + tmp10 = tmp4 + tmp5; // phase 2 + tmp11 = tmp5 + tmp6; + tmp12 = tmp6 + tmp7; + + // The rotator is modified from fig 4-8 to avoid extra negations. + float z5 = (tmp10 - tmp12) * 0.382683433f; // c6 + float z2 = tmp10 * 0.541196100f + z5; // c2-c6 + float z4 = tmp12 * 1.306562965f + z5; // c2+c6 + float z3 = tmp11 * 0.707106781f; // c4 + + float z11 = tmp7 + z3; // phase 5 + float z13 = tmp7 - z3; + + *d5 = z13 + z2; // phase 6 + *d3 = z13 - z2; + *d1 = z11 + z4; + *d7 = z11 - z4; +} + +static void jo_calcBits(int val, unsigned short bits[2]) { + int tmp1 = val < 0 ? -val : val; + val = val < 0 ? val-1 : val; + bits[1] = 1; + while(tmp1 >>= 1) { + ++bits[1]; + } + bits[0] = val & ((1<0)&&(DU[end0pos]==0); --end0pos) { + } + // end0pos = first element in reverse order !=0 + if(end0pos == 0) { + jo_writeBits(fp, bitBuf, bitCnt, EOB); + return DU[0]; + } + for(int i = 1; i <= end0pos; ++i) { + int startpos = i; + for (; DU[i]==0 && i<=end0pos; ++i) { + } + int nrzeroes = i-startpos; + if ( nrzeroes >= 16 ) { + int lng = nrzeroes>>4; + for (int nrmarker=1; nrmarker <= lng; ++nrmarker) + jo_writeBits(fp, bitBuf, bitCnt, M16zeroes); + nrzeroes &= 15; + } + unsigned short bits[2]; + jo_calcBits(DU[i], bits); + jo_writeBits(fp, bitBuf, bitCnt, HTAC[(nrzeroes<<4)+bits[1]]); + jo_writeBits(fp, bitBuf, bitCnt, bits); + } + if(end0pos != 63) { + jo_writeBits(fp, bitBuf, bitCnt, EOB); + } + return DU[0]; +} + +int jo_write_jpg(const char *filename, const void *data, int width, int height, int comp, int quality) { + // Constants that don't pollute global namespace + static const unsigned char std_dc_luminance_nrcodes[] = {0,0,1,5,1,1,1,1,1,1,0,0,0,0,0,0,0}; + static const unsigned char std_dc_luminance_values[] = {0,1,2,3,4,5,6,7,8,9,10,11}; + static const unsigned char std_ac_luminance_nrcodes[] = {0,0,2,1,3,3,2,4,3,5,5,4,4,0,0,1,0x7d}; + static const unsigned char std_ac_luminance_values[] = { + 0x01,0x02,0x03,0x00,0x04,0x11,0x05,0x12,0x21,0x31,0x41,0x06,0x13,0x51,0x61,0x07,0x22,0x71,0x14,0x32,0x81,0x91,0xa1,0x08, + 0x23,0x42,0xb1,0xc1,0x15,0x52,0xd1,0xf0,0x24,0x33,0x62,0x72,0x82,0x09,0x0a,0x16,0x17,0x18,0x19,0x1a,0x25,0x26,0x27,0x28, + 0x29,0x2a,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x53,0x54,0x55,0x56,0x57,0x58,0x59, + 0x5a,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x83,0x84,0x85,0x86,0x87,0x88,0x89, + 0x8a,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xb2,0xb3,0xb4,0xb5,0xb6, + 0xb7,0xb8,0xb9,0xba,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xe1,0xe2, + 0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa + }; + static const unsigned char std_dc_chrominance_nrcodes[] = {0,0,3,1,1,1,1,1,1,1,1,1,0,0,0,0,0}; + static const unsigned char std_dc_chrominance_values[] = {0,1,2,3,4,5,6,7,8,9,10,11}; + static const unsigned char std_ac_chrominance_nrcodes[] = {0,0,2,1,2,4,4,3,4,7,5,4,4,0,1,2,0x77}; + static const unsigned char std_ac_chrominance_values[] = { + 0x00,0x01,0x02,0x03,0x11,0x04,0x05,0x21,0x31,0x06,0x12,0x41,0x51,0x07,0x61,0x71,0x13,0x22,0x32,0x81,0x08,0x14,0x42,0x91, + 0xa1,0xb1,0xc1,0x09,0x23,0x33,0x52,0xf0,0x15,0x62,0x72,0xd1,0x0a,0x16,0x24,0x34,0xe1,0x25,0xf1,0x17,0x18,0x19,0x1a,0x26, + 0x27,0x28,0x29,0x2a,0x35,0x36,0x37,0x38,0x39,0x3a,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x53,0x54,0x55,0x56,0x57,0x58, + 0x59,0x5a,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x82,0x83,0x84,0x85,0x86,0x87, + 0x88,0x89,0x8a,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xb2,0xb3,0xb4, + 0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda, + 0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa + }; + // Huffman tables + static const unsigned short YDC_HT[256][2] = { {0,2},{2,3},{3,3},{4,3},{5,3},{6,3},{14,4},{30,5},{62,6},{126,7},{254,8},{510,9}}; + static const unsigned short UVDC_HT[256][2] = { {0,2},{1,2},{2,2},{6,3},{14,4},{30,5},{62,6},{126,7},{254,8},{510,9},{1022,10},{2046,11}}; + static const unsigned short YAC_HT[256][2] = { + {10,4},{0,2},{1,2},{4,3},{11,4},{26,5},{120,7},{248,8},{1014,10},{65410,16},{65411,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {12,4},{27,5},{121,7},{502,9},{2038,11},{65412,16},{65413,16},{65414,16},{65415,16},{65416,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {28,5},{249,8},{1015,10},{4084,12},{65417,16},{65418,16},{65419,16},{65420,16},{65421,16},{65422,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {58,6},{503,9},{4085,12},{65423,16},{65424,16},{65425,16},{65426,16},{65427,16},{65428,16},{65429,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {59,6},{1016,10},{65430,16},{65431,16},{65432,16},{65433,16},{65434,16},{65435,16},{65436,16},{65437,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {122,7},{2039,11},{65438,16},{65439,16},{65440,16},{65441,16},{65442,16},{65443,16},{65444,16},{65445,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {123,7},{4086,12},{65446,16},{65447,16},{65448,16},{65449,16},{65450,16},{65451,16},{65452,16},{65453,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {250,8},{4087,12},{65454,16},{65455,16},{65456,16},{65457,16},{65458,16},{65459,16},{65460,16},{65461,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {504,9},{32704,15},{65462,16},{65463,16},{65464,16},{65465,16},{65466,16},{65467,16},{65468,16},{65469,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {505,9},{65470,16},{65471,16},{65472,16},{65473,16},{65474,16},{65475,16},{65476,16},{65477,16},{65478,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {506,9},{65479,16},{65480,16},{65481,16},{65482,16},{65483,16},{65484,16},{65485,16},{65486,16},{65487,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {1017,10},{65488,16},{65489,16},{65490,16},{65491,16},{65492,16},{65493,16},{65494,16},{65495,16},{65496,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {1018,10},{65497,16},{65498,16},{65499,16},{65500,16},{65501,16},{65502,16},{65503,16},{65504,16},{65505,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {2040,11},{65506,16},{65507,16},{65508,16},{65509,16},{65510,16},{65511,16},{65512,16},{65513,16},{65514,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {65515,16},{65516,16},{65517,16},{65518,16},{65519,16},{65520,16},{65521,16},{65522,16},{65523,16},{65524,16},{0,0},{0,0},{0,0},{0,0},{0,0}, + {2041,11},{65525,16},{65526,16},{65527,16},{65528,16},{65529,16},{65530,16},{65531,16},{65532,16},{65533,16},{65534,16},{0,0},{0,0},{0,0},{0,0},{0,0} + }; + static const unsigned short UVAC_HT[256][2] = { + {0,2},{1,2},{4,3},{10,4},{24,5},{25,5},{56,6},{120,7},{500,9},{1014,10},{4084,12},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {11,4},{57,6},{246,8},{501,9},{2038,11},{4085,12},{65416,16},{65417,16},{65418,16},{65419,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {26,5},{247,8},{1015,10},{4086,12},{32706,15},{65420,16},{65421,16},{65422,16},{65423,16},{65424,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {27,5},{248,8},{1016,10},{4087,12},{65425,16},{65426,16},{65427,16},{65428,16},{65429,16},{65430,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {58,6},{502,9},{65431,16},{65432,16},{65433,16},{65434,16},{65435,16},{65436,16},{65437,16},{65438,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {59,6},{1017,10},{65439,16},{65440,16},{65441,16},{65442,16},{65443,16},{65444,16},{65445,16},{65446,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {121,7},{2039,11},{65447,16},{65448,16},{65449,16},{65450,16},{65451,16},{65452,16},{65453,16},{65454,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {122,7},{2040,11},{65455,16},{65456,16},{65457,16},{65458,16},{65459,16},{65460,16},{65461,16},{65462,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {249,8},{65463,16},{65464,16},{65465,16},{65466,16},{65467,16},{65468,16},{65469,16},{65470,16},{65471,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {503,9},{65472,16},{65473,16},{65474,16},{65475,16},{65476,16},{65477,16},{65478,16},{65479,16},{65480,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {504,9},{65481,16},{65482,16},{65483,16},{65484,16},{65485,16},{65486,16},{65487,16},{65488,16},{65489,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {505,9},{65490,16},{65491,16},{65492,16},{65493,16},{65494,16},{65495,16},{65496,16},{65497,16},{65498,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {506,9},{65499,16},{65500,16},{65501,16},{65502,16},{65503,16},{65504,16},{65505,16},{65506,16},{65507,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {2041,11},{65508,16},{65509,16},{65510,16},{65511,16},{65512,16},{65513,16},{65514,16},{65515,16},{65516,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {16352,14},{65517,16},{65518,16},{65519,16},{65520,16},{65521,16},{65522,16},{65523,16},{65524,16},{65525,16},{0,0},{0,0},{0,0},{0,0},{0,0}, + {1018,10},{32707,15},{65526,16},{65527,16},{65528,16},{65529,16},{65530,16},{65531,16},{65532,16},{65533,16},{65534,16},{0,0},{0,0},{0,0},{0,0},{0,0} + }; + static const int YQT[] = {16,11,10,16,24,40,51,61,12,12,14,19,26,58,60,55,14,13,16,24,40,57,69,56,14,17,22,29,51,87,80,62,18,22,37,56,68,109,103,77,24,35,55,64,81,104,113,92,49,64,78,87,103,121,120,101,72,92,95,98,112,100,103,99}; + static const int UVQT[] = {17,18,24,47,99,99,99,99,18,21,26,66,99,99,99,99,24,26,56,99,99,99,99,99,47,66,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99}; + static const float aasf[] = { 1.0f * 2.828427125f, 1.387039845f * 2.828427125f, 1.306562965f * 2.828427125f, 1.175875602f * 2.828427125f, 1.0f * 2.828427125f, 0.785694958f * 2.828427125f, 0.541196100f * 2.828427125f, 0.275899379f * 2.828427125f }; + + if(!data || !filename || !width || !height || comp > 4 || comp < 1 || comp == 2) { + return 0; + } + + FILE *fp = fopen(filename, "wb"); + if(!fp) { + return 0; + } + + quality = quality ? quality : 90; + quality = quality < 1 ? 1 : quality > 100 ? 100 : quality; + quality = quality < 50 ? 5000 / quality : 200 - quality * 2; + + unsigned char YTable[64], UVTable[64]; + for(int i = 0; i < 64; ++i) { + int yti = (YQT[i]*quality+50)/100; + YTable[s_jo_ZigZag[i]] = yti < 1 ? 1 : yti > 255 ? 255 : yti; + int uvti = (UVQT[i]*quality+50)/100; + UVTable[s_jo_ZigZag[i]] = uvti < 1 ? 1 : uvti > 255 ? 255 : uvti; + } + + float fdtbl_Y[64], fdtbl_UV[64]; + for(int row = 0, k = 0; row < 8; ++row) { + for(int col = 0; col < 8; ++col, ++k) { + fdtbl_Y[k] = 1 / (YTable [s_jo_ZigZag[k]] * aasf[row] * aasf[col]); + fdtbl_UV[k] = 1 / (UVTable[s_jo_ZigZag[k]] * aasf[row] * aasf[col]); + } + } + + // Write Headers + static const unsigned char head0[] = { 0xFF,0xD8,0xFF,0xE0,0,0x10,'J','F','I','F',0,1,1,0,0,1,0,1,0,0,0xFF,0xDB,0,0x84,0 }; + fwrite(head0, sizeof(head0), 1, fp); + fwrite(YTable, sizeof(YTable), 1, fp); + putc(1, fp); + fwrite(UVTable, sizeof(UVTable), 1, fp); + const unsigned char head1[] = { 0xFF,0xC0,0,0x11,8,(unsigned char)(height>>8),(unsigned char)(height&0xFF),(unsigned char)(width>>8),(unsigned char)(width&0xFF),3,1,0x11,0,2,0x11,1,3,0x11,1,0xFF,0xC4,0x01,0xA2,0 }; + fwrite(head1, sizeof(head1), 1, fp); + fwrite(std_dc_luminance_nrcodes+1, sizeof(std_dc_luminance_nrcodes)-1, 1, fp); + fwrite(std_dc_luminance_values, sizeof(std_dc_luminance_values), 1, fp); + putc(0x10, fp); // HTYACinfo + fwrite(std_ac_luminance_nrcodes+1, sizeof(std_ac_luminance_nrcodes)-1, 1, fp); + fwrite(std_ac_luminance_values, sizeof(std_ac_luminance_values), 1, fp); + putc(1, fp); // HTUDCinfo + fwrite(std_dc_chrominance_nrcodes+1, sizeof(std_dc_chrominance_nrcodes)-1, 1, fp); + fwrite(std_dc_chrominance_values, sizeof(std_dc_chrominance_values), 1, fp); + putc(0x11, fp); // HTUACinfo + fwrite(std_ac_chrominance_nrcodes+1, sizeof(std_ac_chrominance_nrcodes)-1, 1, fp); + fwrite(std_ac_chrominance_values, sizeof(std_ac_chrominance_values), 1, fp); + static const unsigned char head2[] = { 0xFF,0xDA,0,0xC,3,1,0,2,0x11,3,0x11,0,0x3F,0 }; + fwrite(head2, sizeof(head2), 1, fp); + + // Encode 8x8 macroblocks + const unsigned char *imageData = (const unsigned char *)data; + int DCY=0, DCU=0, DCV=0; + int bitBuf=0, bitCnt=0; + int ofsG = comp > 1 ? 1 : 0, ofsB = comp > 1 ? 2 : 0; + for(int y = 0; y < height; y += 8) { + for(int x = 0; x < width; x += 8) { + float YDU[64], UDU[64], VDU[64]; + for(int row = y, pos = 0; row < y+8; ++row) { + for(int col = x; col < x+8; ++col, ++pos) { + int p = row*width*comp + col*comp; + if(row >= height) { + p -= width*comp*(row+1 - height); + } + if(col >= width) { + p -= comp*(col+1 - width); + } + + float r = imageData[p+0], g = imageData[p+ofsG], b = imageData[p+ofsB]; + YDU[pos]=+0.29900f*r+0.58700f*g+0.11400f*b-128; + UDU[pos]=-0.16874f*r-0.33126f*g+0.50000f*b; + VDU[pos]=+0.50000f*r-0.41869f*g-0.08131f*b; + } + } + + DCY = jo_processDU(fp, &bitBuf, &bitCnt, YDU, fdtbl_Y, DCY, YDC_HT, YAC_HT); + DCU = jo_processDU(fp, &bitBuf, &bitCnt, UDU, fdtbl_UV, DCU, UVDC_HT, UVAC_HT); + DCV = jo_processDU(fp, &bitBuf, &bitCnt, VDU, fdtbl_UV, DCV, UVDC_HT, UVAC_HT); + } + } + + // Do the bit alignment of the EOI marker + static const unsigned short fillBits[] = {0x7F, 7}; + jo_writeBits(fp, &bitBuf, &bitCnt, fillBits); + + // EOI + putc(0xFF, fp); + putc(0xD9, fp); + + fclose(fp); + return 1; +} + +#endif + diff --git a/Loaders/SoilTextureLoader/SOIL/pkm_helper.h b/Loaders/SoilTextureLoader/SOIL/pkm_helper.h new file mode 100644 index 0000000..0143e3f --- /dev/null +++ b/Loaders/SoilTextureLoader/SOIL/pkm_helper.h @@ -0,0 +1,19 @@ +#ifndef PKM_HELPER_H +#define PKM_HELPER_H + +typedef struct { + char aName[6]; + unsigned short iBlank; + unsigned char iPaddedWidthMSB; + unsigned char iPaddedWidthLSB; + unsigned char iPaddedHeightMSB; + unsigned char iPaddedHeightLSB; + unsigned char iWidthMSB; + unsigned char iWidthLSB; + unsigned char iHeightMSB; + unsigned char iHeightLSB; +} PKMHeader; + +#define PKM_HEADER_SIZE 16 + +#endif diff --git a/Loaders/SoilTextureLoader/SOIL/pvr_helper.h b/Loaders/SoilTextureLoader/SOIL/pvr_helper.h new file mode 100644 index 0000000..bace1f3 --- /dev/null +++ b/Loaders/SoilTextureLoader/SOIL/pvr_helper.h @@ -0,0 +1,264 @@ +#ifndef PVR_HELPER_H +#define PVR_HELPER_H + +// Taken from PowerVR SDK + +/*!*************************************************************************** + Describes the header of a PVR header-texture + *****************************************************************************/ +typedef struct +{ + unsigned int dwHeaderSize; /*!< size of the structure */ + unsigned int dwHeight; /*!< height of surface to be created */ + unsigned int dwWidth; /*!< width of input surface */ + unsigned int dwMipMapCount; /*!< number of mip-map levels requested */ + unsigned int dwpfFlags; /*!< pixel format flags */ + unsigned int dwTextureDataSize; /*!< Total size in bytes */ + unsigned int dwBitCount; /*!< number of bits per pixel */ + unsigned int dwRBitMask; /*!< mask for red bit */ + unsigned int dwGBitMask; /*!< mask for green bits */ + unsigned int dwBBitMask; /*!< mask for blue bits */ + unsigned int dwAlphaBitMask; /*!< mask for alpha channel */ + unsigned int dwPVR; /*!< magic number identifying pvr file */ + unsigned int dwNumSurfs; /*!< the number of surfaces present in the pvr */ +} PVR_Texture_Header; + +/***************************************************************************** + * ENUMS + *****************************************************************************/ + +enum PixelType +{ + MGLPT_ARGB_4444 = 0x00, + MGLPT_ARGB_1555, + MGLPT_RGB_565, + MGLPT_RGB_555, + MGLPT_RGB_888, + MGLPT_ARGB_8888, + MGLPT_ARGB_8332, + MGLPT_I_8, + MGLPT_AI_88, + MGLPT_1_BPP, + MGLPT_VY1UY0, + MGLPT_Y1VY0U, + MGLPT_PVRTC2, + MGLPT_PVRTC4, + MGLPT_PVRTC2_2, + MGLPT_PVRTC2_4, + + OGL_RGBA_4444= 0x10, + OGL_RGBA_5551, + OGL_RGBA_8888, + OGL_RGB_565, + OGL_RGB_555, + OGL_RGB_888, + OGL_I_8, + OGL_AI_88, + OGL_PVRTC2, + OGL_PVRTC4, + + // OGL_BGRA_8888 extension + OGL_BGRA_8888, + + D3D_DXT1 = 0x20, + D3D_DXT2, + D3D_DXT3, + D3D_DXT4, + D3D_DXT5, + + D3D_RGB_332, + D3D_AI_44, + D3D_LVU_655, + D3D_XLVU_8888, + D3D_QWVU_8888, + + //10 bits per channel + D3D_ABGR_2101010, + D3D_ARGB_2101010, + D3D_AWVU_2101010, + + //16 bits per channel + D3D_GR_1616, + D3D_VU_1616, + D3D_ABGR_16161616, + + //HDR formats + D3D_R16F, + D3D_GR_1616F, + D3D_ABGR_16161616F, + + //32 bits per channel + D3D_R32F, + D3D_GR_3232F, + D3D_ABGR_32323232F, + + // Ericsson + ETC_RGB_4BPP, + ETC_RGBA_EXPLICIT, + ETC_RGBA_INTERPOLATED, + + // DX10 + + + ePT_DX10_R32G32B32A32_FLOAT= 0x50, + ePT_DX10_R32G32B32A32_UINT , + ePT_DX10_R32G32B32A32_SINT, + + ePT_DX10_R32G32B32_FLOAT, + ePT_DX10_R32G32B32_UINT, + ePT_DX10_R32G32B32_SINT, + + ePT_DX10_R16G16B16A16_FLOAT , + ePT_DX10_R16G16B16A16_UNORM, + ePT_DX10_R16G16B16A16_UINT , + ePT_DX10_R16G16B16A16_SNORM , + ePT_DX10_R16G16B16A16_SINT , + + ePT_DX10_R32G32_FLOAT , + ePT_DX10_R32G32_UINT , + ePT_DX10_R32G32_SINT , + + ePT_DX10_R10G10B10A2_UNORM , + ePT_DX10_R10G10B10A2_UINT , + + ePT_DX10_R11G11B10_FLOAT , + + ePT_DX10_R8G8B8A8_UNORM , + ePT_DX10_R8G8B8A8_UNORM_SRGB , + ePT_DX10_R8G8B8A8_UINT , + ePT_DX10_R8G8B8A8_SNORM , + ePT_DX10_R8G8B8A8_SINT , + + ePT_DX10_R16G16_FLOAT , + ePT_DX10_R16G16_UNORM , + ePT_DX10_R16G16_UINT , + ePT_DX10_R16G16_SNORM , + ePT_DX10_R16G16_SINT , + + ePT_DX10_R32_FLOAT , + ePT_DX10_R32_UINT , + ePT_DX10_R32_SINT , + + ePT_DX10_R8G8_UNORM , + ePT_DX10_R8G8_UINT , + ePT_DX10_R8G8_SNORM , + ePT_DX10_R8G8_SINT , + + ePT_DX10_R16_FLOAT , + ePT_DX10_R16_UNORM , + ePT_DX10_R16_UINT , + ePT_DX10_R16_SNORM , + ePT_DX10_R16_SINT , + + ePT_DX10_R8_UNORM, + ePT_DX10_R8_UINT, + ePT_DX10_R8_SNORM, + ePT_DX10_R8_SINT, + + ePT_DX10_A8_UNORM, + ePT_DX10_R1_UNORM, + ePT_DX10_R9G9B9E5_SHAREDEXP, + ePT_DX10_R8G8_B8G8_UNORM, + ePT_DX10_G8R8_G8B8_UNORM, + + ePT_DX10_BC1_UNORM, + ePT_DX10_BC1_UNORM_SRGB, + + ePT_DX10_BC2_UNORM, + ePT_DX10_BC2_UNORM_SRGB, + + ePT_DX10_BC3_UNORM, + ePT_DX10_BC3_UNORM_SRGB, + + ePT_DX10_BC4_UNORM, + ePT_DX10_BC4_SNORM, + + ePT_DX10_BC5_UNORM, + ePT_DX10_BC5_SNORM, + + //ePT_DX10_B5G6R5_UNORM, // defined but obsolete - won't actually load in DX10 + //ePT_DX10_B5G5R5A1_UNORM, + //ePT_DX10_B8G8R8A8_UNORM, + //ePT_DX10_B8G8R8X8_UNORM, + + // OpenVG + + /* RGB{A,X} channel ordering */ + ePT_VG_sRGBX_8888 = 0x90, + ePT_VG_sRGBA_8888, + ePT_VG_sRGBA_8888_PRE, + ePT_VG_sRGB_565, + ePT_VG_sRGBA_5551, + ePT_VG_sRGBA_4444, + ePT_VG_sL_8, + ePT_VG_lRGBX_8888, + ePT_VG_lRGBA_8888, + ePT_VG_lRGBA_8888_PRE, + ePT_VG_lL_8, + ePT_VG_A_8, + ePT_VG_BW_1, + + /* {A,X}RGB channel ordering */ + ePT_VG_sXRGB_8888, + ePT_VG_sARGB_8888, + ePT_VG_sARGB_8888_PRE, + ePT_VG_sARGB_1555, + ePT_VG_sARGB_4444, + ePT_VG_lXRGB_8888, + ePT_VG_lARGB_8888, + ePT_VG_lARGB_8888_PRE, + + /* BGR{A,X} channel ordering */ + ePT_VG_sBGRX_8888, + ePT_VG_sBGRA_8888, + ePT_VG_sBGRA_8888_PRE, + ePT_VG_sBGR_565, + ePT_VG_sBGRA_5551, + ePT_VG_sBGRA_4444, + ePT_VG_lBGRX_8888, + ePT_VG_lBGRA_8888, + ePT_VG_lBGRA_8888_PRE, + + /* {A,X}BGR channel ordering */ + ePT_VG_sXBGR_8888, + ePT_VG_sABGR_8888 , + ePT_VG_sABGR_8888_PRE, + ePT_VG_sABGR_1555, + ePT_VG_sABGR_4444, + ePT_VG_lXBGR_8888, + ePT_VG_lABGR_8888, + ePT_VG_lABGR_8888_PRE, + + // max cap for iterating + END_OF_PIXEL_TYPES, + + MGLPT_NOTYPE = 0xff + +}; + +/***************************************************************************** + * constants + *****************************************************************************/ + +#define PVRTEX_MIPMAP (1<<8) // has mip map levels +#define PVRTEX_TWIDDLE (1<<9) // is twiddled +#define PVRTEX_BUMPMAP (1<<10) // has normals encoded for a bump map +#define PVRTEX_TILING (1<<11) // is bordered for tiled pvr +#define PVRTEX_CUBEMAP (1<<12) // is a cubemap/skybox +#define PVRTEX_FALSEMIPCOL (1<<13) // +#define PVRTEX_VOLUME (1<<14) +#define PVRTEX_PIXELTYPE 0xff // pixel type is always in the last 16bits of the flags +#define PVRTEX_IDENTIFIER 0x21525650 // the pvr identifier is the characters 'P','V','R' + +#define PVRTEX_V1_HEADER_SIZE 44 // old header size was 44 for identification purposes + +#define PVRTC2_MIN_TEXWIDTH 16 +#define PVRTC2_MIN_TEXHEIGHT 8 +#define PVRTC4_MIN_TEXWIDTH 8 +#define PVRTC4_MIN_TEXHEIGHT 8 +#define ETC_MIN_TEXWIDTH 4 +#define ETC_MIN_TEXHEIGHT 4 +#define DXT_MIN_TEXWIDTH 4 +#define DXT_MIN_TEXHEIGHT 4 + +#endif diff --git a/Loaders/SoilTextureLoader/SOIL/stb_image.h b/Loaders/SoilTextureLoader/SOIL/stb_image.h new file mode 100644 index 0000000..67946b6 --- /dev/null +++ b/Loaders/SoilTextureLoader/SOIL/stb_image.h @@ -0,0 +1,6582 @@ +/* stb_image - v2.08 - public domain image loader - http://nothings.org/stb_image.h + no warranty implied; use at your own risk + + Do this: + #define STB_IMAGE_IMPLEMENTATION + before you include this file in *one* C or C++ file to create the implementation. + + // i.e. it should look like this: + #include ... + #include ... + #include ... + #define STB_IMAGE_IMPLEMENTATION + #include "stb_image.h" + + You can #define STBI_ASSERT(x) before the #include to avoid using assert.h. + And #define STBI_MALLOC, STBI_REALLOC, and STBI_FREE to avoid using malloc,realloc,free + + + QUICK NOTES: + Primarily of interest to game developers and other people who can + avoid problematic images and only need the trivial interface + + JPEG baseline & progressive (12 bpc/arithmetic not supported, same as stock IJG lib) + PNG 1/2/4/8-bit-per-channel (16 bpc not supported) + + TGA (not sure what subset, if a subset) + BMP non-1bpp, non-RLE + PSD (composited view only, no extra channels, 8/16 bit-per-channel) + + GIF (*comp always reports as 4-channel) + HDR (radiance rgbE format) + PIC (Softimage PIC) + PNM (PPM and PGM binary only) + + Animated GIF still needs a proper API, but here's one way to do it: + http://gist.github.com/urraka/685d9a6340b26b830d49 + + - decode from memory or through FILE (define STBI_NO_STDIO to remove code) + - decode from arbitrary I/O callbacks + - SIMD acceleration on x86/x64 (SSE2) and ARM (NEON) + + Full documentation under "DOCUMENTATION" below. + + + Revision 2.00 release notes: + + - Progressive JPEG is now supported. + + - PPM and PGM binary formats are now supported, thanks to Ken Miller. + + - x86 platforms now make use of SSE2 SIMD instructions for + JPEG decoding, and ARM platforms can use NEON SIMD if requested. + This work was done by Fabian "ryg" Giesen. SSE2 is used by + default, but NEON must be enabled explicitly; see docs. + + With other JPEG optimizations included in this version, we see + 2x speedup on a JPEG on an x86 machine, and a 1.5x speedup + on a JPEG on an ARM machine, relative to previous versions of this + library. The same results will not obtain for all JPGs and for all + x86/ARM machines. (Note that progressive JPEGs are significantly + slower to decode than regular JPEGs.) This doesn't mean that this + is the fastest JPEG decoder in the land; rather, it brings it + closer to parity with standard libraries. If you want the fastest + decode, look elsewhere. (See "Philosophy" section of docs below.) + + See final bullet items below for more info on SIMD. + + - Added STBI_MALLOC, STBI_REALLOC, and STBI_FREE macros for replacing + the memory allocator. Unlike other STBI libraries, these macros don't + support a context parameter, so if you need to pass a context in to + the allocator, you'll have to store it in a global or a thread-local + variable. + + - Split existing STBI_NO_HDR flag into two flags, STBI_NO_HDR and + STBI_NO_LINEAR. + STBI_NO_HDR: suppress implementation of .hdr reader format + STBI_NO_LINEAR: suppress high-dynamic-range light-linear float API + + - You can suppress implementation of any of the decoders to reduce + your code footprint by #defining one or more of the following + symbols before creating the implementation. + + STBI_NO_JPEG + STBI_NO_PNG + STBI_NO_BMP + STBI_NO_PSD + STBI_NO_TGA + STBI_NO_GIF + STBI_NO_HDR + STBI_NO_PIC + STBI_NO_PNM (.ppm and .pgm) + + - You can request *only* certain decoders and suppress all other ones + (this will be more forward-compatible, as addition of new decoders + doesn't require you to disable them explicitly): + + STBI_ONLY_JPEG + STBI_ONLY_PNG + STBI_ONLY_BMP + STBI_ONLY_PSD + STBI_ONLY_TGA + STBI_ONLY_GIF + STBI_ONLY_HDR + STBI_ONLY_PIC + STBI_ONLY_PNM (.ppm and .pgm) + + Note that you can define multiples of these, and you will get all + of them ("only x" and "only y" is interpreted to mean "only x&y"). + + - If you use STBI_NO_PNG (or _ONLY_ without PNG), and you still + want the zlib decoder to be available, #define STBI_SUPPORT_ZLIB + + - Compilation of all SIMD code can be suppressed with + #define STBI_NO_SIMD + It should not be necessary to disable SIMD unless you have issues + compiling (e.g. using an x86 compiler which doesn't support SSE + intrinsics or that doesn't support the method used to detect + SSE2 support at run-time), and even those can be reported as + bugs so I can refine the built-in compile-time checking to be + smarter. + + - The old STBI_SIMD system which allowed installing a user-defined + IDCT etc. has been removed. If you need this, don't upgrade. My + assumption is that almost nobody was doing this, and those who + were will find the built-in SIMD more satisfactory anyway. + + - RGB values computed for JPEG images are slightly different from + previous versions of stb_image. (This is due to using less + integer precision in SIMD.) The C code has been adjusted so + that the same RGB values will be computed regardless of whether + SIMD support is available, so your app should always produce + consistent results. But these results are slightly different from + previous versions. (Specifically, about 3% of available YCbCr values + will compute different RGB results from pre-1.49 versions by +-1; + most of the deviating values are one smaller in the G channel.) + + - If you must produce consistent results with previous versions of + stb_image, #define STBI_JPEG_OLD and you will get the same results + you used to; however, you will not get the SIMD speedups for + the YCbCr-to-RGB conversion step (although you should still see + significant JPEG speedup from the other changes). + + Please note that STBI_JPEG_OLD is a temporary feature; it will be + removed in future versions of the library. It is only intended for + near-term back-compatibility use. + + + Latest revision history: + 2.08 (2015-09-13) fix to 2.07 cleanup, reading RGB PSD as RGBA + 2.07 (2015-09-13) partial animated GIF support + limited 16-bit PSD support + minor bugs, code cleanup, and compiler warnings + 2.06 (2015-04-19) fix bug where PSD returns wrong '*comp' value + 2.05 (2015-04-19) fix bug in progressive JPEG handling, fix warning + 2.04 (2015-04-15) try to re-enable SIMD on MinGW 64-bit + 2.03 (2015-04-12) additional corruption checking + stbi_set_flip_vertically_on_load + fix NEON support; fix mingw support + 2.02 (2015-01-19) fix incorrect assert, fix warning + 2.01 (2015-01-17) fix various warnings + 2.00b (2014-12-25) fix STBI_MALLOC in progressive JPEG + 2.00 (2014-12-25) optimize JPEG, including x86 SSE2 & ARM NEON SIMD + progressive JPEG + PGM/PPM support + STBI_MALLOC,STBI_REALLOC,STBI_FREE + STBI_NO_*, STBI_ONLY_* + GIF bugfix + 1.48 (2014-12-14) fix incorrectly-named assert() + 1.47 (2014-12-14) 1/2/4-bit PNG support (both grayscale and paletted) + optimize PNG + fix bug in interlaced PNG with user-specified channel count + + See end of file for full revision history. + + + ============================ Contributors ========================= + + Image formats Bug fixes & warning fixes + Sean Barrett (jpeg, png, bmp) Marc LeBlanc + Nicolas Schulz (hdr, psd) Christpher Lloyd + Jonathan Dummer (tga) Dave Moore + Jean-Marc Lienher (gif) Won Chun + Tom Seddon (pic) the Horde3D community + Thatcher Ulrich (psd) Janez Zemva + Ken Miller (pgm, ppm) Jonathan Blow + urraka@github (animated gif) Laurent Gomila + Aruelien Pocheville + Ryamond Barbiero + David Woo + Extensions, features Martin Golini + Jetro Lauha (stbi_info) Roy Eltham + Martin "SpartanJ" Golini (stbi_info) Luke Graham + James "moose2000" Brown (iPhone PNG) Thomas Ruf + Ben "Disch" Wenger (io callbacks) John Bartholomew + Omar Cornut (1/2/4-bit PNG) Ken Hamada + Nicolas Guillemot (vertical flip) Cort Stratton + Richard Mitton (16-bit PSD) Blazej Dariusz Roszkowski + Thibault Reuille + Paul Du Bois + Guillaume George + Jerry Jansson + Hayaki Saito + Johan Duparc + Ronny Chevalier + Optimizations & bugfixes Michal Cichon + Fabian "ryg" Giesen Tero Hanninen + Arseny Kapoulkine Sergio Gonzalez + Cass Everitt + Engin Manap + If your name should be here but Martins Mozeiko + isn't, let Sean know. Joseph Thomson + Phil Jordan + Nathan Reed + Michaelangel007@github + Nick Verigakis + +LICENSE + +This software is in the public domain. Where that dedication is not +recognized, you are granted a perpetual, irrevocable license to copy, +distribute, and modify this file as you see fit. + +*/ + +#ifndef STBI_INCLUDE_STB_IMAGE_H +#define STBI_INCLUDE_STB_IMAGE_H + +// DOCUMENTATION +// +// Limitations: +// - no 16-bit-per-channel PNG +// - no 12-bit-per-channel JPEG +// - no JPEGs with arithmetic coding +// - no 1-bit BMP +// - GIF always returns *comp=4 +// +// Basic usage (see HDR discussion below for HDR usage): +// int x,y,n; +// unsigned char *data = stbi_load(filename, &x, &y, &n, 0); +// // ... process data if not NULL ... +// // ... x = width, y = height, n = # 8-bit components per pixel ... +// // ... replace '0' with '1'..'4' to force that many components per pixel +// // ... but 'n' will always be the number that it would have been if you said 0 +// stbi_image_free(data) +// +// Standard parameters: +// int *x -- outputs image width in pixels +// int *y -- outputs image height in pixels +// int *comp -- outputs # of image components in image file +// int req_comp -- if non-zero, # of image components requested in result +// +// The return value from an image loader is an 'unsigned char *' which points +// to the pixel data, or NULL on an allocation failure or if the image is +// corrupt or invalid. The pixel data consists of *y scanlines of *x pixels, +// with each pixel consisting of N interleaved 8-bit components; the first +// pixel pointed to is top-left-most in the image. There is no padding between +// image scanlines or between pixels, regardless of format. The number of +// components N is 'req_comp' if req_comp is non-zero, or *comp otherwise. +// If req_comp is non-zero, *comp has the number of components that _would_ +// have been output otherwise. E.g. if you set req_comp to 4, you will always +// get RGBA output, but you can check *comp to see if it's trivially opaque +// because e.g. there were only 3 channels in the source image. +// +// An output image with N components has the following components interleaved +// in this order in each pixel: +// +// N=#comp components +// 1 grey +// 2 grey, alpha +// 3 red, green, blue +// 4 red, green, blue, alpha +// +// If image loading fails for any reason, the return value will be NULL, +// and *x, *y, *comp will be unchanged. The function stbi_failure_reason() +// can be queried for an extremely brief, end-user unfriendly explanation +// of why the load failed. Define STBI_NO_FAILURE_STRINGS to avoid +// compiling these strings at all, and STBI_FAILURE_USERMSG to get slightly +// more user-friendly ones. +// +// Paletted PNG, BMP, GIF, and PIC images are automatically depalettized. +// +// =========================================================================== +// +// Philosophy +// +// stb libraries are designed with the following priorities: +// +// 1. easy to use +// 2. easy to maintain +// 3. good performance +// +// Sometimes I let "good performance" creep up in priority over "easy to maintain", +// and for best performance I may provide less-easy-to-use APIs that give higher +// performance, in addition to the easy to use ones. Nevertheless, it's important +// to keep in mind that from the standpoint of you, a client of this library, +// all you care about is #1 and #3, and stb libraries do not emphasize #3 above all. +// +// Some secondary priorities arise directly from the first two, some of which +// make more explicit reasons why performance can't be emphasized. +// +// - Portable ("ease of use") +// - Small footprint ("easy to maintain") +// - No dependencies ("ease of use") +// +// =========================================================================== +// +// I/O callbacks +// +// I/O callbacks allow you to read from arbitrary sources, like packaged +// files or some other source. Data read from callbacks are processed +// through a small internal buffer (currently 128 bytes) to try to reduce +// overhead. +// +// The three functions you must define are "read" (reads some bytes of data), +// "skip" (skips some bytes of data), "eof" (reports if the stream is at the end). +// +// =========================================================================== +// +// SIMD support +// +// The JPEG decoder will try to automatically use SIMD kernels on x86 when +// supported by the compiler. For ARM Neon support, you must explicitly +// request it. +// +// (The old do-it-yourself SIMD API is no longer supported in the current +// code.) +// +// On x86, SSE2 will automatically be used when available based on a run-time +// test; if not, the generic C versions are used as a fall-back. On ARM targets, +// the typical path is to have separate builds for NEON and non-NEON devices +// (at least this is true for iOS and Android). Therefore, the NEON support is +// toggled by a build flag: define STBI_NEON to get NEON loops. +// +// The output of the JPEG decoder is slightly different from versions where +// SIMD support was introduced (that is, for versions before 1.49). The +// difference is only +-1 in the 8-bit RGB channels, and only on a small +// fraction of pixels. You can force the pre-1.49 behavior by defining +// STBI_JPEG_OLD, but this will disable some of the SIMD decoding path +// and hence cost some performance. +// +// If for some reason you do not want to use any of SIMD code, or if +// you have issues compiling it, you can disable it entirely by +// defining STBI_NO_SIMD. +// +// =========================================================================== +// +// HDR image support (disable by defining STBI_NO_HDR) +// +// stb_image now supports loading HDR images in general, and currently +// the Radiance .HDR file format, although the support is provided +// generically. You can still load any file through the existing interface; +// if you attempt to load an HDR file, it will be automatically remapped to +// LDR, assuming gamma 2.2 and an arbitrary scale factor defaulting to 1; +// both of these constants can be reconfigured through this interface: +// +// stbi_hdr_to_ldr_gamma(2.2f); +// stbi_hdr_to_ldr_scale(1.0f); +// +// (note, do not use _inverse_ constants; stbi_image will invert them +// appropriately). +// +// Additionally, there is a new, parallel interface for loading files as +// (linear) floats to preserve the full dynamic range: +// +// float *data = stbi_loadf(filename, &x, &y, &n, 0); +// +// If you load LDR images through this interface, those images will +// be promoted to floating point values, run through the inverse of +// constants corresponding to the above: +// +// stbi_ldr_to_hdr_scale(1.0f); +// stbi_ldr_to_hdr_gamma(2.2f); +// +// Finally, given a filename (or an open file or memory block--see header +// file for details) containing image data, you can query for the "most +// appropriate" interface to use (that is, whether the image is HDR or +// not), using: +// +// stbi_is_hdr(char *filename); +// +// =========================================================================== +// +// iPhone PNG support: +// +// By default we convert iphone-formatted PNGs back to RGB, even though +// they are internally encoded differently. You can disable this conversion +// by by calling stbi_convert_iphone_png_to_rgb(0), in which case +// you will always just get the native iphone "format" through (which +// is BGR stored in RGB). +// +// Call stbi_set_unpremultiply_on_load(1) as well to force a divide per +// pixel to remove any premultiplied alpha *only* if the image file explicitly +// says there's premultiplied data (currently only happens in iPhone images, +// and only if iPhone convert-to-rgb processing is on). +// + + +#ifndef STBI_NO_STDIO +#include +#endif // STBI_NO_STDIO + +#define STBI_VERSION 1 + +enum +{ + STBI_default = 0, // only used for req_comp + + STBI_grey = 1, + STBI_grey_alpha = 2, + STBI_rgb = 3, + STBI_rgb_alpha = 4 +}; + +typedef unsigned char stbi_uc; + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef STB_IMAGE_STATIC +#define STBIDEF static +#else +#define STBIDEF extern +#endif + +////////////////////////////////////////////////////////////////////////////// +// +// PRIMARY API - works on images of any type +// + +// +// load image by filename, open file, or memory buffer +// + +typedef struct +{ + int (*read) (void *user,char *data,int size); // fill 'data' with 'size' bytes. return number of bytes actually read + void (*skip) (void *user,int n); // skip the next 'n' bytes, or 'unget' the last -n bytes if negative + int (*eof) (void *user); // returns nonzero if we are at end of file/data +} stbi_io_callbacks; + +STBIDEF stbi_uc *stbi_load (char const *filename, int *x, int *y, int *comp, int req_comp); +STBIDEF stbi_uc *stbi_load_from_memory (stbi_uc const *buffer, int len , int *x, int *y, int *comp, int req_comp); +STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk , void *user, int *x, int *y, int *comp, int req_comp); + +#ifndef STBI_NO_STDIO +STBIDEF stbi_uc *stbi_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp); +// for stbi_load_from_file, file pointer is left pointing immediately after image +#endif + +#ifndef STBI_NO_LINEAR + STBIDEF float *stbi_loadf (char const *filename, int *x, int *y, int *comp, int req_comp); + STBIDEF float *stbi_loadf_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp); + STBIDEF float *stbi_loadf_from_callbacks (stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp); + + #ifndef STBI_NO_STDIO + STBIDEF float *stbi_loadf_from_file (FILE *f, int *x, int *y, int *comp, int req_comp); + #endif +#endif + +#ifndef STBI_NO_HDR + STBIDEF void stbi_hdr_to_ldr_gamma(float gamma); + STBIDEF void stbi_hdr_to_ldr_scale(float scale); +#endif + +#ifndef STBI_NO_LINEAR + STBIDEF void stbi_ldr_to_hdr_gamma(float gamma); + STBIDEF void stbi_ldr_to_hdr_scale(float scale); +#endif // STBI_NO_HDR + +// stbi_is_hdr is always defined, but always returns false if STBI_NO_HDR +STBIDEF int stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user); +STBIDEF int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len); +#ifndef STBI_NO_STDIO +STBIDEF int stbi_is_hdr (char const *filename); +STBIDEF int stbi_is_hdr_from_file(FILE *f); +#endif // STBI_NO_STDIO + + +// get a VERY brief reason for failure +// NOT THREADSAFE +STBIDEF const char *stbi_failure_reason (void); + +// free the loaded image -- this is just free() +STBIDEF void stbi_image_free (void *retval_from_stbi_load); + +// get image dimensions & components without fully decoding +STBIDEF int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp); +STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp); + +#ifndef STBI_NO_STDIO +STBIDEF int stbi_info (char const *filename, int *x, int *y, int *comp); +STBIDEF int stbi_info_from_file (FILE *f, int *x, int *y, int *comp); + +#endif + + + +// for image formats that explicitly notate that they have premultiplied alpha, +// we just return the colors as stored in the file. set this flag to force +// unpremultiplication. results are undefined if the unpremultiply overflow. +STBIDEF void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply); + +// indicate whether we should process iphone images back to canonical format, +// or just pass them through "as-is" +STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert); + +// flip the image vertically, so the first pixel in the output array is the bottom left +STBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip); + +// ZLIB client - used by PNG, available for other purposes + +STBIDEF char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen); +STBIDEF char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header); +STBIDEF char *stbi_zlib_decode_malloc(const char *buffer, int len, int *outlen); +STBIDEF int stbi_zlib_decode_buffer(char *obuffer, int olen, const char *ibuffer, int ilen); + +STBIDEF char *stbi_zlib_decode_noheader_malloc(const char *buffer, int len, int *outlen); +STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen); + +#ifndef STBI_NO_DDS +#include "stbi_DDS.h" +#endif + +#ifndef STBI_NO_PVR +#include "stbi_pvr.h" +#endif + +#ifndef STBI_NO_PKM +#include "stbi_pkm.h" +#endif + +#ifndef STBI_NO_EXT +#include "stbi_ext.h" +#endif + +#ifdef __cplusplus +} +#endif + +// +// +//// end header file ///////////////////////////////////////////////////// +#endif // STBI_INCLUDE_STB_IMAGE_H + +#ifdef STB_IMAGE_IMPLEMENTATION + +#if defined(STBI_ONLY_JPEG) || defined(STBI_ONLY_PNG) || defined(STBI_ONLY_BMP) \ + || defined(STBI_ONLY_TGA) || defined(STBI_ONLY_GIF) || defined(STBI_ONLY_PSD) \ + || defined(STBI_ONLY_HDR) || defined(STBI_ONLY_PIC) || defined(STBI_ONLY_PNM) \ + || defined(STBI_ONLY_ZLIB) + #ifndef STBI_ONLY_JPEG + #define STBI_NO_JPEG + #endif + #ifndef STBI_ONLY_PNG + #define STBI_NO_PNG + #endif + #ifndef STBI_ONLY_BMP + #define STBI_NO_BMP + #endif + #ifndef STBI_ONLY_PSD + #define STBI_NO_PSD + #endif + #ifndef STBI_ONLY_TGA + #define STBI_NO_TGA + #endif + #ifndef STBI_ONLY_GIF + #define STBI_NO_GIF + #endif + #ifndef STBI_ONLY_HDR + #define STBI_NO_HDR + #endif + #ifndef STBI_ONLY_PIC + #define STBI_NO_PIC + #endif + #ifndef STBI_ONLY_PNM + #define STBI_NO_PNM + #endif +#endif + +#if defined(STBI_NO_PNG) && !defined(STBI_SUPPORT_ZLIB) && !defined(STBI_NO_ZLIB) +#define STBI_NO_ZLIB +#endif + + +#include +#include // ptrdiff_t on osx +#include +#include + +#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) +#include // ldexp +#endif + +#ifndef STBI_NO_STDIO +#include +#endif + +#ifndef STBI_ASSERT +#include +#define STBI_ASSERT(x) assert(x) +#endif + + +#ifndef _MSC_VER + #ifdef __cplusplus + #define stbi_inline inline + #else + #define stbi_inline + #endif +#else + #define stbi_inline __forceinline +#endif + + +#ifdef _MSC_VER +typedef unsigned short stbi__uint16; +typedef signed short stbi__int16; +typedef unsigned int stbi__uint32; +typedef signed int stbi__int32; +#else +#include +typedef uint16_t stbi__uint16; +typedef int16_t stbi__int16; +typedef uint32_t stbi__uint32; +typedef int32_t stbi__int32; +#endif + +// should produce compiler error if size is wrong +typedef unsigned char validate_uint32[sizeof(stbi__uint32)==4 ? 1 : -1]; + +#ifdef _MSC_VER +#define STBI_NOTUSED(v) (void)(v) +#else +#define STBI_NOTUSED(v) (void)sizeof(v) +#endif + +#ifdef _MSC_VER +#define STBI_HAS_LROTL +#endif + +#ifdef STBI_HAS_LROTL + #define stbi_lrot(x,y) _lrotl(x,y) +#else + #define stbi_lrot(x,y) (((x) << (y)) | ((x) >> (32 - (y)))) +#endif + +#if defined(STBI_MALLOC) && defined(STBI_FREE) && defined(STBI_REALLOC) +// ok +#elif !defined(STBI_MALLOC) && !defined(STBI_FREE) && !defined(STBI_REALLOC) +// ok +#else +#error "Must define all or none of STBI_MALLOC, STBI_FREE, and STBI_REALLOC." +#endif + +#ifndef STBI_MALLOC +#define STBI_MALLOC(sz) malloc(sz) +#define STBI_REALLOC(p,sz) realloc(p,sz) +#define STBI_FREE(p) free(p) +#endif + +// x86/x64 detection +#if defined(__x86_64__) || defined(_M_X64) +#define STBI__X64_TARGET +#elif defined(__i386) || defined(_M_IX86) +#define STBI__X86_TARGET +#endif + +#if defined(__GNUC__) && (defined(STBI__X86_TARGET) || defined(STBI__X64_TARGET)) && !defined(__SSE2__) && !defined(STBI_NO_SIMD) +// NOTE: not clear do we actually need this for the 64-bit path? +// gcc doesn't support sse2 intrinsics unless you compile with -msse2, +// (but compiling with -msse2 allows the compiler to use SSE2 everywhere; +// this is just broken and gcc are jerks for not fixing it properly +// http://www.virtualdub.org/blog/pivot/entry.php?id=363 ) +#define STBI_NO_SIMD +#endif + +#if defined(__MINGW32__) && !defined(__x86_64__) && !defined(STBI_NO_SIMD) +#define STBI_MINGW_ENABLE_SSE2 +#define STBI_FORCE_STACK_ALIGN __attribute__((force_align_arg_pointer)) +#else +#define STBI_FORCE_STACK_ALIGN +#endif + +#if defined(__MINGW32__) && defined(STBI__X86_TARGET) && !defined(STBI_MINGW_ENABLE_SSE2) && !defined(STBI_NO_SIMD) +// Note that __MINGW32__ doesn't actually mean 32-bit, so we have to avoid STBI__X64_TARGET +// +// 32-bit MinGW wants ESP to be 16-byte aligned, but this is not in the +// Windows ABI and VC++ as well as Windows DLLs don't maintain that invariant. +// As a result, enabling SSE2 on 32-bit MinGW is dangerous when not +// simultaneously enabling "-mstackrealign". +// +// See https://github.com/nothings/stb/issues/81 for more information. +// +// So default to no SSE2 on 32-bit MinGW. If you've read this far and added +// -mstackrealign to your build settings, feel free to #define STBI_MINGW_ENABLE_SSE2. +#define STBI_NO_SIMD +#endif + +#if !defined(STBI_NO_SIMD) && defined(STBI__X86_TARGET) +#define STBI_SSE2 +#include + +#ifdef _MSC_VER + +#if _MSC_VER >= 1400 // not VC6 +#include // __cpuid +static int stbi__cpuid3(void) +{ + int info[4]; + __cpuid(info,1); + return info[3]; +} +#else +static int stbi__cpuid3(void) +{ + int res; + __asm { + mov eax,1 + cpuid + mov res,edx + } + return res; +} +#endif + +#define STBI_SIMD_ALIGN(type, name) __declspec(align(16)) type name + +static int stbi__sse2_available() +{ + int info3 = stbi__cpuid3(); + return ((info3 >> 26) & 1) != 0; +} +#else // assume GCC-style if not VC++ +#define STBI_SIMD_ALIGN(type, name) type name __attribute__((aligned(16))) + +static int stbi__sse2_available() +{ +#if defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__) >= 408 // GCC 4.8 or later + // GCC 4.8+ has a nice way to do this + return __builtin_cpu_supports("sse2"); +#else + // portable way to do this, preferably without using GCC inline ASM? + // just bail for now. + return 0; +#endif +} +#endif +#endif + +// ARM NEON +#if defined(STBI_NO_SIMD) && defined(STBI_NEON) +#undef STBI_NEON +#endif + +#ifdef STBI_NEON +#include +// assume GCC or Clang on ARM targets +#define STBI_SIMD_ALIGN(type, name) type name __attribute__((aligned(16))) +#endif + +#ifndef STBI_SIMD_ALIGN +#define STBI_SIMD_ALIGN(type, name) type name +#endif + +/////////////////////////////////////////////// +// +// stbi__context struct and start_xxx functions + +// stbi__context structure is our basic context used by all images, so it +// contains all the IO context, plus some basic image information +typedef struct +{ + stbi__uint32 img_x, img_y; + int img_n, img_out_n; + + stbi_io_callbacks io; + void *io_user_data; + + int read_from_callbacks; + int buflen; + stbi_uc buffer_start[128]; + + stbi_uc *img_buffer, *img_buffer_end; + stbi_uc *img_buffer_original, *img_buffer_original_end; +} stbi__context; + + +static void stbi__refill_buffer(stbi__context *s); + +// initialize a memory-decode context +static void stbi__start_mem(stbi__context *s, stbi_uc const *buffer, int len) +{ + s->io.read = NULL; + s->read_from_callbacks = 0; + s->img_buffer = s->img_buffer_original = (stbi_uc *) buffer; + s->img_buffer_end = s->img_buffer_original_end = (stbi_uc *) buffer+len; +} + +// initialize a callback-based context +static void stbi__start_callbacks(stbi__context *s, stbi_io_callbacks *c, void *user) +{ + s->io = *c; + s->io_user_data = user; + s->buflen = sizeof(s->buffer_start); + s->read_from_callbacks = 1; + s->img_buffer_original = s->buffer_start; + stbi__refill_buffer(s); + s->img_buffer_original_end = s->img_buffer_end; +} + +#ifndef STBI_NO_STDIO + +static int stbi__stdio_read(void *user, char *data, int size) +{ + return (int) fread(data,1,size,(FILE*) user); +} + +static void stbi__stdio_skip(void *user, int n) +{ + fseek((FILE*) user, n, SEEK_CUR); +} + +static int stbi__stdio_eof(void *user) +{ + return feof((FILE*) user); +} + +static stbi_io_callbacks stbi__stdio_callbacks = +{ + stbi__stdio_read, + stbi__stdio_skip, + stbi__stdio_eof, +}; + +static void stbi__start_file(stbi__context *s, FILE *f) +{ + stbi__start_callbacks(s, &stbi__stdio_callbacks, (void *) f); +} + +//static void stop_file(stbi__context *s) { } + +#endif // !STBI_NO_STDIO + +static void stbi__rewind(stbi__context *s) +{ + // conceptually rewind SHOULD rewind to the beginning of the stream, + // but we just rewind to the beginning of the initial buffer, because + // we only use it after doing 'test', which only ever looks at at most 92 bytes + s->img_buffer = s->img_buffer_original; + s->img_buffer_end = s->img_buffer_original_end; +} + +#ifndef STBI_NO_JPEG +static int stbi__jpeg_test(stbi__context *s); +static stbi_uc *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int req_comp); +static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_PNG +static int stbi__png_test(stbi__context *s); +static stbi_uc *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp); +static int stbi__png_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_BMP +static int stbi__bmp_test(stbi__context *s); +static stbi_uc *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp); +static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_TGA +static int stbi__tga_test(stbi__context *s); +static stbi_uc *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp); +static int stbi__tga_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_PSD +static int stbi__psd_test(stbi__context *s); +static stbi_uc *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp); +static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_HDR +static int stbi__hdr_test(stbi__context *s); +static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int req_comp); +static int stbi__hdr_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_PIC +static int stbi__pic_test(stbi__context *s); +static stbi_uc *stbi__pic_load(stbi__context *s, int *x, int *y, int *comp, int req_comp); +static int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_GIF +static int stbi__gif_test(stbi__context *s); +static stbi_uc *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp); +static int stbi__gif_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_PNM +static int stbi__pnm_test(stbi__context *s); +static stbi_uc *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp); +static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_PNM +static int stbi__pnm_test(stbi__context *s); +static stbi_uc *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp); +static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_DDS +#include "stbi_DDS.h" +static int stbi__dds_test(stbi__context *s); +static stbi_uc *stbi__dds_load(stbi__context *s, int *x, int *y, int *comp, int req_comp); +#endif + +#ifndef STBI_NO_PVR +#include "stbi_pvr.h" +static int stbi__pvr_test(stbi__context *s); +static stbi_uc *stbi__pvr_load(stbi__context *s, int *x, int *y, int *comp, int req_comp); +#endif + +#ifndef STBI_NO_PKM +#include "stbi_pkm.h" +static int stbi__pkm_test(stbi__context *s); +static stbi_uc *stbi__pkm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp); +#endif + +// this is not threadsafe +static const char *stbi__g_failure_reason; + +STBIDEF const char *stbi_failure_reason(void) +{ + return stbi__g_failure_reason; +} + +static int stbi__err(const char *str) +{ + stbi__g_failure_reason = str; + return 0; +} + +static void *stbi__malloc(size_t size) +{ + return STBI_MALLOC(size); +} + +// stbi__err - error +// stbi__errpf - error returning pointer to float +// stbi__errpuc - error returning pointer to unsigned char + +#ifdef STBI_NO_FAILURE_STRINGS + #define stbi__err(x,y) 0 +#elif defined(STBI_FAILURE_USERMSG) + #define stbi__err(x,y) stbi__err(y) +#else + #define stbi__err(x,y) stbi__err(x) +#endif + +#define stbi__errpf(x,y) ((float *)(size_t) (stbi__err(x,y)?NULL:NULL)) +#define stbi__errpuc(x,y) ((unsigned char *)(size_t) (stbi__err(x,y)?NULL:NULL)) + +STBIDEF void stbi_image_free(void *retval_from_stbi_load) +{ + STBI_FREE(retval_from_stbi_load); +} + +#ifndef STBI_NO_LINEAR +static float *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp); +#endif + +#ifndef STBI_NO_HDR +static stbi_uc *stbi__hdr_to_ldr(float *data, int x, int y, int comp); +#endif + +static int stbi__vertically_flip_on_load = 0; + +STBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip) +{ + stbi__vertically_flip_on_load = flag_true_if_should_flip; +} + +static unsigned char *stbi__load_main(stbi__context *s, int *x, int *y, int *comp, int req_comp) +{ + #ifndef STBI_NO_JPEG + if (stbi__jpeg_test(s)) return stbi__jpeg_load(s,x,y,comp,req_comp); + #endif + #ifndef STBI_NO_PNG + if (stbi__png_test(s)) return stbi__png_load(s,x,y,comp,req_comp); + #endif + #ifndef STBI_NO_BMP + if (stbi__bmp_test(s)) return stbi__bmp_load(s,x,y,comp,req_comp); + #endif + #ifndef STBI_NO_GIF + if (stbi__gif_test(s)) return stbi__gif_load(s,x,y,comp,req_comp); + #endif + #ifndef STBI_NO_PSD + if (stbi__psd_test(s)) return stbi__psd_load(s,x,y,comp,req_comp); + #endif + #ifndef STBI_NO_PIC + if (stbi__pic_test(s)) return stbi__pic_load(s,x,y,comp,req_comp); + #endif + #ifndef STBI_NO_PNM + if (stbi__pnm_test(s)) return stbi__pnm_load(s,x,y,comp,req_comp); + #endif + #ifndef STBI_NO_DDS + if (stbi__dds_test(s)) return stbi__dds_load(s,x,y,comp,req_comp); + #endif + #ifndef STBI_NO_PVR + if (stbi__pvr_test(s)) return stbi__pvr_load(s,x,y,comp,req_comp); + #endif + #ifndef STBI_NO_PKM + if (stbi__pkm_test(s)) return stbi__pkm_load(s,x,y,comp,req_comp); + #endif + #ifndef STBI_NO_HDR + if (stbi__hdr_test(s)) { + float *hdr = stbi__hdr_load(s, x,y,comp,req_comp); + return stbi__hdr_to_ldr(hdr, *x, *y, req_comp ? req_comp : *comp); + } + #endif + + #ifndef STBI_NO_TGA + // test tga last because it's a crappy test! + if (stbi__tga_test(s)) + return stbi__tga_load(s,x,y,comp,req_comp); + #endif + + return stbi__errpuc("unknown image type", "Image not of any known type, or corrupt"); +} + +static unsigned char *stbi__load_flip(stbi__context *s, int *x, int *y, int *comp, int req_comp) +{ + unsigned char *result = stbi__load_main(s, x, y, comp, req_comp); + + if (stbi__vertically_flip_on_load && result != NULL) { + int w = *x, h = *y; + int depth = req_comp ? req_comp : *comp; + int row,col,z; + stbi_uc temp; + + // @OPTIMIZE: use a bigger temp buffer and memcpy multiple pixels at once + for (row = 0; row < (h>>1); row++) { + for (col = 0; col < w; col++) { + for (z = 0; z < depth; z++) { + temp = result[(row * w + col) * depth + z]; + result[(row * w + col) * depth + z] = result[((h - row - 1) * w + col) * depth + z]; + result[((h - row - 1) * w + col) * depth + z] = temp; + } + } + } + } + + return result; +} + +#ifndef STBI_NO_HDR +static void stbi__float_postprocess(float *result, int *x, int *y, int *comp, int req_comp) +{ + if (stbi__vertically_flip_on_load && result != NULL) { + int w = *x, h = *y; + int depth = req_comp ? req_comp : *comp; + int row,col,z; + float temp; + + // @OPTIMIZE: use a bigger temp buffer and memcpy multiple pixels at once + for (row = 0; row < (h>>1); row++) { + for (col = 0; col < w; col++) { + for (z = 0; z < depth; z++) { + temp = result[(row * w + col) * depth + z]; + result[(row * w + col) * depth + z] = result[((h - row - 1) * w + col) * depth + z]; + result[((h - row - 1) * w + col) * depth + z] = temp; + } + } + } + } +} +#endif + +#ifndef STBI_NO_STDIO + +static FILE *stbi__fopen(char const *filename, char const *mode) +{ + FILE *f; +#if defined(_MSC_VER) && _MSC_VER >= 1400 + if (0 != fopen_s(&f, filename, mode)) + f=0; +#else + f = fopen(filename, mode); +#endif + return f; +} + + +STBIDEF stbi_uc *stbi_load(char const *filename, int *x, int *y, int *comp, int req_comp) +{ + FILE *f = stbi__fopen(filename, "rb"); + unsigned char *result; + if (!f) return stbi__errpuc("can't fopen", "Unable to open file"); + result = stbi_load_from_file(f,x,y,comp,req_comp); + fclose(f); + return result; +} + +STBIDEF stbi_uc *stbi_load_from_file(FILE *f, int *x, int *y, int *comp, int req_comp) +{ + unsigned char *result; + stbi__context s; + stbi__start_file(&s,f); + result = stbi__load_flip(&s,x,y,comp,req_comp); + if (result) { + // need to 'unget' all the characters in the IO buffer + fseek(f, - (int) (s.img_buffer_end - s.img_buffer), SEEK_CUR); + } + return result; +} +#endif //!STBI_NO_STDIO + +STBIDEF stbi_uc *stbi_load_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) +{ + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__load_flip(&s,x,y,comp,req_comp); +} + +STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp) +{ + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); + return stbi__load_flip(&s,x,y,comp,req_comp); +} + +#ifndef STBI_NO_LINEAR +static float *stbi__loadf_main(stbi__context *s, int *x, int *y, int *comp, int req_comp) +{ + unsigned char *data; + #ifndef STBI_NO_HDR + if (stbi__hdr_test(s)) { + float *hdr_data = stbi__hdr_load(s,x,y,comp,req_comp); + if (hdr_data) + stbi__float_postprocess(hdr_data,x,y,comp,req_comp); + return hdr_data; + } + #endif + data = stbi__load_flip(s, x, y, comp, req_comp); + if (data) + return stbi__ldr_to_hdr(data, *x, *y, req_comp ? req_comp : *comp); + return stbi__errpf("unknown image type", "Image not of any known type, or corrupt"); +} + +STBIDEF float *stbi_loadf_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) +{ + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__loadf_main(&s,x,y,comp,req_comp); +} + +STBIDEF float *stbi_loadf_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp) +{ + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); + return stbi__loadf_main(&s,x,y,comp,req_comp); +} + +#ifndef STBI_NO_STDIO +STBIDEF float *stbi_loadf(char const *filename, int *x, int *y, int *comp, int req_comp) +{ + float *result; + FILE *f = stbi__fopen(filename, "rb"); + if (!f) return stbi__errpf("can't fopen", "Unable to open file"); + result = stbi_loadf_from_file(f,x,y,comp,req_comp); + fclose(f); + return result; +} + +STBIDEF float *stbi_loadf_from_file(FILE *f, int *x, int *y, int *comp, int req_comp) +{ + stbi__context s; + stbi__start_file(&s,f); + return stbi__loadf_main(&s,x,y,comp,req_comp); +} +#endif // !STBI_NO_STDIO + +#endif // !STBI_NO_LINEAR + +// these is-hdr-or-not is defined independent of whether STBI_NO_LINEAR is +// defined, for API simplicity; if STBI_NO_LINEAR is defined, it always +// reports false! + +STBIDEF int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len) +{ + #ifndef STBI_NO_HDR + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__hdr_test(&s); + #else + STBI_NOTUSED(buffer); + STBI_NOTUSED(len); + return 0; + #endif +} + +#ifndef STBI_NO_STDIO +STBIDEF int stbi_is_hdr (char const *filename) +{ + FILE *f = stbi__fopen(filename, "rb"); + int result=0; + if (f) { + result = stbi_is_hdr_from_file(f); + fclose(f); + } + return result; +} + +STBIDEF int stbi_is_hdr_from_file(FILE *f) +{ + #ifndef STBI_NO_HDR + stbi__context s; + stbi__start_file(&s,f); + return stbi__hdr_test(&s); + #else + STBI_NOTUSED(f); + return 0; + #endif +} +#endif // !STBI_NO_STDIO + +STBIDEF int stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user) +{ + #ifndef STBI_NO_HDR + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); + return stbi__hdr_test(&s); + #else + STBI_NOTUSED(clbk); + STBI_NOTUSED(user); + return 0; + #endif +} + +static float stbi__h2l_gamma_i=1.0f/2.2f, stbi__h2l_scale_i=1.0f; +static float stbi__l2h_gamma=2.2f, stbi__l2h_scale=1.0f; + +#ifndef STBI_NO_LINEAR +STBIDEF void stbi_ldr_to_hdr_gamma(float gamma) { stbi__l2h_gamma = gamma; } +STBIDEF void stbi_ldr_to_hdr_scale(float scale) { stbi__l2h_scale = scale; } +#endif + +STBIDEF void stbi_hdr_to_ldr_gamma(float gamma) { stbi__h2l_gamma_i = 1/gamma; } +STBIDEF void stbi_hdr_to_ldr_scale(float scale) { stbi__h2l_scale_i = 1/scale; } + + +////////////////////////////////////////////////////////////////////////////// +// +// Common code used by all image loaders +// + +enum +{ + STBI__SCAN_load=0, + STBI__SCAN_type, + STBI__SCAN_header +}; + +static void stbi__refill_buffer(stbi__context *s) +{ + int n = (s->io.read)(s->io_user_data,(char*)s->buffer_start,s->buflen); + if (n == 0) { + // at end of file, treat same as if from memory, but need to handle case + // where s->img_buffer isn't pointing to safe memory, e.g. 0-byte file + s->read_from_callbacks = 0; + s->img_buffer = s->buffer_start; + s->img_buffer_end = s->buffer_start+1; + *s->img_buffer = 0; + } else { + s->img_buffer = s->buffer_start; + s->img_buffer_end = s->buffer_start + n; + } +} + +stbi_inline static stbi_uc stbi__get8(stbi__context *s) +{ + if (s->img_buffer < s->img_buffer_end) + return *s->img_buffer++; + if (s->read_from_callbacks) { + stbi__refill_buffer(s); + return *s->img_buffer++; + } + return 0; +} + +stbi_inline static int stbi__at_eof(stbi__context *s) +{ + if (s->io.read) { + if (!(s->io.eof)(s->io_user_data)) return 0; + // if feof() is true, check if buffer = end + // special case: we've only got the special 0 character at the end + if (s->read_from_callbacks == 0) return 1; + } + + return s->img_buffer >= s->img_buffer_end; +} + +static void stbi__skip(stbi__context *s, int n) +{ + if (n < 0) { + s->img_buffer = s->img_buffer_end; + return; + } + if (s->io.read) { + int blen = (int) (s->img_buffer_end - s->img_buffer); + if (blen < n) { + s->img_buffer = s->img_buffer_end; + (s->io.skip)(s->io_user_data, n - blen); + return; + } + } + s->img_buffer += n; +} + +static int stbi__getn(stbi__context *s, stbi_uc *buffer, int n) +{ + if (s->io.read) { + int blen = (int) (s->img_buffer_end - s->img_buffer); + if (blen < n) { + int res, count; + + memcpy(buffer, s->img_buffer, blen); + + count = (s->io.read)(s->io_user_data, (char*) buffer + blen, n - blen); + res = (count == (n-blen)); + s->img_buffer = s->img_buffer_end; + return res; + } + } + + if (s->img_buffer+n <= s->img_buffer_end) { + memcpy(buffer, s->img_buffer, n); + s->img_buffer += n; + return 1; + } else + return 0; +} + +static int stbi__get16be(stbi__context *s) +{ + int z = stbi__get8(s); + return (z << 8) + stbi__get8(s); +} + +static stbi__uint32 stbi__get32be(stbi__context *s) +{ + stbi__uint32 z = stbi__get16be(s); + return (z << 16) + stbi__get16be(s); +} + +#if defined(STBI_NO_BMP) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) +// nothing +#else +static int stbi__get16le(stbi__context *s) +{ + int z = stbi__get8(s); + return z + (stbi__get8(s) << 8); +} +#endif + +#ifndef STBI_NO_BMP +static stbi__uint32 stbi__get32le(stbi__context *s) +{ + stbi__uint32 z = stbi__get16le(s); + return z + (stbi__get16le(s) << 16); +} +#endif + +#define STBI__BYTECAST(x) ((stbi_uc) ((x) & 255)) // truncate int to byte without warnings + + +////////////////////////////////////////////////////////////////////////////// +// +// generic converter from built-in img_n to req_comp +// individual types do this automatically as much as possible (e.g. jpeg +// does all cases internally since it needs to colorspace convert anyway, +// and it never has alpha, so very few cases ). png can automatically +// interleave an alpha=255 channel, but falls back to this for other cases +// +// assume data buffer is malloced, so malloc a new one and free that one +// only failure mode is malloc failing + +static stbi_uc stbi__compute_y(int r, int g, int b) +{ + return (stbi_uc) (((r*77) + (g*150) + (29*b)) >> 8); +} + +static unsigned char *stbi__convert_format(unsigned char *data, int img_n, int req_comp, unsigned int x, unsigned int y) +{ + int i,j; + unsigned char *good; + + if (req_comp == img_n) return data; + STBI_ASSERT(req_comp >= 1 && req_comp <= 4); + + good = (unsigned char *) stbi__malloc(req_comp * x * y); + if (good == NULL) { + STBI_FREE(data); + return stbi__errpuc("outofmem", "Out of memory"); + } + + for (j=0; j < (int) y; ++j) { + unsigned char *src = data + j * x * img_n ; + unsigned char *dest = good + j * x * req_comp; + + #define COMBO(a,b) ((a)*8+(b)) + #define CASE(a,b) case COMBO(a,b): for(i=x-1; i >= 0; --i, src += a, dest += b) + // convert source image with img_n components to one with req_comp components; + // avoid switch per pixel, so use switch per scanline and massive macros + switch (COMBO(img_n, req_comp)) { + CASE(1,2) dest[0]=src[0], dest[1]=255; break; + CASE(1,3) dest[0]=dest[1]=dest[2]=src[0]; break; + CASE(1,4) dest[0]=dest[1]=dest[2]=src[0], dest[3]=255; break; + CASE(2,1) dest[0]=src[0]; break; + CASE(2,3) dest[0]=dest[1]=dest[2]=src[0]; break; + CASE(2,4) dest[0]=dest[1]=dest[2]=src[0], dest[3]=src[1]; break; + CASE(3,4) dest[0]=src[0],dest[1]=src[1],dest[2]=src[2],dest[3]=255; break; + CASE(3,1) dest[0]=stbi__compute_y(src[0],src[1],src[2]); break; + CASE(3,2) dest[0]=stbi__compute_y(src[0],src[1],src[2]), dest[1] = 255; break; + CASE(4,1) dest[0]=stbi__compute_y(src[0],src[1],src[2]); break; + CASE(4,2) dest[0]=stbi__compute_y(src[0],src[1],src[2]), dest[1] = src[3]; break; + CASE(4,3) dest[0]=src[0],dest[1]=src[1],dest[2]=src[2]; break; + default: STBI_ASSERT(0); + } + #undef CASE + } + + STBI_FREE(data); + return good; +} + +#ifndef STBI_NO_LINEAR +static float *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp) +{ + int i,k,n; + float *output = (float *) stbi__malloc(x * y * comp * sizeof(float)); + if (output == NULL) { STBI_FREE(data); return stbi__errpf("outofmem", "Out of memory"); } + // compute number of non-alpha components + if (comp & 1) n = comp; else n = comp-1; + for (i=0; i < x*y; ++i) { + for (k=0; k < n; ++k) { + output[i*comp + k] = (float) (pow(data[i*comp+k]/255.0f, stbi__l2h_gamma) * stbi__l2h_scale); + } + if (k < comp) output[i*comp + k] = data[i*comp+k]/255.0f; + } + STBI_FREE(data); + return output; +} +#endif + +#ifndef STBI_NO_HDR +#define stbi__float2int(x) ((int) (x)) +static stbi_uc *stbi__hdr_to_ldr(float *data, int x, int y, int comp) +{ + int i,k,n; + stbi_uc *output = (stbi_uc *) stbi__malloc(x * y * comp); + if (output == NULL) { STBI_FREE(data); return stbi__errpuc("outofmem", "Out of memory"); } + // compute number of non-alpha components + if (comp & 1) n = comp; else n = comp-1; + for (i=0; i < x*y; ++i) { + for (k=0; k < n; ++k) { + float z = (float) pow(data[i*comp+k]*stbi__h2l_scale_i, stbi__h2l_gamma_i) * 255 + 0.5f; + if (z < 0) z = 0; + if (z > 255) z = 255; + output[i*comp + k] = (stbi_uc) stbi__float2int(z); + } + if (k < comp) { + float z = data[i*comp+k] * 255 + 0.5f; + if (z < 0) z = 0; + if (z > 255) z = 255; + output[i*comp + k] = (stbi_uc) stbi__float2int(z); + } + } + STBI_FREE(data); + return output; +} +#endif + +////////////////////////////////////////////////////////////////////////////// +// +// "baseline" JPEG/JFIF decoder +// +// simple implementation +// - doesn't support delayed output of y-dimension +// - simple interface (only one output format: 8-bit interleaved RGB) +// - doesn't try to recover corrupt jpegs +// - doesn't allow partial loading, loading multiple at once +// - still fast on x86 (copying globals into locals doesn't help x86) +// - allocates lots of intermediate memory (full size of all components) +// - non-interleaved case requires this anyway +// - allows good upsampling (see next) +// high-quality +// - upsampled channels are bilinearly interpolated, even across blocks +// - quality integer IDCT derived from IJG's 'slow' +// performance +// - fast huffman; reasonable integer IDCT +// - some SIMD kernels for common paths on targets with SSE2/NEON +// - uses a lot of intermediate memory, could cache poorly + +#ifndef STBI_NO_JPEG + +// huffman decoding acceleration +#define FAST_BITS 9 // larger handles more cases; smaller stomps less cache + +typedef struct +{ + stbi_uc fast[1 << FAST_BITS]; + // weirdly, repacking this into AoS is a 10% speed loss, instead of a win + stbi__uint16 code[256]; + stbi_uc values[256]; + stbi_uc size[257]; + unsigned int maxcode[18]; + int delta[17]; // old 'firstsymbol' - old 'firstcode' +} stbi__huffman; + +typedef struct +{ + stbi__context *s; + stbi__huffman huff_dc[4]; + stbi__huffman huff_ac[4]; + stbi_uc dequant[4][64]; + stbi__int16 fast_ac[4][1 << FAST_BITS]; + +// sizes for components, interleaved MCUs + int img_h_max, img_v_max; + int img_mcu_x, img_mcu_y; + int img_mcu_w, img_mcu_h; + +// definition of jpeg image component + struct + { + int id; + int h,v; + int tq; + int hd,ha; + int dc_pred; + + int x,y,w2,h2; + stbi_uc *data; + void *raw_data, *raw_coeff; + stbi_uc *linebuf; + short *coeff; // progressive only + int coeff_w, coeff_h; // number of 8x8 coefficient blocks + } img_comp[4]; + + stbi__uint32 code_buffer; // jpeg entropy-coded buffer + int code_bits; // number of valid bits + unsigned char marker; // marker seen while filling entropy buffer + int nomore; // flag if we saw a marker so must stop + + int progressive; + int spec_start; + int spec_end; + int succ_high; + int succ_low; + int eob_run; + + int scan_n, order[4]; + int restart_interval, todo; + +// kernels + void (*idct_block_kernel)(stbi_uc *out, int out_stride, short data[64]); + void (*YCbCr_to_RGB_kernel)(stbi_uc *out, const stbi_uc *y, const stbi_uc *pcb, const stbi_uc *pcr, int count, int step); + stbi_uc *(*resample_row_hv_2_kernel)(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs); +} stbi__jpeg; + +static int stbi__build_huffman(stbi__huffman *h, int *count) +{ + int i,j,k=0,code; + // build size list for each symbol (from JPEG spec) + for (i=0; i < 16; ++i) + for (j=0; j < count[i]; ++j) + h->size[k++] = (stbi_uc) (i+1); + h->size[k] = 0; + + // compute actual symbols (from jpeg spec) + code = 0; + k = 0; + for(j=1; j <= 16; ++j) { + // compute delta to add to code to compute symbol id + h->delta[j] = k - code; + if (h->size[k] == j) { + while (h->size[k] == j) + h->code[k++] = (stbi__uint16) (code++); + if (code-1 >= (1 << j)) return stbi__err("bad code lengths","Corrupt JPEG"); + } + // compute largest code + 1 for this size, preshifted as needed later + h->maxcode[j] = code << (16-j); + code <<= 1; + } + h->maxcode[j] = 0xffffffff; + + // build non-spec acceleration table; 255 is flag for not-accelerated + memset(h->fast, 255, 1 << FAST_BITS); + for (i=0; i < k; ++i) { + int s = h->size[i]; + if (s <= FAST_BITS) { + int c = h->code[i] << (FAST_BITS-s); + int m = 1 << (FAST_BITS-s); + for (j=0; j < m; ++j) { + h->fast[c+j] = (stbi_uc) i; + } + } + } + return 1; +} + +// build a table that decodes both magnitude and value of small ACs in +// one go. +static void stbi__build_fast_ac(stbi__int16 *fast_ac, stbi__huffman *h) +{ + int i; + for (i=0; i < (1 << FAST_BITS); ++i) { + stbi_uc fast = h->fast[i]; + fast_ac[i] = 0; + if (fast < 255) { + int rs = h->values[fast]; + int run = (rs >> 4) & 15; + int magbits = rs & 15; + int len = h->size[fast]; + + if (magbits && len + magbits <= FAST_BITS) { + // magnitude code followed by receive_extend code + int k = ((i << len) & ((1 << FAST_BITS) - 1)) >> (FAST_BITS - magbits); + int m = 1 << (magbits - 1); + if (k < m) k += (-1 << magbits) + 1; + // if the result is small enough, we can fit it in fast_ac table + if (k >= -128 && k <= 127) + fast_ac[i] = (stbi__int16) ((k << 8) + (run << 4) + (len + magbits)); + } + } + } +} + +static void stbi__grow_buffer_unsafe(stbi__jpeg *j) +{ + do { + int b = j->nomore ? 0 : stbi__get8(j->s); + if (b == 0xff) { + int c = stbi__get8(j->s); + if (c != 0) { + j->marker = (unsigned char) c; + j->nomore = 1; + return; + } + } + j->code_buffer |= b << (24 - j->code_bits); + j->code_bits += 8; + } while (j->code_bits <= 24); +} + +// (1 << n) - 1 +static stbi__uint32 stbi__bmask[17]={0,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,16383,32767,65535}; + +// decode a jpeg huffman value from the bitstream +stbi_inline static int stbi__jpeg_huff_decode(stbi__jpeg *j, stbi__huffman *h) +{ + unsigned int temp; + int c,k; + + if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); + + // look at the top FAST_BITS and determine what symbol ID it is, + // if the code is <= FAST_BITS + c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1); + k = h->fast[c]; + if (k < 255) { + int s = h->size[k]; + if (s > j->code_bits) + return -1; + j->code_buffer <<= s; + j->code_bits -= s; + return h->values[k]; + } + + // naive test is to shift the code_buffer down so k bits are + // valid, then test against maxcode. To speed this up, we've + // preshifted maxcode left so that it has (16-k) 0s at the + // end; in other words, regardless of the number of bits, it + // wants to be compared against something shifted to have 16; + // that way we don't need to shift inside the loop. + temp = j->code_buffer >> 16; + for (k=FAST_BITS+1 ; ; ++k) + if (temp < h->maxcode[k]) + break; + if (k == 17) { + // error! code not found + j->code_bits -= 16; + return -1; + } + + if (k > j->code_bits) + return -1; + + // convert the huffman code to the symbol id + c = ((j->code_buffer >> (32 - k)) & stbi__bmask[k]) + h->delta[k]; + STBI_ASSERT((((j->code_buffer) >> (32 - h->size[c])) & stbi__bmask[h->size[c]]) == h->code[c]); + + // convert the id to a symbol + j->code_bits -= k; + j->code_buffer <<= k; + return h->values[c]; +} + +// bias[n] = (-1<code_bits < n) stbi__grow_buffer_unsafe(j); + + sgn = (stbi__int32)j->code_buffer >> 31; // sign bit is always in MSB + k = stbi_lrot(j->code_buffer, n); + STBI_ASSERT(n >= 0 && n < (int) (sizeof(stbi__bmask)/sizeof(*stbi__bmask))); + j->code_buffer = k & ~stbi__bmask[n]; + k &= stbi__bmask[n]; + j->code_bits -= n; + return k + (stbi__jbias[n] & ~sgn); +} + +// get some unsigned bits +stbi_inline static int stbi__jpeg_get_bits(stbi__jpeg *j, int n) +{ + unsigned int k; + if (j->code_bits < n) stbi__grow_buffer_unsafe(j); + k = stbi_lrot(j->code_buffer, n); + j->code_buffer = k & ~stbi__bmask[n]; + k &= stbi__bmask[n]; + j->code_bits -= n; + return k; +} + +stbi_inline static int stbi__jpeg_get_bit(stbi__jpeg *j) +{ + unsigned int k; + if (j->code_bits < 1) stbi__grow_buffer_unsafe(j); + k = j->code_buffer; + j->code_buffer <<= 1; + --j->code_bits; + return k & 0x80000000; +} + +// given a value that's at position X in the zigzag stream, +// where does it appear in the 8x8 matrix coded as row-major? +static stbi_uc stbi__jpeg_dezigzag[64+15] = +{ + 0, 1, 8, 16, 9, 2, 3, 10, + 17, 24, 32, 25, 18, 11, 4, 5, + 12, 19, 26, 33, 40, 48, 41, 34, + 27, 20, 13, 6, 7, 14, 21, 28, + 35, 42, 49, 56, 57, 50, 43, 36, + 29, 22, 15, 23, 30, 37, 44, 51, + 58, 59, 52, 45, 38, 31, 39, 46, + 53, 60, 61, 54, 47, 55, 62, 63, + // let corrupt input sample past end + 63, 63, 63, 63, 63, 63, 63, 63, + 63, 63, 63, 63, 63, 63, 63 +}; + +// decode one 64-entry block-- +static int stbi__jpeg_decode_block(stbi__jpeg *j, short data[64], stbi__huffman *hdc, stbi__huffman *hac, stbi__int16 *fac, int b, stbi_uc *dequant) +{ + int diff,dc,k; + int t; + + if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); + t = stbi__jpeg_huff_decode(j, hdc); + if (t < 0) return stbi__err("bad huffman code","Corrupt JPEG"); + + // 0 all the ac values now so we can do it 32-bits at a time + memset(data,0,64*sizeof(data[0])); + + diff = t ? stbi__extend_receive(j, t) : 0; + dc = j->img_comp[b].dc_pred + diff; + j->img_comp[b].dc_pred = dc; + data[0] = (short) (dc * dequant[0]); + + // decode AC components, see JPEG spec + k = 1; + do { + unsigned int zig; + int c,r,s; + if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); + c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1); + r = fac[c]; + if (r) { // fast-AC path + k += (r >> 4) & 15; // run + s = r & 15; // combined length + j->code_buffer <<= s; + j->code_bits -= s; + // decode into unzigzag'd location + zig = stbi__jpeg_dezigzag[k++]; + data[zig] = (short) ((r >> 8) * dequant[zig]); + } else { + int rs = stbi__jpeg_huff_decode(j, hac); + if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG"); + s = rs & 15; + r = rs >> 4; + if (s == 0) { + if (rs != 0xf0) break; // end block + k += 16; + } else { + k += r; + // decode into unzigzag'd location + zig = stbi__jpeg_dezigzag[k++]; + data[zig] = (short) (stbi__extend_receive(j,s) * dequant[zig]); + } + } + } while (k < 64); + return 1; +} + +static int stbi__jpeg_decode_block_prog_dc(stbi__jpeg *j, short data[64], stbi__huffman *hdc, int b) +{ + int diff,dc; + int t; + if (j->spec_end != 0) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); + + if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); + + if (j->succ_high == 0) { + // first scan for DC coefficient, must be first + memset(data,0,64*sizeof(data[0])); // 0 all the ac values now + t = stbi__jpeg_huff_decode(j, hdc); + diff = t ? stbi__extend_receive(j, t) : 0; + + dc = j->img_comp[b].dc_pred + diff; + j->img_comp[b].dc_pred = dc; + data[0] = (short) (dc << j->succ_low); + } else { + // refinement scan for DC coefficient + if (stbi__jpeg_get_bit(j)) + data[0] += (short) (1 << j->succ_low); + } + return 1; +} + +// @OPTIMIZE: store non-zigzagged during the decode passes, +// and only de-zigzag when dequantizing +static int stbi__jpeg_decode_block_prog_ac(stbi__jpeg *j, short data[64], stbi__huffman *hac, stbi__int16 *fac) +{ + int k; + if (j->spec_start == 0) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); + + if (j->succ_high == 0) { + int shift = j->succ_low; + + if (j->eob_run) { + --j->eob_run; + return 1; + } + + k = j->spec_start; + do { + unsigned int zig; + int c,r,s; + if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); + c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1); + r = fac[c]; + if (r) { // fast-AC path + k += (r >> 4) & 15; // run + s = r & 15; // combined length + j->code_buffer <<= s; + j->code_bits -= s; + zig = stbi__jpeg_dezigzag[k++]; + data[zig] = (short) ((r >> 8) << shift); + } else { + int rs = stbi__jpeg_huff_decode(j, hac); + if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG"); + s = rs & 15; + r = rs >> 4; + if (s == 0) { + if (r < 15) { + j->eob_run = (1 << r); + if (r) + j->eob_run += stbi__jpeg_get_bits(j, r); + --j->eob_run; + break; + } + k += 16; + } else { + k += r; + zig = stbi__jpeg_dezigzag[k++]; + data[zig] = (short) (stbi__extend_receive(j,s) << shift); + } + } + } while (k <= j->spec_end); + } else { + // refinement scan for these AC coefficients + + short bit = (short) (1 << j->succ_low); + + if (j->eob_run) { + --j->eob_run; + for (k = j->spec_start; k <= j->spec_end; ++k) { + short *p = &data[stbi__jpeg_dezigzag[k]]; + if (*p != 0) + if (stbi__jpeg_get_bit(j)) + if ((*p & bit)==0) { + if (*p > 0) + *p += bit; + else + *p -= bit; + } + } + } else { + k = j->spec_start; + do { + int r,s; + int rs = stbi__jpeg_huff_decode(j, hac); // @OPTIMIZE see if we can use the fast path here, advance-by-r is so slow, eh + if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG"); + s = rs & 15; + r = rs >> 4; + if (s == 0) { + if (r < 15) { + j->eob_run = (1 << r) - 1; + if (r) + j->eob_run += stbi__jpeg_get_bits(j, r); + r = 64; // force end of block + } else { + // r=15 s=0 should write 16 0s, so we just do + // a run of 15 0s and then write s (which is 0), + // so we don't have to do anything special here + } + } else { + if (s != 1) return stbi__err("bad huffman code", "Corrupt JPEG"); + // sign bit + if (stbi__jpeg_get_bit(j)) + s = bit; + else + s = -bit; + } + + // advance by r + while (k <= j->spec_end) { + short *p = &data[stbi__jpeg_dezigzag[k++]]; + if (*p != 0) { + if (stbi__jpeg_get_bit(j)) + if ((*p & bit)==0) { + if (*p > 0) + *p += bit; + else + *p -= bit; + } + } else { + if (r == 0) { + *p = (short) s; + break; + } + --r; + } + } + } while (k <= j->spec_end); + } + } + return 1; +} + +// take a -128..127 value and stbi__clamp it and convert to 0..255 +stbi_inline static stbi_uc stbi__clamp(int x) +{ + // trick to use a single test to catch both cases + if ((unsigned int) x > 255) { + if (x < 0) return 0; + if (x > 255) return 255; + } + return (stbi_uc) x; +} + +#define stbi__f2f(x) ((int) (((x) * 4096 + 0.5))) +#define stbi__fsh(x) ((x) << 12) + +// derived from jidctint -- DCT_ISLOW +#define STBI__IDCT_1D(s0,s1,s2,s3,s4,s5,s6,s7) \ + int t0,t1,t2,t3,p1,p2,p3,p4,p5,x0,x1,x2,x3; \ + p2 = s2; \ + p3 = s6; \ + p1 = (p2+p3) * stbi__f2f(0.5411961f); \ + t2 = p1 + p3*stbi__f2f(-1.847759065f); \ + t3 = p1 + p2*stbi__f2f( 0.765366865f); \ + p2 = s0; \ + p3 = s4; \ + t0 = stbi__fsh(p2+p3); \ + t1 = stbi__fsh(p2-p3); \ + x0 = t0+t3; \ + x3 = t0-t3; \ + x1 = t1+t2; \ + x2 = t1-t2; \ + t0 = s7; \ + t1 = s5; \ + t2 = s3; \ + t3 = s1; \ + p3 = t0+t2; \ + p4 = t1+t3; \ + p1 = t0+t3; \ + p2 = t1+t2; \ + p5 = (p3+p4)*stbi__f2f( 1.175875602f); \ + t0 = t0*stbi__f2f( 0.298631336f); \ + t1 = t1*stbi__f2f( 2.053119869f); \ + t2 = t2*stbi__f2f( 3.072711026f); \ + t3 = t3*stbi__f2f( 1.501321110f); \ + p1 = p5 + p1*stbi__f2f(-0.899976223f); \ + p2 = p5 + p2*stbi__f2f(-2.562915447f); \ + p3 = p3*stbi__f2f(-1.961570560f); \ + p4 = p4*stbi__f2f(-0.390180644f); \ + t3 += p1+p4; \ + t2 += p2+p3; \ + t1 += p2+p4; \ + t0 += p1+p3; + +static void stbi__idct_block(stbi_uc *out, int out_stride, short data[64]) +{ + int i,val[64],*v=val; + stbi_uc *o; + short *d = data; + + // columns + for (i=0; i < 8; ++i,++d, ++v) { + // if all zeroes, shortcut -- this avoids dequantizing 0s and IDCTing + if (d[ 8]==0 && d[16]==0 && d[24]==0 && d[32]==0 + && d[40]==0 && d[48]==0 && d[56]==0) { + // no shortcut 0 seconds + // (1|2|3|4|5|6|7)==0 0 seconds + // all separate -0.047 seconds + // 1 && 2|3 && 4|5 && 6|7: -0.047 seconds + int dcterm = d[0] << 2; + v[0] = v[8] = v[16] = v[24] = v[32] = v[40] = v[48] = v[56] = dcterm; + } else { + STBI__IDCT_1D(d[ 0],d[ 8],d[16],d[24],d[32],d[40],d[48],d[56]) + // constants scaled things up by 1<<12; let's bring them back + // down, but keep 2 extra bits of precision + x0 += 512; x1 += 512; x2 += 512; x3 += 512; + v[ 0] = (x0+t3) >> 10; + v[56] = (x0-t3) >> 10; + v[ 8] = (x1+t2) >> 10; + v[48] = (x1-t2) >> 10; + v[16] = (x2+t1) >> 10; + v[40] = (x2-t1) >> 10; + v[24] = (x3+t0) >> 10; + v[32] = (x3-t0) >> 10; + } + } + + for (i=0, v=val, o=out; i < 8; ++i,v+=8,o+=out_stride) { + // no fast case since the first 1D IDCT spread components out + STBI__IDCT_1D(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7]) + // constants scaled things up by 1<<12, plus we had 1<<2 from first + // loop, plus horizontal and vertical each scale by sqrt(8) so together + // we've got an extra 1<<3, so 1<<17 total we need to remove. + // so we want to round that, which means adding 0.5 * 1<<17, + // aka 65536. Also, we'll end up with -128 to 127 that we want + // to encode as 0..255 by adding 128, so we'll add that before the shift + x0 += 65536 + (128<<17); + x1 += 65536 + (128<<17); + x2 += 65536 + (128<<17); + x3 += 65536 + (128<<17); + // tried computing the shifts into temps, or'ing the temps to see + // if any were out of range, but that was slower + o[0] = stbi__clamp((x0+t3) >> 17); + o[7] = stbi__clamp((x0-t3) >> 17); + o[1] = stbi__clamp((x1+t2) >> 17); + o[6] = stbi__clamp((x1-t2) >> 17); + o[2] = stbi__clamp((x2+t1) >> 17); + o[5] = stbi__clamp((x2-t1) >> 17); + o[3] = stbi__clamp((x3+t0) >> 17); + o[4] = stbi__clamp((x3-t0) >> 17); + } +} + +#ifdef STBI_SSE2 +// sse2 integer IDCT. not the fastest possible implementation but it +// produces bit-identical results to the generic C version so it's +// fully "transparent". +static void stbi__idct_simd(stbi_uc *out, int out_stride, short data[64]) +{ + // This is constructed to match our regular (generic) integer IDCT exactly. + __m128i row0, row1, row2, row3, row4, row5, row6, row7; + __m128i tmp; + + // dot product constant: even elems=x, odd elems=y + #define dct_const(x,y) _mm_setr_epi16((x),(y),(x),(y),(x),(y),(x),(y)) + + // out(0) = c0[even]*x + c0[odd]*y (c0, x, y 16-bit, out 32-bit) + // out(1) = c1[even]*x + c1[odd]*y + #define dct_rot(out0,out1, x,y,c0,c1) \ + __m128i c0##lo = _mm_unpacklo_epi16((x),(y)); \ + __m128i c0##hi = _mm_unpackhi_epi16((x),(y)); \ + __m128i out0##_l = _mm_madd_epi16(c0##lo, c0); \ + __m128i out0##_h = _mm_madd_epi16(c0##hi, c0); \ + __m128i out1##_l = _mm_madd_epi16(c0##lo, c1); \ + __m128i out1##_h = _mm_madd_epi16(c0##hi, c1) + + // out = in << 12 (in 16-bit, out 32-bit) + #define dct_widen(out, in) \ + __m128i out##_l = _mm_srai_epi32(_mm_unpacklo_epi16(_mm_setzero_si128(), (in)), 4); \ + __m128i out##_h = _mm_srai_epi32(_mm_unpackhi_epi16(_mm_setzero_si128(), (in)), 4) + + // wide add + #define dct_wadd(out, a, b) \ + __m128i out##_l = _mm_add_epi32(a##_l, b##_l); \ + __m128i out##_h = _mm_add_epi32(a##_h, b##_h) + + // wide sub + #define dct_wsub(out, a, b) \ + __m128i out##_l = _mm_sub_epi32(a##_l, b##_l); \ + __m128i out##_h = _mm_sub_epi32(a##_h, b##_h) + + // butterfly a/b, add bias, then shift by "s" and pack + #define dct_bfly32o(out0, out1, a,b,bias,s) \ + { \ + __m128i abiased_l = _mm_add_epi32(a##_l, bias); \ + __m128i abiased_h = _mm_add_epi32(a##_h, bias); \ + dct_wadd(sum, abiased, b); \ + dct_wsub(dif, abiased, b); \ + out0 = _mm_packs_epi32(_mm_srai_epi32(sum_l, s), _mm_srai_epi32(sum_h, s)); \ + out1 = _mm_packs_epi32(_mm_srai_epi32(dif_l, s), _mm_srai_epi32(dif_h, s)); \ + } + + // 8-bit interleave step (for transposes) + #define dct_interleave8(a, b) \ + tmp = a; \ + a = _mm_unpacklo_epi8(a, b); \ + b = _mm_unpackhi_epi8(tmp, b) + + // 16-bit interleave step (for transposes) + #define dct_interleave16(a, b) \ + tmp = a; \ + a = _mm_unpacklo_epi16(a, b); \ + b = _mm_unpackhi_epi16(tmp, b) + + #define dct_pass(bias,shift) \ + { \ + /* even part */ \ + dct_rot(t2e,t3e, row2,row6, rot0_0,rot0_1); \ + __m128i sum04 = _mm_add_epi16(row0, row4); \ + __m128i dif04 = _mm_sub_epi16(row0, row4); \ + dct_widen(t0e, sum04); \ + dct_widen(t1e, dif04); \ + dct_wadd(x0, t0e, t3e); \ + dct_wsub(x3, t0e, t3e); \ + dct_wadd(x1, t1e, t2e); \ + dct_wsub(x2, t1e, t2e); \ + /* odd part */ \ + dct_rot(y0o,y2o, row7,row3, rot2_0,rot2_1); \ + dct_rot(y1o,y3o, row5,row1, rot3_0,rot3_1); \ + __m128i sum17 = _mm_add_epi16(row1, row7); \ + __m128i sum35 = _mm_add_epi16(row3, row5); \ + dct_rot(y4o,y5o, sum17,sum35, rot1_0,rot1_1); \ + dct_wadd(x4, y0o, y4o); \ + dct_wadd(x5, y1o, y5o); \ + dct_wadd(x6, y2o, y5o); \ + dct_wadd(x7, y3o, y4o); \ + dct_bfly32o(row0,row7, x0,x7,bias,shift); \ + dct_bfly32o(row1,row6, x1,x6,bias,shift); \ + dct_bfly32o(row2,row5, x2,x5,bias,shift); \ + dct_bfly32o(row3,row4, x3,x4,bias,shift); \ + } + + __m128i rot0_0 = dct_const(stbi__f2f(0.5411961f), stbi__f2f(0.5411961f) + stbi__f2f(-1.847759065f)); + __m128i rot0_1 = dct_const(stbi__f2f(0.5411961f) + stbi__f2f( 0.765366865f), stbi__f2f(0.5411961f)); + __m128i rot1_0 = dct_const(stbi__f2f(1.175875602f) + stbi__f2f(-0.899976223f), stbi__f2f(1.175875602f)); + __m128i rot1_1 = dct_const(stbi__f2f(1.175875602f), stbi__f2f(1.175875602f) + stbi__f2f(-2.562915447f)); + __m128i rot2_0 = dct_const(stbi__f2f(-1.961570560f) + stbi__f2f( 0.298631336f), stbi__f2f(-1.961570560f)); + __m128i rot2_1 = dct_const(stbi__f2f(-1.961570560f), stbi__f2f(-1.961570560f) + stbi__f2f( 3.072711026f)); + __m128i rot3_0 = dct_const(stbi__f2f(-0.390180644f) + stbi__f2f( 2.053119869f), stbi__f2f(-0.390180644f)); + __m128i rot3_1 = dct_const(stbi__f2f(-0.390180644f), stbi__f2f(-0.390180644f) + stbi__f2f( 1.501321110f)); + + // rounding biases in column/row passes, see stbi__idct_block for explanation. + __m128i bias_0 = _mm_set1_epi32(512); + __m128i bias_1 = _mm_set1_epi32(65536 + (128<<17)); + + // load + row0 = _mm_load_si128((const __m128i *) (data + 0*8)); + row1 = _mm_load_si128((const __m128i *) (data + 1*8)); + row2 = _mm_load_si128((const __m128i *) (data + 2*8)); + row3 = _mm_load_si128((const __m128i *) (data + 3*8)); + row4 = _mm_load_si128((const __m128i *) (data + 4*8)); + row5 = _mm_load_si128((const __m128i *) (data + 5*8)); + row6 = _mm_load_si128((const __m128i *) (data + 6*8)); + row7 = _mm_load_si128((const __m128i *) (data + 7*8)); + + // column pass + dct_pass(bias_0, 10); + + { + // 16bit 8x8 transpose pass 1 + dct_interleave16(row0, row4); + dct_interleave16(row1, row5); + dct_interleave16(row2, row6); + dct_interleave16(row3, row7); + + // transpose pass 2 + dct_interleave16(row0, row2); + dct_interleave16(row1, row3); + dct_interleave16(row4, row6); + dct_interleave16(row5, row7); + + // transpose pass 3 + dct_interleave16(row0, row1); + dct_interleave16(row2, row3); + dct_interleave16(row4, row5); + dct_interleave16(row6, row7); + } + + // row pass + dct_pass(bias_1, 17); + + { + // pack + __m128i p0 = _mm_packus_epi16(row0, row1); // a0a1a2a3...a7b0b1b2b3...b7 + __m128i p1 = _mm_packus_epi16(row2, row3); + __m128i p2 = _mm_packus_epi16(row4, row5); + __m128i p3 = _mm_packus_epi16(row6, row7); + + // 8bit 8x8 transpose pass 1 + dct_interleave8(p0, p2); // a0e0a1e1... + dct_interleave8(p1, p3); // c0g0c1g1... + + // transpose pass 2 + dct_interleave8(p0, p1); // a0c0e0g0... + dct_interleave8(p2, p3); // b0d0f0h0... + + // transpose pass 3 + dct_interleave8(p0, p2); // a0b0c0d0... + dct_interleave8(p1, p3); // a4b4c4d4... + + // store + _mm_storel_epi64((__m128i *) out, p0); out += out_stride; + _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p0, 0x4e)); out += out_stride; + _mm_storel_epi64((__m128i *) out, p2); out += out_stride; + _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p2, 0x4e)); out += out_stride; + _mm_storel_epi64((__m128i *) out, p1); out += out_stride; + _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p1, 0x4e)); out += out_stride; + _mm_storel_epi64((__m128i *) out, p3); out += out_stride; + _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p3, 0x4e)); + } + +#undef dct_const +#undef dct_rot +#undef dct_widen +#undef dct_wadd +#undef dct_wsub +#undef dct_bfly32o +#undef dct_interleave8 +#undef dct_interleave16 +#undef dct_pass +} + +#endif // STBI_SSE2 + +#ifdef STBI_NEON + +// NEON integer IDCT. should produce bit-identical +// results to the generic C version. +static void stbi__idct_simd(stbi_uc *out, int out_stride, short data[64]) +{ + int16x8_t row0, row1, row2, row3, row4, row5, row6, row7; + + int16x4_t rot0_0 = vdup_n_s16(stbi__f2f(0.5411961f)); + int16x4_t rot0_1 = vdup_n_s16(stbi__f2f(-1.847759065f)); + int16x4_t rot0_2 = vdup_n_s16(stbi__f2f( 0.765366865f)); + int16x4_t rot1_0 = vdup_n_s16(stbi__f2f( 1.175875602f)); + int16x4_t rot1_1 = vdup_n_s16(stbi__f2f(-0.899976223f)); + int16x4_t rot1_2 = vdup_n_s16(stbi__f2f(-2.562915447f)); + int16x4_t rot2_0 = vdup_n_s16(stbi__f2f(-1.961570560f)); + int16x4_t rot2_1 = vdup_n_s16(stbi__f2f(-0.390180644f)); + int16x4_t rot3_0 = vdup_n_s16(stbi__f2f( 0.298631336f)); + int16x4_t rot3_1 = vdup_n_s16(stbi__f2f( 2.053119869f)); + int16x4_t rot3_2 = vdup_n_s16(stbi__f2f( 3.072711026f)); + int16x4_t rot3_3 = vdup_n_s16(stbi__f2f( 1.501321110f)); + +#define dct_long_mul(out, inq, coeff) \ + int32x4_t out##_l = vmull_s16(vget_low_s16(inq), coeff); \ + int32x4_t out##_h = vmull_s16(vget_high_s16(inq), coeff) + +#define dct_long_mac(out, acc, inq, coeff) \ + int32x4_t out##_l = vmlal_s16(acc##_l, vget_low_s16(inq), coeff); \ + int32x4_t out##_h = vmlal_s16(acc##_h, vget_high_s16(inq), coeff) + +#define dct_widen(out, inq) \ + int32x4_t out##_l = vshll_n_s16(vget_low_s16(inq), 12); \ + int32x4_t out##_h = vshll_n_s16(vget_high_s16(inq), 12) + +// wide add +#define dct_wadd(out, a, b) \ + int32x4_t out##_l = vaddq_s32(a##_l, b##_l); \ + int32x4_t out##_h = vaddq_s32(a##_h, b##_h) + +// wide sub +#define dct_wsub(out, a, b) \ + int32x4_t out##_l = vsubq_s32(a##_l, b##_l); \ + int32x4_t out##_h = vsubq_s32(a##_h, b##_h) + +// butterfly a/b, then shift using "shiftop" by "s" and pack +#define dct_bfly32o(out0,out1, a,b,shiftop,s) \ + { \ + dct_wadd(sum, a, b); \ + dct_wsub(dif, a, b); \ + out0 = vcombine_s16(shiftop(sum_l, s), shiftop(sum_h, s)); \ + out1 = vcombine_s16(shiftop(dif_l, s), shiftop(dif_h, s)); \ + } + +#define dct_pass(shiftop, shift) \ + { \ + /* even part */ \ + int16x8_t sum26 = vaddq_s16(row2, row6); \ + dct_long_mul(p1e, sum26, rot0_0); \ + dct_long_mac(t2e, p1e, row6, rot0_1); \ + dct_long_mac(t3e, p1e, row2, rot0_2); \ + int16x8_t sum04 = vaddq_s16(row0, row4); \ + int16x8_t dif04 = vsubq_s16(row0, row4); \ + dct_widen(t0e, sum04); \ + dct_widen(t1e, dif04); \ + dct_wadd(x0, t0e, t3e); \ + dct_wsub(x3, t0e, t3e); \ + dct_wadd(x1, t1e, t2e); \ + dct_wsub(x2, t1e, t2e); \ + /* odd part */ \ + int16x8_t sum15 = vaddq_s16(row1, row5); \ + int16x8_t sum17 = vaddq_s16(row1, row7); \ + int16x8_t sum35 = vaddq_s16(row3, row5); \ + int16x8_t sum37 = vaddq_s16(row3, row7); \ + int16x8_t sumodd = vaddq_s16(sum17, sum35); \ + dct_long_mul(p5o, sumodd, rot1_0); \ + dct_long_mac(p1o, p5o, sum17, rot1_1); \ + dct_long_mac(p2o, p5o, sum35, rot1_2); \ + dct_long_mul(p3o, sum37, rot2_0); \ + dct_long_mul(p4o, sum15, rot2_1); \ + dct_wadd(sump13o, p1o, p3o); \ + dct_wadd(sump24o, p2o, p4o); \ + dct_wadd(sump23o, p2o, p3o); \ + dct_wadd(sump14o, p1o, p4o); \ + dct_long_mac(x4, sump13o, row7, rot3_0); \ + dct_long_mac(x5, sump24o, row5, rot3_1); \ + dct_long_mac(x6, sump23o, row3, rot3_2); \ + dct_long_mac(x7, sump14o, row1, rot3_3); \ + dct_bfly32o(row0,row7, x0,x7,shiftop,shift); \ + dct_bfly32o(row1,row6, x1,x6,shiftop,shift); \ + dct_bfly32o(row2,row5, x2,x5,shiftop,shift); \ + dct_bfly32o(row3,row4, x3,x4,shiftop,shift); \ + } + + // load + row0 = vld1q_s16(data + 0*8); + row1 = vld1q_s16(data + 1*8); + row2 = vld1q_s16(data + 2*8); + row3 = vld1q_s16(data + 3*8); + row4 = vld1q_s16(data + 4*8); + row5 = vld1q_s16(data + 5*8); + row6 = vld1q_s16(data + 6*8); + row7 = vld1q_s16(data + 7*8); + + // add DC bias + row0 = vaddq_s16(row0, vsetq_lane_s16(1024, vdupq_n_s16(0), 0)); + + // column pass + dct_pass(vrshrn_n_s32, 10); + + // 16bit 8x8 transpose + { +// these three map to a single VTRN.16, VTRN.32, and VSWP, respectively. +// whether compilers actually get this is another story, sadly. +#define dct_trn16(x, y) { int16x8x2_t t = vtrnq_s16(x, y); x = t.val[0]; y = t.val[1]; } +#define dct_trn32(x, y) { int32x4x2_t t = vtrnq_s32(vreinterpretq_s32_s16(x), vreinterpretq_s32_s16(y)); x = vreinterpretq_s16_s32(t.val[0]); y = vreinterpretq_s16_s32(t.val[1]); } +#define dct_trn64(x, y) { int16x8_t x0 = x; int16x8_t y0 = y; x = vcombine_s16(vget_low_s16(x0), vget_low_s16(y0)); y = vcombine_s16(vget_high_s16(x0), vget_high_s16(y0)); } + + // pass 1 + dct_trn16(row0, row1); // a0b0a2b2a4b4a6b6 + dct_trn16(row2, row3); + dct_trn16(row4, row5); + dct_trn16(row6, row7); + + // pass 2 + dct_trn32(row0, row2); // a0b0c0d0a4b4c4d4 + dct_trn32(row1, row3); + dct_trn32(row4, row6); + dct_trn32(row5, row7); + + // pass 3 + dct_trn64(row0, row4); // a0b0c0d0e0f0g0h0 + dct_trn64(row1, row5); + dct_trn64(row2, row6); + dct_trn64(row3, row7); + +#undef dct_trn16 +#undef dct_trn32 +#undef dct_trn64 + } + + // row pass + // vrshrn_n_s32 only supports shifts up to 16, we need + // 17. so do a non-rounding shift of 16 first then follow + // up with a rounding shift by 1. + dct_pass(vshrn_n_s32, 16); + + { + // pack and round + uint8x8_t p0 = vqrshrun_n_s16(row0, 1); + uint8x8_t p1 = vqrshrun_n_s16(row1, 1); + uint8x8_t p2 = vqrshrun_n_s16(row2, 1); + uint8x8_t p3 = vqrshrun_n_s16(row3, 1); + uint8x8_t p4 = vqrshrun_n_s16(row4, 1); + uint8x8_t p5 = vqrshrun_n_s16(row5, 1); + uint8x8_t p6 = vqrshrun_n_s16(row6, 1); + uint8x8_t p7 = vqrshrun_n_s16(row7, 1); + + // again, these can translate into one instruction, but often don't. +#define dct_trn8_8(x, y) { uint8x8x2_t t = vtrn_u8(x, y); x = t.val[0]; y = t.val[1]; } +#define dct_trn8_16(x, y) { uint16x4x2_t t = vtrn_u16(vreinterpret_u16_u8(x), vreinterpret_u16_u8(y)); x = vreinterpret_u8_u16(t.val[0]); y = vreinterpret_u8_u16(t.val[1]); } +#define dct_trn8_32(x, y) { uint32x2x2_t t = vtrn_u32(vreinterpret_u32_u8(x), vreinterpret_u32_u8(y)); x = vreinterpret_u8_u32(t.val[0]); y = vreinterpret_u8_u32(t.val[1]); } + + // sadly can't use interleaved stores here since we only write + // 8 bytes to each scan line! + + // 8x8 8-bit transpose pass 1 + dct_trn8_8(p0, p1); + dct_trn8_8(p2, p3); + dct_trn8_8(p4, p5); + dct_trn8_8(p6, p7); + + // pass 2 + dct_trn8_16(p0, p2); + dct_trn8_16(p1, p3); + dct_trn8_16(p4, p6); + dct_trn8_16(p5, p7); + + // pass 3 + dct_trn8_32(p0, p4); + dct_trn8_32(p1, p5); + dct_trn8_32(p2, p6); + dct_trn8_32(p3, p7); + + // store + vst1_u8(out, p0); out += out_stride; + vst1_u8(out, p1); out += out_stride; + vst1_u8(out, p2); out += out_stride; + vst1_u8(out, p3); out += out_stride; + vst1_u8(out, p4); out += out_stride; + vst1_u8(out, p5); out += out_stride; + vst1_u8(out, p6); out += out_stride; + vst1_u8(out, p7); + +#undef dct_trn8_8 +#undef dct_trn8_16 +#undef dct_trn8_32 + } + +#undef dct_long_mul +#undef dct_long_mac +#undef dct_widen +#undef dct_wadd +#undef dct_wsub +#undef dct_bfly32o +#undef dct_pass +} + +#endif // STBI_NEON + +#define STBI__MARKER_none 0xff +// if there's a pending marker from the entropy stream, return that +// otherwise, fetch from the stream and get a marker. if there's no +// marker, return 0xff, which is never a valid marker value +static stbi_uc stbi__get_marker(stbi__jpeg *j) +{ + stbi_uc x; + if (j->marker != STBI__MARKER_none) { x = j->marker; j->marker = STBI__MARKER_none; return x; } + x = stbi__get8(j->s); + if (x != 0xff) return STBI__MARKER_none; + while (x == 0xff) + x = stbi__get8(j->s); + return x; +} + +// in each scan, we'll have scan_n components, and the order +// of the components is specified by order[] +#define STBI__RESTART(x) ((x) >= 0xd0 && (x) <= 0xd7) + +// after a restart interval, stbi__jpeg_reset the entropy decoder and +// the dc prediction +static void stbi__jpeg_reset(stbi__jpeg *j) +{ + j->code_bits = 0; + j->code_buffer = 0; + j->nomore = 0; + j->img_comp[0].dc_pred = j->img_comp[1].dc_pred = j->img_comp[2].dc_pred = 0; + j->marker = STBI__MARKER_none; + j->todo = j->restart_interval ? j->restart_interval : 0x7fffffff; + j->eob_run = 0; + // no more than 1<<31 MCUs if no restart_interal? that's plenty safe, + // since we don't even allow 1<<30 pixels +} + +static int stbi__parse_entropy_coded_data(stbi__jpeg *z) +{ + stbi__jpeg_reset(z); + if (!z->progressive) { + if (z->scan_n == 1) { + int i,j; + STBI_SIMD_ALIGN(short, data[64]); + int n = z->order[0]; + // non-interleaved data, we just need to process one block at a time, + // in trivial scanline order + // number of blocks to do just depends on how many actual "pixels" this + // component has, independent of interleaved MCU blocking and such + int w = (z->img_comp[n].x+7) >> 3; + int h = (z->img_comp[n].y+7) >> 3; + for (j=0; j < h; ++j) { + for (i=0; i < w; ++i) { + int ha = z->img_comp[n].ha; + if (!stbi__jpeg_decode_block(z, data, z->huff_dc+z->img_comp[n].hd, z->huff_ac+ha, z->fast_ac[ha], n, z->dequant[z->img_comp[n].tq])) return 0; + z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*j*8+i*8, z->img_comp[n].w2, data); + // every data block is an MCU, so countdown the restart interval + if (--z->todo <= 0) { + if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); + // if it's NOT a restart, then just bail, so we get corrupt data + // rather than no data + if (!STBI__RESTART(z->marker)) return 1; + stbi__jpeg_reset(z); + } + } + } + return 1; + } else { // interleaved + int i,j,k,x,y; + STBI_SIMD_ALIGN(short, data[64]); + for (j=0; j < z->img_mcu_y; ++j) { + for (i=0; i < z->img_mcu_x; ++i) { + // scan an interleaved mcu... process scan_n components in order + for (k=0; k < z->scan_n; ++k) { + int n = z->order[k]; + // scan out an mcu's worth of this component; that's just determined + // by the basic H and V specified for the component + for (y=0; y < z->img_comp[n].v; ++y) { + for (x=0; x < z->img_comp[n].h; ++x) { + int x2 = (i*z->img_comp[n].h + x)*8; + int y2 = (j*z->img_comp[n].v + y)*8; + int ha = z->img_comp[n].ha; + if (!stbi__jpeg_decode_block(z, data, z->huff_dc+z->img_comp[n].hd, z->huff_ac+ha, z->fast_ac[ha], n, z->dequant[z->img_comp[n].tq])) return 0; + z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*y2+x2, z->img_comp[n].w2, data); + } + } + } + // after all interleaved components, that's an interleaved MCU, + // so now count down the restart interval + if (--z->todo <= 0) { + if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); + if (!STBI__RESTART(z->marker)) return 1; + stbi__jpeg_reset(z); + } + } + } + return 1; + } + } else { + if (z->scan_n == 1) { + int i,j; + int n = z->order[0]; + // non-interleaved data, we just need to process one block at a time, + // in trivial scanline order + // number of blocks to do just depends on how many actual "pixels" this + // component has, independent of interleaved MCU blocking and such + int w = (z->img_comp[n].x+7) >> 3; + int h = (z->img_comp[n].y+7) >> 3; + for (j=0; j < h; ++j) { + for (i=0; i < w; ++i) { + short *data = z->img_comp[n].coeff + 64 * (i + j * z->img_comp[n].coeff_w); + if (z->spec_start == 0) { + if (!stbi__jpeg_decode_block_prog_dc(z, data, &z->huff_dc[z->img_comp[n].hd], n)) + return 0; + } else { + int ha = z->img_comp[n].ha; + if (!stbi__jpeg_decode_block_prog_ac(z, data, &z->huff_ac[ha], z->fast_ac[ha])) + return 0; + } + // every data block is an MCU, so countdown the restart interval + if (--z->todo <= 0) { + if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); + if (!STBI__RESTART(z->marker)) return 1; + stbi__jpeg_reset(z); + } + } + } + return 1; + } else { // interleaved + int i,j,k,x,y; + for (j=0; j < z->img_mcu_y; ++j) { + for (i=0; i < z->img_mcu_x; ++i) { + // scan an interleaved mcu... process scan_n components in order + for (k=0; k < z->scan_n; ++k) { + int n = z->order[k]; + // scan out an mcu's worth of this component; that's just determined + // by the basic H and V specified for the component + for (y=0; y < z->img_comp[n].v; ++y) { + for (x=0; x < z->img_comp[n].h; ++x) { + int x2 = (i*z->img_comp[n].h + x); + int y2 = (j*z->img_comp[n].v + y); + short *data = z->img_comp[n].coeff + 64 * (x2 + y2 * z->img_comp[n].coeff_w); + if (!stbi__jpeg_decode_block_prog_dc(z, data, &z->huff_dc[z->img_comp[n].hd], n)) + return 0; + } + } + } + // after all interleaved components, that's an interleaved MCU, + // so now count down the restart interval + if (--z->todo <= 0) { + if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); + if (!STBI__RESTART(z->marker)) return 1; + stbi__jpeg_reset(z); + } + } + } + return 1; + } + } +} + +static void stbi__jpeg_dequantize(short *data, stbi_uc *dequant) +{ + int i; + for (i=0; i < 64; ++i) + data[i] *= dequant[i]; +} + +static void stbi__jpeg_finish(stbi__jpeg *z) +{ + if (z->progressive) { + // dequantize and idct the data + int i,j,n; + for (n=0; n < z->s->img_n; ++n) { + int w = (z->img_comp[n].x+7) >> 3; + int h = (z->img_comp[n].y+7) >> 3; + for (j=0; j < h; ++j) { + for (i=0; i < w; ++i) { + short *data = z->img_comp[n].coeff + 64 * (i + j * z->img_comp[n].coeff_w); + stbi__jpeg_dequantize(data, z->dequant[z->img_comp[n].tq]); + z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*j*8+i*8, z->img_comp[n].w2, data); + } + } + } + } +} + +static int stbi__process_marker(stbi__jpeg *z, int m) +{ + int L; + switch (m) { + case STBI__MARKER_none: // no marker found + return stbi__err("expected marker","Corrupt JPEG"); + + case 0xDD: // DRI - specify restart interval + if (stbi__get16be(z->s) != 4) return stbi__err("bad DRI len","Corrupt JPEG"); + z->restart_interval = stbi__get16be(z->s); + return 1; + + case 0xDB: // DQT - define quantization table + L = stbi__get16be(z->s)-2; + while (L > 0) { + int q = stbi__get8(z->s); + int p = q >> 4; + int t = q & 15,i; + if (p != 0) return stbi__err("bad DQT type","Corrupt JPEG"); + if (t > 3) return stbi__err("bad DQT table","Corrupt JPEG"); + for (i=0; i < 64; ++i) + z->dequant[t][stbi__jpeg_dezigzag[i]] = stbi__get8(z->s); + L -= 65; + } + return L==0; + + case 0xC4: // DHT - define huffman table + L = stbi__get16be(z->s)-2; + while (L > 0) { + stbi_uc *v; + int sizes[16],i,n=0; + int q = stbi__get8(z->s); + int tc = q >> 4; + int th = q & 15; + if (tc > 1 || th > 3) return stbi__err("bad DHT header","Corrupt JPEG"); + for (i=0; i < 16; ++i) { + sizes[i] = stbi__get8(z->s); + n += sizes[i]; + } + L -= 17; + if (tc == 0) { + if (!stbi__build_huffman(z->huff_dc+th, sizes)) return 0; + v = z->huff_dc[th].values; + } else { + if (!stbi__build_huffman(z->huff_ac+th, sizes)) return 0; + v = z->huff_ac[th].values; + } + for (i=0; i < n; ++i) + v[i] = stbi__get8(z->s); + if (tc != 0) + stbi__build_fast_ac(z->fast_ac[th], z->huff_ac + th); + L -= n; + } + return L==0; + } + // check for comment block or APP blocks + if ((m >= 0xE0 && m <= 0xEF) || m == 0xFE) { + stbi__skip(z->s, stbi__get16be(z->s)-2); + return 1; + } + return 0; +} + +// after we see SOS +static int stbi__process_scan_header(stbi__jpeg *z) +{ + int i; + int Ls = stbi__get16be(z->s); + z->scan_n = stbi__get8(z->s); + if (z->scan_n < 1 || z->scan_n > 4 || z->scan_n > (int) z->s->img_n) return stbi__err("bad SOS component count","Corrupt JPEG"); + if (Ls != 6+2*z->scan_n) return stbi__err("bad SOS len","Corrupt JPEG"); + for (i=0; i < z->scan_n; ++i) { + int id = stbi__get8(z->s), which; + int q = stbi__get8(z->s); + for (which = 0; which < z->s->img_n; ++which) + if (z->img_comp[which].id == id) + break; + if (which == z->s->img_n) return 0; // no match + z->img_comp[which].hd = q >> 4; if (z->img_comp[which].hd > 3) return stbi__err("bad DC huff","Corrupt JPEG"); + z->img_comp[which].ha = q & 15; if (z->img_comp[which].ha > 3) return stbi__err("bad AC huff","Corrupt JPEG"); + z->order[i] = which; + } + + { + int aa; + z->spec_start = stbi__get8(z->s); + z->spec_end = stbi__get8(z->s); // should be 63, but might be 0 + aa = stbi__get8(z->s); + z->succ_high = (aa >> 4); + z->succ_low = (aa & 15); + if (z->progressive) { + if (z->spec_start > 63 || z->spec_end > 63 || z->spec_start > z->spec_end || z->succ_high > 13 || z->succ_low > 13) + return stbi__err("bad SOS", "Corrupt JPEG"); + } else { + if (z->spec_start != 0) return stbi__err("bad SOS","Corrupt JPEG"); + if (z->succ_high != 0 || z->succ_low != 0) return stbi__err("bad SOS","Corrupt JPEG"); + z->spec_end = 63; + } + } + + return 1; +} + +static int stbi__process_frame_header(stbi__jpeg *z, int scan) +{ + stbi__context *s = z->s; + int Lf,p,i,q, h_max=1,v_max=1,c; + Lf = stbi__get16be(s); if (Lf < 11) return stbi__err("bad SOF len","Corrupt JPEG"); // JPEG + p = stbi__get8(s); if (p != 8) return stbi__err("only 8-bit","JPEG format not supported: 8-bit only"); // JPEG baseline + s->img_y = stbi__get16be(s); if (s->img_y == 0) return stbi__err("no header height", "JPEG format not supported: delayed height"); // Legal, but we don't handle it--but neither does IJG + s->img_x = stbi__get16be(s); if (s->img_x == 0) return stbi__err("0 width","Corrupt JPEG"); // JPEG requires + c = stbi__get8(s); + if (c != 3 && c != 1) return stbi__err("bad component count","Corrupt JPEG"); // JFIF requires + s->img_n = c; + for (i=0; i < c; ++i) { + z->img_comp[i].data = NULL; + z->img_comp[i].linebuf = NULL; + } + + if (Lf != 8+3*s->img_n) return stbi__err("bad SOF len","Corrupt JPEG"); + + for (i=0; i < s->img_n; ++i) { + z->img_comp[i].id = stbi__get8(s); + if (z->img_comp[i].id != i+1) // JFIF requires + if (z->img_comp[i].id != i) // some version of jpegtran outputs non-JFIF-compliant files! + return stbi__err("bad component ID","Corrupt JPEG"); + q = stbi__get8(s); + z->img_comp[i].h = (q >> 4); if (!z->img_comp[i].h || z->img_comp[i].h > 4) return stbi__err("bad H","Corrupt JPEG"); + z->img_comp[i].v = q & 15; if (!z->img_comp[i].v || z->img_comp[i].v > 4) return stbi__err("bad V","Corrupt JPEG"); + z->img_comp[i].tq = stbi__get8(s); if (z->img_comp[i].tq > 3) return stbi__err("bad TQ","Corrupt JPEG"); + } + + if (scan != STBI__SCAN_load) return 1; + + if ((1 << 30) / s->img_x / s->img_n < s->img_y) return stbi__err("too large", "Image too large to decode"); + + for (i=0; i < s->img_n; ++i) { + if (z->img_comp[i].h > h_max) h_max = z->img_comp[i].h; + if (z->img_comp[i].v > v_max) v_max = z->img_comp[i].v; + } + + // compute interleaved mcu info + z->img_h_max = h_max; + z->img_v_max = v_max; + z->img_mcu_w = h_max * 8; + z->img_mcu_h = v_max * 8; + z->img_mcu_x = (s->img_x + z->img_mcu_w-1) / z->img_mcu_w; + z->img_mcu_y = (s->img_y + z->img_mcu_h-1) / z->img_mcu_h; + + for (i=0; i < s->img_n; ++i) { + // number of effective pixels (e.g. for non-interleaved MCU) + z->img_comp[i].x = (s->img_x * z->img_comp[i].h + h_max-1) / h_max; + z->img_comp[i].y = (s->img_y * z->img_comp[i].v + v_max-1) / v_max; + // to simplify generation, we'll allocate enough memory to decode + // the bogus oversized data from using interleaved MCUs and their + // big blocks (e.g. a 16x16 iMCU on an image of width 33); we won't + // discard the extra data until colorspace conversion + z->img_comp[i].w2 = z->img_mcu_x * z->img_comp[i].h * 8; + z->img_comp[i].h2 = z->img_mcu_y * z->img_comp[i].v * 8; + z->img_comp[i].raw_data = stbi__malloc(z->img_comp[i].w2 * z->img_comp[i].h2+15); + + if (z->img_comp[i].raw_data == NULL) { + for(--i; i >= 0; --i) { + STBI_FREE(z->img_comp[i].raw_data); + z->img_comp[i].raw_data = NULL; + } + return stbi__err("outofmem", "Out of memory"); + } + // align blocks for idct using mmx/sse + z->img_comp[i].data = (stbi_uc*) (((size_t) z->img_comp[i].raw_data + 15) & ~15); + z->img_comp[i].linebuf = NULL; + if (z->progressive) { + z->img_comp[i].coeff_w = (z->img_comp[i].w2 + 7) >> 3; + z->img_comp[i].coeff_h = (z->img_comp[i].h2 + 7) >> 3; + z->img_comp[i].raw_coeff = STBI_MALLOC(z->img_comp[i].coeff_w * z->img_comp[i].coeff_h * 64 * sizeof(short) + 15); + z->img_comp[i].coeff = (short*) (((size_t) z->img_comp[i].raw_coeff + 15) & ~15); + } else { + z->img_comp[i].coeff = 0; + z->img_comp[i].raw_coeff = 0; + } + } + + return 1; +} + +// use comparisons since in some cases we handle more than one case (e.g. SOF) +#define stbi__DNL(x) ((x) == 0xdc) +#define stbi__SOI(x) ((x) == 0xd8) +#define stbi__EOI(x) ((x) == 0xd9) +#define stbi__SOF(x) ((x) == 0xc0 || (x) == 0xc1 || (x) == 0xc2) +#define stbi__SOS(x) ((x) == 0xda) + +#define stbi__SOF_progressive(x) ((x) == 0xc2) + +static int stbi__decode_jpeg_header(stbi__jpeg *z, int scan) +{ + int m; + z->marker = STBI__MARKER_none; // initialize cached marker to empty + m = stbi__get_marker(z); + if (!stbi__SOI(m)) return stbi__err("no SOI","Corrupt JPEG"); + if (scan == STBI__SCAN_type) return 1; + m = stbi__get_marker(z); + while (!stbi__SOF(m)) { + if (!stbi__process_marker(z,m)) return 0; + m = stbi__get_marker(z); + while (m == STBI__MARKER_none) { + // some files have extra padding after their blocks, so ok, we'll scan + if (stbi__at_eof(z->s)) return stbi__err("no SOF", "Corrupt JPEG"); + m = stbi__get_marker(z); + } + } + z->progressive = stbi__SOF_progressive(m); + if (!stbi__process_frame_header(z, scan)) return 0; + return 1; +} + +// decode image to YCbCr format +static int stbi__decode_jpeg_image(stbi__jpeg *j) +{ + int m; + for (m = 0; m < 4; m++) { + j->img_comp[m].raw_data = NULL; + j->img_comp[m].raw_coeff = NULL; + } + j->restart_interval = 0; + if (!stbi__decode_jpeg_header(j, STBI__SCAN_load)) return 0; + m = stbi__get_marker(j); + while (!stbi__EOI(m)) { + if (stbi__SOS(m)) { + if (!stbi__process_scan_header(j)) return 0; + if (!stbi__parse_entropy_coded_data(j)) return 0; + if (j->marker == STBI__MARKER_none ) { + // handle 0s at the end of image data from IP Kamera 9060 + while (!stbi__at_eof(j->s)) { + int x = stbi__get8(j->s); + if (x == 255) { + j->marker = stbi__get8(j->s); + break; + } else if (x != 0) { + return stbi__err("junk before marker", "Corrupt JPEG"); + } + } + // if we reach eof without hitting a marker, stbi__get_marker() below will fail and we'll eventually return 0 + } + } else { + if (!stbi__process_marker(j, m)) return 0; + } + m = stbi__get_marker(j); + } + if (j->progressive) + stbi__jpeg_finish(j); + return 1; +} + +// static jfif-centered resampling (across block boundaries) + +typedef stbi_uc *(*resample_row_func)(stbi_uc *out, stbi_uc *in0, stbi_uc *in1, + int w, int hs); + +#define stbi__div4(x) ((stbi_uc) ((x) >> 2)) + +static stbi_uc *resample_row_1(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + STBI_NOTUSED(out); + STBI_NOTUSED(in_far); + STBI_NOTUSED(w); + STBI_NOTUSED(hs); + return in_near; +} + +static stbi_uc* stbi__resample_row_v_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + // need to generate two samples vertically for every one in input + int i; + STBI_NOTUSED(hs); + for (i=0; i < w; ++i) + out[i] = stbi__div4(3*in_near[i] + in_far[i] + 2); + return out; +} + +static stbi_uc* stbi__resample_row_h_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + // need to generate two samples horizontally for every one in input + int i; + stbi_uc *input = in_near; + + if (w == 1) { + // if only one sample, can't do any interpolation + out[0] = out[1] = input[0]; + return out; + } + + out[0] = input[0]; + out[1] = stbi__div4(input[0]*3 + input[1] + 2); + for (i=1; i < w-1; ++i) { + int n = 3*input[i]+2; + out[i*2+0] = stbi__div4(n+input[i-1]); + out[i*2+1] = stbi__div4(n+input[i+1]); + } + out[i*2+0] = stbi__div4(input[w-2]*3 + input[w-1] + 2); + out[i*2+1] = input[w-1]; + + STBI_NOTUSED(in_far); + STBI_NOTUSED(hs); + + return out; +} + +#define stbi__div16(x) ((stbi_uc) ((x) >> 4)) + +static stbi_uc *stbi__resample_row_hv_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + // need to generate 2x2 samples for every one in input + int i,t0,t1; + if (w == 1) { + out[0] = out[1] = stbi__div4(3*in_near[0] + in_far[0] + 2); + return out; + } + + t1 = 3*in_near[0] + in_far[0]; + out[0] = stbi__div4(t1+2); + for (i=1; i < w; ++i) { + t0 = t1; + t1 = 3*in_near[i]+in_far[i]; + out[i*2-1] = stbi__div16(3*t0 + t1 + 8); + out[i*2 ] = stbi__div16(3*t1 + t0 + 8); + } + out[w*2-1] = stbi__div4(t1+2); + + STBI_NOTUSED(hs); + + return out; +} + +#if defined(STBI_SSE2) || defined(STBI_NEON) +static stbi_uc *stbi__resample_row_hv_2_simd(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + // need to generate 2x2 samples for every one in input + int i=0,t0,t1; + + if (w == 1) { + out[0] = out[1] = stbi__div4(3*in_near[0] + in_far[0] + 2); + return out; + } + + t1 = 3*in_near[0] + in_far[0]; + // process groups of 8 pixels for as long as we can. + // note we can't handle the last pixel in a row in this loop + // because we need to handle the filter boundary conditions. + for (; i < ((w-1) & ~7); i += 8) { +#if defined(STBI_SSE2) + // load and perform the vertical filtering pass + // this uses 3*x + y = 4*x + (y - x) + __m128i zero = _mm_setzero_si128(); + __m128i farb = _mm_loadl_epi64((__m128i *) (in_far + i)); + __m128i nearb = _mm_loadl_epi64((__m128i *) (in_near + i)); + __m128i farw = _mm_unpacklo_epi8(farb, zero); + __m128i nearw = _mm_unpacklo_epi8(nearb, zero); + __m128i diff = _mm_sub_epi16(farw, nearw); + __m128i nears = _mm_slli_epi16(nearw, 2); + __m128i curr = _mm_add_epi16(nears, diff); // current row + + // horizontal filter works the same based on shifted vers of current + // row. "prev" is current row shifted right by 1 pixel; we need to + // insert the previous pixel value (from t1). + // "next" is current row shifted left by 1 pixel, with first pixel + // of next block of 8 pixels added in. + __m128i prv0 = _mm_slli_si128(curr, 2); + __m128i nxt0 = _mm_srli_si128(curr, 2); + __m128i prev = _mm_insert_epi16(prv0, t1, 0); + __m128i next = _mm_insert_epi16(nxt0, 3*in_near[i+8] + in_far[i+8], 7); + + // horizontal filter, polyphase implementation since it's convenient: + // even pixels = 3*cur + prev = cur*4 + (prev - cur) + // odd pixels = 3*cur + next = cur*4 + (next - cur) + // note the shared term. + __m128i bias = _mm_set1_epi16(8); + __m128i curs = _mm_slli_epi16(curr, 2); + __m128i prvd = _mm_sub_epi16(prev, curr); + __m128i nxtd = _mm_sub_epi16(next, curr); + __m128i curb = _mm_add_epi16(curs, bias); + __m128i even = _mm_add_epi16(prvd, curb); + __m128i odd = _mm_add_epi16(nxtd, curb); + + // interleave even and odd pixels, then undo scaling. + __m128i int0 = _mm_unpacklo_epi16(even, odd); + __m128i int1 = _mm_unpackhi_epi16(even, odd); + __m128i de0 = _mm_srli_epi16(int0, 4); + __m128i de1 = _mm_srli_epi16(int1, 4); + + // pack and write output + __m128i outv = _mm_packus_epi16(de0, de1); + _mm_storeu_si128((__m128i *) (out + i*2), outv); +#elif defined(STBI_NEON) + // load and perform the vertical filtering pass + // this uses 3*x + y = 4*x + (y - x) + uint8x8_t farb = vld1_u8(in_far + i); + uint8x8_t nearb = vld1_u8(in_near + i); + int16x8_t diff = vreinterpretq_s16_u16(vsubl_u8(farb, nearb)); + int16x8_t nears = vreinterpretq_s16_u16(vshll_n_u8(nearb, 2)); + int16x8_t curr = vaddq_s16(nears, diff); // current row + + // horizontal filter works the same based on shifted vers of current + // row. "prev" is current row shifted right by 1 pixel; we need to + // insert the previous pixel value (from t1). + // "next" is current row shifted left by 1 pixel, with first pixel + // of next block of 8 pixels added in. + int16x8_t prv0 = vextq_s16(curr, curr, 7); + int16x8_t nxt0 = vextq_s16(curr, curr, 1); + int16x8_t prev = vsetq_lane_s16(t1, prv0, 0); + int16x8_t next = vsetq_lane_s16(3*in_near[i+8] + in_far[i+8], nxt0, 7); + + // horizontal filter, polyphase implementation since it's convenient: + // even pixels = 3*cur + prev = cur*4 + (prev - cur) + // odd pixels = 3*cur + next = cur*4 + (next - cur) + // note the shared term. + int16x8_t curs = vshlq_n_s16(curr, 2); + int16x8_t prvd = vsubq_s16(prev, curr); + int16x8_t nxtd = vsubq_s16(next, curr); + int16x8_t even = vaddq_s16(curs, prvd); + int16x8_t odd = vaddq_s16(curs, nxtd); + + // undo scaling and round, then store with even/odd phases interleaved + uint8x8x2_t o; + o.val[0] = vqrshrun_n_s16(even, 4); + o.val[1] = vqrshrun_n_s16(odd, 4); + vst2_u8(out + i*2, o); +#endif + + // "previous" value for next iter + t1 = 3*in_near[i+7] + in_far[i+7]; + } + + t0 = t1; + t1 = 3*in_near[i] + in_far[i]; + out[i*2] = stbi__div16(3*t1 + t0 + 8); + + for (++i; i < w; ++i) { + t0 = t1; + t1 = 3*in_near[i]+in_far[i]; + out[i*2-1] = stbi__div16(3*t0 + t1 + 8); + out[i*2 ] = stbi__div16(3*t1 + t0 + 8); + } + out[w*2-1] = stbi__div4(t1+2); + + STBI_NOTUSED(hs); + + return out; +} +#endif + +static stbi_uc *stbi__resample_row_generic(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + // resample with nearest-neighbor + int i,j; + STBI_NOTUSED(in_far); + for (i=0; i < w; ++i) + for (j=0; j < hs; ++j) + out[i*hs+j] = in_near[i]; + return out; +} + +#ifdef STBI_JPEG_OLD +// this is the same YCbCr-to-RGB calculation that stb_image has used +// historically before the algorithm changes in 1.49 +#define float2fixed(x) ((int) ((x) * 65536 + 0.5)) +static void stbi__YCbCr_to_RGB_row(stbi_uc *out, const stbi_uc *y, const stbi_uc *pcb, const stbi_uc *pcr, int count, int step) +{ + int i; + for (i=0; i < count; ++i) { + int y_fixed = (y[i] << 16) + 32768; // rounding + int r,g,b; + int cr = pcr[i] - 128; + int cb = pcb[i] - 128; + r = y_fixed + cr*float2fixed(1.40200f); + g = y_fixed - cr*float2fixed(0.71414f) - cb*float2fixed(0.34414f); + b = y_fixed + cb*float2fixed(1.77200f); + r >>= 16; + g >>= 16; + b >>= 16; + if ((unsigned) r > 255) { if (r < 0) r = 0; else r = 255; } + if ((unsigned) g > 255) { if (g < 0) g = 0; else g = 255; } + if ((unsigned) b > 255) { if (b < 0) b = 0; else b = 255; } + out[0] = (stbi_uc)r; + out[1] = (stbi_uc)g; + out[2] = (stbi_uc)b; + out[3] = 255; + out += step; + } +} +#else +// this is a reduced-precision calculation of YCbCr-to-RGB introduced +// to make sure the code produces the same results in both SIMD and scalar +#define float2fixed(x) (((int) ((x) * 4096.0f + 0.5f)) << 8) +static void stbi__YCbCr_to_RGB_row(stbi_uc *out, const stbi_uc *y, const stbi_uc *pcb, const stbi_uc *pcr, int count, int step) +{ + int i; + for (i=0; i < count; ++i) { + int y_fixed = (y[i] << 20) + (1<<19); // rounding + int r,g,b; + int cr = pcr[i] - 128; + int cb = pcb[i] - 128; + r = y_fixed + cr* float2fixed(1.40200f); + g = y_fixed + (cr*-float2fixed(0.71414f)) + ((cb*-float2fixed(0.34414f)) & 0xffff0000); + b = y_fixed + cb* float2fixed(1.77200f); + r >>= 20; + g >>= 20; + b >>= 20; + if ((unsigned) r > 255) { if (r < 0) r = 0; else r = 255; } + if ((unsigned) g > 255) { if (g < 0) g = 0; else g = 255; } + if ((unsigned) b > 255) { if (b < 0) b = 0; else b = 255; } + out[0] = (stbi_uc)r; + out[1] = (stbi_uc)g; + out[2] = (stbi_uc)b; + out[3] = 255; + out += step; + } +} +#endif + +#if defined(STBI_SSE2) || defined(STBI_NEON) +static void stbi__YCbCr_to_RGB_simd(stbi_uc *out, stbi_uc const *y, stbi_uc const *pcb, stbi_uc const *pcr, int count, int step) +{ + int i = 0; + +#ifdef STBI_SSE2 + // step == 3 is pretty ugly on the final interleave, and i'm not convinced + // it's useful in practice (you wouldn't use it for textures, for example). + // so just accelerate step == 4 case. + if (step == 4) { + // this is a fairly straightforward implementation and not super-optimized. + __m128i signflip = _mm_set1_epi8(-0x80); + __m128i cr_const0 = _mm_set1_epi16( (short) ( 1.40200f*4096.0f+0.5f)); + __m128i cr_const1 = _mm_set1_epi16( - (short) ( 0.71414f*4096.0f+0.5f)); + __m128i cb_const0 = _mm_set1_epi16( - (short) ( 0.34414f*4096.0f+0.5f)); + __m128i cb_const1 = _mm_set1_epi16( (short) ( 1.77200f*4096.0f+0.5f)); + __m128i y_bias = _mm_set1_epi8((char) (unsigned char) 128); + __m128i xw = _mm_set1_epi16(255); // alpha channel + + for (; i+7 < count; i += 8) { + // load + __m128i y_bytes = _mm_loadl_epi64((__m128i *) (y+i)); + __m128i cr_bytes = _mm_loadl_epi64((__m128i *) (pcr+i)); + __m128i cb_bytes = _mm_loadl_epi64((__m128i *) (pcb+i)); + __m128i cr_biased = _mm_xor_si128(cr_bytes, signflip); // -128 + __m128i cb_biased = _mm_xor_si128(cb_bytes, signflip); // -128 + + // unpack to short (and left-shift cr, cb by 8) + __m128i yw = _mm_unpacklo_epi8(y_bias, y_bytes); + __m128i crw = _mm_unpacklo_epi8(_mm_setzero_si128(), cr_biased); + __m128i cbw = _mm_unpacklo_epi8(_mm_setzero_si128(), cb_biased); + + // color transform + __m128i yws = _mm_srli_epi16(yw, 4); + __m128i cr0 = _mm_mulhi_epi16(cr_const0, crw); + __m128i cb0 = _mm_mulhi_epi16(cb_const0, cbw); + __m128i cb1 = _mm_mulhi_epi16(cbw, cb_const1); + __m128i cr1 = _mm_mulhi_epi16(crw, cr_const1); + __m128i rws = _mm_add_epi16(cr0, yws); + __m128i gwt = _mm_add_epi16(cb0, yws); + __m128i bws = _mm_add_epi16(yws, cb1); + __m128i gws = _mm_add_epi16(gwt, cr1); + + // descale + __m128i rw = _mm_srai_epi16(rws, 4); + __m128i bw = _mm_srai_epi16(bws, 4); + __m128i gw = _mm_srai_epi16(gws, 4); + + // back to byte, set up for transpose + __m128i brb = _mm_packus_epi16(rw, bw); + __m128i gxb = _mm_packus_epi16(gw, xw); + + // transpose to interleave channels + __m128i t0 = _mm_unpacklo_epi8(brb, gxb); + __m128i t1 = _mm_unpackhi_epi8(brb, gxb); + __m128i o0 = _mm_unpacklo_epi16(t0, t1); + __m128i o1 = _mm_unpackhi_epi16(t0, t1); + + // store + _mm_storeu_si128((__m128i *) (out + 0), o0); + _mm_storeu_si128((__m128i *) (out + 16), o1); + out += 32; + } + } +#endif + +#ifdef STBI_NEON + // in this version, step=3 support would be easy to add. but is there demand? + if (step == 4) { + // this is a fairly straightforward implementation and not super-optimized. + uint8x8_t signflip = vdup_n_u8(0x80); + int16x8_t cr_const0 = vdupq_n_s16( (short) ( 1.40200f*4096.0f+0.5f)); + int16x8_t cr_const1 = vdupq_n_s16( - (short) ( 0.71414f*4096.0f+0.5f)); + int16x8_t cb_const0 = vdupq_n_s16( - (short) ( 0.34414f*4096.0f+0.5f)); + int16x8_t cb_const1 = vdupq_n_s16( (short) ( 1.77200f*4096.0f+0.5f)); + + for (; i+7 < count; i += 8) { + // load + uint8x8_t y_bytes = vld1_u8(y + i); + uint8x8_t cr_bytes = vld1_u8(pcr + i); + uint8x8_t cb_bytes = vld1_u8(pcb + i); + int8x8_t cr_biased = vreinterpret_s8_u8(vsub_u8(cr_bytes, signflip)); + int8x8_t cb_biased = vreinterpret_s8_u8(vsub_u8(cb_bytes, signflip)); + + // expand to s16 + int16x8_t yws = vreinterpretq_s16_u16(vshll_n_u8(y_bytes, 4)); + int16x8_t crw = vshll_n_s8(cr_biased, 7); + int16x8_t cbw = vshll_n_s8(cb_biased, 7); + + // color transform + int16x8_t cr0 = vqdmulhq_s16(crw, cr_const0); + int16x8_t cb0 = vqdmulhq_s16(cbw, cb_const0); + int16x8_t cr1 = vqdmulhq_s16(crw, cr_const1); + int16x8_t cb1 = vqdmulhq_s16(cbw, cb_const1); + int16x8_t rws = vaddq_s16(yws, cr0); + int16x8_t gws = vaddq_s16(vaddq_s16(yws, cb0), cr1); + int16x8_t bws = vaddq_s16(yws, cb1); + + // undo scaling, round, convert to byte + uint8x8x4_t o; + o.val[0] = vqrshrun_n_s16(rws, 4); + o.val[1] = vqrshrun_n_s16(gws, 4); + o.val[2] = vqrshrun_n_s16(bws, 4); + o.val[3] = vdup_n_u8(255); + + // store, interleaving r/g/b/a + vst4_u8(out, o); + out += 8*4; + } + } +#endif + + for (; i < count; ++i) { + int y_fixed = (y[i] << 20) + (1<<19); // rounding + int r,g,b; + int cr = pcr[i] - 128; + int cb = pcb[i] - 128; + r = y_fixed + cr* float2fixed(1.40200f); + g = y_fixed + cr*-float2fixed(0.71414f) + ((cb*-float2fixed(0.34414f)) & 0xffff0000); + b = y_fixed + cb* float2fixed(1.77200f); + r >>= 20; + g >>= 20; + b >>= 20; + if ((unsigned) r > 255) { if (r < 0) r = 0; else r = 255; } + if ((unsigned) g > 255) { if (g < 0) g = 0; else g = 255; } + if ((unsigned) b > 255) { if (b < 0) b = 0; else b = 255; } + out[0] = (stbi_uc)r; + out[1] = (stbi_uc)g; + out[2] = (stbi_uc)b; + out[3] = 255; + out += step; + } +} +#endif + +// set up the kernels +static void stbi__setup_jpeg(stbi__jpeg *j) +{ + j->idct_block_kernel = stbi__idct_block; + j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_row; + j->resample_row_hv_2_kernel = stbi__resample_row_hv_2; + +#ifdef STBI_SSE2 + if (stbi__sse2_available()) { + j->idct_block_kernel = stbi__idct_simd; + #ifndef STBI_JPEG_OLD + j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_simd; + #endif + j->resample_row_hv_2_kernel = stbi__resample_row_hv_2_simd; + } +#endif + +#ifdef STBI_NEON + j->idct_block_kernel = stbi__idct_simd; + #ifndef STBI_JPEG_OLD + j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_simd; + #endif + j->resample_row_hv_2_kernel = stbi__resample_row_hv_2_simd; +#endif +} + +// clean up the temporary component buffers +static void stbi__cleanup_jpeg(stbi__jpeg *j) +{ + int i; + for (i=0; i < j->s->img_n; ++i) { + if (j->img_comp[i].raw_data) { + STBI_FREE(j->img_comp[i].raw_data); + j->img_comp[i].raw_data = NULL; + j->img_comp[i].data = NULL; + } + if (j->img_comp[i].raw_coeff) { + STBI_FREE(j->img_comp[i].raw_coeff); + j->img_comp[i].raw_coeff = 0; + j->img_comp[i].coeff = 0; + } + if (j->img_comp[i].linebuf) { + STBI_FREE(j->img_comp[i].linebuf); + j->img_comp[i].linebuf = NULL; + } + } +} + +typedef struct +{ + resample_row_func resample; + stbi_uc *line0,*line1; + int hs,vs; // expansion factor in each axis + int w_lores; // horizontal pixels pre-expansion + int ystep; // how far through vertical expansion we are + int ypos; // which pre-expansion row we're on +} stbi__resample; + +static stbi_uc *load_jpeg_image(stbi__jpeg *z, int *out_x, int *out_y, int *comp, int req_comp) +{ + int n, decode_n; + z->s->img_n = 0; // make stbi__cleanup_jpeg safe + + // validate req_comp + if (req_comp < 0 || req_comp > 4) return stbi__errpuc("bad req_comp", "Internal error"); + + // load a jpeg image from whichever source, but leave in YCbCr format + if (!stbi__decode_jpeg_image(z)) { stbi__cleanup_jpeg(z); return NULL; } + + // determine actual number of components to generate + n = req_comp ? req_comp : z->s->img_n; + + if (z->s->img_n == 3 && n < 3) + decode_n = 1; + else + decode_n = z->s->img_n; + + // resample and color-convert + { + int k; + unsigned int i,j; + stbi_uc *output; + stbi_uc *coutput[4]; + + stbi__resample res_comp[4]; + + for (k=0; k < decode_n; ++k) { + stbi__resample *r = &res_comp[k]; + + // allocate line buffer big enough for upsampling off the edges + // with upsample factor of 4 + z->img_comp[k].linebuf = (stbi_uc *) stbi__malloc(z->s->img_x + 3); + if (!z->img_comp[k].linebuf) { stbi__cleanup_jpeg(z); return stbi__errpuc("outofmem", "Out of memory"); } + + r->hs = z->img_h_max / z->img_comp[k].h; + r->vs = z->img_v_max / z->img_comp[k].v; + r->ystep = r->vs >> 1; + r->w_lores = (z->s->img_x + r->hs-1) / r->hs; + r->ypos = 0; + r->line0 = r->line1 = z->img_comp[k].data; + + if (r->hs == 1 && r->vs == 1) r->resample = resample_row_1; + else if (r->hs == 1 && r->vs == 2) r->resample = stbi__resample_row_v_2; + else if (r->hs == 2 && r->vs == 1) r->resample = stbi__resample_row_h_2; + else if (r->hs == 2 && r->vs == 2) r->resample = z->resample_row_hv_2_kernel; + else r->resample = stbi__resample_row_generic; + } + + // can't error after this so, this is safe + output = (stbi_uc *) stbi__malloc(n * z->s->img_x * z->s->img_y + 1); + if (!output) { stbi__cleanup_jpeg(z); return stbi__errpuc("outofmem", "Out of memory"); } + + // now go ahead and resample + for (j=0; j < z->s->img_y; ++j) { + stbi_uc *out = output + n * z->s->img_x * j; + for (k=0; k < decode_n; ++k) { + stbi__resample *r = &res_comp[k]; + int y_bot = r->ystep >= (r->vs >> 1); + coutput[k] = r->resample(z->img_comp[k].linebuf, + y_bot ? r->line1 : r->line0, + y_bot ? r->line0 : r->line1, + r->w_lores, r->hs); + if (++r->ystep >= r->vs) { + r->ystep = 0; + r->line0 = r->line1; + if (++r->ypos < z->img_comp[k].y) + r->line1 += z->img_comp[k].w2; + } + } + if (n >= 3) { + stbi_uc *y = coutput[0]; + if (z->s->img_n == 3) { + z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n); + } else + for (i=0; i < z->s->img_x; ++i) { + out[0] = out[1] = out[2] = y[i]; + out[3] = 255; // not used if n==3 + out += n; + } + } else { + stbi_uc *y = coutput[0]; + if (n == 1) + for (i=0; i < z->s->img_x; ++i) out[i] = y[i]; + else + for (i=0; i < z->s->img_x; ++i) *out++ = y[i], *out++ = 255; + } + } + stbi__cleanup_jpeg(z); + *out_x = z->s->img_x; + *out_y = z->s->img_y; + if (comp) *comp = z->s->img_n; // report original components, not output + return output; + } +} + +static unsigned char * STBI_FORCE_STACK_ALIGN stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int req_comp) +{ + stbi__jpeg j; + j.s = s; + stbi__setup_jpeg(&j); + return load_jpeg_image(&j, x,y,comp,req_comp); +} + +static int stbi__jpeg_test(stbi__context *s) +{ + int r; + stbi__jpeg j; + j.s = s; + stbi__setup_jpeg(&j); + r = stbi__decode_jpeg_header(&j, STBI__SCAN_type); + stbi__rewind(s); + return r; +} + +static int stbi__jpeg_info_raw(stbi__jpeg *j, int *x, int *y, int *comp) +{ + if (!stbi__decode_jpeg_header(j, STBI__SCAN_header)) { + stbi__rewind( j->s ); + return 0; + } + if (x) *x = j->s->img_x; + if (y) *y = j->s->img_y; + if (comp) *comp = j->s->img_n; + return 1; +} + +static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp) +{ + stbi__jpeg j; + j.s = s; + return stbi__jpeg_info_raw(&j, x, y, comp); +} +#endif + +// public domain zlib decode v0.2 Sean Barrett 2006-11-18 +// simple implementation +// - all input must be provided in an upfront buffer +// - all output is written to a single output buffer (can malloc/realloc) +// performance +// - fast huffman + +#ifndef STBI_NO_ZLIB + +// fast-way is faster to check than jpeg huffman, but slow way is slower +#define STBI__ZFAST_BITS 9 // accelerate all cases in default tables +#define STBI__ZFAST_MASK ((1 << STBI__ZFAST_BITS) - 1) + +// zlib-style huffman encoding +// (jpegs packs from left, zlib from right, so can't share code) +typedef struct +{ + stbi__uint16 fast[1 << STBI__ZFAST_BITS]; + stbi__uint16 firstcode[16]; + int maxcode[17]; + stbi__uint16 firstsymbol[16]; + stbi_uc size[288]; + stbi__uint16 value[288]; +} stbi__zhuffman; + +stbi_inline static int stbi__bitreverse16(int n) +{ + n = ((n & 0xAAAA) >> 1) | ((n & 0x5555) << 1); + n = ((n & 0xCCCC) >> 2) | ((n & 0x3333) << 2); + n = ((n & 0xF0F0) >> 4) | ((n & 0x0F0F) << 4); + n = ((n & 0xFF00) >> 8) | ((n & 0x00FF) << 8); + return n; +} + +stbi_inline static int stbi__bit_reverse(int v, int bits) +{ + STBI_ASSERT(bits <= 16); + // to bit reverse n bits, reverse 16 and shift + // e.g. 11 bits, bit reverse and shift away 5 + return stbi__bitreverse16(v) >> (16-bits); +} + +static int stbi__zbuild_huffman(stbi__zhuffman *z, stbi_uc *sizelist, int num) +{ + int i,k=0; + int code, next_code[16], sizes[17]; + + // DEFLATE spec for generating codes + memset(sizes, 0, sizeof(sizes)); + memset(z->fast, 0, sizeof(z->fast)); + for (i=0; i < num; ++i) + ++sizes[sizelist[i]]; + sizes[0] = 0; + for (i=1; i < 16; ++i) + if (sizes[i] > (1 << i)) + return stbi__err("bad sizes", "Corrupt PNG"); + code = 0; + for (i=1; i < 16; ++i) { + next_code[i] = code; + z->firstcode[i] = (stbi__uint16) code; + z->firstsymbol[i] = (stbi__uint16) k; + code = (code + sizes[i]); + if (sizes[i]) + if (code-1 >= (1 << i)) return stbi__err("bad codelengths","Corrupt PNG"); + z->maxcode[i] = code << (16-i); // preshift for inner loop + code <<= 1; + k += sizes[i]; + } + z->maxcode[16] = 0x10000; // sentinel + for (i=0; i < num; ++i) { + int s = sizelist[i]; + if (s) { + int c = next_code[s] - z->firstcode[s] + z->firstsymbol[s]; + stbi__uint16 fastv = (stbi__uint16) ((s << 9) | i); + z->size [c] = (stbi_uc ) s; + z->value[c] = (stbi__uint16) i; + if (s <= STBI__ZFAST_BITS) { + int j = stbi__bit_reverse(next_code[s],s); + while (j < (1 << STBI__ZFAST_BITS)) { + z->fast[j] = fastv; + j += (1 << s); + } + } + ++next_code[s]; + } + } + return 1; +} + +// zlib-from-memory implementation for PNG reading +// because PNG allows splitting the zlib stream arbitrarily, +// and it's annoying structurally to have PNG call ZLIB call PNG, +// we require PNG read all the IDATs and combine them into a single +// memory buffer + +typedef struct +{ + stbi_uc *zbuffer, *zbuffer_end; + int num_bits; + stbi__uint32 code_buffer; + + char *zout; + char *zout_start; + char *zout_end; + int z_expandable; + + stbi__zhuffman z_length, z_distance; +} stbi__zbuf; + +stbi_inline static stbi_uc stbi__zget8(stbi__zbuf *z) +{ + if (z->zbuffer >= z->zbuffer_end) return 0; + return *z->zbuffer++; +} + +static void stbi__fill_bits(stbi__zbuf *z) +{ + do { + STBI_ASSERT(z->code_buffer < (1U << z->num_bits)); + z->code_buffer |= (unsigned int) stbi__zget8(z) << z->num_bits; + z->num_bits += 8; + } while (z->num_bits <= 24); +} + +stbi_inline static unsigned int stbi__zreceive(stbi__zbuf *z, int n) +{ + unsigned int k; + if (z->num_bits < n) stbi__fill_bits(z); + k = z->code_buffer & ((1 << n) - 1); + z->code_buffer >>= n; + z->num_bits -= n; + return k; +} + +static int stbi__zhuffman_decode_slowpath(stbi__zbuf *a, stbi__zhuffman *z) +{ + int b,s,k; + // not resolved by fast table, so compute it the slow way + // use jpeg approach, which requires MSbits at top + k = stbi__bit_reverse(a->code_buffer, 16); + for (s=STBI__ZFAST_BITS+1; ; ++s) + if (k < z->maxcode[s]) + break; + if (s == 16) return -1; // invalid code! + // code size is s, so: + b = (k >> (16-s)) - z->firstcode[s] + z->firstsymbol[s]; + STBI_ASSERT(z->size[b] == s); + a->code_buffer >>= s; + a->num_bits -= s; + return z->value[b]; +} + +stbi_inline static int stbi__zhuffman_decode(stbi__zbuf *a, stbi__zhuffman *z) +{ + int b,s; + if (a->num_bits < 16) stbi__fill_bits(a); + b = z->fast[a->code_buffer & STBI__ZFAST_MASK]; + if (b) { + s = b >> 9; + a->code_buffer >>= s; + a->num_bits -= s; + return b & 511; + } + return stbi__zhuffman_decode_slowpath(a, z); +} + +static int stbi__zexpand(stbi__zbuf *z, char *zout, int n) // need to make room for n bytes +{ + char *q; + int cur, limit; + z->zout = zout; + if (!z->z_expandable) return stbi__err("output buffer limit","Corrupt PNG"); + cur = (int) (z->zout - z->zout_start); + limit = (int) (z->zout_end - z->zout_start); + while (cur + n > limit) + limit *= 2; + q = (char *) STBI_REALLOC(z->zout_start, limit); + if (q == NULL) return stbi__err("outofmem", "Out of memory"); + z->zout_start = q; + z->zout = q + cur; + z->zout_end = q + limit; + return 1; +} + +static int stbi__zlength_base[31] = { + 3,4,5,6,7,8,9,10,11,13, + 15,17,19,23,27,31,35,43,51,59, + 67,83,99,115,131,163,195,227,258,0,0 }; + +static int stbi__zlength_extra[31]= +{ 0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0 }; + +static int stbi__zdist_base[32] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193, +257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,0,0}; + +static int stbi__zdist_extra[32] = +{ 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; + +static int stbi__parse_huffman_block(stbi__zbuf *a) +{ + char *zout = a->zout; + for(;;) { + int z = stbi__zhuffman_decode(a, &a->z_length); + if (z < 256) { + if (z < 0) return stbi__err("bad huffman code","Corrupt PNG"); // error in huffman codes + if (zout >= a->zout_end) { + if (!stbi__zexpand(a, zout, 1)) return 0; + zout = a->zout; + } + *zout++ = (char) z; + } else { + stbi_uc *p; + int len,dist; + if (z == 256) { + a->zout = zout; + return 1; + } + z -= 257; + len = stbi__zlength_base[z]; + if (stbi__zlength_extra[z]) len += stbi__zreceive(a, stbi__zlength_extra[z]); + z = stbi__zhuffman_decode(a, &a->z_distance); + if (z < 0) return stbi__err("bad huffman code","Corrupt PNG"); + dist = stbi__zdist_base[z]; + if (stbi__zdist_extra[z]) dist += stbi__zreceive(a, stbi__zdist_extra[z]); + if (zout - a->zout_start < dist) return stbi__err("bad dist","Corrupt PNG"); + if (zout + len > a->zout_end) { + if (!stbi__zexpand(a, zout, len)) return 0; + zout = a->zout; + } + p = (stbi_uc *) (zout - dist); + if (dist == 1) { // run of one byte; common in images. + stbi_uc v = *p; + if (len) { do *zout++ = v; while (--len); } + } else { + if (len) { do *zout++ = *p++; while (--len); } + } + } + } +} + +static int stbi__compute_huffman_codes(stbi__zbuf *a) +{ + static stbi_uc length_dezigzag[19] = { 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 }; + stbi__zhuffman z_codelength; + stbi_uc lencodes[286+32+137];//padding for maximum single op + stbi_uc codelength_sizes[19]; + int i,n; + + int hlit = stbi__zreceive(a,5) + 257; + int hdist = stbi__zreceive(a,5) + 1; + int hclen = stbi__zreceive(a,4) + 4; + + memset(codelength_sizes, 0, sizeof(codelength_sizes)); + for (i=0; i < hclen; ++i) { + int s = stbi__zreceive(a,3); + codelength_sizes[length_dezigzag[i]] = (stbi_uc) s; + } + if (!stbi__zbuild_huffman(&z_codelength, codelength_sizes, 19)) return 0; + + n = 0; + while (n < hlit + hdist) { + int c = stbi__zhuffman_decode(a, &z_codelength); + if (c < 0 || c >= 19) return stbi__err("bad codelengths", "Corrupt PNG"); + if (c < 16) + lencodes[n++] = (stbi_uc) c; + else if (c == 16) { + c = stbi__zreceive(a,2)+3; + memset(lencodes+n, lencodes[n-1], c); + n += c; + } else if (c == 17) { + c = stbi__zreceive(a,3)+3; + memset(lencodes+n, 0, c); + n += c; + } else { + STBI_ASSERT(c == 18); + c = stbi__zreceive(a,7)+11; + memset(lencodes+n, 0, c); + n += c; + } + } + if (n != hlit+hdist) return stbi__err("bad codelengths","Corrupt PNG"); + if (!stbi__zbuild_huffman(&a->z_length, lencodes, hlit)) return 0; + if (!stbi__zbuild_huffman(&a->z_distance, lencodes+hlit, hdist)) return 0; + return 1; +} + +static int stbi__parse_uncomperssed_block(stbi__zbuf *a) +{ + stbi_uc header[4]; + int len,nlen,k; + if (a->num_bits & 7) + stbi__zreceive(a, a->num_bits & 7); // discard + // drain the bit-packed data into header + k = 0; + while (a->num_bits > 0) { + header[k++] = (stbi_uc) (a->code_buffer & 255); // suppress MSVC run-time check + a->code_buffer >>= 8; + a->num_bits -= 8; + } + STBI_ASSERT(a->num_bits == 0); + // now fill header the normal way + while (k < 4) + header[k++] = stbi__zget8(a); + len = header[1] * 256 + header[0]; + nlen = header[3] * 256 + header[2]; + if (nlen != (len ^ 0xffff)) return stbi__err("zlib corrupt","Corrupt PNG"); + if (a->zbuffer + len > a->zbuffer_end) return stbi__err("read past buffer","Corrupt PNG"); + if (a->zout + len > a->zout_end) + if (!stbi__zexpand(a, a->zout, len)) return 0; + memcpy(a->zout, a->zbuffer, len); + a->zbuffer += len; + a->zout += len; + return 1; +} + +static int stbi__parse_zlib_header(stbi__zbuf *a) +{ + int cmf = stbi__zget8(a); + int cm = cmf & 15; + /* int cinfo = cmf >> 4; */ + int flg = stbi__zget8(a); + if ((cmf*256+flg) % 31 != 0) return stbi__err("bad zlib header","Corrupt PNG"); // zlib spec + if (flg & 32) return stbi__err("no preset dict","Corrupt PNG"); // preset dictionary not allowed in png + if (cm != 8) return stbi__err("bad compression","Corrupt PNG"); // DEFLATE required for png + // window = 1 << (8 + cinfo)... but who cares, we fully buffer output + return 1; +} + +// @TODO: should statically initialize these for optimal thread safety +static stbi_uc stbi__zdefault_length[288], stbi__zdefault_distance[32]; +static void stbi__init_zdefaults(void) +{ + int i; // use <= to match clearly with spec + for (i=0; i <= 143; ++i) stbi__zdefault_length[i] = 8; + for ( ; i <= 255; ++i) stbi__zdefault_length[i] = 9; + for ( ; i <= 279; ++i) stbi__zdefault_length[i] = 7; + for ( ; i <= 287; ++i) stbi__zdefault_length[i] = 8; + + for (i=0; i <= 31; ++i) stbi__zdefault_distance[i] = 5; +} + +static int stbi__parse_zlib(stbi__zbuf *a, int parse_header) +{ + int final, type; + if (parse_header) + if (!stbi__parse_zlib_header(a)) return 0; + a->num_bits = 0; + a->code_buffer = 0; + do { + final = stbi__zreceive(a,1); + type = stbi__zreceive(a,2); + if (type == 0) { + if (!stbi__parse_uncomperssed_block(a)) return 0; + } else if (type == 3) { + return 0; + } else { + if (type == 1) { + // use fixed code lengths + if (!stbi__zdefault_distance[31]) stbi__init_zdefaults(); + if (!stbi__zbuild_huffman(&a->z_length , stbi__zdefault_length , 288)) return 0; + if (!stbi__zbuild_huffman(&a->z_distance, stbi__zdefault_distance, 32)) return 0; + } else { + if (!stbi__compute_huffman_codes(a)) return 0; + } + if (!stbi__parse_huffman_block(a)) return 0; + } + } while (!final); + return 1; +} + +static int stbi__do_zlib(stbi__zbuf *a, char *obuf, int olen, int exp, int parse_header) +{ + a->zout_start = obuf; + a->zout = obuf; + a->zout_end = obuf + olen; + a->z_expandable = exp; + + return stbi__parse_zlib(a, parse_header); +} + +STBIDEF char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen) +{ + stbi__zbuf a; + char *p = (char *) stbi__malloc(initial_size); + if (p == NULL) return NULL; + a.zbuffer = (stbi_uc *) buffer; + a.zbuffer_end = (stbi_uc *) buffer + len; + if (stbi__do_zlib(&a, p, initial_size, 1, 1)) { + if (outlen) *outlen = (int) (a.zout - a.zout_start); + return a.zout_start; + } else { + STBI_FREE(a.zout_start); + return NULL; + } +} + +STBIDEF char *stbi_zlib_decode_malloc(char const *buffer, int len, int *outlen) +{ + return stbi_zlib_decode_malloc_guesssize(buffer, len, 16384, outlen); +} + +STBIDEF char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header) +{ + stbi__zbuf a; + char *p = (char *) stbi__malloc(initial_size); + if (p == NULL) return NULL; + a.zbuffer = (stbi_uc *) buffer; + a.zbuffer_end = (stbi_uc *) buffer + len; + if (stbi__do_zlib(&a, p, initial_size, 1, parse_header)) { + if (outlen) *outlen = (int) (a.zout - a.zout_start); + return a.zout_start; + } else { + STBI_FREE(a.zout_start); + return NULL; + } +} + +STBIDEF int stbi_zlib_decode_buffer(char *obuffer, int olen, char const *ibuffer, int ilen) +{ + stbi__zbuf a; + a.zbuffer = (stbi_uc *) ibuffer; + a.zbuffer_end = (stbi_uc *) ibuffer + ilen; + if (stbi__do_zlib(&a, obuffer, olen, 0, 1)) + return (int) (a.zout - a.zout_start); + else + return -1; +} + +STBIDEF char *stbi_zlib_decode_noheader_malloc(char const *buffer, int len, int *outlen) +{ + stbi__zbuf a; + char *p = (char *) stbi__malloc(16384); + if (p == NULL) return NULL; + a.zbuffer = (stbi_uc *) buffer; + a.zbuffer_end = (stbi_uc *) buffer+len; + if (stbi__do_zlib(&a, p, 16384, 1, 0)) { + if (outlen) *outlen = (int) (a.zout - a.zout_start); + return a.zout_start; + } else { + STBI_FREE(a.zout_start); + return NULL; + } +} + +STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen) +{ + stbi__zbuf a; + a.zbuffer = (stbi_uc *) ibuffer; + a.zbuffer_end = (stbi_uc *) ibuffer + ilen; + if (stbi__do_zlib(&a, obuffer, olen, 0, 0)) + return (int) (a.zout - a.zout_start); + else + return -1; +} +#endif + +// public domain "baseline" PNG decoder v0.10 Sean Barrett 2006-11-18 +// simple implementation +// - only 8-bit samples +// - no CRC checking +// - allocates lots of intermediate memory +// - avoids problem of streaming data between subsystems +// - avoids explicit window management +// performance +// - uses stb_zlib, a PD zlib implementation with fast huffman decoding + +#ifndef STBI_NO_PNG +typedef struct +{ + stbi__uint32 length; + stbi__uint32 type; +} stbi__pngchunk; + +static stbi__pngchunk stbi__get_chunk_header(stbi__context *s) +{ + stbi__pngchunk c; + c.length = stbi__get32be(s); + c.type = stbi__get32be(s); + return c; +} + +static int stbi__check_png_header(stbi__context *s) +{ + static stbi_uc png_sig[8] = { 137,80,78,71,13,10,26,10 }; + int i; + for (i=0; i < 8; ++i) + if (stbi__get8(s) != png_sig[i]) return stbi__err("bad png sig","Not a PNG"); + return 1; +} + +typedef struct +{ + stbi__context *s; + stbi_uc *idata, *expanded, *out; +} stbi__png; + + +enum { + STBI__F_none=0, + STBI__F_sub=1, + STBI__F_up=2, + STBI__F_avg=3, + STBI__F_paeth=4, + // synthetic filters used for first scanline to avoid needing a dummy row of 0s + STBI__F_avg_first, + STBI__F_paeth_first +}; + +static stbi_uc first_row_filter[5] = +{ + STBI__F_none, + STBI__F_sub, + STBI__F_none, + STBI__F_avg_first, + STBI__F_paeth_first +}; + +static int stbi__paeth(int a, int b, int c) +{ + int p = a + b - c; + int pa = abs(p-a); + int pb = abs(p-b); + int pc = abs(p-c); + if (pa <= pb && pa <= pc) return a; + if (pb <= pc) return b; + return c; +} + +static stbi_uc stbi__depth_scale_table[9] = { 0, 0xff, 0x55, 0, 0x11, 0,0,0, 0x01 }; + +// create the png data from post-deflated data +static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 raw_len, int out_n, stbi__uint32 x, stbi__uint32 y, int depth, int color) +{ + stbi__context *s = a->s; + stbi__uint32 i,j,stride = x*out_n; + stbi__uint32 img_len, img_width_bytes; + int k; + int img_n = s->img_n; // copy it into a local for later + + STBI_ASSERT(out_n == s->img_n || out_n == s->img_n+1); + a->out = (stbi_uc *) stbi__malloc(x * y * out_n); // extra bytes to write off the end into + if (!a->out) return stbi__err("outofmem", "Out of memory"); + + img_width_bytes = (((img_n * x * depth) + 7) >> 3); + img_len = (img_width_bytes + 1) * y; + if (s->img_x == x && s->img_y == y) { + if (raw_len != img_len) return stbi__err("not enough pixels","Corrupt PNG"); + } else { // interlaced: + if (raw_len < img_len) return stbi__err("not enough pixels","Corrupt PNG"); + } + + for (j=0; j < y; ++j) { + stbi_uc *cur = a->out + stride*j; + stbi_uc *prior = cur - stride; + int filter = *raw++; + int filter_bytes = img_n; + int width = x; + if (filter > 4) + return stbi__err("invalid filter","Corrupt PNG"); + + if (depth < 8) { + STBI_ASSERT(img_width_bytes <= x); + cur += x*out_n - img_width_bytes; // store output to the rightmost img_len bytes, so we can decode in place + filter_bytes = 1; + width = img_width_bytes; + } + + // if first row, use special filter that doesn't sample previous row + if (j == 0) filter = first_row_filter[filter]; + + // handle first byte explicitly + for (k=0; k < filter_bytes; ++k) { + switch (filter) { + case STBI__F_none : cur[k] = raw[k]; break; + case STBI__F_sub : cur[k] = raw[k]; break; + case STBI__F_up : cur[k] = STBI__BYTECAST(raw[k] + prior[k]); break; + case STBI__F_avg : cur[k] = STBI__BYTECAST(raw[k] + (prior[k]>>1)); break; + case STBI__F_paeth : cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(0,prior[k],0)); break; + case STBI__F_avg_first : cur[k] = raw[k]; break; + case STBI__F_paeth_first: cur[k] = raw[k]; break; + } + } + + if (depth == 8) { + if (img_n != out_n) + cur[img_n] = 255; // first pixel + raw += img_n; + cur += out_n; + prior += out_n; + } else { + raw += 1; + cur += 1; + prior += 1; + } + + // this is a little gross, so that we don't switch per-pixel or per-component + if (depth < 8 || img_n == out_n) { + int nk = (width - 1)*img_n; + #define CASE(f) \ + case f: \ + for (k=0; k < nk; ++k) + switch (filter) { + // "none" filter turns into a memcpy here; make that explicit. + case STBI__F_none: memcpy(cur, raw, nk); break; + CASE(STBI__F_sub) cur[k] = STBI__BYTECAST(raw[k] + cur[k-filter_bytes]); break; + CASE(STBI__F_up) cur[k] = STBI__BYTECAST(raw[k] + prior[k]); break; + CASE(STBI__F_avg) cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k-filter_bytes])>>1)); break; + CASE(STBI__F_paeth) cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],prior[k],prior[k-filter_bytes])); break; + CASE(STBI__F_avg_first) cur[k] = STBI__BYTECAST(raw[k] + (cur[k-filter_bytes] >> 1)); break; + CASE(STBI__F_paeth_first) cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],0,0)); break; + } + #undef CASE + raw += nk; + } else { + STBI_ASSERT(img_n+1 == out_n); + #define CASE(f) \ + case f: \ + for (i=x-1; i >= 1; --i, cur[img_n]=255,raw+=img_n,cur+=out_n,prior+=out_n) \ + for (k=0; k < img_n; ++k) + switch (filter) { + CASE(STBI__F_none) cur[k] = raw[k]; break; + CASE(STBI__F_sub) cur[k] = STBI__BYTECAST(raw[k] + cur[k-out_n]); break; + CASE(STBI__F_up) cur[k] = STBI__BYTECAST(raw[k] + prior[k]); break; + CASE(STBI__F_avg) cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k-out_n])>>1)); break; + CASE(STBI__F_paeth) cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-out_n],prior[k],prior[k-out_n])); break; + CASE(STBI__F_avg_first) cur[k] = STBI__BYTECAST(raw[k] + (cur[k-out_n] >> 1)); break; + CASE(STBI__F_paeth_first) cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-out_n],0,0)); break; + } + #undef CASE + } + } + + // we make a separate pass to expand bits to pixels; for performance, + // this could run two scanlines behind the above code, so it won't + // intefere with filtering but will still be in the cache. + if (depth < 8) { + for (j=0; j < y; ++j) { + stbi_uc *cur = a->out + stride*j; + stbi_uc *in = a->out + stride*j + x*out_n - img_width_bytes; + // unpack 1/2/4-bit into a 8-bit buffer. allows us to keep the common 8-bit path optimal at minimal cost for 1/2/4-bit + // png guarante byte alignment, if width is not multiple of 8/4/2 we'll decode dummy trailing data that will be skipped in the later loop + stbi_uc scale = (color == 0) ? stbi__depth_scale_table[depth] : 1; // scale grayscale values to 0..255 range + + // note that the final byte might overshoot and write more data than desired. + // we can allocate enough data that this never writes out of memory, but it + // could also overwrite the next scanline. can it overwrite non-empty data + // on the next scanline? yes, consider 1-pixel-wide scanlines with 1-bit-per-pixel. + // so we need to explicitly clamp the final ones + + if (depth == 4) { + for (k=x*img_n; k >= 2; k-=2, ++in) { + *cur++ = scale * ((*in >> 4) ); + *cur++ = scale * ((*in ) & 0x0f); + } + if (k > 0) *cur++ = scale * ((*in >> 4) ); + } else if (depth == 2) { + for (k=x*img_n; k >= 4; k-=4, ++in) { + *cur++ = scale * ((*in >> 6) ); + *cur++ = scale * ((*in >> 4) & 0x03); + *cur++ = scale * ((*in >> 2) & 0x03); + *cur++ = scale * ((*in ) & 0x03); + } + if (k > 0) *cur++ = scale * ((*in >> 6) ); + if (k > 1) *cur++ = scale * ((*in >> 4) & 0x03); + if (k > 2) *cur++ = scale * ((*in >> 2) & 0x03); + } else if (depth == 1) { + for (k=x*img_n; k >= 8; k-=8, ++in) { + *cur++ = scale * ((*in >> 7) ); + *cur++ = scale * ((*in >> 6) & 0x01); + *cur++ = scale * ((*in >> 5) & 0x01); + *cur++ = scale * ((*in >> 4) & 0x01); + *cur++ = scale * ((*in >> 3) & 0x01); + *cur++ = scale * ((*in >> 2) & 0x01); + *cur++ = scale * ((*in >> 1) & 0x01); + *cur++ = scale * ((*in ) & 0x01); + } + if (k > 0) *cur++ = scale * ((*in >> 7) ); + if (k > 1) *cur++ = scale * ((*in >> 6) & 0x01); + if (k > 2) *cur++ = scale * ((*in >> 5) & 0x01); + if (k > 3) *cur++ = scale * ((*in >> 4) & 0x01); + if (k > 4) *cur++ = scale * ((*in >> 3) & 0x01); + if (k > 5) *cur++ = scale * ((*in >> 2) & 0x01); + if (k > 6) *cur++ = scale * ((*in >> 1) & 0x01); + } + if (img_n != out_n) { + int q; + // insert alpha = 255 + cur = a->out + stride*j; + if (img_n == 1) { + for (q=x-1; q >= 0; --q) { + cur[q*2+1] = 255; + cur[q*2+0] = cur[q]; + } + } else { + STBI_ASSERT(img_n == 3); + for (q=x-1; q >= 0; --q) { + cur[q*4+3] = 255; + cur[q*4+2] = cur[q*3+2]; + cur[q*4+1] = cur[q*3+1]; + cur[q*4+0] = cur[q*3+0]; + } + } + } + } + } + + return 1; +} + +static int stbi__create_png_image(stbi__png *a, stbi_uc *image_data, stbi__uint32 image_data_len, int out_n, int depth, int color, int interlaced) +{ + stbi_uc *final; + int p; + if (!interlaced) + return stbi__create_png_image_raw(a, image_data, image_data_len, out_n, a->s->img_x, a->s->img_y, depth, color); + + // de-interlacing + final = (stbi_uc *) stbi__malloc(a->s->img_x * a->s->img_y * out_n); + for (p=0; p < 7; ++p) { + int xorig[] = { 0,4,0,2,0,1,0 }; + int yorig[] = { 0,0,4,0,2,0,1 }; + int xspc[] = { 8,8,4,4,2,2,1 }; + int yspc[] = { 8,8,8,4,4,2,2 }; + int i,j,x,y; + // pass1_x[4] = 0, pass1_x[5] = 1, pass1_x[12] = 1 + x = (a->s->img_x - xorig[p] + xspc[p]-1) / xspc[p]; + y = (a->s->img_y - yorig[p] + yspc[p]-1) / yspc[p]; + if (x && y) { + stbi__uint32 img_len = ((((a->s->img_n * x * depth) + 7) >> 3) + 1) * y; + if (!stbi__create_png_image_raw(a, image_data, image_data_len, out_n, x, y, depth, color)) { + STBI_FREE(final); + return 0; + } + for (j=0; j < y; ++j) { + for (i=0; i < x; ++i) { + int out_y = j*yspc[p]+yorig[p]; + int out_x = i*xspc[p]+xorig[p]; + memcpy(final + out_y*a->s->img_x*out_n + out_x*out_n, + a->out + (j*x+i)*out_n, out_n); + } + } + STBI_FREE(a->out); + image_data += img_len; + image_data_len -= img_len; + } + } + a->out = final; + + return 1; +} + +static int stbi__compute_transparency(stbi__png *z, stbi_uc tc[3], int out_n) +{ + stbi__context *s = z->s; + stbi__uint32 i, pixel_count = s->img_x * s->img_y; + stbi_uc *p = z->out; + + // compute color-based transparency, assuming we've + // already got 255 as the alpha value in the output + STBI_ASSERT(out_n == 2 || out_n == 4); + + if (out_n == 2) { + for (i=0; i < pixel_count; ++i) { + p[1] = (p[0] == tc[0] ? 0 : 255); + p += 2; + } + } else { + for (i=0; i < pixel_count; ++i) { + if (p[0] == tc[0] && p[1] == tc[1] && p[2] == tc[2]) + p[3] = 0; + p += 4; + } + } + return 1; +} + +static int stbi__expand_png_palette(stbi__png *a, stbi_uc *palette, int len, int pal_img_n) +{ + stbi__uint32 i, pixel_count = a->s->img_x * a->s->img_y; + stbi_uc *p, *temp_out, *orig = a->out; + + p = (stbi_uc *) stbi__malloc(pixel_count * pal_img_n); + if (p == NULL) return stbi__err("outofmem", "Out of memory"); + + // between here and free(out) below, exitting would leak + temp_out = p; + + if (pal_img_n == 3) { + for (i=0; i < pixel_count; ++i) { + int n = orig[i]*4; + p[0] = palette[n ]; + p[1] = palette[n+1]; + p[2] = palette[n+2]; + p += 3; + } + } else { + for (i=0; i < pixel_count; ++i) { + int n = orig[i]*4; + p[0] = palette[n ]; + p[1] = palette[n+1]; + p[2] = palette[n+2]; + p[3] = palette[n+3]; + p += 4; + } + } + STBI_FREE(a->out); + a->out = temp_out; + + STBI_NOTUSED(len); + + return 1; +} + +static int stbi__unpremultiply_on_load = 0; +static int stbi__de_iphone_flag = 0; + +STBIDEF void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply) +{ + stbi__unpremultiply_on_load = flag_true_if_should_unpremultiply; +} + +STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert) +{ + stbi__de_iphone_flag = flag_true_if_should_convert; +} + +static void stbi__de_iphone(stbi__png *z) +{ + stbi__context *s = z->s; + stbi__uint32 i, pixel_count = s->img_x * s->img_y; + stbi_uc *p = z->out; + + if (s->img_out_n == 3) { // convert bgr to rgb + for (i=0; i < pixel_count; ++i) { + stbi_uc t = p[0]; + p[0] = p[2]; + p[2] = t; + p += 3; + } + } else { + STBI_ASSERT(s->img_out_n == 4); + if (stbi__unpremultiply_on_load) { + // convert bgr to rgb and unpremultiply + for (i=0; i < pixel_count; ++i) { + stbi_uc a = p[3]; + stbi_uc t = p[0]; + if (a) { + p[0] = p[2] * 255 / a; + p[1] = p[1] * 255 / a; + p[2] = t * 255 / a; + } else { + p[0] = p[2]; + p[2] = t; + } + p += 4; + } + } else { + // convert bgr to rgb + for (i=0; i < pixel_count; ++i) { + stbi_uc t = p[0]; + p[0] = p[2]; + p[2] = t; + p += 4; + } + } + } +} + +#define STBI__PNG_TYPE(a,b,c,d) (((a) << 24) + ((b) << 16) + ((c) << 8) + (d)) + +static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp) +{ + stbi_uc palette[1024], pal_img_n=0; + stbi_uc has_trans=0, tc[3]; + stbi__uint32 ioff=0, idata_limit=0, i, pal_len=0; + int first=1,k,interlace=0, color=0, depth=0, is_iphone=0; + stbi__context *s = z->s; + + z->expanded = NULL; + z->idata = NULL; + z->out = NULL; + + if (!stbi__check_png_header(s)) return 0; + + if (scan == STBI__SCAN_type) return 1; + + for (;;) { + stbi__pngchunk c = stbi__get_chunk_header(s); + switch (c.type) { + case STBI__PNG_TYPE('C','g','B','I'): + is_iphone = 1; + stbi__skip(s, c.length); + break; + case STBI__PNG_TYPE('I','H','D','R'): { + int comp,filter; + if (!first) return stbi__err("multiple IHDR","Corrupt PNG"); + first = 0; + if (c.length != 13) return stbi__err("bad IHDR len","Corrupt PNG"); + s->img_x = stbi__get32be(s); if (s->img_x > (1 << 24)) return stbi__err("too large","Very large image (corrupt?)"); + s->img_y = stbi__get32be(s); if (s->img_y > (1 << 24)) return stbi__err("too large","Very large image (corrupt?)"); + depth = stbi__get8(s); if (depth != 1 && depth != 2 && depth != 4 && depth != 8) return stbi__err("1/2/4/8-bit only","PNG not supported: 1/2/4/8-bit only"); + color = stbi__get8(s); if (color > 6) return stbi__err("bad ctype","Corrupt PNG"); + if (color == 3) pal_img_n = 3; else if (color & 1) return stbi__err("bad ctype","Corrupt PNG"); + comp = stbi__get8(s); if (comp) return stbi__err("bad comp method","Corrupt PNG"); + filter= stbi__get8(s); if (filter) return stbi__err("bad filter method","Corrupt PNG"); + interlace = stbi__get8(s); if (interlace>1) return stbi__err("bad interlace method","Corrupt PNG"); + if (!s->img_x || !s->img_y) return stbi__err("0-pixel image","Corrupt PNG"); + if (!pal_img_n) { + s->img_n = (color & 2 ? 3 : 1) + (color & 4 ? 1 : 0); + if ((1 << 30) / s->img_x / s->img_n < s->img_y) return stbi__err("too large", "Image too large to decode"); + if (scan == STBI__SCAN_header) return 1; + } else { + // if paletted, then pal_n is our final components, and + // img_n is # components to decompress/filter. + s->img_n = 1; + if ((1 << 30) / s->img_x / 4 < s->img_y) return stbi__err("too large","Corrupt PNG"); + // if SCAN_header, have to scan to see if we have a tRNS + } + break; + } + + case STBI__PNG_TYPE('P','L','T','E'): { + if (first) return stbi__err("first not IHDR", "Corrupt PNG"); + if (c.length > 256*3) return stbi__err("invalid PLTE","Corrupt PNG"); + pal_len = c.length / 3; + if (pal_len * 3 != c.length) return stbi__err("invalid PLTE","Corrupt PNG"); + for (i=0; i < pal_len; ++i) { + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + } + break; + } + + case STBI__PNG_TYPE('t','R','N','S'): { + if (first) return stbi__err("first not IHDR", "Corrupt PNG"); + if (z->idata) return stbi__err("tRNS after IDAT","Corrupt PNG"); + if (pal_img_n) { + if (scan == STBI__SCAN_header) { s->img_n = 4; return 1; } + if (pal_len == 0) return stbi__err("tRNS before PLTE","Corrupt PNG"); + if (c.length > pal_len) return stbi__err("bad tRNS len","Corrupt PNG"); + pal_img_n = 4; + for (i=0; i < c.length; ++i) + palette[i*4+3] = stbi__get8(s); + } else { + if (!(s->img_n & 1)) return stbi__err("tRNS with alpha","Corrupt PNG"); + if (c.length != (stbi__uint32) s->img_n*2) return stbi__err("bad tRNS len","Corrupt PNG"); + has_trans = 1; + for (k=0; k < s->img_n; ++k) + tc[k] = (stbi_uc) (stbi__get16be(s) & 255) * stbi__depth_scale_table[depth]; // non 8-bit images will be larger + } + break; + } + + case STBI__PNG_TYPE('I','D','A','T'): { + if (first) return stbi__err("first not IHDR", "Corrupt PNG"); + if (pal_img_n && !pal_len) return stbi__err("no PLTE","Corrupt PNG"); + if (scan == STBI__SCAN_header) { s->img_n = pal_img_n; return 1; } + if ((int)(ioff + c.length) < (int)ioff) return 0; + if (ioff + c.length > idata_limit) { + stbi_uc *p; + if (idata_limit == 0) idata_limit = c.length > 4096 ? c.length : 4096; + while (ioff + c.length > idata_limit) + idata_limit *= 2; + p = (stbi_uc *) STBI_REALLOC(z->idata, idata_limit); if (p == NULL) return stbi__err("outofmem", "Out of memory"); + z->idata = p; + } + if (!stbi__getn(s, z->idata+ioff,c.length)) return stbi__err("outofdata","Corrupt PNG"); + ioff += c.length; + break; + } + + case STBI__PNG_TYPE('I','E','N','D'): { + stbi__uint32 raw_len, bpl; + if (first) return stbi__err("first not IHDR", "Corrupt PNG"); + if (scan != STBI__SCAN_load) return 1; + if (z->idata == NULL) return stbi__err("no IDAT","Corrupt PNG"); + // initial guess for decoded data size to avoid unnecessary reallocs + bpl = (s->img_x * depth + 7) / 8; // bytes per line, per component + raw_len = bpl * s->img_y * s->img_n /* pixels */ + s->img_y /* filter mode per row */; + z->expanded = (stbi_uc *) stbi_zlib_decode_malloc_guesssize_headerflag((char *) z->idata, ioff, raw_len, (int *) &raw_len, !is_iphone); + if (z->expanded == NULL) return 0; // zlib should set error + STBI_FREE(z->idata); z->idata = NULL; + if ((req_comp == s->img_n+1 && req_comp != 3 && !pal_img_n) || has_trans) + s->img_out_n = s->img_n+1; + else + s->img_out_n = s->img_n; + if (!stbi__create_png_image(z, z->expanded, raw_len, s->img_out_n, depth, color, interlace)) return 0; + if (has_trans) + if (!stbi__compute_transparency(z, tc, s->img_out_n)) return 0; + if (is_iphone && stbi__de_iphone_flag && s->img_out_n > 2) + stbi__de_iphone(z); + if (pal_img_n) { + // pal_img_n == 3 or 4 + s->img_n = pal_img_n; // record the actual colors we had + s->img_out_n = pal_img_n; + if (req_comp >= 3) s->img_out_n = req_comp; + if (!stbi__expand_png_palette(z, palette, pal_len, s->img_out_n)) + return 0; + } + STBI_FREE(z->expanded); z->expanded = NULL; + return 1; + } + + default: + // if critical, fail + if (first) return stbi__err("first not IHDR", "Corrupt PNG"); + if ((c.type & (1 << 29)) == 0) { + #ifndef STBI_NO_FAILURE_STRINGS + // not threadsafe + static char invalid_chunk[] = "XXXX PNG chunk not known"; + invalid_chunk[0] = STBI__BYTECAST(c.type >> 24); + invalid_chunk[1] = STBI__BYTECAST(c.type >> 16); + invalid_chunk[2] = STBI__BYTECAST(c.type >> 8); + invalid_chunk[3] = STBI__BYTECAST(c.type >> 0); + #endif + return stbi__err(invalid_chunk, "PNG not supported: unknown PNG chunk type"); + } + stbi__skip(s, c.length); + break; + } + // end of PNG chunk, read and skip CRC + stbi__get32be(s); + } +} + +static unsigned char *stbi__do_png(stbi__png *p, int *x, int *y, int *n, int req_comp) +{ + unsigned char *result=NULL; + if (req_comp < 0 || req_comp > 4) return stbi__errpuc("bad req_comp", "Internal error"); + if (stbi__parse_png_file(p, STBI__SCAN_load, req_comp)) { + result = p->out; + p->out = NULL; + if (req_comp && req_comp != p->s->img_out_n) { + result = stbi__convert_format(result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y); + p->s->img_out_n = req_comp; + if (result == NULL) return result; + } + *x = p->s->img_x; + *y = p->s->img_y; + if (n) *n = p->s->img_out_n; + } + STBI_FREE(p->out); p->out = NULL; + STBI_FREE(p->expanded); p->expanded = NULL; + STBI_FREE(p->idata); p->idata = NULL; + + return result; +} + +static unsigned char *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp) +{ + stbi__png p; + p.s = s; + return stbi__do_png(&p, x,y,comp,req_comp); +} + +static int stbi__png_test(stbi__context *s) +{ + int r; + r = stbi__check_png_header(s); + stbi__rewind(s); + return r; +} + +static int stbi__png_info_raw(stbi__png *p, int *x, int *y, int *comp) +{ + if (!stbi__parse_png_file(p, STBI__SCAN_header, 0)) { + stbi__rewind( p->s ); + return 0; + } + if (x) *x = p->s->img_x; + if (y) *y = p->s->img_y; + if (comp) *comp = p->s->img_n; + return 1; +} + +static int stbi__png_info(stbi__context *s, int *x, int *y, int *comp) +{ + stbi__png p; + p.s = s; + return stbi__png_info_raw(&p, x, y, comp); +} +#endif + +// Microsoft/Windows BMP image + +#ifndef STBI_NO_BMP +static int stbi__bmp_test_raw(stbi__context *s) +{ + int r; + int sz; + if (stbi__get8(s) != 'B') return 0; + if (stbi__get8(s) != 'M') return 0; + stbi__get32le(s); // discard filesize + stbi__get16le(s); // discard reserved + stbi__get16le(s); // discard reserved + stbi__get32le(s); // discard data offset + sz = stbi__get32le(s); + r = (sz == 12 || sz == 40 || sz == 56 || sz == 108 || sz == 124); + return r; +} + +static int stbi__bmp_test(stbi__context *s) +{ + int r = stbi__bmp_test_raw(s); + stbi__rewind(s); + return r; +} + + +// returns 0..31 for the highest set bit +static int stbi__high_bit(unsigned int z) +{ + int n=0; + if (z == 0) return -1; + if (z >= 0x10000) n += 16, z >>= 16; + if (z >= 0x00100) n += 8, z >>= 8; + if (z >= 0x00010) n += 4, z >>= 4; + if (z >= 0x00004) n += 2, z >>= 2; + if (z >= 0x00002) n += 1, z >>= 1; + return n; +} + +static int stbi__bitcount(unsigned int a) +{ + a = (a & 0x55555555) + ((a >> 1) & 0x55555555); // max 2 + a = (a & 0x33333333) + ((a >> 2) & 0x33333333); // max 4 + a = (a + (a >> 4)) & 0x0f0f0f0f; // max 8 per 4, now 8 bits + a = (a + (a >> 8)); // max 16 per 8 bits + a = (a + (a >> 16)); // max 32 per 8 bits + return a & 0xff; +} + +static int stbi__shiftsigned(int v, int shift, int bits) +{ + int result; + int z=0; + + if (shift < 0) v <<= -shift; + else v >>= shift; + result = v; + + z = bits; + while (z < 8) { + result += v >> z; + z += bits; + } + return result; +} + +static stbi_uc *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp) +{ + stbi_uc *out; + unsigned int mr=0,mg=0,mb=0,ma=0, all_a=255; + stbi_uc pal[256][4]; + int psize=0,i,j,compress=0,width; + int bpp, flip_vertically, pad, target, offset, hsz; + if (stbi__get8(s) != 'B' || stbi__get8(s) != 'M') return stbi__errpuc("not BMP", "Corrupt BMP"); + stbi__get32le(s); // discard filesize + stbi__get16le(s); // discard reserved + stbi__get16le(s); // discard reserved + offset = stbi__get32le(s); + hsz = stbi__get32le(s); + if (hsz != 12 && hsz != 40 && hsz != 56 && hsz != 108 && hsz != 124) return stbi__errpuc("unknown BMP", "BMP type not supported: unknown"); + if (hsz == 12) { + s->img_x = stbi__get16le(s); + s->img_y = stbi__get16le(s); + } else { + s->img_x = stbi__get32le(s); + s->img_y = stbi__get32le(s); + } + if (stbi__get16le(s) != 1) return stbi__errpuc("bad BMP", "bad BMP"); + bpp = stbi__get16le(s); + if (bpp == 1) return stbi__errpuc("monochrome", "BMP type not supported: 1-bit"); + flip_vertically = ((int) s->img_y) > 0; + s->img_y = abs((int) s->img_y); + if (hsz == 12) { + if (bpp < 24) + psize = (offset - 14 - 24) / 3; + } else { + compress = stbi__get32le(s); + if (compress == 1 || compress == 2) return stbi__errpuc("BMP RLE", "BMP type not supported: RLE"); + stbi__get32le(s); // discard sizeof + stbi__get32le(s); // discard hres + stbi__get32le(s); // discard vres + stbi__get32le(s); // discard colorsused + stbi__get32le(s); // discard max important + if (hsz == 40 || hsz == 56) { + if (hsz == 56) { + stbi__get32le(s); + stbi__get32le(s); + stbi__get32le(s); + stbi__get32le(s); + } + if (bpp == 16 || bpp == 32) { + mr = mg = mb = 0; + if (compress == 0) { + if (bpp == 32) { + mr = 0xffu << 16; + mg = 0xffu << 8; + mb = 0xffu << 0; + ma = 0xffu << 24; + all_a = 0; // if all_a is 0 at end, then we loaded alpha channel but it was all 0 + } else { + mr = 31u << 10; + mg = 31u << 5; + mb = 31u << 0; + } + } else if (compress == 3) { + mr = stbi__get32le(s); + mg = stbi__get32le(s); + mb = stbi__get32le(s); + // not documented, but generated by photoshop and handled by mspaint + if (mr == mg && mg == mb) { + // ?!?!? + return stbi__errpuc("bad BMP", "bad BMP"); + } + } else + return stbi__errpuc("bad BMP", "bad BMP"); + } + } else { + STBI_ASSERT(hsz == 108 || hsz == 124); + mr = stbi__get32le(s); + mg = stbi__get32le(s); + mb = stbi__get32le(s); + ma = stbi__get32le(s); + stbi__get32le(s); // discard color space + for (i=0; i < 12; ++i) + stbi__get32le(s); // discard color space parameters + if (hsz == 124) { + stbi__get32le(s); // discard rendering intent + stbi__get32le(s); // discard offset of profile data + stbi__get32le(s); // discard size of profile data + stbi__get32le(s); // discard reserved + } + } + if (bpp < 16) + psize = (offset - 14 - hsz) >> 2; + } + s->img_n = ma ? 4 : 3; + if (req_comp && req_comp >= 3) // we can directly decode 3 or 4 + target = req_comp; + else + target = s->img_n; // if they want monochrome, we'll post-convert + out = (stbi_uc *) stbi__malloc(target * s->img_x * s->img_y); + if (!out) return stbi__errpuc("outofmem", "Out of memory"); + if (bpp < 16) { + int z=0; + if (psize == 0 || psize > 256) { STBI_FREE(out); return stbi__errpuc("invalid", "Corrupt BMP"); } + for (i=0; i < psize; ++i) { + pal[i][2] = stbi__get8(s); + pal[i][1] = stbi__get8(s); + pal[i][0] = stbi__get8(s); + if (hsz != 12) stbi__get8(s); + pal[i][3] = 255; + } + stbi__skip(s, offset - 14 - hsz - psize * (hsz == 12 ? 3 : 4)); + if (bpp == 4) width = (s->img_x + 1) >> 1; + else if (bpp == 8) width = s->img_x; + else { STBI_FREE(out); return stbi__errpuc("bad bpp", "Corrupt BMP"); } + pad = (-width)&3; + for (j=0; j < (int) s->img_y; ++j) { + for (i=0; i < (int) s->img_x; i += 2) { + int v=stbi__get8(s),v2=0; + if (bpp == 4) { + v2 = v & 15; + v >>= 4; + } + out[z++] = pal[v][0]; + out[z++] = pal[v][1]; + out[z++] = pal[v][2]; + if (target == 4) out[z++] = 255; + if (i+1 == (int) s->img_x) break; + v = (bpp == 8) ? stbi__get8(s) : v2; + out[z++] = pal[v][0]; + out[z++] = pal[v][1]; + out[z++] = pal[v][2]; + if (target == 4) out[z++] = 255; + } + stbi__skip(s, pad); + } + } else { + int rshift=0,gshift=0,bshift=0,ashift=0,rcount=0,gcount=0,bcount=0,acount=0; + int z = 0; + int easy=0; + stbi__skip(s, offset - 14 - hsz); + if (bpp == 24) width = 3 * s->img_x; + else if (bpp == 16) width = 2*s->img_x; + else /* bpp = 32 and pad = 0 */ width=0; + pad = (-width) & 3; + if (bpp == 24) { + easy = 1; + } else if (bpp == 32) { + if (mb == 0xff && mg == 0xff00 && mr == 0x00ff0000 && ma == 0xff000000) + easy = 2; + } + if (!easy) { + if (!mr || !mg || !mb) { STBI_FREE(out); return stbi__errpuc("bad masks", "Corrupt BMP"); } + // right shift amt to put high bit in position #7 + rshift = stbi__high_bit(mr)-7; rcount = stbi__bitcount(mr); + gshift = stbi__high_bit(mg)-7; gcount = stbi__bitcount(mg); + bshift = stbi__high_bit(mb)-7; bcount = stbi__bitcount(mb); + ashift = stbi__high_bit(ma)-7; acount = stbi__bitcount(ma); + } + for (j=0; j < (int) s->img_y; ++j) { + if (easy) { + for (i=0; i < (int) s->img_x; ++i) { + unsigned char a; + out[z+2] = stbi__get8(s); + out[z+1] = stbi__get8(s); + out[z+0] = stbi__get8(s); + z += 3; + a = (easy == 2 ? stbi__get8(s) : 255); + all_a |= a; + if (target == 4) out[z++] = a; + } + } else { + for (i=0; i < (int) s->img_x; ++i) { + stbi__uint32 v = (bpp == 16 ? (stbi__uint32) stbi__get16le(s) : stbi__get32le(s)); + int a; + out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mr, rshift, rcount)); + out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mg, gshift, gcount)); + out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mb, bshift, bcount)); + a = (ma ? stbi__shiftsigned(v & ma, ashift, acount) : 255); + all_a |= a; + if (target == 4) out[z++] = STBI__BYTECAST(a); + } + } + stbi__skip(s, pad); + } + } + + // if alpha channel is all 0s, replace with all 255s + if (target == 4 && all_a == 0) + for (i=4*s->img_x*s->img_y-1; i >= 0; i -= 4) + out[i] = 255; + + if (flip_vertically) { + stbi_uc t; + for (j=0; j < (int) s->img_y>>1; ++j) { + stbi_uc *p1 = out + j *s->img_x*target; + stbi_uc *p2 = out + (s->img_y-1-j)*s->img_x*target; + for (i=0; i < (int) s->img_x*target; ++i) { + t = p1[i], p1[i] = p2[i], p2[i] = t; + } + } + } + + if (req_comp && req_comp != target) { + out = stbi__convert_format(out, target, req_comp, s->img_x, s->img_y); + if (out == NULL) return out; // stbi__convert_format frees input on failure + } + + *x = s->img_x; + *y = s->img_y; + if (comp) *comp = s->img_n; + return out; +} +#endif + +// Targa Truevision - TGA +// by Jonathan Dummer +#ifndef STBI_NO_TGA +static int stbi__tga_info(stbi__context *s, int *x, int *y, int *comp) +{ + int tga_w, tga_h, tga_comp; + int sz; + stbi__get8(s); // discard Offset + sz = stbi__get8(s); // color type + if( sz > 1 ) { + stbi__rewind(s); + return 0; // only RGB or indexed allowed + } + sz = stbi__get8(s); // image type + // only RGB or grey allowed, +/- RLE + if ((sz != 1) && (sz != 2) && (sz != 3) && (sz != 9) && (sz != 10) && (sz != 11)) return 0; + stbi__skip(s,9); + tga_w = stbi__get16le(s); + if( tga_w < 1 ) { + stbi__rewind(s); + return 0; // test width + } + tga_h = stbi__get16le(s); + if( tga_h < 1 ) { + stbi__rewind(s); + return 0; // test height + } + sz = stbi__get8(s); // bits per pixel + // only RGB or RGBA or grey allowed + if ((sz != 8) && (sz != 16) && (sz != 24) && (sz != 32)) { + stbi__rewind(s); + return 0; + } + tga_comp = sz; + if (x) *x = tga_w; + if (y) *y = tga_h; + if (comp) *comp = tga_comp / 8; + return 1; // seems to have passed everything +} + +static int stbi__tga_test(stbi__context *s) +{ + int res; + int sz; + stbi__get8(s); // discard Offset + sz = stbi__get8(s); // color type + if ( sz > 1 ) return 0; // only RGB or indexed allowed + sz = stbi__get8(s); // image type + if ( (sz != 1) && (sz != 2) && (sz != 3) && (sz != 9) && (sz != 10) && (sz != 11) ) return 0; // only RGB or grey allowed, +/- RLE + stbi__get16be(s); // discard palette start + stbi__get16be(s); // discard palette length + stbi__get8(s); // discard bits per palette color entry + stbi__get16be(s); // discard x origin + stbi__get16be(s); // discard y origin + if ( stbi__get16be(s) < 1 ) return 0; // test width + if ( stbi__get16be(s) < 1 ) return 0; // test height + sz = stbi__get8(s); // bits per pixel + if ( (sz != 8) && (sz != 16) && (sz != 24) && (sz != 32) ) + res = 0; + else + res = 1; + stbi__rewind(s); + return res; +} + +static stbi_uc *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp) +{ + // read in the TGA header stuff + int tga_offset = stbi__get8(s); + int tga_indexed = stbi__get8(s); + int tga_image_type = stbi__get8(s); + int tga_is_RLE = 0; + int tga_palette_start = stbi__get16le(s); + int tga_palette_len = stbi__get16le(s); + int tga_palette_bits = stbi__get8(s); + int tga_x_origin = stbi__get16le(s); + int tga_y_origin = stbi__get16le(s); + int tga_width = stbi__get16le(s); + int tga_height = stbi__get16le(s); + int tga_bits_per_pixel = stbi__get8(s); + int tga_comp = tga_bits_per_pixel / 8; + int tga_inverted = stbi__get8(s); + // image data + unsigned char *tga_data; + unsigned char *tga_palette = NULL; + int i, j; + unsigned char raw_data[4]; + int RLE_count = 0; + int RLE_repeating = 0; + int read_next_pixel = 1; + + // do a tiny bit of precessing + if ( tga_image_type >= 8 ) + { + tga_image_type -= 8; + tga_is_RLE = 1; + } + /* int tga_alpha_bits = tga_inverted & 15; */ + tga_inverted = 1 - ((tga_inverted >> 5) & 1); + + // error check + if ( //(tga_indexed) || + (tga_width < 1) || (tga_height < 1) || + (tga_image_type < 1) || (tga_image_type > 3) || + ((tga_bits_per_pixel != 8) && (tga_bits_per_pixel != 16) && + (tga_bits_per_pixel != 24) && (tga_bits_per_pixel != 32)) + ) + { + return NULL; // we don't report this as a bad TGA because we don't even know if it's TGA + } + + // If I'm paletted, then I'll use the number of bits from the palette + if ( tga_indexed ) + { + tga_comp = tga_palette_bits / 8; + } + + // tga info + *x = tga_width; + *y = tga_height; + if (comp) *comp = tga_comp; + + tga_data = (unsigned char*)stbi__malloc( (size_t)tga_width * tga_height * tga_comp ); + if (!tga_data) return stbi__errpuc("outofmem", "Out of memory"); + + // skip to the data's starting position (offset usually = 0) + stbi__skip(s, tga_offset ); + + if ( !tga_indexed && !tga_is_RLE) { + for (i=0; i < tga_height; ++i) { + int row = tga_inverted ? tga_height -i - 1 : i; + stbi_uc *tga_row = tga_data + row*tga_width*tga_comp; + stbi__getn(s, tga_row, tga_width * tga_comp); + } + } else { + // do I need to load a palette? + if ( tga_indexed) + { + // any data to skip? (offset usually = 0) + stbi__skip(s, tga_palette_start ); + // load the palette + tga_palette = (unsigned char*)stbi__malloc( tga_palette_len * tga_palette_bits / 8 ); + if (!tga_palette) { + STBI_FREE(tga_data); + return stbi__errpuc("outofmem", "Out of memory"); + } + if (!stbi__getn(s, tga_palette, tga_palette_len * tga_palette_bits / 8 )) { + STBI_FREE(tga_data); + STBI_FREE(tga_palette); + return stbi__errpuc("bad palette", "Corrupt TGA"); + } + } + // load the data + for (i=0; i < tga_width * tga_height; ++i) + { + // if I'm in RLE mode, do I need to get a RLE stbi__pngchunk? + if ( tga_is_RLE ) + { + if ( RLE_count == 0 ) + { + // yep, get the next byte as a RLE command + int RLE_cmd = stbi__get8(s); + RLE_count = 1 + (RLE_cmd & 127); + RLE_repeating = RLE_cmd >> 7; + read_next_pixel = 1; + } else if ( !RLE_repeating ) + { + read_next_pixel = 1; + } + } else + { + read_next_pixel = 1; + } + // OK, if I need to read a pixel, do it now + if ( read_next_pixel ) + { + // load however much data we did have + if ( tga_indexed ) + { + // read in 1 byte, then perform the lookup + int pal_idx = stbi__get8(s); + if ( pal_idx >= tga_palette_len ) + { + // invalid index + pal_idx = 0; + } + pal_idx *= tga_bits_per_pixel / 8; + for (j = 0; j*8 < tga_bits_per_pixel; ++j) + { + raw_data[j] = tga_palette[pal_idx+j]; + } + } else + { + // read in the data raw + for (j = 0; j*8 < tga_bits_per_pixel; ++j) + { + raw_data[j] = stbi__get8(s); + } + } + // clear the reading flag for the next pixel + read_next_pixel = 0; + } // end of reading a pixel + + // copy data + for (j = 0; j < tga_comp; ++j) + tga_data[i*tga_comp+j] = raw_data[j]; + + // in case we're in RLE mode, keep counting down + --RLE_count; + } + // do I need to invert the image? + if ( tga_inverted ) + { + for (j = 0; j*2 < tga_height; ++j) + { + int index1 = j * tga_width * tga_comp; + int index2 = (tga_height - 1 - j) * tga_width * tga_comp; + for (i = tga_width * tga_comp; i > 0; --i) + { + unsigned char temp = tga_data[index1]; + tga_data[index1] = tga_data[index2]; + tga_data[index2] = temp; + ++index1; + ++index2; + } + } + } + // clear my palette, if I had one + if ( tga_palette != NULL ) + { + STBI_FREE( tga_palette ); + } + } + + // swap RGB + if (tga_comp >= 3) + { + unsigned char* tga_pixel = tga_data; + for (i=0; i < tga_width * tga_height; ++i) + { + unsigned char temp = tga_pixel[0]; + tga_pixel[0] = tga_pixel[2]; + tga_pixel[2] = temp; + tga_pixel += tga_comp; + } + } + + // convert to target component count + if (req_comp && req_comp != tga_comp) + tga_data = stbi__convert_format(tga_data, tga_comp, req_comp, tga_width, tga_height); + + // the things I do to get rid of an error message, and yet keep + // Microsoft's C compilers happy... [8^( + tga_palette_start = tga_palette_len = tga_palette_bits = + tga_x_origin = tga_y_origin = 0; + // OK, done + return tga_data; +} +#endif + +// ************************************************************************************************* +// Photoshop PSD loader -- PD by Thatcher Ulrich, integration by Nicolas Schulz, tweaked by STB + +#ifndef STBI_NO_PSD +static int stbi__psd_test(stbi__context *s) +{ + int r = (stbi__get32be(s) == 0x38425053); + stbi__rewind(s); + return r; +} + +static stbi_uc *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp) +{ + int pixelCount; + int channelCount, compression; + int channel, i, count, len; + int bitdepth; + int w,h; + stbi_uc *out; + + // Check identifier + if (stbi__get32be(s) != 0x38425053) // "8BPS" + return stbi__errpuc("not PSD", "Corrupt PSD image"); + + // Check file type version. + if (stbi__get16be(s) != 1) + return stbi__errpuc("wrong version", "Unsupported version of PSD image"); + + // Skip 6 reserved bytes. + stbi__skip(s, 6 ); + + // Read the number of channels (R, G, B, A, etc). + channelCount = stbi__get16be(s); + if (channelCount < 0 || channelCount > 16) + return stbi__errpuc("wrong channel count", "Unsupported number of channels in PSD image"); + + // Read the rows and columns of the image. + h = stbi__get32be(s); + w = stbi__get32be(s); + + // Make sure the depth is 8 bits. + bitdepth = stbi__get16be(s); + if (bitdepth != 8 && bitdepth != 16) + return stbi__errpuc("unsupported bit depth", "PSD bit depth is not 8 or 16 bit"); + + // Make sure the color mode is RGB. + // Valid options are: + // 0: Bitmap + // 1: Grayscale + // 2: Indexed color + // 3: RGB color + // 4: CMYK color + // 7: Multichannel + // 8: Duotone + // 9: Lab color + if (stbi__get16be(s) != 3) + return stbi__errpuc("wrong color format", "PSD is not in RGB color format"); + + // Skip the Mode Data. (It's the palette for indexed color; other info for other modes.) + stbi__skip(s,stbi__get32be(s) ); + + // Skip the image resources. (resolution, pen tool paths, etc) + stbi__skip(s, stbi__get32be(s) ); + + // Skip the reserved data. + stbi__skip(s, stbi__get32be(s) ); + + // Find out if the data is compressed. + // Known values: + // 0: no compression + // 1: RLE compressed + compression = stbi__get16be(s); + if (compression > 1) + return stbi__errpuc("bad compression", "PSD has an unknown compression format"); + + // Create the destination image. + out = (stbi_uc *) stbi__malloc(4 * w*h); + if (!out) return stbi__errpuc("outofmem", "Out of memory"); + pixelCount = w*h; + + // Initialize the data to zero. + //memset( out, 0, pixelCount * 4 ); + + // Finally, the image data. + if (compression) { + // RLE as used by .PSD and .TIFF + // Loop until you get the number of unpacked bytes you are expecting: + // Read the next source byte into n. + // If n is between 0 and 127 inclusive, copy the next n+1 bytes literally. + // Else if n is between -127 and -1 inclusive, copy the next byte -n+1 times. + // Else if n is 128, noop. + // Endloop + + // The RLE-compressed data is preceeded by a 2-byte data count for each row in the data, + // which we're going to just skip. + stbi__skip(s, h * channelCount * 2 ); + + // Read the RLE data by channel. + for (channel = 0; channel < 4; channel++) { + stbi_uc *p; + + p = out+channel; + if (channel >= channelCount) { + // Fill this channel with default data. + for (i = 0; i < pixelCount; i++, p += 4) + *p = (channel == 3 ? 255 : 0); + } else { + // Read the RLE data. + count = 0; + while (count < pixelCount) { + len = stbi__get8(s); + if (len == 128) { + // No-op. + } else if (len < 128) { + // Copy next len+1 bytes literally. + len++; + count += len; + while (len) { + *p = stbi__get8(s); + p += 4; + len--; + } + } else if (len > 128) { + stbi_uc val; + // Next -len+1 bytes in the dest are replicated from next source byte. + // (Interpret len as a negative 8-bit int.) + len ^= 0x0FF; + len += 2; + val = stbi__get8(s); + count += len; + while (len) { + *p = val; + p += 4; + len--; + } + } + } + } + } + + } else { + // We're at the raw image data. It's each channel in order (Red, Green, Blue, Alpha, ...) + // where each channel consists of an 8-bit value for each pixel in the image. + + // Read the data by channel. + for (channel = 0; channel < 4; channel++) { + stbi_uc *p; + + p = out + channel; + if (channel >= channelCount) { + // Fill this channel with default data. + stbi_uc val = channel == 3 ? 255 : 0; + for (i = 0; i < pixelCount; i++, p += 4) + *p = val; + } else { + // Read the data. + if (bitdepth == 16) { + for (i = 0; i < pixelCount; i++, p += 4) + *p = (stbi_uc) (stbi__get16be(s) >> 8); + } else { + for (i = 0; i < pixelCount; i++, p += 4) + *p = stbi__get8(s); + } + } + } + } + + if (req_comp && req_comp != 4) { + out = stbi__convert_format(out, 4, req_comp, w, h); + if (out == NULL) return out; // stbi__convert_format frees input on failure + } + + if (comp) *comp = 4; + *y = h; + *x = w; + + return out; +} +#endif + +// ************************************************************************************************* +// Softimage PIC loader +// by Tom Seddon +// +// See http://softimage.wiki.softimage.com/index.php/INFO:_PIC_file_format +// See http://ozviz.wasp.uwa.edu.au/~pbourke/dataformats/softimagepic/ + +#ifndef STBI_NO_PIC +static int stbi__pic_is4(stbi__context *s,const char *str) +{ + int i; + for (i=0; i<4; ++i) + if (stbi__get8(s) != (stbi_uc)str[i]) + return 0; + + return 1; +} + +static int stbi__pic_test_core(stbi__context *s) +{ + int i; + + if (!stbi__pic_is4(s,"\x53\x80\xF6\x34")) + return 0; + + for(i=0;i<84;++i) + stbi__get8(s); + + if (!stbi__pic_is4(s,"PICT")) + return 0; + + return 1; +} + +typedef struct +{ + stbi_uc size,type,channel; +} stbi__pic_packet; + +static stbi_uc *stbi__readval(stbi__context *s, int channel, stbi_uc *dest) +{ + int mask=0x80, i; + + for (i=0; i<4; ++i, mask>>=1) { + if (channel & mask) { + if (stbi__at_eof(s)) return stbi__errpuc("bad file","PIC file too short"); + dest[i]=stbi__get8(s); + } + } + + return dest; +} + +static void stbi__copyval(int channel,stbi_uc *dest,const stbi_uc *src) +{ + int mask=0x80,i; + + for (i=0;i<4; ++i, mask>>=1) + if (channel&mask) + dest[i]=src[i]; +} + +static stbi_uc *stbi__pic_load_core(stbi__context *s,int width,int height,int *comp, stbi_uc *result) +{ + int act_comp=0,num_packets=0,y,chained; + stbi__pic_packet packets[10]; + + // this will (should...) cater for even some bizarre stuff like having data + // for the same channel in multiple packets. + do { + stbi__pic_packet *packet; + + if (num_packets==sizeof(packets)/sizeof(packets[0])) + return stbi__errpuc("bad format","too many packets"); + + packet = &packets[num_packets++]; + + chained = stbi__get8(s); + packet->size = stbi__get8(s); + packet->type = stbi__get8(s); + packet->channel = stbi__get8(s); + + act_comp |= packet->channel; + + if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (reading packets)"); + if (packet->size != 8) return stbi__errpuc("bad format","packet isn't 8bpp"); + } while (chained); + + *comp = (act_comp & 0x10 ? 4 : 3); // has alpha channel? + + for(y=0; ytype) { + default: + return stbi__errpuc("bad format","packet has bad compression type"); + + case 0: {//uncompressed + int x; + + for(x=0;xchannel,dest)) + return 0; + break; + } + + case 1://Pure RLE + { + int left=width, i; + + while (left>0) { + stbi_uc count,value[4]; + + count=stbi__get8(s); + if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (pure read count)"); + + if (count > left) + count = (stbi_uc) left; + + if (!stbi__readval(s,packet->channel,value)) return 0; + + for(i=0; ichannel,dest,value); + left -= count; + } + } + break; + + case 2: {//Mixed RLE + int left=width; + while (left>0) { + int count = stbi__get8(s), i; + if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (mixed read count)"); + + if (count >= 128) { // Repeated + stbi_uc value[4]; + + if (count==128) + count = stbi__get16be(s); + else + count -= 127; + if (count > left) + return stbi__errpuc("bad file","scanline overrun"); + + if (!stbi__readval(s,packet->channel,value)) + return 0; + + for(i=0;ichannel,dest,value); + } else { // Raw + ++count; + if (count>left) return stbi__errpuc("bad file","scanline overrun"); + + for(i=0;ichannel,dest)) + return 0; + } + left-=count; + } + break; + } + } + } + } + + return result; +} + +static stbi_uc *stbi__pic_load(stbi__context *s,int *px,int *py,int *comp,int req_comp) +{ + stbi_uc *result; + int i, x,y; + + for (i=0; i<92; ++i) + stbi__get8(s); + + x = stbi__get16be(s); + y = stbi__get16be(s); + if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (pic header)"); + if ((1 << 28) / x < y) return stbi__errpuc("too large", "Image too large to decode"); + + stbi__get32be(s); //skip `ratio' + stbi__get16be(s); //skip `fields' + stbi__get16be(s); //skip `pad' + + // intermediate buffer is RGBA + result = (stbi_uc *) stbi__malloc(x*y*4); + memset(result, 0xff, x*y*4); + + if (!stbi__pic_load_core(s,x,y,comp, result)) { + STBI_FREE(result); + result=0; + } + *px = x; + *py = y; + if (req_comp == 0) req_comp = *comp; + result=stbi__convert_format(result,4,req_comp,x,y); + + return result; +} + +static int stbi__pic_test(stbi__context *s) +{ + int r = stbi__pic_test_core(s); + stbi__rewind(s); + return r; +} +#endif + +// ************************************************************************************************* +// GIF loader -- public domain by Jean-Marc Lienher -- simplified/shrunk by stb + +#ifndef STBI_NO_GIF +typedef struct +{ + stbi__int16 prefix; + stbi_uc first; + stbi_uc suffix; +} stbi__gif_lzw; + +typedef struct +{ + int w,h; + stbi_uc *out, *old_out; // output buffer (always 4 components) + int flags, bgindex, ratio, transparent, eflags, delay; + stbi_uc pal[256][4]; + stbi_uc lpal[256][4]; + stbi__gif_lzw codes[4096]; + stbi_uc *color_table; + int parse, step; + int lflags; + int start_x, start_y; + int max_x, max_y; + int cur_x, cur_y; + int line_size; +} stbi__gif; + +static int stbi__gif_test_raw(stbi__context *s) +{ + int sz; + if (stbi__get8(s) != 'G' || stbi__get8(s) != 'I' || stbi__get8(s) != 'F' || stbi__get8(s) != '8') return 0; + sz = stbi__get8(s); + if (sz != '9' && sz != '7') return 0; + if (stbi__get8(s) != 'a') return 0; + return 1; +} + +static int stbi__gif_test(stbi__context *s) +{ + int r = stbi__gif_test_raw(s); + stbi__rewind(s); + return r; +} + +static void stbi__gif_parse_colortable(stbi__context *s, stbi_uc pal[256][4], int num_entries, int transp) +{ + int i; + for (i=0; i < num_entries; ++i) { + pal[i][2] = stbi__get8(s); + pal[i][1] = stbi__get8(s); + pal[i][0] = stbi__get8(s); + pal[i][3] = transp == i ? 0 : 255; + } +} + +static int stbi__gif_header(stbi__context *s, stbi__gif *g, int *comp, int is_info) +{ + stbi_uc version; + if (stbi__get8(s) != 'G' || stbi__get8(s) != 'I' || stbi__get8(s) != 'F' || stbi__get8(s) != '8') + return stbi__err("not GIF", "Corrupt GIF"); + + version = stbi__get8(s); + if (version != '7' && version != '9') return stbi__err("not GIF", "Corrupt GIF"); + if (stbi__get8(s) != 'a') return stbi__err("not GIF", "Corrupt GIF"); + + stbi__g_failure_reason = ""; + g->w = stbi__get16le(s); + g->h = stbi__get16le(s); + g->flags = stbi__get8(s); + g->bgindex = stbi__get8(s); + g->ratio = stbi__get8(s); + g->transparent = -1; + + if (comp != 0) *comp = 4; // can't actually tell whether it's 3 or 4 until we parse the comments + + if (is_info) return 1; + + if (g->flags & 0x80) + stbi__gif_parse_colortable(s,g->pal, 2 << (g->flags & 7), -1); + + return 1; +} + +static int stbi__gif_info_raw(stbi__context *s, int *x, int *y, int *comp) +{ + stbi__gif g; + if (!stbi__gif_header(s, &g, comp, 1)) { + stbi__rewind( s ); + return 0; + } + if (x) *x = g.w; + if (y) *y = g.h; + return 1; +} + +static void stbi__out_gif_code(stbi__gif *g, stbi__uint16 code) +{ + stbi_uc *p, *c; + + // recurse to decode the prefixes, since the linked-list is backwards, + // and working backwards through an interleaved image would be nasty + if (g->codes[code].prefix >= 0) + stbi__out_gif_code(g, g->codes[code].prefix); + + if (g->cur_y >= g->max_y) return; + + p = &g->out[g->cur_x + g->cur_y]; + c = &g->color_table[g->codes[code].suffix * 4]; + + if (c[3] >= 128) { + p[0] = c[2]; + p[1] = c[1]; + p[2] = c[0]; + p[3] = c[3]; + } + g->cur_x += 4; + + if (g->cur_x >= g->max_x) { + g->cur_x = g->start_x; + g->cur_y += g->step; + + while (g->cur_y >= g->max_y && g->parse > 0) { + g->step = (1 << g->parse) * g->line_size; + g->cur_y = g->start_y + (g->step >> 1); + --g->parse; + } + } +} + +static stbi_uc *stbi__process_gif_raster(stbi__context *s, stbi__gif *g) +{ + stbi_uc lzw_cs; + stbi__int32 len, init_code; + stbi__uint32 first; + stbi__int32 codesize, codemask, avail, oldcode, bits, valid_bits, clear; + stbi__gif_lzw *p; + + lzw_cs = stbi__get8(s); + if (lzw_cs > 12) return NULL; + clear = 1 << lzw_cs; + first = 1; + codesize = lzw_cs + 1; + codemask = (1 << codesize) - 1; + bits = 0; + valid_bits = 0; + for (init_code = 0; init_code < clear; init_code++) { + g->codes[init_code].prefix = -1; + g->codes[init_code].first = (stbi_uc) init_code; + g->codes[init_code].suffix = (stbi_uc) init_code; + } + + // support no starting clear code + avail = clear+2; + oldcode = -1; + + len = 0; + for(;;) { + if (valid_bits < codesize) { + if (len == 0) { + len = stbi__get8(s); // start new block + if (len == 0) + return g->out; + } + --len; + bits |= (stbi__int32) stbi__get8(s) << valid_bits; + valid_bits += 8; + } else { + stbi__int32 code = bits & codemask; + bits >>= codesize; + valid_bits -= codesize; + // @OPTIMIZE: is there some way we can accelerate the non-clear path? + if (code == clear) { // clear code + codesize = lzw_cs + 1; + codemask = (1 << codesize) - 1; + avail = clear + 2; + oldcode = -1; + first = 0; + } else if (code == clear + 1) { // end of stream code + stbi__skip(s, len); + while ((len = stbi__get8(s)) > 0) + stbi__skip(s,len); + return g->out; + } else if (code <= avail) { + if (first) return stbi__errpuc("no clear code", "Corrupt GIF"); + + if (oldcode >= 0) { + p = &g->codes[avail++]; + if (avail > 4096) return stbi__errpuc("too many codes", "Corrupt GIF"); + p->prefix = (stbi__int16) oldcode; + p->first = g->codes[oldcode].first; + p->suffix = (code == avail) ? p->first : g->codes[code].first; + } else if (code == avail) + return stbi__errpuc("illegal code in raster", "Corrupt GIF"); + + stbi__out_gif_code(g, (stbi__uint16) code); + + if ((avail & codemask) == 0 && avail <= 0x0FFF) { + codesize++; + codemask = (1 << codesize) - 1; + } + + oldcode = code; + } else { + return stbi__errpuc("illegal code in raster", "Corrupt GIF"); + } + } + } +} + +static void stbi__fill_gif_background(stbi__gif *g, int x0, int y0, int x1, int y1) +{ + int x, y; + stbi_uc *c = g->pal[g->bgindex]; + for (y = y0; y < y1; y += 4 * g->w) { + for (x = x0; x < x1; x += 4) { + stbi_uc *p = &g->out[y + x]; + p[0] = c[2]; + p[1] = c[1]; + p[2] = c[0]; + p[3] = 0; + } + } +} + +// this function is designed to support animated gifs, although stb_image doesn't support it +static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, int req_comp) +{ + int i; + stbi_uc *prev_out = 0; + + if (g->out == 0 && !stbi__gif_header(s, g, comp,0)) + return 0; // stbi__g_failure_reason set by stbi__gif_header + + prev_out = g->out; + g->out = (stbi_uc *) stbi__malloc(4 * g->w * g->h); + if (g->out == 0) return stbi__errpuc("outofmem", "Out of memory"); + + switch ((g->eflags & 0x1C) >> 2) { + case 0: // unspecified (also always used on 1st frame) + stbi__fill_gif_background(g, 0, 0, 4 * g->w, 4 * g->w * g->h); + break; + case 1: // do not dispose + if (prev_out) memcpy(g->out, prev_out, 4 * g->w * g->h); + g->old_out = prev_out; + break; + case 2: // dispose to background + if (prev_out) memcpy(g->out, prev_out, 4 * g->w * g->h); + stbi__fill_gif_background(g, g->start_x, g->start_y, g->max_x, g->max_y); + break; + case 3: // dispose to previous + if (g->old_out) { + for (i = g->start_y; i < g->max_y; i += 4 * g->w) + memcpy(&g->out[i + g->start_x], &g->old_out[i + g->start_x], g->max_x - g->start_x); + } + break; + } + + for (;;) { + switch (stbi__get8(s)) { + case 0x2C: /* Image Descriptor */ + { + int prev_trans = -1; + stbi__int32 x, y, w, h; + stbi_uc *o; + + x = stbi__get16le(s); + y = stbi__get16le(s); + w = stbi__get16le(s); + h = stbi__get16le(s); + if (((x + w) > (g->w)) || ((y + h) > (g->h))) + return stbi__errpuc("bad Image Descriptor", "Corrupt GIF"); + + g->line_size = g->w * 4; + g->start_x = x * 4; + g->start_y = y * g->line_size; + g->max_x = g->start_x + w * 4; + g->max_y = g->start_y + h * g->line_size; + g->cur_x = g->start_x; + g->cur_y = g->start_y; + + g->lflags = stbi__get8(s); + + if (g->lflags & 0x40) { + g->step = 8 * g->line_size; // first interlaced spacing + g->parse = 3; + } else { + g->step = g->line_size; + g->parse = 0; + } + + if (g->lflags & 0x80) { + stbi__gif_parse_colortable(s,g->lpal, 2 << (g->lflags & 7), g->eflags & 0x01 ? g->transparent : -1); + g->color_table = (stbi_uc *) g->lpal; + } else if (g->flags & 0x80) { + if (g->transparent >= 0 && (g->eflags & 0x01)) { + prev_trans = g->pal[g->transparent][3]; + g->pal[g->transparent][3] = 0; + } + g->color_table = (stbi_uc *) g->pal; + } else + return stbi__errpuc("missing color table", "Corrupt GIF"); + + o = stbi__process_gif_raster(s, g); + if (o == NULL) return NULL; + + if (prev_trans != -1) + g->pal[g->transparent][3] = (stbi_uc) prev_trans; + + return o; + } + + case 0x21: // Comment Extension. + { + int len; + if (stbi__get8(s) == 0xF9) { // Graphic Control Extension. + len = stbi__get8(s); + if (len == 4) { + g->eflags = stbi__get8(s); + g->delay = stbi__get16le(s); + g->transparent = stbi__get8(s); + } else { + stbi__skip(s, len); + break; + } + } + while ((len = stbi__get8(s)) != 0) + stbi__skip(s, len); + break; + } + + case 0x3B: // gif stream termination code + return (stbi_uc *) s; // using '1' causes warning on some compilers + + default: + return stbi__errpuc("unknown code", "Corrupt GIF"); + } + } + + STBI_NOTUSED(req_comp); +} + +static stbi_uc *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp) +{ + stbi_uc *u = 0; + stbi__gif g; + memset(&g, 0, sizeof(g)); + + u = stbi__gif_load_next(s, &g, comp, req_comp); + if (u == (stbi_uc *) s) u = 0; // end of animated gif marker + if (u) { + *x = g.w; + *y = g.h; + if (req_comp && req_comp != 4) + u = stbi__convert_format(u, 4, req_comp, g.w, g.h); + } + else if (g.out) + STBI_FREE(g.out); + + return u; +} + +static int stbi__gif_info(stbi__context *s, int *x, int *y, int *comp) +{ + return stbi__gif_info_raw(s,x,y,comp); +} +#endif + +// ************************************************************************************************* +// Radiance RGBE HDR loader +// originally by Nicolas Schulz +#ifndef STBI_NO_HDR +static int stbi__hdr_test_core(stbi__context *s) +{ + const char *signature = "#?RADIANCE\n"; + int i; + for (i=0; signature[i]; ++i) + if (stbi__get8(s) != signature[i]) + return 0; + return 1; +} + +static int stbi__hdr_test(stbi__context* s) +{ + int r = stbi__hdr_test_core(s); + stbi__rewind(s); + return r; +} + +#define STBI__HDR_BUFLEN 1024 +static char *stbi__hdr_gettoken(stbi__context *z, char *buffer) +{ + int len=0; + char c = '\0'; + + c = (char) stbi__get8(z); + + while (!stbi__at_eof(z) && c != '\n') { + buffer[len++] = c; + if (len == STBI__HDR_BUFLEN-1) { + // flush to end of line + while (!stbi__at_eof(z) && stbi__get8(z) != '\n') + ; + break; + } + c = (char) stbi__get8(z); + } + + buffer[len] = 0; + return buffer; +} + +static void stbi__hdr_convert(float *output, stbi_uc *input, int req_comp) +{ + if ( input[3] != 0 ) { + float f1; + // Exponent + f1 = (float) ldexp(1.0f, input[3] - (int)(128 + 8)); + if (req_comp <= 2) + output[0] = (input[0] + input[1] + input[2]) * f1 / 3; + else { + output[0] = input[0] * f1; + output[1] = input[1] * f1; + output[2] = input[2] * f1; + } + if (req_comp == 2) output[1] = 1; + if (req_comp == 4) output[3] = 1; + } else { + switch (req_comp) { + case 4: output[3] = 1; /* fallthrough */ + case 3: output[0] = output[1] = output[2] = 0; + break; + case 2: output[1] = 1; /* fallthrough */ + case 1: output[0] = 0; + break; + } + } +} + +static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int req_comp) +{ + char buffer[STBI__HDR_BUFLEN]; + char *token; + int valid = 0; + int width, height; + stbi_uc *scanline; + float *hdr_data; + int len; + unsigned char count, value; + int i, j, k, c1,c2, z; + + + // Check identifier + if (strcmp(stbi__hdr_gettoken(s,buffer), "#?RADIANCE") != 0) + return stbi__errpf("not HDR", "Corrupt HDR image"); + + // Parse header + for(;;) { + token = stbi__hdr_gettoken(s,buffer); + if (token[0] == 0) break; + if (strcmp(token, "FORMAT=32-bit_rle_rgbe") == 0) valid = 1; + } + + if (!valid) return stbi__errpf("unsupported format", "Unsupported HDR format"); + + // Parse width and height + // can't use sscanf() if we're not using stdio! + token = stbi__hdr_gettoken(s,buffer); + if (strncmp(token, "-Y ", 3)) return stbi__errpf("unsupported data layout", "Unsupported HDR format"); + token += 3; + height = (int) strtol(token, &token, 10); + while (*token == ' ') ++token; + if (strncmp(token, "+X ", 3)) return stbi__errpf("unsupported data layout", "Unsupported HDR format"); + token += 3; + width = (int) strtol(token, NULL, 10); + + *x = width; + *y = height; + + if (comp) *comp = 3; + if (req_comp == 0) req_comp = 3; + + // Read data + hdr_data = (float *) stbi__malloc(height * width * req_comp * sizeof(float)); + + // Load image data + // image data is stored as some number of sca + if ( width < 8 || width >= 32768) { + // Read flat data + for (j=0; j < height; ++j) { + for (i=0; i < width; ++i) { + stbi_uc rgbe[4]; + main_decode_loop: + stbi__getn(s, rgbe, 4); + stbi__hdr_convert(hdr_data + j * width * req_comp + i * req_comp, rgbe, req_comp); + } + } + } else { + // Read RLE-encoded data + scanline = NULL; + + for (j = 0; j < height; ++j) { + c1 = stbi__get8(s); + c2 = stbi__get8(s); + len = stbi__get8(s); + if (c1 != 2 || c2 != 2 || (len & 0x80)) { + // not run-length encoded, so we have to actually use THIS data as a decoded + // pixel (note this can't be a valid pixel--one of RGB must be >= 128) + stbi_uc rgbe[4]; + rgbe[0] = (stbi_uc) c1; + rgbe[1] = (stbi_uc) c2; + rgbe[2] = (stbi_uc) len; + rgbe[3] = (stbi_uc) stbi__get8(s); + stbi__hdr_convert(hdr_data, rgbe, req_comp); + i = 1; + j = 0; + STBI_FREE(scanline); + goto main_decode_loop; // yes, this makes no sense + } + len <<= 8; + len |= stbi__get8(s); + if (len != width) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("invalid decoded scanline length", "corrupt HDR"); } + if (scanline == NULL) scanline = (stbi_uc *) stbi__malloc(width * 4); + + for (k = 0; k < 4; ++k) { + i = 0; + while (i < width) { + count = stbi__get8(s); + if (count > 128) { + // Run + value = stbi__get8(s); + count -= 128; + for (z = 0; z < count; ++z) + scanline[i++ * 4 + k] = value; + } else { + // Dump + for (z = 0; z < count; ++z) + scanline[i++ * 4 + k] = stbi__get8(s); + } + } + } + for (i=0; i < width; ++i) + stbi__hdr_convert(hdr_data+(j*width + i)*req_comp, scanline + i*4, req_comp); + } + STBI_FREE(scanline); + } + + return hdr_data; +} + +static int stbi__hdr_info(stbi__context *s, int *x, int *y, int *comp) +{ + char buffer[STBI__HDR_BUFLEN]; + char *token; + int valid = 0; + + if (strcmp(stbi__hdr_gettoken(s,buffer), "#?RADIANCE") != 0) { + stbi__rewind( s ); + return 0; + } + + for(;;) { + token = stbi__hdr_gettoken(s,buffer); + if (token[0] == 0) break; + if (strcmp(token, "FORMAT=32-bit_rle_rgbe") == 0) valid = 1; + } + + if (!valid) { + stbi__rewind( s ); + return 0; + } + token = stbi__hdr_gettoken(s,buffer); + if (strncmp(token, "-Y ", 3)) { + stbi__rewind( s ); + return 0; + } + token += 3; + *y = (int) strtol(token, &token, 10); + while (*token == ' ') ++token; + if (strncmp(token, "+X ", 3)) { + stbi__rewind( s ); + return 0; + } + token += 3; + *x = (int) strtol(token, NULL, 10); + *comp = 3; + return 1; +} +#endif // STBI_NO_HDR + +#ifndef STBI_NO_BMP +static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp) +{ + int hsz; + if (stbi__get8(s) != 'B' || stbi__get8(s) != 'M') { + stbi__rewind( s ); + return 0; + } + stbi__skip(s,12); + hsz = stbi__get32le(s); + if (hsz != 12 && hsz != 40 && hsz != 56 && hsz != 108 && hsz != 124) { + stbi__rewind( s ); + return 0; + } + if (hsz == 12) { + *x = stbi__get16le(s); + *y = stbi__get16le(s); + } else { + *x = stbi__get32le(s); + *y = stbi__get32le(s); + } + if (stbi__get16le(s) != 1) { + stbi__rewind( s ); + return 0; + } + *comp = stbi__get16le(s) / 8; + return 1; +} +#endif + +#ifndef STBI_NO_PSD +static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp) +{ + int channelCount; + if (stbi__get32be(s) != 0x38425053) { + stbi__rewind( s ); + return 0; + } + if (stbi__get16be(s) != 1) { + stbi__rewind( s ); + return 0; + } + stbi__skip(s, 6); + channelCount = stbi__get16be(s); + if (channelCount < 0 || channelCount > 16) { + stbi__rewind( s ); + return 0; + } + *y = stbi__get32be(s); + *x = stbi__get32be(s); + if (stbi__get16be(s) != 8) { + stbi__rewind( s ); + return 0; + } + if (stbi__get16be(s) != 3) { + stbi__rewind( s ); + return 0; + } + *comp = 4; + return 1; +} +#endif + +#ifndef STBI_NO_PIC +static int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp) +{ + int act_comp=0,num_packets=0,chained; + stbi__pic_packet packets[10]; + + if (!stbi__pic_is4(s,"\x53\x80\xF6\x34")) { + stbi__rewind(s); + return 0; + } + + stbi__skip(s, 88); + + *x = stbi__get16be(s); + *y = stbi__get16be(s); + if (stbi__at_eof(s)) { + stbi__rewind( s); + return 0; + } + if ( (*x) != 0 && (1 << 28) / (*x) < (*y)) { + stbi__rewind( s ); + return 0; + } + + stbi__skip(s, 8); + + do { + stbi__pic_packet *packet; + + if (num_packets==sizeof(packets)/sizeof(packets[0])) + return 0; + + packet = &packets[num_packets++]; + chained = stbi__get8(s); + packet->size = stbi__get8(s); + packet->type = stbi__get8(s); + packet->channel = stbi__get8(s); + act_comp |= packet->channel; + + if (stbi__at_eof(s)) { + stbi__rewind( s ); + return 0; + } + if (packet->size != 8) { + stbi__rewind( s ); + return 0; + } + } while (chained); + + *comp = (act_comp & 0x10 ? 4 : 3); + + return 1; +} +#endif + +// ************************************************************************************************* +// Portable Gray Map and Portable Pixel Map loader +// by Ken Miller +// +// PGM: http://netpbm.sourceforge.net/doc/pgm.html +// PPM: http://netpbm.sourceforge.net/doc/ppm.html +// +// Known limitations: +// Does not support comments in the header section +// Does not support ASCII image data (formats P2 and P3) +// Does not support 16-bit-per-channel + +#ifndef STBI_NO_PNM + +static int stbi__pnm_test(stbi__context *s) +{ + char p, t; + p = (char) stbi__get8(s); + t = (char) stbi__get8(s); + if (p != 'P' || (t != '5' && t != '6')) { + stbi__rewind( s ); + return 0; + } + return 1; +} + +static stbi_uc *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp) +{ + stbi_uc *out; + if (!stbi__pnm_info(s, (int *)&s->img_x, (int *)&s->img_y, (int *)&s->img_n)) + return 0; + *x = s->img_x; + *y = s->img_y; + *comp = s->img_n; + + out = (stbi_uc *) stbi__malloc(s->img_n * s->img_x * s->img_y); + if (!out) return stbi__errpuc("outofmem", "Out of memory"); + stbi__getn(s, out, s->img_n * s->img_x * s->img_y); + + if (req_comp && req_comp != s->img_n) { + out = stbi__convert_format(out, s->img_n, req_comp, s->img_x, s->img_y); + if (out == NULL) return out; // stbi__convert_format frees input on failure + } + return out; +} + +static int stbi__pnm_isspace(char c) +{ + return c == ' ' || c == '\t' || c == '\n' || c == '\v' || c == '\f' || c == '\r'; +} + +static void stbi__pnm_skip_whitespace(stbi__context *s, char *c) +{ + while (!stbi__at_eof(s) && stbi__pnm_isspace(*c)) + *c = (char) stbi__get8(s); +} + +static int stbi__pnm_isdigit(char c) +{ + return c >= '0' && c <= '9'; +} + +static int stbi__pnm_getinteger(stbi__context *s, char *c) +{ + int value = 0; + + while (!stbi__at_eof(s) && stbi__pnm_isdigit(*c)) { + value = value*10 + (*c - '0'); + *c = (char) stbi__get8(s); + } + + return value; +} + +static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp) +{ + int maxv; + char c, p, t; + + stbi__rewind( s ); + + // Get identifier + p = (char) stbi__get8(s); + t = (char) stbi__get8(s); + if (p != 'P' || (t != '5' && t != '6')) { + stbi__rewind( s ); + return 0; + } + + *comp = (t == '6') ? 3 : 1; // '5' is 1-component .pgm; '6' is 3-component .ppm + + c = (char) stbi__get8(s); + stbi__pnm_skip_whitespace(s, &c); + + *x = stbi__pnm_getinteger(s, &c); // read width + stbi__pnm_skip_whitespace(s, &c); + + *y = stbi__pnm_getinteger(s, &c); // read height + stbi__pnm_skip_whitespace(s, &c); + + maxv = stbi__pnm_getinteger(s, &c); // read max value + + if (maxv > 255) + return stbi__err("max value > 255", "PPM image not 8-bit"); + else + return 1; +} +#endif + +static int stbi__info_main(stbi__context *s, int *x, int *y, int *comp) +{ + #ifndef STBI_NO_JPEG + if (stbi__jpeg_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_PNG + if (stbi__png_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_GIF + if (stbi__gif_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_BMP + if (stbi__bmp_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_PSD + if (stbi__psd_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_PIC + if (stbi__pic_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_PNM + if (stbi__pnm_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_HDR + if (stbi__hdr_info(s, x, y, comp)) return 1; + #endif + + // test tga last because it's a crappy test! + #ifndef STBI_NO_TGA + if (stbi__tga_info(s, x, y, comp)) + return 1; + #endif + return stbi__err("unknown image type", "Image not of any known type, or corrupt"); +} + +#ifndef STBI_NO_STDIO +STBIDEF int stbi_info(char const *filename, int *x, int *y, int *comp) +{ + FILE *f = stbi__fopen(filename, "rb"); + int result; + if (!f) return stbi__err("can't fopen", "Unable to open file"); + result = stbi_info_from_file(f, x, y, comp); + fclose(f); + return result; +} + +STBIDEF int stbi_info_from_file(FILE *f, int *x, int *y, int *comp) +{ + int r; + stbi__context s; + long pos = ftell(f); + stbi__start_file(&s, f); + r = stbi__info_main(&s,x,y,comp); + fseek(f,pos,SEEK_SET); + return r; +} +#endif // !STBI_NO_STDIO + +STBIDEF int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp) +{ + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__info_main(&s,x,y,comp); +} + +STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *c, void *user, int *x, int *y, int *comp) +{ + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *) c, user); + return stbi__info_main(&s,x,y,comp); +} + +// add in my DDS loading support +#ifndef STBI_NO_DDS +#include "stbi_DDS_c.h" +#endif + +// add in my pvr loading support +#ifndef STBI_NO_PVR +#include "stbi_pvr_c.h" +#endif + +// add in my pkm ( ETC1 ) loading support +#ifndef STBI_NO_PKM +#include "stbi_pkm_c.h" +#endif + +#ifndef STBI_NO_EXT +#include "stbi_ext_c.h" +#endif + +#endif // STB_IMAGE_IMPLEMENTATION + +/* + revision history: + 2.08 (2015-09-13) fix to 2.07 cleanup, reading RGB PSD as RGBA + 2.07 (2015-09-13) fix compiler warnings + partial animated GIF support + limited 16-bit PSD support + #ifdef unused functions + bug with < 92 byte PIC,PNM,HDR,TGA + 2.06 (2015-04-19) fix bug where PSD returns wrong '*comp' value + 2.05 (2015-04-19) fix bug in progressive JPEG handling, fix warning + 2.04 (2015-04-15) try to re-enable SIMD on MinGW 64-bit + 2.03 (2015-04-12) extra corruption checking (mmozeiko) + stbi_set_flip_vertically_on_load (nguillemot) + fix NEON support; fix mingw support + 2.02 (2015-01-19) fix incorrect assert, fix warning + 2.01 (2015-01-17) fix various warnings; suppress SIMD on gcc 32-bit without -msse2 + 2.00b (2014-12-25) fix STBI_MALLOC in progressive JPEG + 2.00 (2014-12-25) optimize JPG, including x86 SSE2 & NEON SIMD (ryg) + progressive JPEG (stb) + PGM/PPM support (Ken Miller) + STBI_MALLOC,STBI_REALLOC,STBI_FREE + GIF bugfix -- seemingly never worked + STBI_NO_*, STBI_ONLY_* + 1.48 (2014-12-14) fix incorrectly-named assert() + 1.47 (2014-12-14) 1/2/4-bit PNG support, both direct and paletted (Omar Cornut & stb) + optimize PNG (ryg) + fix bug in interlaced PNG with user-specified channel count (stb) + 1.46 (2014-08-26) + fix broken tRNS chunk (colorkey-style transparency) in non-paletted PNG + 1.45 (2014-08-16) + fix MSVC-ARM internal compiler error by wrapping malloc + 1.44 (2014-08-07) + various warning fixes from Ronny Chevalier + 1.43 (2014-07-15) + fix MSVC-only compiler problem in code changed in 1.42 + 1.42 (2014-07-09) + don't define _CRT_SECURE_NO_WARNINGS (affects user code) + fixes to stbi__cleanup_jpeg path + added STBI_ASSERT to avoid requiring assert.h + 1.41 (2014-06-25) + fix search&replace from 1.36 that messed up comments/error messages + 1.40 (2014-06-22) + fix gcc struct-initialization warning + 1.39 (2014-06-15) + fix to TGA optimization when req_comp != number of components in TGA; + fix to GIF loading because BMP wasn't rewinding (whoops, no GIFs in my test suite) + add support for BMP version 5 (more ignored fields) + 1.38 (2014-06-06) + suppress MSVC warnings on integer casts truncating values + fix accidental rename of 'skip' field of I/O + 1.37 (2014-06-04) + remove duplicate typedef + 1.36 (2014-06-03) + convert to header file single-file library + if de-iphone isn't set, load iphone images color-swapped instead of returning NULL + 1.35 (2014-05-27) + various warnings + fix broken STBI_SIMD path + fix bug where stbi_load_from_file no longer left file pointer in correct place + fix broken non-easy path for 32-bit BMP (possibly never used) + TGA optimization by Arseny Kapoulkine + 1.34 (unknown) + use STBI_NOTUSED in stbi__resample_row_generic(), fix one more leak in tga failure case + 1.33 (2011-07-14) + make stbi_is_hdr work in STBI_NO_HDR (as specified), minor compiler-friendly improvements + 1.32 (2011-07-13) + support for "info" function for all supported filetypes (SpartanJ) + 1.31 (2011-06-20) + a few more leak fixes, bug in PNG handling (SpartanJ) + 1.30 (2011-06-11) + added ability to load files via callbacks to accomidate custom input streams (Ben Wenger) + removed deprecated format-specific test/load functions + removed support for installable file formats (stbi_loader) -- would have been broken for IO callbacks anyway + error cases in bmp and tga give messages and don't leak (Raymond Barbiero, grisha) + fix inefficiency in decoding 32-bit BMP (David Woo) + 1.29 (2010-08-16) + various warning fixes from Aurelien Pocheville + 1.28 (2010-08-01) + fix bug in GIF palette transparency (SpartanJ) + 1.27 (2010-08-01) + cast-to-stbi_uc to fix warnings + 1.26 (2010-07-24) + fix bug in file buffering for PNG reported by SpartanJ + 1.25 (2010-07-17) + refix trans_data warning (Won Chun) + 1.24 (2010-07-12) + perf improvements reading from files on platforms with lock-heavy fgetc() + minor perf improvements for jpeg + deprecated type-specific functions so we'll get feedback if they're needed + attempt to fix trans_data warning (Won Chun) + 1.23 fixed bug in iPhone support + 1.22 (2010-07-10) + removed image *writing* support + stbi_info support from Jetro Lauha + GIF support from Jean-Marc Lienher + iPhone PNG-extensions from James Brown + warning-fixes from Nicolas Schulz and Janez Zemva (i.stbi__err. Janez (U+017D)emva) + 1.21 fix use of 'stbi_uc' in header (reported by jon blow) + 1.20 added support for Softimage PIC, by Tom Seddon + 1.19 bug in interlaced PNG corruption check (found by ryg) + 1.18 (2008-08-02) + fix a threading bug (local mutable static) + 1.17 support interlaced PNG + 1.16 major bugfix - stbi__convert_format converted one too many pixels + 1.15 initialize some fields for thread safety + 1.14 fix threadsafe conversion bug + header-file-only version (#define STBI_HEADER_FILE_ONLY before including) + 1.13 threadsafe + 1.12 const qualifiers in the API + 1.11 Support installable IDCT, colorspace conversion routines + 1.10 Fixes for 64-bit (don't use "unsigned long") + optimized upsampling by Fabian "ryg" Giesen + 1.09 Fix format-conversion for PSD code (bad global variables!) + 1.08 Thatcher Ulrich's PSD code integrated by Nicolas Schulz + 1.07 attempt to fix C++ warning/errors again + 1.06 attempt to fix C++ warning/errors again + 1.05 fix TGA loading to return correct *comp and use good luminance calc + 1.04 default float alpha is 1, not 255; use 'void *' for stbi_image_free + 1.03 bugfixes to STBI_NO_STDIO, STBI_NO_HDR + 1.02 support for (subset of) HDR files, float interface for preferred access to them + 1.01 fix bug: possible bug in handling right-side up bmps... not sure + fix bug: the stbi__bmp_load() and stbi__tga_load() functions didn't work at all + 1.00 interface to zlib that skips zlib header + 0.99 correct handling of alpha in palette + 0.98 TGA loader by lonesock; dynamically add loaders (untested) + 0.97 jpeg errors on too large a file; also catch another malloc failure + 0.96 fix detection of invalid v value - particleman@mollyrocket forum + 0.95 during header scan, seek to markers in case of padding + 0.94 STBI_NO_STDIO to disable stdio usage; rename all #defines the same + 0.93 handle jpegtran output; verbose errors + 0.92 read 4,8,16,24,32-bit BMP files of several formats + 0.91 output 24-bit Windows 3.0 BMP files + 0.90 fix a few more warnings; bump version number to approach 1.0 + 0.61 bugfixes due to Marc LeBlanc, Christopher Lloyd + 0.60 fix compiling as c++ + 0.59 fix warnings: merge Dave Moore's -Wall fixes + 0.58 fix bug: zlib uncompressed mode len/nlen was wrong endian + 0.57 fix bug: jpg last huffman symbol before marker was >9 bits but less than 16 available + 0.56 fix bug: zlib uncompressed mode len vs. nlen + 0.55 fix bug: restart_interval not initialized to 0 + 0.54 allow NULL for 'int *comp' + 0.53 fix bug in png 3->4; speedup png decoding + 0.52 png handles req_comp=3,4 directly; minor cleanup; jpeg comments + 0.51 obey req_comp requests, 1-component jpegs return as 1-component, + on 'test' only check type, not whether we support this variant + 0.50 (2006-11-19) + first released version +*/ diff --git a/Loaders/SoilTextureLoader/SOIL/stb_image_write.h b/Loaders/SoilTextureLoader/SOIL/stb_image_write.h new file mode 100644 index 0000000..ecc285f --- /dev/null +++ b/Loaders/SoilTextureLoader/SOIL/stb_image_write.h @@ -0,0 +1,993 @@ +/* stb_image_write - v1.00 - public domain - http://nothings.org/stb/stb_image_write.h + writes out PNG/BMP/TGA images to C stdio - Sean Barrett 2010-2015 + no warranty implied; use at your own risk + + Before #including, + + #define STB_IMAGE_WRITE_IMPLEMENTATION + + in the file that you want to have the implementation. + + Will probably not work correctly with strict-aliasing optimizations. + +ABOUT: + + This header file is a library for writing images to C stdio. It could be + adapted to write to memory or a general streaming interface; let me know. + + The PNG output is not optimal; it is 20-50% larger than the file + written by a decent optimizing implementation. This library is designed + for source code compactness and simplicity, not optimal image file size + or run-time performance. + +BUILDING: + + You can #define STBIW_ASSERT(x) before the #include to avoid using assert.h. + You can #define STBIW_MALLOC(), STBIW_REALLOC(), and STBIW_FREE() to replace + malloc,realloc,free. + You can define STBIW_MEMMOVE() to replace memmove() + +USAGE: + + There are four functions, one for each image file format: + + int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes); + int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data); + int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data); + int stbi_write_hdr(char const *filename, int w, int h, int comp, const void *data); + + There are also four equivalent functions that use an arbitrary write function. You are + expected to open/close your file-equivalent before and after calling these: + + int stbi_write_png_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data, int stride_in_bytes); + int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data); + int stbi_write_tga_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data); + int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const float *data); + + where the callback is: + void stbi_write_func(void *context, void *data, int size); + + You can define STBI_WRITE_NO_STDIO to disable the file variant of these + functions, so the library will not use stdio.h at all. However, this will + also disable HDR writing, because it requires stdio for formatted output. + + Each function returns 0 on failure and non-0 on success. + + The functions create an image file defined by the parameters. The image + is a rectangle of pixels stored from left-to-right, top-to-bottom. + Each pixel contains 'comp' channels of data stored interleaved with 8-bits + per channel, in the following order: 1=Y, 2=YA, 3=RGB, 4=RGBA. (Y is + monochrome color.) The rectangle is 'w' pixels wide and 'h' pixels tall. + The *data pointer points to the first byte of the top-left-most pixel. + For PNG, "stride_in_bytes" is the distance in bytes from the first byte of + a row of pixels to the first byte of the next row of pixels. + + PNG creates output files with the same number of components as the input. + The BMP format expands Y to RGB in the file format and does not + output alpha. + + PNG supports writing rectangles of data even when the bytes storing rows of + data are not consecutive in memory (e.g. sub-rectangles of a larger image), + by supplying the stride between the beginning of adjacent rows. The other + formats do not. (Thus you cannot write a native-format BMP through the BMP + writer, both because it is in BGR order and because it may have padding + at the end of the line.) + + HDR expects linear float data. Since the format is always 32-bit rgb(e) + data, alpha (if provided) is discarded, and for monochrome data it is + replicated across all three channels. + + TGA supports RLE or non-RLE compressed data. To use non-RLE-compressed + data, set the global variable 'stbi_write_tga_with_rle' to 0. + +CREDITS: + + PNG/BMP/TGA + Sean Barrett + HDR + Baldur Karlsson + TGA monochrome: + Jean-Sebastien Guay + misc enhancements: + Tim Kelsey + TGA RLE + Alan Hickman + initial file IO callback implementation + Emmanuel Julien + bugfixes: + github:Chribba + Guillaume Chereau + github:jry2 + +LICENSE + +This software is in the public domain. Where that dedication is not +recognized, you are granted a perpetual, irrevocable license to copy, +distribute, and modify this file as you see fit. + +*/ + +#ifndef INCLUDE_STB_IMAGE_WRITE_H +#define INCLUDE_STB_IMAGE_WRITE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef STB_IMAGE_WRITE_STATIC +#define STBIWDEF static +#else +#define STBIWDEF extern +extern int stbi_write_tga_with_rle; +#endif + +#ifndef STBI_WRITE_NO_STDIO +STBIWDEF int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes); +STBIWDEF int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data); +STBIWDEF int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data); +STBIWDEF int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *data); +#endif + +typedef void stbi_write_func(void *context, void *data, int size); + +STBIWDEF int stbi_write_png_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data, int stride_in_bytes); +STBIWDEF int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data); +STBIWDEF int stbi_write_tga_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data); +STBIWDEF int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const float *data); + +#ifdef __cplusplus +} +#endif + +#endif//INCLUDE_STB_IMAGE_WRITE_H + +#ifdef STB_IMAGE_WRITE_IMPLEMENTATION + +#ifdef _WIN32 + #define _CRT_SECURE_NO_WARNINGS + #define _CRT_NONSTDC_NO_DEPRECATE +#endif + +#ifndef STBI_WRITE_NO_STDIO +#include +#endif // STBI_WRITE_NO_STDIO + +#include +#include +#include +#include + +#if defined(STBIW_MALLOC) && defined(STBIW_FREE) && defined(STBIW_REALLOC) +// ok +#elif !defined(STBIW_MALLOC) && !defined(STBIW_FREE) && !defined(STBIW_REALLOC) +// ok +#else +#error "Must define all or none of STBIW_MALLOC, STBIW_FREE, and STBIW_REALLOC." +#endif + +#ifndef STBIW_MALLOC +#define STBIW_MALLOC(sz) malloc(sz) +#define STBIW_REALLOC(p,sz) realloc(p,sz) +#define STBIW_FREE(p) free(p) +#endif +#ifndef STBIW_MEMMOVE +#define STBIW_MEMMOVE(a,b,sz) memmove(a,b,sz) +#endif + + +#ifndef STBIW_ASSERT +#include +#define STBIW_ASSERT(x) assert(x) +#endif + +typedef struct +{ + stbi_write_func *func; + void *context; +} stbi__write_context; + +// initialize a callback-based context +static void stbi__start_write_callbacks(stbi__write_context *s, stbi_write_func *c, void *context) +{ + s->func = c; + s->context = context; +} + +#ifndef STBI_WRITE_NO_STDIO + +static void stbi__stdio_write(void *context, void *data, int size) +{ + fwrite(data,1,size,(FILE*) context); +} + +static int stbi__start_write_file(stbi__write_context *s, const char *filename) +{ + FILE *f = fopen(filename, "wb"); + stbi__start_write_callbacks(s, stbi__stdio_write, (void *) f); + return f != NULL; +} + +static void stbi__end_write_file(stbi__write_context *s) +{ + fclose((FILE *)s->context); +} + +#endif // !STBI_WRITE_NO_STDIO + +typedef unsigned int stbiw_uint32; +typedef int stb_image_write_test[sizeof(stbiw_uint32)==4 ? 1 : -1]; + +#ifdef STB_IMAGE_WRITE_STATIC +static int stbi_write_tga_with_rle = 1; +#else +int stbi_write_tga_with_rle = 1; +#endif + +static void stbiw__writefv(stbi__write_context *s, const char *fmt, va_list v) +{ + while (*fmt) { + switch (*fmt++) { + case ' ': break; + case '1': { unsigned char x = (unsigned char) va_arg(v, int); + s->func(s->context,&x,1); + break; } + case '2': { int x = va_arg(v,int); + unsigned char b[2]; + b[0] = (unsigned char) x; + b[1] = (unsigned char) (x>>8); + s->func(s->context,b,2); + break; } + case '4': { stbiw_uint32 x = va_arg(v,int); + unsigned char b[4]; + b[0]=(unsigned char)x; + b[1]=(unsigned char)(x>>8); + b[2]=(unsigned char)(x>>16); + b[3]=(unsigned char)(x>>24); + s->func(s->context,b,4); + break; } + default: + STBIW_ASSERT(0); + return; + } + } +} + +static void stbiw__writef(stbi__write_context *s, const char *fmt, ...) +{ + va_list v; + va_start(v, fmt); + stbiw__writefv(s, fmt, v); + va_end(v); +} + +static void stbiw__write3(stbi__write_context *s, unsigned char a, unsigned char b, unsigned char c) +{ + unsigned char arr[3]; + arr[0] = a, arr[1] = b, arr[2] = c; + s->func(s->context, arr, 3); +} + +static void stbiw__write_pixel(stbi__write_context *s, int rgb_dir, int comp, int write_alpha, int expand_mono, unsigned char *d) +{ + unsigned char bg[3] = { 255, 0, 255}, px[3]; + int k; + + if (write_alpha < 0) + s->func(s->context, &d[comp - 1], 1); + + switch (comp) { + case 1: + s->func(s->context,d,1); + break; + case 2: + if (expand_mono) + stbiw__write3(s, d[0], d[0], d[0]); // monochrome bmp + else + s->func(s->context, d, 1); // monochrome TGA + break; + case 4: + if (!write_alpha) { + // composite against pink background + for (k = 0; k < 3; ++k) + px[k] = bg[k] + ((d[k] - bg[k]) * d[3]) / 255; + stbiw__write3(s, px[1 - rgb_dir], px[1], px[1 + rgb_dir]); + break; + } + /* FALLTHROUGH */ + case 3: + stbiw__write3(s, d[1 - rgb_dir], d[1], d[1 + rgb_dir]); + break; + } + if (write_alpha > 0) + s->func(s->context, &d[comp - 1], 1); +} + +static void stbiw__write_pixels(stbi__write_context *s, int rgb_dir, int vdir, int x, int y, int comp, void *data, int write_alpha, int scanline_pad, int expand_mono) +{ + stbiw_uint32 zero = 0; + int i,j, j_end; + + if (y <= 0) + return; + + if (vdir < 0) + j_end = -1, j = y-1; + else + j_end = y, j = 0; + + for (; j != j_end; j += vdir) { + for (i=0; i < x; ++i) { + unsigned char *d = (unsigned char *) data + (j*x+i)*comp; + stbiw__write_pixel(s, rgb_dir, comp, write_alpha, expand_mono, d); + } + s->func(s->context, &zero, scanline_pad); + } +} + +static int stbiw__outfile(stbi__write_context *s, int rgb_dir, int vdir, int x, int y, int comp, int expand_mono, void *data, int alpha, int pad, const char *fmt, ...) +{ + if (y < 0 || x < 0) { + return 0; + } else { + va_list v; + va_start(v, fmt); + stbiw__writefv(s, fmt, v); + va_end(v); + stbiw__write_pixels(s,rgb_dir,vdir,x,y,comp,data,alpha,pad, expand_mono); + return 1; + } +} + +static int stbi_write_bmp_core(stbi__write_context *s, int x, int y, int comp, const void *data) +{ + int pad = (-x*3) & 3; + return stbiw__outfile(s,-1,-1,x,y,comp,1,(void *) data,0,pad, + "11 4 22 4" "4 44 22 444444", + 'B', 'M', 14+40+(x*3+pad)*y, 0,0, 14+40, // file header + 40, x,y, 1,24, 0,0,0,0,0,0); // bitmap header +} + +STBIWDEF int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data) +{ + stbi__write_context s; + stbi__start_write_callbacks(&s, func, context); + return stbi_write_bmp_core(&s, x, y, comp, data); +} + +#ifndef STBI_WRITE_NO_STDIO +STBIWDEF int stbi_write_bmp(char const *filename, int x, int y, int comp, const void *data) +{ + stbi__write_context s; + if (stbi__start_write_file(&s,filename)) { + int r = stbi_write_bmp_core(&s, x, y, comp, data); + stbi__end_write_file(&s); + return r; + } else + return 0; +} +#endif //!STBI_WRITE_NO_STDIO + +static int stbi_write_tga_core(stbi__write_context *s, int x, int y, int comp, void *data) +{ + int has_alpha = (comp == 2 || comp == 4); + int colorbytes = has_alpha ? comp-1 : comp; + int format = colorbytes < 2 ? 3 : 2; // 3 color channels (RGB/RGBA) = 2, 1 color channel (Y/YA) = 3 + + if (y < 0 || x < 0) + return 0; + + if (!stbi_write_tga_with_rle) { + return stbiw__outfile(s, -1, -1, x, y, comp, 0, (void *) data, has_alpha, 0, + "111 221 2222 11", 0, 0, format, 0, 0, 0, 0, 0, x, y, (colorbytes + has_alpha) * 8, has_alpha * 8); + } else { + int i,j,k; + + stbiw__writef(s, "111 221 2222 11", 0,0,format+8, 0,0,0, 0,0,x,y, (colorbytes + has_alpha) * 8, has_alpha * 8); + + for (j = y - 1; j >= 0; --j) { + unsigned char *row = (unsigned char *) data + j * x * comp; + int len; + + for (i = 0; i < x; i += len) { + unsigned char *begin = row + i * comp; + int diff = 1; + len = 1; + + if (i < x - 1) { + ++len; + diff = memcmp(begin, row + (i + 1) * comp, comp); + if (diff) { + const unsigned char *prev = begin; + for (k = i + 2; k < x && len < 128; ++k) { + if (memcmp(prev, row + k * comp, comp)) { + prev += comp; + ++len; + } else { + --len; + break; + } + } + } else { + for (k = i + 2; k < x && len < 128; ++k) { + if (!memcmp(begin, row + k * comp, comp)) { + ++len; + } else { + break; + } + } + } + } + + if (diff) { + unsigned char header = (unsigned char) (len - 1); + s->func(s->context, &header, 1); + for (k = 0; k < len; ++k) { + stbiw__write_pixel(s, -1, comp, has_alpha, 0, begin + k * comp); + } + } else { + unsigned char header = (unsigned char) (len - 129); + s->func(s->context, &header, 1); + stbiw__write_pixel(s, -1, comp, has_alpha, 0, begin); + } + } + } + } + return 1; +} + +int stbi_write_tga_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data) +{ + stbi__write_context s; + stbi__start_write_callbacks(&s, func, context); + return stbi_write_tga_core(&s, x, y, comp, (void *) data); +} + +#ifndef STBI_WRITE_NO_STDIO +int stbi_write_tga(char const *filename, int x, int y, int comp, const void *data) +{ + stbi__write_context s; + if (stbi__start_write_file(&s,filename)) { + int r = stbi_write_tga_core(&s, x, y, comp, (void *) data); + stbi__end_write_file(&s); + return r; + } else + return 0; +} +#endif + +// ************************************************************************************************* +// Radiance RGBE HDR writer +// by Baldur Karlsson +#ifndef STBI_WRITE_NO_STDIO + +#define stbiw__max(a, b) ((a) > (b) ? (a) : (b)) + +void stbiw__linear_to_rgbe(unsigned char *rgbe, float *linear) +{ + int exponent; + float maxcomp = stbiw__max(linear[0], stbiw__max(linear[1], linear[2])); + + if (maxcomp < 1e-32) { + rgbe[0] = rgbe[1] = rgbe[2] = rgbe[3] = 0; + } else { + float normalize = (float) frexp(maxcomp, &exponent) * 256.0f/maxcomp; + + rgbe[0] = (unsigned char)(linear[0] * normalize); + rgbe[1] = (unsigned char)(linear[1] * normalize); + rgbe[2] = (unsigned char)(linear[2] * normalize); + rgbe[3] = (unsigned char)(exponent + 128); + } +} + +void stbiw__write_run_data(stbi__write_context *s, int length, unsigned char databyte) +{ + unsigned char lengthbyte = (unsigned char) (length+128); + STBIW_ASSERT(length+128 <= 255); + s->func(s->context, &lengthbyte, 1); + s->func(s->context, &databyte, 1); +} + +void stbiw__write_dump_data(stbi__write_context *s, int length, unsigned char *data) +{ + unsigned char lengthbyte = (unsigned char )(length & 0xff); + STBIW_ASSERT(length <= 128); // inconsistent with spec but consistent with official code + s->func(s->context, &lengthbyte, 1); + s->func(s->context, data, length); +} + +void stbiw__write_hdr_scanline(stbi__write_context *s, int width, int ncomp, unsigned char *scratch, float *scanline) +{ + unsigned char scanlineheader[4] = { 2, 2, 0, 0 }; + unsigned char rgbe[4]; + float linear[3]; + int x; + + scanlineheader[2] = (width&0xff00)>>8; + scanlineheader[3] = (width&0x00ff); + + /* skip RLE for images too small or large */ + if (width < 8 || width >= 32768) { + for (x=0; x < width; x++) { + switch (ncomp) { + case 4: /* fallthrough */ + case 3: linear[2] = scanline[x*ncomp + 2]; + linear[1] = scanline[x*ncomp + 1]; + linear[0] = scanline[x*ncomp + 0]; + break; + default: + linear[0] = linear[1] = linear[2] = scanline[x*ncomp + 0]; + break; + } + stbiw__linear_to_rgbe(rgbe, linear); + s->func(s->context, rgbe, 4); + } + } else { + int c,r; + /* encode into scratch buffer */ + for (x=0; x < width; x++) { + switch(ncomp) { + case 4: /* fallthrough */ + case 3: linear[2] = scanline[x*ncomp + 2]; + linear[1] = scanline[x*ncomp + 1]; + linear[0] = scanline[x*ncomp + 0]; + break; + default: + linear[0] = linear[1] = linear[2] = scanline[x*ncomp + 0]; + break; + } + stbiw__linear_to_rgbe(rgbe, linear); + scratch[x + width*0] = rgbe[0]; + scratch[x + width*1] = rgbe[1]; + scratch[x + width*2] = rgbe[2]; + scratch[x + width*3] = rgbe[3]; + } + + s->func(s->context, scanlineheader, 4); + + /* RLE each component separately */ + for (c=0; c < 4; c++) { + unsigned char *comp = &scratch[width*c]; + + x = 0; + while (x < width) { + // find first run + r = x; + while (r+2 < width) { + if (comp[r] == comp[r+1] && comp[r] == comp[r+2]) + break; + ++r; + } + if (r+2 >= width) + r = width; + // dump up to first run + while (x < r) { + int len = r-x; + if (len > 128) len = 128; + stbiw__write_dump_data(s, len, &comp[x]); + x += len; + } + // if there's a run, output it + if (r+2 < width) { // same test as what we break out of in search loop, so only true if we break'd + // find next byte after run + while (r < width && comp[r] == comp[x]) + ++r; + // output run up to r + while (x < r) { + int len = r-x; + if (len > 127) len = 127; + stbiw__write_run_data(s, len, comp[x]); + x += len; + } + } + } + } + } +} + +static int stbi_write_hdr_core(stbi__write_context *s, int x, int y, int comp, float *data) +{ + if (y <= 0 || x <= 0 || data == NULL) + return 0; + else { + // Each component is stored separately. Allocate scratch space for full output scanline. + unsigned char *scratch = (unsigned char *) STBIW_MALLOC(x*4); + int i, len; + char buffer[128]; + char header[] = "#?RADIANCE\n# Written by stb_image_write.h\nFORMAT=32-bit_rle_rgbe\n"; + s->func(s->context, header, sizeof(header)-1); + + len = sprintf(buffer, "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x); + s->func(s->context, buffer, len); + + for(i=0; i < y; i++) + stbiw__write_hdr_scanline(s, x, comp, scratch, data + comp*i*x); + STBIW_FREE(scratch); + return 1; + } +} + +int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const float *data) +{ + stbi__write_context s; + stbi__start_write_callbacks(&s, func, context); + return stbi_write_hdr_core(&s, x, y, comp, (float *) data); +} + +int stbi_write_hdr(char const *filename, int x, int y, int comp, const float *data) +{ + stbi__write_context s; + if (stbi__start_write_file(&s,filename)) { + int r = stbi_write_hdr_core(&s, x, y, comp, (float *) data); + stbi__end_write_file(&s); + return r; + } else + return 0; +} +#endif // STBI_WRITE_NO_STDIO + + +////////////////////////////////////////////////////////////////////////////// +// +// PNG writer +// + +// stretchy buffer; stbiw__sbpush() == vector<>::push_back() -- stbiw__sbcount() == vector<>::size() +#define stbiw__sbraw(a) ((int *) (a) - 2) +#define stbiw__sbm(a) stbiw__sbraw(a)[0] +#define stbiw__sbn(a) stbiw__sbraw(a)[1] + +#define stbiw__sbneedgrow(a,n) ((a)==0 || stbiw__sbn(a)+n >= stbiw__sbm(a)) +#define stbiw__sbmaybegrow(a,n) (stbiw__sbneedgrow(a,(n)) ? stbiw__sbgrow(a,n) : 0) +#define stbiw__sbgrow(a,n) stbiw__sbgrowf((void **) &(a), (n), sizeof(*(a))) + +#define stbiw__sbpush(a, v) (stbiw__sbmaybegrow(a,1), (a)[stbiw__sbn(a)++] = (v)) +#define stbiw__sbcount(a) ((a) ? stbiw__sbn(a) : 0) +#define stbiw__sbfree(a) ((a) ? STBIW_FREE(stbiw__sbraw(a)),0 : 0) + +static void *stbiw__sbgrowf(void **arr, int increment, int itemsize) +{ + int m = *arr ? 2*stbiw__sbm(*arr)+increment : increment+1; + void *p = STBIW_REALLOC(*arr ? stbiw__sbraw(*arr) : 0, itemsize * m + sizeof(int)*2); + STBIW_ASSERT(p); + if (p) { + if (!*arr) ((int *) p)[1] = 0; + *arr = (void *) ((int *) p + 2); + stbiw__sbm(*arr) = m; + } + return *arr; +} + +static unsigned char *stbiw__zlib_flushf(unsigned char *data, unsigned int *bitbuffer, int *bitcount) +{ + while (*bitcount >= 8) { + stbiw__sbpush(data, (unsigned char) *bitbuffer); + *bitbuffer >>= 8; + *bitcount -= 8; + } + return data; +} + +static int stbiw__zlib_bitrev(int code, int codebits) +{ + int res=0; + while (codebits--) { + res = (res << 1) | (code & 1); + code >>= 1; + } + return res; +} + +static unsigned int stbiw__zlib_countm(unsigned char *a, unsigned char *b, int limit) +{ + int i; + for (i=0; i < limit && i < 258; ++i) + if (a[i] != b[i]) break; + return i; +} + +static unsigned int stbiw__zhash(unsigned char *data) +{ + stbiw_uint32 hash = data[0] + (data[1] << 8) + (data[2] << 16); + hash ^= hash << 3; + hash += hash >> 5; + hash ^= hash << 4; + hash += hash >> 17; + hash ^= hash << 25; + hash += hash >> 6; + return hash; +} + +#define stbiw__zlib_flush() (out = stbiw__zlib_flushf(out, &bitbuf, &bitcount)) +#define stbiw__zlib_add(code,codebits) \ + (bitbuf |= (code) << bitcount, bitcount += (codebits), stbiw__zlib_flush()) +#define stbiw__zlib_huffa(b,c) stbiw__zlib_add(stbiw__zlib_bitrev(b,c),c) +// default huffman tables +#define stbiw__zlib_huff1(n) stbiw__zlib_huffa(0x30 + (n), 8) +#define stbiw__zlib_huff2(n) stbiw__zlib_huffa(0x190 + (n)-144, 9) +#define stbiw__zlib_huff3(n) stbiw__zlib_huffa(0 + (n)-256,7) +#define stbiw__zlib_huff4(n) stbiw__zlib_huffa(0xc0 + (n)-280,8) +#define stbiw__zlib_huff(n) ((n) <= 143 ? stbiw__zlib_huff1(n) : (n) <= 255 ? stbiw__zlib_huff2(n) : (n) <= 279 ? stbiw__zlib_huff3(n) : stbiw__zlib_huff4(n)) +#define stbiw__zlib_huffb(n) ((n) <= 143 ? stbiw__zlib_huff1(n) : stbiw__zlib_huff2(n)) + +#define stbiw__ZHASH 16384 + +unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_len, int quality) +{ + static unsigned short lengthc[] = { 3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258, 259 }; + static unsigned char lengtheb[]= { 0,0,0,0,0,0,0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0 }; + static unsigned short distc[] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577, 32768 }; + static unsigned char disteb[] = { 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13 }; + unsigned int bitbuf=0; + int i,j, bitcount=0; + unsigned char *out = NULL; + unsigned char **hash_table[stbiw__ZHASH]; // 64KB on the stack! + if (quality < 5) quality = 5; + + stbiw__sbpush(out, 0x78); // DEFLATE 32K window + stbiw__sbpush(out, 0x5e); // FLEVEL = 1 + stbiw__zlib_add(1,1); // BFINAL = 1 + stbiw__zlib_add(1,2); // BTYPE = 1 -- fixed huffman + + for (i=0; i < stbiw__ZHASH; ++i) + hash_table[i] = NULL; + + i=0; + while (i < data_len-3) { + // hash next 3 bytes of data to be compressed + int h = stbiw__zhash(data+i)&(stbiw__ZHASH-1), best=3; + unsigned char *bestloc = 0; + unsigned char **hlist = hash_table[h]; + int n = stbiw__sbcount(hlist); + for (j=0; j < n; ++j) { + if (hlist[j]-data > i-32768) { // if entry lies within window + int d = stbiw__zlib_countm(hlist[j], data+i, data_len-i); + if (d >= best) best=d,bestloc=hlist[j]; + } + } + // when hash table entry is too long, delete half the entries + if (hash_table[h] && stbiw__sbn(hash_table[h]) == 2*quality) { + STBIW_MEMMOVE(hash_table[h], hash_table[h]+quality, sizeof(hash_table[h][0])*quality); + stbiw__sbn(hash_table[h]) = quality; + } + stbiw__sbpush(hash_table[h],data+i); + + if (bestloc) { + // "lazy matching" - check match at *next* byte, and if it's better, do cur byte as literal + h = stbiw__zhash(data+i+1)&(stbiw__ZHASH-1); + hlist = hash_table[h]; + n = stbiw__sbcount(hlist); + for (j=0; j < n; ++j) { + if (hlist[j]-data > i-32767) { + int e = stbiw__zlib_countm(hlist[j], data+i+1, data_len-i-1); + if (e > best) { // if next match is better, bail on current match + bestloc = NULL; + break; + } + } + } + } + + if (bestloc) { + int d = (int) (data+i - bestloc); // distance back + STBIW_ASSERT(d <= 32767 && best <= 258); + for (j=0; best > lengthc[j+1]-1; ++j); + stbiw__zlib_huff(j+257); + if (lengtheb[j]) stbiw__zlib_add(best - lengthc[j], lengtheb[j]); + for (j=0; d > distc[j+1]-1; ++j); + stbiw__zlib_add(stbiw__zlib_bitrev(j,5),5); + if (disteb[j]) stbiw__zlib_add(d - distc[j], disteb[j]); + i += best; + } else { + stbiw__zlib_huffb(data[i]); + ++i; + } + } + // write out final bytes + for (;i < data_len; ++i) + stbiw__zlib_huffb(data[i]); + stbiw__zlib_huff(256); // end of block + // pad with 0 bits to byte boundary + while (bitcount) + stbiw__zlib_add(0,1); + + for (i=0; i < stbiw__ZHASH; ++i) + (void) stbiw__sbfree(hash_table[i]); + + { + // compute adler32 on input + unsigned int s1=1, s2=0; + int blocklen = (int) (data_len % 5552); + j=0; + while (j < data_len) { + for (i=0; i < blocklen; ++i) s1 += data[j+i], s2 += s1; + s1 %= 65521, s2 %= 65521; + j += blocklen; + blocklen = 5552; + } + stbiw__sbpush(out, (unsigned char) (s2 >> 8)); + stbiw__sbpush(out, (unsigned char) s2); + stbiw__sbpush(out, (unsigned char) (s1 >> 8)); + stbiw__sbpush(out, (unsigned char) s1); + } + *out_len = stbiw__sbn(out); + // make returned pointer freeable + STBIW_MEMMOVE(stbiw__sbraw(out), out, *out_len); + return (unsigned char *) stbiw__sbraw(out); +} + +unsigned int stbiw__crc32(unsigned char *buffer, int len) +{ + static unsigned int crc_table[256]; + unsigned int crc = ~0u; + int i,j; + if (crc_table[1] == 0) + for(i=0; i < 256; i++) + for (crc_table[i]=i, j=0; j < 8; ++j) + crc_table[i] = (crc_table[i] >> 1) ^ (crc_table[i] & 1 ? 0xedb88320 : 0); + for (i=0; i < len; ++i) + crc = (crc >> 8) ^ crc_table[buffer[i] ^ (crc & 0xff)]; + return ~crc; +} + +#define stbiw__wpng4(o,a,b,c,d) ((o)[0]=(unsigned char)(a),(o)[1]=(unsigned char)(b),(o)[2]=(unsigned char)(c),(o)[3]=(unsigned char)(d),(o)+=4) +#define stbiw__wp32(data,v) stbiw__wpng4(data, (v)>>24,(v)>>16,(v)>>8,(v)); +#define stbiw__wptag(data,s) stbiw__wpng4(data, s[0],s[1],s[2],s[3]) + +static void stbiw__wpcrc(unsigned char **data, int len) +{ + unsigned int crc = stbiw__crc32(*data - len - 4, len+4); + stbiw__wp32(*data, crc); +} + +static unsigned char stbiw__paeth(int a, int b, int c) +{ + int p = a + b - c, pa = abs(p-a), pb = abs(p-b), pc = abs(p-c); + if (pa <= pb && pa <= pc) return (unsigned char) a; + if (pb <= pc) return (unsigned char) b; + return (unsigned char) c; +} + +unsigned char *stbi_write_png_to_mem(unsigned char *pixels, int stride_bytes, int x, int y, int n, int *out_len) +{ + int ctype[5] = { -1, 0, 4, 2, 6 }; + unsigned char sig[8] = { 137,80,78,71,13,10,26,10 }; + unsigned char *out,*o, *filt, *zlib; + signed char *line_buffer; + int i,j,k,p,zlen; + + if (stride_bytes == 0) + stride_bytes = x * n; + + filt = (unsigned char *) STBIW_MALLOC((x*n+1) * y); if (!filt) return 0; + line_buffer = (signed char *) STBIW_MALLOC(x * n); if (!line_buffer) { STBIW_FREE(filt); return 0; } + for (j=0; j < y; ++j) { + static int mapping[] = { 0,1,2,3,4 }; + static int firstmap[] = { 0,1,0,5,6 }; + int *mymap = j ? mapping : firstmap; + int best = 0, bestval = 0x7fffffff; + for (p=0; p < 2; ++p) { + for (k= p?best:0; k < 5; ++k) { + int type = mymap[k],est=0; + unsigned char *z = pixels + stride_bytes*j; + for (i=0; i < n; ++i) + switch (type) { + case 0: line_buffer[i] = z[i]; break; + case 1: line_buffer[i] = z[i]; break; + case 2: line_buffer[i] = z[i] - z[i-stride_bytes]; break; + case 3: line_buffer[i] = z[i] - (z[i-stride_bytes]>>1); break; + case 4: line_buffer[i] = (signed char) (z[i] - stbiw__paeth(0,z[i-stride_bytes],0)); break; + case 5: line_buffer[i] = z[i]; break; + case 6: line_buffer[i] = z[i]; break; + } + for (i=n; i < x*n; ++i) { + switch (type) { + case 0: line_buffer[i] = z[i]; break; + case 1: line_buffer[i] = z[i] - z[i-n]; break; + case 2: line_buffer[i] = z[i] - z[i-stride_bytes]; break; + case 3: line_buffer[i] = z[i] - ((z[i-n] + z[i-stride_bytes])>>1); break; + case 4: line_buffer[i] = z[i] - stbiw__paeth(z[i-n], z[i-stride_bytes], z[i-stride_bytes-n]); break; + case 5: line_buffer[i] = z[i] - (z[i-n]>>1); break; + case 6: line_buffer[i] = z[i] - stbiw__paeth(z[i-n], 0,0); break; + } + } + if (p) break; + for (i=0; i < x*n; ++i) + est += abs((signed char) line_buffer[i]); + if (est < bestval) { bestval = est; best = k; } + } + } + // when we get here, best contains the filter type, and line_buffer contains the data + filt[j*(x*n+1)] = (unsigned char) best; + STBIW_MEMMOVE(filt+j*(x*n+1)+1, line_buffer, x*n); + } + STBIW_FREE(line_buffer); + zlib = stbi_zlib_compress(filt, y*( x*n+1), &zlen, 8); // increase 8 to get smaller but use more memory + STBIW_FREE(filt); + if (!zlib) return 0; + + // each tag requires 12 bytes of overhead + out = (unsigned char *) STBIW_MALLOC(8 + 12+13 + 12+zlen + 12); + if (!out) return 0; + *out_len = 8 + 12+13 + 12+zlen + 12; + + o=out; + STBIW_MEMMOVE(o,sig,8); o+= 8; + stbiw__wp32(o, 13); // header length + stbiw__wptag(o, "IHDR"); + stbiw__wp32(o, x); + stbiw__wp32(o, y); + *o++ = 8; + *o++ = (unsigned char) ctype[n]; + *o++ = 0; + *o++ = 0; + *o++ = 0; + stbiw__wpcrc(&o,13); + + stbiw__wp32(o, zlen); + stbiw__wptag(o, "IDAT"); + STBIW_MEMMOVE(o, zlib, zlen); + o += zlen; + STBIW_FREE(zlib); + stbiw__wpcrc(&o, zlen); + + stbiw__wp32(o,0); + stbiw__wptag(o, "IEND"); + stbiw__wpcrc(&o,0); + + STBIW_ASSERT(o == out + *out_len); + + return out; +} + +#ifndef STBI_WRITE_NO_STDIO +STBIWDEF int stbi_write_png(char const *filename, int x, int y, int comp, const void *data, int stride_bytes) +{ + FILE *f; + int len; + unsigned char *png = stbi_write_png_to_mem((unsigned char *) data, stride_bytes, x, y, comp, &len); + if (png == NULL) return 0; + f = fopen(filename, "wb"); + if (!f) { STBIW_FREE(png); return 0; } + fwrite(png, 1, len, f); + fclose(f); + STBIW_FREE(png); + return 1; +} +#endif + +STBIWDEF int stbi_write_png_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int stride_bytes) +{ + int len; + unsigned char *png = stbi_write_png_to_mem((unsigned char *) data, stride_bytes, x, y, comp, &len); + if (png == NULL) return 0; + func(context, png, len); + STBIW_FREE(png); + return 1; +} + +#endif // STB_IMAGE_WRITE_IMPLEMENTATION + +/* Revision history + 1.00 (2015-09-14) + installable file IO function + 0.99 (2015-09-13) + warning fixes; TGA rle support + 0.98 (2015-04-08) + added STBIW_MALLOC, STBIW_ASSERT etc + 0.97 (2015-01-18) + fixed HDR asserts, rewrote HDR rle logic + 0.96 (2015-01-17) + add HDR output + fix monochrome BMP + 0.95 (2014-08-17) + add monochrome TGA output + 0.94 (2014-05-31) + rename private functions to avoid conflicts with stb_image.h + 0.93 (2014-05-27) + warning fixes + 0.92 (2010-08-01) + casts to unsigned char to fix warnings + 0.91 (2010-07-17) + first public release + 0.90 first internal release +*/ diff --git a/Loaders/SoilTextureLoader/SOIL/stbi_DDS.h b/Loaders/SoilTextureLoader/SOIL/stbi_DDS.h new file mode 100644 index 0000000..4994d1d --- /dev/null +++ b/Loaders/SoilTextureLoader/SOIL/stbi_DDS.h @@ -0,0 +1,34 @@ +/* + adding DDS loading support to stbi +*/ + +#ifndef HEADER_STB_IMAGE_DDS_AUGMENTATION +#define HEADER_STB_IMAGE_DDS_AUGMENTATION + +/* is it a DDS file? */ +extern int stbi__dds_test_memory (stbi_uc const *buffer, int len); +extern int stbi__dds_test_callbacks (stbi_io_callbacks const *clbk, void *user); + +extern stbi_uc *stbi__dds_load_from_path (const char *filename, int *x, int *y, int *comp, int req_comp); +extern stbi_uc *stbi__dds_load_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp); +extern stbi_uc *stbi__dds_load_from_callbacks (stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp); + +#ifndef STBI_NO_STDIO +extern int stbi__dds_test_filename (char const *filename); +extern int stbi__dds_test_file (FILE *f); +extern stbi_uc *stbi__dds_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp); +#endif + +extern int stbi__dds_info_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int *iscompressed); +extern int stbi__dds_info_from_callbacks (stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int *iscompressed); + + +#ifndef STBI_NO_STDIO +extern int stbi__dds_info_from_path (char const *filename, int *x, int *y, int *comp, int *iscompressed); +extern int stbi__dds_info_from_file (FILE *f, int *x, int *y, int *comp, int *iscompressed); +#endif + +/* +// +//// end header file /////////////////////////////////////////////////////*/ +#endif /* HEADER_STB_IMAGE_DDS_AUGMENTATION */ diff --git a/Loaders/SoilTextureLoader/SOIL/stbi_DDS_c.h b/Loaders/SoilTextureLoader/SOIL/stbi_DDS_c.h new file mode 100644 index 0000000..97e9ad9 --- /dev/null +++ b/Loaders/SoilTextureLoader/SOIL/stbi_DDS_c.h @@ -0,0 +1,589 @@ + +/// DDS file support, does decoding, _not_ direct uploading +/// (use SOIL for that ;-) + +#include "image_DXT.h" + +static int stbi__dds_test(stbi__context *s) +{ + // check the magic number + if (stbi__get8(s) != 'D') { + stbi__rewind(s); + return 0; + } + + if (stbi__get8(s) != 'D') { + stbi__rewind(s); + return 0; + } + + if (stbi__get8(s) != 'S') { + stbi__rewind(s); + return 0; + } + + if (stbi__get8(s) != ' ') { + stbi__rewind(s); + return 0; + } + + // check header size + if (stbi__get32le(s) != 124) { + stbi__rewind(s); + return 0; + } + + // Also rewind because the loader needs to read the header + stbi__rewind(s); + + return 1; +} +#ifndef STBI_NO_STDIO + +int stbi__dds_test_filename (char const *filename) +{ + int r; + FILE *f = fopen(filename, "rb"); + if (!f) return 0; + r = stbi__dds_test_file(f); + fclose(f); + return r; +} + +int stbi__dds_test_file (FILE *f) +{ + stbi__context s; + int r,n = ftell(f); + stbi__start_file(&s,f); + r = stbi__dds_test(&s); + fseek(f,n,SEEK_SET); + return r; +} +#endif + +int stbi__dds_test_memory (stbi_uc const *buffer, int len) +{ + stbi__context s; + stbi__start_mem(&s,buffer, len); + return stbi__dds_test(&s); +} + +int stbi__dds_test_callbacks (stbi_io_callbacks const *clbk, void *user) +{ + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); + return stbi__dds_test(&s); +} + +// helper functions +int stbi_convert_bit_range( int c, int from_bits, int to_bits ) +{ + int b = (1 << (from_bits - 1)) + c * ((1 << to_bits) - 1); + return (b + (b >> from_bits)) >> from_bits; +} +void stbi_rgb_888_from_565( unsigned int c, int *r, int *g, int *b ) +{ + *r = stbi_convert_bit_range( (c >> 11) & 31, 5, 8 ); + *g = stbi_convert_bit_range( (c >> 05) & 63, 6, 8 ); + *b = stbi_convert_bit_range( (c >> 00) & 31, 5, 8 ); +} +void stbi_decode_DXT1_block( + unsigned char uncompressed[16*4], + unsigned char compressed[8] ) +{ + int next_bit = 4*8; + int i, r, g, b; + int c0, c1; + unsigned char decode_colors[4*4]; + // find the 2 primary colors + c0 = compressed[0] + (compressed[1] << 8); + c1 = compressed[2] + (compressed[3] << 8); + stbi_rgb_888_from_565( c0, &r, &g, &b ); + decode_colors[0] = r; + decode_colors[1] = g; + decode_colors[2] = b; + decode_colors[3] = 255; + stbi_rgb_888_from_565( c1, &r, &g, &b ); + decode_colors[4] = r; + decode_colors[5] = g; + decode_colors[6] = b; + decode_colors[7] = 255; + if( c0 > c1 ) + { + // no alpha, 2 interpolated colors + decode_colors[8] = (2*decode_colors[0] + decode_colors[4]) / 3; + decode_colors[9] = (2*decode_colors[1] + decode_colors[5]) / 3; + decode_colors[10] = (2*decode_colors[2] + decode_colors[6]) / 3; + decode_colors[11] = 255; + decode_colors[12] = (decode_colors[0] + 2*decode_colors[4]) / 3; + decode_colors[13] = (decode_colors[1] + 2*decode_colors[5]) / 3; + decode_colors[14] = (decode_colors[2] + 2*decode_colors[6]) / 3; + decode_colors[15] = 255; + } else + { + // 1 interpolated color, alpha + decode_colors[8] = (decode_colors[0] + decode_colors[4]) / 2; + decode_colors[9] = (decode_colors[1] + decode_colors[5]) / 2; + decode_colors[10] = (decode_colors[2] + decode_colors[6]) / 2; + decode_colors[11] = 255; + decode_colors[12] = 0; + decode_colors[13] = 0; + decode_colors[14] = 0; + decode_colors[15] = 0; + } + // decode the block + for( i = 0; i < 16*4; i += 4 ) + { + int idx = ((compressed[next_bit>>3] >> (next_bit & 7)) & 3) * 4; + next_bit += 2; + uncompressed[i+0] = decode_colors[idx+0]; + uncompressed[i+1] = decode_colors[idx+1]; + uncompressed[i+2] = decode_colors[idx+2]; + uncompressed[i+3] = decode_colors[idx+3]; + } + // done +} +void stbi_decode_DXT23_alpha_block( + unsigned char uncompressed[16*4], + unsigned char compressed[8] ) +{ + int i, next_bit = 0; + // each alpha value gets 4 bits + for( i = 3; i < 16*4; i += 4 ) + { + uncompressed[i] = stbi_convert_bit_range( + (compressed[next_bit>>3] >> (next_bit&7)) & 15, + 4, 8 ); + next_bit += 4; + } +} +void stbi_decode_DXT45_alpha_block( + unsigned char uncompressed[16*4], + unsigned char compressed[8] ) +{ + int i, next_bit = 8*2; + unsigned char decode_alpha[8]; + // each alpha value gets 3 bits, and the 1st 2 bytes are the range + decode_alpha[0] = compressed[0]; + decode_alpha[1] = compressed[1]; + if( decode_alpha[0] > decode_alpha[1] ) + { + // 6 step intermediate + decode_alpha[2] = (6*decode_alpha[0] + 1*decode_alpha[1]) / 7; + decode_alpha[3] = (5*decode_alpha[0] + 2*decode_alpha[1]) / 7; + decode_alpha[4] = (4*decode_alpha[0] + 3*decode_alpha[1]) / 7; + decode_alpha[5] = (3*decode_alpha[0] + 4*decode_alpha[1]) / 7; + decode_alpha[6] = (2*decode_alpha[0] + 5*decode_alpha[1]) / 7; + decode_alpha[7] = (1*decode_alpha[0] + 6*decode_alpha[1]) / 7; + } else + { + // 4 step intermediate, pluss full and none + decode_alpha[2] = (4*decode_alpha[0] + 1*decode_alpha[1]) / 5; + decode_alpha[3] = (3*decode_alpha[0] + 2*decode_alpha[1]) / 5; + decode_alpha[4] = (2*decode_alpha[0] + 3*decode_alpha[1]) / 5; + decode_alpha[5] = (1*decode_alpha[0] + 4*decode_alpha[1]) / 5; + decode_alpha[6] = 0; + decode_alpha[7] = 255; + } + for( i = 3; i < 16*4; i += 4 ) + { + int idx = 0, bit; + bit = (compressed[next_bit>>3] >> (next_bit&7)) & 1; + idx += bit << 0; + ++next_bit; + bit = (compressed[next_bit>>3] >> (next_bit&7)) & 1; + idx += bit << 1; + ++next_bit; + bit = (compressed[next_bit>>3] >> (next_bit&7)) & 1; + idx += bit << 2; + ++next_bit; + uncompressed[i] = decode_alpha[idx & 7]; + } + // done +} +void stbi_decode_DXT_color_block( + unsigned char uncompressed[16*4], + unsigned char compressed[8] ) +{ + int next_bit = 4*8; + int i, r, g, b; + int c0, c1; + unsigned char decode_colors[4*3]; + // find the 2 primary colors + c0 = compressed[0] + (compressed[1] << 8); + c1 = compressed[2] + (compressed[3] << 8); + stbi_rgb_888_from_565( c0, &r, &g, &b ); + decode_colors[0] = r; + decode_colors[1] = g; + decode_colors[2] = b; + stbi_rgb_888_from_565( c1, &r, &g, &b ); + decode_colors[3] = r; + decode_colors[4] = g; + decode_colors[5] = b; + // Like DXT1, but no choicees: + // no alpha, 2 interpolated colors + decode_colors[6] = (2*decode_colors[0] + decode_colors[3]) / 3; + decode_colors[7] = (2*decode_colors[1] + decode_colors[4]) / 3; + decode_colors[8] = (2*decode_colors[2] + decode_colors[5]) / 3; + decode_colors[9] = (decode_colors[0] + 2*decode_colors[3]) / 3; + decode_colors[10] = (decode_colors[1] + 2*decode_colors[4]) / 3; + decode_colors[11] = (decode_colors[2] + 2*decode_colors[5]) / 3; + // decode the block + for( i = 0; i < 16*4; i += 4 ) + { + int idx = ((compressed[next_bit>>3] >> (next_bit & 7)) & 3) * 3; + next_bit += 2; + uncompressed[i+0] = decode_colors[idx+0]; + uncompressed[i+1] = decode_colors[idx+1]; + uncompressed[i+2] = decode_colors[idx+2]; + } + // done +} + +static int stbi__dds_info( stbi__context *s, int *x, int *y, int *comp, int *iscompressed ) { + int flags,is_compressed,has_alpha; + DDS_header header={0}; + + if( sizeof( DDS_header ) != 128 ) + { + return 0; + } + + stbi__getn( s, (stbi_uc*)(&header), 128 ); + + if( header.dwMagic != (('D' << 0) | ('D' << 8) | ('S' << 16) | (' ' << 24)) ) { + stbi__rewind( s ); + return 0; + } + if( header.dwSize != 124 ) { + stbi__rewind( s ); + return 0; + } + flags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT; + if( (header.dwFlags & flags) != flags ) { + stbi__rewind( s ); + return 0; + } + if( header.sPixelFormat.dwSize != 32 ) { + stbi__rewind( s ); + return 0; + } + flags = DDPF_FOURCC | DDPF_RGB; + if( (header.sPixelFormat.dwFlags & flags) == 0 ) { + stbi__rewind( s ); + return 0; + } + if( (header.sCaps.dwCaps1 & DDSCAPS_TEXTURE) == 0 ) { + stbi__rewind( s ); + return 0; + } + + is_compressed = (header.sPixelFormat.dwFlags & DDPF_FOURCC) / DDPF_FOURCC; + has_alpha = (header.sPixelFormat.dwFlags & DDPF_ALPHAPIXELS) / DDPF_ALPHAPIXELS; + + *x = header.dwWidth; + *y = header.dwHeight; + + if ( !is_compressed ) { + *comp = 3; + + if ( has_alpha ) + *comp = 4; + } + else + *comp = 4; + + if ( iscompressed ) + *iscompressed = is_compressed; + + return 1; +} + +int stbi__dds_info_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int *iscompressed) +{ + stbi__context s; + stbi__start_mem(&s,buffer, len); + return stbi__dds_info( &s, x, y, comp, iscompressed ); +} + +int stbi__dds_info_from_callbacks (stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int *iscompressed) +{ + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); + return stbi__dds_info( &s, x, y, comp, iscompressed ); +} + +#ifndef STBI_NO_STDIO +int stbi__dds_info_from_path(char const *filename, int *x, int *y, int *comp, int *iscompressed) +{ + int res; + FILE *f = fopen(filename, "rb"); + if (!f) return 0; + res = stbi__dds_info_from_file( f, x, y, comp, iscompressed ); + fclose(f); + return res; +} + +int stbi__dds_info_from_file(FILE *f, int *x, int *y, int *comp, int *iscompressed) +{ + stbi__context s; + int res; + long n = ftell(f); + stbi__start_file(&s, f); + res = stbi__dds_info(&s, x, y, comp, iscompressed); + fseek(f, n, SEEK_SET); + return res; +} +#endif + +static stbi_uc * stbi__dds_load(stbi__context *s, int *x, int *y, int *comp, int req_comp) +{ + // all variables go up front + stbi_uc *dds_data = NULL; + stbi_uc block[16*4]; + stbi_uc compressed[8]; + int flags, DXT_family; + int has_alpha, has_mipmap; + int is_compressed, cubemap_faces; + int block_pitch, num_blocks; + DDS_header header={0}; + int i, sz, cf; + // load the header + if( sizeof( DDS_header ) != 128 ) + { + return NULL; + } + stbi__getn( s, (stbi_uc*)(&header), 128 ); + // and do some checking + if( header.dwMagic != (('D' << 0) | ('D' << 8) | ('S' << 16) | (' ' << 24)) ) return NULL; + if( header.dwSize != 124 ) return NULL; + flags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT; + if( (header.dwFlags & flags) != flags ) return NULL; + /* According to the MSDN spec, the dwFlags should contain + DDSD_LINEARSIZE if it's compressed, or DDSD_PITCH if + uncompressed. Some DDS writers do not conform to the + spec, so I need to make my reader more tolerant */ + if( header.sPixelFormat.dwSize != 32 ) return NULL; + flags = DDPF_FOURCC | DDPF_RGB; + if( (header.sPixelFormat.dwFlags & flags) == 0 ) return NULL; + if( (header.sCaps.dwCaps1 & DDSCAPS_TEXTURE) == 0 ) return NULL; + // get the image data + s->img_x = header.dwWidth; + s->img_y = header.dwHeight; + s->img_n = 4; + is_compressed = (header.sPixelFormat.dwFlags & DDPF_FOURCC) / DDPF_FOURCC; + has_alpha = (header.sPixelFormat.dwFlags & DDPF_ALPHAPIXELS) / DDPF_ALPHAPIXELS; + has_mipmap = (header.sCaps.dwCaps1 & DDSCAPS_MIPMAP) && (header.dwMipMapCount > 1); + cubemap_faces = (header.sCaps.dwCaps2 & DDSCAPS2_CUBEMAP) / DDSCAPS2_CUBEMAP; + /* I need cubemaps to have square faces */ + cubemap_faces &= (s->img_x == s->img_y); + cubemap_faces *= 5; + cubemap_faces += 1; + block_pitch = (s->img_x+3) >> 2; + num_blocks = block_pitch * ((s->img_y+3) >> 2); + /* let the user know what's going on */ + *x = s->img_x; + *y = s->img_y; + *comp = s->img_n; + /* is this uncompressed? */ + if( is_compressed ) + { + /* compressed */ + // note: header.sPixelFormat.dwFourCC is something like (('D'<<0)|('X'<<8)|('T'<<16)|('1'<<24)) + DXT_family = 1 + (header.sPixelFormat.dwFourCC >> 24) - '1'; + if( (DXT_family < 1) || (DXT_family > 5) ) return NULL; + /* check the expected size...oops, nevermind... + those non-compliant writers leave + dwPitchOrLinearSize == 0 */ + // passed all the tests, get the RAM for decoding + sz = (s->img_x)*(s->img_y)*4*cubemap_faces; + dds_data = (unsigned char*)malloc( sz ); + /* do this once for each face */ + for( cf = 0; cf < cubemap_faces; ++ cf ) + { + // now read and decode all the blocks + for( i = 0; i < num_blocks; ++i ) + { + // where are we? + int bx, by, bw=4, bh=4; + int ref_x = 4 * (i % block_pitch); + int ref_y = 4 * (i / block_pitch); + // get the next block's worth of compressed data, and decompress it + if( DXT_family == 1 ) + { + // DXT1 + stbi__getn( s, compressed, 8 ); + stbi_decode_DXT1_block( block, compressed ); + } else if( DXT_family < 4 ) + { + // DXT2/3 + stbi__getn( s, compressed, 8 ); + stbi_decode_DXT23_alpha_block ( block, compressed ); + stbi__getn( s, compressed, 8 ); + stbi_decode_DXT_color_block ( block, compressed ); + } else + { + // DXT4/5 + stbi__getn( s, compressed, 8 ); + stbi_decode_DXT45_alpha_block ( block, compressed ); + stbi__getn( s, compressed, 8 ); + stbi_decode_DXT_color_block ( block, compressed ); + } + // is this a partial block? + if( ref_x + 4 > (int)s->img_x ) + { + bw = s->img_x - ref_x; + } + if( ref_y + 4 > (int)s->img_y ) + { + bh = s->img_y - ref_y; + } + // now drop our decompressed data into the buffer + for( by = 0; by < bh; ++by ) + { + int idx = 4*((ref_y+by+cf*s->img_x)*s->img_x + ref_x); + for( bx = 0; bx < bw*4; ++bx ) + { + + dds_data[idx+bx] = block[by*16+bx]; + } + } + } + /* done reading and decoding the main image... + stbi__skip MIPmaps if present */ + if( has_mipmap ) + { + int block_size = 16; + if( DXT_family == 1 ) + { + block_size = 8; + } + for( i = 1; i < (int)header.dwMipMapCount; ++i ) + { + int mx = s->img_x >> (i + 2); + int my = s->img_y >> (i + 2); + if( mx < 1 ) + { + mx = 1; + } + if( my < 1 ) + { + my = 1; + } + stbi__skip( s, mx*my*block_size ); + } + } + }/* per cubemap face */ + } else + { + /* uncompressed */ + DXT_family = 0; + s->img_n = 3; + if( has_alpha ) + { + s->img_n = 4; + } + *comp = s->img_n; + sz = s->img_x*s->img_y*s->img_n*cubemap_faces; + dds_data = (unsigned char*)malloc( sz ); + /* do this once for each face */ + for( cf = 0; cf < cubemap_faces; ++ cf ) + { + /* read the main image for this face */ + stbi__getn( s, &dds_data[cf*s->img_x*s->img_y*s->img_n], s->img_x*s->img_y*s->img_n ); + /* done reading and decoding the main image... + stbi__skip MIPmaps if present */ + if( has_mipmap ) + { + for( i = 1; i < (int)header.dwMipMapCount; ++i ) + { + int mx = s->img_x >> i; + int my = s->img_y >> i; + if( mx < 1 ) + { + mx = 1; + } + if( my < 1 ) + { + my = 1; + } + stbi__skip( s, mx*my*s->img_n ); + } + } + } + /* data was BGR, I need it RGB */ + for( i = 0; i < sz; i += s->img_n ) + { + unsigned char temp = dds_data[i]; + dds_data[i] = dds_data[i+2]; + dds_data[i+2] = temp; + } + } + /* finished decompressing into RGBA, + adjust the y size if we have a cubemap + note: sz is already up to date */ + s->img_y *= cubemap_faces; + *y = s->img_y; + // did the user want something else, or + // see if all the alpha values are 255 (i.e. no transparency) + has_alpha = 0; + if( s->img_n == 4) + { + for( i = 3; (i < sz) && (has_alpha == 0); i += 4 ) + { + has_alpha |= (dds_data[i] < 255); + } + } + if( (req_comp <= 4) && (req_comp >= 1) ) + { + // user has some requirements, meet them + if( req_comp != s->img_n ) + { + dds_data = stbi__convert_format( dds_data, s->img_n, req_comp, s->img_x, s->img_y ); + *comp = req_comp; + } + } else + { + // user had no requirements, only drop to RGB is no alpha + if( (has_alpha == 0) && (s->img_n == 4) ) + { + dds_data = stbi__convert_format( dds_data, 4, 3, s->img_x, s->img_y ); + *comp = 3; + } + } + // OK, done + return dds_data; +} + +#ifndef STBI_NO_STDIO +stbi_uc *stbi__dds_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp) +{ + stbi__context s; + stbi__start_file(&s,f); + return stbi__dds_load(&s,x,y,comp,req_comp); +} + +stbi_uc *stbi__dds_load_from_path (const char *filename, int *x, int *y, int *comp, int req_comp) +{ + stbi_uc *data; + FILE *f = fopen(filename, "rb"); + if (!f) return NULL; + data = stbi__dds_load_from_file(f,x,y,comp,req_comp); + fclose(f); + return data; +} +#endif + +stbi_uc *stbi__dds_load_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) +{ + stbi__context s; + stbi__start_mem(&s,buffer, len); + return stbi__dds_load(&s,x,y,comp,req_comp); +} + +stbi_uc *stbi__dds_load_from_callbacks (stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp) +{ + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); + return stbi__dds_load(&s,x,y,comp,req_comp); +} diff --git a/Loaders/SoilTextureLoader/SOIL/stbi_ext.h b/Loaders/SoilTextureLoader/SOIL/stbi_ext.h new file mode 100644 index 0000000..de0ecc8 --- /dev/null +++ b/Loaders/SoilTextureLoader/SOIL/stbi_ext.h @@ -0,0 +1,28 @@ +#ifndef HEADER_STB_IMAGE_EXT +#define HEADER_STB_IMAGE_EXT + +enum { + STBI_unknown= 0, + STBI_jpeg = 1, + STBI_png = 2, + STBI_bmp = 3, + STBI_gif = 4, + STBI_tga = 5, + STBI_psd = 6, + STBI_pic = 7, + STBI_pnm = 8, + STBI_dds = 9, + STBI_pvr = 10, + STBI_pkm = 11, + STBI_hdr = 12 +}; + +extern int stbi_test_from_memory (stbi_uc const *buffer, int len); +extern int stbi_test_from_callbacks (stbi_io_callbacks const *clbk, void *user); + +#ifndef STBI_NO_STDIO +extern int stbi_test (char const *filename); +extern int stbi_test_from_file (FILE *f); +#endif + +#endif /* HEADER_STB_IMAGE_EXT */ diff --git a/Loaders/SoilTextureLoader/SOIL/stbi_ext_c.h b/Loaders/SoilTextureLoader/SOIL/stbi_ext_c.h new file mode 100644 index 0000000..224f436 --- /dev/null +++ b/Loaders/SoilTextureLoader/SOIL/stbi_ext_c.h @@ -0,0 +1,74 @@ + +static int stbi_test_main(stbi__context *s) +{ + #ifndef STBI_NO_JPEG + if (stbi__jpeg_test(s)) return STBI_jpeg; + #endif + #ifndef STBI_NO_PNG + if (stbi__png_test(s)) return STBI_png; + #endif + #ifndef STBI_NO_BMP + if (stbi__bmp_test(s)) return STBI_bmp; + #endif + #ifndef STBI_NO_GIF + if (stbi__gif_test(s)) return STBI_gif; + #endif + #ifndef STBI_NO_PSD + if (stbi__psd_test(s)) return STBI_psd; + #endif + #ifndef STBI_NO_PIC + if (stbi__pic_test(s)) return STBI_pic; + #endif + #ifndef STBI_NO_PNM + if (stbi__pnm_test(s)) return STBI_pnm; + #endif + #ifndef STBI_NO_DDS + if (stbi__dds_test(s)) return STBI_dds; + #endif + #ifndef STBI_NO_PVR + if (stbi__pvr_test(s)) return STBI_pvr; + #endif + #ifndef STBI_NO_PKM + if (stbi__pkm_test(s)) return STBI_pkm; + #endif + #ifndef STBI_NO_HDR + if (stbi__hdr_test(s)) return STBI_hdr; + #endif + #ifndef STBI_NO_TGA + if (stbi__tga_test(s)) return STBI_tga; + #endif + return STBI_unknown; +} + +#ifndef STBI_NO_STDIO +int stbi_test_from_file(FILE *f) +{ + stbi__context s; + stbi__start_file(&s,f); + return stbi_test_main(&s); +} + +int stbi_test(char const *filename) +{ + FILE *f = fopen(filename, "rb"); + int result; + if (!f) return STBI_unknown; + result = stbi_test_from_file(f); + fclose(f); + return result; +} +#endif //!STBI_NO_STDIO + +int stbi_test_from_memory(stbi_uc const *buffer, int len) +{ + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi_test_main(&s); +} + +int stbi_test_from_callbacks(stbi_io_callbacks const *clbk, void *user) +{ + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); + return stbi_test_main(&s); +} diff --git a/Loaders/SoilTextureLoader/SOIL/stbi_pkm.h b/Loaders/SoilTextureLoader/SOIL/stbi_pkm.h new file mode 100644 index 0000000..7d9eaf6 --- /dev/null +++ b/Loaders/SoilTextureLoader/SOIL/stbi_pkm.h @@ -0,0 +1,34 @@ +/* + adding PKM loading support to stbi +*/ + +#ifndef HEADER_STB_IMAGE_PKM_AUGMENTATION +#define HEADER_STB_IMAGE_PKM_AUGMENTATION + +/* is it a PKM file? */ +extern int stbi__pkm_test_memory (stbi_uc const *buffer, int len); +extern int stbi__pkm_test_callbacks (stbi_io_callbacks const *clbk, void *user); + +extern stbi_uc *stbi__pkm_load_from_path (char const *filename, int *x, int *y, int *comp, int req_comp); +extern stbi_uc *stbi__pkm_load_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp); +extern stbi_uc *stbi__pkm_load_from_callbacks (stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp); + +#ifndef STBI_NO_STDIO +extern int stbi__pkm_test_filename (char const *filename); +extern int stbi__pkm_test_file (FILE *f); +extern stbi_uc *stbi__pkm_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp); +#endif + +extern int stbi__pkm_info_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp); +extern int stbi__pkm_info_from_callbacks (stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp); + + +#ifndef STBI_NO_STDIO +extern int stbi__pkm_info_from_path (char const *filename, int *x, int *y, int *comp); +extern int stbi__pkm_info_from_file (FILE *f, int *x, int *y, int *comp); +#endif + +/* +// +//// end header file /////////////////////////////////////////////////////*/ +#endif /* HEADER_STB_IMAGE_PKM_AUGMENTATION */ diff --git a/Loaders/SoilTextureLoader/SOIL/stbi_pkm_c.h b/Loaders/SoilTextureLoader/SOIL/stbi_pkm_c.h new file mode 100644 index 0000000..106eb90 --- /dev/null +++ b/Loaders/SoilTextureLoader/SOIL/stbi_pkm_c.h @@ -0,0 +1,227 @@ +#include "pkm_helper.h" +#include "etc1_utils.h" + +static int stbi__pkm_test(stbi__context *s) +{ + // check the magic number + if (stbi__get8(s) != 'P') { + stbi__rewind(s); + return 0; + } + + if (stbi__get8(s) != 'K') { + stbi__rewind(s); + return 0; + } + + if (stbi__get8(s) != 'M') { + stbi__rewind(s); + return 0; + } + + if (stbi__get8(s) != ' ') { + stbi__rewind(s); + return 0; + } + + if (stbi__get8(s) != '1') { + stbi__rewind(s); + return 0; + } + + if (stbi__get8(s) != '0') { + stbi__rewind(s); + return 0; + } + + stbi__rewind(s); + return 1; +} + +#ifndef STBI_NO_STDIO + +int stbi__pkm_test_filename (char const *filename) +{ + int r; + FILE *f = fopen(filename, "rb"); + if (!f) return 0; + r = stbi__pkm_test_file(f); + fclose(f); + return r; +} + +int stbi__pkm_test_file (FILE *f) +{ + stbi__context s; + int r,n = ftell(f); + stbi__start_file(&s,f); + r = stbi__pkm_test(&s); + fseek(f,n,SEEK_SET); + return r; +} +#endif + +int stbi__pkm_test_memory (stbi_uc const *buffer, int len) +{ + stbi__context s; + stbi__start_mem(&s,buffer, len); + return stbi__pkm_test(&s); +} + +int stbi__pkm_test_callbacks (stbi_io_callbacks const *clbk, void *user) +{ + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); + return stbi__pkm_test(&s); +} + +static int stbi__pkm_info(stbi__context *s, int *x, int *y, int *comp ) +{ + PKMHeader header; + unsigned int width, height; + + stbi__getn( s, (stbi_uc*)(&header), sizeof(PKMHeader) ); + + if ( 0 != strcmp( header.aName, "PKM 10" ) ) { + stbi__rewind(s); + return 0; + } + + width = (header.iWidthMSB << 8) | header.iWidthLSB; + height = (header.iHeightMSB << 8) | header.iHeightLSB; + + *x = s->img_x = width; + *y = s->img_y = height; + *comp = s->img_n = 3; + + stbi__rewind(s); + + return 1; +} + +int stbi__pkm_info_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp ) +{ + stbi__context s; + stbi__start_mem(&s,buffer, len); + return stbi__pkm_info( &s, x, y, comp ); +} + +int stbi__pkm_info_from_callbacks (stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp) +{ + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); + return stbi__pkm_info( &s, x, y, comp ); +} + +#ifndef STBI_NO_STDIO +int stbi__pkm_info_from_path(char const *filename, int *x, int *y, int *comp) +{ + int res; + FILE *f = fopen(filename, "rb"); + if (!f) return 0; + res = stbi__pkm_info_from_file( f, x, y, comp ); + fclose(f); + return res; +} + +int stbi__pkm_info_from_file(FILE *f, int *x, int *y, int *comp) +{ + stbi__context s; + int res; + long n = ftell(f); + stbi__start_file(&s, f); + res = stbi__pkm_info(&s, x, y, comp); + fseek(f, n, SEEK_SET); + return res; +} +#endif + +static stbi_uc * stbi__pkm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp) +{ + stbi_uc *pkm_data = NULL; + stbi_uc *pkm_res_data = NULL; + PKMHeader header; + unsigned int width; + unsigned int height; + unsigned int align = 0; + unsigned int bpr; + unsigned int size; + unsigned int compressedSize; + + int res; + + stbi__getn( s, (stbi_uc*)(&header), sizeof(PKMHeader) ); + + if ( 0 != strcmp( header.aName, "PKM 10" ) ) { + return NULL; + } + + width = (header.iWidthMSB << 8) | header.iWidthLSB; + height = (header.iHeightMSB << 8) | header.iHeightLSB; + + *x = s->img_x = width; + *y = s->img_y = height; + *comp = s->img_n = 3; + + compressedSize = etc1_get_encoded_data_size(width, height); + + pkm_data = (stbi_uc *)malloc(compressedSize); + stbi__getn( s, pkm_data, compressedSize ); + + bpr = ((width * 3) + align) & ~align; + size = bpr * height; + pkm_res_data = (stbi_uc *)malloc(size); + + res = etc1_decode_image((const etc1_byte*)pkm_data, (etc1_byte*)pkm_res_data, width, height, 3, bpr); + + free( pkm_data ); + + if ( 0 == res ) { + if( (req_comp <= 4) && (req_comp >= 1) ) { + // user has some requirements, meet them + if( req_comp != s->img_n ) { + pkm_res_data = stbi__convert_format( pkm_res_data, s->img_n, req_comp, s->img_x, s->img_y ); + *comp = req_comp; + } + } + + return (stbi_uc *)pkm_res_data; + } else { + free( pkm_res_data ); + } + + return NULL; +} + +#ifndef STBI_NO_STDIO +stbi_uc *stbi__pkm_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp) +{ + stbi__context s; + stbi__start_file(&s,f); + return stbi__pkm_load(&s,x,y,comp,req_comp); +} + +stbi_uc *stbi__pkm_load_from_path (char const*filename, int *x, int *y, int *comp, int req_comp) +{ + stbi_uc *data; + FILE *f = fopen(filename, "rb"); + if (!f) return NULL; + data = stbi__pkm_load_from_file(f,x,y,comp,req_comp); + fclose(f); + return data; +} +#endif + +stbi_uc *stbi__pkm_load_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) +{ + stbi__context s; + stbi__start_mem(&s,buffer, len); + return stbi__pkm_load(&s,x,y,comp,req_comp); +} + +stbi_uc *stbi__pkm_load_from_callbacks (stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp) +{ + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); + return stbi__pkm_load(&s,x,y,comp,req_comp); +} diff --git a/Loaders/SoilTextureLoader/SOIL/stbi_pvr.h b/Loaders/SoilTextureLoader/SOIL/stbi_pvr.h new file mode 100644 index 0000000..5e84a3f --- /dev/null +++ b/Loaders/SoilTextureLoader/SOIL/stbi_pvr.h @@ -0,0 +1,34 @@ +/* + adding PVR loading support to stbi +*/ + +#ifndef HEADER_STB_IMAGE_PVR_AUGMENTATION +#define HEADER_STB_IMAGE_PVR_AUGMENTATION + +/* is it a PVR file? */ +extern int stbi__pvr_test_memory (stbi_uc const *buffer, int len); +extern int stbi__pvr_test_callbacks (stbi_io_callbacks const *clbk, void *user); + +extern stbi_uc *stbi__pvr_load_from_path (char const *filename, int *x, int *y, int *comp, int req_comp); +extern stbi_uc *stbi__pvr_load_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp); +extern stbi_uc *stbi__pvr_load_from_callbacks (stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp); + +#ifndef STBI_NO_STDIO +extern int stbi__pvr_test_filename (char const *filename); +extern int stbi__pvr_test_file (FILE *f); +extern stbi_uc *stbi__pvr_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp); +#endif + +extern int stbi__pvr_info_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int *iscompressed); +extern int stbi__pvr_info_from_callbacks (stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int *iscompressed); + + +#ifndef STBI_NO_STDIO +extern int stbi__pvr_info_from_path (char const *filename, int *x, int *y, int *comp, int *iscompressed); +extern int stbi__pvr_info_from_file (FILE *f, int *x, int *y, int *comp, int *iscompressed); +#endif + +/* +// +//// end header file /////////////////////////////////////////////////////*/ +#endif /* HEADER_STB_IMAGE_PVR_AUGMENTATION */ diff --git a/Loaders/SoilTextureLoader/SOIL/stbi_pvr_c.h b/Loaders/SoilTextureLoader/SOIL/stbi_pvr_c.h new file mode 100644 index 0000000..134585f --- /dev/null +++ b/Loaders/SoilTextureLoader/SOIL/stbi_pvr_c.h @@ -0,0 +1,1001 @@ +#include "pvr_helper.h" + +static int stbi__pvr_test(stbi__context *s) +{ + // check header size + if (stbi__get32le(s) != sizeof(PVR_Texture_Header)) { + stbi__rewind(s); + return 0; + } + + // stbi__skip until the magic number + stbi__skip(s, 10*4); + + // check the magic number + if ( stbi__get32le(s) != PVRTEX_IDENTIFIER ) { + stbi__rewind(s); + return 0; + } + + // Also rewind because the loader needs to read the header + stbi__rewind(s); + + return 1; +} + +#ifndef STBI_NO_STDIO + +int stbi__pvr_test_filename (char const *filename) +{ + int r; + FILE *f = fopen(filename, "rb"); + if (!f) return 0; + r = stbi__pvr_test_file(f); + fclose(f); + return r; +} + +int stbi__pvr_test_file (FILE *f) +{ + stbi__context s; + int r,n = ftell(f); + stbi__start_file(&s,f); + r = stbi__pvr_test(&s); + fseek(f,n,SEEK_SET); + return r; +} +#endif + +int stbi__pvr_test_memory (stbi_uc const *buffer, int len) +{ + stbi__context s; + stbi__start_mem(&s,buffer, len); + return stbi__pvr_test(&s); +} + +int stbi__pvr_test_callbacks (stbi_io_callbacks const *clbk, void *user) +{ + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); + return stbi__pvr_test(&s); +} + +static int stbi__pvr_info(stbi__context *s, int *x, int *y, int *comp, int * iscompressed ) +{ + PVR_Texture_Header header={0}; + + stbi__getn( s, (stbi_uc*)(&header), sizeof(PVR_Texture_Header) ); + + // Check the header size + if ( header.dwHeaderSize != sizeof(PVR_Texture_Header) ) { + stbi__rewind( s ); + return 0; + } + + // Check the magic identifier + if ( header.dwPVR != PVRTEX_IDENTIFIER ) { + stbi__rewind(s); + return 0; + } + + *x = s->img_x = header.dwWidth; + *y = s->img_y = header.dwHeight; + *comp = s->img_n = ( header.dwBitCount + 7 ) / 8; + + if ( iscompressed ) + *iscompressed = 0; + + switch ( header.dwpfFlags & PVRTEX_PIXELTYPE ) + { + case OGL_RGBA_4444: + s->img_n = 2; + break; + case OGL_RGBA_5551: + s->img_n = 2; + break; + case OGL_RGBA_8888: + s->img_n = 4; + break; + case OGL_RGB_565: + s->img_n = 2; + break; + case OGL_RGB_888: + s->img_n = 3; + break; + case OGL_I_8: + s->img_n = 1; + break; + case OGL_AI_88: + s->img_n = 2; + break; + case OGL_PVRTC2: + s->img_n = 4; + if ( iscompressed ) + *iscompressed = 1; + break; + case OGL_PVRTC4: + s->img_n = 4; + if ( iscompressed ) + *iscompressed = 1; + break; + case OGL_RGB_555: + default: + stbi__rewind(s); + return 0; + } + + *comp = s->img_n; + + return 1; +} + +int stbi__pvr_info_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int * iscompressed ) +{ + stbi__context s; + stbi__start_mem(&s,buffer, len); + return stbi__pvr_info( &s, x, y, comp, iscompressed ); +} + +int stbi__pvr_info_from_callbacks (stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int * iscompressed) +{ + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); + return stbi__pvr_info( &s, x, y, comp, iscompressed ); +} + +#ifndef STBI_NO_STDIO +int stbi__pvr_info_from_path(char const *filename, int *x, int *y, int *comp, int * iscompressed) +{ + int res; + FILE *f = fopen(filename, "rb"); + if (!f) return 0; + res = stbi__pvr_info_from_file( f, x, y, comp, iscompressed ); + fclose(f); + return res; +} + +int stbi__pvr_info_from_file(FILE *f, int *x, int *y, int *comp, int * iscompressed) +{ + stbi__context s; + int res; + long n = ftell(f); + stbi__start_file(&s, f); + res = stbi__pvr_info(&s, x, y, comp, iscompressed); + fseek(f, n, SEEK_SET); + return res; +} +#endif + +/****************************************************************************** + Taken from: + @File PVRTDecompress.cpp + @Title PVRTDecompress + @Copyright Copyright (C) Imagination Technologies Limited. + @Platform ANSI compatible + @Description PVRTC Texture Decompression. +******************************************************************************/ + +typedef unsigned char PVRTuint8; +typedef unsigned short PVRTuint16; +typedef unsigned int PVRTuint32; + +/***************************************************************************** + * defines and consts + *****************************************************************************/ +#define PT_INDEX (2) // The Punch-through index + +#define BLK_Y_SIZE (4) // always 4 for all 2D block types + +#define BLK_X_MAX (8) // Max X dimension for blocks + +#define BLK_X_2BPP (8) // dimensions for the two formats +#define BLK_X_4BPP (4) + +#define WRAP_COORD(Val, Size) ((Val) & ((Size)-1)) + +#define POWER_OF_2(X) util_number_is_power_2(X) + +/* + Define an expression to either wrap or clamp large or small vals to the + legal coordinate range +*/ +#define PVRT_MIN(a,b) (((a) < (b)) ? (a) : (b)) +#define PVRT_MAX(a,b) (((a) > (b)) ? (a) : (b)) +#define PVRT_CLAMP(x, l, h) (PVRT_MIN((h), PVRT_MAX((x), (l)))) + +#define LIMIT_COORD(Val, Size, AssumeImageTiles) \ + ((AssumeImageTiles)? WRAP_COORD((Val), (Size)): PVRT_CLAMP((Val), 0, (Size)-1)) + +/***************************************************************************** + * Useful typedefs + *****************************************************************************/ +typedef PVRTuint32 U32; +typedef PVRTuint8 U8; + +/*********************************************************** + DECOMPRESSION ROUTINES +************************************************************/ + +/*!*********************************************************************** + @Struct AMTC_BLOCK_STRUCT + @Brief +*************************************************************************/ +typedef struct +{ + // Uses 64 bits pre block + U32 PackedData[2]; +}AMTC_BLOCK_STRUCT; + + /*!*********************************************************************** + @Function util_number_is_power_2 + @Input input A number + @Returns TRUE if the number is an integer power of two, else FALSE. + @Description Check that a number is an integer power of two, i.e. + 1, 2, 4, 8, ... etc. + Returns FALSE for zero. +*************************************************************************/ +int util_number_is_power_2( unsigned input ) +{ + unsigned minus1; + + if( !input ) return 0; + + minus1 = input - 1; + return ( (input | minus1) == (input ^ minus1) ) ? 1 : 0; +} + +/*!*********************************************************************** + @Function Unpack5554Colour + @Input pBlock + @Input ABColours + @Description Given a block, extract the colour information and convert + to 5554 formats +*************************************************************************/ +static void Unpack5554Colour(const AMTC_BLOCK_STRUCT *pBlock, + int ABColours[2][4]) +{ + U32 RawBits[2]; + + int i; + + // Extract A and B + RawBits[0] = pBlock->PackedData[1] & (0xFFFE); // 15 bits (shifted up by one) + RawBits[1] = pBlock->PackedData[1] >> 16; // 16 bits + + // step through both colours + for(i = 0; i < 2; i++) + { + // If completely opaque + if(RawBits[i] & (1<<15)) + { + // Extract R and G (both 5 bit) + ABColours[i][0] = (RawBits[i] >> 10) & 0x1F; + ABColours[i][1] = (RawBits[i] >> 5) & 0x1F; + + /* + The precision of Blue depends on A or B. If A then we need to + replicate the top bit to get 5 bits in total + */ + ABColours[i][2] = RawBits[i] & 0x1F; + if(i==0) + { + ABColours[0][2] |= ABColours[0][2] >> 4; + } + + // set 4bit alpha fully on... + ABColours[i][3] = 0xF; + } + else // Else if colour has variable translucency + { + /* + Extract R and G (both 4 bit). + (Leave a space on the end for the replication of bits + */ + ABColours[i][0] = (RawBits[i] >> (8-1)) & 0x1E; + ABColours[i][1] = (RawBits[i] >> (4-1)) & 0x1E; + + // replicate bits to truly expand to 5 bits + ABColours[i][0] |= ABColours[i][0] >> 4; + ABColours[i][1] |= ABColours[i][1] >> 4; + + // grab the 3(+padding) or 4 bits of blue and add an extra padding bit + ABColours[i][2] = (RawBits[i] & 0xF) << 1; + + /* + expand from 3 to 5 bits if this is from colour A, or 4 to 5 bits if from + colour B + */ + if(i==0) + { + ABColours[0][2] |= ABColours[0][2] >> 3; + } + else + { + ABColours[0][2] |= ABColours[0][2] >> 4; + } + + // Set the alpha bits to be 3 + a zero on the end + ABColours[i][3] = (RawBits[i] >> 11) & 0xE; + } + } +} + +/*!*********************************************************************** + @Function UnpackModulations + @Input pBlock + @Input Do2bitMode + @Input ModulationVals + @Input ModulationModes + @Input StartX + @Input StartY + @Description Given the block and the texture type and it's relative + position in the 2x2 group of blocks, extract the bit + patterns for the fully defined pixels. +*************************************************************************/ +static void UnpackModulations(const AMTC_BLOCK_STRUCT *pBlock, + const int Do2bitMode, + int ModulationVals[8][16], + int ModulationModes[8][16], + int StartX, + int StartY) +{ + int BlockModMode; + U32 ModulationBits; + + int x, y; + + BlockModMode= pBlock->PackedData[1] & 1; + ModulationBits = pBlock->PackedData[0]; + + // if it's in an interpolated mode + if(Do2bitMode && BlockModMode) + { + /* + run through all the pixels in the block. Note we can now treat all the + "stored" values as if they have 2bits (even when they didn't!) + */ + for(y = 0; y < BLK_Y_SIZE; y++) + { + for(x = 0; x < BLK_X_2BPP; x++) + { + ModulationModes[y+StartY][x+StartX] = BlockModMode; + + // if this is a stored value... + if(((x^y)&1) == 0) + { + ModulationVals[y+StartY][x+StartX] = ModulationBits & 3; + ModulationBits >>= 2; + } + } + } + } + else if(Do2bitMode) // else if direct encoded 2bit mode - i.e. 1 mode bit per pixel + { + for(y = 0; y < BLK_Y_SIZE; y++) + { + for(x = 0; x < BLK_X_2BPP; x++) + { + ModulationModes[y+StartY][x+StartX] = BlockModMode; + + // double the bits so 0=> 00, and 1=>11 + if(ModulationBits & 1) + { + ModulationVals[y+StartY][x+StartX] = 0x3; + } + else + { + ModulationVals[y+StartY][x+StartX] = 0x0; + } + ModulationBits >>= 1; + } + } + } + else // else its the 4bpp mode so each value has 2 bits + { + for(y = 0; y < BLK_Y_SIZE; y++) + { + for(x = 0; x < BLK_X_4BPP; x++) + { + ModulationModes[y+StartY][x+StartX] = BlockModMode; + + ModulationVals[y+StartY][x+StartX] = ModulationBits & 3; + ModulationBits >>= 2; + } + } + } + + // make sure nothing is left over + assert(ModulationBits==0); +} + +/*!*********************************************************************** + @Function InterpolateColours + @Input ColourP + @Input ColourQ + @Input ColourR + @Input ColourS + @Input Do2bitMode + @Input x + @Input y + @Modified Result + @Description This performs a HW bit accurate interpolation of either the + A or B colours for a particular pixel. + + NOTE: It is assumed that the source colours are in ARGB 5554 + format - This means that some "preparation" of the values will + be necessary. +*************************************************************************/ +static void InterpolateColours(const int ColourP[4], + const int ColourQ[4], + const int ColourR[4], + const int ColourS[4], + const int Do2bitMode, + const int x, + const int y, + int Result[4]) +{ + int u, v, uscale; + int k; + + int tmp1, tmp2; + + int P[4], Q[4], R[4], S[4]; + + // Copy the colours + for(k = 0; k < 4; k++) + { + P[k] = ColourP[k]; + Q[k] = ColourQ[k]; + R[k] = ColourR[k]; + S[k] = ColourS[k]; + } + + // put the x and y values into the right range + v = (y & 0x3) | ((~y & 0x2) << 1); + + if(Do2bitMode) + u = (x & 0x7) | ((~x & 0x4) << 1); + else + u = (x & 0x3) | ((~x & 0x2) << 1); + + // get the u and v scale amounts + v = v - BLK_Y_SIZE/2; + + if(Do2bitMode) + { + u = u - BLK_X_2BPP/2; + uscale = 8; + } + else + { + u = u - BLK_X_4BPP/2; + uscale = 4; + } + + for(k = 0; k < 4; k++) + { + tmp1 = P[k] * uscale + u * (Q[k] - P[k]); + tmp2 = R[k] * uscale + u * (S[k] - R[k]); + + tmp1 = tmp1 * 4 + v * (tmp2 - tmp1); + + Result[k] = tmp1; + } + + // Lop off the appropriate number of bits to get us to 8 bit precision + if(Do2bitMode) + { + // do RGB + for(k = 0; k < 3; k++) + { + Result[k] >>= 2; + } + + Result[3] >>= 1; + } + else + { + // do RGB (A is ok) + for(k = 0; k < 3; k++) + { + Result[k] >>= 1; + } + } + + // sanity check + for(k = 0; k < 4; k++) + { + assert(Result[k] < 256); + } + + + /* + Convert from 5554 to 8888 + + do RGB 5.3 => 8 + */ + for(k = 0; k < 3; k++) + { + Result[k] += Result[k] >> 5; + } + + Result[3] += Result[3] >> 4; + + // 2nd sanity check + for(k = 0; k < 4; k++) + { + assert(Result[k] < 256); + } + +} + +/*!*********************************************************************** + @Function GetModulationValue + @Input x + @Input y + @Input Do2bitMode + @Input ModulationVals + @Input ModulationModes + @Input Mod + @Input DoPT + @Description Get the modulation value as a numerator of a fraction of 8ths +*************************************************************************/ +static void GetModulationValue(int x, + int y, + const int Do2bitMode, + const int ModulationVals[8][16], + const int ModulationModes[8][16], + int *Mod, + int *DoPT) +{ + static const int RepVals0[4] = {0, 3, 5, 8}; + static const int RepVals1[4] = {0, 4, 4, 8}; + + int ModVal; + + // Map X and Y into the local 2x2 block + y = (y & 0x3) | ((~y & 0x2) << 1); + + if(Do2bitMode) + x = (x & 0x7) | ((~x & 0x4) << 1); + else + x = (x & 0x3) | ((~x & 0x2) << 1); + + // assume no PT for now + *DoPT = 0; + + // extract the modulation value. If a simple encoding + if(ModulationModes[y][x]==0) + { + ModVal = RepVals0[ModulationVals[y][x]]; + } + else if(Do2bitMode) + { + // if this is a stored value + if(((x^y)&1)==0) + ModVal = RepVals0[ModulationVals[y][x]]; + else if(ModulationModes[y][x] == 1) // else average from the neighbours if H&V interpolation.. + { + ModVal = (RepVals0[ModulationVals[y-1][x]] + + RepVals0[ModulationVals[y+1][x]] + + RepVals0[ModulationVals[y][x-1]] + + RepVals0[ModulationVals[y][x+1]] + 2) / 4; + } + else if(ModulationModes[y][x] == 2) // else if H-Only + { + ModVal = (RepVals0[ModulationVals[y][x-1]] + + RepVals0[ModulationVals[y][x+1]] + 1) / 2; + } + else // else it's V-Only + { + ModVal = (RepVals0[ModulationVals[y-1][x]] + + RepVals0[ModulationVals[y+1][x]] + 1) / 2; + } + } + else // else it's 4BPP and PT encoding + { + ModVal = RepVals1[ModulationVals[y][x]]; + + *DoPT = ModulationVals[y][x] == PT_INDEX; + } + + *Mod =ModVal; +} + +/*!*********************************************************************** + @Function TwiddleUV + @Input YSize Y dimension of the texture in pixels + @Input XSize X dimension of the texture in pixels + @Input YPos Pixel Y position + @Input XPos Pixel X position + @Returns The twiddled offset of the pixel + @Description Given the Block (or pixel) coordinates and the dimension of + the texture in blocks (or pixels) this returns the twiddled + offset of the block (or pixel) from the start of the map. + + NOTE the dimensions of the texture must be a power of 2 +*************************************************************************/ +static int DisableTwiddlingRoutine = 0; + +static U32 TwiddleUV(U32 YSize, U32 XSize, U32 YPos, U32 XPos) +{ + U32 Twiddled; + + U32 MinDimension; + U32 MaxValue; + + U32 SrcBitPos; + U32 DstBitPos; + + int ShiftCount; + + assert(YPos < YSize); + assert(XPos < XSize); + + assert(POWER_OF_2(YSize)); + assert(POWER_OF_2(XSize)); + + if(YSize < XSize) + { + MinDimension = YSize; + MaxValue = XPos; + } + else + { + MinDimension = XSize; + MaxValue = YPos; + } + + // Nasty hack to disable twiddling + if(DisableTwiddlingRoutine) + return (YPos* XSize + XPos); + + // Step through all the bits in the "minimum" dimension + SrcBitPos = 1; + DstBitPos = 1; + Twiddled = 0; + ShiftCount = 0; + + while(SrcBitPos < MinDimension) + { + if(YPos & SrcBitPos) + { + Twiddled |= DstBitPos; + } + + if(XPos & SrcBitPos) + { + Twiddled |= (DstBitPos << 1); + } + + + SrcBitPos <<= 1; + DstBitPos <<= 2; + ShiftCount += 1; + + } + + // prepend any unused bits + MaxValue >>= ShiftCount; + + Twiddled |= (MaxValue << (2*ShiftCount)); + + return Twiddled; +} + +/***********************************************************/ +/* +// Decompress +// +// Takes the compressed input data and outputs the equivalent decompressed +// image. +*/ +/***********************************************************/ + +static void Decompress(AMTC_BLOCK_STRUCT *pCompressedData, + const int Do2bitMode, + const int XDim, + const int YDim, + const int AssumeImageTiles, + unsigned char* pResultImage) +{ + int x, y; + int i, j; + + int BlkX, BlkY; + int BlkXp1, BlkYp1; + int XBlockSize; + int BlkXDim, BlkYDim; + + int StartX, StartY; + + int ModulationVals[8][16]; + int ModulationModes[8][16]; + + int Mod, DoPT; + + unsigned int uPosition; + + /* + // local neighbourhood of blocks + */ + AMTC_BLOCK_STRUCT *pBlocks[2][2]; + + AMTC_BLOCK_STRUCT *pPrevious[2][2] = {{NULL, NULL}, {NULL, NULL}}; + + /* + // Low precision colours extracted from the blocks + */ + struct + { + int Reps[2][4]; + }Colours5554[2][2]; + + /* + // Interpolated A and B colours for the pixel + */ + int ASig[4], BSig[4]; + + int Result[4]; + + if(Do2bitMode) + { + XBlockSize = BLK_X_2BPP; + } + else + { + XBlockSize = BLK_X_4BPP; + } + + + /* + // For MBX don't allow the sizes to get too small + */ + BlkXDim = PVRT_MAX(2, XDim / XBlockSize); + BlkYDim = PVRT_MAX(2, YDim / BLK_Y_SIZE); + + /* + // Step through the pixels of the image decompressing each one in turn + // + // Note that this is a hideously inefficient way to do this! + */ + for(y = 0; y < YDim; y++) + { + for(x = 0; x < XDim; x++) + { + /* + // map this pixel to the top left neighbourhood of blocks + */ + BlkX = (x - XBlockSize/2); + BlkY = (y - BLK_Y_SIZE/2); + + BlkX = LIMIT_COORD(BlkX, XDim, AssumeImageTiles); + BlkY = LIMIT_COORD(BlkY, YDim, AssumeImageTiles); + + + BlkX /= XBlockSize; + BlkY /= BLK_Y_SIZE; + + //BlkX = LIMIT_COORD(BlkX, BlkXDim, AssumeImageTiles); + //BlkY = LIMIT_COORD(BlkY, BlkYDim, AssumeImageTiles); + + + /* + // compute the positions of the other 3 blocks + */ + BlkXp1 = LIMIT_COORD(BlkX+1, BlkXDim, AssumeImageTiles); + BlkYp1 = LIMIT_COORD(BlkY+1, BlkYDim, AssumeImageTiles); + + /* + // Map to block memory locations + */ + pBlocks[0][0] = pCompressedData +TwiddleUV(BlkYDim, BlkXDim, BlkY, BlkX); + pBlocks[0][1] = pCompressedData +TwiddleUV(BlkYDim, BlkXDim, BlkY, BlkXp1); + pBlocks[1][0] = pCompressedData +TwiddleUV(BlkYDim, BlkXDim, BlkYp1, BlkX); + pBlocks[1][1] = pCompressedData +TwiddleUV(BlkYDim, BlkXDim, BlkYp1, BlkXp1); + + + /* + // extract the colours and the modulation information IF the previous values + // have changed. + */ + if(memcmp(pPrevious, pBlocks, 4*sizeof(void*)) != 0) + { + StartY = 0; + for(i = 0; i < 2; i++) + { + StartX = 0; + for(j = 0; j < 2; j++) + { + Unpack5554Colour(pBlocks[i][j], Colours5554[i][j].Reps); + + UnpackModulations(pBlocks[i][j], + Do2bitMode, + ModulationVals, + ModulationModes, + StartX, StartY); + + StartX += XBlockSize; + }/*end for j*/ + + StartY += BLK_Y_SIZE; + }/*end for i*/ + + /* + // make a copy of the new pointers + */ + memcpy(pPrevious, pBlocks, 4*sizeof(void*)); + }/*end if the blocks have changed*/ + + + /* + // decompress the pixel. First compute the interpolated A and B signals + */ + InterpolateColours(Colours5554[0][0].Reps[0], + Colours5554[0][1].Reps[0], + Colours5554[1][0].Reps[0], + Colours5554[1][1].Reps[0], + Do2bitMode, x, y, + ASig); + + InterpolateColours(Colours5554[0][0].Reps[1], + Colours5554[0][1].Reps[1], + Colours5554[1][0].Reps[1], + Colours5554[1][1].Reps[1], + Do2bitMode, x, y, + BSig); + + GetModulationValue(x,y, Do2bitMode, (const int (*)[16])ModulationVals, (const int (*)[16])ModulationModes, + &Mod, &DoPT); + + /* + // compute the modulated colour + */ + for(i = 0; i < 4; i++) + { + Result[i] = ASig[i] * 8 + Mod * (BSig[i] - ASig[i]); + Result[i] >>= 3; + } + if(DoPT) + { + Result[3] = 0; + } + + /* + // Store the result in the output image + */ + uPosition = (x+y*XDim)<<2; + pResultImage[uPosition+0] = (unsigned char)Result[0]; + pResultImage[uPosition+1] = (unsigned char)Result[1]; + pResultImage[uPosition+2] = (unsigned char)Result[2]; + pResultImage[uPosition+3] = (unsigned char)Result[3]; + + }/*end for x*/ + }/*end for y*/ + +} + +static stbi_uc * stbi__pvr_load(stbi__context *s, int *x, int *y, int *comp, int req_comp) +{ + stbi_uc *pvr_data = NULL; + stbi_uc *pvr_res_data = NULL; + PVR_Texture_Header header={0}; + int iscompressed = 0; + int bitmode = 0; + unsigned int levelSize = 0; + + stbi__getn( s, (stbi_uc*)(&header), sizeof(PVR_Texture_Header) ); + + // Check the header size + if ( header.dwHeaderSize != sizeof(PVR_Texture_Header) ) { + return NULL; + } + + // Check the magic identifier + if ( header.dwPVR != PVRTEX_IDENTIFIER ) { + return NULL; + } + + *x = s->img_x = header.dwWidth; + *y = s->img_y = header.dwHeight; + + /* Get if the texture is compressed and the texture mode ( 2bpp or 4bpp ) */ + switch ( header.dwpfFlags & PVRTEX_PIXELTYPE ) + { + case OGL_RGBA_4444: + s->img_n = 2; + break; + case OGL_RGBA_5551: + s->img_n = 2; + break; + case OGL_RGBA_8888: + s->img_n = 4; + break; + case OGL_RGB_565: + s->img_n = 2; + break; + case OGL_RGB_888: + s->img_n = 3; + break; + case OGL_I_8: + s->img_n = 1; + break; + case OGL_AI_88: + s->img_n = 2; + break; + case OGL_PVRTC2: + bitmode = 1; + s->img_n = 4; + iscompressed = 1; + break; + case OGL_PVRTC4: + s->img_n = 4; + iscompressed = 1; + break; + case OGL_RGB_555: + default: + return NULL; + } + + *comp = s->img_n; + + // Load only the first mip map level + levelSize = (s->img_x * s->img_y * header.dwBitCount + 7) / 8; + + // get the raw data + pvr_data = (stbi_uc *)malloc( levelSize ); + stbi__getn( s, pvr_data, levelSize ); + + // if compressed decompress as RGBA + if ( iscompressed ) { + pvr_res_data = (stbi_uc *)malloc( s->img_x * s->img_y * 4 ); + Decompress( (AMTC_BLOCK_STRUCT*)pvr_data, bitmode, s->img_x, s->img_y, 1, (unsigned char*)pvr_res_data ); + free( pvr_data ); + } else { + // otherwise use the raw data + pvr_res_data = pvr_data; + } + + if( (req_comp <= 4) && (req_comp >= 1) ) { + // user has some requirements, meet them + if( req_comp != s->img_n ) { + pvr_res_data = stbi__convert_format( pvr_res_data, s->img_n, req_comp, s->img_x, s->img_y ); + *comp = req_comp; + } + } + + return pvr_res_data; +} + +#ifndef STBI_NO_STDIO +stbi_uc *stbi__pvr_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp) +{ + stbi__context s; + stbi__start_file(&s,f); + return stbi__pvr_load(&s,x,y,comp,req_comp); +} + +stbi_uc *stbi__pvr_load_from_path (char const*filename, int *x, int *y, int *comp, int req_comp) +{ + stbi_uc *data; + FILE *f = fopen(filename, "rb"); + if (!f) return NULL; + data = stbi__pvr_load_from_file(f,x,y,comp,req_comp); + fclose(f); + return data; +} +#endif + +stbi_uc *stbi__pvr_load_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) +{ + stbi__context s; + stbi__start_mem(&s,buffer, len); + return stbi__pvr_load(&s,x,y,comp,req_comp); +} + +stbi_uc *stbi__pvr_load_from_callbacks (stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp) +{ + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); + return stbi__pvr_load(&s,x,y,comp,req_comp); +} diff --git a/Loaders/SoilTextureLoader/SoilTextureLoader.cpp b/Loaders/SoilTextureLoader/SoilTextureLoader.cpp new file mode 100644 index 0000000..edf75f0 --- /dev/null +++ b/Loaders/SoilTextureLoader/SoilTextureLoader.cpp @@ -0,0 +1,176 @@ +/** +@file SoilTextureLoader.cpp +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + +#include "swGraphicAPI/Loaders/SoilTextureLoader/stdafx.h" + + +#include "SoilTextureLoader.h" + +#include "swGraphicAPI/Resources/Textures/TextureInitData.h" +#include "swGraphicAPI/ResourceManager/Loaders/TextureLoadInfo.h" +#include "swGraphicAPI/ResourceManager/Exceptions/LoaderException.h" +#include "swGraphicAPI/ResourceManager/Loaders/Tools/CanLoad.h" + +#include "swCommonLib/Common/Exceptions/Common/FileNotFoundException.h" +#include "swCommonLib/Common/Buffers/BufferTyped.h" +#include "swCommonLib/Common/Converters.h" + +#include + +#define STB_IMAGE_IMPLEMENTATION +#define STBI_FAILURE_USERMSG +#include "SOIL/stb_image.h" + + +namespace sw +{ + + +// ================================ // +// +struct SoilAllocator +{ + uint8* allocate ( Size numElements ); + void deallocate ( uint8* data, Size numElements ); +}; + +// ================================ // +// +uint8* SoilAllocator::allocate ( Size numElements ) +{ + return static_cast< uint8* >( stbi__malloc( numElements ) ); +} + +// ================================ // +// +void SoilAllocator::deallocate ( uint8* data, Size numElements ) +{ + stbi_image_free( data ); +} + + + + +// ================================ // +// +bool SoilTextureLoader::CanLoad ( const AssetPath& filePath, TypeID resourceType ) +{ + std::string allowedExtensions[] = + { + ".png", + ".jpeg", + ".jpg", + ".bmp", + ".tga", + ".gif", + ".hdr", + ".psd", + ".dds", + }; + + TypeID allowedTypes[] = + { + TypeID::get< Texture >(), + TypeID::get< Resource >() + }; + + return DefaultCanLoad( filePath, resourceType, allowedExtensions, allowedTypes ); +} + +// ================================ // +// +ReturnResult SoilTextureLoader::ValidateParameters ( const LoadPath& filePath, TypeID resourceType, const IAssetLoadInfo* assetDesc ) +{ + if( assetDesc->get_type() != TypeID::get< TextureLoadInfo >() ) + return LoaderException::Create( "SoilTextureLoader", "Unsupported descriptor type [ " + assetDesc->get_type().get_name().to_string() + " ].", filePath, resourceType ); + + auto loadInfo = static_cast< const TextureLoadInfo* >( assetDesc ); + + // In future we could force expected number of channels. + if( loadInfo->Processing.ForceFormat ) + return LoaderException::Create( "SoilTextureLoader", "ForceFormat option is not supported.", filePath, resourceType ); + + return Result::Success; +} + + +// ================================ // +// +LoadingResult SoilTextureLoader::Load ( const LoadPath& filePath, TypeID resourceType, const IAssetLoadInfo* assetDesc, RMLoaderAPI factory ) +{ + if( filePath.GetFile().Exists() ) + { + // Validate assetDesc parameters, if this loader can handle them. + auto validation = ValidateParameters( filePath, resourceType, assetDesc ); + + if( !validation.IsValid() ) + return { validation.GetError() }; + + auto loadInfo = static_cast< const TextureLoadInfo* >( assetDesc ); + + int height = 0; + int width = 0; + int channels = 0; + int realChannels = 0; + + // Check file metadata. This can fail, but we ignore it. We handle fails after calling stbi_load. + stbi_info( filePath.GetFile().String().c_str(), &width, &height, &channels ); + + // Force alpha channel if image has 3 channels. We don't support 3-components + // images, because DirectX don't support this format. + if( channels == 3 ) + channels = 4; + + uint8* data = stbi_load( filePath.GetFile().String().c_str(), &width, &height, &realChannels, channels ); + + if( data == nullptr ) + return { LoaderException::Create( "SoilTextureLoader", stbi_failure_reason(), filePath, resourceType ) }; + + Size memSize = height * width * channels; + auto texBuffer = BufferTyped< uint8, SoilAllocator >::StealMemory( std::move( data ), memSize ); + + TextureInitData texInfo( texBuffer.MoveToRawBuffer() ); + texInfo.Width = width; + texInfo.Height = height; + texInfo.MipMaps = loadInfo->MipMaps; + texInfo.TextureUsage = loadInfo->TextureUsage; + + if( realChannels == 1 ) + texInfo.Format = ResourceFormat::RESOURCE_FORMAT_R8_UNORM; + else if( realChannels == 2 ) + texInfo.Format = ResourceFormat::RESOURCE_FORMAT_R8G8_UNORM; + else if( realChannels == 3 ) + texInfo.Format = ResourceFormat::RESOURCE_FORMAT_R8G8B8A8_UNORM; + else if( realChannels == 4 ) + texInfo.Format = ResourceFormat::RESOURCE_FORMAT_R8G8B8A8_UNORM; + else + return { LoaderException::Create( "SoilTextureLoader", "Unexpected number of color channels " + Convert::ToString( realChannels ), filePath, resourceType ) }; + + // Create texture asset. + auto result = factory.CreateGenericAsset( filePath.GetOriginalPath(), resourceType, std::move( texInfo ) ); + + if( result.IsValid() ) + return { result.Get() }; + else + return { result.GetError() }; + } + else + { + return { std::make_shared< FileNotFoundException >( filePath.GetFile() ) }; + } +} + +// ================================ // +// +ReturnResult SoilTextureLoader::Prefetch ( const LoadPath& filePath, TypeID resourceType, const IAssetLoadInfo* assetDesc, RMLoaderAPI factory ) +{ + return Result::Error; +} + + + +} // sw + diff --git a/Loaders/SoilTextureLoader/SoilTextureLoader.h b/Loaders/SoilTextureLoader/SoilTextureLoader.h new file mode 100644 index 0000000..584ed6d --- /dev/null +++ b/Loaders/SoilTextureLoader/SoilTextureLoader.h @@ -0,0 +1,43 @@ +#pragma once +/** +@file SoilTextureLoader.h +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + + + +#include "swCommonLib/Common/TypesDefinitions.h" +#include "swCommonLib/System/Path.h" + +#include "swGraphicAPI/ResourceManager/Loaders/IAssetLoadInfo.h" +#include "swGraphicAPI/ResourceManager/Loaders/IAssetLoader.h" + + +namespace sw +{ + + +/**@brief Loades textures using SOIL library. +@ingroup Loaders +@ingroup TexturesLoaders*/ +class SoilTextureLoader : public IAssetLoader +{ +private: +public: + + explicit SoilTextureLoader () = default; + virtual ~SoilTextureLoader () = default; + + + virtual bool CanLoad ( const AssetPath& filePath, TypeID resourceType ) override; + virtual LoadingResult Load ( const LoadPath& filePath, TypeID resourceType, const IAssetLoadInfo* assetDesc, RMLoaderAPI factory ) override; + virtual ReturnResult Prefetch ( const LoadPath& filePath, TypeID resourceType, const IAssetLoadInfo* assetDesc, RMLoaderAPI factory ) override; + + +public: + + ReturnResult ValidateParameters ( const LoadPath& filePath, TypeID resourceType, const IAssetLoadInfo* assetDesc ); +}; + +} // sw diff --git a/Loaders/SoilTextureLoader/stdafx.cpp b/Loaders/SoilTextureLoader/stdafx.cpp new file mode 100644 index 0000000..03529ba --- /dev/null +++ b/Loaders/SoilTextureLoader/stdafx.cpp @@ -0,0 +1,9 @@ +// stdafx.cpp : source file that includes just the standard includes +// stdafx.obj will contain the pre-compiled type information + +#include "swGraphicAPI/Loaders/SoilTextureLoader/stdafx.h" + + + +// TODO: reference any additional headers you need in STDAFX.H +// and not in this file diff --git a/Loaders/SoilTextureLoader/stdafx.h b/Loaders/SoilTextureLoader/stdafx.h new file mode 100644 index 0000000..6f8701f --- /dev/null +++ b/Loaders/SoilTextureLoader/stdafx.h @@ -0,0 +1,40 @@ +#pragma once +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently +// + + +/// @note You can disable all headers in precompiled header with one macro. +/// All cpp files should be precompiled header independet and explicitly include needed headers. +#ifndef DISABLE_PRECOMPILED_HEADER + + +#include + +#include +#include +#include + +#include + +#include "swCommonLib/Common/RTTR.h" + +#include "swGraphicAPI/Resources/MeshResources.h" +#include "swGraphicAPI/Rendering/GraphicAPIConstants.h" +#include "swGraphicAPI/ResourceManager/ResourceManager.h" +#include "swGraphicAPI/Resources/ResourcesFactory.h" +#include "swGraphicAPI/Resources/SwapChain.h" + +#include "swGraphicAPI/ResourceManager/Loaders/IAssetLoadInfo.h" +#include "swGraphicAPI/ResourceManager/Loaders/IAssetLoader.h" + + +#undef min +#undef max +#undef RegisterClass + + +#endif // !DISABLE_PRECOMPILED_HEADER + + diff --git a/Loaders/swMaterialLoader/stdafx.cpp b/Loaders/swMaterialLoader/stdafx.cpp new file mode 100644 index 0000000..584ee2e --- /dev/null +++ b/Loaders/swMaterialLoader/stdafx.cpp @@ -0,0 +1,9 @@ +// stdafx.cpp : source file that includes just the standard includes +// stdafx.obj will contain the pre-compiled type information + +#include "swGraphicAPI/Loaders/swMaterialLoader/stdafx.h" + + + +// TODO: reference any additional headers you need in STDAFX.H +// and not in this file diff --git a/Loaders/swMaterialLoader/stdafx.h b/Loaders/swMaterialLoader/stdafx.h new file mode 100644 index 0000000..171a0ad --- /dev/null +++ b/Loaders/swMaterialLoader/stdafx.h @@ -0,0 +1,43 @@ +#pragma once +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently +// + + +/// @note You can disable all headers in precompiled header with one macro. +/// All cpp files should be precompiled header independet and explicitly include needed headers. +#ifndef DISABLE_PRECOMPILED_HEADER + + +#include + +#include +#include +#include + +#include + +#include "swCommonLib/Common/RTTR.h" + +#include "swGraphicAPI/Resources/MeshResources.h" +#include "swGraphicAPI/Rendering/GraphicAPIConstants.h" +#include "swGraphicAPI/ResourceManager/ResourceManager.h" +#include "swGraphicAPI/Resources/ResourcesFactory.h" +#include "swGraphicAPI/Resources/SwapChain.h" + +#include "swGraphicAPI/ResourceManager/Loaders/IAssetLoadInfo.h" +#include "swGraphicAPI/ResourceManager/Loaders/IAssetLoader.h" + +#include "swGraphicAPI/Assets/MaterialAsset/MaterialAsset.h" +#include "swGraphicAPI/Assets/MaterialAsset/MaterialAssetInitData.h" + + +#undef min +#undef max +#undef RegisterClass + + +#endif // !DISABLE_PRECOMPILED_HEADER + + diff --git a/Loaders/swMaterialLoader/swMaterialLoader.cpp b/Loaders/swMaterialLoader/swMaterialLoader.cpp new file mode 100644 index 0000000..4096d27 --- /dev/null +++ b/Loaders/swMaterialLoader/swMaterialLoader.cpp @@ -0,0 +1,548 @@ +/** +@file swMaterialLoader.cpp +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ +#include "swGraphicAPI/Loaders/swMaterialLoader/stdafx.h" + + +#include "swMaterialLoader.h" + +#include "swCommonLib/Common/Converters.h" +#include "swCommonLib/Serialization/PropertySerialization/Serialization.h" +#include "swCommonLib/Serialization/Deserializer.h" + +#include "swGraphicAPI/Assets/MaterialAsset/ShadingModelData.h" +#include "swGraphicAPI/Assets/MaterialAsset/PhongMaterialData.h" + +#include "swGraphicAPI/ResourceManager/Loaders/Tools/CanLoad.h" +#include "swGraphicAPI/ResourceManager/PathTranslators/LoadPath.h" +#include "swGraphicAPI/ResourceManager/Exceptions/LoaderException.h" + +#include "swCommonLib/Common/fmt.h" + + +namespace sw +{ + + +// ================================ // +// +SWMaterialLoader::~SWMaterialLoader() +{} + +// ================================ // +// +Version SWMaterialLoader::GetVersion () +{ + return Version( 0, 1, 0, 0 ); +} + +// ================================ // +// +bool SWMaterialLoader::CanLoad ( const AssetPath& filePath, TypeID resourceType ) +{ + std::string allowedExtensions[] = + { + ".swmat", + }; + + TypeID allowedTypes[] = + { + TypeID::get< MaterialAsset >(), + TypeID::get< Resource >() + }; + + return DefaultCanLoad( filePath, resourceType, allowedExtensions, allowedTypes ); +} + +// ================================ // +// +ReturnResult SWMaterialLoader::Prefetch ( const LoadPath& filePath, TypeID resourceType, const IAssetLoadInfo* assetDesc, RMLoaderAPI factory ) +{ + return ReturnResult(); +} + + +struct STRINGS_0_1_0 +{ + static const std::string FILE_HEADER_STRING; + static const std::string VERSION; + + static const std::string FILE_PATH_STRING; + static const std::string SHADER_ENTRY_STRING; + + static const std::string VERTEX_SHADER_STRING; + static const std::string PIXEL_SHADER_STRING; + static const std::string GEOMETRY_SHADER_STRING; + static const std::string CONTROL_SHADER_STRING; + static const std::string EVALUATION_SHADER_STRING; + + static const std::string TEXTURES_ARRAY_STRING; + static const std::string TEXTURE_STRING; + + static const std::string ADD_BUFFERS_ARRAY_STRING; + static const std::string BUFFER_SIZE_STRING; + static const std::string SHADING_DATA_STRING; + static const std::string SHADING_MODEL_WRAPPER_TYPE_STRING; +}; + +const std::string STRINGS_0_1_0::FILE_HEADER_STRING = "swMaterial"; +const std::string STRINGS_0_1_0::VERSION = "Version"; + +const std::string STRINGS_0_1_0::FILE_PATH_STRING = "FilePath"; +const std::string STRINGS_0_1_0::SHADER_ENTRY_STRING = "ShaderEntry"; + +const std::string STRINGS_0_1_0::VERTEX_SHADER_STRING = "VertexShader"; +const std::string STRINGS_0_1_0::PIXEL_SHADER_STRING = "PixelShader"; +const std::string STRINGS_0_1_0::GEOMETRY_SHADER_STRING = "GeometryShader"; +const std::string STRINGS_0_1_0::CONTROL_SHADER_STRING = "TesselationControlShader"; +const std::string STRINGS_0_1_0::EVALUATION_SHADER_STRING = "TesselationEvaluationShader"; + +const std::string STRINGS_0_1_0::TEXTURES_ARRAY_STRING = "Textures"; +const std::string STRINGS_0_1_0::TEXTURE_STRING = "Texture"; + +const std::string STRINGS_0_1_0::ADD_BUFFERS_ARRAY_STRING = "AdditionalBuffers"; +const std::string STRINGS_0_1_0::BUFFER_SIZE_STRING = "BufferSize"; +const std::string STRINGS_0_1_0::SHADING_DATA_STRING = "ShadingModel"; +const std::string STRINGS_0_1_0::SHADING_MODEL_WRAPPER_TYPE_STRING = "WrapperType"; + + +const uint32 cMaxMaterialTextures = 5; + + + +// ================================ // +// +LoadingResult SWMaterialLoader::Load ( const LoadPath& path, TypeID resourceType, const IAssetLoadInfo* assetDesc, RMLoaderAPI factory ) +{ + IDeserializer deser( std::make_unique< SerializationContext >() ); + + if( !deser.LoadFromFile( path.GetFileTranslated().String(), ParsingMode::ParseInsitu ) ) + return LoaderException::Create( "swMaterialLoader", "Deserialization failed: " + deser.GetError() + " ].", path, TypeID::get< MaterialAsset >() ); + + if( deser.EnterObject( STRINGS_0_1_0::FILE_HEADER_STRING ) ) + { + auto loaderVersion = GetVersion(); + + auto versionStr = deser.GetAttribute( STRINGS_0_1_0::VERSION, "" ); + auto version = Version::From( versionStr ); + + if( !version.IsValid() ) + return LoaderException::Create( "swMaterialLoader", "Can't parse version string.", path, TypeID::get< MaterialAsset >() ); + + if( loaderVersion.IsBackwardCompatibileWith( version ) ) + { + if( version.Get().Major == 0 ) + return LoadMaterial_Version0( path , &deser, LoadingContext( factory ) ); + } + else + { + std::string errorString = "File version " + version.Get().ToString() + " not supported. Maximal version " + loaderVersion.ToString(); + return LoaderException::Create( "swMaterialLoader", errorString, path, TypeID::get< MaterialAsset >() ); + } + + deser.Exit(); + } + + return LoaderException::Create( "swMaterialLoader", "Invalid .swmat file. Header not found.", path, TypeID::get< MaterialAsset >() ); +} + +// ================================ // +// @todo Maybe we should tell AssetsManager to release resources, if something went wrong. +LoadingResult SWMaterialLoader::LoadMaterial_Version0 ( const LoadPath& path, IDeserializer* deser, LoadingContext& context ) +{ + Nullable< MaterialInitData > data = Nullable< MaterialInitData >( MaterialInitData () ); + + if( deser->EnterObject( TypeID::get< MaterialAsset >().get_name().to_string() ) ) + { + data = LoadShaders( deser, data, context ); + data = LoadTextures( deser, data, context ); + data = LoadShadingData( deser, data, context ); + data = LoadAdditionalBuffers( deser, data, context ); + + deser->Exit(); + + // Create MaterialAsset here. + return CreateMaterial( path, data, context ); + } + + return LoaderException::Create( "swMaterialLoader", "Invalid .swmat file. MaterialAsset entry not found.", path, TypeID::get< MaterialAsset >() ); +} + +// ================================ // +// +LoadingResult SWMaterialLoader::CreateMaterial ( const LoadPath& path, Nullable< MaterialInitData >& init, LoadingContext& context ) +{ + if( !init.IsValid() ) + return LoaderException::Create( "swMaterialLoader", init.GetErrorReason(), path, TypeID::get< MaterialAsset >() ); + + init.Get().AutoCreateBuffer( path.GetOriginalPath(), context.Factory ); + + auto result = context.Factory.CreateAsset< MaterialAsset >( path.GetOriginalPath(), std::move( init ).Get() ); + if( result.IsValid() ) + { + context.CollectAsset( result.Get() ); + return { std::move( context.AssetsCollection ), context.Warnings.GetException() }; + } + + return { result.GetError(), std::move( context.Warnings ) }; +} + +// ================================ // +// +template< typename ShaderType > +inline Nullable< ResourcePtr< ShaderType > > SWMaterialLoader::LoadShader ( const AssetPath& shaderPath, LoadingContext& context ) +{ + if( !shaderPath.GetFile().HasFileName() ) + return Nullable< ResourcePtr< ShaderType > >( fmt::format( "{} path is not set.", Convert::ToString< ShaderType >() ) ); + + auto shaderLoadResult = context.Factory.LoadShader< ShaderType >( shaderPath ); + if( !shaderLoadResult.IsValid() ) + return Nullable< ResourcePtr< ShaderType > >( Convert::ToString< ShaderType >() + " file could not be loaded." ); + + return shaderLoadResult; +} + +// ================================ // +// +Nullable< AssetPath > SWMaterialLoader::DeserializeShader ( IDeserializer* deser, const std::string& shaderNameString ) +{ + const char* shaderFile = nullptr; + const char* shaderEntry = nullptr; + + if( deser->EnterObject( shaderNameString ) ) + { + shaderEntry = deser->GetAttribute( STRINGS_0_1_0::SHADER_ENTRY_STRING, ( const char* )nullptr ); + shaderFile = deser->GetAttribute( STRINGS_0_1_0::FILE_PATH_STRING, ( const char* )nullptr ); + + deser->Exit(); + + if( shaderFile && shaderFile ) + return AssetPath( shaderFile, shaderEntry ); + + // If there's no entrypoint, default main function will be loaded. + if( shaderFile ) + return AssetPath( shaderFile, filesystem::Path() ); + } + + return "No shader."; +} + +// ================================ // +// +template< typename ShaderType > +ResourcePtr< ShaderType > SWMaterialLoader::LoadOptionalShader ( IDeserializer* deser, const std::string& shaderNameString, LoadingContext& context ) +{ + auto shaderPath = DeserializeShader( deser, shaderNameString ); + + // Note: It's ok, if shader doesn't exist. + if( shaderPath.IsValid() ) + { + auto shader = LoadShader< ShaderType >( shaderPath.Get(), context ); + + // Here we expect, that shader will be loaded correctly, because we found entry + // in swmat file. If somethinf was wrong we threat this only as warning. + if( context.CollectAssetOrWarn( shader ) ) + return std::move( shader ).Get(); + } + + return nullptr; +} + +// ================================ // +// +Nullable< MaterialInitData > SWMaterialLoader::LoadShaders ( IDeserializer* deser, Nullable< MaterialInitData >& init, LoadingContext& context ) +{ + ReturnIfInvalid( init ); + + auto vertexShaderPath = DeserializeShader( deser, STRINGS_0_1_0::VERTEX_SHADER_STRING ); + if( !vertexShaderPath.IsValid() ) + return "Can't deserialize vertex shader."; + + auto vertexShader = LoadShader< VertexShader >( vertexShaderPath.Get(), context ); + if( vertexShader.IsValid() ) + { + context.CollectAsset( vertexShader.Get() ); + init.Get().VertexShader = std::move( vertexShader ).Get(); + } + else + { + return vertexShader.GetError(); + } + + auto pixelShaderPath = DeserializeShader( deser, STRINGS_0_1_0::PIXEL_SHADER_STRING ); + if( !pixelShaderPath.IsValid() ) + return "Can't deserialize pixel shader."; + + auto pixelShader = LoadShader< PixelShader >( pixelShaderPath.Get(), context ); + if( pixelShader.IsValid() ) + { + context.CollectAsset( pixelShader.Get() ); + init.Get().PixelShader = std::move( pixelShader ).Get(); + } + else + { + return pixelShader.GetError(); + } + + + // Note: We don't check if shader was created. Nullptrs are acceptable value. + init.Get().GeometryShader = LoadOptionalShader< GeometryShader >( deser, STRINGS_0_1_0::GEOMETRY_SHADER_STRING, context ); + init.Get().TesselationEvaluationShader = LoadOptionalShader< EvaluationShader >( deser, STRINGS_0_1_0::EVALUATION_SHADER_STRING, context ); + init.Get().TesselationControlShader = LoadOptionalShader< ControlShader >( deser, STRINGS_0_1_0::CONTROL_SHADER_STRING, context ); + + return std::move( init ); +} + +// ================================ // +// +Nullable< MaterialInitData > SWMaterialLoader::LoadTextures ( IDeserializer* deser, Nullable< MaterialInitData >& init, LoadingContext& context ) +{ + ReturnIfInvalid( init ); + + // Textures + if( deser->EnterArray( STRINGS_0_1_0::TEXTURES_ARRAY_STRING ) ) + { + if( deser->FirstElement() ) + { + int texIdx = 0; + do + { + assert( deser->GetName() == STRINGS_0_1_0::TEXTURE_STRING ); + + auto assetPath = AssetPath::FromString( deser->GetAttribute( STRINGS_0_1_0::FILE_PATH_STRING, "" ) ); + + // AssetPath must have system path part (checked by HasFileName). + // We don't support generated textures so internal path can't be alone. + if( assetPath.IsValid() && assetPath.Get().GetFile().HasFileName() ) + { + auto tex = context.Factory.LoadTexture( assetPath ); + if( context.CollectAssetOrWarn( tex ) ) + init.Get().Textures[ texIdx ] = tex.Get(); + } + + texIdx++; + } while( deser->NextElement() && texIdx < cMaxMaterialTextures ); + + } + deser->Exit(); + } + + return std::move( init ); +} + +// ================================ // +// +Nullable< MaterialInitData > SWMaterialLoader::LoadShadingData ( IDeserializer* deser, Nullable< MaterialInitData >& init, LoadingContext& context ) +{ + ReturnIfInvalid( init ); + auto& initData = init.Get(); + + + // Shading model data + if( deser->EnterObject( STRINGS_0_1_0::SHADING_DATA_STRING ) ) + { + uint32 bufferSize = deser->GetAttribute( STRINGS_0_1_0::BUFFER_SIZE_STRING, (uint32)0 ); + const char* wrapperName = deser->GetAttribute( STRINGS_0_1_0::SHADING_MODEL_WRAPPER_TYPE_STRING, nullptr ); + + if( !wrapperName ) + return Nullable< MaterialInitData >( "File doesn't contain WrapperType field." ); + + TypeID wrapper = TypeID::get_by_name( wrapperName ); + if( !wrapper.is_valid() ) + return Nullable< MaterialInitData >( "WrapperType is not registered." ); + + auto constructor = wrapper.get_constructor(); + if( !constructor.is_valid() ) + return Nullable< MaterialInitData >( "WrapperType constructor is not registered." ); + + rttr::variant object = wrapper.create(); + if( !object.is_valid() ) + return Nullable< MaterialInitData >( "WrapperType could not be created." ); + + if( !object.can_convert( TypeID::get< ShadingModelBase* >() ) ) + return Nullable< MaterialInitData >( "Can't convert MaterialData to ShadingModelBase*. Make sure, constructor was declared with AsRawPtr policy." ); + + initData.ShadingData = UPtr< ShadingModelBase >( object.get_value< ShadingModelBase* >() ); + + if( initData.ShadingData->GetSize() != bufferSize ) + return Nullable< MaterialInitData >( "Declared buffer size is other then real buffer size." ); + + + rttr::variant dataObject = (void*)initData.ShadingData->GetData(); + dataObject.unsafe_convert_void( initData.ShadingData->GetShadingModelPtrType() ); + + + if( deser->EnterObject( initData.ShadingData->GetShadingModelTypeName() ) ) + { + SerializationCore::DefaultDeserializeImpl( *deser, dataObject, initData.ShadingData->GetShadingModelType() ); + + deser->Exit(); + } + else + return Nullable< MaterialInitData >( initData.ShadingData->GetShadingModelTypeName() + " not found in file." ); + + deser->Exit(); + } + + return std::move( init ); +} + +// ================================ // +// +Nullable< MaterialInitData > SWMaterialLoader::LoadAdditionalBuffers ( IDeserializer* deser, Nullable< MaterialInitData >& init, LoadingContext& context ) +{ + ReturnIfInvalid( init ); + auto& initData = init.Get(); + + std::vector< ParametricBufferInfo >& addBuffers = init.Get().AdditionalBuffers; + + if( deser->EnterArray( STRINGS_0_1_0::ADD_BUFFERS_ARRAY_STRING ) ) + { + auto arraySize = deser->GetAttribute( "ArraySize", 0 ); + if( arraySize != 0 ) + addBuffers.reserve( arraySize ); + + if( deser->FirstElement() ) + { + do + { + ParametricBufferInfo newBuffer; + addBuffers.push_back( newBuffer ); + auto newBuffRealPtr = &addBuffers[ addBuffers.size() - 1 ]; + + rttr::variant buffVariant = newBuffRealPtr; + + SerializationCore::DefaultDeserializeImpl( *deser, buffVariant, TypeID::get< ParametricBufferInfo >() ); + + } while( deser->NextElement() ); + } + + deser->Exit(); + } + // else there's no buffers probably. It's not an error. + + return std::move( init ); +} + + + +//====================================================================================// +// Material Saver +//====================================================================================// + +// ================================ // +// +void SWMaterialLoader::SaveMaterial ( const filesystem::Path& fileName, MaterialAsset* mat ) +{ + ISerializer ser( std::make_unique< SerializationContext >() ); + + ser.EnterObject( STRINGS_0_1_0::FILE_HEADER_STRING ); + + WriteHeader( ser ); + + ser.EnterObject( TypeID::get< MaterialAsset >().get_name().to_string() ); + + // Shaders + WriteShader( ser, mat->GetVertexShader().Ptr(), STRINGS_0_1_0::VERTEX_SHADER_STRING ); + WriteShader( ser, mat->GetPixelShader().Ptr(), STRINGS_0_1_0::PIXEL_SHADER_STRING ); + WriteShader( ser, mat->GetGeometryShader().Ptr(), STRINGS_0_1_0::GEOMETRY_SHADER_STRING ); + WriteShader( ser, mat->GetTessControlShader().Ptr(), STRINGS_0_1_0::CONTROL_SHADER_STRING ); + WriteShader( ser, mat->GetTessEvaluationShader().Ptr(), STRINGS_0_1_0::EVALUATION_SHADER_STRING ); + + // Textures + WriteTextures( ser, mat ); + + // Shading model data + WriteShadingModel( ser, mat->GetDescriptor().ShadingData.get() ); + + // Additional buffers + WriteParametersBuffers( ser, mat ); + + + ser.Exit(); // type name + + ser.Exit(); // SWMaterial + + ser.SaveFile( fileName.String(), WritingMode::Readable ); +} + +// ================================ // +// +void SWMaterialLoader::WriteHeader ( ISerializer& ser ) +{ + ser.SetAttribute( STRINGS_0_1_0::VERSION, SWMaterialLoader::GetVersion().ToString() ); +} + +// ================================ // +// +void SWMaterialLoader::WriteShader ( ISerializer& ser, IShader* shader, const std::string& entry ) +{ + ser.EnterObject( entry ); + if( shader ) + { + auto assetPath = shader->GetAssetPath(); + + ser.SetAttribute( STRINGS_0_1_0::FILE_PATH_STRING, assetPath.GetFile().String() ); + ser.SetAttribute( STRINGS_0_1_0::SHADER_ENTRY_STRING, assetPath.GetInternalPath().String() ); + } + ser.Exit(); +} + +// ================================ // +// +void SWMaterialLoader::WriteTextures ( ISerializer& ser, MaterialAssetPtr mat ) +{ + ser.EnterArray( STRINGS_0_1_0::TEXTURES_ARRAY_STRING ); + + for( int i = 0; i < cMaxMaterialTextures; ++i ) + { + auto tex = mat->GetTexture( i ); + WriteTexture( ser, tex ); + } + + ser.Exit(); // Textures +} + +// ================================ // +// +void SWMaterialLoader::WriteTexture ( ISerializer& ser, TexturePtr tex ) +{ + ser.EnterObject( STRINGS_0_1_0::TEXTURE_STRING ); + + if( tex ) + ser.SetAttribute( STRINGS_0_1_0::FILE_PATH_STRING, tex->GetAssetPath().String() ); + + ser.Exit(); +} + +// ================================ // +// +void SWMaterialLoader::WriteShadingModel ( ISerializer& ser, ShadingModelBase* shadingData ) +{ + TypeID shadingModelType = shadingData->GetShadingModelType(); + TypeID shadingModelPtrType = shadingData->GetShadingModelPtrType(); + + rttr::variant shadingDataPtr( (void* )shadingData->GetData() ); + shadingDataPtr.unsafe_convert_void( shadingModelPtrType ); + + ser.EnterObject( STRINGS_0_1_0::SHADING_DATA_STRING ); + + ser.SetAttribute( STRINGS_0_1_0::SHADING_MODEL_WRAPPER_TYPE_STRING, shadingData->GetTypeName() ); + ser.SetAttribute( STRINGS_0_1_0::BUFFER_SIZE_STRING, shadingData->GetSize() ); + + Serialization().Serialize( ser, shadingDataPtr ); + + ser.Exit(); // SHADING_DATA_STRING +} + +// ================================ // +// +void SWMaterialLoader::WriteParametersBuffers ( ISerializer& ser, MaterialAssetPtr mat ) +{ + Serialization().Serialize( ser, mat->GetDescriptor().ParametricBuffers ); +} + + +} // sw \ No newline at end of file diff --git a/Loaders/swMaterialLoader/swMaterialLoader.h b/Loaders/swMaterialLoader/swMaterialLoader.h new file mode 100644 index 0000000..53c3f38 --- /dev/null +++ b/Loaders/swMaterialLoader/swMaterialLoader.h @@ -0,0 +1,88 @@ +#pragma once +/** +@file swMaterialLoader.h +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + + + +#include "swCommonLib/Common/Exceptions/Nullable.h" +#include "swCommonLib/Common/Version.h" +#include "swCommonLib/System/Path.h" + +#include "swGraphicAPI/ResourceManager/Loaders/IAssetLoadInfo.h" +#include "swGraphicAPI/ResourceManager/Loaders/IAssetLoader.h" + +#include "swGraphicAPI/ResourceManager/Loaders/Tools/LoadingContext.h" + +#include "swGraphicAPI/Assets/MaterialAsset/MaterialAssetInitData.h" +#include "swGraphicAPI/Assets/MaterialAsset/MaterialAsset.h" + + +namespace sw +{ + + +/**@brief Loads .swmat files. + +@todo Handle relative paths of textures and shaders. Caller can choose if he wants +to use path aliases or relative paths. + +@todo Add tests of ParametricBuffers. Create some utilities to use them in renderers. + +@todo More elegant handling of shading models. There's should be no need to register +ShadingModelData wrapper. Material file should contain only shading model structure name +defined by user. + +@todo Extract asset saver interface. Saver should support versioning. It should be able to +save older material format version. + +@ingroup Loaders*/ +class SWMaterialLoader : public IAssetLoader +{ +private: +public: + explicit SWMaterialLoader () = default; + virtual ~SWMaterialLoader (); + + virtual bool CanLoad ( const AssetPath& filePath, TypeID resourceType ) override; + virtual LoadingResult Load ( const LoadPath& filePath, TypeID resourceType, const IAssetLoadInfo* assetDesc, RMLoaderAPI context ) override; + virtual ReturnResult Prefetch ( const LoadPath& filePath, TypeID resourceType, const IAssetLoadInfo* assetDesc, RMLoaderAPI factory ) override; + +public: + + static Version GetVersion (); + void SaveMaterial ( const filesystem::Path& fileName, MaterialAsset* mat ); + +private: + + LoadingResult LoadMaterial_Version0 ( const LoadPath& path, IDeserializer* deser, LoadingContext& context ); + + LoadingResult CreateMaterial ( const LoadPath& path, Nullable< MaterialInitData >& init, LoadingContext& context ); + + Nullable< MaterialInitData > LoadShaders ( IDeserializer* deser, Nullable< MaterialInitData >& init, LoadingContext& context ); + Nullable< MaterialInitData > LoadTextures ( IDeserializer* deser, Nullable< MaterialInitData >& init, LoadingContext& context ); + Nullable< MaterialInitData > LoadShadingData ( IDeserializer* deser, Nullable< MaterialInitData >& init, LoadingContext& context ); + Nullable< MaterialInitData > LoadAdditionalBuffers ( IDeserializer* deser, Nullable< MaterialInitData >& init, LoadingContext& context ); + + Nullable< AssetPath > DeserializeShader ( IDeserializer* deser, const std::string& shaderNameString ); + + template< typename ShaderType > + Nullable< ResourcePtr< ShaderType > > LoadShader ( const AssetPath& shaderPath, LoadingContext& context ); + + template< typename ShaderType > + ResourcePtr< ShaderType > LoadOptionalShader ( IDeserializer* deser, const std::string& shaderNameString, LoadingContext& context ); + +protected: + + void WriteHeader ( ISerializer& ser ); + void WriteShader ( ISerializer& ser, IShader* shader, const std::string& entry ); + void WriteTextures ( ISerializer& ser, MaterialAssetPtr mat ); + void WriteTexture ( ISerializer& ser, TexturePtr tex ); + void WriteShadingModel ( ISerializer& ser, ShadingModelBase* shadingData ); + void WriteParametersBuffers ( ISerializer& ser, MaterialAssetPtr mat ); +}; + + +} // sw \ No newline at end of file diff --git a/MockAPI/MockInitializer/MockInitializer.cpp b/MockAPI/MockInitializer/MockInitializer.cpp index 4b82f85..ef09198 100644 --- a/MockAPI/MockInitializer/MockInitializer.cpp +++ b/MockAPI/MockInitializer/MockInitializer.cpp @@ -32,18 +32,18 @@ IRenderer* MockInitializer::CreateRenderer ( RendererUsage usage ) /**@brief */ SwapChain* MockInitializer::CreateSwapChain ( const SwapChainInitData& swapChainData ) { - MockRenderTarget* renderTargetObject = new MockRenderTarget( nullptr, nullptr, nullptr ); - renderTargetObject->SetHeight( static_cast( swapChainData.WindowHeight ) ); - renderTargetObject->SetWidth( static_cast( swapChainData.WindowWidth ) ); + MockRenderTarget* renderTargetObject = new MockRenderTarget( AssetPath( "", "/RenderTarget" ), nullptr, nullptr, nullptr ); + renderTargetObject->SetHeight( static_cast< uint16 >( swapChainData.WindowHeight ) ); + renderTargetObject->SetWidth( static_cast< uint16 >( swapChainData.WindowWidth ) ); MockSwapChain* newSwapChain = new MockSwapChain( renderTargetObject ); return newSwapChain; } /**@brief */ -bool MockInitializer::InitAPI ( const GraphicAPIInitData& initData ) +ReturnResult MockInitializer::InitAPI ( const GraphicAPIInitData& initData ) { - return true; + return Result::Success; } /**@brief */ @@ -51,15 +51,15 @@ void MockInitializer::ReleaseAPI () {} /**@brief Not working. Use regular API.*/ -void* MockInitializer::GetRenderTargetHandle ( RenderTargetObject* renderTarget ) +void* MockInitializer::GetRenderTargetHandle ( RenderTarget* renderTarget ) { return nullptr; } /**@brief Creates only device and device context.*/ -Nullable< bool > MockInitializer::InitDevices ( const GraphicAPIInitData& initData ) +ReturnResult MockInitializer::InitDevices ( const GraphicAPIInitData& initData ) { - return true; + return Result::Success; } } // sw diff --git a/MockAPI/MockInitializer/MockInitializer.h b/MockAPI/MockInitializer/MockInitializer.h index 6c07256..e6dccc6 100644 --- a/MockAPI/MockInitializer/MockInitializer.h +++ b/MockAPI/MockInitializer/MockInitializer.h @@ -5,7 +5,7 @@ @copyright Plik jest cz�ci� silnika graficznego SWEngine. */ -#include "swCommonLib/Common/Nullable.h" +#include "swCommonLib/Common/Exceptions/Nullable.h" #include "swGraphicAPI/Rendering/IGraphicAPIInitializer.h" #include "swGraphicAPI/Resources/SwapChain.h" @@ -34,12 +34,12 @@ class MockInitializer : public IGraphicAPIInitializer virtual IRenderer* CreateRenderer ( RendererUsage usage ) override; virtual SwapChain* CreateSwapChain ( const SwapChainInitData& swapChainData ) override; - virtual bool InitAPI ( const GraphicAPIInitData& initData ) override; + virtual ReturnResult InitAPI ( const GraphicAPIInitData& initData ) override; virtual void ReleaseAPI () override; - virtual void* GetRenderTargetHandle ( RenderTargetObject* renderTarget ) override; + virtual void* GetRenderTargetHandle ( RenderTarget* renderTarget ) override; private: - Nullable< bool > InitDevices ( const GraphicAPIInitData& initData ); + ReturnResult InitDevices ( const GraphicAPIInitData& initData ); }; } // sw diff --git a/MockAPI/MockRenderer/MockRenderer.cpp b/MockAPI/MockRenderer/MockRenderer.cpp index 798d7b7..94fa259 100644 --- a/MockAPI/MockRenderer/MockRenderer.cpp +++ b/MockAPI/MockRenderer/MockRenderer.cpp @@ -75,7 +75,10 @@ void MockRenderer::SetRenderTarget ( const SetRenderTargetExCommand& command ) // ================================ // // void MockRenderer::ClearRenderTarget ( const ClearRenderTargetCommand& command ) -{} +{ + if( command.RenderTarget == nullptr ) + throw RuntimeException( "[ClearRenderTarget] RenderTarget is set to nullptr." ); +} // ================================ // // @@ -133,7 +136,7 @@ void MockRenderer::FlushCommands () // ================================ // // -bool MockRenderer::SetVertexBuffer ( BufferObject* buffer, unsigned int offset ) +bool MockRenderer::SetVertexBuffer ( Buffer* buffer, unsigned int offset ) { if( buffer ) { @@ -150,17 +153,17 @@ bool MockRenderer::SetVertexBuffer ( BufferObject* buffer, unsigned int off // ================================ // // Buffer can be nullptr. -void MockRenderer::SetIndexBuffer ( BufferObject* buffer, unsigned int offset, bool extendedIndex ) +void MockRenderer::SetIndexBuffer ( Buffer* buffer, unsigned int offset, bool extendedIndex ) {} // ================================ // // -void MockRenderer::SetRenderTarget ( RenderTargetObject* const targets[ MAX_BOUND_RENDER_TARGETS ], RenderTargetObject* depthStencil ) +void MockRenderer::SetRenderTarget ( RenderTarget* const targets[ MAX_BOUND_RENDER_TARGETS ], RenderTarget* depthStencil ) {} // ================================ // // -void MockRenderer::SetTextures ( TextureObject* const texturesArray[ MAX_BOUND_RENDER_TARGETS ], const uint8 shaderTypes[ MAX_BOUND_RENDER_TARGETS ] ) +void MockRenderer::SetTextures ( Texture* const texturesArray[ MAX_BOUND_RENDER_TARGETS ], const uint8 shaderTypes[ MAX_BOUND_RENDER_TARGETS ] ) {} } // sw diff --git a/MockAPI/MockRenderer/MockRenderer.h b/MockAPI/MockRenderer/MockRenderer.h index 63b8bb4..f2eb0e6 100644 --- a/MockAPI/MockRenderer/MockRenderer.h +++ b/MockAPI/MockRenderer/MockRenderer.h @@ -9,9 +9,9 @@ #include "swGraphicAPI/Resources/MeshResources.h" -#include "swGraphicAPI/Resources/BlendingState.h" -#include "swGraphicAPI/Resources/RasterizerState.h" -#include "swGraphicAPI/Resources/DepthStencilState.h" +#include "swGraphicAPI/Resources/PipelineStates/BlendingState.h" +#include "swGraphicAPI/Resources/PipelineStates/RasterizerState.h" +#include "swGraphicAPI/Resources/PipelineStates/DepthStencilState.h" #include "swGraphicAPI/Rendering/IRenderer.h" class MockRenderer; @@ -75,10 +75,10 @@ class MockRenderer : public IRenderer private: - bool SetVertexBuffer ( BufferObject* buffer, unsigned int offset ); - void SetIndexBuffer ( BufferObject* buffer, unsigned int offset, bool extendedIndex ); - void SetRenderTarget ( RenderTargetObject* const targets[ MAX_BOUND_RENDER_TARGETS ], RenderTargetObject* depthStencil ); - void SetTextures ( TextureObject* const texturesArray[ MAX_BOUND_RENDER_TARGETS ], const uint8 shaderTypes[ MAX_BOUND_RENDER_TARGETS ] ); + bool SetVertexBuffer ( Buffer* buffer, unsigned int offset ); + void SetIndexBuffer ( Buffer* buffer, unsigned int offset, bool extendedIndex ); + void SetRenderTarget ( RenderTarget* const targets[ MAX_BOUND_RENDER_TARGETS ], RenderTarget* depthStencil ); + void SetTextures ( Texture* const texturesArray[ MAX_BOUND_RENDER_TARGETS ], const uint8 shaderTypes[ MAX_BOUND_RENDER_TARGETS ] ); }; } // sw diff --git a/MockAPI/MockResources/MockBuffer.cpp b/MockAPI/MockResources/MockBuffer.cpp index 8b99c69..1431924 100644 --- a/MockAPI/MockResources/MockBuffer.cpp +++ b/MockAPI/MockResources/MockBuffer.cpp @@ -20,20 +20,21 @@ namespace sw { - -MockBuffer::MockBuffer( const std::wstring& name, const BufferInfo& descriptor ) - : BufferObject( descriptor.ElementSize, descriptor.NumElements ) +// ================================ // +// +MockBuffer::MockBuffer( const AssetPath& name, const BufferInfo& descriptor ) + : Buffer( name, descriptor.ElementSize, descriptor.NumElements ) , m_descriptor( descriptor ) -{ - m_descriptor.Name = name; -} +{} +// ================================ // +// MockBuffer::~MockBuffer() {} /**@brief */ -MockBuffer* MockBuffer::CreateFromMemory ( const std::wstring& name, const uint8* data, const BufferInfo& bufferInfo ) +sw::Nullable< Buffer* > MockBuffer::CreateFromMemory ( const AssetPath& name, const uint8* data, const BufferInfo& bufferInfo ) { MockBuffer* newBufferObject = new MockBuffer( name, bufferInfo ); return newBufferObject; @@ -41,7 +42,7 @@ MockBuffer* MockBuffer::CreateFromMemory ( const std::wstring& name, const uint /**@brief*/ -MemoryChunk MockBuffer::CopyData() +MemoryChunk MockBuffer::CopyData () { MemoryChunk memoryChunk; return std::move( memoryChunk ); diff --git a/MockAPI/MockResources/MockBuffer.h b/MockAPI/MockResources/MockBuffer.h index 2314f119b663f64ab8ecf8c4008de03f2a1c24f7..a6b17b148c1d62a08e5f17182020bc3469a1aa09 100644 GIT binary patch delta 348 zcmdnR{f=h?594G3MhRbMhJ1!xAk1gTWAI_fWJqGrXFwLyXK-bxU`S?2Whh`M0m_5a z6$91yF_bdo0AV6fM-EU{k0FCWX)`;cEaPMYCZoxDOf{1iv52s9GJs&+JD11|#?7#9Ey0cp2J2Cx%jn zG$2f6C}PlH&}6V?;AP-qC;*BkG2}300@YZ7ML2QjPynjPXUJnHW+-7$0Fx;|9aaqG zV0IDEggl0H1~s5u9z!BSF3=vG$#0osCz^;bYE7Bp$8&;XgTx=--ue>+m diff --git a/MockAPI/MockResources/MockComputeShader.cpp b/MockAPI/MockResources/MockComputeShader.cpp index 0d8d80d954339df448b23f2b21ceb8e8c2c5e3ee..7da02ed520dc563e54dc10eaf678e537c13fdfd5 100644 GIT binary patch literal 2754 zcmd6pT~FIE6o$`jChb2&nS@xiwfAG7F$5DA>!xGpT6yR?S!Ni zr5T7ZS+O1aoa6K5_xSg(j}w}M!w@>jnnNvVAt%jP8`DekzJ0a*+DhA<)Uu8nrLDdfj()&7XU?9`qDD54petq6 z$DVzm_3RtpzJ0Jm^w9q<{h@ubuH(9Lec-Ig>EF;&w3hZ67Rs)id4m4hlYTKf8FJrZ zTZRXXH(7&`Tr{nd4m5SpOJr&0ot>kCvA`f_*H0#hp+kRjRot#ph z#`V@V^NIYSe4C-WvT2tw!w3=c=G;-|*&M>gA!AhNRpNxnH40 z9q)zu$Ii>X*6PJ@>M&naI;%N{-W;memsCV$oc_v6;o}pqdUB(=q__F>mdfGMy(#Hs z;Ud07ydg?TRod#+kdO~=^JEqBEELoFJF&~(0!l5+z6^p`T2et{58(6rYe2K|gYujTCT+m84QUGDL{2a41PdXE|8_epumvKkPkE+WDkf9Qd7jB1!NCBnz z%_+&KIJul%ak2oH1g{>0D?p5#!g&m(K)2*D6oB1r&A`jRHCd5Wlr;~i zyBy?Vehmgq2Cz6oEm(FwlRCmLpm2cr-4M<1Ko_M!{TUB*FU0){K(l~0FjT|r;YG23 MvLKV_&)0l-j0&c)g9}865z3~qeA~jH%mx^v;48%l zE)sG=-0%$eO^_pFKEM_8J&na>U5^zR86##dSzoZa!#fpti&*Ir4~Q!yrMim~jfTk9 zNk~}c;*8J`T@n@TfcdT#RBb~xX=ynR{)5vz+|%SC|4B*p@jK_Ejcd+H1-6ScFNcpK z?ie!yHdphh?H8V$S0P=qE~ezWSdkrLR(^>kzCOgFbgg=Im-0E;1&;N2139)EFQvEw`d4&Q8E<>sa!Y=ij;#jo%Q?&WM`+*Lww1wsd2X%MLatlT Pl?m5MwR45Mvsb?XNBv;; delta 249 zcmX@ayNP>(++-d`na$G}r!Y=-U{+(*V9;c+o?OhVInhXE@&RVH$vMnCn>kq27$@hj zaq*Tj6f=}C6ftBnWpP9B9j$Zu{pyR=*WLS4=rJn0{~rEH@N@+ diff --git a/MockAPI/MockResources/MockInputLayout.cpp b/MockAPI/MockResources/MockInputLayout.cpp index 76d57fe..5975987 100644 --- a/MockAPI/MockResources/MockInputLayout.cpp +++ b/MockAPI/MockResources/MockInputLayout.cpp @@ -17,10 +17,21 @@ RTTR_REGISTRATION namespace sw { -MockInputLayout::MockInputLayout() +// ================================ // +// +MockInputLayout::MockInputLayout ( const AssetPath& fileName ) + : ShaderInputLayout( fileName ) {} +// ================================ // +// +sw::Nullable< MockInputLayout* > MockInputLayout::CreateLayout ( const AssetPath& fileName, const InputLayoutDescriptor& layoutDesc ) +{ + return new MockInputLayout( fileName ); +} +// ================================ // +// MockInputLayout::~MockInputLayout() {} diff --git a/MockAPI/MockResources/MockInputLayout.h b/MockAPI/MockResources/MockInputLayout.h index c26e2e9..f00d28e 100644 --- a/MockAPI/MockResources/MockInputLayout.h +++ b/MockAPI/MockResources/MockInputLayout.h @@ -2,9 +2,11 @@ /** @file MockInputLayout.h @author nieznanysprawiciel -@copyright Plik jest cz�ci� silnika graficznego SWEngine. +@copyright File is part of Sleeping Wombat Libraries. */ +#include "swCommonLib/Common/Exceptions/Nullable.h" + #include "swGraphicAPI/Resources/MeshResources.h" @@ -20,10 +22,14 @@ class MockInputLayout : public ShaderInputLayout RTTR_ENABLE( ShaderInputLayout ); private: protected: - ~MockInputLayout(); + + virtual ~MockInputLayout (); + public: - MockInputLayout(); + explicit MockInputLayout ( const AssetPath& fileName ); + + static sw::Nullable< MockInputLayout* > CreateLayout ( const AssetPath& fileName, const InputLayoutDescriptor& layoutDesc ); }; } // sw diff --git a/MockAPI/MockResources/MockInputLayoutDescriptor.cpp b/MockAPI/MockResources/MockInputLayoutDescriptor.cpp deleted file mode 100644 index e17cdfd..0000000 --- a/MockAPI/MockResources/MockInputLayoutDescriptor.cpp +++ /dev/null @@ -1,48 +0,0 @@ -/** -@file MockInputLayoutDescriptor.cpp -@author nieznanysprawiciel -@copyright File is part of graphic engine SWEngine. -*/ - - -#include "MockInputLayoutDescriptor.h" - -#include - - - -namespace sw -{ - - -// ================================ // -// -void MockInputLayoutDescriptor::AddRow( const char* semanticName, ResourceFormat format, unsigned int inputSlot, unsigned int byteOffset, bool perInstance, unsigned int instanceDataStep ) -{ - InputLayoutInfo inputElement; - inputElement.SemanticName = semanticName; - inputElement.Format = format; - inputElement.InputSlot = inputSlot; - inputElement.ByteOffset = byteOffset; - inputElement.InstanceDataStep = instanceDataStep; - inputElement.PerInstance = perInstance; - inputElement.SemanticName = semanticName; - - m_inputElement.push_back( inputElement ); -} - -// ================================ // -// -unsigned int MockInputLayoutDescriptor::CountSemantic( const char* semanticName ) -{ - unsigned int numSemantic = 0; - - for( auto element : m_inputElement ) - if( strcmp( element.SemanticName, semanticName ) == 0 ) - ++numSemantic; - - return numSemantic; -} - -} // sw - diff --git a/MockAPI/MockResources/MockInputLayoutDescriptor.h b/MockAPI/MockResources/MockInputLayoutDescriptor.h deleted file mode 100644 index 40f68a3..0000000 --- a/MockAPI/MockResources/MockInputLayoutDescriptor.h +++ /dev/null @@ -1,45 +0,0 @@ -#pragma once - - -#include "swGraphicAPI/Resources/MeshResources.h" - -#include - - -namespace sw -{ - -struct InputLayoutInfo -{ - const char* SemanticName; - ResourceFormat Format; - unsigned int InputSlot; - unsigned int ByteOffset; - bool PerInstance; - unsigned int InstanceDataStep; -}; - - -/**@brief -@ingroup MockAPI*/ -class MockInputLayoutDescriptor : public InputLayoutDescriptor -{ -private: - std::vector< InputLayoutInfo > m_inputElement; -public: - MockInputLayoutDescriptor( const std::wstring& layoutName ) : InputLayoutDescriptor( layoutName ) {} - ~MockInputLayoutDescriptor() = default; - - Size GetNumElements() { return m_inputElement.size(); } - - virtual void AddRow( const char* semanticName, - ResourceFormat format, - unsigned int inputSlot, - unsigned int byteOffset, - bool perInstance, - unsigned int instanceDataStep ); - - unsigned int CountSemantic( const char* semanticName ); -}; - -} // sw diff --git a/MockAPI/MockResources/MockPipelineState.cpp b/MockAPI/MockResources/MockPipelineState.cpp index 648b2d3..ed95cfe 100644 --- a/MockAPI/MockResources/MockPipelineState.cpp +++ b/MockAPI/MockResources/MockPipelineState.cpp @@ -23,29 +23,23 @@ namespace sw // RasterizerState //====================================================================================// -MockRasterizerState::MockRasterizerState( const RasterizerStateInfo& info ) - : m_info( info ) +MockRasterizerState::MockRasterizerState ( const AssetPath& name, const RasterizerStateInfo& info ) + : RasterizerState( name ) + , m_info( info ) {} // ================================ // // -std::string MockRasterizerState::GetResourceName() const -{ - return std::string(); -} - -// ================================ // -// -const RasterizerStateInfo& MockRasterizerState::GetDescriptor() +const RasterizerStateInfo& MockRasterizerState::GetDescriptor () const { return m_info; } // ================================ // // -MockRasterizerState* MockRasterizerState::Create ( const RasterizerStateInfo& info ) +MockRasterizerState* MockRasterizerState::Create ( const AssetPath& name, const RasterizerStateInfo& info ) { - return new MockRasterizerState( info ); + return new MockRasterizerState( name, info ); } @@ -54,29 +48,23 @@ MockRasterizerState* MockRasterizerState::Create ( const RasterizerStateInfo& // DepthStencilState //====================================================================================// -MockDepthStencilState::MockDepthStencilState( const DepthStencilInfo& info ) - : m_info( info ) +MockDepthStencilState::MockDepthStencilState ( const AssetPath& name, const DepthStencilInfo& info ) + : DepthStencilState( name ) + , m_info( info ) {} // ================================ // // -std::string MockDepthStencilState::GetResourceName() const -{ - return std::string(); -} - -// ================================ // -// -const DepthStencilInfo& MockDepthStencilState::GetDescriptor() +const DepthStencilInfo& MockDepthStencilState::GetDescriptor () const { return m_info; } // ================================ // // -MockDepthStencilState* MockDepthStencilState::Create ( const DepthStencilInfo& info ) +MockDepthStencilState* MockDepthStencilState::Create ( const AssetPath& name, const DepthStencilInfo& info ) { - return new MockDepthStencilState( info ); + return new MockDepthStencilState( name, info ); } @@ -85,27 +73,24 @@ MockDepthStencilState* MockDepthStencilState::Create ( const DepthStencilInf // BlendingState //====================================================================================// -MockBlendingState::MockBlendingState( const BlendingInfo& info ) - : m_info( info ) +MockBlendingState::MockBlendingState ( const AssetPath& name, const BlendingInfo& info ) + : BlendingState( name ) + , m_info( info ) {} -// ================================ // -// -std::string MockBlendingState::GetResourceName() const -{ - return std::string(); -} // ================================ // // -const BlendingInfo& MockBlendingState::GetDescriptor() +const BlendingInfo& MockBlendingState::GetDescriptor () const { return m_info; } -MockBlendingState* MockBlendingState::Create ( const BlendingInfo & info ) +// ================================ // +// +MockBlendingState* MockBlendingState::Create ( const AssetPath& name, const BlendingInfo & info ) { - return new MockBlendingState( info ); + return new MockBlendingState( name, info ); } } // sw diff --git a/MockAPI/MockResources/MockPipelineState.h b/MockAPI/MockResources/MockPipelineState.h index d8ab880..298bd45 100644 --- a/MockAPI/MockResources/MockPipelineState.h +++ b/MockAPI/MockResources/MockPipelineState.h @@ -6,9 +6,9 @@ */ -#include "swGraphicAPI/Resources/BlendingState.h" -#include "swGraphicAPI/Resources/DepthStencilState.h" -#include "swGraphicAPI/Resources/RasterizerState.h" +#include "swGraphicAPI/Resources/PipelineStates/BlendingState.h" +#include "swGraphicAPI/Resources/PipelineStates/DepthStencilState.h" +#include "swGraphicAPI/Resources/PipelineStates/RasterizerState.h" @@ -28,14 +28,12 @@ class MockRasterizerState : public RasterizerState protected: ~MockRasterizerState() = default; public: - explicit MockRasterizerState ( const RasterizerStateInfo& info ); + explicit MockRasterizerState ( const AssetPath& name, const RasterizerStateInfo& info ); - // Inherited via RasterizerState - virtual std::string GetResourceName () const override; - virtual const RasterizerStateInfo& GetDescriptor () override; + virtual const RasterizerStateInfo& GetDescriptor () const override; - static MockRasterizerState* Create ( const RasterizerStateInfo& info ); + static MockRasterizerState* Create ( const AssetPath& name, const RasterizerStateInfo& info ); }; @@ -51,14 +49,12 @@ class MockDepthStencilState : public DepthStencilState protected: ~MockDepthStencilState() = default; public: - explicit MockDepthStencilState ( const DepthStencilInfo& info ); + explicit MockDepthStencilState ( const AssetPath& name, const DepthStencilInfo& info ); - // Inherited via DepthStencilState - virtual std::string GetResourceName () const override; - virtual const DepthStencilInfo& GetDescriptor () override; + virtual const DepthStencilInfo& GetDescriptor () const override; - static MockDepthStencilState* Create ( const DepthStencilInfo& info ); + static MockDepthStencilState* Create ( const AssetPath& name, const DepthStencilInfo& info ); }; @@ -75,14 +71,12 @@ class MockBlendingState : public BlendingState protected: ~MockBlendingState() = default; public: - explicit MockBlendingState ( const BlendingInfo& info ); + explicit MockBlendingState ( const AssetPath& name, const BlendingInfo& info ); - // Inherited via BlendingState - virtual std::string GetResourceName () const override; - virtual const BlendingInfo& GetDescriptor () override; + virtual const BlendingInfo& GetDescriptor () const override; - static MockBlendingState* Create ( const BlendingInfo& info ); + static MockBlendingState* Create ( const AssetPath& name, const BlendingInfo& info ); }; } // sw diff --git a/MockAPI/MockResources/MockPixelShader.cpp b/MockAPI/MockResources/MockPixelShader.cpp index 85364cc6d509407cd7e689d926235184157eb10b..a15207fd82f668b3ef68b470604d21dee4d0ebc4 100644 GIT binary patch delta 543 zcmb7Bu}Z^W5dNe#>7QCqBGgbzLqu&wEG{aITA~O};_eh}p@Oa2#G!+ZzQAohg{y-| z1~+l`5d^^}aPa#JRR=}N!Topl-Q9op-SyOS{`M(dS5PR!#Su=?L4=rgz&ApZ_C7-D z7Umf3&~7v8qJkVO*43cod^Dfa^sv1a7Pm@cS4bIWp< zEy|U-A|1mTqHE3c>|g$u1M^W{lq+kQU3oReQdPJTj0EglrRWU@?;b92LJ4t5-NZUG z6RVV7;H;aHnDg?UnOxl_gAJmZ(IHrsAiJzI`?_{fCNhq+)VSRwqcOVZ;f&a^_T*kU z_8@bK*==GmdQ!AX6%RWDpHoG=S=jH`rT1Oq!IuZak%m=ve%y=~_4^xNYAtWs!Y60O BTw?$L delta 458 zcmX>n-X^i(3@f9?WPP?mFsVOz13TAb7IwSI790^!w%KGc4n83Nh64{7J(+nKxF)Y<6Q3Nwro*T;`7fvSWGkRaPF!NDICL?nF(@#k0ZqtZ zNM-PwoX=&*Tg;HbkO;IP6=*U@MBF+VEK&uW2R+j@5*JJ?N%}@;{If3S- zF=zlq6(|4ZPz3r(mQ$QpkHM9p0w@D=N%3SsZh8JZhEkxtISd70Usz9epRyh@Mmg4<03Lqb)Q|Y$I9^dh@KTzd^is z5Py$|2mgn&+Z;rYN0QCVy!Yn4eVTpFJ}l&1R2f-JV+&{Kp$}hvTIIVMx(Vvx5;6Zm z3?VR}#>Wl69-lErh=_Z*BHq?qKgnw|BcftR^ql!Iv-fyr2cCM&6y!bfiV4|W;8?Rh zq6P&6rU{&o3eciZ$@Yo2bVF6vXOWt2SB3jnEFbJ>alrQ=k-GSex!A=ueX;|~^|WpT z7l)j&&+u4W`BT#`z7<~$X`3^d3?^|azbwb(S$-Q%&S#~F>dD-((nup!mJK`aY}43? zbz&T8<6SJ#yxLhnRJ>PG>xPr8n?kk5m_&e8Mv@{=?UKAt<>iYxKlj(*8ZW703T(&^ uvy@gNc6f1hyHNP2wQO4TDRm_sxoNEweVU26$1z6;IfD8VSVmJ`q$@vCu4tbC literal 1940 zcmc(gT}vBL5Qg8|E%ZMu5sHS=^rBahf>pE>s)*@*iEGrwO|oQTY?1V*w?1?B<80Cs zNJS`zlii&&AMeb(bMoi+j&jX3)Q!gc#+quPL?gY{E4O!)I!UH`T_KOvQK1KYc2>D= zIZyOS=lY_aF3>3OanGrFDUhAI=WXEZ9oC&DQXO#uj z$7CGR^e7`T{>Hk{cOC1D*oXSc+wMl&SbN%c$gC%+7Q~-}rQgV=?mKb6SCu@{uO`1R zrrnlbpF!z0+S=AKt9Jyp6pV8!GNd9gb(yj5gL}8GPMEbf zoLyIyIK#8?-MYW27FPGjc`!zl{Hr+~?s>OCe?(nJ#4sjp>caC;zXfwRW6QmrZ_%2k zI_Guk#OchKYO9@}Kg-paVNCnT?$C>Zx%$9<&zGN^m#osu_IEv3&yD|6sghG6t{d+M zRD0gcP~ES3BJ2(ecYRx)KjL9b_u5^q?}oC+>+`XX#nRnCb~F4vp&oU6Mpuz<#=T7s k$_Wi2KW3_p?LWb2{A_1cBk=f_)eUDISW@dA%m2qc0Y;WETL1t6 diff --git a/MockAPI/MockResources/MockRenderTarget.cpp b/MockAPI/MockResources/MockRenderTarget.cpp index b053701ea60043926ec799206141d63c671491d5..132bd13243283c8188a8dae4fb23bf4f06f1a16e 100644 GIT binary patch delta 955 zcmb_aO-~b16g@M2AcNC(uq|O6KgKGxMN&207(>+t{6Hfi7!wm?49HYXaDvmKlDJ{7 zCgd*MDNA>j%*GfOCMIr>g=-Rj2@B7R6d~Oaax?GU&-3oRb6S<37h3NUGMQB+9}P6& zqQ<)ckNPC0c|JjbUZ46idWYdkS`BJLvaB4j)G7I39hQ_T$Q3mv^M*3EGs9)2>1R6O ziiFEk2!%Ts#T2emCh$fmfe^CB(nR3r4_H{fMzBjtGL>~8LRX=h20bd;@kdM>xxQ`GJFdEcjB+`A%@(gG- z=@0OjRug5~5p4&}7G{7yUKn?2#L-c9XR8Q0^2C^-TRct<7eZ5B~t z=~;et!bHPWvTqm`$uefXGaT!P#;-0JN&oN7E z`C^qT9e)K84cc63@9f&vMxq@JlVP^3m`4(kUbXI$X*c$S^U<=Um2BhKvT2Qwt;g6` zDxB|g^*w>s)KU4K>5)%nHg523=Er~P$F0}1-{f5Gb@(+mq^CW+A{!QBf}O{hEDc9wS8-~0=TEXh*< delta 487 zcmX?RvB7vlAG2f#Ln=cBLkUAELlKbW&yd8B1*DT1N+w?vl%D*HS&bW6OrFINh5t}k zesUd)8ZVL>293=dSs0ln3$ZI~R$vccn(W4`F!>6r+2m)O8sf!3n^G98fUuka#4cjU zWXNMk-z?9?%E+4sbVLpi7Jwu+ujZC#Vpd?#o?OT;KiPy&X>t_b87SXz@;3fkaJgRs zYLit2*P*!UqM+yG3BqEN=Ly-Mh|9A`Pktk)2b2p!7T^3(*q3SY0F}ZW7-! zxlf93vYkW?h~B(QLW@b&l_7#5gdvn6h{2U19>|Jh2!OJXWG26tayCWc<5tOF$lwB$ obp)Ch1SBITdrRA^6Q|R7@<%C0Wn5~VfNpdHLRW^M$q%Jd0qg#BkN^Mx diff --git a/MockAPI/MockResources/MockRenderTarget.h b/MockAPI/MockResources/MockRenderTarget.h index dc5d527bae07f09fbf52ca381850e58c05178bc1..66cf8ae50ea161a0c489b8c16066732e7284440f 100644 GIT binary patch delta 678 zcmaJN<`TYN4Jb!C{z=6GBxKNtCob`irWdOlvVoMwLs$c#OpMw-vd{)#+0W{P!8yL66MeM(!0X5Th*;IydIO&RazQ+ zvoG&*bdWKKPidp^Q|(O5`o_eEcEQ~d55At5@xO?7e|A+WPa)S=Bel!NkR9sO-@!U< kc!C@JiY<-h2 zuq~Ke#BRWiaN+0$qe}nc?`usmneYA6b36GEC;iT7&3u!>63jq O4o?>1RGDnUIRyacw>rxJ diff --git a/MockAPI/MockResources/MockSwapChain.cpp b/MockAPI/MockResources/MockSwapChain.cpp index 408c787..81bb221 100644 --- a/MockAPI/MockResources/MockSwapChain.cpp +++ b/MockAPI/MockResources/MockSwapChain.cpp @@ -19,29 +19,34 @@ RTTR_REGISTRATION namespace sw { -MockSwapChain::MockSwapChain( RenderTargetObject* screenRT ) + +// ================================ // +// +MockSwapChain::MockSwapChain( RenderTarget* screenRT ) : SwapChain( screenRT ) {} +// ================================ // +// MockSwapChain::~MockSwapChain() {} /**@copydoc SwapChain::Present.*/ -void MockSwapChain::Present( int syncInterval ) +void MockSwapChain::Present ( int syncInterval ) { //m_swapChain->Present( syncInterval, 0 ); } /**@copydoc SwapChain::Resize.*/ -void MockSwapChain::Resize( uint16 newWidth, uint16 newHeight ) +void MockSwapChain::Resize ( uint16 newWidth, uint16 newHeight ) { assert( !"Implement me" ); } /**@brief */ -MockSwapChain* MockSwapChain::CreateScreenSwapChain( RenderTargetObject* screenRT ) +MockSwapChain* MockSwapChain::CreateScreenSwapChain ( RenderTarget* screenRT ) { MockSwapChain* swapChainObject = new MockSwapChain( screenRT ); return swapChainObject; diff --git a/MockAPI/MockResources/MockSwapChain.h b/MockAPI/MockResources/MockSwapChain.h index 890d869..1660704 100644 --- a/MockAPI/MockResources/MockSwapChain.h +++ b/MockAPI/MockResources/MockSwapChain.h @@ -15,14 +15,14 @@ class MockSwapChain : public SwapChain RTTR_ENABLE( SwapChain ) private: public: - MockSwapChain( RenderTargetObject* screenRT ); - ~MockSwapChain(); + explicit MockSwapChain ( RenderTarget* screenRT ); + virtual ~MockSwapChain (); virtual void Present ( int syncInterval ) override; virtual void Resize ( uint16 newWidth, uint16 newHeight ) override; public: - static MockSwapChain* CreateScreenSwapChain ( RenderTargetObject* screenRT ); + static MockSwapChain* CreateScreenSwapChain ( RenderTarget* screenRT ); }; } // sw diff --git a/MockAPI/MockResources/MockTexture.cpp b/MockAPI/MockResources/MockTexture.cpp index a54ef0e..a229bdd 100644 --- a/MockAPI/MockResources/MockTexture.cpp +++ b/MockAPI/MockResources/MockTexture.cpp @@ -29,8 +29,9 @@ void MockTexture::Construct() /**@brief */ -MockTexture::MockTexture( TextureInfo&& texInfo ) - : m_descriptor( std::move( texInfo ) ) +MockTexture::MockTexture( const AssetPath& name, TextureInfo&& texInfo ) + : Texture( name ) + , m_descriptor( std::move( texInfo ) ) { Construct(); } @@ -44,36 +45,39 @@ MockTexture::~MockTexture() {} -/**@copydoc TextureObject::GetDescriptor.*/ -const TextureInfo& MockTexture::GetDescriptor() const +/**@copydoc Texture::GetDescriptor.*/ +const TextureInfo& MockTexture::GetDescriptor() const { return m_descriptor; } -/**@copydoc TextureObject::GetFilePath.*/ -const filesystem::Path& MockTexture::GetFilePath() const +/**@brief */ +MockTexture* MockTexture::CreateFromMemory ( const MemoryChunk& texData, TextureInfo&& texInfo ) { - return m_descriptor.FilePath; -} + if( texData.IsNull() ) + return nullptr; + return new MockTexture( AssetPath( texInfo.FilePath, "" ), std::move( texInfo ) ); +} -/**@brief */ -MockTexture* MockTexture::CreateFromMemory( const MemoryChunk& texData, TextureInfo&& texInfo ) +// ================================ // +// +sw::Nullable< MockTexture* > MockTexture::CreateFromMemory ( const AssetPath& name, const BufferRaw& texData, TextureInfo&& texInfo ) { - if( texData.IsNull() ) + if( texData.GetData() == nullptr ) return nullptr; - return new MockTexture( std::move( texInfo ) ); + return new MockTexture( name, std::move( texInfo ) ); } /**@brief */ -bool MockTexture::UpdateData ( uint8* dataPtr, uint16 mipLevel, uint16 arrayIdx ) +bool MockTexture::UpdateData ( uint8* dataPtr, uint16 mipLevel, uint16 arrayIdx ) { return true; } /**@brief */ -MemoryChunk MockTexture::CopyData() const +MemoryChunk MockTexture::CopyData () const { MemoryChunk memoryChunk( m_descriptor.MemorySize ); return std::move( memoryChunk ); diff --git a/MockAPI/MockResources/MockTexture.h b/MockAPI/MockResources/MockTexture.h index bedb08aa0d140242f115259008fac44319ffdf2b..9f5aaf7b560839e74d7365ec5fa1e4897c93e6e2 100644 GIT binary patch delta 598 zcmaJ;%Syvg5IsrAqGFLkMN54|7sV89K-~DYii#p4D!6c!medy7G&Gf}8}$n`+%ItN zPTjjG`W^m)U*NgdE@BrlBy(r(oO5R8b_ZWmj}yZV^0Xuduz?C{sKbLLQu@ek0o7jK z#U{UnTUWDEoLu>Zxg-4v(lgs83#nR)J>E6 z7EaWyhhUxsK4BKlNYg-xg_7Wa`H~Wpv>r(cN-hs4%5jUtDij;6+U+=eAs-&mQIEMf#9JZ5*jxRFPv=K0^bZ zcrsUC-u12~(&mSqP!PE=`6d>l4wh(rU13E`nprlrCW_|b`o990B~QGa_!8C9#Dn?v E192U6f&c&j delta 154 zcmdlYc!Xzy+$6@L$!<(LxcwQD7_t~r8Il=FCjVtJMd2GV%T5krcAGqhSz_`TW+_$; z22BR*$zPeHH`lTJVVt~+nQ!txRzBM_hD?SWpb^Ckl|WnqWaTng0bu|`B9NECpvJ%n chVDR_5(YP@YN+hwy{v|lOW4j#_TtC_0HWn5i2wiq diff --git a/MockAPI/MockResources/MockVertexShader.cpp b/MockAPI/MockResources/MockVertexShader.cpp index cb11c2f259fad0bf4f9fb29ff15b9422cf079fb0..98371d2c9c4740250942655d431cb8f406711e54 100644 GIT binary patch literal 2498 zcmd6p+iuf95QgVANW6m;Bvc~g+;gZXRf{5(f)WImm7C@ya+2+|gsMC`@crX%od%H@ zK~=QcwY@ttJM+)UKfX7u!FXs7?3MLxWMk`DWN&R|UHfbw`ARKk{bC&(T4HCu6LUIe z6nu#-pc%rG!aGGu&%W|Zm`lr`OL@Owzw2k?YrZZVb0|`F2k_@`AM#%4FoHAUJaG*o zX#0E*T-F?FNsG8?%HD`odUx!T9jxrcepADm{(R(gUF0v^j>zg2EFD56J2f{+XmRh{ zkvKx|xXCSi=^@K4)#t~YcqH)Ku6ZR9n-Xl{O-V@Z#h6X9_xm>5821<3F^8csQHKx-QnO@ZG+Y0^J-dl4U^><4Se< zr}N(Sd^6gRl*m#>{Ez|xL5W=M&YroQ8SGzM&3}>Mgx;C<>r(+$yt`$70kD=1p{csqv0I8!p#% zv|_9o6OF#o`k7Wg(zRpgYh|M6EklrK?y2rynXIv9BQ4QRBaQX-3+`rk9u9LOd$!YV z*th?$Y+gt5Q_~{}+Z$+lrdjC8`Ck%_wC~s~@kE&C!i!ZN3fELf(Q&MMY_uozF7x{G zvb9xsrn2+{?Q^cjLo-7??I^!uHTiDcu8sU+j^nXW;=Gpydyld0tXAWwmk@w!M$!cXCj=5KGj zVq3F!!uN*nt^G#t5s~NS52C80E62fe*C)=bL$wL=J3`@-GZdT1{j1g{Ws=#cEo)!M z&h_~V{uAjx)O>RKk^Du(#O%v8)A%!%^H<+>CAn%NuFc zmwuaBq$!==NTWQ{tztSSC;O$sgpM%ALjwC;;9L=fhFcJdy5Qriguwo&PVQkAhuMB8G?OzDPOrzLnE?q%7 zxBJl&JyP;0S{6t3Xo*^41D?9qXoZK3ju3RDHTFUJU>Rw22UHXMc}ufat&<2>l;yE; zV7AU!>NlarhaH`0fdA#M2G$>Fgx#*6RrC*STb)Xap->X}o&z4+bBmssKkjSnN-lS$ zC0$Ejd+(|D^4_E_mv<$?qn)iJDTTvY=zb8Hj;-k z&w4LGF0Rk($*1+6VYk(eJl0J%^9&nPcQl;Htrj)c)bw&$KgMNA^0$ z!E09y*oCT8MCi!#+~;-385m42#4^sy*oL?!SKHEME_8`H;5g!%QU#a~ql3#io-7|) zhI^i;#*9<|XJJ-!jm=^u#70?7XzLl$$}oJY)!4;*mru2t2)U_R?eD8}ImN7@D_kt& zeDpr6)8)w2a+q#`9LeWaRkbZjuVMo4tg`&48za|lH|lbYZv^C_cbA@LZLOp3dTu)p zRApCr2a`t~-|3U(+x_HdINM2&>UdnpTs`~gb_D)sb zi_rG}*)!1_&{354KGko1S?A+@19Hlbq*D53oz*7to4I$2@}7XNfW?@+YgMZpvyXzj zTw2VK{8z74`Ekx>`{eCk-#yY>CE-V%+j^tto71;CztLS{9e3>f{HxE$(_Pke_-I96 zby@gE;hOq**85fEV%Cdp$rgDQDwk94;k=aMm!WlhtDP?qyNRZCbE@8VKKz?amc3P( jzgcb;SJ%gFF)lr`SFOALW|DnDdMl3E*Fo2PY5Dsvj7bzW diff --git a/MockAPI/MockResources/MockVertexShader.h b/MockAPI/MockResources/MockVertexShader.h index 7102517b74821bc0037e62fae193c1868ae4fe22..f5a12d6dd54af6e95531476e8e09911cbcf28c7b 100644 GIT binary patch delta 504 zcmZuu%SyvQ6g{;KH9{Aqf`)=di=aW9oeLEoh`JHAxNx1c(FXD&iD(tk9}q0_CE{ne z(Y0H@Lp(DEDk7I;X6`xXo;!EG8lSbNnT8FEQNskbaSk5=JaJrY-M7&%vJNhh^Asb6 ziHIBzH(VWl17t{;cW}jgS7AY+>r#=BkurNheNOd0_jKUSr_v(I!C^V0{rN)z%Q6$%@_b2j#H&30+Ts=nf7 ztZ>Au1`LNDZ1efdNeZ#X7!jM|t!&l*SYv~)uuwL!DYi62lg;-;M>qbldeo-GLuFBu^X`e;%8KFf V+Bt_bVB;|xmnRcTSQj69>l<;6Wc2_5 literal 2558 zcmd6pT}vBL5QgV=3;hpE1hGN17rlxUtgS6Vm13l~lB}^=nvW%$XhqVWZu`ufY|hDM zw?td0ESsD?J7?y7-}y*>J#0xP6Y0n|8S)v+SVodaPhQFkySF5@oq^2civ3s`lFO}p zvQwG#d7sET`64H>FXvd~_?Yolz2xkj+IPR=-5#eK%Sak=1css6XROpiY|-@H{fcFb z=O)*obcvN>d5!HUu@m{u>V}<(O!@p_KKl4m{1cv1Vq`MlNn?$$>TsvVeb1sC@-#w| ziE+sS&yH!6=!z-9O9zB`VDZ(WxX5i7`nWBuGPLP(N>z)c&erpd(CvcjTrTBU&QSVD zKC{~S!|7OF$${b1+@@%u{Cd(_?v3p^vCpf;ek4Da`qkmu2|Rlq&TsUH)5t=GX}MLaO=E>hJ*S%axAUOf9e$SlpWZ4aet9x#CA7)& zbUAN}{w``nf9b-Uc_y1q#d|yq>Gp6c6u%;FCX}b?0Vn2*+FhUK9&^|etGMe?Z=%1O j=2f_l={%i{cOcYh7IG>Oc=YqdFQKYGN9lbo|Bvc7CRvPm diff --git a/MockAPI/MockResources/ResourcesFactory.cpp b/MockAPI/MockResources/ResourcesFactory.cpp index d95078a..228537f 100644 --- a/MockAPI/MockResources/ResourcesFactory.cpp +++ b/MockAPI/MockResources/ResourcesFactory.cpp @@ -13,7 +13,6 @@ #include "MockBuffer.h" #include "MockTexture.h" #include "MockRenderTarget.h" -#include "MockInputLayoutDescriptor.h" #include "MockInputLayout.h" #include "MockSwapChain.h" #include "MockPipelineState.h" @@ -22,107 +21,74 @@ -typedef sw::MockTexture Texture; +typedef sw::MockTexture TextureObject; typedef sw::MockVertexShader VertexShaderObject; typedef sw::MockPixelShader PixelShaderObject; -typedef sw::MockBuffer Buffer; +typedef sw::MockBuffer BufferObject; typedef sw::MockComputeShader ComputeShaderObject; typedef sw::MockDepthStencilState DepthStencilStateObject; typedef sw::MockRasterizerState RasterizerStateObject; typedef sw::MockBlendingState BlendingStateObject; -/**@brief Tworzy tekstur� z podanego deskryptora.*/ -TextureObject* ResourcesFactory::CreateTextureFromMemory ( const MemoryChunk& texData, TextureInfo&& texInfo ) -{ - return Texture::CreateFromMemory( texData, std::move( texInfo ) ); -} -/**@brief Tworzy obiekt vertex shadera. -@param[in] fileName Nazwa pliku z kodem shadera. -@param[in] shaderName Nazwa funkcji, od kt�rej ma si� rozpocz�� wykonanie programu shadera. -@param[in] shaderModel Shader model. -@return Zwraca obiekt vertex shadera lub nullptr w przypadku niepowodzenia.*/ -VertexShader* ResourcesFactory::CreateVertexShaderFromFile( const std::wstring& fileName, const std::string& shaderName, const char* shaderModel ) +namespace sw { - auto shader = VertexShaderObject::CreateFromFile( fileName, shaderName, shaderModel ); - if( shader ) - { - shader->SetFileName( fileName ); - shader->SetShaderName( shaderName ); - } - return shader; -} -/**@brief Tworzy obiekt vertex shadera oraz layout wierzcho�ka. - -@param[in] fileName Nazwa pliku z kodem shadera. -@param[in] shaderName Nazwa funkcji, od kt�rej ma si� rozpocz�� wykonanie programu shadera. -@param[out] layout Zwraca obiekt layoutu. -@param[in] layoutDesc Deskryptor opisuj�cy layout. -@param[in] shaderModel Shader model. -@return Zwraca obiekt vertex shadera lub nullptr w przypadku niepowodzenia.*/ -VertexShader* ResourcesFactory::CreateVertexShaderFromFile ( const std::wstring& fileName, - const std::string& shaderName, - ShaderInputLayout** layout, - InputLayoutDescriptor* layoutDesc, - const char* shaderModel/* = "vs_4_0"*/ ) + +// ================================ // +// +sw::Nullable< VertexShader* > ResourcesFactory::CreateVertexShader ( const AssetPath& fileName, const std::string& code, const std::string& entrypoint ) { - auto shader = VertexShaderObject::CreateFromFile( fileName, shaderName, layout, layoutDesc, shaderModel ); - if( shader ) - { - shader->SetFileName( fileName ); - shader->SetShaderName( shaderName ); - } - return shader; + return VertexShaderObject::CreateFromCode( fileName, code, entrypoint ); } -/**@brief Creates BlendingState.*/ -BlendingState* ResourcesFactory::CreateBlendingState ( const BlendingInfo& info ) +// ================================ // +// +sw::Nullable< PixelShader* > ResourcesFactory::CreatePixelShader ( const AssetPath& fileName, const std::string& code, const std::string& entrypoint ) { - return BlendingStateObject::Create( info ); + return PixelShaderObject::CreateFromCode( fileName, code, entrypoint ); } -/**@brief Creates RasterizerState*/ -RasterizerState* ResourcesFactory::CreateRasterizerState ( const RasterizerStateInfo& info ) +// ================================ // +// +sw::Nullable< ComputeShader* > ResourcesFactory::CreateComputeShader ( const AssetPath& fileName, const std::string& code, const std::string& entrypoint ) { - return RasterizerStateObject::Create( info ); + return ComputeShaderObject::CreateFromCode( fileName, code, entrypoint ); } -/**@brief Creates DepthStencilState.*/ -DepthStencilState* ResourcesFactory::CreateDepthStencilState ( const DepthStencilInfo& info ) +// ================================ // +// +sw::Nullable< ShaderInputLayout* > ResourcesFactory::CreateInputLayout ( const AssetPath& name, const InputLayoutDescriptor& layoutDesc ) { - return DepthStencilStateObject::Create( info ); + return sw::MockInputLayout::CreateLayout( name, layoutDesc ); } +// ================================ // +// +sw::Nullable< Texture* > ResourcesFactory::CreateTextureFromMemory ( const AssetPath& name, const BufferRaw& texData, sw::TextureInfo&& texInfo ) +{ + return TextureObject::CreateFromMemory( name, texData, std::move( texInfo ) ); +} -/**@brief Tworzy obekt pixel shadera. -@param[in] fileName Nazwa pliku z kodem shadera. -@param[in] shaderName Nazwa funkcji, od kt�rej ma si� rozpocz�� wykonanie programu shadera. -@param[in] shaderModel Shader model. -@return Zwraca obiekt vertex shadera lub nullptr w przypadku niepowodzenia.*/ -PixelShader* ResourcesFactory::CreatePixelShaderFromFile( const std::wstring& fileName, const std::string& shaderName, const char* shaderModel ) +/**@brief Creates BlendingState.*/ +sw::Nullable< BlendingState* > ResourcesFactory::CreateBlendingState ( const AssetPath& name, const BlendingInfo& info ) { - auto shader = PixelShaderObject::CreateFromFile( fileName, shaderName, shaderModel ); - if( shader ) - { - shader->SetFileName( fileName ); - shader->SetShaderName( shaderName ); - } - return shader; + return BlendingStateObject::Create( name, info ); } -/**@brief Tworzy obekt compute shadera. -@param[in] fileName Nazwa pliku z kodem shadera. -@param[in] shaderName Nazwa funkcji, od kt�rej ma si� rozpocz�� wykonanie programu shadera. -@param[in] shaderModel Shader model. -@return Zwraca obiekt vertex shadera lub nullptr w przypadku niepowodzenia.*/ -ComputeShader* ResourcesFactory::CreateComputeShaderFromFile ( const std::wstring& fileName, const std::string& shaderName, const char* shaderModel ) +/**@brief Creates RasterizerState*/ +sw::Nullable< RasterizerState* > ResourcesFactory::CreateRasterizerState ( const AssetPath& name, const RasterizerStateInfo& info ) { - return ComputeShaderObject::CreateFromFile( fileName, shaderName, shaderModel ); + return RasterizerStateObject::Create( name, info ); } +/**@brief Creates DepthStencilState.*/ +sw::Nullable< DepthStencilState* > ResourcesFactory::CreateDepthStencilState ( const AssetPath& name, const DepthStencilInfo& info ) +{ + return DepthStencilStateObject::Create( name, info ); +} /**@brief Tworzy bufor na podstawie sanych w pami�ci. @@ -130,37 +96,41 @@ ComputeShader* ResourcesFactory::CreateComputeShaderFromFile ( const std::wstr @param[in] data Pointer to initialization data. Memory can be released after call. @param[in] bufferInfo Buffer descriptor. @return Zwraca wska�nik na obiekt bufora lub nullptr w przypadku niepowodzenia.*/ -BufferObject* ResourcesFactory::CreateBufferFromMemory ( const std::wstring& name, const uint8* data, const BufferInfo& bufferInfo ) +sw::Nullable< Buffer* > ResourcesFactory::CreateBufferFromMemory ( const AssetPath& name, const uint8* data, const BufferInfo& bufferInfo ) { - return Buffer::CreateFromMemory( name, data, bufferInfo ); + return BufferObject::CreateFromMemory( name, data, bufferInfo ); } -/**Tworzy object RenderTargetObject z bufora tylnego ekranu. +/**Tworzy object RenderTarget z bufora tylnego ekranu. -@return Zwraca object RenderTargetObject.*/ -RenderTargetObject* ResourcesFactory::CreateScreenRenderTarget() +@return Zwraca object RenderTarget.*/ +RenderTarget* ResourcesFactory::CreateScreenRenderTarget () { return sw::MockRenderTarget::CreateScreenRenderTarget(); } -SwapChain* ResourcesFactory::CreateScreenSwapChain( RenderTargetObject* screenRT ) +// ================================ // +// +SwapChain* ResourcesFactory::CreateScreenSwapChain ( RenderTarget* screenRT ) { return sw::MockSwapChain::CreateScreenSwapChain( screenRT ); } -IGraphicAPIInitializer* ResourcesFactory::CreateAPIInitializer() +// ================================ // +// +IGraphicAPIInitializer* ResourcesFactory::CreateAPIInitializer () { return new sw::MockInitializer(); } -/**Tworzy obiekt deskryptora layoutu.*/ -InputLayoutDescriptor* ResourcesFactory::CreateInputLayoutDescriptor( const std::wstring& layoutName ) -{ - return new sw::MockInputLayoutDescriptor( layoutName ); -} - -RenderTargetObject* ResourcesFactory::CreateRenderTarget( const std::wstring& name, const RenderTargetDescriptor& renderTargetDescriptor ) +// ================================ // +// +sw::Nullable< RenderTarget* > ResourcesFactory::CreateRenderTarget ( const AssetPath& name, const RenderTargetDescriptor& renderTargetDescriptor ) { return sw::MockRenderTarget::CreateRenderTarget( name, renderTargetDescriptor ); } + +} // sw + + diff --git a/MockAssets/GraphicAPI.h b/MockAssets/GraphicAPI.h new file mode 100644 index 0000000..60776f8 --- /dev/null +++ b/MockAssets/GraphicAPI.h @@ -0,0 +1,112 @@ +#pragma once +/** +@file GraphicAPI.h +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + + +#include "swGraphicAPI/ResourceManager/ResourceManager.h" +#include "swGraphicAPI/ResourceManager/ResourceManagerAPI.h" +#include "swGraphicAPI/ResourceManager/Loaders/ShaderLoader.h" +#include "swGraphicAPI/ResourceManager/Loaders/RenderTargetLoader.h" +#include "swGraphicAPI/Loaders/SoilTextureLoader/SoilTextureLoader.h" + +#include "swGraphicAPI/Resources/ResourcesFactory.h" +#include "swGraphicAPI/Rendering/IGraphicAPIInitializer.h" + + + +// ================================ // +// +struct Graphic +{ + sw::IGraphicAPIInitializer* API; + sw::ResourceManager* RM; + sw::ResourceManagerAPI RMApi = sw::ResourceManagerAPI( nullptr ); + +// ================================ // +// + ~Graphic() + { + if( RM ) delete RM; + if( API ) + { + API->ReleaseAPI(); + delete API; + } + + API = nullptr; + RM = nullptr; + } +}; + + +// ================================ // +// +inline Graphic& GetGraphic () +{ + static Graphic graphic; + + if( !graphic.API ) + { + graphic.API = sw::ResourcesFactory::CreateAPIInitializer(); + + sw::GraphicAPIInitData graphicApiData; + graphicApiData.CreateSwapChain = false; // We will create swap chain and render target later with window. + graphicApiData.SingleThreaded = true; + graphicApiData.UseDebugLayer = true; + + auto result = graphic.API->InitAPI( graphicApiData ); + } + + if( !graphic.RM ) + { + graphic.RM = new sw::ResourceManager(); + graphic.RMApi = sw::ResourceManagerAPI( graphic.RM ); + } + + return graphic; +} + + +namespace sw +{ + +// ================================ // +// +inline std::unique_ptr< ResourceManager > CreateResourceManagerWithDefaults () +{ + std::unique_ptr< ResourceManager > rm = std::make_unique< ResourceManager >(); + + { + auto loader = std::make_shared< ShaderLoader >(); + rm->RegisterLoader( loader ); + } + + { + auto loader = std::make_shared< RenderTargetLoader >(); + rm->RegisterLoader( loader ); + } + + return std::move( rm ); +} + + +// ================================ // +// +inline std::unique_ptr< ResourceManager > CreateRMWithDefaultsSoil () +{ + auto rm = CreateResourceManagerWithDefaults(); + + { + auto loader = std::make_shared< SoilTextureLoader >(); + rm->RegisterLoader( loader ); + } + + return std::move( rm ); +} + + +} // sw + diff --git a/MockAssets/MockAsset.cpp b/MockAssets/MockAsset.cpp new file mode 100644 index 0000000..621daa4 --- /dev/null +++ b/MockAssets/MockAsset.cpp @@ -0,0 +1,39 @@ +/** +@file MockAsset.cpp +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + +#include "swGraphicAPI/MockAssets/stdafx.h" + +#include "MockAsset.h" +#include "MockAssetCreator.h" + + + + +namespace sw +{ + + + +// ================================ // +// +MockAsset::MockAsset ( MockAssetCreator* creator, const AssetPath& name, const std::string& content ) + : Resource( name ) + , m_creator( creator ) + , m_content( content ) +{ + m_creator->OnCreateAsset( this ); +} + +// ================================ // +// +MockAsset::~MockAsset() +{ + m_creator->OnDeleteAsset( this ); +} + + +} // sw + diff --git a/MockAssets/MockAsset.h b/MockAssets/MockAsset.h new file mode 100644 index 0000000..496f2b6 --- /dev/null +++ b/MockAssets/MockAsset.h @@ -0,0 +1,42 @@ +#pragma once +/** +@file MockAsset.h +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + +#include "swGraphicAPI/Resources/ResourceObject.h" + + + +namespace sw +{ + +class MockAssetCreator; + + +/**@brief Mocks asset.*/ +class MockAsset : public Resource +{ +private: + + MockAssetCreator* m_creator; ///< Remembers creator to remove reference after deletion. + std::string m_content; + +protected: +public: + explicit MockAsset ( MockAssetCreator* creator, const AssetPath& name, const std::string& content ); + virtual ~MockAsset (); + +public: + + std::string GetContent () const { return m_content; } + +}; +DEFINE_RESOURCE_PTR_TYPE( MockAsset ) + + +} // sw + + + diff --git a/MockAssets/MockAssetCreator.cpp b/MockAssets/MockAssetCreator.cpp new file mode 100644 index 0000000..7d6b059 --- /dev/null +++ b/MockAssets/MockAssetCreator.cpp @@ -0,0 +1,105 @@ +/** +@file MockAssetCreator.cpp +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + +#include "swGraphicAPI/MockAssets/stdafx.h" + +#include "MockAssetCreator.h" + +#include "MockAsset.h" +#include "swCommonLib/Common/Buffers/BufferTyped.h" + + + + +namespace sw +{ + +// ================================ // +// +Nullable< Resource* > MockAssetCreator::Create ( const AssetPath& assetName, IAssetCreateInfo&& createInfo ) +{ + if( createInfo.get_type() == TypeID::get< MockAssetCreateInfo >() ) + { + auto& typedInfo = static_cast< MockAssetCreateInfo& >(createInfo); + return new MockAsset( this, assetName, typedInfo.Content ); + } + + return "Wrong IAssetCreateInfo of type [" + createInfo.get_type().get_name().to_string() + "]."; +} + +// ================================ // +// +Nullable< Resource* > MockAssetCreator::LoadFromRaw ( const AssetPath& assetName, const BufferRaw& rawData ) +{ + assert( !"InputLayout is not cacheable" ); + return nullptr; +} + +// ================================ // +// +BufferRaw MockAssetCreator::SaveToRaw ( const IAssetCreateInfo& createInfo ) +{ + assert( !"InputLayout is not cacheable" ); + return BufferTyped< uint8 >::CreateEmpty(); +} + +// ================================ // +// +BufferRaw MockAssetCreator::SaveToRaw ( ResourcePtr< Resource > resource ) +{ + assert( !"InputLayout is not cacheable" ); + return BufferTyped< uint8 >::CreateEmpty(); +} + +// ================================ // +// +bool MockAssetCreator::IsCacheable () const +{ + return false; +} + +// ================================ // +// +bool MockAssetCreator::SupportsResourceToRaw() const +{ + return false; +} + +// ================================ // +// +TypeID MockAssetCreator::GetAssetType () const +{ + return TypeID::get< MockAsset >(); +} + +// ================================ // +// +void MockAssetCreator::OnDeleteAsset ( MockAsset* asset ) +{ + auto iter = std::find( m_livingAssets.begin(), m_livingAssets.end(), asset ); + m_livingAssets.erase( iter ); +} + +// ================================ // +// +void MockAssetCreator::OnCreateAsset ( MockAsset* asset ) +{ + m_livingAssets.push_back( asset ); +} + +// ================================ // +// +MockAssetCreatorPtr MockAssetCreator::CreateCreator () +{ + return std::make_shared< MockAssetCreator >(); +} + + + +} // sw + + + diff --git a/MockAssets/MockAssetCreator.h b/MockAssets/MockAssetCreator.h new file mode 100644 index 0000000..f922895 --- /dev/null +++ b/MockAssets/MockAssetCreator.h @@ -0,0 +1,79 @@ +#pragma once +/** +@file MockAssetCreator.h +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + + +#include "swGraphicAPI/ResourceManager/AssetCreators/IAssetCreator.h" + +#include + + +namespace sw +{ + +class MockAsset; +class MockAssetCreator; +DEFINE_PTR_TYPE( MockAssetCreator ); + + +/**@brief +@ingroup Mocks*/ +struct MockAssetCreateInfo : public IAssetCreateInfo +{ + RTTR_ENABLE( IAssetCreateInfo ); +public: + + std::string Content; + +public: + virtual TypeID GetAssetType () const { return TypeID::get< MockAsset >(); } +}; + + +/**@brief Creates MockAsset. +@ingroup Mocks*/ +class MockAssetCreator : public IAssetCreator +{ +private: + + std::vector< MockAsset* > m_livingAssets; + +protected: +public: + explicit MockAssetCreator () = default; + virtual ~MockAssetCreator () = default; + +public: + + virtual Nullable< Resource* > Create ( const AssetPath& assetName, IAssetCreateInfo&& createInfo ) override; + + virtual Nullable< Resource* > LoadFromRaw ( const AssetPath& assetName, const BufferRaw& rawData ) override; + virtual BufferRaw SaveToRaw ( const IAssetCreateInfo& createInfo ) override; + virtual BufferRaw SaveToRaw ( ResourcePtr< Resource > resource ) override; + + virtual bool IsCacheable () const override; + virtual bool SupportsResourceToRaw () const override; + virtual TypeID GetAssetType () const override; + +public: + + void OnDeleteAsset ( MockAsset* asset ); + void OnCreateAsset ( MockAsset* asset ); + + Size CountLivingAssets () const { return m_livingAssets.size(); } + +public: + + static MockAssetCreatorPtr CreateCreator (); + +}; + + + +} // sw + + + diff --git a/MockAssets/MockAssetLoader.cpp b/MockAssets/MockAssetLoader.cpp new file mode 100644 index 0000000..86ec46d --- /dev/null +++ b/MockAssets/MockAssetLoader.cpp @@ -0,0 +1,67 @@ +/** +@file MockAssetLoader.cpp +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + +#include "swGraphicAPI/MockAssets/stdafx.h" + +#include "MockAssetLoader.h" +#include "MockAsset.h" +#include "MockAssetCreator.h" + +#include "swCommonLib/System/File.h" + + +namespace sw +{ + +// ================================ // +// +bool MockAssetLoader::CanLoad ( const AssetPath& filePath, TypeID resourceType ) +{ + return filePath.GetFile().GetExtension() == ".mock" && + ( TypeID::get< MockAsset >() == resourceType || + TypeID::get< Resource >() == resourceType ); +} + +// ================================ // +// +LoadingResult MockAssetLoader::Load ( const LoadPath& filePath, TypeID resourceType, const IAssetLoadInfo* assetDesc, RMLoaderAPI factory ) +{ + LoadingResult result; + + if( resourceType != TypeID::get< MockAsset >() && + resourceType != TypeID::get< Resource >() ) + return "Can't load asset of type [" + resourceType.get_name().to_string() + "]."; + + + MockAssetCreateInfo createInfo; + + if( filePath.GetFile().Exists() ) + { + createInfo.Content = filesystem::File::Load( filePath.GetFile() ); + + auto res = factory.CreateGenericAsset( filePath.GetOriginalPath(), TypeID::get< MockAsset >(), std::move( createInfo ) ); + if( !res.IsValid() ) + return res.GetError(); + + return LoadingResult( res.Get() ); + } + else + { + return "File [" + filePath.GetFile().String() + "] doesn't exist."; + } +} + +// ================================ // +// +ReturnResult MockAssetLoader::Prefetch ( const LoadPath& filePath, TypeID resourceType, const IAssetLoadInfo* assetDesc, RMLoaderAPI factory ) +{ + return ReturnResult(); +} + + +} // sw + + diff --git a/MockAssets/MockAssetLoader.h b/MockAssets/MockAssetLoader.h new file mode 100644 index 0000000..15a9dcf --- /dev/null +++ b/MockAssets/MockAssetLoader.h @@ -0,0 +1,61 @@ +#pragma once +/** +@file MockAssetLoader.h +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + + +#include "swGraphicAPI/ResourceManager/Loaders/IAssetLoader.h" +#include "swGraphicAPI/ResourceManager/Loaders/IAssetLoadInfo.h" + +#include "MockAsset.h" + + + +namespace sw +{ + +// ================================ // +// +class MockAssetLoadInfo : public IAssetLoadInfo +{ +private: +protected: +public: + explicit MockAssetLoadInfo () = default; + virtual ~MockAssetLoadInfo () = default; + +public: + // ================================ // + // + TypeID MockAssetLoadInfo::GetAssetType () const override { return TypeID::get< MockAsset >(); } +}; + + + + +/**@brief MockAsset loader.*/ +class MockAssetLoader : public IAssetLoader +{ +private: +protected: +public: + explicit MockAssetLoader () = default; + virtual ~MockAssetLoader () = default; + + + // Inherited via IAssetLoader + virtual bool CanLoad ( const AssetPath& filePath, TypeID resourceType ) override; + virtual LoadingResult Load ( const LoadPath& filePath, TypeID resourceType, const IAssetLoadInfo* assetDesc, RMLoaderAPI factory ) override; + virtual ReturnResult Prefetch ( const LoadPath& filePath, TypeID resourceType, const IAssetLoadInfo* assetDesc, RMLoaderAPI factory ) override; + +}; + + + + +} // sw + + + diff --git a/MockAssets/MockCompositeAsset.cpp b/MockAssets/MockCompositeAsset.cpp new file mode 100644 index 0000000..9644b1a --- /dev/null +++ b/MockAssets/MockCompositeAsset.cpp @@ -0,0 +1,35 @@ +/** +@file MockCompositeAsset.h +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + +#include "swGraphicAPI/MockAssets/stdafx.h" + + +#include "MockCompositeAsset.h" + + + + + + +namespace sw +{ + +// ================================ // +// +MockCompositeAsset::MockCompositeAsset ( const AssetPath& name, std::vector< MockAssetPtr > subAssets, std::vector< MockCompositeAssetPtr > composites ) + : Resource( name ) + , m_subAssets( std::move( subAssets ) ) + , m_compositeSubAssets( std::move( composites ) ) +{} + +// ================================ // +// +MockCompositeAsset::~MockCompositeAsset() +{} + +} // sw + + diff --git a/MockAssets/MockCompositeAsset.h b/MockAssets/MockCompositeAsset.h new file mode 100644 index 0000000..0cbbfdd --- /dev/null +++ b/MockAssets/MockCompositeAsset.h @@ -0,0 +1,47 @@ +#pragma once +/** +@file MockCompositeAsset.h +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + + + +#include "swGraphicAPI/Resources/ResourceObject.h" + +#include "MockAsset.h" + +#include + + + + +namespace sw +{ + +class MockCompositeAsset; +DEFINE_RESOURCE_PTR_TYPE( MockCompositeAsset ); + + +/**@brief Mock Asset with dependent MockAssets.*/ +class MockCompositeAsset : public Resource +{ +private: + + std::vector< MockAssetPtr > m_subAssets; + std::vector< MockCompositeAssetPtr > m_compositeSubAssets; + +public: + explicit MockCompositeAsset ( const AssetPath& name, std::vector< MockAssetPtr > subAssets, std::vector< MockCompositeAssetPtr > composites ); + virtual ~MockCompositeAsset (); + + +public: + + std::vector< MockAssetPtr > GetSubAssets () const { return m_subAssets; } + std::vector< MockCompositeAssetPtr > GetCompositeSubAssets () const { return m_compositeSubAssets; } +}; + +} // sw + + diff --git a/MockAssets/MockCompositeAssetCreator.cpp b/MockAssets/MockCompositeAssetCreator.cpp new file mode 100644 index 0000000..48b60be --- /dev/null +++ b/MockAssets/MockCompositeAssetCreator.cpp @@ -0,0 +1,95 @@ +/** +@file MockCompositeAssetCreator.cpp +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + +#include "swGraphicAPI/MockAssets/stdafx.h" + + +#include "MockCompositeAssetCreator.h" + +#include "MockCompositeAsset.h" +#include "swCommonLib/Common/Buffers/BufferTyped.h" + + + + +namespace sw +{ + +// ================================ // +// +Nullable< Resource* > MockCompositeAssetCreator::Create ( const AssetPath& assetName, IAssetCreateInfo&& createInfo ) +{ + if( createInfo.get_type() == TypeID::get< MockCompositeAssetCreateInfo >() ) + { + auto& typedInfo = static_cast< MockCompositeAssetCreateInfo& >( createInfo ); + return new MockCompositeAsset( assetName, typedInfo.SubAssets, typedInfo.CompositeSubAssets ); + } + + return "Wrong IAssetCreateInfo of type [" + createInfo.get_type().get_name().to_string() + "]."; +} + +// ================================ // +// +Nullable< Resource* > MockCompositeAssetCreator::LoadFromRaw ( const AssetPath& assetName, const BufferRaw& rawData ) +{ + assert( !"InputLayout is not cacheable" ); + return nullptr; +} + +// ================================ // +// +BufferRaw MockCompositeAssetCreator::SaveToRaw ( const IAssetCreateInfo& createInfo ) +{ + assert( !"InputLayout is not cacheable" ); + return BufferTyped< uint8 >::CreateEmpty(); +} + +// ================================ // +// +BufferRaw MockCompositeAssetCreator::SaveToRaw ( ResourcePtr< Resource > resource ) +{ + assert( !"InputLayout is not cacheable" ); + return BufferTyped< uint8 >::CreateEmpty(); +} + +// ================================ // +// +bool MockCompositeAssetCreator::IsCacheable () const +{ + return false; +} + +// ================================ // +// +bool MockCompositeAssetCreator::SupportsResourceToRaw() const +{ + return false; +} + +// ================================ // +// +TypeID MockCompositeAssetCreator::GetAssetType () const +{ + return TypeID::get< MockCompositeAsset >(); +} + + +// ================================ // +// +MockCompositeAssetCreatorPtr MockCompositeAssetCreator::CreateCreator () +{ + return std::make_shared< MockCompositeAssetCreator >(); +} + + + +} // sw + + + + + + diff --git a/MockAssets/MockCompositeAssetCreator.h b/MockAssets/MockCompositeAssetCreator.h new file mode 100644 index 0000000..581857c --- /dev/null +++ b/MockAssets/MockCompositeAssetCreator.h @@ -0,0 +1,73 @@ +#pragma once +/** +@file MockCompositeAssetCreator.h +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + +#include "swGraphicAPI/ResourceManager/AssetCreators/IAssetCreator.h" +#include "MockAsset.h" + + + +namespace sw +{ + + +class MockAsset; +class MockCompositeAsset; +class MockCompositeAssetCreator; +DEFINE_RESOURCE_PTR_TYPE( MockCompositeAsset ); +DEFINE_PTR_TYPE( MockCompositeAssetCreator ); + + +/**@brief +@ingroup Mocks*/ +struct MockCompositeAssetCreateInfo : public IAssetCreateInfo +{ + RTTR_ENABLE( IAssetCreateInfo ); +public: + + std::vector< MockAssetPtr > SubAssets; + std::vector< MockCompositeAssetPtr > CompositeSubAssets; + +public: + virtual TypeID GetAssetType () const { return TypeID::get< MockCompositeAsset >(); } +}; + + +/**@brief Creates MockAsset. +@ingroup Mocks*/ +class MockCompositeAssetCreator : public IAssetCreator +{ +private: +protected: +public: + explicit MockCompositeAssetCreator () = default; + virtual ~MockCompositeAssetCreator () = default; + +public: + + virtual Nullable< Resource* > Create ( const AssetPath& assetName, IAssetCreateInfo&& createInfo ) override; + + virtual Nullable< Resource* > LoadFromRaw ( const AssetPath& assetName, const BufferRaw& rawData ) override; + virtual BufferRaw SaveToRaw ( const IAssetCreateInfo& createInfo ) override; + virtual BufferRaw SaveToRaw ( ResourcePtr< Resource > resource ) override; + + virtual bool IsCacheable () const override; + virtual bool SupportsResourceToRaw () const override; + virtual TypeID GetAssetType () const override; + +public: + + static MockCompositeAssetCreatorPtr CreateCreator (); + +}; + + + + + +} // sw + + diff --git a/MockAssets/MockCompositeAssetLoader.cpp b/MockAssets/MockCompositeAssetLoader.cpp new file mode 100644 index 0000000..3c6900c --- /dev/null +++ b/MockAssets/MockCompositeAssetLoader.cpp @@ -0,0 +1,143 @@ +/** +@file MockAssetLoader.cpp +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + +#include "swGraphicAPI/MockAssets/stdafx.h" + + +#include "MockCompositeAssetLoader.h" +#include "MockCompositeAsset.h" +#include "MockCompositeAssetCreator.h" +#include "MockAssetLoader.h" + +#include "swCommonLib/System/File.h" +#include "swCommonLib/Common/Exceptions/ErrorsCollector.h" + +#include "swGraphicAPI/ResourceManager/Loaders/Tools/LoadingContext.h" + + +namespace sw +{ + +// ================================ // +// +bool MockCompositeAssetLoader::CanLoad ( const AssetPath& filePath, TypeID resourceType ) +{ + return resourceType == TypeID::get< MockCompositeAsset >(); +} + +// ================================ // +// +Nullable< MockAssetPtr > LoadSubAsset ( const AssetPath& assetName, LoadingContext& context ) +{ + auto& factory = context.Factory; + MockAssetLoadInfo info; + + return factory.Load< MockAsset >( assetName, &info ); +} + +// ================================ // +// +Nullable< MockCompositeAssetPtr > LoadComposite ( const LoadPath& path, const MockCompositeAssetLoadInfo* compositeDesc, LoadingContext& context ) +{ + ErrorsCollector collector; + + std::vector< MockCompositeAssetPtr > compositeAssets; + std::vector< MockAssetPtr > subAssets; + + uint32 idx = 0; + + for( auto& nested : compositeDesc->NestedComposites ) + { + LoadPath name = path / Convert::ToString( idx ); + + auto result = LoadComposite( name, nested.get(), context ); + if( collector.Success( result ) ) + { + compositeAssets.push_back( result.Get() ); + context.AssetsCollection.push_back( result.Get().Ptr() ); + } + + idx++; + } + + for( auto& subasset : compositeDesc->SubAssets ) + { + auto result = LoadSubAsset( subasset, context ); + if( collector.Success( result ) ) + { + subAssets.push_back( result.Get() ); + context.AssetsCollection.push_back( result.Get().Ptr() ); + } + } + + MockCompositeAssetCreateInfo createInfo; + createInfo.SubAssets = std::move( subAssets ); + createInfo.CompositeSubAssets = std::move( compositeAssets ); + + auto result = context.Factory.CreateGenericAsset( path.GetOriginalPath(), TypeID::get< MockCompositeAsset >(), std::move( createInfo ) ); + if( collector.Success( result ) ) + { + context.Warnings.Add( collector ); + return MockCompositeAssetPtr( static_cast< MockCompositeAsset* >( result.Get().Ptr() ) ); + } + + return collector.Get().GetError(); +} + + +// ================================ // +// +LoadingResult MockCompositeAssetLoader::Load ( const LoadPath& filePath, TypeID resourceType, const IAssetLoadInfo* assetDesc, RMLoaderAPI factory ) +{ + LoadingResult loadingResult; + + if( resourceType != TypeID::get< MockCompositeAsset >() && + resourceType != TypeID::get< Resource >() ) + return "Can't load asset of type [" + resourceType.get_name().to_string() + "]."; + + ErrorsCollector warnings; + LoadingContext context( factory ); + + auto typedDesc = static_cast< const MockCompositeAssetLoadInfo* >( assetDesc ); + auto result = LoadComposite( filePath, typedDesc, context ); + + if( !result.IsValid() ) + return { result.GetError(), context.Warnings }; + + // Asset that was requested as filePath parameter, should be on the first place of the array. + context.AssetsCollection.insert( context.AssetsCollection.begin(), result.Get().Ptr() ); + + return { std::move( context.AssetsCollection ), context.Warnings.GetException() }; +} + +// ================================ // +// +ReturnResult MockCompositeAssetLoader::Prefetch ( const LoadPath& filePath, TypeID resourceType, const IAssetLoadInfo * assetDesc, RMLoaderAPI factory ) +{ + return ReturnResult(); +} + +//====================================================================================// +// MockCompositeAssetLoadInfo +//====================================================================================// + +// ================================ // +// +MockCompositeAssetLoadInfo::MockCompositeAssetLoadInfo ( std::vector< MockCompositeAssetLoadInfoPtr > nested, std::vector< AssetPath > subAssets ) + : NestedComposites( std::move( nested ) ) + , SubAssets( std::move( subAssets ) ) +{} + +// ================================ // +// +MockCompositeAssetLoadInfoPtr MockCompositeAssetLoadInfo::Create ( std::vector< MockCompositeAssetLoadInfoPtr > nested, std::vector< AssetPath > subAssets ) +{ + return std::make_shared< MockCompositeAssetLoadInfo >( std::move( nested ), std::move( subAssets ) ); +} + +} // sw + + diff --git a/MockAssets/MockCompositeAssetLoader.h b/MockAssets/MockCompositeAssetLoader.h new file mode 100644 index 0000000..b669c36 --- /dev/null +++ b/MockAssets/MockCompositeAssetLoader.h @@ -0,0 +1,73 @@ +#pragma once +/** +@file MockCompositeAssetLoader.h +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + + + +#include "swGraphicAPI/ResourceManager/Loaders/IAssetLoader.h" +#include "swGraphicAPI/ResourceManager/Loaders/IAssetLoadInfo.h" + +#include "MockCompositeAsset.h" + + + +namespace sw +{ + +class MockCompositeAssetLoadInfo; +DEFINE_PTR_TYPE( MockCompositeAssetLoadInfo ); + + +// ================================ // +// +class MockCompositeAssetLoadInfo : public IAssetLoadInfo +{ +public: + + std::vector< MockCompositeAssetLoadInfoPtr > NestedComposites; + std::vector< AssetPath > SubAssets; + +protected: +public: + explicit MockCompositeAssetLoadInfo ( std::vector< MockCompositeAssetLoadInfoPtr > nested, std::vector< AssetPath > subAssets ); + virtual ~MockCompositeAssetLoadInfo () = default; + +public: + // ================================ // + // + TypeID GetAssetType () const override { return TypeID::get< MockCompositeAsset >(); } + + +public: + + static MockCompositeAssetLoadInfoPtr Create ( std::vector< MockCompositeAssetLoadInfoPtr > nested, std::vector< AssetPath > subAssets ); +}; + + + + +/**@brief MockAsset loader.*/ +class MockCompositeAssetLoader : public IAssetLoader +{ +private: +protected: +public: + explicit MockCompositeAssetLoader () = default; + virtual ~MockCompositeAssetLoader () = default; + + + // Inherited via IAssetLoader + virtual bool CanLoad ( const AssetPath& filePath, TypeID resourceType ) override; + virtual LoadingResult Load ( const LoadPath& filePath, TypeID resourceType, const IAssetLoadInfo* assetDesc, RMLoaderAPI factory ) override; + virtual ReturnResult Prefetch ( const LoadPath& filePath, TypeID resourceType, const IAssetLoadInfo* assetDesc, RMLoaderAPI factory ) override; + +}; + + + + +} // sw + diff --git a/MockAssets/Utils.h b/MockAssets/Utils.h new file mode 100644 index 0000000..2cf3279 --- /dev/null +++ b/MockAssets/Utils.h @@ -0,0 +1,97 @@ +#pragma once +/** +@file Utils.h +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + + +#include "swGraphicAPI/ResourceManager/ResourceManager.h" + + +#include "swGraphicAPI/MockAssets/MockAssetCreator.h" +#include "swGraphicAPI/MockAssets/MockAsset.h" +#include "swGraphicAPI/MockAssets/MockAssetLoader.h" +#include "swGraphicAPI/MockAssets/MockCompositeAsset.h" +#include "swGraphicAPI/MockAssets/MockCompositeAssetCreator.h" +#include "swGraphicAPI/MockAssets/MockCompositeAssetLoader.h" + +#include "swGraphicAPI/ResourceManager/AssetCreators/Shaders/ShaderCreator.h" +#include "swGraphicAPI/ResourceManager/Loaders/ShaderLoader.h" +#include "swGraphicAPI/ResourceManager/Loaders/RenderTargetLoader.h" +#include "swGraphicAPI/Loaders/SoilTextureLoader/SoilTextureLoader.h" + +#include "swCommonLib/TestUtils/CatchUtils/ExtendedMacros.h" + + +namespace sw +{ + +// ================================ // +// +inline std::unique_ptr< ResourceManager > CreateResourceManagerWithMocks () +{ + std::unique_ptr< ResourceManager > rm = std::make_unique< ResourceManager >(); + + auto pm = rm->GetPathsManager(); + pm->RegisterAlias( "$(TestAssets)", "../TestAssets/" ); + pm->RegisterAlias( "$(MocksDir)", "$(TestAssets)/mock/" ); + pm->RegisterAlias( "$(TestWorkingDir)", "Working-Dir" ); + + { + auto creator = MockAssetCreator::CreateCreator(); // Creator must live longer then ResourceManager since it tracks references of created assets. + auto loader = std::make_shared< MockAssetLoader >(); + + rm->RegisterAssetCreator( creator ); + rm->RegisterLoader( loader ); + } + + { + auto creator = MockCompositeAssetCreator::CreateCreator(); + auto loader = std::make_shared< MockCompositeAssetLoader >(); + + rm->RegisterAssetCreator( creator ); + rm->RegisterLoader( loader ); + } + + return std::move( rm ); +} + +// ================================ // +// +inline std::unique_ptr< ResourceManager > CreateResourceManagerWithMocksAndDefaults () +{ + auto rm = CreateResourceManagerWithMocks(); + + { + auto loader = std::make_shared< ShaderLoader >(); + rm->RegisterLoader( loader ); + } + + { + auto loader = std::make_shared< RenderTargetLoader >(); + rm->RegisterLoader( loader ); + } + + return std::move( rm ); +} + +// ================================ // +// +inline std::unique_ptr< ResourceManager > CreateRMWithDefaultsMocksSoil () +{ + auto rm = CreateResourceManagerWithMocksAndDefaults(); + + { + auto loader = std::make_shared< SoilTextureLoader >(); + rm->RegisterLoader( loader ); + } + + return std::move( rm ); +} + + +} // sw + + + diff --git a/MockAssets/stdafx.cpp b/MockAssets/stdafx.cpp new file mode 100644 index 0000000..68d6f95 --- /dev/null +++ b/MockAssets/stdafx.cpp @@ -0,0 +1,9 @@ +// stdafx.cpp : source file that includes just the standard includes +// stdafx.obj will contain the pre-compiled type information + +#include "swGraphicAPI/MockAssets/stdafx.h" + + + +// TODO: reference any additional headers you need in STDAFX.H +// and not in this file diff --git a/MockAssets/stdafx.h b/MockAssets/stdafx.h new file mode 100644 index 0000000..9bac247 --- /dev/null +++ b/MockAssets/stdafx.h @@ -0,0 +1,51 @@ +#pragma once +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently +// + + +/// @note You can disable all headers in precompiled header with one macro. +/// All cpp files should be precompiled header independet and explicitly include needed headers. +#ifndef DISABLE_PRECOMPILED_HEADER + + +#include + +#include +#include +#include + +#include + +#include "swCommonLib/Common/RTTR.h" + +#include "swGraphicAPI/Resources/MeshResources.h" +#include "swGraphicAPI/Resources/PipelineStates/BlendingState.h" +#include "swGraphicAPI/Resources/PipelineStates/DepthStencilState.h" +#include "swGraphicAPI/Resources/PipelineStates/RasterizerState.h" +#include "swGraphicAPI/Rendering/GraphicAPIConstants.h" +#include "swGraphicAPI/ResourceManager/ResourceManager.h" +#include "swGraphicAPI/Resources/ResourcesFactory.h" +#include "swGraphicAPI/Resources/SwapChain.h" + +#include "swGraphicAPI/MockAssets/MockAsset.h" +#include "swGraphicAPI/MockAssets/MockAssetCreator.h" +#include "swGraphicAPI/MockAssets/MockAssetLoader.h" +#include "swGraphicAPI/MockAssets/MockCompositeAsset.h" +#include "swGraphicAPI/MockAssets/MockCompositeAssetCreator.h" +#include "swGraphicAPI/MockAssets/MockCompositeAssetLoader.h" + +#include "swCommonLib/System/File.h" +#include "swCommonLib/Common/Buffers/BufferTyped.h" + + + +#undef min +#undef max +#undef RegisterClass + + +#endif // !DISABLE_PRECOMPILED_HEADER + + diff --git a/ProjectsDir/Templates/Visual2015/LibraryTemplate.vcxproj b/ProjectsDir/Templates/Visual2015/LibraryTemplate.vcxproj new file mode 100644 index 0000000..1d143bc --- /dev/null +++ b/ProjectsDir/Templates/Visual2015/LibraryTemplate.vcxproj @@ -0,0 +1,153 @@ + + + + + LibraryTemplate + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + + Win32Proj + $(ProjectName) + + + + + Create + Create + Create + Create + + + + + + StaticLibrary + true + v140 + Unicode + + + StaticLibrary + true + v140 + Unicode + + + StaticLibrary + false + v140 + true + Unicode + + + StaticLibrary + false + v140 + true + Unicode + + + + + + + + + + + + + + + + + + + + + + + + + + Use + Level3 + Disabled + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + swGraphicAPI/$(ProjectName)/stdafx.h + + + Windows + true + + + + + Use + Level3 + Disabled + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + swGraphicAPI/$(ProjectName)/stdafx.h + + + Windows + true + + + + + Level3 + Use + MaxSpeed + true + true + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + swGraphicAPI/$(ProjectName)/stdafx.h + + + Windows + true + true + true + + + + + Level3 + Use + MaxSpeed + true + true + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + swGraphicAPI/$(ProjectName)/stdafx.h + + + Windows + true + true + true + + + + + + \ No newline at end of file diff --git a/ProjectsDir/Templates/Visual2015/LibraryTemplateConfig.props b/ProjectsDir/Templates/Visual2015/LibraryTemplateConfig.props new file mode 100644 index 0000000..bb5e7a7 --- /dev/null +++ b/ProjectsDir/Templates/Visual2015/LibraryTemplateConfig.props @@ -0,0 +1,21 @@ + + + + + + + $(ProjectName) + $(LibDir)$(LibraryName)\ + $(SourceDir)$(LibraryName)\ + $(LibraryName)_$(Configuration)_$(PlatformShortName)_$(PlatformToolset) + $(BuildDir)$(LibraryName)_$(Configuration)_$(PlatformShortName)_$(PlatformToolset)\ + + + + $(LibraryNameBuildDir) + $(LibraryNameFileName) + $(LibraryNameLibDir) + + + + \ No newline at end of file diff --git a/ProjectsDir/Templates/Visual2015/TestTemplate.vcxproj b/ProjectsDir/Templates/Visual2015/TestTemplate.vcxproj new file mode 100644 index 0000000..6bd7866 --- /dev/null +++ b/ProjectsDir/Templates/Visual2015/TestTemplate.vcxproj @@ -0,0 +1,167 @@ + + + + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + {22C79F18-F938-4A9E-A4B0-B77E8F87429D} + Win32Proj + 8.1 + + + + Application + true + v140 + Unicode + + + Application + false + v140 + true + Unicode + + + Application + true + v140 + Unicode + + + Application + false + v140 + true + Unicode + + + + + + + + + + + + + + + + + + + + + + + + + true + + + true + + + false + + + false + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + + + Console + true + + + + + + + Level3 + Disabled + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + + + Console + true + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + + + Console + true + true + true + + + + + Level3 + + + MaxSpeed + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + + + Console + true + true + true + + + + + $(ProjectName) + $(LibDir)$(TestName)\ + $(SourceDir)$(TestName)\ + $(TestName) + $(BuildDir)$(TestName)_$(Configuration)_$(PlatformShortName)_$(PlatformToolset)\ + + + $(TestBuildDir) + $(TestFileName) + $(TestBuildDir) + + + + + + \ No newline at end of file diff --git a/ProjectsDir/TestAssets/material/invalid-version.swmat b/ProjectsDir/TestAssets/material/invalid-version.swmat new file mode 100644 index 0000000..626ffd2 --- /dev/null +++ b/ProjectsDir/TestAssets/material/invalid-version.swmat @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ProjectsDir/TestAssets/material/invalid-xml.swmat b/ProjectsDir/TestAssets/material/invalid-xml.swmat new file mode 100644 index 0000000..2d2f81e --- /dev/null +++ b/ProjectsDir/TestAssets/material/invalid-xml.swmat @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ProjectsDir/TestAssets/material/no-MaterialAsset.swmat b/ProjectsDir/TestAssets/material/no-MaterialAsset.swmat new file mode 100644 index 0000000..5fa036b --- /dev/null +++ b/ProjectsDir/TestAssets/material/no-MaterialAsset.swmat @@ -0,0 +1,2 @@ + + diff --git a/ProjectsDir/TestAssets/material/no-gs-entry.swmat b/ProjectsDir/TestAssets/material/no-gs-entry.swmat new file mode 100644 index 0000000..02c3cd5 --- /dev/null +++ b/ProjectsDir/TestAssets/material/no-gs-entry.swmat @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ProjectsDir/TestAssets/material/no-header.swmat b/ProjectsDir/TestAssets/material/no-header.swmat new file mode 100644 index 0000000..89316e1 --- /dev/null +++ b/ProjectsDir/TestAssets/material/no-header.swmat @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/ProjectsDir/TestAssets/material/no-ps.swmat b/ProjectsDir/TestAssets/material/no-ps.swmat new file mode 100644 index 0000000..7686e64 --- /dev/null +++ b/ProjectsDir/TestAssets/material/no-ps.swmat @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ProjectsDir/TestAssets/material/no-textures-entry.swmat b/ProjectsDir/TestAssets/material/no-textures-entry.swmat new file mode 100644 index 0000000..6d42b6f --- /dev/null +++ b/ProjectsDir/TestAssets/material/no-textures-entry.swmat @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/ProjectsDir/TestAssets/material/no-vs.swmat b/ProjectsDir/TestAssets/material/no-vs.swmat new file mode 100644 index 0000000..5578165 --- /dev/null +++ b/ProjectsDir/TestAssets/material/no-vs.swmat @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ProjectsDir/TestAssets/material/not-existing-ps.swmat b/ProjectsDir/TestAssets/material/not-existing-ps.swmat new file mode 100644 index 0000000..b9bdc13 --- /dev/null +++ b/ProjectsDir/TestAssets/material/not-existing-ps.swmat @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ProjectsDir/TestAssets/material/not-existing-texture.swmat b/ProjectsDir/TestAssets/material/not-existing-texture.swmat new file mode 100644 index 0000000..77006ef --- /dev/null +++ b/ProjectsDir/TestAssets/material/not-existing-texture.swmat @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/ProjectsDir/TestAssets/material/not-existing-vs.swmat b/ProjectsDir/TestAssets/material/not-existing-vs.swmat new file mode 100644 index 0000000..e215e28 --- /dev/null +++ b/ProjectsDir/TestAssets/material/not-existing-vs.swmat @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ProjectsDir/TestAssets/material/single-texture-entry.swmat b/ProjectsDir/TestAssets/material/single-texture-entry.swmat new file mode 100644 index 0000000..9c612f3 --- /dev/null +++ b/ProjectsDir/TestAssets/material/single-texture-entry.swmat @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/ProjectsDir/TestAssets/mock/example.mock b/ProjectsDir/TestAssets/mock/example.mock new file mode 100644 index 0000000..0c3c67e --- /dev/null +++ b/ProjectsDir/TestAssets/mock/example.mock @@ -0,0 +1 @@ +Example \ No newline at end of file diff --git a/ProjectsDir/TestAssets/mock/example1.mock b/ProjectsDir/TestAssets/mock/example1.mock new file mode 100644 index 0000000..0c34bdf --- /dev/null +++ b/ProjectsDir/TestAssets/mock/example1.mock @@ -0,0 +1 @@ +example1 \ No newline at end of file diff --git a/ProjectsDir/TestAssets/mock/example2.mock b/ProjectsDir/TestAssets/mock/example2.mock new file mode 100644 index 0000000..b7d9bb0 --- /dev/null +++ b/ProjectsDir/TestAssets/mock/example2.mock @@ -0,0 +1 @@ +example2 \ No newline at end of file diff --git a/ProjectsDir/TestAssets/mock/example3.mock b/ProjectsDir/TestAssets/mock/example3.mock new file mode 100644 index 0000000..eedfd49 --- /dev/null +++ b/ProjectsDir/TestAssets/mock/example3.mock @@ -0,0 +1 @@ +example3 \ No newline at end of file diff --git a/ProjectsDir/TestAssets/shaders/hlsl/MinimalShader.csh b/ProjectsDir/TestAssets/shaders/hlsl/MinimalShader.csh new file mode 100644 index 0000000..9c5b37c --- /dev/null +++ b/ProjectsDir/TestAssets/shaders/hlsl/MinimalShader.csh @@ -0,0 +1,19 @@ +struct BufType +{ + int i; + float f; + double d; +}; + + +StructuredBuffer Buffer0 : register(t0); +StructuredBuffer Buffer1 : register(t1); +RWStructuredBuffer BufferOut : register(u0); + +[numthreads(1, 1, 1)] +void main( uint3 DTid : SV_DispatchThreadID ) +{ + BufferOut[DTid.x].i = Buffer0[DTid.x].i + Buffer1[DTid.x].i; + BufferOut[DTid.x].f = Buffer0[DTid.x].f + Buffer1[DTid.x].f; + BufferOut[DTid.x].d = Buffer0[DTid.x].d + Buffer1[DTid.x].d; +} \ No newline at end of file diff --git a/ProjectsDir/TestAssets/shaders/hlsl/MinimalShader.psh b/ProjectsDir/TestAssets/shaders/hlsl/MinimalShader.psh new file mode 100644 index 0000000..069adb7 --- /dev/null +++ b/ProjectsDir/TestAssets/shaders/hlsl/MinimalShader.psh @@ -0,0 +1,9 @@ + + + +// ================================ // +// +float4 main() : SV_TARGET +{ + return float4( 0.0, 0.0, 0.0, 0.0 ); +} diff --git a/ProjectsDir/TestAssets/shaders/hlsl/MinimalShader.vsh b/ProjectsDir/TestAssets/shaders/hlsl/MinimalShader.vsh new file mode 100644 index 0000000..853b2e6 --- /dev/null +++ b/ProjectsDir/TestAssets/shaders/hlsl/MinimalShader.vsh @@ -0,0 +1,16 @@ + +// ================================ // +// +struct ShaderOutput +{ + float4 Position : SV_Position; +}; + + +// ================================ // +// +ShaderOutput main() +{ + ShaderOutput output = (ShaderOutput)0; + return output; +} diff --git a/ProjectsDir/TestAssets/shaders/hlsl/NotCompiing.psh b/ProjectsDir/TestAssets/shaders/hlsl/NotCompiing.psh new file mode 100644 index 0000000..eaff0f4 --- /dev/null +++ b/ProjectsDir/TestAssets/shaders/hlsl/NotCompiing.psh @@ -0,0 +1,8 @@ + + +// ================================ // +// +float4 main() : SV_TARGET +{ + return float4( 0.0, 0.0, 0.0, 0.0 ) +} diff --git a/ProjectsDir/TestAssets/shaders/hlsl/NotCompiling.csh b/ProjectsDir/TestAssets/shaders/hlsl/NotCompiling.csh new file mode 100644 index 0000000..329adfb --- /dev/null +++ b/ProjectsDir/TestAssets/shaders/hlsl/NotCompiling.csh @@ -0,0 +1,19 @@ +struct BufType +{ + int i; + float f; + double d; +}; + + +StructuredBuffer Buffer0 : register(t0); +StructuredBuffer Buffer1 : register(t1); +RWStructuredBuffer BufferOut : register(u0); + +[numthreads(1, 1, 1)] +void main( uint3 DTid : SV_DispatchThreadID ) +{ + BufferOut[DTid.x].i = Buffer0[DTid.x].i + Buffer1[DTid.x].i + BufferOut[DTid.x].f = Buffer0[DTid.x].f + Buffer1[DTid.x].f; + BufferOut[DTid.x].d = Buffer0[DTid.x].d + Buffer1[DTid.x].d; +} \ No newline at end of file diff --git a/ProjectsDir/TestAssets/shaders/hlsl/NotCompiling.vsh b/ProjectsDir/TestAssets/shaders/hlsl/NotCompiling.vsh new file mode 100644 index 0000000..554d022 --- /dev/null +++ b/ProjectsDir/TestAssets/shaders/hlsl/NotCompiling.vsh @@ -0,0 +1,16 @@ + +// ================================ // +// +struct ShaderOutput +{ + float4 Position : SV_Position; +}; + + +// ================================ // +// +ShaderOutput main() +{ + ShaderOutput output = (ShaderOutput)0 + return output; +} diff --git a/ProjectsDir/TestAssets/texture/big-lightweight.png b/ProjectsDir/TestAssets/texture/big-lightweight.png new file mode 100644 index 0000000000000000000000000000000000000000..7a803048d43bb9a159d17f1ee8bb8984642002f3 GIT binary patch literal 16786 zcmeI3u}Z^G6oyYUN?MyDj$$E$;1ftE!CN9p21_X}I*5W;H-#>OBGS!CpFka*3O;}! z6j2<+wTsS5-=Gejd+#%d%U38TfzZOocm6|?doNneEH2NNMI}T+5Ri6|E+FFJVCMj-APxLK zz#zy0bR-KiqY?v?AS1INnAuRebI{N?Mn?>~P20{M%Pff?d0xX;l1B?$Bv6EF@~*g^hcWGV+@WL##!|&t=^LloLx9hpz(qAu^nK1L|o?VlkIr+}r{?Srh*81~FOO;81 qt~Kf$DK~3#=Cwv$QPebDUD%x;es%Gy9j^@k-93_dwf?2X|C<11D(x`< literal 0 HcmV?d00001 diff --git a/ProjectsDir/TestAssets/texture/random-pixels.png b/ProjectsDir/TestAssets/texture/random-pixels.png new file mode 100644 index 0000000000000000000000000000000000000000..8e6ccb315f514ada2292022c2eea18718ce67eac GIT binary patch literal 148 zcmeAS@N?(olHy`uVBq!ia0vp^EFjFm1SHiab7}%9#^NA%Cx&(BWL|<~(j9#r85lP9 zbN@+X1@buyJR*x382Ao@Fyrz36)8YLO-~oc5Q*?)i<%!FuBC7K|N3g9%He29Q3Y-f nCRfP@9ge1=29XY%8VQEG2V{0TJ!xVDYGUwo^>bP0l+XkKmvbl5 literal 0 HcmV?d00001 diff --git a/ProjectsDir/Visual2015/DX11API/DX11API.vcxproj b/ProjectsDir/Visual2015/DX11API/DX11API.vcxproj index b040caf..4b0fc61 100644 --- a/ProjectsDir/Visual2015/DX11API/DX11API.vcxproj +++ b/ProjectsDir/Visual2015/DX11API/DX11API.vcxproj @@ -142,6 +142,7 @@ + @@ -149,7 +150,6 @@ - @@ -161,6 +161,7 @@ + @@ -168,7 +169,6 @@ - diff --git a/ProjectsDir/Visual2015/DX11API/DX11API.vcxproj.filters b/ProjectsDir/Visual2015/DX11API/DX11API.vcxproj.filters index 4d84297..882fc4e 100644 --- a/ProjectsDir/Visual2015/DX11API/DX11API.vcxproj.filters +++ b/ProjectsDir/Visual2015/DX11API/DX11API.vcxproj.filters @@ -30,9 +30,6 @@ DX11API\DX11Resources - - DX11API\DX11Resources - DX11API\DX11Resources @@ -69,6 +66,9 @@ DX11API\DX11Resources + + DX11API\DX11Initializer + @@ -83,9 +83,6 @@ DX11API\DX11Resources - - DX11API\DX11Resources - DX11API\DX11Resources @@ -125,6 +122,9 @@ DX11API\DX11Resources + + DX11API\DX11Initializer + diff --git a/ProjectsDir/Visual2015/MaterialAsset/MaterialAsset.vcxproj b/ProjectsDir/Visual2015/MaterialAsset/MaterialAsset.vcxproj new file mode 100644 index 0000000..17b286e --- /dev/null +++ b/ProjectsDir/Visual2015/MaterialAsset/MaterialAsset.vcxproj @@ -0,0 +1,166 @@ + + + + MaterialAsset + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + + + + + + Create + Create + Create + Create + + + + + + + + + + + + + + {9f71f0da-1d72-4e96-93b7-5ac2c9cb6ede} + + + + Win32Proj + $(ProjectName) + {85BA6BD1-9CDC-451F-ADF8-A8CDE6443EAF} + + + + StaticLibrary + true + v140 + Unicode + + + StaticLibrary + true + v140 + Unicode + + + StaticLibrary + false + v140 + true + Unicode + + + StaticLibrary + false + v140 + true + Unicode + + + + + + + + + + + + + + + + + + + + + + + + + Use + Level3 + Disabled + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + swGraphicAPI/Assets/MaterialAsset/stdafx.h + + + Windows + true + + + + + Use + Level3 + Disabled + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + swGraphicAPI/Assets/MaterialAsset/stdafx.h + + + Windows + true + + + + + Level3 + Use + MaxSpeed + true + true + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + swGraphicAPI/Assets/MaterialAsset/stdafx.h + + + Windows + true + true + true + + + + + Level3 + Use + MaxSpeed + true + true + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + swGraphicAPI/Assets/MaterialAsset/stdafx.h + + + Windows + true + true + true + + + + + + \ No newline at end of file diff --git a/ProjectsDir/Visual2015/MaterialAsset/MaterialAsset.vcxproj.filters b/ProjectsDir/Visual2015/MaterialAsset/MaterialAsset.vcxproj.filters new file mode 100644 index 0000000..c42d8dd --- /dev/null +++ b/ProjectsDir/Visual2015/MaterialAsset/MaterialAsset.vcxproj.filters @@ -0,0 +1,51 @@ + + + + + {7168a8bd-8533-4642-9b64-a31b35eb73f5} + + + {f3e383ce-9dfe-4be3-8c2c-8dc846dc6c68} + + + + + PrecompiledHeader + + + MaterialAsset + + + MaterialAsset + + + MaterialAsset + + + MaterialAsset + + + + + PrecompiledHeader + + + MaterialAsset + + + MaterialAsset + + + MaterialAsset + + + MaterialAsset + + + MaterialAsset + + + MaterialAsset + + + \ No newline at end of file diff --git a/ProjectsDir/Visual2015/MaterialAsset/MaterialAssetConfig.props b/ProjectsDir/Visual2015/MaterialAsset/MaterialAssetConfig.props new file mode 100644 index 0000000..bb5e7a7 --- /dev/null +++ b/ProjectsDir/Visual2015/MaterialAsset/MaterialAssetConfig.props @@ -0,0 +1,21 @@ + + + + + + + $(ProjectName) + $(LibDir)$(LibraryName)\ + $(SourceDir)$(LibraryName)\ + $(LibraryName)_$(Configuration)_$(PlatformShortName)_$(PlatformToolset) + $(BuildDir)$(LibraryName)_$(Configuration)_$(PlatformShortName)_$(PlatformToolset)\ + + + + $(LibraryNameBuildDir) + $(LibraryNameFileName) + $(LibraryNameLibDir) + + + + \ No newline at end of file diff --git a/ProjectsDir/Visual2015/MeshAsset/MeshAsset.vcxproj b/ProjectsDir/Visual2015/MeshAsset/MeshAsset.vcxproj new file mode 100644 index 0000000..5c12972 --- /dev/null +++ b/ProjectsDir/Visual2015/MeshAsset/MeshAsset.vcxproj @@ -0,0 +1,156 @@ + + + + MeshAsset + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + + Create + Create + Create + Create + + + + + + + + {9f71f0da-1d72-4e96-93b7-5ac2c9cb6ede} + + + + Win32Proj + $(ProjectName) + {406C51BB-C070-4B6A-8631-4C9A26CB1B2E} + + + + StaticLibrary + true + v140 + Unicode + + + StaticLibrary + true + v140 + Unicode + + + StaticLibrary + false + v140 + true + Unicode + + + StaticLibrary + false + v140 + true + Unicode + + + + + + + + + + + + + + + + + + + + + + + + + Use + Level3 + Disabled + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + swGraphicAPI/Assets/$(ProjectName)/stdafx.h + + + Windows + true + + + + + Use + Level3 + Disabled + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + swGraphicAPI/Assets/$(ProjectName)/stdafx.h + + + Windows + true + + + + + Level3 + Use + MaxSpeed + true + true + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + swGraphicAPI/Assets/$(ProjectName)/stdafx.h + + + Windows + true + true + true + + + + + Level3 + Use + MaxSpeed + true + true + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + swGraphicAPI/Assets/$(ProjectName)/stdafx.h + + + Windows + true + true + true + + + + + + \ No newline at end of file diff --git a/ProjectsDir/Visual2015/MeshAsset/MeshAsset.vcxproj.filters b/ProjectsDir/Visual2015/MeshAsset/MeshAsset.vcxproj.filters new file mode 100644 index 0000000..5304870 --- /dev/null +++ b/ProjectsDir/Visual2015/MeshAsset/MeshAsset.vcxproj.filters @@ -0,0 +1,21 @@ + + + + + {4d655544-0421-4507-8f6e-4f832e3e0dba} + + + {895e9e41-ed20-4b5e-8167-4c2b40876fc4} + + + + + PrecompiledHeader + + + + + PrecompiledHeader + + + \ No newline at end of file diff --git a/ProjectsDir/Visual2015/MeshAsset/MeshAssetConfig.props b/ProjectsDir/Visual2015/MeshAsset/MeshAssetConfig.props new file mode 100644 index 0000000..bb5e7a7 --- /dev/null +++ b/ProjectsDir/Visual2015/MeshAsset/MeshAssetConfig.props @@ -0,0 +1,21 @@ + + + + + + + $(ProjectName) + $(LibDir)$(LibraryName)\ + $(SourceDir)$(LibraryName)\ + $(LibraryName)_$(Configuration)_$(PlatformShortName)_$(PlatformToolset) + $(BuildDir)$(LibraryName)_$(Configuration)_$(PlatformShortName)_$(PlatformToolset)\ + + + + $(LibraryNameBuildDir) + $(LibraryNameFileName) + $(LibraryNameLibDir) + + + + \ No newline at end of file diff --git a/ProjectsDir/Visual2015/MockAPI/MockAPI.vcxproj b/ProjectsDir/Visual2015/MockAPI/MockAPI.vcxproj index cdbfaa4..4d12d99 100644 --- a/ProjectsDir/Visual2015/MockAPI/MockAPI.vcxproj +++ b/ProjectsDir/Visual2015/MockAPI/MockAPI.vcxproj @@ -24,7 +24,6 @@ - @@ -39,7 +38,6 @@ - diff --git a/ProjectsDir/Visual2015/MockAPI/MockAPI.vcxproj.filters b/ProjectsDir/Visual2015/MockAPI/MockAPI.vcxproj.filters index a1c3c73..7cc4e53 100644 --- a/ProjectsDir/Visual2015/MockAPI/MockAPI.vcxproj.filters +++ b/ProjectsDir/Visual2015/MockAPI/MockAPI.vcxproj.filters @@ -24,9 +24,6 @@ MockAPI\MockResources - - MockAPI\MockResources - MockAPI\MockResources @@ -65,9 +62,6 @@ MockAPI\MockResources - - MockAPI\MockResources - MockAPI\MockResources diff --git a/ProjectsDir/Visual2015/MockAssets/MockAssets.vcxproj b/ProjectsDir/Visual2015/MockAssets/MockAssets.vcxproj new file mode 100644 index 0000000..c715f99 --- /dev/null +++ b/ProjectsDir/Visual2015/MockAssets/MockAssets.vcxproj @@ -0,0 +1,170 @@ + + + + MockAssets + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + + {9f71f0da-1d72-4e96-93b7-5ac2c9cb6ede} + + + + + + + + + + + Create + Create + Create + Create + + + + + + + + + + + + + + + Win32Proj + $(ProjectName) + {FC28F28C-C54C-4F0C-BF70-43E7F4E7192E} + + + + StaticLibrary + true + v140 + Unicode + + + StaticLibrary + true + v140 + Unicode + + + StaticLibrary + false + v140 + true + Unicode + + + StaticLibrary + false + v140 + true + Unicode + + + + + + + + + + + + + + + + + + + + + + + + + Use + Level3 + Disabled + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + swGraphicAPI/MockAssets/stdafx.h + + + Windows + true + + + + + Use + Level3 + Disabled + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + swGraphicAPI/MockAssets/stdafx.h + + + Windows + true + + + + + Level3 + Use + MaxSpeed + true + true + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + swGraphicAPI/MockAssets/stdafx.h + + + Windows + true + true + true + + + + + Level3 + Use + MaxSpeed + true + true + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + swGraphicAPI/MockAssets/stdafx.h + + + Windows + true + true + true + + + + + + \ No newline at end of file diff --git a/ProjectsDir/Visual2015/MockAssets/MockAssets.vcxproj.filters b/ProjectsDir/Visual2015/MockAssets/MockAssets.vcxproj.filters new file mode 100644 index 0000000..0582b22 --- /dev/null +++ b/ProjectsDir/Visual2015/MockAssets/MockAssets.vcxproj.filters @@ -0,0 +1,66 @@ + + + + + {230928cc-0d9b-48cf-827e-7a8d12223151} + + + {a342df7e-146f-41bc-881a-e35db9f2e35b} + + + {694521c7-994f-48f1-b604-5e7a2c8d0750} + + + + + PrecompiledHeader + + + MockAssets + + + MockAssets + + + MockAssets + + + MockAssets + + + MockAssets + + + MockAssets + + + + + PrecompiledHeader + + + MockAssets + + + MockAssets + + + MockAssets + + + MockAssets + + + MockAssets + + + MockAssets + + + Utils + + + Utils + + + \ No newline at end of file diff --git a/ProjectsDir/Visual2015/MockAssets/MockAssetsConfig.props b/ProjectsDir/Visual2015/MockAssets/MockAssetsConfig.props new file mode 100644 index 0000000..bb5e7a7 --- /dev/null +++ b/ProjectsDir/Visual2015/MockAssets/MockAssetsConfig.props @@ -0,0 +1,21 @@ + + + + + + + $(ProjectName) + $(LibDir)$(LibraryName)\ + $(SourceDir)$(LibraryName)\ + $(LibraryName)_$(Configuration)_$(PlatformShortName)_$(PlatformToolset) + $(BuildDir)$(LibraryName)_$(Configuration)_$(PlatformShortName)_$(PlatformToolset)\ + + + + $(LibraryNameBuildDir) + $(LibraryNameFileName) + $(LibraryNameLibDir) + + + + \ No newline at end of file diff --git a/ProjectsDir/Visual2015/Paths.props b/ProjectsDir/Visual2015/Paths.props index 5d63889..6af742a 100644 --- a/ProjectsDir/Visual2015/Paths.props +++ b/ProjectsDir/Visual2015/Paths.props @@ -21,7 +21,7 @@ $(SourceInclude);$(SourceInclude)swCommonLib/Reflection/src/;%(AdditionalIncludeDirectories) - RTTR_DLL;%(PreprocessorDefinitions) + FMT_HEADER_ONLY;RTTR_DLL;%(PreprocessorDefinitions) diff --git a/ProjectsDir/Visual2015/ResourceManager/ResourceManager.vcxproj b/ProjectsDir/Visual2015/ResourceManager/ResourceManager.vcxproj index 18aa6b6..097ae47 100644 --- a/ProjectsDir/Visual2015/ResourceManager/ResourceManager.vcxproj +++ b/ProjectsDir/Visual2015/ResourceManager/ResourceManager.vcxproj @@ -19,38 +19,127 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - + + + - + + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + Document + + + + + + + + NotUsing + NotUsing + NotUsing + NotUsing + + + + + + + + Create Create Create Create - - + + + + + + {9abcbab4-05b4-47c5-b5d8-f201559fd096} + + + {561754cb-295d-4d69-8dbc-bc069d1a636a} + {9F71F0DA-1D72-4E96-93B7-5AC2C9CB6EDE} diff --git a/ProjectsDir/Visual2015/ResourceManager/ResourceManager.vcxproj.filters b/ProjectsDir/Visual2015/ResourceManager/ResourceManager.vcxproj.filters index 67abf28..717af93 100644 --- a/ProjectsDir/Visual2015/ResourceManager/ResourceManager.vcxproj.filters +++ b/ProjectsDir/Visual2015/ResourceManager/ResourceManager.vcxproj.filters @@ -13,6 +13,60 @@ {789ce426-c09f-475d-b42f-e620b8e9891a} + + {bc9fe5a8-2e78-4796-a29c-78593ee7afc1} + + + {109aaa4d-08d9-462a-8def-3baa551804f0} + + + {1a78c6dc-95f4-453b-92c6-342673921141} + + + {608b6d99-86e8-495a-8c5d-2030e8876186} + + + {af417ba2-7ad0-4576-ab21-44410c74d482} + + + {8b4595d8-4173-4632-821e-0f4dd58752ad} + + + {5a78aff8-47ef-4094-99c6-ed51954842f0} + + + {c8277046-d812-4e99-8acc-4f5b150b05d9} + + + {44631b0d-5d6a-46c8-a140-d29af5d801ed} + + + {650d0f75-9ccb-45b3-9bdd-f330d291cd90} + + + {e42ecf68-a8c0-4bbf-8458-bf16bf57e47a} + + + {0acb497f-3d98-4a47-97da-9cc0b816e03b} + + + {17bac032-4543-4380-bd48-d3b8e5062c6f} + + + {21fab0d8-65c8-4533-b6cc-5729b33f10f7} + + + {8f4f8bec-efb3-4307-9487-87df7f7e3d68} + + + {5e98a667-2f6c-4093-b4fa-01a668ca6254} + + + {0cb0ceaf-52eb-44c8-a34c-864f5632aee9} + + + {bd89a30a-b372-406b-a238-ec8a712fc45a} + @@ -27,70 +81,292 @@ Rendering - - ResourceManager - - - ResourceManager - - + Resources - + Resources - + Resources - + Resources - + Resources - - Resources + + PrecompiledHeader - - Resources + + ResourceManager\AssetCreators - - Resources + + ResourceManager\AssetCreators - - Resources + + ResourceManager\Cache - - Resources + + ResourceManager\Cache - - Resources + + ResourceManager\AssetCreators\Buffers - - Resources + + ResourceManager\AssetCreators\Shaders - - Resources + + Resources\Shaders - - PrecompiledHeader + + Resources\Shaders - - Resources + + ResourceManager\Cache + + + ResourceManager\AsyncLoad + + + ResourceManager\AsyncLoad + + + ResourceManager\AssetCreators\Shaders + + + ResourceManager\AsyncLoad + + + ResourceManager\Loaders + + + Resources\Shaders + + + Resources\Shaders + + + ResourceManager\AssetCreators\Shaders + + + ResourceManager\AsyncLoad + + + ResourceManager\AssetCreators + + + ResourceManager\AssetCreators\PipelineStates + + + ResourceManager\AssetCreators\PipelineStates + + + ResourceManager\AssetCreators\PipelineStates + + + ResourceManager\AssetCreators\Textures + + + ResourceManager\AssetCreators\Textures\Resampler + + + ResourceManager\AssetCreators\Textures + + + ImageGenerators + + + Resources\Textures + + + Resources\Shaders + + + Resources\Shaders + + + Resources\Buffers + + + Resources\Buffers + + + Resources\Buffers + + + Resources\Textures + + + Resources\PipelineStates + + + Resources\PipelineStates + + + Resources\PipelineStates + + + Resources\Textures + + + Resources\Textures + + + ResourceManager\AssetCreators\Textures + + + ResourceManager\Exceptions + + + ResourceManager\Loaders + + + ResourceManager\Loaders + + + ResourceManager\Loaders + + + ResourceManager\PathTranslators + + + ResourceManager\Loaders + + + ResourceManager\Loaders\Tools + + + Resources\Shaders\Exceptions + + + ResourceManager\Loaders + + + ResourceManager\Loaders + + + ResourceManager\Exceptions + + + ResourceManager\PathTranslators + + + ResourceManager\PathTranslators + + + ResourceManager\AsyncLoad + + + ResourceManager + + + ResourceManager\Loaders\Tools + + + ResourceManager + + + ResourceManager + + + ResourceManager\Loaders - - ResourceManager - - - Resources - PrecompiledHeader - + + ResourceManager\Cache + + + ResourceManager\AssetCreators\Buffers + + + Resources\Shaders + + + ResourceManager\AsyncLoad + + + ResourceManager\Loaders + + + ResourceManager\AssetCreators\Shaders + + + ResourceManager\AsyncLoad + + + ResourceManager\Cache + + + ResourceManager\AssetCreators + + + Resources\Shaders + + + ResourceManager\AssetCreators\PipelineStates + + + ResourceManager\AssetCreators\PipelineStates + + + ResourceManager\AssetCreators\PipelineStates + + + ResourceManager\AssetCreators\Textures + + + ResourceManager\AssetCreators\Textures\Resampler + + + ResourceManager\AssetCreators\Textures + + + ImageGenerators + + + Resources\Textures + + + Resources\Buffers + + + Resources\Textures + + + ResourceManager\AssetCreators\Textures + + + ResourceManager\Exceptions + + + ResourceManager\PathTranslators + + Resources + + ResourceManager\Loaders + + + ResourceManager\Exceptions + + + ResourceManager\PathTranslators + + + ResourceManager\AsyncLoad + + + ResourceManager + + + ResourceManager + \ No newline at end of file diff --git a/ProjectsDir/Visual2015/SoilTextureLoader/SoilTextureLoader.vcxproj b/ProjectsDir/Visual2015/SoilTextureLoader/SoilTextureLoader.vcxproj new file mode 100644 index 0000000..5633c53 --- /dev/null +++ b/ProjectsDir/Visual2015/SoilTextureLoader/SoilTextureLoader.vcxproj @@ -0,0 +1,180 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + + NotUsing + + + NotUsing + + + NotUsing + + + Create + + + + + + + + + + + + + + + + + + + + + + + + + + {9abcbab4-05b4-47c5-b5d8-f201559fd096} + + + {9f71f0da-1d72-4e96-93b7-5ac2c9cb6ede} + + + + Win32Proj + SoilTextureLoader + {7275758B-1ABC-4B28-BB42-CBDBCD2584D1} + + + + StaticLibrary + true + v140 + Unicode + + + StaticLibrary + true + v140 + Unicode + + + StaticLibrary + false + v140 + true + Unicode + + + StaticLibrary + false + v140 + true + Unicode + + + + + + + + + + + + + + + + + + + + + + + + + Use + Level3 + Disabled + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + swGraphicAPI/Loaders/SoilTextureLoader/stdafx.h + + + Windows + true + + + + + Use + Level3 + Disabled + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + swGraphicAPI/Loaders/SoilTextureLoader/stdafx.h + + + Windows + true + + + + + Level3 + Use + MaxSpeed + true + true + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + swGraphicAPI/Loaders/SoilTextureLoader/stdafx.h + + + Windows + true + true + true + + + + + Level3 + Use + MaxSpeed + true + true + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + swGraphicAPI/Loaders/SoilTextureLoader/stdafx.h + + + Windows + true + true + true + + + + + + \ No newline at end of file diff --git a/ProjectsDir/Visual2015/SoilTextureLoader/SoilTextureLoader.vcxproj.filters b/ProjectsDir/Visual2015/SoilTextureLoader/SoilTextureLoader.vcxproj.filters new file mode 100644 index 0000000..534b910 --- /dev/null +++ b/ProjectsDir/Visual2015/SoilTextureLoader/SoilTextureLoader.vcxproj.filters @@ -0,0 +1,87 @@ + + + + + {4616c4f0-0712-45ca-9d03-0e7b1bdeb25f} + + + {3bf8129d-3423-47de-8dfd-1e338b428ce8} + + + {57a3e8ea-1cbc-4612-a0c8-3783b3f29f6d} + + + + + PrecompiledHeader + + + SOIL + + + SOIL + + + SOIL + + + Loader + + + + + PrecompiledHeader + + + SOIL + + + SOIL + + + SOIL + + + SOIL + + + SOIL + + + SOIL + + + SOIL + + + SOIL + + + SOIL + + + SOIL + + + SOIL + + + SOIL + + + SOIL + + + SOIL + + + SOIL + + + SOIL + + + Loader + + + \ No newline at end of file diff --git a/ProjectsDir/Visual2015/SoilTextureLoader/SoilTextureLoaderConfig.props b/ProjectsDir/Visual2015/SoilTextureLoader/SoilTextureLoaderConfig.props new file mode 100644 index 0000000..2ad89a9 --- /dev/null +++ b/ProjectsDir/Visual2015/SoilTextureLoader/SoilTextureLoaderConfig.props @@ -0,0 +1,21 @@ + + + + + + + SoilTextureLoader + $(LibDir)$(SoilTextureLoaderName)\ + $(SourceDir)$(SoilTextureLoaderName)\ + $(SoilTextureLoaderName)_$(Configuration)_$(PlatformShortName)_$(PlatformToolset) + $(BuildDir)$(SoilTextureLoaderName)_$(Configuration)_$(PlatformShortName)_$(PlatformToolset)\ + + + + $(SoilTextureLoaderBuildDir) + $(SoilTextureLoaderFileName) + $(SoilTextureLoaderLibDir) + + + + \ No newline at end of file diff --git a/ProjectsDir/Visual2015/Tests/TestMaterial/TestMaterial.vcxproj b/ProjectsDir/Visual2015/Tests/TestMaterial/TestMaterial.vcxproj new file mode 100644 index 0000000..ee0da86 --- /dev/null +++ b/ProjectsDir/Visual2015/Tests/TestMaterial/TestMaterial.vcxproj @@ -0,0 +1,195 @@ + + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + + + + + + + + {561754cb-295d-4d69-8dbc-bc069d1a636a} + + + {91cc6d16-f22c-434a-95e0-35ee857054c7} + + + {85ba6bd1-9cdc-451f-adf8-a8cde6443eaf} + + + {eeefab61-f404-4957-ac24-a3bf81c5e4ed} + + + {fc28f28c-c54c-4f0c-bf70-43e7f4e7192e} + + + {7275758b-1abc-4b28-bb42-cbdbcd2584d1} + + + {572003b3-3cc2-438e-9436-6b6ef9dc7bf5} + + + + + + + {0FCBB0B0-0459-47F1-B93F-70E6BA6CA1A8} + Win32Proj + 8.1 + + + + Application + true + v140 + Unicode + + + Application + false + v140 + true + Unicode + + + Application + true + v140 + Unicode + + + Application + false + v140 + true + Unicode + + + + + + + + + + + + + + + + + + + + + + + + + true + + + true + + + false + + + false + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + + + Console + true + + + + + + + Level3 + Disabled + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + + + Console + true + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + + + Console + true + true + true + + + + + Level3 + + + MaxSpeed + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + + + Console + true + true + true + + + + $(ProjectName) + $(LibDir)$(TestName)\ + $(SourceDir)$(TestName)\ + $(TestName) + $(BuildDir)$(TestName)_$(Configuration)_$(PlatformShortName)_$(PlatformToolset)\ + + + $(TestBuildDir) + $(TestFileName) + $(TestBuildDir) + + + + + \ No newline at end of file diff --git a/ProjectsDir/Visual2015/Tests/TestMaterial/TestMaterial.vcxproj.filters b/ProjectsDir/Visual2015/Tests/TestMaterial/TestMaterial.vcxproj.filters new file mode 100644 index 0000000..13d5ec8 --- /dev/null +++ b/ProjectsDir/Visual2015/Tests/TestMaterial/TestMaterial.vcxproj.filters @@ -0,0 +1,25 @@ + + + + + {8eb4feb2-99e1-4661-a858-e2e63f410f12} + + + + + + Tests + + + Tests + + + Tests + + + + + Tests + + + \ No newline at end of file diff --git a/ProjectsDir/Visual2015/Tests/TestMipMapsGenerator/TestMipMapGenerator.vcxproj b/ProjectsDir/Visual2015/Tests/TestMipMapsGenerator/TestMipMapGenerator.vcxproj new file mode 100644 index 0000000..59ad0ec --- /dev/null +++ b/ProjectsDir/Visual2015/Tests/TestMipMapsGenerator/TestMipMapGenerator.vcxproj @@ -0,0 +1,175 @@ + + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + + {9abcbab4-05b4-47c5-b5d8-f201559fd096} + + + {9f71f0da-1d72-4e96-93b7-5ac2c9cb6ede} + + + + + + + + {CD54BACD-BC9B-40D8-8319-A3B4C6234073} + Win32Proj + 8.1 + + + + Application + true + v140 + Unicode + + + Application + false + v140 + true + Unicode + + + Application + true + v140 + Unicode + + + Application + false + v140 + true + Unicode + + + + + + + + + + + + + + + + + + + + + + + + + true + + + true + + + false + + + false + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + + + Console + true + + + + + + + Level3 + Disabled + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + + + Console + true + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + + + Console + true + true + true + + + + + Level3 + + + MaxSpeed + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + + + Console + true + true + true + + + + $(ProjectName) + $(LibDir)$(TestName)\ + $(SourceDir)$(TestName)\ + $(TestName) + $(BuildDir)$(TestName)_$(Configuration)_$(PlatformShortName)_$(PlatformToolset)\ + + + $(TestBuildDir) + $(TestFileName) + $(TestBuildDir) + + + + + \ No newline at end of file diff --git a/ProjectsDir/Visual2015/Tests/TestResourceManager/TestResourceManager.vcxproj b/ProjectsDir/Visual2015/Tests/TestResourceManager/TestResourceManager.vcxproj new file mode 100644 index 0000000..e4488a8 --- /dev/null +++ b/ProjectsDir/Visual2015/Tests/TestResourceManager/TestResourceManager.vcxproj @@ -0,0 +1,220 @@ + + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + {54F074CF-39C0-4FD6-BBEE-2DC880EB5C24} + Win32Proj + TestResourceManager + 8.1 + + + + Application + true + v140 + Unicode + + + Application + false + v140 + true + Unicode + + + Application + true + v140 + Unicode + + + Application + false + v140 + true + Unicode + + + + + + + + + + + + + + + + + + + + + + + + + true + + + true + + + false + + + false + + + + Use + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + swGraphicAPI/Tests/TestResourceManager/stdafx.h + + + Console + true + + + + + Use + Level3 + Disabled + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + swGraphicAPI/Tests/TestResourceManager/stdafx.h + + + Console + true + + + + + Level3 + Use + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + swGraphicAPI/Tests/TestResourceManager/stdafx.h + + + Console + true + true + true + + + + + Level3 + Use + MaxSpeed + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + swGraphicAPI/Tests/TestResourceManager/stdafx.h + + + Console + true + true + true + + + + $(ProjectName) + $(LibDir)$(TestName)\ + $(SourceDir)$(TestName)\ + $(TestName) + $(BuildDir)$(TestName)_$(Configuration)_$(PlatformShortName)_$(PlatformToolset)\ + + + $(TestBuildDir) + $(TestFileName) + $(TestBuildDir) + + + + + NotUsing + NotUsing + NotUsing + NotUsing + + + Create + Create + Create + Create + + + + + + + + + + + + + + + + + + + + + + + {9abcbab4-05b4-47c5-b5d8-f201559fd096} + + + {561754cb-295d-4d69-8dbc-bc069d1a636a} + + + {91cc6d16-f22c-434a-95e0-35ee857054c7} + + + {eeefab61-f404-4957-ac24-a3bf81c5e4ed} + + + {fc28f28c-c54c-4f0c-bf70-43e7f4e7192e} + + + {9f71f0da-1d72-4e96-93b7-5ac2c9cb6ede} + + + + + + + + + \ No newline at end of file diff --git a/ProjectsDir/Visual2015/Tests/TestResourceManager/TestResourceManager.vcxproj.filters b/ProjectsDir/Visual2015/Tests/TestResourceManager/TestResourceManager.vcxproj.filters new file mode 100644 index 0000000..6ad9902 --- /dev/null +++ b/ProjectsDir/Visual2015/Tests/TestResourceManager/TestResourceManager.vcxproj.filters @@ -0,0 +1,94 @@ + + + + + + Tests + + + Tests + + + Tests\TestCreators + + + Tests\TestResourceManager + + + Tests + + + Tests\TestResourceManager + + + Tests\TestResourceManager + + + Tests\TestResourceManager + + + Tests + + + Utils\Tests + + + Tests\TestResourceManager + + + Tests + + + Tests\TestLoaders + + + Tests\TestLoaders + + + Tests + + + Tests\TestResourceManager + + + Tests + + + Tests\TestResourceManager + + + Tests\TestResourceManager + + + PrecompiledHeader + + + + + {f8dd9c62-3b53-4454-b5c2-62c03f7ce92e} + + + {7b4ee1f2-f121-450a-98af-c4a4eea8dfe5} + + + {f3325ed5-4f61-4279-b87d-bab254a9d0b4} + + + {da4ff1f4-13fd-4ca4-a081-d19ca9701d69} + + + {3ffcb99c-ce8b-4abb-9b50-7208a7495431} + + + {8b4a4068-6d30-412e-9ac0-bb4c5be6935d} + + + {8e63f9f2-ea10-4edb-ada4-fe702d4fd5da} + + + + + PrecompiledHeader + + + \ No newline at end of file diff --git a/ProjectsDir/Visual2015/Tests/TestResources/TestResources.DX11.vcxproj b/ProjectsDir/Visual2015/Tests/TestResources/TestResources.DX11.vcxproj index cc083ac..944a875 100644 --- a/ProjectsDir/Visual2015/Tests/TestResources/TestResources.DX11.vcxproj +++ b/ProjectsDir/Visual2015/Tests/TestResources/TestResources.DX11.vcxproj @@ -22,9 +22,16 @@ - - - + + + + + + + + + + diff --git a/ProjectsDir/Visual2015/Tests/TestResources/TestResources.DX11.vcxproj.filters b/ProjectsDir/Visual2015/Tests/TestResources/TestResources.DX11.vcxproj.filters new file mode 100644 index 0000000..22425fd --- /dev/null +++ b/ProjectsDir/Visual2015/Tests/TestResources/TestResources.DX11.vcxproj.filters @@ -0,0 +1,50 @@ + + + + + + Tests + + + Tests\TestCreators + + + Tests\TestCreators + + + Tests\TestCreators + + + Tests\TestCreators + + + Tests\TestCreators + + + Tests\TestCreators + + + Tests\TestCreators + + + Tests\TestCreators + + + Tests\TestLoaders + + + Tests\TestLoaders + + + + + {08c08f31-9bff-467c-b6e4-a110c5bddae9} + + + {a7b7edd7-b4cd-4f61-a20f-8aa3024371fc} + + + {f06c9516-1a7c-449c-a40b-c8ac070afd54} + + + \ No newline at end of file diff --git a/ProjectsDir/Visual2015/Tests/TestSoilTextureLoader/TestSoilTextureLoader.DX11.vcxproj b/ProjectsDir/Visual2015/Tests/TestSoilTextureLoader/TestSoilTextureLoader.DX11.vcxproj new file mode 100644 index 0000000..7074bc8 --- /dev/null +++ b/ProjectsDir/Visual2015/Tests/TestSoilTextureLoader/TestSoilTextureLoader.DX11.vcxproj @@ -0,0 +1,179 @@ + + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + + {44643d7f-1c71-41c1-b452-b2dc5e088a58} + + + {9f71f0da-1d72-4e96-93b7-5ac2c9cb6ede} + + + {7275758b-1abc-4b28-bb42-cbdbcd2584d1} + + + + + + + + + {20597CBF-CF6D-4D30-B0E3-2D289AF61143} + Win32Proj + 8.1 + + + + Application + true + v140 + Unicode + + + Application + false + v140 + true + Unicode + + + Application + true + v140 + Unicode + + + Application + false + v140 + true + Unicode + + + + + + + + + + + + + + + + + + + + + + + + + true + + + true + + + false + + + false + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + + + Console + true + + + + + + + Level3 + Disabled + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + + + Console + true + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + + + Console + true + true + true + + + + + Level3 + + + MaxSpeed + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + + + Console + true + true + true + + + + $(ProjectName) + $(LibDir)$(TestName)\ + $(SourceDir)$(TestName)\ + $(TestName) + $(BuildDir)$(TestName)_$(Configuration)_$(PlatformShortName)_$(PlatformToolset)\ + + + $(TestBuildDir) + $(TestFileName) + $(TestBuildDir) + + + + + \ No newline at end of file diff --git a/ProjectsDir/Visual2015/Tests/TestSoilTextureLoader/TestSoilTextureLoader.DX11.vcxproj.filters b/ProjectsDir/Visual2015/Tests/TestSoilTextureLoader/TestSoilTextureLoader.DX11.vcxproj.filters new file mode 100644 index 0000000..363d719 --- /dev/null +++ b/ProjectsDir/Visual2015/Tests/TestSoilTextureLoader/TestSoilTextureLoader.DX11.vcxproj.filters @@ -0,0 +1,16 @@ + + + + + {33607f75-2da8-4dce-9d9a-bb616da8a740} + + + + + Tests + + + Tests + + + \ No newline at end of file diff --git a/ProjectsDir/Visual2015/Tests/TestSoilTextureLoader/TestSoilTextureLoader.vcxproj b/ProjectsDir/Visual2015/Tests/TestSoilTextureLoader/TestSoilTextureLoader.vcxproj new file mode 100644 index 0000000..4cc960b --- /dev/null +++ b/ProjectsDir/Visual2015/Tests/TestSoilTextureLoader/TestSoilTextureLoader.vcxproj @@ -0,0 +1,190 @@ + + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + + {9abcbab4-05b4-47c5-b5d8-f201559fd096} + + + {561754cb-295d-4d69-8dbc-bc069d1a636a} + + + {91cc6d16-f22c-434a-95e0-35ee857054c7} + + + {eeefab61-f404-4957-ac24-a3bf81c5e4ed} + + + {fc28f28c-c54c-4f0c-bf70-43e7f4e7192e} + + + {9f71f0da-1d72-4e96-93b7-5ac2c9cb6ede} + + + {7275758b-1abc-4b28-bb42-cbdbcd2584d1} + + + + + + + + {A4A7B575-BCEE-43A6-A3F7-9831A2CCA253} + Win32Proj + 8.1 + + + + Application + true + v140 + Unicode + + + Application + false + v140 + true + Unicode + + + Application + true + v140 + Unicode + + + Application + false + v140 + true + Unicode + + + + + + + + + + + + + + + + + + + + + + + + + true + + + true + + + false + + + false + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + + + Console + true + + + + + + + Level3 + Disabled + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + + + Console + true + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + + + Console + true + true + true + + + + + Level3 + + + MaxSpeed + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + + + Console + true + true + true + + + + $(ProjectName) + $(LibDir)$(TestName)\ + $(SourceDir)$(TestName)\ + $(TestName) + $(BuildDir)$(TestName)_$(Configuration)_$(PlatformShortName)_$(PlatformToolset)\ + + + $(TestBuildDir) + $(TestFileName) + $(TestBuildDir) + + + + + \ No newline at end of file diff --git a/ProjectsDir/Visual2015/Tests/TestSoilTextureLoader/TestSoilTextureLoader.vcxproj.filters b/ProjectsDir/Visual2015/Tests/TestSoilTextureLoader/TestSoilTextureLoader.vcxproj.filters new file mode 100644 index 0000000..0464145 --- /dev/null +++ b/ProjectsDir/Visual2015/Tests/TestSoilTextureLoader/TestSoilTextureLoader.vcxproj.filters @@ -0,0 +1,14 @@ + + + + + {0ba6a683-2e7d-4f96-bcb0-94573e2951ed} + + + + + Tests + + + + \ No newline at end of file diff --git a/ProjectsDir/Visual2015/swMaterialLoader/swMaterialLoader.vcxproj b/ProjectsDir/Visual2015/swMaterialLoader/swMaterialLoader.vcxproj new file mode 100644 index 0000000..6cda615 --- /dev/null +++ b/ProjectsDir/Visual2015/swMaterialLoader/swMaterialLoader.vcxproj @@ -0,0 +1,161 @@ + + + + swMaterialLoader + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + Win32Proj + $(ProjectName) + {572003B3-3CC2-438E-9436-6B6EF9DC7BF5} + + + + Create + Create + Create + Create + + + + + + + + + + {85ba6bd1-9cdc-451f-adf8-a8cde6443eaf} + + + {9f71f0da-1d72-4e96-93b7-5ac2c9cb6ede} + + + + + StaticLibrary + true + v140 + Unicode + + + StaticLibrary + true + v140 + Unicode + + + StaticLibrary + false + v140 + true + Unicode + + + StaticLibrary + false + v140 + true + Unicode + + + + + + + + + + + + + + + + + + + + + + + + + Use + Level3 + Disabled + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + swGraphicAPI/Loaders/$(ProjectName)/stdafx.h + + + Windows + true + + + + + Use + Level3 + Disabled + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + swGraphicAPI/Loaders/$(ProjectName)/stdafx.h + + + Windows + true + + + + + Level3 + Use + MaxSpeed + true + true + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + swGraphicAPI/Loaders/$(ProjectName)/stdafx.h + + + Windows + true + true + true + + + + + Level3 + Use + MaxSpeed + true + true + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + swGraphicAPI/Loaders/$(ProjectName)/stdafx.h + + + Windows + true + true + true + + + + + + \ No newline at end of file diff --git a/ProjectsDir/Visual2015/swMaterialLoader/swMaterialLoader.vcxproj.filters b/ProjectsDir/Visual2015/swMaterialLoader/swMaterialLoader.vcxproj.filters new file mode 100644 index 0000000..dd753c9 --- /dev/null +++ b/ProjectsDir/Visual2015/swMaterialLoader/swMaterialLoader.vcxproj.filters @@ -0,0 +1,27 @@ + + + + + {8306bee6-aa94-4c1a-992b-8989e6043e57} + + + {2d83aa22-ea2b-48e3-83a0-1d804a855171} + + + + + PrecompiledHeader + + + Loader + + + + + PrecompiledHeader + + + Loader + + + \ No newline at end of file diff --git a/ProjectsDir/Visual2015/swMaterialLoader/swMaterialLoaderConfig.props b/ProjectsDir/Visual2015/swMaterialLoader/swMaterialLoaderConfig.props new file mode 100644 index 0000000..bb5e7a7 --- /dev/null +++ b/ProjectsDir/Visual2015/swMaterialLoader/swMaterialLoaderConfig.props @@ -0,0 +1,21 @@ + + + + + + + $(ProjectName) + $(LibDir)$(LibraryName)\ + $(SourceDir)$(LibraryName)\ + $(LibraryName)_$(Configuration)_$(PlatformShortName)_$(PlatformToolset) + $(BuildDir)$(LibraryName)_$(Configuration)_$(PlatformShortName)_$(PlatformToolset)\ + + + + $(LibraryNameBuildDir) + $(LibraryNameFileName) + $(LibraryNameLibDir) + + + + \ No newline at end of file diff --git a/Rendering/GraphicAPIConstants.h b/Rendering/GraphicAPIConstants.h index 7a4ccca..efa3c43 100644 --- a/Rendering/GraphicAPIConstants.h +++ b/Rendering/GraphicAPIConstants.h @@ -2,11 +2,17 @@ /** @file GraphicAPIConstants.h @author nieznanysprawiciel -@copyright Plik jest cz�ci� silnika graficznego SWEngine. +@copyright File is part of Sleeping Wombat Libraries. */ + #include "swCommonLib/Common/TypesDefinitions.h" + +namespace sw +{ + + /**@brief Blending operation. @attention Don't change constants order. @@ -65,72 +71,72 @@ enum class FillMode : uint8 }; -/**@brief Specyfikuje typ dost�pu do pami�ci danego zasobu. +/**@brief Tells how GPU will access resource. @attention Don't change constants order. @see @ref GraphicAPI*/ enum class ResourceUsage : uint8 { - RESOURCE_USAGE_DEFAULT = 0, /// -/**@defgroup GraphicAPI -@ingroup ModulesStructure -@brief Interfejsy dla obiekt�w zasob�w, renderera i initializera. +namespace sw +{ -@EngineCore jest niezale�ny od konkretnej implementacji API graficznego, kt�ra -zosta�a u�yta. W tym celu w tym projekcie zgromadzone s� wszystkie interfejsy, -kt�re powinny zosta� zaimplementowane przez dziedzicz�ce API oraz zestawy sta�ych silnikowych -niezale�nych od platformy. -Pliki w tym projekcie powinny zosta� w��czone do ka�dego projektu, kt�ry u�ywa b�d� -implementuje API graficzne. Opr�cz interfejs�w do zaimplementowania, projekt zawiera te� -pliki .cpp, kt�re powinny by� skompilowane do biblioteki statycznej razem z poszczeg�lnymi API graficznymi.*/ +/**@defgroup GraphicAPI +@ingroup ModulesStructure +@brief Interfaces for Resources, rendering and resources management. +*/ -/**@brief Przechowuje informacje potrzebne do SwapChaina. Parametr dla funkcji IGraphicAPIInitializer::CreateSwapChain. +/**@brief Stores information for SwapChain initialization. Parameter for function IGraphicAPIInitializer::CreateSwapChain. @ingroup GraphicAPI*/ struct SwapChainInitData { @@ -45,7 +41,7 @@ struct SwapChainInitData // ================================ // // - SwapChainInitData() + explicit SwapChainInitData() { DefaultSettings(); } @@ -64,8 +60,7 @@ struct SwapChainInitData } }; -/**@brief Przechowuje informacje potrzebne do inicjalizacji -API graficznego. Parametr dla funkcji IGraphicAPIInitializer::InitAPI. +/**@brief GraphicAPI initialialization data. Parameter for function IGraphicAPIInitializer::InitAPI. @ingroup GraphicAPI*/ struct GraphicAPIInitData { @@ -89,12 +84,10 @@ struct GraphicAPIInitData } }; -/**@brief Interfejs klasy do inicjowania API graficznego. +/**@brief Graphic API interface. -Klasa powinna zosta� zainicjowana przez dziedziczace API graficzne. -Podstawowymi funkcjonalno�ciami klasy jest: -- zainicjowanie i zwolnienie API -- stworzenie renderer�w*/ +@todo Use Nullable in functions that can fail. +@ingroup GraphicAPI*/ class IGraphicAPIInitializer { private: @@ -102,12 +95,13 @@ class IGraphicAPIInitializer public: virtual ~IGraphicAPIInitializer() = default; - virtual IRenderer* CreateRenderer ( RendererUsage usage ) = 0; - virtual SwapChain* CreateSwapChain ( const SwapChainInitData& swapChainData ) = 0; - virtual bool InitAPI ( const GraphicAPIInitData& initData ) = 0; - virtual void ReleaseAPI () = 0; - virtual void* GetRenderTargetHandle ( RenderTargetObject* renderTarget ) = 0; - - // Future - // virtual std::wstring GetErrorString() = 0; + virtual IRenderer* CreateRenderer ( RendererUsage usage ) = 0; + virtual SwapChain* CreateSwapChain ( const SwapChainInitData& swapChainData ) = 0; + virtual ReturnResult InitAPI ( const GraphicAPIInitData& initData ) = 0; + virtual void ReleaseAPI () = 0; + virtual void* GetRenderTargetHandle ( RenderTarget* renderTarget ) = 0; }; + +} // sw + + diff --git a/Rendering/IRenderer.h b/Rendering/IRenderer.h index 645d582..9e4b7ea 100644 --- a/Rendering/IRenderer.h +++ b/Rendering/IRenderer.h @@ -2,14 +2,19 @@ /** @file IRenderer.h @author nieznanysprawiciel -@copyright Plik jest cz�ci� silnika graficznego SWEngine. +@copyright File is part of Sleeping Wombat Libraries. */ + #include "swGraphicAPI/Resources/MeshResources.h" #include "RenderCommands.h" + +namespace sw +{ + /**@brief Spos�b u�ycia renderera. Renderer mo�e wysy�a� polecenia na kart� graficzn� od razu lub @@ -38,27 +43,28 @@ class IRenderer virtual bool IsValid() = 0; - virtual void Draw ( const DrawCommand& command ) = 0; - virtual void DrawInstanced ( const DrawInstancedCommand& command ) = 0; + virtual void Draw ( const DrawCommand& command ) = 0; + virtual void DrawInstanced ( const DrawInstancedCommand& command ) = 0; + + virtual void SetRenderTarget ( const SetRenderTargetCommand& command ) = 0; + virtual void SetRenderTarget ( const SetRenderTargetExCommand& command ) = 0; + virtual void ClearRenderTarget ( const ClearRenderTargetCommand& command ) = 0; - virtual void SetRenderTarget ( const SetRenderTargetCommand& command ) = 0; - virtual void SetRenderTarget ( const SetRenderTargetExCommand& command ) = 0; - virtual void ClearRenderTarget ( const ClearRenderTargetCommand& command ) = 0; + virtual void UpdateBuffer ( const UpdateBufferCommand& command ) = 0; + virtual void BindBuffer ( const BindBufferCommand& command ) = 0; + virtual void UpdateAndBindBuffer ( const UpdateBindBuffer& command ) = 0; - virtual void UpdateBuffer ( const UpdateBufferCommand& command ) = 0; - virtual void BindBuffer ( const BindBufferCommand& command ) = 0; - virtual void UpdateAndBindBuffer ( const UpdateBindBuffer& command ) = 0; + virtual void SetDefaultBuffers ( const SetDefaultBuffersCommand& command ) = 0; - virtual void SetDefaultBuffers ( const SetDefaultBuffersCommand& command ) = 0; - - virtual void SetShaderState ( const SetShaderStateCommand& command ) = 0; - virtual void SetShaderState ( const SetShaderStateExCommand& command ) = 0; - virtual void SetShaderState ( const SetRenderStateCommand& command ) = 0; - virtual void SetShaderState ( const SetRenderStateExCommand& command ) = 0; + virtual void SetShaderState ( const SetShaderStateCommand& command ) = 0; + virtual void SetShaderState ( const SetShaderStateExCommand& command ) = 0; + virtual void SetShaderState ( const SetRenderStateCommand& command ) = 0; + virtual void SetShaderState ( const SetRenderStateExCommand& command ) = 0; - virtual void CopyTexture ( const CopyTextureCommand& command ) = 0; + virtual void CopyTexture ( const CopyTextureCommand& command ) = 0; - virtual void FlushCommands () = 0; + virtual void FlushCommands () = 0; }; +} // sw diff --git a/Rendering/RenderCommands.h b/Rendering/RenderCommands.h index 533cd9d..da4de18 100644 --- a/Rendering/RenderCommands.h +++ b/Rendering/RenderCommands.h @@ -6,9 +6,14 @@ */ #include "swGraphicAPI/Resources/MeshResources.h" -#include "swGraphicAPI/Resources/BlendingState.h" -#include "swGraphicAPI/Resources/DepthStencilState.h" -#include "swGraphicAPI/Resources/RasterizerState.h" +#include "swGraphicAPI/Resources/PipelineStates/BlendingState.h" +#include "swGraphicAPI/Resources/PipelineStates/DepthStencilState.h" +#include "swGraphicAPI/Resources/PipelineStates/RasterizerState.h" + + +namespace sw +{ + /**@defgroup RenderingCommands Rendering commands Commands for @ref IRenderer class. @@ -36,13 +41,13 @@ If you want your custom settings use @ref SetRenderTargetExCommand. @ingroup RenderingCommands*/ struct SetRenderTargetCommand : public RendererCommand { - RenderTargetObject* RenderTargets[ MAX_BOUND_RENDER_TARGETS ]; ///< Render targets. If you want to use only one slot, set other to nullptr. - RenderTargetObject* DepthStencil; ///< Renderer will extract depth stencil from this render target. You can use one of objects from RenderTargets array. + RenderTarget* RenderTargets[ MAX_BOUND_RENDER_TARGETS ]; ///< Render targets. If you want to use only one slot, set other to nullptr. + RenderTarget* DepthStencil; ///< Renderer will extract depth stencil from this render target. You can use one of objects from RenderTargets array. RasterizerState* RasterizerState; BlendingState* BlendingState; DepthStencilState* DepthStencilState; - BufferObject* CameraBuffer; ///< Buffer updated once per render target (or even once per frame). Buffer is bound to both pixel and vertex shader. - BufferObject* LightBuffer; ///< Buffer updated once per render target (or even once per frame). Buffer is bound only to pixel shader. + Buffer* CameraBuffer; ///< Buffer updated once per render target (or even once per frame). Buffer is bound to both pixel and vertex shader. + Buffer* LightBuffer; ///< Buffer updated once per render target (or even once per frame). Buffer is bound only to pixel shader. }; @@ -94,7 +99,7 @@ struct SetRenderTargetExCommand : public SetRenderTargetCommand @ingroup RenderingCommands*/ struct ClearRenderTargetCommand : public RendererCommand { - RenderTargetObject* RenderTarget; + RenderTarget* RenderTarget; DirectX::XMFLOAT4 ClearColor; float DepthValue; uint8 StencilValue; @@ -109,8 +114,8 @@ If mesh doesn't have index buffer, set IndexBuffer field to nullptr. @ingroup RenderingCommands*/ struct DrawCommand : public RendererCommand { - BufferObject* VertexBuffer; - BufferObject* IndexBufer; + Buffer* VertexBuffer; + Buffer* IndexBufer; ShaderInputLayout* Layout; uint32 BufferOffset; uint32 NumVertices; @@ -124,7 +129,7 @@ struct DrawCommand : public RendererCommand @ingroup RenderingCommands*/ struct DrawInstancedCommand : public DrawCommand { - BufferObject* PerInstanceBuffer; ///< Per instance transformation. + Buffer* PerInstanceBuffer; ///< Per instance transformation. uint16 NumInstances; }; @@ -138,7 +143,7 @@ struct SetShaderStateCommand : public RendererCommand { VertexShader* VertexShader; PixelShader* PixelShader; - TextureObject* Textures[ sMaxTextures ]; + Texture* Textures[ sMaxTextures ]; uint8 BindToShader[ sMaxTextures ]; ///< Use @ref ShaderType flag. @note ShaderType::ComputeShader will be ignored. }; @@ -159,19 +164,19 @@ struct SetShaderStateExCommand : public SetShaderStateCommand @ingroup RenderingCommands*/ struct SetDefaultBuffersCommand : public RendererCommand { - BufferObject* TransformBuffer; - BufferObject* MaterialBuffer; - BufferObject* BonesTransforms; + Buffer* TransformBuffer; + Buffer* MaterialBuffer; + Buffer* BonesTransforms; }; -/**@brief +/**@brief @ingroup RenderingCommands*/ struct SetRenderStateCommand : public SetShaderStateCommand, SetDefaultBuffersCommand {}; -/**@brief +/**@brief @ingroup RenderingCommands*/ struct SetRenderStateExCommand : public SetShaderStateExCommand, SetDefaultBuffersCommand @@ -183,8 +188,8 @@ struct SetRenderStateExCommand : public SetShaderStateExCommand, SetDefaultBuffe @ingroup RenderingCommands*/ struct CopyTextureCommand : public RendererCommand { - TextureObject* SourceTexture; - TextureObject* DestinationTexture; + Texture* SourceTexture; + Texture* DestinationTexture; }; /**@brief Binds additional buffers. @@ -196,7 +201,7 @@ will override this setting. @ingroup RenderingCommands*/ struct BindBufferCommand : public RendererCommand { - BufferObject* Buffer; + Buffer* Buffer; uint8 BufferSlot; uint8 BindToShader; ///< Use @ref ShaderType flag. @note ShaderType::ComputeShader will be ignored. }; @@ -207,7 +212,7 @@ struct BindBufferCommand : public RendererCommand @ingroup RenderingCommands*/ struct UpdateBufferCommand : public RendererCommand { - BufferObject* Buffer; + Buffer* Buffer; uint8* FillData; uint32 Size; ///< Size in bytes. }; @@ -221,3 +226,8 @@ struct UpdateBindBuffer : public BindBufferCommand uint8* FillData; uint32 Size; ///< Size in bytes. }; + +} // sw + + + diff --git a/ResourceManager/AssetCreators/AssetsFactory.cpp b/ResourceManager/AssetCreators/AssetsFactory.cpp new file mode 100644 index 0000000..fe9663d --- /dev/null +++ b/ResourceManager/AssetCreators/AssetsFactory.cpp @@ -0,0 +1,158 @@ +/** +@file AssetsFactory.cpp +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ +#include "swGraphicAPI/ResourceManager/stdafx.h" + +#include "AssetsFactory.h" + +#include "swGraphicAPI/ResourceManager/AssetCreators/Buffers/BufferCreator.h" +#include "swGraphicAPI/ResourceManager/AssetCreators/Shaders/ShaderCreator.h" +#include "swGraphicAPI/ResourceManager/AssetCreators/Shaders/LayoutCreator.h" +#include "swGraphicAPI/ResourceManager/AssetCreators/PipelineStates/BlendingStateCreator.h" +#include "swGraphicAPI/ResourceManager/AssetCreators/PipelineStates/RasterizerStateCreator.h" +#include "swGraphicAPI/ResourceManager/AssetCreators/PipelineStates/DepthStencilStateCreator.h" +#include "swGraphicAPI/ResourceManager/AssetCreators/Textures/TextureCreator.h" +#include "swGraphicAPI/ResourceManager/AssetCreators/Textures/RenderTargetCreator.h" + + + +RTTR_REGISTRATION +{ + rttr::registration::class_< sw::IAssetCreator >( "sw::IAssetCreator" ); +} + + +namespace sw +{ + + +// ================================ // +// +AssetsFactory::AssetsFactory () +{ + RegisterDefaults(); +} + + +// ================================ // +// +bool AssetsFactory::RegisterCreator ( IAssetCreatorPtr creator ) +{ + TypeID type = creator->GetAssetType(); + for( size_t i = 0; i < m_assetCreators.size(); i++ ) + { + if( m_assetCreators[ i ]->GetAssetType() == type ) + return false; + } + + m_assetCreators.push_back( creator ); + return true; +} + +// ================================ // +// +void AssetsFactory::RegisterDefaults () +{ + RegisterCreator( IAssetCreatorPtr( new BufferCreator() ) ); + m_buffersCreatorIdx = (uint8)m_assetCreators.size() - 1; + + RegisterCreator( IAssetCreatorPtr( new ShaderCreator< VertexShader >() ) ); + m_VSCreatorIdx = (uint8)m_assetCreators.size() - 1; + + RegisterCreator( IAssetCreatorPtr( new ShaderCreator< PixelShader >() ) ); + m_PSCreatorIdx = (uint8)m_assetCreators.size() - 1; + + RegisterCreator( IAssetCreatorPtr( new ShaderCreator< EvaluationShader >() ) ); + m_ESCreatorIdx = (uint8)m_assetCreators.size() - 1; + + RegisterCreator( IAssetCreatorPtr( new ShaderCreator< ComputeShader >() ) ); + m_CSCreatorIdx = (uint8)m_assetCreators.size() - 1; + + RegisterCreator( IAssetCreatorPtr( new ShaderCreator< ControlShader >() ) ); + m_CtrlSCreatorIdx = (uint8)m_assetCreators.size() - 1; + + RegisterCreator( IAssetCreatorPtr( new ShaderCreator< GeometryShader >() ) ); + m_GSCreatorIdx = (uint8)m_assetCreators.size() - 1; + + RegisterCreator( IAssetCreatorPtr( new LayoutCreator() ) ); + m_layoutCreator = (uint8)m_assetCreators.size() - 1; + + RegisterCreator( IAssetCreatorPtr( new BlendingStateCreator() ) ); + m_blendingStateCreator = (uint8)m_assetCreators.size() - 1; + + RegisterCreator( IAssetCreatorPtr( new RasterizerStateCreator() ) ); + m_rasterizerStateCreator = (uint8)m_assetCreators.size() - 1; + + RegisterCreator( IAssetCreatorPtr( new DepthStencilStateCreator() ) ); + m_depthStencilStateCreator = (uint8)m_assetCreators.size() - 1; + + RegisterCreator( IAssetCreatorPtr( new TextureCreator() ) ); + m_textureCreator = (uint8)m_assetCreators.size() - 1; + + RegisterCreator( IAssetCreatorPtr( new RenderTargetCreator() ) ); + m_rtCreator = (uint8)m_assetCreators.size() - 1; + +} + +// ================================ // +// +Nullable< Resource* > AssetsFactory::CreateAsset ( const AssetPath& assetName, TypeID assetType, IAssetCreateInfo&& createInfo ) +{ + IAssetCreator* creator = FindCreator( assetType ); + + if( creator ) + { + // We prefere to obtain buffer for cache from resource, but some resources resides on GPU + // and loading data back is too difficult. This is last moment, where we can take necessary data. + bool canConvertResourceToRaw = creator->SupportsResourceToRaw(); + if( !canConvertResourceToRaw ) + Cache( creator, createInfo ); + + auto resource = creator->Create( assetName, std::move( createInfo ) ); + + if( canConvertResourceToRaw ) + Cache( creator, resource ); + + return resource; + } + + return "Asset creator for type [" + assetType.get_name().to_string() + "] not registered."; +} + +// ================================ // +// +IAssetCreator* AssetsFactory::FindCreator ( TypeID assetType ) const +{ + for( size_t i = 0; i < m_assetCreators.size(); i++ ) + { + if( m_assetCreators[ i ]->GetAssetType() == assetType ) + return m_assetCreators[ i ].get(); + } + + return nullptr; +} + +// ================================ // +// +void AssetsFactory::Cache ( IAssetCreator* creator, const IAssetCreateInfo& createInfo ) +{ + if( creator->IsCacheable() ) + { + // Implement me + } +} + +// ================================ // +// +void AssetsFactory::Cache ( IAssetCreator* creator, Resource* resource ) +{ + if( creator->IsCacheable() ) + { + // Implement me + } +} + +} // sw + diff --git a/ResourceManager/AssetCreators/AssetsFactory.h b/ResourceManager/AssetCreators/AssetsFactory.h new file mode 100644 index 0000000..9ab0b7a --- /dev/null +++ b/ResourceManager/AssetCreators/AssetsFactory.h @@ -0,0 +1,88 @@ +#pragma once +/** +@file AssetsFactory.h +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + +#include "IAssetCreator.h" + +#include "swGraphicAPI/Resources/MeshResources.h" +#include "swGraphicAPI/ResourceManager/PathTranslators/AssetPath.h" + + +#include + + + + + +namespace sw +{ + +class IAssetCache; +class Buffer; + + +/**@brief Assets factory. +@ingroup AssetsManagement*/ +class AssetsFactory +{ +private: +protected: + + uint8 m_buffersCreatorIdx; + uint8 m_VSCreatorIdx; + uint8 m_PSCreatorIdx; + uint8 m_ESCreatorIdx; + uint8 m_CSCreatorIdx; + uint8 m_CtrlSCreatorIdx; + uint8 m_GSCreatorIdx; + uint8 m_layoutCreator; + uint8 m_blendingStateCreator; + uint8 m_rasterizerStateCreator; + uint8 m_depthStencilStateCreator; + uint8 m_textureCreator; + uint8 m_rtCreator; + + std::vector< IAssetCreatorPtr > m_assetCreators; + +public: + explicit AssetsFactory (); + ~AssetsFactory () = default; + + /**@brief Function for generic asset creation. + Internal implementation can steal content of IAssetCreateInfo.*/ + Nullable< Resource* > CreateAsset ( const AssetPath& assetName, TypeID assetType, IAssetCreateInfo&& createInfo ); + + /**@brief Registers asset creator. + Can't register creator when it existed. + @note This function is not thread safe.*/ + bool RegisterCreator ( IAssetCreatorPtr creator ); + + /**@brief Registers built in creators.*/ + void RegisterDefaults(); + + +public: + + ResourcePtr< Buffer > CreateVertexBuffer ( const AssetPath& name, const uint8* buffer, unsigned int elementSize, unsigned int vertCount ); + ResourcePtr< Buffer > CreateVertexBuffer ( const AssetPath& name, const VertexBufferInitData& data ); + ResourcePtr< Buffer > CreateIndexBuffer ( const AssetPath& name, const uint8* buffer, unsigned int elementSize, unsigned int vertCount ); + ResourcePtr< Buffer > CreateIndexBuffer ( const AssetPath& name, const IndexBufferInitData& data ); + ResourcePtr< Buffer > CreateConstantsBuffer ( const AssetPath& name, const uint8* buffer, unsigned int size ); + ResourcePtr< Buffer > CreateConstantsBuffer ( const AssetPath& name, const ConstantBufferInitData& data ); + + +private: + + IAssetCreator* FindCreator ( TypeID assetType) const; + + void Cache ( IAssetCreator* creator, const IAssetCreateInfo& createInfo ); + void Cache ( IAssetCreator* creator, Resource* resource ); +}; + + +DEFINE_OPTR_TYPE( AssetsFactory ); + +} // sw diff --git a/ResourceManager/AssetCreators/Buffers/BufferCreator.cpp b/ResourceManager/AssetCreators/Buffers/BufferCreator.cpp new file mode 100644 index 0000000..feaba9a --- /dev/null +++ b/ResourceManager/AssetCreators/Buffers/BufferCreator.cpp @@ -0,0 +1,145 @@ +/** +@file BufferCreator.cpp +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + +#include "swGraphicAPI/ResourceManager/stdafx.h" + +#include "BufferCreator.h" +#include "swGraphicAPI/Resources/MeshResources.h" +#include "swCommonLib/Common/Converters.h" +#include "swCommonLib/Common/Buffers/BufferTyped.h" + + + +namespace sw +{ + +// ================================ // +// +Nullable< Resource* > BufferCreator::Create ( const AssetPath& assetName, IAssetCreateInfo&& createInfo ) +{ + TypeID type = createInfo.get_type(); + if( type == TypeID::get< ConstantBufferInitData >() ) + return CreateConstantsBuffer( assetName, static_cast< ConstantBufferInitData& >( createInfo ) ); + else if( type == TypeID::get< VertexBufferInitData >() ) + return CreateVertexBuffer( assetName, static_cast< VertexBufferInitData& >( createInfo ) ); + else if( type == TypeID::get< IndexBufferInitData >() ) + return CreateIndexBuffer( assetName, static_cast< IndexBufferInitData& >( createInfo ) ); + + return fmt::format( "[BufferCreator] IAssetCreateInfo of type [{}] not supported.", type ); +} + +// ================================ // +// +Nullable< Resource* > BufferCreator::LoadFromRaw ( const AssetPath& assetName, const BufferRaw& rawData ) +{ + assert( !"Buffer is not cacheable" ); + return nullptr; +} + +// ================================ // +// +BufferRaw BufferCreator::SaveToRaw ( const IAssetCreateInfo& createInfo ) +{ + assert( !"Buffer is not cacheable" ); + return BufferTyped< uint8 >::CreateEmpty(); +} + +// ================================ // +// +BufferRaw BufferCreator::SaveToRaw ( ResourcePtr< Resource > resource ) +{ + assert( !"Buffer is not cacheable" ); + return BufferTyped< uint8 >::CreateEmpty(); +} + +// ================================ // +// +bool BufferCreator::IsCacheable () const +{ + return false; +} + +// ================================ // +// +bool BufferCreator::SupportsResourceToRaw() const +{ + return false; +} + +// ================================ // +// +TypeID BufferCreator::GetAssetType () const +{ + return TypeID::get< Buffer >(); +} + +//====================================================================================// +// Non generic functions. +//====================================================================================// + + +// ================================ // +// +Nullable< Buffer* > BufferCreator::CreateVertexBuffer ( const AssetPath& name, const uint8* buffer, unsigned int elementSize, unsigned int vertCount ) +{ + VertexBufferInitData initData; + initData.Data = buffer; + initData.ElementSize = elementSize; + initData.NumElements = vertCount; + + return CreateVertexBuffer( name, initData ); +} + +// ================================ // +// +Nullable< Buffer* > BufferCreator::CreateVertexBuffer ( const AssetPath& name, const VertexBufferInitData& data ) +{ + return ResourcesFactory::CreateBufferFromMemory( name, data.Data, data.CreateBufferInfo() ); +} + +// ================================ // +// +Nullable< Buffer* > BufferCreator::CreateIndexBuffer ( const AssetPath& name, const uint8* buffer, unsigned int elementSize, unsigned int vertCount ) +{ + IndexBufferInitData initData; + initData.Data = buffer; + initData.ElementSize = elementSize; + initData.NumElements = vertCount; + + return CreateIndexBuffer( name, initData ); +} + +// ================================ // +// +Nullable< Buffer* > BufferCreator::CreateIndexBuffer ( const AssetPath& name, const IndexBufferInitData& data ) +{ + return ResourcesFactory::CreateBufferFromMemory( name, data.Data, data.CreateBufferInfo() ); +} + +// ================================ // +// +Nullable< Buffer* > BufferCreator::CreateConstantsBuffer ( const AssetPath& name, const uint8* buffer, unsigned int size ) +{ + ConstantBufferInitData initData; + initData.Data = (const uint8*)buffer; + initData.ElementSize = size; + initData.NumElements = 1; + + return CreateConstantsBuffer( name, initData ); +} + +// ================================ // +// +Nullable< Buffer* > BufferCreator::CreateConstantsBuffer ( const AssetPath& name, const ConstantBufferInitData& data ) +{ + if( data.ElementSize % 16 != 0 ) + return "[BufferCreator] Invalid Buffer size. Should be multiply of 16."; + + return ResourcesFactory::CreateBufferFromMemory( name, data.Data, data.CreateBufferInfo() ); +} + + +} // sw diff --git a/ResourceManager/AssetCreators/Buffers/BufferCreator.h b/ResourceManager/AssetCreators/Buffers/BufferCreator.h new file mode 100644 index 0000000..d81eed5 --- /dev/null +++ b/ResourceManager/AssetCreators/Buffers/BufferCreator.h @@ -0,0 +1,52 @@ +#pragma once +/** +@file BufferCreator.h +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + +#include "swGraphicAPI/ResourceManager/AssetCreators/IAssetCreator.h" + + + +namespace sw +{ + +/**@brief Creates GPU Buffer. +@ingroup AssetsCreators*/ +class BufferCreator : public IAssetCreator +{ +private: +protected: +public: + explicit BufferCreator () = default; + virtual ~BufferCreator () = default; + + +public: + + virtual Nullable< Resource* > Create ( const AssetPath& assetName, IAssetCreateInfo&& createInfo ) override; + + virtual Nullable< Resource* > LoadFromRaw ( const AssetPath& assetName, const BufferRaw& rawData ) override; + virtual BufferRaw SaveToRaw ( const IAssetCreateInfo& createInfo ) override; + virtual BufferRaw SaveToRaw ( ResourcePtr< Resource > resource ) override; + + virtual bool IsCacheable () const override; + virtual bool SupportsResourceToRaw () const override; + virtual TypeID GetAssetType () const override; + +public: + + Nullable< Buffer* > CreateVertexBuffer ( const AssetPath& name, const uint8* buffer, unsigned int elementSize, unsigned int vertCount ); + Nullable< Buffer* > CreateVertexBuffer ( const AssetPath& name, const VertexBufferInitData& data ); + Nullable< Buffer* > CreateIndexBuffer ( const AssetPath& name, const uint8* buffer, unsigned int elementSize, unsigned int vertCount ); + Nullable< Buffer* > CreateIndexBuffer ( const AssetPath& name, const IndexBufferInitData& data ); + Nullable< Buffer* > CreateConstantsBuffer ( const AssetPath& name, const uint8* buffer, unsigned int size ); + Nullable< Buffer* > CreateConstantsBuffer ( const AssetPath& name, const ConstantBufferInitData& data ); + +}; + + + +} // sw + diff --git a/ResourceManager/AssetCreators/IAssetCreateInfo.h b/ResourceManager/AssetCreators/IAssetCreateInfo.h new file mode 100644 index 0000000..678b17a --- /dev/null +++ b/ResourceManager/AssetCreators/IAssetCreateInfo.h @@ -0,0 +1,42 @@ +#pragma once +/** +@file IAssetsCreateInfo.h +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + +#include "swCommonLib/Common/RTTR.h" + +namespace sw +{ + +class RMLoaderAPI; +class ResourceManagerAPI; + + + +/**@brief Base class for generic assets creation. + +Generally all structure used to create assets should inherit from this interface even if generic +creation is not necessary. + +@ingroup AssetsManagement +@ingroup AssetsCreators*/ +class IAssetCreateInfo +{ + RTTR_ENABLE(); +private: +protected: +public: + explicit IAssetCreateInfo () = default; + virtual ~IAssetCreateInfo () = default; + + /**@brief Gets type of asset to create.*/ + virtual TypeID GetAssetType () const = 0; + +}; + + +} // sw + + diff --git a/ResourceManager/AssetCreators/IAssetCreator.h b/ResourceManager/AssetCreators/IAssetCreator.h new file mode 100644 index 0000000..300b9e1 --- /dev/null +++ b/ResourceManager/AssetCreators/IAssetCreator.h @@ -0,0 +1,85 @@ +#pragma once +/** +@file IAssetCreator.h +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + +#include "swCommonLib/System/Path.h" +#include "swCommonLib/Common/RTTR.h" +#include "swCommonLib/Common/Buffers/BufferRaw.h" +#include "swCommonLib/Common/Exceptions/Nullable.h" + +#include "swGraphicAPI/Resources/ResourceObject.h" +#include "swGraphicAPI/Resources/ResourcePtr.h" + +#include "swGraphicAPI/ResourceManager/PathTranslators/AssetPath.h" + +#include "IAssetCreateInfo.h" + + +namespace sw +{ + +/**@defgroup AssetsCreators Assets Creators +@copydetails IAssetCreator +@ingroup AssetsManagement*/ + + + +/**@brief Interface for assets creator. + +Each asset type should have associated creator class, which implements creation function. +This allows user to create generic assets. AssetCreator can be registered in AssetsFactory. + +Derived implementation should implement functions for typed IAssetCreateInfo descriptors. + +Second purpose of this class is ability to write asset in raw data format to cache. + +@todo Change Cache data generation api. During creation we should return created Resource +and data for cache in the most processed form to avoid recomputation after loading from cache. + +@ingroup AssetsManagement +@ingroup AssetsCreators*/ +class IAssetCreator +{ +private: +protected: +public: + explicit IAssetCreator () = default; + virtual ~IAssetCreator () = 0 {}; + + /**@brief Main generic function for assets creation. + Implementation is allowed to move content of createInfo parameter.*/ + virtual Nullable< Resource* > Create ( const AssetPath& assetName, IAssetCreateInfo&& createInfo ) = 0; + + /**@brief Loads Asset from raw data format. + This function is used to read data from cache.*/ + virtual Nullable< Resource* > LoadFromRaw ( const AssetPath& assetName, const BufferRaw& rawData ) = 0; + + /**@brief Creates raw data format MemoryChunk. + This function is used to create data that will be written to cache.*/ + virtual BufferRaw SaveToRaw ( const IAssetCreateInfo& createInfo ) = 0; + + /**@brief Saves resource in raw format. + Note: Not all resources must support this conversion. Many of them stores their data on GPU and shouldn't try + to read it.*/ + virtual BufferRaw SaveToRaw ( ResourcePtr< Resource > resource ) = 0; + + /**@brief Checks if asset should be cached. + If Asset is cacheable, creator must implement IAssetCreator::LoadFromRaw and of IAssetCreator::SaveToRaw functions.*/ + virtual bool IsCacheable () const = 0; + + /**@brief You can check if this AssetCreator supports SaveToRaw function with resources in parameters. If + not, this class must implement SaveToRaw with IAssetCreateInfo in parameter.*/ + virtual bool SupportsResourceToRaw () const = 0; + + /**@brief Gets type of asset which this creator creates.*/ + virtual TypeID GetAssetType () const = 0; +}; + +DEFINE_PTR_TYPE( IAssetCreator ); + + +} // sw + diff --git a/ResourceManager/AssetCreators/PipelineStates/BlendingStateCreator.cpp b/ResourceManager/AssetCreators/PipelineStates/BlendingStateCreator.cpp new file mode 100644 index 0000000..d03c806 --- /dev/null +++ b/ResourceManager/AssetCreators/PipelineStates/BlendingStateCreator.cpp @@ -0,0 +1,81 @@ +/** +@file BlendingStateCreator.cpp +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + +#include "swGraphicAPI/ResourceManager/stdafx.h" + +#include "BlendingStateCreator.h" +#include "swGraphicAPI/Resources/MeshResources.h" +#include "swCommonLib/Common/Converters.h" + +#include "swCommonLib/Common/Buffers/BufferTyped.h" + + +namespace sw +{ + +// ================================ // +// +Nullable< Resource* > BlendingStateCreator::Create ( const AssetPath& assetName, IAssetCreateInfo&& createInfo ) +{ + TypeID type = createInfo.get_type(); + if( type == TypeID::get< BlendingInfo >() ) + return ResourcesFactory::CreateBlendingState( assetName, static_cast< BlendingInfo& >( createInfo ) ); + + return fmt::format( "[BlendingStateCreator] IAssetCreateInfo of type [{}] not supported.", type ); +} + +// ================================ // +// +Nullable< Resource* > BlendingStateCreator::LoadFromRaw ( const AssetPath& assetName, const BufferRaw& rawData ) +{ + assert( !"Buffer is not cacheable" ); + return nullptr; +} + +// ================================ // +// +BufferRaw BlendingStateCreator::SaveToRaw ( const IAssetCreateInfo& createInfo ) +{ + assert( !"Buffer is not cacheable" ); + return BufferTyped< uint8 >::CreateEmpty(); +} + +// ================================ // +// +BufferRaw BlendingStateCreator::SaveToRaw ( ResourcePtr< Resource > resource ) +{ + assert( !"Buffer is not cacheable" ); + return BufferTyped< uint8 >::CreateEmpty(); +} + +// ================================ // +// +bool BlendingStateCreator::IsCacheable () const +{ + return false; +} + +// ================================ // +// +bool BlendingStateCreator::SupportsResourceToRaw() const +{ + return false; +} + +// ================================ // +// +TypeID BlendingStateCreator::GetAssetType () const +{ + return TypeID::get< BlendingState >(); +} + +//====================================================================================// +// Non generic functions. +//====================================================================================// + + + +} // sw diff --git a/ResourceManager/AssetCreators/PipelineStates/BlendingStateCreator.h b/ResourceManager/AssetCreators/PipelineStates/BlendingStateCreator.h new file mode 100644 index 0000000..23d9247 --- /dev/null +++ b/ResourceManager/AssetCreators/PipelineStates/BlendingStateCreator.h @@ -0,0 +1,48 @@ +#pragma once +/** +@file BlendingStateCreator.h +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + + +#include "swGraphicAPI/ResourceManager/AssetCreators/IAssetCreator.h" + + + + +namespace sw +{ + +/**@brief Creates blending state for graphic pipeline. +@ingroup AssetsCreators*/ +class BlendingStateCreator : public IAssetCreator +{ +private: +protected: +public: + explicit BlendingStateCreator () = default; + virtual ~BlendingStateCreator () = default; + + +public: + + virtual Nullable< Resource* > Create ( const AssetPath& assetName, IAssetCreateInfo&& createInfo ) override; + + virtual Nullable< Resource* > LoadFromRaw ( const AssetPath& assetName, const BufferRaw& rawData ) override; + virtual BufferRaw SaveToRaw ( const IAssetCreateInfo& createInfo ) override; + virtual BufferRaw SaveToRaw ( ResourcePtr< Resource > resource ) override; + + virtual bool IsCacheable () const override; + virtual bool SupportsResourceToRaw () const override; + virtual TypeID GetAssetType () const override; + + +}; + + + + +} // sw + + diff --git a/ResourceManager/AssetCreators/PipelineStates/DepthStencilStateCreator.cpp b/ResourceManager/AssetCreators/PipelineStates/DepthStencilStateCreator.cpp new file mode 100644 index 0000000..1d80ddb --- /dev/null +++ b/ResourceManager/AssetCreators/PipelineStates/DepthStencilStateCreator.cpp @@ -0,0 +1,81 @@ +/** +@file DepthStencilStateCreator.cpp +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + +#include "swGraphicAPI/ResourceManager/stdafx.h" + +#include "DepthStencilStateCreator.h" +#include "swGraphicAPI/Resources/MeshResources.h" +#include "swCommonLib/Common/Converters.h" + +#include "swCommonLib/Common/Buffers/BufferTyped.h" + + +namespace sw +{ + +// ================================ // +// +Nullable< Resource* > DepthStencilStateCreator::Create ( const AssetPath& assetName, IAssetCreateInfo&& createInfo ) +{ + TypeID type = createInfo.get_type(); + if( type == TypeID::get< DepthStencilInfo >() ) + return ResourcesFactory::CreateDepthStencilState( assetName, static_cast< DepthStencilInfo& >( createInfo ) ); + + return fmt::format( "[DepthStencilStateCreator] IAssetCreateInfo of type [{}] not supported.", type ); +} + +// ================================ // +// +Nullable< Resource* > DepthStencilStateCreator::LoadFromRaw ( const AssetPath& assetName, const BufferRaw& rawData ) +{ + assert( !"Buffer is not cacheable" ); + return nullptr; +} + +// ================================ // +// +BufferRaw DepthStencilStateCreator::SaveToRaw ( const IAssetCreateInfo& createInfo ) +{ + assert( !"Buffer is not cacheable" ); + return BufferTyped< uint8 >::CreateEmpty(); +} + +// ================================ // +// +BufferRaw DepthStencilStateCreator::SaveToRaw ( ResourcePtr< Resource > resource ) +{ + assert( !"Buffer is not cacheable" ); + return BufferTyped< uint8 >::CreateEmpty(); +} + +// ================================ // +// +bool DepthStencilStateCreator::IsCacheable () const +{ + return false; +} + +// ================================ // +// +bool DepthStencilStateCreator::SupportsResourceToRaw() const +{ + return false; +} + +// ================================ // +// +TypeID DepthStencilStateCreator::GetAssetType () const +{ + return TypeID::get< DepthStencilState >(); +} + +//====================================================================================// +// Non generic functions. +//====================================================================================// + + + +} // sw diff --git a/ResourceManager/AssetCreators/PipelineStates/DepthStencilStateCreator.h b/ResourceManager/AssetCreators/PipelineStates/DepthStencilStateCreator.h new file mode 100644 index 0000000..7ba1e78 --- /dev/null +++ b/ResourceManager/AssetCreators/PipelineStates/DepthStencilStateCreator.h @@ -0,0 +1,48 @@ +#pragma once +/** +@file DepthStencilStateCreator.h +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + + +#include "swGraphicAPI/ResourceManager/AssetCreators/IAssetCreator.h" + + + + +namespace sw +{ + +/**@brief Creates depth-stencil state for graphic pipeline. +@ingroup AssetsCreators*/ +class DepthStencilStateCreator : public IAssetCreator +{ +private: +protected: +public: + explicit DepthStencilStateCreator () = default; + virtual ~DepthStencilStateCreator () = default; + + +public: + + virtual Nullable< Resource* > Create ( const AssetPath& assetName, IAssetCreateInfo&& createInfo ) override; + + virtual Nullable< Resource* > LoadFromRaw ( const AssetPath& assetName, const BufferRaw& rawData ) override; + virtual BufferRaw SaveToRaw ( const IAssetCreateInfo& createInfo ) override; + virtual BufferRaw SaveToRaw ( ResourcePtr< Resource > resource ) override; + + virtual bool IsCacheable () const override; + virtual bool SupportsResourceToRaw () const override; + virtual TypeID GetAssetType () const override; + + +}; + + + + +} // sw + + diff --git a/ResourceManager/AssetCreators/PipelineStates/RasterizerStateCreator.cpp b/ResourceManager/AssetCreators/PipelineStates/RasterizerStateCreator.cpp new file mode 100644 index 0000000..0a9fe37 --- /dev/null +++ b/ResourceManager/AssetCreators/PipelineStates/RasterizerStateCreator.cpp @@ -0,0 +1,81 @@ +/** +@file RasterizerStateCreator.cpp +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + +#include "swGraphicAPI/ResourceManager/stdafx.h" + +#include "RasterizerStateCreator.h" +#include "swGraphicAPI/Resources/MeshResources.h" +#include "swCommonLib/Common/Converters.h" + +#include "swCommonLib/Common/Buffers/BufferTyped.h" + + +namespace sw +{ + +// ================================ // +// +Nullable< Resource* > RasterizerStateCreator::Create ( const AssetPath& assetName, IAssetCreateInfo&& createInfo ) +{ + TypeID type = createInfo.get_type(); + if( type == TypeID::get< RasterizerStateInfo >() ) + return ResourcesFactory::CreateRasterizerState( assetName, static_cast< RasterizerStateInfo& >( createInfo ) ); + + return fmt::format( "[RasterizerStateCreator] IAssetCreateInfo of type [{}] not supported.", type ); +} + +// ================================ // +// +Nullable< Resource* > RasterizerStateCreator::LoadFromRaw ( const AssetPath& assetName, const BufferRaw& rawData ) +{ + assert( !"Buffer is not cacheable" ); + return nullptr; +} + +// ================================ // +// +BufferRaw RasterizerStateCreator::SaveToRaw ( const IAssetCreateInfo& createInfo ) +{ + assert( !"Buffer is not cacheable" ); + return BufferTyped< uint8 >::CreateEmpty(); +} + +// ================================ // +// +BufferRaw RasterizerStateCreator::SaveToRaw ( ResourcePtr< Resource > resource ) +{ + assert( !"Buffer is not cacheable" ); + return BufferTyped< uint8 >::CreateEmpty(); +} + +// ================================ // +// +bool RasterizerStateCreator::IsCacheable () const +{ + return false; +} + +// ================================ // +// +bool RasterizerStateCreator::SupportsResourceToRaw() const +{ + return false; +} + +// ================================ // +// +TypeID RasterizerStateCreator::GetAssetType () const +{ + return TypeID::get< RasterizerState >(); +} + +//====================================================================================// +// Non generic functions. +//====================================================================================// + + + +} // sw diff --git a/ResourceManager/AssetCreators/PipelineStates/RasterizerStateCreator.h b/ResourceManager/AssetCreators/PipelineStates/RasterizerStateCreator.h new file mode 100644 index 0000000..b07c7a0 --- /dev/null +++ b/ResourceManager/AssetCreators/PipelineStates/RasterizerStateCreator.h @@ -0,0 +1,48 @@ +#pragma once +/** +@file RasterizerStateCreator.h +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + + +#include "swGraphicAPI/ResourceManager/AssetCreators/IAssetCreator.h" + + + + +namespace sw +{ + +/**@brief Creates rasterizer state for graphic pipeline. +@ingroup AssetsCreators*/ +class RasterizerStateCreator : public IAssetCreator +{ +private: +protected: +public: + explicit RasterizerStateCreator () = default; + virtual ~RasterizerStateCreator () = default; + + +public: + + virtual Nullable< Resource* > Create ( const AssetPath& assetName, IAssetCreateInfo&& createInfo ) override; + + virtual Nullable< Resource* > LoadFromRaw ( const AssetPath& assetName, const BufferRaw& rawData ) override; + virtual BufferRaw SaveToRaw ( const IAssetCreateInfo& createInfo ) override; + virtual BufferRaw SaveToRaw ( ResourcePtr< Resource > resource ) override; + + virtual bool IsCacheable () const override; + virtual bool SupportsResourceToRaw () const override; + virtual TypeID GetAssetType () const override; + + +}; + + + + +} // sw + + diff --git a/ResourceManager/AssetCreators/Shaders/LayoutCreator.cpp b/ResourceManager/AssetCreators/Shaders/LayoutCreator.cpp new file mode 100644 index 0000000..49fdd1d --- /dev/null +++ b/ResourceManager/AssetCreators/Shaders/LayoutCreator.cpp @@ -0,0 +1,79 @@ +/** +@file ShaderCreator.inl +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + +#include "swGraphicAPI/ResourceManager/stdafx.h" + +#include "LayoutCreator.h" +#include "swGraphicAPI/Resources/Shaders/LayoutInitData.h" +#include "swCommonLib/Common/Buffers/BufferTyped.h" + + + +namespace sw +{ + +// ================================ // +// +Nullable< Resource* > LayoutCreator::Create ( const AssetPath& assetName, IAssetCreateInfo&& createInfo ) +{ + TypeID type = createInfo.get_type(); + if( type == TypeID::get< InputLayoutDescriptor >() ) + { + auto init = static_cast< InputLayoutDescriptor&& >( createInfo ); + return ResourcesFactory::CreateInputLayout( assetName, init ); + } + + return fmt::format( "[LayoutCreator] IAssetCreateInfo of type [{}] not supported.", type ); +} + +// ================================ // +// +Nullable< Resource* > LayoutCreator::LoadFromRaw ( const AssetPath& assetName, const BufferRaw& rawData ) +{ + assert( !"InputLayout is not cacheable" ); + return nullptr; +} + +// ================================ // +// +BufferRaw LayoutCreator::SaveToRaw ( const IAssetCreateInfo& createInfo ) +{ + assert( !"InputLayout is not cacheable" ); + return BufferTyped< uint8 >::CreateEmpty(); +} + +// ================================ // +// +BufferRaw LayoutCreator::SaveToRaw ( ResourcePtr< Resource > resource ) +{ + assert( !"InputLayout is not cacheable" ); + return BufferTyped< uint8 >::CreateEmpty(); +} + +// ================================ // +// +bool LayoutCreator::IsCacheable () const +{ + return false; +} + +// ================================ // +// +bool LayoutCreator::SupportsResourceToRaw() const +{ + return false; +} + +// ================================ // +// +TypeID LayoutCreator::GetAssetType () const +{ + return TypeID::get< ShaderInputLayout >(); +} + + + +} // sw diff --git a/ResourceManager/AssetCreators/Shaders/LayoutCreator.h b/ResourceManager/AssetCreators/Shaders/LayoutCreator.h new file mode 100644 index 0000000..9e488fa --- /dev/null +++ b/ResourceManager/AssetCreators/Shaders/LayoutCreator.h @@ -0,0 +1,45 @@ +#pragma once +/** +@file LayoutCreator.h +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + + +#include "swGraphicAPI/ResourceManager/AssetCreators/IAssetCreator.h" + + +namespace sw +{ + + + +/**@brief Creator for input layout. +@ingroup AssetsCreators*/ +class LayoutCreator : public IAssetCreator +{ +private: +protected: +public: + explicit LayoutCreator () = default; + virtual ~LayoutCreator () = default; + +public: + + virtual Nullable< Resource* > Create ( const AssetPath& assetName, IAssetCreateInfo&& createInfo ) override; + + virtual Nullable< Resource* > LoadFromRaw ( const AssetPath& assetName, const BufferRaw& rawData ) override; + virtual BufferRaw SaveToRaw ( const IAssetCreateInfo& createInfo ) override; + virtual BufferRaw SaveToRaw ( ResourcePtr< Resource > resource ) override; + + virtual bool IsCacheable () const override; + virtual bool SupportsResourceToRaw () const override; + virtual TypeID GetAssetType () const override; + +public: + +}; + + + +} // sw diff --git a/ResourceManager/AssetCreators/Shaders/ShaderCreator.h b/ResourceManager/AssetCreators/Shaders/ShaderCreator.h new file mode 100644 index 0000000..1188ee7 --- /dev/null +++ b/ResourceManager/AssetCreators/Shaders/ShaderCreator.h @@ -0,0 +1,62 @@ +#pragma once +/** +@file ShaderCreator.h +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + + +#include "swGraphicAPI/ResourceManager/AssetCreators/IAssetCreator.h" + + +namespace sw +{ + + +/**@brief Creates shaders objects. + +@todo Implement functions to create shader from compiled shaders. +@ingroup AssetsCreators*/ +template< typename ShaderObjectType > +class ShaderCreator : public IAssetCreator +{ +private: +protected: +public: + explicit ShaderCreator () = default; + virtual ~ShaderCreator () = default; + + +public: + + virtual Nullable< Resource* > Create ( const AssetPath& assetName, IAssetCreateInfo&& createInfo ) override; + + virtual Nullable< Resource* > LoadFromRaw ( const AssetPath& assetName, const BufferRaw& rawData ) override; + virtual BufferRaw SaveToRaw ( const IAssetCreateInfo& createInfo ) override; + virtual BufferRaw SaveToRaw ( ResourcePtr< Resource > resource ) override; + + virtual bool IsCacheable () const override; + virtual bool SupportsResourceToRaw () const override; + virtual TypeID GetAssetType () const override; + +public: + + inline Nullable< VertexShader* > CreateVertexShader ( const AssetPath& fileName, const std::string& code, const std::string& shaderEntry = "main" ); + inline Nullable< PixelShader* > CreatePixelShader ( const AssetPath& fileName, const std::string& code, const std::string& shaderEntry = "main" ); + inline Nullable< GeometryShader* > CreateGeometryShader ( const AssetPath& fileName, const std::string& code, const std::string& shaderEntry = "main" ); + inline Nullable< ControlShader* > CreateControlShader ( const AssetPath& fileName, const std::string& code, const std::string& shaderEntry = "main" ); + inline Nullable< EvaluationShader* > CreateEvaluationShader ( const AssetPath& fileName, const std::string& code, const std::string& shaderEntry = "main" ); + inline Nullable< ComputeShader* > CreateComputeShader ( const AssetPath& fileName, const std::string& code, const std::string& shaderEntry = "main" ); + +private: + + inline Nullable< Resource* > CreateShader ( const AssetPath& assetName, ShaderType type, const std::string& code, const std::string& shaderEntry ); + +}; + + +} // sw + + +#include "ShaderCreator.inl" + diff --git a/ResourceManager/AssetCreators/Shaders/ShaderCreator.inl b/ResourceManager/AssetCreators/Shaders/ShaderCreator.inl new file mode 100644 index 0000000..f285f6c --- /dev/null +++ b/ResourceManager/AssetCreators/Shaders/ShaderCreator.inl @@ -0,0 +1,179 @@ +/** +@file ShaderCreator.inl +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + +#include "ShaderCreator.h" +#include "swGraphicAPI/Resources/MeshResources.h" + +#include "swGraphicAPI/Resources/Shaders/ShaderInitData.h" + +#include "swCommonLib/Common/Buffers/BufferTyped.h" +#include "swCommonLib/System/File.h" +#include "swCommonLib/Common/Exceptions/Common/InvalidCodeLogicException.h" + + + + +namespace sw +{ + + +// ================================ // +// +template< typename ShaderObjectType > +Nullable< Resource* > ShaderCreator< ShaderObjectType >::CreateShader ( const AssetPath& assetName, ShaderType type, const std::string& code, const std::string& shaderEntry ) +{ + switch( type ) + { + case ShaderType::VertexShader: + return CreateVertexShader( assetName, code, shaderEntry ); + case ShaderType::PixelShader: + return CreatePixelShader( assetName, code, shaderEntry ); + case ShaderType::GeometryShader: + return CreateGeometryShader( assetName, code, shaderEntry ); + case ShaderType::ComputeShader: + return CreateComputeShader( assetName, code, shaderEntry ); + case ShaderType::TesselationControlShader: + return CreateControlShader( assetName, code, shaderEntry ); + case ShaderType::TesselationEvaluationShader: + return CreateEvaluationShader( assetName, code, shaderEntry ); + default: + return InvalidCodeLogicException::Create( "[ShaderCreator] Unknown shader type", __FILE__, __LINE__ ); + } +} + +// ================================ // +// +template< typename ShaderObjectType > +inline Nullable< Resource* > ShaderCreator< ShaderObjectType >::Create ( const AssetPath& assetName, IAssetCreateInfo&& createInfo ) +{ + auto type = TypeID::get( createInfo ); + if( type == TypeID::get< ShaderInitData >() ) + { + auto& init = static_cast< ShaderInitData&& >( createInfo ); + std::string code = filesystem::File::Load( assetName.GetFile() ); + + return CreateShader( assetName, init.Type, code, init.EntryFunction ); + } + else if( type == TypeID::get< ShaderCodeInitData >() ) + { + auto& init = static_cast< ShaderCodeInitData&& >( createInfo ); + + return CreateShader( assetName, init.Type, init.SourceCode, init.EntryFunction ); + } + else + { + return fmt::format( "[ShaderCreator] IAssetCreateInfo of type [{}] not supported.", type ); + } +} + +// ================================ // +// +template< typename ShaderObjectType > +inline Nullable< Resource* > ShaderCreator< ShaderObjectType >::LoadFromRaw ( const AssetPath& assetName, const BufferRaw& rawData ) +{ + assert( !"Buffer is not cacheable" ); + return nullptr; +} + +// ================================ // +// +template< typename ShaderObjectType > +inline BufferRaw ShaderCreator< ShaderObjectType >::SaveToRaw ( const IAssetCreateInfo& createInfo ) +{ + assert( !"Buffer is not cacheable" ); + return BufferTyped< uint8 >::CreateEmpty(); +} + +// ================================ // +// +template< typename ShaderObjectType > +inline BufferRaw ShaderCreator< ShaderObjectType >::SaveToRaw ( ResourcePtr< Resource > resource ) +{ + assert( !"Buffer is not cacheable" ); + return BufferTyped< uint8 >::CreateEmpty(); +} + +// ================================ // +// +template< typename ShaderObjectType > +inline bool ShaderCreator< ShaderObjectType >::IsCacheable () const +{ + return false; +} + +// ================================ // +// +template< typename ShaderObjectType > +inline bool ShaderCreator< ShaderObjectType >::SupportsResourceToRaw() const +{ + return false; +} + +//====================================================================================// +// Non generic functions. +//====================================================================================// + + +// ================================ // +// +template< typename ShaderObjectType > +inline TypeID ShaderCreator< ShaderObjectType >::GetAssetType () const +{ + return TypeID::get< ShaderObjectType >(); +} + +// ================================ // +// +template< typename ShaderObjectType > +inline Nullable< VertexShader* > ShaderCreator< ShaderObjectType >::CreateVertexShader ( const AssetPath& fileName, const std::string& code, const std::string& shaderEntry ) +{ + return ResourcesFactory::CreateVertexShader( fileName, code, shaderEntry ); +} + +// ================================ // +// +template< typename ShaderObjectType > +inline Nullable< PixelShader* > ShaderCreator< ShaderObjectType >::CreatePixelShader ( const AssetPath& fileName, const std::string& code, const std::string& shaderEntry ) +{ + return ResourcesFactory::CreatePixelShader( fileName, code, shaderEntry ); +} + +// ================================ // +// +template< typename ShaderObjectType > +inline Nullable< GeometryShader* > ShaderCreator< ShaderObjectType >::CreateGeometryShader ( const AssetPath& fileName, const std::string& code, const std::string& shaderEntry ) +{ + return nullptr; +} + +// ================================ // +// +template< typename ShaderObjectType > +inline Nullable< ControlShader* > ShaderCreator< ShaderObjectType >::CreateControlShader ( const AssetPath& fileName, const std::string& code, const std::string& shaderEntry ) +{ + return nullptr; +} + +// ================================ // +// +template< typename ShaderObjectType > +inline Nullable< EvaluationShader* > ShaderCreator< ShaderObjectType >::CreateEvaluationShader ( const AssetPath& fileName, const std::string& code, const std::string& shaderEntry ) +{ + return nullptr; +} + +// ================================ // +// +template< typename ShaderObjectType > +inline Nullable< ComputeShader* > ShaderCreator< ShaderObjectType >::CreateComputeShader ( const AssetPath& fileName, const std::string& code, const std::string & shaderEntry ) +{ + return ResourcesFactory::CreateComputeShader( fileName, code, shaderEntry ); +} + + + +} // sw + diff --git a/ResourceManager/AssetCreators/Textures/MipMapGenerator.cpp b/ResourceManager/AssetCreators/Textures/MipMapGenerator.cpp new file mode 100644 index 0000000..8bf2ad0 --- /dev/null +++ b/ResourceManager/AssetCreators/Textures/MipMapGenerator.cpp @@ -0,0 +1,296 @@ +/** +@file MipMapGenerator.cpp +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ +#include "swGraphicAPI/ResourceManager/stdafx.h" + +#include "MipMapGenerator.h" + +#include "Resampler/resampler.h" +#include "swCommonLib/Common/Converters.h" +#include "swCommonLib/Common/Buffers/BufferTyped.h" + + +namespace sw +{ + + +const int sMaxChannels = 4; + +// ================================ // +// +MipMapGenerator::MipMapGenerator() + : NumChannels( 4 ) +{} + +/**@brief Generates mipmaps + +Set MipMapFilter field to filter that should be used. + +If texture dimension isn't power of 2, this function will scale image and modify in TextureInfo structure these fields: +- Width +- Height + +These fields will be modified, if non zero CutOffMipMaps value is set. +Then the biggest mipmap will become main texture . + +Moreover two fileds are set: +- MipMapLevels +- MemorySize*/ +sw::Nullable< BufferRaw > MipMapGenerator::Generate ( const BufferRaw& source, TextureInfo& texInfo ) +{ + if( texInfo.Format != ResourceFormat::RESOURCE_FORMAT_R8G8B8A8_UNORM ) + return "[MipMapGenerator] Format isn't supported. Should be R8G8B8A8."; + + NumChannels = 4; + + uint16 newWidth = PowerOfTwo( texInfo.Width ) >> texInfo.CutOffMipMaps; + uint16 newHeight = PowerOfTwo( texInfo.Height ) >> texInfo.CutOffMipMaps; + texInfo.MipMapLevels = ComputeMipMapsLevels( newWidth, newHeight ); + + if( newWidth == 0 || newHeight == 0 ) + return "[MipMapGenerator] Image should be at least 1 pixel size."; + + texInfo.MemorySize = ComputeBufferSize( newWidth, newHeight, NumChannels ); + BufferTyped< uint8 > texWithMips( texInfo.MemorySize ); + + if( newWidth != texInfo.Width || newHeight != texInfo.Height ) + { + // Przeskaluj tekstur�, �eby jej wymiary by�y pot�g� dw�jki. + Resample( texInfo.Width, texInfo.Height, newWidth, newHeight, source.GetData(), texWithMips.GetRawData(), texInfo.MipMapFilter ); + } + else + { + // Przekopiuj oryginalny obraz do nowego bufora. + memcpy( texWithMips.GetRawData(), source.GetData(), source.GetSize() ); + } + + // Aktualizujemy informacje o teksturze. + texInfo.Width = newWidth; + texInfo.Height = newHeight; + + PtrOffset offset = 0; + PtrOffset prevOffset = 0; + uint16 prevWidth = newWidth; + uint16 prevHeight = newHeight; + + // Tworzenie mipmap. Zaczynamy od pierwszego poziomu, bo zerowa tekstura jest ju� w buforze (tekstura oryginalna). + for( int level = 1; level < texInfo.MipMapLevels; level++ ) + { + offset += prevWidth * prevHeight * NumChannels; + newWidth /= 2; + newHeight /= 2; + + if( newHeight == 0 ) + newHeight = 1; + if( newWidth == 0 ) + newWidth = 1; + + Resample( prevWidth, prevHeight, newWidth, newHeight, texWithMips.GetRawData() + prevOffset, texWithMips.GetRawData() + offset, texInfo.MipMapFilter ); + + prevOffset = offset; + prevWidth = newWidth; + prevHeight = newHeight; + } + + return texWithMips.MoveToRawBuffer(); +} + +/**@brief Scales texture, using chosen filtering method.*/ +void MipMapGenerator::Resample ( uint32 srcWidth, uint32 srcHeight, uint32 dstWidth, uint32 dstHeight, const uint8* source, uint8* dest, MipMapFilter filter ) +{ + assert( NumChannels > 0 && NumChannels <= sMaxChannels ); + + // ============================================== // + // Initialization. + + Resampler* resamplers[ sMaxChannels ]; + std::vector< float > samples[ sMaxChannels ]; + + resamplers[ 0 ] = new Resampler( srcWidth, srcHeight, dstWidth, dstHeight, Resampler::Boundary_Op::BOUNDARY_CLAMP, 0.0f, 1.0f, Resampler::get_filter_name( (int)filter ) ); + samples[ 0 ].resize( srcWidth ); + + for( int channel = 1; channel < NumChannels; channel++ ) + { + resamplers[ channel ] = new Resampler( srcWidth, srcHeight, dstWidth, dstHeight, Resampler::Boundary_Op::BOUNDARY_CLAMP, 0.0f, 1.0f, Resampler::get_filter_name( (int)filter ), resamplers[ 0 ]->get_clist_x(), resamplers[ 0 ]->get_clist_y() ); + samples[ channel ].resize( srcWidth ); + } + + // ============================================== // + // Gamma correction. + + // Partial gamma correction looks better on mips. Set to 1.0 to disable gamma correction. + const float sourceGamma = 1.0f;//1.75f; + + + float srgbToLinear[ 256 ]; + for( int i = 0; i < 256; ++i ) + srgbToLinear[ i ] = (float)pow( i * 1.0f / 255.0f, sourceGamma ); + + const int linearToSrgbTableSize = 4096; + unsigned char linearToSrgb[ linearToSrgbTableSize ]; + + const float invLinearToSrgbTableSize = 1.0f / linearToSrgbTableSize; + const float invSourceGamma = 1.0f / sourceGamma; + + for( int i = 0; i < linearToSrgbTableSize; ++i ) + { + int k = (int)( 255.0f * pow( i * invLinearToSrgbTableSize, invSourceGamma ) + .5f ); + if( k < 0 ) k = 0; else if( k > 255 ) k = 255; + linearToSrgb[ i ] = (unsigned char)k; + } + + // ============================================== // + // Resampling. + + const int srcPitch = srcWidth * NumChannels; + const int dstPitch = dstWidth * NumChannels; + int dstY = 0; + + for( unsigned int srcY = 0; srcY < srcHeight; srcY++ ) + { + const uint8* pSrc = &source[ srcY * srcPitch ]; + + for( unsigned int x = 0; x < srcWidth; x++ ) + { + for( int c = 0; c < NumChannels; c++ ) + { + if( ( c == 3 ) || ( ( NumChannels == 2 ) && ( c == 1 ) ) ) + samples[ c ][ x ] = *pSrc++ * ( 1.0f / 255.0f ); + else + samples[ c ][ x ] = srgbToLinear[ *pSrc++ ]; + } + } + + for( int c = 0; c < NumChannels; c++ ) + { + if( !resamplers[ c ]->put_line( &samples[ c ][ 0 ] ) ) + { + for( int channel = 0; channel < NumChannels; channel++ ) + delete resamplers[ channel ]; + + // Out of memory. + return; + } + } + + for( ; ; ) + { + int compIndex; + for( compIndex = 0; compIndex < NumChannels; compIndex++ ) + { + const float* pOutput_samples = resamplers[ compIndex ]->get_line(); + if( !pOutput_samples ) + break; + + const bool alphaChannel = ( compIndex == 3 ) || ( ( NumChannels == 2 ) && ( compIndex == 1 ) ); + assert( dstY < (int)dstHeight ); + unsigned char* pDst = &dest[ dstY * dstPitch + compIndex ]; + + for( unsigned int x = 0; x < dstWidth; x++ ) + { + if( alphaChannel ) + { + int c = (int)( 255.0f * pOutput_samples[ x ] + .5f ); + if( c < 0 ) c = 0; else if( c > 255 ) c = 255; + *pDst = (unsigned char)c; + } + else + { + int j = (int)( linearToSrgbTableSize * pOutput_samples[ x ] + .5f ); + if( j < 0 ) j = 0; else if( j >= linearToSrgbTableSize ) j = linearToSrgbTableSize - 1; + *pDst = linearToSrgb[ j ]; + } + + pDst += NumChannels; + } + } + + if( compIndex < NumChannels ) + break; + + dstY++; + } + } + + // Release resources. + for( int channel = 0; channel < NumChannels; channel++ ) + delete resamplers[ channel ]; +} + +/**@brief Finds nearest power of 2.*/ +unsigned int MipMapGenerator::PowerOfTwo ( unsigned int dimmension ) +{ + unsigned int newDimm = 1; + + while( newDimm < dimmension ) + { + newDimm = newDimm << 1; + } + + return newDimm; +} + +/**@brief Wylicza rozmiar bufora dla tekstury o podanych rozmiarach wliczaj�c w to wszystkie poziomy mipmap.*/ +uint32 MipMapGenerator::ComputeBufferSize( unsigned int width, unsigned int height, int bytesPerPixel ) +{ + uint32 bufferSize = 0; + + while( width > 1 || height > 1 ) + { + bufferSize += width * height * bytesPerPixel; + width = width / 2; + height = height / 2; + + if( width == 0 ) + width = 1; + if( height == 0 ) + height = 1; + } + + bufferSize += bytesPerPixel; // Add last mipmap 1x1. + return bufferSize; +} + +// ================================ // +// +unsigned int MipMapGenerator::ComputeMipMapsLevels( unsigned int width, unsigned int height ) +{ + int widthMips = 1; + int heightMips = 1; + + while( width > 1 ) + { + width = width / 2; + widthMips++; + } + + while( height > 1 ) + { + height = height / 2; + heightMips++; + } + + return std::max( widthMips, heightMips ); +} + +// ================================ // +// +PtrOffset MipMapGenerator::ComputeMipLevelOffset( unsigned int initWidth, unsigned int initHeight, int bytesPerPixel, int level ) +{ + PtrOffset offset = 0; + + for( int curLevel = 0; curLevel < level; curLevel++ ) + { + offset += initHeight * initWidth * bytesPerPixel; + + initHeight /= 2; + initWidth /= 2; + } + + return offset; +} + +} // sw + diff --git a/ResourceManager/AssetCreators/Textures/MipMapGenerator.h b/ResourceManager/AssetCreators/Textures/MipMapGenerator.h new file mode 100644 index 0000000..fc76eb4 --- /dev/null +++ b/ResourceManager/AssetCreators/Textures/MipMapGenerator.h @@ -0,0 +1,43 @@ +#pragma once +/** +@file MipMapGenerator.h +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + + +#include "swCommonLib/Common/Buffers/BufferRaw.h" +#include "swCommonLib/Common/Exceptions/Nullable.h" + +#include "swGraphicAPI/Resources//MeshResources.h" + + + +namespace sw +{ + +/**@brief */ +class MipMapGenerator +{ +private: +public: + int NumChannels; + +protected: +public: + MipMapGenerator(); + ~MipMapGenerator() = default; + + sw::Nullable< BufferRaw > Generate ( const BufferRaw& source, TextureInfo& texInfo ); + void Resample ( uint32 srcWidth, uint32 srcHeight, uint32 dstWidth, uint32 dstHeight, const uint8* source, uint8* dest, MipMapFilter filter ); + +private: + + static unsigned int PowerOfTwo ( unsigned int dimmension ); + static uint32 ComputeBufferSize ( unsigned int width, unsigned int height, int bytesPerPixel ); + static unsigned int ComputeMipMapsLevels ( unsigned int width, unsigned int height ); + static PtrOffset ComputeMipLevelOffset ( unsigned int initWidth, unsigned int initHeight, int bytesPerPixel, int level ); +}; + +} // sw + diff --git a/ResourceManager/AssetCreators/Textures/RenderTargetCreator.cpp b/ResourceManager/AssetCreators/Textures/RenderTargetCreator.cpp new file mode 100644 index 0000000..c7425a9 --- /dev/null +++ b/ResourceManager/AssetCreators/Textures/RenderTargetCreator.cpp @@ -0,0 +1,87 @@ +/** +@file RenderTargetCreator.cpp +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + +#include "swGraphicAPI/ResourceManager/stdafx.h" + +#include "RenderTargetCreator.h" + +#include "swCommonLib/Common/Converters.h" +#include "swCommonLib/Common/Buffers/BufferTyped.h" +#include "swCommonLib/Common/fmt.h" + +#include "swGraphicAPI/Resources/Textures/RenderTarget.h" + +#include "MipMapGenerator.h" + + +namespace sw +{ + +// ================================ // +// +Nullable< Resource* > RenderTargetCreator::Create ( const AssetPath& assetName, IAssetCreateInfo&& createInfo ) +{ + TypeID type = createInfo.get_type(); + if( type == TypeID::get< RenderTargetDescriptor >() ) + { + return ResourcesFactory::CreateRenderTarget( assetName, static_cast< RenderTargetDescriptor& >( createInfo ) ); + } + else if( type == TypeID::get < RenderTargetExistingInitInfo >() ) + { + return static_cast< RenderTargetExistingInitInfo& >( createInfo ).RT.Ptr(); + } + + return fmt::format( "[RenderTargetCreator] IAssetCreateInfo of type [{}] not supported.", type ); +} + +// ================================ // +// +Nullable< Resource* > RenderTargetCreator::LoadFromRaw ( const AssetPath& assetName, const BufferRaw& rawData ) +{ + assert( !"Buffer is not cacheable" ); + return nullptr; +} + +// ================================ // +// +BufferRaw RenderTargetCreator::SaveToRaw ( const IAssetCreateInfo& createInfo ) +{ + assert( !"Buffer is not cacheable" ); + return BufferTyped< uint8 >::CreateEmpty(); +} + +// ================================ // +// +BufferRaw RenderTargetCreator::SaveToRaw ( ResourcePtr< Resource > resource ) +{ + assert( !"Buffer is not cacheable" ); + return BufferTyped< uint8 >::CreateEmpty(); +} + +// ================================ // +// +bool RenderTargetCreator::IsCacheable () const +{ + return false; +} + +// ================================ // +// +bool RenderTargetCreator::SupportsResourceToRaw() const +{ + return false; +} + +// ================================ // +// +TypeID RenderTargetCreator::GetAssetType () const +{ + return TypeID::get< RenderTarget >(); +} + + + +} // sw diff --git a/ResourceManager/AssetCreators/Textures/RenderTargetCreator.h b/ResourceManager/AssetCreators/Textures/RenderTargetCreator.h new file mode 100644 index 0000000..b491807 --- /dev/null +++ b/ResourceManager/AssetCreators/Textures/RenderTargetCreator.h @@ -0,0 +1,69 @@ +#pragma once +/** +@file RenderTargetCreator.h +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + + + +#include "swGraphicAPI/ResourceManager/AssetCreators/IAssetCreator.h" + + +namespace sw +{ + + +/**@brief Adds existing RenderTarget. +Hack for SwapChain RenderTargets that are created through GraphicAPI.*/ +struct RenderTargetExistingInitInfo : public sw::IAssetCreateInfo +{ +private: + RTTR_ENABLE( sw::IAssetCreateInfo ); +public: + + RenderTargetPtr RT; + +public: + virtual TypeID GetAssetType () const override { return TypeID::get< RenderTarget >(); } +}; + + + +/**@brief Creates RenderTarget. + +@note RenderTargetCreator can't add color, depth and stencil textures to ResourceManager. +We need to load render targets using Loader to add them. + +@ingroup AssetsCreators*/ +class RenderTargetCreator : public IAssetCreator +{ +private: +protected: +public: + explicit RenderTargetCreator () = default; + virtual ~RenderTargetCreator () = default; + + +public: + + virtual Nullable< Resource* > Create ( const AssetPath& assetName, IAssetCreateInfo&& createInfo ) override; + + virtual Nullable< Resource* > LoadFromRaw ( const AssetPath& assetName, const BufferRaw& rawData ) override; + virtual BufferRaw SaveToRaw ( const IAssetCreateInfo& createInfo ) override; + virtual BufferRaw SaveToRaw ( ResourcePtr< Resource > resource ) override; + + virtual bool IsCacheable () const override; + virtual bool SupportsResourceToRaw () const override; + virtual TypeID GetAssetType () const override; + +}; + + + +} // sw + + + + + diff --git a/ResourceManager/AssetCreators/Textures/Resampler/resampler.cpp b/ResourceManager/AssetCreators/Textures/Resampler/resampler.cpp new file mode 100644 index 0000000..8073425 --- /dev/null +++ b/ResourceManager/AssetCreators/Textures/Resampler/resampler.cpp @@ -0,0 +1,1220 @@ +// resampler.cpp, Separable filtering image rescaler v2.21, Rich Geldreich - richgel99@gmail.com +// See unlicense at the bottom of resampler.h, or at http://unlicense.org/ +// +// Feb. 1996: Creation, losely based on a heavily bugfixed version of Schumacher's resampler in Graphics Gems 3. +// Oct. 2000: Ported to C++, tweaks. +// May 2001: Continous to discrete mapping, box filter tweaks. +// March 9, 2002: Kaiser filter grabbed from Jonathan Blow's GD magazine mipmap sample code. +// Sept. 8, 2002: Comments cleaned up a bit. +// Dec. 31, 2008: v2.2: Bit more cleanup, released as public domain. +// June 4, 2012: v2.21: Switched to unlicense.org, integrated GCC fixes supplied by Peter Nagy , Anteru at anteru.net, and clay@coge.net, +// added Codeblocks project (for testing with MinGW and GCC), VS2008 static code analysis pass. +#include +#include +#include +#include +#include +#include "resampler.h" + +#define resampler_assert assert + +static inline int resampler_range_check(int v, int h) { (void)h; resampler_assert((v >= 0) && (v < h)); return v; } + +#ifndef max + #define max(a,b) (((a) > (b)) ? (a) : (b)) +#endif + +#ifndef min + #define min(a,b) (((a) < (b)) ? (a) : (b)) +#endif + +#ifndef TRUE + #define TRUE (1) +#endif + +#ifndef FALSE + #define FALSE (0) +#endif + +#define RESAMPLER_DEBUG 0 + +#define M_PI 3.14159265358979323846 + +// Float to int cast with truncation. +static inline int cast_to_int(Resample_Real i) +{ + return (int)i; +} + +// (x mod y) with special handling for negative x values. +static inline int posmod(int x, int y) +{ + if (x >= 0) + return (x % y); + else + { + int m = (-x) % y; + + if (m != 0) + m = y - m; + + return (m); + } +} + +// To add your own filter, insert the new function below and update the filter table. +// There is no need to make the filter function particularly fast, because it's +// only called during initializing to create the X and Y axis contributor tables. + +#define BOX_FILTER_SUPPORT (0.5f) +static Resample_Real box_filter(Resample_Real t) /* pulse/Fourier window */ +{ + // make_clist() calls the filter function with t inverted (pos = left, neg = right) + if ((t >= -0.5f) && (t < 0.5f)) + return 1.0f; + else + return 0.0f; +} + +#define TENT_FILTER_SUPPORT (1.0f) +static Resample_Real tent_filter(Resample_Real t) /* box (*) box, bilinear/triangle */ +{ + if (t < 0.0f) + t = -t; + + if (t < 1.0f) + return 1.0f - t; + else + return 0.0f; +} + +#define BELL_SUPPORT (1.5f) +static Resample_Real bell_filter(Resample_Real t) /* box (*) box (*) box */ +{ + if (t < 0.0f) + t = -t; + + if (t < .5f) + return (.75f - (t * t)); + + if (t < 1.5f) + { + t = (t - 1.5f); + return (.5f * (t * t)); + } + + return (0.0f); +} + +#define B_SPLINE_SUPPORT (2.0f) +static Resample_Real B_spline_filter(Resample_Real t) /* box (*) box (*) box (*) box */ +{ + Resample_Real tt; + + if (t < 0.0f) + t = -t; + + if (t < 1.0f) + { + tt = t * t; + return ((.5f * tt * t) - tt + (2.0f / 3.0f)); + } + else if (t < 2.0f) + { + t = 2.0f - t; + return ((1.0f / 6.0f) * (t * t * t)); + } + + return (0.0f); +} + +// Dodgson, N., "Quadratic Interpolation for Image Resampling" +#define QUADRATIC_SUPPORT 1.5f +static Resample_Real quadratic(Resample_Real t, const Resample_Real R) +{ + if (t < 0.0f) + t = -t; + if (t < QUADRATIC_SUPPORT) + { + Resample_Real tt = t * t; + if (t <= .5f) + return (-2.0f * R) * tt + .5f * (R + 1.0f); + else + return (R * tt) + (-2.0f * R - .5f) * t + (3.0f / 4.0f) * (R + 1.0f); + } + else + return 0.0f; +} + +static Resample_Real quadratic_interp_filter(Resample_Real t) +{ + return quadratic(t, 1.0f); +} + +static Resample_Real quadratic_approx_filter(Resample_Real t) +{ + return quadratic(t, .5f); +} + +static Resample_Real quadratic_mix_filter(Resample_Real t) +{ + return quadratic(t, .8f); +} + +// Mitchell, D. and A. Netravali, "Reconstruction Filters in Computer Graphics." +// Computer Graphics, Vol. 22, No. 4, pp. 221-228. +// (B, C) +// (1/3, 1/3) - Defaults recommended by Mitchell and Netravali +// (1, 0) - Equivalent to the Cubic B-Spline +// (0, 0.5) - Equivalent to the Catmull-Rom Spline +// (0, C) - The family of Cardinal Cubic Splines +// (B, 0) - Duff's tensioned B-Splines. +static Resample_Real mitchell(Resample_Real t, const Resample_Real B, const Resample_Real C) +{ + Resample_Real tt; + + tt = t * t; + + if(t < 0.0f) + t = -t; + + if(t < 1.0f) + { + t = (((12.0f - 9.0f * B - 6.0f * C) * (t * tt)) + + ((-18.0f + 12.0f * B + 6.0f * C) * tt) + + (6.0f - 2.0f * B)); + + return (t / 6.0f); + } + else if (t < 2.0f) + { + t = (((-1.0f * B - 6.0f * C) * (t * tt)) + + ((6.0f * B + 30.0f * C) * tt) + + ((-12.0f * B - 48.0f * C) * t) + + (8.0f * B + 24.0f * C)); + + return (t / 6.0f); + } + + return (0.0f); +} + +#define MITCHELL_SUPPORT (2.0f) +static Resample_Real mitchell_filter(Resample_Real t) +{ + return mitchell(t, 1.0f / 3.0f, 1.0f / 3.0f); +} + +#define CATMULL_ROM_SUPPORT (2.0f) +static Resample_Real catmull_rom_filter(Resample_Real t) +{ + return mitchell(t, 0.0f, .5f); +} + +static double sinc(double x) +{ + x = (x * M_PI); + + if ((x < 0.01f) && (x > -0.01f)) + return 1.0f + x*x*(-1.0f/6.0f + x*x*1.0f/120.0f); + + return sin(x) / x; +} + +static Resample_Real clean(double t) +{ + const Resample_Real EPSILON = .0000125f; + if (fabs(t) < EPSILON) + return 0.0f; + return (Resample_Real)t; +} + +//static double blackman_window(double x) +//{ +// return .42f + .50f * cos(M_PI*x) + .08f * cos(2.0f*M_PI*x); +//} + +static double blackman_exact_window(double x) +{ + return 0.42659071f + 0.49656062f * cos(M_PI*x) + 0.07684867f * cos(2.0f*M_PI*x); +} + +#define BLACKMAN_SUPPORT (3.0f) +static Resample_Real blackman_filter(Resample_Real t) +{ + if (t < 0.0f) + t = -t; + + if (t < 3.0f) + //return clean(sinc(t) * blackman_window(t / 3.0f)); + return clean(sinc(t) * blackman_exact_window(t / 3.0f)); + else + return (0.0f); +} + +#define GAUSSIAN_SUPPORT (1.25f) +static Resample_Real gaussian_filter(Resample_Real t) // with blackman window +{ + if (t < 0) + t = -t; + if (t < GAUSSIAN_SUPPORT) + return clean(exp(-2.0f * t * t) * sqrt(2.0f / M_PI) * blackman_exact_window(t / GAUSSIAN_SUPPORT)); + else + return 0.0f; +} + +// Windowed sinc -- see "Jimm Blinn's Corner: Dirty Pixels" pg. 26. +#define LANCZOS3_SUPPORT (3.0f) +static Resample_Real lanczos3_filter(Resample_Real t) +{ + if (t < 0.0f) + t = -t; + + if (t < 3.0f) + return clean(sinc(t) * sinc(t / 3.0f)); + else + return (0.0f); +} + +#define LANCZOS4_SUPPORT (4.0f) +static Resample_Real lanczos4_filter(Resample_Real t) +{ + if (t < 0.0f) + t = -t; + + if (t < 4.0f) + return clean(sinc(t) * sinc(t / 4.0f)); + else + return (0.0f); +} + +#define LANCZOS6_SUPPORT (6.0f) +static Resample_Real lanczos6_filter(Resample_Real t) +{ + if (t < 0.0f) + t = -t; + + if (t < 6.0f) + return clean(sinc(t) * sinc(t / 6.0f)); + else + return (0.0f); +} + +#define LANCZOS12_SUPPORT (12.0f) +static Resample_Real lanczos12_filter(Resample_Real t) +{ + if (t < 0.0f) + t = -t; + + if (t < 12.0f) + return clean(sinc(t) * sinc(t / 12.0f)); + else + return (0.0f); +} + +static double bessel0(double x) +{ + const double EPSILON_RATIO = 1E-16; + double xh, sum, pow, ds; + int k; + + xh = 0.5 * x; + sum = 1.0; + pow = 1.0; + k = 0; + ds = 1.0; + while (ds > sum * EPSILON_RATIO) // FIXME: Shouldn't this stop after X iterations for max. safety? + { + ++k; + pow = pow * (xh / k); + ds = pow * pow; + sum = sum + ds; + } + + return sum; +} + +static const Resample_Real KAISER_ALPHA = 4.0; +static double kaiser(double alpha, double half_width, double x) +{ + const double ratio = (x / half_width); + return bessel0(alpha * sqrt(1 - ratio * ratio)) / bessel0(alpha); +} + +#define KAISER_SUPPORT 3 +static Resample_Real kaiser_filter(Resample_Real t) +{ + if (t < 0.0f) + t = -t; + + if (t < KAISER_SUPPORT) + { + // db atten + const Resample_Real att = 40.0f; + const Resample_Real alpha = (Resample_Real)(exp(log((double)0.58417 * (att - 20.96)) * 0.4) + 0.07886 * (att - 20.96)); + //const Resample_Real alpha = KAISER_ALPHA; + return (Resample_Real)clean(sinc(t) * kaiser(alpha, KAISER_SUPPORT, t)); + } + + return 0.0f; +} + +// filters[] is a list of all the available filter functions. +static struct +{ + char name[32]; + Resample_Real (*func)(Resample_Real t); + Resample_Real support; +} g_filters[] = +{ + { "box", box_filter, BOX_FILTER_SUPPORT }, + { "tent", tent_filter, TENT_FILTER_SUPPORT }, + { "bell", bell_filter, BELL_SUPPORT }, + { "b-spline", B_spline_filter, B_SPLINE_SUPPORT }, + { "mitchell", mitchell_filter, MITCHELL_SUPPORT }, + { "lanczos3", lanczos3_filter, LANCZOS3_SUPPORT }, + { "blackman", blackman_filter, BLACKMAN_SUPPORT }, + { "lanczos4", lanczos4_filter, LANCZOS4_SUPPORT }, + { "lanczos6", lanczos6_filter, LANCZOS6_SUPPORT }, + { "lanczos12", lanczos12_filter, LANCZOS12_SUPPORT }, + { "kaiser", kaiser_filter, KAISER_SUPPORT }, + { "gaussian", gaussian_filter, GAUSSIAN_SUPPORT }, + { "catmullrom", catmull_rom_filter, CATMULL_ROM_SUPPORT }, + { "quadratic_interp", quadratic_interp_filter, QUADRATIC_SUPPORT }, + { "quadratic_approx", quadratic_approx_filter, QUADRATIC_SUPPORT }, + { "quadratic_mix", quadratic_mix_filter, QUADRATIC_SUPPORT }, +}; + +static const int NUM_FILTERS = sizeof(g_filters) / sizeof(g_filters[0]); + +/* Ensure that the contributing source sample is +* within bounds. If not, reflect, clamp, or wrap. +*/ +int Resampler::reflect(const int j, const int src_x, const Boundary_Op boundary_op) +{ + int n; + + if (j < 0) + { + if (boundary_op == BOUNDARY_REFLECT) + { + n = -j; + + if (n >= src_x) + n = src_x - 1; + } + else if (boundary_op == BOUNDARY_WRAP) + n = posmod(j, src_x); + else + n = 0; + } + else if (j >= src_x) + { + if (boundary_op == BOUNDARY_REFLECT) + { + n = (src_x - j) + (src_x - 1); + + if (n < 0) + n = 0; + } + else if (boundary_op == BOUNDARY_WRAP) + n = posmod(j, src_x); + else + n = src_x - 1; + } + else + n = j; + + return n; +} + +// The make_clist() method generates, for all destination samples, +// the list of all source samples with non-zero weighted contributions. +Resampler::Contrib_List* Resampler::make_clist( + int src_x, int dst_x, Boundary_Op boundary_op, + Resample_Real (*Pfilter)(Resample_Real), + Resample_Real filter_support, + Resample_Real filter_scale, + Resample_Real src_ofs) +{ + typedef struct + { + // The center of the range in DISCRETE coordinates (pixel center = 0.0f). + Resample_Real center; + int left, right; + } Contrib_Bounds; + + int i, j, k, n, left, right; + Resample_Real total_weight; + Resample_Real xscale, center, half_width, weight; + Contrib_List* Pcontrib; + Contrib* Pcpool; + Contrib* Pcpool_next; + Contrib_Bounds* Pcontrib_bounds; + + if ((Pcontrib = (Contrib_List*)calloc(dst_x, sizeof(Contrib_List))) == NULL) + return NULL; + + Pcontrib_bounds = (Contrib_Bounds*)calloc(dst_x, sizeof(Contrib_Bounds)); + if (!Pcontrib_bounds) + { + free(Pcontrib); + return (NULL); + } + + const Resample_Real oo_filter_scale = 1.0f / filter_scale; + + const Resample_Real NUDGE = 0.5f; + xscale = dst_x / (Resample_Real)src_x; + + if (xscale < 1.0f) + { + int total; (void)total; + + /* Handle case when there are fewer destination + * samples than source samples (downsampling/minification). + */ + + // stretched half width of filter + half_width = (filter_support / xscale) * filter_scale; + + // Find the range of source sample(s) that will contribute to each destination sample. + + for (i = 0, n = 0; i < dst_x; i++) + { + // Convert from discrete to continuous coordinates, scale, then convert back to discrete. + center = ((Resample_Real)i + NUDGE) / xscale; + center -= NUDGE; + center += src_ofs; + + left = cast_to_int((Resample_Real)floor(center - half_width)); + right = cast_to_int((Resample_Real)ceil(center + half_width)); + + Pcontrib_bounds[i].center = center; + Pcontrib_bounds[i].left = left; + Pcontrib_bounds[i].right = right; + + n += (right - left + 1); + } + + /* Allocate memory for contributors. */ + + if ((n == 0) || ((Pcpool = (Contrib*)calloc(n, sizeof(Contrib))) == NULL)) + { + free(Pcontrib); + free(Pcontrib_bounds); + return NULL; + } + total = n; + + Pcpool_next = Pcpool; + + /* Create the list of source samples which + * contribute to each destination sample. + */ + + for (i = 0; i < dst_x; i++) + { + int max_k = -1; + Resample_Real max_w = -1e+20f; + + center = Pcontrib_bounds[i].center; + left = Pcontrib_bounds[i].left; + right = Pcontrib_bounds[i].right; + + Pcontrib[i].n = 0; + Pcontrib[i].p = Pcpool_next; + Pcpool_next += (right - left + 1); + resampler_assert ((Pcpool_next - Pcpool) <= total); + + total_weight = 0; + + for (j = left; j <= right; j++) + total_weight += (*Pfilter)((center - (Resample_Real)j) * xscale * oo_filter_scale); + const Resample_Real norm = static_cast(1.0f / total_weight); + + total_weight = 0; + +#if RESAMPLER_DEBUG + printf("%i: ", i); +#endif + + for (j = left; j <= right; j++) + { + weight = (*Pfilter)((center - (Resample_Real)j) * xscale * oo_filter_scale) * norm; + if (weight == 0.0f) + continue; + + n = reflect(j, src_x, boundary_op); + +#if RESAMPLER_DEBUG + printf("%i(%f), ", n, weight); +#endif + + /* Increment the number of source + * samples which contribute to the + * current destination sample. + */ + + k = Pcontrib[i].n++; + + Pcontrib[i].p[k].pixel = (unsigned short)(n); /* store src sample number */ + Pcontrib[i].p[k].weight = weight; /* store src sample weight */ + + total_weight += weight; /* total weight of all contributors */ + + if (weight > max_w) + { + max_w = weight; + max_k = k; + } + } + +#if RESAMPLER_DEBUG + printf("\n\n"); +#endif + + //resampler_assert(Pcontrib[i].n); + //resampler_assert(max_k != -1); + if ((max_k == -1) || (Pcontrib[i].n == 0)) + { + free(Pcpool); + free(Pcontrib); + free(Pcontrib_bounds); + return NULL; + } + + if (total_weight != 1.0f) + Pcontrib[i].p[max_k].weight += 1.0f - total_weight; + } + } + else + { + /* Handle case when there are more + * destination samples than source + * samples (upsampling). + */ + + half_width = filter_support * filter_scale; + + // Find the source sample(s) that contribute to each destination sample. + + for (i = 0, n = 0; i < dst_x; i++) + { + // Convert from discrete to continuous coordinates, scale, then convert back to discrete. + center = ((Resample_Real)i + NUDGE) / xscale; + center -= NUDGE; + center += src_ofs; + + left = cast_to_int((Resample_Real)floor(center - half_width)); + right = cast_to_int((Resample_Real)ceil(center + half_width)); + + Pcontrib_bounds[i].center = center; + Pcontrib_bounds[i].left = left; + Pcontrib_bounds[i].right = right; + + n += (right - left + 1); + } + + /* Allocate memory for contributors. */ + + int total = n; + if ((total == 0) || ((Pcpool = (Contrib*)calloc(total, sizeof(Contrib))) == NULL)) + { + free(Pcontrib); + free(Pcontrib_bounds); + return NULL; + } + + Pcpool_next = Pcpool; + + /* Create the list of source samples which + * contribute to each destination sample. + */ + + for (i = 0; i < dst_x; i++) + { + int max_k = -1; + Resample_Real max_w = -1e+20f; + + center = Pcontrib_bounds[i].center; + left = Pcontrib_bounds[i].left; + right = Pcontrib_bounds[i].right; + + Pcontrib[i].n = 0; + Pcontrib[i].p = Pcpool_next; + Pcpool_next += (right - left + 1); + resampler_assert((Pcpool_next - Pcpool) <= total); + + total_weight = 0; + for (j = left; j <= right; j++) + total_weight += (*Pfilter)((center - (Resample_Real)j) * oo_filter_scale); + + const Resample_Real norm = static_cast(1.0f / total_weight); + + total_weight = 0; + +#if RESAMPLER_DEBUG + printf("%i: ", i); +#endif + + for (j = left; j <= right; j++) + { + weight = (*Pfilter)((center - (Resample_Real)j) * oo_filter_scale) * norm; + if (weight == 0.0f) + continue; + + n = reflect(j, src_x, boundary_op); + +#if RESAMPLER_DEBUG + printf("%i(%f), ", n, weight); +#endif + + /* Increment the number of source + * samples which contribute to the + * current destination sample. + */ + + k = Pcontrib[i].n++; + + Pcontrib[i].p[k].pixel = (unsigned short)(n); /* store src sample number */ + Pcontrib[i].p[k].weight = weight; /* store src sample weight */ + + total_weight += weight; /* total weight of all contributors */ + + if (weight > max_w) + { + max_w = weight; + max_k = k; + } + } + +#if RESAMPLER_DEBUG + printf("\n\n"); +#endif + + //resampler_assert(Pcontrib[i].n); + //resampler_assert(max_k != -1); + + if ((max_k == -1) || (Pcontrib[i].n == 0)) + { + free(Pcpool); + free(Pcontrib); + free(Pcontrib_bounds); + return NULL; + } + + if (total_weight != 1.0f) + Pcontrib[i].p[max_k].weight += 1.0f - total_weight; + } + } + +#if RESAMPLER_DEBUG + printf("*******\n"); +#endif + + free(Pcontrib_bounds); + + return Pcontrib; +} + +void Resampler::resample_x(Sample* Pdst, const Sample* Psrc) +{ + resampler_assert(Pdst); + resampler_assert(Psrc); + + int i, j; + Sample total; + Contrib_List *Pclist = m_Pclist_x; + Contrib *p; + + for (i = m_resample_dst_x; i > 0; i--, Pclist++) + { +#if RESAMPLER_DEBUG_OPS + total_ops += Pclist->n; +#endif + + for (j = Pclist->n, p = Pclist->p, total = 0; j > 0; j--, p++) + total += Psrc[p->pixel] * p->weight; + + *Pdst++ = total; + } +} + +void Resampler::scale_y_mov(Sample* Ptmp, const Sample* Psrc, Resample_Real weight, int dst_x) +{ + int i; + +#if RESAMPLER_DEBUG_OPS + total_ops += dst_x; +#endif + + // Not += because temp buf wasn't cleared. + for (i = dst_x; i > 0; i--) + *Ptmp++ = *Psrc++ * weight; +} + +void Resampler::scale_y_add(Sample* Ptmp, const Sample* Psrc, Resample_Real weight, int dst_x) +{ +#if RESAMPLER_DEBUG_OPS + total_ops += dst_x; +#endif + + for (int i = dst_x; i > 0; i--) + (*Ptmp++) += *Psrc++ * weight; +} + +void Resampler::clamp(Sample* Pdst, int n) +{ + while (n > 0) + { + *Pdst = clamp_sample(*Pdst); + ++Pdst; + n--; + } +} + +void Resampler::resample_y(Sample* Pdst) +{ + int i, j; + Sample* Psrc; + Contrib_List* Pclist = &m_Pclist_y[m_cur_dst_y]; + + Sample* Ptmp = m_delay_x_resample ? m_Ptmp_buf : Pdst; + resampler_assert(Ptmp); + + /* Process each contributor. */ + + for (i = 0; i < Pclist->n; i++) + { + /* locate the contributor's location in the scan + * buffer -- the contributor must always be found! + */ + + for (j = 0; j < MAX_SCAN_BUF_SIZE; j++) + if (m_Pscan_buf->scan_buf_y[j] == Pclist->p[i].pixel) + break; + + resampler_assert(j < MAX_SCAN_BUF_SIZE); + + Psrc = m_Pscan_buf->scan_buf_l[j]; + + if (!i) + scale_y_mov(Ptmp, Psrc, Pclist->p[i].weight, m_intermediate_x); + else + scale_y_add(Ptmp, Psrc, Pclist->p[i].weight, m_intermediate_x); + + /* If this source line doesn't contribute to any + * more destination lines then mark the scanline buffer slot + * which holds this source line as free. + * (The max. number of slots used depends on the Y + * axis sampling factor and the scaled filter width.) + */ + + if (--m_Psrc_y_count[resampler_range_check(Pclist->p[i].pixel, m_resample_src_y)] == 0) + { + m_Psrc_y_flag[resampler_range_check(Pclist->p[i].pixel, m_resample_src_y)] = FALSE; + m_Pscan_buf->scan_buf_y[j] = -1; + } + } + + /* Now generate the destination line */ + + if (m_delay_x_resample) // Was X resampling delayed until after Y resampling? + { + resampler_assert(Pdst != Ptmp); + resample_x(Pdst, Ptmp); + } + else + { + resampler_assert(Pdst == Ptmp); + } + + if (m_lo < m_hi) + clamp(Pdst, m_resample_dst_x); +} + +bool Resampler::put_line(const Sample* Psrc) +{ + int i; + + if (m_cur_src_y >= m_resample_src_y) + return false; + + /* Does this source line contribute + * to any destination line? if not, + * exit now. + */ + + if (!m_Psrc_y_count[resampler_range_check(m_cur_src_y, m_resample_src_y)]) + { + m_cur_src_y++; + return true; + } + + /* Find an empty slot in the scanline buffer. (FIXME: Perf. is terrible here with extreme scaling ratios.) */ + + for (i = 0; i < MAX_SCAN_BUF_SIZE; i++) + if (m_Pscan_buf->scan_buf_y[i] == -1) + break; + + /* If the buffer is full, exit with an error. */ + + if (i == MAX_SCAN_BUF_SIZE) + { + m_status = STATUS_SCAN_BUFFER_FULL; + return false; + } + + m_Psrc_y_flag[resampler_range_check(m_cur_src_y, m_resample_src_y)] = TRUE; + m_Pscan_buf->scan_buf_y[i] = m_cur_src_y; + + /* Does this slot have any memory allocated to it? */ + + if (!m_Pscan_buf->scan_buf_l[i]) + { + if ((m_Pscan_buf->scan_buf_l[i] = (Sample*)malloc(m_intermediate_x * sizeof(Sample))) == NULL) + { + m_status = STATUS_OUT_OF_MEMORY; + return false; + } + } + + // Resampling on the X axis first? + if (m_delay_x_resample) + { + resampler_assert(m_intermediate_x == m_resample_src_x); + + // Y-X resampling order + memcpy(m_Pscan_buf->scan_buf_l[i], Psrc, m_intermediate_x * sizeof(Sample)); + } + else + { + resampler_assert(m_intermediate_x == m_resample_dst_x); + + // X-Y resampling order + resample_x(m_Pscan_buf->scan_buf_l[i], Psrc); + } + + m_cur_src_y++; + + return true; +} + +const Resampler::Sample* Resampler::get_line() +{ + int i; + + /* If all the destination lines have been + * generated, then always return NULL. + */ + + if (m_cur_dst_y == m_resample_dst_y) + return NULL; + + /* Check to see if all the required + * contributors are present, if not, + * return NULL. + */ + + for (i = 0; i < m_Pclist_y[m_cur_dst_y].n; i++) + if (!m_Psrc_y_flag[resampler_range_check(m_Pclist_y[m_cur_dst_y].p[i].pixel, m_resample_src_y)]) + return NULL; + + resample_y(m_Pdst_buf); + + m_cur_dst_y++; + + return m_Pdst_buf; +} + +Resampler::~Resampler() +{ + int i; + +#if RESAMPLER_DEBUG_OPS + printf("actual ops: %i\n", total_ops); +#endif + + free(m_Pdst_buf); + m_Pdst_buf = NULL; + + if (m_Ptmp_buf) + { + free(m_Ptmp_buf); + m_Ptmp_buf = NULL; + } + + /* Don't deallocate a contibutor list + * if the user passed us one of their own. + */ + + if ((m_Pclist_x) && (!m_clist_x_forced)) + { + free(m_Pclist_x->p); + free(m_Pclist_x); + m_Pclist_x = NULL; + } + + if ((m_Pclist_y) && (!m_clist_y_forced)) + { + free(m_Pclist_y->p); + free(m_Pclist_y); + m_Pclist_y = NULL; + } + + free(m_Psrc_y_count); + m_Psrc_y_count = NULL; + + free(m_Psrc_y_flag); + m_Psrc_y_flag = NULL; + + if (m_Pscan_buf) + { + for (i = 0; i < MAX_SCAN_BUF_SIZE; i++) + free(m_Pscan_buf->scan_buf_l[i]); + + free(m_Pscan_buf); + m_Pscan_buf = NULL; + } +} + +void Resampler::restart() +{ + if (STATUS_OKAY != m_status) + return; + + m_cur_src_y = m_cur_dst_y = 0; + + int i, j; + for (i = 0; i < m_resample_src_y; i++) + { + m_Psrc_y_count[i] = 0; + m_Psrc_y_flag[i] = FALSE; + } + + for (i = 0; i < m_resample_dst_y; i++) + { + for (j = 0; j < m_Pclist_y[i].n; j++) + m_Psrc_y_count[resampler_range_check(m_Pclist_y[i].p[j].pixel, m_resample_src_y)]++; + } + + for (i = 0; i < MAX_SCAN_BUF_SIZE; i++) + { + m_Pscan_buf->scan_buf_y[i] = -1; + + free(m_Pscan_buf->scan_buf_l[i]); + m_Pscan_buf->scan_buf_l[i] = NULL; + } +} + +Resampler::Resampler(int src_x, int src_y, + int dst_x, int dst_y, + Boundary_Op boundary_op, + Resample_Real sample_low, Resample_Real sample_high, + const char* Pfilter_name, + Contrib_List* Pclist_x, + Contrib_List* Pclist_y, + Resample_Real filter_x_scale, + Resample_Real filter_y_scale, + Resample_Real src_x_ofs, + Resample_Real src_y_ofs) +{ + int i, j; + Resample_Real support, (*func)(Resample_Real); + + resampler_assert(src_x > 0); + resampler_assert(src_y > 0); + resampler_assert(dst_x > 0); + resampler_assert(dst_y > 0); + +#if RESAMPLER_DEBUG_OPS + total_ops = 0; +#endif + + m_lo = sample_low; + m_hi = sample_high; + + m_delay_x_resample = false; + m_intermediate_x = 0; + m_Pdst_buf = NULL; + m_Ptmp_buf = NULL; + m_clist_x_forced = false; + m_Pclist_x = NULL; + m_clist_y_forced = false; + m_Pclist_y = NULL; + m_Psrc_y_count = NULL; + m_Psrc_y_flag = NULL; + m_Pscan_buf = NULL; + m_status = STATUS_OKAY; + + m_resample_src_x = src_x; + m_resample_src_y = src_y; + m_resample_dst_x = dst_x; + m_resample_dst_y = dst_y; + + m_boundary_op = boundary_op; + + if ((m_Pdst_buf = (Sample*)malloc(m_resample_dst_x * sizeof(Sample))) == NULL) + { + m_status = STATUS_OUT_OF_MEMORY; + return; + } + + // Find the specified filter. + + if (Pfilter_name == NULL) + Pfilter_name = RESAMPLER_DEFAULT_FILTER; + + for (i = 0; i < NUM_FILTERS; i++) + if (strcmp(Pfilter_name, g_filters[i].name) == 0) + break; + + if (i == NUM_FILTERS) + { + m_status = STATUS_BAD_FILTER_NAME; + return; + } + + func = g_filters[i].func; + support = g_filters[i].support; + + /* Create contributor lists, unless the user supplied custom lists. */ + + if (!Pclist_x) + { + m_Pclist_x = make_clist(m_resample_src_x, m_resample_dst_x, m_boundary_op, func, support, filter_x_scale, src_x_ofs); + if (!m_Pclist_x) + { + m_status = STATUS_OUT_OF_MEMORY; + return; + } + } + else + { + m_Pclist_x = Pclist_x; + m_clist_x_forced = true; + } + + if (!Pclist_y) + { + m_Pclist_y = make_clist(m_resample_src_y, m_resample_dst_y, m_boundary_op, func, support, filter_y_scale, src_y_ofs); + if (!m_Pclist_y) + { + m_status = STATUS_OUT_OF_MEMORY; + return; + } + } + else + { + m_Pclist_y = Pclist_y; + m_clist_y_forced = true; + } + + if ((m_Psrc_y_count = (int*)calloc(m_resample_src_y, sizeof(int))) == NULL) + { + m_status = STATUS_OUT_OF_MEMORY; + return; + } + + if ((m_Psrc_y_flag = (unsigned char*)calloc(m_resample_src_y, sizeof(unsigned char))) == NULL) + { + m_status = STATUS_OUT_OF_MEMORY; + return; + } + + /* Count how many times each source line + * contributes to a destination line. + */ + + for (i = 0; i < m_resample_dst_y; i++) + for (j = 0; j < m_Pclist_y[i].n; j++) + m_Psrc_y_count[resampler_range_check(m_Pclist_y[i].p[j].pixel, m_resample_src_y)]++; + + if ((m_Pscan_buf = (Scan_Buf*)malloc(sizeof(Scan_Buf))) == NULL) + { + m_status = STATUS_OUT_OF_MEMORY; + return; + } + + for (i = 0; i < MAX_SCAN_BUF_SIZE; i++) + { + m_Pscan_buf->scan_buf_y[i] = -1; + m_Pscan_buf->scan_buf_l[i] = NULL; + } + + m_cur_src_y = m_cur_dst_y = 0; + { + // Determine which axis to resample first by comparing the number of multiplies required + // for each possibility. + int x_ops = count_ops(m_Pclist_x, m_resample_dst_x); + int y_ops = count_ops(m_Pclist_y, m_resample_dst_y); + + // Hack 10/2000: Weight Y axis ops a little more than X axis ops. + // (Y axis ops use more cache resources.) + int xy_ops = x_ops * m_resample_src_y + + (4 * y_ops * m_resample_dst_x)/3; + + int yx_ops = (4 * y_ops * m_resample_src_x)/3 + + x_ops * m_resample_dst_y; + +#if RESAMPLER_DEBUG_OPS + printf("src: %i %i\n", m_resample_src_x, m_resample_src_y); + printf("dst: %i %i\n", m_resample_dst_x, m_resample_dst_y); + printf("x_ops: %i\n", x_ops); + printf("y_ops: %i\n", y_ops); + printf("xy_ops: %i\n", xy_ops); + printf("yx_ops: %i\n", yx_ops); +#endif + + // Now check which resample order is better. In case of a tie, choose the order + // which buffers the least amount of data. + if ((xy_ops > yx_ops) || + ((xy_ops == yx_ops) && (m_resample_src_x < m_resample_dst_x)) + ) + { + m_delay_x_resample = true; + m_intermediate_x = m_resample_src_x; + } + else + { + m_delay_x_resample = false; + m_intermediate_x = m_resample_dst_x; + } +#if RESAMPLER_DEBUG_OPS + printf("delaying: %i\n", m_delay_x_resample); +#endif + } + + if (m_delay_x_resample) + { + if ((m_Ptmp_buf = (Sample*)malloc(m_intermediate_x * sizeof(Sample))) == NULL) + { + m_status = STATUS_OUT_OF_MEMORY; + return; + } + } +} + +void Resampler::get_clists(Contrib_List** ptr_clist_x, Contrib_List** ptr_clist_y) +{ + if (ptr_clist_x) + *ptr_clist_x = m_Pclist_x; + + if (ptr_clist_y) + *ptr_clist_y = m_Pclist_y; +} + +int Resampler::get_filter_num() +{ + return NUM_FILTERS; +} + +char* Resampler::get_filter_name(int filter_num) +{ + if ((filter_num < 0) || (filter_num >= NUM_FILTERS)) + return NULL; + else + return g_filters[filter_num].name; +} + diff --git a/ResourceManager/AssetCreators/Textures/Resampler/resampler.h b/ResourceManager/AssetCreators/Textures/Resampler/resampler.h new file mode 100644 index 0000000..77a95a1 --- /dev/null +++ b/ResourceManager/AssetCreators/Textures/Resampler/resampler.h @@ -0,0 +1,196 @@ +// resampler.h, Separable filtering image rescaler v2.21, Rich Geldreich - richgel99@gmail.com +// See unlicense.org text at the bottom of this file. +#ifndef __RESAMPLER_H__ +#define __RESAMPLER_H__ + +#define RESAMPLER_DEBUG_OPS 0 +#define RESAMPLER_DEFAULT_FILTER "lanczos4" + +#define RESAMPLER_MAX_DIMENSION 16384 + +// float or double +typedef float Resample_Real; + +class Resampler +{ +public: + typedef Resample_Real Sample; + + struct Contrib + { + Resample_Real weight; + unsigned short pixel; + }; + + struct Contrib_List + { + unsigned short n; + Contrib* p; + }; + + enum Boundary_Op + { + BOUNDARY_WRAP = 0, + BOUNDARY_REFLECT = 1, + BOUNDARY_CLAMP = 2 + }; + + enum Status + { + STATUS_OKAY = 0, + STATUS_OUT_OF_MEMORY = 1, + STATUS_BAD_FILTER_NAME = 2, + STATUS_SCAN_BUFFER_FULL = 3 + }; + + // src_x/src_y - Input dimensions + // dst_x/dst_y - Output dimensions + // boundary_op - How to sample pixels near the image boundaries + // sample_low/sample_high - Clamp output samples to specified range, or disable clamping if sample_low >= sample_high + // Pclist_x/Pclist_y - Optional pointers to contributor lists from another instance of a Resampler + // src_x_ofs/src_y_ofs - Offset input image by specified amount (fractional values okay) + Resampler( + int src_x, int src_y, + int dst_x, int dst_y, + Boundary_Op boundary_op = BOUNDARY_CLAMP, + Resample_Real sample_low = 0.0f, Resample_Real sample_high = 0.0f, + const char* Pfilter_name = RESAMPLER_DEFAULT_FILTER, + Contrib_List* Pclist_x = NULL, + Contrib_List* Pclist_y = NULL, + Resample_Real filter_x_scale = 1.0f, + Resample_Real filter_y_scale = 1.0f, + Resample_Real src_x_ofs = 0.0f, + Resample_Real src_y_ofs = 0.0f); + + ~Resampler(); + + // Reinits resampler so it can handle another frame. + void restart(); + + // false on out of memory. + bool put_line(const Sample* Psrc); + + // NULL if no scanlines are currently available (give the resampler more scanlines!) + const Sample* get_line(); + + Status status() const { return m_status; } + + // Returned contributor lists can be shared with another Resampler. + void get_clists(Contrib_List** ptr_clist_x, Contrib_List** ptr_clist_y); + Contrib_List* get_clist_x() const { return m_Pclist_x; } + Contrib_List* get_clist_y() const { return m_Pclist_y; } + + // Filter accessors. + static int get_filter_num(); + static char* get_filter_name(int filter_num); + +private: + Resampler(); + Resampler(const Resampler& o); + Resampler& operator= (const Resampler& o); + +#ifdef RESAMPLER_DEBUG_OPS + int total_ops; +#endif + + int m_intermediate_x; + + int m_resample_src_x; + int m_resample_src_y; + int m_resample_dst_x; + int m_resample_dst_y; + + Boundary_Op m_boundary_op; + + Sample* m_Pdst_buf; + Sample* m_Ptmp_buf; + + Contrib_List* m_Pclist_x; + Contrib_List* m_Pclist_y; + + bool m_clist_x_forced; + bool m_clist_y_forced; + + bool m_delay_x_resample; + + int* m_Psrc_y_count; + unsigned char* m_Psrc_y_flag; + + // The maximum number of scanlines that can be buffered at one time. + enum { MAX_SCAN_BUF_SIZE = RESAMPLER_MAX_DIMENSION }; + + struct Scan_Buf + { + int scan_buf_y[MAX_SCAN_BUF_SIZE]; + Sample* scan_buf_l[MAX_SCAN_BUF_SIZE]; + }; + + Scan_Buf* m_Pscan_buf; + + int m_cur_src_y; + int m_cur_dst_y; + + Status m_status; + + void resample_x(Sample* Pdst, const Sample* Psrc); + void scale_y_mov(Sample* Ptmp, const Sample* Psrc, Resample_Real weight, int dst_x); + void scale_y_add(Sample* Ptmp, const Sample* Psrc, Resample_Real weight, int dst_x); + void clamp(Sample* Pdst, int n); + void resample_y(Sample* Pdst); + + int reflect(const int j, const int src_x, const Boundary_Op boundary_op); + + Contrib_List* make_clist( + int src_x, int dst_x, Boundary_Op boundary_op, + Resample_Real (*Pfilter)(Resample_Real), + Resample_Real filter_support, + Resample_Real filter_scale, + Resample_Real src_ofs); + + inline int count_ops(Contrib_List* Pclist, int k) + { + int i, t = 0; + for (i = 0; i < k; i++) + t += Pclist[i].n; + return (t); + } + + Resample_Real m_lo; + Resample_Real m_hi; + + inline Resample_Real clamp_sample(Resample_Real f) const + { + if (f < m_lo) + f = m_lo; + else if (f > m_hi) + f = m_hi; + return f; + } +}; + +#endif // __RESAMPLER_H__ + +// This is free and unencumbered software released into the public domain. +// +// Anyone is free to copy, modify, publish, use, compile, sell, or +// distribute this software, either in source code form or as a compiled +// binary, for any purpose, commercial or non-commercial, and by any +// means. +// +// In jurisdictions that recognize copyright laws, the author or authors +// of this software dedicate any and all copyright interest in the +// software to the public domain. We make this dedication for the benefit +// of the public at large and to the detriment of our heirs and +// successors. We intend this dedication to be an overt act of +// relinquishment in perpetuity of all present and future rights to this +// software under copyright law. +// +// 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 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. +// +// For more information, please refer to diff --git a/ResourceManager/AssetCreators/Textures/TextureCreator.cpp b/ResourceManager/AssetCreators/Textures/TextureCreator.cpp new file mode 100644 index 0000000..ad01936 --- /dev/null +++ b/ResourceManager/AssetCreators/Textures/TextureCreator.cpp @@ -0,0 +1,119 @@ +/** +@file TextureCreator.cpp +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + +#include "swGraphicAPI/ResourceManager/stdafx.h" + +#include "TextureCreator.h" + +#include "swCommonLib/Common/Converters.h" +#include "swCommonLib/Common/Buffers/BufferTyped.h" + +#include "swGraphicAPI/Resources/Textures/TextureInitData.h" + +#include "MipMapGenerator.h" + + +namespace sw +{ + +// ================================ // +// +Nullable< Resource* > TextureCreator::Create ( const AssetPath& assetName, IAssetCreateInfo&& createInfo ) +{ + TypeID type = createInfo.get_type(); + if( type == TypeID::get< TextureInitData >() ) + { + auto& typedInitData = static_cast< TextureInitData& >( createInfo ); + + TextureInfo info; + info.Width = typedInitData.Width; + info.Height = typedInitData.Height; + info.ArraySize = typedInitData.ArraySize; + info.CPURead = typedInitData.TextureUsage.CPURead; + info.CPUWrite = typedInitData.TextureUsage.CPUWrite; + info.AllowShareResource = typedInitData.TextureUsage.AllowShareResource; + info.IsCubeMap = typedInitData.IsCubeMap; + info.GenerateMipMaps = typedInitData.MipMaps.GenerateMipMaps; + info.TextureType = typedInitData.TextureType; + info.Usage = typedInitData.TextureUsage.Usage; + info.Format = typedInitData.Format; + info.MipMapFilter = typedInitData.MipMaps.Filter; + info.MipMapLevels = typedInitData.NumMipMapLevels(); + info.CutOffMipMaps = typedInitData.MipMaps.CutOffMipMaps; + + if( typedInitData.MipMaps.GenerateMipMaps ) + { + MipMapGenerator generator; + auto result = generator.Generate( typedInitData.Data, info ); + + if( !result.IsValid() ) + return result.GetError(); + + return ResourcesFactory::CreateTextureFromMemory( assetName, result.Get(), std::move( info ) ); + } + else + return ResourcesFactory::CreateTextureFromMemory( assetName, typedInitData.Data, std::move( info ) ); + } + else if( type == TypeID::get< TextureExistingInitInfo >() ) + { + // This initialization makes possible to add render target textures to + // ResourceManager. We don't create anything, because Texture already exists + // but external layers will add this asset to resources. + auto& typedInitData = static_cast< TextureExistingInitInfo& >( createInfo ); + return typedInitData.Tex.Ptr(); + } + + return fmt::format( "[TextureCreator] IAssetCreateInfo of type [{}] not supported.", type ); +} + +// ================================ // +// +Nullable< Resource* > TextureCreator::LoadFromRaw ( const AssetPath& assetName, const BufferRaw& rawData ) +{ + assert( !"Buffer is not cacheable" ); + return nullptr; +} + +// ================================ // +// +BufferRaw TextureCreator::SaveToRaw ( const IAssetCreateInfo& createInfo ) +{ + assert( !"Buffer is not cacheable" ); + return BufferTyped< uint8 >::CreateEmpty(); +} + +// ================================ // +// +BufferRaw TextureCreator::SaveToRaw ( ResourcePtr< Resource > resource ) +{ + assert( !"Buffer is not cacheable" ); + return BufferTyped< uint8 >::CreateEmpty(); +} + +// ================================ // +// +bool TextureCreator::IsCacheable () const +{ + return false; +} + +// ================================ // +// +bool TextureCreator::SupportsResourceToRaw() const +{ + return false; +} + +// ================================ // +// +TypeID TextureCreator::GetAssetType () const +{ + return TypeID::get< Texture >(); +} + + + +} // sw diff --git a/ResourceManager/AssetCreators/Textures/TextureCreator.h b/ResourceManager/AssetCreators/Textures/TextureCreator.h new file mode 100644 index 0000000..f10a7c7 --- /dev/null +++ b/ResourceManager/AssetCreators/Textures/TextureCreator.h @@ -0,0 +1,65 @@ +#pragma once +/** +@file TextureCreator.h +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + + +#include "swGraphicAPI/ResourceManager/AssetCreators/IAssetCreator.h" + + + +namespace sw +{ + +/**@brief Adds existing texture. +Hack for RenderTargets textures.*/ +struct TextureExistingInitInfo : public sw::IAssetCreateInfo +{ +private: + RTTR_ENABLE( sw::IAssetCreateInfo ); +public: + + TexturePtr Tex; + +public: + virtual TypeID GetAssetType () const override { return TypeID::get< Texture >(); } +}; + + + +/**@brief Creates texture and generates mipmaps. + +@todo Implement Texture creation with already generated mipmaps. Add new IAssetCreateInfo +structure. + +@ingroup AssetsCreators*/ +class TextureCreator : public IAssetCreator +{ +private: +protected: +public: + explicit TextureCreator () = default; + virtual ~TextureCreator () = default; + + +public: + + virtual Nullable< Resource* > Create ( const AssetPath& assetName, IAssetCreateInfo&& createInfo ) override; + + virtual Nullable< Resource* > LoadFromRaw ( const AssetPath& assetName, const BufferRaw& rawData ) override; + virtual BufferRaw SaveToRaw ( const IAssetCreateInfo& createInfo ) override; + virtual BufferRaw SaveToRaw ( ResourcePtr< Resource > resource ) override; + + virtual bool IsCacheable () const override; + virtual bool SupportsResourceToRaw () const override; + virtual TypeID GetAssetType () const override; + +}; + + + +} // sw + + diff --git a/ResourceManager/AsyncLoad/AssetLoadRequest.h b/ResourceManager/AsyncLoad/AssetLoadRequest.h new file mode 100644 index 0000000..b267a92 --- /dev/null +++ b/ResourceManager/AsyncLoad/AssetLoadRequest.h @@ -0,0 +1,67 @@ +#pragma once +/** +@file AssetLoadRequest.h +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + +#include "swCommonLib/Common/RTTR.h" +#include "swCommonLib/External/FastDelegate/FastDelegate.h" + +#include "swGraphicAPI/ResourceManager/PathTranslators/AssetPath.h" +#include "swGraphicAPI/ResourceManager/Loaders/IAssetLoadInfo.h" + +#include "AssetLoadResponse.h" + + +namespace sw +{ + +class AssetsThread; + + +namespace impl +{ + +class CreateEndMessage +{ + friend class AssetsThread; + CreateEndMessage() {} +}; + +} + + + +/**@brief Queue element for asynchronous asset loading thread. + +@ingroup AsyncLoading*/ +struct AssetLoadRequest +{ + AssetPath AssetPath; + TypeID AssetType; + IAssetLoadInfoPtr LoadInfo; + LoadingSuccessHandler OnLoaded; + LoadingFailedHandler OnFailed; + +private: + bool EndMessage; ///< Set to true if you want end loading thread execution. + +// ================================ // +// +public: + AssetLoadRequest() + : EndMessage( false ) + , AssetType( TypeID::get_by_name( "" ) ) // Set invalid type. + {} + + AssetLoadRequest( const impl::CreateEndMessage& ) + : EndMessage( true ) + , AssetType( TypeID::get_by_name( "" ) ) // Set invalid type. + {} + + bool IsEndMessage () const { return EndMessage; } +}; + +} // sw + diff --git a/ResourceManager/AsyncLoad/AssetLoadResponse.h b/ResourceManager/AsyncLoad/AssetLoadResponse.h new file mode 100644 index 0000000..af90db0 --- /dev/null +++ b/ResourceManager/AsyncLoad/AssetLoadResponse.h @@ -0,0 +1,41 @@ +#pragma once +/** +@file AssetLoadResponse.h +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + +#include "swCommonLib/Common/Exceptions/Exception.h" + +#include "swGraphicAPI/ResourceManager/PathTranslators/AssetPath.h" +#include "swGraphicAPI/ResourceManager/Loaders/IAssetLoadInfo.h" + +#include "swGraphicAPI/Resources/ResourceObject.h" +#include "swGraphicAPI/Resources/ResourcePtr.h" + + +namespace sw +{ + +/**@brief This structure is send after asset is loaded. + +@ingroup AsyncLoading*/ +struct AssetLoadResponse +{ + ResourcePointer Resource; + AssetPath FilePath; ///< Path of loaded asset, the same that was used to call async request. + IAssetLoadInfoPtr LoadInfo; ///< Structure sent to load asset. Can be nullptr. +}; + +/**@brief Delegate to invoke after asset is loaded. +@ingroup AsyncLoading*/ +//typedef fastdelegate::FastDelegate1< AssetLoadResponse& > LoadingSuccessHandler; +typedef std::function< void( AssetLoadResponse& ) > LoadingSuccessHandler; + +/**@brief Delegate to invoke after asset laoding failed. +@ingroup AsyncLoading*/ +typedef std::function< void( AssetLoadResponse&, ExceptionPtr ) > LoadingFailedHandler; + +} // sw + + diff --git a/ResourceManager/AsyncLoad/AssetsThread.cpp b/ResourceManager/AsyncLoad/AssetsThread.cpp new file mode 100644 index 0000000..96ba6fc --- /dev/null +++ b/ResourceManager/AsyncLoad/AssetsThread.cpp @@ -0,0 +1,86 @@ +/** +@file AssetsThread.cpp +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + + +#include "swGraphicAPI/ResourceManager/stdafx.h" + +#include "AssetsThread.h" + + +namespace sw +{ + + +// ================================ // +// +AssetsThread::AssetsThread( ResourceManager* resourceManApi ) + : m_resourceManager( resourceManApi ) +{ + m_thread = std::thread( &AssetsThread::LoadingThread, this ); +} + +// ================================ // +// +AssetsThread::~AssetsThread() +{ + StopThread(); + + m_thread.join(); +} + +// ================================ // +// +void AssetsThread::StopThread () +{ + /// @todo Maybe we should empty queue. + m_requests.Push( AssetLoadRequest( impl::CreateEndMessage() ) ); +} + +// ================================ // +// +void AssetsThread::QueueRequest ( AssetLoadRequest&& request ) +{ + m_requests.Push( request ); +} + +// ================================ // +// +void AssetsThread::LoadingThread () +{ + AssetLoadRequest request; + + while( true ) + { + m_requests.Pop( request ); + + if( request.IsEndMessage() ) + break; + + auto result = m_resourceManager->LoadGeneric( request.AssetPath, request.LoadInfo.get(), request.AssetType ); + + AssetLoadResponse response; + response.FilePath = std::move( request.AssetPath ); + response.LoadInfo = std::move( request.LoadInfo ); + + if( result.IsValid() ) + { + response.Resource = result.Get(); + + if( request.OnLoaded ) + request.OnLoaded( response ); + } + else + { + response.Resource = nullptr; + + if( request.OnFailed ) + request.OnFailed( response, result.GetError() ); + } + } +} + +} // sw + diff --git a/ResourceManager/AsyncLoad/AssetsThread.h b/ResourceManager/AsyncLoad/AssetsThread.h new file mode 100644 index 0000000..f28ff45 --- /dev/null +++ b/ResourceManager/AsyncLoad/AssetsThread.h @@ -0,0 +1,80 @@ +#pragma once +/** +@file AssetsThread.h +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + +#include "swCommonLib/Common/Multithreading/QueueMT.h" + +#include "AssetLoadRequest.h" +#include "AssetLoadResponse.h" +#include "swGraphicAPI/ResourceManager/ResourceManager.h" + +#include + + +namespace sw +{ + +/**@defgroup AsyncLoading Asynchronous Loading +@ingroup AssetsManagement + +@copydoc AsyncLoadingPage + + +@page AsyncLoadingPage Asynchronous Loading +@tableofcontents + +@section AsyncLoadIntro Introduction + +ResourceManager loads assets synchronously in caller thread or can queue loading request and process them +in internal thread. For managing this internal thread, AssetsThread was created. After asset is already loaded, +AssetsThread calls delegate (@ref LoadingSuccessHandler) specified by requestor to return loaded value. + +LoadingSuccessHandler gets @ref AssetLoadResponse in parameter which contains desired resource, path to file and +IAssetLoadInfo structure info. Requestor is now allowed to do with this structure whatever he wants (for example +he can move path and load info with std::move. + +All request are executed in order of pushing to queue. That means that there's guarantee that two calls to async load +from the same thread will result in the same order of loads. There're no guaranties between threads. +*/ + + +/**@brief Class for managing asynchronous assets loading. + +@todo Consider supporting multiple priority levels in future. +@todo Consider posibility to provide additional generic structure. Requestor can then identify, wich request was executed. + +@ingroup AsyncLoading*/ +class AssetsThread +{ +private: + + ResourceManager* m_resourceManager; + + QueueMT< AssetLoadRequest > m_requests; + + std::thread m_thread; + +protected: +public: + explicit AssetsThread ( ResourceManager* resourceManApi ); + ~AssetsThread (); + + /**@brief Breaks thread execution by sending end message to queue.*/ + void StopThread (); + + /**@brief Adds new request to queue.*/ + void QueueRequest ( AssetLoadRequest&& request ); + +private: + + void LoadingThread (); +}; + + + +} // sw + + diff --git a/ResourceManager/AsyncLoad/LoadBarrier.cpp b/ResourceManager/AsyncLoad/LoadBarrier.cpp new file mode 100644 index 0000000..e87e916 --- /dev/null +++ b/ResourceManager/AsyncLoad/LoadBarrier.cpp @@ -0,0 +1,213 @@ +/** +@file LoadBarrier.h +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + + +#include "swGraphicAPI/ResourceManager/stdafx.h" +#include "LoadBarrier.h" + + +namespace sw +{ + +// ================================ // +// +WaitingAsset::WaitingAsset ( const filesystem::Path& filePath ) + : m_fileName( filePath ) + , m_numWaiting( 0 ) + , m_ready( false ) +{} + +// ================================ // +// +WaitingAsset::~WaitingAsset() +{ + // @todo It won't work :( + LoadingCompleted(); +} + +// ================================ // +// +bool WaitingAsset::WaitUntilLoaded () +{ + std::unique_lock< std::mutex > lock( m_lock ); + while( !m_ready ) + m_condition.wait( lock ); + + lock.unlock(); + + auto remaining = --m_numWaiting; + if( remaining == 0 ) + return true; + return false; +} + +// ================================ // +// +void WaitingAsset::RequestAsset () +{ + m_numWaiting++; +} + +// ================================ // +// +bool WaitingAsset::LoadingCompleted () +{ + return LoadingCompleted( nullptr ); +} + +// ================================ // +// +bool WaitingAsset::LoadingCompleted ( ExceptionPtr error ) +{ + m_lock.lock(); + + m_ready = true; + m_error = error; + bool noOneWaits = m_numWaiting == 0; + + m_lock.unlock(); + + m_condition.notify_all(); + + if( noOneWaits ) + return true; + return false; +} + +// ================================ // +// +bool WaitingAsset::Compare ( const filesystem::Path& filePath ) +{ + return m_fileName == filePath; +} + + +//====================================================================================// +// LoadBarrier +//====================================================================================// + +// ================================ // +// +LoadBarrier::~LoadBarrier() +{ + for( auto& asset : m_waitingAssets ) + delete asset; +} + +// ================================ // +// +std::pair< WaitingAsset*, bool > LoadBarrier::RequestAsset ( const filesystem::Path& filePath ) +{ + std::unique_lock< std::mutex > lock( m_lock ); + + WaitingAsset* assetWait = nullptr; + for( auto asset : m_waitingAssets ) + { + if( asset->Compare( filePath ) ) + { + assert( assetWait == nullptr ); // Should be only one file in waiting vector. + assetWait = asset; + } + } + + if( assetWait ) + { + assetWait->RequestAsset(); + return std::make_pair< WaitingAsset*, bool >( std::move( assetWait ), true ); + } + else + { + auto iter = m_waitingAssets.insert( m_waitingAssets.end(), new WaitingAsset( filePath ) ); + return std::make_pair< WaitingAsset*, bool >( std::move( *iter ), false ); + } +} + +// ================================ // +// +ReturnResult LoadBarrier::WaitUntilLoaded ( WaitingAsset* asset ) +{ + bool isLast = asset->WaitUntilLoaded(); + auto error = asset->GetError(); + + if( isLast ) + { + std::unique_lock< std::mutex > lock( m_lock ); + bool removed = RemoveWaitingAsset( asset ); + + assert( removed ); + } + + if( error != nullptr ) + return error; + else + return Result::Success; +} + +// ================================ // +// +void LoadBarrier::LoadingCompleted ( const filesystem::Path& filePath ) +{ + LoadingFinishedImpl( filePath, nullptr ); +} + +// ================================ // +// +void LoadBarrier::LoadingFailed ( const filesystem::Path& filePath, ExceptionPtr error ) +{ + LoadingFinishedImpl( filePath, error ); +} + +// ================================ // +// +void LoadBarrier::LoadingFinishedImpl( const filesystem::Path& filePath, ExceptionPtr error ) +{ + std::unique_lock< std::mutex > lock( m_lock ); + + WaitingAsset* asset = nullptr; + + for( int i = 0; i < m_waitingAssets.size(); ++i ) + { + if( m_waitingAssets[ i ]->Compare( filePath ) ) + { + asset = m_waitingAssets[ i ]; + break; + } + } + + + if( asset ) + { + bool noOneWaits = asset->LoadingCompleted( error ); // Error can be nullptr and that means that asset was loaded successfully. + + // Remove if there're no waiting threads + if( noOneWaits ) + RemoveWaitingAsset( asset ); + + // In other cases WaitingAsset will be removed when last thread will leave waiting lock. + } +} + +// ================================ // +// +bool LoadBarrier::RemoveWaitingAsset ( WaitingAsset* asset ) +{ + bool removed = false; + for( auto iter = m_waitingAssets.begin(); iter != m_waitingAssets.end(); ++iter ) + { + if( *iter == asset ) + { + delete *iter; + m_waitingAssets.erase( iter ); + removed = true; + break; + } + } + + return removed; +} + +} // sw + diff --git a/ResourceManager/AsyncLoad/LoadBarrier.h b/ResourceManager/AsyncLoad/LoadBarrier.h new file mode 100644 index 0000000..55e3521 --- /dev/null +++ b/ResourceManager/AsyncLoad/LoadBarrier.h @@ -0,0 +1,110 @@ +#pragma once +/** +@file LoadBarrier.h +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + + +#include "swCommonLib/System/Path.h" +#include "swCommonLib/Common/TypesDefinitions.h" +#include "swCommonLib/Common/Exceptions/Exception.h" +#include "swCommonLib/Common/Exceptions/Nullable.h" + +#include +#include +#include + + +namespace sw +{ + +/**@brief Class describing asset waiting for beeing loaded.*/ +class WaitingAsset +{ + friend class LoadBarrier; +private: + + filesystem::Path m_fileName; + std::atomic< uint16 > m_numWaiting; + bool m_ready; + + std::condition_variable m_condition; + std::mutex m_lock; + + ExceptionPtr m_error; + +public: + WaitingAsset () = default; + WaitingAsset ( const filesystem::Path& filePath ); + ~WaitingAsset (); + + +private: + + /**@brief Function blocks until resource will be loaded. + @return Returns true if it was last waiting thread.*/ + bool WaitUntilLoaded (); + + /**@brief Increments loading threads count.*/ + void RequestAsset (); + + /**@brief Notify all threads waiting for this asset. + @return Returns true if it was last waiting thread.*/ + bool LoadingCompleted (); + + /**@brief Notify all threads waiting for this asset. + @return Returns true if it was last waiting thread.*/ + bool LoadingCompleted ( ExceptionPtr error ); + + /**@brief Check if file is during laoding.*/ + bool Compare ( const filesystem::Path& filePath ); + + /**@brief Returns error or nullptr.*/ + ExceptionPtr GetError () const { return m_error; } + +private: + FRIEND_CLASS_TESTER( LoadBarrier ) +}; + + + +/**@brief Class prevents ResourceManager from loading Assets multiple times.*/ +class LoadBarrier +{ +private: + + std::vector< WaitingAsset* > m_waitingAssets; + std::mutex m_lock; + +public: + ~LoadBarrier(); + + /**@brief Tries to access asset described by filePath. If asset exists, function increments waiting threads counter. + Otherwise new WaitingAsset object is created to block future loads. + @return Function returns true if asset already existed. If WaitingAsset was created in this function call function returns true. + Note: WaitingAsset should never be nullptr.*/ + std::pair< WaitingAsset*, bool > RequestAsset ( const filesystem::Path& filePath ); + + /**@brief Function waits until asset will be loaded.*/ + ReturnResult WaitUntilLoaded ( WaitingAsset* asset ); + + /**@brief Notify all threads waiting for this asset.*/ + void LoadingCompleted ( const filesystem::Path& filePath ); + + /**@brief Notify all threads waiting for this asset that loading failed.*/ + void LoadingFailed ( const filesystem::Path& filePath, ExceptionPtr error ); + +private: + + void LoadingFinishedImpl ( const filesystem::Path& filePath, ExceptionPtr error ); + + bool RemoveWaitingAsset ( WaitingAsset* asset ); + +private: + FRIEND_CLASS_TESTER( LoadBarrier ) +}; + + +} // sw + diff --git a/ResourceManager/AsyncLoad/RMAsyncThread.cpp b/ResourceManager/AsyncLoad/RMAsyncThread.cpp new file mode 100644 index 0000000..8af3b06 --- /dev/null +++ b/ResourceManager/AsyncLoad/RMAsyncThread.cpp @@ -0,0 +1,42 @@ +/** +@file RMAsyncThread.cpp +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + +#include "swGraphicAPI/ResourceManager/stdafx.h" + + +#include "RMAsyncThread.h" + + +namespace sw +{ + +// ================================ // +// +RMAsyncThread::RMAsyncThread ( ResourceManager* manager ) + : m_resourceManager( manager ) + , m_assetsThread( manager ) // This will start thread. +{} + +// ================================ // +// +void RMAsyncThread::LoadGenericAsync ( AssetPath assetName, + IAssetLoadInfoPtr desc, + TypeID type, + LoadingSuccessHandler onSuccess, + LoadingFailedHandler onFailed ) +{ + AssetLoadRequest request; + request.AssetPath = std::move( assetName ); + request.AssetType = type; + request.LoadInfo = desc; + request.OnLoaded = onSuccess; + request.OnFailed = onFailed; + + m_assetsThread.QueueRequest( std::move( request ) ); +} + +} // sw + diff --git a/ResourceManager/AsyncLoad/RMAsyncThread.h b/ResourceManager/AsyncLoad/RMAsyncThread.h new file mode 100644 index 0000000..3edbe34 --- /dev/null +++ b/ResourceManager/AsyncLoad/RMAsyncThread.h @@ -0,0 +1,50 @@ +#pragma once +/** +@file RMAsyncThread.h +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + +#include "AssetsThread.h" + + +namespace sw +{ + +class ResourceManager; + + + +/**@brief ResourceManager asynchornous API. + +RMAsyncThread class initializes asynchornous assets loading thread and +exposes api for loading assets. + +@ingroup AsyncLoading*/ +class RMAsyncThread +{ +private: + + ResourceManager* m_resourceManager; + AssetsThread m_assetsThread; + +protected: +public: + explicit RMAsyncThread ( ResourceManager* manager ); + ~RMAsyncThread () = default; + +public: + + /**@brief Asynchronous call to LoadGeneric.*/ + void LoadGenericAsync ( AssetPath assetName, + IAssetLoadInfoPtr desc, + TypeID type, + LoadingSuccessHandler onSuccess, + LoadingFailedHandler onFailed ); + +}; + + +} // sw + + diff --git a/ResourceManager/Cache/CacheManager.cpp b/ResourceManager/Cache/CacheManager.cpp new file mode 100644 index 0000000..de6306c --- /dev/null +++ b/ResourceManager/Cache/CacheManager.cpp @@ -0,0 +1,46 @@ +/** +@file CacheManager.cpp +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + + +#include "swGraphicAPI/ResourceManager/stdafx.h" +#include "CacheManager.h" + + +#include "swGraphicAPI/ResourceManager/Cache/MemoryCache.h" + + +namespace sw +{ + +// ================================ // +// +CacheManager::CacheManager() +{ + InitDefaultCacheHierarchy(); +} + +// ================================ // +// +ResourcePtr< Resource > CacheManager::LoadFromCache ( const AssetPath& assetName, TypeID assetType ) +{ + return ResourcePtr< Resource >(); +} + + +//====================================================================================// +// Internal +//====================================================================================// + +// ================================ // +// +void CacheManager::InitDefaultCacheHierarchy() +{ + m_cacheList = MemoryCacheOPtr( new MemoryCache() ); +} + +} // sw + + diff --git a/ResourceManager/Cache/CacheManager.h b/ResourceManager/Cache/CacheManager.h new file mode 100644 index 0000000..21206d0 --- /dev/null +++ b/ResourceManager/Cache/CacheManager.h @@ -0,0 +1,43 @@ +#pragma once +/** +@file CacheManager.h +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + +#include "IAssetCache.h" + +#include "swGraphicAPI/ResourceManager/PathTranslators/AssetPath.h" + + + +namespace sw +{ + +/**@brief */ +class CacheManager +{ +private: + + IAssetCacheOPtr m_cacheList; ///< Hierarchy of cache objects. + +protected: +public: + explicit CacheManager (); + ~CacheManager () = default; + + /**@brief Loads asset from cache if it exists. Oterwise returns nullptr. + @todo Probably we should pass pointer to resource manager to allow asset creation. + @todo Maybe we could use string as key instead of AssetPath.*/ + ResourcePtr< Resource > LoadFromCache ( const AssetPath& assetName, TypeID assetType ); + +private: + + /**@brief Creates default cache levels.*/ + void InitDefaultCacheHierarchy (); +}; + + + +} // sw + diff --git a/ResourceManager/Cache/IAssetCache.h b/ResourceManager/Cache/IAssetCache.h new file mode 100644 index 0000000..935225a --- /dev/null +++ b/ResourceManager/Cache/IAssetCache.h @@ -0,0 +1,55 @@ +#pragma once +/** +@file IAssetCache.h +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + + +#include "swCommonLib/Common/RTTR.h" +#include "swCommonLib/System/Path.h" + + +/**@defgroup AssetCache Asset Cache +@ingroup AssetsManagement + +@copydoc CachingAssets +*/ + +/**@page CachingAssets Caching Assets + +*/ + + + +namespace sw +{ + +/**@brief Interface for assets cache. + +@todo Change Cache interface and storage. We should store BufferRaw and IAssetCreateInfo +that will be passed to asset creator. + +@ingroup AssetCache*/ +class IAssetCache +{ +private: +protected: +public: + explicit IAssetCache () = default; + virtual ~IAssetCache () = 0 {}; + + + virtual bool AddCacheEntry ( const AssetPath& filePath, TypeID resourceType, MemoryChunk rawData ) = 0; + virtual bool RemoveEntry ( const AssetPath& filePath, TypeID resourceType ) = 0; + + /**@brief Gets raw cache entry. + @todo Solve problem with multithreading. This entry can be released during use.*/ + virtual MemoryChunk& GetEntry ( const AssetPath& filePath, TypeID resourceType ) = 0; + +}; + +DEFINE_OPTR_TYPE( IAssetCache ); + +} // sw + diff --git a/ResourceManager/Cache/MemoryCache.cpp b/ResourceManager/Cache/MemoryCache.cpp new file mode 100644 index 0000000..93252c7 --- /dev/null +++ b/ResourceManager/Cache/MemoryCache.cpp @@ -0,0 +1,37 @@ +/** +@file MemoryCache.cpp +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + +#include "swGraphicAPI/ResourceManager/stdafx.h" +#include "MemoryCache.h" + + + +namespace sw +{ + +// ================================ // +// +bool MemoryCache::AddCacheEntry ( const AssetPath& filePath, TypeID resourceType, MemoryChunk rawData ) +{ + return false; +} + +// ================================ // +// +bool MemoryCache::RemoveEntry ( const AssetPath& filePath, TypeID resourceType ) +{ + return false; +} + +// ================================ // +// +MemoryChunk& MemoryCache::GetEntry ( const AssetPath& filePath, TypeID resourceType ) +{ + // TODO: insert return statement here + return MemoryChunk(); +} + +} // sw \ No newline at end of file diff --git a/ResourceManager/Cache/MemoryCache.h b/ResourceManager/Cache/MemoryCache.h new file mode 100644 index 0000000..53185b9 --- /dev/null +++ b/ResourceManager/Cache/MemoryCache.h @@ -0,0 +1,40 @@ +#pragma once +/** +@file MemoryCache.h +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + +#include "IAssetCache.h" + + + +namespace sw +{ + + +/**@brief RAM cache. + +@ingroup AssetCache*/ +class MemoryCache : public IAssetCache +{ +private: +protected: +public: + explicit MemoryCache () = default; + virtual ~MemoryCache () = default; + + + /**@copydoc IAssetCache::AddCacheEntry*/ + virtual bool AddCacheEntry ( const AssetPath& filePath, TypeID resourceType, MemoryChunk rawData ) override; + /**@copydoc IAssetCache::RemoveEntry*/ + virtual bool RemoveEntry ( const AssetPath& filePath, TypeID resourceType ) override; + /**@copydoc IAssetCache::GetEntry*/ + virtual MemoryChunk& GetEntry ( const AssetPath& filePath, TypeID resourceType ) override; + +}; + +DEFINE_OPTR_TYPE( MemoryCache ); + +} // sw + diff --git a/ResourceManager/Exceptions/LoaderException.cpp b/ResourceManager/Exceptions/LoaderException.cpp new file mode 100644 index 0000000..3456f66 --- /dev/null +++ b/ResourceManager/Exceptions/LoaderException.cpp @@ -0,0 +1,60 @@ +/** +@file LoaderException.cpp +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ +#include "swGraphicAPI/ResourceManager/stdafx.h" + +#include "LoaderException.h" + +#include "swCommonLib/Common/fmt.h" + + + +namespace sw +{ + +// ================================ // +// +LoaderException::LoaderException ( std::string loaderName, std::string error, LoadPath path, TypeID assetType ) + : RuntimeException( std::move( error ) ) + , m_path( std::move( path ) ) + , m_resourceType( assetType ) + , m_loaderName( std::move( loaderName ) ) +{} + +// ================================ // +// +LoaderExceptionPtr LoaderException::Create ( std::string loaderName, std::string error, LoadPath path, TypeID assetType ) +{ + return std::make_shared< LoaderException >( std::move( loaderName ), std::move( error ), std::move( path ), assetType ); +} + + +// ================================ // +// +std::string LoaderException::ErrorMessage () const +{ + return LoaderHeader() + + RuntimeException::ErrorMessage() + + ResourceInfo(); +} + +// ================================ // +// +std::string LoaderException::LoaderHeader () const +{ + return fmt::format( "[{}] ", m_loaderName ); +} + +// ================================ // +// +std::string LoaderException::ResourceInfo () const +{ + return fmt::format( " {}, type [{}].", m_path, m_resourceType ); +} + + + + +} // sw diff --git a/ResourceManager/Exceptions/LoaderException.h b/ResourceManager/Exceptions/LoaderException.h new file mode 100644 index 0000000..6f5f408 --- /dev/null +++ b/ResourceManager/Exceptions/LoaderException.h @@ -0,0 +1,57 @@ +#pragma once +/** +@file LoaderException.h +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + + +#include "swCommonLib/Common/Exceptions/Exception.h" +#include "swCommonLib/Common/RTTR.h" +#include "swCommonLib/System/Path.h" + +#include "swGraphicAPI/ResourceManager/PathTranslators/AssetPath.h" +#include "swGraphicAPI/ResourceManager/PathTranslators/LoadPath.h" + + +namespace sw +{ + +class LoaderException; +DEFINE_PTR_TYPE( LoaderException ); + + +/**@brief Base exception for Loaders error. +@ingroup Loaders*/ +class LoaderException : public RuntimeException +{ + RTTR_ENABLE( RuntimeException ); +private: +protected: + + LoadPath m_path; + TypeID m_resourceType; + std::string m_loaderName; + +public: + explicit LoaderException ( std::string loaderName, std::string error, LoadPath path, TypeID assetType ); + virtual ~LoaderException () = default; + + std::string ErrorMessage () const override; + +private: + + std::string LoaderHeader () const; + std::string ResourceInfo () const; + +public: + + static LoaderExceptionPtr Create ( std::string loaderName, std::string error, LoadPath path, TypeID assetType ); +}; + + +} // sw + + + + diff --git a/ResourceManager/Exceptions/ResourceManagerException.cpp b/ResourceManager/Exceptions/ResourceManagerException.cpp new file mode 100644 index 0000000..29c25d7 --- /dev/null +++ b/ResourceManager/Exceptions/ResourceManagerException.cpp @@ -0,0 +1,49 @@ +/** +@file ResourceManagerException.cpp +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ +#include "swGraphicAPI/ResourceManager/stdafx.h" + +#include "ResourceManagerException.h" + + + + +namespace sw +{ + +// ================================ // +// +ResourceManagerException::ResourceManagerException ( const std::string& error, const filesystem::Path& name, TypeID assetType ) + : RuntimeException( error ) + , m_resourceName( name ) + , m_resourceType( assetType ) +{} + + +// ================================ // +// +std::string ResourceManagerException::ErrorMessage () const +{ + return ResourceManagerHeader() + + RuntimeException::ErrorMessage() + + ResourceInfo(); +} + +// ================================ // +// +std::string ResourceManagerException::ResourceManagerHeader () const +{ + return "[ResourceManager] "; +} + +// ================================ // +// +std::string ResourceManagerException::ResourceInfo () const +{ + return " Name [" + m_resourceName.String() + "], type [" + m_resourceType.get_name().to_string() + "]."; +} + + +} // sw diff --git a/ResourceManager/Exceptions/ResourceManagerException.h b/ResourceManager/Exceptions/ResourceManagerException.h new file mode 100644 index 0000000..81301bf --- /dev/null +++ b/ResourceManager/Exceptions/ResourceManagerException.h @@ -0,0 +1,42 @@ +#pragma once +/** +@file ResourceManagerException.h +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + + +#include "swCommonLib/Common/Exceptions/Exception.h" +#include "swCommonLib/Common/RTTR.h" +#include "swCommonLib/System/Path.h" + + +namespace sw +{ + +/**@brief Exceptions tells that two types cannot be bound.*/ +class ResourceManagerException : public RuntimeException +{ + RTTR_ENABLE( RuntimeException ); +private: +protected: + + filesystem::Path m_resourceName; + TypeID m_resourceType; + +public: + explicit ResourceManagerException ( const std::string& error, const filesystem::Path& name, TypeID assetType ); + virtual ~ResourceManagerException () = default; + + std::string ErrorMessage () const override; + +private: + + std::string ResourceManagerHeader () const; + std::string ResourceInfo () const; +}; + + +} // sw + + diff --git a/ResourceManager/Loaders/IAssetLoadInfo.h b/ResourceManager/Loaders/IAssetLoadInfo.h new file mode 100644 index 0000000..d4edff4 --- /dev/null +++ b/ResourceManager/Loaders/IAssetLoadInfo.h @@ -0,0 +1,38 @@ +#pragma once +/** +@file IAssetLoadInfo.h +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + +#include "swCommonLib/Common/RTTR.h" +#include "swCommonLib/Common/TypesDefinitions.h" + +namespace sw +{ + + +/**@brief Interface of asset descriptor used to load asset. + +@ingroup Loaders*/ +class IAssetLoadInfo +{ + RTTR_ENABLE(); +private: +protected: +public: + explicit IAssetLoadInfo () = default; + virtual ~IAssetLoadInfo () = 0 {} + + +public: + + virtual TypeID GetAssetType () const = 0; + +}; + +DEFINE_OPTR_TYPE( IAssetLoadInfo ); +DEFINE_PTR_TYPE( IAssetLoadInfo ); + + +} // sw diff --git a/ResourceManager/Loaders/IAssetLoader.h b/ResourceManager/Loaders/IAssetLoader.h new file mode 100644 index 0000000..d26a275 --- /dev/null +++ b/ResourceManager/Loaders/IAssetLoader.h @@ -0,0 +1,117 @@ +#pragma once +/** +@file IAssetLoader.h +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + + +#include "swCommonLib/Common/RTTR.h" +#include "swCommonLib/System/Path.h" + +#include "swGraphicAPI/Resources/ResourcePtr.h" +#include "swGraphicAPI/Resources/ResourceObject.h" + +#include "swGraphicAPI/ResourceManager/Loaders/IAssetLoadInfo.h" +#include "swGraphicAPI/ResourceManager/Loaders/LoadingResult.h" +#include "swGraphicAPI/ResourceManager/Loaders/RMLoaderAPI.h" +#include "swGraphicAPI/ResourceManager/PathTranslators/AssetPath.h" +#include "swGraphicAPI/ResourceManager/PathTranslators/LoadPath.h" + +#include + + +namespace sw +{ + + +/**@defgroup Loaders +@brief Classes for loading resources from different files formats. +@ingroup AssetsManagement + +@copydoc WritingLoaders +*/ + +/**@page WritingLoaders Developing loaders +@tableofcontents + +@section LoadersOverview Loaders Overview + +Loaders are abstraction layer between different file formats and Assets used in engine. +When @ref ResourceManager gets request to load asset, it finds proper loader and passes this task to it. + +Since @ref ResourceManager supports asynchronous loading, Loader shouldn't depend on some static internal state, while loading data. + +@section InheritingIAssetLoader Inheriting IAssetLoader + +To write your own file loader you should implement @ref IAssetLoader interface. + +@subsection CanLoadFunction CanLoad function + +@copydoc IAssetLoader::CanLoad + +@subsection LoadFunction Load function + +@copydoc IAssetLoader::Load +*/ + + + + +/**@brief Base class for resource and assets loaders. +@ingroup Loaders*/ +class IAssetLoader +{ +private: +protected: +public: + explicit IAssetLoader () = default; + virtual ~IAssetLoader () = 0 {} + + + /**@brief Override this function. It checks if this loader can load specified file. + + Override this function checks if this loader can load specified file. + @param[in] filePath + From file path argument this function should check only file extension. There's no deep check needed, since this function will be called + multiple times while searching for loaders and this could hurt performance. + + @param[in] resourceType Different files can contain multiple assets of multiple types. You should check this argument and confirm, that this asset + type is supported by this loader.*/ + virtual bool CanLoad ( const AssetPath& filePath, TypeID resourceType ) = 0; + + /**@brief Function loads asset. + + Function for loading assets. Loader should create all assets internally, by using RMLoaderAPI from parameter. + RMLoaderAPI adds all created assets to ResourceManager. + + Frequently asset Loader must create multiple nested assets before creating main asset. All these assets should be placed + in result vector. Main asset should take 0 index of this vector and should have the same name as passed in filePath parameter and type + described by resourceType. + This is important when someone wants to load for example mesh and provides file path to ResourceManager. After asset is loaded, someone must + choose which from asset vector is desired mesh (one file can have multiple meshes). If it's not explicitly specified after :: in file path parameter, + it's up to Loader implementation to decide, which asset is the most important and give him the same name as whole file. + + @note There's nothing bad when multiple resources have the same name (for example name of file, from which they were created), + as long as they have different types. + + @param[in] filePath Path to asset file. Note that this path can contain after :: name of asset. Implementation should choose this asset as main asset. + @param[in] resourceType Type of asset to load. Each loader can load multiple assets type, because loader is connected rather to file type + then to asset. + @param[in] assetDesc Asset descriptor has all info needed to create and process asset internally. + @param[in] factory Pointer to interface for creating assets. + */ + virtual LoadingResult Load ( const LoadPath& filePath, TypeID resourceType, const IAssetLoadInfo* assetDesc, RMLoaderAPI factory ) = 0; + + /**@brief Function used to prefetch and cache asset. + + Loader shouldn't create this asset. Instead it should call asset creation functiond from asset manager with + flag indicating, that it should be cached. Note that this should apply to all nested assets too.*/ + virtual ReturnResult Prefetch ( const LoadPath& filePath, TypeID resourceType, const IAssetLoadInfo* assetDesc, RMLoaderAPI factory ) = 0; +}; + +DEFINE_PTR_TYPE( IAssetLoader ); + + +} // sw + diff --git a/ResourceManager/Loaders/LoadingResult.h b/ResourceManager/Loaders/LoadingResult.h new file mode 100644 index 0000000..03bf8e4 --- /dev/null +++ b/ResourceManager/Loaders/LoadingResult.h @@ -0,0 +1,98 @@ +#pragma once +/** +@file LoadingResult.h +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + + +#include "swGraphicAPI/Resources/ResourceObject.h" +#include "swGraphicAPI/Resources/ResourcePtr.h" + +#include "swCommonLib/Common/Exceptions/Exception.h" +#include "swCommonLib/Common/Exceptions/ErrorsCollector.h" + +#include + + +namespace sw +{ + +typedef std::vector< ResourcePointer > AssetsVec; + + + +/**@brief Structure returned by loader. +@ingroup Loaders*/ +struct LoadingResult +{ + Nullable< AssetsVec > Assets; ///< Contains all assets loaded in @ref Load call or errors in case of fail. + ExceptionPtr Warnings; ///< Contains all warining that occured during loading. + +public: + + LoadingResult () = default; + LoadingResult ( ResourcePointer resource ); + LoadingResult ( std::string error ); + LoadingResult ( ExceptionPtr error ); + LoadingResult ( std::string error, ExceptionPtr warnings ); + LoadingResult ( ExceptionPtr error, ExceptionPtr warnings ); + LoadingResult ( AssetsVec assets, ExceptionPtr warnings ); + LoadingResult ( ExceptionPtr error, const ErrorsCollector& warnings ); + +}; + +//====================================================================================// +// Implementation +//====================================================================================// + + +// ================================ // +// +inline LoadingResult::LoadingResult ( ResourcePointer resource ) + : Assets( AssetsVec( { resource } ) ) +{} + +// ================================ // +// +inline LoadingResult::LoadingResult ( std::string error ) + : Assets( Nullable< AssetsVec >( error ) ) +{} + +// ================================ // +// +inline LoadingResult::LoadingResult ( ExceptionPtr error ) + : Assets( Nullable< AssetsVec >( error ) ) +{} + +// ================================ // +// +inline LoadingResult::LoadingResult ( ExceptionPtr error, ExceptionPtr warnings ) + : Assets( Nullable< AssetsVec >( error ) ) + , Warnings( warnings ) +{} + +// ================================ // +// +inline LoadingResult::LoadingResult ( std::string error, ExceptionPtr warnings ) + : Assets( Nullable< AssetsVec >( error ) ) + , Warnings( warnings ) +{} + +// ================================ // +// +inline LoadingResult::LoadingResult ( AssetsVec assets, ExceptionPtr warnings ) + : Assets( std::move( assets ) ) + , Warnings( warnings ) +{} + +// ================================ // +// +inline LoadingResult::LoadingResult ( ExceptionPtr error, const ErrorsCollector& warnings ) + : Assets( Nullable< AssetsVec >( error ) ) + , Warnings( warnings.GetException() ) +{} + +} // sw + + diff --git a/ResourceManager/Loaders/RMLoaderAPI.h b/ResourceManager/Loaders/RMLoaderAPI.h new file mode 100644 index 0000000..12a3b18 --- /dev/null +++ b/ResourceManager/Loaders/RMLoaderAPI.h @@ -0,0 +1,73 @@ +#pragma once +/** +@file RMLoaderAPI.h +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + + +#include "swGraphicAPI/ResourceManager/Loaders/IAssetLoadInfo.h" +#include "swGraphicAPI/ResourceManager/AssetCreators/IAssetCreateInfo.h" + +#include "swGraphicAPI/ResourceManager/ResourceManagerAPI.h" + + +namespace sw +{ + + +class ResourceManager; + + + +/**@brief ResourceManager API for @ref Loaders internal usage. + +Loaders should use only synchronous functions. This API gives acces only +to those functions that won't cause deadlocks. + +@todo Consider adding path of loaded asset to constructor. This way we could block +loading, that could cause deadlocks. (For example: Someone calls LoadGeneric on asset +that resides in file that is currenly loaded by loader). + +@ingroup Loaders*/ +class RMLoaderAPI : protected ResourceManagerAPI +{ +protected: +public: + + explicit RMLoaderAPI ( ResourceManager* manager ) + : ResourceManagerAPI( manager ) + {} + + ~RMLoaderAPI () = default; + +public: + + using ResourceManagerAPI::GetGeneric; + using ResourceManagerAPI::GetCachedGeneric; + using ResourceManagerAPI::LoadGeneric; + using ResourceManagerAPI::Load; + using ResourceManagerAPI::GetCached; + using ResourceManagerAPI::CreateGenericAsset; + using ResourceManagerAPI::CreateAsset; + + using ResourceManagerAPI::LoadTexture; + + using ResourceManagerAPI::CreateConstantsBuffer; + + using ResourceManagerAPI::LoadVertexShader; + using ResourceManagerAPI::LoadPixelShader; + using ResourceManagerAPI::LoadGeometryShader; + using ResourceManagerAPI::LoadControlShader; + using ResourceManagerAPI::LoadEvaluationShader; + using ResourceManagerAPI::LoadComputeShader; + using ResourceManagerAPI::LoadShader; + +}; + + + +} // sw + + + diff --git a/ResourceManager/Loaders/RenderTargetLoadInfo.h b/ResourceManager/Loaders/RenderTargetLoadInfo.h new file mode 100644 index 0000000..466aa7e --- /dev/null +++ b/ResourceManager/Loaders/RenderTargetLoadInfo.h @@ -0,0 +1,63 @@ +#pragma once +/** +@file RenderTargetLoadInfo.h +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + + + +#include "swGraphicAPI/ResourceManager/Loaders/IAssetLoader.h" + +#include "swGraphicAPI/Resources/Textures/RenderTarget.h" +#include "swGraphicAPI/Resources/SwapChain.h" + + +namespace sw +{ + + +/**@brief Check @ref RenderTargetDescriptor*/ +struct RenderTargetLoadInfo : public IAssetLoadInfo, public RenderTargetDescriptor +{ + RTTR_ENABLE( IAssetLoadInfo ) +public: + + // ================================ // + // + TypeID GetAssetType () const + { + return TypeID::get< RenderTarget >(); + } + + // ================================ // + // + RenderTargetDescriptor ToDescriptor () const + { + RenderTargetDescriptor descriptor = *this; + return descriptor; + } +}; + +/**@brief Create RenderTarget from existing SwapChain. +@attention Use only in synchronous api.*/ +struct RenderTargetFromSwapChain : public IAssetLoadInfo +{ + RTTR_ENABLE( IAssetLoadInfo ) +public: + + SwapChain* Chain; ///< @todo This can be unsafe is someone releases SwapChain. + +public: + // ================================ // + // + TypeID GetAssetType () const + { + return TypeID::get< RenderTarget >(); + } +}; + + +} // sw + + diff --git a/ResourceManager/Loaders/RenderTargetLoader.cpp b/ResourceManager/Loaders/RenderTargetLoader.cpp new file mode 100644 index 0000000..d1acd21 --- /dev/null +++ b/ResourceManager/Loaders/RenderTargetLoader.cpp @@ -0,0 +1,116 @@ +/** +@file RenderTargetLoader.cpp +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + +#include "swGraphicAPI/ResourceManager/stdafx.h" + +#include "RenderTargetLoader.h" + +#include "swGraphicAPI/Resources/Textures/RenderTarget.h" +#include "swGraphicAPI/Resources/Textures/Texture.h" +#include "swGraphicAPI/ResourceManager/AssetCreators/Textures/TextureCreator.h" +#include "swGraphicAPI/ResourceManager/AssetCreators/Textures/RenderTargetCreator.h" + +#include "swGraphicAPI/ResourceManager/Loaders/Tools/LoadingContext.h" + + + +namespace sw +{ + +// ================================ // +// +bool RenderTargetLoader::CanLoad ( const AssetPath& filePath, TypeID resourceType ) +{ + if( TypeID::get< RenderTarget >() != resourceType ) + return false; + + return true; +} + +// ================================ // +// +void AddTextureIfNotNull ( TexturePtr tex, LoadingContext& context ) +{ + if( tex ) + { + TextureExistingInitInfo info; + info.Tex = tex; + + auto result = context.Factory.CreateGenericAsset( tex->GetAssetPath(), TypeID::get< Texture >(), std::move( info ) ); + if( context.Warnings.Success( result ) ) + context.AssetsCollection.push_back( result.Get() ); + } +} + + +// ================================ // +// +LoadingResult RenderTargetLoader::Load ( const LoadPath& filePath, TypeID resourceType, const IAssetLoadInfo* assetDesc, RMLoaderAPI factory ) +{ + RenderTargetPtr rt = nullptr; + + if( assetDesc->get_type() == TypeID::get< RenderTargetLoadInfo >() ) + { + // Translate load info to descriptor used in creators. + const RenderTargetLoadInfo* loadInfo = static_cast< const RenderTargetLoadInfo* >( assetDesc ); + + auto resourceNullable = factory.CreateAsset< RenderTarget >( filePath.GetOriginalPath(), loadInfo->ToDescriptor() ); + + // Creation failed. + if( !resourceNullable.IsValid() ) + return { resourceNullable.GetError() }; + + rt = resourceNullable.Get(); + } + else if( assetDesc->get_type() == TypeID::get< RenderTargetFromSwapChain >() ) + { + const auto* loadInfo = static_cast< const RenderTargetFromSwapChain* >( assetDesc ); + + RenderTargetExistingInitInfo init; + init.RT = loadInfo->Chain->GetRenderTarget(); + + auto resourceNullable = factory.CreateAsset< RenderTarget >( filePath.GetOriginalPath(), std::move( init ) ); + + // Creation failed. + if( !resourceNullable.IsValid() ) + return { resourceNullable.GetError() }; + + rt = resourceNullable.Get(); + } + else + { + return { fmt::format( "Unsupported descriptor type [{}].", assetDesc->get_type() ) }; + } + + // Add associated textures to ResourceManager. + TexturePtr color = rt->GetColorBuffer(); + TexturePtr depth = rt->GetDepthBuffer(); + TexturePtr stencil = rt->GetStencilBuffer(); + + ErrorsCollector warnings; + LoadingContext context( factory ); + + context.CollectAsset( rt ); + + AddTextureIfNotNull( color, context ); + AddTextureIfNotNull( depth, context ); + AddTextureIfNotNull( stencil, context ); + + return { std::move( context.AssetsCollection ), context.Warnings.GetException() }; +} + +// ================================ // +// +ReturnResult RenderTargetLoader::Prefetch ( const LoadPath& filePath, TypeID resourceType, const IAssetLoadInfo* assetDesc, RMLoaderAPI factory ) +{ + return Result::Error; +} + + + +} // sw + + diff --git a/ResourceManager/Loaders/RenderTargetLoader.h b/ResourceManager/Loaders/RenderTargetLoader.h new file mode 100644 index 0000000..5f62e42 --- /dev/null +++ b/ResourceManager/Loaders/RenderTargetLoader.h @@ -0,0 +1,45 @@ +#pragma once +/** +@file RenderTargetLoader.h +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + + +#include "swGraphicAPI/ResourceManager/Loaders/IAssetLoader.h" +#include "swGraphicAPI/ResourceManager/Loaders/RenderTargetLoadInfo.h" + +#include "swGraphicAPI/Resources/Textures/RenderTarget.h" +#include "swGraphicAPI/Resources/SwapChain.h" + + +namespace sw +{ + + + + +/**@brief Creates RenderTarget. + +Render Target has internal textures which have to be added to ResourceManager. +We need this loader to add them, because asset creators don't have access to ResourceManager.*/ +class RenderTargetLoader : public IAssetLoader +{ +private: +protected: +public: + explicit RenderTargetLoader () = default; + virtual ~RenderTargetLoader () = default; + + + virtual bool CanLoad ( const AssetPath& filePath, TypeID resourceType ) override; + virtual LoadingResult Load ( const LoadPath& filePath, TypeID resourceType, const IAssetLoadInfo* assetDesc, RMLoaderAPI factory ) override; + virtual ReturnResult Prefetch ( const LoadPath& filePath, TypeID resourceType, const IAssetLoadInfo* assetDesc, RMLoaderAPI factory ) override; + +}; + + + + +} // sw + diff --git a/ResourceManager/Loaders/ShaderLoader.cpp b/ResourceManager/Loaders/ShaderLoader.cpp new file mode 100644 index 0000000..d403a50 --- /dev/null +++ b/ResourceManager/Loaders/ShaderLoader.cpp @@ -0,0 +1,98 @@ +/** +@file ShaderLoader.cpp +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + +#include "swGraphicAPI/ResourceManager/stdafx.h" + +#include "ShaderLoader.h" + +#include "swGraphicAPI/Resources/Shaders/Shaders.h" +#include "swGraphicAPI/Resources/Shaders/ShaderInitData.h" + +#include "swCommonLib/Common/Exceptions/Common/FileNotFoundException.h" +#include "swCommonLib/System/File.h" + +#include + + +namespace sw +{ + +// ================================ // +// +bool ShaderLoader::CanLoad ( const AssetPath& filePath, TypeID resourceType ) +{ + std::string allowedExtensions[] = + { + ".vert", + ".tesc", + ".tese", + ".geom", + ".frag", + ".comp", + + ".vsh", + ".psh", + ".gsh", + ".csh" + }; + + auto extension = filePath.GetFile().GetExtension(); + + if( std::find( std::begin( allowedExtensions ), std::end( allowedExtensions ), extension ) == std::end( allowedExtensions ) ) + return false; + + TypeID allowedTypes[] = + { + TypeID::get< VertexShader >(), + TypeID::get< PixelShader >(), + TypeID::get< GeometryShader >(), + TypeID::get< ControlShader >(), + TypeID::get< EvaluationShader >(), + TypeID::get< ComputeShader >(), + // Note that we don't support loading of all shaders from file, because we can't find out + // all symbols that can be treated as entrypoint to shader. + // TypeID::get< Resource >(), + }; + + if( std::find( std::begin( allowedTypes ), std::end( allowedTypes ), resourceType ) == std::end( allowedTypes ) ) + return false; + + return true; +} + +// ================================ // +// +LoadingResult ShaderLoader::Load ( const LoadPath& filePath, TypeID resourceType, const IAssetLoadInfo* assetDesc, RMLoaderAPI factory ) +{ + if( filePath.GetFile().Exists() ) + { + std::string fileContent = filesystem::File::Load( filePath.GetFile() ); + + ShaderCodeInitData init( ShaderInitData::GetFromTypeID( resourceType ), std::move( fileContent ) ); + + // We don't use GetCachedGeneric here because it's not nested asset and ResourceManager + // checks cache first. + auto resourceNullable = factory.CreateGenericAsset( filePath.GetOriginalPath(), resourceType, std::move( init ) ); + if( resourceNullable.IsValid() ) + return { resourceNullable.Get() }; + else + return { resourceNullable.GetError() }; + } + else + { + return { std::make_shared< FileNotFoundException >( filePath.GetFile() ) }; + } +} + +// ================================ // +// +ReturnResult ShaderLoader::Prefetch ( const LoadPath& filePath, TypeID resourceType, const IAssetLoadInfo* assetDesc, RMLoaderAPI factory ) +{ + return Result::Error; +} + +} // sw + diff --git a/ResourceManager/Loaders/ShaderLoader.h b/ResourceManager/Loaders/ShaderLoader.h new file mode 100644 index 0000000..ab80496 --- /dev/null +++ b/ResourceManager/Loaders/ShaderLoader.h @@ -0,0 +1,36 @@ +#pragma once +/** +@file ShaderLoader.h +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + +#include "swGraphicAPI/ResourceManager/Loaders/IAssetLoader.h" + + +namespace sw +{ + +/**@brief Loads shader from file. + +This class only loads content of file. There's nothing magical or interesting here. +@ingroup Loaders*/ +class ShaderLoader : public IAssetLoader +{ +private: +protected: +public: + explicit ShaderLoader () = default; + virtual ~ShaderLoader () = default; + + + virtual bool CanLoad ( const AssetPath& filePath, TypeID resourceType ) override; + virtual LoadingResult Load ( const LoadPath& filePath, TypeID resourceType, const IAssetLoadInfo* assetDesc, RMLoaderAPI factory ) override; + virtual ReturnResult Prefetch ( const LoadPath& filePath, TypeID resourceType, const IAssetLoadInfo* assetDesc, RMLoaderAPI factory ) override; + +}; + + + +} // sw + diff --git a/ResourceManager/Loaders/TextureLoadInfo.h b/ResourceManager/Loaders/TextureLoadInfo.h new file mode 100644 index 0000000..b19ae9f --- /dev/null +++ b/ResourceManager/Loaders/TextureLoadInfo.h @@ -0,0 +1,69 @@ +#pragma once +/** +@file TextureLoadInfo.h +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + + +#include "swGraphicAPI/ResourceManager/Loaders/IAssetLoadInfo.h" +#include "swGraphicAPI/Resources/Textures/TextureInitData.h" + + +namespace sw +{ + +/**@defgroup TexturesLoaders Textures Loaders +@ingroup Loaders*/ + + + + +/**@brief Describes how Loader should process source texture data. +@ingroup TexturesLoaders*/ +struct TextureProcessingInfo +{ + bool ForceFormat; ///< Loader should generate texture in TargetFormat no matter what it loaded. + ResourceFormat TargetFormat; + + + // ================================ // + // + TextureProcessingInfo() + : ForceFormat( false ) + , TargetFormat( ResourceFormat::RESOURCE_FORMAT_UNKNOWN ) + {} +}; + + + + +/**@brief Descriptor informs loader how to load Texture. +@ingroup TexturesLoaders*/ +class TextureLoadInfo : public IAssetLoadInfo +{ + RTTR_ENABLE( IAssetLoadInfo ); +public: + + MipMapsInfo MipMaps; + TextureUsageInfo TextureUsage; + TextureProcessingInfo Processing; + +public: + explicit TextureLoadInfo () = default; + virtual ~TextureLoadInfo () = default; + +public: + + + virtual TypeID GetAssetType () const { return TypeID::get< Texture >(); } + +}; + + + + +} // sw + + + diff --git a/ResourceManager/Loaders/Tools/CanLoad.h b/ResourceManager/Loaders/Tools/CanLoad.h new file mode 100644 index 0000000..3370011 --- /dev/null +++ b/ResourceManager/Loaders/Tools/CanLoad.h @@ -0,0 +1,62 @@ +#pragma once +/** +@file CanLoad.h +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + +#include +#include + +#include "swCommonLib/Common/RTTR.h" +#include "swGraphicAPI/ResourceManager/PathTranslators/AssetPath.h" + + + + +namespace sw +{ + +// ================================ // +// +template< size_t N > +bool CanLoadExtension ( const AssetPath& filePath, std::string (&allowedExtensions)[ N ] ) +{ + // Get extension in lowercase. Note that we deal with multibytes character and something can be wrong with this. + auto extension = filePath.GetFile().GetExtension(); + std::transform( extension.begin(), extension.end(), extension.begin(), ::tolower ); + + if( std::find( std::begin( allowedExtensions ), std::end( allowedExtensions ), extension ) == std::end( allowedExtensions ) ) + return false; + + return true; +} + +// ================================ // +// +template< size_t N > +bool CanLoadType ( TypeID resourceType, TypeID (&allowedTypes)[ N ] ) +{ + if( std::find( std::begin( allowedTypes ), std::end( allowedTypes ), resourceType ) == std::end( allowedTypes ) ) + return false; + + return true; +} + +// ================================ // +// +template< size_t N, size_t M > +bool DefaultCanLoad ( const AssetPath& filePath, TypeID resourceType, std::string (&allowedExtensions)[ N ], TypeID (&allowedTypes)[ M ] ) +{ + if( !CanLoadExtension( filePath, allowedExtensions ) ) + return false; + + if( !CanLoadType( resourceType, allowedTypes ) ) + return false; + + return true; +} + + +} // sw + diff --git a/ResourceManager/Loaders/Tools/LoadingContext.h b/ResourceManager/Loaders/Tools/LoadingContext.h new file mode 100644 index 0000000..b73bba5 --- /dev/null +++ b/ResourceManager/Loaders/Tools/LoadingContext.h @@ -0,0 +1,99 @@ +#pragma once +/** +@file LoadingContext.h +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + +#include "swGraphicAPI/ResourceManager/Loaders/IAssetLoader.h" +#include "swGraphicAPI/ResourceManager/Loaders/IAssetLoadInfo.h" +#include "swGraphicAPI/ResourceManager/Loaders/LoadingResult.h" + +#include "swCommonLib/Common/Exceptions/ErrorsCollector.h" +#include "swCommonLib/Common/Exceptions/Common/InvalidCodeLogicException.h" + + + +namespace sw +{ + + +/**@brief Helper class which can be used to pass useful parameters to functions. + +Note that IAssetLoader can't store variables in class members, since there's +only one loader per application that can be used by multiple threads. +This class helps to pass parameters to loading functions. + +@ingroup Loaders*/ +class LoadingContext +{ +public: + + RMLoaderAPI Factory; + ErrorsCollector Warnings; + AssetsVec AssetsCollection; + +protected: +public: + explicit LoadingContext ( RMLoaderAPI rm ); + ~LoadingContext () = default; + +public: + + template< typename AssetType > + void CollectAsset ( ResourcePtr< AssetType > asset ); + + /**@brief Collects asset if Nullable isn't exception. + @return Returns true if asset was valid, false if it was exception.*/ + template< typename AssetType > + bool CollectAssetOrWarn ( const Nullable< ResourcePtr< AssetType > >& asset ); + +}; + + +//====================================================================================// +// Implementation +//====================================================================================// + +// ================================ // +// +inline LoadingContext::LoadingContext ( RMLoaderAPI rm ) + : Factory( rm ) +{} + + +// ================================ // +// +template< typename AssetType > +inline void LoadingContext::CollectAsset ( ResourcePtr< AssetType > asset ) +{ + AssetsCollection.push_back( asset.Ptr() ); +} + +// ================================ // +// +template< typename AssetType > +inline bool LoadingContext::CollectAssetOrWarn ( const Nullable< ResourcePtr< AssetType > >& asset ) +{ + if( Warnings.Success( asset ) ) + { + // Sanity check. + if( asset.Get() == nullptr ) + { + std::string message = "Asset returned in Nullable shouldn't be nullptr. Asset type: [" + Convert::ToString< AssetType >() + "]."; + Warnings.Add( InvalidCodeLogicException::Create( std::move( message ), __FILE__, __LINE__ ) ); + + return false; + } + + AssetsCollection.push_back( asset.Get().Ptr() ); + return true; + } + + return false; +} + +} // sw + + + diff --git a/ResourceManager/PathTranslators/AssetPath.cpp b/ResourceManager/PathTranslators/AssetPath.cpp new file mode 100644 index 0000000..13e70f5 --- /dev/null +++ b/ResourceManager/PathTranslators/AssetPath.cpp @@ -0,0 +1,42 @@ +/** +@file AssetPath.cpp +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ +#include "swGraphicAPI/ResourceManager/stdafx.h" + + +#include "swCommonLib/Common/Exceptions/Exception.h" +#include "AssetPath.h" + +#include + + +namespace sw +{ + + +namespace impl +{ + std::regex sAssetPathRegex( "^(.*?)(?:::(.*))?$" ); +} + + +// ================================ // +// +Nullable< AssetPath > AssetPath::FromString ( const std::string& assetPath ) +{ + std::smatch match; + + if( std::regex_match( assetPath, match, impl::sAssetPathRegex ) ) + { + // Ignore first match, it represents full match, that is full string. + return AssetPath( match[ 1 ], match[ 2 ] ); + } + + return std::make_shared< RuntimeException >( "String can't be converted to AssetPath." ); +} + + +} // sw + diff --git a/ResourceManager/PathTranslators/AssetPath.h b/ResourceManager/PathTranslators/AssetPath.h new file mode 100644 index 0000000..bdc546e --- /dev/null +++ b/ResourceManager/PathTranslators/AssetPath.h @@ -0,0 +1,165 @@ +#pragma once +/** +@file AssetPath.h +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + +#include "swCommonLib/System/Path.h" +#include "swCommonLib/Common/Exceptions/Nullable.h" + +#include + + +namespace sw +{ + + +/**@brief Represents asset path. + +Asset path consists of two parts: +- file path - which is normal path to file on user filesystem +- internal path - which points to specific asset inside file + +Each file can contain multiple assets, for example mesh file contains vertex and index +buffers and materials. To load asset and assing it to enitity someone must provide it's full path. +Internal path can mean different things in different assets. +- It can be asset name inside file as in our example materials need to have different names, so +we can distinguish between them +- Sometimes file could contain scene represented as tree and scene elements would have names after +their position in tree. +- Files can have their internal filesystem.*/ +class AssetPath +{ +private: + + filesystem::Path m_filePath; ///< Path in filesystem. + filesystem::Path m_internalPath; ///< Internal path in asset file or simply asset name. + +protected: +public: + + explicit AssetPath () = default; + explicit AssetPath ( filesystem::Path file, filesystem::Path internalPath ); + AssetPath ( const std::string& assetPath ); + AssetPath ( const char* assetPath ); + + ~AssetPath () = default; + +public: + + const filesystem::Path& GetFile () const { return m_filePath; } + const filesystem::Path& GetInternalPath () const { return m_internalPath; } + + std::string String () const; + +public: + + bool operator== ( const AssetPath& other ) const; + bool operator!= ( const AssetPath& other ) const; + bool operator< ( const AssetPath& other ) const; + bool operator<= ( const AssetPath& other ) const; + bool operator> ( const AssetPath& other ) const; + bool operator>= ( const AssetPath& other ) const; + +public: + + static Nullable< AssetPath > FromString ( const std::string& assetPath ); +}; + +} // sw + +DEFINE_FMT_FORMATTER( sw::AssetPath, "{}::{}", GetFile(), GetInternalPath() ); + + + +namespace sw +{ + +//====================================================================================// +// Implementation +//====================================================================================// + + +// ================================ // +// +inline AssetPath::AssetPath ( filesystem::Path file, filesystem::Path internalPath ) + : m_filePath( file ) + , m_internalPath( internalPath ) +{} + +// ================================ // +// +inline AssetPath::AssetPath ( const std::string& assetPath ) +{ + auto pathNullable = AssetPath::FromString( assetPath ); + + if( pathNullable.IsValid() ) + { + auto path = std::move( pathNullable ).Get(); + + m_filePath = std::move( path.m_filePath ); + m_internalPath = std::move( path.m_internalPath ); + } +} + +// ================================ // +// +inline AssetPath::AssetPath ( const char* assetPath ) + : AssetPath( std::string( assetPath ) ) +{} + +// ================================ // +// +inline std::string AssetPath::String () const +{ + return fmt::format( "{}", *this ); +} + +// ================================ // +// +inline bool AssetPath::operator== ( const AssetPath& other ) const +{ + return std::tie( m_filePath, m_internalPath ) == std::tie( other.GetFile(), other.GetInternalPath() ); +} + +// ================================ // +// +inline bool AssetPath::operator!= ( const AssetPath& other ) const +{ + return std::tie( m_filePath, m_internalPath ) != std::tie( other.GetFile(), other.GetInternalPath() ); +} + +// ================================ // +// +inline bool AssetPath::operator< ( const AssetPath& other ) const +{ + return std::tie( m_filePath, m_internalPath ) < std::tie( other.GetFile(), other.GetInternalPath() ); +} + +// ================================ // +// +inline bool AssetPath::operator<= ( const AssetPath& other ) const +{ + return std::tie( m_filePath, m_internalPath ) <= std::tie( other.GetFile(), other.GetInternalPath() ); +} + +// ================================ // +// +inline bool AssetPath::operator> ( const AssetPath& other ) const +{ + return std::tie( m_filePath, m_internalPath ) > std::tie( other.GetFile(), other.GetInternalPath() ); +} + +// ================================ // +// +inline bool AssetPath::operator>= ( const AssetPath& other ) const +{ + return std::tie( m_filePath, m_internalPath ) >= std::tie( other.GetFile(), other.GetInternalPath() ); +} + + + +} // sw + + diff --git a/ResourceManager/PathTranslators/LoadPath.h b/ResourceManager/PathTranslators/LoadPath.h new file mode 100644 index 0000000..072501a --- /dev/null +++ b/ResourceManager/PathTranslators/LoadPath.h @@ -0,0 +1,131 @@ +#pragma once +/** +@file LoadPath.h +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + +#include "PathsManager.h" +#include "AssetPath.h" + +#include "swCommonLib/Common/Macros/DefineFmtFormatter.h" + + +namespace sw +{ + + +/**@brief Represents path provided for @ref IAssetLoader. + +This class stores both original AssetPath with aliases and translated path. +It need to make translation from @ref IAssetLoader.*/ +class LoadPath +{ +private: + + AssetPath m_originalPath; + AssetPath m_translatedPath; + +protected: +public: + explicit LoadPath ( AssetPath original, AssetPath translated ); + explicit LoadPath ( AssetPath original, const PathsManager* pm ); + ~LoadPath () = default; + +public: + + /**@brief Gets file path ready to loading. + Note that this path don't have aliases. If you want to build paths, better use not translated version.*/ + const filesystem::Path& GetFile () const { return m_translatedPath.GetFile(); } + + const filesystem::Path& GetInternalPath () const { return m_originalPath.GetInternalPath(); } + const filesystem::Path& GetFileTranslated () const { return m_translatedPath.GetFile(); } + const filesystem::Path& GetFileOriginal () const { return m_originalPath.GetFile(); } + + const AssetPath& GetOriginalPath () const { return m_originalPath; } + const AssetPath& GetTranslatedPath () const { return m_translatedPath; } + +public: + + /**@brief Extends internal path and returns new object.*/ + LoadPath operator/ ( const filesystem::Path& path ) const; + +public: + + std::string Print () const; + +public: + + static filesystem::Path Translate ( const filesystem::Path& path, const PathsManager* pm ); + static AssetPath Translate ( const AssetPath& name, const PathsManager* pm ); +}; + +} // sw + +DEFINE_FMT_FORMATTER( sw::LoadPath, "Path: [{}] translated to: [{}]", GetOriginalPath(), GetTranslatedPath() ); + + +namespace sw +{ + +//====================================================================================// +// Implementation +//====================================================================================// + +// ================================ // +// +inline LoadPath::LoadPath ( AssetPath original, AssetPath translated ) + : m_originalPath( std::move( original ) ) + , m_translatedPath( std::move( translated ) ) +{} + +// ================================ // +// +inline LoadPath::LoadPath ( AssetPath original, const PathsManager* pm ) + : m_originalPath( std::move( original ) ) + , m_translatedPath( LoadPath::Translate( original, pm ) ) +{} + +// ================================ // +// +inline LoadPath LoadPath::operator/ ( const filesystem::Path& path ) const +{ + auto newInternalPath = GetInternalPath() / path; + return LoadPath( AssetPath( GetFileOriginal(), newInternalPath ), AssetPath( GetFileTranslated(), newInternalPath ) ); +} + +// ================================ // +// +inline std::string LoadPath::Print () const +{ + return fmt::format( "{}", *this ); +} + +// ================================ // +// +inline filesystem::Path LoadPath::Translate ( const filesystem::Path& path, const PathsManager* pm ) +{ + auto translated = pm->Translate( path ); + + // @todo If working directory changes this code translates to another path. + // Is this expected behavior in this case? + if( translated.IsRelative() && !translated.IsEmpty() ) + translated = filesystem::Path::WorkingDirectory() / translated; + + translated.Normalize(); + + return translated; +} + +// ================================ // +// +inline AssetPath LoadPath::Translate ( const AssetPath& name, const PathsManager* pm ) +{ + auto systemPath = Translate( name.GetFile(), pm ); + return AssetPath( systemPath, name.GetInternalPath() ); +} + + +} // sw + + diff --git a/ResourceManager/PathTranslators/PathsManager.cpp b/ResourceManager/PathTranslators/PathsManager.cpp new file mode 100644 index 0000000..a1416d6 --- /dev/null +++ b/ResourceManager/PathTranslators/PathsManager.cpp @@ -0,0 +1,114 @@ +/** +@file PathsManager.cpp +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ +#include "swGraphicAPI/ResourceManager/stdafx.h" + +#include "PathsManager.h" + +#include +#include + + + +namespace sw +{ + + +std::regex gAliasFormat( "^\\$\\([_\\-.[:alnum:]]+\\)$" ); + + +// ================================ // +// +filesystem::Path PathsManager::Translate ( const filesystem::Path& path ) const +{ + // Absolut paths don't need translation. + if( path.IsRelative() ) + { + const auto& segments = path.GetTokens(); + if( segments.size() > 0 ) + { + const auto& alias = segments[ 0 ]; + if( IsValidAlias( alias ) ) + { + auto iter = m_aliases.find( alias ); + if( iter != m_aliases.end() ) + { + filesystem::Path relativePart = path.ClipFromRoot( 1 ); + return iter->second / relativePart; + } + } + } + } + + return path; +} + +// ================================ // +// +Nullable< filesystem::Path > PathsManager::FindAlias ( const std::string& alias ) const +{ + auto iter = m_aliases.find( alias ); + + if( iter == m_aliases.end() ) + return std::make_shared< RuntimeException >( "Alias " + alias + " is not registered." ); + + return iter->second; +} + +// ================================ // +// +ReturnResult PathsManager::RegisterAlias ( const std::string& alias, const filesystem::Path& path ) +{ + if( IsValidAlias( alias ) ) + { + auto iter = m_aliases.find( alias ); + + if( iter != m_aliases.end() ) + return Result::Error; + + m_aliases[ alias ] = Translate( path ); + + return Result::Success; + } + + return Result::Error; +} + +// ================================ // +// +bool PathsManager::IsValidAlias ( const std::string& alias ) +{ + return std::regex_match( alias, gAliasFormat ); +} + + +//====================================================================================// +// API for TestFramework +//====================================================================================// + +// ================================ // +// +ReturnResult PathsManager::OverrideAlias ( const std::string& alias, const filesystem::Path& path ) +{ + if( IsValidAlias( alias ) ) + { + auto iter = m_aliases.find( alias ); + + if( iter == m_aliases.end() ) + return Result::Error; + + m_aliases[ alias ] = Translate( path ); + + return Result::Success; + } + + return Result::Error; +} + + +} // sw + + + diff --git a/ResourceManager/PathTranslators/PathsManager.h b/ResourceManager/PathTranslators/PathsManager.h new file mode 100644 index 0000000..33d9d83 --- /dev/null +++ b/ResourceManager/PathTranslators/PathsManager.h @@ -0,0 +1,70 @@ +#pragma once +/** +@file PathsManager.h +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + + +#include "swCommonLib/System/Path.h" +#include "swCommonLib/Common/Exceptions/Nullable.h" + +#include +#include + + +namespace sw +{ + + +/**@brief Translates paths. + +PathsManager stores paths aliases and can translate them to absolute paths during programm execution. +Example alias $(APP_DIR) would be resolved to absolut path.*/ +class PathsManager +{ +private: +protected: + + std::map< std::string, filesystem::Path > m_aliases; + +public: + explicit PathsManager () = default; + ~PathsManager () = default; + +public: + + filesystem::Path Translate ( const filesystem::Path& path ) const; + Nullable< filesystem::Path > FindAlias ( const std::string& alias ) const; + +public: + + ///@name Aliases registration API + ///@{ + + /**@brief Adds new alias. + Alias must have valid format $(ALIAS_NAME). If alias already existed it won't be overwritten. + @return If user provides existing or invalid alias, function returns false.*/ + ReturnResult RegisterAlias ( const std::string& alias, const filesystem::Path& path ); + + ///@} + + ///@name API for TestFramework. Don't use in normal applications. + ///@{ + ReturnResult OverrideAlias ( const std::string& alias, const filesystem::Path& path ); + + ///@} + + +public: + + static bool IsValidAlias ( const std::string& alias ); +}; + +DEFINE_OPTR_TYPE( PathsManager ) +DEFINE_UPTR_TYPE( PathsManager ) +DEFINE_PTR_TYPE( PathsManager ) + + +} // sw + diff --git a/ResourceManager/ResourceContainer.h b/ResourceManager/ResourceContainer.h index 59a003f..f1df390 100644 --- a/ResourceManager/ResourceContainer.h +++ b/ResourceManager/ResourceContainer.h @@ -1,16 +1,15 @@ #pragma once - -/**@file ResourceContainer.h +/** +@file ResourceContainer.h @author nieznanysprawiciel -@copyright Plik jest cz�ci� silnika graficznego SWEngine. +@copyright File is part of Sleeping Wombat Libraries. +*/ -@brief Zawiera deklaracj� szblonu klasy kontenera dla asset�w. -*/ -///@todo Doda� IDki obok �cie�ek. -///@todo Kontrner powinien obs�ugiwa� �cie�ki, jako obiekty typu Path zamiast wstring�w. -//#include "swCommonLib/Common/System/Path.h" +#include "swCommonLib/System/Path.h" +#include "swGraphicAPI/ResourceManager/PathTranslators/AssetPath.h" + #include #include @@ -19,98 +18,116 @@ #include "swGraphicAPI/Resources/ResourcePtr.h" -/** -@brief Szablon klasy do przechowywania asset�w. +namespace sw +{ + + + + +/**@brief Container for resources. -Wszystkie assety s� identyfikowane po nazwie, kt�ra najcz�ciej jest nazw� pliku, z kt�rego asset -pochodzi. Mapa zapewnia logarytmiczny czas dost�pu po nazwie. Istnieje te� mo�liwo�� odwo�ania si� -po identyfikatorze, wtedy czas dost�pu jest liniowy (chyba �e iterowanie po kolejnych elementacj mapy -nie odbywa si� liniowo.*/ -template < class TYPE > +Resources are identified by their path.*/ +template< class ResourceType > class ResourceContainer { friend class AssetsManager; friend class ResourceManager; + friend class nResourceManager; private: - unsigned int count; /// container; /// m_resMap; ///< Maps assets names/paths to Resources. + + +protected: + + // Deleting objects. + bool ForceRemove ( const AssetPath& name ); + bool ForceRemove ( ResourceID id ); + void ForceRemoveAll (); + void ReleaseMemory ( ResourceType* ); - // Kasowanie obiekt�w - int ForceRemove ( const std::wstring& name ); - int ForceRemove ( unsigned int id ); - void ForceRemoveAll (); - void ReleaseMemory ( TYPE* ); public: ResourceContainer(); ~ResourceContainer(); - // Kasowanie obiekt�w - int Remove ( const std::wstring& name ); - int Remove ( unsigned int id ); - int RemoveUnused (); + // Deleting objects. + bool Remove ( const AssetPath& name ); + bool Remove ( ResourceID id ); + Size RemoveUnused (); - // Dodawanie obiekt�w - void UnsafeAdd ( const std::wstring& name, TYPE* resource ); + // Adding objects + void UnsafeAdd ( const AssetPath& name, ResourceType* resource ); + bool SafeAdd ( const AssetPath& name, ResourceType* resource ); - // Dost�p do obiekt�w - TYPE* get ( unsigned int id ); - inline unsigned int GetNextId() { return count; } ///second; return nullptr; } /**@brief Finds resource matching given descriptor. - + Resource must implement GetDescriptor function. Descriptor must implement operator==. - + Function finds resource in linear time. Use only for small containers.*/ template< typename DescType > - TYPE* Find ( const DescType& desc ); + ResourceType* Find ( const DescType& desc ); + + // Listing resources. + template< typename ResourceCastType > + std::vector< ResourcePtr< ResourceCastType > > List() const; - // Listowanie obiekt�w. - std::vector< ResourcePtr< TYPE > > List(); + inline uint32 GetNextId() { return count; } ///< Returns idetifier for next resource of this type. }; -template -ResourceContainer::ResourceContainer() -{ - count = 1; -} -/**@brief Destruktor zwalnia wszystkie elementy w mapie (tak�e pami�� po nich)*/ -template -ResourceContainer::~ResourceContainer( ) +//====================================================================================// +// Implementation +//====================================================================================// + + +// ================================ // +// +template< class ResourceType > +ResourceContainer< ResourceType >::ResourceContainer() + : m_counter( 1 ) +{} + +/**@brief Releases all assets.*/ +template< class ResourceType > +ResourceContainer< ResourceType >::~ResourceContainer() { - for ( auto iter = container.begin( ); iter != container.end( ); iter++ ) + for( auto iter = m_resMap.begin(); iter != m_resMap.end(); iter++ ) { ReleaseMemory( iter->second ); } - container.clear(); + m_resMap.clear(); } -/**@brief Zwraca element na podstawie identyfikatora. +/**@brief Returns resource base on identifier. -Wyszukiwanie po identyfikatorze jest liniowe, a po nazwie logarytmiczne. -Jednak�e por�wnania string�w mog� si� okaza� bardziej kosztowne. -@param[in] id Identyfikator elementu. -@return Wska�nik na poszukiwany element.*/ -template -TYPE* ResourceContainer::get ( unsigned int id ) +Searching in linear time. + +@param[in] id Resource identifier. +@return Resource pointer*/ +template< class ResourceType > +ResourceType* ResourceContainer< ResourceType >::Get ( ResourceID id ) { - for ( auto iter = container.begin(); iter != container.end(); iter++ ) + for( auto iter = m_resMap.begin(); iter != m_resMap.end(); iter++ ) { - if ( iter->second->GetID() == id ) + if( iter->second->GetID() == id ) return iter->second; } return nullptr; @@ -118,13 +135,13 @@ TYPE* ResourceContainer::get ( unsigned int id ) // ================================ // // -template< class TYPE > +template< class ResourceType > template< typename DescType > -inline TYPE* ResourceContainer< TYPE >::Find ( const DescType& desc ) +inline ResourceType* ResourceContainer< ResourceType >::Find ( const DescType& desc ) { - static_assert( std::is_member_function_pointer< decltype( &TYPE::GetDescriptor ) >::value, "TYPE must implement GetDescriptor function." ); + static_assert( std::is_member_function_pointer< decltype( &ResourceType::GetDescriptor ) >::value, "ResourceType must implement GetDescriptor function." ); - for( auto& resource : container ) + for( auto& resource : m_resMap ) { if( resource.second->GetDescriptor() == desc ) return resource.second; @@ -134,191 +151,170 @@ inline TYPE* ResourceContainer< TYPE >::Find ( const DescType& desc ) //-------------------------------------------------------------------------------// -// dodawanie obiekt�w +// Adding elements //-------------------------------------------------------------------------------// -/*Dodaje element do kontanera + nadaje mu unikalny identyfikator. -Je�eli element ju� istnia�, to po prostu nie zostanie wstawiony, dlatego -przed uzyciem warto pobra� element o danej nazwie, �eby sprawdzi� -czy dodawanie jest konieczne.*/ -// Mo�e kiedy� zrobie wstawianie ze sprawdzaniem, na razie nie wydaje si� potrzebne -/**@brief Dodaje element do kontanera + nadaje mu unikalny identyfikator. +/**@brief Adds resource without checking it's existance. +Resource will be overwritten if it existed.*/ +template< class ResourceType > +void ResourceContainer< ResourceType >::UnsafeAdd ( const AssetPath& name, ResourceType* resource ) +{ + if( !resource ) + return; -Je�eli element ju� istnia�, to zostanie nadpisany nowym, dlatego nale�y -zawsze przed u�yciem sprawdzi� czy pod tak� nazw�, co� ju� si� nie -znajduje. -@param[in] name Nazwa elementu, pod jak� zostanie dodany. -@param[in] resource Element dodania.*/ -template -void ResourceContainer::UnsafeAdd( const std::wstring& name, TYPE* resource ) + m_resMap[ name ] = resource; + resource->SetID( m_counter++ ); +} + +/**@brief Adds resource only if it didn't existed.*/ +template< class ResourceType > +inline bool ResourceContainer< ResourceType >::SafeAdd ( const AssetPath& name, ResourceType* resource ) { - if ( !resource ) - return; //Nie mo�emy potem ustawi� id + if( !resource ) + return false; - container[name] = resource; + auto insertResult = m_resMap.insert( std::make_pair( name, resource ) ); + + // Check if element existed. + if( insertResult.second == false ) + return false; - resource->SetID( count ); - ++count; // Inkrementujemy licznik + return true; } //-------------------------------------------------------------------------------// -// kasowanie obiekt�w +// Removing resources //-------------------------------------------------------------------------------// -/**@brief Zwalnia obiekt podany w parametrze. -Kasowanie pami�ci nie jest mo�liwe przy pomocy operatora delete, -poniewa� destruktory w tych klasach s� prywatne. Dlatego trzeba zrobi� to -za po�rednictwem obiektu, kt�ry ma uprawnienia do tego. -@param[in] object Objekt do skasowania. -*/ -template -void ResourceContainer::ReleaseMemory( TYPE* object ) +/**@brief Release resource.*/ +template< class ResourceType > +void ResourceContainer< ResourceType >::ReleaseMemory ( ResourceType* object ) { - // Destruktor jest prywatny, wi�c nie mo�emy kasowa� obiektu bezpo�rednio. - ObjectDeleterKey key; // Tworzymy klucz. - ObjectDeleter model_deleter( key ); // Tworzymy obiekt kasuj�cy i podajemy mu nasz klucz. - model_deleter.delete_object( object ); // Kasujemy obiekt za po�rednictwem klucza. + object->Delete( ResourceAccessKey< ResourceType >() ); } -/**@brief Usuwa element o podanej nazwie, je�eli nie ma do niego odwo�a�. - -@param[in] name nazwa elementu do usuni�cia. -@return Zwracana warto��: -- 0 - w przypadku powodzenia, -- -1 - nie znaleziono elementu, -- 1 - nie da si� usun��, bo jest w u�yciu*/ -template -int ResourceContainer::Remove( const std::wstring& name ) +/**@brief Removes resource if it's posible. +@return Returns false if resource doesn't exist or it still has references.*/ +template< class ResourceType > +bool ResourceContainer< ResourceType >::Remove ( const AssetPath& name ) { - auto iter = container.find( name ); - if ( iter != container.end() ) - return -1; // Nie znale�li�my elementu + auto iter = m_resMap.find( name ); + if( iter != m_resMap.end() ) + return false; - if ( !iter->second->CanDelete() ) - return 1; // Nie mo�emy skasowa�, bo s� odwo�ania + if( !iter->second->CanDelete() ) + return false; - ReleaseMemory( iter->second ); // Zwalniamy pami�� spod wska�nika - container.erase( iter ); // Kasujemy element z mapy + ReleaseMemory( iter->second ); + m_resMap.erase( iter ); - return 0; // Wychodzimy z powodzeniem + return true; } -/**@brief Usuwa element o podanym indeksie, je�eli nie ma do niego odwo�a�. - -@param[in] id Identyfikator elementu -@return Zwracana warto��: -- 0 - w przypadku powodzenia, -- -1 - nie znaleziono elementu, -- 1 - nie da si� usun��, bo jest w u�yciu*/ -template -int ResourceContainer::Remove( unsigned int id ) +/**@brief Removes resource if it's posible. +@return Returns false if resource doesn't exist or it still has references.*/ +template +bool ResourceContainer< ResourceType >::Remove ( ResourceID id ) { - for ( auto iter = container.begin( ); iter != container.end( ); iter++ ) + for( auto iter = m_resMap.begin(); iter != m_resMap.end(); iter++ ) { - if ( iter->second->GetID() == id ) + if( iter->second->GetID() == id ) { - // Sprawdzamy czy nie ma jakich� odwo�a� do obiektu - if ( !iter->second->CanDelete() ) - return 1; // S� odwo�ania, wi�c nie kasujemy + if( !iter->second->CanDelete() ) + return false; - ReleaseMemory( iter->second ); // Zwalniamy pami�� spod wska�nika - container.erase( iter ); // Kasujemy element z mapy + ReleaseMemory( iter->second ); + m_resMap.erase( iter ); - return 0; // Zwracamy 0 jako powodzenie operacji + return true; } } - return -1; // Nie znale�li�my elementu + return false; } -/**@brief Kasuje wszystkie elementy w kontenerze, kt�re nie s� u�ywane przez -�aden obiekt. Kasowanie jest w pe�ni bezpieczne. - -@return Zwraca liczb� usuni�tych element�w.*/ -template -int ResourceContainer::RemoveUnused() +/**@brief Removes all resources witout references. +@return Returns number of deleted elements.*/ +template< class ResourceType > +Size ResourceContainer< ResourceType >::RemoveUnused () { int count = 0; - for ( auto iter = container.begin(); iter != container.end(); iter++ ) - {// Iterujemy po ca�ej mapie - if ( iter->second->CanDelete() ) + for( auto iter = m_resMap.begin(); iter != m_resMap.end(); ) + { + if( iter->second->CanDelete() ) { - // Mo�emy skasowa� obiekt, bo nikt go nie u�ywa - ReleaseMemory( iter->second ); // Zwalniamy pami�� spod wska�nika - container.erase( iter ); // Kasujemy element z mapy + ReleaseMemory( iter->second ); + iter = m_resMap.erase( iter ); ++count; } + else + { + iter++; + } } return count; } -/**@brief Wymusza skasowanie podanego elementu, nawet je�eli jest u�ywany - -@param[in] name Nazwa elementu do usuni�cia. -@return Zwracana warto��: -- 0 - w przypadku powodzenia, -- -1 - nie znaleziono elementu*/ -template -int ResourceContainer::ForceRemove( const std::wstring& name ) +/**@brief Removes resource even if it's reference count is greater then 0. +@return Returns false if resource doesn't exist.*/ +template< class ResourceType > +bool ResourceContainer< ResourceType >::ForceRemove ( const AssetPath& name ) { - auto iter = container.find( name ); - if ( iter != container.end( ) ) - return -1; // Nie znale�li�my elementu + auto iter = m_resMap.find( name ); + if( iter != m_resMap.end() ) + return false; - delete iter->second; // Zwalniamy pami�� spod wska�nika - return 0; + delete iter->second; + return true; } -/**@brief Wymusza skasowanie podanego elementu - -@param[in] id Identyfkator elementu do usuni�cia -@return Zwracana warto��: -- 0 - w przypadku powodzenia, -- -1 - nie znaleziono elementu*/ -template -int ResourceContainer::ForceRemove( unsigned int id ) +/**@brief Removes resource even if it's reference count is greater then 0. +@return Returns false if resource doesn't exist.*/ +template< class ResourceType > +bool ResourceContainer< ResourceType >::ForceRemove ( ResourceID id ) { - for ( auto iter = container.begin( ); iter != container.end( ); iter++ ) + for( auto iter = m_resMap.begin(); iter != m_resMap.end(); iter++ ) { - if ( iter->second->GetID( ) == id ) + if( iter->second->GetID() == id ) { - delete iter->second; // Zwalniamy pami�� spod wska�nika - return 0; + delete iter->second; + return true; } } - return -1; // Nie znaleziono elementu + return false; } -/**@brief Kasuje wszystkie elementy niezale�nie od tego czy by�y u�ywane, -a nast�pnie czy�ci map�.*/ -template -void ResourceContainer::ForceRemoveAll( ) +/**@brief removes all elements.*/ +template< class ResourceType > +void ResourceContainer< ResourceType >::ForceRemoveAll () { - for ( auto iter = container.begin(); iter != container.end(); iter++ ) - {// Iterujemy po ca�ej mapie - delete iter->second; // Zwalniamy pami�� spod wska�nika + for( auto iter = m_resMap.begin(); iter != m_resMap.end(); iter++ ) + { + delete iter->second; } - container.clear(); + m_resMap.clear(); } -/**@brief Listuje wszystkie assety danego typu.*/ -template< class TYPE > -inline std::vector< ResourcePtr< TYPE > > ResourceContainer< TYPE >::List() +/**@brief Lists all elements in ResourceContainer.*/ +template< class ResourceType > +template< typename ResourceCastType > +inline std::vector< ResourcePtr< ResourceCastType > > ResourceContainer< ResourceType >::List () const { - std::vector< ResourcePtr< TYPE > > resourcesList; - resourcesList.reserve( container.size() ); + std::vector< ResourcePtr< ResourceCastType > > resourcesList; + resourcesList.reserve( m_resMap.size() ); - for( auto iter = container.begin(); iter != container.end(); iter++ ) + for( auto iter = m_resMap.begin(); iter != m_resMap.end(); iter++ ) { - resourcesList.push_back( ResourcePtr< TYPE >( iter->second ) ); + resourcesList.push_back( ResourcePtr< ResourceCastType >( iter->second ) ); } return resourcesList; } +} // sw diff --git a/ResourceManager/ResourceManager.cpp b/ResourceManager/ResourceManager.cpp index 34dfdea..aa3982c 100644 --- a/ResourceManager/ResourceManager.cpp +++ b/ResourceManager/ResourceManager.cpp @@ -1,534 +1,393 @@ /** @file ResourceManager.cpp @author nieznanysprawiciel -@copyright File is part of graphic engine SWEngine. +@copyright File is part of Sleeping Wombat Libraries. */ - #include "swGraphicAPI/ResourceManager/stdafx.h" -#include "ResourceManager.h" - -#include "swCommonLib/Common/ObjectDeleter.h" -#include "swCommonLib/Common/Converters.h" -#include "swCommonLib/System/Path.h" - -#include "swGraphicAPI/Resources/ResourcesFactory.h" +#include "ResourceManager.h" +#include "swGraphicAPI/ResourceManager/ResourceContainer.h" +#include "swGraphicAPI/ResourceManager/Exceptions/ResourceManagerException.h" +#include "swGraphicAPI/ResourceManager/PathTranslators/LoadPath.h" -#include "swCommonLib/Common/MemoryLeaks.h" +#include "swGraphicAPI/ResourceManager/Loaders/RenderTargetLoader.h" +#include "swGraphicAPI/ResourceManager/Loaders/ShaderLoader.h" +#include "swCommonLib/Common/Multithreading/UniqueLock.h" -using namespace DirectX; -//-------------------------------------------------------------------------------// -// wersja DirectX11 -//-------------------------------------------------------------------------------// +namespace sw +{ +// ================================ // +// ResourceManager::ResourceManager() -{} - - - -ResourceManager::~ResourceManager( ) -{} - - + : m_pathsManager( new PathsManager() ) +{ + m_assetsFactory = AssetsFactoryOPtr( new AssetsFactory() ); + // Register default loaders for basic types. + RegisterBasicLoaders(); +} -/** @brief Znajduje Loader pasuj�cy do pliku podanego w parametrze. -@param[in] path �cie�ka do pliku, dla kt�rej szukamy loadera. -@return Wska�nik na odpowiedni loader lub nullptr, je�eli nie znaleziono pasuj�cego.*/ -//ILoader* ResourceManager::FindLoader( const std::wstring& path ) -//{ -// for ( unsigned int i = 0; i < m_loader.size( ); ++i ) -// if ( m_loader[i]->can_load( path ) ) -// return m_loader[i]; -// return nullptr; -//} +// ================================ // +// +ResourceManager::~ResourceManager() +{ + // It would happen later, but we want to release Resources before creators and loaders. + m_resources.clear(); +} +// ================================ // +// +void ResourceManager::RegisterBasicLoaders () +{ + RegisterLoader( std::make_shared< RenderTargetLoader >() ); + RegisterLoader( std::make_shared< ShaderLoader >() ); +} +//====================================================================================// +// Getting assets +//====================================================================================// -/**@brief Tworzy nowy render target. +// ================================ // +// +ResourcePointer ResourceManager::GetGeneric ( const AssetPath& name, TypeID type ) +{ + // Lock as Reader. + ReaderUniqueLock< ReaderWriterLock > lock( m_rwLock ); -Funkcja dodaje stworzony obiekt do tablicy m_renderTarget. Je�eli tekstury -bufora color�w, g��boko�ci i stencilu nie s� nullptrami, to i one s� dodawane do tablicy m_texture. + return FindResource( name, type ); +} -Tekstury te maj� nazwy jak render target + dodany jest cz�on -- ::color -- ::depth -- ::stencil +//====================================================================================// +// Loading +//====================================================================================// -@todo Przy dodawaniu tekstur nie jest sprawdzane czy one ju� istniej�. Trzeba albo to sprawdza�, albo zapewni� -np. jak�� polityk� nazewnictwa, �e w ten spos�b nie nadpisujemy istniej�cej tekstury. -@param[in] name Nazwa identyfikuj�ca render target. -@param[in] renderTargetDescriptor Deskryptor opisuj�cy parametry render targetu. -@return Zwraca stworzony obiekt lub nullptr w przypadku niepowodzenia. Je�eli render target ju� istnia�, to zwracany jest istniej�cy obiekt. -*/ -RenderTargetObject* ResourceManager::CreateRenderTarget( const std::wstring& name, const RenderTargetDescriptor& renderTargetDescriptor ) +sw::Nullable< ResourcePointer > ResourceManager::LoadGeneric ( const AssetPath& name, const IAssetLoadInfo* desc, TypeID type ) { - RenderTargetObject* newRenderTarget = m_renderTarget.get( name ); - if( !newRenderTarget ) - { - newRenderTarget = ResourcesFactory::CreateRenderTarget( name, renderTargetDescriptor ); - if( !newRenderTarget ) return nullptr; - - m_renderTarget.UnsafeAdd( name, newRenderTarget ); - - auto colorBuff = newRenderTarget->GetColorBuffer(); - if( colorBuff ) - m_texture.UnsafeAdd( Convert::FromString( colorBuff->GetFilePath().String(), std::wstring() ), colorBuff ); + auto loadPath = LoadPath( name, m_pathsManager.get() ); + return LoadGeneric( loadPath, desc, type ); +} - auto depthBuffer = newRenderTarget->GetDepthBuffer(); - if( depthBuffer ) - m_texture.UnsafeAdd( Convert::FromString( depthBuffer->GetFilePath().String(), std::wstring() ), depthBuffer ); +// ================================ // +/// @note If asset loading fails and we call LoadGeneric function again, LoadGeneric will try to load it +/// for the second time. This will cause performance problem, when something is wrong with important asset +/// loaded by multiple entities, because even failed loading is heavy operation. +sw::Nullable< ResourcePointer > ResourceManager::LoadGeneric ( const LoadPath& loadPath, const IAssetLoadInfo* desc, TypeID type ) +{ + // Lock as Reader. Try to find resource and request asset atomically. + ReaderUniqueLock< ReaderWriterLock > lock( m_rwLock ); - auto stencilBuffer = newRenderTarget->GetStencilBuffer(); - if( stencilBuffer ) - m_texture.UnsafeAdd( Convert::FromString( stencilBuffer->GetFilePath().String(), std::wstring() ), stencilBuffer ); + auto resource = FindResource( loadPath.GetOriginalPath(), type ); + if( !resource ) + { + WaitingAsset* assetLock = nullptr; + bool isLoadingInProgress = false; + + // We want to lock on absolute path without aliases. Otherwise two paths can point to the same asset. + std::tie( assetLock, isLoadingInProgress ) = LockFileForLoading( loadPath ); + + // Unlock as Reader. Here we either have locked asset for this thread or asset was already + // locked and we must wait until other thread will load it completly. + lock.Unlock(); + + if( isLoadingInProgress ) + { + auto result = m_waitingAssets.WaitUntilLoaded( assetLock ); + + // Loading could fail. If this is the case, we return error stored in WaitingAsset. + // Note that we must store error in WaitingAsset to avoid reloading the same file again. + // All threads that waited for asset, have no other way to get to know loading result. + if( result.IsValid() ) + { + // Asset loader could load requested file but there's no guarantee that requested asset was loaded too. + // For example name contains path to material inside mesh file. Loader loads entire mesh, but material wasn't necessary. + // If asset was loaded, next call to LoadGeneric will take it from m_resources map. If it wasn't - next call will try to load + // specific asset (not entire file). If it returns nullptr, it means that asset can't be loaded. + // + // @todo Consider situation when first found loader isn't able to load file, but next could. Should we handle this? Maybe use some loader flags. + return LoadGeneric( loadPath, desc, type ); + } + + return result.GetError(); + } + else + { + return LoadingImpl( loadPath, desc, type ); + } } - return newRenderTarget; + return resource; } - - -/**@brief Dodaje renderTarget do ResourceManagera, je�eli jeszcze nie istnia�. -@note Funkcja nie dodaje odwo�ania do obiektu, bo nie zak�ada, �e kto� go od razu u�yje. -W ka�dym miejscu, gdzie zostanie przypisany zwr�cony obiekt, nale�y pami�ta� o dodaniu odwo�ania oraz -skasowaniu go, gdy obiekt przestanie by� u�ywany. - -@note Je�eli renderTarget ju� istnia� (jego nazwa), to ten podany w parametrze nie zostanie dodany. -Oznacza to, �e za jego zwolnienie odpowiada ten, kto go stworzy�. Trzeba zawsze sprawdzi� czy -zwr�cona warto�� jest tym samym co podali�my. - -@todo Nie mo�e tak zosta�, �e kto� dodaje renderTarget i musi sprawdzi� czy nie dosta� innego. Nie mo�na -te� zmusza� kogo� do zwalniania pami�ci po renderTargecie. Wog�le dodawanie renderTarget�w musi si� odbywa� jako� inaczej. -Najlepiej, �eby by�y one tworzone przez ResourceManager, ale wtedy trzeba wymy�le� spos�b dodawania renderTargetu zwi�zanego z buforem okna. - -@param[in] renderTarget renderTarget, kt�ry ma zosta� dodany. -@param[in] name Nazwa renderTargetu. Do materia�u b�dzie mo�na si� odwo�a� podaj�c ci�g znak�w -@return Zwraca wska�nik na dodany renderTarget.*/ -RenderTargetObject* ResourceManager::AddRenderTarget( RenderTargetObject* renderTarget, const std::wstring& name ) +// ================================ // +// +LoadingResult ResourceManager::LoadFileGeneric ( const AssetPath& assetName, IAssetLoadInfo* desc, TypeID type ) { - RenderTargetObject* newRenderTarget = m_renderTarget.get( name ); - if ( !newRenderTarget ) - m_renderTarget.UnsafeAdd( name, renderTarget ); // Dodali�my materia� - - return newRenderTarget; + return LoadingResult(); } -/**@brief Dodaje vertex shader do ResourceManagera. Je�eli obiekt ju� istnia�, to nie jest tworzony nowy. -@note Funkcja nie dodaje odwo�ania do obiektu, bo nie zak�ada, �e kto� go od razu u�yje. -W ka�dym miejscu, gdzie zostanie przypisany zwr�cony obiekt, nale�y pami�ta� o dodaniu odwo�ania oraz -skasowaniu go, gdy obiekt przestanie by� u�ywany. - -@param[in] fileName Nazwa pliku, w kt�rym znajduje si� vertex shader. -@param[in] shaderEntry Nazwa funkcji od kt�rej ma si� zacz�� wykonywanie shadera. -@return Zwraca obiekt dodanego shadera. Zwraca nullptr, je�eli shadera nie uda�o si� skompilowa�.*/ -VertexShader* ResourceManager::LoadVertexShader( const std::wstring& fileName, const std::string& shaderEntry ) +// ================================ // +// +LoadingResult ResourceManager::LoadFileGeneric ( const AssetPath& assetName, IAssetLoadInfo* desc, TypeID type, IAssetLoader* loader ) { - VertexShader* shader = m_vertexShader.get( fileName ); - if ( !shader ) - { - // Nie by�o shadera, trzeba go stworzy� i doda� - shader = ResourcesFactory::CreateVertexShaderFromFile( fileName, shaderEntry ); - if ( !shader ) // shader m�g� mie� z�y format, a nie chcemy dodawa� nullptra do ResourceManagera - return nullptr; - - m_vertexShader.UnsafeAdd( fileName, shader ); // Dodali�my tekstur� - } - - return shader; + return LoadingResult(); } -/**@brief Dodaje vertex shader do ResourceManagera. Je�eli obiekt ju� istnia�, to nie jest tworzony nowy. -Tworzy te� layout wierzcho�ka zwi�zany z tym shaderem i zwraca go w zmiennej layout. - -Je�eli vertex shader wcze�niej istnia�, to stworzenie layoutu wymaga ponownego skompilowania shadera. Shader taki jest potem -kasowany i nie zostaje zdublowany w ResourceManagerze, ale niepotrzebna praca zostaje w�o�ona. Jest wi�c zadaniem programisty, �eby -do takich rzeczy dochodzi�o jak najrzadziej. - -@note Funkcja nie dodaje odwo�ania do obiektu, bo nie zak�ada, �e kto� go od razu u�yje. -W ka�dym miejscu, gdzie zostanie przypisany zwr�cony obiekt, nale�y pami�ta� o dodaniu odwo�ania oraz -skasowaniu go, gdy obiekt przestanie by� u�ywany. - -@param[in] fileName Nazwa pliku, w kt�rym znajduje si� vertex shader. -@param[in] shaderEntry Nazwa funkcji od kt�rej ma si� zacz�� wykonywanie shadera. -@param[out] layout W zmiennej umieszczany jest wska�nik na layout wierzcho�ka. Nawet je�eli shader si� nie skompilowa�, to pole mo�e mie� warto�� inn� ni� nullptr. -Dzieje si� tak wtedy, gdy layout istnia� ju� wcze�niej. -@attention Je�eli vertex shader wcze�niej istnia�, to stworzenie layoutu wymaga ponownego skompilowania shadera. Shader taki jest potem -kasowany i nie zostaje zdublowany w ResourceManagerze, ale niepotrzebna praca zostaje w�o�ona. Jest wi�c zadaniem programisty, �eby -do takich rzeczy dochodzi�o jak najrzadziej. -@param[in] layoutDesc Deskryptor opisujacy tworzony layout. -@return Zwraca obiekt dodanego shadera. Zwraca nullptr, je�eli shadera nie uda�o si� skompilowa�.*/ -VertexShader* ResourceManager::LoadVertexShader( const std::wstring& fileName, - const std::string& shaderEntry, - ShaderInputLayout** layout, - InputLayoutDescriptor* layoutDesc ) -{ - /// @todo Ten kod to jaki� totalny shit. Jak komu� si� b�dzie nudzi�o kiedy� (ha ha), to mo�e niech poprawi. - *layout = nullptr; - VertexShader* shader = m_vertexShader.get( fileName ); - VertexShader* newShader = nullptr; - ShaderInputLayout* inputLayout = m_vertexLayout.get( layoutDesc->GetName() ); +//====================================================================================// +// Assets creation +//====================================================================================// - // Tworzymy potrzebne obiekty - if( !inputLayout ) - { - // Tworzymy shader niezale�nie czy istnieje. Inaczej nie mogliby�my stworzy� layoutu. - // Shader zostanie potem usuni�ty. - newShader = ResourcesFactory::CreateVertexShaderFromFile( fileName, shaderEntry, layout, layoutDesc ); - if ( !newShader ) // shader m�g� mie� z�y format, a nie chcemy dodawa� nullptra do ResourceManagera - return nullptr; // layout te� jest nullptrem, nie trzeba si� martwi�. - } - else if( !shader ) +// ================================ // +// +sw::Nullable< ResourcePointer > ResourceManager::CreateGenericAsset ( const AssetPath& name, TypeID assetType, IAssetCreateInfo&& createInfo ) +{ + auto asset = m_assetsFactory->CreateAsset( name, assetType, std::move( createInfo ) ); + + // If asset is valid we need to add it to m_resources. + if( asset.IsValid() ) { - // Layout istnieje, ale shader nie. - newShader = ResourcesFactory::CreateVertexShaderFromFile( fileName, shaderEntry ); - *layout = inputLayout; // Je�eli layout istnia�, to przepisujemy go na wyj�cie. Je�eli nie to i tak b�dzie nullptr. - if ( !newShader ) // shader m�g� mie� z�y format, a nie chcemy dodawa� nullptra do ResourceManagera - return nullptr; - } - else - {// Wszystkie obiekty istania�y ju� wcze�niej. - *layout = inputLayout; - return shader; - } + // Create this pointer here to increment reference counter. Assets factory returns raw C pointers. + // After adding asset to m_resources, it can be released any time by other threads. + ResourcePointer assetPointer = asset.Get(); - // Nowo powsta�e obiekty musz� zosta� dodane do kontener�w. - if ( !shader ) - { - // Nie by�o shadera, trzeba go doda� - m_vertexShader.UnsafeAdd( fileName, newShader ); // Dodali�my shader - shader = newShader; + auto result = AddGenericResource( name, assetType, assetPointer ); + + // Note: Asset under this name could already exist and it won't be added in AddGenericResource function. + if( result.IsValid() ) + return assetPointer; + else + { + // We must manually remove asset here, because it wasn't added to resources list. + // @todo It would be better not to create asset in first place if we can't add it to resources list. + // There are some solutions for that: + // - Create asset under m_rwLock as writer - but creation would last long and we don't want to stop other threads. + // - Check if asset can be added as reader and then add as writer - this suffers from race conditions but this way we could + // avoid most of not necessary creations. + // - Use LoadBarrier (separate then in loader) - I don't know if it is reasonable, because we don't want to use asset created by others. + assetPointer->Delete( ResourceAccessKey< Resource >() ); + + return result.GetError(); + } } else - { // Shader ju� by�, wi�c kasujemy nowy - // Destruktor jest prywatny, wi�c nie mo�emy kasowa� obiektu bezpo�rednio. - ObjectDeleter< VertexShader>::delete_object( shader, ObjectDeleterKey< VertexShader>() ); + { + return asset.GetError(); } - - if( !inputLayout ) // Layoutu nie by�o wcze�niej wi�c dodajemy. - m_vertexLayout.UnsafeAdd( layoutDesc->GetName(), *layout ); - - return shader; } +//====================================================================================// +// Releasing resources +//====================================================================================// -/**@brief Dodaje pixel shader do ResourceManagera. Je�eli obiekt ju� istnia�, to nie jest tworzony nowy. -@note Funkcja nie dodaje odwo�ania do obiektu, bo nie zak�ada, �e kto� go od razu u�yje. -W ka�dym miejscu, gdzie zostanie przypisany zwr�cony obiekt, nale�y pami�ta� o dodaniu odwo�ania oraz -skasowaniu go, gdy obiekt przestanie by� u�ywany. - -@param[in] fileName Nazwa pliku, w kt�rym znajduje si� pixel shader. -@param[in] shaderEntry Nazwa funkcji od kt�rej ma si� zacz�� wykonywanie shadera. -@return Zwraca obiekt dodanego shadera. Zwraca nullptr, je�eli shadera nie uda�o si� skompilowa�.*/ -PixelShader* ResourceManager::LoadPixelShader ( const std::wstring& fileName, const std::string& shaderEntry ) +// ================================ // +// +void ResourceManager::FreeUnusedAssets () { - PixelShader* shader = m_pixelShader.get( fileName ); - if ( !shader ) + WriterUniqueLock< ReaderWriterLock > lock( m_rwLock ); + + // Assets can depend on other Assets. The simplest way to free Resources is to iterate multiple times. + Size removedAssets = 0; + + do { - // Nie by�o shadera, trzeba go stworzy� i doda� - shader = ResourcesFactory::CreatePixelShaderFromFile( fileName, shaderEntry ); - if ( !shader ) // shader m�g� mie� z�y format, a nie chcemy dodawa� nullptra do ResourceManagera - return nullptr; - - m_pixelShader.UnsafeAdd( fileName, shader ); // Dodali�my tekstur� - } + removedAssets = 0; + for( auto& container : m_resources ) + { + removedAssets += container.second.RemoveUnused(); + } - return shader; + } while( removedAssets > 0 ); } -GeometryShader* ResourceManager::LoadGeometryShader ( const std::wstring& fileName, const std::string& shaderEntry ) -{ - //GeometryShader* shader = m_geometryShader.get( fileName ); - //if ( !shader ) - //{ - // // Nie by�o shadera, trzeba go stworzy� i doda� - // shader = ResourcesFactory::CreatePixelShaderFromFile( fileName, shaderEntry ); - // if ( !shader ) // shader m�g� mie� z�y format, a nie chcemy dodawa� nullptra do ResourceManagera - // return nullptr; - - // m_geometryShader.UnsafeAdd( fileName, shader ); // Dodali�my tekstur� - //} - - //return shader; - assert( !"Implements me" ); - return nullptr; -} - -ControlShader* ResourceManager::LoadControlShader ( const std::wstring& fileName, const std::string& shaderEntry ) -{ - assert( !"Implements me" ); - return nullptr; -} +//====================================================================================// +// Listing assets +//====================================================================================// -EvaluationShader* ResourceManager::LoadEvaluationShader ( const std::wstring& fileName, const std::string& shaderEntry ) +// ================================ // +// +std::vector< ResourcePointer > ResourceManager::ListAssets ( TypeID assetType ) const { - assert( !"Implements me" ); - return nullptr; + return ListAssetsTyped< Resource >( assetType ); } -/**@brief Dodaje tekstur� do ModelManagera, je�eli jeszcze nie istnia�a. -@note Funkcja nie dodaje odwo�ania do obiektu, bo nie zak�ada, �e kto� go od razu u�yje. -W ka�dym miejscu, gdzie zostanie przypisany zwr�cony obiekt, nale�y pami�ta� o dodaniu odwo�ania oraz -skasowaniu go, gdy obiekt przestanie by� u�ywany. +//====================================================================================// +// Loaders, creators, registration +//====================================================================================// -@param[in] fileName �cie�ka do tekstury -@return Zwraca wska�nik na dodan� tekstur� lub nullptr, je�eli nie da�o si� wczyta�.*/ -TextureObject* ResourceManager::LoadTexture( const std::wstring& fileName ) +// ================================ // +// +bool ResourceManager::RegisterAssetCreator ( IAssetCreatorPtr creator ) { - TextureObject* tex = m_texture.get( fileName ); - if ( !tex ) - { - // Nie by�o tekstury, trzeba j� stworzy� i doda� - TextureInfo texInfo; - texInfo.FilePath = filesystem::Path( fileName ); - texInfo.GenerateMipMaps = true; - texInfo.MipMapFilter = MipMapFilter::Lanczos4; - - MemoryChunk texData = LoadTextureImpl( texInfo.FilePath, texInfo ); - - tex = ResourcesFactory::CreateTextureFromMemory( texData, std::move( texInfo ) ); - if ( !tex ) // Tekstura mog�a mie� z�y format, a nie chcemy dodawa� nullptra do ResourceManagera - return nullptr; - - m_texture.UnsafeAdd( fileName, tex ); // Dodali�my tekstur� - } - - return tex; + return m_assetsFactory->RegisterCreator( creator ); } -/**@brief Dodaje do ResourceManagera bufor wierzcho�k�w. -Je�eli pod tak� nazw� istnieje jaki� bufor, to zostanie zwr�cony wska�nik na niego. -@note Funkcja nie dodaje odwo�ania do obiektu, bo nie zak�ada, �e kto� go od razu u�yje. -W ka�dym miejscu, gdzie zostanie przypisany zwr�cony obiekt, nale�y pami�ta� o dodaniu odwo�ania oraz -skasowaniu go, gdy obiekt przestanie by� u�ywany. - -@param[in] name Nazwa bufora, po kt�rej mo�na si� b�dzie odwo�a�. -@param[in] buffer Wska�nik na bufor z danym, kt�re maj� by� przeniesione do bufora DirectXowego. -@param[in] elementSize Rozmiar pojedynczego elementu w buforze. -@param[in] vertCount Liczba wierzcho�k�w/indeks�w w buforze. -@return Dodany bufor wierzcho�k�w. Zwraca nullptr, je�eli nie uda�o si� stworzy� bufora.*/ -ResourcePtr< BufferObject > ResourceManager::CreateVertexBuffer( const std::wstring& name, const void* buffer, unsigned int elementSize, unsigned int vertCount ) +// ================================ // +// +bool ResourceManager::RegisterLoader ( IAssetLoaderPtr loader ) { - VertexBufferInitData initData; - initData.Data = (const uint8*)buffer; - initData.ElementSize = elementSize; - initData.NumElements = vertCount; - - return CreateVertexBuffer( name, initData ); + m_loaders.push_back( loader ); + return true; } -/**@brief Creates vetex buffer. - -@return Returns buffer or nullptr if name already exists or buffer creation failed.*/ -ResourcePtr ResourceManager::CreateVertexBuffer ( const std::wstring& name, const VertexBufferInitData& data ) +// ================================ // +// +LoadersVec ResourceManager::ListLoaders () const { - BufferObject* vertexBuff = m_vertexBuffer.get( name ); - if ( vertexBuff ) // Je�eli znale�li�my bufor, to zwracamy nullptr - return ResourcePtr(); - - - vertexBuff = ResourcesFactory::CreateBufferFromMemory( name, data.Data, data.CreateBufferInfo() ); - if ( !vertexBuff ) // Bufor m�g� si� nie stworzy�, a nie chcemy dodawa� nullptra do ResourceManagera - return nullptr; - - m_vertexBuffer.UnsafeAdd( name, vertexBuff ); // Dodali�my bufor - return ResourcePtr( vertexBuff ); + return m_loaders; } -/**@brief Dodaje do ResourceManagera bufor indeks�w. -Je�eli pod tak� nazw� istnieje jaki� bufor, to zostanie zwr�cony wska�nik na niego. -@note Funkcja nie dodaje odwo�ania do obiektu, bo nie zak�ada, �e kto� go od razu u�yje. -W ka�dym miejscu, gdzie zostanie przypisany zwr�cony obiekt, nale�y pami�ta� o dodaniu odwo�ania oraz -skasowaniu go, gdy obiekt przestanie by� u�ywany. - -@param[in] name Nazwa bufora, po kt�rej mo�na si� b�dzie odwo�a�. -@param[in] buffer Wska�nik na bufor z danym, kt�re maj� by� przeniesione do bufora DirectXowego. -@param[in] elementSize Rozmiar pojedynczego elementu w buforze. -@param[in] vertCount Liczba wierzcho�k�w/indeks�w w buforze. -@return Dodany bufor indeks�w. Zwraca nullptr, je�eli nie uda�o si� stworzy� bufora.*/ -ResourcePtr< BufferObject > ResourceManager::CreateIndexBuffer( const std::wstring& name, const void* buffer, unsigned int elementSize, unsigned int vertCount ) -{ - IndexBufferInitData initData; - initData.Data = (const uint8*)buffer; - initData.ElementSize = elementSize; - initData.NumElements = vertCount; - return CreateIndexBuffer( name, initData ); -} +//====================================================================================// +// Internal implementation +//====================================================================================// -/**@brief Vreates index buffer. -@return Returns buffer or nullptr if name already exists or buffer creation failed.*/ -ResourcePtr ResourceManager::CreateIndexBuffer ( const std::wstring& name, const IndexBufferInitData& data ) +// ================================ // +// +ResourcePtr< Resource > ResourceManager::FindResource ( const AssetPath& name, TypeID assetType ) { - BufferObject* indexBuff = m_indexBuffer.get( name ); - if ( indexBuff ) // Je�eli znale�li�my bufor, to zwracamy nullptr - return ResourcePtr(); - - - indexBuff = ResourcesFactory::CreateBufferFromMemory( name, data.Data, data.CreateBufferInfo() ); - if ( !indexBuff ) // Bufor m�g� si� nie stworzy�, a nie chcemy dodawa� nullptra do ResourceManagera - return nullptr; - - m_indexBuffer.UnsafeAdd( name, indexBuff ); // Dodali�my bufor - return ResourcePtr( indexBuff ); -} + auto translatedPath = Translate( name ); -/**@brief Dodaje do ResourceManagera bufor sta�ch dla shadera. -Je�eli pod tak� nazw� istnieje jaki� bufor, to zostanie zwr�cony wska�nik na niego. -@note Funkcja nie dodaje odwo�ania do obiektu, bo nie zak�ada, �e kto� go od razu u�yje. -W ka�dym miejscu, gdzie zostanie przypisany zwr�cony obiekt, nale�y pami�ta� o dodaniu odwo�ania oraz -skasowaniu go, gdy obiekt przestanie by� u�ywany. - -@param[in] name Nazwa bufora, po kt�rej mo�na si� b�dzie odwo�a�. -@param[in] buffer Wska�nik na bufor z danym, kt�re maj� by� przeniesione do bufora DirectXowego. -@param[in] size Rozmiar bufora. -@return Dodany bufor indeks�w. Zwraca nullptr, je�eli nie uda�o si� stworzy� bufora.*/ -ResourcePtr< BufferObject > ResourceManager::CreateConstantsBuffer( const std::wstring& name, const void* buffer, unsigned int size ) -{ - ConstantBufferInitData initData; - initData.Data = (const uint8*)buffer; - initData.ElementSize = size; - initData.NumElements = 1; + auto containerIter = m_resources.find( assetType ); + if( containerIter != m_resources.end() ) + { + ResourceContainer< Resource >& container = containerIter->second; + return container.Get( translatedPath ); + } - return CreateConstantsBuffer( name, initData ); + return ResourcePtr< Resource >(); } -/**@brief Creates constant buffer. - -@return Returns buffer or nullptr if name already exists or buffer creation failed.*/ -ResourcePtr ResourceManager::CreateConstantsBuffer ( const std::wstring& name, const ConstantBufferInitData& data ) +// ================================ // +// +IAssetLoader* ResourceManager::FindLoader ( const AssetPath& assetName, TypeID assetType ) { - BufferObject* constBuff = m_constantBuffer.get( name ); - if ( constBuff ) // Je�eli znale�li�my bufor, to zwracamy nullptr - return ResourcePtr(); - - - constBuff = ResourcesFactory::CreateBufferFromMemory( name, data.Data, data.CreateBufferInfo() ); - if ( !constBuff ) // Bufor m�g� si� nie stworzy�, a nie chcemy dodawa� nullptra do ResourceManagera - return nullptr; + for( auto& loader : m_loaders ) + { + if( loader->CanLoad( assetName, assetType ) ) + return loader.get(); + } - m_constantBuffer.UnsafeAdd( name, constBuff ); // Dodali�my bufor - return ResourcePtr( constBuff ); + return nullptr; } -/**@brief Created BlendingState object. - -@return If object named name exist, returns nullptr.*/ -ResourcePtr< BlendingState > ResourceManager::CreateBlendingState ( const std::wstring& name, const BlendingInfo& info ) +// ================================ // +// +std::pair< WaitingAsset*, bool > ResourceManager::LockFileForLoading ( const LoadPath& loadPath ) { - auto resource = m_blendingState.get( name ); - if ( resource ) // Je�eli znale�li�my bufor, to zwracamy nullptr - return ResourcePtr< BlendingState >(); - - resource = ResourcesFactory::CreateBlendingState( info ); - m_blendingState.UnsafeAdd( name, resource ); - - return ResourcePtr< BlendingState >( resource ); + // We want to lock on absolute path without aliases. Otherwise two paths can point to the same asset. + return m_waitingAssets.RequestAsset( loadPath.GetTranslatedPath().GetFile() ); } -/**@brief Created RasterizerState object. - -@return If object named name exist, returns nullptr.*/ -ResourcePtr< RasterizerState > ResourceManager::CreateRasterizerState ( const std::wstring& name, const RasterizerStateInfo& info ) +// ================================ // +// +ResourcePtr< Resource > ResourceManager::FindRequestedAsset ( const LoadPath& loadPath, TypeID assetType, const AssetsVec& loadedAssets ) { - auto resource = m_rasterizerState.get( name ); - if ( resource ) // Je�eli znale�li�my bufor, to zwracamy nullptr - return ResourcePtr< RasterizerState >(); + std::string assetNameStr = loadPath.GetOriginalPath().String(); - resource = ResourcesFactory::CreateRasterizerState( info ); - m_rasterizerState.UnsafeAdd( name, resource ); + for( auto loadedAsset : loadedAssets ) + { + if( loadedAsset->GetResourceName() == assetNameStr && + loadedAsset->GetType().is_derived_from( assetType ) ) + return loadedAsset; + } - return ResourcePtr< RasterizerState >( resource ); -} + // There's no asset that has the same name. We could return first asset in raw maybe... + if( loadedAssets.size() > 0 ) + return loadedAssets[ 0 ]; -/**@brief Created DepthStencilState object. + return nullptr; +} -@return If object named name exist, returns nullptr.*/ -ResourcePtr< DepthStencilState > ResourceManager::CreateDepthStencilState ( const std::wstring& name, const DepthStencilInfo& info ) +// ================================ // +// +sw::Nullable< ResourcePointer > ResourceManager::LoadingImpl ( const LoadPath& loadPath, const IAssetLoadInfo* desc, TypeID assetType ) { - auto resource = m_depthStencilState.get( name ); - if ( resource ) // Je�eli znale�li�my bufor, to zwracamy nullptr - return ResourcePtr< DepthStencilState >(); + // @attention: Remember to remove asset lock before each return statement. + // Otherwise assetName will be locked for loading for always. + + auto resource = m_cacheManager.LoadFromCache( loadPath.GetTranslatedPath(), assetType ); + if( !resource ) + { + auto loader = FindLoader( loadPath.GetOriginalPath(), assetType ); + if( loader ) + { + auto loadingResult = loader->Load( loadPath, assetType, desc, RMLoaderAPI( this ) ); + + if( !loadingResult.Assets.IsValid() ) + { + // Remove asset lock. + m_waitingAssets.LoadingFailed( loadPath.GetFileTranslated(), loadingResult.Assets.GetError() ); + return loadingResult.Assets.GetError(); + } + + resource = FindRequestedAsset( loadPath, assetType, loadingResult.Assets ); + } + else + { + auto exception = std::make_shared< ResourceManagerException >( "Loader for asset not found. ", loadPath.Print(), assetType ); + + // Remove asset lock. + m_waitingAssets.LoadingFailed( loadPath.GetFileTranslated(), exception ); + return exception; + } + } - resource = ResourcesFactory::CreateDepthStencilState( info ); - m_depthStencilState.UnsafeAdd( name, resource ); + // Remove asset lock. + m_waitingAssets.LoadingCompleted( loadPath.GetFileTranslated() ); - return ResourcePtr< DepthStencilState >( resource ); + return resource; } -//====================================================================================// -// Listowanie asset�w -//====================================================================================// +// ================================ // +// +ReturnResult ResourceManager::AddGenericResource ( const AssetPath& name, TypeID assetType, ResourcePointer resource ) +{ + if( !resource ) + return std::make_shared< ResourceManagerException >( "Trying to add nullptr resource.", name.String(), assetType ); + auto translatedName = Translate( name ); -/**@brief Listowanie bufor�w wierzcho�k�w.*/ -std::vector< ResourcePtr< BufferObject > > ResourceManager::ListVertexBuffers() -{ - return m_vertexBuffer.List(); -} + // Check if asset already exists in m_resources. Note that even if asset exists, that doesn't + // mean that it is the same asset. It could be generated by user (and have different content) or it could be loaded + // and postprocessed using different parameters. -/**@brief Listowanie bufor�w indeks�w.*/ -std::vector< ResourcePtr< BufferObject > > ResourceManager::ListIndexBuffers() -{ - return m_indexBuffer.List(); -} + // Lock as Writer, because we want to add Resource atomically. + WriterUniqueLock< ReaderWriterLock > lock( m_rwLock ); -/**@brief Listowanie bufor�w sta�ych.*/ -std::vector< ResourcePtr< BufferObject > > ResourceManager::ListConstantBuffers() -{ - return m_constantBuffer.List(); -} + ResourceContainer< Resource >& container = m_resources[ assetType ]; + bool inserted = container.SafeAdd( translatedName, resource.Ptr() ); -/**@brief Listowanie layout�w wierzcho�k�w.*/ -std::vector< ResourcePtr< ShaderInputLayout > > ResourceManager::ListShaderLayouts() -{ - return m_vertexLayout.List(); -} + if( !inserted ) + return std::make_shared< ResourceManagerException >( "Can't add asset, because it already existed.", name.String(), assetType ); -/**@brief Listowanie tekstur.*/ -std::vector< ResourcePtr< TextureObject > > ResourceManager::ListTextures() -{ - return m_texture.List(); + return Result::Success; } -/**@brief Listowanie vertex shader�w.*/ -std::vector< ResourcePtr< VertexShader > > ResourceManager::ListVertexShaders() +// ================================ // +// +filesystem::Path ResourceManager::Translate ( const filesystem::Path& path ) { - return m_vertexShader.List(); + return LoadPath::Translate( path, m_pathsManager.get() ); } -/**@brief Listowanie pixel shader�w.*/ -std::vector< ResourcePtr< PixelShader > > ResourceManager::ListPixelShaders() +// ================================ // +// +AssetPath ResourceManager::Translate ( const AssetPath& name ) { - return m_pixelShader.List(); + return LoadPath::Translate( name, m_pathsManager.get() ); } -/**@brief Listowanie render target�w.*/ -std::vector< ResourcePtr< RenderTargetObject > > ResourceManager::ListRenderTargets() -{ - return m_renderTarget.List(); -} -/**@brief Implementation of texture loading. -This is hack function. Resource manager have no texture loading function beacause -it needs separate library for this. Derived classes will implement it, but in future -this must change. ResourceManager must be fully operational class. Otherwise GUI -won't load textures.*/ -MemoryChunk ResourceManager::LoadTextureImpl( const filesystem::Path& filePath, TextureInfo& texInfo ) -{ - MemoryChunk fakeChunk( 1024 ); - //assert( !"Implement me" ); - return fakeChunk; -} +} // sw diff --git a/ResourceManager/ResourceManager.h b/ResourceManager/ResourceManager.h index 006cfa0..8780574 100644 --- a/ResourceManager/ResourceManager.h +++ b/ResourceManager/ResourceManager.h @@ -2,130 +2,259 @@ /** @file ResourceManager.h @author nieznanysprawiciel -@copyright File is part of graphic engine SWEngine. +@copyright File is part of Sleeping Wombat Libraries. */ #include "swGraphicAPI/Resources/MeshResources.h" -#include "swGraphicAPI/Resources/BlendingState.h" -#include "swGraphicAPI/Resources/RasterizerState.h" -#include "swGraphicAPI/Resources/DepthStencilState.h" +#include "swGraphicAPI/Resources/PipelineStates/BlendingState.h" +#include "swGraphicAPI/Resources/PipelineStates/RasterizerState.h" +#include "swGraphicAPI/Resources/PipelineStates/DepthStencilState.h" + #include "swGraphicAPI/ResourceManager/ResourceContainer.h" +#include "swGraphicAPI/ResourceManager/PathTranslators/AssetPath.h" +#include "swGraphicAPI/ResourceManager/PathTranslators/PathsManager.h" + +#include "swCommonLib/Common/Multithreading/ReaderWriterLock.h" +#include "swCommonLib/Common/Exceptions/Nullable.h" + +#include "AssetCreators/AssetsFactory.h" +#include "Loaders/IAssetLoader.h" +#include "Cache/CacheManager.h" +#include "AsyncLoad/LoadBarrier.h" + +#include +#include + + + +namespace sw +{ -class ILoader; +/**@defgroup AssetsManagement Assets Management +@brief Class for loading assets and managing their lifetime. +@ingroup GraphicAPI +@copydoc ResourceManagerRequirements +@page ResourceManagerRequirements Resource Manager Requirements -/**@brief Manager for low level resources. +@section RMRequirements ResourceManager requirements -@todo This class should implement generic high level asssets managment. +-# ResourceManager supports generic assets types defined by future users. It should also expose special functions +for built in low level types without need to use this generic API, but these types should be also avaible through generic API. +-# User can write his own implementations of loaders for different file types. +Requirements: + - Loaders implement generic interface, but user can also add parameters for specific loader. + For example FBX SDK loader could load Meshes and merge them all in one asset or it could + create several assets for all parts. + - ResourceManager finds best matching loader and uses it to load asset. + - Loaders support loading of whole content of file. + - Loaders allow to prefetch data and store it in cache, without loading asset. + - Separated asset creation and file loading. + - User uses the same API to generate assets as Loader uses to load file. + - Assets are created using descritpors describing their content. + - User can provide their own implementation of @ref sw::IAssetCreator "Asset Creator". + - Library provides set of basic creators for native GPU Resources. +-# Asynchronous assets loading. Assets can be loaded in separate thread. User provides callback function which will be called +when asset is ready. + - There's separate API for synchronous and asynchronous loading. + - Request can come from multiple threads. In case of synchronous load, when multiple threads want to load the same asset, + all threads are blocked until asset is loaded. ResourceManager takes care of dealing with these conflicts and prevents from loading + same asset multiple times. + - Internal implementation uses only one thread for loading. This should be enough for high performance, since disk access is bottleneck. +-# Paths translation. Some assets' directory can depend on graphic API which is being used (for example shaders glsl or hlsl). +User can register Paths Aliases in ResourceManager and access assets paths using these aliases. ResourceManager translates aliases to +real paths. +Requirements: + - Paths Aliases are user defined so can be used for different purposes too. + - Functionality of finding best matching alias. This functionality is usefull, when editor has browse file dialog and sends absolut + path to ResourceManager. +-# ResourceManager supports packed file which internally consist of many smaller files. + - ResourceManager paths consist of system path and internal path. + - Asset file can contain multiple assets. + - File can have internal filesystem and internal path represent this internal structure. + - ResourceManager supports generated content. Paths should constist only from internal path then. +-# Assets caching. Assets can be cached in RAM memory in raw form to speed up creating. Second cache level can exist on SSD drive. +Requirements: + - Cache automatically manages resources. + - Assets are moved automatically based on chosen cache strategy. + - It supports maximal memory occupancy limit. + - Support for prefetching mechanism. Assets can be loaded from cache depending on prefetching strategy. + - Cache should be aware of assets dependencies. Dependend assets can't be moved to lower cache level before + parent asset is moved. + - Support for multilevel cache hierarchy. User can implement his own cache levels. + - Predefined cache levels: RAM cache and disk cache. + - API for user defined caching strategy. + - API for user defined prefetching strategy. +-# Descriptive error handling. + - Most of API returns @ref sw::Nullable "Nullable", which can hold error message (@ref sw::Exception). + - ResourceManager doesn't throws exceptions. + - Two levels of errors: errors and warnings. +-# Support for level of detailes. +-# Support for asset streaming. +-# Support for hot reload of shaders and other assets where possible. +*/ + +typedef std::vector< IAssetLoaderPtr > LoadersVec; + + +/**@brief Manages resources creation, loading and releasing. -@ingroup ResourcesManagment*/ +@ingroup AssetsManagement*/ class ResourceManager { + typedef std::map< TypeID, ResourceContainer< Resource > > ResourcesMap; + private: protected: - ResourceContainer< BlendingState > m_blendingState; ///< BlendingState objects. - ResourceContainer< RasterizerState > m_rasterizerState; ///< RasterizerState objects. - ResourceContainer< DepthStencilState > m_depthStencilState;///< DepthStencilState objects. - - ResourceContainer< VertexShader > m_vertexShader; ///< Vertex shaders. - ResourceContainer< PixelShader > m_pixelShader; ///< Pixel shaders. - ResourceContainer< GeometryShader > m_geometryShader; ///< Geometry shaders. - ResourceContainer< EvaluationShader > m_evaluationShader; ///< Tesselation evaluation shaders. - ResourceContainer< ControlShader > m_controlShaders; ///< Tesselation control shaders. - - ResourceContainer< TextureObject > m_texture; ///< Textures. - ResourceContainer< BufferObject > m_vertexBuffer; ///< Vertex buffers. - ResourceContainer< BufferObject > m_indexBuffer; ///< Index buffers. - ResourceContainer< BufferObject > m_constantBuffer; ///< Shader constant buffers. - ResourceContainer< ShaderInputLayout > m_vertexLayout; ///< Vertex layouts. - // UWAGA! m_fileModel musi by� na ko�cu. Jego destruktor kasuje odwo�ania do obiekt�w powy�ej. Podobnie RenderTargetObject odwo�uje si� do tekstur. - // Musz� one w tym czasie istnie�, a destruktory s� wywo�ywane w kolejno�ci odwrotnej do zadeklarowanej w klasie. - ResourceContainer< RenderTargetObject > m_renderTarget; /// m_loader; /// + ResourcePtr< AssetType > Get ( const AssetPath& name ); + ///@} ///@name Resource loading ///@detail Load assets from specified file. Functions protect from loading assets multiple times. ///@{ - TextureObject* LoadTexture ( const std::wstring& fileName ); - VertexShader* LoadVertexShader ( const std::wstring& fileName, const std::string& shaderEntry ); - VertexShader* LoadVertexShader ( const std::wstring& fileName, const std::string& shaderEntry, ShaderInputLayout** layout, InputLayoutDescriptor* layout_desc ); - PixelShader* LoadPixelShader ( const std::wstring& fileName, const std::string& shaderEntry ); - GeometryShader* LoadGeometryShader ( const std::wstring& fileName, const std::string& shaderEntry ); - ControlShader* LoadControlShader ( const std::wstring& fileName, const std::string& shaderEntry ); - EvaluationShader* LoadEvaluationShader ( const std::wstring& fileName, const std::string& shaderEntry ); + + sw::Nullable< ResourcePointer > LoadGeneric ( const AssetPath& assetName, const IAssetLoadInfo* desc, TypeID type ); + + /**@brief Loads asset file with it's whole content. + + This function is meant for Editor usage. It will load and return all assets that will be found in specified file. + Moreover all assets from other files, that are referenced by these assets will be loaded too. + If asset alredy existed in ResourceManager, Loader should take this existing asset and return warning. + + @note Note that Loader will be called each time this function is called, even if all assets were loaded. There is + no other way to determine content of file, than to load it again. Loaders should always check if asset existed + and shouldn't spend time on creating not necessary assets, but performance penalty exists and depends on Laoder. + + @note Note that it is posible that file contains assets that couldn't be loaded, because IAssetLoader implementation + doesn't support that. + + @return Returns list of loaded assets or error if loader was unable to load file. Loading results + contains all warnings that occured during loading.*/ + LoadingResult LoadFileGeneric ( const AssetPath& assetName, IAssetLoadInfo* desc, TypeID type ); + LoadingResult LoadFileGeneric ( const AssetPath& assetName, IAssetLoadInfo* desc, TypeID type, IAssetLoader* loader ); ///@} ///@name Resource creation ///@detail You can create assets in code using these functions. Remember to give unique names for your assets. ///Engine uses convention, that all generated resources have :: before name, to distinguish them from assets loaded from files. ///@{ - ResourcePtr< BufferObject > CreateVertexBuffer ( const std::wstring& name, const void* buffer, unsigned int element_size, unsigned int vert_count ); - ResourcePtr< BufferObject > CreateVertexBuffer ( const std::wstring& name, const VertexBufferInitData& data ); - ResourcePtr< BufferObject > CreateIndexBuffer ( const std::wstring& name, const void* buffer, unsigned int element_size, unsigned int vert_count ); - ResourcePtr< BufferObject > CreateIndexBuffer ( const std::wstring& name, const IndexBufferInitData& data ); - ResourcePtr< BufferObject > CreateConstantsBuffer ( const std::wstring& name, const void* buffer, unsigned int size ); - ResourcePtr< BufferObject > CreateConstantsBuffer ( const std::wstring& name, const ConstantBufferInitData& data ); - - ResourcePtr< BlendingState > CreateBlendingState ( const std::wstring& name, const BlendingInfo& info ); - ResourcePtr< RasterizerState > CreateRasterizerState ( const std::wstring& name, const RasterizerStateInfo& info ); - ResourcePtr< DepthStencilState >CreateDepthStencilState ( const std::wstring& name, const DepthStencilInfo& info ); + sw::Nullable< ResourcePointer > CreateGenericAsset ( const AssetPath& name, TypeID assetType, IAssetCreateInfo&& createInfo ); ///@} - RenderTargetObject* AddRenderTarget ( RenderTargetObject* renderTarget, const std::wstring& name ); + + ///@name Reasource freeing api + ///@{ + void FreeUnusedAssets (); + + ///@} ///@name Listing resources ///@{ - std::vector< ResourcePtr< BufferObject > > ListVertexBuffers (); - std::vector< ResourcePtr< BufferObject > > ListIndexBuffers (); - std::vector< ResourcePtr< BufferObject > > ListConstantBuffers (); - std::vector< ResourcePtr< ShaderInputLayout > > ListShaderLayouts (); - - std::vector< ResourcePtr< TextureObject > > ListTextures (); - std::vector< ResourcePtr< VertexShader > > ListVertexShaders (); - std::vector< ResourcePtr< PixelShader > > ListPixelShaders (); - - std::vector< ResourcePtr< RenderTargetObject > > ListRenderTargets (); + std::vector< ResourcePointer > ListAssets ( TypeID assetType ) const; + + template< typename AssetType > + std::vector< ResourcePtr< AssetType > > ListAssetsTyped ( TypeID assetType ) const; + ///@} -private: - //ILoader* FindLoader ( const std::wstring& path ); - - virtual MemoryChunk LoadTextureImpl ( const filesystem::Path& filePath, TextureInfo& texInfo ); +public: + + ///@name Thread unsafe initialization api + /// These api functions should be called on the beginning of the program. + /// @todo Consider doing this API thread safe. + ///@{ + bool RegisterAssetCreator ( IAssetCreatorPtr creator ); + bool RegisterLoader ( IAssetLoaderPtr loader ); + + LoadersVec ListLoaders () const; + + PathsManager* GetPathsManager () const { return m_pathsManager.get(); } + ///@} + + +protected: + + ResourcePtr< Resource > FindResource ( const AssetPath& assetName, TypeID assetType ); + ResourcePtr< Resource > FindRequestedAsset ( const LoadPath& assetName, TypeID assetType, const AssetsVec& loadedAssets ); + IAssetLoader* FindLoader ( const AssetPath& assetName, TypeID assetType ); + + std::pair< WaitingAsset*, bool > LockFileForLoading ( const LoadPath& assetName ); + + sw::Nullable< ResourcePointer > LoadGeneric ( const LoadPath& assetName, const IAssetLoadInfo* desc, TypeID type ); + sw::Nullable< ResourcePointer > LoadingImpl ( const LoadPath& assetName, const IAssetLoadInfo* desc, TypeID assetType ); + + ReturnResult AddGenericResource ( const AssetPath& name, TypeID assetType, ResourcePointer resource ); + + filesystem::Path Translate ( const filesystem::Path& path ); + AssetPath Translate ( const AssetPath& name ); + + void RegisterBasicLoaders(); }; + +//====================================================================================// +// Implementation +//====================================================================================// + + +// ================================ // +// +template< typename AssetType > +inline ResourcePtr< AssetType > ResourceManager::Get ( const AssetPath& assetName ) +{ + auto result = GetGeneric( assetName, TypeID::get< AssetType >() ); + return ResourcePtr< AssetType >( static_cast< AssetType* >( result.Ptr() ) ); +} + +// ================================ // +// +template< typename AssetType > +inline std::vector< ResourcePtr< AssetType > > ResourceManager::ListAssetsTyped ( TypeID assetType ) const +{ + auto containerIter = m_resources.find( assetType ); + if( containerIter != m_resources.end() ) + { + const ResourceContainer< AssetType >& container = containerIter->second; + return container.List< AssetType >(); + } + + return std::vector< ResourcePtr< AssetType > >(); +} + +} // sw + diff --git a/ResourceManager/ResourceManagerAPI.cpp b/ResourceManager/ResourceManagerAPI.cpp new file mode 100644 index 0000000..6431b49 --- /dev/null +++ b/ResourceManager/ResourceManagerAPI.cpp @@ -0,0 +1,279 @@ +/** +@file ResourceManagerAPI.cpp +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + + +#include "swGraphicAPI/ResourceManager/stdafx.h" + +#include "ResourceManagerAPI.h" + +#include "swGraphicAPI/ResourceManager/ResourceManager.h" +#include "swGraphicAPI/ResourceManager/Loaders/TextureLoadInfo.h" + + +namespace sw +{ + +// ================================ // +// +ResourceManagerAPI::ResourceManagerAPI( ResourceManager* resourceManager ) + : m_resourceManager( resourceManager ) +{} + +// ================================ // +// +ResourcePointer ResourceManagerAPI::GetGeneric ( const AssetPath& name, TypeID type ) +{ + return m_resourceManager->GetGeneric( name, type ); +} + +// ================================ // +// +ResourcePointer ResourceManagerAPI::GetCachedGeneric ( const AssetPath& name, TypeID type ) +{ + /// @todo Call creation from cache, when caching mechanism is ready. + return m_resourceManager->GetGeneric( name, type ); +} + +// ================================ // +// +sw::Nullable< ResourcePointer > ResourceManagerAPI::LoadGeneric ( const AssetPath& assetName, const IAssetLoadInfo* desc, TypeID type ) +{ + return m_resourceManager->LoadGeneric( assetName, desc, type ); +} + +// ================================ // +// +Nullable< ResourcePointer > ResourceManagerAPI::CreateGenericAsset ( const AssetPath& name, TypeID assetType, IAssetCreateInfo&& createInfo ) +{ + return m_resourceManager->CreateGenericAsset( name, assetType, std::move( createInfo ) ); +} + +//====================================================================================// +// Non generic API +//====================================================================================// + +// ================================ // +// +Nullable< TexturePtr > ResourceManagerAPI::LoadTexture ( const AssetPath& name ) +{ + return Load< Texture >( name, &TextureLoadInfo() ); +} + +//====================================================================================// +// Shader loading +//====================================================================================// + +// ================================ // +// +Nullable< VertexShaderPtr > ResourceManagerAPI::LoadVertexShader ( const AssetPath& name ) +{ + return LoadShader< VertexShader >( name ); +} + +// ================================ // +// +Nullable< PixelShaderPtr > ResourceManagerAPI::LoadPixelShader ( const AssetPath& name ) +{ + return LoadShader< PixelShader >( name ); +} + +// ================================ // +// +Nullable< GeometryShaderPtr > ResourceManagerAPI::LoadGeometryShader ( const AssetPath& name ) +{ + return LoadShader< GeometryShader >( name ); +} + +// ================================ // +// +Nullable< ControlShaderPtr > ResourceManagerAPI::LoadControlShader ( const AssetPath& name ) +{ + return LoadShader< ControlShader >( name ); +} + +// ================================ // +// +Nullable< EvaluationShaderPtr > ResourceManagerAPI::LoadEvaluationShader ( const AssetPath& name ) +{ + return LoadShader< EvaluationShader >( name ); +} + +// ================================ // +// +Nullable< ComputeShaderPtr > ResourceManagerAPI::LoadComputeShader ( const AssetPath& name ) +{ + return LoadShader< ComputeShader >( name ); +} + +//====================================================================================// +// Shader creation +//====================================================================================// + +// ================================ // +// +Nullable< VertexShaderPtr > ResourceManagerAPI::CreateVertexShader ( const AssetPath& name, std::string code ) +{ + return CreateShader< VertexShader >( name, std::move( code ) ); +} + +// ================================ // +// +Nullable< PixelShaderPtr > ResourceManagerAPI::CreatePixelShader ( const AssetPath& name, std::string code ) +{ + return CreateShader< PixelShader >( name, std::move( code ) ); +} + +// ================================ // +// +Nullable< GeometryShaderPtr > ResourceManagerAPI::CreateGeometryShader ( const AssetPath& name, std::string code ) +{ + return CreateShader< GeometryShader >( name, std::move( code ) ); +} + +// ================================ // +// +Nullable< ControlShaderPtr > ResourceManagerAPI::CreateControlShader ( const AssetPath& name, std::string code ) +{ + return CreateShader< ControlShader >( name, std::move( code ) ); +} + +// ================================ // +// +Nullable< EvaluationShaderPtr > ResourceManagerAPI::CreateEvaluationShader ( const AssetPath& name, std::string code ) +{ + return CreateShader< EvaluationShader >( name, std::move( code ) ); +} + +// ================================ // +// +Nullable< ComputeShaderPtr > ResourceManagerAPI::CreateComputeShader ( const AssetPath& name, std::string code ) +{ + return CreateShader< ComputeShader >( name, std::move( code ) ); +} + +// ================================ // +// +Nullable< ShaderInputLayoutPtr> ResourceManagerAPI::CreateLayout ( const AssetPath& name, InputLayoutDescriptor descriptor ) +{ + return CreateAsset< ShaderInputLayout >( name, std::move( descriptor ) ); +} + +//====================================================================================// +// Buffer creation +//====================================================================================// + +// ================================ // +// +Nullable< BufferPtr > ResourceManagerAPI::CreateVertexBuffer ( const AssetPath& name, BufferRange buffer, uint32 elementSize ) +{ + return CreateVertexBuffer( name, buffer, elementSize, TypeID::get_by_name( "" ) ); +} + +// ================================ // +// +Nullable< BufferPtr > ResourceManagerAPI::CreateVertexBuffer ( const AssetPath& name, BufferRange buffer, uint32 elementSize, TypeID elementType ) +{ + auto initData = CreateBufferDescriptor< VertexBufferInitData >( name, buffer.DataPtr, (uint32)buffer.DataSize, elementSize, elementType ); + + if( !initData.IsValid() ) + return initData.GetError(); + return CreateAsset< Buffer >( name, std::move( initData ).Get() ); +} + +// ================================ // +// +Nullable< BufferPtr > ResourceManagerAPI::CreateVertexBuffer ( const AssetPath& name, const BufferRaw& buffer, uint32 elementSize ) +{ + auto initData = CreateBufferDescriptor< VertexBufferInitData >( name, buffer.GetData(), (uint32)buffer.GetSize(), elementSize, buffer.GetType() ); + + if( !initData.IsValid() ) + return initData.GetError(); + return CreateAsset< Buffer >( name, std::move( initData ).Get() ); +} + +// ================================ // +// +Nullable< BufferPtr > ResourceManagerAPI::CreateIndexBuffer ( const AssetPath& name, BufferRange buffer, uint32 elementSize ) +{ + return CreateIndexBuffer( name, buffer, elementSize, TypeID::get_by_name( "" ) ); +} + +// ================================ // +// +Nullable< BufferPtr > ResourceManagerAPI::CreateIndexBuffer ( const AssetPath& name, BufferRange buffer, uint32 elementSize, TypeID elementType ) +{ + auto initData = CreateBufferDescriptor< IndexBufferInitData >( name, buffer.DataPtr, (uint32)buffer.DataSize, elementSize, elementType ); + + if( !initData.IsValid() ) + return initData.GetError(); + return CreateAsset< Buffer >( name, std::move( initData ).Get() ); +} + +// ================================ // +// +Nullable< BufferPtr > ResourceManagerAPI::CreateIndexBuffer ( const AssetPath& name, const BufferRaw& buffer, uint32 elementSize ) +{ + auto initData = CreateBufferDescriptor< IndexBufferInitData >( name, buffer.GetData(), (uint32)buffer.GetSize(), elementSize, buffer.GetType() ); + + if( !initData.IsValid() ) + return initData.GetError(); + return CreateAsset< Buffer >( name, std::move( initData ).Get() ); +} + +// ================================ // +// +Nullable< BufferPtr > ResourceManagerAPI::CreateConstantsBuffer ( const AssetPath& name, BufferRange buffer ) +{ + return CreateConstantsBuffer( name, buffer, (uint32)buffer.DataSize ); +} + +// ================================ // +// +Nullable< BufferPtr > ResourceManagerAPI::CreateConstantsBuffer ( const AssetPath& name, BufferRange buffer, uint32 elementSize ) +{ + return CreateConstantsBuffer( name, buffer, elementSize, TypeID::get_by_name( "" ) ); +} + +// ================================ // +// +Nullable< BufferPtr > ResourceManagerAPI::CreateConstantsBuffer ( const AssetPath& name, BufferRange buffer, uint32 elementSize, TypeID elementType ) +{ + auto initData = CreateBufferDescriptor< ConstantBufferInitData >( name, buffer.DataPtr, (uint32)buffer.DataSize, elementSize, elementType ); + + if( !initData.IsValid() ) + return initData.GetError(); + return CreateAsset< Buffer >( name, std::move( initData ).Get() ); +} + + +//====================================================================================// +// Pipeline states creation +//====================================================================================// + +// ================================ // +// +Nullable< BlendingStatePtr > ResourceManagerAPI::CreateBlendingState ( const AssetPath& name, const BlendingInfo& info ) +{ + return CreateAsset< BlendingState >( name, BlendingInfo( info ) ); +} + +// ================================ // +// +Nullable< RasterizerStatePtr > ResourceManagerAPI::CreateRasterizerState ( const AssetPath& name, const RasterizerStateInfo& info ) +{ + return CreateAsset< RasterizerState >( name, RasterizerStateInfo( info ) ); +} + +// ================================ // +// +Nullable< DepthStencilStatePtr > ResourceManagerAPI::CreateDepthStencilState ( const AssetPath& name, const DepthStencilInfo& info ) +{ + return CreateAsset< DepthStencilState >( name, DepthStencilInfo( info ) ); +} + + +} // sw + diff --git a/ResourceManager/ResourceManagerAPI.h b/ResourceManager/ResourceManagerAPI.h new file mode 100644 index 0000000..581d986 --- /dev/null +++ b/ResourceManager/ResourceManagerAPI.h @@ -0,0 +1,302 @@ +#pragma once +/** +@file ResourceManagerAPI.h +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + +#include "swGraphicAPI/ResourceManager/Loaders/IAssetLoadInfo.h" +#include "swGraphicAPI/ResourceManager/AssetCreators/IAssetCreateInfo.h" + +#include "swGraphicAPI/Resources/MeshResources.h" +#include "swGraphicAPI/Resources/Shaders/ShaderInitData.h" + +#include "swCommonLib/Common/Buffers/StackBuffer.h" +#include "swCommonLib/Common/Buffers/BufferRange.h" +#include "swCommonLib/Common/Buffers/BufferRaw.h" + + +namespace sw +{ + +class ResourceManager; + + +/**@brief ResourceManager API and additional functions. + +This class exposes full ResourceManager API. Some other API classes inherit this, to hide functions, +that shouldn't be used in different contexts like @ref RMLoaderAPI. + +Except functionalities of ResourceManager, this class can implement helper functions that +provide less generic and more specific resources managment posibilities.*/ +class ResourceManagerAPI +{ +protected: + + ResourceManager* m_resourceManager; ///< Pointer to synchronous resource manager. + +public: + explicit ResourceManagerAPI ( ResourceManager* resourceManager ); + virtual ~ResourceManagerAPI () = default; + +public: + + /**@brief Gets asset that is already loaded or returns nullptr if it isn't. + + Probably there are only rare cases when you want use this function. The main purpose could be checking if assets + were already loaded by ResourceManager. If Loader can't get asset this way, creates new asset himself. + I discourage to use GetGeneric for that. Even if asset doesn't exist in ResourceManager, it can be cached + and ready to load. You should use GetCachedGeneric function in such case. + + The second case is, when Loader wants to load asset referenced by file that he loads. In this case you should + use LoadGeneric function.*/ + ResourcePointer GetGeneric ( const AssetPath& name, TypeID type ); + + /**@brief Gets asset from ResourceManager or tries to create it from cache. + + Function will return nullptr if it won't find asset and is unable to create it from cache. + You should always use this function before creating asset in Loader. There're some reasons causing, that + asset already exist and despite this, Loader was called for the second time: + - Someone requested asset from file, but didn't set Loader flag to load whole content of file. In this case + some assets exist in @ref ResourceManager and some not, so second load request must load remaining content. + - Assets were loaded in the past but they were removed as unnecessary and remained in cache. + - Editor called LoadFileGeneric. This function always tries to load file even if assets existed and Loaders + must be prepared for it. + + Don't use LoadGeneric to load assets from file that you are loading. Load Generic should be used to load + assets referenced by file, but placed in other files.*/ + ResourcePointer GetCachedGeneric ( const AssetPath& name, TypeID type ); + + /**@copydoc ResourceManager::LoadGeneric*/ + sw::Nullable< ResourcePointer > LoadGeneric ( const AssetPath& assetName, const IAssetLoadInfo* desc, TypeID type ); + + /**Typed version of LoadGeneric. + @copydoc ResourceManager::LoadGeneric*/ + template< typename AssetType > + sw::Nullable< ResourcePtr< AssetType > > Load ( const AssetPath& assetName, const IAssetLoadInfo* desc ); + + /**@brief Typed version of GetCachedGeneric. + @copydoc ResourceManagerAPI::GetCachedGeneric*/ + template< typename AssetType > + ResourcePtr< AssetType > GetCached ( const AssetPath& name ); + + /**@copydoc ResourceManager::CreateGenericAsset*/ + sw::Nullable< ResourcePointer > CreateGenericAsset ( const AssetPath& name, TypeID assetType, IAssetCreateInfo&& createInfo ); + + /**Typed version of CreateGenericAsset. + @copydoc ResourceManager::CreateGenericAsset*/ + template< typename AssetType > + sw::Nullable< ResourcePtr< AssetType > > CreateAsset ( const AssetPath& name, IAssetCreateInfo&& createInfo ); + +public: + + Nullable< TexturePtr > LoadTexture ( const AssetPath& name ); + + /// @name Shader loading functions. + /// Load shader file. Parameter name can contain shader entrypoint as internal path. + /// If internal path is empty, default entrpoint (main) will be added. + ///@{ + Nullable< VertexShaderPtr > LoadVertexShader ( const AssetPath& name ); + Nullable< PixelShaderPtr > LoadPixelShader ( const AssetPath& name ); + Nullable< GeometryShaderPtr > LoadGeometryShader ( const AssetPath& name ); + Nullable< ControlShaderPtr > LoadControlShader ( const AssetPath& name ); + Nullable< EvaluationShaderPtr > LoadEvaluationShader ( const AssetPath& name ); + Nullable< ComputeShaderPtr > LoadComputeShader ( const AssetPath& name ); + + ///@} + + + /// @name Shader creation + /// Generate shaders and create them from code. To load shaders from file use + /// loading functions. + ///@{ + Nullable< VertexShaderPtr > CreateVertexShader ( const AssetPath& name, std::string code ); + Nullable< PixelShaderPtr > CreatePixelShader ( const AssetPath& name, std::string code ); + Nullable< GeometryShaderPtr > CreateGeometryShader ( const AssetPath& name, std::string code ); + Nullable< ControlShaderPtr > CreateControlShader ( const AssetPath& name, std::string code ); + Nullable< EvaluationShaderPtr > CreateEvaluationShader ( const AssetPath& name, std::string code ); + Nullable< ComputeShaderPtr > CreateComputeShader ( const AssetPath& name, std::string code ); + + Nullable< ShaderInputLayoutPtr > CreateLayout ( const AssetPath& name, InputLayoutDescriptor descriptor ); + + template< typename ShaderType > + Nullable< ResourcePtr< ShaderType > > CreateShader ( const AssetPath& name, std::string code ); + ///@} + + /// @name Buffers creation functions. + ///@{ + Nullable< BufferPtr > CreateVertexBuffer ( const AssetPath& name, BufferRange buffer, uint32 elementSize ); + Nullable< BufferPtr > CreateVertexBuffer ( const AssetPath& name, BufferRange buffer, uint32 elementSize, TypeID elementType ); + Nullable< BufferPtr > CreateVertexBuffer ( const AssetPath& name, const BufferRaw& buffer, uint32 elementSize ); + + Nullable< BufferPtr > CreateIndexBuffer ( const AssetPath& name, BufferRange buffer, uint32 elementSize ); + Nullable< BufferPtr > CreateIndexBuffer ( const AssetPath& name, BufferRange buffer, uint32 elementSize, TypeID elementType ); + Nullable< BufferPtr > CreateIndexBuffer ( const AssetPath& name, const BufferRaw& buffer, uint32 elementSize ); + + template< typename IndexType > + Nullable< BufferPtr > CreateIndexBuffer ( const AssetPath& name, BufferRange buffer ); + + /**@brief Creates constants buffer with element of size of whole buffer. + @note Function doesn't set buffer data type.*/ + Nullable< BufferPtr > CreateConstantsBuffer ( const AssetPath& name, BufferRange buffer ); + Nullable< BufferPtr > CreateConstantsBuffer ( const AssetPath& name, BufferRange buffer, uint32 elementSize ); + Nullable< BufferPtr > CreateConstantsBuffer ( const AssetPath& name, BufferRange buffer, uint32 elementSize, TypeID elementType ); + + /**@brief Creates buffer from local structure allocated on stack. + @note Function sets buffer data type. Data type is not necessary to work, but it helps + for debugging and type retrospection in editor. It is recommended to use typed functions.*/ + template< typename DataStruct > + Nullable< BufferPtr > CreateConstantsBuffer ( const AssetPath& name, const StackBufferA< DataStruct >& buffer ); + + ///@} + + + /// @name Pipeline State creation + ///@{ + Nullable< BlendingStatePtr > CreateBlendingState ( const AssetPath& name, const BlendingInfo& info ); + Nullable< RasterizerStatePtr > CreateRasterizerState ( const AssetPath& name, const RasterizerStateInfo& info ); + Nullable< DepthStencilStatePtr > CreateDepthStencilState ( const AssetPath& name, const DepthStencilInfo& info ); + + ///@} + + +protected: + + template< typename ShaderType > + Nullable< ResourcePtr< ShaderType > > LoadShader ( const AssetPath& name ); + + template< typename BufferDescType > + Nullable< BufferDescType > CreateBufferDescriptor ( const AssetPath& name, const uint8* data, uint32 dataSize, uint32 elementSize, TypeID elementType ); +}; + + +//====================================================================================// +// Implementation +//====================================================================================// + + + + +// ================================ // +// +template< typename AssetType > +inline sw::Nullable< ResourcePtr< AssetType > > ResourceManagerAPI::Load ( const AssetPath& assetName, const IAssetLoadInfo* desc ) +{ + auto assetLoadResult = LoadGeneric( assetName, desc, TypeID::get< AssetType >() ); + + /// @todo It would be nice if Nullable could make this conversion by itself. + /// It's imposible, because we store ResorucePtr in Nullable and wrappers + /// types aren't related. + if( assetLoadResult.IsValid() ) + return ResourcePtr< AssetType >( static_cast< AssetType* >( assetLoadResult.Get().Ptr() ) ); + else + return assetLoadResult.GetError(); +} + +// ================================ // +// +template< typename AssetType > +inline ResourcePtr< AssetType > ResourceManagerAPI::GetCached ( const AssetPath& name ) +{ + auto resource = GetCachedGeneric( name, TypeID::get< AssetType >() ); + + // Cast to typed asset. + return ResourcePtr< AssetType >( static_cast< AssetType* >( resource.Ptr() ) ); +} + +// ================================ // +// +template< typename AssetType > +inline sw::Nullable< ResourcePtr< AssetType > > ResourceManagerAPI::CreateAsset ( const AssetPath& name, IAssetCreateInfo&& createInfo ) +{ + auto creationResult = CreateGenericAsset( name, TypeID::get< AssetType >(), std::move( createInfo ) ); + + /// @todo It would be nice if Nullable could make this conversion by itself. + /// It's imposible, because we store ResorucePtr in Nullable and wrappers + /// types aren't related. + if( creationResult.IsValid() ) + return ResourcePtr< AssetType >( static_cast< AssetType* >( creationResult.Get().Ptr() ) ); + else + return creationResult.GetError(); +} + +// ================================ // +// +template< typename ShaderType > +inline Nullable< ResourcePtr< ShaderType > > ResourceManagerAPI::CreateShader ( const AssetPath& name, std::string code ) +{ + ShaderCodeInitData init( ShaderInitData::GetFromTypeID( TypeID::get< ShaderType >() ), std::move( code ) ); + + // Check if InternalPath contains anything. We should use entrypoint + // from AssetPath, if it's posible or use default otherwise. + if( !name.GetInternalPath().HasFileName() ) + { + init.EntryFunction = name.GetInternalPath().String(); + } + + return CreateAsset< ShaderType >( name, std::move( init ) ); +} + +// ================================ // +// +template< typename IndexType > +inline Nullable< BufferPtr > ResourceManagerAPI::CreateIndexBuffer ( const AssetPath& name, BufferRange buffer ) +{ + return CreateIndexBuffer( name, buffer, sizeof( IndexType ), TypeID::get< IndexType >() ); +} + +// ================================ // +// +template< typename DataStruct > +inline Nullable< BufferPtr > ResourceManagerAPI::CreateConstantsBuffer ( const AssetPath& name, const StackBufferA< DataStruct >& buffer ) +{ + return CreateConstantsBuffer( name, buffer.GetView(), (uint32)buffer.GetSize(), TypeID::get< DataStruct >() ); +} + +//====================================================================================// +// Private helper functions +//====================================================================================// + +// ================================ // +// +template< typename ShaderType > +inline Nullable< ResourcePtr< ShaderType > > ResourceManagerAPI::LoadShader ( const AssetPath& name ) +{ + // Check if InternalPath contains anything. If not we should append + // default shader entrypoint function. + if( !name.GetInternalPath().HasFileName() ) + { + AssetPath path( name.GetFile(), "main" ); + return Load< ShaderType >( path, nullptr ); + } + + return Load< ShaderType >( name, nullptr ); +} + +// ================================ // +// +template< typename BufferDescType > +inline Nullable< BufferDescType > ResourceManagerAPI::CreateBufferDescriptor ( const AssetPath& name, + const uint8* data, + uint32 dataSize, + uint32 elementSize, + TypeID elementType ) +{ + if( data == nullptr || + dataSize == 0 ) + return fmt::format( "Trying to create constant bufffer [{}] using empty BufferRange.", name ); + + if( elementSize == 0 ) + return fmt::format( "Trying to create constant bufffer [{}] using [elementSize=0].", name ); + + BufferDescType initData; + initData.Data = data; + initData.ElementSize = elementSize; + initData.DataType = elementType; + initData.NumElements = dataSize / elementSize; + + return initData; +} + +} // sw + diff --git a/ResourceManager/stdafx.h b/ResourceManager/stdafx.h index 9aea665..6ed6226 100644 --- a/ResourceManager/stdafx.h +++ b/ResourceManager/stdafx.h @@ -21,14 +21,22 @@ #include "swCommonLib/Common/RTTR.h" #include "swGraphicAPI/Resources/MeshResources.h" -#include "swGraphicAPI/Resources/BlendingState.h" -#include "swGraphicAPI/Resources/DepthStencilState.h" -#include "swGraphicAPI/Resources/RasterizerState.h" +#include "swGraphicAPI/Resources/PipelineStates/BlendingState.h" +#include "swGraphicAPI/Resources/PipelineStates/DepthStencilState.h" +#include "swGraphicAPI/Resources/PipelineStates/RasterizerState.h" #include "swGraphicAPI/Rendering/GraphicAPIConstants.h" #include "swGraphicAPI/ResourceManager/ResourceManager.h" #include "swGraphicAPI/Resources/ResourcesFactory.h" #include "swGraphicAPI/Resources/SwapChain.h" +#include "swGraphicAPI/ResourceManager/PathTranslators/LoadPath.h" +#include "swGraphicAPI/ResourceManager/PathTranslators/AssetPath.h" + +#include "swGraphicAPI/ResourceManager/Loaders/IAssetLoader.h" +#include "swGraphicAPI/ResourceManager/Loaders/IAssetLoadInfo.h" + +#include "swGraphicAPI/ResourceManager/AssetCreators/IAssetCreator.h" + #undef min #undef max #undef RegisterClass diff --git a/Resources/Buffers/Buffer.cpp b/Resources/Buffers/Buffer.cpp new file mode 100644 index 0000000..1864d53 --- /dev/null +++ b/Resources/Buffers/Buffer.cpp @@ -0,0 +1,59 @@ +/** +@file Buffer.cpp +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ +#include "swGraphicAPI/ResourceManager/stdafx.h" + +#include "Buffer.h" + + +using namespace sw; + +RTTR_REGISTRATION +{ + + // Buffer + rttr::registration::class_< Buffer >( "sw::Buffer" ) + .property_readonly( "Descriptor", &Buffer::GetDescriptor ) BIND_AS_PTR; + + rttr::registration::class_< BufferInfo >( "sw::BufferInfo" ) + .property_readonly( "NumberElements", &BufferInfo::NumElements ) + .property_readonly( "ElementSize", &BufferInfo::ElementSize ) + .property_readonly( "Usage", &BufferInfo::Usage ) + .property_readonly( "BufferType", &BufferInfo::BufferType ) + .property_readonly( "Topology", &BufferInfo::Topology ) + .property_readonly( "4 Bytes Index Size", &BufferInfo::Use4BytesIndex ) + .property_readonly( "VertexLayout", &BufferInfo::VertexLayout ); + + rttr::registration::class_< BufferInitData >( "sw::BufferInitData" ); + rttr::registration::class_< ConstantBufferInitData >( "sw::ConstantBufferInitData" ); + rttr::registration::class_< VertexBufferInitData >( "sw::VertexBufferInitData" ); + rttr::registration::class_< IndexBufferInitData >( "sw::IndexBufferInitData" ); + +} + + +namespace sw +{ + +// ================================ // +// +Buffer::Buffer( const AssetPath& assetPath, unsigned int elementSize, unsigned int elementCount ) + : IBuffer( assetPath ) + , m_elementSize( elementSize ) + , m_elementCount( elementCount ) +{} + +// ================================ // +// +TypeID BufferInitData::GetAssetType () const +{ + return TypeID::get< Buffer >(); +} + + + + +} // sw + diff --git a/Resources/Buffers/Buffer.h b/Resources/Buffers/Buffer.h new file mode 100644 index 0000000..0282c56 --- /dev/null +++ b/Resources/Buffers/Buffer.h @@ -0,0 +1,47 @@ +#pragma once +/** +@file Buffer.h +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + +#include "swGraphicAPI/Resources/Buffers/IBuffer.h" +#include "swGraphicAPI/Resources/Buffers/BufferInitData.h" + + + +namespace sw +{ + + + +/**@brief Object for GPU buffer. + +It can be vertex, index or constant buffer. + +@ingroup Buffers +@ingroup Resources +@ingroup GraphicAPI*/ +class Buffer : public IBuffer +{ + RTTR_ENABLE( IBuffer ) +protected: + + unsigned int m_elementSize; ///< Element size. + unsigned int m_elementCount; ///< Number of elements. + + virtual ~Buffer () = default; +public: + + explicit Buffer ( const AssetPath& assetPath, unsigned int elementSize, unsigned int elementCount ); + + inline unsigned int GetStride () const { return m_elementSize; } + inline unsigned int GetElementSize () const { return m_elementSize; } + inline unsigned int GetElementCount () const { return m_elementCount; } +}; + +DEFINE_RESOURCE_PTR_TYPE( Buffer ); + + +} // sw + diff --git a/Resources/BufferInitData.h b/Resources/Buffers/BufferInitData.h similarity index 61% rename from Resources/BufferInitData.h rename to Resources/Buffers/BufferInitData.h index 520fa7c..446e1b6 100644 --- a/Resources/BufferInitData.h +++ b/Resources/Buffers/BufferInitData.h @@ -1,42 +1,83 @@ #pragma once +/** +@file BufferInitData.h +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ -#include "swCommonLib/Common/MemoryChunk.h" + +#include "swCommonLib/Common/Buffers/BufferRange.h" #include "swCommonLib/Common/RTTR.h" #include "swGraphicAPI/Rendering/GraphicAPIConstants.h" -#include "swGraphicAPI/Resources/IBuffer.h" +#include "swGraphicAPI/Resources/Buffers/IBuffer.h" +#include "swGraphicAPI/Resources/ResourcePtr.h" + +#include "swGraphicAPI/ResourceManager/AssetCreators/IAssetCreateInfo.h" #include -/**@brief Buffer initialization data.*/ -struct BufferInitData + + + +namespace sw +{ + +class Buffer; + + +/**@brief Buffer initialization data. + +@attention This structure doesn't take ownership of Data. Use only in synchronous api. + +@ingroup Buffers*/ +struct BufferInitData : public sw::IAssetCreateInfo { const uint8* Data; ///< Pointer must be valid only in time of creation. uint32 NumElements; uint32 ElementSize; - rttr::type DataType; ///< [Optional] Type of single element in buffer. + TypeID DataType; ///< [Optional] Type of single element in buffer. ResourceUsage Usage; + +// ================================ // +// BufferInitData() - : DataType( rttr::type::get_by_name( "" ) ) // Set invalid type. + : DataType( rttr::type::get_by_name( "" ) ) // Set invalid type. { - Usage = ResourceUsage::RESOURCE_USAGE_DEFAULT; + Usage = ResourceUsage::Default; NumElements = 1; ElementSize = 0; Data = nullptr; } + + virtual TypeID GetAssetType () const override; + +public: + RTTR_ENABLE( sw::IAssetCreateInfo ); }; -/**@brief Constant buffer initialization data.*/ +/**@brief Constant buffer initialization data. + +@attention This structure doesn't take ownership of Data. Use only in synchronous api. + +@ingroup Buffers*/ struct ConstantBufferInitData : public BufferInitData { BufferInfo CreateBufferInfo() const; + +public: + RTTR_ENABLE( BufferInitData ); }; -/**@brief Vertex buffer initialization data.*/ +/**@brief Vertex buffer initialization data. + +@attention This structure doesn't take ownership of Data. Use only in synchronous api. + +@ingroup Buffers*/ struct VertexBufferInitData : public BufferInitData { ResourcePtr< ShaderInputLayout > VertexLayout; ///< [Optional] Layout of single vertex in buffer. You can add this layout to enable additional information in editor. Otherwise set to nullptr. @@ -44,13 +85,20 @@ struct VertexBufferInitData : public BufferInitData VertexBufferInitData() { - Topology = PrimitiveTopology::PRIMITIVE_TOPOLOGY_POINTLIST; + Topology = PrimitiveTopology::Points; } BufferInfo CreateBufferInfo() const; + +public: + RTTR_ENABLE( BufferInitData ); }; -/**@brief Index buffer initialization data.*/ +/**@brief Index buffer initialization data. + +@attention This structure doesn't take ownership of Data. Use only in synchronous api. + +@ingroup Buffers*/ struct IndexBufferInitData : public BufferInitData { PrimitiveTopology Topology; ///< [Optional] Topology of verticies. @note Index buffer topology override vertex buffer topology. @@ -58,11 +106,14 @@ struct IndexBufferInitData : public BufferInitData IndexBufferInitData() { - Topology = PrimitiveTopology::PRIMITIVE_TOPOLOGY_POINTLIST; + Topology = PrimitiveTopology::Points; Use4BytesIndex = false; } BufferInfo CreateBufferInfo() const; + +public: + RTTR_ENABLE( BufferInitData ); }; @@ -75,7 +126,7 @@ inline BufferInfo ConstantBufferInitData::CreateBufferInfo() const info.ElementSize = ElementSize; info.NumElements = NumElements; info.DataType = DataType; - info.Topology = PrimitiveTopology::PRIMITIVE_TOPOLOGY_POINTLIST; + info.Topology = PrimitiveTopology::Points; info.Usage = Usage; info.Use4BytesIndex = false; @@ -117,3 +168,5 @@ inline BufferInfo IndexBufferInitData::CreateBufferInfo() const return info; } + +} // sw \ No newline at end of file diff --git a/Resources/IBuffer.h b/Resources/Buffers/IBuffer.h similarity index 82% rename from Resources/IBuffer.h rename to Resources/Buffers/IBuffer.h index d178bc1..cc52cb0 100644 --- a/Resources/IBuffer.h +++ b/Resources/Buffers/IBuffer.h @@ -13,9 +13,23 @@ #include "swCommonLib/System/Path.h" -/**@defgroup Buffers -@ingroup Resources -*/ +/**@defgroup Buffers Buffers + +@brief GPU buffer objects. +@detail + +Buffer initialization classes: +- @ref ConstantBufferInitData +- @ref IndexBufferInitData +- @ref VertexBufferInitData + +@ingroup Resources*/ + + + +namespace sw +{ + class ShaderInputLayout; @@ -30,7 +44,7 @@ enum class BufferType : uint8 }; -/**@brief Descriptor of buffer. +/**@brief Descriptor of buffer hold by @ref Buffer. @ingroup Buffers*/ struct BufferInfo { @@ -39,7 +53,6 @@ struct BufferInfo rttr::type DataType; ///< [Optional] Type of single element in buffer. ResourceUsage Usage; ///< Usage of resource by graphic card. BufferType BufferType; ///< Vertex, index or constant buffer. - filesystem::Path Name; ///< Buffer name or file path. ///@name Only for vertex or index buffer. ///@{ @@ -61,23 +74,26 @@ struct BufferInfo : DataType( rttr::type::get_by_name( "" ) ) // Set invalid type. {} - std::string GetName () const { return Name.String(); } }; /**@brief Base class for buffers. @ingroup Buffers @ingroup Resources*/ -class IBuffer : public ResourceObject +class IBuffer : public Resource { - RTTR_ENABLE( ResourceObject ) + RTTR_ENABLE( Resource ) private: protected: - IBuffer() : ResourceObject( 0 ) {} - virtual ~IBuffer() = default; + explicit IBuffer ( const AssetPath& assetPath ) : Resource( assetPath ) {} + virtual ~IBuffer () = default; public: virtual MemoryChunk CopyData () = 0; ///; -private: -protected: - - virtual ~DepthStencilState() = default; - -public: - explicit DepthStencilState() - : ResourceObject( 0 ) - {} - - virtual const DepthStencilInfo& GetDescriptor () = 0; -}; diff --git a/Resources/IRenderTarget.h b/Resources/IRenderTarget.h deleted file mode 100644 index d2ae574..0000000 --- a/Resources/IRenderTarget.h +++ /dev/null @@ -1,18 +0,0 @@ -#pragma once -/** -@file IRenderTarget.h -@author nieznanysprawiciel -@copyright Plik jest cz�ci� silnika graficznego SWEngine. -*/ - -#include "ResourceObject.h" - -class IRenderTarget : public ResourceObject -{ - RTTR_ENABLE( ResourceObject ); -private: -protected: - IRenderTarget() : ResourceObject( 0 ) {} - virtual ~IRenderTarget() = default; -public: -}; \ No newline at end of file diff --git a/Resources/IShader.h b/Resources/IShader.h deleted file mode 100644 index 63d8616..0000000 --- a/Resources/IShader.h +++ /dev/null @@ -1,34 +0,0 @@ -#pragma once -/** -@file IShader.h -@author nieznanysprawiciel -@copyright Plik jest cz�ci� silnika graficznego SWEngine. -*/ - - -#include "swGraphicAPI/Resources/ResourceObject.h" - -#include - - - -class IShader : public ResourceObject -{ - RTTR_ENABLE( ResourceObject ) -private: -protected: - std::string m_shaderEntry; ///< Nazwa g�ownej funkcji shadera. - std::wstring m_shaderFile; ///< �cie�ka do pliku z shaderem. -protected: - IShader() : ResourceObject( 0 ) {} - virtual ~IShader() = default; -public: - const std::wstring& GetShaderFile () const { return m_shaderFile; } - const std::string& GetShaderEntry () const { return m_shaderEntry; } - - - virtual bool ReloadFromFile () = 0; - virtual bool ReloadFromBinFile () = 0; - virtual void SaveShaderBinFile ( const std::wstring& file_name ) = 0; -}; - diff --git a/Resources/IShaderInputLayout.h b/Resources/IShaderInputLayout.h deleted file mode 100644 index 4259ccc..0000000 --- a/Resources/IShaderInputLayout.h +++ /dev/null @@ -1,23 +0,0 @@ -#pragma once -/** -@file IShader.h -@author nieznanysprawiciel -@copyright Plik jest cz�ci� silnika graficznego SWEngine. -*/ - - -#include "swGraphicAPI/Resources/ResourceObject.h" - - - -class IShaderInputLayout : public ResourceObject -{ - RTTR_ENABLE( ResourceObject ); -private: -protected: - IShaderInputLayout() : ResourceObject( 0 ) {} - virtual ~IShaderInputLayout() = default; -public: - -}; - diff --git a/Resources/MeshResources.cpp b/Resources/MeshResources.cpp index ee985b3..b4ef72b 100644 --- a/Resources/MeshResources.cpp +++ b/Resources/MeshResources.cpp @@ -1,20 +1,23 @@ /** @file MeshResources.cpp @author nieznanysprawiciel -@copyright File is part of graphic engine SWEngine. +@copyright File is part of Sleeping Wombat Libraries. */ #include "swGraphicAPI/ResourceManager/stdafx.h" #include "swGraphicAPI/Resources/ResourcesFactory.h" -#include "RasterizerState.h" -#include "BlendingState.h" -#include "DepthStencilState.h" +#include "swGraphicAPI/Resources/PipelineStates/RasterizerState.h" +#include "swGraphicAPI/Resources/PipelineStates/BlendingState.h" +#include "swGraphicAPI/Resources/PipelineStates/DepthStencilState.h" #include "swCommonLib/Common/MemoryLeaks.h" +using namespace sw; + + RTTR_REGISTRATION { RTTR_REGISTRATION_STANDARD_TYPE_VARIANTS( std::wstring ); @@ -24,15 +27,15 @@ RTTR_REGISTRATION //====================================================================================// - rttr::registration::enumeration< ResourceUsage >( "ResourceUsage" ) + rttr::registration::enumeration< ResourceUsage >( "sw::ResourceUsage" ) ( - rttr::value( "Default", ResourceUsage::RESOURCE_USAGE_DEFAULT ), - rttr::value( "Dynamic", ResourceUsage::RESOURCE_USAGE_DYNAMIC ), - rttr::value( "Staging", ResourceUsage::RESOURCE_USAGE_STAGING ), - rttr::value( "Static", ResourceUsage::RESOURCE_USAGE_STATIC ) + rttr::value( "Default", ResourceUsage::Default ), + rttr::value( "Dynamic", ResourceUsage::Dynamic ), + rttr::value( "Staging", ResourceUsage::Staging ), + rttr::value( "Static", ResourceUsage::Static ) ); - rttr::registration::enumeration< BlendOperation >( "BlendOperation" ) + rttr::registration::enumeration< BlendOperation >( "sw::BlendOperation" ) ( rttr::value( "Add", BlendOperation::Add ), rttr::value( "Subtract", BlendOperation::Subtract ), @@ -42,7 +45,7 @@ RTTR_REGISTRATION ); - rttr::registration::enumeration< BlendFactor >( "BlendFactor" ) + rttr::registration::enumeration< BlendFactor >( "sw::BlendFactor" ) ( rttr::value( "Zero", BlendFactor::Zero ), rttr::value( "One", BlendFactor::One ), @@ -58,20 +61,20 @@ RTTR_REGISTRATION rttr::value( "InverseBlendFactor", BlendFactor::InverseBlendFactor ) ); - rttr::registration::enumeration< CullMode >( "CullMode" ) + rttr::registration::enumeration< CullMode >( "sw::CullMode" ) ( rttr::value( "Front", CullMode::Front ), rttr::value( "Back", CullMode::Back ), rttr::value( "None", CullMode::None ) ); - rttr::registration::enumeration< FillMode >( "FillMode" ) + rttr::registration::enumeration< FillMode >( "sw::FillMode" ) ( rttr::value( "Solid", FillMode::Solid ), rttr::value( "Wireframe", FillMode::Wireframe ) ); - rttr::registration::enumeration< ResourceFormat >( "ResourceFormat" ) + rttr::registration::enumeration< ResourceFormat >( "sw::ResourceFormat" ) ( rttr::value( "Unknown", ResourceFormat::RESOURCE_FORMAT_UNKNOWN ), rttr::value( "R32G32B32A32_TYPELESS", ResourceFormat::RESOURCE_FORMAT_R32G32B32A32_TYPELESS ), @@ -194,7 +197,7 @@ RTTR_REGISTRATION rttr::value( "V408", ResourceFormat::RESOURCE_FORMAT_V408 ) ); - rttr::registration::enumeration< ShaderType >( "ShaderType" ) + rttr::registration::enumeration< ShaderType >( "sw::ShaderType" ) ( rttr::value( "VertexShader", ShaderType::VertexShader ), rttr::value( "PixelShader", ShaderType::PixelShader ), @@ -205,7 +208,7 @@ RTTR_REGISTRATION ); - rttr::registration::enumeration< BufferType >( "BufferType" ) + rttr::registration::enumeration< BufferType >( "sw::BufferType" ) ( rttr::value( "VertexBuffer", BufferType::VertexBuffer ), rttr::value( "IndexBuffer", BufferType::IndexBuffer ), @@ -213,40 +216,40 @@ RTTR_REGISTRATION ); - rttr::registration::enumeration< PrimitiveTopology >( "PrimitiveTopology" ) + rttr::registration::enumeration< PrimitiveTopology >( "sw::PrimitiveTopology" ) ( - rttr::value( "Points", PrimitiveTopology::PRIMITIVE_TOPOLOGY_POINTLIST ), - rttr::value( "Lines", PrimitiveTopology::PRIMITIVE_TOPOLOGY_LINELIST ), - rttr::value( "LinesAdjacency", PrimitiveTopology::PRIMITIVE_TOPOLOGY_LINELIST_ADJ ), - rttr::value( "LineStrip", PrimitiveTopology::PRIMITIVE_TOPOLOGY_LINESTRIP ), - rttr::value( "LineStripAdjacency", PrimitiveTopology::PRIMITIVE_TOPOLOGY_LINESTRIP_ADJ ), - rttr::value( "Triangles", PrimitiveTopology::PRIMITIVE_TOPOLOGY_TRIANGLELIST ), - rttr::value( "TrianglesAdjacency", PrimitiveTopology::PRIMITIVE_TOPOLOGY_TRIANGLELIST_ADJ ), - rttr::value( "TriangleStrip", PrimitiveTopology::PRIMITIVE_TOPOLOGY_TRIANGLESTRIP ), - rttr::value( "TriangleStripAdjacency", PrimitiveTopology::PRIMITIVE_TOPOLOGY_TRIANGLESTRIP_ADJ ) + rttr::value( "Points", PrimitiveTopology::Points ), + rttr::value( "Lines", PrimitiveTopology::Lines ), + rttr::value( "LinesAdjacency", PrimitiveTopology::LinesAdjacency ), + rttr::value( "LineStrip", PrimitiveTopology::LineStrip ), + rttr::value( "LineStripAdjacency", PrimitiveTopology::LineStripAdjacency ), + rttr::value( "Triangles", PrimitiveTopology::Triangles ), + rttr::value( "TrianglesAdjacency", PrimitiveTopology::TrianglesAdjacency ), + rttr::value( "TriangleStrip", PrimitiveTopology::TriangleStrip ), + rttr::value( "TriangleStripAdjacency", PrimitiveTopology::TriangleStripAdjacency ) ); //====================================================================================// // Resources //====================================================================================// - rttr::registration::class_< ResourceObject >( "ResourceObject" ) - .property_readonly( "ID", &ResourceObject::m_uniqueId ) + rttr::registration::class_< Resource >( "sw::Resource" ) + .property_readonly( "ID", &Resource::m_uniqueId ) ( rttr::metadata( MetaDataType::AllowInSaveFile, false), rttr::metadata( MetaDataType::Serialize, false ) ) - .property_readonly( "References", &ResourceObject::m_objectReferences ) + .property_readonly( "References", &Resource::m_objectReferences ) ( rttr::metadata( MetaDataType::AllowInSaveFile, false), rttr::metadata( MetaDataType::Serialize, false ) ); - rttr::registration::class_< SwapChain >( "SwapChain" ); + rttr::registration::class_< SwapChain >( "sw::SwapChain" ); // Blending - rttr::registration::class_< BlendingInfo >( "BlendingInfo" ) + rttr::registration::class_< BlendingInfo >( "sw::BlendingInfo" ) .property_readonly( "CustomBlendFactor", &BlendingInfo::CustomBlendFactor ) BIND_AS_PTR .property_readonly( "EnableBlending", &BlendingInfo::EnableBlending ) .property_readonly( "ColorOperation", &BlendingInfo::ColorOperation ) @@ -256,12 +259,12 @@ RTTR_REGISTRATION .property_readonly( "SrcAlphaBlend", &BlendingInfo::SrcAlphaBlend ) .property_readonly( "DstAlphaBlend", &BlendingInfo::DstAlphaBlend ); - rttr::registration::class_< BlendingState >( "BlendingState" ) + rttr::registration::class_< BlendingState >( "sw::BlendingState" ) .property_readonly( "Descriptor", &BlendingState::GetDescriptor ) BIND_AS_PTR; // Rasterizer - rttr::registration::class_< RasterizerStateInfo >( "RasterizerStateInfo" ) + rttr::registration::class_< RasterizerStateInfo >( "sw::RasterizerStateInfo" ) .property_readonly( "CullMode", &RasterizerStateInfo::CullMode ) .property_readonly( "FillMode", &RasterizerStateInfo::FillMode ) .property_readonly( "IsClockwise", &RasterizerStateInfo::IsClockwise ) @@ -271,167 +274,20 @@ RTTR_REGISTRATION .property_readonly( "DepthBias", &RasterizerStateInfo::DepthBias ); - rttr::registration::class_< RasterizerState >( "RasterizerState" ) + rttr::registration::class_< RasterizerState >( "sw::RasterizerState" ) .property_readonly( "Descriptor", &RasterizerState::GetDescriptor ) BIND_AS_PTR; // Depth/Stencil - rttr::registration::class_< DepthStencilInfo >( "DepthStencilInfo" ) + rttr::registration::class_< DepthStencilInfo >( "sw::DepthStencilInfo" ) .property_readonly( "EnableDepthTest", &DepthStencilInfo::EnableDepthTest ) .property_readonly( "EnableStencilTest", &DepthStencilInfo::EnableStencilTest ); - rttr::registration::class_< DepthStencilState >( "DepthStencilState" ) + rttr::registration::class_< DepthStencilState >( "sw::DepthStencilState" ) .property_readonly( "Descriptor", &RasterizerState::GetDescriptor ) BIND_AS_PTR; - // Buffer - rttr::registration::class_< BufferObject >( "BufferObject" ) - .property_readonly( "Descriptor", &BufferObject::GetDescriptor ) BIND_AS_PTR; - - rttr::registration::class_< BufferInfo >( "BufferInfo" ) - .property_readonly( "BufferName", &BufferInfo::GetName ) - .property_readonly( "NumberElements", &BufferInfo::NumElements ) - .property_readonly( "ElementSize", &BufferInfo::ElementSize ) - .property_readonly( "Usage", &BufferInfo::Usage ) - .property_readonly( "BufferType", &BufferInfo::BufferType ) - .property_readonly( "Topology", &BufferInfo::Topology ) - .property_readonly( "4 Bytes Index Size", &BufferInfo::Use4BytesIndex ) - .property_readonly( "VertexLayout", &BufferInfo::VertexLayout ); - - - rttr::registration::class_< ShaderInputLayout >( "ShaderInputLayout" ); - rttr::registration::class_< IShader >( "IShader" ) - .property_readonly( "FilePath", &IShader::GetShaderFile ) - .property_readonly( "MainFunction", &IShader::GetShaderEntry ); - - rttr::registration::class_< PixelShader >( "PixelShader" ); - rttr::registration::class_< VertexShader >( "VertexShader" ); - - rttr::registration::class_< RenderTargetObject >( "RenderTargetObject" ) - .property( "ColorBuffer", &RenderTargetObject::m_colorBuffer ) - .property( "DepthBuffer", &RenderTargetObject::m_depthBuffer ) - .property( "StencilBuffer", &RenderTargetObject::m_stencilBuffer ); - - rttr::registration::class_< MaterialObject >( "MaterialObject" ) - .property( "Diffuse", &MaterialObject::Diffuse ) BIND_AS_PTR - .property( "Specular", &MaterialObject::Specular ) BIND_AS_PTR - .property( "Ambient", &MaterialObject::Ambient ) BIND_AS_PTR - .property( "Emissive", &MaterialObject::Emissive ) BIND_AS_PTR - .property( "SpecularPower", &MaterialObject::Power ); - -} - - -//----------------------------------------------------------------------------------------------// -// PixelShader // -//----------------------------------------------------------------------------------------------// - -//----------------------------------------------------------------------------------------------// -// VertexShader // -//----------------------------------------------------------------------------------------------// - -//----------------------------------------------------------------------------------------------// -// RenderTargetObject // -//----------------------------------------------------------------------------------------------// -RenderTargetObject::RenderTargetObject( TextureObject* colorBuffer, TextureObject* depthBuffer, TextureObject* stencilBuffer ) - : m_colorBuffer( colorBuffer ) - , m_depthBuffer( depthBuffer ) - , m_stencilBuffer( stencilBuffer ) -{ - //if( m_colorBuffer ) - // m_colorBuffer->AddAssetReference(); - //if( m_depthBuffer ) - // m_depthBuffer->AddAssetReference(); - //if( m_stencilBuffer ) - // m_stencilBuffer->AddAssetReference(); -} - -/**@brief Destruktor kasuje obiekty tekstury g��boko�ci i bufora koloru, je�eli nie s� u�ywane. -Je�eli istniej� odwo�ania do tych obiekt�w, to nie s� one kasowane, a jedynie usuwa si� odwo�ania -pochodz�ce od RenderTargetObject.*/ -RenderTargetObject::~RenderTargetObject() -{ - //if( m_colorBuffer ) - //{ - // m_colorBuffer->DeleteAssetReference(); - // //if( m_colorBuffer->CanDelete() ) - // // ObjectDeleter::delete_object( m_colorBuffer, ObjectDeleterKey() ); - //} - //if( m_depthBuffer ) - //{ - // m_depthBuffer->DeleteAssetReference(); - // //if( m_depthBuffer->CanDelete() ) - // // ObjectDeleter::delete_object( m_depthBuffer, ObjectDeleterKey() ); - //} - //if( m_stencilBuffer ) - //{ - // m_stencilBuffer->DeleteAssetReference(); - // //if( m_stencilBuffer->CanDelete() ) - // // ObjectDeleter::delete_object( m_stencilBuffer, ObjectDeleterKey() ); - //} } -std::string RenderTargetObject::GetResourceName() const -{ - if( m_colorBuffer ) - return m_colorBuffer->GetFilePath().String(); - if( m_depthBuffer ) - return m_depthBuffer->GetFilePath().String(); - if( m_stencilBuffer ) - return m_stencilBuffer->GetFilePath().String(); - return ""; -} - -//----------------------------------------------------------------------------------------------// -// BufferObject // -//----------------------------------------------------------------------------------------------// - -BufferObject::BufferObject( unsigned int elementSize, unsigned int elementCount ) - : m_elementSize( elementSize ), - m_elementCount( elementCount ) -{ -} - - -//----------------------------------------------------------------------------------------------// -// MaterialObject // -//----------------------------------------------------------------------------------------------// - -MaterialObject::MaterialObject( const MaterialObject* material ) -: ResourceObject(WRONG_ID) -{ - memcpy( this, material, sizeof(MaterialObject) ); -} - -/**@brief Ustawia materia� na warto�ci domy�lne dla silnika. - -Te warto�ci s� najbardziej neutralne, w przypadku gdy nie ma materia�u, a jest ustawiona tekstura. -Wtedy shadery wymana�aj� jasno�� piksela przez 1.0 i nic sie nie zmienia.*/ -void MaterialObject::SetNullMaterial( ) -{ - Diffuse.x = 1.0f; - Diffuse.y = 1.0f; - Diffuse.z = 1.0f; - Diffuse.w = 1.0f; - - Ambient.x = 1.0f; - Ambient.y = 1.0f; - Ambient.z = 1.0f; - Ambient.w = 1.0f; - - Specular.x = 1.0f; - Specular.y = 1.0f; - Specular.z = 1.0f; - Specular.w = 1.0f; - - Emissive.x = 0.0f; - Emissive.y = 0.0f; - Emissive.z = 0.0f; - Emissive.w = 0.0f; - - Power = 1.0f; -} - - diff --git a/Resources/MeshResources.h b/Resources/MeshResources.h index a482e7c..fa9aa6b 100644 --- a/Resources/MeshResources.h +++ b/Resources/MeshResources.h @@ -2,76 +2,61 @@ /** @file MeshResources.h @author nieznanysprawiciel -@copyright Plik jest cz�ci� silnika graficznego SWEngine. +@copyright File is part of Sleeping Wombat Libraries. -@brief Plik zawiera deklaracje format�w wierzcho�k�w oraz klas zawieraj�cych assety shadery itp. +@brief This file contains includes for low level API dependent Resources. */ -#include "swCommonLib/Common/ObjectDeleter.h" + #include "swCommonLib/System/Path.h" #include "swGraphicAPI/Resources/ResourceObject.h" -#include "swGraphicAPI/Resources/IShader.h" -#include "swGraphicAPI/Resources/IBuffer.h" -#include "swGraphicAPI/Resources/IRenderTarget.h" -#include "swGraphicAPI/Resources/IShaderInputLayout.h" +#include "swGraphicAPI/Resources/Shaders/IShader.h" +#include "swGraphicAPI/Resources/Buffers/Buffer.h" +#include "swGraphicAPI/Resources/Textures/RenderTarget.h" +#include "swGraphicAPI/Resources/Shaders/IShaderInputLayout.h" #include "swGraphicAPI/Rendering/GraphicAPIConstants.h" #include "swGraphicAPI/Resources/ResourcePtr.h" -#include "swGraphicAPI/Resources/BufferInitData.h" -#include "swGraphicAPI/Resources/Texture.h" +#include "swGraphicAPI/Resources/Shaders/Shaders.h" +#include "swGraphicAPI/Resources/Shaders/InputLayout.h" +#include "swGraphicAPI/Resources/Shaders/LayoutInitData.h" + +#include "swGraphicAPI/Resources/Textures/Texture.h" + +#include "swGraphicAPI/Resources/PipelineStates/BlendingState.h" +#include "swGraphicAPI/Resources/PipelineStates/DepthStencilState.h" +#include "swGraphicAPI/Resources/PipelineStates/RasterizerState.h" #include -//definicje -/** @def WRONG_ID -B��dny identyfikator assetu w klasie @ref ResourceObject.*/ -#define WRONG_ID 0 + /**@defgroup Resources Resources @ingroup ResourcesManagment @ingroup GraphicAPI -@brief Niskopoziomowe zasoby zwi�zane z api graficznym. - -Zasoby s� silnie zale�ne od u�ywanej platformy sprz�towej. W celu oddzielenia referencji do -API graficznego od @ref EngineCore, wszystkie obiekty silnika u�ywaj� jedynie klas bazowych, kt�re -s� implementowane przez poszczeg�lne API graficzne. Aby zobaczy� konkretne implementacje tych klas -zobacz @ref GraphicAPI. - -Zasoby nigdy nie s� tworzone bezpo�rednio. Zamiast tego u�ywa si� klasy @ref ResourcesFactory, kt�r� -implementuje konkretne API graficzne. +@brief Low level resources that depend on graphic API. -Poniewa� zasoby mog� by� wsp�dzielone przez wiele obiekt�w w silniku, istnieje mechanizm zliczania -odwo�a� do obiekt�w implementowany przez klas� @ref ResourceObject.*/ +Resources are strongly dependent from platform and graphic API used. This library gives you +abstraction layer over platform specific things. All graphic APIs are encapsulated in common +interfaces. Dependent libraries use only base classes. To create Resources @ref ResourcesFactory +class is used. +Resources can be shared by many objects. ResourceManager class is created to manage them and release +them when necessary. in future this class will be responsible for caching. -class BufferObject; -class TextureObject; -class VertexShader; -class PixelShader; +Note that Resources from this library are tightly related to device Resources. Except low level +Resources developer can define his own hiher level Assets, that are managed by @ref ResourceManager too.*/ -/* -// W buforze wierzcho�k�w znajduj� si� elementy typu VERT_INDEX. -// Definicja typu VERT_INDEX znajduje si� w pliku macros_switches.h i wygl�da tak: -#if defined(INDEX_BUFFER_UINT16) -typedef UINT16 VERT_INDEX; -#elif defined(INDEX_BUFFER_UINT32) -typedef UINT32 VERT_INDEX; -#else -typedef UINT32 VERT_INDEX; -#endif - -*/ +namespace sw +{ -static const std::wstring RENDER_TARGET_COLOR_BUFFER_NAME = L"::color"; -static const std::wstring RENDER_TARGET_DEPTH_BUFFER_NAME = L"::depth"; -static const std::wstring RENDER_TARGET_STENCIL_BUFFER_NAME = L"::stencil"; typedef uint16 Index16; @@ -79,378 +64,6 @@ typedef uint32 Index32; typedef uint8 Index8; -/**@brief Meaning of texture indicies. - -@ingroup Textures - -These are values used by default shaders. You don't have to use this convention -when you write your own shaders.*/ -enum TextureUse -{ - TEX_DIFFUSE /// m_colorBuffer; /// m_depthBuffer; /// m_stencilBuffer; ///; -private: -protected: - virtual ~ShaderInputLayout() = default; -public: - ShaderInputLayout() = default; - - virtual std::string GetResourceName () const override { return ""; } -}; - -/**@brief Klasa przechowuje opis layoutu wierzcho�ka, na podstawie kt�rego -tworzony jest obiekt layoutu. -@ingroup Buffers -@ingroup Shaders -@ingroup Resources*/ -class InputLayoutDescriptor -{ -private: - std::wstring m_inputLayoutName; -protected: -public: - InputLayoutDescriptor( const std::wstring& layoutName ) : m_inputLayoutName( layoutName ){} - virtual ~InputLayoutDescriptor() = default; - - virtual void AddRow ( const char* semanticName, ResourceFormat format, unsigned int inputSlot, unsigned int byteOffset, bool perInstance, unsigned int instanceDataStep ) = 0; - - std::wstring& GetName () { return m_inputLayoutName; } -}; - -DEFINE_UPTR_TYPE( InputLayoutDescriptor ) - - -/**@brief Typ shadera. -@ingroup Shaders*/ -enum class ShaderType : uint8 -{ - VertexShader = 0x01, - PixelShader = 0x02, - GeometryShader = 0x04, - TesselationControlShader = 0x08, - TesselationEvaluationShader = 0x10, - ComputeShader = 0x20 -}; - -//----------------------------------------------------------------------------------------------// -// VertexShader // -//----------------------------------------------------------------------------------------------// - -/** @brief Klasa przechowuj�ca vertex shader. -@ingroup Shaders -@ingroup Resources -@ingroup GraphicAPI*/ -class VertexShader : public IShader -{ - RTTR_ENABLE( IShader ); - friend ObjectDeleter< VertexShader >; -private: -protected: - ~VertexShader() = default; -public: - VertexShader() = default; - - virtual std::string GetResourceName () const override { return ""; } -}; - -//----------------------------------------------------------------------------------------------// -// PixelShader // -//----------------------------------------------------------------------------------------------// - -/**@brief Klasa przechowuj�ca pixel shader. -@ingroup Shaders -@ingroup Resources -@ingroup GraphicAPI*/ -class PixelShader : public IShader -{ - RTTR_ENABLE( IShader ); - friend ObjectDeleter< PixelShader >; -private: -protected: - ~PixelShader() = default; -public: - PixelShader() = default; - - virtual std::string GetResourceName () const override { return ""; } -}; - -//----------------------------------------------------------------------------------------------// -// GeometryShader // -//----------------------------------------------------------------------------------------------// - -/**@brief Klasa przechowuj�ca pixel shader. -@ingroup Shaders -@ingroup Resources -@ingroup GraphicAPI*/ -class GeometryShader : public IShader -{ - RTTR_ENABLE( IShader ); - friend ObjectDeleter; -private: -protected: - ~GeometryShader() = default; -public: - GeometryShader() = default; - - virtual std::string GetResourceName () const override { return ""; } -}; - -//----------------------------------------------------------------------------------------------// -// ControlShader // -//----------------------------------------------------------------------------------------------// - -/**@brief Klasa przechowuj�ca pixel shader. -@ingroup Shaders -@ingroup Resources -@ingroup GraphicAPI*/ -class ControlShader : public IShader -{ - RTTR_ENABLE( IShader ); - friend ObjectDeleter< ControlShader >; -private: -protected: - ~ControlShader() = default; -public: - ControlShader() = default; - - virtual std::string GetResourceName () const override { return ""; } -}; - -//----------------------------------------------------------------------------------------------// -// EvaluationShader // -//----------------------------------------------------------------------------------------------// - -/**@brief Klasa przechowuj�ca pixel shader. -@ingroup Shaders -@ingroup Resources -@ingroup GraphicAPI*/ -class EvaluationShader : public IShader -{ - RTTR_ENABLE( IShader ); - friend ObjectDeleter< EvaluationShader >; -private: -protected: - ~EvaluationShader() = default; -public: - EvaluationShader() = default; - - virtual std::string GetResourceName () const override { return ""; } -}; - -//----------------------------------------------------------------------------------------------// -// ComputeShader // -//----------------------------------------------------------------------------------------------// - -/**@brief Klasa przechowuj�ca compute shader -@ingroup Shaders -@ingroup Resources -@ingroup GraphicAPI*/ -class ComputeShader : public IShader -{ - RTTR_ENABLE( IShader ); - friend ObjectDeleter; -private: -protected: - ~ComputeShader() = default; -public: - ComputeShader() = default; - - virtual std::string GetResourceName () const override { return ""; } -}; - -//----------------------------------------------------------------------------------------------// -// BufferObject // -//----------------------------------------------------------------------------------------------// - -/**@brief Obiekt opakowuj�cy bufor. -@ingroup Buffers -@ingroup Resources -@ingroup GraphicAPI - -Bufor mo�e by� zar�wno buforem wierzcho�k�w, indeks�w jak i sta�ych. -*/ -class BufferObject : public IBuffer -{ - RTTR_ENABLE( IBuffer ) - friend ObjectDeleter; -protected: - unsigned int m_elementSize; ///; - - DirectX::XMFLOAT4 Diffuse; //Sk�adowa przezroczysto�ci odnosi si� do ca�ego materia�u - DirectX::XMFLOAT4 Ambient; - DirectX::XMFLOAT4 Specular; - DirectX::XMFLOAT4 Emissive; - float Power; - - MaterialObject( unsigned int id = WRONG_ID ) : ResourceObject( id ){} - MaterialObject( const MaterialObject* material ); - - void SetNullMaterial(); - - virtual std::string GetResourceName () const override { return ""; } -}; +} // sw diff --git a/Resources/BlendingState.h b/Resources/PipelineStates/BlendingState.h similarity index 55% rename from Resources/BlendingState.h rename to Resources/PipelineStates/BlendingState.h index 82c716d..bc02c8e 100644 --- a/Resources/BlendingState.h +++ b/Resources/PipelineStates/BlendingState.h @@ -1,24 +1,35 @@ #pragma once /** -@file FileName +@file BlendingState.h @author nieznanysprawiciel @copyright File is part of graphic engine SWEngine. */ -#include "swCommonLib/Common/ObjectDeleter.h" - -#include "ResourceObject.h" +#include "swGraphicAPI/Resources/ResourceObject.h" #include "swGraphicAPI/Rendering/GraphicAPIConstants.h" +#include "swGraphicAPI/ResourceManager/AssetCreators/IAssetCreateInfo.h" #include + + +namespace sw +{ + + +class BlendingState; + + + /**@brief Initialization of BlendingState. @ingroup PipelineState*/ -struct BlendingInfo +struct BlendingInfo : public sw::IAssetCreateInfo { + RTTR_ENABLE( sw::IAssetCreateInfo ); +public: DirectX::XMFLOAT4 CustomBlendFactor; ///< Custom blend factors. bool EnableBlending; BlendOperation ColorOperation; @@ -31,14 +42,14 @@ struct BlendingInfo // ================================ // // BlendingInfo() - : CustomBlendFactor( DirectX::XMFLOAT4( 0.0f, 0.0f, 0.0f, 0.0f ) ) - , EnableBlending( false ) - , ColorOperation( BlendOperation::Add ) - , AlphaOperation( BlendOperation::Add ) - , SrcColorBlend( BlendFactor::One ) - , DstColorBlend( BlendFactor::One ) - , SrcAlphaBlend( BlendFactor::One ) - , DstAlphaBlend( BlendFactor::One ) + : CustomBlendFactor( DirectX::XMFLOAT4( 0.0f, 0.0f, 0.0f, 0.0f ) ) + , EnableBlending( false ) + , ColorOperation( BlendOperation::Add ) + , AlphaOperation( BlendOperation::Add ) + , SrcColorBlend( BlendFactor::One ) + , DstColorBlend( BlendFactor::One ) + , SrcAlphaBlend( BlendFactor::One ) + , DstAlphaBlend( BlendFactor::One ) {} #define Compare( x ) if( x != other.x ) return false; @@ -61,29 +72,33 @@ struct BlendingInfo } #undef Compare + +public: + + virtual TypeID GetAssetType () const override { return TypeID::get< BlendingState >(); } }; -/**@brief +/**@brief @ingroup PipelineState*/ -class BlendingState : public ResourceObject +class BlendingState : public Resource { - RTTR_ENABLE( ResourceObject ); - friend ObjectDeleter< BlendingState >; + RTTR_ENABLE( Resource ); private: protected: virtual ~BlendingState() = default; public: - explicit BlendingState() - : ResourceObject( 0 ) - {} - + explicit BlendingState ( const AssetPath& assetPath ) : Resource( assetPath ) {} - virtual const BlendingInfo& GetDescriptor () = 0; + virtual const BlendingInfo& GetDescriptor () const = 0; }; +DEFINE_RESOURCE_PTR_TYPE( BlendingState ); + + +} // sw \ No newline at end of file diff --git a/Resources/PipelineStates/DepthStencilState.h b/Resources/PipelineStates/DepthStencilState.h new file mode 100644 index 0000000..e844ac6 --- /dev/null +++ b/Resources/PipelineStates/DepthStencilState.h @@ -0,0 +1,75 @@ +#pragma once +/** +@file DepthStencilState.h +@author nieznanysprawiciel +@copyright File is part of graphic engine SWEngine. +*/ + +#include "swGraphicAPI/Resources/ResourceObject.h" + +#include "swGraphicAPI/ResourceManager/AssetCreators/IAssetCreateInfo.h" + + + + +namespace sw +{ + +class DepthStencilState; + + +/**@brief +@ingroup PipelineState*/ +struct DepthStencilInfo : public sw::IAssetCreateInfo +{ + RTTR_ENABLE( sw::IAssetCreateInfo ); +public: + bool EnableDepthTest; + bool EnableStencilTest; + +// ================================ // +// + DepthStencilInfo() + : EnableDepthTest( true ) + , EnableStencilTest( false ) + {} + +#define Compare( x ) if( x != other.x ) return false; + + bool operator== ( const DepthStencilInfo& other ) const + { + Compare( EnableDepthTest ); + Compare( EnableStencilTest ); + return true; + } + +#undef Compare + +public: + + virtual TypeID GetAssetType () const override { return TypeID::get< DepthStencilState >(); } +}; + + + + +/**@brief +@ingroup PipelineState*/ +class DepthStencilState : public Resource +{ + RTTR_ENABLE( Resource ); +private: +protected: + + virtual ~DepthStencilState() = default; + +public: + explicit DepthStencilState ( const AssetPath& assetPath ) : Resource( assetPath ) {} + + virtual const DepthStencilInfo& GetDescriptor () const = 0; +}; + +DEFINE_RESOURCE_PTR_TYPE( DepthStencilState ); + + +} // sw diff --git a/Resources/RasterizerState.h b/Resources/PipelineStates/RasterizerState.h similarity index 54% rename from Resources/RasterizerState.h rename to Resources/PipelineStates/RasterizerState.h index 81d015f..30107e3 100644 --- a/Resources/RasterizerState.h +++ b/Resources/PipelineStates/RasterizerState.h @@ -5,8 +5,9 @@ @copyright File is part of graphic engine SWEngine. */ -#include "swCommonLib/Common/ObjectDeleter.h" -#include "ResourceObject.h" +#include "swGraphicAPI/Resources/ResourceObject.h" + +#include "swGraphicAPI/ResourceManager/AssetCreators/IAssetCreateInfo.h" /**@defgroup PipelineState @@ -15,10 +16,18 @@ -/**@brief +namespace sw +{ + +class RasterizerState; + + +/**@brief @ingroup PipelineState*/ -struct RasterizerStateInfo +struct RasterizerStateInfo : public sw::IAssetCreateInfo { + RTTR_ENABLE( sw::IAssetCreateInfo ); +public: CullMode CullMode; FillMode FillMode; int DepthBias; @@ -31,13 +40,13 @@ struct RasterizerStateInfo // ================================ // // RasterizerStateInfo() - : CullMode( CullMode::Back ) - , FillMode( FillMode::Solid ) - , DepthBias( 0 ) - , IsClockwise( false ) - , EnableScissor( false ) - , EnableZClipping( true ) - , ConservativeRasterizer( false ) + : CullMode( CullMode::Back ) + , FillMode( FillMode::Solid ) + , DepthBias( 0 ) + , IsClockwise( false ) + , EnableScissor( false ) + , EnableZClipping( true ) + , ConservativeRasterizer( false ) {} #define Compare( x ) if( x != other.x ) return false; @@ -56,6 +65,10 @@ struct RasterizerStateInfo } #undef Compare + +public: + + virtual TypeID GetAssetType () const override { return TypeID::get< RasterizerState >(); } }; @@ -64,19 +77,23 @@ struct RasterizerStateInfo /**@brief Rasterizer state and depth stencil state. @ingroup PipelineState*/ -class RasterizerState : public ResourceObject +class RasterizerState : public Resource { - RTTR_ENABLE( ResourceObject ); - friend ObjectDeleter< RasterizerState >; + RTTR_ENABLE( Resource ); private: protected: + virtual ~RasterizerState() = default; + public: - explicit RasterizerState() - : ResourceObject( 0 ) - {} + explicit RasterizerState ( const AssetPath& assetPath ) : Resource( assetPath ) {} - virtual const RasterizerStateInfo& GetDescriptor () = 0; + virtual const RasterizerStateInfo& GetDescriptor () const = 0; }; +DEFINE_RESOURCE_PTR_TYPE( RasterizerState ); + + +} // sw + diff --git a/Resources/Resource.cpp b/Resources/Resource.cpp new file mode 100644 index 0000000..0a780fe --- /dev/null +++ b/Resources/Resource.cpp @@ -0,0 +1,318 @@ +/** +@file Resource.cpp +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ +#include "swGraphicAPI/ResourceManager/stdafx.h" + +#include "swGraphicAPI/Resources/ResourceObject.h" + + +using namespace sw; + +RTTR_REGISTRATION +{ + RTTR_REGISTRATION_STANDARD_TYPE_VARIANTS( std::wstring ); + +//====================================================================================// +// Enumarations +//====================================================================================// + + + rttr::registration::enumeration< ResourceUsage >( "sw::ResourceUsage" ) + ( + rttr::value( "Default", ResourceUsage::Default ), + rttr::value( "Dynamic", ResourceUsage::Dynamic ), + rttr::value( "Staging", ResourceUsage::Staging ), + rttr::value( "Static", ResourceUsage::Static ) + ); + + rttr::registration::enumeration< BlendOperation >( "sw::BlendOperation" ) + ( + rttr::value( "Add", BlendOperation::Add ), + rttr::value( "Subtract", BlendOperation::Subtract ), + rttr::value( "ReverseSubtract", BlendOperation::ReverseSubtract ), + rttr::value( "Min", BlendOperation::Min ), + rttr::value( "Max", BlendOperation::Max ) + ); + + + rttr::registration::enumeration< BlendFactor >( "sw::BlendFactor" ) + ( + rttr::value( "Zero", BlendFactor::Zero ), + rttr::value( "One", BlendFactor::One ), + rttr::value( "SrcColor", BlendFactor::SrcColor ), + rttr::value( "DstColor", BlendFactor::DstColor ), + rttr::value( "SrcAlpha", BlendFactor::SrcAlpha ), + rttr::value( "DstAlpha", BlendFactor::DstAlpha ), + rttr::value( "BlendFactor", BlendFactor::BlendFactor ), + rttr::value( "InverseSrcColor", BlendFactor::InverseSrcColor ), + rttr::value( "InverseDstColor", BlendFactor::InverseDstColor ), + rttr::value( "InverseSrcAlpha", BlendFactor::InverseSrcAlpha ), + rttr::value( "InverseDstAlpha", BlendFactor::InverseDstAlpha ), + rttr::value( "InverseBlendFactor", BlendFactor::InverseBlendFactor ) + ); + + rttr::registration::enumeration< CullMode >( "sw::CullMode" ) + ( + rttr::value( "Front", CullMode::Front ), + rttr::value( "Back", CullMode::Back ), + rttr::value( "None", CullMode::None ) + ); + + rttr::registration::enumeration< FillMode >( "sw::FillMode" ) + ( + rttr::value( "Solid", FillMode::Solid ), + rttr::value( "Wireframe", FillMode::Wireframe ) + ); + + rttr::registration::enumeration< ResourceFormat >( "sw::ResourceFormat" ) + ( + rttr::value( "Unknown", ResourceFormat::RESOURCE_FORMAT_UNKNOWN ), + rttr::value( "R32G32B32A32_TYPELESS", ResourceFormat::RESOURCE_FORMAT_R32G32B32A32_TYPELESS ), + rttr::value( "R32G32B32A32_UINT", ResourceFormat::RESOURCE_FORMAT_R32G32B32A32_FLOAT ), + rttr::value( "R32G32B32A32_UINT", ResourceFormat::RESOURCE_FORMAT_R32G32B32A32_UINT ), + rttr::value( "R32G32B32A32_SINT", ResourceFormat::RESOURCE_FORMAT_R32G32B32A32_SINT ), + rttr::value( "R32G32B32_TYPELESS", ResourceFormat::RESOURCE_FORMAT_R32G32B32_TYPELESS ), + rttr::value( "R32G32B32_FLOAT", ResourceFormat::RESOURCE_FORMAT_R32G32B32_FLOAT ), + rttr::value( "R32G32B32_UINT", ResourceFormat::RESOURCE_FORMAT_R32G32B32_UINT ), + rttr::value( "R32G32B32_SINT", ResourceFormat::RESOURCE_FORMAT_R32G32B32_SINT ), + rttr::value( "R16G16B16A16_TYPELESS", ResourceFormat::RESOURCE_FORMAT_R16G16B16A16_TYPELESS ), + rttr::value( "R16G16B16A16_FLOAT", ResourceFormat::RESOURCE_FORMAT_R16G16B16A16_FLOAT ), + rttr::value( "R16G16B16A16_UNORM", ResourceFormat::RESOURCE_FORMAT_R16G16B16A16_UNORM ), + rttr::value( "R16G16B16A16_UINT", ResourceFormat::RESOURCE_FORMAT_R16G16B16A16_UINT ), + rttr::value( "R16G16B16A16_SNORM", ResourceFormat::RESOURCE_FORMAT_R16G16B16A16_SNORM ), + rttr::value( "R16G16B16A16_SINT", ResourceFormat::RESOURCE_FORMAT_R16G16B16A16_SINT ), + rttr::value( "R32G32_TYPELESS", ResourceFormat::RESOURCE_FORMAT_R32G32_TYPELESS ), + rttr::value( "R32G32_FLOAT", ResourceFormat::RESOURCE_FORMAT_R32G32_FLOAT ), + rttr::value( "R32G32_UINT", ResourceFormat::RESOURCE_FORMAT_R32G32_UINT ), + rttr::value( "R32G32_SINT", ResourceFormat::RESOURCE_FORMAT_R32G32_SINT ), + rttr::value( "R32G8X24_TYPELESS", ResourceFormat::RESOURCE_FORMAT_R32G8X24_TYPELESS ), + rttr::value( "D32_FLOAT_S8X24_UINT", ResourceFormat::RESOURCE_FORMAT_D32_FLOAT_S8X24_UINT ), + rttr::value( "R32_FLOAT_X8X24_TYPELESS", ResourceFormat::RESOURCE_FORMAT_R32_FLOAT_X8X24_TYPELESS ), + rttr::value( "X32_TYPELESS_G8X24_UINT", ResourceFormat::RESOURCE_FORMAT_X32_TYPELESS_G8X24_UINT ), + rttr::value( "R10G10B10A2_TYPELESS", ResourceFormat::RESOURCE_FORMAT_R10G10B10A2_TYPELESS ), + rttr::value( "R10G10B10A2_UNORM", ResourceFormat::RESOURCE_FORMAT_R10G10B10A2_UNORM ), + rttr::value( "R10G10B10A2_UINT", ResourceFormat::RESOURCE_FORMAT_R10G10B10A2_UINT ), + rttr::value( "R11G11B10_FLOAT", ResourceFormat::RESOURCE_FORMAT_R11G11B10_FLOAT ), + rttr::value( "R8G8B8A8_TYPELESS", ResourceFormat::RESOURCE_FORMAT_R8G8B8A8_TYPELESS ), + rttr::value( "R8G8B8A8_UNORM", ResourceFormat::RESOURCE_FORMAT_R8G8B8A8_UNORM ), + rttr::value( "R8G8B8A8_UNORM_SRGB", ResourceFormat::RESOURCE_FORMAT_R8G8B8A8_UNORM_SRGB ), + rttr::value( "R8G8B8A8_UINT", ResourceFormat::RESOURCE_FORMAT_R8G8B8A8_UINT ), + rttr::value( "R8G8B8A8_SNORM", ResourceFormat::RESOURCE_FORMAT_R8G8B8A8_SNORM ), + rttr::value( "R8G8B8A8_SINT", ResourceFormat::RESOURCE_FORMAT_R8G8B8A8_SINT ), + rttr::value( "R16G16_TYPELESS", ResourceFormat::RESOURCE_FORMAT_R16G16_TYPELESS ), + rttr::value( "R16G16_FLOAT", ResourceFormat::RESOURCE_FORMAT_R16G16_FLOAT ), + rttr::value( "R16G16_UNORM", ResourceFormat::RESOURCE_FORMAT_R16G16_UNORM ), + rttr::value( "R16G16_UINT", ResourceFormat::RESOURCE_FORMAT_R16G16_UINT ), + rttr::value( "R16G16_SNORM", ResourceFormat::RESOURCE_FORMAT_R16G16_SNORM ), + rttr::value( "R16G16_SINT", ResourceFormat::RESOURCE_FORMAT_R16G16_SINT ), + rttr::value( "R32_TYPELESS", ResourceFormat::RESOURCE_FORMAT_R32_TYPELESS ), + rttr::value( "D32_FLOAT", ResourceFormat::RESOURCE_FORMAT_D32_FLOAT ), + rttr::value( "R32_FLOAT", ResourceFormat::RESOURCE_FORMAT_R32_FLOAT ), + rttr::value( "R32_UINT", ResourceFormat::RESOURCE_FORMAT_R32_UINT ), + rttr::value( "R32_SINT", ResourceFormat::RESOURCE_FORMAT_R32_SINT ), + rttr::value( "R24G8_TYPELESS", ResourceFormat::RESOURCE_FORMAT_R24G8_TYPELESS ), + rttr::value( "D24_UNORM_S8_UINT", ResourceFormat::RESOURCE_FORMAT_D24_UNORM_S8_UINT ), + rttr::value( "R24_UNORM_X8_TYPELESS", ResourceFormat::RESOURCE_FORMAT_R24_UNORM_X8_TYPELESS ), + rttr::value( "X24_TYPELESS_G8_UINT", ResourceFormat::RESOURCE_FORMAT_X24_TYPELESS_G8_UINT ), + rttr::value( "R8G8_TYPELESS", ResourceFormat::RESOURCE_FORMAT_R8G8_TYPELESS ), + rttr::value( "R8G8_UNORM", ResourceFormat::RESOURCE_FORMAT_R8G8_UNORM ), + rttr::value( "R8G8_UINT", ResourceFormat::RESOURCE_FORMAT_R8G8_UINT ), + rttr::value( "R8G8_SNORM", ResourceFormat::RESOURCE_FORMAT_R8G8_SNORM ), + rttr::value( "R8G8_SINT", ResourceFormat::RESOURCE_FORMAT_R8G8_SINT ), + rttr::value( "R16_TYPELESS", ResourceFormat::RESOURCE_FORMAT_R16_TYPELESS ), + rttr::value( "R16_FLOAT", ResourceFormat::RESOURCE_FORMAT_R16_FLOAT ), + rttr::value( "D16_UNORM", ResourceFormat::RESOURCE_FORMAT_D16_UNORM ), + rttr::value( "R16_UNORM", ResourceFormat::RESOURCE_FORMAT_R16_UNORM ), + rttr::value( "R16_UINT", ResourceFormat::RESOURCE_FORMAT_R16_UINT ), + rttr::value( "R16_SNORM", ResourceFormat::RESOURCE_FORMAT_R16_SNORM ), + rttr::value( "R16_SINT", ResourceFormat::RESOURCE_FORMAT_R16_SINT ), + rttr::value( "R8_TYPELESS", ResourceFormat::RESOURCE_FORMAT_R8_TYPELESS ), + rttr::value( "R8_UNORM", ResourceFormat::RESOURCE_FORMAT_R8_UNORM ), + rttr::value( "R8_UINT", ResourceFormat::RESOURCE_FORMAT_R8_UINT ), + rttr::value( "R8_SNORM", ResourceFormat::RESOURCE_FORMAT_R8_SNORM ), + rttr::value( "R8_SINT", ResourceFormat::RESOURCE_FORMAT_R8_SINT ), + rttr::value( "A8_UNORM", ResourceFormat::RESOURCE_FORMAT_A8_UNORM ), + rttr::value( "R1_UNORM", ResourceFormat::RESOURCE_FORMAT_R1_UNORM ), + rttr::value( "R9G9B9E5_SHAREDEXP", ResourceFormat::RESOURCE_FORMAT_R9G9B9E5_SHAREDEXP ), + rttr::value( "R8G8_B8G8_UNORM", ResourceFormat::RESOURCE_FORMAT_R8G8_B8G8_UNORM ), + rttr::value( "G8R8_G8B8_UNORM", ResourceFormat::RESOURCE_FORMAT_G8R8_G8B8_UNORM ), + rttr::value( "BC1_TYPELESS", ResourceFormat::RESOURCE_FORMAT_BC1_TYPELESS ), + rttr::value( "BC1_UNORM", ResourceFormat::RESOURCE_FORMAT_BC1_UNORM ), + rttr::value( "BC1_UNORM_SRGB", ResourceFormat::RESOURCE_FORMAT_BC1_UNORM_SRGB ), + rttr::value( "BC2_TYPELESS", ResourceFormat::RESOURCE_FORMAT_BC2_TYPELESS ), + rttr::value( "BC2_UNORM", ResourceFormat::RESOURCE_FORMAT_BC2_UNORM ), + rttr::value( "BC2_UNORM_SRGB", ResourceFormat::RESOURCE_FORMAT_BC2_UNORM_SRGB ), + rttr::value( "BC3_TYPELESS", ResourceFormat::RESOURCE_FORMAT_BC3_TYPELESS ), + rttr::value( "BC3_UNORM", ResourceFormat::RESOURCE_FORMAT_BC3_UNORM ), + rttr::value( "BC3_UNORM_SRGB", ResourceFormat::RESOURCE_FORMAT_BC3_UNORM_SRGB ), + rttr::value( "BC4_TYPELESS", ResourceFormat::RESOURCE_FORMAT_BC4_TYPELESS ), + rttr::value( "FORMAT_BC4_UNORM", ResourceFormat::RESOURCE_FORMAT_BC4_UNORM ), + rttr::value( "BC4_SNORM", ResourceFormat::RESOURCE_FORMAT_BC4_SNORM ), + rttr::value( "BC5_TYPELESS", ResourceFormat::RESOURCE_FORMAT_BC5_TYPELESS ), + rttr::value( "BC5_UNORM", ResourceFormat::RESOURCE_FORMAT_BC5_UNORM ), + rttr::value( "BC5_SNORM", ResourceFormat::RESOURCE_FORMAT_BC5_SNORM ), + rttr::value( "B5G6R5_UNORM", ResourceFormat::RESOURCE_FORMAT_B5G6R5_UNORM ), + rttr::value( "B5G5R5A1_UNORM", ResourceFormat::RESOURCE_FORMAT_B5G5R5A1_UNORM ), + rttr::value( "B8G8R8A8_UNORM", ResourceFormat::RESOURCE_FORMAT_B8G8R8A8_UNORM ), + rttr::value( "B8G8R8X8_UNORM", ResourceFormat::RESOURCE_FORMAT_B8G8R8X8_UNORM ), + rttr::value( "R10G10B10_XR_BIAS_A2_UNORM", ResourceFormat::RESOURCE_FORMAT_R10G10B10_XR_BIAS_A2_UNORM ), + rttr::value( "B8G8R8A8_TYPELESS", ResourceFormat::RESOURCE_FORMAT_B8G8R8A8_TYPELESS ), + rttr::value( "B8G8R8A8_UNORM_SRGB", ResourceFormat::RESOURCE_FORMAT_B8G8R8A8_UNORM_SRGB ), + rttr::value( "B8G8R8X8_TYPELESS", ResourceFormat::RESOURCE_FORMAT_B8G8R8X8_TYPELESS ), + rttr::value( "B8G8R8X8_UNORM_SRGB", ResourceFormat::RESOURCE_FORMAT_B8G8R8X8_UNORM_SRGB ), + rttr::value( "BC6H_TYPELESS", ResourceFormat::RESOURCE_FORMAT_BC6H_TYPELESS ), + rttr::value( "BC6H_UF16", ResourceFormat::RESOURCE_FORMAT_BC6H_UF16 ), + rttr::value( "BC6H_SF16", ResourceFormat::RESOURCE_FORMAT_BC6H_SF16 ), + rttr::value( "BC7_TYPELESS", ResourceFormat::RESOURCE_FORMAT_BC7_TYPELESS ), + rttr::value( "BC7_UNORM", ResourceFormat::RESOURCE_FORMAT_BC7_UNORM ), + rttr::value( "BC7_UNORM_SRGB", ResourceFormat::RESOURCE_FORMAT_BC7_UNORM_SRGB ), + rttr::value( "AYUV", ResourceFormat::RESOURCE_FORMAT_AYUV ), + rttr::value( "Y410", ResourceFormat::RESOURCE_FORMAT_Y410 ), + rttr::value( "Y416", ResourceFormat::RESOURCE_FORMAT_Y416 ), + rttr::value( "NV12", ResourceFormat::RESOURCE_FORMAT_NV12 ), + rttr::value( "P010", ResourceFormat::RESOURCE_FORMAT_P010 ), + rttr::value( "P016", ResourceFormat::RESOURCE_FORMAT_P016 ), + rttr::value( "420_OPAQUE", ResourceFormat::RESOURCE_FORMAT_420_OPAQUE ), + rttr::value( "YUY2", ResourceFormat::RESOURCE_FORMAT_YUY2 ), + rttr::value( "Y210", ResourceFormat::RESOURCE_FORMAT_Y210 ), + rttr::value( "Y216", ResourceFormat::RESOURCE_FORMAT_Y216 ), + rttr::value( "NV11", ResourceFormat::RESOURCE_FORMAT_NV11 ), + rttr::value( "AI44", ResourceFormat::RESOURCE_FORMAT_AI44 ), + rttr::value( "IA44", ResourceFormat::RESOURCE_FORMAT_IA44 ), + rttr::value( "P8", ResourceFormat::RESOURCE_FORMAT_P8 ), + rttr::value( "A8P8", ResourceFormat::RESOURCE_FORMAT_A8P8 ), + rttr::value( "B4G4R4A4_UNORM", ResourceFormat::RESOURCE_FORMAT_B4G4R4A4_UNORM ), + rttr::value( "P208", ResourceFormat::RESOURCE_FORMAT_P208 ), + rttr::value( "V208", ResourceFormat::RESOURCE_FORMAT_V208 ), + rttr::value( "V408", ResourceFormat::RESOURCE_FORMAT_V408 ) + ); + + rttr::registration::enumeration< ShaderType >( "sw::ShaderType" ) + ( + rttr::value( "VertexShader", ShaderType::VertexShader ), + rttr::value( "PixelShader", ShaderType::PixelShader ), + rttr::value( "GeometryShader", ShaderType::GeometryShader ), + rttr::value( "TesselationControlShader", ShaderType::TesselationControlShader ), + rttr::value( "TesselationEvaluationShader", ShaderType::TesselationEvaluationShader ), + rttr::value( "ComputeShader", ShaderType::ComputeShader ) + ); + + + rttr::registration::enumeration< BufferType >( "sw::BufferType" ) + ( + rttr::value( "VertexBuffer", BufferType::VertexBuffer ), + rttr::value( "IndexBuffer", BufferType::IndexBuffer ), + rttr::value( "ConstantBuffer", BufferType::ConstantBuffer ) + ); + + + rttr::registration::enumeration< PrimitiveTopology >( "sw::PrimitiveTopology" ) + ( + rttr::value( "Points", PrimitiveTopology::Points ), + rttr::value( "Lines", PrimitiveTopology::Lines ), + rttr::value( "LinesAdjacency", PrimitiveTopology::LinesAdjacency ), + rttr::value( "LineStrip", PrimitiveTopology::LineStrip ), + rttr::value( "LineStripAdjacency", PrimitiveTopology::LineStripAdjacency ), + rttr::value( "Triangles", PrimitiveTopology::Triangles ), + rttr::value( "TrianglesAdjacency", PrimitiveTopology::TrianglesAdjacency ), + rttr::value( "TriangleStrip", PrimitiveTopology::TriangleStrip ), + rttr::value( "TriangleStripAdjacency", PrimitiveTopology::TriangleStripAdjacency ) + ); + +//====================================================================================// +// Resources +//====================================================================================// + + rttr::registration::class_< SwapChain >( "sw::SwapChain" ); + + + // Blending + rttr::registration::class_< BlendingInfo >( "sw::BlendingInfo" ) + .property_readonly( "CustomBlendFactor", &BlendingInfo::CustomBlendFactor ) BIND_AS_PTR + .property_readonly( "EnableBlending", &BlendingInfo::EnableBlending ) + .property_readonly( "ColorOperation", &BlendingInfo::ColorOperation ) + .property_readonly( "AlphaOperation", &BlendingInfo::AlphaOperation ) + .property_readonly( "SrcColorBlend", &BlendingInfo::SrcColorBlend ) + .property_readonly( "DstColorBlend", &BlendingInfo::DstColorBlend ) + .property_readonly( "SrcAlphaBlend", &BlendingInfo::SrcAlphaBlend ) + .property_readonly( "DstAlphaBlend", &BlendingInfo::DstAlphaBlend ); + + rttr::registration::class_< BlendingState >( "sw::BlendingState" ) + .property_readonly( "Descriptor", &BlendingState::GetDescriptor ) BIND_AS_PTR; + + + // Rasterizer + rttr::registration::class_< RasterizerStateInfo >( "sw::RasterizerStateInfo" ) + .property_readonly( "CullMode", &RasterizerStateInfo::CullMode ) + .property_readonly( "FillMode", &RasterizerStateInfo::FillMode ) + .property_readonly( "IsClockwise", &RasterizerStateInfo::IsClockwise ) + .property_readonly( "EnableScissor", &RasterizerStateInfo::EnableScissor ) + .property_readonly( "EnableZClipping", &RasterizerStateInfo::EnableZClipping ) + .property_readonly( "ConservativeRaserizer", &RasterizerStateInfo::ConservativeRasterizer ) + .property_readonly( "DepthBias", &RasterizerStateInfo::DepthBias ); + + + rttr::registration::class_< RasterizerState >( "sw::RasterizerState" ) + .property_readonly( "Descriptor", &RasterizerState::GetDescriptor ) BIND_AS_PTR; + + + // Depth/Stencil + rttr::registration::class_< DepthStencilInfo >( "sw::DepthStencilInfo" ) + .property_readonly( "EnableDepthTest", &DepthStencilInfo::EnableDepthTest ) + .property_readonly( "EnableStencilTest", &DepthStencilInfo::EnableStencilTest ); + + rttr::registration::class_< DepthStencilState >( "sw::DepthStencilState" ) + .property_readonly( "Descriptor", &RasterizerState::GetDescriptor ) BIND_AS_PTR; + + + rttr::registration::class_< Resource >( "sw::Resource" ) + .property_readonly( "Name", &Resource::m_name ) + ( + rttr::metadata( MetaDataType::AllowInSaveFile, false ), + rttr::metadata( MetaDataType::Serialize, false ) + ) + .property_readonly( "References", &Resource::m_references ) + ( + rttr::metadata( MetaDataType::AllowInSaveFile, false ), + rttr::metadata( MetaDataType::Serialize, false ) + ) + .property_readonly( "FilePath", &Resource::GetFilePath ) + ( + rttr::metadata( MetaDataType::AllowInSaveFile, false ), + rttr::metadata( MetaDataType::Serialize, false ) + ); + +} + + + +namespace sw +{ + + +// ================================ // +// +std::string Resource::GetResourceName () const +{ + return m_name; +} + +// ================================ // +// +AssetPath Resource::GetAssetPath () const +{ + return AssetPath::FromString( m_name ).Get(); +} + +// ================================ // +// +filesystem::Path Resource::GetFilePath () const +{ + return AssetPath::FromString( m_name ).Get().GetFile(); +} + + +} // sw + diff --git a/Resources/ResourceObject.h b/Resources/ResourceObject.h index b09b416..38a4c21 100644 --- a/Resources/ResourceObject.h +++ b/Resources/ResourceObject.h @@ -1,107 +1,141 @@ #pragma once -/**@file ResourceObject.h +/** +@file Resource.h @author nieznanysprawiciel -@copyright Plik jest cz�ci� silnika graficznego SWEngine. +@copyright File is part of Sleeping Wombat Libraries. +*/ -@brief Plik zawiera deklaracj� i definicj� klasy ResourceObject s�u��c� -do zliczania odwo�a� do obiektu.*/ #include "swCommonLib/Serialization/PropertySerialization/EngineObject.h" +#include "swGraphicAPI/Resources/ResourcePtr.h" +#include "swGraphicAPI/ResourceManager/PathTranslators/AssetPath.h" //#include +#include -/**@brief Klasa u�atwiaj�ca zarz�dzanie odwo�aniami do asset�w. -@ingroup GraphicAPI -Obiekty asset�w (np. MaterialObject, TextureObject, VertexShader, PixelShader itp.) wymagaj� jakiego� systemu zapewniaj�cego wsp�dzielenie mi�dzy innymi obiektami. +namespace sw +{ + -Do ka�dego pojedynczego obiektu mog� istnie� wilokrotne odwo�ania w klasie MeshAsset, -a tak�e w obiektach dziedzicz�cych po @ref StaticActor oraz w modu�ach silnika. -Z tego wzgl�du istnieje zmienna m_objectReferences, kt�ra zlicza odwo�ania do obiekt�w. +class Resource; +class ResourceManager; -�aden obiekt nie powinien by� kasowany, dop�ki istniej� do niego odwo�ania. +typedef uint32 ResourceID; +template< class ResourceType > class ResourceContainer; -Zmienna m_uniqueId jest na pocz�tku ustawiana na 0. Jej faktyczne ustawienie odbywa robi klasa ResourceContainer. -Jest to wymagane do u�atwienia obs�ugi wielow�tkowo�ci. Inaczej mog�yby si� pokrywa� identyfikatory. -@todo Zliczanie referencji w ResourceObject nie nadaje si� do wielow�tkowo�ci. Poprawi� w odpowiednim momencie. -*/ -class ResourceObject : public sw::EngineObject +/**@brief Class Restricts access to some functions only for chosen classes.*/ +template< typename ResType > +class ResourceAccessKey { - RTTR_ENABLE( sw::EngineObject ); + friend class sw::ResourceManager; + friend class sw::ResourceContainer< ResType >; + +private: + ResourceAccessKey() = default; ///< Only friend class can create key. + ResourceAccessKey( const ResourceAccessKey& ) {} ///< Only friend class can create key. + ResourceAccessKey( const ResourceAccessKey&& ) {} ///< Only friend class can create key. +public: +}; + + + +/**@brief Base class for all assets and resources. It supports reference counting. +@ingroup GraphicAPI + +Resource can be referenced from multiple actors or other assets. All references should remember to increment and decrement +reference counter to avoid deletion. Use class ResourcePtr for this purpose. + +@todo Zliczanie referencji w Resource nie nadaje si� do wielow�tkowo�ci. Poprawi� w odpowiednim momencie. +@todo Rename ResourceObject.h to Resoruce.h +*/ +class Resource : public EngineObject +{ + RTTR_ENABLE( EngineObject ); RTTR_REGISTRATION_FRIEND private: - unsigned int m_objectReferences; ///< Liczba asset�w, kt�re sie odwo�uj�. @todo To powinien by� std::atomic_uint, ale wtedy nie kompiluje si� z CLRem. - unsigned int m_uniqueId; ///< Unikalny identyfikator zasobu. + + uint32 m_references; ///< Number of references to this Resource. (@todo This should be atomic, but atomics won't compile with CLR). + std::string m_name; protected: - virtual ~ResourceObject() = default; /// ) { delete this; } + + /**@brief Reference counting functions. + Use ResourcePtr to manage reference count.*/ + inline void AddAssetReference () { ++m_references; } + inline void AddObjectReference () { ++m_references; } + inline void DeleteAssetReference () { --m_references; } + inline void DeleteObjectReference () { --m_references; } + + /**@brief Returns name of resource. + Default implementation returns AssetPath converted to string.*/ + virtual std::string GetResourceName () const; + + /**@brief Returns AssetPath object.*/ + virtual AssetPath GetAssetPath () const; + + /**@brief Returns Resource path in filesystem*/ + virtual filesystem::Path GetFilePath () const; + +public: + + /**@brief Override in derived classes, if objects is suitable to be cached.*/ + virtual bool IsCacheable () const { return false; } + +protected: + + void SetAssetPath ( const AssetPath& assetPath ) { m_name = assetPath.String(); } +}; + +typedef ResourcePtr< Resource > ResourcePointer; //----------------------------------------------------------------------------------------------// -// ResourceObject // +// Resource // //----------------------------------------------------------------------------------------------// //==============================================================================================// - -/**@brief Funkcja informuje czy obiekt s� obiektu, kt�re odwo�uj� si� do assetu. - -@param[out] file_ref W zmiennej zostanie umieszczona liczba referencji plikowych. -@param[out] other_ref W zmiennej zostanie umieszczona liczba referencji bezpo�rednich od obiekt�w. -@return Zwraca warto�� logiczn� m�wi�c� czy asset nadaje si� do usuni�cia. -*/ -inline bool ResourceObject::CanDelete( unsigned int& objectRef ) +// ================================ // +// +inline bool Resource::CanDelete ( uint32& objectRef ) const { - objectRef = m_objectReferences; + objectRef = m_references; - if( m_objectReferences == 0 ) + if( m_references == 0 ) return true; return false; } -/**@brief Funkcja informuje czy obiekt s� obiektu, kt�re odwo�uj� si� do assetu. - -@return Zwraca warto�� logiczn� m�wi�c� czy asset nadaje si� do usuni�cia. -*/ -inline bool ResourceObject::CanDelete() +// ================================ // +// +inline bool Resource::CanDelete () const { - if( m_objectReferences == 0 ) + if( m_references == 0 ) return true; return false; } + + +} // sw + diff --git a/Resources/ResourcePtr.h b/Resources/ResourcePtr.h index 0465add..90530f9 100644 --- a/Resources/ResourcePtr.h +++ b/Resources/ResourcePtr.h @@ -1,9 +1,23 @@ #pragma once +/** +@file ResourcePtr.h +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + + #include +// Included to register wrapper_mapper in rttr +#include "swCommonLib/Common/RTTR.h" + + +namespace sw +{ + -class ResourceObject; +class Resource; /**@brief Wrapper for low level resources and high level assets. @@ -18,99 +32,183 @@ template< typename ResourceType > class ResourcePtr { private: + ResourceType* m_resource; public: - ResourcePtr() - { - static_assert( std::is_base_of< ResourceObject, ResourceType >::value, "Template parameter type must inherit from ResourceObject" ); - m_resource = nullptr; - } - ResourcePtr( ResourceType* ptr ) - { - static_assert( std::is_base_of< ResourceObject, ResourceType >::value, "Template parameter type must inherit from ResourceObject" ); - m_resource = ptr; - } + explicit ResourcePtr (); + ResourcePtr ( ResourceType* ptr ); + ResourcePtr ( const ResourcePtr& other ); + ResourcePtr ( ResourcePtr&& other ); - ~ResourcePtr() - { - ReleaseResource(); - } + ~ResourcePtr (); +public: + + void operator= ( ResourceType* ptr ); + void operator= ( const ResourcePtr< ResourceType >& ptr ); + ResourceType* operator* (); + ResourceType* operator-> (); + const ResourceType* operator* () const; + const ResourceType* operator-> () const; + operator void* () const; - ResourcePtr( const ResourcePtr& other ) - { - m_resource = nullptr; - AssignPointer( other.m_resource ); - } + void ReleaseResource (); + void AssignPointer ( ResourceType* ptr ); - ResourcePtr( ResourcePtr&& other ) - { - if( this != &other) - { - m_resource = other.m_resource; - other.m_resource = nullptr; - } - } + ResourceType* Ptr () const; - void operator=( ResourceType* ptr ) - { - ReleaseResource(); - AssignPointer( ptr ); - } +}; - void operator=( const ResourcePtr< ResourceType >& ptr ) - { - ReleaseResource(); - AssignPointer( ptr.m_resource ); - } +#define DEFINE_RESOURCE_PTR_TYPE( type ) typedef ResourcePtr< type > type ## Ptr; - operator void*() const - { - return m_resource; - } - ResourceType* operator*() - { - return m_resource; - } +//====================================================================================// +// Implementation +//====================================================================================// - ResourceType* operator->() - { - return m_resource; - } +// ================================ // +// +template< typename ResourceType > +inline ResourcePtr< ResourceType >::ResourcePtr () +{ + static_assert( std::is_base_of< Resource, ResourceType >::value, "Template parameter type must inherit from Resource" ); + m_resource = nullptr; +} - const ResourceType* operator*() const - { - return m_resource; - } +// ================================ // +// +template< typename ResourceType > +inline ResourcePtr< ResourceType >::ResourcePtr ( ResourceType* ptr ) + : m_resource( nullptr ) +{ + static_assert( std::is_base_of< Resource, ResourceType >::value, "Template parameter type must inherit from Resource" ); + AssignPointer( ptr ); +} - const ResourceType* operator->() const - { - return m_resource; - } +// ================================ // +// +template< typename ResourceType > +inline ResourcePtr< ResourceType >::~ResourcePtr () +{ + ReleaseResource(); +} + +// ================================ // +// +template< typename ResourceType > +inline ResourcePtr< ResourceType >::ResourcePtr ( const ResourcePtr& other ) +{ + m_resource = nullptr; + AssignPointer( other.m_resource ); +} - void ReleaseResource() +// ================================ // +// +template< typename ResourceType > +inline ResourcePtr< ResourceType >::ResourcePtr ( ResourcePtr&& other ) +{ + if( this != &other ) { - if( m_resource ) - m_resource->DeleteObjectReference(); - m_resource = nullptr; + m_resource = other.m_resource; + other.m_resource = nullptr; } +} + +// ================================ // +// +template< typename ResourceType > +void ResourcePtr< ResourceType >::operator= ( ResourceType* ptr ) +{ + ReleaseResource(); + AssignPointer( ptr ); +} + +// ================================ // +// +template< typename ResourceType > +void ResourcePtr< ResourceType >::operator= ( const ResourcePtr< ResourceType >& ptr ) +{ + ReleaseResource(); + AssignPointer( ptr.m_resource ); +} + +// ================================ // +// +template< typename ResourceType > +inline ResourcePtr< ResourceType >::operator void* () const +{ + return m_resource; +} + +// ================================ // +// +template< typename ResourceType > +ResourceType* ResourcePtr< ResourceType >::operator* () +{ + return m_resource; +} - void AssignPointer( ResourceType* ptr ) +// ================================ // +// +template< typename ResourceType > +ResourceType* ResourcePtr< ResourceType >::operator-> () +{ + return m_resource; +} + +// ================================ // +// +template< typename ResourceType > +const ResourceType* ResourcePtr< ResourceType >::operator* () const +{ + return m_resource; +} + +// ================================ // +// +template< typename ResourceType > +const ResourceType* ResourcePtr< ResourceType >::operator-> () const +{ + return m_resource; +} + +// ================================ // +// +template< typename ResourceType > +inline void ResourcePtr< ResourceType >::ReleaseResource () +{ + if( m_resource ) + m_resource->DeleteObjectReference(); + m_resource = nullptr; +} + +// ================================ // +// +template< typename ResourceType > +inline void ResourcePtr< ResourceType >::AssignPointer ( ResourceType* ptr ) +{ + if( ptr ) { - if( ptr ) - { - m_resource = ptr; - m_resource->AddObjectReference(); - } + m_resource = ptr; + m_resource->AddObjectReference(); } +} - ResourceType* Ptr () const - { return m_resource; } +// ================================ // +// +template< typename ResourceType > +inline ResourceType* ResourcePtr< ResourceType >::Ptr () const +{ + return m_resource; +} + +} // sw -}; +//====================================================================================// +// Register in rttr as wrapper +//====================================================================================// namespace rttr @@ -120,10 +218,10 @@ namespace rttr template< typename T > -struct wrapper_mapper< ResourcePtr< T > > +struct wrapper_mapper< sw::ResourcePtr< T > > { - using wrapped_type = decltype( std::declval< ResourcePtr< T > >().Ptr() ); - using type = ResourcePtr< T >; + using wrapped_type = decltype( std::declval< sw::ResourcePtr< T > >().Ptr() ); + using type = sw::ResourcePtr< T >; inline static wrapped_type get ( const type& obj ) { @@ -132,7 +230,7 @@ struct wrapper_mapper< ResourcePtr< T > > inline static type create ( const wrapped_type& value ) { - return ResourcePtr< T >( value ); + return sw::ResourcePtr< T >( value ); } }; diff --git a/Resources/ResourcesFactory.h b/Resources/ResourcesFactory.h index 164cb1f..2844b2e 100644 --- a/Resources/ResourcesFactory.h +++ b/Resources/ResourcesFactory.h @@ -2,53 +2,89 @@ /** @file ResourcesFactory.h @author nieznanysprawiciel -@copyright Plik jest cz�ci� silnika graficznego SWEngine. +@copyright File is part of Sleeping Wombat Libraries. */ + +#include "swCommonLib/Common/Exceptions/Nullable.h" +#include "swCommonLib/Common/Buffers/BufferRaw.h" + + #include "swGraphicAPI/Resources/MeshResources.h" -#include "swGraphicAPI/Resources/RasterizerState.h" -#include "swGraphicAPI/Resources/BlendingState.h" -#include "swGraphicAPI/Resources/DepthStencilState.h" +#include "swGraphicAPI/Resources/PipelineStates/RasterizerState.h" +#include "swGraphicAPI/Resources/PipelineStates/BlendingState.h" +#include "swGraphicAPI/Resources/PipelineStates/DepthStencilState.h" #include "swGraphicAPI/Resources/SwapChain.h" #include "swGraphicAPI/Rendering/IGraphicAPIInitializer.h" -class AssetsManager; +#include "swGraphicAPI/ResourceManager/PathTranslators/AssetPath.h" + + + + + +namespace sw +{ + +class ResourceManager; -/**@brief Klasa ze statycznymi funkcjami do tworzenia obiekt�w asset�w. + +class BufferCreator; +class LayoutCreator; +class BlendingStateCreator; +class RasterizerStateCreator; +class DepthStencilStateCreator; +class TextureCreator; + +template< typename ShaderObjectType > class ShaderCreator; + + + +/**@brief Class for creating low level graphic API dependent resources. @ingroup GraphicAPI -Jest potrzebna, �eby wybra� implementacj� resourc�w zgodn� z typem renderera. -Ka�de API graficzne powinno zaimplementowa� t� klas�. +This class should be implemented in graphicAPI implementation. At this moment we use link time +binding. In future this could change to virtual class. */ class ResourcesFactory { - friend class ResourceManager; - friend class AssetsManager; + friend class sw::BufferCreator; + + friend class sw::ShaderCreator< VertexShader >; + friend class sw::ShaderCreator< PixelShader >; + friend class sw::ShaderCreator< GeometryShader >; + friend class sw::ShaderCreator< EvaluationShader >; + friend class sw::ShaderCreator< ControlShader >; + friend class sw::ShaderCreator< ComputeShader >; + friend class sw::LayoutCreator; + friend class sw::BlendingStateCreator; + friend class sw::RasterizerStateCreator; + friend class sw::DepthStencilStateCreator; + friend class sw::TextureCreator; + + private: - static TextureObject* CreateTextureFromMemory ( const MemoryChunk& texData, TextureInfo&& texInfo ); - static VertexShader* CreateVertexShaderFromFile ( const std::wstring& fileName, const std::string& shaderName, const char* shaderModel = "vs_4_0" ); - static PixelShader* CreatePixelShaderFromFile ( const std::wstring& fileName, const std::string& shaderName, const char* shaderModel = "ps_4_0" ); - static ComputeShader* CreateComputeShaderFromFile ( const std::wstring& fileName, const std::string& shaderName, const char* shaderModel = "cs_4_0" ); + static sw::Nullable< VertexShader* > CreateVertexShader ( const AssetPath& name, const std::string& code, const std::string& entrypoint ); + static sw::Nullable< PixelShader* > CreatePixelShader ( const AssetPath& name, const std::string& code, const std::string& entrypoint ); + static sw::Nullable< ComputeShader* > CreateComputeShader ( const AssetPath& name, const std::string& code, const std::string& entrypoint ); - static BufferObject* CreateBufferFromMemory ( const std::wstring& name, const uint8* data, const BufferInfo& bufferInfo ); + static sw::Nullable< ShaderInputLayout* > CreateInputLayout ( const AssetPath& name, const InputLayoutDescriptor& layoutDesc ); - static VertexShader* CreateVertexShaderFromFile ( const std::wstring& fileName, - const std::string& shaderName, - ShaderInputLayout** layout, - InputLayoutDescriptor* layout_desc, - const char* shaderModel = "vs_4_0" ); + static sw::Nullable< Texture* > CreateTextureFromMemory ( const AssetPath& name, const BufferRaw& texData, sw::TextureInfo&& texInfo ); + static sw::Nullable< Buffer* > CreateBufferFromMemory ( const AssetPath& name, const uint8* data, const BufferInfo& bufferInfo ); - static BlendingState* CreateBlendingState ( const BlendingInfo& info ); - static RasterizerState* CreateRasterizerState ( const RasterizerStateInfo& info ); - static DepthStencilState* CreateDepthStencilState ( const DepthStencilInfo& info ); + static sw::Nullable< BlendingState* > CreateBlendingState ( const AssetPath& name, const BlendingInfo& info ); + static sw::Nullable< RasterizerState* > CreateRasterizerState ( const AssetPath& name, const RasterizerStateInfo& info ); + static sw::Nullable< DepthStencilState* > CreateDepthStencilState ( const AssetPath& name, const DepthStencilInfo& info ); public: - static IGraphicAPIInitializer* CreateAPIInitializer (); - static RenderTargetObject* CreateScreenRenderTarget (); - static SwapChain* CreateScreenSwapChain ( RenderTargetObject* screenRT ); - static InputLayoutDescriptor* CreateInputLayoutDescriptor ( const std::wstring& layoutName ); - static RenderTargetObject* CreateRenderTarget ( const std::wstring& name, const RenderTargetDescriptor& renderTargetDescriptor ); + static IGraphicAPIInitializer* CreateAPIInitializer (); + static RenderTarget* CreateScreenRenderTarget (); + static SwapChain* CreateScreenSwapChain ( RenderTarget* screenRT ); + static sw::Nullable< RenderTarget* > CreateRenderTarget ( const AssetPath& name, const RenderTargetDescriptor& renderTargetDescriptor ); }; + +} // sw \ No newline at end of file diff --git a/Resources/Shaders/Exceptions/CompilationException.h b/Resources/Shaders/Exceptions/CompilationException.h new file mode 100644 index 0000000..f7f2d41 --- /dev/null +++ b/Resources/Shaders/Exceptions/CompilationException.h @@ -0,0 +1,54 @@ +#pragma once +/** +@file CompilationException.h +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + + +#include "swCommonLib/Common/Exceptions/Exception.h" + + +namespace sw +{ + +class CompilationException; +DEFINE_PTR_TYPE( CompilationException ); + + + +/**@brief Shader compilation failed.*/ +class CompilationException : public RuntimeException +{ + RTTR_ENABLE( RuntimeException ); +private: +protected: +public: + explicit CompilationException ( std::string compilationError ); + virtual ~CompilationException () = default; + +public: + + static CompilationExceptionPtr Create ( std::string compilationError ); +}; + + +//====================================================================================// +// Implementation +//====================================================================================// + + +// ================================ // +// +inline CompilationException::CompilationException ( std::string compilationError ) + : RuntimeException( std::move( compilationError ) ) +{} + +// ================================ // +// +inline CompilationExceptionPtr CompilationException::Create ( std::string compilationError ) +{ + return std::make_shared< CompilationException >( std::move( compilationError ) ); +} + +} // sw diff --git a/Resources/Shaders/IShader.h b/Resources/Shaders/IShader.h new file mode 100644 index 0000000..1a1d046 --- /dev/null +++ b/Resources/Shaders/IShader.h @@ -0,0 +1,37 @@ +#pragma once +/** +@file IShader.h +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + + +#include "swGraphicAPI/Resources/ResourceObject.h" + +#include + + + +namespace sw +{ + +/**@brief Shader interface. +@ingroup Shaders*/ +class IShader : public Resource +{ + RTTR_ENABLE( Resource ) +private: +protected: +protected: + + explicit IShader ( const AssetPath& assetPath ) : Resource( assetPath ) {} + virtual ~IShader () = default; + +public: + + virtual bool ReloadFromFile () = 0; + virtual bool ReloadFromBinFile () = 0; + virtual void SaveShaderBinFile ( const filesystem::Path& fileName ) = 0; +}; + +} // sw diff --git a/Resources/Shaders/IShaderInputLayout.h b/Resources/Shaders/IShaderInputLayout.h new file mode 100644 index 0000000..14e54de --- /dev/null +++ b/Resources/Shaders/IShaderInputLayout.h @@ -0,0 +1,31 @@ +#pragma once +/** +@file IShaderInputLayout.h +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + + + +#include "swGraphicAPI/Resources/ResourceObject.h" + + + + +namespace sw +{ + +// ================================ // +// +class IShaderInputLayout : public Resource +{ + RTTR_ENABLE( Resource ); +private: +protected: + explicit IShaderInputLayout ( const AssetPath& assetPath ) : Resource( assetPath ) {} + virtual ~IShaderInputLayout () = default; +public: + +}; + +} // sw diff --git a/Resources/Shaders/InputLayout.h b/Resources/Shaders/InputLayout.h new file mode 100644 index 0000000..1b6ba96 --- /dev/null +++ b/Resources/Shaders/InputLayout.h @@ -0,0 +1,38 @@ +#pragma once +/** +@file InputLayout.h +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + + +#include "swGraphicAPI/Resources/Shaders/IShaderInputLayout.h" + + + + +namespace sw +{ + + + +/**@brief Class storing vertex shader input layout. +@ingroup Shaders +@ingroup Buffers +@ingroup Resources*/ +class ShaderInputLayout : public IShaderInputLayout +{ + RTTR_ENABLE( IShaderInputLayout ); +private: +protected: + + virtual ~ShaderInputLayout () = default; + +public: + explicit ShaderInputLayout ( const AssetPath& assetPath ) : IShaderInputLayout( assetPath ) {} +}; + +DEFINE_RESOURCE_PTR_TYPE( ShaderInputLayout ); + + +} // sw \ No newline at end of file diff --git a/Resources/Shaders/LayoutInitData.h b/Resources/Shaders/LayoutInitData.h new file mode 100644 index 0000000..79d7e5f --- /dev/null +++ b/Resources/Shaders/LayoutInitData.h @@ -0,0 +1,96 @@ +#pragma once +/** +@file LayoutInitData.h +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + + +#include +#include + + +#include "swGraphicAPI/Rendering/GraphicAPIConstants.h" +#include "swGraphicAPI/ResourceManager/AssetCreators/IAssetCreateInfo.h" + + + + +namespace sw +{ + +/**@brief Posible semantics of vertex attributes in shaders. +@ingroup Shaders*/ +enum class AttributeSemantic : uint8 +{ + Position, + PositionTransformed, + Normal, + Tangent, + Binormal, + Color, + Texcoord, + PointSize, + BlendIndicies, + BlendWeights +}; + + +/**@brief Describes one attribute in vertex layout descriptor. +@ingroup Shaders*/ +struct LayoutEntry +{ + AttributeSemantic SemanticName; + ResourceFormat AttribFormat; + uint16 InputSlot; + uint16 ByteOffset; + uint32 InstanceDataStep; ///< Number of instances which will be drawn with the same data (before stepping to next element). + bool PerInstance; ///< Set to true if this entry describes per instance attribute. +}; + + + + + + +/**@brief Describes vertex shader layout. + +@todo Move to sw namespace + +@ingroup Buffers +@ingroup Shaders +@ingroup Resources*/ +class InputLayoutDescriptor : public sw::IAssetCreateInfo +{ + RTTR_ENABLE( sw::IAssetCreateInfo ); + RTTR_REGISTRATION_FRIEND; +private: + + std::vector< sw::LayoutEntry > m_entries; + +protected: +public: + explicit InputLayoutDescriptor () = default; + virtual ~InputLayoutDescriptor () = default; + + + /**@brief Adds shader input layout entry. + This function will fill not specified data with apropriate values.*/ + void AddEntry ( sw::AttributeSemantic semanticName, ResourceFormat format ); + void AddEntry ( sw::AttributeSemantic semanticName, ResourceFormat format, uint16 inputSlot ); + void AddEntryPerInstance ( sw::AttributeSemantic semanticName, ResourceFormat format, uint16 inputSlot, uint32 instanceDataStep ); + + virtual TypeID GetAssetType () const override; + + const std::vector< sw::LayoutEntry >& GetEntries () const { return m_entries; } + +protected: + + void AddEntryImpl ( sw::AttributeSemantic semanticName, ResourceFormat format, uint16 inputSlot, bool perInstance, uint32 instanceDataStep ); +}; + +} // sw + + + + diff --git a/Resources/Shaders/Layouts.cpp b/Resources/Shaders/Layouts.cpp new file mode 100644 index 0000000..21b6be1 --- /dev/null +++ b/Resources/Shaders/Layouts.cpp @@ -0,0 +1,91 @@ +/** +@file Layouts.cpp +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ +#include "swGraphicAPI/ResourceManager/stdafx.h" + + +#include "LayoutInitData.h" +#include "InputLayout.h" + + +RTTR_REGISTRATION +{ + + rttr::registration::enumeration< sw::AttributeSemantic >( "sw::AttributeSemantic" ) + ( + rttr::value( "Position", sw::AttributeSemantic::Position ), + rttr::value( "PositionTransformed", sw::AttributeSemantic::PositionTransformed ), + rttr::value( "Normal", sw::AttributeSemantic::Normal ), + rttr::value( "Tangent", sw::AttributeSemantic::Tangent ), + rttr::value( "Binormal", sw::AttributeSemantic::Binormal ), + rttr::value( "Color", sw::AttributeSemantic::Color ), + rttr::value( "Texcoord", sw::AttributeSemantic::Texcoord ), + rttr::value( "PointSize", sw::AttributeSemantic::PointSize ), + rttr::value( "BlendIndicies", sw::AttributeSemantic::BlendIndicies ), + rttr::value( "BlendWeights", sw::AttributeSemantic::BlendWeights ) + ); + + rttr::registration::class_< sw::LayoutEntry >( "sw::LayoutEntry" ) + .property( "Semantic", &sw::LayoutEntry::SemanticName ) + .property( "Format", &sw::LayoutEntry::AttribFormat ) + .property( "InputSlot", &sw::LayoutEntry::InputSlot ) + .property( "ByteOffset", &sw::LayoutEntry::ByteOffset ) + .property( "IsPerInstance", &sw::LayoutEntry::PerInstance ) + .property( "InstanceDataStep", &sw::LayoutEntry::InstanceDataStep ); + + rttr::registration::class_< sw::InputLayoutDescriptor >( "sw::InputLayoutDescriptor" ) + .property( "Entries", &sw::InputLayoutDescriptor::m_entries ); + +} + + +namespace sw +{ + + +// ================================ // +// +void InputLayoutDescriptor::AddEntry ( sw::AttributeSemantic semanticName, ResourceFormat format ) +{ + AddEntryImpl( semanticName, format, 0, false, 0 ); +} + +// ================================ // +// +void InputLayoutDescriptor::AddEntry ( sw::AttributeSemantic semanticName, ResourceFormat format, uint16 inputSlot ) +{ + AddEntryImpl( semanticName, format, inputSlot, false, 0 ); +} + +// ================================ // +// +void InputLayoutDescriptor::AddEntryPerInstance ( sw::AttributeSemantic semanticName, ResourceFormat format, uint16 inputSlot, uint32 instanceDataStep ) +{ + AddEntryImpl( semanticName, format, inputSlot, true, instanceDataStep ); +} + + +// ================================ // +// +TypeID InputLayoutDescriptor::GetAssetType () const +{ + return TypeID::get< ShaderInputLayout >(); +} + +// ================================ // +// +void InputLayoutDescriptor::AddEntryImpl ( sw::AttributeSemantic semanticName, ResourceFormat format, uint16 inputSlot, bool perInstance, uint32 instanceDataStep ) +{ + sw::LayoutEntry entry; + entry.SemanticName = semanticName; + entry.AttribFormat = format; + entry.InputSlot = inputSlot; + entry.PerInstance = perInstance; + entry.InstanceDataStep = instanceDataStep; + + m_entries.push_back( entry ); +} + +} // sw diff --git a/Resources/Shaders/ShaderInitData.h b/Resources/Shaders/ShaderInitData.h new file mode 100644 index 0000000..e37d004 --- /dev/null +++ b/Resources/Shaders/ShaderInitData.h @@ -0,0 +1,76 @@ +#pragma once +/** +@file ShaderInitData.h +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + +#include "swCommonLib/Common/RTTR.h" +#include "swGraphicAPI/ResourceManager/AssetCreators/IAssetCreateInfo.h" + +#include "swGraphicAPI/Resources/Shaders/Shaders.h" + +#include + + + +namespace sw +{ + + +/**@brief Create shader of given type from file path. + +Note: File path will be passed as second parameter to creator function so is ommited here. +@ingroup Shaders*/ +struct ShaderInitData : public IAssetCreateInfo +{ + RTTR_ENABLE( IAssetCreateInfo ); +public: + + std::string EntryFunction; ///< Name of shader entry point function. "main" by default. + ShaderType Type; ///< Type of shader to create. + + + +// ================================ // +// + ShaderInitData( ShaderType type ) + : Type( type ) + , EntryFunction( "main" ) + {} + + virtual TypeID GetAssetType () const override; + +public: + + static ShaderType GetFromTypeID ( TypeID type ); +}; + + +/**@brief Create shader from string containing source code. +@ingroup Shaders*/ +struct ShaderCodeInitData : public ShaderInitData +{ + RTTR_ENABLE( ShaderInitData ); +public: + + std::string SourceCode; + + +// ================================ // +// + ShaderCodeInitData( ShaderType type ) + : ShaderInitData( type ) + {} + + ShaderCodeInitData( ShaderType type, std::string sourceCode ) + : ShaderInitData( type ) + , SourceCode( std::move( sourceCode ) ) + {} + +}; + + + +} // sw + diff --git a/Resources/Shaders/Shaders.cpp b/Resources/Shaders/Shaders.cpp new file mode 100644 index 0000000..79ba59e --- /dev/null +++ b/Resources/Shaders/Shaders.cpp @@ -0,0 +1,82 @@ +/** +@file Shaders.cpp +@author nieznanysprawiciel +@copyright File is part of graphic engine SWEngine. +*/ +#include "swGraphicAPI/ResourceManager/stdafx.h" + + +#include "ShaderInitData.h" +#include "LayoutInitData.h" +#include "InputLayout.h" +#include "Shaders.h" + + +using namespace sw; + + +RTTR_REGISTRATION +{ + + // Shader + rttr::registration::class_< ShaderInputLayout >( "sw::ShaderInputLayout" ); + rttr::registration::class_< IShader >( "sw::IShader" ); + + rttr::registration::class_< PixelShader >( "sw::PixelShader" ); + rttr::registration::class_< VertexShader >( "sw::VertexShader" ); + +} + + +namespace sw +{ + +// ================================ // +// +TypeID ShaderInitData::GetAssetType () const +{ + switch( Type ) + { + case ShaderType::VertexShader: + return TypeID::get< VertexShader >(); + case ShaderType::PixelShader: + return TypeID::get< PixelShader >(); + case ShaderType::GeometryShader: + return TypeID::get< GeometryShader >(); + case ShaderType::TesselationControlShader: + return TypeID::get< ControlShader >(); + case ShaderType::TesselationEvaluationShader: + return TypeID::get< EvaluationShader >(); + case ShaderType::ComputeShader: + return TypeID::get< ComputeShader >(); + default: + return TypeID::get_by_name( "" ); + break; + } +} + +// ================================ // +// +ShaderType ShaderInitData::GetFromTypeID ( TypeID type ) +{ + if( type == TypeID::get< VertexShader >() ) + return ShaderType::VertexShader; + if( type == TypeID::get< PixelShader >() ) + return ShaderType::PixelShader; + if( type == TypeID::get< GeometryShader >() ) + return ShaderType::GeometryShader; + if( type == TypeID::get< ControlShader >() ) + return ShaderType::TesselationControlShader; + if( type == TypeID::get< EvaluationShader >() ) + return ShaderType::TesselationEvaluationShader; + if( type == TypeID::get< ComputeShader >() ) + return ShaderType::ComputeShader; + + return ShaderType(); +} + + +} // sw + + + diff --git a/Resources/Shaders/Shaders.h b/Resources/Shaders/Shaders.h new file mode 100644 index 0000000..57bd4c4 --- /dev/null +++ b/Resources/Shaders/Shaders.h @@ -0,0 +1,169 @@ +#pragma once +/** +@file VertexShader.h +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + +#include "swGraphicAPI/Resources/Shaders/IShader.h" + +#include "swCommonLib/System/Path.h" + + +/**@defgroup Shaders Shaders + +Shader creation structures: +- @ref ShaderInitData +- @ref ShaderCodeInitData + +@ingroup Resources*/ + + + + + +namespace sw +{ + + +/**@brief Shader type flag. +@ingroup Shaders*/ +enum class ShaderType : uint8 +{ + VertexShader = 0x01, + PixelShader = 0x02, + GeometryShader = 0x04, + TesselationControlShader = 0x08, + TesselationEvaluationShader = 0x10, + ComputeShader = 0x20 +}; + + + +//----------------------------------------------------------------------------------------------// +// VertexShader // +//----------------------------------------------------------------------------------------------// + +/** @brief Vertex shader class. +@ingroup Shaders +@ingroup Resources +@ingroup GraphicAPI*/ +class VertexShader : public IShader +{ + RTTR_ENABLE( IShader ); +private: +protected: + virtual ~VertexShader () = default; +public: + explicit VertexShader ( const AssetPath& assetPath ) : IShader( assetPath ) {} +}; + +DEFINE_RESOURCE_PTR_TYPE( VertexShader ); + + +//----------------------------------------------------------------------------------------------// +// PixelShader // +//----------------------------------------------------------------------------------------------// + +/**@brief Pixel shader class. +@ingroup Shaders +@ingroup Resources +@ingroup GraphicAPI*/ +class PixelShader : public IShader +{ + RTTR_ENABLE( IShader ); +private: +protected: + virtual ~PixelShader () = default; +public: + explicit PixelShader ( const AssetPath& assetPath ) : IShader( assetPath ) {} +}; + +DEFINE_RESOURCE_PTR_TYPE( PixelShader ); + + +//----------------------------------------------------------------------------------------------// +// GeometryShader // +//----------------------------------------------------------------------------------------------// + +/**@brief Geometry shader class. +@ingroup Shaders +@ingroup Resources +@ingroup GraphicAPI*/ +class GeometryShader : public IShader +{ + RTTR_ENABLE( IShader ); +private: +protected: + virtual ~GeometryShader () = default; +public: + explicit GeometryShader ( const AssetPath& assetPath ) : IShader( assetPath ) {} +}; + +DEFINE_RESOURCE_PTR_TYPE( GeometryShader ); + + +//----------------------------------------------------------------------------------------------// +// ControlShader // +//----------------------------------------------------------------------------------------------// + +/**@brief Tesselation control shader class. +@ingroup Shaders +@ingroup Resources +@ingroup GraphicAPI*/ +class ControlShader : public IShader +{ + RTTR_ENABLE( IShader ); +private: +protected: + virtual ~ControlShader () = default; +public: + explicit ControlShader ( const AssetPath& assetPath ) : IShader( assetPath ) {} +}; + +DEFINE_RESOURCE_PTR_TYPE( ControlShader ); + + +//----------------------------------------------------------------------------------------------// +// EvaluationShader // +//----------------------------------------------------------------------------------------------// + +/**@brief Tesselation evaluation shader class. +@ingroup Shaders +@ingroup Resources +@ingroup GraphicAPI*/ +class EvaluationShader : public IShader +{ + RTTR_ENABLE( IShader ); +private: +protected: + virtual ~EvaluationShader () = default; +public: + explicit EvaluationShader ( const AssetPath& assetPath ) : IShader( assetPath ) {} +}; + +DEFINE_RESOURCE_PTR_TYPE( EvaluationShader ); + + +//----------------------------------------------------------------------------------------------// +// ComputeShader // +//----------------------------------------------------------------------------------------------// + +/**@brief Compute shader class. +@ingroup Shaders +@ingroup Resources +@ingroup GraphicAPI*/ +class ComputeShader : public IShader +{ + RTTR_ENABLE( IShader ); +private: +protected: + virtual ~ComputeShader () = default; +public: + explicit ComputeShader ( const AssetPath& assetPath ) : IShader( assetPath ) {} +}; + +DEFINE_RESOURCE_PTR_TYPE( ComputeShader ); + + +} // sw diff --git a/Resources/SwapChain.h b/Resources/SwapChain.h index 00750b6..818708b 100644 --- a/Resources/SwapChain.h +++ b/Resources/SwapChain.h @@ -6,6 +6,14 @@ typedef void* WindowHandler; + + +namespace sw +{ + + +/**@brief Descripto of SwapChain +@ingroup Resources*/ struct SwapChainDescriptor { WindowHandler WindowHandle; @@ -19,28 +27,29 @@ struct SwapChainDescriptor SwapChainDescriptor() - : SamplesCount( 1 ) - , SamplesQuality( 0 ) - , AllowFullscreen( true ) - , Format( ResourceFormat::RESOURCE_FORMAT_R8G8B8A8_UNORM ) - , WindowHandle( nullptr ) - , NumBuffers( 1 ) + : SamplesCount( 1 ) + , SamplesQuality( 0 ) + , AllowFullscreen( true ) + , Format( ResourceFormat::RESOURCE_FORMAT_R8G8B8A8_UNORM ) + , WindowHandle( nullptr ) + , NumBuffers( 1 ) {} }; - -class SwapChain : public ResourceObject +/**@brief +@ingroup Resources*/ +class SwapChain : public Resource { RTTR_ENABLE() protected: - ResourcePtr< RenderTargetObject > m_renderTarget; + ResourcePtr< RenderTarget > m_renderTarget; protected: - SwapChain( RenderTargetObject* windowRT ) - : ResourceObject( WRONG_ID ) - , m_renderTarget( windowRT ) + explicit SwapChain ( RenderTarget* windowRT ) + : Resource( CreateName( windowRT ) ) + , m_renderTarget( windowRT ) { assert( windowRT ); } @@ -50,13 +59,33 @@ class SwapChain : public ResourceObject {} - virtual void Present ( int syncInterval ) = 0; - virtual void Resize ( uint16 newWidth, uint16 newHeight ) = 0; + virtual void Present ( int syncInterval ) = 0; + virtual void Resize ( uint16 newWidth, uint16 newHeight ) = 0; + + ResourcePtr< RenderTarget > GetRenderTarget () { return m_renderTarget; } - ResourcePtr< RenderTargetObject > GetRenderTarget () { return m_renderTarget; } + // Inherited via Resource + virtual std::string GetResourceName () const override { return "SwapChain: " + m_renderTarget->GetResourceName(); } - // Inherited via ResourceObject - virtual std::string GetResourceName () const override { return "SwapChain: " + m_renderTarget->GetResourceName(); } +private: + + AssetPath CreateName ( RenderTarget* rt ) const; }; + +//====================================================================================// +// Implementation +//====================================================================================// + +// ================================ // +// +inline AssetPath SwapChain::CreateName ( RenderTarget* rt ) const +{ + auto rtPath = rt->GetAssetPath(); + auto swapChainPath = rtPath.GetInternalPath() / "SwpaChain"; + + return AssetPath( rtPath.GetFile(), swapChainPath ); +} + +} // sw diff --git a/Resources/Texture.cpp b/Resources/Texture.cpp deleted file mode 100644 index c638695..0000000 --- a/Resources/Texture.cpp +++ /dev/null @@ -1,99 +0,0 @@ -/** -@file Texture.cpp -@author nieznanysprawiciel -@copyright File is part of Sleeping Wombat Libraries. -*/ -#include "swGraphicAPI/ResourceManager/stdafx.h" - -#include "swGraphicAPI/Resources/Texture.h" - - - -RTTR_REGISTRATION -{ - - rttr::registration::enumeration< TextureType >( "TextureType" ) - ( - rttr::value( "Buffer", TextureType::TEXTURE_TYPE_BUFFER ), - rttr::value( "Texture 1D", TextureType::TEXTURE_TYPE_TEXTURE1D ), - rttr::value( "Texture 1D Array", TextureType::TEXTURE_TYPE_TEXTURE1D_ARRAY ), - rttr::value( "Texture 2D", TextureType::TEXTURE_TYPE_TEXTURE2D ), - rttr::value( "Texture 2D Array", TextureType::TEXTURE_TYPE_TEXTURE2D_ARRAY ), - rttr::value( "Texture 2D Multisample", TextureType::TEXTURE_TYPE_TEXTURE2D_MULTISAMPLE ), - rttr::value( "Texture 2D Multisample Array", TextureType::TEXTURE_TYPE_TEXTURE2D_MULTISAMPLE_ARRAY ), - rttr::value( "Texture 3D", TextureType::TEXTURE_TYPE_TEXTURE3D ) - ); - - rttr::registration::enumeration< MipMapFilter >( "MipMapFilter" ) - ( - rttr::value( "Bell", MipMapFilter::Bell ), - rttr::value( "Blackman", MipMapFilter::Blackman ), - rttr::value( "Box", MipMapFilter::Box ), - rttr::value( "bSpline", MipMapFilter::bSpline ), - rttr::value( "Catmullrom", MipMapFilter::Catmullrom ), - rttr::value( "Gaussian", MipMapFilter::Gaussian ), - rttr::value( "Kaiser", MipMapFilter::Kaiser ), - rttr::value( "Lanczos12", MipMapFilter::Lanczos12 ), - rttr::value( "Lanczos3", MipMapFilter::Lanczos3 ), - rttr::value( "Lanczos4", MipMapFilter::Lanczos4 ), - rttr::value( "Lanczos6", MipMapFilter::Lanczos6 ), - rttr::value( "Mitchell", MipMapFilter::Mitchell ), - rttr::value( "QuadraticAproximation", MipMapFilter::QuadraticAproximation ), - rttr::value( "QuadraticInterpolation", MipMapFilter::QuadraticInterpolation ), - rttr::value( "QuadraticMix", MipMapFilter::QuadraticMix ), - rttr::value( "Tent", MipMapFilter::Tent ), - rttr::value( "No filtering", MipMapFilter::Unknown ) - ); - - rttr::registration::class_< TextureInfo >( "TextureInfo" ) - .property_readonly( "Width", &TextureInfo::GetWidth ) - .property_readonly( "Height", &TextureInfo::GetHeight ) - .property_readonly( "ArraySize", &TextureInfo::GetArraySize ) - .property_readonly( "CPUReadable", &TextureInfo::IsCPUReadable ) - .property_readonly( "CPUWritable", &TextureInfo::IsCPUWriteable ) - .property_readonly( "SharedResource", &TextureInfo::IsSharedResource ) - .property_readonly( "CubeMap", &TextureInfo::IsCubeMapTex ) - .property_readonly( "GeneratedMipMaps", &TextureInfo::GenMipMaps ) - .property_readonly( "TextureType", &TextureInfo::TextureType ) - .property_readonly( "Usage", &TextureInfo::Usage ) - .property_readonly( "Format", &TextureInfo::Format ) - .property_readonly( "MipMapFilter", &TextureInfo::MipMapFilter ) - .property_readonly( "MipMapsLevels", &TextureInfo::GetMipLevels ) - .property_readonly( "FilePath", &TextureInfo::GetPath ); - - rttr::registration::class_< TextureObject >( "TextureObject" ) - .property_readonly( "Descriptor", &TextureObject::GetDescriptor ) BIND_AS_PTR; -} - - -//----------------------------------------------------------------------------------------------// -// TextureObject // -//----------------------------------------------------------------------------------------------// - - -/**@brief Por�wnuje ze soba dwa obiekty tekstur. - -Obiekty s� takie same, kiedy odwo�uj� si� do tego samego pliku. -*/ -bool TextureObject::operator==( TextureObject& object ) -{ - if( this->GetFilePath().String() == object.GetFilePath().String() ) - return true; - return false; -} - -/**@brief Por�wnuje ze soba dwa obiekty tekstur. - -Obiekty s� takie same, kiedy odwo�uj� si� do tego samego pliku. -*/ -bool TextureObject::operator==( const std::wstring& fileName ) -{ - typedef std::codecvt_utf8 convert_type; - std::wstring_convert converter; - auto convertedFileName = converter.to_bytes( fileName ); - - if( this->GetFilePath().String() == convertedFileName ) - return true; - return false; -} - diff --git a/Resources/Texture.h b/Resources/Texture.h deleted file mode 100644 index b8fd820..0000000 --- a/Resources/Texture.h +++ /dev/null @@ -1,157 +0,0 @@ -#pragma once -/** -@file Texture.h -@author nieznanysprawiciel -@copyright File is part of Sleeping Wombat Libraries. -*/ - - - -#include "swCommonLib/Common/ObjectDeleter.h" -#include "swCommonLib/System/Path.h" -#include "swCommonLib/Common/TypesDefinitions.h" -#include "swCommonLib/Common/MemoryChunk.h" - -#include "swGraphicAPI/Resources/ResourcePtr.h" -#include "swGraphicAPI/Resources/ResourceObject.h" -#include "swGraphicAPI/Rendering/GraphicAPIConstants.h" - - -//----------------------------------------------------------------------------------------------// -// TextureObject // -//----------------------------------------------------------------------------------------------// - -/**@defgroup Textures Textures -@ingroup Resources - -@todo Rename TextureObject to Texture. TextureObject is too long name. -*/ - -/**@brief Textures filtering modes. - -Poni�sze tryby filtrowania s� u�ywane przy tworzeniu mipmap. -Istnieje jeszcze drugi etap filtrowania przy pr�bkowania w pixel shaderze, -do kt�rego odnosi si� inna enumeracja. - -@ingroup Textures -*/ -enum class MipMapFilter : short -{ - Box = 0, ///< - Tent, ///< - Bell, ///< - bSpline, ///< - Mitchell, ///< - Lanczos3, ///< - Blackman, ///< - Lanczos4, ///< - Lanczos6, ///< - Lanczos12, ///< - Kaiser, ///< - Gaussian, ///< - Catmullrom, ///< - QuadraticInterpolation, ///< - QuadraticAproximation, ///< - QuadraticMix, ///< - - Unknown ///< -}; - - -/**@brief Deskryptor tekstury. - -@ingroup Textures -*/ -struct TextureInfo -{ - uint16 TextureWidth; ///< Szeroko�� tekstury w pikselach. - uint16 TextureHeight; ///< Wysoko�� tekstury w pikselach. - uint16 ArraySize; ///< Liczba element�w tablicy. - bool CPURead : 1; ///< Pozwala na odczyt tekstury przez CPU. - bool CPUWrite : 1; ///< Pozwala na zapis tekstury przez CPU. - bool AllowShareResource : 1; ///< Pozwala na dost�p do zasoby z wielu API graficznych i pomi�dzy kontekstami. - bool IsCubeMap : 1; ///< Nale�y ustawi� je�eli tekstura jest cubemap�. - bool GenerateMipMaps : 1; ///< Automatyczne generowanie mipmap. - TextureType TextureType; ///< Typ tekstury (liczba wymiar�w, multsampling). Na razie tekstura nie mo�e by� inna ni� dwuwymiarowa (mo�e by� tablic�). - ResourceUsage Usage; ///< Spos�b u�ycia render targetu. Wp�ywa na optymalizacje u�o�enia w pami�ci. - ResourceFormat Format; ///< Format tekstury (liczba kana��w, liczba bit�w na kana� itp) - MipMapFilter MipMapFilter; ///< Tryb filtrowania tekstury. U�ywany tylko je�eli ustawiono GenerateMipMaps na true. - uint16 MipMapLevels; ///< Liczba poziom�w mipmap. 1 oznacza tylko tekstur� oryginaln�. - uint16 CutOffMipMaps; ///< Usuwa podan� liczb� poziom�w mipmap. Przydatne gdy nie potrzebujemy tekstur zbyt wysokiej rozdzielczo�ci (np. stosuj�c dynamiczny LoD). - ///< Ustawienie warto�ci 1 oznacza, �e oryginalna tekstura zostanie zast�piona pierwsz� mipmap� w kolejno�ci. - - uint32 MemorySize; ///< Pami�� zajmowana przez tekstur�. - filesystem::Path FilePath; ///< �cie�ka do pliku z tekstur� lub jej nazwa. - - TextureInfo() - { - ArraySize = 1; - CPURead = false; - CPUWrite = false; - AllowShareResource = false; - IsCubeMap = false; - GenerateMipMaps = false; - Usage = ResourceUsage::RESOURCE_USAGE_DEFAULT; - MipMapFilter = MipMapFilter::Unknown; - MipMapLevels = 1; - CutOffMipMaps = 0; - TextureType = TextureType::TEXTURE_TYPE_TEXTURE2D; - MemorySize = 0; - } - -private: - RTTR_REGISTRATION_FRIEND; - - int GetWidth () { return TextureWidth; } - int GetHeight () { return TextureHeight; } - int GetArraySize () { return ArraySize; } - bool IsCPUReadable () { return CPURead; } - bool IsCPUWriteable () { return CPUWrite; } - bool IsSharedResource() { return AllowShareResource; } - bool IsCubeMapTex () { return IsCubeMap; } - bool GenMipMaps () { return GenerateMipMaps; } - int GetMipLevels () { return MipMapLevels; } - - std::string GetPath () { return FilePath.String(); } -}; - - - - - -/** @brief Base class for textures. -@ingroup Textures -@ingroup Resources -@ingroup GraphicAPI - -This class is platform independent. Inherit it while implementing chosen graphic API.*/ -class TextureObject : public ResourceObject -{ - RTTR_ENABLE( ResourceObject ); - friend ObjectDeleter; -private: -protected: - /// �eby unikn�� pomy�ki, obiekt mo�e by� kasowany tylko przez AssetsManager. Zapewnia to ObjectDeleter. - virtual ~TextureObject() = default; -public: - TextureObject() : ResourceObject( 0 ) {} - - virtual const filesystem::Path& GetFilePath () const = 0; ///< Returns name of file, from which this object was created. - - /**@brief Updates texture data on graphic card. - Note that size of dataPtr memory must large be enough to fill requested miplevel and array idx. - You can always check @ref GetDescriptor function to get desired info. - - @todo Do something with this when rendering will use event queues.*/ - virtual bool UpdateData ( uint8* dataPtr, uint16 mipLevel, uint16 arrayIdx ) = 0; - - /**@brief Copies texture data from graphic card to memory chunk.*/ - virtual MemoryChunk CopyData () const = 0; - virtual const TextureInfo& GetDescriptor () const = 0; ///< Gets texture descriptor. - - virtual std::string GetResourceName () const override { return GetFilePath().String(); } - - inline bool operator==( TextureObject& object ); - inline bool operator==( const std::wstring& file_name ); -}; - diff --git a/Resources/Textures/IRenderTarget.h b/Resources/Textures/IRenderTarget.h new file mode 100644 index 0000000..733621c --- /dev/null +++ b/Resources/Textures/IRenderTarget.h @@ -0,0 +1,31 @@ +#pragma once +/** +@file IRenderTarget.h +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + + +#include "swGraphicAPI/Resources/ResourceObject.h" + + +namespace sw +{ + + +// ================================ // +// +class IRenderTarget : public Resource +{ + RTTR_ENABLE( Resource ); +private: +protected: + + explicit IRenderTarget ( const AssetPath& name ) : Resource( name ) {} + virtual ~IRenderTarget () = default; + +public: +}; + +} // sw + diff --git a/Resources/Textures/RenderTarget.cpp b/Resources/Textures/RenderTarget.cpp new file mode 100644 index 0000000..e651f9b --- /dev/null +++ b/Resources/Textures/RenderTarget.cpp @@ -0,0 +1,56 @@ +/** +@file RenderTarget.cpp +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ +#include "swGraphicAPI/ResourceManager/stdafx.h" + +#include "RenderTarget.h" + + +using namespace sw; + + + +RTTR_REGISTRATION +{ + + + rttr::registration::class_< sw::RenderTarget >( "sw::RenderTarget" ) + .property( "ColorBuffer", &sw::RenderTarget::m_colorBuffer ) + .property( "DepthBuffer", &sw::RenderTarget::m_depthBuffer ) + .property( "StencilBuffer", &sw::RenderTarget::m_stencilBuffer ); + +} + + +namespace sw +{ + + + +// ================================ // +// +RenderTarget::RenderTarget ( const AssetPath& name, Texture* colorBuffer, Texture* depthBuffer, Texture* stencilBuffer ) + : IRenderTarget( name ) + , m_colorBuffer( colorBuffer ) + , m_depthBuffer( depthBuffer ) + , m_stencilBuffer( stencilBuffer ) +{} + + +// ================================ // +// +RenderTarget::~RenderTarget() +{} + + + + + +} // sw + + + + + diff --git a/Resources/Textures/RenderTarget.h b/Resources/Textures/RenderTarget.h new file mode 100644 index 0000000..516cbb9 --- /dev/null +++ b/Resources/Textures/RenderTarget.h @@ -0,0 +1,128 @@ +#pragma once +/** +@file RenderTarget.h +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + +#include "swGraphicAPI/ResourceManager/AssetCreators/IAssetCreateInfo.h" + +#include "swGraphicAPI/Rendering/GraphicAPIConstants.h" +#include "swGraphicAPI/Resources/ResourcePtr.h" +#include "swGraphicAPI/Resources/Textures/Texture.h" + +#include "IRenderTarget.h" + +#include + + +namespace sw +{ + + +/**@defgroup RenderTargets RenderTargets +@ingroup Resources*/ + + +class RenderTarget; + + +static const std::string RENDER_TARGET_COLOR_BUFFER_NAME = "color"; +static const std::string RENDER_TARGET_DEPTH_BUFFER_NAME = "depth"; +static const std::string RENDER_TARGET_STENCIL_BUFFER_NAME = "stencil"; + +static const std::string SCREEN_RENDER_TARGET = "ScreenRT"; + + + +/**@brief Structure for creating RenderTarget. +@ingroup RenderTargets*/ +struct RenderTargetDescriptor : public IAssetCreateInfo +{ + RTTR_ENABLE( IAssetCreateInfo ) +public: + uint32 Width; ///< Texture width in pixels. + uint32 Height; ///< Texture height in pixels. + uint16 ArraySize; ///< Size of array. + bool CPURead : 1; ///< Allows to read texture by CPU. + bool CPUWrite : 1; ///< Allows to write texture by CPU. + bool AllowShareResource : 1; ///< Can share resource between multiple graphic APIs. + bool IsCubeMap : 1; ///< True if texture is cube map. + uint8 NumSamples; ///< Number of samples if RenderTarget format is set to multisampled format. + uint16 SamplesQuality; ///< Quality of multisampling. + TextureType TextureType; ///< Texture type (number of dimensions, multsampling). Only 2-dimensional textures are spoprted now (can be array). + ResourceFormat ColorBuffFormat; ///< Format of color buffer + DepthStencilFormat DepthStencilFormat; ///< Format depth and stencil buffer. + ResourceUsage Usage; ///< Texture usage type. Influences how texture will be placed in GPU memory. + + /**@brief Sets default values for descriptor.*/ + explicit RenderTargetDescriptor () + : Width( 0 ) + , Height( 0 ) + , ArraySize( 1 ) + , CPURead( false ) + , CPUWrite( false ) + , AllowShareResource( false ) + , IsCubeMap( false ) + , Usage( ResourceUsage::Default ) + , TextureType( TextureType::Texture2D ) + , ColorBuffFormat( ResourceFormat::RESOURCE_FORMAT_UNKNOWN ) + , DepthStencilFormat( DepthStencilFormat::DEPTH_STENCIL_FORMAT_D16_UNORM ) + + {} + + /**@brief Created TextureInfo Tworzy strukture TextureInfo wype�nion� danymi zgodnymi z deskryptorem RenderTargetu. + + @attention Function doesn't set texture format. We can't deduce format from RenderTargetDescriptor.*/ + TextureInfo CreateTextureInfo () const + { + TextureInfo texInfo; + texInfo.Width = Width; + texInfo.Height = Height; + texInfo.ArraySize = ArraySize; + texInfo.CPURead = CPURead; + texInfo.CPUWrite = CPUWrite; + texInfo.AllowShareResource = AllowShareResource; + texInfo.IsCubeMap = IsCubeMap; + texInfo.TextureType = TextureType; + texInfo.Usage = Usage; + + return texInfo; + } + + +public: + virtual TypeID GetAssetType () const override { return TypeID::get< RenderTarget >(); } +}; + +/**@brief Class representing render target. +@ingroup RenderTargets +@ingroup Resources +@ingroup GraphicAPI*/ +class RenderTarget : public IRenderTarget +{ + RTTR_ENABLE( IRenderTarget ); + RTTR_REGISTRATION_FRIEND; +private: +protected: + + ResourcePtr< Texture > m_colorBuffer; ///< Can be nullptr. + ResourcePtr< Texture > m_depthBuffer; ///< Can be nullptr. + ResourcePtr< Texture > m_stencilBuffer; ///< Can be nullptr. + +public: + + explicit RenderTarget ( const AssetPath& name, sw::Texture* colorBuffer, sw::Texture* depthBuffer, sw::Texture* stencilBuffer ); + virtual ~RenderTarget (); + + inline sw::Texture* GetColorBuffer () { return m_colorBuffer.Ptr(); } + inline sw::Texture* GetDepthBuffer () { return m_depthBuffer.Ptr(); } + inline sw::Texture* GetStencilBuffer() { return m_stencilBuffer.Ptr(); } +}; + +DEFINE_RESOURCE_PTR_TYPE( RenderTarget ); + + +} // sw + + diff --git a/Resources/Textures/Texture.cpp b/Resources/Textures/Texture.cpp new file mode 100644 index 0000000..2ee4a5a --- /dev/null +++ b/Resources/Textures/Texture.cpp @@ -0,0 +1,105 @@ +/** +@file Texture.cpp +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ +#include "swGraphicAPI/ResourceManager/stdafx.h" + +#include "Texture.h" + + + +RTTR_REGISTRATION +{ + + rttr::registration::enumeration< sw::TextureType >( "TextureType" ) + ( + rttr::value( "Buffer", sw::TextureType::Buffer ), + rttr::value( "Texture 1D", sw::TextureType::Texture1D ), + rttr::value( "Texture 1D Array", sw::TextureType::TextureArray1D ), + rttr::value( "Texture 2D", sw::TextureType::Texture2D ), + rttr::value( "Texture 2D Array", sw::TextureType::TextureArray2D ), + rttr::value( "Texture 2D Multisample", sw::TextureType::Texture2DMultisample ), + rttr::value( "Texture 2D Multisample Array", sw::TextureType::TextureArray2DMultisample ), + rttr::value( "Texture 3D", sw::TextureType::Texture3D ) + ); + + rttr::registration::enumeration< sw::MipMapFilter >( "sw::MipMapFilter" ) + ( + rttr::value( "Bell", sw::MipMapFilter::Bell ), + rttr::value( "Blackman", sw::MipMapFilter::Blackman ), + rttr::value( "Box", sw::MipMapFilter::Box ), + rttr::value( "bSpline", sw::MipMapFilter::bSpline ), + rttr::value( "Catmullrom", sw::MipMapFilter::Catmullrom ), + rttr::value( "Gaussian", sw::MipMapFilter::Gaussian ), + rttr::value( "Kaiser", sw::MipMapFilter::Kaiser ), + rttr::value( "Lanczos12", sw::MipMapFilter::Lanczos12 ), + rttr::value( "Lanczos3", sw::MipMapFilter::Lanczos3 ), + rttr::value( "Lanczos4", sw::MipMapFilter::Lanczos4 ), + rttr::value( "Lanczos6", sw::MipMapFilter::Lanczos6 ), + rttr::value( "Mitchell", sw::MipMapFilter::Mitchell ), + rttr::value( "QuadraticAproximation", sw::MipMapFilter::QuadraticAproximation ), + rttr::value( "QuadraticInterpolation", sw::MipMapFilter::QuadraticInterpolation ), + rttr::value( "QuadraticMix", sw::MipMapFilter::QuadraticMix ), + rttr::value( "Tent", sw::MipMapFilter::Tent ), + rttr::value( "No filtering", sw::MipMapFilter::Unknown ) + ); + + rttr::registration::class_< sw::TextureInfo >( "sw::TextureInfo" ) + .property_readonly( "Width", &sw::TextureInfo::GetWidth ) + .property_readonly( "Height", &sw::TextureInfo::GetHeight ) + .property_readonly( "ArraySize", &sw::TextureInfo::GetArraySize ) + .property_readonly( "CPUReadable", &sw::TextureInfo::IsCPUReadable ) + .property_readonly( "CPUWritable", &sw::TextureInfo::IsCPUWriteable ) + .property_readonly( "SharedResource", &sw::TextureInfo::IsSharedResource ) + .property_readonly( "CubeMap", &sw::TextureInfo::IsCubeMapTex ) + .property_readonly( "GeneratedMipMaps", &sw::TextureInfo::GenMipMaps ) + .property_readonly( "TextureType", &sw::TextureInfo::TextureType ) + .property_readonly( "Usage", &sw::TextureInfo::Usage ) + .property_readonly( "Format", &sw::TextureInfo::Format ) + .property_readonly( "MipMapFilter", &sw::TextureInfo::MipMapFilter ) + .property_readonly( "MipMapsLevels", &sw::TextureInfo::GetMipLevels ) + .property_readonly( "FilePath", &sw::TextureInfo::GetPath ); + + rttr::registration::class_< sw::Texture >( "sw::Texture" ) + .property_readonly( "Descriptor", &sw::Texture::GetDescriptor ) BIND_AS_PTR; +} + + +//----------------------------------------------------------------------------------------------// +// Texture // +//----------------------------------------------------------------------------------------------// + + + +namespace sw +{ + +/**@brief Por�wnuje ze soba dwa obiekty tekstur. + +Obiekty s� takie same, kiedy odwo�uj� si� do tego samego pliku. +*/ +bool Texture::operator==( Texture& object ) +{ + if( this->GetFilePath().String() == object.GetFilePath().String() ) + return true; + return false; +} + +/**@brief Por�wnuje ze soba dwa obiekty tekstur. + +Obiekty s� takie same, kiedy odwo�uj� si� do tego samego pliku. +*/ +bool Texture::operator==( const std::wstring& fileName ) +{ + typedef std::codecvt_utf8 convert_type; + std::wstring_convert converter; + auto convertedFileName = converter.to_bytes( fileName ); + + if( this->GetFilePath().String() == convertedFileName ) + return true; + return false; +} + + +} // sw \ No newline at end of file diff --git a/Resources/Textures/Texture.h b/Resources/Textures/Texture.h new file mode 100644 index 0000000..0a5bb5a --- /dev/null +++ b/Resources/Textures/Texture.h @@ -0,0 +1,216 @@ +#pragma once +/** +@file Texture.h +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + + + +#include "swCommonLib/System/Path.h" +#include "swCommonLib/Common/TypesDefinitions.h" +#include "swCommonLib/Common/MemoryChunk.h" + +#include "swGraphicAPI/Resources/ResourcePtr.h" +#include "swGraphicAPI/Resources/ResourceObject.h" +#include "swGraphicAPI/Rendering/GraphicAPIConstants.h" + + +//----------------------------------------------------------------------------------------------// +// Texture // +//----------------------------------------------------------------------------------------------// + + +namespace sw +{ + +/**@defgroup Textures Textures +@ingroup Resources*/ + + + + +/**@brief Textures filtering modes. + +Filtering types used to create mipmaps. +@ingroup Textures*/ +enum class MipMapFilter : short +{ + Box = 0, ///< + Tent, ///< + Bell, ///< + bSpline, ///< + Mitchell, ///< + Lanczos3, ///< + Blackman, ///< + Lanczos4, ///< + Lanczos6, ///< + Lanczos12, ///< + Kaiser, ///< + Gaussian, ///< + Catmullrom, ///< + QuadraticInterpolation, ///< + QuadraticAproximation, ///< + QuadraticMix, ///< + + Unknown ///< +}; + + +/**@brief Describes how to handle mipmaps. + +@todo Add computing of mipmap levels. + +@ingroup Textures*/ +struct MipMapsInfo +{ + bool GenerateMipMaps; + MipMapFilter Filter; ///< Filtering used to generate mipmaps. Valid only if GenerateMipMaps is set to true. + uint16 CutOffMipMaps; ///< Removes number of mipmaps levels. Useful when we don't need full resolution of mipmaps (for example using dynamic LoD). + ///< Set value to 1 if you want to replace original texture with first mipmap. + + + // ================================ // + // + MipMapsInfo() + : GenerateMipMaps( false ) + , CutOffMipMaps( 0 ) + , Filter( MipMapFilter::Unknown ) + {} + + // ================================ // + // + MipMapsInfo( MipMapFilter filter ) + : GenerateMipMaps( filter != MipMapFilter::Unknown ) + , CutOffMipMaps( 0 ) + , Filter( filter ) + {} +}; + + + +/**@brief How texture will be used by GPU and CPU. +@ingroup Textures*/ +struct TextureUsageInfo +{ + bool CPURead : 1; ///< Allows to read texture by CPU. + bool CPUWrite : 1; ///< Allows to write texture by CPU. + bool AllowShareResource : 1; ///< Can share resource between multiple graphic APIs. + ResourceUsage Usage; ///< Texture usage type. Influences how texture will be placed in GPU memory. + + // ================================ // + // + TextureUsageInfo() + : Usage( ResourceUsage::Default ) + , CPURead( false ) + , CPUWrite( false ) + , AllowShareResource( false ) + {} +}; + + + +/**@brief Texture descriptor. + +@ingroup Textures*/ +struct TextureInfo +{ + uint32 Width; ///< Texture width in pixels. + uint32 Height; ///< Texture height in pixels. + uint16 ArraySize; ///< Size of array. + bool CPURead : 1; ///< Allows to read texture by CPU. + bool CPUWrite : 1; ///< Allows to write texture by CPU. + bool AllowShareResource : 1; ///< Can share resource between multiple graphic APIs. + bool IsCubeMap : 1; ///< True if texture is cube map. + bool GenerateMipMaps : 1; ///< Will automatically generates mipmpas. + TextureType TextureType; ///< Texture type (number of dimensions, multsampling). Only 2-dimensional textures are spoprted now (can be array). + ResourceUsage Usage; ///< Texture usage type. Influences how texture will be placed in GPU memory. + ResourceFormat Format; ///< Texture format. + MipMapFilter MipMapFilter; ///< Filtering used to generate mipmaps. Valid only if GenerateMipMaps is set to true. + uint16 MipMapLevels; ///< Number of mipmaps levels. 1 means only original texture. + uint16 CutOffMipMaps; ///< Removes number of mipmaps levels. Useful when we don't need full resolution of mipmaps (for example using dynamic LoD). + ///< Set value to 1 if you want to replace original texture with first mipmap. + + uint32 MemorySize; ///< Texture size in memory. + filesystem::Path FilePath; ///< Texture path or name. @deprecated Remove, after we get rid of old creation functions. + +// ================================ // +// + explicit TextureInfo() + { + ArraySize = 1; + CPURead = false; + CPUWrite = false; + AllowShareResource = false; + IsCubeMap = false; + GenerateMipMaps = false; + Usage = ResourceUsage::Default; + MipMapFilter = MipMapFilter::Unknown; + MipMapLevels = 1; + CutOffMipMaps = 0; + TextureType = TextureType::Texture2D; + MemorySize = 0; + } + +private: + RTTR_REGISTRATION_FRIEND; + + int GetWidth () { return Width; } + int GetHeight () { return Height; } + int GetArraySize () { return ArraySize; } + bool IsCPUReadable () { return CPURead; } + bool IsCPUWriteable () { return CPUWrite; } + bool IsSharedResource() { return AllowShareResource; } + bool IsCubeMapTex () { return IsCubeMap; } + bool GenMipMaps () { return GenerateMipMaps; } + int GetMipLevels () { return MipMapLevels; } + + std::string GetPath () { return FilePath.String(); } +}; + + + + + +/** @brief Base class for textures. +@ingroup Textures +@ingroup Resources +@ingroup GraphicAPI + +This class is platform independent. Inherit it while implementing chosen graphic API.*/ +class Texture : public Resource +{ + RTTR_ENABLE( Resource ); +private: +protected: + + virtual ~Texture () = default; + +public: + + explicit Texture ( const AssetPath& name ) : Resource( name ) {} + +public: + + /**@brief Updates texture data on graphic card. + Note that size of dataPtr memory must large be enough to fill requested miplevel and array idx. + You can always check @ref GetDescriptor function to get desired info. + + @todo Do something with this when rendering will use event queues.*/ + virtual bool UpdateData ( uint8* dataPtr, uint16 mipLevel, uint16 arrayIdx ) = 0; + + /**@brief Copies texture data from graphic card to memory chunk. + @deprecated Use BufferRaw instead of MemoryChunk.*/ + virtual MemoryChunk CopyData () const = 0; + virtual const TextureInfo& GetDescriptor () const = 0; ///< Gets texture descriptor. + + virtual std::string GetResourceName () const override { return GetFilePath().String(); } + + inline bool operator==( Texture& object ); + inline bool operator==( const std::wstring& file_name ); +}; + +DEFINE_RESOURCE_PTR_TYPE( Texture ); + + +} // sw diff --git a/Resources/Textures/TextureInitData.h b/Resources/Textures/TextureInitData.h new file mode 100644 index 0000000..91a39c8 --- /dev/null +++ b/Resources/Textures/TextureInitData.h @@ -0,0 +1,80 @@ +#pragma once +/** +@file TextureInitData.h +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + + +#include "swGraphicAPI/ResourceManager/AssetCreators/IAssetCreateInfo.h" +#include "swCommonLib/Common/Buffers/BufferRaw.h" +#include "swGraphicAPI/Resources/Textures/Texture.h" + + +namespace sw +{ + + +class Texture; + + +/**@brief Texture descriptor. + +@ingroup Textures*/ +struct TextureInitData : public sw::IAssetCreateInfo +{ +private: + RTTR_ENABLE( sw::IAssetCreateInfo ); +public: + + BufferRaw Data; + + uint32 Width; ///< Texture width in pixels. + uint32 Height; ///< Texture height in pixels. + uint16 ArraySize; ///< Size of array. + bool IsCubeMap : 1; ///< True if texture is cube map. + TextureType TextureType; ///< Texture type (number of dimensions, multsampling). Only 2-dimensional textures are spoprted now (can be array). + ResourceFormat Format; ///< Texture format. + MipMapsInfo MipMaps; ///< Mipmaps generation information. + TextureUsageInfo TextureUsage; + +// ================================ // +// + explicit TextureInitData( BufferRaw&& buffer ) + : Data( std::move( buffer ) ) + { + ArraySize = 1; + TextureUsage.CPURead = false; + TextureUsage.CPUWrite = false; + TextureUsage.AllowShareResource = false; + IsCubeMap = false; + MipMaps.GenerateMipMaps = false; + TextureUsage.Usage = ResourceUsage::Default; + MipMaps.Filter = MipMapFilter::Unknown; + MipMaps.CutOffMipMaps = 0; + TextureType = TextureType::Texture2D; + Format = ResourceFormat::RESOURCE_FORMAT_R8G8B8A8_UNORM; + } + + // ================================ // + // + uint16 NumMipMapLevels () const + { + // If there's only original texture, we return only 1 mipmap what means that there's only + // original texture. + if( !MipMaps.GenerateMipMaps ) + return 1; + + auto size = std::max( Width, Height ); + auto levels = 1 + (uint32)std::floor( std::log2( size ) ); + return levels - MipMaps.CutOffMipMaps; + } + +public: + virtual TypeID GetAssetType () const override { return TypeID::get< Texture >(); } +}; + + + +} // sw + diff --git a/Tests/TestMaterial/TestCreation.cpp b/Tests/TestMaterial/TestCreation.cpp new file mode 100644 index 0000000..29af32b --- /dev/null +++ b/Tests/TestMaterial/TestCreation.cpp @@ -0,0 +1,71 @@ +#include "swCommonLib/External/Catch/catch.hpp" +/** +@file TestCreation.cpp +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + +#include "swGraphicAPI/ResourceManager/ResourceManager.h" +#include "swGraphicAPI/ResourceManager/ResourceManagerAPI.h" +#include "swGraphicAPI/Assets/MaterialAsset/MaterialAsset.h" +#include "swGraphicAPI/Assets/MaterialAsset/MaterialAssetInitData.h" +#include "swGraphicAPI/Assets/MaterialAsset/MaterialCreator.h" + +#include "swGraphicAPI/Assets/MaterialAsset/PhongMaterialData.h" + +#include "swGraphicAPI/MockAssets/Utils.h" + + + +using namespace sw; + + +// ================================ // +// +TEST_CASE( "GraphicAPI.Assets.Material.Creation.PS_VS_only", "[GraphicAPI][SoilTextureLoader]" ) +{ + auto rm = CreateResourceManagerWithMocksAndDefaults(); + rm->RegisterAssetCreator( MaterialCreator::CreateCreator() ); + auto api = ResourceManagerAPI( rm.get() ); + + MaterialInitData initInfo; + initInfo.PixelShader = api.LoadPixelShader( "$(TestAssets)/shaders/hlsl/MinimalShader.psh" ).Get(); + initInfo.VertexShader = api.LoadVertexShader( "$(TestAssets)/shaders/hlsl/MinimalShader.vsh" ).Get(); + initInfo.ShadingData = std::make_shared< ShadingModelData< PhongMaterial > >(); + REQUIRE_IS_VALID( initInfo.AutoCreateBuffer( "::Generated/test-material-1", RMLoaderAPI( rm.get() ) ) ); + + auto resource = api.CreateAsset< MaterialAsset >( "::Generated/test-material-1", std::move( initInfo ) ); + REQUIRE_IS_VALID( resource ); + + auto material = resource.Get(); + + CHECK( material->GetMaterialBuffer() != nullptr ); + CHECK( material->GetPixelShader() != nullptr ); + CHECK( material->GetVertexShader() != nullptr ); + CHECK( material->GetGeometryShader() == nullptr ); + CHECK( material->GetTessControlShader() == nullptr ); + CHECK( material->GetTessEvaluationShader() == nullptr ); + + CHECK( material->GetTexture( 0 ) == nullptr ); + CHECK( material->GetTexture( 1 ) == nullptr ); + CHECK( material->GetTexture( 2 ) == nullptr ); + CHECK( material->GetTexture( 3 ) == nullptr ); + CHECK( material->GetTexture( 4 ) == nullptr ); + + CHECK( material->GetAssetPath() == "::Generated/test-material-1" ); + CHECK( material->GetDescriptor().ShadingData->GetShadingModelType() == TypeID::get< PhongMaterial >() ); +} + +// ================================ // +// AutoCreateBuffer should return invalid ReturnResult if ShadingModel was nullptr. +TEST_CASE( "GraphicAPI.Assets.Material.Creation.AutoCreateBuffer.NullptrShadingModel", "[GraphicAPI][SoilTextureLoader]" ) +{ + auto rm = CreateResourceManagerWithMocksAndDefaults(); + rm->RegisterAssetCreator( MaterialCreator::CreateCreator() ); + + MaterialInitData initInfo; + auto result = initInfo.AutoCreateBuffer( "::Generated/test-material-1", RMLoaderAPI( rm.get() ) ); + REQUIRE_FALSE( result.IsValid() ); +} + + diff --git a/Tests/TestMaterial/TestSWMaterialLoader.cpp b/Tests/TestMaterial/TestSWMaterialLoader.cpp new file mode 100644 index 0000000..ffcd6c0 --- /dev/null +++ b/Tests/TestMaterial/TestSWMaterialLoader.cpp @@ -0,0 +1,190 @@ +#include "swCommonLib/External/Catch/catch.hpp" +/** +@file TestSWMaterialLoader.cpp +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + +#include "swGraphicAPI/ResourceManager/ResourceManager.h" +#include "swGraphicAPI/ResourceManager/ResourceManagerAPI.h" +#include "swGraphicAPI/Assets/MaterialAsset/MaterialAsset.h" +#include "swGraphicAPI/Assets/MaterialAsset/MaterialAssetInitData.h" +#include "swGraphicAPI/Assets/MaterialAsset/MaterialCreator.h" + +#include "swGraphicAPI/Assets/MaterialAsset/PhongMaterialData.h" + +#include "swGraphicAPI/Loaders/swMaterialLoader/swMaterialLoader.h" + +#include "swGraphicAPI/MockAssets/Utils.h" +#include "swGraphicAPI/Tests/TestMaterial/Utils.h" +#include "swCommonLib/Common/Macros/GenerateOperators.h" + + + +using namespace sw; + + +//====================================================================================// +// Negative tests +//====================================================================================// + +// ================================ // +// +TEST_CASE( "GraphicAPI.Loaders.swMaterialLoader.Loader.Format.NoHeader", "[GraphicAPI][swMaterialLoader]" ) +{ + auto rm = CreateResourceManagerWithMaterials(); + auto api = ResourceManagerAPI( rm.get() ); + + auto material = api.Load< MaterialAsset >( "$(MaterialAssets)/no-header.swmat", nullptr ); + REQUIRE( !material.IsValid() ); +} + +// ================================ // +// +TEST_CASE( "GraphicAPI.Loaders.swMaterialLoader.Loader.Format.NoMaterialAsset", "[GraphicAPI][swMaterialLoader]" ) +{ + auto rm = CreateResourceManagerWithMaterials(); + auto api = ResourceManagerAPI( rm.get() ); + + auto material = api.Load< MaterialAsset >( "$(MaterialAssets)/no-MaterialAsset.swmat", nullptr ); + REQUIRE( !material.IsValid() ); +} + +// ================================ // +// +TEST_CASE( "GraphicAPI.Loaders.swMaterialLoader.Loader.Format.InvalidXML", "[GraphicAPI][swMaterialLoader]" ) +{ + auto rm = CreateResourceManagerWithMaterials(); + auto api = ResourceManagerAPI( rm.get() ); + + auto material = api.Load< MaterialAsset >( "$(MaterialAssets)/invalid-xml.swmat", nullptr ); + REQUIRE( !material.IsValid() ); +} + +// ================================ // +// +TEST_CASE( "GraphicAPI.Loaders.swMaterialLoader.Loader.Format.InvalidVersion", "[GraphicAPI][swMaterialLoader]" ) +{ + auto rm = CreateResourceManagerWithMaterials(); + auto api = ResourceManagerAPI( rm.get() ); + + auto material = api.Load< MaterialAsset >( "$(MaterialAssets)/invalid-version.swmat", nullptr ); + REQUIRE( !material.IsValid() ); +} + + +//====================================================================================// +// Shaders tests +//====================================================================================// + +// ================================ // +// +TEST_CASE( "GraphicAPI.Loaders.swMaterialLoader.Loader.Shaders.NoPixelShader", "[GraphicAPI][swMaterialLoader]" ) +{ + auto rm = CreateResourceManagerWithMaterials(); + auto api = ResourceManagerAPI( rm.get() ); + + auto material = api.Load< MaterialAsset >( "$(MaterialAssets)/no-ps.swmat", nullptr ); + REQUIRE( !material.IsValid() ); +} + +// ================================ // +// +TEST_CASE( "GraphicAPI.Loaders.swMaterialLoader.Loader.Shaders.NoVertexShader", "[GraphicAPI][swMaterialLoader]" ) +{ + auto rm = CreateResourceManagerWithMaterials(); + auto api = ResourceManagerAPI( rm.get() ); + + auto material = api.Load< MaterialAsset >( "$(MaterialAssets)/no-vs.swmat", nullptr ); + REQUIRE( !material.IsValid() ); +} + +// ================================ // +// +TEST_CASE( "GraphicAPI.Loaders.swMaterialLoader.Loader.Shaders.NotExistingPS", "[GraphicAPI][swMaterialLoader]" ) +{ + auto rm = CreateResourceManagerWithMaterials(); + auto api = ResourceManagerAPI( rm.get() ); + + auto material = api.Load< MaterialAsset >( "$(MaterialAssets)/not-existing-ps.swmat", nullptr ); + REQUIRE( !material.IsValid() ); +} + +// ================================ // +// +TEST_CASE( "GraphicAPI.Loaders.swMaterialLoader.Loader.Shaders.NotExistingVS", "[GraphicAPI][swMaterialLoader]" ) +{ + auto rm = CreateResourceManagerWithMaterials(); + auto api = ResourceManagerAPI( rm.get() ); + + auto material = api.Load< MaterialAsset >( "$(MaterialAssets)/not-existing-vs.swmat", nullptr ); + REQUIRE( !material.IsValid() ); +} + +// ================================ // +// No key in xml. Loader should produce valid Material. +TEST_CASE( "GraphicAPI.Loaders.swMaterialLoader.Loader.Shaders.NoGeometryShaderEntry", "[GraphicAPI][swMaterialLoader]" ) +{ + auto rm = CreateResourceManagerWithMaterials(); + auto api = ResourceManagerAPI( rm.get() ); + + auto material = api.Load< MaterialAsset >( "$(MaterialAssets)/no-gs-entry.swmat", nullptr ); + REQUIRE_IS_VALID( material ); +} + + +//====================================================================================// +// Textures +//====================================================================================// + +// ================================ // +// Material file contains one valid texture, but doesn't contains empty entries. +// Loader should produce valid material with one texture under index 0. +TEST_CASE( "GraphicAPI.Loaders.swMaterialLoader.Loader.Textures.SingleTextureEntry", "[GraphicAPI][swMaterialLoader]" ) +{ + auto rm = CreateResourceManagerWithMaterials(); + auto api = ResourceManagerAPI( rm.get() ); + + auto material = api.Load< MaterialAsset >( "$(MaterialAssets)/single-texture-entry.swmat", nullptr ); + REQUIRE_IS_VALID( material ); + + CHECK( material.Get()->GetTexture( 0 ) != nullptr ); + CHECK( material.Get()->GetTexture( 0 )->GetFilePath() == "$(TestAssets)/texture/random-pixels.jpg" ); + CHECK( material.Get()->GetTexture( 0 )->GetAssetPath().GetInternalPath() == "" ); + + // Validate textures expected to be nullptrs. + for( int i = 1; i < MAX_MATERIAL_TEXTURES; i++ ) + CHECK( material.Get()->GetTexture( i ) == nullptr ); +} + +// ================================ // +// Material file contains no entry. +// Loader should produce valid material without textures. +TEST_CASE( "GraphicAPI.Loaders.swMaterialLoader.Loader.Textures.NoTexturesEntry", "[GraphicAPI][swMaterialLoader]" ) +{ + auto rm = CreateResourceManagerWithMaterials(); + auto api = ResourceManagerAPI( rm.get() ); + + auto material = api.Load< MaterialAsset >( "$(MaterialAssets)/no-textures-entry.swmat", nullptr ); + REQUIRE_IS_VALID( material ); + + // Validate textures expected to be nullptrs. + for( int i = 0; i < MAX_MATERIAL_TEXTURES; i++ ) + CHECK( material.Get()->GetTexture( i ) == nullptr ); +} + +// ================================ // +// File references not existing texture. Loader should produce valid +// material without requested texture. Warning is reported. +TEST_CASE( "GraphicAPI.Loaders.swMaterialLoader.Loader.Textures.NotExistingTexture", "[GraphicAPI][swMaterialLoader]" ) +{ + auto rm = CreateResourceManagerWithMaterials(); + auto api = ResourceManagerAPI( rm.get() ); + + auto material = api.Load< MaterialAsset >( "$(MaterialAssets)/not-existing-texture.swmat", nullptr ); + REQUIRE_IS_VALID( material ); + + // Validate textures expected to be nullptrs. + for( int i = 0; i < MAX_MATERIAL_TEXTURES; i++ ) + CHECK( material.Get()->GetTexture( i ) == nullptr ); +} diff --git a/Tests/TestMaterial/TestSWMaterialSaver.cpp b/Tests/TestMaterial/TestSWMaterialSaver.cpp new file mode 100644 index 0000000..fb1cc4a --- /dev/null +++ b/Tests/TestMaterial/TestSWMaterialSaver.cpp @@ -0,0 +1,170 @@ +#include "swCommonLib/External/Catch/catch.hpp" +/** +@file TestSWMaterialSaver.cpp +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + +#include "swGraphicAPI/ResourceManager/ResourceManager.h" +#include "swGraphicAPI/ResourceManager/ResourceManagerAPI.h" +#include "swGraphicAPI/Assets/MaterialAsset/MaterialAsset.h" +#include "swGraphicAPI/Assets/MaterialAsset/MaterialAssetInitData.h" +#include "swGraphicAPI/Assets/MaterialAsset/MaterialCreator.h" + +#include "swGraphicAPI/Assets/MaterialAsset/PhongMaterialData.h" + +#include "swGraphicAPI/Loaders/swMaterialLoader/swMaterialLoader.h" + +#include "swGraphicAPI/MockAssets/Utils.h" +#include "swGraphicAPI/Tests/TestMaterial/Utils.h" +#include "swCommonLib/Common/Macros/GenerateOperators.h" + + + +using namespace sw; + +//====================================================================================// +// Material test utils +//====================================================================================// + +GENERATE_RELATIONAL_OPERATORS( DirectX::XMFLOAT3, x, y, z ); +GENERATE_RELATIONAL_OPERATORS( DirectX::XMFLOAT4, x, y, z, w ); + + +// ================================ // +// +filesystem::Path Translate ( ResourceManager* rm, filesystem::Path path ) +{ + return rm->GetPathsManager()->Translate( path ); +} + +//====================================================================================// +// Test cases +//====================================================================================// + + +// ================================ // +// +TEST_CASE( "GraphicAPI.Loaders.swMaterialLoader.Saver.PS_VS_only", "[GraphicAPI][swMaterialLoader]" ) +{ + auto rm = CreateResourceManagerWithMaterials(); + auto api = ResourceManagerAPI( rm.get() ); + + MaterialInitData initInfo; + initInfo.PixelShader = api.LoadPixelShader( "$(TestAssets)/shaders/hlsl/MinimalShader.psh" ).Get(); + initInfo.VertexShader = api.LoadVertexShader( "$(TestAssets)/shaders/hlsl/MinimalShader.vsh" ).Get(); + initInfo.ShadingData = std::make_shared< ShadingModelData< PhongMaterial > >(); + REQUIRE_IS_VALID( initInfo.AutoCreateBuffer( "::Generated/test-material-1", RMLoaderAPI( rm.get() ) ) ); + + auto resource = api.CreateAsset< MaterialAsset >( "::Generated/test-material-1", std::move( initInfo ) ); + REQUIRE_IS_VALID( resource ); + + SWMaterialLoader().SaveMaterial( Translate( rm.get(), "$(TestWorkingDir)/swMaterialLoader/Material-PS_VS_only.swmat" ), resource.Get().Ptr() ); + + auto material = api.Load< MaterialAsset >( "$(TestWorkingDir)/swMaterialLoader/Material-PS_VS_only.swmat", nullptr ); + REQUIRE_IS_VALID( material ); + + REQUIRE( material.Get()->GetMaterialBuffer() != nullptr ); + + // Validate shaders. + REQUIRE( material.Get()->GetPixelShader() != nullptr ); + REQUIRE( material.Get()->GetVertexShader() != nullptr ); + + CHECK( material.Get()->GetPixelShader()->GetFilePath() == "$(TestAssets)/shaders/hlsl/MinimalShader.psh" ); + CHECK( material.Get()->GetVertexShader()->GetFilePath() == "$(TestAssets)/shaders/hlsl/MinimalShader.vsh" ); + + CHECK( material.Get()->GetGeometryShader() == nullptr ); + CHECK( material.Get()->GetTessControlShader() == nullptr ); + CHECK( material.Get()->GetTessEvaluationShader() == nullptr ); + + // Validate textures + for( int i = 0; i < MAX_MATERIAL_TEXTURES; i++ ) + CHECK( material.Get()->GetTexture( i ) == nullptr ); + + CHECK( material.Get()->GetDescriptor().ParametricBuffers.size() == 0 ); + CHECK( material.Get()->GetDescriptor().ShadingData.get() != nullptr ); + + REQUIRE_IS_VALID( Compare( material, resource ) ); +} + +// ================================ // +// +TEST_CASE( "GraphicAPI.Loaders.swMaterialLoader.Saver.2Textures", "[GraphicAPI][swMaterialLoader]" ) +{ + auto rm = CreateResourceManagerWithMaterials(); + auto api = ResourceManagerAPI( rm.get() ); + + MaterialInitData initInfo; + initInfo.PixelShader = api.LoadPixelShader( "$(TestAssets)/shaders/hlsl/MinimalShader.psh" ).Get(); + initInfo.VertexShader = api.LoadVertexShader( "$(TestAssets)/shaders/hlsl/MinimalShader.vsh" ).Get(); + initInfo.ShadingData = std::make_shared< ShadingModelData< PhongMaterial > >(); + initInfo.Textures[ 0 ] = api.LoadTexture( "$(TestAssets)/texture/random-pixels.jpg" ).Get(); + initInfo.Textures[ 2 ] = api.LoadTexture( "$(TestAssets)/texture/big-lightweight.png" ).Get(); + REQUIRE_IS_VALID( initInfo.AutoCreateBuffer( "::Generated/test-material-2", RMLoaderAPI( rm.get() ) ) ); + + auto resource = api.CreateAsset< MaterialAsset >( "::Generated/test-material-2", std::move( initInfo ) ); + REQUIRE_IS_VALID( resource ); + + SWMaterialLoader().SaveMaterial( Translate( rm.get(), "$(TestWorkingDir)/swMaterialLoader/Material-2Textures.swmat" ), resource.Get().Ptr() ); + + auto material = api.Load< MaterialAsset >( "$(TestWorkingDir)/swMaterialLoader/Material-2Textures.swmat", nullptr ); + REQUIRE_IS_VALID( material ); + + CHECK( material.Get()->GetTexture( 0 ) != nullptr ); + CHECK( material.Get()->GetTexture( 2 ) != nullptr ); + + CHECK( material.Get()->GetTexture( 1 ) == nullptr ); + CHECK( material.Get()->GetTexture( 3 ) == nullptr ); + CHECK( material.Get()->GetTexture( 4 ) == nullptr ); + + CHECK( material.Get()->GetTexture( 0 )->GetFilePath() == "$(TestAssets)/texture/random-pixels.jpg" ); + CHECK( material.Get()->GetTexture( 2 )->GetFilePath() == "$(TestAssets)/texture/big-lightweight.png" ); + + REQUIRE_IS_VALID( Compare( material, resource ) ); +} + +// ================================ // +// +TEST_CASE( "GraphicAPI.Loaders.swMaterialLoader.Saver.ShadingModel", "[GraphicAPI][swMaterialLoader]" ) +{ + auto rm = CreateResourceManagerWithMaterials(); + auto api = ResourceManagerAPI( rm.get() ); + + MaterialInitData initInfo; + initInfo.PixelShader = api.LoadPixelShader( "$(TestAssets)/shaders/hlsl/MinimalShader.psh" ).Get(); + initInfo.VertexShader = api.LoadVertexShader( "$(TestAssets)/shaders/hlsl/MinimalShader.vsh" ).Get(); + + auto shadingModel = std::make_shared< ShadingModelData< PhongMaterial > >(); + initInfo.ShadingData = shadingModel; + + shadingModel->Data.Diffuse = DirectX::XMFLOAT4( 0.2f, 0.3f, 0.4f, 0.5f ); + shadingModel->Data.Ambient = DirectX::XMFLOAT4( 0.1f, 0.14f, 0.17f, 0.19f ); + shadingModel->Data.Emissive = DirectX::XMFLOAT3( 0.32f, 0.35f, 0.47f ); + shadingModel->Data.Specular = DirectX::XMFLOAT4( 0.6f, 0.7f, 0.75f, 0.9f ); + shadingModel->Data.Power = 13.0f; + + REQUIRE_IS_VALID( initInfo.AutoCreateBuffer( "::Generated/test-material-3", RMLoaderAPI( rm.get() ) ) ); + + auto resource = api.CreateAsset< MaterialAsset >( "::Generated/test-material-3", std::move( initInfo ) ); + REQUIRE_IS_VALID( resource ); + + SWMaterialLoader().SaveMaterial( Translate( rm.get(), "$(TestWorkingDir)/swMaterialLoader/Material-ShadingData.swmat" ), resource.Get().Ptr() ); + + auto material = api.Load< MaterialAsset >( "$(TestWorkingDir)/swMaterialLoader/Material-ShadingData.swmat", nullptr ); + REQUIRE_IS_VALID( material ); + + auto& desc = material.Get()->GetDescriptor(); + REQUIRE( desc.ShadingData->GetShadingModelType() == TypeID::get< PhongMaterial >() ); + + auto shadingData = std::static_pointer_cast< ShadingModelData< PhongMaterial > >( desc.ShadingData ); + + CHECK( shadingData->Data.Diffuse == DirectX::XMFLOAT4( 0.2f, 0.3f, 0.4f, 0.5f ) ); + CHECK( shadingData->Data.Ambient == DirectX::XMFLOAT4( 0.1f, 0.14f, 0.17f, 0.19f ) ); + CHECK( shadingData->Data.Emissive == DirectX::XMFLOAT3( 0.32f, 0.35f, 0.47f ) ); + CHECK( shadingData->Data.Specular == DirectX::XMFLOAT4( 0.6f, 0.7f, 0.75f, 0.9f ) ); + CHECK( shadingData->Data.Power == 13.0f ); + + CHECK( material.Get()->GetMaterialBuffer()->GetElementSize() == shadingData->GetSize() ); + + REQUIRE_IS_VALID( Compare( material, resource ) ); +} diff --git a/Tests/TestMaterial/Utils.h b/Tests/TestMaterial/Utils.h new file mode 100644 index 0000000..efb63f2 --- /dev/null +++ b/Tests/TestMaterial/Utils.h @@ -0,0 +1,89 @@ +#pragma once +/** +@file Utils.h +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + +#include "swGraphicAPI/ResourceManager/ResourceManager.h" +#include "swGraphicAPI/ResourceManager/ResourceManagerAPI.h" +#include "swGraphicAPI/Assets/MaterialAsset/MaterialAsset.h" +#include "swGraphicAPI/Assets/MaterialAsset/MaterialAssetInitData.h" +#include "swGraphicAPI/Assets/MaterialAsset/MaterialCreator.h" + +#include "swGraphicAPI/Assets/MaterialAsset/PhongMaterialData.h" + +#include "swGraphicAPI/Loaders/swMaterialLoader/swMaterialLoader.h" + + + +namespace sw +{ + +// ================================ // +// +inline ReturnResult Compare ( MaterialAssetPtr mat, MaterialAssetPtr reference ) +{ + if( mat->GetMaterialBuffer()->GetElementSize() != reference->GetMaterialBuffer()->GetElementSize() ) + return "MaterialBuffer sizes differ"; + + if( mat->GetMaterialBuffer()->GetElementCount() != reference->GetMaterialBuffer()->GetElementCount() ) + return "MaterialBuffer elements count differs"; + + // Compare shaders. + if( mat->GetVertexShader() != reference->GetVertexShader() ) + return "VertexShader differs"; + + if( mat->GetPixelShader() != reference->GetPixelShader() ) + return "PixelShader differs"; + + if( mat->GetGeometryShader() != reference->GetGeometryShader() ) + return "GeometryShader differs"; + + if( mat->GetTessControlShader() != reference->GetTessControlShader() ) + return "ControlShader differs"; + + if( mat->GetTessEvaluationShader() != reference->GetTessEvaluationShader() ) + return "EvaluationShader differs"; + + // Compare textures. + for( int i = 0; i < MAX_MATERIAL_TEXTURES; i++ ) + { + if( mat->GetTexture( i ) != reference->GetTexture( i ) ) + return "Texture on index " + Convert::ToString( i ) + " differes."; + } + + if( TypeID::get( mat->GetDescriptor().ShadingData.get() ) != TypeID::get( reference->GetDescriptor().ShadingData.get() ) ) + return "Type of ShadingData differs"; + + if( mat->GetDescriptor().ParametricBuffers.size() != reference->GetDescriptor().ParametricBuffers.size() ) + return "Sizes of ParametricBuffers differ"; + + for( Size i = 0; i < mat->GetDescriptor().ParametricBuffers.size(); i++ ) + { + if( mat->GetDescriptor().ParametricBuffers[ i ] != reference->GetDescriptor().ParametricBuffers[ i ] ) + return "Parametric buffers differ on index " + Convert::ToString( i ); + } + + return Result::Success; +} + +// ================================ // +// +inline std::unique_ptr< ResourceManager > CreateResourceManagerWithMaterials () +{ + auto rm = CreateResourceManagerWithMocksAndDefaults(); + + rm->RegisterAssetCreator( MaterialCreator::CreateCreator() ); + rm->RegisterLoader( std::make_shared< SWMaterialLoader >() ); + rm->RegisterLoader( std::make_shared< SoilTextureLoader >() ); + + auto pm = rm->GetPathsManager(); + pm->RegisterAlias( "$(MaterialAssets)", "$(TestAssets)/material/" ); + + return std::move( rm ); +} + + +} // sw + diff --git a/Tests/TestMaterial/main.cpp b/Tests/TestMaterial/main.cpp new file mode 100644 index 0000000..d3f9d80 --- /dev/null +++ b/Tests/TestMaterial/main.cpp @@ -0,0 +1,3 @@ +#define CATCH_CONFIG_MAIN // This tells Catch to provide a main() - only do this in one cpp file +#include "swCommonLib/External/Catch/catch.hpp" + diff --git a/Tests/TestMipMapGenerator/TestMipMaps.cpp b/Tests/TestMipMapGenerator/TestMipMaps.cpp new file mode 100644 index 0000000..7ba04bb --- /dev/null +++ b/Tests/TestMipMapGenerator/TestMipMaps.cpp @@ -0,0 +1,64 @@ +#include "swCommonLib/External/Catch/catch.hpp" + +/** +@file TestMipMaps.cpp +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + +#include "swGraphicAPI/ResourceManager/AssetCreators/Textures/MipMapGenerator.h" +#include "swGraphicAPI/ImageGenerators/CheckerboardGenerator.h" + +using namespace sw; + + +// ================================ // +// +TEST_CASE( "GraphicAPI.TextureCreator.MipMapGenerator.Generate.ImagePowerOf2", "[GraphicAPI]" ) +{ + CheckerboardGenerator checker( 8, 8 ); + auto buffer = checker.Generate(); + auto startSize = buffer.GetSize(); + + TextureInfo texInfo; + texInfo.GenerateMipMaps = true; + texInfo.MipMapFilter = MipMapFilter::Box; + texInfo.Format = ResourceFormat::RESOURCE_FORMAT_R8G8B8A8_UNORM; + texInfo.Width = 8; + texInfo.Height = 8; + + MipMapGenerator mipmap; + auto newBuffer = mipmap.Generate( buffer, texInfo ).Get(); + + CHECK( texInfo.Width == 8 ); + CHECK( texInfo.Height == 8 ); + CHECK( texInfo.MipMapLevels == 4 ); + + CHECK( newBuffer.GetSize() == 4 * (8*8 + 4*4 + 2*2 + 1 ) ); +} + + +// ================================ // +// +TEST_CASE( "GraphicAPI.TextureCreator.MipMapGenerator.Generate.ImageNotPowerOf2", "[GraphicAPI]" ) +{ + CheckerboardGenerator checker( 10, 10 ); + auto buffer = checker.Generate(); + auto startSize = buffer.GetSize(); + + TextureInfo texInfo; + texInfo.GenerateMipMaps = true; + texInfo.MipMapFilter = MipMapFilter::Box; + texInfo.Format = ResourceFormat::RESOURCE_FORMAT_R8G8B8A8_UNORM; + texInfo.Width = 10; + texInfo.Height = 10; + + MipMapGenerator mipmap; + auto newBuffer = mipmap.Generate( buffer, texInfo ).Get(); + + CHECK( texInfo.Width == 16 ); + CHECK( texInfo.Height == 16 ); + CHECK( texInfo.MipMapLevels == 5 ); + + CHECK( newBuffer.GetSize() == 4 * ( 16*16 + 8*8 + 4*4 + 2*2 + 1 ) ); +} diff --git a/Tests/TestMipMapGenerator/main.cpp b/Tests/TestMipMapGenerator/main.cpp new file mode 100644 index 0000000..d3f9d80 --- /dev/null +++ b/Tests/TestMipMapGenerator/main.cpp @@ -0,0 +1,3 @@ +#define CATCH_CONFIG_MAIN // This tells Catch to provide a main() - only do this in one cpp file +#include "swCommonLib/External/Catch/catch.hpp" + diff --git a/Tests/TestResourceManager/LoadBarrierTest.cpp b/Tests/TestResourceManager/LoadBarrierTest.cpp new file mode 100644 index 0000000..35c2fc6 --- /dev/null +++ b/Tests/TestResourceManager/LoadBarrierTest.cpp @@ -0,0 +1,249 @@ +#include "swGraphicAPI/Tests/TestResourceManager/stdafx.h" +#include "swCommonLib/External/Catch/catch.hpp" +/** +@file LoadBarrierTest.cpp +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + + +#include "swCommonLib/Common/Multithreading/ThreadsBarrier.h" + +#include "swGraphicAPI/ResourceManager/AsyncLoad/LoadBarrier.h" + + + + +namespace sw +{ + +// ================================ // +// +class CLASS_TESTER( LoadBarrier ) +{ +private: +public: + + static std::vector< WaitingAsset* > & GetWaitingAssets ( LoadBarrier & barrier ) { return barrier.m_waitingAssets; } + +}; + + +} // sw + + +const int numThreads = 4; + +sw::ThreadsBarrier gPreAccessBarrier( numThreads ); +sw::ThreadsBarrier gPreWaitBarrier( numThreads - 1 ); +sw::LoadBarrier gLoadBarrier; +std::vector< int > gOrderChecker; +std::mutex gCheckerLock; + +filesystem::Path assetFile( "assets/wombat.jpg" ); +filesystem::Path independentAsset( "assets/texture.jpg" ); + +bool threadsInternalResult[ numThreads ]; +bool notNullWaitingAsset[ numThreads ]; + + + +// ================================ // +// +void PushThreadNum ( int threadNum ) +{ + gCheckerLock.lock(); + gOrderChecker.push_back( threadNum ); + gCheckerLock.unlock(); +} + + +// ================================ // +// +void FakeLoadAsset ( int threadNum ) +{ + PushThreadNum( threadNum ); + + gPreWaitBarrier.ArriveAndWait(); + + std::this_thread::sleep_for( std::chrono::milliseconds( 13 ) ); + + PushThreadNum( threadNum ); + + gLoadBarrier.LoadingCompleted( assetFile ); +} + +// ================================ // +// +void LoadingThread ( int threadNum ) +{ + auto result = gLoadBarrier.RequestAsset( assetFile ); + + // Allow other threads to call RequestAsset. + gPreAccessBarrier.ArriveAndWait(); + + threadsInternalResult[ threadNum ] = result.second; + notNullWaitingAsset[ threadNum ] = result.first != nullptr; + + FakeLoadAsset( threadNum ); +} + +// ================================ // +// +void RequestingThread ( int threadNum ) +{ + // LoadingThread must RequestAsset first. Wait for it. + gPreAccessBarrier.ArriveAndWait(); + + auto result = gLoadBarrier.RequestAsset( assetFile ); + + threadsInternalResult[ threadNum ] = result.second; + notNullWaitingAsset[ threadNum ] = result.first != nullptr; + + gPreWaitBarrier.ArriveAndWait(); + gLoadBarrier.WaitUntilLoaded( result.first ); + + PushThreadNum( threadNum ); +} + +// ================================ // +// +void IndependentAssetThread ( int threadNum ) +{ + // LoadingThread must RequestAsset first. Wait for it. + gPreAccessBarrier.ArriveAndWait(); + + auto result = gLoadBarrier.RequestAsset( independentAsset ); + + // Independent thread should pass without blocking. result.second should be false. + threadsInternalResult[ threadNum ] = result.second; + notNullWaitingAsset[ threadNum ] = result.first != nullptr; + + gLoadBarrier.LoadingCompleted( independentAsset ); +} + + +// ================================ // +// Only one thread should enter loading at the same time. Rest should wait. +TEST_CASE( "GraphicAPI.LoadBarrier.MultiThreadsLoading", "[GraphicAPI]" ) +{ + std::thread threads[ numThreads ]; + + threads[ 0 ] = std::thread( &LoadingThread, 0 ); + for( int i = 1; i < numThreads - 1; ++i ) + threads[ i ] = std::thread( &RequestingThread, i ); + + // Independent thread + threads[ numThreads - 1 ] = std::thread( &IndependentAssetThread, numThreads - 1 ); + + for( auto& thread : threads ) + thread.join(); + + + // Waiting asset should never be nullptr. + for( auto notNull : notNullWaitingAsset ) + CHECK( notNull == true ); + + CHECK( threadsInternalResult[ 0 ] == false ); + CHECK( threadsInternalResult[ 1 ] == true ); + CHECK( threadsInternalResult[ 2 ] == true ); + CHECK( threadsInternalResult[ 3 ] == false ); + + REQUIRE( gOrderChecker.size() == 4 ); + + CHECK( gOrderChecker[ 0 ] == 0 ); + CHECK( gOrderChecker[ 1 ] == 0 ); + CHECK( ( gOrderChecker[ 2 ] == 1 || gOrderChecker[ 2 ] == 2 ) ); + CHECK( ( gOrderChecker[ 3 ] == 1 || gOrderChecker[ 3 ] == 2 ) ); + + // Waiting assets list should be cleaned. + CHECK( sw::CLASS_TESTER( LoadBarrier )::GetWaitingAssets( gLoadBarrier ).size() == 0 ); +} + + +sw::LoadBarrier gBarrier; + + +// ================================ // +// Load asset from single thread. Barrier should end in clean state without waiting assets on list. +// Note that this checks state cleaning in situation, when there're no other threads what differs +// from previous test case. +TEST_CASE( "GraphicAPI.LoadBarrier.SingleAssetLoading", "[GraphicAPI]" ) +{ + auto result = gBarrier.RequestAsset( assetFile ); + + // New Waiting asset should be created in this case. + REQUIRE( result.second == false ); + CHECK( result.first != nullptr ); + + // Here in real application should be loading code. + + gBarrier.LoadingCompleted( assetFile ); + + // Waiting assets list should be cleaned. + CHECK( sw::CLASS_TESTER( LoadBarrier )::GetWaitingAssets( gBarrier ).size() == 0 ); +} + +// ================================ // +// +TEST_CASE( "GraphicAPI.LoadBarrier.SingleAssetLoading.FailedLoading", "[GraphicAPI]" ) +{ + sw::LoadBarrier barrier; + auto result = barrier.RequestAsset( assetFile ); + + // New Waiting asset should be created in this case. + REQUIRE( result.second == false ); + CHECK( result.first != nullptr ); + + // Here in real application should be loading code. + + barrier.LoadingFailed( assetFile, std::make_shared< sw::RuntimeException >( "Error!" ) ); + + // Waiting assets list should be cleaned. + CHECK( sw::CLASS_TESTER( LoadBarrier )::GetWaitingAssets( barrier ).size() == 0 ); +} + + +// ================================ // +// Checks if we can access error after loading asset. +TEST_CASE( "GraphicAPI.LoadBarrier.SingleAssetLoading.FailedLoading.AccessError", "[GraphicAPI]" ) +{ + sw::ThreadsBarrier waitForMainThread( 2 ); + sw::ThreadsBarrier waitWithLoading( 2 ); + + sw::LoadBarrier waitingAssets; + + std::thread loadingThread( [&]() + { + auto result = waitingAssets.RequestAsset( assetFile ); + + waitForMainThread.ArriveAndWait(); // This forces this thread to request asset as first. + waitWithLoading.ArriveAndWait(); // Wait for first thread to request asset. + + waitingAssets.LoadingFailed( assetFile, std::make_shared< sw::RuntimeException >( "Error!" ) ); + } ); + + // Wait for second thread to RequestAsset + waitForMainThread.ArriveAndWait(); + + // Request asset as second. + auto result = waitingAssets.RequestAsset( assetFile ); + + sw::WaitingAsset* assetWait = result.first; + bool needWait = result.second; + + REQUIRE( needWait ); // Needs to wait. + + // After this barrier second thread can send LoadingFailed + waitWithLoading.ArriveAndWait(); + + auto loadingResult = waitingAssets.WaitUntilLoaded( assetWait ); + + loadingThread.join(); + + REQUIRE( loadingResult.IsValid() == false ); + CHECK( loadingResult.GetError() != nullptr ); + + // Waiting assets list should be cleaned. + CHECK( sw::CLASS_TESTER( LoadBarrier )::GetWaitingAssets( waitingAssets ).size() == 0 ); +} diff --git a/Tests/TestResourceManager/TestAssetPath.cpp b/Tests/TestResourceManager/TestAssetPath.cpp new file mode 100644 index 0000000..81de98c --- /dev/null +++ b/Tests/TestResourceManager/TestAssetPath.cpp @@ -0,0 +1,180 @@ +#include "swGraphicAPI/Tests/TestResourceManager/stdafx.h" +#include "swCommonLib/External/Catch/catch.hpp" +/** +@file TestAssetPath.cpp +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + +#include "swGraphicAPI/ResourceManager/PathTranslators/AssetPath.h" + + +using namespace sw; + + +// ================================ // +// +TEST_CASE( "GraphicAPI.AssetPath.Constructor.FromPaths", "[GraphicAPI]" ) +{ + AssetPath path( "C://temp/newfolder/file.mesh", "materials/checker" ); + + CHECK( path.GetFile() == "C://temp/newfolder/file.mesh" ); + CHECK( path.GetInternalPath() == "materials/checker" ); +} + +// ================================ // +// +TEST_CASE( "GraphicAPI.AssetPath.Constructor.FromConstChar", "[GraphicAPI]" ) +{ + AssetPath path( "C://temp/newfolder/file.mesh::/materials/checker" ); + + CHECK( path.GetFile() == "C://temp/newfolder/file.mesh" ); + CHECK( path.GetInternalPath() == "/materials/checker" ); +} + +// ================================ // +// +TEST_CASE( "GraphicAPI.AssetPath.Constructor.FromString", "[GraphicAPI]" ) +{ + AssetPath path( std::string( "C://temp/newfolder/file.mesh::/materials/checker" ) ); + + CHECK( path.GetFile() == "C://temp/newfolder/file.mesh" ); + CHECK( path.GetInternalPath() == "/materials/checker" ); +} + +// ================================ // +// +TEST_CASE( "GraphicAPI.AssetPath.FromString.BothPathsExist", "[GraphicAPI]" ) +{ + auto nullablePath = AssetPath::FromString( "C://temp/newfolder/file.mesh::/materials/checker" ); + + REQUIRE( nullablePath.IsValid() == true ); + auto path = nullablePath.Get(); + + CHECK( path.GetFile() == "C://temp/newfolder/file.mesh" ); + CHECK( path.GetInternalPath() == "/materials/checker" ); +} + +// ================================ // +// +TEST_CASE( "GraphicAPI.AssetPath.FromString.OnlyFilePath", "[GraphicAPI]" ) +{ + auto nullablePath = AssetPath::FromString( "C://temp/newfolder/file.mesh" ); + + REQUIRE( nullablePath.IsValid() == true ); + auto path = nullablePath.Get(); + + CHECK( path.GetFile() == "C://temp/newfolder/file.mesh" ); + CHECK( path.GetInternalPath() == "" ); +} + +// ================================ // +// +TEST_CASE( "GraphicAPI.AssetPath.FromString.OnlyInternalPath", "[GraphicAPI]" ) +{ + auto nullablePath = AssetPath::FromString( "::/materials/checker" ); + + REQUIRE( nullablePath.IsValid() == true ); + auto path = nullablePath.Get(); + + CHECK( path.GetFile() == "" ); + CHECK( path.GetInternalPath() == "/materials/checker" ); +} + +// ================================ // +// +TEST_CASE( "GraphicAPI.AssetPath.FromString.OnlyFilePathSeparatorOnEnd", "[GraphicAPI]" ) +{ + auto nullablePath = AssetPath::FromString( "C://temp/newfolder/file.mesh::" ); + + REQUIRE( nullablePath.IsValid() == true ); + auto path = nullablePath.Get(); + + CHECK( path.GetFile() == "C://temp/newfolder/file.mesh" ); + CHECK( path.GetInternalPath() == "" ); +} + +// ================================ // +/// If there are two separators in string we threat everything after first separator as internal name. +TEST_CASE( "GraphicAPI.AssetPath.FromString.TwoSeparators", "[GraphicAPI]" ) +{ + auto nullablePath = AssetPath::FromString( "C://temp/newfolder/file.mesh::materials::checker" ); + + REQUIRE( nullablePath.IsValid() == true ); + auto path = nullablePath.Get(); + + CHECK( path.GetFile() == "C://temp/newfolder/file.mesh" ); + CHECK( path.GetInternalPath() == "materials::checker" ); +} + + +//====================================================================================// +// Operators +//====================================================================================// + +// ================================ // +// +TEST_CASE( "GraphicAPI.AssetPath.Operators.EqualPaths", "[GraphicAPI]" ) +{ + AssetPath path1( "C://temp/newfolder/file.mesh", "materials/checker" ); + AssetPath path2( "C://temp/newfolder/file.mesh", "materials/checker" ); + + CHECK( ( path1 == path2 ) == true ); + CHECK( ( path1 != path2 ) == false ); + CHECK( ( path1 < path2 ) == false ); + CHECK( ( path1 > path2 ) == false ); + CHECK( ( path1 <= path2 ) == true ); + CHECK( ( path1 >= path2 ) == true ); + + CHECK( ( path2 == path1 ) == true ); + CHECK( ( path2 != path1 ) == false ); + CHECK( ( path2 < path1 ) == false ); + CHECK( ( path2 > path1 ) == false ); + CHECK( ( path2 <= path1 ) == true ); + CHECK( ( path2 >= path1 ) == true ); +} + + +// ================================ // +// +TEST_CASE( "GraphicAPI.AssetPath.Operators.FilePathDiffers", "[GraphicAPI]" ) +{ + AssetPath path1( "C://temp/newfolder/fila.mesh", "materials/checker" ); + AssetPath path2( "C://temp/newfolder/file.mesh", "materials/checker" ); + + CHECK( ( path1 == path2 ) == false ); + CHECK( ( path1 != path2 ) == true ); + CHECK( ( path1 < path2 ) == true ); + CHECK( ( path1 > path2 ) == false ); + CHECK( ( path1 <= path2 ) == true ); + CHECK( ( path1 >= path2 ) == false ); + + CHECK( ( path2 == path1 ) == false ); + CHECK( ( path2 != path1 ) == true ); + CHECK( ( path2 < path1 ) == false ); + CHECK( ( path2 > path1 ) == true ); + CHECK( ( path2 <= path1 ) == false ); + CHECK( ( path2 >= path1 ) == true ); +} + +// ================================ // +// +TEST_CASE( "GraphicAPI.AssetPath.Operators.InternalPathDiffers", "[GraphicAPI]" ) +{ + AssetPath path1( "C://temp/newfolder/file.mesh", "materials/checkerA" ); + AssetPath path2( "C://temp/newfolder/file.mesh", "materials/checkerB" ); + + CHECK( ( path1 == path2 ) == false ); + CHECK( ( path1 != path2 ) == true ); + CHECK( ( path1 < path2 ) == true ); + CHECK( ( path1 > path2 ) == false ); + CHECK( ( path1 <= path2 ) == true ); + CHECK( ( path1 >= path2 ) == false ); + + CHECK( ( path2 == path1 ) == false ); + CHECK( ( path2 != path1 ) == true ); + CHECK( ( path2 < path1 ) == false ); + CHECK( ( path2 > path1 ) == true ); + CHECK( ( path2 <= path1 ) == false ); + CHECK( ( path2 >= path1 ) == true ); +} diff --git a/Tests/TestResourceManager/TestAssetsFactory.cpp b/Tests/TestResourceManager/TestAssetsFactory.cpp new file mode 100644 index 0000000..1d884d4 --- /dev/null +++ b/Tests/TestResourceManager/TestAssetsFactory.cpp @@ -0,0 +1,75 @@ +#include "swGraphicAPI/Tests/TestResourceManager/stdafx.h" +#include "swCommonLib/External/Catch/catch.hpp" +/** +@file TestAssetsFactory.cpp +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + + +#include "swGraphicAPI/ResourceManager/AssetCreators/AssetsFactory.h" + +#include "swGraphicAPI/ResourceManager/AssetCreators/Shaders/ShaderCreator.h" +#include "swGraphicAPI/Resources/Shaders/ShaderInitData.h" + + +using namespace sw; + +//====================================================================================// +// Helpers +//====================================================================================// + +// ================================ // +// +class FakeResource : public Resource +{ + RTTR_ENABLE( Resource ); +}; + +// ================================ // +// +struct FakeResourceInitData : public IAssetCreateInfo +{ + RTTR_ENABLE( IAssetCreateInfo ); + +public: + + virtual TypeID GetAssetType () const override + { + return TypeID::get< FakeResource >(); + } +}; + + + +//====================================================================================// +// Tests +//====================================================================================// + +// ================================ // +// +TEST_CASE( "GraphicAPI.AssetsFactory.CreateAsset", "[GraphicAPI]" ) +{ + AssetsFactory factory; + ShaderInitData init( ShaderType::VertexShader ); + + auto result = factory.CreateAsset( "../TestAssets/shaders/hlsl/MinimalShader.vsh", TypeID::get< VertexShader >(), std::move( init ) ); + REQUIRE( result.IsValid() == true ); + + CHECK( result.Get() != nullptr ); +} + +// ================================ // +// +TEST_CASE( "GraphicAPI.AssetsFactory.CreateAsset.NotRegisteredCreator", "[GraphicAPI]" ) +{ + AssetsFactory factory; + FakeResourceInitData init; + + auto result = factory.CreateAsset( "Fake", TypeID::get< FakeResource >(), std::move( init ) ); + REQUIRE( result.IsValid() == false ); + CHECK( result.GetError() != nullptr ); +} + + + diff --git a/Tests/TestResourceManager/TestCreators/TestBufferCreator.cpp b/Tests/TestResourceManager/TestCreators/TestBufferCreator.cpp new file mode 100644 index 0000000..1fc4935 --- /dev/null +++ b/Tests/TestResourceManager/TestCreators/TestBufferCreator.cpp @@ -0,0 +1,47 @@ +#include "swGraphicAPI/Tests/TestResourceManager/stdafx.h" +#include "swCommonLib/External/Catch/catch.hpp" +/** +@file TestBufferCreator.cpp +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + + +#include "swGraphicAPI/ResourceManager/AssetCreators/AssetsFactory.h" + +#include "swGraphicAPI/ResourceManager/AssetCreators/Buffers/BufferCreator.h" +#include "swGraphicAPI/Resources/Buffers/Buffer.h" + +#include "swCommonLib/Common/Buffers/BufferTyped.h" + + +using namespace sw; + + + +// ================================ // +// +struct Buffer8Bytes +{ + float x, y; +}; + + +// ================================ // +// Creator shouldn't create buffer, that hasn't size that is multiply of 16 bytes. +TEST_CASE( "GraphicAPI.AssetsCreators.BufferCreator.ConstantBuffer.NotAligned", "[GraphicAPI][AssetsCreators]" ) +{ + BufferCreator creator; + BufferTyped< Buffer8Bytes > buffer( 1 ); + + ConstantBufferInitData init; + init.ElementSize = (uint32)buffer.ElementSize(); + init.NumElements = (uint32)buffer.ElementsCount(); + init.Data = buffer.GetRawData(); + + auto result = creator.Create( "::/Buffer/NotAligned", std::move( init ) ); + REQUIRE( result.IsValid() == false ); + + CHECK( result.GetError() != nullptr ); +} + diff --git a/Tests/TestResourceManager/TestLoadPath.cpp b/Tests/TestResourceManager/TestLoadPath.cpp new file mode 100644 index 0000000..5e91dff --- /dev/null +++ b/Tests/TestResourceManager/TestLoadPath.cpp @@ -0,0 +1,68 @@ +#include "swGraphicAPI/Tests/TestResourceManager/stdafx.h" +#include "swCommonLib/External/Catch/catch.hpp" +/** +@file LoadPath.cpp +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + + +#include "swGraphicAPI/ResourceManager/PathTranslators/LoadPath.h" +#include "swGraphicAPI/MockAssets/Utils.h" + + +using namespace sw; + + +// ================================ // +// Constructor translates path using PathsManager from parameters. +TEST_CASE( "GraphicAPI.ResourceManager.PathAliases.LoadPath.Constructor", "[GraphicAPI]" ) +{ + auto rm = CreateResourceManagerWithMocks(); + + auto path = AssetPath::FromString( "$(MocksDir)/example.mock" ); + auto loadPath = LoadPath( path, rm->GetPathsManager() ); + + CHECK( loadPath.GetFileOriginal() == "$(MocksDir)/example.mock" ); + CHECK( loadPath.GetFileTranslated() == filesystem::Path::WorkingDirectory().GetParent() / "TestAssets/mock/example.mock" ); +} + +// ================================ // +// Translation should normalize path. +TEST_CASE( "GraphicAPI.ResourceManager.PathAliases.LoadPath.Normalization", "[GraphicAPI]" ) +{ + auto rm = CreateResourceManagerWithMocks(); + + auto path = AssetPath::FromString( "$(MocksDir)/../example.mock" ); + auto loadPath = LoadPath( path, rm->GetPathsManager() ); + + CHECK( loadPath.GetFileOriginal() == "$(MocksDir)/../example.mock" ); + CHECK( loadPath.GetFileTranslated() == filesystem::Path::WorkingDirectory().GetParent() / "TestAssets/example.mock" ); +} + +// ================================ // +// +TEST_CASE( "GraphicAPI.ResourceManager.PathAliases.LoadPath.TranslateEmpty", "[GraphicAPI]" ) +{ + auto rm = CreateResourceManagerWithMocks(); + + auto path = AssetPath::FromString( "::example/TranslateEmpty" ); + auto loadPath = LoadPath( path, rm->GetPathsManager() ); + + CHECK( loadPath.GetFileOriginal() == "" ); + CHECK( loadPath.GetFileTranslated().String() == "" ); +} + +// ================================ // +// +TEST_CASE( "GraphicAPI.ResourceManager.PathAliases.LoadPath.TranslateRelative", "[GraphicAPI]" ) +{ + auto rm = CreateResourceManagerWithMocks(); + + auto path = AssetPath::FromString( "TestAssets/example.mock" ); + auto loadPath = LoadPath( path, rm->GetPathsManager() ); + + CHECK( loadPath.GetFileOriginal() == "TestAssets/example.mock" ); + CHECK( loadPath.GetFileTranslated() == ( filesystem::Path::WorkingDirectory() / "TestAssets/example.mock" ).String() ); +} + diff --git a/Tests/TestResourceManager/TestLoaders/TestRenderTargetLoader.cpp b/Tests/TestResourceManager/TestLoaders/TestRenderTargetLoader.cpp new file mode 100644 index 0000000..a1b1fed --- /dev/null +++ b/Tests/TestResourceManager/TestLoaders/TestRenderTargetLoader.cpp @@ -0,0 +1,49 @@ +#include "swGraphicAPI/Tests/TestResourceManager/stdafx.h" +#include "swCommonLib/External/Catch/catch.hpp" +/** +@file TestRenderTargetLoader.cpp +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + + +#include "swGraphicAPI/ResourceManager/ResourceManager.h" + +#include "swGraphicAPI/MockAssets/Utils.h" + + + +using namespace sw; + + +// ================================ // +// Checks if RenderTargetLoader adds all textures to ResoruceManager correctly. +TEST_CASE( "GraphicAPI.RenderTargetLoader.Create.ColorDepthStencil", "[GraphicAPI]" ) +{ + auto rm = CreateResourceManagerWithMocksAndDefaults(); + + RenderTargetLoadInfo init; + init.Height = 8; + init.Width = 8; + init.DepthStencilFormat = DepthStencilFormat::DEPTH_STENCIL_FORMAT_D24_UNORM_S8_UINT; + init.ColorBuffFormat = ResourceFormat::RESOURCE_FORMAT_B8G8R8A8_UNORM; + + auto result = rm->LoadGeneric( "::/ColorDepthStencilRT", &init, TypeID::get< RenderTarget >() ); + REQUIRE_IS_VALID( result ); + + auto loadedRT = result.Get(); + + auto rt = rm->Get< RenderTarget >( "::/ColorDepthStencilRT" ); + auto colorTex = rm->Get< Texture >( "::/ColorDepthStencilRT/color" ); + auto depthTex = rm->Get< Texture >( "::/ColorDepthStencilRT/depth" ); + auto stencilTex = rm->Get< Texture >( "::/ColorDepthStencilRT/stencil" ); + + CHECK( rt != nullptr ); + CHECK( rt == loadedRT ); + + CHECK( colorTex == rt->GetColorBuffer() ); + CHECK( depthTex == rt->GetDepthBuffer() ); + CHECK( stencilTex == rt->GetStencilBuffer() ); +} + + diff --git a/Tests/TestResourceManager/TestLoaders/TestShaderLoader.cpp b/Tests/TestResourceManager/TestLoaders/TestShaderLoader.cpp new file mode 100644 index 0000000..834eb55 --- /dev/null +++ b/Tests/TestResourceManager/TestLoaders/TestShaderLoader.cpp @@ -0,0 +1,67 @@ +#include "swGraphicAPI/Tests/TestResourceManager/stdafx.h" +#include "swCommonLib/External/Catch/catch.hpp" +/** +@file TestShaderLoader.cpp +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + + +#include "swGraphicAPI/ResourceManager/ResourceManager.h" + +#include "swGraphicAPI/MockAssets/Utils.h" + +#include "swCommonLib/Common/Exceptions/Common/FileNotFoundException.h" + + +using namespace sw; + + +// ================================ // +// +TEST_CASE( "GraphicAPI.ShaderLoader.FileDoesntExists", "[GraphicAPI]" ) +{ + auto rm = CreateResourceManagerWithMocksAndDefaults(); + + auto resource = rm->LoadGeneric( "../TestAssets/shaders/example-notexists.vsh::main", nullptr, TypeID::get< VertexShader >() ); + REQUIRE( resource.IsValid() == false ); + + CHECK( resource.GetError() != nullptr ); + CHECK( resource.GetError()->get_type() == TypeID::get< FileNotFoundException >() ); +} + +// ================================ // +// +TEST_CASE( "GraphicAPI.ShaderLoader.Load.VertexShader", "[GraphicAPI]" ) +{ + auto rm = CreateResourceManagerWithMocksAndDefaults(); + + auto resource = rm->LoadGeneric( "../TestAssets/shaders/hlsl/MinimalShader.vsh::main", nullptr, TypeID::get< VertexShader >() ); + REQUIRE( resource.IsValid() == true ); + + CHECK( resource.Get() != nullptr ); +} + +// ================================ // +// +TEST_CASE( "GraphicAPI.ShaderLoader.Load.PixelShader", "[GraphicAPI]" ) +{ + auto rm = CreateResourceManagerWithMocksAndDefaults(); + + auto resource = rm->LoadGeneric( "../TestAssets/shaders/hlsl/MinimalShader.psh::main", nullptr, TypeID::get< PixelShader >() ); + REQUIRE( resource.IsValid() == true ); + + CHECK( resource.Get() != nullptr ); +} + +// ================================ // +// +TEST_CASE( "GraphicAPI.ShaderLoader.Load.ComputeShader", "[GraphicAPI]" ) +{ + auto rm = CreateResourceManagerWithMocksAndDefaults(); + + auto resource = rm->LoadGeneric( "../TestAssets/shaders/hlsl/MinimalShader.csh::main", nullptr, TypeID::get< ComputeShader >() ); + REQUIRE( resource.IsValid() == true ); + + CHECK( resource.Get() != nullptr ); +} diff --git a/Tests/TestResourceManager/TestLoadingResult.cpp b/Tests/TestResourceManager/TestLoadingResult.cpp new file mode 100644 index 0000000..b9e7070 --- /dev/null +++ b/Tests/TestResourceManager/TestLoadingResult.cpp @@ -0,0 +1,140 @@ +#include "swGraphicAPI/Tests/TestResourceManager/stdafx.h" +#include "swCommonLib/External/Catch/catch.hpp" +/** +@file TestLoadingResult.cpp +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + + +#include "swGraphicAPI/ResourceManager/Loaders/LoadingResult.h" + +#include "swGraphicAPI/ResourceManager/ResourceManager.h" +#include "swGraphicAPI/MockAssets/MockAssetCreator.h" +#include "swGraphicAPI/MockAssets/MockAsset.h" + + +namespace sw +{ + +// ================================ // +// +LoadingResult ConstructFromString ( std::string error ) +{ return error; } + +// ================================ // +// Test checks if LoadingResult works with expected syntax +// when returning value from function. +TEST_CASE( "GraphicAPI.Loading.LoadingResult.Constructor.ErrorString", "[GraphicAPI]" ) +{ + auto result = ConstructFromString( "Error message" ); + + REQUIRE( result.Assets.IsValid() == false ); + CHECK( result.Assets.GetError() != nullptr ); + CHECK( result.Assets.GetErrorReason() == "Error message" ); + CHECK( result.Warnings == nullptr ); +} + +// ================================ // +// +LoadingResult ConstructFromStringAndWarning ( std::string error, ExceptionPtr warning ) +{ + return { error, warning }; +} + +// ================================ // +// Test checks if LoadingResult works with expected syntax +// when returning value from function. +TEST_CASE( "GraphicAPI.Loading.LoadingResult.Constructor.ErrorStringAndWarning", "[GraphicAPI]" ) +{ + auto result = ConstructFromStringAndWarning( "Error message", std::make_shared< RuntimeException >( "Warning" ) ); + + REQUIRE( result.Assets.IsValid() == false ); + CHECK( result.Assets.GetError() != nullptr ); + CHECK( result.Assets.GetErrorReason() == "Error message" ); + + REQUIRE( result.Warnings != nullptr ); + CHECK( result.Warnings->ErrorMessage() == "Warning" ); +} + +// ================================ // +// +LoadingResult ConstructFromException ( ExceptionPtr error ) +{ + return error; +} + +// ================================ // +// Test checks if LoadingResult works with expected syntax +// when returning value from function. +TEST_CASE( "GraphicAPI.Loading.LoadingResult.Constructor.Exception", "[GraphicAPI]" ) +{ + auto result = ConstructFromException( std::make_shared< RuntimeException >( "Error message" ) ); + + REQUIRE( result.Assets.IsValid() == false ); + CHECK( result.Assets.GetError() != nullptr ); + CHECK( result.Assets.GetErrorReason() == "Error message" ); + CHECK( result.Warnings == nullptr ); +} + +// ================================ // +// +LoadingResult ConstructFromExceptions ( ExceptionPtr error, ExceptionPtr warning ) +{ + return { error, warning }; +} + +// ================================ // +// Test checks if LoadingResult works with expected syntax +// when returning value from function. +TEST_CASE( "GraphicAPI.Loading.LoadingResult.Constructor.ExceptionAndWarning", "[GraphicAPI]" ) +{ + auto result = ConstructFromExceptions( std::make_shared< RuntimeException >( "Error message" ), std::make_shared< RuntimeException >( "Warning" ) ); + + REQUIRE( result.Assets.IsValid() == false ); + CHECK( result.Assets.GetError() != nullptr ); + CHECK( result.Assets.GetErrorReason() == "Error message" ); + + REQUIRE( result.Warnings != nullptr ); + CHECK( result.Warnings->ErrorMessage() == "Warning" ); +} + +// ================================ // +// +TEST_CASE( "GraphicAPI.Loading.LoadingResult.Constructor.SingleResource", "[GraphicAPI]" ) +{ + auto creator = MockAssetCreator::CreateCreator(); // Creator must live longer then ResourceManager since it tracks references of created assets. + ResourceManager rm; rm.RegisterAssetCreator( creator ); + + MockAssetCreateInfo init; + + auto result = rm.CreateGenericAsset( "::/LoadingResult/ResourceToReturn", TypeID::get< MockAsset >(), std::move( init ) ); + REQUIRE( result.IsValid() ); + + LoadingResult resourceResult( result.Get() ); + + REQUIRE( resourceResult.Assets.IsValid() == true ); + CHECK( resourceResult.Assets.Get()[ 0 ] == result.Get() ); +} + +// ================================ // +// +TEST_CASE( "GraphicAPI.Loading.LoadingResult.Constructor.Exception+ErrorsCollector", "[GraphicAPI]" ) +{ + ErrorsCollector collector; + collector.Add( std::static_pointer_cast< Exception >( std::make_shared< RuntimeException >( "Warning" ) ) ); + + LoadingResult result{ std::make_shared< RuntimeException >( "Error message" ), collector }; + + REQUIRE( result.Assets.IsValid() == false ); + CHECK( result.Assets.GetError() != nullptr ); + CHECK( result.Assets.GetErrorReason() == "Error message" ); + + REQUIRE( result.Warnings != nullptr ); + CHECK( result.Warnings->ErrorMessage() == "Warning" ); +} + + +} // sw + + diff --git a/Tests/TestResourceManager/TestPathsManager.cpp b/Tests/TestResourceManager/TestPathsManager.cpp new file mode 100644 index 0000000..c25d3e0 --- /dev/null +++ b/Tests/TestResourceManager/TestPathsManager.cpp @@ -0,0 +1,97 @@ +#include "swGraphicAPI/Tests/TestResourceManager/stdafx.h" +#include "swCommonLib/External/Catch/catch.hpp" +/** +@file TestPathsManager.cpp +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + + + +#include "swGraphicAPI/ResourceManager/PathTranslators/PathsManager.h" + + + + +// ================================ // +// Register new alias. +TEST_CASE( "GUI.PathsManager.AliasRegister.ValidAlias", "[GUISystem][PathsManager]" ) +{ + sw::PathsManager pathsManager; + + sw::ReturnResult result = pathsManager.RegisterAlias( "$(BLABLA_DIR)", "C:\\blabla/blabla" ); + + REQUIRE( result.IsValid() == true ); + CHECK( pathsManager.FindAlias( "$(BLABLA_DIR)" ).IsValid() == true ); +} + +// ================================ // +// Don't register invalid alias. +TEST_CASE( "GUI.PathsManager.AliasRegister.InvalidAlias", "[GUISystem][PathsManager]" ) +{ + sw::PathsManager pathsManager; + + sw::ReturnResult result = pathsManager.RegisterAlias( "BLABLA_DIR", "C:\\blabla/blabla" ); + + REQUIRE( result.IsValid() == false ); + CHECK( pathsManager.FindAlias( "$(BLABLA_DIR)" ).IsValid() == false ); +} + +// ================================ // +// Don't register existing alias. +TEST_CASE( "GUI.PathsManager.AliasRegister.Existing", "[GUISystem][PathsManager]" ) +{ + sw::PathsManager pathsManager; + + pathsManager.RegisterAlias( "$(BLABLA_DIR)", "C:\\blabla/blabla" ); + sw::ReturnResult result = pathsManager.RegisterAlias( "$(BLABLA_DIR)", "C:\\blabla/blabla" ); + + REQUIRE( result.IsValid() == false ); + CHECK( pathsManager.FindAlias( "$(BLABLA_DIR)" ).IsValid() == true ); +} + + +// ================================ // +// Translate path using alias. +TEST_CASE( "GUI.PathsManager.Translate.ExistingAlias", "[GUISystem][PathsManager]" ) +{ + sw::PathsManager pathsManager; + + sw::ReturnResult result = pathsManager.RegisterAlias( "$(BLABLA_DIR)", "C:\\blabla/blabla" ); + REQUIRE( result.IsValid() == true ); + + auto path = pathsManager.Translate( "$(BLABLA_DIR)/gooddir/goodfile.txt" ); + CHECK( path == "C:\\blabla/blabla/gooddir/goodfile.txt" ); +} + + +// ================================ // +// Translate path using not existing alias. Path remains unchanged. +TEST_CASE( "GUI.PathsManager.Translate.NotExistingAlias", "[GUISystem][PathsManager]" ) +{ + sw::PathsManager pathsManager; + + sw::ReturnResult result = pathsManager.RegisterAlias( "$(BLABLA_DIR)", "C:\\blabla/blabla" ); + REQUIRE( result.IsValid() == true ); + + auto path = pathsManager.Translate( "$(WORKING_DIR)/gooddir/goodfile.txt" ); + CHECK( path == "$(WORKING_DIR)/gooddir/goodfile.txt" ); +} + +// ================================ // +// Create alias with path, that references other xisting alias. +// Path should be resolved correctly. +TEST_CASE( "GUI.PathsManager.Translate.AliasReferenceInAlias", "[GUISystem][PathsManager]" ) +{ + sw::PathsManager pathsManager; + + sw::ReturnResult result = pathsManager.RegisterAlias( "$(TMP_DIR)", "C:\\blabla/tmp" ); + REQUIRE( result.IsValid() == true ); + + result = pathsManager.RegisterAlias( "$(BLABLA_DIR)", "$(TMP_DIR)/blabla/not_tmp" ); + REQUIRE( result.IsValid() == true ); + + auto path = pathsManager.Translate( "$(BLABLA_DIR)/gooddir/goodfile.txt" ); + CHECK( path == "C:\\blabla/tmp//blabla/not_tmp/gooddir/goodfile.txt" ); +} + diff --git a/Tests/TestResourceManager/TestResourceManager/TestAssetsCreation.cpp b/Tests/TestResourceManager/TestResourceManager/TestAssetsCreation.cpp new file mode 100644 index 0000000..d5c1dff --- /dev/null +++ b/Tests/TestResourceManager/TestResourceManager/TestAssetsCreation.cpp @@ -0,0 +1,125 @@ +#include "swGraphicAPI/Tests/TestResourceManager/stdafx.h" +#include "swCommonLib/External/Catch/catch.hpp" +/** +@file TestAssetsCreation.cpp +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + + +#include "swGraphicAPI/ResourceManager/ResourceManager.h" + + +#include "swGraphicAPI/Resources/Buffers/BufferInitData.h" +#include "swCommonLib/Common/Buffers/BufferTyped.h" + +#include "swGraphicAPI/MockAssets/MockAssetCreator.h" +#include "swGraphicAPI/MockAssets/MockAsset.h" + + + +using namespace sw; + + +// ================================ // +// +struct RandomStruct +{ + float x, y, z, w; +}; + + + +// ================================ // +// +TEST_CASE( "GraphicAPI.ResourceManager.RegisterAssetCreator", "[GraphicAPI]" ) +{ + auto creator = MockAssetCreator::CreateCreator(); // Creator must live longer then ResourceManager since it tracks references of created assets. + + ResourceManager rm; + + bool regResult = rm.RegisterAssetCreator( creator ); + REQUIRE( regResult == true ); + + MockAssetCreateInfo init; + + auto result = rm.CreateGenericAsset( "::/RegisterAssetCreator/Check", TypeID::get< MockAsset >(), std::move( init ) ); + REQUIRE( result.IsValid() ); + + CHECK( rm.GetGeneric( "::/RegisterAssetCreator/Check", TypeID::get< MockAsset >() ) != nullptr ); +} + + +// ================================ // +// +TEST_CASE( "GraphicAPI.ResourceManager.CreateAsset.SingleAsset", "[GraphicAPI]" ) +{ + ResourceManager rm; + + BufferTyped< RandomStruct > buffer( 10 ); + + ConstantBufferInitData init; + init.ElementSize = (uint32)buffer.ElementSize(); + init.NumElements = (uint32)buffer.ElementsCount(); + init.Data = buffer.GetRawData(); + + auto result = rm.CreateGenericAsset( "::/RandomBuffer", TypeID::get< Buffer >(), std::move( init ) ); + REQUIRE( result.IsValid() ); + + CHECK( result.Get() != nullptr ); + CHECK( rm.GetGeneric( "::RandomBuffer", TypeID::get< Buffer >() ) != nullptr ); +} + +// ================================ // +// Can't create second asset with the same name. +TEST_CASE( "GraphicAPI.ResourceManager.CreateAsset.TwoAssetsSameName", "[GraphicAPI]" ) +{ + auto creator = MockAssetCreator::CreateCreator(); // Creator must live longer then ResourceManager since it tracks references of created assets. + ResourceManager rm; rm.RegisterAssetCreator( creator ); + + MockAssetCreateInfo init; + + auto result = rm.CreateGenericAsset( "::/CreateAsset/TwoAssetsSameName", TypeID::get< MockAsset >(), std::move( init ) ); + REQUIRE( result.IsValid() ); + + MockAssetCreateInfo init2; + + result = rm.CreateGenericAsset( "::/CreateAsset/TwoAssetsSameName", TypeID::get< MockAsset >(), std::move( init2 ) ); + REQUIRE( !result.IsValid() ); + + // One asset should still be alive in ResourceManager. Second asset shouldn't be created or should be properly destroyed. + CHECK( creator->CountLivingAssets() == 1 ); +} + +// ================================ // +// Can't create asset when creator isn't registered. +TEST_CASE( "GraphicAPI.ResourceManager.CreateAsset.AssetWithoutCreator", "[GraphicAPI]" ) +{ + ResourceManager rm; + + MockAssetCreateInfo init; + + auto result = rm.CreateGenericAsset( "::/CreateAsset/AssetWithoutCreator", TypeID::get< MockAsset >(), std::move( init ) ); + REQUIRE( !result.IsValid() ); + + CHECK( rm.GetGeneric( "::/RandomBuffer", TypeID::get< MockAsset >() ) == nullptr ); +} + +// ================================ // +// Asset won't be created if we specify wrong type. +TEST_CASE( "GraphicAPI.ResourceManager.CreateAsset.TypeOtherThenDeclared", "[GraphicAPI]" ) +{ + auto creator = MockAssetCreator::CreateCreator(); // Creator must live longer then ResourceManager since it tracks references of created assets. + + ResourceManager rm; + + bool regResult = rm.RegisterAssetCreator( creator ); + REQUIRE( regResult == true ); + + MockAssetCreateInfo init; + + auto result = rm.CreateGenericAsset( "::/RegisterAssetCreator/Check", TypeID::get< Buffer >(), std::move( init ) ); + REQUIRE( !result.IsValid() ); +} + + diff --git a/Tests/TestResourceManager/TestResourceManager/TestAssetsLoadingAsync.cpp b/Tests/TestResourceManager/TestResourceManager/TestAssetsLoadingAsync.cpp new file mode 100644 index 0000000..7faa931 --- /dev/null +++ b/Tests/TestResourceManager/TestResourceManager/TestAssetsLoadingAsync.cpp @@ -0,0 +1,107 @@ +#include "swGraphicAPI/Tests/TestResourceManager/stdafx.h" +#include "swCommonLib/External/Catch/catch.hpp" +/** +@file TestAssetsLoadingAsync.cpp +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + + +#include "swGraphicAPI/ResourceManager/ResourceManager.h" +#include "swGraphicAPI/ResourceManager/AsyncLoad/RMAsyncThread.h" + + +#include "swGraphicAPI/MockAssets/MockAssetCreator.h" +#include "swGraphicAPI/MockAssets/MockAsset.h" +#include "swGraphicAPI/MockAssets/MockAssetLoader.h" + +#include "swGraphicAPI/MockAssets/Utils.h" + +#include "swCommonLib/Common/Multithreading/ThreadsBarrier.h" + + +using namespace sw; + + + +// ================================ // +// +TEST_CASE( "GraphicAPI.ResourceManager.LoadGenericAsync.SimpleLoading", "[GraphicAPI][ResourceManager]" ) +{ + auto rm = CreateResourceManagerWithMocks(); + RMAsyncThread rmThread( rm.get() ); + + ResourcePointer resource; + ThreadsBarrier barier( 2 ); + + rmThread.LoadGenericAsync( "../TestAssets/mock/example.mock", nullptr, TypeID::get< MockAsset >(), + [ & ]( AssetLoadResponse& response ) + { + resource = response.Resource; + barier.ArriveAndWait(); + }, nullptr ); + + barier.ArriveAndWait(); + + REQUIRE( resource != nullptr ); +} + +// ================================ // +// If loading of asset fails, onFailed handler should be called. +TEST_CASE( "GraphicAPI.ResourceManager.LoadGenericAsync.LoadFails", "[GraphicAPI][ResourceManager]" ) +{ + auto rm = CreateResourceManagerWithMocks(); + RMAsyncThread rmThread( rm.get() ); + + ResourcePointer resource; + ExceptionPtr error; + ThreadsBarrier barier( 2 ); + + rmThread.LoadGenericAsync( "../TestAssets/mock/example-not-existing.mock", nullptr, TypeID::get< MockAsset >(), + nullptr, + [ & ]( AssetLoadResponse& response, ExceptionPtr exception ) + { + resource = response.Resource; + error = exception; + + barier.ArriveAndWait(); + } ); + + barier.ArriveAndWait(); + + REQUIRE( resource == nullptr ); + CHECK( error != nullptr ); +} + +// ================================ // +// +TEST_CASE( "GraphicAPI.ResourceManager.LoadGenericAsync.Load2Assets", "[GraphicAPI][ResourceManager]" ) +{ + auto rm = CreateResourceManagerWithMocks(); + RMAsyncThread rmThread( rm.get() ); + + ResourcePointer resource1; + ResourcePointer resource2; + ThreadsBarrier barier( 2 ); + + rmThread.LoadGenericAsync( "../TestAssets/mock/example.mock", nullptr, TypeID::get< MockAsset >(), + [ & ]( AssetLoadResponse& response ) + { + resource1 = response.Resource; + barier.ArriveAndWait(); + }, nullptr ); + + rmThread.LoadGenericAsync( "../TestAssets/mock/example1.mock", nullptr, TypeID::get< MockAsset >(), + [ & ]( AssetLoadResponse& response ) + { + resource2 = response.Resource; + barier.ArriveAndWait(); + }, nullptr ); + + // Wait for assets to be loaded. + barier.ArriveAndWait(); + barier.ArriveAndWait(); + + REQUIRE( resource1 != nullptr ); + REQUIRE( resource2 != nullptr ); +} diff --git a/Tests/TestResourceManager/TestResourceManager/TestAssetsLoadingSync.cpp b/Tests/TestResourceManager/TestResourceManager/TestAssetsLoadingSync.cpp new file mode 100644 index 0000000..d33007f --- /dev/null +++ b/Tests/TestResourceManager/TestResourceManager/TestAssetsLoadingSync.cpp @@ -0,0 +1,123 @@ +#include "swGraphicAPI/Tests/TestResourceManager/stdafx.h" +#include "swCommonLib/External/Catch/catch.hpp" +/** +@file TestAssetsLoadingSync.cpp +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + + +#include "swGraphicAPI/ResourceManager/ResourceManager.h" + + +#include "swGraphicAPI/MockAssets/MockAssetCreator.h" +#include "swGraphicAPI/MockAssets/MockAsset.h" +#include "swGraphicAPI/MockAssets/MockAssetLoader.h" + +#include "swGraphicAPI/MockAssets/Utils.h" + +#include "swCommonLib/Common/Multithreading/ThreadsBarrier.h" + + +using namespace sw; + + + +// ================================ // +// +TEST_CASE( "GraphicAPI.ResourceManager.LoadGeneric.SimpleLoading", "[GraphicAPI]" ) +{ + auto rm = CreateResourceManagerWithMocks(); + + MockAssetLoadInfo info; + + auto resource = rm->LoadGeneric( "../TestAssets/mock/example.mock", &info, TypeID::get< MockAsset >() ); + + REQUIRE( resource.IsValid() == true ); + REQUIRE( resource.Get() != nullptr ); + CHECK( static_cast< MockAsset* >( resource.Get().Ptr() )->GetContent() == "Example"); + + // This will hang if assets locks aren't released properly. + auto resource2 = rm->LoadGeneric( "../TestAssets/mock/example.mock", &info, TypeID::get< MockAsset >() ); +} + +// ================================ // +// +TEST_CASE( "GraphicAPI.ResourceManager.LoadGeneric.LoadNotExisting", "[GraphicAPI]" ) +{ + auto rm = CreateResourceManagerWithMocks(); + + MockAssetLoadInfo info; + + auto resource = rm->LoadGeneric( "../TestAssets/mock/example-notexists.mock", &info, TypeID::get< MockAsset >() ); + + REQUIRE( resource.IsValid() == false ); + + // This will hang if assets locks aren't released properly. + auto resource2 = rm->LoadGeneric( "../TestAssets/mock/example.mock", &info, TypeID::get< MockAsset >() ); +} + +// ================================ // +// +TEST_CASE( "GraphicAPI.ResourceManager.LoadGeneric.NotRegisteredLoader", "[GraphicAPI]" ) +{ + std::unique_ptr< ResourceManager > rm = std::make_unique< ResourceManager >(); + + MockAssetLoadInfo info; + auto resource = rm->LoadGeneric( "../TestAssets/mock/example.mock", &info, TypeID::get< MockAsset >() ); + + REQUIRE( resource.IsValid() == false ); + + // This will hang if assets locks aren't released properly. + auto resource2 = rm->LoadGeneric( "../TestAssets/mock/example.mock", &info, TypeID::get< MockAsset >() ); +} + +// ================================ // +// Load resource from two threads at the same time. Only one resource should +// be loaded. +TEST_CASE( "GraphicAPI.ResourceManager.LoadGeneric.TwoThreadsSameAsset", "[GraphicAPI]" ) +{ + auto rm = CreateResourceManagerWithMocks(); + + MockAssetLoadInfo info; + ThreadsBarrier barrier( 2 ); + + Nullable< ResourcePointer > threadResource; + + std::thread thread( [ & ]() + { + barrier.ArriveAndWait(); + threadResource = rm->LoadGeneric( "../TestAssets/mock/example.mock", &info, TypeID::get< MockAsset >() ); + } ); + + // Wait for second thread initialization. + barrier.ArriveAndWait(); + auto resource = rm->LoadGeneric( "../TestAssets/mock/example.mock", &info, TypeID::get< MockAsset >() ); + + thread.join(); + + REQUIRE( resource.IsValid() == true ); + REQUIRE( threadResource.IsValid() == true ); + + CHECK( resource.Get() == threadResource.Get() ); +} + +// ================================ // +// We first load asset and then try to load it again. We should get the same asset object. +TEST_CASE( "GraphicAPI.ResourceManager.LoadGeneric.LoadSameAfterLoad", "[GraphicAPI]" ) +{ + auto rm = CreateResourceManagerWithMocks(); + + MockAssetLoadInfo info; + + auto resource = rm->LoadGeneric( "../TestAssets/mock/example.mock", &info, TypeID::get< MockAsset >() ); + + REQUIRE( resource.IsValid() == true ); + REQUIRE( resource.Get() != nullptr ); + + // This will hang if assets locks aren't released properly. + auto resource2 = rm->LoadGeneric( "../TestAssets/mock/example.mock", &info, TypeID::get< MockAsset >() ); + + CHECK( resource.Get() == resource2.Get() ); +} + diff --git a/Tests/TestResourceManager/TestResourceManager/TestAssetsRemoval.cpp b/Tests/TestResourceManager/TestResourceManager/TestAssetsRemoval.cpp new file mode 100644 index 0000000..7a9b433 --- /dev/null +++ b/Tests/TestResourceManager/TestResourceManager/TestAssetsRemoval.cpp @@ -0,0 +1,118 @@ +#include "swGraphicAPI/Tests/TestResourceManager/stdafx.h" +#include "swCommonLib/External/Catch/catch.hpp" +/** +@file TestAssetsLoadingSync.cpp +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + + +#include "swGraphicAPI/ResourceManager/ResourceManager.h" + +#include "swGraphicAPI/MockAssets/Utils.h" + + +using namespace sw; + + + +// ================================ // +// FreeUnusedAssets must properly free all dependent assets. +TEST_CASE( "GraphicAPI.ResourceManager.AssetsRemoval.FreeUnusedAssets", "[GraphicAPI]" ) +{ + auto rm = CreateResourceManagerWithMocks(); + + auto nestedLevel3 = MockCompositeAssetLoadInfo::Create( {}, { "../TestAssets/mock/example1.mock", "../TestAssets/mock/example.mock" } ); + auto nestedLevel2 = MockCompositeAssetLoadInfo::Create( { nestedLevel3 }, { "../TestAssets/mock/example2.mock", } ); + auto nestedLevel1 = MockCompositeAssetLoadInfo::Create( { nestedLevel2 }, { "../TestAssets/mock/example3.mock", } ); + + auto resource = rm->LoadGeneric( "::/AssetsRemoval/FreeUnusedAssets", nestedLevel1.get(), TypeID::get< MockCompositeAsset >() ); + REQUIRE( resource.IsValid() == true ); + REQUIRE( resource.Get() != nullptr ); + + { + // Make sure rm holds as many assets as we expect. + auto mockAssetsList = rm->ListAssets( TypeID::get< MockAsset >() ); + auto mockCompositeAssetsList = rm->ListAssets( TypeID::get< MockCompositeAsset >() ); + + CHECK( mockAssetsList.size() == 4 ); + CHECK( mockCompositeAssetsList.size() == 3 ); + } + + // Free reference to top level resource. This is necessary because FreeUnusedAssets + // removes only assets without references. + resource.Get().ReleaseResource(); + + // Free all assets. + rm->FreeUnusedAssets(); + + // Check if all assets were removed. + { + auto mockAssetsList = rm->ListAssets( TypeID::get< MockAsset >() ); + auto mockCompositeAssetsList = rm->ListAssets( TypeID::get< MockCompositeAsset >() ); + + CHECK( mockAssetsList.size() == 0 ); + CHECK( mockCompositeAssetsList.size() == 0 ); + } +} + +// ================================ // +// Checks if FreeUnusedAssets doesn't remove referenced assets. +TEST_CASE( "GraphicAPI.ResourceManager.AssetsRemoval.FreeUnusedAssets.DontFreeUsedAsset", "[GraphicAPI]" ) +{ + auto rm = CreateResourceManagerWithMocks(); + + auto usedAssetInfo = MockCompositeAssetLoadInfo::Create( {}, { "../TestAssets/mock/example1.mock" } ); + auto unusedAssetInfo = MockCompositeAssetLoadInfo::Create( {}, { "../TestAssets/mock/example2.mock" } ); + + auto usedRes = rm->LoadGeneric( "::/AssetsRemoval/FreeUnusedAssets/DontFreeUsedAsset/Used", usedAssetInfo.get(), TypeID::get< MockCompositeAsset >() ); + auto unusedRes = rm->LoadGeneric( "::/AssetsRemoval/FreeUnusedAssets/DontFreeUsedAsset/NotUsed", unusedAssetInfo.get(), TypeID::get< MockCompositeAsset >() ); + + REQUIRE( usedRes.IsValid() == true ); + REQUIRE( unusedRes.IsValid() == true ); + + // Release only one resource. + unusedRes.Get().ReleaseResource(); + + rm->FreeUnusedAssets(); + + // Check if all expected assets were removed. + { + auto mockAssetsList = rm->ListAssets( TypeID::get< MockAsset >() ); + auto mockCompositeAssetsList = rm->ListAssets( TypeID::get< MockCompositeAsset >() ); + + CHECK( mockAssetsList.size() == 1 ); + CHECK( mockCompositeAssetsList.size() == 1 ); + } + + auto usedAsset2 = rm->GetGeneric( "::/AssetsRemoval/FreeUnusedAssets/DontFreeUsedAsset/Used", TypeID::get< MockCompositeAsset >() ); + CHECK( usedAsset2.Ptr() != nullptr ); + + auto internalReferenced = rm->GetGeneric( "../TestAssets/mock/example1.mock", TypeID::get< MockAsset >() ); + CHECK( internalReferenced.Ptr() != nullptr ); +} + +// ================================ // +// Checks if assets are removed properly. If assets aren't released it causes not only +// memory leaks by GPU resources leaks. +TEST_CASE( "GraphicAPI.ResourceManager.AssetsRemoval.FreeUnusedAssets.CheckLeaks", "[GraphicAPI]" ) +{ + auto creator = MockAssetCreator::CreateCreator(); // Creator must live longer then ResourceManager since it tracks references of created assets. + + ResourceManager rm; rm.RegisterAssetCreator( creator ); + + MockAssetCreateInfo init; + + auto asset = rm.CreateGenericAsset( "::/AssetsRemoval/FreeUnusedAssets/CheckLeaks", TypeID::get< MockAsset >(), std::move( init ) ); + REQUIRE( asset.IsValid() ); + + // Release all references to asset and than remove all unused assets. + asset.Get().ReleaseResource(); + rm.FreeUnusedAssets(); + + CHECK( creator->CountLivingAssets() == 0 ); +} + + + + diff --git a/Tests/TestResourceManager/TestResourceManager/TestListAssets.cpp b/Tests/TestResourceManager/TestResourceManager/TestListAssets.cpp new file mode 100644 index 0000000..919a52f --- /dev/null +++ b/Tests/TestResourceManager/TestResourceManager/TestListAssets.cpp @@ -0,0 +1,36 @@ +#include "swGraphicAPI/Tests/TestResourceManager/stdafx.h" +#include "swCommonLib/External/Catch/catch.hpp" +/** +@file TestListAssets.cpp +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + + +#include "swGraphicAPI/ResourceManager/ResourceManager.h" + +#include "swGraphicAPI/MockAssets/Utils.h" + + +using namespace sw; + + +// ================================ // +// FreeUnusedAssets must properly free all dependent assets. +TEST_CASE( "GraphicAPI.ResourceManager.ListAssets", "[GraphicAPI]" ) +{ + auto rm = CreateResourceManagerWithMocks(); + auto info = MockCompositeAssetLoadInfo::Create( {}, { "../TestAssets/mock/example1.mock", "../TestAssets/mock/example2.mock", "../TestAssets/mock/example3.mock" } ); + + auto resource = rm->LoadGeneric( "::GraphicAPI/ResourceManager/AssetsRemoval/FreeUnusedAssets", info.get(), TypeID::get< MockCompositeAsset >() ); + REQUIRE( resource.IsValid() == true ); + REQUIRE( resource.Get() != nullptr ); + + auto mockAssetsList = rm->ListAssets( TypeID::get< MockAsset >() ); + auto mockCompositeAssetsList = rm->ListAssets( TypeID::get< MockCompositeAsset >() ); + + CHECK( mockAssetsList.size() == 3 ); + CHECK( mockCompositeAssetsList.size() == 1 ); +} + + diff --git a/Tests/TestResourceManager/TestResourceManager/TestLoaders.cpp b/Tests/TestResourceManager/TestResourceManager/TestLoaders.cpp new file mode 100644 index 0000000..54181ac --- /dev/null +++ b/Tests/TestResourceManager/TestResourceManager/TestLoaders.cpp @@ -0,0 +1,41 @@ +#include "swGraphicAPI/Tests/TestResourceManager/stdafx.h" +#include "swCommonLib/External/Catch/catch.hpp" +/** +@file TestAssetsLoadingSync.cpp +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + + +#include "swGraphicAPI/ResourceManager/ResourceManager.h" + + +#include "swGraphicAPI/MockAssets/MockAssetCreator.h" +#include "swGraphicAPI/MockAssets/MockAsset.h" +#include "swGraphicAPI/MockAssets/MockAssetLoader.h" + +#include "swGraphicAPI/MockAssets/Utils.h" + + +using namespace sw; + + +// ================================ // +// +TEST_CASE( "GraphicAPI.ResourceManager.RegisterLoader", "[GraphicAPI]" ) +{ + auto loader = std::make_shared< MockAssetLoader >(); + + ResourceManager rm; + bool registerResult = rm.RegisterLoader( loader ); + + REQUIRE( registerResult == true ); + + auto loaders = rm.ListLoaders(); + + // RM registers 2 loaders by itself. + REQUIRE( loaders.size() == 3 ); + CHECK( std::find( loaders.begin(), loaders.end(), loader ) != loaders.end() ); +} + + diff --git a/Tests/TestResourceManager/TestResourceManager/TestPathAliases.cpp b/Tests/TestResourceManager/TestResourceManager/TestPathAliases.cpp new file mode 100644 index 0000000..c565ebd --- /dev/null +++ b/Tests/TestResourceManager/TestResourceManager/TestPathAliases.cpp @@ -0,0 +1,87 @@ +#include "swGraphicAPI/Tests/TestResourceManager/stdafx.h" +#include "swCommonLib/External/Catch/catch.hpp" +/** +@file TestPathAliases.cpp +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + + +#include "swGraphicAPI/ResourceManager/ResourceManager.h" + +#include "swGraphicAPI/MockAssets/Utils.h" +#include "swCommonLib/Common/Multithreading/ThreadsBarrier.h" + + +using namespace sw; + + +// ================================ // +// Developer can use path aliases to load resource. +TEST_CASE( "GraphicAPI.ResourceManager.PathAliases.Loading", "[GraphicAPI]" ) +{ + auto rm = CreateResourceManagerWithMocks(); + + MockAssetLoadInfo info; + auto resource = rm->LoadGeneric( "$(MocksDir)/example.mock", &info, TypeID::get< MockAsset >() ); + REQUIRE_IS_VALID( resource ); + + // Resource file name should contain alias. + CHECK( resource.Get()->GetFilePath() == "$(MocksDir)/example.mock" ); + + // Resource can be found using alias path. + auto resourceByMockAlias = rm->Get< MockAsset >( "$(MocksDir)/example.mock" ); + REQUIRE_IS_VALID( resource ); + + // Resource can be found using absolute path. + auto resourceByAbsolutePath = rm->Get< MockAsset >( "../TestAssets/mock/example.mock" ); + REQUIRE_IS_VALID( resource ); +} + + +// ================================ // +// Loading the same file pointed by two different path aliases, should load the same asset. +TEST_CASE( "GraphicAPI.ResourceManager.PathAliases.Loading.SamePathDifferentAliases", "[GraphicAPI]" ) +{ + auto rm = CreateResourceManagerWithMocks(); + + MockAssetLoadInfo info; + auto resource1 = rm->LoadGeneric( "$(MocksDir)/example.mock", &info, TypeID::get< MockAsset >() ); + REQUIRE_IS_VALID( resource1 ); + + auto resource2 = rm->LoadGeneric( "$(TestAssets)/mock/example.mock", &info, TypeID::get< MockAsset >() ); + REQUIRE_IS_VALID( resource2 ); + + CHECK( resource1.Get() == resource2.Get() ); +} + + +// ================================ // +// Load resource from two threads at the same time using two diferent path aliases. +// Only one resource should be loaded. +TEST_CASE( "GraphicAPI.ResourceManager.PathAliases.Loading.TwoThreadsSameAsset", "[GraphicAPI]" ) +{ + auto rm = CreateResourceManagerWithMocks(); + + MockAssetLoadInfo info; + ThreadsBarrier barrier( 2 ); + + Nullable< ResourcePointer > threadResource; + + std::thread thread( [ & ]() + { + barrier.ArriveAndWait(); + threadResource = rm->LoadGeneric( "$(MocksDir)/example.mock", &info, TypeID::get< MockAsset >() ); + } ); + + // Wait for second thread initialization. + barrier.ArriveAndWait(); + auto resource = rm->LoadGeneric( "$(TestAssets)/mock/example.mock", &info, TypeID::get< MockAsset >() ); + + thread.join(); + + REQUIRE( resource.IsValid() == true ); + REQUIRE( threadResource.IsValid() == true ); + + CHECK( resource.Get() == threadResource.Get() ); +} diff --git a/Tests/TestResourceManager/TestResourceManager/TestResourceManagerAPI.cpp b/Tests/TestResourceManager/TestResourceManager/TestResourceManagerAPI.cpp new file mode 100644 index 0000000..9b98514 --- /dev/null +++ b/Tests/TestResourceManager/TestResourceManager/TestResourceManagerAPI.cpp @@ -0,0 +1,97 @@ +#include "swGraphicAPI/Tests/TestResourceManager/stdafx.h" +#include "swCommonLib/External/Catch/catch.hpp" +/** +@file TestResourceManagerAPI.cpp +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + + +#include "swGraphicAPI/ResourceManager/ResourceManager.h" +#include "swGraphicAPI/ResourceManager/ResourceManagerAPI.h" + +#include "swGraphicAPI/MockAssets/MockAssetCreator.h" +#include "swGraphicAPI/MockAssets/MockAsset.h" +#include "swGraphicAPI/MockAssets/MockAssetLoader.h" + +#include "swGraphicAPI/MockAssets/Utils.h" + + +using namespace sw; + + +// ================================ // +// +struct Struct16Bytes +{ + float x, y, z, w; +}; + + + +// ================================ // +// +TEST_CASE( "GraphicAPI.ResourceManager.API.Buffer.FromStackBuffer", "[GraphicAPI]" ) +{ + auto rm = CreateResourceManagerWithMocks(); + auto api = ResourceManagerAPI( rm.get() ); + + auto buffer = api.CreateConstantsBuffer( "::/Buffer/FromStackBuffer", StackBufferA< Struct16Bytes >() ); + REQUIRE_IS_VALID( buffer ); + + CHECK( buffer.Get()->GetElementSize() == sizeof( Struct16Bytes ) ); + CHECK( buffer.Get()->GetElementCount() == 1 ); +} + +// ================================ // +// +TEST_CASE( "GraphicAPI.ResourceManager.API.Buffer.FromBufferRange.EmptyBufferRange", "[GraphicAPI]" ) +{ + auto rm = CreateResourceManagerWithMocks(); + auto api = ResourceManagerAPI( rm.get() ); + + auto range = BufferRange( nullptr, 0 ); + + auto buffer = api.CreateConstantsBuffer( "::/Buffer/FromBufferRange/EmptyBufferRange/Constants", range ); + REQUIRE( !buffer.IsValid() ); +} + +// ================================ // +// +TEST_CASE( "GraphicAPI.ResourceManager.API.Buffer.FromBufferRange.ElementSize=0", "[GraphicAPI]" ) +{ + auto rm = CreateResourceManagerWithMocks(); + auto api = ResourceManagerAPI( rm.get() ); + + auto data = StackBufferA< Struct16Bytes >(); + + auto buffer = api.CreateVertexBuffer( "::/VertexBuffer/FromBufferRangw/EmptyBufferRange", data.GetView(), 0 ); + REQUIRE( !buffer.IsValid() ); +} + +// ================================ // +// +TEST_CASE( "GraphicAPI.ResourceManager.API.VertexBuffer.FromBufferRange.EmptyBufferRange", "[GraphicAPI]" ) +{ + auto rm = CreateResourceManagerWithMocks(); + auto api = ResourceManagerAPI( rm.get() ); + + auto range = BufferRange( nullptr, 0 ); + + auto buffer = api.CreateVertexBuffer( "::/VertexBuffer/FromBufferRangw/EmptyBufferRange", range, 0 ); + REQUIRE( !buffer.IsValid() ); +} + +// ================================ // +// +TEST_CASE( "GraphicAPI.ResourceManager.API.IndexBuffer.FromBufferRange.EmptyBufferRange", "[GraphicAPI]" ) +{ + auto rm = CreateResourceManagerWithMocks(); + auto api = ResourceManagerAPI( rm.get() ); + + auto data = StackBufferA< Struct16Bytes >(); + + auto buffer = api.CreateVertexBuffer( "::/IndexBuffer/FromBufferRangw/EmptyBufferRange", data.GetView(), 0 ); + REQUIRE( !buffer.IsValid() ); +} + diff --git a/Tests/TestResourceManager/TestResourcePtr.cpp b/Tests/TestResourceManager/TestResourcePtr.cpp new file mode 100644 index 0000000..06c5fe8 --- /dev/null +++ b/Tests/TestResourceManager/TestResourcePtr.cpp @@ -0,0 +1,43 @@ +#include "swGraphicAPI/Tests/TestResourceManager/stdafx.h" +#include "swCommonLib/External/Catch/catch.hpp" +/** +@file TestResourcePtr.cpp +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + + +#include "swGraphicAPI/Resources/ResourcePtr.h" + +#include "swGraphicAPI/MockAssets/Utils.h" + + +using namespace sw; + + + +// ================================ // +// +TEST_CASE( "GraphicAPI.ResourcePtr.Construct.FromPtr", "[GraphicAPI]" ) +{ + auto asset = new MockCompositeAsset( "::TestResourcePtr", {}, {} ); + + uint32 numRefs = 0; + + { + MockCompositeAssetPtr ptr1( asset ); + + CHECK( ptr1->CanDelete( numRefs ) == false ); + CHECK( numRefs == 1 ); + + MockCompositeAssetPtr ptr2( asset ); + + CHECK( ptr1->CanDelete( numRefs ) == false ); + CHECK( numRefs == 2 ); + } + + CHECK( asset->CanDelete( numRefs ) == true ); + CHECK( numRefs == 0 ); +} + + diff --git a/Tests/TestResourceManager/Utils/Tests/TestMockCompositeAsset.cpp b/Tests/TestResourceManager/Utils/Tests/TestMockCompositeAsset.cpp new file mode 100644 index 0000000..888a9bd --- /dev/null +++ b/Tests/TestResourceManager/Utils/Tests/TestMockCompositeAsset.cpp @@ -0,0 +1,85 @@ +#include "swGraphicAPI/Tests/TestResourceManager/stdafx.h" +#include "swCommonLib/External/Catch/catch.hpp" +/** +@file TestMockCompositeAsset.cpp +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + + +#include "swGraphicAPI/ResourceManager/ResourceManager.h" + +#include "swGraphicAPI/MockAssets/Utils.h" + + +using namespace sw; + + +// ================================ // +// Check if MockCompositeAssetLoader creates good assets hierarchy. +TEST_CASE( "GraphicAPI.TestUtils.MockCompositeAsset.Hierarchy", "[GraphicAPI]" ) +{ + auto rm = CreateResourceManagerWithMocks(); + + auto nestedLevel3_1 = MockCompositeAssetLoadInfo::Create( {}, { "../TestAssets/mock/example1.mock", } ); + auto nestedLevel3_2 = MockCompositeAssetLoadInfo::Create( {}, { "../TestAssets/mock/example2.mock", } ); + + auto nestedLevel2_1 = MockCompositeAssetLoadInfo::Create( { nestedLevel3_1, nestedLevel3_2 }, { "../TestAssets/mock/example3.mock", } ); + + auto nestedLevel1_1 = MockCompositeAssetLoadInfo::Create( { nestedLevel2_1, nestedLevel2_1 }, { "../TestAssets/mock/example.mock", } ); + + auto resource = rm->LoadGeneric( "::MockCompositeAsset/Hierarchy", nestedLevel1_1.get(), TypeID::get< MockCompositeAsset >() ); + REQUIRE( resource.IsValid() == true ); + + auto asset = static_cast< MockCompositeAsset* >( resource.Get().Ptr() ); + + auto subassets1 = asset->GetSubAssets(); + REQUIRE( subassets1.size() == 1 ); + CHECK( subassets1[ 0 ]->GetContent() == "Example" ); + CHECK( subassets1[ 0 ]->GetAssetPath() == "../TestAssets/mock/example.mock" ); + + // nestedLevel1_1 + auto composites1 = asset->GetCompositeSubAssets(); + REQUIRE( composites1.size() == 2 ); + CHECK( composites1[ 0 ]->GetAssetPath() == "::MockCompositeAsset/Hierarchy/0" ); // This is how MockCompositeAsset builds paths of nested assets. + CHECK( composites1[ 1 ]->GetAssetPath() == "::MockCompositeAsset/Hierarchy/1" ); + + // nestedLevel2_1 + REQUIRE( composites1[ 0 ]->GetSubAssets().size() == 1 ); + CHECK( composites1[ 0 ]->GetSubAssets()[ 0 ]->GetAssetPath() == "../TestAssets/mock/example3.mock" ); + CHECK( composites1[ 0 ]->GetSubAssets()[ 0 ]->GetContent() == "example3" ); + + REQUIRE( composites1[ 1 ]->GetSubAssets().size() == 1 ); + CHECK( composites1[ 1 ]->GetSubAssets()[ 0 ]->GetAssetPath() == "../TestAssets/mock/example3.mock" ); + CHECK( composites1[ 1 ]->GetSubAssets()[ 0 ]->GetContent() == "example3" ); + + // nestedLevel3_1 and nestedLevel3_2 + auto composites1_1 = composites1[ 0 ]->GetCompositeSubAssets(); + auto composites1_2 = composites1[ 1 ]->GetCompositeSubAssets(); + + REQUIRE( composites1_1.size() == 2 ); + REQUIRE( composites1_2.size() == 2 ); + + CHECK( composites1_1[ 0 ]->GetAssetPath() == "::MockCompositeAsset/Hierarchy/0/0" ); + CHECK( composites1_1[ 1 ]->GetAssetPath() == "::MockCompositeAsset/Hierarchy/0/1" ); + + CHECK( composites1_2[ 0 ]->GetAssetPath() == "::MockCompositeAsset/Hierarchy/1/0" ); + CHECK( composites1_2[ 1 ]->GetAssetPath() == "::MockCompositeAsset/Hierarchy/1/1" ); + + CHECK( composites1_1[ 0 ]->GetCompositeSubAssets().size() == 0 ); + CHECK( composites1_1[ 1 ]->GetCompositeSubAssets().size() == 0 ); + CHECK( composites1_2[ 0 ]->GetCompositeSubAssets().size() == 0 ); + CHECK( composites1_2[ 1 ]->GetCompositeSubAssets().size() == 0 ); + + CHECK( composites1_1[ 0 ]->GetSubAssets().size() == 1 ); + CHECK( composites1_1[ 1 ]->GetSubAssets().size() == 1 ); + CHECK( composites1_2[ 0 ]->GetSubAssets().size() == 1 ); + CHECK( composites1_2[ 1 ]->GetSubAssets().size() == 1 ); + + CHECK( composites1_1[ 0 ]->GetSubAssets()[ 0 ]->GetContent() == "example1" ); + CHECK( composites1_1[ 1 ]->GetSubAssets()[ 0 ]->GetContent() == "example2" ); + CHECK( composites1_2[ 0 ]->GetSubAssets()[ 0 ]->GetContent() == "example1" ); + CHECK( composites1_2[ 1 ]->GetSubAssets()[ 0 ]->GetContent() == "example2" ); +} + + diff --git a/Tests/TestResourceManager/main.cpp b/Tests/TestResourceManager/main.cpp new file mode 100644 index 0000000..d3f9d80 --- /dev/null +++ b/Tests/TestResourceManager/main.cpp @@ -0,0 +1,3 @@ +#define CATCH_CONFIG_MAIN // This tells Catch to provide a main() - only do this in one cpp file +#include "swCommonLib/External/Catch/catch.hpp" + diff --git a/Tests/TestResourceManager/stdafx.cpp b/Tests/TestResourceManager/stdafx.cpp new file mode 100644 index 0000000..d19efe7 --- /dev/null +++ b/Tests/TestResourceManager/stdafx.cpp @@ -0,0 +1,7 @@ +/** +@file stdafx.cpp +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + +#include "swGraphicAPI/Tests/TestResourceManager/stdafx.h" diff --git a/Tests/TestResourceManager/stdafx.h b/Tests/TestResourceManager/stdafx.h new file mode 100644 index 0000000..e623a99 --- /dev/null +++ b/Tests/TestResourceManager/stdafx.h @@ -0,0 +1,25 @@ +/** +@file stdafx.h +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + + +#include "swGraphicAPI/Resources/MeshResources.h" + +#include "swGraphicAPI/ResourceManager/ResourceManager.h" +#include "swGraphicAPI/ResourceManager/ResourceManagerAPI.h" +#include "swGraphicAPI/ResourceManager/AsyncLoad/RMAsyncThread.h" + +#include "swGraphicAPI/ResourceManager/Loaders/ShaderLoader.h" +#include "swGraphicAPI/ResourceManager/Loaders/RenderTargetLoader.h" + +#include "swGraphicAPI/ResourceManager/AssetCreators/Textures/RenderTargetCreator.h" +#include "swGraphicAPI/ResourceManager/AssetCreators/Textures/TextureCreator.h" +#include "swGraphicAPI/ResourceManager/AssetCreators/Buffers/BufferCreator.h" +#include "swGraphicAPI/ResourceManager/AssetCreators/Shaders/ShaderCreator.h" +#include "swGraphicAPI/ResourceManager/AssetCreators/Shaders/LayoutCreator.h" +#include "swGraphicAPI/ResourceManager/AssetCreators/PipelineStates/BlendingStateCreator.h" +#include "swGraphicAPI/ResourceManager/AssetCreators/PipelineStates/DepthStencilStateCreator.h" +#include "swGraphicAPI/ResourceManager/AssetCreators/PipelineStates/RasterizerStateCreator.h" + diff --git a/Tests/TestResources.DX11/GraphicAPI.h b/Tests/TestResources.DX11/GraphicAPI.h deleted file mode 100644 index 5a8145b..0000000 --- a/Tests/TestResources.DX11/GraphicAPI.h +++ /dev/null @@ -1,54 +0,0 @@ -#pragma once - -#include "swGraphicAPI/ResourceManager/ResourceManager.h" -#include "swGraphicAPI/Resources/ResourcesFactory.h" -#include "swGraphicAPI/Rendering/IGraphicAPIInitializer.h" - - - -// ================================ // -// -struct Graphic -{ - IGraphicAPIInitializer* API; - ResourceManager* RM; - -// ================================ // -// - ~Graphic() - { - if( API ) delete API; - if( RM ) delete RM; - - API = nullptr; - RM = nullptr; - } -}; - - -// ================================ // -// -inline Graphic& GetGraphic () -{ - static Graphic graphic; - - if( !graphic.API ) - { - graphic.API = ResourcesFactory::CreateAPIInitializer(); - - GraphicAPIInitData graphicApiData; - graphicApiData.CreateSwapChain = false; // We will create swap chain and render target later with window. - graphicApiData.SingleThreaded = true; - graphicApiData.UseDebugLayer = false; - - auto result = graphic.API->InitAPI( graphicApiData ); - } - - if( !graphic.RM ) - { - graphic.RM = new ResourceManager(); - } - - return graphic; -} - diff --git a/Tests/TestResources.DX11/TestBlendingState.cpp b/Tests/TestResources.DX11/TestBlendingState.cpp index 490b4f0..5a15681 100644 --- a/Tests/TestResources.DX11/TestBlendingState.cpp +++ b/Tests/TestResources.DX11/TestBlendingState.cpp @@ -1,19 +1,25 @@ #include "swCommonLib/External/Catch/catch.hpp" +/** +@file TestBlendingState.cpp +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ -#include "GraphicAPI.h" + +#include "swGraphicAPI/MockAssets/GraphicAPI.h" // ================================ // // -TEST_CASE( "GraphicAPI.Resources.BlendingState.Creation", "[GraphicAPI][Resources]" ) +TEST_CASE( "GraphicAPI.DX11.Resources.BlendingState.Creation", "[GraphicAPI][Resources]" ) { auto& graphic = GetGraphic(); - BlendingInfo blendDesc; + sw::BlendingInfo blendDesc; blendDesc.EnableBlending = true; - auto blendingState = graphic.RM->CreateBlendingState( L"TransparentBlendState", blendDesc ); + auto blendingState = graphic.RMApi.CreateBlendingState( "::TransparentBlendState", blendDesc ); CHECK( blendingState != nullptr ); } diff --git a/Tests/TestResources.DX11/TestCreators/TestBlendingStateCreator.cpp b/Tests/TestResources.DX11/TestCreators/TestBlendingStateCreator.cpp new file mode 100644 index 0000000..d317752 --- /dev/null +++ b/Tests/TestResources.DX11/TestCreators/TestBlendingStateCreator.cpp @@ -0,0 +1,35 @@ +#include "swCommonLib/External/Catch/catch.hpp" + +/** +@file TestBlendingStateCreator.cpp +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + + +#include "swGraphicAPI/ResourceManager/AssetCreators/AssetsFactory.h" + +#include "swGraphicAPI/ResourceManager/AssetCreators/PipelineStates/BlendingStateCreator.h" +#include "swGraphicAPI/Resources/PipelineStates/BlendingState.h" + +#include "swCommonLib/TestUtils/CatchUtils/ExtendedMacros.h" + + + +using namespace sw; + + +// ================================ // +// +TEST_CASE( "GraphicAPI.DX11.BlendingStateCreator.Create", "[GraphicAPI]" ) +{ + AssetsFactory factory; + + BlendingInfo init; + init.EnableBlending = false; + + auto result = factory.CreateAsset( "::/BlendingState/Opaque", TypeID::get< BlendingState >(), std::move( init ) ); + REQUIRE_IS_VALID( result ); + + REQUIRE( result.Get() != nullptr ); +} \ No newline at end of file diff --git a/Tests/TestResources.DX11/TestCreators/TestBufferCreator.cpp b/Tests/TestResources.DX11/TestCreators/TestBufferCreator.cpp new file mode 100644 index 0000000..bc66d08 --- /dev/null +++ b/Tests/TestResources.DX11/TestCreators/TestBufferCreator.cpp @@ -0,0 +1,124 @@ +#include "swCommonLib/External/Catch/catch.hpp" + +/** +@file TestBufferCreator.cpp +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + + +#include "swGraphicAPI/ResourceManager/AssetCreators/AssetsFactory.h" + +#include "swGraphicAPI/ResourceManager/AssetCreators/Buffers/BufferCreator.h" +#include "swGraphicAPI/Resources/Buffers/BufferInitData.h" + +#include "swCommonLib/Common/Buffers/BufferTyped.h" + +#include "swCommonLib/TestUtils/CatchUtils/ExtendedMacros.h" + + +using namespace sw; + + +// ================================ // +// +struct Struct16Bytes +{ + float x, y, z, w; +}; + + +// ================================ // +// +TEST_CASE( "GraphicAPI.DX11.BufferCreator.ConstantBuffer.Create", "[GraphicAPI]" ) +{ + AssetsFactory factory; + + BufferTyped< Struct16Bytes > buffer( 10 ); + + ConstantBufferInitData init; + init.ElementSize = (uint32)buffer.ElementSize(); + init.NumElements = (uint32)buffer.ElementsCount(); + init.Data = buffer.GetRawData(); + + auto result = factory.CreateAsset( "::/BufferFromMemory/Constants", TypeID::get< Buffer >(), std::move( init ) ); + REQUIRE_IS_VALID( result ); + + REQUIRE( result.Get() != nullptr ); + + Buffer* bufferPtr = static_cast< Buffer* >( result.Get() ); + + CHECK( bufferPtr->GetElementSize() == sizeof( Struct16Bytes ) ); + CHECK( bufferPtr->GetElementCount() == 10 ); +} + +// ================================ // +// +TEST_CASE( "GraphicAPI.DX11.BufferCreator.IndexBuffer.Create", "[GraphicAPI]" ) +{ + AssetsFactory factory; + + BufferTyped< Index16 > buffer( 10 ); + + IndexBufferInitData init; + init.ElementSize = (uint32)buffer.ElementSize(); + init.NumElements = (uint32)buffer.ElementsCount(); + init.Data = buffer.GetRawData(); + + auto result = factory.CreateAsset( "::/BufferFromMemory/Index", TypeID::get< Buffer >(), std::move( init ) ); + REQUIRE_IS_VALID( result ); + + REQUIRE( result.Get() != nullptr ); + + Buffer* bufferPtr = static_cast< Buffer* >( result.Get() ); + + CHECK( bufferPtr->GetElementSize() == sizeof( Index16 ) ); + CHECK( bufferPtr->GetElementCount() == 10 ); +} + +// ================================ // +// +TEST_CASE( "GraphicAPI.DX11.BufferCreator.VertexBuffer.Create", "[GraphicAPI]" ) +{ + AssetsFactory factory; + + BufferTyped< Struct16Bytes > buffer( 10 ); + + VertexBufferInitData init; + init.ElementSize = (uint32)buffer.ElementSize(); + init.NumElements = (uint32)buffer.ElementsCount(); + init.Data = buffer.GetRawData(); + + auto result = factory.CreateAsset( "::/BufferFromMemory/Vertex", TypeID::get< Buffer >(), std::move( init ) ); + REQUIRE_IS_VALID( result ); + + REQUIRE( result.Get() != nullptr ); + + Buffer* bufferPtr = static_cast< Buffer* >( result.Get() ); + + CHECK( bufferPtr->GetElementSize() == sizeof( Struct16Bytes ) ); + CHECK( bufferPtr->GetElementCount() == 10 ); +} + +// ================================ // +// +TEST_CASE( "GraphicAPI.DX11.BufferCreator.ConstantBuffer.Create.NullptrInit", "[GraphicAPI]" ) +{ + AssetsFactory factory; + + ConstantBufferInitData init; + init.ElementSize = 16; + init.NumElements = 2; + init.Data = nullptr; + + auto result = factory.CreateAsset( "::/BufferFromMemory/Constants", TypeID::get< Buffer >(), std::move( init ) ); + REQUIRE_IS_VALID( result ); + + REQUIRE( result.Get() != nullptr ); + + Buffer* bufferPtr = static_cast< Buffer* >( result.Get() ); + + CHECK( bufferPtr->GetElementSize() == 16 ); + CHECK( bufferPtr->GetElementCount() == 2 ); +} + diff --git a/Tests/TestResources.DX11/TestCreators/TestDepthStencilStateCreator.cpp b/Tests/TestResources.DX11/TestCreators/TestDepthStencilStateCreator.cpp new file mode 100644 index 0000000..59fbdb1 --- /dev/null +++ b/Tests/TestResources.DX11/TestCreators/TestDepthStencilStateCreator.cpp @@ -0,0 +1,33 @@ +#include "swCommonLib/External/Catch/catch.hpp" + +/** +@file TestDepthStencilStateCreator.cpp +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + + +#include "swGraphicAPI/ResourceManager/AssetCreators/AssetsFactory.h" + +#include "swGraphicAPI/ResourceManager/AssetCreators/PipelineStates/DepthStencilStateCreator.h" +#include "swGraphicAPI/Resources/PipelineStates/DepthStencilState.h" + +#include "swCommonLib/TestUtils/CatchUtils/ExtendedMacros.h" + + + +using namespace sw; + + +// ================================ // +// +TEST_CASE( "GraphicAPI.DX11.DepthStencilStateCreator.Create", "[GraphicAPI]" ) +{ + AssetsFactory factory; + DepthStencilInfo init; + + auto result = factory.CreateAsset( "::/DepthStencilState/Opaque", TypeID::get< DepthStencilState >(), std::move( init ) ); + REQUIRE_IS_VALID( result ); + + REQUIRE( result.Get() != nullptr ); +} \ No newline at end of file diff --git a/Tests/TestResources.DX11/TestCreators/TestLayoutCreator.cpp b/Tests/TestResources.DX11/TestCreators/TestLayoutCreator.cpp new file mode 100644 index 0000000..53e75a6 --- /dev/null +++ b/Tests/TestResources.DX11/TestCreators/TestLayoutCreator.cpp @@ -0,0 +1,120 @@ +#include "swCommonLib/External/Catch/catch.hpp" + +/** +@file TestLayoutCreator.cpp +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + + +#include "swGraphicAPI/ResourceManager/AssetCreators/AssetsFactory.h" + +#include "swGraphicAPI/ResourceManager/AssetCreators/Shaders/LayoutCreator.h" +#include "swGraphicAPI/Resources/Shaders/LayoutInitData.h" + +#include "swCommonLib/TestUtils/CatchUtils/ExtendedMacros.h" + + + +using namespace sw; + + +// ================================ // +// +TEST_CASE( "GraphicAPI.DX11.LayoutCreator.Create.Semantic.Position", "[GraphicAPI]" ) +{ + AssetsFactory factory; + + InputLayoutDescriptor init; + init.AddEntry( AttributeSemantic::Position, ResourceFormat::RESOURCE_FORMAT_R32G32B32_FLOAT ); + + + auto result = factory.CreateAsset( "::/Layout", TypeID::get< ShaderInputLayout >(), std::move( init ) ); + REQUIRE_IS_VALID( result ); + + REQUIRE( result.Get() != nullptr ); +} + +// ================================ // +// +TEST_CASE( "GraphicAPI.DX11.LayoutCreator.Create.Semantic.Blending", "[GraphicAPI]" ) +{ + AssetsFactory factory; + + InputLayoutDescriptor init; + init.AddEntry( AttributeSemantic::Position, ResourceFormat::RESOURCE_FORMAT_R32G32B32_FLOAT ); + init.AddEntry( AttributeSemantic::BlendIndicies, ResourceFormat::RESOURCE_FORMAT_B8G8R8A8_UNORM ); + init.AddEntry( AttributeSemantic::BlendWeights, ResourceFormat::RESOURCE_FORMAT_R32G32B32A32_FLOAT ); + + auto result = factory.CreateAsset( "::/Layout", TypeID::get< ShaderInputLayout >(), std::move( init ) ); + REQUIRE_IS_VALID( result ); + + REQUIRE( result.Get() != nullptr ); +} + +// ================================ // +// +TEST_CASE( "GraphicAPI.DX11.LayoutCreator.Create.Semantic.Color", "[GraphicAPI]" ) +{ + AssetsFactory factory; + + InputLayoutDescriptor init; + init.AddEntry( AttributeSemantic::Position, ResourceFormat::RESOURCE_FORMAT_R32G32B32_FLOAT ); + init.AddEntry( AttributeSemantic::Color, ResourceFormat::RESOURCE_FORMAT_R32G32B32A32_FLOAT ); + + auto result = factory.CreateAsset( "::/Layout", TypeID::get< ShaderInputLayout >(), std::move( init ) ); + REQUIRE_IS_VALID( result ); + + REQUIRE( result.Get() != nullptr ); +} + +// ================================ // +// +TEST_CASE( "GraphicAPI.DX11.LayoutCreator.Create.Semantic.Coordinates", "[GraphicAPI]" ) +{ + AssetsFactory factory; + + InputLayoutDescriptor init; + init.AddEntry( AttributeSemantic::Position, ResourceFormat::RESOURCE_FORMAT_R32G32B32_FLOAT ); + init.AddEntry( AttributeSemantic::Texcoord, ResourceFormat::RESOURCE_FORMAT_R32G32_FLOAT ); + + auto result = factory.CreateAsset( "::/Layout", TypeID::get< ShaderInputLayout >(), std::move( init ) ); + REQUIRE_IS_VALID( result ); + + REQUIRE( result.Get() != nullptr ); +} + +// ================================ // +// +TEST_CASE( "GraphicAPI.DX11.LayoutCreator.Create.Semantic.NormalBinormalTangent", "[GraphicAPI]" ) +{ + AssetsFactory factory; + + InputLayoutDescriptor init; + init.AddEntry( AttributeSemantic::Position, ResourceFormat::RESOURCE_FORMAT_R32G32B32_FLOAT ); + init.AddEntry( AttributeSemantic::Normal, ResourceFormat::RESOURCE_FORMAT_R32G32B32_FLOAT ); + init.AddEntry( AttributeSemantic::Tangent, ResourceFormat::RESOURCE_FORMAT_R32G32B32_FLOAT ); + init.AddEntry( AttributeSemantic::Binormal, ResourceFormat::RESOURCE_FORMAT_R32G32B32_FLOAT ); + + auto result = factory.CreateAsset( "::/Layout", TypeID::get< ShaderInputLayout >(), std::move( init ) ); + REQUIRE_IS_VALID( result ); + + REQUIRE( result.Get() != nullptr ); +} + +// ================================ // +// +TEST_CASE( "GraphicAPI.DX11.LayoutCreator.Create.Semantic.PointSize", "[GraphicAPI]" ) +{ + AssetsFactory factory; + + InputLayoutDescriptor init; + init.AddEntry( AttributeSemantic::Position, ResourceFormat::RESOURCE_FORMAT_R32G32B32_FLOAT ); + init.AddEntry( AttributeSemantic::PointSize, ResourceFormat::RESOURCE_FORMAT_R32_FLOAT ); + + auto result = factory.CreateAsset( "::/Layout", TypeID::get< ShaderInputLayout >(), std::move( init ) ); + REQUIRE_IS_VALID( result ); + + REQUIRE( result.Get() != nullptr ); +} + diff --git a/Tests/TestResources.DX11/TestCreators/TestRasterizerStateCreator.cpp b/Tests/TestResources.DX11/TestCreators/TestRasterizerStateCreator.cpp new file mode 100644 index 0000000..84f21ab --- /dev/null +++ b/Tests/TestResources.DX11/TestCreators/TestRasterizerStateCreator.cpp @@ -0,0 +1,32 @@ +#include "swCommonLib/External/Catch/catch.hpp" + +/** +@file TestRasterizerStateCreator.cpp +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + + +#include "swGraphicAPI/ResourceManager/AssetCreators/AssetsFactory.h" + +#include "swGraphicAPI/ResourceManager/AssetCreators/PipelineStates/RasterizerStateCreator.h" +#include "swGraphicAPI/Resources/PipelineStates/RasterizerState.h" + +#include "swCommonLib/TestUtils/CatchUtils/ExtendedMacros.h" + + +using namespace sw; + + +// ================================ // +// +TEST_CASE( "GraphicAPI.DX11.RasterizerStateCreator.Create", "[GraphicAPI]" ) +{ + AssetsFactory factory; + RasterizerStateInfo init; + + auto result = factory.CreateAsset( "::/RasterizerState/Default", TypeID::get< RasterizerState >(), std::move( init ) ); + REQUIRE_IS_VALID( result ); + + REQUIRE( result.Get() != nullptr ); +} \ No newline at end of file diff --git a/Tests/TestResources.DX11/TestCreators/TestRenderTargetCreator.cpp b/Tests/TestResources.DX11/TestCreators/TestRenderTargetCreator.cpp new file mode 100644 index 0000000..ec175ed --- /dev/null +++ b/Tests/TestResources.DX11/TestCreators/TestRenderTargetCreator.cpp @@ -0,0 +1,72 @@ +#include "swCommonLib/External/Catch/catch.hpp" + +/** +@file TestTextureCreator.cpp +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + + +#include "swGraphicAPI/ResourceManager/AssetCreators/AssetsFactory.h" + +#include "swGraphicAPI/ResourceManager/AssetCreators/Textures/RenderTargetCreator.h" +#include "swGraphicAPI/Resources/Textures/RenderTarget.h" + +#include "swGraphicAPI/MockAssets/Utils.h" +#include "swCommonLib/TestUtils/CatchUtils/ExtendedMacros.h" + + +using namespace sw; + + + +// ================================ // +// +TEST_CASE( "GraphicAPI.DX11.RenderTargetCreator.Create.ColorDepth", "[GraphicAPI]" ) +{ + AssetsFactory factory; + + RenderTargetDescriptor init; + init.Height = 8; + init.Width = 8; + init.DepthStencilFormat = DepthStencilFormat::DEPTH_STENCIL_FORMAT_D16_UNORM; + init.ColorBuffFormat = ResourceFormat::RESOURCE_FORMAT_B8G8R8A8_UNORM; + + + auto result = factory.CreateAsset( "::/RenderTarget/ColorDepth", TypeID::get< RenderTarget >(), std::move( init ) ); + REQUIRE_IS_VALID( result ); + + REQUIRE( result.Get() != nullptr ); + + RenderTarget* rt = static_cast< RenderTarget* >( result.Get() ); + CHECK( rt->GetColorBuffer() != nullptr ); + CHECK( rt->GetDepthBuffer() != nullptr ); + CHECK( rt->GetStencilBuffer() == nullptr ); +} + + +// ================================ // +// +TEST_CASE( "GraphicAPI.DX11.RenderTargetCreator.Create.ColorDepthStencil", "[GraphicAPI]" ) +{ + AssetsFactory factory; + + RenderTargetDescriptor init; + init.Height = 8; + init.Width = 8; + init.DepthStencilFormat = DepthStencilFormat::DEPTH_STENCIL_FORMAT_D24_UNORM_S8_UINT; + init.ColorBuffFormat = ResourceFormat::RESOURCE_FORMAT_B8G8R8A8_UNORM; + + + auto result = factory.CreateAsset( "::/RenderTarget/ColorDepthStencil", TypeID::get< RenderTarget >(), std::move( init ) ); + REQUIRE_IS_VALID( result ); + + REQUIRE( result.Get() != nullptr ); + + RenderTarget* rt = static_cast< RenderTarget* >( result.Get() ); + CHECK( rt->GetColorBuffer() != nullptr ); + CHECK( rt->GetDepthBuffer() != nullptr ); + CHECK( rt->GetStencilBuffer() != nullptr ); +} + + diff --git a/Tests/TestResources.DX11/TestCreators/TestShaderCreator.cpp b/Tests/TestResources.DX11/TestCreators/TestShaderCreator.cpp new file mode 100644 index 0000000..f1e2ee2 --- /dev/null +++ b/Tests/TestResources.DX11/TestCreators/TestShaderCreator.cpp @@ -0,0 +1,122 @@ +#include "swCommonLib/External/Catch/catch.hpp" + +/** +@file TestShaderCreator.cpp +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + + +#include "swGraphicAPI/ResourceManager/AssetCreators/AssetsFactory.h" + +#include "swGraphicAPI/ResourceManager/AssetCreators/Shaders/ShaderCreator.h" +#include "swGraphicAPI/Resources/Shaders/ShaderInitData.h" + +#include "swCommonLib/System/File.h" +#include "swCommonLib/TestUtils/CatchUtils/ExtendedMacros.h" + + +using namespace sw; + + +// ================================ // +// +TEST_CASE( "GraphicAPI.DX11.ShaderCreator.VertexShader.Create", "[GraphicAPI]" ) +{ + AssetsFactory factory; + + ShaderInitData init( ShaderType::VertexShader ); + + auto result = factory.CreateAsset( "../TestAssets/shaders/hlsl/MinimalShader.vsh", TypeID::get< VertexShader >(), std::move( init ) ); + REQUIRE_IS_VALID( result ); + + CHECK( result.Get() != nullptr ); +} + +// ================================ // +// Not compiling shader creation should return error message. +TEST_CASE( "GraphicAPI.DX11.ShaderCreator.VertexShader.Create.CompilationFailed", "[GraphicAPI]" ) +{ + AssetsFactory factory; + + ShaderInitData init( ShaderType::VertexShader ); + + auto result = factory.CreateAsset( "../TestAssets/shaders/hlsl/NotCompiling.vsh", TypeID::get< VertexShader >(), std::move( init ) ); + + REQUIRE( result.IsValid() == false ); + CHECK( result.GetError() != nullptr ); +} + +// ================================ // +// +TEST_CASE( "GraphicAPI.DX11.ShaderCreator.PixelShader.Create", "[GraphicAPI]" ) +{ + AssetsFactory factory; + + ShaderInitData init( ShaderType::PixelShader ); + + auto result = factory.CreateAsset( "../TestAssets/shaders/hlsl/MinimalShader.psh", TypeID::get< PixelShader >(), std::move( init ) ); + REQUIRE_IS_VALID( result ); + + CHECK( result.Get() != nullptr ); +} + +// ================================ // +// Not compiling shader creation should return error message. +TEST_CASE( "GraphicAPI.DX11.ShaderCreator.PixelShader.Create.CompilationFailed", "[GraphicAPI]" ) +{ + AssetsFactory factory; + + ShaderInitData init( ShaderType::PixelShader ); + + auto result = factory.CreateAsset( "../TestAssets/shaders/hlsl/NotCompiling.psh", TypeID::get< PixelShader >(), std::move( init ) ); + + REQUIRE( result.IsValid() == false ); + CHECK( result.GetError() != nullptr ); +} + +// ================================ // +// +TEST_CASE( "GraphicAPI.DX11.ShaderCreator.ComputeShader.Create", "[GraphicAPI]" ) +{ + AssetsFactory factory; + + ShaderInitData init( ShaderType::ComputeShader ); + + auto result = factory.CreateAsset( "../TestAssets/shaders/hlsl/MinimalShader.csh", TypeID::get< ComputeShader >(), std::move( init ) ); + REQUIRE_IS_VALID( result ); + + CHECK( result.Get() != nullptr ); +} + + +// ================================ // +// Not compiling shader creation should return error message. +TEST_CASE( "GraphicAPI.DX11.ShaderCreator.ComputeShader.Create.CompilationFailed", "[GraphicAPI]" ) +{ + AssetsFactory factory; + + ShaderInitData init( ShaderType::ComputeShader ); + + auto result = factory.CreateAsset( "../TestAssets/shaders/hlsl/NotCompiling.csh", TypeID::get< ComputeShader >(), std::move( init ) ); + + REQUIRE( result.IsValid() == false ); + CHECK( result.GetError() != nullptr ); +} + +// ================================ // +// Checks shader generation from ShaderCodeInitData. +// This creates shader from source code in string. Tested only for one shader type. +// Rest left for intefrations tests of ShaderLoader. +TEST_CASE( "GraphicAPI.DX11.ShaderCreator.ComputeShader.Create.FromCode", "[GraphicAPI]" ) +{ + AssetsFactory factory; + + ShaderCodeInitData init( ShaderType::VertexShader ); + init.SourceCode = filesystem::File::Load( "../TestAssets/shaders/hlsl/MinimalShader.vsh" ); + + auto result = factory.CreateAsset( "../TestAssets/shaders/hlsl/MinimalShader.vsh", TypeID::get< VertexShader >(), std::move( init ) ); + REQUIRE_IS_VALID( result ); + + CHECK( result.Get() != nullptr ); +} diff --git a/Tests/TestResources.DX11/TestCreators/TestTextureCreator.cpp b/Tests/TestResources.DX11/TestCreators/TestTextureCreator.cpp new file mode 100644 index 0000000..159b217 --- /dev/null +++ b/Tests/TestResources.DX11/TestCreators/TestTextureCreator.cpp @@ -0,0 +1,81 @@ +#include "swCommonLib/External/Catch/catch.hpp" + +/** +@file TestTextureCreator.cpp +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + + +#include "swGraphicAPI/ResourceManager/AssetCreators/AssetsFactory.h" + +#include "swGraphicAPI/ResourceManager/AssetCreators/Textures/TextureCreator.h" +#include "swGraphicAPI/Resources/Textures/TextureInitData.h" + +#include "swGraphicAPI/ImageGenerators/CheckerboardGenerator.h" + +#include "swCommonLib/Common/Buffers/BufferTyped.h" + +#include "swCommonLib/TestUtils/CatchUtils/ExtendedMacros.h" + +using namespace sw; + + + + + +// ================================ // +// +TEST_CASE( "GraphicAPI.DX11.TextureCreator.Create.GenerateMipmaps", "[GraphicAPI]" ) +{ + AssetsFactory factory; + + CheckerboardGenerator checker( 8, 8 ); + auto buffer = checker.Generate(); + + TextureInitData init( std::move( buffer ) ); + init.Height = 8; + init.Width = 8; + init.MipMaps.GenerateMipMaps = true; + init.MipMaps.Filter = MipMapFilter::Box; + init.Format = ResourceFormat::RESOURCE_FORMAT_R8G8B8A8_UNORM; + + auto result = factory.CreateAsset( "::/Texture/Checkerboard/Mipmaps", TypeID::get< Texture >(), std::move( init ) ); + REQUIRE_IS_VALID( result ); + + REQUIRE( result.Get() != nullptr ); + + Texture* textureRes = static_cast< Texture* >( result.Get() ); + + CHECK( textureRes->GetDescriptor().MipMapLevels == 4 ); + CHECK( textureRes->GetDescriptor().Width == 8 ); + CHECK( textureRes->GetDescriptor().Height == 8 ); +} + +// ================================ // +// +TEST_CASE( "GraphicAPI.DX11.TextureCreator.Create.NoMipmaps", "[GraphicAPI]" ) +{ + AssetsFactory factory; + + CheckerboardGenerator checker( 8, 8 ); + auto buffer = checker.Generate(); + + TextureInitData init( std::move( buffer ) ); + init.Height = 8; + init.Width = 8; + init.MipMaps.GenerateMipMaps = false; + init.Format = ResourceFormat::RESOURCE_FORMAT_R8G8B8A8_UNORM; + + auto result = factory.CreateAsset( "::/Texture/Checkerboard/NoMipmaps", TypeID::get< Texture >(), std::move( init ) ); + REQUIRE_IS_VALID( result ); + + REQUIRE( result.Get() != nullptr ); + + Texture* textureRes = static_cast< Texture* >( result.Get() ); + + CHECK( textureRes->GetDescriptor().MipMapLevels == 1 ); + CHECK( textureRes->GetDescriptor().Width == 8 ); + CHECK( textureRes->GetDescriptor().Height == 8 ); +} + diff --git a/Tests/TestResources.DX11/TestLoaders/TestRenderTargetLoader.cpp b/Tests/TestResources.DX11/TestLoaders/TestRenderTargetLoader.cpp new file mode 100644 index 0000000..d401fc0 --- /dev/null +++ b/Tests/TestResources.DX11/TestLoaders/TestRenderTargetLoader.cpp @@ -0,0 +1,65 @@ +#include "swCommonLib/External/Catch/catch.hpp" +/** +@file TestRenderTargetLoader.cpp +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + +#include "swGraphicAPI/ResourceManager/Loaders/RenderTargetLoader.h" + +#include "swGraphicAPI/MockAssets/GraphicAPI.h" +#include "swCommonLib/TestUtils/CatchUtils/ExtendedMacros.h" + + +using namespace sw; + + + +// ================================ // +// Checks if RenderTargetLoader adds all textures to ResoruceManager correctly. +TEST_CASE( "GraphicAPI.DX11.RenderTargetLoader.Create.ColorDepthStencil", "[GraphicAPI]" ) +{ + auto rm = CreateResourceManagerWithDefaults(); + + RenderTargetLoadInfo init; + init.Height = 8; + init.Width = 8; + init.DepthStencilFormat = DepthStencilFormat::DEPTH_STENCIL_FORMAT_D24_UNORM_S8_UINT; + init.ColorBuffFormat = ResourceFormat::RESOURCE_FORMAT_B8G8R8A8_UNORM; + + auto result = rm->LoadGeneric( "::/ColorDepthStencilRT", &init, TypeID::get< RenderTarget >() ); + REQUIRE_IS_VALID( result ); + + auto loadedRT = result.Get(); + + auto rt = rm->Get< RenderTarget >( "::/ColorDepthStencilRT" ); + auto colorTex = rm->Get< Texture >( "::/ColorDepthStencilRT/color" ); + auto depthTex = rm->Get< Texture >( "::/ColorDepthStencilRT/depth" ); + auto stencilTex = rm->Get< Texture >( "::/ColorDepthStencilRT/stencil" ); + + CHECK( rt != nullptr ); + CHECK( rt == loadedRT ); + + CHECK( colorTex == rt->GetColorBuffer() ); + CHECK( depthTex == rt->GetDepthBuffer() ); + CHECK( stencilTex == rt->GetStencilBuffer() ); +} + +// ================================ // +// Checks if RenderTargetLoader forwards errors. +TEST_CASE( "GraphicAPI.DX11.RenderTargetLoader.Create.InvalidRT", "[GraphicAPI]" ) +{ + auto rm = CreateResourceManagerWithDefaults(); + + RenderTargetLoadInfo init; + init.Height = 0; + init.Width = 0; + init.DepthStencilFormat = DepthStencilFormat::DEPTH_STENCIL_FORMAT_D24_UNORM_S8_UINT; + init.ColorBuffFormat = ResourceFormat::RESOURCE_FORMAT_B8G8R8A8_UNORM; + + auto result = rm->LoadGeneric( "::/ColorDepthStencilRT", &init, TypeID::get< RenderTarget >() ); + REQUIRE( !result.IsValid() ); + + CHECK( result.GetError() != nullptr ); +} + diff --git a/Tests/TestResources.DX11/TestLoaders/TestShaderLoader.cpp b/Tests/TestResources.DX11/TestLoaders/TestShaderLoader.cpp new file mode 100644 index 0000000..e1d2b47 --- /dev/null +++ b/Tests/TestResources.DX11/TestLoaders/TestShaderLoader.cpp @@ -0,0 +1,65 @@ +#include "swCommonLib/External/Catch/catch.hpp" +/** +@file TestShaderLoader.cpp +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + +#include "swGraphicAPI/Resources/Shaders/Exceptions/CompilationException.h" + +#include "swGraphicAPI/MockAssets/GraphicAPI.h" + + +using namespace sw; + + + +// ================================ // +// +TEST_CASE( "GraphicAPI.DX11.ShaderLoader.Load.VertexShader", "[GraphicAPI]" ) +{ + auto rm = CreateResourceManagerWithDefaults(); + + auto resource = rm->LoadGeneric( "../TestAssets/shaders/hlsl/MinimalShader.vsh::main", nullptr, TypeID::get< VertexShader >() ); + REQUIRE( resource.IsValid() == true ); + + CHECK( resource.Get() != nullptr ); +} + +// ================================ // +// +TEST_CASE( "GraphicAPI.DX11.ShaderLoader.Load.PixelShader", "[GraphicAPI]" ) +{ + auto rm = CreateResourceManagerWithDefaults(); + + auto resource = rm->LoadGeneric( "../TestAssets/shaders/hlsl/MinimalShader.psh::main", nullptr, TypeID::get< PixelShader >() ); + REQUIRE( resource.IsValid() == true ); + + CHECK( resource.Get() != nullptr ); +} + +// ================================ // +// +TEST_CASE( "GraphicAPI.DX11.ShaderLoader.Load.ComputeShader", "[GraphicAPI]" ) +{ + auto rm = CreateResourceManagerWithDefaults(); + + auto resource = rm->LoadGeneric( "../TestAssets/shaders/hlsl/MinimalShader.csh::main", nullptr, TypeID::get< ComputeShader >() ); + REQUIRE( resource.IsValid() == true ); + + CHECK( resource.Get() != nullptr ); +} + +// ================================ // +// Loader should forward compilation errors from shaders. +TEST_CASE( "GraphicAPI.DX11.ShaderLoader.Load.VertexShader.CompilationFailed", "[GraphicAPI]" ) +{ + auto rm = CreateResourceManagerWithDefaults(); + + auto resource = rm->LoadGeneric( "../TestAssets/shaders/hlsl/NotCompiling.vsh::main", nullptr, TypeID::get< VertexShader >() ); + REQUIRE( resource.IsValid() == false ); + + CHECK( resource.GetError() != nullptr ); + CHECK( resource.GetError()->get_type() == TypeID::get< CompilationException >() ); +} + diff --git a/Tests/TestResources.DX11/main.cpp b/Tests/TestResources.DX11/main.cpp index 34f9cea..9f31869 100644 --- a/Tests/TestResources.DX11/main.cpp +++ b/Tests/TestResources.DX11/main.cpp @@ -1,2 +1,6 @@ +#include "swGraphicAPI/MockAssets/GraphicAPI.h" + +Graphic& graphic = GetGraphic(); + #define CATCH_CONFIG_MAIN // This tells Catch to provide a main() - only do this in one cpp file #include "swCommonLib/External/Catch/catch.hpp" diff --git a/Tests/TestSoilTextureLoader.DX11/TestFilesLoading.cpp b/Tests/TestSoilTextureLoader.DX11/TestFilesLoading.cpp new file mode 100644 index 0000000..2af0ab8 --- /dev/null +++ b/Tests/TestSoilTextureLoader.DX11/TestFilesLoading.cpp @@ -0,0 +1,104 @@ +#include "swCommonLib/External/Catch/catch.hpp" +/** +@file TestFilesLoading.cpp +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + + +#include "swGraphicAPI/ResourceManager/ResourceManager.h" +#include "swGraphicAPI/ResourceManager/Loaders/TextureLoadInfo.h" + +#include "swGraphicAPI/MockAssets/GraphicAPI.h" + +#include "swCommonLib/TestUtils/CatchUtils/ExtendedMacros.h" + + +using namespace sw; + + +// ================================ // +// +TEST_CASE( "GraphicAPI.DX11.SoilTextureLoader.Load.png", "[GraphicAPI][SoilTextureLoader]" ) +{ + auto rm = CreateRMWithDefaultsSoil(); + + TextureLoadInfo loadInfo; + + auto resource = rm->LoadGeneric( "../TestAssets/texture/random-pixels.png", &loadInfo, TypeID::get< Texture >() ); + REQUIRE_IS_VALID( resource ); + + TexturePtr texture = static_cast< Texture* >( resource.Get().Ptr() ); + auto desc = texture->GetDescriptor(); + + CHECK( desc.Height == 4 ); + CHECK( desc.Width == 4 ); + + CHECK( desc.Format == ResourceFormat::RESOURCE_FORMAT_R8G8B8A8_UNORM ); +} + +// ================================ // +// +TEST_CASE( "GraphicAPI.DX11.SoilTextureLoader.Load.jpg", "[GraphicAPI][SoilTextureLoader]" ) +{ + auto rm = CreateRMWithDefaultsSoil(); + + TextureLoadInfo loadInfo; + + auto resource = rm->LoadGeneric( "../TestAssets/texture/random-pixels.jpg", &loadInfo, TypeID::get< Texture >() ); + REQUIRE_IS_VALID( resource ); + + TexturePtr texture = static_cast< Texture* >( resource.Get().Ptr() ); + auto desc = texture->GetDescriptor(); + + CHECK( desc.Height == 4 ); + CHECK( desc.Width == 4 ); + + CHECK( desc.Format == ResourceFormat::RESOURCE_FORMAT_R8G8B8A8_UNORM ); +} + +// ================================ // +// +TEST_CASE( "GraphicAPI.DX11.SoilTextureLoader.Load.bmp", "[GraphicAPI][SoilTextureLoader]" ) +{ + auto rm = CreateRMWithDefaultsSoil(); + + TextureLoadInfo loadInfo; + + auto resource = rm->LoadGeneric( "../TestAssets/texture/random-pixels.bmp", &loadInfo, TypeID::get< Texture >() ); + REQUIRE_IS_VALID( resource ); + + TexturePtr texture = static_cast< Texture* >( resource.Get().Ptr() ); + auto desc = texture->GetDescriptor(); + + CHECK( desc.Height == 4 ); + CHECK( desc.Width == 4 ); + + CHECK( desc.Format == ResourceFormat::RESOURCE_FORMAT_R8G8B8A8_UNORM ); +} + +// ================================ // +// Loading bigger file often shows segmentation fault problems. +TEST_CASE( "GraphicAPI.DX11.SoilTextureLoader.Load.large-png", "[GraphicAPI][SoilTextureLoader]" ) +{ + auto rm = CreateRMWithDefaultsSoil(); + + TextureLoadInfo loadInfo; + + auto resource = rm->LoadGeneric( "../TestAssets/texture/big-lightweight.png", &loadInfo, TypeID::get< Texture >() ); + REQUIRE_IS_VALID( resource ); + + TexturePtr texture = static_cast< Texture* >( resource.Get().Ptr() ); + auto desc = texture->GetDescriptor(); + + CHECK( desc.Height == 2048 ); + CHECK( desc.Width == 2048 ); + + CHECK( desc.Format == ResourceFormat::RESOURCE_FORMAT_R8G8B8A8_UNORM ); +} + + + + + + diff --git a/Tests/TestSoilTextureLoader.DX11/TestMipMapGeneration.cpp b/Tests/TestSoilTextureLoader.DX11/TestMipMapGeneration.cpp new file mode 100644 index 0000000..9caac4b --- /dev/null +++ b/Tests/TestSoilTextureLoader.DX11/TestMipMapGeneration.cpp @@ -0,0 +1,45 @@ +#include "swCommonLib/External/Catch/catch.hpp" +/** +@file TestMipMapsGeneration.cpp +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + + +#include "swGraphicAPI/ResourceManager/ResourceManager.h" +#include "swGraphicAPI/ResourceManager/Loaders/TextureLoadInfo.h" + +#include "swGraphicAPI/MockAssets/GraphicAPI.h" + +#include "swCommonLib/TestUtils/CatchUtils/ExtendedMacros.h" + + +using namespace sw; + + + + +// ================================ // +// +TEST_CASE( "GraphicAPI.DX11.SoilTextureLoader.Load.GenerateMipMaps", "[GraphicAPI][SoilTextureLoader]" ) +{ + auto rm = CreateRMWithDefaultsSoil(); + + TextureLoadInfo loadInfo; + loadInfo.MipMaps.GenerateMipMaps = true; + loadInfo.MipMaps.Filter = MipMapFilter::Box; + + auto resource = rm->LoadGeneric( "../TestAssets/texture/random-pixels.png", &loadInfo, TypeID::get< Texture >() ); + REQUIRE_IS_VALID( resource ); + + TexturePtr texture = static_cast< Texture* >( resource.Get().Ptr() ); + auto desc = texture->GetDescriptor(); + + CHECK( desc.Height == 4 ); + CHECK( desc.Width == 4 ); + + CHECK( desc.GenerateMipMaps == true ); + CHECK( desc.MipMapLevels == 3 ); +} + + diff --git a/Tests/TestSoilTextureLoader.DX11/main.cpp b/Tests/TestSoilTextureLoader.DX11/main.cpp new file mode 100644 index 0000000..087f4d3 --- /dev/null +++ b/Tests/TestSoilTextureLoader.DX11/main.cpp @@ -0,0 +1,7 @@ +#include "swGraphicAPI/MockAssets/GraphicAPI.h" + +Graphic& graphic = GetGraphic(); + +#define CATCH_CONFIG_MAIN // This tells Catch to provide a main() - only do this in one cpp file +#include "swCommonLib/External/Catch/catch.hpp" + diff --git a/Tests/TestSoilTextureLoader/TestTextureLoading.cpp b/Tests/TestSoilTextureLoader/TestTextureLoading.cpp new file mode 100644 index 0000000..3c21e90 --- /dev/null +++ b/Tests/TestSoilTextureLoader/TestTextureLoading.cpp @@ -0,0 +1,78 @@ +#include "swCommonLib/External/Catch/catch.hpp" +/** +@file TestTextureLoading.cpp +@author nieznanysprawiciel +@copyright File is part of Sleeping Wombat Libraries. +*/ + + +#include "swGraphicAPI/ResourceManager/ResourceManager.h" +#include "swGraphicAPI/ResourceManager/Loaders/TextureLoadInfo.h" +#include "swGraphicAPI/ResourceManager/Exceptions/LoaderException.h" + +#include "swGraphicAPI/MockAssets/Utils.h" +#include "swCommonLib/TestUtils/CatchUtils/ExtendedMacros.h" + +#include "swCommonLib/Common/Exceptions/Common/FileNotFoundException.h" + + +using namespace sw; + + +// ================================ // +// +TEST_CASE( "GraphicAPI.SoilTextureLoader.FileDoesntExists", "[GraphicAPI][SoilTextureLoader]" ) +{ + auto rm = CreateRMWithDefaultsMocksSoil(); + + TextureLoadInfo loadInfo; + + auto resource = rm->LoadGeneric( "../TestAssets/texture/NotExisting.png", &loadInfo, TypeID::get< Texture >() ); + REQUIRE( resource.IsValid() == false ); + + CHECK( resource.GetError() != nullptr ); + CHECK( resource.GetError()->get_type() == TypeID::get< FileNotFoundException >() ); +} + +// ================================ // +// +TEST_CASE( "GraphicAPI.DX11.SoilTextureLoader.Load.png", "[GraphicAPI][SoilTextureLoader]" ) +{ + auto rm = CreateRMWithDefaultsMocksSoil(); + + TextureLoadInfo loadInfo; + + auto resource = rm->LoadGeneric( "../TestAssets/texture/random-pixels.png", &loadInfo, TypeID::get< Texture >() ); + REQUIRE_IS_VALID( resource ); + + TexturePtr texture = static_cast< Texture* >( resource.Get().Ptr() ); + auto desc = texture->GetDescriptor(); + + CHECK( desc.Height == 4 ); + CHECK( desc.Width == 4 ); + + CHECK( desc.Format == ResourceFormat::RESOURCE_FORMAT_R8G8B8A8_UNORM ); +} + + +// ================================ // +// Forcing format is not supported. +TEST_CASE( "GraphicAPI.DX11.SoilTextureLoader.Load.ForceFormat", "[GraphicAPI][SoilTextureLoader]" ) +{ + auto rm = CreateRMWithDefaultsMocksSoil(); + + TextureLoadInfo loadInfo; + loadInfo.Processing.ForceFormat = true; + loadInfo.Processing.TargetFormat = ResourceFormat::RESOURCE_FORMAT_R8G8B8A8_UNORM; + + auto resource = rm->LoadGeneric( "../TestAssets/texture/random-pixels.png", &loadInfo, TypeID::get< Texture >() ); + REQUIRE( resource.IsValid() == false ); + + CHECK( resource.GetError() != nullptr ); + CHECK( resource.GetError()->get_type() == TypeID::get< LoaderException >() ); +} + + + + + diff --git a/Tests/TestSoilTextureLoader/main.cpp b/Tests/TestSoilTextureLoader/main.cpp new file mode 100644 index 0000000..d3f9d80 --- /dev/null +++ b/Tests/TestSoilTextureLoader/main.cpp @@ -0,0 +1,3 @@ +#define CATCH_CONFIG_MAIN // This tells Catch to provide a main() - only do this in one cpp file +#include "swCommonLib/External/Catch/catch.hpp" +