Skip to content

Commit

Permalink
Concave polygon (#18)
Browse files Browse the repository at this point in the history
* extra_function: Line: add getDirection and getLength methods

* Add first iteration of the ConcavePolygon class

* extra_function: add missing "nodiscard" attribute
- add IsVertexInCone
- add DotSquare
- add GetHandedness

* CheckIntersection: fix norm and length compare

* fix missing Line constructors

* CheckIntersection: add IntersectionOptions argument in order to control the outcome of the function

* Tunnel: fixing the move operator

* Fix PhysicalDevice::findQueueFamilies logic and avoid using a present queue with VK_QUEUE_VIDEO_DECODE_BIT_KHR

* remove ObstacleComponent and LightObstacle now inherit from LightComponent, cleaning

* RenderResourceInstances: add a vertexOffset property

* FGE_MAX_FRAMES_IN_FLIGHT: set to 1 as visual glitch can appear

* ObjLight: apply new ConcavePolygon shapes

* update lightAndObstacle_002 example

* apply a fix for possible missing VK_QUEUE_VIDEO_DECODE_BIT_KHR

* ObjLight: draw: do some cleaning/refactoring

* lightAndObstacle_002: add controls to rotate the obstacle

* add FGE_MULTIUSE_POOL_MAX_COMBINED_IMAGE_SAMPLER
- this fix a problem in createMultiUseDescriptorPool()

* replace add_custom_command with add_custom_target, that fix some weird symlink creation issue (on windows)

* DescriptorPool: fix the pool._count wasn't incrementing while creating a new pool
- fix pool throwing "out of pool memory" with only 1 element

* RenderTarget: remove the gLastTexture cache as (at current stat) is not relevant, not safe and can provide graphical glitch
  • Loading branch information
JonathSpirit authored Dec 16, 2023
1 parent dbc556a commit bb65160
Show file tree
Hide file tree
Showing 23 changed files with 923 additions and 293 deletions.
14 changes: 8 additions & 6 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -371,6 +371,7 @@ target_sources(${FGE_SERVER_LIB_NAME} PRIVATE "sources/C_event.cpp")
target_sources(${FGE_SERVER_LIB_NAME} PRIVATE "sources/C_eventList.cpp")
target_sources(${FGE_SERVER_LIB_NAME} PRIVATE "sources/C_font.cpp")
target_sources(${FGE_SERVER_LIB_NAME} PRIVATE "sources/C_property.cpp")
target_sources(${FGE_SERVER_LIB_NAME} PRIVATE "sources/C_concavePolygon.cpp")

target_sources(${FGE_SERVER_LIB_NAME} PRIVATE "sources/object/C_objAnim.cpp")
target_sources(${FGE_SERVER_LIB_NAME} PRIVATE "sources/object/C_objButton.cpp")
Expand Down Expand Up @@ -482,6 +483,7 @@ target_sources(${FGE_LIB_NAME} PRIVATE "sources/C_event.cpp")
target_sources(${FGE_LIB_NAME} PRIVATE "sources/C_eventList.cpp")
target_sources(${FGE_LIB_NAME} PRIVATE "sources/C_font.cpp")
target_sources(${FGE_LIB_NAME} PRIVATE "sources/C_property.cpp")
target_sources(${FGE_LIB_NAME} PRIVATE "sources/C_concavePolygon.cpp")

target_sources(${FGE_LIB_NAME} PRIVATE "sources/object/C_objAnim.cpp")
target_sources(${FGE_LIB_NAME} PRIVATE "sources/object/C_objButton.cpp")
Expand Down Expand Up @@ -622,15 +624,15 @@ elseif(APPLE)
CopyFilesToRuntimeDirectory("${GLSLANG_LIB_APPLE_HELL};${GLSLANG_RES_LIB_APPLE_HELL};${GLSLANG_SPIRV_LIB_APPLE_HELL}" FgeServerExeDeps)
endif()

add_custom_command(TARGET FgeClientExeDeps PRE_BUILD
add_custom_target(ResourcesSymlink
COMMAND ${CMAKE_COMMAND} -E create_symlink
${CMAKE_CURRENT_SOURCE_DIR}/resources
${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/resources)
${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/resources
BYPRODUCTS resources/
VERBATIM)

add_custom_command(TARGET FgeServerExeDeps PRE_BUILD
COMMAND ${CMAKE_COMMAND} -E create_symlink
${CMAKE_CURRENT_SOURCE_DIR}/resources
${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/resources)
add_dependencies(FgeClientExeDeps ResourcesSymlink)
add_dependencies(FgeServerExeDeps ResourcesSymlink)

#Set some variables that help exe linking
if(WIN32)
Expand Down
69 changes: 55 additions & 14 deletions examples/lightAndObstacle_002/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,29 @@
#include <FastEngine/C_scene.hpp>
#include <iostream>

//Create a obstacle class object
std::vector<fge::Vector2f> ConvertTriangleStripTopologyToPolygon(fge::vulkan::Vertex const* vertices, std::size_t count)
{
std::vector<fge::Vector2f> polygon;

for (size_t i = 1; i < count; ++i)
{
if (i % 2 != 0)
{
polygon.push_back(vertices[i]._position);
}
}
for (size_t i = count; i > 0; --i)
{
if ((i - 1) % 2 == 0)
{
polygon.push_back(vertices[i - 1]._position);
}
}

return polygon;
}

//Create an obstacle class object
class Obstacle : public fge::Object, public fge::LightObstacle
{
public:
Expand All @@ -39,10 +61,17 @@ class Obstacle : public fge::Object, public fge::LightObstacle
};

Obstacle() :
fge::LightObstacle(this),
g_vertices(fge::vulkan::GetActiveContext())
{
this->g_vertices.create(0, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP);
}
Obstacle(Obstacle const& r) :
fge::Object(r),
fge::LightObstacle(*this, this),
g_type(r.g_type),
g_vertices(r.g_vertices)
{}

FGE_OBJ_DEFAULT_COPYMETHOD(Obstacle)

Expand All @@ -66,12 +95,6 @@ class Obstacle : public fge::Object, public fge::LightObstacle
{
this->setPosition(screen.mapPixelToCoords(event.getMousePixelPos()));
}

this->_g_myPoints.resize(this->g_vertices.getCount());
for (std::size_t i = 0; i < this->g_vertices.getCount(); ++i)
{
this->_g_myPoints[i] = this->getTransform() * this->g_vertices[i]._position;
}
}

void draw(fge::RenderTarget& target, fge::RenderStates const& states) const override
Expand All @@ -87,6 +110,7 @@ class Obstacle : public fge::Object, public fge::LightObstacle
{
this->g_type = type;
this->g_vertices.clear();
this->_g_shape.clear();

switch (type)
{
Expand All @@ -111,18 +135,22 @@ class Obstacle : public fge::Object, public fge::LightObstacle
break;
case ObstacleTypes::OBSTACLE_CONCAVE:
this->g_vertices.append(fge::vulkan::Vertex{{0.0f, 0.0f}, fge::Color::Green});
this->g_vertices.append(fge::vulkan::Vertex{{10.0f, -20.0f}, fge::Color::Green});
this->g_vertices.append(fge::vulkan::Vertex{{0.0f, 20.0f}, fge::Color::Green});
this->g_vertices.append(fge::vulkan::Vertex{{10.0f, 10.0f}, fge::Color::Green});
this->g_vertices.append(fge::vulkan::Vertex{{20.0f, 20.0f}, fge::Color::Green});
this->g_vertices.append(fge::vulkan::Vertex{{20.0f, 0.0f}, fge::Color::Green});

this->g_vertices.append(fge::vulkan::Vertex{{20.0f, 10.0f}, fge::Color::Green});
this->g_vertices.append(fge::vulkan::Vertex{{30.0f, 10.0f}, fge::Color::Green});

this->g_vertices.append(fge::vulkan::Vertex{{30.0f, -20.0f}, fge::Color::Green});
this->g_vertices.append(fge::vulkan::Vertex{{40.0f, 0.0f}, fge::Color::Green});
break;
}
}

void updateObstacleShape() override
{
auto vertices =
ConvertTriangleStripTopologyToPolygon(this->g_vertices.getVertices(), this->g_vertices.getCount());
this->_g_shape = fge::ConcavePolygon(std::move(vertices));
this->_g_shape.convexDecomposition();
}

char const* getClassName() const override { return "OBSTACLE"; }
char const* getReadableClassName() const override { return "obstacle"; }

Expand Down Expand Up @@ -155,6 +183,7 @@ class MainScene : public fge::Scene
//Create a text object with explanation
auto explainText = this->newObject(FGE_NEWOBJECT(fge::ObjText,
"Use Q/E to switch between light and obstacle follow up\n"
"Use A/D to rotate the obstacle\n"
"Use 1/2/3/4 to change the obstacle form\n"
"Use left mouse click to duplicate the obstacle/light\n"
"Use space to delete all duplicated objects\n"
Expand Down Expand Up @@ -243,6 +272,16 @@ class MainScene : public fge::Scene
this->_properties["follow"] = "light";
}

//Rotate the obstacle
if (keyEvent.keysym.sym == SDLK_a)
{
obstacle->getObject()->rotate(-10.0f);
}
else if (keyEvent.keysym.sym == SDLK_d)
{
obstacle->getObject()->rotate(10.0f);
}

//Remove all duplicates
if (keyEvent.keysym.sym == SDLK_SPACE)
{
Expand All @@ -252,6 +291,8 @@ class MainScene : public fge::Scene
{
this->delObject(duplicate->getSid());
}

obstacle->getObject()->setRotation(0.0f);
}
}));

Expand Down
112 changes: 112 additions & 0 deletions includes/FastEngine/C_concavePolygon.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
/*
* Copyright 2023 Guillaume Guillet
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#ifndef _FGE_C_CONCAVEPOLYGON_HPP_INCLUDED
#define _FGE_C_CONCAVEPOLYGON_HPP_INCLUDED

#include "FastEngine/fge_extern.hpp"
#include "FastEngine/C_vector.hpp"
#include "FastEngine/extra/extra_function.hpp"
#include <map>
#include <vector>

/*
* Original from : https://github.com/mjjq/ConvexDecomposition
* Copyright (C) mjjq
* License MIT
* The algorithm for decomposing concave polygons to convex can be found here:
* https://mpen.ca/406/bayazit (Mark Bayazit).
*
* Altered/Modified by Guillaume Guillet
*/

namespace fge
{

class FGE_API ConcavePolygon
{
public:
using VertexArray = std::vector<fge::Vector2f>;

ConcavePolygon() = default;
explicit ConcavePolygon(VertexArray const& vertices);
explicit ConcavePolygon(VertexArray&& vertices);
ConcavePolygon(ConcavePolygon const& r) = default;
ConcavePolygon(ConcavePolygon&& r) noexcept = default;

ConcavePolygon& operator=(ConcavePolygon const& r) = default;
ConcavePolygon& operator=(ConcavePolygon&& r) noexcept = default;

[[nodiscard]] bool checkIfRightHanded();

void convexDecomposition();

void setVertices(VertexArray const& vertices);
void setVertices(VertexArray&& vertices);
[[nodiscard]] inline fge::Vector2f& vertex(std::size_t index) { return this->g_vertices[index]; }
[[nodiscard]] inline fge::Vector2f const& vertex(std::size_t index) const { return this->g_vertices[index]; }
[[nodiscard]] inline VertexArray const& vertices() const { return this->g_vertices; }

[[nodiscard]] inline VertexArray const& subPolygon(std::size_t subPolyIndex) const
{
return this->g_subPolygons[subPolyIndex];
}
[[nodiscard]] inline std::size_t subPolygonCount() const { return this->g_subPolygons.size(); }

[[nodiscard]] inline std::size_t totalVertexCount() const { return this->g_totalVertexCount; }

void clear();

private:
VertexArray g_vertices;
std::vector<VertexArray> g_subPolygons;
std::size_t g_totalVertexCount = 0;

using VertexIndexMap = std::map<std::size_t, fge::Vector2f>;
using Indices = std::vector<std::size_t>;

[[nodiscard]] static bool checkIfRightHanded(VertexArray const& vertices);

[[nodiscard]] static std::pair<ConcavePolygon::VertexArray, ConcavePolygon::VertexArray>
slicePolygon(std::size_t const& startVertexIndex,
std::size_t const& stopVertexIndex,
VertexArray const& inputVertices);

[[nodiscard]] static Indices findVerticesInCone(fge::Line const& line1,
fge::Line const& line2,
fge::Vector2f const& origin,
VertexArray const& inputVertices);

[[nodiscard]] static bool checkVisibility(fge::Vector2f const& originalPosition,
fge::Vector2f const& vert,
VertexArray const& polygonVertices);

[[nodiscard]] static std::optional<std::size_t>
getBestVertexToConnect(Indices const& indices, VertexArray const& polygonVertices, fge::Vector2f const& origin);

[[nodiscard]] static std::optional<std::size_t> findFirstReflexVertex(VertexArray const& polygon);

static void flipPolygon(VertexArray& vertices);

[[nodiscard]] static VertexIndexMap verticesAlongLineSegment(fge::Line const& segment, VertexArray const& vertices);

[[nodiscard]] static std::optional<std::size_t>
addNewVertex(std::size_t& positionIndex, fge::Vector2f const& direction, VertexArray& vertices);
};

} // namespace fge

#endif //_FGE_C_CONCAVEPOLYGON_HPP_INCLUDED
4 changes: 2 additions & 2 deletions includes/FastEngine/C_tunnel.inl
Original file line number Diff line number Diff line change
Expand Up @@ -263,8 +263,8 @@ fge::TunnelGate<T>& TunnelGate<T>::operator=(fge::TunnelGate<T>&& gate) noexcept

if (gate.g_tunnel)
{
gate.g_tunnel->addGate(this, gate.g_tunnel->isAnonymous(&gate));
gate.g_tunnel->closeGate(&gate);
gate.g_tunnel->addGate(*this, gate.g_tunnel->isAnonymous(gate));
gate.g_tunnel->closeGate(gate);
}
return *this;
}
Expand Down
Loading

0 comments on commit bb65160

Please sign in to comment.