From 57c870c79a49aa68a7b978deacabcf0b4f7d4572 Mon Sep 17 00:00:00 2001 From: Hapaxia Date: Thu, 12 Jan 2023 16:34:25 +0000 Subject: [PATCH 01/64] Update .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 6164850..1a85d20 100644 --- a/.gitignore +++ b/.gitignore @@ -13,6 +13,7 @@ *.props *.vc.db *.vc.vc.opendb +*.bak licence for header.txt From 5823e2bb2adb38bab43abc839272df6bc841a482 Mon Sep 17 00:00:00 2001 From: Hapaxia Date: Thu, 12 Jan 2023 16:36:30 +0000 Subject: [PATCH 02/64] Update .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 1a85d20..f6f9d67 100644 --- a/.gitignore +++ b/.gitignore @@ -14,6 +14,7 @@ *.vc.db *.vc.vc.opendb *.bak +priv_*.* licence for header.txt From 9c6d971ed0825441a705c5e5a5ad1136c1d7ee99 Mon Sep 17 00:00:00 2001 From: Hapaxia Date: Tue, 9 May 2023 01:42:03 +0100 Subject: [PATCH 03/64] Update .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index f6f9d67..afeb4e8 100644 --- a/.gitignore +++ b/.gitignore @@ -26,6 +26,7 @@ extlibs/ backup/ backup_*/ test/ +test-*/ test_*/ temp/ temp_*/ From 5c9ca71a1bc8c5093c8277efcc454897f7c10734 Mon Sep 17 00:00:00 2001 From: Hapaxia Date: Tue, 9 May 2023 16:26:56 +0100 Subject: [PATCH 04/64] Line - update to v1.2.3 patch update. since updating Selba Ward to no longer use quads, Line uses a triangle strip. However, it had been setup similar to other objects - that instead use triangles - following the 6 vertices per quad rule. this caused attempts at accessing vertices that didn't exist as the triangle strip only needs 4 vertices for a quad. this fixes that problem, reducing all vertex looping to only go 4 times and no attempting to access the 5th and 6th vertex that do not exist. --- src/SelbaWard/Line.cpp | 6 ++---- src/SelbaWard/Line.hpp | 2 +- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/SelbaWard/Line.cpp b/src/SelbaWard/Line.cpp index f922df4..0eab1e1 100644 --- a/src/SelbaWard/Line.cpp +++ b/src/SelbaWard/Line.cpp @@ -97,7 +97,7 @@ sf::FloatRect Line::getLocalBounds() const float minX, maxX, minY, maxY; minX = maxX = m_quad[0].position.x; minY = maxY = m_quad[0].position.y; - for (unsigned int v{ 1u }; v < 6u; ++v) + for (unsigned int v{ 1u }; v < 4u; ++v) { minX = std::min(minX, m_quad[v].position.x); maxX = std::max(maxX, m_quad[v].position.x); @@ -129,7 +129,7 @@ sf::FloatRect Line::getGlobalBounds() const float minX, maxX, minY, maxY; minX = maxX = transformedPosition0.x; minY = maxY = transformedPosition0.y; - for (unsigned int v{ 1u }; v < 6u; ++v) + for (unsigned int v{ 1u }; v < 4u; ++v) { const sf::Vector2f transformedPosition{ transform.transformPoint(m_quad[v].position) }; minX = std::min(minX, transformedPosition.x); @@ -177,8 +177,6 @@ void Line::setColor(const sf::Color& color) m_quad[1u].color = color; m_quad[2u].color = color; m_quad[3u].color = color; - m_quad[4u].color = color; - m_quad[5u].color = color; } void Line::setTexture(const sf::Texture& texture) diff --git a/src/SelbaWard/Line.hpp b/src/SelbaWard/Line.hpp index 66e9990..308ab02 100644 --- a/src/SelbaWard/Line.hpp +++ b/src/SelbaWard/Line.hpp @@ -41,7 +41,7 @@ namespace selbaward { -// SW Line v1.2.2 +// SW Line v1.2.3 class Line : public sf::Drawable, public sf::Transformable { public: From 5616dae62972dadfc0c8048f89517f968ae449ff Mon Sep 17 00:00:00 2001 From: Hapaxia Date: Wed, 24 May 2023 21:38:44 +0100 Subject: [PATCH 05/64] Update .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index f6f9d67..ff2a551 100644 --- a/.gitignore +++ b/.gitignore @@ -27,6 +27,7 @@ backup/ backup_*/ test/ test_*/ +test-*/ temp/ temp_*/ temp_storage/ From 885400993240abc73abcf7679dba6db5c2092677 Mon Sep 17 00:00:00 2001 From: Hapaxia Date: Mon, 29 May 2023 23:23:07 +0100 Subject: [PATCH 06/64] add Starfield 3D add new drawable: Starfield 3D similar to Starfield, it creates a randomised set of stars that can be moved with parallax. however, this version uses actual 3D projection and allows Z movement as well. you can specify the front and back colours as well as the front and back scale (of the star shape) and they are automatically "tweened" between them. included is the ability to create a "star template" that is the shape of each star. it can be any shape or colour. colours are multiplied with the colour (from the front and back colours). you can "move" in all three dimensions and pan in two dimension. "roll" rotation is not included; you can simply use the sf::Drawable's rotation feature for that. --- src/SelbaWard/Starfield3d.cpp | 332 ++++++++++++++++++++++++++++++++++ src/SelbaWard/Starfield3d.hpp | 107 +++++++++++ 2 files changed, 439 insertions(+) create mode 100644 src/SelbaWard/Starfield3d.cpp create mode 100644 src/SelbaWard/Starfield3d.hpp diff --git a/src/SelbaWard/Starfield3d.cpp b/src/SelbaWard/Starfield3d.cpp new file mode 100644 index 0000000..070a0cd --- /dev/null +++ b/src/SelbaWard/Starfield3d.cpp @@ -0,0 +1,332 @@ +////////////////////////////////////////////////////////////////////////////// +// +// Selba Ward (https://github.com/Hapaxia/SelbaWard) +// -- +// +// Starfield 3D +// +// Copyright(c) 2023 M.J.Silk +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions : +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software.If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +// M.J.Silk +// MJSilk2@gmail.com +// +////////////////////////////////////////////////////////////////////////////// + +#include "Starfield3d.hpp" + +#include +#include +#include + +namespace +{ + +std::mt19937 randomGenerator; +std::uniform_int_distribution randomDistributionAlpha(1u, 255u); +std::function randomAlpha; + +inline void randomSeed() +{ + std::random_device rd; + randomGenerator.seed(rd()); + randomAlpha = std::bind(randomDistributionAlpha, randomGenerator); +} + +inline float randomValue(const float low, const float high) +{ + return std::uniform_real_distribution{low, high}(randomGenerator); +} + +template +inline T linearTween(const T start, const T end, const float alpha) +{ + return static_cast((start * (1.f - alpha)) + (end * alpha)); +} + +inline sf::Color linearTween(const sf::Color& start, const sf::Color& end, const float alpha) +{ + return{ linearTween(start.r, end.r, alpha), linearTween(start.g, end.g, alpha), linearTween(start.b, end.b, alpha), linearTween(start.a, end.a, alpha) }; +} + +} // namespace + +namespace selbaward +{ + +Starfield3d::Starfield3d(const sf::Vector2f size, const std::size_t numberOfStars, const float maxDepth, const sf::Color& frontColor, const sf::Color& backColor, const float frontScale, const float backScale) + : m_depthCalibration{ 0.001f } + , m_depthSpeedCalibration{ 0.93f } + , m_isUpdateRequired{ true } + , m_size{ size } + , m_numberOfStars{ numberOfStars } + , m_positions(numberOfStars) + , m_starTemplate(6u) + , m_primitiveType{ sf::PrimitiveType::Triangles } + , m_vertices(numberOfStars) + , m_deepestSliceBounds() + , m_maxDepth{ maxDepth } + , m_frontColor{ frontColor } + , m_backColor{ backColor } + , m_frontScale{ frontScale } + , m_backScale{ backScale } +{ + randomSeed(); + regenerate(); + + m_starTemplate[0u].position = { 0.f, 1.f }; + m_starTemplate[1u].position = { 1.f, -0.5f }; + m_starTemplate[2u].position = { -1.f, -0.5f }; + m_starTemplate[3u].position = { 0.f, -1.f }; + m_starTemplate[4u].position = { -1.f, 0.5f }; + m_starTemplate[5u].position = { 1.f, 0.5f }; + + // color + for (auto& v : m_starTemplate) + v.color = sf::Color::White; +} + +void Starfield3d::move(const sf::Vector3f movement) +{ + m_isUpdateRequired = true; + for (auto& position : m_positions) + { + // move + position -= movement * std::pow(m_maxDepth * m_depthCalibration, m_depthSpeedCalibration); + + // wrap depth + if (position.z < 0.f) + position = priv_generateRandomStarPosition(EdgeLock::Back); + else if (position.z > m_maxDepth) + position = priv_generateRandomStarPosition(EdgeLock::Front); + + // wrap 2D (xy slice) + if (position.x < m_deepestSliceBounds.left) + position = priv_generateRandomStarPosition(EdgeLock::Right); + else if (position.x > (m_deepestSliceBounds.left + m_deepestSliceBounds.width)) + position = priv_generateRandomStarPosition(EdgeLock::Left); + if (position.y < m_deepestSliceBounds.top) + position = priv_generateRandomStarPosition(EdgeLock::Bottom); + else if (position.y > (m_deepestSliceBounds.top + m_deepestSliceBounds.height)) + position = priv_generateRandomStarPosition(EdgeLock::Top); + + } +} + +void Starfield3d::pan(const sf::Vector2f panAmount) +{ + m_isUpdateRequired = true; + const sf::Vector3f movement{ panAmount.x, panAmount.y, 0.f }; + for (auto& position : m_positions) + { + // move + position -= movement * (((1.f + position.z) * m_depthCalibration - 1.f)); + + // wrap 2D (xy slice) + if (position.x < m_deepestSliceBounds.left) + position = priv_generateRandomStarPosition(EdgeLock::Right); + else if (position.x > (m_deepestSliceBounds.left + m_deepestSliceBounds.width)) + position = priv_generateRandomStarPosition(EdgeLock::Left); + if (position.y < m_deepestSliceBounds.top) + position = priv_generateRandomStarPosition(EdgeLock::Bottom); + else if (position.y > (m_deepestSliceBounds.top + m_deepestSliceBounds.height)) + position = priv_generateRandomStarPosition(EdgeLock::Top); + + } +} + +void Starfield3d::regenerate() +{ + m_deepestSliceBounds = priv_calculateFrustumSliceBounds(m_maxDepth); + + m_positions.resize(m_numberOfStars); + for (auto& position : m_positions) + position = priv_generateRandomStarPosition(); +} + +void Starfield3d::regenerate(const sf::Vector2f size) +{ + m_size = size; + regenerate(); +} + +void Starfield3d::regenerate(const sf::Vector2f size, const std::size_t numberOfStars) +{ + m_numberOfStars = numberOfStars; + regenerate(size); +} + +void Starfield3d::regenerate(const std::size_t numberOfStars) +{ + regenerate(m_size, numberOfStars); +} + +void Starfield3d::setMaxDepth(const float maxDepth) +{ + m_isUpdateRequired = true; + m_maxDepth = maxDepth; +} + +void Starfield3d::setFrontColor(const sf::Color& color) +{ + m_isUpdateRequired = true; + m_frontColor = color; +} + +void Starfield3d::setBackColor(const sf::Color& color) +{ + m_isUpdateRequired = true; + m_backColor = color; +} + +void Starfield3d::setFrontScale(const float frontScale) +{ + m_isUpdateRequired = true; + m_frontScale = frontScale; +} + +void Starfield3d::setBackScale(const float backScale) +{ + m_isUpdateRequired = true; + m_backScale = backScale; +} + +void Starfield3d::setStarTemplate(const std::vector& vertices) +{ + m_isUpdateRequired = true; + m_starTemplate = vertices; +} + +void Starfield3d::setStarTemplate(const std::vector& vertices) +{ + m_isUpdateRequired = true; + m_starTemplate.resize(vertices.size()); + for (std::size_t i{ 0u }; i < m_starTemplate.size(); ++i) + { + m_starTemplate[i].position = vertices[i]; + m_starTemplate[i].color = sf::Color::White; + } +} + +void Starfield3d::setStarTemplate(const sf::VertexArray& vertexArray) +{ + m_isUpdateRequired = true; + m_starTemplate.resize(vertexArray.getVertexCount()); + for (std::size_t i{ 0u }; i < m_starTemplate.size(); ++i) + m_starTemplate[i] = vertexArray[i]; +} + + + +// PRIVATE + +void Starfield3d::draw(sf::RenderTarget& target, sf::RenderStates states) const +{ + if (m_isUpdateRequired) + priv_updateVertices(); + + states.transform *= getTransform(); + const std::size_t size{ m_vertices.size() }; + if (size > 0) + target.draw(m_vertices.data(), size, m_primitiveType, states); +} + +void Starfield3d::priv_updateVertices() const +{ + // positions' indices sorted by depth + m_positionIndices.resize(m_positions.size()); + for (std::size_t i{ 0u }; i < m_positionIndices.size(); ++i) + m_positionIndices[i] = i; + std::sort(m_positionIndices.begin(), m_positionIndices.end(), [&](std::size_t a, std::size_t b) { return m_positions[a].z > m_positions[b].z; }); + + // vertices + const std::size_t numberOfVerticesPerStar{ m_starTemplate.size() }; + m_vertices.resize(m_numberOfStars * numberOfVerticesPerStar); + for (std::size_t star{ 0u }; star < m_numberOfStars; ++star) + { + const std::size_t starIndex{ m_positionIndices[star] }; + const float depthRatio{ m_positions[starIndex].z / m_maxDepth }; + const float depthInverseRatio{ 1.f - depthRatio }; + const sf::Color color{ linearTween(m_frontColor, m_backColor, depthRatio) }; + const float depthScale{ linearTween(m_frontScale, m_backScale, depthRatio) }; + sf::Vector2f starPosition{ priv_projectPoint(m_positions[starIndex]) }; + for (std::size_t vertex{ 0u }; vertex < numberOfVerticesPerStar; ++vertex) + { + m_vertices[star * numberOfVerticesPerStar + vertex] = starPosition + (sf::Vector2f{ m_starTemplate[vertex].position.x, m_starTemplate[vertex].position.y } * depthScale); + m_vertices[star * numberOfVerticesPerStar + vertex].color = m_starTemplate[vertex].color * color; + } + } +} + +sf::Vector2f Starfield3d::priv_projectPoint(const sf::Vector3f point) const +{ + const sf::Vector2f center{ m_size / 2.f }; + const float depth{ (point.z < 0.f) ? 1.f : (m_depthCalibration * point.z) + 1.f }; + return { ((point.x - center.x) / depth) + center.x, ((point.y - center.y) / depth) + center.y }; +} + +sf::FloatRect Starfield3d::priv_calculateFrustumSliceBounds(float z) const +{ + z *= m_depthCalibration; + ++z; + const sf::Vector2f center{ m_size / 2.f }; + const sf::Vector2f topLeft{ (-center * z) + center }; + const sf::Vector2f bottomRight{ (center * z) + center }; + return { topLeft, bottomRight - topLeft }; +} + +sf::Vector3f Starfield3d::priv_generateRandomStarPosition() const +{ + sf::Vector3f position; + position.z = randomValue(0.f, m_maxDepth); + position.x = randomValue(m_deepestSliceBounds.left, m_deepestSliceBounds.left + m_deepestSliceBounds.width); + position.y = randomValue(m_deepestSliceBounds.top, m_deepestSliceBounds.top + m_deepestSliceBounds.height); + return position; +} + +sf::Vector3f Starfield3d::priv_generateRandomStarPosition(const EdgeLock edgeLock) const +{ + sf::Vector3f position; + + if (edgeLock == EdgeLock::Front) + position.z = 0.f; + else if (edgeLock == EdgeLock::Back) + position.z = m_maxDepth; + else + position.z = randomValue(0.f, m_maxDepth); + + if (edgeLock == EdgeLock::Left) + position.x = m_deepestSliceBounds.left; + else if (edgeLock == EdgeLock::Right) + position.x = m_deepestSliceBounds.left + m_deepestSliceBounds.width; + else + position.x = randomValue(m_deepestSliceBounds.left, m_deepestSliceBounds.left + m_deepestSliceBounds.width); + + if (edgeLock == EdgeLock::Top) + position.y = m_deepestSliceBounds.top; + else if (edgeLock == EdgeLock::Bottom) + position.y = m_deepestSliceBounds.top + m_deepestSliceBounds.height; + else + position.y = randomValue(m_deepestSliceBounds.top, m_deepestSliceBounds.top + m_deepestSliceBounds.height); + + return position; +} + +} // namespace selbaward diff --git a/src/SelbaWard/Starfield3d.hpp b/src/SelbaWard/Starfield3d.hpp new file mode 100644 index 0000000..b1ef6db --- /dev/null +++ b/src/SelbaWard/Starfield3d.hpp @@ -0,0 +1,107 @@ +////////////////////////////////////////////////////////////////////////////// +// +// Selba Ward (https://github.com/Hapaxia/SelbaWard) +// -- +// +// Starfield 3D +// +// Copyright(c) 2023 M.J.Silk +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions : +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software.If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +// M.J.Silk +// MJSilk2@gmail.com +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef SELBAWARD_STARFIELD3D_HPP +#define SELBAWARD_STARFIELD3D_HPP + +#include "Common.hpp" +#include +#include + +namespace selbaward +{ + +// SW Starfield3d v1.0.0 +class Starfield3d : public sf::Drawable, public sf::Transformable +{ +public: + Starfield3d(sf::Vector2f size = { 0.f, 0.f }, std::size_t numberOfStars = 400u, float maxDepth = 1000000.f, const sf::Color& frontColor = sf::Color(255u, 255u, 255u, 255u), const sf::Color& backColor = sf::Color(0u, 0u, 0u, 255u), float frontScale = 0.f, float backScale = 0.f); + void regenerate(); + void regenerate(sf::Vector2f size); + void regenerate(sf::Vector2f size, std::size_t numberOfStars); + void regenerate(std::size_t numberOfStars); + + void setMaxDepth(float maxDepth); + void setFrontColor(const sf::Color& color); + void setBackColor(const sf::Color& color); + void setFrontScale(float frontScale); + void setBackScale(float backScale); + + void setStarTemplate(const std::vector& vertices); + void setStarTemplate(const std::vector& vertices); + void setStarTemplate(const sf::VertexArray& vertexArray); // ignores primitive type - uses given vertices with sf::Triangles primitive type + + void move(sf::Vector3f movement); + void pan(sf::Vector2f panAmount); + +private: + const float m_depthCalibration; + const float m_depthSpeedCalibration; + bool m_isUpdateRequired; + sf::Vector2f m_size; + std::size_t m_numberOfStars; + std::vector m_positions; + float m_maxDepth; + sf::Color m_frontColor; + sf::Color m_backColor; + float m_frontScale; + float m_backScale; + + std::vector m_starTemplate; + + sf::PrimitiveType m_primitiveType; + mutable std::vector m_vertices; + mutable std::vector m_positionIndices; + mutable sf::FloatRect m_deepestSliceBounds; + + enum class EdgeLock + { + Left, + Right, + Top, + Bottom, + Front, + Back, + }; + + virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const; + + void priv_updateVertices() const; + sf::Vector2f priv_projectPoint(sf::Vector3f point) const; + sf::FloatRect priv_calculateFrustumSliceBounds(float z) const; + sf::Vector3f priv_generateRandomStarPosition() const; + sf::Vector3f priv_generateRandomStarPosition(EdgeLock edgeLock) const; + +}; + +} // namespace selbaward +#endif // SELBAWARD_STARFIELD3D_HPP From 94a39b8966558beb3c3ddb9662097f60a807b7db Mon Sep 17 00:00:00 2001 From: Hapaxia Date: Thu, 1 Jun 2023 16:09:14 +0100 Subject: [PATCH 07/64] add Starfield 3D to inclusion header --- src/SelbaWard.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/SelbaWard.hpp b/src/SelbaWard.hpp index d672e45..88a54d2 100644 --- a/src/SelbaWard.hpp +++ b/src/SelbaWard.hpp @@ -47,6 +47,7 @@ #include "SelbaWard/Spline.hpp" #include "SelbaWard/Sprite3d.hpp" #include "SelbaWard/Starfield.hpp" +#include "SelbaWard/Starfield3d.hpp" #include "SelbaWard/TileMap.hpp" #endif // SELBAWARD_HPP From fc3459abe6cd518469c1ddc0324bdae03e1bc750 Mon Sep 17 00:00:00 2001 From: Hapaxia Date: Sat, 3 Jun 2023 00:44:51 +0100 Subject: [PATCH 08/64] Starfield 3D - update to v1.0.1 patch update to fix the default parameter for frontScale. it was 0 (meaning nearest stars were not visible); it has been fixed and set to 1. --- src/SelbaWard/Starfield3d.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/SelbaWard/Starfield3d.hpp b/src/SelbaWard/Starfield3d.hpp index b1ef6db..5d2d58b 100644 --- a/src/SelbaWard/Starfield3d.hpp +++ b/src/SelbaWard/Starfield3d.hpp @@ -40,11 +40,11 @@ namespace selbaward { -// SW Starfield3d v1.0.0 +// SW Starfield3d v1.0.1 class Starfield3d : public sf::Drawable, public sf::Transformable { public: - Starfield3d(sf::Vector2f size = { 0.f, 0.f }, std::size_t numberOfStars = 400u, float maxDepth = 1000000.f, const sf::Color& frontColor = sf::Color(255u, 255u, 255u, 255u), const sf::Color& backColor = sf::Color(0u, 0u, 0u, 255u), float frontScale = 0.f, float backScale = 0.f); + Starfield3d(sf::Vector2f size = { 0.f, 0.f }, std::size_t numberOfStars = 400u, float maxDepth = 1000000.f, const sf::Color& frontColor = sf::Color(255u, 255u, 255u, 255u), const sf::Color& backColor = sf::Color(0u, 0u, 0u, 255u), float frontScale = 1.f, float backScale = 0.f); void regenerate(); void regenerate(sf::Vector2f size); void regenerate(sf::Vector2f size, std::size_t numberOfStars); From 02ab27afeac91bb8223109fb9b43e83056e19082 Mon Sep 17 00:00:00 2001 From: Hapaxia Date: Wed, 21 Jun 2023 21:23:27 +0100 Subject: [PATCH 09/64] Polygon - update to v1.1.1 just a patch update. mostly code re-organisation, removing redundant repeats. minor corrections made too. should function the same. --- src/SelbaWard/Polygon.cpp | 274 +++++++++----------------------------- src/SelbaWard/Polygon.hpp | 2 +- 2 files changed, 65 insertions(+), 211 deletions(-) diff --git a/src/SelbaWard/Polygon.cpp b/src/SelbaWard/Polygon.cpp index 1b597e3..a6927f6 100644 --- a/src/SelbaWard/Polygon.cpp +++ b/src/SelbaWard/Polygon.cpp @@ -33,6 +33,7 @@ #include "Polygon.hpp" #include +#include namespace { @@ -234,7 +235,61 @@ void Polygon::priv_triangulateBasicEarClip() std::vector ear; reflex.reserve(m_vertices.size() - 3u); // impossible for vertices to be reflex without enough convex (need at least 3 convex to make a polygon) convex.reserve(m_vertices.size()); - ear.reserve(m_vertices.size()); + ear.reserve(m_vertices.size() - 2u); // with one ear per vertex, the final ear requires 3 vertices + + std::function isEar = + [&](const std::size_t i, const std::size_t p, const std::size_t n, const std::size_t current) + { + bool aPointIsInside{ false }; + for (std::size_t other{ 0u }; other < indices.size(); ++other) + { + if ((other == i) || (other == p) || (other == n) || (other == current)) + continue; + + if (pointIsInsideTriangle({ m_vertices[indices[p]].position, m_vertices[indices[i]].position, m_vertices[indices[n]].position }, m_vertices[indices[other]].position)) + { + aPointIsInside = true; + break; + } + } + return !aPointIsInside; + }; + + std::function isEarAnalysis = + [&](const std::size_t i, const std::size_t p, const std::size_t n) + { + return isEar(i, p, n, i); + }; + + std::function retest = + [&](const std::size_t i, const std::size_t p, const std::size_t n, const std::size_t current) + { + std::vector::iterator reflexIt{ std::find(reflex.begin(), reflex.end(), indices[i]) }; + if (reflexIt != reflex.end()) + { + // if reflex, re-test + const sf::Vector2f pLine{ m_vertices[indices[i]].position - m_vertices[indices[p]].position }; + const sf::Vector2f nLine{ m_vertices[indices[n]].position - m_vertices[indices[i]].position }; + + if (isSecondVectorAntiClockwiseOfFirstVector(pLine, nLine)) + { + reflex.erase(reflexIt); + convex.push_back(indices[i]); + } + } + + std::vector::iterator convexIt{ std::find(convex.begin(), convex.end(), indices[i]) }; + if (convexIt != convex.end()) + { + // if convex, re-test for ear only (must still be convex) + const bool isNowEar{ isEar(i, p, n, current) }; + const std::vector::iterator it{ std::find(ear.begin(), ear.end(), indices[i]) }; + if (isNowEar && (it == ear.end())) + ear.push_back(indices[i]); + else if (!isNowEar && (it != ear.end())) + ear.erase(it); + } + }; // analyse points for (std::size_t i{ 0u }; i < indicesSize; ++i) @@ -245,28 +300,14 @@ void Polygon::priv_triangulateBasicEarClip() const sf::Vector2f prevLine{ m_vertices[indices[i]].position - m_vertices[indices[prev]].position }; const sf::Vector2f nextLine{ m_vertices[indices[next]].position - m_vertices[indices[i]].position }; - if (isSecondVectorAntiClockwiseOfFirstVector(prevLine, nextLine)) + if (!isSecondVectorAntiClockwiseOfFirstVector(prevLine, nextLine)) + reflex.push_back(indices[i]); + else { convex.push_back(i); - bool aPointIsInside{ false }; - for (std::size_t other{ 0u }; other < indicesSize; ++other) - { - if ((other == i) || (other == prev) || (other == next)) - continue; - - if (pointIsInsideTriangle({ m_vertices[indices[prev]].position, m_vertices[indices[i]].position, m_vertices[indices[next]].position }, m_vertices[indices[other]].position)) - { - aPointIsInside = true; - break; - } - } - if (!aPointIsInside) + if (isEarAnalysis(i, prev, next)) ear.push_back(indices[i]); } - else - { - reflex.push_back(indices[i]); - } } // process @@ -281,203 +322,16 @@ void Polygon::priv_triangulateBasicEarClip() TriangleIndices triangle{ indices[prev], indices[current], indices[next] }; m_triangles.push_back(triangle); + retest(prev, ((prev > 0u) ? (prev - 1u) : (indices.size() - 1u)), next, current); + retest(next, prev, ((next < (indices.size() - 1u)) ? (next + 1u) : 0u), current); - - std::vector::iterator earPrevIt{ std::find(ear.begin(), ear.end(), indices[prev]) }; - if (earPrevIt != ear.end()) - { - // if ear, re-test for ear only (might not still be one) - - std::size_t i{ prev }; - - const std::size_t p{ (i > 0u) ? (i - 1u) : (indices.size() - 1u) }; - const std::size_t n{ next }; - - bool aPointIsInside{ false }; - for (std::size_t other{ 0u }; other < indices.size(); ++other) - { - if ((other == i) || (other == p) || (other == n) || (other == current)) - continue; - - if (pointIsInsideTriangle({ m_vertices[indices[p]].position, m_vertices[indices[i]].position, m_vertices[indices[n]].position }, m_vertices[indices[other]].position)) - { - aPointIsInside = true; - break; - } - } - if (aPointIsInside) - ear.erase(earPrevIt); - } - - - - std::vector::iterator earNextIt{ std::find(ear.begin(), ear.end(), indices[next]) }; - if (earNextIt != ear.end()) - { - // if ear, re-test for ear only (might not still be one) - - std::size_t i{ next }; - - const std::size_t p{ prev }; - const std::size_t n{ (i < (indices.size() - 1u)) ? (i + 1u) : 0u }; - - bool aPointIsInside{ false }; - for (std::size_t other{ 0u }; other < indices.size(); ++other) - { - if ((other == i) || (other == p) || (other == n) || (other == current)) - continue; - - if (pointIsInsideTriangle({ m_vertices[indices[p]].position, m_vertices[indices[i]].position, m_vertices[indices[n]].position }, m_vertices[indices[other]].position)) - { - aPointIsInside = true; - break; - } - } - if (aPointIsInside) - ear.erase(earNextIt); - } - - - - std::vector::iterator convexPrevIt{ std::find(convex.begin(), convex.end(), indices[prev]) }; - if (convexPrevIt != convex.end()) - { - // if convex, re-test for ear only (must still be convex) - - if (std::find(ear.begin(), ear.end(), indices[prev]) == ear.end()) - { - std::size_t i{ prev }; - - const std::size_t p{ (i > 0u) ? (i - 1u) : (indices.size() - 1u) }; - const std::size_t n{ next }; - - bool aPointIsInside{ false }; - for (std::size_t other{ 0u }; other < indices.size(); ++other) - { - if ((other == i) || (other == p) || (other == n) || (other == current)) - continue; - - if (pointIsInsideTriangle({ m_vertices[indices[p]].position, m_vertices[indices[i]].position, m_vertices[indices[n]].position }, m_vertices[indices[other]].position)) - { - aPointIsInside = true; - break; - } - } - if (!aPointIsInside) - ear.push_back(indices[i]); - } - } - - - - std::vector::iterator convexNextIt{ std::find(convex.begin(), convex.end(), indices[next]) }; - if (convexNextIt != convex.end()) - { - // if convex, re-test for ear only (must still be convex) - - if (std::find(ear.begin(), ear.end(), indices[next]) == ear.end()) - { - std::size_t i{ next }; - - const std::size_t p{ prev }; - const std::size_t n{ (i < (indices.size() - 1u)) ? (i + 1u) : 0u }; - - bool aPointIsInside{ false }; - for (std::size_t other{ 0u }; other < indices.size(); ++other) - { - if ((other == i) || (other == p) || (other == n) || (other == current)) - continue; - - if (pointIsInsideTriangle({ m_vertices[indices[p]].position, m_vertices[indices[i]].position, m_vertices[indices[n]].position }, m_vertices[indices[other]].position)) - { - aPointIsInside = true; - break; - } - } - if (!aPointIsInside) - ear.push_back(indices[i]); - } - } - - - - std::vector::iterator reflexPrevIt{ std::find(reflex.begin(), reflex.end(), indices[prev]) }; - if (reflexPrevIt != reflex.end()) - { - // if reflex, re-test - std::size_t i{ prev }; - - const std::size_t p{ (i > 0u) ? (i - 1u) : (indices.size() - 1u) }; - const std::size_t n{ next }; - - const sf::Vector2f pLine{ m_vertices[indices[i]].position - m_vertices[indices[p]].position }; - const sf::Vector2f nLine{ m_vertices[indices[n]].position - m_vertices[indices[i]].position }; - - if (isSecondVectorAntiClockwiseOfFirstVector(pLine, nLine)) - { - reflex.erase(reflexPrevIt); - - convex.push_back(indices[i]); - bool aPointIsInside{ false }; - for (std::size_t other{ 0u }; other < indices.size(); ++other) - { - if ((other == i) || (other == p) || (other == n) || (other == current)) - continue; - - if (pointIsInsideTriangle({ m_vertices[indices[p]].position, m_vertices[indices[i]].position, m_vertices[indices[n]].position }, m_vertices[indices[other]].position)) - { - aPointIsInside = true; - break; - } - } - if (!aPointIsInside) - ear.push_back(indices[i]); - } - } - - std::vector::iterator reflexNextIt{ std::find(reflex.begin(), reflex.end(), indices[next]) }; - if (reflexNextIt != reflex.end()) - { - // if reflex, re-test - std::size_t i{ next }; - - const std::size_t p{ prev }; - const std::size_t n{ (i < (indices.size() - 1u)) ? (i + 1u) : 0u }; - - const sf::Vector2f pLine{ m_vertices[indices[i]].position - m_vertices[indices[p]].position }; - const sf::Vector2f nLine{ m_vertices[indices[n]].position - m_vertices[indices[i]].position }; - - if (isSecondVectorAntiClockwiseOfFirstVector(pLine, nLine)) - { - reflex.erase(reflexNextIt); - - convex.push_back(indices[i]); - bool aPointIsInside{ false }; - for (std::size_t other{ 0u }; other < indices.size(); ++other) - { - if ((other == i) || (other == p) || (other == n) || (other == current)) - continue; - - if (pointIsInsideTriangle({ m_vertices[indices[p]].position, m_vertices[indices[i]].position, m_vertices[indices[n]].position }, m_vertices[indices[other]].position)) - { - aPointIsInside = true; - break; - } - } - if (!aPointIsInside) - ear.push_back(indices[i]); - } - } - + // remove current (the one we clipped) convex.erase(std::find(convex.begin(), convex.end(), indices[current])); - if (std::find(ear.begin(), ear.end(), indices[current]) != ear.end()) - ear.erase(std::find(ear.begin(), ear.end(), indices[current])); + ear.erase(std::find(ear.begin(), ear.end(), indices[current])); indices.erase(currentIt); - ///* if (m_triangles.size() == stopAfterThisNumberOfTrianglesHaveBeenCreated) break; - //*/ } if (m_triangles.size() < stopAfterThisNumberOfTrianglesHaveBeenCreated) diff --git a/src/SelbaWard/Polygon.hpp b/src/SelbaWard/Polygon.hpp index 7a4ca07..1ec47db 100644 --- a/src/SelbaWard/Polygon.hpp +++ b/src/SelbaWard/Polygon.hpp @@ -39,7 +39,7 @@ namespace selbaward { -// SW Polygon v1.1 +// SW Polygon v1.1.1 class Polygon : public sf::Drawable, public sf::Transformable { public: From 6e61b953377ae8a816675c5d645311f807eb6ab3 Mon Sep 17 00:00:00 2001 From: Hapaxia Date: Mon, 26 Jun 2023 03:36:13 +0100 Subject: [PATCH 10/64] Polygon-update to v1.2 in addition to BasicEarClip, which triangulates simple polygons, EarClip is now provided, which can triangulate simple polygons that contain any number of simple polygon holes. some restrictions: polygons vertices must be provided in an anti-clockwise order. holes' vertices must be provided in a clockwise order. all vertices (polygon and holes) must be provided together. holes' vertices must be provided after all of the polygon vertices. an index (per hole) must be provided to mark the start of that hole. --- src/SelbaWard/Polygon.cpp | 346 ++++++++++++++++++++++++++++++++++++++ src/SelbaWard/Polygon.hpp | 13 +- 2 files changed, 358 insertions(+), 1 deletion(-) diff --git a/src/SelbaWard/Polygon.cpp b/src/SelbaWard/Polygon.cpp index a6927f6..9b0cafd 100644 --- a/src/SelbaWard/Polygon.cpp +++ b/src/SelbaWard/Polygon.cpp @@ -34,6 +34,7 @@ #include #include +#include namespace { @@ -54,6 +55,16 @@ inline bool pointIsInsideTriangle(const std::vector& points, sf::V return a >= 0.f && a <= 1.f && b >= 0.f && b <= 1.f && c >= 0.f && c <= 1.f; } +inline float crossProduct(const sf::Vector2f& a, const sf::Vector2f& b) +{ + return (a.x * b.y) - (a.y * b.x); +} + +inline float lengthSquared(const sf::Vector2f& a) +{ + return (a.x * a.x) + (a.y * a.y); +} + } // namespace namespace selbaward @@ -62,6 +73,7 @@ namespace selbaward Polygon::Polygon() : m_outputVertices() , m_vertices() + , m_holeStartIndices() , m_color{ sf::Color::White } , m_triangulationMethod{ TriangulationMethod::BasicEarClip } , m_meshRefinementMethod{ MeshRefinementMethod::None } @@ -140,6 +152,21 @@ sf::Vector2f Polygon::getVertexPosition(const std::size_t index) const return m_vertices[index].position; } +void Polygon::addHoleStartIndex(const std::size_t index) +{ + m_holeStartIndices.push_back(index); +} + +void Polygon::clearHoleStartIndices() +{ + m_holeStartIndices.clear(); +} + +void Polygon::setHoleStartIndices(const std::vector& indices) +{ + m_holeStartIndices = indices; +} + void Polygon::reverseVertices() { std::reverse(m_vertices.begin(), m_vertices.end()); @@ -208,6 +235,325 @@ void Polygon::priv_triangulate() case TriangulationMethod::BasicEarClip: priv_triangulateBasicEarClip(); break; + case TriangulationMethod::EarClip: + priv_triangulateEarClip(); + break; + } +} + +void Polygon::priv_triangulateEarClip() +{ + constexpr std::size_t stopAfterThisNumberOfTrianglesHaveBeenCreated{ 100u }; + + // ear clipping method + // polygon points must be anti-clockwise + // hole points must be clockwise + // number of triangles will always be (number of points - 2) + + // vertexNumbers is the order of the vertices (can re-use vertices) + // this is a single stream of vertices creating the polygon (after the holes are added, this becomes a single polygon) + std::vector vertexNumbers(m_vertices.size()); + std::size_t vertexNumbersSize{ vertexNumbers.size() }; + for (std::size_t i{ 0u }; i < vertexNumbersSize; ++i) + vertexNumbers[i] = i; + + if (!m_holeStartIndices.empty()) + { + std::sort(m_holeStartIndices.begin(), m_holeStartIndices.end()); + vertexNumbersSize = m_holeStartIndices[0u]; + } + const std::vector holeVertexNumbers(vertexNumbers.begin() + vertexNumbersSize, vertexNumbers.end()); + const std::size_t holeVertexNumbersSize{ holeVertexNumbers.size() }; + vertexNumbers.erase(vertexNumbers.begin() + vertexNumbersSize, vertexNumbers.end()); + // now, vertexNumbers is polygon vertex numbers (including any hole already cut in - later on) and holeVertexNumbers is the hole vertex numbers (all of them - no need to remove or rearrange this) + + // indices is the list of indices of the vertex numbers in order + // each index is treated as a separate vertex, even if it's technically the same vertex as another (same vertex numbers) + std::vector indices(vertexNumbersSize); + std::size_t indicesSize{ indices.size() }; + for (std::size_t i{ 0u }; i < indicesSize; ++i) + indices[i] = i; + + // points lists (to keep track of their state) + // note that these store indices - their numbers refer to which index to access: e.g. m_vertices[vertexNumbers[indices[reflex]]] + std::vector reflex; + std::vector convex; + std::vector ear; + + std::function isEar = + [&](const std::size_t i, const std::size_t p, const std::size_t n, const std::size_t current) + { + bool aPointIsInside{ false }; + for (std::size_t other{ 0u }; other < vertexNumbers.size(); ++other) + { + if ((vertexNumbers[other] == vertexNumbers[i]) || (vertexNumbers[other] == vertexNumbers[p]) || (vertexNumbers[other] == vertexNumbers[n]) || (vertexNumbers[other] == vertexNumbers[current])) + continue; + + if (pointIsInsideTriangle({ m_vertices[vertexNumbers[p]].position, m_vertices[vertexNumbers[i]].position, m_vertices[vertexNumbers[n]].position }, m_vertices[vertexNumbers[other]].position)) + { + aPointIsInside = true; + break; + } + } + return !aPointIsInside; + }; + + std::function isEarAnalysis = + [&](const std::size_t i, const std::size_t p, const std::size_t n) + { + return isEar(i, p, n, i); + }; + + std::function retest = + [&](const std::size_t i, const std::size_t p, const std::size_t n, const std::size_t current) + { + std::vector::iterator reflexIt{ std::find(reflex.begin(), reflex.end(), indices[i]) }; + if (reflexIt != reflex.end()) + { + // if reflex, re-test + const sf::Vector2f pLine{ m_vertices[vertexNumbers[indices[i]]].position - m_vertices[vertexNumbers[indices[p]]].position }; + const sf::Vector2f nLine{ m_vertices[vertexNumbers[indices[n]]].position - m_vertices[vertexNumbers[indices[i]]].position }; + + if (isSecondVectorAntiClockwiseOfFirstVector(pLine, nLine)) + { + reflex.erase(reflexIt); + convex.push_back(indices[i]); + } + } + + std::vector::iterator convexIt{ std::find(convex.begin(), convex.end(), indices[i]) }; + if (convexIt != convex.end()) + { + // if convex, re-test for ear only (must still be convex) + const bool isNowEar{ isEar(indices[i], indices[p], indices[n], indices[current]) }; + const std::vector::iterator it{ std::find(ear.begin(), ear.end(), indices[i]) }; + if (isNowEar && (it == ear.end())) + ear.push_back(indices[i]); + else if (!isNowEar && (it != ear.end())) + ear.erase(it); + } + }; + + std::function analysePoints = + [&]() + { + for (std::size_t i{ 0u }; i < indicesSize; ++i) + { + const std::size_t prev{ (i > 0u) ? (i - 1u) : (indicesSize - 1u) }; + const std::size_t next{ (i < (indicesSize - 1u)) ? (i + 1u) : 0u }; + + const sf::Vector2f prevLine{ m_vertices[vertexNumbers[indices[i]]].position - m_vertices[vertexNumbers[indices[prev]]].position }; + const sf::Vector2f nextLine{ m_vertices[vertexNumbers[indices[next]]].position - m_vertices[vertexNumbers[indices[i]]].position }; + + if (!isSecondVectorAntiClockwiseOfFirstVector(prevLine, nextLine)) + reflex.push_back(indices[i]); + else + { + convex.push_back(indices[i]); + if (isEarAnalysis(indices[i], indices[prev], indices[next])) + ear.push_back(indices[i]); + } + } + }; + + reflex.reserve(m_vertices.size() - 3u); // impossible for vertices to be reflex without enough convex (need at least 3 convex to make a polygon) + convex.reserve(m_vertices.size()); // any number (up to all) of the vertices may be convex although at least 3 are required + ear.reserve(m_vertices.size() - 2u); // with one ear per vertex, the final ear requires 3 vertices + + analysePoints(); + + if (!m_holeStartIndices.empty()) + { + struct Hole + { + std::size_t start; + std::size_t length; + float maxX; + }; + std::vector holeInfo(m_holeStartIndices.size()); + + for (std::size_t h{ 0u }; h < holeInfo.size(); ++h) + { + holeInfo[h].start = m_holeStartIndices[h] - vertexNumbersSize; + if (h < (holeInfo.size() - 1u)) + holeInfo[h].length = m_holeStartIndices[h + 1u] - m_holeStartIndices[h]; + else + holeInfo[h].length = holeVertexNumbersSize - (m_holeStartIndices[h] - vertexNumbersSize); + holeInfo[h].maxX = m_vertices[holeVertexNumbers[holeInfo[h].start]].position.x; + for (std::size_t v{ 1u }; v < holeInfo[h].length; ++v) + holeInfo[h].maxX = std::max(holeInfo[h].maxX, m_vertices[holeVertexNumbers[holeInfo[h].start + v]].position.x); + } + // sort order from the furthest right so that first hole is furthest right + std::sort(holeInfo.begin(), holeInfo.end(), [](const Hole& left, const Hole& right) { return left.maxX > right.maxX; }); + + + float vertexMinX{ m_vertices[0u].position.x }; + float vertexMaxX{ m_vertices[0u].position.x }; + for (std::size_t v{ 1u }; v < m_vertices.size(); ++v) + { + vertexMinX = std::min(vertexMinX, m_vertices[v].position.x); + vertexMaxX = std::max(vertexMaxX, m_vertices[v].position.x); + } + const float maxWidth{ vertexMaxX - vertexMinX }; + + const sf::Vector2f rayVector{ 1.f, 0.f }; + + for (std::size_t h{ 0u }; h < holeInfo.size(); ++h) + { + const std::size_t holeStart{ holeInfo[h].start }; + const std::size_t holeLength{ holeInfo[h].length }; + + // choose where the cut appears + std::size_t cutPolygonVertexNumber; + std::size_t cutHoleVertexNumber; + std::size_t cutHoleHoleIndex; + + + + // hole vertex (the easy bit) + float furthestRight{ m_vertices[holeVertexNumbers[holeStart]].position.x }; + for (std::size_t v{ 1u }; v < holeLength; ++v) + { + const float currentRight{ m_vertices[holeVertexNumbers[holeStart + v]].position.x }; + if (currentRight > furthestRight) + { + furthestRight = currentRight; + cutHoleHoleIndex = holeStart + v; + } + } + cutHoleVertexNumber = holeVertexNumbers[cutHoleHoleIndex]; + + + + // polygon vertex (the hard bit) + const sf::Vector2f rayOrigin{ m_vertices[cutHoleVertexNumber].position }; + sf::Vector2f pointOfIntersection{ 0.f, 0.f }; + + // find closest edge (to the right) + std::size_t candidateIndex{ 0u }; + float distance{ maxWidth }; + for (std::size_t v{ 0u }; v < vertexNumbersSize; ++v) + { + const std::size_t edgeStartIndex{ v }; + const std::size_t edgeEndIndex{ (v < (vertexNumbersSize - 1u)) ? v + 1u : 0u }; + + const sf::Vector2f edgeStart{ m_vertices[vertexNumbers[edgeStartIndex]].position }; + const sf::Vector2f edgeEnd{ m_vertices[vertexNumbers[edgeEndIndex]].position }; + const sf::Vector2f edgeVector{ edgeEnd - edgeStart }; + + if (((edgeStart.x < rayOrigin.x) && (edgeEnd.x < rayOrigin.x)) || (edgeStart.y < rayOrigin.y) || (edgeEnd.y > rayOrigin.y)) + continue; + + // calculate distance (of intersection of edge) + const float d{ crossProduct((edgeStart - rayOrigin), edgeVector) / crossProduct(rayVector, edgeVector) }; + + if (d < distance) + { + distance = d; + if (edgeStart.x > edgeEnd.x) + candidateIndex = edgeStartIndex; + else + candidateIndex = edgeEndIndex; + pointOfIntersection = { rayOrigin.x + d, rayOrigin.y }; + } + } + + const std::size_t candidateVertexNumber{ vertexNumbers[candidateIndex] }; + std::vector insideTriangle; + for (auto& r : reflex) + { + if ((candidateIndex == r) || (r >= vertexNumbersSize)) + continue; + + if (pointIsInsideTriangle({ m_vertices[candidateVertexNumber].position, rayOrigin, pointOfIntersection }, m_vertices[vertexNumbers[r]].position)) + insideTriangle.push_back(r); + } + + if (insideTriangle.empty()) + cutPolygonVertexNumber = vertexNumbers[candidateIndex]; + else + { + // choose the closest point to the ray origin within the triangle formed by the ray to intersection and the candidate vertex + float distanceSquared{ maxWidth * maxWidth }; + for (auto& inside : insideTriangle) + { + const float thisLengthSquared{ lengthSquared(m_vertices[vertexNumbers[inside]].position - rayOrigin) }; + if (thisLengthSquared < distanceSquared) + { + distanceSquared = thisLengthSquared; + cutPolygonVertexNumber = vertexNumbers[inside]; + } + } + } + + + + // automatically insert vertices for the cut + const std::size_t holeIndexOffsetCut{ cutHoleHoleIndex - holeStart }; + // prepare vertices to insert around the cut + std::vector holeInsertVertices(holeLength + 2u); + holeInsertVertices[0u] = cutPolygonVertexNumber; + for (std::size_t i{ 0u }; i <= holeLength; ++i) + holeInsertVertices[i + 1u] = holeVertexNumbers[holeStart + ((holeIndexOffsetCut + i) % holeLength)]; + // then add them around the cut + vertexNumbers.insert(std::find(vertexNumbers.begin(), vertexNumbers.end(), cutPolygonVertexNumber), holeInsertVertices.begin(), holeInsertVertices.end()); + + // indices for each of the vertex numbers (allowing re-using of vertices - needed for cutting polygon) + vertexNumbersSize = vertexNumbers.size(); + indices.resize(vertexNumbersSize); + indicesSize = indices.size(); + for (std::size_t i{ 0u }; i < indicesSize; ++i) + indices[i] = i; + + + + //clear lists to allow re-analysis of entire new arrangement + reflex.clear(); + convex.clear(); + ear.clear(); + + // re-analyse points + analysePoints(); + } + } + + + + // avoid movement in memory when resizing + m_triangles.clear(); + m_triangles.reserve(m_vertices.size() - 2u); + + + + // process + while (indices.size() > 3u) + { + std::size_t currentPoint{ ear.front() }; + std::vector::iterator currentIt{ std::find(indices.begin(), indices.end(), currentPoint) }; + std::size_t current{ static_cast(std::distance(indices.begin(), currentIt)) }; + std::size_t prev{ (current > 0u) ? (current - 1u) : (indices.size() - 1u) }; + std::size_t next{ (current < (indices.size() - 1u)) ? (current + 1u) : 0u }; + + TriangleIndices triangle{ vertexNumbers[indices[prev]], vertexNumbers[indices[current]], vertexNumbers[indices[next]] }; + m_triangles.push_back(triangle); + + retest(prev, ((prev > 0u) ? (prev - 1u) : (indices.size() - 1u)), next, current); + retest(next, prev, ((next < (indices.size() - 1u)) ? (next + 1u) : 0u), current); + + // remove current (the one we clipped) + convex.erase(std::find(convex.begin(), convex.end(), indices[current])); + ear.erase(std::find(ear.begin(), ear.end(), indices[current])); + indices.erase(currentIt); + + if (m_triangles.size() == stopAfterThisNumberOfTrianglesHaveBeenCreated) + break; + } + + // 3 vertices remaining; add final triangle + if (m_triangles.size() < stopAfterThisNumberOfTrianglesHaveBeenCreated) + { + TriangleIndices triangle{ vertexNumbers[indices[0u]], vertexNumbers[indices[1u]], vertexNumbers[indices[2u]] }; + m_triangles.push_back(triangle); } } diff --git a/src/SelbaWard/Polygon.hpp b/src/SelbaWard/Polygon.hpp index 1ec47db..5dddb8b 100644 --- a/src/SelbaWard/Polygon.hpp +++ b/src/SelbaWard/Polygon.hpp @@ -39,13 +39,14 @@ namespace selbaward { -// SW Polygon v1.1.1 +// SW Polygon v1.2 class Polygon : public sf::Drawable, public sf::Transformable { public: enum class TriangulationMethod { BasicEarClip, + EarClip, }; enum class MeshRefinementMethod { @@ -76,6 +77,14 @@ class Polygon : public sf::Drawable, public sf::Transformable void importVertexPositions(const std::vector& position); std::vector exportTriangulatedPositions() const; + // holes must not overlap and must be specified in opposite direction to outer polygon + void addHoleStartIndex(std::size_t index); + void clearHoleStartIndices(); + void setHoleStartIndices(const std::vector& indices); + + + + @@ -85,6 +94,7 @@ class Polygon : public sf::Drawable, public sf::Transformable std::vector m_vertices; std::vector m_triangles; std::vector m_outputVertices; + std::vector m_holeStartIndices; sf::Color m_color; TriangulationMethod m_triangulationMethod; @@ -96,6 +106,7 @@ class Polygon : public sf::Drawable, public sf::Transformable void priv_update(); void priv_updateOutputVertices(); void priv_triangulate(); + void priv_triangulateEarClip(); void priv_triangulateBasicEarClip(); bool priv_isValidVertexIndex(std::size_t vertexIndex) const; bool priv_testVertexIndex(std::size_t vertexIndex, const std::string& exceptionMessage) const; From 5d30ac60183477aa1ac0792068ede609bdfa809d Mon Sep 17 00:00:00 2001 From: Hapaxia Date: Tue, 27 Jun 2023 17:34:13 +0100 Subject: [PATCH 11/64] Polygon-update to v1.2.1 patch update. fixes some miscalculations of multiple holes under certain conditions that could cause attempting to access elements of an empty vector. --- src/SelbaWard/Polygon.cpp | 19 +++++++++++++++++-- src/SelbaWard/Polygon.hpp | 2 +- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/src/SelbaWard/Polygon.cpp b/src/SelbaWard/Polygon.cpp index 9b0cafd..d5866a5 100644 --- a/src/SelbaWard/Polygon.cpp +++ b/src/SelbaWard/Polygon.cpp @@ -432,6 +432,7 @@ void Polygon::priv_triangulateEarClip() // find closest edge (to the right) std::size_t candidateIndex{ 0u }; float distance{ maxWidth }; + bool isEndIndex{ false }; for (std::size_t v{ 0u }; v < vertexNumbersSize; ++v) { const std::size_t edgeStartIndex{ v }; @@ -453,7 +454,10 @@ void Polygon::priv_triangulateEarClip() if (edgeStart.x > edgeEnd.x) candidateIndex = edgeStartIndex; else + { candidateIndex = edgeEndIndex; + isEndIndex = true; + } pointOfIntersection = { rayOrigin.x + d, rayOrigin.y }; } } @@ -462,7 +466,7 @@ void Polygon::priv_triangulateEarClip() std::vector insideTriangle; for (auto& r : reflex) { - if ((candidateIndex == r) || (r >= vertexNumbersSize)) + if ((candidateIndex == r) || (vertexNumbers[r] >= vertexNumbersSize)) continue; if (pointIsInsideTriangle({ m_vertices[candidateVertexNumber].position, rayOrigin, pointOfIntersection }, m_vertices[vertexNumbers[r]].position)) @@ -482,6 +486,7 @@ void Polygon::priv_triangulateEarClip() { distanceSquared = thisLengthSquared; cutPolygonVertexNumber = vertexNumbers[inside]; + isEndIndex = false; } } } @@ -496,7 +501,17 @@ void Polygon::priv_triangulateEarClip() for (std::size_t i{ 0u }; i <= holeLength; ++i) holeInsertVertices[i + 1u] = holeVertexNumbers[holeStart + ((holeIndexOffsetCut + i) % holeLength)]; // then add them around the cut - vertexNumbers.insert(std::find(vertexNumbers.begin(), vertexNumbers.end(), cutPolygonVertexNumber), holeInsertVertices.begin(), holeInsertVertices.end()); + if (isEndIndex) + { + vertexNumbers.insert(std::find(vertexNumbers.begin(), vertexNumbers.end(), cutPolygonVertexNumber), holeInsertVertices.begin(), holeInsertVertices.end()); + } + else + { + std::vector::reverse_iterator vnRIt{ std::find(vertexNumbers.rbegin(), vertexNumbers.rend(), cutPolygonVertexNumber) }; + std::vector::iterator vnIt{ (vnRIt + 1u).base() }; + //vertexNumbers.insert(std::find(vertexNumbers.rbegin(), vertexNumbers.rend(), cutPolygonVertexNumber).base() + 1u, holeInsertVertices.begin(), holeInsertVertices.end()); + vertexNumbers.insert(vnIt, holeInsertVertices.begin(), holeInsertVertices.end()); + } // indices for each of the vertex numbers (allowing re-using of vertices - needed for cutting polygon) vertexNumbersSize = vertexNumbers.size(); diff --git a/src/SelbaWard/Polygon.hpp b/src/SelbaWard/Polygon.hpp index 5dddb8b..1f6e295 100644 --- a/src/SelbaWard/Polygon.hpp +++ b/src/SelbaWard/Polygon.hpp @@ -39,7 +39,7 @@ namespace selbaward { -// SW Polygon v1.2 +// SW Polygon v1.2.1 class Polygon : public sf::Drawable, public sf::Transformable { public: From adb1f718d377f4a4fc7e0a5f7408e5f64b0af90d Mon Sep 17 00:00:00 2001 From: Hapaxia Date: Tue, 27 Jun 2023 17:44:29 +0100 Subject: [PATCH 12/64] Polygon-update to v1.2.2 quick patch update that fixes an un-initialised variable that may get used without being assigned a value. --- src/SelbaWard/Polygon.cpp | 2 +- src/SelbaWard/Polygon.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/SelbaWard/Polygon.cpp b/src/SelbaWard/Polygon.cpp index d5866a5..fa443d6 100644 --- a/src/SelbaWard/Polygon.cpp +++ b/src/SelbaWard/Polygon.cpp @@ -406,7 +406,7 @@ void Polygon::priv_triangulateEarClip() // choose where the cut appears std::size_t cutPolygonVertexNumber; std::size_t cutHoleVertexNumber; - std::size_t cutHoleHoleIndex; + std::size_t cutHoleHoleIndex{ holeStart }; diff --git a/src/SelbaWard/Polygon.hpp b/src/SelbaWard/Polygon.hpp index 1f6e295..52676fb 100644 --- a/src/SelbaWard/Polygon.hpp +++ b/src/SelbaWard/Polygon.hpp @@ -39,7 +39,7 @@ namespace selbaward { -// SW Polygon v1.2.1 +// SW Polygon v1.2.2 class Polygon : public sf::Drawable, public sf::Transformable { public: From 4fc83eb23f63fee083880bae1b4ccb4bd7fc6caa Mon Sep 17 00:00:00 2001 From: Hapaxia Date: Tue, 27 Jun 2023 18:09:45 +0100 Subject: [PATCH 13/64] Polygon-update to v1.2.3 now throws a Selba Ward exception showing an error code instead of attempting to access an empty vector (during the update method). this allows both: reporting an error for investigation and catching the error suring runtime to avoid invalid use. to catch this exception, simply put the update() method in a try block. remember to reset any changes before attempting to update again (e.g. if you've changed a vertex position before the update that failed, change the vertex position back to what it was before) --- src/SelbaWard/Polygon.cpp | 3 +++ src/SelbaWard/Polygon.hpp | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/SelbaWard/Polygon.cpp b/src/SelbaWard/Polygon.cpp index fa443d6..9532734 100644 --- a/src/SelbaWard/Polygon.cpp +++ b/src/SelbaWard/Polygon.cpp @@ -543,6 +543,9 @@ void Polygon::priv_triangulateEarClip() // process while (indices.size() > 3u) { + if (ear.empty()) + throw Exception("Polygon - ERROR: 0001"); + std::size_t currentPoint{ ear.front() }; std::vector::iterator currentIt{ std::find(indices.begin(), indices.end(), currentPoint) }; std::size_t current{ static_cast(std::distance(indices.begin(), currentIt)) }; diff --git a/src/SelbaWard/Polygon.hpp b/src/SelbaWard/Polygon.hpp index 52676fb..09c391d 100644 --- a/src/SelbaWard/Polygon.hpp +++ b/src/SelbaWard/Polygon.hpp @@ -39,7 +39,7 @@ namespace selbaward { -// SW Polygon v1.2.2 +// SW Polygon v1.2.3 class Polygon : public sf::Drawable, public sf::Transformable { public: From 71a4b538a2c671090079417ad925de6976103557 Mon Sep 17 00:00:00 2001 From: Hapaxia Date: Sun, 4 Dec 2022 10:18:12 +0000 Subject: [PATCH 14/64] Polygon - initial commit (v1.0) From b368231ec5c63b75047f7eeb93a267de08e89f14 Mon Sep 17 00:00:00 2001 From: Hapaxia Date: Sun, 4 Dec 2022 10:34:02 +0000 Subject: [PATCH 15/64] Merge pull request #32 from Hapaxia/Polygon-v1_0 Polygon - initial commit (v1.0) From b547b1617207e7b49e89d58256bae4b3e93e7f44 Mon Sep 17 00:00:00 2001 From: Hapaxia Date: Wed, 28 Dec 2022 17:04:00 +0000 Subject: [PATCH 16/64] added Polygon to list of contents --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 7c34ade..8d9230c 100644 --- a/readme.md +++ b/readme.md @@ -6,7 +6,7 @@ A collection of SFML drawables by [Hapaxia](http://github.com/Hapaxia) -Contents: **Bitmap Text**, **Console Screen**, **Crosshair**, **Elastic Sprite**, **Gallery Sprite**, **Line**, **Nine Patch**, **Pie Chart**, **Pixel Display**, **Progress Bar**, **Ring**, **Spinning Card**, **Spline**, **Sprite 3D**, **Starfield**, **Tile Map** +Contents: **Bitmap Text**, **Console Screen**, **Crosshair**, **Elastic Sprite**, **Gallery Sprite**, **Line**, **Nine Patch**, **Pie Chart**, **Pixel Display**, **Polygon**, **Progress Bar**, **Ring**, **Spinning Card**, **Spline**, **Sprite 3D**, **Starfield**, **Tile Map** ## For information, view the [Wiki]. From d3b8c831575c9a9072646ddb6b4312b53e77f60a Mon Sep 17 00:00:00 2001 From: Hapaxia Date: Wed, 28 Dec 2022 17:12:29 +0000 Subject: [PATCH 17/64] update Polygon to v1.1 added ability to set/get mass of points/positions/vertices at once: importVertexPositions to bring in positions of all vertices of the polygon, and exportTriangulatedPositions to export a vector of positions in groups of three to represent each triangle that has been triangulated. --- src/SelbaWard/Polygon.cpp | 20 ++++++++++++++++++++ src/SelbaWard/Polygon.hpp | 5 ++++- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/SelbaWard/Polygon.cpp b/src/SelbaWard/Polygon.cpp index b56d788..5889fd6 100644 --- a/src/SelbaWard/Polygon.cpp +++ b/src/SelbaWard/Polygon.cpp @@ -144,6 +144,26 @@ void Polygon::reverseVertices() std::reverse(m_vertices.begin(), m_vertices.end()); } +void Polygon::importVertexPositions(const std::vector& positions) +{ + setNumberOfVertices(positions.size()); + for (std::size_t i{ 0u }; i < positions.size(); ++i) + m_vertices[i].position = positions[i]; +} + +std::vector Polygon::exportTriangulatedPositions() const +{ + std::vector positions(m_triangles.size() * 3u); + for (std::size_t i{ 0u }; i < m_triangles.size(); ++i) + { + positions[i * 3u + 0u] = m_vertices[m_triangles[i][0u]].position; + positions[i * 3u + 1u] = m_vertices[m_triangles[i][1u]].position; + positions[i * 3u + 2u] = m_vertices[m_triangles[i][2u]].position; + } + return positions; +} + + diff --git a/src/SelbaWard/Polygon.hpp b/src/SelbaWard/Polygon.hpp index 490011a..f0fb38b 100644 --- a/src/SelbaWard/Polygon.hpp +++ b/src/SelbaWard/Polygon.hpp @@ -39,7 +39,7 @@ namespace selbaward { -// SW Polygon v1.0 +// SW Polygon v1.1 class Polygon : public sf::Drawable, public sf::Transformable { public: @@ -73,6 +73,9 @@ class Polygon : public sf::Drawable, public sf::Transformable void reverseVertices(); + void importVertexPositions(const std::vector& position); + std::vector exportTriangulatedPositions() const; + From 55a6c8bf01b3f6324e94fbe60d4a884e826d36a4 Mon Sep 17 00:00:00 2001 From: Hapaxia Date: Thu, 12 Jan 2023 16:33:58 +0000 Subject: [PATCH 18/64] Update .gitignore From 89b450335f796ca88a5078790ccabe62d15d3b06 Mon Sep 17 00:00:00 2001 From: Hapaxia Date: Tue, 27 Jun 2023 19:07:05 +0100 Subject: [PATCH 19/64] update some from master --- src/SelbaWard/BitmapText.cpp | 35 +++---- src/SelbaWard/BitmapText.hpp | 2 +- src/SelbaWard/ConsoleScreen.cpp | 69 ++++++++------ src/SelbaWard/ConsoleScreen.hpp | 2 +- src/SelbaWard/ElasticSprite.cpp | 8 +- src/SelbaWard/ElasticSprite.hpp | 2 +- src/SelbaWard/Line.cpp | 41 ++++---- src/SelbaWard/Line.hpp | 2 +- src/SelbaWard/NinePatch.cpp | 163 +++++++++++++------------------- src/SelbaWard/NinePatch.hpp | 2 +- src/SelbaWard/PixelDisplay.cpp | 18 ++-- src/SelbaWard/PixelDisplay.hpp | 2 +- src/SelbaWard/Polygon.cpp | 17 ++++ src/SelbaWard/ProgressBar.cpp | 20 ++-- src/SelbaWard/ProgressBar.hpp | 2 +- src/SelbaWard/Spline.cpp | 85 ++++++++++++++++- src/SelbaWard/Spline.hpp | 8 +- src/SelbaWard/TileMap.hpp | 2 +- src/SelbaWard/TileMap.inl | 40 ++++---- 19 files changed, 309 insertions(+), 211 deletions(-) diff --git a/src/SelbaWard/BitmapText.cpp b/src/SelbaWard/BitmapText.cpp index 31f4782..b59688e 100644 --- a/src/SelbaWard/BitmapText.cpp +++ b/src/SelbaWard/BitmapText.cpp @@ -37,7 +37,7 @@ namespace selbaward BitmapText::BitmapText() : m_pBitmapFont{ nullptr } - , m_vertices(sf::Quads) + , m_vertices(sf::PrimitiveType::Triangles) , m_string() , m_color(sf::Color::White) , m_tracking{ 1 } @@ -136,7 +136,7 @@ void BitmapText::priv_updateVertices() m_bounds = { 0.f, 0.f, 0.f, 0.f }; } - m_vertices.resize(m_string.length() * 4); + m_vertices.resize(m_string.length() * 6u); sf::Vector2f penPosition{ 0.f, 0.f }; @@ -153,30 +153,33 @@ void BitmapText::priv_updateVertices() const sf::Vector2f glyphOffset{ 0.f - glyph.startX, (glyph.baseline < 0) ? (0.f - glyph.baseline - glyph.textureRect.height) : (0.f - glyph.baseline) }; const sf::Vector2f glyphPosition{ penPosition + glyphOffset }; - m_vertices[character * 4 + 0].position = glyphPosition; - m_vertices[character * 4 + 1].position = glyphPosition + sf::Vector2f(static_cast(glyph.textureRect.width), 0); - m_vertices[character * 4 + 2].position = glyphPosition + sf::Vector2f(static_cast(glyph.textureRect.width), static_cast(glyph.textureRect.height)); - m_vertices[character * 4 + 3].position = glyphPosition + sf::Vector2f(0, static_cast(glyph.textureRect.height)); + m_vertices[(character * 6u) + 0u].position = glyphPosition; + m_vertices[(character * 6u) + 1u].position = glyphPosition + sf::Vector2f(0, static_cast(glyph.textureRect.height)); + m_vertices[(character * 6u) + 2u].position = glyphPosition + sf::Vector2f(static_cast(glyph.textureRect.width), 0); + m_vertices[(character * 6u) + 3u].position = glyphPosition + sf::Vector2f(static_cast(glyph.textureRect.width), static_cast(glyph.textureRect.height)); - m_vertices[character * 4 + 0].texCoords = sf::Vector2f( + m_vertices[(character * 6u) + 0u].texCoords = sf::Vector2f( static_cast(glyph.textureRect.left), static_cast(glyph.textureRect.top)); - m_vertices[character * 4 + 1].texCoords = sf::Vector2f( + m_vertices[(character * 6u) + 1u].texCoords = sf::Vector2f( + static_cast(glyph.textureRect.left), + static_cast(glyph.textureRect.top + glyph.textureRect.height)); + m_vertices[(character * 6u) + 2u].texCoords = sf::Vector2f( static_cast(glyph.textureRect.left + glyph.textureRect.width), static_cast(glyph.textureRect.top)); - m_vertices[character * 4 + 2].texCoords = sf::Vector2f( + m_vertices[(character * 6u) + 3u].texCoords = sf::Vector2f( static_cast(glyph.textureRect.left + glyph.textureRect.width), static_cast(glyph.textureRect.top + glyph.textureRect.height)); - m_vertices[character * 4 + 3].texCoords = sf::Vector2f( - static_cast(glyph.textureRect.left), - static_cast(glyph.textureRect.top + glyph.textureRect.height)); + + m_vertices[(character * 6u) + 4u] = m_vertices[(character * 6u) + 2u]; + m_vertices[(character * 6u) + 5u] = m_vertices[(character * 6u) + 1u]; penPosition += sf::Vector2f((glyph.width > 0) ? (0.f + m_tracking + kerning + glyph.width) : (0.f + m_tracking + kerning + glyph.width + glyph.textureRect.width - glyph.startX), 0); - minX = std::min(minX, m_vertices[character * 4 + 0].position.x); - maxX = std::max(maxX, m_vertices[character * 4 + 2].position.x); - minY = std::min(minY, m_vertices[character * 4 + 0].position.y); - maxY = std::max(maxY, m_vertices[character * 4 + 2].position.y); + minX = std::min(minX, m_vertices[(character * 6u) + 0u].position.x); + maxX = std::max(maxX, m_vertices[(character * 6u) + 3u].position.x); + minY = std::min(minY, m_vertices[(character * 6u) + 0u].position.y); + maxY = std::max(maxY, m_vertices[(character * 6u) + 3u].position.y); } priv_updateColor(); diff --git a/src/SelbaWard/BitmapText.hpp b/src/SelbaWard/BitmapText.hpp index 8e4d0db..c1cb35a 100644 --- a/src/SelbaWard/BitmapText.hpp +++ b/src/SelbaWard/BitmapText.hpp @@ -40,7 +40,7 @@ namespace selbaward { -// SW Bitmap Text v1.1.2 +// SW Bitmap Text v1.1.3 class BitmapText : public sf::Drawable, public sf::Transformable { public: diff --git a/src/SelbaWard/ConsoleScreen.cpp b/src/SelbaWard/ConsoleScreen.cpp index 9aed486..2740684 100644 --- a/src/SelbaWard/ConsoleScreen.cpp +++ b/src/SelbaWard/ConsoleScreen.cpp @@ -43,7 +43,7 @@ namespace const std::string exceptionPrefix{ "Console Screen: " }; -const sf::PrimitiveType primitiveType{ sf::PrimitiveType::Quads }; +const sf::PrimitiveType primitiveType{ sf::PrimitiveType::Triangles }; const selbaward::ConsoleScreen::Color defaultColor(selbaward::ConsoleScreen::ColorCommand::Contrast); const selbaward::ConsoleScreen::Color defaultBackgroundColor(0); @@ -722,7 +722,7 @@ void ConsoleScreen::setMode(sf::Vector2u mode) m_mode = mode; m_cells.resize(m_mode.x * m_mode.y, defaultCell); - m_display.resize(m_cells.size() * 4); + m_display.resize(m_cells.size() * 6u); m_backgroundDisplay = m_display; clear(Color(0)); @@ -811,12 +811,12 @@ void ConsoleScreen::setUseCursorColor(const bool useCursorColor) void ConsoleScreen::update() { - if (m_display.size() != (m_mode.x * m_mode.y * 4)) + if (m_display.size() != (m_mode.x * m_mode.y * 6u)) return; if (m_backgroundDisplay.size() != m_display.size()) m_backgroundDisplay.resize(m_display.size()); - if (m_display.size() < 4) + if (m_display.size() < 6u) { if (m_do.throwExceptions) throw Exception(exceptionPrefix + "Cannot update display.\nNo cells available."); @@ -2412,15 +2412,15 @@ void ConsoleScreen::draw(sf::RenderTarget& target, sf::RenderStates states) cons if (m_do.showBackround && m_backgroundDisplay.size() > 0) { states.texture = nullptr; - target.draw(&m_backgroundDisplay.front(), m_backgroundDisplay.size(), primitiveType, states); + target.draw(m_backgroundDisplay.data(), m_backgroundDisplay.size(), primitiveType, states); } states.texture = m_texture; - if (m_underDisplay.size() > 0) - target.draw(&m_underDisplay.front(), m_underDisplay.size(), primitiveType, states); - if (m_display.size() > 0) - target.draw(&m_display.front(), m_display.size(), primitiveType, states); - if (m_overDisplay.size() > 0) - target.draw(&m_overDisplay.front(), m_overDisplay.size(), primitiveType, states); + if (m_underDisplay.size() > 0u) + target.draw(m_underDisplay.data(), m_underDisplay.size(), primitiveType, states); + if (m_display.size() > 0u) + target.draw(m_display.data(), m_display.size(), primitiveType, states); + if (m_overDisplay.size() > 0u) + target.draw(m_overDisplay.data(), m_overDisplay.size(), primitiveType, states); } void ConsoleScreen::priv_setVerticesFromCell(unsigned int index, int baseVertex, const bool overLayer) @@ -2515,29 +2515,34 @@ void ConsoleScreen::priv_setVerticesFromCell(unsigned int index, int baseVertex, const float textureBottom{ static_cast(m_textureOffset.y + (textureCell.y + (!useCursorValue && cell.stretch == StretchType::Top ? 0.5f : 1.f)) * m_tileSize.y) }; if (mainLayer) - baseVertex = index * 4; + baseVertex = index * 6u; // main display sf::Vertex* const pVertex1{ (mainLayer ? &m_display[baseVertex] : overLayer ? &m_overDisplay[baseVertex] : &m_underDisplay[baseVertex]) }; - sf::Vertex* const pVertex2{ pVertex1 + 1 }; - sf::Vertex* const pVertex3{ pVertex1 + 2 }; - sf::Vertex* const pVertex4{ pVertex1 + 3 }; + sf::Vertex* const pVertex2{ pVertex1 + 1u }; + sf::Vertex* const pVertex3{ pVertex1 + 2u }; + sf::Vertex* const pVertex4{ pVertex1 + 3u }; + sf::Vertex* const pVertex5{ pVertex1 + 4u }; + sf::Vertex* const pVertex6{ pVertex1 + 5u }; pVertex1->position = { left, top }; - pVertex2->position = { right, top }; - pVertex3->position = { right, bottom }; - pVertex4->position = { left, bottom }; + pVertex2->position = { left, bottom }; + pVertex3->position = { right, top }; + pVertex4->position = { right, bottom }; pVertex1->texCoords = { textureLeft, textureTop }; - pVertex2->texCoords = { textureRight, textureTop }; - pVertex3->texCoords = { textureRight, textureBottom }; - pVertex4->texCoords = { textureLeft, textureBottom }; + pVertex2->texCoords = { textureLeft, textureBottom }; + pVertex3->texCoords = { textureRight, textureTop }; + pVertex4->texCoords = { textureRight, textureBottom }; pVertex1->color = cellColor; pVertex2->color = cellColor; pVertex3->color = cellColor; pVertex4->color = cellColor; + *pVertex5 = *pVertex3; + *pVertex6 = *pVertex2; + // background display if (mainLayer) { @@ -2545,16 +2550,22 @@ void ConsoleScreen::priv_setVerticesFromCell(unsigned int index, int baseVertex, sf::Vertex* const pBackgroundVertex2{ pBackgroundVertex1 + 1 }; sf::Vertex* const pBackgroundVertex3{ pBackgroundVertex1 + 2 }; sf::Vertex* const pBackgroundVertex4{ pBackgroundVertex1 + 3 }; + sf::Vertex* const pBackgroundVertex5{ pBackgroundVertex1 + 4 }; + sf::Vertex* const pBackgroundVertex6{ pBackgroundVertex1 + 5 }; pBackgroundVertex1->position = pVertex1->position; pBackgroundVertex2->position = pVertex2->position; pBackgroundVertex3->position = pVertex3->position; pBackgroundVertex4->position = pVertex4->position; + pBackgroundVertex5->position = pVertex5->position; + pBackgroundVertex6->position = pVertex6->position; pBackgroundVertex1->color = backgroundColor; pBackgroundVertex2->color = backgroundColor; pBackgroundVertex3->color = backgroundColor; pBackgroundVertex4->color = backgroundColor; + pBackgroundVertex5->color = backgroundColor; + pBackgroundVertex6->color = backgroundColor; } } @@ -2563,14 +2574,14 @@ void ConsoleScreen::priv_updateCell(const unsigned int index) if (!priv_isCellIndexInRange(index)) return; - if (m_display.size() != (m_mode.x * m_mode.y * 4)) + if (m_display.size() != (m_mode.x * m_mode.y * 6u)) { if (m_do.throwExceptions) throw Exception(exceptionPrefix + "Bug: display does not match cells."); return; } - if (m_display.size() < 4) + if (m_display.size() < 6u) { if (m_do.throwExceptions) throw Exception(exceptionPrefix + "Bug: cannot update cell. No cells available."); @@ -2582,7 +2593,7 @@ void ConsoleScreen::priv_updateCell(const unsigned int index) void ConsoleScreen::priv_updateUnderCells() { - m_underDisplay.resize(m_underCells.size() * 4); + m_underDisplay.resize(m_underCells.size() * 6u); unsigned int outOfRangeCells{ 0u }; unsigned int baseVertex{ 0u }; for (unsigned int i{ 0u }; i < m_underCells.size(); ++i) @@ -2595,15 +2606,15 @@ void ConsoleScreen::priv_updateUnderCells() priv_setVerticesFromCell(i, baseVertex, false); - baseVertex += 4; + baseVertex += 6u; } - if (outOfRangeCells > 0) + if (outOfRangeCells > 0u) m_underDisplay.resize(baseVertex); } void ConsoleScreen::priv_updateOverCells() { - m_overDisplay.resize(m_overCells.size() * 4); + m_overDisplay.resize(m_overCells.size() * 6u); unsigned int outOfRangeCells{ 0u }; unsigned int baseVertex{ 0u }; for (unsigned int i{ 0u }; i < m_overCells.size(); ++i) @@ -2616,9 +2627,9 @@ void ConsoleScreen::priv_updateOverCells() priv_setVerticesFromCell(i, baseVertex, true); - baseVertex += 4; + baseVertex += 6u; } - if (outOfRangeCells > 0) + if (outOfRangeCells > 0u) m_overDisplay.resize(baseVertex); } diff --git a/src/SelbaWard/ConsoleScreen.hpp b/src/SelbaWard/ConsoleScreen.hpp index 58d88cd..6823683 100644 --- a/src/SelbaWard/ConsoleScreen.hpp +++ b/src/SelbaWard/ConsoleScreen.hpp @@ -45,7 +45,7 @@ namespace sf namespace selbaward { -// SW Console Screen v2.4.2 +// SW Console Screen v2.4.3 class ConsoleScreen : public sf::Drawable, public sf::Transformable { public: diff --git a/src/SelbaWard/ElasticSprite.cpp b/src/SelbaWard/ElasticSprite.cpp index b8ece1b..7dca1fb 100644 --- a/src/SelbaWard/ElasticSprite.cpp +++ b/src/SelbaWard/ElasticSprite.cpp @@ -43,7 +43,7 @@ namespace { -const sf::PrimitiveType primitiveType{ sf::PrimitiveType::Quads }; +const sf::PrimitiveType primitiveType{ sf::PrimitiveType::TriangleFan }; bool areShadersLoaded{ false }; sf::Shader bilinearShader; sf::Shader perspectiveShader; @@ -149,9 +149,9 @@ namespace selbaward ElasticSprite::ElasticSprite() : m_requiresVerticesUpdate{ false } - , m_vertices(4) - , m_weights(0) - , m_offsets(4) + , m_vertices(4u) + , m_weights(0u) + , m_offsets(4u) , m_pTexture{ nullptr } , m_baseTextureRect() , m_actualTextureRect() diff --git a/src/SelbaWard/ElasticSprite.hpp b/src/SelbaWard/ElasticSprite.hpp index 5c48d30..97c34ef 100644 --- a/src/SelbaWard/ElasticSprite.hpp +++ b/src/SelbaWard/ElasticSprite.hpp @@ -49,7 +49,7 @@ class Vector2; namespace selbaward { -// SW Elastic Sprite v1.3.0 +// SW Elastic Sprite v1.3.1 class ElasticSprite : public sf::Drawable, public sf::Transformable { public: diff --git a/src/SelbaWard/Line.cpp b/src/SelbaWard/Line.cpp index 8ffc4d3..0b1a934 100644 --- a/src/SelbaWard/Line.cpp +++ b/src/SelbaWard/Line.cpp @@ -49,8 +49,8 @@ namespace selbaward { Line::Line() - : m_vertices(sf::Lines, 2) - , m_quad(sf::Quads, 4) + : m_vertices(sf::PrimitiveType::Lines, 2u) + , m_quad(sf::PrimitiveType::TriangleStrip, 4u) , m_thickness{ 0.f } , m_texture{ nullptr } , m_textureRect() @@ -97,7 +97,7 @@ sf::FloatRect Line::getLocalBounds() const float minX, maxX, minY, maxY; minX = maxX = m_quad[0].position.x; minY = maxY = m_quad[0].position.y; - for (unsigned int v{ 1u }; v < 4; ++v) + for (unsigned int v{ 1u }; v < 6u; ++v) { minX = std::min(minX, m_quad[v].position.x); maxX = std::max(maxX, m_quad[v].position.x); @@ -129,7 +129,7 @@ sf::FloatRect Line::getGlobalBounds() const float minX, maxX, minY, maxY; minX = maxX = transformedPosition0.x; minY = maxY = transformedPosition0.y; - for (unsigned int v{ 1u }; v < 4; ++v) + for (unsigned int v{ 1u }; v < 6u; ++v) { const sf::Vector2f transformedPosition{ transform.transformPoint(m_quad[v].position) }; minX = std::min(minX, transformedPosition.x); @@ -171,13 +171,14 @@ sf::Color Line::getColor() const void Line::setColor(const sf::Color& color) { - //m_color = color; - m_vertices[0].color = color; - m_vertices[1].color = color; - m_quad[0].color = color; - m_quad[1].color = color; - m_quad[2].color = color; - m_quad[3].color = color; + m_vertices[0u].color = color; + m_vertices[1u].color = color; + m_quad[0u].color = color; + m_quad[1u].color = color; + m_quad[2u].color = color; + m_quad[3u].color = color; + m_quad[4u].color = color; + m_quad[5u].color = color; } void Line::setTexture(const sf::Texture& texture) @@ -233,21 +234,21 @@ bool Line::isThick() const void Line::updateQuad() { - const sf::Vector2f lineVector{ m_vertices[0].position - m_vertices[1].position }; + const sf::Vector2f lineVector{ m_vertices[0u].position - m_vertices[1u].position }; const float lineLength{ std::sqrt(lineVector.x * lineVector.x + lineVector.y * lineVector.y) }; const sf::Vector2f unitVector{ lineVector / lineLength }; const sf::Vector2f unitNormalVector{ unitVector.y, -unitVector.x }; const sf::Vector2f normalVector{ unitNormalVector * m_thickness / 2.f }; - m_quad[0].position = m_vertices[0].position - normalVector; - m_quad[1].position = m_vertices[1].position - normalVector; - m_quad[2].position = m_vertices[1].position + normalVector; - m_quad[3].position = m_vertices[0].position + normalVector; + m_quad[0u].position = m_vertices[0u].position + normalVector; + m_quad[1u].position = m_vertices[0u].position - normalVector; + m_quad[2u].position = m_vertices[1u].position + normalVector; + m_quad[3u].position = m_vertices[1u].position - normalVector; - m_quad[0].texCoords = { m_textureRect.left, m_textureRect.top }; - m_quad[1].texCoords = { m_textureRect.left + m_textureRect.width, m_textureRect.top }; - m_quad[2].texCoords = { m_textureRect.left + m_textureRect.width, m_textureRect.top + m_textureRect.height }; - m_quad[3].texCoords = { m_textureRect.left, m_textureRect.top + m_textureRect.height }; + m_quad[0u].texCoords = { m_textureRect.left, m_textureRect.top }; + m_quad[1u].texCoords = { m_textureRect.left, m_textureRect.top + m_textureRect.height }; + m_quad[2u].texCoords = { m_textureRect.left + m_textureRect.width, m_textureRect.top }; + m_quad[3u].texCoords = { m_textureRect.left + m_textureRect.width, m_textureRect.top + m_textureRect.height }; } } // selbaward diff --git a/src/SelbaWard/Line.hpp b/src/SelbaWard/Line.hpp index da477bb..46189c6 100644 --- a/src/SelbaWard/Line.hpp +++ b/src/SelbaWard/Line.hpp @@ -41,7 +41,7 @@ namespace selbaward { -// SW Line v1.2.1 +// SW Line v1.2.2 class Line : public sf::Drawable, public sf::Transformable { public: diff --git a/src/SelbaWard/NinePatch.cpp b/src/SelbaWard/NinePatch.cpp index 5d2070e..5330aeb 100644 --- a/src/SelbaWard/NinePatch.cpp +++ b/src/SelbaWard/NinePatch.cpp @@ -144,8 +144,8 @@ namespace selbaward { NinePatch::NinePatch() - : m_primitiveType{ sf::PrimitiveType::Quads } - , m_vertices(36, sf::Vertex({ 0.f, 0.f })) + : m_primitiveType{ sf::PrimitiveType::TriangleStrip } + , m_vertices(22u, sf::Vertex({ 0.f, 0.f })) , m_texture{ nullptr } , m_trimmedSize({ 0.f, 0.f }) , m_size({ 0.f, 0.f }) @@ -244,7 +244,7 @@ void NinePatch::draw(sf::RenderTarget& target, sf::RenderStates states) const { states.texture = m_texture; states.transform *= getTransform(); - target.draw(&m_vertices.front(), 36, m_primitiveType, states); + target.draw(m_vertices.data(), 22u, m_primitiveType, states); } void NinePatch::priv_updateVertices() @@ -257,107 +257,74 @@ void NinePatch::priv_updateVerticesPositions() { const sf::Vector2f newBottomRightScaled{ m_size - (m_trimmedSize - m_scaleBottomRight) }; - // top row - m_vertices[0].position = { 0.f, 0.f }; - m_vertices[1].position = { m_scaleTopLeft.x, 0.f }; - m_vertices[2].position = m_scaleTopLeft; - m_vertices[3].position = { 0.f, m_scaleTopLeft.y }; - - m_vertices[4].position = { m_scaleTopLeft.x, 0.f }; - m_vertices[5].position = { newBottomRightScaled.x, 0.f }; - m_vertices[6].position = { newBottomRightScaled.x, m_scaleTopLeft.y }; - m_vertices[7].position = m_scaleTopLeft; - - m_vertices[8].position = { newBottomRightScaled.x, 0.f }; - m_vertices[9].position = { m_size.x, 0.f }; - m_vertices[10].position = { m_size.x, m_scaleTopLeft.y }; - m_vertices[11].position = { newBottomRightScaled.x, m_scaleTopLeft.y }; - - // centre row - m_vertices[12].position = { 0.f, m_scaleTopLeft.y }; - m_vertices[13].position = { m_scaleTopLeft.x, m_scaleTopLeft.y }; - m_vertices[14].position = { m_scaleTopLeft.x, newBottomRightScaled.y }; - m_vertices[15].position = { 0.f, newBottomRightScaled.y }; - - m_vertices[16].position = { m_scaleTopLeft.x, m_scaleTopLeft.y }; - m_vertices[17].position = { newBottomRightScaled.x, m_scaleTopLeft.y }; - m_vertices[18].position = { newBottomRightScaled.x, newBottomRightScaled.y }; - m_vertices[19].position = { m_scaleTopLeft.x, newBottomRightScaled.y }; - - m_vertices[20].position = { newBottomRightScaled.x, m_scaleTopLeft.y }; - m_vertices[21].position = { m_size.x, m_scaleTopLeft.y }; - m_vertices[22].position = { m_size.x, newBottomRightScaled.y }; - m_vertices[23].position = { newBottomRightScaled.x, newBottomRightScaled.y }; - - // bottom row - m_vertices[24].position = { 0.f, newBottomRightScaled.y }; - m_vertices[25].position = { m_scaleTopLeft.x, newBottomRightScaled.y }; - m_vertices[26].position = { m_scaleTopLeft.x, m_size.y }; - m_vertices[27].position = { 0.f, m_size.y }; - - m_vertices[28].position = { m_scaleTopLeft.x, newBottomRightScaled.y }; - m_vertices[29].position = { newBottomRightScaled.x, newBottomRightScaled.y }; - m_vertices[30].position = { newBottomRightScaled.x, m_size.y }; - m_vertices[31].position = { m_scaleTopLeft.x, m_size.y }; - - m_vertices[32].position = { newBottomRightScaled.x, newBottomRightScaled.y }; - m_vertices[33].position = { m_size.x, newBottomRightScaled.y }; - m_vertices[34].position = { m_size.x, m_size.y }; - m_vertices[35].position = { newBottomRightScaled.x, m_size.y }; - + const float x0{ 0.f }; + const float x1{ m_scaleTopLeft.x }; + const float x2{ newBottomRightScaled.x }; + const float x3{ m_size.x }; + const float y0{ 0.f }; + const float y1{ m_scaleTopLeft.y }; + const float y2{ newBottomRightScaled.y }; + const float y3{ m_size.y }; + + m_vertices[0u].position = { x0, y0 }; + m_vertices[1u].position = { x0, y1 }; + m_vertices[2u].position = { x1, y0 }; + m_vertices[3u].position = { x1, y1 }; + m_vertices[4u].position = { x2, y0 }; + m_vertices[5u].position = { x2, y1 }; + m_vertices[6u].position = { x3, y0 }; + m_vertices[7u].position = { x3, y1 }; + m_vertices[8u].position = { x3, y2 }; + m_vertices[9u].position = { x2, y1 }; + m_vertices[10u].position = { x2, y2 }; + m_vertices[11u].position = { x1, y1 }; + m_vertices[12u].position = { x1, y2 }; + m_vertices[13u].position = { x0, y1 }; + m_vertices[14u].position = { x0, y2 }; + m_vertices[15u].position = { x0, y3 }; + m_vertices[16u].position = { x1, y2 }; + m_vertices[17u].position = { x1, y3 }; + m_vertices[18u].position = { x2, y2 }; + m_vertices[19u].position = { x2, y3 }; + m_vertices[20u].position = { x3, y2 }; + m_vertices[21u].position = { x3, y3 }; } void NinePatch::priv_updateVerticesTexCoords() { const sf::Vector2f textureBottomRight{ m_trimmedSize }; - // top row - m_vertices[0].texCoords = { 0.f, 0.f }; - m_vertices[1].texCoords = { m_scaleTopLeft.x, 0.f }; - m_vertices[2].texCoords = m_scaleTopLeft; - m_vertices[3].texCoords = { 0.f, m_scaleTopLeft.y }; - - m_vertices[4].texCoords = { m_scaleTopLeft.x, 0.f }; - m_vertices[5].texCoords = { m_scaleBottomRight.x, 0.f }; - m_vertices[6].texCoords = { m_scaleBottomRight.x, m_scaleTopLeft.y }; - m_vertices[7].texCoords = m_scaleTopLeft; - - m_vertices[8].texCoords = { m_scaleBottomRight.x, 0.f }; - m_vertices[9].texCoords = { textureBottomRight.x, 0.f }; - m_vertices[10].texCoords = { textureBottomRight.x, m_scaleTopLeft.y }; - m_vertices[11].texCoords = { m_scaleBottomRight.x, m_scaleTopLeft.y }; - - // centre row - m_vertices[12].texCoords = { 0.f, m_scaleTopLeft.y }; - m_vertices[13].texCoords = m_scaleTopLeft; - m_vertices[14].texCoords = { m_scaleTopLeft.x, m_scaleBottomRight.y }; - m_vertices[15].texCoords = { 0.f, m_scaleBottomRight.y }; - - m_vertices[16].texCoords = m_scaleTopLeft; - m_vertices[17].texCoords = { m_scaleBottomRight.x, m_scaleTopLeft.y }; - m_vertices[18].texCoords = m_scaleBottomRight; - m_vertices[19].texCoords = { m_scaleTopLeft.x, m_scaleBottomRight.y }; - - m_vertices[20].texCoords = { m_scaleBottomRight.x, m_scaleTopLeft.y }; - m_vertices[21].texCoords = { textureBottomRight.x, m_scaleTopLeft.y }; - m_vertices[22].texCoords = { textureBottomRight.x, m_scaleBottomRight.y }; - m_vertices[23].texCoords = m_scaleBottomRight; - - // bottom row - m_vertices[24].texCoords = { 0.f, m_scaleBottomRight.y }; - m_vertices[25].texCoords = { m_scaleTopLeft.x, m_scaleBottomRight.y }; - m_vertices[26].texCoords = { m_scaleTopLeft.x, textureBottomRight.y }; - m_vertices[27].texCoords = { 0.f, textureBottomRight.y }; - - m_vertices[28].texCoords = { m_scaleTopLeft.x, m_scaleBottomRight.y }; - m_vertices[29].texCoords = m_scaleBottomRight; - m_vertices[30].texCoords = { m_scaleBottomRight.x, textureBottomRight.y }; - m_vertices[31].texCoords = { m_scaleTopLeft.x, textureBottomRight.y }; - - m_vertices[32].texCoords = m_scaleBottomRight; - m_vertices[33].texCoords = { textureBottomRight.x, m_scaleBottomRight.y }; - m_vertices[34].texCoords = textureBottomRight; - m_vertices[35].texCoords = { m_scaleBottomRight.x, textureBottomRight.y }; + const float x0{ 0.f }; + const float x1{ m_scaleTopLeft.x }; + const float x2{ m_scaleBottomRight.x }; + const float x3{ textureBottomRight.x }; + const float y0{ 0.f }; + const float y1{ m_scaleTopLeft.y }; + const float y2{ m_scaleBottomRight.y }; + const float y3{ textureBottomRight.y }; + + m_vertices[0u].texCoords = { x0, y0 }; + m_vertices[1u].texCoords = { x0, y1 }; + m_vertices[2u].texCoords = { x1, y0 }; + m_vertices[3u].texCoords = { x1, y1 }; + m_vertices[4u].texCoords = { x2, y0 }; + m_vertices[5u].texCoords = { x2, y1 }; + m_vertices[6u].texCoords = { x3, y0 }; + m_vertices[7u].texCoords = { x3, y1 }; + m_vertices[8u].texCoords = { x3, y2 }; + m_vertices[9u].texCoords = { x2, y1 }; + m_vertices[10u].texCoords = { x2, y2 }; + m_vertices[11u].texCoords = { x1, y1 }; + m_vertices[12u].texCoords = { x1, y2 }; + m_vertices[13u].texCoords = { x0, y1 }; + m_vertices[14u].texCoords = { x0, y2 }; + m_vertices[15u].texCoords = { x0, y3 }; + m_vertices[16u].texCoords = { x1, y2 }; + m_vertices[17u].texCoords = { x1, y3 }; + m_vertices[18u].texCoords = { x2, y2 }; + m_vertices[19u].texCoords = { x2, y3 }; + m_vertices[20u].texCoords = { x3, y2 }; + m_vertices[21u].texCoords = { x3, y3 }; // offset trim and texture rectangle const sf::Vector2f textureRectangleOffset{ static_cast(m_textureRectangle.left), static_cast(m_textureRectangle.top) }; diff --git a/src/SelbaWard/NinePatch.hpp b/src/SelbaWard/NinePatch.hpp index 363d5a9..a55946e 100644 --- a/src/SelbaWard/NinePatch.hpp +++ b/src/SelbaWard/NinePatch.hpp @@ -40,7 +40,7 @@ namespace selbaward { -// SW Nine Patch v1.4.2 +// SW Nine Patch v1.4.3 class NinePatch : public sf::Drawable, public sf::Transformable { public: diff --git a/src/SelbaWard/PixelDisplay.cpp b/src/SelbaWard/PixelDisplay.cpp index a5a12c8..78c7a31 100644 --- a/src/SelbaWard/PixelDisplay.cpp +++ b/src/SelbaWard/PixelDisplay.cpp @@ -525,22 +525,24 @@ void PixelDisplay::draw(sf::RenderTarget& target, sf::RenderStates states) const { states.texture = nullptr; states.transform *= getTransform(); - target.draw(m_vertices.data(), m_vertices.size(), sf::PrimitiveType::Quads, states); + target.draw(m_vertices.data(), m_vertices.size(), sf::PrimitiveType::Triangles, states); } void PixelDisplay::priv_updateVertices() { - m_vertices.resize(m_resolution.x * m_resolution.y * 4u); + m_vertices.resize(m_resolution.x * m_resolution.y * 6u); for (unsigned int y{ 0u }; y < m_resolution.y; ++y) { for (unsigned int x{ 0u }; x < m_resolution.x; ++x) { const sf::Vector2f topLeft{ m_size.x * x / m_resolution.x, m_size.y * y / m_resolution.y }; const sf::Vector2f bottomRight{ m_size.x * (x + 1u) / m_resolution.x, m_size.y * (y + 1u) / m_resolution.y }; - m_vertices[(y * m_resolution.x + x) * 4u + 0u].position = topLeft; - m_vertices[(y * m_resolution.x + x) * 4u + 1u].position = { bottomRight.x, topLeft.y }; - m_vertices[(y * m_resolution.x + x) * 4u + 2u].position = bottomRight; - m_vertices[(y * m_resolution.x + x) * 4u + 3u].position = { topLeft.x, bottomRight.y }; + m_vertices[((y * m_resolution.x + x) * 6u) + 0u].position = topLeft; + m_vertices[((y * m_resolution.x + x) * 6u) + 1u].position = { topLeft.x, bottomRight.y }; + m_vertices[((y * m_resolution.x + x) * 6u) + 2u].position = { bottomRight.x, topLeft.y }; + m_vertices[((y * m_resolution.x + x) * 6u) + 3u].position = bottomRight; + m_vertices[((y * m_resolution.x + x) * 6u) + 4u].position = m_vertices[((y * m_resolution.x + x) * 6u) + 2u].position; + m_vertices[((y * m_resolution.x + x) * 6u) + 5u].position = m_vertices[((y * m_resolution.x + x) * 6u) + 1u].position; } } } @@ -554,12 +556,14 @@ void PixelDisplay::priv_updatePixels() void PixelDisplay::priv_updatePixel(const unsigned int index) { - const unsigned int baseVertexIndex{ index * 4u }; + const unsigned int baseVertexIndex{ index * 6u }; const sf::Color rgb{ m_palette[m_pixels[index]] }; m_vertices[baseVertexIndex + 0u].color = rgb; m_vertices[baseVertexIndex + 1u].color = rgb; m_vertices[baseVertexIndex + 2u].color = rgb; m_vertices[baseVertexIndex + 3u].color = rgb; + m_vertices[baseVertexIndex + 4u].color = rgb; + m_vertices[baseVertexIndex + 5u].color = rgb; } unsigned int PixelDisplay::priv_getRandomColor() const diff --git a/src/SelbaWard/PixelDisplay.hpp b/src/SelbaWard/PixelDisplay.hpp index c2da004..3a2e0b3 100644 --- a/src/SelbaWard/PixelDisplay.hpp +++ b/src/SelbaWard/PixelDisplay.hpp @@ -38,7 +38,7 @@ namespace selbaward { -// SW PixelDisplay v1.0.0 +// SW PixelDisplay v1.0.1 class PixelDisplay : public sf::Drawable, public sf::Transformable { public: diff --git a/src/SelbaWard/Polygon.cpp b/src/SelbaWard/Polygon.cpp index 5889fd6..45e745f 100644 --- a/src/SelbaWard/Polygon.cpp +++ b/src/SelbaWard/Polygon.cpp @@ -46,11 +46,28 @@ inline bool isSecondVectorAntiClockwiseOfFirstVector(const sf::Vector2f& first, inline bool pointIsInsideTriangle(const std::vector& points, sf::Vector2f point) { + long double point1X{ static_cast(points[0].x) }; + long double point1Y{ static_cast(points[0].y) }; + long double point2X{ static_cast(points[1].x) }; + long double point2Y{ static_cast(points[1].y) }; + long double point3X{ static_cast(points[2].x) }; + long double point3Y{ static_cast(points[2].y) }; + long double pointX{ static_cast(point.x) }; + long double pointY{ static_cast(point.y) }; + + long double denominatorMultiplier{ 1.l / ((point2Y - point3Y) * (point1X - point3X) + (point3X - point2X) * (point1Y - point3Y)) }; + long double a{ ((point2Y - point3Y) * (pointX - point3X) + (point3X - point2X) * (pointY - point3Y)) * denominatorMultiplier }; + long double b{ ((point3Y - point1Y) * (pointX - point3X) + (point1X - point3X) * (pointY - point3Y)) * denominatorMultiplier }; + long double c{ 1.l - a - b }; + return a >= 0.l && a <= 1.l && b >= 0.l && b <= 1.l && c >= 0.l && c <= 1.l; + + /* float denominatorMultiplier{ 1.f / ((points[1u].y - points[2u].y) * (points[0u].x - points[2u].x) + (points[2u].x - points[1u].x) * (points[0u].y - points[2u].y)) }; float a{ ((points[1u].y - points[2u].y) * (point.x - points[2u].x) + (points[2u].x - points[1u].x) * (point.y - points[2u].y)) * denominatorMultiplier }; float b{ ((points[2u].y - points[0u].y) * (point.x - points[2u].x) + (points[0u].x - points[2u].x) * (point.y - points[2u].y)) * denominatorMultiplier }; float c{ 1.f - a - b }; return a >= 0.f && a <= 1.f && b >= 0.f && b <= 1.f && c >= 0.f && c <= 1.f; + */ } } // namespace diff --git a/src/SelbaWard/ProgressBar.cpp b/src/SelbaWard/ProgressBar.cpp index 6cc46a6..f74a84e 100644 --- a/src/SelbaWard/ProgressBar.cpp +++ b/src/SelbaWard/ProgressBar.cpp @@ -41,7 +41,7 @@ ProgressBar::ProgressBar(const sf::Vector2f size) , m_showBackground{ false } , m_size(size) , m_color(sf::Color::White) - , m_bar(4) + , m_bar(4u) , m_backgroundAndFrame(size) , m_texture{ nullptr } , m_backgroundTexture{ nullptr } @@ -203,7 +203,7 @@ void ProgressBar::draw(sf::RenderTarget& target, sf::RenderStates states) const if (m_showBar) { states.texture = m_texture; - target.draw(&m_bar.front(), 4, sf::PrimitiveType::Quads, states); + target.draw(&m_bar.front(), 4u, sf::PrimitiveType::TriangleStrip, states); } } @@ -214,16 +214,16 @@ void ProgressBar::priv_updateGraphics() m_backgroundAndFrame.setTextureRect(m_backgroundTextureRectangle); const float width{ m_size.x * m_amount }; - m_bar[0].position = { 0.f, 0.f }; - m_bar[1].position = { width, 0.f }; - m_bar[2].position = { width, m_size.y }; - m_bar[3].position = { 0.f, m_size.y }; + m_bar[0u].position = { 0.f, 0.f }; + m_bar[1u].position = { 0.f, m_size.y }; + m_bar[2u].position = { width, 0.f }; + m_bar[3u].position = { width, m_size.y }; sf::FloatRect textureRect{ m_textureRectangle }; textureRect.width = textureRect.width * m_amount; - m_bar[0].texCoords = { textureRect.left, textureRect.top }; - m_bar[1].texCoords = { textureRect.left + textureRect.width, textureRect.top }; - m_bar[2].texCoords = { textureRect.left + textureRect.width, textureRect.top + textureRect.height }; - m_bar[3].texCoords = { textureRect.left, textureRect.top + textureRect.height }; + m_bar[0u].texCoords = { textureRect.left, textureRect.top }; + m_bar[1u].texCoords = { textureRect.left, textureRect.top + textureRect.height }; + m_bar[2u].texCoords = { textureRect.left + textureRect.width, textureRect.top }; + m_bar[3u].texCoords = { textureRect.left + textureRect.width, textureRect.top + textureRect.height }; for (auto& vertex : m_bar) vertex.color = m_color; } diff --git a/src/SelbaWard/ProgressBar.hpp b/src/SelbaWard/ProgressBar.hpp index 1e4e28c..f73c83c 100644 --- a/src/SelbaWard/ProgressBar.hpp +++ b/src/SelbaWard/ProgressBar.hpp @@ -41,7 +41,7 @@ namespace selbaward { -// SW Progress Bar 1.1.1 +// SW Progress Bar 1.1.2 class ProgressBar : public sf::Drawable, public sf::Transformable { public: diff --git a/src/SelbaWard/Spline.cpp b/src/SelbaWard/Spline.cpp index 35ccb65..0a593f7 100644 --- a/src/SelbaWard/Spline.cpp +++ b/src/SelbaWard/Spline.cpp @@ -203,6 +203,69 @@ Spline::Spline(std::initializer_list list) m_vertices[index++].position = position; } +Spline::Spline(const Spline& spline) + : m_throwExceptions{ spline.m_throwExceptions } + , m_isClosed{ spline.m_isClosed } + , m_isRandomNormalOffsetsActivated{ spline.m_isRandomNormalOffsetsActivated } + , m_thickCornerType{ spline.m_thickCornerType } + , m_thickStartCapType{ spline.m_thickStartCapType } + , m_thickEndCapType{ spline.m_thickEndCapType } + , m_roundedThickCornerInterpolationLevel{ spline.m_roundedThickCornerInterpolationLevel } + , m_roundedThickStartCapInterpolationLevel{ spline.m_roundedThickStartCapInterpolationLevel } + , m_roundedThickEndCapInterpolationLevel{ spline.m_roundedThickEndCapInterpolationLevel } + , m_maxPointLength{ spline.m_maxPointLength } + , m_automaticallyUpdateRandomNormalOffset{ spline.m_automaticallyUpdateRandomNormalOffset } + //, m_vertices(vertexCount, Vertex(initialPosition)) + , m_color{ spline.m_color } + , m_thickness{ spline.m_thickness } + , m_randomNormalOffsetRange{ spline.m_randomNormalOffsetRange } + //, m_interpolatedVertices() + //, m_interpolatedVerticesUnitTangents() + //, m_outputVertices() + , m_primitiveType{ spline.m_primitiveType } + , m_interpolationSteps{ spline.m_interpolationSteps } + , m_useBezier{ spline.m_useBezier } + //, m_handlesVertices() + , m_showHandles{ spline.m_showHandles } + , m_lockHandleMirror{ spline.m_lockHandleMirror } + , m_lockHandleAngle{ spline.m_lockHandleAngle } +{ + m_vertices = spline.m_vertices; + m_interpolatedVertices = spline.m_interpolatedVertices; + m_interpolatedVerticesUnitTangents = spline.m_interpolatedVerticesUnitTangents; + m_outputVertices = spline.m_outputVertices; + m_handlesVertices = spline.m_handlesVertices; +} + +void Spline::operator=(const Spline& spline) +{ + m_throwExceptions = spline.m_throwExceptions; + m_isClosed = spline.m_isClosed; + m_isRandomNormalOffsetsActivated = spline.m_isRandomNormalOffsetsActivated; + m_thickCornerType = spline.m_thickCornerType; + m_thickStartCapType = spline.m_thickStartCapType; + m_thickEndCapType = spline.m_thickEndCapType; + m_roundedThickCornerInterpolationLevel = spline.m_roundedThickCornerInterpolationLevel; + m_roundedThickStartCapInterpolationLevel = spline.m_roundedThickStartCapInterpolationLevel; + m_roundedThickEndCapInterpolationLevel = spline.m_roundedThickEndCapInterpolationLevel; + m_maxPointLength = spline.m_maxPointLength; + m_color = spline.m_color; + m_thickness = spline.m_thickness; + m_randomNormalOffsetRange = spline.m_randomNormalOffsetRange; + m_primitiveType = spline.m_primitiveType; + m_interpolationSteps = spline.m_interpolationSteps; + m_useBezier = spline.m_useBezier; + m_showHandles = spline.m_showHandles; + m_lockHandleMirror = spline.m_lockHandleMirror; + m_lockHandleAngle = spline.m_lockHandleAngle; + + m_vertices = spline.m_vertices; + m_interpolatedVertices = spline.m_interpolatedVertices; + m_interpolatedVerticesUnitTangents = spline.m_interpolatedVerticesUnitTangents; + m_outputVertices = spline.m_outputVertices; + m_handlesVertices = spline.m_handlesVertices; +} + float Spline::getLength() const { if (m_vertices.size() < 2) @@ -791,7 +854,7 @@ sf::Vector2f Spline::getInterpolatedPosition(const std::size_t interpolationOffs std::size_t Spline::getInterpolatedPositionCount() const { - return ((m_isClosed) ? (m_vertices.size() * priv_getNumberOfPointsPerVertex()) : ((m_vertices.size() - 1u) * priv_getNumberOfPointsPerVertex() + 1u)); + return ((m_isClosed) ? (m_vertices.size() * priv_getNumberOfPointsPerVertex() + 1u) : ((m_vertices.size() - 1u) * priv_getNumberOfPointsPerVertex() + 1u)); } sf::Vector2f Spline::getInterpolatedPositionTangent(const std::size_t interpolationOffset, const std::size_t index) const @@ -837,6 +900,26 @@ float Spline::getInterpolatedPositionThicknessCorrectionScale(const std::size_t return sideOffsetLength * 2 / getInterpolatedPositionThickness(interpolationOffset, index); } +std::vector Spline::exportAllPositions() const +{ + std::vector positions(m_vertices.size()); + for (std::size_t i{ 0u }; i < positions.size(); ++i) + positions[i] = m_vertices[i].position; + if (m_isClosed) + positions.push_back(m_vertices[0u].position); + return positions; +} + +std::vector Spline::exportAllInterpolatedPositions() const +{ + std::vector positions(m_interpolatedVertices.size()); + for (std::size_t i{ 0u }; i < positions.size(); ++i) + positions[i] = m_interpolatedVertices[i].position; + if (m_isClosed) + positions.push_back(m_vertices[0u].position); + return positions; +} + // PRIVATE diff --git a/src/SelbaWard/Spline.hpp b/src/SelbaWard/Spline.hpp index 63880d3..d91cab7 100644 --- a/src/SelbaWard/Spline.hpp +++ b/src/SelbaWard/Spline.hpp @@ -38,7 +38,7 @@ namespace selbaward { -// SW Spline v1.6.2 +// SW Spline v1.7.0 class Spline : public sf::Drawable { public: @@ -70,6 +70,9 @@ class Spline : public sf::Drawable Spline(std::size_t vertexCount = 0u, sf::Vector2f initialPosition = { 0.f, 0.f }); Spline(std::initializer_list list); // pass vertices' positions (sf::Vector2f) to the constructor (sets size automatically) + Spline(const Spline& spline); + void operator=(const Spline& spline); + void update(); void updateOutputVertices(); @@ -187,6 +190,9 @@ class Spline : public sf::Drawable float getInterpolatedPositionThicknessCorrectionScale(std::size_t interpolationOffset, std::size_t index = 0u) const; // index is control vertex offset std::size_t getInterpolatedPositionCount() const; + std::vector exportAllPositions() const; + std::vector exportAllInterpolatedPositions() const; + diff --git a/src/SelbaWard/TileMap.hpp b/src/SelbaWard/TileMap.hpp index e9d626a..99b49eb 100644 --- a/src/SelbaWard/TileMap.hpp +++ b/src/SelbaWard/TileMap.hpp @@ -44,7 +44,7 @@ namespace selbaward { -// SW Tile Map v2.0.1 +// SW Tile Map v2.0.2 template class TileMap : public sf::Drawable, public sf::Transformable { diff --git a/src/SelbaWard/TileMap.inl b/src/SelbaWard/TileMap.inl index 7b249cc..37ca43e 100644 --- a/src/SelbaWard/TileMap.inl +++ b/src/SelbaWard/TileMap.inl @@ -50,7 +50,7 @@ TileMap::TileMap() , m_camera({ 0.f, 0.f }) , m_cameraTarget({ 0.f, 0.f }) , m_color(sf::Color::White) - , m_primitiveType(sf::PrimitiveType::Quads) + , m_primitiveType(sf::PrimitiveType::Triangles) , m_size() , m_texture(nullptr) , m_numberOfTextureTilesPerRow(16u) @@ -59,7 +59,7 @@ TileMap::TileMap() , m_vertices() , m_redrawRequired(true) , m_renderTexture() - , m_render(4) + , m_render(4u) { priv_recreateRenderTexture(); } @@ -384,7 +384,7 @@ void TileMap::draw(sf::RenderTarget& target, sf::RenderStates states) const states.texture = &m_renderTexture.getTexture(); states.transform = getTransform(); - target.draw(&m_render.front(), 4, sf::PrimitiveType::Quads, states); // final render is always 4 vertices & quad + target.draw(m_render.data(), 4u, sf::PrimitiveType::TriangleStrip, states); // final render is always 4 vertices & quad } template @@ -401,13 +401,18 @@ void TileMap::priv_updateVertices() const const unsigned int tileIndex{ y * m_gridSize.x + x }; const unsigned long int tileValue{ m_grid[tileIndex] }; const sf::Vector2u textureTilePosition{ static_cast(tileValue % m_numberOfTextureTilesPerRow * m_textureTileSize.x), static_cast(tileValue / m_numberOfTextureTilesPerRow * m_textureTileSize.y) }; - sf::Vertex* pVertex{ &m_vertices[tileIndex * 4] }; + sf::Vertex* pVertex{ &m_vertices[tileIndex * 6u] }; // top-left pVertex->position = { static_cast(m_textureTileSize.x * x), static_cast(m_textureTileSize.y * y) }; pVertex->texCoords = sf::Vector2f(m_textureOffset + textureTilePosition); pVertex++->color = m_color; + // bottom-left + pVertex->position = { static_cast(m_textureTileSize.x * x), static_cast(m_textureTileSize.y * (y + 1)) }; + pVertex->texCoords = { static_cast(m_textureOffset.x + textureTilePosition.x), static_cast(m_textureOffset.y + textureTilePosition.y + m_textureTileSize.y) }; + pVertex++->color = m_color; + // top-right pVertex->position = { static_cast(m_textureTileSize.x * (x + 1)), static_cast(m_textureTileSize.y * y) }; pVertex->texCoords = { static_cast(m_textureOffset.x + textureTilePosition.x + m_textureTileSize.x), static_cast(m_textureOffset.y + textureTilePosition.y) }; @@ -418,10 +423,11 @@ void TileMap::priv_updateVertices() const pVertex->texCoords = sf::Vector2f(m_textureOffset + textureTilePosition + m_textureTileSize); pVertex++->color = m_color; - // bottom-left - pVertex->position = { static_cast(m_textureTileSize.x * x), static_cast(m_textureTileSize.y * (y + 1)) }; - pVertex->texCoords = { static_cast(m_textureOffset.x + textureTilePosition.x), static_cast(m_textureOffset.y + textureTilePosition.y + m_textureTileSize.y) }; - pVertex++->color = m_color; + // repeated top-right + *(pVertex++) = *(pVertex - 2u); + + // repeated bottom-left + *(pVertex++) = *(pVertex - 4u); } } @@ -434,15 +440,15 @@ void TileMap::priv_updateVertices() const template void TileMap::priv_updateRender() const { - m_render[0].position = { 0.f, 0.f }; - m_render[1].position = { m_size.x, 0.f }; - m_render[2].position = m_size; - m_render[3].position = { 0.f, m_size.y }; + m_render[0u].position = { 0.f, 0.f }; + m_render[1u].position = { 0.f, m_size.y }; + m_render[2u].position = { m_size.x, 0.f }; + m_render[3u].position = m_size; const sf::Vector2f size{ m_renderTexture.getSize() }; - m_render[0].texCoords = { 0.f, 0.f }; - m_render[1].texCoords = { size.x, 0.f }; - m_render[2].texCoords = size; - m_render[3].texCoords = { 0.f, size.y }; + m_render[0u].texCoords = { 0.f, 0.f }; + m_render[1u].texCoords = { 0.f, size.y }; + m_render[2u].texCoords = { size.x, 0.f }; + m_render[3u].texCoords = size; if (m_do.scrollSmoothly) { @@ -458,7 +464,7 @@ void TileMap::priv_updateRender() const m_renderTexture.clear(sf::Color::Transparent); const unsigned int numberOfVertices{ static_cast(m_vertices.size()) }; if (numberOfVertices > 0) - m_renderTexture.draw(&m_vertices.front(), numberOfVertices, m_primitiveType, m_texture); + m_renderTexture.draw(m_vertices.data(), numberOfVertices, m_primitiveType, m_texture); m_renderTexture.display(); m_renderTexture.setSmooth(m_is.smooth); From 9cb03020bf56aa6431d2f72c828c32150f93895b Mon Sep 17 00:00:00 2001 From: Chris Thrasher Date: Sun, 20 Aug 2023 15:37:21 -0600 Subject: [PATCH 20/64] Add build script and CI pipeline --- .github/workflows/ci.yml | 78 ++++++++++++++++++++++++++++++++++++++++ CMakeLists.txt | 39 ++++++++++++++++++++ examples/CMakeLists.txt | 26 ++++++++++++++ 3 files changed, 143 insertions(+) create mode 100644 .github/workflows/ci.yml create mode 100644 CMakeLists.txt create mode 100644 examples/CMakeLists.txt diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..72e3e78 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,78 @@ +name: CI + +on: [push, pull_request, workflow_dispatch] + +concurrency: + group: environment-${{github.ref}} + cancel-in-progress: true + +jobs: + build: + name: ${{matrix.platform.name}} ${{matrix.type.name}} + runs-on: ${{matrix.platform.os}} + defaults: + run: + shell: bash + + strategy: + fail-fast: false + matrix: + platform: + - { name: Windows MSVC, os: windows-2022 } + - { name: Windows ClangCL, os: windows-2022, flags: -T ClangCL } + - { name: Windows Clang, os: windows-2022, flags: -GNinja -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ } + - { name: Windows MinGW, os: windows-2022, flags: -GNinja -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ } + - { name: Linux GCC, os: ubuntu-22.04, flags: -GNinja } + - { name: Linux Clang, os: ubuntu-22.04, flags: -GNinja -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ } + - { name: macOS, os: macos-12, flags: -GNinja } + type: + - { name: Release } + - { name: Debug } + + steps: + - name: Install Linux Dependencies + if: runner.os == 'Linux' + run: | + sudo apt update + sudo apt install ninja-build llvm xorg-dev libxrandr-dev libxcursor-dev libudev-dev libgl1-mesa-dev libegl1-mesa-dev + + - name: Install macOS Tools + if: runner.os == 'macOS' + run: brew install ninja + + - name: Checkout SFML + uses: actions/checkout@v3 + with: + repository: SFML/SFML + path: sfml + ref: 2.6.0 + + - name: Configure SFML + run: | + cmake -S sfml -B sfml/build \ + -DCMAKE_INSTALL_PREFIX=sfml/install \ + -DCMAKE_BUILD_TYPE=${{matrix.type.name}} \ + -DSFML_BUILD_AUDIO=OFF \ + -DSFML_BUILD_NETWORK=OFF \ + ${{matrix.platform.flags}} + + - name: Build SFML + run: cmake --build sfml/build --config ${{matrix.type.name}} --target install + + - name: Checkout SelbaWard + uses: actions/checkout@v3 + with: + path: SelbaWard + + - name: Configure SelbaWard + run: | + cmake -S SelbaWard -B SelbaWard/build \ + -DBUILD_EXAMPLES=ON \ + -DCMAKE_INSTALL_PREFIX=$GITHUB_WORKSPACE/install \ + -DCMAKE_BUILD_TYPE=${{matrix.type.name}} \ + -DCMAKE_VERBOSE_MAKEFILE=ON \ + -DSFML_ROOT=$GITHUB_WORKSPACE/sfml/install \ + ${{matrix.platform.flags}} + + - name: Build SelbaWard + run: cmake --build SelbaWard/build --config ${{matrix.type.name}} diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..67adf98 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,39 @@ +cmake_minimum_required(VERSION 3.16) +project(SelbaWard LANGUAGES CXX) + +find_package(SFML 2.6 REQUIRED COMPONENTS graphics) + +add_library(SelbaWard + src/SelbaWard/BitmapFont.cpp + src/SelbaWard/BitmapText.cpp + src/SelbaWard/ConsoleScreen.cpp + src/SelbaWard/Crosshair.cpp + src/SelbaWard/ElasticSprite.cpp + src/SelbaWard/GallerySprite.cpp + src/SelbaWard/Line.cpp + src/SelbaWard/NinePatch.cpp + src/SelbaWard/PieChart.cpp + src/SelbaWard/PixelDisplay.cpp + src/SelbaWard/Polygon.cpp + src/SelbaWard/ProgressBar.cpp + src/SelbaWard/Ring.cpp + src/SelbaWard/SpinningCard.cpp + src/SelbaWard/Spline.cpp + src/SelbaWard/Sprite3d.cpp + src/SelbaWard/Starfield.cpp + src/SelbaWard/Starfield3d.cpp +) +add_library(SelbaWard::SelbaWard ALIAS SelbaWard) +target_include_directories(SelbaWard PUBLIC src) +target_link_libraries(SelbaWard PUBLIC sfml-graphics) +target_compile_features(SelbaWard PUBLIC cxx_std_11) + +# Stop configuration if being consumed by a higher level project +if(NOT PROJECT_IS_TOP_LEVEL) + return() +endif() + +option(BUILD_EXAMPLES "Build examples" OFF) +if(BUILD_EXAMPLES) + add_subdirectory(examples) +endif() diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt new file mode 100644 index 0000000..ddc2c72 --- /dev/null +++ b/examples/CMakeLists.txt @@ -0,0 +1,26 @@ +add_executable(bitmap-text bitmapTextExample.cpp) +target_link_libraries(bitmap-text PRIVATE SelbaWard::SelbaWard) + +add_executable(line lineExample.cpp) +target_link_libraries(line PRIVATE SelbaWard::SelbaWard) + +add_executable(progress-bar progressBarExample.cpp) +target_link_libraries(progress-bar PRIVATE SelbaWard::SelbaWard) + +add_executable(spinning-card spinningCardExample.cpp) +target_link_libraries(spinning-card PRIVATE SelbaWard::SelbaWard) + +add_executable(spline splineExample.cpp) +target_link_libraries(spline PRIVATE SelbaWard::SelbaWard) + +add_executable(spline2 splineExample2.cpp) +target_link_libraries(spline2 PRIVATE SelbaWard::SelbaWard) + +add_executable(sprite3d sprite3dExample.cpp) +target_link_libraries(sprite3d PRIVATE SelbaWard::SelbaWard) + +add_executable(sprite3d-card-fan sprite3dExampleCardFan.cpp) +target_link_libraries(sprite3d-card-fan PRIVATE SelbaWard::SelbaWard) + +add_executable(sprite3d-spinning-card sprite3dExampleSpinningCard.cpp) +target_link_libraries(sprite3d-spinning-card PRIVATE SelbaWard::SelbaWard) From dd0a6b378cd32519c7e204d66182dbc088076fee Mon Sep 17 00:00:00 2001 From: Hapaxia Date: Mon, 21 Aug 2023 17:54:17 +0100 Subject: [PATCH 21/64] Update licence.txt --- licence.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/licence.txt b/licence.txt index ddf02c2..04edf34 100644 --- a/licence.txt +++ b/licence.txt @@ -1,6 +1,6 @@ Selba Ward (https://github.com/Hapaxia/SelbaWard) -Copyright (c) 2014-2022 M. J. Silk +Copyright (c) 2014-2023 M. J. Silk This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages From cd24dea8b6eaaa00798da71a1f573947305ded7a Mon Sep 17 00:00:00 2001 From: Hapaxia Date: Mon, 21 Aug 2023 18:11:45 +0100 Subject: [PATCH 22/64] PixelDisplay - update to v1.0.2 patch update to address a bug. --- src/SelbaWard/PixelDisplay.cpp | 2 +- src/SelbaWard/PixelDisplay.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/SelbaWard/PixelDisplay.cpp b/src/SelbaWard/PixelDisplay.cpp index d82beb8..cce1474 100644 --- a/src/SelbaWard/PixelDisplay.cpp +++ b/src/SelbaWard/PixelDisplay.cpp @@ -580,7 +580,7 @@ void PixelDisplay::priv_copyToBufferFromSelectionRectangle(Buffer& buffer, const for (unsigned int y{ 0u }; y < rectangle.height; ++y) { for (unsigned int x{ 0u }; x < buffer.width; ++x) - buffer.pixels[y * buffer.width + x] = m_pixels[x + rectangle.left, y + rectangle.top]; + buffer.pixels[y * buffer.width + x] = m_pixels[(y + rectangle.top) * buffer.width + (x + rectangle.left)]; } } diff --git a/src/SelbaWard/PixelDisplay.hpp b/src/SelbaWard/PixelDisplay.hpp index 75bc649..35f849b 100644 --- a/src/SelbaWard/PixelDisplay.hpp +++ b/src/SelbaWard/PixelDisplay.hpp @@ -38,7 +38,7 @@ namespace selbaward { -// SW PixelDisplay v1.0.1 +// SW PixelDisplay v1.0.2 class PixelDisplay : public sf::Drawable, public sf::Transformable { public: From 899d8dae6a42ae4b07d2ca7567657a15d4c51ce3 Mon Sep 17 00:00:00 2001 From: Hapaxia Date: Wed, 8 Nov 2023 22:19:06 +0000 Subject: [PATCH 23/64] update ConsoleScreen to v2.4.4 fixes the order of the colours in the 16-colour Windows palette. --- src/SelbaWard/ConsoleScreen.cpp | 6 +++--- src/SelbaWard/ConsoleScreen.hpp | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/SelbaWard/ConsoleScreen.cpp b/src/SelbaWard/ConsoleScreen.cpp index ae59e22..90ba8f9 100644 --- a/src/SelbaWard/ConsoleScreen.cpp +++ b/src/SelbaWard/ConsoleScreen.cpp @@ -216,12 +216,12 @@ void addPalette16ColorWindows(std::vector& palette) addColorToPalette(palette, sf::Color(0, 0, 128)); addColorToPalette(palette, sf::Color(128, 0, 128)); addColorToPalette(palette, sf::Color(0, 128, 128)); - addColorToPalette(palette, sf::Color(128, 128, 128)); addColorToPalette(palette, sf::Color(192, 192, 192)); + addColorToPalette(palette, sf::Color(128, 128, 128)); addColorToPalette(palette, sf::Color(255, 0, 0)); - addColorToPalette(palette, sf::Color(0, 0, 255)); - addColorToPalette(palette, sf::Color(255, 255, 0)); addColorToPalette(palette, sf::Color(0, 255, 0)); + addColorToPalette(palette, sf::Color(255, 255, 0)); + addColorToPalette(palette, sf::Color(0, 0, 255)); addColorToPalette(palette, sf::Color(255, 0, 255)); addColorToPalette(palette, sf::Color(0, 255, 255)); addColorToPalette(palette, sf::Color(255, 255, 255)); diff --git a/src/SelbaWard/ConsoleScreen.hpp b/src/SelbaWard/ConsoleScreen.hpp index 6f6b863..c1f9b48 100644 --- a/src/SelbaWard/ConsoleScreen.hpp +++ b/src/SelbaWard/ConsoleScreen.hpp @@ -45,7 +45,7 @@ namespace sf namespace selbaward { -// SW Console Screen v2.4.3 +// SW Console Screen v2.4.4 class ConsoleScreen : public sf::Drawable, public sf::Transformable { public: From f61fd44a47c06448aed0a8f06fe3f958f7da81be Mon Sep 17 00:00:00 2001 From: Hapaxia Date: Wed, 8 Nov 2023 22:34:31 +0000 Subject: [PATCH 24/64] update ConsoleScreen to v2.4.5 contracted the texture rectangle slightly (by 0.1 on each side) to reduce chance of texture bleeding. --- src/SelbaWard/ConsoleScreen.cpp | 8 ++++---- src/SelbaWard/ConsoleScreen.hpp | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/SelbaWard/ConsoleScreen.cpp b/src/SelbaWard/ConsoleScreen.cpp index 90ba8f9..273ab04 100644 --- a/src/SelbaWard/ConsoleScreen.cpp +++ b/src/SelbaWard/ConsoleScreen.cpp @@ -2509,10 +2509,10 @@ void ConsoleScreen::priv_setVerticesFromCell(unsigned int index, int baseVertex, const float bottom{ offset.y + linearInterpolation(0.f, m_size.y, static_cast(cellY + (cell.attributes.flipY ? 0 : 1)) / m_mode.y) }; sf::Vector2u textureCell{ cellValue % m_numberOfTilesPerRow, cellValue / m_numberOfTilesPerRow }; - const float textureLeft{ static_cast(m_textureOffset.x + textureCell.x * m_tileSize.x) }; - const float textureTop{ static_cast(m_textureOffset.y + (textureCell.y + (!useCursorValue && cell.stretch == StretchType::Bottom ? 0.5f : 0.f)) * m_tileSize.y) }; - const float textureRight{ static_cast(m_textureOffset.x + (textureCell.x + 1) * m_tileSize.x) }; - const float textureBottom{ static_cast(m_textureOffset.y + (textureCell.y + (!useCursorValue && cell.stretch == StretchType::Top ? 0.5f : 1.f)) * m_tileSize.y) }; + const float textureLeft{ 0.1f + static_cast(m_textureOffset.x + textureCell.x * m_tileSize.x) }; + const float textureTop{ 0.1f + static_cast(m_textureOffset.y + (textureCell.y + (!useCursorValue && cell.stretch == StretchType::Bottom ? 0.5f : 0.f)) * m_tileSize.y) }; + const float textureRight{ -0.1f + static_cast(m_textureOffset.x + (textureCell.x + 1) * m_tileSize.x) }; + const float textureBottom{ -0.1f + static_cast(m_textureOffset.y + (textureCell.y + (!useCursorValue && cell.stretch == StretchType::Top ? 0.5f : 1.f)) * m_tileSize.y) }; if (mainLayer) baseVertex = index * 6u; diff --git a/src/SelbaWard/ConsoleScreen.hpp b/src/SelbaWard/ConsoleScreen.hpp index c1f9b48..f3da1c4 100644 --- a/src/SelbaWard/ConsoleScreen.hpp +++ b/src/SelbaWard/ConsoleScreen.hpp @@ -45,7 +45,7 @@ namespace sf namespace selbaward { -// SW Console Screen v2.4.4 +// SW Console Screen v2.4.5 class ConsoleScreen : public sf::Drawable, public sf::Transformable { public: From f8905310600a5107c80011ca10cb09af6af23be6 Mon Sep 17 00:00:00 2001 From: Hapaxia Date: Sun, 12 Nov 2023 16:52:08 +0000 Subject: [PATCH 25/64] update Spline to v1.6.3 add ability to assign a Spline to another Spline: a Spline's equals operator has been added to accept another spline to allow copying from the other. --- src/SelbaWard/Spline.cpp | 29 +++++++++++++++++++++++++++++ src/SelbaWard/Spline.hpp | 4 +++- 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/src/SelbaWard/Spline.cpp b/src/SelbaWard/Spline.cpp index 621dfff..3f95a6a 100644 --- a/src/SelbaWard/Spline.cpp +++ b/src/SelbaWard/Spline.cpp @@ -314,6 +314,35 @@ void Spline::updateOutputVertices() priv_updateOutputVertices(); } +Spline& Spline::operator=(const Spline& spline) +{ + m_throwExceptions = spline.m_throwExceptions; + m_isClosed = spline.m_isClosed; + m_isRandomNormalOffsetsActivated = spline.m_isRandomNormalOffsetsActivated; + m_thickCornerType = spline.m_thickCornerType; + m_thickStartCapType = spline.m_thickStartCapType; + m_thickEndCapType = spline.m_thickEndCapType; + m_roundedThickCornerInterpolationLevel = spline.m_roundedThickCornerInterpolationLevel; + m_roundedThickStartCapInterpolationLevel = spline.m_roundedThickStartCapInterpolationLevel; + m_roundedThickEndCapInterpolationLevel = spline.m_roundedThickEndCapInterpolationLevel; + m_maxPointLength = spline.m_maxPointLength; + m_vertices = spline.m_vertices; + m_color = spline.m_color; + m_thickness = spline.m_thickness; + m_randomNormalOffsetRange = spline.m_randomNormalOffsetRange; + m_interpolatedVerticesUnitTangents = spline.m_interpolatedVerticesUnitTangents; + m_outputVertices = spline.m_outputVertices; + m_primitiveType = spline.m_primitiveType; + m_interpolationSteps = spline.m_interpolationSteps; + m_useBezier = spline.m_useBezier; + m_handlesVertices = spline.m_handlesVertices; + m_showHandles = spline.m_showHandles; + m_lockHandleMirror = spline.m_lockHandleMirror; + m_lockHandleAngle = spline.m_lockHandleAngle; + + return *this; +} + void Spline::connectFrontToFrontOf(const Spline& spline, const bool rotateSpline, const bool moveSpline) { if (!moveSpline && !rotateSpline) diff --git a/src/SelbaWard/Spline.hpp b/src/SelbaWard/Spline.hpp index d599035..adca806 100644 --- a/src/SelbaWard/Spline.hpp +++ b/src/SelbaWard/Spline.hpp @@ -38,7 +38,7 @@ namespace selbaward { -// SW Spline v1.6.2 +// SW Spline v1.6.3 class Spline : public sf::Drawable { public: @@ -73,6 +73,8 @@ class Spline : public sf::Drawable void update(); void updateOutputVertices(); + Spline& operator=(const Spline& spline); + Vertex& operator[] (std::size_t index); // direct access to the spline's vertices (sw::Spline::Vertex) using the [] operator. no checks are performed. using with an invalid index results in undefined behaviour void connectFrontToFrontOf(const Spline& spline, bool rotateSpline = true, bool moveSpline = true); From ebb17d033877d808ac1a18bc381f49fabbae0a76 Mon Sep 17 00:00:00 2001 From: Hapaxia Date: Sun, 12 Nov 2023 16:52:08 +0000 Subject: [PATCH 26/64] update Spline to v1.6.3 add ability to assign a Spline to another Spline: a Spline's equals operator has been added to accept another spline to allow copying from the other. --- src/SelbaWard/Spline.cpp | 29 +++++++++++++++++++++++++++++ src/SelbaWard/Spline.hpp | 4 +++- 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/src/SelbaWard/Spline.cpp b/src/SelbaWard/Spline.cpp index 0a593f7..03c999d 100644 --- a/src/SelbaWard/Spline.cpp +++ b/src/SelbaWard/Spline.cpp @@ -377,6 +377,35 @@ void Spline::updateOutputVertices() priv_updateOutputVertices(); } +Spline& Spline::operator=(const Spline& spline) +{ + m_throwExceptions = spline.m_throwExceptions; + m_isClosed = spline.m_isClosed; + m_isRandomNormalOffsetsActivated = spline.m_isRandomNormalOffsetsActivated; + m_thickCornerType = spline.m_thickCornerType; + m_thickStartCapType = spline.m_thickStartCapType; + m_thickEndCapType = spline.m_thickEndCapType; + m_roundedThickCornerInterpolationLevel = spline.m_roundedThickCornerInterpolationLevel; + m_roundedThickStartCapInterpolationLevel = spline.m_roundedThickStartCapInterpolationLevel; + m_roundedThickEndCapInterpolationLevel = spline.m_roundedThickEndCapInterpolationLevel; + m_maxPointLength = spline.m_maxPointLength; + m_vertices = spline.m_vertices; + m_color = spline.m_color; + m_thickness = spline.m_thickness; + m_randomNormalOffsetRange = spline.m_randomNormalOffsetRange; + m_interpolatedVerticesUnitTangents = spline.m_interpolatedVerticesUnitTangents; + m_outputVertices = spline.m_outputVertices; + m_primitiveType = spline.m_primitiveType; + m_interpolationSteps = spline.m_interpolationSteps; + m_useBezier = spline.m_useBezier; + m_handlesVertices = spline.m_handlesVertices; + m_showHandles = spline.m_showHandles; + m_lockHandleMirror = spline.m_lockHandleMirror; + m_lockHandleAngle = spline.m_lockHandleAngle; + + return *this; +} + void Spline::connectFrontToFrontOf(const Spline& spline, const bool rotateSpline, const bool moveSpline) { if (!moveSpline && !rotateSpline) diff --git a/src/SelbaWard/Spline.hpp b/src/SelbaWard/Spline.hpp index d91cab7..9314576 100644 --- a/src/SelbaWard/Spline.hpp +++ b/src/SelbaWard/Spline.hpp @@ -38,7 +38,7 @@ namespace selbaward { -// SW Spline v1.7.0 +// SW Spline v1.6.3 class Spline : public sf::Drawable { public: @@ -76,6 +76,8 @@ class Spline : public sf::Drawable void update(); void updateOutputVertices(); + Spline& operator=(const Spline& spline); + Vertex& operator[] (std::size_t index); // direct access to the spline's vertices (sw::Spline::Vertex) using the [] operator. no checks are performed. using with an invalid index results in undefined behaviour void connectFrontToFrontOf(const Spline& spline, bool rotateSpline = true, bool moveSpline = true); From 8c75cfdbb5faf9f5f5e0308f1bb6bc2d95515edd Mon Sep 17 00:00:00 2001 From: Hapaxia Date: Thu, 12 Jan 2023 16:35:50 +0000 Subject: [PATCH 27/64] Update .gitignore From b8c252564f4c34bc278b3f0c77f67a1ed8d0d771 Mon Sep 17 00:00:00 2001 From: Hapaxia Date: Mon, 17 Apr 2023 02:06:39 +0100 Subject: [PATCH 28/64] remove use of deprecated quads primitive removed all use of deprecated quads primitive type from all objects (except ConsoleScreenOld - this does not get updated and may be removed in the future). quads have been replaced with a different primitive type but each object may use different ones depending on its usage. updates: BitmapText to v1.1.3. now uses triangles so now requires 6 vertices per character instead of 4. ConsoleScreen to v2.4.3. now uses triangles so now requires 6 vertices per cell (on every layer) instead of 4. ElasticSprite to v1.3.1. now uses triangle fan and therefore still uses 4 vertices. Line to v1.2.2. now uses triangle strip and therefore still uses 4 vertices (for the thick line only). NinePatch to v1.4.3. now uses triangle strip and uses significantly fewer vertices - down from 36 to just 22! PixelDisplay to v1.0.1. now uses triangles so requires 6 vertices per 'pixel' instead of 4. ProgressBar to v1.1.2. now uses triangle strip so still uses 4 vertices (for the progress quad - the background and frame is still an SFML rectangle shape). TileMap to v2.0.2. now uses triangles so requires 6 vertices per tile instead of 4. in addition to the replacement of the quads primitive, some literals have been replaced with more accurate ones (e.g. 5u instead of just 5 when it's unsigned or size_t), especially in the areas that have been updated for the primitive change. From 2f43da351d7e1d2f155c3a6af0fcb38575bda2bb Mon Sep 17 00:00:00 2001 From: Hapaxia Date: Mon, 17 Apr 2023 14:19:04 +0100 Subject: [PATCH 29/64] update year update all years to reach 2023, the current year --- src/SelbaWard.hpp | 2 +- src/SelbaWard/BitmapFont.cpp | 2 +- src/SelbaWard/BitmapFont.hpp | 2 +- src/SelbaWard/BitmapText.cpp | 2 +- src/SelbaWard/BitmapText.hpp | 2 +- src/SelbaWard/Common.hpp | 2 +- src/SelbaWard/ConsoleScreen.cpp | 2 +- src/SelbaWard/ConsoleScreen.hpp | 2 +- src/SelbaWard/ConsoleScreenOld.cpp | 2 +- src/SelbaWard/ConsoleScreenOld.hpp | 2 +- src/SelbaWard/Crosshair.cpp | 2 +- src/SelbaWard/Crosshair.hpp | 2 +- src/SelbaWard/ElasticSprite.cpp | 2 +- src/SelbaWard/ElasticSprite.hpp | 2 +- src/SelbaWard/Exception.hpp | 2 +- src/SelbaWard/GallerySprite.cpp | 2 +- src/SelbaWard/GallerySprite.hpp | 2 +- src/SelbaWard/Line.cpp | 2 +- src/SelbaWard/Line.hpp | 2 +- src/SelbaWard/NinePatch.cpp | 2 +- src/SelbaWard/NinePatch.hpp | 2 +- src/SelbaWard/PaletteEnums.hpp | 2 +- src/SelbaWard/PieChart.cpp | 2 +- src/SelbaWard/PieChart.hpp | 2 +- src/SelbaWard/PixelDisplay.cpp | 2 +- src/SelbaWard/PixelDisplay.hpp | 2 +- src/SelbaWard/Polygon.cpp | 2 +- src/SelbaWard/Polygon.hpp | 2 +- src/SelbaWard/ProgressBar.cpp | 2 +- src/SelbaWard/ProgressBar.hpp | 2 +- src/SelbaWard/Ring.cpp | 2 +- src/SelbaWard/Ring.hpp | 2 +- src/SelbaWard/SpinningCard.cpp | 2 +- src/SelbaWard/SpinningCard.hpp | 2 +- src/SelbaWard/Spline.cpp | 2 +- src/SelbaWard/Spline.hpp | 2 +- src/SelbaWard/Sprite3d.cpp | 2 +- src/SelbaWard/Sprite3d.hpp | 2 +- src/SelbaWard/Starfield.cpp | 2 +- src/SelbaWard/Starfield.hpp | 2 +- src/SelbaWard/TileMap.hpp | 2 +- src/SelbaWard/TileMap.inl | 2 +- 42 files changed, 42 insertions(+), 42 deletions(-) diff --git a/src/SelbaWard.hpp b/src/SelbaWard.hpp index e56b01b..1f0a0fd 100644 --- a/src/SelbaWard.hpp +++ b/src/SelbaWard.hpp @@ -2,7 +2,7 @@ // // Selba Ward (https://github.com/Hapaxia/SelbaWard) // -// Copyright(c) 2015-2022 M.J.Silk +// Copyright(c) 2015-2023 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/BitmapFont.cpp b/src/SelbaWard/BitmapFont.cpp index 9eac8d6..01e3bd3 100644 --- a/src/SelbaWard/BitmapFont.cpp +++ b/src/SelbaWard/BitmapFont.cpp @@ -5,7 +5,7 @@ // // BitmapFont // -// Copyright(c) 2014-2022 M.J.Silk +// Copyright(c) 2014-2023 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/BitmapFont.hpp b/src/SelbaWard/BitmapFont.hpp index 224403c..2b28ea4 100644 --- a/src/SelbaWard/BitmapFont.hpp +++ b/src/SelbaWard/BitmapFont.hpp @@ -5,7 +5,7 @@ // // BitmapFont // -// Copyright(c) 2014-2022 M.J.Silk +// Copyright(c) 2014-2023 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/BitmapText.cpp b/src/SelbaWard/BitmapText.cpp index b59688e..da817cd 100644 --- a/src/SelbaWard/BitmapText.cpp +++ b/src/SelbaWard/BitmapText.cpp @@ -5,7 +5,7 @@ // // BitmapText // -// Copyright(c) 2014-2022 M.J.Silk +// Copyright(c) 2014-2023 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/BitmapText.hpp b/src/SelbaWard/BitmapText.hpp index c1cb35a..f401a01 100644 --- a/src/SelbaWard/BitmapText.hpp +++ b/src/SelbaWard/BitmapText.hpp @@ -5,7 +5,7 @@ // // BitmapText // -// Copyright(c) 2014-2022 M.J.Silk +// Copyright(c) 2014-2023 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/Common.hpp b/src/SelbaWard/Common.hpp index a33f750..c7ce274 100644 --- a/src/SelbaWard/Common.hpp +++ b/src/SelbaWard/Common.hpp @@ -2,7 +2,7 @@ // // Selba Ward (https://github.com/Hapaxia/SelbaWard) // -// Copyright(c) 2015-2022 M.J.Silk +// Copyright(c) 2015-2023 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/ConsoleScreen.cpp b/src/SelbaWard/ConsoleScreen.cpp index 2740684..ae59e22 100644 --- a/src/SelbaWard/ConsoleScreen.cpp +++ b/src/SelbaWard/ConsoleScreen.cpp @@ -5,7 +5,7 @@ // // Console Screen v2 // -// Copyright(c) 2014-2022 M.J.Silk +// Copyright(c) 2014-2023 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/ConsoleScreen.hpp b/src/SelbaWard/ConsoleScreen.hpp index 6823683..6f6b863 100644 --- a/src/SelbaWard/ConsoleScreen.hpp +++ b/src/SelbaWard/ConsoleScreen.hpp @@ -5,7 +5,7 @@ // // Console Screen v2 // -// Copyright(c) 2014-2022 M.J.Silk +// Copyright(c) 2014-2023 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/ConsoleScreenOld.cpp b/src/SelbaWard/ConsoleScreenOld.cpp index bb0a777..ac74c24 100644 --- a/src/SelbaWard/ConsoleScreenOld.cpp +++ b/src/SelbaWard/ConsoleScreenOld.cpp @@ -5,7 +5,7 @@ // // Console Screen v1 // -// Copyright(c) 2014-2022 M.J.Silk +// Copyright(c) 2014-2023 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/ConsoleScreenOld.hpp b/src/SelbaWard/ConsoleScreenOld.hpp index d87b17c..dbc9cca 100644 --- a/src/SelbaWard/ConsoleScreenOld.hpp +++ b/src/SelbaWard/ConsoleScreenOld.hpp @@ -5,7 +5,7 @@ // // Console Screen v1 // -// Copyright(c) 2014-2022 M.J.Silk +// Copyright(c) 2014-2023 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/Crosshair.cpp b/src/SelbaWard/Crosshair.cpp index 687c753..6a2891a 100644 --- a/src/SelbaWard/Crosshair.cpp +++ b/src/SelbaWard/Crosshair.cpp @@ -5,7 +5,7 @@ // // Crosshair // -// Copyright(c) 2016-2022 M.J.Silk +// Copyright(c) 2016-2023 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/Crosshair.hpp b/src/SelbaWard/Crosshair.hpp index 56e81ee..9f0a20a 100644 --- a/src/SelbaWard/Crosshair.hpp +++ b/src/SelbaWard/Crosshair.hpp @@ -5,7 +5,7 @@ // // Crosshair // -// Copyright(c) 2016-2022 M.J.Silk +// Copyright(c) 2016-2023 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/ElasticSprite.cpp b/src/SelbaWard/ElasticSprite.cpp index 7dca1fb..6877648 100644 --- a/src/SelbaWard/ElasticSprite.cpp +++ b/src/SelbaWard/ElasticSprite.cpp @@ -5,7 +5,7 @@ // // Elastic Sprite // -// Copyright(c) 2017-2022 M.J.Silk +// Copyright(c) 2017-2023 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/ElasticSprite.hpp b/src/SelbaWard/ElasticSprite.hpp index 97c34ef..d926371 100644 --- a/src/SelbaWard/ElasticSprite.hpp +++ b/src/SelbaWard/ElasticSprite.hpp @@ -5,7 +5,7 @@ // // Elastic Sprite // -// Copyright(c) 2017-2022 M.J.Silk +// Copyright(c) 2017-2023 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/Exception.hpp b/src/SelbaWard/Exception.hpp index fbc3b01..1a98ca0 100644 --- a/src/SelbaWard/Exception.hpp +++ b/src/SelbaWard/Exception.hpp @@ -2,7 +2,7 @@ // // Selba Ward (https://github.com/Hapaxia/SelbaWard) // -// Copyright(c) 2015-2022 M.J.Silk +// Copyright(c) 2015-2023 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/GallerySprite.cpp b/src/SelbaWard/GallerySprite.cpp index 7fe8316..fcc8c11 100644 --- a/src/SelbaWard/GallerySprite.cpp +++ b/src/SelbaWard/GallerySprite.cpp @@ -5,7 +5,7 @@ // // Gallery Sprite // -// Copyright(c) 2016-2022 M.J.Silk +// Copyright(c) 2016-2023 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/GallerySprite.hpp b/src/SelbaWard/GallerySprite.hpp index da52e85..6a58474 100644 --- a/src/SelbaWard/GallerySprite.hpp +++ b/src/SelbaWard/GallerySprite.hpp @@ -5,7 +5,7 @@ // // Gallery Sprite // -// Copyright(c) 2016-2022 M.J.Silk +// Copyright(c) 2016-2023 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/Line.cpp b/src/SelbaWard/Line.cpp index 0b1a934..f922df4 100644 --- a/src/SelbaWard/Line.cpp +++ b/src/SelbaWard/Line.cpp @@ -5,7 +5,7 @@ // // Line // -// Copyright(c) 2015-2022 M.J.Silk +// Copyright(c) 2015-2023 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/Line.hpp b/src/SelbaWard/Line.hpp index 46189c6..66e9990 100644 --- a/src/SelbaWard/Line.hpp +++ b/src/SelbaWard/Line.hpp @@ -5,7 +5,7 @@ // // Line // -// Copyright(c) 2015-2022 M.J.Silk +// Copyright(c) 2015-2023 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/NinePatch.cpp b/src/SelbaWard/NinePatch.cpp index 5330aeb..bdca4b3 100644 --- a/src/SelbaWard/NinePatch.cpp +++ b/src/SelbaWard/NinePatch.cpp @@ -5,7 +5,7 @@ // // NinePatch // -// Copyright(c) 2015-2022 M.J.Silk +// Copyright(c) 2015-2023 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/NinePatch.hpp b/src/SelbaWard/NinePatch.hpp index a55946e..ec1d53a 100644 --- a/src/SelbaWard/NinePatch.hpp +++ b/src/SelbaWard/NinePatch.hpp @@ -5,7 +5,7 @@ // // NinePatch // -// Copyright(c) 2015-2022 M.J.Silk +// Copyright(c) 2015-2023 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/PaletteEnums.hpp b/src/SelbaWard/PaletteEnums.hpp index 95aafa1..80ca425 100644 --- a/src/SelbaWard/PaletteEnums.hpp +++ b/src/SelbaWard/PaletteEnums.hpp @@ -5,7 +5,7 @@ // // Palette Enums // -// Copyright(c) 2016-2022 M.J.Silk +// Copyright(c) 2016-2023 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/PieChart.cpp b/src/SelbaWard/PieChart.cpp index 706cc8d..8650f3e 100644 --- a/src/SelbaWard/PieChart.cpp +++ b/src/SelbaWard/PieChart.cpp @@ -5,7 +5,7 @@ // // Pie Chart // -// Copyright(c) 2015-2022 M.J.Silk +// Copyright(c) 2015-2023 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/PieChart.hpp b/src/SelbaWard/PieChart.hpp index 6ae81dc..50423cc 100644 --- a/src/SelbaWard/PieChart.hpp +++ b/src/SelbaWard/PieChart.hpp @@ -5,7 +5,7 @@ // // Pie Chart // -// Copyright(c) 2015-2022 M.J.Silk +// Copyright(c) 2015-2023 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/PixelDisplay.cpp b/src/SelbaWard/PixelDisplay.cpp index 78c7a31..d82beb8 100644 --- a/src/SelbaWard/PixelDisplay.cpp +++ b/src/SelbaWard/PixelDisplay.cpp @@ -5,7 +5,7 @@ // // Pixel Display // -// Copyright(c) 2019-2022 M.J.Silk +// Copyright(c) 2019-2023 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/PixelDisplay.hpp b/src/SelbaWard/PixelDisplay.hpp index 3a2e0b3..75bc649 100644 --- a/src/SelbaWard/PixelDisplay.hpp +++ b/src/SelbaWard/PixelDisplay.hpp @@ -5,7 +5,7 @@ // // Pixel Display // -// Copyright(c) 2019-2022 M.J.Silk +// Copyright(c) 2019-2023 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/Polygon.cpp b/src/SelbaWard/Polygon.cpp index 45e745f..b9eed0a 100644 --- a/src/SelbaWard/Polygon.cpp +++ b/src/SelbaWard/Polygon.cpp @@ -5,7 +5,7 @@ // // Polygon // -// Copyright(c) 2022 M.J.Silk +// Copyright(c) 2022-2023 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/Polygon.hpp b/src/SelbaWard/Polygon.hpp index f0fb38b..7a4ca07 100644 --- a/src/SelbaWard/Polygon.hpp +++ b/src/SelbaWard/Polygon.hpp @@ -5,7 +5,7 @@ // // Polygon // -// Copyright(c) 2022 M.J.Silk +// Copyright(c) 2022-2023 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/ProgressBar.cpp b/src/SelbaWard/ProgressBar.cpp index f74a84e..5dfb869 100644 --- a/src/SelbaWard/ProgressBar.cpp +++ b/src/SelbaWard/ProgressBar.cpp @@ -5,7 +5,7 @@ // // Progress Bar // -// Copyright(c) 2015-2022 M.J.Silk +// Copyright(c) 2015-2023 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/ProgressBar.hpp b/src/SelbaWard/ProgressBar.hpp index f73c83c..a36750b 100644 --- a/src/SelbaWard/ProgressBar.hpp +++ b/src/SelbaWard/ProgressBar.hpp @@ -5,7 +5,7 @@ // // Progress Bar // -// Copyright(c) 2015-2022 M.J.Silk +// Copyright(c) 2015-2023 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/Ring.cpp b/src/SelbaWard/Ring.cpp index e89d076..bcc367b 100644 --- a/src/SelbaWard/Ring.cpp +++ b/src/SelbaWard/Ring.cpp @@ -5,7 +5,7 @@ // // Ring // -// Copyright(c) 2016-2022 M.J.Silk +// Copyright(c) 2016-2023 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/Ring.hpp b/src/SelbaWard/Ring.hpp index 7a6e52c..5c660cd 100644 --- a/src/SelbaWard/Ring.hpp +++ b/src/SelbaWard/Ring.hpp @@ -5,7 +5,7 @@ // // Ring // -// Copyright(c) 2016-2022 M.J.Silk +// Copyright(c) 2016-2023 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/SpinningCard.cpp b/src/SelbaWard/SpinningCard.cpp index 468b0d8..46def47 100644 --- a/src/SelbaWard/SpinningCard.cpp +++ b/src/SelbaWard/SpinningCard.cpp @@ -5,7 +5,7 @@ // // SpinningCard // -// Copyright(c) 2014-2022 M.J.Silk +// Copyright(c) 2014-2023 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/SpinningCard.hpp b/src/SelbaWard/SpinningCard.hpp index 7b56eb8..3d607b8 100644 --- a/src/SelbaWard/SpinningCard.hpp +++ b/src/SelbaWard/SpinningCard.hpp @@ -5,7 +5,7 @@ // // Spinning Card // -// Copyright(c) 2014-2022 M.J.Silk +// Copyright(c) 2014-2023 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/Spline.cpp b/src/SelbaWard/Spline.cpp index 03c999d..0c7a243 100644 --- a/src/SelbaWard/Spline.cpp +++ b/src/SelbaWard/Spline.cpp @@ -5,7 +5,7 @@ // // Spline // -// Copyright(c) 2014-2022 M.J.Silk +// Copyright(c) 2014-2023 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/Spline.hpp b/src/SelbaWard/Spline.hpp index 9314576..8b9fb6a 100644 --- a/src/SelbaWard/Spline.hpp +++ b/src/SelbaWard/Spline.hpp @@ -5,7 +5,7 @@ // // Spline // -// Copyright(c) 2014-2022 M.J.Silk +// Copyright(c) 2014-2023 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/Sprite3d.cpp b/src/SelbaWard/Sprite3d.cpp index 08313fd..293daa6 100644 --- a/src/SelbaWard/Sprite3d.cpp +++ b/src/SelbaWard/Sprite3d.cpp @@ -5,7 +5,7 @@ // // Sprite3d // -// Copyright(c) 2015-2022 M.J.Silk +// Copyright(c) 2015-2023 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/Sprite3d.hpp b/src/SelbaWard/Sprite3d.hpp index 960db3b..f2246c0 100644 --- a/src/SelbaWard/Sprite3d.hpp +++ b/src/SelbaWard/Sprite3d.hpp @@ -5,7 +5,7 @@ // // Sprite3d // -// Copyright(c) 2015-2022 M.J.Silk +// Copyright(c) 2015-2023 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/Starfield.cpp b/src/SelbaWard/Starfield.cpp index 3c93b00..1c25b2f 100644 --- a/src/SelbaWard/Starfield.cpp +++ b/src/SelbaWard/Starfield.cpp @@ -5,7 +5,7 @@ // // Starfield // -// Copyright(c) 2016-2022 M.J.Silk +// Copyright(c) 2016-2023 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/Starfield.hpp b/src/SelbaWard/Starfield.hpp index 099cf9a..86fc053 100644 --- a/src/SelbaWard/Starfield.hpp +++ b/src/SelbaWard/Starfield.hpp @@ -5,7 +5,7 @@ // // Starfield // -// Copyright(c) 2016-2022 M.J.Silk +// Copyright(c) 2016-2023 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/TileMap.hpp b/src/SelbaWard/TileMap.hpp index 99b49eb..fed04cb 100644 --- a/src/SelbaWard/TileMap.hpp +++ b/src/SelbaWard/TileMap.hpp @@ -5,7 +5,7 @@ // // Tile Map // -// Copyright(c) 2016-2022 M.J.Silk +// Copyright(c) 2016-2023 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/TileMap.inl b/src/SelbaWard/TileMap.inl index 37ca43e..eecc689 100644 --- a/src/SelbaWard/TileMap.inl +++ b/src/SelbaWard/TileMap.inl @@ -5,7 +5,7 @@ // // Tile Map // -// Copyright(c) 2016-2022 M.J.Silk +// Copyright(c) 2016-2023 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages From 1a7dff474be9699b15c723a64db93faab8ce1066 Mon Sep 17 00:00:00 2001 From: Hapaxia Date: Mon, 17 Apr 2023 15:32:49 +0100 Subject: [PATCH 30/64] update TileMap to v2.0.3 bug patch. wrong value used for vertices. since changing from quads (4 vertices per tile) to triangles (6 vertices per tile), the vertex vector should be resized to 6 per tile to be able to hold all of the vertices otherwise attempts to access vertices not available can cause errors. this is fixed here. --- src/SelbaWard/TileMap.hpp | 2 +- src/SelbaWard/TileMap.inl | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/SelbaWard/TileMap.hpp b/src/SelbaWard/TileMap.hpp index fed04cb..b550fce 100644 --- a/src/SelbaWard/TileMap.hpp +++ b/src/SelbaWard/TileMap.hpp @@ -44,7 +44,7 @@ namespace selbaward { -// SW Tile Map v2.0.2 +// SW Tile Map v2.0.3 template class TileMap : public sf::Drawable, public sf::Transformable { diff --git a/src/SelbaWard/TileMap.inl b/src/SelbaWard/TileMap.inl index eecc689..2ec41c5 100644 --- a/src/SelbaWard/TileMap.inl +++ b/src/SelbaWard/TileMap.inl @@ -390,7 +390,7 @@ void TileMap::draw(sf::RenderTarget& target, sf::RenderStates states) const template void TileMap::priv_updateVertices() const { - m_vertices.resize(m_gridSize.x * m_gridSize.y * 4); + m_vertices.resize(m_gridSize.x * m_gridSize.y * 6u); if (m_gridSize.x == 0 || m_gridSize.y == 0) return; From 3d3fa4c93c67763145e187f4248dfac68c0a56f5 Mon Sep 17 00:00:00 2001 From: Hapaxia Date: Mon, 8 May 2023 23:26:22 +0100 Subject: [PATCH 31/64] remove ConsoleScreenOld removed old version of Console Screen as the current, latest version succeeds it completely and the old version is out-of-date. --- src/SelbaWard.hpp | 1 - src/SelbaWard/ConsoleScreenOld.cpp | 2344 ---------------------------- src/SelbaWard/ConsoleScreenOld.hpp | 416 ----- 3 files changed, 2761 deletions(-) delete mode 100644 src/SelbaWard/ConsoleScreenOld.cpp delete mode 100644 src/SelbaWard/ConsoleScreenOld.hpp diff --git a/src/SelbaWard.hpp b/src/SelbaWard.hpp index 1f0a0fd..d672e45 100644 --- a/src/SelbaWard.hpp +++ b/src/SelbaWard.hpp @@ -32,7 +32,6 @@ #include "SelbaWard/BitmapText.hpp" #include "SelbaWard/ConsoleScreen.hpp" -#include "SelbaWard/ConsoleScreenOld.hpp" #include "SelbaWard/Crosshair.hpp" #include "SelbaWard/ElasticSprite.hpp" #include "SelbaWard/GallerySprite.hpp" diff --git a/src/SelbaWard/ConsoleScreenOld.cpp b/src/SelbaWard/ConsoleScreenOld.cpp deleted file mode 100644 index ac74c24..0000000 --- a/src/SelbaWard/ConsoleScreenOld.cpp +++ /dev/null @@ -1,2344 +0,0 @@ -////////////////////////////////////////////////////////////////////////////// -// -// Selba Ward (https://github.com/Hapaxia/SelbaWard) -// -- -// -// Console Screen v1 -// -// Copyright(c) 2014-2023 M.J.Silk -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any damages -// arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions : -// -// 1. The origin of this software must not be misrepresented; you must not -// claim that you wrote the original software.If you use this software -// in a product, an acknowledgment in the product documentation would be -// appreciated but is not required. -// -// 2. Altered source versions must be plainly marked as such, and must not be -// misrepresented as being the original software. -// -// 3. This notice may not be removed or altered from any source distribution. -// -// M.J.Silk -// MJSilk2@gmail.com -// -////////////////////////////////////////////////////////////////////////////// - -#include "ConsoleScreenOld.hpp" - -#include -#include -#include - -namespace -{ - -const std::string exceptionPrefix{ "Console Screen (v1): " }; - -const sf::Color defaultColor{ sf::Color::White }; -const sf::Color defaultBackgroundColor{ sf::Color::Black }; -const sf::Color defaultCursorColor{ sf::Color::White }; -const sf::Color defaultNewPaletteColor{ sf::Color::Black }; -const double unBrightAttributeMultiplier{ 0.5 }; - -const selbaward::ConsoleScreenV1::Cell defaultCell{ 0u, sf::Color::White, sf::Color::Black, selbaward::ConsoleScreenV1::Stretch::None }; - -std::mt19937 randomGenerator; -const std::uniform_int_distribution randomDistribution(0u, 255u); -std::function getRandomByteValue; - -inline void randomSeed() -{ - std::random_device rd; - randomGenerator.seed(rd()); - getRandomByteValue = std::bind(randomDistribution, randomGenerator); -} - -inline unsigned char randomByte() -{ - return static_cast(getRandomByteValue()); -} - -inline float linearInterpolation(const float start, const float end, const float alpha) -{ - return start * (1 - alpha) + end * alpha; -} - -inline void makeColorUnBright(sf::Color& color) -{ - color.r = static_cast(unBrightAttributeMultiplier * color.r); - color.g = static_cast(unBrightAttributeMultiplier * color.g); - color.b = static_cast(unBrightAttributeMultiplier * color.b); -} - -inline void swapColors(sf::Color& a, sf::Color& b) -{ - sf::Color temp{ a }; - a = b; - b = temp; -} - -inline sf::Color sepiaColor(const float alpha) -{ - // scaling sepia from grey (1.351, 1.203, 0.937). clamp component to <= 1. scaled to 0-255 range: (344.505, 306.765, 238.935) - const unsigned int r{ static_cast(linearInterpolation(0.f, 344.505f, alpha)) }; - const unsigned int g{ static_cast(linearInterpolation(0.f, 306.765f, alpha)) }; - const unsigned int b{ static_cast(linearInterpolation(0.f, 238.935f, alpha)) }; - return sf::Color((r > 255 ? 255 : static_cast(r)), (g > 255 ? 255 : static_cast(g)), (b > 255 ? 255 : static_cast(b))); -} - -inline float relativeLuminance(const sf::Color& color) -{ - return 0.2126f * (color.r / 255.f) + 0.7152f * (color.g / 255.f) + 0.0722f * (color.b / 255.f); -} - -// contrasts RGB (black or white to contrast RGB's luminance) and keeps same alpha -inline sf::Color contrastedColor(const sf::Color& color) -{ - sf::Color result{ sf::Color::Black }; - if (relativeLuminance(color) < 0.33f) - result = sf::Color::White; - result.a = color.a; - return result; -} - -// inverts RGB and keeps same alpha -inline sf::Color invertedColor(const sf::Color& color) -{ - sf::Color result{ sf::Color::White - color }; - result.a = color.a; - return result; -} - -inline void addColorToPalette(std::vector& palette, const sf::Color& color) -{ - palette.emplace_back(color); -} - -void addPaletteDefault(std::vector& palette) -{ - addColorToPalette(palette, sf::Color::Black); - addColorToPalette(palette, sf::Color(0, 0, 128)); // dark blue - addColorToPalette(palette, sf::Color(128, 0, 0)); // dark red - addColorToPalette(palette, sf::Color(128, 0, 128)); // dark magenta - addColorToPalette(palette, sf::Color(0, 128, 0)); // dark green - addColorToPalette(palette, sf::Color(0, 128, 128)); // dark cyan - addColorToPalette(palette, sf::Color(128, 128, 0)); // dark yellow - addColorToPalette(palette, sf::Color(128, 128, 128)); // dark white/medium grey - addColorToPalette(palette, sf::Color(64, 64, 64)); // light black/dark grey - addColorToPalette(palette, sf::Color::Blue); - addColorToPalette(palette, sf::Color::Red); - addColorToPalette(palette, sf::Color::Magenta); - addColorToPalette(palette, sf::Color::Green); - addColorToPalette(palette, sf::Color::Cyan); - addColorToPalette(palette, sf::Color::Yellow); - addColorToPalette(palette, sf::Color::White); -} - -void addPalette2ColorBlackWhite(std::vector& palette) -{ - addColorToPalette(palette, sf::Color::Black); - addColorToPalette(palette, sf::Color::White); -} - -void addPalette2ColorWhiteBlack(std::vector& palette) -{ - addColorToPalette(palette, sf::Color::White); - addColorToPalette(palette, sf::Color::Black); -} - -void addPalette16ColorGreenscale(std::vector& palette) -{ - for (sf::Uint8 i{ 0 }; i < 16; ++i) - addColorToPalette(palette, sf::Color(0, i * 17, 0)); -} - -void addPalette16ColorGrayscale(std::vector& palette) -{ - for (sf::Uint8 i{ 0 }; i < 16; ++i) - addColorToPalette(palette, sf::Color(i * 17, i * 17, i * 17)); -} - -void addPalette16ColorSepia(std::vector& palette) -{ - const unsigned int numberOfColors{ 16 }; - for (unsigned int i{ 0 }; i < numberOfColors; ++i) - addColorToPalette(palette, sepiaColor(static_cast(i) / (numberOfColors - 1))); -} - -void addPalette16ColorCga(std::vector& palette) -{ - addColorToPalette(palette, sf::Color(0, 0, 0)); - addColorToPalette(palette, sf::Color(0, 0, 170)); - addColorToPalette(palette, sf::Color(170, 0, 0)); - addColorToPalette(palette, sf::Color(170, 0, 170)); - addColorToPalette(palette, sf::Color(0, 170, 0)); - addColorToPalette(palette, sf::Color(0, 170, 170)); - addColorToPalette(palette, sf::Color(170, 85, 0)); - addColorToPalette(palette, sf::Color(170, 170, 170)); - addColorToPalette(palette, sf::Color(85, 85, 85)); - addColorToPalette(palette, sf::Color(85, 85, 255)); - addColorToPalette(palette, sf::Color(255, 85, 0)); - addColorToPalette(palette, sf::Color(255, 85, 255)); - addColorToPalette(palette, sf::Color(85, 255, 85)); - addColorToPalette(palette, sf::Color(85, 255, 255)); - addColorToPalette(palette, sf::Color(255, 255, 85)); - addColorToPalette(palette, sf::Color(255, 255, 255)); -} - -void addPalette16ColorWindows(std::vector& palette) -{ - addColorToPalette(palette, sf::Color(0, 0, 0)); - addColorToPalette(palette, sf::Color(128, 0, 0)); - addColorToPalette(palette, sf::Color(0, 128, 0)); - addColorToPalette(palette, sf::Color(128, 128, 0)); - addColorToPalette(palette, sf::Color(0, 0, 128)); - addColorToPalette(palette, sf::Color(128, 0, 128)); - addColorToPalette(palette, sf::Color(0, 128, 128)); - addColorToPalette(palette, sf::Color(128, 128, 128)); - addColorToPalette(palette, sf::Color(192, 192, 192)); - addColorToPalette(palette, sf::Color(255, 0, 0)); - addColorToPalette(palette, sf::Color(0, 0, 255)); - addColorToPalette(palette, sf::Color(255, 255, 0)); - addColorToPalette(palette, sf::Color(0, 255, 0)); - addColorToPalette(palette, sf::Color(255, 0, 255)); - addColorToPalette(palette, sf::Color(0, 255, 255)); - addColorToPalette(palette, sf::Color(255, 255, 255)); -} - -void addPalette16ColorMac(std::vector& palette) -{ - addColorToPalette(palette, sf::Color(255, 255, 255)); // 0 - addColorToPalette(palette, sf::Color(255, 255, 0)); // 1 - addColorToPalette(palette, sf::Color(255, 102, 0)); // 2 - addColorToPalette(palette, sf::Color(221, 0, 0)); // 3 - addColorToPalette(palette, sf::Color(255, 0, 153)); // 4 - addColorToPalette(palette, sf::Color(51, 0, 153)); // 5 - addColorToPalette(palette, sf::Color(0, 0, 204)); // 6 - addColorToPalette(palette, sf::Color(0, 153, 255)); // 7 - addColorToPalette(palette, sf::Color(0, 170, 0)); // 8 - addColorToPalette(palette, sf::Color(0, 102, 0)); // 9 - addColorToPalette(palette, sf::Color(102, 51, 0)); // 10 - addColorToPalette(palette, sf::Color(153, 102, 51)); // 11 - addColorToPalette(palette, sf::Color(187, 187, 187)); // 12 - addColorToPalette(palette, sf::Color(136, 136, 136)); // 13 - addColorToPalette(palette, sf::Color(68, 68, 68)); // 14 - addColorToPalette(palette, sf::Color(0, 0, 0)); // 15 -} - -void addPalette16ColorZxSpectrum(std::vector& palette) -{ - addColorToPalette(palette, sf::Color(0, 0, 0)); - addColorToPalette(palette, sf::Color(0, 0, 128)); - addColorToPalette(palette, sf::Color(128, 0, 0)); - addColorToPalette(palette, sf::Color(128, 0, 128)); - addColorToPalette(palette, sf::Color(0, 128, 0)); - addColorToPalette(palette, sf::Color(0, 128, 128)); - addColorToPalette(palette, sf::Color(128, 128, 0)); - addColorToPalette(palette, sf::Color(128, 128, 128)); - addColorToPalette(palette, sf::Color(0, 0, 0)); - addColorToPalette(palette, sf::Color(0, 0, 255)); - addColorToPalette(palette, sf::Color(255, 0, 0)); - addColorToPalette(palette, sf::Color(255, 0, 255)); - addColorToPalette(palette, sf::Color(0, 255, 0)); - addColorToPalette(palette, sf::Color(0, 255, 255)); - addColorToPalette(palette, sf::Color(255, 255, 0)); - addColorToPalette(palette, sf::Color(255, 255, 255)); -} - -inline void addPalette16ColorCgaNonIbm(std::vector& palette) -{ - addPalette16ColorZxSpectrum(palette); -} - -void addPalette216ColorWebSafe(std::vector& palette) -{ - for (sf::Uint8 g{ 0 }; g < 6; ++g) - { - for (sf::Uint8 r{ 0 }; r < 6; ++r) - { - for (sf::Uint8 b{ 0 }; b < 6; ++b) - addColorToPalette(palette, sf::Color(r * 51, g * 51, b * 51)); - } - } -} - -void addPalette256ColorGreenscale(std::vector& palette) -{ - for (unsigned int i{ 0 }; i < 256; ++i) - addColorToPalette(palette, sf::Color(0, static_cast(i), 0)); -} - -void addPalette256ColorGrayscale(std::vector& palette) -{ - for (unsigned int i{ 0 }; i < 256; ++i) - addColorToPalette(palette, sf::Color(static_cast(i), static_cast(i), static_cast(i))); -} - -void addPalette256ColorSepia(std::vector& palette) -{ - const unsigned int numberOfColors{ 256 }; - for (unsigned int i{ 0 }; i < numberOfColors; ++i) - addColorToPalette(palette, sepiaColor(static_cast(i) / (numberOfColors - 1))); -} - -} // namespace - -namespace selbaward -{ - -ConsoleScreenV1::ConsoleScreenV1(const sf::Vector2u mode) - : m_do() - , m_cells() - , m_mode(mode) - , m_buffers() - , m_cursor({ 0, static_cast('_'), true, false, false }) - , m_colors({ defaultColor, defaultBackgroundColor, defaultCursorColor }) - , m_stretch() - , m_attributes() - , m_palette() - , m_characterMap() - , m_primitiveType{ sf::PrimitiveType::Quads } - , m_display() - , m_backgroundDisplay() - , m_size({ 100.f, 100.f }) - , m_texture{ nullptr } - , m_textureOffset({ 0u, 0u }) - , m_tileSize({ 8u, 8u }) - , m_numberOfTilesPerRow{ 8u } -{ - randomSeed(); - setMode(m_mode); - loadPalette(Palette::Default); -} - -void ConsoleScreenV1::setMode(sf::Vector2u mode) -{ - if (mode.x == 0 || mode.y == 0) - mode = { 0u, 0u }; - - m_mode = mode; - m_cells.resize(m_mode.x * m_mode.y, defaultCell); - m_display.resize(m_cells.size() * 4); - m_backgroundDisplay = m_display; - m_buffers.clear(); - - clear(); -} - -void ConsoleScreenV1::setTexture(const sf::Texture& texture) -{ - m_texture = &texture; -} - -void ConsoleScreenV1::setTexture() -{ - m_texture = nullptr; -} - -void ConsoleScreenV1::setSize(const sf::Vector2f size) -{ - m_size = size; - - if (m_do.updateAutomatically) - update(); -} - -void ConsoleScreenV1::setTextureOffset(const sf::Vector2u textureOffset) -{ - m_textureOffset = textureOffset; - - if (m_do.updateAutomatically) - update(); -} - -void ConsoleScreenV1::setTextureTileSize(const sf::Vector2u tileSize) -{ - m_tileSize = tileSize; - - if (m_do.updateAutomatically) - update(); -} - -void ConsoleScreenV1::setNumberOfTextureTilesPerRow(const unsigned int numberOfTextureTilesPerRow) -{ - if (numberOfTextureTilesPerRow < 1) - { - if (m_do.throwExceptions) - throw Exception(exceptionPrefix + "Cannot set number of texture tiles per row to zero."); - return; - } - - m_numberOfTilesPerRow = numberOfTextureTilesPerRow; - - if (m_do.updateAutomatically) - update(); -} - -void ConsoleScreenV1::setThrowExceptions(const bool throwExceptions) -{ - m_do.throwExceptions = throwExceptions; -} - -void ConsoleScreenV1::setUpdateAutomatically(const bool updateAutomatically) -{ - m_do.updateAutomatically = updateAutomatically; -} - -void ConsoleScreenV1::setShowCursor(const bool showCursor) -{ - m_cursor.visible = showCursor; - - if (m_do.updateAutomatically) - priv_updateCell(m_cursor.index); -} - -void ConsoleScreenV1::setInvertCursor(const bool invertCursor) -{ - m_cursor.inverse = invertCursor; - - if (m_do.updateAutomatically) - priv_updateCell(m_cursor.index); -} - -void ConsoleScreenV1::setUseCursorColor(const bool useCursorColor) -{ - m_cursor.useOwnColour = useCursorColor; - - if (m_do.updateAutomatically) - priv_updateCell(m_cursor.index); -} - -void ConsoleScreenV1::setShowBackground(const bool showBackground) -{ - m_do.showBackround = showBackground; -} - -void ConsoleScreenV1::setScrollAutomatically(const bool scrollAutomatically) -{ - m_do.scrollAutomatically = scrollAutomatically; -} - -void ConsoleScreenV1::setWrapOnManualScroll(const bool wrapOnManualScroll) -{ - m_do.wrapOnManualScroll = wrapOnManualScroll; -} - -void ConsoleScreenV1::update() -{ - if (m_display.size() != (m_mode.x * m_mode.y * 4)) - return; - if (m_backgroundDisplay.size() != m_display.size()) - m_backgroundDisplay.resize(m_display.size()); - - if (m_display.size() < 4) - { - if (m_do.throwExceptions) - throw Exception(exceptionPrefix + "Cannot update display.\nNo cells available."); - return; - } - - for (unsigned int i{ 0 }; i < m_cells.size(); ++i) - priv_updateCell(i); -} - -sf::Vector2f ConsoleScreenV1::getSize() const -{ - return m_size; -} - -sf::FloatRect ConsoleScreenV1::getLocalBounds() const -{ - return{ { 0.f, 0.f }, m_size }; -} - -sf::FloatRect ConsoleScreenV1::getGlobalBounds() const -{ - return getTransform().transformRect(getLocalBounds()); -} - -sf::Vector2u ConsoleScreenV1::getMode() const -{ - return m_mode; -} - -unsigned int ConsoleScreenV1::getNumberOfCells() const -{ - return static_cast(m_cells.size()); - //return m_mode.x * m_mode.y; -} - -sf::Vector2u ConsoleScreenV1::getNumberOfTilesInTexture2d() const -{ - return{ m_numberOfTilesPerRow, m_texture->getSize().y / m_tileSize.y }; -} - -unsigned int ConsoleScreenV1::getNumberOfTilesInTexture() const -{ - const sf::Vector2u numberOfTiles{ getNumberOfTilesInTexture2d() }; - return numberOfTiles.x * numberOfTiles.y; -} - -bool ConsoleScreenV1::getThrowExceptions() const -{ - return m_do.throwExceptions; -} - -bool ConsoleScreenV1::getUpdateAutomatically() const -{ - return m_do.updateAutomatically; -} - -bool ConsoleScreenV1::getShowCursor() const -{ - return m_cursor.visible; -} - -bool ConsoleScreenV1::getInvertCursor() const -{ - return m_cursor.inverse; -} - -bool ConsoleScreenV1::getUseCursorColor() const -{ - return m_cursor.useOwnColour; -} - -bool ConsoleScreenV1::getShowBackground() const -{ - return m_do.showBackround; -} - -bool ConsoleScreenV1::getScrollAutomatically() const -{ - return m_do.scrollAutomatically; -} - -bool ConsoleScreenV1::getWrapOnManualScroll() const -{ - return m_do.wrapOnManualScroll; -} - -void ConsoleScreenV1::setColor(const sf::Color color) -{ - m_colors.main = color; -} - -void ConsoleScreenV1::setColor(const int colorId) -{ - if (priv_isColorIdInPaletteRange(colorId)) - m_colors.main = m_palette[colorId]; - else - { - switch (colorId) - { - case Color::Invert: - m_colors.main = invertedColor(m_colors.background); - break; - case Color::Ignore: - case Color::Current: - default: - ; - } - } -} - -void ConsoleScreenV1::setBackgroundColor(const sf::Color backgroundColor) -{ - m_colors.background = backgroundColor; -} - -void ConsoleScreenV1::setBackgroundColor(const int colorId) -{ - if (priv_isColorIdInPaletteRange(colorId)) - m_colors.background = m_palette[colorId]; - else - { - switch (colorId) - { - case Color::Invert: - m_colors.background = invertedColor(m_colors.main); - break; - case Color::Ignore: - case Color::Current: - default: - ; - } - } -} - -void ConsoleScreenV1::setCursorColor(const sf::Color cursorColor) -{ - m_colors.cursor = cursorColor; -} - -void ConsoleScreenV1::setCursorColor(const int colorId) -{ - if (priv_isColorIdInPaletteRange(colorId)) - m_colors.cursor = m_palette[colorId]; - else - { - switch (colorId) - { - case Color::Invert: - m_colors.cursor = invertedColor(m_colors.background); - break; - case Color::Current: - m_colors.cursor = m_colors.main; - break; - case Color::Ignore: - default: - ; - } - } -} - -void ConsoleScreenV1::setColors(const sf::Color color, const sf::Color backgroundColor) -{ - setColor(color); - setBackgroundColor(backgroundColor); -} - -void ConsoleScreenV1::setColors(const int colorId, const int backgroundColorId) -{ - setColor(colorId); - setBackgroundColor(backgroundColorId); -} - -void ConsoleScreenV1::setColors(const sf::Color color, const sf::Color backgroundColor, const sf::Color cursorColor) -{ - setColors(color, backgroundColor); - setCursorColor(cursorColor); -} - -void ConsoleScreenV1::setColors(const int colorId, const int backgroundColorId, const int cursorColorId) -{ - setColors(colorId, backgroundColorId); - setCursorColor(cursorColorId); -} - -sf::Color ConsoleScreenV1::getColor() const -{ - return m_colors.main; -} - -sf::Color ConsoleScreenV1::getBackgroundColor() const -{ - return m_colors.background; -} - -sf::Color ConsoleScreenV1::getCursorColor() const -{ - return m_colors.cursor; -} - -void ConsoleScreenV1::setStretch(const Stretch stretch) -{ - m_stretch = stretch; -} - -ConsoleScreenV1::Stretch ConsoleScreenV1::getStretch() const -{ - return m_stretch; -} - -void ConsoleScreenV1::setAttributes(const CellAttributes attributes) -{ - m_attributes = attributes; -} - -ConsoleScreenV1::CellAttributes ConsoleScreenV1::getAttributes() const -{ - return m_attributes; -} - -void ConsoleScreenV1::setAttribute(const bool attributeValue, const Attribute attribute) -{ - priv_chooseAttribute(m_attributes, attribute) = attributeValue; -} - -bool ConsoleScreenV1::getAttribute(const Attribute attribute) -{ - return priv_chooseAttribute(m_attributes, attribute); -} - -void ConsoleScreenV1::cursorLeft(const unsigned int distance) -{ - for (unsigned int i{ 0 }; i < distance; ++i) - priv_moveCursorLeft(); -} - -void ConsoleScreenV1::cursorRight(const unsigned int distance) -{ - for (unsigned int i{ 0 }; i < distance; ++i) - priv_moveCursorRight(); -} - -void ConsoleScreenV1::cursorUp(const unsigned int distance) -{ - for (unsigned int i{ 0 }; i < distance; ++i) - priv_moveCursorUp(); -} - -void ConsoleScreenV1::cursorDown(const unsigned int distance) -{ - for (unsigned int i{ 0 }; i < distance; ++i) - priv_moveCursorDown(); -} - -void ConsoleScreenV1::moveCursor(const sf::Vector2i offset) -{ - if (offset.x < 0) - cursorLeft(-offset.x); - else - cursorRight(offset.x); - if (offset.y < 0) - cursorUp(-offset.y); - else - cursorDown(offset.y); -} - -void ConsoleScreenV1::setCursor(const sf::Vector2u location) -{ - if (!priv_isCellLocationInRange(location)) - { - if (m_do.throwExceptions) - throw Exception(exceptionPrefix + "Cannot set cursor.\nLocation (" + std::to_string(location.x) + ", " + std::to_string(location.y) + ") out of range."); - return; - } - - priv_setCursorIndex(priv_cellIndex(location)); -} - -sf::Vector2u ConsoleScreenV1::getCursor() const -{ - return priv_cellLocation(m_cursor.index); -} - -void ConsoleScreenV1::cursorHome() -{ - priv_setCursorIndex(0u); -} - -void ConsoleScreenV1::cursorHomeLine() -{ - priv_moveCursorToBeginningOfLine(); -} - -void ConsoleScreenV1::cursorEnd() -{ - priv_setCursorIndex(static_cast(m_cells.size()) - 1u); -} - -void ConsoleScreenV1::cursorEndLine() -{ - priv_setCursorIndex(m_cursor.index - m_cursor.index % m_mode.x + m_mode.x - 1); -} - -void ConsoleScreenV1::cursorTab(const unsigned int tabSize) -{ - const unsigned int targetDistance{ tabSize - (m_cursor.index % tabSize) }; - cursorRight(targetDistance); -} - -void ConsoleScreenV1::cursorTabReverse(const unsigned int tabSize) -{ - if (m_cursor.index == 0) - return; - - const unsigned int targetDistance{ (m_cursor.index - 1) % tabSize + 1 }; - cursorLeft(targetDistance); -} - -void ConsoleScreenV1::cursorNextline() -{ - priv_moveCursorDown(); - priv_moveCursorToBeginningOfLine(); -} - -void ConsoleScreenV1::cursorBackspace() -{ - priv_moveCursorLeft(); - priv_clearCell(m_cursor.index, true, true); -} - -void ConsoleScreenV1::setCursor(const int cellValue) -{ - m_cursor.value = cellValue; - - if (m_do.updateAutomatically) - priv_updateCell(m_cursor.index); -} - -void ConsoleScreenV1::setCursor(const char cellCharacter, bool mapCharacter) -{ - m_cursor.value = (mapCharacter && getIsMappedCharacter(cellCharacter)) ? getMappedCharacter(cellCharacter) : cellCharacter; - - if (m_do.updateAutomatically) - priv_updateCell(m_cursor.index); -} - -void ConsoleScreenV1::print(const char character, const int colorId, const int backgroundColorId) -{ - if (!priv_isCursorInRange()) - return; - - print(character, m_cells[m_cursor.index].attributes, colorId, backgroundColorId); -} - -void ConsoleScreenV1::print(const char character, const Stretch& stretch, const int colorId, const int backgroundColorId) -{ - if (!priv_isCursorInRange()) - return; - - const unsigned int currentIndex{ m_cursor.index }; - const unsigned int cellValue{ priv_getCellValueFromCharacter(character) }; - if (colorId == Color::Invert || colorId == Color::Contrast) - { - poke(currentIndex, Cell{ cellValue, sf::Color::Black, priv_backgroundColorFromColorIdAtIndex(currentIndex, backgroundColorId), stretch }); - poke(currentIndex, priv_colorFromColorIdAtIndex(currentIndex, colorId)); - } - else - poke(currentIndex, Cell{ cellValue, priv_colorFromColorIdAtIndex(currentIndex, colorId), priv_backgroundColorFromColorIdAtIndex(currentIndex, backgroundColorId), stretch }); - priv_moveCursorRight(); - - if (m_do.updateAutomatically) - { - priv_updateCell(currentIndex); - priv_updateCell(m_cursor.index); - } -} - - -void ConsoleScreenV1::print(const char character, const CellAttributes& attributes, const int colorId, const int backgroundColorId) -{ - if (!priv_isCursorInRange()) - return; - - const unsigned int currentIndex{ m_cursor.index }; - const unsigned int cellValue{ priv_getCellValueFromCharacter(character) }; - const Cell existingCell = peek(currentIndex); - if (colorId == Color::Invert || colorId == Color::Contrast) - { - poke(currentIndex, Cell{ cellValue, sf::Color::Black, priv_backgroundColorFromColorIdAtIndex(currentIndex, backgroundColorId), existingCell.stretch, attributes }); - poke(currentIndex, priv_colorFromColorIdAtIndex(currentIndex, colorId)); - } - else - poke(currentIndex, Cell{ cellValue, priv_colorFromColorIdAtIndex(currentIndex, colorId), priv_backgroundColorFromColorIdAtIndex(currentIndex, backgroundColorId), existingCell.stretch, attributes }); - priv_moveCursorRight(); - - if (m_do.updateAutomatically) - { - priv_updateCell(currentIndex); - priv_updateCell(m_cursor.index); - } -} - -void ConsoleScreenV1::print(const std::string& string, const int colorId, const int backgroundColorId) -{ - for (auto& character : string) - print(character, colorId, backgroundColorId); - - if (!priv_isCursorInRange()) - priv_setCursorIndex(static_cast(m_cells.size()) - 1u); -} - -void ConsoleScreenV1::print(const std::string& string, const Stretch& stretch, const int colorId, const int backgroundColorId) -{ - for (auto& character : string) - print(character, stretch, colorId, backgroundColorId); - - if (!priv_isCursorInRange()) - priv_setCursorIndex(static_cast(m_cells.size()) - 1u); -} - -void ConsoleScreenV1::print(const std::string& string, const CellAttributes& attributes, const int colorId, const int backgroundColorId) -{ - for (auto& character : string) - print(character, attributes, colorId, backgroundColorId); - - if (!priv_isCursorInRange()) - priv_setCursorIndex(static_cast(m_cells.size()) - 1u); -} - -void ConsoleScreenV1::printLine(const std::string& string, const int colorId, const int backgroundColorId) -{ - print(string, colorId, backgroundColorId); - cursorNextline(); -} - -void ConsoleScreenV1::clearCellAt(const sf::Vector2u location) -{ - if (!priv_isCellLocationInRange(location)) - { - if (m_do.throwExceptions) - throw Exception(exceptionPrefix + "Cannot clear cell.\nLocation (" + std::to_string(location.x) + ", " + std::to_string(location.y) + ") out of range."); - return; - } - - priv_clearCell(priv_cellIndex(location), m_colors.main, m_colors.background); - - if (m_do.updateAutomatically) - priv_updateCell(priv_cellIndex(location)); -} - -void ConsoleScreenV1::setCellAt(const sf::Vector2u location, const Cell& cell) -{ - if (!priv_isCellLocationInRange(location)) - { - if (m_do.throwExceptions) - throw Exception(exceptionPrefix + "Cannot set cell.\nLocation (" + std::to_string(location.x) + ", " + std::to_string(location.y) + ") out of range."); - return; - } - - m_cells[priv_cellIndex(location)] = cell; - - if (m_do.updateAutomatically) - priv_updateCell(priv_cellIndex(location)); -} - -void ConsoleScreenV1::printAt(const sf::Vector2u location, const std::string& string, const sf::Color color, const sf::Color backgroundColor) -{ - if (string.size() == 0) - { - if (m_do.throwExceptions) - throw Exception(exceptionPrefix + "Cannot print.\nString does not exist."); - return; - } - - for (unsigned int i{ 0 }; i < string.size(); ++i) - printAt({ location.x + i, location.y }, string[i], color, backgroundColor); // print single character -} - -void ConsoleScreenV1::printAt(const sf::Vector2u location, const std::string& string, const sf::Color color, const int backgroundColorId) -{ - if (string.size() == 0) - { - if (m_do.throwExceptions) - throw Exception(exceptionPrefix + "Cannot print.\nString does not exist."); - return; - } - - for (unsigned int i{ 0 }; i < string.size(); ++i) - printAt({ location.x + i, location.y }, string[i], color, backgroundColorId); // print single character -} - -void ConsoleScreenV1::printAt(const sf::Vector2u location, const std::string& string, const int colorId, const sf::Color backgroundColor) -{ - if (string.size() == 0) - { - if (m_do.throwExceptions) - throw Exception(exceptionPrefix + "Cannot print.\nString does not exist."); - return; - } - - for (unsigned int i{ 0 }; i < string.size(); ++i) - printAt({ location.x + i, location.y }, string[i], colorId, backgroundColor); // print single character -} - -void ConsoleScreenV1::printAt(const sf::Vector2u location, const std::string& string, const int colorId, const int backgroundColorId) -{ - if (string.size() == 0) - { - if (m_do.throwExceptions) - throw Exception(exceptionPrefix + "Cannot print.\nString does not exist."); - return; - } - - for (unsigned int i{ 0 }; i < string.size(); ++i) - printAt({ location.x + i, location.y }, string[i], colorId, backgroundColorId); // print single character -} - -void ConsoleScreenV1::printAt(const sf::Vector2u location, const char character, const sf::Color color, const sf::Color backgroundColor) -{ - unsigned int index{ priv_getPrintIndex(location) }; - Cell cell = defaultCell; - cell.value = priv_getCellValueFromCharacter(character); - cell.color = color; - cell.backgroundColor = backgroundColor; - m_cells[index] = cell; - - if (m_do.updateAutomatically) - priv_updateCell(index); -} - -void ConsoleScreenV1::printAt(const sf::Vector2u location, const char character, const sf::Color color, const int backgroundColorId) -{ - const unsigned int currentIndex{ priv_getPrintIndex(location) }; - printAt(location, character, color, priv_backgroundColorFromColorIdAtIndex(currentIndex, backgroundColorId)); -} - -void ConsoleScreenV1::printAt(const sf::Vector2u location, const char character, const int colorId, const sf::Color backgroundColor) -{ - const unsigned int currentIndex{ priv_getPrintIndex(location) }; - printAt(location, character, priv_colorFromColorIdAtIndex(currentIndex, colorId), backgroundColor); -} - -void ConsoleScreenV1::printAt(const sf::Vector2u location, const char character, const int colorId, const int backgroundColorId) -{ - const unsigned int currentIndex{ priv_getPrintIndex(location) }; - printAt(location, character, priv_colorFromColorIdAtIndex(currentIndex, colorId), priv_backgroundColorFromColorIdAtIndex(currentIndex, backgroundColorId)); -} - -void ConsoleScreenV1::printStretchedAt(const sf::Vector2u location, const std::string& string, const Stretch& stretchAttribute, const sf::Color color, const sf::Color backgroundColor) -{ - if (string.size() == 0) - { - if (m_do.throwExceptions) - throw Exception(exceptionPrefix + "Cannot print.\nString does not exist."); - return; - } - - for (unsigned int i{ 0 }; i < string.size(); ++i) - printStretchedAt({ location.x + i, location.y }, string[i], stretchAttribute, color, backgroundColor); // print single character -} - -void ConsoleScreenV1::printStretchedAt(const sf::Vector2u location, const std::string& string, const Stretch& stretchAttribute, const int colorId, const int backgroundColorId) -{ - if (string.size() == 0) - { - if (m_do.throwExceptions) - throw Exception(exceptionPrefix + "Cannot print.\nString does not exist."); - return; - } - - for (unsigned int i{ 0 }; i < string.size(); ++i) - printStretchedAt({ location.x + i, location.y }, string[i], stretchAttribute, colorId, backgroundColorId); // print single character -} - -void ConsoleScreenV1::printStretchedAt(sf::Vector2u location, const char character, const Stretch& stretchAttribute, const sf::Color color, const sf::Color backgroundColor) -{ - switch (stretchAttribute) - { - case Stretch::Bottom: - if (location.y < 1) - return; - --location.y; - case Stretch::Top: - if (location.y > m_mode.y - 2) - return; - break; - case Stretch::None: - default: - return; - } - unsigned int topIndex{ priv_getPrintIndex(location) }; - unsigned int bottomIndex{ topIndex + m_mode.x }; - const unsigned int cellValue{ priv_getCellValueFromCharacter(character) }; - - m_cells[topIndex] = defaultCell; - m_cells[topIndex].value = cellValue; - m_cells[topIndex].color = color; - m_cells[topIndex].backgroundColor = backgroundColor; - m_cells[topIndex].stretch = Stretch::Top; - m_cells[bottomIndex] = defaultCell; - m_cells[bottomIndex].value = cellValue; - m_cells[bottomIndex].color = color; - m_cells[bottomIndex].backgroundColor = backgroundColor; - m_cells[bottomIndex].stretch = Stretch::Bottom; - - if (m_do.updateAutomatically) - { - priv_updateCell(topIndex); - priv_updateCell(bottomIndex); - } -} - -void ConsoleScreenV1::printStretchedAt(sf::Vector2u location, const char character, const Stretch& stretchAttribute, const int colorId, const int backgroundColorId) -{ - switch (stretchAttribute) - { - case Stretch::Bottom: - if (location.y < 1) - return; - --location.y; - case Stretch::Top: - if (location.y > m_mode.y - 2) - return; - break; - case Stretch::None: - default: - return; - } - unsigned int topIndex{ priv_getPrintIndex(location) }; - unsigned int bottomIndex{ topIndex + m_mode.x }; - const unsigned int cellValue{ priv_getCellValueFromCharacter(character) }; - - m_cells[topIndex].value = cellValue; - m_cells[topIndex].color = priv_colorFromColorIdAtIndex(topIndex, colorId); - m_cells[topIndex].backgroundColor = priv_backgroundColorFromColorIdAtIndex(topIndex, backgroundColorId); - m_cells[topIndex].stretch = Stretch::Top; - m_cells[topIndex].attributes = CellAttributes(); - m_cells[bottomIndex].value = cellValue; - m_cells[bottomIndex].color = priv_colorFromColorIdAtIndex(bottomIndex, colorId); - m_cells[bottomIndex].backgroundColor = priv_backgroundColorFromColorIdAtIndex(bottomIndex, backgroundColorId); - m_cells[bottomIndex].stretch = Stretch::Bottom; - m_cells[bottomIndex].attributes = CellAttributes(); - - if (m_do.updateAutomatically) - { - priv_updateCell(topIndex); - priv_updateCell(bottomIndex); - } -} - -void ConsoleScreenV1::paintAt(const sf::Vector2u location, const unsigned int length, const sf::Color color, const sf::Color backgroundColor) -{ - for (unsigned int i{ 0 }; i < length; ++i) - priv_paintCell(priv_getPrintIndex({ location.x + i, location.y }), color, backgroundColor); -} - -void ConsoleScreenV1::paintAt(const sf::Vector2u location, const unsigned int length, const sf::Color color, const int backgroundColorId) -{ - for (unsigned int i{ 0 }; i < length; ++i) - { - const unsigned int index{ priv_getPrintIndex({ location.x + i, location.y }) }; - priv_paintCell(index, color, priv_backgroundColorFromColorIdAtIndex(index, backgroundColorId)); - } -} - -void ConsoleScreenV1::paintAt(const sf::Vector2u location, const unsigned int length, const int colorId, const sf::Color backgroundColor) -{ - for (unsigned int i{ 0 }; i < length; ++i) - { - const unsigned int index{ priv_getPrintIndex({ location.x + i, location.y }) }; - priv_paintCell(index, priv_colorFromColorIdAtIndex(index, colorId), backgroundColor); - } -} - -void ConsoleScreenV1::paintAt(const sf::Vector2u location, const unsigned int length, const int colorId, const int backgroundColorId) -{ - for (unsigned int i{ 0 }; i < length; ++i) - { - const unsigned int index{ priv_getPrintIndex({ location.x + i, location.y }) }; - priv_paintCell(index, priv_colorFromColorIdAtIndex(index, colorId), priv_backgroundColorFromColorIdAtIndex(index, backgroundColorId)); - } -} - -void ConsoleScreenV1::paintAttributeAt(const sf::Vector2u location, const unsigned int length, const bool attributeValue, const Attribute attribute) -{ - for (unsigned int i{ 0 }; i < length; ++i) - { - unsigned int index{ priv_getPrintIndex({ location.x + i, location.y }) }; - priv_chooseAttribute(m_cells[index].attributes, attribute) = attributeValue; - - if (m_do.updateAutomatically) - priv_updateCell(index); - } -} - -std::string ConsoleScreenV1::read(const unsigned int length, const bool unmapCharacters) -{ - std::string string; - - for (unsigned int i{ 0u }; i < length; ++i) - { - if (!priv_isCursorInRange()) - break;; - - const unsigned int currentIndex{ m_cursor.index }; - string += (unmapCharacters ? priv_getCharacterFromCellValue(m_cells[currentIndex].value) : static_cast(m_cells[currentIndex].value)); - priv_moveCursorRight(); - } - - return string; -} - -std::string ConsoleScreenV1::readAt(const sf::Vector2u location, const unsigned int length, const bool unmapCharacters) const -{ - if (!priv_isCellLocationInRange(location)) - { - if (m_do.throwExceptions) - throw Exception(exceptionPrefix + "Cannot read.\nLocation (" + std::to_string(location.x) + ", " + std::to_string(location.y) + ") out of range."); - return ""; - } - - std::string string; - unsigned int index{ priv_getPrintIndex(location) }; - - for (unsigned int i{ 0u }; i < length; ++i) - { - string += (unmapCharacters ? priv_getCharacterFromCellValue(m_cells[index].value) : static_cast(m_cells[index].value)); - ++index; - if (!priv_isCellIndexInRange(index)) - break; - } - - return string; -} - -void ConsoleScreenV1::setValueAt(const sf::Vector2u location, const unsigned int value) -{ - if (!priv_isCellLocationInRange(location)) - { - if (m_do.throwExceptions) - throw Exception(exceptionPrefix + "Cannot set value.\nLocation (" + std::to_string(location.x) + ", " + std::to_string(location.y) + ") out of range."); - return; - } - - m_cells[priv_cellIndex(location)].value = value; - - if (m_do.updateAutomatically) - priv_updateCell(priv_cellIndex(location)); -} - -void ConsoleScreenV1::setColorsAt(const sf::Vector2u location, const sf::Color color, const sf::Color backgroundColor) -{ - if (!priv_isCellLocationInRange(location)) - { - if (m_do.throwExceptions) - throw Exception(exceptionPrefix + "Cannot set colors.\nLocation (" + std::to_string(location.x) + ", " + std::to_string(location.y) + ") out of range."); - return; - } - - const unsigned int index{ priv_cellIndex(location) }; - m_cells[index].color = color; - m_cells[index].backgroundColor = backgroundColor; - - if (m_do.updateAutomatically) - priv_updateCell(index); - -} - -void ConsoleScreenV1::setColorsAt(const sf::Vector2u location, const int colorId, const int backgroundColorId) -{ - if (!priv_isCellLocationInRange(location)) - { - if (m_do.throwExceptions) - throw Exception(exceptionPrefix + "Cannot set colors.\nLocation (" + std::to_string(location.x) + ", " + std::to_string(location.y) + ") out of range."); - return; - } - - const unsigned int index{ priv_cellIndex(location) }; - m_cells[index].color = priv_colorFromColorIdAtIndex(index, colorId); - m_cells[index].backgroundColor = priv_backgroundColorFromColorIdAtIndex(index, backgroundColorId); - - if (m_do.updateAutomatically) - priv_updateCell(index); -} - -void ConsoleScreenV1::setColorAt(const sf::Vector2u location, const sf::Color color) -{ - if (!priv_isCellLocationInRange(location)) - { - if (m_do.throwExceptions) - throw Exception(exceptionPrefix + "Cannot set color.\nLocation (" + std::to_string(location.x) + ", " + std::to_string(location.y) + ") out of range."); - return; - } - - const unsigned int index{ priv_cellIndex(location) }; - m_cells[index].color = color; - - if (m_do.updateAutomatically) - priv_updateCell(index); -} - -void ConsoleScreenV1::setColorAt(const sf::Vector2u location, const int colorId) -{ - if (!priv_isCellLocationInRange(location)) - { - if (m_do.throwExceptions) - throw Exception(exceptionPrefix + "Cannot set color.\nLocation (" + std::to_string(location.x) + ", " + std::to_string(location.y) + ") out of range."); - return; - } - - const unsigned int index{ priv_cellIndex(location) }; - m_cells[index].color = priv_colorFromColorIdAtIndex(index, colorId); - - if (m_do.updateAutomatically) - priv_updateCell(index); -} - -void ConsoleScreenV1::setBackgroundColorAt(const sf::Vector2u location, const sf::Color backgroundColor) -{ - if (!priv_isCellLocationInRange(location)) - { - if (m_do.throwExceptions) - throw Exception(exceptionPrefix + "Cannot set background colors.\nLocation (" + std::to_string(location.x) + ", " + std::to_string(location.y) + ") out of range."); - return; - } - - const unsigned int index{ priv_cellIndex(location) }; - m_cells[index].backgroundColor = backgroundColor; - - if (m_do.updateAutomatically) - priv_updateCell(index); -} - -void ConsoleScreenV1::setBackgroundColorAt(const sf::Vector2u location, const int backgroundColorId) -{ - if (!priv_isCellLocationInRange(location)) - { - if (m_do.throwExceptions) - throw Exception(exceptionPrefix + "Cannot set background colors.\nLocation (" + std::to_string(location.x) + ", " + std::to_string(location.y) + ") out of range."); - return; - } - - const unsigned int index{ priv_cellIndex(location) }; - m_cells[index].backgroundColor = priv_backgroundColorFromColorIdAtIndex(index, backgroundColorId); - - if (m_do.updateAutomatically) - priv_updateCell(index); -} - -void ConsoleScreenV1::setStretchAt(const sf::Vector2u location, const Stretch& stretch) -{ - if (!priv_isCellLocationInRange(location)) - { - if (m_do.throwExceptions) - throw Exception(exceptionPrefix + "Cannot set stretch.\nLocation (" + std::to_string(location.x) + ", " + std::to_string(location.y) + ") out of range."); - return; - } - - m_cells[priv_cellIndex(location)].stretch = stretch; - - if (m_do.updateAutomatically) - priv_updateCell(priv_cellIndex(location)); -} - -void ConsoleScreenV1::setAttributesAt(const sf::Vector2u location, const CellAttributes& attributes) -{ - if (!priv_isCellLocationInRange(location)) - { - if (m_do.throwExceptions) - throw Exception(exceptionPrefix + "Cannot set attributes.\nLocation (" + std::to_string(location.x) + ", " + std::to_string(location.y) + ") out of range."); - return; - } - - m_cells[priv_cellIndex(location)].attributes = attributes; - - if (m_do.updateAutomatically) - priv_updateCell(priv_cellIndex(location)); -} - -void ConsoleScreenV1::setAttributeAt(const sf::Vector2u location, const bool attributeValue, const Attribute attribute) -{ - if (!priv_isCellLocationInRange(location)) - { - if (m_do.throwExceptions) - throw Exception(exceptionPrefix + "Cannot set attribute.\nLocation (" + std::to_string(location.x) + ", " + std::to_string(location.y) + ") out of range."); - return; - } - - priv_chooseAttribute(m_cells[priv_cellIndex(location)].attributes, attribute) = attributeValue; - - if (m_do.updateAutomatically) - priv_updateCell(priv_cellIndex(location)); -} - -ConsoleScreenV1::Cell ConsoleScreenV1::getCellAt(const sf::Vector2u location) const -{ - if (!priv_isCellLocationInRange(location)) - { - if (m_do.throwExceptions) - throw Exception(exceptionPrefix + "Cannot get cell.\nLocation (" + std::to_string(location.x) + ", " + std::to_string(location.y) + ") out of range."); - return Cell(); - } - - return m_cells[priv_cellIndex(location)]; -} - -unsigned int ConsoleScreenV1::getValueAt(const sf::Vector2u location) const -{ - if (!priv_isCellLocationInRange(location)) - { - if (m_do.throwExceptions) - throw Exception(exceptionPrefix + "Cannot get cell value.\nLocation (" + std::to_string(location.x) + ", " + std::to_string(location.y) + ") out of range."); - return 0u; - } - - return m_cells[priv_cellIndex(location)].value; -} - -sf::Color ConsoleScreenV1::getColorAt(const sf::Vector2u location) const -{ - if (!priv_isCellLocationInRange(location)) - { - if (m_do.throwExceptions) - throw Exception(exceptionPrefix + "Cannot get cell color.\nLocation (" + std::to_string(location.x) + ", " + std::to_string(location.y) + ") out of range."); - return sf::Color::Transparent; - } - - return m_cells[priv_cellIndex(location)].color; -} - -sf::Color ConsoleScreenV1::getBackgroundColorAt(const sf::Vector2u location) const -{ - if (!priv_isCellLocationInRange(location)) - { - if (m_do.throwExceptions) - throw Exception(exceptionPrefix + "Cannot get cell background color.\nLocation (" + std::to_string(location.x) + ", " + std::to_string(location.y) + ") out of range."); - return sf::Color::Transparent; - } - - return m_cells[priv_cellIndex(location)].backgroundColor; -} - -ConsoleScreenV1::Stretch ConsoleScreenV1::getStretchAt(const sf::Vector2u location) const -{ - if (!priv_isCellLocationInRange(location)) - { - if (m_do.throwExceptions) - throw Exception(exceptionPrefix + "Cannot get cell stretch.\nLocation (" + std::to_string(location.x) + ", " + std::to_string(location.y) + ") out of range."); - return Stretch::None; - } - - return m_cells[priv_cellIndex(location)].stretch; -} - -ConsoleScreenV1::CellAttributes ConsoleScreenV1::getAttributesAt(const sf::Vector2u location) const -{ - if (!priv_isCellLocationInRange(location)) - { - if (m_do.throwExceptions) - throw Exception(exceptionPrefix + "Cannot get cell attributes.\nLocation (" + std::to_string(location.x) + ", " + std::to_string(location.y) + ") out of range."); - return CellAttributes(); - } - - return m_cells[priv_cellIndex(location)].attributes; -} - -bool ConsoleScreenV1::getAttributeAt(const sf::Vector2u location, const Attribute attribute) -{ - if (!priv_isCellLocationInRange(location)) - { - if (m_do.throwExceptions) - throw Exception(exceptionPrefix + "Cannot get cell attribute.\nLocation (" + std::to_string(location.x) + ", " + std::to_string(location.y) + ") out of range."); - return false; - } - - return priv_chooseAttribute(m_cells[priv_cellIndex(location)].attributes, attribute); -} - -void ConsoleScreenV1::scrollUp(const unsigned int amount) -{ - if (m_mode.y == 0 || amount == 0) - return; - - std::vector topRow(m_mode.x); - for (unsigned int repeat{ 0 }; repeat < amount; ++repeat) // lazy way of scrolling multiple times - loop scrolling (entirely by 1 each time) - { - for (unsigned int y{ 0 }; y < m_mode.y; ++y) - { - for (unsigned int x{ 0 }; x < m_mode.x; ++x) - { - if (m_do.wrapOnManualScroll && y == 0) - topRow[x] = m_cells[x]; - if (y < m_mode.y - 1) - m_cells[priv_cellIndex({ x, y })] = m_cells[priv_cellIndex({ x, y + 1 })]; - else if (m_do.wrapOnManualScroll) - m_cells[priv_cellIndex({ x, y })] = topRow[x]; - else - priv_clearCell(priv_cellIndex({ x, y }), true, true); - } - } - } - - if (m_do.updateAutomatically) - update(); -} - -void ConsoleScreenV1::scrollDown(const unsigned int amount) -{ - if (m_mode.y == 0 || amount == 0) - return; - - std::vector bottomRow(m_mode.x); - for (unsigned int repeat{ 0 }; repeat < amount; ++repeat) // lazy way of scrolling multiple times - loop scrolling (entirely by 1 each time) - { - for (unsigned int y{ 0 }; y < m_mode.y; ++y) - { - for (unsigned int x{ 0 }; x < m_mode.x; ++x) - { - const unsigned cellY{ m_mode.y - y - 1 }; - if (m_do.wrapOnManualScroll && y == 0) - bottomRow[x] = m_cells[priv_cellIndex({ x, cellY })]; - if (cellY > 0) - m_cells[priv_cellIndex({ x, cellY })] = m_cells[priv_cellIndex({ x, cellY - 1 })]; - else if (m_do.wrapOnManualScroll) - m_cells[priv_cellIndex({ x, cellY })] = bottomRow[x]; - else - priv_clearCell(priv_cellIndex({ x, cellY }), true, true); - } - } - } - - if (m_do.updateAutomatically) - update(); -} - -void ConsoleScreenV1::scrollLeft(const unsigned int amount) -{ - if (m_mode.x == 0 || amount == 0) - return; - - Cell leftCell; - for (unsigned int repeat{ 0 }; repeat < amount; ++repeat) // lazy way of scrolling multiple times - loop scrolling (entirely by 1 each time) - { - for (unsigned int cell{ 0 }; cell < m_cells.size(); ++cell) - { - if (cell % m_mode.x == 0) - leftCell = m_cells[cell]; - if (cell % m_mode.x == m_mode.x - 1) - { - if (m_do.wrapOnManualScroll) - m_cells[cell] = leftCell; - else - priv_clearCell(cell, true, true); - } - else - m_cells[cell] = m_cells[cell + 1]; - } - } - - if (m_do.updateAutomatically) - update(); -} - -void ConsoleScreenV1::scrollRight(const unsigned int amount) -{ - if (m_mode.x == 0 || amount == 0) - return; - - Cell rightCell; - for (unsigned int repeat{ 0 }; repeat < amount; ++repeat) // lazy way of scrolling multiple times - loop scrolling (entirely by 1 each time) - { - for (unsigned int i{ 0 }; i < m_cells.size(); ++i) - { - const unsigned int cell{ static_cast(m_cells.size()) - i - 1 }; - if (i % m_mode.x == 0) - rightCell = m_cells[cell]; - if (cell % m_mode.x == 0) - { - if (m_do.wrapOnManualScroll) - m_cells[cell] = rightCell; - else - priv_clearCell(cell, true, true); - } - else - m_cells[cell] = m_cells[cell - 1]; - } - } - - if (m_do.updateAutomatically) - update(); -} - -void ConsoleScreenV1::clear(const int backgroundColorId) -{ - if (priv_isColorIdInPaletteRange(backgroundColorId)) - clear(m_palette[backgroundColorId]); - else - { - switch (backgroundColorId) - { - case Color::Contrast: - clear(contrastedColor(m_colors.main)); - break; - case Color::Invert: - clear(invertedColor(m_colors.main)); - break; - case Color::Ignore: - case Color::Current: - default: - clear(m_colors.background); - } - } -} - -void ConsoleScreenV1::clear(const sf::Color backgroundColor) -{ - if (m_cells.size() == 0) - { - if (m_do.throwExceptions) - throw Exception(exceptionPrefix + "Cannot clear cell.\nNo cells exist."); - return; - } - - for (unsigned int i{ 0 }; i < m_cells.size(); ++i) - priv_clearCell(i, m_colors.main, backgroundColor); - cursorHome(); - - if (m_do.updateAutomatically) - update(); -} - -void ConsoleScreenV1::crash() -{ - for (auto& cell : m_cells) - { - cell = { randomByte(), sf::Color(randomByte(), randomByte(), randomByte()), sf::Color(randomByte(), randomByte(), randomByte()) }; - } - cursorEnd(); - - if (m_do.updateAutomatically) - update(); -} - -void ConsoleScreenV1::loadPalette(const Palette palette) -{ - m_palette.clear(); - switch (palette) - { - case Palette::Colors16Cga: - addPalette16ColorCga(m_palette); - break; - case Palette::Colors16CgaNonIbm: - addPalette16ColorCgaNonIbm(m_palette); - break; - case Palette::Colors16Greenscale: - addPalette16ColorGreenscale(m_palette); - break; - case Palette::Colors16Grayscale: - addPalette16ColorGrayscale(m_palette); - break; - case Palette::Colors16Sepia: - addPalette16ColorSepia(m_palette); - break; - case Palette::Colors16Windows: - addPalette16ColorWindows(m_palette); - break; - case Palette::Colors16Mac: - addPalette16ColorMac(m_palette); - break; - case Palette::Colors16ZxSpectrum: - addPalette16ColorZxSpectrum(m_palette); - break; - case Palette::Colors216Web: - addPalette216ColorWebSafe(m_palette); - break; - case Palette::Colors256Greenscale: - addPalette256ColorGreenscale(m_palette); - break; - case Palette::Colors256Grayscale: - addPalette256ColorGrayscale(m_palette); - break; - case Palette::Colors256Sepia: - addPalette256ColorSepia(m_palette); - break; - case Palette::Default: - default: - addPaletteDefault(m_palette); - } -} - -void ConsoleScreenV1::addColorToPalette(const sf::Color color) -{ - m_palette.emplace_back(color); -} - -void ConsoleScreenV1::setPaletteColor(const int colorId, const sf::Color color) -{ - if (!priv_isColorIdInPaletteRange(colorId)) - { - if (m_do.throwExceptions) - throw Exception(exceptionPrefix + "Cannot set palette color.\nColor ID (" + std::to_string(colorId) + ") out of range."); - return; - } - - m_palette[colorId] = color; -} - -sf::Color ConsoleScreenV1::getPaletteColor(const int colorId) const -{ - if (!priv_isColorIdInPaletteRange(colorId)) - { - if (m_do.throwExceptions) - throw Exception(exceptionPrefix + "Cannot get palette color.\nColor ID (" + std::to_string(colorId) + ") out of range."); - return defaultNewPaletteColor; - } - - return m_palette[colorId]; -} - -void ConsoleScreenV1::setPaletteSize(const unsigned int size) -{ - if (size < 1) - { - if (m_do.throwExceptions) - throw Exception(exceptionPrefix + "Cannot set palette size to zero."); - return; - } - - m_palette.resize(size); -} - -unsigned int ConsoleScreenV1::getPaletteSize() const -{ - return static_cast(m_palette.size()); -} - -void ConsoleScreenV1::removePaletteColor(const int colorId) -{ - if (!priv_isColorIdInPaletteRange(colorId)) - { - if (m_do.throwExceptions) - throw Exception(exceptionPrefix + "Cannot remove palette color.\nColor ID (" + std::to_string(colorId) + ") out of range."); - return; - } - if (m_palette.size() < 2) - { - if (m_do.throwExceptions) - throw Exception(exceptionPrefix + "Cannot remove final palette color."); - return; - } - - m_palette.erase(m_palette.begin() + colorId); -} - -unsigned int ConsoleScreenV1::copy() -{ - m_buffers.push_back({ m_mode.x, m_cells }); - return static_cast(m_buffers.size()) - 1u; -} - -void ConsoleScreenV1::copy(const unsigned int index) -{ - if (!priv_isScreenBufferIndexInRange(index)) - { - if (m_do.throwExceptions) - throw Exception(exceptionPrefix + "Cannot replace buffer with copy.\nBuffer index (" + std::to_string(index) + ") does not exist."); - return; - } - - m_buffers[index] = { m_mode.x, m_cells }; - - if (m_do.updateAutomatically) - update(); -} - -unsigned int ConsoleScreenV1::copy(const sf::IntRect selectionRectangle) -{ - m_buffers.emplace_back(); - priv_copyToBufferFromSelectionRectangle(m_buffers.back(), selectionRectangle); - return static_cast(m_buffers.size()) - 1u; -} - -void ConsoleScreenV1::copy(const unsigned int index, const sf::IntRect selectionRectangle) -{ - if (!priv_isScreenBufferIndexInRange(index)) - { - if (m_do.throwExceptions) - throw Exception(exceptionPrefix + "Cannot replace buffer with copy.\nBuffer index (" + std::to_string(index) + ") does not exist."); - return; - } - - priv_copyToBufferFromSelectionRectangle(m_buffers[index], selectionRectangle); -} - -void ConsoleScreenV1::paste(const sf::Vector2i offset) -{ - if (m_buffers.size() == 0) - { - if (m_do.throwExceptions) - throw Exception(exceptionPrefix + "Cannot paste buffer.\nNo buffer exists."); - return; - } - - priv_pasteOffsettedBuffer(m_buffers.back(), offset); -} - -void ConsoleScreenV1::paste(const unsigned int index, const sf::Vector2i offset) -{ - if (!priv_isScreenBufferIndexInRange(index)) - { - if (m_do.throwExceptions) - throw Exception(exceptionPrefix + "Cannot paste buffer.\nBuffer index (" + std::to_string(index) + ") out of range."); - return; - } - - priv_pasteOffsettedBuffer(m_buffers[index], offset); -} - -void ConsoleScreenV1::removeBuffer() -{ - if (m_buffers.size() == 0) - { - if (m_do.throwExceptions) - throw Exception(exceptionPrefix + "Cannot remove buffer.\nNo buffer exists."); - return; - } - - m_buffers.pop_back(); -} - -void ConsoleScreenV1::removeBuffer(const unsigned int index) -{ - if (!priv_isScreenBufferIndexInRange(index)) - { - if (m_do.throwExceptions) - throw Exception(exceptionPrefix + "Cannot remove buffer.\nBuffer index (" + std::to_string(index) + ") out of range."); - return; - } - - m_buffers.erase(m_buffers.begin() + index); -} - -void ConsoleScreenV1::removeAllBuffers() -{ - m_buffers.clear(); -} - -unsigned int ConsoleScreenV1::getNumberOfBuffers() const -{ - return static_cast(m_buffers.size()); -} - -void ConsoleScreenV1::setMappedCharacter(const char character, const unsigned int value) -{ - m_characterMap[character] = value; -} - -void ConsoleScreenV1::setMappedCharacters(const std::string& characters, unsigned int initialValue) -{ - for (auto& character : characters) - setMappedCharacter(character, initialValue++); -} - -void ConsoleScreenV1::removeMappedCharacter(const char character) -{ - m_characterMap.erase(character); -} - -void ConsoleScreenV1::removeMappedCharacters(const std::string& characters) -{ - for (auto& character : characters) - removeMappedCharacter(character); -} - -bool ConsoleScreenV1::getIsMappedCharacter(const char character) const -{ - return m_characterMap.find(character) != m_characterMap.end(); -} - -unsigned int ConsoleScreenV1::getMappedCharacter(const char character) const -{ - return m_characterMap.at(character); -} - -void ConsoleScreenV1::poke(const unsigned int index, const Cell& cell) -{ - if (!priv_isCellIndexInRange(index)) - { - if (m_do.throwExceptions) - throw Exception(exceptionPrefix + "Cannot poke cell.\nCell number (" + std::to_string(index) + ") out of range."); - return; - } - - m_cells[index] = cell; - - if (m_do.updateAutomatically) - priv_updateCell(index); -} - -void ConsoleScreenV1::poke(const unsigned int index, const unsigned int value) -{ - if (!priv_isCellIndexInRange(index)) - { - if (m_do.throwExceptions) - throw Exception(exceptionPrefix + "Cannot poke value.\nCell number (" + std::to_string(index) + ") out of range."); - return; - } - - m_cells[index].value = value; - - if (m_do.updateAutomatically) - priv_updateCell(index); -} - -void ConsoleScreenV1::poke(const unsigned int index, const sf::Color& color) -{ - if (!priv_isCellIndexInRange(index)) - { - if (m_do.throwExceptions) - throw Exception(exceptionPrefix + "Cannot poke color.\nCell number (" + std::to_string(index) + ") out of range."); - return; - } - - m_cells[index].color = color; - - if (m_do.updateAutomatically) - priv_updateCell(index); -} - -void ConsoleScreenV1::poke(const unsigned int index, const sf::Color& color, const sf::Color& backgroundColor) -{ - if (!priv_isCellIndexInRange(index)) - { - if (m_do.throwExceptions) - throw Exception(exceptionPrefix + "Cannot poke colors.\nCell number (" + std::to_string(index) + ") out of range."); - return; - } - - m_cells[index].color = color; - m_cells[index].backgroundColor = backgroundColor; - - if (m_do.updateAutomatically) - priv_updateCell(index); -} - -void ConsoleScreenV1::poke(const unsigned int index, const Stretch& stretch) -{ - if (!priv_isCellIndexInRange(index)) - { - if (m_do.throwExceptions) - throw Exception(exceptionPrefix + "Cannot poke stretch attribute.\nCell number (" + std::to_string(index) + ") out of range."); - return; - } - - m_cells[index].stretch = stretch; - - if (m_do.updateAutomatically) - priv_updateCell(index); -} - -void ConsoleScreenV1::poke(const unsigned int index, const CellAttributes& cellAttributes) -{ - if (!priv_isCellIndexInRange(index)) - { - if (m_do.throwExceptions) - throw Exception(exceptionPrefix + "Cannot poke attributes.\nCell number (" + std::to_string(index) + ") out of range."); - return; - } - - m_cells[index].attributes = cellAttributes; - - if (m_do.updateAutomatically) - priv_updateCell(index); -} - -void ConsoleScreenV1::poke(const unsigned int index, const bool attributeValue, const Attribute attribute) -{ - if (!priv_isCellIndexInRange(index)) - { - if (m_do.throwExceptions) - throw Exception(exceptionPrefix + "Cannot poke attribute.\nCell number (" + std::to_string(index) + ") out of range."); - return; - } - - priv_chooseAttribute(m_cells[index].attributes, attribute) = attributeValue; - - if (m_do.updateAutomatically) - priv_updateCell(index); -} - -ConsoleScreenV1::Cell ConsoleScreenV1::peek(const unsigned int index) const -{ - if (!priv_isCellIndexInRange(index)) - { - if (m_do.throwExceptions) - throw Exception(exceptionPrefix + "Cannot peek cell.\nCell number (" + std::to_string(index) + ") out of range."); - return Cell(); - } - - return m_cells[index]; -} - - - -// PRIVATE - -void ConsoleScreenV1::draw(sf::RenderTarget& target, sf::RenderStates states) const -{ - states.transform *= getTransform(); - - if (m_do.showBackround && m_backgroundDisplay.size() > 0) - { - states.texture = nullptr; - target.draw(&m_backgroundDisplay.front(), m_backgroundDisplay.size(), m_primitiveType, states); - } - if (m_display.size() > 0) - { - states.texture = m_texture; - target.draw(&m_display.front(), m_display.size(), m_primitiveType, states); - } -} - -void ConsoleScreenV1::priv_updateCell(const unsigned int index) -{ - if (!priv_isCellIndexInRange(index)) - return; - - if (m_display.size() != (m_mode.x * m_mode.y * 4)) - { - if (m_do.throwExceptions) - throw Exception(exceptionPrefix + "Bug: display does not match cells."); - return; - } - - if (m_display.size() < 4) - { - if (m_do.throwExceptions) - throw Exception(exceptionPrefix + "Bug: cannot update cell. No cells available."); - return; - } - - Cell& cell{ m_cells[index] }; - - unsigned int cellValue{ cell.value }; - sf::Color cellColor{ cell.color }; - sf::Color backgroundColor{ cell.backgroundColor }; - - const bool isCursor{ m_cursor.visible && m_cursor.index == index }; - bool useCursorValue{ false }; - - if (isCursor) - { - if (m_cursor.value >= 0) - { - useCursorValue = true; - cellValue = m_cursor.value; - } - if (m_cursor.useOwnColour) - cellColor = m_colors.cursor; - if (cell.attributes.inverse != m_cursor.inverse) - swapColors(cellColor, backgroundColor); - } - else if (cell.attributes.inverse) - swapColors(cellColor, backgroundColor); - - if (!cell.attributes.bright) - { - makeColorUnBright(cellColor); - makeColorUnBright(backgroundColor); - } - - const unsigned int cellX{ index % m_mode.x }; - const unsigned int cellY{ index / m_mode.x }; - const float left{ linearInterpolation(0.f, m_size.x, static_cast(cellX + (cell.attributes.flipX ? 1 : 0)) / m_mode.x) }; - const float right{ linearInterpolation(0.f, m_size.x, static_cast(cellX + (cell.attributes.flipX ? 0 : 1)) / m_mode.x) }; - const float top{ linearInterpolation(0.f, m_size.y, static_cast(cellY + (cell.attributes.flipY ? 1 : 0)) / m_mode.y) }; - const float bottom{ linearInterpolation(0.f, m_size.y, static_cast(cellY + (cell.attributes.flipY ? 0 : 1)) / m_mode.y) }; - - sf::Vector2u textureCell{ cellValue % m_numberOfTilesPerRow, cellValue / m_numberOfTilesPerRow }; - const float textureLeft{ static_cast(m_textureOffset.x + textureCell.x * m_tileSize.x) }; - const float textureTop{ static_cast(m_textureOffset.y + (textureCell.y + (!useCursorValue && cell.stretch == Stretch::Bottom ? 0.5f : 0.f)) * m_tileSize.y) }; - const float textureRight{ static_cast(m_textureOffset.x + (textureCell.x + 1) * m_tileSize.x) }; - const float textureBottom{ static_cast(m_textureOffset.y + (textureCell.y + (!useCursorValue && cell.stretch == Stretch::Top ? 0.5f : 1.f)) * m_tileSize.y) }; - - const unsigned int baseVertex{ index * 4 }; - sf::Vertex* const pVertex1{ &m_display[baseVertex] }; - sf::Vertex* const pVertex2{ pVertex1 + 1 }; - sf::Vertex* const pVertex3{ pVertex1 + 2 }; - sf::Vertex* const pVertex4{ pVertex1 + 3 }; - sf::Vertex* const pBackgroundVertex1{ &m_backgroundDisplay[baseVertex] }; - sf::Vertex* const pBackgroundVertex2{ pBackgroundVertex1 + 1 }; - sf::Vertex* const pBackgroundVertex3{ pBackgroundVertex1 + 2 }; - sf::Vertex* const pBackgroundVertex4{ pBackgroundVertex1 + 3 }; - - // main display - pVertex1->position = { left, top }; - pVertex2->position = { right, top }; - pVertex3->position = { right, bottom }; - pVertex4->position = { left, bottom }; - - pVertex1->texCoords = { textureLeft, textureTop }; - pVertex2->texCoords = { textureRight, textureTop }; - pVertex3->texCoords = { textureRight, textureBottom }; - pVertex4->texCoords = { textureLeft, textureBottom }; - - pVertex1->color = cellColor; - pVertex2->color = cellColor; - pVertex3->color = cellColor; - pVertex4->color = cellColor; - - // background display - pBackgroundVertex1->position = pVertex1->position; - pBackgroundVertex2->position = pVertex2->position; - pBackgroundVertex3->position = pVertex3->position; - pBackgroundVertex4->position = pVertex4->position; - - pBackgroundVertex1->color = backgroundColor; - pBackgroundVertex2->color = backgroundColor; - pBackgroundVertex3->color = backgroundColor; - pBackgroundVertex4->color = backgroundColor; -} - -inline unsigned int ConsoleScreenV1::priv_cellIndex(const sf::Vector2u location) const -{ - return location.y * m_mode.x + location.x; -} - -inline sf::Vector2u ConsoleScreenV1::priv_cellLocation(const unsigned int index) const -{ - return{ index % m_mode.x, index / m_mode.x }; -} - -inline bool ConsoleScreenV1::priv_isCellIndexInRange(const unsigned int index) const -{ - return index < m_cells.size(); -} - -inline bool ConsoleScreenV1::priv_isCellLocationInRange(const sf::Vector2u location) const -{ - return (location.x < m_mode.x && location.y < m_mode.y); -} - -inline bool ConsoleScreenV1::priv_isScreenBufferIndexInRange(const unsigned int index) const -{ - return index < m_buffers.size(); -} - -inline bool ConsoleScreenV1::priv_isCursorInRange() const -{ - return priv_isCellIndexInRange(m_cursor.index); -} - -inline bool ConsoleScreenV1::priv_isColorIdInPaletteRange(const int id) const -{ - return (id >= 0) && (id < static_cast(m_palette.size())); -} - -inline void ConsoleScreenV1::priv_clearCell(const unsigned int index, const bool overwriteColor, const bool overwriteBackgroundColor) -{ - const sf::Color color{ overwriteColor ? m_colors.main : m_cells[index].color }; - const sf::Color backgroundColor{ overwriteBackgroundColor ? m_colors.background : m_cells[index].backgroundColor }; - poke(index, { 0, color, backgroundColor, Stretch::None, CellAttributes() }); -} - -inline void ConsoleScreenV1::priv_clearCell(const unsigned int index, const sf::Color& backgroundColor, const bool overwriteColor) -{ - const sf::Color color{ overwriteColor ? m_colors.main : m_cells[index].color }; - poke(index, { 0, color, backgroundColor, Stretch::None, CellAttributes() }); -} - -inline void ConsoleScreenV1::priv_clearCell(const unsigned int index, const sf::Color& color, const sf::Color& backgroundColor) -{ - poke(index, { 0, color, backgroundColor, Stretch::None, CellAttributes() }); -} - -inline void ConsoleScreenV1::priv_paintCell(const unsigned int index, const sf::Color& color, const sf::Color& backgroundColor) -{ - poke(index, color, backgroundColor); - - if (m_do.updateAutomatically) - priv_updateCell(index); -} - -void ConsoleScreenV1::priv_setCursorIndex(const unsigned int index) -{ - const unsigned int previousIndex{ m_cursor.index }; - m_cursor.index = index; - - if (m_do.updateAutomatically) - { - priv_updateCell(previousIndex); - priv_updateCell(m_cursor.index); - } -} - -void ConsoleScreenV1::priv_moveCursorToBeginningOfLine() -{ - priv_setCursorIndex(m_cursor.index - m_cursor.index % m_mode.x); -} - -void ConsoleScreenV1::priv_moveCursorUp() -{ - if (m_cursor.index >= m_mode.x) - priv_setCursorIndex(m_cursor.index - m_mode.x); -} - -void ConsoleScreenV1::priv_moveCursorDown() -{ - priv_setCursorIndex(m_cursor.index + m_mode.x); - priv_testCursorForScroll(); -} - -void ConsoleScreenV1::priv_moveCursorLeft() -{ - if (m_cursor.index > 0) - priv_setCursorIndex(m_cursor.index - 1); -} - -void ConsoleScreenV1::priv_moveCursorRight() -{ - priv_setCursorIndex(m_cursor.index + 1); - priv_testCursorForScroll(); -} - -void ConsoleScreenV1::priv_testCursorForScroll() -{ - if (m_cursor.index >= m_cells.size()) - { - if (m_do.scrollAutomatically) - { - priv_scroll(); - if (m_do.updateAutomatically) - update(); - } - else - { - m_cursor.index = static_cast(m_cells.size()) - 1u; - if (m_do.updateAutomatically) - priv_updateCell(m_cursor.index); - } - } -} - -void ConsoleScreenV1::priv_scroll() -{ - for (unsigned int y{ 0 }; y < m_mode.y; ++y) - { - for (unsigned int x{ 0 }; x < m_mode.x; ++x) - { - if (y < m_mode.y - 1) - m_cells[priv_cellIndex({ x, y })] = m_cells[priv_cellIndex({ x, y + 1 })]; - else - priv_clearCell(priv_cellIndex({ x, y }), true, true); - } - } - priv_moveCursorUp(); -} - -void ConsoleScreenV1::priv_copyToBufferFromSelectionRectangle(Buffer& buffer, const sf::IntRect& selectionRectangle) -{ - if (selectionRectangle.left >= static_cast(m_mode.x) || - selectionRectangle.top >= static_cast(m_mode.y) || - selectionRectangle.width <= 0 || - selectionRectangle.height <= 0 || - (selectionRectangle.left + selectionRectangle.width) < 0 || - (selectionRectangle.top + selectionRectangle.height) < 0) - { - if (m_do.throwExceptions) - throw Exception(exceptionPrefix + "Cannot copy selection.\nSelection does not contain any cells."); - return; - } - - buffer.width = 0u; - buffer.cells.clear(); - - for (int y{ 0 }; y < selectionRectangle.height; ++y) - { - for (int x{ 0 }; x < selectionRectangle.width; ++x) - { - const sf::Vector2i location{ x + selectionRectangle.left, y + selectionRectangle.top }; - if (location.x < 0 || location.y < 0) - continue; - const sf::Vector2u cellLocation{ static_cast(location.x), static_cast(location.y) }; - if (priv_isCellLocationInRange(cellLocation)) - { - buffer.cells.push_back(m_cells[priv_cellIndex(cellLocation)]); - if (y == 0) - ++buffer.width; - } - } - } -} - -void ConsoleScreenV1::priv_pasteOffsettedBuffer(Buffer& buffer, const sf::Vector2i& offset) -{ - for (unsigned int i{ 0 }; i < buffer.cells.size(); ++i) - { - const sf::Vector2i location{ static_cast(i % buffer.width) + offset.x, static_cast(i / buffer.width) + offset.y }; - if (location.x < 0 || location.y < 0) - continue; - const sf::Vector2u cellLocation{ static_cast(location.x), static_cast(location.y) }; - if (priv_isCellLocationInRange(cellLocation)) - m_cells[priv_cellIndex(cellLocation)] = buffer.cells[i]; - } - - if (m_do.updateAutomatically) - update(); -} - -unsigned int ConsoleScreenV1::priv_getPrintIndex(sf::Vector2u location) const -{ - if (location.x >= m_mode.x) - { - location.y += location.x / m_mode.x; - location.x %= m_mode.x; - } - if (location.y >= m_mode.y) - { - location.y = m_mode.y - 1; - location.x = m_mode.x - 1; // push cursor to the end of the line if cursor was below the last line - } - - return priv_cellIndex(location); -} - -inline unsigned int ConsoleScreenV1::priv_getCellValueFromCharacter(const char character) const -{ - if (getIsMappedCharacter(character)) - return m_characterMap.at(character); - else - return static_cast(character); -} - -inline char ConsoleScreenV1::priv_getCharacterFromCellValue(const unsigned int cellValue) const -{ - for (auto& pair : m_characterMap) - { - if (pair.second == cellValue) - return pair.first; - } - return static_cast(cellValue); -} - -sf::Color ConsoleScreenV1::priv_colorFromColorIdAtIndex(const unsigned int index, const int colorId) const -{ - sf::Color color; - if (priv_isColorIdInPaletteRange(colorId)) - return m_palette[colorId]; - else - { - switch (colorId) - { - case Color::Contrast: - return contrastedColor(m_cells[index].backgroundColor); - case Color::Invert: - return invertedColor(m_cells[index].backgroundColor); - case Color::Ignore: - return m_cells[index].color; - case Color::Current: - default: - return m_colors.main; - } - } -} - -sf::Color ConsoleScreenV1::priv_backgroundColorFromColorIdAtIndex(const unsigned int index, const int colorId) const -{ - sf::Color color; - if (priv_isColorIdInPaletteRange(colorId)) - return m_palette[colorId]; - else - { - switch (colorId) - { - case Color::Contrast: - return contrastedColor(m_cells[index].color); - case Color::Invert: - return invertedColor(m_cells[index].color); - case Color::Ignore: - return m_cells[index].backgroundColor; - case Color::Current: - default: - return m_colors.background; - } - } -} - -bool& ConsoleScreenV1::priv_chooseAttribute(CellAttributes& cellAttributes, const Attribute attribute) -{ - switch (attribute) - { - case Attribute::FlipX: - return cellAttributes.flipX; - case Attribute::FlipY: - return cellAttributes.flipY; - case Attribute::Bright: - return cellAttributes.bright; - case Attribute::Inverse: - default: - return cellAttributes.inverse; - } -} - -} // namespace selbaward diff --git a/src/SelbaWard/ConsoleScreenOld.hpp b/src/SelbaWard/ConsoleScreenOld.hpp deleted file mode 100644 index dbc9cca..0000000 --- a/src/SelbaWard/ConsoleScreenOld.hpp +++ /dev/null @@ -1,416 +0,0 @@ -////////////////////////////////////////////////////////////////////////////// -// -// Selba Ward (https://github.com/Hapaxia/SelbaWard) -// -- -// -// Console Screen v1 -// -// Copyright(c) 2014-2023 M.J.Silk -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any damages -// arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions : -// -// 1. The origin of this software must not be misrepresented; you must not -// claim that you wrote the original software.If you use this software -// in a product, an acknowledgment in the product documentation would be -// appreciated but is not required. -// -// 2. Altered source versions must be plainly marked as such, and must not be -// misrepresented as being the original software. -// -// 3. This notice may not be removed or altered from any source distribution. -// -// M.J.Silk -// MJSilk2@gmail.com -// -////////////////////////////////////////////////////////////////////////////// - -#ifndef SELBAWARD_CONSOLESCREEN_V1_HPP -#define SELBAWARD_CONSOLESCREEN_V1_HPP - -#include "Common.hpp" - -#include - -namespace selbaward -{ - -// SW Console Screen v1.5.3 -class ConsoleScreenV1 : public sf::Drawable, public sf::Transformable -{ -public: - struct Cell; - enum class Palette; - enum class Stretch - { - None, - Top, - Bottom - }; - enum class Attribute - { - Inverse, - Bright, - FlipX, - FlipY, - }; - struct CellAttributes - { - bool inverse{ false }; - bool bright{ true }; - bool flipX{ false }; - bool flipY{ false }; - }; - enum Color // colour command - { - Current = -1, // use current colour - Ignore = -2, // ignore colour (leave cell's colour as it is) - Invert = -3, // invert the opposite colour ("main colour = invert" would set main colour to inverted background colour and vice versa) - Contrast = -4 // contrast the opposite colour ("main colour = contrast" would set main colour to contrast background colour and vice versa). contrast is black or white based on opposite's luminance - }; - - // setup - ConsoleScreenV1(sf::Vector2u mode = { 80u, 45u }); - void setMode(sf::Vector2u mode); // "mode" is the number of cells used to fit the screen - sf::Vector2u getMode() const; - unsigned int getNumberOfCells() const; - sf::Vector2u getNumberOfTilesInTexture2d() const; - unsigned int getNumberOfTilesInTexture() const; - - // texture - void setTexture(const sf::Texture& texture); - void setTexture(); - void setTextureOffset(sf::Vector2u textureOffset = { 0u, 0u }); - void setTextureTileSize(sf::Vector2u tileSize = { 8u, 8u }); - void setNumberOfTextureTilesPerRow(unsigned int numberOfTextureTilesPerRow = 1); - - // switches - void setThrowExceptions(bool exceptions); - void setUpdateAutomatically(bool automaticUpdate); - void setShowCursor(bool showCursor); - void setInvertCursor(bool invertCursor); - void setUseCursorColor(bool useCursorColor); - void setShowBackground(bool showBackground); - void setScrollAutomatically(bool scroll); - void setWrapOnManualScroll(bool wrapOnManualScroll); - bool getThrowExceptions() const; - bool getUpdateAutomatically() const; - bool getShowCursor() const; - bool getInvertCursor() const; - bool getUseCursorColor() const; - bool getShowBackground() const; - bool getScrollAutomatically() const; - bool getWrapOnManualScroll() const; - - // visual representation - void setSize(sf::Vector2f size); - sf::Vector2f getSize() const; - sf::FloatRect getLocalBounds() const; - sf::FloatRect getGlobalBounds() const; - - // global - void update(); - void clear(int backgroundColorId = Color::Current); - void clear(sf::Color backgroundColor); - void crash(); - - // current colours - void setColor(sf::Color color); - void setColor(int colorId); - void setBackgroundColor(sf::Color backgroundColor); - void setBackgroundColor(int colorId); - void setCursorColor(sf::Color cursorColor); - void setCursorColor(int colorId); - void setColors(sf::Color color, sf::Color backgroundColor); - void setColors(sf::Color color, sf::Color backgroundColor, sf::Color cursorColor); - void setColors(int colorId, int backgroundColorId); - void setColors(int colorId, int backgroundColorId, int cursorColorId); - sf::Color getColor() const; - sf::Color getBackgroundColor() const; - sf::Color getCursorColor() const; - - // current stretch - void setStretch(Stretch stretch); - Stretch getStretch() const; - - // current attributes - void setAttributes(CellAttributes attributes); - void setAttribute(bool attributeValue, Attribute attribute = Attribute::Inverse); - CellAttributes getAttributes() const; - bool getAttribute(Attribute attribute = Attribute::Inverse); - - // cursor position - void cursorHome(); - void cursorHomeLine(); - void cursorEnd(); - void cursorEndLine(); - void cursorTab(unsigned int tabSize = 4); // move cursor right in a tab-like way. if the end of a line is passed, the beginning of the next line is the next tab - void cursorTabReverse(unsigned int tabSize = 4); // move cursor left in a tab-like way. if the beginning of a line is passed, the last tab position of the previous line is the destination - void cursorNextline(); - void cursorBackspace(); // clears the cursor's destination's cell - void cursorLeft(unsigned int distance = 1); - void cursorRight(unsigned int distance = 1); - void cursorUp(unsigned int distance = 1); - void cursorDown(unsigned int distance = 1); - void moveCursor(sf::Vector2i offset); - void setCursor(sf::Vector2u location); - sf::Vector2u getCursor() const; - - // cursor value (tile/character used to represent cursor) - void setCursor(int cellValue); - void setCursor(char cellChar, bool mapCharacter); // converts from character to cell value. this can map the character if the character has an associated mapping - - // printing (using cursor) - void print(char character, int colorId = Color::Current, int backgroundColorId = Color::Current); - void print(char character, const Stretch& stretch, int colorId = Color::Current, int backgroundColorId = Color::Current); - void print(char character, const CellAttributes& attributes, int colorId = Color::Current, int backgroundColorId = Color::Current); - void print(const std::string& string, int colorId = Color::Current, int backgroundColorId = Color::Current); - void print(const std::string& string, const Stretch& stretch, int colorId = Color::Current, int backgroundColorId = Color::Current); - void print(const std::string& string, const CellAttributes& attributes, int colorId = Color::Current, int backgroundColorId = Color::Current); - void printLine(const std::string& string, int colorId = Color::Current, int backgroundColorId = Color::Current); - - // printing (directly) - void printAt(sf::Vector2u location, const std::string& string, sf::Color color, sf::Color backgroundColor); - void printAt(sf::Vector2u location, const std::string& string, sf::Color color, int backgroundColorId = Color::Ignore); - void printAt(sf::Vector2u location, const std::string& string, int colorId, sf::Color backgroundColor); - void printAt(sf::Vector2u location, const std::string& string, int colorId = Color::Ignore, int backgroundColorId = Color::Ignore); - void printAt(sf::Vector2u location, char character, sf::Color color, sf::Color backgroundColor); - void printAt(sf::Vector2u location, char character, sf::Color color, int backgroundColorId = Color::Ignore); - void printAt(sf::Vector2u location, char character, int colorId, sf::Color backgroundColor); - void printAt(sf::Vector2u location, char character, int colorId = Color::Ignore, int backgroundColorId = Color::Ignore); - - // printing stretched (directly - cannot mix sf::Colors and color IDs therefore cannot supply only foreground colour) - void printStretchedAt(sf::Vector2u location, const std::string& string, const Stretch& stretch, sf::Color color, sf::Color backgroundColor); - void printStretchedAt(sf::Vector2u location, const std::string& string, const Stretch& stretch = Stretch::Top, int colorId = Color::Ignore, int backgroundColorId = Color::Ignore); - void printStretchedAt(sf::Vector2u location, char character, const Stretch& stretch, sf::Color color, sf::Color backgroundColor); - void printStretchedAt(sf::Vector2u location, char character, const Stretch& stretch = Stretch::Top, int colorId = Color::Ignore, int backgroundColorId = Color::Ignore); - - // painting (directly) - void paintAt(sf::Vector2u location, unsigned int length, sf::Color color, sf::Color backgroundColor); - void paintAt(sf::Vector2u location, unsigned int length, sf::Color color, int backgroundColorId = Color::Ignore); - void paintAt(sf::Vector2u location, unsigned int length, int colorId, sf::Color backgroundColor); - void paintAt(sf::Vector2u location, unsigned int length, int colorId = Color::Current, int backgroundColorId = Color::Ignore); - - // painting attributes (directly - flags only) - void paintAttributeAt(sf::Vector2u location, unsigned int length, bool attributeValue, Attribute attribute = Attribute::Inverse); - - // reading - std::string read(unsigned int length = 1u, bool unmapCharacters = true); // not const because cursor is moved by reading - - // reading (directly) - std::string readAt(sf::Vector2u location, unsigned int length = 1u, bool unmapCharacters = true) const; - - // cell manipulation - void clearCellAt(sf::Vector2u location); - void setCellAt(sf::Vector2u location, const Cell& cell); - void setValueAt(sf::Vector2u location, unsigned int value); - void setColorAt(sf::Vector2u location, sf::Color color); - void setColorAt(sf::Vector2u location, int colorId); - void setBackgroundColorAt(sf::Vector2u location, sf::Color backgroundColor); - void setBackgroundColorAt(sf::Vector2u location, int backgroundColorId); - void setColorsAt(sf::Vector2u location, sf::Color color, sf::Color backgroundColor); - void setColorsAt(sf::Vector2u location, int colorId, int backgroundColorId); - void setStretchAt(sf::Vector2u location, const Stretch& stretch); - void setAttributesAt(sf::Vector2u location, const CellAttributes& attributes); - void setAttributeAt(sf::Vector2u location, bool attributeValue, Attribute attribute = Attribute::Inverse); - - // cell information - Cell getCellAt(sf::Vector2u location) const; - unsigned int getValueAt(sf::Vector2u location) const; - sf::Color getColorAt(sf::Vector2u location) const; - sf::Color getBackgroundColorAt(sf::Vector2u location) const; - Stretch getStretchAt(sf::Vector2u location) const; - CellAttributes getAttributesAt(sf::Vector2u location) const; - bool getAttributeAt(sf::Vector2u location, Attribute attribute = Attribute::Inverse); - - // manual scrolling - void scrollUp(unsigned int amount = 1); - void scrollDown(unsigned int amount = 1); - void scrollLeft(unsigned int amount = 1); - void scrollRight(unsigned int amount = 1); - - // colour palette - void loadPalette(Palette palette); - void addColorToPalette(sf::Color color); - void setPaletteColor(int colorId, sf::Color color); - sf::Color getPaletteColor(int colorId) const; - void setPaletteSize(unsigned int size); - unsigned int getPaletteSize() const; - void removePaletteColor(int colorId); - - // buffers/clipboards/"screenshots"/captures - unsigned int copy(); // returns index of buffer - unsigned int copy(sf::IntRect selectionRectangle); // returns index of buffer - void paste(sf::Vector2i offset = sf::Vector2i(0, 0)); // replace screen with last saved buffer (recalls actual cell data, not the state of the console screen e.g. cursor isn't restored) - void removeBuffer(); // removes last saved buffer - void copy(unsigned int index); // copies over (replaces) an existing buffer - void copy(unsigned int index, sf::IntRect selectionRectangle); - void paste(unsigned int index, sf::Vector2i offset = sf::Vector2i(0, 0)); // replace screen with saved buffer (recalls actual cell data, not the state of the console screen e.g. cursor isn't restored) - void removeBuffer(unsigned int index); // as usual, when one buffer is removed, the indices of all following buffers are decreased - void removeAllBuffers(); - unsigned int getNumberOfBuffers() const; - - // character mapping (to cell values) - void setMappedCharacter(char character, unsigned int value); - void setMappedCharacters(const std::string& characters, unsigned int initialValue); - void removeMappedCharacter(char character); - void removeMappedCharacters(const std::string& characters); - bool getIsMappedCharacter(char character) const; - unsigned int getMappedCharacter(char character) const; - - // direct manipulation - void poke(unsigned int index, const Cell& cell); - void poke(unsigned int index, unsigned int value); - void poke(unsigned int index, const sf::Color& color); - void poke(unsigned int index, const sf::Color& color, const sf::Color& backgroundColor); - void poke(unsigned int index, const Stretch& stretch); - void poke(unsigned int index, bool attributeValue, Attribute attribute = Attribute::Inverse); - void poke(unsigned int index, const CellAttributes& attributes); - Cell peek(unsigned int index) const; - - - - - - - - - - -private: - struct CurrentColors - { - sf::Color main; - sf::Color background; - sf::Color cursor; - }; - - struct Cursor - { - unsigned int index; - int value; // if -1, doesn't change the cell's value (allows other cursor features to still be displayed) - bool visible; - bool inverse; - bool useOwnColour; - }; - - struct Flags - { - bool throwExceptions = true; - bool showBackround = true; - bool updateAutomatically = true; - bool scrollAutomatically = true; - bool wrapOnManualScroll = false; - }; - - // flags - Flags m_do; - - // definition - using Cells = std::vector; - Cells m_cells; - sf::Vector2u m_mode; - - // buffers - struct Buffer - { - unsigned int width; - Cells cells; - }; - std::vector m_buffers; - - // cursor - Cursor m_cursor; - - // current colours - CurrentColors m_colors; - - // current stretch - Stretch m_stretch; - - // current attributes - CellAttributes m_attributes; - - // colour palette - std::vector m_palette; - - // character map (mapped to cell value) - std::unordered_map m_characterMap; - - // visual representation - const sf::PrimitiveType m_primitiveType; - std::vector m_display; - std::vector m_backgroundDisplay; - sf::Vector2f m_size; - const sf::Texture* m_texture; - sf::Vector2u m_textureOffset; - sf::Vector2u m_tileSize; - unsigned int m_numberOfTilesPerRow; - - virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const; - void priv_updateCell(unsigned int index); - unsigned int priv_cellIndex(sf::Vector2u location) const; - sf::Vector2u priv_cellLocation(unsigned int index) const; - bool priv_isCellIndexInRange(unsigned int index) const; - bool priv_isCellLocationInRange(sf::Vector2u location) const; - bool priv_isScreenBufferIndexInRange(unsigned int index) const; - bool priv_isCursorInRange() const; - bool priv_isColorIdInPaletteRange(int id) const; - //bool priv_isColorIdInExtendedRange(int id) const; - void priv_clearCell(unsigned int index, bool overwriteColor, bool overwriteBackgroundColor); - void priv_clearCell(unsigned int index, const sf::Color& backgroundColor, bool overwriteColor); - void priv_clearCell(unsigned int index, const sf::Color& color, const sf::Color& backgroundColor); - void priv_paintCell(unsigned int index, const sf::Color& color, const sf::Color& backgroundColor); - void priv_setCursorIndex(unsigned int index); - void priv_moveCursorToBeginningOfLine(); - void priv_moveCursorUp(); - void priv_moveCursorDown(); - void priv_moveCursorLeft(); - void priv_moveCursorRight(); - void priv_testCursorForScroll(); - void priv_scroll(); - void priv_copyToBufferFromSelectionRectangle(Buffer& buffer, const sf::IntRect& selectionRectangle); - void priv_pasteOffsettedBuffer(Buffer& buffer, const sf::Vector2i& offset); - unsigned int priv_getPrintIndex(sf::Vector2u location) const; - unsigned int priv_getCellValueFromCharacter(char character) const; - char priv_getCharacterFromCellValue(unsigned int cellValue) const; - sf::Color priv_colorFromColorIdAtIndex(unsigned int index, int colorId) const; - sf::Color priv_backgroundColorFromColorIdAtIndex(unsigned int index, int colorId) const; - bool& priv_chooseAttribute(CellAttributes& cellAttributes, Attribute attribute = Attribute::Inverse); -}; - -struct ConsoleScreenV1::Cell -{ - unsigned int value; - sf::Color color; - sf::Color backgroundColor; - Stretch stretch; - CellAttributes attributes; -}; - -enum class ConsoleScreenV1::Palette -{ - Default, // basic 16-colour palette - Colors2BlackWhite, - Colors2WhiteBlack, - Colors16Greenscale, - Colors16Grayscale, - Colors16Sepia, - Colors16Cga, - Colors16CgaNonIbm, - Colors16Windows, - Colors16Mac, - Colors16ZxSpectrum, - Colors216Web, - Colors256Greenscale, - Colors256Grayscale, - Colors256Sepia -}; - -} // namespace selbaward -#endif // SELBAWARD_CONSOLESCREEN_V1_HPP From bc8535cf394d1e887500e4e621095fb3abf1b048 Mon Sep 17 00:00:00 2001 From: Hapaxia Date: Tue, 9 May 2023 01:42:03 +0100 Subject: [PATCH 32/64] Update .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index ff2a551..bd98dae 100644 --- a/.gitignore +++ b/.gitignore @@ -26,6 +26,7 @@ extlibs/ backup/ backup_*/ test/ +test-*/ test_*/ test-*/ temp/ From f538694064b225d47b9ac308c444a3cdc7f143f7 Mon Sep 17 00:00:00 2001 From: Hapaxia Date: Tue, 9 May 2023 16:26:56 +0100 Subject: [PATCH 33/64] Line - update to v1.2.3 patch update. since updating Selba Ward to no longer use quads, Line uses a triangle strip. However, it had been setup similar to other objects - that instead use triangles - following the 6 vertices per quad rule. this caused attempts at accessing vertices that didn't exist as the triangle strip only needs 4 vertices for a quad. this fixes that problem, reducing all vertex looping to only go 4 times and no attempting to access the 5th and 6th vertex that do not exist. --- src/SelbaWard/Line.cpp | 6 ++---- src/SelbaWard/Line.hpp | 2 +- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/SelbaWard/Line.cpp b/src/SelbaWard/Line.cpp index f922df4..0eab1e1 100644 --- a/src/SelbaWard/Line.cpp +++ b/src/SelbaWard/Line.cpp @@ -97,7 +97,7 @@ sf::FloatRect Line::getLocalBounds() const float minX, maxX, minY, maxY; minX = maxX = m_quad[0].position.x; minY = maxY = m_quad[0].position.y; - for (unsigned int v{ 1u }; v < 6u; ++v) + for (unsigned int v{ 1u }; v < 4u; ++v) { minX = std::min(minX, m_quad[v].position.x); maxX = std::max(maxX, m_quad[v].position.x); @@ -129,7 +129,7 @@ sf::FloatRect Line::getGlobalBounds() const float minX, maxX, minY, maxY; minX = maxX = transformedPosition0.x; minY = maxY = transformedPosition0.y; - for (unsigned int v{ 1u }; v < 6u; ++v) + for (unsigned int v{ 1u }; v < 4u; ++v) { const sf::Vector2f transformedPosition{ transform.transformPoint(m_quad[v].position) }; minX = std::min(minX, transformedPosition.x); @@ -177,8 +177,6 @@ void Line::setColor(const sf::Color& color) m_quad[1u].color = color; m_quad[2u].color = color; m_quad[3u].color = color; - m_quad[4u].color = color; - m_quad[5u].color = color; } void Line::setTexture(const sf::Texture& texture) diff --git a/src/SelbaWard/Line.hpp b/src/SelbaWard/Line.hpp index 66e9990..308ab02 100644 --- a/src/SelbaWard/Line.hpp +++ b/src/SelbaWard/Line.hpp @@ -41,7 +41,7 @@ namespace selbaward { -// SW Line v1.2.2 +// SW Line v1.2.3 class Line : public sf::Drawable, public sf::Transformable { public: From 5162beddf76841cf21977db53d3a7bd82c5ae9ae Mon Sep 17 00:00:00 2001 From: Hapaxia Date: Mon, 29 May 2023 23:23:07 +0100 Subject: [PATCH 34/64] add Starfield 3D add new drawable: Starfield 3D similar to Starfield, it creates a randomised set of stars that can be moved with parallax. however, this version uses actual 3D projection and allows Z movement as well. you can specify the front and back colours as well as the front and back scale (of the star shape) and they are automatically "tweened" between them. included is the ability to create a "star template" that is the shape of each star. it can be any shape or colour. colours are multiplied with the colour (from the front and back colours). you can "move" in all three dimensions and pan in two dimension. "roll" rotation is not included; you can simply use the sf::Drawable's rotation feature for that. --- src/SelbaWard/Starfield3d.cpp | 332 ++++++++++++++++++++++++++++++++++ src/SelbaWard/Starfield3d.hpp | 107 +++++++++++ 2 files changed, 439 insertions(+) create mode 100644 src/SelbaWard/Starfield3d.cpp create mode 100644 src/SelbaWard/Starfield3d.hpp diff --git a/src/SelbaWard/Starfield3d.cpp b/src/SelbaWard/Starfield3d.cpp new file mode 100644 index 0000000..070a0cd --- /dev/null +++ b/src/SelbaWard/Starfield3d.cpp @@ -0,0 +1,332 @@ +////////////////////////////////////////////////////////////////////////////// +// +// Selba Ward (https://github.com/Hapaxia/SelbaWard) +// -- +// +// Starfield 3D +// +// Copyright(c) 2023 M.J.Silk +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions : +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software.If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +// M.J.Silk +// MJSilk2@gmail.com +// +////////////////////////////////////////////////////////////////////////////// + +#include "Starfield3d.hpp" + +#include +#include +#include + +namespace +{ + +std::mt19937 randomGenerator; +std::uniform_int_distribution randomDistributionAlpha(1u, 255u); +std::function randomAlpha; + +inline void randomSeed() +{ + std::random_device rd; + randomGenerator.seed(rd()); + randomAlpha = std::bind(randomDistributionAlpha, randomGenerator); +} + +inline float randomValue(const float low, const float high) +{ + return std::uniform_real_distribution{low, high}(randomGenerator); +} + +template +inline T linearTween(const T start, const T end, const float alpha) +{ + return static_cast((start * (1.f - alpha)) + (end * alpha)); +} + +inline sf::Color linearTween(const sf::Color& start, const sf::Color& end, const float alpha) +{ + return{ linearTween(start.r, end.r, alpha), linearTween(start.g, end.g, alpha), linearTween(start.b, end.b, alpha), linearTween(start.a, end.a, alpha) }; +} + +} // namespace + +namespace selbaward +{ + +Starfield3d::Starfield3d(const sf::Vector2f size, const std::size_t numberOfStars, const float maxDepth, const sf::Color& frontColor, const sf::Color& backColor, const float frontScale, const float backScale) + : m_depthCalibration{ 0.001f } + , m_depthSpeedCalibration{ 0.93f } + , m_isUpdateRequired{ true } + , m_size{ size } + , m_numberOfStars{ numberOfStars } + , m_positions(numberOfStars) + , m_starTemplate(6u) + , m_primitiveType{ sf::PrimitiveType::Triangles } + , m_vertices(numberOfStars) + , m_deepestSliceBounds() + , m_maxDepth{ maxDepth } + , m_frontColor{ frontColor } + , m_backColor{ backColor } + , m_frontScale{ frontScale } + , m_backScale{ backScale } +{ + randomSeed(); + regenerate(); + + m_starTemplate[0u].position = { 0.f, 1.f }; + m_starTemplate[1u].position = { 1.f, -0.5f }; + m_starTemplate[2u].position = { -1.f, -0.5f }; + m_starTemplate[3u].position = { 0.f, -1.f }; + m_starTemplate[4u].position = { -1.f, 0.5f }; + m_starTemplate[5u].position = { 1.f, 0.5f }; + + // color + for (auto& v : m_starTemplate) + v.color = sf::Color::White; +} + +void Starfield3d::move(const sf::Vector3f movement) +{ + m_isUpdateRequired = true; + for (auto& position : m_positions) + { + // move + position -= movement * std::pow(m_maxDepth * m_depthCalibration, m_depthSpeedCalibration); + + // wrap depth + if (position.z < 0.f) + position = priv_generateRandomStarPosition(EdgeLock::Back); + else if (position.z > m_maxDepth) + position = priv_generateRandomStarPosition(EdgeLock::Front); + + // wrap 2D (xy slice) + if (position.x < m_deepestSliceBounds.left) + position = priv_generateRandomStarPosition(EdgeLock::Right); + else if (position.x > (m_deepestSliceBounds.left + m_deepestSliceBounds.width)) + position = priv_generateRandomStarPosition(EdgeLock::Left); + if (position.y < m_deepestSliceBounds.top) + position = priv_generateRandomStarPosition(EdgeLock::Bottom); + else if (position.y > (m_deepestSliceBounds.top + m_deepestSliceBounds.height)) + position = priv_generateRandomStarPosition(EdgeLock::Top); + + } +} + +void Starfield3d::pan(const sf::Vector2f panAmount) +{ + m_isUpdateRequired = true; + const sf::Vector3f movement{ panAmount.x, panAmount.y, 0.f }; + for (auto& position : m_positions) + { + // move + position -= movement * (((1.f + position.z) * m_depthCalibration - 1.f)); + + // wrap 2D (xy slice) + if (position.x < m_deepestSliceBounds.left) + position = priv_generateRandomStarPosition(EdgeLock::Right); + else if (position.x > (m_deepestSliceBounds.left + m_deepestSliceBounds.width)) + position = priv_generateRandomStarPosition(EdgeLock::Left); + if (position.y < m_deepestSliceBounds.top) + position = priv_generateRandomStarPosition(EdgeLock::Bottom); + else if (position.y > (m_deepestSliceBounds.top + m_deepestSliceBounds.height)) + position = priv_generateRandomStarPosition(EdgeLock::Top); + + } +} + +void Starfield3d::regenerate() +{ + m_deepestSliceBounds = priv_calculateFrustumSliceBounds(m_maxDepth); + + m_positions.resize(m_numberOfStars); + for (auto& position : m_positions) + position = priv_generateRandomStarPosition(); +} + +void Starfield3d::regenerate(const sf::Vector2f size) +{ + m_size = size; + regenerate(); +} + +void Starfield3d::regenerate(const sf::Vector2f size, const std::size_t numberOfStars) +{ + m_numberOfStars = numberOfStars; + regenerate(size); +} + +void Starfield3d::regenerate(const std::size_t numberOfStars) +{ + regenerate(m_size, numberOfStars); +} + +void Starfield3d::setMaxDepth(const float maxDepth) +{ + m_isUpdateRequired = true; + m_maxDepth = maxDepth; +} + +void Starfield3d::setFrontColor(const sf::Color& color) +{ + m_isUpdateRequired = true; + m_frontColor = color; +} + +void Starfield3d::setBackColor(const sf::Color& color) +{ + m_isUpdateRequired = true; + m_backColor = color; +} + +void Starfield3d::setFrontScale(const float frontScale) +{ + m_isUpdateRequired = true; + m_frontScale = frontScale; +} + +void Starfield3d::setBackScale(const float backScale) +{ + m_isUpdateRequired = true; + m_backScale = backScale; +} + +void Starfield3d::setStarTemplate(const std::vector& vertices) +{ + m_isUpdateRequired = true; + m_starTemplate = vertices; +} + +void Starfield3d::setStarTemplate(const std::vector& vertices) +{ + m_isUpdateRequired = true; + m_starTemplate.resize(vertices.size()); + for (std::size_t i{ 0u }; i < m_starTemplate.size(); ++i) + { + m_starTemplate[i].position = vertices[i]; + m_starTemplate[i].color = sf::Color::White; + } +} + +void Starfield3d::setStarTemplate(const sf::VertexArray& vertexArray) +{ + m_isUpdateRequired = true; + m_starTemplate.resize(vertexArray.getVertexCount()); + for (std::size_t i{ 0u }; i < m_starTemplate.size(); ++i) + m_starTemplate[i] = vertexArray[i]; +} + + + +// PRIVATE + +void Starfield3d::draw(sf::RenderTarget& target, sf::RenderStates states) const +{ + if (m_isUpdateRequired) + priv_updateVertices(); + + states.transform *= getTransform(); + const std::size_t size{ m_vertices.size() }; + if (size > 0) + target.draw(m_vertices.data(), size, m_primitiveType, states); +} + +void Starfield3d::priv_updateVertices() const +{ + // positions' indices sorted by depth + m_positionIndices.resize(m_positions.size()); + for (std::size_t i{ 0u }; i < m_positionIndices.size(); ++i) + m_positionIndices[i] = i; + std::sort(m_positionIndices.begin(), m_positionIndices.end(), [&](std::size_t a, std::size_t b) { return m_positions[a].z > m_positions[b].z; }); + + // vertices + const std::size_t numberOfVerticesPerStar{ m_starTemplate.size() }; + m_vertices.resize(m_numberOfStars * numberOfVerticesPerStar); + for (std::size_t star{ 0u }; star < m_numberOfStars; ++star) + { + const std::size_t starIndex{ m_positionIndices[star] }; + const float depthRatio{ m_positions[starIndex].z / m_maxDepth }; + const float depthInverseRatio{ 1.f - depthRatio }; + const sf::Color color{ linearTween(m_frontColor, m_backColor, depthRatio) }; + const float depthScale{ linearTween(m_frontScale, m_backScale, depthRatio) }; + sf::Vector2f starPosition{ priv_projectPoint(m_positions[starIndex]) }; + for (std::size_t vertex{ 0u }; vertex < numberOfVerticesPerStar; ++vertex) + { + m_vertices[star * numberOfVerticesPerStar + vertex] = starPosition + (sf::Vector2f{ m_starTemplate[vertex].position.x, m_starTemplate[vertex].position.y } * depthScale); + m_vertices[star * numberOfVerticesPerStar + vertex].color = m_starTemplate[vertex].color * color; + } + } +} + +sf::Vector2f Starfield3d::priv_projectPoint(const sf::Vector3f point) const +{ + const sf::Vector2f center{ m_size / 2.f }; + const float depth{ (point.z < 0.f) ? 1.f : (m_depthCalibration * point.z) + 1.f }; + return { ((point.x - center.x) / depth) + center.x, ((point.y - center.y) / depth) + center.y }; +} + +sf::FloatRect Starfield3d::priv_calculateFrustumSliceBounds(float z) const +{ + z *= m_depthCalibration; + ++z; + const sf::Vector2f center{ m_size / 2.f }; + const sf::Vector2f topLeft{ (-center * z) + center }; + const sf::Vector2f bottomRight{ (center * z) + center }; + return { topLeft, bottomRight - topLeft }; +} + +sf::Vector3f Starfield3d::priv_generateRandomStarPosition() const +{ + sf::Vector3f position; + position.z = randomValue(0.f, m_maxDepth); + position.x = randomValue(m_deepestSliceBounds.left, m_deepestSliceBounds.left + m_deepestSliceBounds.width); + position.y = randomValue(m_deepestSliceBounds.top, m_deepestSliceBounds.top + m_deepestSliceBounds.height); + return position; +} + +sf::Vector3f Starfield3d::priv_generateRandomStarPosition(const EdgeLock edgeLock) const +{ + sf::Vector3f position; + + if (edgeLock == EdgeLock::Front) + position.z = 0.f; + else if (edgeLock == EdgeLock::Back) + position.z = m_maxDepth; + else + position.z = randomValue(0.f, m_maxDepth); + + if (edgeLock == EdgeLock::Left) + position.x = m_deepestSliceBounds.left; + else if (edgeLock == EdgeLock::Right) + position.x = m_deepestSliceBounds.left + m_deepestSliceBounds.width; + else + position.x = randomValue(m_deepestSliceBounds.left, m_deepestSliceBounds.left + m_deepestSliceBounds.width); + + if (edgeLock == EdgeLock::Top) + position.y = m_deepestSliceBounds.top; + else if (edgeLock == EdgeLock::Bottom) + position.y = m_deepestSliceBounds.top + m_deepestSliceBounds.height; + else + position.y = randomValue(m_deepestSliceBounds.top, m_deepestSliceBounds.top + m_deepestSliceBounds.height); + + return position; +} + +} // namespace selbaward diff --git a/src/SelbaWard/Starfield3d.hpp b/src/SelbaWard/Starfield3d.hpp new file mode 100644 index 0000000..b1ef6db --- /dev/null +++ b/src/SelbaWard/Starfield3d.hpp @@ -0,0 +1,107 @@ +////////////////////////////////////////////////////////////////////////////// +// +// Selba Ward (https://github.com/Hapaxia/SelbaWard) +// -- +// +// Starfield 3D +// +// Copyright(c) 2023 M.J.Silk +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions : +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software.If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +// M.J.Silk +// MJSilk2@gmail.com +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef SELBAWARD_STARFIELD3D_HPP +#define SELBAWARD_STARFIELD3D_HPP + +#include "Common.hpp" +#include +#include + +namespace selbaward +{ + +// SW Starfield3d v1.0.0 +class Starfield3d : public sf::Drawable, public sf::Transformable +{ +public: + Starfield3d(sf::Vector2f size = { 0.f, 0.f }, std::size_t numberOfStars = 400u, float maxDepth = 1000000.f, const sf::Color& frontColor = sf::Color(255u, 255u, 255u, 255u), const sf::Color& backColor = sf::Color(0u, 0u, 0u, 255u), float frontScale = 0.f, float backScale = 0.f); + void regenerate(); + void regenerate(sf::Vector2f size); + void regenerate(sf::Vector2f size, std::size_t numberOfStars); + void regenerate(std::size_t numberOfStars); + + void setMaxDepth(float maxDepth); + void setFrontColor(const sf::Color& color); + void setBackColor(const sf::Color& color); + void setFrontScale(float frontScale); + void setBackScale(float backScale); + + void setStarTemplate(const std::vector& vertices); + void setStarTemplate(const std::vector& vertices); + void setStarTemplate(const sf::VertexArray& vertexArray); // ignores primitive type - uses given vertices with sf::Triangles primitive type + + void move(sf::Vector3f movement); + void pan(sf::Vector2f panAmount); + +private: + const float m_depthCalibration; + const float m_depthSpeedCalibration; + bool m_isUpdateRequired; + sf::Vector2f m_size; + std::size_t m_numberOfStars; + std::vector m_positions; + float m_maxDepth; + sf::Color m_frontColor; + sf::Color m_backColor; + float m_frontScale; + float m_backScale; + + std::vector m_starTemplate; + + sf::PrimitiveType m_primitiveType; + mutable std::vector m_vertices; + mutable std::vector m_positionIndices; + mutable sf::FloatRect m_deepestSliceBounds; + + enum class EdgeLock + { + Left, + Right, + Top, + Bottom, + Front, + Back, + }; + + virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const; + + void priv_updateVertices() const; + sf::Vector2f priv_projectPoint(sf::Vector3f point) const; + sf::FloatRect priv_calculateFrustumSliceBounds(float z) const; + sf::Vector3f priv_generateRandomStarPosition() const; + sf::Vector3f priv_generateRandomStarPosition(EdgeLock edgeLock) const; + +}; + +} // namespace selbaward +#endif // SELBAWARD_STARFIELD3D_HPP From e2ab868136ae3f8362570d5d20e792d272d27d09 Mon Sep 17 00:00:00 2001 From: Hapaxia Date: Thu, 1 Jun 2023 16:05:59 +0100 Subject: [PATCH 35/64] Merge pull request #35 from Hapaxia/starfield3d add Starfield 3D From 7b72e61166d7b25570a359a4278386ef854165c0 Mon Sep 17 00:00:00 2001 From: Hapaxia Date: Thu, 1 Jun 2023 16:09:14 +0100 Subject: [PATCH 36/64] add Starfield 3D to inclusion header --- src/SelbaWard.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/SelbaWard.hpp b/src/SelbaWard.hpp index d672e45..88a54d2 100644 --- a/src/SelbaWard.hpp +++ b/src/SelbaWard.hpp @@ -47,6 +47,7 @@ #include "SelbaWard/Spline.hpp" #include "SelbaWard/Sprite3d.hpp" #include "SelbaWard/Starfield.hpp" +#include "SelbaWard/Starfield3d.hpp" #include "SelbaWard/TileMap.hpp" #endif // SELBAWARD_HPP From 3368abe13240a53287b1b7199e54d9fb37b1c4b1 Mon Sep 17 00:00:00 2001 From: Hapaxia Date: Sat, 3 Jun 2023 00:44:51 +0100 Subject: [PATCH 37/64] Starfield 3D - update to v1.0.1 patch update to fix the default parameter for frontScale. it was 0 (meaning nearest stars were not visible); it has been fixed and set to 1. --- src/SelbaWard/Starfield3d.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/SelbaWard/Starfield3d.hpp b/src/SelbaWard/Starfield3d.hpp index b1ef6db..5d2d58b 100644 --- a/src/SelbaWard/Starfield3d.hpp +++ b/src/SelbaWard/Starfield3d.hpp @@ -40,11 +40,11 @@ namespace selbaward { -// SW Starfield3d v1.0.0 +// SW Starfield3d v1.0.1 class Starfield3d : public sf::Drawable, public sf::Transformable { public: - Starfield3d(sf::Vector2f size = { 0.f, 0.f }, std::size_t numberOfStars = 400u, float maxDepth = 1000000.f, const sf::Color& frontColor = sf::Color(255u, 255u, 255u, 255u), const sf::Color& backColor = sf::Color(0u, 0u, 0u, 255u), float frontScale = 0.f, float backScale = 0.f); + Starfield3d(sf::Vector2f size = { 0.f, 0.f }, std::size_t numberOfStars = 400u, float maxDepth = 1000000.f, const sf::Color& frontColor = sf::Color(255u, 255u, 255u, 255u), const sf::Color& backColor = sf::Color(0u, 0u, 0u, 255u), float frontScale = 1.f, float backScale = 0.f); void regenerate(); void regenerate(sf::Vector2f size); void regenerate(sf::Vector2f size, std::size_t numberOfStars); From 377f99f0c2a803f228816ed20efa71555602ae59 Mon Sep 17 00:00:00 2001 From: Hapaxia Date: Sat, 3 Jun 2023 00:45:01 +0100 Subject: [PATCH 38/64] Merge pull request #36 from Hapaxia/starfield3d Starfield 3D - update to v1.0.1 From 195c2a8d630dc701bb56de5667e83948f039524a Mon Sep 17 00:00:00 2001 From: Hapaxia Date: Wed, 21 Jun 2023 21:23:27 +0100 Subject: [PATCH 39/64] Polygon - update to v1.1.1 just a patch update. mostly code re-organisation, removing redundant repeats. minor corrections made too. should function the same. --- src/SelbaWard/Polygon.cpp | 274 +++++++++----------------------------- src/SelbaWard/Polygon.hpp | 2 +- 2 files changed, 65 insertions(+), 211 deletions(-) diff --git a/src/SelbaWard/Polygon.cpp b/src/SelbaWard/Polygon.cpp index b9eed0a..99d606a 100644 --- a/src/SelbaWard/Polygon.cpp +++ b/src/SelbaWard/Polygon.cpp @@ -33,6 +33,7 @@ #include "Polygon.hpp" #include +#include namespace { @@ -251,7 +252,61 @@ void Polygon::priv_triangulateBasicEarClip() std::vector ear; reflex.reserve(m_vertices.size() - 3u); // impossible for vertices to be reflex without enough convex (need at least 3 convex to make a polygon) convex.reserve(m_vertices.size()); - ear.reserve(m_vertices.size()); + ear.reserve(m_vertices.size() - 2u); // with one ear per vertex, the final ear requires 3 vertices + + std::function isEar = + [&](const std::size_t i, const std::size_t p, const std::size_t n, const std::size_t current) + { + bool aPointIsInside{ false }; + for (std::size_t other{ 0u }; other < indices.size(); ++other) + { + if ((other == i) || (other == p) || (other == n) || (other == current)) + continue; + + if (pointIsInsideTriangle({ m_vertices[indices[p]].position, m_vertices[indices[i]].position, m_vertices[indices[n]].position }, m_vertices[indices[other]].position)) + { + aPointIsInside = true; + break; + } + } + return !aPointIsInside; + }; + + std::function isEarAnalysis = + [&](const std::size_t i, const std::size_t p, const std::size_t n) + { + return isEar(i, p, n, i); + }; + + std::function retest = + [&](const std::size_t i, const std::size_t p, const std::size_t n, const std::size_t current) + { + std::vector::iterator reflexIt{ std::find(reflex.begin(), reflex.end(), indices[i]) }; + if (reflexIt != reflex.end()) + { + // if reflex, re-test + const sf::Vector2f pLine{ m_vertices[indices[i]].position - m_vertices[indices[p]].position }; + const sf::Vector2f nLine{ m_vertices[indices[n]].position - m_vertices[indices[i]].position }; + + if (isSecondVectorAntiClockwiseOfFirstVector(pLine, nLine)) + { + reflex.erase(reflexIt); + convex.push_back(indices[i]); + } + } + + std::vector::iterator convexIt{ std::find(convex.begin(), convex.end(), indices[i]) }; + if (convexIt != convex.end()) + { + // if convex, re-test for ear only (must still be convex) + const bool isNowEar{ isEar(i, p, n, current) }; + const std::vector::iterator it{ std::find(ear.begin(), ear.end(), indices[i]) }; + if (isNowEar && (it == ear.end())) + ear.push_back(indices[i]); + else if (!isNowEar && (it != ear.end())) + ear.erase(it); + } + }; // analyse points for (std::size_t i{ 0u }; i < indicesSize; ++i) @@ -262,28 +317,14 @@ void Polygon::priv_triangulateBasicEarClip() const sf::Vector2f prevLine{ m_vertices[indices[i]].position - m_vertices[indices[prev]].position }; const sf::Vector2f nextLine{ m_vertices[indices[next]].position - m_vertices[indices[i]].position }; - if (isSecondVectorAntiClockwiseOfFirstVector(prevLine, nextLine)) + if (!isSecondVectorAntiClockwiseOfFirstVector(prevLine, nextLine)) + reflex.push_back(indices[i]); + else { convex.push_back(i); - bool aPointIsInside{ false }; - for (std::size_t other{ 0u }; other < indicesSize; ++other) - { - if ((other == i) || (other == prev) || (other == next)) - continue; - - if (pointIsInsideTriangle({ m_vertices[indices[prev]].position, m_vertices[indices[i]].position, m_vertices[indices[next]].position }, m_vertices[indices[other]].position)) - { - aPointIsInside = true; - break; - } - } - if (!aPointIsInside) + if (isEarAnalysis(i, prev, next)) ear.push_back(indices[i]); } - else - { - reflex.push_back(indices[i]); - } } // process @@ -298,203 +339,16 @@ void Polygon::priv_triangulateBasicEarClip() TriangleIndices triangle{ indices[prev], indices[current], indices[next] }; m_triangles.push_back(triangle); + retest(prev, ((prev > 0u) ? (prev - 1u) : (indices.size() - 1u)), next, current); + retest(next, prev, ((next < (indices.size() - 1u)) ? (next + 1u) : 0u), current); - - std::vector::iterator earPrevIt{ std::find(ear.begin(), ear.end(), indices[prev]) }; - if (earPrevIt != ear.end()) - { - // if ear, re-test for ear only (might not still be one) - - std::size_t i{ prev }; - - const std::size_t p{ (i > 0u) ? (i - 1u) : (indices.size() - 1u) }; - const std::size_t n{ next }; - - bool aPointIsInside{ false }; - for (std::size_t other{ 0u }; other < indices.size(); ++other) - { - if ((other == i) || (other == p) || (other == n) || (other == current)) - continue; - - if (pointIsInsideTriangle({ m_vertices[indices[p]].position, m_vertices[indices[i]].position, m_vertices[indices[n]].position }, m_vertices[indices[other]].position)) - { - aPointIsInside = true; - break; - } - } - if (aPointIsInside) - ear.erase(earPrevIt); - } - - - - std::vector::iterator earNextIt{ std::find(ear.begin(), ear.end(), indices[next]) }; - if (earNextIt != ear.end()) - { - // if ear, re-test for ear only (might not still be one) - - std::size_t i{ next }; - - const std::size_t p{ prev }; - const std::size_t n{ (i < (indices.size() - 1u)) ? (i + 1u) : 0u }; - - bool aPointIsInside{ false }; - for (std::size_t other{ 0u }; other < indices.size(); ++other) - { - if ((other == i) || (other == p) || (other == n) || (other == current)) - continue; - - if (pointIsInsideTriangle({ m_vertices[indices[p]].position, m_vertices[indices[i]].position, m_vertices[indices[n]].position }, m_vertices[indices[other]].position)) - { - aPointIsInside = true; - break; - } - } - if (aPointIsInside) - ear.erase(earNextIt); - } - - - - std::vector::iterator convexPrevIt{ std::find(convex.begin(), convex.end(), indices[prev]) }; - if (convexPrevIt != convex.end()) - { - // if convex, re-test for ear only (must still be convex) - - if (std::find(ear.begin(), ear.end(), indices[prev]) == ear.end()) - { - std::size_t i{ prev }; - - const std::size_t p{ (i > 0u) ? (i - 1u) : (indices.size() - 1u) }; - const std::size_t n{ next }; - - bool aPointIsInside{ false }; - for (std::size_t other{ 0u }; other < indices.size(); ++other) - { - if ((other == i) || (other == p) || (other == n) || (other == current)) - continue; - - if (pointIsInsideTriangle({ m_vertices[indices[p]].position, m_vertices[indices[i]].position, m_vertices[indices[n]].position }, m_vertices[indices[other]].position)) - { - aPointIsInside = true; - break; - } - } - if (!aPointIsInside) - ear.push_back(indices[i]); - } - } - - - - std::vector::iterator convexNextIt{ std::find(convex.begin(), convex.end(), indices[next]) }; - if (convexNextIt != convex.end()) - { - // if convex, re-test for ear only (must still be convex) - - if (std::find(ear.begin(), ear.end(), indices[next]) == ear.end()) - { - std::size_t i{ next }; - - const std::size_t p{ prev }; - const std::size_t n{ (i < (indices.size() - 1u)) ? (i + 1u) : 0u }; - - bool aPointIsInside{ false }; - for (std::size_t other{ 0u }; other < indices.size(); ++other) - { - if ((other == i) || (other == p) || (other == n) || (other == current)) - continue; - - if (pointIsInsideTriangle({ m_vertices[indices[p]].position, m_vertices[indices[i]].position, m_vertices[indices[n]].position }, m_vertices[indices[other]].position)) - { - aPointIsInside = true; - break; - } - } - if (!aPointIsInside) - ear.push_back(indices[i]); - } - } - - - - std::vector::iterator reflexPrevIt{ std::find(reflex.begin(), reflex.end(), indices[prev]) }; - if (reflexPrevIt != reflex.end()) - { - // if reflex, re-test - std::size_t i{ prev }; - - const std::size_t p{ (i > 0u) ? (i - 1u) : (indices.size() - 1u) }; - const std::size_t n{ next }; - - const sf::Vector2f pLine{ m_vertices[indices[i]].position - m_vertices[indices[p]].position }; - const sf::Vector2f nLine{ m_vertices[indices[n]].position - m_vertices[indices[i]].position }; - - if (isSecondVectorAntiClockwiseOfFirstVector(pLine, nLine)) - { - reflex.erase(reflexPrevIt); - - convex.push_back(indices[i]); - bool aPointIsInside{ false }; - for (std::size_t other{ 0u }; other < indices.size(); ++other) - { - if ((other == i) || (other == p) || (other == n) || (other == current)) - continue; - - if (pointIsInsideTriangle({ m_vertices[indices[p]].position, m_vertices[indices[i]].position, m_vertices[indices[n]].position }, m_vertices[indices[other]].position)) - { - aPointIsInside = true; - break; - } - } - if (!aPointIsInside) - ear.push_back(indices[i]); - } - } - - std::vector::iterator reflexNextIt{ std::find(reflex.begin(), reflex.end(), indices[next]) }; - if (reflexNextIt != reflex.end()) - { - // if reflex, re-test - std::size_t i{ next }; - - const std::size_t p{ prev }; - const std::size_t n{ (i < (indices.size() - 1u)) ? (i + 1u) : 0u }; - - const sf::Vector2f pLine{ m_vertices[indices[i]].position - m_vertices[indices[p]].position }; - const sf::Vector2f nLine{ m_vertices[indices[n]].position - m_vertices[indices[i]].position }; - - if (isSecondVectorAntiClockwiseOfFirstVector(pLine, nLine)) - { - reflex.erase(reflexNextIt); - - convex.push_back(indices[i]); - bool aPointIsInside{ false }; - for (std::size_t other{ 0u }; other < indices.size(); ++other) - { - if ((other == i) || (other == p) || (other == n) || (other == current)) - continue; - - if (pointIsInsideTriangle({ m_vertices[indices[p]].position, m_vertices[indices[i]].position, m_vertices[indices[n]].position }, m_vertices[indices[other]].position)) - { - aPointIsInside = true; - break; - } - } - if (!aPointIsInside) - ear.push_back(indices[i]); - } - } - + // remove current (the one we clipped) convex.erase(std::find(convex.begin(), convex.end(), indices[current])); - if (std::find(ear.begin(), ear.end(), indices[current]) != ear.end()) - ear.erase(std::find(ear.begin(), ear.end(), indices[current])); + ear.erase(std::find(ear.begin(), ear.end(), indices[current])); indices.erase(currentIt); - ///* if (m_triangles.size() == stopAfterThisNumberOfTrianglesHaveBeenCreated) break; - //*/ } if (m_triangles.size() < stopAfterThisNumberOfTrianglesHaveBeenCreated) diff --git a/src/SelbaWard/Polygon.hpp b/src/SelbaWard/Polygon.hpp index 7a4ca07..1ec47db 100644 --- a/src/SelbaWard/Polygon.hpp +++ b/src/SelbaWard/Polygon.hpp @@ -39,7 +39,7 @@ namespace selbaward { -// SW Polygon v1.1 +// SW Polygon v1.1.1 class Polygon : public sf::Drawable, public sf::Transformable { public: From a47de12d6fef7ff49f6d795c7a552587ccffcb71 Mon Sep 17 00:00:00 2001 From: Hapaxia Date: Mon, 26 Jun 2023 03:36:13 +0100 Subject: [PATCH 40/64] Polygon-update to v1.2 in addition to BasicEarClip, which triangulates simple polygons, EarClip is now provided, which can triangulate simple polygons that contain any number of simple polygon holes. some restrictions: polygons vertices must be provided in an anti-clockwise order. holes' vertices must be provided in a clockwise order. all vertices (polygon and holes) must be provided together. holes' vertices must be provided after all of the polygon vertices. an index (per hole) must be provided to mark the start of that hole. --- src/SelbaWard/Polygon.cpp | 346 ++++++++++++++++++++++++++++++++++++++ src/SelbaWard/Polygon.hpp | 13 +- 2 files changed, 358 insertions(+), 1 deletion(-) diff --git a/src/SelbaWard/Polygon.cpp b/src/SelbaWard/Polygon.cpp index 99d606a..fb9d67f 100644 --- a/src/SelbaWard/Polygon.cpp +++ b/src/SelbaWard/Polygon.cpp @@ -34,6 +34,7 @@ #include #include +#include namespace { @@ -71,6 +72,16 @@ inline bool pointIsInsideTriangle(const std::vector& points, sf::V */ } +inline float crossProduct(const sf::Vector2f& a, const sf::Vector2f& b) +{ + return (a.x * b.y) - (a.y * b.x); +} + +inline float lengthSquared(const sf::Vector2f& a) +{ + return (a.x * a.x) + (a.y * a.y); +} + } // namespace namespace selbaward @@ -79,6 +90,7 @@ namespace selbaward Polygon::Polygon() : m_outputVertices() , m_vertices() + , m_holeStartIndices() , m_color{ sf::Color::White } , m_triangulationMethod{ TriangulationMethod::BasicEarClip } , m_meshRefinementMethod{ MeshRefinementMethod::None } @@ -157,6 +169,21 @@ sf::Vector2f Polygon::getVertexPosition(const std::size_t index) const return m_vertices[index].position; } +void Polygon::addHoleStartIndex(const std::size_t index) +{ + m_holeStartIndices.push_back(index); +} + +void Polygon::clearHoleStartIndices() +{ + m_holeStartIndices.clear(); +} + +void Polygon::setHoleStartIndices(const std::vector& indices) +{ + m_holeStartIndices = indices; +} + void Polygon::reverseVertices() { std::reverse(m_vertices.begin(), m_vertices.end()); @@ -225,6 +252,325 @@ void Polygon::priv_triangulate() case TriangulationMethod::BasicEarClip: priv_triangulateBasicEarClip(); break; + case TriangulationMethod::EarClip: + priv_triangulateEarClip(); + break; + } +} + +void Polygon::priv_triangulateEarClip() +{ + constexpr std::size_t stopAfterThisNumberOfTrianglesHaveBeenCreated{ 100u }; + + // ear clipping method + // polygon points must be anti-clockwise + // hole points must be clockwise + // number of triangles will always be (number of points - 2) + + // vertexNumbers is the order of the vertices (can re-use vertices) + // this is a single stream of vertices creating the polygon (after the holes are added, this becomes a single polygon) + std::vector vertexNumbers(m_vertices.size()); + std::size_t vertexNumbersSize{ vertexNumbers.size() }; + for (std::size_t i{ 0u }; i < vertexNumbersSize; ++i) + vertexNumbers[i] = i; + + if (!m_holeStartIndices.empty()) + { + std::sort(m_holeStartIndices.begin(), m_holeStartIndices.end()); + vertexNumbersSize = m_holeStartIndices[0u]; + } + const std::vector holeVertexNumbers(vertexNumbers.begin() + vertexNumbersSize, vertexNumbers.end()); + const std::size_t holeVertexNumbersSize{ holeVertexNumbers.size() }; + vertexNumbers.erase(vertexNumbers.begin() + vertexNumbersSize, vertexNumbers.end()); + // now, vertexNumbers is polygon vertex numbers (including any hole already cut in - later on) and holeVertexNumbers is the hole vertex numbers (all of them - no need to remove or rearrange this) + + // indices is the list of indices of the vertex numbers in order + // each index is treated as a separate vertex, even if it's technically the same vertex as another (same vertex numbers) + std::vector indices(vertexNumbersSize); + std::size_t indicesSize{ indices.size() }; + for (std::size_t i{ 0u }; i < indicesSize; ++i) + indices[i] = i; + + // points lists (to keep track of their state) + // note that these store indices - their numbers refer to which index to access: e.g. m_vertices[vertexNumbers[indices[reflex]]] + std::vector reflex; + std::vector convex; + std::vector ear; + + std::function isEar = + [&](const std::size_t i, const std::size_t p, const std::size_t n, const std::size_t current) + { + bool aPointIsInside{ false }; + for (std::size_t other{ 0u }; other < vertexNumbers.size(); ++other) + { + if ((vertexNumbers[other] == vertexNumbers[i]) || (vertexNumbers[other] == vertexNumbers[p]) || (vertexNumbers[other] == vertexNumbers[n]) || (vertexNumbers[other] == vertexNumbers[current])) + continue; + + if (pointIsInsideTriangle({ m_vertices[vertexNumbers[p]].position, m_vertices[vertexNumbers[i]].position, m_vertices[vertexNumbers[n]].position }, m_vertices[vertexNumbers[other]].position)) + { + aPointIsInside = true; + break; + } + } + return !aPointIsInside; + }; + + std::function isEarAnalysis = + [&](const std::size_t i, const std::size_t p, const std::size_t n) + { + return isEar(i, p, n, i); + }; + + std::function retest = + [&](const std::size_t i, const std::size_t p, const std::size_t n, const std::size_t current) + { + std::vector::iterator reflexIt{ std::find(reflex.begin(), reflex.end(), indices[i]) }; + if (reflexIt != reflex.end()) + { + // if reflex, re-test + const sf::Vector2f pLine{ m_vertices[vertexNumbers[indices[i]]].position - m_vertices[vertexNumbers[indices[p]]].position }; + const sf::Vector2f nLine{ m_vertices[vertexNumbers[indices[n]]].position - m_vertices[vertexNumbers[indices[i]]].position }; + + if (isSecondVectorAntiClockwiseOfFirstVector(pLine, nLine)) + { + reflex.erase(reflexIt); + convex.push_back(indices[i]); + } + } + + std::vector::iterator convexIt{ std::find(convex.begin(), convex.end(), indices[i]) }; + if (convexIt != convex.end()) + { + // if convex, re-test for ear only (must still be convex) + const bool isNowEar{ isEar(indices[i], indices[p], indices[n], indices[current]) }; + const std::vector::iterator it{ std::find(ear.begin(), ear.end(), indices[i]) }; + if (isNowEar && (it == ear.end())) + ear.push_back(indices[i]); + else if (!isNowEar && (it != ear.end())) + ear.erase(it); + } + }; + + std::function analysePoints = + [&]() + { + for (std::size_t i{ 0u }; i < indicesSize; ++i) + { + const std::size_t prev{ (i > 0u) ? (i - 1u) : (indicesSize - 1u) }; + const std::size_t next{ (i < (indicesSize - 1u)) ? (i + 1u) : 0u }; + + const sf::Vector2f prevLine{ m_vertices[vertexNumbers[indices[i]]].position - m_vertices[vertexNumbers[indices[prev]]].position }; + const sf::Vector2f nextLine{ m_vertices[vertexNumbers[indices[next]]].position - m_vertices[vertexNumbers[indices[i]]].position }; + + if (!isSecondVectorAntiClockwiseOfFirstVector(prevLine, nextLine)) + reflex.push_back(indices[i]); + else + { + convex.push_back(indices[i]); + if (isEarAnalysis(indices[i], indices[prev], indices[next])) + ear.push_back(indices[i]); + } + } + }; + + reflex.reserve(m_vertices.size() - 3u); // impossible for vertices to be reflex without enough convex (need at least 3 convex to make a polygon) + convex.reserve(m_vertices.size()); // any number (up to all) of the vertices may be convex although at least 3 are required + ear.reserve(m_vertices.size() - 2u); // with one ear per vertex, the final ear requires 3 vertices + + analysePoints(); + + if (!m_holeStartIndices.empty()) + { + struct Hole + { + std::size_t start; + std::size_t length; + float maxX; + }; + std::vector holeInfo(m_holeStartIndices.size()); + + for (std::size_t h{ 0u }; h < holeInfo.size(); ++h) + { + holeInfo[h].start = m_holeStartIndices[h] - vertexNumbersSize; + if (h < (holeInfo.size() - 1u)) + holeInfo[h].length = m_holeStartIndices[h + 1u] - m_holeStartIndices[h]; + else + holeInfo[h].length = holeVertexNumbersSize - (m_holeStartIndices[h] - vertexNumbersSize); + holeInfo[h].maxX = m_vertices[holeVertexNumbers[holeInfo[h].start]].position.x; + for (std::size_t v{ 1u }; v < holeInfo[h].length; ++v) + holeInfo[h].maxX = std::max(holeInfo[h].maxX, m_vertices[holeVertexNumbers[holeInfo[h].start + v]].position.x); + } + // sort order from the furthest right so that first hole is furthest right + std::sort(holeInfo.begin(), holeInfo.end(), [](const Hole& left, const Hole& right) { return left.maxX > right.maxX; }); + + + float vertexMinX{ m_vertices[0u].position.x }; + float vertexMaxX{ m_vertices[0u].position.x }; + for (std::size_t v{ 1u }; v < m_vertices.size(); ++v) + { + vertexMinX = std::min(vertexMinX, m_vertices[v].position.x); + vertexMaxX = std::max(vertexMaxX, m_vertices[v].position.x); + } + const float maxWidth{ vertexMaxX - vertexMinX }; + + const sf::Vector2f rayVector{ 1.f, 0.f }; + + for (std::size_t h{ 0u }; h < holeInfo.size(); ++h) + { + const std::size_t holeStart{ holeInfo[h].start }; + const std::size_t holeLength{ holeInfo[h].length }; + + // choose where the cut appears + std::size_t cutPolygonVertexNumber; + std::size_t cutHoleVertexNumber; + std::size_t cutHoleHoleIndex; + + + + // hole vertex (the easy bit) + float furthestRight{ m_vertices[holeVertexNumbers[holeStart]].position.x }; + for (std::size_t v{ 1u }; v < holeLength; ++v) + { + const float currentRight{ m_vertices[holeVertexNumbers[holeStart + v]].position.x }; + if (currentRight > furthestRight) + { + furthestRight = currentRight; + cutHoleHoleIndex = holeStart + v; + } + } + cutHoleVertexNumber = holeVertexNumbers[cutHoleHoleIndex]; + + + + // polygon vertex (the hard bit) + const sf::Vector2f rayOrigin{ m_vertices[cutHoleVertexNumber].position }; + sf::Vector2f pointOfIntersection{ 0.f, 0.f }; + + // find closest edge (to the right) + std::size_t candidateIndex{ 0u }; + float distance{ maxWidth }; + for (std::size_t v{ 0u }; v < vertexNumbersSize; ++v) + { + const std::size_t edgeStartIndex{ v }; + const std::size_t edgeEndIndex{ (v < (vertexNumbersSize - 1u)) ? v + 1u : 0u }; + + const sf::Vector2f edgeStart{ m_vertices[vertexNumbers[edgeStartIndex]].position }; + const sf::Vector2f edgeEnd{ m_vertices[vertexNumbers[edgeEndIndex]].position }; + const sf::Vector2f edgeVector{ edgeEnd - edgeStart }; + + if (((edgeStart.x < rayOrigin.x) && (edgeEnd.x < rayOrigin.x)) || (edgeStart.y < rayOrigin.y) || (edgeEnd.y > rayOrigin.y)) + continue; + + // calculate distance (of intersection of edge) + const float d{ crossProduct((edgeStart - rayOrigin), edgeVector) / crossProduct(rayVector, edgeVector) }; + + if (d < distance) + { + distance = d; + if (edgeStart.x > edgeEnd.x) + candidateIndex = edgeStartIndex; + else + candidateIndex = edgeEndIndex; + pointOfIntersection = { rayOrigin.x + d, rayOrigin.y }; + } + } + + const std::size_t candidateVertexNumber{ vertexNumbers[candidateIndex] }; + std::vector insideTriangle; + for (auto& r : reflex) + { + if ((candidateIndex == r) || (r >= vertexNumbersSize)) + continue; + + if (pointIsInsideTriangle({ m_vertices[candidateVertexNumber].position, rayOrigin, pointOfIntersection }, m_vertices[vertexNumbers[r]].position)) + insideTriangle.push_back(r); + } + + if (insideTriangle.empty()) + cutPolygonVertexNumber = vertexNumbers[candidateIndex]; + else + { + // choose the closest point to the ray origin within the triangle formed by the ray to intersection and the candidate vertex + float distanceSquared{ maxWidth * maxWidth }; + for (auto& inside : insideTriangle) + { + const float thisLengthSquared{ lengthSquared(m_vertices[vertexNumbers[inside]].position - rayOrigin) }; + if (thisLengthSquared < distanceSquared) + { + distanceSquared = thisLengthSquared; + cutPolygonVertexNumber = vertexNumbers[inside]; + } + } + } + + + + // automatically insert vertices for the cut + const std::size_t holeIndexOffsetCut{ cutHoleHoleIndex - holeStart }; + // prepare vertices to insert around the cut + std::vector holeInsertVertices(holeLength + 2u); + holeInsertVertices[0u] = cutPolygonVertexNumber; + for (std::size_t i{ 0u }; i <= holeLength; ++i) + holeInsertVertices[i + 1u] = holeVertexNumbers[holeStart + ((holeIndexOffsetCut + i) % holeLength)]; + // then add them around the cut + vertexNumbers.insert(std::find(vertexNumbers.begin(), vertexNumbers.end(), cutPolygonVertexNumber), holeInsertVertices.begin(), holeInsertVertices.end()); + + // indices for each of the vertex numbers (allowing re-using of vertices - needed for cutting polygon) + vertexNumbersSize = vertexNumbers.size(); + indices.resize(vertexNumbersSize); + indicesSize = indices.size(); + for (std::size_t i{ 0u }; i < indicesSize; ++i) + indices[i] = i; + + + + //clear lists to allow re-analysis of entire new arrangement + reflex.clear(); + convex.clear(); + ear.clear(); + + // re-analyse points + analysePoints(); + } + } + + + + // avoid movement in memory when resizing + m_triangles.clear(); + m_triangles.reserve(m_vertices.size() - 2u); + + + + // process + while (indices.size() > 3u) + { + std::size_t currentPoint{ ear.front() }; + std::vector::iterator currentIt{ std::find(indices.begin(), indices.end(), currentPoint) }; + std::size_t current{ static_cast(std::distance(indices.begin(), currentIt)) }; + std::size_t prev{ (current > 0u) ? (current - 1u) : (indices.size() - 1u) }; + std::size_t next{ (current < (indices.size() - 1u)) ? (current + 1u) : 0u }; + + TriangleIndices triangle{ vertexNumbers[indices[prev]], vertexNumbers[indices[current]], vertexNumbers[indices[next]] }; + m_triangles.push_back(triangle); + + retest(prev, ((prev > 0u) ? (prev - 1u) : (indices.size() - 1u)), next, current); + retest(next, prev, ((next < (indices.size() - 1u)) ? (next + 1u) : 0u), current); + + // remove current (the one we clipped) + convex.erase(std::find(convex.begin(), convex.end(), indices[current])); + ear.erase(std::find(ear.begin(), ear.end(), indices[current])); + indices.erase(currentIt); + + if (m_triangles.size() == stopAfterThisNumberOfTrianglesHaveBeenCreated) + break; + } + + // 3 vertices remaining; add final triangle + if (m_triangles.size() < stopAfterThisNumberOfTrianglesHaveBeenCreated) + { + TriangleIndices triangle{ vertexNumbers[indices[0u]], vertexNumbers[indices[1u]], vertexNumbers[indices[2u]] }; + m_triangles.push_back(triangle); } } diff --git a/src/SelbaWard/Polygon.hpp b/src/SelbaWard/Polygon.hpp index 1ec47db..5dddb8b 100644 --- a/src/SelbaWard/Polygon.hpp +++ b/src/SelbaWard/Polygon.hpp @@ -39,13 +39,14 @@ namespace selbaward { -// SW Polygon v1.1.1 +// SW Polygon v1.2 class Polygon : public sf::Drawable, public sf::Transformable { public: enum class TriangulationMethod { BasicEarClip, + EarClip, }; enum class MeshRefinementMethod { @@ -76,6 +77,14 @@ class Polygon : public sf::Drawable, public sf::Transformable void importVertexPositions(const std::vector& position); std::vector exportTriangulatedPositions() const; + // holes must not overlap and must be specified in opposite direction to outer polygon + void addHoleStartIndex(std::size_t index); + void clearHoleStartIndices(); + void setHoleStartIndices(const std::vector& indices); + + + + @@ -85,6 +94,7 @@ class Polygon : public sf::Drawable, public sf::Transformable std::vector m_vertices; std::vector m_triangles; std::vector m_outputVertices; + std::vector m_holeStartIndices; sf::Color m_color; TriangulationMethod m_triangulationMethod; @@ -96,6 +106,7 @@ class Polygon : public sf::Drawable, public sf::Transformable void priv_update(); void priv_updateOutputVertices(); void priv_triangulate(); + void priv_triangulateEarClip(); void priv_triangulateBasicEarClip(); bool priv_isValidVertexIndex(std::size_t vertexIndex) const; bool priv_testVertexIndex(std::size_t vertexIndex, const std::string& exceptionMessage) const; From e99798d017a4ecd9e8b09e414f51e1dd21b15406 Mon Sep 17 00:00:00 2001 From: Hapaxia Date: Mon, 26 Jun 2023 03:37:46 +0100 Subject: [PATCH 41/64] Merge pull request #37 from Hapaxia/Polygon_v1-2 Polygon-update to v1.2 --- src/SelbaWard/Polygon.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/SelbaWard/Polygon.cpp b/src/SelbaWard/Polygon.cpp index fb9d67f..88c75be 100644 --- a/src/SelbaWard/Polygon.cpp +++ b/src/SelbaWard/Polygon.cpp @@ -82,6 +82,16 @@ inline float lengthSquared(const sf::Vector2f& a) return (a.x * a.x) + (a.y * a.y); } +inline float crossProduct(const sf::Vector2f& a, const sf::Vector2f& b) +{ + return (a.x * b.y) - (a.y * b.x); +} + +inline float lengthSquared(const sf::Vector2f& a) +{ + return (a.x * a.x) + (a.y * a.y); +} + } // namespace namespace selbaward From 5dd95fd24f38430b9556eadfa0ef085afe7764f8 Mon Sep 17 00:00:00 2001 From: Hapaxia Date: Tue, 27 Jun 2023 17:34:13 +0100 Subject: [PATCH 42/64] Polygon-update to v1.2.1 patch update. fixes some miscalculations of multiple holes under certain conditions that could cause attempting to access elements of an empty vector. --- src/SelbaWard/Polygon.cpp | 19 +++++++++++++++++-- src/SelbaWard/Polygon.hpp | 2 +- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/src/SelbaWard/Polygon.cpp b/src/SelbaWard/Polygon.cpp index 88c75be..5834013 100644 --- a/src/SelbaWard/Polygon.cpp +++ b/src/SelbaWard/Polygon.cpp @@ -459,6 +459,7 @@ void Polygon::priv_triangulateEarClip() // find closest edge (to the right) std::size_t candidateIndex{ 0u }; float distance{ maxWidth }; + bool isEndIndex{ false }; for (std::size_t v{ 0u }; v < vertexNumbersSize; ++v) { const std::size_t edgeStartIndex{ v }; @@ -480,7 +481,10 @@ void Polygon::priv_triangulateEarClip() if (edgeStart.x > edgeEnd.x) candidateIndex = edgeStartIndex; else + { candidateIndex = edgeEndIndex; + isEndIndex = true; + } pointOfIntersection = { rayOrigin.x + d, rayOrigin.y }; } } @@ -489,7 +493,7 @@ void Polygon::priv_triangulateEarClip() std::vector insideTriangle; for (auto& r : reflex) { - if ((candidateIndex == r) || (r >= vertexNumbersSize)) + if ((candidateIndex == r) || (vertexNumbers[r] >= vertexNumbersSize)) continue; if (pointIsInsideTriangle({ m_vertices[candidateVertexNumber].position, rayOrigin, pointOfIntersection }, m_vertices[vertexNumbers[r]].position)) @@ -509,6 +513,7 @@ void Polygon::priv_triangulateEarClip() { distanceSquared = thisLengthSquared; cutPolygonVertexNumber = vertexNumbers[inside]; + isEndIndex = false; } } } @@ -523,7 +528,17 @@ void Polygon::priv_triangulateEarClip() for (std::size_t i{ 0u }; i <= holeLength; ++i) holeInsertVertices[i + 1u] = holeVertexNumbers[holeStart + ((holeIndexOffsetCut + i) % holeLength)]; // then add them around the cut - vertexNumbers.insert(std::find(vertexNumbers.begin(), vertexNumbers.end(), cutPolygonVertexNumber), holeInsertVertices.begin(), holeInsertVertices.end()); + if (isEndIndex) + { + vertexNumbers.insert(std::find(vertexNumbers.begin(), vertexNumbers.end(), cutPolygonVertexNumber), holeInsertVertices.begin(), holeInsertVertices.end()); + } + else + { + std::vector::reverse_iterator vnRIt{ std::find(vertexNumbers.rbegin(), vertexNumbers.rend(), cutPolygonVertexNumber) }; + std::vector::iterator vnIt{ (vnRIt + 1u).base() }; + //vertexNumbers.insert(std::find(vertexNumbers.rbegin(), vertexNumbers.rend(), cutPolygonVertexNumber).base() + 1u, holeInsertVertices.begin(), holeInsertVertices.end()); + vertexNumbers.insert(vnIt, holeInsertVertices.begin(), holeInsertVertices.end()); + } // indices for each of the vertex numbers (allowing re-using of vertices - needed for cutting polygon) vertexNumbersSize = vertexNumbers.size(); diff --git a/src/SelbaWard/Polygon.hpp b/src/SelbaWard/Polygon.hpp index 5dddb8b..1f6e295 100644 --- a/src/SelbaWard/Polygon.hpp +++ b/src/SelbaWard/Polygon.hpp @@ -39,7 +39,7 @@ namespace selbaward { -// SW Polygon v1.2 +// SW Polygon v1.2.1 class Polygon : public sf::Drawable, public sf::Transformable { public: From 4c2a038fb421c57a7b265408504749ba03949bc3 Mon Sep 17 00:00:00 2001 From: Hapaxia Date: Tue, 27 Jun 2023 17:38:47 +0100 Subject: [PATCH 43/64] Merge pull request #38 from Hapaxia/Polygon_v1-2 Polygon-update to v1.2.1 From 378f3477a0bd5d90b6f007805a39d64083f1bd1e Mon Sep 17 00:00:00 2001 From: Hapaxia Date: Tue, 27 Jun 2023 17:44:29 +0100 Subject: [PATCH 44/64] Polygon-update to v1.2.2 quick patch update that fixes an un-initialised variable that may get used without being assigned a value. --- src/SelbaWard/Polygon.cpp | 2 +- src/SelbaWard/Polygon.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/SelbaWard/Polygon.cpp b/src/SelbaWard/Polygon.cpp index 5834013..c7acbb6 100644 --- a/src/SelbaWard/Polygon.cpp +++ b/src/SelbaWard/Polygon.cpp @@ -433,7 +433,7 @@ void Polygon::priv_triangulateEarClip() // choose where the cut appears std::size_t cutPolygonVertexNumber; std::size_t cutHoleVertexNumber; - std::size_t cutHoleHoleIndex; + std::size_t cutHoleHoleIndex{ holeStart }; diff --git a/src/SelbaWard/Polygon.hpp b/src/SelbaWard/Polygon.hpp index 1f6e295..52676fb 100644 --- a/src/SelbaWard/Polygon.hpp +++ b/src/SelbaWard/Polygon.hpp @@ -39,7 +39,7 @@ namespace selbaward { -// SW Polygon v1.2.1 +// SW Polygon v1.2.2 class Polygon : public sf::Drawable, public sf::Transformable { public: From fd119a7df09548bdf5771c76084a5961bdb19292 Mon Sep 17 00:00:00 2001 From: Hapaxia Date: Tue, 27 Jun 2023 17:44:49 +0100 Subject: [PATCH 45/64] Merge pull request #39 from Hapaxia/Polygon_v1-2 Polygon-update to v1.2.2 From 95c68b2904b6033bec40adc5dac76111ca26c8ea Mon Sep 17 00:00:00 2001 From: Hapaxia Date: Tue, 27 Jun 2023 18:09:45 +0100 Subject: [PATCH 46/64] Polygon-update to v1.2.3 now throws a Selba Ward exception showing an error code instead of attempting to access an empty vector (during the update method). this allows both: reporting an error for investigation and catching the error suring runtime to avoid invalid use. to catch this exception, simply put the update() method in a try block. remember to reset any changes before attempting to update again (e.g. if you've changed a vertex position before the update that failed, change the vertex position back to what it was before) --- src/SelbaWard/Polygon.cpp | 3 +++ src/SelbaWard/Polygon.hpp | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/SelbaWard/Polygon.cpp b/src/SelbaWard/Polygon.cpp index c7acbb6..25db674 100644 --- a/src/SelbaWard/Polygon.cpp +++ b/src/SelbaWard/Polygon.cpp @@ -570,6 +570,9 @@ void Polygon::priv_triangulateEarClip() // process while (indices.size() > 3u) { + if (ear.empty()) + throw Exception("Polygon - ERROR: 0001"); + std::size_t currentPoint{ ear.front() }; std::vector::iterator currentIt{ std::find(indices.begin(), indices.end(), currentPoint) }; std::size_t current{ static_cast(std::distance(indices.begin(), currentIt)) }; diff --git a/src/SelbaWard/Polygon.hpp b/src/SelbaWard/Polygon.hpp index 52676fb..09c391d 100644 --- a/src/SelbaWard/Polygon.hpp +++ b/src/SelbaWard/Polygon.hpp @@ -39,7 +39,7 @@ namespace selbaward { -// SW Polygon v1.2.2 +// SW Polygon v1.2.3 class Polygon : public sf::Drawable, public sf::Transformable { public: From 2ac35431b5bf49d66f887bbd1f8f6c97ced0ff50 Mon Sep 17 00:00:00 2001 From: Hapaxia Date: Tue, 27 Jun 2023 18:09:54 +0100 Subject: [PATCH 47/64] Merge pull request #40 from Hapaxia/Polygon_v1-2 Polygon-update to v1.2.3 From fb3582a4ca813f0c3acd909a410f3f1fbdd312ba Mon Sep 17 00:00:00 2001 From: Hapaxia Date: Sun, 12 Nov 2023 20:34:31 +0000 Subject: [PATCH 48/64] Spline - add manipulations add manipulations: move and scale to join the rotate manipulation. move moves all the vertices by the given offset. scale scales all the vertices by the scale factor with the given origin. the thickness and handle lengths can also be scaled by the same factor (both are scaled by default). --- src/SelbaWard/Spline.cpp | 62 +++++++++++++++++----------------------- src/SelbaWard/Spline.hpp | 8 +++--- 2 files changed, 31 insertions(+), 39 deletions(-) diff --git a/src/SelbaWard/Spline.cpp b/src/SelbaWard/Spline.cpp index 0c7a243..5bae1d4 100644 --- a/src/SelbaWard/Spline.cpp +++ b/src/SelbaWard/Spline.cpp @@ -237,7 +237,7 @@ Spline::Spline(const Spline& spline) m_handlesVertices = spline.m_handlesVertices; } -void Spline::operator=(const Spline& spline) +Spline& Spline::operator=(const Spline& spline) { m_throwExceptions = spline.m_throwExceptions; m_isClosed = spline.m_isClosed; @@ -249,21 +249,21 @@ void Spline::operator=(const Spline& spline) m_roundedThickStartCapInterpolationLevel = spline.m_roundedThickStartCapInterpolationLevel; m_roundedThickEndCapInterpolationLevel = spline.m_roundedThickEndCapInterpolationLevel; m_maxPointLength = spline.m_maxPointLength; + m_vertices = spline.m_vertices; m_color = spline.m_color; m_thickness = spline.m_thickness; m_randomNormalOffsetRange = spline.m_randomNormalOffsetRange; + m_interpolatedVerticesUnitTangents = spline.m_interpolatedVerticesUnitTangents; + m_outputVertices = spline.m_outputVertices; m_primitiveType = spline.m_primitiveType; m_interpolationSteps = spline.m_interpolationSteps; m_useBezier = spline.m_useBezier; + m_handlesVertices = spline.m_handlesVertices; m_showHandles = spline.m_showHandles; m_lockHandleMirror = spline.m_lockHandleMirror; m_lockHandleAngle = spline.m_lockHandleAngle; - m_vertices = spline.m_vertices; - m_interpolatedVertices = spline.m_interpolatedVertices; - m_interpolatedVerticesUnitTangents = spline.m_interpolatedVerticesUnitTangents; - m_outputVertices = spline.m_outputVertices; - m_handlesVertices = spline.m_handlesVertices; + return *this; } float Spline::getLength() const @@ -377,35 +377,6 @@ void Spline::updateOutputVertices() priv_updateOutputVertices(); } -Spline& Spline::operator=(const Spline& spline) -{ - m_throwExceptions = spline.m_throwExceptions; - m_isClosed = spline.m_isClosed; - m_isRandomNormalOffsetsActivated = spline.m_isRandomNormalOffsetsActivated; - m_thickCornerType = spline.m_thickCornerType; - m_thickStartCapType = spline.m_thickStartCapType; - m_thickEndCapType = spline.m_thickEndCapType; - m_roundedThickCornerInterpolationLevel = spline.m_roundedThickCornerInterpolationLevel; - m_roundedThickStartCapInterpolationLevel = spline.m_roundedThickStartCapInterpolationLevel; - m_roundedThickEndCapInterpolationLevel = spline.m_roundedThickEndCapInterpolationLevel; - m_maxPointLength = spline.m_maxPointLength; - m_vertices = spline.m_vertices; - m_color = spline.m_color; - m_thickness = spline.m_thickness; - m_randomNormalOffsetRange = spline.m_randomNormalOffsetRange; - m_interpolatedVerticesUnitTangents = spline.m_interpolatedVerticesUnitTangents; - m_outputVertices = spline.m_outputVertices; - m_primitiveType = spline.m_primitiveType; - m_interpolationSteps = spline.m_interpolationSteps; - m_useBezier = spline.m_useBezier; - m_handlesVertices = spline.m_handlesVertices; - m_showHandles = spline.m_showHandles; - m_lockHandleMirror = spline.m_lockHandleMirror; - m_lockHandleAngle = spline.m_lockHandleAngle; - - return *this; -} - void Spline::connectFrontToFrontOf(const Spline& spline, const bool rotateSpline, const bool moveSpline) { if (!moveSpline && !rotateSpline) @@ -580,6 +551,27 @@ void Spline::rotate(const float angle, const sf::Vector2f origin) } } +void Spline::scale(const float scale, const sf::Vector2f origin, const bool scaleThickness, const bool scaleHandles) +{ + for (auto& vertex : m_vertices) + { + vertex.position = ((vertex.position - origin) * scale) + origin; + if (scaleHandles) + { + vertex.frontHandle *= scale; + vertex.backHandle *= scale; + } + } + if (scaleThickness) + m_thickness *= scale; +} + +void Spline::move(const sf::Vector2f offset) +{ + for (auto& vertex : m_vertices) + vertex.position += offset; +} + void Spline::setRandomNormalOffsetsActivated(const bool randomNormalOffsetsActivated) { m_isRandomNormalOffsetsActivated = randomNormalOffsetsActivated; diff --git a/src/SelbaWard/Spline.hpp b/src/SelbaWard/Spline.hpp index 8b9fb6a..e573c7d 100644 --- a/src/SelbaWard/Spline.hpp +++ b/src/SelbaWard/Spline.hpp @@ -38,7 +38,7 @@ namespace selbaward { -// SW Spline v1.6.3 +// SW Spline v1.7.0- class Spline : public sf::Drawable { public: @@ -71,13 +71,11 @@ class Spline : public sf::Drawable Spline(std::size_t vertexCount = 0u, sf::Vector2f initialPosition = { 0.f, 0.f }); Spline(std::initializer_list list); // pass vertices' positions (sf::Vector2f) to the constructor (sets size automatically) Spline(const Spline& spline); - void operator=(const Spline& spline); + Spline& operator=(const Spline& spline); void update(); void updateOutputVertices(); - Spline& operator=(const Spline& spline); - Vertex& operator[] (std::size_t index); // direct access to the spline's vertices (sw::Spline::Vertex) using the [] operator. no checks are performed. using with an invalid index results in undefined behaviour void connectFrontToFrontOf(const Spline& spline, bool rotateSpline = true, bool moveSpline = true); @@ -97,6 +95,8 @@ class Spline : public sf::Drawable bool getClosed() const; void rotate(float rotation, sf::Vector2f origin); + void scale(float scale, sf::Vector2f origin, bool scaleThickness = true, bool scaleHandles = true); + void move(sf::Vector2f offset); void setRandomNormalOffsetsActivated(bool randomNormalOffsetsActivated); bool getRandomNormalOffsetsActivated() const; From d72792e8c9414df46bb5067703b382baec49347a Mon Sep 17 00:00:00 2001 From: Hapaxia Date: Sun, 12 Nov 2023 21:27:35 +0000 Subject: [PATCH 49/64] update code - bitmap text/font update the code of bitmap text and bitmap font to be more consistent with Selba Ward style and reduce needs for casting. --- src/SelbaWard/BitmapFont.cpp | 78 ++++++++++++++++++------------------ src/SelbaWard/BitmapFont.hpp | 40 +++++++++--------- src/SelbaWard/BitmapText.cpp | 63 +++++++++++++++-------------- src/SelbaWard/BitmapText.hpp | 4 +- 4 files changed, 93 insertions(+), 92 deletions(-) diff --git a/src/SelbaWard/BitmapFont.cpp b/src/SelbaWard/BitmapFont.cpp index 01e3bd3..1e91196 100644 --- a/src/SelbaWard/BitmapFont.cpp +++ b/src/SelbaWard/BitmapFont.cpp @@ -78,7 +78,7 @@ void BitmapFont::setSmooth(const bool smooth) m_texture.setSmooth(smooth); } -void BitmapFont::setNumberOfTilesPerRow(const unsigned int numberOfTilesPerRow) +void BitmapFont::setNumberOfTilesPerRow(const std::size_t numberOfTilesPerRow) { m_numberOfTilesPerRow = numberOfTilesPerRow; } @@ -105,7 +105,7 @@ void BitmapFont::setDefaultTextureRect(const sf::IntRect& defaultTextureRect) m_defaultTextureRect = defaultTextureRect; } -void BitmapFont::setTextureRect(const sf::IntRect& textureRect, const unsigned int glyphIndex) +void BitmapFont::setTextureRect(const sf::IntRect& textureRect, const std::size_t glyphIndex) { if (!priv_isGlyphIndexValid(glyphIndex)) { @@ -114,20 +114,20 @@ void BitmapFont::setTextureRect(const sf::IntRect& textureRect, const unsigned i return; } - m_glyphs[glyphIndex].useDefaultTextureRect = false;; + m_glyphs[glyphIndex].useDefaultTextureRect = false; m_glyphs[glyphIndex].textureRect = textureRect; m_glyphs[glyphIndex].width = textureRect.width; m_glyphs[glyphIndex].baseline = textureRect.height - 1; m_glyphs[glyphIndex].startX = 0; } -void BitmapFont::setTextureRects(const std::vector& textureRects, const unsigned int initialGlyphIndex) +void BitmapFont::setTextureRects(const std::vector& textureRects, const std::size_t initialGlyphIndex) { - for (unsigned int i{ 0 }; i < textureRects.size(); ++i) + for (std::size_t i{ 0u }; i < textureRects.size(); ++i) setTextureRect(textureRects[i], initialGlyphIndex + i); } -void BitmapFont::clearTextureRect(const unsigned int glyphIndex) +void BitmapFont::clearTextureRect(const std::size_t glyphIndex) { if (!priv_isGlyphIndexValid(glyphIndex)) { @@ -141,7 +141,7 @@ void BitmapFont::clearTextureRect(const unsigned int glyphIndex) void BitmapFont::clearAllTextureRects() { - for (unsigned int i{ 0 }; i < m_glyphs.size(); ++i) + for (std::size_t i{ 0u }; i < m_glyphs.size(); ++i) clearTextureRect(i); } @@ -150,7 +150,7 @@ void BitmapFont::clearAllTextureRects() -void BitmapFont::setGlyphToDefault(const unsigned int glyphIndex) +void BitmapFont::setGlyphToDefault(const std::size_t glyphIndex) { if (!priv_isGlyphIndexValid(glyphIndex)) { @@ -166,15 +166,15 @@ void BitmapFont::setGlyphToDefault(const unsigned int glyphIndex) m_glyphs[glyphIndex].startX = 0; } -void BitmapFont::setGlyphsToDefault(const unsigned int numberOfGlyphs, const unsigned int initialGlyphIndex) +void BitmapFont::setGlyphsToDefault(const std::size_t numberOfGlyphs, const std::size_t initialGlyphIndex) { - for (unsigned int i{ 0 }; i < numberOfGlyphs; ++i) + for (std::size_t i{ 0u }; i < numberOfGlyphs; ++i) setGlyphToDefault(initialGlyphIndex + i); } void BitmapFont::setAllGlyphsToDefault() { - setGlyphsToDefault(static_cast(m_glyphs.size())); + setGlyphsToDefault(m_glyphs.size()); } @@ -185,7 +185,7 @@ void BitmapFont::setAllGlyphsToDefault() -void BitmapFont::setBaseline(const int baseline, const unsigned int glyphIndex) +void BitmapFont::setBaseline(const int baseline, const std::size_t glyphIndex) { if (!priv_isGlyphIndexValid(glyphIndex)) { @@ -197,7 +197,7 @@ void BitmapFont::setBaseline(const int baseline, const unsigned int glyphIndex) m_glyphs[glyphIndex].baseline = baseline; } -void BitmapFont::setWidth(const int width, const unsigned int glyphIndex) +void BitmapFont::setWidth(const int width, const std::size_t glyphIndex) { if (!priv_isGlyphIndexValid(glyphIndex)) { @@ -209,7 +209,7 @@ void BitmapFont::setWidth(const int width, const unsigned int glyphIndex) m_glyphs[glyphIndex].width = width; } -void BitmapFont::setStartX(const int startX, const unsigned int glyphIndex) +void BitmapFont::setStartX(const int startX, const std::size_t glyphIndex) { if (!priv_isGlyphIndexValid(glyphIndex)) { @@ -221,39 +221,39 @@ void BitmapFont::setStartX(const int startX, const unsigned int glyphIndex) m_glyphs[glyphIndex].startX = startX; } -void BitmapFont::setBaselines(const int baseline, const unsigned int numberOfGlyphs, const unsigned int initialGlyphIndex) +void BitmapFont::setBaselines(const int baseline, const std::size_t numberOfGlyphs, const std::size_t initialGlyphIndex) { - for (unsigned int i{ 0 }; i < numberOfGlyphs; ++i) + for (std::size_t i{ 0u }; i < numberOfGlyphs; ++i) setBaseline(baseline, initialGlyphIndex + i); } -void BitmapFont::setWidths(const int width, const unsigned int numberOfGlyphs, const unsigned int initialGlyphIndex) +void BitmapFont::setWidths(const int width, const std::size_t numberOfGlyphs, const std::size_t initialGlyphIndex) { - for (unsigned int i{ 0 }; i < numberOfGlyphs; ++i) + for (std::size_t i{ 0u }; i < numberOfGlyphs; ++i) setWidth(width, initialGlyphIndex + i); } -void BitmapFont::setStartXs(const int startX, const unsigned int numberOfGlyphs, const unsigned int initialGlyphIndex) +void BitmapFont::setStartXs(const int startX, const std::size_t numberOfGlyphs, const std::size_t initialGlyphIndex) { - for (unsigned int i{ 0 }; i < numberOfGlyphs; ++i) + for (std::size_t i{ 0u }; i < numberOfGlyphs; ++i) setStartX(startX, initialGlyphIndex + i); } -void BitmapFont::setBaselines(const std::vector& baselines, const unsigned int initialGlyphIndex) +void BitmapFont::setBaselines(const std::vector& baselines, const std::size_t initialGlyphIndex) { - for (unsigned int i{ 0 }; i < baselines.size(); ++i) + for (std::size_t i{ 0u }; i < baselines.size(); ++i) setBaseline(baselines[i], initialGlyphIndex + i); } -void BitmapFont::setWidths(const std::vector& widths, const unsigned int initialGlyphIndex) +void BitmapFont::setWidths(const std::vector& widths, const std::size_t initialGlyphIndex) { - for (unsigned int i{ 0 }; i < widths.size(); ++i) + for (std::size_t i{ 0u }; i < widths.size(); ++i) setWidth(widths[i], initialGlyphIndex + i); } -void BitmapFont::setStartXs(const std::vector& startXs, const unsigned int initialGlyphIndex) +void BitmapFont::setStartXs(const std::vector& startXs, const std::size_t initialGlyphIndex) { - for (unsigned int i{ 0 }; i < startXs.size(); ++i) + for (std::size_t i{ 0u }; i < startXs.size(); ++i) setStartX(startXs[i], initialGlyphIndex + i); } @@ -277,17 +277,17 @@ void BitmapFont::setStartX(const int startX, const std::string& glyphs) void BitmapFont::setKerning(const int kerning, const std::string& glyphs) { - if (glyphs.size() < 2) + if (glyphs.size() < 2u) { if (m_throwExceptions) throw Exception(exceptionPrefix + "cannot set kerning - glyph pair not specified."); return; } - for (std::size_t i{ 0u }; i < glyphs.size(); i += 2) + for (std::size_t i{ 0u }; i < glyphs.size(); i += 2u) { - std::string glyphPair{ glyphs.substr(i, 2) }; - if (glyphPair.size() != 2) + std::string glyphPair{ glyphs.substr(i, 2u) }; + if (glyphPair.size() != 2u) { if (m_throwExceptions) throw Exception(exceptionPrefix + "cannot set kerning - final glyph pair is missing second glyph."); @@ -311,7 +311,7 @@ const sf::Texture* BitmapFont::getTexture() const return &m_texture; } -const BitmapFont::Glyph BitmapFont::getGlyph(const unsigned int glyphIndex) const +const BitmapFont::Glyph BitmapFont::getGlyph(const std::size_t glyphIndex) const { if (!priv_isGlyphIndexValid(glyphIndex)) { @@ -326,14 +326,14 @@ const BitmapFont::Glyph BitmapFont::getGlyph(const unsigned int glyphIndex) cons return m_glyphs[glyphIndex]; } -const unsigned int BitmapFont::getNumberOfGlyphs() const +const std::size_t BitmapFont::getNumberOfGlyphs() const { - return static_cast(m_glyphs.size()); + return m_glyphs.size(); } const int BitmapFont::getKerning(const std::string& glyphPair) const { - if (glyphPair.size() != 2) + if (glyphPair.size() != 2u) { if (m_throwExceptions) throw Exception(exceptionPrefix + "cannot get kerning - glyph pair not valid."); @@ -354,7 +354,7 @@ const int BitmapFont::getKerning(const std::string& glyphPair) const // PRIVATE -const bool BitmapFont::priv_isGlyphIndexValid(const unsigned int glyphIndex) const +const bool BitmapFont::priv_isGlyphIndexValid(const std::size_t glyphIndex) const { if (glyphIndex < m_glyphs.size()) return true; @@ -364,16 +364,16 @@ const bool BitmapFont::priv_isGlyphIndexValid(const unsigned int glyphIndex) con return false; } -const BitmapFont::Glyph BitmapFont::priv_getGlyphWithDefaultTextureRect(unsigned int glyphIndex) const +const BitmapFont::Glyph BitmapFont::priv_getGlyphWithDefaultTextureRect(std::size_t glyphIndex) const { if (!priv_isGlyphIndexValid(glyphIndex)) { if (m_throwExceptions) throw Exception(exceptionPrefix + "cannot get default glyph - glyph index (" + std::to_string(glyphIndex) + ") out of range."); - glyphIndex = 0; + glyphIndex = 0u; } - if (m_glyphs.size() == 0) + if (m_glyphs.empty()) throw Exception(exceptionPrefix + "BUG - no glyphs available."); Glyph defaultGlyph; @@ -389,7 +389,7 @@ const BitmapFont::Glyph BitmapFont::priv_getGlyphWithDefaultTextureRect(unsigned void BitmapFont::priv_setKerning(const int kerning, const std::string& glyphPair) { - if (glyphPair.size() != 2) + if (glyphPair.size() != 2u) { if (m_throwExceptions) throw Exception(exceptionPrefix + "cannot set kerning - glyph pair not valid."); diff --git a/src/SelbaWard/BitmapFont.hpp b/src/SelbaWard/BitmapFont.hpp index 2b28ea4..cde9b40 100644 --- a/src/SelbaWard/BitmapFont.hpp +++ b/src/SelbaWard/BitmapFont.hpp @@ -47,7 +47,7 @@ class BitmapFont public: struct Glyph { - bool useDefaultTextureRect = true; + bool useDefaultTextureRect{ true }; sf::IntRect textureRect; int width; // zero and below represent counting from full texture rect width e.g. 0 is full width, -1 is 1 less than full width. int baseline; // negative numbers represent counting from bottom e.g. -1 is bottom line, -2 is 1 above bottom. @@ -58,38 +58,38 @@ class BitmapFont // output const sf::Texture* getTexture() const; - const Glyph getGlyph(unsigned int glyphIndex = 0) const; - const unsigned int getNumberOfGlyphs() const; + const Glyph getGlyph(std::size_t glyphIndex = 0u) const; + const std::size_t getNumberOfGlyphs() const; const int getKerning(const std::string& glyphPair) const; // texture setup void setExternalTexture(const sf::Texture& externalTexture); void loadTexture(const std::string& filename); void setSmooth(bool smooth = true); - void setNumberOfTilesPerRow(unsigned int numberOfTilesPerRow); + void setNumberOfTilesPerRow(std::size_t numberOfTilesPerRow); // texture rect setup void setDefaultTextureRect(const sf::IntRect& defaultTextureRect); - void setTextureRect(const sf::IntRect& textureRect, unsigned int glyphIndex = 0); - void setTextureRects(const std::vector& textureRects, unsigned int initialGlyphIndex = 0); - void clearTextureRect(unsigned int glyphIndex); + void setTextureRect(const sf::IntRect& textureRect, std::size_t glyphIndex = 0u); + void setTextureRects(const std::vector& textureRects, std::size_t initialGlyphIndex = 0u); + void clearTextureRect(std::size_t glyphIndex); void clearAllTextureRects(); // glyph setup - void setGlyphToDefault(unsigned int glyphIndex = 0); - void setGlyphsToDefault(unsigned int numberOfGlyphs = 1, unsigned int glyphIndex = 0); + void setGlyphToDefault(std::size_t glyphIndex = 0u); + void setGlyphsToDefault(std::size_t numberOfGlyphs = 1u, std::size_t glyphIndex = 0u); void setAllGlyphsToDefault(); // glyph attribute setup - void setBaseline(int baseline, unsigned int glyphIndex = 0); - void setWidth(int width, unsigned int glyphIndex = 0); - void setStartX(int startX, unsigned int glyphIndex = 0); - void setBaselines(int baseline, unsigned int numberOfGlyphs = 1, unsigned int initialGlyphIndex = 0); - void setWidths(int width, unsigned int numberOfGlyphs = 1, unsigned int initialGlyphIndex = 0); - void setStartXs(int startX, unsigned int numberOfGlyphs = 1, unsigned int initialGlyphIndex = 0); - void setBaselines(const std::vector& baselines, unsigned int initialGlyphIndex = 0); - void setWidths(const std::vector& widths, unsigned int initialGlyphIndex = 0); - void setStartXs(const std::vector& startXs, unsigned int initialGlyphIndex = 0); + void setBaseline(int baseline, std::size_t glyphIndex = 0u); + void setWidth(int width, std::size_t glyphIndex = 0u); + void setStartX(int startX, std::size_t glyphIndex = 0u); + void setBaselines(int baseline, std::size_t numberOfGlyphs = 1u, std::size_t initialGlyphIndex = 0u); + void setWidths(int width, std::size_t numberOfGlyphs = 1u, std::size_t initialGlyphIndex = 0u); + void setStartXs(int startX, std::size_t numberOfGlyphs = 1u, std::size_t initialGlyphIndex = 0u); + void setBaselines(const std::vector& baselines, std::size_t initialGlyphIndex = 0u); + void setWidths(const std::vector& widths, std::size_t initialGlyphIndex = 0u); + void setStartXs(const std::vector& startXs, std::size_t initialGlyphIndex = 0u); void setBaseline(int baseline, const std::string& glyphs); void setWidth(int width, const std::string& glyphs); void setStartX(int startX, const std::string& glyphs); @@ -119,8 +119,8 @@ class BitmapFont mutable std::map m_kernings; std::vector m_glyphs; - const bool priv_isGlyphIndexValid(unsigned int glyphIndex) const; - const Glyph priv_getGlyphWithDefaultTextureRect(unsigned int glyphIndex = 0) const; + const bool priv_isGlyphIndexValid(std::size_t glyphIndex) const; + const Glyph priv_getGlyphWithDefaultTextureRect(std::size_t glyphIndex = 0u) const; void priv_setKerning(int kerning, const std::string& glyphs); // string must have length of 2 }; diff --git a/src/SelbaWard/BitmapText.cpp b/src/SelbaWard/BitmapText.cpp index da817cd..7cfe924 100644 --- a/src/SelbaWard/BitmapText.cpp +++ b/src/SelbaWard/BitmapText.cpp @@ -39,7 +39,7 @@ BitmapText::BitmapText() : m_pBitmapFont{ nullptr } , m_vertices(sf::PrimitiveType::Triangles) , m_string() - , m_color(sf::Color::White) + , m_color{ sf::Color::White } , m_tracking{ 1 } { } @@ -67,7 +67,7 @@ const std::string BitmapText::getString() const return m_string; } -void BitmapText::setTracking(int tracking) +void BitmapText::setTracking(const int tracking) { m_tracking = tracking; priv_updateVertices(); @@ -89,17 +89,17 @@ const sf::Color BitmapText::getColor() const return m_color; } -void BitmapText::setScale(unsigned int scale) +void BitmapText::setScale(const std::size_t scale) { setScale(scale, scale); } -void BitmapText::setScale(sf::Vector2u scale) +void BitmapText::setScale(const sf::Vector2u scale) { setScale(scale.x, scale.y); } -void BitmapText::setScale(unsigned int scaleX, unsigned int scaleY) +void BitmapText::setScale(const std::size_t scaleX, const std::size_t scaleY) { this->Transformable::setScale(static_cast(scaleX), static_cast(scaleY)); } @@ -140,59 +140,60 @@ void BitmapText::priv_updateVertices() sf::Vector2f penPosition{ 0.f, 0.f }; - float minX(0.f), minY(0.f), maxX(0.f), maxY(0.f); + sf::Vector2f min{ 0.f, 0.f }; + sf::Vector2f max{ 0.f, 0.f }; - for (unsigned int character{ 0 }; character < m_string.length(); ++character) + for (std::size_t character{ 0u }; character < m_string.length(); ++character) { - const unsigned int glyphNumber{ (m_string[character] >= 0) ? static_cast(m_string[character]) : static_cast(m_string[character] + 256) }; // after 125, 126, 127 is -128, -127, -126. this moves them to 128, 129, 130 + const std::size_t glyphNumber{ (m_string[character] >= 0u) ? static_cast(m_string[character]) : static_cast(m_string[character] + 256) }; // after 125, 126, 127 is -128, -127, -126. this moves them to 128, 129, 130 - const int kerning{ (character < m_string.length() - 1) ? m_pBitmapFont->getKerning(m_string.substr(character, 2)) : 0 }; + const int kerning{ (character < m_string.length() - 1u) ? m_pBitmapFont->getKerning(m_string.substr(character, 2u)) : 0 }; - BitmapFont::Glyph glyph = m_pBitmapFont->getGlyph(glyphNumber); + BitmapFont::Glyph glyph{ m_pBitmapFont->getGlyph(glyphNumber) }; const sf::Vector2f glyphOffset{ 0.f - glyph.startX, (glyph.baseline < 0) ? (0.f - glyph.baseline - glyph.textureRect.height) : (0.f - glyph.baseline) }; const sf::Vector2f glyphPosition{ penPosition + glyphOffset }; m_vertices[(character * 6u) + 0u].position = glyphPosition; - m_vertices[(character * 6u) + 1u].position = glyphPosition + sf::Vector2f(0, static_cast(glyph.textureRect.height)); - m_vertices[(character * 6u) + 2u].position = glyphPosition + sf::Vector2f(static_cast(glyph.textureRect.width), 0); - m_vertices[(character * 6u) + 3u].position = glyphPosition + sf::Vector2f(static_cast(glyph.textureRect.width), static_cast(glyph.textureRect.height)); + m_vertices[(character * 6u) + 1u].position = glyphPosition + sf::Vector2f{ 0.f, static_cast(glyph.textureRect.height) }; + m_vertices[(character * 6u) + 2u].position = glyphPosition + sf::Vector2f{ static_cast(glyph.textureRect.width), 0.f }; + m_vertices[(character * 6u) + 3u].position = glyphPosition + sf::Vector2f{ static_cast(glyph.textureRect.width), static_cast(glyph.textureRect.height) }; - m_vertices[(character * 6u) + 0u].texCoords = sf::Vector2f( + m_vertices[(character * 6u) + 0u].texCoords = sf::Vector2f{ static_cast(glyph.textureRect.left), - static_cast(glyph.textureRect.top)); - m_vertices[(character * 6u) + 1u].texCoords = sf::Vector2f( + static_cast(glyph.textureRect.top) }; + m_vertices[(character * 6u) + 1u].texCoords = sf::Vector2f{ static_cast(glyph.textureRect.left), - static_cast(glyph.textureRect.top + glyph.textureRect.height)); - m_vertices[(character * 6u) + 2u].texCoords = sf::Vector2f( + static_cast(glyph.textureRect.top + glyph.textureRect.height) }; + m_vertices[(character * 6u) + 2u].texCoords = sf::Vector2f{ static_cast(glyph.textureRect.left + glyph.textureRect.width), - static_cast(glyph.textureRect.top)); - m_vertices[(character * 6u) + 3u].texCoords = sf::Vector2f( + static_cast(glyph.textureRect.top) }; + m_vertices[(character * 6u) + 3u].texCoords = sf::Vector2f{ static_cast(glyph.textureRect.left + glyph.textureRect.width), - static_cast(glyph.textureRect.top + glyph.textureRect.height)); + static_cast(glyph.textureRect.top + glyph.textureRect.height) }; m_vertices[(character * 6u) + 4u] = m_vertices[(character * 6u) + 2u]; m_vertices[(character * 6u) + 5u] = m_vertices[(character * 6u) + 1u]; - penPosition += sf::Vector2f((glyph.width > 0) ? (0.f + m_tracking + kerning + glyph.width) : (0.f + m_tracking + kerning + glyph.width + glyph.textureRect.width - glyph.startX), 0); + penPosition.x += (glyph.width > 0) ? (0.f + m_tracking + kerning + glyph.width) : (0.f + m_tracking + kerning + glyph.width + glyph.textureRect.width - glyph.startX); - minX = std::min(minX, m_vertices[(character * 6u) + 0u].position.x); - maxX = std::max(maxX, m_vertices[(character * 6u) + 3u].position.x); - minY = std::min(minY, m_vertices[(character * 6u) + 0u].position.y); - maxY = std::max(maxY, m_vertices[(character * 6u) + 3u].position.y); + min.x = std::min(min.x, m_vertices[(character * 6u) + 0u].position.x); + max.x = std::max(max.x, m_vertices[(character * 6u) + 3u].position.x); + min.y = std::min(min.y, m_vertices[(character * 6u) + 0u].position.y); + max.y = std::max(max.y, m_vertices[(character * 6u) + 3u].position.y); } priv_updateColor(); - m_bounds.left = minX; - m_bounds.top = minY; - m_bounds.width = maxX - minX; - m_bounds.height = maxY - minY; + m_bounds.left = min.x; + m_bounds.top = min.y; + m_bounds.width = max.x - min.x; + m_bounds.height = max.y - min.y; } void BitmapText::priv_updateColor() { - for (unsigned int v{ 0 }; v < m_vertices.getVertexCount(); ++v) + for (std::size_t v{ 0u }; v < m_vertices.getVertexCount(); ++v) m_vertices[v].color = m_color; } diff --git a/src/SelbaWard/BitmapText.hpp b/src/SelbaWard/BitmapText.hpp index f401a01..7090d22 100644 --- a/src/SelbaWard/BitmapText.hpp +++ b/src/SelbaWard/BitmapText.hpp @@ -53,8 +53,8 @@ class BitmapText : public sf::Drawable, public sf::Transformable const int getTracking() const; void setColor(const sf::Color& color); const sf::Color getColor() const; - void setScale(unsigned int scale); - void setScale(unsigned int scaleX, unsigned int scaleY); + void setScale(std::size_t scale); + void setScale(std::size_t scaleX, std::size_t scaleY); void setScale(sf::Vector2u scale); sf::FloatRect getGlobalBounds() const; sf::FloatRect getLocalBounds() const; From 7016d9e61858c20524d39db53ed328bc2fd00b0a Mon Sep 17 00:00:00 2001 From: Hapaxia Date: Sun, 12 Nov 2023 22:05:20 +0000 Subject: [PATCH 50/64] fix merging errors --- src/SelbaWard/Polygon.cpp | 20 -------------------- src/SelbaWard/Spline.cpp | 29 ----------------------------- src/SelbaWard/Spline.hpp | 2 -- 3 files changed, 51 deletions(-) diff --git a/src/SelbaWard/Polygon.cpp b/src/SelbaWard/Polygon.cpp index d83bc68..dae52da 100644 --- a/src/SelbaWard/Polygon.cpp +++ b/src/SelbaWard/Polygon.cpp @@ -82,26 +82,6 @@ inline float lengthSquared(const sf::Vector2f& a) return (a.x * a.x) + (a.y * a.y); } -inline float crossProduct(const sf::Vector2f& a, const sf::Vector2f& b) -{ - return (a.x * b.y) - (a.y * b.x); -} - -inline float lengthSquared(const sf::Vector2f& a) -{ - return (a.x * a.x) + (a.y * a.y); -} - -inline float crossProduct(const sf::Vector2f& a, const sf::Vector2f& b) -{ - return (a.x * b.y) - (a.y * b.x); -} - -inline float lengthSquared(const sf::Vector2f& a) -{ - return (a.x * a.x) + (a.y * a.y); -} - } // namespace namespace selbaward diff --git a/src/SelbaWard/Spline.cpp b/src/SelbaWard/Spline.cpp index db79e0d..5bae1d4 100644 --- a/src/SelbaWard/Spline.cpp +++ b/src/SelbaWard/Spline.cpp @@ -377,35 +377,6 @@ void Spline::updateOutputVertices() priv_updateOutputVertices(); } -Spline& Spline::operator=(const Spline& spline) -{ - m_throwExceptions = spline.m_throwExceptions; - m_isClosed = spline.m_isClosed; - m_isRandomNormalOffsetsActivated = spline.m_isRandomNormalOffsetsActivated; - m_thickCornerType = spline.m_thickCornerType; - m_thickStartCapType = spline.m_thickStartCapType; - m_thickEndCapType = spline.m_thickEndCapType; - m_roundedThickCornerInterpolationLevel = spline.m_roundedThickCornerInterpolationLevel; - m_roundedThickStartCapInterpolationLevel = spline.m_roundedThickStartCapInterpolationLevel; - m_roundedThickEndCapInterpolationLevel = spline.m_roundedThickEndCapInterpolationLevel; - m_maxPointLength = spline.m_maxPointLength; - m_vertices = spline.m_vertices; - m_color = spline.m_color; - m_thickness = spline.m_thickness; - m_randomNormalOffsetRange = spline.m_randomNormalOffsetRange; - m_interpolatedVerticesUnitTangents = spline.m_interpolatedVerticesUnitTangents; - m_outputVertices = spline.m_outputVertices; - m_primitiveType = spline.m_primitiveType; - m_interpolationSteps = spline.m_interpolationSteps; - m_useBezier = spline.m_useBezier; - m_handlesVertices = spline.m_handlesVertices; - m_showHandles = spline.m_showHandles; - m_lockHandleMirror = spline.m_lockHandleMirror; - m_lockHandleAngle = spline.m_lockHandleAngle; - - return *this; -} - void Spline::connectFrontToFrontOf(const Spline& spline, const bool rotateSpline, const bool moveSpline) { if (!moveSpline && !rotateSpline) diff --git a/src/SelbaWard/Spline.hpp b/src/SelbaWard/Spline.hpp index be18b12..f3ce276 100644 --- a/src/SelbaWard/Spline.hpp +++ b/src/SelbaWard/Spline.hpp @@ -76,8 +76,6 @@ class Spline : public sf::Drawable void update(); void updateOutputVertices(); - Spline& operator=(const Spline& spline); - Vertex& operator[] (std::size_t index); // direct access to the spline's vertices (sw::Spline::Vertex) using the [] operator. no checks are performed. using with an invalid index results in undefined behaviour void connectFrontToFrontOf(const Spline& spline, bool rotateSpline = true, bool moveSpline = true); From 1fa53280f9737d2d6a7678a7702e9adf56018471 Mon Sep 17 00:00:00 2001 From: Hapaxia Date: Sun, 12 Nov 2023 23:19:18 +0000 Subject: [PATCH 51/64] Update ci.yml add manual installation of Ninja --- .github/workflows/ci.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 72e3e78..e31521f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -30,6 +30,12 @@ jobs: - { name: Debug } steps: + - name: Get CMake and Ninja + uses: lukka/get-cmake@latest + with: + cmakeVersion: 3.22 + ninjaVersion: latest + - name: Install Linux Dependencies if: runner.os == 'Linux' run: | From 35b80e8f9c4e856b5f6a5afeeccc351266f9cfab Mon Sep 17 00:00:00 2001 From: Hapaxia Date: Sun, 12 Nov 2023 23:35:31 +0000 Subject: [PATCH 52/64] Update ci.yml remove WinGW and change CMake version to latest --- .github/workflows/ci.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e31521f..9cbe8bf 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -21,7 +21,6 @@ jobs: - { name: Windows MSVC, os: windows-2022 } - { name: Windows ClangCL, os: windows-2022, flags: -T ClangCL } - { name: Windows Clang, os: windows-2022, flags: -GNinja -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ } - - { name: Windows MinGW, os: windows-2022, flags: -GNinja -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ } - { name: Linux GCC, os: ubuntu-22.04, flags: -GNinja } - { name: Linux Clang, os: ubuntu-22.04, flags: -GNinja -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ } - { name: macOS, os: macos-12, flags: -GNinja } @@ -33,7 +32,7 @@ jobs: - name: Get CMake and Ninja uses: lukka/get-cmake@latest with: - cmakeVersion: 3.22 + cmakeVersion: latest ninjaVersion: latest - name: Install Linux Dependencies From 8f8755bf40356b92bbcaf1adcbe949b44b97d251 Mon Sep 17 00:00:00 2001 From: Hapaxia Date: Thu, 23 Nov 2023 15:13:37 +0000 Subject: [PATCH 53/64] Update .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index bd98dae..c981782 100644 --- a/.gitignore +++ b/.gitignore @@ -33,6 +33,7 @@ temp/ temp_*/ temp_storage/ PropertySheets/ +priv_*/ # User-specific files (MonoDevelop/Xamarin Studio) *.userprefs From 12544088bfc9de8559e97583b2fa07b02bd4d808 Mon Sep 17 00:00:00 2001 From: Hapaxia Date: Thu, 23 Nov 2023 22:36:33 +0000 Subject: [PATCH 54/64] add SpriteBatch v1.0.0 add Sprite Batch, v1. stores multiple sprites internally and creates a single vertex array from them when drawing. can avoid global updates in basic situations. the stored sprites can be manipulated indirectly only via class methods. this allows only updating what is required. if an order function exists (to sort pointer to sprites), it is used to order the sprites when updating; this forces global update to always be active. if no function exists, it will order them according to their storage and global updates are not required. if a manual order (a vector of sprite indices) exists, this override the order function if it exists (but does not clear it). the manual order is used for the first part of the vector and any missing indices will follow in original order. if the manual order is cleared, the order function will be re-activated if it exists, otherwise it'll use the normal method. setting the order function clears the manual order but clearing the order function does not clear the manual order. neither setting nor clearing the order clears the order function (but if a manual order exists, it overrides the order function). clearAllOrdering() is provided to clear both the order function and the manual order at once. all standard SFML sprite methods are present but require a sprite index to be included (to identify which sprite to apply it to). if "move", "rotate" and "scale" are used without a sprite index, it will be applied to all sprites. --- src/SelbaWard.hpp | 1 + src/SelbaWard/SpriteBatch.cpp | 519 ++++++++++++++++++++++++++++++++++ src/SelbaWard/SpriteBatch.hpp | 168 +++++++++++ 3 files changed, 688 insertions(+) create mode 100644 src/SelbaWard/SpriteBatch.cpp create mode 100644 src/SelbaWard/SpriteBatch.hpp diff --git a/src/SelbaWard.hpp b/src/SelbaWard.hpp index 88a54d2..8d12586 100644 --- a/src/SelbaWard.hpp +++ b/src/SelbaWard.hpp @@ -46,6 +46,7 @@ #include "SelbaWard/SpinningCard.hpp" #include "SelbaWard/Spline.hpp" #include "SelbaWard/Sprite3d.hpp" +#include "SelbaWard/SpriteBatch.hpp" #include "SelbaWard/Starfield.hpp" #include "SelbaWard/Starfield3d.hpp" #include "SelbaWard/TileMap.hpp" diff --git a/src/SelbaWard/SpriteBatch.cpp b/src/SelbaWard/SpriteBatch.cpp new file mode 100644 index 0000000..026bc7e --- /dev/null +++ b/src/SelbaWard/SpriteBatch.cpp @@ -0,0 +1,519 @@ +////////////////////////////////////////////////////////////////////////////// +// +// Selba Ward (https://github.com/Hapaxia/SelbaWard) +// -- +// +// Sprite Batch +// +// Copyright(c) 2023 M.J.Silk +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions : +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software.If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +// M.J.Silk +// MJSilk2@gmail.com +// +////////////////////////////////////////////////////////////////////////////// + +#include "SpriteBatch.hpp" + +#include + +namespace +{ + +const std::string exceptionPrefix{ "Sprite Batch: " }; + +constexpr std::size_t numberOfVerticesPerQuad{ 6u }; + +} // namespace + +namespace selbaward +{ + +SpriteBatch::SpriteBatch() + : m_texture{ nullptr } + , m_orderFunction{ nullptr } + , m_orderIndices() + , m_sprites() + , m_isGlobalUpdateRequired { false } + , m_vertices() +{ + +} + +void SpriteBatch::setTexture(const sf::Texture& texture) +{ + m_texture = &texture; +} + +void SpriteBatch::setTexture() +{ + m_texture = nullptr; +} + +void SpriteBatch::setNumberOfSprites(const std::size_t numberOfSprites) +{ + if (numberOfSprites == m_sprites.size()) + return; + + m_sprites.resize(numberOfSprites); + m_isGlobalUpdateRequired = true; +} + +std::size_t SpriteBatch::getNumberOfSprites() const +{ + return m_sprites.size(); +} + +std::size_t SpriteBatch::insertSprite(std::size_t insertIndex, const std::size_t numberOfSprites, const sf::Sprite& sprite) +{ + if (numberOfSprites == 0u) + return m_sprites.size(); + + if (insertIndex > m_sprites.size()) + insertIndex = m_sprites.size(); + m_sprites.insert(m_sprites.begin() + insertIndex, numberOfSprites, Sprite{ false, sprite }); + m_isGlobalUpdateRequired = true; + return m_sprites.size(); +} + +std::size_t SpriteBatch::addSprite(const std::size_t numberOfSprites, const sf::Sprite& sprite) +{ + return insertSprite(m_sprites.size(), numberOfSprites, sprite); +} + +std::size_t SpriteBatch::removeSprite(const std::size_t removeIndex, const std::size_t numberOfSprites) +{ + if (numberOfSprites == 0u) + return m_sprites.size(); + + if (m_sprites.empty()) + throw Exception(exceptionPrefix + "Cannot remove sprite; no sprites available."); + + assert(removeIndex < m_sprites.size()); + if (removeIndex >= m_sprites.size()) + throw Exception(exceptionPrefix + "Cannot remove sprite; invalid sprite index."); + + std::size_t endIndex{ removeIndex + numberOfSprites }; + if (endIndex > m_sprites.size()) + endIndex = m_sprites.size(); + m_sprites.erase(m_sprites.begin() + removeIndex, m_sprites.begin() + endIndex); + m_isGlobalUpdateRequired = true; + return m_sprites.size(); +} + +std::size_t SpriteBatch::removeSprite(const std::size_t numberOfSprites) +{ + if (m_sprites.empty()) + throw Exception(exceptionPrefix + "Cannot remove sprite; no sprites available."); + + return removeSprite(m_sprites.size() - 1u, numberOfSprites); +} + +void SpriteBatch::batchSprites(const std::vector& sprites) +{ + const std::size_t numberOfSprites{ sprites.size() }; + m_sprites.resize(numberOfSprites); + for (std::size_t i{ 0u }; i < numberOfSprites; ++i) + m_sprites[i] = { false, sprites[i] }; + m_isGlobalUpdateRequired = true; +} + +void SpriteBatch::batchSprites(const std::vector& sprites) +{ + const std::size_t numberOfSprites{ sprites.size() }; + m_sprites.resize(numberOfSprites); + for (std::size_t i{ 0u }; i < numberOfSprites; ++i) + m_sprites[i] = { false, *sprites[i] }; + m_isGlobalUpdateRequired = true; +} + +void SpriteBatch::updateSprite(const std::size_t index, const sf::Sprite& sprite) +{ + priv_testIsIndexValid(index); + + m_sprites[index].isUpdateRequired = true; + m_sprites[index].sprite = sprite; +} + +sf::Sprite SpriteBatch::getSprite(const std::size_t index) +{ + priv_testIsIndexValid(index); + return m_sprites[index].sprite; +} + +sf::Sprite SpriteBatch::operator[](const std::size_t index) +{ + priv_testIsIndexValid(index); + return m_sprites[index].sprite; +} + +void SpriteBatch::setOrderFunction(const std::function& orderFunction) +{ + m_orderFunction = orderFunction; + m_orderIndices.clear(); +} + +void SpriteBatch::setOrderFunction() +{ + m_orderFunction = nullptr; +} + +void SpriteBatch::setOrder(const std::vector& orderIndices) +{ + m_orderIndices = orderIndices; +} + +void SpriteBatch::setOrder() +{ + m_orderIndices.clear(); +} + +void SpriteBatch::clearAllOrdering() +{ + setOrderFunction(); + setOrder(); +} + +void SpriteBatch::setPosition(const std::size_t index, const sf::Vector2f position) +{ + priv_testIsIndexValid(index); + m_sprites[index].sprite.setPosition(position); + m_sprites[index].isUpdateRequired = true; +} + +void SpriteBatch::setOrigin(const std::size_t index, const sf::Vector2f origin) +{ + priv_testIsIndexValid(index); + m_sprites[index].sprite.setOrigin(origin); + m_sprites[index].isUpdateRequired = true; +} + +void SpriteBatch::setRotation(const std::size_t index, const float rotation) +{ + priv_testIsIndexValid(index); + m_sprites[index].sprite.setRotation(rotation); + m_sprites[index].isUpdateRequired = true; +} + +void SpriteBatch::setScale(const std::size_t index, const sf::Vector2f scale) +{ + priv_testIsIndexValid(index); + m_sprites[index].sprite.setScale(scale); + m_sprites[index].isUpdateRequired = true; +} + +void SpriteBatch::setScale(const std::size_t index, const float scale) +{ + setScale(index, { scale, scale }); +} + +void SpriteBatch::setTextureRect(const std::size_t index, const sf::IntRect textureRect) +{ + priv_testIsIndexValid(index); + m_sprites[index].sprite.setTextureRect(textureRect); + m_sprites[index].isUpdateRequired = true; +} + +void SpriteBatch::setColor(const std::size_t index, const sf::Color& color) +{ + priv_testIsIndexValid(index); + m_sprites[index].sprite.setColor(color); + m_sprites[index].isUpdateRequired = true; +} + +void SpriteBatch::move(const std::size_t index, const sf::Vector2f offset) +{ + priv_testIsIndexValid(index); + m_sprites[index].sprite.move(offset); + m_sprites[index].isUpdateRequired = true; +} + +void SpriteBatch::rotate(const std::size_t index, const float angle) +{ + priv_testIsIndexValid(index); + m_sprites[index].sprite.rotate(angle); + m_sprites[index].isUpdateRequired = true; +} + +void SpriteBatch::scale(const std::size_t index, const sf::Vector2f factor) +{ + priv_testIsIndexValid(index); + m_sprites[index].sprite.scale(factor); + m_sprites[index].isUpdateRequired = true; +} + +void SpriteBatch::scale(const std::size_t index, const float factor) +{ + scale(index, { factor, factor }); +} + +sf::Vector2f SpriteBatch::getPosition(const std::size_t index) const +{ + priv_testIsIndexValid(index); + return m_sprites[index].sprite.getPosition(); +} + +sf::Vector2f SpriteBatch::getOrigin(const std::size_t index) const +{ + priv_testIsIndexValid(index); + return m_sprites[index].sprite.getOrigin(); +} + +float SpriteBatch::getRotation(const std::size_t index) const +{ + priv_testIsIndexValid(index); + return m_sprites[index].sprite.getRotation(); +} + +sf::Vector2f SpriteBatch::getScale(const std::size_t index) const +{ + priv_testIsIndexValid(index); + return m_sprites[index].sprite.getScale(); +} + +sf::IntRect SpriteBatch::getTextureRect(const std::size_t index) const +{ + priv_testIsIndexValid(index); + return m_sprites[index].sprite.getTextureRect(); +} + +sf::Color SpriteBatch::getColor(const std::size_t index) const +{ + priv_testIsIndexValid(index); + return m_sprites[index].sprite.getColor(); +} + +sf::FloatRect SpriteBatch::getLocalBounds(const std::size_t index) const +{ + priv_testIsIndexValid(index); + return m_sprites[index].sprite.getLocalBounds(); +} + +sf::FloatRect SpriteBatch::getGlobalBounds(const std::size_t index) const +{ + priv_testIsIndexValid(index); + return m_sprites[index].sprite.getGlobalBounds(); +} + +sf::Transform SpriteBatch::getTransform(const std::size_t index) const +{ + priv_testIsIndexValid(index); + return m_sprites[index].sprite.getTransform(); +} + +sf::Transform SpriteBatch::getInverseTransform(const std::size_t index) const +{ + priv_testIsIndexValid(index); + return m_sprites[index].sprite.getInverseTransform(); +} + +void SpriteBatch::move(const sf::Vector2f offset) +{ + for (auto& sprite : m_sprites) + sprite.sprite.move(offset); + m_isGlobalUpdateRequired = true; +} + +void SpriteBatch::rotate(const float angle) +{ + for (auto& sprite : m_sprites) + sprite.sprite.rotate(angle); + m_isGlobalUpdateRequired = true; +} + +void SpriteBatch::scale(const sf::Vector2f factor) +{ + for (auto& sprite : m_sprites) + sprite.sprite.scale(factor); + m_isGlobalUpdateRequired = true; +} + +void SpriteBatch::scale(const float factor) +{ + scale({ factor, factor }); + m_isGlobalUpdateRequired = true; +} + + + + + + + + + + + + + + + + + + +// PRIVATE + +void SpriteBatch::draw(sf::RenderTarget& target, sf::RenderStates states) const +{ + if ((m_orderFunction != nullptr) || (m_isGlobalUpdateRequired) || (!m_orderIndices.empty())) + priv_updateAll(); + else + priv_updateRequired(); + + states.texture = m_texture; + target.draw(m_vertices.data(), m_vertices.size(), sf::PrimitiveType::Triangles, states); +} + +void SpriteBatch::priv_testIsIndexValid(const std::size_t index) const +{ + const std::size_t numberOfSprites{ m_sprites.size() }; + assert(index < numberOfSprites); + if (index >= numberOfSprites) + throw Exception(exceptionPrefix + "Sprite index invalid."); +} + +void SpriteBatch::priv_updateAll() const +{ + if (m_sprites.empty()) + { + m_vertices.clear(); + return; + } + + const std::size_t numberOfSprites{ m_sprites.size() }; + m_vertices.resize(numberOfSprites * numberOfVerticesPerQuad); + + if (!m_orderIndices.empty()) + { + // create a vector of orig(ordered) indices + std::vector origIndices(numberOfSprites); + for (std::size_t i{ 0u }; i < numberOfSprites; ++i) + origIndices[i] = i; + + // copy order indices in reverse + std::vector orderIndices{ m_orderIndices }; + std::sort(orderIndices.rbegin(), orderIndices.rend()); + + // remove all indices in order indices from orig(ordered) indices + for (auto& orderIndex : orderIndices) + origIndices.erase(origIndices.begin() + orderIndex); + + // rebuild order indices (copy) to contain order indices followed by remaining orig(ordered) indices + orderIndices.resize(numberOfSprites); + const std::size_t sizeOfOrderIndices{ m_orderIndices.size() }; + for (std::size_t i{ 0u }; i < numberOfSprites; ++i) + { + if (i < sizeOfOrderIndices) + orderIndices[i] = m_orderIndices[i]; + else + orderIndices[i] = origIndices[i - sizeOfOrderIndices]; + } + + // update quads + for (std::size_t i{ 0u }; i < numberOfSprites; ++i) + { + priv_updateQuad(i, &(m_sprites[orderIndices[i]].sprite)); + m_sprites[i].isUpdateRequired = false; // this "i" doesn't need to match as we're clearing the update for all anyway + } + } + else if (m_orderFunction != nullptr) + { + // create vector of pointers to sort + std::vector pointers(numberOfSprites); + for (std::size_t i{ 0u }; i < numberOfSprites; ++i) + pointers[i] = &(m_sprites[i].sprite); + + // sort pointers using custom order function + std::sort(pointers.begin(), pointers.end(), m_orderFunction); + + // update quads + for (std::size_t i{ 0u }; i < numberOfSprites; ++i) + { + priv_updateQuad(i, pointers[i]); + m_sprites[i].isUpdateRequired = false; + } + } + else + { + // update quads + for (std::size_t i{ 0u }; i < numberOfSprites; ++i) + { + priv_updateQuad(i, &(m_sprites[i].sprite)); + m_sprites[i].isUpdateRequired = false; + } + } + + m_isGlobalUpdateRequired = false; +} + +void SpriteBatch::priv_updateRequired() const +{ + const std::size_t numberOfSprites{ m_sprites.size() }; + for (std::size_t i{ 0u }; i < numberOfSprites; ++i) + { + if (m_sprites[i].isUpdateRequired) + { + priv_updateQuad(i, &(m_sprites[i].sprite)); + m_sprites[i].isUpdateRequired = false; + } + } +} + +void SpriteBatch::priv_updateQuad(const std::size_t quadIndex, const sf::Sprite* sprite) const +{ + const std::size_t startVertex{ quadIndex * numberOfVerticesPerQuad }; + + const sf::Transform transform{ sprite->getTransform() }; + const sf::Color color{ sprite->getColor() }; + const sf::IntRect rect{ sprite->getTextureRect() }; + + sf::Vector2f shapeTopLeft{ 0.f, 0.f }; + sf::Vector2f shapeBottomRight(rect.getSize()); + sf::Vector2f shapeTopRight{ shapeBottomRight.x, shapeTopLeft.y }; + sf::Vector2f shapeBottomLeft{ shapeTopLeft.x, shapeBottomRight.y }; + sf::Vector2f textureTopLeft(rect.getPosition()); + sf::Vector2f textureBottomRight{ textureTopLeft + shapeBottomRight }; + sf::Vector2f textureTopRight{ textureBottomRight.x, textureTopLeft.y }; + sf::Vector2f textureBottomLeft{ textureTopLeft.x, textureBottomRight.y }; + + + shapeTopLeft = transform.transformPoint(shapeTopLeft); + shapeBottomRight = transform.transformPoint(shapeBottomRight); + shapeTopRight = transform.transformPoint(shapeTopRight); + shapeBottomLeft = transform.transformPoint(shapeBottomLeft); + + m_vertices[startVertex + 0u].position = shapeTopLeft; + m_vertices[startVertex + 0u].texCoords = textureTopLeft; + m_vertices[startVertex + 0u].color = color; + m_vertices[startVertex + 1u].position = shapeBottomLeft; + m_vertices[startVertex + 1u].texCoords = textureBottomLeft; + m_vertices[startVertex + 1u].color = color; + m_vertices[startVertex + 2u].position = shapeBottomRight; + m_vertices[startVertex + 2u].texCoords = textureBottomRight; + m_vertices[startVertex + 2u].color = color; + m_vertices[startVertex + 5u].position = shapeTopRight; + m_vertices[startVertex + 5u].texCoords = textureTopRight; + m_vertices[startVertex + 5u].color = color; + + m_vertices[startVertex + 3u] = m_vertices[startVertex + 0u]; + m_vertices[startVertex + 4u] = m_vertices[startVertex + 2u]; +} + +} // namespace selbaward diff --git a/src/SelbaWard/SpriteBatch.hpp b/src/SelbaWard/SpriteBatch.hpp new file mode 100644 index 0000000..fffff29 --- /dev/null +++ b/src/SelbaWard/SpriteBatch.hpp @@ -0,0 +1,168 @@ +////////////////////////////////////////////////////////////////////////////// +// +// Selba Ward (https://github.com/Hapaxia/SelbaWard) +// -- +// +// Sprite Batch +// +// Copyright(c) 2023 M.J.Silk +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions : +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software.If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +// M.J.Silk +// MJSilk2@gmail.com +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef SELBAWARD_SPRITEBATCH_HPP +#define SELBAWARD_SPRITEBATCH_HPP + +#include "Common.hpp" + +#include +#include + +#include + +namespace selbaward +{ + +// Sprite Batch v1.0.0 +class SpriteBatch : public sf::Drawable +{ +public: + SpriteBatch(); + + void setTexture(const sf::Texture& texture); + void setTexture(); + + void setNumberOfSprites(std::size_t numberOfSprites); + std::size_t getNumberOfSprites() const; + + std::size_t insertSprite(std::size_t insertIndex, std::size_t numberOfSprites = 1u, const sf::Sprite& sprite = sf::Sprite()); + std::size_t addSprite(std::size_t numberOfSprites = 1u, const sf::Sprite& sprite = sf::Sprite()); // to back + + std::size_t removeSprite(std::size_t removeIndex, std::size_t numberOfSprites = 1u); + std::size_t removeSprite(std::size_t numberOfSprites = 1u); // from back + + void batchSprites(const std::vector& sprites); // copy entire vector of sprites into batch and prepares it for entire update + void batchSprites(const std::vector& sprites); // copy entire vector of sprites (from the pointers) into batch and prepares it for entire update + + void updateSprite(std::size_t index, const sf::Sprite& sprite); + sf::Sprite getSprite(std::size_t index); // this sf::Sprite is a copy, not access to the internally stored one! + sf::Sprite operator[](std::size_t index); // this sf::Sprite is a copy, not access to the internally stored one! + + void setOrderFunction(const std::function& orderFunction); // sets order function and clears any manual order + void setOrderFunction(); // clears order function and but does not clear any manual order + + void setOrder(const std::vector& orderIndices); // sets manual order, which overrides order function (but doesn't clear the order function) + void setOrder(); // clears manual order and reinstates order function, if available + + void clearAllOrdering(); // clears order function and also the manual order + + + + + + + + // standard SFML sprite methods + + // setters - absolute + void setPosition(std::size_t index, sf::Vector2f position); + void setOrigin(std::size_t index, sf::Vector2f origin); + void setRotation(std::size_t index, float rotation); + void setScale(std::size_t index, sf::Vector2f scale); + void setScale(std::size_t index, float scale); // sets both x and y to the scale + void setTextureRect(std::size_t index, sf::IntRect textureRect); + void setColor(std::size_t index, const sf::Color& color); + + // setters - relative + void move(std::size_t index, sf::Vector2f offset); + void rotate(std::size_t index, float angle); + void scale(std::size_t index, sf::Vector2f factor); + void scale(std::size_t index, float factor); // scales both x and y by the same factor + + // getters (that match the setters) + sf::Vector2f getPosition(std::size_t index) const; + sf::Vector2f getOrigin(std::size_t index) const; + float getRotation(std::size_t index) const; + sf::Vector2f getScale(std::size_t index) const; + sf::IntRect getTextureRect(std::size_t index) const; + sf::Color getColor(std::size_t index) const; + + // getters (extra - no matching setter) + sf::FloatRect getLocalBounds(std::size_t index) const; + sf::FloatRect getGlobalBounds(std::size_t index) const; + sf::Transform getTransform(std::size_t index) const; + sf::Transform getInverseTransform(std::size_t index) const; + + + + // global sprite methods (affects all sprites) - relative + void move(sf::Vector2f offset); + void rotate(float angle); + void scale(sf::Vector2f factor); + void scale(float factor); // scales both x and y by the same factor + + + + + + + + + + + + + + + + + + + + + +private: + struct Sprite + { + bool isUpdateRequired; + sf::Sprite sprite; + }; + + const sf::Texture* m_texture; + + std::function m_orderFunction; + std::vector m_orderIndices; + + mutable std::vector m_sprites; + mutable bool m_isGlobalUpdateRequired; + mutable std::vector m_vertices; + + void draw(sf::RenderTarget& target, sf::RenderStates states) const; + void priv_testIsIndexValid(const std::size_t index) const; + void priv_updateAll() const; + void priv_updateRequired() const; + void priv_updateQuad(const std::size_t quadIndex, const sf::Sprite* sprite) const; +}; + +} // namespace selbaward +#endif // SELBAWARD_SPRITEBATCH_HPP From b27187ecdcc3c4689965d0d86d2023a745270f6f Mon Sep 17 00:00:00 2001 From: Hapaxia Date: Thu, 23 Nov 2023 22:39:21 +0000 Subject: [PATCH 55/64] Update readme.md add "Sprite Batch" and "Starfield 3D" to contents list --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 8d9230c..3fa0b26 100644 --- a/readme.md +++ b/readme.md @@ -6,7 +6,7 @@ A collection of SFML drawables by [Hapaxia](http://github.com/Hapaxia) -Contents: **Bitmap Text**, **Console Screen**, **Crosshair**, **Elastic Sprite**, **Gallery Sprite**, **Line**, **Nine Patch**, **Pie Chart**, **Pixel Display**, **Polygon**, **Progress Bar**, **Ring**, **Spinning Card**, **Spline**, **Sprite 3D**, **Starfield**, **Tile Map** +Contents: **Bitmap Text**, **Console Screen**, **Crosshair**, **Elastic Sprite**, **Gallery Sprite**, **Line**, **Nine Patch**, **Pie Chart**, **Pixel Display**, **Polygon**, **Progress Bar**, **Ring**, **Spinning Card**, **Spline**, **Sprite 3D**, **Sprite Batch**, **Starfield**, **Starfield 3D**, **Tile Map** ## For information, view the [Wiki]. From b6aa36dc0157601948469a71ab5586980b8ebac8 Mon Sep 17 00:00:00 2001 From: Hapaxia Date: Wed, 3 Jan 2024 12:58:40 +0000 Subject: [PATCH 56/64] update year (2024) update year for 2024 --- src/SelbaWard.hpp | 2 +- src/SelbaWard/BitmapFont.cpp | 2 +- src/SelbaWard/BitmapFont.hpp | 2 +- src/SelbaWard/BitmapText.cpp | 2 +- src/SelbaWard/BitmapText.hpp | 2 +- src/SelbaWard/Common.hpp | 2 +- src/SelbaWard/ConsoleScreen.cpp | 2 +- src/SelbaWard/ConsoleScreen.hpp | 2 +- src/SelbaWard/Crosshair.cpp | 2 +- src/SelbaWard/Crosshair.hpp | 2 +- src/SelbaWard/ElasticSprite.cpp | 2 +- src/SelbaWard/ElasticSprite.hpp | 2 +- src/SelbaWard/Exception.hpp | 2 +- src/SelbaWard/GallerySprite.cpp | 2 +- src/SelbaWard/GallerySprite.hpp | 2 +- src/SelbaWard/Line.cpp | 2 +- src/SelbaWard/Line.hpp | 2 +- src/SelbaWard/NinePatch.cpp | 2 +- src/SelbaWard/NinePatch.hpp | 2 +- src/SelbaWard/PaletteEnums.hpp | 2 +- src/SelbaWard/PieChart.cpp | 2 +- src/SelbaWard/PieChart.hpp | 2 +- src/SelbaWard/PixelDisplay.cpp | 2 +- src/SelbaWard/PixelDisplay.hpp | 2 +- src/SelbaWard/Polygon.cpp | 2 +- src/SelbaWard/Polygon.hpp | 2 +- src/SelbaWard/ProgressBar.cpp | 2 +- src/SelbaWard/ProgressBar.hpp | 2 +- src/SelbaWard/Ring.cpp | 2 +- src/SelbaWard/Ring.hpp | 2 +- src/SelbaWard/SpinningCard.cpp | 2 +- src/SelbaWard/SpinningCard.hpp | 2 +- src/SelbaWard/Spline.cpp | 2 +- src/SelbaWard/Spline.hpp | 2 +- src/SelbaWard/Sprite3d.cpp | 2 +- src/SelbaWard/Sprite3d.hpp | 2 +- src/SelbaWard/SpriteBatch.cpp | 2 +- src/SelbaWard/SpriteBatch.hpp | 2 +- src/SelbaWard/Starfield.cpp | 2 +- src/SelbaWard/Starfield.hpp | 2 +- src/SelbaWard/Starfield3d.cpp | 2 +- src/SelbaWard/Starfield3d.hpp | 2 +- src/SelbaWard/TileMap.hpp | 2 +- src/SelbaWard/TileMap.inl | 2 +- 44 files changed, 44 insertions(+), 44 deletions(-) diff --git a/src/SelbaWard.hpp b/src/SelbaWard.hpp index 8d12586..8ac5640 100644 --- a/src/SelbaWard.hpp +++ b/src/SelbaWard.hpp @@ -2,7 +2,7 @@ // // Selba Ward (https://github.com/Hapaxia/SelbaWard) // -// Copyright(c) 2015-2023 M.J.Silk +// Copyright(c) 2015-2024 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/BitmapFont.cpp b/src/SelbaWard/BitmapFont.cpp index 1e91196..7f00de6 100644 --- a/src/SelbaWard/BitmapFont.cpp +++ b/src/SelbaWard/BitmapFont.cpp @@ -5,7 +5,7 @@ // // BitmapFont // -// Copyright(c) 2014-2023 M.J.Silk +// Copyright(c) 2014-2024 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/BitmapFont.hpp b/src/SelbaWard/BitmapFont.hpp index cde9b40..1b5b4a8 100644 --- a/src/SelbaWard/BitmapFont.hpp +++ b/src/SelbaWard/BitmapFont.hpp @@ -5,7 +5,7 @@ // // BitmapFont // -// Copyright(c) 2014-2023 M.J.Silk +// Copyright(c) 2014-2024 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/BitmapText.cpp b/src/SelbaWard/BitmapText.cpp index 7cfe924..783c0db 100644 --- a/src/SelbaWard/BitmapText.cpp +++ b/src/SelbaWard/BitmapText.cpp @@ -5,7 +5,7 @@ // // BitmapText // -// Copyright(c) 2014-2023 M.J.Silk +// Copyright(c) 2014-2024 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/BitmapText.hpp b/src/SelbaWard/BitmapText.hpp index 7090d22..490dbb7 100644 --- a/src/SelbaWard/BitmapText.hpp +++ b/src/SelbaWard/BitmapText.hpp @@ -5,7 +5,7 @@ // // BitmapText // -// Copyright(c) 2014-2023 M.J.Silk +// Copyright(c) 2014-2024 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/Common.hpp b/src/SelbaWard/Common.hpp index c7ce274..f38125e 100644 --- a/src/SelbaWard/Common.hpp +++ b/src/SelbaWard/Common.hpp @@ -2,7 +2,7 @@ // // Selba Ward (https://github.com/Hapaxia/SelbaWard) // -// Copyright(c) 2015-2023 M.J.Silk +// Copyright(c) 2015-2024 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/ConsoleScreen.cpp b/src/SelbaWard/ConsoleScreen.cpp index 273ab04..a774386 100644 --- a/src/SelbaWard/ConsoleScreen.cpp +++ b/src/SelbaWard/ConsoleScreen.cpp @@ -5,7 +5,7 @@ // // Console Screen v2 // -// Copyright(c) 2014-2023 M.J.Silk +// Copyright(c) 2014-2024 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/ConsoleScreen.hpp b/src/SelbaWard/ConsoleScreen.hpp index f3da1c4..0b52895 100644 --- a/src/SelbaWard/ConsoleScreen.hpp +++ b/src/SelbaWard/ConsoleScreen.hpp @@ -5,7 +5,7 @@ // // Console Screen v2 // -// Copyright(c) 2014-2023 M.J.Silk +// Copyright(c) 2014-2024 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/Crosshair.cpp b/src/SelbaWard/Crosshair.cpp index 6a2891a..e24c9b2 100644 --- a/src/SelbaWard/Crosshair.cpp +++ b/src/SelbaWard/Crosshair.cpp @@ -5,7 +5,7 @@ // // Crosshair // -// Copyright(c) 2016-2023 M.J.Silk +// Copyright(c) 2016-2024 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/Crosshair.hpp b/src/SelbaWard/Crosshair.hpp index 9f0a20a..c6872ff 100644 --- a/src/SelbaWard/Crosshair.hpp +++ b/src/SelbaWard/Crosshair.hpp @@ -5,7 +5,7 @@ // // Crosshair // -// Copyright(c) 2016-2023 M.J.Silk +// Copyright(c) 2016-2024 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/ElasticSprite.cpp b/src/SelbaWard/ElasticSprite.cpp index 6877648..90312e0 100644 --- a/src/SelbaWard/ElasticSprite.cpp +++ b/src/SelbaWard/ElasticSprite.cpp @@ -5,7 +5,7 @@ // // Elastic Sprite // -// Copyright(c) 2017-2023 M.J.Silk +// Copyright(c) 2017-2024 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/ElasticSprite.hpp b/src/SelbaWard/ElasticSprite.hpp index d926371..55ec10a 100644 --- a/src/SelbaWard/ElasticSprite.hpp +++ b/src/SelbaWard/ElasticSprite.hpp @@ -5,7 +5,7 @@ // // Elastic Sprite // -// Copyright(c) 2017-2023 M.J.Silk +// Copyright(c) 2017-2024 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/Exception.hpp b/src/SelbaWard/Exception.hpp index 1a98ca0..fd4b07c 100644 --- a/src/SelbaWard/Exception.hpp +++ b/src/SelbaWard/Exception.hpp @@ -2,7 +2,7 @@ // // Selba Ward (https://github.com/Hapaxia/SelbaWard) // -// Copyright(c) 2015-2023 M.J.Silk +// Copyright(c) 2015-2024 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/GallerySprite.cpp b/src/SelbaWard/GallerySprite.cpp index fcc8c11..aebd7d4 100644 --- a/src/SelbaWard/GallerySprite.cpp +++ b/src/SelbaWard/GallerySprite.cpp @@ -5,7 +5,7 @@ // // Gallery Sprite // -// Copyright(c) 2016-2023 M.J.Silk +// Copyright(c) 2016-2024 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/GallerySprite.hpp b/src/SelbaWard/GallerySprite.hpp index 6a58474..9a0b527 100644 --- a/src/SelbaWard/GallerySprite.hpp +++ b/src/SelbaWard/GallerySprite.hpp @@ -5,7 +5,7 @@ // // Gallery Sprite // -// Copyright(c) 2016-2023 M.J.Silk +// Copyright(c) 2016-2024 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/Line.cpp b/src/SelbaWard/Line.cpp index 0eab1e1..62c39be 100644 --- a/src/SelbaWard/Line.cpp +++ b/src/SelbaWard/Line.cpp @@ -5,7 +5,7 @@ // // Line // -// Copyright(c) 2015-2023 M.J.Silk +// Copyright(c) 2015-2024 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/Line.hpp b/src/SelbaWard/Line.hpp index 308ab02..b724655 100644 --- a/src/SelbaWard/Line.hpp +++ b/src/SelbaWard/Line.hpp @@ -5,7 +5,7 @@ // // Line // -// Copyright(c) 2015-2023 M.J.Silk +// Copyright(c) 2015-2024 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/NinePatch.cpp b/src/SelbaWard/NinePatch.cpp index bdca4b3..7c20e1f 100644 --- a/src/SelbaWard/NinePatch.cpp +++ b/src/SelbaWard/NinePatch.cpp @@ -5,7 +5,7 @@ // // NinePatch // -// Copyright(c) 2015-2023 M.J.Silk +// Copyright(c) 2015-2024 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/NinePatch.hpp b/src/SelbaWard/NinePatch.hpp index ec1d53a..1a6f99d 100644 --- a/src/SelbaWard/NinePatch.hpp +++ b/src/SelbaWard/NinePatch.hpp @@ -5,7 +5,7 @@ // // NinePatch // -// Copyright(c) 2015-2023 M.J.Silk +// Copyright(c) 2015-2024 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/PaletteEnums.hpp b/src/SelbaWard/PaletteEnums.hpp index 80ca425..9db6a26 100644 --- a/src/SelbaWard/PaletteEnums.hpp +++ b/src/SelbaWard/PaletteEnums.hpp @@ -5,7 +5,7 @@ // // Palette Enums // -// Copyright(c) 2016-2023 M.J.Silk +// Copyright(c) 2016-2024 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/PieChart.cpp b/src/SelbaWard/PieChart.cpp index 8650f3e..132eb39 100644 --- a/src/SelbaWard/PieChart.cpp +++ b/src/SelbaWard/PieChart.cpp @@ -5,7 +5,7 @@ // // Pie Chart // -// Copyright(c) 2015-2023 M.J.Silk +// Copyright(c) 2015-2024 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/PieChart.hpp b/src/SelbaWard/PieChart.hpp index 50423cc..04f737f 100644 --- a/src/SelbaWard/PieChart.hpp +++ b/src/SelbaWard/PieChart.hpp @@ -5,7 +5,7 @@ // // Pie Chart // -// Copyright(c) 2015-2023 M.J.Silk +// Copyright(c) 2015-2024 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/PixelDisplay.cpp b/src/SelbaWard/PixelDisplay.cpp index cce1474..03b8d32 100644 --- a/src/SelbaWard/PixelDisplay.cpp +++ b/src/SelbaWard/PixelDisplay.cpp @@ -5,7 +5,7 @@ // // Pixel Display // -// Copyright(c) 2019-2023 M.J.Silk +// Copyright(c) 2019-2024 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/PixelDisplay.hpp b/src/SelbaWard/PixelDisplay.hpp index 35f849b..ce55eef 100644 --- a/src/SelbaWard/PixelDisplay.hpp +++ b/src/SelbaWard/PixelDisplay.hpp @@ -5,7 +5,7 @@ // // Pixel Display // -// Copyright(c) 2019-2023 M.J.Silk +// Copyright(c) 2019-2024 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/Polygon.cpp b/src/SelbaWard/Polygon.cpp index dae52da..6fd523f 100644 --- a/src/SelbaWard/Polygon.cpp +++ b/src/SelbaWard/Polygon.cpp @@ -5,7 +5,7 @@ // // Polygon // -// Copyright(c) 2022-2023 M.J.Silk +// Copyright(c) 2022-2024 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/Polygon.hpp b/src/SelbaWard/Polygon.hpp index 09c391d..2897d89 100644 --- a/src/SelbaWard/Polygon.hpp +++ b/src/SelbaWard/Polygon.hpp @@ -5,7 +5,7 @@ // // Polygon // -// Copyright(c) 2022-2023 M.J.Silk +// Copyright(c) 2022-2024 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/ProgressBar.cpp b/src/SelbaWard/ProgressBar.cpp index 5dfb869..5bb11d3 100644 --- a/src/SelbaWard/ProgressBar.cpp +++ b/src/SelbaWard/ProgressBar.cpp @@ -5,7 +5,7 @@ // // Progress Bar // -// Copyright(c) 2015-2023 M.J.Silk +// Copyright(c) 2015-2024 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/ProgressBar.hpp b/src/SelbaWard/ProgressBar.hpp index a36750b..a4ef624 100644 --- a/src/SelbaWard/ProgressBar.hpp +++ b/src/SelbaWard/ProgressBar.hpp @@ -5,7 +5,7 @@ // // Progress Bar // -// Copyright(c) 2015-2023 M.J.Silk +// Copyright(c) 2015-2024 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/Ring.cpp b/src/SelbaWard/Ring.cpp index bcc367b..b79ef7a 100644 --- a/src/SelbaWard/Ring.cpp +++ b/src/SelbaWard/Ring.cpp @@ -5,7 +5,7 @@ // // Ring // -// Copyright(c) 2016-2023 M.J.Silk +// Copyright(c) 2016-2024 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/Ring.hpp b/src/SelbaWard/Ring.hpp index 5c660cd..75b67a4 100644 --- a/src/SelbaWard/Ring.hpp +++ b/src/SelbaWard/Ring.hpp @@ -5,7 +5,7 @@ // // Ring // -// Copyright(c) 2016-2023 M.J.Silk +// Copyright(c) 2016-2024 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/SpinningCard.cpp b/src/SelbaWard/SpinningCard.cpp index 46def47..713db68 100644 --- a/src/SelbaWard/SpinningCard.cpp +++ b/src/SelbaWard/SpinningCard.cpp @@ -5,7 +5,7 @@ // // SpinningCard // -// Copyright(c) 2014-2023 M.J.Silk +// Copyright(c) 2014-2024 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/SpinningCard.hpp b/src/SelbaWard/SpinningCard.hpp index 3d607b8..fd8fffc 100644 --- a/src/SelbaWard/SpinningCard.hpp +++ b/src/SelbaWard/SpinningCard.hpp @@ -5,7 +5,7 @@ // // Spinning Card // -// Copyright(c) 2014-2023 M.J.Silk +// Copyright(c) 2014-2024 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/Spline.cpp b/src/SelbaWard/Spline.cpp index 5bae1d4..29354a0 100644 --- a/src/SelbaWard/Spline.cpp +++ b/src/SelbaWard/Spline.cpp @@ -5,7 +5,7 @@ // // Spline // -// Copyright(c) 2014-2023 M.J.Silk +// Copyright(c) 2014-2024 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/Spline.hpp b/src/SelbaWard/Spline.hpp index f3ce276..97cfe13 100644 --- a/src/SelbaWard/Spline.hpp +++ b/src/SelbaWard/Spline.hpp @@ -5,7 +5,7 @@ // // Spline // -// Copyright(c) 2014-2023 M.J.Silk +// Copyright(c) 2014-2024 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/Sprite3d.cpp b/src/SelbaWard/Sprite3d.cpp index 293daa6..d4cac99 100644 --- a/src/SelbaWard/Sprite3d.cpp +++ b/src/SelbaWard/Sprite3d.cpp @@ -5,7 +5,7 @@ // // Sprite3d // -// Copyright(c) 2015-2023 M.J.Silk +// Copyright(c) 2015-2024 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/Sprite3d.hpp b/src/SelbaWard/Sprite3d.hpp index f2246c0..9a70609 100644 --- a/src/SelbaWard/Sprite3d.hpp +++ b/src/SelbaWard/Sprite3d.hpp @@ -5,7 +5,7 @@ // // Sprite3d // -// Copyright(c) 2015-2023 M.J.Silk +// Copyright(c) 2015-2024 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/SpriteBatch.cpp b/src/SelbaWard/SpriteBatch.cpp index 026bc7e..65d222c 100644 --- a/src/SelbaWard/SpriteBatch.cpp +++ b/src/SelbaWard/SpriteBatch.cpp @@ -5,7 +5,7 @@ // // Sprite Batch // -// Copyright(c) 2023 M.J.Silk +// Copyright(c) 2023-2024 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/SpriteBatch.hpp b/src/SelbaWard/SpriteBatch.hpp index fffff29..a7cec28 100644 --- a/src/SelbaWard/SpriteBatch.hpp +++ b/src/SelbaWard/SpriteBatch.hpp @@ -5,7 +5,7 @@ // // Sprite Batch // -// Copyright(c) 2023 M.J.Silk +// Copyright(c) 2023-2024 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/Starfield.cpp b/src/SelbaWard/Starfield.cpp index 1c25b2f..5c64d68 100644 --- a/src/SelbaWard/Starfield.cpp +++ b/src/SelbaWard/Starfield.cpp @@ -5,7 +5,7 @@ // // Starfield // -// Copyright(c) 2016-2023 M.J.Silk +// Copyright(c) 2016-2024 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/Starfield.hpp b/src/SelbaWard/Starfield.hpp index 86fc053..6366486 100644 --- a/src/SelbaWard/Starfield.hpp +++ b/src/SelbaWard/Starfield.hpp @@ -5,7 +5,7 @@ // // Starfield // -// Copyright(c) 2016-2023 M.J.Silk +// Copyright(c) 2016-2024 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/Starfield3d.cpp b/src/SelbaWard/Starfield3d.cpp index 070a0cd..7e43b12 100644 --- a/src/SelbaWard/Starfield3d.cpp +++ b/src/SelbaWard/Starfield3d.cpp @@ -5,7 +5,7 @@ // // Starfield 3D // -// Copyright(c) 2023 M.J.Silk +// Copyright(c) 2023-2024 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/Starfield3d.hpp b/src/SelbaWard/Starfield3d.hpp index 5d2d58b..7e3f80c 100644 --- a/src/SelbaWard/Starfield3d.hpp +++ b/src/SelbaWard/Starfield3d.hpp @@ -5,7 +5,7 @@ // // Starfield 3D // -// Copyright(c) 2023 M.J.Silk +// Copyright(c) 2023-2024 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/TileMap.hpp b/src/SelbaWard/TileMap.hpp index b550fce..f999379 100644 --- a/src/SelbaWard/TileMap.hpp +++ b/src/SelbaWard/TileMap.hpp @@ -5,7 +5,7 @@ // // Tile Map // -// Copyright(c) 2016-2023 M.J.Silk +// Copyright(c) 2016-2024 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/TileMap.inl b/src/SelbaWard/TileMap.inl index 2ec41c5..4aa7b44 100644 --- a/src/SelbaWard/TileMap.inl +++ b/src/SelbaWard/TileMap.inl @@ -5,7 +5,7 @@ // // Tile Map // -// Copyright(c) 2016-2023 M.J.Silk +// Copyright(c) 2016-2024 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages From 06ddd59d1813e334527b69bf352a39c0f2fd0c85 Mon Sep 17 00:00:00 2001 From: Hapaxia Date: Wed, 3 Jan 2024 12:58:40 +0000 Subject: [PATCH 57/64] update year (2024) update year for 2024 --- src/SelbaWard.hpp | 2 +- src/SelbaWard/BitmapFont.cpp | 2 +- src/SelbaWard/BitmapFont.hpp | 2 +- src/SelbaWard/BitmapText.cpp | 2 +- src/SelbaWard/BitmapText.hpp | 2 +- src/SelbaWard/Common.hpp | 2 +- src/SelbaWard/ConsoleScreen.cpp | 2 +- src/SelbaWard/ConsoleScreen.hpp | 2 +- src/SelbaWard/Crosshair.cpp | 2 +- src/SelbaWard/Crosshair.hpp | 2 +- src/SelbaWard/ElasticSprite.cpp | 2 +- src/SelbaWard/ElasticSprite.hpp | 2 +- src/SelbaWard/Exception.hpp | 2 +- src/SelbaWard/GallerySprite.cpp | 2 +- src/SelbaWard/GallerySprite.hpp | 2 +- src/SelbaWard/Line.cpp | 2 +- src/SelbaWard/Line.hpp | 2 +- src/SelbaWard/NinePatch.cpp | 2 +- src/SelbaWard/NinePatch.hpp | 2 +- src/SelbaWard/PaletteEnums.hpp | 2 +- src/SelbaWard/PieChart.cpp | 2 +- src/SelbaWard/PieChart.hpp | 2 +- src/SelbaWard/PixelDisplay.cpp | 2 +- src/SelbaWard/PixelDisplay.hpp | 2 +- src/SelbaWard/Polygon.cpp | 2 +- src/SelbaWard/Polygon.hpp | 2 +- src/SelbaWard/ProgressBar.cpp | 2 +- src/SelbaWard/ProgressBar.hpp | 2 +- src/SelbaWard/Ring.cpp | 2 +- src/SelbaWard/Ring.hpp | 2 +- src/SelbaWard/SpinningCard.cpp | 2 +- src/SelbaWard/SpinningCard.hpp | 2 +- src/SelbaWard/Spline.cpp | 2 +- src/SelbaWard/Spline.hpp | 2 +- src/SelbaWard/Sprite3d.cpp | 2 +- src/SelbaWard/Sprite3d.hpp | 2 +- src/SelbaWard/SpriteBatch.cpp | 2 +- src/SelbaWard/SpriteBatch.hpp | 2 +- src/SelbaWard/Starfield.cpp | 2 +- src/SelbaWard/Starfield.hpp | 2 +- src/SelbaWard/Starfield3d.cpp | 2 +- src/SelbaWard/Starfield3d.hpp | 2 +- src/SelbaWard/TileMap.hpp | 2 +- src/SelbaWard/TileMap.inl | 2 +- 44 files changed, 44 insertions(+), 44 deletions(-) diff --git a/src/SelbaWard.hpp b/src/SelbaWard.hpp index 8d12586..8ac5640 100644 --- a/src/SelbaWard.hpp +++ b/src/SelbaWard.hpp @@ -2,7 +2,7 @@ // // Selba Ward (https://github.com/Hapaxia/SelbaWard) // -// Copyright(c) 2015-2023 M.J.Silk +// Copyright(c) 2015-2024 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/BitmapFont.cpp b/src/SelbaWard/BitmapFont.cpp index 1e91196..7f00de6 100644 --- a/src/SelbaWard/BitmapFont.cpp +++ b/src/SelbaWard/BitmapFont.cpp @@ -5,7 +5,7 @@ // // BitmapFont // -// Copyright(c) 2014-2023 M.J.Silk +// Copyright(c) 2014-2024 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/BitmapFont.hpp b/src/SelbaWard/BitmapFont.hpp index cde9b40..1b5b4a8 100644 --- a/src/SelbaWard/BitmapFont.hpp +++ b/src/SelbaWard/BitmapFont.hpp @@ -5,7 +5,7 @@ // // BitmapFont // -// Copyright(c) 2014-2023 M.J.Silk +// Copyright(c) 2014-2024 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/BitmapText.cpp b/src/SelbaWard/BitmapText.cpp index 7cfe924..783c0db 100644 --- a/src/SelbaWard/BitmapText.cpp +++ b/src/SelbaWard/BitmapText.cpp @@ -5,7 +5,7 @@ // // BitmapText // -// Copyright(c) 2014-2023 M.J.Silk +// Copyright(c) 2014-2024 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/BitmapText.hpp b/src/SelbaWard/BitmapText.hpp index 7090d22..490dbb7 100644 --- a/src/SelbaWard/BitmapText.hpp +++ b/src/SelbaWard/BitmapText.hpp @@ -5,7 +5,7 @@ // // BitmapText // -// Copyright(c) 2014-2023 M.J.Silk +// Copyright(c) 2014-2024 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/Common.hpp b/src/SelbaWard/Common.hpp index c7ce274..f38125e 100644 --- a/src/SelbaWard/Common.hpp +++ b/src/SelbaWard/Common.hpp @@ -2,7 +2,7 @@ // // Selba Ward (https://github.com/Hapaxia/SelbaWard) // -// Copyright(c) 2015-2023 M.J.Silk +// Copyright(c) 2015-2024 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/ConsoleScreen.cpp b/src/SelbaWard/ConsoleScreen.cpp index 273ab04..a774386 100644 --- a/src/SelbaWard/ConsoleScreen.cpp +++ b/src/SelbaWard/ConsoleScreen.cpp @@ -5,7 +5,7 @@ // // Console Screen v2 // -// Copyright(c) 2014-2023 M.J.Silk +// Copyright(c) 2014-2024 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/ConsoleScreen.hpp b/src/SelbaWard/ConsoleScreen.hpp index f3da1c4..0b52895 100644 --- a/src/SelbaWard/ConsoleScreen.hpp +++ b/src/SelbaWard/ConsoleScreen.hpp @@ -5,7 +5,7 @@ // // Console Screen v2 // -// Copyright(c) 2014-2023 M.J.Silk +// Copyright(c) 2014-2024 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/Crosshair.cpp b/src/SelbaWard/Crosshair.cpp index 6a2891a..e24c9b2 100644 --- a/src/SelbaWard/Crosshair.cpp +++ b/src/SelbaWard/Crosshair.cpp @@ -5,7 +5,7 @@ // // Crosshair // -// Copyright(c) 2016-2023 M.J.Silk +// Copyright(c) 2016-2024 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/Crosshair.hpp b/src/SelbaWard/Crosshair.hpp index 9f0a20a..c6872ff 100644 --- a/src/SelbaWard/Crosshair.hpp +++ b/src/SelbaWard/Crosshair.hpp @@ -5,7 +5,7 @@ // // Crosshair // -// Copyright(c) 2016-2023 M.J.Silk +// Copyright(c) 2016-2024 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/ElasticSprite.cpp b/src/SelbaWard/ElasticSprite.cpp index 6877648..90312e0 100644 --- a/src/SelbaWard/ElasticSprite.cpp +++ b/src/SelbaWard/ElasticSprite.cpp @@ -5,7 +5,7 @@ // // Elastic Sprite // -// Copyright(c) 2017-2023 M.J.Silk +// Copyright(c) 2017-2024 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/ElasticSprite.hpp b/src/SelbaWard/ElasticSprite.hpp index d926371..55ec10a 100644 --- a/src/SelbaWard/ElasticSprite.hpp +++ b/src/SelbaWard/ElasticSprite.hpp @@ -5,7 +5,7 @@ // // Elastic Sprite // -// Copyright(c) 2017-2023 M.J.Silk +// Copyright(c) 2017-2024 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/Exception.hpp b/src/SelbaWard/Exception.hpp index 1a98ca0..fd4b07c 100644 --- a/src/SelbaWard/Exception.hpp +++ b/src/SelbaWard/Exception.hpp @@ -2,7 +2,7 @@ // // Selba Ward (https://github.com/Hapaxia/SelbaWard) // -// Copyright(c) 2015-2023 M.J.Silk +// Copyright(c) 2015-2024 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/GallerySprite.cpp b/src/SelbaWard/GallerySprite.cpp index fcc8c11..aebd7d4 100644 --- a/src/SelbaWard/GallerySprite.cpp +++ b/src/SelbaWard/GallerySprite.cpp @@ -5,7 +5,7 @@ // // Gallery Sprite // -// Copyright(c) 2016-2023 M.J.Silk +// Copyright(c) 2016-2024 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/GallerySprite.hpp b/src/SelbaWard/GallerySprite.hpp index 6a58474..9a0b527 100644 --- a/src/SelbaWard/GallerySprite.hpp +++ b/src/SelbaWard/GallerySprite.hpp @@ -5,7 +5,7 @@ // // Gallery Sprite // -// Copyright(c) 2016-2023 M.J.Silk +// Copyright(c) 2016-2024 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/Line.cpp b/src/SelbaWard/Line.cpp index 0eab1e1..62c39be 100644 --- a/src/SelbaWard/Line.cpp +++ b/src/SelbaWard/Line.cpp @@ -5,7 +5,7 @@ // // Line // -// Copyright(c) 2015-2023 M.J.Silk +// Copyright(c) 2015-2024 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/Line.hpp b/src/SelbaWard/Line.hpp index 308ab02..b724655 100644 --- a/src/SelbaWard/Line.hpp +++ b/src/SelbaWard/Line.hpp @@ -5,7 +5,7 @@ // // Line // -// Copyright(c) 2015-2023 M.J.Silk +// Copyright(c) 2015-2024 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/NinePatch.cpp b/src/SelbaWard/NinePatch.cpp index bdca4b3..7c20e1f 100644 --- a/src/SelbaWard/NinePatch.cpp +++ b/src/SelbaWard/NinePatch.cpp @@ -5,7 +5,7 @@ // // NinePatch // -// Copyright(c) 2015-2023 M.J.Silk +// Copyright(c) 2015-2024 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/NinePatch.hpp b/src/SelbaWard/NinePatch.hpp index ec1d53a..1a6f99d 100644 --- a/src/SelbaWard/NinePatch.hpp +++ b/src/SelbaWard/NinePatch.hpp @@ -5,7 +5,7 @@ // // NinePatch // -// Copyright(c) 2015-2023 M.J.Silk +// Copyright(c) 2015-2024 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/PaletteEnums.hpp b/src/SelbaWard/PaletteEnums.hpp index 80ca425..9db6a26 100644 --- a/src/SelbaWard/PaletteEnums.hpp +++ b/src/SelbaWard/PaletteEnums.hpp @@ -5,7 +5,7 @@ // // Palette Enums // -// Copyright(c) 2016-2023 M.J.Silk +// Copyright(c) 2016-2024 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/PieChart.cpp b/src/SelbaWard/PieChart.cpp index 8650f3e..132eb39 100644 --- a/src/SelbaWard/PieChart.cpp +++ b/src/SelbaWard/PieChart.cpp @@ -5,7 +5,7 @@ // // Pie Chart // -// Copyright(c) 2015-2023 M.J.Silk +// Copyright(c) 2015-2024 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/PieChart.hpp b/src/SelbaWard/PieChart.hpp index 50423cc..04f737f 100644 --- a/src/SelbaWard/PieChart.hpp +++ b/src/SelbaWard/PieChart.hpp @@ -5,7 +5,7 @@ // // Pie Chart // -// Copyright(c) 2015-2023 M.J.Silk +// Copyright(c) 2015-2024 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/PixelDisplay.cpp b/src/SelbaWard/PixelDisplay.cpp index cce1474..03b8d32 100644 --- a/src/SelbaWard/PixelDisplay.cpp +++ b/src/SelbaWard/PixelDisplay.cpp @@ -5,7 +5,7 @@ // // Pixel Display // -// Copyright(c) 2019-2023 M.J.Silk +// Copyright(c) 2019-2024 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/PixelDisplay.hpp b/src/SelbaWard/PixelDisplay.hpp index 35f849b..ce55eef 100644 --- a/src/SelbaWard/PixelDisplay.hpp +++ b/src/SelbaWard/PixelDisplay.hpp @@ -5,7 +5,7 @@ // // Pixel Display // -// Copyright(c) 2019-2023 M.J.Silk +// Copyright(c) 2019-2024 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/Polygon.cpp b/src/SelbaWard/Polygon.cpp index dae52da..6fd523f 100644 --- a/src/SelbaWard/Polygon.cpp +++ b/src/SelbaWard/Polygon.cpp @@ -5,7 +5,7 @@ // // Polygon // -// Copyright(c) 2022-2023 M.J.Silk +// Copyright(c) 2022-2024 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/Polygon.hpp b/src/SelbaWard/Polygon.hpp index 09c391d..2897d89 100644 --- a/src/SelbaWard/Polygon.hpp +++ b/src/SelbaWard/Polygon.hpp @@ -5,7 +5,7 @@ // // Polygon // -// Copyright(c) 2022-2023 M.J.Silk +// Copyright(c) 2022-2024 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/ProgressBar.cpp b/src/SelbaWard/ProgressBar.cpp index 5dfb869..5bb11d3 100644 --- a/src/SelbaWard/ProgressBar.cpp +++ b/src/SelbaWard/ProgressBar.cpp @@ -5,7 +5,7 @@ // // Progress Bar // -// Copyright(c) 2015-2023 M.J.Silk +// Copyright(c) 2015-2024 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/ProgressBar.hpp b/src/SelbaWard/ProgressBar.hpp index a36750b..a4ef624 100644 --- a/src/SelbaWard/ProgressBar.hpp +++ b/src/SelbaWard/ProgressBar.hpp @@ -5,7 +5,7 @@ // // Progress Bar // -// Copyright(c) 2015-2023 M.J.Silk +// Copyright(c) 2015-2024 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/Ring.cpp b/src/SelbaWard/Ring.cpp index bcc367b..b79ef7a 100644 --- a/src/SelbaWard/Ring.cpp +++ b/src/SelbaWard/Ring.cpp @@ -5,7 +5,7 @@ // // Ring // -// Copyright(c) 2016-2023 M.J.Silk +// Copyright(c) 2016-2024 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/Ring.hpp b/src/SelbaWard/Ring.hpp index 5c660cd..75b67a4 100644 --- a/src/SelbaWard/Ring.hpp +++ b/src/SelbaWard/Ring.hpp @@ -5,7 +5,7 @@ // // Ring // -// Copyright(c) 2016-2023 M.J.Silk +// Copyright(c) 2016-2024 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/SpinningCard.cpp b/src/SelbaWard/SpinningCard.cpp index 46def47..713db68 100644 --- a/src/SelbaWard/SpinningCard.cpp +++ b/src/SelbaWard/SpinningCard.cpp @@ -5,7 +5,7 @@ // // SpinningCard // -// Copyright(c) 2014-2023 M.J.Silk +// Copyright(c) 2014-2024 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/SpinningCard.hpp b/src/SelbaWard/SpinningCard.hpp index 3d607b8..fd8fffc 100644 --- a/src/SelbaWard/SpinningCard.hpp +++ b/src/SelbaWard/SpinningCard.hpp @@ -5,7 +5,7 @@ // // Spinning Card // -// Copyright(c) 2014-2023 M.J.Silk +// Copyright(c) 2014-2024 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/Spline.cpp b/src/SelbaWard/Spline.cpp index 5bae1d4..29354a0 100644 --- a/src/SelbaWard/Spline.cpp +++ b/src/SelbaWard/Spline.cpp @@ -5,7 +5,7 @@ // // Spline // -// Copyright(c) 2014-2023 M.J.Silk +// Copyright(c) 2014-2024 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/Spline.hpp b/src/SelbaWard/Spline.hpp index f3ce276..97cfe13 100644 --- a/src/SelbaWard/Spline.hpp +++ b/src/SelbaWard/Spline.hpp @@ -5,7 +5,7 @@ // // Spline // -// Copyright(c) 2014-2023 M.J.Silk +// Copyright(c) 2014-2024 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/Sprite3d.cpp b/src/SelbaWard/Sprite3d.cpp index 293daa6..d4cac99 100644 --- a/src/SelbaWard/Sprite3d.cpp +++ b/src/SelbaWard/Sprite3d.cpp @@ -5,7 +5,7 @@ // // Sprite3d // -// Copyright(c) 2015-2023 M.J.Silk +// Copyright(c) 2015-2024 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/Sprite3d.hpp b/src/SelbaWard/Sprite3d.hpp index f2246c0..9a70609 100644 --- a/src/SelbaWard/Sprite3d.hpp +++ b/src/SelbaWard/Sprite3d.hpp @@ -5,7 +5,7 @@ // // Sprite3d // -// Copyright(c) 2015-2023 M.J.Silk +// Copyright(c) 2015-2024 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/SpriteBatch.cpp b/src/SelbaWard/SpriteBatch.cpp index 026bc7e..65d222c 100644 --- a/src/SelbaWard/SpriteBatch.cpp +++ b/src/SelbaWard/SpriteBatch.cpp @@ -5,7 +5,7 @@ // // Sprite Batch // -// Copyright(c) 2023 M.J.Silk +// Copyright(c) 2023-2024 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/SpriteBatch.hpp b/src/SelbaWard/SpriteBatch.hpp index fffff29..a7cec28 100644 --- a/src/SelbaWard/SpriteBatch.hpp +++ b/src/SelbaWard/SpriteBatch.hpp @@ -5,7 +5,7 @@ // // Sprite Batch // -// Copyright(c) 2023 M.J.Silk +// Copyright(c) 2023-2024 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/Starfield.cpp b/src/SelbaWard/Starfield.cpp index 1c25b2f..5c64d68 100644 --- a/src/SelbaWard/Starfield.cpp +++ b/src/SelbaWard/Starfield.cpp @@ -5,7 +5,7 @@ // // Starfield // -// Copyright(c) 2016-2023 M.J.Silk +// Copyright(c) 2016-2024 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/Starfield.hpp b/src/SelbaWard/Starfield.hpp index 86fc053..6366486 100644 --- a/src/SelbaWard/Starfield.hpp +++ b/src/SelbaWard/Starfield.hpp @@ -5,7 +5,7 @@ // // Starfield // -// Copyright(c) 2016-2023 M.J.Silk +// Copyright(c) 2016-2024 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/Starfield3d.cpp b/src/SelbaWard/Starfield3d.cpp index 070a0cd..7e43b12 100644 --- a/src/SelbaWard/Starfield3d.cpp +++ b/src/SelbaWard/Starfield3d.cpp @@ -5,7 +5,7 @@ // // Starfield 3D // -// Copyright(c) 2023 M.J.Silk +// Copyright(c) 2023-2024 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/Starfield3d.hpp b/src/SelbaWard/Starfield3d.hpp index 5d2d58b..7e3f80c 100644 --- a/src/SelbaWard/Starfield3d.hpp +++ b/src/SelbaWard/Starfield3d.hpp @@ -5,7 +5,7 @@ // // Starfield 3D // -// Copyright(c) 2023 M.J.Silk +// Copyright(c) 2023-2024 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/TileMap.hpp b/src/SelbaWard/TileMap.hpp index b550fce..f999379 100644 --- a/src/SelbaWard/TileMap.hpp +++ b/src/SelbaWard/TileMap.hpp @@ -5,7 +5,7 @@ // // Tile Map // -// Copyright(c) 2016-2023 M.J.Silk +// Copyright(c) 2016-2024 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages diff --git a/src/SelbaWard/TileMap.inl b/src/SelbaWard/TileMap.inl index 2ec41c5..4aa7b44 100644 --- a/src/SelbaWard/TileMap.inl +++ b/src/SelbaWard/TileMap.inl @@ -5,7 +5,7 @@ // // Tile Map // -// Copyright(c) 2016-2023 M.J.Silk +// Copyright(c) 2016-2024 M.J.Silk // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages From 9be0d2af394912174b8372f6d9081c1237a381b1 Mon Sep 17 00:00:00 2001 From: Hapaxia Date: Wed, 3 Jan 2024 16:03:40 +0000 Subject: [PATCH 58/64] add Frame Transition (v1) add Frame Transition drawable. transitions between two (equally sized) rectangles. Each frame's alpha animation (Fade) can be customised to allow linear fades, step switch or just keeping their alpha or even just removing it (invisible). "TexCrop" 'wipes' a line across the rectangle replacing one texture with another. how the texture is calculated for these quads can be customised allowing for different wipe types including the standard "wipe", "push", "slide in", "slide out", "shuffle". TexCrop can also be animated in either of the four standard directions (right, left, down, up). Note that the two quads never overlap and always fill the entire FrameTransition rectangle. "Zoom" places the first frame (A) in front of the second frame (B) and zooms in, out, a combination of both or neither. the Fade is particular useful here. Each frame can be customised to have different zoom types (as listed above), zoom amounts (via parameters) and whether it scales the actual quad or its texture rectangle to control zooms. each frame (A and B) can have its own colour, along with an alpha, that is taken into account for its quad including during alpha animations (Fades). during "proper" usage, the quads will never exceed the FrameTransition rectangle. however, it's possible to "hack" this (if required) when using parameters with zoom. note that local and global bounds always return the rectangle of the drawable and purposefully ignores any scaling of quads. each frame can have a separate texture or use the same one. the order of the frames can also be swapped if required for something special. if the frame order is not swapped and the textures are the same for both frames, FrameTransition can optimise the draw calls (a single draw call instead of two). --- src/SelbaWard.hpp | 1 + src/SelbaWard/FrameTransition.cpp | 765 ++++++++++++++++++++++++++++++ src/SelbaWard/FrameTransition.hpp | 352 ++++++++++++++ 3 files changed, 1118 insertions(+) create mode 100644 src/SelbaWard/FrameTransition.cpp create mode 100644 src/SelbaWard/FrameTransition.hpp diff --git a/src/SelbaWard.hpp b/src/SelbaWard.hpp index 8ac5640..f6e7102 100644 --- a/src/SelbaWard.hpp +++ b/src/SelbaWard.hpp @@ -34,6 +34,7 @@ #include "SelbaWard/ConsoleScreen.hpp" #include "SelbaWard/Crosshair.hpp" #include "SelbaWard/ElasticSprite.hpp" +#include "SelbaWard/FrameTransition.hpp" #include "SelbaWard/GallerySprite.hpp" #include "SelbaWard/Line.hpp" #include "SelbaWard/NinePatch.hpp" diff --git a/src/SelbaWard/FrameTransition.cpp b/src/SelbaWard/FrameTransition.cpp new file mode 100644 index 0000000..859b6aa --- /dev/null +++ b/src/SelbaWard/FrameTransition.cpp @@ -0,0 +1,765 @@ +////////////////////////////////////////////////////////////////////////////// +// +// Selba Ward (https://github.com/Hapaxia/SelbaWard) +// -- +// +// Frame Transition +// +// Copyright(c) 2023-2024 M.J.Silk +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions : +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software.If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +// M.J.Silk +// MJSilk2@gmail.com +// +////////////////////////////////////////////////////////////////////////////// + +#include "FrameTransition.hpp" + +#include // for lround + +namespace +{ + +inline float linearInterpolation(const float a, const float b, const float alpha) +{ + return (a * (1.f - alpha)) + (b * alpha); +} +inline sf::Color colorFromColorAndAlpha(sf::Color color, const unsigned int alpha) +{ + color.a = static_cast(alpha); + return color; +} + +} // namespace + +namespace selbaward +{ + +FrameTransition::FrameTransition(const sf::Vector2f size) + : m_ratio{ 0.f } + , m_size{} + , m_transitionId{} + , m_drawAOverB{ true } + , m_parameter1{} + , m_parameter2{} + , m_frameA{} + , m_frameB{} + + // mutable + , m_isUpdateRequired{ true } + , m_vertices() +{ + setTransition(T::TexCrop_A_Start | T::TexCrop_B_End | T::Direction_Right); +} +void FrameTransition::setSize(const sf::Vector2f size) +{ + m_isUpdateRequired = true; + m_size = size; +} +void FrameTransition::setDrawOrderToAOverB() +{ + m_drawAOverB = true; +} +void FrameTransition::setDrawOrderToBOverA() +{ + m_drawAOverB = false; +} + +void FrameTransition::setPercentage(const float percentage) +{ + setRatio(percentage / 100.f); +} +void FrameTransition::setRatio(const float ratio) +{ + m_isUpdateRequired = true; + m_ratio = ratio; + if (m_ratio < 0.f) + m_ratio = 0.f; + else if (m_ratio > 1.f) + m_ratio = 1.f; +} +void FrameTransition::setTransition(const T transitionId) +{ + m_isUpdateRequired = true; + m_transitionId = transitionId; + + switch (m_transitionId & T::Type) + { + case T::Type_Zoom: + case T::Type_TexCrop: + default: + m_frameA.numberOfVertices = 6u; + m_frameB.numberOfVertices = 6u; + } +} + +void FrameTransition::setColors(const sf::Color colorA, const sf::Color colorB) +{ + setColor(FrameId::A, colorA); + setColor(FrameId::B, colorB); +} +void FrameTransition::setColors(const sf::Color color) +{ + setColors(color, color); +} +void FrameTransition::setColor(const FrameId frameId, const sf::Color color) +{ + priv_getFrame(frameId).color = color; +} +sf::Color FrameTransition::getColor(const FrameId frameId) const +{ + return priv_getFrame(frameId).color; +} + +void FrameTransition::setTextures(const sf::Texture& textureA, const sf::Texture& textureB) +{ + setTexture(FrameId::A, textureA); + setTexture(FrameId::B, textureB); +} +void FrameTransition::setTextures(const sf::Texture& texture) +{ + setTextures(texture, texture); +} +void FrameTransition::setTextures() +{ + setTexture(FrameId::A); + setTexture(FrameId::B); +} +void FrameTransition::setTexture(const FrameId frameId, const sf::Texture& texture, const bool resetRect) +{ + m_isUpdateRequired = true; + Frame& frame{ priv_getFrame(frameId) }; + frame.pTexture = &texture; + if (resetRect) + { + frame.textureRect.width = frame.pTexture->getSize().x; + frame.textureRect.height = frame.pTexture->getSize().y; + } +} +void FrameTransition::setTexture(const FrameId frameId) +{ + m_isUpdateRequired = true; + priv_getFrame(frameId).pTexture = nullptr; +} +void FrameTransition::setTextureRect(const FrameId frameId, const sf::IntRect& textureRect) +{ + m_isUpdateRequired = true; + priv_getFrame(frameId).textureRect = textureRect; +} +const sf::Texture& FrameTransition::getTexture(const FrameId frameId) const +{ + return *(priv_getFrame(frameId).pTexture); +} + +void FrameTransition::setParameter1(const float parameterValue) +{ + m_parameter1 = parameterValue; +} +void FrameTransition::setParameter2(const float parameterValue) +{ + m_parameter2 = parameterValue; +} +float FrameTransition::getParameter1() const +{ + return m_parameter1; +} +float FrameTransition::getParameter2() const +{ + return m_parameter2; +} +void FrameTransition::resetParameters() +{ + setParameter1(); + setParameter2(); +} + +sf::FloatRect FrameTransition::getLocalBounds() const +{ + return{ { 0.f, 0.f }, m_size }; +} +sf::FloatRect FrameTransition::getGlobalBounds() const +{ + return getTransform().transformRect(getLocalBounds()); +} + + + +// PRIVATE +void FrameTransition::draw(sf::RenderTarget& target, sf::RenderStates states) const +{ + states.transform *= getTransform(); + + if (m_isUpdateRequired) + priv_update(); + + if (m_frameA.pTexture == m_frameB.pTexture) + { + states.texture = m_frameA.pTexture; + if (m_drawAOverB) + target.draw(m_vertices.data(), m_vertices.size(), sf::PrimitiveType::Triangles, states); + else + { + target.draw(m_vertices.data() + m_frameB.numberOfVertices, m_frameA.numberOfVertices, sf::PrimitiveType::Triangles, states); + target.draw(m_vertices.data(), m_frameB.numberOfVertices, sf::PrimitiveType::Triangles, states); + } + } + else + { + if (m_drawAOverB) + { + states.texture = m_frameB.pTexture; + target.draw(m_vertices.data(), m_frameB.numberOfVertices, sf::PrimitiveType::Triangles, states); + states.texture = m_frameA.pTexture; + target.draw(m_vertices.data() + m_frameB.numberOfVertices, m_frameA.numberOfVertices, sf::PrimitiveType::Triangles, states); + } + else + { + states.texture = m_frameA.pTexture; + target.draw(m_vertices.data() + m_frameB.numberOfVertices, m_frameA.numberOfVertices, sf::PrimitiveType::Triangles, states); + states.texture = m_frameB.pTexture; + target.draw(m_vertices.data(), m_frameB.numberOfVertices, sf::PrimitiveType::Triangles, states); + } + } +} +void FrameTransition::priv_update() const +{ + m_isUpdateRequired = false; + m_vertices.resize(m_frameA.numberOfVertices + m_frameB.numberOfVertices); + + + + enum class Type + { + TexCrop, + Zoom, + } type; + + if ((m_transitionId & T::Type) == T::Type_Zoom) + type = Type::Zoom; + else + type = Type::TexCrop; + + switch (type) + { + case Type::Zoom: + priv_updateFromZoom(); + break; + case Type::TexCrop: + priv_updateFromTexCrop(); + break; + } + + + + sf::Color colorA{}; + sf::Color colorB{}; + + switch (m_transitionId & T::Fade_A) + { + case T::Fade_A_Step: + colorA = (m_ratio > 0.5f) ? colorFromColorAndAlpha(m_frameA.color, 0u) : m_frameA.color; + break; + case T::Fade_A_Linear: + colorA = colorFromColorAndAlpha(m_frameA.color, std::lround(m_frameA.color.a * (1.f - m_ratio))); + break; + case T::Fade_A_Off: + colorA = colorFromColorAndAlpha(m_frameA.color, 0u); + break; + case T::Fade_A_None: + colorA = m_frameA.color; + break; + } + switch (m_transitionId & T::Fade_B) + { + case T::Fade_B_Step: + colorB = (m_ratio > 0.5f) ? m_frameB.color : colorFromColorAndAlpha(m_frameB.color, 0u); + break; + case T::Fade_B_Linear: + colorB = colorFromColorAndAlpha(m_frameB.color, std::lround(m_frameA.color.a * m_ratio)); + break; + case T::Fade_B_Off: + colorB = colorFromColorAndAlpha(m_frameB.color, 0u); + break; + case T::Fade_B_None: + colorB = m_frameB.color; + break; + } + + for (std::size_t i{ 0u }; i < m_frameB.numberOfVertices; ++i) + m_vertices[i].color = colorB; + for (std::size_t i{ 0u }; i < m_frameA.numberOfVertices; ++i) + m_vertices[m_frameB.numberOfVertices + i].color = colorA; +} +void FrameTransition::priv_updateFromTexCrop() const +{ + float ratio{ m_ratio }; + float inverseRatio{ 1.f - m_ratio }; + bool swapDirection{ false }; + + + + enum class Direction + { + Right, + Left, + Down, + Up, + } direction; + if ((m_transitionId & T::Direction_Up) == T::Direction_Up) + direction = Direction::Up; + else if ((m_transitionId & T::Direction_Left) != T::None) + direction = Direction::Left; + else if ((m_transitionId & T::Direction_Down) != T::None) + direction = Direction::Down; + else + direction = Direction::Right; + + switch (direction) + { + case Direction::Left: + case Direction::Up: + swapDirection = true; + break; + } + + + + // front is left/up (depending on horizontal/vertical direction) + // back is right/down (depending on horizontal/vertical direction) + // note that this is different from "start" and "end" which refers to different edges depending on direction (e.g. start is right edge when direction is left) + enum class TexCrop + { + None, + Front, + Back, + Both, + Shuffle, + }; + TexCrop texCropA{ TexCrop::None }; + TexCrop texCropB{ TexCrop::None }; + + T transitionTexCropA{ m_transitionId & T::TexCrop_A }; + T transitionTexCropB{ m_transitionId & T::TexCrop_B }; + + if ((transitionTexCropA & T::TexCrop_A_Shuffle) != T::None) + texCropA = TexCrop::Shuffle; + else if ((m_transitionId & T::TexCrop_A_Both) == T::TexCrop_A_Both) + texCropA = TexCrop::Both; + else if ((m_transitionId & T::TexCrop_A_Start) != T::None) + texCropA = TexCrop::Front; + else if ((m_transitionId & T::TexCrop_A_End) != T::None) + texCropA = TexCrop::Back; + else + texCropA = TexCrop::None; + + if ((transitionTexCropB & T::TexCrop_B_Shuffle) != T::None) + texCropB = TexCrop::Shuffle; + else if ((m_transitionId & T::TexCrop_B_Both) == T::TexCrop_B_Both) + texCropB = TexCrop::Both; + else if ((m_transitionId & T::TexCrop_B_Start) != T::None) + texCropB = TexCrop::Front; + else if ((m_transitionId & T::TexCrop_B_End) != T::None) + texCropB = TexCrop::Back; + else + texCropB = TexCrop::None; + + + if (swapDirection) + { + // since front and back are currenty equal to start and end, flip them if we are facing in opposite direction + if (texCropA == TexCrop::Front) + texCropA = TexCrop::Back; + else if (texCropA == TexCrop::Back) + texCropA = TexCrop::Front; + if (texCropB == TexCrop::Back) + texCropB = TexCrop::Front; + else if (texCropB == TexCrop::Front) + texCropB = TexCrop::Back; + } + + + + sf::FloatRect texRectA(m_frameA.textureRect); + sf::FloatRect texRectB(m_frameB.textureRect); + float scaleSizeA{}; + float scaleSizeB{}; + switch (direction) + { + case Direction::Left: + case Direction::Right: + scaleSizeA = texRectA.width; + scaleSizeB = texRectB.width; + break; + case Direction::Up: + case Direction::Down: + scaleSizeA = texRectA.height; + scaleSizeB = texRectB.height; + break; + } + + + + float offsetPosA{}; + float offsetPosB{}; + switch (texCropA) + { + case TexCrop::None: + break; + case TexCrop::Back: + offsetPosA = 0.f; + break; + case TexCrop::Front: + offsetPosA = scaleSizeA * ratio; + break; + case TexCrop::Both: + offsetPosA = scaleSizeA * ratio * 0.5f; + break; + case TexCrop::Shuffle: + if (swapDirection) + offsetPosA = scaleSizeA * ((ratio > 0.5f) ? inverseRatio : ratio); + else + offsetPosA = (ratio < 0.5f) ? 0.f : scaleSizeA * ((ratio * 2.f) - 1.f); + break; + } + switch (texCropB) + { + case TexCrop::None: + break; + case TexCrop::Back: + offsetPosB = 0.f; + break; + case TexCrop::Front: + offsetPosB = scaleSizeB * inverseRatio; + break; + case TexCrop::Both: + offsetPosB = scaleSizeB * inverseRatio * 0.5f; + break; + case TexCrop::Shuffle: + if (swapDirection) + offsetPosB = (ratio > 0.5f) ? 0.f : scaleSizeB * (1.f - (ratio * 2.f)); + else + offsetPosB = scaleSizeB * ((ratio > 0.5f) ? inverseRatio : ratio); + break; + } + + scaleSizeA *= inverseRatio; + scaleSizeB *= ratio; + switch (direction) + { + case Direction::Left: + case Direction::Right: + texRectA.left = offsetPosA; + texRectA.width = scaleSizeA; + texRectB.left = offsetPosB; + texRectB.width = scaleSizeB; + break; + case Direction::Down: + case Direction::Up: + texRectA.top = offsetPosA; + texRectA.height = scaleSizeA; + texRectB.top = offsetPosB; + texRectB.height = scaleSizeB; + break; + } + + + + + + if (texCropA == TexCrop::None) + texRectA = sf::FloatRect(m_frameA.textureRect); + if (texCropB == TexCrop::None) + texRectB = sf::FloatRect(m_frameB.textureRect); + + + + Quad quadA; + Quad quadB; + + Quad* qa{ &quadA }; + Quad* qb{ &quadB }; + + if (swapDirection) + { + std::swap(ratio, inverseRatio); + std::swap(qa, qb); + } + + switch (direction) + { + case Direction::Right: + case Direction::Left: + qa->topLeft.position = { m_size.x * ratio, 0.f }; + qa->bottomLeft.position = { m_size.x * ratio, m_size.y }; + qa->bottomRight.position = m_size; + qa->topRight.position = { m_size.x, 0.f }; + + qb->topLeft.position = { 0.f, 0.f }; + qb->bottomLeft.position = { 0.f, m_size.y }; + qb->bottomRight.position = { m_size.x * ratio, m_size.y }; + qb->topRight.position = { m_size.x * ratio, 0.f }; + break; + case Direction::Down: + case Direction::Up: + qa->topLeft.position = { 0.f, m_size.y * ratio }; + qa->bottomLeft.position = { 0.f, m_size.y }; + qa->bottomRight.position = m_size; + qa->topRight.position = { m_size.x, m_size.y * ratio }; + + qb->topLeft.position = { 0.f, 0.f }; + qb->bottomLeft.position = { 0.f, m_size.y * ratio }; + qb->bottomRight.position = { m_size.x, m_size.y * ratio }; + qb->topRight.position = { m_size.x, 0.f }; + break; + } + + + + priv_setQuadTextureCoordsFromRect(quadA, texRectA); + priv_setQuadTextureCoordsFromRect(quadB, texRectB); + + priv_addQuad(0u, quadB); + priv_addQuad(m_frameB.numberOfVertices, quadA); +} +void FrameTransition::priv_updateFromZoom() const +{ + const float ratio{ m_ratio }; + + enum class ZoomType + { + Crop, + Scale, + }; + const ZoomType zoomTypeA{ ((m_transitionId & T::ZoomType_A) == T::ZoomType_A_Scale) ? ZoomType::Scale : ZoomType::Crop }; + const ZoomType zoomTypeB{ ((m_transitionId & T::ZoomType_B) == T::ZoomType_B_Scale) ? ZoomType::Scale : ZoomType::Crop }; + + const float zoomScaleA{ m_parameter1 }; + const float zoomScaleB{ m_parameter2 }; + + // we use divide by this reciprical (later) instead of the standard multiplication so that texture cropping is as if it was "un-scaled" + // this allows cropping and scaling to be used together and they match movement + const float zoomScaleARecip{ 1.f / ((zoomScaleA > 0.f) ? zoomScaleA : 0.001f) }; + const float zoomScaleBRecip{ 1.f / ((zoomScaleB > 0.f) ? zoomScaleB : 0.001f) }; + + float zoomSizeScaleA{ zoomTypeA == ZoomType::Scale ? zoomScaleA : zoomScaleARecip }; + float zoomSizeScaleB{ zoomTypeB == ZoomType::Scale ? zoomScaleB : zoomScaleBRecip }; + + enum class ZoomMovementType + { + None, + In, + Out, + InOut, + OutIn, + }; + ZoomMovementType zoomMovementTypeA{}; + ZoomMovementType zoomMovementTypeB{}; + switch (m_transitionId & T::Zoom_A) + { + case T::Zoom_A_OutIn: + zoomMovementTypeA = (zoomTypeA == ZoomType::Scale) ? ZoomMovementType::InOut : ZoomMovementType::OutIn; + break; + case T::Zoom_A_InOut: + zoomMovementTypeA = (zoomTypeA == ZoomType::Scale) ? ZoomMovementType::OutIn : ZoomMovementType::InOut; + break; + case T::Zoom_A_Out: + zoomMovementTypeA = (zoomTypeA == ZoomType::Scale) ? ZoomMovementType::In : ZoomMovementType::Out; + break; + case T::Zoom_A_In: + zoomMovementTypeA = (zoomTypeA == ZoomType::Scale) ? ZoomMovementType::Out : ZoomMovementType::In; + break; + case T::Zoom_A_None: + default: + zoomMovementTypeA = ZoomMovementType::None; + } + switch (m_transitionId & T::Zoom_B) + { + case T::Zoom_B_OutIn: + zoomMovementTypeB = (zoomTypeB == ZoomType::Scale) ? ZoomMovementType::InOut : ZoomMovementType::OutIn; + break; + case T::Zoom_B_InOut: + zoomMovementTypeB = (zoomTypeB == ZoomType::Scale) ? ZoomMovementType::OutIn : ZoomMovementType::InOut; + break; + case T::Zoom_B_Out: + zoomMovementTypeB = (zoomTypeB == ZoomType::Scale) ? ZoomMovementType::In : ZoomMovementType::Out; + break; + case T::Zoom_B_In: + zoomMovementTypeB = (zoomTypeB == ZoomType::Scale) ? ZoomMovementType::Out : ZoomMovementType::In; + break; + case T::Zoom_B_None: + default: + zoomMovementTypeB = ZoomMovementType::None; + } + + float multiplierA{}; + float multiplierB{}; + switch (zoomMovementTypeA) + { + case ZoomMovementType::OutIn: + multiplierA = (ratio > 0.5f) ? linearInterpolation(1.f, zoomSizeScaleA, (ratio * 2.f) - 1.f) : linearInterpolation(zoomSizeScaleA, 1.f, ratio * 2.f); + break; + case ZoomMovementType::InOut: + multiplierA = (ratio > 0.5f) ? linearInterpolation(zoomSizeScaleA, 1.f, (ratio * 2.f) - 1.f) : linearInterpolation(1.f, zoomSizeScaleA, ratio * 2.f); + break; + case ZoomMovementType::Out: + multiplierA = linearInterpolation(zoomSizeScaleA, 1.f, ratio); + break; + case ZoomMovementType::In: + multiplierA = linearInterpolation(1.f, zoomSizeScaleA, ratio); + break; + case ZoomMovementType::None: + default: + multiplierA = 1.f; + } + switch (zoomMovementTypeB) + { + case ZoomMovementType::OutIn: + multiplierB = (ratio > 0.5f) ? linearInterpolation(1.f, zoomSizeScaleB, (ratio * 2.f) - 1.f) : linearInterpolation(zoomSizeScaleB, 1.f, ratio * 2.f); + break; + case ZoomMovementType::InOut: + multiplierB = (ratio > 0.5f) ? linearInterpolation(zoomSizeScaleB, 1.f, (ratio * 2.f) - 1.f) : linearInterpolation(1.f, zoomSizeScaleB, ratio * 2.f); + break; + case ZoomMovementType::Out: + multiplierB = linearInterpolation(zoomSizeScaleB, 1.f, ratio); + break; + case ZoomMovementType::In: + multiplierB = linearInterpolation(1.f, zoomSizeScaleB, ratio); + break; + case ZoomMovementType::None: + default: + multiplierB = 1.f; + } + + + + sf::FloatRect texRectA(m_frameA.textureRect); + sf::FloatRect texRectB(m_frameB.textureRect); + + sf::Vector2f quadSizeA{ m_size }; + sf::Vector2f quadSizeB{ m_size }; + sf::Vector2f texSizeA{ texRectA.getSize() }; + sf::Vector2f texSizeB{ texRectB.getSize() }; + switch (zoomTypeA) + { + case ZoomType::Scale: + quadSizeA *= multiplierA; + break; + case ZoomType::Crop: + texSizeA /= multiplierA; + break; + } + switch (zoomTypeB) + { + case ZoomType::Scale: + quadSizeB *= multiplierB; + break; + case ZoomType::Crop: + texSizeB /= multiplierB; + break; + } + + + + // top lefts calculated to place the resized rectangles in the centre of their originals + sf::Vector2f texTopLeftA{ (texRectA.getSize() - texSizeA) * 0.5f }; + sf::Vector2f texTopLeftB{ (texRectB.getSize() - texSizeB) * 0.5f }; + sf::Vector2f posTopLeftA{ (m_size - quadSizeA) * 0.5f }; + sf::Vector2f posTopLeftB{ (m_size - quadSizeB) * 0.5f }; + + // resized texture rectangles + texRectA.left = texTopLeftA.x; + texRectA.top = texTopLeftA.y; + texRectA.width = texSizeA.x; + texRectA.height = texSizeA.y; + + texRectB.left = texTopLeftB.x; + texRectB.top = texTopLeftB.y; + texRectB.width = texSizeB.x; + texRectB.height = texSizeB.y; + + // resized quad rectangles + sf::FloatRect posRectA{}; + sf::FloatRect posRectB{}; + + posRectA.left = posTopLeftA.x; + posRectA.top = posTopLeftA.y; + posRectA.width = quadSizeA.x; + posRectA.height = quadSizeA.y; + + posRectB.left = posTopLeftB.x; + posRectB.top = posTopLeftB.y; + posRectB.width = quadSizeB.x; + posRectB.height = quadSizeB.y; + + + + Quad quadA{}; + Quad quadB{}; + + priv_setQuadPositionsFromRect(quadA, posRectA); + priv_setQuadPositionsFromRect(quadB, posRectB); + + priv_setQuadTextureCoordsFromRect(quadA, texRectA); + priv_setQuadTextureCoordsFromRect(quadB, texRectB); + + priv_addQuad(0u, quadB); + priv_addQuad(m_frameB.numberOfVertices, quadA); +} +void FrameTransition::priv_addQuad(const std::size_t startVertex, const sf::Vertex topLeft, const sf::Vertex bottomLeft, const sf::Vertex bottomRight, const sf::Vertex topRight) const +{ + m_vertices[startVertex + 0u] = topLeft; + m_vertices[startVertex + 1u] = bottomLeft; + m_vertices[startVertex + 2u] = bottomRight; + m_vertices[startVertex + 3u] = topLeft; + m_vertices[startVertex + 4u] = bottomRight; + m_vertices[startVertex + 5u] = topRight; +} +void FrameTransition::priv_addQuad(const std::size_t startVertex, const Quad& quad) const +{ + priv_addQuad(startVertex, quad.topLeft, quad.bottomLeft, quad.bottomRight, quad.topRight); +} +void FrameTransition::priv_setQuadPositionsFromRect(Quad& quad, sf::FloatRect rect) const +{ + const sf::Vector2f topLeft(rect.getPosition()); + const sf::Vector2f bottomRight{ sf::Vector2f(rect.getSize()) + topLeft }; + quad.topLeft.position = topLeft; + quad.bottomRight.position = bottomRight; + quad.bottomLeft.position = { topLeft.x, bottomRight.y }; + quad.topRight.position = { bottomRight.x, topLeft.y }; +} +void FrameTransition::priv_setQuadTextureCoordsFromRect(Quad& quad, sf::FloatRect rect) const +{ + const sf::Vector2f topLeft(rect.getPosition()); + const sf::Vector2f bottomRight{ sf::Vector2f(rect.getSize()) + topLeft }; + quad.topLeft.texCoords = topLeft; + quad.bottomRight.texCoords = bottomRight; + quad.bottomLeft.texCoords = { topLeft.x, bottomRight.y }; + quad.topRight.texCoords = { bottomRight.x, topLeft.y }; +} +const FrameTransition::Frame& FrameTransition::priv_getFrame(const FrameId frameId) const +{ + return (frameId == FrameId::A) ? m_frameA : m_frameB; +} +FrameTransition::Frame& FrameTransition::priv_getFrame(const FrameId frameId) +{ + return (frameId == FrameId::A) ? m_frameA : m_frameB; +} + +} // namespace selbward diff --git a/src/SelbaWard/FrameTransition.hpp b/src/SelbaWard/FrameTransition.hpp new file mode 100644 index 0000000..874a17f --- /dev/null +++ b/src/SelbaWard/FrameTransition.hpp @@ -0,0 +1,352 @@ +////////////////////////////////////////////////////////////////////////////// +// +// Selba Ward (https://github.com/Hapaxia/SelbaWard) +// -- +// +// Frame Transition +// +// Copyright(c) 2023-2024 M.J.Silk +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions : +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software.If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +// M.J.Silk +// MJSilk2@gmail.com +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef SELBAWARD_FRAMETRANSITION_HPP +#define SELBAWARD_FRAMETRANSITION_HPP + +#include "Common.hpp" + +#include + +namespace selbaward +{ + +// SW Frame Transition v1.0.0 +class FrameTransition : public sf::Drawable, public sf::Transformable +{ +public: + enum class FrameId + { + A, // "start" or "source" frame, shown fully (usually) at 0 ratio + B, // "end" or "destination" frame, shown fully (usually) at 1 ratio + }; + + enum class T + { + // prefixes-only are bitmasks that cover all of that group + // e.g. Type can be used to check types only + + None = 0u, // used as a general "none" (useful for non-overly-verbose conditionals) + + + + // "_" in names are separators that show groups and each group can be (bit)masked using the name before the "_". + // e.g. TexCrop_A masks TexCrop_A_None, TexCrop_A_Start, TexCrop_A_End... + // whereas TexCrop masks all of TexCrop_A as well as TexCrop_B + + // can combine a type with any - or all - of the groups it "uses" + // e.g. with a TexCrop type, you can set the TexCrop group, the Direction group, both, or neither. + // and, within those groups, you can set A, B, both, or neither (if the group allows separate A and B settings e.g. Direction cannot be set separately for A and B) + + // Types + // + // [] = global (available for all types) + // "" = set outside of the Transition ID (T) (e.g. "parameters" are set via setParameter1 and setParameter2 methods) + // + // TexCrop + // uses: + // TexCrop_ + // Direction_ + // [Fade_] + // + // Zoom + // uses: + // Zoom_ + // ZoomType_ + // [Fade_] + // "parameters" + + Type_TexCrop = 0u, + Type_Zoom = 1u << 0u, + Type = 1u << 0u, // 1 bit + + + + // global + // applies to all types + + // fade + // can be set separately for A and B + // "none" : keeps colours exactly as they are - does not modify alpha for fades + // "off" : sets alpha to zero, allowing that frame to be invisible for the entire time + // "step" : for A, starts at normal colour and changes alpha to zero half way through; for B, start with alpha of zero and resets it half way through + // "linear" : linearly interpolates alpha. for A, starts at normal colour and interpolates alpha to zero; for B, starts with alpha of zero and interpolates to normal colour's alpha + + Fade_A_None = 0u, + Fade_A_Off = 1u << 1u, + Fade_A_Step = 2u << 1u, + Fade_A_Linear = 3u << 1u, + Fade_A = 3u << 1u, // 2 bits + Fade_B_None = 0u, + Fade_B_Off = 1u << 3u, + Fade_B_Step = 2u << 3u, + Fade_B_Linear = 3u << 3u, + Fade_B = 3u << 3u, // 2 bits + Fade = Fade_A | Fade_B, // 4 bits + + + + // tex crop + // "none" scales the texture: the entire texture (rect) is fit inside the quad. (others keep the same size texture but crop it) + // "start" and "end" are which side crops + // "start" is the beginning side of the direction (e.g. left side when direction is "right") + // "end" is the end side of the direction (e.g. right side when direction is "right") + // "both" crops both opposite sides (start and end) equally and keeps the center in the center of the quad + // "shuffle" is a special form that is designed to animate the shuffling of the frames (A slides "behind" during 2nd half, B slides "out" during 1st half) + // front edge is left for horizontal directions (left/right) and top for vertical directions (up/down) + // back edge is right for horizontal directions (left/right) and bottom for vertical directions (up/down) + // + // direction: + // this is the direction of the separating edge (the line that separates the two quads - they don't overlap) + // right: vertical separator starts from the left and moves to the right + // left: vertical separator starts from the right and moves to the left + // down: horizontal separator starts from the top and moves down to the bottom + // up: horizontal separator starts from the bottom and moves up to the top + + TexCrop_A_None = 0u, + TexCrop_A_Start = 1u << 5u, + TexCrop_A_End = 2u << 5u, + TexCrop_A_Both = TexCrop_A_Start | TexCrop_A_End, + TexCrop_A_Shuffle = 4u << 5u, + TexCrop_A = 7u << 5u, // 3 bits + TexCrop_B_None = 0u, + TexCrop_B_Start = 1u << 8u, + TexCrop_B_End = 2u << 8u, + TexCrop_B_Both = TexCrop_B_Start | TexCrop_B_End, + TexCrop_B_Shuffle = 4u << 8u, + TexCrop_B = 7u << 8u, // 3 bits + TexCrop = TexCrop_A | TexCrop_B, // 6 bits + + Direction_Right = 0u, + Direction_Left = 1u << 11u, + Direction_Down = 2u << 11u, + Direction_Up = 3u << 11u, + Direction = 3u << 11u, // 2 bits + + + + // zooming (can also be set separately for A and B): + // zooming in means the image will be larger at the end + // zooming in means the image will be smaller at the end + // zooming in&out means the image will be larger in the middle and back to normal by the end + // zooming out&in means the image will be smaller in the middle and back to normal by the end + // + // zoomtype is whether is crops the texture rect or scales the quad to zoom in and/or out (can be set separately for A and B) + // note that some combinations can cause an start or end state that isn't the full texture rect/quad of a frame (e.g. zoom out with scale ends with small, scaled B) + // + // parameters: + // parameter1: "A scale" (scales the quad or texture rect for zooming in or out) for A. this should be in the range 0-1 + // parameter2: "B scale" (scales the quad or texture rect for zooming in or out) for B. this should be in the range 0-1 + // low values (under 0.1) are only recommended for scale zoom types (not for crop zoom types) but experimentation is encouraged + + + Zoom_A_None = 0u, + Zoom_A_In = 1u << 5u, + Zoom_A_Out = 2u << 5u, + Zoom_A_InOut = 3u << 5u, + Zoom_A_OutIn = 4u << 5u, + Zoom_A = 7u << 5u, // 3 bits + Zoom_B_None = 0u, + Zoom_B_In = 1u << 8u, + Zoom_B_Out = 2u << 8u, + Zoom_B_InOut = 3u << 8u, + Zoom_B_OutIn = 4u << 8u, + Zoom_B = 7u << 8u, // 3 bits + Zoom = Zoom_A | Zoom_B, // 6 bits + + ZoomType_A_Crop = 0u, + ZoomType_A_Scale = 1u << 11u, + ZoomType_A = 1u << 11u, // 1 bit + ZoomType_B_Crop = 0u, + ZoomType_B_Scale = 1u << 12u, + ZoomType_B = 1u << 12u, // 1 bit + ZoomType = ZoomType_A | ZoomType_B, // 2 bits + }; + + // creation and size + FrameTransition(sf::Vector2f size = { 64.f, 8.f }); + void setSize(sf::Vector2f size); + sf::Vector2f getSize() const; + + // draw order + void setDrawOrderToAOverB(); // this should be always be used except for specific reasons. this places A over B and can optimise draw calls if possible. + void setDrawOrderToBOverA(); // this forces B to be drawn over A. always takes 2 separate draw calls (one for A and one for B) + + // transition ID (all transitions information; the T bitwise enum class) + void setTransition(T transitionId); + T getTransition() const; + + // transition ratio/alpha (0-1) + void setRatio(float ratio); + float getRatio() const; + void setPercentage(float percentage); // (0-100 percent instead of 0-1 ratio/alpha) + float getPercentage() const; // (0-100 percent instead of 0-1 ratio/alpha) + template + void setFromValueInRange(const Type& value, const Type& min, const Type& max); // (min-max) + template + void setFromValueInRange(const Type& value, const Type& range); // (0-range) + + // visual representation + void setColors(sf::Color colorA, sf::Color colorB); + void setColors(sf::Color color); + void setColor(FrameId frameId, sf::Color color); + sf::Color getColor(FrameId frameId) const; + + // texturing + void setTextures(const sf::Texture& textureA, const sf::Texture& textureB); + void setTextures(const sf::Texture& texture); + void setTextures(); // clear/nullify textures + void setTexture(FrameId frameId, const sf::Texture& texture, bool resetRect = false); + void setTexture(FrameId frameId); // clear/nullify texture + void setTextureRect(FrameId, const sf::IntRect& textureRectangle = sf::IntRect{}); + const sf::Texture& getTexture(FrameId frameId) const; + + // parameters + void setParameter1(float parameterValue = 0.f); + void setParameter2(float parameterValue = 0.f); + float getParameter1() const; + float getParameter2() const; + void resetParameters(); + + // bounds + sf::FloatRect getLocalBounds() const; + sf::FloatRect getGlobalBounds() const; + +private: + float m_ratio; + sf::Vector2f m_size; + T m_transitionId; + bool m_drawAOverB; + float m_parameter1; + float m_parameter2; + + struct Frame + { + const sf::Texture* pTexture{}; + sf::IntRect textureRect{}; + sf::Color color{ sf::Color::White }; + std::size_t numberOfVertices{}; + }; + Frame m_frameA; + Frame m_frameB; + + struct Quad + { + sf::Vertex topLeft; + sf::Vertex bottomLeft; + sf::Vertex bottomRight; + sf::Vertex topRight; + + void setColor(const sf::Color color) + { + topLeft.color = color; + bottomLeft.color = color; + bottomRight.color = color; + topRight.color = color; + } + }; + + mutable bool m_isUpdateRequired; + mutable std::vector m_vertices; + + virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const; + void priv_update() const; + void priv_updateFromTexCrop() const; + void priv_updateFromZoom() const; + void priv_addQuad( + const std::size_t startVertex, + const sf::Vertex topLeft, + const sf::Vertex bottomLeft, + const sf::Vertex bottomRight, + const sf::Vertex topRight) const; + void priv_addQuad(const std::size_t startVertex, const Quad& quad) const; + void priv_setQuadPositionsFromRect(Quad& quad, sf::FloatRect rect) const; + void priv_setQuadTextureCoordsFromRect(Quad& quad, sf::FloatRect rect) const; + const Frame& priv_getFrame(const FrameId frameId) const; + Frame& priv_getFrame(const FrameId frameId); +}; + +inline FrameTransition::T operator|(FrameTransition::T a, FrameTransition::T b) +{ + return static_cast(static_cast(a) | static_cast(b)); +} +inline FrameTransition::T operator^(FrameTransition::T a, FrameTransition::T b) +{ + return static_cast(static_cast(a) ^ static_cast(b)); +} +inline FrameTransition::T operator&(FrameTransition::T a, FrameTransition::T b) +{ + return static_cast(static_cast(a) & static_cast(b)); +} +inline FrameTransition::T operator~(FrameTransition::T a) +{ + return static_cast(~static_cast(a)); +} +inline FrameTransition::T operator>>(FrameTransition::T a, std::size_t bits) +{ + return static_cast(static_cast(a) >> bits); +} +inline FrameTransition::T operator<<(FrameTransition::T a, std::size_t bits) +{ + return static_cast(static_cast(a) << bits); +} + +inline sf::Vector2f FrameTransition::getSize() const +{ + return m_size; +} +inline FrameTransition::T FrameTransition::getTransition() const +{ + return m_transitionId; +} +inline float FrameTransition::getRatio() const +{ + return m_ratio; +} +inline float FrameTransition::getPercentage() const +{ + return m_ratio * 100.f; +} + +template +void FrameTransition::setFromValueInRange(const Type& value, const Type& minimum, const Type& maximum) +{ + setRatio(static_cast(value - minimum) / static_cast(maximum - minimum)); +} +template +void FrameTransition::setFromValueInRange(const Type& value, const Type& range) +{ + setRatio(static_cast(value) / static_cast(range)); +} + +} // namespace selbaward +#endif // SELBAWARD_PROGRESSBAR_HPP From 2b6d14770efc757b52bd6ffbf502467e9c5c08d5 Mon Sep 17 00:00:00 2001 From: Hapaxia Date: Wed, 3 Jan 2024 16:15:03 +0000 Subject: [PATCH 59/64] Update readme.md --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 3fa0b26..ddb1e79 100644 --- a/readme.md +++ b/readme.md @@ -6,7 +6,7 @@ A collection of SFML drawables by [Hapaxia](http://github.com/Hapaxia) -Contents: **Bitmap Text**, **Console Screen**, **Crosshair**, **Elastic Sprite**, **Gallery Sprite**, **Line**, **Nine Patch**, **Pie Chart**, **Pixel Display**, **Polygon**, **Progress Bar**, **Ring**, **Spinning Card**, **Spline**, **Sprite 3D**, **Sprite Batch**, **Starfield**, **Starfield 3D**, **Tile Map** +Contents: **Bitmap Text**, **Console Screen**, **Crosshair**, **Elastic Sprite**, **Frame Transition**, **Gallery Sprite**, **Line**, **Nine Patch**, **Pie Chart**, **Pixel Display**, **Polygon**, **Progress Bar**, **Ring**, **Spinning Card**, **Spline**, **Sprite 3D**, **Sprite Batch**, **Starfield**, **Starfield 3D**, **Tile Map** ## For information, view the [Wiki]. From 5ffd546ca1711a43d7ab70b2da572f7016aa954a Mon Sep 17 00:00:00 2001 From: Hapaxia Date: Tue, 16 Jan 2024 21:05:01 +0000 Subject: [PATCH 60/64] update year to 2024 --- licence.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/licence.txt b/licence.txt index 04edf34..ac201ce 100644 --- a/licence.txt +++ b/licence.txt @@ -1,6 +1,6 @@ Selba Ward (https://github.com/Hapaxia/SelbaWard) -Copyright (c) 2014-2023 M. J. Silk +Copyright (c) 2014-2024 M. J. Silk This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages From a6887244c909c38d547ed7eaea2585db3b75a616 Mon Sep 17 00:00:00 2001 From: Hapaxia Date: Mon, 12 Feb 2024 21:26:52 +0000 Subject: [PATCH 61/64] update Polygon to v1.3 update Polygon to v1.3, adding some extra functionality. adds ability to manually set triangle limit: maximum amount of triangles that can be created before the update is halted. the default is 10000 (this limit was previously hard-coded as 100). adds ability to add a "wireframe" mesh over the top of the polygon. this is drawn using separate lines and is rebuilt (updated) whenever the polygon is updated. it's based on the final triangles after triangulation so will continue to work when other methods are added. the wireframe can be set to be shown or not and its colour can also be set. if it's set to not be shown, it will clear it (as well as not build it or draw it) during the update. note that this means that update will need to be called if this is modified. in addition, casts have been corrected: now casts to the long double it should be. also added const where a parameter is not expected to change, and removed some unused (commented-out) code. --- src/SelbaWard/Polygon.cpp | 102 ++++++++++++++++++++++++++++---------- src/SelbaWard/Polygon.hpp | 18 ++++++- 2 files changed, 93 insertions(+), 27 deletions(-) diff --git a/src/SelbaWard/Polygon.cpp b/src/SelbaWard/Polygon.cpp index 6fd523f..e5ec6a4 100644 --- a/src/SelbaWard/Polygon.cpp +++ b/src/SelbaWard/Polygon.cpp @@ -46,30 +46,22 @@ inline bool isSecondVectorAntiClockwiseOfFirstVector(const sf::Vector2f& first, return (first.x * second.y) < (first.y * second.x); } -inline bool pointIsInsideTriangle(const std::vector& points, sf::Vector2f point) +inline bool pointIsInsideTriangle(const std::vector& points, const sf::Vector2f point) { - long double point1X{ static_cast(points[0].x) }; - long double point1Y{ static_cast(points[0].y) }; - long double point2X{ static_cast(points[1].x) }; - long double point2Y{ static_cast(points[1].y) }; - long double point3X{ static_cast(points[2].x) }; - long double point3Y{ static_cast(points[2].y) }; - long double pointX{ static_cast(point.x) }; - long double pointY{ static_cast(point.y) }; + long double point1X{ static_cast(points[0].x) }; + long double point1Y{ static_cast(points[0].y) }; + long double point2X{ static_cast(points[1].x) }; + long double point2Y{ static_cast(points[1].y) }; + long double point3X{ static_cast(points[2].x) }; + long double point3Y{ static_cast(points[2].y) }; + long double pointX{ static_cast(point.x) }; + long double pointY{ static_cast(point.y) }; long double denominatorMultiplier{ 1.l / ((point2Y - point3Y) * (point1X - point3X) + (point3X - point2X) * (point1Y - point3Y)) }; long double a{ ((point2Y - point3Y) * (pointX - point3X) + (point3X - point2X) * (pointY - point3Y)) * denominatorMultiplier }; long double b{ ((point3Y - point1Y) * (pointX - point3X) + (point1X - point3X) * (pointY - point3Y)) * denominatorMultiplier }; long double c{ 1.l - a - b }; return a >= 0.l && a <= 1.l && b >= 0.l && b <= 1.l && c >= 0.l && c <= 1.l; - - /* - float denominatorMultiplier{ 1.f / ((points[1u].y - points[2u].y) * (points[0u].x - points[2u].x) + (points[2u].x - points[1u].x) * (points[0u].y - points[2u].y)) }; - float a{ ((points[1u].y - points[2u].y) * (point.x - points[2u].x) + (points[2u].x - points[1u].x) * (point.y - points[2u].y)) * denominatorMultiplier }; - float b{ ((points[2u].y - points[0u].y) * (point.x - points[2u].x) + (points[0u].x - points[2u].x) * (point.y - points[2u].y)) * denominatorMultiplier }; - float c{ 1.f - a - b }; - return a >= 0.f && a <= 1.f && b >= 0.f && b <= 1.f && c >= 0.f && c <= 1.f; - */ } inline float crossProduct(const sf::Vector2f& a, const sf::Vector2f& b) @@ -92,8 +84,12 @@ Polygon::Polygon() , m_vertices() , m_holeStartIndices() , m_color{ sf::Color::White } + , m_showWireframe{ false } + , m_wireframeVertices{} + , m_wireframeColor{ sf::Color::White } , m_triangulationMethod{ TriangulationMethod::BasicEarClip } , m_meshRefinementMethod{ MeshRefinementMethod::None } + , m_triangleLimit{ 10000u } , m_throwExceptions{ true } { @@ -169,6 +165,36 @@ sf::Vector2f Polygon::getVertexPosition(const std::size_t index) const return m_vertices[index].position; } +void Polygon::setTriangleLimit(const std::size_t triangleLimit) +{ + m_triangleLimit = triangleLimit; +} + +std::size_t Polygon::getTriangleLimit() const +{ + return m_triangleLimit; +} + +void Polygon::setShowWireframe(bool showWireframe) +{ + m_showWireframe = showWireframe; +} + +bool Polygon::getShowWireframe() const +{ + return m_showWireframe; +} + +void Polygon::setWireframeColor(sf::Color wireframeColor) +{ + m_wireframeColor = wireframeColor; +} + +sf::Color Polygon::getWireframeColor() const +{ + return m_wireframeColor; +} + void Polygon::addHoleStartIndex(const std::size_t index) { m_holeStartIndices.push_back(index); @@ -219,8 +245,10 @@ void Polygon::draw(sf::RenderTarget& target, sf::RenderStates states) const { states.texture = nullptr; states.transform *= getTransform(); - if (m_outputVertices.size() > 0) + if (!m_outputVertices.empty()) target.draw(m_outputVertices.data(), m_outputVertices.size(), sf::Triangles, states); + if (m_showWireframe && !m_wireframeVertices.empty()) + target.draw(m_wireframeVertices.data(), m_wireframeVertices.size(), sf::Lines, states); } void Polygon::priv_update() @@ -241,6 +269,8 @@ void Polygon::priv_updateOutputVertices() m_outputVertices[baseIndex + v].color = m_color; } } + + priv_buildWireframe(); } void Polygon::priv_triangulate() @@ -260,8 +290,6 @@ void Polygon::priv_triangulate() void Polygon::priv_triangulateEarClip() { - constexpr std::size_t stopAfterThisNumberOfTrianglesHaveBeenCreated{ 100u }; - // ear clipping method // polygon points must be anti-clockwise // hole points must be clockwise @@ -580,12 +608,12 @@ void Polygon::priv_triangulateEarClip() ear.erase(std::find(ear.begin(), ear.end(), indices[current])); indices.erase(currentIt); - if (m_triangles.size() == stopAfterThisNumberOfTrianglesHaveBeenCreated) + if (m_triangles.size() == m_triangleLimit) break; } // 3 vertices remaining; add final triangle - if (m_triangles.size() < stopAfterThisNumberOfTrianglesHaveBeenCreated) + if (m_triangles.size() < m_triangleLimit) { TriangleIndices triangle{ vertexNumbers[indices[0u]], vertexNumbers[indices[1u]], vertexNumbers[indices[2u]] }; m_triangles.push_back(triangle); @@ -594,8 +622,6 @@ void Polygon::priv_triangulateEarClip() void Polygon::priv_triangulateBasicEarClip() { - constexpr std::size_t stopAfterThisNumberOfTrianglesHaveBeenCreated{ 100u }; - // ear clipping method // polygon points must be anti-clockwise // number of triangles will always be (number of points - 2) @@ -711,11 +737,11 @@ void Polygon::priv_triangulateBasicEarClip() ear.erase(std::find(ear.begin(), ear.end(), indices[current])); indices.erase(currentIt); - if (m_triangles.size() == stopAfterThisNumberOfTrianglesHaveBeenCreated) + if (m_triangles.size() == m_triangleLimit) break; } - if (m_triangles.size() < stopAfterThisNumberOfTrianglesHaveBeenCreated) + if (m_triangles.size() < m_triangleLimit) { TriangleIndices triangle{ indices[0u], indices[1u], indices[2u] }; m_triangles.push_back(triangle); @@ -738,4 +764,28 @@ bool Polygon::priv_testVertexIndex(const std::size_t vertexIndex, const std::str return true; } +void Polygon::priv_buildWireframe() +{ + if (!m_showWireframe) + { + m_wireframeVertices.clear(); + return; + } + + m_wireframeVertices.resize(m_triangles.size() * 6u); + + for (std::size_t t{ 0u }; t < m_triangles.size(); ++t) + { + const std::size_t baseTriangleIndex{ t * 6u }; + for (std::size_t l{ 0u }; l < 3u; ++l) + { + const std::size_t baseLineIndex{ l * 2u }; + m_wireframeVertices[baseTriangleIndex + baseLineIndex + 0u].position = m_vertices[m_triangles[t][l]].position; + m_wireframeVertices[baseTriangleIndex + baseLineIndex + 1u].position = m_vertices[m_triangles[t][(l < 2u) ? l + 1u : 0u]].position; + m_wireframeVertices[baseTriangleIndex + baseLineIndex + 0u].color = m_wireframeColor; + m_wireframeVertices[baseTriangleIndex + baseLineIndex + 1u].color = m_wireframeColor; + } + } +} + } // namespace selbaward diff --git a/src/SelbaWard/Polygon.hpp b/src/SelbaWard/Polygon.hpp index 2897d89..ada554e 100644 --- a/src/SelbaWard/Polygon.hpp +++ b/src/SelbaWard/Polygon.hpp @@ -39,7 +39,7 @@ namespace selbaward { -// SW Polygon v1.2.3 +// SW Polygon v1.3.0 class Polygon : public sf::Drawable, public sf::Transformable { public: @@ -72,6 +72,15 @@ class Polygon : public sf::Drawable, public sf::Transformable void setVertexPosition(std::size_t index, sf::Vector2f position); sf::Vector2f getVertexPosition(std::size_t index) const; + void setTriangleLimit(std::size_t triangleLimit); + std::size_t getTriangleLimit() const; + + void setShowWireframe(bool showWireframe); + bool getShowWireframe() const; + + void setWireframeColor(sf::Color wireframeColor); + sf::Color getWireframeColor() const; + void reverseVertices(); void importVertexPositions(const std::vector& position); @@ -97,9 +106,15 @@ class Polygon : public sf::Drawable, public sf::Transformable std::vector m_holeStartIndices; sf::Color m_color; + bool m_showWireframe; + std::vector m_wireframeVertices; + sf::Color m_wireframeColor; + TriangulationMethod m_triangulationMethod; MeshRefinementMethod m_meshRefinementMethod; + std::size_t m_triangleLimit; + const bool m_throwExceptions; virtual void draw(sf::RenderTarget&, sf::RenderStates) const; @@ -110,6 +125,7 @@ class Polygon : public sf::Drawable, public sf::Transformable void priv_triangulateBasicEarClip(); bool priv_isValidVertexIndex(std::size_t vertexIndex) const; bool priv_testVertexIndex(std::size_t vertexIndex, const std::string& exceptionMessage) const; + void priv_buildWireframe(); }; } // namespace selbaward From d904450096834953eb5fda9646a95eca439feb41 Mon Sep 17 00:00:00 2001 From: Hapaxia Date: Mon, 12 Feb 2024 22:56:30 +0000 Subject: [PATCH 62/64] Spline - update to v1.7.1 (patch) patch update to fix non-thick splines not taking into account individual vertex colours. --- src/SelbaWard/Spline.cpp | 3 +++ src/SelbaWard/Spline.hpp | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/SelbaWard/Spline.cpp b/src/SelbaWard/Spline.cpp index 29354a0..13c5a2e 100644 --- a/src/SelbaWard/Spline.cpp +++ b/src/SelbaWard/Spline.cpp @@ -1015,6 +1015,9 @@ void Spline::priv_updateOutputVertices() else if (m_isClosed) nextVertex = m_vertices.begin(); + const sf::Color color{ m_color * linearInterpolation(currentVertex->color, nextVertex->color, vertexRatio) }; + m_outputVertices[outputIndex].color = color; + sf::Vector2f tangentUnit{ *(m_interpolatedVerticesUnitTangents.begin() + (it - begin)) }; if (m_isClosed || it != last) { diff --git a/src/SelbaWard/Spline.hpp b/src/SelbaWard/Spline.hpp index 97cfe13..add7fd3 100644 --- a/src/SelbaWard/Spline.hpp +++ b/src/SelbaWard/Spline.hpp @@ -38,7 +38,7 @@ namespace selbaward { -// SW Spline v1.7.0 +// SW Spline v1.7.1 class Spline : public sf::Drawable { public: From 27efc139c81ad9bb8a186c4a706742febd5578a2 Mon Sep 17 00:00:00 2001 From: Hapaxia Date: Thu, 15 Feb 2024 15:13:21 +0000 Subject: [PATCH 63/64] Polygon - update to v1.4 update Polygon to v1.4 adds: - vertex color, and tex-coords - bounds (local and global) - texture (used by tex-coords if set, ignored if not set; always ignored by wireframe) - ability to provide points in a reverses direction (i.e. clockwise for outer and anti-clockwise for holes - instead of anti-clockwise for outer and clockwise for holes) - ability to get perimeter of polygon (length of all edges; include hole edges) - ability to get area of polygon (after triangulation) - ability to get if point is inside polygon (after triangulation) - ability to get centroid (average of all outer's points; doesn't include hole vertices) - ability to get centre of mass (actual centre of mass; based on triangles' areas) - ability to get and set (existing) hole start indices/number of holes - export vertex positions (the actual vertices forming the polygon boundary, in order) - export vertex positions for only the outer boundary (does not include hole vertices) - export vertex positions for only the given hole (vertices for the hole) - export wireframe position (in pairs for each separate line) - constructors (from other Polygon or initializer list of positions) and operator= (from other Polygon) - operator[] to provide direct access to vertices (no validity checking). note that these are the vertices of the polygon "blueprint" - the thing you provide - not the actual vertices used to draw the shape. also fixed: - draw() signature: removed "virtual", added "override final" (just code-style update) - now tests exception flag before throwing error in trangulation; also moved exception flag into cpp. note that this flag is always set to true. --- src/SelbaWard/Polygon.cpp | 348 +++++++++++++++++++++++++++++++++++--- src/SelbaWard/Polygon.hpp | 52 +++++- 2 files changed, 378 insertions(+), 22 deletions(-) diff --git a/src/SelbaWard/Polygon.cpp b/src/SelbaWard/Polygon.cpp index e5ec6a4..3434eed 100644 --- a/src/SelbaWard/Polygon.cpp +++ b/src/SelbaWard/Polygon.cpp @@ -35,12 +35,30 @@ #include #include #include +#include namespace { +constexpr bool doThrowExceptions{ true }; + const std::string exceptionPrefix{ "Polygon: " }; +inline float crossProduct(const sf::Vector2f& a, const sf::Vector2f& b) +{ + return (a.x * b.y) - (a.y * b.x); +} + +inline float lengthSquared(const sf::Vector2f& v) +{ + return (v.x * v.x) + (v.y * v.y); +} + +inline float length(const sf::Vector2f& v) +{ + return std::sqrt(lengthSquared(v)); +} + inline bool isSecondVectorAntiClockwiseOfFirstVector(const sf::Vector2f& first, const sf::Vector2f& second) { return (first.x * second.y) < (first.y * second.x); @@ -64,14 +82,16 @@ inline bool pointIsInsideTriangle(const std::vector& points, const return a >= 0.l && a <= 1.l && b >= 0.l && b <= 1.l && c >= 0.l && c <= 1.l; } -inline float crossProduct(const sf::Vector2f& a, const sf::Vector2f& b) +inline float areaOfTriangle(const std::vector& points) { - return (a.x * b.y) - (a.y * b.x); -} - -inline float lengthSquared(const sf::Vector2f& a) -{ - return (a.x * a.x) + (a.y * a.y); + const sf::Vector2f a{ points[0u] }; + const sf::Vector2f b{ points[1u] }; + const sf::Vector2f c{ points[2u] }; + const float ab{ length(b - a) }; + const float bc{ length(c - b) }; + const float ca{ length(a - c) }; + const float halfPerimeter{ (ab + bc + ca) / 2.f }; + return std::sqrt(halfPerimeter * (halfPerimeter - ab) * (halfPerimeter - bc) * (halfPerimeter - ca)); } } // namespace @@ -80,9 +100,11 @@ namespace selbaward { Polygon::Polygon() - : m_outputVertices() - , m_vertices() - , m_holeStartIndices() + : m_texture{ nullptr } + , m_vertices{} + , m_triangles{} + , m_outputVertices{} + , m_holeStartIndices{} , m_color{ sf::Color::White } , m_showWireframe{ false } , m_wireframeVertices{} @@ -90,11 +112,56 @@ Polygon::Polygon() , m_triangulationMethod{ TriangulationMethod::BasicEarClip } , m_meshRefinementMethod{ MeshRefinementMethod::None } , m_triangleLimit{ 10000u } - , m_throwExceptions{ true } + , m_reverseDirection{ false } { } +Polygon::Polygon(std::initializer_list list) + : Polygon() +{ + m_vertices.resize(list.size()); + std::size_t index{ 0u }; + for (auto& position : list) + m_vertices[index++].position = position; +} + +Polygon::Polygon(const Polygon& other) + : m_texture{ other.m_texture } + , m_vertices{ other.m_vertices } + , m_triangles{ other.m_triangles } + , m_outputVertices{ other.m_outputVertices } + , m_holeStartIndices{ other.m_holeStartIndices } + , m_color{ other.m_color } + , m_showWireframe{ other.m_showWireframe } + , m_wireframeVertices{ other.m_wireframeVertices } + , m_wireframeColor{ other.m_wireframeColor } + , m_triangulationMethod{ other.m_triangulationMethod } + , m_meshRefinementMethod{ other.m_meshRefinementMethod } + , m_triangleLimit{ other.m_triangleLimit } + , m_reverseDirection{ other.m_reverseDirection } +{ +} + +Polygon& Polygon::operator=(const Polygon& other) +{ + m_texture = other.m_texture; + m_vertices = other.m_vertices; + m_triangles = other.m_triangles; + m_outputVertices = other.m_outputVertices; + m_holeStartIndices = other.m_holeStartIndices; + m_color = other.m_color; + m_showWireframe = other.m_showWireframe; + m_wireframeVertices = other.m_wireframeVertices; + m_wireframeColor = other.m_wireframeColor; + m_triangulationMethod = other.m_triangulationMethod; + m_meshRefinementMethod = other.m_meshRefinementMethod; + m_triangleLimit = other.m_triangleLimit; + m_reverseDirection = other.m_reverseDirection; + + return *this; +} + void Polygon::update() { priv_update(); @@ -130,6 +197,16 @@ Polygon::MeshRefinementMethod Polygon::getMeshRefinementMethod() const return m_meshRefinementMethod; } +void Polygon::setReverseDirection(const bool reverseDirection) +{ + m_reverseDirection = reverseDirection; +} + +bool Polygon::getReverseDirection() const +{ + return m_reverseDirection; +} + void Polygon::reserveVertices(const std::size_t numberOfVertices) { if (numberOfVertices == 0) @@ -165,6 +242,48 @@ sf::Vector2f Polygon::getVertexPosition(const std::size_t index) const return m_vertices[index].position; } +void Polygon::setVertexColor(const std::size_t index, const sf::Color color) +{ + if (!priv_testVertexIndex(index, "Cannot set vertex colour.")) + return; + + m_vertices[index].color = color; +} + +sf::Color Polygon::getVertexColor(const std::size_t index) const +{ + if (!priv_testVertexIndex(index, "Cannot get vertex colour.")) + return sf::Color{}; + + return m_vertices[index].color; +} + +void Polygon::setVertexTexCoords(std::size_t index, sf::Vector2f texCoords) +{ + if (!priv_testVertexIndex(index, "Cannot set vertex texcoords.")) + return; + + m_vertices[index].texCoords = texCoords; +} + +sf::Vector2f Polygon::getVertexTexCoords(std::size_t index) const +{ + if (!priv_testVertexIndex(index, "Cannot get vertex texcoords.")) + return{ 0.f, 0.f }; + + return m_vertices[index].texCoords; +} + +void Polygon::setTexture(const sf::Texture& texture) +{ + m_texture = &texture; +} + +void Polygon::setTexture() +{ + m_texture = nullptr; +} + void Polygon::setTriangleLimit(const std::size_t triangleLimit) { m_triangleLimit = triangleLimit; @@ -195,6 +314,109 @@ sf::Color Polygon::getWireframeColor() const return m_wireframeColor; } +float Polygon::getPerimeter() const +{ + const std::size_t numberOfVertices{ m_vertices.size() }; + float perimeter{ 0.f }; + const bool hasHoles{ !m_holeStartIndices.empty()}; + for (std::size_t i{ 0u }; i < numberOfVertices; ++i) + { + std::size_t nextI{ i + 1u }; + + const auto holeIt{ std::find(m_holeStartIndices.begin(), m_holeStartIndices.end(), nextI) }; + if (hasHoles && (holeIt != m_holeStartIndices.end())) + { + if (holeIt == m_holeStartIndices.begin()) + nextI = 0u; + else + nextI = *(holeIt - 1u); + } + + if ((nextI + 1u) > numberOfVertices) + nextI = 0u; + + perimeter += length(m_vertices[(nextI < numberOfVertices) ? nextI : 0u].position - m_vertices[i].position); + } + return perimeter; +} + +float Polygon::getArea() const +{ + float area{ 0.f }; + for (auto& triangle : m_triangles) + area += areaOfTriangle({ m_vertices[triangle[0u]].position, m_vertices[triangle[1u]].position, m_vertices[triangle[2u]].position }); + return area; +} + +bool Polygon::isPointInside(const sf::Vector2f point) const +{ + for (const auto& triangle : m_triangles) + { + if (pointIsInsideTriangle({ m_vertices[triangle[0u]].position, m_vertices[triangle[1u]].position, m_vertices[triangle[2u]].position }, point)) + return true; + } + return false; +} + +sf::FloatRect Polygon::getLocalBounds() const +{ + if (m_vertices.empty()) + return {}; + + const std::size_t numberOfVertices{ getHoleStartIndex(0u) }; + sf::Vector2f topLeft{ m_vertices[0u].position }; + sf::Vector2f bottomRight{ topLeft }; + for (std::size_t i{ 1u }; i < numberOfVertices; ++i) + { + const sf::Vector2f position{ m_vertices[i].position }; + topLeft.x = std::min(topLeft.x, position.x); + topLeft.y = std::min(topLeft.y, position.y); + bottomRight.x = std::max(bottomRight.x, position.x); + bottomRight.y = std::max(bottomRight.y, position.y); + } + return { topLeft, bottomRight - topLeft }; +} + +sf::FloatRect Polygon::getGlobalBounds() const +{ + return getTransform().transformRect(getLocalBounds()); +} + +sf::Vector2f Polygon::getCentroid() const +{ + const std::size_t numberOfVerticesToUse{ getHoleStartIndex(0u) }; + sf::Vector2f total{ 0.f, 0.f }; + for (std::size_t i{ 0u }; i < numberOfVerticesToUse; ++i) + total += m_vertices[i].position; + return total / static_cast(numberOfVerticesToUse); +} + +sf::Vector2f Polygon::getCenterOfMass() const +{ + float totalArea{ 0.f }; + sf::Vector2f total{ 0.f, 0.f }; + for (const auto& triangle : m_triangles) + { + const sf::Vector2f point1{ m_vertices[triangle[0u]].position }; + const sf::Vector2f point2{ m_vertices[triangle[1u]].position }; + const sf::Vector2f point3{ m_vertices[triangle[2u]].position }; + const sf::Vector2f current{ point1 + point2 + point3 }; + const float area{ areaOfTriangle({ point1, point2, point3 }) }; + total += (current * area); + totalArea += area; + } + //const float numberOfTriangles{ static_cast(m_triangles.size()) }; + //return (total / (numberOfTriangles * 3u)) / (totalArea / numberOfTriangles); + /* + c = (t / 3n) / (a / n) + = n(t / 3n) / a + = (nt / 3n) / a + = (t / 3) / a + = t / 3a + */ + return total / (totalArea * 3.f); +} + void Polygon::addHoleStartIndex(const std::size_t index) { m_holeStartIndices.push_back(index); @@ -210,6 +432,31 @@ void Polygon::setHoleStartIndices(const std::vector& indices) m_holeStartIndices = indices; } +void Polygon::setNumberOfHoles(std::size_t numberOfHoles) +{ + m_holeStartIndices.resize(numberOfHoles); +} + +void Polygon::setHoleStartIndex(const std::size_t holeIndex, const std::size_t holeStartIndex) +{ + if (!priv_testHoleIndex(holeIndex, "Cannot set hole start index.")) + return; + + m_holeStartIndices[holeIndex] = holeStartIndex; +} + +std::size_t Polygon::getNumberOfHoles() const +{ + return m_holeStartIndices.size(); +} + +std::size_t Polygon::getHoleStartIndex(const std::size_t holeIndex) const +{ + if (holeIndex >= m_holeStartIndices.size()) + return m_vertices.size(); + return m_holeStartIndices[holeIndex]; +} + void Polygon::reverseVertices() { std::reverse(m_vertices.begin(), m_vertices.end()); @@ -222,6 +469,35 @@ void Polygon::importVertexPositions(const std::vector& positions) m_vertices[i].position = positions[i]; } +std::vector Polygon::exportVertexPositions() const +{ + const std::size_t numberOfVertices{ m_vertices.size() }; + std::vector positions(numberOfVertices); + for (std::size_t i{ 0u }; i < numberOfVertices; ++i) + positions[i] = m_vertices[i].position; + return positions; +} + +std::vector Polygon::exportVertexPositionsOuterOnly() const +{ + const std::size_t numberOfVertices{ getHoleStartIndex(0u) }; + std::vector positions(numberOfVertices); + for (std::size_t i{ 0u }; i < numberOfVertices; ++i) + positions[i] = m_vertices[i].position; + return positions; +} + +std::vector Polygon::exportVertexPositionsHoleOnly(std::size_t holeIndex) const +{ + const std::size_t startIndex{ getHoleStartIndex(holeIndex) }; + const std::size_t endIndex{ getHoleStartIndex(holeIndex + 1u) }; + const std::size_t numberOfVertices{ endIndex - startIndex }; + std::vector positions(numberOfVertices); + for (std::size_t i{ 0u }; i < numberOfVertices; ++i) + positions[i] = m_vertices[startIndex + i].position; + return positions; +} + std::vector Polygon::exportTriangulatedPositions() const { std::vector positions(m_triangles.size() * 3u); @@ -234,6 +510,14 @@ std::vector Polygon::exportTriangulatedPositions() const return positions; } +std::vector Polygon::exportWireframePositions() const +{ + std::vector positions(m_wireframeVertices.size()); + for (std::size_t i{ 0u }; i < m_wireframeVertices.size(); ++i) + positions[i] = m_wireframeVertices[i].position; + return positions; +} + @@ -243,12 +527,15 @@ std::vector Polygon::exportTriangulatedPositions() const void Polygon::draw(sf::RenderTarget& target, sf::RenderStates states) const { - states.texture = nullptr; + states.texture = m_texture; states.transform *= getTransform(); if (!m_outputVertices.empty()) target.draw(m_outputVertices.data(), m_outputVertices.size(), sf::Triangles, states); if (m_showWireframe && !m_wireframeVertices.empty()) + { + states.texture = nullptr; target.draw(m_wireframeVertices.data(), m_wireframeVertices.size(), sf::Lines, states); + } } void Polygon::priv_update() @@ -266,7 +553,8 @@ void Polygon::priv_updateOutputVertices() for (std::size_t v{ 0u }; v < 3u; ++v) { m_outputVertices[baseIndex + v].position = m_vertices[m_triangles[t][v]].position; - m_outputVertices[baseIndex + v].color = m_color; + m_outputVertices[baseIndex + v].color = m_color * m_vertices[m_triangles[t][v]].color; + m_outputVertices[baseIndex + v].texCoords = m_vertices[m_triangles[t][v]].texCoords; } } @@ -359,7 +647,7 @@ void Polygon::priv_triangulateEarClip() const sf::Vector2f pLine{ m_vertices[vertexNumbers[indices[i]]].position - m_vertices[vertexNumbers[indices[p]]].position }; const sf::Vector2f nLine{ m_vertices[vertexNumbers[indices[n]]].position - m_vertices[vertexNumbers[indices[i]]].position }; - if (isSecondVectorAntiClockwiseOfFirstVector(pLine, nLine)) + if (m_reverseDirection != isSecondVectorAntiClockwiseOfFirstVector(pLine, nLine)) { reflex.erase(reflexIt); convex.push_back(indices[i]); @@ -390,7 +678,7 @@ void Polygon::priv_triangulateEarClip() const sf::Vector2f prevLine{ m_vertices[vertexNumbers[indices[i]]].position - m_vertices[vertexNumbers[indices[prev]]].position }; const sf::Vector2f nextLine{ m_vertices[vertexNumbers[indices[next]]].position - m_vertices[vertexNumbers[indices[i]]].position }; - if (!isSecondVectorAntiClockwiseOfFirstVector(prevLine, nextLine)) + if (m_reverseDirection != !isSecondVectorAntiClockwiseOfFirstVector(prevLine, nextLine)) reflex.push_back(indices[i]); else { @@ -589,7 +877,13 @@ void Polygon::priv_triangulateEarClip() while (indices.size() > 3u) { if (ear.empty()) - throw Exception("Polygon - ERROR: 0001"); + { + if (doThrowExceptions) + throw Exception("Polygon - ERROR: 0001"); + else + return; + } + std::size_t currentPoint{ ear.front() }; std::vector::iterator currentIt{ std::find(indices.begin(), indices.end(), currentPoint) }; @@ -678,7 +972,7 @@ void Polygon::priv_triangulateBasicEarClip() const sf::Vector2f pLine{ m_vertices[indices[i]].position - m_vertices[indices[p]].position }; const sf::Vector2f nLine{ m_vertices[indices[n]].position - m_vertices[indices[i]].position }; - if (isSecondVectorAntiClockwiseOfFirstVector(pLine, nLine)) + if (m_reverseDirection != isSecondVectorAntiClockwiseOfFirstVector(pLine, nLine)) { reflex.erase(reflexIt); convex.push_back(indices[i]); @@ -707,7 +1001,7 @@ void Polygon::priv_triangulateBasicEarClip() const sf::Vector2f prevLine{ m_vertices[indices[i]].position - m_vertices[indices[prev]].position }; const sf::Vector2f nextLine{ m_vertices[indices[next]].position - m_vertices[indices[i]].position }; - if (!isSecondVectorAntiClockwiseOfFirstVector(prevLine, nextLine)) + if (m_reverseDirection != !isSecondVectorAntiClockwiseOfFirstVector(prevLine, nextLine)) reflex.push_back(indices[i]); else { @@ -753,17 +1047,33 @@ bool Polygon::priv_isValidVertexIndex(const std::size_t vertexIndex) const return vertexIndex < m_vertices.size(); } +bool Polygon::priv_isValidHoleIndex(const std::size_t holeIndex) const +{ + return holeIndex < m_holeStartIndices.size(); +} + bool Polygon::priv_testVertexIndex(const std::size_t vertexIndex, const std::string& exceptionMessage) const { if (!priv_isValidVertexIndex(vertexIndex)) { - if (m_throwExceptions) + if (doThrowExceptions) throw Exception(exceptionPrefix + exceptionMessage + " Vertex index (" + std::to_string(vertexIndex) + ") out of range"); return false; } return true; } +bool Polygon::priv_testHoleIndex(std::size_t holeIndex, const std::string& exceptionMessage) const +{ + if (!priv_isValidHoleIndex(holeIndex)) + { + if (doThrowExceptions) + throw Exception(exceptionPrefix + exceptionMessage + " Hole index (" + std::to_string(holeIndex) + ") out of range"); + return false; + } + return true; +} + void Polygon::priv_buildWireframe() { if (!m_showWireframe) diff --git a/src/SelbaWard/Polygon.hpp b/src/SelbaWard/Polygon.hpp index ada554e..8d024f2 100644 --- a/src/SelbaWard/Polygon.hpp +++ b/src/SelbaWard/Polygon.hpp @@ -39,7 +39,7 @@ namespace selbaward { -// SW Polygon v1.3.0 +// SW Polygon v1.4.0 class Polygon : public sf::Drawable, public sf::Transformable { public: @@ -54,8 +54,14 @@ class Polygon : public sf::Drawable, public sf::Transformable }; Polygon(); + Polygon(std::initializer_list list); // pass vertices' positions (sf::Vector2f) to the constructor (sets size automatically) + Polygon(const Polygon& polygon); + Polygon& operator=(const Polygon& polygon); + void update(); + sf::Vertex& operator[] (std::size_t index); // direct access to the polygon's vertices (sf::Vertex) using the [] operator. no checks are performed. using with an invalid index results in undefined behaviour + void setColor(sf::Color color); sf::Color getColor(); @@ -64,6 +70,9 @@ class Polygon : public sf::Drawable, public sf::Transformable void setMeshRefinementMethod(MeshRefinementMethod meshRefinementMethod); MeshRefinementMethod getMeshRefinementMethod() const; + void setReverseDirection(bool reverseDirection); + bool getReverseDirection() const; + void reserveVertices(std::size_t numberOfVertices); void setNumberOfVertices(std::size_t numberOfVertices); @@ -72,6 +81,15 @@ class Polygon : public sf::Drawable, public sf::Transformable void setVertexPosition(std::size_t index, sf::Vector2f position); sf::Vector2f getVertexPosition(std::size_t index) const; + void setVertexColor(std::size_t index, sf::Color color); + sf::Color getVertexColor(std::size_t index) const; + + void setVertexTexCoords(std::size_t index, sf::Vector2f texCoords); + sf::Vector2f getVertexTexCoords(std::size_t index) const; + + void setTexture(const sf::Texture& texture); // activate texture (ignored for wireframe) + void setTexture(); // de-activate/reset ("un-set") texture + void setTriangleLimit(std::size_t triangleLimit); std::size_t getTriangleLimit() const; @@ -81,15 +99,34 @@ class Polygon : public sf::Drawable, public sf::Transformable void setWireframeColor(sf::Color wireframeColor); sf::Color getWireframeColor() const; + float getPerimeter() const; + float getArea() const; + + bool isPointInside(sf::Vector2f point) const; + + sf::FloatRect getLocalBounds() const; + sf::FloatRect getGlobalBounds() const; + + sf::Vector2f getCentroid() const; // ignores holes - gives decent representation (averaged points of outer) + sf::Vector2f getCenterOfMass() const; // uses each point of each triangle, weighted by triangle area - represents actual "centre of mass" + void reverseVertices(); void importVertexPositions(const std::vector& position); + std::vector exportVertexPositions() const; + std::vector exportVertexPositionsOuterOnly() const; + std::vector exportVertexPositionsHoleOnly(std::size_t holeIndex) const; std::vector exportTriangulatedPositions() const; + std::vector exportWireframePositions() const; // holes must not overlap and must be specified in opposite direction to outer polygon void addHoleStartIndex(std::size_t index); void clearHoleStartIndices(); void setHoleStartIndices(const std::vector& indices); + void setNumberOfHoles(std::size_t numberOfHoles); + void setHoleStartIndex(std::size_t holeIndex, std::size_t holeStartIndex); + std::size_t getNumberOfHoles() const; + std::size_t getHoleStartIndex(std::size_t holeIndex) const; // hole index indentifies the hole. returned value is the vertex index of the start of that hole. "number of vertices" is returned if there are no holes or hole does not exist. @@ -100,6 +137,8 @@ class Polygon : public sf::Drawable, public sf::Transformable private: using TriangleIndices = std::array; + const sf::Texture* m_texture; + std::vector m_vertices; std::vector m_triangles; std::vector m_outputVertices; @@ -115,18 +154,25 @@ class Polygon : public sf::Drawable, public sf::Transformable std::size_t m_triangleLimit; - const bool m_throwExceptions; + bool m_reverseDirection; - virtual void draw(sf::RenderTarget&, sf::RenderStates) const; + void draw(sf::RenderTarget&, sf::RenderStates) const override final; void priv_update(); void priv_updateOutputVertices(); void priv_triangulate(); void priv_triangulateEarClip(); void priv_triangulateBasicEarClip(); bool priv_isValidVertexIndex(std::size_t vertexIndex) const; + bool priv_isValidHoleIndex(std::size_t holeIndex) const; bool priv_testVertexIndex(std::size_t vertexIndex, const std::string& exceptionMessage) const; + bool priv_testHoleIndex(std::size_t holeIndex, const std::string& exceptionMessage) const; void priv_buildWireframe(); }; +inline sf::Vertex& Polygon::operator[] (const std::size_t index) +{ + return m_vertices[index]; +} + } // namespace selbaward #endif // SELBAWARD_POLYGON_HPP From c539a5fdb6d430d244d9909585fc7c46cc7ebe25 Mon Sep 17 00:00:00 2001 From: Hapaxia Date: Thu, 23 Jan 2025 22:08:56 +0000 Subject: [PATCH 64/64] Update TileMap.inl --- src/SelbaWard/TileMap.inl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/SelbaWard/TileMap.inl b/src/SelbaWard/TileMap.inl index 4aa7b44..38fdcd1 100644 --- a/src/SelbaWard/TileMap.inl +++ b/src/SelbaWard/TileMap.inl @@ -189,7 +189,7 @@ template void TileMap::setGridSize(const sf::Vector2u gridSize) { m_gridSize = { gridSize.x + 1, gridSize.y + 1 }; - m_grid.resize(m_gridSize.x * m_gridSize.y); + m_grid.resize(static_cast(m_gridSize.x) * m_gridSize.y); priv_recreateRenderTexture(); } @@ -390,7 +390,7 @@ void TileMap::draw(sf::RenderTarget& target, sf::RenderStates states) const template void TileMap::priv_updateVertices() const { - m_vertices.resize(m_gridSize.x * m_gridSize.y * 6u); + m_vertices.resize(static_cast(m_gridSize.x) * m_gridSize.y * 6u); if (m_gridSize.x == 0 || m_gridSize.y == 0) return; @@ -499,7 +499,7 @@ unsigned int TileMap::priv_getTileAtGridPosition(const sf::Vector2i gridPosit static_cast(gridPosition.y) >= m_gridSize.y) return 0u; - return m_grid[gridPosition.y * m_gridSize.x + gridPosition.x]; + return m_grid[static_cast(gridPosition.y) * m_gridSize.x + gridPosition.x]; } template