Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/cmake_linux_gcc_64bit.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ jobs:
shell: bash
working-directory: ${{github.workspace}}/deps
run: |
cmake . -D CMAKE_BUILD_TYPE=$BUILD_TYPE
cmake . -D CMAKE_C_COMPILER=gcc-11 -D CMAKE_CXX_COMPILER=g++-11 -D CMAKE_BUILD_TYPE=$BUILD_TYPE
cmake --build . -j ${{steps.cpu-cores.outputs.count}} --config $BUILD_TYPE

- name: Configure CMake
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/codeql.yml
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ jobs:
shell: bash
working-directory: ${{github.workspace}}/deps
run: |
cmake . -D CMAKE_BUILD_TYPE=$BUILD_TYPE
cmake . -D CMAKE_C_COMPILER=gcc-11 -D CMAKE_CXX_COMPILER=g++-11 -D CMAKE_BUILD_TYPE=$BUILD_TYPE
cmake --build . -j ${{steps.cpu-cores.outputs.count}} --config $BUILD_TYPE

# Initializes the CodeQL tools for scanning.
Expand Down
9 changes: 9 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ else()
endif()

option(FGE_BUILD_EXAMPLES "Build examples" ON)
option(FGE_BUILD_EXTENSIONS "Build extensions (see extensions/ directory)" ON)
option(FGE_BUILD_TESTS "Build tests" ON)

option(FGE_ENABLE_SERVER_NETWORK_RANDOM_LOST "enable/disable random packet lost for server" OFF)
Expand Down Expand Up @@ -476,6 +477,11 @@ install(TARGETS ${FGE_SERVER_LIB_NAME} EXPORT ${PROJECT_NAME}Targets
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
FILE_SET publicHeaders DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME})

#Extensions
if (FGE_BUILD_EXTENSIONS)
add_subdirectory(extensions)
endif()

install(FILES fge_changelog.txt DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/${PROJECT_NAME})
install(FILES IMAGE_AUDIO_LOGO_LICENSE DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/${PROJECT_NAME})
install(FILES LICENSE DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/${PROJECT_NAME})
Expand Down Expand Up @@ -585,4 +591,7 @@ if (FGE_BUILD_EXAMPLES)
add_subdirectory(examples/mipmaps_007)
add_subdirectory(examples/noWindowOnlyRenderTexture_008)
add_subdirectory(examples/shaderChain_009)
if (FGE_BUILD_EXTENSIONS)
add_subdirectory(examples/objChart_010)
endif()
endif()
9 changes: 6 additions & 3 deletions deps/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,16 @@ set(CMAKE_INSTALL_PREFIX "${CMAKE_CURRENT_BINARY_DIR}/install/" CACHE PATH "" FO

file(WRITE ${DEPS_GLOBAL_CMAKE_FILE} "")

#Forward the compilers to every dependency, mixing compiler versions breaks the final link (libstdc++ ABI)
set(DEPS_COMPILER_ARGS -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER} -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER})

function(AddCmakeDependency NAME URL TAG SHARED ARGS SOURCE_SUBDIR)
separate_arguments(ARGS UNIX_COMMAND "${ARGS}")

ExternalProject_Add(${NAME}
GIT_REPOSITORY ${URL}
GIT_TAG ${TAG}
CMAKE_ARGS -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=${SHARED} ${ARGS}
CMAKE_ARGS -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=${SHARED} ${ARGS} ${DEPS_COMPILER_ARGS}
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=${CMAKE_CURRENT_BINARY_DIR}/libs/${NAME}
PREFIX project/${NAME}
TEST_COMMAND ""
Expand All @@ -37,7 +40,7 @@ function(AddPatchedDependency NAME URL TAG SHARED ARGS SOURCE_SUBDIR PATCH APPEN
ExternalProject_Add(${NAME}
GIT_REPOSITORY ${URL}
GIT_TAG ${TAG}
CMAKE_ARGS -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=${SHARED} ${ARGS}
CMAKE_ARGS -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=${SHARED} ${ARGS} ${DEPS_COMPILER_ARGS}
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=${CMAKE_CURRENT_BINARY_DIR}/libs/${NAME}
PREFIX project/${NAME}
PATCH_COMMAND ${GIT_EXECUTABLE} clean --force -d -x &&
Expand Down Expand Up @@ -133,7 +136,7 @@ AddCmakeDependency(SDL3_mixer
https://github.com/libsdl-org/SDL_mixer.git
release-3.2.4
ON
"-DSDL3MIXER_VENDORED=ON -DCMAKE_PREFIX_PATH=${CMAKE_CURRENT_BINARY_DIR}/libs/SDL3"
"-DSDL3MIXER_VENDORED=ON -DCMAKE_PREFIX_PATH=${CMAKE_CURRENT_BINARY_DIR}/libs/SDL3 -DSDLMIXER_TESTS_INSTALL=OFF -DSDLMIXER_EXAMPLES_INSTALL=OFF"
"")
add_dependencies(SDL3_mixer SDL3)

Expand Down
1 change: 1 addition & 0 deletions docs/Doxyfile.in
Original file line number Diff line number Diff line change
Expand Up @@ -1027,6 +1027,7 @@ WARN_LOGFILE =
# Note: If this tag is empty the current directory is searched.

INPUT = "../includes" \
"../extensions" \
"../README.md"

# This tag can be used to specify the character encoding of the source files
Expand Down
9 changes: 9 additions & 0 deletions examples/objChart_010/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
cmake_minimum_required(VERSION 3.10)
project(example_objChart_010)

add_executable(${PROJECT_NAME} main.cpp)
add_dependencies(${PROJECT_NAME} FgeClientExeDeps)

target_link_libraries(${PROJECT_NAME} ${FGE_CLIENT_LIBS} FastEngine::ObjChart)

setMSVCDefaultWorkingDir(${PROJECT_NAME})
296 changes: 296 additions & 0 deletions examples/objChart_010/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,296 @@
/*
* Copyright 2026 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.
*/

#include "FastEngine/C_clock.hpp"
#include "FastEngine/C_random.hpp"
#include "FastEngine/C_scene.hpp"
#include "FastEngine/extensions/C_objChart.hpp"
#include "FastEngine/graphic/C_renderWindow.hpp"
#include "FastEngine/manager/shader_manager.hpp"
#include "FastEngine/manager/texture_manager.hpp"
#include "FastEngine/object/C_objShape.hpp"
#include "FastEngine/object/C_objText.hpp"
#include "FastEngine/object/C_objWindow.hpp"
#include "SDL3/SDL.h"
#include "SDL3/SDL_main.h"
#include <cmath>
#include <iostream>

#define CHART_POINT_COUNT 25
#define CHART_MOVE_INTERVAL std::chrono::milliseconds(2000)

//Create the MainScene class
class MainScene : public fge::Scene
{
public:
void start(fge::RenderWindow& renderWindow)
{
fge::Event event(renderWindow);
fge::GuiElementHandler guiElementHandler(event, renderWindow);
guiElementHandler.setEventCallback();

this->setLinkedRenderTarget(&renderWindow);

//Set default callback context
this->setCallbackContext({&event, &guiElementHandler});

//Init texture manager
if (!fge::texture::gManager.initialize())
{
std::cout << "Failed to initialize texture manager" << std::endl;
return;
}
//Init font manager
if (!fge::font::gManager.initialize())
{
std::cout << "Failed to initialize font manager" << std::endl;
return;
}

//Load texture
fge::texture::gManager.loadFromFile("close", "resources/images/window/close.png");
fge::texture::gManager.loadFromFile("minimize", "resources/images/window/minimize.png");
fge::texture::gManager.loadFromFile("resize", "resources/images/window/resize.png");
fge::texture::gManager.loadFromFile("window", "resources/images/window/window.png");

//Load font
fge::font::gManager.loadFromFile("base", "resources/fonts/SourceSansPro-Regular.ttf");

fge::Clock tick;

//Create a text object with explanation
auto* explainText =
this->newObject<fge::ObjText>({FGE_SCENE_PLAN_HIGH_TOP + 1}, "", "base", fge::Vector2f{}, 18);
explainText->setFillColor(fge::Color::Black);

//Create the window
auto* objWindow = this->newObject<fge::ObjWindow>({FGE_SCENE_PLAN_HIGH_TOP});
objWindow->setTextureClose("close");
objWindow->setTextureMinimize("minimize");
objWindow->setTextureResize("resize");
objWindow->setTexture("window");
objWindow->setSize({500.0f, 360.0f});
objWindow->setPosition({150.0f, 130.0f});
objWindow->showExitButton(false);

//Create the chart (using double for the data) that fill the window
auto* objChart = objWindow->_windowScene.newObject<fge::ObjChartD>();
objChart->setFont("base");
objChart->setDynamicSize(
{{0.0f, 0.0f}, {fge::DynamicSize::SizeModes::SIZE_AUTO, fge::DynamicSize::SizeModes::SIZE_AUTO}});

//Add some points, a noisy sine wave
for (std::size_t i = 0; i < CHART_POINT_COUNT; ++i)
{
double const x = static_cast<double>(i) * 0.5;
objChart->addPoint({x, std::sin(x) * 10.0 + fge::_random.range(-2.0, 2.0)});
}

//Move every point randomly, the chart will animate the change
auto const movePoints = [objChart]() {
for (std::size_t i = 0; i < objChart->getPointCount(); ++i)
{
auto point = objChart->getPoint(i);
point.y += fge::_random.range(-4.0, 4.0);
objChart->setPoint(i, point);
}
};

auto const updateExplainText = [explainText, objChart]() {
char const* shapeName = "circle";
switch (objChart->getPointShape())
{
case fge::ObjChartD::PointShapes::SHAPE_SQUARE:
shapeName = "square";
break;
case fge::ObjChartD::PointShapes::SHAPE_DIAMOND:
shapeName = "diamond";
break;
default:
break;
}

explainText->setString(std::string{"Points are moving every 2 seconds, use your mouse to play with the "
"window\n"
"SPACE: move the points now\n"
"A: toggle animation ("} +
(objChart->isAnimationEnabled() ? "on" : "off") +
")\n"
"L: toggle lines (" +
(objChart->isLinesShown() ? "on" : "off") +
")\n"
"R: add a point, D: remove the last point\n"
"S: change point shape (" +
shapeName + ")");
};
updateExplainText();

event._onKeyDown.addLambda([&]([[maybe_unused]] fge::Event const& evt, SDL_KeyboardEvent const& keyEvent) {
switch (keyEvent.key)
{
case SDLK_SPACE:
movePoints();
break;
case SDLK_A:
objChart->enableAnimation(!objChart->isAnimationEnabled());
break;
case SDLK_L:
objChart->showLines(!objChart->isLinesShown());
break;
case SDLK_R:
{
double x = 0.0;
if (objChart->getPointCount() > 0)
{
x = objChart->getPoint(objChart->getPointCount() - 1).x + 0.5;
}
objChart->addPoint({x, std::sin(x) * 10.0 + fge::_random.range(-2.0, 2.0)}, fge::Color{220, 70, 50});
break;
}
case SDLK_D:
if (objChart->getPointCount() > 0)
{
objChart->removePoint(objChart->getPointCount() - 1);
}
break;
case SDLK_S:
switch (objChart->getPointShape())
{
case fge::ObjChartD::PointShapes::SHAPE_CIRCLE:
objChart->setPointShape(fge::ObjChartD::PointShapes::SHAPE_SQUARE);
break;
case fge::ObjChartD::PointShapes::SHAPE_SQUARE:
objChart->setPointShape(fge::ObjChartD::PointShapes::SHAPE_DIAMOND);
break;
case fge::ObjChartD::PointShapes::SHAPE_DIAMOND:
objChart->setPointShape(fge::ObjChartD::PointShapes::SHAPE_CIRCLE);
break;
}
break;
default:
return;
}
updateExplainText();
});

fge::Clock moveClock;

//Begin loop
bool running = true;
while (running)
{
//Update event
event.process();
if (event.isEventType(SDL_EVENT_QUIT))
{
running = false;
}
if (event.isEventType(SDL_EVENT_WINDOW_RESIZED))
{
auto view = renderWindow.getView();
view.resizeFixCenter({event.getWindowSize().x, event.getWindowSize().y});
renderWindow.setView(view);
guiElementHandler.checkViewSize();
}

if (moveClock.reached(CHART_MOVE_INTERVAL))
{
moveClock.restart();
movePoints();
}

//Update scene
auto deltaTick = tick.restart();
this->update(renderWindow, event, std::chrono::duration_cast<std::chrono::milliseconds>(deltaTick));

//Drawing
auto imageIndex = renderWindow.prepareNextFrame(nullptr, FGE_RENDER_TIMEOUT_BLOCKING);
if (imageIndex != FGE_RENDER_BAD_IMAGE_INDEX)
{
fge::vulkan::GetActiveContext()._garbageCollector.setCurrentFrame(renderWindow.getCurrentFrame());

renderWindow.beginRenderPass(imageIndex);

this->draw(renderWindow);

renderWindow.endRenderPass();

renderWindow.display(imageIndex);
}
}

fge::vulkan::GetActiveContext().waitIdle();

fge::vulkan::GetActiveContext()._garbageCollector.enable(false);
}
};

int main([[maybe_unused]] int argc, [[maybe_unused]] char* argv[])
{
using namespace fge::vulkan;

auto instance = Context::init(SDL_INIT_VIDEO | SDL_INIT_EVENTS, "example 010: objChart");
Context::enumerateExtensions();

SurfaceSDLWindow window(instance, FGE_WINDOWPOS_CENTERED, {800, 600}, SDL_WINDOW_RESIZABLE);

// Check that the window was successfully created
if (!window.isCreated())
{
// In the case that the window could not be made...
std::cout << "Could not create window: " << SDL_GetError() << std::endl;
return 1;
}

Context vulkanContext(window);
vulkanContext._garbageCollector.enable(true);

if (!fge::shader::gManager.initialize())
{
std::cout << "Could not initialize shader manager" << std::endl;
return 1;
}
fge::shader::gManager.loadFromFile(FGE_OBJSHAPE_INSTANCES_SHADER_VERTEX,
"resources/shaders/objShapeInstances_vertex.vert", Shader::Type::SHADER_VERTEX,
fge::shader::ShaderInputTypes::SHADER_GLSL);
fge::shader::gManager.loadFromFile(FGE_OBJSPRITEBATCHES_SHADER_FRAGMENT,
"resources/shaders/objSpriteBatches_fragment.frag",
Shader::Type::SHADER_FRAGMENT, fge::shader::ShaderInputTypes::SHADER_GLSL);
fge::shader::gManager.loadFromFile(FGE_OBJSPRITEBATCHES_SHADER_VERTEX,
"resources/shaders/objSpriteBatches_vertex.vert", Shader::Type::SHADER_VERTEX,
fge::shader::ShaderInputTypes::SHADER_GLSL);

fge::RenderWindow renderWindow(vulkanContext, window);
renderWindow.setClearColor(fge::Color::White);

std::unique_ptr<MainScene> scene = std::make_unique<MainScene>();
scene->start(renderWindow);
scene.reset();

fge::texture::gManager.uninitialize();
fge::font::gManager.uninitialize();
fge::shader::gManager.uninitialize();

renderWindow.destroy();

vulkanContext.destroy();

window.destroy();
instance.destroy();
SDL_Quit();

return 0;
}
Loading
Loading