From d2faa6042df05995567d0a3e391e55f7c2c4be78 Mon Sep 17 00:00:00 2001 From: Jens Behley Date: Tue, 27 Mar 2018 10:35:53 +0200 Subject: [PATCH 01/31] added .vscode --- .gitignore | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index fd1359f..45b15fb 100644 --- a/.gitignore +++ b/.gitignore @@ -44,4 +44,6 @@ debug/ *.out *.app -./*.txt \ No newline at end of file +./*.txt + +.vscode \ No newline at end of file From 67dd6683f27d8b1be31a065b83b545d0e61a54b8 Mon Sep 17 00:00:00 2001 From: Jens Behley Date: Tue, 27 Mar 2018 10:37:11 +0200 Subject: [PATCH 02/31] clang format that somehow reproduces the style from VS --- .clang-format | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 .clang-format diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..488cc04 --- /dev/null +++ b/.clang-format @@ -0,0 +1,9 @@ +IndentWidth: 4 +BreakBeforeBraces: Allman +AllowShortIfStatementsOnASingleLine: true +AllowShortBlocksOnASingleLine: true +AllowShortFunctionsOnASingleLine : All +IndentCaseLabels: false +ColumnLimit: 0 +NamespaceIndentation: All +PointerAlignment: Left \ No newline at end of file From 04747b30495db10aa5a40f1c983ec3e3301364f1 Mon Sep 17 00:00:00 2001 From: Jens Behley Date: Tue, 27 Mar 2018 10:38:34 +0200 Subject: [PATCH 03/31] Fix for case sensitive filesystems: Cell.h -> cell.h --- demo/program.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/demo/program.cpp b/demo/program.cpp index 95276ca..abde6c6 100644 --- a/demo/program.cpp +++ b/demo/program.cpp @@ -2,7 +2,7 @@ #include #include -#include +#include #include #include "scenes/pbr_test.h" From 25d2b37ac937c7d9cac1cf8f32cce28c6e7248e0 Mon Sep 17 00:00:00 2001 From: Jens Behley Date: Tue, 27 Mar 2018 10:39:34 +0200 Subject: [PATCH 04/31] build with Cmake. --- CMakeLists.txt | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..df67638 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,68 @@ +cmake_minimum_required(VERSION 3.1) +project(cell) + + +# find_package() + +set (CMAKE_CXX_STANDARD 11) + +include_directories(.) + +add_library(cell + cell/camera/camera_frustum.cpp + cell/camera/camera.cpp + cell/camera/fly_camera.cpp + cell/imgui/imgui_demo.cpp + cell/imgui/imgui_draw.cpp + cell/imgui/imgui.cpp + cell/mesh/circle.cpp + cell/mesh/cube.cpp + cell/mesh/mesh.cpp + cell/mesh/plane.cpp + cell/mesh/quad.cpp + cell/mesh/sphere.cpp + cell/mesh/torus.cpp + cell/renderer/command_buffer.cpp + cell/renderer/gl_cache.cpp + cell/renderer/MaterialLibrary.cpp + cell/renderer/pbr_capture.cpp + cell/renderer/PostProcessor.cpp + cell/renderer/PBR.cpp + cell/renderer/render_target.cpp + cell/renderer/renderer.cpp + cell/resources/mesh_loader.cpp + cell/resources/resources.cpp + cell/resources/shader_loader.cpp + cell/resources/texture_loader.cpp + cell/stb/stb_image.cpp + cell/scene/background.cpp + cell/scene/scene_node.cpp + cell/scene/scene.cpp + cell/shading/material.cpp + cell/shading/shader.cpp + cell/shading/texture_cube.cpp + cell/shading/Texture.cpp + cell/stb/stb_image.cpp + cell/cell.cpp +) + +add_library(math + math/geometry/plane.cpp + math/trigonometry/spherical.cpp + math/trigonometry/polar.cpp +) + +add_library(utility + utility/logging/log.cpp + utility/random/random.cpp + utility/timing/time.cpp +) + +add_executable(demo + demo/scenes/pbr_test.cpp + demo/program.cpp +) + +target_link_libraries(utility math) +target_link_libraries(cell math utility) +target_link_libraries(demo cell) \ No newline at end of file From 8f0e414f612f646ad1c694db6603fe0fbea7acca Mon Sep 17 00:00:00 2001 From: Jens Behley Date: Tue, 27 Mar 2018 10:45:41 +0200 Subject: [PATCH 05/31] fixing some compiler issues with gcc: Seems like that gcc is more pedantic with anonymous structs. --- math/linear_algebra/operation.h | 3 ++- math/linear_algebra/vector.h | 16 ++++++++-------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/math/linear_algebra/operation.h b/math/linear_algebra/operation.h index 77c0870..1cb0c71 100644 --- a/math/linear_algebra/operation.h +++ b/math/linear_algebra/operation.h @@ -6,6 +6,7 @@ // NOTE(Nabil/htmlboss): Going to try to use the built in OpenMP to speed up Matrix operations #include +#include namespace math { @@ -17,7 +18,7 @@ namespace math T result = {}; for(std::size_t i = 0; i < n; ++i) result += vec[i] * vec[i]; - return sqrt(result); + return std::sqrt(result); } // NOTE(Joey): often we only care about the relative length differences // between vectors and not their exact length values. Seeing as a square diff --git a/math/linear_algebra/vector.h b/math/linear_algebra/vector.h index 5388a5a..2d94ea5 100644 --- a/math/linear_algebra/vector.h +++ b/math/linear_algebra/vector.h @@ -166,7 +166,7 @@ namespace math { T s; T t; - T r; + T tt; }; struct { @@ -274,7 +274,7 @@ namespace math { T s; T t; - T r; + T tt; }; struct { @@ -284,24 +284,24 @@ namespace math }; struct { - T _ignored1; - T _ignored2; + T _ignored11; + T _ignored21; vector<2, T> yz; }; struct { vector<3, T> xyz; - T _ignored1; + T _ignored12; }; struct { vector<3, T> rgb; - T _ignored1; + T _ignored13; }; struct { vector<3, T> srt; - T _ignored1; + T _ignored14; }; }; @@ -408,7 +408,7 @@ namespace math { vector result; for (std::size_t i = 0; i < n; ++i) - result[i] = lhs[i] + scalar; + result[i] = rhs[i] + scalar; return result; } template From 1aeebf0861d3957fe1e490c0624f8d65dd302c79 Mon Sep 17 00:00:00 2001 From: Jens Behley Date: Tue, 27 Mar 2018 10:49:45 +0200 Subject: [PATCH 06/31] following style more closely. --- .clang-format | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.clang-format b/.clang-format index 488cc04..a7a5983 100644 --- a/.clang-format +++ b/.clang-format @@ -6,4 +6,6 @@ AllowShortFunctionsOnASingleLine : All IndentCaseLabels: false ColumnLimit: 0 NamespaceIndentation: All -PointerAlignment: Left \ No newline at end of file +PointerAlignment: Left +AlignConsecutiveAssignments: true +AlignConsecutiveDeclarations: true \ No newline at end of file From 328139cfb6d08ae66a69724e425fbbf484668378 Mon Sep 17 00:00:00 2001 From: Jens Behley Date: Tue, 27 Mar 2018 10:51:07 +0200 Subject: [PATCH 07/31] Use getters instead of unions, since gcc has problems with that. --- cell/camera/camera_frustum.cpp | 17 +++++++-------- cell/camera/camera_frustum.h | 38 ++++++++++++++++++---------------- 2 files changed, 28 insertions(+), 27 deletions(-) diff --git a/cell/camera/camera_frustum.cpp b/cell/camera/camera_frustum.cpp index 8b5572f..af401b7 100644 --- a/cell/camera/camera_frustum.cpp +++ b/cell/camera/camera_frustum.cpp @@ -7,7 +7,7 @@ namespace Cell // ------------------------------------------------------------------------ void CameraFrustum::Update(Camera* camera) { - float tan = 2.0 * std::tan(camera->FOV * 0.5); + float tan = 2.0 * std::tan(camera->FOV * 0.5f); float nearHeight = tan * camera->Near; float nearWidth = nearHeight * camera->Aspect; float farHeight = tan * camera->Far; @@ -21,7 +21,7 @@ namespace Cell v = (nearCenter - camera->Right * nearWidth * 0.5f) - camera->Position; Left.SetNormalD(math::cross(math::normalize(v), camera->Up), nearCenter - camera->Right * nearWidth * 0.5f); // right plane - v = (nearCenter + camera->Right * nearWidth * 0.5f) - camera->Position; + v = (nearCenter + camera->Right * nearWidth * 0.5f) - camera->Position; Right.SetNormalD(math::cross(camera->Up, math::normalize(v)), nearCenter + camera->Right * nearWidth * 0.5f); // top plane v = (nearCenter + camera->Up * nearHeight * 0.5f) - camera->Position; @@ -39,7 +39,7 @@ namespace Cell { for (int i = 0; i < 6; ++i) { - if (Planes[i].Distance(point) < 0) + if (Planes(i).Distance(point) < 0) { return false; } @@ -51,7 +51,7 @@ namespace Cell { for (int i = 0; i < 6; ++i) { - if (Planes[i].Distance(point) < -radius) + if (Planes(i).Distance(point) < -radius) { return false; } @@ -64,24 +64,23 @@ namespace Cell for (int i = 0; i < 6; ++i) { math::vec3 positive = boxMin; - if (Planes[i].Normal.x >= 0) + if (Planes(i).Normal.x >= 0) { positive.x = boxMax.x; } - if (Planes[i].Normal.y >= 0) + if (Planes(i).Normal.y >= 0) { positive.y = boxMax.y; } - if (Planes[i].Normal.z >= 0) + if (Planes(i).Normal.z >= 0) { positive.z = boxMax.z; } - if(Planes[i].Distance(positive) < 0) + if (Planes(i).Distance(positive) < 0) { return false; } } return true; } - } \ No newline at end of file diff --git a/cell/camera/camera_frustum.h b/cell/camera/camera_frustum.h index bbc1f2a..b59d04a 100644 --- a/cell/camera/camera_frustum.h +++ b/cell/camera/camera_frustum.h @@ -1,8 +1,8 @@ #ifndef CELL_CAMERA_FRUSTUM_H #define CELL_CAMERA_FRUSTUM_H -#include #include +#include namespace Cell { @@ -32,7 +32,6 @@ namespace Cell } }; - /* Container object managing all 6 camera frustum planes as calculated from any Camera object. @@ -45,23 +44,26 @@ namespace Cell */ class CameraFrustum { - public: - union - { - FrustumPlane Planes[6]; - struct - { - FrustumPlane Left; - FrustumPlane Right; - FrustumPlane Top; - FrustumPlane Bottom; - FrustumPlane Near; - FrustumPlane Far; - }; - }; + public: + // union + // { + // FrustumPlane Planes[6]; + // struct + // { + FrustumPlane Left; + FrustumPlane Right; + FrustumPlane Top; + FrustumPlane Bottom; + FrustumPlane Near; + FrustumPlane Far; + // }; + // }; + + public: + CameraFrustum() {} // NOTE(Joey): why do I need to define a constructor here? (otherwise I get deleted constructor error) LOOK IT UP! - public: - CameraFrustum() { } // NOTE(Joey): why do I need to define a constructor here? (otherwise I get deleted constructor error) LOOK IT UP! + FrustumPlane& Planes(int i) { return (&Left)[i]; } + const FrustumPlane& Planes(int i) const { return (&Left)[i]; } void Update(Camera* camera); From 1ebfb03270aec58d7f4b6c90682796d567bfd428 Mon Sep 17 00:00:00 2001 From: Jens Behley Date: Tue, 27 Mar 2018 10:52:36 +0200 Subject: [PATCH 08/31] MCube: Use getters instead of unions, since gcc has problems with that. --- cell/mesh/mesh.cpp | 788 +++++++++++++++++++++++---------------------- 1 file changed, 397 insertions(+), 391 deletions(-) diff --git a/cell/mesh/mesh.cpp b/cell/mesh/mesh.cpp index 4b0a032..b6cb9bd 100644 --- a/cell/mesh/mesh.cpp +++ b/cell/mesh/mesh.cpp @@ -10,7 +10,6 @@ namespace Cell // -------------------------------------------------------------------------------------------- Mesh::Mesh() { - } // -------------------------------------------------------------------------------------------- Mesh::Mesh(std::vector positions, std::vector indices) @@ -76,7 +75,7 @@ namespace Cell } // preprocess buffer data as interleaved or seperate when specified - std::vector data; + std::vector data; if (interleaved) { for (int i = 0; i < Positions.size(); ++i) @@ -156,38 +155,38 @@ namespace Cell if (interleaved) { // calculate stride from number of non-empty vertex attribute arrays - size_t stride = 3 * sizeof(float); - if (UV.size() > 0) stride += 2 * sizeof(float); - if (Normals.size() > 0) stride += 3 * sizeof(float); - if (Tangents.size() > 0) stride += 3 * sizeof(float); + size_t stride = 3 * sizeof(float); + if (UV.size() > 0) stride += 2 * sizeof(float); + if (Normals.size() > 0) stride += 3 * sizeof(float); + if (Tangents.size() > 0) stride += 3 * sizeof(float); if (Bitangents.size() > 0) stride += 3 * sizeof(float); size_t offset = 0; glEnableVertexAttribArray(0); - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, stride, (GLvoid*)offset); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, stride, (GLvoid *)offset); offset += 3 * sizeof(float); if (UV.size() > 0) { glEnableVertexAttribArray(1); - glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, stride, (GLvoid*)offset); + glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, stride, (GLvoid *)offset); offset += 2 * sizeof(float); } if (Normals.size() > 0) { glEnableVertexAttribArray(2); - glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, stride, (GLvoid*)offset); + glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, stride, (GLvoid *)offset); offset += 3 * sizeof(float); } if (Tangents.size() > 0) { glEnableVertexAttribArray(3); - glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, stride, (GLvoid*)offset); + glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, stride, (GLvoid *)offset); offset += 3 * sizeof(float); } if (Bitangents.size() > 0) { glEnableVertexAttribArray(4); - glVertexAttribPointer(4, 3, GL_FLOAT, GL_FALSE, stride, (GLvoid*)offset); + glVertexAttribPointer(4, 3, GL_FLOAT, GL_FALSE, stride, (GLvoid *)offset); offset += 3 * sizeof(float); } } @@ -195,440 +194,446 @@ namespace Cell { size_t offset = 0; glEnableVertexAttribArray(0); - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (GLvoid*)offset); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (GLvoid *)offset); offset += Positions.size() * sizeof(float); if (UV.size() > 0) { glEnableVertexAttribArray(1); - glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, (GLvoid*)offset); + glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, (GLvoid *)offset); offset += UV.size() * sizeof(float); } if (Normals.size() > 0) { glEnableVertexAttribArray(2); - glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 0, (GLvoid*)offset); + glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 0, (GLvoid *)offset); offset += Normals.size() * sizeof(float); } if (Tangents.size() > 0) { glEnableVertexAttribArray(3); - glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, 0, (GLvoid*)offset); + glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, 0, (GLvoid *)offset); offset += Tangents.size() * sizeof(float); } if (Bitangents.size() > 0) { glEnableVertexAttribArray(4); - glVertexAttribPointer(4, 3, GL_FLOAT, GL_FALSE, 0, (GLvoid*)offset); + glVertexAttribPointer(4, 3, GL_FLOAT, GL_FALSE, 0, (GLvoid *)offset); offset += Bitangents.size() * sizeof(float); } } glBindVertexArray(0); } // -------------------------------------------------------------------------------------------- - void Mesh::FromSDF(std::function& sdf, float maxDistance, uint16_t gridResolution) + void Mesh::FromSDF(std::function &sdf, float maxDistance, uint16_t gridResolution) { Log::Message("Generating 3D mesh from SDF", LOG_DEBUG); // tables from: http://paulbourke.net/geometry/polygonise/ - static int edgeTable[256]= - { - 0x0 , 0x109, 0x203, 0x30a, 0x406, 0x50f, 0x605, 0x70c, - 0x80c, 0x905, 0xa0f, 0xb06, 0xc0a, 0xd03, 0xe09, 0xf00, - 0x190, 0x99 , 0x393, 0x29a, 0x596, 0x49f, 0x795, 0x69c, - 0x99c, 0x895, 0xb9f, 0xa96, 0xd9a, 0xc93, 0xf99, 0xe90, - 0x230, 0x339, 0x33 , 0x13a, 0x636, 0x73f, 0x435, 0x53c, - 0xa3c, 0xb35, 0x83f, 0x936, 0xe3a, 0xf33, 0xc39, 0xd30, - 0x3a0, 0x2a9, 0x1a3, 0xaa , 0x7a6, 0x6af, 0x5a5, 0x4ac, - 0xbac, 0xaa5, 0x9af, 0x8a6, 0xfaa, 0xea3, 0xda9, 0xca0, - 0x460, 0x569, 0x663, 0x76a, 0x66 , 0x16f, 0x265, 0x36c, - 0xc6c, 0xd65, 0xe6f, 0xf66, 0x86a, 0x963, 0xa69, 0xb60, - 0x5f0, 0x4f9, 0x7f3, 0x6fa, 0x1f6, 0xff , 0x3f5, 0x2fc, - 0xdfc, 0xcf5, 0xfff, 0xef6, 0x9fa, 0x8f3, 0xbf9, 0xaf0, - 0x650, 0x759, 0x453, 0x55a, 0x256, 0x35f, 0x55 , 0x15c, - 0xe5c, 0xf55, 0xc5f, 0xd56, 0xa5a, 0xb53, 0x859, 0x950, - 0x7c0, 0x6c9, 0x5c3, 0x4ca, 0x3c6, 0x2cf, 0x1c5, 0xcc , - 0xfcc, 0xec5, 0xdcf, 0xcc6, 0xbca, 0xac3, 0x9c9, 0x8c0, - 0x8c0, 0x9c9, 0xac3, 0xbca, 0xcc6, 0xdcf, 0xec5, 0xfcc, - 0xcc , 0x1c5, 0x2cf, 0x3c6, 0x4ca, 0x5c3, 0x6c9, 0x7c0, - 0x950, 0x859, 0xb53, 0xa5a, 0xd56, 0xc5f, 0xf55, 0xe5c, - 0x15c, 0x55 , 0x35f, 0x256, 0x55a, 0x453, 0x759, 0x650, - 0xaf0, 0xbf9, 0x8f3, 0x9fa, 0xef6, 0xfff, 0xcf5, 0xdfc, - 0x2fc, 0x3f5, 0xff , 0x1f6, 0x6fa, 0x7f3, 0x4f9, 0x5f0, - 0xb60, 0xa69, 0x963, 0x86a, 0xf66, 0xe6f, 0xd65, 0xc6c, - 0x36c, 0x265, 0x16f, 0x66 , 0x76a, 0x663, 0x569, 0x460, - 0xca0, 0xda9, 0xea3, 0xfaa, 0x8a6, 0x9af, 0xaa5, 0xbac, - 0x4ac, 0x5a5, 0x6af, 0x7a6, 0xaa , 0x1a3, 0x2a9, 0x3a0, - 0xd30, 0xc39, 0xf33, 0xe3a, 0x936, 0x83f, 0xb35, 0xa3c, - 0x53c, 0x435, 0x73f, 0x636, 0x13a, 0x33 , 0x339, 0x230, - 0xe90, 0xf99, 0xc93, 0xd9a, 0xa96, 0xb9f, 0x895, 0x99c, - 0x69c, 0x795, 0x49f, 0x596, 0x29a, 0x393, 0x99 , 0x190, - 0xf00, 0xe09, 0xd03, 0xc0a, 0xb06, 0xa0f, 0x905, 0x80c, - 0x70c, 0x605, 0x50f, 0x406, 0x30a, 0x203, 0x109, 0x0 - }; - static int triTable[256][16] = - { - {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {0, 1, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {1, 8, 3, 9, 8, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {0, 8, 3, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {9, 2, 10, 0, 2, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {2, 8, 3, 2, 10, 8, 10, 9, 8, -1, -1, -1, -1, -1, -1, -1}, - {3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {0, 11, 2, 8, 11, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {1, 9, 0, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {1, 11, 2, 1, 9, 11, 9, 8, 11, -1, -1, -1, -1, -1, -1, -1}, - {3, 10, 1, 11, 10, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {0, 10, 1, 0, 8, 10, 8, 11, 10, -1, -1, -1, -1, -1, -1, -1}, - {3, 9, 0, 3, 11, 9, 11, 10, 9, -1, -1, -1, -1, -1, -1, -1}, - {9, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {4, 3, 0, 7, 3, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {0, 1, 9, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {4, 1, 9, 4, 7, 1, 7, 3, 1, -1, -1, -1, -1, -1, -1, -1}, - {1, 2, 10, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {3, 4, 7, 3, 0, 4, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1}, - {9, 2, 10, 9, 0, 2, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1}, - {2, 10, 9, 2, 9, 7, 2, 7, 3, 7, 9, 4, -1, -1, -1, -1}, - {8, 4, 7, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {11, 4, 7, 11, 2, 4, 2, 0, 4, -1, -1, -1, -1, -1, -1, -1}, - {9, 0, 1, 8, 4, 7, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1}, - {4, 7, 11, 9, 4, 11, 9, 11, 2, 9, 2, 1, -1, -1, -1, -1}, - {3, 10, 1, 3, 11, 10, 7, 8, 4, -1, -1, -1, -1, -1, -1, -1}, - {1, 11, 10, 1, 4, 11, 1, 0, 4, 7, 11, 4, -1, -1, -1, -1}, - {4, 7, 8, 9, 0, 11, 9, 11, 10, 11, 0, 3, -1, -1, -1, -1}, - {4, 7, 11, 4, 11, 9, 9, 11, 10, -1, -1, -1, -1, -1, -1, -1}, - {9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {9, 5, 4, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {0, 5, 4, 1, 5, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {8, 5, 4, 8, 3, 5, 3, 1, 5, -1, -1, -1, -1, -1, -1, -1}, - {1, 2, 10, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {3, 0, 8, 1, 2, 10, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1}, - {5, 2, 10, 5, 4, 2, 4, 0, 2, -1, -1, -1, -1, -1, -1, -1}, - {2, 10, 5, 3, 2, 5, 3, 5, 4, 3, 4, 8, -1, -1, -1, -1}, - {9, 5, 4, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {0, 11, 2, 0, 8, 11, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1}, - {0, 5, 4, 0, 1, 5, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1}, - {2, 1, 5, 2, 5, 8, 2, 8, 11, 4, 8, 5, -1, -1, -1, -1}, - {10, 3, 11, 10, 1, 3, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1}, - {4, 9, 5, 0, 8, 1, 8, 10, 1, 8, 11, 10, -1, -1, -1, -1}, - {5, 4, 0, 5, 0, 11, 5, 11, 10, 11, 0, 3, -1, -1, -1, -1}, - {5, 4, 8, 5, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1}, - {9, 7, 8, 5, 7, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {9, 3, 0, 9, 5, 3, 5, 7, 3, -1, -1, -1, -1, -1, -1, -1}, - {0, 7, 8, 0, 1, 7, 1, 5, 7, -1, -1, -1, -1, -1, -1, -1}, - {1, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {9, 7, 8, 9, 5, 7, 10, 1, 2, -1, -1, -1, -1, -1, -1, -1}, - {10, 1, 2, 9, 5, 0, 5, 3, 0, 5, 7, 3, -1, -1, -1, -1}, - {8, 0, 2, 8, 2, 5, 8, 5, 7, 10, 5, 2, -1, -1, -1, -1}, - {2, 10, 5, 2, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1}, - {7, 9, 5, 7, 8, 9, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1}, - {9, 5, 7, 9, 7, 2, 9, 2, 0, 2, 7, 11, -1, -1, -1, -1}, - {2, 3, 11, 0, 1, 8, 1, 7, 8, 1, 5, 7, -1, -1, -1, -1}, - {11, 2, 1, 11, 1, 7, 7, 1, 5, -1, -1, -1, -1, -1, -1, -1}, - {9, 5, 8, 8, 5, 7, 10, 1, 3, 10, 3, 11, -1, -1, -1, -1}, - {5, 7, 0, 5, 0, 9, 7, 11, 0, 1, 0, 10, 11, 10, 0, -1}, - {11, 10, 0, 11, 0, 3, 10, 5, 0, 8, 0, 7, 5, 7, 0, -1}, - {11, 10, 5, 7, 11, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {0, 8, 3, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {9, 0, 1, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {1, 8, 3, 1, 9, 8, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1}, - {1, 6, 5, 2, 6, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {1, 6, 5, 1, 2, 6, 3, 0, 8, -1, -1, -1, -1, -1, -1, -1}, - {9, 6, 5, 9, 0, 6, 0, 2, 6, -1, -1, -1, -1, -1, -1, -1}, - {5, 9, 8, 5, 8, 2, 5, 2, 6, 3, 2, 8, -1, -1, -1, -1}, - {2, 3, 11, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {11, 0, 8, 11, 2, 0, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1}, - {0, 1, 9, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1}, - {5, 10, 6, 1, 9, 2, 9, 11, 2, 9, 8, 11, -1, -1, -1, -1}, - {6, 3, 11, 6, 5, 3, 5, 1, 3, -1, -1, -1, -1, -1, -1, -1}, - {0, 8, 11, 0, 11, 5, 0, 5, 1, 5, 11, 6, -1, -1, -1, -1}, - {3, 11, 6, 0, 3, 6, 0, 6, 5, 0, 5, 9, -1, -1, -1, -1}, - {6, 5, 9, 6, 9, 11, 11, 9, 8, -1, -1, -1, -1, -1, -1, -1}, - {5, 10, 6, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {4, 3, 0, 4, 7, 3, 6, 5, 10, -1, -1, -1, -1, -1, -1, -1}, - {1, 9, 0, 5, 10, 6, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1}, - {10, 6, 5, 1, 9, 7, 1, 7, 3, 7, 9, 4, -1, -1, -1, -1}, - {6, 1, 2, 6, 5, 1, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1}, - {1, 2, 5, 5, 2, 6, 3, 0, 4, 3, 4, 7, -1, -1, -1, -1}, - {8, 4, 7, 9, 0, 5, 0, 6, 5, 0, 2, 6, -1, -1, -1, -1}, - {7, 3, 9, 7, 9, 4, 3, 2, 9, 5, 9, 6, 2, 6, 9, -1}, - {3, 11, 2, 7, 8, 4, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1}, - {5, 10, 6, 4, 7, 2, 4, 2, 0, 2, 7, 11, -1, -1, -1, -1}, - {0, 1, 9, 4, 7, 8, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1}, - {9, 2, 1, 9, 11, 2, 9, 4, 11, 7, 11, 4, 5, 10, 6, -1}, - {8, 4, 7, 3, 11, 5, 3, 5, 1, 5, 11, 6, -1, -1, -1, -1}, - {5, 1, 11, 5, 11, 6, 1, 0, 11, 7, 11, 4, 0, 4, 11, -1}, - {0, 5, 9, 0, 6, 5, 0, 3, 6, 11, 6, 3, 8, 4, 7, -1}, - {6, 5, 9, 6, 9, 11, 4, 7, 9, 7, 11, 9, -1, -1, -1, -1}, - {10, 4, 9, 6, 4, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {4, 10, 6, 4, 9, 10, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1}, - {10, 0, 1, 10, 6, 0, 6, 4, 0, -1, -1, -1, -1, -1, -1, -1}, - {8, 3, 1, 8, 1, 6, 8, 6, 4, 6, 1, 10, -1, -1, -1, -1}, - {1, 4, 9, 1, 2, 4, 2, 6, 4, -1, -1, -1, -1, -1, -1, -1}, - {3, 0, 8, 1, 2, 9, 2, 4, 9, 2, 6, 4, -1, -1, -1, -1}, - {0, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {8, 3, 2, 8, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1}, - {10, 4, 9, 10, 6, 4, 11, 2, 3, -1, -1, -1, -1, -1, -1, -1}, - {0, 8, 2, 2, 8, 11, 4, 9, 10, 4, 10, 6, -1, -1, -1, -1}, - {3, 11, 2, 0, 1, 6, 0, 6, 4, 6, 1, 10, -1, -1, -1, -1}, - {6, 4, 1, 6, 1, 10, 4, 8, 1, 2, 1, 11, 8, 11, 1, -1}, - {9, 6, 4, 9, 3, 6, 9, 1, 3, 11, 6, 3, -1, -1, -1, -1}, - {8, 11, 1, 8, 1, 0, 11, 6, 1, 9, 1, 4, 6, 4, 1, -1}, - {3, 11, 6, 3, 6, 0, 0, 6, 4, -1, -1, -1, -1, -1, -1, -1}, - {6, 4, 8, 11, 6, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {7, 10, 6, 7, 8, 10, 8, 9, 10, -1, -1, -1, -1, -1, -1, -1}, - {0, 7, 3, 0, 10, 7, 0, 9, 10, 6, 7, 10, -1, -1, -1, -1}, - {10, 6, 7, 1, 10, 7, 1, 7, 8, 1, 8, 0, -1, -1, -1, -1}, - {10, 6, 7, 10, 7, 1, 1, 7, 3, -1, -1, -1, -1, -1, -1, -1}, - {1, 2, 6, 1, 6, 8, 1, 8, 9, 8, 6, 7, -1, -1, -1, -1}, - {2, 6, 9, 2, 9, 1, 6, 7, 9, 0, 9, 3, 7, 3, 9, -1}, - {7, 8, 0, 7, 0, 6, 6, 0, 2, -1, -1, -1, -1, -1, -1, -1}, - {7, 3, 2, 6, 7, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {2, 3, 11, 10, 6, 8, 10, 8, 9, 8, 6, 7, -1, -1, -1, -1}, - {2, 0, 7, 2, 7, 11, 0, 9, 7, 6, 7, 10, 9, 10, 7, -1}, - {1, 8, 0, 1, 7, 8, 1, 10, 7, 6, 7, 10, 2, 3, 11, -1}, - {11, 2, 1, 11, 1, 7, 10, 6, 1, 6, 7, 1, -1, -1, -1, -1}, - {8, 9, 6, 8, 6, 7, 9, 1, 6, 11, 6, 3, 1, 3, 6, -1}, - {0, 9, 1, 11, 6, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {7, 8, 0, 7, 0, 6, 3, 11, 0, 11, 6, 0, -1, -1, -1, -1}, - {7, 11, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {3, 0, 8, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {0, 1, 9, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {8, 1, 9, 8, 3, 1, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1}, - {10, 1, 2, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {1, 2, 10, 3, 0, 8, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1}, - {2, 9, 0, 2, 10, 9, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1}, - {6, 11, 7, 2, 10, 3, 10, 8, 3, 10, 9, 8, -1, -1, -1, -1}, - {7, 2, 3, 6, 2, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {7, 0, 8, 7, 6, 0, 6, 2, 0, -1, -1, -1, -1, -1, -1, -1}, - {2, 7, 6, 2, 3, 7, 0, 1, 9, -1, -1, -1, -1, -1, -1, -1}, - {1, 6, 2, 1, 8, 6, 1, 9, 8, 8, 7, 6, -1, -1, -1, -1}, - {10, 7, 6, 10, 1, 7, 1, 3, 7, -1, -1, -1, -1, -1, -1, -1}, - {10, 7, 6, 1, 7, 10, 1, 8, 7, 1, 0, 8, -1, -1, -1, -1}, - {0, 3, 7, 0, 7, 10, 0, 10, 9, 6, 10, 7, -1, -1, -1, -1}, - {7, 6, 10, 7, 10, 8, 8, 10, 9, -1, -1, -1, -1, -1, -1, -1}, - {6, 8, 4, 11, 8, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {3, 6, 11, 3, 0, 6, 0, 4, 6, -1, -1, -1, -1, -1, -1, -1}, - {8, 6, 11, 8, 4, 6, 9, 0, 1, -1, -1, -1, -1, -1, -1, -1}, - {9, 4, 6, 9, 6, 3, 9, 3, 1, 11, 3, 6, -1, -1, -1, -1}, - {6, 8, 4, 6, 11, 8, 2, 10, 1, -1, -1, -1, -1, -1, -1, -1}, - {1, 2, 10, 3, 0, 11, 0, 6, 11, 0, 4, 6, -1, -1, -1, -1}, - {4, 11, 8, 4, 6, 11, 0, 2, 9, 2, 10, 9, -1, -1, -1, -1}, - {10, 9, 3, 10, 3, 2, 9, 4, 3, 11, 3, 6, 4, 6, 3, -1}, - {8, 2, 3, 8, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1}, - {0, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {1, 9, 0, 2, 3, 4, 2, 4, 6, 4, 3, 8, -1, -1, -1, -1}, - {1, 9, 4, 1, 4, 2, 2, 4, 6, -1, -1, -1, -1, -1, -1, -1}, - {8, 1, 3, 8, 6, 1, 8, 4, 6, 6, 10, 1, -1, -1, -1, -1}, - {10, 1, 0, 10, 0, 6, 6, 0, 4, -1, -1, -1, -1, -1, -1, -1}, - {4, 6, 3, 4, 3, 8, 6, 10, 3, 0, 3, 9, 10, 9, 3, -1}, - {10, 9, 4, 6, 10, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {4, 9, 5, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {0, 8, 3, 4, 9, 5, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1}, - {5, 0, 1, 5, 4, 0, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1}, - {11, 7, 6, 8, 3, 4, 3, 5, 4, 3, 1, 5, -1, -1, -1, -1}, - {9, 5, 4, 10, 1, 2, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1}, - {6, 11, 7, 1, 2, 10, 0, 8, 3, 4, 9, 5, -1, -1, -1, -1}, - {7, 6, 11, 5, 4, 10, 4, 2, 10, 4, 0, 2, -1, -1, -1, -1}, - {3, 4, 8, 3, 5, 4, 3, 2, 5, 10, 5, 2, 11, 7, 6, -1}, - {7, 2, 3, 7, 6, 2, 5, 4, 9, -1, -1, -1, -1, -1, -1, -1}, - {9, 5, 4, 0, 8, 6, 0, 6, 2, 6, 8, 7, -1, -1, -1, -1}, - {3, 6, 2, 3, 7, 6, 1, 5, 0, 5, 4, 0, -1, -1, -1, -1}, - {6, 2, 8, 6, 8, 7, 2, 1, 8, 4, 8, 5, 1, 5, 8, -1}, - {9, 5, 4, 10, 1, 6, 1, 7, 6, 1, 3, 7, -1, -1, -1, -1}, - {1, 6, 10, 1, 7, 6, 1, 0, 7, 8, 7, 0, 9, 5, 4, -1}, - {4, 0, 10, 4, 10, 5, 0, 3, 10, 6, 10, 7, 3, 7, 10, -1}, - {7, 6, 10, 7, 10, 8, 5, 4, 10, 4, 8, 10, -1, -1, -1, -1}, - {6, 9, 5, 6, 11, 9, 11, 8, 9, -1, -1, -1, -1, -1, -1, -1}, - {3, 6, 11, 0, 6, 3, 0, 5, 6, 0, 9, 5, -1, -1, -1, -1}, - {0, 11, 8, 0, 5, 11, 0, 1, 5, 5, 6, 11, -1, -1, -1, -1}, - {6, 11, 3, 6, 3, 5, 5, 3, 1, -1, -1, -1, -1, -1, -1, -1}, - {1, 2, 10, 9, 5, 11, 9, 11, 8, 11, 5, 6, -1, -1, -1, -1}, - {0, 11, 3, 0, 6, 11, 0, 9, 6, 5, 6, 9, 1, 2, 10, -1}, - {11, 8, 5, 11, 5, 6, 8, 0, 5, 10, 5, 2, 0, 2, 5, -1}, - {6, 11, 3, 6, 3, 5, 2, 10, 3, 10, 5, 3, -1, -1, -1, -1}, - {5, 8, 9, 5, 2, 8, 5, 6, 2, 3, 8, 2, -1, -1, -1, -1}, - {9, 5, 6, 9, 6, 0, 0, 6, 2, -1, -1, -1, -1, -1, -1, -1}, - {1, 5, 8, 1, 8, 0, 5, 6, 8, 3, 8, 2, 6, 2, 8, -1}, - {1, 5, 6, 2, 1, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {1, 3, 6, 1, 6, 10, 3, 8, 6, 5, 6, 9, 8, 9, 6, -1}, - {10, 1, 0, 10, 0, 6, 9, 5, 0, 5, 6, 0, -1, -1, -1, -1}, - {0, 3, 8, 5, 6, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {10, 5, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {11, 5, 10, 7, 5, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {11, 5, 10, 11, 7, 5, 8, 3, 0, -1, -1, -1, -1, -1, -1, -1}, - {5, 11, 7, 5, 10, 11, 1, 9, 0, -1, -1, -1, -1, -1, -1, -1}, - {10, 7, 5, 10, 11, 7, 9, 8, 1, 8, 3, 1, -1, -1, -1, -1}, - {11, 1, 2, 11, 7, 1, 7, 5, 1, -1, -1, -1, -1, -1, -1, -1}, - {0, 8, 3, 1, 2, 7, 1, 7, 5, 7, 2, 11, -1, -1, -1, -1}, - {9, 7, 5, 9, 2, 7, 9, 0, 2, 2, 11, 7, -1, -1, -1, -1}, - {7, 5, 2, 7, 2, 11, 5, 9, 2, 3, 2, 8, 9, 8, 2, -1}, - {2, 5, 10, 2, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1}, - {8, 2, 0, 8, 5, 2, 8, 7, 5, 10, 2, 5, -1, -1, -1, -1}, - {9, 0, 1, 5, 10, 3, 5, 3, 7, 3, 10, 2, -1, -1, -1, -1}, - {9, 8, 2, 9, 2, 1, 8, 7, 2, 10, 2, 5, 7, 5, 2, -1}, - {1, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {0, 8, 7, 0, 7, 1, 1, 7, 5, -1, -1, -1, -1, -1, -1, -1}, - {9, 0, 3, 9, 3, 5, 5, 3, 7, -1, -1, -1, -1, -1, -1, -1}, - {9, 8, 7, 5, 9, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {5, 8, 4, 5, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1}, - {5, 0, 4, 5, 11, 0, 5, 10, 11, 11, 3, 0, -1, -1, -1, -1}, - {0, 1, 9, 8, 4, 10, 8, 10, 11, 10, 4, 5, -1, -1, -1, -1}, - {10, 11, 4, 10, 4, 5, 11, 3, 4, 9, 4, 1, 3, 1, 4, -1}, - {2, 5, 1, 2, 8, 5, 2, 11, 8, 4, 5, 8, -1, -1, -1, -1}, - {0, 4, 11, 0, 11, 3, 4, 5, 11, 2, 11, 1, 5, 1, 11, -1}, - {0, 2, 5, 0, 5, 9, 2, 11, 5, 4, 5, 8, 11, 8, 5, -1}, - {9, 4, 5, 2, 11, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {2, 5, 10, 3, 5, 2, 3, 4, 5, 3, 8, 4, -1, -1, -1, -1}, - {5, 10, 2, 5, 2, 4, 4, 2, 0, -1, -1, -1, -1, -1, -1, -1}, - {3, 10, 2, 3, 5, 10, 3, 8, 5, 4, 5, 8, 0, 1, 9, -1}, - {5, 10, 2, 5, 2, 4, 1, 9, 2, 9, 4, 2, -1, -1, -1, -1}, - {8, 4, 5, 8, 5, 3, 3, 5, 1, -1, -1, -1, -1, -1, -1, -1}, - {0, 4, 5, 1, 0, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {8, 4, 5, 8, 5, 3, 9, 0, 5, 0, 3, 5, -1, -1, -1, -1}, - {9, 4, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {4, 11, 7, 4, 9, 11, 9, 10, 11, -1, -1, -1, -1, -1, -1, -1}, - {0, 8, 3, 4, 9, 7, 9, 11, 7, 9, 10, 11, -1, -1, -1, -1}, - {1, 10, 11, 1, 11, 4, 1, 4, 0, 7, 4, 11, -1, -1, -1, -1}, - {3, 1, 4, 3, 4, 8, 1, 10, 4, 7, 4, 11, 10, 11, 4, -1}, - {4, 11, 7, 9, 11, 4, 9, 2, 11, 9, 1, 2, -1, -1, -1, -1}, - {9, 7, 4, 9, 11, 7, 9, 1, 11, 2, 11, 1, 0, 8, 3, -1}, - {11, 7, 4, 11, 4, 2, 2, 4, 0, -1, -1, -1, -1, -1, -1, -1}, - {11, 7, 4, 11, 4, 2, 8, 3, 4, 3, 2, 4, -1, -1, -1, -1}, - {2, 9, 10, 2, 7, 9, 2, 3, 7, 7, 4, 9, -1, -1, -1, -1}, - {9, 10, 7, 9, 7, 4, 10, 2, 7, 8, 7, 0, 2, 0, 7, -1}, - {3, 7, 10, 3, 10, 2, 7, 4, 10, 1, 10, 0, 4, 0, 10, -1}, - {1, 10, 2, 8, 7, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {4, 9, 1, 4, 1, 7, 7, 1, 3, -1, -1, -1, -1, -1, -1, -1}, - {4, 9, 1, 4, 1, 7, 0, 8, 1, 8, 7, 1, -1, -1, -1, -1}, - {4, 0, 3, 7, 4, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {4, 8, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {9, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {3, 0, 9, 3, 9, 11, 11, 9, 10, -1, -1, -1, -1, -1, -1, -1}, - {0, 1, 10, 0, 10, 8, 8, 10, 11, -1, -1, -1, -1, -1, -1, -1}, - {3, 1, 10, 11, 3, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {1, 2, 11, 1, 11, 9, 9, 11, 8, -1, -1, -1, -1, -1, -1, -1}, - {3, 0, 9, 3, 9, 11, 1, 2, 9, 2, 11, 9, -1, -1, -1, -1}, - {0, 2, 11, 8, 0, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {3, 2, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {2, 3, 8, 2, 8, 10, 10, 8, 9, -1, -1, -1, -1, -1, -1, -1}, - {9, 10, 2, 0, 9, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {2, 3, 8, 2, 8, 10, 0, 1, 8, 1, 10, 8, -1, -1, -1, -1}, - {1, 10, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {1, 3, 8, 9, 1, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {0, 9, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {0, 3, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1} - }; + static int edgeTable[256] = + { + 0x0, 0x109, 0x203, 0x30a, 0x406, 0x50f, 0x605, 0x70c, + 0x80c, 0x905, 0xa0f, 0xb06, 0xc0a, 0xd03, 0xe09, 0xf00, + 0x190, 0x99, 0x393, 0x29a, 0x596, 0x49f, 0x795, 0x69c, + 0x99c, 0x895, 0xb9f, 0xa96, 0xd9a, 0xc93, 0xf99, 0xe90, + 0x230, 0x339, 0x33, 0x13a, 0x636, 0x73f, 0x435, 0x53c, + 0xa3c, 0xb35, 0x83f, 0x936, 0xe3a, 0xf33, 0xc39, 0xd30, + 0x3a0, 0x2a9, 0x1a3, 0xaa, 0x7a6, 0x6af, 0x5a5, 0x4ac, + 0xbac, 0xaa5, 0x9af, 0x8a6, 0xfaa, 0xea3, 0xda9, 0xca0, + 0x460, 0x569, 0x663, 0x76a, 0x66, 0x16f, 0x265, 0x36c, + 0xc6c, 0xd65, 0xe6f, 0xf66, 0x86a, 0x963, 0xa69, 0xb60, + 0x5f0, 0x4f9, 0x7f3, 0x6fa, 0x1f6, 0xff, 0x3f5, 0x2fc, + 0xdfc, 0xcf5, 0xfff, 0xef6, 0x9fa, 0x8f3, 0xbf9, 0xaf0, + 0x650, 0x759, 0x453, 0x55a, 0x256, 0x35f, 0x55, 0x15c, + 0xe5c, 0xf55, 0xc5f, 0xd56, 0xa5a, 0xb53, 0x859, 0x950, + 0x7c0, 0x6c9, 0x5c3, 0x4ca, 0x3c6, 0x2cf, 0x1c5, 0xcc, + 0xfcc, 0xec5, 0xdcf, 0xcc6, 0xbca, 0xac3, 0x9c9, 0x8c0, + 0x8c0, 0x9c9, 0xac3, 0xbca, 0xcc6, 0xdcf, 0xec5, 0xfcc, + 0xcc, 0x1c5, 0x2cf, 0x3c6, 0x4ca, 0x5c3, 0x6c9, 0x7c0, + 0x950, 0x859, 0xb53, 0xa5a, 0xd56, 0xc5f, 0xf55, 0xe5c, + 0x15c, 0x55, 0x35f, 0x256, 0x55a, 0x453, 0x759, 0x650, + 0xaf0, 0xbf9, 0x8f3, 0x9fa, 0xef6, 0xfff, 0xcf5, 0xdfc, + 0x2fc, 0x3f5, 0xff, 0x1f6, 0x6fa, 0x7f3, 0x4f9, 0x5f0, + 0xb60, 0xa69, 0x963, 0x86a, 0xf66, 0xe6f, 0xd65, 0xc6c, + 0x36c, 0x265, 0x16f, 0x66, 0x76a, 0x663, 0x569, 0x460, + 0xca0, 0xda9, 0xea3, 0xfaa, 0x8a6, 0x9af, 0xaa5, 0xbac, + 0x4ac, 0x5a5, 0x6af, 0x7a6, 0xaa, 0x1a3, 0x2a9, 0x3a0, + 0xd30, 0xc39, 0xf33, 0xe3a, 0x936, 0x83f, 0xb35, 0xa3c, + 0x53c, 0x435, 0x73f, 0x636, 0x13a, 0x33, 0x339, 0x230, + 0xe90, 0xf99, 0xc93, 0xd9a, 0xa96, 0xb9f, 0x895, 0x99c, + 0x69c, 0x795, 0x49f, 0x596, 0x29a, 0x393, 0x99, 0x190, + 0xf00, 0xe09, 0xd03, 0xc0a, 0xb06, 0xa0f, 0x905, 0x80c, + 0x70c, 0x605, 0x50f, 0x406, 0x30a, 0x203, 0x109, 0x0}; + static int triTable[256][16] = + { + {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {0, 1, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 8, 3, 9, 8, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {0, 8, 3, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {9, 2, 10, 0, 2, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {2, 8, 3, 2, 10, 8, 10, 9, 8, -1, -1, -1, -1, -1, -1, -1}, + {3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {0, 11, 2, 8, 11, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 9, 0, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 11, 2, 1, 9, 11, 9, 8, 11, -1, -1, -1, -1, -1, -1, -1}, + {3, 10, 1, 11, 10, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {0, 10, 1, 0, 8, 10, 8, 11, 10, -1, -1, -1, -1, -1, -1, -1}, + {3, 9, 0, 3, 11, 9, 11, 10, 9, -1, -1, -1, -1, -1, -1, -1}, + {9, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {4, 3, 0, 7, 3, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {0, 1, 9, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {4, 1, 9, 4, 7, 1, 7, 3, 1, -1, -1, -1, -1, -1, -1, -1}, + {1, 2, 10, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {3, 4, 7, 3, 0, 4, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1}, + {9, 2, 10, 9, 0, 2, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1}, + {2, 10, 9, 2, 9, 7, 2, 7, 3, 7, 9, 4, -1, -1, -1, -1}, + {8, 4, 7, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {11, 4, 7, 11, 2, 4, 2, 0, 4, -1, -1, -1, -1, -1, -1, -1}, + {9, 0, 1, 8, 4, 7, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1}, + {4, 7, 11, 9, 4, 11, 9, 11, 2, 9, 2, 1, -1, -1, -1, -1}, + {3, 10, 1, 3, 11, 10, 7, 8, 4, -1, -1, -1, -1, -1, -1, -1}, + {1, 11, 10, 1, 4, 11, 1, 0, 4, 7, 11, 4, -1, -1, -1, -1}, + {4, 7, 8, 9, 0, 11, 9, 11, 10, 11, 0, 3, -1, -1, -1, -1}, + {4, 7, 11, 4, 11, 9, 9, 11, 10, -1, -1, -1, -1, -1, -1, -1}, + {9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {9, 5, 4, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {0, 5, 4, 1, 5, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {8, 5, 4, 8, 3, 5, 3, 1, 5, -1, -1, -1, -1, -1, -1, -1}, + {1, 2, 10, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {3, 0, 8, 1, 2, 10, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1}, + {5, 2, 10, 5, 4, 2, 4, 0, 2, -1, -1, -1, -1, -1, -1, -1}, + {2, 10, 5, 3, 2, 5, 3, 5, 4, 3, 4, 8, -1, -1, -1, -1}, + {9, 5, 4, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {0, 11, 2, 0, 8, 11, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1}, + {0, 5, 4, 0, 1, 5, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1}, + {2, 1, 5, 2, 5, 8, 2, 8, 11, 4, 8, 5, -1, -1, -1, -1}, + {10, 3, 11, 10, 1, 3, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1}, + {4, 9, 5, 0, 8, 1, 8, 10, 1, 8, 11, 10, -1, -1, -1, -1}, + {5, 4, 0, 5, 0, 11, 5, 11, 10, 11, 0, 3, -1, -1, -1, -1}, + {5, 4, 8, 5, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1}, + {9, 7, 8, 5, 7, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {9, 3, 0, 9, 5, 3, 5, 7, 3, -1, -1, -1, -1, -1, -1, -1}, + {0, 7, 8, 0, 1, 7, 1, 5, 7, -1, -1, -1, -1, -1, -1, -1}, + {1, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {9, 7, 8, 9, 5, 7, 10, 1, 2, -1, -1, -1, -1, -1, -1, -1}, + {10, 1, 2, 9, 5, 0, 5, 3, 0, 5, 7, 3, -1, -1, -1, -1}, + {8, 0, 2, 8, 2, 5, 8, 5, 7, 10, 5, 2, -1, -1, -1, -1}, + {2, 10, 5, 2, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1}, + {7, 9, 5, 7, 8, 9, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1}, + {9, 5, 7, 9, 7, 2, 9, 2, 0, 2, 7, 11, -1, -1, -1, -1}, + {2, 3, 11, 0, 1, 8, 1, 7, 8, 1, 5, 7, -1, -1, -1, -1}, + {11, 2, 1, 11, 1, 7, 7, 1, 5, -1, -1, -1, -1, -1, -1, -1}, + {9, 5, 8, 8, 5, 7, 10, 1, 3, 10, 3, 11, -1, -1, -1, -1}, + {5, 7, 0, 5, 0, 9, 7, 11, 0, 1, 0, 10, 11, 10, 0, -1}, + {11, 10, 0, 11, 0, 3, 10, 5, 0, 8, 0, 7, 5, 7, 0, -1}, + {11, 10, 5, 7, 11, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {0, 8, 3, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {9, 0, 1, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 8, 3, 1, 9, 8, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1}, + {1, 6, 5, 2, 6, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 6, 5, 1, 2, 6, 3, 0, 8, -1, -1, -1, -1, -1, -1, -1}, + {9, 6, 5, 9, 0, 6, 0, 2, 6, -1, -1, -1, -1, -1, -1, -1}, + {5, 9, 8, 5, 8, 2, 5, 2, 6, 3, 2, 8, -1, -1, -1, -1}, + {2, 3, 11, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {11, 0, 8, 11, 2, 0, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1}, + {0, 1, 9, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1}, + {5, 10, 6, 1, 9, 2, 9, 11, 2, 9, 8, 11, -1, -1, -1, -1}, + {6, 3, 11, 6, 5, 3, 5, 1, 3, -1, -1, -1, -1, -1, -1, -1}, + {0, 8, 11, 0, 11, 5, 0, 5, 1, 5, 11, 6, -1, -1, -1, -1}, + {3, 11, 6, 0, 3, 6, 0, 6, 5, 0, 5, 9, -1, -1, -1, -1}, + {6, 5, 9, 6, 9, 11, 11, 9, 8, -1, -1, -1, -1, -1, -1, -1}, + {5, 10, 6, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {4, 3, 0, 4, 7, 3, 6, 5, 10, -1, -1, -1, -1, -1, -1, -1}, + {1, 9, 0, 5, 10, 6, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1}, + {10, 6, 5, 1, 9, 7, 1, 7, 3, 7, 9, 4, -1, -1, -1, -1}, + {6, 1, 2, 6, 5, 1, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1}, + {1, 2, 5, 5, 2, 6, 3, 0, 4, 3, 4, 7, -1, -1, -1, -1}, + {8, 4, 7, 9, 0, 5, 0, 6, 5, 0, 2, 6, -1, -1, -1, -1}, + {7, 3, 9, 7, 9, 4, 3, 2, 9, 5, 9, 6, 2, 6, 9, -1}, + {3, 11, 2, 7, 8, 4, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1}, + {5, 10, 6, 4, 7, 2, 4, 2, 0, 2, 7, 11, -1, -1, -1, -1}, + {0, 1, 9, 4, 7, 8, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1}, + {9, 2, 1, 9, 11, 2, 9, 4, 11, 7, 11, 4, 5, 10, 6, -1}, + {8, 4, 7, 3, 11, 5, 3, 5, 1, 5, 11, 6, -1, -1, -1, -1}, + {5, 1, 11, 5, 11, 6, 1, 0, 11, 7, 11, 4, 0, 4, 11, -1}, + {0, 5, 9, 0, 6, 5, 0, 3, 6, 11, 6, 3, 8, 4, 7, -1}, + {6, 5, 9, 6, 9, 11, 4, 7, 9, 7, 11, 9, -1, -1, -1, -1}, + {10, 4, 9, 6, 4, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {4, 10, 6, 4, 9, 10, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1}, + {10, 0, 1, 10, 6, 0, 6, 4, 0, -1, -1, -1, -1, -1, -1, -1}, + {8, 3, 1, 8, 1, 6, 8, 6, 4, 6, 1, 10, -1, -1, -1, -1}, + {1, 4, 9, 1, 2, 4, 2, 6, 4, -1, -1, -1, -1, -1, -1, -1}, + {3, 0, 8, 1, 2, 9, 2, 4, 9, 2, 6, 4, -1, -1, -1, -1}, + {0, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {8, 3, 2, 8, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1}, + {10, 4, 9, 10, 6, 4, 11, 2, 3, -1, -1, -1, -1, -1, -1, -1}, + {0, 8, 2, 2, 8, 11, 4, 9, 10, 4, 10, 6, -1, -1, -1, -1}, + {3, 11, 2, 0, 1, 6, 0, 6, 4, 6, 1, 10, -1, -1, -1, -1}, + {6, 4, 1, 6, 1, 10, 4, 8, 1, 2, 1, 11, 8, 11, 1, -1}, + {9, 6, 4, 9, 3, 6, 9, 1, 3, 11, 6, 3, -1, -1, -1, -1}, + {8, 11, 1, 8, 1, 0, 11, 6, 1, 9, 1, 4, 6, 4, 1, -1}, + {3, 11, 6, 3, 6, 0, 0, 6, 4, -1, -1, -1, -1, -1, -1, -1}, + {6, 4, 8, 11, 6, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {7, 10, 6, 7, 8, 10, 8, 9, 10, -1, -1, -1, -1, -1, -1, -1}, + {0, 7, 3, 0, 10, 7, 0, 9, 10, 6, 7, 10, -1, -1, -1, -1}, + {10, 6, 7, 1, 10, 7, 1, 7, 8, 1, 8, 0, -1, -1, -1, -1}, + {10, 6, 7, 10, 7, 1, 1, 7, 3, -1, -1, -1, -1, -1, -1, -1}, + {1, 2, 6, 1, 6, 8, 1, 8, 9, 8, 6, 7, -1, -1, -1, -1}, + {2, 6, 9, 2, 9, 1, 6, 7, 9, 0, 9, 3, 7, 3, 9, -1}, + {7, 8, 0, 7, 0, 6, 6, 0, 2, -1, -1, -1, -1, -1, -1, -1}, + {7, 3, 2, 6, 7, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {2, 3, 11, 10, 6, 8, 10, 8, 9, 8, 6, 7, -1, -1, -1, -1}, + {2, 0, 7, 2, 7, 11, 0, 9, 7, 6, 7, 10, 9, 10, 7, -1}, + {1, 8, 0, 1, 7, 8, 1, 10, 7, 6, 7, 10, 2, 3, 11, -1}, + {11, 2, 1, 11, 1, 7, 10, 6, 1, 6, 7, 1, -1, -1, -1, -1}, + {8, 9, 6, 8, 6, 7, 9, 1, 6, 11, 6, 3, 1, 3, 6, -1}, + {0, 9, 1, 11, 6, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {7, 8, 0, 7, 0, 6, 3, 11, 0, 11, 6, 0, -1, -1, -1, -1}, + {7, 11, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {3, 0, 8, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {0, 1, 9, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {8, 1, 9, 8, 3, 1, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1}, + {10, 1, 2, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 2, 10, 3, 0, 8, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1}, + {2, 9, 0, 2, 10, 9, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1}, + {6, 11, 7, 2, 10, 3, 10, 8, 3, 10, 9, 8, -1, -1, -1, -1}, + {7, 2, 3, 6, 2, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {7, 0, 8, 7, 6, 0, 6, 2, 0, -1, -1, -1, -1, -1, -1, -1}, + {2, 7, 6, 2, 3, 7, 0, 1, 9, -1, -1, -1, -1, -1, -1, -1}, + {1, 6, 2, 1, 8, 6, 1, 9, 8, 8, 7, 6, -1, -1, -1, -1}, + {10, 7, 6, 10, 1, 7, 1, 3, 7, -1, -1, -1, -1, -1, -1, -1}, + {10, 7, 6, 1, 7, 10, 1, 8, 7, 1, 0, 8, -1, -1, -1, -1}, + {0, 3, 7, 0, 7, 10, 0, 10, 9, 6, 10, 7, -1, -1, -1, -1}, + {7, 6, 10, 7, 10, 8, 8, 10, 9, -1, -1, -1, -1, -1, -1, -1}, + {6, 8, 4, 11, 8, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {3, 6, 11, 3, 0, 6, 0, 4, 6, -1, -1, -1, -1, -1, -1, -1}, + {8, 6, 11, 8, 4, 6, 9, 0, 1, -1, -1, -1, -1, -1, -1, -1}, + {9, 4, 6, 9, 6, 3, 9, 3, 1, 11, 3, 6, -1, -1, -1, -1}, + {6, 8, 4, 6, 11, 8, 2, 10, 1, -1, -1, -1, -1, -1, -1, -1}, + {1, 2, 10, 3, 0, 11, 0, 6, 11, 0, 4, 6, -1, -1, -1, -1}, + {4, 11, 8, 4, 6, 11, 0, 2, 9, 2, 10, 9, -1, -1, -1, -1}, + {10, 9, 3, 10, 3, 2, 9, 4, 3, 11, 3, 6, 4, 6, 3, -1}, + {8, 2, 3, 8, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1}, + {0, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 9, 0, 2, 3, 4, 2, 4, 6, 4, 3, 8, -1, -1, -1, -1}, + {1, 9, 4, 1, 4, 2, 2, 4, 6, -1, -1, -1, -1, -1, -1, -1}, + {8, 1, 3, 8, 6, 1, 8, 4, 6, 6, 10, 1, -1, -1, -1, -1}, + {10, 1, 0, 10, 0, 6, 6, 0, 4, -1, -1, -1, -1, -1, -1, -1}, + {4, 6, 3, 4, 3, 8, 6, 10, 3, 0, 3, 9, 10, 9, 3, -1}, + {10, 9, 4, 6, 10, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {4, 9, 5, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {0, 8, 3, 4, 9, 5, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1}, + {5, 0, 1, 5, 4, 0, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1}, + {11, 7, 6, 8, 3, 4, 3, 5, 4, 3, 1, 5, -1, -1, -1, -1}, + {9, 5, 4, 10, 1, 2, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1}, + {6, 11, 7, 1, 2, 10, 0, 8, 3, 4, 9, 5, -1, -1, -1, -1}, + {7, 6, 11, 5, 4, 10, 4, 2, 10, 4, 0, 2, -1, -1, -1, -1}, + {3, 4, 8, 3, 5, 4, 3, 2, 5, 10, 5, 2, 11, 7, 6, -1}, + {7, 2, 3, 7, 6, 2, 5, 4, 9, -1, -1, -1, -1, -1, -1, -1}, + {9, 5, 4, 0, 8, 6, 0, 6, 2, 6, 8, 7, -1, -1, -1, -1}, + {3, 6, 2, 3, 7, 6, 1, 5, 0, 5, 4, 0, -1, -1, -1, -1}, + {6, 2, 8, 6, 8, 7, 2, 1, 8, 4, 8, 5, 1, 5, 8, -1}, + {9, 5, 4, 10, 1, 6, 1, 7, 6, 1, 3, 7, -1, -1, -1, -1}, + {1, 6, 10, 1, 7, 6, 1, 0, 7, 8, 7, 0, 9, 5, 4, -1}, + {4, 0, 10, 4, 10, 5, 0, 3, 10, 6, 10, 7, 3, 7, 10, -1}, + {7, 6, 10, 7, 10, 8, 5, 4, 10, 4, 8, 10, -1, -1, -1, -1}, + {6, 9, 5, 6, 11, 9, 11, 8, 9, -1, -1, -1, -1, -1, -1, -1}, + {3, 6, 11, 0, 6, 3, 0, 5, 6, 0, 9, 5, -1, -1, -1, -1}, + {0, 11, 8, 0, 5, 11, 0, 1, 5, 5, 6, 11, -1, -1, -1, -1}, + {6, 11, 3, 6, 3, 5, 5, 3, 1, -1, -1, -1, -1, -1, -1, -1}, + {1, 2, 10, 9, 5, 11, 9, 11, 8, 11, 5, 6, -1, -1, -1, -1}, + {0, 11, 3, 0, 6, 11, 0, 9, 6, 5, 6, 9, 1, 2, 10, -1}, + {11, 8, 5, 11, 5, 6, 8, 0, 5, 10, 5, 2, 0, 2, 5, -1}, + {6, 11, 3, 6, 3, 5, 2, 10, 3, 10, 5, 3, -1, -1, -1, -1}, + {5, 8, 9, 5, 2, 8, 5, 6, 2, 3, 8, 2, -1, -1, -1, -1}, + {9, 5, 6, 9, 6, 0, 0, 6, 2, -1, -1, -1, -1, -1, -1, -1}, + {1, 5, 8, 1, 8, 0, 5, 6, 8, 3, 8, 2, 6, 2, 8, -1}, + {1, 5, 6, 2, 1, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 3, 6, 1, 6, 10, 3, 8, 6, 5, 6, 9, 8, 9, 6, -1}, + {10, 1, 0, 10, 0, 6, 9, 5, 0, 5, 6, 0, -1, -1, -1, -1}, + {0, 3, 8, 5, 6, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {10, 5, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {11, 5, 10, 7, 5, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {11, 5, 10, 11, 7, 5, 8, 3, 0, -1, -1, -1, -1, -1, -1, -1}, + {5, 11, 7, 5, 10, 11, 1, 9, 0, -1, -1, -1, -1, -1, -1, -1}, + {10, 7, 5, 10, 11, 7, 9, 8, 1, 8, 3, 1, -1, -1, -1, -1}, + {11, 1, 2, 11, 7, 1, 7, 5, 1, -1, -1, -1, -1, -1, -1, -1}, + {0, 8, 3, 1, 2, 7, 1, 7, 5, 7, 2, 11, -1, -1, -1, -1}, + {9, 7, 5, 9, 2, 7, 9, 0, 2, 2, 11, 7, -1, -1, -1, -1}, + {7, 5, 2, 7, 2, 11, 5, 9, 2, 3, 2, 8, 9, 8, 2, -1}, + {2, 5, 10, 2, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1}, + {8, 2, 0, 8, 5, 2, 8, 7, 5, 10, 2, 5, -1, -1, -1, -1}, + {9, 0, 1, 5, 10, 3, 5, 3, 7, 3, 10, 2, -1, -1, -1, -1}, + {9, 8, 2, 9, 2, 1, 8, 7, 2, 10, 2, 5, 7, 5, 2, -1}, + {1, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {0, 8, 7, 0, 7, 1, 1, 7, 5, -1, -1, -1, -1, -1, -1, -1}, + {9, 0, 3, 9, 3, 5, 5, 3, 7, -1, -1, -1, -1, -1, -1, -1}, + {9, 8, 7, 5, 9, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {5, 8, 4, 5, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1}, + {5, 0, 4, 5, 11, 0, 5, 10, 11, 11, 3, 0, -1, -1, -1, -1}, + {0, 1, 9, 8, 4, 10, 8, 10, 11, 10, 4, 5, -1, -1, -1, -1}, + {10, 11, 4, 10, 4, 5, 11, 3, 4, 9, 4, 1, 3, 1, 4, -1}, + {2, 5, 1, 2, 8, 5, 2, 11, 8, 4, 5, 8, -1, -1, -1, -1}, + {0, 4, 11, 0, 11, 3, 4, 5, 11, 2, 11, 1, 5, 1, 11, -1}, + {0, 2, 5, 0, 5, 9, 2, 11, 5, 4, 5, 8, 11, 8, 5, -1}, + {9, 4, 5, 2, 11, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {2, 5, 10, 3, 5, 2, 3, 4, 5, 3, 8, 4, -1, -1, -1, -1}, + {5, 10, 2, 5, 2, 4, 4, 2, 0, -1, -1, -1, -1, -1, -1, -1}, + {3, 10, 2, 3, 5, 10, 3, 8, 5, 4, 5, 8, 0, 1, 9, -1}, + {5, 10, 2, 5, 2, 4, 1, 9, 2, 9, 4, 2, -1, -1, -1, -1}, + {8, 4, 5, 8, 5, 3, 3, 5, 1, -1, -1, -1, -1, -1, -1, -1}, + {0, 4, 5, 1, 0, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {8, 4, 5, 8, 5, 3, 9, 0, 5, 0, 3, 5, -1, -1, -1, -1}, + {9, 4, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {4, 11, 7, 4, 9, 11, 9, 10, 11, -1, -1, -1, -1, -1, -1, -1}, + {0, 8, 3, 4, 9, 7, 9, 11, 7, 9, 10, 11, -1, -1, -1, -1}, + {1, 10, 11, 1, 11, 4, 1, 4, 0, 7, 4, 11, -1, -1, -1, -1}, + {3, 1, 4, 3, 4, 8, 1, 10, 4, 7, 4, 11, 10, 11, 4, -1}, + {4, 11, 7, 9, 11, 4, 9, 2, 11, 9, 1, 2, -1, -1, -1, -1}, + {9, 7, 4, 9, 11, 7, 9, 1, 11, 2, 11, 1, 0, 8, 3, -1}, + {11, 7, 4, 11, 4, 2, 2, 4, 0, -1, -1, -1, -1, -1, -1, -1}, + {11, 7, 4, 11, 4, 2, 8, 3, 4, 3, 2, 4, -1, -1, -1, -1}, + {2, 9, 10, 2, 7, 9, 2, 3, 7, 7, 4, 9, -1, -1, -1, -1}, + {9, 10, 7, 9, 7, 4, 10, 2, 7, 8, 7, 0, 2, 0, 7, -1}, + {3, 7, 10, 3, 10, 2, 7, 4, 10, 1, 10, 0, 4, 0, 10, -1}, + {1, 10, 2, 8, 7, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {4, 9, 1, 4, 1, 7, 7, 1, 3, -1, -1, -1, -1, -1, -1, -1}, + {4, 9, 1, 4, 1, 7, 0, 8, 1, 8, 7, 1, -1, -1, -1, -1}, + {4, 0, 3, 7, 4, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {4, 8, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {9, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {3, 0, 9, 3, 9, 11, 11, 9, 10, -1, -1, -1, -1, -1, -1, -1}, + {0, 1, 10, 0, 10, 8, 8, 10, 11, -1, -1, -1, -1, -1, -1, -1}, + {3, 1, 10, 11, 3, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 2, 11, 1, 11, 9, 9, 11, 8, -1, -1, -1, -1, -1, -1, -1}, + {3, 0, 9, 3, 9, 11, 1, 2, 9, 2, 11, 9, -1, -1, -1, -1}, + {0, 2, 11, 8, 0, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {3, 2, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {2, 3, 8, 2, 8, 10, 10, 8, 9, -1, -1, -1, -1, -1, -1, -1}, + {9, 10, 2, 0, 9, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {2, 3, 8, 2, 8, 10, 0, 1, 8, 1, 10, 8, -1, -1, -1, -1}, + {1, 10, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 3, 8, 9, 1, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {0, 9, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {0, 3, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}; // container object for all voxel data required for an individual algorithm march - struct MCube + struct MCube { - union - { - math::vec4 Corners[8]; // - struct - { - // notation: L = Left, R = Right, B = Bottom, T = Top, F = Front, B = Back (XYZ in right-handed system) - math::vec4 LBB; - math::vec4 RBB; - math::vec4 RBF; - math::vec4 LBF; - math::vec4 LTB; - math::vec4 RTB; - math::vec4 RTF; - math::vec4 LTF; - }; - }; - MCube() { } + // Note: gcc does not allow this: + // union + // { + // math::vec4 Corners[8]; // + // struct data + // { + // notation: L = Left, R = Right, B = Bottom, T = Top, F = Front, B = Back (XYZ in right-handed system) + math::vec4 LBB; + math::vec4 RBB; + math::vec4 RBF; + math::vec4 LBF; + math::vec4 LTB; + math::vec4 RTB; + math::vec4 RTF; + math::vec4 LTF; + // }; + // }; + MCube() {} int GetEdgeIndex() { int index = 0; - if (Corners[0].w < 0.0f) index |= 1; - if (Corners[1].w < 0.0f) index |= 2; - if (Corners[2].w < 0.0f) index |= 4; - if (Corners[3].w < 0.0f) index |= 8; - if (Corners[4].w < 0.0f) index |= 16; - if (Corners[5].w < 0.0f) index |= 32; - if (Corners[6].w < 0.0f) index |= 64; - if (Corners[7].w < 0.0f) index |= 128; + if (Corners(0).w < 0.0f) index |= 1; + if (Corners(1).w < 0.0f) index |= 2; + if (Corners(2).w < 0.0f) index |= 4; + if (Corners(3).w < 0.0f) index |= 8; + if (Corners(4).w < 0.0f) index |= 16; + if (Corners(5).w < 0.0f) index |= 32; + if (Corners(6).w < 0.0f) index |= 64; + if (Corners(7).w < 0.0f) index |= 128; return index; } + + math::vec4 &Corners(int i) + { + return (&LBB)[i]; + } + const math::vec4 &Corners(int i) const + { + return (&LBB)[i]; + } }; // cube-march aware lerp - static auto mLerp = [](const math::vec4& p1, const math::vec4& p2) -> math::vec3 - { + static auto mLerp = [](const math::vec4 &p1, const math::vec4 &p2) -> math::vec3 { const float epsilon = 0.0001f; - if(std::abs(0.0f - p1.w) < epsilon) + if (std::abs(0.0f - p1.w) < epsilon) return p1.xyz; - if(std::abs(0.0f - p2.w) < epsilon) + if (std::abs(0.0f - p2.w) < epsilon) return p2.xyz; - if(std::abs(p1.w - p2.w) < epsilon) + if (std::abs(p1.w - p2.w) < epsilon) return p1.xyz; - float t = (0.0f - p1.w) / (p2.w - p1.w); - math::vec3 result({ - p1.x + t * (p2.x - p1.x), - p1.y + t * (p2.y - p1.y), - p1.z + t * (p2.z - p1.z) - }); + float t = (0.0f - p1.w) / (p2.w - p1.w); + math::vec3 result({p1.x + t * (p2.x - p1.x), + p1.y + t * (p2.y - p1.y), + p1.z + t * (p2.z - p1.z)}); return result; }; // create a grid of cubes, evaluatie SDF at each cube vertex - const uint16_t gridSize = gridResolution; - const float scale = maxDistance; + const uint16_t gridSize = gridResolution; + const float scale = maxDistance; const float cubeScale = (1.0f / static_cast(gridSize)) * 2.0f * scale; // range => [-scale, scale] => 2*scale - // traverse the voxel grid - for (uint16_t z = 0; z < gridSize; ++z) { - for (uint16_t y = 0; y < gridSize; ++y) { - for (uint16_t x = 0; x < gridSize; ++x) { + // traverse the voxel grid + for (uint16_t z = 0; z < gridSize; ++z) + { + for (uint16_t y = 0; y < gridSize; ++y) + { + for (uint16_t x = 0; x < gridSize; ++x) + { // calculate voxel's 3D positions and evaluate SDF at each of its corners - float halfCube = cubeScale * 0.5f; - math::vec3 center({ - -scale + x * cubeScale + halfCube, - -scale + y * cubeScale + halfCube, - -scale + z * cubeScale + halfCube - }); + float halfCube = cubeScale * 0.5f; + math::vec3 center({-scale + x * cubeScale + halfCube, + -scale + y * cubeScale + halfCube, + -scale + z * cubeScale + halfCube}); - MCube voxel; + MCube voxel; math::vec3 offset; // left-bottom-back offset = math::vec3(-halfCube, -halfCube, -halfCube); - voxel.LBB = math::vec4(center + offset, 0.0f); + voxel.LBB = math::vec4(center + offset, 0.0f); voxel.LBB.w = sdf(voxel.LBB.xyz); // right-bottom-back - offset = math::vec3( halfCube, -halfCube, -halfCube); - voxel.RBB = math::vec4(center + offset, 0.0f); + offset = math::vec3(halfCube, -halfCube, -halfCube); + voxel.RBB = math::vec4(center + offset, 0.0f); voxel.RBB.w = sdf(voxel.RBB.xyz); // right-bottom-front - offset = math::vec3( halfCube, -halfCube, halfCube); - voxel.RBF = math::vec4(center + offset, 0.0f); + offset = math::vec3(halfCube, -halfCube, halfCube); + voxel.RBF = math::vec4(center + offset, 0.0f); voxel.RBF.w = sdf(voxel.RBF.xyz); // left-bottom-front - offset = math::vec3(-halfCube, -halfCube, halfCube); - voxel.LBF = math::vec4(center + offset, 0.0f); + offset = math::vec3(-halfCube, -halfCube, halfCube); + voxel.LBF = math::vec4(center + offset, 0.0f); voxel.LBF.w = sdf(voxel.LBF.xyz); // left-top-back - offset = math::vec3(-halfCube, halfCube, -halfCube); - voxel.LTB = math::vec4(center + offset, 0.0f); + offset = math::vec3(-halfCube, halfCube, -halfCube); + voxel.LTB = math::vec4(center + offset, 0.0f); voxel.LTB.w = sdf(voxel.LTB.xyz); // right-top-back - offset = math::vec3( halfCube, halfCube, -halfCube); - voxel.RTB = math::vec4(center + offset, 0.0f); + offset = math::vec3(halfCube, halfCube, -halfCube); + voxel.RTB = math::vec4(center + offset, 0.0f); voxel.RTB.w = sdf(voxel.RTB.xyz); // right-top-front - offset = math::vec3( halfCube, halfCube, halfCube); - voxel.RTF = math::vec4(center + offset, 0.0f); + offset = math::vec3(halfCube, halfCube, halfCube); + voxel.RTF = math::vec4(center + offset, 0.0f); voxel.RTF.w = sdf(voxel.RTF.xyz); // left-top-front - offset = math::vec3(-halfCube, halfCube, halfCube); - voxel.LTF = math::vec4(center + offset, 0.0f); + offset = math::vec3(-halfCube, halfCube, halfCube); + voxel.LTF = math::vec4(center + offset, 0.0f); voxel.LTF.w = sdf(voxel.LTF.xyz); // given all calculated data, generate this voxel's vertices @@ -636,19 +641,20 @@ namespace Cell int index = voxel.GetEdgeIndex(); // edge table indexing from: http://paulbourke.net/geometry/polygonise/ - if (edgeTable[index] == 0) { } // cube is in/out of surface, do nothing - if (edgeTable[index] & 1) { vertList[0] = mLerp(voxel.Corners[0], voxel.Corners[1]); } - if (edgeTable[index] & 2) { vertList[1] = mLerp(voxel.Corners[1], voxel.Corners[2]); } - if (edgeTable[index] & 4) { vertList[2] = mLerp(voxel.Corners[2], voxel.Corners[3]); } - if (edgeTable[index] & 8) { vertList[3] = mLerp(voxel.Corners[3], voxel.Corners[0]); } - if (edgeTable[index] & 16) { vertList[4] = mLerp(voxel.Corners[4], voxel.Corners[5]); } - if (edgeTable[index] & 32) { vertList[5] = mLerp(voxel.Corners[5], voxel.Corners[6]); } - if (edgeTable[index] & 64) { vertList[6] = mLerp(voxel.Corners[6], voxel.Corners[7]); } - if (edgeTable[index] & 128) { vertList[7] = mLerp(voxel.Corners[7], voxel.Corners[4]); } - if (edgeTable[index] & 256) { vertList[8] = mLerp(voxel.Corners[0], voxel.Corners[4]); } - if (edgeTable[index] & 512) { vertList[9] = mLerp(voxel.Corners[1], voxel.Corners[5]); } - if (edgeTable[index] & 1024) { vertList[10] = mLerp(voxel.Corners[2], voxel.Corners[6]); } - if (edgeTable[index] & 2048) { vertList[11] = mLerp(voxel.Corners[3], voxel.Corners[7]); } + if (edgeTable[index] == 0) { + } // cube is in/out of surface, do nothing + if (edgeTable[index] & 1) vertList[0] = mLerp(voxel.Corners(0), voxel.Corners(1)); + if (edgeTable[index] & 2) vertList[1] = mLerp(voxel.Corners(1), voxel.Corners(2)); + if (edgeTable[index] & 4) vertList[2] = mLerp(voxel.Corners(2), voxel.Corners(3)); + if (edgeTable[index] & 8) vertList[3] = mLerp(voxel.Corners(3), voxel.Corners(0)); + if (edgeTable[index] & 16) vertList[4] = mLerp(voxel.Corners(4), voxel.Corners(5)); + if (edgeTable[index] & 32) vertList[5] = mLerp(voxel.Corners(5), voxel.Corners(6)); + if (edgeTable[index] & 64) vertList[6] = mLerp(voxel.Corners(6), voxel.Corners(7)); + if (edgeTable[index] & 128) vertList[7] = mLerp(voxel.Corners(7), voxel.Corners(4)); + if (edgeTable[index] & 256) vertList[8] = mLerp(voxel.Corners(0), voxel.Corners(4)); + if (edgeTable[index] & 512) vertList[9] = mLerp(voxel.Corners(1), voxel.Corners(5)); + if (edgeTable[index] & 1024) vertList[10] = mLerp(voxel.Corners(2), voxel.Corners(6)); + if (edgeTable[index] & 2048) vertList[11] = mLerp(voxel.Corners(3), voxel.Corners(7)); // generate triangle vertices for (uint16_t i = 0; triTable[index][i] != -1; i += 3) @@ -706,7 +712,7 @@ namespace Cell // glm::vec2 uv2 = uv[index2]; // glm::vec2 uv3 = uv[index3]; - // // due to winding order getting changed each next triangle (as we render as triangle strip) we + // // due to winding order getting changed each next triangle (as we render as triangle strip) we // // change the order of the cross product to account for winding order switch // glm::vec3 edge1 = pos2 - pos1; // glm::vec3 edge2 = pos3 - pos1; @@ -724,7 +730,7 @@ namespace Cell // bitangent.x = f * (-deltaUV2.x * edge1.x + deltaUV1.x * edge2.x); // bitangent.y = f * (-deltaUV2.x * edge1.y + deltaUV1.x * edge2.y); // bitangent.z = f * (-deltaUV2.x * edge1.z + deltaUV1.x * edge2.z); - // //} + // //} // /* else // { // bitangent.x = f * (-deltaUV2.x * edge2.x + deltaUV1.x * edge1.x); From e8731ad1e055254c472ab32ee1cd506b90831256 Mon Sep 17 00:00:00 2001 From: Jens Behley Date: Tue, 27 Mar 2018 11:02:08 +0200 Subject: [PATCH 09/31] added some const references in operations, added const accessor. --- math/linear_algebra/vector.h | 256 ++++++++++++++++++++--------------- 1 file changed, 149 insertions(+), 107 deletions(-) diff --git a/math/linear_algebra/vector.h b/math/linear_algebra/vector.h index 2d94ea5..008d1ca 100644 --- a/math/linear_algebra/vector.h +++ b/math/linear_algebra/vector.h @@ -1,9 +1,9 @@ #ifndef MATH_LINEAR_ALGEBRA_VECTOR_H #define MATH_LINEAR_ALGEBRA_VECTOR_H -#include -#include #include +#include +#include namespace math { @@ -24,14 +24,14 @@ namespace math template struct vector { - public: - std::array data; + public: + std::array data; // NOTE(Joey): constructor0: default empty constructor; default initialize all vector elements vector() { // NOTE(Joey): the empty constructor frequently gets called (when declaring large lists of - // vectors for instance) so default initializing them can be expensive as in almost all + // vectors for instance) so default initializing them can be expensive as in almost all // cases we'll be setting them to different values anyways. /*for (unsigned int i = 0; i < n; ++i) e[i] = {};*/ @@ -39,19 +39,26 @@ namespace math // NOTE(Joey): constructor1: one argument given: initialize all vectors elements w/ same value vector(const T& v) { - for (auto& el : data) { - el = v; - } + for (auto& el : data) + { + el = v; + } } // NOTE(Joey): constructor2: use std::initializer list for accepting any number of arguments vector(const std::initializer_list args) { assert(args.size() < n); - data = args; + data = args; } // NOTE(Joey): subscript operator - T& operator[] (const std::size_t index) + T& operator[](const std::size_t index) + { + assert(index >= 0 && index < n); + return data.at(index); + } + + T operator[](const std::size_t index) const { assert(index >= 0 && index < n); return data.at(index); @@ -71,11 +78,10 @@ namespace math template struct vector<2, T> { - union - { - std::array data; + union { + std::array data; // position - struct + struct { T x; T y; @@ -89,7 +95,7 @@ namespace math }; // texture coordinates // NOTE(Joey): s,t,r is the general form of accessing texture coordinates in OpenGL. - // Using u,v,w in 3 dimensions requires w which is reserved for the position's + // Using u,v,w in 3 dimensions requires w which is reserved for the position's // homogenous coordinate set. struct { @@ -101,30 +107,37 @@ namespace math // NOTE(Joey): constructor0: default empty constructor; default initialize all vector elements vector() { - data = { }; + data = {}; } // NOTE(Joey): constructor1: one argument given: initialize all vectors elements w/ same value vector(const T& v) { - data = { v, v }; + data = {v, v}; } // NOTE(Joey): constructor2: use std::initializer list for accepting any number of arguments vector(const std::initializer_list args) { assert(args.size() <= 2); int index = 0; - for (auto begin = args.begin(); begin != args.end(); ++begin) { - data.at(index++) = *begin; - } + for (auto begin = args.begin(); begin != args.end(); ++begin) + { + data.at(index++) = *begin; + } } // NOTE(Joey): constructor3: vec2 per-element initialization vector(const T& x, const T& y) { - data = { x, y }; + data = {x, y}; } // NOTE(Joey): subscript operator - T& operator[] (const std::size_t index) + T& operator[](const std::size_t index) + { + assert(index >= 0 && index < 2); + return data.at(index); + } + + T operator[](const std::size_t index) const { assert(index >= 0 && index < 2); return data.at(index); @@ -141,12 +154,11 @@ namespace math Specialized vector version for 3-dimensional vectors. */ - template + template struct vector<3, T> { - union - { - std::array data; + union { + std::array data; // position struct { @@ -189,40 +201,47 @@ namespace math // NOTE(Joey): constructor0: default empty constructor; default initialize all vector elements vector() { - data = {}; + data = {}; } // NOTE(Joey): constructor1: one argument given: initialize all vectors elements w/ same value vector(const T& v) { - data = { v, v, v }; + data = {v, v, v}; } // NOTE(Joey): constructor2: use std::initializer list for accepting any number of arguments vector(const std::initializer_list args) { assert(args.size() <= 3); int index = 0; - for (auto begin = args.begin(); begin != args.end(); ++begin) { - data.at(index++) = *begin; - } + for (auto begin = args.begin(); begin != args.end(); ++begin) + { + data.at(index++) = *begin; + } } // NOTE(Joey): constructor3: vec3 per-element initialization vector(const T& x, const T& y, const T& z) { - data = { x, y, z }; + data = {x, y, z}; } // NOTE(Joey): constructor4: vec2 initialization vector(const vector<2, T>& vec, const T& z) { - data = { vec.x, vec.y, z }; + data = {vec.x, vec.y, z}; } // NOTE(Joey): constructor5: vec2 initialization vector(const T& x, const vector<2, T>& vec) { - data = { x, vec.x, vec.y }; + data = {x, vec.x, vec.y}; } // NOTE(Joey): subscript operator - T& operator[] (const std::size_t index) + T& operator[](const std::size_t index) + { + assert(index >= 0 && index < 3); + return data.at(index); + } + + T operator[](const std::size_t index) const { assert(index >= 0 && index < 3); return data.at(index); @@ -235,24 +254,29 @@ namespace math }; // NOTE(Joey): initialize static variables of vec3 - template vector<3, T> vector<3, T>::UP = vector<3, T>( 0.0, 1.0, 0.0); - template vector<3, T> vector<3, T>::DOWN = vector<3, T>( 0.0, -1.0, 0.0); - template vector<3, T> vector<3, T>::LEFT = vector<3, T>(-1.0, 0.0, 0.0); - template vector<3, T> vector<3, T>::RIGHT = vector<3, T>( 1.0, 0.0, 0.0); - template vector<3, T> vector<3, T>::FORWARD = vector<3, T>( 0.0, 0.0, -1.0); - template vector<3, T> vector<3, T>::BACK = vector<3, T>( 0.0, 0.0, 1.0); + template + vector<3, T> vector<3, T>::UP = vector<3, T>(0.0, 1.0, 0.0); + template + vector<3, T> vector<3, T>::DOWN = vector<3, T>(0.0, -1.0, 0.0); + template + vector<3, T> vector<3, T>::LEFT = vector<3, T>(-1.0, 0.0, 0.0); + template + vector<3, T> vector<3, T>::RIGHT = vector<3, T>(1.0, 0.0, 0.0); + template + vector<3, T> vector<3, T>::FORWARD = vector<3, T>(0.0, 0.0, -1.0); + template + vector<3, T> vector<3, T>::BACK = vector<3, T>(0.0, 0.0, 1.0); /* NOTE(Joey): Specialized vector version for 4-dimensional vectors. */ - template + template struct vector<4, T> { - union - { - std::array data; + union { + std::array data; // position struct { @@ -279,73 +303,80 @@ namespace math struct { vector<2, T> xy; - T _ignored1; - T _ignored2; + T _ignored1; + T _ignored2; }; struct { - T _ignored11; - T _ignored21; + T _ignored11; + T _ignored21; vector<2, T> yz; }; struct { vector<3, T> xyz; - T _ignored12; + T _ignored12; }; struct { vector<3, T> rgb; - T _ignored13; + T _ignored13; }; struct { vector<3, T> srt; - T _ignored14; + T _ignored14; }; }; // NOTE(Joey): constructor0: default empty constructor; default initialize all vector elements vector() { - data = { }; + data = {}; } // NOTE(Joey): constructor1: one argument given: initialize all vectors elements w/ same value vector(const T& v) { - data = { v, v, v, v }; + data = {v, v, v, v}; } // NOTE(Joey): constructor2: use std::initializer list for accepting any number of arguments vector(const std::initializer_list args) { assert(args.size() <= 4); int index = 0; - for (auto begin = args.begin(); begin != args.end(); ++begin) { - data.at(index++) = *begin; - } + for (auto begin = args.begin(); begin != args.end(); ++begin) + { + data.at(index++) = *begin; + } } // NOTE(Joey): constructor3: vec3 per-element initialization vector(const T& x, const T& y, const T& z, const T& w) { - data = { x, y, z, w }; + data = {x, y, z, w}; } // NOTE(Joey): constructor4: vec2 initialization vector(const vector<2, T>& xy, const vector<2, T>& zw) { - data = { xy.x, xy.y, zw.z, zw.w }; + data = {xy.x, xy.y, zw.z, zw.w}; } // NOTE(Joey): constructor5: vec3 initialization vector(const vector<3, T>& xyz, const T& w) { - data = { xyz.x, xyz.y, xyz.z, w }; + data = {xyz.x, xyz.y, xyz.z, w}; } // NOTE(Joey): subscript operator - T& operator[] (const std::size_t index) + T& operator[](const std::size_t index) + { + assert(index >= 0 && index < 4); + return data.at(index); + } + + T operator[](const std::size_t index) const { assert(index >= 0 && index < 4); return data.at(index); - } + } // NOTE(Joey): math operators (defined in operation.h) // --------------------------------------------------- @@ -372,39 +403,41 @@ namespace math inline vector vector::operator-() { vector result; - for (std::size_t i = 0; i < n; ++i) { - result[i] = -data[i]; - } + for (std::size_t i = 0; i < n; ++i) + { + result[i] = -data[i]; + } return result; } template inline vector<2, T> vector<2, T>::operator-() { - return{ -x, -y }; + return {-x, -y}; } template inline vector<3, T> vector<3, T>::operator-() { - return{ -x, -y, -z }; + return {-x, -y, -z}; } template inline vector<4, T> vector<4, T>::operator-() { - return{ -x, -y, -z, -w }; + return {-x, -y, -z, -w}; } // NOTE(Joey): addition template - inline vector operator+(vector lhs, T scalar) + inline vector operator+(const vector& lhs, T scalar) { vector result; - for (std::size_t i = 0; i < n; ++i) { - result[i] = lhs[i] + scalar; - } + for (std::size_t i = 0; i < n; ++i) + { + result[i] = lhs[i] + scalar; + } return result; } template - inline vector operator+(T scalar, vector rhs) + inline vector operator+(T scalar, const vector& rhs) { vector result; for (std::size_t i = 0; i < n; ++i) @@ -412,7 +445,7 @@ namespace math return result; } template - inline vector operator+(vector lhs, vector rhs) + inline vector operator+(const vector& lhs, const vector& rhs) { vector result; for (std::size_t i = 0; i < n; ++i) @@ -422,87 +455,96 @@ namespace math // NOTE(Joey): subtraction template - inline vector operator-(vector lhs, T scalar) + inline vector operator-(const vector& lhs, T scalar) { vector result; - for (std::size_t i = 0; i < n; ++i) { - result[i] = lhs[i] - scalar; - } + for (std::size_t i = 0; i < n; ++i) + { + result[i] = lhs[i] - scalar; + } return result; } template - inline vector operator-(vector lhs, vector rhs) + inline vector operator-(const vector& lhs, const vector& rhs) { vector result; - for (std::size_t i = 0; i < n; ++i) { - result[i] = lhs[i] - rhs[i]; - } + for (std::size_t i = 0; i < n; ++i) + { + result[i] = lhs[i] - rhs[i]; + } return result; } // NOTE(Joey): multiplication template - inline vector operator*(vector lhs, T scalar) + inline vector operator*(const vector& lhs, T scalar) { vector result; - for (std::size_t i = 0; i < n; ++i) { - result[i] = lhs[i] * scalar; - } + for (std::size_t i = 0; i < n; ++i) + { + result[i] = lhs[i] * scalar; + } return result; } template vector& operator*=(vector& lhs, T scalar) { - for (std::size_t i = 0; i < n; ++i) { + for (std::size_t i = 0; i < n; ++i) + { lhs[i] *= scalar; } return lhs; } template - inline vector operator*(T scalar, vector lhs) + inline vector operator*(T scalar, const vector& lhs) { vector result; - for (std::size_t i = 0; i < n; ++i) { - result[i] = lhs[i] * scalar; - } + for (std::size_t i = 0; i < n; ++i) + { + result[i] = lhs[i] * scalar; + } return result; } template - inline vector operator*(vector lhs, vector rhs) // NOTE(Joey): hadamard product + inline vector operator*(const vector& lhs, const vector& rhs) // NOTE(Joey): hadamard product { vector result; - for (std::size_t i = 0; i < n; ++i) { - result[i] = lhs[i] * rhs[i]; - } + for (std::size_t i = 0; i < n; ++i) + { + result[i] = lhs[i] * rhs[i]; + } return result; } // NOTE(Joey): division template - inline vector operator/(vector lhs, T scalar) + inline vector operator/(const vector& lhs, T scalar) { vector result; - for (unsigned int i = 0; i < n; ++i) { - result[i] = lhs[i] / scalar; - } + for (unsigned int i = 0; i < n; ++i) + { + result[i] = lhs[i] / scalar; + } return result; } template - inline vector operator/(T scalar, vector lhs) + inline vector operator/(T scalar, const vector& rhs) { vector result; - for (std::size_t i = 0; i < n; ++i) { - result[i] = lhs[i] / scalar; - } + for (std::size_t i = 0; i < n; ++i) + { + result[i] = rhs[i] / scalar; + } return result; } template - inline vector operator/(vector lhs, vector rhs) // NOTE(Joey): hadamard product + inline vector operator/(const vector& lhs, const vector& rhs) // NOTE(Joey): hadamard product { vector result; - for (std::size_t i = 0; i < n; ++i) { - result[i] = lhs[i] / rhs[i]; - } + for (std::size_t i = 0; i < n; ++i) + { + result[i] = lhs[i] / rhs[i]; + } return result; } } // namespace math From 9204eb2ad265c90258594760325104b2677f3282 Mon Sep 17 00:00:00 2001 From: Jens Behley Date: Tue, 27 Mar 2018 11:16:54 +0200 Subject: [PATCH 10/31] make minus operator const. --- math/linear_algebra/vector.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/math/linear_algebra/vector.h b/math/linear_algebra/vector.h index 008d1ca..a018abf 100644 --- a/math/linear_algebra/vector.h +++ b/math/linear_algebra/vector.h @@ -67,7 +67,7 @@ namespace math // NOTE(Joey): math member operators (defined in operation.h) // --------------------------------------------------- // NOTE(Joey): negate operator - vector operator-(); + vector operator-() const; }; /* NOTE(Joey): @@ -146,7 +146,7 @@ namespace math // NOTE(Joey): math operators (defined in operation.h) // --------------------------------------------------- // NOTE(Joey): negate operator - vector<2, T> operator-(); + vector<2, T> operator-() const; }; /* NOTE(Joey): @@ -250,7 +250,7 @@ namespace math // NOTE(Joey): math operators (defined in operation.h) // --------------------------------------------------- // NOTE(Joey): negate operator - vector<3, T> operator-(); + vector<3, T> operator-() const; }; // NOTE(Joey): initialize static variables of vec3 @@ -381,7 +381,7 @@ namespace math // NOTE(Joey): math operators (defined in operation.h) // --------------------------------------------------- // NOTE(Joey): negate operator - vector<4, T> operator-(); + vector<4, T> operator-() const; }; typedef vector<2, float> vec2; @@ -400,7 +400,7 @@ namespace math // NOTE(Joey): because this is a member operator, we have to // define this for each specialization. template - inline vector vector::operator-() + inline vector vector::operator-() const { vector result; for (std::size_t i = 0; i < n; ++i) @@ -410,17 +410,17 @@ namespace math return result; } template - inline vector<2, T> vector<2, T>::operator-() + inline vector<2, T> vector<2, T>::operator-() const { return {-x, -y}; } template - inline vector<3, T> vector<3, T>::operator-() + inline vector<3, T> vector<3, T>::operator-() const { return {-x, -y, -z}; } template - inline vector<4, T> vector<4, T>::operator-() + inline vector<4, T> vector<4, T>::operator-() const { return {-x, -y, -z, -w}; } From 0bd261ddd8facc2ef7fee068b4864c79f5049424 Mon Sep 17 00:00:00 2001 From: Jens Behley Date: Tue, 27 Mar 2018 11:18:19 +0200 Subject: [PATCH 11/31] add const column operator --- math/linear_algebra/matrix.h | 54 +++++++++++++++++++----------------- 1 file changed, 29 insertions(+), 25 deletions(-) diff --git a/math/linear_algebra/matrix.h b/math/linear_algebra/matrix.h index 2c2d141..fcd8281 100644 --- a/math/linear_algebra/matrix.h +++ b/math/linear_algebra/matrix.h @@ -1,13 +1,13 @@ #ifndef MATH_LINEAR_ALGEBRA_MATRIX_H #define MATH_LINEAR_ALGEBRA_MATRIX_H -#include #include +#include #include "vector.h" namespace math -{ +{ /* Generic m by n dimensional matrix template type version supporting matrices of any type. The @@ -38,18 +38,17 @@ namespace math template struct matrix { - union - { + union { T e[n][m]; struct { - // allow access on a per-column basis. We do not provide support for per-row access + // allow access on a per-column basis. We do not provide support for per-row access // as this is not sequential in memory. vector col[n]; }; }; // -------------------------------------------------------------------------------------------- - // consturctor0: default initializes matrix to identity matrix + // consturctor0: default initializes matrix to identity matrix matrix() { for (std::size_t col = 0; col < n; ++col) @@ -67,24 +66,30 @@ namespace math assert(args.size() <= m * n); std::size_t cols = 0, rows = 0; - for (auto& it : args) - { - e[cols][rows++] = it; - if (rows >= m) - { - ++cols; - rows = 0; - } - } + for (auto& it : args) + { + e[cols][rows++] = it; + if (rows >= m) + { + ++cols; + rows = 0; + } + } } // -------------------------------------------------------------------------------------------- - // returns a column vector, that can again be indexed with the vector subscript operator. + // returns a column vector, that can again be indexed with the vector subscript operator. // In effect: [][] and [] indexing is possible. vector& operator[](const std::size_t colIndex) { assert(colIndex >= 0 && colIndex < n); return col[colIndex]; } + + const vector& operator[](const std::size_t colIndex) const + { + assert(colIndex >= 0 && colIndex < n); + return col[colIndex]; + } }; typedef matrix<2, 2, float> mat2; @@ -94,11 +99,10 @@ namespace math typedef matrix<3, 3, double> dmat3; typedef matrix<4, 4, double> dmat4; - // per-matrix operations // -------------------------------------------------------------------------------------------- - // addition (note that we do not define matrix scalar operations as they are not mathematically - // defined; they should be defined as operations on a matrix completely filled with the + // addition (note that we do not define matrix scalar operations as they are not mathematically + // defined; they should be defined as operations on a matrix completely filled with the // respective scalar. template matrix operator+(matrix& lhs, matrix& rhs) @@ -130,9 +134,9 @@ namespace math } // multiplication // -------------------------------------------------------------------------------------------- - // note that with matrix multiplication both matrices can have varying dimensions/sizes as long - // as they adhere to the following rule: the number of columns (n) of the LHS matrix should - // equal the number of rows (n) on the RHS matrix. Theresult of the matrix multiplication is + // note that with matrix multiplication both matrices can have varying dimensions/sizes as long + // as they adhere to the following rule: the number of columns (n) of the LHS matrix should + // equal the number of rows (n) on the RHS matrix. Theresult of the matrix multiplication is // then always a matrix of dimensions m x o (LHS:rows x RHS:cols) dimensions. template matrix operator*(matrix& lhs, matrix& rhs) @@ -155,7 +159,7 @@ namespace math // multiplication with reference matrix (store directly inside provided matrix) // -------------------------------------------------------------------------------------------- template - matrix& mul(matrix &result, const matrix& lhs, const matrix& rhs) + matrix& mul(matrix& result, const matrix& lhs, const matrix& rhs) { for (std::size_t col = 0; col < o; ++col) { @@ -173,7 +177,7 @@ namespace math } // matrix * vector multiplication // -------------------------------------------------------------------------------------------- - // rhs vector multiplication. We only define vector-matrix multiplication with the vector on + // rhs vector multiplication. We only define vector-matrix multiplication with the vector on // the right-side of the equation due to the column-major convention. template vector operator*(matrix& lhs, vector& rhs) @@ -190,5 +194,5 @@ namespace math } return result; } -} +} #endif \ No newline at end of file From 59d814afc7199750ff4f03aad4970bb27d3d41f8 Mon Sep 17 00:00:00 2001 From: Jens Behley Date: Tue, 27 Mar 2018 11:19:03 +0200 Subject: [PATCH 12/31] made type long unsigned int for template resolution. --- math/linear_algebra/operation.h | 4 ++-- math/linear_algebra/transformation.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/math/linear_algebra/operation.h b/math/linear_algebra/operation.h index 1cb0c71..9c4285e 100644 --- a/math/linear_algebra/operation.h +++ b/math/linear_algebra/operation.h @@ -88,8 +88,8 @@ namespace math // NOTE(Joey): matrix algebraic operations // --------------------------------------- - template - inline matrix transpose(matrix& mat) + template + inline matrix transpose(const matrix& mat) { matrix result; diff --git a/math/linear_algebra/transformation.h b/math/linear_algebra/transformation.h index 820221e..9ad0df0 100644 --- a/math/linear_algebra/transformation.h +++ b/math/linear_algebra/transformation.h @@ -112,7 +112,7 @@ namespace math // NOTE(Joey): view-space // ---------------------- template - matrix<4, 4, T> lookAt(vector<3, T>& position, vector<3, T>& target, vector<3, T>& worldUp) + matrix<4, 4, T> lookAt(const vector<3, T>& position, const vector<3, T>& target, const vector<3, T>& worldUp) { matrix<4, 4, T> frame; matrix<4, 4, T> translate; From 8f6bb0afea7bd0e67036db1f5db18b86ad7bcc5f Mon Sep 17 00:00:00 2001 From: Jens Behley Date: Tue, 27 Mar 2018 11:33:11 +0200 Subject: [PATCH 13/31] use lower case variable names to avoid change of meaning after forward declaration (gcc issue) --- cell/renderer/PBR.cpp | 10 +++--- cell/renderer/command_buffer.cpp | 30 ++++++++--------- cell/renderer/render_command.h | 12 +++---- cell/renderer/renderer.cpp | 58 ++++++++++++++++---------------- cell/scene/scene_node.h | 4 +-- cell/shading/shading_types.h | 20 +++++------ 6 files changed, 66 insertions(+), 68 deletions(-) diff --git a/cell/renderer/PBR.cpp b/cell/renderer/PBR.cpp index cbb2a03..a5a8cb9 100644 --- a/cell/renderer/PBR.cpp +++ b/cell/renderer/PBR.cpp @@ -41,8 +41,8 @@ namespace Cell m_PBRCaptureCube = new Cube(); m_SceneEnvCube = new SceneNode(0); - m_SceneEnvCube->Mesh = m_PBRCaptureCube; - m_SceneEnvCube->Material = m_PBRHdrToCubemap; + m_SceneEnvCube->mesh = m_PBRCaptureCube; + m_SceneEnvCube->material = m_PBRHdrToCubemap; // - brdf integration m_Renderer->Blit(nullptr, m_RenderTargetBRDFLUT, m_PBRIntegrateBRDF); @@ -110,7 +110,7 @@ namespace Cell PBRCapture* PBR::ProcessEquirectangular(Texture* envMap) { // convert HDR radiance image to HDR environment cubemap - m_SceneEnvCube->Material = m_PBRHdrToCubemap; + m_SceneEnvCube->material = m_PBRHdrToCubemap; m_PBRHdrToCubemap->SetTexture("environment", envMap, 0); Cell::TextureCube hdrEnvMap; hdrEnvMap.DefaultInitialize(128, 128, GL_RGB, GL_FLOAT); @@ -127,7 +127,7 @@ namespace Cell captureProbe->Irradiance = new TextureCube; captureProbe->Irradiance->DefaultInitialize(32, 32, GL_RGB, GL_FLOAT); m_PBRIrradianceCapture->SetTextureCube("environment", capture, 0); - m_SceneEnvCube->Material = m_PBRIrradianceCapture; + m_SceneEnvCube->material = m_PBRIrradianceCapture; m_Renderer->renderToCubemap(m_SceneEnvCube, captureProbe->Irradiance, math::vec3(0.0f), 0); // prefilter if (prefilter) @@ -136,7 +136,7 @@ namespace Cell captureProbe->Prefiltered->FilterMin = GL_LINEAR_MIPMAP_LINEAR; captureProbe->Prefiltered->DefaultInitialize(128, 128, GL_RGB, GL_FLOAT, true); m_PBRPrefilterCapture->SetTextureCube("environment", capture, 0); - m_SceneEnvCube->Material = m_PBRPrefilterCapture; + m_SceneEnvCube->material = m_PBRPrefilterCapture; // calculate prefilter for multiple roughness levels unsigned int maxMipLevels = 5; for (unsigned int i = 0; i < maxMipLevels; ++i) diff --git a/cell/renderer/command_buffer.cpp b/cell/renderer/command_buffer.cpp index 33e601f..b079adb 100644 --- a/cell/renderer/command_buffer.cpp +++ b/cell/renderer/command_buffer.cpp @@ -24,12 +24,12 @@ namespace Cell void CommandBuffer::Push(Mesh* mesh, Material* material, math::mat4 transform, math::mat4 prevTransform, math::vec3 boxMin, math::vec3 boxMax, RenderTarget* target) { RenderCommand command = {}; - command.Mesh = mesh; - command.Material = material; - command.Transform = transform; - command.PrevTransform = prevTransform; - command.BoxMin = boxMin; - command.BoxMax = boxMax; + command.mesh = mesh; + command.material = material; + command.transform = transform; + command.prevTransform = prevTransform; + command.boxMin = boxMin; + command.boxMax = boxMax; // if material requires alpha support, add it to alpha render commands for later rendering. if (material->Blend) @@ -74,7 +74,7 @@ namespace Cell // custom per-element sort compare function used by the CommandBuffer::Sort() function. bool renderSortDeferred(const RenderCommand &a, const RenderCommand &b) { - return a.Material->GetShader()->ID < b.Material->GetShader()->ID; + return a.material->GetShader()->ID < b.material->GetShader()->ID; } // sort render state bool renderSortCustom(const RenderCommand &a, const RenderCommand &b) @@ -106,12 +106,12 @@ namespace Cell return false; */ - return std::make_tuple(a.Material->Blend, a.Material->GetShader()->ID) < - std::make_tuple(b.Material->Blend, b.Material->GetShader()->ID); + return std::make_tuple(a.material->Blend, a.material->GetShader()->ID) < + std::make_tuple(b.material->Blend, b.material->GetShader()->ID); } bool renderSortShader(const RenderCommand &a, const RenderCommand &b) { - return a.Material->GetShader()->ID < b.Material->GetShader()->ID; + return a.material->GetShader()->ID < b.material->GetShader()->ID; } // -------------------------------------------------------------------------------------------- void CommandBuffer::Sort() @@ -131,7 +131,7 @@ namespace Cell for (auto it = m_DeferredRenderCommands.begin(); it != m_DeferredRenderCommands.end(); ++it) { RenderCommand command = *it; - if (m_Renderer->GetCamera()->Frustum.Intersect(command.BoxMin, command.BoxMax)) { + if (m_Renderer->GetCamera()->Frustum.Intersect(command.boxMin, command.boxMax)) { commands.push_back(command); } } @@ -152,7 +152,7 @@ namespace Cell for (auto it = m_CustomRenderCommands[target].begin(); it != m_CustomRenderCommands[target].end(); ++it) { RenderCommand command = *it; - if (m_Renderer->GetCamera()->Frustum.Intersect(command.BoxMin, command.BoxMax)) { + if (m_Renderer->GetCamera()->Frustum.Intersect(command.boxMin, command.boxMax)) { commands.push_back(command); } } @@ -172,7 +172,7 @@ namespace Cell for (auto it = m_AlphaRenderCommands.begin(); it != m_AlphaRenderCommands.end(); ++it) { RenderCommand command = *it; - if (m_Renderer->GetCamera()->Frustum.Intersect(command.BoxMin, command.BoxMax)) { + if (m_Renderer->GetCamera()->Frustum.Intersect(command.boxMin, command.boxMax)) { commands.push_back(command); } } @@ -194,14 +194,14 @@ namespace Cell std::vector commands; for (auto it = m_DeferredRenderCommands.begin(); it != m_DeferredRenderCommands.end(); ++it) { - if (it->Material->ShadowCast) + if (it->material->ShadowCast) { commands.push_back(*it); } } for (auto it = m_CustomRenderCommands[nullptr].begin(); it != m_CustomRenderCommands[nullptr].end(); ++it) { - if (it->Material->ShadowCast) + if (it->material->ShadowCast) { commands.push_back(*it); } diff --git a/cell/renderer/render_command.h b/cell/renderer/render_command.h index 96a8cba..f924eb1 100644 --- a/cell/renderer/render_command.h +++ b/cell/renderer/render_command.h @@ -15,12 +15,12 @@ namespace Cell */ struct RenderCommand { - math::mat4 Transform; - math::mat4 PrevTransform; - Mesh* Mesh; - Material* Material; - math::vec3 BoxMin; - math::vec3 BoxMax; + math::mat4 transform; + math::mat4 prevTransform; + Mesh* mesh; + Material* material; + math::vec3 boxMin; + math::vec3 boxMax; }; } diff --git a/cell/renderer/renderer.cpp b/cell/renderer/renderer.cpp index 584a02e..8ca5344 100644 --- a/cell/renderer/renderer.cpp +++ b/cell/renderer/renderer.cpp @@ -206,11 +206,11 @@ namespace Cell SceneNode* node = nodeStack.top(); nodeStack.pop(); // only push render command if the child isn't a container node. - if (node->Mesh) + if (node->mesh) { math::vec3 boxMinWorld = node->GetWorldPosition() + (node->GetWorldScale() * node->BoxMin); math::vec3 boxMaxWorld = node->GetWorldPosition() + (node->GetWorldScale() * node->BoxMax); - m_CommandBuffer->Push(node->Mesh, node->Material, node->GetTransform(), node->GetPrevTransform(), boxMinWorld, boxMaxWorld, target); + m_CommandBuffer->Push(node->mesh, node->material, node->GetTransform(), node->GetPrevTransform(), boxMinWorld, boxMaxWorld, target); } for(unsigned int i = 0; i < node->GetChildCount(); ++i) nodeStack.push(node->GetChildByIndex(i)); @@ -432,12 +432,12 @@ namespace Cell m_MaterialLibrary->debugLightMaterial->SetVector("lightColor", (*it)->Color * (*it)->Intensity * 0.25f); RenderCommand command; - command.Material = m_MaterialLibrary->debugLightMaterial; - command.Mesh = m_DebugLightMesh; + command.material = m_MaterialLibrary->debugLightMaterial; + command.mesh = m_DebugLightMesh; math::mat4 model; math::translate(model, (*it)->Position); math::scale(model, math::vec3(0.25f)); - command.Transform = model; + command.transform = model; renderCustomCommand(&command, nullptr); } @@ -458,12 +458,12 @@ namespace Cell m_MaterialLibrary->debugLightMaterial->SetVector("lightColor", (*it)->Color); RenderCommand command; - command.Material = m_MaterialLibrary->debugLightMaterial; - command.Mesh = m_DebugLightMesh; + command.material = m_MaterialLibrary->debugLightMaterial; + command.mesh = m_DebugLightMesh; math::mat4 model; math::translate(model, (*it)->Position); math::scale(model, math::vec3((*it)->Radius)); - command.Transform = model; + command.transform = model; renderCustomCommand(&command, nullptr); } @@ -483,7 +483,7 @@ namespace Cell bool even = i % 2 == 0; Blit(even ? m_CustomTarget->GetColorTexture(0) : m_PostProcessTarget1->GetColorTexture(0), even ? m_PostProcessTarget1 : m_CustomTarget, - postProcessingCommands[i].Material); + postProcessingCommands[i].material); } // 11. final post-processing steps, blitting to default framebuffer @@ -534,8 +534,8 @@ namespace Cell } // render screen-space material to quad which will be displayed in dst's buffers. RenderCommand command; - command.Material = material; - command.Mesh = m_NDCPlane; + command.material = material; + command.mesh = m_NDCPlane; renderCustomCommand(&command, nullptr); } // ------------------------------------------------------------------------ @@ -573,33 +573,33 @@ namespace Cell { SceneNode *node = sceneStack.top(); sceneStack.pop(); - if (node->Mesh) + if (node->mesh) { - auto samplerUniforms = *(node->Material->GetSamplerUniforms()); + auto samplerUniforms = *(node->material->GetSamplerUniforms()); if (samplerUniforms.find("TexAlbedo") != samplerUniforms.end()) { materials.push_back(new Material(m_PBR->m_ProbeCaptureShader)); - materials[materials.size() - 1]->SetTexture("TexAlbedo", samplerUniforms["TexAlbedo"].Texture, 0); + materials[materials.size() - 1]->SetTexture("TexAlbedo", samplerUniforms["TexAlbedo"].texture, 0); if (samplerUniforms.find("TexNormal") != samplerUniforms.end()) { - materials[materials.size() - 1]->SetTexture("TexNormal", samplerUniforms["TexNormal"].Texture, 1); + materials[materials.size() - 1]->SetTexture("TexNormal", samplerUniforms["TexNormal"].texture, 1); } if (samplerUniforms.find("TexMetallic") != samplerUniforms.end()) { - materials[materials.size() - 1]->SetTexture("TexMetallic", samplerUniforms["TexMetallic"].Texture, 2); + materials[materials.size() - 1]->SetTexture("TexMetallic", samplerUniforms["TexMetallic"].texture, 2); } if (samplerUniforms.find("TexRoughness") != samplerUniforms.end()) { - materials[materials.size() - 1]->SetTexture("TexRoughness", samplerUniforms["TexRoughness"].Texture, 3); + materials[materials.size() - 1]->SetTexture("TexRoughness", samplerUniforms["TexRoughness"].texture, 3); } - commandBuffer.Push(node->Mesh, materials[materials.size() - 1], node->GetTransform()); + commandBuffer.Push(node->mesh, materials[materials.size() - 1], node->GetTransform()); } else if (samplerUniforms.find("background") != samplerUniforms.end()) { // we have a background scene node, add those as well materials.push_back(new Material(m_PBR->m_ProbeCaptureBackgroundShader)); - materials[materials.size() - 1]->SetTextureCube("background", samplerUniforms["background"].TextureCube, 0); - materials[materials.size() - 1]->DepthCompare = node->Material->DepthCompare; - commandBuffer.Push(node->Mesh, materials[materials.size() - 1], node->GetTransform()); + materials[materials.size() - 1]->SetTextureCube("background", samplerUniforms["background"].textureCube, 0); + materials[materials.size() - 1]->DepthCompare = node->material->DepthCompare; + commandBuffer.Push(node->mesh, materials[materials.size() - 1], node->GetTransform()); } } for (unsigned int i = 0; i < node->GetChildCount(); ++i) @@ -628,8 +628,8 @@ namespace Cell // ------------------------------------------------------------------------ void Renderer::renderCustomCommand(RenderCommand* command, Camera* customCamera, bool updateGLSettings) { - Material *material = command->Material; - Mesh *mesh = command->Mesh; + Material *material = command->material; + Mesh *mesh = command->mesh; // update global GL blend state based on material if (updateGLSettings) @@ -654,8 +654,8 @@ namespace Cell material->GetShader()->SetMatrix("view", customCamera->View); material->GetShader()->SetVector("CamPos", customCamera->Position); } - material->GetShader()->SetMatrix("model", command->Transform); - material->GetShader()->SetMatrix("prevModel", command->PrevTransform); + material->GetShader()->SetMatrix("model", command->transform); + material->GetShader()->SetMatrix("prevModel", command->prevTransform); material->GetShader()->SetBool("ShadowsEnabled", Shadows); if (Shadows && material->Type == MATERIAL_CUSTOM && material->ShadowReceive) @@ -675,9 +675,9 @@ namespace Cell for (auto it = samplers->begin(); it != samplers->end(); ++it) { if (it->second.Type == SHADER_TYPE_SAMPLERCUBE) - it->second.TextureCube->Bind(it->second.Unit); + it->second.textureCube->Bind(it->second.Unit); else - it->second.Texture->Bind(it->second.Unit); + it->second.texture->Bind(it->second.Unit); } // set uniform state of material @@ -930,8 +930,8 @@ namespace Cell shadowShader->SetMatrix("projection", projection); shadowShader->SetMatrix("view", view); - shadowShader->SetMatrix("model", command->Transform); + shadowShader->SetMatrix("model", command->transform); - renderMesh(command->Mesh, shadowShader); + renderMesh(command->mesh, shadowShader); } } \ No newline at end of file diff --git a/cell/scene/scene_node.h b/cell/scene/scene_node.h index 68df1cb..b31d8a0 100644 --- a/cell/scene/scene_node.h +++ b/cell/scene/scene_node.h @@ -28,8 +28,8 @@ namespace Cell { public: // each node contains relevant render state - Mesh* Mesh; - Material* Material; + Mesh* mesh; + Material* material; // bounding box math::vec3 BoxMin = math::vec3(-99999.0f); diff --git a/cell/shading/shading_types.h b/cell/shading/shading_types.h index 7f94178..4f87182 100644 --- a/cell/shading/shading_types.h +++ b/cell/shading/shading_types.h @@ -1,8 +1,8 @@ #ifndef CELL_SHADING_SHADING_TYPES_H #define CELL_SHADING_SHADING_TYPES_H -#include #include +#include #include @@ -39,13 +39,12 @@ namespace Cell struct UniformValue { SHADER_TYPE Type; - // TODO(Joey): now each element takes up the space of its largest + // TODO(Joey): now each element takes up the space of its largest // element (mat4) which is 64 bytes; come up with a better solution! - union - { - bool Bool; - int Int; - float Float; + union { + bool Bool; + int Int; + float Float; math::vec2 Vec2; math::vec3 Vec3; @@ -62,10 +61,9 @@ namespace Cell { SHADER_TYPE Type; unsigned int Unit; - union - { - Texture *Texture; - TextureCube *TextureCube; + union { + Texture* texture; + TextureCube* textureCube; }; UniformValueSampler() {} From eef189340b9e66acdf9c83ebc5a65a1751c40bcb Mon Sep 17 00:00:00 2001 From: Jens Behley Date: Tue, 27 Mar 2018 13:04:24 +0200 Subject: [PATCH 14/31] renaming of member variable due to issue with the changed meaning. --- cell/renderer/renderer.cpp | 14 +++++++------- cell/resources/mesh_loader.cpp | 16 ++++++++-------- cell/scene/background.cpp | 20 ++++++++++---------- cell/scene/scene.cpp | 20 ++++++++++---------- cell/scene/scene_node.h | 4 ++-- cell/shading/material.cpp | 4 ++-- 6 files changed, 39 insertions(+), 39 deletions(-) diff --git a/cell/renderer/renderer.cpp b/cell/renderer/renderer.cpp index 8ca5344..2ff7ad6 100644 --- a/cell/renderer/renderer.cpp +++ b/cell/renderer/renderer.cpp @@ -208,8 +208,8 @@ namespace Cell // only push render command if the child isn't a container node. if (node->mesh) { - math::vec3 boxMinWorld = node->GetWorldPosition() + (node->GetWorldScale() * node->BoxMin); - math::vec3 boxMaxWorld = node->GetWorldPosition() + (node->GetWorldScale() * node->BoxMax); + math::vec3 boxMinWorld = node->GetWorldPosition() + (node->GetWorldScale() * node->boxMin); + math::vec3 boxMaxWorld = node->GetWorldPosition() + (node->GetWorldScale() * node->boxMax); m_CommandBuffer->Push(node->mesh, node->material, node->GetTransform(), node->GetPrevTransform(), boxMinWorld, boxMaxWorld, target); } for(unsigned int i = 0; i < node->GetChildCount(); ++i) @@ -730,7 +730,7 @@ namespace Cell // create a command buffer specifically for this operation (as to not conflict with main // command buffer) CommandBuffer commandBuffer(this); - commandBuffer.Push(scene->Mesh, scene->Material, scene->GetTransform()); + commandBuffer.Push(scene->mesh, scene->material, scene->GetTransform()); // recursive function transformed to iterative version by maintaining a stack std::stack childStack; for (unsigned int i = 0; i < scene->GetChildCount(); ++i) @@ -739,7 +739,7 @@ namespace Cell { SceneNode *child = childStack.top(); childStack.pop(); - commandBuffer.Push(child->Mesh, child->Material, child->GetTransform()); + commandBuffer.Push(child->mesh, child->material, child->GetTransform()); for (unsigned int i = 0; i < child->GetChildCount(); ++i) childStack.push(child->GetChildByIndex(i)); } @@ -762,8 +762,8 @@ namespace Cell }; // resize target dimensions based on mip level we're rendering. - float width = (float)target->FaceWidth * pow(0.5, mipLevel); - float height = (float)target->FaceHeight * pow(0.5, mipLevel); + float width = (float)target->FaceWidth * std::pow(0.5, mipLevel); + float height = (float)target->FaceHeight * std::pow(0.5, mipLevel); glBindFramebuffer(GL_FRAMEBUFFER, m_FramebufferCubemap); glBindRenderbuffer(GL_RENDERBUFFER, m_CubemapDepthRBO); @@ -785,7 +785,7 @@ namespace Cell for (unsigned int i = 0; i < renderCommands.size(); ++i) { // cubemap generation only works w/ custom materials - assert(renderCommands[i].Material->Type == MATERIAL_CUSTOM); + assert(renderCommands[i].material->Type == MATERIAL_CUSTOM); renderCustomCommand(&renderCommands[i], camera); } } diff --git a/cell/resources/mesh_loader.cpp b/cell/resources/mesh_loader.cpp index 0d99b78..193a7df 100644 --- a/cell/resources/mesh_loader.cpp +++ b/cell/resources/mesh_loader.cpp @@ -68,22 +68,22 @@ namespace Cell // if we only have one mesh, this node itself contains the mesh/material. if (aNode->mNumMeshes == 1) { - node->Mesh = mesh; + node->mesh = mesh; if (setDefaultMaterial) { - node->Material = material; + node->material = material; } - node->BoxMin = boxMin; - node->BoxMax = boxMax; + node->boxMin = boxMin; + node->boxMax = boxMax; } // otherwise, the meshes are considered on equal depth of its children else { SceneNode* child = new SceneNode(0); - child->Mesh = mesh; - child->Material = material; - child->BoxMin = boxMin; - child->BoxMax = boxMax; + child->mesh = mesh; + child->material = material; + child->boxMin = boxMin; + child->boxMax = boxMax; node->AddChild(child); } } diff --git a/cell/scene/background.cpp b/cell/scene/background.cpp index d5e8665..6b6f06b 100644 --- a/cell/scene/background.cpp +++ b/cell/scene/background.cpp @@ -17,17 +17,17 @@ namespace Cell Scene::Root->AddChild(this); m_Shader = Resources::LoadShader("background", "shaders/background.vs", "shaders/background.fs"); - Material = new Cell::Material(m_Shader); - Mesh = new Cell::Cube; - BoxMin = math::vec3(-99999.0); - BoxMax = math::vec3( 99999.0); + material = new Cell::Material(m_Shader); + mesh = new Cell::Cube; + boxMin = math::vec3(-99999.0); + boxMax = math::vec3( 99999.0); // default material configuration - Material->SetFloat("Exposure", 1.0f); - Material->DepthCompare = GL_LEQUAL; - Material->Cull = false; - Material->ShadowCast = false; - Material->ShadowReceive = false; + material->SetFloat("Exposure", 1.0f); + material->DepthCompare = GL_LEQUAL; + material->Cull = false; + material->ShadowCast = false; + material->ShadowReceive = false; } // -------------------------------------------------------------------------------------------- Background::~Background() @@ -38,6 +38,6 @@ namespace Cell void Background::SetCubemap(TextureCube* cubemap) { m_CubeMap = cubemap; - Material->SetTextureCube("background", m_CubeMap, 0); + material->SetTextureCube("background", m_CubeMap, 0); } }; \ No newline at end of file diff --git a/cell/scene/scene.cpp b/cell/scene/scene.cpp index b4d12d7..49d4783 100644 --- a/cell/scene/scene.cpp +++ b/cell/scene/scene.cpp @@ -30,8 +30,8 @@ namespace Cell { SceneNode* node = new SceneNode(Scene::CounterID++); - node->Mesh = mesh; - node->Material = material; + node->mesh = mesh; + node->material = material; // keep a global rerefence to this scene node s.t. we can clear the scene's nodes for // memory management: end of program or when switching scenes. @@ -43,10 +43,10 @@ namespace Cell { SceneNode *newNode = new SceneNode(Scene::CounterID++); - newNode->Mesh = node->Mesh; - newNode->Material = node->Material; - newNode->BoxMin = node->BoxMin; - newNode->BoxMax = node->BoxMax; + newNode->mesh = node->mesh; + newNode->material = node->material; + newNode->boxMin = node->boxMin; + newNode->boxMax = node->boxMax; // traverse through the list of children and add them correspondingly std::stack nodeStack; @@ -58,10 +58,10 @@ namespace Cell nodeStack.pop(); // similarly, create SceneNode for each child and push to scene node memory list. SceneNode* newChild = new SceneNode(Scene::CounterID++); - newChild->Mesh = child->Mesh; - newChild->Material = child->Material; - newChild->BoxMin = child->BoxMin; - newChild->BoxMax = child->BoxMax; + newChild->mesh = child->mesh; + newChild->material = child->material; + newChild->boxMin = child->boxMin; + newChild->boxMax = child->boxMax; newNode->AddChild(newChild); for (unsigned int i = 0; i < child->GetChildCount(); ++i) diff --git a/cell/scene/scene_node.h b/cell/scene/scene_node.h index b31d8a0..0acb256 100644 --- a/cell/scene/scene_node.h +++ b/cell/scene/scene_node.h @@ -32,8 +32,8 @@ namespace Cell Material* material; // bounding box - math::vec3 BoxMin = math::vec3(-99999.0f); - math::vec3 BoxMax = math::vec3( 99999.0f); + math::vec3 boxMin = math::vec3(-99999.0f); + math::vec3 boxMax = math::vec3( 99999.0f); private: std::vector m_Children; SceneNode *m_Parent; diff --git a/cell/shading/material.cpp b/cell/shading/material.cpp index 9beeb55..9a591f9 100644 --- a/cell/shading/material.cpp +++ b/cell/shading/material.cpp @@ -73,7 +73,7 @@ namespace Cell void Material::SetTexture(std::string name, Texture* value, unsigned int unit) { m_SamplerUniforms[name].Unit = unit; - m_SamplerUniforms[name].Texture = value; + m_SamplerUniforms[name].texture = value; switch (value->Target) { @@ -102,7 +102,7 @@ namespace Cell { m_SamplerUniforms[name].Unit = unit; m_SamplerUniforms[name].Type = SHADER_TYPE_SAMPLERCUBE; - m_SamplerUniforms[name].TextureCube = value; + m_SamplerUniforms[name].textureCube = value; if (m_Shader) { From 35a46cb209c0c994255cb8d6172da3b9e8cd014b Mon Sep 17 00:00:00 2001 From: Jens Behley Date: Tue, 27 Mar 2018 13:05:38 +0200 Subject: [PATCH 15/31] constness & consitency of template arguments. --- math/linear_algebra/matrix.h | 8 ++++---- math/linear_algebra/operation.h | 2 +- math/linear_algebra/transformation.h | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/math/linear_algebra/matrix.h b/math/linear_algebra/matrix.h index fcd8281..534355e 100644 --- a/math/linear_algebra/matrix.h +++ b/math/linear_algebra/matrix.h @@ -105,7 +105,7 @@ namespace math // defined; they should be defined as operations on a matrix completely filled with the // respective scalar. template - matrix operator+(matrix& lhs, matrix& rhs) + matrix operator+(const matrix& lhs, const matrix& rhs) { matrix result; for (std::size_t col = 0; col < n; ++col) @@ -120,7 +120,7 @@ namespace math // subtraction // -------------------------------------------------------------------------------------------- template - matrix operator-(matrix& lhs, matrix& rhs) + matrix operator-(const matrix& lhs, const matrix& rhs) { matrix result; for (std::size_t col = 0; col < n; ++col) @@ -139,7 +139,7 @@ namespace math // equal the number of rows (n) on the RHS matrix. Theresult of the matrix multiplication is // then always a matrix of dimensions m x o (LHS:rows x RHS:cols) dimensions. template - matrix operator*(matrix& lhs, matrix& rhs) + matrix operator*(const matrix& lhs, const matrix& rhs) { matrix result; for (std::size_t col = 0; col < o; ++col) @@ -180,7 +180,7 @@ namespace math // rhs vector multiplication. We only define vector-matrix multiplication with the vector on // the right-side of the equation due to the column-major convention. template - vector operator*(matrix& lhs, vector& rhs) + vector operator*(const matrix& lhs, const vector& rhs) { vector result; for (std::size_t row = 0; row < m; ++row) diff --git a/math/linear_algebra/operation.h b/math/linear_algebra/operation.h index 9c4285e..82eead7 100644 --- a/math/linear_algebra/operation.h +++ b/math/linear_algebra/operation.h @@ -88,7 +88,7 @@ namespace math // NOTE(Joey): matrix algebraic operations // --------------------------------------- - template + template < std::size_t m, std::size_t n, typename T> inline matrix transpose(const matrix& mat) { matrix result; diff --git a/math/linear_algebra/transformation.h b/math/linear_algebra/transformation.h index 9ad0df0..a6006a3 100644 --- a/math/linear_algebra/transformation.h +++ b/math/linear_algebra/transformation.h @@ -43,7 +43,7 @@ namespace math } // NOTE(Joey): version w/ reference template - matrix<4, 4, T>& scale(matrix<4, 4, T>& result, vector<3, T>& scale) + matrix<4, 4, T>& scale(matrix<4, 4, T>& result, const vector<3, T>& scale) { // NOTE(Joey): we can do a manual operation on the matrix scale for (std::size_t i = 0; i < 3; ++i) { From 2e991f8041fa85a7fad19950b5a05ad3ea5ed31c Mon Sep 17 00:00:00 2001 From: Jens Behley Date: Tue, 27 Mar 2018 14:12:33 +0200 Subject: [PATCH 16/31] missing intrin.h, replaced with limits. --- utility/timing/diagnostics.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utility/timing/diagnostics.h b/utility/timing/diagnostics.h index f806375..c6a0cb0 100644 --- a/utility/timing/diagnostics.h +++ b/utility/timing/diagnostics.h @@ -3,7 +3,7 @@ #include #include -#include +// #include #include "../std_types.h" From a9919451f0a3ebe477ef95dd55f825990a967b83 Mon Sep 17 00:00:00 2001 From: Jens Behley Date: Tue, 27 Mar 2018 14:13:18 +0200 Subject: [PATCH 17/31] correct packages, compiling assimp, etc. --- CMakeLists.txt | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index df67638..ca0d0df 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,16 +2,20 @@ cmake_minimum_required(VERSION 3.1) project(cell) -# find_package() +find_package(glfw3 REQUIRED) +find_package(OpenGL REQUIRED) set (CMAKE_CXX_STANDARD 11) -include_directories(.) +include_directories(. ${GLFW3_INCLUDE_DIR} ${OPENGL_INCLUDE_DIR}) + +add_subdirectory(vendor/assimp) add_library(cell cell/camera/camera_frustum.cpp cell/camera/camera.cpp cell/camera/fly_camera.cpp + cell/glad/glad.c cell/imgui/imgui_demo.cpp cell/imgui/imgui_draw.cpp cell/imgui/imgui.cpp @@ -65,4 +69,4 @@ add_executable(demo target_link_libraries(utility math) target_link_libraries(cell math utility) -target_link_libraries(demo cell) \ No newline at end of file +target_link_libraries(demo cell assimp ${GLFW3_LIBRARY} ${OPENGL_LIBRARY}) \ No newline at end of file From 125cfd83c2ca66d9ae8f138e41e57a91fb07523c Mon Sep 17 00:00:00 2001 From: Jens Behley Date: Tue, 27 Mar 2018 14:14:16 +0200 Subject: [PATCH 18/31] fixed issue with stb and gcc by using newer version. --- cell/stb/stb_image.h | 2123 ++++++++++++++++++++++++++++-------------- 1 file changed, 1415 insertions(+), 708 deletions(-) diff --git a/cell/stb/stb_image.h b/cell/stb/stb_image.h index a3c1129..d9c21bc 100644 --- a/cell/stb/stb_image.h +++ b/cell/stb/stb_image.h @@ -1,5 +1,5 @@ -/* stb_image - v2.12 - public domain image loader - http://nothings.org/stb_image.h - no warranty implied; use at your own risk +/* stb_image - v2.19 - public domain image loader - http://nothings.org/stb + no warranty implied; use at your own risk Do this: #define STB_IMAGE_IMPLEMENTATION @@ -21,7 +21,7 @@ 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) + PNG 1/2/4/8/16-bit-per-channel TGA (not sure what subset, if a subset) BMP non-1bpp, non-RLE @@ -42,136 +42,26 @@ 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: +LICENSE + + See end of file for license information. + +RECENT REVISION HISTORY: + + 2.19 (2018-02-11) fix warning + 2.18 (2018-01-30) fix warnings + 2.17 (2018-01-29) bugfix, 1-bit BMP, 16-bitness query, fix warnings + 2.16 (2017-07-23) all functions have 16-bit variants; optimizations; bugfixes + 2.15 (2017-03-18) fix png-1,2,4; all Imagenet JPGs; no runtime SSE detection on GCC + 2.14 (2017-03-03) remove deprecated STBI_JPEG_OLD; fixes for Imagenet JPGs + 2.13 (2016-12-04) experimental 16-bit API, only for PNG so far; fixes 2.12 (2016-04-02) fix typo in 2.11 PSD fix that caused crashes 2.11 (2016-04-02) 16-bit PNGS; enable SSE2 in non-gcc x64 RGB-format JPEG; remove white matting in PSD; - allocate large structures on the stack; + allocate large structures on the stack; correct channel count for PNG & BMP 2.10 (2016-01-22) avoid warning introduced in 2.09 2.09 (2016-01-16) 16-bit TGA; comments in PNM files; STBI_REALLOC_SIZED - 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 See end of file for full revision history. @@ -186,34 +76,31 @@ Tom Seddon (pic) Omar Cornut (1/2/4-bit PNG) Thatcher Ulrich (psd) Nicolas Guillemot (vertical flip) Ken Miller (pgm, ppm) Richard Mitton (16-bit PSD) - urraka@github (animated gif) Junggon Kim (PNM comments) - Daniel Gibson (16-bit TGA) - - Optimizations & bugfixes - Fabian "ryg" Giesen + github:urraka (animated gif) Junggon Kim (PNM comments) + Christopher Forseth (animated gif) Daniel Gibson (16-bit TGA) + socks-the-fox (16-bit PNG) + Jeremy Sawicki (handle all ImageNet JPGs) + Optimizations & bugfixes Mikhail Morozov (1-bit BMP) + Fabian "ryg" Giesen Anael Seghezzi (is-16-bit query) Arseny Kapoulkine + John-Mark Allen Bug & warning fixes Marc LeBlanc David Woo Guillaume George Martins Mozeiko - Christpher Lloyd Martin Golini Jerry Jansson Joseph Thomson - Dave Moore Roy Eltham Hayaki Saito Phil Jordan - Won Chun Luke Graham Johan Duparc Nathan Reed - the Horde3D community Thomas Ruf Ronny Chevalier Nick Verigakis - Janez Zemva John Bartholomew Michal Cichon svdijk@github - Jonathan Blow Ken Hamada Tero Hanninen Baldur Karlsson - Laurent Gomila Cort Stratton Sergio Gonzalez romigrou@github - Aruelien Pocheville Thibault Reuille Cass Everitt Matthew Gregan - Ryamond Barbiero Paul Du Bois Engin Manap snagar@github - Michaelangel007@github Oriol Ferrer Mesia socks-the-fox - Blazej Dariusz Roszkowski - - -LICENSE - -This software is dual-licensed to the public domain and under the following -license: you are granted a perpetual, irrevocable license to copy, modify, -publish, and distribute this file as you see fit. - + Christpher Lloyd Jerry Jansson Joseph Thomson Phil Jordan + Dave Moore Roy Eltham Hayaki Saito Nathan Reed + Won Chun Luke Graham Johan Duparc Nick Verigakis + the Horde3D community Thomas Ruf Ronny Chevalier github:rlyeh + Janez Zemva John Bartholomew Michal Cichon github:romigrou + Jonathan Blow Ken Hamada Tero Hanninen github:svdijk + Laurent Gomila Cort Stratton Sergio Gonzalez github:snagar + Aruelien Pocheville Thibault Reuille Cass Everitt github:Zelex + Ryamond Barbiero Paul Du Bois Engin Manap github:grim210 + Aldo Culquicondor Philipp Wiesemann Dale Weiler github:sammyhw + Oriol Ferrer Mesia Josh Tobin Matthew Gregan github:phprus + Julian Raschke Gregory Mullen Baldur Karlsson github:poppolopoppo + Christian Floisand Kevin Schmidt github:darealshinji + Blazej Dariusz Roszkowski github:Michaelangel007 */ #ifndef STBI_INCLUDE_STB_IMAGE_H @@ -222,10 +109,8 @@ publish, and distribute this file as you see fit. // 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): @@ -238,10 +123,10 @@ publish, and distribute this file as you see fit. // 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 +// int *x -- outputs image width in pixels +// int *y -- outputs image height in pixels +// int *channels_in_file -- outputs # of image components in image file +// int desired_channels -- 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 @@ -249,11 +134,12 @@ publish, and distribute this file as you see fit. // 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. +// components N is 'desired_channels' if desired_channels is non-zero, or +// *channels_in_file otherwise. If desired_channels is non-zero, +// *channels_in_file has the number of components that _would_ have been +// output otherwise. E.g. if you set desired_channels to 4, you will always +// get RGBA output, but you can check *channels_in_file 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: @@ -265,10 +151,10 @@ publish, and distribute this file as you see fit. // 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 +// and *x, *y, *channels_in_file 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. @@ -287,13 +173,13 @@ publish, and distribute this file as you see fit. // 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. +// 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") +// - Small source code footprint ("easy to maintain") // - No dependencies ("ease of use") // // =========================================================================== @@ -325,13 +211,6 @@ publish, and distribute this file as you see fit. // (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. @@ -387,6 +266,41 @@ publish, and distribute this file as you see fit. // says there's premultiplied data (currently only happens in iPhone images, // and only if iPhone convert-to-rgb processing is on). // +// =========================================================================== +// +// ADDITIONAL CONFIGURATION +// +// - 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) +// +// - If you use STBI_NO_PNG (or _ONLY_ without PNG), and you still +// want the zlib decoder to be available, #define STBI_SUPPORT_ZLIB +// #ifndef STBI_NO_STDIO @@ -397,7 +311,7 @@ publish, and distribute this file as you see fit. enum { - STBI_default = 0, // only used for req_comp + STBI_default = 0, // only used for desired_channels STBI_grey = 1, STBI_grey_alpha = 2, @@ -406,6 +320,7 @@ enum }; typedef unsigned char stbi_uc; +typedef unsigned short stbi_us; #ifdef __cplusplus extern "C" { @@ -433,22 +348,48 @@ typedef struct 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); +//////////////////////////////////// +// +// 8-bits-per-channel interface +// + +STBIDEF stbi_uc *stbi_load_from_memory (stbi_uc const *buffer, int len , int *x, int *y, int *channels_in_file, int desired_channels); +STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk , void *user, int *x, int *y, int *channels_in_file, int desired_channels); +#ifndef STBI_NO_GIF +STBIDEF stbi_uc *stbi_load_gif_from_memory(stbi_uc const *buffer, int len, int **delays, int *x, int *y, int *z, int *comp, int req_comp); +#endif + #ifndef STBI_NO_STDIO -STBIDEF stbi_uc *stbi_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp); +STBIDEF stbi_uc *stbi_load (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels); +STBIDEF stbi_uc *stbi_load_from_file (FILE *f, int *x, int *y, int *channels_in_file, int desired_channels); // for stbi_load_from_file, file pointer is left pointing immediately after image #endif +//////////////////////////////////// +// +// 16-bits-per-channel interface +// + +STBIDEF stbi_us *stbi_load_16_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels); +STBIDEF stbi_us *stbi_load_16_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels); + +#ifndef STBI_NO_STDIO +STBIDEF stbi_us *stbi_load_16 (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels); +STBIDEF stbi_us *stbi_load_from_file_16(FILE *f, int *x, int *y, int *channels_in_file, int desired_channels); +#endif + +//////////////////////////////////// +// +// float-per-channel interface +// #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); + STBIDEF float *stbi_loadf_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels); + STBIDEF float *stbi_loadf_from_callbacks (stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels); #ifndef STBI_NO_STDIO - STBIDEF float *stbi_loadf_from_file (FILE *f, int *x, int *y, int *comp, int req_comp); + STBIDEF float *stbi_loadf (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels); + STBIDEF float *stbi_loadf_from_file (FILE *f, int *x, int *y, int *channels_in_file, int desired_channels); #endif #endif @@ -481,11 +422,14 @@ 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); +STBIDEF int stbi_is_16_bit_from_memory(stbi_uc const *buffer, int len); +STBIDEF int stbi_is_16_bit_from_callbacks(stbi_io_callbacks const *clbk, void *user); #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); - +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); +STBIDEF int stbi_is_16_bit (char const *filename); +STBIDEF int stbi_is_16_bit_from_file(FILE *f); #endif @@ -566,9 +510,10 @@ STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const ch #include // ptrdiff_t on osx #include #include +#include #if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) -#include // ldexp +#include // ldexp, pow #endif #ifndef STBI_NO_STDIO @@ -649,12 +594,14 @@ typedef unsigned char validate_uint32[sizeof(stbi__uint32)==4 ? 1 : -1]; #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? +#if defined(__GNUC__) && defined(STBI__X86_TARGET) && !defined(__SSE2__) && !defined(STBI_NO_SIMD) // 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 ) +// which in turn means it gets to use SSE2 everywhere. This is unfortunate, +// but previous attempts to provide the SSE2 functions with runtime +// detection caused numerous issues. The way architecture extensions are +// exposed in GCC/Clang is, sadly, not really suited for one-file libs. +// New behavior: if compiled with -msse2, we use SSE2 without any +// detection; if not, we don't use it at all. #define STBI_NO_SIMD #endif @@ -702,7 +649,7 @@ static int stbi__cpuid3(void) #define STBI_SIMD_ALIGN(type, name) __declspec(align(16)) type name -static int stbi__sse2_available() +static int stbi__sse2_available(void) { int info3 = stbi__cpuid3(); return ((info3 >> 26) & 1) != 0; @@ -710,16 +657,12 @@ static int stbi__sse2_available() #else // assume GCC-style if not VC++ #define STBI_SIMD_ALIGN(type, name) type name __attribute__((aligned(16))) -static int stbi__sse2_available() +static int stbi__sse2_available(void) { -#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 + // If we're even attempting to compile this on GCC/Clang, that means + // -msse2 is on, which means the compiler is allowed to use SSE2 + // instructions at will, and so are we. + return 1; } #endif #endif @@ -827,57 +770,73 @@ static void stbi__rewind(stbi__context *s) s->img_buffer_end = s->img_buffer_original_end; } +enum +{ + STBI_ORDER_RGB, + STBI_ORDER_BGR +}; + +typedef struct +{ + int bits_per_channel; + int num_channels; + int channel_order; +} stbi__result_info; + #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 void *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); 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 void *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); static int stbi__png_info(stbi__context *s, int *x, int *y, int *comp); +static int stbi__png_is16(stbi__context *s); #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 void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); 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 void *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); 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 void *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc); static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp); +static int stbi__psd_is16(stbi__context *s); #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 float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); 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 void *stbi__pic_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); 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 void *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static void *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y, int *z, 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 void *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp); #endif @@ -900,6 +859,81 @@ static void *stbi__malloc(size_t size) return STBI_MALLOC(size); } +// stb_image uses ints pervasively, including for offset calculations. +// therefore the largest decoded image size we can support with the +// current code, even on 64-bit targets, is INT_MAX. this is not a +// significant limitation for the intended use case. +// +// we do, however, need to make sure our size calculations don't +// overflow. hence a few helper functions for size calculations that +// multiply integers together, making sure that they're non-negative +// and no overflow occurs. + +// return 1 if the sum is valid, 0 on overflow. +// negative terms are considered invalid. +static int stbi__addsizes_valid(int a, int b) +{ + if (b < 0) return 0; + // now 0 <= b <= INT_MAX, hence also + // 0 <= INT_MAX - b <= INTMAX. + // And "a + b <= INT_MAX" (which might overflow) is the + // same as a <= INT_MAX - b (no overflow) + return a <= INT_MAX - b; +} + +// returns 1 if the product is valid, 0 on overflow. +// negative factors are considered invalid. +static int stbi__mul2sizes_valid(int a, int b) +{ + if (a < 0 || b < 0) return 0; + if (b == 0) return 1; // mul-by-0 is always safe + // portable way to check for no overflows in a*b + return a <= INT_MAX/b; +} + +// returns 1 if "a*b + add" has no negative terms/factors and doesn't overflow +static int stbi__mad2sizes_valid(int a, int b, int add) +{ + return stbi__mul2sizes_valid(a, b) && stbi__addsizes_valid(a*b, add); +} + +// returns 1 if "a*b*c + add" has no negative terms/factors and doesn't overflow +static int stbi__mad3sizes_valid(int a, int b, int c, int add) +{ + return stbi__mul2sizes_valid(a, b) && stbi__mul2sizes_valid(a*b, c) && + stbi__addsizes_valid(a*b*c, add); +} + +// returns 1 if "a*b*c*d + add" has no negative terms/factors and doesn't overflow +#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) +static int stbi__mad4sizes_valid(int a, int b, int c, int d, int add) +{ + return stbi__mul2sizes_valid(a, b) && stbi__mul2sizes_valid(a*b, c) && + stbi__mul2sizes_valid(a*b*c, d) && stbi__addsizes_valid(a*b*c*d, add); +} +#endif + +// mallocs with size overflow checking +static void *stbi__malloc_mad2(int a, int b, int add) +{ + if (!stbi__mad2sizes_valid(a, b, add)) return NULL; + return stbi__malloc(a*b + add); +} + +static void *stbi__malloc_mad3(int a, int b, int c, int add) +{ + if (!stbi__mad3sizes_valid(a, b, c, add)) return NULL; + return stbi__malloc(a*b*c + add); +} + +#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) +static void *stbi__malloc_mad4(int a, int b, int c, int d, int add) +{ + if (!stbi__mad4sizes_valid(a, b, c, d, add)) return NULL; + return stbi__malloc(a*b*c*d + add); +} +#endif + // stbi__err - error // stbi__errpf - error returning pointer to float // stbi__errpuc - error returning pointer to unsigned char @@ -935,33 +969,38 @@ 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) +static void *stbi__load_main(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc) { + memset(ri, 0, sizeof(*ri)); // make sure it's initialized if we add new fields + ri->bits_per_channel = 8; // default is 8 so most paths don't have to be changed + ri->channel_order = STBI_ORDER_RGB; // all current input & output are this, but this is here so we can add BGR order + ri->num_channels = 0; + #ifndef STBI_NO_JPEG - if (stbi__jpeg_test(s)) return stbi__jpeg_load(s,x,y,comp,req_comp); + if (stbi__jpeg_test(s)) return stbi__jpeg_load(s,x,y,comp,req_comp, ri); #endif #ifndef STBI_NO_PNG - if (stbi__png_test(s)) return stbi__png_load(s,x,y,comp,req_comp); + if (stbi__png_test(s)) return stbi__png_load(s,x,y,comp,req_comp, ri); #endif #ifndef STBI_NO_BMP - if (stbi__bmp_test(s)) return stbi__bmp_load(s,x,y,comp,req_comp); + if (stbi__bmp_test(s)) return stbi__bmp_load(s,x,y,comp,req_comp, ri); #endif #ifndef STBI_NO_GIF - if (stbi__gif_test(s)) return stbi__gif_load(s,x,y,comp,req_comp); + if (stbi__gif_test(s)) return stbi__gif_load(s,x,y,comp,req_comp, ri); #endif #ifndef STBI_NO_PSD - if (stbi__psd_test(s)) return stbi__psd_load(s,x,y,comp,req_comp); + if (stbi__psd_test(s)) return stbi__psd_load(s,x,y,comp,req_comp, ri, bpc); #endif #ifndef STBI_NO_PIC - if (stbi__pic_test(s)) return stbi__pic_load(s,x,y,comp,req_comp); + if (stbi__pic_test(s)) return stbi__pic_load(s,x,y,comp,req_comp, ri); #endif #ifndef STBI_NO_PNM - if (stbi__pnm_test(s)) return stbi__pnm_load(s,x,y,comp,req_comp); + if (stbi__pnm_test(s)) return stbi__pnm_load(s,x,y,comp,req_comp, ri); #endif #ifndef STBI_NO_HDR if (stbi__hdr_test(s)) { - float *hdr = stbi__hdr_load(s, x,y,comp,req_comp); + float *hdr = stbi__hdr_load(s, x,y,comp,req_comp, ri); return stbi__hdr_to_ldr(hdr, *x, *y, req_comp ? req_comp : *comp); } #endif @@ -969,56 +1008,135 @@ static unsigned char *stbi__load_main(stbi__context *s, int *x, int *y, int *com #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); + return stbi__tga_load(s,x,y,comp,req_comp, ri); #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) +static stbi_uc *stbi__convert_16_to_8(stbi__uint16 *orig, int w, int h, int channels) { - unsigned char *result = stbi__load_main(s, x, y, comp, req_comp); + int i; + int img_len = w * h * channels; + stbi_uc *reduced; - 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; - } - } + reduced = (stbi_uc *) stbi__malloc(img_len); + if (reduced == NULL) return stbi__errpuc("outofmem", "Out of memory"); + + for (i = 0; i < img_len; ++i) + reduced[i] = (stbi_uc)((orig[i] >> 8) & 0xFF); // top half of each byte is sufficient approx of 16->8 bit scaling + + STBI_FREE(orig); + return reduced; +} + +static stbi__uint16 *stbi__convert_8_to_16(stbi_uc *orig, int w, int h, int channels) +{ + int i; + int img_len = w * h * channels; + stbi__uint16 *enlarged; + + enlarged = (stbi__uint16 *) stbi__malloc(img_len*2); + if (enlarged == NULL) return (stbi__uint16 *) stbi__errpuc("outofmem", "Out of memory"); + + for (i = 0; i < img_len; ++i) + enlarged[i] = (stbi__uint16)((orig[i] << 8) + orig[i]); // replicate to high and low byte, maps 0->0, 255->0xffff + + STBI_FREE(orig); + return enlarged; +} + +static void stbi__vertical_flip(void *image, int w, int h, int bytes_per_pixel) +{ + int row; + size_t bytes_per_row = (size_t)w * bytes_per_pixel; + stbi_uc temp[2048]; + stbi_uc *bytes = (stbi_uc *)image; + + for (row = 0; row < (h>>1); row++) { + stbi_uc *row0 = bytes + row*bytes_per_row; + stbi_uc *row1 = bytes + (h - row - 1)*bytes_per_row; + // swap row0 with row1 + size_t bytes_left = bytes_per_row; + while (bytes_left) { + size_t bytes_copy = (bytes_left < sizeof(temp)) ? bytes_left : sizeof(temp); + memcpy(temp, row0, bytes_copy); + memcpy(row0, row1, bytes_copy); + memcpy(row1, temp, bytes_copy); + row0 += bytes_copy; + row1 += bytes_copy; + bytes_left -= bytes_copy; } } +} - return result; +static void stbi__vertical_flip_slices(void *image, int w, int h, int z, int bytes_per_pixel) +{ + int slice; + int slice_size = w * h * bytes_per_pixel; + + stbi_uc *bytes = (stbi_uc *)image; + for (slice = 0; slice < z; ++slice) { + stbi__vertical_flip(bytes, w, h, bytes_per_pixel); + bytes += slice_size; + } } -#ifndef STBI_NO_HDR +static unsigned char *stbi__load_and_postprocess_8bit(stbi__context *s, int *x, int *y, int *comp, int req_comp) +{ + stbi__result_info ri; + void *result = stbi__load_main(s, x, y, comp, req_comp, &ri, 8); + + if (result == NULL) + return NULL; + + if (ri.bits_per_channel != 8) { + STBI_ASSERT(ri.bits_per_channel == 16); + result = stbi__convert_16_to_8((stbi__uint16 *) result, *x, *y, req_comp == 0 ? *comp : req_comp); + ri.bits_per_channel = 8; + } + + // @TODO: move stbi__convert_format to here + + if (stbi__vertically_flip_on_load) { + int channels = req_comp ? req_comp : *comp; + stbi__vertical_flip(result, *x, *y, channels * sizeof(stbi_uc)); + } + + return (unsigned char *) result; +} + +static stbi__uint16 *stbi__load_and_postprocess_16bit(stbi__context *s, int *x, int *y, int *comp, int req_comp) +{ + stbi__result_info ri; + void *result = stbi__load_main(s, x, y, comp, req_comp, &ri, 16); + + if (result == NULL) + return NULL; + + if (ri.bits_per_channel != 16) { + STBI_ASSERT(ri.bits_per_channel == 8); + result = stbi__convert_8_to_16((stbi_uc *) result, *x, *y, req_comp == 0 ? *comp : req_comp); + ri.bits_per_channel = 16; + } + + // @TODO: move stbi__convert_format16 to here + // @TODO: special case RGB-to-Y (and RGBA-to-YA) for 8-bit-to-16-bit case to keep more precision + + if (stbi__vertically_flip_on_load) { + int channels = req_comp ? req_comp : *comp; + stbi__vertical_flip(result, *x, *y, channels * sizeof(stbi__uint16)); + } + + return (stbi__uint16 *) result; +} + +#if !defined(STBI_NO_HDR) || !defined(STBI_NO_LINEAR) 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; - } - } - } + int channels = req_comp ? req_comp : *comp; + stbi__vertical_flip(result, *x, *y, channels * sizeof(float)); } } #endif @@ -1053,28 +1171,83 @@ STBIDEF stbi_uc *stbi_load_from_file(FILE *f, int *x, int *y, int *comp, int req unsigned char *result; stbi__context s; stbi__start_file(&s,f); - result = stbi__load_flip(&s,x,y,comp,req_comp); + result = stbi__load_and_postprocess_8bit(&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; } + +STBIDEF stbi__uint16 *stbi_load_from_file_16(FILE *f, int *x, int *y, int *comp, int req_comp) +{ + stbi__uint16 *result; + stbi__context s; + stbi__start_file(&s,f); + result = stbi__load_and_postprocess_16bit(&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; +} + +STBIDEF stbi_us *stbi_load_16(char const *filename, int *x, int *y, int *comp, int req_comp) +{ + FILE *f = stbi__fopen(filename, "rb"); + stbi__uint16 *result; + if (!f) return (stbi_us *) stbi__errpuc("can't fopen", "Unable to open file"); + result = stbi_load_from_file_16(f,x,y,comp,req_comp); + fclose(f); + return result; +} + + #endif //!STBI_NO_STDIO +STBIDEF stbi_us *stbi_load_16_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels) +{ + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__load_and_postprocess_16bit(&s,x,y,channels_in_file,desired_channels); +} + +STBIDEF stbi_us *stbi_load_16_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels) +{ + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *)clbk, user); + return stbi__load_and_postprocess_16bit(&s,x,y,channels_in_file,desired_channels); +} + 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); + return stbi__load_and_postprocess_8bit(&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); + return stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp); +} + +#ifndef STBI_NO_GIF +STBIDEF stbi_uc *stbi_load_gif_from_memory(stbi_uc const *buffer, int len, int **delays, int *x, int *y, int *z, int *comp, int req_comp) +{ + unsigned char *result; + stbi__context s; + stbi__start_mem(&s,buffer,len); + + result = (unsigned char*) stbi__load_gif_main(&s, delays, x, y, z, comp, req_comp); + if (stbi__vertically_flip_on_load) { + stbi__vertical_flip_slices( result, *x, *y, *z, *comp ); + } + + return result; } +#endif #ifndef STBI_NO_LINEAR static float *stbi__loadf_main(stbi__context *s, int *x, int *y, int *comp, int req_comp) @@ -1082,13 +1255,14 @@ static float *stbi__loadf_main(stbi__context *s, int *x, int *y, int *comp, int unsigned char *data; #ifndef STBI_NO_HDR if (stbi__hdr_test(s)) { - float *hdr_data = stbi__hdr_load(s,x,y,comp,req_comp); + stbi__result_info ri; + float *hdr_data = stbi__hdr_load(s,x,y,comp,req_comp, &ri); 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); + data = stbi__load_and_postprocess_8bit(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"); @@ -1158,12 +1332,16 @@ STBIDEF int stbi_is_hdr (char const *filename) return result; } -STBIDEF int stbi_is_hdr_from_file(FILE *f) +STBIDEF int stbi_is_hdr_from_file(FILE *f) { #ifndef STBI_NO_HDR + long pos = ftell(f); + int res; stbi__context s; stbi__start_file(&s,f); - return stbi__hdr_test(&s); + res = stbi__hdr_test(&s); + fseek(f, pos, SEEK_SET); + return res; #else STBI_NOTUSED(f); return 0; @@ -1346,7 +1524,7 @@ static unsigned char *stbi__convert_format(unsigned char *data, int img_n, int r if (req_comp == img_n) return data; STBI_ASSERT(req_comp >= 1 && req_comp <= 4); - good = (unsigned char *) stbi__malloc(req_comp * x * y); + good = (unsigned char *) stbi__malloc_mad3(req_comp, x, y, 0); if (good == NULL) { STBI_FREE(data); return stbi__errpuc("outofmem", "Out of memory"); @@ -1356,26 +1534,75 @@ static unsigned char *stbi__convert_format(unsigned char *data, int img_n, int r 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) + #define STBI__COMBO(a,b) ((a)*8+(b)) + #define STBI__CASE(a,b) case STBI__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 (STBI__COMBO(img_n, req_comp)) { + STBI__CASE(1,2) { dest[0]=src[0], dest[1]=255; } break; + STBI__CASE(1,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; + STBI__CASE(1,4) { dest[0]=dest[1]=dest[2]=src[0], dest[3]=255; } break; + STBI__CASE(2,1) { dest[0]=src[0]; } break; + STBI__CASE(2,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; + STBI__CASE(2,4) { dest[0]=dest[1]=dest[2]=src[0], dest[3]=src[1]; } break; + STBI__CASE(3,4) { dest[0]=src[0],dest[1]=src[1],dest[2]=src[2],dest[3]=255; } break; + STBI__CASE(3,1) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); } break; + STBI__CASE(3,2) { dest[0]=stbi__compute_y(src[0],src[1],src[2]), dest[1] = 255; } break; + STBI__CASE(4,1) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); } break; + STBI__CASE(4,2) { dest[0]=stbi__compute_y(src[0],src[1],src[2]), dest[1] = src[3]; } break; + STBI__CASE(4,3) { dest[0]=src[0],dest[1]=src[1],dest[2]=src[2]; } break; + default: STBI_ASSERT(0); + } + #undef STBI__CASE + } + + STBI_FREE(data); + return good; +} + +static stbi__uint16 stbi__compute_y_16(int r, int g, int b) +{ + return (stbi__uint16) (((r*77) + (g*150) + (29*b)) >> 8); +} + +static stbi__uint16 *stbi__convert_format16(stbi__uint16 *data, int img_n, int req_comp, unsigned int x, unsigned int y) +{ + int i,j; + stbi__uint16 *good; + + if (req_comp == img_n) return data; + STBI_ASSERT(req_comp >= 1 && req_comp <= 4); + + good = (stbi__uint16 *) stbi__malloc(req_comp * x * y * 2); + if (good == NULL) { + STBI_FREE(data); + return (stbi__uint16 *) stbi__errpuc("outofmem", "Out of memory"); + } + + for (j=0; j < (int) y; ++j) { + stbi__uint16 *src = data + j * x * img_n ; + stbi__uint16 *dest = good + j * x * req_comp; + + #define STBI__COMBO(a,b) ((a)*8+(b)) + #define STBI__CASE(a,b) case STBI__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; + switch (STBI__COMBO(img_n, req_comp)) { + STBI__CASE(1,2) { dest[0]=src[0], dest[1]=0xffff; } break; + STBI__CASE(1,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; + STBI__CASE(1,4) { dest[0]=dest[1]=dest[2]=src[0], dest[3]=0xffff; } break; + STBI__CASE(2,1) { dest[0]=src[0]; } break; + STBI__CASE(2,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; + STBI__CASE(2,4) { dest[0]=dest[1]=dest[2]=src[0], dest[3]=src[1]; } break; + STBI__CASE(3,4) { dest[0]=src[0],dest[1]=src[1],dest[2]=src[2],dest[3]=0xffff; } break; + STBI__CASE(3,1) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); } break; + STBI__CASE(3,2) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]), dest[1] = 0xffff; } break; + STBI__CASE(4,1) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); } break; + STBI__CASE(4,2) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]), dest[1] = src[3]; } break; + STBI__CASE(4,3) { dest[0]=src[0],dest[1]=src[1],dest[2]=src[2]; } break; default: STBI_ASSERT(0); } - #undef CASE + #undef STBI__CASE } STBI_FREE(data); @@ -1386,7 +1613,9 @@ static unsigned char *stbi__convert_format(unsigned char *data, int img_n, int r 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)); + float *output; + if (!data) return NULL; + output = (float *) stbi__malloc_mad4(x, y, comp, sizeof(float), 0); 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; @@ -1406,7 +1635,9 @@ static float *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp) 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); + stbi_uc *output; + if (!data) return NULL; + output = (stbi_uc *) stbi__malloc_mad3(x, y, comp, 0); 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; @@ -1471,7 +1702,7 @@ typedef struct stbi__context *s; stbi__huffman huff_dc[4]; stbi__huffman huff_ac[4]; - stbi_uc dequant[4][64]; + stbi__uint16 dequant[4][64]; stbi__int16 fast_ac[4][1 << FAST_BITS]; // sizes for components, interleaved MCUs @@ -1507,6 +1738,8 @@ typedef struct int succ_high; int succ_low; int eob_run; + int jfif; + int app14_color_transform; // Adobe APP14 tag int rgb; int scan_n, order[4]; @@ -1520,7 +1753,8 @@ typedef struct static int stbi__build_huffman(stbi__huffman *h, int *count) { - int i,j,k=0,code; + int i,j,k=0; + unsigned int code; // build size list for each symbol (from JPEG spec) for (i=0; i < 16; ++i) for (j=0; j < count[i]; ++j) @@ -1536,7 +1770,7 @@ static int stbi__build_huffman(stbi__huffman *h, int *count) 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"); + if (code-1 >= (1u << 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); @@ -1577,10 +1811,10 @@ static void stbi__build_fast_ac(stbi__int16 *fast_ac, stbi__huffman *h) // 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 (k < m) k += (~0U << 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)); + fast_ac[i] = (stbi__int16) ((k * 256) + (run * 16) + (len + magbits)); } } } @@ -1589,9 +1823,10 @@ static void stbi__build_fast_ac(stbi__int16 *fast_ac, stbi__huffman *h) static void stbi__grow_buffer_unsafe(stbi__jpeg *j) { do { - int b = j->nomore ? 0 : stbi__get8(j->s); + unsigned int b = j->nomore ? 0 : stbi__get8(j->s); if (b == 0xff) { int c = stbi__get8(j->s); + while (c == 0xff) c = stbi__get8(j->s); // consume fill bytes if (c != 0) { j->marker = (unsigned char) c; j->nomore = 1; @@ -1604,7 +1839,7 @@ static void stbi__grow_buffer_unsafe(stbi__jpeg *j) } // (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}; +static const 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) @@ -1657,7 +1892,7 @@ stbi_inline static int stbi__jpeg_huff_decode(stbi__jpeg *j, stbi__huffman *h) } // bias[n] = (-1<s); if (x != 0xff) return STBI__MARKER_none; while (x == 0xff) - x = stbi__get8(j->s); + x = stbi__get8(j->s); // consume repeated 0xff fill bytes return x; } @@ -2440,7 +2675,7 @@ 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->img_comp[0].dc_pred = j->img_comp[1].dc_pred = j->img_comp[2].dc_pred = j->img_comp[3].dc_pred = 0; j->marker = STBI__MARKER_none; j->todo = j->restart_interval ? j->restart_interval : 0x7fffffff; j->eob_run = 0; @@ -2572,7 +2807,7 @@ static int stbi__parse_entropy_coded_data(stbi__jpeg *z) } } -static void stbi__jpeg_dequantize(short *data, stbi_uc *dequant) +static void stbi__jpeg_dequantize(short *data, stbi__uint16 *dequant) { int i; for (i=0; i < 64; ++i) @@ -2614,13 +2849,14 @@ static int stbi__process_marker(stbi__jpeg *z, int m) L = stbi__get16be(z->s)-2; while (L > 0) { int q = stbi__get8(z->s); - int p = q >> 4; + int p = q >> 4, sixteen = (p != 0); int t = q & 15,i; - if (p != 0) return stbi__err("bad DQT type","Corrupt JPEG"); + if (p != 0 && p != 1) 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; + z->dequant[t][stbi__jpeg_dezigzag[i]] = (stbi__uint16)(sixteen ? stbi__get16be(z->s) : stbi__get8(z->s)); + L -= (sixteen ? 129 : 65); } return L==0; @@ -2653,12 +2889,50 @@ static int stbi__process_marker(stbi__jpeg *z, int m) } 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); + L = stbi__get16be(z->s); + if (L < 2) { + if (m == 0xFE) + return stbi__err("bad COM len","Corrupt JPEG"); + else + return stbi__err("bad APP len","Corrupt JPEG"); + } + L -= 2; + + if (m == 0xE0 && L >= 5) { // JFIF APP0 segment + static const unsigned char tag[5] = {'J','F','I','F','\0'}; + int ok = 1; + int i; + for (i=0; i < 5; ++i) + if (stbi__get8(z->s) != tag[i]) + ok = 0; + L -= 5; + if (ok) + z->jfif = 1; + } else if (m == 0xEE && L >= 12) { // Adobe APP14 segment + static const unsigned char tag[6] = {'A','d','o','b','e','\0'}; + int ok = 1; + int i; + for (i=0; i < 6; ++i) + if (stbi__get8(z->s) != tag[i]) + ok = 0; + L -= 6; + if (ok) { + stbi__get8(z->s); // version + stbi__get16be(z->s); // flags0 + stbi__get16be(z->s); // flags1 + z->app14_color_transform = stbi__get8(z->s); // color transform + L -= 6; + } + } + + stbi__skip(z->s, L); return 1; } - return 0; + + return stbi__err("unknown marker","Corrupt JPEG"); } // after we see SOS @@ -2701,6 +2975,28 @@ static int stbi__process_scan_header(stbi__jpeg *z) return 1; } +static int stbi__free_jpeg_components(stbi__jpeg *z, int ncomp, int why) +{ + int i; + for (i=0; i < ncomp; ++i) { + if (z->img_comp[i].raw_data) { + STBI_FREE(z->img_comp[i].raw_data); + z->img_comp[i].raw_data = NULL; + z->img_comp[i].data = NULL; + } + if (z->img_comp[i].raw_coeff) { + STBI_FREE(z->img_comp[i].raw_coeff); + z->img_comp[i].raw_coeff = 0; + z->img_comp[i].coeff = 0; + } + if (z->img_comp[i].linebuf) { + STBI_FREE(z->img_comp[i].linebuf); + z->img_comp[i].linebuf = NULL; + } + } + return why; +} + static int stbi__process_frame_header(stbi__jpeg *z, int scan) { stbi__context *s = z->s; @@ -2710,7 +3006,7 @@ static int stbi__process_frame_header(stbi__jpeg *z, int scan) 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 + if (c != 3 && c != 1 && c != 4) return stbi__err("bad component count","Corrupt JPEG"); s->img_n = c; for (i=0; i < c; ++i) { z->img_comp[i].data = NULL; @@ -2721,15 +3017,10 @@ static int stbi__process_frame_header(stbi__jpeg *z, int scan) z->rgb = 0; for (i=0; i < s->img_n; ++i) { - static unsigned char rgb[3] = { 'R', 'G', 'B' }; + static const unsigned char rgb[3] = { 'R', 'G', 'B' }; 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! - // somethings output this (see http://fileformats.archiveteam.org/wiki/JPEG#Color_format) - if (z->img_comp[i].id != rgb[i]) - return stbi__err("bad component ID","Corrupt JPEG"); - ++z->rgb; - } + if (s->img_n == 3 && z->img_comp[i].id == rgb[i]) + ++z->rgb; 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"); @@ -2738,7 +3029,7 @@ static int stbi__process_frame_header(stbi__jpeg *z, int scan) 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"); + if (!stbi__mad3sizes_valid(s->img_x, s->img_y, s->img_n, 0)) 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; @@ -2750,6 +3041,7 @@ static int stbi__process_frame_header(stbi__jpeg *z, int scan) z->img_v_max = v_max; z->img_mcu_w = h_max * 8; z->img_mcu_h = v_max * 8; + // these sizes can't be more than 17 bits 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; @@ -2761,28 +3053,27 @@ static int stbi__process_frame_header(stbi__jpeg *z, int scan) // 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 + // + // img_mcu_x, img_mcu_y: <=17 bits; comp[i].h and .v are <=4 (checked earlier) + // so these muls can't overflow with 32-bit ints (which we require) 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"); - } + z->img_comp[i].coeff = 0; + z->img_comp[i].raw_coeff = 0; + z->img_comp[i].linebuf = NULL; + z->img_comp[i].raw_data = stbi__malloc_mad2(z->img_comp[i].w2, z->img_comp[i].h2, 15); + if (z->img_comp[i].raw_data == NULL) + return stbi__free_jpeg_components(z, i+1, 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); + // w2, h2 are multiples of 8 (see above) + z->img_comp[i].coeff_w = z->img_comp[i].w2 / 8; + z->img_comp[i].coeff_h = z->img_comp[i].h2 / 8; + z->img_comp[i].raw_coeff = stbi__malloc_mad3(z->img_comp[i].w2, z->img_comp[i].h2, sizeof(short), 15); + if (z->img_comp[i].raw_coeff == NULL) + return stbi__free_jpeg_components(z, i+1, stbi__err("outofmem", "Out of memory")); 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; } } @@ -2801,6 +3092,8 @@ static int stbi__process_frame_header(stbi__jpeg *z, int scan) static int stbi__decode_jpeg_header(stbi__jpeg *z, int scan) { int m; + z->jfif = 0; + z->app14_color_transform = -1; // valid values are 0,1,2 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"); @@ -2842,12 +3135,15 @@ static int stbi__decode_jpeg_image(stbi__jpeg *j) 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__DNL(m)) { + int Ld = stbi__get16be(j->s); + stbi__uint32 NL = stbi__get16be(j->s); + if (Ld != 4) return stbi__err("bad DNL len", "Corrupt JPEG"); + if (NL != j->s->img_y) return stbi__err("bad DNL height", "Corrupt JPEG"); } else { if (!stbi__process_marker(j, m)) return 0; } @@ -3066,38 +3362,9 @@ static stbi_uc *stbi__resample_row_generic(stbi_uc *out, stbi_uc *in_near, stbi_ 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) +#define stbi__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; @@ -3106,9 +3373,9 @@ static void stbi__YCbCr_to_RGB_row(stbi_uc *out, const stbi_uc *y, const stbi_uc 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 = y_fixed + cr* stbi__float2fixed(1.40200f); + g = y_fixed + (cr*-stbi__float2fixed(0.71414f)) + ((cb*-stbi__float2fixed(0.34414f)) & 0xffff0000); + b = y_fixed + cb* stbi__float2fixed(1.77200f); r >>= 20; g >>= 20; b >>= 20; @@ -3122,7 +3389,6 @@ static void stbi__YCbCr_to_RGB_row(stbi_uc *out, const stbi_uc *y, const stbi_uc 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) @@ -3241,9 +3507,9 @@ static void stbi__YCbCr_to_RGB_simd(stbi_uc *out, stbi_uc const *y, stbi_uc cons 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 = y_fixed + cr* stbi__float2fixed(1.40200f); + g = y_fixed + cr*-stbi__float2fixed(0.71414f) + ((cb*-stbi__float2fixed(0.34414f)) & 0xffff0000); + b = y_fixed + cb* stbi__float2fixed(1.77200f); r >>= 20; g >>= 20; b >>= 20; @@ -3269,18 +3535,14 @@ static void stbi__setup_jpeg(stbi__jpeg *j) #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 } @@ -3288,23 +3550,7 @@ static void stbi__setup_jpeg(stbi__jpeg *j) // 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; - } - } + stbi__free_jpeg_components(j, j->s->img_n, 0); } typedef struct @@ -3317,9 +3563,16 @@ typedef struct int ypos; // which pre-expansion row we're on } stbi__resample; +// fast 0..255 * 0..255 => 0..255 rounded multiplication +static stbi_uc stbi__blinn_8x8(stbi_uc x, stbi_uc y) +{ + unsigned int t = x*y + 128; + return (stbi_uc) ((t + (t >>8)) >> 8); +} + static stbi_uc *load_jpeg_image(stbi__jpeg *z, int *out_x, int *out_y, int *comp, int req_comp) { - int n, decode_n; + int n, decode_n, is_rgb; z->s->img_n = 0; // make stbi__cleanup_jpeg safe // validate req_comp @@ -3329,9 +3582,11 @@ static stbi_uc *load_jpeg_image(stbi__jpeg *z, int *out_x, int *out_y, int *comp 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; + n = req_comp ? req_comp : z->s->img_n >= 3 ? 3 : 1; - if (z->s->img_n == 3 && n < 3) + is_rgb = z->s->img_n == 3 && (z->rgb == 3 || (z->app14_color_transform == 0 && !z->jfif)); + + if (z->s->img_n == 3 && n < 3 && !is_rgb) decode_n = 1; else decode_n = z->s->img_n; @@ -3368,7 +3623,7 @@ static stbi_uc *load_jpeg_image(stbi__jpeg *z, int *out_x, int *out_y, int *comp } // can't error after this so, this is safe - output = (stbi_uc *) stbi__malloc(n * z->s->img_x * z->s->img_y + 1); + output = (stbi_uc *) stbi__malloc_mad3(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 @@ -3391,7 +3646,7 @@ static stbi_uc *load_jpeg_image(stbi__jpeg *z, int *out_x, int *out_y, int *comp if (n >= 3) { stbi_uc *y = coutput[0]; if (z->s->img_n == 3) { - if (z->rgb == 3) { + if (is_rgb) { for (i=0; i < z->s->img_x; ++i) { out[0] = y[i]; out[1] = coutput[1][i]; @@ -3399,7 +3654,29 @@ static stbi_uc *load_jpeg_image(stbi__jpeg *z, int *out_x, int *out_y, int *comp out[3] = 255; out += n; } - } else { + } else { + z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n); + } + } else if (z->s->img_n == 4) { + if (z->app14_color_transform == 0) { // CMYK + for (i=0; i < z->s->img_x; ++i) { + stbi_uc m = coutput[3][i]; + out[0] = stbi__blinn_8x8(coutput[0][i], m); + out[1] = stbi__blinn_8x8(coutput[1][i], m); + out[2] = stbi__blinn_8x8(coutput[2][i], m); + out[3] = 255; + out += n; + } + } else if (z->app14_color_transform == 2) { // YCCK + z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n); + for (i=0; i < z->s->img_x; ++i) { + stbi_uc m = coutput[3][i]; + out[0] = stbi__blinn_8x8(255 - out[0], m); + out[1] = stbi__blinn_8x8(255 - out[1], m); + out[2] = stbi__blinn_8x8(255 - out[2], m); + out += n; + } + } else { // YCbCr + alpha? Ignore the fourth channel for now z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n); } } else @@ -3409,25 +3686,54 @@ static stbi_uc *load_jpeg_image(stbi__jpeg *z, int *out_x, int *out_y, int *comp 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; + if (is_rgb) { + if (n == 1) + for (i=0; i < z->s->img_x; ++i) + *out++ = stbi__compute_y(coutput[0][i], coutput[1][i], coutput[2][i]); + else { + for (i=0; i < z->s->img_x; ++i, out += 2) { + out[0] = stbi__compute_y(coutput[0][i], coutput[1][i], coutput[2][i]); + out[1] = 255; + } + } + } else if (z->s->img_n == 4 && z->app14_color_transform == 0) { + for (i=0; i < z->s->img_x; ++i) { + stbi_uc m = coutput[3][i]; + stbi_uc r = stbi__blinn_8x8(coutput[0][i], m); + stbi_uc g = stbi__blinn_8x8(coutput[1][i], m); + stbi_uc b = stbi__blinn_8x8(coutput[2][i], m); + out[0] = stbi__compute_y(r, g, b); + out[1] = 255; + out += n; + } + } else if (z->s->img_n == 4 && z->app14_color_transform == 2) { + for (i=0; i < z->s->img_x; ++i) { + out[0] = stbi__blinn_8x8(255 - coutput[0][i], coutput[3][i]); + out[1] = 255; + 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 + if (comp) *comp = z->s->img_n >= 3 ? 3 : 1; // report original components, not output return output; } } -static unsigned char *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int req_comp) +static void *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) { unsigned char* result; stbi__jpeg* j = (stbi__jpeg*) stbi__malloc(sizeof(stbi__jpeg)); + STBI_NOTUSED(ri); j->s = s; stbi__setup_jpeg(j); result = load_jpeg_image(j, x,y,comp,req_comp); @@ -3438,11 +3744,12 @@ static unsigned char *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *com 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__jpeg* j = (stbi__jpeg*)stbi__malloc(sizeof(stbi__jpeg)); + j->s = s; + stbi__setup_jpeg(j); + r = stbi__decode_jpeg_header(j, STBI__SCAN_type); stbi__rewind(s); + STBI_FREE(j); return r; } @@ -3454,7 +3761,7 @@ static int stbi__jpeg_info_raw(stbi__jpeg *j, int *x, int *y, int *comp) } if (x) *x = j->s->img_x; if (y) *y = j->s->img_y; - if (comp) *comp = j->s->img_n; + if (comp) *comp = j->s->img_n >= 3 ? 3 : 1; return 1; } @@ -3511,7 +3818,7 @@ stbi_inline static int stbi__bit_reverse(int v, int bits) return stbi__bitreverse16(v) >> (16-bits); } -static int stbi__zbuild_huffman(stbi__zhuffman *z, stbi_uc *sizelist, int num) +static int stbi__zbuild_huffman(stbi__zhuffman *z, const stbi_uc *sizelist, int num) { int i,k=0; int code, next_code[16], sizes[17]; @@ -3654,18 +3961,18 @@ static int stbi__zexpand(stbi__zbuf *z, char *zout, int n) // need to make room return 1; } -static int stbi__zlength_base[31] = { +static const 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]= +static const 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, +static const 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] = +static const 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) @@ -3712,7 +4019,7 @@ static int stbi__parse_huffman_block(stbi__zbuf *a) 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 }; + static const 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]; @@ -3721,6 +4028,7 @@ static int stbi__compute_huffman_codes(stbi__zbuf *a) int hlit = stbi__zreceive(a,5) + 257; int hdist = stbi__zreceive(a,5) + 1; int hclen = stbi__zreceive(a,4) + 4; + int ntot = hlit + hdist; memset(codelength_sizes, 0, sizeof(codelength_sizes)); for (i=0; i < hclen; ++i) { @@ -3730,27 +4038,29 @@ static int stbi__compute_huffman_codes(stbi__zbuf *a) if (!stbi__zbuild_huffman(&z_codelength, codelength_sizes, 19)) return 0; n = 0; - while (n < hlit + hdist) { + while (n < ntot) { 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); + else { + stbi_uc fill = 0; + if (c == 16) { + c = stbi__zreceive(a,2)+3; + if (n == 0) return stbi__err("bad codelengths", "Corrupt PNG"); + fill = lencodes[n-1]; + } else if (c == 17) + c = stbi__zreceive(a,3)+3; + else { + STBI_ASSERT(c == 18); + c = stbi__zreceive(a,7)+11; + } + if (ntot - n < c) return stbi__err("bad codelengths", "Corrupt PNG"); + memset(lencodes+n, fill, c); n += c; } } - if (n != hlit+hdist) return stbi__err("bad codelengths","Corrupt PNG"); + if (n != ntot) 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; @@ -3798,9 +4108,24 @@ static int stbi__parse_zlib_header(stbi__zbuf *a) 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) +static const stbi_uc stbi__zdefault_length[288] = +{ + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, + 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, + 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, + 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,8,8,8,8,8,8,8,8 +}; +static const stbi_uc stbi__zdefault_distance[32] = +{ + 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5 +}; +/* +Init algorithm: { int i; // use <= to match clearly with spec for (i=0; i <= 143; ++i) stbi__zdefault_length[i] = 8; @@ -3810,6 +4135,7 @@ static void stbi__init_zdefaults(void) for (i=0; i <= 31; ++i) stbi__zdefault_distance[i] = 5; } +*/ static int stbi__parse_zlib(stbi__zbuf *a, int parse_header) { @@ -3828,7 +4154,6 @@ static int stbi__parse_zlib(stbi__zbuf *a, int parse_header) } 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 { @@ -3953,7 +4278,7 @@ static stbi__pngchunk stbi__get_chunk_header(stbi__context *s) static int stbi__check_png_header(stbi__context *s) { - static stbi_uc png_sig[8] = { 137,80,78,71,13,10,26,10 }; + static const 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"); @@ -3999,7 +4324,7 @@ static int stbi__paeth(int a, int b, int c) return c; } -static stbi_uc stbi__depth_scale_table[9] = { 0, 0xff, 0x55, 0, 0x11, 0,0,0, 0x01 }; +static const 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) @@ -4016,20 +4341,21 @@ static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 r int width = x; STBI_ASSERT(out_n == s->img_n || out_n == s->img_n+1); - a->out = (stbi_uc *) stbi__malloc(x * y * output_bytes); // extra bytes to write off the end into + a->out = (stbi_uc *) stbi__malloc_mad3(x, y, output_bytes, 0); // extra bytes to write off the end into if (!a->out) return stbi__err("outofmem", "Out of memory"); + if (!stbi__mad3sizes_valid(img_n, x, depth, 7)) return stbi__err("too large", "Corrupt PNG"); 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"); - } + + // we used to check for exact match between raw_len and img_len on non-interlaced PNGs, + // but issue #276 reported a PNG in the wild that had extra data at the end (all zeros), + // so just check for raw_len < img_len always. + 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; + stbi_uc *prior; int filter = *raw++; if (filter > 4) @@ -4041,6 +4367,7 @@ static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 r filter_bytes = 1; width = img_width_bytes; } + prior = cur - stride; // bugfix: need to compute this after 'cur +=' computation above // if first row, use special filter that doesn't sample previous row if (j == 0) filter = first_row_filter[filter]; @@ -4081,37 +4408,37 @@ static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 r // 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)*filter_bytes; - #define CASE(f) \ + #define STBI__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; + STBI__CASE(STBI__F_sub) { cur[k] = STBI__BYTECAST(raw[k] + cur[k-filter_bytes]); } break; + STBI__CASE(STBI__F_up) { cur[k] = STBI__BYTECAST(raw[k] + prior[k]); } break; + STBI__CASE(STBI__F_avg) { cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k-filter_bytes])>>1)); } break; + STBI__CASE(STBI__F_paeth) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],prior[k],prior[k-filter_bytes])); } break; + STBI__CASE(STBI__F_avg_first) { cur[k] = STBI__BYTECAST(raw[k] + (cur[k-filter_bytes] >> 1)); } break; + STBI__CASE(STBI__F_paeth_first) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],0,0)); } break; } - #undef CASE + #undef STBI__CASE raw += nk; } else { STBI_ASSERT(img_n+1 == out_n); - #define CASE(f) \ + #define STBI__CASE(f) \ case f: \ for (i=x-1; i >= 1; --i, cur[filter_bytes]=255,raw+=filter_bytes,cur+=output_bytes,prior+=output_bytes) \ for (k=0; k < filter_bytes; ++k) switch (filter) { - CASE(STBI__F_none) cur[k] = raw[k]; break; - CASE(STBI__F_sub) cur[k] = STBI__BYTECAST(raw[k] + cur[k- output_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- output_bytes])>>1)); break; - CASE(STBI__F_paeth) cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k- output_bytes],prior[k],prior[k- output_bytes])); break; - CASE(STBI__F_avg_first) cur[k] = STBI__BYTECAST(raw[k] + (cur[k- output_bytes] >> 1)); break; - CASE(STBI__F_paeth_first) cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k- output_bytes],0,0)); break; + STBI__CASE(STBI__F_none) { cur[k] = raw[k]; } break; + STBI__CASE(STBI__F_sub) { cur[k] = STBI__BYTECAST(raw[k] + cur[k- output_bytes]); } break; + STBI__CASE(STBI__F_up) { cur[k] = STBI__BYTECAST(raw[k] + prior[k]); } break; + STBI__CASE(STBI__F_avg) { cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k- output_bytes])>>1)); } break; + STBI__CASE(STBI__F_paeth) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k- output_bytes],prior[k],prior[k- output_bytes])); } break; + STBI__CASE(STBI__F_avg_first) { cur[k] = STBI__BYTECAST(raw[k] + (cur[k- output_bytes] >> 1)); } break; + STBI__CASE(STBI__F_paeth_first) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k- output_bytes],0,0)); } break; } - #undef CASE + #undef STBI__CASE // the loop above sets the high byte of the pixels' alpha, but for // 16 bit png files we also need the low byte set. we'll do that here. @@ -4214,13 +4541,15 @@ static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 r 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) { + int bytes = (depth == 16 ? 2 : 1); + int out_bytes = out_n * bytes; 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); + final = (stbi_uc *) stbi__malloc_mad3(a->s->img_x, a->s->img_y, out_bytes, 0); for (p=0; p < 7; ++p) { int xorig[] = { 0,4,0,2,0,1,0 }; int yorig[] = { 0,0,4,0,2,0,1 }; @@ -4240,8 +4569,8 @@ static int stbi__create_png_image(stbi__png *a, stbi_uc *image_data, stbi__uint3 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); + memcpy(final + out_y*a->s->img_x*out_bytes + out_x*out_bytes, + a->out + (j*x+i)*out_bytes, out_bytes); } } STBI_FREE(a->out); @@ -4309,7 +4638,7 @@ static int stbi__expand_png_palette(stbi__png *a, stbi_uc *palette, int len, int 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); + p = (stbi_uc *) stbi__malloc_mad2(pixel_count, pal_img_n, 0); if (p == NULL) return stbi__err("outofmem", "Out of memory"); // between here and free(out) below, exitting would leak @@ -4341,26 +4670,6 @@ static int stbi__expand_png_palette(stbi__png *a, stbi_uc *palette, int len, int return 1; } -static int stbi__reduce_png(stbi__png *p) -{ - int i; - int img_len = p->s->img_x * p->s->img_y * p->s->img_out_n; - stbi_uc *reduced; - stbi__uint16 *orig = (stbi__uint16*)p->out; - - if (p->depth != 16) return 1; // don't need to do anything if not 16-bit data - - reduced = (stbi_uc *)stbi__malloc(img_len); - if (p == NULL) return stbi__err("outofmem", "Out of memory"); - - for (i = 0; i < img_len; ++i) reduced[i] = (stbi_uc)((orig[i] >> 8) & 0xFF); // top half of each byte is a decent approx of 16->8 bit scaling - - p->out = reduced; - STBI_FREE(orig); - - return 1; -} - static int stbi__unpremultiply_on_load = 0; static int stbi__de_iphone_flag = 0; @@ -4395,9 +4704,10 @@ static void stbi__de_iphone(stbi__png *z) 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; + stbi_uc half = a / 2; + p[0] = (p[2] * 255 + half) / a; + p[1] = (p[1] * 255 + half) / a; + p[2] = ( t * 255 + half) / a; } else { p[0] = p[2]; p[2] = t; @@ -4416,7 +4726,7 @@ static void stbi__de_iphone(stbi__png *z) } } -#define STBI__PNG_TYPE(a,b,c,d) (((a) << 24) + ((b) << 16) + ((c) << 8) + (d)) +#define STBI__PNG_TYPE(a,b,c,d) (((unsigned) (a) << 24) + ((unsigned) (b) << 16) + ((unsigned) (c) << 8) + (unsigned) (d)) static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp) { @@ -4451,7 +4761,7 @@ static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp) s->img_y = stbi__get32be(s); if (s->img_y > (1 << 24)) return stbi__err("too large","Very large image (corrupt?)"); z->depth = stbi__get8(s); if (z->depth != 1 && z->depth != 2 && z->depth != 4 && z->depth != 8 && z->depth != 16) return stbi__err("1/2/4/8/16-bit only","PNG not supported: 1/2/4/8/16-bit only"); color = stbi__get8(s); if (color > 6) return stbi__err("bad ctype","Corrupt PNG"); - if (color == 3 && z->depth == 16) return stbi__err("bad ctype","Corrupt PNG"); + if (color == 3 && z->depth == 16) 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"); @@ -4500,7 +4810,7 @@ static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp) if (c.length != (stbi__uint32) s->img_n*2) return stbi__err("bad tRNS len","Corrupt PNG"); has_trans = 1; if (z->depth == 16) { - for (k = 0; k < s->img_n; ++k) tc16[k] = stbi__get16be(s); // copy the values as-is + for (k = 0; k < s->img_n; ++k) tc16[k] = (stbi__uint16)stbi__get16be(s); // copy the values as-is } else { for (k = 0; k < s->img_n; ++k) tc[k] = (stbi_uc)(stbi__get16be(s) & 255) * stbi__depth_scale_table[z->depth]; // non 8-bit images will be larger } @@ -4560,6 +4870,9 @@ static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp) 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; + } else if (has_trans) { + // non-paletted image with tRNS -> source image has (constant) alpha + ++s->img_n; } STBI_FREE(z->expanded); z->expanded = NULL; return 1; @@ -4587,20 +4900,22 @@ static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp) } } -static unsigned char *stbi__do_png(stbi__png *p, int *x, int *y, int *n, int req_comp) +static void *stbi__do_png(stbi__png *p, int *x, int *y, int *n, int req_comp, stbi__result_info *ri) { - unsigned char *result=NULL; + void *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)) { - if (p->depth == 16) { - if (!stbi__reduce_png(p)) { - return result; - } - } + if (p->depth < 8) + ri->bits_per_channel = 8; + else + ri->bits_per_channel = p->depth; 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); + if (ri->bits_per_channel == 8) + result = stbi__convert_format((unsigned char *) result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y); + else + result = stbi__convert_format16((stbi__uint16 *) 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; } @@ -4615,11 +4930,11 @@ static unsigned char *stbi__do_png(stbi__png *p, int *x, int *y, int *n, int req return result; } -static unsigned char *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp) +static void *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) { stbi__png p; p.s = s; - return stbi__do_png(&p, x,y,comp,req_comp); + return stbi__do_png(&p, x,y,comp,req_comp, ri); } static int stbi__png_test(stbi__context *s) @@ -4648,6 +4963,19 @@ static int stbi__png_info(stbi__context *s, int *x, int *y, int *comp) p.s = s; return stbi__png_info_raw(&p, x, y, comp); } + +static int stbi__png_is16(stbi__context *s) +{ + stbi__png p; + p.s = s; + if (!stbi__png_info_raw(&p, NULL, NULL, NULL)) + return 0; + if (p.depth != 16) { + stbi__rewind(p.s); + return 0; + } + return 1; +} #endif // Microsoft/Windows BMP image @@ -4699,21 +5027,27 @@ static int stbi__bitcount(unsigned int a) return a & 0xff; } +// extract an arbitrarily-aligned N-bit value (N=bits) +// from v, and then make it 8-bits long and fractionally +// extend it to full full range. 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 unsigned int mul_table[9] = { + 0, + 0xff/*0b11111111*/, 0x55/*0b01010101*/, 0x49/*0b01001001*/, 0x11/*0b00010001*/, + 0x21/*0b00100001*/, 0x41/*0b01000001*/, 0x81/*0b10000001*/, 0x01/*0b00000001*/, + }; + static unsigned int shift_table[9] = { + 0, 0,0,1,0,2,4,6,0, + }; + if (shift < 0) + v <<= -shift; + else + v >>= shift; + STBI_ASSERT(v >= 0 && v < 256); + v >>= (8-bits); + STBI_ASSERT(bits >= 0 && bits <= 8); + return (int) ((unsigned) v * mul_table[bits]) >> shift_table[bits]; } typedef struct @@ -4732,7 +5066,7 @@ static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info) info->offset = stbi__get32le(s); info->hsz = hsz = stbi__get32le(s); info->mr = info->mg = info->mb = info->ma = 0; - + 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); @@ -4743,7 +5077,6 @@ static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info) } if (stbi__get16le(s) != 1) return stbi__errpuc("bad BMP", "bad BMP"); info->bpp = stbi__get16le(s); - if (info->bpp == 1) return stbi__errpuc("monochrome", "BMP type not supported: 1-bit"); if (hsz != 12) { int compress = stbi__get32le(s); if (compress == 1 || compress == 2) return stbi__errpuc("BMP RLE", "BMP type not supported: RLE"); @@ -4807,7 +5140,7 @@ static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info) } -static stbi_uc *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp) +static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) { stbi_uc *out; unsigned int mr=0,mg=0,mb=0,ma=0, all_a; @@ -4815,8 +5148,9 @@ static stbi_uc *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int int psize=0,i,j,width; int flip_vertically, pad, target; stbi__bmp_data info; + STBI_NOTUSED(ri); - info.all_a = 255; + info.all_a = 255; if (stbi__bmp_parse_header(s, &info) == NULL) return NULL; // error code already set @@ -4843,7 +5177,11 @@ static stbi_uc *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int 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); + // sanity-check size + if (!stbi__mad3sizes_valid(target, s->img_x, s->img_y, 0)) + return stbi__errpuc("too large", "Corrupt BMP"); + + out = (stbi_uc *) stbi__malloc_mad3(target, s->img_x, s->img_y, 0); if (!out) return stbi__errpuc("outofmem", "Out of memory"); if (info.bpp < 16) { int z=0; @@ -4856,29 +5194,47 @@ static stbi_uc *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int pal[i][3] = 255; } stbi__skip(s, info.offset - 14 - info.hsz - psize * (info.hsz == 12 ? 3 : 4)); - if (info.bpp == 4) width = (s->img_x + 1) >> 1; + if (info.bpp == 1) width = (s->img_x + 7) >> 3; + else if (info.bpp == 4) width = (s->img_x + 1) >> 1; else if (info.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 (info.bpp == 4) { - v2 = v & 15; - v >>= 4; + if (info.bpp == 1) { + for (j=0; j < (int) s->img_y; ++j) { + int bit_offset = 7, v = stbi__get8(s); + for (i=0; i < (int) s->img_x; ++i) { + int color = (v>>bit_offset)&0x1; + out[z++] = pal[color][0]; + out[z++] = pal[color][1]; + out[z++] = pal[color][2]; + if((--bit_offset) < 0) { + bit_offset = 7; + v = stbi__get8(s); + } } - 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 = (info.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 { + 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 (info.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 = (info.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); } - stbi__skip(s, pad); } } else { int rshift=0,gshift=0,bshift=0,ashift=0,rcount=0,gcount=0,bcount=0,acount=0; @@ -4919,7 +5275,7 @@ static stbi_uc *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int int bpp = info.bpp; for (i=0; i < (int) s->img_x; ++i) { stbi__uint32 v = (bpp == 16 ? (stbi__uint32) stbi__get16le(s) : stbi__get32le(s)); - int a; + unsigned 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)); @@ -4931,7 +5287,7 @@ static stbi_uc *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int 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) @@ -4967,14 +5323,14 @@ static stbi_uc *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int static int stbi__tga_get_comp(int bits_per_pixel, int is_grey, int* is_rgb16) { // only RGB or RGBA (incl. 16bit) or grey allowed - if(is_rgb16) *is_rgb16 = 0; + if (is_rgb16) *is_rgb16 = 0; switch(bits_per_pixel) { case 8: return STBI_grey; case 16: if(is_grey) return STBI_grey_alpha; - // else: fall-through + // fallthrough case 15: if(is_rgb16) *is_rgb16 = 1; - return STBI_rgb; - case 24: // fall-through + return STBI_rgb; + case 24: // fallthrough case 32: return bits_per_pixel/8; default: return 0; } @@ -5077,18 +5433,18 @@ static int stbi__tga_test(stbi__context *s) } // read 16bit value and convert to 24bit RGB -void stbi__tga_read_rgb16(stbi__context *s, stbi_uc* out) +static void stbi__tga_read_rgb16(stbi__context *s, stbi_uc* out) { - stbi__uint16 px = stbi__get16le(s); + stbi__uint16 px = (stbi__uint16)stbi__get16le(s); stbi__uint16 fiveBitMask = 31; // we have 3 channels with 5bits each int r = (px >> 10) & fiveBitMask; int g = (px >> 5) & fiveBitMask; int b = px & fiveBitMask; // Note that this saves the data in RGB(A) order, so it doesn't need to be swapped later - out[0] = (r * 255)/31; - out[1] = (g * 255)/31; - out[2] = (b * 255)/31; + out[0] = (stbi_uc)((r * 255)/31); + out[1] = (stbi_uc)((g * 255)/31); + out[2] = (stbi_uc)((b * 255)/31); // some people claim that the most significant bit might be used for alpha // (possibly if an alpha-bit is set in the "image descriptor byte") @@ -5096,7 +5452,7 @@ void stbi__tga_read_rgb16(stbi__context *s, stbi_uc* out) // so let's treat all 15 and 16bit TGAs as RGB with no alpha. } -static stbi_uc *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp) +static void *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) { // read in the TGA header stuff int tga_offset = stbi__get8(s); @@ -5118,10 +5474,11 @@ static stbi_uc *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int unsigned char *tga_data; unsigned char *tga_palette = NULL; int i, j; - unsigned char raw_data[4]; + unsigned char raw_data[4] = {0}; int RLE_count = 0; int RLE_repeating = 0; int read_next_pixel = 1; + STBI_NOTUSED(ri); // do a tiny bit of precessing if ( tga_image_type >= 8 ) @@ -5143,7 +5500,10 @@ static stbi_uc *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int *y = tga_height; if (comp) *comp = tga_comp; - tga_data = (unsigned char*)stbi__malloc( (size_t)tga_width * tga_height * tga_comp ); + if (!stbi__mad3sizes_valid(tga_width, tga_height, tga_comp, 0)) + return stbi__errpuc("too large", "Corrupt TGA"); + + tga_data = (unsigned char*)stbi__malloc_mad3(tga_width, tga_height, tga_comp, 0); if (!tga_data) return stbi__errpuc("outofmem", "Out of memory"); // skip to the data's starting position (offset usually = 0) @@ -5162,7 +5522,7 @@ static stbi_uc *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int // 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_comp ); + tga_palette = (unsigned char*)stbi__malloc_mad2(tga_palette_len, tga_comp, 0); if (!tga_palette) { STBI_FREE(tga_data); return stbi__errpuc("outofmem", "Out of memory"); @@ -5298,14 +5658,53 @@ static int stbi__psd_test(stbi__context *s) return r; } -static stbi_uc *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp) +static int stbi__psd_decode_rle(stbi__context *s, stbi_uc *p, int pixelCount) +{ + int count, nleft, len; + + count = 0; + while ((nleft = pixelCount - count) > 0) { + len = stbi__get8(s); + if (len == 128) { + // No-op. + } else if (len < 128) { + // Copy next len+1 bytes literally. + len++; + if (len > nleft) return 0; // corrupt data + 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 = 257 - len; + if (len > nleft) return 0; // corrupt data + val = stbi__get8(s); + count += len; + while (len) { + *p = val; + p += 4; + len--; + } + } + } + + return 1; +} + +static void *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc) { - int pixelCount; + int pixelCount; int channelCount, compression; - int channel, i, count, len; + int channel, i; int bitdepth; int w,h; stbi_uc *out; + STBI_NOTUSED(ri); // Check identifier if (stbi__get32be(s) != 0x38425053) // "8BPS" @@ -5362,8 +5761,18 @@ static stbi_uc *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int if (compression > 1) return stbi__errpuc("bad compression", "PSD has an unknown compression format"); + // Check size + if (!stbi__mad3sizes_valid(4, w, h, 0)) + return stbi__errpuc("too large", "Corrupt PSD"); + // Create the destination image. - out = (stbi_uc *) stbi__malloc(4 * w*h); + + if (!compression && bitdepth == 16 && bpc == 16) { + out = (stbi_uc *) stbi__malloc_mad3(8, w, h, 0); + ri->bits_per_channel = 16; + } else + out = (stbi_uc *) stbi__malloc(4 * w*h); + if (!out) return stbi__errpuc("outofmem", "Out of memory"); pixelCount = w*h; @@ -5395,82 +5804,86 @@ static stbi_uc *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int *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--; - } - } + if (!stbi__psd_decode_rle(s, p, pixelCount)) { + STBI_FREE(out); + return stbi__errpuc("corrupt", "bad RLE data"); } } } } 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. + // where each channel consists of an 8-bit (or 16-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); + if (bitdepth == 16 && bpc == 16) { + stbi__uint16 *q = ((stbi__uint16 *) out) + channel; + stbi__uint16 val = channel == 3 ? 65535 : 0; + for (i = 0; i < pixelCount; i++, q += 4) + *q = val; } else { + stbi_uc *p = out+channel; + stbi_uc val = channel == 3 ? 255 : 0; for (i = 0; i < pixelCount; i++, p += 4) - *p = stbi__get8(s); + *p = val; + } + } else { + if (ri->bits_per_channel == 16) { // output bpc + stbi__uint16 *q = ((stbi__uint16 *) out) + channel; + for (i = 0; i < pixelCount; i++, q += 4) + *q = (stbi__uint16) stbi__get16be(s); + } else { + stbi_uc *p = out+channel; + if (bitdepth == 16) { // input bpc + 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); + } } } } } + // remove weird white matte from PSD if (channelCount >= 4) { - for (i=0; i < w*h; ++i) { - unsigned char *pixel = out + 4*i; - if (pixel[3] != 0 && pixel[3] != 255) { - // remove weird white matte from PSD - float a = pixel[3] / 255.0f; - float ra = 1.0f / a; - float inv_a = 255.0f * (1 - ra); - pixel[0] = (unsigned char) (pixel[0]*ra + inv_a); - pixel[1] = (unsigned char) (pixel[1]*ra + inv_a); - pixel[2] = (unsigned char) (pixel[2]*ra + inv_a); + if (ri->bits_per_channel == 16) { + for (i=0; i < w*h; ++i) { + stbi__uint16 *pixel = (stbi__uint16 *) out + 4*i; + if (pixel[3] != 0 && pixel[3] != 65535) { + float a = pixel[3] / 65535.0f; + float ra = 1.0f / a; + float inv_a = 65535.0f * (1 - ra); + pixel[0] = (stbi__uint16) (pixel[0]*ra + inv_a); + pixel[1] = (stbi__uint16) (pixel[1]*ra + inv_a); + pixel[2] = (stbi__uint16) (pixel[2]*ra + inv_a); + } + } + } else { + for (i=0; i < w*h; ++i) { + unsigned char *pixel = out + 4*i; + if (pixel[3] != 0 && pixel[3] != 255) { + float a = pixel[3] / 255.0f; + float ra = 1.0f / a; + float inv_a = 255.0f * (1 - ra); + pixel[0] = (unsigned char) (pixel[0]*ra + inv_a); + pixel[1] = (unsigned char) (pixel[1]*ra + inv_a); + pixel[2] = (unsigned char) (pixel[2]*ra + inv_a); + } } } } + // convert to desired output format if (req_comp && req_comp != 4) { - out = stbi__convert_format(out, 4, req_comp, w, h); + if (ri->bits_per_channel == 16) + out = (stbi_uc *) stbi__convert_format16((stbi__uint16 *) out, 4, req_comp, w, h); + else + out = stbi__convert_format(out, 4, req_comp, w, h); if (out == NULL) return out; // stbi__convert_format frees input on failure } @@ -5654,10 +6067,13 @@ static stbi_uc *stbi__pic_load_core(stbi__context *s,int width,int height,int *c return result; } -static stbi_uc *stbi__pic_load(stbi__context *s,int *px,int *py,int *comp,int req_comp) +static void *stbi__pic_load(stbi__context *s,int *px,int *py,int *comp,int req_comp, stbi__result_info *ri) { stbi_uc *result; - int i, x,y; + int i, x,y, internal_comp; + STBI_NOTUSED(ri); + + if (!comp) comp = &internal_comp; for (i=0; i<92; ++i) stbi__get8(s); @@ -5665,14 +6081,14 @@ static stbi_uc *stbi__pic_load(stbi__context *s,int *px,int *py,int *comp,int re 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"); + if (!stbi__mad3sizes_valid(x, y, 4, 0)) return stbi__errpuc("too large", "PIC 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); + result = (stbi_uc *) stbi__malloc_mad3(x, y, 4, 0); memset(result, 0xff, x*y*4); if (!stbi__pic_load_core(s,x,y,comp, result)) { @@ -5709,11 +6125,13 @@ typedef struct typedef struct { int w,h; - stbi_uc *out, *old_out; // output buffer (always 4 components) - int flags, bgindex, ratio, transparent, eflags, delay; + stbi_uc *out; // output buffer (always 4 components) + stbi_uc *background; // The current "background" as far as a gif is concerned + stbi_uc *history; + int flags, bgindex, ratio, transparent, eflags; stbi_uc pal[256][4]; stbi_uc lpal[256][4]; - stbi__gif_lzw codes[4096]; + stbi__gif_lzw codes[8192]; stbi_uc *color_table; int parse, step; int lflags; @@ -5721,6 +6139,7 @@ typedef struct int max_x, max_y; int cur_x, cur_y; int line_size; + int delay; } stbi__gif; static int stbi__gif_test_raw(stbi__context *s) @@ -5796,6 +6215,7 @@ static int stbi__gif_info_raw(stbi__context *s, int *x, int *y, int *comp) static void stbi__out_gif_code(stbi__gif *g, stbi__uint16 code) { stbi_uc *p, *c; + int idx; // recurse to decode the prefixes, since the linked-list is backwards, // and working backwards through an interleaved image would be nasty @@ -5804,10 +6224,12 @@ static void stbi__out_gif_code(stbi__gif *g, stbi__uint16 code) 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]; + idx = g->cur_x + g->cur_y; + p = &g->out[idx]; + g->history[idx / 4] = 1; - if (c[3] >= 128) { + c = &g->color_table[g->codes[code].suffix * 4]; + if (c[3] > 128) { // don't render transparent pixels; p[0] = c[2]; p[1] = c[1]; p[2] = c[0]; @@ -5881,11 +6303,16 @@ static stbi_uc *stbi__process_gif_raster(stbi__context *s, stbi__gif *g) stbi__skip(s,len); return g->out; } else if (code <= avail) { - if (first) return stbi__errpuc("no clear code", "Corrupt GIF"); + 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"); + if (avail > 8192) { + 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; @@ -5907,59 +6334,72 @@ static stbi_uc *stbi__process_gif_raster(stbi__context *s, stbi__gif *g) } } -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 +// two back is the image from two frames ago, used for a very specific disposal format +static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, int req_comp, stbi_uc *two_back) +{ + int dispose; + int first_frame; + int pi; + int pcount; + + // on first frame, any non-written pixels get the background colour (non-transparent) + first_frame = 0; + if (g->out == 0) { + if (!stbi__gif_header(s, g, comp,0)) return 0; // stbi__g_failure_reason set by stbi__gif_header + g->out = (stbi_uc *) stbi__malloc(4 * g->w * g->h); + g->background = (stbi_uc *) stbi__malloc(4 * g->w * g->h); + g->history = (stbi_uc *) stbi__malloc(g->w * g->h); + if (g->out == 0) return stbi__errpuc("outofmem", "Out of memory"); + + // image is treated as "tranparent" at the start - ie, nothing overwrites the current background; + // background colour is only used for pixels that are not rendered first frame, after that "background" + // color refers to teh color that was there the previous frame. + memset( g->out, 0x00, 4 * g->w * g->h ); + memset( g->background, 0x00, 4 * g->w * g->h ); // state of the background (starts transparent) + memset( g->history, 0x00, g->w * g->h ); // pixels that were affected previous frame + first_frame = 1; + } else { + // second frame - how do we dispoase of the previous one? + dispose = (g->eflags & 0x1C) >> 2; + pcount = g->w * g->h; - 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"); + if ((dispose == 3) && (two_back == 0)) { + dispose = 2; // if I don't have an image to revert back to, default to the old background + } - 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); + if (dispose == 3) { // use previous graphic + for (pi = 0; pi < pcount; ++pi) { + if (g->history[pi]) { + memcpy( &g->out[pi * 4], &two_back[pi * 4], 4 ); + } } - break; + } else if (dispose == 2) { + // restore what was changed last frame to background before that frame; + for (pi = 0; pi < pcount; ++pi) { + if (g->history[pi]) { + memcpy( &g->out[pi * 4], &g->background[pi * 4], 4 ); + } + } + } else { + // This is a non-disposal case eithe way, so just + // leave the pixels as is, and they will become the new background + // 1: do not dispose + // 0: not specified. + } + + // background is what out is after the undoing of the previou frame; + memcpy( g->background, g->out, 4 * g->w * g->h ); } + // clear my history; + memset( g->history, 0x00, g->w * g->h ); // pixels that were affected previous frame + for (;;) { - switch (stbi__get8(s)) { + int tag = stbi__get8(s); + switch (tag) { case 0x2C: /* Image Descriptor */ { - int prev_trans = -1; stbi__int32 x, y, w, h; stbi_uc *o; @@ -5992,19 +6432,24 @@ static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, i 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"); - + 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; + // if this was the first frame, + pcount = g->w * g->h; + if (first_frame && (g->bgindex > 0)) { + // if first frame, any pixel not drawn to gets the background color + for (pi = 0; pi < pcount; ++pi) { + if (g->history[pi] == 0) { + g->pal[g->bgindex][3] = 255; // just in case it was made transparent, undo that; It will be reset next frame if need be; + memcpy( &g->out[pi * 4], &g->pal[g->bgindex], 4 ); + } + } + } return o; } @@ -6012,19 +6457,35 @@ static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, i case 0x21: // Comment Extension. { int len; - if (stbi__get8(s) == 0xF9) { // Graphic Control Extension. + int ext = stbi__get8(s); + if (ext == 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); + g->delay = 10 * stbi__get16le(s); // delay - 1/100th of a second, saving as 1/1000ths. + + // unset old transparent + if (g->transparent >= 0) { + g->pal[g->transparent][3] = 255; + } + if (g->eflags & 0x01) { + g->transparent = stbi__get8(s); + if (g->transparent >= 0) { + g->pal[g->transparent][3] = 0; + } + } else { + // don't need transparent + stbi__skip(s, 1); + g->transparent = -1; + } } else { stbi__skip(s, len); break; } - } - while ((len = stbi__get8(s)) != 0) + } + while ((len = stbi__get8(s)) != 0) { stbi__skip(s, len); + } break; } @@ -6035,27 +6496,92 @@ static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, i return stbi__errpuc("unknown code", "Corrupt GIF"); } } +} + +static void *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y, int *z, int *comp, int req_comp) +{ + if (stbi__gif_test(s)) { + int layers = 0; + stbi_uc *u = 0; + stbi_uc *out = 0; + stbi_uc *two_back = 0; + stbi__gif g; + int stride; + memset(&g, 0, sizeof(g)); + if (delays) { + *delays = 0; + } + + do { + u = stbi__gif_load_next(s, &g, comp, req_comp, two_back); + if (u == (stbi_uc *) s) u = 0; // end of animated gif marker + + if (u) { + *x = g.w; + *y = g.h; + ++layers; + stride = g.w * g.h * 4; + + if (out) { + out = (stbi_uc*) STBI_REALLOC( out, layers * stride ); + if (delays) { + *delays = (int*) STBI_REALLOC( *delays, sizeof(int) * layers ); + } + } else { + out = (stbi_uc*)stbi__malloc( layers * stride ); + if (delays) { + *delays = (int*) stbi__malloc( layers * sizeof(int) ); + } + } + memcpy( out + ((layers - 1) * stride), u, stride ); + if (layers >= 2) { + two_back = out - 2 * stride; + } - STBI_NOTUSED(req_comp); + if (delays) { + (*delays)[layers - 1U] = g.delay; + } + } + } while (u != 0); + + // free temp buffer; + STBI_FREE(g.out); + STBI_FREE(g.history); + STBI_FREE(g.background); + + // do the final conversion after loading everything; + if (req_comp && req_comp != 4) + out = stbi__convert_format(out, 4, req_comp, layers * g.w, g.h); + + *z = layers; + return out; + } else { + return stbi__errpuc("not GIF", "Image was not as a gif type."); + } } -static stbi_uc *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp) +static void *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) { stbi_uc *u = 0; - stbi__gif* g = (stbi__gif*) stbi__malloc(sizeof(stbi__gif)); - memset(g, 0, sizeof(*g)); + stbi__gif g; + memset(&g, 0, sizeof(g)); - u = stbi__gif_load_next(s, g, comp, req_comp); + u = stbi__gif_load_next(s, &g, comp, req_comp, 0); if (u == (stbi_uc *) s) u = 0; // end of animated gif marker if (u) { - *x = g->w; - *y = g->h; + *x = g.w; + *y = g.h; + + // moved conversion to after successful load so that the same + // can be done for multiple frames. if (req_comp && req_comp != 4) - u = stbi__convert_format(u, 4, req_comp, g->w, g->h); + u = stbi__convert_format(u, 4, req_comp, g.w, g.h); } - else if (g->out) - STBI_FREE(g->out); - STBI_FREE(g); + + // free buffers needed for multiple frame loading; + STBI_FREE(g.history); + STBI_FREE(g.background); + return u; } @@ -6069,20 +6595,24 @@ static int stbi__gif_info(stbi__context *s, int *x, int *y, int *comp) // Radiance RGBE HDR loader // originally by Nicolas Schulz #ifndef STBI_NO_HDR -static int stbi__hdr_test_core(stbi__context *s) +static int stbi__hdr_test_core(stbi__context *s, const char *signature) { - const char *signature = "#?RADIANCE\n"; int i; for (i=0; signature[i]; ++i) if (stbi__get8(s) != signature[i]) - return 0; + return 0; + stbi__rewind(s); return 1; } static int stbi__hdr_test(stbi__context* s) { - int r = stbi__hdr_test_core(s); + int r = stbi__hdr_test_core(s, "#?RADIANCE\n"); stbi__rewind(s); + if(!r) { + r = stbi__hdr_test_core(s, "#?RGBE\n"); + stbi__rewind(s); + } return r; } @@ -6136,7 +6666,7 @@ static void stbi__hdr_convert(float *output, stbi_uc *input, int req_comp) } } -static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int req_comp) +static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) { char buffer[STBI__HDR_BUFLEN]; char *token; @@ -6147,10 +6677,12 @@ static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int re int len; unsigned char count, value; int i, j, k, c1,c2, z; - + const char *headerToken; + STBI_NOTUSED(ri); // Check identifier - if (strcmp(stbi__hdr_gettoken(s,buffer), "#?RADIANCE") != 0) + headerToken = stbi__hdr_gettoken(s,buffer); + if (strcmp(headerToken, "#?RADIANCE") != 0 && strcmp(headerToken, "#?RGBE") != 0) return stbi__errpf("not HDR", "Corrupt HDR image"); // Parse header @@ -6179,8 +6711,13 @@ static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int re if (comp) *comp = 3; if (req_comp == 0) req_comp = 3; + if (!stbi__mad4sizes_valid(width, height, req_comp, sizeof(float), 0)) + return stbi__errpf("too large", "HDR image is too large"); + // Read data - hdr_data = (float *) stbi__malloc(height * width * req_comp * sizeof(float)); + hdr_data = (float *) stbi__malloc_mad4(width, height, req_comp, sizeof(float), 0); + if (!hdr_data) + return stbi__errpf("outofmem", "Out of memory"); // Load image data // image data is stored as some number of sca @@ -6219,20 +6756,29 @@ static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int re 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); + if (scanline == NULL) { + scanline = (stbi_uc *) stbi__malloc_mad2(width, 4, 0); + if (!scanline) { + STBI_FREE(hdr_data); + return stbi__errpf("outofmem", "Out of memory"); + } + } for (k = 0; k < 4; ++k) { + int nleft; i = 0; - while (i < width) { + while ((nleft = width - i) > 0) { count = stbi__get8(s); if (count > 128) { // Run value = stbi__get8(s); count -= 128; + if (count > nleft) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("corrupt", "bad RLE data in HDR"); } for (z = 0; z < count; ++z) scanline[i++ * 4 + k] = value; } else { // Dump + if (count > nleft) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("corrupt", "bad RLE data in HDR"); } for (z = 0; z < count; ++z) scanline[i++ * 4 + k] = stbi__get8(s); } @@ -6241,7 +6787,8 @@ static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int re for (i=0; i < width; ++i) stbi__hdr_convert(hdr_data+(j*width + i)*req_comp, scanline + i*4, req_comp); } - STBI_FREE(scanline); + if (scanline) + STBI_FREE(scanline); } return hdr_data; @@ -6252,6 +6799,11 @@ static int stbi__hdr_info(stbi__context *s, int *x, int *y, int *comp) char buffer[STBI__HDR_BUFLEN]; char *token; int valid = 0; + int dummy; + + if (!x) x = &dummy; + if (!y) y = &dummy; + if (!comp) comp = &dummy; if (stbi__hdr_test(s) == 0) { stbi__rewind( s ); @@ -6293,14 +6845,14 @@ static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp) void *p; stbi__bmp_data info; - info.all_a = 255; + info.all_a = 255; p = stbi__bmp_parse_header(s, &info); stbi__rewind( s ); if (p == NULL) return 0; - *x = s->img_x; - *y = s->img_y; - *comp = info.ma ? 4 : 3; + if (x) *x = s->img_x; + if (y) *y = s->img_y; + if (comp) *comp = info.ma ? 4 : 3; return 1; } #endif @@ -6308,7 +6860,10 @@ static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp) #ifndef STBI_NO_PSD static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp) { - int channelCount; + int channelCount, dummy, depth; + if (!x) x = &dummy; + if (!y) y = &dummy; + if (!comp) comp = &dummy; if (stbi__get32be(s) != 0x38425053) { stbi__rewind( s ); return 0; @@ -6325,7 +6880,8 @@ static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp) } *y = stbi__get32be(s); *x = stbi__get32be(s); - if (stbi__get16be(s) != 8) { + depth = stbi__get16be(s); + if (depth != 8 && depth != 16) { stbi__rewind( s ); return 0; } @@ -6336,14 +6892,45 @@ static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp) *comp = 4; return 1; } + +static int stbi__psd_is16(stbi__context *s) +{ + int channelCount, depth; + 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; + } + (void) stbi__get32be(s); + (void) stbi__get32be(s); + depth = stbi__get16be(s); + if (depth != 16) { + stbi__rewind( s ); + return 0; + } + 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; + int act_comp=0,num_packets=0,chained,dummy; stbi__pic_packet packets[10]; + if (!x) x = &dummy; + if (!y) y = &dummy; + if (!comp) comp = &dummy; + if (!stbi__pic_is4(s,"\x53\x80\xF6\x34")) { stbi__rewind(s); return 0; @@ -6419,16 +7006,22 @@ static int stbi__pnm_test(stbi__context *s) return 1; } -static stbi_uc *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp) +static void *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) { stbi_uc *out; + STBI_NOTUSED(ri); + 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; + if (comp) *comp = s->img_n; - out = (stbi_uc *) stbi__malloc(s->img_n * s->img_x * s->img_y); + if (!stbi__mad3sizes_valid(s->img_n, s->img_x, s->img_y, 0)) + return stbi__errpuc("too large", "PNM too large"); + + out = (stbi_uc *) stbi__malloc_mad3(s->img_n, s->img_x, s->img_y, 0); if (!out) return stbi__errpuc("outofmem", "Out of memory"); stbi__getn(s, out, s->img_n * s->img_x * s->img_y); @@ -6477,16 +7070,20 @@ static int stbi__pnm_getinteger(stbi__context *s, char *c) static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp) { - int maxv; + int maxv, dummy; char c, p, t; - stbi__rewind( s ); + if (!x) x = &dummy; + if (!y) y = &dummy; + if (!comp) comp = &dummy; + + 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 ); + stbi__rewind(s); return 0; } @@ -6552,6 +7149,19 @@ static int stbi__info_main(stbi__context *s, int *x, int *y, int *comp) return stbi__err("unknown image type", "Image not of any known type, or corrupt"); } +static int stbi__is_16_main(stbi__context *s) +{ + #ifndef STBI_NO_PNG + if (stbi__png_is16(s)) return 1; + #endif + + #ifndef STBI_NO_PSD + if (stbi__psd_is16(s)) return 1; + #endif + + return 0; +} + #ifndef STBI_NO_STDIO STBIDEF int stbi_info(char const *filename, int *x, int *y, int *comp) { @@ -6573,6 +7183,27 @@ STBIDEF int stbi_info_from_file(FILE *f, int *x, int *y, int *comp) fseek(f,pos,SEEK_SET); return r; } + +STBIDEF int stbi_is_16_bit(char const *filename) +{ + FILE *f = stbi__fopen(filename, "rb"); + int result; + if (!f) return stbi__err("can't fopen", "Unable to open file"); + result = stbi_is_16_bit_from_file(f); + fclose(f); + return result; +} + +STBIDEF int stbi_is_16_bit_from_file(FILE *f) +{ + int r; + stbi__context s; + long pos = ftell(f); + stbi__start_file(&s, f); + r = stbi__is_16_main(&s); + 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) @@ -6589,10 +7220,43 @@ STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *c, void *user, int return stbi__info_main(&s,x,y,comp); } +STBIDEF int stbi_is_16_bit_from_memory(stbi_uc const *buffer, int len) +{ + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__is_16_main(&s); +} + +STBIDEF int stbi_is_16_bit_from_callbacks(stbi_io_callbacks const *c, void *user) +{ + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *) c, user); + return stbi__is_16_main(&s); +} + #endif // STB_IMAGE_IMPLEMENTATION /* revision history: + 2.19 (2018-02-11) fix warning + 2.18 (2018-01-30) fix warnings + 2.17 (2018-01-29) change sbti__shiftsigned to avoid clang -O2 bug + 1-bit BMP + *_is_16_bit api + avoid warnings + 2.16 (2017-07-23) all functions have 16-bit variants; + STBI_NO_STDIO works again; + compilation fixes; + fix rounding in unpremultiply; + optimize vertical flip; + disable raw_len validation; + documentation fixes + 2.15 (2017-03-18) fix png-1,2,4 bug; now all Imagenet JPGs decode; + warning fixes; disable run-time SSE detection on gcc; + uniform handling of optional "return" values; + thread-safe initialization of zlib tables + 2.14 (2017-03-03) remove deprecated STBI_JPEG_OLD; fixes for Imagenet JPGs + 2.13 (2016-11-29) add 16-bit API, only supported for PNG right now 2.12 (2016-04-02) fix typo in 2.11 PSD fix that caused crashes 2.11 (2016-04-02) allocate large structures on the stack remove white matting for transparent PSD @@ -6753,3 +7417,46 @@ STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *c, void *user, int 0.50 (2006-11-19) first released version */ + + +/* +------------------------------------------------------------------------------ +This software is available under 2 licenses -- choose whichever you prefer. +------------------------------------------------------------------------------ +ALTERNATIVE A - MIT License +Copyright (c) 2017 Sean Barrett +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +------------------------------------------------------------------------------ +ALTERNATIVE B - Public Domain (www.unlicense.org) +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. +------------------------------------------------------------------------------ +*/ From aa1000b7f79f494801150088654aa880e6d9c95a Mon Sep 17 00:00:00 2001 From: Jens Behley Date: Tue, 27 Mar 2018 14:15:00 +0200 Subject: [PATCH 19/31] now compiling. --- cell/cell.cpp | 6 ++++-- demo/program.cpp | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/cell/cell.cpp b/cell/cell.cpp index 2010153..7849183 100644 --- a/cell/cell.cpp +++ b/cell/cell.cpp @@ -1,8 +1,9 @@ #include "cell.h" #include +#include -#include +#include #include "imgui/imgui.h" #include "renderer/PostProcessor.h" @@ -561,7 +562,8 @@ namespace Cell } else { - io.MousePos = ImVec2(-FLT_MAX, -FLT_MAX); + // float FLT_MAX = ; + io.MousePos = ImVec2(-std::numeric_limits::max(), -std::numeric_limits::max()); } for (int i = 0; i < 3; i++) diff --git a/demo/program.cpp b/demo/program.cpp index abde6c6..13834b2 100644 --- a/demo/program.cpp +++ b/demo/program.cpp @@ -133,7 +133,7 @@ int main(int argc, char *argv[]) Cell::PBRCapture *pbrEnv = renderer->GetSkypCature(); background->SetCubemap(pbrEnv->Prefiltered); float lodLevel = 1.5f; - background->Material->SetFloat("lodLevel", lodLevel); + background->material->SetFloat("lodLevel", lodLevel); // post processing Cell::Shader *postProcessing1 = Cell::Resources::LoadShader("postprocessing1", "shaders/screen_quad.vs", "shaders/custom_post_1.fs"); From 523b219f251223f194710ab0c97801bf60a4206b Mon Sep 17 00:00:00 2001 From: Jens Behley Date: Tue, 27 Mar 2018 14:19:36 +0200 Subject: [PATCH 20/31] use #version 420 core, since binding points for UBO is available since 4.20 --- build/shaders/background.vs | 2 +- build/shaders/capture.fs | 2 +- build/shaders/custom/plasma_orb.fs | 2 +- build/shaders/custom/plasma_orb.vs | 2 +- build/shaders/deferred/ambient.fs | 2 +- build/shaders/deferred/directional.fs | 2 +- build/shaders/deferred/g_buffer.fs | 2 +- build/shaders/deferred/g_buffer.vs | 2 +- build/shaders/deferred/point.fs | 2 +- build/shaders/deferred/point.vs | 2 +- build/shaders/deferred/screen_ambient.vs | 2 +- build/shaders/deferred/screen_directional.vs | 2 +- build/shaders/forward_render.fs | 2 +- build/shaders/forward_render.vs | 2 +- build/shaders/light.vs | 2 +- 15 files changed, 15 insertions(+), 15 deletions(-) diff --git a/build/shaders/background.vs b/build/shaders/background.vs index d670d24..54d1971 100644 --- a/build/shaders/background.vs +++ b/build/shaders/background.vs @@ -1,4 +1,4 @@ -#version 330 core +#version 420 core layout (location = 0) in vec3 aPos; #include common/uniforms.glsl diff --git a/build/shaders/capture.fs b/build/shaders/capture.fs index d181e92..c4e51a5 100644 --- a/build/shaders/capture.fs +++ b/build/shaders/capture.fs @@ -1,4 +1,4 @@ -#version 330 core +#version 420 core out vec4 FragColor; in vec3 color; diff --git a/build/shaders/custom/plasma_orb.fs b/build/shaders/custom/plasma_orb.fs index ebab084..c62f995 100644 --- a/build/shaders/custom/plasma_orb.fs +++ b/build/shaders/custom/plasma_orb.fs @@ -1,4 +1,4 @@ -#version 330 core +#version 420 core out vec4 FragColor; in vec2 TexCoords; diff --git a/build/shaders/custom/plasma_orb.vs b/build/shaders/custom/plasma_orb.vs index 65c6ec5..8fda68b 100644 --- a/build/shaders/custom/plasma_orb.vs +++ b/build/shaders/custom/plasma_orb.vs @@ -1,4 +1,4 @@ -#version 330 core +#version 420 core layout (location = 0) in vec3 aPos; layout (location = 1) in vec2 aUV; layout (location = 2) in vec3 aNormal; diff --git a/build/shaders/deferred/ambient.fs b/build/shaders/deferred/ambient.fs index 48d897e..f61eb48 100644 --- a/build/shaders/deferred/ambient.fs +++ b/build/shaders/deferred/ambient.fs @@ -1,4 +1,4 @@ -#version 330 core +#version 420 core out vec4 FragColor; in vec2 TexCoords; diff --git a/build/shaders/deferred/directional.fs b/build/shaders/deferred/directional.fs index 51d5ad7..7632e69 100644 --- a/build/shaders/deferred/directional.fs +++ b/build/shaders/deferred/directional.fs @@ -1,4 +1,4 @@ -#version 330 core +#version 420 core out vec4 FragColor; in vec2 TexCoords; diff --git a/build/shaders/deferred/g_buffer.fs b/build/shaders/deferred/g_buffer.fs index a1105f1..df9df4e 100644 --- a/build/shaders/deferred/g_buffer.fs +++ b/build/shaders/deferred/g_buffer.fs @@ -1,4 +1,4 @@ -#version 330 core +#version 420 core layout (location = 0) out vec4 gPositionMetallic; layout (location = 1) out vec4 gNormalRoughness; layout (location = 2) out vec4 gAlbedoAO; diff --git a/build/shaders/deferred/g_buffer.vs b/build/shaders/deferred/g_buffer.vs index 799c9f4..5bcc5d3 100644 --- a/build/shaders/deferred/g_buffer.vs +++ b/build/shaders/deferred/g_buffer.vs @@ -1,4 +1,4 @@ -#version 330 core +#version 420 core layout (location = 0) in vec3 aPos; layout (location = 1) in vec2 aUV0; layout (location = 2) in vec3 aNormal; diff --git a/build/shaders/deferred/point.fs b/build/shaders/deferred/point.fs index 6d10319..edf20bf 100644 --- a/build/shaders/deferred/point.fs +++ b/build/shaders/deferred/point.fs @@ -1,4 +1,4 @@ -#version 330 core +#version 420 core out vec4 FragColor; in vec3 FragPos; diff --git a/build/shaders/deferred/point.vs b/build/shaders/deferred/point.vs index cf97073..8f7e074 100644 --- a/build/shaders/deferred/point.vs +++ b/build/shaders/deferred/point.vs @@ -1,4 +1,4 @@ -#version 330 core +#version 420 core layout (location = 0) in vec3 aPos; out vec3 FragPos; diff --git a/build/shaders/deferred/screen_ambient.vs b/build/shaders/deferred/screen_ambient.vs index 6304dcc..af2c30d 100644 --- a/build/shaders/deferred/screen_ambient.vs +++ b/build/shaders/deferred/screen_ambient.vs @@ -1,4 +1,4 @@ -#version 330 core +#version 420 core layout (location = 0) in vec3 aPos; layout (location = 1) in vec2 aUV0; diff --git a/build/shaders/deferred/screen_directional.vs b/build/shaders/deferred/screen_directional.vs index 6304dcc..af2c30d 100644 --- a/build/shaders/deferred/screen_directional.vs +++ b/build/shaders/deferred/screen_directional.vs @@ -1,4 +1,4 @@ -#version 330 core +#version 420 core layout (location = 0) in vec3 aPos; layout (location = 1) in vec2 aUV0; diff --git a/build/shaders/forward_render.fs b/build/shaders/forward_render.fs index b970876..8537887 100644 --- a/build/shaders/forward_render.fs +++ b/build/shaders/forward_render.fs @@ -1,4 +1,4 @@ -#version 330 core +#version 420 core out vec4 FragColor; in vec3 color; diff --git a/build/shaders/forward_render.vs b/build/shaders/forward_render.vs index 3df8182..db2daae 100644 --- a/build/shaders/forward_render.vs +++ b/build/shaders/forward_render.vs @@ -1,4 +1,4 @@ -#version 330 core +#version 420 core layout (location = 0) in vec3 pos; layout (location = 1) in vec2 texCoords; layout (location = 2) in vec3 normal; diff --git a/build/shaders/light.vs b/build/shaders/light.vs index 1749dfe..9604b1e 100644 --- a/build/shaders/light.vs +++ b/build/shaders/light.vs @@ -1,4 +1,4 @@ -#version 330 core +#version 420 core layout (location = 0) in vec3 pos; #include common/uniforms.glsl From 9f033fa6fce74e6f2bf1fde8089b3144746b3fc0 Mon Sep 17 00:00:00 2001 From: Jens Behley Date: Tue, 27 Mar 2018 14:22:15 +0200 Subject: [PATCH 21/31] explicit conversion from int to bool. --- build/shaders/deferred/ambient.fs | 2 +- build/shaders/deferred/ambient_irradience.fs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build/shaders/deferred/ambient.fs b/build/shaders/deferred/ambient.fs index f61eb48..c75264e 100644 --- a/build/shaders/deferred/ambient.fs +++ b/build/shaders/deferred/ambient.fs @@ -26,7 +26,7 @@ void main() vec4 normalRoughness = texture(gNormalRoughness, TexCoords); vec4 positionMetallic = texture(gPositionMetallic, TexCoords); float ao = 1.0; - if(SSAO) + if(bool(SSAO)) { ao = texture(TexSSAO, TexCoords).r; } diff --git a/build/shaders/deferred/ambient_irradience.fs b/build/shaders/deferred/ambient_irradience.fs index 8adb0ba..68e460b 100644 --- a/build/shaders/deferred/ambient_irradience.fs +++ b/build/shaders/deferred/ambient_irradience.fs @@ -33,7 +33,7 @@ void main() vec4 normalRoughness = texture(gNormalRoughness, uv); vec4 positionMetallic = texture(gPositionMetallic, uv); float ao = 1.0; - if(SSAO) + if(bool(SSAO)) { ao = texture(TexSSAO, uv).r; } From 40bf58f89e24baa3b5515569145f13316224e1ad Mon Sep 17 00:00:00 2001 From: Jens Behley Date: Tue, 27 Mar 2018 14:40:29 +0200 Subject: [PATCH 22/31] fixed inconsistency of uniforms caused by UBO in fragement shader. --- build/shaders/capture.vs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/build/shaders/capture.vs b/build/shaders/capture.vs index 714143b..0b8a803 100644 --- a/build/shaders/capture.vs +++ b/build/shaders/capture.vs @@ -1,4 +1,4 @@ -#version 330 core +#version 420 core layout (location = 0) in vec3 pos; layout (location = 1) in vec2 texCoords; layout (location = 2) in vec3 normal; @@ -7,8 +7,10 @@ out vec2 TexCoords; out vec3 FragPos; out vec3 Normal; -uniform mat4 projection; -uniform mat4 view; +#include common/uniforms.glsl + +// uniform mat4 projection; +// uniform mat4 view; uniform mat4 model; void main() From b33f84fac1b30a3fefb7b7ab4116afc17d92ef13 Mon Sep 17 00:00:00 2001 From: Jens Behley Date: Tue, 27 Mar 2018 14:41:40 +0200 Subject: [PATCH 23/31] throw runtime_error if linking of shader fails, since it is easier to debug with stack trace. --- cell/shading/shader.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cell/shading/shader.cpp b/cell/shading/shader.cpp index cfceb23..88df04c 100644 --- a/cell/shading/shader.cpp +++ b/cell/shading/shader.cpp @@ -110,6 +110,8 @@ namespace Cell { glGetProgramInfoLog(ID, 1024, NULL, log); Log::Message("Shader program linking error: \n" + std::string(log), LOG_ERROR); + + throw std::runtime_error("Shader linker error."); } glDeleteShader(vs); From 1242cb6d59b7fec50ca7f7a1ffb9ea995cca3669 Mon Sep 17 00:00:00 2001 From: Jens Behley Date: Tue, 27 Mar 2018 15:05:19 +0200 Subject: [PATCH 24/31] initialize parent and checks for nullptr. --- cell/scene/scene_node.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cell/scene/scene_node.cpp b/cell/scene/scene_node.cpp index 6ddb72d..7f19077 100644 --- a/cell/scene/scene_node.cpp +++ b/cell/scene/scene_node.cpp @@ -10,7 +10,7 @@ namespace Cell { // -------------------------------------------------------------------------------------------- - SceneNode::SceneNode(unsigned int id) : m_ID(id) + SceneNode::SceneNode(unsigned int id) : m_ID(id), m_Parent(nullptr) { } @@ -91,7 +91,7 @@ namespace Cell { // check if this child already has a parent. If so, first remove this scene node from its // current parent. Scene nodes aren't allowed to exist under multiple parents. - if (node->m_Parent) + if (node->m_Parent != nullptr) { node->m_Parent->RemoveChild(node->m_ID); } @@ -165,7 +165,7 @@ namespace Cell m_Transform = math::translate(m_Position); m_Transform = math::scale(m_Transform, m_Scale); // TODO: order is off here for some reason, figure out why m_Transform = math::rotate(m_Transform, m_Rotation.xyz, m_Rotation.w); - if (m_Parent) + if (m_Parent != nullptr) { m_Transform = m_Parent->m_Transform * m_Transform; } From 1aa4d666f884a65a0601823d94deba4d950ae7e6 Mon Sep 17 00:00:00 2001 From: Jens Behley Date: Tue, 27 Mar 2018 15:36:36 +0200 Subject: [PATCH 25/31] consistent naming & fixes issue with case-sensitive filesnames. --- ...round_Albedo.tga => Background_albedo.tga} | Bin ...round_Normal.tga => Background_normal.tga} | Bin ...Roughness.tga => Background_roughness.tga} | Bin ...lpha.tga => ChainTexture_albedo_alpha.tga} | Bin ...Metallic.tga => ChainTexture_metallic.tga} | Bin ...ure_Normal.tga => ChainTexture_normal.tga} | Bin ...ughness.tga => ChainTexture_roughness.tga} | Bin .../{Lion_Albedo.tga => Lion_albedo.tga} | Bin .../{Lion_Normal.tga => Lion_normal.tga} | Bin ...{Lion_Roughness.tga => Lion_roughness.tga} | Bin ..._Albedo.tga => Sponza_Bricks_a_albedo.tga} | Bin ..._Normal.tga => Sponza_Bricks_a_normal.tga} | Bin ...ness.tga => Sponza_Bricks_a_roughness.tga} | Bin build/meshes/sponza/sponza.mtl | 32 +++++++++--------- 14 files changed, 16 insertions(+), 16 deletions(-) rename build/meshes/sponza/{Background_Albedo.tga => Background_albedo.tga} (100%) rename build/meshes/sponza/{Background_Normal.tga => Background_normal.tga} (100%) rename build/meshes/sponza/{Background_Roughness.tga => Background_roughness.tga} (100%) rename build/meshes/sponza/{ChainTexture_Albedo_alpha.tga => ChainTexture_albedo_alpha.tga} (100%) rename build/meshes/sponza/{ChainTexture_Metallic.tga => ChainTexture_metallic.tga} (100%) rename build/meshes/sponza/{ChainTexture_Normal.tga => ChainTexture_normal.tga} (100%) rename build/meshes/sponza/{ChainTexture_Roughness.tga => ChainTexture_roughness.tga} (100%) rename build/meshes/sponza/{Lion_Albedo.tga => Lion_albedo.tga} (100%) rename build/meshes/sponza/{Lion_Normal.tga => Lion_normal.tga} (100%) rename build/meshes/sponza/{Lion_Roughness.tga => Lion_roughness.tga} (100%) rename build/meshes/sponza/{Sponza_Bricks_a_Albedo.tga => Sponza_Bricks_a_albedo.tga} (100%) rename build/meshes/sponza/{Sponza_Bricks_a_Normal.tga => Sponza_Bricks_a_normal.tga} (100%) rename build/meshes/sponza/{Sponza_Bricks_a_Roughness.tga => Sponza_Bricks_a_roughness.tga} (100%) diff --git a/build/meshes/sponza/Background_Albedo.tga b/build/meshes/sponza/Background_albedo.tga similarity index 100% rename from build/meshes/sponza/Background_Albedo.tga rename to build/meshes/sponza/Background_albedo.tga diff --git a/build/meshes/sponza/Background_Normal.tga b/build/meshes/sponza/Background_normal.tga similarity index 100% rename from build/meshes/sponza/Background_Normal.tga rename to build/meshes/sponza/Background_normal.tga diff --git a/build/meshes/sponza/Background_Roughness.tga b/build/meshes/sponza/Background_roughness.tga similarity index 100% rename from build/meshes/sponza/Background_Roughness.tga rename to build/meshes/sponza/Background_roughness.tga diff --git a/build/meshes/sponza/ChainTexture_Albedo_alpha.tga b/build/meshes/sponza/ChainTexture_albedo_alpha.tga similarity index 100% rename from build/meshes/sponza/ChainTexture_Albedo_alpha.tga rename to build/meshes/sponza/ChainTexture_albedo_alpha.tga diff --git a/build/meshes/sponza/ChainTexture_Metallic.tga b/build/meshes/sponza/ChainTexture_metallic.tga similarity index 100% rename from build/meshes/sponza/ChainTexture_Metallic.tga rename to build/meshes/sponza/ChainTexture_metallic.tga diff --git a/build/meshes/sponza/ChainTexture_Normal.tga b/build/meshes/sponza/ChainTexture_normal.tga similarity index 100% rename from build/meshes/sponza/ChainTexture_Normal.tga rename to build/meshes/sponza/ChainTexture_normal.tga diff --git a/build/meshes/sponza/ChainTexture_Roughness.tga b/build/meshes/sponza/ChainTexture_roughness.tga similarity index 100% rename from build/meshes/sponza/ChainTexture_Roughness.tga rename to build/meshes/sponza/ChainTexture_roughness.tga diff --git a/build/meshes/sponza/Lion_Albedo.tga b/build/meshes/sponza/Lion_albedo.tga similarity index 100% rename from build/meshes/sponza/Lion_Albedo.tga rename to build/meshes/sponza/Lion_albedo.tga diff --git a/build/meshes/sponza/Lion_Normal.tga b/build/meshes/sponza/Lion_normal.tga similarity index 100% rename from build/meshes/sponza/Lion_Normal.tga rename to build/meshes/sponza/Lion_normal.tga diff --git a/build/meshes/sponza/Lion_Roughness.tga b/build/meshes/sponza/Lion_roughness.tga similarity index 100% rename from build/meshes/sponza/Lion_Roughness.tga rename to build/meshes/sponza/Lion_roughness.tga diff --git a/build/meshes/sponza/Sponza_Bricks_a_Albedo.tga b/build/meshes/sponza/Sponza_Bricks_a_albedo.tga similarity index 100% rename from build/meshes/sponza/Sponza_Bricks_a_Albedo.tga rename to build/meshes/sponza/Sponza_Bricks_a_albedo.tga diff --git a/build/meshes/sponza/Sponza_Bricks_a_Normal.tga b/build/meshes/sponza/Sponza_Bricks_a_normal.tga similarity index 100% rename from build/meshes/sponza/Sponza_Bricks_a_Normal.tga rename to build/meshes/sponza/Sponza_Bricks_a_normal.tga diff --git a/build/meshes/sponza/Sponza_Bricks_a_Roughness.tga b/build/meshes/sponza/Sponza_Bricks_a_roughness.tga similarity index 100% rename from build/meshes/sponza/Sponza_Bricks_a_Roughness.tga rename to build/meshes/sponza/Sponza_Bricks_a_roughness.tga diff --git a/build/meshes/sponza/sponza.mtl b/build/meshes/sponza/sponza.mtl index 11f633c..6fefc9a 100644 --- a/build/meshes/sponza/sponza.mtl +++ b/build/meshes/sponza/sponza.mtl @@ -66,9 +66,9 @@ newmtl Material__298 Ks 0.0000 0.0000 0.0000 Ke 0.0000 0.0000 0.0000 map_Ks Dielectric_metallic.tga - map_Kd Background_Albedo.tga - disp Background_Normal.tga - bump Background_Normal.tga + map_Kd Background_albedo.tga + disp Background_normal.tga + bump Background_normal.tga map_NS Background_roughness.tga newmtl bricks @@ -83,10 +83,10 @@ newmtl bricks Ks 0.0000 0.0000 0.0000 Ke 0.0000 0.0000 0.0000 map_Ks Dielectric_metallic.tga - map_Kd Sponza_Bricks_a_Albedo.tga - disp Sponza_Bricks_a_Normal.tga - map_Ns Sponza_Bricks_a_Roughness.tga - bump Sponza_Bricks_a_Normal.tga + map_Kd Sponza_Bricks_a_albedo.tga + disp Sponza_Bricks_a_normal.tga + map_Ns Sponza_Bricks_a_roughness.tga + bump Sponza_Bricks_a_normal.tga newmtl arch Ns 10.0000 @@ -337,12 +337,12 @@ newmtl chain Kd 0.5880 0.5880 0.5880 Ks 0.0000 0.0000 0.0000 Ke 0.0000 0.0000 0.0000 - map_Ks ChainTexture_Metallic.tga - map_Kd ChainTexture_Albedo_alpha.tga + map_Ks ChainTexture_metallic.tga + map_Kd ChainTexture_albedo_alpha.tga map_d chain_texture_mask.tga - disp ChainTexture_Normal.tga - bump ChainTexture_Normal.tga - map_Ns ChainTexture_Roughness.tga + disp ChainTexture_normal.tga + bump ChainTexture_normal.tga + map_Ns ChainTexture_roughness.tga newmtl vase_hanging Ns 10.0000 @@ -390,10 +390,10 @@ newmtl Material__25 Ks 0.0000 0.0000 0.0000 Ke 0.0000 0.0000 0.0000 map_Ks Dielectric_metallic.tga - map_Kd Lion_Albedo.tga - disp Lion_Normal.tga - bump Lion_Normal.tga - map_Ns Lion_Roughness.tga + map_Kd Lion_albedo.tga + disp Lion_normal.tga + bump Lion_normal.tga + map_Ns Lion_roughness.tga newmtl roof Ns 10.0000 From d0ef46e0c74b4bab513d859faf63fd0d7daad0de Mon Sep 17 00:00:00 2001 From: jbehley Date: Tue, 27 Mar 2018 15:50:34 +0200 Subject: [PATCH 26/31] added initializations for pointers and explicit checks for nullptr. Now it runs, ... but still a lot of pointers uninitalized. --- cell/lighting/directional_light.h | 3 +-- cell/renderer/gl_cache.h | 6 +++--- cell/renderer/renderer.cpp | 4 ++-- cell/renderer/renderer.h | 16 ++++++++-------- cell/scene/background.h | 4 ++-- cell/scene/scene_node.h | 6 +++--- 6 files changed, 19 insertions(+), 20 deletions(-) diff --git a/cell/lighting/directional_light.h b/cell/lighting/directional_light.h index d989c7c..8f47b97 100644 --- a/cell/lighting/directional_light.h +++ b/cell/lighting/directional_light.h @@ -3,7 +3,6 @@ #include #include -# namespace Cell { @@ -24,7 +23,7 @@ namespace Cell float Intensity = 1.0f; bool CastShadows = true; - RenderTarget* ShadowMapRT; + RenderTarget* ShadowMapRT{nullptr}; math::mat4 LightSpaceViewProjection; }; } diff --git a/cell/renderer/gl_cache.h b/cell/renderer/gl_cache.h index 00a1f21..d8d4854 100644 --- a/cell/renderer/gl_cache.h +++ b/cell/renderer/gl_cache.h @@ -18,9 +18,9 @@ namespace Cell { private: // gl toggles - bool m_DepthTest; - bool m_Blend; - bool m_CullFace; + bool m_DepthTest{false}; + bool m_Blend{false}; + bool m_CullFace{false}; // gl state GLenum m_DepthFunc; diff --git a/cell/renderer/renderer.cpp b/cell/renderer/renderer.cpp index 2ff7ad6..72fa6c1 100644 --- a/cell/renderer/renderer.cpp +++ b/cell/renderer/renderer.cpp @@ -573,7 +573,7 @@ namespace Cell { SceneNode *node = sceneStack.top(); sceneStack.pop(); - if (node->mesh) + if (node->mesh != nullptr) { auto samplerUniforms = *(node->material->GetSamplerUniforms()); if (samplerUniforms.find("TexAlbedo") != samplerUniforms.end()) @@ -662,7 +662,7 @@ namespace Cell { for (int i = 0; i < m_DirectionalLights.size(); ++i) { - if (m_DirectionalLights[i]->ShadowMapRT) + if (m_DirectionalLights[i]->ShadowMapRT != nullptr) { material->GetShader()->SetMatrix("lightShadowViewProjection" + std::to_string(i + 1), m_DirectionalLights[i]->LightSpaceViewProjection); m_DirectionalLights[i]->ShadowMapRT->GetDepthStencilTexture()->Bind(10 + i); diff --git a/cell/renderer/renderer.h b/cell/renderer/renderer.h index 909f19e..87767f6 100644 --- a/cell/renderer/renderer.h +++ b/cell/renderer/renderer.h @@ -53,7 +53,7 @@ namespace Cell bool Wireframe = false; private: // render state - CommandBuffer* m_CommandBuffer; + CommandBuffer* m_CommandBuffer{nullptr}; GLCache m_GLCache; math::vec2 m_RenderSize; @@ -64,19 +64,19 @@ namespace Cell Mesh* m_DeferredPointMesh; // materials - MaterialLibrary* m_MaterialLibrary; + MaterialLibrary* m_MaterialLibrary{nullptr}; // camera - Camera* m_Camera; + Camera* m_Camera{nullptr}; math::mat4 m_PrevViewProjection; // render-targets/post std::vector m_RenderTargetsCustom; RenderTarget* m_CurrentRenderTargetCustom = nullptr; - RenderTarget* m_CustomTarget; - RenderTarget* m_PostProcessTarget1; - PostProcessor* m_PostProcessor; - Quad* m_NDCPlane; + RenderTarget* m_CustomTarget{nullptr}; + RenderTarget* m_PostProcessTarget1{nullptr}; + PostProcessor* m_PostProcessor{nullptr}; + Quad* m_NDCPlane{nullptr}; unsigned int m_FramebufferCubemap; unsigned int m_CubemapDepthRBO; @@ -93,7 +93,7 @@ namespace Cell unsigned int m_GlobalUBO; // debug - Mesh* m_DebugLightMesh; + Mesh* m_DebugLightMesh{nullptr}; public: Renderer(); diff --git a/cell/scene/background.h b/cell/scene/background.h index bff082f..dde2e84 100644 --- a/cell/scene/background.h +++ b/cell/scene/background.h @@ -21,8 +21,8 @@ namespace Cell class Background : public SceneNode { private: - TextureCube *m_CubeMap; - Shader *m_Shader; + TextureCube *m_CubeMap{nullptr}; + Shader *m_Shader{nullptr}; public: Background(); diff --git a/cell/scene/scene_node.h b/cell/scene/scene_node.h index 0acb256..b118149 100644 --- a/cell/scene/scene_node.h +++ b/cell/scene/scene_node.h @@ -28,15 +28,15 @@ namespace Cell { public: // each node contains relevant render state - Mesh* mesh; - Material* material; + Mesh* mesh{nullptr}; + Material* material{nullptr}; // bounding box math::vec3 boxMin = math::vec3(-99999.0f); math::vec3 boxMax = math::vec3( 99999.0f); private: std::vector m_Children; - SceneNode *m_Parent; + SceneNode *m_Parent{nullptr}; // per-node transform (w/ parent-child relationship) math::mat4 m_Transform; From f3dd9d4024f1961ecda690b0cbb6b9f1631fe7d8 Mon Sep 17 00:00:00 2001 From: jbehley Date: Tue, 27 Mar 2018 16:00:21 +0200 Subject: [PATCH 27/31] updated readme with instructions for building & dependencies. --- README.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/README.md b/README.md index 8b7b32b..e2438e0 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,18 @@ to take a look at any of its inner workings, without feeling too overwhelming. ![Cell Preview](preview.png "Cell Preview") +Dependencies +------------ +- glfw3 + +Build +----- +1. Ensure that you also downloaded the submodule, either you used `git clone --recurse-submodules ` or update the submodule by `git submodule update`. +2. `cd build` +3. `cmake -DCMAKE_BUILD_TYPE=Release ..` +4. `make -j5` +5. run `.\demo` + Feature List (complete:base-functionality) ------ * Fully functioning (custom) math library (vectors, matrices, transformations, utility functions): From ed2660226a6ca60eefe2225e286ca476705b2f53 Mon Sep 17 00:00:00 2001 From: Jens Behley Date: Wed, 28 Mar 2018 00:22:50 +0200 Subject: [PATCH 28/31] update submodule procedure. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e2438e0..3dce05f 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ Dependencies Build ----- -1. Ensure that you also downloaded the submodule, either you used `git clone --recurse-submodules ` or update the submodule by `git submodule update`. +1. Ensure that you also downloaded the submodule, either you used `git clone --recurse-submodules ` or update the submodule by `git submodule init` & `git submodule update`. 2. `cd build` 3. `cmake -DCMAKE_BUILD_TYPE=Release ..` 4. `make -j5` From 87f6670feec1ba462f1f2b37f912e41a9ca466e2 Mon Sep 17 00:00:00 2001 From: Jens Behley Date: Wed, 28 Mar 2018 01:51:00 +0200 Subject: [PATCH 29/31] initialized some uninitialized values. --- cell/renderer/gl_cache.h | 12 +-- cell/renderer/renderer.cpp | 178 ++++++++++++++++++------------------- cell/scene/scene_node.cpp | 27 +++--- cell/scene/scene_node.h | 2 +- 4 files changed, 107 insertions(+), 112 deletions(-) diff --git a/cell/renderer/gl_cache.h b/cell/renderer/gl_cache.h index d8d4854..268d860 100644 --- a/cell/renderer/gl_cache.h +++ b/cell/renderer/gl_cache.h @@ -23,14 +23,14 @@ namespace Cell bool m_CullFace{false}; // gl state - GLenum m_DepthFunc; - GLenum m_BlendSrc; - GLenum m_BlendDst; - GLenum m_FrontFace; - GLenum m_PolygonMode; + GLenum m_DepthFunc{0}; + GLenum m_BlendSrc{0}; + GLenum m_BlendDst{0}; + GLenum m_FrontFace{0}; + GLenum m_PolygonMode{0}; // shaders - unsigned int m_ActiveShaderID; + unsigned int m_ActiveShaderID{0}; public: GLCache(); ~GLCache(); diff --git a/cell/renderer/renderer.cpp b/cell/renderer/renderer.cpp index 72fa6c1..29a3512 100644 --- a/cell/renderer/renderer.cpp +++ b/cell/renderer/renderer.cpp @@ -1,22 +1,22 @@ #include "renderer.h" -#include "render_target.h" #include "MaterialLibrary.h" #include "PBR.h" #include "PostProcessor.h" +#include "render_target.h" -#include "../mesh/mesh.h" -#include "../mesh/cube.h" -#include "../shading/material.h" -#include "../scene/scene.h" -#include "../scene/scene_node.h" #include "../camera/camera.h" #include "../camera/fly_camera.h" -#include "../resources/resources.h" #include "../imgui/imgui.h" +#include "../mesh/cube.h" +#include "../mesh/mesh.h" +#include "../resources/resources.h" +#include "../scene/scene.h" +#include "../scene/scene_node.h" +#include "../shading/material.h" -#include #include +#include #include #include @@ -28,11 +28,10 @@ namespace Cell // ------------------------------------------------------------------------ Renderer::Renderer() { - } // ------------------------------------------------------------------------ Renderer::~Renderer() - { + { delete m_CommandBuffer; delete m_NDCPlane; @@ -56,7 +55,7 @@ namespace Cell delete m_PostProcessor; // pbr - delete m_PBR; + delete m_PBR; } // ------------------------------------------------------------------------ void Renderer::Init(GLADloadproc loadProcFunc) @@ -94,16 +93,16 @@ namespace Cell // shadows for (int i = 0; i < 4; ++i) // allow up to a total of 4 dir/spot shadow casters { - RenderTarget *rt = new RenderTarget(2048, 2048, GL_UNSIGNED_BYTE, 1, true); + RenderTarget* rt = new RenderTarget(2048, 2048, GL_UNSIGNED_BYTE, 1, true); rt->m_DepthStencil.Bind(); rt->m_DepthStencil.SetFilterMin(GL_NEAREST); rt->m_DepthStencil.SetFilterMax(GL_NEAREST); rt->m_DepthStencil.SetWrapMode(GL_CLAMP_TO_BORDER); - float borderColor[] = { 1.0f, 1.0f, 1.0f, 1.0f }; + float borderColor[] = {1.0f, 1.0f, 1.0f, 1.0f}; glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor); m_ShadowRenderTargets.push_back(rt); } - + // pbr m_PBR = new PBR(this); @@ -114,8 +113,8 @@ namespace Cell glBindBufferBase(GL_UNIFORM_BUFFER, 0, m_GlobalUBO); // default PBR pre-compute (get a more default oriented HDR map for this) - Cell::Texture *hdrMap = Cell::Resources::LoadHDR("sky env", "textures/backgrounds/alley.hdr"); - Cell::PBRCapture *envBridge = m_PBR->ProcessEquirectangular(hdrMap); + Cell::Texture* hdrMap = Cell::Resources::LoadHDR("sky env", "textures/backgrounds/alley.hdr"); + Cell::PBRCapture* envBridge = m_PBR->ProcessEquirectangular(hdrMap); SetSkyCapture(envBridge); } // ------------------------------------------------------------------------ @@ -128,7 +127,7 @@ namespace Cell m_CustomTarget->Resize(width, height); m_PostProcessTarget1->Resize(width, height); - + m_PostProcessor->UpdateRenderSize(width, height); } // ------------------------------------------------------------------------ @@ -140,10 +139,9 @@ namespace Cell void Renderer::SetTarget(RenderTarget* renderTarget, GLenum target) { m_CurrentRenderTargetCustom = renderTarget; - if (renderTarget != nullptr) + if (renderTarget != nullptr) { - if (std::find(m_RenderTargetsCustom.begin(), m_RenderTargetsCustom.end(), renderTarget) - == m_RenderTargetsCustom.end()) + if (std::find(m_RenderTargetsCustom.begin(), m_RenderTargetsCustom.end(), renderTarget) == m_RenderTargetsCustom.end()) { m_RenderTargetsCustom.push_back(renderTarget); } @@ -167,15 +165,15 @@ namespace Cell // ------------------------------------------------------------------------ Material* Renderer::CreateMaterial(std::string base) { - return m_MaterialLibrary->CreateMaterial(base); + return m_MaterialLibrary->CreateMaterial(base); } // ------------------------------------------------------------------------ - Material* Renderer::CreateCustomMaterial(Shader *shader) + Material* Renderer::CreateCustomMaterial(Shader* shader) { return m_MaterialLibrary->CreateCustomMaterial(shader); } // ------------------------------------------------------------------------ - Material* Renderer::CreatePostProcessingMaterial(Shader *shader) + Material* Renderer::CreatePostProcessingMaterial(Shader* shader) { return m_MaterialLibrary->CreatePostProcessingMaterial(shader); } @@ -195,7 +193,7 @@ namespace Cell // get current render target RenderTarget* target = getCurrentRenderTarget(); - // traverse through all the scene nodes and for each node: push its render state to the + // traverse through all the scene nodes and for each node: push its render state to the // command buffer together with a calculated transform matrix. std::stack nodeStack; nodeStack.push(node); @@ -210,9 +208,9 @@ namespace Cell { math::vec3 boxMinWorld = node->GetWorldPosition() + (node->GetWorldScale() * node->boxMin); math::vec3 boxMaxWorld = node->GetWorldPosition() + (node->GetWorldScale() * node->boxMax); - m_CommandBuffer->Push(node->mesh, node->material, node->GetTransform(), node->GetPrevTransform(), boxMinWorld, boxMaxWorld, target); + m_CommandBuffer->Push(node->mesh, node->material, node->GetTransform(), node->GetPrevTransform(), boxMinWorld, boxMaxWorld, target); } - for(unsigned int i = 0; i < node->GetChildCount(); ++i) + for (unsigned int i = 0; i < node->GetChildCount(); ++i) nodeStack.push(node->GetChildByIndex(i)); } } @@ -234,7 +232,7 @@ namespace Cell } // ------------------------------------------------------------------------ void Renderer::RenderPushedCommands() - { + { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); /* @@ -272,7 +270,7 @@ namespace Cell std::vector deferredRenderCommands = m_CommandBuffer->GetDeferredRenderCommands(true); glViewport(0, 0, m_RenderSize.x, m_RenderSize.y); glBindFramebuffer(GL_FRAMEBUFFER, m_GBuffer->ID); - unsigned int attachments[4] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2, GL_COLOR_ATTACHMENT3 }; + unsigned int attachments[4] = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2, GL_COLOR_ATTACHMENT3}; glDrawBuffers(4, attachments); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); m_GLCache.SetPolygonMode(Wireframe ? GL_LINE : GL_FILL); @@ -307,10 +305,10 @@ namespace Cell glViewport(0, 0, m_ShadowRenderTargets[shadowRtIndex]->Width, m_ShadowRenderTargets[shadowRtIndex]->Height); glClear(GL_DEPTH_BUFFER_BIT); - math::mat4 lightProjection = math::orthographic(-20.0f, 20.0f, 20.0f, -20.0f, -15.0f, 20.0f); - math::mat4 lightView = math::lookAt(-light->Direction * 10.0f, math::vec3(0.0), math::vec3::UP); + math::mat4 lightProjection = math::orthographic(-20.0f, 20.0f, 20.0f, -20.0f, -15.0f, 20.0f); + math::mat4 lightView = math::lookAt(-light->Direction * 10.0f, math::vec3(0.0), math::vec3::UP); m_DirectionalLights[i]->LightSpaceViewProjection = lightProjection * lightView; - m_DirectionalLights[i]->ShadowMapRT = m_ShadowRenderTargets[shadowRtIndex]; + m_DirectionalLights[i]->ShadowMapRT = m_ShadowRenderTargets[shadowRtIndex]; for (int j = 0; j < shadowRenderCommands.size(); ++j) { renderShadowCastCommand(&shadowRenderCommands[j], lightProjection, lightView); @@ -339,7 +337,7 @@ namespace Cell m_GBuffer->GetColorTexture(0)->Bind(0); m_GBuffer->GetColorTexture(1)->Bind(1); m_GBuffer->GetColorTexture(2)->Bind(2); - + // ambient lighting renderDeferredAmbient(); @@ -371,16 +369,15 @@ namespace Cell glBindFramebuffer(GL_READ_FRAMEBUFFER, m_GBuffer->ID); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_CustomTarget->ID); // write to default framebuffer glBlitFramebuffer( - 0, 0, m_GBuffer->Width, m_GBuffer->Height, 0, 0, m_RenderSize.x, m_RenderSize.y, GL_DEPTH_BUFFER_BIT, GL_NEAREST - ); + 0, 0, m_GBuffer->Width, m_GBuffer->Height, 0, 0, m_RenderSize.x, m_RenderSize.y, GL_DEPTH_BUFFER_BIT, GL_NEAREST); - // 6. custom forward render pass - // push default render target to the end of the render target buffer s.t. we always render + // 6. custom forward render pass + // push default render target to the end of the render target buffer s.t. we always render // the default buffer last. - m_RenderTargetsCustom.push_back(nullptr); + m_RenderTargetsCustom.push_back(nullptr); for (unsigned int targetIndex = 0; targetIndex < m_RenderTargetsCustom.size(); ++targetIndex) { - RenderTarget *renderTarget = m_RenderTargetsCustom[targetIndex]; + RenderTarget* renderTarget = m_RenderTargetsCustom[targetIndex]; if (renderTarget) { glViewport(0, 0, renderTarget->Width, renderTarget->Height); @@ -389,17 +386,17 @@ namespace Cell glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); else glClear(GL_COLOR_BUFFER_BIT); - m_Camera->SetPerspective(m_Camera->FOV, - (float)renderTarget->Width / (float)renderTarget->Height, - 0.1, 100.0f); + m_Camera->SetPerspective(m_Camera->FOV, + (float)renderTarget->Width / (float)renderTarget->Height, + 0.1, 100.0f); } else { - // don't render to default framebuffer, but to custom target framebuffer which + // don't render to default framebuffer, but to custom target framebuffer which // we'll use for post-processing. glViewport(0, 0, m_RenderSize.x, m_RenderSize.y); glBindFramebuffer(GL_FRAMEBUFFER, m_CustomTarget->ID); - m_Camera->SetPerspective(m_Camera->FOV, m_RenderSize.x / m_RenderSize.y, 0.1, + m_Camera->SetPerspective(m_Camera->FOV, m_RenderSize.x / m_RenderSize.y, 0.1, 100.0f); } @@ -433,7 +430,7 @@ namespace Cell RenderCommand command; command.material = m_MaterialLibrary->debugLightMaterial; - command.mesh = m_DebugLightMesh; + command.mesh = m_DebugLightMesh; math::mat4 model; math::translate(model, (*it)->Position); math::scale(model, math::vec3(0.25f)); @@ -443,7 +440,7 @@ namespace Cell } } - // 8. post-processing stage after all lighting calculations + // 8. post-processing stage after all lighting calculations m_PostProcessor->ProcessPostLighting(this, m_GBuffer, m_CustomTarget, m_Camera); // 9. render debug visuals @@ -459,7 +456,7 @@ namespace Cell RenderCommand command; command.material = m_MaterialLibrary->debugLightMaterial; - command.mesh = m_DebugLightMesh; + command.mesh = m_DebugLightMesh; math::mat4 model; math::translate(model, (*it)->Position); math::scale(model, math::vec3((*it)->Radius)); @@ -482,7 +479,7 @@ namespace Cell // ping-pong between render textures bool even = i % 2 == 0; Blit(even ? m_CustomTarget->GetColorTexture(0) : m_PostProcessTarget1->GetColorTexture(0), - even ? m_PostProcessTarget1 : m_CustomTarget, + even ? m_PostProcessTarget1 : m_CustomTarget, postProcessingCommands[i].material); } @@ -501,8 +498,8 @@ namespace Cell } // ------------------------------------------------------------------------ void Renderer::Blit(Texture* src, - RenderTarget* dst, - Material* material, + RenderTarget* dst, + Material* material, std::string textureUniformName) { // if a destination target is given, bind to its framebuffer @@ -535,9 +532,9 @@ namespace Cell // render screen-space material to quad which will be displayed in dst's buffers. RenderCommand command; command.material = material; - command.mesh = m_NDCPlane; + command.mesh = m_NDCPlane; renderCustomCommand(&command, nullptr); - } + } // ------------------------------------------------------------------------ void Renderer::SetSkyCapture(PBRCapture* pbrEnvironment) { @@ -556,22 +553,22 @@ namespace Cell // ------------------------------------------------------------------------ void Renderer::BakeProbes(SceneNode* scene) { - if(!scene) + if (!scene) { // if no scene node was provided, use root node (capture all) scene = Scene::Root; } scene->UpdateTransform(); // build a command list of nodes within the reflection probe's capture box/radius. - CommandBuffer commandBuffer(this); + CommandBuffer commandBuffer(this); std::vector materials; - + // originally a recursive function but transformed to iterative version std::stack sceneStack; sceneStack.push(scene); while (!sceneStack.empty()) { - SceneNode *node = sceneStack.top(); + SceneNode* node = sceneStack.top(); sceneStack.pop(); if (node->mesh != nullptr) { @@ -595,7 +592,7 @@ namespace Cell commandBuffer.Push(node->mesh, materials[materials.size() - 1], node->GetTransform()); } else if (samplerUniforms.find("background") != samplerUniforms.end()) - { // we have a background scene node, add those as well + { // we have a background scene node, add those as well materials.push_back(new Material(m_PBR->m_ProbeCaptureBackgroundShader)); materials[materials.size() - 1]->SetTextureCube("background", samplerUniforms["background"].textureCube, 0); materials[materials.size() - 1]->DepthCompare = node->material->DepthCompare; @@ -624,18 +621,18 @@ namespace Cell { delete materials[i]; } - } + } // ------------------------------------------------------------------------ void Renderer::renderCustomCommand(RenderCommand* command, Camera* customCamera, bool updateGLSettings) { - Material *material = command->material; - Mesh *mesh = command->mesh; + Material* material = command->material; + Mesh* mesh = command->mesh; // update global GL blend state based on material if (updateGLSettings) { m_GLCache.SetBlend(material->Blend); - if(material->Blend) + if (material->Blend) { m_GLCache.SetBlendFunc(material->BlendSrc, material->BlendDst); } @@ -645,14 +642,14 @@ namespace Cell m_GLCache.SetCullFace(material->CullFace); } - // default uniforms that are always configured regardless of shader configuration (see them + // default uniforms that are always configured regardless of shader configuration (see them // as a default set of shader uniform variables always there); with UBO material->GetShader()->Use(); if (customCamera) // pass custom camera specific uniform { material->GetShader()->SetMatrix("projection", customCamera->Projection); - material->GetShader()->SetMatrix("view", customCamera->View); - material->GetShader()->SetVector("CamPos", customCamera->Position); + material->GetShader()->SetMatrix("view", customCamera->View); + material->GetShader()->SetVector("CamPos", customCamera->Position); } material->GetShader()->SetMatrix("model", command->transform); material->GetShader()->SetMatrix("prevModel", command->prevTransform); @@ -722,12 +719,12 @@ namespace Cell renderMesh(mesh, material->GetShader()); } // ------------------------------------------------------------------------ - void Renderer::renderToCubemap(SceneNode* scene, - TextureCube* target, - math::vec3 position, - unsigned int mipLevel) + void Renderer::renderToCubemap(SceneNode* scene, + TextureCube* target, + math::vec3 position, + unsigned int mipLevel) { - // create a command buffer specifically for this operation (as to not conflict with main + // create a command buffer specifically for this operation (as to not conflict with main // command buffer) CommandBuffer commandBuffer(this); commandBuffer.Push(scene->mesh, scene->material, scene->GetTransform()); @@ -737,7 +734,7 @@ namespace Cell childStack.push(scene->GetChildByIndex(i)); while (!childStack.empty()) { - SceneNode *child = childStack.top(); + SceneNode* child = childStack.top(); childStack.pop(); commandBuffer.Push(child->mesh, child->material, child->GetTransform()); for (unsigned int i = 0; i < child->GetChildCount(); ++i) @@ -753,23 +750,22 @@ namespace Cell { // define 6 camera directions/lookup vectors Camera faceCameras[6] = { - Camera(position, math::vec3(1.0f, 0.0f, 0.0f), math::vec3(0.0f, -1.0f, 0.0f)), - Camera(position, math::vec3(-1.0f, 0.0f, 0.0f), math::vec3(0.0f, -1.0f, 0.0f)), - Camera(position, math::vec3(0.0f, 1.0f, 0.0f), math::vec3(0.0f, 0.0f, 1.0f)), - Camera(position, math::vec3(0.0f, -1.0f, 0.0f), math::vec3(0.0f, 0.0f,-1.0f)), - Camera(position, math::vec3(0.0f, 0.0f, 1.0f), math::vec3(0.0f, -1.0f, 0.0f)), - Camera(position, math::vec3(0.0f, 0.0f, -1.0f), math::vec3(0.0f, -1.0f, 0.0f)) - }; + Camera(position, math::vec3(1.0f, 0.0f, 0.0f), math::vec3(0.0f, -1.0f, 0.0f)), + Camera(position, math::vec3(-1.0f, 0.0f, 0.0f), math::vec3(0.0f, -1.0f, 0.0f)), + Camera(position, math::vec3(0.0f, 1.0f, 0.0f), math::vec3(0.0f, 0.0f, 1.0f)), + Camera(position, math::vec3(0.0f, -1.0f, 0.0f), math::vec3(0.0f, 0.0f, -1.0f)), + Camera(position, math::vec3(0.0f, 0.0f, 1.0f), math::vec3(0.0f, -1.0f, 0.0f)), + Camera(position, math::vec3(0.0f, 0.0f, -1.0f), math::vec3(0.0f, -1.0f, 0.0f))}; // resize target dimensions based on mip level we're rendering. - float width = (float)target->FaceWidth * std::pow(0.5, mipLevel); + float width = (float)target->FaceWidth * std::pow(0.5, mipLevel); float height = (float)target->FaceHeight * std::pow(0.5, mipLevel); glBindFramebuffer(GL_FRAMEBUFFER, m_FramebufferCubemap); glBindRenderbuffer(GL_RENDERBUFFER, m_CubemapDepthRBO); glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, width, height); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, - m_CubemapDepthRBO); + m_CubemapDepthRBO); // resize relevant buffers glViewport(0, 0, width, height); @@ -777,14 +773,14 @@ namespace Cell for (unsigned int i = 0; i < 6; ++i) { - Camera *camera = &faceCameras[i]; + Camera* camera = &faceCameras[i]; camera->SetPerspective(math::Deg2Rad(90.0f), width / height, 0.1f, 100.0f); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, - GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, target->ID, mipLevel); + GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, target->ID, mipLevel); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); for (unsigned int i = 0; i < renderCommands.size(); ++i) { - // cubemap generation only works w/ custom materials + // cubemap generation only works w/ custom materials assert(renderCommands[i].material->Type == MATERIAL_CUSTOM); renderCustomCommand(&renderCommands[i], camera); } @@ -808,8 +804,8 @@ namespace Cell { glBindBuffer(GL_UNIFORM_BUFFER, m_GlobalUBO); // transformation matrices - glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(math::mat4), &(m_Camera->Projection * m_Camera->View)[0][0]); // sizeof(math::mat4) = 64 bytes - glBufferSubData(GL_UNIFORM_BUFFER, 64, sizeof(math::mat4), &m_PrevViewProjection[0][0]); + glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(math::mat4), &(m_Camera->Projection * m_Camera->View)[0][0]); // sizeof(math::mat4) = 64 bytes + glBufferSubData(GL_UNIFORM_BUFFER, 64, sizeof(math::mat4), &m_PrevViewProjection[0][0]); glBufferSubData(GL_UNIFORM_BUFFER, 128, sizeof(math::mat4), &m_Camera->Projection[0][0]); glBufferSubData(GL_UNIFORM_BUFFER, 192, sizeof(math::mat4), &m_Camera->View[0][0]); glBufferSubData(GL_UNIFORM_BUFFER, 256, sizeof(math::mat4), &m_Camera->View[0][0]); // TODO: make inv function in math library @@ -819,12 +815,12 @@ namespace Cell unsigned int stride = 2 * sizeof(math::vec4); for (unsigned int i = 0; i < m_DirectionalLights.size() && i < 4; ++i) // no more than 4 directional lights { - glBufferSubData(GL_UNIFORM_BUFFER, 336 + i * stride, sizeof(math::vec4), &m_DirectionalLights[i]->Direction[0]); + glBufferSubData(GL_UNIFORM_BUFFER, 336 + i * stride, sizeof(math::vec4), &m_DirectionalLights[i]->Direction[0]); glBufferSubData(GL_UNIFORM_BUFFER, 336 + i * stride + sizeof(math::vec4), sizeof(math::vec4), &m_DirectionalLights[i]->Color[0]); } for (unsigned int i = 0; i < m_PointLights.size() && i < 8; ++i) // constrained to max 8 point lights in forward context { - glBufferSubData(GL_UNIFORM_BUFFER, 464 + i * stride, sizeof(math::vec4), &m_PointLights[i]->Position[0]); + glBufferSubData(GL_UNIFORM_BUFFER, 464 + i * stride, sizeof(math::vec4), &m_PointLights[i]->Position[0]); glBufferSubData(GL_UNIFORM_BUFFER, 464 + i * stride + sizeof(math::vec4), sizeof(math::vec4), &m_PointLights[i]->Color[0]); } } @@ -836,8 +832,8 @@ namespace Cell // -------------------------------------------------------------------------------------------- void Renderer::renderDeferredAmbient() { - PBRCapture* skyCapture = m_PBR->GetSkyCapture(); - auto irradianceProbes = m_PBR->m_CaptureProbes; + PBRCapture* skyCapture = m_PBR->GetSkyCapture(); + auto irradianceProbes = m_PBR->m_CaptureProbes; // if irradiance probes are present, use these as ambient lighting if (IrradianceGI && irradianceProbes.size() > 0) @@ -894,7 +890,7 @@ namespace Cell dirShader->Use(); dirShader->SetVector("camPos", m_Camera->Position); dirShader->SetVector("lightDir", light->Direction); - dirShader->SetVector("lightColor", math::normalize(light->Color) * light->Intensity); + dirShader->SetVector("lightColor", math::normalize(light->Color) * light->Intensity); dirShader->SetBool("ShadowsEnabled", Shadows); if (light->ShadowMapRT) @@ -902,13 +898,13 @@ namespace Cell dirShader->SetMatrix("lightShadowViewProjection", light->LightSpaceViewProjection); light->ShadowMapRT->GetDepthStencilTexture()->Bind(3); } - + renderMesh(m_NDCPlane, dirShader); } // -------------------------------------------------------------------------------------------- void Renderer::renderDeferredPointLight(PointLight* light) { - Shader *pointShader = m_MaterialLibrary->deferredPointShader; + Shader* pointShader = m_MaterialLibrary->deferredPointShader; pointShader->Use(); pointShader->SetVector("camPos", m_Camera->Position); @@ -921,7 +917,7 @@ namespace Cell math::scale(model, math::vec3(light->Radius)); pointShader->SetMatrix("model", model); - renderMesh(m_DeferredPointMesh, pointShader); + renderMesh(m_DeferredPointMesh, pointShader); } // -------------------------------------------------------------------------------------------- void Renderer::renderShadowCastCommand(RenderCommand* command, const math::mat4& projection, const math::mat4& view) diff --git a/cell/scene/scene_node.cpp b/cell/scene/scene_node.cpp index 7f19077..54a9845 100644 --- a/cell/scene/scene_node.cpp +++ b/cell/scene/scene_node.cpp @@ -12,7 +12,6 @@ namespace Cell // -------------------------------------------------------------------------------------------- SceneNode::SceneNode(unsigned int id) : m_ID(id), m_Parent(nullptr) { - } // -------------------------------------------------------------------------------------------- SceneNode::~SceneNode() @@ -29,13 +28,13 @@ namespace Cell void SceneNode::SetPosition(math::vec3 position) { m_Position = position; - m_Dirty = true; + m_Dirty = true; } // -------------------------------------------------------------------------------------------- void SceneNode::SetRotation(math::vec4 rotation) { m_Rotation = rotation; - m_Dirty = true; + m_Dirty = true; } // -------------------------------------------------------------------------------------------- void SceneNode::SetScale(math::vec3 scale) @@ -68,17 +67,17 @@ namespace Cell math::vec3 SceneNode::GetWorldPosition() { math::mat4 transform = GetTransform(); - math::vec4 pos = transform * math::vec4(m_Position, 1.0f); + math::vec4 pos = transform * math::vec4(m_Position, 1.0f); return pos.xyz; } // -------------------------------------------------------------------------------------------- math::vec3 SceneNode::GetWorldScale() { math::mat4 transform = GetTransform(); - math::vec3 scale = math::vec3(transform[0][0], transform[1][1], transform[2][2]); + math::vec3 scale = math::vec3(transform[0][0], transform[1][1], transform[2][2]); if (scale.x < 0.0f) scale.x *= -1.0f; if (scale.y < 0.0f) scale.y *= -1.0f; - if(scale.z < 0.0f) scale.z *= -1.0f; + if (scale.z < 0.0f) scale.z *= -1.0f; return scale; } // -------------------------------------------------------------------------------------------- @@ -87,9 +86,9 @@ namespace Cell return m_ID; } // -------------------------------------------------------------------------------------------- - void SceneNode::AddChild(SceneNode *node) + void SceneNode::AddChild(SceneNode* node) { - // check if this child already has a parent. If so, first remove this scene node from its + // check if this child already has a parent. If so, first remove this scene node from its // current parent. Scene nodes aren't allowed to exist under multiple parents. if (node->m_Parent != nullptr) { @@ -102,7 +101,7 @@ namespace Cell void SceneNode::RemoveChild(unsigned int id) { auto it = std::find(m_Children.begin(), m_Children.end(), GetChild(id)); - if(it != m_Children.end()) + if (it != m_Children.end()) m_Children.erase(it); } // -------------------------------------------------------------------------------------------- @@ -116,11 +115,11 @@ namespace Cell return m_Children.size(); } // -------------------------------------------------------------------------------------------- - SceneNode *SceneNode::GetChild(unsigned int id) + SceneNode* SceneNode::GetChild(unsigned int id) { for (unsigned int i = 0; i < m_Children.size(); ++i) { - if(m_Children[i]->GetID() == id) + if (m_Children[i]->GetID() == id) return m_Children[i]; } return nullptr; @@ -132,7 +131,7 @@ namespace Cell return m_Children[index]; } // -------------------------------------------------------------------------------------------- - SceneNode *SceneNode::GetParent() + SceneNode* SceneNode::GetParent() { return m_Parent; } @@ -156,7 +155,7 @@ namespace Cell // if specified, store current transform as prev transform (for calculating motion vectors) if (updatePrevTransform) { - m_PrevTransform = m_Transform; + m_PrevTransform = m_Transform; } // we only do this if the node itself or its parent is flagged as dirty if (m_Dirty) @@ -168,7 +167,7 @@ namespace Cell if (m_Parent != nullptr) { m_Transform = m_Parent->m_Transform * m_Transform; - } + } } for (int i = 0; i < m_Children.size(); ++i) { diff --git a/cell/scene/scene_node.h b/cell/scene/scene_node.h index b118149..1462f88 100644 --- a/cell/scene/scene_node.h +++ b/cell/scene/scene_node.h @@ -46,7 +46,7 @@ namespace Cell math::vec3 m_Scale = math::vec3(1.0f); // mark the current node's tranform as dirty if it needs to be re-calculated this frame - bool m_Dirty; + bool m_Dirty{true}; // each node is uniquely identified by a 32-bit incrementing unsigned integer unsigned int m_ID; From 05c7f5f45f1405bb53e3c2041f1c829893183da5 Mon Sep 17 00:00:00 2001 From: Jens Behley Date: Wed, 28 Mar 2018 01:51:19 +0200 Subject: [PATCH 30/31] memory leak? --- cell/scene/background.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cell/scene/background.cpp b/cell/scene/background.cpp index 6b6f06b..96b97d1 100644 --- a/cell/scene/background.cpp +++ b/cell/scene/background.cpp @@ -32,7 +32,8 @@ namespace Cell // -------------------------------------------------------------------------------------------- Background::~Background() { - + delete material; + delete mesh; } // -------------------------------------------------------------------------------------------- void Background::SetCubemap(TextureCube* cubemap) From 689e0b799484bd0638f3fb662f77300365716b3e Mon Sep 17 00:00:00 2001 From: jbehley Date: Wed, 28 Mar 2018 09:25:55 +0200 Subject: [PATCH 31/31] fixed issue with probes. now the shader compiles and the results look not that dark/dim. --- build/shaders/capture.fs | 5 ++++- build/shaders/capture.vs | 7 ++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/build/shaders/capture.fs b/build/shaders/capture.fs index c4e51a5..a038ec1 100644 --- a/build/shaders/capture.fs +++ b/build/shaders/capture.fs @@ -6,7 +6,10 @@ in vec2 TexCoords; in vec3 FragPos; in vec3 Normal; -#include common/uniforms.glsl +// #include common/uniforms.glsl +uniform vec4 camPos; +uniform vec4 dirLight0_Dir; +uniform vec4 dirLight0_Col; uniform sampler2D TexAlbedo; uniform sampler2D TexNormal; diff --git a/build/shaders/capture.vs b/build/shaders/capture.vs index 0b8a803..79cd063 100644 --- a/build/shaders/capture.vs +++ b/build/shaders/capture.vs @@ -7,10 +7,11 @@ out vec2 TexCoords; out vec3 FragPos; out vec3 Normal; -#include common/uniforms.glsl +// #include common/uniforms.glsl -// uniform mat4 projection; -// uniform mat4 view; + +uniform mat4 projection; +uniform mat4 view; uniform mat4 model; void main()