Last active
August 3, 2025 00:32
-
-
Save Kinane-dev/79be40843a2f60bf74b10aa4ed1f395a to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
cmake_minimum_required(VERSION 3.16) | |
project(SpicyGamesEngine) | |
# Configuration du standard C++ | |
set(CMAKE_CXX_STANDARD 17) | |
set(CMAKE_CXX_STANDARD_REQUIRED ON) | |
# Définir les chemins des bibliothèques selon votre structure | |
set(LIBS_DIR "${CMAKE_CURRENT_SOURCE_DIR}/libs") | |
set(EXTERN_DIR "${CMAKE_CURRENT_SOURCE_DIR}/extern") | |
set(ENGINE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/engine") | |
# Chemins des bibliothèques | |
set(SDL2_DIR "${LIBS_DIR}/SDL2") | |
set(ASSIMP_DIR "${LIBS_DIR}/assimp") | |
set(GLM_DIR "${LIBS_DIR}/glm") | |
set(IMGUI_DIR "${LIBS_DIR}/imgui") | |
set(GLAD_DIR "${LIBS_DIR}/glad") | |
set(IMGUIZMO_DIR "${LIBS_DIR}/ImGuizmo") | |
set(STB_DIR "${LIBS_DIR}/stb") | |
set(LUA_DIR "${EXTERN_DIR}/lua") | |
# Rechercher OpenGL | |
find_package(OpenGL REQUIRED) | |
# Configuration SDL2 | |
set(SDL2_INCLUDE_DIRS "${SDL2_DIR}/include") | |
if(WIN32) | |
set(SDL2_LIBRARIES "${SDL2_DIR}/lib/x64/SDL2.lib;${SDL2_DIR}/lib/x64/SDL2main.lib") | |
set(SDL2_DLLS "${SDL2_DIR}/lib/x64/SDL2.dll") | |
else() | |
find_package(PkgConfig REQUIRED) | |
pkg_check_modules(SDL2 REQUIRED sdl2) | |
endif() | |
# Configuration Assimp | |
set(ASSIMP_INCLUDE_DIRS "${ASSIMP_DIR}/include") | |
if(WIN32) | |
# Chercher la bibliothèque Assimp dans les répertoires possibles | |
find_library(ASSIMP_LIBRARY | |
NAMES assimp assimp-vc143-mt assimp-vc142-mt assimp-vc141-mt | |
PATHS "${ASSIMP_DIR}/lib" "${ASSIMP_DIR}/bin/x64" | |
NO_DEFAULT_PATH | |
) | |
if(NOT ASSIMP_LIBRARY) | |
message(FATAL_ERROR "Assimp library not found in ${ASSIMP_DIR}") | |
endif() | |
set(ASSIMP_LIBRARIES ${ASSIMP_LIBRARY}) | |
# Chercher la DLL Assimp | |
find_file(ASSIMP_DLL | |
NAMES assimp.dll assimp-vc143-mt.dll assimp-vc142-mt.dll assimp-vc141-mt.dll | |
PATHS "${ASSIMP_DIR}/bin" "${ASSIMP_DIR}/bin/x64" | |
NO_DEFAULT_PATH | |
) | |
else() | |
find_package(assimp REQUIRED) | |
set(ASSIMP_LIBRARIES assimp) | |
endif() | |
# Configuration GLM (header-only) | |
set(GLM_INCLUDE_DIRS "${GLM_DIR}") | |
# Configuration Lua | |
set(LUA_INCLUDE_DIRS "${LUA_DIR}/include") | |
if(WIN32) | |
find_library(LUA_LIBRARY | |
NAMES lua lua54 lua53 lua52 | |
PATHS "${LUA_DIR}/lib" | |
NO_DEFAULT_PATH | |
) | |
if(LUA_LIBRARY) | |
set(LUA_LIBRARIES ${LUA_LIBRARY}) | |
set(LUA_FOUND TRUE) | |
else() | |
set(LUA_FOUND FALSE) | |
message(WARNING "Lua library not found, building without Lua support") | |
endif() | |
else() | |
find_package(Lua) | |
endif() | |
# Sources GLAD | |
set(GLAD_SOURCES | |
"${GLAD_DIR}/src/glad.c" | |
) | |
# Sources ImGui | |
set(IMGUI_SOURCES | |
"${IMGUI_DIR}/imgui.cpp" | |
"${IMGUI_DIR}/imgui_demo.cpp" | |
"${IMGUI_DIR}/imgui_draw.cpp" | |
"${IMGUI_DIR}/imgui_tables.cpp" | |
"${IMGUI_DIR}/imgui_widgets.cpp" | |
"${IMGUI_DIR}/backends/imgui_impl_sdl2.cpp" | |
"${IMGUI_DIR}/backends/imgui_impl_opengl3.cpp" | |
) | |
# Sources ImGuizmo | |
set(IMGUIZMO_SOURCES | |
"${IMGUIZMO_DIR}/ImGuizmo.cpp" | |
) | |
# Collecter tous les fichiers source du moteur | |
file(GLOB_RECURSE ENGINE_SOURCES | |
"${ENGINE_DIR}/src/*.cpp" | |
"${ENGINE_DIR}/src/*.c" | |
) | |
# Vérifier que main.cpp existe | |
if(NOT EXISTS "${ENGINE_DIR}/src/main.cpp") | |
message(FATAL_ERROR "main.cpp not found in ${ENGINE_DIR}/src/") | |
endif() | |
# Créer l'exécutable | |
add_executable(${PROJECT_NAME} | |
${ENGINE_SOURCES} | |
${GLAD_SOURCES} | |
${IMGUI_SOURCES} | |
${IMGUIZMO_SOURCES} | |
) | |
# Répertoires d'inclusion | |
target_include_directories(${PROJECT_NAME} PRIVATE | |
# Répertoires du moteur | |
"${ENGINE_DIR}/src" | |
"${ENGINE_DIR}/src/core" | |
"${ENGINE_DIR}/src/graphics" | |
# Bibliothèques externes | |
${SDL2_INCLUDE_DIRS} | |
${ASSIMP_INCLUDE_DIRS} | |
${GLM_INCLUDE_DIRS} | |
"${GLAD_DIR}/include" | |
"${IMGUI_DIR}" | |
"${IMGUI_DIR}/backends" | |
"${IMGUIZMO_DIR}" | |
"${STB_DIR}" | |
) | |
# Configuration Lua conditionnelle | |
if(LUA_FOUND) | |
target_include_directories(${PROJECT_NAME} PRIVATE ${LUA_INCLUDE_DIRS}) | |
target_link_libraries(${PROJECT_NAME} ${LUA_LIBRARIES}) | |
target_compile_definitions(${PROJECT_NAME} PRIVATE LUA_ENABLED) | |
message(STATUS "Lua support enabled") | |
else() | |
target_compile_definitions(${PROJECT_NAME} PRIVATE NO_LUA) | |
message(STATUS "Building without Lua support") | |
endif() | |
# Lier les bibliothèques | |
target_link_libraries(${PROJECT_NAME} | |
${SDL2_LIBRARIES} | |
${ASSIMP_LIBRARIES} | |
${OPENGL_LIBRARIES} | |
) | |
# Configuration spécifique à Windows | |
if(WIN32) | |
# Définir les macros Windows | |
target_compile_definitions(${PROJECT_NAME} PRIVATE | |
_WIN32 | |
NOMINMAX | |
WIN32_LEAN_AND_MEAN | |
) | |
# Copier les DLL nécessaires | |
if(EXISTS "${SDL2_DLLS}") | |
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD | |
COMMAND ${CMAKE_COMMAND} -E copy_if_different | |
"${SDL2_DLLS}" | |
$<TARGET_FILE_DIR:${PROJECT_NAME}> | |
COMMENT "Copying SDL2.dll" | |
) | |
endif() | |
if(ASSIMP_DLL AND EXISTS "${ASSIMP_DLL}") | |
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD | |
COMMAND ${CMAKE_COMMAND} -E copy_if_different | |
"${ASSIMP_DLL}" | |
$<TARGET_FILE_DIR:${PROJECT_NAME}> | |
COMMENT "Copying Assimp DLL" | |
) | |
endif() | |
# Configuration du sous-système | |
set_target_properties(${PROJECT_NAME} PROPERTIES | |
WIN32_EXECUTABLE TRUE | |
LINK_FLAGS "/SUBSYSTEM:CONSOLE" | |
) | |
# Bibliothèques système Windows | |
target_link_libraries(${PROJECT_NAME} | |
kernel32 | |
user32 | |
gdi32 | |
winspool | |
shell32 | |
ole32 | |
oleaut32 | |
uuid | |
comdlg32 | |
advapi32 | |
) | |
endif() | |
# Configuration Debug/Release | |
if(CMAKE_BUILD_TYPE STREQUAL "Debug") | |
target_compile_definitions(${PROJECT_NAME} PRIVATE | |
DEBUG | |
_DEBUG | |
) | |
if(MSVC) | |
target_compile_options(${PROJECT_NAME} PRIVATE /W4 /WX-) | |
else() | |
target_compile_options(${PROJECT_NAME} PRIVATE -Wall -Wextra -g) | |
endif() | |
else() | |
target_compile_definitions(${PROJECT_NAME} PRIVATE | |
NDEBUG | |
RELEASE | |
) | |
if(MSVC) | |
target_compile_options(${PROJECT_NAME} PRIVATE /O2) | |
else() | |
target_compile_options(${PROJECT_NAME} PRIVATE -O3) | |
endif() | |
endif() | |
# Support pour les threads | |
find_package(Threads REQUIRED) | |
target_link_libraries(${PROJECT_NAME} Threads::Threads) | |
# Créer un dossier pour les assets dans le répertoire de sortie | |
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD | |
COMMAND ${CMAKE_COMMAND} -E make_directory | |
$<TARGET_FILE_DIR:${PROJECT_NAME}>/assets | |
COMMENT "Creating assets directory" | |
) | |
# Copier les assets s'ils existent | |
if(EXISTS "${ENGINE_DIR}/assets") | |
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD | |
COMMAND ${CMAKE_COMMAND} -E copy_directory | |
"${ENGINE_DIR}/assets" | |
$<TARGET_FILE_DIR:${PROJECT_NAME}>/assets | |
COMMENT "Copying assets" | |
) | |
endif() | |
# Définir le répertoire de travail pour Visual Studio | |
if(MSVC) | |
set_target_properties(${PROJECT_NAME} PROPERTIES | |
VS_DEBUGGER_WORKING_DIRECTORY $<TARGET_FILE_DIR:${PROJECT_NAME}> | |
) | |
endif() | |
# Messages informatifs | |
message(STATUS "") | |
message(STATUS "=== SpicyGamesEngine Configuration ===") | |
message(STATUS "Build Type: ${CMAKE_BUILD_TYPE}") | |
message(STATUS "C++ Standard: ${CMAKE_CXX_STANDARD}") | |
message(STATUS "") | |
message(STATUS "Engine Sources: ${ENGINE_DIR}/src") | |
message(STATUS "Assets: ${ENGINE_DIR}/assets") | |
message(STATUS "") | |
message(STATUS "Libraries:") | |
message(STATUS " SDL2: ${SDL2_INCLUDE_DIRS}") | |
message(STATUS " Assimp: ${ASSIMP_INCLUDE_DIRS}") | |
message(STATUS " GLM: ${GLM_INCLUDE_DIRS}") | |
message(STATUS " GLAD: ${GLAD_DIR}") | |
message(STATUS " ImGui: ${IMGUI_DIR}") | |
message(STATUS " ImGuizmo: ${IMGUIZMO_DIR}") | |
message(STATUS " STB: ${STB_DIR}") | |
if(LUA_FOUND) | |
message(STATUS " Lua: ${LUA_INCLUDE_DIRS} ✓") | |
else() | |
message(STATUS " Lua: Not found ✗") | |
endif() | |
message(STATUS "") | |
message(STATUS "Build commands:") | |
message(STATUS " cd build")A | |
message(STATUS " cmake ..") | |
message(STATUS " cmake --build . --config Release") | |
message(STATUS "==========================================") | |
message(STATUS "") |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[CMake] G├®n├®ration... | |
-- Selecting Windows SDK version 10.0.26100.0 to target Windows 10.0.22631. | |
CMake Warning at CMakeLists.txt:77 (message): | |
Lua library not found, building without Lua support | |
-- Building without Lua support | |
-- | |
-- === SpicyGamesEngine Configuration === | |
-- Build Type: | |
-- C++ Standard: 17 | |
-- | |
-- Engine Sources: C:/Users/sanab/Music/SpicyGamesEngine/engine/src | |
-- Assets: C:/Users/sanab/Music/SpicyGamesEngine/engine/assets | |
-- | |
-- Libraries: | |
-- SDL2: C:/Users/sanab/Music/SpicyGamesEngine/libs/SDL2/include | |
-- Assimp: C:/Users/sanab/Music/SpicyGamesEngine/libs/assimp/include | |
-- GLM: C:/Users/sanab/Music/SpicyGamesEngine/libs/glm | |
-- GLAD: C:/Users/sanab/Music/SpicyGamesEngine/libs/glad | |
-- ImGui: C:/Users/sanab/Music/SpicyGamesEngine/libs/imgui | |
-- ImGuizmo: C:/Users/sanab/Music/SpicyGamesEngine/libs/ImGuizmo | |
-- STB: C:/Users/sanab/Music/SpicyGamesEngine/libs/stb | |
-- Lua: Not found ✗ | |
-- | |
-- Build commands: | |
-- cd build | |
-- cmake .. | |
-- cmake --build . --config Release | |
-- ========================================== | |
-- | |
-- Configuring done (0.8s) | |
-- Generating done (0.4s) | |
-- Build files have been written to: C:/Users/sanab/Music/SpicyGamesEngine/build | |
[CMake] Compilation... | |
Version MSBuild 17.14.14+a129329f1 pour .NET Framework | |
main.cpp | |
C:\Users\sanab\Music\SpicyGamesEngine\engine\src\main.cpp(67,10): error C2143: erreur de syntaxe : absence de ';' avant | |
'*' [C:\Users\sanab\Music\SpicyGamesEngine\build\SpicyGamesEngine.vcxproj] | |
C:\Users\sanab\Music\SpicyGamesEngine\engine\src\main.cpp(67,1): error C4430: spécificateur de type manquant - int est | |
pris en compte par défaut. Remarque : C++ ne prend pas en charge int par défaut [C:\Users\sanab\Music\SpicyGamesEngine\ | |
build\SpicyGamesEngine.vcxproj] | |
C:\Users\sanab\Music\SpicyGamesEngine\engine\src\main.cpp(67,12): error C4430: spécificateur de type manquant - int est | |
pris en compte par défaut. Remarque : C++ ne prend pas en charge int par défaut [C:\Users\sanab\Music\SpicyGamesEngine | |
\build\SpicyGamesEngine.vcxproj] | |
C:\Users\sanab\Music\SpicyGamesEngine\engine\src\main.cpp(293,36): error C2143: erreur de syntaxe : absence de '}' avan | |
t '(' [C:\Users\sanab\Music\SpicyGamesEngine\build\SpicyGamesEngine.vcxproj] | |
C:\Users\sanab\Music\SpicyGamesEngine\engine\src\main.cpp(293,36): error C2059: erreur de syntaxe : 'constante' [C:\Use | |
rs\sanab\Music\SpicyGamesEngine\build\SpicyGamesEngine.vcxproj] | |
C:\Users\sanab\Music\SpicyGamesEngine\engine\src\main.cpp(293,51): error C2143: erreur de syntaxe : absence de ';' avan | |
t '}' [C:\Users\sanab\Music\SpicyGamesEngine\build\SpicyGamesEngine.vcxproj] | |
C:\Users\sanab\Music\SpicyGamesEngine\engine\src\main.cpp(293,51): error C2238: jetons inattendus avant ';' [C:\Users\s | |
anab\Music\SpicyGamesEngine\build\SpicyGamesEngine.vcxproj] | |
C:\Users\sanab\Music\SpicyGamesEngine\engine\src\main.cpp(296,1): error C2059: erreur de syntaxe : '}' [C:\Users\sanab\ | |
Music\SpicyGamesEngine\build\SpicyGamesEngine.vcxproj] | |
C:\Users\sanab\Music\SpicyGamesEngine\engine\src\main.cpp(296,1): error C2143: erreur de syntaxe : absence de ';' avant | |
'}' [C:\Users\sanab\Music\SpicyGamesEngine\build\SpicyGamesEngine.vcxproj] | |
C:\Users\sanab\Music\SpicyGamesEngine\engine\src\main.cpp(656,23): error C2065: 'ImGuiConfigFlags_DockingEnable' : iden | |
tificateur non déclaré [C:\Users\sanab\Music\SpicyGamesEngine\build\SpicyGamesEngine.vcxproj] | |
C:\Users\sanab\Music\SpicyGamesEngine\engine\src\main.cpp(657,23): error C2065: 'ImGuiConfigFlags_ViewportsEnable' : id | |
entificateur non déclaré [C:\Users\sanab\Music\SpicyGamesEngine\build\SpicyGamesEngine.vcxproj] | |
C:\Users\sanab\Music\SpicyGamesEngine\engine\src\main.cpp(661,26): error C2065: 'ImGuiConfigFlags_ViewportsEnable' : id | |
entificateur non déclaré [C:\Users\sanab\Music\SpicyGamesEngine\build\SpicyGamesEngine.vcxproj] | |
C:\Users\sanab\Music\SpicyGamesEngine\engine\src\main.cpp(733,9): error C2065: 'ImGuiDockNodeFlags' : identificateur no | |
n déclaré [C:\Users\sanab\Music\SpicyGamesEngine\build\SpicyGamesEngine.vcxproj] | |
C:\Users\sanab\Music\SpicyGamesEngine\engine\src\main.cpp(733,28): error C2146: erreur de syntaxe : absence de ';' avan | |
t l'identificateur 'dockspace_flags' [C:\Users\sanab\Music\SpicyGamesEngine\build\SpicyGamesEngine.vcxproj] | |
C:\Users\sanab\Music\SpicyGamesEngine\engine\src\main.cpp(733,28): error C2065: 'dockspace_flags' : identificateur non | |
déclaré [C:\Users\sanab\Music\SpicyGamesEngine\build\SpicyGamesEngine.vcxproj] | |
C:\Users\sanab\Music\SpicyGamesEngine\engine\src\main.cpp(733,46): error C2065: 'ImGuiDockNodeFlags_None' : identificat | |
eur non déclaré [C:\Users\sanab\Music\SpicyGamesEngine\build\SpicyGamesEngine.vcxproj] | |
C:\Users\sanab\Music\SpicyGamesEngine\engine\src\main.cpp(734,68): error C2065: 'ImGuiWindowFlags_NoDocking' : identifi | |
cateur non déclaré [C:\Users\sanab\Music\SpicyGamesEngine\build\SpicyGamesEngine.vcxproj] | |
C:\Users\sanab\Music\SpicyGamesEngine\engine\src\main.cpp(739,16): error C2039: 'SetNextWindowViewport' n'est pas membr | |
e de 'ImGui' [C:\Users\sanab\Music\SpicyGamesEngine\build\SpicyGamesEngine.vcxproj] | |
C:\Users\sanab\Music\SpicyGamesEngine\libs\imgui\imgui.h(3970,11): | |
voir la déclaration de 'ImGui' | |
C:\Users\sanab\Music\SpicyGamesEngine\engine\src\main.cpp(739,16): error C3861: 'SetNextWindowViewport' : identificateu | |
r introuvable [C:\Users\sanab\Music\SpicyGamesEngine\build\SpicyGamesEngine.vcxproj] | |
C:\Users\sanab\Music\SpicyGamesEngine\engine\src\main.cpp(745,13): error C2065: 'dockspace_flags' : identificateur non | |
déclaré [C:\Users\sanab\Music\SpicyGamesEngine\build\SpicyGamesEngine.vcxproj] | |
C:\Users\sanab\Music\SpicyGamesEngine\engine\src\main.cpp(745,31): error C2065: 'ImGuiDockNodeFlags_PassthruCentralNode | |
' : identificateur non déclaré [C:\Users\sanab\Music\SpicyGamesEngine\build\SpicyGamesEngine.vcxproj] | |
C:\Users\sanab\Music\SpicyGamesEngine\engine\src\main.cpp(755,30): error C2065: 'ImGuiConfigFlags_DockingEnable' : iden | |
tificateur non déclaré [C:\Users\sanab\Music\SpicyGamesEngine\build\SpicyGamesEngine.vcxproj] | |
C:\Users\sanab\Music\SpicyGamesEngine\engine\src\main.cpp(757,20): error C2039: 'DockSpace' n'est pas membre de 'ImGui' | |
[C:\Users\sanab\Music\SpicyGamesEngine\build\SpicyGamesEngine.vcxproj] | |
C:\Users\sanab\Music\SpicyGamesEngine\libs\imgui\imgui.h(3970,11): | |
voir la déclaration de 'ImGui' | |
C:\Users\sanab\Music\SpicyGamesEngine\engine\src\main.cpp(757,64): error C2065: 'dockspace_flags' : identificateur non | |
déclaré [C:\Users\sanab\Music\SpicyGamesEngine\build\SpicyGamesEngine.vcxproj] | |
C:\Users\sanab\Music\SpicyGamesEngine\engine\src\main.cpp(757,20): error C3861: 'DockSpace' : identificateur introuvabl | |
e [C:\Users\sanab\Music\SpicyGamesEngine\build\SpicyGamesEngine.vcxproj] | |
C:\Users\sanab\Music\SpicyGamesEngine\engine\src\main.cpp(791,30): error C2065: 'ImGuiConfigFlags_ViewportsEnable' : id | |
entificateur non déclaré [C:\Users\sanab\Music\SpicyGamesEngine\build\SpicyGamesEngine.vcxproj] | |
C:\Users\sanab\Music\SpicyGamesEngine\engine\src\main.cpp(794,20): error C2039: 'UpdatePlatformWindows' n'est pas membr | |
e de 'ImGui' [C:\Users\sanab\Music\SpicyGamesEngine\build\SpicyGamesEngine.vcxproj] | |
C:\Users\sanab\Music\SpicyGamesEngine\libs\imgui\imgui.h(3970,11): | |
voir la déclaration de 'ImGui' | |
C:\Users\sanab\Music\SpicyGamesEngine\engine\src\main.cpp(794,20): error C3861: 'UpdatePlatformWindows' : identificateu | |
r introuvable [C:\Users\sanab\Music\SpicyGamesEngine\build\SpicyGamesEngine.vcxproj] | |
C:\Users\sanab\Music\SpicyGamesEngine\engine\src\main.cpp(795,20): error C2039: 'RenderPlatformWindowsDefault' n'est pa | |
s membre de 'ImGui' [C:\Users\sanab\Music\SpicyGamesEngine\build\SpicyGamesEngine.vcxproj] | |
C:\Users\sanab\Music\SpicyGamesEngine\libs\imgui\imgui.h(3970,11): | |
voir la déclaration de 'ImGui' | |
C:\Users\sanab\Music\SpicyGamesEngine\engine\src\main.cpp(795,20): error C3861: 'RenderPlatformWindowsDefault' : identi | |
ficateur introuvable [C:\Users\sanab\Music\SpicyGamesEngine\build\SpicyGamesEngine.vcxproj] | |
C:\Users\sanab\Music\SpicyGamesEngine\engine\src\main.cpp(808,9): error C3861: 'lua_close' : identificateur introuvable | |
[C:\Users\sanab\Music\SpicyGamesEngine\build\SpicyGamesEngine.vcxproj] | |
C:\Users\sanab\Music\SpicyGamesEngine\engine\src\main.cpp(1734,2): error C4430: spécificateur de type manquant - int es | |
t pris en compte par défaut. Remarque : C++ ne prend pas en charge int par défaut [C:\Users\sanab\Music\SpicyGamesEngin | |
e\build\SpicyGamesEngine.vcxproj] | |
C:\Users\sanab\Music\SpicyGamesEngine\engine\src\main.cpp(1734,11): error C2059: erreur de syntaxe : ':' [C:\Users\sana | |
b\Music\SpicyGamesEngine\build\SpicyGamesEngine.vcxproj] | |
C:\Users\sanab\Music\SpicyGamesEngine\engine\src\main.cpp(1735,21): error C2059: erreur de syntaxe : 'if' [C:\Users\san | |
ab\Music\SpicyGamesEngine\build\SpicyGamesEngine.vcxproj] | |
C:\Users\sanab\Music\SpicyGamesEngine\engine\src\main.cpp(1735,50): error C2143: erreur de syntaxe : absence de ';' ava | |
nt '{' [C:\Users\sanab\Music\SpicyGamesEngine\build\SpicyGamesEngine.vcxproj] | |
C:\Users\sanab\Music\SpicyGamesEngine\engine\src\main.cpp(1735,50): error C2447: '{' : en-tête de fonction manquant (li | |
ste formelle à l'ancien format ?) [C:\Users\sanab\Music\SpicyGamesEngine\build\SpicyGamesEngine.vcxproj] | |
C:\Users\sanab\Music\SpicyGamesEngine\engine\src\main.cpp(1741,21): error C2059: erreur de syntaxe : 'break' [C:\Users\ | |
sanab\Music\SpicyGamesEngine\build\SpicyGamesEngine.vcxproj] | |
C:\Users\sanab\Music\SpicyGamesEngine\engine\src\main.cpp(1742,17): error C2059: erreur de syntaxe : 'case' [C:\Users\s | |
anab\Music\SpicyGamesEngine\build\SpicyGamesEngine.vcxproj] | |
Ô£à Build termin├®. | |
L'ex├®cutable est situ├® dans: build\Release\SpicyGamesEngine.exe | |
Appuyez sur une touche pour continuer... |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <iostream> | |
#include <string> | |
#include <vector> | |
#include <memory> | |
#include <map> | |
#include <filesystem> | |
#include <chrono> | |
#include <fstream> | |
#include <sstream> | |
#include <set> | |
#include <algorithm> | |
#include <utility> | |
#include <cstring> | |
#include <cstdint> | |
// File dialog for Windows | |
#ifdef _WIN32 | |
#include <windows.h> | |
#include <commdlg.h> | |
#endif | |
#include <SDL.h> | |
// Fix APIENTRY redefinition | |
#ifdef _WIN32 | |
#undef APIENTRY | |
#endif | |
#include <glad/glad.h> | |
#include <imgui.h> | |
#include <imgui_impl_sdl2.h> | |
#include <imgui_impl_opengl3.h> | |
#include <ImGuizmo.h> | |
#include <assimp/version.h> | |
#include <assimp/Importer.hpp> | |
#include <assimp/scene.h> | |
#include <assimp/postprocess.h> | |
#ifndef NO_LUA | |
#include <lua.hpp> | |
#endif | |
#include <glm/glm.hpp> | |
#include <glm/gtc/type_ptr.hpp> | |
#include <glm/gtx/matrix_decompose.hpp> | |
#include <glm/gtx/transform.hpp> | |
#include <glm/gtc/matrix_transform.hpp> | |
#define STB_IMAGE_IMPLEMENTATION | |
#include <stb_image.h> | |
// Définir M_PI si pas défini | |
#ifndef M_PI | |
#define M_PI 3.14159265358979323846 | |
#endif | |
// Forward declarations | |
struct Mesh; | |
struct SceneObject; | |
struct Camera; | |
struct InputState; | |
struct PerformanceStats; | |
// Global variables | |
SDL_Window* g_window = nullptr; | |
SDL_GLContext g_glContext = nullptr; | |
lua_State* g_luaState = nullptr; | |
// OpenGL variables | |
GLuint g_shaderProgram = 0; | |
GLuint g_skyboxShader = 0; | |
GLuint g_skyboxVAO = 0; | |
GLuint g_skyboxVBO = 0; | |
// Textures | |
std::map<std::string, GLuint> g_textures; | |
GLuint g_skyboxTexture = 0; | |
// Project settings | |
struct ProjectSettings { | |
std::string projectName = "New Project"; | |
std::string projectPath = ""; | |
std::string sceneName = "Main Scene"; | |
bool autoSave = true; | |
int autoSaveInterval = 300; // seconds | |
} g_projectSettings; | |
// Mesh data structure | |
struct Vertex { | |
glm::vec3 position; | |
glm::vec2 texCoords; | |
glm::vec3 normal; | |
}; | |
struct Mesh { | |
std::vector<Vertex> vertices; | |
std::vector<unsigned int> indices; | |
GLuint VAO = 0, VBO = 0, EBO = 0; | |
std::string textureName; | |
void setupMesh() { | |
glGenVertexArrays(1, &VAO); | |
glGenBuffers(1, &VBO); | |
glGenBuffers(1, &EBO); | |
glBindVertexArray(VAO); | |
glBindBuffer(GL_ARRAY_BUFFER, VBO); | |
glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(Vertex), &vertices[0], GL_STATIC_DRAW); | |
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO); | |
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(unsigned int), &indices[0], GL_STATIC_DRAW); | |
// Positions | |
glEnableVertexAttribArray(0); | |
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)0); | |
// Texture coordinates | |
glEnableVertexAttribArray(1); | |
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, texCoords)); | |
// Normals | |
glEnableVertexAttribArray(2); | |
glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, normal)); | |
glBindVertexArray(0); | |
} | |
void draw() { | |
glBindVertexArray(VAO); | |
glDrawElements(GL_TRIANGLES, static_cast<GLsizei>(indices.size()), GL_UNSIGNED_INT, 0); | |
glBindVertexArray(0); | |
} | |
~Mesh() { | |
if (VAO) glDeleteVertexArrays(1, &VAO); | |
if (VBO) glDeleteBuffers(1, &VBO); | |
if (EBO) glDeleteBuffers(1, &EBO); | |
} | |
}; | |
// Camera | |
struct Camera { | |
glm::vec3 position = glm::vec3(5.0f, 5.0f, 5.0f); | |
glm::vec3 target = glm::vec3(0.0f, 0.0f, 0.0f); | |
glm::vec3 up = glm::vec3(0.0f, 1.0f, 0.0f); | |
glm::vec3 front = glm::vec3(0.0f, 0.0f, -1.0f); | |
glm::vec3 right = glm::vec3(1.0f, 0.0f, 0.0f); | |
float yaw = -90.0f; | |
float pitch = 0.0f; | |
float fov = 45.0f; | |
float nearPlane = 0.1f; | |
float farPlane = 100.0f; | |
float speed = 5.0f; | |
float sensitivity = 0.1f; | |
void updateVectors() { | |
glm::vec3 direction; | |
direction.x = cos(glm::radians(yaw)) * cos(glm::radians(pitch)); | |
direction.y = sin(glm::radians(pitch)); | |
direction.z = sin(glm::radians(yaw)) * cos(glm::radians(pitch)); | |
front = glm::normalize(direction); | |
right = glm::normalize(glm::cross(front, glm::vec3(0.0f, 1.0f, 0.0f))); | |
up = glm::normalize(glm::cross(right, front)); | |
target = position + front; | |
} | |
glm::mat4 getViewMatrix() { | |
return glm::lookAt(position, position + front, up); | |
} | |
glm::mat4 getProjectionMatrix(float aspectRatio) { | |
return glm::perspective(glm::radians(fov), aspectRatio, nearPlane, farPlane); | |
} | |
}; | |
// Input state | |
struct InputState { | |
bool keys[SDL_NUM_SCANCODES] = {false}; | |
bool mouseButtons[8] = {false}; | |
int mouseX = 0, mouseY = 0; | |
int mouseDeltaX = 0, mouseDeltaY = 0; | |
bool firstMouse = true; | |
int lastMouseX = 0, lastMouseY = 0; | |
bool rightMousePressed = false; | |
}; | |
enum class ObjectType { | |
CUBE, | |
SPHERE, | |
PLANE, | |
CYLINDER, | |
LIGHT, | |
MODEL, | |
EMPTY | |
}; | |
struct SceneObject { | |
std::string name; | |
glm::mat4 transform = glm::mat4(1.0f); | |
ObjectType type = ObjectType::CUBE; | |
glm::vec3 color = glm::vec3(0.7f, 0.7f, 1.0f); | |
bool visible = true; | |
bool selected = false; | |
std::string textureName = ""; | |
std::string modelPath = ""; | |
glm::vec3 scale = glm::vec3(1.0f); | |
glm::vec3 rotation = glm::vec3(0.0f); | |
glm::vec3 position = glm::vec3(0.0f); | |
// Light properties | |
float lightIntensity = 1.0f; | |
float lightRange = 10.0f; | |
// Material properties | |
float roughness = 0.5f; | |
float metallic = 0.0f; | |
float emission = 0.0f; | |
std::vector<std::unique_ptr<Mesh>> meshes; | |
void updateTransform() { | |
glm::mat4 T = glm::translate(glm::mat4(1.0f), position); | |
glm::mat4 R = glm::rotate(glm::mat4(1.0f), glm::radians(rotation.x), glm::vec3(1, 0, 0)); | |
R = glm::rotate(R, glm::radians(rotation.y), glm::vec3(0, 1, 0)); | |
R = glm::rotate(R, glm::radians(rotation.z), glm::vec3(0, 0, 1)); | |
glm::mat4 S = glm::scale(glm::mat4(1.0f), scale); | |
transform = T * R * S; | |
} | |
void decomposeTransform() { | |
glm::vec3 skew; | |
glm::vec4 perspective; | |
glm::quat orient; | |
glm::decompose(transform, scale, orient, position, skew, perspective); | |
rotation = glm::degrees(glm::eulerAngles(orient)); | |
} | |
}; | |
// Global scene objects and variables | |
std::vector<std::unique_ptr<SceneObject>> g_sceneObjects; | |
int g_objectCounter = 0; | |
int g_selectedIndex = -1; | |
Camera g_camera; | |
InputState g_input; | |
// Default meshes | |
std::unique_ptr<Mesh> g_defaultCubeMesh; | |
std::unique_ptr<Mesh> g_defaultSphereMesh; | |
std::unique_ptr<Mesh> g_defaultPlaneMesh; | |
std::unique_ptr<Mesh> g_defaultCylinderMesh; | |
// Gizmo settings | |
ImGuizmo::OPERATION g_gizmoOperation = ImGuizmo::TRANSLATE; | |
ImGuizmo::MODE g_gizmoMode = ImGuizmo::LOCAL; | |
bool g_useSnap = false; | |
float g_snapValues[3] = { 1.0f, 15.0f, 0.1f }; // translate, rotation, scale | |
// UI State | |
bool g_showSceneHierarchy = true; | |
bool g_showProperties = true; | |
bool g_showViewport = true; | |
bool g_showAssetBrowser = true; | |
bool g_showConsole = true; | |
bool g_showTextureManager = true; | |
bool g_showSettings = false; | |
bool g_showStats = true; | |
bool g_showDemoWindow = false; | |
// Console | |
std::vector<std::string> g_consoleLog; | |
std::string g_consoleInput; | |
// Skybox colors | |
glm::vec3 g_skyboxTopColor = glm::vec3(0.5f, 0.7f, 1.0f); | |
glm::vec3 g_skyboxBottomColor = glm::vec3(0.8f, 0.9f, 1.0f); | |
// Framebuffer for viewport | |
GLuint g_framebuffer = 0; | |
GLuint g_colorTexture = 0; | |
GLuint g_depthTexture = 0; | |
int g_viewportWidth = 800; | |
int g_viewportHeight = 600; | |
// Performance tracking | |
struct PerformanceStats { | |
float frameTime = 0.0f; | |
float fps = 0.0f; | |
int drawCalls = 0; | |
int vertices = 0; | |
int triangles = 0; | |
} g_stats; | |
// Undo/Redo system | |
struct UndoAction { | |
enum Type { TRANSFORM, CREATE, DELETE, MODIFY } type; | |
int objectIndex; | |
std::string data; | |
}; | |
std::vector<UndoAction> g_undoStack; | |
std::vector<UndoAction> g_redoStack; | |
const size_t MAX_UNDO_STACK = 50; | |
// Global variables for settings | |
bool g_wireframe = false; | |
bool g_vsync = true; | |
float g_gamma = 2.2f; | |
bool g_gizmoBounds = false; | |
// Function prototypes | |
void LogToConsole(const std::string& message); | |
std::string OpenFileDialog(const char* filter); | |
std::string SaveFileDialog(const char* filter); | |
GLuint LoadTexture(const std::string& path); | |
GLuint CompileShader(GLenum type, const char* source); | |
void CreateDefaultCubeMesh(); | |
void CreateSphereMesh(); | |
void CreatePlaneMesh(); | |
void CreateCylinderMesh(); | |
void CreateFramebuffer(int width, int height); | |
void InitOpenGL(); | |
void InitLua(); | |
void ProcessInput(float deltaTime); | |
void CreateObject(ObjectType type); | |
void ImportModel(); | |
void ImportTexture(); | |
bool LoadModel(const std::string& path, SceneObject* obj); | |
void RenderScene(); | |
void RenderSkybox(const glm::mat4& view, const glm::mat4& projection); | |
Mesh* GetMeshForObjectType(ObjectType type); | |
std::unique_ptr<Mesh> ProcessMesh(aiMesh* mesh, const aiScene* scene); | |
void ProcessNode(aiNode* node, const aiScene* scene, std::vector<std::unique_ptr<Mesh>>& meshes); | |
void RenderMenuBar(); | |
void RenderSceneHierarchy(); | |
void RenderProperties(); | |
void RenderAssetBrowser(); | |
void RenderTextureManager(); | |
void RenderConsole(); | |
void RenderSettings(); | |
void RenderStats(); | |
void RenderViewport(); | |
// Function to log messages to console | |
void LogToConsole(const std::string& message) { | |
g_consoleLog.push_back(message); | |
if (g_consoleLog.size() > 1000) { | |
g_consoleLog.erase(g_consoleLog.begin()); | |
} | |
std::cout << "[LOG] " << message << std::endl; | |
} | |
// File dialog functions | |
#ifdef _WIN32 | |
std::string OpenFileDialog(const char* filter) { | |
OPENFILENAMEA ofn; | |
char szFile[260] = {0}; | |
ZeroMemory(&ofn, sizeof(ofn)); | |
ofn.lStructSize = sizeof(ofn); | |
ofn.hwndOwner = NULL; | |
ofn.lpstrFile = szFile; | |
ofn.nMaxFile = sizeof(szFile); | |
ofn.lpstrFilter = filter; | |
ofn.nFilterIndex = 1; | |
ofn.lpstrFileTitle = NULL; | |
ofn.nMaxFileTitle = 0; | |
ofn.lpstrInitialDir = NULL; | |
ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST; | |
if (GetOpenFileNameA(&ofn)) { | |
return std::string(szFile); | |
} | |
return ""; | |
} | |
std::string SaveFileDialog(const char* filter) { | |
OPENFILENAMEA ofn; | |
char szFile[260] = {0}; | |
ZeroMemory(&ofn, sizeof(ofn)); | |
ofn.lStructSize = sizeof(ofn); | |
ofn.hwndOwner = NULL; | |
ofn.lpstrFile = szFile; | |
ofn.nMaxFile = sizeof(szFile); | |
ofn.lpstrFilter = filter; | |
ofn.nFilterIndex = 1; | |
ofn.lpstrFileTitle = NULL; | |
ofn.nMaxFileTitle = 0; | |
ofn.lpstrInitialDir = NULL; | |
ofn.Flags = OFN_PATHMUSTEXIST | OFN_OVERWRITEPROMPT; | |
if (GetSaveFileNameA(&ofn)) { | |
return std::string(szFile); | |
} | |
return ""; | |
} | |
#else | |
std::string OpenFileDialog(const char* filter) { | |
LogToConsole("File dialog not implemented for this platform"); | |
return ""; | |
} | |
std::string SaveFileDialog(const char* filter) { | |
LogToConsole("Save dialog not implemented for this platform"); | |
return ""; | |
} | |
#endif | |
// Texture loading function | |
GLuint LoadTexture(const std::string& path) { | |
GLuint textureID; | |
glGenTextures(1, &textureID); | |
int width, height, nrChannels; | |
stbi_set_flip_vertically_on_load(true); | |
unsigned char* data = stbi_load(path.c_str(), &width, &height, &nrChannels, 0); | |
if (data) { | |
GLenum format = GL_RGB; | |
if (nrChannels == 1) format = GL_RED; | |
else if (nrChannels == 3) format = GL_RGB; | |
else if (nrChannels == 4) format = GL_RGBA; | |
glBindTexture(GL_TEXTURE_2D, textureID); | |
glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, data); | |
glGenerateMipmap(GL_TEXTURE_2D); | |
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); | |
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); | |
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); | |
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | |
stbi_image_free(data); | |
LogToConsole("Texture chargee: " + path + " (" + std::to_string(width) + "x" + std::to_string(height) + ")"); | |
} else { | |
LogToConsole("Erreur chargement texture: " + path); | |
glDeleteTextures(1, &textureID); | |
return 0; | |
} | |
return textureID; | |
} | |
// Shader sources | |
const char* vertexShaderSource = R"( | |
#version 330 core | |
layout (location = 0) in vec3 aPos; | |
layout (location = 1) in vec2 aTexCoord; | |
layout (location = 2) in vec3 aNormal; | |
uniform mat4 model; | |
uniform mat4 view; | |
uniform mat4 projection; | |
uniform bool isWireframe; | |
out vec2 TexCoord; | |
out vec3 Normal; | |
out vec3 FragPos; | |
void main() | |
{ | |
FragPos = vec3(model * vec4(aPos, 1.0)); | |
Normal = mat3(transpose(inverse(model))) * aNormal; | |
TexCoord = aTexCoord; | |
gl_Position = projection * view * vec4(FragPos, 1.0); | |
} | |
)"; | |
const char* fragmentShaderSource = R"( | |
#version 330 core | |
out vec4 FragColor; | |
in vec2 TexCoord; | |
in vec3 Normal; | |
in vec3 FragPos; | |
uniform vec3 objectColor; | |
uniform bool isSelected; | |
uniform bool isWireframe; | |
uniform bool hasTexture; | |
uniform sampler2D texture1; | |
uniform vec3 lightPos; | |
uniform vec3 lightColor; | |
uniform vec3 viewPos; | |
uniform float roughness; | |
uniform float metallic; | |
uniform float emission; | |
void main() | |
{ | |
if (isWireframe) { | |
FragColor = vec4(1.0, 0.5, 0.0, 1.0); | |
return; | |
} | |
vec3 color = objectColor; | |
if (hasTexture) { | |
vec3 texColor = texture(texture1, TexCoord).rgb; | |
color = color * texColor; | |
} | |
// Simple PBR-like lighting | |
vec3 norm = normalize(Normal); | |
vec3 lightDir = normalize(lightPos - FragPos); | |
vec3 viewDir = normalize(viewPos - FragPos); | |
vec3 halfwayDir = normalize(lightDir + viewDir); | |
// Diffuse | |
float diff = max(dot(norm, lightDir), 0.0); | |
vec3 diffuse = diff * lightColor * (1.0 - metallic); | |
// Specular | |
float spec = pow(max(dot(norm, halfwayDir), 0.0), (1.0 - roughness) * 256.0); | |
vec3 specular = spec * lightColor * mix(vec3(0.04), color, metallic); | |
vec3 ambient = 0.1 * color; | |
vec3 result = ambient + diffuse * color + specular; | |
// Add emission | |
result += color * emission; | |
if (isSelected) { | |
result = mix(result, vec3(1.0, 0.5, 0.0), 0.3); | |
} | |
FragColor = vec4(result, 1.0); | |
} | |
)"; | |
const char* skyboxVertexShader = R"( | |
#version 330 core | |
layout (location = 0) in vec3 aPos; | |
uniform mat4 view; | |
uniform mat4 projection; | |
out vec3 WorldPos; | |
void main() | |
{ | |
WorldPos = aPos; | |
mat4 rotView = mat4(mat3(view)); | |
vec4 clipPos = projection * rotView * vec4(aPos, 1.0); | |
gl_Position = clipPos.xyww; | |
} | |
)"; | |
const char* skyboxFragmentShader = R"( | |
#version 330 core | |
out vec4 FragColor; | |
in vec3 WorldPos; | |
uniform vec3 topColor; | |
uniform vec3 bottomColor; | |
void main() | |
{ | |
float t = (normalize(WorldPos).y + 1.0) * 0.5; | |
vec3 color = mix(bottomColor, topColor, t); | |
FragColor = vec4(color, 1.0); | |
} | |
)"; | |
// Shader compilation function | |
GLuint CompileShader(GLenum type, const char* source) { | |
GLuint shader = glCreateShader(type); | |
glShaderSource(shader, 1, &source, NULL); | |
glCompileShader(shader); | |
GLint success; | |
glGetShaderiv(shader, GL_COMPILE_STATUS, &success); | |
if (!success) { | |
char infoLog[512]; | |
glGetShaderInfoLog(shader, 512, NULL, infoLog); | |
LogToConsole("Erreur compilation shader: " + std::string(infoLog)); | |
} | |
return shader; | |
} | |
// Mesh creation functions (reste du code...) | |
void CreateDefaultCubeMesh() { | |
g_defaultCubeMesh = std::make_unique<Mesh>(); | |
g_defaultCubeMesh->vertices = { | |
// Front face | |
{{-0.5f, -0.5f, 0.5f}, {0.0f, 0.0f}, {0.0f, 0.0f, 1.0f}}, | |
{{ 0.5f, -0.5f, 0.5f}, {1.0f, 0.0f}, {0.0f, 0.0f, 1.0f}}, | |
{{ 0.5f, 0.5f, 0.5f}, {1.0f, 1.0f}, {0.0f, 0.0f, 1.0f}}, | |
{{-0.5f, 0.5f, 0.5f}, {0.0f, 1.0f}, {0.0f, 0.0f, 1.0f}}, | |
// Back face | |
{{-0.5f, -0.5f, -0.5f}, {1.0f, 0.0f}, {0.0f, 0.0f, -1.0f}}, | |
{{ 0.5f, -0.5f, -0.5f}, {0.0f, 0.0f}, {0.0f, 0.0f, -1.0f}}, | |
{{ 0.5f, 0.5f, -0.5f}, {0.0f, 1.0f}, {0.0f, 0.0f, -1.0f}}, | |
{{-0.5f, 0.5f, -0.5f}, {1.0f, 1.0f}, {0.0f, 0.0f, -1.0f}} | |
}; | |
g_defaultCubeMesh->indices = { | |
0, 1, 2, 2, 3, 0, // Front | |
4, 5, 6, 6, 7, 4, // Back | |
3, 2, 6, 6, 7, 3, // Top | |
0, 1, 5, 5, 4, 0, // Bottom | |
0, 3, 7, 7, 4, 0, // Left | |
1, 2, 6, 6, 5, 1 // Right | |
}; | |
g_defaultCubeMesh->setupMesh(); | |
} | |
// Ajoutez ici les autres fonctions manquantes... | |
// Note: Le fichier original semble tronqué, je fournis la structure de base corrigée | |
int main(int argc, char* argv[]) { | |
// Initialization | |
if (SDL_Init(SDL_INIT_VIDEO) < 0) { | |
std::cerr << "SDL initialization failed: " << SDL_GetError() << std::endl; | |
return -1; | |
} | |
// OpenGL context | |
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); | |
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3); | |
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); | |
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); | |
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); | |
// Create window | |
g_window = SDL_CreateWindow("SpicyGamesEngine", | |
SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, | |
1280, 720, | |
SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE); | |
if (!g_window) { | |
std::cerr << "Window creation failed: " << SDL_GetError() << std::endl; | |
SDL_Quit(); | |
return -1; | |
} | |
g_glContext = SDL_GL_CreateContext(g_window); | |
if (!g_glContext) { | |
std::cerr << "OpenGL context creation failed: " << SDL_GetError() << std::endl; | |
SDL_DestroyWindow(g_window); | |
SDL_Quit(); | |
return -1; | |
} | |
if (!gladLoadGLLoader((GLADloadproc)SDL_GL_GetProcAddress)) { | |
std::cerr << "Failed to initialize OpenGL context" << std::endl; | |
return -1; | |
} | |
// Enable VSync | |
SDL_GL_SetSwapInterval(g_vsync ? 1 : 0); | |
// Initialize ImGui | |
IMGUI_CHECKVERSION(); | |
ImGui::CreateContext(); | |
ImGuiIO& io = ImGui::GetIO(); | |
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; | |
io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; | |
io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; | |
ImGui::StyleColorsDark(); | |
ImGuiStyle& style = ImGui::GetStyle(); | |
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) { | |
style.WindowRounding = 0.0f; | |
style.Colors[ImGuiCol_WindowBg].w = 1.0f; | |
} | |
ImGui_ImplSDL2_InitForOpenGL(g_window, g_glContext); | |
ImGui_ImplOpenGL3_Init("#version 330"); | |
// Initialize engine systems | |
InitOpenGL(); | |
InitLua(); | |
LogToConsole("SpicyGamesEngine demarré avec succès!"); | |
// Main loop | |
bool running = true; | |
auto lastTime = std::chrono::high_resolution_clock::now(); | |
while (running) { | |
auto currentTime = std::chrono::high_resolution_clock::now(); | |
float deltaTime = std::chrono::duration<float>(currentTime - lastTime).count(); | |
lastTime = currentTime; | |
g_stats.frameTime = deltaTime; | |
g_stats.fps = 1.0f / deltaTime; | |
// Events | |
SDL_Event event; | |
while (SDL_PollEvent(&event)) { | |
ImGui_ImplSDL2_ProcessEvent(&event); | |
switch (event.type) { | |
case SDL_QUIT: | |
running = false; | |
break; | |
case SDL_KEYDOWN: | |
if (event.key.keysym.scancode < SDL_NUM_SCANCODES) { | |
g_input.keys[event.key.keysym.scancode] = true; | |
} | |
break; | |
case SDL_KEYUP: | |
if (event.key.keysym.scancode < SDL_NUM_SCANCODES) { | |
g_input.keys[event.key.keysym.scancode] = false; | |
} | |
break; | |
case SDL_MOUSEBUTTONUP: | |
if (event.button.button < 8) { | |
g_input.mouseButtons[event.button.button] = false; | |
if (event.button.button == SDL_BUTTON_RIGHT) { | |
g_input.rightMousePressed = false; | |
} | |
} | |
break; | |
case SDL_MOUSEMOTION: | |
g_input.mouseX = event.motion.x; | |
g_input.mouseY = event.motion.y; | |
g_input.mouseDeltaX = event.motion.xrel; | |
g_input.mouseDeltaY = event.motion.yrel; | |
break; | |
} | |
} | |
// Process input | |
ProcessInput(deltaTime); | |
// Start ImGui frame | |
ImGui_ImplOpenGL3_NewFrame(); | |
ImGui_ImplSDL2_NewFrame(); | |
ImGui::NewFrame(); | |
ImGuizmo::BeginFrame(); | |
// Create dockspace | |
ImGuiDockNodeFlags dockspace_flags = ImGuiDockNodeFlags_None; | |
ImGuiWindowFlags window_flags = ImGuiWindowFlags_MenuBar | ImGuiWindowFlags_NoDocking; | |
const ImGuiViewport* viewport = ImGui::GetMainViewport(); | |
ImGui::SetNextWindowPos(viewport->WorkPos); | |
ImGui::SetNextWindowSize(viewport->WorkSize); | |
ImGui::SetNextWindowViewport(viewport->ID); | |
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f); | |
ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f); | |
window_flags |= ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove; | |
window_flags |= ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoNavFocus; | |
if (dockspace_flags & ImGuiDockNodeFlags_PassthruCentralNode) | |
window_flags |= ImGuiWindowFlags_NoBackground; | |
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f)); | |
ImGui::Begin("DockSpace Demo", nullptr, window_flags); | |
ImGui::PopStyleVar(); | |
ImGui::PopStyleVar(2); | |
// Submit the DockSpace | |
ImGuiIO& io = ImGui::GetIO(); | |
if (io.ConfigFlags & ImGuiConfigFlags_DockingEnable) { | |
ImGuiID dockspace_id = ImGui::GetID("MyDockSpace"); | |
ImGui::DockSpace(dockspace_id, ImVec2(0.0f, 0.0f), dockspace_flags); | |
} | |
// Render menu bar | |
RenderMenuBar(); | |
ImGui::End(); | |
// Render UI panels | |
RenderSceneHierarchy(); | |
RenderProperties(); | |
RenderAssetBrowser(); | |
RenderTextureManager(); | |
RenderConsole(); | |
RenderSettings(); | |
RenderStats(); | |
RenderViewport(); | |
if (g_showDemoWindow) { | |
ImGui::ShowDemoWindow(&g_showDemoWindow); | |
} | |
// Render | |
int displayW, displayH; | |
SDL_GetWindowSize(g_window, &displayW, &displayH); | |
glViewport(0, 0, displayW, displayH); | |
glClearColor(0.45f, 0.55f, 0.60f, 1.00f); | |
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); | |
// Render ImGui | |
ImGui::Render(); | |
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); | |
// Update and Render additional Platform Windows | |
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) { | |
SDL_Window* backup_current_window = SDL_GL_GetCurrentWindow(); | |
SDL_GLContext backup_current_context = SDL_GL_GetCurrentContext(); | |
ImGui::UpdatePlatformWindows(); | |
ImGui::RenderPlatformWindowsDefault(); | |
SDL_GL_MakeCurrent(backup_current_window, backup_current_context); | |
} | |
SDL_GL_SwapWindow(g_window); | |
} | |
// Cleanup | |
ImGui_ImplOpenGL3_Shutdown(); | |
ImGui_ImplSDL2_Shutdown(); | |
ImGui::DestroyContext(); | |
if (g_luaState) { | |
lua_close(g_luaState); | |
} | |
SDL_GL_DeleteContext(g_glContext); | |
SDL_DestroyWindow(g_window); | |
SDL_Quit(); | |
return 0; | |
} | |
// Implémentation des fonctions manquantes... | |
void CreateSphereMesh() { | |
g_defaultSphereMesh = std::make_unique<Mesh>(); | |
const int segments = 32; | |
const int rings = 16; | |
// Generate vertices | |
for (int ring = 0; ring <= rings; ring++) { | |
float phi = static_cast<float>(M_PI * ring / rings); | |
for (int segment = 0; segment <= segments; segment++) { | |
float theta = static_cast<float>(2.0 * M_PI * segment / segments); | |
Vertex vertex; | |
vertex.position.x = sin(phi) * cos(theta); | |
vertex.position.y = cos(phi); | |
vertex.position.z = sin(phi) * sin(theta); | |
vertex.normal = vertex.position; | |
vertex.texCoords.x = static_cast<float>(segment) / segments; | |
vertex.texCoords.y = static_cast<float>(ring) / rings; | |
g_defaultSphereMesh->vertices.push_back(vertex); | |
} | |
} | |
// Generate indices | |
for (int ring = 0; ring < rings; ring++) { | |
for (int segment = 0; segment < segments; segment++) { | |
int current = ring * (segments + 1) + segment; | |
int next = current + segments + 1; | |
g_defaultSphereMesh->indices.push_back(current); | |
g_defaultSphereMesh->indices.push_back(next); | |
g_defaultSphereMesh->indices.push_back(current + 1); | |
g_defaultSphereMesh->indices.push_back(current + 1); | |
g_defaultSphereMesh->indices.push_back(next); | |
g_defaultSphereMesh->indices.push_back(next + 1); | |
} | |
} | |
g_defaultSphereMesh->setupMesh(); | |
} | |
void CreatePlaneMesh() { | |
g_defaultPlaneMesh = std::make_unique<Mesh>(); | |
g_defaultPlaneMesh->vertices = { | |
{{-0.5f, 0.0f, -0.5f}, {0.0f, 0.0f}, {0.0f, 1.0f, 0.0f}}, | |
{{ 0.5f, 0.0f, -0.5f}, {1.0f, 0.0f}, {0.0f, 1.0f, 0.0f}}, | |
{{ 0.5f, 0.0f, 0.5f}, {1.0f, 1.0f}, {0.0f, 1.0f, 0.0f}}, | |
{{-0.5f, 0.0f, 0.5f}, {0.0f, 1.0f}, {0.0f, 1.0f, 0.0f}}, | |
}; | |
g_defaultPlaneMesh->indices = { | |
0, 1, 2, 2, 3, 0 | |
}; | |
g_defaultPlaneMesh->setupMesh(); | |
} | |
void CreateCylinderMesh() { | |
g_defaultCylinderMesh = std::make_unique<Mesh>(); | |
const int segments = 32; | |
const float height = 1.0f; | |
const float radius = 0.5f; | |
// Top and bottom centers | |
g_defaultCylinderMesh->vertices.push_back({{0.0f, height/2, 0.0f}, {0.5f, 0.5f}, {0.0f, 1.0f, 0.0f}}); | |
g_defaultCylinderMesh->vertices.push_back({{0.0f, -height/2, 0.0f}, {0.5f, 0.5f}, {0.0f, -1.0f, 0.0f}}); | |
// Side vertices | |
for (int i = 0; i <= segments; i++) { | |
float theta = static_cast<float>(2.0 * M_PI * i / segments); | |
float x = radius * cos(theta); | |
float z = radius * sin(theta); | |
float u = static_cast<float>(i) / segments; | |
// Top ring | |
g_defaultCylinderMesh->vertices.push_back({{x, height/2, z}, {u, 1.0f}, {x, 0.0f, z}}); | |
// Bottom ring | |
g_defaultCylinderMesh->vertices.push_back({{x, -height/2, z}, {u, 0.0f}, {x, 0.0f, z}}); | |
} | |
// Generate indices (caps and sides) | |
for (int i = 0; i < segments; i++) { | |
// Top cap | |
g_defaultCylinderMesh->indices.push_back(0); | |
g_defaultCylinderMesh->indices.push_back(2 + i * 2); | |
g_defaultCylinderMesh->indices.push_back(2 + ((i + 1) % segments) * 2); | |
// Bottom cap | |
g_defaultCylinderMesh->indices.push_back(1); | |
g_defaultCylinderMesh->indices.push_back(3 + ((i + 1) % segments) * 2); | |
g_defaultCylinderMesh->indices.push_back(3 + i * 2); | |
// Side faces | |
int current = 2 + i * 2; | |
int next = 2 + ((i + 1) % segments) * 2; | |
g_defaultCylinderMesh->indices.push_back(current); | |
g_defaultCylinderMesh->indices.push_back(current + 1); | |
g_defaultCylinderMesh->indices.push_back(next); | |
g_defaultCylinderMesh->indices.push_back(next); | |
g_defaultCylinderMesh->indices.push_back(current + 1); | |
g_defaultCylinderMesh->indices.push_back(next + 1); | |
} | |
g_defaultCylinderMesh->setupMesh(); | |
} | |
void CreateFramebuffer(int width, int height) { | |
// Delete existing framebuffer if it exists | |
if (g_framebuffer != 0) { | |
glDeleteFramebuffers(1, &g_framebuffer); | |
glDeleteTextures(1, &g_colorTexture); | |
glDeleteTextures(1, &g_depthTexture); | |
} | |
g_viewportWidth = width; | |
g_viewportHeight = height; | |
// Create framebuffer | |
glGenFramebuffers(1, &g_framebuffer); | |
glBindFramebuffer(GL_FRAMEBUFFER, g_framebuffer); | |
// Create color texture | |
glGenTextures(1, &g_colorTexture); | |
glBindTexture(GL_TEXTURE_2D, g_colorTexture); | |
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); | |
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | |
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | |
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, g_colorTexture, 0); | |
// Create depth texture | |
glGenTextures(1, &g_depthTexture); | |
glBindTexture(GL_TEXTURE_2D, g_depthTexture); | |
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, width, height, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL); | |
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | |
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | |
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, g_depthTexture, 0); | |
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { | |
LogToConsole("Erreur: Framebuffer incomplet!"); | |
} | |
glBindFramebuffer(GL_FRAMEBUFFER, 0); | |
} | |
void InitOpenGL() { | |
// Compilation des shaders principaux | |
GLuint vertexShader = CompileShader(GL_VERTEX_SHADER, vertexShaderSource); | |
GLuint fragmentShader = CompileShader(GL_FRAGMENT_SHADER, fragmentShaderSource); | |
g_shaderProgram = glCreateProgram(); | |
glAttachShader(g_shaderProgram, vertexShader); | |
glAttachShader(g_shaderProgram, fragmentShader); | |
glLinkProgram(g_shaderProgram); | |
GLint success; | |
glGetProgramiv(g_shaderProgram, GL_LINK_STATUS, &success); | |
if (!success) { | |
char infoLog[512]; | |
glGetProgramInfoLog(g_shaderProgram, 512, NULL, infoLog); | |
LogToConsole("Erreur link programme: " + std::string(infoLog)); | |
} | |
glDeleteShader(vertexShader); | |
glDeleteShader(fragmentShader); | |
// Compilation des shaders skybox | |
GLuint skyVertexShader = CompileShader(GL_VERTEX_SHADER, skyboxVertexShader); | |
GLuint skyFragmentShader = CompileShader(GL_FRAGMENT_SHADER, skyboxFragmentShader); | |
g_skyboxShader = glCreateProgram(); | |
glAttachShader(g_skyboxShader, skyVertexShader); | |
glAttachShader(g_skyboxShader, skyFragmentShader); | |
glLinkProgram(g_skyboxShader); | |
glGetProgramiv(g_skyboxShader, GL_LINK_STATUS, &success); | |
if (!success) { | |
char infoLog[512]; | |
glGetProgramInfoLog(g_skyboxShader, 512, NULL, infoLog); | |
LogToConsole("Erreur link programme skybox: " + std::string(infoLog)); | |
} | |
glDeleteShader(skyVertexShader); | |
glDeleteShader(skyFragmentShader); | |
// Skybox setup | |
float skyboxVertices[] = { | |
-1.0f, 1.0f, -1.0f, | |
-1.0f, -1.0f, -1.0f, | |
1.0f, -1.0f, -1.0f, | |
1.0f, -1.0f, -1.0f, | |
1.0f, 1.0f, -1.0f, | |
-1.0f, 1.0f, -1.0f, | |
-1.0f, -1.0f, 1.0f, | |
-1.0f, -1.0f, -1.0f, | |
-1.0f, 1.0f, -1.0f, | |
-1.0f, 1.0f, -1.0f, | |
-1.0f, 1.0f, 1.0f, | |
-1.0f, -1.0f, 1.0f, | |
1.0f, -1.0f, -1.0f, | |
1.0f, -1.0f, 1.0f, | |
1.0f, 1.0f, 1.0f, | |
1.0f, 1.0f, 1.0f, | |
1.0f, 1.0f, -1.0f, | |
1.0f, -1.0f, -1.0f, | |
-1.0f, -1.0f, 1.0f, | |
-1.0f, 1.0f, 1.0f, | |
1.0f, 1.0f, 1.0f, | |
1.0f, 1.0f, 1.0f, | |
1.0f, -1.0f, 1.0f, | |
-1.0f, -1.0f, 1.0f, | |
-1.0f, 1.0f, -1.0f, | |
1.0f, 1.0f, -1.0f, | |
1.0f, 1.0f, 1.0f, | |
1.0f, 1.0f, 1.0f, | |
-1.0f, 1.0f, 1.0f, | |
-1.0f, 1.0f, -1.0f, | |
-1.0f, -1.0f, -1.0f, | |
-1.0f, -1.0f, 1.0f, | |
1.0f, -1.0f, -1.0f, | |
1.0f, -1.0f, -1.0f, | |
-1.0f, -1.0f, 1.0f, | |
1.0f, -1.0f, 1.0f | |
}; | |
glGenVertexArrays(1, &g_skyboxVAO); | |
glGenBuffers(1, &g_skyboxVBO); | |
glBindVertexArray(g_skyboxVAO); | |
glBindBuffer(GL_ARRAY_BUFFER, g_skyboxVBO); | |
glBufferData(GL_ARRAY_BUFFER, sizeof(skyboxVertices), &skyboxVertices, GL_STATIC_DRAW); | |
glEnableVertexAttribArray(0); | |
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0); | |
glBindVertexArray(0); | |
// Create default meshes | |
CreateDefaultCubeMesh(); | |
CreateSphereMesh(); | |
CreatePlaneMesh(); | |
CreateCylinderMesh(); | |
// Create framebuffer | |
CreateFramebuffer(g_viewportWidth, g_viewportHeight); | |
// Enable depth testing | |
glEnable(GL_DEPTH_TEST); | |
glEnable(GL_CULL_FACE); | |
glCullFace(GL_BACK); | |
LogToConsole("OpenGL initialise avec succes"); | |
} | |
void InitLua() { | |
#ifndef NO_LUA | |
g_luaState = luaL_newstate(); | |
luaL_openlibs(g_luaState); | |
// Register print function | |
lua_pushcfunction(g_luaState, [](lua_State* L) -> int { | |
const char* msg = luaL_checkstring(L, 1); | |
LogToConsole("Lua: " + std::string(msg)); | |
return 0; | |
}); | |
lua_setglobal(g_luaState, "cpp_print"); | |
LogToConsole("Lua initialise avec succes"); | |
#else | |
LogToConsole("Lua desactive"); | |
g_luaState = nullptr; | |
#endif | |
} | |
void ProcessInput(float deltaTime) { | |
float velocity = g_camera.speed * deltaTime; | |
if (g_input.keys[SDL_SCANCODE_W] || g_input.keys[SDL_SCANCODE_Z]) { | |
g_camera.position += g_camera.front * velocity; | |
} | |
if (g_input.keys[SDL_SCANCODE_S]) { | |
g_camera.position -= g_camera.front * velocity; | |
} | |
if (g_input.keys[SDL_SCANCODE_A] || g_input.keys[SDL_SCANCODE_Q]) { | |
g_camera.position -= g_camera.right * velocity; | |
} | |
if (g_input.keys[SDL_SCANCODE_D]) { | |
g_camera.position += g_camera.right * velocity; | |
} | |
if (g_input.keys[SDL_SCANCODE_SPACE]) { | |
g_camera.position += g_camera.up * velocity; | |
} | |
if (g_input.keys[SDL_SCANCODE_LSHIFT]) { | |
g_camera.position -= g_camera.up * velocity; | |
} | |
// Gizmo shortcuts | |
if (g_input.keys[SDL_SCANCODE_G]) g_gizmoOperation = ImGuizmo::TRANSLATE; | |
if (g_input.keys[SDL_SCANCODE_R]) g_gizmoOperation = ImGuizmo::ROTATE; | |
if (g_input.keys[SDL_SCANCODE_T]) g_gizmoOperation = ImGuizmo::SCALE; | |
// Delete selected object | |
if (g_input.keys[SDL_SCANCODE_DELETE] && g_selectedIndex >= 0) { | |
g_sceneObjects.erase(g_sceneObjects.begin() + g_selectedIndex); | |
g_selectedIndex = -1; | |
LogToConsole("Objet supprime"); | |
} | |
if (g_input.rightMousePressed) { | |
if (g_input.firstMouse) { | |
g_input.lastMouseX = g_input.mouseX; | |
g_input.lastMouseY = g_input.mouseY; | |
g_input.firstMouse = false; | |
} | |
float xoffset = g_input.mouseX - g_input.lastMouseX; | |
float yoffset = g_input.lastMouseY - g_input.mouseY; | |
g_input.lastMouseX = g_input.mouseX; | |
g_input.lastMouseY = g_input.mouseY; | |
xoffset *= g_camera.sensitivity; | |
yoffset *= g_camera.sensitivity; | |
g_camera.yaw += xoffset; | |
g_camera.pitch += yoffset; | |
if (g_camera.pitch > 89.0f) g_camera.pitch = 89.0f; | |
if (g_camera.pitch < -89.0f) g_camera.pitch = -89.0f; | |
g_camera.updateVectors(); | |
} else { | |
g_input.firstMouse = true; | |
} | |
} | |
// Ajoutez les autres fonctions UI et de rendu ici... | |
// (Le code est très long, je peux continuer avec les fonctions spécifiques si nécessaire) | |
void CreateObject(ObjectType type) { | |
auto obj = std::make_unique<SceneObject>(); | |
switch (type) { | |
case ObjectType::CUBE: | |
obj->name = "Cube_" + std::to_string(g_objectCounter++); | |
obj->color = glm::vec3(0.7f, 0.7f, 1.0f); | |
break; | |
case ObjectType::SPHERE: | |
obj->name = "Sphere_" + std::to_string(g_objectCounter++); | |
obj->color = glm::vec3(1.0f, 0.7f, 0.7f); | |
break; | |
case ObjectType::PLANE: | |
obj->name = "Plane_" + std::to_string(g_objectCounter++); | |
obj->color = glm::vec3(0.7f, 1.0f, 0.7f); | |
obj->scale = glm::vec3(5.0f, 0.1f, 5.0f); | |
break; | |
case ObjectType::CYLINDER: | |
obj->name = "Cylinder_" + std::to_string(g_objectCounter++); | |
obj->color = glm::vec3(0.7f, 1.0f, 1.0f); | |
break; | |
case ObjectType::LIGHT: | |
obj->name = "Light_" + std::to_string(g_objectCounter++); | |
obj->color = glm::vec3(1.0f, 1.0f, 0.7f); | |
obj->scale = glm::vec3(0.2f, 0.2f, 0.2f); | |
obj->lightIntensity = 1.0f; | |
obj->lightRange = 10.0f; | |
obj->emission = 2.0f; | |
break; | |
case ObjectType::MODEL: | |
obj->name = "Model_" + std::to_string(g_objectCounter++); | |
obj->color = glm::vec3(0.8f, 0.8f, 0.8f); | |
break; | |
case ObjectType::EMPTY: | |
obj->name = "Empty_" + std::to_string(g_objectCounter++); | |
obj->color = glm::vec3(0.5f, 0.5f, 0.5f); | |
obj->scale = glm::vec3(0.1f, 0.1f, 0.1f); | |
break; | |
} | |
obj->type = type; | |
obj->updateTransform(); | |
g_sceneObjects.push_back(std::move(obj)); | |
LogToConsole("Objet cree: " + g_sceneObjects.back()->name); | |
} | |
void ImportTexture() { | |
std::string path = OpenFileDialog("Image Files\0*.png;*.jpg;*.jpeg;*.bmp;*.tga\0All Files\0*.*\0"); | |
if (!path.empty()) { | |
GLuint textureID = LoadTexture(path); | |
if (textureID != 0) { | |
std::filesystem::path filePath(path); | |
std::string textureName = filePath.stem().string(); | |
int counter = 1; | |
std::string originalName = textureName; | |
while (g_textures.find(textureName) != g_textures.end()) { | |
textureName = originalName + "_" + std::to_string(counter++); | |
} | |
g_textures[textureName] = textureID; | |
LogToConsole("Texture importee: " + textureName); | |
} | |
} | |
} | |
// Stub implementations pour les fonctions UI manquantes | |
void RenderMenuBar() { | |
if (ImGui::BeginMenuBar()) { | |
if (ImGui::BeginMenu("File")) { | |
if (ImGui::MenuItem("New Scene", "Ctrl+N")) { | |
g_sceneObjects.clear(); | |
g_selectedIndex = -1; | |
g_objectCounter = 0; | |
LogToConsole("Nouvelle scene creee"); | |
} | |
ImGui::EndMenu(); | |
} | |
if (ImGui::BeginMenu("Create")) { | |
if (ImGui::MenuItem("Cube")) CreateObject(ObjectType::CUBE); | |
if (ImGui::MenuItem("Sphere")) CreateObject(ObjectType::SPHERE); | |
if (ImGui::MenuItem("Plane")) CreateObject(ObjectType::PLANE); | |
if (ImGui::MenuItem("Cylinder")) CreateObject(ObjectType::CYLINDER); | |
ImGui::Separator(); | |
if (ImGui::MenuItem("Light")) CreateObject(ObjectType::LIGHT); | |
if (ImGui::MenuItem("Empty")) CreateObject(ObjectType::EMPTY); | |
ImGui::EndMenu(); | |
} | |
ImGui::EndMenuBar(); | |
} | |
} | |
void RenderSceneHierarchy() { | |
if (!g_showSceneHierarchy) return; | |
ImGui::Begin("Scene Hierarchy", &g_showSceneHierarchy); | |
// Quick create buttons | |
if (ImGui::Button("Cube")) CreateObject(ObjectType::CUBE); | |
ImGui::SameLine(); | |
if (ImGui::Button("Sphere")) CreateObject(ObjectType::SPHERE); | |
ImGui::Separator(); | |
for (size_t i = 0; i < g_sceneObjects.size(); ++i) { | |
auto& obj = g_sceneObjects[i]; | |
ImGuiTreeNodeFlags flags = ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen; | |
if (g_selectedIndex == static_cast<int>(i)) { | |
flags |= ImGuiTreeNodeFlags_Selected; | |
} | |
ImGui::TreeNodeEx((void*)(intptr_t)i, flags, "%s", obj->name.c_str()); | |
if (ImGui::IsItemClicked()) { | |
g_selectedIndex = static_cast<int>(i); | |
obj->selected = true; | |
for (size_t j = 0; j < g_sceneObjects.size(); ++j) { | |
if (j != i) g_sceneObjects[j]->selected = false; | |
} | |
} | |
} | |
if (g_sceneObjects.empty()) { | |
ImGui::TextColored(ImVec4(0.5f, 0.5f, 0.5f, 1.0f), "Scene vide"); | |
} | |
ImGui::End(); | |
} | |
void RenderProperties() { | |
if (!g_showProperties) return; | |
ImGui::Begin("Properties", &g_showProperties); | |
if (g_selectedIndex >= 0 && g_selectedIndex < static_cast<int>(g_sceneObjects.size())) { | |
auto& obj = g_sceneObjects[g_selectedIndex]; | |
// Transform | |
if (ImGui::CollapsingHeader("Transform", ImGuiTreeNodeFlags_DefaultOpen)) { | |
bool transformChanged = false; | |
transformChanged |= ImGui::DragFloat3("Position", glm::value_ptr(obj->position), 0.1f); | |
transformChanged |= ImGui::DragFloat3("Rotation", glm::value_ptr(obj->rotation), 1.0f); | |
transformChanged |= ImGui::DragFloat3("Scale", glm::value_ptr(obj->scale), 0.01f, 0.001f, 10.0f); | |
if (transformChanged) { | |
obj->updateTransform(); | |
} | |
} | |
// Material | |
if (ImGui::CollapsingHeader("Material")) { | |
ImGui::ColorEdit3("Color", glm::value_ptr(obj->color)); | |
ImGui::SliderFloat("Roughness", &obj->roughness, 0.0f, 1.0f); | |
ImGui::SliderFloat("Metallic", &obj->metallic, 0.0f, 1.0f); | |
ImGui::SliderFloat("Emission", &obj->emission, 0.0f, 5.0f); | |
} | |
} else { | |
ImGui::TextColored(ImVec4(0.5f, 0.5f, 0.5f, 1.0f), "Aucun objet selectionne"); | |
} | |
ImGui::End(); | |
} | |
void RenderAssetBrowser() { | |
if (!g_showAssetBrowser) return; | |
ImGui::Begin("Asset Browser", &g_showAssetBrowser); | |
if (ImGui::Button("Import Texture...")) { | |
ImportTexture(); | |
} | |
ImGui::Separator(); | |
if (ImGui::CollapsingHeader("Textures", ImGuiTreeNodeFlags_DefaultOpen)) { | |
if (g_textures.empty()) { | |
ImGui::TextColored(ImVec4(0.5f, 0.5f, 0.5f, 1.0f), "No textures loaded"); | |
} else { | |
for (const auto& tex : g_textures) { | |
ImGui::Text("%s", tex.first.c_str()); | |
} | |
} | |
} | |
ImGui::End(); | |
} | |
void RenderTextureManager() { | |
if (!g_showTextureManager) return; | |
ImGui::Begin("Texture Manager", &g_showTextureManager); | |
if (ImGui::Button("Import Texture...")) { | |
ImportTexture(); | |
} | |
ImGui::Separator(); | |
ImGui::Text("Textures disponibles (%zu):", g_textures.size()); | |
for (const auto& tex : g_textures) { | |
ImGui::Text("%s", tex.first.c_str()); | |
} | |
if (g_textures.empty()) { | |
ImGui::TextColored(ImVec4(0.5f, 0.5f, 0.5f, 1.0f), "Aucune texture chargee"); | |
} | |
ImGui::End(); | |
} | |
void RenderConsole() { | |
if (!g_showConsole) return; | |
ImGui::Begin("Console", &g_showConsole); | |
if (ImGui::Button("Clear")) { | |
g_consoleLog.clear(); | |
} | |
ImGui::Separator(); | |
// Console output | |
ImGui::BeginChild("ScrollingRegion", ImVec2(0, -35), false, ImGuiWindowFlags_HorizontalScrollbar); | |
for (const auto& line : g_consoleLog) { | |
ImVec4 color = ImVec4(1.0f, 1.0f, 1.0f, 1.0f); | |
if (line.find("Erreur") != std::string::npos) { | |
color = ImVec4(1.0f, 0.4f, 0.4f, 1.0f); | |
} else if (line.find("Lua:") != std::string::npos) { | |
color = ImVec4(0.4f, 1.0f, 0.4f, 1.0f); | |
} | |
ImGui::TextColored(color, "%s", line.c_str()); | |
} | |
ImGui::EndChild(); | |
// Console input | |
ImGui::Separator(); | |
static char inputBuffer[256] = ""; | |
if (ImGui::InputText("##ConsoleInput", inputBuffer, sizeof(inputBuffer), ImGuiInputTextFlags_EnterReturnsTrue)) { | |
std::string command = std::string(inputBuffer); | |
if (!command.empty()) { | |
LogToConsole("> " + command); | |
if (command == "clear") { | |
g_consoleLog.clear(); | |
} else if (command == "help") { | |
LogToConsole("Available commands: clear, help, stats"); | |
} else if (command == "stats") { | |
LogToConsole("Objects: " + std::to_string(g_sceneObjects.size())); | |
LogToConsole("Textures: " + std::to_string(g_textures.size())); | |
} | |
memset(inputBuffer, 0, sizeof(inputBuffer)); | |
} | |
} | |
ImGui::End(); | |
} | |
void RenderSettings() { | |
if (!g_showSettings) return; | |
ImGui::Begin("Settings", &g_showSettings); | |
if (ImGui::CollapsingHeader("Graphics")) { | |
ImGui::Checkbox("VSync", &g_vsync); | |
ImGui::Checkbox("Wireframe", &g_wireframe); | |
ImGui::SliderFloat("Gamma", &g_gamma, 0.1f, 3.0f); | |
} | |
if (ImGui::CollapsingHeader("Camera")) { | |
ImGui::SliderFloat("Speed", &g_camera.speed, 1.0f, 20.0f); | |
ImGui::SliderFloat("Sensitivity", &g_camera.sensitivity, 0.01f, 1.0f); | |
ImGui::SliderFloat("FOV", &g_camera.fov, 30.0f, 120.0f); | |
} | |
ImGui::End(); | |
} | |
void RenderStats() { | |
if (!g_showStats) return; | |
ImGui::Begin("Statistics", &g_showStats); | |
ImGui::Text("Performance"); | |
ImGui::Separator(); | |
ImGui::Text("Frame Time: %.3f ms", g_stats.frameTime * 1000.0f); | |
ImGui::Text("FPS: %.1f", g_stats.fps); | |
ImGui::Text("Draw Calls: %d", g_stats.drawCalls); | |
ImGui::Text("Vertices: %d", g_stats.vertices); | |
ImGui::Text("Triangles: %d", g_stats.triangles); | |
ImGui::Separator(); | |
ImGui::Text("Scene"); | |
ImGui::Text("Objects: %zu", g_sceneObjects.size()); | |
ImGui::Text("Textures: %zu", g_textures.size()); | |
ImGui::End(); | |
} | |
void RenderViewport() { | |
if (!g_showViewport) return; | |
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f)); | |
ImGui::Begin("Viewport", &g_showViewport); | |
ImVec2 viewportSize = ImGui::GetContentRegionAvail(); | |
// Resize framebuffer if needed | |
if (viewportSize.x != g_viewportWidth || viewportSize.y != g_viewportHeight) { | |
if (viewportSize.x > 0 && viewportSize.y > 0) { | |
CreateFramebuffer(static_cast<int>(viewportSize.x), static_cast<int>(viewportSize.y)); | |
} | |
} | |
// Render scene to framebuffer | |
glBindFramebuffer(GL_FRAMEBUFFER, g_framebuffer); | |
glViewport(0, 0, g_viewportWidth, g_viewportHeight); | |
glClearColor(0.2f, 0.3f, 0.3f, 1.0f); | |
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); | |
// Render scene | |
RenderScene(); | |
glBindFramebuffer(GL_FRAMEBUFFER, 0); | |
// Display framebuffer texture in ImGui | |
ImGui::Image((void*)(intptr_t)g_colorTexture, viewportSize, ImVec2(0, 1), ImVec2(1, 0)); | |
ImGui::End(); | |
ImGui::PopStyleVar(); | |
} | |
void RenderSkybox(const glm::mat4& view, const glm::mat4& projection) { | |
glDepthFunc(GL_LEQUAL); | |
glUseProgram(g_skyboxShader); | |
GLint viewLoc = glGetUniformLocation(g_skyboxShader, "view"); | |
GLint projectionLoc = glGetUniformLocation(g_skyboxShader, "projection"); | |
GLint topColorLoc = glGetUniformLocation(g_skyboxShader, "topColor"); | |
GLint bottomColorLoc = glGetUniformLocation(g_skyboxShader, "bottomColor"); | |
glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(view)); | |
glUniformMatrix4fv(projectionLoc, 1, GL_FALSE, glm::value_ptr(projection)); | |
glUniform3fv(topColorLoc, 1, glm::value_ptr(g_skyboxTopColor)); | |
glUniform3fv(bottomColorLoc, 1, glm::value_ptr(g_skyboxBottomColor)); | |
glBindVertexArray(g_skyboxVAO); | |
glDrawArrays(GL_TRIANGLES, 0, 36); | |
glBindVertexArray(0); | |
glDepthFunc(GL_LESS); | |
} | |
Mesh* GetMeshForObjectType(ObjectType type) { | |
switch (type) { | |
case ObjectType::CUBE: | |
default: | |
return g_defaultCubeMesh.get(); | |
case ObjectType::SPHERE: | |
return g_defaultSphereMesh.get(); | |
case ObjectType::PLANE: | |
return g_defaultPlaneMesh.get(); | |
case ObjectType::CYLINDER: | |
return g_defaultCylinderMesh.get(); | |
case ObjectType::LIGHT: | |
return g_defaultCubeMesh.get(); | |
case ObjectType::EMPTY: | |
return g_defaultCubeMesh.get(); | |
} | |
} | |
void RenderScene() { | |
// Clear stats | |
g_stats.drawCalls = 0; | |
g_stats.vertices = 0; | |
g_stats.triangles = 0; | |
glEnable(GL_DEPTH_TEST); | |
glEnable(GL_CULL_FACE); | |
// Calculate matrices | |
float aspectRatio = (float)g_viewportWidth / (float)g_viewportHeight; | |
glm::mat4 view = g_camera.getViewMatrix(); | |
glm::mat4 projection = g_camera.getProjectionMatrix(aspectRatio); | |
// Render skybox first | |
RenderSkybox(view, projection); | |
// Use main shader | |
glUseProgram(g_shaderProgram); | |
// Set common uniforms | |
GLint viewLoc = glGetUniformLocation(g_shaderProgram, "view"); | |
GLint projectionLoc = glGetUniformLocation(g_shaderProgram, "projection"); | |
GLint lightPosLoc = glGetUniformLocation(g_shaderProgram, "lightPos"); | |
GLint lightColorLoc = glGetUniformLocation(g_shaderProgram, "lightColor"); | |
GLint viewPosLoc = glGetUniformLocation(g_shaderProgram, "viewPos"); | |
glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(view)); | |
glUniformMatrix4fv(projectionLoc, 1, GL_FALSE, glm::value_ptr(projection)); | |
glUniform3fv(viewPosLoc, 1, glm::value_ptr(g_camera.position)); | |
// Find first light for basic lighting | |
glm::vec3 lightPos = glm::vec3(5.0f, 5.0f, 5.0f); | |
glm::vec3 lightColor = glm::vec3(1.0f, 1.0f, 1.0f); | |
for (const auto& obj : g_sceneObjects) { | |
if (obj->type == ObjectType::LIGHT && obj->visible) { | |
lightPos = obj->position; | |
lightColor = obj->color * obj->lightIntensity; | |
break; | |
} | |
} | |
glUniform3fv(lightPosLoc, 1, glm::value_ptr(lightPos)); | |
glUniform3fv(lightColorLoc, 1, glm::value_ptr(lightColor)); | |
// Render all objects | |
for (const auto& obj : g_sceneObjects) { | |
if (!obj->visible) continue; | |
// Set object-specific uniforms | |
GLint modelLoc = glGetUniformLocation(g_shaderProgram, "model"); | |
GLint colorLoc = glGetUniformLocation(g_shaderProgram, "objectColor"); | |
GLint selectedLoc = glGetUniformLocation(g_shaderProgram, "isSelected"); | |
GLint wireframeLoc = glGetUniformLocation(g_shaderProgram, "isWireframe"); | |
GLint hasTextureLoc = glGetUniformLocation(g_shaderProgram, "hasTexture"); | |
GLint roughnessLoc = glGetUniformLocation(g_shaderProgram, "roughness"); | |
GLint metallicLoc = glGetUniformLocation(g_shaderProgram, "metallic"); | |
GLint emissionLoc = glGetUniformLocation(g_shaderProgram, "emission"); | |
glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(obj->transform)); | |
glUniform3fv(colorLoc, 1, glm::value_ptr(obj->color)); | |
glUniform1i(selectedLoc, obj->selected ? 1 : 0); | |
glUniform1i(wireframeLoc, g_wireframe ? 1 : 0); | |
glUniform1f(roughnessLoc, obj->roughness); | |
glUniform1f(metallicLoc, obj->metallic); | |
glUniform1f(emissionLoc, obj->emission); | |
// Bind texture if available | |
bool hasTexture = false; | |
if (!obj->textureName.empty() && g_textures.find(obj->textureName) != g_textures.end()) { | |
glActiveTexture(GL_TEXTURE0); | |
glBindTexture(GL_TEXTURE_2D, g_textures[obj->textureName]); | |
glUniform1i(glGetUniformLocation(g_shaderProgram, "texture1"), 0); | |
hasTexture = true; | |
} | |
glUniform1i(hasTextureLoc, hasTexture ? 1 : 0); | |
// Set wireframe mode | |
if (g_wireframe) { | |
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); | |
} else { | |
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); | |
} | |
// Render appropriate mesh | |
if (obj->type == ObjectType::MODEL && !obj->meshes.empty()) { | |
for (const auto& mesh : obj->meshes) { | |
mesh->draw(); | |
g_stats.drawCalls++; | |
g_stats.vertices += static_cast<int>(mesh->vertices.size()); | |
g_stats.triangles += static_cast<int>(mesh->indices.size()) / 3; | |
} | |
} else { | |
Mesh* mesh = GetMeshForObjectType(obj->type); | |
if (mesh) { | |
mesh->draw(); | |
g_stats.drawCalls++; | |
g_stats.vertices += static_cast<int>(mesh->vertices.size()); | |
g_stats.triangles += static_cast<int>(mesh->indices.size()) / 3; | |
} | |
} | |
} | |
// Reset polygon mode | |
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); | |
} | |
// Assimp model loading functions | |
std::unique_ptr<Mesh> ProcessMesh(aiMesh* mesh, const aiScene* scene) { | |
auto newMesh = std::make_unique<Mesh>(); | |
for (unsigned int i = 0; i < mesh->mNumVertices; i++) { | |
Vertex vertex; | |
vertex.position.x = mesh->mVertices[i].x; | |
vertex.position.y = mesh->mVertices[i].y; | |
vertex.position.z = mesh->mVertices[i].z; | |
if (mesh->HasNormals()) { | |
vertex.normal.x = mesh->mNormals[i].x; | |
vertex.normal.y = mesh->mNormals[i].y; | |
vertex.normal.z = mesh->mNormals[i].z; | |
} else { | |
vertex.normal = glm::vec3(0.0f, 1.0f, 0.0f); | |
} | |
if (mesh->mTextureCoords[0]) { | |
vertex.texCoords.x = mesh->mTextureCoords[0][i].x; | |
vertex.texCoords.y = mesh->mTextureCoords[0][i].y; | |
} else { | |
vertex.texCoords = glm::vec2(0.0f, 0.0f); | |
} | |
newMesh->vertices.push_back(vertex); | |
} | |
for (unsigned int i = 0; i < mesh->mNumFaces; i++) { | |
aiFace face = mesh->mFaces[i]; | |
for (unsigned int j = 0; j < face.mNumIndices; j++) { | |
newMesh->indices.push_back(face.mIndices[j]); | |
} | |
} | |
newMesh->setupMesh(); | |
return newMesh; | |
} | |
void ProcessNode(aiNode* node, const aiScene* scene, std::vector<std::unique_ptr<Mesh>>& meshes) { | |
for (unsigned int i = 0; i < node->mNumMeshes; i++) { | |
aiMesh* mesh = scene->mMeshes[node->mMeshes[i]]; | |
meshes.push_back(ProcessMesh(mesh, scene)); | |
} | |
for (unsigned int i = 0; i < node->mNumChildren; i++) { | |
ProcessNode(node->mChildren[i], scene, meshes); | |
} | |
} | |
bool LoadModel(const std::string& path, SceneObject* obj) { | |
Assimp::Importer importer; | |
const aiScene* scene = importer.ReadFile(path, | |
aiProcess_Triangulate | | |
aiProcess_FlipUVs | | |
aiProcess_CalcTangentSpace | | |
aiProcess_GenNormals); | |
if (!scene || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode) { | |
LogToConsole("Erreur Assimp: " + std::string(importer.GetErrorString())); | |
return false; | |
} | |
obj->meshes.clear(); | |
ProcessNode(scene->mRootNode, scene, obj->meshes); | |
LogToConsole("Modele charge: " + path + " (" + std::to_string(obj->meshes.size()) + " meshes)"); | |
return true; | |
} | |
void ImportModel() { | |
std::string path = OpenFileDialog("3D Models\0*.obj;*.fbx;*.dae;*.3ds;*.blend;*.ply\0All Files\0*.*\0"); | |
if (!path.empty()) { | |
CreateObject(ObjectType::MODEL); | |
auto& obj = g_sceneObjects.back(); | |
obj->modelPath = path; | |
std::filesystem::path filePath(path); | |
obj->name = filePath.stem().string() + "_" + std::to_string(g_objectCounter - 1); | |
if (LoadModel(path, obj.get())) { | |
LogToConsole("Modele importe avec succes: " + path); | |
} else { | |
LogToConsole("Echec import modele: " + path); | |
g_sceneObjects.pop_back(); | |
g_objectCounter--; | |
} | |
} | |
}UTTONDOWN: | |
if (event.button.button < 8) { | |
g_input.mouseButtons[event.button.button] = true; | |
if (event.button.button == SDL_BUTTON_RIGHT) { | |
g_input.rightMousePressed = true; | |
} | |
} | |
break; | |
case SDL_MOUSEB |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment